ASPROTECT 2.0 脱壳示例
【目 标】:Win98’s notepad
【工 具】:Olydbg1.1(diy版)、LORDPE、ImportREC1.6F
【任 务】:简单的脱一下asprotect的壳
【操作平台】:Windows Xp sp2
【作 者】:loveboom[DFCG][FCG][US]
【简要说明】:有一段时间没写文章了,这篇文章本来是想在奥运会那时写出来,因为公事比较多,有空的时候心情不好等原因,所以一直放到现在才写.
【详细过程】:
设置忽略全部异常,去掉调试标志。
载入后到这里:
00401000 > 68 01D040>PUSH 0040D001 ; EP壳的入口
00401005 E8 010000>CALL 0040100B
载入后,直接g LoadLibraryA运行到LoadLibraryA这个API处.
7C801D77 > 8BFF MOV EDI,EDI ; LoadLibraryA
7C801D79 55 PUSH EBP
到了后,ALT+F9执行到返回:
009884B7 8985 4D29>MOV DWORD PTR SS:[EBP+44294D],EAX ; 返回到这里
009884BD C785 5129>MOV DWORD PTR SS:[EBP+442951],0
……
009885C1 61 POPAD
009885C2 75 08 JNZ SHORT 009885CC ; 看到这里,跟过Aspack的朋友就是知道这里是什么了
009885C4 B8 010000>MOV EAX,1
009885C9 C2 0C00 RETN 0C
009885CC 68 000000>PUSH 0 ; 如果解压完壳代码这里会push 一个返回的地址
009885D1 C3 RETN
返回到009884B7处后,右键查找全部字符串,然后在字符串窗中查找250这样就会看到这些东西:
双击10那里到了cpu窗口处:
0096CD66 /75 0A JNZ SHORT 0096CD72
0096CD68 |68 C8D096>PUSH 96D0C8 ; 双击到这里,这里向上找到代码开始处
0096CD6D |E8 BE6DFF>CALL 00963B30
向上找到这里:
0096CC70 /EB 01 JMP SHORT 0096CC73
0096CC72 |90 NOP
0096CC73 \8B43 08 MOV EAX,DWORD PTR DS:[EBX+8] ; 这里开始对IAT进行处理
0096CC76 8B30 MOV ESI,DWORD PTR DS:[EAX]
0096CC78 8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CC7C 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]
0096CC7F 8A00 MOV AL,BYTE PTR DS:[EAX]
0096CC81 884424 07 MOV BYTE PTR SS:[ESP+7],AL
0096CC85 FF43 08 INC DWORD PTR DS:[EBX+8]
0096CC88 85F6 TEST ESI,ESI
0096CC8A 75 1A JNZ SHORT 0096CCA6 ; 这里比较输入表是否处理完毕,如果没有就跳下去
0096CC8C EB 01 JMP SHORT 0096CC8F
……
0096CCC9 FF43 08 INC DWORD PTR DS:[EBX+8]
0096CCCC 84C0 TEST AL,AL ; 这里开始对AL的值的不同而进行相关的处理
0096CCCE 75 20 JNZ SHORT 0096CCF0
……
0096CD59 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14]
0096CD5D E8 DEECFF>CALL 0096BA40 ; GetProcAddress
0096CD62 8BE8 MOV EBP,EAX
0096CD64 85ED TEST EBP,EBP
0096CD66 75 0A JNZ SHORT 0096CD72 ; 判断获取API是否成功
0096CD68 68 C8D096>PUSH 96D0C8 ; 双击到这里,这里向上找到代码开始处
0096CD6D E8 BE6DFF>CALL 00963B30
0096CD72 837C24 20>CMP DWORD PTR SS:[ESP+20],0
……
0096CDF7 E8 8469FF>CALL 00963780 ; 当AL为2时对IAT的处理,跟进去
0096CDFC ^ E9 72FEFF>JMP 0096CC73 ; 处理完跳回去
……
跟进看看:
00963756 8BC0 MOV EAX,EAX
00963758 55 PUSH EBP
00963759 8BEC MOV EBP,ESP
0096375B 53 PUSH EBX
0096375C 8BD8 MOV EBX,EAX
0096375E 8BC2 MOV EAX,EDX
00963760 8BD1 MOV EDX,ECX
00963762 E8 79FFFF>CALL 009636E0
00963767 C603 E9 MOV BYTE PTR DS:[EBX],0E9 ; 先在这里也下个断,因为这里就是程序的OEP
0096376A 8D53 01 LEA EDX,DWORD PTR DS:[EBX+1] ; 这里原程跳就是壳抽程序代码的开始地方
0096376D 8902 MOV DWORD PTR DS:[EDX],EAX
0096376F 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
00963772 8910 MOV DWORD PTR DS:[EAX],EDX
00963774 B8 050000>MOV EAX,5
00963779 5B POP EBX
0096377A 5D POP EBP
0096377B C2 0400 RETN 4
0096377E 8BC0 MOV EAX,EAX
00963780 53 PUSH EBX ; 进到这里
00963781 8BD8 MOV EBX,EAX
00963783 8BC3 MOV EAX,EBX
00963785 E8 56FFFF>CALL 009636E0
0096378A C603 E8 MOV BYTE PTR DS:[EBX],0E8 ; 这里把IAT的改成call xxxxxx的样式,所以我们这里要进去处理
0096378D 43 INC EBX
0096378E 8903 MOV DWORD PTR DS:[EBX],EAX
00963790 5B POP EBX
00963791 C3 RETN
现在这里我们来修复一下:
先自己申请两块空间,当然你也可以直接找空闲的地方来写代码,我分别申请了00B90000和00BA0000这个块内存空间,00b90000这块是用来写patch代码,00ba0000是用来保存临时要存放的数据。
00BA0000用来保存DLL的基址,00BA0010用来保存要存放IAT的地址。
搞清这些东西后,我们开始写代码:
00963781 8BD8 MOV EBX,EAX
00963783 8BC3 MOV EAX,EBX
00963785 E8 56FFFF>CALL 009636E0
0096378A E8 71C822>CALL 00B90000 ; 调用我们改的代码处
0096378F 90 NOP
00963790 5B POP EBX
00963791 C3 RETN
00B90000用来写我们自己的修复代码:
00B90000 51 PUSH ECX ; 保护现场
00B90001 52 PUSH EDX
00B90002 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+28] ; 取出基址到EDX中
00B90006 3B15 0000>CMP EDX,DWORD PTR DS:[BA0000] ; 比较基址是否相同
00B9000C 74 0D JE SHORT 00B9001B
00B9000E 8915 0000>MOV DWORD PTR DS:[BA0000],EDX ; 如果不同就写入新的基址
00B90014 8305 1000>ADD DWORD PTR DS:[BA0010],4 ; 并把填入IAT的地址再加上4
00B9001B 8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010] ; 如果是第一次我们要手工写一下保存IAT的地址,我选择的是40C000
00B90021 8929 MOV DWORD PTR DS:[ECX],EBP ; 写入正确的函数
00B90023 66:C703 F>MOV WORD PTR DS:[EBX],15FF ; 这里要看程序的情况而定,如果是DELPHI之类的,这果就可能是FF25了,因为是C的,所以这里是ff15
00B90028 890E MOV DWORD PTR DS:[ESI],ECX ; 把存放IAT的地址放到程序里
00B9002A 8305 1000>ADD DWORD PTR DS:[BA0010],4 ; 保存IAT的地址+4
00B90031 5A POP EDX ; 还原现场
00B90032 59 POP ECX
00B90033 C3 RETN ; 返回到壳那边继续
继续到AL=1时的处理:
0096CE07 ^\E9 67FEFF>JMP 0096CC73
0096CE0C 3C 01 CMP AL,1 ; 当AL=1的处理
0096CE0E 0F85 B200>JNZ 0096CEC6
……
0096CE7E A1 B8A697>MOV EAX,DWORD PTR DS:[97A6B8]
0096CE83 8B00 MOV EAX,DWORD PTR DS:[EAX]
0096CE85 FFD0 CALL EAX ; GetProcAddress
0096CE87 8BE8 MOV EBP,EAX
0096CE89 85ED TEST EBP,EBP
0096CE8B 75 0A JNZ SHORT 0096CE97 ; 如果获取成功就跳
0096CE8D 68 D8D096>PUSH 96D0D8 ; ASCII "11
"
0096CE92 E8 996CFF>CALL 00963B30
0096CE97 8B0424 MOV EAX,DWORD PTR SS:[ESP]
0096CE9A 50 PUSH EAX
0096CE9B 68 08BC96>PUSH 96BC08
0096CEA0 8D4C24 20 LEA ECX,DWORD PTR SS:[ESP+20]
0096CEA4 8BD5 MOV EDX,EBP
0096CEA6 8BC3 MOV EAX,EBX
0096CEA8 E8 BFF4FF>CALL 0096C36C
0096CEAD 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C] ; 这里壳又要对IAT破坏处理,我们这里又要自己修复一下
0096CEB1 8902 MOV DWORD PTR DS:[EDX],EAX ; 这里写上我们自己的代码
0096CEB3 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
0096CEB7 8906 MOV DWORD PTR DS:[ESI],EAX
0096CEB9 0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]
0096CEBE 0143 08 ADD DWORD PTR DS:[EBX+8],EAX
0096CEC1 ^ E9 ADFDFF>JMP 0096CC73 ; 处理完就跳回去
当AL=1时的修复代码:
0096CEA8 E8 BFF4FF>CALL 0096C36C
0096CEAD E8 8E3122>CALL 00B90040
0096CEB2 90 NOP
0096CEB3 90 NOP
0096CEB4 90 NOP
0096CEB5 90 NOP
0096CEB6 90 NOP
0096CEB7 90 NOP
0096CEB8 90 NOP
0096CEB9 0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]
0096CEBE 0143 08 ADD DWORD PTR DS:[EBX+8],EAX
0096CEC1 ^ E9 ADFDFF>JMP 0096CC73
00B90040处的修复代码:
00B90040 51 PUSH ECX ; 保护现场
00B90041 52 PUSH EDX
00B90042 8B5424 20 MOV EDX,DWORD PTR SS:[ESP+20] ; 取出当然要处理DLL的基址
00B90046 3B15 0000>CMP EDX,DWORD PTR DS:[BA0000] ; 比较基址是否相同
00B9004C 74 0D JE SHORT 00B9005B
00B9004E 8915 0000>MOV DWORD PTR DS:[BA0000],EDX
00B90054 8305 1000>ADD DWORD PTR DS:[BA0010],4
00B9005B 8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010] ; 1.0040C004
00B90061 8929 MOV DWORD PTR DS:[ECX],EBP ; 把IAT写到我们要指定的地址去也就是40c000那个段里
00B90063 890E MOV DWORD PTR DS:[ESI],ECX ; 那保存函数的地址写入程序中
00B90065 8305 1000>ADD DWORD PTR DS:[BA0010],4
00B9006C 5A POP EDX
00B9006D 59 POP ECX ; 还原现场
00B9006E C3 RETN ; 执行到返回
到了AL=4的处理了:
0096CEC6 3C 04 CMP AL,4 ; 当AL为4有两个分支
0096CEC8 0F85 F400>JNZ 0096CFC2
0096CECE EB 01 JMP SHORT 0096CED1
0096CED0 90 NOP
0096CED1 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]
0096CED4 8A00 MOV AL,BYTE PTR DS:[EAX]
0096CED6 FF43 08 INC DWORD PTR DS:[EBX+8]
0096CED9 84C0 TEST AL,AL
0096CEDB 75 5B JNZ SHORT 0096CF38 ; 这里跳的话就和AL=1时的处理一样
0096CEDD 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8] ; 这里是AL=4时的第一个分支
0096CEE0 8B30 MOV ESI,DWORD PTR DS:[EAX]
0096CEE2 8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CEE6 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]
0096CEE9 8B28 MOV EBP,DWORD PTR DS:[EAX]
0096CEEB 8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CEEF 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]
0096CEF2 8B00 MOV EAX,DWORD PTR DS:[EAX]
0096CEF4 894424 2C MOV DWORD PTR SS:[ESP+2C],EAX
0096CEF8 8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CEFC 837B 30 0>CMP DWORD PTR DS:[EBX+30],0
0096CF00 75 0A JNZ SHORT 0096CF0C
0096CF02 68 E8D096>PUSH 96D0E8 ; ASCII "81
"
0096CF07 E8 246CFF>CALL 00963B30
0096CF0C 8D5424 30 LEA EDX,DWORD PTR SS:[ESP+30]
0096CF10 8BC3 MOV EAX,EBX
0096CF12 E8 8DF8FF>CALL 0096C7A4 ; 这个CALL要进去,因为这里面就是计算将要保存IAT的地址
进去看看先:
0096C7A4 53 PUSH EBX
0096C7A5 56 PUSH ESI
0096C7A6 8BF2 MOV ESI,EDX
0096C7A8 8BD8 MOV EBX,EAX
0096C7AA B8 040000>MOV EAX,4
0096C7AF E8 985DFE>CALL 0095254C
0096C7B4 8906 MOV DWORD PTR DS:[ESI],EAX ; 这里把计算出来的地址填入[esi]中
0096C7B6 8B43 40 MOV EAX,DWORD PTR DS:[EBX+40]
0096C7B9 8946 04 MOV DWORD PTR DS:[ESI+4],EAX
0096C7BC 5E POP ESI
0096C7BD 5B POP EBX
0096C7BE C3 RETN
这里处理第一个分支先,第二个分支我们可以完全调用AL=1时的代码,AL=4第一个分支的修复代码:
0096C7A4 53 PUSH EBX
0096C7A5 56 PUSH ESI
0096C7A6 8BF2 MOV ESI,EDX
0096C7A8 8BD8 MOV EBX,EAX
0096C7AA B8 040000>MOV EAX,4
0096C7AF E8 985DFE>CALL 0095254C
0096C7B4 E8 C13822>CALL 00B9007A
0096C7B9 8946 04 MOV DWORD PTR DS:[ESI+4],EAX
0096C7BC 5E POP ESI
0096C7BD 5B POP EBX
0096C7BE C3 RETN
00B9007A的修复代码:
00B9007A 51 PUSH ECX ; 保护现场
00B9007B 52 PUSH EDX
00B9007C 8B5424 2C MOV EDX,DWORD PTR SS:[ESP+2C] ; 取出当然要处理DLL的基址
00B90080 3B15 0000>CMP EDX,DWORD PTR DS:[BA0000] ; kernel32.7C800000
00B90086 74 0D JE SHORT 00B90095
00B90088 8915 0000>MOV DWORD PTR DS:[BA0000],EDX
00B9008E 8305 1000>ADD DWORD PTR DS:[BA0010],4
00B90095 8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010] ; 1.0040C020
00B9009B 890E MOV DWORD PTR DS:[ESI],ECX ; 取出我们要保存IAT的址址到[ESI]中
00B9009D 8305 1000>ADD DWORD PTR DS:[BA0010],4
00B900A4 5A POP EDX
00B900A5 59 POP ECX ; 还原现场
00B900A6 8B43 40 MOV EAX,DWORD PTR DS:[EBX+40] ; 执行我们前面所"吃"掉一行代码
00B900A9 C3 RETN ;执行到返回
……
0096CF17 8B4424 2C MOV EAX,DWORD PTR SS:[ESP+2C]
0096CF1B 50 PUSH EAX
0096CF1C 8D4424 34 LEA EAX,DWORD PTR SS:[ESP+34]
0096CF20 50 PUSH EAX
0096CF21 55 PUSH EBP
0096CF22 A1 70A597>MOV EAX,DWORD PTR DS:[97A570]
0096CF27 8B00 MOV EAX,DWORD PTR DS:[EAX]
0096CF29 50 PUSH EAX
0096CF2A 56 PUSH ESI
0096CF2B 8B4424 28 MOV EAX,DWORD PTR SS:[ESP+28]
0096CF2F 50 PUSH EAX
0096CF30 FF53 30 CALL DWORD PTR DS:[EBX+30] ; 这里计算函数并写入地址
0096CF33 ^ E9 3BFDFF>JMP 0096CC73
0096CF38 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]
0096CF3B 8B00 MOV EAX,DWORD PTR DS:[EAX]
0096CF3D 890424 MOV DWORD PTR SS:[ESP],EAX
0096CF40 8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CF44 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]
0096CF47 66:8B00 MOV AX,WORD PTR DS:[EAX]
0096CF4A 66:894424>MOV WORD PTR SS:[ESP+4],AX
0096CF4F 8343 08 0>ADD DWORD PTR DS:[EBX+8],2
0096CF53 8B0C24 MOV ECX,DWORD PTR SS:[ESP]
0096CF56 66:8B5424>MOV DX,WORD PTR SS:[ESP+4]
0096CF5B 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]
0096CF5E E8 91ABFF>CALL 00967AF4
0096CF63 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+10]
0096CF67 E8 E055FE>CALL 0095254C
0096CF6C 894424 0C MOV DWORD PTR SS:[ESP+C],EAX
0096CF70 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]
0096CF73 50 PUSH EAX
0096CF74 8B4424 18 MOV EAX,DWORD PTR SS:[ESP+18]
0096CF78 50 PUSH EAX
0096CF79 A1 B8A697>MOV EAX,DWORD PTR DS:[97A6B8]
0096CF7E 8B00 MOV EAX,DWORD PTR DS:[EAX]
0096CF80 FFD0 CALL EAX ; GetProcAddress
0096CF82 8BE8 MOV EBP,EAX
0096CF84 85ED TEST EBP,EBP
0096CF86 75 0C JNZ SHORT 0096CF94 ; 如果获取成功就跳
0096CF88 68 F8D096>PUSH 96D0F8 ; ASCII "250
"
0096CF8D E8 9E6BFF>CALL 00963B30
0096CF92 EB 15 JMP SHORT 0096CFA9
0096CF94 A1 ECA597>MOV EAX,DWORD PTR DS:[97A5EC]
0096CF99 3B28 CMP EBP,DWORD PTR DS:[EAX]
0096CF9B 75 0C JNZ SHORT 0096CFA9
0096CF9D 837B 34 0>CMP DWORD PTR DS:[EBX+34],0
0096CFA1 74 06 JE SHORT 0096CFA9
0096CFA3 8B6B 34 MOV EBP,DWORD PTR DS:[EBX+34]
0096CFA6 036B 40 ADD EBP,DWORD PTR DS:[EBX+40]
0096CFA9 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C] ; 到这里就是和AL=1的处理一样,这里就是第二个分支
0096CFAD 8928 MOV DWORD PTR DS:[EAX],EBP
0096CFAF 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
0096CFB3 8906 MOV DWORD PTR DS:[ESI],EAX
0096CFB5 0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]
0096CFBA 0143 08 ADD DWORD PTR DS:[EBX+8],EAX
0096CFBD ^ E9 B1FCFF>JMP 0096CC73
……
第二个分支的处理,这里很简单我们只改几行代码就行了,改成这样子:
0096CFA9 E8 923022>CALL 00B90040 ;和AL=1一样的处理
0096CFAE 90 NOP
0096CFAF 90 NOP
0096CFB0 90 NOP
0096CFB1 90 NOP
0096CFB2 90 NOP
0096CFB3 90 NOP
0096CFB4 90 NOP
这个程序里没有AL=3和AL=5的情况,所以我也就不多说了.
好了,处理完IAT后我们记住这里:
00963767 C603 E9 MOV BYTE PTR DS:[EBX],0E9
直接在这00963767处下断,然后运行,中断在这里后,我们就知道这里的[EBX]就是保存我们的目标程序的OEP,这个对DELPHI的程序就可能不止在这里中断一次,但跳去的地方一定是壳抽程序的代码。
00963756 8BC0 MOV EAX,EAX
00963758 55 PUSH EBP
00963759 8BEC MOV EBP,ESP
0096375B 53 PUSH EBX
0096375C 8BD8 MOV EBX,EAX
0096375E 8BC2 MOV EAX,EDX
00963760 8BD1 MOV EDX,ECX
00963762 E8 79FFFF>CALL 009636E0
00963767 C603 E9 MOV BYTE PTR DS:[EBX],0E9
0096376A 8D53 01 LEA EDX,DWORD PTR DS:[EBX+1] ; 这里原程跳就是壳抽程序代码的开始地方
0096376D 8902 MOV DWORD PTR DS:[EDX],EAX
0096376F 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
00963772 8910 MOV DWORD PTR DS:[EAX],EDX
00963774 B8 050000>MOV EAX,5
00963779 5B POP EBX
0096377A 5D POP EBP
0096377B C2 0400 RETN 4 ; 直接执行到这里,然后到4010cc处看看
……
004010CC - E9 48F177>JMP 00B80219 ; 这里跳去的地方就是壳抽程序的代码的开始处
004010D1 7D 5E JGE SHORT 00401131
004010D3 FF15 00C0>CALL DWORD PTR DS:[40C000] ; kernel32.GetCommandLineA
00B80219就是壳执行原程序的开始处.所以我们直接在00B80219处下个断,然后运行,再次中断后我们就可以比较直观的看到被抽的代码。
00B80219 55 PUSH EBP ; 在这里下断,这就是程序的第一行代码
00B8021A 336C24 08 XOR EBP,DWORD PTR SS:[ESP+8]
00B8021E 336C24 28 XOR EBP,DWORD PTR SS:[ESP+28]
00B80222 8BEC MOV EBP,ESP ; 第二行
……
00B80273 83EC 44 SUB ESP,44 ; 第三行
00B80276 56 PUSH ESI ; 最后一行代码
00B80277 ^ E9 ADFFFF>JMP 00B80229
这样程序被抽的代码就找回来的,当然,如果是加的DELPHI或其它的C的程序抽的代码就不是这么少了。
好了,现在我们被上代码,然后DUMP和修复一下就行了.
Greetz:
Fly.Jingulong,yock,tDasm.David.ahao.UFO(brother).alan(sister).all of my friends and you!
By loveboom[DFCG][FCG]
Email:bmd2chen@tom.com
附件:aspr.rar 附件:aspr.rar
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!