【破解作者】 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->函数名
看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~