PE知识复习之PE的导入表
PE知识复习之PE的导入表
一丶简介
上一讲讲解了导出表. 也就是一个PE文件给别人使用的时候.导出的函数 函数的地址 函数名称 序号 等等.
一个进程是一组PE文件构成的. PE文件需要依赖那些模块.以及依赖这些模块中的那些函数.这个就是导入表需要做的.
确定PE依赖那个模块. 确定PE依赖的那个函数. 以及确定函数地址.
总共分为三部分讲解.
导入表定位位置: 在扩展头中有一个数据目录结构体. 第二项保存的就是导入表的 RVA 以及大小.
如下图所示:
EXE文件.没有导出表.有一个导入表. RVA 是 0x1A1C0 位于节Text中. 虚拟地址位 0x11000 文件偏移为 0x400
转换为 FOA = 1A1C0 - 11000 + 400 = 0x95c0
我们发现在文件中定位导入表的时候都是0,原因是程序加载到内存中.需要用到的时候.操作系统才会往这个地方填写数据.
二丶导入表结构
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) 指向IAT结构注释表明了
} DUMMYUNIONNAME;
DWORD TimeDateStamp; // 时间戳.
// -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; //指向DLL名字的 RVA
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
导入表大小为十进制的20个字节. 16进制的 0x14. 如果以16进制为一行. 则是 一行零4个字节
导入表跟导出表不同.导出表只有一个.里面有子表记录. 而导入表你依赖一个模块.则有一个导入表存在.
导入表结束位置是20个字节的连续为0的数据为结束位置. 也就是导入表最后一项都为0的时候.说明导入表结束了.
对于导入表来说.我们只需要关心三个成员.上面都标红了.
会一一进行讲解.首先从最简单的成员开始.
2.1 Name成员. 确定依赖的模块的名字是什么
我们说过.一个PE文件.依赖模块. 那么这个成员就是记录了.我要依赖的模块的名字是什么.是一个RVA属性. RVA指向了一个ASCII码字符串.以0结尾.
因为在文件中导入表并没有.所以我们直接在内存中查看.
根据数据目录 导入表位置 0x1A1C0 + ImageBase(0x400000) == 0x41AC0
在内存中的0x41AC0位置.则是导入表的位置. 我们看一下.
导入表大小总共一行零4个字节. 倒数第二个成员则是 Name的 RVA 0x1A4A6
我们可以加上ImageBase 去内存中查看.
可以通过RVA 属性.看到导入表依赖的模块名字就是 VCRUNTIME140D.dll 带有D结尾的.dll说明是调试DLL. 140是编译器版本.说明是
VS2015编译的 .VCRuntime 是运行库 . 说明我们这个程序是一个 Debug版本编译的程序. 并且使用编译器 140版本编译的.
我们查看的这个Name属性.描述的就是 VCRUNTIME140D.dll 这个模块的信息了.如果想看其它依赖的模块就需要查看下一张导入表.
下一张导入表在第一章导入表的下面.最后一项的导入表全部为0. 我们下一张导入表的 依赖模块的模块名称的 RVA 属性是 0x1A75A
VA = Imagebase + RVA = 41A75A
依次查看即可.
2.2 确定依赖的函数的名称
上面我们讲了Name成员.确定了导入表依赖的DLL的名字.那么我们导入表怎么确定依赖了那些函数那?
这个主要讲解导入表的第一个成员跟最后一个成员.
如下图所示:
第一个成员指向了一个INT 表.最后一个成员指向了一个 IAT表.
INT :: 导入名称表 Improt Name Table
IAT:: 导入地址表 Improt Address Table
Name成员直接指向一个 ASC 结尾的字符串.
根据上图所示. 两张表是一样的. 但是所在位置是不一样的名字也不一样.一个叫做 INT 一个叫做IAT
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; // PBYTE
DWORD Function; // PDWORD
DWORD Ordinal;
DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
结构体大小: 4个字节. 他是一个联合体.找最大的.
里面有4个成员.为当前的4个字节起了四个名字. 真正有用的是下面两个. 也就是说有的时候需要用第三个成员.
有的时候需要用第四个成员. 而第四个成员是指向一个 IMAGE_IMPORT_BY_NAME的结构的RVA
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //编译器决定,不是空的话,就是函数在导出表中的 函数地址表的导出索引.
CHAR Name[]; //函数名称,0结尾.
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
无论是第一个成员还是最后一个成员.都能确定 我一来的当前模块的那个函数.
为什么需要两个表. 这个下面会将. 首先讲解的就是无论使用那个表.都能找到依赖当前模块的函数.
第一个成员找:
INT表 INT表是4个字节.最后0结尾. INT表有多大.就是说依赖这个模块的多少个函数.
IAT 同上. 0结尾.
那么我们怎么去寻找?
看这个表的4个字节. 最高位为1那么就是函数的导出序号. 去掉最高位.就是函数的序号. 也就是说我们看的是序号.
如果最高位不是1,那么找的就是一个 RVA ,一个指向 IMAGE_IMPROT_BY_NAME的结构.
例如下图:
INT 或者 IAT表. 都可以通过最高位判断. 是函数的序号.还是函数的名字.
INT或者IAT就是两种情况, 高位为1, 那么去掉高位就是依赖的函数序号. 不是1, 那么就是一个RVA. 指向了一个 IMAGE_IMPROT_BY_NAME 结构.
以一个导入表为例
INT的 RVA 为 1A2A8 VA = 41A2A8
41A2A8是INT表开始. 每一个是4个字节,以0结尾. 观看第一项. 高位为0,所以 0x1A48E 是一个RVA. 一个指向 IMAGE_IMPROT_BY_NAME 的结构
VA = 41A48E
高位两个字节,是函数在导出表中的导出索引. 后面就是以0结尾的函数名称了.
总结来说: 不管是INT表还是 IAT表. 主要看其高位值,高位为1,那么去掉高位,就是函数的序号. 高位为0.指向一个结构.这个结构保存了函数的导出序号.以及函数名称.
在IMAGE_IMPROT_BY_NAME 结构中的 HINT 如果不是空,那么这个序号(索引) 就是导出表的函数地址表的索引. 我们可以直接拿着这个索引去导出表中获取函数地址.
2.3 确定函数地址
如果我们使用DLL的函数.那么在程序中.调用这个DLL的函数.那么就会生成一个间接Call
比如我们程序调用MessageBoxA
反汇编
跳转过去之后.会看到内存中有一个地址
这个地址才是真正的MessageBox的地址
在我们导入表中,最后一个成员 IAT表.就是上面所说的表,保存了函数地址表.
那么这和我们说的结构是不一样的. IAT不是说跟INT是一样的吗?
PE加载前加载后的区别.
一样是一样的.但是需要分清 PE加载前.还有PE加载后.如果加载前,那么IAT跟INT一样.都可以找到依赖的函数名称.
如果是加载后.也就是在内存中的话.那么IAT表保存的就是函数的地址.
PE加载后如下图:
IAT表保存的就是函数地址了.
从导入表中找到IAT表.
IAT表的RVA 偏移为 0x1A098 VA == 41A098
IAT表中存储了函数地址,4个字节为单位.0x6AD79CF0 就是函数 __Vcrt_loadlibraryExW . INT表中存储的就是 依赖的函数名称.上面我们也看到了.
三丶知识总结
导入表大小为20个字节. 十六进制 0x14 ,一行零4个字节.
1.导入表重要成员有三个. INT表. Name表. IAT表.
PE加载前.
INT 表 IAT表相同. 根据INT或者IAT表的高位,高位为1.去掉高位就是函数序号. 高位为0. 那么是一个RVA偏移. 指向函数名称表.
函数名称表
HINT 当前函数在导出函数地址表中的索引
Name 当前函数的名称.
PE加载后INT 表同上. IAT表变成了存储函数地址的地址表了.
2. Name 民称表. 直接指向DLL名称文件名. 是一个RVA .注意是直接指向.
3.INT IAT表.的RVA 都是定位INT IAT表位置. 定位的位置是INT IAT表.这个表存储的才是数据
PE知识复习之PE的导入表的更多相关文章
- PE知识复习之PE的绑定导入表
PE知识复习之PE的绑定导入表 一丶简介 根据前几讲,我们已经熟悉了导入表结构.但是如果大家尝试过打印导入表的结构. INT IAT的时候. 会出现问题. PE在加载前 INT IAT表都指向一个名称 ...
- PE知识复习之PE的重定位表
PE知识复习之PE的重定位表 一丶何为重定位 重定位的意思就是修正偏移的意思. 如一个地址位 0x401234 ,Imagebase = 0x400000 . 那么RVA就是 1234. 如果Im ...
- PE知识复习之PE的节表
PE知识复习之PE的节表 一丶节表信息,PE两种状态.以及重要两个成员解析. 确定节表位置: DOS + NT头下面就是节表. 确定节表数量: 节表数量在文件头中存放着.可以准确知道节表有多少个. 节 ...
- PE知识复习之PE的导出表
PE知识复习之PE的导出表 一丶简介 在说明PE导出表之前.我们要理解.一个PE可执行程序.是由一个文件组成的吗. 答案: 不是.是由很多PE文件组成.DLL也是PE文件.如果我们PE文件运行.那么就 ...
- PE知识复习之PE的各种头属性解析
PE知识复习之PE的各种头属性解析 一丶DOS头结构体 typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // M ...
- PE知识复习之PE合并节
PE知识复习之PE合并节 一丶简介 根据上一讲.我们为PE新增了一个节. 并且属性了各个成员中的相互配合. 例如文件头记录节个数.我们新增节就要修改这个个数. 那么现在我们要合并一个节.以上一讲我们例 ...
- PE知识复习之PE新增节
PE知识复习之PE新增节 一丶为什么新增节.以及新增节的步骤 例如前几讲.我们的PE文件在空白区可以添加代码.但是这样是由一个弊端的.因为你的空白区节属性可能是只读的不能执行.如果你修改了属性.那么程 ...
- PE知识复习之PE扩大节
PE知识复习之PE扩大节 一丶为什么扩大节 上面我们讲了,空白区添加我们的代码.但是有的时候.我们的空白区不够了怎么办.所以需要进行扩大节. 扩大节其实很简单.修改节数据对齐后的大小即可. 并且在PE ...
- PE知识复习之PE的RVA与FOA的转换
PE知识复习之PE的RVA与FOA的转换 一丶简介PE的两种状态 首先我们知道PE有两种状态.一种是内存展开.一种是在文件中的状态.那么此时我们有一个需求. 我们想改变一个全局变量的初始值.此时应该怎 ...
随机推荐
- Zathura: 轻巧好用的 PDF 查看器]
[Zathura: 轻巧好用的 PDF 查看器](https://linuxtoy.org/archives/zathura.html) 这个文件很轻巧,且支持VIM方式的 快捷键
- Do-Now—团队 冲刺博客六
Do-Now-团队 冲刺博客六 作者:仇夏 前言 终于从四级的考试中解脱了(不过我觉得可能凉凉,呵呵),我们的APP制作也迎来了最后的两天. 自己觉得自己其实没有干成什么事情,代码什么的大都是队友们写 ...
- 关于 Mybatis 设置懒加载无效的问题
看了 mybatis 的教程,讲到关于mybatis 的懒加载的设置: 只需要在 mybatis 的配置文件中设置两个属性就可以了: <settings> <!-- 打开延迟加载的开 ...
- JavaScript模板引擎Handlebars
Handlebars模板库简单介绍 Handlebars是JavaScript一个语义模板库,通过对view(模板)和data(ajax请求的数据,一般是json)的分离来快速构建Web模板.它采用& ...
- Linux正则表达式练习
练习一 1.生成30位的随机口令 [root@centos7 ~]#cat /dev/urandom | tr -dc "[:alnum:]" | head -c30 RJL5qc ...
- web项目如何使用Material Icons
使用文档链接 图标库 最简单的使用方法 引入 <link href="https://fonts.googleapis.com/icon?family=Material+Icons&q ...
- ABP入门系列(5)——展现层实现增删改查
ABP入门系列目录--学习Abp框架之实操演练 这一章节将通过完善Controller.View.ViewModel,来实现展现层的增删改查.最终实现效果如下图: 一.定义Controller ABP ...
- 【同余方程组】POJ1006 生理周期
同余方程组: 先来看一道题目:有物不知其数,三三数之剩二:五五数之剩三:七七数之剩二.问物几何? 然后我们可以做如下变换,设x为所求的数. x%3=2 x ≡ a1(%m1 ...
- [Swift]LeetCode380. 常数时间插入、删除和获取随机元素 | Insert Delete GetRandom O(1)
Design a data structure that supports all following operations in averageO(1) time. insert(val): Ins ...
- [Swift]LeetCode440. 字典序的第K小数字 | K-th Smallest in Lexicographical Order
Given integers n and k, find the lexicographically k-th smallest integer in the range from 1 to n. N ...