1

[原创]新手——010纯手工编辑打造PE文件

Weaving 2018-4-15 16:24 788
工具
1.010Editor :填充16进制码
2.lordPE     :检查PE文件出错原因
知识背景
1.  PE知识   :  (PE中结构体的字段分布,PE加载器的原理)
2.  汇编知识 :  (汇编调用MessageBoxA个ExitProcess)

目标:构造一个程序(CUI).exe
程序功能:
1.调用MessageBoxA弹出消息框
2.调用ExitProcess退出程序
思路
1.在Windows下PE文件格式的程序如何运行?
答:符合PE格式的文件+系统加载器,如何成功运行程序,失败,报错。
2.那么系统加载的原理或者执行逻辑又是什么呢?
答:
加载器:简单执行流程如下
1.内存映射
2.修复IAT
3.修复重定位
tip:本次程序并没有重定位,只需要考虑前2步即可。
3.PE文件如何构建?还可以做哪些优化呢?
答:
构建:
1.Dos头:IMAGE_DOS_HEADER;
1.1->WORD   e_magic; //标识符:MZ
1.2->LONG   e_lfanew;  //Dos头部的大小
2.NT头:IMAGE_NT_HEADERS32
2.1->DWORD Signature;
2.2->IMAGE_FILE_HEADER FileHeader;
2.3->IMAGE_OPTIONAL_HEADER32 OptionalHeader;
3.区段头:IMAGE_SECTION_HEADER
3.1 ->.text
3.2 ->.rdata
4.区段数据数据
4.1 ->代码数据(OpCode) == 200+
4.2 ->导入数据(IAT、导入表、INT、HitName) == 200+
优化:
1.DosStub是个历史遗留问题,在一定情况下也可在该区域填写代码,但在本次程序可以将该区域删除。
2.区段减少到2个,.text、.rdata。(ps:其实还可以减少到只有一个区段.text)
3.对程序运行无影响的字段用0填充。


构造PE步骤


1.整理以上思路大致可以得到以下思维导图
仔细观察PE文件的格式,就不难发现到处都体现出了头部+身体,目录+内容的管理数据的思想,那么对于我们自己手工建立PE文件,同样也可以以此作为思路开始构建PE文件。(在构建时最好同时去做这两件事,有助于加快进度)
1.组成头部:
1.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;
关键字段:
 1.WORD   e_magic; ==> MZ  => 4D 5A (标识符)
 2.LONG   e_lfanew; ==> 40h => 40 00 00 00(DosStub去除后,IMAGE_DOS_HEADER 的结构体大小就是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
----------------------------------------------------------------------------------------------------
1.2-NT头
typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

关键字段:
1.2.1.DWORD Signature;                           ==> PE ==>50 45 00 00 (标识符)
1.2.2IMAGE_FILE_HEADER FileHeader; 
typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
关键字段
2.1 WORD    Machine;                          ==> x86  ==>   4c 01 (0x014c 应用的机器型号)
2.2 WORD    NumberOfSections;         ==> 2个  ==>   02 00 (1.text 2.rdata)
2.3 WORD    SizeOfOptionalHeader;   ==> E0    ==>    E0 00 (NT扩展头大小)
2.4 WORD    Characteristics;               ==> 10F  ==>     0F 01 (可以自定义)

1.2.3. IMAGE_OPTIONAL_HEADER32 OptionalHeader;
typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //
    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;
    //
    // NT additional fields.
    //
    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
关键字段
3.1 WORD    Magic;                                            ==> 10B    ==>0B 01 (文件类型:PE32文件)
3.2 DWORD   AddressOfEntryPoint;                  ==> 1000   ==>00 10 00 00(.text在文件中200h位置,转内存偏移后为1000h)
3.2 DWORD   ImageBase;                                 ==> 40000 ==>00 00 04 00 (PE文件在内存的优先加载起始地址VA)
3.3 DWORD   SectionAlignment;                       ==> 1000h ==>00 10 00 00 (内存对齐)
3.4 DWORD   FileAlignment;                             ==> 200h   ==>00 02 00 00 (文件对齐)
3.5 WORD    MajorOperatingSystemVersion;   ==> 6         ==>06 00
3.6 WORD    MajorSubsystemVersion;             ==> 6         ==>06 00
3.7 DWORD   SizeOfImage;                              ==>207E   ==> 7E 20 00 00 (加载到内存中镜像大小)
3.8 DWORD   SizeOfHeaders;                          ==>200h   ==> 00 02 00 00  (Dos+NT+Section :在文件中未超过200h)
3.9 WORD    Subsystem;                                ==> 3        ==>03 00        (使用界面的子系统:(CUI) subsystem)   
3.10 WORD    DllCharacteristics;                    ==> 8100  ==>00 81        (DLL文件属性)
3.11 DWORD   NumberOfRvaAndSizes;        ==> 10h    ==>10 00        (表示数据目录结构的数量.默认16个)
3.12 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
          ==>Import Table                                   ==>  10 20 00 00  (.rdata 在400h处,rva: 2000h+10h(IAT字节数)) 
                                                                       ==>  3C 00 00 00    (有2个DLL,即2个导入表结构体(结尾为20个00),即3Ch个字节)

--------------------------------------------

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

--------------------------------------------

1.3-区段头
typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    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;


关键字段
1.text
1.1 BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];      ==>.text            ==>   2E 74 65 78 74 00 00 00(区段名称)
1.2 DWORD   VirtualSize;                                                  ==>22h             ==>   22 00 00 00 (有效的OpCode数目)
1.3 DWORD   VirtualAddress;                                            ==>1000h         ==>   00 10 00 00 (区段rva:200h映射到内存中为1000h)
1.4 DWORD   SizeOfRawData;                                          ==>200h           ==>   00 02 00 00 (在文件中的对齐后大小)
1.5 DWORD   PointerToRawData;                                     ==>200h           ==>   00 02 00 00 (在文件中相对与0的偏移)
1.6 DWORD   Characteristics;                                            ==>E00000E0  ==>  E0 00 00 E0 (区段属性可以自定义)
2.rdata

1.1 BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];      ==>.rdata          ==>   2E 72 64 61 74 61 00 00(区段名称)

1.2 DWORD   VirtualSize;                                                  ==>7Eh             ==>   7E 00 00 00 (有效的字节数目)

1.3 DWORD   VirtualAddress;                                            ==>2000h         ==>   00 20 00 00 (区段rva:400h映射到内存中为2000h)

1.4 DWORD   SizeOfRawData;                                          ==>200h           ==>   00 02 00 00 (在文件中的对齐后大小)

1.5 DWORD   PointerToRawData;                                     ==>400h           ==>   00 04 00 00 (在文件中相对与0的偏移)

1.6 DWORD   Characteristics;                                            ==>E00000E0  ==>  E0 00 00 E0 (区段属性可以自定义)


--------------------------------------------
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
--------------------------------------------
tip:200对齐其余填0
2.组成身体:
2.1-区段1.text
伪代码如下:
push 0x0;
push 0x0;
push 0x0;
push 0x0;
call MessageBoxA;
push 0x0;
call ExitProcess;
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
--------------------------------------------
6A 00
6A 00
6A 00
6A 00
FF 15 00 20 40 00
6A 00
FF 15 08 20 40 00
--------------------------------------------
tip:200对齐其余填0
2.2-区段2.rdata



1.IAT:
typedef struct _IMAGE_THUNK_DATA {
    union {
        DWORD   ForwarderString;  
        DWORD   Function;         
        DWORD   Ordinal;
        DWORD   AddressOfData;    
    } u1;
} IMAGE_THUNK_DATA;          
关键字段
1.DWORD   AddressOfData1;                             ==>  MessageBoxA ==>5C 20 00 00 00 00 00 00 (以0结尾)
2.DWORD   AddressOfData2;                             ==>  ExitProcess     ==>75 20 00 00 00 00 00 00 (以0结尾)
tip:加载到内存后IAT里面的内容更新为API的为VA,不在和INT的内容相同。
2.Import Table:
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;

3.INT:
typedef struct _IMAGE_THUNK_DATA {
    union {
        DWORD   ForwarderString;  
        DWORD   Function;         
        DWORD   Ordinal;
        DWORD   AddressOfData;    
    } u1;
} IMAGE_THUNK_DATA;

关键字段

1.DWORD   AddressOfData1;                             ==>  MessageBoxA ==>5C 20 00 00 00 00 00 00 (以0结尾)

2.DWORD   AddressOfData2;                             ==>  ExitProcess     ==>75 20 00 00 00 00 00 00 (以0结尾)

tip:75、5C为字节偏移。

4.HitName:
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
关键字段
1.MessageBoxA
1.1 WORD    Hint;                                                ==> API名称在DLL中的编号==>00 00 (名称导入)
1.2 CHAR   Name[1];                                           ==>MessageBoxA名称        ==>4D 65 73 73 61 67 65 42 6F 78 41
                                                                             ==>USER32.dll                   ==>00 55 53 45 52 33 32 2E 64 6C 6C 00
2.ExitProcess
2.1 WORD    Hint;                                                ==> API名称在DLL中的编号==>00 00 (名称导入)
2.2 CHAR   Name[1];                                           ==> ExitProcess名称           ==>45 78 69 74 50 72 6F 63 65 73 73
                                                                             ==>KERNEL32.dll               ==>00 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00
tip:DLL函数结尾处,会加以DLL名称结尾
--------------------------------------------
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
--------------------------------------------
tip:200对齐其余填0

结语

以上将16进制码复制到010Editor中保存为.exe格式即可运行,运行环境为win10,并未考虑兼容性的问题,发帖的本意为0到1质变,1往后的变化希望大家自行发挥,例如:添加新的区段,在弹窗中添加文字,将代码复杂化等等。


最新回复 (9)
friendanx 2018-4-15 19:43
2
VaultHunter 2018-4-16 08:07
3
HadesW 2018-4-16 08:56
4
社会白
懒癌晚期 2018-4-16 15:45
5
新手膜拜...
DeeLMind 2018-4-16 17:59
6
都是大佬
ggsuper 2018-4-16 18:01
7
mark
聖blue 2018-4-16 23:21
8
tianjigezhu 6天前
9
这思维导图啥画的啊
1
Weaving 5天前
10
Xmind
返回