Android Hook 机制分析

9 阅读4分钟

Android Hook 机制分析

一、Hook 是什么

在运行时替换或拦截原有方法/函数的调用,使执行流程走到自定义逻辑,再决定是否继续调用原实现。


二、常见 Hook 实现方式

1. Java 反射 Hook

思路:通过反射修改对象字段或替换方法实现。

// 示例:Hook ActivityThread 的 mH(Handler)
val activityThreadClass = Class.forName("android.app.ActivityThread")
val currentActivityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null)
val mHField = activityThreadClass.getDeclaredField("mH")
mHField.isAccessible = true
val mH = mHField.get(currentActivityThread) as Handler

// 替换 mH 的 mCallback
val callbackField = Handler::class.java.getDeclaredField("mCallback")
callbackField.isAccessible = true
callbackField.set(mH, Handler.Callback { msg ->
    // 拦截消息,可修改、转发或丢弃
    if (msg.what == 100) {
        // 自定义逻辑
        return@Callback true  // 已处理,不继续分发
    }
    false  // 未处理,继续原逻辑
})
步骤说明
1用反射拿到目标类/对象(如 ActivityThreadmH
2修改字段(如 mCallback)或替换为代理对象
3后续调用会先经过代理,再决定是否调用原实现

2. 动态代理 Hook

思路:用 Proxy.newProxyInstance 生成接口的代理实现,在 InvocationHandler 里拦截方法。

// 示例:Hook 系统 Service
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val iClipboard = ClipboardManager::class.java.getDeclaredField("mService")
    .apply { isAccessible = true }
    .get(clipboard)

val proxy = Proxy.newProxyInstance(
    iClipboard.javaClass.classLoader,
    arrayOf(Class.forName("android.content.IClipboard"))
) { _, method, args ->
    if (method.name == "getPrimaryClip") {
        // 拦截剪贴板读取
        return@newProxyInstance null  // 或修改返回值
    }
    method.invoke(iClipboard, *(args ?: arrayOfNulls(0)))
}
// 再通过反射把 mService 替换为 proxy
适用限制
接口型 API只能代理接口,不能代理类

3. 替换 ClassLoader / Dex 元素 Hook

思路:在类加载前替换字节码或 Dex 中的方法实现(如通过自定义 ClassLoader、Gradle 插件等)。

// 简化:自定义 ClassLoader 在 loadClass 时返回修改过的 Class
class HookClassLoader(parent: ClassLoader) : ClassLoader(parent) {
    override fun loadClass(name: String, resolve: Boolean): Class<*> {
        if (name == "target.ClassName") {
            // 加载修改过的字节码
            return defineClass(name, modifiedBytecode, 0, modifiedBytecode.size)
        }
        return super.loadClass(name, resolve)
    }
}
特点说明
时机在类加载前介入
实现需要字节码操作(ASM、Javassist 等)或自定义 ClassLoader

4. Native Hook(C/C++ 层)

思路:修改函数入口的机器码,跳转到自定义函数(inline hook、GOT/PLT hook 等)。

// 简化:inline hook 思路
// 1. 修改目标函数前几条指令为 JMP 到 hook 函数
// 2. hook 函数执行自定义逻辑后,再调用原函数(需先备份原指令)
常见库用途
Substrate、Frida动态插桩、函数替换
PLT Hook修改 GOT 表,拦截动态链接函数

三、典型 Hook 点(Android)

目标作用
ActivityThread.mH拦截 Activity 生命周期、启动等消息
ActivityThread.mInstrumentation拦截 Activity 创建、生命周期调用
PackageManagerClipboardManager 等 Binder 代理拦截系统服务调用
View.mAttachInfo.mSession拦截 Window 相关操作
Resources / AssetManager换肤、资源替换
InputMethodManager输入法相关逻辑

四、优点

优点说明
无侵入不改业务源码,通过 Hook 统一处理
灵活可拦截系统 API、第三方 SDK,扩展能力强
集中控制在少数点统一实现埋点、权限控制、兼容等
可逆可恢复原实现,便于调试和回滚
兼容老版本在不改 APK 的前提下适配不同系统行为

五、缺点

缺点说明
稳定性差依赖系统内部实现,ROM/版本升级易失效或崩溃
维护成本高需适配各厂商、各 Android 版本,测试量大
性能开销反射、代理有额外调用成本,高频路径需谨慎
安全风险易被检测,部分场景违反应用商店或合规要求
调试困难调用链被改写,堆栈不直观,问题难定位
兼容性不同 ROM 可能加固、混淆,类名/字段名变化

六、使用建议

场景建议
埋点、监控优先用 AOP(AspectJ 等)、编译期插桩,少用运行时 Hook
换肤、资源替换可 Hook Resources / AssetManager,但要做好版本兼容
系统行为适配评估是否可用官方 API 或配置替代,再考虑 Hook
安全/合规要求高避免 Hook 系统核心逻辑,优先正规 API

七、小结

维度说明
本质运行时替换/拦截调用链,插入自定义逻辑
常见手段反射改字段、动态代理、字节码替换、Native Hook
优点无侵入、灵活、可集中控制
缺点稳定性依赖实现细节、维护成本高、有性能和安全风险

结论:Hook 适合做兼容、监控、扩展,但应控制范围和调用频率,并做好版本适配与回退方案。