Lazy loaded image
Frida学习笔记(十一):Android 系统级 Hook
Words 7035Read Time 18 min
2026-7-10
2026-7-10
type
Post
status
Published
date
Jul 10, 2026
slug
summary
本篇目标:学会 Hook Android Framework 层的核心组件,建立对 App 行为的「上帝视角」。前面几篇聚焦于加密、网络、检测绕过等特定目标——你总是先知道要 Hook 什么,再去写脚本。但在面对一个完全陌生的 App 时,你往往不知道从哪里下手。本篇教你通过 Hook Android 系统级 API——Activity 生命周期、Intent 传递、SharedPreferences 读写、ContentProvider 查询、WebView 交互——来快速绘制 App 的行为全景图:它有哪些页面、页面之间传了什么数据、本地存了什么配置、WebView 里加载了什么 URL。
tags
frida
逆向工程
实用教程
category
公众号
icon
password
网址
上次编辑时间
Jul 10, 2026 06:28 AM
comment
AI 总结
本篇目标:学会 Hook Android Framework 层的核心组件,建立对 App 行为的「上帝视角」。前面几篇聚焦于加密、网络、检测绕过等特定目标——你总是先知道要 Hook 什么,再去写脚本。但在面对一个完全陌生的 App 时,你往往不知道从哪里下手。本篇教你通过 Hook Android 系统级 API——Activity 生命周期、Intent 传递、SharedPreferences 读写、ContentProvider 查询、WebView 交互——来快速绘制 App 的行为全景图:它有哪些页面、页面之间传了什么数据、本地存了什么配置、WebView 里加载了什么 URL。

一、为什么需要系统级 Hook

1.1 从「定向 Hook」到「全景监控」

前面几篇的 Hook 都是「定向」的——你已经通过 jadx 找到了目标类和方法,然后写脚本去拦截。但这有一个前提:你得知道 Hook 什么
面对一个完全陌生的、重度混淆的 App,你常常连"登录逻辑在哪个 Activity、Token 存在哪个 SP key、H5 页面通过什么 JSBridge 通信"都不知道。这些信息不在 App 的业务代码中,而在 Android Framework 的系统 API 中流转——不管业务代码怎么混淆,它总得调用系统 API 来创建 Activity、发送 Intent、读写 SharedPreferences。Hook 这些系统 API,就像在操作系统层面安装了监控摄像头。

1.2 本篇覆盖的系统 API

| 系统组件 | Hook 目标 | 你能看到什么 | | :-- | :-- | :-- | | Activity | 生命周期方法 | 页面跳转路径、当前显示的页面 | | Intent | 构造与发送 | 页面间传递的数据(用户ID、Token、URL) | | BroadcastReceiver | 接收侧分发漏斗 | 谁发的广播、谁收的、带了什么数据 | | SharedPreferences | getString/putString 等 | 本地存储的配置、Token、开关 | | ContentProvider | query/insert/update/delete | 数据库操作、跨进程数据共享 | | WebView | loadUrl/evaluateJavascript | H5 页面 URL、JS 注入、JSBridge 调用 | | Clipboard | getText/setText | 复制粘贴的内容(可能含敏感数据) | | Toast/Dialog | show/makeText | App 给用户的提示信息 | | PackageManager | getInstalledPackages 等 | App 检查了哪些其他 App(环境检测) |
notion image
Android 系统级 Hook 的 4 层架构与 8 个 hook 点

二、Hook Activity 生命周期:追踪页面跳转

2.1 Activity 生命周期回顾

每个 Android 页面都是一个 Activity。Activity 有一套标准的生命周期方法:
但单看一个 Activity 的生命周期没用——分析师真正想知道的是"从 A 切到 B 时各方法的交错顺序",因为这决定了"上一页"和"当前页"分别该 hook 在哪里:
notion image
Activity A → B 切换时的生命周期时序
记住这张图的三个判断:onResume 标记当前页 / onCreate 拿跳转参数 / onPause + onResume 配对画页面流转图。下面的脚本就是按这个思路写的。

2.2 追踪所有 Activity 的生命周期

运行效果:
通过这个输出,你可以清楚地看到 App 的页面流转:SplashActivity → MainActivity → LoginActivity,并且知道跳转到登录页时携带了 redirect_urlsource 两个参数。

2.3 获取当前前台 Activity

有时候你只想知道当前显示的是哪个页面,不需要追踪完整的生命周期:
Android 14+ hiddenapi 注意ActivityThread.mActivitiesActivityClientRecord 字段在 Android 9+ 进入 non-SDK 限制名单,Android 14 起进一步收紧。Frida 已能自动绕过限制,但 logcat 中可能看到 Accessing hidden field 警告 —— 不影响读值。

三、Hook Intent:拦截页面间的数据传递

3.1 Intent 的角色

在 Android 中,组件之间(Activity ↔ Activity, Activity ↔ Service, Activity ↔ BroadcastReceiver)的通信都通过 Intent 进行。Intent 携带了目标组件的信息和要传递的数据(Extras)。
Hook Intent 可以捕获:
  • 页面跳转时传递的用户 ID、订单号、Token
  • 启动 Service 时传递的任务参数
  • 发送广播时携带的数据

3.2 Hook startActivity 和 sendBroadcast

要 hook "所有的 startActivity 调用",新手往往直接挂在 Activity.startActivity 上 —— 这其实漏了一大片。所有入口在底层都汇聚到 Instrumentation.execStartActivity 这一个方法,hook 在这里才是最稳的"漏斗底部":
notion image
Intent 启动调用链收敛图
安全分析价值:很多 App 在 Intent Extras 中传递敏感数据(明文 Token、用户信息、支付金额),这些数据如果被恶意 App 截获(通过 BroadcastReceiver 或 exported Activity),就构成了安全漏洞。通过这个脚本可以快速发现这类问题。

3.3 Hook BroadcastReceiver 接收侧

发送侧(sendBroadcast)已在 §3.2 覆盖;接收侧才是"App 收到了什么 → 触发了什么动作"的关键。常见思路是遍历所有 BroadcastReceiver 子类挂 onReceive——但这漏了运行时注册的接收器、并且类加载时机难控。更稳的漏斗点是 android.app.LoadedApk$ReceiverDispatcher$Args.run(),所有静态/动态注册的接收器最终都在这里被分发执行:
字段稳定性mCurIntentmReceiver 在 Android 5-14 的 AOSP 中字段名一致,但部分深度定制 ROM(一些国产厂商)可能改名。若读字段抛 NoSuchFieldError,回退到「枚举 BroadcastReceiver 子类 + 挂 onReceive」的笨办法:可以在 Java.performJava.enumerateLoadedClasses({ onMatch: function(name) { if (...) hookOnReceive(name); }, onComplete: ... }),但要注意类还没加载就不会被命中——需要在每次新 ClassLoader 出现时重跑。
运行效果:
结合发送侧的 sendBroadcast 监控,就拿到了广播的完整闭环:谁发的(包名/Action)→ 谁收的(接收器类名)→ 带了什么数据。这对分析推送链路、风控触发条件、跨组件协作都非常有用。

四、Hook SharedPreferences:监控本地配置读写

4.1 SharedPreferences 的作用

SharedPreferences 是 Android 最常用的轻量级持久化存储方案,存储在 /data/data/包名/shared_prefs/ 下的 XML 文件中。Token、设备指纹、功能开关、首次启动标记几乎都落在这里——监控价值极高。

4.2 全面监控 SharedPreferences 读写

覆盖范围与盲区:上面这套 hook 只拦截系统默认实现 android.app.SharedPreferencesImpl。如果 App 使用了下面这些方案,需要单独 hook 对应入口: - MMKV(腾讯):hook com.tencent.mmkv.MMKVencode* / decode* 方法 - Jetpack DataStore:基于 Protobuf + Coroutine,hook androidx.datastore.* 序列化层 - EncryptedSharedPreferences(Jetpack Security):是 SP 的装饰器,本套 hook 落到的是密文。要拿明文,挂公开方法 androidx.security.crypto.EncryptedSharedPreferences$Editor.putString / putInt / putBoolean / ... —— 进入这一层时参数还是明文,序列化与加密发生在内部私有 putEncryptedObject(String, byte[]),想看序列化中间态可以再挂这个私有方法 - 多进程 SP:部分 ROM 走 MultiProcessSharedPreferences,类名不同
上面四种实现里,前三种都走 SharedPreferences 接口(一个基础实现 + 两个装饰器),最终落到 SharedPreferencesImpl;后两种 MMKV / DataStore 是「平行替代系」——完全独立于 SP 接口,本节脚本一次都不会命中。下图把 5 种实现的 hook 入口和能拿到的明文位置画在同一张图里,配上拿到 App 后的诊断顺序:
notion image
SharedPreferences 5 种实现的 Hook 入口对照
运行效果:
这个输出告诉你:Token 存储在 user_session.xmlaccess_token key 下;设备 ID 存储在 app_config.xmldevice_id key 下。这些信息对后续的 RPC 调用(第27篇)和协议还原非常有价值。

4.3 直接读取 SharedPreferences 中的值

除了被动监控,你也可以主动读取 SharedPreferences 中的现有数据:

五、Hook WebView:拦截 H5 页面与 JSBridge

5.1 WebView 在现代 App 中的角色

很多 App 不是纯 Native 的——它们使用 WebView 加载 H5 页面来实现部分功能(活动页、支付页、广告页、内容详情页)。WebView 中的 JavaScript 通过 JSBridge 与 Native 通信,获取 Token、设备信息、调用 Native 功能。Hook WebView 能拿到 H5 URL、Native 注入的 JS 代码、以及 JSBridge 双向传递的数据。
Native ↔ WebView ↔ H5 三方有 4 个独立的通信方向,每个方向对应一个 hook 点。看清谁调谁,才知道下面的代码挂在哪里:
notion image
WebView Native↔H5 通信全景时序

5.2 Hook WebView.loadUrl

5.3 Hook JSBridge 方法调用

当你通过 addJavascriptInterface 的 Hook 发现了 Bridge 类名后,可以进一步 Hook 它的每个方法:

六、Hook ContentProvider:监控数据库操作

6.1 ContentProvider 的用途

ContentProvider 是 Android 四大组件之一,用于在 App 内部或跨 App 共享结构化数据。App 内部常用它封装 SQLite 数据库操作。

七、Hook 其他系统 API

7.1 剪贴板监控

7.2 Toast 和 Dialog 监控

7.3 PackageManager 监控(环境检测行为)

App 通过 PackageManager 检查设备上安装的其他 App——这通常是环境检测(Root 检测、模拟器检测、风控采集)的一部分:
Android 11+ Package Visibility 注意事项:targetSdk ≥ 30 的 App 调用 getInstalledPackages / getPackageInfo 时,默认只返回 <queries> 清单里声明过的包(或自身),未声明的查询会返回空或抛 NameNotFoundException。所以"App 检查 Magisk"这种行为可能根本不走 getPackageInfo,而是直接 new File("/sbin/.magisk").exists() 或 hook Runtime.exec("pm list packages")。监控覆盖面要相应扩大。

八、实战:综合系统监控脚本

把上面所有 Hook 模块合并为一个综合脚本,加载后可以快速获取 App 的行为全景图:
运行后操作 App,终端输出示例:
从这一段输出中你已经获得了大量信息:
  • App 启动时检测了 Magisk 和 SuperSU(Root 检测)
  • Token 存储在 SharedPreferences 的 access_token key 下
  • WebView 加载 H5 页面时在 URL 参数中传递了 Token(安全隐患)
  • JSBridge 名为 NativeBridge,实现类是 com.example.app.bridge.AppBridge
  • 商品详情页通过 Intent 传递 product_idsource
这些信息构成了 App 行为的完整画像,为后续的深入分析(定向 Hook 加密、还原签名算法等)提供了精准的方向。

总结

本篇的核心价值是:不需要了解 App 的业务代码,通过 Hook 系统 API 就能获得 App 行为的全景图。
面对一个陌生 App,第一步永远是 §8 的综合监控脚本——加载它,操作 App,从输出里捞 Activity 跳转路径、SP 中的 Token key、WebView 加载的 H5、JSBridge 类名、Intent Extras 里的敏感字段。这些信息合在一起就是"该往哪里写定向 Hook"的方向盘。
需要注意三个盲区:① SP hook 只覆盖系统默认实现,MMKV/DataStore/加密 SP 要单独挂;② Package Visibility 让 Android 11+ 的 getInstalledPackages 默认裁剪;③ 主流加固/混淆方案可能改写 Toast、自定义 SP 类名,遇到打不出日志的情况优先回到 Java.deoptimizeEverything()Java.enumerateLoadedClasses 排查。
上一篇
Frida学习笔记(十二):加密算法还原(上)· AES、DES、RSA
下一篇
Frida学习笔记(十):gRPC、Protobuf 协议逆向

Comments
Loading...