免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

我让 AI 学会了“拆“App——Antigravity 逆向分析能力搭建手记:从 MCP 到 IDA Pro 的配置实录

我让 AI 学会了“拆“App——Antigravity 逆向分析能力搭建手记:从 MCP 到 IDA Pro 的配置实录 1. 为什么我要让 Antigravity 学会“拆”App先说清楚这套东西是什么、能做什么、适合谁。Antigravity 是 Google DeepMind 推出的 AI 编程助手你可以把它理解成一个住在你电脑里的资深程序员写代码、调 bug、查文档都很顺手。但它有个明显短板不会用逆向工具。你让它分析一个 APK它只能给你讲理论没法真的把包拆开、把函数反编译出来、把运行时行为 Hook 下来。我想要的是一句话丢过去——“帮我看看这个 APK 里的加密逻辑”——然后它自己调 IDA Pro 反编译、用 Frida 挂 Hook、通过 ADB 把结果拉回来。要做到这一点核心只有一件事用 MCPModel Context Protocol模型上下文协议把本地逆向工具的能力“喂”给 AI。MCP 说白了就是一套让 AI 调用外部工具的标准接口每个工具是一个电器MCP 是那个万能遥控器AI 拿着遥控器就能操作任何接入的工具。这套工作流适合谁适合做 Android 安全分析、协议逆向、CTF 的工程师也适合想把重复性逆向操作自动化的开发者。不适合完全没碰过命令行的纯小白因为你需要至少能看懂 Python 脚本和 JSON 配置。但只要你愿意跟着敲一遍整个链路是可以复现的。我试过把这套流程跑在一个 Cocos2d-x 游戏 App 上从静态分析到动态 Hook 再到批量解密全程 AI 自主决策我只负责看。下面把配置、脚本、验证命令和踩过的坑全部摊开讲。2. 前置准备TaoToken 接入与 MCP 环境搭建在讲逆向工具接入之前得先把 AI 侧的模型通道打通。Antigravity 本身需要一个大模型后端来驱动推理我用的是 TaoToken 提供的 API 通道它兼容 OpenAI 风格的接口配置起来比较直接。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。你需要先拿到一个 API Key。登录后进控制台在 API Keys 页面创建一个新 Key复制出来备用。这个 Key 后面会写进 Antigravity 的模型配置里。如果你还没决定用哪个模型可以先去模型对话页面试一下不同模型的响应质量再决定给逆向工作流配哪个。环境方面你需要准备这些东西Python 3.10 以上MCP Server 用 Python 写、Node.js 18 以上部分 MCP 客户端依赖、IDA Pro 7.5 以上带 idapython、Frida 16.x、ADB 平台工具、一台已经 root 或者可调试的 Android 设备或模拟器。把这些工具的路径都记下来后面配置里要填绝对路径。MCP 的架构分两层Server 端是你自己写的 Python 脚本负责把工具能力注册成 MCP 工具Client 端是 Antigravity它通过 stdio 或者 SSE 连接 Server读取工具列表并调用。所以你要做的是写 Server 脚本 → 在 Antigravity 的 MCP 配置里登记 Server → 重启 Antigravity → AI 就能看到新工具。这里有个关键点MCP Server 脚本本身不执行逆向逻辑它只是“翻译官”把 AI 的调用请求转成对 IDA Pro、Frida、ADB 的实际命令。真正的分析工作还是这些工具在做MCP 只是让 AI 能指挥它们。3. 可复制配置MCP Server 脚本与 Antigravity 登记这一节是全文最核心的部分所有配置都可以直接复制。先写 IDA Pro 的 MCP Server。新建一个文件ida_mcp_server.pyfrom mcp.server.fastmcp import FastMCP import subprocess import json import os mcp FastMCP(ida-pro, instructions二进制静态分析工具支持反编译、函数枚举、字符串提取) IDA_PATH rC:\Program Files\IDA Pro 7.7\idat64.exe IDA_SCRIPT rD:\mcp\ida_scripts\decompile.py mcp.tool() async def decompile_function(binary_path: str, function_name: str) - str: 反编译指定函数返回伪代码 cmd [IDA_PATH, -A, f-S{IDA_SCRIPT} {function_name}, binary_path] result subprocess.run(cmd, capture_outputTrue, textTrue, timeout300) return result.stdout mcp.tool() async def list_functions(binary_path: str) - str: 列出二进制文件中所有函数名 cmd [IDA_PATH, -A, f-S{IDA_SCRIPT} --list, binary_path] result subprocess.run(cmd, capture_outputTrue, textTrue, timeout300) return result.stdout mcp.tool() async def extract_strings(binary_path: str, min_length: int 6) - str: 提取二进制中的字符串用于搜索密钥、URL cmd [IDA_PATH, -A, f-S{IDA_SCRIPT} --strings {min_length}, binary_path] result subprocess.run(cmd, capture_outputTrue, textTrue, timeout300) return result.stdout if __name__ __main__: mcp.run()Frida 的 Server 脚本frida_mcp_server.pyfrom mcp.server.fastmcp import FastMCP import frida import json mcp FastMCP(frida, instructions运行时 Hook 工具支持注入脚本、拦截函数、枚举类方法) mcp.tool() async def inject_script(package_name: str, script_source: str) - str: 向目标 App 注入 Frida 脚本 device frida.get_usb_device() session device.attach(package_name) script session.create_script(script_source) script.load() return fscript injected into {package_name} mcp.tool() async def hook_function(package_name: str, class_name: str, method_name: str) - str: Hook 指定类的指定方法打印参数和返回值 script_source f Java.perform(function() {{ var target Java.use({class_name}); target.{method_name}.overload().implementation function() {{ console.log([*] {method_name} called); var ret this.{method_name}(); console.log([*] return: ret); return ret; }}; }}); device frida.get_usb_device() session device.attach(package_name) script session.create_script(script_source) script.load() return fhooked {class_name}.{method_name} mcp.tool() async def enumerate_classes(package_name: str) - str: 枚举目标 App 加载的所有类 script_source Java.perform(function() { Java.enumerateLoadedClasses({ onMatch: function(name) { console.log(name); }, onComplete: function() {} }); }); device frida.get_usb_device() session device.attach(package_name) script session.create_script(script_source) script.load() return class enumeration startedADB 的 Server 脚本adb_mcp_server.pyfrom mcp.server.fastmcp import FastMCP import subprocess mcp FastMCP(adb, instructionsAndroid 设备控制工具支持安装、卸载、文件传输、命令执行) ADB_PATH rC:\platform-tools\adb.exe mcp.tool() async def install_apk(apk_path: str) - str: 安装 APK 到设备 result subprocess.run([ADB_PATH, install, -r, apk_path], capture_outputTrue, textTrue) return result.stdout mcp.tool() async def pull_file(remote_path: str, local_path: str) - str: 从设备拉取文件 result subprocess.run([ADB_PATH, pull, remote_path, local_path], capture_outputTrue, textTrue) return result.stdout mcp.tool() async def shell_command(command: str) - str: 在设备上执行 shell 命令 result subprocess.run([ADB_PATH, shell, command], capture_outputTrue, textTrue) return result.stdout mcp.tool() async def list_packages() - str: 列出设备上所有已安装的包名 result subprocess.run([ADB_PATH, shell, pm, list, packages], capture_outputTrue, textTrue) return result.stdout三个 Server 写好后在 Antigravity 的 MCP 配置文件里登记。配置文件路径通常是%APPDATA%\Antigravity\mcp_settings.jsonWindows或~/.config/antigravity/mcp_settings.jsonmacOS/Linux。内容如下{ mcpServers: { ida-pro: { command: python, args: [D:\\mcp\\ida_mcp_server.py], env: {} }, frida: { command: python, args: [D:\\mcp\\frida_mcp_server.py], env: {} }, adb: { command: python, args: [D:\\mcp\\adb_mcp_server.py], env: {} } } }注意路径里的反斜杠要转义成双反斜杠。如果你用的是虚拟环境command要填虚拟环境里 python.exe 的绝对路径。保存后重启 Antigravity在工具面板里应该能看到这三个 Server 注册的工具列表。4. 验证请求静态动态分析闭环实测配置完成后先做一次最小验证确认 AI 真的能调用工具。在 Antigravity 对话框里输入“列出当前连接的 Android 设备上所有已安装的包名。”如果配置正确AI 会调用adbServer 的list_packages工具返回一长串包名。这一步成功说明 MCP 链路通了。接下来做完整的静态动态闭环。我拿一个 Cocos2d-x 游戏 App 做测试包名假设为com.example.game。第一步让 AI 解析 APK 结构adb shell pm path com.example.game adb pull /data/app/com.example.game-1/base.apk ./target.apkAI 会自动执行这两条命令把 APK 拉到本地。然后调用 IDA Pro 的extract_strings工具在 22MB 的引擎库里搜索xxtea关键字返回结果里出现xxtea_decrypt和jsb_set_xxtea_key确认使用了 XXTEA 加密。第二步静态分析找密钥。AI 调用decompile_function反编译启动函数在伪代码里看到密钥的一部分但因为编译器优化被截断了。这时候 AI 自己决定切换到动态分析——这一步不是我告诉它的。第三步动态 Hook。AI 调用 Frida 的hook_functionHookjsb_set_xxtea_key函数Java.perform(function() { var target Module.findExportByName(libcocos2djs.so, jsb_set_xxtea_key); if (target) { Interceptor.attach(target, { onEnter: function(args) { console.log([*] xxtea key: Memory.readUtf8String(args[0])); } }); } });App 运行时完整密钥被打印出来。两条路线交叉验证确认了加密密钥。第四步批量解密。AI 写了一个 Python 脚本用提取到的密钥一次性解密 27 个.jsc文件import xxtea import gzip import os KEY bextracted_key_here input_dir ./jsc_files output_dir ./decrypted for filename in os.listdir(input_dir): if filename.endswith(.jsc): with open(os.path.join(input_dir, filename), rb) as f: encrypted f.read() decrypted xxtea.decrypt(encrypted, KEY, paddingFalse) try: decompressed gzip.decompress(decrypted) except: decompressed decrypted with open(os.path.join(output_dir, filename.replace(.jsc, .js)), wb) as f: f.write(decompressed) print(fdecrypted: {filename})解密流程是加密文件 → XXTEA 解密 → Gzip 解压 → 可读的 JavaScript 源码。跑完后decrypted目录里就是还原出来的源码。第五步源码分析。AI 自动分析还原出的源码结构识别出模块系统、网络协议、调试接口甚至找到开发者遗留的内部调试系统。整个闭环从静态到动态再到批量处理AI 在工具之间自主切换我只在关键节点确认了一下。5. 常见报错排查401、local proxy failed、reading choices配置和运行过程中会遇到几类典型报错这里逐个对照排查。401 Unauthorized这个通常出现在模型 API 调用环节。检查 TaoToken 的 API Key 是否正确写入 Antigravity 的模型配置Key 有没有过期请求头里的Authorization: Bearer key格式对不对。如果用的是环境变量确认变量名和代码里读的一致。另外检查 Base URL 是不是https://taotoken.net/api末尾不要多加斜杠。local proxy failedMCP Server 启动失败时常见。先确认mcp_settings.json里的command路径正确Python 解释器能正常执行。然后在命令行手动跑一下python ida_mcp_server.py看有没有 import 错误。常见原因是mcp包没装执行pip install mcp即可。如果报ModuleNotFoundError: No module named frida装pip install frida frida-tools。reading choices 报错这个一般出现在模型返回格式解析环节通常是模型输出被截断或者返回了非预期结构。检查max_tokens设置是不是太小逆向分析返回的伪代码可能很长建议调到 8192 以上。如果用的是流式输出确认客户端正确处理了 SSE 分块。OAuth 相关报错如果你在 Antigravity 里配置了需要 OAuth 的模型通道报OAuth token expired或者invalid_grant重新走一遍授权流程即可。TaoToken 的 API Key 方式不涉及 OAuth直接用 Key 就行。IDA Pro 路径含空格报错C:\Program Files\...里的空格会导致命令行解析出错。解决方法是在 subprocess 调用时把路径作为列表元素传入而不是拼成字符串。上面脚本里subprocess.run([IDA_PATH, ...])的写法已经规避了这个问题。如果你手动拼命令记得给路径加引号。Frida 线程崩溃Frida 脚本在自己的线程运行但 Cocos2d-x 的 JS 引擎函数必须在 GL 渲染线程调用直接调用会崩溃。解决方案是 Hook 引擎的帧更新函数每秒调用 60 次把要执行的代码排队在下一帧由正确的线程安全执行。这就像不能在高速路上突然停车修轮胎但可以在下一个服务区停下来修。ADB 设备未授权adb devices显示unauthorized在手机上确认 USB 调试授权弹窗或者执行adb kill-server adb start-server重启 ADB 服务。6. 把能力边界往外推一步这套方案跑通之后最直接的变化是效率。传统逆向分析要在 IDA、Frida、ADB、文件管理器、编辑器之间来回切换手动复制粘贴数据。现在对 AI 说一句话它自己协调所有工具完成分析。四个 MCP Server 脚本是通用的换个 App 照样能用就像买了一套厨具做中餐能用做西餐也能用。更值得说的是 AI 在工具之间做出的决策。静态分析遇到瓶颈时自动切换动态分析一种 Hook 方式崩溃时自动尝试替代方案字符串搜索没结果时改用二进制模式搜索。这些决策不是我预设的是 AI 根据工具返回结果自己判断的。工具的能力边界就是 AI 的能力边界通过 MCP 把工具接进来等于把 AI 的能力边界往外推了一步。如果你想把模型对话能力也接进这套工作流可以直接用 TaoToken 的模型对话接口测试不同模型在逆向场景下的表现。长期做编码和 Agent 任务的话Coding Plan 更适合高频调用。接入文档里有完整的 API 说明和示例代码照着改就能把模型通道换成你自己的。最后留一个实用技巧MCP Server 脚本里的工具描述instructions和 docstring写得越具体AI 调用时越准确。比如extract_strings的 docstring 里写明“用于搜索密钥、URL”AI 在需要找密钥时就会优先想到这个工具。这比在提示词里反复强调“记得用字符串提取”有效得多。
返回列表