-
-
[原创]新手补给之脱壳1——DBPE
-
发表于: 2009-5-21 02:00 6240
-
【文章标题】: 新手补给之DBPE
【文章作者】: rocktx
【软件名称】: 雪狐提醒簿 v3.0beta1
【软件大小】: 2.74MB
【下载地址】: 狗狗一下
【加壳方式】: DBPE 2.33
【编写语言】: Delphi
【使用工具】: Ollydbg、LordPE、ImportRec
【操作平台】: Win2K/XP SP2
【软件介绍】: 老版本就不作介绍了
【作者声明】: 只为学习,失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
一直没碰到过幻影的壳,今天终于让我给逮住了,也算是补补课吧,新手万一也碰到了,可以拿来主义一下!
高手们只管超光速飞过...
幻影DBPE v2.33 加壳程序的入口特征:
008C9000 R> /EB 20 jmp short RemindBo.008C9022
008C9002 |0000 add byte ptr ds:[eax],al
008C9004 |40 inc eax
008C9005 |0000 add byte ptr ds:[eax],al
008C9007 |0040 00 add byte ptr ds:[eax],al
008C900A |0000 add byte ptr ds:[eax],al
008C900C |0000 add byte ptr ds:[eax],al
008C900E |0000 add byte ptr ds:[eax],al
008C9010 |0090 4C000B00 add byte ptr ds:[eax+B004C],dl
008C9016 |0000 add byte ptr ds:[eax],al
008C9018 |0230 add dh,byte ptr ds:[eax]
008C901A |0000 add byte ptr ds:[eax],al
008C901C |0000 add byte ptr ds:[eax],al
008C901E |0000 add byte ptr ds:[eax],al
008C9020 |0000 add byte ptr ds:[eax],al
008C9022 \9C pushfd
008C9023 55 push ebp
008C9024 57 push edi
008C9025 56 push esi
008C9026 52 push edx
008C9027 51 push ecx
008C9028 53 push ebx
008C9029 9C pushfd
008C902A E8 00000000 call RemindBo.008C902F
往下F7单步跟踪会发现两个函数调用 VirtualAlloc、VirtualFree;
如果用断点 bp VirtualAlloc 跟踪,运行两次就挂了,这是DBPE壳的AntiDebug在作祟;
主要是通过修改IDT(Interrupt Descriptor Table 中断向量表)来阻止调试,表现为:
1、OD重新载入加壳程序后,无法停在入口,程序直接跑飞;
2、严重一点,直接重启计算机;
3、再严重一点,直接蓝屏;
4、再再严重一点,首先(同时省去286字...)
对抗DBPE的步骤(前提是曾经运行过幻影加壳的程序):
1、用Trial-Reset将DBPE的注册表信息清除(一般没什么东西);
2、加壳程序运行后,会在c:\windows\system32生成cdcd.sys文件,并注册一个叫做Cdsys的服务;
这里要用Wsyscheck、Syscheck2等高级安全工具,停止并删除该服务以及cdcd.sys文件;
3、如果软件过期,可能会影响脱壳,所以最好先修改系统时间;
4、重启计算机,用Xidt.exe保存当前的idt;
5、每次调试DBPE加壳的程序时,如果出错(也可能不明显),就要用Xidt.exe恢复保存的idt;
废话不多,开始脱壳:
1、寻找OEP
下断点 he VirtualAlloc,Shift+F9三次,查看堆栈:
0013FF94 008E6234 /CALL 到 VirtualAlloc 来自 RemindBo.008E622E
0013FF98 7FF60000 |Address = 7FF60000 ;注意这个地址
0013FF9C 0003078D |Size = 3078D (198541.)
0013FFA0 00101000 |AllocationType = MEM_COMMIT|MEM_TOP_DOWN
0013FFA4 00000040 \Protect = PAGE_EXECUTE_READWRITE
DBPE壳代码的地址一般在7F打头的高位区段,这里申请的是7FF60000;
然后数据窗口跟随寄存器窗口中ESP的地址,下WORD硬件访问断点,Shift+F9两次后,来到壳代码领空:
7FF7D504 83C4 04 add esp,4
7FF7D507 EB 02 jmp short 7FF7D50B
7FF7D509 99 cdq
7FF7D50A EB FF jmp short 7FF7D50B
7FF7D50C 0C 24 or al,24
7FF7D50E 71 01 jno short 7FF7D511
7FF7D510 E8 79E07A01 call 8172B58E
7FF7D515 ^ 75 83 jnz short 7FF7D49A
查找命令jmp eax,发现有两个,选择当前地址以后的,来到
7FF8AACB 6A 00 push 0
7FF8AACD FF96 EA664300 call dword ptr ds:[esi+4366EA]
7FF8AAD3 61 popad
7FF8AAD4 58 pop eax ;OEP地址pop到eax
7FF8AAD5 83F8 FF cmp eax,-1
7FF8AAD8 75 05 jnz short 7FF8AADF
7FF8AADA 33C0 xor eax,eax
7FF8AADC C2 0C00 retn 0C
7FF8AADF FFE0 jmp eax ;这里跳到OEP
在jmp eax 处下内存访问断点,F9运行后来到OEP:
00693770 55 push ebp
00693771 8BEC mov ebp,esp
00693773 83C4 DC add esp,-24
00693776 33C0 xor eax,eax
00693778 8945 DC mov dword ptr ss:[ebp-24],eax
0069377B B8 B02D6900 mov eax,RemindBo.00692DB0
00693780 E8 AB41D7FF call RemindBo.00407930
00693785 33C0 xor eax,eax
00693787 55 push ebp
00693788 68 07396900 push RemindBo.00693907
0069378D 64:FF30 push dword ptr fs:[eax]
00693790 64:8920 mov dword ptr fs:[eax],esp
2、处理IAT
右键-查找-所有模块间的调用,发现有很多IAT跳转跑到壳里去了:
0040143C - FF25 49E0F87F jmp dword ptr ds:[7FF8E049]
00401442 8BC0 mov eax,eax
00401444 - FF25 4DE0F87F jmp dword ptr ds:[7FF8E04D]
0040144A 8BC0 mov eax,eax
0040144C - FF25 51E0F87F jmp dword ptr ds:[7FF8E051]
00401452 8BC0 mov eax,eax
00401454 - FF25 55E0F87F jmp dword ptr ds:[7FF8E055]
0040145A 8BC0 mov eax,eax
0040145C - FF25 59E0F87F jmp dword ptr ds:[7FF8E059]
00401462 8BC0 mov eax,eax
00401464 - FF25 5DE0F87F jmp dword ptr ds:[7FF8E05D]
0040146A 8BC0 mov eax,eax
0040146C - FF25 61E0F87F jmp dword ptr ds:[7FF8E061]
当然也有一部分IAT没有被修改
004087DC - FF25 18686B00 jmp dword ptr ds:[6B6818]
004087E2 8BC0 mov eax,eax
004087E4 - FF25 14686B00 jmp dword ptr ds:[6B6814]
004087EA 8BC0 mov eax,eax
004087EC - FF25 10686B00 jmp dword ptr ds:[6B6810]
004087F2 8BC0 mov eax,eax
004087F4 - FF25 0C686B00 jmp dword ptr ds:[6B680C]
004087FA 8BC0 mov eax,eax
004087FC - FF25 08686B00 jmp dword ptr ds:[6B6808]
00408802 8BC0 mov eax,eax
00408804 - FF25 04686B00 jmp dword ptr ds:[6B6804]
0040880A 8BC0 mov eax,eax
0040880C - FF25 00686B00 jmp dword ptr ds:[6B6800]
可以用patch代码修复,但比较麻烦;
程序中idata的区段是006B6000,查看发现:
006B636C 77DDEAF4 絷輜 advapi32.RegCreateKeyExA
006B6370 77DD6BF0 餶輜 advapi32.RegCloseKey
006B6374 77DD7753 Sw輜 advapi32.OpenProcessToken
006B6378 77DFD11B 堰w advapi32.LookupPrivilegeValueA
006B637C 77DFC534 4胚w advapi32.AdjustTokenPrivileges
006B6380 00000000 ....
006B6384 7FF87F15 ? ASCII "h6"
006B6388 7FF87F20 ? ASCII "h7"
006B638C 7FF87F2B +? ASCII "h8"
006B6390 7FF87F36 6? ASCII "h9"
006B6394 7FF87F41 A? ASCII "h:"
006B6398 7FF87F4C L? ASCII "h;"
006B639C 7FF87F57 W? ASCII "h<"
这下知道该怎么办了,关闭OD(不想出意外的话),然后用Xidt.exe写入之前保存的idt,再用OD载入程序;
数据窗口跟随地址:006B6390,下内存访问断点后运行,停在
7FF7EBE4 66:3103 xor word ptr ds:[ebx],ax ;停在这里
7FF7EBE7 7A 03 jpe short 7FF7EBEC
7FF7EBE9 7B 01 jpo short 7FF7EBEC
7FF7EBEB 75 66 jnz short 7FF7EC53
7FF7EBED 48 dec eax
7FF7EBEE 9C pushfd
7FF7EBEF 6A 10 push 10
7FF7EBF1 73 0B jnb short 7FF7EBFE
7FF7EBF3 EB 02 jmp short 7FF7EBF7
7FF7EBF5 C151 E8 06 rcl dword ptr ds:[ecx-18],6
清除内存断点,用花指令去除器插件去掉花指令,效果如下
7FF7EBE4 66:3103 xor word ptr ds:[ebx],ax
7FF7EBE7 90 nop
7FF7EBE8 90 nop
7FF7EBE9 90 nop
7FF7EBEA 90 nop
7FF7EBEB 90 nop
7FF7EBEC 66:48 dec ax
7FF7EBEE 90 nop
7FF7EBEF 90 nop
7FF7EBF0 90 nop
7FF7EBF1 90 nop
往下找popad指令
7FF7F085 68 00800000 push 8000
7FF7F08A 6A 00 push 0
7FF7F08C 50 push eax
7FF7F08D FF95 43C64200 call dword ptr ss:[ebp+42C643] ;这个是VirtualFree
7FF7F093 90 nop
7FF7F094 90 nop
7FF7F095 90 nop
7FF7F096 90 nop
7FF7F097 90 nop
7FF7F098 90 nop
7FF7F099 90 nop
7FF7F09A 90 nop
7FF7F09B 90 nop
7FF7F09C 90 nop
7FF7F09D 61 popad ;F4到这里
往下有个pushad指令
7FF7F0CE 60 pushad
7FF7F0CF 90 nop
7FF7F0D0 90 nop
7FF7F0D1 90 nop
7FF7F0D2 90 nop
7FF7F0D3 90 nop
7FF7F0D4 8B9D 32CC4200 mov ebx,dword ptr ss:[ebp+42CC32]
继续往下找到popad指令
7FF7F166 50 push eax
7FF7F167 6A 04 push 4
7FF7F169 51 push ecx
7FF7F16A 53 push ebx
7FF7F16B FF95 53C64200 call dword ptr ss:[ebp+42C653] ;这个是VirtualProtect
7FF7F171 90 nop
7FF7F172 90 nop
7FF7F173 90 nop
7FF7F174 90 nop
7FF7F175 90 nop
7FF7F176 61 popad ;F4到这里
继续往下有个jmp回跳
7FF7F1D5 90 nop
7FF7F1D6 90 nop
7FF7F1D7 90 nop
7FF7F1D8 90 nop
7FF7F1D9 ^ E9 BBF8FFFF jmp 7FF7EA99
继续往下找到
7FF7F270 90 nop
7FF7F271 E8 F40F0000 call 7FF8026A ;IAT解密call,F7跟进
7FF7F276 90 nop
7FF7F277 90 nop
7FF7F278 90 nop
7FF7F279 90 nop
7FF7F27A 90 nop
7FF7F27B 8D9D 90CB4200 lea ebx,dword ptr ss:[ebp+42CB90]
继续去除花指令,来到
7FF802B2 FF95 47C64200 call dword ptr ss:[ebp+42C647] ; kernel32.GetCurrentProcessId
7FF80448 03D3 add edx,ebx
7FF8044A ^ E2 DF loopd short 7FF8042B ;loop循环
7FF804BB 0385 32CC4200 add eax,dword ptr ss:[ebp+42CC32] ;执行后出现DLL模块名称kernel32.dll
7FF8068B 50 push eax
7FF8068C FF95 1A6F4300 call dword ptr ss:[ebp+436F1A] ; kernel32.LoadLibraryA
7FF806D1 8985 ABC34200 mov dword ptr ss:[ebp+42C3AB],eax ; kernel32.7C800000
7FF807C1 03D3 add edx,ebx
7FF807C3 ^ E2 DF loopd short 7FF807A4 ;又一个loop循环
7FF808E2 03D3 add edx,ebx
7FF808E4 ^ E2 DF loopd short 7FF808C5 ;继续loop
7FF80AB2 50 push eax
7FF80AB3 FFB5 ABC34200 push dword ptr ss:[ebp+42C3AB]
7FF80AB9 FF95 1E6F4300 call dword ptr ss:[ebp+436F1E] ; kernel32.GetProcAddress
上面有很多函数调用,可以作为断点跟踪的依据,仅供参考;
往下到关键修改
第一处:
7FF80F5E 39BD 89CE4200 cmp dword ptr ss:[ebp+42CE89],edi ; RemindBo.006B6244
7FF80F64 76 10 jbe short 7FF80F76
7FF80F66 90 nop
7FF80F67 90 nop
7FF80F68 90 nop
7FF80F69 90 nop
7FF80F6A 90 nop
7FF80F6B 89BD 89CE4200 mov dword ptr ss:[ebp+42CE89],edi ;nop掉
第二处:
7FF80F8D 39BD 85CE4200 cmp dword ptr ss:[ebp+42CE85],edi ; RemindBo.006B6244
7FF80F93 73 34 jnb short 7FF80FC9
......
7FF80FAC 89BD 85CE4200 mov dword ptr ss:[ebp+42CE85],edi ;nop掉
第三处:
7FF80FEA 890F mov dword ptr ds:[edi],ecx ;ecx改成eax,因为eax中是IAT函数指针
7FF80FEC 90 nop
7FF80FED 90 nop
7FF80FEE 90 nop
7FF80FEF 90 nop
7FF80FF0 90 nop
7FF80FF1 83C6 04 add esi,4
7FF80FF4 90 nop
7FF80FF5 90 nop
7FF80FF6 90 nop
7FF80FF7 90 nop
7FF80FF8 90 nop
7FF80FF9 83C7 04 add edi,4
7FF81011 90 nop
7FF81012 90 nop
7FF81013 ^ E9 71F9FFFF jmp 7FF80989 ;解密循环
下面有个popad指令,F4到那里后,恢复上面修改的代码,搜索命令jmp eax,直达OEP即可【切记勿下F2断点】;
3、修复跳转
IAT搞定了,可代码中有很多IAT地址出错了,类似:
00407BE4 FF25 7C636B80 jmp dword ptr ds:[806B637C]
00407BEA 8BC0 mov eax,eax
00407BEC FF25 78636B80 jmp dword ptr ds:[806B6378]
00407BF2 8BC0 mov eax,eax
00407BF4 FF25 74636B80 jmp dword ptr ds:[806B6374]
00407BFA 8BC0 mov eax,eax
00407BFC FF25 70636B80 jmp dword ptr ds:[806B6370]
00407C02 8BC0 mov eax,eax
00407C04 FF25 6C636B80 jmp dword ptr ds:[806B636C]
00407C0A 8BC0 mov eax,eax
00407C0C FF25 68636B80 jmp dword ptr ds:[806B6368]
懒得跟踪原因,其实很简单,把80改成00即可,或者找个空白处,用下面的代码修复:
00E80000 BA 00104000 mov edx,401000 ;code段起始地址
00E80005 66:813A FF25 cmp word ptr ds:[edx],25FF ;搜索jmp指令
00E8000A 75 1C jnz short 00E80028
00E8000C 8B42 01 mov eax,dword ptr ds:[edx+1]
00E8000F 3D 2500606B cmp eax,6B600025 ;idata段起始地址,左移两位后,补25
00E80014 7C 12 jl short 00E80028
00E80016 3D 2500A06B cmp eax,6BA00025 ;idata段下一区段的起始地址
00E8001B 77 0B ja short 00E80028
00E8001D 807A 05 00 cmp byte ptr ds:[edx+5],0 ;比较IAT地址第一个字节是否为0
00E80021 74 05 je short 00E80028
00E80023 C642 05 00 mov byte ptr ds:[edx+5],0 ;如果不是就赋0修正
00E80027 41 inc ecx ;计数器,看有多少个地址被修正了
00E80028 42 inc edx
00E80029 81FA 00406900 cmp edx,694000 ;data段起始地址
00E8002F ^ 72 D4 jb short 00E80005
00E80031 - E9 3A3781FF jmp RemindBo.00693770 ;跳到OEP
二进制:
BA 00 10 40 00 66 81 3A FF 25 75 1C 8B 42 01 3D 25 00 60 6B 7C 12 3D 25 00 A0 6B 77 0B 80 7A 05
00 74 05 C6 42 05 00 41 42 81 FA 00 40 69 00 72 D4 E9 3A 37 81 FF
写完后在00E80000处新建EIP,一定记得要在OEP处F2下断,跑飞就不爽了;
4、DUMP修复
Dump时注意修正一下镜像大小,ImportRec中填入OEP:00293770,IAT的RVA:002B6244,大小:1000;
获取IAT,剪切掉无效指针,修复后程序运行正常;
系统时间调回来以后,程序提示过期,用bp GetLocalTime跟踪一下,修改关键跳即可,具体从略;
总结:
没什么可总结的,互相学习,茁壮成长;
步骤1和2借鉴了fly前辈5年前的方法,再次感激涕零!!!
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年05月20日 11:48:01
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]GLCD Font Creator v1.0 算法注册机 5985
- [原创]Photo-Brush v5.3 算法注册机 7499
- [原创]某字体软件的破解过程 5561
- [下载]山寨脱壳机一例 5006