`

使用SoftICE破解Winzip8.0全攻略

阅读更多


摘要

Winzip是大家都很熟悉的压缩解压工具,装机必备工具。Winzip是个免费的共享软件,不注册也一样使用,只是会出现一个未注册的画面而已。它对注册码的保护并不复杂,破解这个软件也是相对简单的。

程序名 :Winzip
版本   :V8.0(3105)
大小   :1,230KB
运行平台:Windows 95/98/NT/2000
保护方式:注册码
破解方式:制作注册补丁

1        破解的准备工作
(1)    安装好SoftICE,并进入Windows。通过CTRL+D来检查SoftICE是否可用。

(2)    加载符号表,可以采用两种方式:一是在当前情况下,使用Symbol Loader动态加载,另一种是修改Windows目录下的Winice.dat文件,删除usr32.dll前面的“exp=”。

2        监测软件的代码
2.1      设置断点
(1)   Windows通过user32.dll库的四个API函数来获取用户输入文本,它们是GetWindowText,GetWindowTextA,GetDlgItemText,GetDlgItemTextA。

(2)   前面已经加载了user32.dll,可以使用exp getwindowtext来查看GetWindowText这个符号是否已经加载,其余仿此。如果没有加载,请参考1.(2)加载。

(3)   为(1)所列的四个函数设置断点,方法是bpx GetWindowText……

(4)   设置完四个断点以后用bl命令确认一下。

(5)   使用bd *命令暂时禁用所有的断点

2.2      中断注册过程
(1)    安装运行Winzip,在主接口中选择”Help”下面的” Enter Registration Code...”,输入用户名”FeiZhaoDong”,注册码”Bingo”。

(2)    按CTRL+D呼出SoftICE,使用be *命令启用所有的断点。

(3)    按F5回到WinZip注册接口,按下”OK”按钮,程序很快被中断在”GetDlgItemTextA”的位置。按F11继续,可以看到又中断在”GetDlgItemTextA”一次。这样我们可以猜测,Winzip是使用了GetDlgItemTextA这个函数来获取用户名和注册码。

(4)    使用bc命令清除掉GetDlgItemTextA以外的三个断点。

(5)    重新输入用户名和注册码(同上),准备进行正式的拆解过程。

2.3      分析注册码的验证过程
(1)    按下”OK”按钮,程序停留在GetDlgItemTextA的入口,按F11跳出这个函数,这样可以看到以下的汇编代码:



0167:00407F6D CALL [USER32!GetDlgItemTextA]
0167:00407F73 PUSH EDI       ;程序停留在这里,EDI指向”FeiZhaoDoing”

0167:00407F74 CALL 0043F89A

0167:00407F79 PUSH EDI

0167:00407F7A CALL 0043F8C3

0167:00407F7F POP ECX

0167:00407F80 MOV ESI, 0048CDA4

0167:00407F85 POP ECX

0167:00407F86 PUSH 0B

0167:00407F88 PUSH ESI

0167:00407F89 PUSH 00000C81

0167:00407F8E PUSH EBX

0167:00407F8F CALL [USER32!GetDlgItemTextA]

0167:00407F95 PUSH ESI       ;ESI指向”Bingo”



按下F11之后程序停留在上面标志的语句,用d EDI命令可以看待,EDI中地址的内容是用户名。按F10一步步走下来,不远处是另一个GetDlgItemTextA,按F10跟进去,  然后按F11跳出来,可以用b ESI看到ESI指向注册码。

这样我们已经证明了前面的判断是正确的,Winzip是使用了GetDlgItemTextA这个函数来获取用户名和注册码。



(2)    Winzip已经得到了它想要的用户名和注册码,接下来应该是验证过程了。按F10接着走,我们看到以下一段代码:



0167:00407F96 CALL 0043F89A

0167:00407F9B PUSH ESI

0167:00407F9C CALL 0043F8C3

0167:00407FA1 CMP BYTE PTR [0048CD78],00   ;[0048CD78]指向“FeiZhaoDong”

0167:00407FA8 POP ECX

0167:00407FA9 POP ECX

0167:00407FAA JZ 00408005

0167:00407FAC CMP BYTE PTR [0048CDA4],00   ;[0048CDA4]指向“Bingo”

0167:00407FB3 JZ 00408005

0167:00407FB5 CALL 00407905

0167:00407FBA TEST EAX,EAX

0167:00407FC3 JZ 00408005



注意样的两部分代码

0167:00407FA1 CMP BYTE PTR [0048CD78],00   ;[0048CD78]指向“FeiZhaoDong”

……

0167:00407FAA JZ 00408005

0167:00407FAC CMP BYTE PTR [0048CDA4],00   ;[0048CDA4]指向“Bingo”

……

0167:00407FB3 JZ 00408005

熟悉汇编语言的人都能很容易的看出这是在判断字符串是否为空。Winzip在判断出字符串为空以后跳转到[00408005],那个地方估计就是弹出注册失败对话框的地方。再走下去,可以看到:

0167:00407FB5 CALL 00407905

0167:00407FBA TEST EAX,EAX

0167:00407FC3 JZ 00408005            ;注意这里的跳转

  Winzip在调用了[00407905]以后,判断EAX是否为0,如果是则跳转到[00408005]。

  多幺熟悉的[00408005]!

  跟着走下去到了[00408005],按着F10很快注册失败的消息框就弹出来了。这样证明了前面的判断,[00408005]就是弹出注册失败对话框的地方。



(3)    程序看到这里已经没有悬念了,[00407905]的调用就是判断注册码是否正确的过程,如果正确,那幺返回EAX为非0值,否则返回0,注册也就失败了。

2.4      深入注册码计算过程
(1)    我们的目的是让这个验证注册码的过程永远返回1这个代表正确的值,因此有必要进入到[00407905]里面去看看,按F10一步步走下去,同时监控ESI、ECX和EAX指向的内容,务必找到最后一次更改EAX值的地方!

(2)    看着看着有了意外的收获:

0167:00407AA9 PUSH ESI      ;ESI指向输入的注册码“Bingo”

0167:00407AAA PUSH EAX      ;EAX指向正确的注册码“3E41159C”

……

0167:00407AD2 PUSH ESI     ;ESI指向输入的注册码“Bingo”

0167:00407AD3 PUSH EAX     ;EAX指向正确的注册码“65293585”



其实到这里我们已经可以利用给出的正确注册码注册成功了,不过目标还是没有达到。



(3) 按F10走了好久好久(有多久?你试试好了^_^),终于看到了下面的代码:

0167:00407B3A  MOV EAX ,[0048FDC]  ;最后一次更改EAX的值,这里是0

……

0167:00407B46  RET

 接着走下去,验证过程就结束了,返回以后很快就弹出注册失败的消息框了。我们已经找到了最后一次更改EAX值的地方,接下去就是修改汇编代码了。



2.5      小结
通过上面的跟踪过程,我们可以看出:

(1)        Winzip对验证过程的保护的确是很弱的,我们很容易就能找到验证是否成功的标志;

(2)        要注意调用API之后的第一个PUSH指令,这往往是重要的数据和标志;

(3)        要注意判空代码,其后面的跳转往往是很重要的标志。

好了,下面让我们去直接修改程序的二进制代码吧。

3        制作注册补丁
3.1      修改内存中的代码
(1)    先修改内存中的代码试试,目的是让验证过程永远返回1值。

(2)    0167:00407B3A  MOV EAX ,[0048FDC]这个代码是关键,考虑到MOV这个指令有立即数赋值的功能,试着这样改:

0167:00407B3A  MOV EAX ,1

(3)    让程序停在[00407B3A],使用a命令,按上述方法修改代码,然后按Esc退出修改模式。

(4)    用bd *禁用所有断点。

(5)    按F5接着执行程序,哈哈,注册成功的消息框弹出来了。选择Retry再试一次,仍然可以注册成功。

3.2      制作注册补丁
(1)    最后,直接修改exe文件来制作注册补丁。重复3.1的过程,当走到[00407B3A]的时候,不要直接修改,先看看这个指令的二进制代码,使用d 407B3A命令,可以看到以下内容:

00407B3A: A1 DC 9F 48 00 83……

(2)    如3.1所述修改汇编代码以后,再使用d 407B3A命令,可以看到以下内容:

  00407B3A: B8 01 00 00 00 83……

(3)    关闭Winzip,使用WinHEX打开Winzip32.exe文件,直接寻找十六进制串A1 DC 9F 48 00 83,找到以后修改为B8 01 00 00 00 83,关闭文件,OK!大功告成。储存修改过的Winzip32.exe文件,这就是我们要的补丁。

4        补丁效果
重新安装Winzip,然后用补丁文件替换原来的Winzip32.exe文件,打开注册接口,输入用户名”FeiZhaoDong”,注册码”Bingo”,然后按”OK”,注册成功。重启Winzip以后可以在”help”里面看到注册信息。如附图。

5        结论
通过这次破解的过程,我熟悉了SoftICE的使用方法,作为一种优秀的调试工具,SoftICE必然在将来的工作中有广泛的应用。另外,还了解了软件注册码保护和破解补丁制作的基本原理。

中国好的的加密解秘网站是看雪学院,里有很多加密解秘的相关资料,部分不是免费的,可以参阅。直接在浏览器中输入”看雪学苑”即可。

参考资料:

(1)    拆解教程,看雪学院

(2)    SoftICE使用手册



(图略)





本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fzd999/archive/2004/08/19/79112.aspx


Winzip是大家都很熟悉的压缩/解压工具,只要你使用WINDOWS,就离不开Winzip,装机必备工具!虽然Winzip是个非常实用的工具,但它却是个免费的共享软件,不注册也一样使用,只是会出现一个未注册的画面而已。它对注册码的保护并不复杂,所以我们就拿它来做练习。

程序名 :Winzip
版本   :V8.0(3105)
大小   :1,230KB
运行平台:Windows 95/98/NT/2000
保护方式:注册码
破解方式:注册码破解
破解难度:容易
程序下载:winzip.exe

破解步骤:

1. 用softice载入windows(通过CTRL+D来检查softice是否已经准备好,按F5退出softice);

2. 运行winzip,选择“help”下的“Enter Registration Code...”;

3. 在“Name:”中输入:ddcrack(随意),“Registration #:”中输入:12345678(随意);

4. 用CTRL+D呼出softice,下万能断点:bpx hmemcpy,按F5返回到winzip;

5. 在winzip中选择“OK”,很快程序就被softice拦截下来(因为我们设置了断点bpx hmemcpy,当在winzip中选择“OK”时,winzip会通过hmemcpy这个功能去取我们输入的名字“ddcrack”和注册码“12345678”,softice检测到hmemcpy被调用,于是就中断winzip的运行,停留在winzip中调用hmemcpy的地方);

6. 用 bd * 暂停刚才设置的断点 bpx hmemcpy (为什么要暂停断点bpx hmemcpy呢?因为我们的目的是要在winzip取名字和注册码的时候中断它的运行,但是 bpx hmemcpy 这个断点并不是针对winzip才有效的,计算机里运行的程序都可能会随时调用它。由于我们在winzip中刚输入名字和注册码后设置断点 bpx hmemcpy ,此时winzip会马上去取我们输入的名字和注册码,所以我们能确保是中断在winzip程序中,通过 bd * 这个命令暂停断点 bpx hmemcpy ,能够防止解密时被其它不相干的程序中断,影响解密的正常进行);

7. 按F12键9次,返回到winzip的领空(因为刚才softice中断在hmemcpy中,这是windows系统区域,不能更改的,winzip仅仅是调用这个功能而已,所以我们必须要返回到winzip程序中才有用),来到下面的地方:
......
0167:00407F6D CALL [USER32!GetDlgItemTextA]
0167:00407F73 PUSH EDI             ←- 程序停留在这里,EDI指向“ddcrack”
0167:00407F74 CALL 0043F89A
0167:00407F79 PUSH EDI
0167:00407F7A CALL 0043F8C3
0167:00407F7F POP ECX
0167:00407F80 MOV ESI, 0048CDA4
0167:00407F85 POP ECX
0167:00407F86 PUSH 0B
0167:00407F88 PUSH ESI
0167:00407F89 PUSH 00000C81
0167:00407F8E PUSH EBX
0167:00407F8F CALL [USER32!GetDlgItemTextA]
0167:00407F95 PUSH ESI             ←- ESI指向“12345678”
0167:00407F96 CALL 0043F89A
0167:00407F9B PUSH ESI
0167:00407F9C CALL 0043F8C3
0167:00407FA1 CMP BYTE PTR [0048CD78],00   ←- [0048CD78]指向“ddcrack”
0167:00407FA8 POP ECX
0167:00407FA9 POP ECX
0167:00407FAA JZ 00408005
0167:00407FAC CMP BYTE PTR [0048CDA4],00   ←- [0048CDA4]指向“12345678”
0167:00407FB3 JZ 00408005
0167:00407FB5 CALL 00407905
0167:00407FBA TEST EAX,EAX
0167:00407FC3 JZ 00408005
......

8. 我们从调用hmemcpy的系统区域中返回到winzip领空时,程序停留在0167:00407F73 PUSH EDI上,看看它上面的那条指令0167:00407F6D CALL [USER32!GetDlgItemTextA],这个CALL就是取我们输入数据的程序,也就是这个CALL让我们用 bpx hmemcpy 将winzip拦截了下来。既然winzip用这个CALL去取输入的东西,那么调用之后肯定会返回结果的,让我们来看看:用 D EDI ,观察softice的数据区,你会看到EDI指向的内存区域的内容是我们输入的名字“ddcrack”;

9. 从程序中可看出,下面不远的地方还有一个同样的地方调用USER32!GetDlgItemTextA,既0167:00407F8F CALL [USER32!GetDlgItemTextA]这一行。按F10键多次,走到这个CALL的下一句停下,既程序停在0167:00407F95 PUSH ESI这条指令上,用 D ESI ,同样的我们可以看到ESI指向的内存区域的内容是我们输入的注册码“12345678”。现在winzip已经将我们输入的名字和注册码都取到,让我们来看看它下一步要做什么?

10. 继续按F10多次,当程序走到0167:00407FA1 CMP BYTE PTR [0048CD78],00时停下来,这条指令将内存0048CD78中的数据和00比较,然后根据比较结果判断程序走向。用 D 0048CD78,观察softice的数据区,我们可以看到0048CD78中的数据是“ddcrack”,现在我们知道这条指令的作用是判断我们输入的名字是否为空,如果没有输入任何东西,程序将会跳到00408005去;同样的,按F10走到0407FAC CMP BYTE PTR [0048CDA4],00这行停下,然后用 D 0048CDA4,可以看到0048CDA4中的数据是“12345678”。因为我们输入了名字和注册码,所以程序不会跳到 00408005去,程序检查输入的名字和注册码,如果任何一个没有输入(既其值为00),程序都会跳到00408005去,由此我们应该想到00408005很可能就是显示出错的地方,即当程序走到00408005 的时候,表示输入的名字和注册码是错误的;

11. 按F10两次来到下面的那个CALL 00407905(因为程序刚才停在0167:00407FAC CMP BYTE PTR [0048CDA4],00上):
......
0167:00407FB5 CALL 00407905          ←- 程序停留在这里
0167:00407FBA TEST EAX,EAX
0167:00407FC3 JZ 00408005
......
程序判断输入的名字和注册码是否为空后调用CALL 00407905,这个CALL将结果返回到EAX中,程序根据EAX值判断走向。从程序可以知道,如果EAX的返回值是0,则程序会跳到00408005,就是刚才我们判断是有问题的地方。那么这个CALL倒底藏着什么猫腻呀?现在还不是很清楚,接着按F10两次来到JZ 00408005停下。现在看看softice中的零(即Z)标志位,其值是零,所以程序将会跳到00408005去,我们姑且按F10跳到00408005去看个究竟:
......
0167:00408005 CALL 004082A6          ←- 程序停留在这里
0167:0040800A PUSH 0000028E
0167:0040800F CALL 0043F5ED
0167:00408014 PUSH EAX
0167:00408015 PUSH EBX
0167:00408016 PUSH 3D
0167:00408018 CALL 00430025          ←- 出现错误框
0167:0040801D ADD ESP,10
0167:00408020 INC DWORD PTR [00487AF8]
0167:00408026 CMP DWORD PTR [00487AF8],03   ←- 判断错误次数是否到了3次?
0167:0040802D JNZ 0040812C
0167:00408033 PUSH 00
0167:00408035 PUSH EBX
0167:00408036 CALL [USER32!EndDialog]
0167:0040803C JMP 0040812C
......

12. 一直按F10走过0167:00408018 CALL 00430025,这是程序蹦出一个窗口,警告:Incomplete or incorrect information(不完整或不正确的信息),程序走到这里就已经很明朗了:如果程序在前面的时候跳到00408005来,就表示输入的名字和注册码是错误的,所以刚才的那个0167:00407FB5 CALL 00407905一定是比较输入的注册码是否正确的地方,也就是里面肯定有将我们输入的注册码和正确的注册码相比较的地方,所以我们要进入CALL 00430025里去看看。如果继续往CALL 00430025下面的语句看的话,你会看到下面的几句:
0167:00408020 INC DWORD PTR [00487AF8]
0167:00408026 CMP DWORD PTR [00487AF8],03
0167:0040802D JNZ 0040812C
程序先将内存00487AF8处的值加1(其初始值为0,可以在这条语句前用 D 00487AF8 查看),然后比较是否是3,如果不是就跳到0040812C,如果是则执行后面的0167:00408036 CALL [USER32!EndDialog],其作用就是关闭对话框,也就是我们输入名字和注册码的窗口。由此我们可以看出此处程序的作用是检查错误输入名字、注册码的错误次数是否已经到了3次,如果到了3次,则关闭对话框,不允许再输入;如果少于3次,可有机会再次输入名字和注册码。

13. 重复前面的步骤1到11,让程序停在0167:00407FB5 CALL 00407905上,然后按F8进入这个CALL里面去:
......
0167:004079D5 PUSH EBP
0167:004079D6 PUSH EBP,ESP
0167:004079D8 SUB ESP,00000208
0167:004079DE PUSH EBX
0167:004079DF PUSH ESI
0167:004079E0 XOR ESI,ESI
0167:004079E2 CMP BYTE PTR [0048CD78],00
0167:004079E9 PUSH EDI
0167:004079EA JZ 00407A8A
......

14. 按F10键N次(我也不知道几次,你自己数一数吧^_^),一直来到下面的地方停下:
......
0167:00407A91 LEA EAX,[EBP-0140]     ←- 程序停留在这里
0167:00407A97 PUSH EAX
0167:00407A98 PUSH EDI          ←- EDI指向输入的名字“ddcrack”
0167:00407A99 CALL 00407B47        ←- 计算注册码
0167:00407A9E MOV ESI,0048CDA4
0167:00407AA3 LEA EAX,[EBP-0140]
0167:00407AA9 PUSH ESI          ←- ESI指向输入的注册码“12345678”
0167:00407AAA PUSH EAX          ←- EAX指向正确的注册码“5CFC0875”
0167:00407AAB CALL 004692D0
0167:00407AB0 ADD ESP,10
0167:00407AB3 NEG EAX
0167:00407AB5 SBB EAX,EAX
0167:00407AB7 INC EAX
0167:00407AB8 MOV [00489FDC],EAX
0167:00407ABD JNZ 00407B27
0167:00407ABF LEA EAX,[EBP-0140]
0167:00407AC5 PUSH EAX
0167:00407AC6 PUSH EDI          ←- EDI指向输入的名字“ddcrack”
0167:00407AC7 CALL 00407BE4        ←- 计算注册码
0167:00407ACC LEA EAX,[EBP-0140]
0167:00407AD2 PUSH ESI          ←- ESI指向输入的注册码“12345678”
0167:00407AD3 PUSH EAX          ←- EAX指向正确的注册码“23804216”
0167:00407AD4 CALL 004692D0
0167:00407AD9 ADD ESP,10
0167:00407ADC NEG EAX
0167:00407ADE SBB EAX,EAX
0167:00407AE0 INC EAX
0167:00407AE1 MOV [00489FDC],EAX
0167:00407AE6 JNZ 00407B27
......

15. 大家一定会问:为什么会在这里停下,而不是其它地方呢?因为我在前面的程序中已经用 D *** 看过了,没有发现什么可疑的呀^_^!

  按F10走到0167:00407A99 CALL 00407B47处,用 D EAX 和 D EDI 观察其里面是什么?可以看到EDI指向我们输入的名字“ddcrack”,EAX指向的内存区域没有什么特别的数据;紧接着下面的CALL 00407B47 会对“ddcrack”进行一些处理,具体的 我们还不知道,继续往后走;

16. 按F10走到0167:00407AAB CALL 004692D0这一句,然后用 D ESI 和 D EAX 查看内存中的数据,可以看到ESI指向我们输入的注册码“12345678”,而EAX指向另外一串字符“5CFC0875”。不用说,十有八九这就是正确的注册码了,赶紧把它写在纸上吧^_^!继续往下走,我们会在下面的地方紧接着发现另外一个类似程序段,从而得到另外一串码“23804216”;

17. 验证注册码:按F5返回winzip,选择注册,输入名字“ddcrack”和注册码“5CFC0875”或“23804216”。然后你看到了什么?注册成功的画面出现,直接确认就搞定了,哈哈哈。。。!

18. 现在我们知道CALL 00407B47这条语句的作用是根据我们输入的名字来计算正确的注册码,然后和我们输入的注册码比较,看两者是否相等。处理后事:最后别忘了用CTRL+D呼出softice,然后下命令 BC * 清除所有断点!!!
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics