Portable Executable PE

PE-Files

السَّلاَمُ عَلَيْكُمْ وَرَحْمَةُ اللهِ وَبَرَكَاتُهُ

اللَّهُمَّ صَلِّ عَلَى مُحَمَّدٍ وَعَلَى آلِ مُحَمَّدٍ، كَمَا صَلَّيْتَ عَلَى إِبْرَاهِيمَ وَآلِ إِبْرَاهِيمَ، إِنَّكَ حَمِيدٌ مَجِيدٌ، وَبَارِكْ عَلَى مُحَمَّدٍ وَعَلَى آلِ مُحَمَّدٍ، كَمَا بَارَكْتَ عَلَى إِبْرَاهِيمَ وَآلِ إِبْرَاهِيمَ، إِنَّكَ حَمِيدٌ مَجِيدٌ،

Introduction

[+] هنتكلم فـ المقالة دي عن الـ PE Format ، وهنعرف شوية حاجات زي:

  1. إي هو الـ PE Format.
  2. ليه هو مهم.
  3. هنشرح الـ PE File Structure.
  4. هنكتب كود بسيط بالـ C يقرأ الـ DOS Header لملف PE.

1. إي هو الـ PE Format.

[+] الـ Portable Executable (PE) Format هو الهيكل الأساسي لأي ملف تنفيذي ع Windows ، زي:

  • ملفات .exe (البرامج العادية).
  • ملفات .dll (مكتبات الربط الديناميكية).
  • حتى بعض ملفات .sys (الدرايفرز).

[+] أي برنامج بتشغله ع ويندوز معمول بصيغة PE ، لأنه الشكل القياسي اللـ الويندوز بيستخدمه لتحميل وتشغيل الملفات التنفيذية.

2. ليه هو مهم؟

[+] معرفة الـ PE Format طبعا مهمة ومفيدة لكذا حد ، بمعني إن:

  • لو مهتم بـ Reverse Engineering ، فـ فهم الـ PE هيساعدك في تحليل البرامج ، سواء لفحصها أو حتى لفهم الـ Malwares.
  • ولو بتطور برامج ، فهمك للـ PE هيخليك تعرف إزاي الويندوز بيتعامل مع الأكواد ، وإزاي الـ DLLs بيتعملها Sharing بين البرامج.
  • ولو حاجه تانية غيرهم ، فـ يسيدي اعرفه لمجرد المعرفة أكيد هيفيدك يوم من الأيام يعني.

3. الـ PE File Structure :

[+] عرفنا فوق إنه الهيكل الأساسي لأي برنامج تنفيذي ع الويندوز ، والهيكل دا بيتكون من 3 أجزاء رئيسية:

  1. جزء الـ Headers
  2. ↑ ودا فية معلومات تخص الملف نفسه .. زي نوعه (EXE / DLL / SYS) .. وكمان نقدر نعرف معلومات تانية زي هل الملف ده 32-bit أو 64-bit وحجم الملف ، وهكذا .. وهنتكلم عنهم بالتفصيل كمان شوية.

  3. جزء الـ Data Directories
  4. ↑ وهنا بنعرف منه نقط الوصول اللـ بيقدر يوصل للـ Libraries ، سواء يعمل Import أو Export.

  5. جزء الـ Sections
  6. ↑ ودا فيه الأكواد بتاعة البرنامج نفسة.

PE-Headers

[+] نبدأ بـ أول جزء وهو:

1. الـ Headers:

ودا بيتكون من كذا جزء زي:

  1. Dos Header
  2. Dos Sub
  3. NT Headers:
    • NT Signature
    • File Header
    • Optional Header

[+] تعالي نبدأ بيهم واحد واحد ، وبالتفصيل:

1.1.1 الـ Dos Header:

[+] كل ملف PE بيبدأ بالـ Dos Header ، ودا بيهدف إن بيخلي الملف من صيغة MS-DOS Executable ، يعني ملف تشغيلي ع أنظمة MS-DOS.

[+] زمان في أنظمة MS-DOS:

  • كان الويندوز بيشغل البرامج من خلال Command Line (بدون واجهة رسومية GUI).
  • كان لما بيحصل عليه Load من الـ MS-DOS ، بيتأكد من الهيدرز ويشوف هل هو فعلا من صيغة MS-DOS Executable ولا لا.
  • لو اه ع الصيغة ، فـ يبدأ بعدها الـ DOS Stub يشتغل ، ولو لا .. يقولك فشل التعرف ع البرنامج وميشتغلش.

[+] حاليا فـ أنظمة الويندوز الحديثة:

  • الـ DOS Header بقى موجود بس عشان التوافق مع الأنظمة القديمة، بس مش بيتم استخدامه فعليًا.

1.1.2 بنية الـ DOS Header:

[+] الـ DOS Header حجمه 64 بايت ، بيحتوي ع معلومات ، ودا كان مهم للـ PE Loader ع الـ MS-DOS ، وهنتكلم عن أهم عنصرين فيه وهما الـ e_magic ، والـ e_lfanew.

DOS-Header
  • الـ e_magic (Signature) :
    1. دا أول عنصر فـ عناصر الـ DOS Header ، وبيتكون من 2 بايت اسمهم الـ (Magic Numbers).
    2. قيمتة ثابته دايما 0x5A4D بالـ Hex ، أو MZ كـ Ascii (الحروف دي نسبة إلى Mark Zbikowski اللي صمم الصيغة دي).
  • الـ e_lfanew (Offset to NT Headers) :
    1. دا آخر عنصر فـ الـ DOS Header ، واللوكيشن بتاعه بيكون فـ الـ Offset الـ 0x3C.
    2. بيحدد نقطة البداية للـ NT Headers داخل الملف.

1.1.3 تحليل DOS Header عمليًا باستخدام PE-BEAR:

[+] هوضحلك الفكرة بـ مثال عملي:

[+] إفتح برنامج الـ PE-Bear .. إختار أي ملف .exe ، فـ حالتي دي أنا فتحت الـ Mspaint.exe .. روح ع الـ DOS Header .. هتلاقي ايه بقي ؟

  1. أول حاجه هتلاقي 2 bytes بتوع الـ Magic Number ودول الـ 0x4D5A بالـ hex أو MZ بالـ Ascii .. وبيكون موجود ع الـ Offset رقم 0.
  2. لو روحت ع اخر عنصر اللـ هو الـ e_lfanew اللـ موجود عند الـ Offset رقم 0x3C ، هتلاقي مكتوب إن الـ Value بتاعته 0xE8 .. ودا قولنا إنه بيشير للـ offset بتاع بداية الـ NT Header.
DOS-Header2

[+] طب تعالي نتأكد ونشوف هل الكلام دا فعلا صح ولا لا .. هنقف ع الـ NT Header .. ونشوف أول Value واللـ هي فـ الحالة بتاعتي دي 0x50 ودي اللـ هي تقاطع بداية أول صف مع بداية أول عمود .. طب موجودة عن الـ Offset كام؟ .. لو بصيت هتلاقي ان دا الـ Offset رقم 0xE8 يعني فعليا الكلام اللـ قولناه فوق طلع صح.

DOS-Header3

1.2 الـ DOS Stub:

[+] ودا اتكلمنا عنه فوق وقولنا ان كان زمان موجود تبع أنظمة الـ MS-DOS ، ولسه موجود فـ الأنظمة الحديثة عشان يتوافق مع الإصدارات القديمة .. وكل مهمة الجزء هنا عشان يطبع الجملة دي بس ، وملوش لازمه غير كده ، وحجمة 64 bytes زي الـ Dos Header.

This program cannot be run in DOS mode
DOS-Stub

الـ Rich Header

[+] بعد الـ DOS Stub ، هتلاقي داتا غريبة بينه وبين NT Headers ، والجزء ده اسمه Rich Header.

  • ده مش جزء أساسي من الـ PE Format ، بس موجود لو الملف اتعمله Build باستخدام أدوات Microsoft زي Visual Studio.
  • بيحتوي ع معلومات عن المترجم (Compiler) ، إصدار Visual Studio ، والـ Build Number .. وكدا.
  • مش بيكون موجود فـ كل ملفات الـ PE ، بس بيساعد أحيانًا فـ معرفة أداة الـ Build المستخدمة.
Rich-Header

الـ :RVA – Relative Virtual Address

[+] قبل مـ ندخل فـ الـ NT Headers ، لازم نفهم يعني إيه RVA الأول ، عشان هنحتاجه كتير بعد كده.

[+] الـ RVA (Relative Virtual Address) هو عنوان نسبي جوه الميموري ، بيشاور ع أماكن محددة جوا الـ PE File.

  • الفرق بينه وبين العنوان العادي إنه مش مُطلق ، يعني مش بيتحدد بناءً ع الذاكرة الفعلية اللـ الويندوز بيحجزها للبرنامج ، بس نسبي لبداية التحميل بتاع البرنامج فـ الميموري.
  • الويندوز لما بيحمل ملف PE فـ الميموري ، بيحجزله عنوان معين (Base Address) ، وكل حاجة جواه بتتحسب نسبةً للعنوان ده.

[+] هقولك مثال عملي عشان تفهم الفكرة:

  • تخيل إن عندك برنامج exe الويندوز قرر يحمله فـ الميموري عند العنوان 0x400000
  • وبعدين لقيت إن Entry Point بتاع البرنامج موجود عند RVA = 0x1000 ، فده معناه إيه؟
  • معناه إن العنوان الفعلي اللـ الويندوز هيبدأ منه التنفيذ هو:
Base Address (0x400000) + RVA (0x1000) = 0x401000

[+] طب إيه فايدة الـ RVA؟

  • الويندوز لما بيحمّل أي ملف PE ، مش شرط يحطه فـ نفس العنوان كل مرة ، بس الـ RVA بيسمحله يعرف أماكن كل حاجة نسبةً لمكان التحميل.
  • الـ PE Loader بيستخدم الـ RVA عشان يعرف فين نقطة البداية (Entry Point) ، وفين الأكواد ، وفين الـ Imports / Exports.

1.3 الـ NT Headers:

[+] الـ NT Headers هو تاني جزء رئيسي فـ الـ PE File بعد الـ DOS Header ، وبيحتوي ع 3 أجزاء رئيسية:

NT-Headers
  1. PE Signature
  2. File Header
  3. Optional Header

1.3.1 PE Signature:

  • أول 4 بايت فـ الـ NT Headers ، بتمثل التوقيع بتاع ملفات PE.
  • دايمًا بيكون 0x50450000 بالـ Hex، أو "PE\0\0" بالـ ASCII.
  • ده ببساطة بيأكد للويندوز إن الملف ده فعلًا PE File ، ولو التوقيع مش موجود أو مش متوافق ، الملف مش هيشتغل.
PE-Signature

1.3.2 File Header (COFF Header):

[+] الـ File Header (أو COFF Header) فيه شوية معلومات أساسية عن الملف ، وبيتكون من 7 عناصر رئيسية:

NT-Headers2
  1. Machine:
  2. ده رقم بيعبر عن نوع المعالج (CPU Architecture) اللـ البرنامج ده معمول له زي:

    • 0x014C → Intel 386 (x86 - 32-bit).
    • 0x8664 → AMD64 (x64 - 64-bit).

    وتقدر تقرأ من [هنا] وتشوف كل الأنواع.

    NT-Headers3
  3. NumberOfSections:
    • بيوضح عدد الـ Sections الموجودة فـ الملف.
    • كل برنامج لازم يكون فيه Sections زي .text (للكود) ، .data (للمتغيرات) ، وهكذا.
  4. TimeDateStamp:
    • ده وقت وتاريخ إنشاء الملف ، بس مش بيكون دايمًا دقيق ، خصوصًا مع الملفات اللـ بيتم تعديلها أو معالجتها ببرامج Packers / Protectors.
  5. PointerToSymbolTable & NumberOfSymbols
    • دول كانوا بيتم استخدامهم فـ COFF Debugging Symbols، بس حاليًا مش بيتم استخدامهم فـ معظم الملفات التنفيذية الحديثة.
  6. SizeOfOptionalHeader
    • بيحدد حجم الـ Optional Header (الموجود بعد الـ File Header).
  7. Characteristics
  8. مجموعة Flags بتحدد بعض الخصائص بتاعة الملف ، زي:

    • 0x0002 → ملف Executable (EXE).
    • 0x2000 → ملف DLL.
    • 0x8000 → ملف System (Driver).

    وتقدر تقرأ من [هنا] وتشوف كل الخصائص التانية.

    NT-Headers4

1.3.3 Optional Header:

[+] الـ Optional Header جزء مهم جدًا ، لأن الـ PE Loader بيعتمد عليه بشكل أساسي فـ تشغيل البرامج ، ودا شكل الهيكل بالعناصر بتاعته فـ نسخة الـ 32-bit والـ 64-bit:

NT-Headers5

[+] طب إيه الفرق بين 32-bit و 64-bit؟

  • نسخة الـ 32-bit فيها عنصر زيادة اسمه BaseOfData ، مش موجود فـ نسخة الـ 64-bit.
  • بعض الـ Data Types بتختلف بين النسختين.

[+] أهم العناصر فـ الـ Optional Header:

  1. Magic
  2. ↑ بيوضح إذا كان الملف 32-bit أو 64-bit:

    • 0x10B → 32-bit PE File.
    • 0x20B → 64-bit PE File.
    NT-Headers6
  3. MajorLinkerVersion & MinorLinkerVersion
  4. ↑ بيوضح نسخة الـ Linker اللـ تم استخدامه لإنشاء الملف.

    فـ المثال ده ، الـ Linker version بيكون E14 ، ودي حاجة تهم الـ PE Loader:

    NT-Headers7
  5. SizeOfCode
  6. ↑ بيوضح حجم الأكواد التنفـذية ، وغالبًا بتكون موجودة فـ الـ [.text] Section.

    NT-Headers8
  7. SizeOfInitializedData
  8. ↑ حجم البيانات اللـ تم تهيئتها ، وعادةً بتكون فـ الـ [.data] Section.

    NT-Headers9
  9. SizeOfUninitializedData
  10. ↑ حجم البيانات الغير مهيأة ، وعادةً بتكون فـ الـ [.bss] Section.

    NT-Headers10
  11. AddressOfEntryPoint
  12. ↑ ده RVA بيحدد أول Instruction هيتم تنفـذها لما الملف يتحمل فـ الميموري.

    مهم جدًا فـ عمليات Reverse Engineering & Malware Analysis ، لأنه بيحدد أول سطر كود هيشتغل.

    NT-Headers11
  13. BaseOfCode
  14. ↑ ده RVA بيشاور على أول Byte فـ الكود التنفـذي.

    NT-Headers12
  15. BaseOfData (موجود فـ 32-bit بس)
  16. ↑ ده RVA بيشاور على أول Byte فـ الـ Data Section.

    NT-Headers13
  17. NumberOfRvaAndSizes
  18. ↑ عدد العناصر الموجودة فـ DataDirectory Array.

    NT-Headers14
  19. Data Directory
  20. ↑ ده Array فيه بيانات بتحدد حاجات زي Imports / Exports / Resources ، وهنتكلم عنها كمان شوية.

    NT-Headers15

[+] تاني جزء وهو:

الـ Data Directory:

[+] فـ الجزء اللـ فات ، كنا بنتكلم عن Optional Header ، وشفنا إنه بيحتوي ع DataDirectory ، واللـ هو عبارة عن Array فيها بيانات بتساعد الـ PE Loader أثناء تحميل وتشغيل الملف.

[+] طب يعني إيه Data Directory أصلاً؟

ببساطة الـ Data Directory دي عبارة عن بيانات بتكون موجودة جوا أحد الـ Sections بتاعة ملف الـ PE ، والهدف منها إنها بتوفر معلومات حيوية للـ Loader عشان يعرف يستخدم الـ Imports, Exports, Resources, Debug Info... etc.

[+] ودي شكلها عامل إزاي؟

الـ Data Directory عبارة عن Array مُكوّن من 16 عنصر:

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16

وكل عنصر فيهم هو هيكل بيانات من نوع IMAGE_DATA_DIRECTORY

IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

، والهيكل ده بيتكوّن من حاجتين بس:

  1. VirtualAddress
  2. ↑ وده عبارة عن RVA (Relative Virtual Address) بيشاور ع بداية الـ Data Directory فـ الميموري.

  3. Size
  4. ↑ وده حجم الـ Data Directory نفسه.

DataDirectory

بمعنى أبسط ، أي Data Directory هي مجرد مكان جوا الميموري فيه بيانات معينة ، والـ VirtualAddress بيشاور عليه ، والـ Size بيحدد مساحته.

[+] طب إيه هي أنواع الـ Data Directories؟

كل نوع من الـ Data Directories ليه وظيفة مختلفة ، ودول الـ 16 Directory الأساسيين اللـ بيكونوا موجودين فـ الملفات التنفيذية ع الويندوز:

DataDirectory2
  1. Export Directory (IMAGE_DIRECTORY_ENTRY_EXPORT)
  2. ↑ خاص بالدوال اللـ البرنامج بيصدرها عشان برامج تانية تقدر تستخدمها.

  3. Import Directory (IMAGE_DIRECTORY_ENTRY_IMPORT)
  4. ↑ خاص بالدوال اللـ البرنامج بيستوردها من مكتبات تانية (DLLs).

  5. Resource Directory (IMAGE_DIRECTORY_ENTRY_RESOURCE)
  6. ↑ خاص بالـ Resources زي الأيقونات ، الصور ، النصوص ، والـ dialogs اللـ جوه الملف.

  7. Exception Directory (IMAGE_DIRECTORY_ENTRY_EXCEPTION)
  8. ↑ بيحتوي ع معلومات الـ Exception Handling الخاصة بالبرنامج.

  9. Security Directory (IMAGE_DIRECTORY_ENTRY_SECURITY)
  10. ↑ بيحفظ البيانات الخاصة بالتوقيعات الرقمية (Digital Signatures) لو البرنامج موقع رقمياً.

  11. Base Relocation Table (IMAGE_DIRECTORY_ENTRY_BASERELOC)
  12. ↑ فيه البيانات الخاصة بتعديل عناوين الميموري أثناء تحميل الملف (لو مكانه فـ الميموري اختلف).

  13. Debug Directory (IMAGE_DIRECTORY_ENTRY_DEBUG)
  14. ↑ بيحفظ معلومات خاصة بالـ Debugging Symbols لو البرنامج متكامل مع أدوات Debugging.

  15. Architecture Specific Data (IMAGE_DIRECTORY_ENTRY_ARCHITECTURE)
  16. ↑ مش بيستخدم عادةً ، بس معمول لأنظمة معينة لو محتاجة بيانات خاصة.

  17. Global Pointer (IMAGE_DIRECTORY_ENTRY_GLOBALPTR)
  18. ↑ خاص بأنظمة الـ IA-64 وكان بيستخدم للـ Global Pointer Register.

  19. TLS Directory (IMAGE_DIRECTORY_ENTRY_TLS)
  20. ↑ مسؤول عن بيانات الـ Thread Local Storage (TLS) ، وده بيكون مهم للـ Multithreading.

  21. Load Configuration Directory (IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG)
  22. ↑ بيحتوي ع معلومات خاصة بإعدادات تحميل الملف.

  23. Bound Import Directory (IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)
  24. ↑ بيحتوي ع معلومات عن الـ DLLs اللـ البرنامج مربوط بيها وقت الـ Linking.

  25. Import Address Table (IMAGE_DIRECTORY_ENTRY_IAT)
  26. ↑ خاص بجدول العناوين اللـ بيتم استدعاء الدوال الخارجية منه.

  27. Delay Load Import Descriptors (IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)
  28. ↑ مشابه للـ Import Directory لكنه بيأخر تحميل الـ DLLs لحد ما يتم استدعاؤها فعلياً.

  29. COM Runtime Descriptor (IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
  30. ↑ خاص بالملفات اللـ بتستخدم .NET CLR والـ COM Interop.

DataDirectory

[+] طب هل كل ملفات الـ PE فيها الـ 16 Directory دول؟

لأ ، مش شرط .. أوقات لما تفتح ملف PE ممكن تلاقي بعض الـ Data Directories القيم بتاعتها 0x00000000 سواء فـ الـ VirtualAddress أو الـ Size ، وده معناه إن النوع ده من الـ Data Directories مش مُستخدم فـ الملف.

[+] آخر جزء وهو:

3. الـ Sections:

[+] الـ Sections هي الأجزاء اللـ بتحتوي ع الأكواد والبيانات الفعلية للبرنامج ، وهي بتبدأ بعد الـ Headers ع طول .. كل Section بيكون ليه اسم بيدل ع وظيفته ، ودي أشهر الـ Sections الموجودة جوه أي ملف PE:

PE-Sections
  • [text.]
  • ↑ وده أهم جزء ، لأنه بيحتوي ع الكود التنفيذي (Executable Code) بتاع البرنامج. يعني هنا بتلاقي التعليمات البرمجية اللـ الـ CPU بينفذها.

  • [data.]
  • ↑ بيحتوي ع البيانات اللـ اتعملها تهيئة مسبقة (Initialized Data) ، يعني المتغيرات اللـ ليها قيم محددة قبل مـ البرنامج يشتغل.

  • [bss.]
  • ↑ بيحتوي ع البيانات اللـ ملهاش تهيئة مسبقة (Uninitialized Data) ، يعني أي متغيرات اتعرفت بس مفيش قيم اتحطت فيها قبل تشغيل البرنامج.

  • [rdata.]
  • ↑ وده بيحتوي ع بيانات ثابتة للقراءة فقط (Read-Only Data) ، زي الـ Strings اللـ مش هتتغير أثناء تشغيل البرنامج.

  • [edata.]
  • ↑ الجزء ده فيه جدول التصدير (Export Table) ، اللـ بيحدد أي دوال (Functions) بيتم تصديرها من الملف عشان تستخدمها برامج تانية.

  • [idata.]
  • ↑ وده العكس ، بيحتوي ع جدول الاستيراد (Import Table) ، اللـ فيه كل الدوال والـ APIs اللـ البرنامج بيحتاج يستدعيها من مكتبات تانية (زي دوال Windows API من kernel32.dll مثلًا).

  • [reloc.]
  • ↑ ده فيه معلومات إعادة التمركز (Relocation Information) ، ودي مهمة لو البرنامج هيتحمل في الميموري عند عنوان مختلف عن اللـ كان متوقع وقت الكومبايل.

  • [rsrc.]
  • ↑ ده خاص بالـ Resources ، يعني أي موارد بيستخدمها البرنامج زي الأيكونات ، الصور ، الفورمات ، أو حتى ملفات مدمجة جواه.

  • [tls.]
  • ↑ وده بيخص الـ Thread Local Storage (TLS) ، ودي آلية بتوفر لكل Thread مجموعة من البيانات الخاصة بيه منفصلة عن باقي الـ Threads.

PE-Sections2

[+] طب هل كل ملفات الـ PE فيها نفس الـ Sections دي؟

لأ ، مش كل الملفات بتحتوي ع كل الـ Sections دي ، بعض الملفات ممكن يكون فيها Sections بأسماء مختلفة حسب نوع البرنامج والمترجم (Compiler) اللـ اتعمل بيه.

[+] دا بوستر لطيف شامل ولامم كل حاجه عن الـ PE ، وتقدر تشوفه من [هنا].

PE-Poster

4. DOS Header Reader:

[+] فـ الجزء ده ، هنكتب كود C بسيط نتعلم بيه إزاي نقرأ الـ Magic Numbers لأي ملف PE:

[+] دا الكود النهائي وهنشرحه دلوقتي:

#include <windows.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
    if (argc < 2) {
        printf("Usage: %s <PE File>\n", argv[0]);
        return -1;
    }

    HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        printf("Failed to open file.\n");
        return -1;
    }

    IMAGE_DOS_HEADER dosHeader;
    DWORD bytesRead;
    ReadFile(hFile, &dosHeader, sizeof(IMAGE_DOS_HEADER), &bytesRead, NULL);

    if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
        printf("Not a valid PE file.\n");
        CloseHandle(hFile);
        return -1;
    }

    printf("Valid PE file detected!\n");
    printf("DOS e_magic: 0x%X\n", dosHeader.e_magic);

    CloseHandle(hFile);
    return 0;
}

[+] الكود ده ببساطة برنامج مكتوب بلغة C بيقرأ الـ DOS Headers بتاعة أي ملف PE (Portable Executable) ، وبيتحقق إذا كان فعلاً ملف PE صالح ولا لأ.

[+] تعالي نشرح الكود جزء بجزء:

  • أول جزء هنا بيتأكد من عدد الـ arguments اللـ انت بتدخلهم للبرنامج ، لو العدد أقل من 2 (argc < 2)، يبقى اليوزر كدا مكتبش اسم ملف PE بعد تشغيل البرنامج .. فـ الحالة دي ، بيطبع رسالة توضح طريقة الاستخدام.
  •     if (argc < 2) {
            printf("Usage: %s <PE File>\n", argv[0]);
            return -1;
        }
  • تاني جزء هنا بيحاول يفتح الملف اللـ انت عطتهوله ، بيستخدم CreateFileA ودي Windows API بتفتح الملف اللـ اسمه argv[1] .. وبصلاحيات Read-Only عشان يقدر يقرأه .. ولو فشل فـ فتح الملف بيقولك انه فشل عادي جدا.
  •     HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
            printf("Failed to open file.\n");
            return -1;
        }
  • تالت جزء هنا البرنامج بيبدأ يقرأ أول 64 byte من الملف .. ولو لقاهم مختلفين عن الهيدر اللـ هو عارفهم اللـ هما 0x5A4D بالـ Hex ، أو MZ كـ Ascii .. يبقي كدا البرنامج مش PE ويخرج برسالة خطأ بتقول إن دا مش برنامج PE.
  •     IMAGE_DOS_HEADER dosHeader;
        DWORD bytesRead;
        ReadFile(hFile, &dosHeader, sizeof(IMAGE_DOS_HEADER), &bytesRead, NULL);
        if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
            printf("Not a valid PE file.\n");
            CloseHandle(hFile);
            return -1;
        }
  • آخر جزء ودا عادي جدا .. لو كان فعلا البرنامج PE من تالت جزء .. فـ هنا هيطلع اه فعلا PE .. ويطبع الـ Magic Numbers ، ويقفل الـ Handle.
  •     printf("Valid PE file detected!\n");
        printf("DOS e_magic: 0x%X\n", dosHeader.e_magic);

        CloseHandle(hFile);
        return 0;
    }

[+] هنبدأ نجرب نـ رن الكود ونشوف إي الكلام:

  1. هنفتح الـ Visual Studio ونضيف الكود فـ main.c بعدين نعمل Build:
  2. DOS-Reader
  3. هنفتح الـ exe بالـ CMD ، ونجرب نـ رن البرنامج لوحده .. هيطلع الإستخدام بتاعه وإن مطلوب تديله ملف الـ PE:
  4. DOS-Reader2
  5. فـ الحالة دي جربت برنامج exe ، وطلع إن فعلا هو ملف PE:
  6. DOS-Reader3
  7. بعدين جربت كذا ملف تاني وزي مـ انت شايف الـ Output:
  8. DOS-Reader4

وبكدا . أتمني تكون استفدت حاجه .. ونلتقي فـ مقالة قادمة .. ولو عندك أي تعليق ، استفسار ، أي حاجه .. متترددش وكلمني.

References

خدلك لفة فـ المصادر والمراجع يا عزيزي: