PE文件结构:学习概览
一、前言
PE是 Portable Executable 的缩写,Windows下所有可执行文件都是PE格式。
例如:exe、dll、sys...
PE格式是微软公司规定好的,大致可分为Header和Section两部分,
如下图:
注:画图工具为drwa.io
header用于管理pe文件,主要包含了PE文件各部分的属性、大小、起始位置等信息。
section部分是我们编写的代码实际存储的区域,但编译器会按照不同功能将代码分类存储在不同部分。
比如:数据可能存储在.data节,而函数则可能存储在.text节。
二、学习PE文件格式其实就是学习以下四点:
(一):数据结构映射
按照不同结构体和数组的定义对PE文件内部进行划分。
数据结构定义可以参见winnt.h文件,在其中搜索Image Format即可找到相关结构体。
(二):结构体解读:
理解不同结构体内部成员的不同含义
参看微软官方文档:
例如:NT头
(三):PE加载过程:
理解PE文件从硬盘加载到内存的过程:
硬盘文件->加载到内存(FileBuffer)->PE Loader加载并拉伸->ImageBuffer(起始位置ImageBase)
我们要明白PE文件在硬盘中和载入内存后大小可能是不一样的,
如下图:
注意:拉伸这块是一个学习难点。
(四):改动PE
改动PE可分为以下四类:
1.空白区添加代码
2.增加节
3.扩大节
4.合并节
目的都是为了把我们自己的代码添加进现有的pe文件中。
三、需要了解的PE结构体
struct _IMAGE_DOS_HEADER
struct _IMAGE_NT_HEADERS
struct _IMAGE_FILE_HEADER
struct _IMAGE_OPTIONAL_HEADER
struct _IMAGE_DATA_DIRECTORY
struct _IMAGE_SECTION_HEADER
FILE头和OPTIONAL头,这两个是初期学习的重点。
四、基础代码
除了要掌握c语言的基础语法,以及深刻理解c语言中的指针外,还要能理解下面代码中的8个c函数:
#define FilePath "C:\\Windows\\System32\\notepad.exe"
FILE* pFile = NULL;
char* buffer;
int nFileLength = 0;
pFile = fopen(FilePath, "rb"); //打开文件
fseek(pFile, 0, SEEK_END); //文件内部指针指向文件尾
nFileLength = ftell(pFile); //计算文件长度
rewind(pFile); //恢复文件内部指针
buffer = (char*)malloc(nFileLength); //分配内存
memset(buffer, 0, nFileLength); //将分配的内存中数据初始化为0
fread(buffer, 1, nFileLength, pFile); //将文件读入刚才申请的内存中
fclose(pFile); //关闭打开的文件
有了以上函数,再结合定义好的数据结构,我们就能尝试对pe文件进行加载与修改了。
五、更详细的PE文件结构图
六、参考资料
https://www.kanxue.com/chm.htm?id=16807&pid=node1001252
https://bbs.kanxue.com/thread-278377.htm