Visual Studio 2005 中的函数指针不正确,代码从 1 字节偏移量开始

发布于 2024-07-11 22:40:06 字数 2348 浏览 7 评论 0原文

有问题的代码挂接到explorer.exe,但在进入回调函数时崩溃:

Unhandled exception at 0x60055b50 (redacted.dll) in explorer.exe: 0xC0000005: Access violation writing location 0x548b0cca.

Callstack:

>     redacted.dll!myCallWndProcRetCallback(int nCode=0x00000000, unsigned int wParam=0x00000000, long lParam=0x015afa58)  Line 799  C++
      user32.dll!_DispatchHookW@16()  + 0x31 bytes    
      user32.dll!_fnHkINLPCWPRETSTRUCTW@20()  + 0x5e bytes  
      user32.dll!___fnDWORD@4()  + 0x24 bytes   
      ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x13 bytes      
      user32.dll!_NtUserMessageCall@28()  + 0xc bytes 
      user32.dll!_SendMessageW@16()  + 0x49 bytes     
      explorer.exe!CTaskBand::_FindIndexByHwnd()  + 0x21 bytes    
      explorer.exe!CTaskBand::_HandleShellHook()  + 0x48 bytes    
      explorer.exe!CTaskBand::v_WndProc()  + 0x660 bytes    
      explorer.exe!CImpWndProc::s_WndProc()  + 0x3f bytes   

Visual Studio 2005 给出以下反汇编:

--- c:\projects\redacted.cpp -------------------------
//------------------------------------------------------------------------------
LRESULT CALLBACK myCallWndProcRetCallback(int nCode, WPARAM wParam, LPARAM lParam) {
60055B50  inc         dword ptr [ebx+548B0CC4h] 
60055B56  and         al,18h 
60055B58  mov         eax,dword ptr [g_callWndProcRetHook (600B9EE8h)] 
60055B5D  push        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  add         esp,0Ch 
    if ( nCode == HC_ACTION && lParam != NULL) {
60055B54  mov         edx,dword ptr [esp+18h] 
60055B58  mov         eax,dword ptr [g_callWndProcRetHook (600B9EE8h)] 
60055B5D  push        esi  

这看起来像是正确的反汇编,但它比上面的反汇编晚 1 个字节! 您可以看到从 0x60055B58 开始的指令是相同的。

因此,看起来链接器说函数位于 0x60055B50,但代码实际上从 0x60055B51 开始。 我已经确认前者是设置到 Windows 挂钩中的回调。 因此,当 Windows 回调该函数时,它会执行错误的代码。

我的问题是链接器怎么会出错? 我进行了重建,问题就消失了,看起来是随机的。 当时 /FORCE:MULTIPLE 链接器选项有效,但如果没有它,则不会为此回调报告链接错误。

最新补充:这是否与 DLL 的重定位或变基有关? 如果重定位偏移了 1 个字节,这可能会导致问题吗?

The code in question hooks into explorer.exe but was crashing on entry to the callback function:

Unhandled exception at 0x60055b50 (redacted.dll) in explorer.exe: 0xC0000005: Access violation writing location 0x548b0cca.

Callstack:

>     redacted.dll!myCallWndProcRetCallback(int nCode=0x00000000, unsigned int wParam=0x00000000, long lParam=0x015afa58)  Line 799  C++
      user32.dll!_DispatchHookW@16()  + 0x31 bytes    
      user32.dll!_fnHkINLPCWPRETSTRUCTW@20()  + 0x5e bytes  
      user32.dll!___fnDWORD@4()  + 0x24 bytes   
      ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x13 bytes      
      user32.dll!_NtUserMessageCall@28()  + 0xc bytes 
      user32.dll!_SendMessageW@16()  + 0x49 bytes     
      explorer.exe!CTaskBand::_FindIndexByHwnd()  + 0x21 bytes    
      explorer.exe!CTaskBand::_HandleShellHook()  + 0x48 bytes    
      explorer.exe!CTaskBand::v_WndProc()  + 0x660 bytes    
      explorer.exe!CImpWndProc::s_WndProc()  + 0x3f bytes   

Visual Studio 2005 gave the following disassembly:

--- c:\projects\redacted.cpp -------------------------
//------------------------------------------------------------------------------
LRESULT CALLBACK myCallWndProcRetCallback(int nCode, WPARAM wParam, LPARAM lParam) {
60055B50  inc         dword ptr [ebx+548B0CC4h] 
60055B56  and         al,18h 
60055B58  mov         eax,dword ptr [g_callWndProcRetHook (600B9EE8h)] 
60055B5D  push        esi  

and the memory around 0x548B0CC4 is all ?????? so it is not mapped memory, hence the crash.

The machine code at the start of myCallWndProcRetCallback is this:

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 

But Visual Studio also sometimes gives the following disassembly for this function:

--- c:\projects\redacted.cpp -------------------------
60055B51  add         esp,0Ch 
    if ( nCode == HC_ACTION && lParam != NULL) {
60055B54  mov         edx,dword ptr [esp+18h] 
60055B58  mov         eax,dword ptr [g_callWndProcRetHook (600B9EE8h)] 
60055B5D  push        esi  

This looks like the correct disassembly but it is from 1 byte later than the disassembly above! You can see the instructions are the same from 0x60055B58 onward.

So, it looks like the linker says the function is at 0x60055B50 but the code actually starts at 0x60055B51. I have confirmed the former is the callback set into the Windows hook. So when Windows calls back into the function it executes bad code.

The question I have is how the linker could get this wrong? I did a rebuild and the problem went away, it seems random. At the time the /FORCE:MULTIPLE linker option was in effect but without it no link error is reported for this callback.

A late addition: Could this be related to the relocation or rebasing of a DLL? If the relocation was off by 1 byte, this could perhaps cause the problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怂人 2024-07-18 22:40:06

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

这段代码有效了多久? 如果它是随机的,那么 /FORCE:MULTIPLE 可能值得怀疑。 或者您可以使用 Incredibuild...

Relocations will almost never be off by 1 byte; the .dll image has to be aligned to the granularity of allocations returned by VirtualAlloc which should be 64k on most machines.

How long has this code worked? If it's random then the /FORCE:MULTIPLE might be suspect. Or you could be using Incredibuild...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文