Resharper v1.0注册机编写

来源:互联网 发布:windows shell编程入门 编辑:程序博客网 时间:2024/06/06 01:48

本人写这个,仅供学习和研究之用,也算是自己的一个心得,注册后的插件,自己在家玩玩可以,但最好别拿去开发产品,更不要用于商业用途,JBuilder的教训是深刻的,作为公司觉得好还是去买正版吧,这点钱对公司来说还不算贵。如出现版权问题,本人概不负责。

      

上次给大家推荐了Resharper这个Vs.net插件(不知道他是啥的,可以看上次写的推荐一个NB的Vs.net 2003插件 ),虽然后面有兄弟向我推荐coderush,但是我装上了试试,感觉并不是很好,除了PP一点外,没有给我很兴奋的功能,也许也是因为飞刀我用eclipse写了太多的Java吧,还是喜欢与IntelleJ类似的编程工具。

Resharper牛是牛啊,可就是眼看着30天的试用期一天天临近,又舍不499$(看清楚了是美刀)的注册费,我急啊。在网上搜索了N天,也没有找到过Resharper的破解或注册机,无奈,只有自己动手搞定它了。。

这次是第一次上阵搞破解注册,所以水平有限,有搞破解的专家看到了,别笑话俺。。

以下是俺编写Resharper注册机的流水帐,以享观众:

 

一、装备

       .Net反编译器是不能少的,除非你很牛,能轻易看懂IL Code,反编译器就很多,免费的有reflector,要钱的有Remotesoft、.Net Decompiler什么的。有一个就OK,Reflector足够了。

      

二、开始分析

       使用你手上的反编器器,把Resharper安装目录下的dll、exe全部打开,一个个的查看。上天保佑,Resharper竟然是没有被混淆的,而且命名很规范,不愧是出品IntelleJ的公司啊。命名规范,看结构就很容易,很快我就锁定了JetBrainShared.dll中的JetBrains.License命名空间(问我为什么锁定?那么大一个License总认识吧,呵呵)。

       发现在这个命名空间下有四个类:BigInteger、EnterLicenseForm、LicenseChecker、PasteTextBox。看名字就知道PasteTextBox没用,将其它三个类,统统反编译:

1.       BigInteger:大整型,超大整型类,先不管它。

2.       EnterLicenseForm 看名字就知道是输入License的窗口,一定要看,破解的入口啊。

3.       LicenseChecker 不用说了,名字已经很清楚了,八成算法就在里头。

接下来看代码,唉,反编译器还是不能完全反编译,有些地方还是不能搞定,不过不要紧,能看懂就行。

首先查看EnterLicenseForm的源代码,发现里面有一个CheckLicense的方法,估计这就是重点了,JetBrains公司真是太大方了,代码放得这么明显:)

private bool CheckLicense()        {            LicenseChecker checker1;            DateTime time1;            this._okButton.Enabled = false;            if ((this._userName.Text.Length == 0) || (this._edtLicenseKey.Text.Length == 0))            {                this._detailsLabel.Text =                         "Please enter or paste user name and corresponding license key";                return false;            }            string text1 = this.LicenseString;            if (text1.Length == 32)            {                checker1 = new LicenseChecker(this._publicKey, this._userName.Text, "", text1);                // 判断username与license是否匹配                 if (checker1.IsChecksumOK)                {                    time1 = DateTime.Now;                    // 判断是否已经过期了                    if (DateTime.op_GreaterThan(checker1.ExpirationDate, time1.Date)                         && DateTime.op_GreaterThan(checker1.ExpirationDate, checker1.GenerationDate))                    {                        this._detailsLabel.Text                             = ((checker1.ExpirationDate == DateTime.MaxValue) ?                                "Your license is ENDLESS!"                                 :                                 "Expiration date: "                                     + (time1 = checker1.ExpirationDate).ToLongDateString());                        this._okButton.Enabled = true;                        return true;                    }                    time1 = checker1.ExpirationDate;                    this._detailsLabel.Text = "Your license has expired on "                                                 + time1.ToLongDateString();                    return false;                }            }            this._detailsLabel.Text = "The license key is invalid";            return false;        }

代码反编译的效果并不是很好,但是还是能够看出来逻辑,大致是先生成一个CheckLicense实例,传入PublicKey,UserName,以及CompanyName,然后使用IsChecksunOK来判断License与UserName是否配制,然后再比较License中包含过期时间是否大于当前时间。这里看出来过期时间是跟着License走的,而不是像以前一样的是根据安装时间。

       再来看CheckLicense类的结构,主要有五个属性:

IsChecksumOK、Type、Version、GenerateDate、ExpirationDate。

这些属性看名字就知道是什么了,就不解释了。

在EnterLicenseForm中只比较了IsChecksumOK和ExpirationDate两个属性,他们两个属性应当是最重要的。

 

三、失败的破解过程

       人天生都是很懒的,我也一样,一看只是简单的比较了两个属性,就开始想捷径了,想想也是,破解是最省事的,把IsChecksum直接返回true,把ExpirationDate改成DateTime.MaxValue不就一切搞定了??

       马上搞出ildasm,把dll反编译成为il,直接改il 代码,并重新编译,然后把dll向安装目录和Vs.net的privateAssembly目录各copy一份,马上重新打开Vs.net 2003。。

       完了,Resharper插件,根本就不起作用了。。。连菜单都出不来了:(,太失败了。

       是哪里没有搞定呢?我没写过Vs.net插件,并不了解插件的加载过程:(到底是哪里出问题了,我就改了几个il code而已啊。失败,太打击人了。。。

       看来还是直接改字节,做Patch吧。。。

       不过当我用UltraEdit打开dll,看着满屏的16进制码(不要笑话飞刀俺,俺已经N年没碰过了,不像专业搞C的兄弟),算了,找个特征码都要搞死我,放弃。

       这时谷牛人提示我,像我这种对破解不熟的人,还是直接做注册机好,这样也最保险。

       好吧,做注册机吧。

四、注册机

       做注册机,就得搞清别人的算法,算法估计都在LicenseChecker类里面,现在看他的代码吧。。

       首先是构造函数: 

public LicenseChecker(string publickey, string username, string company, string license) {     // 搞定public key       this.N = new BigInteger(publickey, 10);       this._username = username;       this._company = company;       try       {         // _code 就是最终的明文Lincense             this._code = new BigInteger(Convert.FromBase64String(license));       }       catch (FormatException)       {             this._code = LicenseChecker._zero;             return;       }     // 将username转换为Biginteger,并与1进行位或运算       byte[] buffer1 = LicenseChecker.GetBytesFromString(username);       BigInteger integer1 = new BigInteger(buffer1);       integer1 = BigInteger.op_BitwiseOr(integer1, BigInteger.op_Implicit(((int) 1)));      // 解码       this._code = this._code.modPow(integer1, this.N); } 

唉,代码还是太。。。看来Reflector还要改进。不过看懂还是没有问题的,

1. 取得PublicKey,并将其以十进制转换为BigInteger类型

       2. License解码,并转换为BigInteger类型.

       3. username也转换为BigInteger类型,并与1做位或运算,实际上它就是真正的公钥。

       4. usernameBigIntegerpublicKeyBigIntegerLicense做模&&幂运算。

      

看到这里,我算是看懂了,又是BigInteger,又是publicKey,又是modPow运算,再明显不过了,这就是RSA算法嘛!!!太好玩了,兄弟们赶快去找公式,这个算法俺后面就不具体说了的。

       其中BigInteger类是算法的重点,C#中没有现成的类型,用Resharper自带的吧,But由于重载了很多运算符,resharper反编译出来的代码几乎不可读,咋办?

       俺想起了,JDK。。。在JDK 1.4BigInteger是标准库中的,JDK又是开源的,拿过来抄抄嘛:)

       但是一打开JDKBigInteger源代码,天,那么多,还继承至一个Number,而且Java是不支持运算符重载的:(算了,俺很懒,还是网上找找有没有现成的吧。

       Google就是牛,一下子就找到了,还是C#的。。。

       http://www.codeproject.com/csharp/BigInteger.asp

       直接拿过来用吧:)

 

       回头再看,在LicenseChecker构造函数中实际上就是已经把License解码成为“明文”了,并保存在_code字段中了,这个_code代表的“明文”里面又有一些什么信息呢?接着看。

       首先来看IsChecksumOK的源代码 

public bool IsChecksumOK {       get       {             if (this._code != LicenseChecker._zero)             {                   return (((this._code.IntValue() & 65535) % 65521) == this.UserHash());             }             return false;       } } 

这段代码不用多解释,但是很重要,_code65535进行位与运算,并被65521除余UserHash的值,这个UserHash在反编译的代码写的很清楚,虽然反编译的不咋的,但是改一改就可以直接拿来用了。

       这段代码虽少,但是却是算法的关健,实际上就告诉你了,“明文”是啥样子的。

       还有一个重要的属性是ExpirationDate,他的源代码如下:

public DateTime ExpirationDate {       get       {             DateTime time1;         // 以下两句是关健             int num1 = (BigInteger.op_RightShift(this._code, 56).IntValue() & 65535);             if (num1 == 65535)             {                   return DateTime.MaxValue;             }             try             {                   time1 = new DateTime((2003 + (num1 & 127)), ((num1 >> 7) & 15), (num1 >> 11));                   return time1;             }             catch (Exception)             {                   return DateTime.MinValue;             }             return time1;       } } 

这代码太有意思了,看了前两行就不用看了,实际上就是判断(_code >> 56 & 65535) = 65535,等于则返回最大的DateTime,这就是我们要的,我们就是要个无限大的注册时间嘛:)至于后面的带时间的注册信息,看都别看了。。哈哈。

       另外还有几个属性的源代码也是要看一下的,不过,我后面写了一个Check程序验证了几个试用版的号码,发现TypeVersion的值永远为0,所以像TypeVersion这些属性应当是为以后版本准备的,本版本不重要,所以我这里就不多说了。

       “明文”知道了,“密文”又是什么呢?呵呵,这还不简单,License就是加密后的密文嘛:)

       搞到这里,突然想起来CheckerLicener参数中的PublicKey是哪来的还不知道,往上找,找到EnterLicenseForm,发现没有,它自已倒还有一个SetPublic方法,看来,这个PublicKey还是从外面传进来的。

到底是从哪里传来的呢?俺不知道,唉,不了解Vs.net插件是怎么运行的嘛。。。

不过,事到如此,不了解也不行了,马上上网找了几篇讲Vs.net编写插件的文章,一边看一边用,最后又来分析Resharper的结构,花了一个上午,总算是在JetBrains.Resharper.Services.dllJetBrains.Resharper.Shell.Impl命名空间中的LicenseData类找到了它的身影。(唉,这么大一个LicenseData类,我以前怎么就没有看到:()

反编译,PublicKey就这样呈现在我们的面前 

public static string PublicKey {       get       {             return "3439664563558343388897268028516178220150974083190422162869";       } } 

OK,PublicKey知道了,就要来找PrivateKey了。

回来看看RSA算法,我发现CheckLicense中的modPow运算是把PublicKey做N用的,而将Username做为公钥使用的。

          // Iteger1username | 1的结果,NpublicKeybigint
          this._code = this._code.modPow(integer1, this.N);

       这就意味着,这个publickey,就是两个素数的积(即p * q),只要我算出这两个素数,就可以知道z(即(p-1) * (q-1)),从而就可以知道真正的密钥d了。

       但是MyGod,这个publicKey足有60位啊!!!估计p、q的取值也在1*10的29次方至1*10的30次方之间,俺穷人的机器只有AMD 号称的XP 1700+啊。你要让我算多久啊。。。。

神啊救救我吧。。 

四、大功告成

神来了,那就是发动群众的力量,半夜三更爬上MSN,发动群众帮我找高效的RSA分析工具或算法, IceSharK兄弟一连给俺找了三四个RSA工具,其中有个叫RSATool的东东,看样子还蛮专业的,不管它,用上先。

运气真好,神立马就出现了:)本来我还以为要算上几天的,结果在和IceSharK聊天的几分钟内就完成了,不敢相信啊。

结果如下,P 、Q全出来了:)

       p: 76934561593903517890538965067

q: 44708964245672789920122782207

e: 3439664563558343388897268028516178220150974083190422162869

       由于BigInteger算出来的素数并不一定是完全正确的,所以我还不敢肯定的说已经成功了。但是总要试试吧。将P、Q的值分别代入公式

       Z = (p – 1) * (q – 1)

       Z = 3439664563558343388897268028394534694311397775379760415596

       OK,知道了Z,D也就搞定了。

       现在P、Q、Z 、E、D、MI,CI都统统知道了,加密还有啥难的呢:)代公式就行了。

       完成这个注册机:),VS.net 2003写的。 


用算出的号码一试,哈哈。 


OK,大功告成:)

 

以下是注册机的核心算法,主要就这些,其它的都是winform操作:)

这样看,代码就很简单了:

// 生成License         // 飞刀再次提醒,本代码仅学习和研究之用,千万别用于商业,否则版权纠纷很麻烦的。         private string getLicense()         {             int iUserHash = UserHash();              // 基础的Seed,即找到Endless License的明文             BigInteger bigBaseSeed = new BigInteger((long) 65535);             bigBaseSeed <<= 56; // 校验代码中向右移56位,我就向左移56位             bigBaseSeed += new BigInteger((long) iUserHash); // 为了使IsChecksum返回true              // Public Key 即充当N             BigInteger bigPublickKey = new BigInteger(Constants.PUBLIC_KEY, 10);              // Private Key 即充当Z             BigInteger bigPrivateKey = new BigInteger(Constants.PRIVATE_KEY, 10);              // 用户名计算 即充当E             BigInteger bigUserName = new BigInteger(Encoding.Default.GetBytes(_username));             bigUserName |= 1;              // 搞定最重要的密钥D             BigInteger bigD = bigUserName.modInverse(bigPrivateKey);              // 套加密公式 ci = n^d mod n             BigInteger bigLicense = bigBaseSeed.modPow(bigD, bigPublickKey);               return (Convert.ToBase64String(bigLicense.getBytes()));         }          // UserHash ,直接从反编译的源代码中抄过来的         // 作用是判断用户名与License是否匹配         private int UserHash()         {             int i = 0;             for (int j = 0; j < _username.Length; j++)             {                 i = ((i << 7) + _username[j])%65521;             }              for (int k = 0; k < _company.Length; k++)             {                 i = ((i << 7) + _company[k])%65521;             }             return (i);         } 

从这里摘抄过来的:http://www.cnblogs.com/feidao/archive/2004/08/12/32537.aspx。