2

有问题的代码挂接到 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 个字节,这可能会导致问题吗?

4

1 回答 1

0

重定位几乎不会偏离 1 个字节;.dll 映像必须与 VirtualAlloc 返回的分配粒度对齐,在大多数机器上应该是 64k。

这段代码工作了多长时间?如果它是随机的,那么 /FORCE:MULTIPLE可能是可疑的。或者您可以使用 Incredibuild...

于 2009-01-22T23:59:27.480 回答