博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android插件化架构 拦截Activity的启动流程绕过AndroidManifest检测
阅读量:6433 次
发布时间:2019-06-23

本文共 5923 字,大约阅读时间需要 19 分钟。

1. 概述


  了解了Java的动态代理设计模式之后,配合上一期的文章,那么接下来就需要亲自操刀去拦截Activity的启动流程了。前面好事没少干,那么现在就来干干坏事,到底怎样才能让没有注册的Activity启动不报错呢?答案就是Hook下钩子。   

2. Hook启动流程


  怎么样去找Hook点是个问题,把钩子下在哪里呢?一般的套路肯定最好是静态,然后是接口,配合反射注入就可以了。Activity启动流程的源码我就不再贴了,如果不了解请移步这里,我这里直接下钩子。

/**     * hook start activity     */    public void hookStartActivity() throws Exception{        // 先获取ActivityManagerNative中的gDefault        Class
amnClazz = Class.forName("android.app.ActivityManagerNative"); Field defaultField = amnClazz.getDeclaredField("gDefault"); defaultField.setAccessible(true); Object gDefaultObj = defaultField.get(null); // 获取Singleton里面的mInstance Class
singletonClazz = Class.forName("android.util.Singleton"); Field amsField = singletonClazz.getDeclaredField("mInstance"); amsField.setAccessible(true); Object amsObj = amsField.get(gDefaultObj); // 动态代理Hook下钩子 amsObj = Proxy.newProxyInstance(mContext.getClass().getClassLoader(), amsObj.getClass().getInterfaces(), new StartActivityInvocationHandler(amsObj)); // 注入 amsField.set(gDefaultObj,amsObj); } /** * Start Activity Invocation Handler */ private class StartActivityInvocationHandler implements InvocationHandler{ private Object mAmsObj; public StartActivityInvocationHandler(Object amsObj){ this.mAmsObj = amsObj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 拦截到所有ActivityManagerService的方法 Log.e("TAG","methodName"+method.getName()); return method.invoke(mAmsObj,args); } }复制代码

3. 借尸还魂


  上面我们已经拦截到了Activity的启动了,也能够看到startActivity方法的打印。但是如果不做任何处理还是会蹦,那么我们需要有一个Activity预先在AndroidMnifest.xml中注册一下,它是不怕太阳的,通过它可以做到借尸还魂。

/**     * Start Activity Invocation Handler     */    private class StartActivityInvocationHandler implements InvocationHandler{        private Object mAmsObj;        public StartActivityInvocationHandler(Object amsObj){            this.mAmsObj = amsObj;        }        @Override        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {            // 拦截到所有ActivityManagerService的方法            Log.e("TAG","methodName"+method.getName());            if(method.getName().equals("startActivity")){                // 启动Activity的方法,找到原来的Intent                Intent realIntent = (Intent) args[2];                // 代理的Intent                Intent proxyIntent = new Intent();                proxyIntent.setComponent(new ComponentName(mContext,mProxyActivity));                // 把原来的Intent绑在代理Intent上面                proxyIntent.putExtra("realIntent",realIntent);                // 让proxyIntent去晒太阳,借尸                args[2] = proxyIntent;            }            return method.invoke(mAmsObj,args);        }    }复制代码

还魂

/**     * hook Launch Activity     */    public void hookLaunchActivity() throws Exception{        // 获取ActivityThread        Class
activityThreadClazz = Class.forName("android.app.ActivityThread"); Field sCurrentActivityThreadField = activityThreadClazz.getDeclaredField("sCurrentActivityThread"); sCurrentActivityThreadField.setAccessible(true); Object sCurrentActivityThreadObj = sCurrentActivityThreadField.get(null); // 获取Handler mH Field mHField = activityThreadClazz.getDeclaredField("mH"); mHField.setAccessible(true); Handler mH = (Handler) mHField.get(sCurrentActivityThreadObj); // 设置Callback Field callBackField = Handler.class.getDeclaredField("mCallback"); callBackField.setAccessible(true); callBackField.set(mH, new ActivityThreadHandlerCallBack()); } class ActivityThreadHandlerCallBack implements Handler.Callback { @Override public boolean handleMessage(Message msg) { if (msg.what == LAUNCH_ACTIVITY) { handleLaunchActivity(msg); } return false; } } // 还魂 private void handleLaunchActivity(Message msg) { // final ActivityClientRecord r = (ActivityClientRecord) msg.obj; try { Object obj = msg.obj; Field intentField = obj.getClass().getDeclaredField("intent"); intentField.setAccessible(true); Intent proxyIntent = (Intent) intentField.get(obj); // 代理意图 Intent originIntent = proxyIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT); if (originIntent != null) { // 替换意图 intentField.set(obj, originIntent); } } catch (Exception e) { e.printStackTrace(); } }复制代码

4. 兼容AppCompatActivity


  继承自Activity是百试百灵,再也不需要在AndroidMnifest中注册了,但是发现继承AppCompatActivity还是会报错,我都不记得当时是怎么解决这个问题的,反正搞了好几天,我选择遗忘那段操蛋的时光。

// 兼容AppCompatActivity报错问题    Class
forName = Class.forName("android.app.ActivityThread"); Field field = forName.getDeclaredField("sCurrentActivityThread"); field.setAccessible(true); Object activityThread = field.get(null); Method getPackageManager = activityThread.getClass().getDeclaredMethod("getPackageManager"); Object iPackageManager = getPackageManager.invoke(activityThread); PackageManagerHandler handler = new PackageManagerHandler(iPackageManager); Class
iPackageManagerIntercept = Class.forName("android.content.pm.IPackageManager"); Object proxy = newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class
[]{iPackageManagerIntercept}, handler); // 获取 sPackageManager 属性 Field iPackageManagerField = activityThread.getClass().getDeclaredField("sPackageManager"); iPackageManagerField.setAccessible(true); iPackageManagerField.set(activityThread, proxy);复制代码

  总算走出了插件化架构的一小步,过程对于一般人来讲还是有点痛苦的,但是结果带来那种成就感还是值得的,后面我们解决一下资源和布局的加载问题,然后介绍一下360开源的插件化框架DroidPlugin,分析一下它的源码就直接拿过用吧。

所有分享大纲:

视频讲解地址:http://pan.baidu.com/s/1o8bPZ9C

转载地址:http://bhxga.baihongyu.com/

你可能感兴趣的文章
STL中的set容器的一点总结(转)
查看>>
在线最优化求解(Online Optimization)之三:FOBOS
查看>>
unity, sprite atlas
查看>>
[CareerCup] 4.8 Contain Tree 包含树
查看>>
HDU 4946 Area of Mushroom 凸包
查看>>
nginx 编译选项
查看>>
android TextView 带滚动条,和ScrollView 用法(暂时觉得ScrollView滑动速度比较快)...
查看>>
poj 3187 Backward Digit Sums(穷竭搜索dfs)
查看>>
jQuery获取、设置title的值
查看>>
qq群文件管理
查看>>
Node.js v0.10.31API手工-DNS
查看>>
oracle的sqlldr并行导入表不要加索引
查看>>
修改linux系统编码
查看>>
RMI、Hessian、Burlap、Httpinvoker、WebService的比较
查看>>
A successful Git branching model
查看>>
【转】VS2013中如何解决error C4996: 'fopen'问题
查看>>
JavaHTTP下载视频
查看>>
grep命令做永久别名 显示颜色
查看>>
死锁以及锁等待
查看>>
入门视频采集与处理(BT656简介) 转
查看>>