逆向工程核心原理学习笔记1-通过IAT手工定位notepad.exe中的导入函数

来源:互联网 发布:ubuntu无法创建文件夹 编辑:程序博客网 时间:2024/05/21 17:59

本文将通过PEview 0.99这款PE查看器来复习与IAT相关的知识,复习方式就是手工查找xpsp3下notepad.exe文件中第一个导入DLL中的第一个导入函数。之所以选用PEview而不用winhex类软件,主要是为了便于验证自己的思路是否正确。在熟悉了IAT手工查找的具体过程之后,还是使用工具软件直接获取信息比较方便。

导入函数表IAT应该是分析PE文件时比较难过的一关了,涉及到多个结构体数组之间的相互关联,我看了很多遍也没有完全搞清楚,那不如就把本文作为一道练习题,来系统地梳理一下思路。如有不对之处,还请各位指出。

1. 试验环境

  • 操作系统:windows xp sp3 x86
  • 目标程序:notepad.exe
  • 分析程序:PEview、OD
  • 参考网页:http://blog.csdn.net/evileagle/article/details/12357155

2. 查找过程整体思路

这里写图片描述

3. 具体查找过程

(1)梳理处各节区的地址段,以便于后续的RAW换算。针对本文中的notepad程序,其各区段的RAW和RVA如下图所示。

这里写图片描述

其中,RAW通过查看各节区头Image_Section_Header中的PointerToRawData属性可得,而RVA通过查看各节区头Image_Section_Header中的VirtualAddress可得。

(2)查找Image_Dos_Header头中的e_lfanew属性,结果如下。

这里写图片描述

从而可知,Image_NT_Headers在PE文件中的偏移是0xE0。

(3)通过偏移,找到Image_NT_Headers,具体如下。

这里写图片描述

(4)根据Image_NT_Headers结构体,我们可以找到DataDirectory数据目录表数组中对应导入表入口处的元素,具体如下。

这里写图片描述

从而可知,导入表的入口处偏移为0x7604。由于该地址是RVA,故需要计算其RAW。由于RVA是0x7604,处于0x1000-0x9000这个地址范围内,故等式两侧的被减数均为text区段的RAW和RVA。

RAW - 400 = 7604 - 1000
即RAW = 0x6A04

导入表入口地址为0x6A04,指向一个image_import_descriptor结构体的数组,每个image_import_descriptor结构体代表一个被导入的DLL。

(5)通过计算得到的0x6A04,我们找到如下信息,这是导入表中第一个被导入的DLL(comdlg32.dll)的image_import_descriptor结构体。

这里写图片描述

a. 我们先看name这一项,peview是怎么知道该值对应的就是“comdlg32.dll”这个DLL名称字符串呢?首先,我们要从RVA转换成RAW:

RAW - 400 = 7AAC - 1000
故RAW = 0x6EAC

我们来看这个地址的对应数值,如下图所示。

这里写图片描述

可以看到,其对应的确实是“comdlg32.dll”字符串。

b. 我们再看import_name_table,即OriginalFirstThunk,其对应值为0x7990,

RAW - 400 = 7990 - 1000
故RAW = 0x6D90

该地址指向一个IMAGE_THUNK_DATA数组,这个数组中的每一项表示一个导入函数,如下图所示。

这里写图片描述

最后的全0表示comdlg32.dll导入库的结束。

c. 我们再看import_address_table,即FirstThunk,其对应值为0x12C4。

RAW - 400 = 12C4 - 1000
故RAW = 0x6C4

该地址也指向一个IMAGE_THUNK_DATA数组,如下图所示。

这里写图片描述

最后的全0表示comdlg32.dll导入库的结束。

d. OriginalFirstThunk与FirstThunk区别
既然两者都指向一个大小相同的IMAGE_THUNK_DATA数组,他俩有什么区别呢?这是IAT中的一个难点。为了解答这个问题,先来认识一下IMAGE_THUNK_DATA结构:

这里写图片描述

ForwarderString是转发用的,暂时不用考虑。Function表示函数地址。如果是按序号导入,则Ordinal就有用了,若是按名字导入,AddressOfData便指向名字信息。可以看出这个结构体就是一个大的union,大家都知道union虽包含多个域但是在不同时刻代表不同的意义,那到底应该是名字还是序号,该如何区分呢?

可以通过Ordinal判断,如果Ordinal的最高位是1,就是按序号导入,这时候,低16位就是导入序号;如果最高位是0,则AddressOfData是一个RVA,指向一个IMAGE_IMPORT_BY_NAME结构,用来保存名字信息。由于Ordinal和AddressOfData实际上是同一个内存空间,所以AddressOfData其实只有低31位可以表示RVA,但是一个PE文件不可能超过2G,所以最高位永远为0,这样设计很合理地利用了空间。

对于OriginalFirstThunk指向的Image_Thunk_Data数组,其中的元素可表示如下。union共同体中,只有Ordinal和AddressOfData是有用的。

这里写图片描述

我们这里以comdlg32.dll对应image_import_descriptor中的OriginalFirstThunk字段对应的Image_Thunk_Data数组为例,其第一个函数的对应值为0x00007A7A。由于最高位是0,所以AddressOfData(即0x00007A7A)是一个RVA,指向一个IMAGE_IMPORT_BY_NAME结构,用来保存名字信息。

这里写图片描述

通过RVA与RAW的转换公式可知,0x00007A7A对应的RAW为0x6E7A,其对应信息如下。

这里写图片描述

由上可知,0x6E7A处保存的是字符串“PageSetupDlgW”,即comdlg32.dll的第一个导入函数。

而FirstThunk指向的Image_Thunk_Data数组如下。

这里写图片描述

其第一个元素值为0x76344906,对应的值是程序被载入后的内存地址,故需要在OD中查看。我们用OD载入notepad.exe,并在反汇编窗口中按CTR+N组合键,调出模块窗口,可看到,0x76344906处的值为函数名称字符串“PageSetupDlgW”,是comdlg32.dll输出的函数,与OriginalFirstThunk指向的数值是一致的。

这里写图片描述

在PE文件加载以前或者说在导入表未处理以前,FirstThunk所指向的数组与OriginalFirstThunk中的数组虽不是同一个,但内容却是相同的,都包含了导入信息。而在加载之后,FirstThunk中的Function开始生效,它被载入器填充了实际的函数地址。

4. 需要注意的问题

以下摘自《逆向工程核心原理》第111页。

1、FirstThunk中的元素值其实是没有实际意义的,当程序被加载到内存中时,准确的地址值会取代该值。换句话说,winxpsp3中的notepad也可以在win7中运行,当系统载入程序时,PE装载器会使用相应API的起始地址替换该值。

2、与comdlg32.dll这样的系统DLL不同,普通DLL在IAT中不会硬编码实际地址,通常带有与INT相同的数值。也就是说,对于普通DLL,OriginalFirstThunk与FirstThunk指向完全相同的同一个Image_Thunk_Data数组。

3、普通DLL文件的ImageBase为10000000,所以经常会发生DLL重定位。但Windows系统DLL(如kernel32等)拥有自身固有的ImageBase,不会出现DLL重定位。当然,开启了ASLR之后的情况就另说了。

0 0
原创粉丝点击