Указатель на функцию неверен в Visual Studio 2005, код начинается со смещения в 1 байт

Рассматриваемый код перехватывает файл explorer.exe, но он аварийно завершает работу при входе в функцию обратного вызова:

Необработанное исключение в 0x60055b50 (redacted.dll) в explorer.exe: 0xC0000005: место записи нарушения прав доступа 0x548b0cca.

Стек вызовов:

> redacted.dll! myCallWndProcRetCallback (int nCode = 0x00000000, без знака int, wParam=0x00000000, long lParam=0x015afa58) Строка 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 pword ptr [ebx+548B0CC4h] 
60055B56 и др.,18ч 
60055B58  mov         eax, pword 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 добавить esp,0Ch 
    if ( nCode == HC_ACTION && lParam!= NULL) {
60055B54  mov         edx,dword ptr [esp+18h] 
60055B58  mov         eax, pword ptr [g_callWndProcRetHook (600B9EE8h)] 
60055B5D  push        esi  

Это похоже на правильную разборку, но это на 1 байт позже, чем разборка выше! Вы можете видеть, что инструкции такие же, начиная с 0x60055B58 и далее.

Итак, похоже, что компоновщик говорит, что функция имеет значение 0x60055B50, но код фактически начинается с 0x60055B51. Я подтвердил, что первым является обратный вызов, установленный в хуке Windows. Поэтому, когда Windows перезванивает в функцию, она выполняет неверный код.

У меня есть вопрос, как компоновщик может сделать это неправильно? Я сделал восстановление, и проблема ушла, это кажется случайным. В то время, когда использовался параметр компоновщика /FORCE:MULTIPLE, но без него не сообщалось об ошибке связи для этого обратного вызова.

Позднее добавление: может ли это быть связано с перемещением или перебазированием DLL? Если перемещение было отключено на 1 байт, это может вызвать проблему?

1 ответ

Решение

Перестановки почти никогда не будут отключены на 1 байт; образ.dll должен быть выровнен с гранулярностью выделений, возвращаемых VirtualAlloc, которая должна быть 64 КБ на большинстве машин.

Как долго работает этот код? Если это случайно, то /FORCE:MULTIPLE может быть подозрительным. Или вы могли бы использовать Incredibuild...

Другие вопросы по тегам