Acting and reflection summary

First, agents

Acting divided into static and dynamic proxy agent. Static agents already exist before running before the proxy class and delegate class relations in the run it has been identified. The dynamic proxy is determined at runtime, and can be determined at run time based on the relationship between the agent class and delegate class reflection mechanism generated.

1, the static agent

When speaking Binder mechanisms, there is a very typical static agent. It took about here:

public static com.example.runningh.myapplication.phone.IPhoneManager asInterface(android.os.IBinder obj) {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.runningh.myapplication.phone.IPhoneManager))) {
        return ((com.example.runningh.myapplication.phone.IPhoneManager)iin);
      }
      return new com.example.runningh.myapplication.phone.IPhoneManager.Stub.Proxy(obj);
}
复制代码

If the returned IInterface services and the current process is not in the same process a new Stub.Proxy proxy class, when the client access to related methods, the proxy class method would be to call the server and returned to the client, which is a typical static proxy mode.

2, dynamic proxy

When implementation does not need to specify which object proxy, you are required to achieve at run time, it has the advantage of more flexible and convenient. Let's look at how it is used.

Object proxy = Proxy.newProxyInstance(ClassLoader loader, Class[] claz , InvocationHanlder handler);
复制代码

Dynamic prototype agent returns a proxy object by the above method. For example, the following call:

Class<?> serviceManager = Class.forName("android.os.ServiceManager");
Method getServiceMethod = serviceManager.getDeclaredMethod("getService", String.class);
IBinder binder = (IBinder) getServiceMethod.invoke(null, "alarm");
IBinder myBinder = (IBinder) Proxy.newProxyInstance(serviceManager.getClassLoader()
      , new Class[]{IBinder.class}, new MyProxy(binder));
复制代码

We analyze in detail the method of its three parameters.

  • ClassLoader loader. This is a class loader, which means that we use a class loader to load the proxy class. Generally, we use the class loader delegate class.
  • Class [] claz. Object specifies newProxyInstance return (that is, our proxy class) which interfaces to implement. This is an array, indicating that can implement multiple interfaces. IBinder above example implements the interface, so it can be cast into IBinder type.
  • InvocationHandler handler. This is an interface. There invoke a method. Actually, no matter what you call a method of the proxy object, it will eventually come to invoke methods. All methods can invoke some operations to achieve what we want to do for the method name.

Second, reflection

Such a reflection function for the category, it is known during operation may be any of a class of all properties and methods; for objects, it can be called any one of attributes and methods. Let's look at some of the related operations reflected:

1、Class对象的获取:
        Class.forName(类名全路径); //这是Class的一个静态方法
        类对象.getClass();  //通过类对象.getClass方法
        boolean.class, Boolean.class, int.class, Integer.class; //基本数据的Class对象获取,注意boolean.class和Boolean.class并不一样

2、实现接口的获取:
        Class<?> clazz  = Class.forName(类名全路径);
        Class<?>[] interfaces = clazz.getInterfaces()

3、通过指定参数获取构造函数及实例化
        Class<?> clazz  = Class.forName(类名全路径);
        Constructor<?> constructor = clazz.getConstructor(Class<?>  ... class);//获取公有的构造函数(public修饰符的)
        Constructor<?> constructor = clazz.getDeclaredConstructor(); //获取构造函数,包括公有和私有的
        constructor.newInstance(Object args);

4、获取所有构造函数和参数类型
        Class<?> clazz  = Class.forName(类名全路径);
        Constructor<?>[] constructors = clazz.getConstructors();//公共的构造函数
        Constructor<?>[] constructors = clazz.getDeclaredConstructors()//所有的构造函数,包括私有的

         for (int i = 0; i < constructors.length; i++) {
            Class<?> clazzs[] = constructors[i].getParameterTypes();//获取参数类型
             Log.d("ABC", "constructors[" + i + "] =" + constructors[i]);
            for (int j = 0; j < clazzs.length; j++) {
                if (j == clazzs.length - 1)
                    Log.d("ABC", clazzs[j].getName() + " ;");
            }
          }

5、获取字段,修改字段
        Class<?> clazz  = Class.forName(类名全路径);

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

        Field field = clazz.getDeclaredField("price");
        field.setAccessible(true);//设置取消访问检查,私有类型也可以访问
        field.set(obj, 100);

6、获取方法
        Class<?> clazz  = Class.forName(类名全路径);

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

        Method method = clazz.getMethod("setPrice", int.class);
        method.setAccessible(true);
        method.invoke(clazz.newInstance(), 200);
复制代码

Third, the practical application

Here we clipboard by copy and paste method of hook system, let it say a word when you copy and paste. First we look at is how to obtain the service system:

Context.getSystemService(Context.CLIPBOARD_SERVICE);
复制代码

And we know that in fact ContextImpl Context object into getSystemService method ContextImpl of:

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

Which in turn calls a static method SystemServiceRegistry class:

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

SYSTEM_SERVICE_FETCHERS acquired from the corresponding ServiceFetcher, ServiceFetcher getService method call returns the corresponding service. The SYSTEM_SERVICE_FETCHERS is initialized in a static block of code SystemServiceRegistry class initialization, we copy and paste initialize services out of view:

registerService(Context.CLIPBOARD_SERVICE, ClipboardManager.class,
      new CachedServiceFetcher<ClipboardManager>() {
      @Override
      public ClipboardManager createService(ContextImpl ctx) {
          return new ClipboardManager(ctx.getOuterContext(),
                ctx.mMainThread.getHandler());
}});
复制代码

You can see the service is actually a copy and paste ClipboardManagerobjects. And ClipboardManagerall methods which objects are returned by proxy object execution getService () it is. getService what is returned, we continue to look at the source code (note ① here, we will come back to wait to see this part of the code):

static private IClipboard getService() {
      synchronized (sStaticLock) {
          if (sService != null) {
            return sService;
          }
          IBinder b = ServiceManager.getService("clipboard");
          //注意这里,后面拿到代理的IBinder对象后会执行到asInterface的queryLocalInterface方法。
          sService = IClipboard.Stub.asInterface(b); 
          return sService;
      }
}

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

If sService object is not null, it is returned. Otherwise, get IBinder objects by getService method ServiceManager and calls IClipboard.Stub.asInterface (IBinder binder) is generated. ServiceManager of getService way to do anything at all? Continue to look at the source code:

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;
}
复制代码

If there sCache IBinder object is returned, or else continue to go that far. See here we will know by replacing sCache of IBinder custom proxy class for themselves, other than to achieve the return of the original IBinder cheat the system or the object to achieve the effect we want it.

The following is a specific code:

ReflectActivity:

public class ReflectActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.reflect_activity);
        ClipHelper.binder();
    }
}
复制代码

Layout file on a EditText, not posted out. Call ClipHelper.binder method onCreate method.

ClipHelper:

public class ClipHelper {
    public static void binder() {
        try {
            Class<?> serviceManager = Class.forName("android.os.ServiceManager"); //获取ServiceManager对象
            Method getServiceMethod = serviceManager.getDeclaredMethod("getService", String.class); //调用getService方法
            IBinder binder = (IBinder) getServiceMethod.invoke(null, "clipboard"); //调用剪切板的方法,获取原始的IBinder对象
            IBinder myBinder = (IBinder) Proxy.newProxyInstance(serviceManager.getClassLoader()
                    , new Class[]{IBinder.class}, new MyProxy(binder)); //获取代理的IBinder对象
            Field sCache = serviceManager.getDeclaredField("sCache");
            sCache.setAccessible(true);
            HashMap<String, IBinder> map = (HashMap<String, IBinder>) sCache.get(null);
            map.put("clipboard", myBinder); //将该代理对象放到sCache里面
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}
复制代码

ClipHelper mainly generated IBinder a proxy object, the proxy object and to put the inside sCache.

MyProxy:

public class MyProxy implements InvocationHandler {
    private IBinder orginBinder;

    public MyProxy(IBinder binder) {
        this.orginBinder = binder;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("queryLocalInterface")) {
            Class<?> mStubClass = Class.forName("android.content.IClipboard$Stub");
            Class<?> mClipBoard = Class.forName("android.content.IClipboard");
            return Proxy.newProxyInstance(mStubClass.getClassLoader(), new Class[]{mClipBoard}, new MyClipBoard(orginBinder, mStubClass));
        }
        return method.invoke(orginBinder, args);
    }
}
复制代码

hook live IBinder of queryLocalInterface method. You can go back and look at the above ① Note that part, IBinder execution method and return to the queryLocalInterface a IClipboard object. This object is to clipboard clients, which we need to hook in. So here again return a proxy object through a dynamic proxy. The proxy object implements the IClipboard interface. Here's proxy object to MyClipBoard. As follows.

MyClipBoard:

public class MyClipBoard implements InvocationHandler {
    private Object mBase;

    public MyClipBoard(IBinder binder, Class stub) {
        try {
            Method asInterface = stub.getDeclaredMethod("asInterface", IBinder.class);
            mBase = asInterface.invoke(null, binder);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("getPrimaryClip")) {
            return ClipData.newPlainText(null, "怎么老是你");
        }
        if (method.getName().equals("hasPrimaryClip")) {
            return true;
        }
        return method.invoke(mBase, args);
    }
}
复制代码

We just need to live hook clipboard getPrimaryClip and hasPrimaryClip method, or other method calls in the normal way. The normal way requires a clipboard normal service, or look back at the top of the note ① code, normal clipboard service is through IClipboard.Stub.asInterface(binder)acquisition, so the above is mBase clipboard service, available through asInterface static method, therefore, asInterface method call the constructor of IClipboard.Stub.

Above is all the code and paste in the EditText long press will be "how old are you", and the words that we get through the clipboard service hook live system.

IV Summary

Dynamic binding agents and generally reflected with some methods that can be used to change the system so as to achieve our desired effect. When we get the source code can not be modified, can be carried out by means of such a reform, but be sure to note that this is risky, not likely to change hidden potential bug, so you must be careful when using. This article is the original author here after I read http://blog.csdn.net/yulong0809/article/details/56842027 exposition agent, hook, reflective knowledge, some conclusions of their own, thanks to the selfless sharing of the original author .

Guess you like

Origin juejin.im/post/5d73188c518825312330b1e8