脱Aspack手动查找IAT完成脱壳修复

时间:2022-07-23
本文章向大家介绍脱Aspack手动查找IAT完成脱壳修复,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

对于脱一些简单的壳来说,可以比较好的学习 PE 文件结构的知识,因为简单的壳比较容易脱,脱完以后进行修复的时候大部分就是处理 PE 文件结构了。因此,学习 PE 文件结构时,可以通过修复壳来加深对 PE 文件结构的学习。

本文介绍以下 Aspack 修复 IAT 的步骤。

请出 Peid 进行查看,查壳的结果是“什么也没发现”。换一个查壳工具接着查壳,用 Detect it Easy 0.64 查壳结果是 “Aspack2.12” 的壳。Aspack 的壳是压缩壳,是非常好脱的一个壳。

我们打开 OD 将 crackme 拽入 OD 中,入口代码如下所示:

00405001 c>  E8 03000000         call crackme6.00405009
00405006   - E9 EB045D45         jmp 459D54F6
0040500B     55                  push ebp
0040500C     C3                  retn
0040500D     90                  nop
0040500E     E8 01000000         call crackme6.00405014
00405013     EB 5D               jmp short crackme6.00405072
00405015     BB EDFFFFFF         mov ebx,-13

我们用 OD 打开 crackme 后,入口地址为 00405001。我们不管它的入口代码是什么,我们直接 Alt+M 打开“内存映射”窗口,找到 crackme 所在的虚拟内存区域。我们在 data 节用 F2 进行下断,也就是 00402000 的地址处。有可能有人习惯在最后一个节进行下断,也就是 00406000 处下断。其实在哪个节进行下断都可以,只要别在 code 节和 PE Header 处就可以。

为什么除了这两个节以外其他的节都可以呢?

压缩壳在对文件进行压缩时,是分节进行压缩的,在还原的时候也是一样的。通常压缩的顺序是逐节进行压缩,解压缩也是一样的。因此我们把 F2 断点下在 data 节,或者是下在最后一个节,当断点被中断时,也就是 code 节已经解压缩完成了。所以 F2 断点下到处 code 节和 PE 头的其余节都是可以的。

注:PE 头其实不能称为一个节,只是在 PE 装载时会用到,它在 code 节之前,且也是对齐的,因此在内存映射中看,也像是一个节,其实不是的。

我们在 data 节用 F2 下断后,按 F9 让 crackme 运行起来。很快 OD 被我们刚才下的 F2 断点中断住了,代码如下所示:

0040575F     8A18                mov bl,byte ptr ds:[eax]
00405761     40                  inc eax
00405762     885C24 0C           mov byte ptr ss:[esp+C],bl
00405766     8902                mov dword ptr ds:[edx],eax
00405768     8B42 08             mov eax,dword ptr ds:[edx+8]

从内存的地址可以看出,0040575f 仍然是壳的代码,在这里中断说明,这处代码是开始还原 data 节的起始位置。我们再次使用 ALT+M 打开“内存映射”窗口,这次在 code 节进行下断,也就是 00401000 处地址下 F2 断点。当断点在代码中断时,表示控制权由壳交给了真正程序的代码。因此当再次被中断时,也就是我们的 OEP 了。F9 让 crackme 运行起来。很快代码又一次被中断了,中断后的代码如下所示:

004011CB     64:A1 01000000      mov eax,dword ptr fs:[1]
004011D1     55                  push ebp
004011D2     89E5                mov ebp,esp
004011D4     6A FF               push -1
004011D6     68 1C204000         push crackme6.0040201C
004011DB     68 9A104000         push crackme6.0040109A
004011E0     50                  push eax
004011E1     64:8925 00000000    mov dword ptr fs:[0],esp
004011E8     83EC 10             sub esp,10

注意观察我们当前的地址为 004011cb,相对于我们的入口地址 00405001 来说,两个地址的距离已经非常远了。这样跨节的地址对我们脱压缩壳来说,是一个非常明显的找到 OEP 的界线。如果自己使用单步跟踪脱壳时,看到一个跨节的跳转或返回时,就说明我们要找到 OEP 了。

我们进行脱壳,在 OD 的菜单栏找到 “插件”->“OllyDump”->“脱壳在当前调试的进程”,出现对话框。我们直接点脱壳,并保存到磁盘上名为 dump.exe。我们别着急关 OD,我们试运行一下我们脱壳后的文件,发现脱壳后的 crackme 并没有显示出来,说明我们需要对脱壳后的文件进行修复。

我们打开 “ImportRec” 这个工具,在进程列表中选中 crackme 的进程,在 OEP 处填入 11cb。我们脱壳后的入口虚拟地址(VA)为 004011cb,但是这里填入的是一个相对虚拟地址(RVA)。点击 “自动查找IAT”,发现 OEP 下面的RVA变成了“3138”,大小是“20”,这次我们点击“获取输入表”,共找到了 1 个导入的 DLL 和 6 个导入函数。我们点击“修复转储文件”,在出现的保存窗口中我们选择 “dump.exe”,也就是刚才脱壳后的文件。ImportREC 为我们生成了一个 dump_.exe 的文件,我们运行这个文件,依然没有显示处 crackme 的界面。

这次我们回到 OD 中,运行 crackme,待 crackme 窗口显示后,我们对 API 函数进行下断,bp GetDlgItemTextA。然后在 crackme 中的 name 处和 serial 处随便填入内容,点击 check 按钮。当我们点击 check 按钮后,OD 中断在了 GetDlgItemTextA 的代码处,代码如下:

77D6B05E U>  8BFF                mov edi,edi
77D6B060     55                  push ebp
77D6B061     8BEC                mov ebp,esp
77D6B063     FF75 0C             push dword ptr ss:[ebp+C]
77D6B066     FF75 08             push dword ptr ss:[ebp+8]
77D6B069     E8 0093FBFF         call USER32.GetDlgItem

我们按下 CTRL+F9 回到调用 GetDlgItemTextA 的下一行代码,代码如下所示:

00401533     50                  push eax
00401534     6A 65               push 65
00401536     FF75 08             push dword ptr ss:[ebp+8]
00401539     E8 FA010000         call crackme6.00401738                            ; jmp 到
0040153E     89C3                mov ebx,eax
00401540     09DB                or ebx,ebx
00401542     75 04               jnz short crackme6.00401548
00401544     31C0                xor eax,eax

我们返回的地址是 0040153e,调用 GetDlgItemTextA 的地址也就是 00401539,我们选中 00401539 的反汇编指令,按后按下回车,代码的位置在 00401738 处,代码如下所示:

00401732     90                  nop
00401733     90                  nop
00401734     0000                add byte ptr ds:[eax],al
00401736     0000                add byte ptr ds:[eax],al
00401738   - FF25 20314000       jmp dword ptr ds:[403120]              ; USER32.GetDlgItemTextA
0040173E     90                  nop
0040173F     90                  nop

可以看到 00401738 处的 jmp 指令跳入了 403120 中保存的地址处(在该地址周围也有很多的 jmp 指令,这里应该是调用导入函数的跳转表),也就是说 403120 应该就是导入表的一项了,我们在 OD 的数据窗口中输入 403120,然后在数据窗口点击右键选择“长型”->“地址”,出现了 GetDlgItemTextA 的地址,如下所示:

00403118  77D24A4E  USER32.EndDialog
0040311C  77D3E577  USER32.DefDlgProcA
00403120  77D6B05E  USER32.GetDlgItemTextA
00403124  77D2D33E  USER32.LoadCursorA
00403128  77D2EA5E  USER32.RegisterClassA

看来 00403XXX 这里应该是导入表的地址,我们在数据窗口中往上找,直到来到 403100 地址处。我们再次回到 ImportREC 中,我们修改 RVA 中的值为 3100,大小为 1000,然后点击“获取输入表”。这次在“找到的输入表函数”中找到了很多的输入函数,但是有很多是无效的。我们点击“显示无效的”,在“找到的输入表函数”中点击右键,在弹出的菜单中选择“剪切指针”,这样就剩下了 3 个导入的 DLL 文件。我们点击“修复转储文件”,在选择 “dump.exe” 进行保存。

这次我们运行 dump_.exe 文件,可以看到我们脱壳后的 crackme 运行起来了。

我们较为详细的分析了对 ASPACK2.12 的脱壳过程,和脱壳后对导入表的修复过程。希望大家能够举一反三,从中学到更多的知识。

注:文章时很久以前写的,crackme 文件已经找不到了,自己用 Aspack 压缩后测试即可。