Activity免注册跳转

原创 2017年06月25日 21:15:45

要实现免注册跳转需要解决的问题:

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 显示找不到




版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010945409/article/details/73728338

Android之免清单注册启动Activity

在此立志:我要努力大学毕业进BAT 实习目标:Activity不需要注册在清单即可通过intent启动。有些文章叫做hook技术。大致内容为监听方法或者的调用或触发,期间修改方法参数或者返回值达到无...
  • qfanmingyiq
  • qfanmingyiq
  • 2017-10-12 16:29:53
  • 971

Android插件化系列第(一)篇---Hook技术之Activity的启动过程的拦截

这篇文章主要讲解如何利用动态代理技术Hook掉系统的AMS服务,来实现拦截Activity的启动流程。代码量不是很多,为了更容易的理解,需要掌握JAVA的反射,动态代理技术,以及Activity的启动...
  • u013263323
  • u013263323
  • 2017-02-09 14:07:23
  • 2621

Activity免注册跳转

要实现免注册跳转需要解决的问题: 1、未注册的activity怎么通过系统验证 2、怎么在handleMessage中监听 LAUNCH_ACTIVITY 的消息 解决的方法 1、使用动态代理...
  • u010945409
  • u010945409
  • 2017-06-25 21:15:45
  • 291

Android Kotlin Activity已经注册为什么找不到?问题解决

初识Kotlin,赶紧来体验一把,愉快的写了下面的代码,准备跳转到另外一个界面 fun goMain(view: View) { var intent = Intent(this, L...
  • u010399316
  • u010399316
  • 2017-07-18 12:31:05
  • 541

android数据传递(二)之activity带返回值的跳转,模拟登陆注册

这篇博客实现的逻辑是带返回值的跳转, 从ActivityA跳转到ActivityB,然后结束ActivityB后带返回值到ActivityA。下图就是运行的结果,模拟登陆注册 Activity...
  • dl10210950
  • dl10210950
  • 2016-07-30 16:26:39
  • 12198

不需要在清单文件中注册的Acrivity的启动方式--Hook技术

最近发现自己的技术很欠缺所以看了一些真正大神级别的开发者的直播课比如什么华为的定制开发项目经理啊、什么担任过腾讯的什么经理啊等等的我认为的大神(不知道别人怎么认为啊) 好了废话不多说,开始说说今天...
  • songxin393764941
  • songxin393764941
  • 2016-12-29 16:37:17
  • 792

关于Activity和intent事件的注册

在AndroidManifest.xml文件中的元素中有这么两句:           你知道中间的两句话都是什么含义么? www.2cto.com 当写好的应用发布到手机上之后,当双击该应用的图...
  • jinguangyang
  • jinguangyang
  • 2017-03-09 18:36:16
  • 161

android.content.ActivityNotFoundException:

错误信息中提醒我们,没有任何一个活动可以响应我们的 Intent,为什么呢?这是因为 我们刚刚在 Intent 中新增了一个 category,而 SecondActivity 的标签中并没有声 明可...
  • pengweid
  • pengweid
  • 2016-10-22 11:52:02
  • 951

新添的Activity 要在 manifest 中注册 否则界面跳转时会崩掉

android:name=".文件名(注意点名的点)"             android:label="@string/app_name" >                ...
  • sugesi
  • sugesi
  • 2017-09-26 01:34:47
  • 80

【总结】在两个Activity之间进行跳转时出错原因分析(二)——在AndroidManifest.xml未声明导致

这是一个比较常见的原因,很多人在两个Activity之间进行跳转时,往往是由于未在AndroidManifest.xml中声明相应的Activity而导致出错。 ...
  • chjr1000
  • chjr1000
  • 2013-11-22 20:40:27
  • 4099
收藏助手
不良信息举报
您举报文章:Activity免注册跳转
举报原因:
原因补充:

(最多只允许输入30个字)