美文网首页
插件化Hook Activity

插件化Hook Activity

作者: xqiiitan | 来源:发表于2024-07-08 16:33 被阅读0次

插件化架构介绍

简介:点击按钮,去服务器下载一个功能.apk, 保存到本地。
它没有运行是单独的plugin,我们要把它启动起来,并给它传递参数。

  • 启动的插件Activity,是没有在主app中注册的。绕过Manifest的检测。
  • 类需要加载,插件的Activity的类是在插件中,
  • 资源需要加载,

2.Hook启动流程 startActivity: 动态代理,下钩子函数。

基于动态代理设计模式,基于Activity启动流程。 IActivityManager
MVP,RXJava 都使用了代理。
用一个注册了的ProxyActivity占坑,让ProxyActivity去过安检。真实的Activity不过安检,后面将intent替换回来。

2.1 获取ActivityManagerNative里面的IActivityManagerSingleton( 旧版本gDefault)
2.2 获取IActivityManagerSingleton( 旧版本gDefault) 中的 IActivityManagerSingleton(旧版本mInstance)属性。
2.3 用一个注册了的ProxyActivity占坑,让ProxyActivity去过安检。
2.4 将intent换回来,换成原来的。
- 2.4.1 获取 ActivityThread 实例;
- 2.4.2 获取 ActivityThread中的mH。
- 2.4.3 hook handleLaunchActivity.

@Hide
public abstract class Singleton<T> {
    @UnsupportedAppUsage
    public Singleton() {
    }
    @UnsupportedAppUsage
    private T mInstance;
    protected abstract T create();
    @UnsupportedAppUsage
    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}
// Handler
public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) { // mCallback 非空的情况下。
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
} 

public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        HookStartActivityUtil hookUtil = new HookStartActivityUtil(this, ProxyActivity.class);
        try {
            hookUtil.hookStartActivity();
            hookUtil.hookLaunchActivity();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

// 主app中页面,跳转到 插件化未注册的TestActivity。
public void jumpPage(View view) {
    try {
        Intent intent = new Intent();
        intent.setClass(this, Class.forName("com.tom.hook.TestActivity"));
        intent.putExtra("user_name", "zhangSan");
        startActivity(intent);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}
   
/**
 * Added by Tom on 2024/07/09.
 * 代理过检测的Activity
 */
public class ProxyActivity extends Activity {
}
package com.tom.hook;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Added by Tom on 2024/07/09.
 */
public class HookStartActivityUtil {
    private static final String TAG = "HookStartActivityUtil";
    private Context mContext;
    private Class<?> mProxyClass; // 用来过安检的类。已经注册过的类。
    private final String EXTRA_ORIGIN_INTENT = "EXTRA_ORIGIN_INTENT";

    public HookStartActivityUtil(Context context, Class<?> proxyClass) {
        this.mContext = context.getApplicationContext();
        this.mProxyClass = proxyClass;
    }

    public void hookStartActivity() throws Exception {
        Object singleTon = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            @SuppressLint("PrivateApi")
            Class<?> activityManagerClass = Class.forName("android.app.ActivityTaskManager");
            Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("IActivityTaskManagerSingleton");
            iActivityManagerSingletonField.setAccessible(true);
            singleTon = iActivityManagerSingletonField.get(null);
            Log.d(TAG, "singleTon:" + singleTon.toString());
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            /*
             * android 26或以上版本的API是一样的
             */
            Class<?> activityManagerClass = Class.forName("android.app.ActivityManager");
            Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("IActivityManagerSingleton");
            iActivityManagerSingletonField.setAccessible(true);
            singleTon = iActivityManagerSingletonField.get(null);
        } else {
            /*
             *  android 26或以下版本的API是一个系列
             */
            Class<?> activityManagerClass = Class.forName("android.app.ActivityManagerNative");
            Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("gDefault");
            iActivityManagerSingletonField.setAccessible(true);
            singleTon = iActivityManagerSingletonField.get(null);
            // 2.1 获取ActivityManagerNative里面的IActivityManagerSingleton( 旧版本gDefault)
            // 2.2 获取属性: IActivityTaskManagerSingleton(旧版本 gDefault)属性。
        }
        // 2.3 通过gDefault的mInstance属性,获取

        // 而实际上AMS在单例Singleton中
        Class<?> singletonClazz = Class.forName("android.util.Singleton");
        Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
        mInstanceField.setAccessible(true);
        Object iamInstance = mInstanceField.get(singleTon); // AMS
        if (iamInstance == null) Log.e(TAG, "iamInstance is null!!!");

        Class<?> iActivityManagerClass;
        // 因为生成的接口类变了,所以这里我们需要根据版本来代理不同的接口class
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // android10+ 代理IActivityTaskManager
            iActivityManagerClass = Class.forName("android.app.IActivityTaskManager");
        } else {
            // android10- 代理IActivityManager
            iActivityManagerClass = Class.forName("android.app.IActivityManager");
        }
        iamInstance = Proxy.newProxyInstance(HookStartActivityUtil.class.getClassLoader(),
                new Class[]{iActivityManagerClass},
                // InvocationHandler 执行者,
                new StartActivityInvocationHandler(iamInstance));
        // 4. 重新设定, 重新设定为我们的代理。
        mInstanceField.set(singleTon, iamInstance);
    }

    // 动态代理
    private class StartActivityInvocationHandler implements InvocationHandler {
        // 方法真正的执行者。高版本API中,TODO 拿到的这个值为null。可使用腾讯的Shadow 插件化框架。
        private Object mObject;
        public StartActivityInvocationHandler(Object object) {
            this.mObject = object;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.e(TAG, "method: " + method.getName());
            // 替换intent,过AndroidManifest.xml 的检测
            if (method.getName().equals("startActivity")) {
                // 1.获取原来intent替换,最后启动的时候再替换回来。
                Intent originIntent = (Intent) args[2];
                // 2.使用安全的intent替换。去安检。
                Intent safeIntent = new Intent(mContext, mProxyClass);
                args[2] = safeIntent;
                // 3.绑定原来的(缓存原来的Activity)
                safeIntent.putExtra(EXTRA_ORIGIN_INTENT, originIntent);
            }
            return method.invoke(mObject, args);
        }
    }

    // hook handler(ActivityManager.mH)
    public void hookLaunchActivity() throws Exception {
        // 2.4.1 获取 ActivityThread 实例;
        Class<?> atClass = Class.forName("android.app.ActivityThread");
        Field scatField = atClass.getField("sCurrentActivityThread");
        scatField.setAccessible(true);
        Object sCurrentActivityThread = scatField.get(null);

        // 2.4.2 获取  ActivityThread中的mH。
        Field mHField = atClass.getDeclaredField("mH");
        mHField.setAccessible(true);
        Handler mHandler = (Handler) mHField.get(sCurrentActivityThread);

        // 2.4.3 hook  handleLaunchActivity.
        // 给Handler 设置Callback
        Class<?> handlerClass = Class.forName("android.os.Handler");
        Field mCallback = handlerClass.getDeclaredField("mCallback");
        mCallback.setAccessible(true);
        mCallback.set(mHandler, new HandlerCallback());
    }

    private class HandlerCallback implements Handler.Callback {
        @Override
        public boolean handleMessage(Message msg) {
            // 每发一个消息,都会走handleMessage 方法一次。
            if (msg.what == 100) {
                handleLaunchActivity(msg);
            }
            return false;
        }

        // 开始启动创建Activity 拦截,将intent还回去。
        private void handleLaunchActivity(Message msg) {
            try {
                Object record = msg.obj;
                // 1.从record 中拿过安检的intent
                Field intentField = record.getClass().getDeclaredField("intent");
                intentField.setAccessible(true);
                Intent safeIntent = (Intent) intentField.get(record);

                // 2.从safeIntent中, 获取原来的originIntent
                Intent originIntent = safeIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
                // 3.重新设置回去intent。
                if (originIntent != null) {
                    intentField.set(record, originIntent);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

相关文章

网友评论

      本文标题:插件化Hook Activity

      本文链接:https://www.haomeiwen.com/subject/lumvcjtx.html