Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Winapi ReadProcessMemory返回不正确的值_Winapi_Windbg_Breakpoints_Readprocessmemory - Fatal编程技术网

Winapi ReadProcessMemory返回不正确的值

Winapi ReadProcessMemory返回不正确的值,winapi,windbg,breakpoints,readprocessmemory,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 implmentat

考虑以下代码:

#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;
}
至于断点,在VS中,我只是在
返回x+1
上放置了一个断点

在WinDBG中,我使用了
bp-cpp\u-exe!f+20
,假设模块(exe)的名称是
cpp\u exe

,所以我想我已经找到了答案

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

另一方面,VS始终返回正确的值(0xCC字节,无论是在运行还是在中断模式下)

所以我猜每当WinDBG中断时,它实际上会删除所有软件断点,然后在您继续应用程序时立即恢复这些断点。
我想这是一种有趣的方法,但至少它是有意义的。

如果您感兴趣,我是在尝试在.net运行时设置断点时想到这一点的。但是,运行时本身偶尔会在运行时修补自己的代码,然后断言代码字节与预期的一致,如果存在断点,这当然会失败。请参阅:例如,0xCC是INT3指令,调试器普遍使用它来设置断点。当代码指令到达操作系统时,操作系统将生成一个由调试器处理的异常。Windbg和afaik。但它不会在增量链接生成的JMP存根上设置断点。很难直接看到,当您请求反汇编时,它会假装原始字节仍然存在。从技术上讲,还有另一种方法可以做到这一点,处理器还支持硬件中的断点。但它只支持其中三个,调试器支持它们设置数据断点。@HansPassant我知道你写了什么。但这不是重点。正如我所写的,当我从
main
函数打印
f
的字节时,我确实可以看到0xCC,它确认正在使用软件断点。在使用ReadProcessMemory时,只要调试器是VS,我也会得到这个结果。我的问题是:为什么在WinDBG调试时ReadProcessMemory的工作方式会有所不同?当程序进入调试器时,0xCC会被删除,当执行恢复时会被替换。如果您从未恢复执行,那么您将永远不会看到0xCC。停止时将断点留在内存中会使转储内存和反汇编代码变得更加困难,因为您必须在显示/反汇编0xCC字节之前将其更改回原始值。我很惊讶VS在停止时会留下修补过的字节。ReadProcessMemory没有什么特别的功能。没有正确或不正确的值。它返回存在的内容。关键是不同的调试器的行为不同。@DavidHeffernan你说得对。本可以选择更好的措辞。也许以后会编辑。
#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;
}