VMP-修复dump内存导入表

VMP-“完美”修复dump内存导入表

修复对应64位程序(ring3),不能应用于32位,跳转指令含义不同。一些原理就不介绍了,主要说明一下修复dump内存导入表的步骤,使得可以直接使用IDA逆向,思路也是借鉴了前人,后附参考链接,先展示一下修复前后的效果吧。

下图是直接dump下来的内存,不过还是修改了SizeOfRawData和PointerToRawData的,并且进行过针对无壳程序dump内存IAT修复方式处理过。

VMP8

下图是修复dump内存IAT过后的,放两张图。

VMP9

VMP10

上图程序还没加载完,看着很舒服,完美。

实现修复VMP dump内存导入表的关键步骤如下,分小标题介绍。

核心思想

文件加载到IDA上,成功地反汇编呈现给我们,事实上是实现了内存自加载PE(可以这样理解,但其实不是),所以修复的关键是要让其成功模拟内存自加载,内存自加载有以下三个要点:

  • 内存对齐,即文件映射到内存,文件每个节区实现从memcpy(VirtualAddrss,PointerToRawData,SizeOfRawData)
  • 修复导入表
  • 重定位

因此,对应要点进行修复。

内存对齐

由于dump下来的文件已经是内存状态,如果要让IDA识别,需要修改两个字段,每个节表头的PointerToRawData以及SizeOfRawData,满足PointerToRawData == VirtualAddress,SizeOfRawData == VirtualSize。

PointerToRawData == VirtualAddress

VMP1

izeOfRawData == VirtualSize

VMP2

此时,把dump下来的文件放到IDA已经可以加载,但是导入表是坏的。

备注:需要注意的是,dump下来的内存中原始的Import Table指向的VirtualAddress和Size都不是进程真正使用的导入表位置,真正的导入表位置已经被VMP修改到其他位置,但是原始的Import Table可以帮助我们修复导入表。

重定位

并不需要重定位,不需要修改Image Base,保持不动。

修复导入表

下面是重头戏,修复导入表,核心的编程点如下:

  • 添加一个新的区段,用于存放我们新建的导入表以及其相关结构

VMP3

​ 我的程序导入的函数很多,所用空间比较大,申请了0x15000大小的区段

  • 扫描内存dump文件中特定的opcode,64位程序对应ff 15/25

    VMP4

  • 找到ff 15/25的位置,记下该位置,之后要修改ff 15/25 后面的四个字节,修改其IAT位置到我们新建的IAT当中

    VMP5

  • 通过找到ff 15/25位置,找到dump内存中动态加载该API函数的地址,保存地址

    VMP6

  • 利用原始Import Table找到进程载入的所有的DLL名称,如果Import Table指向的位置没有,那么搜索dll字符串,定位所有的dll名称,把它整合一下。LoadLibrary所有dll,从EAT中遍历该DLL的所有地址与找到的API函数地址匹配

  • 匹配成功,保存函数名以及对应的ff 15/25位置,下标一一对应,并记录匹配的函数个数,方便IAT内存的合理分配

    VMP7

  • 重建IAT,我是0x20字节用于存放0x14大小的ImportDescriptor,0x30开始对应Name字段,接着是OriginalFirstThunk以及FirstThunk,最后是一个个的IMAGE_IMPORT_BY_NAME结构

  • 同时修改ff 15/25对应的后4字节,让其指向我们新建的IAT位置,一一对应

另外,dump以后的内存,要保证在不重启的情况下,使用工具修复,重启会使得系统DLL地址重新分配。

参考链接

手动分析VMP加密的x64驱动导入表

使用模拟器进行x64驱动的Safengine脱壳+导入表修复