crossreferences (XREFs)
Androguard 的交叉引用包含了一下的四个东西:
XREFs 工作在两个方向: xref_from 和 xref_to . To 表示的是现在的这个对象正在调用其他的对象, from 意味这当前的对象正在被其他的对象调用。
举一个例子:
A 调用了B的对象,那么 A.xref_to 就包含了B
那么B被A调用了,那么B.xref_from 就包含了A
考虑如下的Java 源代码:
class Foobar {
public int afield = 23;
public void somemethod() {
String astring = "hello world";
}
}
class Barfoo {
public void othermethod() {
Foobar x = new Foobar();
x.somemethod();
System.out.println(x.afield);
}
}
这里有两个类,一个Foobar,一个Barfoo. Barfoo 这个列实例化了另一个类 FooBar 以及调用了这个类的方法和字段。
afield 在 Barfoo.othermethod的xref_to 中, 同样的也在Foobar 的xref_to 里。
针对Androguard 的3.4.0 版本来说
我们可以使用androguard analyze 来启动 ipython, 简单快速的分析我们的apk 文件。
$ androguard analyze examples/android/TestsAndroguard/bin/TestActivity.apk
Please be patient, this might take a while.
Found the provided file is of type 'APK'
[INFO ] androguard.analysis: End of creating cross references (XREF)
[INFO ] androguard.analysis: run time: 0min 00s
Added file to session: SHA256::3bb32dd50129690bce850124ea120aa334e708eaa7987cf2329fd1ea0467a0eb
Loaded APK file...
>>> a
<androguard.core.bytecodes.apk.APK object at 0x000000000581D710>
>>> d
[<androguard.core.bytecodes.dvm.DalvikVMFormat object at 0x000000000D847400>]
>>> dx
<analysis.Analysis VMs: 1, Classes: 495, Strings: 496>
不同的Androguard 版本的启用ipython 方式稍微有点不同
下面是androguard 3.1.1 的启动方式
$ androlyze.py
Androguard version 3.1.1 started
In [1]: a, d, dx = AnalyzeAPK("examples/android/abcore/app-prod-debug.apk")
# Depending on the size of the APK, this might take a while...
In [2]:
这里的三个对象分别表示了 一个APK的对象a, 一个DalvikVMFormat 的对象,dx 的一个Analysis 分析对象
我们使用 Analysis 的对象来做分析 ~androguard.core.analysis.analysis.Analysis
In [2]: dx.get_classes()
Out[2]:
[<analysis.ClassAnalysis Ljava/io/FileNotFoundException; EXTERNAL>,
<analysis.ClassAnalysis Landroid/content/SharedPreferences; EXTERNAL>,
<analysis.ClassAnalysis Landroid/support/v4/widget/FocusStrategy$BoundsAdapter;>,
<analysis.ClassAnalysis Landroid/support/v4/media/MediaBrowserCompat$MediaBrowserServiceCallbackImpl;>,
<analysis.ClassAnalysis Landroid/support/transition/WindowIdImpl;>,
<analysis.ClassAnalysis Landroid/media/MediaMetadataEditor; EXTERNAL>,
<analysis.ClassAnalysis Landroid/support/v4/app/BundleCompat$BundleCompatBaseImpl;>,
<analysis.ClassAnalysis Landroid/support/transition/MatrixUtils$1;>,
<analysis.ClassAnalysis Landroid/support/v7/widget/ShareActionProvider;>,
...
我们可以使用get_classes() 来得到一个list 的ClassAnalysis 的对象.
需要注意的是,这里External 字段表示的是这个类不是我们Dex 文件里面自己定义的,而是直接引用了整个Java 文件定义的函数,或者是API
类似的还有get_methods(), get_fields(),get_strings()
XREFS for method calls
我们可以使用dx.get_classes() 找到我们的所有的方法
我们可以选取其中的类,根据这个结果我们想得到想要分析的那个类这个时候查看它的调用关系。
In [4]: dx.classes['Ltests/androguard/TestActivity;']
Out[4]: <analysis.ClassAnalysis Ltests/androguard/TestActivity;>
在这里得到一个class 的analysis的分析对象,我们可以使用 classes, 或者是find_classes() ,在这里传入的参数是我们的类的名字
这个时候我们会得到一个ClassAnalysis 的对象,我们可以遍历这个类(‘Ltests/androguard/TestActivity;’)含有的方法,以及这个类调用的类的名字以及这个调用的方法
e.g.
In [10]: for meth in dx.classes['Ltests/androguard/TestActivity;'].get_methods():
...: print("inside method {}".format(meth.name))
...: for _, call, _ in meth.get_xref_to():
...: print(" calling -> {} -- {}".format(call.class_name, call.name))
...:
inside method testCall1
calling -> Ljava/lang/StringBuilder; -- toString
calling -> Ljava/lang/StringBuilder; -- append
calling -> Ljava/lang/StringBuilder; -- <init>
calling -> Ljava/io/PrintStream; -- println
inside method testCalls
calling -> Ljava/lang/Object; -- getClass
calling -> Ljava/io/PrintStream; -- println
calling -> Ltests/androguard/TestIfs; -- testIF
calling -> Ltests/androguard/TestActivity; -- testCall2
[...]
External 的方法是没有交叉引用的Xref_to 这个属性的(method), 因为它们就是一些造好的轮子,不能调用谁,只能被别人调用,所以它们是有xref_from 的属性的
e.g.
In [3]: dx.classes['Ljava/io/File;']
Out[3]: <analysis.ClassAnalysis Ljava/io/File; EXTERNAL>
In [4]: for meth in dx.classes['Ljava/io/File;'].get_methods():
...: print("usage of method {}".format(meth.name))
...: for _, call, _ in meth.get_xref_from():
...: print(" called by -> {} -- {}".format(call.class_name, call.name))
...:
usage of method getPath
called by -> Landroid/support/v4/util/AtomicFile; -- <init>
usage of method <init>
called by -> Landroid/support/v4/util/AtomicFile; -- <init>
usage of method delete
called by -> Landroid/support/v4/util/AtomicFile; -- failWrite
called by -> Landroid/support/v4/util/AtomicFile; -- delete
called by -> Landroid/support/v4/util/AtomicFile; -- delete
called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
called by -> Landroid/support/v4/util/AtomicFile; -- openRead
called by -> Landroid/support/v4/util/AtomicFile; -- finishWrite
usage of method renameTo
called by -> Landroid/support/v4/util/AtomicFile; -- openRead
called by -> Landroid/support/v4/util/AtomicFile; -- failWrite
called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
usage of method exists
called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
called by -> Landroid/support/v4/util/AtomicFile; -- openRead
called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
usage of method getParentFile
called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
usage of method mkdir
called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
我们如果想去查询某个类或者是方法使用的字段我们可以使用, get_strings() 这个方法,之后我们如果对某个字符串感兴趣的话,我们可以使用的 strings 或者find_strings() 来得到我们交叉引用的对象。
In [12]: dx.strings['boom']
Out[12]: <analysis.StringAnalysis 'boom'>
这个时候我们就可以得到一个StringAnalysis 的对象。
同样需要注意的是,string也没有调用的能力,所以不可能存在xref_to 的能力
但是我们仍然可以使用xref_from() 来得到它的使用情况:
In [14]: for _, meth in dx.strings['boom'].get_xref_from():
...: print("Used in: {} -- {}".format(meth.class_name, meth.name))
...:
Used in: Ltests/androguard/TestActivity; -- test_base
XREFs for fields
字段的使用是有意嗲点的不同,它没有xref_from 和xref_to 的方法,但是它用的是xref_read() 和xref_write(), 我们需要先用find_methods() 之后查找字段。
In [25]: 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))
...:
Field: value
read in Ltests/androguard/TestActivity; -- pouet
read in Ltests/androguard/TestActivity; -- test1
read in Ltests/androguard/TestActivity; -- test_base
read in Ltests/androguard/TestActivity; -- testVars
write in Ltests/androguard/TestActivity; -- <init>
write in Ltests/androguard/TestActivity; -- pouet2
write in Ltests/androguard/TestActivity; -- <init>
write in Ltests/androguard/TestActivity; -- <init>