有什么办法可以观察当前进程的一块内存是否发生变化?

逆向工程 登录
2021-07-01 10:42:09

我正在寻找一种在当前进程的某些内存块发生变化时得到通知的方法。

更具体地说,我想跟踪结构的某些字段何时发生变化。

假设我在内存中有这个结构的一个实例:

struct {
   int field_a;
   int field_b;
} my_struct;

有什么方法可以注册回调以在任何字段发生更改时通知我吗?

我知道一些调试器提供“数据断点”,当指定的变量改变时暂停执行。

有什么办法,也许是一些 win32 调试 api 或中断使这成为可能?

1个回答

VirtualProtect 锁定整个页面并在访问时引发异常并删除 PAGE_GUARD 内存保护。
在异常处理程序中,您监视一个小块
如果except->ExceptionRecord->ExceptionAddress 不在您的监视块中
,则在您的异常处理程序中重置保护。
将 ContextRecord->Rip 重置为下一条指令并返回 EXECEPTION_CONTINUE_EXECUTION

请参阅下面的示例代码

#include <stdio.h>
#include <windows.h>
typedef struct _S1{
    int field_a;
    int field_b;
} S1, *PS1;
//putting guarded data in a seperate section for convenience 
#pragma data_seg(push, MyGuardedSection, ".guarded")
S1 t1 = {0, 0};
#pragma data_seg(pop, MyGuardedSection)
DWORD oldprot = 0;
int filter(unsigned int code, struct _EXCEPTION_POINTERS *except){
    if (code == EXCEPTION_GUARD_PAGE &&
        except->ExceptionRecord->ExceptionAddress != (&(t1.field_b)))    {
        VirtualProtect(&t1.field_b, sizeof(t1.field_b), 0x140, &oldprot);
        except->ContextRecord->Rip += 6;
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    printf("%x\n%p\n",
           except->ExceptionRecord->ExceptionCode,
           except->ExceptionRecord->ExceptionAddress);
    return EXCEPTION_EXECUTE_HANDLER;
}
int main(void){
    DWORD counter = 0;
    DWORD loopcount = 0;
    VirtualProtect(&t1.field_b, sizeof(t1.field_b), 0x140, &oldprot);
    __try    {
        while (loopcount < 2)        {
            while (counter < 0x30)            {
                t1.field_a++; //this will raise guard page exception
                counter++;   // we return here from handler after reguarding
                printf("%x ", counter);
                Sleep(0x10);
            }
            counter = 0;
            loopcount += 1;
            printf("\nwe have reset guard page exception 0x60 times \n");
        }
        printf("we access our field now \n");
        t1.field_b = 0xdead; //this again will raise exception and we execute handler 
        
    }
    __except (filter(GetExceptionCode(), GetExceptionInformation()))    {
        //removing page guard
        VirtualProtect(&t1.field_b, sizeof(t1.field_b), 0x40, &oldprot);
        printf("t1.field_b = %x\n", t1.field_b);
        t1.field_b = 0xdead;
        printf("t1.field_b = %x\n", t1.field_b); // no exception 
        printf("Handler for PG %x\n", GetExceptionCode());
    }
}

编译并执行

:\>cl /Zi /W4 /analyze /EHsc /nologo vlock.cpp /link /release
vlock.cpp

:\>vlock.exe
1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30
we have reset guard page exception 0x60 times
1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30
we have reset guard page exception 0x60 times
we access our field now
c0000005
00007FF7CA131159
t1.field_b = 0
t1.field_b = dead
Handler for PG c0000005