最近一个项目是基于androguard的,花时间阅读了androguard的源码,对一个apk从axml到资源再到操作码的解析过程,第一篇-AXML解析
一段基本的androguard解析代码是这样的:
from androguard.core import androconf
from androguard.core.bytecodes import apk
from androguard.core.bytecodes import dvm
from androguard.core.analysis import analysis
from androguard.core.analysis import ganalysis
def main():
TEST ='test.apk'
apk_file = apk.APK(TEST)
vm = dvm.DalvikVMFormat(apk_file.get_dex())
vmx = analysis.VMAnalysis(vm) //或者是 vmx = analysis.uVMAnalysis(vm)
gmx = ganalysis.GVMAnalysis(vmx)
androguard的核心类apk,我们看看它的构造函数(允许我这么称呼__init__()):
def __init__(self, filename, raw=False, mode="r", magic_file=None, zipmodule=ZIPMODULE):
self.filename = filename #保存文件名
self.xml = {} #保存AndroidManifest.xml 解码后的 minidom对象
self.axml = {} #保存AndroidManifest.xml 解码后的 buff
self.arsc = {} #arsc 字典对象 构造时未作处理
self.package = "" #保存包名
self.androidversion = {} #保存版本信息
self.permissions = [] #保存权限list
self.valid_apk = False #是否未合法apk,默认值false
self.files = {} #apk里的文件以及其类型字典
self.files_crc32 = {} #apk里的文件对应的crc32值字典
self.magic_file = magic_file #魔术文件,用来生成files列表,默认输入为None
if raw == True:
self.__raw = filename #保存输入文件的字节流
else:
self.__raw = read(filename) #保存输入文件的字节流
self.zipmodule = zipmodule #文件使用的压缩模块,默认输入为1,使用系统自带zipfile模块
if zipmodule == 0:
self.zip = ChilkatZip(self.__raw) #为0使用 ChilkatZip
elif zipmodule == 2:
from androguard.patch import zipfile
self.zip = zipfile.ZipFile(StringIO.StringIO(self.__raw), mode=mode) #为2使用androguard自己patch的一个zipfile类
else:
import zipfile
self.zip = zipfile.ZipFile(StringIO.StringIO(self.__raw), mode=mode) #为1使用python自带zipfile模块
for i in self.zip.namelist(): #遍历zip里的文件列表
if i == "AndroidManifest.xml": #如果是 AndroidManifest.xml
self.axml[i] = AXMLPrinter(self.zip.read(i)) #通过AXMLPrinter类处理 AndroidManifest.xml,将解码后的代码保存给 axml['AndroidManifest.xml']
try:
self.xml[i] = minidom.parseString(self.axml[i].get_buff()) #将解码后的 AndroidManifest.xml代码再经过minidom.parseString 处理后保存到xml['AndroidManifest.xml']
except:
self.xml[i] = None
if self.xml[i] != None:
self.package = self.xml[i].documentElement.getAttribute("package") #寻找xml的元素属性 package即为包名
self.androidversion["Code"] = self.xml[i].documentElement.getAttributeNS(NS_ANDROID_URI, "versionCode") #寻找xml的元素属性 versionCode 即为版本号
self.androidversion["Name"] = self.xml[i].documentElement.getAttributeNS(NS_ANDROID_URI, "versionName") #寻找xml的元素属性 versionName 即为版本名
for item in self.xml[i].getElementsByTagName('uses-permission'):
self.permissions.append(str(item.getAttributeNS(NS_ANDROID_URI, "name"))) #寻找xml的元素属性 uses-permission 即为apk所用到权限保存到 self.permissions
self.valid_apk = True #标记为合法apk文件
self.get_files_types() #这个方法是获取文件以及其类型字典保存进self.files ,获取文件的crc32校验值保存进 self.files_crc32
解析之前允许我先介绍一下AXML的大概格式: