سوف يركز هذا المنشور على الوحدات النمطية الاصطناعية ورموز محرك تصحيح الأخطاء لـ Windows (مشغل مصحح الأخطاء). بمعنى ، حول الكيانات التي يمكن إضافتها بشكل مصطنع إلى مصحح الأخطاء لتلوين عناوين الذاكرة.

وحدات الاصطناعية
بشكل عام ، الوحدة النمطية كجزء من مشغل مصحح الأخطاء هي منطقة معينة متصلة من الذاكرة الظاهرية: العنوان الأساسي للوحدة النمطية (عنوان البايت الأول من الملف المسقط) وحجمها. لكل نوع من أنواع تصحيح الأخطاء (تحليل الأخطاء / التفريغ المباشر ، وضع المستخدم / وضع kernel ، وما إلى ذلك) ، لدى المصحح آليته الخاصة لقراءة وتحديث قائمة الوحدات النمطية المحملة. أسهل طريقة لفرض قائمة الوحدات النمطية المحملة التي يتم تحديثها هي أمر .reload مع الخيار / s .
إذا تحدثنا ، على سبيل المثال ، عن التصحيح المباشر لعملية وضع المستخدم ، يتم بناء قائمة الوحدات النمطية المحمّلة وفقًا لثلاثة قوائم رئيسية من المُحمل : قائمة بترتيب تحميل الوحدة النمطية (InLoadOrderModuleList) ، وقائمة بالوحدات النمطية في الذاكرة (InMemoryOrderModuleList) وقائمة أولويات التهيئة. من ناحية ، لا شيء ( تقريبا ) يمنعنا من أخذ بيانات تعسفية (من ملف PE على القرص ، على سبيل المثال) ووضع علامة عليها في الذاكرة للتنفيذ بأيدينا. من ناحية أخرى ، منذ فترة طويلة تقنيات إزالة DLL محملة بالوسائل العادية من قوائم محمل الثلاثة المذكورة أعلاه (إخفاء الوحدة النمطية) معروفة.
في كلتا الحالتين ، عند تصحيح هذا الموقف ، سيكون من المفيد وضع علامة على مساحة الوحدة النمطية المخفية. لهذا ، وحدات الاصطناعية هي مناسبة. كتجربة عملية ، يمكنك ببساطة جعل WinDbg يسقط الوحدة المحملة من قائمته الداخلية بنفس الأمر .reload ، ولكن مع خيار / u .
علاوة على ذلك ، في جودة القوائم المدرجة ، سأستخدم التصحيح المعتاد لعملية وضع المستخدم (notepad.exe). أولاً ، تذكر العنوان الأساسي لوحدة ntdll (0x07ffa8a160000) وحساب حجمها (0x01e1000):
0:007> lm m ntdll Browse full module list start end module name 00007ffa`8a160000 00007ffa`8a341000 ntdll 0:007> ? 00007ffa`8a341000-00007ffa`8a160000 Evaluate expression: 1970176 = 00000000`001e1000
ضع في اعتبارك قائمة بوظيفة RtlFreeSid البسيطة من الوحدة النمطية ntdll ، والتي تستدعي وظيفة RtlFreeHeap من هذه الوحدة ، مع تذكر عناوين الأحرف RtlFreeSid و RtlFreeHeap (0x7ffa8a1cbc20 و 0x7ffa8a176df0) في نفس الوقت:
0:007> uf ntdll!RtlFreeSid ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
أيضًا ، وفقًا لقائمة البيانات ، من السهل حساب حجم الدالة ntdll! RtlFreeSid:
0:007> ? 00007ffa`8a1cbc51 - 0x07ffa8a1cbc20 Evaluate expression: 49 = 00000000`00000031
وحجم ntdll! وظيفة RtlFreeHeap ليست مهمة لتجربتنا ، لذلك من أجل البساطة يمكنك أن تأخذها على قدم المساواة مع بايت واحد.
الآن محاكاة إخفاء وحدة ntdll:
0:007> .reload /u ntdll Unloaded ntdll
حقل هذا العمل بعنوان ntdll! RtlFreeSid في مصحح الأخطاء ليس غني بالمعلومات (ويمكنك بالفعل الوصول إلى بداية الدالة فقط بواسطة العنوان الظاهري):
0:007> uf 00007ffa`8a1cbc20 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call 00007ffa`8a176df0 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
لإضافة وحدة تركيبية ، تحتاج إلى استدعاء واجهة البرنامج IDebugSymbols3 :: AddSyntheticModule . لا توجد ببساطة أوامر مدمجة لإجراء هذه المكالمة (حسب علمي). اقترح Mikhail I. Izmestev أن هناك آلية مماثلة - نفس التحميل . ولكن مع الاسم والعنوان ومعلمات الحجم: "الوحدة النمطية = العنوان والحجم" (وربما يتم تنفيذها على وحدات تركيبية).
.reload ntdll = 00007ff8`470e1000،001e1000 0:007> .reload ntdll=00007ff8`470e1000,001e1000 *** WARNING: Unable to verify timestamp for ntdll *** ERROR: Module load completed but symbols could not be loaded for ntdll 0:007> uf 00007ff8`4714bc20 ntdll+0x6ac20: 00007ff8`4714bc20 4053 push rbx 00007ff8`4714bc22 4883ec20 sub rsp,20h 00007ff8`4714bc26 488bd9 mov rbx,rcx 00007ff8`4714bc29 33d2 xor edx,edx 00007ff8`4714bc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ff8`4714bc34 4c8bc3 mov r8,rbx 00007ff8`4714bc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ff8`4714bc3b e8b0b1faff call ntdll+0x15df0 (00007ff8`470f6df0) 00007ff8`4714bc40 33c9 xor ecx,ecx 00007ff8`4714bc42 85c0 test eax,eax 00007ff8`4714bc44 480f45d9 cmovne rbx,rcx 00007ff8`4714bc48 488bc3 mov rax,rbx 00007ff8`4714bc4b 4883c420 add rsp,20h 00007ff8`4714bc4f 5b pop rbx 00007ff8`4714bc50 c3 ret
حسنًا ، سوف نستخدم ملحق مصحح الأخطاء ، وهنا pykd سيأتي إلى الإنقاذ
. في الإصدار الأخير (في وقت الكتابة) 0.3.4.3 ، تمت إضافة وظائف لإدارة الوحدات الاصطناعية: addSyntheticModule (...) (وهو أمر ضروري في حالتنا) و removeSyntheticModule (...).
باستخدام العنوان الأساسي وحجم الوحدة النمطية التي تم حفظها مسبقًا ، نضيف معلومات حول وحدة ntdll المخفية إلى مصحح الأخطاء (في حالة حدوث خطأ ، سيتم طرح استثناء ، لذلك يعد التنفيذ الصامت علامة على النجاح ، ويمكن تجاهل تحذيرات الطباعة):
0:007> !py Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> addSyntheticModule(0x07ffa8a160000, 0x01e1000, 'ntdll') *** WARNING: Unable to verify timestamp for ntdll >>> exit()
الآن أصبحت قائمة المفكك أكثر إفادة:
0:007> uf 00007ffa`8a1cbc20 ntdll+0x6bc20: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll+0x16df0 (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
بتعبير أدق ، نرى أن الوظيفة داخل الوحدة النمطية ntdll تستدعي وظيفة أخرى داخل الوحدة النمطية نفسها.
الرموز الاصطناعية
أصبحت القائمة ، بعد إضافة وحدة تركيبية ، أكثر إفادة ، ولكنها لا تزال غير بليغة مثل الأصل الأصلي. يفتقر إلى الأحرف (في حالتنا ، أسماء الدالتين RtlFreeSid و RtlFreeHeap). لإصلاح ذلك ، يلزم إجراء مكالمة مرة أخرى ، ولكن من أجل واجهة برنامج مختلفة - IDebugSymbols3 :: AddSyntheticSymbol . Pykd مرة أخرى
على استعداد لمساعدتنا في هذا:
0:007> !py Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> addSyntheticSymbol(0x07ffa8a1cbc20, 0x31, 'RtlFreeSid') <pykd.syntheticSymbol object at 0x0000014D47699518> >>> addSyntheticSymbol(0x07ffa8a176df0, 1, 'RtlFreeHeap') <pykd.syntheticSymbol object at 0x0000014D476994A8> >>> exit()
تشبه النتيجة إلى حد كبير النتيجة عند استخدام الرموز من ملف pdb ntdll:
0:007> uf 00007ffa`8a1cbc20 ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
ملامح الكيانات الاصطناعية
تجدر الإشارة إلى أن إنشاء الرموز الاصطناعية مسموح به في أي وحدات موجودة ، وليس فقط في تلك الاصطناعية. وهذا يعني أنه يمكنك إضافة رموز إلى الوحدات النمطية التي بها ملفات pdb يمكن الوصول إليها ، وإلى الوحدات النمطية التي ليس لدينا ملفات بها معلومات تصحيح الأخطاء. ولكن لا يمكنك إنشاء أحرف خارج الوحدات النمطية. وهذا يعني أنه من أجل تحديد عنوان ذاكرة تعسفي خارج حدود الوحدات النمطية الحالية ، يجب أولاً إنشاء وحدة تركيبية مغلفة ، ثم (إذا لزم الأمر ، لأن اسم الوحدة قد يكون كافيًا جدًا للتلوين ) ، قم بإنشاء رمز اصطناعي فيه.
تجدر الإشارة أيضًا إلى أنه يمكن إزالة الوحدات والرموز الاصطناعية بحركة غير مبهمة لليد:
- إعادة تحميل رموز تصحيح الوحدة النمطية يحذف كافة الرموز الاصطناعية لهذه الوحدة النمطية ؛
- إعادة تحميل جميع الوحدات سوف يزيل جميع الوحدات الاصطناعية.
على الرغم من أن استخدام pykd مناسب في الغالبية العظمى من الحالات (خاصة بالنظر إلى وجود bootstarpper لها) ، في بعض الأحيان يمكنك الدخول في موقف حيث سيكون عليك بذل جهد كبير لاستخدام pykd. على سبيل المثال ، كنت بحاجة إلى تصحيح الأخطاء من جهاز host'ovy الذي يعمل عليه نظام Windows XP. كما اتضح فيما بعد ، لم يدعم pykd نظام التشغيل XP لبعض الوقت ، وكنت بحاجة إلى أحرف ووحدات تركيبية. يبدو لي أنه بالنسبة لهذه المهمة ، من السهل تجميع ملحق صغير منفصل سيؤدي إلى حل نطاق ضيق من المهام الضرورية بدلاً من استعادة دعم XP الكامل ل pykd. نتيجة لذلك ، تم إنشاء مشروع منفصل !
هذا امتداد بسيط يحتوي على تصديرين متاحين للمستخدم:
- ! synexts.addsymbol - ينشئ رمزًا اصطناعيًا في أي وحدة نمطية موجودة ؛
- ! synexts.addmodule - تنشئ وحدة تركيبية في القائمة الداخلية لمحرك تصحيح الأخطاء.
للتوضيح ، نقوم بمحاكاة إخفاء وحدة ntdll مرة أخرى:
0:007> .reload /u ntdll Unloaded ntdll 0:007> uf 00007ffa`8a1cbc20 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call 00007ffa`8a176df0 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret
مرة أخرى ، نستعيد معرفة الوحدة والرموز في شكل كيانات اصطناعية ، ولكن باستخدام امتداد! Synexts بالفعل:
0:007> !synexts.addmodule ntdll C:\Windows\System32\ntdll.dll 00007ffa`8a160000 0x01e1000 *** WARNING: Unable to verify timestamp for C:\Windows\System32\ntdll.dll Synthetic module successfully added 0:007> !synexts.addsymbol RtlFreeSid 00007ffa`8a1cbc20 31 Synthetic symbol successfully added 0:007> !synexts.addsymbol RtlFreeHeap 00007ffa`8a176df0 1 Synthetic symbol successfully added
من المفترض أنك قمت بالفعل بنسخ مكتبة synexts.dll المترجمة (المطابقة لعمق البت المستخدم بواسطة WinDbg) إلى دليل winext الخاص بالمصحح:
0:007> .chain Extension DLL search Path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\WINXP;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\arcade;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\pri;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64;<…> Extension DLL chain: pykd.pyd: image 0.3.4.3, API 1.0.0, built Thu Jan 10 19:56:25 2019 [path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\pykd.pyd] synexts: API 1.0.0, built Fri Jan 18 17:38:17 2019 [path: C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\synexts.dll] <…>
ومرة أخرى نرى نتيجة إضافة أحرف تركيبية إلى الوحدة الاصطناعية:
0:007> uf 00007ffa`8a1cbc20 ntdll!RtlFreeSid: 00007ffa`8a1cbc20 4053 push rbx 00007ffa`8a1cbc22 4883ec20 sub rsp,20h 00007ffa`8a1cbc26 488bd9 mov rbx,rcx 00007ffa`8a1cbc29 33d2 xor edx,edx 00007ffa`8a1cbc2b 65488b0c2560000000 mov rcx,qword ptr gs:[60h] 00007ffa`8a1cbc34 4c8bc3 mov r8,rbx 00007ffa`8a1cbc37 488b4930 mov rcx,qword ptr [rcx+30h] 00007ffa`8a1cbc3b e8b0b1faff call ntdll!RtlFreeHeap (00007ffa`8a176df0) 00007ffa`8a1cbc40 33c9 xor ecx,ecx 00007ffa`8a1cbc42 85c0 test eax,eax 00007ffa`8a1cbc44 480f45d9 cmovne rbx,rcx 00007ffa`8a1cbc48 488bc3 mov rax,rbx 00007ffa`8a1cbc4b 4883c420 add rsp,20h 00007ffa`8a1cbc4f 5b pop rbx 00007ffa`8a1cbc50 c3 ret