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 ; LoadLibraryA7C801D79 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 POPAD009885C2 75 08 JNZ SHORT 009885CC ; 看到这里,跟过Aspack的朋友就是知道这里是什么了009885C4 B8 010000>MOV EAX,1009885C9 C2 0C00 RETN 0C009885CC 68 000000>PUSH 0 ; 如果解压完壳代码这里会push 一个返回的地址009885D1 C3 RETN返回到009884B7处后,右键查找全部字符串,然后在字符串窗中查找250这样就会看到这些东西:双击10那里到了cpu窗口处:0096CD66 /75 0A JNZ SHORT 0096CD720096CD68 |68 C8D096>PUSH 96D0C8 ; 双击到这里,这里向上找到代码开始处0096CD6D |E8 BE6DFF>CALL 00963B30向上找到这里:0096CC70 /EB 01 JMP SHORT 0096CC730096CC72 |90 NOP0096CC73 \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],40096CC7C 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],AL0096CC85 FF43 08 INC DWORD PTR DS:[EBX+8]0096CC88 85F6 TEST ESI,ESI0096CC8A 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 ; GetProcAddress0096CD62 8BE8 MOV EBP,EAX0096CD64 85ED TEST EBP,EBP0096CD66 75 0A JNZ SHORT 0096CD72 ; 判断获取API是否成功0096CD68 68 C8D096>PUSH 96D0C8 ; 双击到这里,这里向上找到代码开始处0096CD6D E8 BE6DFF>CALL 00963B300096CD72 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,EAX00963758 55 PUSH EBP00963759 8BEC MOV EBP,ESP0096375B 53 PUSH EBX0096375C 8BD8 MOV EBX,EAX0096375E 8BC2 MOV EAX,EDX00963760 8BD1 MOV EDX,ECX00963762 E8 79FFFF>CALL 009636E000963767 C603 E9 MOV BYTE PTR DS:[EBX],0E9 ; 先在这里也下个断,因为这里就是程序的OEP0096376A 8D53 01 LEA EDX,DWORD PTR DS:[EBX+1] ; 这里原程跳就是壳抽程序代码的开始地方0096376D 8902 MOV DWORD PTR DS:[EDX],EAX0096376F 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]00963772 8910 MOV DWORD PTR DS:[EAX],EDX00963774 B8 050000>MOV EAX,500963779 5B POP EBX0096377A 5D POP EBP0096377B C2 0400 RETN 40096377E 8BC0 MOV EAX,EAX00963780 53 PUSH EBX ; 进到这里00963781 8BD8 MOV EBX,EAX00963783 8BC3 MOV EAX,EBX00963785 E8 56FFFF>CALL 009636E00096378A C603 E8 MOV BYTE PTR DS:[EBX],0E8 ; 这里把IAT的改成call xxxxxx的样式,所以我们这里要进去处理0096378D 43 INC EBX0096378E 8903 MOV DWORD PTR DS:[EBX],EAX00963790 5B POP EBX00963791 C3 RETN现在这里我们来修复一下:先自己申请两块空间,当然你也可以直接找空闲的地方来写代码,我分别申请了00B90000和00BA0000这个块内存空间,00b90000这块是用来写patch代码,00ba0000是用来保存临时要存放的数据。00BA0000用来保存DLL的基址,00BA0010用来保存要存放IAT的地址。搞清这些东西后,我们开始写代码:00963781 8BD8 MOV EBX,EAX00963783 8BC3 MOV EAX,EBX00963785 E8 56FFFF>CALL 009636E00096378A E8 71C822>CALL 00B90000 ; 调用我们改的代码处0096378F 90 NOP00963790 5B POP EBX00963791 C3 RETN 00B90000用来写我们自己的修复代码:00B90000 51 PUSH ECX ; 保护现场00B90001 52 PUSH EDX00B90002 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+28] ; 取出基址到EDX中00B90006 3B15 0000>CMP EDX,DWORD PTR DS:[BA0000] ; 比较基址是否相同00B9000C 74 0D JE SHORT 00B9001B00B9000E 8915 0000>MOV DWORD PTR DS:[BA0000],EDX ; 如果不同就写入新的基址00B90014 8305 1000>ADD DWORD PTR DS:[BA0010],4 ; 并把填入IAT的地址再加上400B9001B 8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010] ; 如果是第一次我们要手工写一下保存IAT的地址,我选择的是40C00000B90021 8929 MOV DWORD PTR DS:[ECX],EBP ; 写入正确的函数00B90023 66:C703 F>MOV WORD PTR DS:[EBX],15FF ; 这里要看程序的情况而定,如果是DELPHI之类的,这果就可能是FF25了,因为是C的,所以这里是ff1500B90028 890E MOV DWORD PTR DS:[ESI],ECX ; 把存放IAT的地址放到程序里00B9002A 8305 1000>ADD DWORD PTR DS:[BA0010],4 ; 保存IAT的地址+400B90031 5A POP EDX ; 还原现场00B90032 59 POP ECX00B90033 C3 RETN ; 返回到壳那边继续 继续到AL=1时的处理:0096CE07 ^\E9 67FEFF>JMP 0096CC730096CE0C 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 ; GetProcAddress0096CE87 8BE8 MOV EBP,EAX0096CE89 85ED TEST EBP,EBP0096CE8B 75 0A JNZ SHORT 0096CE97 ; 如果获取成功就跳0096CE8D 68 D8D096>PUSH 96D0D8 ; ASCII "11"0096CE92 E8 996CFF>CALL 00963B300096CE97 8B0424 MOV EAX,DWORD PTR SS:[ESP]0096CE9A 50 PUSH EAX0096CE9B 68 08BC96>PUSH 96BC080096CEA0 8D4C24 20 LEA ECX,DWORD PTR SS:[ESP+20]0096CEA4 8BD5 MOV EDX,EBP0096CEA6 8BC3 MOV EAX,EBX0096CEA8 E8 BFF4FF>CALL 0096C36C0096CEAD 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],EAX0096CEB9 0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]0096CEBE 0143 08 ADD DWORD PTR DS:[EBX+8],EAX0096CEC1 ^ E9 ADFDFF>JMP 0096CC73 ; 处理完就跳回去当AL=1时的修复代码:0096CEA8 E8 BFF4FF>CALL 0096C36C0096CEAD E8 8E3122>CALL 00B900400096CEB2 90 NOP0096CEB3 90 NOP0096CEB4 90 NOP0096CEB5 90 NOP0096CEB6 90 NOP0096CEB7 90 NOP0096CEB8 90 NOP0096CEB9 0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]0096CEBE 0143 08 ADD DWORD PTR DS:[EBX+8],EAX0096CEC1 ^ E9 ADFDFF>JMP 0096CC73 00B90040处的修复代码:00B90040 51 PUSH ECX ; 保护现场00B90041 52 PUSH EDX00B90042 8B5424 20 MOV EDX,DWORD PTR SS:[ESP+20] ; 取出当然要处理DLL的基址00B90046 3B15 0000>CMP EDX,DWORD PTR DS:[BA0000] ; 比较基址是否相同00B9004C 74 0D JE SHORT 00B9005B00B9004E 8915 0000>MOV DWORD PTR DS:[BA0000],EDX00B90054 8305 1000>ADD DWORD PTR DS:[BA0010],400B9005B 8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010] ; 1.0040C00400B90061 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],400B9006C 5A POP EDX00B9006D 59 POP ECX ; 还原现场00B9006E C3 RETN ; 执行到返回到了AL=4的处理了:0096CEC6 3C 04 CMP AL,4 ; 当AL为4有两个分支0096CEC8 0F85 F400>JNZ 0096CFC20096CECE EB 01 JMP SHORT 0096CED10096CED0 90 NOP0096CED1 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,AL0096CEDB 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],40096CEE6 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],40096CEEF 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],EAX0096CEF8 8343 08 0>ADD DWORD PTR DS:[EBX+8],40096CEFC 837B 30 0>CMP DWORD PTR DS:[EBX+30],00096CF00 75 0A JNZ SHORT 0096CF0C0096CF02 68 E8D096>PUSH 96D0E8 ; ASCII "81"0096CF07 E8 246CFF>CALL 00963B300096CF0C 8D5424 30 LEA EDX,DWORD PTR SS:[ESP+30]0096CF10 8BC3 MOV EAX,EBX0096CF12 E8 8DF8FF>CALL 0096C7A4 ; 这个CALL要进去,因为这里面就是计算将要保存IAT的地址进去看看先:0096C7A4 53 PUSH EBX0096C7A5 56 PUSH ESI0096C7A6 8BF2 MOV ESI,EDX0096C7A8 8BD8 MOV EBX,EAX0096C7AA B8 040000>MOV EAX,40096C7AF E8 985DFE>CALL 0095254C0096C7B4 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],EAX0096C7BC 5E POP ESI0096C7BD 5B POP EBX0096C7BE C3 RETN这里处理第一个分支先,第二个分支我们可以完全调用AL=1时的代码,AL=4第一个分支的修复代码:0096C7A4 53 PUSH EBX0096C7A5 56 PUSH ESI0096C7A6 8BF2 MOV ESI,EDX0096C7A8 8BD8 MOV EBX,EAX0096C7AA B8 040000>MOV EAX,40096C7AF E8 985DFE>CALL 0095254C0096C7B4 E8 C13822>CALL 00B9007A0096C7B9 8946 04 MOV DWORD PTR DS:[ESI+4],EAX0096C7BC 5E POP ESI0096C7BD 5B POP EBX0096C7BE C3 RETN 00B9007A的修复代码:00B9007A 51 PUSH ECX ; 保护现场00B9007B 52 PUSH EDX00B9007C 8B5424 2C MOV EDX,DWORD PTR SS:[ESP+2C] ; 取出当然要处理DLL的基址00B90080 3B15 0000>CMP EDX,DWORD PTR DS:[BA0000] ; kernel32.7C80000000B90086 74 0D JE SHORT 00B9009500B90088 8915 0000>MOV DWORD PTR DS:[BA0000],EDX00B9008E 8305 1000>ADD DWORD PTR DS:[BA0010],400B90095 8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010] ; 1.0040C02000B9009B 890E MOV DWORD PTR DS:[ESI],ECX ; 取出我们要保存IAT的址址到[ESI]中00B9009D 8305 1000>ADD DWORD PTR DS:[BA0010],400B900A4 5A POP EDX00B900A5 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 EAX0096CF1C 8D4424 34 LEA EAX,DWORD PTR SS:[ESP+34]0096CF20 50 PUSH EAX0096CF21 55 PUSH EBP0096CF22 A1 70A597>MOV EAX,DWORD PTR DS:[97A570]0096CF27 8B00 MOV EAX,DWORD PTR DS:[EAX]0096CF29 50 PUSH EAX0096CF2A 56 PUSH ESI0096CF2B 8B4424 28 MOV EAX,DWORD PTR SS:[ESP+28]0096CF2F 50 PUSH EAX0096CF30 FF53 30 CALL DWORD PTR DS:[EBX+30] ; 这里计算函数并写入地址0096CF33 ^ E9 3BFDFF>JMP 0096CC730096CF38 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]0096CF3B 8B00 MOV EAX,DWORD PTR DS:[EAX]0096CF3D 890424 MOV DWORD PTR SS:[ESP],EAX0096CF40 8343 08 0>ADD DWORD PTR DS:[EBX+8],40096CF44 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],AX0096CF4F 8343 08 0>ADD DWORD PTR DS:[EBX+8],20096CF53 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 00967AF40096CF63 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+10]0096CF67 E8 E055FE>CALL 0095254C0096CF6C 894424 0C MOV DWORD PTR SS:[ESP+C],EAX0096CF70 8B43 08 MOV EAX,DWORD PTR DS:[EBX+8]0096CF73 50 PUSH EAX0096CF74 8B4424 18 MOV EAX,DWORD PTR SS:[ESP+18]0096CF78 50 PUSH EAX0096CF79 A1 B8A697>MOV EAX,DWORD PTR DS:[97A6B8]0096CF7E 8B00 MOV EAX,DWORD PTR DS:[EAX]0096CF80 FFD0 CALL EAX ; GetProcAddress0096CF82 8BE8 MOV EBP,EAX0096CF84 85ED TEST EBP,EBP0096CF86 75 0C JNZ SHORT 0096CF94 ; 如果获取成功就跳0096CF88 68 F8D096>PUSH 96D0F8 ; ASCII "250"0096CF8D E8 9E6BFF>CALL 00963B300096CF92 EB 15 JMP SHORT 0096CFA90096CF94 A1 ECA597>MOV EAX,DWORD PTR DS:[97A5EC]0096CF99 3B28 CMP EBP,DWORD PTR DS:[EAX]0096CF9B 75 0C JNZ SHORT 0096CFA90096CF9D 837B 34 0>CMP DWORD PTR DS:[EBX+34],00096CFA1 74 06 JE SHORT 0096CFA90096CFA3 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],EBP0096CFAF 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]0096CFB3 8906 MOV DWORD PTR DS:[ESI],EAX0096CFB5 0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]0096CFBA 0143 08 ADD DWORD PTR DS:[EBX+8],EAX0096CFBD ^ E9 B1FCFF>JMP 0096CC73……第二个分支的处理,这里很简单我们只改几行代码就行了,改成这样子:0096CFA9 E8 923022>CALL 00B90040 ;和AL=1一样的处理0096CFAE 90 NOP0096CFAF 90 NOP0096CFB0 90 NOP0096CFB1 90 NOP0096CFB2 90 NOP0096CFB3 90 NOP0096CFB4 90 NOP这个程序里没有AL=3和AL=5的情况,所以我也就不多说了.好了,处理完IAT后我们记住这里:00963767 C603 E9 MOV BYTE PTR DS:[EBX],0E9直接在这00963767处下断,然后运行,中断在这里后,我们就知道这里的[EBX]就是保存我们的目标程序的OEP,这个对DELPHI的程序就可能不止在这里中断一次,但跳去的地方一定是壳抽程序的代码。00963756 8BC0 MOV EAX,EAX00963758 55 PUSH EBP00963759 8BEC MOV EBP,ESP0096375B 53 PUSH EBX0096375C 8BD8 MOV EBX,EAX0096375E 8BC2 MOV EAX,EDX00963760 8BD1 MOV EDX,ECX00963762 E8 79FFFF>CALL 009636E000963767 C603 E9 MOV BYTE PTR DS:[EBX],0E90096376A 8D53 01 LEA EDX,DWORD PTR DS:[EBX+1] ; 这里原程跳就是壳抽程序代码的开始地方0096376D 8902 MOV DWORD PTR DS:[EDX],EAX0096376F 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]00963772 8910 MOV DWORD PTR DS:[EAX],EDX00963774 B8 050000>MOV EAX,500963779 5B POP EBX0096377A 5D POP EBP0096377B C2 0400 RETN 4 ; 直接执行到这里,然后到4010cc处看看……004010CC - E9 48F177>JMP 00B80219 ; 这里跳去的地方就是壳抽程序的代码的开始处004010D1 7D 5E JGE SHORT 00401131004010D3 FF15 00C0>CALL DWORD PTR DS:[40C000] ; kernel32.GetCommandLineA00B80219就是壳执行原程序的开始处.所以我们直接在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:
[email protected]
本文地址:http://com.8s8s.com/it/it22376.htm