第一篇先写一个PE格式解析器,学了那么久了写出来防止自己忘记,顺便练练手。PE格式解析是比较基础的内容,后面再越写越深。我写这个不是介绍pe格式,而是说编写解析代码,解释定义什么的网上一堆就不粘了,重要的定义我尽量简洁的描述清楚就行,如果想知道每一个定义或者字段是用来干嘛的,在pecoff文档里写的很清楚。业余时间写的,时间不充裕写得很慢,写错请斧正,转载请注明,高手轻批。
解析前需要弄清楚的是RVA相对虚拟地址和RA相对地址,RVA是系统的loader加载到内存中用的,RA是解析文件用的。PE里存的偏移地址大部分都是RVA,因为它是要加载到内存中使用的,所以pe里存rva会快一些。
写解析代码的时候如果想让RVA和RA通用, 需要对载入的方式进行区分,因为后面文章会讲到修改PE内容往里面塞东西和其它一些什么的,所以为了方便我写成通用的。
用读文件或者用GetModuleHandle之类的函数载入,读文件方式解析时需要做rva2ra转换,GetModuleHandle载入的是运行中的进程,已经映射好了,就不用做转换了,把得到的地址作为基址,直接把它转成PCHAR就行。
几乎所有的定义都在winnt.h里,一般使用时只要导入这个就行,只有一些不太常用的定义在其它头文件里。
下面开始:
1、IMAGE_DOS_HEADER【Dos头】
这个段应该是历史遗留问题,需要到的只有e_magic和e_lfanew两个字段。e_magic直接判断等于IMAGE_DOS_SIGNATURE就行,一般pe是以0x4D5A开始的,看定义有其它的值,但是我没见过有其它值的pe。e_lfanew是用来跳过dos stub的,就是用21中断显示那一段英文的代码,删掉这段代码也没关系,以后再写。其它字段可以全部无视。
2、IMAGE_NT_HEADERS【Nt头】
通过base+dosHeader->e_lfanew偏移得到。这个结构分为32版本和64位版本,包含Signature(PE的为IMAGE_NT_SIGNATURE,就是PE\0\0)、FileHeader和OptionalHeader,其中只有OptionalHeader有32和64的区别,其它都是一样,解析到这里的时候需要注意区分是否为32或64位的pe,其信息记录在OptionalHeader字段中,字段中的Magic记录了该pe类型,因为Magic所在位置是一样的,所以可以用PIMAGE_NT_HEADERS32(base + DosHeader->e_lfanew)->OptionalHeader.Magic判断值,再确定使用IMAGE_NT_HEADERS32还是IMAGE_NT_HEADERS64来定这个结构的类型,声明的时候直接用union就行,直接以32位版本赋值后也不用改。
IMAGE_FILE_HEADER FileHeader相对有用的地方是NumberOfSections和SizeOfOptionalHeader。其它有用的信息都记录在OptionalHeader里。(叫做可选,实际上非常重要)
2.1、IMAGE_FILE_HEADER【文件头】
Machine记录机器类型,后面会用到。FileHeader里的NumberOfSections记录了PE节的数量,SizeOfOptionalHeader记录了可选头的大小,第一个节头是紧跟着可选头的&#x