ReadProcessMemory返回的值不正确

时间:2019-06-04 09:46:34

标签: winapi windbg breakpoints readprocessmemory

考虑以下代码:

#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. 有没有办法查看内存地址的实际值?

编辑: 这是我用来调用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中,假设模块(exe)名称为bp cpp_exe!f+20,则使用cpp_exe

1 个答案:

答案 0 :(得分:1)

所以我想我已经解决了。

使用WinDBG调试并且运行debgugee时,ReadProcessMemory返回正确的值(这意味着我可以看到0xCC字节)。 但是,当调试对象处于中断模式时,ReadProcessMemory会返回原始字节值。

另一方面,VS总是返回正确的值(0xCC字节,无论是运行还是处于中断模式)。

因此,我想每当WinDBG中断时,它实际上就会删除所有软件断点,并在您继续应用程序后立即将其恢复。 我猜这是一种有趣的方法,但至少有道理。