- :每个CPU都有一个唯一的Machine码,兼容32位Intel x86芯片的machine码是14c。其它Machine码可在winnt.h中查看。
-
指示文件中存在的节区数量, 此值是一定要大于0,且当定义的节区数与实际的节区数不一样时,将发生运行错误。
- :标识第三个成员变量的大小。
- :标识文件属性,是否是dll,是否可执行等信息。
如下图便是,
根据图片所示,我们可以得出各值:
0x02.2.2 IMAGE_OPTIONAL_HEADER
扩展PE头在32位和64位系统上大小是不同的,在32位系统上有224个字节,16进制就是0xE0,与上面的SizeOfOptionalHeader也能对上。
是PE头结构体最大的一个,先看定义:
部分成员变量说明:
- :指出文件被加载到内存应该被优先加载的内存地址,exe,dll文件被装载到用户内存的中,sys文件被载入内存的中,一般情况下,exe会被装载到,dll文件的值为
- : 用来指定数组的个数,在winnt.h中被明确定义为16,但PE loader一般会通过此值来识别的大小,也就是说的长度不一定都是16。
- 是由结构体数据组成的,数组中的每一项都有定义,详细如下:

但我们一般只需要关心几个常见的即可,导出表、导入表、资源表、TLS表。详细的我们放到后面再讲。

根据图片例子,我们把常见的成员变量值列举出来如下:
还需要知道的是,程序的真正入口点 = ImageBase + AddressOfEntryPoint。
节区头由IMAGE_SECTION_HEADER定义,节区头的结构如下。
- :非必须以NULL结束,也未限制只能使用ASCII,可放入任何值
- 内存中节区所占大小
- 内存中节区起始地址(RVA)
-
磁盘文件中节区所占大小
- :磁盘文件中节区起始位置
- :节区属性。

如图所示,可知有四个节区,外加一个全为0的节区。
先看如何定位导入表起始地址,在头中的最后一个成员变量,我们有提到其是一个包含16个元素的数组,其中第2个元素就是导入表的起始位置。
先看的定义
即我们可以通过访问到导入表的起始地址。
再来看一下定义导入表的结构体:
一个程序导入了多少个库就有多少个结构体,这些结构体组成一个数组,且结构体数组以一个全为NULL的结构体作为结束。所以被称为.其中比较重要的成员变量如下(以下地址值全为RVA)
- :指向INT(导入名称表 、Improt Name Table)的地址,以全NULL结束。
- :库名称字符串的地址
-
指向IAT(导入地址表、Import Address Table)的地址,以全NULL结束。
的值为 即RVA=F5A9C, 换算成RAW则为F4A9C(换算方法见附)。

OriginalFirstThunk - INT (Import Name Table)
第一个成员变量为,它是INT的起始地址,换句话说,就是INT是一个包含导入函数信息的结构体指针数组,每个数组的元素都指向一个的结构体,并以全为NULL的元素结束。根据上图我们知道第一个元素的值为F6284(RVA)->换成RAW则为F5284。来到F5284这个地址.如下。由图可知INT数组长度为5。(以就代表着从这个库文件里面导入了5个函数)


要看懂这个结构得先看下的定义
前两个字节是库中函数的固有编号,后面的则是一个字符数组,以00结束。所以这个导入的函数则是.
Name
根据的结构可知,第四个成员则为,其值为F666A,换成RAW为F566A,我们转到这个地址看下,可知其导入的是SHLWAPI.dll


FirstThunk- IAT (Import Address Table)
由结构体可知其最后一个成员为。根据上面的图可知,第一数组元素的值为C55F4, RAW为:C45F4。我们来到这个地址处:


既然指向同一个地址,为啥需要两个去索引,这是因为需要区分PE加载前还是加载后。如果是加载前,那个IAT跟INT一样,都可以找到依赖的函数名称,如果是加载后。也就是在内存中的话, 那么IAT表保存的就是函数的地址。
PELoader把导入函数输入至IAT的步骤
- 读取IID的Name成员,获取库名称字符串(eg:kernel32.dll)
- 装载相应库: LoadLibrary(“kernel32.dll”)
- 读取IID的OriginalFirstThunk成员,获取INT地址
- 逐一读取INT中数组的值,获取相应IMAGE_IMPORT_BY_NAME地址(RVA)
- 使用IMAGE_IMPORT_BY_NAME的Hint(ordinal)或Name项,获取相应函数的起始地址:GetProcAddress(“GetCurrentThreadld”)
- 读取IID的FirstThunk(IAT)成员,获得IAT地址
- 将上面获得的函数地址输入相应IAT数组值
- 重复以上步骤4~7,知道INT结束(遇到NULL)
函数查找过程 - GetProAddress工作原理
- 利用AddressOfNames成员转到“函数名称数组”
- “函数名称数组”中存储字符串地址。通过比较字符串,查找指定的函数名称(此时数组的索引称为name_index)
- 利用AddressOfNameOrdinals成员,转到orinal数组
- 在orinal数组中通过name_index查找相应的值
- 利用AddressOfFunction成员转到“函数地址数组”
- 在“函数地址数组”中将刚刚求得的ordinal用作数组索引,获得指定的函数起始地址。
有了导入表的基础,则理解导出表就很简单了,这里就不再举例了。
转换方法如下:
1).查找RVA所在节区
2).使用如下公司计算。
pem文件是什么意思(pe是什么文件夹)
pem文件是什么意思(pe是什么文件夹)每个 CPU 都有一个唯一的 Machine 码 兼容 32 位 Intel x86 芯片的 machine 码是 14c 其它 Machine 码可在 winnt h 中查看 指示文件中存在的节区数量 此值是一定要大于 0 且当定义的节区数与实际的节区数不一样时 将发生运行错误 标识第三个成员变量的大小 标识文件属性 是否是 dll 是否可执行等信息 如下图便是 根据图片所示 我们可以得出各值 0x02 2
大家好,我是讯享网,很高兴认识大家。
数据库课程(数据库课程设计实例100例)
上一篇
2025-05-25 09:30
Py文件是什么软件写的(pyc文件是什么)
下一篇
2025-05-28 16:11













版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/187277.html