عندما أقوم بفحص أمان البرنامج ، فإن إحدى النقاط التي يجب التحقق منها تعمل مع المكتبات الديناميكية. هجمات مثل DLL الخطف ("دلل خداع" أو "دلل اعتراض") نادرة جدا. على الأرجح ، يرجع ذلك إلى حقيقة أن مطوري Windows يضيفون آليات أمنية لمنع الهجمات ، وأن مطوري البرامج أكثر حرصًا على الأمان. ولكن الأمر الأكثر إثارة للاهتمام هو الموقف عندما يكون البرنامج المستهدف ضعيفًا.
بإيجاز للهجوم ، تقوم DLL hijack بإنشاء موقف يحاول فيه بعض الملفات القابلة للتنفيذ تحميل dll ، لكن المهاجم يتدخل في هذه العملية ، وبدلاً من المكتبة المتوقعة ، يتم تحميل dll معد خصيصًا مع حمولة من المهاجم. نتيجة لذلك ، سيتم تنفيذ الرمز من dll مع حقوق التطبيق الذي تم إطلاقه ، وبالتالي يتم اختيار التطبيقات ذات الحقوق الأعلى عادةً كهدف.
لكي يتم تحميل المكتبة بشكل صحيح ، يجب استيفاء عدد من الشروط: حجم بت الملف القابل للتنفيذ ويجب أن تتطابق مع المكتبة ، وإذا تم تحميل المكتبة عند بدء تشغيل التطبيق ، فيجب على dll تصدير جميع الوظائف التي يتوقع هذا التطبيق استيرادها. في كثير من الأحيان ، لا يكفي استيراد واحد - من المستحسن للغاية أن يواصل التطبيق عمله بعد تحميل dll. لهذا ، من الضروري أن تعمل وظائف المكتبة المعدة بنفس الطريقة التي تعمل بها المكتبة الأصلية. أسهل طريقة للقيام بذلك هي ببساطة عن طريق تمرير استدعاءات الوظائف من مكتبة إلى أخرى. هذه هي dlls تسمى dlls الوكيل.

تحت القص سيكون هناك العديد من الخيارات لإنشاء مثل هذه المكتبات - سواء في شكل تعليمات برمجية أو أدوات مساعدة.
مراجعة نظرية صغيرة
غالبًا ما يتم تحميل المكتبات باستخدام وظيفة LoadLibrary ، والتي يتم تمرير اسم المكتبة إليها. إذا قمت بدلاً من الاسم بتمرير المسار الكامل ، فسيحاول التطبيق تحميل المكتبة المحددة. على سبيل المثال ، يؤدي استدعاء LoadLibrary ("C: \ Windows \ system32 \ version.dll") إلى تحميل dll المحدد. أو ، إذا كانت المكتبة غير موجودة ، فلن يتم تحميلها.
قليلا من التعبإذا تم بالفعل تحميل بعض دلل في التطبيق ، فلن يتم تحميله مرة أخرى. نظرًا لأن version.dll يتم تحميله في بداية أي ملف exe تقريبًا ، في الواقع ، فإن المكالمة المذكورة أعلاه لن يتم تحميل أي شيء بالفعل. لكننا ما زلنا نعتبر الحالة العامة ، والنظر في المثال على أنه دعوة إلى مكتبة مجردة.
إنها مسألة أخرى إذا كتبت LoadLibrary ("version.dll"). في الحالة العادية ، ستكون النتيجة هي نفسها تمامًا كما في الحالة السابقة - سيتم تحميل C: \ Windows \ system32 \ version.dll ، ولكن ليس بهذه البساطة.
أولاً ، سيتم البحث في مكتبة ، والتي ستذهب
بالترتيب التالي:
- مجلد قابل للتنفيذ
- المجلد C: \ ويندوز \ System32
- المجلد C: \ ويندوز \ النظام
- المجلد C: \ ويندوز
- المجلد تعيين الحالي للتطبيق
- مجلدات من متغير بيئة PATH
بعض المزيد من الشحعند بدء تشغيل تطبيقات 32 بت على نظام 64 بت ، سيتم إعادة توجيه جميع المكالمات إلى C: \ Windows \ system32 إلى C: \ Windows \ SysWOW64. هذا فقط من أجل دقة الوصف ، من وجهة نظر المهاجم ، الفرق ليس مهم بشكل خاص.
عندما تقوم بتشغيل ملف exe ، يقوم نظام التشغيل بتحميل جميع المكتبات من قسم استيراد الملف. بشكل عام ، يمكننا أن نفترض أن نظام التشغيل يفرض على الملف الاتصال بـ LoadLibrary ، بتمرير جميع أسماء المكتبات المكتوبة في قسم الاستيراد. نظرًا لوجود أسماء وليس مسارات في 99.9٪ من الحالات ، عند بدء تشغيل التطبيق ، سيتم البحث في جميع المكتبات المحملة في النظام.
من قائمة مواقع بحث dll ، هناك نقطتان مهمتان حقًا بالنسبة لنا - 1 و 6. إذا وضعنا version.dll في نفس المجلد من حيث يتم تشغيل الملف ، فبدلاً من النظام ، سيتم تحميل الملف المحمل. لا تتم مواجهة هذا الموقف تقريبًا ، لأنه إذا كانت هناك فرصة لوضع مكتبة ، فمن المحتمل على الأرجح استبدال الملف القابل للتنفيذ نفسه. ولكن لا يزال ، مثل هذه الحالات ممكنة. على سبيل المثال ، إذا كان الملف القابل للتنفيذ موجودًا في مجلد قابل للكتابة وكان خدمة ذات بدء تشغيل تلقائي ، فلا يمكن تغييرها أثناء تشغيل الخدمة نفسها. أو يتم فحص الملف الذي تم تشغيله خارجيًا عن طريق المجموع الاختباري قبل البدء ، ثم استبدال الملف لا يزال غير خيار. لكن وضع المكتبة بجوارها سيكون حقيقيًا تمامًا.
قد لا تتمكن من إنشاء ملفات بجانب الملفات القابلة للتنفيذ ، ولكن يمكنك إنشاء مجلدات. في هذه الحالة ، قد تعمل آلية إعادة توجيه WinSxS (المعروفة أيضًا باسم "DotLocal").
لفترة وجيزة حول DotLocalقد يحتوي ملف البيان على تبعية على مكتبة إصدار محدد. في هذه الحالة ، عند بدء تشغيل الملف القابل للتنفيذ (على سبيل المثال ، اجعله application.exe) ، سيقوم نظام التشغيل بالتحقق من وجود مجلد باسم application.exe.local في نفس المجلد مثل الملف نفسه. يجب أن يحتوي هذا المجلد على مجلد فرعي باسم معقد مثل amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.9600.19291_none_6248a9f3ecb5e89b بداخله توجد مكتبة comctl32.dll بداخله. يجب الإشارة إلى اسم المكتبة والمعلومات الخاصة باسم المجلد في البيان ، وهذا مجرد مثال من العملية الأولى التي ظهرت. إذا لم يكن هناك مجلدات أو ملف ، فسيتم أخذ المكتبة من C: \ Windows \ WinSxS. في المثال ، C: \ Windows \ WinSxS \ amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.9600.19291_none_6248a9f3ecb5e89b \ comctl32.dll.
ولكن هذا هو الاستثناء أكثر من القاعدة. لكن الحالات التي يصل فيها بحث dll إلى الرقم السادس في القائمة حقيقية تمامًا. إذا حاول التطبيق تحميل dll غير موجود على النظام أو بجانب الملف ، فسترتفع جميع عمليات البحث إلى 6 نقاط ، مما قد يكون مجلدات قابلة للكتابة.
على سبيل المثال ، يحدث تثبيت Python النموذجي غالبًا في المجلد C: \ Python (أو الإغلاق). يقترح برنامج تثبيت python نفسه إضافة مجلداته إلى متغير نظام PATH. نتيجة لذلك ، لدينا نقطة انطلاق جيدة لبدء الهجوم - المجلد قابل للكتابة من قبل جميع المستخدمين وأي محاولة لتحميل مكتبة غير موجودة ستذهب إلى البحث عن المسار من PATH.
الآن وقد اكتملت النظرية ، فكر في إنشاء الحمولة - المكتبات الفرعية نفسها.
الخيار الأول. مكتبة وكيل صادقة
لنبدأ بمكتب بسيط نسبيًا - سنقوم بإنشاء مكتبة وكيل نزيهة. الصدق في هذه الحالة يعني أن جميع الوظائف في دلل سيتم تسجيلها بشكل صريح ، ولكل وظيفة سيتم استدعاء استدعاء وظيفة بنفس الاسم من المكتبة الأصلية. سيكون العمل مع هذه المكتبة شفافًا تمامًا للرمز المدعوم: إذا كانت تستدعي بعض الوظائف ، فسوف تتلقى الإجابة الصحيحة والنتيجة وكل شيء يجب أن يحدث جنبًا إلى جنب.
فيما يلي رابط للمثال النهائي (
github ) لمكتبة version.dll.
أبرز رمز:
- جميع النماذج الوظيفية من جدول تصدير المكتبة الأصلية موصوفة بصدق.
- يتم تحميل المكتبة الأصلية ويتم طرح جميع المكالمات إلى وظائفنا فيها.
ملائمًا ، يستمر التطبيق في العمل بشكل صحيح ، دون مواجهة أي "مؤثرات خاصة".
من غير المريح أن اضطررت إلى كتابة مجموعة من الكود الموحد لكل وظيفة ، والتحقق بعناية من تزامن النماذج الأولية.
الخيار الثاني. تبسيط كتابة التعليمات البرمجية
عند التعامل مع مكتبة مثل version.dll ، حيث يكون جدول الاستيراد صغيرًا ، هناك 17 وظيفة فقط ، والنماذج الأولية بسيطة ، ثم تعد مكتبة الوكيل الصادقة خيارًا جيدًا.

ولكن إذا كان وكيل المكتبة ، على سبيل المثال ، bcrypt ، فكل شيء أكثر تعقيدًا. وهنا جدول الاستيراد لها:

57 ميزات! وإليك بعض الأمثلة على النماذج الأولية:


دعنا نقول فقط أنه لا يوجد شيء مستحيل ، ولكن صنع وكيل نزيه لمثل هذه المكتبة ليس لطيفًا جدًا.
يمكنك تبسيط الكود إذا كنت تغش قليلاً في الوظائف. سوف نعلن أن جميع الوظائف في المكتبة هي __declspec (عارية) ، وفي الجسم ، سنستخدم كود التجميع الذي يجعل jmp في الوظيفة من المكتبة الأصلية. سيتيح لنا ذلك عدم استخدام نماذج أولية طويلة ، ولكن نضع إعلانات بسيطة في كل مكان دون عرض معلمات:
فو فو ()
عندما يستدعي التطبيق وظيفتنا ، فإن مكتبة البروكسي لن تقوم بأي معالجة مع السجل والمكدس ، مما يسمح للوظيفة الأصلية بالقيام بكل العمل كما ينبغي.
مثال (
github ) لمكتبة version.dll مع هذا النهج.
أبرز الملامح:
- يتم تحميل المكتبة الأصلية ، ويتم طرح جميع المكالمات إلى وظائفنا فيها. يتم التفاف الهيئات وظيفة والتحميل في وحدات الماكرو.
التشغيل المريح والصحيح للتطبيق وحقيقة أنه يمكن وصف عدد كبير من الوظائف بسهولة بفضل وحدات الماكرو.
من غير المريح أن أشعل النار بشكل غير متوقع في x64. يحظر Visual Studio (في مكان ما منذ عام 2012 ، إذا كنت أتذكر بشكل صحيح) استخدام إدخالات عارية وأسمم في رمز 64 بت. عند كتابة وكيل من نقطة الصفر ، من الضروري أن تتحقق كل وظيفة من وصفها في ملف def ، وأن الأصل قد تم تحميله ، وتم وصف نص الوظيفة.
الخيار الثالث. نرمي الجسم بشكل عام
باستخدام عارية يوحي خيار واحد أكثر. يمكنك إنشاء جدول استيراد ، والذي يشير لجميع الوظائف إلى سطر واحد حقيقي من الكود:
باطل nop () {}
سيتم تحميل هذه المكتبة بواسطة التطبيق ، لكنها لن تعمل. عند استدعاء أي من الوظائف ، من المحتمل أن يتم هز الحزمة أو سيحدث بعض الوحل الآخر. لكن هذا ليس سيئًا دائمًا - على سبيل المثال ، إذا كان هدف حقن dll هو ببساطة تشغيل التعليمات البرمجية مع الحقوق اللازمة ، فهذا يكفي لتنفيذ الحمولة النافعة من مكتبة الوكيل DllMain وإنهاء التطبيق بهدوء على الفور. في هذه الحالة ، لن يتم استدعاء مكالمة حقيقية للوظائف ، ولن يكون هناك أعطال في الأخطاء.
مثال على
github ، مرة أخرى ل version.dll.
أبرز رمز:
- تشير جميع وظائف ملف def إلى وظيفة nop واحدة.
مريح مثل مكتبة الوكيل هو مكتوب فقط لبضع دقائق.
من غير المريح توقف التطبيق الذي تم الاتصال به عن العمل.
الخيار الرابع. خذ المرافق الجاهزة
تعد كتابة dll جيدة ، ولكنها ليست مريحة دائمًا وليست سريعة جدًا ، لذلك يجب عليك التفكير في الخيارات الآلية.
يمكنك اتباع مسار الفيروسات القديمة - خذ المكتبة التي نريد إنشاء وكلاء لها ، وإنشاء قسم قابل للتنفيذ من الشفرة فيه ، وكتابة الحمولة الصافية هناك وتغيير نقطة الإدخال إلى هذا القسم. ليست أسهل طريقة ، لأنه يمكنك كسر شيء بطريق الخطأ ، عليك أن تكتب في مجمع ، وتذكر جهاز ملف PE. هذه ليست طريقتنا.
لتشغيل dll hijack سنقوم بإضافة dll hijack آخر.

هذا سهل نسبيا للقيام به. نقوم بنسخ المكتبة التي نريد عمل وكيل لها وإضافة بعض الدلائل مع وظيفة تعسفية لجدول الاستيراد من هذه النسخة. الآن سيمضي التنزيل على طول السلسلة - في بداية الملف القابل للتنفيذ ، سيتم تحميل ملف dll الوكيل ، والذي سيتم تحميل المكتبة المحددة نفسها.
"مهلا ، لقد قمت باستبدال تحميل مكتبة بأخرى. ما هي النقطة؟ كل نفس سيكون من الضروري رمز دلل! ". كل شيء صحيح ، ولكن لا يزال هناك شعور. الآن مكتبة الحمولة النافعة سيكون لها متطلبات أقل. يمكنك تحديد أي اسم ، الشيء الرئيسي هو تصدير وظيفة واحدة فقط ، والتي يمكن أن يكون لها أي نموذج أولي. أدخل الاسم الرئيسي للمكتبة وأعمل في جدول الاستيراد.
يمكن أن تكون المكتبة ذات الحمولة النافعة واحدة لجميع المناسبات.
يمكنك تعديل جدول الاستيراد مع العديد من برامج تحرير PE ، على سبيل المثال CFF explorer أو pe-bear. بنفسي ، كتبت أداة صغيرة في C # تقوم بتصحيح جدول دون إيماءات غير ضرورية. مصادر على
جيثب ، بينار في قسم
الإصدار .
استنتاج
في المقالة ، حاولت الكشف عن الطرق الأساسية لإنشاء وكيل dll ، والذي استخدمته بنفسي. يبقى فقط لمعرفة كيفية الدفاع.
لا يوجد العديد من التوصيات العالمية:
- لا تقم بتخزين الملفات القابلة للتنفيذ ، خاصة تلك التي تعمل بأذونات عالية ، في مجلدات قابلة للكتابة للمستخدمين.
- من الأفضل أن تجد أولاً وتأكد من وجود المكتبة قبل القيام بـ LoadLibrary.
- انظر إلى طرق الحماية الحالية المتوفرة في نظام التشغيل. على سبيل المثال ، في نظام التشغيل Windows 10 ، يمكنك تعيين علامة PreferSystem32 بحيث لا يبدأ بحث dll مع مجلد الملف القابل للتنفيذ ، ولكن مع system32.
شكرًا لك على اهتمامك ، سأكون سعيدًا لسماع الأسئلة والاقتراحات والاقتراحات والتعليقات.
محدث: بناءً على نصيحة المعلقين ، أذكرك بأنك بحاجة إلى اختيار مكتبة بعناية وبعناية. إذا تم تضمين المكتبة في قائمة KnownDlls أو كان الاسم مشابهًا لـ MinWin (ApiSetSchema ، api-ms-win-core-console-l1-1-0.dll - هذا كل شيء) ، فمن المرجح أنه لن يكون من الممكن اعتراضها نظرًا لميزات المعالجة هذه dlls في نظام التشغيل.