• PE格式第四讲,数据目录表之导入表,以及IAT表


               PE格式第四讲,数据目录表之导入表,以及IAT表

    作者:IBinary
    出处:http://www.cnblogs.com/iBinary/
    版权所有,欢迎保留原文链接进行转载:)

    一丶IAT(地址表)

    首先我们思考一个问题,程序加载的时候会调用API,比如我们以前写的标准PE

    那么他到底是怎么去调用的?

    他会Call 下边的Jmp位置

    而Jmp位置则是对一个全局变量取内容.

    看下全局变量内容是什么.

    我们跟过去看下  75 98 FD AE

    可以看出,这个位置保存了一张表格,这张表格保存的是MessageBoxA的函数地址.

    那么我们想一下,在程序还没加载之前.这张表格是否存在,内容是否是这个.

    利用虚拟地址,转文件地址,定位 虚拟地址502008

    利用快捷方式转化

    FA = VA - 节区表首地址  + pointerToRawData的大小

    节区表在内存中查看

    得出节区表的首地址为502000  因为我们的虚拟地址大于502000,所以他属于是.rdata区.

    看下PE格式,文件中.radata的字段.

    得出400

    公式:

    FA = VA - 节区表首地址  + pointerToRawData的大小

     = 502008 - 502000 + 400

     = 8 + 400

    = 408 (文件偏移处)

    看下文件偏移处

    可以看出,205C是一个RVA偏移,转为FA跟随则是

    FA = 5c + 400 = 45c位置

    45C位置

    正好是MsgBosA的字符串

    这个IAT表格会跟你的函数个数,会预留很多个

    加载到内存的时候,则会写入到这里.

    我们改成FFFFF试试.

    发现还是可以正常运行的.

    而这个表格的存储方式则是

    /*
    
    IAT  [iat1......0   iat2........0]
    
    */

    其中是以0结尾的.

    二丶导入表

    了解什么是导入表

    上面我们说过,程序调用API,那么导入表就是保存这些API的信息

    首先我们猜测一下

    1.应该有函数名,因为根据函数名才可以在DLL中使用(当然也可以是序号,但是不兼容)

    2.猜测应该有DLL名称,要根据这个DLL才可以加载这个函数名

    3.猜测应该会有存放IAT表格的RVA地址, 加载DLL了,根据函数名获得了函数地址,程序启动之后就会往IAT表格中填写地址了.

    等等.

    看下结构体:

    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        union {
            DWORD   Characteristics;            
            DWORD   OriginalFirstThunk;  //指向上面的IAT,是一个结构数组,里面保存了导入函数的信息(例如Msg的实际地址)       
        };                   //最后会以全0的结构为结束,其中每一项是一个结构,一项8个字节,是指向
                           //IMAGE_THUNK_DATA 看下面详解
                            
    DWORD TimeDateStamp; //时间,一般不用
    DWORD ForwarderChain; //链表前一个结构,一般不用 DWORD Name;            //上面说的DLL名称的RVA偏移通过偏移可以找到DLL名称 DWORD FirstThunk; // IAT 的RVA偏移.和originalFirstThunk不同 } IMAGE_IMPORT_DESCRIPTOR;

    看图:

    按照第一个偏移结构体来算,那么

    双字最高位为0,表示导入符号是一个数值,是一个RVA数值(比如我们的Msg可以利用符号导入)

    双字最高位为1,那么表示导入的符号是一个名称(比如Msg的名字)

    我们查看下user32.dll,里面的导出函数是Msg,我们看下它的序号是什么.

    名字则直接是MessageBoxA了

    可以使用

    IAT结构数组结构表格

    typedef struct _IMAGE_THUNK_DATA32 {
        union {
            PBYTE  ForwarderString;
            PDWORD Function;
            DWORD Ordinal;
            PIMAGE_IMPORT_BY_NAME  AddressOfData;
        } u1;
    } IMAGE_THUNK_DATA32;

     表示IAT是按照什么加载的,序号加载,还是名称加载.

    三丶定位导入表

     在数据目录中,记录的是导入表的RVA偏移

    那么我们通过公式计算一下在文件中的偏移

    这里使用标准PE

    在数据目录中找到偏移为  2010  RVA = 2010 位置

    现在找模块地址

    模块地址在 选项头(或者叫做扩展头)的成员ImageBase中存储着 ,现在是00401000

    那么现在要找节表

    节表中记录了虚拟地址的RVA  也就是虚拟地址和模块首地址的RVA,我们则可以快速定位是哪个节表了.

    这个显然不是,1000的RVA,距离1000的位置,那么虚拟地址就是00401000  我们的虚拟地址是 00402010

    那么看下下边的节表

    402000位置,显然这个就是了

    那么根据快速转换公式得到

    VA = 402010

    FA = 402010 - 402000 + pointertoRawData(不截图了,是400)

    FA = 410 

    那么410位置就是导入表了.我们查看位置

    按照上面的结构体,我们可以知道DLL 的RVA地址,那么现在是

    206A  计算得出 FA = 6A + 400 = 46A,那么我们看看46A的位置是不是DLL名称

    ,一句IAT的RVA偏移地址,得出IAT表格位置

    现在是2008

    FA = 8+400 = 408

    那么408的位置就是IAT表格了

    可以看出,表格中前四个字节还记录了一个RVA偏移

    那么这个偏移代表的就是函数名字的位置

    FA = 5C+400 = 45C

    那么45C的位置记录就是函数名称了

    注意黄色方框的两个字节,这个字节就是上面说的 高低双字代表的意义

    如果高字为1,那么这个API地址则是函数名导入

    如果高字为0,那么就是序号导入

     作者:IBinary
    出处:http://www.cnblogs.com/iBinary/
    版权所有,欢迎保留原文链接进行转载:)

  • 相关阅读:
    Oracle 列顺序测试
    Java基于Servlet过虑器
    Java基于Servlet 验证吗
    WCF实例上下文
    WCF的行为与异常-------配置文件说明
    WCF异步
    WCF的通信
    分布式架构剖析
    [loj2542]「PKUWC2018」随机游走——min-max容斥+树上高消
    [bzoj4589]Hard Nim——SG函数+FWT
  • 原文地址:https://www.cnblogs.com/iBinary/p/7659132.html
Copyright © 2020-2023  润新知