android实现启动未声明的Activity

实现原理:首先创建一个占位StubActivity,这个Activity必须要添加声明,用来代替目标的Activity,然后在ActivityThread中的Handler回调中替换掉原来的Callback,改为自己的Callback,并在此修改成自己要启动的真正的Activity,最后启动StubActivity,在启动intent里面放进目标intent,等最后取出目标intent替换原来的intent即可。

另一个问题是,如何加载其它apk或dex文件中的activity?其实这个也很简单,先加载dex文件,得到一个ClassLoader,然后用这个类加载器替换LoadedApk中的ClassLoader,然后就能加载dex文件中的activity对象,用完记着换回去。

最后一个问题是,要实现在任何地方都能启动未注册的Activity,当然也包括正常的Activity,要实现的这样的目的,就需要拦截activity启动过程,我们直接hook掉系统的IActivityManager中的启动对象即可,IActivityManager(Android10以后是IActivityTaskManager)中有一个叫做Singleton的对象,这个对象里有个泛型参数,放的是IActivityManager或者IActivityTaskManager对象,替换成我们自己的代理对象,即可拦截系统AMS服务所有调用,比如拦截startActivity等。

完整代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    private ClassLoader mDexClassLoader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        findViewById(R.id.bn_start1).setOnClickListener(this);
        findViewById(R.id.bn_start2).setOnClickListener(this);

        HookHelper.getInstance().init(this).setHookEnabled(true);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bn_start1: //启动本地Activity测试
                //方式一,主动启动
                Intent intent = new Intent(this, TargetActivity.class);
                intent.putExtra("arg1", "123456"); //携带参数测试
                HookHelper.startActivity(this, intent);

                //方式二,被动拦截
                HookHelper.getInstance().hookAMS(true);
                startActivity(new Intent(this, TargetActivity.class));
                break;
            case R.id.bn_start2: //启动远程Activity测试
                HookHelper.getInstance().hookAMS(false);
                startRemoteActivity();
                break;
        }
    }

    /* 启动远程Activity */
    private void startRemoteActivity() {
        try {
            ClassLoader loader = getDexClassLoader();
            //替换系统默认ClassLoader为加载后的ClassLoader
            HookHelper.getInstance().changeClassLoader(loader);
            //获取远程Activity
            Class RemoteActivity = loader.loadClass("com.zwxuf.remotemodule.RemoteActivity");
            Intent intent = new Intent(this, RemoteActivity);
            HookHelper.startActivity(this, intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private ClassLoader getDexClassLoader() {
        if (mDexClassLoader == null) {
            try {
                ApplicationInfo info = getPackageManager().getApplicationInfo("com.zwxuf.remotemodule", 0);
                mDexClassLoader = new DexClassLoader(info.sourceDir, info.sourceDir + ".tmp", null, getClassLoader());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return mDexClassLoader;
    }
}
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.util.Log;

import androidx.annotation.NonNull;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

public class HookHelper {

    private static final String TAG = HookHelper.class.getSimpleName();

    public static HookHelper mInstance;

    private Object mOrigCallback;
    private ClassLoader mOrigClassLoader;
    private Object mLoadedApk;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private boolean mHookAMSEnabled;
    private Object mOrigAMS;

    public static HookHelper getInstance() {
        if (mInstance == null) {
            mInstance = new HookHelper();
        }
        return mInstance;
    }

    private HookHelper() {
    }

    public HookHelper init(Context context) {
        try {
            //保存LoadedApk对象
            if (mLoadedApk == null) {
                Field mLoadedApkField = Application.class.getDeclaredField("mLoadedApk");
                mLoadedApkField.setAccessible(true);
                mLoadedApk = mLoadedApkField.get((Application) context.getApplicationContext());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return this;
    }

    /**
     * 启用禁用hook
     *
     * @param enabled
     */
    public void setHookEnabled(boolean enabled) {
        if (enabled == (mOrigCallback != null)) {
            return;
        }
        try {
            Class<?> ActivityThread = Class.forName("android.app.ActivityThread");
            Field sCurrentActivityThreadFiled = ActivityThread.getDeclaredField("sCurrentActivityThread");
            sCurrentActivityThreadFiled.setAccessible(true);
            Object sCurrentActivityThread = sCurrentActivityThreadFiled.get(null);
            Field mHField = ActivityThread.getDeclaredField("mH");
            mHField.setAccessible(true);
            Handler mH = (Handler) mHField.get(sCurrentActivityThread);
            Field mCallbackField = Handler.class.getDeclaredField("mCallback");
            mCallbackField.setAccessible(true);
            Object mCallback = mCallbackField.get(mH);
            if (enabled) {
                mOrigCallback = mCallback;
                mCallbackField.set(mH, new ProxyCallback());
            } else {
                mCallbackField.set(mH, mOrigCallback);
                mOrigCallback = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private class ProxyCallback implements Handler.Callback {

        @Override
        public boolean handleMessage(@NonNull Message msg) {
            if (msg.what == 100) { // LAUNCH_ACTIVITY
                try {
                    Object record = msg.obj;
                    Field intentField = record.getClass().getDeclaredField("intent");
                    intentField.setAccessible(true);
                    Intent intent = (Intent) intentField.get(record);
                    if (intent != null) restoreTargetIntent(intent);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        restoreClassLoader(); //恢复类加载器
                    }
                }, 500);
            } else if (msg.what == 159) { // LAUNCH_ACTIVITY
                try {
                    Object record = msg.obj;
                    Field fCallbacks = record.getClass().getDeclaredField("mActivityCallbacks");
                    fCallbacks.setAccessible(true);
                    List<?> lists = (List) fCallbacks.get(record);
                    if (lists != null) {
                        for (int i = 0; i < lists.size(); i++) {
                            Object item = lists.get(i);
                            Class itemClazz = item.getClass();
                            try {
                                Field mIntent = itemClazz.getDeclaredField("mIntent");
                                mIntent.setAccessible(true);
                                Intent intent = (Intent) mIntent.get(item);
                                if (intent != null) restoreTargetIntent(intent);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        restoreClassLoader(); //恢复类加载器
                    }
                }, 500);
            }
            return false;
        }
    }

    /**
     * 恢复目标intent
     *
     * @param intent
     */
    private static void restoreTargetIntent(Intent intent) {
        Intent targetIntent = intent.getParcelableExtra("targetIntent");
        if (targetIntent != null) {
            Parcel parcel = Parcel.obtain();
            targetIntent.writeToParcel(parcel, 0);
            parcel.setDataPosition(0);
            intent.readFromParcel(parcel);
            parcel.recycle();
        }
    }

    /**
     * 启动未注册的Activity
     *
     * @param context
     * @param intent
     */
    public static void startActivity(Context context, Intent intent) {
        Intent baseIntent = new Intent(context, StubActivity.class); //占位intent
        baseIntent.putExtra("targetIntent", intent); //存储目标intent
        context.startActivity(baseIntent);
    }

    public void changeClassLoader(ClassLoader loader) {
        ClassLoader mOldClassLoader = replaceClassLoader(loader);
        if (mOrigClassLoader == null) {
            mOrigClassLoader = mOldClassLoader;
        }
    }

    public void restoreClassLoader() {
        if (mOrigClassLoader != null) {
            replaceClassLoader(mOrigClassLoader);
            mOrigClassLoader = null;
        }
    }

    private ClassLoader replaceClassLoader(ClassLoader loader) {
        try {
            Field mClassLoaderField = mLoadedApk.getClass().getDeclaredField("mClassLoader");
            mClassLoaderField.setAccessible(true);
            ClassLoader oldClassLoader = (ClassLoader) mClassLoaderField.get(mLoadedApk);
            mClassLoaderField.set(mLoadedApk, loader);
            Log.i(TAG, "replaceClassLoader success");
            return oldClassLoader;
        } catch (Exception e) {
            Log.e(TAG, "replaceClassLoader:" + e.toString());
        }
        return null;
    }

    /**
     * 拦截AMS服务
     *
     * @param enabled
     */
    public void hookAMS(boolean enabled) {
        if (enabled == mHookAMSEnabled) return;
        try {
            Class parentClass = Class.forName("android.util.Singleton");
            Field mField = parentClass.getDeclaredField("mInstance");
            mField.setAccessible(true);
            Class hookClass;
            Object mSingleton;
            if (Build.VERSION.SDK_INT < 29) {
                hookClass = Class.forName("android.app.IActivityManager");
                mSingleton = getAMSingleton();
            } else {
                //android10以上
                hookClass = Class.forName("android.app.IActivityTaskManager");
                mSingleton = getATMSingleton();
            }
            if (enabled) {
                mOrigAMS = mField.get(mSingleton);
                InvocationHandlerProxy handlerProxy = new InvocationHandlerProxy(mOrigAMS);
                Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                        new Class<?>[]{hookClass},
                        handlerProxy);
                mField.set(mSingleton, proxy);
            }else {
                mField.set(mSingleton, mOrigAMS);
            }
            mHookAMSEnabled = enabled;
            Log.i(TAG, "hookAMS:" + enabled);
        } catch (Exception e) {
            Log.e(TAG, "hookAMS:" + e.toString());
        }
    }

    /**
     * 代理对象处理器
     */
    public class InvocationHandlerProxy implements InvocationHandler {

        Object original; //原始对象

        public InvocationHandlerProxy(Object original) {
            this.original = original;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("startActivity")) {
                if (args != null && args.length > 0) {
                    int index = -1;
                    for (int i = 0; i < args.length; i++) {
                        if (args[i] instanceof Intent) {
                            index = i;
                            break;
                        }
                    }
                    if (index != -1) {
                        Intent targetIntent = (Intent) args[index];
                        Intent intent = new Intent();
                        intent.putExtra("targetIntent", targetIntent);
                        intent.setClassName("com.zwxuf.mydemo", StubActivity.class.getName());
                        args[index] = intent;
                        Log.i(TAG, "replace intent success");
                    }
                }
            }
            return method.invoke(original, args);
        }
    }

    private Object getAMSingleton() {
        try {
            Class<?> CActivityManager = Class.forName("android.app.ActivityManager");
            Field FSingleton = CActivityManager.getDeclaredField("IActivityManagerSingleton");
            FSingleton.setAccessible(true);
            return FSingleton.get(null);
        } catch (Exception e) {
            Log.e(TAG, "getSingleton:" + e.toString());
        }
        return null;
    }

    private static Object getATMSingleton() {
        try {
            Class<?> CActivityTaskManager = Class.forName("android.app.ActivityTaskManager");
            Field FSingleton = CActivityTaskManager.getDeclaredField("IActivityTaskManagerSingleton");
            FSingleton.setAccessible(true);
            return FSingleton.get(null);
        } catch (Exception e) {
            Log.e(TAG, "getSingleton:" + e.toString());
        }
        return null;
    }

}
public class TargetActivity extends AppCompatActivity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_target);

        Intent intent = getIntent();
        String value = intent.getStringExtra("arg1");
        Log.i("WALX", String.valueOf(value));
    }
}

 

猜你喜欢

转载自blog.csdn.net/zzmzzff/article/details/131485356
今日推荐