本章教程中,使用的工具是上次制作的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库。

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

上方的两个字段OrignalFirstThunkFirstThunk都可以指向导入结构,在实际装入中,当程序中的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内存修正的更多相关文章

  1. PE格式第四讲,数据目录表之导入表,以及IAT表

    PE格式第四讲,数据目录表之导入表,以及IAT表 一丶IAT(地址表) 首先我们思考一个问题,程序加载的时候会调用API,比如我们以前写的标准PE 那么他到底是怎么去调用的? 他会Call 下边的Jm ...

  2. 第四讲,数据目录表之导入表,以及IAT表

    一丶IAT(地址表) 首先我们思考一个问题,程序加载的时候会调用API,比如我们以前写的标准PE 那么他到底是怎么去调用的? 它会Call 下边的Jmp位置 而Jmp位置则是对一个全局变量取内容. 看 ...

  3. [PE结构]导入表与IAT表

    导入表的结构导入表的结构 typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; // 0 for termi ...

  4. Windows PE 第四章 导入表

    第四章 导入表 导入表是PE数据组织中的一个很重要的组成部分,它是为实现代码重用而设置的.通过分析导入表数据,可以获得诸如OE文件的指令中调用了多少外来函数,以及这些外来函数都存在于哪些动态链接库里等 ...

  5. C/C++ 手工实现IAT导入表注入劫持

    DLL注入有多种方式,今天介绍的这一种注入方式是通过修改导入表,增加一项导入DLL以及导入函数,我们知道当程序在被运行起来之前,其导入表中的导入DLL与导入函数会被递归读取加载到目标空间中,我们向导入 ...

  6. IAT表和导入表

    1.关于IAT(import address table)表 当exe程序中调用dll中的函数时,反汇编可以看到,call后面并不是跟的实际函数的地址,而是给了一个地址:

  7. PE文件结构详解(四)PE导入表

    PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPO ...

  8. 《初识PE》导入表

    最近听别人讲的我晕晕乎乎的,于是上网上百度下,感觉这篇还不错.  链接:http://www.blogfshare.com/pe-export.html 一.导入表简介 在编程中常常用到"导 ...

  9. PE文件 01 导入表

    0x01  导入表结构  数据目录表中的第二个成员标记了导入表的RVA和Size大小,由此可以定位到导入表: typedef struct _IMAGE_DATA_DIRECTORY { DWORD ...

随机推荐

  1. free命令查看内存

    [root@jojo ~]# free -h total used free shared buff/cache available Mem: 991M 273M 64M 1.1M 653M 535M ...

  2. 剑指 Offer 46. 把数字翻译成字符串 + 动态规划

    剑指 Offer 46. 把数字翻译成字符串 Offer_46 题目描述 题解分析 本题的解题思路是使用动态规划,首先得出递推公式如下 dp[i] = dp[i-1]+dp[i-2](如果s[i-1] ...

  3. 2020年12月-第02阶段-前端基础-CSS初识

    CSS层叠样式表 理解 css的目的作用 css的三种引入方式 1.HTML的局限性 说起HTML,这其实是个非常单纯的家伙, 他只关注内容的语义, 比如`<h1>`表明这是一个大标题,用 ...

  4. C#中的字段与属性的区别及属性的作用

    C#中的字段与属性的区别及属性的作用 先上代码 public class Employee { //字段 private string name; //属性 public string Name { ...

  5. Hi3359AV100 NNIE开发(1)-RFCN demo LoadModel函数与参数解析

    之后随笔将更多笔墨着重于NNIE开发系列,下文是关于Hi3359AV100 NNIE开发(1)-RFCN demo LoadModel函数与参数解析,通过对LoadModel函数的解析,能够很好理解. ...

  6. Spring Boot 轻量替代框架 Solon 的架构笔记 - new

    Solon 是一个微型的Java开发框架.项目从2018年启动以来,参考过大量前人作品:历时两年,4000多次的commit:内核保持0.1m的身材,超高的跑分,良好的使用体验.支持:RPC.REST ...

  7. WPF 应用 - 图表 LiveCharts

    引用:LiveCharts,LiveCharts.Wpf 1. 示例 折线图 <Window ... xmlns:lvc="clr-namespace:LiveCharts.Wpf;a ...

  8. MAC (Message Authentication Code,消息认证码算法)

    需要将密钥发送到对方,对方用该密钥进行摘要处理,进行摘要验证. //初始化KeyGenerator KeyGenerator keyGenerator= KeyGenerator.getInstanc ...

  9. Mybatis中由于${}直接注入引发的问题

    一.问题引入 我们先来看这段代码,我想从取值为${category}的表中查询全部信息. @Mapper public interface CategoryMapper { @Select(" ...

  10. 【Linux学习笔记1】-centos6.9部署django

    一,centos6.9部署django ​ 部署套件:centos6.9+nginx+mysql+uwsgi+python3+django ​ 首先还是要明白这几个部分之间的关系(自己也是初学者,希望 ...