PE(Portable Executable可移植的执行体),它是Win32自身所带的执行体文件格式。在Windows操作系统下,所有的可执行文件都是PE文件格式。包括:EXE文件、DLL文件、SYS文件、OCX文件等。
所有的PE文件都按照PE文件结构的方式组织存在的。PE文件结构不是一个单纯的结构。一个PE文件由若干个结构集合而成,不同的结构有不同的用处。
PE文件格式是对Windows下可执行文件的一种管理方式。
即使windows运行在非Intel的CPU上,任何win32平台的PE装载器都能识别和使用该文件格式。
windows下每个进程都有独立的4G地址空间,低两G(0x00000000~0x7fffffff)给应用程序使用,高两G(0x80000000~0xFFFFFFFF)给系统内核使用。
PE文件中经常用到三种地址:
DOS头部在winnt.h头文件中的定义如下:(该文件头的大小为64个字节)
从内存中的字符串的位置找到文件中的字符串的位置
1.通过VA转换为RVA
403006-400000=3006
2.找RVA所在的节
3006在.data节
3.计算.data节起始RVA和起始FOA的差值
3000-800=2800(十六进制相减)
4.通过RVA减去差值
3006-2800=806
添加节的步骤:
构造PE头部,包括:
构造PE体,包括:
1.加壳:压缩壳、加密壳(隐藏程序的真正入口点)、虚拟机壳(VM关键代码,让破解者毫无头绪)
加壳的过程:
2.查壳:识别程序的签名(特征码)
3.脱壳:专门的脱壳工作、通用的脱壳工具、手动脱壳(找OEP、DUMP、修复导入表)
特征码通过提取指令的操作码(opcode)集合
1.text节。它的内容是指令代码,必须加密。
2.data节。data包括初始化的数据,比如编译时被初始化的global和static变量,和字符串。也可加密。
3.idata节。这个节是输入数据,包括输入目录和输入地址名字表(IAT{Import Address Table}和INT{Import Name Table})。idata包含其他外来DLL的函数及数据信息。
4.rsrc节。包括所有资源文件。
5.reloc节。reloc保存基地址重定位表(当文件刚开始装载入内存,若指定的内存装载地址已被其他进程占用,则需要此重定位表,来重定位重新装载进内存的地址,这个重定位表包含了调整所需的数据)。
6.edata节。该PE文件输出的函数和数据的表。
7.tls节。线程本地存储器。
8.rdata节。存放调试目录和说明字符串。
typedef struct _IMAGE_DOS_HEADER{
WORD e_magic;
/
/
0000h
EXE标志 MZ 下图中的
4D
5A
WORD e_cblp;
/
/
0002h
最后(部分)页中的字节数 下图中的
90
00
WORD e_cp;
/
/
0004h
文件中的全部和部分页数
03
00
WORD e_crlc;
/
/
0006h
重定位表中的指针数
00
00
WORD e_cparhdr;
/
/
0008h
头部尺寸,以段位为单位
04
00
WORD e_minalloc;
/
/
000Ah
所需的最小附加段
00
00
WORD e_maxalloc;
/
/
000Ch
所需的最大附加段 FF FF
WORD e_ss;
/
/
000Eh
初始的SS值(相对偏移量)
00
00
WORD e_sp;
/
/
0010h
初始的SP值 B8
00
WORD e_csum;
/
/
0012h
校验和
00
00
WORD e_ip;
/
/
0014h
初始的IP值
00
00
WORD e_cs;
/
/
0016h
初始的CS值
00
00
WORD e_lfarlc;
/
/
0018h
重定位表的字节偏移量
40
00
WORD e_ovno;
/
/
001Ah
覆盖号
00
00
WORD e_res[
4
];
/
/
001Ch
保留字
00
00
00
00
00
00
00
00
WORD e_oemid;
/
/
0024h
OEM标识符(相对e_oeminfo)
00
00
WORD e_oeminfo;
/
/
0026h
OEM信息
00
00
WORD e_res2[
10
];
/
/
0028h
保留字
00
00
00
00
...
00
LONG
e_lfanew;
/
/
003Ch
PE头相对于文件的偏移地址,也就是结构体IMAGE_NT_HEADERS的开头
08
01
00
00
}
typedef struct _IMAGE_DOS_HEADER{
WORD e_magic;
/
/
0000h
EXE标志 MZ 下图中的
4D
5A
WORD e_cblp;
/
/
0002h
最后(部分)页中的字节数 下图中的
90
00
WORD e_cp;
/
/
0004h
文件中的全部和部分页数
03
00
WORD e_crlc;
/
/
0006h
重定位表中的指针数
00
00
WORD e_cparhdr;
/
/
0008h
头部尺寸,以段位为单位
04
00
WORD e_minalloc;
/
/
000Ah
所需的最小附加段
00
00
WORD e_maxalloc;
/
/
000Ch
所需的最大附加段 FF FF
WORD e_ss;
/
/
000Eh
初始的SS值(相对偏移量)
00
00
WORD e_sp;
/
/
0010h
初始的SP值 B8
00
WORD e_csum;
/
/
0012h
校验和
00
00
WORD e_ip;
/
/
0014h
初始的IP值
00
00
WORD e_cs;
/
/
0016h
初始的CS值
00
00
WORD e_lfarlc;
/
/
0018h
重定位表的字节偏移量
40
00
WORD e_ovno;
/
/
001Ah
覆盖号
00
00
WORD e_res[
4
];
/
/
001Ch
保留字
00
00
00
00
00
00
00
00
WORD e_oemid;
/
/
0024h
OEM标识符(相对e_oeminfo)
00
00
WORD e_oeminfo;
/
/
0026h
OEM信息
00
00
WORD e_res2[
10
];
/
/
0028h
保留字
00
00
00
00
...
00
LONG
e_lfanew;
/
/
003Ch
PE头相对于文件的偏移地址,也就是结构体IMAGE_NT_HEADERS的开头
08
01
00
00
}
typedef struct _IMAGE_NT_HEADERS{
DWORD Signature;
/
/
PE标识符
50
45
00
00
IMAGE_FILE_HEADER FileHeader;
/
/
文件头
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
/
/
可选头
}IMAGE_NT_HEADERS32,
*
PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_FILE_HEADER{
/
/
该结构体可判断文件是EXE文件还是DLL文件。占用
20
个字节
WORD Machine;
/
/
0004h
运行平台
0x014c
指的是Intel
386
,而
0x0200
指的是Intel
64
WORD NumberOfSections;
/
/
0006h
PE中节的数量 最大
96
个节
DWORD TimeDateStamp;
/
/
0008h
文件创建日期和时间,编译器创建此文件时的时间戳
DWORD PointerToSymbolTable;
/
/
000Ch
指向符号表(用于调试)
DWORD NumberOfSymbols;
/
/
0010h
符号表中的符号数量(用于调试)
WORD SizeOfOptionalHeader;
/
/
0014h
可选头结构体的长度
32
位版本是E0
64
位版本的是F0
WORD Characteristics;
/
/
0016h
文件的属性 exe文件是
010f
dll文件是
210e
}IMAGE_FILE_HEADER,
*
PIMAGE_FILE_HEADER;
typedef struct _IMAGE_NT_HEADERS{
DWORD Signature;
/
/
PE标识符
50
45
00
00
IMAGE_FILE_HEADER FileHeader;
/
/
文件头
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
/
/
可选头
}IMAGE_NT_HEADERS32,
*
PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_FILE_HEADER{
/
/
该结构体可判断文件是EXE文件还是DLL文件。占用
20
个字节
WORD Machine;
/
/
0004h
运行平台
0x014c
指的是Intel
386
,而
0x0200
指的是Intel
64
WORD NumberOfSections;
/
/
0006h
PE中节的数量 最大
96
个节
DWORD TimeDateStamp;
/
/
0008h
文件创建日期和时间,编译器创建此文件时的时间戳
DWORD PointerToSymbolTable;
/
/
000Ch
指向符号表(用于调试)
DWORD NumberOfSymbols;
/
/
0010h
符号表中的符号数量(用于调试)
WORD SizeOfOptionalHeader;
/
/
0014h
可选头结构体的长度
32
位版本是E0
64
位版本的是F0
WORD Characteristics;
/
/
0016h
文件的属性 exe文件是
010f
dll文件是
210e
}IMAGE_FILE_HEADER,
*
PIMAGE_FILE_HEADER;
IMAGE_FILE_HEADER.Characteristics的常用属性
IMAGE_FILE_HEADER.Characteristics的常用属性
typedef struct _IMAGE_OPTIONAL_HEADER{
/
/
占用
224
个字节
WORD Magic;
/
/
0018h
取值为
10B
或
20B
BYTE MajorLinkerVersion;
/
/
001Ah
链接器版本号(对执行没有任何影响)
BYTE MinorLinkerVersion;
/
/
001Bh
DWORD SizeOfCode;
/
/
001Ch
所有含代码的节的大小(按照文件对齐,判断某节是否含代码,使用节属性IMAGE_SCN_CNT_CODE属性判断,而不是通过IMAGE_SCN_CNT_EXECUTE)
DWORD SizeOfInitializedData;
/
/
0020h
所有含初始化数据的节的大小
DWORD SizeOfUninitializedData;
/
/
0024h
所有含未初始化数据的节的大小(被定义为未初始化,不占用文件空间,加载入内存后为其分配空间)
DWORD AddressOfEntryPoint;
/
/
0028h
程序执行入口RVA(距离PE加载后地址的距离,对于病毒和加密程序,都会修改该值,从而获得程序的控制权,对于DLL,如果没有入口函数,那么是
0
,对于驱动,该值是初始化的函数的地址)
DWORD BaseOfCode;
/
/
002Ch
代码的节的起始RVA(一般情况跟在PE头部的后面)
DWORD BaseOfData;
/
/
0030h
数据的节的起始RVA
/
/
以上是standard,以下是additional
DWORD ImageBase;
/
/
0034h
程序的建议装载地址
DWORD SectionAlignment;
/
/
0038h
内存中的节的对齐值
32
位
0x1000
64
位
0x2000
DWORD FileAlignment;
/
/
003Ch
文件中的节的对齐值 现在都是
0x1000
早期都是
0x200
WORD MajorOperatingSystemVersion;
/
/
0040h
操作系统版本号
WORD MinorOperatingSystemVersion;
/
/
0042h
WORD MajorImageVersion;
/
/
0044h
该PE的版本号
WORD MinorImageVersion;
/
/
0046h
WORD MajorSubsystemVersion;
/
/
0048h
所需子系统的版本号
WORD MinorSubsystemVersion;
/
/
004Ah
DWORD Win32VersionValue;
/
/
004Ch
未使用,必须为
0
DWORD SizeOfImage;
/
/
0050h
内存中的整个PE文件映像大小(按照内存对齐)
DWORD SizeOfHeaders;
/
/
0054h
所有头
+
节表的大小
DWORD CheckSum;
/
/
0058h
校验和(一般EXE文件为
0
,而DLL和SYS文件则必须是正确的值)
WORD Subsystem;
/
/
005Ch
文件子系统
WORD DllCharacteristics;
/
/
005Eh
DLL文件特性
DWORD SizeOfStackReserve;
/
/
0060h
初始化时保留的栈的大小(默认
1M
)
DWORD SizeOfStackCommit;
/
/
0064h
初始化时实际提交的栈的大小(默认
4K
)
DWORD SizeOfHeapReserve;
/
/
0068h
初始化时保留的堆的大小(默认
1M
)
DWORD SizeOfHeapCommit;
/
/
006Ch
初始化时实际提交的堆大小(默认
4K
)
DWORD LoaderFlags;
/
/
0070h
加载标志一般为
0
DWORD NumberOfRvaAndSizes;
/
/
0074h
数据目录的数量
IMAGE_DATA_DIRECTORY DataDirectory{IMAGE_NUMBEROF_DIRECTORY_ENTRIES};
/
/
0078h
数据目录数组 导入表的定位由这个值给出
}
typedef struct _IMAGE_OPTIONAL_HEADER{
/
/
占用
224
个字节
WORD Magic;
/
/
0018h
取值为
10B
或
20B
BYTE MajorLinkerVersion;
/
/
001Ah
链接器版本号(对执行没有任何影响)
BYTE MinorLinkerVersion;
/
/
001Bh
DWORD SizeOfCode;
/
/
001Ch
所有含代码的节的大小(按照文件对齐,判断某节是否含代码,使用节属性IMAGE_SCN_CNT_CODE属性判断,而不是通过IMAGE_SCN_CNT_EXECUTE)
DWORD SizeOfInitializedData;
/
/
0020h
所有含初始化数据的节的大小
DWORD SizeOfUninitializedData;
/
/
0024h
所有含未初始化数据的节的大小(被定义为未初始化,不占用文件空间,加载入内存后为其分配空间)
DWORD AddressOfEntryPoint;
/
/
0028h
程序执行入口RVA(距离PE加载后地址的距离,对于病毒和加密程序,都会修改该值,从而获得程序的控制权,对于DLL,如果没有入口函数,那么是
0
,对于驱动,该值是初始化的函数的地址)
DWORD BaseOfCode;
/
/
002Ch
代码的节的起始RVA(一般情况跟在PE头部的后面)
DWORD BaseOfData;
/
/
0030h
数据的节的起始RVA
/
/
以上是standard,以下是additional
DWORD ImageBase;
/
/
0034h
程序的建议装载地址
DWORD SectionAlignment;
/
/
0038h
内存中的节的对齐值
32
位
0x1000
64
位
0x2000
DWORD FileAlignment;
/
/
003Ch
文件中的节的对齐值 现在都是
0x1000
早期都是
0x200
WORD MajorOperatingSystemVersion;
/
/
0040h
操作系统版本号
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)