PE文件导入表详解

文章目录


PE导入表

//下面用到的源程序代码
#include <iostream>
#include<windows.h>
#pragma comment(lib,"DllTest01.lib")
__declspec(dllimport) int Plus(int x, int y);//导出序号为3
__declspec(dllimport) int Sub(int x, int y);//导出序号为5
__declspec(dllimport) int Mul(int x, int y);//导出序号为7
__declspec(dllimport) int Div(int x, int y);//导出序号为9
int main()
{   
    std::cout << Plus(2, 2) <<std::endl;
    std::cout << Sub(2, 3) << std::endl;
    std::cout << Mul(2, 2) << std::endl;
    std::cout << Div(2, 2) << std::endl;
    return 0;
}

PE中数据目录项的第二个是指向导入表,我这里以之前讲导出表的文章中的例子为例(不清楚的可以看之前关于导出表的里面的例子),导入表的结构如下:

在这里插入图片描述导出表的结构类似于一个数组,每一个内容有5项(占20字节),最后以一个全零的结束,程序未运行的时候,在磁盘中存储的二进制形式中INT表和IAT表中的内容完全一样,这里INT与IAT表中每一项的结构如下:

union{
	DOWRD Ordinal;//当最高位为1时,选择这个
	DWORD AddressOfData;//当最高位不为1,选择这个
}

我们这个例子中,INT和IAT表中每一项最高位都为1,则表示除了最高位之外,其他位表示的就是函数导出序号,这里可以看出就是我们在dll生成的def文件中定义的函数导出序号。
然后程序运行起来后,我们在Ollydbg中找到INT表发现没有变化,而IAT表里面的内容已经发生变化,如下图(FirstTrunk为0x001B000,程序加载基址为0X00020000)
在这里插入图片描述
我们发现0x793E102D已经是属于DLL的领域空间,在0x793E102D处加一个内存访问断点,看到下面这句调用了 FF 15 0003B000 (即立即数调用形式),即先把下一个地址push后jmp到793E102D地址空间去执行代码(就是Mul函数定义处)
在这里插入图片描述
下面我们看看,这个793E102D是怎么来的呢?这就回归到关于导出表的内容了,因为DllTest01.dll的导出表中Mul函数的地址是0x0001102D,而DllTest01.dll在作为外部DLL被导入的加载基地址是0x793D0000,二者相加刚好是0x793E102D。

此时,我们大概清楚了PE中是如何利用导入表找到外部函数地址的了。
(1)编译的时候把程序中需要用到的外部函数的地址或序号用IAT和INT表存好
(2)程序加载的时候,去IAT表中找到那个函数的地址或序号,然后根据地址或序号去对应DLL的导出表中找函数地址,最后加上基地址形成函数的绝对地址放到IAT表中
(3)真正调用函数的时候,直接去IAT表中调用,就已经是外部调用函数的绝对地址了。

上面我介绍的是IAT和INT表中都是存放序号的情况,当最高位不为1的时候,里面存放的是地址值(指向的是函数序号+导出函数名的字段),如下图所示。
在这里插入图片描述
此外,还有一些小的细节:
(1)当INT和IAT表中存放的是导出函数序号时,序号值是原DLL中函数导出表AddressOfNameOrdinals字段对应表的值+base值。而当INT和IAT表中存放的地址时,指向的序号为AddressOfNameOrdinals字段对应表的值。

(2)对于DLL文件中采用NONAME注释的导出函数,在AddressOfNameOrdinals和AddressOfNames两个表中都没有其序号,但是程序却把其序号正确添加进来了,那么问题来了,NONAME导出函数的序号存放到了DLL文件的哪里呢?其实根本不用存,只要计算一下AddressOfFunction表中该导出函数所在行数+base值就是其导出序号啦。

(3)INT表和IAT表中到底存序号还是地址,即最高位为1还是不为1由什么决定?我感觉就是如果你的DLL是自定义的函数序号的,即有def文件中定义了序号的,按照序号导入,如果默认则按照地址导入,当然在链接的时候可能也有相关选项参数吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值