純手寫簡單PE

純手寫簡單PE

環境:

Windows 10

010Editor

LoadPE(查看寫的是否正確,文中並沒有截圖)

目的:

使用十六進制編輯器(010Editor)手寫一個可在Windows10上運行的只彈出MessageBox對話框最簡單的exe程序

1.構造DOS頭 

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
關鍵字段(DOS頭)
 WORD   e_magic;    // Magic number                                          =>標記位 4D 5A (MZ)
 LONG   e_lfanew;  // File address of new exe header =>DOS頭大小 40 00 00 00(40h)
(DosStub去除後,IMAGE_DOS_HEADER 的結構體大小就是Dos頭大小)
//DOS頭
4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00

2.構造NT頭 

//64位
typedef struct _IMAGE_NT_HEADERS64 {
    DWORD Signature;                            
    IMAGE_FILE_HEADER FileHeader;                
    IMAGE_OPTIONAL_HEADER64 OptionalHeader;        
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;                            //標示符(PE)
    IMAGE_FILE_HEADER FileHeader;               //文件頭結構體
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;     //可選映像頭結構體
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
關鍵字段(NT頭)
 DWORD Signature;                                        // =>標記位 50 45 00 00 (PE)
 IMAGE_FILE_HEADER FileHeader                // 文件頭結構體
//
// File header format.
//

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;                    //運行平臺
    WORD    NumberOfSections;           //文件區塊數量
    DWORD   TimeDateStamp;              //文件創建日期和時間
    DWORD   PointerToSymbolTable;       //指向符號表(主要用於調試)
    DWORD   NumberOfSymbols;            //符號表中符號個數
    WORD    SizeOfOptionalHeader;       //IMAGE_OPTIONAL_HEADER32結構大小
    WORD    Characteristics;            //文件屬性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
 關鍵字段(文件頭)
    WORD    Machine;                          // 運行平臺                                                     => 4C 01(x86)
             (#define IMAGE_FILE_MACHINE_I386 0x014c  // Intel 386. )
             (#define IMAGE_FILE_MACHINE_IA64 0x0200   // Intel 64    )   
             (#define IMAGE_FILE_MACHINE_AMD64 0x8664  // AMD64 (K8))       
  WORD    NumberOfSections;         // 文件區塊數量                                            => 02 00(2個 , 1 .text , 2 .rdata)
  WORD    SizeOfOptionalHeader;  // IMAGE_OPTIONAL_HEADER32結構大小  => E0 00
 WORD    Characteristics;       // 文件屬性                    => 0F 01

 IMAGE_OPTIONAL_HEADER32 OptionalHeader  // 可選映像頭結構體
typedef struct _IMAGE_OPTIONAL_HEADER  
{  
//  
// Standard fields.  
//  
+18h WORD Magic; // 標誌字, ROM 映像(0107h),普通可執行文件(010Bh)  
+1Ah BYTE MajorLinkerVersion; // 鏈接程序的主版本號  
+1Bh BYTE MinorLinkerVersion; // 鏈接程序的次版本號  
+1Ch DWORD SizeOfCode; // 所有含代碼的節的總大小  
+20h DWORD SizeOfInitializedData; // 所有含已初始化數據的節的總大小  
+24h DWORD SizeOfUninitializedData; // 所有含未初始化數據的節的大小  
+28h DWORD AddressOfEntryPoint; //-----> 程序執行入口RVA(OEP)   
+2Ch DWORD BaseOfCode; // 代碼的區塊的起始RVA  
+30h DWORD BaseOfData; // 數據的區塊的起始RVA  
//  
// NT additional fields. 以下是屬於NT結構增加的領域。  
//  
+34h DWORD ImageBase; // ---------->程序的首選裝載地址(基地址)  
+38h DWORD SectionAlignment; // 內存中的區塊的對齊大小  
+3Ch DWORD FileAlignment; // 文件中的區塊的對齊大小  
+40h WORD MajorOperatingSystemVersion; // 要求操作系統最低版本號的主版本號  
+42h WORD MinorOperatingSystemVersion; // 要求操作系統最低版本號的副版本號  
+44h WORD MajorImageVersion; // 可運行於操作系統的主版本號  
+46h WORD MinorImageVersion; // 可運行於操作系統的次版本號  
+48h WORD MajorSubsystemVersion; // 要求最低子系統版本的主版本號  
+4Ah WORD MinorSubsystemVersion; // 要求最低子系統版本的次版本號  
+4Ch DWORD Win32VersionValue; // 莫須有字段,不被病毒利用的話一般爲0  
+50h DWORD SizeOfImage; // 映像裝入內存後的總尺寸  
+54h DWORD SizeOfHeaders; // 所有頭 + 區塊表的尺寸大小  
+58h DWORD CheckSum; // 映像的校檢和  
+5Ch WORD Subsystem; // 可執行文件期望的子系統  
+5Eh WORD DllCharacteristics; // DllMain()函數何時被調用,默認爲 0  
+60h DWORD SizeOfStackReserve; // 初始化時的棧大小  
+64h DWORD SizeOfStackCommit; // 初始化時實際提交的棧大小  
+68h DWORD SizeOfHeapReserve; // 初始化時保留的堆大小  
+6Ch DWORD SizeOfHeapCommit; // 初始化時實際提交的堆大小  
+70h DWORD LoaderFlags; // 與調試有關,默認爲 0  
+74h DWORD NumberOfRvaAndSizes; // 下邊數據目錄的項數,這個字段自Windows NT 發佈以來 // 一直是16  
+78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];  
//-----> 數據目錄表  
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;  
 關鍵字段(可選映像頭)
 WORD     Magic;              // 標識符               => 0B 01(可執行文件)
  DWORD   AddressOfEntryPoint;// 程序執行入口(OEP)RVA=> 00 10 00 00(1000h)
  DWORD   ImageBase;                    // 程序首選基址           => 00 00 40 00(400000h)
  DWORD   SectionAlignment;       //內存中對齊大小=>  00 10 00 00(1000h)
  DWORD   FileAlignment;// 文件中對齊大小=>  00 02 00 00(1000h)
  WORD    MajorOperatingSystemVersion;// 操作系統最低版本主版本號              => 06 00
 WORD    MajorSubsystemVersion;    // 最低子系統版本主版本號                  => 06 00
  DWORD   SizeOfImage;                             // 加載到內存中映像大小=> 7E 20 00 00
 DWORD   SizeOfHeaders;                         // DOS頭+NT頭+Section(此文件中未超過200h) =>00 02 00 00
  WORD    Subsystem;                             // 子系統(03,GUI)=>03 00
         (#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3//Image runs in the Windows character subsystem.)
   WORD    DllCharacteristics;                // Dll被調用屬性 =>00 81
   DWORD   NumberOfRvaAndSizes;              // 數據目錄表項數(默認16個)=>10 00 00 00
 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];   // 16項,我們只用到了導入表項

//
// Directory format.
//

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress 
// 2000h+10h(IAT字節數)                             =>10 20 00 00

IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size                     
// 2個Dll,即兩個導入表結構體(20個00結尾)=>3C 00 00 00
            ( #define IMAGE_DIRECTORY_ENTRY_IMPORT  1  // Import Directory )

//整個NT頭
50 45 00 00 4C 01 02 00 00 00 00 00 00 00 00 00
00 00 00 00 E0 00 0F 01 0B 01 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00
00 00 00 00 00 00 40 00 00 10 00 00 00 02 00 00
06 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00
7E 20 00 00 00 02 00 00 00 00 00 00 03 00 00 81
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00
10 20 00 00 3C 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00

3.構造區段頭 

//
// Section header format.
//

#define IMAGE_SIZEOF_SHORT_NAME              8

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME]; // 節表名稱,如“.text” 
    union {
            DWORD   PhysicalAddress;       // 物理地址
            DWORD   VirtualSize;           // 真實長度,這兩個值是一個聯合結構,可以使用其中的任何一個,一般是取後一個
    } Misc;
    DWORD   VirtualAddress;                // 節區的 RVA 地址
    DWORD   SizeOfRawData;                 // 在文件中對齊後的尺寸
    DWORD   PointerToRawData;              // 在文件中的偏移量
    DWORD   PointerToRelocations;          // 在OBJ文件中使用,重定位的偏移
    DWORD   PointerToLinenumbers;          // 行號表的偏移(供調試使用地)
    WORD    NumberOfRelocations;           // 在OBJ文件中使用,重定位項數目
    WORD    NumberOfLinenumbers;           // 行號表中行號的數目
    DWORD   Characteristics;               // 節屬性如可讀,可寫,可執行等
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
 關鍵字段(區段頭)
.text段
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];// 區段名稱.text     => 2E 74 65 78 74 00 00 00
    DWORD   VirtualSize;                                    // 真實長度,即有效的OPCode數                 => 22 00 00 00
    DWORD   VirtualAddress;                              // 區段RVA(1000h)   => 0010 00 00
    DWORD   SizeOfRawData;                                // 文件中對齊後的大小 (200h)                      => 00 02 00 00
    DWORD   PointerToRawData;                          // 件中重定位偏移(相對於0的偏移200h ) => 0002 00 00
    DWORD   Characteristics;                            //  區段屬性(可讀可寫可執行)=> E0 00 00 E0
 
.rdata段
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];// 區段名稱.text      => 2E 72 64 61 74 61 00 00
    DWORD   VirtualSize;                                    // 真實長度,即有效的字節數                         => 7E 00 00 00
    DWORD   VirtualAddress;                              // 區段RVA(2000h)                                        => 00 20 00 00
    DWORD   SizeOfRawData;                                // 文件中對齊後的大小 (200h)                      => 00 02 00 00
    DWORD   PointerToRawData;                          // 文件中重定位偏移(相對於0的偏移400h ) => 00 04 00 00
    DWORD   Characteristics;                            //  區段屬性(可讀可寫可執行)=> E0 00 00 E0
 
注:使用0填充至200h(文件對齊200h)
//區段頭
2E 74 65 78 74 00 00 00 22 00 00 00 00 10 00 00
00 02 00 00 00 02 00 00 00 00 00 00 00 00 00 00
00 00 00 00 E0 00 00 E0 2E 72 64 61 74 61 00 00
7E 00 00 00 00 20 00 00 00 02 00 00 00 04 00 00
00 00 00 00 00 00 00 00 00 00 00 00 E0 00 00 E0

4.構造區段身體

.text段
VS程序IAT調用爲:FF 15 XXXXXXXX(IAT地址)(有2個dll)
IAT1:FOA:400h ==> RVA: 2000h ==>VA:400000h + 2000h==>402000h
IAT2:FOA:408h ==> RVA: 2008h ==>VA:400000h + 2008h==>402008h
push 0x0;            // /-_In_ UINT uType              =  0
push 0x0;            // |-_In_opt_ LPCSTR lpCaption    =  0
push 0x0;            // |-_In_opt_ LPCSTR lpText       =  0
push 0x0;            // \_In_opt_ HWND hWnd            =  0
call MessageBoxA;    // MessageBoxA() 
push 0x0;            // /-_In_ UINT uExitCode          =  0
call ExitProcess;    // ExitProcess()
push 0x0;                                    //=> 6A 00
push 0x0;                                    //=> 6A 00
push 0x0;                                    //=> 6A 00
push 0x0;                                    //=> 6A 00
call MessageBoxA;                    //=> FF 15 00 20 40 00
push 0x0;                                    //=> 6A 00
call ExitProcess;                    //=> FF 15 08 20 40 00

注:使用0填充至400h(文件對齊)

.rdata段

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)  INT的地址
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;                                                                                //庫名稱字符串地址
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses) IAT的地址
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

////////////////////////////////////////////////
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;

/////////////////////////////////////////////////
//
// Import Format
//
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;                     //ordinal  
    CHAR   Name[1];                   //function name string  
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
//整個身體
5C 20 00 00 00 00 00 00 75 20 00 00 00 00 00 00
4C 20 00 00 00 00 00 00 00 00 00 00 6A 20 00 00
00 20 00 00 54 20 00 00 00 00 00 00 00 00 00 00
83 20 00 00 08 20 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 5C 20 00 00
00 00 00 00 75 20 00 00 00 00 00 00 00 00 4D 65
73 73 61 67 65 42 6F 78 41 00 55 53 45 52 33 32
2E 64 6C 6C 00 00 00 45 78 69 74 50 72 6F 63 65
73 73 00 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00
IAT:
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
//主要使用 DWORD AddressOfData;字段(兩Dll兩個表,以00 00 00 00結尾) 
=> 5C 20 00 00 00 00 00 00 75 20 00 00 00 00 00 00


Import Table:
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;    // 0 for terminating null import descriptor
               DWORD   OriginalFirstThunk;  //指向INT                  =>4C 20 00 00 
    } DUMMYUNIONNAME;
    DWORD   ForwarderChain;          // -1 if no forwarders     =>00 00 00 00
    DWORD   Name;                         //指向庫文件名(USER32.DLL)  => 6A 20 00 00
    DWORD   TimeDateStamp;          // 0 if not bound           =>00 00 00 00    
DWORD   FirstThunk;                 // RVA to IAT               => 00 20 00 00
IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
    
//同樣兩張表,表1 
=>4C 20 00 00   00 00 00 00   00 00 00 00   6A 20 00 00   
00 20 00 00 
//同樣兩張表,表2 
=> 54 20 00 00   00 00 00 00   00 00 00 00   
83 20 00 00   08 20 00 00  


INT:
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;          // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
//主要使用 DWORD AddressOfData;字段(兩Dll兩個表,以00 00 00 00結尾) 
=> 5C 20 00 00 00 00 00 00 75 20 00 00 00 00 00 00


HintName:
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;                            //名稱導入    =>00 00 
    CHAR   Name[1];   
IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
          
//MessageBoxA名稱 =>4D 65 73 73 61 67 65 42 6F 78 41
//兩個表 ExitProcess名稱 =>00 00 45 78 69 74 50 72 6F 63 65 73 73 + KERNEL32.DLL(DllName)
//兩個表 MessageBoxA名稱 =>00 00 4D 65 73 73 61 67 65 42 6F 78 41 + USER32.DLL(DllName)

DllName:
//USER32.dll   =>00 55 53 45 52 33 32 2E 64 6C 6C 00
//KERNEL32.dll  =>00 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00

注:使用0填充至600h(文件對齊200h)

5.最終文件


6.運行效果


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章