
أداة فك ضغط وتسجيل تلقائي للملفات التي تستهدف إطار عمل DotNet Framework
أداة فك ضغط وتسجيل تلقائية تستهدف ملفات إطار عمل .NET! تم الكشف عن هذه الأداة في Black Hat USA 2022. وفي Black Hat Asia 2023، تم نشر DotDumperGUI وDotDumperNative، إلى جانب الإصدار 1.1-stable من DotDumper. من المفترض استخدام هذه الأدوات الثلاث معًا، حيث يتطلب DotDumper 1.1-stable وجود مكتبات DotDumperNative، بينما يُستخدم DotDumperGUI كواجهة مستخدم رسومية لفتح وتصفية مخرجات JSON من عمليات تشغيل DotDumper.
غالبًا ما يُعتبر الكشف التلقائي والتصنيف الموثوق لأي ملف معين هو الكأس المقدسة لتحليل البرامج الضارة. والمشاكل والعقبات التي تواجه الوصول إلى ذلك كثيرة، ولهذا السبب يحظى إنشاء مثل هذا النظام بتقدير كبير. عندما يتعلق الأمر بالملفات الثنائية التي تستهدف .NET، تهدف أداتنا مفتوحة المصدر الجديدة DotDumper إلى المساعدة في العديد من الخطوات الحاسمة على طول الطريق: تسجيل النشاط (في الذاكرة)، تفريغ أجزاء الذاكرة المثيرة للاهتمام، واستخراج الخصائص من العينة المعطاة.
باختصار، فك الضغط اليدوي هو عملية شاقة تستهلك وقتًا غير متناسب من المحللين. تزيد الملفات الثنائية المُبهمة من الوقت الذي يجب أن يقضيه المحلل لفك ضغط ملف معين. عند توسيع نطاق ذلك، تحتاج المؤسسات إلى العديد من المحللين الذين يشخصون البرامج الضارة يوميًا، ربما بالاقتران مع صندوق حماية قابل للتوسع. يمكن استخدام الوقت الثمين المفقود في التعمق في الحملات أو العينات المثيرة للاهتمام للكشف عن تهديدات جديدة، بدلاً من البرامج الضارة العامة المبتذلة المنتشرة على نطاق واسع. بعد كل شيء، يبحث المحللون عن الإبر القليلة في كومة القش.
إذن، ما الفرق الذي يحدثه DotDumper؟ تشغيل عينة برنامج ضار قائم على .NET عبر DotDumper يوفر ملفات سجل لاستدعاءات الدوال الحاسمة والمُسيّقة والشائعة بثلاثة تنسيقات (نص عادي مقروء للبشر، JSON، وXML)، بالإضافة إلى نسخ من أجزاء الذاكرة المفيدة. على هذا النحو، يمكن للمحلل تصفح سجل استدعاءات الدوال. بالإضافة إلى ذلك، يمكن فحص الملفات المُفرَّغة لتصنيفها، مما يوفر رؤية إضافية للعينة الضارة والبيانات التي تحتويها. وهذا يقلل من الوقت الحاسم لعمليات التصنيف الأولي والاستجابة للحوادث، ويوفر وقت محللي SOC والباحثين لاحتياجات تحليلية أكثر تعقيدًا.
لتسجيل وتفريغ استدعاءات الدوال المُسيّقة ونتائجها، يستخدم DotDumper مزيجًا من الانعكاس والخطافات المدارة، وكلها مكتوبة بلغة C# نقية. أدناه، سيتم إبراز الميزات الرئيسية وتفصيلها، بالإضافة إلى مقتطفات من نتائج DotDumper لعينة من برنامج AgentTesla سارق البيانات المعبأ، والتي توجد تجزئاتها أدناه.
| نوع التجزئة | قيمة التجزئة |
|---|---|
| SHA-256 | b7512e6b8e9517024afdecc9e97121319e7dad2539eb21a79428257401e5558d |
| SHA-1 | c10e48ee1f802f730f41f3d11ae9d7bcc649080c |
| MD-5 | 23541daadb154f1f59119952e7232d6b |
يمكن الوصول إلى DotDumper من خلال واجهة سطر أوامر، مع مجموعة متنوعة من الوسائط. تُظهر الصورة أدناه قائمة المساعدة. لاحظ أنه لن تتم مناقشة جميع الوسائط، بل أكثرها استخدامًا.

الشرط الأدنى لتشغيل عينة معينة هو توفير الوسيطة "-file" مع اسم ملف أو مسار ملف. إذا تم تقديم مسار كامل، يتم استخدامه. إذا تم تقديم اسم ملف، يتم التحقق من دليل العمل الحالي، وكذلك المجلد الذي يوجد فيه ملف DotDumper القابل للتنفيذ.
ما لم يتم تقديم اسم دليل، يتم تعيين اسم المجلد "-log" مساويًا لاسم الملف للعينة بدون الامتداد (إن وجد). يقع المجلد في نفس المجلد الذي يوجد فيه DotDumper، حيث سيتم حفظ السجلات والملفات المُفرَّغة.
في حالة وجود مكتبة، أو نقطة دخول بديلة إلى ملف ثنائي، يجب تجاوز نقطة الدخول باستخدام "-overrideEntry true". بالإضافة إلى ذلك، يجب توفير الفئة المؤهلة بالكامل، والتي تتضمن مساحة الاسم باستخدام "-fqcn My.NameSpace.MyClass". يخبر هذا DotDumper بالفئة التي سيتم تحديدها، حيث يتم استرداد اسم الدالة المقدمة (باستخدام "-functionName MyFunction").
إذا كانت الدالة المحددة تتطلب وسائط، فيجب توفير عدد الوسائط باستخدام "-argc" وعدد الوسائط المطلوبة. يجب توفير أنواع الوسائط وقيمها كـ "string|myValue int|9". لاحظ أنه عند استخدام مسافات في القيم، يجب وضع الوسيطة على واجهة سطر الأوامر بين علامتي اقتباس لضمان تمريرها كوسيطة واحدة.
الخيارات الأخرى الأقل استخدامًا مثل "-raceTime" أو "-deprecated" آمنة في إعداداتها الافتراضية ولكن قد تتطلب تعديلًا في المستقبل بسبب التغييرات في إطار عمل .NET. يتم عرضها حاليًا في واجهة سطر الأوامر لتسهيل إجراء التغييرات، إذا لزم الأمر، حتى لو كنت تستخدم إصدارًا أقدم من DotDumper عندما يحين الوقت.
التسجيل والتفريغ هما الميزتان الأساسيتان لـ DotDumper. لتقليل الوقت الذي يستغرقه التحليل، يجب أن يوفر التسجيل سياقًا للمحلل. يتم ذلك من خلال تزويد المحلل بالمعلومات التالية لكل استدعاء دالة مُسجل:
لاحظ أنه لكل ملف مُفرَّغ، يكون اسم الملف مساويًا لتجزئة SHA-256 الخاصة بالملف.
لتوضيح ما سبق، يتم تقديم مقتطف من سجل أدناه. يُظهر المقتطف تفاصيل عينة AgentTesla المذكورة أعلاه، حيث تقوم بتحميل المرحلة الثانية باستخدام وظيفة Assembly.Load الخاصة بـ .NET.
![سجل لاستدعاء دالة Assembly.Load(byte[] rawAssembly) المُعترَض](images/assembly_load.png)
أولاً، يتم إعطاء وقت النظام المحلي، بالإضافة إلى نوع الإرجاع الأصلي للدالة واسمها ووسيط/وسائطها. ثانيًا، يتم إعطاء تتبع الاستدعاء، حيث يظهر أن الدالة الرئيسية للعينة تؤدي إلى مُنشئ، وتُهيئ المكونات، وتستدعي وظيفتين مخصصتين. تم استدعاء دالة Assembly.Load من داخل "NavigationLib.TaskEightBestOil.GGGGGGGGGGGGGGGGGGGG(String str)". يوفر هذا السياق للمحلل للعثور على الكود حول هذه الاستدعاء إذا كان ذا أهمية.
ثم يتم إعطاء معلومات حول ترتيب استدعاء التجميع. كلما زاد عدد المراحل التي تم تحميلها، زاد التعقيد في رؤية المراحل التي نشأت منها الاستدعاء. يتوقع المرء عادةً أن تقوم مرحلة واحدة بتحميل المرحلة التالية، ولكن في بعض الحالات تستخدم المراحل اللاحقة المراحل السابقة بترتيب غير خطي. بالإضافة إلى ذلك، يتم إعطاء معلومات حول التجميع الأصلي لإثراء البيانات بشكل أكبر للمحلل.
بعد ذلك، يتم إعطاء تجزئة الأصل. أصل المرحلة هو المرحلة السابقة، والتي في هذا المثال ليست موجودة بعد. سيكون للمرحلة المُحملة حديثًا هذه المرحلة كأصل لها. يسمح هذا للمحلل بربط الأحداث بسهولة أكبر.
أخيرًا، يتم تخزين نوع الإرجاع والقيمة للدالة، بالإضافة إلى نوع واسم وقيمة كل وسيطة تم تمريرها إلى الدالة المُخطَّطة. إذا كان أي متغير أكبر من 100 بايت في الحجم، يتم تخزينه على القرص بدلاً من ذلك. ثم يتم إدراج مرجع في السجل للإشارة إلى الملف، بدلاً من عرض القيمة. تم تعيين الحد لتجنب التعثر في طباعة السجل، حيث أن بعض المصفوفات يبلغ حجمها آلاف المؤشرات.
وفقًا لوثائق Microsoft، يتم تلخيص الانعكاس بشكل أفضل على أنه "[...] يوفر كائنات تُغلف التجميعات والوحدات والأنواع". باختصار، يسمح هذا بالإنشاء والاستدعاء الديناميكيين لفئات ودوال .NET من العينة الضارة. يحتوي DotDumper على مُحمِّل عاكس يسمح للمحلل بتحميل وتحليل كل من الملفات القابلة للتنفيذ والمكتبات، طالما أنها قائمة على إطار عمل .NET.
لاستخدام المُحمِّل، يجب على المرء اختيار تجاوز نقطة الدخول في واجهة سطر الأوامر، وتحديد الفئة (بما في ذلك مساحة الاسم التي توجد فيها) واسم الدالة داخل ملف معين. اختياريًا، يمكن للمرء تقديم وسائط للدالة المحددة، لجميع الأنواع الأصلية والمصفوفات منها. أمثلة على الأنواع الأصلية هي int، string، char، والمصفوفات مثل int[]، string[]، وchar[]. يجب تقديم جميع الوسائط عبر واجهة سطر الأوامر، حيث يجب تحديد كل من النوع والقيمة.
عدم تجاوز نقطة الدخول يؤدي إلى استخدام نقطة الدخول الافتراضية. افتراضيًا، يتم تمرير مصفوفة سلسلة فارغة نحو الدالة الرئيسية للعينة، كما لو تم تنفيذ العينة بدون وسائط.
بالإضافة إلى ذلك، غالبًا ما يتم استخدام الانعكاس من قبل المُحمِّلات لاستدعاء دالة معينة في فئة معينة في المرحلة التالية. في بعض الأحيان، يتم تمرير الوسائط أيضًا، والتي تُستخدم لاحقًا لفك تشفير مورد. في عينة AgentTesla المذكورة أعلاه، يحدث هذا السيناريو بالضبط. تُسجل خطافات الاستدعاء المتعلقة بـ DotDumper هذه الأحداث، كما يمكن رؤيته أدناه.

اسم الدالة في السطر الأول ليس دالة داخلية لإطار عمل .NET، بل هو استدعاء لدالة محددة في المرحلة الثانية. أنواع وأسماء الوسائط الثلاثة مُدرجة في توقيع الدالة. يمكن العثور على قيمها في قسم معلومات وسائط الدالة. سيسمح هذا للمحلل بتحميل المرحلة الثانية في مُحمِّل مخصص بالقيم المعطاة للوسائط، أو حتى القيام بذلك باستخدام DotDumper عن طريق تحميل المرحلة المُفرَّغة سابقًا وتقديم الوسائط.
قبل الخوض في الخطافات المدارة، يحتاج المرء إلى فهم كيفية عمل الخطافات. هناك متغيران رئيسيان يجب مراعاتهما هنا: الدالة الهدف ودالة مُتحكم بها يشار إليها بالخطاف. ببساطة، يتم تغيير الذاكرة في الدالة الهدف (أي Assembly.Load) للقفز بدلاً من ذلك إلى الخطاف. على هذا النحو، يتم تحويل تدفق تنفيذ البرنامج. يمكن للخطاف بعد ذلك تنفيذ إجراءات عشوائية، واختياريًا استدعاء الدالة الأصلية، وبعد ذلك يعيد التنفيذ إلى المُستدعي مع قيمة إرجاع إذا لزم الأمر. يوضح الرسم البياني أدناه هذه العملية.

معرفة ما هي الخطافات أمر ضروري لفهم ما هي الخطافات المدارة. يتم تنفيذ الكود المُدار في بيئة افتراضية ومدارة، مثل وقت تشغيل .NET أو الآلة الافتراضية لجافا. يختلف الحصول على عنوان الذاكرة حيث توجد الدالة المدارة عن لغة غير مدارة مثل C. بمجرد الحصول على عناوين الذاكرة الصحيحة لكلتا الدالتين، يمكن تعيين الخطاف عن طريق الوصول المباشر إلى الذاكرة باستخدام C# غير الآمنة، بالإضافة إلى خدمة التشغيل البيني لـ .NET لاستدعاء وظائف Windows API الأصلية.
منذ الإصدار v1.1-stable من DotDumper، يمكن لـ DotDumper أيضًا خطاف الدوال غير المدارة (أو الأصلية، إذا شئت). يمكن أن يكون إعادة توجيه الدالة أي مزيج من وإلى الدوال المدارة وغير المدارة، مع تحذير مهم واحد. أي دالة غير مدارة تستخدم خطافًا مُدارًا لن تكون قادرة على قراءة قيم المكدس بشكل صحيح. على هذا النحو، يلزم وجود مكون أصلي (يُسمى DotDumperNative). يتواصل هذا المكون عبر أنبوب مسمى مع DotDumper نفسه، وبالتالي يستخدم نظام التسجيل المركزي الخاص به، مع اعتراض الاستدعاءات غير المدارة مع الوصول إلى وسائط الدالة الموجودة على المكدس.
نظرًا لأن DotDumper مكتوب بلغة C# نقية بدون أي تبعيات خارجية، يمكن للمرء بسهولة توسيع الإطار باستخدام Visual Studio. تم توثيق الكود في هذه المدونة، على GitHub، وفي الفئات، وفي الدوال، وفي السطر في الكود المصدري. هذا، إلى جانب مخطط التسمية الواضح، يسمح لأي شخص بتعديل الأداة كما يراه مناسبًا، مما يقلل من الوقت والجهد الذي يحتاجه المرء لفهم الأداة. بدلاً من ذلك، يسمح للمطورين والمحللين على حد سواء بالتركيز على تحسين الأداة.
بينما لم يتم تغيير ميزة دعم المهلة الزمنية لصندوق الحماية أو تعديلها، إلا أنها لم يتم توثيقها من قبل. نظرًا لأن DotDumper ينفذ الملف المعطى له، سيستمر تنفيذه حتى تنتهي العينة. غالبًا ما تدخل البرامج الضارة في حالة "انتظار"، حيث يجب استيفاء شرط معين قبل إعادة تنشيطها، أو يستمر البرنامج الضار في التنفيذ في عملية مختلفة (بمساعدة حقن العملية). على سبيل المثال، لا يعود الخيط المُنشأ حديثًا في عملية مجوفة إلا بعد الانتهاء.
لتجنب التوقف، يحتوي DotDumper على معالج ركود. في كل مرة يتم فيها تسجيل نتائج خطاف، يتم زيادة عداد. إذا لم يتغير هذا العداد بعد ثلاث فترات متتالية مدتها 20 ثانية، يفترض DotDumper أنه تمت مواجهة حالة ركود. في هذه الحالة، يتم ضبط وقت النظام على 30-12-2200 12:00 لإجبار صندوق الحماية على انتهاء المهلة، وبعد ذلك يُبلغ المحلل عبر المسجل وينهي نفسه. تحدث مهلة صندوق الحماية عندما يتجاوز الوقت المنقضي من التاريخ الحالي حتى التاريخ المُعيَّن حديثًا الدقائق المعتادة البالغة 5 أو 10 دقائق. حتى إذا تم تعيين وقت تشغيل صندوق الحماية على ساعات أو أيام، يتم تجاوزه.
سبب قطع التحليل مبكرًا هو توفير الوقت والموارد، نظرًا لأن التقديم بمهلة 10 دقائق قد يستغرق دقيقتين فقط للتشغيل. على هذا النحو، سيكون المرء قادرًا على تشغيل عينات متعددة في نفس الفترة الزمنية باستخدام معالج الركود. يظهر أدناه نظرة عامة على منطق معالج الركود.

مع توضيح هدف وميزات DotDumper، قد يبدو أن هناك تداخلاً مع الأدوات المعروفة المتاحة للجمهور مثل ILSpy وdnSpyEx وde4dot أو pe-sieve. لاحظ أنه لا توجد نية للادعاء بأن أداة أفضل من أخرى، بل كيفية اختلاف الأدوات.
هدف DotDumper هو تسجيل وتفريغ استدعاءات الدوال الحاسمة والمُسيّقة والشائعة من العينات التي تستهدف .NET. ILSpy هو مفكك ومفكك ترجمة لـ .NET، لكنه لا يسمح بتنفيذ الملف. dnSpyEx (وسابقه dnSpy) يستخدم ILSpy كمكون مفكك ومفكك ترجمة، مع إضافة مصحح أخطاء. يسمح هذا بفحص الذاكرة ومعالجتها يدويًا. يُستخدم de4dot فقط لإزالة التعتيم عن الملفات الثنائية لـ .NET، مما يحسن قابلية قراءة الكود للعين البشرية. الأداة الأخيرة في هذه المقارنة، pe-sieve، مُخصصة للكشف عن البرامج الضارة من العمليات الجارية وتفريغها، بغض النظر عن لغة البرمجة المستخدمة. يوفر الجدول أدناه نظرة عامة رسومية للأدوات المذكورة أعلاه.

يخضع DotDumper للمراجعة والتطوير المستمرين، وكل ذلك يركز على مجالين رئيسيين: إصلاح الأخطاء وإضافة ميزات جديدة. أثناء التطوير، تم اختبار الكود، ولكن بسبب إدخال خطافات في دوال إطار عمل .NET التي قد تخضع للتغيير، فمن الممكن جدًا وجود أخطاء في الكود. يُحث أي شخص يواجه خطأً على فتح مشكلة في مستودع GitHub، والتي سيتم النظر فيها بعد ذلك. اقتراح ميزات جديدة ممكن أيضًا عبر مستودع GitHub. لأولئك الذين لديهم حساب GitHub، أو لأولئك الذين يفضلون عدم التفاعل علنًا، لا تتردد في إرسال رسالة خاصة إلي على Twitter.
وغني عن القول، إذا كنت قد استخدمت DotDumper أثناء تحليل، أو استخدمته بطريقة إبداعية، فلا تتردد في التواصل علنًا أو بشكل خاص! لا شيء يضاهي سماع استخدام أداة منزلية الصنع!
هناك المزيد في المتجر لـ DotDumper، وسيتم إرسال تحديث إلى المجتمع بمجرد توفره!