输入表在PE中的结构及加载过程
来源:互联网 发布:unity3d webplayer 编辑:程序博客网 时间:2024/05/29 02:22
http://hi.baidu.com/mymillet/blog/item/0c09123debead3c19f3d6249.html
输入表结构我们知道,程序调用外部的dll函数通常都是下面这种形式:
call my_label
...
my_label: jmp dword ptr [xxxxxxxx]
对一个dll中的函数的调用总是通过一个地址间接的调用的.这些地址就放在输入表里(所以如果你改动了输入表, 可能也需要改my_label: jmp dword ptr [xxxxxxxx]).
输入表(Import Table),简而言之,就是描述该pe文件从哪几个动态连接库导入了什么函数的一组结构数组.在这里我希望能用最简洁的语言让你明白什么是输入表.输入表的组成并不复杂,只用到三个结构.它们是:IMAGE_IMPORT_DESCRIPTOR,IMAGE_THUNK_DATA,IMAGE_IMPORT_BY_NAME.
我们先看一下框图.
IMAGE_IMPORT_DESCRIPTOR
|---------------------------|
|---------------------| OriginalFirstThunk |
| |---------------------------|
| | TimeDateStamp |
| |---------------------------|
| | ForwarderChain |
| |---------------------------|
| | Name |----> "USER32.DLL"
| |---------------------------|
| | FirstThunk |---------------------------------------------------------------------|
| |---------------------------|(装入内存后FirstThunk指向的结构数组会被修改) |
| |
| Hint-name table IMAGE_IMPORT_BY_NAME import address table(IAT) |
| |--------------------------------| |--------------------------------| |--------------------------------| |
|-> | IMAGE_THUNK_DATA |-->| 44 | "GetMessage" |<--| IMAGE_THUNK_DATA|<---|
|--------------------------------| |-----|--------------------------| |--------------------------------|
| IMAGE_THUNK_DATA |-->| 72 | "LoadIcon" |<--| IMAGE_THUNK_DATA |
|--------------------------------| |-----|--------------------------| |--------------------------------|
| ...... |-->| .. | ...... |<--| ...... |
|--------------------------------| |------|--------------------------| |---------------------------------|
| NULL | | NULL |
|--------------------------------| |----------------------------------|
当然,这是描述从一个dll中引入函数的情形.从几个dll中引入函数,那么就有几个这样的结构.同时,这也是磁盘文件上的结构.装入内存后FirstThunk指向的结构数组会被修改.可以看下面的图.
我们先来熟悉一下这三个结构的定义:
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;
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_THUNK_DATA32 {
union {
PBYTE ForwarderString;
PDWORD Function;
DWORD Ordinal;
PIMAGE_IMPORT_BY_NAME AddressOfData;
} u1;
} IMAGE_THUNK_DATA32;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //指出函数在所在的dll的输出表中的序号
BYTE Name[1]; //指出要输入的函数的函数名
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
IMAGE_IMPORT_DESCRIPTOR结构的各个域的含义:
1)union {
DWORD Characteristics;
DWORD OriginalFirstThunk;
};
这个联合指向一个 IMAGE_THUNK_DATA 类型的结构数组.这个联合不是很重要,可以为0.
2)TimeDateStamp
该dll的时间日期戳,一般为0.
3)ForwarderChain
正向连接索引.一般为0.
4)Name
dll名字的RVA.
5)FirstThunk
这个域也是一个RVA,指向一个DWORD数组,数组以NULL结束.数组中的每个DWORD实际上是一个IMAGE_THUNK_DATA结构的联合体。IMAGE_THUNK_DATA联合体通常被解释为一个指向IMAGE_IMPORT_BY_NAME结构的RVA.
从上图我们可以看出有两个并行的指针数组都指向IMAGE_IMPORT_BY_NAME结构.事实上,OriginalFirstThunk指向的IMAGE_THUNK_DATA结构数组从来不被修改,该数组有时也叫提示名表(Hint-name table),提示名表总是指向IMAGE_IMPORT_BY_NAME结构数组.而FirstThunk指向的IMAGE_THUNK_DATA结构数组在该pe文件被加载时,加载程序会修改该数组的内容.加载程序迭代搜索数组的每一个指针,找到每一个IMAGE_IMPORT_BY_NAME结构所对应的输入函数的地址,然后加载程序用找到的地址修改相应的IMAGE_THUNK_DATA结构.(这是理解加载过程的关键).
如前面提到的
call my_label
...
my_label: jmp dword ptr [xxxxxxxx]
其中的xxxxxxxx就是FirstThunk指向的IMAGE_THUNK_DATA数组中的一个的值.因为FirstThunk所指向的数组在加载后是所有输入函数的地址,因此它被称为输入地址表(Import Address Table,IAT).
pe文件加载后输入表的情形如下:
IMAGE_IMPORT_DESCRIPTOR
|--------------------------|
|---------------------| OriginalFirstThunk |
| |---------------------------|
| | TimeDateStamp |
| |---------------------------|
| | ForwarderChain |
| |---------------------------|
| | Name |----> "USER32.DLL"
| |---------------------------|
| | FirstThunk |-----------------------------------------------------------|
| |---------------------------| |
| |
| Hint-name table IMAGE_IMPORT_BY_NAME import address table(IAT) |
| |--------------------------------| |-----------------------------| |------------------------------| |
|->| IMAGE_THUNK_DATA |-->| 44 | "GetMessage" | |ptr of GetMessage |<----|
|---------------------------------| |----|------------------------| |------------------------------|
| IMAGE_THUNK_DATA |--> | 72 | "LoadIcon" | | ptr of LoadIcon |
|---------------------------------| |----|------------------------| |------------------------------|
| ...... |-->| .. | ...... | | ...... |
|---------------------------------| |----|------------------------| |------------------------------|
| NULL |
- 输入表在PE中的结构及加载过程
- PE文件结构及在winnt.h中的定义
- PE文件结构(三) 输入表
- PE结构->【输入表】Import【上】
- PE结构->【输入表】Import【下】
- PE文件输入表获取过程
- PE文件加载时Section结构中的变化
- PE 结构分析技术在反病毒中的应用
- PE文件结构(二)-输入表实例分析
- PE文件加载过程揭秘
- PE资源结构及读取
- PE格式解析-区段表及导入表结构详解
- PE 结构详解4 区块表定义及属性
- IOS中的生命周期及加载过程
- PE文件结构及其加载机制
- windows PE文件结构及其加载机制
- windows PE文件结构及其加载机制
- PE文件结构详解-PE导入表
- 关于知识面
- Java的简介
- 04月01日网址
- 205. He is a good friend that speaks well of us behind our back.背后说好话,才是真朋友
- JS对话框 JS模态对话框 showModalDialog用法详解
- 输入表在PE中的结构及加载过程
- Perl连接Mysql
- 倒计时提交页面
- 关于Visual Studio 2010与64位系统的问题
- 硅谷最热的创业公司--寻找创业灵感(我感兴趣的)
- 「一個人」的狀態,總是最糟的。
- 得到一个Unicode串时,可以用下列几种方法之一将它转换成char类型串
- 自己最近写的一组日志处理类(线程调度优化)
- 第一个例子展示的是单接口COM对象