破解ComonentArt License Manage 流水账,验证过程解析。

流水账介绍在 http://www.cnblogs.com/submaie/archive/2004/10/16/53105.htm

//----------
// 对不起,前两天我在忙评职称的事情,单位让我评工程师职称,这两天一直在忙,写了5000字的技术工作总结。没有来的急写,请原谅!
//----------

1 终于破解了ComponentArt Web.UI 2.0  Asp.Net 自定义服务器控件库的License Manager程序,可以让ComponentArt 的安装程序在安装的时候自动把Web.UI 2.0 控件的全部源代码也给安装了。
2 我非常佩服飞刀兄,他做的注册机方法才是正宗的,而我不是,我使用了一种叫“偷梁换柱”的方法欺骗了ComponentArt的安装工具。具体请看我的分析思路。
3 这个分析包含的所有代码我已经打包成微软标准的MSI安装包,下载地址在这里,它是一个标准的InstallShield 生成的安装文件,可以放心安装。一定要安装到E:\CpmponentArt 目录下,大家不要更改这个地址,即可在开始菜单中直接打开Vs.Net 2003的项目了。在解决方案中包含了两个项目,ComponentArt.Licensing.Manager项目是在代码中已经破解好的,Licensing.Manager项目是原始代码。这两个项目中输入Key的文本框已经定义了默认的 WUS-WEBUI2_SUB-02 字符串,不过这个字符串不是合法的注册码,根本不能通过注册。具体原因请继续看我的破解思路。

好,说了太多的废话,现在开始技术内容。
做任何注册机/分析注册码的工作都必须了解官方注册流程。所以第一步必须要了解它。我与飞刀的方法不同,他是直接定位注册机的加密算法,然后写一个反算法就变成注册机了。从ComponentArt上下载一个安装文件,开始安装,如图



很明显,有两个选项,一个输入注册码,一个使用试用版。如果选择了“Enter License Keys Now”,则单击下一步时会启动一个程序,程序的名称是 ComponentArt.Licensing.Manager.exe,它负责验证注册码,然后写入信息到注册表。这时,我第一个反应就是这个.exe程序是使用.Net 写的,只有.Net的程序是无法直接集成到InstallShield的界面中。

等安装完毕后,我立即启动Reflector反编译软件,经过努力,生成了这个.exe的C#源代码。这时,我开始检查注册码的验证步骤。我使用的软件是Vs 2005,它的调试功能非常强。首先从主窗口MainForm的构造器开始,发现初始化的步骤如下:
首先生成一个名叫 Manager 的类,从这个类的构造函数可以看出:
public Manager()
{
            
this._resources = new SortedList();
            
this._licensedata = new LicenseData();
            
this._smallicons = new ImageList();

            ResourceReader reader1 
= new ResourceReader(this.GetType().Assembly.GetManifestResourceStream("ComponentArt.Licensing.Manager.Resource.Manager.resources"));
            IDictionaryEnumerator enumerator1 
= reader1.GetEnumerator();
            
while (enumerator1.MoveNext())
            
{
                
if (enumerator1.Value.GetType() == typeof (Bitmap))
                
{
                    
this._smallicons.Images.Add((Bitmap) enumerator1.Value, Color.White);
                    
continue;
                }

                
this._resources.Add(enumerator1.Key, enumerator1.Value);
            }

            
//this._licensedata.ReadXml(base.GetType().Assembly.GetManifestResourceStream("ComponentArt.Licensing.Management.LicenseData.xml"));
            this._licensedata.ReadXml(this.GetType().Assembly.GetManifestResourceStream("ComponentArt.Licensing.Manager.Resource.LicenseData.xml"));
            
char[] chArray1 = new char[1{','};
            
char[] chArray2 = new char[1{','};
            
this._licensecollection = new LicenseCollection((stringthis._resources["RegistryRoot"], (stringthis._resources["RegistryLicenseKeysNode"], (stringthis._resources["RegistryLicenseKeyTokensNode"], this._resources["SmallIconIndex"].ToString().Split(chArray1), this._resources["SourceCodeIndex"].ToString().Split(chArray2), ref this._licensedata);
}

从上面的代码可以看出,最重要的操作就是生成了一个名叫_licensedata 的LicenseData类型对象,他拥有ReadXml 方法,从保存成资源的名为LicenseData.xml文件中生成LicenseData对象。然后查看这个Xml文件,发现是一个.Net DataSet 的Xml映像,那么他生成的LicenseData肯定是一个DataSet类型对象,用来与注册码计算后的内容比较。通过注册码可以获得安装的Web.UI控件的版本类型。根据官方网站的产品FAQ,有两种版本是拥有源代码的,他们保存在Xml文件中的名称是 Web.UI for ASP.NET 2.x - Corporate Site LicenseWeb.UI for ASP.NET 2.x - Subscription License ,这两种版本都是包含源代码,就是说如果我们能够让注册码通过计算后验证获得的关键字(这个关键字是什么现在还不知道)与上面两个版本的关键字匹配,那么安装程序就可以把源代码安装了。

好,我们开始单步执行验证功能,在vs2005中,定位到输入注册码后的“OK”按钮上,双击鼠标转到代码,然后在执行的第一行代码上添加断点,然后开始调试。

首先,代码把输入的注册码添加到Manager对象中的Licenses属性指向的LicenseCollection中(使用Add方法),然后控制转向到LicenseCollection类的Add方法中。

第一步是一个for循环,它检查LicenseCollectionItem的Key属性是否与输入的Key属性匹配,如果匹配,那么表示注册码已经被验证,则抛出异常推出。从这里可以看出,LicenseCollectionItem是负责处理解密注册表中的加密注册信息的。

如果没有,则新建一个LicenseCollectionItem对象,看样子窍门在这里,继续单步执行。它表示是一个新的许可,其构造函数的参数包含了刚才输入的Key,由Manager对象生成的与输入Key做比较的LicenseData对象,还有就是RegistryTokensCollection对象,这时候已经非常明确了,这个RegistryTokensCollection就是负责读取和写入注册表的对象。而且,注册表从代码中可以看出是在HKEY_LOCAL_MACHINE\SOFTWARE\ComponentArt\Web.UI for ASP.NET\2.0 内,这儿就是存放最重注册码的地方。另外,其主键名称是“Token”。

然后,开始匹配,操作就是使用户输入的Key赋值给刚才新建的那个LicenseCollectionItem对象的Key属性。继续执行。这时,操作权转向到LicenseCollectionItem的Key属性中,终于到了验证用户输入的Key的时候了,原来Key的set操作有一大堆代码,如下:
public string Key
        
{
            
get return _licensekey; }

            
set
            
{
                _licensekey 
= value;
                
try
                
{
                    _licensecode 
= LicenseCodeFromKey(_licensekey);
                    _licensename 
= LicenseNameFromCode(_licensecode);
                    _licensebuild 
= LicenseBuildFromKey(_licensekey);
                    _issubscription 
= SubscriptionTypeFromCode(_licensecode);
                    _issourcecode 
= SourceCodeTypeFromCode(_licensecode);
                    
if (_issourcecode)
                        _sourceentitlement 
= GetSourceCodeEntitlement();
                    _expiry 
= KeyEncoding.ExpiryDateFromKey(_licensekey);
                    _registrytokenscollection.Load(_licensekey, _licensecode);
                    _displaycollection.Load(_licensekey, _licensecode);
                    
return;
                }

                
catch (Exception e)
                
{
                    
throw e;
                }

            }

        }

从上面的属性定义代码可以看出,首先,程序把用户输入的Key赋予给一个本地变量,然后对这个本地变量用各种方法进行查询,从这些查询获取要注册的版本类型,版本名称,版本Build值,这个值看样子是参与计算用的,是否为Subscription,是否包含源代码,控件的到期时间等。而这个代码就是执行验证算法,从代码可以看出,所有的代码都调用了一个名叫 KeyEncoding类中的静态方法,那么这个KeyEncoding类就是执行加密解密计算的类了,转换算法肯定都在里面。

根据从LicenseData类获得的信息(此类中的数据存放在LicenseData.xml文件内),以上的所有代码查询的信息是LicenseData类中License属性中的信息。表示当前处理的是许可信息。

代码调试到这里就执行不下去了,不过没关系,验证器的基本流程都出来了,我们可以使用“眼睛”来运行代码。

下面,有一行这样的代码
_registrytokenscollection.Load(_licensekey, _licensecode);
肯定是刚才生成的RegistryTokenCollection负责执行注册表操作的对象,根据Key,生成一个RegistryTokenCollectionItem对象,再一次验证用户输入的Key,根据Key查询的是LicenseData中Product属性返回的Product表中的内容,然后根据RegistryTokenCollectionItem重新初始化RegistryTokenCollection对象。在这里面要注意的是RegistryTokensCollectionItem类在初始化的时候生成的_token内部变量,这是一个字符串变量,这个变量通过Token属性输出,内容就是写在注册表中的内容。

在上面的所有方法中,如果有一处没有找到对象,都会抛出一个内容是“Invalid license key“ 的异常,表示注册码验证失败。

然后,控制权又返回到MainForm中,执行方法是butOK_Click(),下面的方法Fill()就是向ItemList控件中填充注册过的控件类型。再后面的代码就是普通的窗体操作了。


至此,一个验证的过程结束。后面的文章说明如何根据这个验证过程来生成注册码的。

posted on 2004-10-19 15:30  笑望人生  阅读(8001)  评论(39编辑  收藏  举报

导航