文章作者:regkiller
【作者QQ】14403147
【使用工具】OllyDBG汉化第二版,LordPE,ImportRECv1.6F,PEiDv0.94,PEToolsv1.5.700
【脱壳平台】WinXPSP2
【脱壳目标】Armadillov4.40加过壳的EdrLib.dll文件
【保护选项】Standardprotectiononly仅仅标准保护(单进程)
【加壳方式】Armadillov4.40
--------------------------------------------------------------------------------
【脱壳内容】
一、准备工作
1侦壳:用PEiD查壳Armadillo2.51-3.xxDLLStub->SiliconRealmsToolworks
这里如何判断Arm的版本呢?记得FLY大狭说过ArmadilloV4.0新增的反跟踪手段:
OllyDbg在处理调式包含格式串的消息时存在问题,被跟踪的应用程序可以使OllyDbg崩溃,或可能以进程权限执行任意指令。OutputDebugString函数可发送字符串到调试器上,然后OllyDbg会在底端显示相关状态消息,但是如果包含格式串消息,就可能使OllyDbg崩溃。Armadillo以前的版本没有此种Anti,自V4.0始才有。
有他这句话我们就可以做如下判断了:
OD载入
下断点HEOutputDebugStringA
Shift+F9运行,中断下来。看堆栈:
0006EA9800B8580F/CALL到OutputDebugStringA来自00B85809
0006EA9C0006F410\String="%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
出现这个说明这个DLL是经过Armadillo4.X压缩过
2判断进程:DLL文件加壳应该是不可以双进程,所以这里是单进程方式。
二、脱壳
1寻找MagicJump
先用LordPE看看加壳后的DLL信息:基址=00400000,入口点=0003FE97
设置Ollydbg忽略所有的异常选项。老规矩:用IsDebug1.4插件去掉Ollydbg的调试器标志
清除断点后OD重新载入
008AFE97>/$55PUSHEBP;停在这里
008AFE98|.8BECMOVEBP,ESP
008AFE9A|.53PUSHEBX
008AFE9B|.8B5D08MOVEBX,DWORDPTRSS:[EBP+8]
008AFE9E|.56PUSHESI
下断点BPGetModuleHandleA+5,Shift+F9运行中断后,注意看堆栈:
这里用BPAPI+5是为了多过壳检查是否下过API断点,相关资料看雪论坛上面可以找到。
0006E458/0006E574
0006E45C|74683BEE返回到74683BEE来自kernel32.GetModuleHandleA
0006E460|0006E464ASCII"D:\WINDOWS\system32\ntdll.dll"
0006E460/0006E57C
0006E464|74683BEE返回到74683BEE来自kernel32.GetModuleHandleA
0006E468|0006E46CASCII"D:\WINDOWS\system32\imm32.dll"
0006E3AC/0006E4C8
0006E3B0|74683BEE返回到74683BEE来自kernel32.GetModuleHandleA
0006E3B4|0006E3B8ASCII"D:\WINDOWS\system32\KERNEL32"
0006E504/0006E620
0006E508|7365D4A4返回到msctfime.7365D4A4来自kernel32.GetModuleHandleA
0006E50C|0006E510ASCII"D:\WINDOWS\system32\ntdll.dll"
0006ED60/0006ED7C
0006ED64|77F45BD8返回到77F45BD8来自kernel32.GetModuleHandleA
0006ED68|77F4501CASCII"KERNEL32.DLL"
00069364/0006EAAC
00069368|00B86DF3返回到00B86DF3来自kernel32.GetModuleHandleA
0006936C|00B9BC1CASCII"kernel32.dll"
00069370|00B9CEC4ASCII"VirtualAlloc"
00069364/0006EAAC
00069368|00B86E10返回到00B86E10来自kernel32.GetModuleHandleA
0006936C|00B9BC1CASCII"kernel32.dll"
00069370|00B9CEB8ASCII"VirtualFree"
000690C8/00069368
000690CC|00B75CE1返回到00B75CE1来自kernel32.GetModuleHandleA
000690D0|0006921CASCII"kernel32.dll";★注意!在这里清除断点后Alt+F9返回程序
这里说下我判断返回的经验,我的经验是一般出现下面这两句就快到返回点了
00069364/0006EAAC
00069368|00B86DF3返回到00B86DF3来自kernel32.GetModuleHandleA
0006936C|00B9BC1CASCII"kernel32.dll"
00069370|00B9CEC4ASCII"VirtualAlloc";★注意这句
00069364/0006EAAC
00069368|00B86E10返回到00B86E10来自kernel32.GetModuleHandleA
0006936C|00B9BC1CASCII"kernel32.dll"
00069370|00B9CEB8ASCII"VirtualFree";★注意这句
00B75CE18B0DAC40BA00MOVECX,DWORDPTRDS:[BA40AC];返回到这里
00B75CE789040EMOVDWORDPTRDS:[ESI+ECX],EAX
00B75CEAA1AC40BA00MOVEAX,DWORDPTRDS:[BA40AC]
00B75CEF391C06CMPDWORDPTRDS:[ESI+EAX],EBX
00B75CF27516JNZSHORT00B75D0A
00B75CF48D85B4FEFFFFLEAEAX,DWORDPTRSS:[EBP-14C]
00B75CFA50PUSHEAX
00B75CFBFF15BC62B900CALLDWORDPTRDS:[B962BC];kernel32.LoadLibraryA
00B75D018B0DAC40BA00MOVECX,DWORDPTRDS:[BA40AC]
00B75D0789040EMOVDWORDPTRDS:[ESI+ECX],EAX
00B75D0AA1AC40BA00MOVEAX,DWORDPTRDS:[BA40AC]
00B75D0F391C06CMPDWORDPTRDS:[ESI+EAX],EBX
00B75D120F842F010000JE00B75E47;MagicJump改JE为JMP避开IAT加密
00B75D1833C9XORECX,ECX
00B75D1A8B07MOVEAX,DWORDPTRDS:[EDI]
00B75D1C3918CMPDWORDPTRDS:[EAX],EBX
00B75D1E7406JESHORT00B75D26
00B75D2041INCECX
00B75D2183C00CADDEAX,0C
00B75D24^EBF6JMPSHORT00B75D1C
把00B75D12这句的JE00B75E47改成JMP00B75E47
2获得重定位信息
下断点bpGetTickCount,Shift+F9运行中断后,注意看堆栈:
0006937000B8C009/CALL到GetTickCount来自00B8C003
0006937000B8C3C8/CALL到GetTickCount来自00B8C3C2;★注意!在这里清除断点后Alt+F9返回程序
00B8C3C82B85A4D4FFFFSUBEAX,DWORDPTRSS:[EBP-2B5C];返回到这里
00B8C3CE8B8DA8D4FFFFMOVECX,DWORDPTRSS:[EBP-2B58]
00B8C3D46BC932IMULECX,ECX,32
00B8C3D781C1D0070000ADDECX,7D0
00B8C3DD3BC1CMPEAX,ECX
00B8C3DF7607JBESHORT00B8C3E8
00B8C3E1C68534D9FFFF0>MOVBYTEPTRSS:[EBP-26CC],1
00B8C3E883BDE4D7FFFF0>CMPDWORDPTRSS:[EBP-281C],0
00B8C3EF0F858A000000JNZ00B8C47F
在CPU窗口按Ctrl+S查找如下代码
PUSHEAX
XCHGCX,CX
POPEAX
STC
找到代码如下:
00B8CF5450PUSHEAX
00B8CF5566:87C9XCHGCX,CX
00B8CF5858POPEAX
00B8CF59F9STC
我们在00B8CF54行按F2设置断点,然后F9执行后取消断点到这里后窗口里出现了红色代码
00B8CF59C705E0C0B9006>MOVDWORDPTRDS:[B9C0E0],0B9CB60;★从这里开始出现红色代码
00B8CF63A1E49FBA00MOVEAX,DWORDPTRDS:[BA9FE4]
00B8CF688B00MOVEAX,DWORDPTRDS:[EAX];★这个00006000就是重定位表的RVA
00B8CF6A89853CD9FFFFMOVDWORDPTRSS:[EBP-26C4],EAX
00B8CF70A1E49FBA00MOVEAX,DWORDPTRDS:[BA9FE4]
00B8CF7583C004ADDEAX,4
00B8CF78A3E49FBA00MOVDWORDPTRDS:[BA9FE4],EAX
00B8CF7DA1E49FBA00MOVEAX,DWORDPTRDS:[BA9FE4]
00B8CF828B00MOVEAX,DWORDPTRDS:[EAX];★这个000003B0就是重定位表的大小
00B8CF84898578D9FFFFMOVDWORDPTRSS:[EBP-2688],EAX
00B8CF8AA1E49FBA00MOVEAX,DWORDPTRDS:[BA9FE4]
00B8CF8F83C004ADDEAX,4
00B8CF92A3E49FBA00MOVDWORDPTRDS:[BA9FE4],EAX
00B8CF9783BD3CD9FFFF0>CMPDWORDPTRSS:[EBP-26C4],0;★重定位表的RVA为0吗?
00B8CF9E746FJESHORT00B8D00F;★为0则重定位处理
00B8CFA083BD78D9FFFF0>CMPDWORDPTRSS:[EBP-2688],0;★重定位表的大小为0吗?
00B8CFA77466JESHORT00B8D00F;★为0则重定位处理
00B8CFA98B85FCD7FFFFMOVEAX,DWORDPTRSS:[EBP-2804]
00B8CFAF8B8D0CD8FFFFMOVECX,DWORDPTRSS:[EBP-27F4]
00B8CFB53B4834CMPECX,DWORDPTRDS:[EAX+34]
00B8CFB87455JESHORT00B8D00F;★如与映像基址不符则重定位处理!
00B8CFBAFFB578D9FFFFPUSHDWORDPTRSS:[EBP-2688]
00B8CFC08B850CD8FFFFMOVEAX,DWORDPTRSS:[EBP-27F4]
00B8CFC603853CD9FFFFADDEAX,DWORDPTRSS:[EBP-26C4]
00B8CFCC50PUSHEAX
00B8CFCD8B85FCD7FFFFMOVEAX,DWORDPTRSS:[EBP-2804]
00B8CFD3FF7034PUSHDWORDPTRDS:[EAX+34]
00B8CFD6FFB50CD8FFFFPUSHDWORDPTRSS:[EBP-27F4]
00B8CFDCE83C150000CALL00B8E51D;★重定位处理CALL
00B8CFE183C410ADDESP,10
00B8CFE40FB6C0MOVZXEAX,AL
00B8CFE785C0TESTEAX,EAX
00B8CFE97524JNZSHORT00B8D00F
00B8CFEB8B4508MOVEAX,DWORDPTRSS:[EBP+8]
00B8CFEE8B00MOVEAX,DWORDPTRDS:[EAX]
00B8CFF0C70007000000MOVDWORDPTRDS:[EAX],7
00B8CFF66850CBB900PUSH0B9CB50;ASCII"LocationCPG"
00B8CFFB8B4508MOVEAX,DWORDPTRSS:[EBP+8]
00B8CFFEFF7004PUSHDWORDPTRDS:[EAX+4]
00B8D001E824800000CALL00B9502A;JMP到msvcrt.strcpy
00B8D00659POPECX
00B8D00759POPECX
00B8D00833C0XOREAX,EAX
00B8D00AE9A5070000JMP00B8D7B4
我们把00B8CFB8的JE00B8D00F改成JMP00B8D00F跳过重定位处理,这样就不需要修改DLL的基址了,否则修改基址为OEP处看到的基址,如这里为00870000
现在我们Alt+M打开内存查看窗口,看到这个DLL的给个区段
0087000000001000EdrLibPE文件头ImagRRWE
0087100000003000EdrLib.textImagRRWE
0087400000001000EdrLib.rdata输出表ImagRRWE
0087500000001000EdrLib.data数据ImagRRWE
0087600000001000EdrLib.relocImagRRWE
0087700000040000EdrLib.text1代码ImagRRWE
008B700000010000EdrLib.adata代码ImagRRWE
008C700000010000EdrLib.data1ImagRRWE
008D700000010000EdrLib.reloc1重定位ImagRRWE
008E700000030000EdrLib.pdata输入表ImagRRWE
在0087100000003000EdrLib.text★这里设置内存访问断点F9运行,中断在OEP
008711C955PUSHEBP;等待已久的OEP终于出现了
008711CA8BECMOVEBP,ESP
008711CC53PUSHEBX
008711CD8B5D08MOVEBX,DWORDPTRSS:[EBP+8]
008711D056PUSHESI
008711D18B750CMOVESI,DWORDPTRSS:[EBP+C]
008711D457PUSHEDI
008711D58B7D10MOVEDI,DWORDPTRSS:[EBP+10]
008711D885F6TESTESI,ESI
008711DA7509JNZSHORTEdrLib.008711E5
用LordPE选中Ollydbg的loaddll.exe的进程,在下面的列表里选择EdrLib.dll,然后完整脱壳,得到dumped.dll。
我们用LordPE打开dumped.dll到目录中修改重定位:RVA=6000大小=3B0然后保存修改
3搞定输入表
因为已经修改了MagicJump,所以现在可以得到完整的输入表。随便从程序找个API调用:
00871383FF1524404000CALLDWORDPTRDS:[404024]
由于我们刚才已经跳过了重定位处理所以这里是未经过重定位处理的地址
我们在命令行里输入D874024上下看到许多函数地址,很明显的可以找到IAT开始和结束的地址:
00874024A2CA817C161E807C0DE0807C3797807C...|...|...|7..|
00874034F59B807C0F2B817C5334817C5097807C...|.+.|S4.|P..|
00874044CFC6807CA92C817C6910817CEE1E807C...|?.|i..|...|
008740548A18937C57B3807C3FDC817CE0C6807C...|W..|?..|...|
我们在数据窗口中用长型地址的方式显示数据将看到许多函数
008740247C81CAA2kernel32.ExitProcess
008740287C801E16kernel32.TerminateProcess
0087402C7C80E00Dkernel32.GetCurrentProcess
008740307C809737kernel32.GetCurrentThreadId
008740347C809BF5kernel32.TlsSetValue
008740387C812B0Fkernel32.TlsAlloc
0087403C7C813453kernel32.TlsFree
008740407C809750kernel32.TlsGetValue
008740447C80C6CFkernel32.SetHandleCount
008740487C812CA9kernel32.GetStdHandle
0087404C7C811069kernel32.GetFileType
008740507C801EEEkernel32.GetStartupInfoA
现在上下滚动窗口就可以很容易的找到IAT的开始和结束的地址
开始地址=00874000
结束地址=008740CB
但是现在直接用ImportREC选取EdrLib.dll,填入RVA=00004000、大小=CB,却提示“不能载入当前进程相关数据信息!”
看看ImportREC的日志:
映像基地址:00400000大小:00097000
->>模块被选择!:e:\试炼场\脱壳学习\dll脱壳\armadillo\edrlib.dll\edrlib.dll
原来ImportREC显示EdrLib.dll的基址还是00400000,呵呵
如果填入RVA=00474000、大小=CB,可以得到输入表,却无法完成修复抓取文件。为何?都是重定位惹的祸啦。
于是利用FLY大狭的移花接木的办法:再打开一个Ollydbg,载入Win98的NotePad.EXE,然后把00874000-008740CB的数据复制、粘贴进NotePad.EXE的00404000-004040CB,然后用ImportREC选择NotePad.EXE进程,填入RVA=00004000、大小=CB,得到输入表,CUT掉垃圾指针,改OEP=000011C9,就可以FixDump啦!
三善后工作
1优化
用LordPE删除dumped_.dll的text1、adata、data1、reloc1、pdata共5个区段,然后去掉“转存修正”和“清除重定位表”选项,重建PE简单优化一下脱壳后的文件,672K->16.9K,比加壳前的原文件还小了。
2修复查壳显示错误
脱壳后的DLL用PEiD看依旧显示“Armadillo2.51-3.xxDLLStub->SiliconRealmsToolworks”,用FI看显示“MSVC++v6.0{DLL}”。用PETools打开dumped_.dll在可选头部中修改主连接器版本为06副连接器版本00,现在再用PEiD查看显示为:MicrosoftVisualC++6.0DLL
3测试脱壳文件
把dumped_.dll名字改成EdrLib.dll然后运行EdrTest.exe看是否正确调用脱壳后的DLL文件
--------------------------------------------------------------------------------
【脱壳总结】
Armadillov4.40这个版本的获得重定位信息的位置与以前的版本有点出入,我的获得方法是在修改了MagicJump后对00870000段设置内存访问断点中断1次后一步步手动跟踪后才发现用bpGetTickCount这个断点断2次后返回并F8单步向下走到下面这个特征码
PUSHEAX
XCHGCX,CX
POPEAX
STC
这里教大家一个判断重定位位置和大小的方法。不知道是否通用。
我们可以把DUMP后的文件用LoadPE打开。然后在区段里查看reloc的VOffset来确定重定位的RAV,然后在目录->重定位里点"H"按钮。把从6000开始到后面全是00000000的这段全部选中后看状态行提示的大小就可以了。
--------------------------------------------------------------------------------
【版权声明】本文纯属技术交流,转载请注明作者并保持文章的完整,谢谢!