Android逆向之旅--基于python解析编译之后的AndroidManifest.xml文件格式

    xiaoxiao2023-10-16  32

     本文通过python解析编译过的AndroidManifext.xml文件格式,还原其可阅读的格式。

    # -*- coding:utf-8 -*- __author__ = "教科书般的男人" import os xmldr = { } stringContentList = [] xmlsb =[ ] uri2prefix = {} prefix2uri = {} def filterStringNull(data): if data == None or len(data)==0: return data temp = [] for i in data: if i != "00": temp.append(i) str = [chr(int(i, 16)) for i in temp] return "".join(str) def parse_xml(filename): f = open(filename, "rb") print # 解析xml文件的头部,获取Magic Nubmber和File Size xmlident = f.read() xml_content = [i for i in xmlident] xml_content_16 = [hex(ord(i))[2:].zfill(2) for i in xml_content] header = [hex(ord(i))[2:].zfill(2) for i in xmlident[0:8]] magic_number = header[:4][::-1] xml_size = header[4:8][::-1] xmldr['magic_number'] = magic_number xmldr['xml_size'] = xml_size print "Parse XML Header-----------" print "magic number:" + str(magic_number[0]) + " " + str(magic_number[1]) + " " + str(magic_number[2]) + " " + str(magic_number[3]) print "xml size:" + str(xml_size[0]) + " " + str(xml_size[1]) + " " + str(xml_size[2]) + " " + str(xml_size[3]) xmlsb.append("<?xml version=\'1.0\'encoding=\'utf-8\'?> ") xmlsb.append("\n") # 解析StringChunk信息 print "--------Parse String Chunk-----------" ChunkType = xml_content_16[8:12][::-1] print "string chunktag:" + str(ChunkType[0]) + " " + str(ChunkType[1]) + " " + str(ChunkType[2]) + " " + str(ChunkType[3]) Chunk_size_str = xml_content_16[12:16][::-1] Chunk_size = "".join(Chunk_size_str) print "Chunk_size:" + str(int(Chunk_size, 16)) String_Count_str = xml_content_16[16:20][::-1] String_Count = "".join(String_Count_str) print "Count:" + str(int(String_Count, 16)) Style_Offset_str = xml_content_16[28:32][::-1] Style_Offset = "".join(Style_Offset_str) print "Start:" + str(int(Style_Offset, 16) + 8) chunkStringContentByte = xml_content[212:2056] firstStringSizeByte_str = xml_content_16[212:214][::-1] # 一个字符对应两个字节 firstStringSize = int("".join(firstStringSizeByte_str), 16) * 2 print "size:" + str(firstStringSize) firstStringContent = filterStringNull(xml_content_16[214:238]) print "first string:" + firstStringContent stringContentList.append(firstStringContent) endStringIndex = 212 + 2 + firstStringSize + 2 while (endStringIndex < 2056): stringSize_16 = xml_content_16[endStringIndex:endStringIndex + 2][::-1] stringSize = int("".join(stringSize_16), 16) * 2 per_str = filterStringNull(xml_content_16[endStringIndex + 2:endStringIndex + stringSize + 2]) try: print "str:" + per_str except: print "str:", per_str stringContentList.append(per_str) endStringIndex += 2 + stringSize + 2 # 解析ResourceID Chunk # resourceID chunk的偏移量 = magic number的偏移量 + File size的偏移量 + chunk_size resourceChunkOffset = int(Chunk_size, 16) + 8 resourceChunkContent = xml_content_16[resourceChunkOffset:] print "-------Parse Resource Chunk--------" print " ".join(resourceChunkContent[:4][::-1]) resourceChunkSize = int("".join(resourceChunkContent[4:8][::-1]), 16) print "chunk size:" + str(resourceChunkSize) for i in range(resourceChunkSize / 4 - 2): id_hex = "".join(resourceChunkContent[(8 + 4 * i):(8 + 4 * i+4)][::-1]) id = int(id_hex, 16) print "id:" + str(id) + "," + "hex:" + id_hex nextChunkOffset = resourceChunkOffset + resourceChunkSize parse_xml_content(xml_content_16, nextChunkOffset) def parse_start_namespace_chunk(byteSrc, nextchunkoffset, chunksize): """解析Start Namespace Chunk""" namespaceChunkCotent = byteSrc[nextchunkoffset:] # 解析行号 lineNumber = namespaceChunkCotent[8:12][::-1] print "行号:" + str(int("".join(lineNumber), 16)) # 解析prefix,过滤行号后未知的四个字节 prefixByte = namespaceChunkCotent[16:20][::-1] prefixIndex = int("".join(prefixByte), 16) print "prefix:" + str(prefixIndex) print "prefix str:", stringContentList[prefixIndex] # 解析URI uriByte = namespaceChunkCotent[20:24][::-1] uriIndex = int("".join(uriByte), 16) print "uri:" + str(uriIndex) print "uri str:", stringContentList[uriIndex] uri2prefix[stringContentList[uriIndex]] = stringContentList[prefixIndex] prefix2uri[stringContentList[prefixIndex]] = stringContentList[uriIndex] def parse_start_tag_chunk(bytesrc, nextchunkoffset, chunksize): """解析start tag chunk""" startTagChunkContent = bytesrc[nextchunkoffset:] # 解析行号 startTagChunkLineNumberByte = startTagChunkContent[8:12][::-1] startTagChunkLineNumber = int("".join(startTagChunkLineNumberByte), 16) print "行号:", startTagChunkLineNumber # 解析Uri,略过Unknown startTagPrefixByte = startTagChunkContent[16:20][::-1] startTagPrefixIndex = int("".join(startTagPrefixByte), 16) if startTagPrefixIndex != -1 and startTagPrefixIndex < len(stringContentList): print "NamespaceUri:", startTagPrefixIndex print "NamespaceUri str:", stringContentList[startTagPrefixIndex] else: print startTagPrefixIndex print "NamespaceUri null" # 解析TagName startTagNameByte = startTagChunkContent[20:24][::-1] tagNameIndex = int("".join(startTagNameByte), 16) if tagNameIndex != -1 and tagNameIndex < len(stringContentList): tagName = stringContentList[tagNameIndex] print "tag name index:", tagNameIndex print "tag:", tagName else: print "tag name null" # 解析Flag startTagFlagByte = startTagChunkContent[24:28][::-1] startTagFlag = "".join(startTagFlagByte) print "Flags:", startTagFlag # 解析属性个数 startTagAttrByte = startTagChunkContent[28:32][::-1] startTagAttrCount = int("".join(startTagAttrByte), 16) print "attr count:", startTagAttrCount # 解析包含的类属性 startTagClassAtrByte = startTagChunkContent[32:36][::-1] print "class attr: ", " ".join(startTagClassAtrByte) # 解析属性内容 attrList = [] for i in range(startTagAttrCount): temp = [] for j in range(5): valueByte = startTagChunkContent[(36 + i * 20 + j * 4):(36 + i * 20 + j * 4 + 4)][::-1] value = int("".join(valueByte), 16) if j == 3: value = value >> 24 if j == 4: value = "".join(valueByte) temp.append(value) print temp attrList.append(temp) for i in range(startTagAttrCount): if attrList[i][0] != -1 and attrList[i][0] < len(stringContentList): print "nameSpaceUri:", stringContentList[attrList[i][0]] else: print "nameSpaceUri == null" if attrList[i][1] != -1 and attrList[i][1] < len(stringContentList): print "name:", stringContentList[attrList[i][1]] else: print "name == null" if attrList[i][2] != -1 and attrList[i][2] < len(stringContentList): print "valueString:", stringContentList[attrList[i][2]] else: print "valueString == null" xmlsb.append(createStartTagXml(tagName, attrList)) def createStartTagXml(tagName, attr): tagsb = "" if "manifest" == tagName: tagsb += "<manifest xmls:" for key in prefix2uri.keys(): tagsb = tagsb + str(key) + ":\"" + prefix2uri.get(key) + ":\"" tagsb = tagsb + "\n" else: tagsb = tagsb + "<" + tagName # 构建属性值 if len(attr) == 0: tagsb = tagsb + ">\n" else: tagsb += "\n" for i in range(len(attr)): attributedata = attr[i] print attributedata try: prefixName = uri2prefix.get(stringContentList[attributedata[0]]) except: prefixName = "null" if prefixName == "null": prefixName = "" tagsb += " " # try: # name = stringContentList[attributedata[2]] # except: # name = "null" name = getAttributeData(attributedata) tagsb = tagsb + prefixName + (":" if len(prefixName) > 0 else "") + stringContentList[attributedata[1]] + "=\"" + name +"\"" if i == len(attr) - 1: tagsb = tagsb + "/>" tagsb += "\n" return tagsb def getAttributeData(attributedata): if attributedata[3] == 3: value = stringContentList[attributedata[2]] elif attributedata[3] == 1: value = "@" + attributedata[4] elif attributedata[3] == 18: if int(attributedata[4], 16) > 0: value = "True" else: value = "False" elif attributedata[3] == 16: value = str(int(attributedata[4], 16)) else: value = attributedata[3] return value def parse_end_tag_chunk(byteSrc, nextchunkoffset, chunksize): """解析End tag Chunk""" # 解析行号 endTagChunkContent = byteSrc[nextchunkoffset:] lineNumberByte = endTagChunkContent[8:12][::-1] lineNumber = int("".join(lineNumberByte), 16) print "行号", lineNumber # 解析Uri UriByte = endTagChunkContent[16:20][::-1] UriIndex = int("".join(UriByte), 16) if UriIndex != -1 and UriIndex < len(stringContentList): print "uri:", UriIndex print "uri str:", stringContentList[UriIndex] else: print "uri null" # 解析tag name prefixByte = endTagChunkContent[20:24][::-1] prefixIndex = int("".join(prefixByte), 16) if prefixIndex != -1 and prefixIndex < len(stringContentList): print "name:", prefixIndex print "name str:", stringContentList[prefixIndex] else: print "name null" def parse_end_namespace_chunk(byteSrc, nextchunkoffset, chunksize): """解析End namespace Chunk""" # 解析行号 endNamespaceChunkContent = byteSrc[nextchunkoffset:] lineNumberByte = endNamespaceChunkContent[8:12][::-1] lineNumber = int("".join(lineNumberByte), 16) print "行号", lineNumber # 解析prefix prefixByte = endNamespaceChunkContent[16:20][::-1] prefixIndex = int("".join(prefixByte), 16) if prefixIndex != -1 and prefixIndex < len(stringContentList): print "prefix:", prefixIndex print "prefix str:", stringContentList[prefixIndex] else: print "prefix null" # 解析Uri UriByte = endNamespaceChunkContent[20:24][::-1] UriIndex = int("".join(UriByte), 16) if UriIndex != -1 and UriIndex < len(stringContentList): print "uri:", UriIndex print "uri str:", stringContentList[UriIndex] else: print "uri null" def parse_xml_content(byteSrc, index): """循环解析androidmanifest.xml中CmlContetn Chunk内容""" nextchunkoffset = index while(nextchunkoffset < len(byteSrc)): chunkTagByte = byteSrc[nextchunkoffset+0:nextchunkoffset+4][::-1] chunkSizeByte = byteSrc[nextchunkoffset+4:nextchunkoffset+8][::-1] chunTag = "".join(chunkTagByte) chunksize = int("".join(chunkSizeByte), 16) print "chunk tag", chunTag print "chunk size", chunksize if chunTag == "00100100": print "---------parse start namespace--------" parse_start_namespace_chunk(byteSrc, nextchunkoffset, chunksize) if chunTag == "00100102": print "--------parse start tag--------" parse_start_tag_chunk(byteSrc, nextchunkoffset, chunksize) if chunTag == "00100103": print "---------parse end tag--------" parse_end_tag_chunk(byteSrc, nextchunkoffset, chunksize) if chunTag == "00100101": print "---------parse end namespace--------" parse_end_namespace_chunk(byteSrc, nextchunkoffset, chunksize) nextchunkoffset += chunksize parse_xml("AndroidManifest.xml".decode("utf-8")) print "".join(xmlsb)

    参考链接:http://www.520monkey.com/archives/575

    最新回复(0)