概述:
Android系统的代码调用、回调都是按照一定顺序执行的。
例如,对象小王调用类对象,对象小美处理后将数据回调给对象A。
如果采用Hook的调用流程:
俩人遇到了小王的妈妈(Hook):【注意:这里说的是小王男方的家长】
Hook可以是一个方法或一个对象,如同钩子一样挂在对象小王和小美之间。当对象小王和小美想做一些羞羞的事情,比如打Ber啥的,Hook(小王的妈)就可以做到帮他们悄悄关房门的作用。所以,这里的Hook可以是钩子也可以说是劫持(小美的妈)。
应用程序进程之间是彼此独立的,应用程序进程和系统进程之间也是这样。
想要在应用程序进程更改系统进程的某些行为很难实现,有了Hook技术,就可以在进程间进行行为更改。
Hook可以将自己融入到它所要劫持的对象(对象BB)所在的进程中,成为系统进程的一部分。就可以通过Hook来更改对象B的行为。
被劫持对象(对象BB)就叫:Hook点。
一般Hook点选择容易且不易变化的对象(例如静态变量、单例等),目的是保证Hook的稳定性。
Hook技术分类:
1.根据Hook的api语言划分,
分为:
- Hook Java:主要通过反射和代理实现,应用于SDK开发环境中修改Java代码
- Hook Native: 应用于在NDK开发环境和系统开发中修改Native代码
2.根据Hook的进程划分,
分为:
- 应用程序进程Hook只能Hook当前所在的应用程序进程。
- 应用程序进程是Zygote(孵化器)进程fork出来的。如果对Zygote进行Hook,可实现Hook系统的所有的应用程序进程,即全局Hook.
3.根据Hook的实现方式划分:
- 通过反射和代理实现。只能Hook当前的应用程序进程。
- 通过Hook框架实现。如Xposed框架,实现全局Hook,但需root
Hook可以用来做插件化相关【Hook java】也常用于逆向工程的动态分析。
代理模式
HookJava是插件化的铺垫。想要学习Hook java,代理模式则是铺垫。
代理模式(委托模式)是23种设计模式的一种。代理的场景有很多,比如Kotlin有代理的语法糖(委托属性等 常见的by lazy)。
代理模式:为其他对象提供一种代理以控制这个对象的访问。
- Subject: 抽象主题类,声明真实主题和代理的共同接口方法
- RealSubject: 真实主题类,定义了代理所表示的集体对象,客户端通过代理类间接调用真实主题类的方法
- Proxy: 代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行
- Client: 客户端类
代理模式的简单案例:[静态代理]
情景: 武汉疫情,我想买口罩给家人,但是本地没有,我就委托成都的同学帮我代购给我。
1.抽象主题类:具有真实主题类和代理的共同接口方法。
这里的共同接口方法是代购:
2. 真实主题类:真正的购买者是我,实现了IShop中提供的buy()
3. 代理类:在成都的朋友。需实现Ishop接口,同时要持有被代理者我。即以我的名义去购买。
4.客户端类:
代理类包含了真实主题类(被代理者),最终调用的都是真实主题类(被 代理者)是西安的方法。
动态代理的简单实现:
静态代理在代码运行前就已经存在代理类的class编译文件。
动态代理则在代码运行时通过反射来动态地生成代理类的对象,并确定到底来代理谁。【即编码阶段不确定代理谁,运行时决定。】
Java提供了动态的代理接口InvocationHandler,实现该接口重写invoke()
基于上面的小案例改造:
1. 创建动态代理类:即不确定我哪个朋友。
该朋友类中声明一个Object的引用,指向被代理类我,调用被代理类的具体方法在invoke()中执行。
2. 客户端类:
Hook startActivity()
被劫持的对象叫做Hook点,用代理对象替代Hook点,就可以在代理上实现自己想做的操作。
Hook常用的startActivity()分为 2个:
- startActivity(intent); //activity的startActivity()
- getApplicationContext().startActivity(intent);//context的startActivity()
2个方式的调用链不同。
1. Hook Activity.startActivity():
其中的
调用了mInstrumentation.execStartActivity()来启动Activity。
这个
其实是Activity的成员变量。可以选择Instrumentation为Hook点,用代理Instrumentatiion来替代原始的Instrumentation来完成Hook。
编写代理Instrumentation类:
然后用上面编写的Proxy替换Instrumentation:
2.Hook Context.startActvity():
context的实现类是ContextImpl,所以从这里为出发点寻找Hook点:
可以看到有这么一行:
调用了ActivityThread.getInstrumentation()获取Instrumentation.
ActivityThread是主线程的管理类。
Instrumentation是ActivityThread的成员变量,一个进程中只有一个ActivityThread.因此,还是选择Instrumentation作为Hook点。
即上面的proxy不用改造。
只需要改造一下要调用的地方:
结论:
2个方式的最大区别是替换的Instrumentation不同。
context的是activityThread的Instrumentation,
activity的是Activity的Instrumentation,
选择合适的最佳的替换时间点,可以尝试在Activity的attachBaseContext()中进行Instrumentation的替换。
这个attachBaseContext()先于activity的onCreate()被调用。
Hook的流程:找到Hook点,再用代理对象来替换Hook点。