Apktool 是一个用于逆向工程 Android APK 文件的工具。它可以将资源解码到接近原始形式,并在修改后重新构建它们。它对于以下方面至关重要:
- 提取可读的 AndroidManifest.xml
- 解码资源(XML 布局、字符串、图片)
- 将 DEX 反编译为 smali 代码
- 分析应用程序结构和权限
- 重新打包修改后的 APK
先决条件
- apktool 必须安装在系统上
- 需要 Java 运行时环境 (JRE)
- 足够的磁盘空间(解包后的 APK 通常是原始大小的 2-5 倍)
- 输出目录的写权限
指令
1. 基本 APK 解包(最常见)
当用户要求解包、解码或分析 APK 时:
标准解码命令:
apktool d <apk-file> -o <output-directory>
示例:
apktool d app.apk -o app-unpacked
如果目录存在,则强制覆盖:
apktool d app.apk -o app-unpacked -f
2. 理解输出结构
解包后,输出目录包含:
app-unpacked/
├── AndroidManifest.xml # 可读的清单文件(权限、组件)
├── apktool.yml # Apktool 元数据(版本信息、SDK 级别)
├── original/ # 原始的 META-INF 证书
│ └── META-INF/
├── res/ # 解码的资源
│ ├── layout/ # XML 布局
│ ├── values/ # 字符串、颜色、尺寸
│ ├── drawable/ # 图片和 Drawable
│ └── ...
├── smali/ # 反编译的 DEX 代码(smali 格式)
│ └── com/company/app/ # 包结构
├── assets/ # 应用程序资产(如果存在)
├── lib/ # 本地库(如果存在)
│ ├── arm64-v8a/
│ ├── armeabi-v7a/
│ └── ...
└── unknown/ # Apktool 无法分类的文件
3. 选择性解码(性能优化)
跳过资源(仅代码分析):
apktool d app.apk -o app-code-only -r
# 或
apktool d app.apk -o app-code-only --no-res
- 更快的处理速度
- 仅提取 smali 代码和清单
- 当你只需要分析代码逻辑时使用
跳过源代码(仅资源分析):
apktool d app.apk -o app-resources-only -s
# 或
apktool d app.apk -o app-resources-only --no-src
- 更快的处理速度
- 仅提取资源和清单
- 当你只需要资源、字符串、布局时使用
4. 常见分析任务
A. 检查 AndroidManifest.xml
清单文件揭示了关键的安全信息:
# 解包后
cat app-unpacked/AndroidManifest.xml
查找:
- 权限:应用程序访问的设备功能/数据
- 导出组件:其他应用程序可以访问的活动、服务、接收器
- 意图过滤器:应用程序如何响应系统/应用程序意图
- 备份设置:
android:allowBackup="true"(安全风险) - 可调试标志:
android:debuggable="true"(主要安全问题) - 网络安全配置:自定义证书固定、明文流量
- 最小/目标 SDK 版本:过时版本可能存在漏洞
示例分析命令:
# 查找所有权限
grep "uses-permission" app-unpacked/AndroidManifest.xml
# 查找导出组件
grep "exported=\"true\"" app-unpacked/AndroidManifest.xml
# 检查是否可调试
grep "debuggable" app-unpacked/AndroidManifest.xml
# 查找所有活动
grep "android:name.*Activity" app-unpacked/AndroidManifest.xml
B. 提取字符串和资源
# 查看所有字符串资源
cat app-unpacked/res/values/strings.xml
# 搜索 API 密钥、URL、凭证
grep -r "api" app-unpacked/res/values/
grep -r "http" app-unpacked/res/values/
grep -r "password\|secret\|key\|token" app-unpacked/res/values/
# 查找资源中的硬编码 URL
grep -rE "https?://" app-unpacked/res/
C. 分析 Smali 代码
Smali 是反编译的 Dalvik 字节码格式:
# 查找特定类
find app-unpacked/smali -name "*Login*.smali"
find app-unpacked/smali -name "*Auth*.smali"
# 搜索与安全相关的代码
grep -r "crypto\|encrypt\|decrypt" app-unpacked/smali/
grep -r "http\|https\|url" app-unpacked/smali/
grep -r "password\|credential\|token" app-unpacked/smali/
# 查找本地库使用情况
grep -r "System.loadLibrary" app-unpacked/smali/
# 查找文件操作
grep -r "openFileOutput\|openFileInput" app-unpacked/smali/
注意:Smali 比 Java 源代码更难阅读。考虑使用 jadx 进行 Java 反编译,以便更容易分析。
D. 检查本地库
# 列出本地库
ls -lah app-unpacked/lib/
# 检查支持的架构
ls app-unpacked/lib/
# 识别库类型
file app-unpacked/lib/arm64-v8a/*.so
# 在库中搜索有趣的字符串
strings app-unpacked/lib/arm64-v8a/libnative.so | grep -i "http\|key\|password"
5. 重新打包 APK(构建)
修改资源或 smali 代码后:
apktool b app-unpacked -o app-modified.apk
重要:重新构建的 APK 必须在安装前签名:
# 生成密钥库(一次性设置)
keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-key-alias
# 签名 APK
jarsigner -verbose -keystore my-release-key.jks app-modified.apk my-key-alias
# 验证签名
jarsigner -verify app-modified.apk
# Zipalign(优化)
zipalign -v 4 app-modified.apk app-modified-aligned.apk
6. 框架管理
对于系统应用程序或依赖于设备制造商框架的应用程序:
# 安装框架
apktool if framework-res.apk
# 列出已安装框架
apktool list-frameworks
# 使用特定框架解码
apktool d -t <tag> app.apk
常见工作流
工作流 1: 安全分析
# 1. 解包 APK
apktool d target.apk -o target-unpacked
# 2. 检查清单文件中的安全问题
cat target-unpacked/AndroidManifest.xml
# 3. 搜索硬编码凭证
grep -r "password\|api_key\|secret\|token" target-unpacked/res/
# 4. 检查可调试标志
grep "debuggable" target-unpacked/AndroidManifest.xml
# 5. 查找导出组件
grep "exported=\"true\"" target-unpacked/AndroidManifest.xml
# 6. 检查网络安全配置
cat target-unpacked/res/xml/network_security_config.xml 2>/dev/null
工作流 2: IoT 应用分析
对于 IoT 伴侣应用程序,查找设备通信详细信息:
# 1. 解包 APK
apktool d iot-app.apk -o iot-app-unpacked
# 2. 搜索设备端点
grep -rE "https?://[^\"']+" iot-app-unpacked/res/ | grep -v "google\|android"
# 3. 查找 API 密钥
grep -r "api\|key" iot-app-unpacked/res/values/strings.xml
# 4. 定位设备通信代码
find iot-app-unpacked/smali -name "*Device*.smali"
find iot-app-unpacked/smali -name "*Network*.smali"
find iot-app-unpacked/smali -name "*Api*.smali"
# 5. 检查证书固定
grep -r "certificatePinner\|TrustManager" iot-app-unpacked/smali/
工作流 3: 仅资源提取
# 快速资源提取
apktool d app.apk -o app-resources -s
# 提取应用程序图标
cp app-resources/res/mipmap-xxxhdpi/ic_launcher.png ./
# 提取字符串以进行本地化
cat app-resources/res/values*/strings.xml
# 提取布局以进行 UI 分析
ls app-resources/res/layout/
工作流 4: 快速代码检查(无资源)
# 快速代码提取
apktool d app.apk -o app-code -r
# 快速分析 smali
grep -r "http" app-code/smali/ | head -20
grep -r "password" app-code/smali/
输出格式
Apktool 没有内置的输出格式选项,但你可以组织你的分析:
对于人类可读的报告:
# 生成分析报告
{
echo "=== APK 分析报告 ==="
echo "APK: app.apk"
echo "日期: $(date)"
echo ""
echo "=== 权限 ==="
grep "uses-permission" app-unpacked/AndroidManifest.xml
echo ""
echo "=== 导出组件 ==="
grep "exported=\"true\"" app-unpacked/AndroidManifest.xml
echo ""
echo "=== 包信息 ==="
grep "package=" app-unpacked/AndroidManifest.xml
} > apk-analysis-report.txt
与 IoTHackBot 工具集成
Apktool 与其他分析工作流程配合得很好:
-
APK → 网络分析:
- 从资源中提取 API 端点
- 使用提取的 URL 进行 curl/wget 测试
- 将端点输入到网络测试工具中
-
APK → 凭证发现:
- 在资源中找到硬编码的凭证
- 测试凭证对 IoT 设备的影响
- 与 onvifscan 或其他设备测试工具一起使用
-
APK → 代码分析:
- 使用 apktool 提取 smali 代码
- 使用 jadx 反编译为 Java 以便于阅读
- 在两个工具之间交叉引用发现
最佳实践
1. 始终先检查清单文件
apktool d app.apk -o app-unpacked
cat app-unpacked/AndroidManifest.xml | less
清单文件为进一步分析提供了路线图。
2. 使用选择性解码以提高速度
- 仅代码:
-r标志 - 仅资源:
-s标志 - 全部解码:无标志(默认)
3. 系统地搜索
# 创建分析脚本
cat > analyze.sh << 'EOF'
#!/bin/bash
APK_DIR="$1"
echo "[+] 搜索 URL..."
grep -rE "https?://" "$APK_DIR/res/" | grep -v "schema\|google\|android"
echo "[+] 搜索 API 密钥..."
grep -ri "api.*key\|apikey" "$APK_DIR/res/"
echo "[+] 搜索秘密..."
grep -ri "secret\|password\|credential" "$APK_DIR/res/"
EOF
chmod +x analyze.sh
./analyze.sh app-unpacked
4. 记录你的发现
记录以下内容:
- APK 包名和版本
- 有趣的权限
- 硬编码凭证/URL
- 导出组件
- 安全配置错误
5. 与 Jadx 结合使用
一起使用这两个工具:
- Apktool:用于资源、清单和详细的 smali
- Jadx:用于可读的 Java 源代码
故障排除
问题:“brut.directory.DirectoryException: Framework”
解决方案:安装框架资源:
apktool if <framework-res.apk>
问题:解码失败,资源错误
解决方案:使用 --keep-broken-res 标志:
apktool d app.apk -o output --keep-broken-res
问题:“输入文件未找到或不可读”
解决方案:检查文件路径和权限:
ls -l app.apk
file app.apk # 应显示 "Zip archive data"
问题:内存溢出错误
解决方案:增加 Java 堆大小:
export _JAVA_OPTIONS="-Xmx2048m"
apktool d large-app.apk
问题:修改后构建失败
解决方案:验证你的 smali/XML 语法:
# 检查语法错误
apktool b app-unpacked -o test.apk --use-aapt2
问题:重新打包后 APK 安装失败
解决方案:签名 APK:
jarsigner -verbose -keystore debug.keystore rebuilt.apk androiddebugkey
重要提示
- Apktool 需要 Java 运行时环境 (JRE)
- 解码后的 APK 通常比原始文件大 2-5 倍
- Smali 代码比 Java 源代码更冗长(使用 jadx 进行 Java)
- 始终在 APK 文件的副本上工作,而不是原件
- 重新打包需要在安装前签名
- 一些混淆的应用程序可能具有不可读的类/方法名称
- 系统应用程序可能需要框架安装
安全和道德
重要:只分析您拥有或有权分析的 APK 文件。
- 尊重知识产权和许可
- 遵循漏洞的责任披露
- 不要未经授权分发修改后的 APK
- 了解服务条款和 EULA
- 仅用于授权的安全测试和研究
示例分析会话
# 完整分析工作流程
TARGET="myapp.apk"
OUTPUT="myapp-analysis"
# 1. 解包
echo "[+] 解包 APK..."
apktool d "$TARGET" -o "$OUTPUT"
# 2. 基本信息
echo "[+] 包信息:"
grep "package=" "$OUTPUT/AndroidManifest.xml"
# 3. 权限
echo "[+] 权限:"
grep "uses-permission" "$OUTPUT/AndroidManifest.xml"
# 4. 导出组件
echo "[+] 导出组件:"
grep "exported=\"true\"" "$OUTPUT/AndroidManifest.xml"
# 5. 搜索秘密
echo "[+] 搜索硬编码的秘密..."
grep -r "api.*key\|password\|secret" "$OUTPUT/res/" | grep -v "^Binary"
# 6. 查找 URL
echo "[+] 查找 URL..."
grep -rE "https?://[^\"']+" "$OUTPUT/res/" | grep -v "schema\|xmlns"
# 7. 检查可调试
echo "[+] 调试状态:"
grep "debuggable" "$OUTPUT/AndroidManifest.xml" || echo "不可调试(好)"
# 8. 总结
echo "[+] 分析完成。输出在:$OUTPUT/"
成功标准
成功的 apktool 分析包括:
- APK 成功解码,无错误
- AndroidManifest.xml 可读且已分析
- 资源已提取且可搜索
- Smali 代码可供检查
- 记录了与安全相关的发现
- 输出组织在清晰的目录结构中
- 如有需要,任何修改都可以重新打包
快速参考
# 解码(解包)
apktool d <apk> -o <output-dir>
# 解码并强制覆盖
apktool d <apk> -o <output-dir> -f
# 解码不包含资源(更快)
apktool d <apk> -o <output-dir> -r
# 解码不包含源代码(更快)
apktool d <apk> -o <output-dir> -s
# 构建(重新打包)
apktool b <unpacked-dir> -o <output-apk>
# 安装框架
apktool if <framework.apk>
# 清空框架缓存
apktool empty-framework-dir