查询 25 次,耗时 0.2006 秒

从静态拆包到动态取证:Android 可疑 APK 的本地防御分析实战

黄先生嗯

New member

黄先生嗯 Rep
0
0
0
Rep
0
黄先生嗯 Vouches
Vouches
0
1 MONTH
1 1 MONTH OF SERVICE
黄先生嗯 获得
0
0
0
获得
0
黄先生嗯 凭证
0
0
0
凭证
0
主题
15
点赞
0
HakB
1 月
在社区成长 1 月
LEVEL 1 1 XP
 
一、背景与分析目标

移动端恶意样本往往不会直接暴露完整行为。常见情况包括:在 Application 初始化阶段加载加密 DEX、通过反射隐藏敏感 API、从资源文件释放原生库、检测模拟器与调试器、收集设备信息后访问远程接口等。仅依赖杀毒软件的检测结论,很难回答样本究竟获取了什么权限、数据从哪里产生、是否发生外传,以及风险代码位于哪个组件。

本文给出一套面向防御取证的 Android APK 分析流程:先固定样本证据并检查清单文件,再利用 JADX、Apktool 和原生工具进行静态定位,最后在隔离模拟器中观察文件、进程、网络和运行日志。全部操作应限定在自有应用、授权靶场或本地恶意样本实验环境中,不要将样本安装到日常手机,也不要连接真实生产账号。

二、基本原理与主要攻击面

APK 本质上是 ZIP 容器,通常包含 AndroidManifest.xml、classes.dex、resources.arsc、res、assets 和 lib 等内容。分析时需要同时关注以下层面:

1. 组件攻击面:导出的 Activity、Service、BroadcastReceiver 和 ContentProvider 是否缺少权限保护,是否能被外部 Intent 非预期调用。
2. 权限攻击面:短信、通讯录、录音、定位、通知读取、辅助功能、安装未知应用等权限是否与软件功能匹配。
3. 代码加载:是否使用 DexClassLoader、PathClassLoader、System.loadLibrary 或反射动态加载隐藏代码。
4. 数据安全:令牌、账号、设备标识和数据库是否明文存储,WebView 是否开放危险桥接接口。
5. 通信行为:是否使用明文 HTTP、忽略 TLS 证书校验、连接硬编码地址,或在后台周期性上传数据。
6. 对抗分析:是否检查 ro.kernel.qemu、常见模拟器文件、调试端口、TracerPid、Frida 特征或签名完整性。

静态分析适合快速覆盖代码和资源,但可能被混淆、加壳或动态加载干扰;动态分析能够确认真实运行路径,却容易受到环境检测和触发条件影响。因此,两者必须互相验证,不能因为反编译代码中出现敏感字符串,就直接断定恶意行为已经发生。

三、前置条件

建议准备一台专用分析主机,并安装以下工具:

- Android Studio Emulator 或其他可恢复快照的测试模拟器;
- Android SDK Platform Tools,主要使用 adb;
- JADX,用于查看 Java/Kotlin 伪代码;
- Apktool,用于解码资源与 Smali;
- apksigner、keytool、unzip、file、strings、sha256sum;
- mitmproxy 或 Burp Suite Community,用于观察本地实验流量;
- 可选的 MobSF,用于生成初步检查报告。

实验网络应与办公网、家庭设备和生产系统隔离。推荐禁用共享剪贴板、共享目录和 USB 直通,并通过虚拟机快照保存干净状态。若样本来源不明,可让模拟器仅访问本机代理,不提供直接互联网出口,避免其接收真实控制指令或继续扩散。

四、步骤一:固定样本并建立证据基线

不要直接双击或安装样本。先复制到只用于分析的目录,并计算摘要:

mkdir -p case01/{sample,static,dynamic}
cp suspicious.apk case01/sample/app.apk
sha256sum case01/sample/app.apk | tee case01/sample/SHA256.txt
file case01/sample/app.apk
unzip -t case01/sample/app.apk

SHA-256 是后续报告、复测和多人协作时识别样本的关键依据。除了哈希,还应记录文件大小、获取时间、来源渠道和分析环境版本。不要依赖文件名判断样本,因为文件名很容易被修改。

随后检查签名和证书:

apksigner verify --verbose --print-certs case01/sample/app.apk

重点记录签名方案、证书主题、序列号和证书摘要。自签名证书本身不等于恶意,但如果同一应用不同版本突然更换证书,或所谓官方应用使用明显无关的测试证书,就值得进一步核验。

五、步骤二:解析 Manifest 与组件暴露面

使用 Apktool 解码:

apktool d -f case01/sample/app.apk -o case01/static/apktool

打开 AndroidManifest.xml,重点检查 uses-permission、application、intent-filter、android:exported、provider authorities、networkSecurityConfig 和 usesCleartextTraffic。也可以先快速搜索:

grep -RniE 'exported|uses-permission|usesCleartextTraffic|networkSecurityConfig|BIND_ACCESSIBILITY_SERVICE' case01/static/apktool/AndroidManifest.xml

审查导出组件时,不应只看到 exported=true 就判定漏洞。还要结合组件是否设置签名级权限、是否验证调用方、是否接收外部 URI,以及 Intent 参数能否影响文件路径、WebView 地址或命令执行逻辑。

例如,一个导出的 Activity 接收 url 参数并直接传给 WebView.loadUrl,可能形成任意页面加载和 JavaScript 桥滥用风险。修复时应优先将非必要组件设置为 android:exported=false;确需导出的组件应使用签名级权限,并对 scheme、host、path 和参数类型实施白名单校验。

六、步骤三:反编译并定位高风险代码

使用 JADX 生成可检索代码:

jadx -d case01/static/jadx case01/sample/app.apk

首先搜索高信号 API 和关键字:

grep -RniE 'DexClassLoader|PathClassLoader|loadLibrary|Runtime.getRuntime|ProcessBuilder|setJavaScriptEnabled|addJavascriptInterface|X509TrustManager|HostnameVerifier|AccessibilityService|MediaRecorder|TelephonyManager' case01/static/jadx

grep -RniE 'https?://|wss?://|BEGIN CERTIFICATE|api[_-]?key|token|secret' case01/static/jadx case01/static/apktool/assets

分析命中结果时要沿调用链向上追踪:谁调用了该方法、参数从哪里来、是否受开关控制、是否只用于正常业务。比如 Runtime.exec 可能只是调试工具执行本地诊断,也可能被用于执行下载后的命令;判断依据应包括参数来源、触发条件和动态运行证据。

如果发现 DexClassLoader,应继续查找被加载文件的来源。重点查看 assets、私有目录、下载目录以及解密函数。可枚举容器中的异常文件:

unzip -l case01/sample/app.apk | sort -k1,1n | tail -n 30
find case01/static/apktool/assets -type f -exec file {} \;
find case01/static/apktool/lib -type f -name '*.so' -exec sha256sum {} \;

扩展名并不可靠。名为 data.bin、config.dat 的文件也可能是 DEX、ELF、ZIP 或加密载荷。对未知文件先用 file、xxd 和 strings 查看特征,不要直接执行:

xxd -l 64 case01/static/apktool/assets/data.bin
strings -a -n 6 case01/static/apktool/assets/data.bin | head -n 50

若主要逻辑位于 .so,可使用 readelf 和 objdump 做初筛:

readelf -hW case01/static/apktool/lib/arm64-v8a/libnative.so
readelf -Ws case01/static/apktool/lib/arm64-v8a/libnative.so | head
strings -a -n 6 case01/static/apktool/lib/arm64-v8a/libnative.so | grep -Ei 'http|socket|exec|ptrace|frida|token'

字符串只能作为线索。编译器、第三方 SDK 或未引用代码都可能产生误报,最终仍要结合交叉引用和运行行为确认。

七、步骤四:建立隔离动态环境

创建不含个人数据的模拟器,启动后先保存干净快照。确认 adb 只连接测试设备:

adb devices -l
adb shell getprop ro.build.version.release
adb shell settings put global airplane_mode_on 1

飞行模式命令在不同系统镜像上的效果可能不同,应在虚拟化网络层进一步限制出口。安装前开始记录基础信息:

adb shell pm list packages | sort > case01/dynamic/packages-before.txt
adb shell ps -A > case01/dynamic/process-before.txt

然后安装并记录结果:

adb install -r case01/sample/app.apk
adb shell pm list packages | sort > case01/dynamic/packages-after.txt

安装失败时不要为了运行样本而随意关闭系统安全机制。先查看 adb install 的错误信息,确认是否存在签名不一致、SDK 版本不兼容或 ABI 不匹配。为了迁就样本而启用未知来源、授予 root 或关闭验证,会改变真实行为并扩大风险。

八、步骤五:观察日志、进程与落地文件

清空旧日志后启动应用:

adb logcat -c
adb logcat -v threadtime > case01/dynamic/logcat.txt

另开终端查找包名和进程:

adb shell pidof com.example.suspicious
adb shell dumpsys package com.example.suspicious > case01/dynamic/package.txt
adb shell dumpsys activity services com.example.suspicious > case01/dynamic/services.txt

在授权测试应用或可调试实验镜像上,可观察应用私有目录的新增文件。普通生产权限下无法读取其他应用私有目录,这是正常的 Android 沙箱行为,不应通过破坏真实设备安全边界来绕过。对于自有可调试应用,可使用:

adb shell run-as com.example.suspicious find . -type f -maxdepth 4 -ls
adb shell run-as com.example.suspicious ls -la files cache databases shared_prefs

重点关注运行后新增的 .dex、.jar、.so、无扩展名大文件、异常数据库和配置项。若发现动态落地文件,应拉取副本后再次计算哈希并静态分析,而不是在设备上执行它。

动态触发要采用可复现脚本或明确步骤,例如首次启动、拒绝权限、授予某项权限、切换网络状态、重启应用等。每次只改变一个变量,便于判断行为与条件之间的关系。不要向样本输入真实手机号、账号、验证码或企业令牌。

九、步骤六:受控网络分析

在本机启动代理,仅监听实验接口:

mitmweb --listen-host 127.0.0.1 --listen-port 8080

通过模拟器的代理设置将流量导向分析主机。只在自有应用或授权样本中安装测试 CA。若应用实施证书固定,代理中看不到明文并不代表没有通信,可先利用系统网络统计、DNS 日志、连接目标和应用自身日志确认是否建立连接。

需要记录的证据包括:目标域名或 IP、端口、协议、请求时间、触发页面、请求字段类别、响应状态码及是否包含设备标识。报告中应对令牌、手机号和账号等数据脱敏,不要直接公布仍有效的凭据。

如果发现应用信任所有证书、HostnameVerifier 恒定返回 true,风险不仅是样本自身通信可被中间人观察,也意味着用户数据可能遭劫持。开发侧修复应恢复系统默认信任链,删除全信任 TrustManager,正确验证主机名;确需证书固定时,应设计证书轮换和备用公钥机制,避免证书更新导致全量断网。

十、如何形成可验证的分析结论

建议将结论分为事实、推断和待验证三类。例如:

事实:Manifest 声明了读取通讯录权限;代码中存在查询 ContactsContract 的方法;运行时在用户授权后出现对应系统调用与网络请求。

推断:通讯录内容可能被整理后上传,因为序列化字段与请求时间一致,但当前隔离环境中没有真实联系人,尚未观察到有效数据载荷。

待验证:服务器响应可能下发第二阶段模块,但实验环境禁止外网,未取得响应样本。

这种写法比直接给应用贴上木马标签更严谨。高可信恶意判定通常需要多个证据闭环,例如敏感数据来源、处理函数、网络发送点和动态流量能够相互对应。

十一、风险与注意事项

1. 不要在日常手机、工作电脑或登录真实账号的模拟器中运行未知 APK。
2. 不要允许样本直接访问互联网,尤其不要主动连接代码中发现的控制地址。
3. 不要上传包含客户数据、未公开应用或有效密钥的 APK 到公共在线分析平台。
4. 不要将反编译失败等同于应用安全。壳、混淆和动态加载只会提高分析成本,并不能证明无风险。
5. 修改 APK 后重新签名会改变证书、包完整性和部分运行分支,因此修改版的行为不能完全代表原样本。
6. 日志、抓包文件和内存转储可能含敏感信息,应加密保存并设置访问权限。
7. 分析结论应标明样本哈希、版本、测试时间、系统镜像和网络条件,避免后续无法复现。

十二、常见问题

问题一:JADX 出现大量反编译错误怎么办?

答:先用 Apktool 查看 Smali,并确认是否存在多个 DEX。对于关键方法,可以直接阅读 Smali 控制流;如果逻辑转入原生库,则应切换到 Ghidra、IDA Free 等原生分析工具。不要只依赖单一反编译器的伪代码。

问题二:应用启动后立即退出,是否说明样本无效?

答:不一定。可能是 ABI 不匹配、缺少 Google 服务、签名校验、模拟器检测、网络条件不满足或时间触发。先结合 logcat、崩溃堆栈和系统属性判断,不建议一开始就修改检测逻辑,因为修改可能破坏行为真实性。

问题三:抓不到 HTTPS 明文怎么办?

答:先确认代理路由和 CA 安装是否正确,再判断应用是否使用证书固定、Cronet、自带 TLS 库或原生 Socket。防御分析不必强求所有流量解密;域名、连接时序、字节量、调用栈和服务端模拟结果也能提供证据。

问题四:声明了高危权限就能判定为木马吗?

答:不能。权限只是能力申请,还要确认用户是否授予、代码是否调用、调用结果如何处理以及是否存在外传。正常软件也可能因历史代码或第三方 SDK 声明多余权限,但多余权限本身仍应整改。

问题五:分析后如何给开发团队提出修复建议?

答:建议按攻击面映射到具体代码:关闭不必要的导出组件;为 IPC 增加签名级权限和调用方校验;移除动态下载执行能力或对模块实施签名校验;敏感数据使用 Android Keystore 保护;收紧 WebView 配置;恢复严格 TLS 校验;最小化权限;为后台任务增加用户可见性和可撤销控制。修复后要使用同一套测试步骤回归验证。

十三、总结

高质量 APK 分析不是简单地搜索敏感字符串,而是建立证据链:先用哈希和签名固定样本,再从 Manifest 梳理权限与组件入口,通过 JADX、Smali 和原生库定位可疑调用,最后在隔离环境中验证进程、文件和网络行为。静态线索负责扩大覆盖面,动态证据负责确认行为,二者交叉后才能降低误报。

对于防御人员,最终产物应包含样本身份、环境信息、触发步骤、证据位置、风险影响、可信度和可执行修复方案。这样既能帮助分析人员复现,也能让开发团队明确应关闭哪个入口、校验哪类参数、保护哪份数据,而不是只得到一个缺乏依据的恶意或安全结论。
 
顶部