Import Table (引入表)
本课我们将学习引入表。先警告一下,对于不熟悉引入表的读者来说,这是一堂又长又难的课,所以需要多读几遍,最好再打开调试器来好好分析相关结构。各位,努力啊!
理论 :
首先,您得了解什么是引入函数。一个引入函数是被某模块调用的但又不在调用者模块中的函数,因而命名为 "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 (数据目录) :
MAGE_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 文件中各重要数据结构的位置和尺寸信息。 每个成员包含了一个重要数据结构的信息。
上面那些金色显示的是我熟悉的。了解 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 文件中重要数据结构的一般方法 :
从 DOS header 定位到 PE header 从 optional header 读取 data directory 的地址。 IMAGE_DATA_DIRECTORY 结构尺寸乘上找寻结构的索引号 : 比如您要找寻 import symbols 的位置信息,必须用 IMAGE_DATA_DIRECTORY 结构尺寸 (8 bytes) 乘上 1 ( import symbols 在 data directory 中的索引号)。 将上面的结果加上 data directory 地址,我们就得到包含所查询数据结构信息的 IMAGE_DATA_DIRECTORY 结构项。
现在我们开始真正讨论引入表了。 data directory 数组第二项的 VirtualAddress 包含引入表地址。引入表实际上是一个 IMAGE_IMPORT_DESCRIPTOR 结构数组。每个结构包含 PE 文件引入函数的一个相关 DLL 的信息。比如,如果该 PE 文件从 10 个不同的 DLL 中引入函数,那么这个数组就有 10 个成员。该数组以一个全 0 的成员结尾。下面详细研究结构组成 :
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_DATAs ) 组成一个数组,并以 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.
TimeDateStamp 和 ForwarderChain 可是高级东东 : 让我们精通其他成员后再来讨论它们吧。
Name1 含有指向 DLL 名字的 RVA ,即指向 DLL 名字的指针,也是一个 ASCIIZ 字符串。
FirstThunk 与 OriginalFirstThunk 非常相似,它也包含指向一个 IMAGE_THUNK_DATA 结构数组的 RVA( 当然这是另外一个 IMAGE_THUNK_DATA 结构数组 ) 。
好了,如果您还在犯糊涂,就朝这边看过来 : 现在有几个 IMAGE_IMPORT_BY_NAME 结构,同时您又创建了两个结构数组,并同样寸入指向那些 IMAGE_IMPORT_BY_NAME 结构的 RVAs ,这样两个数组就包含相同数值了 ( 可谓相当精确的复制啊 ) 。 最后您决定将第一个数组的 RVA 赋给 OriginalFirstThunk , 第二个数组的 RVA 赋给 FirstThunk ,这样一切都很清楚了。
现在您应该明白我的意思。不要被 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 指向的 RVA 数组始终不会改变,所以若还反过头来查找引入函数名, PE 装载器还能找寻到。
当然再简单的事物都有其复杂的一面。 有些情况下一些函数仅由序数引出,也就是说您不能用函数名来调用它们 : 您只能用它们的位置来调用。此时,调用者模块中就不存在该函数的 IMAGE_IMPORT_BY_NAME 结构。不同的,对应该函数的 IMAGE_THUNK_DATA 值的低位字指示函数序数,而最高二进位 (MSB) 设为 1 。例如,如果一个函数只由序数引出且其序数是 1234h ,那么对应该函数的 IMAGE_THUNK_DATA 值是 80001234h 。 Microsoft 提供了一个方便的常量来测试 dword 值的 MSB 位,就是 IMAGE_ORDINAL_FLAG32 ,其值为 80000000h 。
假设我们要列出某个 PE 文件的所有引入函数,可以照着下面步骤走 :
校验文件是否是有效的 PE 。 从 DOS header 定位到 PE header 。 获取位于 OptionalHeader 数据目录地址。 转至数据目录的第二个成员提取其 VirtualAddress 值。 利用上值定位第一个 IMAGE_IMPORT_DESCRIPTOR 结构。 检查 OriginalFirstThunk 值。若不为 0 ,顺着 OriginalFirstThunk 里的 RVA 值转入那个 RVA 数组。若 OriginalFirstThunk 为 0 ,就改用 FirstThunk 值。有些连接器生成 PE 文件时会置 OriginalFirstThunk 值为 0 ,这应该算是个 bug 。不过为了安全起见,我们还是检查 OriginalFirstThunk 值先。 对于每个数组元素,我们比对元素值是否等于 IMAGE_ORDINAL_FLAG32 。 如果该元素值的最高二进位为 1 , 那么函数是由序数引入的,可以从该值的低字节提取序数。 如果元素值的最高二进位为 0 ,就可将该值作为 RVA 转入 IMAGE_IMPORT_BY_NAME 数组,跳过 Hint 就是函数名字了。 再跳至下一个数组元素提取函数名一直到数组底部 ( 它以 null 结尾 ) 。现在我们已遍历完一个 DLL 的引入函数,接下去处理下一个 DLL 。 即跳转到下一个 IMAGE_IMPORT_DESCRIPTOR 并处理之,如此这般循环直到数组见底。 ( IMAGE_IMPORT_DESCRIPTOR 数组以一个全 0 域元素结尾 )
发表评论
-
压缩与脱壳-PE文件格式 七
2009-04-13 11:44 694Export Table(引出表) 上一课我们已经学习了 ... -
压缩与脱壳-PE文件格式 六 续
2009-04-13 11:39 1077assume edi:ptr IMAGE_IMPORT_D ... -
压缩与脱壳-PE文件格式 六 续一
2009-04-13 11:33 976示例 : 本例程打开一 PE 文件,将所有引入函数名读入一 ... -
压缩与脱壳-PE文件格式 五
2009-04-13 11:09 922Section Table(节表) 理论 : 到本课为止, ... -
压缩与脱壳-PE文件格式 四
2009-04-13 11:05 1081Optional Header 我们已经学习了关于 DOS ... -
压缩与脱壳-PE文件格式 三
2009-04-13 11:03 913File Header (文件头) ... -
压缩与脱壳-PE文件格式 二
2009-04-13 10:55 978检验PE文件的有效性 理 ... -
压缩与脱壳-PE文件格式 一
2009-04-13 10:48 1233PE 文件格式一览 PE 的 ... -
脱壳基础知识入门之认识壳
2009-04-13 10:35 10801.什么是壳 在一些计算 ...
相关推荐
### PE文件中脱壳技术的研究 #### 摘要与背景 随着信息技术的快速发展,软件保护成为了一个重要的议题。为了防止软件被非法复制或者逆向工程,开发人员常常采用一种称为“加壳”的技术来保护自己的软件产品。然而...
都会使计算机产生安全隐患或者使软件的核心技术被窃取,所以保护PE文件不被修改是一件很重要的工作,当前通常采用加壳的方法对PE文件进行保护,这其中UPX是具有代表性的压缩类外壳。 本文首先对PE文件格式进行了全面...
UPX是一个着名的压缩壳,主要功能是压缩PE文件(比如exe,dll等文件),有时候也可能被病毒用于免杀。壳upx是一种保护程序。 ........................ UPX是大家熟悉的EXE/Dll资源压缩工具,也称作可执行文件压缩...
PE文件格式是Windows操作系统中用于执行程序的标准格式,包括可执行文件(.exe)、动态链接库(.dll)等。PE脱壳工具能够识别并处理这些文件中的各种壳技术,例如UPX、ASPack、PECompact等。这些壳通常用于压缩程序...
UPX(UPX UnPacker eXtended)是一款广泛使用的可执行文件压缩工具,它能够将PE(Portable Executable,Windows平台上的可执行文件格式)文件进行压缩,从而减小程序的体积,提高分发效率。然而,这也为逆向工程和...
在计算机安全领域,PECompact是一款知名的可执行文件打包和压缩工具,它能够将Windows下的PE(Portable Executable)格式文件进行压缩,从而减小文件体积,提高分发效率。然而,这样的压缩过程也使得一些恶意软件...
总结以上内容,脱壳是逆向工程的重要组成部分,需要掌握PE文件格式、SEH机制、调试工具的使用,以及对各种加密算法和保护技术的理解。只有对这些基础知识和高级技术有了充分的认识,才能在软件安全和逆向工程的道路...
Aspack stripper就是这样的一个工具,它的主要功能是对使用ASPack 2.12版本压缩的可执行文件进行自动脱壳。这个工具的存在,使得安全分析人员能够揭示被压缩和混淆的原始代码,从而更好地理解软件的工作原理,检查...
2. **脱壳机制**:脱壳工具的核心在于正确地解压UPX壳并恢复原始的未压缩PE文件。源码可能会包含解压算法,根据UPX的压缩格式进行还原。 3. **内存操作**:由于程序可能已经在内存中运行,脱壳工具可能需要在内存中...
对于想要深入理解脱壳技术的学习者来说,熟悉PE文件格式至关重要。 **PE文件格式简介** - **定义**:PE格式由微软开发,用于定义Windows平台上可执行文件(如.EXE、.DLL等)的结构。 - **关键特性**:PE文件包含了...
- **静态与动态分析的兼容性**:构建一个可以在静态分析时重建有效PE文件,并在动态分析时执行的PE文件。 - **防止恶意软件检测**:确保脱壳过程不会被恶意软件检测到,避免分析过程中的干扰。 - **兼容性问题**:...
这个过程涉及到对PE(Portable Executable)文件格式的理解,包括节区、导入表、导出表等关键结构。脱壳机通过识别和解析ASPack的特定标志和模式来实现这一目标。 在安全社区中,ASPack常被视为一种双刃剑。一方面...
有些模糊处理一个Win32 PE等包装.NET程序集里面的.NET反编译器无法读取该文件。 移除大多数/所有的垃圾类添加混淆。 修复了一些的peverify错误。许多混淆器是马车和创建无法验证的代码错误。 还原类型的方法的参数和...
ASPACK是一款著名的软件压缩和加壳工具,由Andrey Breslav开发,它能将可执行文件进行压缩,减小其体积,同时增加反调试和反静态分析的特性,使得程序更加难以逆向工程分析。ASPACK 2.1和2.2是该工具的两个较早版本...
你可以用它来压缩或解压缩PE(Windows)、ELF(Linux)或DOS格式的可执行文件。例如,将一个.exe文件压缩,可以使用以下命令: ``` upx -q your_program.exe ``` 如果想要脱壳,只需添加`-d`参数: ``` upx -qd your...
这个工具的工作原理,它的壳特征和编译器特征保存在HackFans.txt里面,能识别出来的壳,基本上都有对应的脱壳函数,用壳特征脱壳,可以脱壳,对于一些不好特殊的壳你可以用OEP侦测来脱壳,这要依赖编译器特征,你也可以自己...
通过学习这些基础知识,初学者可以建立起对PE文件格式的理解,学会如何利用SEH技术进行调试,并且能够识别和分析不同类型的壳。这些技能是进行脱壳操作的基础,也是进一步深入学习逆向工程的关键。
UPX(Ultimate Packer for eXecutables)是一款著名的开源加壳工具,它能够对可执行文件(如Windows下的PE文件)进行压缩和加密,以减小文件大小、提高加载速度,同时也能提供一定的保护作用,防止恶意逆向分析。...