偶然在网上看到这个软件,效果很炫,合成出来的图片效果也不错,不过是个收费的软件,最后保存的图片会加上很大的水印字体。
由于本人对.NET有些了解,所以先看看这个软件是不是dotNET语言写的,如果不是,那我就无能为力了。用ildasm.exe反编译此软件,得到如下所示(下面分析的过程需要对MSIL有一定的基础才能看懂):
很庆幸是dotNET语言写的,好了,找到程序的入口点即Main函数,从图上很容易看出在Microsoft.AutoCollage.AppMain中,打开这个类,点开相应的Main函数,找到如下代码所示的部分:
可以清楚的看到在程序开始的时候要检查注册吗,这个程序的注册码形式是:XXXXX-XXXXX-XXXXX-XXXXX-XXXXX,别管怎么样,先看看Microsoft.AutoCollage.Helpers.RegistrationHelper这个类再说,所有的验证工作都在这里面做的,下面是这个类的截图:
我们可以很容易的从函数的名字上看到这个函数的作用,譬如get_ProductID函数肯定是取得产品的ID,get_IsRegistered是判断是否软件已经注册了,等等。由于本人很笨,不会研究算法,所以根据用户的输入算出具体的合法注册码算法部分直接掠过,咱只看它如何验证是个合法的注册码。先查看get_IsRegistered函数内容,如下所示:
从图中看出这个方法调用了get_ProductID方法,如果get_ProductID方法返回的字符串不为空则是合法的注册码,为空则是不合法的,那好了,咱们进入get_ProductID方法看看具体的检查过程:
.method assembly hidebysig specialname static string get_ProductID() cil managed { // Code size 116 (0x74) .maxstack 2 .locals init (string V_0, class [mscorlib]Microsoft.Win32.RegistryKey V_1, class [mscorlib]Microsoft.Win32.RegistryKey V_2) IL_0000: ldnull IL_0001: stloc.0 .try { IL_0002: ldsfld class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.Registry::LocalMachine IL_0007: stloc.1 IL_0008: ldloc.1 IL_0009: ldstr "SOFTWARE//Microsoft//Microsoft Research AutoCollage" + "//2008//Registration" IL_000e: callvirt instance class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.RegistryKey::OpenSubKey(string) IL_0013: stloc.2 IL_0014: ldloc.2 IL_0015: brfalse.s IL_0028 IL_0017: ldloc.2 IL_0018: ldstr "ProductID" IL_001d: callvirt instance object [mscorlib]Microsoft.Win32.RegistryKey::GetValue(string) IL_0022: isinst [mscorlib]System.String IL_0027: stloc.0 IL_0028: leave.s IL_0030 } // end .try catch [mscorlib]System.Security.SecurityException { IL_002a: pop IL_002b: leave.s IL_0030 } // end handler catch [mscorlib]System.Exception { IL_002d: pop IL_002e: leave.s IL_0030 } // end handler IL_0030: ldloc.0 IL_0031: call bool [mscorlib]System.String::IsNullOrEmpty(string) IL_0036: brfalse.s IL_003a IL_0038: ldloc.0 IL_0039: ret IL_003a: ldloc.0 IL_003b: callvirt instance int32 [mscorlib]System.String::get_Length() IL_0040: ldc.i4.s 23 IL_0042: beq.s IL_0048 IL_0044: ldnull IL_0045: stloc.0 IL_0046: br.s IL_006d IL_0048: ldloc.0 IL_0049: ldc.i4.5 IL_004a: callvirt instance char [mscorlib]System.String::get_Chars(int32) IL_004f: ldc.i4.s 45 IL_0051: bne.un.s IL_006b IL_0053: ldloc.0 IL_0054: ldc.i4.s 9 IL_0056: callvirt instance char [mscorlib]System.String::get_Chars(int32) IL_005b: ldc.i4.s 45 IL_005d: bne.un.s IL_006b IL_005f: ldloc.0 IL_0060: ldc.i4.s 17 IL_0062: callvirt instance char [mscorlib]System.String::get_Chars(int32) IL_0067: ldc.i4.s 45 IL_0069: beq.s IL_006d IL_006b: ldnull IL_006c: stloc.0 IL_006d: ldloc.0 IL_006e: call string [System.Web]System.Web.HttpUtility::HtmlEncode(string) IL_0073: ret } // end of method RegistrationHelper::get_ProductID
从IL_0009:行我们看到,首先检查注册表是否有"SOFTWARE//Microsoft//Microsoft Research AutoCollage//2008//Registration"这个子键,通过regedit查看自己的注册表。如果没有则跳转到IL_0028行,那估计肯定是验证不通过了。如果有,继续往下看,IL_0018和IL_001d行,这两行是在读取上一个注册表键下面的一个键值,其中键key叫"ProcductID",并且把取得的值存在局部变量中,这个局部变量在一开始就声明了,我们不用管它。继续往下看(省略异常处理部分),到IL_0031,先检查刚才取得的字符串是否为空或者null,如果是则返回了,那么证明没有注册码,不为空继续往下走到IL_003b,取得字符串的长度,然后和IL_0040行加载到栈上的数值做比较,也就是23,所以这两行的意思就是检查注册码的长度是否是23。所以我们可以得出,用户输入的验证码经过某种算法之后被存入到注册表中的,而不是直接存入的。
如果注册码的长度不是23,那肯定over了,是23继续往下走。到IL_0049行,可以看到又把整数5加载到了栈上,然后调用get_Chars函数得到上面取得的字符串的第5位字符,IL_004f行,把整数45加载到栈上和上面取得的第5位字符相比较,我们知道字符在计算机中也是用整数表示的,所以这里可以查看ASCII码表,看看45表示什么,经过查看是字符'-'。比较的结果是,如果相等继续往下,不等又over了。
下面的过程和上面的是重复的,其中比较了第5位,9位,17位,都是和'-'进行比较,如果相等就是合法的。也就是说合法注册吗的形式是:SSSSS-SSS-SSSSSSS-SSSSS,其中可以用任意字符填充S,只要保证第5,9,17是'-'即可。在注册表中建立相应的键值,然后在运行程序,看看效果,如下图所示:
可以看到已经是注册的了!Done!在用程序合成的图片就不会有水印了~~
注:本篇文章只为学习研究用,不用于任何商业目的,转载请注明出处,如有任何违规行为会立刻删除!