热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

破解ComonentArtLicenseManage流水账,验证过程解析。

流水账介绍在http:www.cnblogs.comsubmaiearchive2004101653105.htm----------
流水账介绍在 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控件中填充注册过的控件类型。再后面的代码就是普通的窗体操作了。


至此,一个验证的过程结束。后面的文章说明如何根据这个验证过程来生成注册码的。
推荐阅读
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
author-avatar
掩飾獨殇_389
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有