ReDroid Usage Example
ReDroid is a toolbox for automatically detecting and countering anti-sandbox behaviors in Android apps. You can find the source here. This post gives a usage example of ReDroid by walking through what ReDroid have done for an Android app equipped with anti-sandbox behaviors, anti-emulator
.
Intuition
Apps with anti-sandbox behaviors would behave differently on real and emulated environments. This mechanism enable an app to hide their malicious behavior (for malicious apps) or protect itself from reverse engineering (for commercial apps) in emulators. Take the anti-emulator
app as an example, we can run the app on an emulator and a real device:
Emulator | Real Device | |
---|---|---|
As we can see from the screenshots, the anti-emulator
app contains common anti-sandbox behaviors, including:
- isTaintTrackingDetected: Checking whether there is TaintDroid installed;
- isMonkeyDetected: Checking whether Monkey is running;
- isDebugged: Checking whether the app is being attached by any debugger;
- isQEmuEnvDetected: Checking whether some critical file related with QEMU emulator is present;
- slowGraphicDetected: Checking whether the environment has poor graphic performance, which indicates that the platform might be an emulator.
Among these checking items, only isQEmuEnvDetected and slowGraphicDetected is checked out by anti-emulator
app. ReDroid’s goal is to automatically eliminate the such differences of app behaviors between the two kinds of platforms. In this post, this is to make the emulator undetectable by anti-emulator
.
Default Workflow
ReDroid’s default workflow consists of mainly two phases, detecting and countering phase. In detecting phase, ReDroid collects information about the app automatically by exercising dynamic tests on an app; in countering phase, ReDroid analyzes information collected and forms a plan for countering anti-sandbox techniques detected. In the case of anti-emulator
, we would like to counter isQEmuEnvDetected and slowGraphicDetected checks.
The default workflow of ReDroid can be launched as steps specified on source page. After these steps, we can get multiple folders containing information collected and generated by ReDroid, under the specified output_dir
folder. Let’s walk through them by the order in which they’re generated.
-
configs
Default workflow calls other scripts to do the real job. This folder contains config files generated for those scripts.
-
ReDroid_apps_droidbot_out
This folder contains information collected by DroidBot. Before any further action, ReDroid will first launch DroidBot to run dynamic tests on the specified apps with different platforms (emulator and real device). The test cases are the same between platforms, so after that we can detect runtime behavior differences caused by anti-sandbox techniques.
-
ReDroid_trace_comparator_out
This folder contains results of trace comparison. ReDroid would then analyzes running traces collected in step 2, and find out suspectable divergences in them. Those divergences are highly likely caused by anti-sandbox techniques. To achieve the goal, ReDroid match the app threads by bipartite graph matching, align the traces and scan through the traces. The following is an example divergence found in
anti-emulator
:{ "real_trace": [ "xit .......diff.strazzere.anti.debugger.FindDebugger$tcp.create ([Ljava/lang/String;)Ldiff/strazzere/anti/debugger/FindDebugger$tcp; FindDebugger.java", "xit ......diff.strazzere.anti.debugger.FindDebugger.hasAdbInEmulator ()Z FindDebugger.java" ]: "emu_trace": [ "xit .......diff.strazzere.anti.debugger.FindDebugger$tcp.create ([Ljava/lang/String;)Ldiff/strazzere/anti/debugger/FindDebugger$tcp; FindDebugger.java", "ent .......diff.strazzere.anti.debugger.FindDebugger$tcp.create ([Ljava/lang/String;)Ldiff/strazzere/anti/debugger/FindDebugger$tcp; FindDebugger.java" ] }
This divergence is caused by the network configuration difference between the two platforms. The code in
anti-emulator
reads the contents in/proc/net/tcp
to findout whether there is a tcp connection, and if you look at the screenshots above again, the real device is out of Internet, which causes the difference. Although the difference is not used in anti-sandbox code directly, this is indeed a difference between real device and “sandbox” and the code finds it out. -
ReDroid_dsm/monitor/*
This folder contains results of trace monitoring. After finding out the diverging point of real device/emulator traces, ReDroid marks all the method calls before the diverging point as suspectable method calls. Suspectable methods have return values that might be vital to anti-sandbox techniques. For example,
getDeviceId
is used inanti-emulator
, which will return IMEI on real devices and null string on emulators.ReDroid then monitors the return values of suspectable methods, using JDWP. An example result pair looks like the following:
-
Real Device
{ "thread": 755, "eventKind": 42, "methodLocation": 38, "returnValue": "358239058753973", "signature": "(Ljava/lang/String;)Ljava/lang/String;", "returnType": "string", "classMethodName": "com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId" }
-
Emulator
{ "thread": 737, "eventKind": 42, "methodLocation": 38, "returnValue": 0, "signature": "(Ljava/lang/String;)Ljava/lang/String;", "returnType": "object", "classMethodName": "com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId" }
Given monitoring results like this, ReDroid can give suggestions on countering anti-sandbox techniques.
-
-
ReDroid_dsm/dsm/dsm.json
This file is the DSM rule generated according to results in step 4. DSM (dynamic state modification) is a word borrowed from this paper, which stands for modifying a program’s control flow during runtime. In ReDroid, DSM means changing a method’s return value during runtime, and it’s implemented as a Xposed module.
Given a dsm rule file, ReDroid Xposed module can make emulator undetectable to the anti-sandbox techniques detected. Here is an example (in
getDeviceId
) of the rules:{ "stackTrace": [ "android.telephony.TelephonyManager.getDeviceId", "diff.strazzere.anti.emulator.FindEmulator.hasKnownDeviceId", "diff.strazzere.anti.MainActivity.isQEmuEnvDetected" ], "emuReturnType": "object", "emuReturnValue": 0, "returnValue": "358239058753973", "returnType": "string", "classMethodName": "android.telephony.TelephonyManager.getDeviceId", "paraList": [] }
stackTrace
means the position of this method in calling stack, andparaList
is for distinguishing overloading methods. We can see thatgetDeviceId
returns null string foremuReturnValue
on emulators and IMEI forreturnValue
on real devices.In
anti-emulator
’s example,dsm.json
finally contains the following suspectable methods:[ "android.os.Parcel.readString", "android.telephony.TelephonyManager.getDeviceId", "com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId", "diff.strazzere.anti.emulator.FindEmulator.hasEmulatorAdb", "diff.strazzere.anti.emulator.FindEmulator.hasEmulatorBuild", "diff.strazzere.anti.emulator.FindEmulator.hasQEmuFiles", "diff.strazzere.anti.MainActivity.isQEmuEnvDetected", "java.io.BufferedReader.fillBuf", "java.io.File.exists", "java.io.FileDescriptor.getInt$", "java.io.FileInputStream.read", "java.io.InputStreamReader.read", "java.lang.ThreadLocal.-get0", "libcore.io.BlockGuardOs.read", "libcore.io.IoBridge.read", "libcore.io.Posix.read" ]
Back to the two screenshots at beginning, the
isQEmuEnvDetected
check item is solved byjava.io.File.exists
DSM, foranti-emulator
uses this method to check related files like/system/lib/libc_malloc_debug_qemu.so
. Also the outer functionhasQEmuFiles
are hacked.The
dsm.json
file will be uploaded to the emulator’s/data/system/ReDroid/
path and loaded by ReDroid Xposed module. After that, theanti-emulator
app cannot detect QEMU files in emulators any more:As for the
slowGraphicDetected
check item, it’s not covered in the method set before diverging point. ReDroid are supposed to applied iteratively here to solve the problem.
Conclusion & Future Work
ReDroid can automatically build an undetectable environment from apk files and its different behavior on emulators and real devices. However, there are some obvious drawbacks:
- More accurate DSM generation: Current DSM generation provided by ReDroid is highly heuristic, incomplete and unstable;
- More advanced DSM types: Currently ReDroid only supports hacking return values of primitive types, plus
String
type.
If you like ReDroid, please give it a star :)