系列文章
HOOK技术一-HOOK技术初探
HOOK技术二-未注册Activity的启动
HOOK技术三-插件Activity启动前提分析
HOOK技术四-插件中Activity启动实战
HOOK技术五-使用LoadedApk式插件化的理论分析
HOOK技术六-LoadedApk式插件化代码实现
HOOK技术七-版本适配及总结
流程梳理
如果Activity并未在AndroidManifest.xml文件中注册, 则启动该Activity会抛出异常。为了能启动未注册的Activity,需要将系统欺骗,使用一个ProxyActivity,在AndroidManifest.xml文件中注册了, 在系统检查之前,将未注册的Activity替换为ProxyActivity,检查完成之后,再讲ProxyActivity还原为未注册的Activity。
寻找替换点
从启动Activity的流程一步步追寻, 发现检查Activity的操作发生再AMS中,如果在进入AMS之前,我们就将Activity替换为ProxyActivity,那么AMS检查将会通过,则不会抛出异常。
寻找还原点
启动Activity的流程中, AMS检查完成之后会调ActivityThread的方法创建Activity的对象和回调生命周期方法。所以要在创建对象之前,将ProxyActivity还原为未注册的Activity。
替换点代码实现
/**
* 要在执行 AMS之前,替换可用的 Activity,替换在AndroidManifest里面配置的Activity
*/
private void hookAmsAction() throws Exception {
// 动态代理
Class mIActivityManagerClass = Class.forName("android.app.IActivityManager");
// 我们要拿到IActivityManager对象,才能让动态代理里面的 invoke 正常执行下
// 执行此方法 static public IActivityManager getDefault(),就能拿到 IActivityManager
Class mActivityManagerNativeClass2 = Class.forName("android.app.ActivityManagerNative");
final Object mIActivityManager = mActivityManagerNativeClass2.getMethod("getDefault").invoke(null);
// 本质是IActivityManager
Object mIActivityManagerProxy = Proxy.newProxyInstance(
HookApplication.class.getClassLoader(),
new Class[]{mIActivityManagerClass}, // 要监听的接口
new InvocationHandler() { // IActivityManager 接口的回调方法
/**
* @param proxy
* @param method IActivityManager里面的方法
* @param args IActivityManager里面的参数
* @return
* @throws
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("startActivity".equals(method.getName())) {
// 做自己的业务逻辑
// 换成 可以 通过 AMS检查的 ProxyActivity
// 用ProxyActivity 绕过了 AMS检查
Intent intent = new Intent(HookApplication.this, ProxyActivity.class);
intent.putExtra("actionIntent", ((Intent) args[2])); // 把之前TestActivity保存 携带过去
args[2] = intent;
}
Log.d("hook", "拦截到了IActivityManager里面的方法" + method.getName());
// 让系统继续正常往下执行
return method.invoke(mIActivityManager, args);
}
});
/**
* 为了拿到 gDefault
* 通过 ActivityManagerNative 拿到 gDefault变量(对象)
*/
Class mActivityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
Field gDefaultField = mActivityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true); // 授权
Object gDefault = gDefaultField.get(null);
// 替换点
Class mSingletonClass = Class.forName("android.util.Singleton");
// 获取此字段 mInstance
Field mInstanceField = mSingletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true); // 让虚拟机不要检测 权限修饰符
// 替换
mInstanceField.set(gDefault, mIActivityManagerProxy); // 替换是需要gDefault
}
还原点代码实现
/**
* Hook LuanchActivity
*/
private void hookLuanchActivity() throws Exception {
Field mCallbackFiled = Handler.class.getDeclaredField("mCallback");
mCallbackFiled.setAccessible(true); // 授权
/**
* handler对象怎么来
* 1.寻找H,先寻找ActivityThread
*
* 执行此方法 public static ActivityThread currentActivityThread()
*
* 通过ActivityThread 找到 H
*
*/
Class mActivityThreadClass = Class.forName("android.app.ActivityThread");
// 获得ActivityThrea对象
Object mActivityThread = mActivityThreadClass.getMethod("currentActivityThread").invoke(null);
Field mHField = mActivityThreadClass.getDeclaredField("mH");
mHField.setAccessible(true);
// 获取真正对象
Handler mH = (Handler) mHField.get(mActivityThread);
mCallbackFiled.set(mH, new MyCallback(mH)); // 替换 增加我们自己的实现代码
}
public static final int LAUNCH_ACTIVITY = 100;
class MyCallback implements Handler.Callback {
private Handler mH;
public MyCallback(Handler mH) {
this.mH = mH;
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY:
// 做我们在自己的业务逻辑(把ProxyActivity 换成 TestActivity)
Object obj = msg.obj;
try {
// 我们要获取之前Hook携带过来的 TestActivity
Field intentField = obj.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
// 获取 intent 对象,才能取出携带过来的 actionIntent
Intent intent = (Intent) intentField.get(obj);
// actionIntent == TestActivity的Intent
Intent actionIntent = intent.getParcelableExtra("actionIntent");
if (actionIntent != null) {
if (activityList.contains(actionIntent.getComponent().getClassName())) {
intentField.set(obj, actionIntent); // 把ProxyActivity 换成 TestActivity
} else { // 没有权限
intentField.set(obj, new Intent(HookApplication.this, PermissionActivity.class));
}
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
mH.handleMessage(msg);
// 让系统继续正常往下执行
// return false; // 系统就会往下执行
return true; // 系统不会往下执行
}
}
调用hook方法
public class HookApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
hookAmsAction();
} catch (Exception e) {
e.printStackTrace();
Log.d("hook", "hookAmsAction 失败 e:" + e.toString());
}
try {
hookLuanchActivity();
} catch (Exception e) {
e.printStackTrace();
Log.d("hook", "hookLuanchActivity 失败 e:" + e.toString());
}
}
}