【目     标】:传奇外挂1.07
【工     具】:Olydbg1.1(diy版)、LORDPE、ImportREC1.6F 
【任     务】: ARM 3.6或以下版本的COPYMEM II标准壳 
【操作平台】:WinXP sp2 
【作     者】: LOVEBOOM[DFCG][FCG][US]
【相关链接】: ……
【简要说明】: 这是一个ARM3.6或以下版本的COPYMEM II壳来的,壳没有乱序,也没有抽壳代码的。所以比较容易。
【详细过程】:
OD设置:忽略全部异常用修改过的OD(必须PATCH过OutputDebugStringA漏洞),隐藏OD,忽略LOCKX(C000001E)
 
脱壳过程分为四部分:找OEP、DUMP程序、修复IAT,修复优化主程序。
第一部分:找OEP
用OD载入目标程序:
0056E379 >/$  55            PUSH EBP                                 ;  壳入口
0056E37A  |.  8BEC          MOV EBP,ESP
……
因为3.7以下版本的ARM不会检测全部API的CC断点。所以可以直接下断BP。先下BP
WaitForDebugEvnet断点,然后F9运行,到这里停下:
7C85A268 >  8BFF            MOV EDI,EDI                              ; 第一次停这里,停下后注意观察堆栈.
7C85A26A    55              PUSH EBP
7C85A26B    8BEC            MOV EBP,ESP
……




停下后去除CC断点,看看堆栈的信息:


 
注意ESP+4处的地址,在dump窗口中显示该地址信息:


 
再下bp WaiteProcessMemory断点并运行,断下后看看我们刚才地DUMP窗口中就可以找到程序有OEP了。


 
OEP在1C处,这个程序的OEP也就是4014AC,记下先。到这里第一部分就算完成了。
第二部分:DUMP程序
知道OEP后,如果你现在直接去follow 4014AC的话,你将什么都得不到,看看刚才断下地方的堆栈信息,我们可以得到我们要用的东西:


 
先算出真正代码所在的位置,计算方法为:OEP减去堆栈ESP+8处的address 401000加上ESP+0C处的Buffer 003c64b8,(至于为什么,可以去参考相关的文章。)所以这个程序的OEP代码为:4014AC-401000+003C64B8=003C6964.
003C6964   /EB 10           JMP SHORT 003C6976                       ; 这里就是程序原OEP代码
003C6966   |66:623A         BOUND DI,DWORD PTR DS:[EDX]
003C6969   |43              INC EBX
003C696A   |2B2B            SUB EBP,DWORD PTR DS:[EBX]
003C696C   |48              DEC EAX
以前有关文章到这里后要再处理下再DUMP,不过这个程序不用处理的,附以前文章里说的处理地方,你也可以直接跳过这一步到NEXT1处。
下面以这个为例说说处理的情况.先看堆栈:
0012D98C   0056C421  /CALL to WriteProcessMemory from MLEx.0056C41B
0012D990   0000004C  |hProcess = 0000004C (window)
0012D994   00401000  |Address = 401000
0012D998   003C64B8  |Buffer = 003C64B8
0012D99C   00001000  |BytesToWrite = 1000 (4096.)
0012D9A0   0012DAA8  \pBytesWritten = 0012DAA8
0012D9A4   00000002
0012D9A8   00000002
0012D9AC   0012F5A4
0012D9B0   00000000
0012D9B4   00000000
0012D9B8   00000000
0012D9BC   00000000
0012D9C0   00000000
0012D9C4   00000000
0012D9C8   00000000
0012D9CC   00000000
0012D9D0   00000000
0012D9D4   00000000
0012D9D8   00000000
0012D9DC   00000000
0012D9E0   00000000
0012D9E4   00000000
0012D9E8   00000000
0012D9EC   00000000
0012D9F0   00000000
0012D9F4   00000000
0012D9F8   00000000
0012D9FC   00000000
0012DA00   00000000
0012DA04   0012BDA4
0012DA08   00000000
0012DA0C   7C9305C8  RETURN to ntdll.7C9305C8 from ntdll.7C922F2F
0012DA10   005EC790  MLEx.005EC790
0012DA14   0012BE70
0012DA18   7C930551  RETURN to ntdll.7C930551 from ntdll.7C9305A2
0012DA1C   00561378  MLEx.00561378
0012DA20   7C93056D  RETURN to ntdll.7C93056D from ntdll.7C92EE02
0012DA24   0012BEC4
0012DA28   00000000
0012DA2C   00000000
0012DA30   00000000
0012DA34   00000000
0012DA38   00000020
0012DA3C   0012C368
0012DA40   0012BDEC
0012DA44   004A6C1C  MLEx.004A6C1C
0012DA48   0012C7FC
0012DA4C   0012BE20
0012DA50   00000039
0012DA54   004C1AB5  MLEx.004C1AB5
0012DA58   0012BE20
0012DA5C   0012BE08
0012DA60   004A6E3B  MLEx.004A6E3B
0012DA64   0012BE20
0012DA68   00000039
0012DA6C   0012C368
0012DA70   00000001
0012DA74   00000000
0012DA78   0012C340
0012DA7C   004A77D8  MLEx.004A77D8
0012DA80   0012BE20
0012DA84   828BF055
0012DA88   003C74B8
0012DA8C   003C74B8
0012DA90   5C3A4431
0012DA94   75636F44
0012DA98   00000020
0012DA9C   00401000  MLEx.00401000
0012DAA0   00000020
0012DAA4   003C74B8
0012DAA8   00001000
0012DAAC   003C74B8
0012DAB0  /0012DAE4
0012DAB4  |0056B12E  RETURN to MLEx.0056B12E from MLEx.0056B475
0012DAB8  |00000000
在0012DAB4处右键跟随:


 在代码窗口中到这里:
0056B129   .  E8 47030000   CALL 0056B475                            ;  这个CALL处理解码
0056B12E   >  83C4 0C       ADD ESP,0C                               ;  跟随到这里
……
到这里后CTRL+F查找命令:CALL 0056B475共会找到两处(如果ARM3.7或以上版本,会有好几个的),第二个地方为:
0056B3E4   .  E8 8C000000   CALL 0056B475                            ;  第二个地方
0056B3E9   .  83C4 0C       ADD ESP,0C
0056B3EC   .  9C            PUSHFD
0056B3ED   .  60            PUSHAD
……
第二地方NOP掉就行了:
0056B3E4      90            NOP                                      ;  第二个地方
0056B3E5      90            NOP
0056B3E6      90            NOP
0056B3E7      90            NOP
0056B3E8      90            NOP
0056B3E9   .  83C4 0C       ADD ESP,0C
处理完毕。



  NEXT1:
到这里后,修改一下代码就要DUMP了,让程序挂起来才能DUMP出来,用和SICE的方法一样改EIP为JMP EIP就行了。
修改003C6964:
003C6964   /EB 10           JMP SHORT 003C6976
003C6966   |66:623A         BOUND DI,DWORD PTR DS:[EDX]
003C6969   |43              INC EBX
003C696A   |2B2B            SUB EBP,DWORD PTR DS:[EBX]
修改为:
003C6964  - EB FE           JMP SHORT 003C6964
003C6966    66:623A         BOUND DI,DWORD PTR DS:[EDX]
003C6969    43              INC EBX
003C696A    2B2B            SUB EBP,DWORD PTR DS:[EBX]
003C696C    48              DEC EAX
这然后让程序“挂起来”,打开LORDPE选择第二个进程,然后选择ARMDUMP的插件,
 
选择好后就可以dump full程序。第二部分完毕。

第三部分:修复IAT
代码已经DUMP下来了,我们现在要修复IAT。关闭前面打开的OD,然后用OD载入刚才DUMP的程序,在OEP附件找到一下IAT的地起位置。比较简单的找到的地址533000(起始位置前一点不用担心搞错)。记得地址后,用OD再次载入目标,下断:bp DebugActiveProcess,运行后断下,就可以看到PROCESS ID了。到这里后,再开一个OD来附加这个PROCESS。附加后中断在系统中,按F9运行,运行中按F12停止就可以到壳代码处,因为那里的代码是死循环的:-)
0056E379 >- EB FE           JMP SHORT <ModuleEntryPoint>      停在这里
0056E37B    EC              IN AL,DX                                 ; I/O command
暂停后把EP代码改回去,改成558B(push ebp,mov ebp,esp),其实到了这里壳就像是一个双进程标准壳了,按双进程标准壳的方法就可以获取到IAT。具体方法:
改回代码后直接下断BP OpenMutexA,F9运行后中断然后清除断点记下ESP+C的内容。


 
在一空白处写入以下代码:
00401000    60              PUSHAD
00401001    9C              PUSHFD
00401002    68 F0FB1200     PUSH 12FBF0                              ; ASCII "168::DAC4C6C5E3"
00401007    33C0            XOR EAX,EAX
00401009    50              PUSH EAX
0040100A    50              PUSH EAX
0040100B    E8 2FDB407C     CALL kernel32.CreateMutexA
00401010    9D              POPFD
00401011    61              POPAD
00401012  - E9 04DC407C     JMP kernel32.OpenMutexA
把EIP定位到代码处(Ctrl+*),写完代码后更改OD异常设置:
 
打开内存访问错误异常。然后F9运行程序,内存异常断下后,忽略全部的异常并下断Bp GetModuleHandleA+5,Shit+f9忽略异常继续运行,API断下后,取消断点,ALT+F9执行返回到用户代码:
00CA532B    FF15 A450CC00   CALL DWORD PTR DS:[CC50A4]               ; kernel32.GetModuleHandleA
00CA5331    8B0D 60D8CC00   MOV ECX,DWORD PTR DS:[CCD860]            ; 返回到这里
00CA5337    89040E          MOV DWORD PTR DS:[ESI+ECX],EAX
00CA533A    A1 60D8CC00     MOV EAX,DWORD PTR DS:[CCD860]
00CA533F    393C06          CMP DWORD PTR DS:[ESI+EAX],EDI
00CA5342    75 16           JNZ SHORT 00CA535A
00CA5344    8D85 B4FEFFFF   LEA EAX,DWORD PTR SS:[EBP-14C]
00CA534A    50              PUSH EAX
00CA534B    FF15 B850CC00   CALL DWORD PTR DS:[CC50B8]               ; kernel32.LoadLibraryA
00CA5351    8B0D 60D8CC00   MOV ECX,DWORD PTR DS:[CCD860]
00CA5357    89040E          MOV DWORD PTR DS:[ESI+ECX],EAX
00CA535A    A1 60D8CC00     MOV EAX,DWORD PTR DS:[CCD860]
00CA535F    393C06          CMP DWORD PTR DS:[ESI+EAX],EDI
00CA5362    0F84 AD000000   JE 00CA5415                              ; 这里Magic jmp 改为JMP
;改为JMP 00CA5415
00CA5368    33C9            XOR ECX,ECX
00CA536A    8B03            MOV EAX,DWORD PTR DS:[EBX]
修改完后ALT+M打开内存页面,在text段下断:


 
下断完毕F9就到OEP处:
004014AC    6D              INS DWORD PTR ES:[EDI],DX                ; 中断在这里,虽然到这里代码不能用,但可以获取到正确的IAT
004014AD    66:16           PUSH SS
……
断下后用ImportREC对PROCESS进行IAT修复操作,IAT的开始地址用我们上面记下的533000-400000=133000,大小可以写大一点(当然你也可以计算的).cut无效的指针再FIXDUMP就行了。
 
修复IAT完毕(注:如果是3.7X或以上版本还有乱序,操作多一点)。



第四部分:修复程序/优化
程序现在已经基本搞完了,现在做一点收尾的工作。关掉两个OD,用lordpe改回OEP的代码。把没有用的段清除掉然后用LordPE FIXDUMP一下:
 

Finished! .

Greetz:
 Fly.Jingulong,yock,tDasm.David.hexer,hmimys,ahao.UFO(brother).alan(sister).all of my friends and you!

By loveboom[DFCG][FCG][US]
Email:loveboom#163.com
Date:3/27/2006 4:57:00 PM