插件化知识详细分解及原理之代理,hook,反射

刘镓旗 刘镓旗     2022-08-23     219

关键词:

上一篇我们说了Binder机制,通过aidl的demo和系统源码的对比进行了运行过程的分析,这一篇我们说代理模式及反射,之前说过了,只是为了梳理插件化需要了解的知识点,所以不会特别深的去讲解。

代理模式:

也叫做委托模式,分为静态代理和动态代理。代理模式也是平时比较常用的设计模式之一,代理模式有代码简洁,高扩展性的特性.主要目的就是为访问者提供一个代理,以达到限制某个对象的访问,也就是说想访问一个对象,其实我给你的是一个代理,不让你直接使用我。估计不理解的人会问为什么使用代理模式,他限制了对象的访问,也就是说不能通过new的方式得到你想要的对象,只能通过访问代理类才能使用,这样的话,我们就实现了内部对象的保护,而且如果有一天我的真实角色因为某个原因换了个名或者换了个方法字段等等,那对外来说一点不影响,因为他拿到的只是代理而已

  • 静态代理,还记的我们上一篇分析的aidl吗,他其实就是一个典型静态代理,我们再看一下代码

    public static com.huanju.chajianhuatest.IMyAidlInterface asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.huanju.chajianhuatest.IMyAidlInterface))) {
    return ((com.huanju.chajianhuatest.IMyAidlInterface) iin);
    }
    return new com.huanju.chajianhuatest.IMyAidlInterface.Stub.Proxy(obj);
    }

如果不是一个进程就返回了一个Stub.Proxy的代理类,如果客户端访问方法的时候,会调用服务端的方法然后将结果返回给客户端,这就是一个代理模式,而且android中的所有系统服务全部使用的这种模式。

  • 动态代理,就是在实现阶段不需要制定代理谁,在运行的时候指定一个代理类,这样就更灵活了,主要实现通过Java提供的InvocationHanler类,

    1.写一个类实现InvocationHanlder接口

    2.重写接口的invoke方法

    3.通过调用Proxy.newProxyInstance(ClassLoader loader, Class[] claz , InvocationHanlder handler)返回一个代理对象;

这里先不给出demo,等说完反射,我们一起实现一个hook系统类的demo,将会用到动态代理及反射

Hook机制

hook,又叫钩子,通常是指对一些方法进行拦截。这样当这些方法被调用时,也能够执行我们自己的代码,这也是面向切面编程的思想(AOP)

android中,本身并不提供这样的拦截机制,但是有时候,我们可以在一些特殊的场合实现一种的Hook方法。

大致思路:

1.找到需要Hook方法的系统类

2.利用代理模式来代理系统类的运行拦截我们需要拦截的方法

3.使用反射的方法把这个系统类替换成你的代理类

反射机制:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

在android中Google很多的类的某些方法不让第三方应用去调用,通过java反射机制能把这些隐藏方法获取出来并调用

相关API:

    1.实例化Class对象,有三种方式,
        Class.forName(类名全路径); //通过Class的静态方法
        对象.getClass() //通过对象.getClass方法
        int.class //基本数据类型及基本数据类型的封装了,例如Integer

    2.获取父类
        Class<?> clazz  = Class.forName(类名全路径); //通过Class的静态方法
        Class<?> superclass = clazz.getSuperclass();

    3.获取实现接口
        Class<?> clazz  = Class.forName(类名全路径); //通过Class的静态方法
        Class<?>[] interfaces = clazz.getInterfaces()


    4.获取指定参数构造函数及实例化
        Class<?> clazz  = Class.forName(类名全路径); //通过Class的静态方法
        Constructor<?> constructor = clazz.getConstructor(Class<?>  ... class);//获取公共的
        Constructor<?> constructor = clazz.getDeclaredConstructor()//获取私有的
        constructor.newInstance(Object args);

    5.获取所有构造函数及构造参数的类型
        Class<?> clazz  = Class.forName(类名全路径); //通过Class的静态方法
        Constructor<?>[] constructors = clazz.getConstructors();//公共的
        Constructor<?>[] constructors = clazz.getDeclaredConstructors()//包括私有的

         for (int i = 0; i < constructors.length; i++) {
            Class<?> clazzs[] = constructors[i].getParameterTypes();//获取类型
            System.out.print("constructors[" + i + "] (");
            for (int j = 0; j < clazzs.length; j++) {
                if (j == clazzs.length - 1)
                    System.out.print(clazzs[j].getName());
                else
                    System.out.print(clazzs[j].getName() + ",");
            }
            System.out.println(")");
        }


    6.通过无参实例化对象
        Class<?> clazz  = Class.forName(类名全路径); //通过Class的静态方法          
        class.newInstance();



    7.获取字段,修改字段
        Class<?> clazz  = Class.forName(类名全路径); //通过Class的静态方法          

        Field field = clazz.getField(String name);//获取公共字段
        Field field = clazz.getDeclaredField(String name);//获取私有公共字段
        Field[] field = clazz.getFields();//获取所有公共字段
        Field[] field = clazz.getDeclaredFields();//获取包括私有所有字段

        Field field = clazz.getDeclaredField("heihei");
        field.setAccessible(true);//设置java取消访问检查,也就是说如果是私有的也可以访问,
        field.set(obj, "Java反射机制");

    8.获取方法,运行方法
        Class<?> clazz  = Class.forName(类名全路径); //通过Class的静态方法          

        clazz.getMethod(String name ,Class<?> ... parame);//获取公共指定方法
        clazz.getDeclaredMethod(String name ,Class<?> ... parame)//获取私有指定方法
        clazz.getMethods()//获取公共所有方法
        clazz.getDeclaredMethods();//获取包括私有全部方法

        Method method = clazz.getMethod("add");
        method.invoke(clazz.newInstance());

        method = clazz.getMethod("getInfo", int.class, String.class);
        method.setAccessible(true)//设置java取消访问检查,也就是说如果是私有的也可以访问,
        method.invoke(clazz.newInstance(), 20, "张三");


    9.获取数组或者list中的类型,如果不是数组或集合返回null
        Class<?> clazz  = Class.forName(类名全路径); //通过Class的静态方法  
        Class<?> componentType = clazz.getComponentType();

好了我们上面讲代理模式,hook机制,反射大概都梳理了一遍,下面我们将运用这些知识写一个demo,来hook系统类的方法,简单点我们就hook一下剪切板服务的复制粘贴的方法,在系统运行这个方法的时候我们让他使用复制粘贴的都是一句话,当然这里是你可以想干的任何事情。

1.我们首先要知道剪切板服务怎么创建的,要知道他创建过程,我们才能拿到这个服务对象并代理他,
我们知道所有的服务对象都是代理对象,他们都被一个叫ServiceManager的类管理,我们来看一下,平时我们使用系统服务都是通过

 Context.getSystemService(Context.CLIPBOARD_SERVICE)方法来获取系统的服务

Context的具体实现类是ContextImpl,这个类在platform_frameworks_base-mastercorejavaandroidappContextImpl

 @Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

到了一个SystemServiceRegistry类中,从一个map中取

public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}

再看这个map怎么初始化的

 registerService(Context.HDMI_CONTROL_SERVICE, HdmiControlManager.class,
            new StaticServiceFetcher<HdmiControlManager>() {
        @Override
        public HdmiControlManager createService() {
            IBinder b = ServiceManager.getService(Context.HDMI_CONTROL_SERVICE);
            return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b));
        }});

看到了一个叫ServiceManager,但是并不是所有的服务都是这么初始化的,比如我们的ActivityManager,他就是返回的这个ActivityManager的包装类

registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
            public Object createService(ContextImpl ctx) {
                return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
            }});

但是,ActivityManager里面所有的核心操作都是使用ActivityManagerNative.getDefault()完成的。那么这个语句干了什么呢?

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        IActivityManager am = asInterface(b);
        return am;
    }
};

我们看到了其实他最终也是通过ServiceManager.getService来获取的,而且其实获取服务就分为两步

IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);

那么我们就先看ServiceManager这个类,这个类在platform_frameworks_base-mastercorejavaandroidosServiceManager

public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

看到了他内部也维护着一个map,我们可以通过反射替换这个map里面的内容为Hook过的IBinder对象,由于系统在getService的时候每次都会优先查找缓存,因此返回给使用者的都是被我们修改过的对象,从而实现代理

我们再看一下asInterface方法,之前我们分析过就时aidl中的方法

public static android.content.IClipboard asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null; 
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); // Hook点
    if (((iin != null) && (iin instanceof android.content.IClipboard))) {
        return ((android.content.IClipboard) iin);
    }
    return new android.content.IClipboard.Stub.Proxy(obj);
}

这里每次都会看一下本进程中是否存在这个Binder对象,如果有就直接返回了,那么我们想想办法
拦截这个方法让这个方法返回一个我们伪造的系统服务对象来替代系统的

实现代码

  • Activity中

>

public class MainActivity extends Activity {

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        ClipHelper.binder();
    } catch (Exception e) {
        e.printStackTrace();
    }
    EditText editText = new EditText(this);
    setContentView(editText);
}

}

  • ClipHelper

>

package com.weishu.binder_hook.app.text;

import android.os.IBinder;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * hook系统剪切板服务
 * Created by 刘镓旗 on 2017/1/22.
 */

public class ClipHelper {
    public static void binder(){
        try {
            //1.剪切板服务,是在系统的ServiceManager中的getSerVice方法中得到的,我们先拿到ServiceManager
            Class<?> serviceMangerClass = Class.forName("android.os.ServiceManager");
            //2.拿到getService方法
            Method getServiceMethod = serviceMangerClass.getDeclaredMethod("getService", String.class);
            //3.通过这个方法,拿到原本的系统服务代理对象
            IBinder binder = (IBinder) getServiceMethod.invoke(null,"clipboard");
            //4.我们通过这个对象,创建我们自己的代理对象,瞒天过海骗过系统
            IBinder myBinder = (IBinder) Proxy.newProxyInstance(serviceMangerClass.getClassLoader(),
                    new Class[]{IBinder.class}
                    ,new MyClipProxy(binder)
                    );
            //5.拿到ServiceManager中的数组
            Field field = serviceMangerClass.getDeclaredField("sCache");
            field.setAccessible(true);
            Map<String, IBinder> map = (Map) field.get(null);
            //将我们的服务类存入map
            map.put("clipboard",myBinder);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • MyClipProxy

s

package com.weishu.binder_hook.app.text;

import android.os.IBinder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * hook系统剪切板服务
 * Created by 刘镓旗 on 2017/1/22.
 */
public class MyClipProxy implements InvocationHandler {
    private final IBinder mBase;

    public MyClipProxy(IBinder binder) {
        mBase = binder;//这里传入的是原系统的代理类
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //拦截原系统类查询本地是否有这个代理的方法
        if("queryLocalInterface".equals(method.getName())){
            //我们这里要创建我们自己的系统类,然后返回
            //1.拿到系统的aidl类中的stub,因为这个对象本来就是个代理,而且源码执行了
//            static private IClipboard getService() {
//                synchronized (sStaticLock) {
//                    if (sService != null) {
//                        return sService;
//                    }
//                    IBinder b = ServiceManager.getService("clipboard");
//                    sService = IClipboard.Stub.asInterface(b);
//                    return sService;
//                }
//            }
            Class<?> mStubClass = Class.forName("android.content.IClipboard$Stub");
            //2.在拿到IClipboard本地对象类
            Class<?> mIClipboard = Class.forName("android.content.IClipboard");
            //3.创建我们自己的代理
            return Proxy.newProxyInstance(mStubClass.getClassLoader(),
                    new Class[]{mIClipboard},
                    new MyClip(mBase,mStubClass));
        }
        //不是这个方法还是返回原系统的执行
        return method.invoke(mBase,args);
    }
}
  • MyClip

>

package com.weishu.binder_hook.app.text;

import android.content.ClipData;
import android.os.Binder;
import android.os.IBinder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * hook系统剪切板服务
 * Created by 刘镓旗 on 2017/1/22.
 */
public class MyClip implements InvocationHandler {
    private Object mBase;

    public MyClip(IBinder base, Class stub) {
        //拿到asInteface方法,因为源码中执行了这一句,我们也要执行这一句
        try {
            Method asInterface = stub.getDeclaredMethod("asInterface", IBinder.class);
            mBase = asInterface.invoke(null,base);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //这里我们拦截粘贴的方法,
        if("getPrimaryClip".equals(method.getName())){
            return ClipData.newPlainText(null,"我是刘镓旗,我改了系统源码,哈哈哈");
        }
        //再拦截是否有复制的方法,放系统认为一直都有
        if("hasPrimaryClip".equals(method.getName())){
            return true;
        }
        //其他启动还是返回原有的
        return method.invoke(mBase,args);
    }
}

哦了,到这这一篇就说完了,下次我们继续的内容是类加载及dex加载过程

小白也能看懂的插件化droidplugin原理--反射机制和hook入门

  前言:在上一篇博文《小白也能看懂的插件化DroidPlugin原理(一)--动态代理》中详细介绍了DroidPlugin原理中涉及到的动态代理模式,看完上篇博文后你就会发现原来动态代理真的非常简单,只不过就是实现一个InvocationHandler... 查看详情

android插件化原理解析——hook机制之动态代理(代码片段)

提示:Java的动态代理非常有用,特别实在Android逆向过程中非常有用,比较典型的两个应用实例就是:1.xposed框架利用Java的动态代理Hook实现对Https请求信息的打印替代Https抓包的操作。2.利用Java的动态代理Hook实现... 查看详情

android插件化原理解析——hook机制之动态代理

...了AOP编程,极大地提升了Web开发效率;同样,插件框架也广泛使用了代理机制来增强系统API从而达到插件化的目的。 查看详情

android插件化原理解析——hook机制之动态代理(代码片段)

...了AOP编程,极大地提升了Web开发效率;同样,插件框架也广泛使用了代理机制来增强系统API从而达到插件化的目的。本文将带你了解基于动态代理的Hook机制。阅读本文之前,可以先clone一份 understand-plugin-framework&#... 查看详情

android插件化hook插件化框架(反射工具类|反射常用操作整理)(代码片段)

Android插件化系列文章目录【Android插件化】插件化简介(组件化与插件化)【Android插件化】插件化原理(JVM内存数据|类加载流程)【Android插件化】插件化原理(类加载器)【Android插件化】“插桩式“插件化框架(原理与实现思路)【Android... 查看详情

唯一插件化replugin源码及原理深度剖析--唯一hook点原理(代码片段)

...微信公众号guolin_blog(郭霖)独家发布上一篇唯一插件化Replugin源码及原理深度剖析–初始化之框架核心,我们说了Replugin的整体框架的初始化,但是因为篇幅的缘故还有Hook系统的ClassLoader和插件的加载没有说,... 查看详情

唯一插件化replugin源码及原理深度剖析--唯一hook点原理(代码片段)

...微信公众号guolin_blog(郭霖)独家发布上一篇唯一插件化Replugin源码及原理深度剖析–初始化之框架核心,我们说了Replugin的整体框架的初始化,但是因为篇幅的缘故还有Hook系统的ClassLoader和插件的加载没有说,... 查看详情

android插件化hook插件化框架(hookactivity启动流程|反射获取iactivitymanager对象)(代码片段)

Android插件化系列文章目录【Android插件化】插件化简介(组件化与插件化)【Android插件化】插件化原理(JVM内存数据|类加载流程)【Android插件化】插件化原理(类加载器)【Android插件化】“插桩式“插件化框架(原理与实现思路)【Android... 查看详情

android插件化hook插件化框架(通过反射获取“插件包“中的element[]dexelements)(代码片段)

Android插件化系列文章目录【Android插件化】插件化简介(组件化与插件化)【Android插件化】插件化原理(JVM内存数据|类加载流程)【Android插件化】插件化原理(类加载器)【Android插件化】“插桩式“插件化框架(原理与实现思路)【Android... 查看详情

android插件化hook插件化框架(通过反射获取“宿主“应用中的element[]dexelements)(代码片段)

Android插件化系列文章目录【Android插件化】插件化简介(组件化与插件化)【Android插件化】插件化原理(JVM内存数据|类加载流程)【Android插件化】插件化原理(类加载器)【Android插件化】“插桩式“插件化框架(原理与实现思路)【Android... 查看详情

唯一插件化replugin源码及原理深度剖析--工程职责及大纲(代码片段)

首先简单介绍一些Replugin,Replugin是360开源的Android插件化框架,它在2017年7月开源后,目前已经成为最火热的插件化框架之一,它的特点是唯一Hook,全工程只有一处Hook了系统类。这无形之中让插件化降低了门... 查看详情

android插件化hook插件化框架(hookactivity启动流程|ams启动前使用动态代理替换掉插件activity类)(代码片段)

Android插件化系列文章目录【Android插件化】插件化简介(组件化与插件化)【Android插件化】插件化原理(JVM内存数据|类加载流程)【Android插件化】插件化原理(类加载器)【Android插件化】“插桩式“插件化框架(原理与实现思路)【Android... 查看详情

android插件化原理解析——hook机制之binderhook

转载自http://www.jianshu.com/p/1b8772e4787fweishu的好文简书作者Android系统通过Binder机制给应用程序提供了一系列的系统服务,诸如ActivityManagerService,ClipboardManager,AudioManager等;这些广泛存在系统服务给应用程序提供了诸... 查看详情

android插件化hook插件化框架(hook插件化原理|插件包管理)(代码片段)

Android插件化系列文章目录【Android插件化】插件化简介(组件化与插件化)【Android插件化】插件化原理(JVM内存数据|类加载流程)【Android插件化】插件化原理(类加载器)【Android插件化】“插桩式“插件化框架(原理与实现思路)【Android... 查看详情

插件化原理

...开发,但没有黑科技,不存在Android版本的兼容问题。而插件化框架功能强大,最关键的是具备热修复、模块动态加载、删除的能力,但因为需要hook系统组件,所以存在可能的兼容性问题。Atlas的热修复使用的是自家的Andfix,基... 查看详情

唯一插件化replugin源码及原理深度剖析--插件的安装加载原理(代码片段)

上一篇唯一插件化Replugin源码及原理深度剖析–唯一Hook点原理在Replugin的初始化过程中,我将他们分成了比较重要3个模块,整体框架的初始化、hook系统ClassLoader、插件的加载,3个模块已经说了两个,在第一篇的最... 查看详情

小白也能看懂的插件化droidplugin原理--动态代理

  前言:插件化在Android开发中的优点不言而喻,也有很多文章介绍插件化的优势,所以在此不再赘述。前一阵子在项目中用到DroidPlugin插件框架,近期准备投入生产环境时出现了一些小问题,所以决心花些时间研究了一下DroidP... 查看详情

android插件化hook插件化框架(hookactivity启动流程|hook点分析)(代码片段)

Android插件化系列文章目录【Android插件化】插件化简介(组件化与插件化)【Android插件化】插件化原理(JVM内存数据|类加载流程)【Android插件化】插件化原理(类加载器)【Android插件化】“插桩式“插件化框架(原理与实现思路)【Android... 查看详情