破解的 Charles 版本 3.13.2, 下载路径:https://www.charlesproxy.com/download/previous-release
在线反编译 jar 工具: http://www.javadecompilers.com/, 使用 jd-gui 可以方便的把jar直接反编译
成java文件,在界面以只读的方式展现。 有可能某个工具反编译出来的代码在 IDEA 这种 IDE 会报
错,那是因为反编译不完整或者反编译出错,这时候就得多尝试几种反编译工具,找寻正确的核心代码。这
里具体的破解过程就不再赘述了,只记录核心思路。
实现破解方式
- 看源代码,找寻是否有 if ( check(license) ) {} else {} ** 这种类似的检查license** 的代码,如果找到了
可以修改这个类的字节码,把这里的判断条件强势改为 true, 就相当于绕过了检查license 判断,可以
实现该版本的破解了。
- 第一种方式太简单了,一般很少见。常见的是网上流传的各种失效的license key,思考一下,如果我们
自己是这个软件的开发者,有license key泄露了,会怎么做?安全的方式是将这个 license key 写死在
代码里进行判断,相当于一种黑名单的方式,那我们就根据这个license key 去代码里搜,找到对应的位置修
改字节码即可。
- 上面两种方式只能在对应的版本才能生效,只有找到它的激活码生成逻辑才能跨版本使用,才是最稳妥方
式。因为有高人指点,所以一开始就那用这种方式了。
经过一番折腾,找到 License 的校验代码:
private long c(final String s, final String s2) {
if (s2.length() != 18) {
throw new LicenceException(this.a(0));
}
// 黑名单校验逻辑
if (s2.equalsIgnoreCase("7055ce2f8cb4f9405f") || s2.equalsIgnoreCase("5bae9d8cdea32760ae") || s2.equalsIgnoreCase("f3264994d9ea6bc595") || s2.equalsIgnoreCase("b9930cef009d3a7865") || s2.equalsIgnoreCase("62bd6a5f95aa67998e") || s2.equalsIgnoreCase("a1c536c35904e64584") || s2.equalsIgnoreCase("d6e5590ecc05edd9b3") || s2.equalsIgnoreCase("8fbe36ce2726458b18") || s2.equalsIgnoreCase("042a8352caf1188945") || s2.equalsIgnoreCase("9d26d5088770221c3c") || s2.equalsIgnoreCase("e19b2a01905e4129bf") || s2.equalsIgnoreCase("68ebe4c9d792f31057") || s2.equalsIgnoreCase("4e4beb8a43e9feb9c7") || s2.equalsIgnoreCase("d04d85b44b306fc9ec") || s2.equalsIgnoreCase("2b5d21a38c9452e342") || s2.equalsIgnoreCase("88cb89c26a813bce44") || s2.equalsIgnoreCase("76c9ee78c8ab124054") || s2.equalsIgnoreCase("729db7c98163ac7d3d") || s2.equalsIgnoreCase("7c1d4761993c412472") || s2.equalsIgnoreCase("08bc0b7ec91cd0f4aa") || s2.equalsIgnoreCase("25bafae175decaedcc") || s2.equalsIgnoreCase("3181aae6822ef90ccd") || s2.equalsIgnoreCase("d7a8fe9dc9dc919f87") || s2.equalsIgnoreCase("728dae81d9d22aca03") || s2.equalsIgnoreCase("119a9b593348fa3e74") || s2.equalsIgnoreCase("04ab87c8d69667878e") || s2.equalsIgnoreCase("4b282d851ebd87a7bb") || s2.equalsIgnoreCase("ed526255313b756e42") || s2.equalsIgnoreCase("ed5ab211362ab25ca7") || s2.equalsIgnoreCase("18f4789a3df48f3b15") || s2.equalsIgnoreCase("67549e44b1c8d8d857") || s2.equalsIgnoreCase("4593c6c54227c4f17d") || s2.equalsIgnoreCase("1c59db29042e7df8ef") || s2.equalsIgnoreCase("a647e3dd42ce9b409b") || s2.equalsIgnoreCase("7e06d6a70b82858113") || s2.equalsIgnoreCase("ef4b5a48595197a373") || s2.equalsIgnoreCase("0ac55f6bebd0330640") || s2.equalsIgnoreCase("1beda9831c78994f43") || s2.equalsIgnoreCase("8a2b9debb15766bff9") || s2.equalsIgnoreCase("da0e7561b10d974216") || s2.equalsIgnoreCase("86257b04b8c303fd9a") || s2.equalsIgnoreCase("a4036b2761c9583fda") || s2.equalsIgnoreCase("18e69f6d5bc820d4d3")) {
throw new LicenceException(this.a(1));
}
final long n = Long.parseLong(s2.substring(2, 10), 16) << 32 | Long.parseLong(s2.substring(10, 18), 16);
final int int1 = Integer.parseInt(s2.substring(0, 2), 16);
this.d(-5408575981733630035L);
final long c;
if (b(c = this.c(n)) != int1) {
throw new LicenceException(this.a(1));
}
this.e = (int)(c << 32 >>> 32 >>> 24);
if (this.e == 1) {
this.f = 1;
}
else if (this.e == 3) {
this.f = (int)(c << 32 >>> 32 >>> 16 & 0xFFL);
if (this.f != 1 && this.f != 2 && this.f != 3) {
throw new LicenceException(this.a(1));
}
}
else {
if (this.e <= 3) {
throw new LicenceException(this.a(1));
}
this.f = (int)(c << 32 >>> 32 >>> 16 & 0xFFL);
}
this.d(8800536498351690864L);
try {
final byte[] bytes = s.getBytes("UTF-8");
final int length;
int n2;
if ((n2 = (length = bytes.length) + 4) % 8 != 0) {
n2 += 8 - n2 % 8;
}
final byte[] array = new byte[n2];
System.arraycopy(bytes, 0, array, 4, length);
array[0] = (byte)(length >> 24);
array[1] = (byte)(length >> 16);
array[2] = (byte)(length >> 8);
array[3] = (byte)length;
final byte[] c2 = this.c(array);
int n3 = 0;
byte[] array2;
for (int length2 = (array2 = c2).length, i = 0; i < length2; ++i) {
final int n4 = n3 ^ array2[i];
n3 = (n4 << 3 | n4 >>> 29);
}
return 0xA58D19C600000000L | (long)(n3 ^ (int)(c >> 32)) << 32 >>> 32;
}
catch (UnsupportedEncodingException ex) {
return -1L;
}
}
只能帮大家到这了,需要license的留言我帮你生成一个,全版本通用。这里记录点 tips
Tips
- 或运算的逆运算是 & ~. 如: x = a | b => b = x & ~b.
- 有些函数很复杂,找关键点,要这样想,这种验证的方式肯定不是开发者自己写的,大概率是网上开源的实现。善用搜索引擎,发现相似的源代码就能用了。(这里是RC5)
- 验证生成的license key是否有效,需要用到java的反射机制,调用这个方法,看返回值。
- 破解过程很有意思,多动脑,善用位运算,最好把它的每一步都理解到位,这样破解就很容易了。