ReadProcessMemory возвращает неправильное значение - PullRequest
0 голосов
/ 04 июня 2019

Рассмотрим следующий код:

#include <stdio.h>
#include <inttypes.h>
#include <Windows.h>

int f(int x)
{
    return x+1;
}

// using vs 2019 debug|x86
int main()
{
    // visual studio's creates a label for f, which eventually jumps to it's implmentation.
    // the jump instruction is E9, then an offset to the implementation.
    // this calculates the actual address of f, by getting f+5(the length of the jump instruction)+the jump offset
    unsigned char *fAddr = (unsigned char*)f + 5 + *(int*)((char*)f + 1);

    printf("printing f bytes (pid %d at 0x%" PRIXPTR "):\n", GetCurrentProcessId(), fAddr);
    int fLen = 0x45; // for me, function size was 0x42
    for (int i = 0; i < fLen;)
    {
        for (int j = 0; j < 10 && i < fLen; ++j)
            printf("%02X ", fAddr[i++]);
        printf("\n");
    }

    getchar();
    return 0;
}

Приведенный выше код в основном выводит байты кода f.

Теперь, если я поставлю программную точку останова внутри f, значение этого байта изменится на 0xCC. И это будет отражено, когда main напечатает f.

Я ожидаю, что при вызове ReadProcessMemory по адресу точки останова я также получу 0xCC вместо исходного значения байта. Это действительно то, что происходит, когда я устанавливаю точку останова с помощью Visual Studio. Однако когда я устанавливаю точку останова с помощью WinDbg, ReadProcessMemory возвращает исходное значение байта.

  1. Кто-нибудь знает, почему это происходит и что в WinDbg отличается от Visual Studio? В конце концов, они оба устанавливают программные точки останова.
  2. Есть ли способ узнать, каково реальное значение адреса памяти?

Edit: Вот код, который я использовал для вызова ReadProcessMemory:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <inttypes.h>
#include <Windows.h>

int main()
{
    int *fPid;
    int *fAddr;
    printf("Please enter the pid of f (upper case hex digits, no 0x): ");
    scanf("%X", &fPid);
    printf("Please enter the address of f (upper case hex digits, no 0x): ");
    scanf("%X", &fAddr);

    printf("printing f bytes (pid 0x%X at 0x%X):\n", fPid, fAddr);

    HANDLE process;
    if ((process = OpenProcess(PROCESS_VM_READ, FALSE, fPid)) == INVALID_HANDLE_VALUE)
    {
        DWORD err = GetLastError();
        printf("OpenProcess error: %d\n", err);
        char cmd[100];
        sprintf(cmd, "net helpmsg %d", err);
        system(cmd);
        return 1;
    }
    int fLen = 0x45;
    unsigned char *buf = malloc(fLen);
    if (!ReadProcessMemory(process, fAddr, buf, fLen, NULL))
    {
        DWORD err = GetLastError();
        printf("ReadProcessMemory error: %d\n", err);
        char cmd[100];
        sprintf(cmd, "net helpmsg %d", err);
        system(cmd);
        return 1;
    }

    for (int i = 0; i < fLen;)
    {
        for (int j = 0; j < 10 && i < fLen; ++j)
            printf("%02x ", buf[i++]);
        printf("\n");
    }
    free(buf);

    return 0;
}

Что касается точки останова, в VS я просто поставил точку останова на return x+1.
В WinDBG я использовал bp cpp_exe!f+20, предполагая, что имя модуля (exe) cpp_exe.

1 Ответ

1 голос
/ 05 июня 2019

Так что я думаю, что я понял это.

При отладке с WinDBG и запущенным отладчиком ReadProcessMemory возвращает правильные значения (то есть я вижу байты 0xCC).Однако, когда отладчик находится в режиме прерывания, ReadProcessMemory возвращает исходные значения байтов.

VS, с другой стороны, всегда возвращает правильное значение (0xCC байт, независимо от того, работает он или находится в режиме прерывания).

Так что, думаю, всякий раз, когда WinDBG ломается, он фактически удаляет все программные точки останова, которые затем восстанавливаются, как только вы продолжаете приложение.Думаю, это интересный подход, но, по крайней мере, он имеет смысл.

...