androlyze 的作用是提供一个交互环境,方便分析人员静态分析 Android 应用程序。
$ androguard analyze
In [1]: from androguard.misc import AnalyzeAPK
In [2]: a, d, dx = AnalyzeAPK("APK/app1.apk")
a:表示 APK文件 对象,在其中可以找到有关 APK 的信息,例如包名、权限、AndroidManifest.xml、resources。
AndroidManifest.xml:XML 格式的 Android 程序声明文件。其中包含 Android 系统运行程序前所必须掌握的重要信息,例如应用程序名称、图标、包名称、模块组成、授权和 SDK 最低版本等。
d:表示 DEX文件对象,是DalvikVMFormat 对象列表。DalvikVMFormat 对应 apk 文件中的 dex 文件,从dex文件中我们可以获取类、方法和字符串。
dex 是 Android 平台上( Dalvik 虚拟机)的可执行文件,相当于 Windows 平台中的 exe 文件,每个 Apk 安装包中都有 dex 文件,里面包含了该 app 的所有源码,通过反编译工具可以获取到相应的 java 源码。
dx:表示 Analysis 对象,其包含链接了关于 classes.dex 信息的特殊的类,甚至可以一次处理许多 dex 文件。
创建APK文件对象
的类其实就是androguard.core.bytecodes.apk.APK
。这个类用于访问APK文件中的所有元素。从类中的一些方法中也可以看出它的功能
#全部基本信息
show() # NoneType
#APK权限相关信息
get_permissions(apilevel=None) # list
get_requested_permissions() # list
get_declared_permissions() # list
get_certificates() # list
#安卓四大组件相关信息
get_activities() # list
get_services() # list
get_receivers() # list
get_providers() # list
#名称、版本号等基本信息
is_valid_APK() # bool
get_filename() # str
get_app_name() # str
get_package() # str
get_androidversion_code() # str
#相关文件和签名信息
get_signature() # bytes
get_files() # list
get_android_manifest_axml().get_xml() # bytes
创建该对象为list
,DalvikVMFormat
对象列表。DalvikVMFormat
类的主要功能是解析APK文件中classes.dex
,并获取其相关信息。
创建该对象的类为androguard.core.analysis.analysis.Analysis
,包含DEX文件的所有类、方法、字符串、成员变量等信息。
#information about class
get_classes() # list
get_external_classes() # generator
get_internal_classes() # generator
get_class_analysis(class_name) # ClassAnalysis
find_classes(name=’.*’, no_external=False) # generator
#information about string
get_strings(string=’.*’) # list
get_strings_analysis() # Dict[str, StringAnalysis]
find_strings() # generator
#information about methods
get_methods() # generator
get_method_by_name() # encoded method
get_method_analysis(method) # MethodAnalysis (parameter: encoded method)
find_methods(classname=’.*’, methodname=’.*’, descriptor=’.*’, accessflags=’.*’,
no_external=False) # generator
#information about fields
get_fields() # generator
get_field_analysis(field) # FiledAnalysis
find_fields(classname=’.*’, fieldname=’.*’, fieldtype=’.*’, accessflags=’.*’)# generator
#call graph
get_call_graph(classname=’.*’, methodname=’.*’, descriptor=’.*’, accessflags=’.*’,
no_isolated=False, entry_points=[]) #还未调试成功
get_classes()
returns a list of ClassAnalysis objects. Some of them are marked as EXTERNAL, which means that the source code of this class is not defined within the DEX files that are loaded inside the Analysis. For example, <analysis.ClassAnalysis Ljava/io/FileNotFoundException; EXTERNAL>.External does not automatically mean that this class/method is an Android or Java API
get_methods() # generator
get_method_analysis(method) # MethodAnalysis
get_xref_from()
get_xref_to()
'''
eg: get_xref_from()
Returns a dictionary of all classes calling the current class.
classes as keys (stored as ClassAnalysis)
a tuple as values
the first item : the ref_kind (which is an Enum of type REF_TYPE),
the second item : the method in which the class is called (MethodAnalysis)
the third item : offset in the method where the call is originating.
'''
is_android_api() # boolean
is_external() # boolean
get_value()
get_xref_from(withoffset=False) # list
get_field() # actual field type
get_xref_read(withoffset=False) # list (where the filed is read)
get_xref_write(withoffset=False)# list (where the filed is written to)
XREFs work in two directions: xref_from and xref_to. To means, that the current object is calling another object. From means, that the current object is called by another object.
# get_xref_from():
cls = dx.get_class_analysis('Landroidx/activity/R$attr;')
print('Found class {} in Analysis'.format(cls.name))
for caller, refs in cls.get_xref_from().items():
print('called from {}.format(caller.name))
for ref_kind, ref_method, ref_offset in refs:
print('in method {} {}'.format(ref_kind, ref_method))
# get_xref_to():
cls = dx.get_class_analysis('Landroidx/activity/R$attr;')
print('Found class {} in Analysis'.format(cls.name))
for calling, refs in cls.get_xref_to().items():
print('calling class {}'.format(calling.name))
for ref_kind, ref_method, ref_offset in refs:
print('calling method {} {}'.format(ref_kind, ref_method))
for one class
对象:ClassAnalysis
for meth in dx.classes['Landroidx/activity/R$attr;'].get_methods():
print("inside method {}".format(meth.name))
for _, call, _ in meth.get_xref_to():
print(" calling -> {} -- {}".format(call.class_name, call.name))
for all
for one_class in dx.find_classes():
for meth in one_class.get_methods():
print("inside method {}".format(meth.name))
for _, call, _ in meth.get_xref_to():
print(" calling -> {} -- {}".format(call.class_name, call.name))
Note: External method, like the API calls, will not give any XREFs for xref_to().
对象:StringAnalysis
确定该string在何处使用
for _, meth in dx.strings['$this$trimStart'].get_xref_from():
print("Used in: {} -- {}".format(meth.class_name, meth.name))
As Strings can contain nearly anything, use find_strings( )
Fields are a little bit different and do not use xref_from and xref_to but xref_read() and xref_write()
for field in dx.find_fields(classname='Ltests/androguard/TestActivity;', fieldname='^value$'):
print("Field: {}".format(field.name))
for _, meth in field.get_xref_read():
print(" read in {} -- {}".format(meth.class_name, meth.name))
for _, meth in field.get_xref_write():
print(" write in {} -- {}".format(meth.class_name, meth.name))
def get_apis_calls(dx, api_file_path):
api_calls = set()
for one_class in dx.find_classes():
if one_class.is_android_api() == True:
for meth in one_class.get_methods():
for _, call, _ in meth.get_xref_from():
api_calls.add("{} --> {}".format(call.name, meth.name))
api_calls = list(api_calls)
api_calls.sort()
with open(api_file_path + '_API_calls.txt', 'w') as f:
for api_call in api_calls:
f.write(api_call + '\n')
return api_calls