前言
在练习脱壳.
这个壳特点:
* 在OEP处少代码, 需要自己在OEP处补齐. 少的代码在OEP之前都能看到. 这是所谓的偷代码.
* 在OEP处脱壳后, ImpRec找不到IAT. 需要自己搜索指令来找到IAT项.
记录
查壳
Detect It Easy => Borland Delphi(-)[-]
PEID => 什么都没找到 *
RDG => PECompact v1.66
查找OEP
用ESP定律
004C3550 50 push eax
004C3551 68 30ED4800 push 0048ED30
004C3556 C2 0400 retn 4
0048ED30 55 push ebp
0048ED31 90 nop
0048ED32 8BEC mov ebp, esp
0048ED34 90 nop
0048ED35 B9 07000000 mov ecx, 7
0048ED3A 90 nop
0048ED3B 6A 00 push 0
0048ED3D 6A 00 push 0
0048ED3F 90 nop
0048ED40 90 nop
0048ED41 49 dec ecx
0048ED42 ^ E9 8EFCFFFF jmp 0048E9D5
0048E9C7 0000 add byte ptr [eax], al
0048E9C9 0000 add byte ptr [eax], al
0048E9CB 0000 add byte ptr [eax], al
0048E9CD 0000 add byte ptr [eax], al
0048E9CF 006A 00 add byte ptr [edx], ch
0048E9D2 6A 00 push 0
0048E9D4 49 dec ecx
0048E9D5 ^ 75 F9 jnz short 0048E9D0 ; 跳到这里来了, 如果这里作为OEP要将前面的代码补上
输入新OEP代码
Address Size Owner Section Contains Type Access Initial Mapped as
00400000 00001000 NfoViewe PE header Imag R RWE
00401000 000A2000 NfoViewe XtreaM code Imag R RWE
004A3000 00023000 NfoViewe .rsrc SFX,data,res Imag R RWE
004C6000 00001000 NfoViewe .rsrc imports Imag R RWE
0048xxxx在代码段(XtreaM)
004Cxxxx在其他段(.rsrc)
必须将004C3550开始的3句话搬到代码段
如果从0048E9C7作为OEP, 正好留了8个字节.
看看将前面欠的语句搬过来, 是否8个字节是否能放下.
试过了,放不下.
0048E9D5下面也放着代码没空隙.
0048ED30~0048ED42中间还空着5个字节.
004C3550 主要语句就是push eax, 那就将 004C3550的push eax搬到0048ED30.重新组织一下, 将多余的nop去掉, 空间就够了
重新运行程序, 当运行到0048ED30时, 直接将旧代码抹掉, 键入新代码, 然后脱壳.
将 0048ED30 作为OEP, 将0048ED30~0048ED42填充为NOP, 再输入下面的新代码
0048ED30 新的代码为:
push eax
push ebp
mov ebp, esp
mov ecx, 7
push 0
push 0
dec ecx
jmp 0048E9D5
新代码码好了
0048ED30 50 push eax ; 0048ed30 new OEP
0048ED31 55 push ebp
0048ED32 8BEC mov ebp, esp
0048ED34 B9 07000000 mov ecx, 7
0048ED39 6A 00 push 0
0048ED3B 6A 00 push 0
0048ED3D 49 dec ecx
0048ED3E ^ E9 92FCFFFF jmp 0048E9D5
0048ED43 90 nop
0048ED44 90 nop
0048ED45 90 nop
0048ED46 90 nop ; 原来的语句结尾, 可以看出空间足够.
脱壳
在0048ED30处, 用ollyDump脱2个版本(不勾选RebuildImport, 勾选RebuildImport)
直接运行脱壳后的2个版本,都是报错的.
修复IAT
ImpREC , 输入OEP = 0008ED30, Click “AutoSearch”.
---------------------------
Found something!
---------------------------
Found address which may be in the Original IAT. Try 'Get Import'.
(If it is not correct, try RVA: 00001000 Size:000A2000)
---------------------------
确定
---------------------------
RVA = 00092018
SIZE = 00000004
去看一下IAT. =>00492018, 都是0, 说明ImpREC没找到IAT.
手工查找IAT
调用API时, 一般都是 call xx
00402BF0 E8 17E6FFFF call 0040120C ; jmp to kernel32.CloseHandle
调用到的API处再跳到IAT表项内容
0040120C - FF25 0C324900 jmp dword ptr [49320C] ; kernel32.CloseHandle
代码段为00401000开始
从00401000开始, 2进制字符串搜索 FF25
搜到了IAT项
004011F9 . 54 49 6E 74 6>ascii "TInterfacedObjec"
00401209 . 74 ascii "t"
0040120A 8BC0 mov eax, eax
0040120C $- FF25 0C324900 jmp dword ptr [49320C] ; kernel32.CloseHandle
00401212 8BC0 mov eax, eax
00401214 $- FF25 08324900 jmp dword ptr [493208] ; kernel32.CreateFileA
0040121A 8BC0 mov eax, eax
0040121C $- FF25 04324900 jmp dword ptr [493204] ; kernel32.GetFileType
00401388 $- FF25 84314900 jmp dword ptr [493184] ; kernel32.LocalAlloc
0040138E 8BC0 mov eax, eax
00401390 $- FF25 80314900 jmp dword ptr [493180] ; kernel32.LocalFree
00401396 8BC0 mov eax, eax
00401398 $- FF25 7C314900 jmp dword ptr [49317C] ; kernel32.VirtualAlloc
0040139E 8BC0 mov eax, eax
004013A0 $- FF25 78314900 jmp dword ptr [493178] ; kernel32.VirtualFree
004013A6 8BC0 mov eax, eax
004013A8 $- FF25 74314900 jmp dword ptr [493174] ; kernel32.InitializeCriticalSection
004013AE 8BC0 mov eax, eax
004013B0 $- FF25 70314900 jmp dword ptr [493170] ; ntdll.RtlEnterCriticalSection
004013B6 8BC0 mov eax, eax
004013B8 $- FF25 6C314900 jmp dword ptr [49316C] ; ntdll.RtlLeaveCriticalSection
004013BE 8BC0 mov eax, eax
004013C0 $- FF25 68314900 jmp dword ptr [493168] ; ntdll.RtlDeleteCriticalSection
004036BC $- FF25 14324900 jmp dword ptr [493214] ; user32.GetKeyboardType
00481C74 $- FF25 50384900 jmp dword ptr [493850] ; UpdSyste.ShowUpdateDialog
用插件”Analyze This”分析一下.连续搜索FF25(CTRL+L), 看到最后一个CAll地址为004036BC
统计IAT范围
第一个Call为 jmp dword ptr [49320C], IAT地址49320C
最后一个Call为 jmp dword ptr [493850], IAT地址为493850
查看IAT地址, 已经找到正确的IAT了
0049320C 7C809BD7 kernel32.CloseHandle
00493210 00000000
00493214 77D311DB user32.GetKeyboardType
00493218 77D2C908 user32.LoadStringA
0049321C 77D507EA user32.MessageBoxA
00493220 77D2C8B0 user32.CharNextA
00493224 00000000
00493228 77DA7AAB advapi32.RegQueryValueExA
0049322C 77DA7842 advapi32.RegOpenKeyExA
00493230 77DA6C17 advapi32.RegCloseKey
00493234 00000000
00493238 770F4880 oleaut32.SysFreeString
0049323C 770FA3EC oleaut32.SysReAllocStringLen
向ImpREC填入IAT搜索参数
OEP = 0008ED30
IAT RVA = 0009320C // IAT开始地址为0049320C
IAT SIZE = 00000644 // 493850 - 49320C
click “Get Imports”
得到的IAT列表正确
IAT修复
点击”Fix Dump”, 对ollyDump脱壳出的2个版本进行IAT修复.
测试
测试时, 2个程序都报错:应用初始化失败
---------------------------
od_dump1_.exe - 应用程序错误
---------------------------
应用程序正常初始化(0xc000007b)失败。请单击“确定”,终止应用程序。
---------------------------
确定
---------------------------
重建PE
对ImpRec修复过的2个版本, 用LordPE重建PE, 设置导入表修复选项.
经过PE重建后, 2个版本中有一个正常运行了.
这个版本是用OllyDump不带引入表重建的版本.
备注
算IAT size时, 弄小了, 前面还有一些(取到一个IAT后, 在Memory窗口前后翻一下, 确定一下RVA和size, 范围弄大点都没关系, 可以在ImpREC中将无效的IAT剪掉).
调整IAT Info RVA and Size后, ImpREC fix.
运行修复完的版本,确实2个都不能运行.
但是经过PETools重建PE后, 2个都可以正常运行了.
不像IAT Info RVA and Size弄小时, PE重建后, 只有一个版本能正常运行.