
مشروع إثبات مفهوم (PoC) لتضمين شيل كود (shellcode) في جدول التلميحات/الأسماء (Hint/Name Table)
HintInject هي أداة لتضمين وتحميل الشيلكود (shellcode) قمت بتطويرها أثناء اللعب بهياكل ملفات PE وجدول دليل الواردات (Import Directory Table). تقوم بأخذ ملف شيلكود خام ووضع الشيلكود على شكل قطع في إدخالات جدول Hint/Name التي يمكن الوصول إليها عبر جدول بحث الواردات (Import Lookup Table) لإدخال DLL وهمي مضاف إلى الملف القابل للتنفيذ (loader). يقوم المحمل بعد ذلك بدمج هذه القطع لتنفيذ الشيلكود. لا أعلم إن كانت هذه التقنية جديدة أم لا، لكنني أردت مشاركتها للمتعة.
قبل شرح كيفية عمل HintInject، أود أن أذكر بإيجاز عملية تحميل DLL بالرجوع إلى منشور في Stack Overflow.
للحصول على معلومات حول الـ DLLs المطلوبة والوظائف/الواردات، يجب النظر أولاً إلى جدول دليل الواردات (Import Directory Table). جدول دليل الواردات هو جدول من الإدخالات، إدخال واحد لكل DLL مستورد. تحتوي هذه الإدخالات على مؤشر لاسم DLL المستورد، ومؤشر إلى جدول بحث الواردات (Import Lookup Table)، ومؤشر إلى جدول عناوين الواردات (Import Address Table)، وحقول أخرى لمعلومات مختلفة.
ببساطة، يقود جدول بحث الواردات إلى معلومات الواردات، ويقود جدول عناوين الواردات إلى عناوين الواردات. ولكن، عندما يكون الملف القابل للتنفيذ على القرص، أو قبل عملية تحميل DLL مباشرة، يكون جدول عناوين الواردات مطابقاً لجدول بحث الواردات. يتم استبدال محتوى جدول عناوين الواردات بعناوين الواردات أثناء عملية تحميل DLL.
دون الخوض في بعض التفاصيل، يمكننا إلقاء نظرة على الرسم البياني أدناه لرؤية العلاقة بين هذه الجداول الثلاثة.
إذا تعمقنا قليلاً في التفاصيل، فإن جدول بحث الواردات لا يحمل أسماء الواردات مباشرة. بالنسبة للوظائف التي يتم استيرادها بالاسم، فإنه يحمل عناوين RVA لإدخالات جدول Hint/Name. تخزن هذه الإدخالات أسماء الوظائف كسلاسل ASCII منتهية بـ null. لذلك، تعريف الهيكل (struct) لإدخال جدول Hint/Name هو كما يلي:
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint;
CHAR Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
حقل Hint هنا هو في الواقع فهرس في جدول مؤشرات أسماء التصدير (export name pointer table) الخاص بـ DLL. يُستخدم لتسريع إيجاد موقع ذلك الاستيراد. لذلك، يمكننا تلخيص العلاقة بين جدول بحث الواردات وجدول Hint/Name بالرسم البياني أدناه.
للاستنتاج، من أجل العثور على DLL ووارداته، يجب اتباع هذه الخطوات:
مؤخراً، أثناء فحص تقنية ImportDLLInjection التي شاركها x86matthew، رأيت كيفية إضافة إدخال وهمي إلى دليل الواردات الخاص بـ DLLs المحملة في الذاكرة. بعد ذلك، أردت تطوير مشروع صغير يضيف إدخالاً وهمياً مباشرة إلى جدول الواردات لملف ثنائي على القرص، للمتعة ولتحديث معلوماتي. أثناء مراجعة عملية تحميل DLL لتطوير هذا المشروع، لفت انتباهي حقل Hint في إدخالات جدول Hint/Name المستخدمة في هذه العملية.
وفقاً لوثيقة MSDN، علمت أن هذا الحقل يستخدم بواسطة محمل Windows للعثور على عنوان ذلك الاستيراد، الذي يتم استيراده بالاسم، مباشرة من جدول أسماء التصدير الخاص بـ DLL الموجود فيه. ومع ذلك، في نفس الوثيقة، ذكر أنه إذا تعذر العثور على الوظيفة باستخدام هذا الحقل، فسيتم البحث عن تلك الوظيفة عبر عملية بحث ثنائي في جدول أسماء التصدير الخاص بـ DLL. بناءً على هذه الجملة، اعتقدت أن وضع قيمة غير صحيحة لهذا الحقل لن يعطل عملية تحميل DLL.
كما ذكرت أعلاه، يوجد إدخال إلى جدول Hint/Name يتوافق مع كل وظيفة سيتم استيرادها. بمعنى آخر، لدينا 2 بايت لاستخدامها لكل استيراد. من خلال دمج عدة واردات، يمكن الحصول على عدد كافٍ من حقول Hint لتخزين الشيلكود الخبيث. ونتيجة لذلك، يمكن استخدام ملف ثنائي محمل (loader) لتضمين الشيلكود في إدخالات Hint/Name الخاصة بإدخال DLL الوهمي المستورد. يمكن لذلك المحمل الوصول إلى هذه الإدخالات لدمج الشيلكود ليتم تنفيذه أثناء وقت التشغيل.
يمكن استخدام HintInject لإنشاء مثل هذا المحمل الذي يحمل الشيلكود في جدول Hint/Name الخاص به. يقوم أولاً بإنشاء قسم جديد باسم .rrdata ونسخ دليل الواردات الحالي إلى هذا القسم. بعد ذلك، يقوم بإلحاق إدخال وهمي جديد ستُستخدم وارداته لحمل الشيلكود المدخل. تُستخدم البايتات المتبقية من القسم لتخزين جدول بحث الواردات، وجدول عناوين الواردات، واسم DLL، وجدول Hint/Name للإدخال الوهمي الجديد. كخطوة أخيرة، يستخدم HintInject حقول Hint للواردات لوضع قطع من الشيلكود المدخل.
مثال على واردات ملف محمل ثنائي:
HintInject.exe مع ملف الشيلكود الخاص بك بصيغة خام ومسار إخراج لإنشاء محمل شيلكود: HintInject.exe <Shellcode File> <Output Name>Loader.exe <PID>InjectShellcode في ملف HintInjectLoader/Main.cpp.تم الاختبار على Windows 10 19044 مع Visual Studio 2019:
dllNames في ملف DllNamesForFakeImports.h.dllNames في ملف DllNamesForFakeImports.h. بشكل افتراضي، سيختار HintInject الوظائف من الـ dlls وفقاً لترتيب المصفوفة. بمعنى آخر، تقوم الأداة أولاً باختيار الوظائف المصدرة من user32.dll، إذا كان حجم الشيلكود أكبر من 2 * عدد تصديرات user32.dll، فإنها تبدأ أيضاً في استخدام تصديرات advapi32.dll وغيرها.static LPCSTR dllNames[] = {"user32.dll","advapi32.dll","gdi32.dll","wininet.dll","comctl32.dll","shell32.dll","wsock32.dll","oleaut32.dll","ws2_32.dll","urlmon.dll"};
للاستخدام المصرح به في اختبارات الأمان فقط. إساءة استخدام هذه الأداة ضد أنظمة دون إذن صريح غير قانوني.