مؤشر الدالة غير صحيح في 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 ساري المفعول ولكن بدونه لم يتم الإبلاغ عن أي خطأ في الارتباط لرد الاتصال هذا.
إضافة متأخرة:هل يمكن أن يكون هذا مرتبطًا بنقل DLL أو إعادة تحديد موقعه؟إذا تم إيقاف النقل بمقدار بايت واحد، فربما يكون هذا هو سبب المشكلة؟
المحلول
لن يتم إيقاف عمليات النقل أبدًا بمقدار بايت واحد؛يجب أن تتم محاذاة صورة .dll مع دقة التخصيصات التي يتم إرجاعها بواسطة VirtualAlloc والتي يجب أن يكون حجمها 64 كيلو بايت على معظم الأجهزة.
كم من الوقت عمل هذا الرمز؟إذا كان عشوائيًا، فإن /FORCE:MULTIPLE قد يكون مشبوهاً.أو يمكنك استخدام Incredibuild ...