Hook技术简析
说到Hook技术需要先提到逆向工程,主要目的是在不能轻易获得必要生产信息的情况下,直接从成品分析,推导出产品的设计原理。
逆向分析又分为
- 静态分析:不执行程序的情况下对程序行为进行分析的技术
- 动态分析:在程序运行时对程序进行调试的技术。Hook属于动态分析。
代理模式
设计模式--静态代理模式和动态代理模式原理及实现Hook技术概述
对象A直接调用B,对象B结果直接回调给A。
Hook可以是一个方法或者对象,它位于对象A和B之间,当对象A调用对象B时会在之前做一些处理。也可以用于应用进程调用系统进程时做一些处理,更改他们间的关系。
其中被Hook的对象B,称作Hook点。
整个Hook的过程分为三步:
- 寻找Hook点。原则上是静态变量或者单例对象(容易找到并且不易变化的对象),尽量Hook Public的对象和方法,非Public不保证每个版本保持一致,可能需要适配。
- 选择合适的代理方式。如果是接口可以使用动态代理方式,类的话多考虑使用静态模式。
- 用代理对象替换原始对象。
Hook实例简析
Hook startActivity()
Activity的启动方式有两种
一个Activity启动另一个Activity
1
startActivity(new Intent(this,XXActivity.class));
通过Service或者其他非Activity类进行启动Activity(必须设置 FLAG_NEW_TASK)
1
2
3Intent intent = new Intent(this, XXActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
1.Hook Activity.startActivity()
从源码分析上需要从startActivity()
开始
1 |
|
最终调用到的是Instrumentation.execStartActivity()
执行启动下一个Activity的逻辑。
按照Hook过程分析,需要先找到Hook点
。由于要Hook的就是Activity的启动,所以我们可以设置Instrumentation
为Hook点,然后使用静态代理模式生成代理对象,最后替换掉原始的Instrumentation
继续执行启动逻辑。
先创建
Instrumentation
代理对象InstrumentationProxy
1 |
|
在需要使用的Activity中实现Hook方法
1 |
|
理论上来说
Hook操作
越早越好,handleLaunchActivity()
内部开始执行启动流程,然后会调用到Activity.attach()
内部继续执行。attachBaseContext()
是最早执行的,但是其中无法去执行Hook操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> final void attach(Context context, ActivityThread aThread,
> Instrumentation instr, IBinder token, int ident,
> Application application, Intent intent, ActivityInfo info,
> CharSequence title, Activity parent, String id,
> NonConfigurationInstances lastNonConfigurationInstances,
> Configuration config, String referrer, IVoiceInteractor voiceInteractor,
> Window window, ActivityConfigCallback activityConfigCallback) {
> attachBaseContext(context);
> ...
> //在这个方法后面又会继续执行赋值,则Hook失效
> mInstrumentation = instr;
> ...
> }
>
>
2.Hook Context.startActivity()
Context
的具体实现类为ContextImpl
,ContextImpl.startActivity()
如下所示
1 |
|
getInstrumentation()
去获取对应的Instrumentation
不过这个是可以全局生效的,ActivityThread
是主线程的管理类,Instrumentation
是其成员变量,一个进程中只会存在一个ActivityThread
,因此依然设置Instrumentation
为Hook点。
可以在Application
中或者Activity
中去设置Hook方法
1 |
|
可能出现的问题
无法进行Hook操作
1
E/Instrumentation: Uninitialized ActivityThread, likely app-created Instrumentation, disabling AppComponentFactory
出现上述提示,发生的情况是在Android P上运行应用时。
主要是因为在Android P的源代码中对
Instrumentation.newActivity()
进行了调整1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26private ActivityThread mThread = null;
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
String pkg = intent != null && intent.getComponent() != null
? intent.getComponent().getPackageName() : null;
return getFactory(pkg).instantiateActivity(cl, className, intent);
}
private AppComponentFactory getFactory(String pkg) {
if (pkg == null) {
Log.e(TAG, "No pkg specified, disabling AppComponentFactory");
return AppComponentFactory.DEFAULT;
}
if (mThread == null) {
Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation,"
+ " disabling AppComponentFactory", new Throwable());
return AppComponentFactory.DEFAULT;
}
LoadedApk apk = mThread.peekPackageInfo(pkg, true);
// This is in the case of starting up "android".
if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
return apk.getAppFactory();
}因为只是hook了
execStartActivity()
而newActivity()
就会抛出如上异常,解决方案就是在我们自定义的InstrumentationProxy
中去重写newActivity()
1
2
3
4
5
6
7public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return mBase.newActivity(cl, className, intent);
}
内容引用
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!