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

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

一丶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,那么就是序号导入

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏君赏技术博客

Jekyll-Admin-Mac-列表

接下来我们需要就是做出这个列表数据,我们可以使用 NSTableView来做出这个效果。

1601
来自专栏web前端教室

[每周日-先行者课堂笔记] -- react版的倒计时实现

image.png 各位同学们大家好,今天是4月9号周日,今天我们继续来做“倒计时”这个前端组件。之前我们是使用原生js来实现的,其实更多的只是实现了功能。 这...

3377
来自专栏chafezhou

程序员探案之被吃掉的串口数据

1844
来自专栏挖坑填坑

angular使用NG ZORRO来构建博客展示项目(简单实现展示页面)

这两个并没有设计成core模块的组件,但是也放在这里,不知道放在哪里合适。有的可以不用设计成angular模块或者组件,初学者真烦恼

2763
来自专栏前端达人

2018年最全面的前端面试题都在这里了

意义:根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析。 注意: 1.尽可能少的...

4.6K6
来自专栏salesforce零基础学习

salesforce lightning零基础学习(二) lightning 知识简单介绍----lightning事件驱动模型

看此篇博客前或者后,看一下trailhead可以加深印象以及理解的更好:https://trailhead.salesforce.com/modules/lex...

1420
来自专栏SHERlocked93的前端小站

Vue源码阅读 - 文件结构与运行机制

vue已是目前国内前端web端三分天下之一,同时也作为本人主要技术栈之一,在日常使用中知其然也好奇着所以然,另外最近的社区涌现了一大票vue源码阅读类的文章,在...

1243
来自专栏Android知识点总结

Android基于TCP的五子棋双人对战实现

1792
来自专栏葡萄城控件技术团队

Silverlight自定义数据绑定控件应该如何处理IEditableObject和IEditableCollectionView对象

最近在一直研究Silverlight下的数据绑定控件,发现有这样两个接口IEditableObject 和IEditableCollectionView,记录一...

1919
来自专栏云瓣

深入Redux架构

关于redux 之前写了一篇通过一个demo了解Redux,但对于redux的核心方法没有进行深入剖析,在此重新总结学习,完整的代码看这里。(参考了React ...

2856

扫码关注云+社区

领取腾讯云代金券