MT管理器MCP APK分析技能
基于 mt_mcp 服务分析 APK,支持只读分析和编辑重打包。根据用户需求动态分析,不预设固定流程。
核心流程
必须先 mt_apk_open → 获取 workspaceId → 后续所有工具都需要此 ID。
只读分析工具
| 工具 |
用途 |
关键参数 |
mt_apk_open |
打开 APK,获取 workspaceId |
path, temporary |
mt_apk_list_available_apks |
列出可用 APK 文件 |
prefix, limit |
mt_apk_list |
浏览 ZIP/DEX类/资源表 |
workspaceId, editSessionId, view, prefix, limit |
mt_apk_outline_class |
查看类结构(字段+方法) |
workspaceId, editSessionId, locator, limit |
mt_apk_search |
搜索关键词/代码/字符串 |
workspaceId, editSessionId, target, query, queryType |
mt_apk_read_text |
读取 Smali/XML/文本 |
workspaceId, editSessionId, locator, limit, maxChars |
mt_apk_read_resource |
批量读取资源值 |
workspaceId, editSessionId, reads[], maxValueXmlChars |
mt_apk_read_zip_bytes |
读取 ZIP 原始字节(十六进制) |
workspaceId, editSessionId, locator, byteOffset, maxBytes |
mt_apk_xref_dex |
DEX 交叉引用(方法/字段/类调用者) |
workspaceId, editSessionId, locator, methodResolution, limit |
mt_apk_xref_resource |
资源引用查询 |
workspaceId, editSessionId, locator, scopes, limit |
mt_apk_continue |
翻页 |
workspaceId, editSessionId, nextCursor, limit |
编辑流程工具
| 工具 |
用途 |
关键参数 |
mt_apk_edit_open |
创建编辑会话 → editSessionId |
workspaceId |
mt_apk_edit_text |
编辑 Smali/AXML/ZIP文本 |
workspaceId, editSessionId, locator, targetVersion, edits[] |
mt_apk_edit_resource |
编辑资源值 |
workspaceId, editSessionId, edits[] |
mt_apk_edit_check |
检查编辑/构建可行性 |
workspaceId, editSessionId, runBuildChecks |
mt_apk_build |
构建并签名 APK |
workspaceId, editSessionId, outputName, overwrite |
mt_apk_close |
关闭临时工作区(temporary=true) |
workspaceId |
关键规则
Locator 格式(字符串,非 JSON)
dex_class:Lcom/example/Foo;
dex_method:Lcom/example/Foo;->bar()V
dex_field:Lcom/example/Foo;->flag:Z
zip_entry:assets/config.json
axml:AndroidManifest.xml
resource:0x7f010000
Dalvik 类名格式:L 前缀 + / 替换 . + ; 后缀(如 Lcom/example/MyClass;)。
editSessionId 规则
- 读取基础工作区:传
""(空字符串)
- 读取/编辑编辑会话:传
mt_apk_edit_open 返回的 ID
- 所有 list/search/read/xref/continue 工具都需要此参数
通用必填参数
所有工具的参数均为必填(无可选参数)。常用默认值:
limit=50(搜索/xref) / 200(list/outline) / 500(read_text)
maxChars=49152 / maxBytes=256
prefix="" 表示无过滤
搜索 target 选择器
mt_apk_search 用 target(单值枚举)选择搜索范围:
| target |
搜索内容 |
最佳用途 |
overview |
ZIP路径+AXML+资源ID/名称/值+DEX名称+DEX字符串 |
未知目标的广搜(不含smali) |
files |
ZIP路径+解码AXML文本 |
搜索清单/布局/文件路径 |
resource_table_names |
资源ID/名称 |
按名称查找资源 |
resource_table_values |
解码资源值 |
查找字符串资源值 |
resource_table_file_paths |
指向ZIP路径的资源值 |
查找引用文件路径的资源 |
dex_names |
类/字段/方法名称 |
按名称查DEX实体 |
dex_strings |
DEX字符串字面量(按类分组) |
硬编码文本、URL、密钥 |
dex_string_members |
DEX字符串字面量(按成员分组) |
字符串使用详情 |
smali |
完整Smali反汇编文本 |
指令模式、字段访问、调用 |
prefix 参数(因 target 而异): overview 必须为 "";files 用 ZIP路径前缀;resource_table_* 用 0x7f../type/name/name;dex_*/smali 用类所有者前缀(Java包名/斜杠/L前缀)。
工具参数详解
mt_apk_open
| 参数 |
说明 |
| path |
"mt://current-apk" / "mt://workspace/<id>"(重开) / list_available_apks 返回的相对路径 |
| temporary |
true=一次性(可close删除);false=可复用/重开/长期保留 |
返回 workspaceId、apkFileName、compact.manifest.package/versionName/versionCode、compact.count.*、compact.capability.*。
mt_apk_list
| view |
prefix 格式 |
返回 |
zip_entries |
"res/layout/" |
zip_entry 定位器 |
dex_classes |
"Lcom/example/" 或 "com.example" |
dex_class 定位器(传给 outline_class) |
resource_table |
"0x7f010000" / "string/" / "app_name" |
resource 定位器 + 轻量值预览 |
mt_apk_outline_class
传入 dex_class:Lcom/example/Foo; 定位器,返回 header(className/super/implements/source/access) + fields[](name/sig/access/locator) + methods[](name/sig/access/interestingStrings/locator)。
mt_apk_read_text
| locator 前缀 |
读取内容 |
可编辑 |
zip_entry: |
ZIP文件文本 |
✓(非 resources.arsc) |
axml: |
解码后的 Android XML |
✓ |
dex_class: |
完整类 Smali 源码 |
✓ |
dex_method: |
单方法 Smali |
✓ |
dex_field: |
字段定义 Smali |
✗(只读) |
参数:limit(行数,max 2000)、maxChars(max 131072)、startLine/startColumn(0-based)。返回 textWindow.text + targetVersion(编辑时必需)。
mt_apk_read_resource
批量读取(1-200个),每个 read 含 locator(如 resource:0x7f010000) + variant(如 default)。
预算参数:maxValueChars=4096 / maxValueXmlChars=32768 / maxItemsPerValue=50 / resolveDepth=0。
返回 results[].value(摘要) + results[].valueXml(完整可编辑XML) + results[].targetVersion。
mt_apk_xref_dex
查找方法/字段/类的调用者。methodResolution 模式:
dispatch(推荐,用于 dex_method):查找可能到达目标的调用
exact:精确匹配 MethodReference
slot:查找可见重写族
not_applicable(用于 dex_field/dex_class):字段/类只支持精确引用
mt_apk_edit_text
必须先 read_text 获取 targetVersion。 edits[] 每项含 mode/matchText/writeText:
| mode |
说明 |
matchText |
writeText |
write_target |
替换整个目标/创建新目标(targetVersion="missing") |
"" |
完整内容 |
delete_target |
删除整个目标 |
"" |
"" |
replace_match |
替换匹配文本(空writeText=删除) |
原文本 |
新文本 |
insert_before_match |
在匹配前插入 |
匹配文本 |
插入文本 |
insert_after_match |
在匹配后插入 |
匹配文本 |
插入文本 |
matchText 必须在目标中恰好出现一次;多次匹配返回 TEXT_MATCH_AMBIGUOUS,需用更长上下文重试。单个 locator 的多个编辑是原子操作。
mt_apk_edit_resource
必须先 read_resource 获取 locator/variant/targetVersion/valueXml。 每次 1-200 项(推荐约20)。不能修改根元素名称/资源ID/变体,不能创建新资源。
mt_apk_build
outputName="" 用默认名 <原文件名>_mcp_<editSessionId>_sign.apk(始终覆盖);非空时若文件存在且 overwrite=false 返回 OUTPUT_ALREADY_EXISTS。输出到 MCP 配置目录,源 APK 不变。
搜索模式速查
| 目标 |
target |
queryType |
query 示例 |
| API URL |
dex_strings |
regex |
https?://[a-zA-Z0-9._/-]+ |
| 按名称查类/方法/字段 |
dex_names |
literal |
onClick |
| 枚举类 |
dex_names |
regex |
.*Status$|.*Type$ |
| 静态字段读取 |
smali |
regex |
sget-object.*->FIELD:Lcom/target/.*; |
| 字段写入 |
smali |
regex |
sput-object|iput-object.*->FIELD: |
| 方法调用 |
smali |
regex |
invoke-virtual.*->methodName |
| 构造函数 |
smali |
regex |
invoke-direct.*-><init> |
| 字符串常量 |
smali |
regex |
const-string.*"target text" |
| 字符串资源 |
resource_table_values |
literal |
error_message |
| 权限/Manifest |
files |
literal |
android.permission |
| 包范围搜索 |
任意 |
任意 |
任意 + prefix="com/example/pkg" |
| 广搜(未知目标) |
overview |
literal |
keyword |
query 始终必填。overview 模式下 prefix 必须为 ""。target="smali" 时 matchMode 不能用 exact。
工作流模板
省磁盘铁律:纯分析/只读任务一律用 open(temporary=true),完成后 mt_apk_close(workspaceId) 释放。
只有要反复重开同一 APK 或要编辑打包才用 temporary=false。否则 Android/data/bin.mt.plus*/mcp/ 会堆到好几 GB。
T1: APK 架构概览
1. open(path="mt://current-apk", temporary=true) → workspaceId + manifest
2. read_text(locator="axml:AndroidManifest.xml", editSessionId="", ...) → 组件/权限
3. outline_class(locator="dex_class:<AppClass>", editSessionId="", ...) → 初始化流程
4. search(target="dex_strings", query="http|https|wss", queryType="regex", prefix="", ...) → API域名
5. search(target="dex_strings", query="Retrofit|OkHttp|Glide", prefix="", ...) → 第三方框架
6. list(view="dex_classes", prefix=<mainPkg>, editSessionId="", limit=1) → 主包类数量7. close(workspaceId) → 分析完释放临时工作区(省磁盘)```
### T2: 定位特定功能/字段
- search(target="overview", query="keyword", prefix="", limit=20, ...) → 找引用关键词的类
- outline_class(locator="dex_class:", editSessionId="", ...) → 理解类结构
- read_text(locator=<hit.locator>, editSessionId="", maxChars=50000, ...) → 读完整Smali
- search(target="dex_names", query="fieldName", prefix="relevant/pkg", ...) → 包范围内查同名字段
- search(target="smali", query="sget.*fieldName|iget.*fieldName", queryType="regex", prefix="", ...) → 追踪字段访问
### T3: 网络配置分析
- search(target="dex_names", query="BaseUrl|ApiHost|ServerConfig", queryType="regex", prefix="", ...) → 找配置类
- read_text(locator="dex_class:", editSessionId="", ...) → 提取域名
- search(target="dex_strings", query="https?://[a-zA-Z0-9._-]+", queryType="regex", prefix="", limit=30, ...) → 提取URL
- search(target="files", query="network_security_config", prefix="", ...) → 找安全配置文件
- read_text(locator="axml:res/xml/network_security_config.xml", editSessionId="", ...) → 读安全策略
### T4: 安全分析
- read_text(locator="axml:AndroidManifest.xml", editSessionId="", ...) → 权限声明
- search(target="files", query="CAMERA|RECORD_AUDIO|ACCESS_FINE_LOCATION", queryType="regex", prefix="", ...) → 敏感权限
- search(target="dex_strings", query="encrypt|decrypt|cipher|AES|RSA", prefix="", ...) → 加密操作
- search(target="dex_names", query="KeyStore|Cipher|Signature", prefix="", ...) → 安全相关类
- search(target="dex_strings", query="WebView|loadUrl|javascript", prefix="", ...) → WebView使用
### T5: 追踪方法调用链
- outline_class(locator="dex_class:", editSessionId="", ...) → 找方法签名
- xref_dex(locator="dex_method:->", methodResolution="dispatch", editSessionId="", ...) → 找调用者(推荐dispatch)
- read_text(locator=<caller.sourceLocator>, editSessionId="", ...) → 读调用上下文
- search(target="smali", query="invoke.*targetClass;->methodName", queryType="regex", prefix="", ...) → 追踪invoke模式
### T6: 编辑修改 APK
- open(path=..., temporary=true) → workspaceId
- edit_open(workspaceId) → editSessionId
- read_text(locator="dex_method:...", editSessionId=, ...) → 获取 targetVersion
- edit_text(locator=..., targetVersion=..., edits=[{mode:"replace_match", matchText:"const/4 v0, 0x0", writeText:"const/4 v0, 0x1"}], ...) → 修改
- edit_check(workspaceId, editSessionId, runBuildChecks=true) → 验证构建
- build(workspaceId, editSessionId, outputName="", overwrite=false) → 构建签名APK
- close(workspaceId) → 释放临时工作区(可选)
---
## 分析场景速查
**功能定位关键词:**
| 场景 | 关键词 | target | 包范围 prefix |
|------|--------|--------|------------|
| 支付 | payment, pay, purchase, order, alipay, wechatpay | dex_strings | 主包 |
| 会员/VIP | vip, premium, member, subscribe, isVip | dex_strings + dex_names | 主包 |
| 登录认证 | login, auth, token, session, credential, oauth | dex_strings | 主包 |
| 网络请求 | http, retrofit, okhttp, api, baseUrl | dex_strings + dex_names | 主包 |
| 数据存储 | sqlite, room, sharedpreferences, database, dao | dex_names | 主包 |
| 推送 | push, fcm, jpush, xiaomi_push, notification | dex_strings | 主包 |
| 广告 | ad, banner, interstitial, reward, admob | dex_strings | 主包 |
**安全审计关键词:**
| 场景 | 关键词 | target |
|------|--------|--------|
| 敏感信息泄露 | password, secret, key, token, api_key | dex_strings |
| 硬编码URL | `https?://[a-zA-Z0-9._-]+` (regex) | dex_strings |
| 加密算法 | AES, RSA, MD5, SHA, Cipher, encrypt | dex_strings + smali |
| 危险权限 | CAMERA, RECORD_AUDIO, READ_PHONE, ACCESS_FINE_LOCATION | files (AXML) |
| WebView风险 | loadUrl, addJavascriptInterface, setJavaScriptEnabled | smali |
| 组件暴露 | exported="true", intent-filter | files (AXML) |
> **大型 APK 优化:** 先 `read_text(axml:AndroidManifest.xml)` 获取包名,再用 `prefix=主包名` 限定搜索范围,排除第三方库(占60-80%代码)。
---
## 进阶分析策略
**锚点扩散法** — 从已知字符串定位功能代码:
search(target="dex_strings", query="已知字符串") → 锚点类
→ outline_class(locator="dex_class:<锚点类>") → 了解结构
→ search(target="smali", query="<锚点类Dalvik名>", queryType="regex") → 找引用者
→ 对引用者重复上述步骤,绘制调用关系图
**字段生命周期追踪** — 理解状态变量读写:
search(target="dex_names", query="isVip") → 找字段定义
→ search(target="smali", query="iget.*isVip|sget.*isVip", queryType="regex") → 读取点
→ search(target="smali", query="iput.*isVip|sput.*isVip", queryType="regex") → 写入点
→ read_text(写入点方法) → 理解赋值逻辑
**方法调用链追踪** — 推荐用 xref_dex 而非 smali 搜索:
outline_class → 找方法签名
→ xref_dex(locator="dex_method:...", methodResolution="dispatch") → 精确找调用者
→ read_text(caller.sourceLocator) → 读调用上下文
`dispatch` 模式能找到接口/抽象方法的所有实现调用,比 smali regex 搜索更准。
**资源反查代码** — 从 UI 资源反推逻辑:
search(target="resource_table_names", query="btn_purchase") → 资源ID
→ xref_resource(locator="resource:0x7f...", scopes=["dex","axml","resource_table"]) → 找引用
→ outline_class(引用类) → 找事件处理方法
---
## 混淆与反混淆
**混淆特征:** 短类名(a/b/c)、短方法名、短字段名、`source="Unknown"`。
**反混淆策略(按可靠性排序):**
1. **字符串常量** — 混淆不改字符串: `search(target="dex_strings", query="已知文本")` 定位锚点
2. **类层次** — `outline_class` 检查 `header.super`/`implements` 中的已知框架类
3. **框架API** — `search(target="smali", query="Landroid/widget/TextView;->setText")` 找UI代码
4. **资源引用** — `search(target="smali", query="R.string.xxx")` 找资源使用者
5. **入口点** — 从 Manifest 的 Activity 类名追踪
多 DEX 透明处理,搜索自动覆盖所有 DEX。
---
## 架构模式识别
先 `list(view="dex_classes", prefix=主包)` 浏览包结构,判断架构后定向搜索:
| 架构 | 包名特征 | 业务逻辑所在层 |
|------|---------|------------|
| MVVM | `.ui.` `.viewmodel.` `.repository.` | ViewModel |
| MVP | `.presenter.` `.view.` `.contract.` | Presenter |
| Clean | `.domain.` `.data.` `.presentation.` | UseCase/Interactor |
| MVI | `.intent.` `.state.` `.reducer.` | Reducer |
看到 `ui/main/viewmodel/` 目录 → MVVM → VIP逻辑在 `MainViewModel`。
---
## 防御机制识别与绕过
分析时先识别防御机制,修改方案才可行:
| 防御类型 | 识别关键词 | 绕过Smali修改 |
|---------|-----------|-------------|
| 签名校验 | getPackageInfo, GET_SIGNATURES, signatures | 校验方法 `const/4 v0, 0x1` + `return v0` |
| Root检测 | "/su", "Superuser", "isRooted", Magisk | 检测方法 `const/4 v0, 0x0` + `return v0` |
| 模拟器检测 | goldfish, nox, isEmulator, genymotion | 同Root,返回false |
| 调试检测 | isDebuggerConnected, TracerPid | 移除调用或返回false |
| 完整性校验 | CRC32, MessageDigest, checksum | 校验方法返回true |
| Hook检测 | Xposed, frida-server, substrate | 检测方法返回false |
**绕过要点:** 用 `edit_text` 的 `replace_match` 修改条件跳转(`if-eq`→`if-ne`)或方法返回值。多种防御可能分散在不同类,需全面搜索逐一处理。
---
## Dalvik/Smali 速查
**类型映射:** `V`void `Z`boolean `I`int `J`long `F`float `D`double `B`byte `C`char `S`short / `Lcom/pkg/Cls;`类 `[I`int[] `[Ljava/lang/String;`String[]
**方法签名:** `name(ParamTypes)ReturnType` — `onCreate(Landroid/os/Bundle;)V` / `isVip()Z` / `getName(I)Ljava/lang/String;`
**字段访问:**
sget-object v0, LCls;->FIELD:LType; # 读静态字段
sput-object v0, LCls;->FIELD:LType; # 写静态字段
iget-object v0, v1, LCls;->FIELD:LType; # 读实例字段(v1=对象)
iput-object v0, v1, LCls;->FIELD:LType; # 写实例字段
**方法调用:**
invoke-virtual {v0,v1}, LCls;->method(I)V # 实例方法
invoke-static {v0}, LCls;->staticMethod(I)I # 静态方法
invoke-interface {v0}, LIfc;->method()V # 接口方法
invoke-direct {v0,v1}, LCls;->(I)V # 构造函数/private
**控制流(常见修改点):**
if-eqz v0, :label # v0==null跳转 → 改 if-nez 反转逻辑
if-nez v0, :label # v0!=null跳转 → 改 if-eqz 反转逻辑
const/4 v0, 0x0 # false → 改 0x1 为 true
const/4 v0, 0x1 # true → 改 0x0 为 false
return v0 # 返回值
return-void # 提前返回(移除广告/跳过校验)
**常见修改模式:**
| 需求 | 修改方法 |
|------|---------|
| 跳过VIP验证 | `if-eq` → `if-ne` 或方法直接 `const/4 v0, 0x1` + `return v0` |
| 解锁付费功能 | 状态检查返回 true |
| 移除广告 | 广告加载方法开头加 `return-void` |
| 绕过登录 | 登录状态检查返回 true |
| 禁用更新 | 版本比较逻辑反转 |
---
## 常见错误
| 错误 | 原因 | 修复 |
|------|------|------|
| Invalid target | target 非枚举值 | 用 `overview`/`files`/`dex_names`/`dex_strings`/`dex_string_members`/`smali`/`resource_table_*` 之一 |
| Class not found | locator 非 Dalvik 格式 | 用 `dex_class:Lcom/example/Cls;` 而非 `com.example.Cls` |
| Unsupported locator | locator 前缀错误 | read_text 接受 `zip_entry:`/`axml:`/`dex_class:`/`dex_method:`/`dex_field:`;read_resource 接受 `resource:` |
| Missing required field | 缺少必填参数 | 所有参数必填,基础工作区 editSessionId 传 `""` |
| Data truncated | 输出过大 | 增大 maxChars(max 131072) / 用 startLine+limit / 用 continue |
| exact + smali 冲突 | target=smali 且 matchMode=exact | target="smali" 时用 matchMode="contains" |
| TEXT_MATCH_AMBIGUOUS | edit_text matchText 多次匹配 | 提供更长上下文使 matchText 唯一 |
| NOT_TEXT_ENTRY | read_text 读二进制条目 | 改用 mt_apk_read_zip_bytes |
| Stale targetVersion | 编辑时版本号过期 | 重新 read_text/read_resource 获取 targetVersion |
| OUTPUT_ALREADY_EXISTS | build 时文件已存在 | 传 overwrite=true 或换 outputName |
错误码:4401=参数校验错误,400=业务逻辑错误。检查 `recoverable`/`retrySameArguments` 标志和 `nextActions` 数组。
---
## 分页与返回结构
所有调用返回 `{ok, data, error, nextActions}`。当 `pagination.hasMore=true` 时,从 `nextActions[].arguments` 复制 `workspaceId`/`editSessionId`/`nextCursor`/`limit` 调用 `mt_apk_continue`。**游标不透明,不要解析/构造/修改。**
`mt_apk_list_available_apks` 续页时:`workspaceId="available_apks"`, `editSessionId=""`。
## APK 匹配
`mt_apk_open` 的 path 支持模糊匹配:
- `"mt://current-apk"` → 当前APK
- `"com.tencent.mm"` → 包名匹配
- `"微信"` / `"kwyy"` → 模糊匹配文件名或包名
- `"a.apk"` → 精确匹配
若返回 `CURRENT_APK_NOT_AVAILABLE`,先调 `mt_apk_list_available_apks` 获取列表再选择。多匹配时列出结果让用户选择。
1---2name: mt-mcp-apk-analyzer3description: MT管理器MCP服务专用APK分析技能。基于MT管理器的mt_mcp服务对APK文件进行深度分析(支付功能、敏感字符串、类结构、资源等),生成结构化分析报告。当用户需要分析APK时触发此技能。4---56# MT管理器MCP APK分析技能78基于 mt_mcp 服务分析 APK,支持只读分析和编辑重打包。**根据用户需求动态分析,不预设固定流程。**910## 核心流程1112**必须先 `mt_apk_open`** → 获取 `workspaceId` → 后续所有工具都需要此 ID。1314### 只读分析工具1516| 工具 | 用途 | 关键参数 |17|------|------|----------|18| `mt_apk_open` | 打开 APK,获取 workspaceId | path, temporary |19| `mt_apk_list_available_apks` | 列出可用 APK 文件 | prefix, limit |20| `mt_apk_list` | 浏览 ZIP/DEX类/资源表 | workspaceId, editSessionId, view, prefix, limit |21| `mt_apk_outline_class` | 查看类结构(字段+方法) | workspaceId, editSessionId, locator, limit |22| `mt_apk_search` | 搜索关键词/代码/字符串 | workspaceId, editSessionId, target, query, queryType |23| `mt_apk_read_text` | 读取 Smali/XML/文本 | workspaceId, editSessionId, locator, limit, maxChars |24| `mt_apk_read_resource` | 批量读取资源值 | workspaceId, editSessionId, reads[], maxValueXmlChars |25| `mt_apk_read_zip_bytes` | 读取 ZIP 原始字节(十六进制) | workspaceId, editSessionId, locator, byteOffset, maxBytes |26| `mt_apk_xref_dex` | DEX 交叉引用(方法/字段/类调用者) | workspaceId, editSessionId, locator, methodResolution, limit |27| `mt_apk_xref_resource` | 资源引用查询 | workspaceId, editSessionId, locator, scopes, limit |28| `mt_apk_continue` | 翻页 | workspaceId, editSessionId, nextCursor, limit |2930### 编辑流程工具3132| 工具 | 用途 | 关键参数 |33|------|------|----------|34| `mt_apk_edit_open` | 创建编辑会话 → editSessionId | workspaceId |35| `mt_apk_edit_text` | 编辑 Smali/AXML/ZIP文本 | workspaceId, editSessionId, locator, targetVersion, edits[] |36| `mt_apk_edit_resource` | 编辑资源值 | workspaceId, editSessionId, edits[] |37| `mt_apk_edit_check` | 检查编辑/构建可行性 | workspaceId, editSessionId, runBuildChecks |38| `mt_apk_build` | 构建并签名 APK | workspaceId, editSessionId, outputName, overwrite |39| `mt_apk_close` | 关闭临时工作区(temporary=true) | workspaceId |4041---4243## 关键规则4445### Locator 格式(字符串,非 JSON)4647```48dex_class:Lcom/example/Foo;49dex_method:Lcom/example/Foo;->bar()V50dex_field:Lcom/example/Foo;->flag:Z51zip_entry:assets/config.json52axml:AndroidManifest.xml53resource:0x7f01000054```5556Dalvik 类名格式:`L` 前缀 + `/` 替换 `.` + `;` 后缀(如 `Lcom/example/MyClass;`)。5758### editSessionId 规则5960- 读取基础工作区:传 `""`(空字符串)61- 读取/编辑编辑会话:传 `mt_apk_edit_open` 返回的 ID62- 所有 list/search/read/xref/continue 工具都需要此参数6364### 通用必填参数6566所有工具的参数均为必填(无可选参数)。常用默认值:67- `limit=50`(搜索/xref) / `200`(list/outline) / `500`(read_text)68- `maxChars=49152` / `maxBytes=256`69- `prefix=""` 表示无过滤7071---7273## 搜索 target 选择器7475`mt_apk_search` 用 `target`(单值枚举)选择搜索范围:7677| target | 搜索内容 | 最佳用途 |78|--------|----------|----------|79| `overview` | ZIP路径+AXML+资源ID/名称/值+DEX名称+DEX字符串 | 未知目标的广搜(不含smali) |80| `files` | ZIP路径+解码AXML文本 | 搜索清单/布局/文件路径 |81| `resource_table_names` | 资源ID/名称 | 按名称查找资源 |82| `resource_table_values` | 解码资源值 | 查找字符串资源值 |83| `resource_table_file_paths` | 指向ZIP路径的资源值 | 查找引用文件路径的资源 |84| `dex_names` | 类/字段/方法名称 | 按名称查DEX实体 |85| `dex_strings` | DEX字符串字面量(按类分组) | 硬编码文本、URL、密钥 |86| `dex_string_members` | DEX字符串字面量(按成员分组) | 字符串使用详情 |87| `smali` | 完整Smali反汇编文本 | 指令模式、字段访问、调用 |8889**prefix 参数(因 target 而异):** `overview` 必须为 `""`;`files` 用 ZIP路径前缀;`resource_table_*` 用 `0x7f..`/`type/name`/`name`;`dex_*`/`smali` 用类所有者前缀(Java包名/斜杠/L前缀)。9091---9293## 工具参数详解9495### mt_apk_open9697| 参数 | 说明 |98|------|------|99| path | `"mt://current-apk"` / `"mt://workspace/<id>"`(重开) / `list_available_apks` 返回的相对路径 |100| temporary | `true`=一次性(可close删除);`false`=可复用/重开/长期保留 |101102返回 `workspaceId`、`apkFileName`、`compact.manifest.package/versionName/versionCode`、`compact.count.*`、`compact.capability.*`。103104### mt_apk_list105106| view | prefix 格式 | 返回 |107|------|----------|------|108| `zip_entries` | `"res/layout/"` | zip_entry 定位器 |109| `dex_classes` | `"Lcom/example/"` 或 `"com.example"` | dex_class 定位器(传给 outline_class) |110| `resource_table` | `"0x7f010000"` / `"string/"` / `"app_name"` | resource 定位器 + 轻量值预览 |111112### mt_apk_outline_class113114传入 `dex_class:Lcom/example/Foo;` 定位器,返回 `header`(className/super/implements/source/access) + `fields[]`(name/sig/access/locator) + `methods[]`(name/sig/access/interestingStrings/locator)。115116### mt_apk_read_text117118| locator 前缀 | 读取内容 | 可编辑 |119|------------|---------|-------|120| `zip_entry:` | ZIP文件文本 | ✓(非 resources.arsc) |121| `axml:` | 解码后的 Android XML | ✓ |122| `dex_class:` | 完整类 Smali 源码 | ✓ |123| `dex_method:` | 单方法 Smali | ✓ |124| `dex_field:` | 字段定义 Smali | ✗(只读) |125126参数:`limit`(行数,max 2000)、`maxChars`(max 131072)、`startLine`/`startColumn`(0-based)。返回 `textWindow.text` + `targetVersion`(**编辑时必需**)。127128### mt_apk_read_resource129130批量读取(1-200个),每个 read 含 `locator`(如 `resource:0x7f010000`) + `variant`(如 `default`)。131预算参数:`maxValueChars=4096` / `maxValueXmlChars=32768` / `maxItemsPerValue=50` / `resolveDepth=0`。132返回 `results[].value`(摘要) + `results[].valueXml`(完整可编辑XML) + `results[].targetVersion`。133134### mt_apk_xref_dex135136查找方法/字段/类的调用者。`methodResolution` 模式:137- `dispatch`(推荐,用于 dex_method):查找可能到达目标的调用138- `exact`:精确匹配 MethodReference139- `slot`:查找可见重写族140- `not_applicable`(用于 dex_field/dex_class):字段/类只支持精确引用141142### mt_apk_edit_text143144**必须先 `read_text` 获取 `targetVersion`。** `edits[]` 每项含 `mode`/`matchText`/`writeText`:145146| mode | 说明 | matchText | writeText |147|------|------|-----------|-----------|148| `write_target` | 替换整个目标/创建新目标(`targetVersion="missing"`) | "" | 完整内容 |149| `delete_target` | 删除整个目标 | "" | "" |150| `replace_match` | 替换匹配文本(空writeText=删除) | 原文本 | 新文本 |151| `insert_before_match` | 在匹配前插入 | 匹配文本 | 插入文本 |152| `insert_after_match` | 在匹配后插入 | 匹配文本 | 插入文本 |153154`matchText` 必须在目标中**恰好出现一次**;多次匹配返回 `TEXT_MATCH_AMBIGUOUS`,需用更长上下文重试。单个 locator 的多个编辑是原子操作。155156### mt_apk_edit_resource157158**必须先 `read_resource` 获取 `locator`/`variant`/`targetVersion`/`valueXml`。** 每次 1-200 项(推荐约20)。不能修改根元素名称/资源ID/变体,不能创建新资源。159160### mt_apk_build161162`outputName=""` 用默认名 `<原文件名>_mcp_<editSessionId>_sign.apk`(始终覆盖);非空时若文件存在且 `overwrite=false` 返回 `OUTPUT_ALREADY_EXISTS`。输出到 MCP 配置目录,源 APK 不变。163164---165166## 搜索模式速查167168| 目标 | target | queryType | query 示例 |169|------|--------|-----------|-------|170| API URL | `dex_strings` | regex | `https?://[a-zA-Z0-9._/-]+` |171| 按名称查类/方法/字段 | `dex_names` | literal | `onClick` |172| 枚举类 | `dex_names` | regex | `.*Status$\|.*Type$` |173| 静态字段读取 | `smali` | regex | `sget-object.*->FIELD:Lcom/target/.*;` |174| 字段写入 | `smali` | regex | `sput-object\|iput-object.*->FIELD:` |175| 方法调用 | `smali` | regex | `invoke-virtual.*->methodName` |176| 构造函数 | `smali` | regex | `invoke-direct.*-><init>` |177| 字符串常量 | `smali` | regex | `const-string.*"target text"` |178| 字符串资源 | `resource_table_values` | literal | `error_message` |179| 权限/Manifest | `files` | literal | `android.permission` |180| 包范围搜索 | 任意 | 任意 | 任意 + prefix="com/example/pkg" |181| 广搜(未知目标) | `overview` | literal | `keyword` |182183> `query` 始终必填。`overview` 模式下 `prefix` 必须为 `""`。`target="smali"` 时 `matchMode` 不能用 `exact`。184185---186187## 工作流模板188189> 省磁盘铁律:纯分析/只读任务一律用 `open(temporary=true)`,完成后 `mt_apk_close(workspaceId)` 释放。190> 只有要反复重开同一 APK 或要编辑打包才用 `temporary=false`。否则 `Android/data/bin.mt.plus*/mcp/` 会堆到好几 GB。191192### T1: APK 架构概览193194```1951. open(path="mt://current-apk", temporary=true) → workspaceId + manifest1962. read_text(locator="axml:AndroidManifest.xml", editSessionId="", ...) → 组件/权限1973. outline_class(locator="dex_class:<AppClass>", editSessionId="", ...) → 初始化流程1984. search(target="dex_strings", query="http|https|wss", queryType="regex", prefix="", ...) → API域名1995. search(target="dex_strings", query="Retrofit|OkHttp|Glide", prefix="", ...) → 第三方框架2006. list(view="dex_classes", prefix=<mainPkg>, editSessionId="", limit=1) → 主包类数量7. close(workspaceId) → 分析完释放临时工作区(省磁盘)```201202### T2: 定位特定功能/字段203204```2051. search(target="overview", query="keyword", prefix="", limit=20, ...) → 找引用关键词的类2062. outline_class(locator="dex_class:<hitClass>", editSessionId="", ...) → 理解类结构2073. read_text(locator=<hit.locator>, editSessionId="", maxChars=50000, ...) → 读完整Smali2084. search(target="dex_names", query="fieldName", prefix="relevant/pkg", ...) → 包范围内查同名字段2095. search(target="smali", query="sget.*fieldName|iget.*fieldName", queryType="regex", prefix="", ...) → 追踪字段访问210```211212### T3: 网络配置分析213214```2151. search(target="dex_names", query="BaseUrl|ApiHost|ServerConfig", queryType="regex", prefix="", ...) → 找配置类2162. read_text(locator="dex_class:<configClass>", editSessionId="", ...) → 提取域名2173. search(target="dex_strings", query="https?://[a-zA-Z0-9._-]+", queryType="regex", prefix="", limit=30, ...) → 提取URL2184. search(target="files", query="network_security_config", prefix="", ...) → 找安全配置文件2195. read_text(locator="axml:res/xml/network_security_config.xml", editSessionId="", ...) → 读安全策略220```221222### T4: 安全分析223224```2251. read_text(locator="axml:AndroidManifest.xml", editSessionId="", ...) → 权限声明2262. search(target="files", query="CAMERA|RECORD_AUDIO|ACCESS_FINE_LOCATION", queryType="regex", prefix="", ...) → 敏感权限2273. search(target="dex_strings", query="encrypt|decrypt|cipher|AES|RSA", prefix="", ...) → 加密操作2284. search(target="dex_names", query="KeyStore|Cipher|Signature", prefix="", ...) → 安全相关类2295. search(target="dex_strings", query="WebView|loadUrl|javascript", prefix="", ...) → WebView使用230```231232### T5: 追踪方法调用链233234```2351. outline_class(locator="dex_class:<targetClass>", editSessionId="", ...) → 找方法签名2362. xref_dex(locator="dex_method:<targetClass>-><methodSig>", methodResolution="dispatch", editSessionId="", ...) → 找调用者(推荐dispatch)2373. read_text(locator=<caller.sourceLocator>, editSessionId="", ...) → 读调用上下文2384. search(target="smali", query="invoke.*targetClass;->methodName", queryType="regex", prefix="", ...) → 追踪invoke模式239```240241### T6: 编辑修改 APK242243```2441. open(path=..., temporary=true) → workspaceId2452. edit_open(workspaceId) → editSessionId2463. read_text(locator="dex_method:...", editSessionId=<editSessionId>, ...) → 获取 targetVersion2474. edit_text(locator=..., targetVersion=..., edits=[{mode:"replace_match", matchText:"const/4 v0, 0x0", writeText:"const/4 v0, 0x1"}], ...) → 修改2485. edit_check(workspaceId, editSessionId, runBuildChecks=true) → 验证构建2496. build(workspaceId, editSessionId, outputName="", overwrite=false) → 构建签名APK2507. close(workspaceId) → 释放临时工作区(可选)251```252253---254255## 分析场景速查256257**功能定位关键词:**258259| 场景 | 关键词 | target | 包范围 prefix |260|------|--------|--------|------------|261| 支付 | payment, pay, purchase, order, alipay, wechatpay | dex_strings | 主包 |262| 会员/VIP | vip, premium, member, subscribe, isVip | dex_strings + dex_names | 主包 |263| 登录认证 | login, auth, token, session, credential, oauth | dex_strings | 主包 |264| 网络请求 | http, retrofit, okhttp, api, baseUrl | dex_strings + dex_names | 主包 |265| 数据存储 | sqlite, room, sharedpreferences, database, dao | dex_names | 主包 |266| 推送 | push, fcm, jpush, xiaomi_push, notification | dex_strings | 主包 |267| 广告 | ad, banner, interstitial, reward, admob | dex_strings | 主包 |268269**安全审计关键词:**270271| 场景 | 关键词 | target |272|------|--------|--------|273| 敏感信息泄露 | password, secret, key, token, api_key | dex_strings |274| 硬编码URL | `https?://[a-zA-Z0-9._-]+` (regex) | dex_strings |275| 加密算法 | AES, RSA, MD5, SHA, Cipher, encrypt | dex_strings + smali |276| 危险权限 | CAMERA, RECORD_AUDIO, READ_PHONE, ACCESS_FINE_LOCATION | files (AXML) |277| WebView风险 | loadUrl, addJavascriptInterface, setJavaScriptEnabled | smali |278| 组件暴露 | exported="true", intent-filter | files (AXML) |279280> **大型 APK 优化:** 先 `read_text(axml:AndroidManifest.xml)` 获取包名,再用 `prefix=主包名` 限定搜索范围,排除第三方库(占60-80%代码)。281282---283284## 进阶分析策略285286**锚点扩散法** — 从已知字符串定位功能代码:287```288search(target="dex_strings", query="已知字符串") → 锚点类289→ outline_class(locator="dex_class:<锚点类>") → 了解结构290→ search(target="smali", query="<锚点类Dalvik名>", queryType="regex") → 找引用者291→ 对引用者重复上述步骤,绘制调用关系图292```293294**字段生命周期追踪** — 理解状态变量读写:295```296search(target="dex_names", query="isVip") → 找字段定义297→ search(target="smali", query="iget.*isVip|sget.*isVip", queryType="regex") → 读取点298→ search(target="smali", query="iput.*isVip|sput.*isVip", queryType="regex") → 写入点299→ read_text(写入点方法) → 理解赋值逻辑300```301302**方法调用链追踪** — 推荐用 xref_dex 而非 smali 搜索:303```304outline_class → 找方法签名305→ xref_dex(locator="dex_method:...", methodResolution="dispatch") → 精确找调用者306→ read_text(caller.sourceLocator) → 读调用上下文307```308`dispatch` 模式能找到接口/抽象方法的所有实现调用,比 smali regex 搜索更准。309310**资源反查代码** — 从 UI 资源反推逻辑:311```312search(target="resource_table_names", query="btn_purchase") → 资源ID313→ xref_resource(locator="resource:0x7f...", scopes=["dex","axml","resource_table"]) → 找引用314→ outline_class(引用类) → 找事件处理方法315```316317---318319## 混淆与反混淆320321**混淆特征:** 短类名(a/b/c)、短方法名、短字段名、`source="Unknown"`。322323**反混淆策略(按可靠性排序):**3241. **字符串常量** — 混淆不改字符串: `search(target="dex_strings", query="已知文本")` 定位锚点3252. **类层次** — `outline_class` 检查 `header.super`/`implements` 中的已知框架类3263. **框架API** — `search(target="smali", query="Landroid/widget/TextView;->setText")` 找UI代码3274. **资源引用** — `search(target="smali", query="R.string.xxx")` 找资源使用者3285. **入口点** — 从 Manifest 的 Activity 类名追踪329330多 DEX 透明处理,搜索自动覆盖所有 DEX。331332---333334## 架构模式识别335336先 `list(view="dex_classes", prefix=主包)` 浏览包结构,判断架构后定向搜索:337338| 架构 | 包名特征 | 业务逻辑所在层 |339|------|---------|------------|340| MVVM | `.ui.` `.viewmodel.` `.repository.` | ViewModel |341| MVP | `.presenter.` `.view.` `.contract.` | Presenter |342| Clean | `.domain.` `.data.` `.presentation.` | UseCase/Interactor |343| MVI | `.intent.` `.state.` `.reducer.` | Reducer |344345看到 `ui/main/viewmodel/` 目录 → MVVM → VIP逻辑在 `MainViewModel`。346347---348349## 防御机制识别与绕过350351分析时先识别防御机制,修改方案才可行:352353| 防御类型 | 识别关键词 | 绕过Smali修改 |354|---------|-----------|-------------|355| 签名校验 | getPackageInfo, GET_SIGNATURES, signatures | 校验方法 `const/4 v0, 0x1` + `return v0` |356| Root检测 | "/su", "Superuser", "isRooted", Magisk | 检测方法 `const/4 v0, 0x0` + `return v0` |357| 模拟器检测 | goldfish, nox, isEmulator, genymotion | 同Root,返回false |358| 调试检测 | isDebuggerConnected, TracerPid | 移除调用或返回false |359| 完整性校验 | CRC32, MessageDigest, checksum | 校验方法返回true |360| Hook检测 | Xposed, frida-server, substrate | 检测方法返回false |361362**绕过要点:** 用 `edit_text` 的 `replace_match` 修改条件跳转(`if-eq`→`if-ne`)或方法返回值。多种防御可能分散在不同类,需全面搜索逐一处理。363364---365366## Dalvik/Smali 速查367368**类型映射:** `V`void `Z`boolean `I`int `J`long `F`float `D`double `B`byte `C`char `S`short / `Lcom/pkg/Cls;`类 `[I`int[] `[Ljava/lang/String;`String[]369370**方法签名:** `name(ParamTypes)ReturnType` — `onCreate(Landroid/os/Bundle;)V` / `isVip()Z` / `getName(I)Ljava/lang/String;`371372**字段访问:**373```374sget-object v0, LCls;->FIELD:LType; # 读静态字段375sput-object v0, LCls;->FIELD:LType; # 写静态字段376iget-object v0, v1, LCls;->FIELD:LType; # 读实例字段(v1=对象)377iput-object v0, v1, LCls;->FIELD:LType; # 写实例字段378```379380**方法调用:**381```382invoke-virtual {v0,v1}, LCls;->method(I)V # 实例方法383invoke-static {v0}, LCls;->staticMethod(I)I # 静态方法384invoke-interface {v0}, LIfc;->method()V # 接口方法385invoke-direct {v0,v1}, LCls;-><init>(I)V # 构造函数/private386```387388**控制流(常见修改点):**389```390if-eqz v0, :label # v0==null跳转 → 改 if-nez 反转逻辑391if-nez v0, :label # v0!=null跳转 → 改 if-eqz 反转逻辑392const/4 v0, 0x0 # false → 改 0x1 为 true393const/4 v0, 0x1 # true → 改 0x0 为 false394return v0 # 返回值395return-void # 提前返回(移除广告/跳过校验)396```397398**常见修改模式:**399| 需求 | 修改方法 |400|------|---------|401| 跳过VIP验证 | `if-eq` → `if-ne` 或方法直接 `const/4 v0, 0x1` + `return v0` |402| 解锁付费功能 | 状态检查返回 true |403| 移除广告 | 广告加载方法开头加 `return-void` |404| 绕过登录 | 登录状态检查返回 true |405| 禁用更新 | 版本比较逻辑反转 |406407---408409## 常见错误410411| 错误 | 原因 | 修复 |412|------|------|------|413| Invalid target | target 非枚举值 | 用 `overview`/`files`/`dex_names`/`dex_strings`/`dex_string_members`/`smali`/`resource_table_*` 之一 |414| Class not found | locator 非 Dalvik 格式 | 用 `dex_class:Lcom/example/Cls;` 而非 `com.example.Cls` |415| Unsupported locator | locator 前缀错误 | read_text 接受 `zip_entry:`/`axml:`/`dex_class:`/`dex_method:`/`dex_field:`;read_resource 接受 `resource:` |416| Missing required field | 缺少必填参数 | 所有参数必填,基础工作区 editSessionId 传 `""` |417| Data truncated | 输出过大 | 增大 maxChars(max 131072) / 用 startLine+limit / 用 continue |418| exact + smali 冲突 | target=smali 且 matchMode=exact | target="smali" 时用 matchMode="contains" |419| TEXT_MATCH_AMBIGUOUS | edit_text matchText 多次匹配 | 提供更长上下文使 matchText 唯一 |420| NOT_TEXT_ENTRY | read_text 读二进制条目 | 改用 mt_apk_read_zip_bytes |421| Stale targetVersion | 编辑时版本号过期 | 重新 read_text/read_resource 获取 targetVersion |422| OUTPUT_ALREADY_EXISTS | build 时文件已存在 | 传 overwrite=true 或换 outputName |423424错误码:4401=参数校验错误,400=业务逻辑错误。检查 `recoverable`/`retrySameArguments` 标志和 `nextActions` 数组。425426---427428## 分页与返回结构429430所有调用返回 `{ok, data, error, nextActions}`。当 `pagination.hasMore=true` 时,从 `nextActions[].arguments` 复制 `workspaceId`/`editSessionId`/`nextCursor`/`limit` 调用 `mt_apk_continue`。**游标不透明,不要解析/构造/修改。**431432`mt_apk_list_available_apks` 续页时:`workspaceId="available_apks"`, `editSessionId=""`。433434## APK 匹配435436`mt_apk_open` 的 path 支持模糊匹配:437- `"mt://current-apk"` → 当前APK438- `"com.tencent.mm"` → 包名匹配439- `"微信"` / `"kwyy"` → 模糊匹配文件名或包名440- `"a.apk"` → 精确匹配441442若返回 `CURRENT_APK_NOT_AVAILABLE`,先调 `mt_apk_list_available_apks` 获取列表再选择。多匹配时列出结果让用户选择。