我把软件分为开源软件和商业软件,开源软件功能相对较弱,源码开放,可以看到底层实现,适合学习研究;商业软件正好相反。但如果我们能看到商业软件的源码或者至少能够免费使用,这就是我理解的破解。
由于本软件是商业软件,所以不能涉及具体名称,这里只是示范演示之用,禁止以此来进行商业使用!
1.安装使用
不管怎样,先安装程序使用,即使卡在某一步,在使用时或卡住时,也许就是破解的关键,运行主程序后,需要网络锁(要插入加密狗)
2.查壳侦壳
这应该是破解的第一步,查是什么壳,我现在只知道.NET的怎么破,而且现在基本是工具党,IL语言不会,不要见笑,新手都是这样走过来的,下面是查壳后,发现并没有壳,窃喜:
3.加载程序
使用.NET Reflector 8.3加载exe后,出现"索引超出了数据界限",在吾爱中,出找到了类似的问题,有人说是代码混淆
百度百科:将代码中的各种元素,如变量,函数,类的名字改写成无意义的名字。比如改写成单个字母,或是简短的无意义字母组合,甚至改写成"__"这样的符号,使得阅读的人无法根据名字猜测其用途。重写代码中的部分逻辑,将其变成功能上等价,但是更难理解的形式。比如将for循环改写成while循环,将循环改写成递归,精简中间变量,等等。打乱代码的格式。比如删除空格,将多行代码挤到一行中,或者将一行代码断成多行等等。被混淆的代码难于理解,因此调试除错也变得困难起来。开发人员通常需要保留原始的未混淆的代码用于调试。
所以,得反混淆。
4.反混淆
反混淆的神器当然数de4dot,直接拖放即可,我以前还在Cmd中傻傻地操作。反混淆结果会新生成一个后缀名为-cleaned的同名文件。
5.加载程序x2
再次使用.NET Reflector 8.3加载反混淆后的exe,就没有出现问题了。
6.寻找关键点
找关键点进行破解这需要经验,现在我都去找登陆窗体,主窗体,主函数,加载函数,许可函数等。幸运的是,我找到了MainFrm中的Form1_Load函数,还有一个CheckDog()函数。
7.深入挖掘
在Load函数函数中,我们看到有一个条件判断,即CheckDog()返回一个Bool值,如果为F,那就完了,必定要调用ProjectData.EndApp();函数,EndApp不就是结束程序吗?都结束了,还破啥呀!再看EndApp函数,做得真绝,关闭所有。
8.不能结束
打开Reflexil插件,看看它的IL代码,实际上调用CheckDog方法(callvirt), 推送一个0(Ldc.i4.0),将0与CheckDog返回的值进行比较(ceq),如果相等则返回1,如果不等则返回0。这里:如果检查加密狗失败,CheckDog会返回Flase,Flase取反(!),实际上是将它与0(Flase)进行比较,相等则跳转调用EndApp()。
这里的修改方法有很多种,目的是让它不调用EndApp函数。
(1)修改CheckDog的返回值,这个方法后面讲;
(2)CheckDog的返回值与0比较,改为与1比较,即改Ldc.i4.0为Ldc.i4.1;
(3)修改比较符号,即将ceq改为cgt;
(4)修改跳转条件,即将brfalse.s改为brtrue.s;
(5)删除跳转后的调用语句,即删除037行;
(6)修改EndApp函数,最好的办法,删除其中代码。
当然,选择其中一种即可,不要做两种,可能造成负负得正的情况。
9.修改保存
我们使用了第三种修改方法,选择exe右键保存。
10.测试问题
将修改后的结果进行测试,发现虽然可以进入主程序,可还是要弹出这个窗口,不好看,我有点强迫症。使用反混淆后的exe重新来(未进行第9步修改的exe)。
11.再次深入
这下,我们来看CheckDog函数,不长,来分析:条件判断如果加密狗检查成功,我们则返回为True,否则,弹出错误窗口(GUsbDogClient.mDogForm),并返回为False。
这里我们的改法很显然:
(1)可以删除所有,只返回一个true即可;
(2)将条件判断==修改,使它能够执行条件语句;
(3)删除ShowDialog的语句,修改最后一个return的值(不修改的话,可修改Load函数的if判断)。
如果按(2),我们需要把==修改成>还是<呢?来看下枚举型UdbSoftKeyStatus,它是枚举常量,不同的值,代表着不同的类型,其中成功的值是2012(16进制是0x7e0),我发现,其他值都大于2012,它最小,所以我就知道怎么修改了。
修改后,果然在程序初始化过程没有任何问题了,像有加密狗一样顺利。
12.不完美
可软件使用中的几个功能点击后还是弹出"请先连接服务器"的警示,且相应功能不能使用。
说明我们还没有找到根源,我们要找到检查软件狗的函数进行修改才行。
13.寻找根本点
CheckDog函数,我们可能要找的函数在GUsbDogClient,而它在另外一个dll中(不在exe中),打开这个dll的函数,发现里面为空,又得脱一下壳吧。
脱壳后的函数便有了内容,如果我们把这里的return返回成功(2012)的话,这又是治标不治本的方法。
(未完等续……)