仅用于学习和研究目的。如果你觉得 Charles 好用,请务必支持正版!
⚠️ 温馨提示: Charles 是一个非常出色的工具,由优秀的开发者投入了大量心血制作。本工具旨在剖析其注册算法,供密码学爱好者学习。请通过官方渠道购买许可证来支持开发者继续维护和更新这款伟大的软件。
🛒 前往官网购买这个生成器的核心是逆向工程自 Charles 注册逻辑的 Go 语言代码,并将其翻译为 JavaScript。整个过程涉及一个自定义的分组密码算法,类似于 RC5/RC6,它使用加法、异或和数据依赖的循环移位(ARX结构)来加密数据。
首先,我们将输入的用户名(例如 "charles")转换成字节,并在其前面加上4个字节的长度信息。然后,为了满足加密算法按块处理的要求(每块8字节),我们会对数据进行填充,确保总长度是8的倍数。
// 伪代码
let nameBytes = toBytes("charles"); // -> [99, 104, 97, 114, 108, 101, 115]
let lengthBytes = toBytes(nameBytes.length); // -> [0, 0, 0, 7]
let buffer = lengthBytes + nameBytes; // -> [0, 0, 0, 7, 99, 104, 97, 114, 108, 101, 115]
let paddedBuffer = padToMultipleOf8(buffer); // -> [0,0,0,7,99,104,97,114,108,101,115,0,0,0,0,0] (16字节)
我们使用一个固定的密钥(`0x7a21c951691cd470`)来初始化我们的自定义加密算法。然后,将上一步准备好的数据,以8字节为一块,逐块进行加密。这个过程类似于用一个加密函数来计算哈希值。
将第一轮加密后的所有字节,通过一个 `(累加值 XOR 字节) <<< 3` 的循环操作,折叠成一个32位的整数。这个整数再与一个“魔法数” `0x54882f8a` 进行异或,得到一个32位的前缀(prefix)。
我们生成一个随机的31位整数作为后缀(suffix)。然后将上一步得到的32位前缀作为高32位,这个随机后缀作为低32位,组合成一个64位的整数 `in`。其中,后缀会根据其值的不同,有微小的调整(这可能对应不同版本的许可证)。
let prefix = folded_hash ^ 0x54882f8a;
let suffix = random_31_bit_integer;
let in = (BigInt(prefix) << 32n) | BigInt(suffix);
这一步非常有趣。我们使用另一个固定的密钥(`-5408575981733630035`)来初始化加密算法,但这次调用的是 解密 函数来处理上一步生成的64位整数 `in`。这利用了解密函数的单向性,作为最终的变换。
最后,我们对中间块 `in` 的所有字节进行异或,计算出一个8位的校验码。最终的密钥由 `2位十六进制校验码` + `16位十六进制的最终变换结果` 组合而成。
let checksum = calculate_checksum(in);
let finalKey = toHex(checksum) + toHex(final_result);
// 示例: "2f" + "0123456789abcdef" -> "2f0123456789abcdef"