我正在编写一个全局钩子来纠正 Matrox TripleHead2Go 等平台上的三头监视器窗口定位,到目前为止,它对于 32 位程序运行良好,但现在我需要构建 64 位版本,我需要一些帮助将我的 x86 操作码转换为我在每个窗口类上安装的 wndproc thunk。
thunk 在 wndproc 调用中添加了一个额外的参数,这是原始的 wndproc 地址,这样我的 wndproc 处理程序就可以在最后调用它。
#ifdef _WIN64
//TODO: figure out the WIN64 instructions
#else
const unsigned char PatchTemplate[] =
{
0x90, // nop, will become int3 if debug = true
0x58, // pop eax (get the return address)
0x68, 0x00, 0x00, 0x00, 0x00, // push imm32, original wndproc address
0x50, // push eax (restore the return address)
0x68, 0x00, 0x00, 0x00, 0x00, // push imm32, our wndproc address
0xC3 // retn
};
#define PATCH_ORIG_OFFSET 3
#define PATCH_NEW_OFFSET 9
#endif
在 64 位模式下,前 4 个参数在寄存器
rcx
、rdx
、r8
和 r9
中传递。尽管如此,堆栈空间还是为它们分配的。
我们需要知道您传递了多少个参数,以便将额外的参数放在正确的位置。如果它是一个标准的 wndproc,它已经有 4 个参数。你的 32 位代码在开头插入新参数,所以我假设这是你的 C 原型,我们也必须在 64 位模式下执行相同的操作,这样在末尾附加新参数会更容易。
此外,堆栈必须保持 16 字节对齐,并且调用约定要求调用者释放参数(64 位模式下不再有 stdcall)。当然,调用者不知道额外的参数,因此无法正确恢复堆栈,因此我们必须自己执行此操作。
代码可能如下所示:
00000000 90 nop ; nop, will become int3 if debug = true
00000001 4883EC28 sub rsp, 40 ; allocate space for arguments
00000005 4C894C2420 mov [rsp + 32], r9 ; spill 4th arg to stack
0000000A 4D89C1 mov r9, r8 ; move 3rd arg
0000000D 4989D0 mov r8, rdx ; move 2nd arg
00000010 4889CA mov rdx, rcx ; move 1st arg
00000013 48B988776655443322- mov rcx, 0x1122334455667788 ; old wndproc
0000001C 11
0000001D 48B888776655443322- mov rax, 0x1122334455667788 ; new wndproc
00000026 11
00000027 FFD0 call rax ; call new wndproc
00000029 4883C428 add rsp, 40 ; restore stack
0000002D C3 ret
更新:这应该是附加旧 wndproc 作为第五个参数的版本:
00000000 90 nop ; nop, will become int3 if debug = true
00000001 4883EC28 sub rsp, 40 ; allocate space for arguments
00000005 48B888776655443322- mov rax, 0x1122334455667788 ; old wndproc
0000000E 11
0000000F 4889442420 mov [rsp + 32], rax ; add as 5th argument
00000014 48B888776655443322- mov rax, 0x1122334455667788 ; new wndproc
0000001D 11
0000001E FFD0 call rax ; call new wndproc
00000020 4883C428 add rsp, 40 ; restore stack
00000024 C3 ret