Undocumented Channels

Please refer to the NDSS paper for more details of both the documented and undocumented access channels, i.e., system properties, system settings, and system services, and how the local and remote context jointly serves the API invocation.

This webpage demonstrates a case study of our static analysis of AOSP 10 OS image for the purpose of undocumented access channel exploration.

Our exploration of undocumented access channels are based on the known APIs of UUI access. Given the 6 UUIs, we sort the corresponding APIs according to the Android developer community website. Those APIs will be treated as the entry points of our following static analysis. We also remark that it is conventional that Android OS serves the API invocation via (system) services mechanism. Therefore we also retrieve the names of system services that are in charge of serving the API invocation at the remote side. The list of APIs is shown below:

# UUI Developers API Name(s) System Service(s) Involved
1 Serial android.os.Build.getSerial() device_identifiers
2 Device ID/IMEI/MEID android.telephony.TelephonyManager.getImei() phone
3 Device ID/IMEI/MEID android.telephony.TelephonyManager.getDeviceId() phone
4 Device ID/IMEI/MEID android.telephony.TelephonyManager.getMeid() phone
5 ICCID android.telephony.TelephonyManager.getSimSerialNumber() phone
6 ICCID android.telephony.SubscriptionInfo.getIccId() isub
7 IMSI android.telephony.TelephonyManager.getSubscriberId() phone
8 Bluetooth MAC android.bluetooth.BluetoothAdapter.getAddress() bluetooth_manager
9 WiFi MAC android.net.wifi.WifiInfo.getMacAddress() wifi

Our static analysis

We use Soot (ver 2.5.0) to construct the call graph of API invocation in both the local and remote contexts. Considering the construction of call graph is a very complicated process that covers a hugh code repository (of AOSP) and takes a long time to execute, we prepare a sample toy project that only contains simplified classes that appears in the call traces of specific API invocation.

Next, we take the getImei() and getSerial() as examples and demonstrate how the static analysis facilitates our exploration of potential undocumented access channels. The sample project is exported to 3 runnable JAR files, which extract the call graph of the local context of getImei() [link to download], the remote context of getImei() [link to download], and the remote context of getSerial() [link to download], respectively.

Alternatively, you can also download the source code of our sample project [Zip file]. If you are using eclipse IDE, you need to relink all dependable libraries provided in the zip file and then you should be able to run the project easily, like the snapshot below shows.

A snapshot of our static analysis sample project

The attached JAR files have all dependable library included and therefore are theoritically runnable on any OS with JRE installed. A successful execution of them generates a "dot" file in the same directory, which can be viewed by GraphViz or any alternative software.

Call graph in the local context

We first write a simple Java script (named EntryPoint.java) to invoke the getImei() APIs of the TelephonyManager class. Then we use Soot to take our Java script as the entry point (the object of analysis), analysis the call trace and generate a call graph in dot file format.

The image attached below is the simplified call graph generated by our project, showing how the Android OS handles the TelephonyManager.getImei() in the local context (from API class to the proxy of a system service stub). To control the size of call graph, we remove the unnecessary components within the API functions and initialization of Java objects (e.g., “java.lang.Object: void<clinit>()”) from the generated dot file. The graph is presented by GVEdit of [GraphViz].

The (simplified) call graph of getImei() in the local context (Click [simplified version or complete version] to view the original image in full size)

Call graph in the remote context

Next, we take the getImei() defined in the stub class as the entry point and continue constructing the call graph in the remote context. We eventually find the getImei() is overrode in a class named “PhoneInterfaceManager”. Although the call graph does not further trace where the IMEI data is retrieved, we can still search the AOSP code repository and find the getImei() function is finally implemented in a class called “GsmCdmaPhone”. The simplified call graph in the remote context is show below.

The (simplified) call graph of getImei() in the remote context (Click [simplified version or complete version] to view the original image in full size)

Through this case we find the IMEI is eventually served by a class in the remote context through a system service called ``phone’’, and therefore, we identify the system service as one of undocumented access channel based on an assumption that, we may find other UUIs through exhaustively calling the public interfaces defined in those active system services.

Next, we use another case, i.e., Build.getSerial(), to briefly demonstrate how another undocumented channel, system properties, is identifed.

Another example (Build.getSerial())

We omit the handling of API at the local side and only present how the system service (device_identifiers) serve the UUI access. Our observation shows that the call graph ends in a class named SystemProperties and then the OS passes the remaining invocation to its native context. We regard the SystemProperties class is used to handle the access of system properties of Android OS, therefore, we add the system properties as another undocumented access channel.

The (simplified) call graph of getSerial() in the remote context (Click [simplified version or complete version] to view the original image in full size)