在 PE文件头的 IMAGE_OPTIONAL_HEADER 结构中的 DataDirectory(数据目录表) 的第二个成员就是指向输入表的。每个被链接进来的 DLL文件都分别对应一个 IMAGE_IMPORT_DESCRIPTOR (简称IID) 数组结构。

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
} DUMMYUNIONNAME;
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;
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

在这个 IID数组中,并没有指出有多少个项(就是没有明确指明有多少个链接文件),但它最后是以一个全为NULL(0) 的 IID 作为结束的标志。

下面只摘录比较重要的字段:

OriginalFirstThunk

它指向first thunk,IMAGE_THUNK_DATA,该 thunk 拥有 Hint 和 Function name 的地址。

Name

它表示DLL 名称的相对虚地址(译注:相对一个用null作为结束符的ASCII字符串的一个RVA,该字符串是该导入DLL文件的名称。如:KERNEL32.DLL)。

FirstThunk

它包含由IMAGE_THUNK_DATA定义的 first thunk数组的虚地址,通过loader用函数虚地址初始化thunk。

在Orignal First Thunk缺席下,它指向first thunk:Hints和The Function names的thunks。

下面来解释下OriginalFirstThunk和FirstThunk。就个人理解而言:

1. 在文件中时,他们都分别指向一个RVA地址。这个地址转换到文件中,分别对应两个以 IMAGE_THUNK_DATA 为元素的的数组,这两个数组是以一个填充为 0 的IMAGE_THUNK_DATA作为结束标识符。虽然他们这两个表位置不同,但实际内容是一模一样的。此时,每个 IMAGE_THUNK_DATA 元素指向的是一个记录了函数名和相对应的DLL文件名的 IMAGE_IMPORT_BY_NAME结构体。

2. 为什么会有两个一模一样的数组呢?是有原因的:

OriginalFirstThunk 指向的数组通常叫做  hint-name table,即 HNT ,他在 PE 加载到内存中时被保留了下来且永远不会被修改。但是在 Windows 加载过 PE 到内存之后,Windows 会重写 FirstThunk 所指向的数组元素中的内容,使得数组中每个 IMAGE_THUNK_DATA 不再表示指向带有函数描述的 IMAGE_THUNK_DATA 元素,而是直接指向了函数地址。此时,FirstThunk 所指向的数组就称之为输入地址表(Import Address Table ,即经常说的 IAT)。

重写前:

重写后:

(以上两张图片来自:http://www.dematte.org/2006/03/04/InterceptingWindowsAPIs.aspx

typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; // PBYTE 指向一个转向者字符串的RVA
DWORD Function; // PDWORD 被输入的函数的内存地址
DWORD Ordinal; // 被输入的 API 的序数值
DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME 指向 IMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;

根据 _IMAGE_THUNK_DATA32 所指虚拟地址转到文件地址可以得到实际的 _IMAGE_IMPORT_BY_NAME 数据

typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; // 序号
    CHAR   Name[];  // 实际上是一个可变长的以0为结尾的字符串
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

例如有程序:

文字版:

#include <windows.h>
int WINAPI WinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nShowCmd)
{
MessageBoxA(, "hello", "my message", MB_OK);
SetWindowTextA(, "Si Wang"); return ;
}

此程序使用了两个 Windows API : MessageBoxA 和 SetWindowTextA

编译得到程序(为简化说明,区段位置由软件计算出):

我们试着找出 MessageBoxA。首先分析 PE 头文件,找到导出表在文件中的位置:

输入表位置在 .rdata 区段内, 0x2264 – 0x2000 = 0x0264 得到偏移量。加上文件地址 0x0E00 得到实际文件偏移量(0x0E00 + 0x264 = 0x1064):0x1064。

接下来查看 0x1064 处:

可以得到三个 DLL 的描述,最后一个_IMAGE_IMPORT_DESCRIPTOR 以0填充表示结束:

那么只要一个个查看每个DLL对应的数据就能找到,不过之前我把所有的数据都看了下,在第一个DLL中

根据第一个DLL描述的 OriginalFirstThunk 的 0x2350 转换可以知道,_IMAGE_THUNK_DATA32 在文件的 0x1150处,FirstThunk 指向的数据相同:

于是就得到了文件中的 MessageBoxA 的信息。

最后,在内存中 FirstThunk 所指位置上的_IMAGE_THUNK_DATA32 数组被 Windows 加载后被重写后就成了传说中的 IAT ,Import Address Table,输入地址表。使用 OllyDbg 查看运行时情况:

[PE结构分析] 8.输入表结构和输入地址表(IAT)的更多相关文章

  1. 15.5 自学Zabbix之路15.5 Zabbix数据库表结构简单解析-其他 表

    点击返回:自学Zabbix之路 自学Zabbix之路15.5 Zabbix数据库表结构简单解析-其他 表  1. Actions表 actions表记录了当触发器触发时,需要采用的动作. 2.Aler ...

  2. 自学Zabbix之路15.1 Zabbix数据库表结构简单解析-Hosts表、Hosts_groups表、Interface表

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix之路15.1 Zabbix数据库表结构简单解析-Hosts表.Hosts_grou ...

  3. 自学Zabbix之路15.2 Zabbix数据库表结构简单解析-Items表

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix之路15.2 Zabbix数据库表结构简单解析-Items表 Items表记录了i ...

  4. 自学Zabbix之路15.3 Zabbix数据库表结构简单解析-Triggers表、Applications表、 Mapplings表

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix之路15.3 Zabbix数据库表结构简单解析-Triggers表.Applica ...

  5. 自学Zabbix之路15.4 Zabbix数据库表结构简单解析-Expressions表、Media表、 Events表

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix之路15.4 Zabbix数据库表结构简单解析-Expressions表.Medi ...

  6. 自学Zabbix之路15.5 Zabbix数据库表结构简单解析-其他 表

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix之路15.5 Zabbix数据库表结构简单解析-其他 表  1. Actions表 ...

  7. Linux 在 i 节点表中的磁盘地址表中,若一个文件的长度是从磁盘地址表的第 1 块到第 11 块 解析?

    面试题: 在 i 节点表中的磁盘地址表中,若一个文件的长度是从磁盘地址表的第 1 块到第 11块,则该文件共占有 B  块号.A 256 B 266 C 11 D 256×10 linux文件系统是L ...

  8. MySQL查看表结构及查看建表语句

    查看表结构:desc 表名 mysql> use recommend; Database changed mysql> desc user; +--------------+------- ...

  9. Oracle学习(三)SQL高级--表结构相关(建表、约束)

    一.建表语句 CREATE DATABASE(创建数据库) --创建数据库 create database 数据库名字; CREATE TABLE(创建表) --创建表 CREATE TABLE 表名 ...

随机推荐

  1. Hibernate一些防止SQL注入的方式

    Hibernate在操作数据库的时候,有以下几种方法来防止SQL注入,大家可以一起学习一下. 1.对参数名称进行绑定: Query query=session.createQuery(hql); qu ...

  2. 理解vmp

    原文作者: 海风月影_百度空间 vmp里面只有1个逻辑运算指令 not_not_and 设这条指令为PP(a,b) = ~a & ~b 这条指令的神奇之处就是能模拟 not and or xo ...

  3. popupwindow 与 输入法

    有时候popupwindow会被输入法覆盖, 有时候popupwindow会被输入法给顶上去. 而且这个问题还跟theme的windowFullscreen属性相关. 不过这些可以都不用管, 根据项目 ...

  4. Xcode8新特性和iOS10新特性

    从 Xcode 8.0 开始,目前所有的插件都无法工作! NSLog 无法输出 -- 此bug等待正式版本... Xcode 提供了文档注释快捷键option + cmd + / 但是要把系统升级到1 ...

  5. distri.lua重写开源手游服务器框架Survive

    Survive之前采用的是C+lua的设计方式,其中网关服务器全部由C编写,其余服务全部是C框架运行lua回调函数的方式编写游戏逻辑. 鉴于一般的手游对服务器端的压力不会太大,便将Survive用di ...

  6. Winform 数据库连接app.config文件配置 数据库连接字符串

    1.添加配置文件 新建一个winform应用程序,类似webfrom下有个web.config,winform下也有个App.config;不过 App.config不是自动生成的需要手动添加,鼠标右 ...

  7. Python & Django 学习笔记

    最近在学校Python和Django.在学习中遇到了种种的问题,对于一个新手来说,下面的问题可能都会遇到.希望能帮助到那些和我一样的人!!0.python-dev安装(ubuntu)  apt-get ...

  8. Backbone1.0.0数据验证的变化

    0.5.3版本对Model数据验证时,绑定Error就可以了: (function(){ var Model = Backbone.Model.extend({ initialize : functi ...

  9. 【weka应用技术与实践】过滤器

    weka中的过滤器主要用于数据预处理阶段对数据集的各种操作. 今天简单地使用一下过滤器: 首先打开一个自带数据集weather.numeric.arff,这是一个关于通过天气条件,气温以及风力等因素来 ...

  10. java攻城狮之路(Android篇)--MP3 MP4、拍照、国际化、样式主题、图片移动和缩放

    一.MP3播放器 查看Android API文档可以看到MediaPlayer状态转换图: 练习: package com.shellway.mp3player; import java.io.Fil ...