Неверный указатель на функцию в Visual Studio 2005, код начинается со смещения в 1 байт
-
19-08-2019 - |
Вопрос
Рассматриваемый код подключается к explorer.exe но произошел сбой при входе в функцию обратного вызова:
Unhandled exception at 0x60055b50 (redacted.dll) in explorer.exe: 0xC0000005: Access violation writing location 0x548b0cca.
Стек вызовов:
> 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 linker, но без нее для этого обратного вызова не сообщается об ошибке ссылки.
Позднее дополнение:Может ли это быть связано с перемещением или перебазированием библиотеки DLL?Если перемещение было отклонено на 1 байт, возможно, это могло вызвать проблему?
Решение
Перемещения почти никогда не будут отклоняться на 1 байт;.образ dll должен быть выровнен с детализацией выделений, возвращаемых VirtualAlloc, которая должна составлять 64 кб на большинстве компьютеров.
Как долго работает этот код?Если это случайно, то /FORCE:МНОЖЕСТВЕННЫЙ мог бы будьте подозрительны.Или вы могли бы использовать Incredibuild...