首先说下什么是 Hook (钩子函数):
钩子函数其实一段程序,在系统的调用中挂载到系统,在没有调用该函数之前,钩子程序先捕获该消息,这样钩子函数先得到控制权,这样钩子函数就可以加工处理该函数的执行从而改变消息的传递。
Hook技术实现的过程:(java层)
1) 找到Hook点
① hook的过程是一个找方法的过程,我们要找到微信怎么登录的,就需要找到微信登录的方法。
② 需要满足的条件 :对象一定是静态
2)找到hook方法执行前的代码
一、 找到拦截系统Intent 的 Hook点
从 Activity的启动过程 我们了解到,在开启一个Activity的时候,会调用若干的方法,仔细一点我们发现其中有一个
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread,
who.getBasePackageName(),
intent.resolveTypeIfNeeded(who.getContentResolver()),
token,
target,
0,
null,
options);
在ActivityManagerNative.getDefault() 中返回了一个对象,虽然是一个静态方法,但是我们需要一个静态对象:
static public IActivityManager getDefault() {
return gDefault.get();
}
再来看下 gDefault 对象:
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
看到 private static final
我们知道这是一个静态的final类型的成员变量,而Singleton是个什么呢?按照字面意思,该类是一个单例类,具体:
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
通过单例的方式来让继承实现其中的create() 方法,返回IActivityManager,但是IActivityManager只是Singleton的成员变量,不过Singleton既然是静态单例,所以也能反射拿到其中的成员。
好了,到此我们就找到了系统的hook点,下面实现:
先还原 gDefault 对象
try {
// 还原 gDefault() 成员
Class activityManagerNative = Class.forName("android.app.ActivityManagerNative");
// 获取到成员变量
Field gDefault = activityManagerNative.getDeclaredField("gDefault");
gDefault.setAccessible(true);
// 获取类成员变量,直接传空,因为是静态变量,所以获取到的是系统值,
// 得到Singleton 静态类,
Object defaultValue = gDefault.get(null);
//mInstance对象
Class<?> singletonClass=Class.forName("android.util.Singleton");
Field mInstance = singletonClass.getDeclaredField("mInstance");
mInstance.setAccessible(true);
// 获取到成员变量
Object iActivityManagerObject = mInstance.get(defaultValue);
} catch (Exception e) {
e.printStackTrace();
}
上面获取到了IActivityManager对象,接下来我们要将我们的代码插入到其中,相当于拦截系统的操作,执行我们的逻辑代码,而实现该操作有两种方式,一个是 动态代理, 另外一个是 实现接口的方式,而动态代理是万能的,实现接口需要将hook到的对象实现一个接口,但是我们获取到的IActivityManager对象本事就是一个接口,不能再实现接口,所以这里我们只能用动态代理的方式进行插入,这里我们用到系统的Proxy
// 实现该接口
Class iActivityManagerIntercept = Class.forName("android.app.IActivityManager");
StartActivity startActivity = new StartActivity(iActivityManagerObject);
/**
* ClassLoader loader 当前的类加载器
* Class<?>[] interfaces 返回的类将会实现的接口
* InvocationHandler h 实现了InvocationHandler 接口的代理类,以便实现系统分发出来的方法,实现拦截操作
*/
Object oldIActivityManager = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{iActivityManagerIntercept},
startActivity
);
// 将我们获取到的值设置进去
mInstance.set(defaultValue, oldIActivityManager);
看下StartActivity
/**
* 拦截类
*/
class StartActivity implements InvocationHandler {
private Object iActivityManager;
public StartActivity(Object iActivityManager) {
this.iActivityManager = iActivityManager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.i("Ellison", " ========= invoke =========");
if ("startActivity".equals(method.getName())) {
Log.d("Ellison", "---------startActivity----------");
}
return method.invoke(iActivityManager, args);
}
}
// 打印的结果:
========= invoke =========getActivityDisplayId
========= invoke =========setTaskDescription
========= invoke =========checkPermission
========= invoke =========checkPermission
========= invoke =========getActivityOptions
========= invoke =========getActivityOptions
derer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
[ 04-20 08:53:02.868 5687: 5687 D/ ]
HostConnection::get() New Host Connection establi
========= invoke =========activityResumed
========= invoke =========activityIdle
========= invoke =========getContentProvider
========= invoke =========startActivity
---------startActivity----------
========= invoke =========activityPaused
========= invoke =========getActivityDisplayId
========= invoke =========setTaskDescription
========= invoke =========getActivityOptions
========= invoke =========getActivityOptions
========= invoke =========activityResumed
nderer: endAllStagingAnimators on 0xb2b7c780 (RippleDrawable) with handle 0xae59
========= invoke =========activityIdle
========= invoke =========activityStopped
到此,我们可以Hook到系统的API~~~