【破文标题】企业报表处理软件(2005版)免光盘破解【破文作者】gc801【作者邮箱】****【作者主页】http://free4.e-168.cn/f1club【破解工具】OllyDbg,PEiD,W32Dasm,Hiew【破解平台】Win9x/NT/2000/XP【软件名称】企业报表处理软件(2005版)【软件大小】50.6m【原版下载】CDFACE.exe【保护方式】光盘保护【软件简介】没有什么好说的,用过的都知道。------------------------------------------------------------------------【破解过程】所需工具在http://www.pediy.com/tools.htm均有下载。破解之前先熟悉一下汇编中常用的东西:CMP 比较 JNZ 不等于就跳转 机器码:75JE 等于就跳转 机器码:74JMP 无条件跳转 机器码:EB
今天我们就是靠它们来实现破解的。简单吧。
做破解的都知道一件事,先查壳。当然我也不例外。可惜今天查壳无用,用PEID查壳显示“[代码未能识别] [重叠] *”,核心扫描显示“Borland Delphi 4.0 - 5.0 [重叠]”,跟了一下,发现要脱这个壳不容易,随便脱了一下,程序不能运行,所兴干脆放弃脱壳,直接载入跟踪,还好,这个软件一开始就检测光盘了。
虽然PEID没能帮我脱掉壳(费话,它也不是脱壳工具),但是它帮了我一个大忙,找到了OEP入口点(用Generic OEP finder插件)。是0055A0AA,我们就把断点下到这里。
OD载入CDFACE,CTRL+G,找到0055A0AA,把断点下在0055A0AA,F9运行。程序在0055A0AA处断下来了,我们先按F8初步跟踪。所幸的是程序加密并不严密,直接就被跟踪了出来。
0055A0AA 55 push ebp0055A0AB 8BEC mov ebp,esp0055A0AD 83C4 F8 add esp,-80055A0B0 60 pushad0055A0B1 C745 FC 00000000 mov dword ptr ss:[ebp-4],00055A0B8 E8 00000000 call CDFace.0055A0BD0055A0BD 5B pop ebx0055A0BE 81EB 1E114000 sub ebx,CDFace.0040111E0055A0C4 55 push ebp0055A0C5 8D83 AC114000 lea eax,dword ptr ds:[ebx+4011AC]0055A0CB 50 push eax0055A0CC 8D83 61104000 lea eax,dword ptr ds:[ebx+401061]0055A0D2 50 push eax0055A0D3 64:FF35 00000000 push dword ptr fs:[0]0055A0DA 64:8925 00000000 mov dword ptr fs:[0],esp0055A0E1 8B7D 0C mov edi,dword ptr ss:[ebp+C]0055A0E4 B9 FFFFFFFF mov ecx,-10055A0E9 32C0 xor al,al0055A0EB FC cld0055A0EC F2:AE repne scas byte ptr es:[edi]0055A0EE 8BCF mov ecx,edi0055A0F0 2B4D 0C sub ecx,dword ptr ss:[ebp+C]0055A0F3 894D F8 mov dword ptr ss:[ebp-8],ecx0055A0F6 8B75 08 mov esi,dword ptr ss:[ebp+8]0055A0F9 0376 3C add esi,dword ptr ds:[esi+3C]0055A0FC 8B76 78 mov esi,dword ptr ds:[esi+78]0055A0FF 0375 08 add esi,dword ptr ss:[ebp+8]0055A102 8B5E 20 mov ebx,dword ptr ds:[esi+20]0055A105 035D 08 add ebx,dword ptr ss:[ebp+8]0055A108 33D2 xor edx,edx0055A10A 56 push esi ;在这里有一个循环这是开始,我们不要跟着它绕了,0055A10B 8B3B mov edi,dword ptr ds:[ebx]0055A10D 037D 08 add edi,dword ptr ss:[ebp+8]0055A110 8B75 0C mov esi,dword ptr ss:[ebp+C]0055A113 8B4D F8 mov ecx,dword ptr ss:[ebp-8]0055A116 F3:A6 repe cmps byte ptr es:[edi],byte ptr ds:[esi]0055A118 75 03 jnz short CDFace.0055A11D ;不满足条件继续转悠。0055A11A 5E pop esi0055A11B EB 0C jmp short CDFace.0055A129 ; 满足条件以后就跳走。我们要跟着它走,跳到它想跳的地方0055A11D 5E pop esi ; kernel32.7C880DD80055A11E 83C3 04 add ebx,40055A121 42 inc edx0055A122 3B56 18 cmp edx,dword ptr ds:[esi+18]0055A125 ^ 72 E3 jb short CDFace.0055A10A ;这里是循环结束。0055A127 EB 22 jmp short CDFace.0055A14B0055A129 2B5E 20 sub ebx,dword ptr ds:[esi+20] ;满足条件以后跳到这,所以我们就在这里按F4程序运行到这0055A12C 2B5D 08 sub ebx,dword ptr ss:[ebp+8] ;就可以不反复循环,跟着它转了。0055A12F D1EB shr ebx,1 ;跳出来以后继续F8跟0055A131 035E 24 add ebx,dword ptr ds:[esi+24]0055A134 035D 08 add ebx,dword ptr ss:[ebp+8]0055A137 0FB703 movzx eax,word ptr ds:[ebx]0055A13A C1E0 02 shl eax,20055A13D 0346 1C add eax,dword ptr ds:[esi+1C]0055A140 0345 08 add eax,dword ptr ss:[ebp+8]0055A143 8B00 mov eax,dword ptr ds:[eax]0055A145 0345 08 add eax,dword ptr ss:[ebp+8]0055A148 8945 FC mov dword ptr ss:[ebp-4],eax0055A14B 64:8F05 00000000 pop dword ptr fs:[0]0055A152 83C4 0C add esp,0C0055A155 61 popad0055A156 8B45 FC mov eax,dword ptr ss:[ebp-4]0055A159 C9 leave0055A15A C2 0800 retn 8
上面的程序段有一个循环,我们根据判断,程序继续运行会在0055A11B /EB 0C jmp short CDFace.0055A129跳出,跳到,0055A129,所以我们就在0055A129上按F4,程序就运行到了这里。(经验需要积累,并不是一下子就学会了的。至于为什么要跳出,你想想就会明白了。这是个循环,程序判断当不满足一个条件时0055A118 /75 03 jnz short CDFace.0055A11D,跳到这句的后面,继续循环,所以,明显的最终会满足这个条件而不跳到它后面,而是不跳转继续执行到0055A11B /EB 0C jmp short CDFace.0055A129,所以我们假设满足这个条件它不跳走,那当然是执行中间这句0055A11B /EB 0C jmp short CDFace.0055A129了)这里说得可能麻烦了一些,越说越糊涂,我做个例子你就会明白了。假设有这样一段程序:/***************程序开始For x=1 to 100 ……假设这里是一些操作 if x=100 then Goto Next x=x+1Loop:Next……/***************程序结束上面那段程序应该很清楚了吧,X是一个变量,如果X<100,它就在这里执行这个循环,如果X=100就会跳出循环。我们为了节约时间,当然让它一下子就跳到:Next执行,而且这时候的条件也已经成立了,就是X=100,在OD中,F4的作用就是运行到该句,在上面那个例子中也就是相当于直接执行到:Next。
上面我们讲的是如何绕过循环,如果你不这么做,一步一步老老实实的F8跟也是可以跟到这里的。不过要按好多下,手都酸了。
在0055A129这句上按F4,程序继续运行。0055A129 2B5E 20 sub ebx,dword ptr ds:[esi+20]继续按F8跟。
最后有个Retu,程序返回到0055A4F6 0BC0 or eax,eax0055A4F8 75 05 jnz short CDFace.0055A4FF
继续跟。它会在0055A4F8跳走,跳到0055A4FF还是跟吧。还没开始判断光盘呢。
继续按F8跟你会发现,程序在穷举光盘,从你运行程序的驱动器号开始,一直到T盘。嘿嘿,有门了。cmp eax,5就是判断驱动器是不是光驱。我们不管它,我们要跟到它提示错误时为止。
我们一直跟到这段程序的最后处:0055A4FF ………………………………//……前面省略N多,都是在穷举光盘。0055A883 83F8 05 cmp eax,5 ;判断是否为光驱0055A886 75 1B jnz short CDFace.0055A8A3 ;不是跳到出错信息处0055A888 8D83 E4134000 lea eax,dword ptr ds:[ebx+4013E4]0055A88E 8D8B 51134000 lea ecx,dword ptr ds:[ebx+401351]0055A894 50 push eax0055A895 51 push ecx0055A896 FF93 D2114000 call dword ptr ds:[ebx+4011D2] ;没有研究它在干什么,判断是不是在根目录运行?(猜的)0055A89C 83F8 FF cmp eax,-1 ;比较0055A89F 74 02 je short CDFace.0055A8A3 ;跳到出错信息处0055A8A1 EB 19 jmp short CDFace.0055A8BC ;明显就是正确的出口,我们要跟着它走才不会挂。0055A8A3 8D8B 93134000 lea ecx,dword ptr ds:[ebx+401393] ;这里其实就是出错信息开始的位置,无论如何不能到这里。0055A8A9 8D83 9C134000 lea eax,dword ptr ds:[ebx+40139C] ;装入出错字符0055A8AF 6A 20 push 200055A8B1 51 push ecx0055A8B2 50 push eax0055A8B3 6A 00 push 00055A8B5 FF93 CE114000 call dword ptr ds:[ebx+4011CE] ; user32.MessageBoxA 提示必须在光盘运行。0055A8BB C3 retn
编过程序的都应该知道MessageBox是什么了。就是那个信息提示窗口。程序运行到这里,就提示错误了,看到了没。程序退出了,没办法跟了。嗯。我们把断点下到0055A883。CTRL+F2重新载入。按F9,第一次断到EOP处,再按F9,就断在我们刚下的断点上0055A883了。(为什么要把断点下在这里?从程序上面分析,这里的下面一句就是跳到失败处的嘛。)
嗯,我们看,现在断点这里EAX的值是0000001,不等于5噢,也就是下面的JNZ就要成立了。我们要么让EAX=5(这是不可能的,因为不是光盘嘛),要么让JNZ不跳,它现在不是不等于就跳吗?我不让它跳,我让它等于就跳,嘿嘿。(怎么可能等于呢,只有在光盘运行才能等于,也就是说,更改条件后,在光盘反而不能运行了。嘎嘎。当然也可以让它在光盘运行,我们这里做最简单的。)
嗯,按上面说的做,把JNZ改为JE,等于就跳到失败处。在0055A886 jnz short CDFace.0055A8A3上面双击,把JNZ改成JE。(改为JG在光盘也可以运行)好了,不跳了。继续F8。
嗯?~!!!!到0055A89F /74 02 je short CDFace.0055A8A3处又要跳到失败处了,我们再改,不让它跳,这回,我们把JE改成JNZ或者是不让它跳到失败处,让它跳到继续运行处。(这里可以有2种选择,可以JE改JNZ或者不跳到失败处,而跳到成功处。成功处在哪里,分析这里你就会发现,成功处就是“0055A8A1 /EB 19 jmp short CDFace.0055A8BC”这一句。)
我们采用第2种方案,让它跳到成功处。je short CDFace.0055A8A3改成je short CDFace.0055A8A1。它不就跳到正确出口处了吗?你想改成je short CDFace.0055A8BC也行啊,不过改的东西多一些,我们的改法只改一个字节,多美。
本来以为改造已经成功了,保存修改运行一看,还有错误。看来后面还有判断。那我们继续跟。
0055A8A1 /EB 19 jmp short CDFace.0055A8BC跳至:0055A8BC - E9 AF53EFFF jmp CDFace.0044FC70
跟到0044FC70。
0044FC70 /. 55 push ebp ;初始化,任何过程开始都是这个,保存现场0044FC71 |. 8BEC mov ebp,esp0044FC73 |. 33C9 xor ecx,ecx0044FC75 |. 51 push ecx0044FC76 |. 51 push ecx0044FC77 |. 51 push ecx0044FC78 |. 51 push ecx0044FC79 |. 51 push ecx0044FC7A |. 51 push ecx0044FC7B |. 51 push ecx0044FC7C |. 53 push ebx0044FC7D |. B8 78FA4400 mov eax,CDFace.0044FA780044FC82 |. E8 D964FBFF call CDFace.004061600044FC87 |. 8B1D A80D4500 mov ebx,dword ptr ds:[450DA8] ; CDFace.004517CC0044FC8D |. 33C0 xor eax,eax0044FC8F |. 55 push ebp0044FC90 |. 68 83FD4400 push CDFace.0044FD830044FC95 |. 64:FF30 push dword ptr fs:[eax]0044FC98 |. 64:8920 mov dword ptr fs:[eax],esp0044FC9B |. 8D55 EC lea edx,dword ptr ss:[ebp-14]0044FC9E |. 8B03 mov eax,dword ptr ds:[ebx]0044FCA0 |. E8 F71BFFFF call CDFace.0044189C0044FCA5 |. 8B45 EC mov eax,dword ptr ss:[ebp-14]0044FCA8 |. 8D55 F0 lea edx,dword ptr ss:[ebp-10]0044FCAB |. E8 6C84FBFF call CDFace.0040811C0044FCB0 |. 8B55 F0 mov edx,dword ptr ss:[ebp-10]0044FCB3 |. B8 F01C4500 mov eax,CDFace.00451CF00044FCB8 |. B9 98FD4400 mov ecx,CDFace.0044FD980044FCBD |. E8 BE40FBFF call CDFace.00403D800044FCC2 |. A1 F01C4500 mov eax,dword ptr ds:[451CF0]0044FCC7 |. E8 2C42FBFF call CDFace.00403EF80044FCCC |. 50 push eax ; /RootPathName0044FCCD |. E8 BA65FBFF call <jmp.&kernel32.GetDriveTypeA> ; /GetDriveTypeA取得驱动器类型0044FCD2 |. 83F8 05 cmp eax,5 ;比较是否光驱0044FCD5 74 31 je short CDFace.0044FD08 ;如果是光驱就跳到继续执行处0044FCD7 |. 8D55 E8 lea edx,dword ptr ss:[ebp-18] ;不是就要出错了。0044FCDA |. B8 01000000 mov eax,10044FCDF |. E8 CC2BFBFF call CDFace.004028B00044FCE4 |. 8B45 E8 mov eax,dword ptr ss:[ebp-18]0044FCE7 |. BA A4FD4400 mov edx,CDFace.0044FDA4 ; ASCII "/AutoRun.inf"0044FCEC |. E8 5341FBFF call CDFace.00403E440044FCF1 |. 74 15 je short CDFace.0044FD080044FCF3 |. 6A 10 push 100044FCF5 |. B9 B4FD4400 mov ecx,CDFace.0044FDB40044FCFA |. BA BCFD4400 mov edx,CDFace.0044FDBC0044FCFF |. 8B03 mov eax,dword ptr ds:[ebx]0044FD01 |. E8 2618FFFF call CDFace.0044152C0044FD06 |. EB 60 jmp short CDFace.0044FD680044FD08 |> 8B03 mov eax,dword ptr ds:[ebx]0044FD0A |. E8 2D16FFFF call CDFace.0044133C0044FD0F |. 8B03 mov eax,dword ptr ds:[ebx]0044FD11 |. BA E8FD4400 mov edx,CDFace.0044FDE80044FD16 |. E8 3D12FFFF call CDFace.00440F580044FD1B |. 8B0D C00C4500 mov ecx,dword ptr ds:[450CC0] ; CDFace.00451CE80044FD21 |. 8B03 mov eax,dword ptr ds:[ebx]0044FD23 |. 8B15 F8F04400 mov edx,dword ptr ds:[44F0F8] ; CDFace.0044F1440044FD29 |. E8 2616FFFF call CDFace.004413540044FD2E |. 8B03 mov eax,dword ptr ds:[ebx]0044FD30 |. 8B40 38 mov eax,dword ptr ds:[eax+38]0044FD33 |. 8B48 08 mov ecx,dword ptr ds:[eax+8]0044FD36 |. 8D45 E4 lea eax,dword ptr ss:[ebp-1C]0044FD39 |. BA 00FE4400 mov edx,CDFace.0044FE00 ; ASCII "MUTEX_"0044FD3E |. E8 3D40FBFF call CDFace.00403D800044FD43 |. 8B45 E4 mov eax,dword ptr ss:[ebp-1C]0044FD46 |. E8 AD41FBFF call CDFace.00403EF80044FD4B |. 50 push eax ; /MutexName0044FD4C |. 6A FF push -1 ; |InitialOwner = TRUE0044FD4E |. 6A 00 push 0 ; |pSecurity = NULL0044FD50 |. E8 AF64FBFF call <jmp.&kernel32.CreateMutexA> ; /CreateMutexA0044FD55 |. E8 4A65FBFF call <jmp.&kernel32.GetLastError> ; [GetLastError0044FD5A |. 3D B7000000 cmp eax,0B70044FD5F |. 74 07 je short CDFace.0044FD680044FD61 |. 8B03 mov eax,dword ptr ds:[ebx]0044FD63 |. E8 6C16FFFF call CDFace.004413D40044FD68 |> 33C0 xor eax,eax0044FD6A |. 5A pop edx0044FD6B |. 59 pop ecx0044FD6C |. 59 pop ecx0044FD6D |. 64:8910 mov dword ptr fs:[eax],edx0044FD70 |. 68 8AFD4400 push CDFace.0044FD8A0044FD75 |> 8D45 E4 lea eax,dword ptr ss:[ebp-1C]0044FD78 |. BA 04000000 mov edx,40044FD7D |. E8 563DFBFF call CDFace.00403AD80044FD82 /. C3 retn
仔细分析这一段,我们发现,程序又判断驱动器是不是光驱,是光驱就继续,不是光驱就提示出错0044FCCD |. E8 BA65FBFF call <jmp.&kernel32.GetDriveTypeA> ; /GetDriveTypeA0044FCD2 |. 83F8 05 cmp eax,5 ;判断是不是光驱0044FCD5 74 31 je short CDFace.0044FD08 ;如果是就跳到成功处。修改这里,JE改JMP,无论如何都跳。0044FCD7 |. 8D55 E8 lea edx,dword ptr ss:[ebp-18]0044FCDA |. B8 01000000 mov eax,10044FCDF |. E8 CC2BFBFF call CDFace.004028B0
改完之后再一运行,已经可以了。
------------------------------------------------------------------------【破解总结】幸运的是程序加密并不严谨,一开始就引入判断光驱的过程,只用了不长时间破解。反而在脱壳上下了不少工夫,结果无功而返。
总结一下。改了三个地方:0055A886 75 1B jnz short CDFace.0055A8A3 //offset 00154886h JNZ改JE,75改74。如果想让程序在光盘也能运行应该改为JG,机器码是7F。0055A89F 74 02 je short CDFace.0055A8A3 //offset 0015489fh JE改JNZ或改跳转,我们选 的是改跳转,7402改7400 0044FCD5 74 31 je short CDFace.0044FD08 //offset 0004f0d5h JE改JMP,74改EB。
需要注意的是在HIEW中修改和在OD中修改不同,OD中已经让程序运行在内存之中,而HIEW是静态修改的,程序并没有运行。所以修改的偏移位置并不相同。借助于W32Dasm我们可以知道偏移位置。具体方法是用W32Dasm反汇编程序,查找0055A886,最下端中间显示的Offset就是在HIEW中显示的偏移位置。其他都相同,这里不再详述。我上面已经把Offset标注出来了。
最后需要说明的是,这次破解并非常规的破解,常规的破解应该先脱壳,然后下函数断点或者其它断点是正规方法。这次没有用常规方法就成功,主要原因是程序加密不严谨,给了破解者可乘之机,一开始就进行检测了。如果遇到严谨的加密方法,没有脱壳就开始破解,可能要跟上几天才能得出结果。------------------------------------------------------------------------【版权声明】本文纯属技术交流, 转载请注明作者信息并保持文章的完整, 谢谢! ------------------------------------------------------------------------