أثناء بحثي عن موضوع ما وجدت برنامجا يُدّعى أنه يعمل بدون استيرات أي مكتبة ولا حتى kernel32.dll، ولكنه يستدعي الدالة MessageBox والتي توجد في المكتبة USER32.dll. وفعلا في cff explorer لا وجود لجدول imports.
البرنامج للأسف لا يعمل عندي على windows 8. من كان عنده windows xp إلى 7 يمكنه التحقق لنا
.
فقمت بتنقيح البرنامج ومحاولة فهم الأوامر، في ما يلي سأوضح نظريا كيف يعمل البرنامج على الرغم من عدم امتلاكي لنسخة تعمل منه حاليا، كما سأوضح سبب فشل البرنامج (البرنامج في المرفقات).
تنبيه: هذا التحليل لا يعني أن البرنامج لن يعمل على الأنظمة السابقة ل windows 8! بل على العكس، فكرة البرنامج تبدو صالحة لو لا بعض الافتراضات الضمنية التي لا تتحقق في windows 8. وغالب ظني أنه فعلا يعمل على الأنظمة السابقة.
خطة البرنامج بشكل مختصر:
1- يفترض البرنامج أن kernel32.dll قد تم تحمليها مسبقا بشكل تلقائي حتى ولو لم يطلب البرنامج ذلك (وهو الحال فعلا).
2- انطلاقا من هذا الفرض 1 يحاول البرنامج البحث عن ال base address ل kernel32.dll.
3- يبحث البرنامج في ال export directory في ال PE Header الخاص ب kernel32.dll عن الدالة LoadLibrary.
4- باستعمال الدالة LoadLibrary يستطيع البرنامج تحميل المكتية USER32.dll ومعرفة عنوانها.
5- البحث في ال export directory في ال PE Header الخاص ب USER32.dll عن الدالة MessageBox
6- استدعاء الدالة MessageBox.
التفاصيل:
سنستعمل ال structure التالي لتخزين معلومات الدوال التي نود البحث عنها.
function_name_length و function_name ثابتان في الحقيقة بينما function_address هو المتغير الذي سوف نقوم بتعبئته عند الخطوتين 3 و 5.
البرنامج يعرف المتغيرات العمومية (Global أهذه الترجمة جيدة؟) التالية:
علي اليمين العناوين المطلقة التي ظهرت عندي وعنوان الأساس كان 0x400000، وأود أن أنوه أن جميع العناويين في هذه المشاركة مطلقة كما أن أسماء المتغيرات والدوال من تسميتي.
لنلق نظرة على kernel32_functions_info_array
نرى أن kernel32_functions_info_array عبارة عن ثلاث function_info متعاقبة، وبالمثل user32_functions_info_array
أسماء الدوال التي تظهر في kernel32_functions_info_array و user32_functions_info_array هي أسماء الدوال التي سيبحث البرنامج عن عناوينها بدون استيراد مكتباتها بشكل صريح.
الأوامر:
سنفصل الخطوتين 2 و 3، لأن البقية واضحة و الخطوة 5 مطابقة ل 3 (فقط باختلاف قيمة DLL_base_address).
الخطوة 2: عمليا يبدأ البرنامج باستدعاء الدالة Fill_kernel32_address_directly_after_running المعرفة كالتالي
تبدأ الدالة ب ecx = [esp+4] وهذا لأن أول ما يوجد في المكدس هو عنوان داخل نطاق kernel32.dll. لكننا نريد عنوان الأساس وليس أي عنوان في kernel32.dll. نعلم أن عنوان الأساس يحقق الخصائص التالية
1- عنوان الأساس يساوي قيمة PE_Header.Optional_Header.ImageBase
والذي يمكننا الوصول إليه كالتالي
أي أن الشرط الأول على ecx هو
2- أصغر من قيمة ecx أعلاه (هل هذا صحيح دائما؟).
كما أن البرنامج يضيف الشرط التالي
3- أن يكون dx & F800 == 0 ولعل المقصود أن تكون قيمة edx صغيرة فلا يحصل memory access violation exception.
فما تقوم به الدالة Fill_kernel32_address_directly_after_running هو انقاص قيمة ecx باستمرار والتحقق من الشرطين 1 و 3. إذا تحققا فهذا هو عنوان الأساس ل kernel32.dll !!
لكن لا بد أنكم رأيتم التعليق access violation exception. Fix this أعلاه، وهذا عندي لوجود مناطق ذاكرة محجوزة تتخلل منطقة ذاكرة kernel32.dll. يبدو أن هذا لم يكن الحال في الأنظمة السابقة.
الخطوة 3:
بما أننا حصلنا على عنوان kernel32.dll وخزناه في DLL_base_address فإبمكاننا الوصول إلى export directory ببساطة والبحث عن أسماء الدوال التي نريد. لنعرف الدالة التالية
قد تبدو كبيرة لكن نظريا بسيطة وجل ما تقوم به هو التالي:
1- استخراج بعض المعلومات من ال PE Header الخاص بال dll المراد البحث فيه وهو في حالتنا الآن kernel32.dll.
2- في ال while loop يقوم بمقارنة اسم الدالة التي نريد أن نبحث عنها (esi) مع قائمة الأسماء المسخرجة في 1 والتي خزنت في edi.
3- بعد إيجاد ترتيب اسم الدالة في قائمة الأسماء (ebx) نستعمله كأنه ال ordinal المحدد للدالة في ال PE Header الخاص ب kernerl32.dll وباستعماله نستطيع إيجاد عنوان الدالة.
هذه الخطوات تطبيق عملي لل PE Header Structure.
هل انتبهت للتعليق False ordinal؟ في الحقيقة حتى هنا توجد مشكلة وهي أن المبرمج افترض أن ترتيب اسم الدالة ebx في مصوفة الأسماء edi سيكون مطابقا ل ordinal الدالة! للأسف هذا غير صحيح عندي. كان من المفترض أن يستخدم address of addresses of names وليس address of first name (انظر التعليقات على الأوامر) لكنه افترض أن ترتيب الأسماء هنا وهناك سيكون متطابقا!
--------------------
في المرفقات: تجدون البرنامج وملف txt فيه أوامر البرنامج معكوسة كلها تقريبا لمن أراد التعقب أثناء التنقيح أو محاولة إعادة كتابة البرنامج لجعله يعمل على الأنظمة الجديدة.
المراجع: البرنامج الأصلي يوجد في مجلد yoda/NoImports.exe بعد التحميل من هنا.
البرنامج للأسف لا يعمل عندي على windows 8. من كان عنده windows xp إلى 7 يمكنه التحقق لنا

فقمت بتنقيح البرنامج ومحاولة فهم الأوامر، في ما يلي سأوضح نظريا كيف يعمل البرنامج على الرغم من عدم امتلاكي لنسخة تعمل منه حاليا، كما سأوضح سبب فشل البرنامج (البرنامج في المرفقات).
تنبيه: هذا التحليل لا يعني أن البرنامج لن يعمل على الأنظمة السابقة ل windows 8! بل على العكس، فكرة البرنامج تبدو صالحة لو لا بعض الافتراضات الضمنية التي لا تتحقق في windows 8. وغالب ظني أنه فعلا يعمل على الأنظمة السابقة.
خطة البرنامج بشكل مختصر:
1- يفترض البرنامج أن kernel32.dll قد تم تحمليها مسبقا بشكل تلقائي حتى ولو لم يطلب البرنامج ذلك (وهو الحال فعلا).
2- انطلاقا من هذا الفرض 1 يحاول البرنامج البحث عن ال base address ل kernel32.dll.
3- يبحث البرنامج في ال export directory في ال PE Header الخاص ب kernel32.dll عن الدالة LoadLibrary.
4- باستعمال الدالة LoadLibrary يستطيع البرنامج تحميل المكتية USER32.dll ومعرفة عنوانها.
5- البحث في ال export directory في ال PE Header الخاص ب USER32.dll عن الدالة MessageBox
6- استدعاء الدالة MessageBox.
التفاصيل:
سنستعمل ال structure التالي لتخزين معلومات الدوال التي نود البحث عنها.
function_name_length و function_name ثابتان في الحقيقة بينما function_address هو المتغير الذي سوف نقوم بتعبئته عند الخطوتين 3 و 5.
البرنامج يعرف المتغيرات العمومية (Global أهذه الترجمة جيدة؟) التالية:
علي اليمين العناوين المطلقة التي ظهرت عندي وعنوان الأساس كان 0x400000، وأود أن أنوه أن جميع العناويين في هذه المشاركة مطلقة كما أن أسماء المتغيرات والدوال من تسميتي.
لنلق نظرة على kernel32_functions_info_array
نرى أن kernel32_functions_info_array عبارة عن ثلاث function_info متعاقبة، وبالمثل user32_functions_info_array
أسماء الدوال التي تظهر في kernel32_functions_info_array و user32_functions_info_array هي أسماء الدوال التي سيبحث البرنامج عن عناوينها بدون استيراد مكتباتها بشكل صريح.
الأوامر:
سنفصل الخطوتين 2 و 3، لأن البقية واضحة و الخطوة 5 مطابقة ل 3 (فقط باختلاف قيمة DLL_base_address).
الخطوة 2: عمليا يبدأ البرنامج باستدعاء الدالة Fill_kernel32_address_directly_after_running المعرفة كالتالي
تبدأ الدالة ب ecx = [esp+4] وهذا لأن أول ما يوجد في المكدس هو عنوان داخل نطاق kernel32.dll. لكننا نريد عنوان الأساس وليس أي عنوان في kernel32.dll. نعلم أن عنوان الأساس يحقق الخصائص التالية
1- عنوان الأساس يساوي قيمة PE_Header.Optional_Header.ImageBase
والذي يمكننا الوصول إليه كالتالي
أي أن الشرط الأول على ecx هو
2- أصغر من قيمة ecx أعلاه (هل هذا صحيح دائما؟).
كما أن البرنامج يضيف الشرط التالي
3- أن يكون dx & F800 == 0 ولعل المقصود أن تكون قيمة edx صغيرة فلا يحصل memory access violation exception.
فما تقوم به الدالة Fill_kernel32_address_directly_after_running هو انقاص قيمة ecx باستمرار والتحقق من الشرطين 1 و 3. إذا تحققا فهذا هو عنوان الأساس ل kernel32.dll !!
لكن لا بد أنكم رأيتم التعليق access violation exception. Fix this أعلاه، وهذا عندي لوجود مناطق ذاكرة محجوزة تتخلل منطقة ذاكرة kernel32.dll. يبدو أن هذا لم يكن الحال في الأنظمة السابقة.
الخطوة 3:
بما أننا حصلنا على عنوان kernel32.dll وخزناه في DLL_base_address فإبمكاننا الوصول إلى export directory ببساطة والبحث عن أسماء الدوال التي نريد. لنعرف الدالة التالية
قد تبدو كبيرة لكن نظريا بسيطة وجل ما تقوم به هو التالي:
1- استخراج بعض المعلومات من ال PE Header الخاص بال dll المراد البحث فيه وهو في حالتنا الآن kernel32.dll.
2- في ال while loop يقوم بمقارنة اسم الدالة التي نريد أن نبحث عنها (esi) مع قائمة الأسماء المسخرجة في 1 والتي خزنت في edi.
3- بعد إيجاد ترتيب اسم الدالة في قائمة الأسماء (ebx) نستعمله كأنه ال ordinal المحدد للدالة في ال PE Header الخاص ب kernerl32.dll وباستعماله نستطيع إيجاد عنوان الدالة.
هذه الخطوات تطبيق عملي لل PE Header Structure.
هل انتبهت للتعليق False ordinal؟ في الحقيقة حتى هنا توجد مشكلة وهي أن المبرمج افترض أن ترتيب اسم الدالة ebx في مصوفة الأسماء edi سيكون مطابقا ل ordinal الدالة! للأسف هذا غير صحيح عندي. كان من المفترض أن يستخدم address of addresses of names وليس address of first name (انظر التعليقات على الأوامر) لكنه افترض أن ترتيب الأسماء هنا وهناك سيكون متطابقا!
--------------------
في المرفقات: تجدون البرنامج وملف txt فيه أوامر البرنامج معكوسة كلها تقريبا لمن أراد التعقب أثناء التنقيح أو محاولة إعادة كتابة البرنامج لجعله يعمل على الأنظمة الجديدة.
المراجع: البرنامج الأصلي يوجد في مجلد yoda/NoImports.exe بعد التحميل من هنا.
I am homesick for a place I have not even visited
مَا ابْيَضَّ وجهٌ باكتساب كريمةٍ ... حتى يسوِّدهُ شُحوب المَطلبِ
مَا ابْيَضَّ وجهٌ باكتساب كريمةٍ ... حتى يسوِّدهُ شُحوب المَطلبِ