用OllyDbg脱ASPR 1.3x壳 
================================================ 
作者：LaBBa 
翻译：softwarecracker  softwarecracker@163.com 
待脱壳软件：System Cleaner 4.89 Build 110 
下载地址：http://www.allerasoft.com/products/systemcleaner/ 


引文（Pre to this tut） 
================== 
ok listen up !这是我第三次写这一内容！！第一次的时候机子死机了，第二次的遇上时候停电！！ 
这篇文章将介绍如何用OllyDbg简易、快速脱ASPR 1.3x的壳并找到stolen bytes的方法。所有这些不需SoftIce、IceDump和the /tracex！ 
怎么脱？你会问。 
用OllyDbg！ 

所需工具： 
================ 
1. OllyDbg 1.09b2或更新 
2. ProcDump(G-rom)/Pe-edit(y0da) 
3. imprec 1.3 (MackT/UCF)(可从protools.cjb.net下载) 
4. HVIEW / Hex Editor 
Needed Tools 
================ 
1. OllyDbg 1.09b2 or newer 
2. ProcDump(G-rom)/Pe-edit(y0da) 
3. imprec 1.3 (MackT/UCF)(protools.cjb.net) 
4. HVIEW / Hex Editor（译者注：WinHEX也是不错的选择） 

脱壳步骤 
======================= 
1.找到OEP（译者注：入口点Entry Point）并抓取内存映像 
2.找到Stolen Bytes（Finding the Stolen Bytes） 
3.重建IAT（译者注：输入表Import Table） 
4.修正OEP（译者注：脱壳后，若不修正OEP为正确值，程序可能无法运行，其提示可能很怪，如内存不足等） 
5.收工 

==================================== 
第一步——找到OEP并抓取内存映像 
==================================== 
1.运行OllyDbg并载入脱壳对象（译者注：本文为System Cleaner），遇到提示均选YES（译者注：加壳文件的OEP等异常，故OllyDbg会提示设断点时注意） 

2.按F9，程序将被中断在如下地址： 

017E3414 3100 XOR DWORD PTR DS:[EAX],EAX <- 程序停在这里！ 
017E3416 EB 01 JMP SHORT 017E3419 
017E3418 68 648F0500 PUSH 58F64 

为什么OllyDbg会在这里中断？我们并没有设置断点？！ 

这是因为OllyDbg每进入一个新模块时都会停在模块开始处……这正是我们需要的！！ 
3.按Shift+F9以便OllyDbg进入下一模块。 
4.按26次Shift+F9将转到以下地址： 

017E2D7A 3100 XOR DWORD PTR DS:[EAX],EAX <-程序停在这里 
017E2D7C 64:8F05 00000000 POP DWORD PTR FS:[0] <-在这里设置一个断点 
017E2D83 58 POP EAX 
017E2D84 833D 806D7E01 00 CMP DWORD PTR DS:[17E6D80],0 
017E2D8B 74 14 JE SHORT 017E2DA1 
017E2D8D 6A 0C PUSH 0C 
017E2D8F B9 806D7E01 MOV ECX,17E6D80 
017E2D94 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] 
017E2D97 BA 04000000 MOV EDX,4 
017E2D9C E8 EFE0FFFF CALL 017E0E90 
017E2DA1 FF75 FC PUSH DWORD PTR SS:[EBP-4] 
017E2DA4 FF75 F8 PUSH DWORD PTR SS:[EBP-8] 
017E2DA7 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] 
017E2DAA 8338 00 CMP DWORD PTR DS:[EAX],0 
017E2DAD 74 02 JE SHORT 017E2DB1 
017E2DAF FF30 PUSH DWORD PTR DS:[EAX] 
017E2DB1 FF75 F0 PUSH DWORD PTR SS:[EBP-10] 
017E2DB4 FF75 EC PUSH DWORD PTR SS:[EBP-14] 
017E2DB7 C3 RETN 

如果再按一次Shift+F9，System Cleaner将开始运行，我们不这么做。 
5. 拖动滚动条，在以下地址单击： 

017E2D7C 64:8F05 00000000 POP DWORD PTR FS:[0] 

然后，按F2（设置断点。译者注：同W32DASM一样，也是按一次F2设置断点，在同一地址再按一次F2则清除断点） 
按Shift+F9，OllyDbg将停在该断点那里。 
6.按F8单步跟踪（不进入子程序）并执行RETN返回后程序运行到这里： 

017F4EC8 E9 080A0000 JMP 017F58D5 <- 程序运行到这里 

继续按F8单步跟踪，程序运行到这里： 

017F58D5 D3DE RCR ESI,CL <--程序停在这里 
017F58D7 B9 7D966271 MOV ECX,7162967D 
017F58DC 81C1 38F10A23 ADD ECX,230AF138 
017F58E2 D3EE SHR ESI,CL 
017F58E4 BA 9ECC7376 MOV EDX,7673CC9E 
017F58E9 81EA C56EFFD4 SUB EDX,D4FF6EC5 
017F58EF 81F2 B7104902 XOR EDX,24910B7 
017F58F5 C1CA 94 ROR EDX,94 
017F58F8 8BF2 MOV ESI,EDX 
017F58FA 81EE 87D851D2 SUB ESI,D251D887 
017F5900 C1CE B0 ROR ESI,0B0 
017F5903 8BC6 MOV EAX,ESI 
017F5905 C1C8 28 ROR EAX,28 
017F5908 53 PUSH EBX 
017F5909 5E POP ESI 
017F590A 81C5 974FAF73 ADD EBP,73AF4F97 
017F5910 BA 048A9178 MOV EDX,78918A04 
017F5915 F7D2 NOT EDX 
017F5917 F7D2 NOT EDX 
017F5919 81C2 FC756E87 ADD EDX,876E75FC 
017F591F 8BDA MOV EBX,EDX 
017F5921 41 INC ECX ；******** 好长的循环（译者注：两星号行间为所指循环） 
017F5922 8BD9 MOV EBX,ECX  
017F5924 D1C3 ROL EBX,1  
017F5926 81F3 A38FD7AC XOR EBX,ACD78FA3 
017F592C 3BD8 CMP EBX,EAX  
017F592E 0F85 EDFFFFFF JNZ 017F5921；******** 
017F5934 8BC1 MOV EAX,ECX <-- 在这里设置一个断点 

不跟进这个循环，按F8跳过！！，我们需要在 
017F5934 8BC1 MOV EAX,ECX 

设置一个断点。设置（按F2）完断点并运行（按F9）后程序将被中断在我们所设置的断点那里。 
7.现在我们该干吗？一直用F8 或 F7（进入子程序）跟踪？？！！不，我们不这么做！！ 
OllyDbg的一大特色就是Command Line（译者注：命令行？像DOS命令？笔者手上用的是V1.04，尚未发现这一功能） 
依次从菜单Plugins->Command line->Command line（译者注：考虑到英文版，这里不翻译；Plugins=插件）打开命令行编辑器。 
我们将用命令行来实现条件跟踪！对，OllyDbg确有一个条件跟踪命令！那就是TC，Trace Condition，它将跟踪直到所设条件满足为止。（译者注：似乎有点像TR中的BP?? <parameters>[if (conditions)] [do "statement"]？没用过，不敢妄言） 
在编辑框里输入TC EIP<900000，回车，在右下角的窗口中可以看到：“Tracing”提示，在我那慢机子上花了8分多钟（主频350MHz），在另一台机子（赛扬900MHz）上用了2分多钟。 

如果有人要送我一台电脑，你会知道在哪里能找到我并通知我。（译者注：英文原文：so if anyone would like to buy me a computer u know where to find me and msg me。我也常这样想……） 

8.待跟踪结束后（译者注：应该是所设置条件满足后），程序停在： 

0057EA5B E8 DB E8 
0057EA5C 00 DB 00 
0057EA5D 8A DB 8A 
0057EA5E E8 DB E8 
0057EA5F FF DB FF 

Hey !! i Dont See Shit !! 这是什么？！ 
这些代码OllyDbg没有处理，没关系，我们找到入口地址OEP了！ 
OEP=57EA5B 

9.这很重要！在口地址处我们查看EAX的值（在有边的CPU窗口那里）， 
EAX=57E318 
记下这个数值备用！ 

10.现在，打开ProcDump/Pe-Edit抓取全部该进程的全部内存映像。 

=================================== 
第二补——找到Stolen Bytes（译者注：英文原文：Finding the Stolen Bytes） 
=================================== 
（译者注：以下部分不知如何翻译才妥当，其大概描述从压缩文件解压并执行到入口地址这一过程） 
well to the Stolen Bytes there is corntly 3 ways: 

1. ASPR一般通过类似如下方式执行stolen bytes然后转到OEP : 

Stolen_Bytes_1 
Stolen_Bytes_2 
Stolen_Bytes_3 
..... 
..... 
PUSH_THE_ADDRESS_OF_OEP 
RET_TO_OEP 

2. ASPR will first Save the Stolen Bytes then it will Eares the bytes From the OEP 
then will Jmp to the OEP like this : 

Stolen_Bytes_1 
Stolen_Bytes_2 
Stolen_Bytes_3 
PUSH EBX 
PUSH ESI 
PUSH EDI 
...... 
...... 
...... 
REPZ STOSB <- Eares the bytes 
POPFD 
POPAD 
JMP_TO_OEP 

3. With NO Stolen Bytes it just PopAD and jumps to the OEP (No Stolen Bytes) 


怎么办？？ 
查看ASPR执行到入口地址前的那几步的跟踪记录。 
对！OllyDbg有一个名为“Run Trace”跟踪代码记录。 
在菜单上View->Run trace那里。在打开窗口的倒数第二行（译者注：英文原文：the line one before the last）我们可以看到CPU窗口同样转到同一地址，像这样： 

017F5779 F3:AA REP STOS BYTE PTR ES:[EDI] 
017F577B 9D POPFD 
017F577C 61 POPAD 
017F577D -E9 D992D8FE JMP SYSTEMCL.0057EA5B <-- 入口地址 

我们决定用第二种方法！：) 
以上形式的代码是基于winXP的，而不是win98。 
在CPU窗口按Ctrl+S(Serch for Seqeuance of Commads)并在那里输入： 
PUSH EBX 
PUSH ESI 
PUSH EDI 
我们将看到： 

01029227 0055 8B ADD BYTE PTR SS:[EBP-75],DL 
0102922A EC IN AL,DX ; I/O 指令 
0102922B 83EC 54 SUB ESP,54 
0102922E 53 PUSH EBX 
0102922F 56 PUSH ESI 
01029230 57 PUSH EDI 
01029231 6A 11 PUSH 11 

忽略“00”后得到stolen bytes为：55,8b,ec,83,ec,54 
记下这些数值备用。 
退出OllyDbg，我们现在不需要它。 


============================= 
第三步——重建输入表IAT 
============================= 

1.运行System Cleaner，等它完全载入。 
2.运行Imprec，在进程列表中选择我们的目标程序（System Cleaner）。 
3.选择“IAT AutoSearch”（自动搜索IAT。译者注：据说这个功能不错，但我每次用都不成功）。 
4.将其值由“BC”修改为1000（BC太小了！！）。 
5.单击“Get Imports”（获取输入表）。 
6. 单击“Show Invalid”（显示无效的输入表）。 
7. 
在无效输入表上右击，选择“Trace level 1”。 
8.再次单击“Show Invalid”（显示无效的输入表），我们将、看到类似信息： 

(cut from the saved tree) 
FThunk: 0019E258 NbFunc: 00000400 
1 0019E258 kernel32.dll 00D6 DeleteCriticalSection 
1 0019E25C kernel32.dll 0228 LeaveCriticalSection 
................ 
snip-snip 
................ 
1 0019E2A4 kernel32.dll 01D1 GetThreadLocale 
1 0019E2A8 kernel32.dll 01B9 GetStartupInfoA 
0 0019E2AC ? 0000 017E0F2C <-- good 
0 0019E2B0 ? 0000 017E139C <-- good 
1 0019E2B4 kernel32.dll 018B GetModuleFileNameA 
1 0019E2B8 kernel32.dll 0183 GetLocaleInfoA 
1 0019E2BC kernel32.dll 0181 GetLastError 
1 0019E2C0 kernel32.dll 0158 GetCurrentDirectoryA 
0 0019E2C4 ? 0000 017E1408 <-- good 
1 0019E2C8 kernel32.dll 0133 FreeLibrary 
1 0019E2CC kernel32.dll 011C FindFirstFileA 
.................. 
snip-snip 
.................. 
1 0019E314 kernel32.dll 00A0 CloseHandle 
0 0019E318 ? 0000 0255A00E <-- BAD 
1 0019E31C user32.dll 0112 GetKeyboardType 
1 0019E320 user32.dll 019F LoadStringA 
1 0019E324 user32.dll 01AD MessageBoxA 
1 0019E328 user32.dll 0026 CharNextA 
0 0019E32C ? 0000 70F7D832 <-- BAD 
1 0019E330 advapi32.dll 00F7 RegQueryValueExA 
1 0019E334 advapi32.dll 00EF RegOpenKeyExA 
1 0019E338 advapi32.dll 00D8 RegCloseKey 
0 0019E33C ? 0000 F37514C2 <-- BAD 
1 0019E340 oleaut32.dll 0006 SysFreeString 
1 0019E344 oleaut32.dll 0005 SysReAllocStringLen 
1 0019E348 oleaut32.dll 0004 SysAllocStringLen 
0 0019E34C ? 0000 4007F56E <-- BAD 
1 0019E350 kernel32.dll 0307 TlsSetValue 
1 0019E354 kernel32.dll 0306 TlsGetValue 
1 0019E358 kernel32.dll 01E6 GlobalAlloc 
0 0019E35C ? 0000 017E139C <-- good 
0 0019E360 ? 0000 BF57C0D8 <-- BAD 
....................... 
snip-snip 
....................... 
如此反复…… 
我们需要依次手工选择所有标有BAD的地址（Not in the packer code），然后右击相应地址，在弹出菜单中选择“Cut Thunk(s)”。 
* Wachout at the end .. there is a good thunk in there.. 
我们还要修复标有Good的相应字节。你可以从fraviamb.cjb.net下载一些插件。 
或参考我其他重建IAT的文章（New2Cracking.cjb.net 或 Fraviamb.cjb.net）。 
这些是我修复好的IAT： 

0019E2AC-> 017E0F2C ->GetProcAddress 
0019E2B0-> 017E139C ->GetModuleHandleA 
0019E2C4-> 017E1408 ->GetCommandLineA 
0019E35C-> 017E139C ->GetModuleHandleA 
0019E428-> 017E1420 ->LockResource 
0019E47C-> 017E13C4 ->GetVersion 
0019E4AC-> 017E0F2C ->GetProcAddress 
0019E4B8-> 017E139C ->GetModuleHandleA 
0019E4FC-> 017E13F8 ->GetCurrentProcessId 
0019E500-> 017E13F0 ->GetCurrentProcess 
0019E50C-> 017E1430 ->FreeResource 

9. 单击“Fix Dump”然后选择我们抓取内存映像的文件，imprec将在内存映像的文件名前面冠以“_”另存。 

========================= 
第四步——修正入口地址OEP 
========================= 

1.打开HVIEW /Hex Editor，（译者注：载入修正后的文件后）跳转到偏移地址57ea5b处，后退到57ea55（后退6字节），用我们得到的stolen bytes替换“00”，然后存盘。 

2.打开ProcDump/Pe-Edit，将要修正入口地址文件载入Pe-Edit，将入口地址修正为57ea55（由stolen bytes决定） 。 

3.如果你现在试图运行System Cleaner将会出错！！（译者注：多半是非法操作） 

4.打开OllyDbg并载入修正后 的文件。 

5. 在入口地址OEP : 57ea55处EAX的值是多少？还记得抓取内存映像前我让你记下入口地址OEP处的EAX的值吗？其值为EAX=57E318。该值与当前值不一样，这说明，有一指令被省略了，它就是MOV EAX, 0157E318 
以字节论，它占了5个字节（你可以用HVIEW自己尝试） 

B818E35700 MOV EAX, 0157E318 

这意味着，stolen bytes字节数为6+5=11（十进制），也就是说，真正的入口地址为： 
11=B（使六进制） 
先前得到的OEP值-STOLEN_BYTES=57EA5B-B=57EA50 
OEP = 57EA50 
在HVIEW/Hex Edit中找到新的OEP并输入：55,8B,EC,83,EC,54,B8,18,E3,57,00 
在ProcDump\Pe-Edit中将入口地址修正为：57EA50，此时，System Cleaner已经可以正常运行了！！！！！ 

收工！ 
