前几天,JetBrains公司放出了ReSharper 4.0的正式版,非常好用,唯一遗憾的是没找到破解,忽然心血来潮自己实验了一把。
记得以前在博客园上看见过一篇说破解ReSharper的文章,赶紧翻来一看,结果发现他是破解1.0版本的。囧…,都差了3代了,不晓得还行不行得通。果然,文章中说的JetBrainShared.dll这个文件根本就没有了。没办法,只好用Refactor把程序安装目录下的dll文件一个个打开看,终于发现了一点端倪。在 JetBrains.Platform.ReSharper.Shell.dll下面发现了命名空间 JetBrains.Application.License,结构如下
恩,看样子就是这个了。和文章说所贴出的代码一对比,好家伙,竟然完全没变。我忽然感觉春天就要来了。
LicenseChecker的代码如下
public LicenseChecker(string publickey, string username, string company, string license)
{
this._hasLicense = license.Length > 0;
this.N = new BigInteger(publickey, 10);
this._username = username.Trim();
this._company = company;
try
{
this._code = new BigInteger(Convert.FromBase64String(license));
}
catch (FormatException)
{
this._code = _zero;
return;
}
BigInteger exponent = new BigInteger(GetBytesFromString(username));
exponent |= 1;
this._code = this._code.modPow(exponent, this.N);
}
接下来就是找publickey了,不过publickey显然没那么好找,弄了很久,终于在JetBrains.ReSharper.VS.dll下发现这段代码
public class ReSharperLicenseSupport : ILicenseSupport
{
// Fields
private List<ProductEdition> myEditions;
protected readonly Dictionary<string, LicenseData.AcceptLicenseDelegate> myLicensePublicKeys;
private readonly string myProductGuid;
protected static string ReSharper25PublicKey = "3439664563558343388897268028516178220150974083190422162869";
protected static string ReSharper30CSPublicKey = "2062698303447698628762013575505401016248061446308190177781";
protected static string ReSharper30FullPublicKey = "4441135767558381656065245909629448701427951998710398510961";
protected static string ReSharper30VBPublicKey = "3849433023835942333262638180741437187304961860850269199253";
protected static string ReSharperPublicKey = "3483968730802868401158985191529641621586542542912639916793";
其中,ReSharper25PublicKey的值和文章中一样,看样子在ReSharper2.5之前,所有版本都用的一类序列号,呵呵。
找到publickey就好办了,按文章中下载到RSATool,然后直接计算出P:48625079161695385866568653587,Q: 71649625889912785451603068739。生成验证码一看,囧...提示”License to version 0.0 is not acceptable”...注册失败!
看样子验证方式还是改了一点,没办法,继续Refactor,然后终于发现:
if (data.ProductVersion < this.Version)
{
return new LicenseCheckResult("License to version {0}.{1} is not acceptable", new object[] { data.ProductVersion / 0x3e8, data.ProductVersion % 0x3e8 });
}
return LicenseCheckResult.LICENSE_VALID;
这里就是验证版本号了,0x3e8是1000,也就是说版本要不小于4000(0xfa0)。事实上,可以在里面找到这样一段代码
public static readonly int LicenseAppVersion = 0xfa0;
也就是说只需要在验证码中提供版本号信息就行了,最终代码 如下
using System;
namespace ResharperKeyGen
{
public class KeyGen
{
/// <summary>
/// Resharper内置的公钥
/// </summary>
private const string PUBLIC_KEY = "3483968730802868401158985191529641621586542542912639916793";
private const string PRIVATE_KEY = "3483968730802868401158985191409366916534934371594468194468";
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 公司名
/// </summary>
public string CompanyName { get; set; }
public KeyGen()
{
CompanyName = string.Empty;
}
/// <summary>
/// 修改自飞刀兄的代码
/// </summary>
/// <returns></returns>
public string GetLicense()
{
int userHash = UserHash();
// 基础的Seed,即找到Endless License的明文
var bigBaseSeed = new BigInteger(65535);
bigBaseSeed <<= 56; // 校验代码中向右移56位,我就向左移56位
bigBaseSeed += new BigInteger(userHash); // 为了使IsChecksum返回true
// 匹配版本,Resharper 4.0不但检测userhash,还检测版本号
var bigbaseseed1 = new BigInteger(4000);
bigbaseseed1 <<= 72;
bigBaseSeed += bigbaseseed1;
// Public Key 即充当N
var bigPublickKey = new BigInteger(PUBLIC_KEY, 10);
// Private Key 即充当Z
var bigPrivateKey = new BigInteger(PRIVATE_KEY, 10);
// 用户名计算 即充当E
var exponent = new BigInteger(GetBytesFromString(UserName));
exponent |= 1;
// 搞定最重要的密钥D
BigInteger bigD = exponent.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 < CompanyName.Length; k++)
{
i = ((i << 7) + CompanyName[k]) % 65521;
}
return i;
}
private static byte[] GetBytesFromString(string s)
{
var result = new byte[s.Length];
for (int i = 0; i < s.Length; i++)
{
char ch = s
;
int intValue = ch;
result = (byte)(intValue & 0x7f);
}
return result;
}
}
}
完成后测试一下,大功告成,第一个算号器就这么诞生了