def _convert(self, value): if isinstance(value, disasm.Module): return self._covert(value.body) elif isinstance(value, disasm.CodeObject): return Block(*[self._convert(x) for x in value.opcodes]) elif isinstance(value, disasm.Opcode): arg = value.argument if isinstance(arg, list): arg = List(*[self._convert(x) for x in arg]) elif isinstance(arg, tuple): arg = Tuple(*[self._convert(x) for x in arg]) elif isinstance(arg, set): arg = Call(Ident('set'), Tuple(*[self._convert(x) for x in arg])) elif isinstance(arg, frozenset): arg = Call(Ident('frozenset'), Tuple(*[self._convert(x) for x in arg])) else: arg = self._convert(arg) return Opcode(value.offset, value.size, value.opcode, arg if op.has_argument(value.opcode) else None) else: return Const(value)
def unmarshal_node(self): type = self.read_int8() # Global singletons if type == _TYPE_NONE: return None elif type == _TYPE_TRUE: return True elif type == _TYPE_FALSE: return False # Collections elif type == _TYPE_TUPLE: return self.unmarshal_collection(tuple) elif type == _TYPE_LIST: return self.unmarshal_collection(list) elif type == _TYPE_SET: return self.unmarshal_collection(set) elif type == _TYPE_FROZEN_SET: return self.unmarshal_collection(frozenset) # Numbers elif type == _TYPE_INT: return self.read_int32() elif type == _TYPE_INT64: return struct.unpack('=q', self.file.read(8))[0] elif type == _TYPE_BINARY_FLOAT: return struct.unpack('=d', self.file.read(8))[0] elif type == _TYPE_BINARY_COMPLEX: return complex(*struct.unpack('=dd', self.file.read(16))) elif type == _TYPE_LONG: nbits = self.read_int32() if not nbits: return 0 n = 0 for i in range(abs(nbits)): digit = self.read_int16() n |= digit << (i * 15) return n if nbits > 0 else -n # Strings elif type == _TYPE_STRING: return self.read_string_ascii() elif type == _TYPE_UNICODE: return self.read_string_utf8() elif type == _TYPE_INTERNED: data = self.read_string_ascii() self.string_table.append(data) return data elif type == _TYPE_STRING_REF: index = self.read_int32() if index < 0 or index >= len(self.string_table): raise DisassemblerException( 'String index %d is outside string table' % index) return self.string_table[index] # Code objects elif type == _TYPE_CODE: co = CodeObject() co.co_argcount = self.read_int32() co.co_kwonlyargcount = self.read_int32() if op.has_kwonlyargcount( self.magic) else 0 co.co_nlocals = self.read_int32() co.co_stacksize = self.read_int32() co.co_flags = self.read_int32() type = self.read_int8() if type != _TYPE_STRING: raise DisassemblerException( 'Bytecode was not marshalled as a string (type was 0x%02X instead of 0x%02X)' % (type, _TYPE_STRING)) co.co_code = self.read_byte_array() co.co_consts = self.unmarshal_node() co.co_names = self.unmarshal_node() co.co_varnames = self.unmarshal_node() co.co_freevars = self.unmarshal_node() co.co_cellvars = self.unmarshal_node() co.co_filename = self.unmarshal_node() co.co_name = self.unmarshal_node() co.co_firstlineno = self.read_int32() co.co_lnotab = self.unmarshal_node() # Start disassembly argument = 0 i = 0 while i < len(co.co_code): offset = i opcode = op.from_bytecode(co.co_code[i], self.magic) if opcode is None: raise DisassemblerException('Unknown bytecode 0x%02X' % co.co_code[i]) i += 1 if op.has_argument(opcode): lo, hi = co.co_code[i:i + 2] argument |= (lo | (hi << 8)) i += 2 # The upper 16 bits of 32-bit arguments are stored in a fake # EXTENDED_ARG opcode that precedes the actual opcode if opcode == op.EXTENDED_ARG: argument <<= 16 continue # Decode the opcode argument if present arg = None if op.has_argument(opcode): if opcode == op.LOAD_CONST: if argument >= len(co.co_consts): raise DisassemblerException( 'Invalid argument %d for opcode %s' % (argument, opcode)) arg = co.co_consts[argument] elif opcode in [ op.LOAD_NAME, op.STORE_NAME, op.DELETE_NAME, op.LOAD_ATTR, op.STORE_ATTR, op.DELETE_ATTR, op.LOAD_GLOBAL, op.STORE_GLOBAL, op.DELETE_GLOBAL, op.IMPORT_NAME, op.IMPORT_FROM ]: if argument >= len(co.co_names): raise DisassemblerException( 'Invalid argument %d for opcode %s' % (argument, opcode)) arg = co.co_names[argument] elif opcode in [ op.LOAD_FAST, op.STORE_FAST, op.DELETE_FAST ]: if argument >= len(co.co_varnames): raise DisassemblerException( 'Invalid argument %d for opcode %s' % (argument, opcode)) arg = co.co_varnames[argument] else: arg = argument # Record disassembled opcode co.opcodes.append(Opcode(offset, i - offset, opcode, arg)) argument = 0 return co else: raise DisassemblerException( 'Cannot unmarshal unknown type 0x%02X' % type)
def unmarshal_node(self): type = self.read_int8() # Global singletons if type == _TYPE_NONE: return None elif type == _TYPE_TRUE: return True elif type == _TYPE_FALSE: return False # Collections elif type == _TYPE_TUPLE: return self.unmarshal_collection(tuple) elif type == _TYPE_LIST: return self.unmarshal_collection(list) elif type == _TYPE_SET: return self.unmarshal_collection(set) elif type == _TYPE_FROZEN_SET: return self.unmarshal_collection(frozenset) # Numbers elif type == _TYPE_INT: return self.read_int32() elif type == _TYPE_INT64: return struct.unpack('=q', self.file.read(8))[0] elif type == _TYPE_BINARY_FLOAT: return struct.unpack('=d', self.file.read(8))[0] elif type == _TYPE_BINARY_COMPLEX: return complex(*struct.unpack('=dd', self.file.read(16))) elif type == _TYPE_LONG: nbits = self.read_int32() if not nbits: return 0 n = 0 for i in range(abs(nbits)): digit = self.read_int16() n |= digit << (i * 15) return n if nbits > 0 else -n # Strings elif type == _TYPE_STRING: return self.read_string_ascii() elif type == _TYPE_UNICODE: return self.read_string_utf8() elif type == _TYPE_INTERNED: data = self.read_string_ascii() self.string_table.append(data) return data elif type == _TYPE_STRING_REF: index = self.read_int32() if index < 0 or index >= len(self.string_table): raise DisassemblerException('String index %d is outside string table' % index) return self.string_table[index] # Code objects elif type == _TYPE_CODE: co = CodeObject() co.co_argcount = self.read_int32() co.co_kwonlyargcount = self.read_int32() if op.has_kwonlyargcount(self.magic) else 0 co.co_nlocals = self.read_int32() co.co_stacksize = self.read_int32() co.co_flags = self.read_int32() type = self.read_int8() if type != _TYPE_STRING: raise DisassemblerException('Bytecode was not marshalled as a string (type was 0x%02X instead of 0x%02X)' % (type, _TYPE_STRING)) co.co_code = self.read_byte_array() co.co_consts = self.unmarshal_node() co.co_names = self.unmarshal_node() co.co_varnames = self.unmarshal_node() co.co_freevars = self.unmarshal_node() co.co_cellvars = self.unmarshal_node() co.co_filename = self.unmarshal_node() co.co_name = self.unmarshal_node() co.co_firstlineno = self.read_int32() co.co_lnotab = self.unmarshal_node() # Start disassembly argument = 0 i = 0 while i < len(co.co_code): offset = i opcode = op.from_bytecode(co.co_code[i], self.magic) if opcode is None: raise DisassemblerException('Unknown bytecode 0x%02X' % co.co_code[i]) i += 1 if op.has_argument(opcode): lo, hi = co.co_code[i:i + 2] argument |= (lo | (hi << 8)) i += 2 # The upper 16 bits of 32-bit arguments are stored in a fake # EXTENDED_ARG opcode that precedes the actual opcode if opcode == op.EXTENDED_ARG: argument <<= 16 continue # Decode the opcode argument if present arg = None if op.has_argument(opcode): if opcode == op.LOAD_CONST: if argument >= len(co.co_consts): raise DisassemblerException('Invalid argument %d for opcode %s' % (argument, opcode)) arg = co.co_consts[argument] elif opcode in [op.LOAD_NAME, op.STORE_NAME, op.DELETE_NAME, op.LOAD_ATTR, op.STORE_ATTR, op.DELETE_ATTR, op.LOAD_GLOBAL, op.STORE_GLOBAL, op.DELETE_GLOBAL, op.IMPORT_NAME, op.IMPORT_FROM]: if argument >= len(co.co_names): raise DisassemblerException('Invalid argument %d for opcode %s' % (argument, opcode)) arg = co.co_names[argument] elif opcode in [op.LOAD_FAST, op.STORE_FAST, op.DELETE_FAST]: if argument >= len(co.co_varnames): raise DisassemblerException('Invalid argument %d for opcode %s' % (argument, opcode)) arg = co.co_varnames[argument] else: arg = argument # Record disassembled opcode co.opcodes.append(Opcode(offset, i - offset, opcode, arg)) argument = 0 return co else: raise DisassemblerException('Cannot unmarshal unknown type 0x%02X' % type)