在移动安全领域,完全依赖正则表达式的扫描容易产生海量误报,而完全依赖 AI 阅读代码又受限于上下文窗口和对复杂数据流的计算能力。有没有一种结合两者优势的方案呢?
本文介绍一种 基于 Skill 编排的审计架构。该架构将传统的静态分析工具(如 Soot/FlowDroid)封装为 Agent 的“工具箱”,由 Claude Code 等大模型作为“大脑”进行调度与最终决策,旨在打造一个高效、低误报的自动化审计流程。
核心架构思路
我们设计了一个 “漏斗式” 的分析流水线,逐层过滤,精准定位:
- 第一层:源码与资源获取 (基础设施层)
- 使用 Jadx 反编译 APK,获取 Java 伪代码和
AndroidManifest.xml 文件。
- 第二层:基于模式匹配的快速筛选 (特征层)
- 使用 Semgrep 或 Regex 快速扫描反编译后的 Java 源码。
- 寻找特征:硬编码密钥、弱加密算法(ECB模式)、SQL 拼接字符串、Log 打印敏感信息。
- 同时分析
AndroidManifest.xml 中的暴露组件。
- 第三层:Soot/FlowDroid 路径验证 (数据流层)
- 针对第二层发现的“可疑点”(作为 Sink),进行定向的污点分析,确认用户输入(Source)是否真的能到达这里。
- 第四层:AI 代码审计 (语义层)
- 提取关键代码片段,结合上下文喂给 LLM。
- 让 AI 进行最终判断:是否存在过滤逻辑?是否是误报?并生成修复建议。
具体架构流程如下图所示:

项目的标准目录结构如下:
app-security-automation/
├── CLAUDE.md <-- 核心:Claude Code 的“大脑”配置
├── SKILL.md <-- 核心:详细的审计技能文档
├── scripts/ <-- 脚本 (quick_scan.sh, analyze_candidates.py)
├── tools/ <-- 工具 (flowdroid, android.jar)
├── targetapks/ <-- 待测 APK
└── files/ <-- 输出结果
详细工作流设计
第一步:源码还原
Agent 调用 scripts/decompile.sh 脚本。该脚本将 APK 转换为 Java 伪代码,并特别关注 --show-bad-code 参数,确保即使反编译不完美也能获取尽可能多的逻辑信息。
第二步:快速锚定
面对海量文件,AI 不可能逐行阅读。我们需要先找到“靶点”。Agent 调用 scripts/quick_scan.sh,基于特征库(如 rawQuery, loadUrl, Runtime.exec)进行快速扫描,产出一份包含文件路径和行号的 “潜在风险列表”。
第三步:污点分析与路径验证
这是本架构的核心差异点。正则只能看到“有点像漏洞”,而数据流分析才能证明“数据确实流过去了”。Agent 针对第二步发现的可疑点,调用 scripts/analyze_candidates.py。该脚本利用 Soot + FlowDroid,将第二步发现的 Sink 点(如 SQL 执行处)作为目标,追踪 Source 点(如 getIntent, EditText),计算是否存在一条从 Source 到 Sink 的通路,最终产出结构化的数据流报告。
第四步:AI 智能裁决
这是传统工具无法替代的环节。工具不懂业务逻辑(比如这个 SQL 拼接是否只是在查本地配置表?),但 AI 可以理解。Agent 读取源码和 FlowDroid 报告,结合数据流证据和业务逻辑,进行最终的 AI决策,判定是误报还是真实漏洞风险。
关键脚本功能详解
decompile.sh – 反编译与源码准备
这个脚本是自动化安全审计流程的第一步,核心作用是将 APK 文件还原为可读的 Java 源代码,为后续分析奠定基础。
它的设计亮点包括:
- 强制命令行模式:确保在服务器或 Docker 等无头环境中静默运行。
- 环境清理:运行前清理旧目录,防止结果混淆。
- 为“机器阅读”优化:使用
--show-bad-code 保留不完整代码;--deobf 尝试反混淆;--no-imports 和 --comments-level none 移除噪音,减少 AI 分析的 Token 消耗。
- 性能与健壮性:分配 4GB 内存防止 OOM,启用 4 线程并行,并在最后验证输出目录结构。
#!/bin/bash
# 用法: ./scripts/decompile.sh <path_to_apk> <output_dir>
APK_PATH=$1
OUTPUT_DIR=${2:-"../source_dump"} # 默认为 source_dump 目录
JADX_JAR="../tools/jadx-1.5.3-all.jar"
if [ -z "$APK_PATH" ]; then
echo "Usage: $0 <apk_file> [output_dir]"
exit 1
fi
if [ ! -f "$JADX_JAR" ]; then
echo "Error: JADX jar not found at $JADX_JAR"
exit 1
fi
echo " Starting Decompilation for $APK_PATH..."
# 清理旧目录,防止混淆
if [ -d "$OUTPUT_DIR" ]; then
echo "[-] Cleaning old output directory..."
rm -rf "$OUTPUT_DIR"
fi
# 执行 Jadx (针对 AI 优化的参数 + 强制 CLI 模式)
java -Xmx4g -cp "$JADX_JAR" jadx.cli.JadxCLI \
-d "$OUTPUT_DIR" \
--show-bad-code \
--deobf \
--threads-count 4 \
--no-imports \
--comments-level none \
"$APK_PATH"
# 检查返回值
if [ $? -eq 0 ]; then
echo "[+] Decompilation Successful! Output: $OUTPUT_DIR"
# 验证目录结构,方便后续脚本定位 source_root
if [ -d "$OUTPUT_DIR/sources" ]; then
echo "[+] Source Root located at: $OUTPUT_DIR/sources"
else
echo "[!] Warning: 'sources' subdirectory not found. Check structure."
fi
else
echo "[!] Decompilation With Errors."
exit 1
fi
quick_scan.sh – 并行化快速扫描
这是流程的第二步,核心作用是利用正则表达式进行快速、粗粒度的“海选”,从海量源码中定位所有“疑似”漏洞点,并生成结构化的 CSV 清单。
它的核心功能包括:
- 并行化扫描:同时启动多个后台进程扫描不同类型漏洞,充分利用多核 CPU。
- 多维度模式匹配:内置针对 SQL 注入、硬编码密钥、命令注入、WebView 风险、路径遍历的检测规则,并带有初步过滤(如排除
BuildConfig.java)。
- 数据清洗与结构化:将
grep 的原始输出解析为标准 CSV 格式(类型、文件路径、行号、代码片段),便于后续 Python 脚本处理。
- 噪音控制:使用
head -n 20 限制每类漏洞的候选数量,防止常见工具类产生海量低质量结果堵塞后续分析。
#!/bin/bash
SOURCE_DIR=$1
OUTPUT_CSV="../files/scan_candidates.csv" # 中间文件
TEMP_DIR=$(mktemp -d)
if [ -z "$SOURCE_DIR" ]; then
echo "Usage: $0 <source_dir>"
exit 1
fi
# 初始化 CSV 头
echo "type,filepath,linenum,content" > "$OUTPUT_CSV"
echo "=== Android Security Quick Scan (Parallel Mode) ==="
echo "Target: $SOURCE_DIR"
# 定义辅助函数:提取信息并写入 CSV
process_results() {
local v_type=$1
local input_file=$2
# 逐行读取 grep 结果 (格式: file:line:content)
while read -r line; do
filepath=$(echo "$line" | cut -d: -f1)
linenum=$(echo "$line" | cut -d: -f2)
content=$(echo "$line" | cut -d: -f3- | tr -d ',')
echo "$v_type,$filepath,$linenum,$content" >> "$OUTPUT_CSV"
done < "$input_file"
}
scan_sql() {
# 增加过滤条件,减少误报
grep -rnE "rawQuery|execSQL" "$SOURCE_DIR" | grep "+" | head -n 20 > "$TEMP_DIR/sql.raw"
process_results "SQL_INJECTION" "$TEMP_DIR/sql.raw"
}
scan_secrets() {
# 排除 BuildConfig 和 R.java
grep -rnEi "api_key|access_token|secret_key|password =" "$SOURCE_DIR" | grep -vE "BuildConfig.java|R.java" | head -n 20 > "$TEMP_DIR/secrets.raw"
process_results "HARDCODED_SECRET" "$TEMP_DIR/secrets.raw"
}
scan_webview() {
grep -rn "setJavaScriptEnabled" "$SOURCE_DIR" | head -n 20 > "$TEMP_DIR/webview.raw"
process_results "WEBVIEW_RISK" "$TEMP_DIR/webview.raw"
}
scan_cmd_injection() {
grep -rnE "Runtime\.getRuntime\(\)\.exec|ProcessBuilder" "$SOURCE_DIR" | head -n 20 > "$TEMP_DIR/cmd.raw"
process_results "CMD_INJECTION" "$TEMP_DIR/cmd.raw"
}
scan_path_traversal() {
grep -rnE "new File\(|FileInputStream" "$SOURCE_DIR" | grep "+" | head -n 20 > "$TEMP_DIR/file.raw"
process_results "PATH_TRAVERSAL" "$TEMP_DIR/file.raw"
}
# 并发执行
scan_sql & PID1=$!
scan_secrets & PID2=$!
scan_webview & PID3=$!
scan_cmd_injection & PID5=$!
scan_path_traversal & PID6=$!
wait $PID1 $PID2 $PID3
echo "=== Scan Finished ==="
echo "candidates saved to: $OUTPUT_CSV"
# 同时也打印给人看
cat "$OUTPUT_CSV" | column -t -s,
rm -rf "$TEMP_DIR"
analyze_candidates.py – 智能分析与裁决
这个 Python 脚本是整个系统的“大脑”(第三步)。它接收正则扫描的“疑似名单”,通过智能调度策略,有选择地启动 FlowDroid 进行深度污点分析,并生成确凿的审计报告。
主要功能亮点:
- 智能分析路由:根据漏洞类型决定处理方式。对 SQL 注入、命令注入等需要验证数据流的类型,触发 FlowDroid;对硬编码密钥等配置问题,则跳过 FlowDroid,直接标记。
- 自动化 FlowDroid 调度:封装了调用 FlowDroid 的复杂命令,包含超时、路径解析、参数优化(如启用上下文敏感分析)。
- 结果验证与分级:解析 FlowDroid 的 XML 报告。找到完整路径的标记为 High (Verified Flow);仅正则匹配但未验证的标记为 Medium (Unverified)。
- 结构化报告生成:输出标准化的 JSON 报告,便于后续展示或直接喂给 LLM 生成修复建议。
#!/usr/bin/env python3
import csv
import sys
import os
import json
import subprocess
import xml.etree.ElementTree as ET
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(SCRIPT_DIR)
FLOWDROID_JAR = os.path.join(BASE_DIR, "tools", "soot-infoflow-cmd-jar-with-dependencies.jar")
ANDROID_PLATFORMS = os.path.join(BASE_DIR, "tools", "android.jar")
SOURCES_SINKS_FILE = os.path.join(BASE_DIR, "tools", "SourcesAndSinks.txt")
TAINT_ANALYSIS_TARGETS = [
"SQL_INJECTION",
"CMD_INJECTION",
"PATH_TRAVERSAL",
"WEBVIEW_LOAD_URL"
]
def get_class_name(filepath, source_root):
"""将文件路径转换为 Java 类名"""
source_root = os.path.abspath(source_root)
filepath = os.path.abspath(filepath)
try:
rel_path = os.path.relpath(filepath, source_root)
if rel_path.endswith(".java"):
rel_path = rel_path[:-5]
return rel_path.replace(os.sep, ".")
except ValueError:
return os.path.basename(filepath).replace(".java", "")
def parse_flowdroid_xml(xml_file):
"""解析 FlowDroid 生成的 XML 报告"""
results = []
try:
tree = ET.parse(xml_file)
root = tree.getroot()
for result in root.findall(".//Result"):
source = result.find("Source")
sink = result.find("Sink")
if source is not None and sink is not None:
results.append({
"source": source.get("Statement"),
"sink": sink.get("Statement")
})
except Exception as e:
print(f"[!] XML Parse Error: {e}")
return []
return results
def run_flowdroid(apk_path, class_name):
"""调用 Java 运行 FlowDroid"""
output_xml = f"flow_results_{class_name.split('.')[-1]}.xml"
cmd = [
"java", "-jar", FLOWDROID_JAR,
"-a", apk_path,
"-p", ANDROID_PLATFORMS,
"-s", SOURCES_SINKS_FILE,
"--output", output_xml,
"--outputformat", "xml",
"--taintanalysis", "apcontext",
"--no-callback-analyzers"
]
print(f" Executing FlowDroid for class: {class_name} ...")
try:
subprocess.run(cmd, timeout=300, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if os.path.exists(output_xml):
findings = parse_flowdroid_xml(output_xml)
os.remove(output_xml)
return findings
else:
return None
except subprocess.TimeoutExpired:
print(f"[!] FlowDroid timed out for {class_name}")
return None
except Exception as e:
print(f"[!] FlowDroid failed: {e}")
return None
def main():
if len(sys.argv) < 4:
print("Usage: python3 analyze_candidates.py <apk_path> <csv_file> <source_dump_dir>")
sys.exit(1)
apk_path = sys.argv[1]
csv_file = sys.argv[2]
source_root = sys.argv[3]
output_json = os.path.join(BASE_DIR, "files", "final_audit_report.json")
os.makedirs(os.path.dirname(output_json), exist_ok=True)
if not os.path.exists(FLOWDROID_JAR):
print(f"[Error] FlowDroid jar not found at: {FLOWDROID_JAR}")
sys.exit(1)
if not os.path.exists(ANDROID_PLATFORMS):
print(f"[Error] Android Platforms not found at: {ANDROID_PLATFORMS}")
sys.exit(1)
final_report = []
try:
with open(csv_file, 'r', encoding='utf-8', errors='ignore') as f:
reader = csv.DictReader(f)
for row in reader:
vuln_type = row.get('type', 'UNKNOWN')
filepath = row.get('filepath', '')
linenum = row.get('linenum', '0')
content = row.get('content', '')
report_item = {
"type": vuln_type,
"file": filepath,
"line": linenum,
"code_snippet": content,
"analysis_mode": "Static Pattern Match"
}
if vuln_type in TAINT_ANALYSIS_TARGETS:
class_name = get_class_name(filepath, source_root)
if class_name and not class_name.endswith(".java"):
flow_data = run_flowdroid(apk_path, class_name)
if flow_data and len(flow_data) > 0:
report_item["flow_analysis"] = {
"reachable": True,
"evidence": flow_data
}
report_item["severity"] = "HIGH (Verified Flow)"
report_item["analysis_mode"] = "FlowDroid Verified"
else:
report_item["flow_analysis"] = {
"reachable": False,
"note": "FlowDroid found no path"
}
report_item["severity"] = "MEDIUM (Unverified)"
else:
report_item["note"] = "Skipped FlowDroid: Cannot determine class name"
else:
report_item["flow_analysis"] = "N/A"
report_item["severity"] = "Check Manually"
final_report.append(report_item)
with open(output_json, 'w') as f:
json.dump(final_report, f, indent=2)
print(f"\n[+] Analysis Complete! Report saved to: {output_json}")
except Exception as e:
print(f"[Error] Script failed: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()
与大模型(Claude Code)的集成
为了让 AI Agent 理解并正确调用这套工具链,需要两个核心文档。
CLAUDE.md – 项目配置说明
这个文件告诉 Claude Code 项目的基本信息、可用命令和目录结构,是 AI 理解项目环境的入口。
# Claude Code Project Configuration
## Project Description
这是一个 Android 自动化安全审计系统。它结合了 grep 正则扫描(快速)和 FlowDroid 污点分析(深度验证)。核心逻辑在 `SKILL.md` 中有详细描述。
## Commands
- **Quick Scan**: `bash scripts/quick_scan.sh targetapks/<apk_name>`
- 作用: 反编译 APK 并生成初步的 `files/scan_candidates.csv`。
- **Deep Analysis**: `python3 scripts/analyze_candidates.py targetapks/<apk_name> files/scan_candidates.csv source_dump/sources`
- 作用: 读取 CSV,对高危漏洞(如 SQL注入)运行 FlowDroid,生成 JSON 报告。
- **Full Audit**: 依次运行 Quick Scan 和 Deep Analysis。
## Project Structure
- `scripts/`: 包含 Python 和 Bash 自动化脚本。
- `tools/`: 包含 FlowDroid jar 包 (`soot-infoflow...jar`) 和 `android.jar`。
- `files/`: 存放扫描结果。
- `targetapks/`: 存放待扫描的 .apk 文件。
## Coding Style
- Python: Follow PEP 8. Use `os.path.join` for paths.
- Bash: Use standard bash syntax.
## Analysis Workflow (Important)
当你被要求审计一个 APK 时:
1. 请先阅读 `SKILL.md` 了解判断逻辑。
2. 检查 `scripts/` 和 `tools/` 是否存在。
3. 按照 Commands 中的顺序执行工具。
4. 如果脚本执行失败,请检查路径是否正确,并尝试修复路径问题。
5. 最后根据 `files/final_audit_report.json` 的内容生成审计报告
SKILL.md – 核心技能与决策逻辑
这个文档是 Agent 的“大脑”,详细定义了审计的 SOP、工具调用逻辑、漏洞判定标准和报告格式。它尤其重要,因为它包含了 智能路由决策表,指导 Agent 何时调用耗时的 FlowDroid,何时直接给出结论,从而在保证深度的同时提升效率。
# 基本信息
- name: app-security-scan-automation
- description: 一个专注于 Android 静态应用安全测试 (SAST) 的智能体。通过编排静态分析工具(Semgrep/Soot)与 LLM 语义分析能力,自动检测代码漏洞,并利用逻辑推理大幅降低误报率。
# 能力与工具链
你拥有对以下本地工具链的调用权限和操作知识:
## 快速扫描工具 (`quick_scan.sh`)
- **功能**: 自动反编译 APK 并使用 `grep` 进行正则匹配。
- **输入**: APK 文件路径。
- 输出:
- `source_dump/`: Java 源码目录。
- `files/scan_candidates.csv`: 包含疑似漏洞的文件名、行号和代码片段的清单。
- **适用场景**: 初始扫描,发现 SQL 注入、硬编码密钥、Webview 配置、命令执行等所有疑似点。
## 深度分析引擎 (`analyze_candidates.py`)
- **功能**: 读取 CSV 候选列表,根据漏洞类型决定是否启动 FlowDroid 污点分析。
- 核心逻辑:
- **污点分析 (Taint Analysis)**: 针对 `SQL_INJECTION`, `CMD_INJECTION`, `PATH_TRAVERSAL`, `WEBVIEW_LOAD_URL`。如果 FlowDroid 发现从 Source 到 Sink 的路径,标记为 `HIGH (Verified Flow)`。
- **静态确认 (Static Check)**: 针对 `HARDCODED_SECRET`, `LOGGING`, `WEAK_CRYPTO`。直接标记为人工复核。
- **依赖**: `tools/android.jar` (便携式 SDK), `tools/soot-infoflow-cmd-jar-with-dependencies.jar`.
- **输出**: `files/final_audit_report.json`。
# 操作标准作业程序 (SOP)
## 1、阶段一:反编译与初步扫描
1. 接收用户提供的 APK 路径(例如 `../targetapks/test.apk`)。
2. 执行 Shell 命令:
```bash
cd scripts
./quick_scan.sh <apk_path>
```
3. 检查 `files/scan_candidates.csv` 是否生成。如果不为空,进入下一阶段。
## 2、阶段二:智能路由与深度验证
1. 调用 Python 脚本进行验证。**注意**: 必须正确指定源码目录(通常是 `source_dump/sources` 以便正确解析包名)。
2. 执行命令:
```bash
python3 analyze_candidates.py <apk_path> ../files/scan_candidates.csv ../source_dump/sources
```
3. 等待脚本运行完成(FlowDroid 可能需要数分钟)。
## 3、阶段三:报告生成与解读
1. 读取 `files/final_audit_report.json`。
2. 按照严重程度排序输出报告:
- 🔴 **HIGH (Verified Flow)**: 必须优先展示。这是 FlowDroid 实锤的漏洞,存在完整的利用链。请展示 `Source` (输入点) 和 `Sink` (触发点)。
- 🟠 **MEDIUM (Unverified)**: 可能是漏洞,但 FlowDroid 未找到路径(可能是逻辑复杂或误报)。建议人工审计。
- 🟡 **Low/Info**: 硬编码密钥、日志泄露等配置问题。
## 4、决策逻辑 (Decision Logic)
Agent 在分析过程中必须遵守以下决策树,以节省计算资源:
| 漏洞类型 (Vuln Type) | 处理方式 | 理由 |
| :------------------------------------------ | :------------------- | :------------------------------------------ |
| **SQL Injection** (`rawQuery`, `execSQL`) | ✅ **Run FlowDroid** | 只有当参数来自用户输入时才危险。 |
| **Cmd Injection** (`Runtime.exec`) | ✅ **Run FlowDroid** | 极高风险,必须确认参数是否可控。 |
| **Path Traversal** (`new File`) | ✅ **Run FlowDroid** | 过滤掉正常的内部文件操作。 |
| **Hardcoded Secrets** (`"api_key"`) | 🚫 **Skip FlowDroid** | 字符串存在即漏洞,无需分析流向。 |
| **WebView Config** (`setJavaScriptEnabled`) | 🚫 **Skip FlowDroid** | 这是状态配置,不是数据流问题。 |
| **Logging** (`Log.d`) | 🚫 **Skip FlowDroid** | 数量巨大,跑 FlowDroid 会导致超时。 |
## 5、错误处理 (Error Handling)
- **Jadx 失败**: 如果反编译目录为空,提示用户 APK 可能损坏或加固。
- **FlowDroid 超时**: 脚本设定了 300秒 超时。如果日志显示 `FlowDroid timed out`,在报告中标记为 "Complexity High - Manual Review Required"。
- **找不到类名**: 如果 `get_class_name` 失败,脚本会跳过 FlowDroid。在报告中注明 "Skipped dynamic analysis due to obfuscation"。
## 6、报告生成
- 汇总为Markdown格式报告,报告名称为 安全审计报告.md
```
## 🔒 安全审计报告
### 🎯 扫描摘要
* **目标 APK**: `demo.apk`
* **发现风险点**: 15 个
* **高危实锤**: 2 个 (经 FlowDroid 验证)
### 🚨 高危漏洞 (High Severity)
**1. SQL 注入**
* **位置**: `com.example.db.DatabaseHelper.java` : Line 45
* **证据**:
* 输入点 (Source): `etUsername.getText().toString()`
* 触发点 (Sink): `db.rawQuery(query, null)`
* **分析**: 这是一个经 FlowDroid 验证的完整攻击路径。用户输入直接拼接到了 SQL 语句中。
### ⚠️ 潜在风险 (Medium/Check Manually)
**1. 硬编码密钥**
* **位置**: `com.example.Config.java` : Line 12
* **代码**: `String API_KEY = "123456-secret";`
* **建议**: 请移除代码中的敏感字符串。
...
```
实战演示与效果
准备好环境后,在 Claude Code 中输入提示词(如“请按照 SKILL.md 的流程,审计 targetapks/test.apk”),即可启动整个自动化审计流程。

执行完成后,Agent 会生成总结并告知报告位置。

最终生成的结构化审计报告清晰明了,包含了扫描摘要、风险分级和详细证据。

总结与展望
本文介绍了一个融合传统静态分析工具与 人工智能 决策的 Android 自动化安全审计 MVP 方案。其核心价值在于“漏斗式”的架构设计:
- 快速层(Regex) 负责广撒网,发现所有疑似点。
- 验证层(FlowDroid) 负责深度求证,为高危漏洞提供数据流证据,显著降低误报。
- 裁决层(LLM) 负责理解上下文和业务逻辑,做出最终判定并生成修复建议。
这种方法有效平衡了扫描速度、分析深度和结果准确性。未来可优化的方向包括:集成 AndroidManifest.xml 的组件与权限分析、扩充漏洞规则库、进一步优化扫描逻辑以去除误报。
这个项目展示了如何通过 Skill 编排 将多个单点工具串联成强大的自动化工作流,为安全/渗透/逆向领域的效率提升提供了新思路。欢迎对 Android 安全或自动化审计感兴趣的朋友在 云栈社区 交流讨论,共同完善这个项目。
项目代码与文档地址:https://github.com/DSFLY100/Skill-Android-Security-Agent