C/C++ 导入表与IAT内存修正
本章教程中,使用的工具是上次制作的PE结构解析器,如果还不会使用请先看前一篇文章中对该工具的介绍,本章节内容主要复习导入表结构的基础知识点,并通过前面编写的一些小案例,实现对内存的转储与导入表的脱壳修复等。
关于Dump内存原理,我们可以使用调试API启动调试事件,然后再程序的OEP位置写入CC断点让其暂停在OEP位置,此时程序已经在内存解码,同时也可以获取到程序的OEP位置,转储就是将程序原封不动的读取出来并放入临时空间中,然后对空间中的节表和OEP以及内存对齐进行修正,最后将此文件在内存保存出来即可。
脱壳修复:输入表一般分为IAT与INT,由于加壳后程序可能会加密或者破坏IAT结构,导致脱壳后IAT不一致了,脱壳修复就是使用未脱壳的源程序的输入表覆盖到新程序中,就这麽简单。
解析器下载与使用:https://www.cnblogs.com/LyShark/p/12960816.html
解析 IMAGE_IMPORT_DESCRIPTOR
数据目录表第二个成员指向输入表,该指针在PE开头位置向下偏移80H处,PE开始位置就是B0H , B0H+80H= 130H处。

此处存放着一个指针,00002040 即输入表在内存中的偏移量为 2040,使用前面制作的工具可以快速定位到此处。

2040是一个RVA,需要将其转换为磁盘文件FOA偏移才能定位到输入表在文件中的位置,使用工具快速完成计算任务,转换为文件偏移为 00000640

也可以这样来找到640的位置,首先2040位于rdata,rdata的虚拟偏移是2000h,而实际偏移是600h 使用 2000h - 600h = 1a00h

将相对偏移地址2040转为文件偏移,使用2040-1a00同样可得出640h 用winhex打开后跳转过去看看。

下面将重点解析一下这几个结构的含义。

如上就是导入表中的IID数组,每个IID结构包含一个装入DLL的描述信息,现在有两个DLL,第三个是一个全部填充为0的结构,标志着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;
以第一个字段为例:
0000 208C => OrignalFirstThunk => 指向输入名称表INT的RVA
0000 0000 => TimeDateStamp => 指向一个32位时间戳,默认此处为0
0000 0000 => ForwardChain => 转向API索引,默认为0
0000 2174 => Name => 指向DLL名字的指针
0000 2010 => FirstThunk => 指向输入地址表IAT的RVA
每个IID结构的第四个字段指向的是DLL名称的地址,以第一个为例,其RVA是0000 2174 将其减去1a00得到文件偏移774,跳转过去看看,调用的是USER32.dll库。

使用工具同样可以快速转换出来。

上方的两个字段OrignalFirstThunk和FirstThunk都可以指向导入结构,在实际装入中,当程序中的OrignalFirstThunk值为0时,则就要看FirstThunk里面的数据了,FirstThunk常被叫做IAT他是在程序初始化时被动态填充的,而OrignalFirstThunk常被叫做INT,他是不可改变的,之所以会保留两份是因为,有些时候会存在反查的需求,保留两份是为了更方便的实现。
解析 IMAGE_THUNK_DATA32
如上,我们找到了User32.dll的OrignalFirstThunk,其地址为208C,使用该值减去1A00h 得到 68Ch,在偏移为68Ch处保存的就是一个IMAGE_THUNK_DATA32数组,他存储的内容就是指向 IMAGE_IMPORT_BY_NAME 结构的地址,最后一个元素以一串0000 0000作为结束标志,先来看一下IMAGE_THUNK_DATA32的定义规范。
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;
直接使用WinHex定位到68Ch处,此处就是OrignalFirstThunk中保存的INT的内容,如下图中,出去最后一个00000000以外,一共有11个四字节,则说明User32.dll中导入了11个API函数。

再来看一下FirstThunk也就是IAT中的内容,由于User32的FirstThunk字段默认值是2010h,使用该值减去1a00h即可得到610h,此处就是IAT的内容,定位过去看看,完全一致的。

我们以第一个导入RVA地址
00002110h,用该值减去1a00h得到710h,定位过去正好是LoadIconA的字符串。
接着来看第二个导入RVA地址0000211ch,用该值减去1a00h得到71c0定位过去正好是PostQuitMessage的字符串。

如上图,以第二个为例,前两个字节表示的是Hint值,后面的蓝色部分则是PostQuitMessage字符串,最后的0标志结束标志。
当程序被运行前,它的FirstThunk值与OrignalFirstThunk字段都指向同一片INT中,如下使用上次编写的MyDump工具对其内存进行dump转储,观察内存变化。

观察发现 OrignalFirstThunk字段并不会发生变化,但是FirstThunk值的指向已经改变,系统在装入内存时会自动将FirstThunk指向的偏移转化为一个个真正的函数地址,并回写到原始空间中,定位到输入表RVA地址处2040h查看。

可以发现,黄色的INT并没有变化,但是绿色的IAT则相应的发生了变化,以第一个0x766bd680则是载入内存后LoadIconA的内存地址,我们使用X64DBG跟过去看看,没错吧!

当系统装入内存后,其实只会用到IAT中的地址解析,输入表中的INT啥的就已经不需要了,此地址每个系统之间都会不同,该地址是操作系统动态计算后填入的,这也是为什么会存在导入表这个东西的原因,就是为了解决不同系统间的互通问题的。
有时我们在拖壳时,由于IAT发生了变化,所以程序会无法被正常启动,我们Dump出来的文件可能收入表已经被破坏了,导入表不一致,我们可以使用原始的未脱壳的导入表地址对脱壳后的导入表地址进行覆盖,来修复文件,使用修复工具修复即可。
例如dump前导入表是这样的。

dump 后变成了这样。

由于导入表错误导致dump文件无法正常运行,这是需要使用修复工具来对导入表进行修正。

修正后文件就可以正常被打开了,我们来看一下dump后的文件导入表。

是不是很清晰了,就是将原来的导入函数的RVA拷贝过来,就这麽简单。
工具学习篇
lyshark.exe 是一个加过UPX壳的程序,现在演示如何流程化脱壳处理。

先查节表,发现UPX

定位到数据目录表中第二个字段,也就是输入表的存储位置,直接使用工具计算出foa地址。

加过壳就是这样 442cc

将内存文件转储出来,保存到dump.exe

跳过去看看,空的

尝试打开文件,出现错误。

使用buid工具修正即可。脱壳后文件体积变大了

不过我自己捣鼓的这些脱壳工具只是用来学习的,很多壳还得借助专业的脱壳工具进行修复,我这个修不了。
既然到这份上了,来演示一下专业脱壳,先查壳,upx

压缩壳,使用ESP定律脱掉。F8一次,ESP右击内存窗口转到

断点设置硬件访问断点,四字节,选择,让程序跑起。

然后运行到jmp 即可到达OEP

获取OEP删除无效函数,直接dump转储文件。

文件转储打不开

使用工具修复buitIAT即可。

脱壳完成,程序可运行起来。

C/C++ 导入表与IAT内存修正的更多相关文章
- PE格式第四讲,数据目录表之导入表,以及IAT表
PE格式第四讲,数据目录表之导入表,以及IAT表 一丶IAT(地址表) 首先我们思考一个问题,程序加载的时候会调用API,比如我们以前写的标准PE 那么他到底是怎么去调用的? 他会Call 下边的Jm ...
- 第四讲,数据目录表之导入表,以及IAT表
一丶IAT(地址表) 首先我们思考一个问题,程序加载的时候会调用API,比如我们以前写的标准PE 那么他到底是怎么去调用的? 它会Call 下边的Jmp位置 而Jmp位置则是对一个全局变量取内容. 看 ...
- [PE结构]导入表与IAT表
导入表的结构导入表的结构 typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; // 0 for termi ...
- Windows PE 第四章 导入表
第四章 导入表 导入表是PE数据组织中的一个很重要的组成部分,它是为实现代码重用而设置的.通过分析导入表数据,可以获得诸如OE文件的指令中调用了多少外来函数,以及这些外来函数都存在于哪些动态链接库里等 ...
- C/C++ 手工实现IAT导入表注入劫持
DLL注入有多种方式,今天介绍的这一种注入方式是通过修改导入表,增加一项导入DLL以及导入函数,我们知道当程序在被运行起来之前,其导入表中的导入DLL与导入函数会被递归读取加载到目标空间中,我们向导入 ...
- IAT表和导入表
1.关于IAT(import address table)表 当exe程序中调用dll中的函数时,反汇编可以看到,call后面并不是跟的实际函数的地址,而是给了一个地址:
- PE文件结构详解(四)PE导入表
PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPO ...
- 《初识PE》导入表
最近听别人讲的我晕晕乎乎的,于是上网上百度下,感觉这篇还不错. 链接:http://www.blogfshare.com/pe-export.html 一.导入表简介 在编程中常常用到"导 ...
- PE文件 01 导入表
0x01 导入表结构 数据目录表中的第二个成员标记了导入表的RVA和Size大小,由此可以定位到导入表: typedef struct _IMAGE_DATA_DIRECTORY { DWORD ...
随机推荐
- MySQL:安装与配置
记录一次 MySQL 在Windows系统的安装配置过程 安装MySQL 0.下载社区版安装包 官网下载地址:https://dev.mysql.com/downloads/installer/ 1. ...
- Java开发不懂Docker,学尽Java也枉然,阿里P8架构师手把手带你玩转Docker实战
转: Java开发不懂Docker,学尽Java也枉然,阿里P8架构师手把手带你玩转Docker实战 Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一 ...
- TKE 容器网络中的 ARP Overflow 问题探究及其解决之道
作者朱瑜坚,腾讯云后台开发工程师,熟悉 CNI 容器网络相关技术,负责腾讯云 TKE 的容器网络的构建和相关网络组件的开发维护工作,作为主力开发实现了 TKE 下一代容器网络方案. 1. 问题背景 1 ...
- pytorch(03)tensor的操作
张量操作 一.张量的拼接 torch.cat() 功能:将张量按维度dim进行拼接,且[不会扩张张量的维度] tensors:张量序列 dim:要拼接的维度 torch.cat(tensors, di ...
- Java基础:重文本markdown
说一说markdown 前言 在系统学习Java等开发语言之前,我们应该养成写"日记"的习惯,也就是写博客:写博客的地方有博客园,csdn等.而写博客又得知道markdown重文本 ...
- java IO流文件拷贝文件(字符流标准写法)
public static void copyFile2(String path1, String path2) { Reader reader = null; Writer writer = nul ...
- SEO优化基础知识
一.标点符号的重要性 很多人忽略了标点符号对爬虫的重要性,爬虫并不是对所有标点符号都爬取,下面列举几个对关键字分隔有帮助的符号. 1.1.逗号( , ) ==> 千万千万要使用英文的逗号,而不是 ...
- FHRP - 网关冗余协议
通常情况下,在终端设备进入网络前,都会有一个 Router 充当网络,作为第一跳的网络地址.但假设路由器发生故障,此时终端设备就无法再接入互联网. 为了防止这样的问题,一般会再加入一台路由器充当备份. ...
- 推荐一款全能测试开发神器:Mockoon!1分钟快速上手!
1. 说一下背景 在日常开发或者测试工作中,经常会因为下游服务不可用或者不稳定时,通过工具或者技术手段去模拟一个HTTP Server,或者模拟所需要的接口数据. 这个时候,很多人脑海里,都会想到可以 ...
- AttributeError: 'str' object has no attribute 'lowerr' Python常见错误
方法名拼写错误 检查方法名拼写,如有错误改正即可 特别注意m和n