VMP-“完美”修复dump内存导入表
修复对应64位程序(ring3),不能应用于32位,跳转指令含义不同。一些原理就不介绍了,主要说明一下修复dump内存导入表的步骤,使得可以直接使用IDA逆向,思路也是借鉴了前人,后附参考链接,先展示一下修复前后的效果吧。
下图是直接dump下来的内存,不过还是修改了SizeOfRawData和PointerToRawData的,并且进行过针对无壳程序dump内存IAT修复方式处理过。
下图是修复dump内存IAT过后的,放两张图。
上图程序还没加载完,看着很舒服,完美。
实现修复VMP dump内存导入表的关键步骤如下,分小标题介绍。
核心思想
文件加载到IDA上,成功地反汇编呈现给我们,事实上是实现了内存自加载PE(可以这样理解,但其实不是),所以修复的关键是要让其成功模拟内存自加载,内存自加载有以下三个要点:
- 内存对齐,即文件映射到内存,文件每个节区实现从memcpy(VirtualAddrss,PointerToRawData,SizeOfRawData)
- 修复导入表
- 重定位
因此,对应要点进行修复。
内存对齐
由于dump下来的文件已经是内存状态,如果要让IDA识别,需要修改两个字段,每个节表头的PointerToRawData以及SizeOfRawData,满足PointerToRawData == VirtualAddress,SizeOfRawData == VirtualSize。
PointerToRawData == VirtualAddress
izeOfRawData == VirtualSize
此时,把dump下来的文件放到IDA已经可以加载,但是导入表是坏的。
备注:需要注意的是,dump下来的内存中原始的Import Table指向的VirtualAddress和Size都不是进程真正使用的导入表位置,真正的导入表位置已经被VMP修改到其他位置,但是原始的Import Table可以帮助我们修复导入表。
重定位
并不需要重定位,不需要修改Image Base,保持不动。
修复导入表
下面是重头戏,修复导入表,核心的编程点如下:
- 添加一个新的区段,用于存放我们新建的导入表以及其相关结构
我的程序导入的函数很多,所用空间比较大,申请了0x15000大小的区段
扫描内存dump文件中特定的opcode,64位程序对应ff 15/25
找到ff 15/25的位置,记下该位置,之后要修改ff 15/25 后面的四个字节,修改其IAT位置到我们新建的IAT当中
通过找到ff 15/25位置,找到dump内存中动态加载该API函数的地址,保存地址
利用原始Import Table找到进程载入的所有的DLL名称,如果Import Table指向的位置没有,那么搜索dll字符串,定位所有的dll名称,把它整合一下。LoadLibrary所有dll,从EAT中遍历该DLL的所有地址与找到的API函数地址匹配
匹配成功,保存函数名以及对应的ff 15/25位置,下标一一对应,并记录匹配的函数个数,方便IAT内存的合理分配
重建IAT,我是0x20字节用于存放0x14大小的ImportDescriptor,0x30开始对应Name字段,接着是OriginalFirstThunk以及FirstThunk,最后是一个个的IMAGE_IMPORT_BY_NAME结构
同时修改ff 15/25对应的后4字节,让其指向我们新建的IAT位置,一一对应
另外,dump以后的内存,要保证在不重启的情况下,使用工具修复,重启会使得系统DLL地址重新分配。