TrollAgent逆向之路

查看 51|回复 10
作者:HackXK   
TrollAgent AI聊天功能付费检查绕过教程 - Hopper版本
⚠️ 免责声明
本教程仅供学习和技术交流使用,请勿用于任何违法用途。
  • 本教程基于Hopper Disassembler进行逆向工程分析和修改
  • 所有分析和修改操作均在Hopper环境中完成
  • 请确保您的使用符合当地法律法规和软件许可协议
  • 修改应用程序可能违反软件使用条款,请自行承担相关风险
  • 作者不对因使用本教程而产生的任何后果承担责任

    工具说明
    本教程完全基于 Hopper Disassembler 进行分析和修改:
  • 使用Hopper进行二进制文件分析
  • 使用Hopper的汇编视图查看指令
  • 使用Hopper的修改功能直接编辑二进制文件
  • 所有截图和操作步骤均来自Hopper界面

    特此说明
    本文档是我用Ai生成的文档,DeepSeek是免费的,不要问,不喜勿喷。
    喜欢就请点个赞,基本有时间就会更新一点教程分享,当然了,如果你也是爱好者,可以一起交流讨论学习。谢谢。
    感谢列表
    因为这个iPA需要高系统,我系统是14.8.1的测试机,没法测试,所以感谢小果子帮忙测试。
    应用信息
  • 应用名称: TrollAgent
  • 目标功能: AI聊天功能付费检查绕过
  • 架构: ARM64 (iOS)
  • 基地址: 0x100000000
  • 分析工具: Hopper Disassembler

    付费检查机制分析
    1. 付费检查流程概述
    TrollAgent的AI聊天功能包含以下付费检查流程:
    [ol]
  • 用户发送消息 → 触发sendMessage方法
  • 调用付费检查函数 → sub_100078EC8()从钥匙串读取付费状态
  • 条件判断 → 根据返回值进行多重条件跳转判断
  • 结果处理 → 未付费则跳转到付费弹窗,已付费则继续AI聊天
    [/ol]
    2. 关键函数分析
    付费状态检查函数 (sub_100078EC8)
    地址: 0x100078EC8
    功能: 从iOS钥匙串(Keychain)读取付费状态
    CFTypeRef sub_100078EC8()
    {
        // 构建钥匙串查询参数
        // kSecClass = kSecClassGenericPassword
        // kSecAttrService = "特定服务名"
        // kSecAttrAccount = "charlieleung"
        // kSecReturnData = kCFBooleanTrue
        // kSecMatchLimit = kSecMatchLimitOne
        // 调用SecItemCopyMatching查询钥匙串
        OSStatus status = SecItemCopyMatching(query, &result);
        if (status == errSecSuccess && result != NULL) {
            // 解析返回的数据,检查付费状态
            // 返回布尔值表示是否已付费
            return boolValue;
        }
        return 0; // 未找到记录或查询失败,返回未付费状态
    }
    工作原理:
  • 查询钥匙串中账户名为"charlieleung"的特定服务记录
  • 如果找到记录且值为true,返回已付费状态
  • 否则返回未付费状态

    主要聊天逻辑函数 (sub_10004C27C)
    地址: 0x10004C27C
    功能: 处理AI聊天的主要逻辑,包含付费检查
    这个函数包含了完整的AI聊天处理流程:
    [ol]
  • 文本输入处理
  • 付费状态检查
  • API调用准备
  • 网络请求发送
  • 响应处理
    [/ol]
    关键修改点分析
    在Hopper中分析发现,付费检查逻辑包含三个关键的条件跳转指令,这些指令决定了是否显示付费弹窗:
    修改点1: 地址 0x10004ccf8
    原始指令: cbz w0, 0x10004c96c
    指令含义: Compare and Branch if Zero - 如果w0寄存器的值为0,则跳转到付费弹窗地址
    十六进制: a0 e3 ff 34
    修改后指令: nop
    指令含义: No Operation - 空操作,不执行任何动作
    十六进制: 1f 20 03 d5
    修改原因:
  • 原指令检查付费状态返回值是否为0(未付费)
  • 如果未付费,跳转到0x10004c96c显示付费弹窗
  • 修改为nop后,无论付费状态如何都不会跳转,继续执行后续代码

    修改点2: 地址 0x10004cd00
    原始指令: tbz w8, 0, 0x10004c96c
    指令含义: Test Bit and Branch if Zero - 测试w8寄存器的第0位,如果为0则跳转
    十六进制: 68 e3 07 36
    修改后指令: nop
    指令含义: No Operation - 空操作
    十六进制: 1f 20 03 d5
    修改原因:
  • 这是第二重付费检查,测试另一个状态位
  • 原指令在检测到未付费状态时跳转到付费弹窗
  • 修改为nop后跳过此检查

    修改点3: 地址 0x10004cd14
    原始指令: tbnz w0, 0, 0x10004c96c
    指令含义: Test Bit and Branch if Not Zero - 测试w0寄存器的第0位,如果不为0则跳转
    十六进制: 1f 40 03 d5 (注意:这个可能已经被修改过)
    修改后指令: nop
    指令含义: No Operation - 空操作
    十六进制: 1f 20 03 d5
    修改原因:
  • 这是第三重付费检查,确保付费状态的准确性
  • 原指令在特定条件下跳转到付费弹窗
  • 修改为nop后完全跳过此检查

    付费弹窗地址 (0x10004c96c)
    功能: 显示付费限制弹窗
    弹窗内容:
  • 标题: "付费功能"
  • 消息: "此为付费功能,请前往设置改用本地模型体验"
  • 按钮: "确定"

    代码逻辑:
    // 创建UIAlertController
    UIAlertController *alert = [UIAlertController
        alertControllerWithTitle:@"付费功能"
        message:@"此为付费功能,请前往设置改用本地模型体验"
        preferredStyle:UIAlertControllerStyleAlert];
    // 添加确定按钮
    UIAlertAction *okAction = [UIAlertAction
        actionWithTitle:@"确定"
        style:UIAlertActionStyleDefault
        handler:nil];
    [alert addAction:okAction];
    // 显示弹窗
    [rootViewController presentViewController:alert animated:YES completion:nil];
    Hopper修改步骤
    步骤1: 在Hopper中打开TrollAgent
    [ol]
  • 启动Hopper Disassembler
  • 选择 File → Read Executable to Disassemble
  • 选择TrollAgent二进制文件
  • 等待Hopper完成分析
    [/ol]
    步骤2: 定位修改地址
    [ol]
  • 使用Hopper的地址跳转功能 (Cmd+G)
  • 依次跳转到以下地址:
  • 0x10004ccf8
  • 0x10004cd00  
  • 0x10004cd14

    [/ol]
    步骤3: 查看原始指令
    在Hopper的汇编视图中,你应该能看到类似以下的指令:
    0x10004ccf8    cbz    w0, 0x10004c96c
    0x10004cd00    tbz    w8, #0, 0x10004c96c
    0x10004cd14    tbnz   w0, #0, 0x10004c96c
    步骤4: 修改指令
    [ol]
  • 双击要修改的指令
  • 在弹出的编辑框中输入 nop
  • 按回车确认修改
  • 重复此步骤修改所有三个地址
    [/ol]
    步骤5: 验证修改
    修改完成后,三个地址的指令应该都显示为:
    0x10004ccf8    nop
    0x10004cd00    nop
    0x10004cd14    nop
    步骤6: 保存修改
    [ol]
  • 选择 File → Produce New Executable
  • 选择保存位置
  • 保存修改后的文件
    [/ol]
    修改原理详解
    ARM64指令集说明
    CBZ指令 (Compare and Branch if Zero):
  • 格式: cbz ,
  • 功能: 比较寄存器值,如果为0则跳转
  • 用途: 检查函数返回值是否为0(失败/未付费)

    TBZ指令 (Test Bit and Branch if Zero):
  • 格式: tbz , #,
  • 功能: 测试指定位,如果为0则跳转
  • 用途: 检查状态位是否未设置

    TBNZ指令 (Test Bit and Branch if Not Zero):
  • 格式: tbnz , #,
  • 功能: 测试指定位,如果不为0则跳转
  • 用途: 检查状态位是否已设置

    NOP指令 (No Operation):
  • 格式: nop
  • 功能: 不执行任何操作,占用一个指令周期
  • 编码: 0x1f2003d5

    修改效果分析
    修改前的执行流程:
    用户发送消息 → 调用付费检查函数 → 检查返回值
                                        ↓
    如果未付费 → 跳转到付费弹窗 → 显示"付费功能"提示 → 阻止继续
    如果已付费 → 继续执行 → 正常AI聊天功能
    修改后的执行流程:
    用户发送消息 → 调用付费检查函数 → 检查返回值
                                        ↓
    无论付费状态如何 → 跳过所有检查 → 直接继续执行 → 正常AI聊天功能
    技术细节
    指令编码对比
    [table]
    [tr]
    [td]地址[/td]
    [td]原始指令[/td]
    [td]原始编码[/td]
    [td]修改后指令[/td]
    [td]修改后编码[/td]
    [/tr]
    [tr]
    [td]0x10004ccf8

    指令, 功能

  • LaureatePoet   

    有个疑问:iOS ipa解包之后,通过逆向工具例如hopper逆向修改之后,需要重新进行codesign,再打包成ipa
    请问对于 不存在“./entitlements.plist”文件的ipa安装包,修改之后如何打包呢?
    HackXK
    OP
      


    LaureatePoet 发表于 2025-9-11 16:51
    但是如果缺失“./entitlements.plist”文件的话,解包之后是无法重新打包成ipa的

    ipa根本就是一个zip,你直接后缀改成zip,然后解压,修改可执行文件直接替换回去,然后压缩成zip再改成ipa即可
    iscasfinsmart   

    沙发,感谢大神分享
    why977   

    感谢大神分享
    xixicoco   

    分析的很好,就是不知道这个ai聊天什么意思?
    zhangzhibo139   

    感谢大佬分享
    longge188   

    感谢大佬分享
    krrred0223   

    受益匪浅,感谢分享
    jimmyright   

    感谢分享,学习了!
    您需要登录后才可以回帖 登录 | 立即注册