[ شرح ] Advanced] C/C++ PE file format introduction]

تم تحميل الصفحة في 1,9411295 ثانية
Advanced] C/C++ PE file format introduction]
إنضم
1 مايو 2007
المشاركات
4,470
الإعجابات
3,773
النقاط
133
الإقامة
USA





اللهم لك الحمد حمدًا طيّبًا كثيرًا مُباركًا فيه؛
ملء السّماوات وملء الأرض وما بينهما، وملء ما شيئت من شيء بعدهما.


*. أرحب بكم إخواني وأخواتي أعضاء منتدى نقطة التطوير .*

*. أتمنى أن تكونوا في تمام الصحة والعافية.*



Advanced] C/C++ PE file format introduction]

في هذا الدرس سوف نتعلم ماهوه PE file وكيف نتعامل معه مثل القراءة والكتابة
PE تعني Portable Executable اي الملفات التنفيذية مثل امتداد EXE

لماذا نتعلم بنية الملفات التنفيذية PE Files ؟
تعلمك لبنية الملفات التنفيذية تساعد في فهم كيف يعمل النظام
(ويندوز) وايضا سوف تتعلم كيف يتم حقن الملفات الخبيثة او صناعة برامج تشفير (لا اقصد نسخ ولصق الاكواد او تشفير بفونكشن جاهز)
سوف ايضا تتعلم كيف تصنع رانبي RunPE والتلاعب بلملفات التفيذية


Portable Executable - Wikipedia


Structure of a Portable Executable 32 bit
صور من داخل PE









كما نلاحظ في الصور يوجد دائما
MS DOS header.
PE signature
Sections.




سوف يكون تركيزنا على

DOS HEADER and info
NT HEADERS and info
SECTIONS and info


لا تهتم لاي شيء اخر في درس اليوم


من داخل موقع مايكروسوفت شرح IMAGE_DOS_HEADER
رابط لشرح كامل
Portable Executable File Format


C++:
typedef struct _IMAGE_DOS_HEADER {  // DOS .EXE header
    USHORT e_magic;         // Magic number
    USHORT e_cblp;          // Bytes on last page of file
    USHORT e_cp;            // Pages in file
    USHORT e_crlc;          // Relocations
    USHORT e_cparhdr;       // Size of header in paragraphs
    USHORT e_minalloc;      // Minimum extra paragraphs needed
    USHORT e_maxalloc;      // Maximum extra paragraphs needed
    USHORT e_ss;            // Initial (relative) SS value
    USHORT e_sp;            // Initial SP value
    USHORT e_csum;          // Checksum
    USHORT e_ip;            // Initial IP value
    USHORT e_cs;            // Initial (relative) CS value
    USHORT e_lfarlc;        // File address of relocation table
    USHORT e_ovno;          // Overlay number
    USHORT e_res[4];        // Reserved words
    USHORT e_oemid;         // OEM identifier (for e_oeminfo)
    USHORT e_oeminfo;       // OEM information; e_oemid specific
    USHORT e_res2[10];      // Reserved words
    LONG   e_lfanew;        // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

حتى يقوم ويندوز بتحميل (تنفيذ الملف) يجب ان تكون قيمة its e_magic تساوي MZ
WORD e_magic; //"MZ"



NT headers

C++:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;

حتى يقوم ويندوز بتحميل (تنفيذ الملف) يجب يكون لدية توقيع الملفات التنفيذية


الان بعد كتابة _IMAGE_NT_HEADERS سوف نحتاج ان نجلب offset التي يبداء منها

C++:
IMAGE_NT_HEADERS + sizeof IMAGE_NT_HEADERS + sizeof IMAGE_SECTION_HEADER * index

الان يجب ان نجلب عدد السكشنات وسوف نفعل هذا من خلال FILE_HEADER


C++:
ypedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections; //نجلب العدد من خلال هذا البرامتر
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

الان دعونا نلقي نظره على section headers


C++:
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
//الحد الاقصى هوه 8 وليس[/SIZE] [SIZE=5] null terminated
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress; //اين سوف تكون محمله
DWORD SizeOfRawData; //الحجم
DWORD PointerToRawData; //اين هيه داخل الباينري
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics; 
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
الان دعونا نبداء كتابة الاكواد
اولا يجب ان نجعل البرنامج يعرف نفسه من خلال

GetModuleHandle
GetModuleHandle function (Windows)

التعريف
C++:
HMODULE WINAPI GetModuleHandle(
  _In_opt_ LPCTSTR lpModuleName
);
الكود الخاص ببرنامجنا

C++:
HMODULE hModule = GetModuleHandle( NULL );

الان سوف نكتب vector حتى يخزن جميع معلومات section

C++:
vector<PIMAGE_SECTION_HEADER> Sections;


دعونا نكتب فونكشن حتى نجد السكشنز



C++:
unsigned int GetSectionInfo(HMODULE hModule, vector<PIMAGE_SECTION_HEADER> &Sections)
{
    unsigned int nret = 0;[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    //في البداية يجب ان نكتب PIMAGE_DOS_HEADER 
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;[/SIZE][/SIZE]


[SIZE=5][SIZE=5]    //نقوم بلتحقق من ان برنامجنا هوه PE
    if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE)
    {[/SIZE][/SIZE]

[SIZE=5][SIZE=5]        //ntHeaders موجود داخل في hModule + e_lfanew
        PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD)hModule + (DWORD)dosHeader->e_lfanew);[/SIZE][/SIZE]

[SIZE=5][SIZE=5]        //نقوم بلتحقق من التوقيع لكن نستطيع التخلي عن هذا التحقق لكن مجرد زياده الحذر
        if (ntHeaders->Signature == IMAGE_NT_SIGNATURE)
        {
            //نستخرج عدد السكشنات
            nret = ntHeaders->FileHeader.NumberOfSections;[/SIZE][/SIZE]

[SIZE=5][SIZE=5]            for (unsigned int i = 0; i < nret ; i++)
            {
                //عدد السكشنات مضروب في الانديكس حتى نحصل على السكشن
                PIMAGE_SECTION_HEADER sectionHeader = PIMAGE_SECTION_HEADER((DWORD)ntHeaders + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * i);[/SIZE][/SIZE]

[SIZE=5][SIZE=5]                //نحفظ كلشيء داخل vector
                Sections.push_back(sectionHeader);
            }
        }
    }[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    return nret;
}


الان سوف نقوم بلتاكد من برنامجنا ووفقا الى موقع مايكروسوفت اذا برنامجنا خالي من الاخطاء سوف نحصل على هذا الناتج

C++:
IMAGE_SCN_MEM_EXECUTE
0x200[/SIZE][/SIZE]

[SIZE=5][SIZE=5]The section can be executed as code.[/SIZE][/SIZE]

[SIZE=5][SIZE=5]IMAGE_SCN_MEM_READ
0x400[/SIZE][/SIZE]

[SIZE=5][SIZE=5]The section can be read.[/SIZE][/SIZE]

[SIZE=5][SIZE=5]IMAGE_SCN_MEM_WRITE
0x800[/SIZE][/SIZE]

[SIZE=5][SIZE=5]The section can be written to.

الان سوف نتحقق ان كنا نستطيع الكتابه والقراءة والتنفيذ

C++:
void PrintCharacteristics(DWORD Characteristics)
{[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    if( Characteristics & IMAGE_SCN_MEM_READ )
    {
  printf("(READ)");
    }[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    if( Characteristics & IMAGE_SCN_MEM_WRITE )
    {
  printf("(WRITE)");
    }[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    if( Characteristics & IMAGE_SCN_MEM_EXECUTE )
    {
  printf("(EXECUTE)");
    }
}

والى هنا انتينا من البرنامج ويبقى ان نجمع الاكواد جميعها



C++:
#include <windows.h>
#include <vector>
#include <stdio.h>[/SIZE][/SIZE]

[SIZE=5][SIZE=5]using namespace std;[/SIZE][/SIZE]

[SIZE=5][SIZE=5]unsigned int GetSectionInfo(HMODULE hModule, vector<PIMAGE_SECTION_HEADER> &Sections)
{
    unsigned int nret = 0;[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
    if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE)
    {
        PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD)hModule + (DWORD)dosHeader->e_lfanew);
        if (ntHeaders->Signature == IMAGE_NT_SIGNATURE)
        {
            nret = ntHeaders->FileHeader.NumberOfSections;[/SIZE][/SIZE]

[SIZE=5][SIZE=5]            for (unsigned int i = 0; i < nret - 1; i++)
            {
                PIMAGE_SECTION_HEADER sectionHeader = PIMAGE_SECTION_HEADER((DWORD)ntHeaders + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * i);
                Sections.push_back(sectionHeader);
            }
        }
    }[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    return nret;
}[/SIZE][/SIZE]

[SIZE=5][SIZE=5]void PrintCharacteristics(DWORD Characteristics)
{
    if (Characteristics & IMAGE_SCN_MEM_READ)
    {
        printf("(READ)");
    }[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    if (Characteristics & IMAGE_SCN_MEM_WRITE)
    {
        printf("(WRITE)");
    }[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    if (Characteristics & IMAGE_SCN_MEM_EXECUTE)
    {
        printf("(EXECUTE)");
    }
}[/SIZE][/SIZE]

[SIZE=5][SIZE=5]int main()
{
    HMODULE hModule = GetModuleHandle(nullptr);
    vector<PIMAGE_SECTION_HEADER> Sections;[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    unsigned int sectionCount = GetSectionInfo(hModule, Sections);[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    for (unsigned int i = 0; i < sectionCount ; i++)
    {
        //نقوم بلتقسيم على  %.8 لان اكبر عدد ممكن هوه 8 وانه ليس  null terminated
        printf("Section: %.8s\n", Sections[i]->Name);
        printf("Virtual Address: 0x%4X\n", Sections[i]->VirtualAddress);
        printf("Size Of Raw Data: 0x%X\n", Sections[i]->SizeOfRawData);
        printf("Ptr Raw Data: 0x%4X\n", Sections[i]->PointerToRawData);
        PrintCharacteristics(Sections[i]->Characteristics);[/SIZE][/SIZE]

[SIZE=5][SIZE=5]        printf("\n\n");
    }
    //حتى نبقي الكونسل مفتوح
    system("PAUSE");[/SIZE][/SIZE]

[SIZE=5][SIZE=5]    return 0;
}[/SIZE][/SIZE]



[SIZE=5][SIZE=5]


الناتج




الان حتى نتعلم بطريقه اكبر يوجد مقالة كامله من قبل مايكروسوفت تشرح كلشيء بكل التفاصيل
Peering Inside the PE: A Tour of the Win32 Portable Executable File Format


نعم عزيزي المتابع التشفير ليس سهل مثل مانقوم بتشفير الملفات التنفيذيه عندما نستعمل فونكشنز جاهزه او نقوم بتغير بعض القيم
ممكن ان نصل لما نريد لكن حتى تصبح مبرمج يجب ان نتعلم بنية الملفات التنفيذية






(بعض الاشياء منقوله لاسهل الشرح باكبر قدر ممكن حتى يفهم الجميع)

*. [ ~ .. في أمان الله .. ~ ] .*


*. [ ~ .. Mariio.. ~ ] .*
 
التعديل الأخير بواسطة المشرف:
إنضم
27 يناير 2018
المشاركات
124
الإعجابات
229
النقاط
43
العمر
22
السلام عليكم
اسمحلي اخي الحبيب على هذا التعقيب الخفيف على الأوامر المستعملة...

عندما اقوم ببناء المشروع بدون اي تعديل ينتج عندي ملف تنفيذي يظهر هذه المعلومات:


التطبيق يظهر 4 مقاطع فقط مع ان الملف التنفيذي يحتوي على 5 مقاطع!

و بعد فحص الأوامر تبن الخلل:
هنا:
JavaScript:
 for (unsigned int i = 0; i < nret-1; i++) {
و هنا:
JavaScript:
    for (unsigned int i = 0; i < sectionCount-1; i++) {
nret-1 و sectionCount-1
يتم تجاهل اضافي للعدد لان المقارنة تقف عند تحقق الشرط (اقل)

و عند التعديل على الأوامر بحذف 1- من الكود لكي نحصل فقط على nret و sectionCount ينجح التطبيق في اظهار كامل المقاطع:
مثل ما هو موضح:


اخوكم YANiS
 
إنضم
1 مايو 2007
المشاركات
4,470
الإعجابات
3,773
النقاط
133
الإقامة
USA
السلام عليكم
اسمحلي اخي الحبيب على هذا التعقيب الخفيف على الأوامر المستعملة...

عندما اقوم ببناء المشروع بدون اي تعديل ينتج عندي ملف تنفيذي يظهر هذه المعلومات:


التطبيق يظهر 4 مقاطع فقط مع ان الملف التنفيذي يحتوي على 5 مقاطع!

و بعد فحص الأوامر تبن الخلل:
هنا:
JavaScript:
 for (unsigned int i = 0; i < nret-1; i++) {
و هنا:
JavaScript:
    for (unsigned int i = 0; i < sectionCount-1; i++) {
nret-1 و sectionCount-1
يتم تجاهل اضافي للعدد لان المقارنة تقف عند تحقق الشرط (اقل)

و عند التعديل على الأوامر بحذف 1- من الكود لكي نحصل فقط على nret و sectionCount ينجح التطبيق في اظهار كامل المقاطع:
مثل ما هو موضح:


اخوكم YANiS

شكرا للملاحظه اخي ريجنارك

دققت على الكود وكلامك صحيح
ربما لاني كنت اقوم بكتابه الموضوع وترتيب الاكواد حتى تسهل على القارءة ونتج الخطاء بدون ان الاحظ :26:

ارجو من المشرفين التعديل على الاكواد
:38:
 

๖ۣۜA M E E R

إداري أقسام حماية الأجهزة
إنضم
8 سبتمبر 2013
المشاركات
6,937
الإعجابات
10,355
النقاط
168
الإقامة
Iraq
عاشت ايديك اخي ماريو .. بالنسبة لإشارة الاستاذ المحترم @ragnarok سوف يتم تعديل الموضوع
مروره مفيد دائماً .. ♥
 

الأعضاء النشطين حاليآ الذين يشاهدون هذا الموضوع (3 عضو و 3 ضيف)

خيارات الاستايل

نوع الخط
مودك
اخفاء السايدر بار OFF
توسيط المنتدى OFF
فصل الأقسام OFF
الأقسام الفرعية OFF
عرض المشاركات
حجم الخط
معلومات العضو OFF
إخفاء التوقيع OFF

إرجاع خيارات الإستايل