构建基于SKILL的Android智能审计Agent(完整版)

admin 2026-03-03 09:46:19 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文提出一种基于Skill编排的Android智能审计架构,解决纯正则误报高与纯AI上下文受限问题。架构采用漏斗式流水线:Jadx反编译还原源码,Semgrep正则快速筛选,Soot与FlowDroid污点分析验证数据流,最终由大模型进行语义裁决。文章详细展示了相关脚本的实现逻辑与参数配置,实现了传统工具与AI优势互补,为移动安全审计提供了高效落地方案。 综合评分: 91 文章分类: 移动安全,代码审计,安全工具,AI安全,安全建设


cover_image

构建基于 SKILL 的 Android 智能审计 Agent(完整版)

sec0nd安全

2026年2月14日 16:52 河北

以下文章来源于从黑客到保安 ,作者牧之

从黑客到保安 .

从攻防到物理安全

一、简言

在移动安全领域,完全依赖正则表达式的扫描容易产生海量误报,而完全依赖 AI 阅读代码又受限于上下文窗口和对复杂数据流的计算能力。

本文提出一种基于 Skill 编排的审计架构。该架构将传统的静态分析工具(Soot/FlowDroid)封装为 Agent 的“工具箱”,由 Claude Code 等大模型作为“大脑”进行调度与最终决策。

二、核心架构思路

我们可以设计一个 “漏斗式” 的分析流水线:

  1. 第一层:java代码和资源文件获取 (基础设施层)
  • Jadx反编译,获取伪码和AndroidManifest.xml
  1. 第二层:基于模式匹配的快速筛选 (特征层)****
  • 先用 Semgrep 或 Regex 快速扫描反编译后的 Java 源码。
  • 寻找特征:硬编码密钥、弱加密算法(ECB模式)、SQL 拼接字符串、Log 打印敏感信息。
  • 分析AndroidManifest.xml中的暴露组件。
  1. 第三层:Soot/FlowDroid 路径验证 (数据流层)
  • 针对第二层发现的“可疑点”,将其作为 Sink(污点汇聚点),进行定向的污点分析。确认用户输入(Source)是否真的能到达这里。
  1. 第四层:AI 代码审计 (语义层)
  • 提取关键代码片段,喂给 LLM。
  • 让 AI 判断:是否存在过滤逻辑?是否是误报?并生成修复建议。

具体架构图示如下:

目录结构如下:

app-security-automation/├── CLAUDE.md &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<-- 核心:Claude Code 的“大脑”配置├── SKILL.md &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<-- 核心:详细的审计技能文档├── scripts/&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<-- 脚本 (quick_scan.sh, analyze_candidates.py)├── tools/&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<-- 工具 (flowdroid, android.jar)├── targetapks/&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<-- 待测 APK└── files/&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<-- 输出结果

三、详细工作流设计

第一步:源码还原

Agent 调用 scripts/decompile.sh

将 APK 转换为 Java 伪代码。Agent 会特别关注 --show-bad-code 参数,确保即使反编译不完美也能获取尽可能多的逻辑信息。

第二步:快速锚定

面对海量文件,AI 不可能逐行阅读。我们需要先找到“靶点”。

Agent 调用 scripts/quick_scan.sh。基于特征库(如 rawQueryloadUrlRuntime.exec)进行快速扫描。产出一份包含文件路径和行号的 “潜在风险列表”

第三步:污点分析与路径验证

这是本架构的核心差异点。 正则只能看到“有点像漏洞”,Soot 才能证明“数据确实流过去了”。Agent 针对第二步发现的可疑点,调用 scripts/analyze_candidates.py。利用工具 Soot + FlowDroid 将第二步发现的 Sink 点(如 SQL 执行处)作为目标,追踪 Source 点(如 getIntentEditText),计算是否存在一条从 Source 到 Sink 的通路。最后产出结构化的数据流报告。例如:“在 LoginActivity.java 中,变量 username 从 Intent 输入,未经净化直接流入 rawQuery。”

第四步:AI 智能裁决

这是传统工具无法替代的环节。工具不懂业务逻辑(比如这个 SQL 拼接是否只是在查本地配置表?),但 AI 懂。

Agent 读取源码 + FlowDroid 报告,结合数据流证据和业务逻辑,判定是误报还是漏洞风险。

四、各个脚本的功能详解

decompile.sh

代码内容如下:

#!/bin/bash
# 用法: ./scripts/decompile.sh <path_to_apk> <output_dir>
APK_PATH=$1OUTPUT_DIR=${2:-"../wsource_dump"}&nbsp;# 默认为 source_dump 目录# 建议:将 JADX_JAR 路径改为配置变量或相对路径,确保通用性JADX_JAR="../tools/jadx-1.5.3-all.jar"
if&nbsp;[ -z&nbsp;"$APK_PATH"&nbsp;];&nbsp;then&nbsp; &nbsp;&nbsp;echo&nbsp;"Usage:&nbsp;$0&nbsp;<apk_file> [output_dir]"&nbsp; &nbsp;&nbsp;exit&nbsp;1fi
if&nbsp;[ ! -f&nbsp;"$JADX_JAR"&nbsp;];&nbsp;then&nbsp; &nbsp;&nbsp;echo&nbsp;"Error: JADX jar not found at&nbsp;$JADX_JAR"&nbsp; &nbsp;&nbsp;exit&nbsp;1fi
echo&nbsp;"[*] Starting Decompilation for&nbsp;$APK_PATH..."
# 清理旧目录,防止混淆if&nbsp;[ -d&nbsp;"$OUTPUT_DIR"&nbsp;];&nbsp;then&nbsp; &nbsp;&nbsp;echo&nbsp;"[-] Cleaning old output directory..."&nbsp; &nbsp;&nbsp;rm&nbsp;-rf&nbsp;"$OUTPUT_DIR"fi
# 执行 Jadx (针对 AI 优化的参数 + 强制 CLI 模式)# -cp "$JADX_JAR" jadx.cli.JadxCLI : 强制调用 CLI 主类,避免启动 GUIjava -Xmx4g -cp&nbsp;"$JADX_JAR"&nbsp;jadx.cli.JadxCLI \&nbsp; &nbsp; -d&nbsp;"$OUTPUT_DIR"&nbsp;\&nbsp; &nbsp; --show-bad-code \&nbsp; &nbsp; --deobf \&nbsp; &nbsp; --threads-count 4 \&nbsp; &nbsp; --no-imports \&nbsp; &nbsp; --comments-level none \&nbsp; &nbsp;&nbsp;"$APK_PATH"
# 检查返回值if&nbsp;[ $? -eq 0 ];&nbsp;then&nbsp; &nbsp;&nbsp;echo&nbsp;"[+] Decompilation Successful! Output:&nbsp;$OUTPUT_DIR"
&nbsp; &nbsp;&nbsp;# 验证目录结构,方便后续脚本定位 source_root&nbsp; &nbsp;&nbsp;if&nbsp;[ -d&nbsp;"$OUTPUT_DIR/sources"&nbsp;];&nbsp;then&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"[+] Source Root located at:&nbsp;$OUTPUT_DIR/sources"&nbsp; &nbsp;&nbsp;else&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 某些旧版 jadx 可能会直接输出在根目录,做个兼容提示&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"[!] Warning: 'sources' subdirectory not found. Check structure."&nbsp; &nbsp;&nbsp;fielse&nbsp; &nbsp;&nbsp;echo&nbsp;"[!] Decompilation With Errors."&nbsp; &nbsp;&nbsp;exit&nbsp;1fi

这个脚本 decompile.sh 是自动化安全审计流程中的第一步,其核心作用是将 APK 文件还原为可读的 Java 源代码

以下是它的主要功能描述:

1. 强制命令行模式 (Headless Automation)

  • 功能: 通过 -cp "$JADX_JAR" jadx.cli.JadxCLI 显式调用 Jadx 的命令行接口类。
  • 目的: 防止在服务器、Docker 或没有图形界面的环境中误启动 Jadx 的 GUI 窗口,确保脚本能静默运行。

2. 环境清理与初始化 (Clean Setup)

  • 功能: 运行前检查输入参数,并执行 rm -rf "$OUTPUT_DIR"
  • 目的: 确保每次反编译都是“干净”的,防止旧的扫描结果(残留文件)干扰本次分析,避免误报。

3. 针对“机器阅读”优化的反编译配置

脚本使用了一组特定的参数,生成的代码是给 Grep 或 AI 看的,而不是给人看的:

  • --show-bad-code保留反编译失败的代码。对于安全审计来说,即使代码反编译不完整(比如只有字节码结构),也可能包含关键的字符串或逻辑,不能直接丢弃。
  • --deobf自动反混淆。尝试给混淆过的变量(如 a.b.c)重命名为有意义的名字,便于后续分析。
  • --no-imports移除 import 语句。对于正则扫描和 AI 分析,import 语句通常是噪音,去掉可以减少文件体积和上下文干扰。
  • --comments-level none移除注释。去掉了 Jadx 生成的自动注释(如“// from class: …”),让代码更纯净,减少 Token 消耗。

4. 性能保障

  • java -Xmx4g: 分配 4GB 内存,防止反编译大型 APK(如 100MB+ 的应用)时发生 OOM(内存溢出)崩溃。
  • --threads-count 4: 启用 4 线程并行处理,加快反编译速度。

5. 输出结构验证

  • 功能: 反编译结束后,自动检查 $OUTPUT_DIR/sources 目录是否存在。
  • 目的: 为下一步(Python 脚本分析)做检查。如果目录结构不对,提前报错,避免后续脚本因为找不到路径而瞎跑。

quick_scan.sh

代码内容如下:

#!/bin/bash
SOURCE_DIR=$1OUTPUT_CSV="../files/scan_candidates.csv"&nbsp;# 中间文件TEMP_DIR=$(mktemp&nbsp;-d)
if&nbsp;[ -z&nbsp;"$SOURCE_DIR"&nbsp;];&nbsp;then&nbsp; &nbsp;&nbsp;echo&nbsp;"Usage:&nbsp;$0&nbsp;<source_dir>"&nbsp; &nbsp;&nbsp;exit&nbsp;1fi
# 初始化 CSV 头echo&nbsp;"type,filepath,linenum,content"&nbsp;>&nbsp;"$OUTPUT_CSV"
echo&nbsp;"=== Android Security Quick Scan (Parallel Mode) ==="echo&nbsp;"Target:&nbsp;$SOURCE_DIR"
# 定义辅助函数:提取信息并写入 CSV# 参数: $1=漏洞类型, $2=输入文件process_results() {&nbsp; &nbsp;&nbsp;local&nbsp;v_type=$1&nbsp; &nbsp;&nbsp;local&nbsp;input_file=$2
&nbsp; &nbsp;&nbsp;# 逐行读取 grep 结果 (格式: file:line:content)&nbsp; &nbsp;&nbsp;# 使用 awk 处理冒号分隔,注意文件路径可能包含冒号的情况需要小心处理,&nbsp; &nbsp;&nbsp;# 这里假设 standard grep output format: path:line:content&nbsp; &nbsp;&nbsp;while&nbsp;read&nbsp;-r line;&nbsp;do&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 提取文件路径 (第一个冒号前)&nbsp; &nbsp; &nbsp; &nbsp; filepath=$(echo&nbsp;"$line"&nbsp;|&nbsp;cut&nbsp;-d: -f1)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 提取行号 (第二个冒号前)&nbsp; &nbsp; &nbsp; &nbsp; linenum=$(echo&nbsp;"$line"&nbsp;|&nbsp;cut&nbsp;-d: -f2)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 提取内容 (剩余部分),移除可能的逗号以防破坏 CSV&nbsp; &nbsp; &nbsp; &nbsp; content=$(echo&nbsp;"$line"&nbsp;|&nbsp;cut&nbsp;-d: -f3- |&nbsp;tr&nbsp;-d&nbsp;',')
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"$v_type,$filepath,$linenum,$content"&nbsp;>>&nbsp;"$OUTPUT_CSV"&nbsp; &nbsp;&nbsp;done&nbsp;<&nbsp;"$input_file"}
scan_sql() {&nbsp; &nbsp;&nbsp;# 增加过滤条件,减少误报&nbsp; &nbsp; grep -rnE&nbsp;"rawQuery|execSQL"&nbsp;"$SOURCE_DIR"&nbsp;| grep&nbsp;"+"&nbsp;|&nbsp;head&nbsp;-n 20 >&nbsp;"$TEMP_DIR/sql.raw"&nbsp; &nbsp; process_results&nbsp;"SQL_INJECTION"&nbsp;"$TEMP_DIR/sql.raw"}
scan_secrets() {&nbsp; &nbsp;&nbsp;# 排除 BuildConfig 和 R.java&nbsp; &nbsp; grep -rnEi&nbsp;"api_key|access_token|secret_key|password ="&nbsp;"$SOURCE_DIR"&nbsp;| grep -vE&nbsp;"BuildConfig.java|R.java"&nbsp;|&nbsp;head&nbsp;-n 20 >&nbsp;"$TEMP_DIR/secrets.raw"&nbsp; &nbsp; process_results&nbsp;"HARDCODED_SECRET"&nbsp;"$TEMP_DIR/secrets.raw"}
scan_webview() {&nbsp; &nbsp; grep -rn&nbsp;"setJavaScriptEnabled"&nbsp;"$SOURCE_DIR"&nbsp;|&nbsp;head&nbsp;-n 20 >&nbsp;"$TEMP_DIR/webview.raw"&nbsp; &nbsp; process_results&nbsp;"WEBVIEW_RISK"&nbsp;"$TEMP_DIR/webview.raw"}
scan_cmd_injection() {&nbsp; &nbsp;&nbsp;# 扫描 Runtime.exec 或 ProcessBuilder&nbsp; &nbsp; grep -rnE&nbsp;"Runtime\.getRuntime\(\)\.exec|ProcessBuilder"&nbsp;"$SOURCE_DIR"&nbsp;|&nbsp;head&nbsp;-n 20 >&nbsp;"$TEMP_DIR/cmd.raw"&nbsp; &nbsp; process_results&nbsp;"CMD_INJECTION"&nbsp;"$TEMP_DIR/cmd.raw"}
scan_path_traversal() {&nbsp; &nbsp;&nbsp;# 简单的文件操作扫描 (注意:这可能会有很多误报,需要 FlowDroid 过滤)&nbsp; &nbsp; grep -rnE&nbsp;"new File\(|FileInputStream"&nbsp;"$SOURCE_DIR"&nbsp;| grep&nbsp;"+"&nbsp;|&nbsp;head&nbsp;-n 20 >&nbsp;"$TEMP_DIR/file.raw"&nbsp; &nbsp; process_results&nbsp;"PATH_TRAVERSAL"&nbsp;"$TEMP_DIR/file.raw"}
# 并发执行scan_sql & PID1=$!scan_secrets & PID2=$!scan_webview & PID3=$!scan_cmd_injection & PID5=$!scan_path_traversal & PID6=$!
wait&nbsp;$PID1&nbsp;$PID2&nbsp;$PID3
echo&nbsp;"=== Scan Finished ==="echo&nbsp;"candidates saved to:&nbsp;$OUTPUT_CSV"# 同时也打印给人看cat&nbsp;"$OUTPUT_CSV"&nbsp;| column -t -s,
rm&nbsp;-rf&nbsp;"$TEMP_DIR"

这个脚本 是自动化安全审计流程中的第二步,接在反编译之后执行。

它的核心作用是利用正则表达式(Regex)进行快速、粗粒度的“海选”,从海量的源代码中定位出所有“疑似”漏洞的代码行,并生成结构化的 CSV 清单,供后续的深度分析工具 FlowDroid 使用。

以下是它的主要功能描述:

1. 并行化正则扫描 (Parallel Grep Scanning)

  • 功能: 同时启动多个后台进程 (&) 分别扫描不同类型的漏洞(SQL注入、硬编码密钥、WebView 风险等)。
  • 目的: 充分利用多核 CPU,极大缩短扫描时间。相比于串行执行 grep,这种方式在处理大型项目时效率倍增。

2. 多维度漏洞模式匹配 (Pattern Matching)

脚本内置了针对 Android 常见高危漏洞的检测规则:

  • SQL 注入 (SQL_INJECTION): 查找 rawQuery 或 execSQL,并尝试通过 grep "+" 筛选存在字符串拼接的代码行(拼接才是注入的根源)。
  • 硬编码密钥 (HARDCODED_SECRET): 查找 api_keyaccess_token 等敏感关键词,同时智能排除BuildConfig.java 和 R.java 等自动生成的干扰文件。
  • 命令注入 (CMD_INJECTION): 监测 Runtime.exec 和 ProcessBuilder,这是执行系统命令的高危入口。
  • WebView 风险 (WEBVIEW_RISK): 检查 setJavaScriptEnabled,这是开启 XSS 攻击面的常见配置。
  • 路径遍历 (PATH_TRAVERSAL): 寻找 new File 或 FileInputStream 并伴随字符串拼接的操作。

3. 数据清洗与结构化输出 (ETL)

  • 功能:

    定义了 process_results函数,将 grep 原始的输出(文件:行号:内容)解析并转换为标准的 CSV 格式:

  • type: 漏洞类别(如 SQL_INJECTION)

  • filepath: 文件路径

  • linenum: 代码行号

  • content: 代码片段(并移除了可能破坏 CSV 结构的逗号)

  • 目的: 将非结构化的文本日志转换为机器可读的 CSV 数据集,作为 Python 分析脚本的标准输入接口。

4. 噪音控制 (Noise Reduction)

  • 功能: 在每个 grep 管道末尾使用了 head -n 20
  • 目的: 限制每个漏洞类型的最大候选数量。这是一种启发式策略:防止某个常见的工具类(如 LogUtil)导致产生成千上万条低质量结果,从而堵塞后续的 FlowDroid 分析队列。

5. 临时环境管理

  • 功能: 使用 mktemp -d 创建隔离的临时目录存放中间结果,脚本结束时自动 rm -rf 清理。
  • 目的: 保证文件系统整洁,避免并发运行时的文件冲突。

analyze_candidates.py

代码内容如下:

#!/usr/bin/env python3import&nbsp;csvimport&nbsp;sysimport&nbsp;osimport&nbsp;jsonimport&nbsp;subprocessimport&nbsp;xml.etree.ElementTree&nbsp;as&nbsp;ET
# === 路径自动配置 ===# 获取当前脚本所在的目录 (例如 .../scripts)SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))# 获取项目根目录 (例如 .../app-security-automation)BASE_DIR = os.path.dirname(SCRIPT_DIR)
# === 工具配置 ===# 使用 os.path.join 确保路径在任何系统下都正确# 假设你的目录结构是项目根目录下有 tools 文件夹FLOWDROID_JAR = os.path.join(BASE_DIR,&nbsp;"tools",&nbsp;"soot-infoflow-cmd-jar-with-dependencies.jar")ANDROID_PLATFORMS = os.path.join(BASE_DIR,&nbsp;"tools",&nbsp;"android.jar")&nbsp;SOURCES_SINKS_FILE = os.path.join(BASE_DIR,&nbsp;"tools",&nbsp;"SourcesAndSinks.txt")
# 定义哪些漏洞类型需要启动 FlowDroid (污点分析)TAINT_ANALYSIS_TARGETS = [&nbsp; &nbsp;&nbsp;"SQL_INJECTION", &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;"CMD_INJECTION", &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;"PATH_TRAVERSAL", &nbsp;&nbsp; &nbsp;&nbsp;"WEBVIEW_LOAD_URL"&nbsp;]
def&nbsp;get_class_name(filepath, source_root):&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; 将文件路径转换为 Java 类名&nbsp; &nbsp; """&nbsp; &nbsp; source_root = os.path.abspath(source_root)&nbsp; &nbsp; filepath = os.path.abspath(filepath)
&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 计算相对路径&nbsp; &nbsp; &nbsp; &nbsp; rel_path = os.path.relpath(filepath, source_root)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;rel_path.endswith(".java"):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rel_path = rel_path[:-5]&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 替换分隔符为点&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;rel_path.replace(os.sep,&nbsp;".")&nbsp; &nbsp;&nbsp;except&nbsp;ValueError:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 兜底:如果文件不在 source_root 下,直接用文件名&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;os.path.basename(filepath).replace(".java",&nbsp;"")
def&nbsp;parse_flowdroid_xml(xml_file):&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; 解析 FlowDroid 生成的 XML 报告&nbsp; &nbsp; """&nbsp; &nbsp; results = []&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; tree = ET.parse(xml_file)&nbsp; &nbsp; &nbsp; &nbsp; root = tree.getroot()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;result&nbsp;in&nbsp;root.findall(".//Result"):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source = result.find("Source")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sink = result.find("Sink")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;source&nbsp;is&nbsp;not&nbsp;None&nbsp;and&nbsp;sink&nbsp;is&nbsp;not&nbsp;None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; results.append({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"source": source.get("Statement"),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"sink": sink.get("Statement")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[!] XML Parse Error:&nbsp;{e}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;[]&nbsp; &nbsp;&nbsp;return&nbsp;results
def&nbsp;run_flowdroid(apk_path, class_name):&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; 调用 Java 运行 FlowDroid&nbsp; &nbsp; """&nbsp; &nbsp;&nbsp;# 生成临时的 xml 结果文件名&nbsp; &nbsp; output_xml =&nbsp;f"flow_results_{class_name.split('.')[-1]}.xml"
&nbsp; &nbsp;&nbsp;# 构造命令&nbsp; &nbsp; cmd = [&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"java",&nbsp;"-jar", FLOWDROID_JAR,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"-a", apk_path,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"-p", ANDROID_PLATFORMS,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"-s", SOURCES_SINKS_FILE,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"--output", output_xml,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"--outputformat",&nbsp;"xml",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"--taintanalysis",&nbsp;"apcontext",&nbsp;# 上下文敏感分析&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"--no-callback-analyzers"&nbsp; &nbsp; &nbsp; &nbsp;# 禁用回调分析以加速&nbsp; &nbsp; ]
&nbsp; &nbsp;&nbsp;print(f"[*] Executing FlowDroid for class:&nbsp;{class_name}&nbsp;...")&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 设置超时时间为 300秒 (5分钟)&nbsp; &nbsp; &nbsp; &nbsp; subprocess.run(cmd, timeout=300, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;os.path.exists(output_xml):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; findings = parse_flowdroid_xml(output_xml)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; os.remove(output_xml)&nbsp;# 清理临时文件&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;findings&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;None&nbsp; &nbsp;&nbsp;except&nbsp;subprocess.TimeoutExpired:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[!] FlowDroid timed out for&nbsp;{class_name}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;None&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[!] FlowDroid failed:&nbsp;{e}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;None
def&nbsp;main():&nbsp; &nbsp;&nbsp;if&nbsp;len(sys.argv) <&nbsp;4:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("Usage: python3 analyze_candidates.py <apk_path> <csv_file> <source_dump_dir>")&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(1)
&nbsp; &nbsp; apk_path = sys.argv[1]&nbsp; &nbsp; csv_file = sys.argv[2]&nbsp; &nbsp; source_root = sys.argv[3]
&nbsp; &nbsp;&nbsp;# 输出文件路径&nbsp; &nbsp; output_json = os.path.join(BASE_DIR,&nbsp;"files",&nbsp;"final_audit_report.json")
&nbsp; &nbsp;&nbsp;# 确保输出目录存在&nbsp; &nbsp; os.makedirs(os.path.dirname(output_json), exist_ok=True)
&nbsp; &nbsp;&nbsp;# 检查工具是否存在&nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;os.path.exists(FLOWDROID_JAR):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[Error] FlowDroid jar not found at:&nbsp;{FLOWDROID_JAR}")&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(1)&nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;os.path.exists(ANDROID_PLATFORMS):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[Error] Android Platforms not found at:&nbsp;{ANDROID_PLATFORMS}")&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(1)
&nbsp; &nbsp; final_report = []
&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 读取 CSV&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;with&nbsp;open(csv_file,&nbsp;'r', encoding='utf-8', errors='ignore')&nbsp;as&nbsp;f:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reader = csv.DictReader(f)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;row&nbsp;in&nbsp;reader:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vuln_type = row.get('type',&nbsp;'UNKNOWN')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filepath = row.get('filepath',&nbsp;'')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; linenum = row.get('linenum',&nbsp;'0')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content = row.get('content',&nbsp;'')
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type": vuln_type,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"file": filepath,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"line": linenum,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"code_snippet": content,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"analysis_mode":&nbsp;"Static Pattern Match"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 核心逻辑:判断是否需要跑 FlowDroid&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;vuln_type&nbsp;in&nbsp;TAINT_ANALYSIS_TARGETS:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 只有当成功解析出类名时才跑&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; class_name = get_class_name(filepath, source_root)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;class_name&nbsp;and&nbsp;not&nbsp;class_name.endswith(".java"):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 执行分析&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flow_data = run_flowdroid(apk_path, class_name)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# === 这里是之前报错的地方,现在已修复 ===&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;flow_data&nbsp;and&nbsp;len(flow_data) >&nbsp;0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item["flow_analysis"] = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"reachable":&nbsp;True,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"evidence": flow_data&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item["severity"] =&nbsp;"HIGH (Verified Flow)"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item["analysis_mode"] =&nbsp;"FlowDroid Verified"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item["flow_analysis"] = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"reachable":&nbsp;False,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"note":&nbsp;"FlowDroid found no path"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item["severity"] =&nbsp;"MEDIUM (Unverified)"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item["note"] =&nbsp;"Skipped FlowDroid: Cannot determine class name"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item["flow_analysis"] =&nbsp;"N/A"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; report_item["severity"] =&nbsp;"Check Manually"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final_report.append(report_item)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 保存结果&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;with&nbsp;open(output_json,&nbsp;'w')&nbsp;as&nbsp;f:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json.dump(final_report, f, indent=2)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"\n[+] Analysis Complete! Report saved to:&nbsp;{output_json}")
&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[Error] Script failed:&nbsp;{e}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;import&nbsp;traceback&nbsp; &nbsp; &nbsp; &nbsp; traceback.print_exc()
if&nbsp;__name__ ==&nbsp;"__main__":&nbsp; &nbsp; main()

这个 Python 脚本 analyze_candidates.py 是自动化安全审计流程中的第三步(核心分析层),也是整个系统的“大脑”。

它的核心作用是接收正则扫描的“疑似名单”,通过智能调度策略,有选择性地启动 FlowDroid 进行深度的污点分析(Taint Analysis),最终生成确凿的审计报告

以下是它的主要功能描述:

1. 智能分析路由 (Smart Routing)

  • 功能: 读取 scan_candidates.csv 中的每一条记录,根据漏洞类型(vuln_type)决定处理方式。

  • 策略:

  • 污点敏感型 (Taint Sensitive): 对于 SQL 注入、命令注入、路径遍历等,必须验证数据流是否可控,因此触发 FlowDroid 分析

  • 配置/特征型 (Config/Pattern): 对于硬编码密钥、日志泄露等,正则匹配即为证据,跳过 FlowDroid,直接标记为待人工复核。

  • 目的: 极大地节省分析时间。FlowDroid 非常耗时,只在刀刃上使用它,避免对整个 APK 进行全量分析。

2. 自动化 FlowDroid 调度 (Orchestration)

  • 功能: 封装了 run_flowdroid 函数,通过 subprocess 调用 Java 命令行启动 Soot-Infoflow (FlowDroid)。

  • 参数优化:

  • --taintanalysis apcontext: 启用上下文敏感分析,提高准确率。

  • --no-callback-analyzers: 禁用回调分析以加速运行(一种性能折中)。

  • timeout=300: 设置 5 分钟超时机制,防止某个复杂的类导致分析卡死。

  • 动态类名解析: 通过 get_class_name 函数,将文件路径(如 com/example/MyClass.java)自动转换为 Java 类名(com.example.MyClass),这是 FlowDroid 识别目标的必要参数。

3. 结果验证与分级 (Verification & Triage)

  • 功能: 解析 FlowDroid 生成的 XML 报告 (parse_flowdroid_xml)。

  • 逻辑:

  • High (Verified Flow): 如果 FlowDroid 找到了从 Source(输入)到 Sink(危险函数)的完整路径,脚本将该漏洞标记为高危且实锤,并附上证据。

  • Medium (Unverified): 如果正则扫描到了危险代码,但 FlowDroid 没跑通(可能是逻辑太复杂或无路径),标记为中危,提示需人工复核。

  • Check Manually: 对于不需要跑 FlowDroid 的类型,标记为需人工检查

4. 报告生成 (Reporting)

  • 功能: 将所有分析结果汇总是,生成标准化的 JSON 报告 (final_audit_report.json)。
  • 内容: 包含漏洞类型、文件位置、源代码片段、以及 FlowDroid 的验证结果(Reachable/Unreachable)。
  • 目的: JSON 格式方便后续对接前端展示、甚至直接喂给 LLM(如 Claude/GPT)让其生成自然语言的修复建议。

5. 环境自适应 (Portability)

  • 功能: 使用 os.path.abspath 和 os.path.dirname 自动计算项目根目录。
  • 目的: 无论脚本在哪里运行,都能准确找到 tools/android.jar 和 SourcesAndSinks.txt,无需用户手动硬编码路径,增强了脚本的健壮性。

五、CLAUDE.md

在项目根目录下创建 CLAUDE.md,这告诉 Claude Code 如何调用你的脚本。

# Claude Code Project Configuration
## Project Description
这是一个 Android 自动化安全审计系统。它结合了 grep 正则扫描(快速)和 FlowDroid 污点分析(深度验证)。核心逻辑在&nbsp;`SKILL.md`&nbsp;中有详细描述。
## Commands
-&nbsp;**Quick Scan**:&nbsp;`bash scripts/quick_scan.sh targetapks/<apk_name>`&nbsp; - 作用: 反编译 APK 并生成初步的&nbsp;`files/scan_candidates.csv`。-&nbsp;**Deep Analysis**:&nbsp;`python3 scripts/analyze_candidates.py targetapks/<apk_name> files/scan_candidates.csv source_dump/sources`&nbsp; - 作用: 读取 CSV,对高危漏洞(如 SQL注入)运行 FlowDroid,生成 JSON 报告。-&nbsp;**Full Audit**: 依次运行 Quick Scan 和 Deep Analysis。
## Project Structure
-&nbsp;`scripts/`: 包含 Python 和 Bash 自动化脚本。-&nbsp;`tools/`: 包含 FlowDroid jar 包 (`soot-infoflow...jar`) 和&nbsp;`android.jar`。-&nbsp;`files/`: 存放扫描结果。-&nbsp;`targetapks/`: 存放待扫描的 .apk 文件。
## Coding Style
-&nbsp;Python: Follow PEP 8. Use&nbsp;`os.path.join`&nbsp;for paths.-&nbsp;Bash: Use standard bash syntax.
## Analysis Workflow (Important)
当你被要求审计一个 APK 时:
1.&nbsp;请先阅读&nbsp;`SKILL.md`&nbsp;了解判断逻辑。2.&nbsp;检查&nbsp;`scripts/`&nbsp;和&nbsp;`tools/`&nbsp;是否存在。3.&nbsp;按照 Commands 中的顺序执行工具。4.&nbsp;如果脚本执行失败,请检查路径是否正确,并尝试修复路径问题。5.&nbsp;最后根据&nbsp;`files/final_audit_report.json`&nbsp;的内容生成审计报告

六、SKILL.md

# 基本信息
-&nbsp;name: app-security-scan-automation-&nbsp;description: 一个专注于 Android 静态应用安全测试 (SAST) 的智能体。通过编排静态分析工具(Semgrep/Soot)与 LLM 语义分析能力,自动检测代码漏洞,并利用逻辑推理大幅降低误报率。
# 能力与工具链
你拥有对以下本地工具链的调用权限和操作知识:
## 快速扫描工具 (`quick_scan.sh`)
-&nbsp;**功能**: 自动反编译 APK 并使用 `grep` 进行正则匹配。-&nbsp;**输入**: APK 文件路径。- 输出:&nbsp; - `source_dump/`: Java 源码目录。&nbsp; -&nbsp;`files/scan_candidates.csv`: 包含疑似漏洞的文件名、行号和代码片段的清单。-&nbsp;**适用场景**: 初始扫描,发现 SQL 注入、硬编码密钥、Webview 配置、命令执行等所有疑似点。
## 深度分析引擎 (`analyze_candidates.py`)
-&nbsp;**功能**: 读取 CSV 候选列表,根据漏洞类型决定是否启动 FlowDroid 污点分析。- 核心逻辑:&nbsp; -&nbsp;**污点分析 (Taint Analysis)**: 针对 `SQL_INJECTION`, `CMD_INJECTION`, `PATH_TRAVERSAL`, `WEBVIEW_LOAD_URL`。如果 FlowDroid 发现从 Source 到 Sink 的路径,标记为 `HIGH (Verified Flow)`。&nbsp; -&nbsp;**静态确认 (Static Check)**: 针对&nbsp;`HARDCODED_SECRET`,&nbsp;`LOGGING`,&nbsp;`WEAK_CRYPTO`。直接标记为人工复核。-&nbsp;**依赖**:&nbsp;`tools/android.jar`&nbsp;(便携式 SDK),&nbsp;`tools/soot-infoflow-cmd-jar-with-dependencies.jar`.-&nbsp;**输出**:&nbsp;`files/final_audit_report.json`。
# 操作标准作业程序 (SOP)
## 1、阶段一:反编译与初步扫描
1.&nbsp;接收用户提供的 APK 路径(例如&nbsp;`../targetapks/test.apk`)。
2.&nbsp;执行 Shell 命令:
&nbsp; &nbsp;```bash&nbsp; &nbsp;cd scripts&nbsp; &nbsp;./quick_scan.sh <apk_path>&nbsp; &nbsp;```
3.&nbsp;检查&nbsp;`files/scan_candidates.csv`&nbsp;是否生成。如果不为空,进入下一阶段。
## 2、阶段二:智能路由与深度验证
1.&nbsp;调用 Python 脚本进行验证。**注意**: 必须正确指定源码目录(通常是&nbsp;`source_dump/sources`&nbsp;以便正确解析包名)。
2.&nbsp;执行命令:
&nbsp; &nbsp;```bash&nbsp; &nbsp;python3 analyze_candidates.py <apk_path> ../files/scan_candidates.csv ../source_dump/sources&nbsp; &nbsp;```
3.&nbsp;等待脚本运行完成(FlowDroid 可能需要数分钟)。
## 3、阶段三:报告生成与解读
1.&nbsp;读取&nbsp;`files/final_audit_report.json`。
2.&nbsp;按照严重程度排序
&nbsp; &nbsp;输出报告:
&nbsp; &nbsp;- 🔴&nbsp;**HIGH (Verified Flow)**: 必须优先展示。这是 FlowDroid 实锤的漏洞,存在完整的利用链。请展示&nbsp;`Source`&nbsp;(输入点) 和&nbsp;`Sink`&nbsp;(触发点)。&nbsp; &nbsp;- 🟠&nbsp;**MEDIUM (Unverified)**: 可能是漏洞,但 FlowDroid 未找到路径(可能是逻辑复杂或误报)。建议人工审计。&nbsp; &nbsp;- 🟡&nbsp;**Low/Info**: 硬编码密钥、日志泄露等配置问题。
## 4、决策逻辑 (Decision Logic)
Agent 在分析过程中必须遵守以下决策树,以节省计算资源:
| 漏洞类型 (Vuln Type) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| 处理方式 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 理由 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|| :------------------------------------------ | :------------------- | :---------------------------------- ||&nbsp;**SQL Injection**&nbsp;(`rawQuery`,&nbsp;`execSQL`) &nbsp; | ✅&nbsp;**Run FlowDroid**&nbsp; | 只有当参数来自用户输入时才危险。 &nbsp; &nbsp;||&nbsp;**Cmd Injection**&nbsp;(`Runtime.exec`) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| ✅&nbsp;**Run FlowDroid**&nbsp; | 极高风险,必须确认参数是否可控。 &nbsp; &nbsp;||&nbsp;**Path Traversal**&nbsp;(`new File`) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | ✅&nbsp;**Run FlowDroid**&nbsp; | 过滤掉正常的内部文件操作。 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;||&nbsp;**Hardcoded Secrets**&nbsp;(`"api_key"`) &nbsp; &nbsp; &nbsp; &nbsp; | 🚫&nbsp;**Skip FlowDroid**&nbsp;| 字符串存在即漏洞,无需分析流向。 &nbsp; &nbsp;||&nbsp;**WebView Config**&nbsp;(`setJavaScriptEnabled`) | 🚫&nbsp;**Skip FlowDroid**&nbsp;| 这是状态配置,不是数据流问题。 &nbsp; &nbsp; &nbsp;||&nbsp;**Logging**&nbsp;(`Log.d`) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 🚫&nbsp;**Skip FlowDroid**&nbsp;| 数量巨大,跑 FlowDroid 会导致超时。 |
## 5、错误处理 (Error Handling)
-&nbsp;**Jadx 失败**: 如果反编译目录为空,提示用户 APK 可能损坏或加固。-&nbsp;**FlowDroid 超时**: 脚本设定了 300秒 超时。如果日志显示&nbsp;`FlowDroid timed out`,在报告中标记为 "Complexity High - Manual Review Required"。-&nbsp;**找不到类名**: 如果&nbsp;`get_class_name`&nbsp;失败,脚本会跳过 FlowDroid。在报告中注明 "Skipped dynamic analysis due to obfuscation"。
## 6、报告生成
-&nbsp;汇总为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,输入提示词,开始app安全审计。我这里随便从应用市场下载了一个30MB的apk

执行完成后:

生成报告展示:

八、待更新

1、AndroidManifest.xml暴露组件结合反编译代码确认权限分析流程

2、新增漏洞规则

3、扫描逻辑优化,进一步去除误报

九、总结

这只是一个MVP版本,我后续会持续更新,欢迎大家跟我一起讨论。

十、广子

欢迎大家关注我的github,脚本代码以及md文档都在项目中:

https://github.com/DSFLY100/Skill-Android-Security-Agent


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:sec0nd安全 《构建基于 SKILL 的 Android 智能审计 Agent(完整版)》

AutoSAR之WdgM 网络安全文章

AutoSAR之WdgM

文章总结: 文档解析AUTOSAR看门狗管理器WdgM在现代ECU中的作用,重点阐述其通过监督软件执行时序确保不同ASIL等级组件免受干扰的机制。文中介绍了Wd
评论:0   参与:  0