PE解析器与加载器编写指南

PE解析器与加载器编写指南数组

  最近准备去实习,看公司要求应该开发PE相关的查杀引擎,所以再回头复习一下PE格式,从新写一个PE解析器和PE加载器,再此记录下有关坑。数据结构

PE解析器部分:函数

1)如何肯定节区表spa

  正确计算方法: pSection =  pNtHeader + sizeof(IMAGE_NT_HEADER) 。
设计

  错误计算方法:pSection = pFile + sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADER)。
3d

  缘由:DOS_HEADER后面还留有一段数据,并不紧跟着NT_HEADER,所以你这样计算是错误的!blog

    

2)RVA与FOA的转换内存

  咱们如今是PE解析,其都基于FOA,所以咱们如今只讲解RVA->FOA进行转换,在后面的PELoader这块,咱们再来分析FOA->RVA。开发

  其分析是基于节表的,循环遍历节表,判断其落在相关区间,而后在差值计算,获得对应的FOA,以下图:io

  

3)导入表的解析

  导入表是当DLL加载时,根据该PE文件的导入表对其进行修复操做,以后函数找到该函数就能够找到对应的函数地址。

  如今咱们来回顾一下导入表结构,其导入表结构以下:

  

   若是咱们要获取整张表的数据,咱们须要创建一个二维数组,对应着两行数据,所以咱们设计了以下数据结构:

  

  如今,随之而来的一个问题:如何肯定导入表的个数?PE文件的数据结构彷佛没有一个数据代表其个数。

  答案是其连续0为结束,所以咱们申请一块中间内存进行比较便可。(这种方式在PE文件解析中常常用到)。

  下面就是初始化导入表的代码,很好理解:

   

4)导出表的解析

  导出表主要是三张子表,函数名称表,函数序号表,函数地址表,这三张表用一张图就很好解决。

  

   所以咱们采用以下数据结构存储:

  

   解析代码:

  先遍历函数地址表,地址和序号初始化,名字先设置为NULL,以后咱们再遍历名称和序号表,根据序号将其赋值。

  

 5)重定位的解析

  重定位表构造相对简单,其sizeOfBlock是加上块头部8字节的大小,计算偏移是要注意不要再加多了。

  重定位元素也很简单,以WORD为单位,但要注意高4位为0x3才有效,修复重定位表时要检查该位是否有效。

  咱们开始是以下的数据结构:

  

   下面为重定位表的解析,其依然采用中间变量的方法:

  

 

PE加载器

  PE加载器,就是将一个PE文件映射到本身的内存,而后启动其main函数运行程序。

  一个PELoader的实现,须要有几个注意点:修复IAT表;修复重定位表;将内存属性写为可执行。

1)修复IAT表

  这里有两个函数 LoadLibrary 和 GetProcAddress,这两个函数能帮助咱们很好的找到目标函数,其代码以下:

  

2)修复重定位表

  

3)修改属性并执行Main函数

  咱们开始将文件映射时,其是只读属性,在修复以后若是执行Main函数会触发0xc0000005页权限访问异常。

  所以咱们须要经过以下代码将其置为可执行属性,固然这里存在瑕疵,可是咱们只是写个简单Demo,也没太多要求。

  

相关文章
相关标签/搜索