使用脚本转存为可执行文件#
此章介绍脱壳后的两个步骤,转存可执行文件和重建导入函数表。
OEP
上一章中,已经调试出来了 OEP,转到 OEP 处并操作 ida 重新分析程序,准备执行转存操作,使用如下 idc 脚本来转存。
static Byte(ea) {
return (ea) & 0xff;
}
static main()
{
auto fp, ea;
fp = fopen("dump.bin", "wb"); // 打开要写入的文件
for (ea=0x400000; ea < 0x40b200; ea++) // 循环指定地址范围
{
fputc(Byte(ea), fp); // 将指定地址中的数据写入文件中
}
fclose(fp); // 关闭文件
}
注:在实战的过程中,ida7.7 中使用如上代码转存的内容会有问题,转存的内容不是正常的内容
所以这里就换成了 python3 的脚本来转存,脚本如下:
import idaapi
import idc
import struct
start_ea = 0x400000
end_ea = 0x40b200
step = 4 # 每个地址处的数据占用4个字节
file_path = "dump.bin"
with open(file_path, "wb") as f:
for ea in range(start_ea, end_ea, step):
# 读取指定地址处的4个字节数据并进行小端字节序转换
bin_data = struct.pack("<L", idaapi.get_32bit(ea))
f.write(bin_data)
文件基址是 0x400000,从 ida segments 选项卡中查找转存的最高地址,从下图中可以看到 Overlay 区块的结尾 0x40b200。
之后打开菜单栏 - 文件 - 脚本文件运行,这个功能 idc 脚本和 python 脚本都可以。idc 脚本执行后,会在 idc 当前目录下生成一个 bin 文件。
bin 文件的文件头如下图就算是正常的。
将 dump.bin 文件备份,然后重命名为.exe 的可执行文件。
这个文件的图标没有显示出来,所以还有问题需要解决。
让后通过 pe editor 打开
pe editor 1.7
点击 sections,打开区段视图。
区段视图
在每一个区段上右键单击并选择 dumpfixer。
这个时候图标正常显示了,但程序还是无法运行,因为还未修复 IAT。
什么是 IAT#
IAT(Import Address Table)是 Windows PE 格式中的一种重要的数据结构,用于在程序运行时动态地加载和链接外部 DLL 库(动态链接库)的符号。IAT 保存了外部 DLL 库中所有要调用的函数的名称和地址,可被程序动态链接器在运行时使用。
IAT 保存程序执行的所有导入函数的地址
加壳文件解密后的 IAT
原始文件的 IAT
上面两张图都标记了 0x403238 地址,内容看上去差不多。
打开原始文件
的 IDA 左下角显示了这个内存地址对应的文件偏移是 0x1038,如上图所示,此时就可以打开十六进制编辑器查看它的内容。
010editor 打开原始文件 0x1038 处的字节
上图中0x1038
处的值是0x355e
。
如果0x355e
加上基址0x400000
就是0x40355e
,为了查看这个地址的内容,需要用 ida 重新手动加载文件中的所有区段(加载原始文件
)。
0x40355e 处的内容
选择加载所有的区段,转到 0x40355e 处,右侧也可以看到 api 的函数名为GetModuleHandleA
。
通过这些偏移的数值加上基址的值,就能找到对应的函数名字符串,根据这个字符串可以获取这些函数在系统上的本机地址,本例中获取了GetModuleHandleA
的地址,然后将5E 35 00 00
字节替换为本机地址。
系统根据初始值 0x355e 加上基址后获取对应的函数名字符串,再将函数的本机地址存放到 0x403238。
再打开一个 ida 窗口加载转存出来的文件dump - bak.exe
,转向0x403238
。
上图中,文件的偏移地址是 0x3238 和原始文件不匹配,主要原因是 dumpfixer 将文件占用(rawsize)改成和内存占用(rawsize)一样,导致了偏移改变。
在 010editor 打开dump - bak.exe
,来到 0x3238 处。
这里是 api 函数的本机地址,不是指向 api 名称字符串的偏移。
因为转存的时候,程序已经获取了调用 api 函数的本机地址并且将它们保存到 IAT,所以加壳程序中的GetModuleHandleA API
本机地址就保存在这个地址上。
GetModuleHandleA API
函数
上述转存有个问题,就是当程序执行时,会从 IAT 中读取偏移,再加上基址地址,获取 API 函数名字符串,通过系统获取这些 API 函数的本机地址,再保存回 IAT。而转存时保留的是函数的实际地址,程序无法按这一流程正确地填充 IAT,最终会导致程序崩溃。
重建 IAT#
重建 IAT 的思路就是恢复这些指向 api 函数字符串的偏移值,修复 IAT 需要一个 Scylla 的工具。
运行 scylla,在 attach to an active process 中,选择在 ida 中暂停在 OEP 的加壳程序的进程。
加壳程序运行到 OEP
填写 OPE 的值为 00401000,点击 IAT Autosearch。
上图中显示起始地址是 0x403184,大小是 0x108。
点击 Get Imports。
上图中,显示有 22 处未修复。
右键选择未识别的函数,选择 scylla plugins-pecompact v2.x 进行修复。
成功修复未识别的函数
有一些可疑函数,选择 show suspect,确认 0x403278 处的函数是否修复成功。
上图中,可以看到成功修复,确认没问题后,点击 scylla 右下角的 FIX DUMP。
选择之前转存的.exe 文件,写入修复后的 IAT。
修复后的程序可正常运行,说明修复成功。
使用 IDA 加载脱壳并完成 IAT 修复的文件,程序从 OEP 也就是 0x401000 开始执行,修复的和原始文件一样。
IDA 加载 IAT 修复之后的可执行文件
修复后的 IAT
这章主要介绍了如何转存区段内容并重建导入 IAT 函数表,并完成最后的脱壳工作,完成了这个 upx 加壳程序的脱壳,学习了下整个脱壳流程。