资讯详情

资讯详情

AI Agent驱动的APK逆向自动化工作流设计与实践

我最早把“逆向工程”和“Agent”这两个词放在一起想的时候身边不少搞安全的同事都觉得不太靠谱。他们的理由也说得通逆向这种事靠的是经验、直觉和对编译产物的熟悉程度每一步都可能岔出去AI 怎么保证链路是通的但问题恰恰就在这里。单个人类去做 APK 逆向大部分时间其实不是花在“看懂代码”上而是花在“整理流程”上得先解包再找入口再看 Manifest再翻字符串资源再定位关键类……这些步骤的重复性极高恰恰是 Agent 最擅长接管的。我做的这个 apk-reverse 项目就是把这套从 APK 解包到关键逻辑定位的完整流程拆成一个个结构化任务交给 Android 逆向工程领域的 AI Agent 去执行让 agent 能按固定工作流产出可追溯、可复用的分析报告。先说清楚这个项目不是做一个“一键破解工具”而是一套通用的静态分析工作流适合做 Android 开发、客户端安全研究、SDK 合规分析、甚至竞品技术调研的人。你手上如果经常会收到来历不明的 APK 想快速弄清楚它干了什么或者要做隐私合规检查这套工作流能帮你省掉大量重复劳动。下面我把整套设计思路、工具组合、踩坑记录以及怎么让 Agent 真正能“扛得住”并发任务的细节一次性写透。1. 为什么要把逆向工程交给 AI Agent传统逆向流程的问题不是“没有工具”而是“工具之间的衔接全靠人来扛”。apktool 解包完了jadx 反编译完了字符串提取出来了Manifest 也看了——然后呢你得在心里把这些碎片拼成一张完整的逻辑图哪个类是入口哪个方法做了关键操作哪些资源泄漏了信息整体上是一个什么样的架构。这个“然后呢”在过去只能靠人肉经验。1.1 传统逆向流程的痛点不是看不懂是记不住我见过很多新人做逆向拿到 APK 的第一反应就是打开 jadx 开始翻代码。翻了两小时看明白了几个类但一问整体架构答不出来。原因很简单人类的短期记忆容量是有限的APK 动辄几万个类、几十万个方法谁能全记住传统做法是一边分析一边写笔记写满了三四页 Markdown分析完还得再整理一遍才能交付。换句话说逆向的真正成本在于“信息整理”和“流程记忆”不在于“单点突破”。这跟把大象装进冰箱一样你知道三步就能完成但每一步之间的状态转换得有人盯着。1.2 AI Agent 擅长什么不擅长什么AI 大模型真正擅长的是“在给定上下文里做推断和归纳”。你给它一个 Manifest 文件它能快速列出权限、组件、导出状态你给它一段反编译的 Java 代码它能大概猜出这段逻辑是干嘛的。它不擅长的则是“自己从一个裸的 APK 开始凭空规划完整分析路径”。前者是分析能力后者是项目管理能力——Agent 工作流要解决的就是把后者结构化让模型每一步都拿到明确输入只做它擅长的判断。所以 apk-reverse 的定位很清晰把“项目规划”交给一套固定的工作流把“每个节点的分析”交给大模型。这条路走得通核心在于这套工作流覆盖了静态分析领域 80% 的固定动作——解包、读 Manifest、查入口、提取字符串、枚举关键类、梳理调用关系、生成报告。这 80% 的固定动作一旦被编码成流程剩下的 20% 判断空间就是 Agent 发挥价值的地方。1.3 这个项目要解决的核心问题把多次命令、多方工具的输出统一成一套结构化上下文喂给 Agent让 Agent 能在每个分析节点上做“局部深入”同时不错全局关键分析路径可追溯每一步的依据来自哪个文件、哪条命令都能查最终产出统一格式的报告适合入库、归档或者进一步喂给下游自动化听起来好像不难但真正落地时你会发现要同时做到这四点难点全在细节怎么规划上下文窗口、怎么设计 Agent 的工具调用、怎么避免反编译产出太重导致模型“淹死”在信息里。这些都是我在项目里反复调的东西下面详细说。2. 工作流整体架构与分层设计整个 apk-reverse 工作流我把它拆成了四层信息采集层、推理分析层、结果落地层、质量校正层。每一层只做自己那一层的事层与层之间通过统一的“任务包”传递信息。2.1 信息采集层先让 Agent 有东西可“看”这一层的职责很纯粹把 APK 文件变成机器可读、模型可理解的结构化输入。我固定使用 apktool 做资源解包、jadx 做 Java 源码反编译、apkanalyzer 提取清单信息再用自写的小脚本把 keystore 签名信息、字符串常量、资源引用表一并导出。这里有一个关键设计不是把全部反编译结果都丢给 Agent而是先做“缩减”。比如 jadx 会生成几十 MB 的 java 源码这直接超出上下文上限所以我只保留两类内容“入口相关类”和“高敏感类”。这两类通过关键词匹配来筛选比如涉及 crypto、payment、dex、反射调用、native 方法的类优先进入分析列表。这一步其实是把人类分析员“先从哪个文件看起”的经验编码成了规则。2.2 推理分析层Agent 的“三步循环”Agent 在这个工作流里不是一次性问答而是进入一个三步循环观察、判断、行动。观察读取当前任务包中的上下文包括 Manifest 摘要、类清单、敏感字符串列表判断基于大模型的分析能力判断当前这一项任务需要看哪些类的具体代码行动调用工具函数去读取指定文件拿到新信息后回到观察状态我借鉴了 ReAct 模式但没有用现成的 LangChain 那套因为逆向领域工具链太重、输出格式太特殊通用 Agent 框架对错误输出的容错不够好。我最后是直接用 Python 少量 Bash 脚本自己实现了一个简单的 Agent 主循环。2.3 结果落地层统一报告格式分析过程跑完必须产出统一格式。我的报告固定为 JSON 结构里面分八个区块应用基础信息、权限与组件清单、入口 Activity 定位、关键类与可疑行为清单、动态行为线索如反射调用目标字符串、第三方 SDK 识别、文件路径与数据流描述、风险初步评级。为什么用 JSON 而不是 Markdown因为报告出来之后往往还要被下游流程接着消费——比如自动生成合规审查清单、自动对比两个 APK 的差异、或者做增量分析。结构化输出是整个工作流能“复用”的根基。2.4 关键工具选型我为什么没有用现成框架试过用 Dify、Coze 这类工作流平台去做概念上完全对口但落到实际逆向场景就发现问题这类平台的节点大多是 HTTP 请求、数据库存取要扩展到本地执行 apktool、读文件系统、跑命令行工具需要大量自定义节点。而且逆向过程动辄产出几百 MB 中间文件上传到平台再拉回来分析吞吐量完全跟不上。所以我最后选择本地化实现Agent 框架只在内网运行。另一条没走的路是用 Java/Kotlin 写 Agent 主流程。虽然逆向圈子玩 JVM 生态很熟但 Agent 主流程最需要的是“快速迭代”Python 的灵活性和库生态明显更适合。至于 Rust——标题可能让人以为我用了 Rust实际我只在“批量重命名反编译产物文件”的小工具里用了 Rust 来做性能加速主流程依然是 Python。这算是个诚实的技术选型结论性能瓶颈在模型推理 IO不在主流程语言。3. 实操过程从 APK 到结构化分析报告这章是重点。我会把每个阶段的具体命令、参数、代码片段以及我在实操中调过的坑都写出来。目标是你照着这套步骤也能把任意一个 APK 跑出报告来。3.1 环境准备与目录规划我是用 WSL2 Ubuntu 跑的整套流程。目录规划非常重要因为逆向工程会产生大量中间文件如果不做目录隔离后面找问题会做到崩溃。mkdir -p ~/apk-rv/{raw,decompiled,agents/context,agents/scratch,reports}raw存放原始 APKdecompiledapktool 解包产物按包名/版本号子目录隔离agents/context每个分析任务的结构化上下文包agents/scratchAgent 在分析过程中写临时文件的地方reports最终 JSON 报告我为什么要单独划一个 scratch 目录因为 Agent 在分析时可能会调用工具函数去“看看某个类的代码”这个“看”的动作不能污染正式上下文。它只能读文件不能改上下文包。每次它需要的新信息都会先落到 scratch 目录再由主循环合并进下一轮上下文。3.2 数据采集把 APK 拆成可分析的语料第一步解包推荐优先用 apktool 而不是直接 jadx。cd ~/apk-rv/raw apktool d your_app.apk -o ~/apk-rv/decompiled/your_appapktool 解包后你会看到一个完整的资源目录结构AndroidManifest.xml已经转为可读 XMLres/里是资源文件smali/里是 smali 字节码。我见过有人拿/storage/emulated/0/android/data/这类路径当线索在 APK 里找东西但其实在静态分析阶段这些路径更多出现在字符串常量里用来指示应用运行期读写外部存储的位置——解包后可以直接 grep 字符串效率比运行时抓取高得多。然后是 jadx 反编译。注意参数jadx -d ~/apk-rv/decompiled/java --show-bad-code --no-res \ -j 4 your_app.apk这里建议加上--show-bad-code因为部分 APK 在混淆后会产生无法完整还原的代码块不开启这个参数的话 jadx 会跳过这些区域导致分析输入不完整。-j参数控制线程数机器内存不够 16G 的建议开-j 2我实测开太高容易 OOM。再提取签名信息可选但推荐apksigner verify --print-certs your_app.apk签名信息在分析应用来源、判断是否被第三方重打包时非常有用。我在工作流里会把输出的证书指纹写进报告的基础信息区。3.3 提取关键信息Manifest、字符串和入口类解包完成后第一时间提取三个维度的信息。Manifest 摘要python3 - PY import re, xml.etree.ElementTree as ET tree ET.parse(~/.ly/AndroidManifest.xml) # 改为实际路径 root tree.getroot() NS {android: http://schemas.android.com/apk/res/android} permissions root.findall(.//uses-permission) for p in permissions: print(p.get({http://schemas.android.com/apk/res/android}name)) PY我实际写的是一个小工具会把 application 节点、activity 节点、service 节点、provider 节点全部提出来做成清单。exported 属性和 intent-filter 里的 action 是重点关注项这两个组合起来能判断哪些组件可以被外部应用唤起对分析数据泄露路径很关键。字符串与路径线索cd ~/apk-rv/decompiled grep -r content:// --include*.xml -l res/ | head -20 grep -r \.so --include*.java -l java/ | head -20这里要提醒一句grep 字符串线索时别一股脑全搜。我建议分成几个固定 pattern 组比如content://相关 provider、/data/和/storage/路径、http/https地址、\.so动态库引用、getClassLoader反射调用。分组搜出结果后每个结果再关联到具体类。这样 Agent 拿到的不是一串干巴巴的字符串而是“这个字符串出现在哪个类、哪个 xml 文件”的上下文线索。入口 Activity 定位python3 ~/apk-rv/tools/find_launcher.py ~/apk-rv/decompiled/java/AndroidManifest.xml这个脚本的逻辑很简单遍历所有 activity 节点找到包含MAINaction 和LAUNCHERcategory 的项。但要注意有些 APK 会在启动后快速跳转到第二个 Activity所以入口不等于业务主逻辑我在报告里会特意区分“启动入口”和“业务入口”。3.4 定义 Agent 的任务节点到这一步数据结构已经准备齐全。接下来就是把任务包组装给 Agent。我定义了一个简单的任务节点每个节点由四部分组成节点名、输入说明、工具列表、预期产出。{ node: manifest_audit, input: app_basic_info.json, tools: [read_file, grep_pattern], output_keys: [permissions_risk, exported_components] }Agent 主循环是一个简单的while循环# agent_loop.py import json def run_task(task_batch, llm_client): context load_task_batch(task_batch) for step in task_batch[steps]: observation prepare_observation(context, step) plan llm_client.decide(observation, step) # plan 是结构化的动作列表读文件/查字符串/写笔记 for action in plan: if action[type] read_file: content read_file(action[path]) context[scratch].append({file: action[path], summary: content}) elif action[type] grep: context[scratch].append(grep_pattern_with_ctx(action[pattern])) context[steps].append(step) return format_report(context)这个循环在今天看来不算复杂但设计时的核心思路是永远不让 Agent 直接面对“整个 APK”这种巨大的不确定性。每个节点给它的输入都是收敛过的子集它的决策空间被限制在一个安全范围内。如果你用的是 OpenAI 的函数调用接口或 Anthropic 的工具调用接口上面的动作列表可以映射为 tools 数组里的函数声明。我给四个工具函数read_file(path)、grep_pattern(pattern, scope)、list_dir(path)、write_note(obj)。注意不要给模型太多自由尤其不要开放任意 shell 执行权限——原因是逆向中间产物包含大量不可信内容让模型直接执行 shell 会带来注入风险。3.5 上下文管理与信息注入策略大模型上下文窗口总是有限的而反编译分析的信息密度又极高。我处理这个问题用了一个土办法但实测很稳“窗口压缩 局部展开”。每轮分析只放三类信息进上下文当前节点要求的摘要信息比如当前类的方法签名列表最近两轮 Agent 自己写的分析笔记用户提供的全局目标例如“找出数据外发路径”如果 Agent 需要看某个类的完整代码它通过 read_file 工具去读读进来的内容直接进 scratch不进主上下文。主上下文永远保持“够用就行”的状态。这个方法在 8K 上下文的模型上也能跑通换成 128K 窗口的模型也只是更从容不会改变架构。关于 token 消耗一次完整 APK 分析大约消耗 20 万到 60 万 token。成本大头不是初始信息而是反复读取类文件的增量消耗。如果你批量分析很多 APK建议按应用分组跑并开启结果缓存——同一应用的二次分析只跑增量部分。4. 常见问题与排查技巧实录这块全部来自我实际操作中踩出来的教训很多坑并不在技术文档里只能靠经验填补。4.1 反编译工具崩溃与资源限制最常碰到的问题就是 jadx 处理超大 APK 时 OOM。这类 APK 通常是大型游戏或者集成了多个重量级 SDK 的应用反编译产物动辄数十万类。遇到过/storage/emulated/0/android/data/这种路径在字符串里大量出现通常是应用在手机上访问自身私有目录时的常量反编译时这些字符串本身不占太多空间但关联的资源文件图会撑爆内存。我的解决策略是分级处理首轮用 apktool 解包后先做资源裁剪把res/里纯图片、音频类资源排除在分析范围外jadx 只跑核心 DEX 而不是所有 DEX用命令行参数指定 dex 文件。如果这样还 OOM开-Xmx4g给 JVM 显式设堆上限避免进程把整机内存吃死。4.2 Agent 在分析过程中的“需求漂移”模型在连续多轮分析后会出现一种现象它慢慢偏离最初的用户目标。比如你的目标是“找出应用是否收集了设备标识符”分析到第三个节点时它突然开始关注某个第三方 SDK 的广告接口。信息多了之后模型会“顺着当前上下文惯性走”。我的解决办法是在每个任务节点开头都注入一段“当前任务目标”的 reminders。代码上也很简单就是一个固定的字符串模板每次循环时都拼进去。别小看这一步我对比过加不加这句话的效果最终报告的关键发现覆盖率差了将近三成。4.3 并发执行与任务队列问题“AI Agent 怎么扛并发”这个话题在社区聊得很热。我自己的实践是Agent 主循环本身是单线程的并发主要发生在“多个任务同时分析多个 APK”这个水平。因为模型调用接口是异步的瓶颈通常在磁盘 IO 和模型 API 的速率限制上。我的做法是把任务拆成“分析单元”每个单元跑一个 Agent 实例单元之间通过文件系统隔离。用multiprocessing简单并行或者直接跑多个进程配合一个 SQLite 表记录任务状态pending/running/done/failed。实测四核机器同时跑 4 个任务没问题超过后会在 apktool 解包阶段出现磁盘抢占收益反而不高。如果你想在自己机器上复现先从concurrency2开始观察磁盘占有率和单任务耗时再往上加。4.4 与混淆代码搏斗的日常混淆后的代码是逆向里最头疼的问题。包名全变成 a/b/c/d类名、方法名全部无意义。Agent 在分析这类 APK 时最大的风险是“因为看不懂就乱猜”。我在工作流里加了一道硬性规则分析混淆代码时模型必须先列出“可观察特征”比如字符串常量、调用的系统 API、库特征签名再下结论。这个规则很有效地压制了幻觉。你可以理解为人类逆向分析也不全靠读名字而是靠行为模式推断——代理模型也应该强制它走同样的路径。真实的类名只是一个辅助信号不能作为主要判断依据。4.5 路径相关问题provider 与文件读取热词里有一堆content://和/storage/emulated/0/android/data/...的路径其实在逆向报告里这部分对应的是 FileProvider 和外部存储访问逻辑。分析时注意provider节点里的android:authorities往往暴露了应用包名或公司域名而 paths 配置会暴露应用向外部暴露了哪些目录。我在字符串扫描阶段会专门搜这两个特征并且在报告里单独做一块“目录与文件访问”分析。这类线索对合规审查用处极大。有一次分析一个 SDK 时发现它的 provider 配置了对外暴露整个/data/data/目录的权限这在真实设备上等于把应用私有数据目录拱手让人。如果是靠人肉分析这种细节很容易漏掉但放在工作流里它就是一条固定的检查规则。5. 目前这套工作流的边界和后续扩展思考先说边界。这套工作流针对的是“静态分析”范畴下的常规任务。它不会做动态调试也不会主动运行恶意负载。如果你的目标是 hook 运行中的真实 App、抓运行时流量、绕过完整性校验这一类任务这套流程只能给你提供线索不能直接给你结果。另外对加固壳类的 APKapktool 和 jadx 解出来的只是壳的加载逻辑真正逻辑在内存里。这种情况下我的工作流会输出“该 APK 疑似加壳”的标记并建议转向动态分析或脱壳环节。这已经是另一种技术栈了不在这篇博文范围里。我能看到的最有扩展潜力的方向有三个把工作流跑在 CI 上订阅新版本 APK自动生成“版本间差异分析报告”。对 SDK 厂商来说每次发版自动对比权限变化、新增 API、敏感字符串省下的合规审计时间非常可观。把多个 APK 的分析结果汇到一起做组件级知识库。比如你维护了 100 家竞品应用跑完之后就有一个“行业组件画像”数据库哪些 SDK 是标配、哪些权限是滥用重灾区都能直接统计。把 Agent 的 final report 接上向量数据库做成团队内部的“逆向检索知识库”。下次新人拿到一个新 APK先检索相似历史分析报告起步效率会高很多。我个人在把整套流程跑通之后最大的体会是——所谓“AI Agent 工作流”真正的价值不在于让模型替你做判断而在于把你过去那些“只可意会不可言传”的流程资产化。每一条分析规则、每一个工具调用顺序过去都长在老手的脑子里人走了经验就没了现在它们被固化成了代码和数据流即使是一个入门不够深的开发者也能借助这套流程做出六十分水平的初步分析然后在这个基础上再深入。这个意义比“某个节点用聪明模型”带来的提升要大得多。如果你正在考虑做类似的事情可以试试我从头到尾用的一套“最小闭环法”先手工走一遍分析流程边做边记录你看了哪些文件、跑了哪些命令然后把这些记录抽象成任务节点再交给 Agent 去跑。你不需要一开始就把所有环节做到自动化先跑通一个 APK 的分析再慢慢加节点。毕竟逆向的价值从来不在于用上吊炸天的工具而在于把每一步都想明白为什么这么做。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →