Android: Hook技术

概述:

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点。

发布了307 篇原创文章 · 获赞 45 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_39969226/article/details/104170525