IAT表详解

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

 http://blog.163.com/ljm1113@126/blog/static/57984452201201485318443/

 

IAT表详解

IAT的全称是Import Address Table。

对于每一个引入的可执行文件(例如dll),有一个镜像引入描述符(IMAGE_IMPORT_DESCRIPTOR)。
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
     union {
          DWORD Characteristics;         // 0 for terminating null import descriptor
          DWORD OriginalFirstThunk;   // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
     };
     DWORD TimeDateStamp;          
// 0 if not bound,
                                                               
// -1 if bound, and real date\time stamp
                                                               
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                                               
// O.W. date/time stamp of DLL bound to (Old BIND)
      DWORD ForwarderChain;          
// -1 if no forwarders
      DWORD Name;                             // RVA,指向字符串,是这个可执行文件的名字。例如"ACE.dll"
      DWORD FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;

dll的forward不好讲,因为很多都是undocumented的.

我们着重关心两个指针,OriginalFirstThunk和FirstThunk。
Characteristics一词出于历史原因,故在此给它了一个别名,OriginalFirstThunk。
OriginalFirstThunk和FirstThunk是两个DWORD值,存贮着两个RVA数值,其实它们就是两个指针。
OriginalFirstThunk和FirstThunk实际上都是指向同一个数组。
前者,我们称之为INT,而后者,我们称之为IAT.

 

IAT是一个IMAGE_THUNK_DATA类型的数组。有多少个函数被导入,这个数组就有多少个成员。该数组以0结尾。
typedef struct _IMAGE_THUNK_DATA32 {
     union {
           DWORD ForwarderString;          // 一个RVA地址,指向forwarder string
           DWORD Function;                       // PDWORD,被导入的函数的入口地址
           DWORD Ordinal;                         // 该函数的序数
           DWORD AddressOfData;           // 一个RVA地址,指向IMAGE_IMPORT_BY_NAME
      } u1;
} IMAGE_THUNK_DATA32;

IMAGE_THUNK_DATA64与IMAGE_THUNK_DATA32的区别,仅仅是把DWORD换成了64位整数。

PIMAGE_IMPORT_BY_NAME是一个非常简单的结构,就两个成员。
typedef struct _IMAGE_IMPORT_BY_NAME {
     WORD Hint;            // 该函数的导出序数
     BYTE Name[1];      // 该函数的名字
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

而IMAGE_THUNK_DATA32就是一个非常魔术般的东西了。
struct IMAGE_THUNK_DATA的大小,恰好等于一个指针的大小。(32bit机器下是32bit,64bit机器下是64bit)

每一个IMAGE_THUNK_DATA对应着一个被导入的函数。
对于可执行文件而言,IAT中的IMAGE_THUNK_DATA中存储的要么是Ordinal,要么是AddressOfData
怎么判断IMAGE_THUNK_DATA中存储的是Ordinal 还是 AddressOfData 呢?
众所周知,在32bit的机器上,地址空间是00000000-FFFFFFFF,
一般而言,其中00000000-7FFFFFFF是用户空间,其它是系统空间。
于是,看IMAGE_THUNK_DATA的最高位,如果是1,就是Ordinal,否则就是AddressOfData。

但是这里还存在一个2GB的问题。因为2GB的用户地址空间对于很多程序不够用,(主要是数据库系统),于是微软就想了一些变通的办法。例如win 2000的/3GB选项。
在启动文件,boot.ini中加上这个选项后,用户空间变成3GB,系统空间减少到1GB。
然后呢?
然后在链接该可执行文件的时候必须加上特殊的选项,这样在PE头就会有一个特殊的设置。
如果开了3GB选项,如果PE头不加这个设置,那么用户空间是2GB,系统空间是1GB.
如果开了3GB选项,且PE头加了这个设置,那么用户空间是3GB,系统空间是1GB.


而INT和IAT中存储的本来应该是同样的数据。
然后说绑定(binding).
当一个可执行文件被绑定的时候,IAT中的IMAGE_THUNK_DATA被改写为(被导入的)该函数的实际地址。
这一步也许是交给链接器在链接的时候执行,也许是在该可执行文件载入的时候执行。
但是,如果,该可执行文件已经和dll绑定。但是这个dll后来又被更改了,这些被导入的函数依然在该dll中存在,但是实际地址已经改变了还有,我们保留过一个IAT的副本,它就是INT.(这就是为什么我们称之为Original FirstThunk).根据INT中的内容,我们可以重建IAT表

 

综上所述,将exe文件绑定到dll的最佳时机,是在安装可执行文件的时候。这就是安装程序,Windows installer,所要做的事情之一。

 

下面说,怎么判断IAT中的信息是否已经过期。
首先,绑定分两种类型,新式的和老式的。
前面已经说过IMAGE_IMPORT_DESCRIPTOR中的TimeDateStamp有三种可能性。
1.TimeDateStamp等于0 =〉 尚未绑定
2.TimeDateStamp等于-1 => 新式绑定
3.其它 => 老式绑定,这里存储的就是上次绑定是在什么时间。

然后我详细介绍下新式绑定
DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ]指向一个重要的数据结构。
typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
      DWORD TimeDateStamp;      // a DWORD that contains the time/date stamp of the imported DLL.
      WORD OffsetModuleName;    // a WORD that contains an offset to a string with the name of the imported DLL.
                                                            // This field is an offset (not an RVA) from the first IMAGE_BOUND_IMPORT_DESCRIPTOR.
       WORD NumberOfModuleForwarderRefs;  // 这个结构体后面还有多少个IMAGE_BOUND_FORWARDER_REF 结构体
                                                                                   // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR;

来看看IMAGE_BOUND_FORWARDER_REF是一个什么样的结构体。
typedef struct _IMAGE_BOUND_FORWARDER_REF {
          DWORD TimeDateStamp;
          WORD OffsetModuleName;
         WORD Reserved;
} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;
和IMAGE_BOUND_IMPORT_DESCRIPTOR完全相同,除了最后一个字节,它是被保留的。

然后说这两个结构体的作用。

IMAGE_BOUND_IMPORT_DESCRIPTOR的作用很显然。根据TimeDateStamp和OffsetModuleName字段的值我们就可以判断IAT表中的信息是否已经过期。

但是存在这样一种情况。一个dll导到另一个dll中。例如USER32.DLL和KERNEL32.DLL。

假如USER32.DLL未更改,但是KERNEL32.DLL更改过了。此时需要重建USER32.DLL的IAT。但是我们的程序只是直接用到了 USER32.DLL,于是导入表中就没有KERNEL32.DLL的IAT,也没有KERNEL32.DLL的TimeDateStamp和 OffsetModuleName。
所以也就有, 如果一个dll forward了另一个dll,那么在这个dll的IMAGE_BOUND_IMPORT_DESCRIPTOR结构体后面需要再插入被forward的 dll的IMAGE_BOUND_FORWARDER_REF结构体。之后才是下一个dll的 IMAGE_BOUND_IMPORT_DESCRIPTOR。

而IMAGE_BOUND_IMPORT_DESCRIPTOR.NumberOfModuleForwarderRefs的意义就不言而喻了。

每个dll一个IAT表,一般而言,这些IAT表都是统一存储在一起的。由于每个IAT表是以0结尾。所以很容易分离开来

 

 

滴水三期:day39.1-IAT和导入 一、引入IAT(1.调用自己写的函数 > 2.调用DLL中的函数 > 3.易错误区)二、导入(1.导入是什么 > 2.定位导入 > 3.导入结构 > 4.IAT和INT > 5.总结)三、作业(1.打印程序运行前的导出 阅读详情

相关推荐

《Windows PE》4.1.3 IAT函数地址

如果导入描述符的TimeDateStamp和ForwarderChain字段是一个特殊的标志值,如0xFFFFFFFF,示导入函数已绑定,则IAT函数地址中存储的是真实的导入函数地址。在程序加载时,操作系统会根据导入描述符中的INTIAT进行动态链接,将导入函数的实际入口地址填充到IAT中的函数指针对应的位置。IAT就是用来存储这些实际的函数入口地址。首先找到数据目录项的第12项,获取IAT函数地址的RVA地址,加上基址后,得到并输出加载到内存中的IAT函数地址的VA地址。

bcdaren的博客 1254

导入解析,IAT解析【滴水逆向三期53笔记】

我们再上一章节简要介绍了IAT,我们知道如果程序调用dll中的函数时,必须通过IAT来找到函数,我们基本了解了IAT之后,我们今天来讲解一下导入,通过本章节的学习,我们可以了解导入,也能对IAT有一个更深入的了解。

WdIg-2023的博客 1290

手把手教你用Scylla修复Mp3Resizer.exe的IAT(附脱壳完整流程)

本文详细解析了使用Scylla工具修复Mp3Resizer.exe导入地址IAT)的完整脱壳流程。针对新手在修复IAT时常见的“未知库文件”难题,提供了从定位OEP、内存转储到精准修复IAT的清晰步骤,并重点讲解了如何识别并移除无效导入项,确保脱壳后的程序可稳定运行。

weixin_29315569的博客 136

滴水逆向三期实践16:IAT和导入

IAT 在我们调用 dll函数的时候,发现代码中的汇编,是通过间接寻址的。也就是不直接 call函数地址,而是通过一个中间地址再跳转的。 比如调用MessageBox这类系统函数的时候(这也是个 dll中的函数),那么它的汇编会为 call dword ptr [ (004322d4) ]通过间接寻址,004322d4里面存的是X就可以跳到X,这个X变量可以任意指定。004322d4是.exe领空的,而间接寻址的X可以不是.exe领空,比如这次运行中X会变为77d5050b,就跳到了.dll ...

Rivival_S 的博客 3561

IAT详解(转)

IAT详解 IAT的全称是Import Address Table。 IAT是执行程序或者dll为了实现动态加载和重定位函数地址,用到的一个导入函数地址。这里面记录了每个导入函数的名字和所在的dll名称,在pe加载的时候系统会加载这些dll到用户的地址空间然后把函数地址覆盖这个里的函数地址,然后重构所有用到这个的代码,让其调用直接指向实际函数地址(PE是否覆盖不确定,驱动会这么做),...

1593

导入IAT详解

本文详细解析了Windows程序中的导入Import Table)和导入地址IAT)机制。主要内容包括: 本质:导入是程序声明的API需求清单,IAT是Loader填写的实际地址 工作流程:Loader加载DLL,查找函数地址,写入IAT 调用方式:程序通过IAT间接调用API 必要性:由于DLL加载地址不固定,不能硬编码API地址 结构解析: Import Directory指向描述符数组 每个DLL对应一个IMAGE_IMPORT_DESCRIPTOR 包含INT(函数需求)和IAT(地址

2501_93430765的博客 18

2.4 数据目录详解(导入/IAT、导出、资源等)

数据目录解析摘要 PE文件的数据目录IMAGE_DATA_DIRECTORY)位于可选头尾部,包含16个关键结构条目,为系统加载器提供核心功能导航。主要目录包括: 导出(0):记录DLL暴露的函数地址,含名称/序号两种导出方式。 导入(1)与IAT(12):声明依赖的外部函数,IAT运行时填充实际地址,支持绑定导入优化。 资源(2):多级树形结构管理图标、字符串等非代码数据。 重定位(5):ASLR必需的地址修正信息,剥离后影响安全性。 调试/TLS:分别存储调试信息与线程回调,后者常被恶意

勤奋的码农 799

【免杀前置课——PE文件结构】十八、数据目录及其内容详解——数据目录(导出、导入IAT、TLS详解;如何在程序在被调试之前反击?TLS反调试(附代码)

【免杀前置课——PE文件结构】十八、数据目录及其内容详解——数据目录(导出、导入IAT、TLS详解;如何在程序在被调试之前反击?TLS反调试(附代码)

m0_62783065的博客 1651

使用x64dbg手动查找程序IAT

储存在IMAGE_OPTIONAL_HEADER->DataDirectory->IMAGE_IMPORT_DESCRIPTOR。程序加载进内存的起始地址(0x7FF646590000) + IID的RVA(0x224A8) = 0x7FF6465B24A8。在CFF Explorer里面可以看到IID的RVA(IID的另一种叫法就是Import Directory Table)其中的FirstThunk里面储存了IAT的RVA。其中的第5个DWORD就是IAT的RVA。下面是IID结构体的定义。

2503_92196128的博客 59

win脱壳3 -- dump程序后的IAT修复

文章摘要 Dump指将内存中的程序镜像导出为文件,常用于脱壳场景。操作需在原始程序入口点(OEP)暂停,通过工具(如x64dbg+Scylla)导出解压后的代码及重建的IAT。Dump后程序崩溃多因IAT未修复,需定位IAT地址(硬件断点跟踪首个调用报错点)并修复条目(还原真实API地址,重建导入)。修复工具推荐Scylla,支持自动扫描与修复,关键步骤包括填OEP、扫描IAT、Dump导出及FixDump修复。注意区分报错与崩溃位置,64位环境需调整方法,最终验证脱壳文件能否独立运行。

盾悟 6224

win脱壳5 -- IAT混淆修复与dbg脚本自动化修复 脱壳完成

脱壳自动化IAT修复流程摘要(150字) 通过x64dbg脚本自动化完成IAT修复: 前置条件:确保程序执行到OEP(ESP定律定位),壳已解密代码并重建IAT。 脚本逻辑:遍历IAT(0x00475000~0x00475120),逐条处理加密条目: 模拟call [IAT]跳转至stub地址(如005E2264),单步执行至RET指令(0xC3)。 从RET前的栈顶([ESP])提取真实API地址(如7C8023xx),回写至IAT条目。 验证与Dump:修复后IAT条目变为系统DLL地址(如kerne

盾悟 4751

​​PE结构 ---> 5.数据目录 节区 节

PE文件中,代码、数据、资源等内容被划分为不同的节,每个节都有IMAGE_SECTION_HEADER属性信息。掌握数据目录,是深入 PE 解析、手动 LoadPE、IAT Hook 等技术的。IMAGE_SECTION_HEADER描述了文件中的位置和内存中的位置。但是我们现在是从文件中来的所以不应该是---> RVA(内存地址)。dos头->dos体->NT头[文件头 可选头]->区段->区段。所以我们现在需要做的操作就是把RVA---> FOA(文件地址)资源 (Resource Table)

盾悟 1万+

WinVisor模块导入黑科技:手动解析IAT导入与延迟执行TLS回调的完整实现

WinVisor 是一款基于 Windows 虚拟化平台(WHP)API 的 x64 用户态程序模拟器。它的"模块导入黑科技"在于:**手动解析 IAT 导入**、**延迟执行 TLS 回调**——先冻结目标进程的依赖加载与初始化,待虚拟 CPU 完全接管后再逐项补做,从而让任意 exe 在虚拟环境中干净、可控地启动。下面带你完整拆解这套实现。 [![WinVisor 手动解析 IAT 导入

gitblog_00323的博客 149

南邮 2024 软件安全实验:Mp3Resizer.exe脱壳与IAT修复实战解析

本文详细解析了南京邮电大学2024年软件安全实验中,针对加壳程序Mp3Resizer.exe的脱壳与IAT修复实战过程。通过运用ESP定律定位OEP,并重点介绍了使用Scylla工具修复IAT时,如何识别并手动清理非法导入项这一核心挑战与解决方案,为软件安全逆向分析提供了清晰的操作指南。

weixin_29326909的博客 316

CTF逆向入门:使用x32dbg手动脱UPX壳实战详解

在软件安全与逆向工程领域,加壳技术常用于保护程序代码、压缩文件体积或增加分析难度。UPX作为一种经典的压缩壳,其原理是在程序执行时,先由壳代码在内存中完成解压和导入修复,再将控制权交还给原始程序入口点。掌握手动脱壳技术,不仅能应对自动脱壳工具失效的变种壳,更是深入理解程序加载、内存布局和动态调试的核心实践。通过调试器跟踪壳的执行流程,在关键跳转点中断并转储内存镜像,随后修复导入,即可成功还原原始程序。这一过程在CTF竞赛、恶意软件分析和软件保护研究中具有广泛应用。本文将以一道典型的UPX加壳CTF逆向题

keke1314520的博客 533
上一篇: IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT问题
下一篇: Debug常用指令
小大小丑
博客等级 码龄18年 483粉丝 425原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值