【破解作者】 Pr0Zel
【使用工具】 OllyDbg,PEid,LoadPE
【破解平台】 Win2K+SP4
【软件名称】 大嘴日语 5.0
【下载地址】 http://www.onlinedown.net/soft/4089.htm
【软件简介】 大嘴日语 融合了【逆向学习法】和【疯狂英语】这两种有效的英语学习方法的精髓,
并加以创新,集日语的【听、说、读、写、背、查】功能于一身, 解决了困扰国人的学习日语难的问题。
是一款集日语口语、日语背单词综合教育软件。
【软件大小】 4.3M
【加壳方式】 EXEStealth 2.75a + ASPack + UPX
【破解声明】 我是一只小菜鸟,偶得一点心得,愿与大家分享:)
开始调试前,最好把OLLYDBG.EXE改名为CMD.EXE因为壳里面有些代码是检测父进程的,如下:
0123CCA0 813F 434D442E cmp dword ptr ds:[edi],2E444D43 ; [EDI]是检测父程序名字, 0x43,0x4D,0x44,0x2E的ASCII字符是"CMD."
0123CCA6 74 3B je short BmJapane.0123CCE3 ; 父程序不是CMD.EXE,就不跳,接着就OVER了 修改ZF寄存器为1
0123CCA8 90 nop
0123CCA9 90 nop
0123CCAA 90 nop
0123CCAB 90 nop
0123CCAC 83EE 0C sub esi,0C
0123CCAF AD lods dword ptr ds:[esi]
0123CCB0 0306 add eax,dword ptr ds:[esi]
0123CCB2 0346 04 add eax,dword ptr ds:[esi+4]
0123CCB5 8BD8 mov ebx,eax
0123CCB7 8DB5 A1194100 lea esi,dword ptr ss:[ebp+4119A1]
0123CCBD AD lods dword ptr ds:[esi]
0123CCBE 0BC0 or eax,eax
0123CCC0 74 0E je short BmJapane.0123CCD0
0123CCC2 90 nop
0123CCC3 90 nop
0123CCC4 90 nop
0123CCC5 90 nop
0123CCC6 2BC3 sub eax,ebx
0123CCC8 74 19 je short BmJapane.0123CCE3
0123CCCA 90 nop
0123CCCB 90 nop
0123CCCC 90 nop
0123CCCD 90 nop
0123CCCE ^ EB ED jmp short BmJapane.0123CCBD
0123CCD0 B8 90010000 mov eax,190
0123CCD5 E8 C6EFFFFF call BmJapane.0123BCA0
0123CCDA 8DBD 69324000 lea edi,dword ptr ss:[ebp+403269]
0123CCE0 03F8 add edi,eax
0123CCE2 AB stos dword ptr es:[edi] ; 若是前面不跳的话,到这里调试器就会无法处理异常,进程退出
0123CCE3 FFB5 30FE4000 push dword ptr ss:[ebp+40FE30] ; 跳到这里
0123CCE9 50 push eax
另把同目录下的Config.ini文件备份一个,当出来说文件不完整要重新安装程序的时候
把备份文件覆盖了Config文件就行了;
---------------------------------------------------------------------------------------------------------
用OD载入程序,停在这里:(第一层壳 EXEStealth)
0124A060 > /EB 58 jmp short BmJapane.0124A0BA
0124A062 |53 push ebx
0124A063 |68 61726577 push 77657261
0124A068 |61 popad
0124A069 |72 65 jb short BmJapane.0124A0D0
忽略除内存异常外的所有异常,经过5个内存异常(按4次Shift+F9)后来到这里:
0078700D 64:8925 0000000>mov dword ptr fs:[0],esp
00787014 33C0 xor eax,eax
00787016 8908 mov dword ptr ds:[eax],ecx ; 内存异常
00787018 0000 add byte ptr ds:[eax],al
0078701A 0000 add byte ptr ds:[eax],al
此时的堆栈是:
0012FFBC FFFFFFFF End of SEH chain
0012FFC0 00D9DAA8 SE handler
0012FFC4 7C4E87F5 RETURN to kernel32.7C4E87F5
0012FFC8 005616A8 BmJapane.005616A8
在D9DAA8上下断点,按Shift+F9
00D9DAA8 B8 A7C8D9F0 mov eax,F0D9C8A7
00D9DAAD 8D88 24120010 lea ecx,dword ptr ds:[eax+10001224]
00D9DAB3 8941 01 mov dword ptr ds:[ecx+1],eax
00D9DAB6 8B5424 04 mov edx,dword ptr ss:[esp+4]
00D9DABA 8B52 0C mov edx,dword ptr ds:[edx+C]
00D9DABD C602 E9 mov byte ptr ds:[edx],0E9
00D9DAC0 83C2 05 add edx,5
00D9DAC3 2BCA sub ecx,edx
00D9DAC5 894A FC mov dword ptr ds:[edx-4],ecx
00D9DAC8 33C0 xor eax,eax
00D9DACA C3 retn
走到RETN后,看原地址的代码:
0078700D 64:8925 0000000>mov dword ptr fs:[0],esp
00787014 33C0 xor eax,eax
00787016 - E9 B06A6100 jmp BmJapane.00D9DACB ; 在这里下断点,程序断在这里,然后把标志寄存器的TP置0,继续运行
0078701B 0000 add byte ptr ds:[eax],al
0078701D 0000 add byte ptr ds:[eax],al
00D9DACA C3 retn
00D9DACB B8 A7C8D9F0 mov eax,F0D9C8A7 ; 原来跳到这里了
00D9DAD0 64:8F05 0000000>pop dword ptr fs:[0]
00D9DAD7 83C4 04 add esp,4
00D9DADA 55 push ebp
00D9DADB 53 push ebx
00D9DADC 51 push ecx
00D9DADD 57 push edi
00D9DADE 56 push esi
00D9DADF 52 push edx
00D9DAE0 8D98 DD110010 lea ebx,dword ptr ds:[eax+100011DD]
一直走到这里:
00D9DB70 5E pop esi
00D9DB71 5F pop edi
00D9DB72 59 pop ecx
00D9DB73 5B pop ebx
00D9DB74 5D pop ebp
00D9DB75 - FFE0 jmp eax ; EAX=B55001
---------------------------------------------------------------------------------------------------------
又跳到下一层去了,貌似是ASPack壳
00B55001 60 pushad
00B55002 E8 03000000 call BmJapane.00B5500A
00B55007 - E9 EB045D45 jmp 461254F7
00B5500C 55 push ebp
00B5500D C3 retn
00B5500E E8 01000000 call BmJapane.00B55014
00B55013 EB 5D jmp short BmJapane.00B55072
直接用Ctrl+S来找popad
来到这里:
00B553A9 8985 A8030000 mov dword ptr ss:[ebp+3A8],eax
00B553AF 61 popad
00B553B0 75 08 jnz short BmJapane.00B553BA
00B553B2 B8 01000000 mov eax,1
00B553B7 C2 0C00 retn 0C
00B553BA 68 00000000 push 0 ; 运行到这里会变成push 90fc10
00B553BF C3 retn
---------------------------------------------------------------------------------------------------------
到达下一层壳,是UPX壳
0090FC10 60 pushad
0090FC11 BE 00707800 mov esi,BmJapane.00787000
0090FC16 8DBE 00A0C7FF lea edi,dword ptr ds:[esi+FFC7A000]
0090FC1C 57 push edi
0090FC1D 83CD FF or ebp,FFFFFFFF
0090FC20 EB 10 jmp short BmJapane.0090FC32
0090FC22 90 nop
0090FC23 90 nop
0090FC24 90 nop
0090FC25 90 nop
0090FC26 90 nop
0090FC27 90 nop
0090FC28 8A06 mov al,byte ptr ds:[esi]
0090FC2A 46 inc esi
0090FC2B 8807 mov byte ptr ds:[edi],al
0090FC2D 47 inc edi
0090FC2E 01DB add ebx,ebx
0090FC30 75 07 jnz short BmJapane.0090FC39
同样往下找popad,找到如下:
0090FD9B 66:8B07 mov ax,word ptr ds:[edi]
0090FD9E 83C7 02 add edi,2
0090FDA1 ^ EB E2 jmp short BmJapane.0090FD85
0090FDA3 61 popad
0090FDA4 ^ E9 8B1DD7FF jmp BmJapane.00681B34
---------------------------------------------------------------------------------------------------------
到达程序的OPE了,用OllDump把程序DUMP出来,用LordPE来DUMP也行,不过要用IR修复一下IAT
00681B34 55 push ebp
00681B35 8BEC mov ebp,esp
00681B37 83C4 F0 add esp,-10
00681B3A 53 push ebx
00681B3B B8 9C146800 mov eax,BmJapane.0068149C
00681B40 E8 175DD8FF call BmJapane.0040785C
00681B45 8B1D D0906800 mov ebx,dword ptr ds:[6890D0] ; BmJapane.0068AC18
00681B4B 8B03 mov eax,dword ptr ds:[ebx]
00681B4D E8 CE22E1FF call BmJapane.00493E20
00681B52 8B03 mov eax,dword ptr ds:[ebx]
00681B54 BA 7C1E6800 mov edx,BmJapane.00681E7C
00681B59 E8 AA1EE1FF call BmJapane.00493A08
00681B5E 8B0B mov ecx,dword ptr ds:[ebx]
---------------------------------------------------------------------------------------------------------
运行一下,程序报错
"Access violation at address 1000100A. Read of address 1000100A."
用LordPE看看内存空间:
ListView的Item总数: 26
-------------------------
Path ImageBase ImageSize
-------------------------------------------------------------------------------
d:\bmjapanese\bmjapanese.exe 00400000 00001000
c:\winnt\system32\ntdll.dll 77F80000 0007B000
c:\winnt\system32\kernel32.dll 7C4E0000 000B9000
c:\winnt\system32\user32.dll 77E10000 00065000
c:\winnt\system32\gdi32.dll 77F40000 0003C000
c:\winnt\system32\imm32.dll 75E60000 0001A000
c:\winnt\system32\advapi32.dll 7C2D0000 00062000
c:\winnt\system32\rpcrt4.dll 77D30000 00071000
d:\bmjapanese\data\data.dat 10000000 00037000
c:\winnt\system32\comctl32.dll 71710000 00084000
c:\winnt\system32\comdlg32.dll 76B30000 0003E000
c:\winnt\system32\shlwapi.dll 70BD0000 00065000
c:\winnt\system32\msvcrt.dll 78000000 00045000
c:\winnt\system32\shell32.dll 782F0000 00248000
c:\winnt\system32\hhctrl.ocx 5D300000 00080000
c:\winnt\system32\ole32.dll 77A50000 000F7000
c:\winnt\system32\oleaut32.dll 779B0000 0009B000
c:\winnt\system32\msacm32.dll 77410000 00013000
c:\winnt\system32\winmm.dll 77570000 00030000
c:\winnt\system32\version.dll 77820000 00007000
c:\winnt\system32\lz32.dll 759B0000 00006000
c:\winnt\system32\winspool.drv 77800000 0001E000
c:\winnt\system32\mpr.dll 76620000 00011000
c:\winnt\system32\wsock32.dll 75050000 00008000
c:\winnt\system32\ws2_32.dll 75030000 00014000
c:\winnt\system32\ws2help.dll 75020000 00008000
地址是data.dat的空间,用PEID一查,是个ASPack壳的DLL文件,查输出表,只有两个函数,
分别是HDSerialNumRead和WEP
还差一个DLL没有LOAD进去,当然会出错了.
重新载入原文件,下LoadLibraryA断点,经过几次后,断在这里:
01240873 53 push ebx
01240874 FF95 94E24100 call dword ptr ss:[ebp+41E294] ; LoadLibraryA .dat\data\data.dat
0124087A 0BC0 or eax,eax
0124087C 75 34 jnz short BmJapane.012408B2
然后来到这里:
01240941 53 push ebx
01240942 FFB5 17FC4000 push dword ptr ss:[ebp+40FC17]
01240948 FF95 8CE24100 call dword ptr ss:[ebp+41E28C] ; kernel32.GetProcAddress
0124094E 3B9D 1FFC4000 cmp ebx,dword ptr ss:[ebp+40FC1F]
得到HDSerialNumRead的地址
用Alt+M,打开内存镜像,
在10001000处按F2下断点,取消刚才的LoadLibraryA断点,按F9,来到这里
10001003 CC int3
10001004 CC int3
10001005 E9 66010000 jmp data.10001170
1000100A > E9 310B0000 jmp data.10001B40 -|jmp
1000100F > E9 3C0C0000 jmp data.10001C50
10001014 E9 C7030000 jmp data.100013E0
10001019 E9 52000000 jmp data.10001070
1000101E E9 0D020000 jmp data.10001230
10001023 E9 78080000 jmp data.100018A0
10001028 E9 93020000 jmp data.100012C0
1000102D E9 BE040000 jmp data.100014F0
10001032 E9 89070000 jmp data.100017C0
10001037 CC int3
10001038 CC int3
----------------------------------------------------|
10001B40 55 push ebp
10001B41 8BEC mov ebp,esp
10001B43 81EC D4070000 sub esp,7D4
10001B49 53 push ebx
10001B4A 56 push esi
按CTRL+F9,然后返回主程序:
0059C567 8D45 C4 lea eax,dword ptr ss:[ebp-3C]
0059C56A E8 518AE6FF call BmJapane.00404FC0
0059C56F E8 D0F1FFFF call BmJapane.0059B744 ; jmp to data.HDSerialNumRead
0059C574 8BD0 mov edx,eax
0059C576 8D45 C4 lea eax,dword ptr ss:[ebp-3C]
原来CALL 59B744是data.HDSerialNumRead的函数的地址CALL,直接到上面看看:
0059B744 - FF25 2CCC6800 jmp dword ptr ds:[68CC2C] ; data.HDSerialNumRead
嗯,只要把68CC20填充为正确的地址就可以了
用OD载入DUMP出来的程序,下断点LoadLibraryA,程序中断后按Alt+F9返回用户代码:
0047E97B /0F85 EE000000 jnz oll.0047EA6F
0047E981 |68 ACEA4700 push oll.0047EAAC ; ASCII "imm32.dll"
0047E986 |E8 D594F8FF call <jmp.&kernel32.LoadLibraryA>
0047E98B |A3 88326800 mov dword ptr ds:[683288],eax ; IMM32.75E60000
0047E990 |833D 88326800 0>cmp dword ptr ds:[683288],0
0047E997 |0F84 D2000000 je oll.0047EA6F
往下找代码,找到出口处:
0047EA8D 5B pop ebx ; USER32.77E10000
0047EA8E 59 pop ecx
0047EA8F 5D pop ebp
0047EA90 C3 retn
0047EA91 0000 add byte ptr ds:[eax],al
找一个地方加上自己的代码:
区块ExeS已经不用了,正好用来写代码:
注:LoadLibraryA的CALL是"call 00407E60" ;GetProcAddress的CALL是"call 00407D50"
情况不同者要相应作出修改.
0047EA8D - E9 6EB5DC00 jmp oll.0124A000
0047EA92 C3 retn
0124A000 68 30A02401 push oll.0124A030 ; ASCII ".\data\Data.dat"
0124A005 E8 56DE1BFF call <jmp.&kernel32.LoadLibraryA>
0124A00A 68 40A02401 push oll.0124A040 ; ASCII "HDSerialNumRead"
0124A00F 50 push eax ; EAX是LoadLibraryA后的DLL句柄
0124A010 E8 3BDD1BFF call <jmp.&kernel32.GetProcAddress>
0124A015 A3 2CCC6800 mov dword ptr ds:[68CC2C],eax
0124A01A 5B pop ebx
0124A01B 59 pop ecx
0124A01C 5D pop ebp
0124A01D 90 nop
0124A01E - E9 6F4A23FF jmp oll.0047EA92
0124A023 90 nop
---------------------------------------------------------------------------------------------------------
去程序的ANTI代码
0067D1E9 ^\EB CE jmp short dumped.0067D1B9
0067D1EB E8 80C4E4FF call dumped.004C9670
0067D1F0 68 FFFF0000 push 0FFFF
0067D1F5 6A 0D push 0D
0067D1F7 E8 7CB2D8FF call <jmp.&user32.ExitWindowsEx> ; 关机了~
0067D1FC E9 CD060000 jmp dumped.0067D8CE
这样危险的API当然不能让程序乱用的,要它指向自己的代码,直接在IAT里面改:
0067D1F7 E8 7CB2D8FF call <jmp.&user32.ExitWindowsEx> 本来是 call 00408478
去408478上看看:
00408478 - FF25 50C96800 jmp dword ptr ds:[<&user32.ExitWindowsEx>; user32.ExitWindowsEx
自己写的代码:
0124A000 83C4 0C add esp,0C
0124A003 FF7424 F4 push dword ptr ss:[esp-C] ; 还原调用CALL以后RETN的地址
0124A007 C3 retn
更改IAT表:
00408478 - E9 831BE400 jmp exit_fix.0124A000
0040847D 90 nop
运行,程序OK,....
脱壳完成
后记,EXEStealth的IAT还原部分,比较有趣:
00FDE535 8B07 mov eax,dword ptr ds:[edi] ; EDI是加密函数名结构(可以这样说)的基地址
00FDE537 09C0 or eax,eax
00FDE539 74 3C je short BmJapane.00FDE577 ; IAT表是否填充完成,完成的话跳
00FDE53B 8B5F 04 mov ebx,dword ptr ds:[edi+4]
00FDE53E 8D8430 BC43BE00 lea eax,dword ptr ds:[eax+esi+BE43BC]
00FDE545 01F3 add ebx,esi
00FDE547 50 push eax
00FDE548 83C7 08 add edi,8 ; 函数名结构基地址+8byte,指向第3项
00FDE54B FF96 1045BE00 call dword ptr ds:[esi+BE4510] ; LoadLibraryA
00FDE551 95 xchg eax,ebp
00FDE552 8A07 mov al,byte ptr ds:[edi] ; 读取第3项数值
00FDE554 47 inc edi ; 函数名结构基地址+1,指向第4项,即函数名
00FDE555 08C0 or al,al ; 看AL(函数名第3项)是否为空
00FDE557 ^ 74 DC je short BmJapane.00FDE535
00FDE559 89F9 mov ecx,edi ; 读取函数名,放入ECX里面
00FDE55B 57 push edi ; 函数名
00FDE55C 48 dec eax
00FDE55D F2:AE repne scas byte ptr es:[edi] ; 这条指令作用实际上是计算下一个函数的基地址
00FDE55F 55 push ebp
00FDE560 FF96 1445BE00 call dword ptr ds:[esi+BE4514] ; GetProcAddress
00FDE566 09C0 or eax,eax
00FDE568 74 07 je short BmJapane.00FDE571 ; 正常情况下不会跳下去的,这里是处理无法取得函数地址的情况
00FDE56A 8903 mov dword ptr ds:[ebx],eax ; 取得地址后填充到[ebx]里面(IAT表)
00FDE56C 83C3 04 add ebx,4 ; IAT表地址+4bytes
00FDE56F ^ EB E1 jmp short BmJapane.00FDE552
以下是其中一个函数的函数结构,与上面联系的:
35 02 00 00 24 B9 99 00 01 61 63 6D 4D 65 74 72 5..$?.acmMetr
|----1----| |----2----| 3 |----4-----
69 63 73 ics
------|
1->用lea eax,dword ptr ds:[eax+esi+BE43BC]来标志该函数是哪个DLL文件里面的,把DLL文件的地址传给EAX
2-> 这部分加上基地址(401000)后用为填充程序IAT表的地址
3->标识函数所在的DLL是否与前一个函数的DLL相同
4->函数名
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!