宝宝取名软件V17.0破解笔记
首先脱壳。ASPack的壳,VC++编写的程序。
运行后如图:
标题有文字“试用版”,于是我们查找字符串,在所有出现“试用版”的地方下断点,然后运行OD,断在这里:
004686D9 . 895D B8 MOV DWORD PTR SS:[EBP-48],EBX
004686DC . 68 26275F00 PUSH Unpacked.005F2726 ; / (试用版)
004686E1 . 8B5D B8 MOV EBX,DWORD PTR SS:[EBP-48] ; |
然后拉到段首,下断,重新来跟一下。断首位置为:
004681F7 $ 55 PUSH EBP
004681F8 . 8BEC MOV EBP,ESP
004681FA . 81EC 58000000 SUB ESP,58
单步走来到关键代码处:
0046834D . 83C4 18 ADD ESP,18
00468350 . E8 4193F9FF CALL Unpacked.00401696 ; 关键CALL
00468355 . 85C0 TEST EAX,EAX
00468357 . 0F84 6A030000 JE Unpacked.004686C7 ; 关键跳,跳了就出错,EAX要为1才注册成功
0046835D . C705 4C938C00>MOV DWORD PTR DS:[8C934C],1
00468367 . 8B1D 2C928C00 MOV EBX,DWORD PTR DS:[8C922C]
0046836D . 895D BC MOV DWORD PTR SS:[EBP-44],EBX
00468370 . 8B1D 2C928C00 MOV EBX,DWORD PTR DS:[8C922C]
00468376 . 83C3 08 ADD EBX,8
00468379 . 895D B8 MOV DWORD PTR SS:[EBP-48],EBX
0046837C . 68 46275E00 PUSH Unpacked.005E2746 ; / (已注册)
00468381 . 8B5D B8 MOV EBX,DWORD PTR SS:[EBP-48] ; |
00468384 . FF33 PUSH DWORD PTR DS:[EBX] ; |Arg3
00468386 . 68 D6265E00 PUSH Unpacked.005E26D6 ; | v
好,我们直接在关键CALL处下好断,重新来过,进入CALL看看。在CALL的最后几句分析了一下:
00401735 |. 50 PUSH EAX
00401736 |. E8 950B0000 CALL Unpacked.004022D0 ; 由下面分析得这里为关键算法CALL
0040173B |. 8945 EC MOV DWORD PTR SS:[EBP-14],EAX ; 这里EAX给EBP-14
0040173E |. 8B5D F0 MOV EBX,DWORD PTR SS:[EBP-10]
00401741 |. 85DB TEST EBX,EBX
00401743 |. 74 09 JE SHORT Unpacked.0040174E
00401745 |. 53 PUSH EBX
00401746 |. E8 76A60B00 CALL Unpacked.004BBDC1
0040174B |. 83C4 04 ADD ESP,4
0040174E |> 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14] ; 这里EBP-14给EAX
00401751 |. E9 00000000 JMP Unpacked.00401756
00401756 |> 8BE5 MOV ESP,EBP
00401758 |. 5D POP EBP
00401759 \. C3 RETN
这里要让EAX最后为1才能注册成功。观察最后的代码,发现最后决定EAX值的是这里“00401736 |. E8 950B0000 CALL Unpacked.004022D0 ; 由下面分析得这里为关键算法CALL
”,然后我们进去看看。
这个“004022D0”地址的算法CALL代码相当长,我刚开始跟的时候就跟得不耐烦了。
终于我们找到了段尾处:
00404142 > \8B5D C4 MOV EBX,DWORD PTR SS:[EBP-3C]
00404145 . 85DB TEST EBX,EBX
00404147 . 74 09 JE SHORT Unpacked.00404152
00404149 . 53 PUSH EBX
0040414A . E8 727C0B00 CALL Unpacked.004BBDC1
0040414F . 83C4 04 ADD ESP,4 ; ESP赋为4
00404152 > 58 POP EAX
00404153 . 8BE5 MOV ESP,EBP ; 又把EBP给ESP,故上面那个ESP=4没用
00404155 . 5D POP EBP
00404156 . C2 0800 RETN 8
分析后就把
0040414F . 83C4 04 ADD ESP,4 ; ESP赋为4
00404152 > 58 POP EAX
00404153 . 8BE5 MOV ESP,EBP ; 又把EBP给ESP,故上面那个ESP=4没用
直接改成:
0040414F B8 01000000 MOV EAX,1 ; 直接让EAX为1
00404154 90 NOP
后面才发现,这样改是不行的,程序运行后就会出错。
然后我又尝试在算法CALL里面改代码,结果都不行,不管改哪都会使程序出错。
那就不改算法CALL了吧,直接改关键CALL里面。
这样改了之后,程序的第一次启动验证就OK了,标题已经显示为“已注册”,但是点击“注册”和其它的功能按钮后,程序依然会出错。
后来分析了一晚上,第二天早上才搞出来。原来这个软件有点变态,它的每一处都会有验证注册的代码。每一次都重新验证,而且还不是调用同一个地址的函数进行验证。
但是最终都是调用了算法CALL,关键不一样。于是我们选中算法CALL,右键->查找参考->调用目的地址。在每一处调用地方都下断点。在搜索出来的结果中右键->在每个命令上设置断点。
这时,运行起来。程序运行后会再次调用这个CALL以确定是否注册,如果没注册就弹出注册框。这个验证我们暂时不管,直接F9运行。当程序完全运行起来后,我们点击“生成”按钮,断下来后,执行到返回,来到如下代码:
0048B9AE |> \E8 E35CF7FF CALL Unpacked.00401696 ; 关键CALL
0048B9B3 |. 85C0 TEST EAX,EAX
0048B9B5 |. 0F84 17000000 JE Unpacked.0048B9D2
0048B9BB |. E8 34D5F9FF CALL Unpacked.00428EF4 ; 关键CALL
0048B9C0 |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
0048B9C3 |. 837D F8 00 CMP DWORD PTR SS:[EBP-8],0
0048B9C7 |. 0F85 05000000 JNZ Unpacked.0048B9D2
0048B9CD |. E8 D755FFFF CALL Unpacked.00480FA9
0048B9D2 |> E8 BF5CF7FF CALL Unpacked.00401696 ; 关键CALL
0048B9D7 |. 85C0 TEST EAX,EAX
0048B9D9 |. 0F84 17000000 JE Unpacked.0048B9F6
0048B9DF |. E8 B3D5F8FF CALL Unpacked.00418F97 ; 关键CALL
0048B9E4 |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
0048B9E7 |. 837D F8 00 CMP DWORD PTR SS:[EBP-8],0
0048B9EB |. 0F85 05000000 JNZ Unpacked.0048B9F6
0048B9F1 |. E8 846CFAFF CALL Unpacked.0043267A
0048B9F6 |> E8 9B5CF7FF CALL Unpacked.00401696 ; 关键CALL
0048B9FB |. 85C0 TEST EAX,EAX
0048B9FD |. 0F84 17000000 JE Unpacked.0048BA1A
0048BA03 |. E8 85D0FCFF CALL Unpacked.00458A8D ; 关键CALL
0048BA08 |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
0048BA0B |. 837D F8 00 CMP DWORD PTR SS:[EBP-8],0
0048BA0F |. 0F85 05000000 JNZ Unpacked.0048BA1A
0048BA15 |. E8 F619FDFF CALL Unpacked.0045D410 ; 关键CALL
0048BA1A |> E8 775CF7FF CALL Unpacked.00401696
0048BA1F |. 85C0 TEST EAX,EAX
0048BA21 |. 0F84 17000000 JE Unpacked.0048BA3E
0048BA27 |. E8 3711FBFF CALL Unpacked.0043CB63
发现这里一口气程序调用了好多次验证注册的算法CALL,每次关键CALL的地址都不一样,但都是调用了算法CALL。
不管它,直接运行,断下后,返回,再运行,一直来到如下代码:
0047BE6C |. E8 2558F8FF CALL Unpacked.00401696 ; 关键CALL
0047BE71 |. 85C0 TEST EAX,EAX
0047BE73 |. 0F84 DF1E0000 JE Unpacked.0047DD58 ; 未注册就跳
0047BE79 |. E8 FEFBFDFF CALL Unpacked.0045BA7C
这里的JE不能让它跳。
同理,下面这个也不能让它跳:
0047BEAB |. 3BC8 CMP ECX,EAX
0047BEAD |. 0F8F 9D1E0000 JG Unpacked.0047DD50 ; 不能跳
0047BEB3 |. 68 00000000 PUSH 0
一直执行到这里,这里有非常多的验证CALL与跳,非常多。多从来没有单步走完过。
分析到这里,就知道这个软件有非常多个,至少有一百多个重复验证注册的地址,每个验证的CALL都会调用算法CALL,算法CALL我们不能改,改了程序就不能运行。于是我们得在每一个关键CALL里面改,下面是一个关键CALL的改法。
由于所有的关键CALL结构类似,于是我们可以查找所有要改的地方 ,Ctrl+B,输入二进制“8B 45 EC E9”也就是
0047E4CF |> \8B45 EC MOV EAX,DWORD PTR SS:[EBP-14] ; 把这里NOP掉
0047E4D2 |. E9 00000000 JMP Unpacked.0047E4D7
这两句代码。
找到一个地方是这种结构的,就把MOV语句NOP掉,找完后再Ctrl+L继续找。这是个体力活,因为有相当多的这个要改。
这里改完后,再运行,来到有非常多的关键CALL与JNZ语句的那个地方,再单步,看是不是每个语句都改正确了,这时会发现有的CALL并没有修改到,这是因为它与我们上面查找的结构有点不同,它的结构为:
我们再通过搜索来找相应的所有类似的结构,搜索“8B 45 F4 E9”,找到所有的MOV 并NOP掉。
这样完成后,就达到完美破解了。
总结:查找“8B 45 F4 E9”与“8B 45 EC E9”,找到所有像:
00437F4A |> \8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00437F4D |. E9 00000000 JMP Unpacked.00437F52
00437F52 |> 8BE5 MOV ESP,EBP
00437F54 |. 5D POP EBP
00437F55 \. C3 RETN
这种结构的地方,NOP掉MOV给EAX赋值的地方就OK了。
至于程序会弹出网站的问题,下断点“bp ShellExecuteA”,NOP掉函数调用就OK了。
破解后的程序图:
“生成”按钮的事件地址为:
0048B1A2 /. 55 PUSH EBP
0048B1A3 |. 8BEC MOV EBP,ESP