作者:掩飾獨殇_389 | 来源:互联网 | 2023-08-12 07:53
流水账介绍在
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((string) this._resources["RegistryRoot"], (string) this._resources["RegistryLicenseKeysNode"], (string) this._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 License 和
Web.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控件中填充注册过的控件类型。再后面的代码就是普通的窗体操作了。
至此,一个验证的过程结束。后面的文章说明如何根据这个验证过程来生成注册码的。