Portable Executable File Format

Getting to know the data structure used to manage executable code

C RunTime CRT

تعلمنا في لغة C ان الملفات التنفيذية يبدأ تنفيذها من الدالة الرئيسية main ولكن هذا غير صحيح بشكل كامل فكل ملف تنفيذي يبدأ من نقطة تُسمي نقطة البدء الأصلية original entry point EOP و التي تشير إلي مجموعة أخري من الأكواد من دورها تهيئة البرنامج للعمل من ثم نقل تنفيذ البرنامج للدالة الرئيسية ليبدأ تنفيذ برنامجنا، و يتم إنشاء تلك الأكواد عن طريق المُجمع Compiler و تُسمي اكواد بداية التشغيل startup code او C Runtime Code CRT.

و من مهام الـ CRT التعرف علي نص وسائط الدالة الرئيسية الذي قبل تهيئته يُعامل كنص واحد حيث يتولي الـ CRT فصله بستخدام المسافات بين اجزائه علي النحو التالي:

و الـ CRT كذلك يقوم بتحضير الـ Environment Variable Array envp التي تسمح للبرنامج بالتعامل مع متغيرات البيئة Environment Variables والتي تسمح للمطور بمعرفة المسارات المُعرفة مسبقا في بيئة المستخدم كالمثال التالي:

image-20200103101956890

image-20200103102342570

اما بالنسبة للبرامج الرسومية Graphical User Interface GUI Applications فيتم استخدام الدالة الرئيسية WinMain بدلا من main و التي تمتلك وسائطها الخاصة التي يقوم الـCRT ايضا بتهيئتها و تكون علي الشكل التالي:

و يدير الـ CRT التعامل مع القيمة المُرجعة للدالة الرئيسية و التي تمثل حالة إنتهاء البرنامج (القيمة المُرجعة0 مثلا تمثل إنتهاء البرنامج بدون اخطاء)، حيث غالبا ما يمررها الـ CRT للدالة ExitProcess او exit و التي تستخدم القيمة المُرجعة من الدالة الرئيسية كوسيط paramter، و عادة ما يكون لكل مُجمع الـ CRT الخاص به. للتوضيح قم بفتح البرنامج التنفيذي للمثال اعلاه في Ghidra و التي سبق لك تحميلها اثناء تهيئة مختبر التحليل الخاص بك، من ثم قم بإنشاء مشروع خاص Non-shared project و اختر المسار و الأسم الخاص به:

image-20200103110428277

الأن يمكنك فقط تحميل الملف داخل المشروع من ثم إخبار ghidra بتحليل البرنامج بعدها قم بالذهاب لدالة الـ CRT المُعرفة بإسم mainCRTStartup_

ghidra

بستخدام نافذه Decompilation يمكننا استعادة شكل اقرب ما يكون للملف المصدري بلغة C مما يفيد كثيرا في تسريع عملية تحليل البرمجيات لأنه (في بعض الحالات فقط) يُغني عن قرائة الـ Disassembly، فكان يجب تعلم لغة C من البداية للتعامل مع ادوات الهندسة العكسية بشكل عام.

يمكننا هنا ان نري استخدام دوال المُجمع MinGW-gcc الخاصة بالـ CRT منها getmainargs___ و p__environ___ المسؤولين عن تهيئة الوسائط argc argv envp ، يمكننا كذلك رؤية الـ CRT يقوم بإستدعاء الدالة الرئيسية و تمرير الوسائط الثلاث لها من ثم تمرير القيمة المُرجعة من الدالة الرئيسية للدالة ExitProcess.

image-20200103105210213


Portable Executable File format

Portable Executable PE هو تركيب من البيانات يحتوي علي المعلومات اللازمة ليتم تحميله و تنفيذه من قبل الـ PE Loader في نظام التشغيل Windows حيث يتم استخدام الـ PE File Structure لإنشاء ملفات تنفيذيه Executable Files مثال التي تمتلك امتدادexe sys dll والتي تشترك في نفس تركيب الملف باختلاف مكان و غرض أستخدامها.

pe101ar

 

قبل التعمق في الـ PE File Format يجب ان نتطرق للمصطلحات Terminology التالية:

image-20200212153744391

و ينقسم الـ PE File إلي فرعين رئيسين:

image-20200401164823205


PE File Headers

اول قسمين (DOS Header و DOS stub) غير مهمين بالنسبة لنا؛ فالقسم الثاني (DOS stub) هو برنامج بحد ذاته مسؤول عن طباعة الرسالة This program cannot run in DOS mode عند محاولة تشغيله في MS-DOS و إنهاء عمل الملف لعجز MS-DOS عن التعامل مع الـ PE File Format:

image-20200103153007775

اما بالنسبة للـ DOS Headers فلا يهمنا منها غير معرفة أن الـ Magic Number يحتوي علي النص MZ و عند قراءة الملف التنفيذي من قبل الـ Loader فإنه يبحث عن هذه القيمة ليتأكد من صلاحية الـ PE File. يمكنك استخدام ادوات مثل PE bear و CFF explorer لعرض و تعديل محتوي الـ PE Files و تُسمي تلك الأدوات عادة بالـ PE Parsers:

image-20200103142356958

 

NT Headers

بعد ان علمنا أن بداية الـ PE Files تتكون من DOS Header و DOS Stub تبقي لنا معرفة من يتبعهم و هو الـ NT Headers التي تتضمن الـ Headers التالية:

PE signautre

بعد الـ MS-DOS stub و تحديدا عند الـ Offset المحدد بـ 0x3c يوجد bytes-4 تشير للـ offset حيث توجد الـ PE signature التي تقوم بتعريف الملف كـ PE executable image. عندما يتم تحميل الملف من قبل الـ Loader فإنه يتحقق من تلك الـ Signature و التي إن كانت تساوي النص PE متبوعا بصفرين null bytes فيتم اعتبار الملف صالح Valid PE

image-20200509214106209

File header

الـ COFF file header او File header للإختصار هو ترويسة قياسية standard header يوجد في بداية الملفات الكائنية او مباشرة بعد الـ PE signature في الـ Executable images.

image-20200103154456054

image-20200103154836993

و يمتلك التركيبة Structre التالية:

  1. IMAGE_FILE_RELOCS_STRIPPED و يشير إلي أن الملف لا يحتوي علي عمليات إعادة تعيين للـ base address و لذلك يجب تحميله في الـ base address المُفضل له و المُعرف داخل الـ ImageBase في الـ optional header. في حالة ان ذلك العنوان غير متاح سيبلغ loader عن خطأ
  2. IMAGE_FILE_EXECUTABLE_IMAGE و يشير إلي ان الـ Executable image صالحة و يمكن تشغيلها. عدم تحديد هذه الراية يشير إلي وجود خطأ في عملية الربط linking error
  3. IMAGE_FILE_LARGE_ADDRESS_AWARE تشير هذه الراية إلي امكانية الـ Process علي التعامل مع عناوين الذاكرة ما فوق الـ 2gigabytes بمعني ان الـ process يمكنها ان تشغل مساحة من الذاكرة اكثر من 2gigabytes
  4. IMAGE_FILE_32BIT_MACHINE الـ Executable Image تعمل علي جهاز يدعم الـ 32bit word
  5. IMAGE_FILE_DEBUG_STRIPPED معلومات تنقيح الملف Debugging information و التي تتضمن اسماء الدوال و المتغيرات من الملف المصدري قد تمت ازالتها
  6. IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP اذا كانت الـ Executable Image مُخزنة علي وسيط قابل للإزالة removable media مثال الـ USB قم بتحميله بشكل كامل و انسخه في الـ swap
  7. IMAGE_FILE_SYSTEM الـ Executable Image ملف من ملفات النظام و ليست من ملفات المستخدم
  8. IMAGE_FILE_DLL الـ Executable Image مكتبة من مكتبات الربط الديناميكي dynamic-link library DLL
  9. IMAGE_FILE_UP_SYSTEM_ONLY الـ Executable Image يجب ان تعمل فقط علي جهاز احادي المعالج uniprocessor machine

الرايات الباقية غير مستخدمة و يجب ان تساوي القيمة 0.


Optional Header

كل Executable Image تمتلك ترويسة اختيارية Optional Header و الذي يوفر للـ loader معلومات يحتاجها لتشغيل الملف، كما يشير اسم الـ header فهو اختياري حيث لا تحتاج بعض الملفات (خصوصا الملفات الكائنية) له، علي عكس الـ Executable Images فهو ضروري بالنسبة لها.

Portable_Executable_32_bit_Structure_in_SVG

و يتكون الـ Optional Header من الأجزاء الثلاثة التالية:

و الـ Optional Header يمتلك التركيب التالي:

image-20200108104616395

image-20200108102325179

image-20200108102354804


CheckSum

Checksum عبارة عن خوارزمية تجزئة بسيطة basic hashing algorith يتم استخدامها للتحقق من صحة الملفات integrity، اي تعديل في البيانات المُدخلة لهذا النوع من الخوارزميات مهما كانت بساطته سيؤدي إلي تغير كبير في قيمة الـ Checksum النهائية. و تتمثل فائدة الـ Checksum في التأكد من سلامة و عدم تغير محتوي الملف التنفيذي بعد عملية التجميع حيث يتم اثناء عملية التجميع حساب قيمته و تخزينها في حقل الـ Checksum داخل الـ Optional header.

و بشكل اساسي، قبل تحميل الـ Device Drivers او الـ DLLs التي يتم تحميلها أثناء بدء التشغيل Boot time او في الـ Modules الخاصة بالنظام، يتم حساب الـ Checksum الخاص بالملف و التأكد من صحته و مطابقته لمحتوي الـ Checksum المُعرف من المُجمع. في حالة عدم التطباق يتم اعتبار الملف غير صالح او تالف Corrupted. و من الجدير بالذكر ان تلك العملية من التحقق لا تتم علي الملفات التنفيذية العادية و في حالة عدم تطابق القيمتين سيظل من الممكن تشغيل البرنامج من قبل المستخدم.

يحمل حقل الـ Checksum قيمة الـ Cyclic Redundancy Check CRC الخاص بالـ Executable image ففي حالة تعديل الملف مثال عمل Patch لوظيفة من وظائفه فلن يتطابق الـ Checksum و رغم سهولة تغيير قيمته ليوافق حالة الـ Executable image بعد التعديل إلا انه في حالة عدم تعديل قيمته يكون وسيلة جيدة لتحديد ما اذا كان قد تم التلاعب بمحتوي الـ Executable image، يمكنك التأكد من صحة الـ Checksum عن طريق ادوات مثل PEstudio

image-20200108131600636


Subsystem و يشير إلي النظام الفرعي المستخدم في تشغيل البرنامج، اشهر ثلاث قيم يحتويها الـ Subsystem optional header هم:


DllCharacteristics

يحمل خصائص مكتبات الربط الديناميكية الخاصة بـ الـ Module و من اهم تلك الخصائص:

IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE

يشير إلي إمكانية تغير عناوين مكتبات الربط الديناميكية في الذاكرة الأفتراضية، في النسخ الأقدم من نظام التشغيل Windows كان يتم تحميل الملفات الخاصة بالنظام في اماكن ثابتة في الذاكرة و الذي كان يمثل قاعدة للثغرات التي تستغل معرفتها بتلك الأماكن و الـ Processes المعروفة بتصالها معها. النسق العشوائي لمساحة العناوين Address Space Layout Randomization ASLR عمل علي حل تلك المشكلة بإعطاء عناوين عشوائية للملفات الخاصة بالنظام و البرامج عامة عند تحميلها للذاكرة مما جعل تخمين العناوين الصحيحة لنجاح تنفيذ ثغرة اصعب.

من Windows 7 صعودا لما بعدها يتم استخدام الـ ASLR بشكل تلقائي لجميع الـ Processes إلا إذا عرف البرنامج نفسه علي انه غير متوافق مع تلك الألية بالتعديل علي الـ IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE. و بالرغم من اهمية تلك الألية كوسيلة للحماية من الثغرات إلا ان التخلص من الـ ASLR يصبح عمليا في تحليل البرمجيات الخبيثة في العديد من الحالات مثل التعامل مع اكثر من اداة كمثال x64dbg و Ghidra فبدون إيقاف الـ ASLR ستظهر نفس البيانات و تعليمات لغة الألة في عناوين ذاكرة مختلفة بشكل عشوائي مما يجعل الوصول لها ابطيء، مثال:

image-20200216234300263

image-20200216234200636

يرجع ذلك إلي أن Ghidra ببساطة ستقوم بالتعامل مع عناوين الذاكرة بناء علي الـ Base Address المُعرف داخل الـ ImageBase في الـ optional header اما x64dbg لكونه منقح Debugger و يقوم بتحميل البرنامج في كل مرة للذاكرة و تشغيله فستكون العناوين مختلفة في كل مرة. يمكننا إيقاف الـ ASLR عن طريق ادوات مثل CFF Explorer بإزالة الـ DLL can move علي النحو التالي:

image-20200216235551394

الأن بعد حفظ الملف يمكننا تشغيله بـ x64dbg للتأكد من توقف الـ ASLR و تطابق عناوين الذاكرة:

image-20200216235838138


 

IMAGE_DLLCHARACTERISTICS_NO_SEH

الإستثناء Exception هو حدث event يحدث أثناء تنفيذ البرنامج، و يتطلب لحدوثة خروج البرنامج عن إطار عمله العادي و السليم. و هناك نوعان رئيسيان من الإستثناءات:

الـ Structured Exception Handling SEH هي آلية للتعامل مع كل من استثناءات الأجهزة والبرامج حيث توفر للمطور كتابة برنامج يتعامل مع الـ Hardware Exceptions والـ Software Exceptions بنفس الطريقة مما يوفر التحكم الكامل في معالجة الإستثناءات و تصحيحها، يمكنك تخيل الـ Exception Handling علي انه القدرة علي تنفيذ تعليمات برمجية في حالة فشل تعليمات أخري. البرنامج في المثال التالي تمت كتابته بلغة ++C و يحاول القسمة علي الصفر مما سيؤدي إلي الإستثناء 0xC0000094: Integer division by zero و تنفيذ الـ Block داخل finally__ حيث سيطبع النص Exception handled using SEH:

image-20200229201046147

بالنسبة للراية IMAGE_DLLCHARACTERISTICS_NO_SEH فعند تفعيلها لن يعمل الـ SEH ولن يدرك البرنامج حدوث Exception ليقوم بتنفيذ تعليمات الإستثناء Exception code، لاحظ عدم طباعة شيء بعد التعديل علي البرنامج:

image-20200229201601937


 

IMAGE_DLLCHARACTERISTICS_NO_ISOLATION

قد تحتوي الـ Executable Image بغض النظر عن طريقة الربط المُستخدمة لإنشائها (الربط الثابت او الديناميكي) علي مجموعة من البيانات metadata تصف كيفية ارتباط العناصر الموجودة داخلها ببعضها البعض. فالـ assemlby manifest او الـ manifest للإختصار يحتوي على جميع البيانات الأولية اللازمة لتحديد إصدار الـ Executable image وهوية الأمان security identity التابعة لها، وجميع البيانات الوصفية اللازمة لتحديد ومعالجة الموارد resources، و يمكن تخزين الـ manifest إما داخل الـ Executable image نفسها سواء كانت ملف تنفيذي او مكتبة ربط ديناميكية او في Executable image منفصلة فقط تحمل الـ assembly manifest. الصورة التالية توضح الاختلاف في طريقة تخزين الـ manifest:

assembly-types-diagram

و يؤدي الـ assembly manifes الوظائف التالية:

مثال علي الشكل العام للـ manifes:

image-20200228185310229

رجوعا للـ IMAGE_DLLCHARACTERISTICS_NO_ISOLATION فهو ما يحدد ما إذا كان الـ loader سيراجع الـ manifest قبل تحميل الـ Executable image للذاكرة ام لا، إذا كان مُفعلا فلن يراجعه الـ loader و لن يتم العمل بما يحدده. المثال التالي يوضح العملية السابق ذكرها، في البداية قم بإنشاء برنامج بسيط بستخدام CodeBlocks فقط يقوم بكتابة الجملة "Hello World":

image-20200228184728011

بفتح الملف داخل اداة مثل PEstudio ستجد انه ما من manifest بالأساس:

image-20200228184942305

الأمر بسيط فبستخدام أداة مثل ResEdit يمكننا إضافة manifest tamplate علي النحو التالي:

minf

الأن دعنا نقم بالتعديل علي الـ manifest tamplate بستخدام اداة مثل PLB Manifest Editor:

BLP

لاحظ بعد تعديل الـ requestedExecutionLevel من asInvoker إلي requireAdministrator يتطلب الأن لتشغيل البرنامج إعطائه صلاحيات Administrator

image-20200228191608044

مع ذلك بالتعديل علي IMAGE_DLLCHARACTERISTICS_NO_ISOLATION سيعمل البرنامج بشكل طبيعي نتيجة لأن الـ loader لن يراجع الـ mainfiest بحثا عما إذا كان البرنامج يتطلب صلاحيات معينة للعمل ام لا و سيباشر العمل بالصلاحيات التلقائية التي يعطيها له المستخدم (تماما مثلما يحدث عند استخدام asInvoker)

image-20200228191934848

test

IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY يشير إلي لزوم التحقق من سلامة الـ Module قبل تحميله.

IMAGE_DLLCHARACTERISTICS_NX_COMPAT بداية من Windows Vista تضمن نظام التشغيل Windows خاصية جديدة تهدف للحماية من الهجمات الخارجية مثل الـ Buffer overflow و يشار لها بالـ Data Execution Prevention DEP او No-Execute NX و التي تمنع تنفيذ تعليمات لغة الألة من مناطق الذاكرة التي لا تمتلك إذونات التنفيذ Execute premissions و الـ IMAGE_DLLCHARACTERISTICS_NX_COMPAT يمكنها من استخدام خاصية الـ DEP علي Windows Vista فيما بعدها.

IMAGE_DLLCHARACTERISTICS_NO_BIND عند تفعيل تلك الراية لن يتم قيد الـ Executable image.

IMAGE_DLLCHARACTERISTICS_WDM_DRIVER الـ Executable Image عبارة عن WDM driver.

IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE عندما لا يكون البرنامج علي دراية بالخادم الطرفي Terminal Server يقوم الخادم الطرفي بإجراء تعديلات معينة علي البرنامج لجعله يعمل بشكل صحيح في بيئة متعددة المستخدمين. إذا كان التطبيق علي علم به فسيعمل البرنامج بشكل طبيعي.


DataDirectory

يحمل مؤشر لمصفوفة من التركيب IMAGE_DATA_DIRECTORY

و يأتي في نهاية الـ optional header و يمثل واحدة من اهم تراكيبه بسبب ما يوفره حيث ان وظيفة مصفوفة الـ DataDirectory هي اعطاء المعلومات عن أين يمكن ايجاد مكونات الـ Executable image مثال الدوال التي يحتاجها البرنامج من مكتبات الربط الديناميكية او الموارد التي سيستخدمها البرنامج اثناء عملية التشغيل لأخره حيث ان كل عنصر من عناصر المصفوفة يحمل نوع التركيب IMAGE_DATA_DIRECTORY_ و الذي يحتوي علي الـ RVA الخاص بالرموز النصية strings او الجداول tables و حجمها.

فيما يلي عناصر مصفوفة الـ DataDirectory:-


Section Table

كل صف من صفوف الـ section table هو فالواقع header، و يأتي مكان الـ section table بعد الـ optional header مباشرة حيث ان الـ file header لا يحمل مؤشر لعنوان بداية الـ section table، بدلا من ذلك يتم تحديد موقع الـ section table عن طريق حساب موقع الـ byte الأولي بعد الـ headers، و يتم تحديد عدد عناصر الـ section table عن طريق الـ NumberOfSections من الـ file header مع مراعاة المحاذا في عناوين و احجام الـ sections بما يوافق الـ SectionAlignment من الـ optional header.

و يمتلك كل section header داخل الـ section table التركيب strcutre التالي:

image-20200109135805787

و الـ Section Table عبارة عن مصفوفة من التراكيب من نوع IMAGE_SECTION_HEADER_:

image-20200113132419087

السجلات entries الأربع التالية غير مهمة لنا و دائما ما تساوي 0 فالـ executable images:

 

Characteristics يحمل خصائص القسم Section Flags. يمكن لهذا العضو ان يحمل العديد من القيم يهمنا فقط منها القيم التالية:

image-20200113134941761


Predefined Sections

تحتوي الأقسام على محتوى الملف، بما في ذلك التعليمات البرمجية والبيانات والموارد والمعلومات التنفيذية الأخرى، يحتوي كل قسم على header يحدد خصائص و محتوي القسم و body يحتوي علي البيانات الخاصة بالقسم. من المهم معرفة احتواء الـ Executable image عادة علي تسع أقسام محددة مسبقا هم:

مع ذلك لا تحتاج الـ Executable image دائما الي كل هذه الأقسام، بينما قد يحدد بعض الأقسام الحاجة لأقسام أخري، فيما يلي مناقشة للأقسام الأكثر اهمية و شيوعا في الـ PE files:

Executable code section, .text

في هذا القسم يتم جمع جميع تعليمات لغة الألة التي سيتم تنفيذها داخل البرنامج بشكل افتراضي. هذا النمط في تخزين البيانات مفيد حيث يوفر سهولة في ادارة القسم اثناء عملية التشغيل للنظام و للمطور بسبب استخدام Windows لنظام ادارة ذاكرة إفتراضية يعتمد علي تقسيم البيانات الي صفحات ذاكرة page-based virtual memory management system كل منها يتمتع بخواص و صلاحيات مستقلة قد تختلف فيما بينها. الـ text section يوجد بداخله الـ C run time CRT المذكور بالأعلي بالأضافة إلي الـ Import address table IAT.

Data sections, .bss, .rdata, .data, .pdata

الـ bss section يمثل البيانات الغير مهيئة والتي سيتم تهيئتها اثناء عملية التشغيل مثل المتغيرات التي تمتلك مدي ثابت static extent

الـ radata section يمثل كل البيانات التي تمتلك فقط صلاحية بالقراءة read-only premission مثال النصوص literal strings و الثوابت constants

الـ data section يمثل كل المتغيرات الأخري بستثناء ذات النطاق التلقائي auomatic extent و التي تظهر علي المكدس stack، مثال الـ global variables الخاصة بالـ module

الـ pdata section يحمل مصفوفة من بدايات الدوال function entries يتم استخدامها في التعامل مع الإستثناءات exception handling و تحديد اي دالة سيتم تنفيذها في حالة حدوث استثناء معين

Resources section, .rsrc

الـ rsrc section يحتوي علي معلومات الموارد الخاصة بالـ Module، تتعد للموارد حيث يمكن ان تكون احدي الأنواع التالية:

و يختلف تركيب الـ rsrc عن باقي التراكيب حيث يتم تنسيقه كشجرة من الموارد resource tree في الـ IMAGE_RESOURCE_DIRECTORY والتي تشكل الـ root والـ nodes للتركيب:

Characteristics دائما يساوي صفر TimeDateStamp يحمل قيمة تاريخ و وقت إنشاء المورد MajorVersion رقم الأصدار الرئيسي للمورد MinorVersion رقم الأصدار الثانوي للمورد NumberOfNamedEntries عدد العناصر التي تمتلك اسماء NumberOfIdEntries عدد العناصر التي تمتلك رقم تعريفي ID

بالنظر للـ IMAGE_RESOURCE_DIRECTORY لن تجد اي مؤشر للفروع nodes التالية، عوضا عن ذلك يتم استخدام عضوين التركيب NumberOfNamedEntries و NumberOfIdEntries لتحديد عدد السجلات الخاصة بالـ directory entry حيث تتبعه السجلات مباشرة في الـ data section.

و يتكون الـ directory entry من حقلين كما يتضح فالـ IMAGE_RESOURCE_DIRECTORY_ENTRY:

يتم استخدام الـ Name للتعريف عن إما نوع او أسم او لغة المورد و الـ TheOffsetToData دائما للتعريف عن اقربائه siblings من الفروع.

بالنسبة للـ leaf nodes و التي تمثل اخر مستوي من مستويات الـ Resource tree فهي تُعرف الحجم و الموقع لبيانات المورد. كل leaf node يتم تمثيلها بتركيب IMAGE_RESOURCE_DATA_ENTRY:

OffsetToData يحمل الـ relative virtual address RVA الخاص البيانات نسبتا للـ base address Size حجم البيانات المُشار إليها عن طريق المؤشر offsetToData

الرسم التالي يوضح تقسيم الـ resource tree:

3a06a9ee732027fe79bb6ed7b943c735a7fa51be

 

Export data section, .edata

الـ edata section يحمل المخرجات من مكتبات الربط الديناميكية DLL، هذا القسم يحمل export directory للوصول لمعلومات المخرجات export information و الذي يمتلك التركيب التالي:

Characteristics هذه القيمة محجوزة و يجب ان تساوي القيمة 0

TimeDateStamp وقت و تاريخ إنشاء البيانات فالـ export data

MajorVersion رقم الأصدار الرئيسي للـ export data

MinorVersion رقم الأصدار الثانوي للـ export data

Name يحمل الـ RVA للنص الذي يُعرف اسم الدالة

Base يحمل الرقم الترتيبي الأساسي للدوال المخرجة export functions حيث يحدد هذا الحقل نقطة البدء لجدول المخرجات export table و عادة ما تكون قيمته 1

NumberOfFunctions عدد الدوال functions في جدول عناوين المخرجات export address table.

NumberOfNames عدد اسماء الدوال في جدول عناوين المخرجات و يتطابق قيمته تلقائيا مع قيمة الـ NumberOfFunctions

AddressOfFunctions يحمل الـ offset لقائمة من بدايات الدوال المخرجة exported function entry points

AddressOfNames يحمل الـ offset لبداية قائمة يفصل الـ 0x00 بين عناصرها null-separated list من اسماء الدوال المخرجة exported function names

AddressOfNameOrdinals يحمل الـ RVA لعنوان الجدول الترتيبي ordinal table لأسماء الدوال

الصورة التالية توضح ما تكون عليه البيانات في الـ edata section:

image-20200401000434812

 

Import data section, .idata

عناوين الدوال الخاصة بمكتبات الربط الديناميكية في الذاكرة ليست ثابتة، بمجرد ان يقوم الـ Loader بتحميل الـ Executable image للذاكرة يقوم ببعض الوظائف منها تحميل مكتبات الربط الديناميكية و تصحيح عناوينها حتي يمكن للبرنامج استخدام تلك الدوال، يتم ذلك عن طريق قسم للواردات import section حيث يتم فيه تخزين معلومات مكتبات الربط الديناميكة و الدوال المستخدمة منها من قبل البرنامج:

image-20200401014321493

تبدأ بيانات الواردات بالـ Import Directory Table او الـ Import table للإختصار، حيث يحتوي علي معلومات العناوين المستخدمة في عملية إصلاح fixup بدايات الدوال DLL entries، و يتكون الـ import directory من مصفوفة من تركيب IMAGE_IMPORT_DESCRIPTOR يحمل كل عضو فالمصفوفة المعلومات الخاصة بإحدي مكتبات الربط الديناميكية المستخدمة بالبرنامج، يتم التعريف عن تركيب IMAGE_IMPORT_DESCRIPTOR علي النحو التالي:

OriginalFirstThunk يحتوي علي الـ RVA للـ Import LookUp Table ILT او للـ Import Name Table INT، و يحتوي الـ ILT علي معلومات كيفية التعامل مع البيانات الورادة عن طريق الترتيب اما الـ INT فعن طريق الأسم. Name يحمل الـ RVA لقيمة نصية تمثل اسم المكتبة المستخدمة و التي سيتم منها الحصول علي البيانات الواردة import information مثال KERNEL32.dll FirstThunk و يحمل الـ RVA للـ Import Address Table IAT

والـ Import Address Table هو جدول من مؤشرات الدوال التي سيتم استخدامها اثناء عملية التشغيل والتي يتم الوصول لها عن طريق استدعاء الدالة مباشرة بستخدام المؤشر مثال:

او عن طريق jump للـ thunk table مثال:

قبل تحميل الملف للذاكرة يشير الـ OriginalFirstThunk لنفس تركيب الـ IMAGE_THUNK_DATA التي يشير ليها FirstThunk لكن في الذاكرة يختلف الأمر حيث يشير الـ OriginalFirstThunk بعد تحميله للعنوان الخاص بالدالة في الذاكرة، الصورة التالية توضح عملية تصحيح العناوين و تبديل محتوي الـ Import Address Table بمؤشرات صالحة لدوال المكتبات:

Imports_on_Disk

Imports_in_Memory

لكل دالة واردة يستخدمها البرنامج هناك تركيب من الـ IMAGE_THUNK_DATA و التي تُعرف المعلومات اللازمة للتعامل و استخدام الدالة علي النحو التالي:

و تخدم الـ IMAGE_THUNK_DATA غرضين رئيسيين فالـ IAT إما ان يحمل ترتيب الدوال الواردة او الـ RVA للتركيب IMAGE_IMPORT_BY_NAME:

Hint يحمل مؤشر index لمكان وجود الدالة المراد استخدامها داخل الـ Export Address Table الخاص بمكتبة الربط الديناميكي حتي يتمكن الـ loader من الوصول للدالة عند مراجعة جدول المخرجات الخاص بالمكتبة DLL’s Export Address Table

Name يحمل قيمة نصية تساوي الأسم الخاص بالدالة الواردة

 

thread local storage, .tls

يدعم نظام التشغيل Windows وجود اكثر من Thread واحد للـ Process، لكل Thread يتم تخصيص مساحة تخزينية محلية تسمي thread local storage TLS. لذلك في كل مرة يتم فيها إنشاء thread يتم بالضرورة إنشاء TLS لهذا الـ thread و يتم استخدام الـ tls section لتحديد المواصفات التلقائية التي سيكون عليها الـ TLS، كون التعليمات داخل الـ tls section تتم قبل بدأ الـ thread و كون لإنشاء process يجب إنشاء thread رئيسي في بداية البرنامج يجعل من الـ tls ييبدأ حتي قبل الـ entry point للبرنامج، هذا الأمر جعل مطوري البرامج الخبيثة يتجهون في بعض الأحيان الي استخدام الـ tls section لتنفيذ ما كانت البرمجية الخبيثة ستفعله في محاولة لتضليل المُحلل.

 


المصادر

  1. https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
  2. https://en.wikipedia.org/wiki/Portable_Executable
  3. https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32
  4. https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64
  5. https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_section_header
  6. https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_nt_headers64
  7. https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_nt_headers32
  8. https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-process_mitigation_aslr_policy
  9. https://docs.microsoft.com/en-us/windows/win32/win7appqual/dep-nx-protection
  10. https://blog.netspi.com/verifying-aslr-dep-and-safeseh-with-powershell/
  11. http://www.openrce.org/reference_library/files/reference/PE%20Format.pdf
  12. http://uploads.7bit.net.ru/2013-02/1360716397-pecoff_v8.pdf
  13. https://media.blackhat.com/bh-us-11/Vuksan/BH_US_11_VuksanPericin_PECOFF_WP.pdf
  14. https://github.com/leecade/reverse-engineering-for-beginners/blob/master/Chapter-68/Windows-NT.md
  15. https://www.sans.org/blog/dealing-with-aslr-when-analyzing-malware-on-windows-8-1/
  16. https://stackoverflow.com/questions/41910841/what-is-the-isolated-image-attribute-in-a-pe
  17. https://docs.microsoft.com/en-us/windows/win32/sbscs/manifest-files-reference?redirectedfrom=MSDN
  18. https://docs.microsoft.com/en-us/cpp/build/reference/allowisolation?redirectedfrom=MSDN&view=vs-2019
  19. https://stackoverflow.com/questions/41910841/what-is-the-isolated-image-attribute-in-a-pe
  20. https://docs.microsoft.com/en-us/dotnet/standard/assembly/manifest
  21. https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests
  22. http://csi-windows.com/toolkit/240-great-pe-editor-for-internal-manifests
  23. https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling
  24. https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement?view=vs-2019
  25. https://docs.microsoft.com/en-us/cpp/cpp/exception-handling-differences?view=vs-2019
  26. https://blog.kowalczyk.info/articles/pefileformat.html
  27. https://www.quora.com/What-is-the-difference-between-pageable-and-non-pageable-memory-Is-user-memory-space-pageable-or-non-pageable
  28. https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/making-drivers-pageable
  29. https://tech-zealots.com/malware-analysis/understanding-concepts-of-va-rva-and-offset/
  30. https://tech-zealots.com/malware-analysis/journey-towards-import-address-table-of-an-executable-file
  31. https://tech-zealots.com/malware-analysis/pe-portable-executable-structure-malware-analysis-part-2
  32. https://resources.infosecinstitute.com/2-malware-researchers-handbook-demystifying-pe-file/#gref
  33. https://resources.infosecinstitute.com/malware-researchers-handbook/#gref
  34. https://keystrokes2016.wordpress.com/2016/06/03/pe-file-structure-sections
  35. https://github.com/mmn3mm/peresources

الأدوات

  1. https://hshrzd.wordpress.com/pe-bear
  2. https://ntcore.com/?page_id=388
  3. https://ghidra-sre.org
  4. https://x64dbg.com/#start
  5. http://www.resedit.net
  6. https://www.visualplb.com/plb-manifest-editor