Mercurial > paraspace
view paraspace/dexfile.py @ 8:59dd10bf60f2
Parse annotation items
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Tue, 24 May 2011 14:55:18 +0800 |
parents | 1d776ec496e5 |
children | 9a49826b26d4 |
line wrap: on
line source
class _DEX_header(object): magic = None # 0x00, 8 bytes checksum = None # 0x08, 4 bytes signature = None # 0x0c, 20 bytes fileSize = None # 0x20, 4 bytes headerSize = None # 0x24 endianTag = None # 0x28 linkSize = None # 0x2c linkOff = None # 0x30 mapOff = None # 0x34 stringIdsSize = None # 0x38 stringIdsOff = None # 0x3c typeIdsSize = None # 0x40 typeIdsOff = None # 0x44 protoIdsSize = None # 0x48 protoIdsOff = None # 0x4c fieldIdsSize = None # 0x50 fieldIdsOff = None # 0x54 methodIdsSize = None # 0x58 methodIdsOff = None # 0x5c classDefsSize = None # 0x60 classDefsOff = None # 0x64 dataSize = None # 0x68 dataOff = None # 0x6c header_fields = \ 'magic checksum signature fileSize headerSize endianTag ' \ 'linkSize linkOff mapOff stringIdsSize stringIdsOff typeIdsSize ' \ 'typeIdsOff protoIdsSize protoIdsOff fieldIdsSize fieldIdsOff ' \ 'methodIdsSize methodIdsOff classDefsSize classDefsOff ' \ 'dataSize dataOff'.split() def parse(self, data): self.magic = data[:8] self.checksum = data[8: 0x0c] self.signature = data[0x0c: 0x20] idx = 0x20 fields = 'fileSize headerSize endianTag linkSize linkOff mapOff ' \ 'stringIdsSize stringIdsOff typeIdsSize typeIdsOff ' \ 'protoIdsSize protoIdsOff fieldIdsSize fieldIdsOff ' \ 'methodIdsSize methodIdsOff classDefsSize classDefsOff ' \ 'dataSize dataOff'.split() for field in fields: d = data[idx: idx + 4] value = _to_uint(d) setattr(self, field, value) idx = idx + 4 pass pass pass class man_off(object): off = None def __init__(self, off): self.off = off pass def __call__(self, sz=0): off = self.off self.off = off + sz return off pass def _to_uint(data): v = 0 sh = 0 for c in data: v = v + (ord(c) << sh) sh = sh + 8 pass return v def _to_int(data): v = _to_uint(data) sz = len(data) if sz and ((1 << (sz * 8 - 1)) & v): v = -((1 << (sz * 8)) - v) pass return v def _uleb128(data): sh = 0 v = 0 for c in data: cv = ord(c) v = v + ((cv & 0x7f) << sh) sh = sh + 7 if cv <= 0x7f: break pass nbytes = sh / 7 return v, nbytes def _leb128(data): v, sh = _uleb128(data) if v & (1 << (sh * 7 - 1)): v = -((1 << (sh * 7)) - v) pass return v, sh class _DEX_MapItem(object): type = None # 2 bytes unused = None # 2 bytes size = None # 4 bytes offset = None # 4 bytes data_size = 12 types = { 0x0000: 'kDexTypeHeaderItem', 0x0001: 'kDexTypeStringIdItem', 0x0002: 'kDexTypeTypeIdItem', 0x0003: 'kDexTypeProtoIdItem', 0x0004: 'kDexTypeFieldIdItem', 0x0005: 'kDexTypeMethodIdItem', 0x0006: 'kDexTypeClassDefItem', 0x1000: 'kDexTypeMapList', 0x1001: 'kDexTypeTypeList', 0x1002: 'kDexTypeAnnotationSetRefList', 0x1003: 'kDexTypeAnnotationSetItem', 0x2000: 'kDexTypeClassDataItem', 0x2001: 'kDexTypeCodeItem', 0x2002: 'kDexTypeStringDataItem', 0x2003: 'kDexTypeDebugInfoItem', 0x2004: 'kDexTypeAnnotationItem', 0x2005: 'kDexTypeEncodedArrayItem', 0x2006: 'kDexTypeAnnotationsDirectoryItem' } def parse(self, data): self.type = _to_uint(data[:2]) self.size = _to_uint(data[4:8]) self.offset = _to_uint(data[8:12]) pass @classmethod def find_type_name(self, type_name): type_value = [v for v, name in _DEX_MapItem.types.items() if name == type_name][0] return type_value pass class _DEX_TypeId(object): descriptorIdx = None # 4 bytes data_size = 4 def parse(self, data): self.descriptorIdx = _to_uint(data[:4]) pass pass class _DEX_ProtoId(object): shortyIdx = None # 4 bytes returnTypeIdx = None # 4 bytes parametersOff = None # 4 bytes data_size = 12 def parse(self, data): self.shortyIdx = _to_uint(data[:4]) self.returnTypeIdx = _to_uint(data[4:8]) self.parametersOff = _to_uint(data[8:12]) pass pass class _DEX_FieldId(object): classIdx = None # 2 bytes typeIdx = None # 2 bytes nameIdx = None # 4 bytes data_size = 8 def parse(self, data): self.classIdx = _to_uint(data[:2]) self.typeIdx = _to_uint(data[2:4]) self.nameIdx = _to_uint(data[4:8]) pass pass class _DEX_MethodId(object): classIdx = None # 2 bytes protoIdx = None # 2 bytes nameIdx = None # 4 bytes data_size = 8 def parse(self, data): self.classIdx = _to_uint(data[:2]) self.protoIdx = _to_uint(data[2:4]) self.nameIdx = _to_uint(data[4:8]) pass pass class _DEX_ClassDef(object): classIdx = None # 0x00 accessFlags = None # 0x04 superclassIdx = None # 0x08 interfacesOff = None # 0x0c sourceFileIdx = None # 0x10 annotationsOff = None # 0x14 classDataOff = None # 0x18 staticValuesOff = None # 0x1c data_size = 0x20 def parse(self, data): self.classIdx = _to_uint(data[:4]) self.accessFlags = _to_uint(data[4:8]) self.superclassIdx = _to_uint(data[8:0xc]) self.interfacesOff = _to_uint(data[0xc:0x10]) self.sourceFileIdx = _to_uint(data[0x10:0x14]) self.annotationsOff = _to_uint(data[0x14:0x18]) self.classDataOff = _to_uint(data[0x18:0x1c]) self.staticValuesOff = _to_uint(data[0x1c:0x20]) pass pass class _DEX_ClassDataHeader(object): staticFieldsSize = None instanceFieldsSize = None directMethodsSize = None virtualMethodsSize = None data_size = None def parse(self, data, off): self.staticFieldsSize, sh = _uleb128(data[off:off + 10]) sz = sh off = off + sh self.instanceFieldsSize, sh = _uleb128(data[off:off + 10]) sz = sz + sh off = off + sh self.directMethodsSize, sh = _uleb128(data[off:off + 10]) sz = sz + sh off = off + sh self.virtualMethodsSize, sh = _uleb128(data[off:off + 10]) sz = sz + sh self.data_size = sz pass pass class _DEX_Field(object): fieldIdx = None accessFlags = None data_size = None def parse(self, data, off): self.fieldIdx, sh = _uleb128(data[off:off + 10]) sz = sh off = off + sh self.accessFlags, sh = _uleb128(data[off:off + 10]) sz = sz + sh self.data_size = sz pass pass class _DEX_Method(object): methodIdx = None accessFlags = None codeOff = None data_size = None def parse(self, data, off): self.methodIdx, sh = _uleb128(data[off:off + 10]) sz = sh off = off + sh self.accessFlags, sh = _uleb128(data[off:off + 10]) sz = sz + sh off = off + sh self.codeOff, sh = _uleb128(data[off:off + 10]) sz = sz + sh self.data_size = sz pass pass class _DEX_ClassData(object): header = None # DexClassDataHeader staticFields = None # DexField* instanceFields = None # DexField* directMethods = None # DexMethod* virtualMethods = None # DexMethod* data_size = None def parse(self, data, off): header = _DEX_ClassDataHeader() header.parse(data, off) self.header = header cur_off = [off + header.data_size] def parse_field(): field = _DEX_Field() off = cur_off[0] field.parse(data, off) cur_off[0] = cur_off[0] + field.data_size # # field index depends previous one to reduce size # field.fieldIdx = field.fieldIdx + idx[0] idx[0] = field.fieldIdx return field def parse_method(): method = _DEX_Method() off = cur_off[0] method.parse(data, off) cur_off[0] = cur_off[0] + method.data_size # # method index depends previous one to reduce size # method.methodIdx = method.methodIdx + idx[0] idx[0] = method.methodIdx return method idx = [0] self.staticFields = [parse_field() for i in range(header.staticFieldsSize)] idx = [0] self.instanceFields = [parse_field() for i in range(header.instanceFieldsSize)] idx = [0] self.directMethods = [parse_method() for i in range(header.directMethodsSize)] idx = [0] self.virtualMethods = [parse_method() for i in range(header.virtualMethodsSize)] self.data_size = cur_off[0] - off pass pass class _DEX_TypeItem(object): typeIdx = None # 2 bytes data_size = 2 def parse(self, data, off): self.typeIdx = _to_uint(data[off:off + 2]) pass pass class _DEX_TypeList(object): typeItems = None data_size = None def parse(self, data, off): moff = man_off(off) size = _to_uint(data[moff(4):moff()]) def parse_type_item(): item = _DEX_TypeItem() item.parse(data, moff()) moff(item.data_size) return item typeItems = [parse_type_item() for i in range(size)] self.typeItems = typeItems self.data_size = moff() - off pass pass class _DEX_TypeLists(object): typeLists = None data_size = None def parse(self, num, data, off): def parse(): off = (cur_off[0] + 3) & ~0x3 # type list must aligned for 4 bytes typeList = _DEX_TypeList() typeList.parse(data, off) cur_off[0] = off + typeList.data_size return typeList cur_off = [off] typeLists = [parse() for i in range(num)] self.typeLists = typeLists self.data_size = cur_off[0] - off pass pass class _DEX_Try(object): startAddr = None # 4 bytes insnCount = None # 2 bytes handlerOff = None # 2 bytes data_size = 8 def parse(self, data, off): cur_off = off self.startAddr = _to_uint(data[cur_off:cur_off + 4]) cur_off = cur_off + 4 self.insnCount = _to_uint(data[cur_off:cur_off + 2]) cur_off = cur_off + 2 self.handlerOff = _to_uint(data[cur_off:cur_off + 2]) pass pass class _DEX_CatchHandler(object): typeIdx = None address = None data_size = None def parse(self, data, off): cur_off = off self.typeIdx, sh = _uleb128(data[cur_off:cur_off + 5]) cur_off = cur_off + sh self.address, sh = _uleb128(data[cur_off:cur_off + 5]) cur_off = cur_off + sh self.data_size = cur_off - off pass def parse1(self, data, off): self.address, sh = _uleb128(data[off:off + 5]) self.data_size = sh pass pass class _DEX_Catch(object): catchesAll = None handlers = None data_size = None def parse(self, data, off): moff = man_off(off) count, sh = _leb128(data[moff():moff() + 5]) moff(sh) if count > 0: self.catchesAll = False else: self.catchesAll = True count = -count pass def parse_handler(): handler = _DEX_CatchHandler() handler.parse(data, moff()) moff(handler.data_size) return handler self.handlers = [parse_handler() for i in range(count)] if self.catchesAll: # # Additional handler for catching all # handler = _DEX_CatchHandler() handler.parse1(data, moff()) moff(handler.data_size) self.handlers.append(handler) pass self.data_size = moff() - off pass pass class _DEX_Code(object): registersSize = None # 2 bytes insSize = None # 2 bytes outsSize = None # 2 bytes triesSize = None # 2 bytes debugInfoOff = None # 4 bytes insnsSize = None # 4 bytes insns = None try_items = None catch_handler_items = None data_size = None def parse(self, data, off): moff = man_off(off) self.registersSize = _to_uint(data[moff(2):moff()]) self.insSize = _to_uint(data[moff(2):moff()]) self.outsSize = _to_uint(data[moff(2):moff()]) self.triesSize = _to_uint(data[moff(2):moff()]) self.debugInfoOff = _to_uint(data[moff(4):moff()]) self.insnsSize = _to_uint(data[moff(4):moff()]) moff(self.insnsSize * 2) # skip insns if self.triesSize > 0: def parse_try_item(): try_item = _DEX_Try() try_item.parse(data, moff()) moff(try_item.data_size) return try_item moff.off = (moff.off + 3) & ~0x3 # align tries to 4 bytes self.try_items = [parse_try_item() for i in range(self.triesSize)] def parse_catch_handler(): catch = _DEX_Catch() catch.parse(data, moff()) moff(catch.data_size) return catch # # No tries, no catch handlers # handlersSize, sh = _uleb128(data[moff():moff() + 5]) moff(sh) self.catch_handler_items = [parse_catch_handler() for i in range(handlersSize)] pass moff.off = (moff() + 3) & ~0x3 # round code item to 4 bytes self.data_size = moff() - off pass pass ## \brief File offset to Annotation item. # # This type is not in libdex of Dalvik. We add this class to tracking # information for layout algorithm. # class _DEX_AnnotationRefItem(object): annotationOff = None # 4 bytes data_size = 4 def parse(self, data, off): self.annotationOff = _to_uint(data[off:off + 4]) pass pass class _DEX_AnnotationSetItem(object): # size = None # 4 bytes annotations = None # 4 * size bytes data_size = None def parse(self, data, off): moff = man_off(off) size = _to_uint(data[moff(4):moff()]) def parse_annotation_ref(): ref = _DEX_AnnotationRefItem() ref.parse(data, moff()) moff(ref.data_size) return ref self.annotations = [parse_annotation_ref() for i in range(size)] self.data_size = moff() - off pass pass class _DEX_FieldAnnotationsItem(object): fieldIdx = None # 4 bytes annotationsOff = None # 4 bytes data_size = 8 def parse(self, data, off): moff = man_off(off) self.fieldIdx = _to_uint(data[moff(4):moff()]) self.annotationsOff = _to_uint(data[moff(4):moff()]) pass pass class _DEX_MethodAnnotationsItem(object): methodIdx = None # 4 bytes annotationsOff = None # 4 bytes data_size = 8 def parse(self, data, off): moff = man_off(off) self.methodIdx = _to_uint(data[moff(4):moff()]) self.annotationsOff = _to_uint(data[moff(4):moff()]) pass pass class _DEX_ParameterAnnotationsItem(object): methodIdx = None # 4 bytes annotationsOff = None # 4 bytes data_size = 8 def parse(self, data, off): moff = man_off(off) self.methodIdx = _to_uint(data[moff(4):moff()]) self.annotationsOff = _to_uint(data[moff(4):moff()]) pass pass class _DEX_AnnotationsDirectoryItem(object): classAnnotationsOff = None # 4 bytes fieldAnnotationsItems = None methodAnnotationsItems = None parameterAnnotationsItems = None data_size = None def parse(self, data, off): moff = man_off(off) self.classAnnotationsOff = _to_uint(data[moff(4):moff()]) fieldsSize = _to_uint(data[moff(4):moff()]) methodsSize = _to_uint(data[moff(4):moff()]) parametersSize = _to_uint(data[moff(4):moff()]) def parse_fieldAnnotationsItem(): item = _DEX_FieldAnnotationsItem() item.parse(data, moff()) moff(item.data_size) return item def parse_methodAnnotationsItem(): item = _DEX_MethodAnnotationsItem() item.parse(data, moff()) moff(item.data_size) return item def parse_parameterAnnotationsItem(): item = _DEX_ParameterAnnotationsItem() item.parse(data, moff()) moff(item.data_size) return item self.fieldAnnotationsItems = [parse_fieldAnnotationsItem() for i in range(fieldsSize)] self.methodAnnotationsItems = [parse_methodAnnotationsItem() for i in range(methodsSize)] self.parameterAnnotationsItems = [parse_parameterAnnotationsItem() for i in range(parametersSize)] self.data_size = moff() - off pass pass ## # # \see createAnnotationMember() in dalvik/vm/reflect/Annotation.c # class _DEX_AnnotationMember(object): nameIdx = None # optional valueType = None # 1 byte value = None # # Constants from DexFile.h # kDexAnnotationByte = 0x00 kDexAnnotationShort = 0x02 kDexAnnotationChar = 0x03 kDexAnnotationInt = 0x04 kDexAnnotationLong = 0x06 kDexAnnotationFloat = 0x10 kDexAnnotationDouble = 0x11 kDexAnnotationString = 0x17 kDexAnnotationType = 0x18 kDexAnnotationField = 0x19 kDexAnnotationMethod = 0x1a kDexAnnotationEnum = 0x1b kDexAnnotationArray = 0x1c kDexAnnotationAnnotation = 0x1d kDexAnnotationNull = 0x1e kDexAnnotationBoolean = 0x1f kDexAnnotationValueTypeMask = 0x1f kDexAnnotationValueArgShift = 5 data_size = None def parse(self, data, off): self.nameIdx, sh = _uleb128(data[off:off + 5]) self.parse_noname(data, off + sh) self.data_size = self.data_size + sh pass def parse_noname(self, data, off): moff = man_off(off) valueType = _to_uint(data[moff(1):moff()]) self.valueType = valueType width = valueType >> self.kDexAnnotationValueArgShift vtype = valueType & self.kDexAnnotationValueTypeMask if vtype == self.kDexAnnotationByte: self.value = _to_int(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationShort: self.value = _to_int(data[moff(width):moff()]) pass elif vtype == self.kDexAnnotationChar: self.value = _to_uint(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationInt: self.value = _to_int(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationLong: self.value = _to_int(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationFloat: self.value = _to_uint(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationDouble: self.value = _to_uint(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationBoolean: self.value = width != 0 pass elif vtype == self.kDexAnnotationString: # string index self.value = _to_uint(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationType: # TypeId index self.value = _to_uint(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationMethod: # MethodId index self.value = _to_uint(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationField: self.value = _to_uint(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationEnum: # FieldId index self.value = _to_uint(data[moff(width):moff()]) moff(1) pass elif vtype == self.kDexAnnotationArray: size, sh = _uleb128(data[moff():moff() + 5]) moff(sh) def parse_array_elm(): elm = _DEX_AnnotationMember() elm.parse_noname(data, moff()) moff(elm.data_size) return elm self.value = [parse_array_elm() for i in range(size)] pass elif vtype == self.kDexAnnotationAnnotation: annoitem = _DEX_AnnotationItem() annoitem.parse_novisibility(data, moff()) moff(annoitem.data_size) self.value = annoitem pass elif vtype == self.kDexAnnotationNull: self.value = 0 pass else: raise ValueError, \ 'Bad annotation element value byte 0x02x' % (valueType) self.data_size = moff() - off pass pass ## \brief Annotation item # # \see processEncodedAnnotation() in dalvik/vm/reflect/Annotation.c # class _DEX_AnnotationItem(object): visibility = None # 1 byte (optional) typeIdx = None members = None kDexVisibilityBuild = 0x00 kDexVisibilityRuntime = 0x01 kDexVisibilitySystem = 0x02 data_size = None def parse(self, data, off): self.visibility = _to_uint(data[off:off + 1]) self.parse_novisibility(data, off + 1) self.data_size = self.data_size + 1 pass def parse_novisibility(self, data, off): moff = man_off(off) self.typeIdx, sh = _uleb128(data[moff():moff() + 5]) moff(sh) size, sh = _uleb128(data[moff():moff() + 5]) moff(sh) def parse_AnnotationMemmber(): member = _DEX_AnnotationMember() member.parse(data, moff()) moff(member.data_size) return member self.members = [parse_AnnotationMemmber() for i in range(size)] self.data_size = moff() - off pass pass class DEXFile(object): _data = None _header = None _maps = None _strings = None _typeIds = None _protoIds = None _fieldIds = None _methodIds = None _classDefs = None _classDatas = None _typeLists = None _codeItems = None _annotationSetItems = None _annotationsDirectoryItems = None _annotationItems = None def __init__(self): pass def open(self, filename): fo = file(filename, 'r') data = fo.read() self.parse(data) pass def _parse_maps(self): data = self._data header = self._header off = header.mapOff num = _to_uint(data[off:off + 4]) off = off + 4 maps = [] for i in range(num): item_data = data[off:off + _DEX_MapItem.data_size] item = _DEX_MapItem() item.parse(item_data) maps.append(item) off = off + _DEX_MapItem.data_size pass self._maps = maps pass def find_map_item(self, type_value): maps = self._maps try: codeItem_map = [map for map in maps if map.type == type_value][0] except IndexError: return None return codeItem_map def find_map_item_name(self, type_name): type_value = _DEX_MapItem.find_type_name(type_name) map = self.find_map_item(type_value) return map def _parse_strings(self): data = self._data header = self._header strings = [] num = header.stringIdsSize off = header.stringIdsOff for i in range(num): str_start_off = _to_uint(data[off:off + 4]) str_stop_off = data.index('\x00', str_start_off) string = data[str_start_off:str_stop_off] sz, sh = _uleb128(string) string = string[sh:] strings.append(string) off = off + 4 pass self._strings = strings pass def _parse_typeIds(self): data = self._data header = self._header num = header.typeIdsSize off = header.typeIdsOff def parse(item_data): type_id = _DEX_TypeId() type_id.parse(item_data) return type_id item_size = _DEX_TypeId.data_size item_offs = range(off, off + item_size * num, item_size) item_datas = [data[item_off:item_off + item_size] for item_off in item_offs] typeIds = [parse(item_data) for item_data in item_datas] self._typeIds = typeIds pass def _parse_protoIds(self): data = self._data header = self._header num = header.protoIdsSize off = header.protoIdsOff def parse(item_data): proto_id = _DEX_ProtoId() proto_id.parse(item_data) return proto_id item_size = _DEX_ProtoId.data_size item_offs = range(off, off + item_size * num, item_size) item_datas = [data[item_off:item_off + item_size] for item_off in item_offs] protoIds = [parse(item_data) for item_data in item_datas] self._protoIds = protoIds pass def _parse_fieldIds(self): data = self._data header = self._header num = header.fieldIdsSize off = header.fieldIdsOff def parse(item_data): field_id = _DEX_FieldId() field_id.parse(item_data) return field_id item_size = _DEX_FieldId.data_size item_offs = range(off, off + item_size * num, item_size) item_datas = [data[item_off:item_off + item_size] for item_off in item_offs] fieldIds = [parse(item_data) for item_data in item_datas] self._fieldIds = fieldIds pass def _parse_methodIds(self): data = self._data header = self._header num = header.methodIdsSize off = header.methodIdsOff def parse(item_data): method_id = _DEX_MethodId() method_id.parse(item_data) return method_id item_size = _DEX_MethodId.data_size item_offs = range(off, off + item_size * num, item_size) item_datas = [data[item_off:item_off + item_size] for item_off in item_offs] methodIds = [parse(item_data) for item_data in item_datas] self._methodIds = methodIds pass def _parse_classDefs(self): data = self._data header = self._header num = header.classDefsSize off = header.classDefsOff def parse(item_data): class_def = _DEX_ClassDef() class_def.parse(item_data) return class_def item_size = _DEX_ClassDef.data_size item_offs = range(off, off + item_size * num, item_size) item_datas = [data[item_off:item_off + item_size] for item_off in item_offs] classDefs = [parse(item_data) for item_data in item_datas] self._classDefs = classDefs pass def _parse_classDatas(self): header = self._header data = self._data class_data_map = self.find_map_item_name('kDexTypeClassDataItem') moff = man_off(class_data_map.offset) def parse_class_data(): class_data = _DEX_ClassData() class_data.parse(data, moff()) moff(class_data.data_size) return class_data class_datas = [parse_class_data() for i in range(class_data_map.size)] self._classDatas = class_datas pass def _parse_typeLists(self): data = self._data typeList_map = self.find_map_item_name('kDexTypeTypeList') num_typeLists = typeList_map.size typeLists = _DEX_TypeLists() typeLists.parse(num_typeLists, data, typeList_map.offset) self._typeLists = typeLists pass def _parse_codeItems(self): data = self._data codeItem_map = self.find_map_item_name('kDexTypeCodeItem') if codeItem_map is None: return num_codeItems = codeItem_map.size moff = man_off(codeItem_map.offset) def parse_code(): code = _DEX_Code() code.parse(data, moff()) moff(code.data_size) return code codeItems = [parse_code() for i in range(num_codeItems)] self._codeItems = codeItems pass def _parse_annotationSetItems(self): data = self._data annoset_map = self.find_map_item_name('kDexTypeAnnotationSetItem') if annoset_map is None: return moff = man_off(annoset_map.offset) def parse_annotationSetItem(): item = _DEX_AnnotationSetItem() item.parse(data, moff()) moff(item.data_size) return item self._annotationSetItems = [parse_annotationSetItem() for i in range(annoset_map.size)] pass def _parse_annotationsDirectoryItems(self): data = self._data annodir_map = \ self.find_map_item_name('kDexTypeAnnotationsDirectoryItem') if annodir_map is None: return moff = man_off(annodir_map.offset) def parse_annotationDirItem(): item = _DEX_AnnotationsDirectoryItem() item.parse(data, moff()) moff(item.data_size) return item self._annotationsDirectoryItems = [parse_annotationDirItem() for i in range(annodir_map.size)] pass def _parse_annotationItems(self): data = self._data annoitem_map = self.find_map_item_name('kDexTypeAnnotationItem') if annoitem_map is None: return moff = man_off(annoitem_map.offset) def parse_annotationItem(): item = _DEX_AnnotationItem() item.parse(data, moff()) moff(item.data_size) return item self._annotationItems = [parse_annotationItem() for i in range(annoitem_map.size)] pass def parse(self, data): self._data = data header = _DEX_header() header.parse(data) self._header = header self._parse_maps() self._parse_strings() self._parse_typeIds() self._parse_protoIds() self._parse_fieldIds() self._parse_methodIds() self._parse_classDefs() self._parse_classDatas() self._parse_typeLists() self._parse_codeItems() self._parse_annotationSetItems() self._parse_annotationsDirectoryItems() self._parse_annotationItems() pass pass if __name__ == '__main__': dex = DEXFile() dex.open('test.dex') print 'Header' h = dex._header for attr in h.header_fields: print '\t%s: %s' % (attr, repr(getattr(h, attr))) pass print print 'Define Classes' strings = dex._strings classDefs = dex._classDefs typeIds = dex._typeIds for classDef in classDefs: typeId = typeIds[classDef.classIdx] descriptor = strings[typeId.descriptorIdx] data_off = classDef.classDataOff print '\t%s @0x%x' % (descriptor, data_off) pass print print 'Reference Classes' for typeId in typeIds: descriptor = strings[typeId.descriptorIdx] print '\t%s' % (descriptor) pass print print 'Class data' methodIds = dex._methodIds classDatas = dex._classDatas for classData in classDatas: print '\tclass' for method in classData.directMethods: code_off = method.codeOff methodId = methodIds[method.methodIdx] name = strings[methodId.nameIdx] print '\t\t%s@0x%x' % (name, code_off) pass for method in classData.virtualMethods: code_off = method.codeOff methodId = methodIds[method.methodIdx] name = strings[methodId.nameIdx] print '\t\t%s@0x%x' % (name, code_off) pass pass print print 'TypeLists size is %d bytes' % (dex._typeLists.data_size) bytes = sum([code.data_size for code in dex._codeItems]) print print 'CodeItems size is %d bytes' % (bytes) bytes = sum([annoset.data_size for annoset in dex._annotationSetItems]) print print 'AnnotationSetItems size is %d bytes' % (bytes) bytes = sum([annodir.data_size for annodir in dex._annotationsDirectoryItems]) print print 'AnnotationsDirtoryItems size is %d bytes' % (bytes) bytes = sum([annoitem.data_size for annoitem in dex._annotationItems]) print print 'AnnotationItems size is %d bytes' % (bytes) print print 'Data maps' maps = dex._maps for map in maps: print '\t0x%04x(%s) size=%d offset=0x%08x' % (map.type, map.types[map.type], map.size, map.offset) pass pass