Skip to content

Commit 47edff2

Browse files
author
vbuell
committed
simple types supported
1 parent d2b4694 commit 47edff2

File tree

2 files changed

+166
-17
lines changed

2 files changed

+166
-17
lines changed

javaobj.py

Lines changed: 130 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,136 @@
22
import struct
33

44
def loads(object):
5+
"""
6+
Deserializes Java primitive data and objects serialized by ObjectOutputStream
7+
"""
58
f = StringIO.StringIO(object)
6-
ba = f.read(4)
7-
(magic, version) = struct.unpack(">HH", ba)
8-
print magic
9-
if magic != 0xaced:
10-
raise RuntimeError("The stream is not java serialized object. Magic number failed.")
9+
marshaller = JavaObjectMarshaller(f)
10+
return marshaller.readObject()
11+
# ba = f.read(4)
12+
# (magic, version) = struct.unpack(">HH", ba)
13+
# print magic
14+
# if magic != 0xaced:
15+
# raise RuntimeError("The stream is not java serialized object. Magic number failed.")
16+
#
17+
# print version
18+
#
19+
# print type(object), Magic
1120

12-
print version
21+
class JavaObjectMarshaller:
1322

14-
print type(object), Magic
15-
23+
STREAM_MAGIC = 0xaced
24+
STREAM_VERSION = 0x05
25+
26+
TC_REFERENCE = 0x71
27+
TC_CLASSDESC = 0x72
28+
TC_OBJECT = 0x73
29+
TC_STRING = 0x74
30+
TC_ARRAY = 0x75
31+
TC_CLASS = 0x76
32+
TC_BLOCKDATA = 0x77
33+
TC_ENDBLOCKDATA = 0x78
34+
TC_RESET = 0x79
35+
TC_BLOCKDATALONG = 0x7A
36+
TC_EXCEPTION = 0x7B
37+
TC_LONGSTRING = 0x7C
38+
TC_PROXYCLASSDESC = 0x7D
39+
TC_ENUM = 0x7E
40+
TC_MAX = 0x7E
41+
42+
def __init__(self, stream):
43+
self.opmap = {
44+
self.TC_CLASSDESC: self.do_classdesc,
45+
self.TC_OBJECT: self.do_object,
46+
self.TC_STRING: self.do_string,
47+
self.TC_CLASS: self.do_class,
48+
self.TC_BLOCKDATA: self.do_blockdata,
49+
self.TC_REFERENCE: self.do_reference
50+
}
51+
self.object_stream = stream
52+
self._readStreamHeader()
53+
self.finalValue = True
54+
55+
def _readStreamHeader(self):
56+
(magic, version) = self._readStruct(">HH", 4)
57+
if magic != self.STREAM_MAGIC or version != self.STREAM_VERSION:
58+
raise IOError("The stream is not java serialized object. Invalid stream header: %04X%04X" % (magic, version))
59+
60+
def readObject(self):
61+
(opid, ) = self._readStruct(">B", 1)
62+
print "OpCode: 0x%X" % opid
63+
self.opmap.get(opid, self.do_default_stuff)()
64+
return self.finalValue
65+
66+
def _readStruct(self, unpack, length):
67+
ba = self.object_stream.read(length)
68+
return struct.unpack(unpack, ba)
69+
70+
def _readString(self):
71+
(length, ) = self._readStruct(">H", 2)
72+
ba = self.object_stream.read(length)
73+
return ba
74+
75+
def do_classdesc(self):
76+
# TC_CLASSDESC className serialVersionUID newHandle classDescInfo
77+
# classDescInfo:
78+
# classDescFlags fields classAnnotation superClassDesc
79+
# classDescFlags:
80+
# (byte) // Defined in Terminal Symbols and Constants
81+
# fields:
82+
# (short)<count> fieldDesc[count]
83+
84+
# fieldDesc:
85+
# primitiveDesc
86+
# objectDesc
87+
# primitiveDesc:
88+
# prim_typecode fieldName
89+
# objectDesc:
90+
# obj_typecode fieldName className1
91+
print "do_classdesc"
92+
ba = self._readString()
93+
print "Class name:", ba
94+
(serialVersionUID, newHandle, classDescFlags) = self._readStruct(">LLB", 4+4+1)
95+
print "Serial: 0x%X newHanle: 0x%X. classDescFlags: 0x%X" % (serialVersionUID, newHandle, classDescFlags)
96+
(length, ) = self._readStruct(">H", 2)
97+
print "Fields num: 0x%X" % length
98+
99+
for fieldId in range(length):
100+
(type, ) = self._readStruct(">B", 1)
101+
ba = self._readString()
102+
print "FieldType: 0x%X" % type, ba
103+
(opid, ) = self._readStruct(">B", 1)
104+
print "OpCode: 0x%X" % opid
105+
res = self.opmap.get(opid, self.do_default_stuff)()
106+
107+
def do_blockdata(self):
108+
# TC_BLOCKDATA (unsigned byte)<size> (byte)[size]
109+
print "[blockdata]"
110+
(length, ) = self._readStruct(">B", 1)
111+
ba = self.object_stream.read(length)
112+
self.finalValue = ba
113+
114+
def do_class(self):
115+
# TC_CLASS classDesc newHandle
116+
print "[class]"
117+
118+
def do_object(self):
119+
# TC_OBJECT classDesc newHandle classdata[] // data for each class
120+
print "[object]"
121+
(opid, ) = self._readStruct(">B", 1)
122+
print "OpCode: 0x%X" % opid
123+
res = self.opmap.get(opid, self.do_default_stuff)()
124+
self.finalValue = res
125+
126+
def do_string(self):
127+
print "[string]"
128+
ba = self._readString()
129+
# (handle, ) = self._readStruct(">B", 1)
130+
return str(ba)
131+
132+
def do_reference(self):
133+
(handle, reference) = self._readStruct(">HH", 4)
134+
pass
135+
136+
def do_default_stuff(self):
137+
raise RuntimeError("Unknown opcode")

tests.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,48 @@ def read_file(self, filename):
1414
def test_0(self):
1515
jobj = self.read_file("obj0.ser")
1616
pobj = javaobj.loads(jobj)
17+
print pobj
18+
self.assertEqual(pobj, '\x00C')
19+
20+
def test_1(self):
21+
jobj = self.read_file("obj1.ser")
22+
pobj = javaobj.loads(jobj)
23+
print pobj
24+
self.assertEqual(pobj, '\x7f\xef\xff\xff\xff\xff\xff\xff')
25+
26+
def test_2(self):
27+
jobj = self.read_file("obj2.ser")
28+
pobj = javaobj.loads(jobj)
29+
print pobj
30+
self.assertEqual(pobj, 'HelloWorld')
1731

32+
def test_3(self):
33+
jobj = self.read_file("obj3.ser")
34+
pobj = javaobj.loads(jobj)
1835
print pobj
36+
self.assertEqual(pobj, chr(0))
1937

20-
# make sure the shuffled sequence does not lose any elements
21-
random.shuffle(self.seq)
22-
self.seq.sort()
23-
self.assertEqual(self.seq, range(10))
38+
def test_4(self):
39+
jobj = self.read_file("obj4.ser")
40+
pobj = javaobj.loads(jobj)
41+
print pobj
42+
self.assertEqual(pobj, 'HelloWorld')
2443

25-
# should raise an exception for an immutable sequence
26-
self.assertRaises(TypeError, random.shuffle, (1,2,3))
44+
def test_5(self):
45+
jobj = self.read_file("obj5.ser")
46+
pobj = javaobj.loads(jobj)
47+
print pobj
48+
self.assertEqual(pobj, 'HelloWorld')
2749

28-
def test_choice(self):
29-
element = random.choice(self.seq)
30-
self.assertTrue(element in self.seq)
50+
# def test_6(self):
51+
# jobj = self.read_file("obj6.ser")
52+
# pobj = javaobj.loads(jobj)
53+
# print pobj
54+
# self.assertEqual(pobj, 'HelloWorld')
3155

56+
# def test_choice(self):
57+
# element = random.choice(self.seq)
58+
# self.assertTrue(element in self.seq)
3259

3360
if __name__ == '__main__':
3461
unittest.main()

0 commit comments

Comments
 (0)