toolsmith
发布于 2026-08-27 / 31 阅读
0

抓包神器Charles的授权机制探秘:一次AI辅助逆向分析的人机协作实战记录

第一章:起点——从"看不懂"开始

为什么我打开了 charles.jar

这段时间我在研究 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 打开它

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

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

然后我输入了最自然的搜索关键词:"license"

搜索结果确实出来了。很多类里都有 license 相关的逻辑,我的目光停在了一个叫 XIzE 的类上。

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

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 能不能理解混淆代码?它会不会被那些无意义的变量名绕晕?它输出的结论靠谱吗?

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

于是,我复制了 XIzE 类的核心代码,打开 ChatGPT,粘贴了进去。

第二章:第一次求助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 没有直接逐行翻译,而是先给出了一份语义还原后的类结构

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 对话中的重复描述):

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 详细解释了这个逻辑:

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 的伪代码中,我反复看到这样的操作:

XOR → 数据相关的循环移位 (ROTATE) → 加法 (ADD)

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

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 的魔法常量直接裸露在代码里

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

static int a = -1209970333;   // 0xB7E15163
static int ar = -1640531527;  // 0x9E3779B9

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

变量十六进制含义
-12099703330xB7E15163Pw(基于自然常数 e)
-16405315270x9E3779B9Qw(基于黄金比例)

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

第二条:子密钥数量 = 26

RC5 的子密钥数量公式是:

S[0] 到 S[2r + 1],一共 2 × (r + 1) 个

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

2 × (r + 1) = 26  →  r = 12

12 轮 RC5,标准参数。

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

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

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];

拆解出来就是:

XOR → 数据相关循环移位(& 31)→ 加子密钥

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

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

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

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

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

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),发现了这样的代码:

c(8800536498351690864L);

以及:

c(-5408575981733630035L);

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

第一套密钥:用户名校验

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

对应的 int 对是:

高 32 位低 32 位
0x7A1F7A1F0x7A1F7A30

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

RC5_SETUP(1763497072, 2049034577);

转成十六进制:

int 值十六进制
17634970720x691D6E30
20490345770x7A1EAF31

组合起来:

RC5 Key #1 = 0x691D6E30 7A1EAF31

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

第二套密钥:License 核心解密

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

对应的 int 对是:

高 32 位低 32 位
0xB4E0B7AC0xEC0E9F1D

代码中另一处表现形式:

RC5_SETUP(-334581843, -1259282228);

转成十六进制:

int 值十六进制
-3345818430xEC0E9F1D
-12592822280xB4E0B7AC

组合起来:

RC5 Key #2 = 0xEC0E9F1D B4E0B7AC

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

两套密钥对比

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

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

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

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

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。

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

① 两套硬编码密钥

// Key #1:用户名校验
r.RC5_SETUP(1763497072, 2049034577);

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

② 18 位 License Key 构建

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

③ 黑名单跳过机制

do {
    licenseKey = generateLicenseKey(...);
} while (isBlacklisted(licenseKey));

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

完整 License 生成链路

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

① 输入:用户名 (如 "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 做的就是把这个流程反过来。

使用示例

# 为特定用户生成 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 辅助逆向工作流速查表

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

核心原则:每轮只问一个问题,让 AI 充分回答后,人类再做下一轮判断。

结尾

回到最开始的那个瞬间。

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

我把代码丢给了 AI。

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

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

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

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

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

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

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


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

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

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