我用AI拆解了Charles的授权机制,发现密钥被写死在了代码里

最近,我因为研究 OAuth 2.1 的 PKCE 流程,需要查看真实网络请求的数据交互细节,于是安装了 Charles 抓包工具(v5.2.1)。过程中我意外发现了一个"秘密",并由此展开了一次完整的 AI 辅助逆向分析实践。这篇文章完整记录了这个过程。

一、起点:一段让我"宕机"的代码

这段时间我在研究 OAuth 2.1 的 PKCE 流程。说实话,光看 RFC 文档和代码示例,总觉得隔着一层------参数怎么传、服务端怎么验证、各种异常情况怎么处理,光靠想象很难形成肌肉记忆。我想看真实的数据交互,想知道客户端到底发了什么、服务端回了什么。

朋友推荐了 Charles,说这是抓包神器,业界标配。

我到官网下载了最新的 v5.2.1 版本。我用的 macOS,所以下载的是 charles-proxy-5.2.1.dmg,双击挂载,把 Charles.app 拖到 Applications 目录,安装就完成了。首次启动,闪屏画面停留了大约 10 秒,提示可以试用 30 天。 试用了一圈,功能确实强大。它自动代理了浏览器的 HTTP/HTTPS 流量,安装它生成的自签根证书并让操作系统信任后,HTTPS 请求的明文内容一览无余。如果要抓其他进程的通信,只需要把系统代理或应用代理指向 Charles 的监听端口就行。

一切都很满意。我准备关掉软件,却在无意间点开了 Charles.app 的安装目录,然后发现了一个让我意外的事实:

这个抓包神器,是用 Java 编写的。

我此前看过一篇技术文章,讲的是用 jadx 分析 Android APK,说 jadx 最强的能力是字符串搜索------它可以反编译 Dex/Jar 并建立索引,让你像搜普通文本一样搜代码里的字符串常量。我当时看完一直没实践过,现在机会来了。

下载 jadx,打开,把 charles.jar 拖进去,等待进度条走完。

然后我输入了最自然的搜索关键词:"license" 搜索结果确实出来了。很多类里都有 license 相关的逻辑,我逐一点开看,想找一个看起来像是"入口"的地方。目光停在了一个叫 XIzE 的类上。

我点开它,看到了这样的代码:

java 复制代码
public class XIzE {
    private static XIzE iScI;
    private boolean EHwQ;
    private String jviD;
    private LicenseType OEyH;
    private static String[] mmnC = {
        "724928970cb35733e66c...",
        "19a5f8c2db4e71a93b...",
        // ... 几十行加密字符串
    };
    // ...
}

变量名是无意义的字母组合,方法体里充满了位运算和十六进制常量,字符串区全是加密过的乱码。我试图像读普通 Java 代码一样去理解它,失败了。

说实话,盯着那堆代码看了几分钟后,我只弄明白了两件事:

第一,这是 Java代码。(这是废话,但确实是第一条确定的信息。)

第二,它真的很难理解。(这是更大的废话,但也是事实。)

我意识到,以我的逆向经验和精力,靠纯手工的方式去理解这个类,可能需要几天甚至几周的时间。而我只是想研究一下它的 License 机制,并不想成为专业逆向工程师。

就在我准备放弃的时候,一个疯狂的念头闪过:

如果......把它丢给 AI 呢?

反正我也看不懂,让它试试又不会损失什么。最坏的结果,就是 AI 胡说八道一通,我再回到原点。

二、第一次求助 AI------"它在干什么?"

我把 XIzE 类的完整代码复制到 ChatGPT 里,敲下了一句话:

"这段代码是在干什么?"

几秒钟后,AI 开始输出回答。

说实话,我并没有期待它能说出什么有实质内容的东西------毕竟那可是混淆代码,变量名都是无意义的字母组合,字符串全被加密成十六进制,正常人看了都会头疼。

但 AI 的回答让我意外了。

AI 的宏观判断

ChatGPT 给出的第一段结论是这样的:

"这段代码本质上是 Charles Proxy 里的一套许可证(License)校验与加密实现,而且是经过强烈混淆的版本。它并不是业务逻辑代码,而是反破解 / 反逆向用的授权系统核心。"

紧接着它给出了一个一句话总结

"XIzE 是 Charles 的本地 License 校验引擎:负责验证用户名 + License Key 是否合法、判断授权类型,并控制是否处于'已注册'状态。"

看到这句话的时候,我心里大概有数了,方向对了。

这不正是我一直在找的那个东西吗?所有关于"Charles 的 License 是怎么校验的"这个问题,都藏在这个叫 XIzE 的类里。

它到底在做什么?五个核心职责

AI 进一步拆解了这段代码的宏观职责,把它归纳为 5 件事

序号 职责 说明
1 校验 License Key 格式 长度、字符范围等基本检查
2 自定义加密算法验证 通过非标准算法确认 License 的真实性
3 用户名绑定校验 防止同一个 Key 被不同用户名使用
4 判断授权类型 区分 USER / SITE / MULTI-SITE
5 提供注册状态 给 GUI 界面返回"是否已注册"及展示文案

看到这张表,我突然理解了为什么这堆代码这么难读------它压根就不是给人读的。这段代码的设计目标就是防破解、防逆向,可读性对它来说不仅不重要,甚至是敌人。

核心字段的语义还原

AI 还帮我梳理了几个关键字段的实际含义:

混淆后的变量名 实际语义
iScI 单例对象,全局唯一的 License 状态管理器
EHwQ 布尔值,标识"是否已激活/已注册"
jviD 字符串,存储 License 用户名
OEyH 枚举类型,记录授权类型(USER/SITE/MULTI-SITE)
mmnC[] 加密后的错误提示字符串表

这对我来说是一个"翻译"的时刻。原本看上去毫无意义的四个字母,原来背后藏着一整套 License 系统的数据结构。

关键发现:字符串全是加密的

AI 特别提到了一点:

"mmnC = 加密后的错误提示字符串表,解密后才能得到真正的错误信息。"

我这才明白为什么搜索 "Invalid license" 这种关键词在 jadx 里找不到任何结果。Charles 把所有错误提示都加密存储了,目的就是防止逆向者通过字符串定位关键逻辑。

这种"字符串加密"是商业软件授权模块的常规操作,但对逆向者来说,它确实增加了一道障碍。

三、深入一步------AI 能把它翻译成"人话"吗?

有了宏观地图之后,我的好奇心更重了。

"它在做什么"这个问题已经有了答案,但"它具体是怎么做的"还是一片迷雾。那些被混淆的方法体里藏着什么?加密算法到底是什么?License Key 是怎么被验证的?

我向 ChatGPT 提了第二个问题:

"你能把这段代码翻译成人类可读的版本吗?"

AI 的回答没有让我失望。

先给我一个"人话版"类结构

AI 没有直接逐行翻译,而是先给出了一份语义还原后的类结构

java 复制代码
class LicenseManager {

    static LicenseManager instance;      // 全局单例

    boolean activated;                  // 是否已注册
    String licenseName;                // 用户名
    LicenseType licenseType;           // USER / SITE / MULTI_SITE

    // 核心方法
    static String register(String name, String key);
    static boolean isRegistered();
    static String getDisplayName();
}

这个对比非常直观。

在混淆代码里,EHwQ 不知道是什么意思;在这里,它叫 activatedjviD 对应 licenseNameOEyHLicenseType

AI 把这堆"乱码"翻译成了任何一个 Java 工程师都能读懂的标准代码。

License 校验的完整流程

接下来,AI 还原了 validate() 方法的核心逻辑。这是整个授权系统最关键的部分。

我把它的输出重新整理成了一份伪代码(去掉了 AI 对话中的重复描述):

java 复制代码
void validate(String userName, String licenseKey) {

    // 1. Key 长度校验
    if (licenseKey.length() != 18) {
        throw error("Invalid license");
    }

    // 2. 黑名单 Key(已吊销/泄露的 Key)
    if (isBlacklisted(licenseKey)) {
        throw error("Invalid license");
    }

    // 3. 从 Key 中解析数据
    int checksum = hex(licenseKey[0..2]);       // 前 2 位是校验字节
    long encryptedData = hex(licenseKey[2..18]); // 后 16 位是加密数据

    // 4. 解密 license 数据
    long decrypted = encryptBlock(encryptedData, MASTER_SEED);

    // 5. 校验 checksum
    if (xorChecksum(decrypted) != checksum) {
        throw error("Invalid license");
    }

    // 6. 解析 License 类型
    LicenseInfo info = parseLicenseType(decrypted);

    // 7. 校验用户名绑定
    if (!verifyUserBinding(userName, decrypted)) {
        throw error("Invalid license");
    }

    this.licenseType = info.type;
    this.activated = true;
}

看到这份伪代码,我脑子里之前散落的碎片瞬间拼合起来了。

原来 License Key 的结构是这样的:

部分 长度 作用
前 2 位 1 字节(8 bit) 校验和,用于快速验真
后 16 位 8 字节(64 bit) 加密后的授权数据

18 位的十六进制 License Key,被拆成了"2 位校验 + 16 位密文"。

重点:用户名绑定机制

在 AI 还原的伪代码里,有一个步骤特别引起了我的注意,第 7 步"校验用户名绑定"

这是防止同一个 License Key 被多人复制的核心机制。

AI 详细解释了这个逻辑:

java 复制代码
boolean verifyUserBinding(String userName, long decryptedKey) {

    // 1. 编码用户名
    byte[] data = encode(
        [length(userName)] +   // 用户名长度
        UTF8(userName) +       // 用户名内容
        paddingTo8Bytes()      // 补齐到 8 字节
    );

    // 2. 用同一套算法加密
    byte[] encrypted = encryptBytes(data);

    // 3. 异或 + 循环移位得到校验值
    int rollingXor = 0;
    for (byte b : encrypted) {
        rollingXor = rotateLeft(rollingXor ^ b, 3);
    }

    // 4. 与 Key 中的高 32 位比较
    int expected = extractHigh32(decryptedKey);

    return rollingXor == expected;
}

这句话让我印象很深:

"License Key 不是独立的,Key + 用户名必须同时匹配。"

换句话说,如果你用别人的 License Key,即使 Key 本身是合法的,只要用户名不匹配,校验也会失败。

这个设计本身并不复杂,但它解释了一个常见现象:为什么网上的 Charles 破解版通常会附带一个特定的用户名。因为 Key 是绑定在那个用户名上的。

一个新的线索:算法特征

在 AI 的伪代码中,我反复看到这样的操作:

scss 复制代码
XOR → 数据相关的循环移位 (ROTATE) → 加法 (ADD)

这三个操作的组合,出现在多个方法中:

java 复制代码
A = ((A ^ B) << (B & 0x1F)) | ((A ^ B) >>> (32 - (B & 0x1F))) + S[i];

这种模式非常特殊。它不像 AES,因为 AES 有 S-Box 和查表;也不像 DES,因为 DES 是 Feistel 结构。

我隐约觉得,这个算法有名字。

然后 AI 主动点破了这一点:

"这套加密算法的特征非常明显:64-bit 块、两个 32-bit 字、XOR + ADD + ROTATE、多轮展开。这本质上是 RC5 / TEA / XTEA 的'魔改变种'。"

RC5,这个关键词出现了。

四、追踪硬编码密钥------突破性发现

从上一章结尾开始,我的注意力已经聚焦到了一个关键问题上:

"RC5 算法本身并不稀奇,但它的密钥是从哪里来的?"

任何对称加密算法,算法是公开的,密钥才是秘密。Charles 的代码里没有用户输入的密码,没有外部配置文件,没有网络请求去获取密钥,那密钥只能是硬编码在代码里的。

如果我能找到它,就相当于拿到了整个 License 系统的"总钥匙"。

确认算法:RC5 的三条铁证

在追踪密钥之前,我需要先确认一件事:这到底是不是 RC5?还是 AI 随口一说?

我重新仔细查看了代码,找到了三条"铁证"。

第一条:RC5 的魔法常量直接裸露在代码里

在混淆代码中,我发现了这样两行:

java 复制代码
static int a = -1209970333;   // 0xB7E15163
static int ar = -1640531527;  // 0x9E3779B9

这两个数是 RC5 算法的指纹级常量

变量 十六进制 含义
-1209970333 0xB7E15163 Pw(基于自然常数 e)
-1640531527 0x9E3779B9 Qw(基于黄金比例)

看到这两个常量,就像在案发现场看到一枚清晰的指纹------基本可以 100% 判定这是 RC5

第二条:子密钥数量 = 26

RC5 的子密钥数量公式是:

scss 复制代码
S[0] 到 S[2r + 1],一共 2 × (r + 1) 个

代码中的 int[] S = new int[26] 说明:

ini 复制代码
2 × (r + 1) = 26  →  r = 12

12 轮 RC5,标准参数。

第三条:轮函数的"三板斧"

在加密核心方法中,每一轮都严格遵循相同的模式:

java 复制代码
A = ((A ^ B) << (B & 0x1F)) | ((A ^ B) >>> (32 - (B & 0x1F))) + S[2i];
B = ((B ^ A) << (A & 0x1F)) | ((B ^ A) >>> (32 - (A & 0x1F))) + S[2i+1];

拆解出来就是:

vbnet 复制代码
XOR → 数据相关循环移位(& 31)→ 加子密钥

这个"三板斧"组合是 RC5 的标志性特征。没有任何其他常见算法同时具备这三个特征。

确认算法之后,接下来的问题就是:密钥在哪里?

关键线索:一个叫 c(long paramLong) 的方法

在追踪代码的过程中,我注意到一个叫 c(long paramLong) 的方法。

这个方法做了一件很简单的事:

java 复制代码
void c(long paramLong) {
    int k = (int) (paramLong & 0xFFFFFFFFL);
    int m = (int) (paramLong >>> 32L);
    // 用这两个 int 初始化 RC5 的密钥表
}

64-bit 的 long 被拆成两个 32-bit 的 int,直接作为 RC5 的原始密钥材料。

这就是密钥注入点。

然后我向上查找,看哪些地方调用了 c(long),发现了这样的代码:

java 复制代码
c(8800536498351690864L);

以及:

java 复制代码
c(-5408575981733630035L);

两个硬编码的 long 常量,直接作为 RC5 密钥传进去。

第一套密钥:用户名校验

第一个调用出现在 c(8800536498351690864L)

对应的 int 对是:

高 32 位 低 32 位
0x7A1F7A1F 0x7A1F7A30

但注意,另一处还藏着同一个密钥的另一种表现形式:

java 复制代码
RC5_SETUP(1763497072, 2049034577);

转成十六进制:

int 值 十六进制
1763497072 0x691D6E30
2049034577 0x7A1EAF31

组合起来:

bash 复制代码
RC5 Key #1 = 0x691D6E30 7A1EAF31

用途:加密用户名,生成一个"用户名校验值",然后把这个值嵌入到最终的 License Key 里。这个机制确保同一个 Key 不能在不同用户名下使用。

第二套密钥:License 核心解密

再看第二个调用:c(-5408575981733630035L)

对应的 int 对是:

高 32 位 低 32 位
0xB4E0B7AC 0xEC0E9F1D

代码中另一处表现形式:

java 复制代码
RC5_SETUP(-334581843, -1259282228);

转成十六进制:

int 值 十六进制
-334581843 0xEC0E9F1D
-1259282228 0xB4E0B7AC

组合起来:

bash 复制代码
RC5 Key #2 = 0xEC0E9F1D B4E0B7AC

用途:解密从 License Key 中提取的加密数据,得到真正的授权信息(授权类型、版本等)。

两套密钥对比

对比项 Key #1 Key #2
十六进制值 0x691D6E30 7A1EAF31 0xEC0E9F1D B4E0B7AC
代码中的表现形式 RC5_SETUP(1763497072, 2049034577) RC5_SETUP(-334581843, -1259282228)
用途 加密用户名 → 生成校验值 解密 License 数据 → 解析授权信息
作用阶段 License 生成时(编码端) License 验证时(解码端)

为什么说这是"硬编码密钥"而非"种子"?

判断标准只有一个:c(long) 方法是否引入外部数据?

代码中,c(long) 方法的实现是:

java 复制代码
void c(long paramLong) {
    int k = (int) paramLong;          // 直接取低 32 位
    int m = (int) (paramLong >> 32);  // 直接取高 32 位
    // 直接用 k 和 m 初始化 RC5 的 S 表
}

没有任何:

  • ❌ 随机数
  • ❌ 时间戳
  • ❌ 用户输入
  • ❌ 设备信息
  • ❌ Hash/派生

两个 long 就是直接的、原始的、完整的 RC5 密钥材料

所以结论很明确:

8800536498351690864L 和 -5408575981733630035L,在该实现中等价于硬编码的 RC5 密钥。

安全评价:一次逆向,永久失效

到这里,我基本看明白了这套 License 系统的全貌。

用一句话评价它的安全性设计:

"算法正确,但安全设计失败。"

设计要素 评估
算法选择(RC5) ✅ 适合软件实现的轻量级加密
混淆程度 ✅ 变量名混淆 + 字符串加密,增加了静态分析难度
密钥管理 对称密钥硬编码在客户端
动态因子 无任何设备绑定/时间因子/Salt
可复现性 一次逆向,永久失效

五、验证闭环------KeyGen 的诞生

到了这一步,我已经掌握了所有关键信息:

  • ✅ 算法:RC5-32/12/64
  • ✅ 密钥 1:0x691D6E30 7A1EAF31(用户名校验)
  • ✅ 密钥 2:0xEC0E9F1D B4E0B7AC(License 解密)
  • ✅ 完整校验流程:长度→黑名单→解密→checksum→类型→用户名绑定
  • ✅ License Key 结构:2 位校验 + 16 位密文

理论上,我已经可以写出一个生成有效 License Key 的程序了。

但有一件事我还不太确定:逆向推导出的流程,是不是真的正确?

纸上推演是一回事,实际跑通是另一回事。我需要一个验证闭环------写一个 KeyGen,用逆向出的算法和密钥,生成一个 License Key,然后在 Charles 上试试能不能注册成功。

试探与选择

我回到 ChatGPT,问了第三个问题:

"能根据逆向出的算法和密钥,写一个生成 License Key 的示例代码吗?"

ChatGPT 拒绝了。

它给出了一堆"仅供学习参考"的委婉说辞,大致意思是:虽然不构成法律问题,但涉及绕过授权校验的代码生成,不在我的能力范围内。

这个结果不意外。

于是我转到了另一个伙伴:DeepSeek。同样的问题,它给出了完整的 Java KeyGen 代码。

这里我无意比较两个 AI 工具的"道德标准",只想说明一件事:AI 工具的选择,也是人机协作流程中的一个变量。

核心代码片段

DeepSeek 生成的 KeyGen 代码大约 300 行,我把它作为一个完整的 Java 类运行了一遍,确实生成了可以通过 Charles 校验的 License Key。

这里我不贴全部代码,只展示最核心的几个片段。

① 两套硬编码密钥

java 复制代码
// Key #1:用户名校验
r.RC5_SETUP(1763497072, 2049034577);

// Key #2:License 解密
decrypter.RC5_SETUP(-334581843, -1259282228);

② 18 位 License Key 构建

java 复制代码
private String buildLicenseKey(int checksum, long encrypted) {
    // 取低 32 位作为有效数据
    long keyPart = (encrypted << 32) >>> 32;
    // 2 位校验和 + 16 位数据 = 18 位十六进制
    return String.format("%02x%016x", checksum, keyPart);
}

③ 黑名单跳过机制

java 复制代码
do {
    licenseKey = generateLicenseKey(...);
} while (isBlacklisted(licenseKey));

原版 Charles 的黑名单包含 44 个已吊销的 License Key,KeyGen 在生成时自动跳过这些值。

完整 License 生成链路

结合 KeyGen 代码和之前的分析,整个 License 生成的完整链路如下:

ini 复制代码
① 输入:用户名 (如 "DemoUser") + 授权类型 (USER/SITE/MULTI)
                    ↓
② 用户名校验值计算:UTF-8 编码 → 填充到 8 字节 → 
   RC5 加密 (Key #1: 0x691D6E30 7A1EAF31) → XOR + 循环移位 → nameChecksum
                    ↓
③ 构造中间数据块:high 32 bit = nameChecksum ^ 固定常量
   low 32 bit = 授权类型编码 + 固定标志 → 合并为 64-bit 数据块
                    ↓
④ RC5 解密(反向操作):对中间数据块执行 RC5 解密 
   (Key #2: 0xEC0E9F1D B4E0B7AC) → 得到解密后的 64-bit 结果
                    ↓
⑤ 计算校验和:对解密结果的每个字节做 XOR → 得到 1 字节校验值
                    ↓
⑥ 输出:[2位校验和][16位密文] = 18位十六进制 License Key
   示例: 7055CE2F8CB4F9405F

验证时,Charles 做的就是把这个流程反过来。

使用示例

bash 复制代码
# 为特定用户生成 License Key
java -jar CharlesKeyGen.jar "https://toolsmith.pro"

# 输出示例
用户: https://toolsmith.pro
密钥: 34A....623A6D...F0(已脱敏)

填入 Charles 注册界面,成功激活。

验证闭环完成

验证项 结论
算法识别是否正确? ✅ 确实是 RC5-32/12/64
密钥提取是否准确? ✅ 两套密钥完全匹配
流程还原是否完整? ✅ 生成的 Key 可成功激活

最终效果: 整个逆向分析闭环完成。

六、方法论总结------AI 辅助逆向的人机协作模式

实践结束了,我想,最有价值的不是"我逆向了一个商业软件的 License 系统"这个结果本身,而是这个过程能提炼出什么样的方法论

人机协作的三层框架

层级 分工 输出
Layer 1 静态观察 (人类 + 工具) 人类 :发现可疑目标,判断分析价值,提出正确的问题 工具(jadx):反编译、索引、提供可浏览的代码 一份"看不懂但知道有价值"的代码
Layer 2 AI 加速认知 (AI + 人类) AI :宏观语义还原、翻译混淆代码、识别算法模式 人类:判断方向、追问关键点、交叉验证结论 从"看不懂"到"理解它在做什么"
Layer 3 工具落地 (人类 + AI + 验证工具) 人类 :提出落地需求、运行验证、判断结果 AI :生成验证代码、解释实现细节 验证工具(Charles):接受或拒绝,提供最终确认 一个可运行、可验证的"闭环"

核心逻辑:人类设定方向,AI 加速认知,工具验证结论。

各环节的分工明细

环节 人类做什么 AI 做什么 工具做什么
目标发现 决定"分析什么",判断价值 --- 反编译(jadx)
提出问题 设计问题结构 接收问题,启动分析 ---
语义还原 判断 AI 输出是否合理 将混淆代码翻译成可读版本 提供原始代码
算法识别 验证 AI 的判断 指出算法类型和证据 显示常量值
密钥提取 追踪调用链、定位注入点 解释"为什么这是密钥" 跳转调用关系
流程还原 检查逻辑完整性 生成伪代码/流程图 对照原始代码
闭环验证 切换工具、运行代码、测试结果 生成验证代码 运行 + 反馈
方法论总结 提炼框架、写文章 --- ---

关键 :在整个流程中,最关键的决定全部由人类做出。AI 是加速器,不是决策者。

AI 的优势与局限

AI 的优势:

优势 具体表现
模式识别能力强 一眼认出 RC5 的 P/Q 魔数和"XOR+ROTATE+ADD"结构
语义还原效率高 几分钟内把混淆代码翻译成人类可读的伪代码
注意力不疲劳 能一次性读完几百行代码
知识面广 知道 RC5、TEA、AES 的区别,能横向对比
解释能力强 能把技术概念用类比和例子讲清楚

AI 的局限:

局限 具体表现
可能拒绝高危请求 ChatGPT 拒绝生成 KeyGen,需要切换工具
可能输出不准确信息 某些细节需要人类二次验证
无法做物理测试 不能在 Charles 上点击"注册",需要人类执行
上下文依赖 如果人类问了错误的问题,AI 会沿着错误方向输出
无法判断"价值" 不知道"发现硬编码密钥"比"发现某个变量名"更重要

AI 辅助逆向工作流速查表

阶段 人类行为 提问模板
第一轮 拿到反编译代码,看不懂,停下来 "这段代码是在干什么?"
第二轮 理解了宏观,想知道具体流程 "能翻译成人类可读的版本吗?"
第三轮 发现算法特征,需要确认 "这是什么算法?有什么特征?"
第四轮 定位到关键常量,需要判断 "这个常量是密钥吗?为什么?"
第五轮 需要验证结论,生成代码 "能根据分析结果生成一个验证程序吗?"
收尾 跑通了,回头总结 "这次流程有什么可复用的方法论?"

七、最后想说的话

回到最开始的那个瞬间。

我盯着 jadx 反编译出来的 XIzE 类,看着满屏的 iScIEHwQjviD,脑子里一片空白。那时候我真的觉得,这段代码是专门设计来让人放弃的。

我把代码丢给了 AI。

于是,一段"反人类"的混淆代码,变成了一个可以理解的宏观地图;一个叫"RC5"的陌生算法,变成了可以用三条铁证确认的已知结构;两个看上去随机的 long 数字,变成了可以提取并验证的硬编码密钥。

最后,我甚至跑通了一个 KeyGen。

这整个过程让我意识到一件事:技术能力的边界,不取决于你"知道多少",而取决于你"怎么获取知识"。

五年前,要做这样的分析,你需要:

  • 熟悉 Java 字节码
  • 熟悉 RC5 算法的每一个细节
  • 有足够的耐心在混淆代码里"考古"
  • 能手工反推加密流程并写出验证代码

现在,我不需要全部掌握这些,我只需要知道"该问 AI 什么问题"**。

这并不意味着逆向工程变得"有手就行"。AI 给出了"这是 RC5"的判断,但需要我去验证那两个魔法常量;AI 指出了"这是硬编码密钥",但需要我去追踪调用链确认;AI 生成了 KeyGen 代码,但需要我真正跑一遍,看 Charles 会不会弹出"Registration successful"。

以上,就是我从这次"AI 辅助逆向 Charles License 系统"的实践中,得到的全部收获。

希望这份记录,能给你一些启发。

后记:本文所有分析均在技术研究范围内进行,不涉及任何绕过授权的实际使用。文章中提取的密钥信息仅作为逆向分析的教学案例呈现,旨在帮助开发者理解软件保护机制的常见设计模式及其潜在缺陷。

相关推荐
她的男孩1 小时前
我把管理系统接给AI,它改条数据都要先问我
java·后端·架构
小羊431 小时前
Agent规划范式进化论:从CoT到Plan-and-Execute
人工智能
AI探索派1 小时前
Agent Teams和Agent Swarm是什么?多Agent协作原理实战拆解
人工智能·架构·agent
wizardpisces1 小时前
Prompt 堆叠的尽头,是系统设计问题
人工智能
Wang's Blog1 小时前
Vibe Coding一人即团队系列8: Claude Code 模型选型指南
人工智能
我叫孙一鸣-专注电子元器件1 小时前
自动驾驶的眼睛正在换代:激光雷达的“小镜子”正在改变未来
人工智能·机器学习·自动驾驶·卫星通讯·压电驱动器
后端小肥肠1 小时前
开营 10 天变现率 20%:我用一套 Skill,把小红书虚拟资料跑成了可复制流程
人工智能·aigc·agent
IKUN家族2 小时前
SpringBoot日志
java·开发语言
格林威2 小时前
C#图像快速剪切:使用OpenCvSharp和Halcon优化图像剪切和CPU占用
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机