ReSharper一直以来以c#的插件闻名, 最近发现他新出的c++插件也挺好用的,就是代码提示有点慢。他的插件都是.net实现的, 之前没搞过.net破解, 把学习过程跟大家分享下
大概是因为性能考虑, 他的代码没有混淆,直接用ILSpy 看,对照写一个假的处理函数,生成假dll,分别用ILDasm导出 假dll 和 原始dll 的IL代码, 然后替换,再用ILAsm编译回去替换就好了。
因为逻辑较多,废了很长时间才找到他的注册码处理函数DecodeLicense
中间试过动态调试, 结果ILSpy的debugger插件attach不上vs, PEBrowser也各种出错,最后只能用在假dll加 Trace.WriteLine 的方法打印出流程, 及找出代码修改的问题
// JetBrains.Application.License2.NewLicenses.UserLicenseService
public NewLicenseData DecodeLicense(string base64)
{
return Logger.CatchIgnore<NewLicenseData>(delegate
{
List<StringSlice> list = new StringSlice(base64).Trim().Split(new char[]
{
'-'
}).ToList<StringSlice>();
if (list.Count != 4)
{
return null;
}
StringSlice stringSlice = list[0];
StringSlice stringSlice2 = list[1];
StringSlice stringSlice3 = list[2];
StringSlice stringSlice4 = list[3];
byte[] left = MD5.Create().ComputeHash(this.RootCertificate.RawData);
byte[] right = new byte[]
{
75,
251,
173,
56,
28,
192,
192,
50,
63,
169,
145,
143,
230,
144,
67,
120
};
if (!left.EqualEnumerables(right))
{
return null;
}
byte[] rawData = Convert.FromBase64String(stringSlice4.ToString());
X509Certificate2 x509Certificate = new X509Certificate2(rawData);
if (!UserLicenseService.VerifyCertificate(x509Certificate, new X509Certificate2[]
{
this.RootCertificate
}))
{
return null;
}
if (this.RevocedCertificateSerialNumbers.Contains(x509Certificate.SerialNumber))
{
return null;
}
byte[] bytes = Convert.FromBase64String(stringSlice2.ToString());
string @string = Encoding.UTF8.GetString(bytes);
if (!UserLicenseService.VerifySignature(@string, stringSlice3.ToString(), x509Certificate))
{
return null;
}
NewLicenseData newLicenseData = NewLicenseData.FromJson(@string);
if (newLicenseData != null && !stringSlice.Equals(newLicenseData.LicenseId))
{
return null;
}
return newLicenseData;
});
}
之前有人破解是将程序里的证书替换成自己的证书来验证License,但新版本里给证书加了md5验证,写死在代码里。 当然也可以改这个写死的md5码,不过既然改程序了,不如都改了,
改成直接创建NewLicenseData返回。
// JetBrains.Application.License2.NewLicenses.UserLicenseService
public NewLicenseData DecodeLicense(string base64)
{
return Logger.CatchIgnore<NewLicenseData>(() => new NewLicenseData
{
LicenseId = "1",
LicenseeName = "Raven",
AssigneeName = "Raven-PC",
LicenseRestriction = null,
CheckConcurrentUse = false,
AutoProlongated = true,
Hash = "",
GracePeriodDays = 0,
Products = new List<ProductData>
{
new ProductData
{
Code = "RSU",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "DM",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "II",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "AC",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "CL",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "DB",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "PS",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "PC",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "RM",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
},
new ProductData
{
Code = "WS",
FallbackDate = DateTime.MinValue,
PaidUpTo = DateTime.MaxValue
}
}
});
}
最后发现这个dll有强名称验证
可以把因为这个dll的assembly的引用改掉,不过因为这个dll引用太多了,改起来比较麻烦, 我采取了比较极端的方式,直接改clr 里的强名称验证函数
BOOLEAN __stdcall StrongNameSignatureVerification(LPCWSTR wszFilePath, DWORD dwInFlags, DWORD *pdwOutFlags)
{
BOOLEAN v3; // bl@1
int v4; // esi@2
int *v5; // eax@2
int v6; // ecx@2
int v7; // esi@7
_DWORD *v9; // eax@17
_DWORD *v10; // eax@20
char v11; // [sp+14h] [bp-40h]@9
char v12; // [sp+1Ch] [bp-38h]@2
char v13; // [sp+3Ch] [bp-18h]@6
int v14; // [sp+50h] [bp-4h]@2
v3 = 1;
if ( !byte_1064D308 )
goto LABEL_2;
if ( dword_1065D0D0(12) )
{
if ( byte_1064D308 )
sub_1042876E(&v11);
LABEL_2:
v14 = 0;
memset(&v12, 0, 0x28u);
v4 = sub_100CA6D3();
v5 = (int *)sub_100CA6E5();
if ( v4 >= 0 )
{
if ( v5 )
*v5 = 0;
if ( !wszFilePath )
{
v9 = (_DWORD *)sub_100CA6E5();
if ( v9 )
*v9 = -2147467261;
goto LABEL_19;
}
v13 = 1;
if ( (unsigned __int8)sub_1009DEAE(&v12, v6, 1) )
{
v7 = sub_1009D71C(&pbEcmaPublicKey, pdwOutFlags);
if ( v7 < 0 )
{
v10 = (_DWORD *)sub_100CA6E5();
if ( v10 )
*v10 = v7;
v3 = 0; // 这里
}
if ( (unsigned __int8)sub_1009DC2A(&v12) )
goto LABEL_9;
if ( !v3 )
{
LABEL_19:
v3 = 0; // 这里
LABEL_9:
v11 = 0;
v14 = -1;
if ( byte_1064D308 )
sub_10428786(&v11);
return v3;
}
}
v4 = sub_100C6DFA();
v5 = (int *)sub_100CA6E5();
}
if ( v5 )
*v5 = v4;
goto LABEL_19;
}
if ( dword_1065D0D4 )
dword_1065D0D4(0);
return v3;
}
返回值有两处被赋值为0, 改为1就好了
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课