Activity免註冊跳轉

要實現免註冊跳轉需要解決的問題:

1、未註冊的activity怎麼通過系統驗證

2、怎麼在handleMessage中監聽 LAUNCH_ACTIVITY 的消息



解決的方法

1、使用動態代理activity替換未註冊activity,使其通過系統驗證

2、hook到ActivityThread、mH變量、H類;在Callback中監聽 LAUNCH_ACTIVITY 的消息



//第一步:

	Class<?> clazz = Class.forName("android.app.ActivityManagerNative");
        //第一種 方式獲取 通過gDefault
        Field gDefault = clazz.getDeclaredField("gDefault");
        gDefault.setAccessible(true);
        //靜態類型字段不用傳入所屬對象
        Object defaultValue = gDefault.get(null);
        Class<?> aClass = Class.forName("android.util.Singleton");
        Field mInstace = aClass.getDeclaredField("mInstance");
        mInstace.setAccessible(true);
        Object iActivityManagerValue = mInstace.get(defaultValue);
//        第二種方式
//        Method getDefault = clazz.getDeclaredMethod("getDefault"); //獲取的是子類 ActivityManagerProxy 
//        getDefault.setAccessible(true);
//        //獲取主線程對象
//        Object defaultValue = getDefault.invoke(null);
//        Class<?> aClass = Class.forName("android.util.Singleton");
//        Field mInstace = aClass.getDeclaredField("mInstance");
//        mInstace.setAccessible(true);
//        Object iActivityManagerValue = mInstace.get(defaultValue); //不能獲取
//創建新的接口對象
          Class<?> iActivityManagerProxy = Class.forName("android.app.IActivityManager");      
          AmsInvocationHandler handler = new AmsInvocationHandler(iActivityManagerValue);     
          Object IActivityManager = Proxy.newProxyInstance(context.getClassLoader(), new Class[]{iActivityManagerProxy}, handler);
//        替換掉原有的IActivityManager      
           mInstace.set(defaultValue, IActivityManager);



        
/**
 * 攔截未註冊的Activity ,替換爲已 註冊代理Activity
 */

 class AmsInvocationHandler implements InvocationHandler {

        private Object iActivityManagerValue;

        public AmsInvocationHandler(Object iActivityManagerValue) {
            this.iActivityManagerValue = iActivityManagerValue;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//          替換系統方法
            if ("startActivity".contains(method.getName())) {

                int index = 0;
                for (int i = 0; i < args.length; i++) {
                    //找到 參數中的意圖
                    if (args[i] instanceof Intent) {
                        index = i;//非法意圖的索引
                        break;
                    }
                }

                for (int i = 0; i < args.length; i++) {
                    Log.e("tag", "args:" + args[i]);
                }

                Intent proxyIntnet = new Intent();
                ComponentName cn = new ComponentName(context, proxyActivity);
                proxyIntnet.setComponent(cn);
                //將 非法的意圖附帶在合法的意圖中 作爲參數
                proxyIntnet.putExtra("oldIntent", (Intent)args[index]);
                args[index] = proxyIntnet;
                return method.invoke(iActivityManagerValue, args);
            }

            return method.invoke(iActivityManagerValue, args);
        }
    }
//第二步:
 // 獲取到回調 使用插件意圖 替換
    public void hookSystemHandler() {
        try {

            Class<?> aClass = Class.forName("android.app.ActivityThread");

            //獲取ActivityThread 方式一 (api17 以上適用)

//            Field sCurrentActivityThread = aClass.getDeclaredField("sCurrentActivityThread");
//            sCurrentActivityThread.setAccessible(true);
//            ActivityThreadValue = sCurrentActivityThread.get(null);
//            獲取ActivityThread 方式二 
            Method currentActivityThreadMethod = aClass.getDeclaredMethod("currentActivityThread");
            currentActivityThreadMethod.setAccessible(true);
            //獲取主線程對象
            Object activityThread = currentActivityThreadMethod.invoke(null);
            //ActivityThread 的mH字段
            Field mH = aClass.getDeclaredField("mH");
            mH.setAccessible(true);
            Handler handlerObject = (Handler) mH.get(activityThread);
            //獲取H類中mCallback字段

            Field mCallbackField = Handler.class.getDeclaredField("mCallback");
            mCallbackField.setAccessible(true);

		//將處理後的 Handler對象替換系統的
mCallbackField.set(handlerObject, new ActivityThreadHandlerCallback(handlerObject));
     } catch (ClassNotFoundException e) {   
         e.printStackTrace();     
   } catch (IllegalAccessException e) {  
          e.printStackTrace();     
   } catch (NoSuchFieldException e) {    
        e.printStackTrace();      
  } catch (NoSuchMethodException e) {         
   e.printStackTrace();      
  } catch (InvocationTargetException e) {   
         e.printStackTrace();    
    }  
  }  
  class ActivityThreadHandlerCallback implements Handler.Callback {   
     Handler handler;     
   public ActivityThreadHandlerCallback(Handler handler) { 
           super();        
    this.handler = handler;      
  }        @Override       
 public boolean handleMessage(Message msg) {   
         //把非法intent替換回來        
    if (msg.what == 100) {         
       try {              
      handleLaunchActivity(msg);    
            } catch (NoSuchFieldException e) {     
               e.printStackTrace();           
     } catch (IllegalAccessException e) {     
               e.printStackTrace();          
      }    
        }        
    handler.handleMessage(msg);  
          return true;      
  }  
  }
	//替換原有的驗證前的合法意圖
    private void handleLaunchActivity(Message msg) throws NoSuchFieldException, IllegalAccessException {
        Object obj = msg.obj; //獲取當前ActivityRecord的記錄信息
        Field intentField = obj.getClass().getDeclaredField("intent");
        intentField.setAccessible(true);

        Intent proxyIntent = (Intent) intentField.get(obj);
        Intent oldIntent = proxyIntent.getParcelableExtra("oldIntent");

        //判斷如果使用的動態代理,就使用插件intent替換掉
        if (oldIntent != null) {
            proxyIntent.setComponent(oldIntent.getComponent());
        }
    }

//第三步
在Application中調用
AmsUtils amsUtils = new AmsUtils(ProxyActivity.class, this);
amsUtils.hookSystemHandler();
try {
    amsUtils.hookAms();
} catch (Exception e) {
    e.printStackTrace();
}





1、api18 以下沒有 sCurrentActivityThread 靜態變量,但是都有一個 靜態方法 currentActivityThread 返回值爲 ActivityThread,可以通過返回值 獲取

2、未註冊的類(OtherActivity)只能直接繼承自Activity才能正常跳轉,繼承AppCompatActivity 顯示找不到




發佈了49 篇原創文章 · 獲贊 17 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章