新手——010纯手工编辑打造PE文件
工具
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;
*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 0000 00 40 00
00 10 00 00
00 02 00 0006 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 8100 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
10 00 00 0000 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 E02E 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
伪代码如下:
<b>push 0x0;</b>
<b>push 0x0;</b>
<b>push 0x0;</b>
<b>push 0x0;</b>
<b>call MessageBoxA;</b>
<b>push 0x0;</b>
<b>call ExitProcess;</b>
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_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 0000 00 40 00
00 10 00 00
00 02 00 0006 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 8100 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
10 00 00 0000 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 E02E 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
结语
以上将16进制码复制到010Editor中保存为.exe格式即可运行,运行环境为win10,并未考虑兼容性的问题,发帖的本意为0到1质变,1往后的变化希望大家自行发挥,例如:添加新的区段,在弹窗中添加文字,将代码复杂化等等。