破解软件感悟-PE文件格式之Import Table(引入表)(四)

先来看一个可执行文件的实例:本例程打开一PE文件,将所有引入dll和对应的函数名读入一编辑控件,同时显示 IMAGE_IMPORT_DESCRIPTOR 结构各域值。

C:\QQDownload\blah.EXE

================[ IMAGE_IMPORT_DESCRIPTOR ]=============

OriginalFirstThunk  =  303C

TimeDateStamp  =  0

ForwarderChain = 0

Name = KERNEL32.dll

FirstThunk = 3064

Hint  Function

-----------------------------------------

0       CreateFileA

0       FreeLibrary

0       ExitProcess

0       LoadLibraryA

0       ReadFile

0       WriteFile

0       GetProcAddress

================[ IMAGE_IMPORT_DESCRIPTOR ]=============

OriginalFirstThunk  =  305C

TimeDateStamp  =  0

ForwarderChain = 0

Name = USER32.dll

FirstThunk = 3084

Hint  Function

-----------------------------------------

0           MessageBoxA

上面的数据我们如何得到的呢?

理论:

一.首先,您得了解什么是引入函数。一个引入函数是被某模块调用的但又不在调用者模块中的函数,因而命名为"import(引入)"。引入函数实际位于一个或者更多的DLL里。调用者模块里只保留一些函数信息,包括函数名及其驻留的DLL名。现在,我们怎样才能找到PE文件中保存的信息呢? 转到 data directory 寻求答案吧。再回顾一把,下面就是 PE header:

IMAGE_NT_HEADERS STRUCT
   Signature dd ?
   FileHeader IMAGE_FILE_HEADER <>
   OptionalHeader IMAGE_OPTIONAL_HEADER <>
IMAGE_NT_HEADERS ENDS

optional header 最后一个成员就是 data directory(数据目录):

IMAGE_OPTIONAL_HEADER32 STRUCT
   .... 
   LoaderFlags dd ? 
   NumberOfRvaAndSizes dd ? 
   DataDirectory IMAGE_DATA_DIRECTORY 16 dup(<>) 
IMAGE_OPTIONAL_HEADER32 ENDS

data directory 是一个 IMAGE_DATA_DIRECTORY 结构数组,共有16个成员。如果您还记得节表可以看作是PE文件各节的根目录的话,也可以认为 data directory 是存储在这些节里的逻辑元素的根目录。明确点,data directory 包含了PE文件中各重要数据结构的位置和尺寸信息。每个成员包含了一个重要数据结构的信息。


Member


Info inside


0


Export symbols


1


Import symbols


2


Resources


3


Exception


4


Security


5


Base relocation


6


Debug


7


Copyright string


8


Unknown


9


Thread local storage (TLS)


10


Load configuration


11


Bound Import


12


Import Address Table


13


Delay Import


14


COM descriptor

上面那些金色显示的是我熟悉的。了解 data directory 包含域后,我们可以仔细研究它们了。data directory 的每个成员都是 IMAGE_DATA_DIRECTORY 结构类型的,其定义如下所示:

IMAGE_DATA_DIRECTORY STRUCT 
  VirtualAddress dd ? 
  isize dd ? 
IMAGE_DATA_DIRECTORY ENDS

VirtualAddress 实际上是数据结构的相对虚拟地址(RVA)。比如,如果该结构是关于import symbols的,该域就包含指向IMAGE_IMPORT_DESCRIPTOR 数组的RVA。 
isize 含有VirtualAddress所指向数据结构的字节数。

下面就是如何找寻PE文件中重要数据结构的一般方法:

1.      从 DOS header 定位到 PE header

2.      从 optional header 读取 data directory 的地址。

3.      IMAGE_DATA_DIRECTORY 结构尺寸乘上找寻结构的索引号: 比如您要找寻import symbols的位置信息,必须用IMAGE_DATA_DIRECTORY 结构尺寸(8 bytes)乘上1(import symbols在data directory中的索引号)。

4.      将上面的结果加上data directory地址,我们就得到包含所查询数据结构信息的 IMAGE_DATA_DIRECTORY 结构项。

小段总结:以上说明data directory是一个结构数组,这里面包含16个结构成员,每一个结构成员是IMAGE_DATA_DIRECTORY 结构类型,而这种结构类型包含VirtualAddress dd ? 
  isize dd ?

 

二.现在我们开始真正讨论引入表了。


1


Import symbols

从上面已经分析过了,这是一个IMAGE_DATA_DIRECTORY 结构类型,这个结构类型中包含VirtualAddress,这个里面放的是引入表地址

什么是引入表呢?

引入表实际上是一个 IMAGE_IMPORT_DESCRIPTOR 结构数组。如下:

IMAGE_IMPORT_DESCRIPTOR STRUCT 
  union 
    Characteristics dd ? 
    OriginalFirstThunk dd ? 
  ends 
  TimeDateStamp dd ? 
  ForwarderChain dd ? 
  Name1 dd ? 
  FirstThunk dd ? 
IMAGE_IMPORT_DESCRIPTOR ENDS

结构第一项是一个union子结构。 事实上,这个union子结构只是给 OriginalFirstThunk 增添了个别名,您也可以称其为"Characteristics"。 该成员项含有指向一个 IMAGE_THUNK_DATA 结构数组的RVA。

什么是 IMAGE_THUNK_DATA? 这是一个dword类型的集合。通常我们将其解释为指向一个 IMAGE_IMPORT_BY_NAME 结构的指针。注意 IMAGE_THUNK_DATA 包含了指向一个IMAGE_IMPORT_BY_NAME 结构的指针: 而不是结构本身。

我们用通俗的语言表示就是:

现有几个 IMAGE_IMPORT_BY_NAME 结构,我们收集起这些结构的RVA (IMAGE_THUNK_DATA)组成一个数组,并以0结尾,然后再将数组的RVA放入 OriginalFirstThunk

此 IMAGE_IMPORT_BY_NAME 结构存有一个引入函数的相关信息。再来研究 IMAGE_IMPORT_BY_NAME 结构到底是什么样子的呢:

IMAGE_IMPORT_BY_NAME STRUCT 
  Hint dw ? 
  Name1 db ? 
IMAGE_IMPORT_BY_NAME ENDS

Hint 指示本函数在其所驻留DLL的引出表中的索引号。该域被PE装载器用来在DLL的引出表里快速查询函数。该值不是必须的,一些连接器将此值设为0。
Name1 含有引入函数的函数名。函数名是一个ASCIIZ字符串。注意这里虽然将Name1的大小定义成字节,其实它是可变尺寸域,只不过我们没有更好方法来表示结构中的可变尺寸域。The structure is provided so that you can refer to the data structure with descriptive names.

小段总结: 可以这样理解上面这段话:

OriginalFirstThunk中的每个成员项实际上是一个指向IMAGE_THUNK_DATA结构数组中的每个成员

IMAGE_THUNK_DATA结构数组中存放的是指向IMAGE_IMPORT_BY_NAME 结构数组的指针

IMAGE_IMPORT_BY_NAME结构数组存放的是每个函数的RAV

三.好了,如果您还在犯糊涂,就朝这边看过来: 现在有几个 IMAGE_IMPORT_BY_NAME 结构,同时您又创建了两个结构数组,并同样寸入指向那些 IMAGE_IMPORT_BY_NAME 结构的RVAs,这样两个数组就包含相同数值了(可谓相当精确的复制啊)。 最后您决定将第一个数组的RVA赋给 OriginalFirstThunk第二个数组的RVA赋给 FirstThunk,这样一切都很清楚了。


OriginalFirstThunk


 


IMAGE_IMPORT_BY_NAME


 


FirstThunk


|


 


 


 


|


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


...


IMAGE_THUNK_DATA


--->


--->


--->


--->


--->


--->


Function 1


Function 2


Function 3


Function 4


...


Function n


<---


<---


<---


<---


<---


<---


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


...


IMAGE_THUNK_DATA

现在您应该明白我的意思。不要被IMAGE_THUNK_DATA这个名字弄糊涂: 它仅是指向 IMAGE_IMPORT_BY_NAME 结构的RVA。 如果将 IMAGE_THUNK_DATA 字眼想象成RVA,就更容易明白了。OriginalFirstThunk 和 FirstThunk 所指向的这两个数组大小取决于PE文件从DLL中引入函数的数目。比如,如果PE文件从kernel32.dll中引入10个函数,那么IMAGE_IMPORT_DESCRIPTOR 结构的 Name1域包含指向字符串"kernel32.dll"的RVA,同时每个IMAGE_THUNK_DATA 数组有10个元素。

下一个问题是: 为什么我们需要两个完全相同的数组? 为了回答该问题,我们需要了解当PE文件被装载到内存时,PE装载器将查找IMAGE_THUNK_DATA 和 IMAGE_IMPORT_BY_NAME 这些结构数组,以此决定引入函数的地址。然后用引入函数真实地址来替代由FirstThunk指向的 IMAGE_THUNK_DATA 数组里的元素值。因此当PE文件准备执行时,上图已转换成:


OriginalFirstThunk


 


IMAGE_IMPORT_BY_NAME


 


FirstThunk


|


 


 


 


|


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


IMAGE_THUNK_DATA


...


IMAGE_THUNK_DATA


--->


--->


--->


--->


--->


--->


Function 1


Function 2


Function 3


Function 4


...


Function n


 


 


 


 


 


Address of Function 1


Address of Function 2


Address of Function 3


Address of Function 4


...


Address of Function n

OriginalFirstThunk 指向的RVA数组始终不会改变,所以若还反过头来查找引入函数名,PE装载器还能找寻到。
当然再简单的事物都有其复杂的一面。有些情况下一些函数仅由序数引出,也就是说您不能用函数名来调用它们: 您只能用它们的位置来调用。此时,调用者模块中就不存在该函数的IMAGE_IMPORT_BY_NAME 结构。不同的,对应该函数的 IMAGE_THUNK_DATA 值的低位字指示函数序数,而最高二进位 (MSB)设为1。例如,如果一个函数只由序数引出且其序数是1234h,那么对应该函数的 IMAGE_THUNK_DATA 值是80001234h。Microsoft提供了一个方便的常量来测试dword值的MSB位,就是 IMAGE_ORDINAL_FLAG32,其值为80000000h。
假设我们要列出某个PE文件的所有引入函数,可以照着下面步骤走:

  1. 校验文件是否是有效的PE。
  2. 从 DOS header 定位到 PE header。
  3. 获取位于 OptionalHeader 数据目录地址。
  4. 转至数据目录的第二个成员提取其VirtualAddress值。
  5. 利用上值定位第一个 IMAGE_IMPORT_DESCRIPTOR 结构。
  6. 检查 OriginalFirstThunk值。若不为0,顺着 OriginalFirstThunk 里的RVA值转入那个RVA数组。若 OriginalFirstThunk 为0,就改用FirstThunk值。有些连接器生成PE文件时会置OriginalFirstThunk值为0,这应该算是个bug。不过为了安全起见,我们还是检查 OriginalFirstThunk值先。
  7. 对于每个数组元素,我们比对元素值是否等于IMAGE_ORDINAL_FLAG32如果该元素值的最高二进位为1, 那么函数是由序数引入的,可以从该值的低字节提取序数。
  8. 如果元素值的最高二进位为0,就可将该值作为RVA转入 IMAGE_IMPORT_BY_NAME 数组,跳过 Hint 就是函数名字了。
  9. 再跳至下一个数组元素提取函数名一直到数组底部(它以null结尾)。现在我们已遍历完一个DLL的引入函数,接下去处理下一个DLL。
  10. 即跳转到下一个 IMAGE_IMPORT_DESCRIPTOR 并处理之,如此这般循环直到数组见底。(IMAGE_IMPORT_DESCRIPTOR 数组以一个全0域元素结尾)。
时间: 2024-08-10 13:08:02

破解软件感悟-PE文件格式之Import Table(引入表)(四)的相关文章

破解软件感悟-PE文件格式之实例总结(五)

有很多介绍PE文件的文章,但是我打算写一篇关于输入表的文章,因为它对于破解很有用.     我想解释它的最好的方法是举一个例子,你可以跟着我逐步深入,一步一步的思考,最后你将完全明白,我选择了一个我刚下载下来的小程序,它是用TASM编译的,有一个比较小的输入表,所以我想它应该是个不错的范例.     好了,让我们开始吧.首先我们得找到输入表,它的地址放在PE文件头偏移80处,所以我们用16进制编辑器打开我们的EXE文件,我们先得找到PE文件头的起始点,这很简单,因为它总是以PE,0,0开始,我们

PE文件格式分析

第一阶段:PE文件格式分析 使用UltraEdit观察PE文件例子程序hello-2.5.exe的16进制数据,在打印稿中画出该PE文件基本结构. 使用Ollydbg对该程序进行初步调试,了解该程序功能结构,在内存中观察该程序的完整结构. 熟悉各类PE文件格式查看和编辑工具(PEView.Stud_PE等). 使用UltraEdit修改该程序,使得该程序仅弹出第二个对话框. 第二阶段:熟悉并分析PE文件的引出表 找到系统System32目录下的user32.dll文件,用UltraEdit打开并

C++PE文件格式解析类(轻松制作自己的PE文件解析器)

PE是Portable Executable File Format(可移植的运行体)简写,它是眼下Windows平台上的主流可运行文件格式. PE文件里包括的内容非常多,详细我就不在这解释了,有兴趣的能够參看之后列出的參考资料及其它相关内容. 近期我也在学习PE文件格式,參考了很多资料.用C++封装了一个高效方便的PE文件格式解析的类. 该类对想学PE文件结构的朋友可算一份可贵的资料.代码均非常易懂,考虑较全面,具有一定的通用性. 同一时候该类也能够让想创建自己的PE文件解析软件的朋能够轻松在

PE文件格式详解(六)

0x00 前言 前面两篇讲到了输出表的内容以及涉及如何在hexWorkShop中找到输出表及输入DLL,感觉有几个地方还是没有理解好,比如由数据目录表DataDirectory[16]找到输出表表后以为找到输入DLL就完了,其实这一流程的最终功能是通过输入DLL找到输入DLL调用的函数,这一步骤是通过输出表结构中的OriginalFristThunk或者OriginalFristThunk所指向的INT或者IAT结构来找到的.这里要说明的是,虽然一般情况通过OriginalFristThunk也

QQ空间一键删除留言破解软件

该破解软件批量删除空间说说.日志.留言.相册.分享.访客.微博等 由于腾讯限制,软件一天只能删除一两百条 ,无需告诉别人密码 ,自己即可删除,保护自己空间隐私不外泄.软件破解图如下: 破解版软件下载地址: 下载地址1  下载地址2   下载地址3

破解软件下载站点

对于有些人对某些软件要购买序列号很苦恼,今天我为大家推荐一些站点,能提供某些破解软件 一:3DMgame(是国内著名的游戏破解站) 许多游戏发布不久之后就被破解了,在这个地方都可以找到,相信一些游戏的爱好者一定会喜欢上这里. 二:大眼仔 这里许多的软件都是由站长亲自破解,相信大伙访问这里一定会爱上这里,爱整软件的就转移到这里来吧1 三:轻志狂 这里的软件方向主要是净化和优化了的 四:吾爱破解 是国内最大的破解论坛,破解方向很广泛.

带你认识Office密码破解软件的攻击先锋

如果将Advanced Office Password Recovery破解Office文档密码形容成一场战争,那AOPR的初步攻击一定是这场战争的先锋官.初步攻击是AOPR尝试破解密码的第一个攻击,一般就会首战告捷.本文将带你了解并掌握Office密码破解软件的初步攻击的使用方法. AOPR攻击先锋是如何工作的 初步攻击是一组事先定义好的攻击,它一般在AOPR不能立刻恢复密码的时候开始尝试破解密码.初步攻击一般有4个攻击步骤,依次是查找密码攻击.密码缓存预破解.初步字典破解.初步暴力破解.在A

带你认识Office密码破解软件的加速器

Advanced Office Password Recovery能够在同类软件中脱颖而出的重要原因之一就是极快的破解速度,而这一优势依托于Office密码破解软件的加速器,本文将主要介绍AOPR的加速器. Office文档密码难以破解的原因 从Office 2007开始,微软不断升级密码保护强度,连不常用的OpenDocument和韩文Office密码都十分牢固.在最新版Office 2013中微软又进一步提高保护实力,并且在Office 2013中使用的都是计算密集型加密方式.因此Offic

压缩文件及office密码破解软件 详记

今日因为公司的office文件被加密(而且是没意义的加密)问题而有心去找一款可以破解office加密的软件.  好吧.之前有更加大的事情我都没去寻找直接给了20块别人让别人给我破了.虽然还是某公司机密文件.唉.服了自己了. 先记一下官网: office破解的官网:http://www.passwordrecovery.cn/xiazai.html rar破解的官网:https://www.elcomsoft.com/archpr.html(不知道是不是) 先说一下rar的压缩破解软件, 忘记在哪