3.3 Implementation
3.3.2 Generating the Backward Slicing Graph
During the inter-procedural analysis enabled by bytecode search, we perform (back-ward) taint analysis and generate a backward slicing graph (BSG) for each sink API call analyzed. We have addressed three major challenges in the course of our im-plementation.
Defining a self-contained graph structure to cover all slicing information.
The first is to define a structure that can cover all slicing information across dif-ferent parameters tracked, difdif-ferent paths traced, and all kinds of bytecode in-structions. Instead of generating individual path-like slices as in typical An-droid slicing tools (e.g., [73, 94, 155]), we propose a self-contained graph struc-ture called backward slicing graph (BSG) to cover all slicing information. In this dissertation, one BSG corresponds to one unique sink API call, and we may also extend such per-sink BSG to per-app BSG in the future. Figure 3.5 shows an example BSG that is automatically generated by BackDroid for the app package com.proxybrowser.vpn.unblock.sites.browser. Com-pared with traditional slides, our BSG contains the following additional slicing in-formation within its structure:
• Hierarchical taint map. Although not displayed in Figure 3.5, a hierarchi-cal taint map is actually maintained during our inter-procedural backtracking.
Specifically, our BSG assigns a taint set to each tracked method and organizes all sets hierarchically according to their method signatures. For static fields, we also maintain a global taint set. With this hierarchical taint map, Back-Droid’s taint analysis module can easily retrieve the current taint set from BSG whenever its tracking jumps in or out from any (caller or inner) method, and can also track multiple sink parameters simultaneously.
• Inter-procedural relationships. To differentiate different taint paths with-out using individual slices, we maintain inter-procedural relationships via different kinds of cross-method edges in BSG. The most common one is the edge connecting a caller method, e.g., the edge from caller a.w.onPostExecute() to m.o.run() in Figure 3.5. It is also possible for a tracked method to invoke its inner method (e.g., method m.p.<init>() in Figure 3.5), and we use both calling and return edges to record this special inter-procedural relationship.
• Raw typed bytecode statements. Lastly, to enable BackDroid to recover full semantics during the forward analysis, it is necessary to keep raw typed byte-code instructions in BSG. We thus define a node structure called BSGUnit to wrap the original bytecode statements in Soot’s Unit format [61]. In this structure, we record the node ID, the signature of corresponding method, and most importantly, the typed bytecode Unit statement.
com.free.vpn.unblock.sites.proxybrowser.m.o
<com.free.vpn.unblock.sites.proxybrowser.activity.aw: void onPostExecute(java.lang.Object)>
<com.free.vpn.unblock.sites.proxybrowser.activity.SplashScreen: void c()> <com.free.vpn.unblock.sites.proxybrowser.m.o: void run()>
<com.free.vpn.unblock.sites.proxybrowser.activity.SplashScreen: void onResume()> <com.free.vpn.unblock.sites.proxybrowser.m.p: void <init>(com.free.vpn.unblock.sites.proxybrowser.m.o,java.net.InetAddress,int)>
<com.free.vpn.unblock.sites.proxybrowser.activity.ax: void onPostExecute(java.lang.Object)> specialinvoke r321.<com.free.vpn.unblock.sites.proxybrowser.m.p: void <init>(com.free.vpn.unblock.sites.proxybrowser.m.o,java.net.InetAddress,int)>(r0, $r7, 8080) r0 := @this: com.free.vpn.unblock.sites.proxybrowser.m.pvirtualinvoke $r10.<java.net.ServerSocket: void bind(java.net.SocketAddress)>(r321) r2 := @parameter1: java.net.InetAddress
$r2 = staticinvoke <java.net.InetAddress: java.net.InetAddress getLocalHost()>() r0.<com.free.vpn.unblock.sites.proxybrowser.m.o: java.net.InetAddress a> = $r2 r321 = new com.free.vpn.unblock.sites.proxybrowser.m.p $r7 = r0.<com.free.vpn.unblock.sites.proxybrowser.m.o: java.net.InetAddress a> i0 := @parameter2: int
virtualinvoke $r1.<com.free.vpn.unblock.sites.proxybrowser.activity.aw: android.os.AsyncTask execute(java.lang.Object[])>($r2) virtualinvoke $r4.<com.free.vpn.unblock.sites.proxybrowser.m.o: void run()>()
virtualinvoke $r3.<com.free.vpn.unblock.sites.proxybrowser.activity.SplashScreen: void c()>() specialinvoke r0.<java.net.InetSocketAddress: void <init>(java.net.InetAddress,int)>(r2, i0)
virtualinvoke $r11.<com.free.vpn.unblock.sites.proxybrowser.activity.ax: android.os.AsyncTask execute(java.lang.Object[])>($r12)virtualinvoke r0.<com.free.vpn.unblock.sites.proxybrowser.activity.SplashScreen: void c()>() Figure3.5:ABSGautomaticallygeneratedbyBackDroid,wherethegreenblockissinkAPIcallandgrayblocksareentrypoints.
Tainting across fields, arrays, and inner methods.With the BSG structure de-fined, our next challenge is to perform precise and efficient backward taint analysis for the BSG generation. Compared to the forward taint analysis in Amandroid and FlowDroid, our taint analysis is more difficult because it reverses normal program execution and thus has no insights into the earlier execution of tainted variables. In particular, we have the following special taint process for fields, arrays, and inner methods. First, for an instance field to be tainted, we add not only the instance field itself (i.e., obj.field) to the taint set but also its class object (i.e., obj) so that we can trace the same field no matter the class object gets aliased or across method boundaries. Moreover, when the instance field needs to be untainted, we first remove obj.field from the taint set and further detect whether there are more fields for the same instance. If there are no other such fields, then we remove objfrom the taint set as well. Arrays are handled in a similar way.
One more special tainting is to handle inner methods when there are static fields in the taint set. In this scenario, a normal processing is to jump into all inner methods (even when their parameters are not tainted) and analyze them, because we cannot determine whether an inner method uses a tainted static field or not. Analyzing all inner methods on the backtracking paths certainly slows down the analysis, and we have proposed a more elegant solution. Specifically, whenever a new static field is tainted, we launch bytecode search of this field signature to capture all methods that invoke this particular static field. Hence, we only need to analyze the inner methods that are matched with search results.
Adding static initializers into BSG on demand. Analyzing static fields in a whole-app analysis fashion is expensive, because static initializers of all invoked classes (i.e., not only those app component classes) and all statements contained in those initializers need to be analyzed. As a result, Amandroid by default does not analyze static initializers via the configuration “static init = false”, and FlowDroid also provides the option “–nostatic” for its users to reduce the running time for large
apps3.
Since BackDroid performs targeted analysis via bytecode search, we can fully track all tainted static fields. Specifically, after the main taint process is done, if there are still unresolved static fields in the BSG’s taint map, we retrieve their cor-responding classes and obtain the <clinit> methods (which are only implic-itly executed by the Java/Android virtual machine (VM) when the corresponding classes are loaded to the VM). We then perform backward taint analysis of these
<clinit>methods, and add only relevant statements into a special track of BSG.
During the forward analysis, we first analyze this special track and then handle the main track of BSG.