在NhibernateProfiler破解这个系列的第一篇里我们描述了NhibernateProfiler的破解思路,同时也对这个思路进行了验证。本来准备第二篇就写这个工具的,但最终中间还是插了二篇关于附加到进程工具的介绍与实现。现在我们就回来把这个工具给完成了,也为这个系列做个完结 。
在第一篇里我们描述的那种方法叫做暴破,也就是暴力破解,理论上跟出注册算法,是更好的选择,但NhibernateProfiler使用的是许可认证技术,采用的是RSA非对称公钥加密(RSACryptoServiceProvider),也就是说在你不知道公钥或私钥中的任何一个的情况下,知道了算法也是白搭,事实上RSA非对称公钥加密的算法本来就是公开的。关于RSA加密,网上的资料很多,各位可自行百度或GOOGLE,在这里就不详述了,使用许可认证技术的软件基本上只有暴破一种方法,暴破虽然较跟出算法更容易一些,但缺点也是很明显的,就是破解的目标每出来一个新版本都要重新破解一次,而跟出算法,就不会出这样的问题,无论他出多少版本,只要他的注册算法不变,写个注册机,就可以无限制的使用,所以为了在一定程度上弥补暴破的这种缺陷,我们来写一个自动破解工具,这样就可以在作者没有改动我们修改的那块代码的情况下,实现多次破解 。
遵循我们一向的习惯,介绍前,先看看这个破解工具实现后的 样子。
如果你不想打开解决方案,调试运行的话(源码在根目录下的src文件平里),附录的根目录的Build文件夹里有一个编译好的程序 NHProfilerCracker.exe , 双击打开就可以运行了。
可以看到有个去除升级的选项框,选中的话,NHibernateProfiler的自动升级部分也会被清除,如果不选的话,破解后的NHibernateProfiler就还可以继续升级,不过如果保留升级的话有个问题,就是他升级一次,你就要再使用工具破解一次,而且不保证他每次升级后,这个破解工具都还有效。所以这个你们可以自行选择,不过建议,至少保存一个去升级的版本,以备各种不测
OKAY,点击中间那个大按钮 会弹出文件选择对话框,选中,附录里 target文件夹里 NHProf.exe ,这个是我下的最新的V2.0 build 2150 的版本,写第一篇时还是build 2148 。 如图所示
点击打开。 这时候如果弹出
则说明破解已经完成了,这时候我们再到target文件夹里去看看,会发现多了两个文件,一个NHProf_bak.exe 还有一个是HibernatingRhinos.Profiler.Client.Host_bak.dll 。这是两个被修改文件的备份,如果发现破解不行了,可以把这两个文件替换回去 。
OKAY,这个很简单,没什么好介绍的,下面就开始讲这个东西是怎么实现的,不过在讲实现之前,还得再回顾一下,第一篇里分析出来的结果 。
在第一篇里,我们分析出来,验证许可有效是由HibernatingRhinos.Profiler.Client.Host.dll 里 Rhino.Licensing命名空间的AbstractLicenseValidator类的IsLicenseValid这个方法完成的,所以我们只要让这个方法永远返回TRUE就可以实现无论如何验证都有效了,另外我们也分析出来,只要在这个方法里改掉三个地方,就可以保证它永远返回TRUE了,其中第一处为
throw new LicenseExpiredException("Expiration Date: " + this.ExpirationDate);
对应的是IL代码是
IL_0085: /* 72 | (70)0021CC */ ldstr "Expiration Date: " IL_008a: /* 02 | */ ldarg.0 IL_008b: /* 28 | (06)0001AD */ call instance valuetype [mscorlib]System.DateTime Rhino.Licensing.AbstractLicenseValidator::get_ExpirationDate() IL_0090: /* 8C | (01)000038 */ box [mscorlib]System.DateTime IL_0095: /* 28 | (0A)000140 */ call string [mscorlib]System.String::Concat(object,object) IL_009a: /* 73 | (06)000207 */ newobj instance void Rhino.Licensing.LicenseExpiredException::.ctor(string) IL_009f: /* 7A | */ throw
提出来上面红字的部分
72 700021CC
02
28 060001AD
8C 01000038
28 0A000140
73 06000207
7A
变成实际顺序(还记得那个大端小端吗,不记得可以翻翻第一篇里的描述)
72 CC210070
02
28 AD010006
8C 38000001
28 4001000A
73 07020006
7A
然后在文件(这段HEX所在的文件,这里是 HibernatingRhinos.Profiler.Client.Host.dll )里搜索上面的HEX。找到后,把他们全部清0,这样就可以实现第一处的更改了,剩下的两处原理也是一样的。
OAKY,上面就是第一篇里分析出来的结果,有了这些,这个工具就容易实现了,其实我们的工具就是把上面的工作自动化了而已,自动搜索HEX,然后自动把这段HEX清0。下面我们就来用这个第一处的修改来作为例子说明一下这个工具是怎么写的,修改其它地方的代码你们可以自己去实现或者看源代码里的实现,原理都是一样的 。
代码不是很麻烦,直接上代码 。
string filePath = rootPath + "\\HibernatingRhinos.Profiler.Client.Host.dll" ; // 将要修改的文件读到文件流里。 FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite) ; // 再将文件流写到一个byte[] byte[] buffer = new byte[stream.Length]; stream.Read(buffer, 0, (int)stream.Length); // Rhino.Licensing命名空间里的AbstractLicenseValidator类的 IsLicenseValid 方法 // 里的throw .... /*********************************** 72 700021CC => CC210070 02 28 060001AD => AD010006 8C 01000038 => 38000001 28 0A000140 => 4001000A 73 06000207 => 07020006 7A ***********************************/ byte[] sinCode = new byte[] { 0x72, 0xCC, 0x21, 0x00, 0x70, 0X02, 0x28, 0xAD, 0x01, 0x00, 0x06, 0x8C, 0x38, 0x00, 0x00, 0x01, 0x28, 0x40, 0x01, 0x00, 0x0A, 0x73, 0x07, 0x02, 0x00, 0x06, 0x7A }; // 找到位置 这个方法在源文件里有,可以自己看一看不麻烦。 int startPos = this.findFirstPos(buffer, 0, sinCode); if (startPos > 0) { // 全部清0 for (int i = 0; i < sinCode.Length; i++) { stream.Seek(startPos + i, SeekOrigin.Begin); stream.WriteByte(0x00); } }
这段代码并不是很难,不详细解释了, 看看注释应该就明白了。 :)
从上面我们可以看出,只要作者不对我们改的这几个方法进行变动的话,这个工具就是一直可以使用的,不过如果变动了这几个地方,这个工具也就不能用了 :)