纯手写简单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)     => 00 10 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.运行效果


猜你喜欢

转载自blog.csdn.net/wrsharper/article/details/79981066
今日推荐