aoshxi001 发表于 2007-3-9 11:52:58

标 题: ASPROTECT 2.x 脱壳系列(一)

标 题: ASPROTECT 2.x 脱壳系列(一)
发帖人:loveboom
时 间: 2005-10-05 20:36
原文链接:http://bbs.pediy.com/showthread.php?threadid=17373
详细信息:


ASPROTECT 2.x 脱壳系列(一)

【目    标】:DVD Fab Gold 2.9.4.2
【工    具】:Olydbg1.1(diy版)、LORDPE、ImportREC1.6F
【任    务】:简单的脱壳
【操作平台】:Windows XP sp2
【作    者】: LOVEBOOM
【相关链接】: 自己搜索下
【简要说明】: 时间在不断的减少,人越靠近死亡的边缘.人在死亡的边缘线上挣扎.寻求人间仅有的希望,骤觉得到了,又已失去了:-(.再虚幻的网络都要回到现实,但愿大家的现实比虚幻过的更充实.
ASPROTECT比起以前的版本可算是进步不少,脱壳难度大了不少,回头看看自己,感觉太失败了,别人进步了这么多,自己却还在原地踏步走:-(

【详细过程】:
想脱这个壳的话,建议对他的历史版本有所了解,那样对看起文章来不会那么吃力.asprotect 2.x惯用的伎俩:2.x版本anti-debug方面没有什么新变化,很多人说这是这个壳的失败之外,我倒觉得说其是失败之处,倒不如说是作者别有用心:-).代码混淆处理方面做了很大功夫,变形处理和1.23可以说基本不是一个层次了,新版不再是只抽程序入口代码,程序入口代码那一个段基本上都抽光了,其它地方也是抽的很利害.输入表也处理的很难修复.我这次挑的目标是没有抽入口代码的程序.所以相对简单些.
用OD载入目标,去除调试标志.打开内存异常项,通过N个异常后到程序的入口:

00ADAF43    64:8921         MOV   DWORD PTR FS:, ESP
00ADAF46    C601 A6         MOV   BYTE PTR DS:, 0A6         ; 最后一次异常
00ADAF49    5B            POP   EBX                              ; 00B4AC90
.......
00ADB09B    E8 807AFEFF   CALL    00AC2B20
00ADB0A0    E8 73CAFFFF   CALL    00AD7B18                         ; 直接在这里下断然后直接这里f2断点
00ADB0A5    83C4 2C         ADD   ESP, 2C
00ADB0A8    5D            POP   EBP                              ; 00B4AC90

最后一个异常发生时,在00adb0a0处下f2断点,然后shift+f9,断下后f7进去,进去之后CTRL+F9执行到RETURN
00D20000    68 1F1C0627   PUSH    27061C1F                         ; 进到这里
00D20005    66:81C0 96FC    ADD   AX, 0FC96
.......
00D2011C   /0F85 0F000000   JNZ   00D20131
00D20122   |B0 6A         MOV   AL, 6A
00D20124   |E9 3E000000   JMP   00D20167                         ; f4运行到这里
00D20129   |40            INC   EAX
......
00D20192    2BC3            SUB   EAX, EBX
00D20194    5C            POP   ESP                              ; DVDFabGo.00400000
00D20195- FFE0            JMP   EAX                              ; 这里跳去OEP
00D20197    40            INC   EAX


当然如果你只是想直接到
oep的话,最后一个异常发生后直接在CODE段下f2断点,再shift+f9就可以了:

0047572E    55            PUSH    EBP                              ; 程序OEP
0047572F    8BEC            MOV   EBP, ESP
00475731    6A FF         PUSH    -1
00475733    68 80F14700   PUSH    0047F180
.....
到了OEP后,我们先定位下IAT,观察后发现相关的API函数并没有什么加密处理,IAT:47A000 SIZE:BC4.


api没有什么特别处理,并不表示容易的,在程序里随便找一下就会看到call api到壳里去了。

00475832    E8 C9A78C00   CALL    00D40000

搜索一下发现很多地方都改成这样子了,一个一个去改??,我以前是试过一个一个去改。但那样效率太低了,且容易出错。跟过aspr 2.x的应该知道壳运行时会改地址的,因此在475832处下写入断点,运行中断:
00AE6265    8B45 F4         MOV   EAX, DWORD PTR SS:
00AE6268    8B40 3C         MOV   EAX, DWORD PTR DS:
00AE626B    8B55 FC         MOV   EDX, DWORD PTR SS:      ; 传递正确的API到EDX中
00AE626E    E8 D1130000   CALL    00AE7644                         ; 因是壳会检测相关代码,进去这里面后有地方不会被检测的
--------------------进入第一层----------------------------
00AE7644    55            PUSH    EBP
00AE7645    8BEC            MOV   EBP, ESP
00AE7647    83C4 E4         ADD   ESP, -1C
00AE764A    53            PUSH    EBX
00AE764B    56            PUSH    ESI
00AE764C    57            PUSH    EDI
00AE764D    894D F4         MOV   DWORD PTR SS:, ECX
00AE7650    8955 F8         MOV   DWORD PTR SS:, EDX      ; kernel32.GetModuleHandleA
00AE7653    8945 FC         MOV   DWORD PTR SS:, EAX
00AE7656    33C0            XOR   EAX, EAX
00AE7658    8945 F0         MOV   DWORD PTR SS:, EAX
00AE765B    B8 00070000   MOV   EAX, 700                         ; 这里还有代码检测的,再次进入
00AE7660    E8 DFAEFDFF   CALL    00AC2544
00AE7665    8945 E4         MOV   DWORD PTR SS:, EAX
----------------------------------进入第二层------------------------------------------
    00AC2544    85C0            TEST    EAX, EAX
    00AC2546    74 0A         JE      SHORT 00AC2552                   ; 经跟踪发现这里的条件判断在这个程序里是不会跳转的
    00AC2548    FF15 18A0AE00   CALL    DWORD PTR DS:            ; 这里的代码也不会被检测到,因此我把这里做为我们的突破点
    00AC254E    09C0            OR      EAX, EAX
    00AC2550    74 01         JE      SHORT 00AC2553
    00AC2552    C3            RETN
    00AC2553    B0 01         MOV   AL, 1
---------------------------------------------------------------------------------------
--------------------END----------------------------
00AE6273    8945 FC         MOV   DWORD PTR SS:, EAX
00AE6276    8B45 E0         MOV   EAX, DWORD PTR SS:
00AE6279    8B00            MOV   EAX, DWORD PTR DS:
00AE627B    E8 D0E6FFFF   CALL    00AE4950
00AE6280    8BD0            MOV   EDX, EAX
00AE6282    0255 DF         ADD   DL, BYTE PTR SS:
00AE6285    8B4D FC         MOV   ECX, DWORD PTR SS:
00AE6288    8B45 F4         MOV   EAX, DWORD PTR SS:
00AE628B    E8 80040000   CALL    00AE6710
00AE6290    8945 FC         MOV   DWORD PTR SS:, EAX
00AE6293    8B45 F4         MOV   EAX, DWORD PTR SS:
00AE6296    8B40 24         MOV   EAX, DWORD PTR DS:
00AE6299    8B55 F4         MOV   EDX, DWORD PTR SS:
00AE629C    0382 E0000000   ADD   EAX, DWORD PTR DS:
00AE62A2    0145 1C         ADD   DWORD PTR SS:, EAX
00AE62A5    8B45 FC         MOV   EAX, DWORD PTR SS:
00AE62A8    2B45 1C         SUB   EAX, DWORD PTR SS:       ; DVDFabGo.00475832
00AE62AB    83E8 05         SUB   EAX, 5
00AE62AE    8B55 1C         MOV   EDX, DWORD PTR SS:       ; DVDFabGo.00475832
00AE62B1    42            INC   EDX                              ; DVDFabGo.00475833
00AE62B2    8902            MOV   DWORD PTR DS:, EAX          ; 这里断下,写入call的地址
00AE62B4    EB 01         JMP   SHORT 00AE62B7
00AE62B6    E8 8B45F883   CALL    84A6A846

找到突破点后,再找这段代码的出口,tc command is:POPFD,条件符合后中断:

00D500B0    9D            POPFD                                    ; 条件中断在这里
00D500B1    5C            POP   ESP
00D500B2    F3:             PREFIX REP:                              ; Superfluous prefix
00D500B3    EB 02         JMP   SHORT 00D500B7
00D500B5    CD 20         INT   20
00D500B7    FF6424 FC       JMP   DWORD PTR SS:             ; 这里跳去执行原程序的call api,注意这里已经处理过了,不再是简单的call api了
00D500BB    F3:             PREFIX REP:                              ; Superfluous prefix
00D500BC    EB 02         JMP   SHORT 00D500C0
00D500BE    CD 20         INT   20

再找一个空闲的地方写上修复代码,考虑到代码可能会长一点,选择代码后的空白地址479bc0修复代码起始地址。
总结一下大概为:

OEP:      47572E
IAT:      47A000
SIZE:      BC4

Patch点一:      00AC2548
Patch点二:      00D500B7(这个地址每次运行都会改变的)
Patch起始地址:      479BC0

现在唯一没有解决的问题就是,都有哪些地方改成了CALL    00D40000,当然,可以通过比较死的方法,直接去搜索,我觉得那样可能没有那么准确,所以我选择了直接记录的方式。
重新加载,载入后,两次GetModuleHandleA中断后,让壳的代码完全解出来:
00AF25C2   /75 08         JNZ   SHORT 00AF25CC
00AF25C4   |B8 01000000   MOV   EAX, 1
00AF25C9   |C2 0C00         RETN    0C
00AF25CC   \68 A08FAE00   PUSH    0AE8FA0                        ; 壳的执行代码执行点
00AF25D1    C3            RETN
......
00AE8FA0    55            PUSH    EBP                              ; 壳的代码
00AE8FA1    8BEC            MOV   EBP, ESP
00AE8FA3    83C4 B4         ADD   ESP, -4C

壳的代码完全解出来后,搜索命令

MOV ,EAX
PUSH 0A

找到相关位置后下硬件执行断点。执行后中断:

00AE653F    8945 00         MOV   DWORD PTR SS:, EAX          ; 找到这里,ebp-1就正好是call d40000的地址
00AE6542    6A 0A         PUSH    0A
00AE6544    E8 63C4FEFF   CALL    00AD29AC
00AE6549    8BC8            MOV   ECX, EAX

现在要要找的就是存放这些地址的空间,ASPR加壳的程序,最后一个段是空的,我们可以利用下,我选择514100开始保存相关数据:
514100保存将要保存相关call地址的实际地址,514108保存call 中的address,514100开始保存相关call 00d40000的实际地址。好了,现在写上一段代码来保存相关数据:
00AE653F   /EB 43         JMP   SHORT 00AE6584                   ; 跳去执行我们的代码
00AE6541   |90            NOP
00AE6542   |6A 0A         PUSH    0A
00AE6544   |E8 63C4FEFF   CALL    00AD29AC
00AE6549   |8BC8            MOV   ECX, EAX
00AE654B   |038B E4000000   ADD   ECX, DWORD PTR DS:
00AE6551   |8BD6            MOV   EDX, ESI
00AE6553   |8BC3            MOV   EAX, EBX
00AE6555   |E8 9EE5FFFF   CALL    00AE4AF8
00AE655A   |FF0C24          DEC   DWORD PTR SS:
00AE655D   |03B3 E4000000   ADD   ESI, DWORD PTR DS:
00AE6563   |833C24 00       CMP   DWORD PTR SS:, 0
00AE6567^|0F87 55FEFFFF   JA      00AE63C2
00AE656D   |53            PUSH    EBX                              ; 写好代码后直接在这里F2断点
00AE656E   |E8 5D000000   CALL    00AE65D0
00AE6573   |0183 EC000000   ADD   DWORD PTR DS:, EAX
00AE6579   |B0 01         MOV   AL, 1
00AE657B   |83C4 24         ADD   ESP, 24
00AE657E   |5D            POP   EBP                              ; DVDFabGo.004033AD
00AE657F   |5F            POP   EDI
00AE6580   |5E            POP   ESI
00AE6581   |5B            POP   EBX
00AE6582   |C3            RETN
00AE6583   |90            NOP
00AE6584   \53            PUSH    EBX                              ; 保存堆栈
00AE6585    51            PUSH    ECX
00AE6586    B9 00415100   MOV   ECX, 514100                      ; 起始地址
00AE658B    8339 00         CMP   DWORD PTR DS:, 0
00AE658E    75 06         JNZ   SHORT 00AE6596
00AE6590    C701 10415100   MOV   DWORD PTR DS:, 514110       ; 如果是第一次则写入相关数据
00AE6596    8B19            MOV   EBX, DWORD PTR DS:
00AE6598    4D            DEC   EBP                              ; DVDFabGo.004033AD
00AE6599    892B            MOV   DWORD PTR DS:, EBP          ; 保存call的地址
00AE659B    83C3 04         ADD   EBX, 4
00AE659E    8919            MOV   DWORD PTR DS:, EBX          ; 保存下次保存数据的地址
00AE65A0    45            INC   EBP                              ; DVDFabGo.004033AD
00AE65A1    59            POP   ECX
00AE65A2    5B            POP   EBX
00AE65A3    8945 00         MOV   DWORD PTR SS:, EAX          ; 执行壳原来的代码
00AE65A6^ EB 9A         JMP   SHORT 00AE6542

写完代码后直接在00AE656D下F2断点,断下后,还原patch代码,514100处的数据保存起来(主要是方便一次操作不成功,第二次不用再写代码获取相关数据,当然其实完全可以一次操作成功的)。

获取到了相关的数据后,运行到OEP处,然后就可以直接写上完整的修复代码了,在前面总结的479BC0处写上修复代码:


00479BC0   .60            PUSHAD                                 ;保护堆栈,直接定位到这里
00479BC1   .B9 10415100   MOV   ECX, 00514110                  ;把call 00d40000改成call ds:
00479BC6   >8B19          MOV   EBX, DWORD PTR DS:          ;取出相关地址
00479BC8   .83FB 00       CMP   EBX, 0                           ;判断是否处理完了
00479BCB   .74 15         JE      SHORT 00479BE2
00479BCD   .- FFE3          JMP   EBX                              ;执行原call
00479BCF   .8B15 08415100 MOV   EDX, DWORD PTR DS:       ;就是保存call 中的address
00479BD5   .66:C703 FF15MOV   WORD PTR DS:, 15FF          ;修复成call ds:
00479BDA   .8953 02       MOV   DWORD PTR DS:, EDX      ;填上实际的address
00479BDD   .83C1 04       ADD   ECX, 4
00479BE0   .^ EB E4         JMP   SHORT 00479BC6
00479BE2   >33C0          XOR   EAX, EAX                         ;这里开始修复call 中实际上是jmp 的部分
00479BE4   .B0 E8         MOV   AL, 0E8
00479BE6   .BF 00104000   MOV   EDI, <ModuleEntryPoint>          ;代码段的起始地址
00479BEB   .B9 B89B0600   MOV   ECX, 69BB8                     ;大小
00479BF0   >F2:AE         REPNE   SCAS BYTE PTR ES:
00479BF2   .83F9 00       CMP   ECX, 0
00479BF5   .74 3C         JE      SHORT 00479C33                   ;如果处理完则结束过程
00479BF7   .8B1F          MOV   EBX, DWORD PTR DS:
00479BF9   .8D5C3B 04   LEA   EBX, DWORD PTR DS:
00479BFD   .81FB 00104000 CMP   EBX, <ModuleEntryPoint>
00479C03   .^ 72 EB         JB      SHORT 00479BF0
00479C05   .81FB BA9B4700 CMP   EBX, 00479BBA
00479C0B   .^ 77 E3         JA      SHORT 00479BF0
00479C0D   .66:813B FF15CMP   WORD PTR DS:, 15FF
00479C12   .^ 75 DC         JNZ   SHORT 00479BF0
00479C14   .817B 02 00A04>CMP   DWORD PTR DS:, 0047A000   ;再次准确的判断是否为真的要修改的代码
00479C1B   .^ 72 D3         JB      SHORT 00479BF0
00479C1D   .817B 02 C0AB4>CMP   DWORD PTR DS:, 0047ABC0
00479C24   .^ 77 CA         JA      SHORT 00479BF0
00479C26   .66:C703 FF25MOV   WORD PTR DS:, 25FF
00479C2B   .83C7 04       ADD   EDI, 4
00479C2E   .83E9 04       SUB   ECX, 4
00479C31   .^ EB BD         JMP   SHORT 00479BF0
00479C33   >61            POPAD                                    ;还原现场
00479C34   .00            DB      00
00479C35   .00            DB      00                               ;因为我是操作边写的,这里留多点空间方便修改代码
00479C36   .00            DB      00
00479C37   .00            DB      00
00479C38   .00            DB      00
00479C39   .00            DB      00
00479C3A   .00            DB      00
00479C3B   .00            DB      00
00479C3C   .00            DB      00
00479C3D   .00            DB      00
00479C3E   .00            DB      00
00479C3F   .00            DB      00
00479C40   .00            DB      00
00479C41   .00            DB      00
00479C42   .00            DB      00
00479C43   .00            DB      00
00479C44   .00            DB      00
00479C45   .00            DB      00
00479C46   .00            DB      00
00479C47   .00            DB      00
00479C48   .00            DB      00
00479C49   .00            DB      00
00479C4A   .00            DB      00
00479C4B   .00            DB      00
00479C4C   .00            DB      00
00479C4D   .00            DB      00
00479C4E   .00            DB      00
00479C4F   .00            DB      00
00479C50   .00            DB      00
00479C51   .00            DB      00
00479C52   .00            DB      00
00479C53   .00            DB      00
00479C54   .00            DB      00
00479C55   .00            DB      00
00479C56   .00            DB      00
00479C57   .00            DB      00
00479C58   .00            DB      00
00479C59   .00            DB      00
00479C5A   .00            DB      00
00479C5B   .00            DB      00
00479C5C   .00            DB      00
00479C5D   .00            DB      00
00479C5E   .00            DB      00
00479C5F   .00            DB      00
00479C60   .00            DB      00
00479C61   .00            DB      00
00479C62   .00            DB      00
00479C63   .00            DB      00
00479C64   .00            DB      00
00479C65   .00            DB      00
00479C66   .00            DB      00
00479C67   .00            DB      00
00479C68   .00            DB      00
00479C69   .00            DB      00
00479C6A   .00            DB      00
00479C6B   .00            DB      00
00479C6C   .00            DB      00
00479C6D   .00            DB      00
00479C6E   .00            DB      00
00479C6F   .00            DB      00
00479C70      789C4700      DD      DVDFabGo.00479C78
00479C74      00            DB      00
00479C75      90            NOP
00479C76      90            NOP
00479C77      90            NOP
00479C78   .60            PUSHAD
00479C79   .8BC2          MOV   EAX, EDX
00479C7B   .B9 C80B0000   MOV   ECX, 0BC8                        ;iat大小
00479C80   .BF 00A04700   MOV   EDI, 0047A000                  ;iat起始地址
00479C85   .F2:AF         REPNE   SCAS DWORD PTR ES:
00479C87   .83EF 04       SUB   EDI, 4
00479C8A   .893D 08415100 MOV   DWORD PTR DS:, EDI       ;保存地址
00479C90   .61            POPAD
00479C91   .FF15 18A0AE00 CALL    DWORD PTR DS:            ;执行程序的原代码
00479C97   .C3            RETN
00479C98      90            NOP

再把这里的代码改一下:
00AC2548    FF15 709C4700   CALL    DWORD PTR DS:            ; DVDFabGo.00479C78

写到这里,完了吗?当然没有了,认真看就会发前的的jmp ebx那里是个call,直接这样操作就回不来了,这也就是为什么前面还用一个patch2,
直接到00D500B7看看去,看看现在在哪里了。
00D500E1    9D            POPFD
00D500E2    5C            POP   ESP                              ; 00A80000
00D500E3- FF6424 FC       JMP   DWORD PTR SS:             ; 这次在这里了
00D500E7    CC            INT3

直接在D500E3处下硬件断点,没错了,我想在这里的时候把返回地址改成跳去00479BCF,直接修改代码?当然不行了,壳会检测的,找到地方去除检测?我偷懒处理下,用脚本就很简单的搞定了:
//fixed aspr 2.x
var addr


start:
run

l1:
cmp eip,00D500E3
jne l2
mov addr,esp
sub addr,4
mov ,479bcf
jmp start

l2:
ret

写好后,记得在479c33处下个f2断,再运行,否则运行脚本后会"飞"的。

脚本运行完毕,赶快dump完,修复收工吧(做完后要记得把修复代码和保存的数据给清除掉哦,做事要有头有尾才行的).嗯,脱壳完毕,当然这里实际上还是有点小问题的,问题解决方法请参考我的第二篇ASPR文章


标 题: 答复
发帖人:wenglingok
时 间: 2005-10-08 11:01
详细信息:



引用:
--------------------------------------------------------------------------------
00AE6265    8B45 F4         MOV   EAX, DWORD PTR SS:
00AE6268    8B40 3C         MOV   EAX, DWORD PTR DS:
00AE626B    8B55 FC         MOV   EDX, DWORD PTR SS:      ; 传递正确的API到EDX中
--------------------------------------------------------------------------------


我用Aspr2.11加壳的记事本
第一个Call api 应该是调用 GetCommandLineA
被改为Call 00D60000
跟进来到你说的传递正确API到EDX的地方时,竟然变成了GetSartupInfo
怎么也想不通会这样,正在郁闷中啊!
(已解决)
原来修改代码前传递正确的API,随后会传递下一个Api准备调用,下一个Api就是GetSartupInfo,我跟到那里去了。

zsl01 发表于 2008-9-27 17:27:29

这么好的贴,为什么没有支持一下,我顶一个.

小生我怕怕 发表于 2008-9-27 21:57:10

强大,完全手工的!喜欢这种脱文,学习有意思,希望能提供文中用到的附件学习!

wqhlgr 发表于 2009-1-26 07:20:25

这壳手脱太麻烦了,还是用脚本吧

樊盟 发表于 2009-1-28 13:57:48

支持,破文写的这么详细,我们菜鸟应该多学习学习,谢谢楼主!/:good /:good /:good

lbmx8 发表于 2009-7-17 11:24:20

学习了,谢谢楼主!!!
页: [1]
查看完整版本: 标 题: ASPROTECT 2.x 脱壳系列(一)