spy++ 在您的屏幕截图中显示 wndproc(它可能是子类;您可能需要跟踪但 wndproc 显示在您的屏幕截图中,因为361c9880
我不知道 x64 dbg 中的命令是什么,但如果您使用的是 ollydbg,您只需执行ctrl+g (goto) 键入地址,如 spy++ 所示,并中断并记录消息以进行过滤。
calc.exe -> comctl32.dll 中的退格按钮窗口 wndproc 的屏幕截图(32 位和 64 位在概念级别上应该无关紧要)
raymond chen 的一篇文章谈到了返回 cookie 而不是 wndproc:http :
//blogs.msdn.com/b/oldnewthing/archive/2003/12/01/55900.aspx
如果所有其他方法都失败,则组装 GetWindowLongPtrW 以获取实际的 WndProc
- 暂停进程(f12 或 esc)
- 使用 ctrl+g 转到 user32.GetWindowLongPtrW
- 右键单击在此处设置新原点(在此之前保存 rip)
- 将寄存器状态保存在某处
- 修改 rcx 并将句柄放入 rcx(在屏幕截图中为 b01c8)
- 使用最新的窗口句柄,如 spy++ 所示
- 对于现有会话不要放 0xb01c8
- 修改 edx 以保持 -4(GWLP_WNDPROC 的索引)
- 单步执行函数
- 在函数返回 rax 之前应该保存实际的 WndProc
- 在 Wndproc 上保存或设置 bp
- 恢复寄存器并撕裂到原始状态并继续探索
我下载了 x64dbg 并运行了 64 位 calc.exe spy++ 32 位不显示 wndproc。我编写了一个脚本来在 calc.exe 的进程内存中分配一个页面,并使用脚本语言组装了一个弯路并获取了实际的 WndProc。
截图如下:
调试对象必须处于暂停状态。
该脚本使用 alloc 在被调试对象地址空间中分配内存;标签后状态栏应显示新分配的地址。另外变量 $lastalloc $result 应该保存新分配的内存地址;如果你做d address
了一堆 00 00 应该盯着你看。
- 确认分配
- 如果内存分配选项卡在脚本的一步
- push rcx 应该在新分配的地址中组装
- 使用 d address 或 d $lastalloc 确认
- 像聪明人一样组装所有指令
- 在 ecx 中使用正确的句柄值(陈旧或重复使用的窗口句柄可能会提供不正确的信息,确认您正确组装 mov rcx , HWND
- 现在你需要确保你在 eax 中放置了正确的地址,地址应该是 user32.GetWindowLongPtrW
- 组装所有清理说明
- 你已经这样做了
- 将现有的 rip 保存在某个地方(写在纸上)
- 右击选择新分配地址中的第一条指令,设置为origin(这里是new origin),rip就会改成新分配的地址
- 按 f8 并逐个执行指令
- 当调用 eax 完成时,eax 将持有 Wndproc
- 保存这个(写在纸上)
- 执行清理指令
- 按 ctrl+g 并输入旧的 RIP
- 右键单击 -> 此处新建原点(当您暂停调试对象时,RIP 现在将指向旧值
这就对了; 现在您在论文中有 Wndproc 并且您已返回到原始状态。
这是绕道(在debuggee的代码流中故意绕过,做一些额外的工作,回到绕过的地方,就好像什么都没做一样继续原来的流程)。
使用 bp 在纸上的 wndproc 中设置断点。