Android插件化Hook技术

内容分享4天前发布
2 0 0

1、寻找Hook点的原则
Android中主要是依靠分析系统源码类来做到的,第一我们得找到被Hook的对象,我称之为Hook点;什么样的对象比较好Hook呢?一般来说,静态变量和单例变量是相对不容易改变,是一个比较好的hook点,而普通的对象有易变的可能,每个版本都不一样,处理难度比较大。我们根据这个原则找到所谓的Hook点。
2、Hook与动态代理结合实现对象替换,然后在代理中进行想要的操作

例子:
Android插件化架构 – 拦截Activity的启动流程绕过AndroidManifest检测
1、Hook启动流程

怎么样去找Hook点是个问题,把钩子下在哪里呢?一般的套路肯定最好是静态,然后是接口,配合反射注入就可以了。Activity启动流程的源码我就不再贴了,如果不了解请移步这里Android插件化架构 – 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);
    }
}

···

2、动态代理替换对象
上面我们已经拦截到了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();
        }
    }

3、兼容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);

···

© 版权声明

相关文章

暂无评论

none
暂无评论...