持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
Hook介绍
Hook
一般用在Android
技术安全以及逆向开发当中,也是Android
安全人员必须具备的技术能力。Hook
技术主要目的是绕过系统限制,修改代码执行内容动态化调用一些API
等常规功能。
根据Android
平台语言分类Hook
分为:Hook Java
和Hook Native
。Hook Java
是通过反射和代理方法实现;Hook Native
则是通过JNI接口函数完成。
代理模式
代理模式也称为委托模式:为其他对象提供一种代理以控制对这个对象的访问称为代理模式。代理模式作为设计模式,通俗理解像是生活中代购,通过中间一层关系实现一个任务。具体代码实现可以参考代理模式文章。
同时代理也分为静态代理和动态代理两种形式。静态代理和动态代理区别在于动态代理在代码运行时反射动态生成代理类。
public class DynamicProxy implements InvocationHandler{
private Object obj;
public DynamicProxy(Object obj){
this.obj = obj;
}
@override
public Object invoke(Object arg,Method arg1,Object[] arg2) throws Throwable{
Object result = method.invoke(obj,args);
// 代理的对象获取到之后 在中间执行其他操作
return result;
}
}
RealSubject realSubject = new RealSubject();
DynamicProxy dynamicProxy = new DynamicProxy(realSubject);
ClassLoader loader = realSubject.getClass().getClassLoader();
RealSubject subject = (RealSubject) Proxy.newProxyInstance(loader,new Class[]{RealSubject.class},proxy);
subject.Request();
动态代理方法实现代理接口InvocationHandler
,被代理类具体方法在invoke
方法中执行实现。Hook的时候使用Proxy.newProxyInstance()
生成动态代理类,当被Hook对象执行方法Request()
时就会执行代理对象的invoke
方法。
同时动态代理类还能修改被代理类执行结果,例如invoke
返回结果是int值且值为10,可将result修改成希望返回结果值比如11或者其他数值。
Hook实现
Hook用于劫持对象,被劫持对象叫做Hook点。在Android开发中常用方法是startActivity
,以此为例子来实现hook操作。在startActivityForResult
方法源码中已知使用mInstrumentation
的execStartActivity
方法来启动Activity
。mInstrumentation
是Activity
的成员变量,因此选择Instrumentation
为Hook
点,用代理Instrumentation
来替代原始的Instrumentation
来完成Hook
。
public class InstrumentationProxy extends Instrumentation {
private static final String TAG = "InstrumentationProxy";
Instrumentation mInstrumentation;
public InstrumentationProxy(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
Log.d(TAG, "Hook" + "hookhookhookhook");
Class[] pareTyples = {Context.class, IBinder.class, IBinder.class,
Activity.class, Intent.class, int.class, Bundle.class};
Object[] pareVaules = {who, contextThread, token, target,
intent, requestCode, options};
String methodName = "execStartActivity";
try {
// 通过反射找到Instrumentation的execStartActivity方法
Method execStartActivity = mInstrumentation.getClass().getDeclaredMethod(methodName, pareTyples);
execStartActivity.setAccessible(true);
return (ActivityResult) execStartActivity.invoke(mInstrumentation, pareVaules);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
实现InstrumentationProxy
代理类之后就在主工程中去代理Activity
中原来mInstrumentation
对象。其中因为InstrumentationProxy
代理改造了execStartActivity
方法,当Activity
调用startActivity
方法时就会打印日志信息从而监控到方法调用。
Class clazz = Activity.class;
try {
Field field = clazz.getDeclaredField("mInstrumentation");//通过Activity.class 拿到 mInstrumentation字段
field.setAccessible(true);
Instrumentation mInstrumentation = (Instrumentation) field.get(this); //根据activity内mInstrumentation字段 获取Instrumentation对象
Instrumentation instrumentationProxy = new InstrumentationProxy(mInstrumentation); ////创建代理对象
field.set(this, instrumentationProxy); //进行替换
} catch (Exception e) {
e.printStackTrace();
}
Hook总结
hook最好选择静态变量和单例,比较容易定位和代理;寻找hook的节点最好是静态变量和单例对象并且是public的对象和方法;Hook过程可能会遇到使用反射,由于Android不同版本兼容性不同,因此还需要做好API兼容配置。