有问题的代码挂接到 explorer.exe,但在进入回调函数时崩溃:
explorer.exe 中 0x60055b50 (redacted.dll) 处的未处理异常:0xC0000005:访问冲突写入位置 0x548b0cca。
调用栈:
> redacted.dll!myCallWndProcRetCallback(int nCode=0x00000000, unsigned int wParam=0x00000000, long lParam=0x015afa58) Line 799 C++ user32.dll!_DispatchHookW@16() + 0x31 字节 user32.dll!_fnHkINLPCWPRETSTRUCTW@20() + 0x5e 字节 user32.dll!___fnDWORD@4() + 0x24 字节 ntdll.dll!_KiUserCallbackDispatcher@12() + 0x13 字节 user32.dll!_NtUserMessageCall@28() + 0xc 字节 user32.dll!_SendMessageW@16() + 0x49 字节 explorer.exe!CTaskBand::_FindIndexByHwnd() + 0x21 字节 explorer.exe!CTaskBand::_HandleShellHook() + 0x48 字节 explorer.exe!CTaskBand::v_WndProc() + 0x660 字节 explorer.exe!CImpWndProc::s_WndProc() + 0x3f 字节
Visual Studio 2005 给出了以下反汇编:
--- c:\projects\redacted.cpp ------------------------- //------------------------------------------------ ------------------------------ LRESULT CALLBACK myCallWndProcRetCallback(int nCode, WPARAM wParam, LPARAM lParam) { 60055B50 inc dword ptr [ebx+548B0CC4h] 60055B56 和 al,18h 60055B58 mov eax,dword ptr [g_callWndProcRetHook (600B9EE8h)] 60055B5D推esi
而0x548B0CC4周围的内存都是?????? 所以它不是映射内存,因此崩溃。
myCallWndProcRetCallback 开头的机器代码是这样的:
0x60055B50:ff 83 c4 0c 8b 54 24 18 a1 e8 9e 0b 60 56 52 57 50 ff 15 8c a6 09 60 5f 5e 83 c4 08 c2 0c 00 cc 8b 4c 24 04 8b 01 8b 50
但 Visual Studio 有时也会为此函数提供以下反汇编:
--- c:\projects\redacted.cpp ------------------------- 60055B51 添加 esp,0Ch if ( nCode == HC_ACTION && lParam != NULL) { 60055B54 mov edx,dword ptr [esp+18h] 60055B58 mov eax,dword ptr [g_callWndProcRetHook (600B9EE8h)] 60055B5D推esi
这看起来像是正确的反汇编,但它比上面的反汇编晚 1 个字节!您可以看到从 0x60055B58 开始的指令是相同的。
因此,看起来链接器说函数位于 0x60055B50,但代码实际上从 0x60055B51 开始。我已经确认前者是设置到 Windows 挂钩中的回调。因此,当 Windows 回调函数时,它会执行错误的代码。
我的问题是链接器怎么会出错?我进行了重建,问题消失了,这似乎是随机的。当时 /FORCE:MULTIPLE 链接器选项有效,但如果没有它,则不会报告此回调的链接错误。
后期添加:这可能与 DLL 的重定位或变基有关吗?如果重定位偏移了 1 个字节,这可能会导致问题吗?