PE结构&绑定导入实现

PE体系

PE结构&整体叙述

PE结构&导入表

PE结构&导出表

PE结构&基址重定位表

PE结构&绑定导入实现

PE结构&延迟加载导入表

简介

作用

绑定导入是一种提高PE加载速度的技术。它只能起辅助性作用,它的存在与否只影响加载过程,并不影响PE的最终加载结果和运行结果

为什么说是辅助性呢?
因为不同的操作系统中,动态链接库的基地址是不一样的。举个例子,kernel32.dll,在Windows 2000中其加载到进程空间的基地址为0x77e60000,而在Windows XP SP3中其加载地址则是0x7c800000。同一动态链接库加载后处于不同的基地址,直接导致了同一个导入函数在不同操作系统中其导入地址VA是不一样的。

因此经过绑定的PE程序可以能在Windows 2000里运行得很好,但是到了Windows XP SP3中却因地址出现错误而造成无法运行。

解决办法

在为PE加入绑定导入机制的时候,微软就已经考虑了这个问题,所以假定PE加载前对IAT的修正都是正确的。那么PE的加载速度是加快的,即使绑定以后的EXE程序在其他兼容系统中运行时,其地址出现错误,PE加载也有检测错误的基址。如果地址检测出错误,PE加载器会重新接管这项工作,加载时对IAT进行修正。

原因

双桥结构导入表中,桥2是指向IAT的,Windows加载程序负责IAT中地址的修正工作。如果导入函数比较多的话,那么就会占用比较长的时间,从而加载速度就会变慢。因此有了绑定导入,它的目的就是把Windows加载程序负责的IAT地址修正工作提到加载前进行,要么由用户手工完成,要么由专门的程序完成;然后再PE文件中声明导入数据,以便告诉操作系统加载器说这部分工作不需要你做了。

操作

微软提供了一个绑定工具bind.exe程序,它把导入表IAT表项IMAGE_THUNK_DATA32的内容都静态替换成虚拟内存地址(如下图)

在这里插入图片描述
在这里插入图片描述

,然后在数据目录表的第12项指定的位置声明这些更改。Windows在加载目标PE相关的动态链接库时,会检查这些地址时候合法(检查操作包括:当前的DLL版本是否符合绑定导入结构中描述的版本号,如果不符合或者DLL需要被重新定位加载器也就会去遍历INT(如下图),计算新的地址。)
在这里插入图片描述

这就是为什么双桥可以绑定, 单桥不能绑定了,因为单桥的话,进行遍历INT这里是无效的(没有桥1,只有桥2),所以单桥结构无法实施静态绑定

绑定导入数据定位

绑定导入数据结构

IMAGE_BOUND_IMPORT_DESCRIPTOR	STRUCT
	TimeDataStamp					dword		?	;	0000h	-时间戳
	OffserModuleName				word		?	;	0004h	-指向DLL名称
	NumberOfModuleForwarderRefs		word		?	;	0006h	-ModuleForwarderRef	数目
IMAGE_BOUND_IMPORT_DESCRIPTOR	ENDS

IMAGE_BOUND_IMPORT_DESCRIPTOR.TimeDataStamp

+0000h,双字。该字段的值必须要与要引用的DLL文件头IMAGE_FILE_HEADER.TimeDataStamp字段值相吻合,否则就会促使加载器去重新计算新IAT,这种情况一般发生在DLL版本不同时或者DLL映像被重定位时

IMAGE_BOUND_IMPORT_DESCRIPTOR.OffserModuleName

+0004h,单字。该字段包含了以第一个IMAGE_BOUND_INPORT_DESCRIPTOR作为基址,DLL名称字符串(ASCII且以“\0”结束)的偏移

注意:
该偏移地址是一个特殊的地址,它即不是RVA,也不是FOA

IMAGE_BOUND_IMPORT_DESCRIPTOR.NumberOfModuleForwarderRefs

+0006h,单字。该字段描述了紧接在IMAGE_BOUND_IMPORT_DESCRIPTOR结构后的另一个结构IMAGE_BOUND_FORWARDER_REF的定义:

IMAGE_BOUND_FORWARDER_REF STRUCT
	TimeDataStamp		dword		?; 0000h		-	时间戳
	OffsetModuleName	word		?; 0004h		-	指向DLL名称
	Reserved			word		?; 0006h		-	预留
IMAGE_BOUND_FORWARDER_REF ENDS

为什么会存在该结构呢?处于不同的目的(如代码更新,结构调整或实施补丁等),动态链接库中的某些函数的实现代码会被转移到别的动态链接库中。但为了提供向前的兼容,这些动态链接库中还保留该函数的定义。

换种说法,一个导入函数将涉及对多个动态链接库函数的调用,数据结构IMAGE_BOUND_FORWARDER_REF就是在这样一个背景下产生的,它将引入函数涉及的所有动态链接库都列举出来。

该结构的字段定义和IMAGE_BOUND_IMPORT_DESCRIPTOR是基本一致的,所以前面的描述“绑定导入数据由一系列的绑定导入描述符IMAGE_BOUND_IMPORT_DESCRIPTOR的结构组成”也是成立。

导入数据组织方式如下图:
在这里插入图片描述

实际操作

在这里插入图片描述

用的是dump后的文件:
在这里插入图片描述

注意:
系统文件的绑定导入表数据在文件中的存放位置:大部分情况下,该数据被存在PE文件头部,紧跟在节表后。

看一个特殊的具有IMAGE_BOUND_FORWARDER_REF的结构,如上图数据进行分析,分析结果如下:
IMAGE_BOUND_IMPORT_DESCRIPTOR。

C6	BD	02	48

绑定时操作系统中动态链接库kernel32.dll 的时间戳

A3	00

指向动态链接库名称字符串的偏移为0x00A3,注意该偏移是基于第一个IMAGE_BOUND_IMPORT_DESCRIPTOR结构的,即基于文件偏移地址0x00000250开始的偏移。

01	00

表示该动态链接库中的函数实现字节码存储在另一个动态链接库中

B0	00

指向动态链接库名称字符串的偏移

00	00

预留值,为0

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寻梦&之璐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值