Skip to content

Commit d0616c4

Browse files
author
vbuell
committed
fix: reference should be expected for arrays' classdesc. methods names refactoring.
1 parent ad39225 commit d0616c4

File tree

1 file changed

+60
-61
lines changed

1 file changed

+60
-61
lines changed

javaobj.py

Lines changed: 60 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,6 @@ def loads(object):
1010
f = StringIO.StringIO(object)
1111
marshaller = JavaObjectMarshaller()
1212
return marshaller.load_stream(f)
13-
# ba = f.read(4)
14-
# (magic, version) = struct.unpack(">HH", ba)
15-
# print magic
16-
# if magic != 0xaced:
17-
# raise RuntimeError("The stream is not java serialized object. Magic number failed.")
18-
#
19-
# print version
20-
#
21-
# print type(object), Magic
2213

2314
def dumps(object):
2415
"""
@@ -130,7 +121,7 @@ def load_stream(self, stream):
130121
self._readStreamHeader()
131122
return self.readObject()
132123
except Exception, e:
133-
self.dump_state()
124+
self._oops_dump_state()
134125
raise
135126

136127
def _readStreamHeader(self):
@@ -139,23 +130,23 @@ def _readStreamHeader(self):
139130
raise IOError("The stream is not java serialized object. Invalid stream header: %04X%04X" % (magic, version))
140131

141132
def readObject(self):
142-
res = self.read_and_exec_opcode(ident=0) # TODO: add expects
133+
res = self._read_and_exec_opcode(ident=0) # TODO: add expects
143134

144135
the_rest = self.object_stream.read()
145136
if len(the_rest):
146137
print "Warning!!!!: Stream still has %s bytes left." % len(the_rest)
147-
print self.hexdump(the_rest)
138+
print self._create_hexdump(the_rest)
148139
else:
149140
print "Ok!!!!"
150141

151142
return res
152143

153-
def read_and_exec_opcode(self, ident=0, expect=None):
144+
def _read_and_exec_opcode(self, ident=0, expect=None):
154145
(opid, ) = self._readStruct(">B")
155-
self.print_ident("OpCode: 0x%X" % opid, ident)
146+
self._log_ident("OpCode: 0x%X" % opid, ident)
156147
if expect and opid not in expect:
157148
raise IOError("Unexpected opcode 0x%X" % opid)
158-
return self.opmap.get(opid, self.do_default_stuff)(ident=ident)
149+
return self.opmap.get(opid, self.do_unknown)(ident=ident)
159150

160151
def _readStruct(self, unpack):
161152
length = struct.calcsize(unpack)
@@ -184,38 +175,38 @@ def do_classdesc(self, parent=None, ident=0):
184175
# objectDesc:
185176
# obj_typecode fieldName className1
186177
clazz = JavaClass()
187-
self.print_ident("[classdesc]", ident)
178+
self._log_ident("[classdesc]", ident)
188179
ba = self._readString()
189180
clazz.name = ba
190-
self.print_ident("Class name: %s" % ba, ident)
181+
self._log_ident("Class name: %s" % ba, ident)
191182
(serialVersionUID, newHandle, classDescFlags) = self._readStruct(">LLB")
192183
clazz.serialVersionUID = serialVersionUID
193184
clazz.flags = classDescFlags
194185

195-
self.add_reference(clazz)
186+
self._add_reference(clazz)
196187

197-
self.print_ident("Serial: 0x%X newHandle: 0x%X. classDescFlags: 0x%X" % (serialVersionUID, newHandle, classDescFlags), ident)
188+
self._log_ident("Serial: 0x%X newHandle: 0x%X. classDescFlags: 0x%X" % (serialVersionUID, newHandle, classDescFlags), ident)
198189
(length, ) = self._readStruct(">H")
199-
self.print_ident("Fields num: 0x%X" % length, ident)
190+
self._log_ident("Fields num: 0x%X" % length, ident)
200191

201192
clazz.fields_names = []
202193
clazz.fields_types = []
203194
for fieldId in range(length):
204195
(type, ) = self._readStruct(">B")
205196
field_name = self._readString()
206197
field_type = None
207-
field_type = self.convert_char_to_type(type)
198+
field_type = self._convert_char_to_type(type)
208199

209200
if field_type == self.TYPE_ARRAY:
210-
field_type = self.read_and_exec_opcode(ident=ident+1, expect=[self.TC_STRING, self.TC_REFERENCE])
201+
field_type = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_STRING, self.TC_REFERENCE])
211202
# if field_type is not None:
212203
# field_type = "array of " + field_type
213204
# else:
214205
# field_type = "array of None"
215206
elif field_type == self.TYPE_OBJECT:
216-
field_type = self.read_and_exec_opcode(ident=ident+1, expect=[self.TC_STRING, self.TC_REFERENCE])
207+
field_type = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_STRING, self.TC_REFERENCE])
217208

218-
self.print_ident("FieldName: 0x%X" % type + " " + str(field_name) + " " + str(field_type), ident)
209+
self._log_ident("FieldName: 0x%X" % type + " " + str(field_name) + " " + str(field_type), ident)
219210
assert field_name is not None
220211
assert field_type is not None
221212

@@ -228,41 +219,41 @@ def do_classdesc(self, parent=None, ident=0):
228219
(opid, ) = self._readStruct(">B")
229220
if opid != self.TC_ENDBLOCKDATA:
230221
raise NotImplementedError("classAnnotation isn't implemented yet")
231-
self.print_ident("OpCode: 0x%X" % opid, ident)
222+
self._log_ident("OpCode: 0x%X" % opid, ident)
232223
# superClassDesc
233-
superclassdesc = self.read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_NULL])
234-
self.print_ident(str(superclassdesc), ident)
224+
superclassdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_NULL, self.TC_REFERENCE])
225+
self._log_ident(str(superclassdesc), ident)
235226
clazz.superclass = superclassdesc
236227

237228
return clazz
238229

239230
def do_blockdata(self, parent=None, ident=0):
240231
# TC_BLOCKDATA (unsigned byte)<size> (byte)[size]
241-
self.print_ident("[blockdata]", ident)
232+
self._log_ident("[blockdata]", ident)
242233
(length, ) = self._readStruct(">B")
243234
ba = self.object_stream.read(length)
244235
return ba
245236

246237
def do_class(self, parent=None, ident=0):
247238
# TC_CLASS classDesc newHandle
248-
self.print_ident("[class]", ident)
239+
self._log_ident("[class]", ident)
249240

250241
# TODO: what to do with "(ClassDesc)prevObject". (see 3rd line for classDesc:)
251-
classdesc = self.read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL])
252-
self.print_ident("Classdesc: %s" % classdesc, ident)
253-
self.add_reference(classdesc)
242+
classdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL, self.TC_REFERENCE])
243+
self._log_ident("Classdesc: %s" % classdesc, ident)
244+
self._add_reference(classdesc)
254245
return classdesc
255246

256247
def do_object(self, parent=None, ident=0):
257248
# TC_OBJECT classDesc newHandle classdata[] // data for each class
258249
java_object = JavaObject()
259-
self.print_ident("[object]", ident)
250+
self._log_ident("[object]", ident)
260251

261252
# TODO: what to do with "(ClassDesc)prevObject". (see 3rd line for classDesc:)
262-
classdesc = self.read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL, self.TC_REFERENCE])
253+
classdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL, self.TC_REFERENCE])
263254
# self.TC_REFERENCE hasn't shown in spec, but actually is here
264255

265-
self.add_reference(java_object)
256+
self._add_reference(java_object)
266257

267258
# classdata[]
268259

@@ -278,7 +269,7 @@ def do_object(self, parent=None, ident=0):
278269
megalist = []
279270
megatypes = []
280271
while tempclass:
281-
print ">>>", tempclass.fields_names, tempclass
272+
self._log_ident(">>> " + str(tempclass.fields_names) + " " + str(tempclass), ident)
282273
fieldscopy = tempclass.fields_names[:]
283274
fieldscopy.extend(megalist)
284275
megalist = fieldscopy
@@ -289,74 +280,75 @@ def do_object(self, parent=None, ident=0):
289280

290281
tempclass = tempclass.superclass
291282

292-
print "Prepared list of values:", megalist
293-
print "Prepared list of types:", megatypes
283+
self._log_ident("Values count: %s" % str(len(megalist)), ident)
284+
self._log_ident("Prepared list of values: %s" % str(megalist), ident)
285+
self._log_ident("Prepared list of types: %s" % str(megatypes), ident)
294286

295287
for field_name, field_type in zip(megalist, megatypes):
296-
res = self.read_native(field_type, ident)
288+
res = self._read_value(field_type, ident, name=field_name)
297289
java_object.__setattr__(field_name, res)
298290

299291
if classdesc.flags & self.SC_SERIALIZABLE and classdesc.flags & self.SC_WRITE_METHOD or classdesc.flags & self.SC_EXTERNALIZABLE and classdesc.flags & self.SC_BLOCK_DATA:
300292
# objectAnnotation
301293
(opid, ) = self._readStruct(">B")
302294
if opid != self.TC_ENDBLOCKDATA: # 0x78:
303295
self.object_stream.seek(-1, mode=1)
304-
print self.hexdump(self.object_stream.read())
296+
print self._create_hexdump(self.object_stream.read())
305297
raise NotImplementedError("objectAnnotation isn't fully implemented yet") # TODO:
306298

307299

308300
return java_object
309301

310302
def do_string(self, parent=None, ident=0):
311-
self.print_ident("[string]", ident)
303+
self._log_ident("[string]", ident)
312304
ba = self._readString()
313-
self.add_reference(str(ba))
305+
self._add_reference(str(ba))
314306
return str(ba)
315307

316308
def do_array(self, parent=None, ident=0):
317309
# TC_ARRAY classDesc newHandle (int)<size> values[size]
318-
self.print_ident("[array]", ident)
319-
classdesc = self.read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL])
310+
self._log_ident("[array]", ident)
311+
classdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL, self.TC_REFERENCE])
320312

321313
array = []
322314

323-
self.add_reference(array)
315+
self._add_reference(array)
324316

325317
(size, ) = self._readStruct(">i")
326-
self.print_ident("size: " + str(size), ident)
318+
self._log_ident("size: " + str(size), ident)
327319

328320
type_char = classdesc.name[0]
329321
assert type_char == self.TYPE_ARRAY
330322
type_char = classdesc.name[1]
331323

332324
if type_char == self.TYPE_OBJECT or type_char == self.TYPE_ARRAY:
333325
for i in range(size):
334-
res = self.read_and_exec_opcode(ident=ident+1)
335-
print res
326+
res = self._read_and_exec_opcode(ident=ident+1)
327+
self._log_ident("Object value: %s" % str(res), ident)
336328
array.append(res)
337329
else:
338330
for i in range(size):
339-
res = self.read_native(type_char, ident)
340-
print "Native value:", res
331+
res = self._read_value(type_char, ident)
332+
self._log_ident("Native value: %s" % str(res), ident)
341333
array.append(res)
342334

343335
return array
344336

345337
def do_reference(self, parent=None, ident=0):
346338
(handle, ) = self._readStruct(">L")
347-
print "## Reference handle: 0x%x" % (handle)
339+
self._log_ident("## Reference handle: 0x%x" % (handle), ident)
348340
return self.references[handle - self.BASE_REFERENCE_IDX]
349341

350342
def do_null(self, parent=None, ident=0):
351343
return None
352344

353-
def do_default_stuff(self, parent=None, ident=0):
345+
def do_unknown(self, parent=None, ident=0):
354346
raise RuntimeError("Unknown OpCode")
355347

356-
def print_ident(self, message, ident):
357-
print " " * ident + str(message)
348+
def _log_ident(self, message, ident):
349+
print " " * (ident * 2) + str(message)
358350

359-
def hexdump(self, src, length=16):
351+
def _create_hexdump(self, src, length=16):
360352
FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
361353
result = []
362354
for i in xrange(0, len(src), length):
@@ -366,7 +358,7 @@ def hexdump(self, src, length=16):
366358
result.append("%04X %-*s %s\n" % (i, length*3, hexa, printable))
367359
return ''.join(result)
368360

369-
def read_native(self, field_type, ident):
361+
def _read_value(self, field_type, ident, name = ""):
370362
if len(field_type) > 1:
371363
field_type = field_type[0] # We don't need details for arrays and objects
372364

@@ -386,12 +378,13 @@ def read_native(self, field_type, ident):
386378
elif field_type == self.TYPE_DOUBLE:
387379
(res, ) = self._readStruct(">d")
388380
elif field_type == self.TYPE_OBJECT or field_type == self.TYPE_ARRAY:
389-
res = self.read_and_exec_opcode(ident=ident+1)
381+
res = self._read_and_exec_opcode(ident=ident+1)
390382
else:
391383
raise RuntimeError("Unknown typecode: %s" % field_type)
384+
self._log_ident("* %s %s: " % (field_type, name) + str(res), ident)
392385
return res
393386

394-
def convert_char_to_type(self, type_char):
387+
def _convert_char_to_type(self, type_char):
395388
typecode = type_char
396389
if type(type_char) is int:
397390
typecode = chr(type_char)
@@ -401,12 +394,18 @@ def convert_char_to_type(self, type_char):
401394
else:
402395
raise RuntimeError("Typecode %s (%s) isn't supported." % (type_char, typecode))
403396

404-
def add_reference(self, obj):
397+
def _add_reference(self, obj):
405398
self.references.append(obj)
406399

407-
def dump_state(self):
400+
def _oops_dump_state(self):
408401
print "==Oops state dump" + "=" * (30 - 17)
409-
print "Referenes:", self.references
402+
print "References:", self.references
403+
print "Stream seeking back at -16 byte (2nd line is an actual position!):"
404+
self.object_stream.seek(-16, mode=1)
405+
the_rest = self.object_stream.read()
406+
if len(the_rest):
407+
print "Warning!!!!: Stream still has %s bytes left." % len(the_rest)
408+
print self._create_hexdump(the_rest)
410409
print "=" * 30
411410
# =====================================================================================
412411

0 commit comments

Comments
 (0)