The Startup
Published in

The Startup

Instrumenting Android Apps With Soot

In this blog post, I describe how to use Soot to read an Android APK (without the source code), change its methods and classes(even add a new class), and write the new code into a working APK. A few notes:

  • You can find the code in the SootTutorial repository.
  • This repository has a CLI to instrument APKs more conveniently.
  • For better understanding this post, I recommend to first take a look at the previous post “Know the basic tools in Soot” to be familiar with the Soot’s APIs that I used in the code.
  • This post is mostly adapted from this page in the Soot’s official wiki.


One way to analyze Android apps is by running them on a device (or an emulator) and observe the logs to capture some desired information. If you have the app’s source code, you can log whatever you want, e.g., record the execution of a method at its beginning. However, in the cases that the source code is not available, such as in security analysis where you are dealing with possible malicious apps, you need to instrument the APK, which is compiled in Dalvik byte code. And as you may have guessed, Soot is going to save the day.

The following figure shows an overview of how Soot reads/modifies/writes an APK. First, Soot uses Dexpler to convert the Dalvik byte code to Jimple bodies. Then it runs Whole Packs that can transform, optimize, and annotate the whole program (for example, call graph generation). Next, the Jimple Transformation Packs will run on each Jimple body (this is the part that we modify the code). Finally, Soot converts all Jimple bodies to Baf (a low-level intermediate representation in Soot), and using Dexpler the whole code will be compiled into an APK. The instrumented APK can be installed on an Android device (you just need to sign it first). Now, let’s instrument some apps!

An overview of instrumenting an Android APK by Soot (the circles are Soot packs, more info here)

Android Logger

We are going to add a simple statement(System.out.println("Beginning of method: " + METHOD_NAME)) at the beginning of each APK method using a BodyTransfomer. Before reading further, please clone the SootTutorial repository and have in front of you.


In order to analyze an Android APK with Soot, you need to install the Android SDK in your machine. You can either use the SootTutorial docker image (docker run -it noidsirius/soot_tutorial:lates) or follow this link.

Soot needs a special configuration for analyzing Android apps. The following code shows the options that I used for the instrumentation. Each option accompanies with a comment that describes it.

Soot Initialization

The last part of the setup code is not setting an option but resolving the required classes for the instrumentation. Recall that we want to add a new statement at the beginning of each APK method, which its Jimple representation is:

$r1 = <java.lang.System: out>
virtualinvoke $r1.< void println(java.lang.String)>("<SOOT_TUTORIAL> Beginning of method METHOD_NAME")

Since these statements require classes java.lang.System and, we should resolve them in Soot, which is done in lines 20–21 in setupSoot.

Body Transformation

Now, we’re ready to write a BodyTransformer to modify the code. The following code shows myLogger BodyTransformer. Note that the transformer is added to the jtp pack and it will be applied to all methods’ bodies.

First of all, we need to filter out non-APK methods (lines 5–6), because Soot loads these methods and may not be aware that they belong to Android libraries (checkisAndroidMethod). Then, we can create the content that we want to log (line 11, the method’s signature is body.getMethod().getSignature()). We add a tag to the content so we can retrieve these logs later. Recall that Jimple statements are three-address code; so, in order to invoke System.out.println we need to first create a local variable, psLocals and $r1in the Jimple code, that points to System.out (lines 13–16), then invoke the println method using that local variable (lines 19–21).

For adding a local variable we input the body and the type of the local variable to a LocalGenerator (can be found here). To create a Jimple statement, we use the singleton Jimple.v() . For example, line 16 creates an AssignStmt equivalent to $r1 = <java.lang.System: out> (note that you need to pass the reference of a SootField or SootMethod). Similarly, line 21 creates an InvokeStmt that has a virtual invoke expression equivalent to virtualinvoke $r1.< void println(java.lang.String)>("<SOOT_TUTORIAL> Beginning of method METHOD_NAME") . Note that the parameter of this invocation must be a Value; therefore, we use StringConstant to create a String constantValue equal to the content.

So far, we have created two Jimple statements (lines 16 and 21). Note that, the IdentitiyStmts of Jimple bodies (that determines the parameters and this pointer) must appear at the beginning; therefore, we need to find the first non-identity statements and insert our code before it (look at lines 17, 22, and 24). Finally, we have to validate the new modified body to make sure no problems exist (at least statically). The final step is to just run the packs (PackManager.v().runPacks()) and write the output into an APK (PackManager.v().writeOutput())

Sign and Run!

That’s it! You add a Java statement at the beginning of all APK methods under 20 lines of code in Soot (actually it should be less than 10 if I didn’t expand all statements to write comments :) ). However, there is one more step before you can install the instrumented APK: you need to sign it. You can use the bash script that basically first run zipalign (that aligns the APK) and then run apksigner using a keyset.

In summary, run AndroidLogger , either in Intellij or CLI by running ./gradlew run --args="AndroidLogger" . It should create demo/Android/Instrumented/calc.apk and you can sign and install it by running the following commands (don’t forget to connect your device to your machine or run an Android emulator):

cd ./demo/Android
./ Instrumented/calc.apk key "android"
adb install -r -t Instrumented/calc.apk

To see the logs, run adb logcat | grep -e "<SOOT_TUTORIAL>" and then use your device and open Numix Calculator. You should see something like this on your terminal:

07-07 11:41:26.570 32487 32487 I System.out: <SOOT_TUTORIAL> Beginning of method <com.numix.calculator.view.CalculatorDisplay: void onSizeChanged(int,int,int,int)>
07-07 11:41:26.571 32487 32487 I System.out: <SOOT_TUTORIAL> Beginning of method <com.numix.calculator.view.ScrollableDisplay: void onLayout(boolean,int,int,int,int)>
07-07 11:41:26.571 32487 32487 I System.out: <SOOT_TUTORIAL> Beginning of method <com.numix.calculator.view.ScrollableDisplay: com.numix.calculator.view.AdvancedDisplay getView()>
07-07 11:41:26.589 32487 32487 I System.out: <SOOT_TUTORIAL> Beginning of method <com.numix.calculator.view.ScrollableDisplay: void scrollTo(int,int)>

If you’re interested in some specific methods you can filter it by piping grep -e "METHOD_SIGNATURE" to adb logcat

Android Class Injector

Let’s do some more existing things. Assume in the previous example, instead of just logging the name of the method, we wanted to keep track of the number of methods that have been called so far (or simply count the executed method). One way to do this is to have a static integer field and increase it by one when a method is executed. Now, I show how to create a new class, field, and method from scratch, add them to the APK, and more importantly, use them in other methods. The whole code can be found in and and the following code shows creating a class:

The new class must be in the same package of APK in order that other methods could access it (line 3). Also, it should be public (Modifier at line 4), a subclass of Object (line 5), and a Soot Application class (line 6). At the end of createCounterClass the generated class has been created and added to the Scene. Now let’s create a static integer field for this class:

As can be seen, it’s so simple: just instantiate a SootField, provide its name, type, and its modifiers (note that the modifiers are aggregated by or, | binary operator). Then we add this field to the class. Now, we are going to create a method that increments this field and prints it:

It’s a little bit more complex than creating the field. For instantiating a SootMethod you need to pass name, parameters’ types, return type, and modifier (lines 3–5). In addition to that, a method needs to have a body (line 7) that represents the functionality of the method. First, we increment the counter field by assigning its value to a temporary local variable (recall Jimple has three-addressed statements), add the local by one, and reassign the field to the incremented number (lines 11–15). Next, we log this number similarly to AndroidLogger; however, since we have two things to print (the string "Counter's value" and the local counterLocal ) we need to contact them using StringBuilder (for more info look at the code in The final statement must be a return statement (line 21). Next, we validate body and make it the active body of incMethod (lines 23-24).

We’re done! A new class, field, and method have been created and added to the APK. To invoke incrementAndLog method we use a similar approach to AndroidLoggger and you can find the corresponding BodyTransformer here. Once you run, sign the instrumented app, install and open it, you should see something like this in the adb logcat:

07-07 14:33:03.177  3967  3967 I <SOOT_TUTORIAL>: Beginning of method <com.numix.calculator.view.ScrollableDisplay: void onMeasure(int,int)>
07-07 14:33:03.177 3967 3967 I <SOOT_TUTORIAL>: Counter's value: 3935
07-07 14:33:03.177 3967 3967 I <SOOT_TUTORIAL>: Beginning of method <com.numix.calculator.view.ScrollableDisplay: void onMeasure(int,int)>
07-07 14:33:03.177 3967 3967 I <SOOT_TUTORIAL>: Counter's value: 3936
07-07 14:33:03.177 3967 3967 I <SOOT_TUTORIAL>: Beginning of method <com.numix.calculator.view.ScrollableDisplay: void onMeasure(int,int)>
07-07 14:33:03.177 3967 3967 I <SOOT_TUTORIAL>: Counter's value: 3937
07-07 14:33:03.177 3967 3967 I <SOOT_TUTORIAL>: Beginning of method <com.numix.calculator.view.ScrollableDisplay: void onMeasure(int,int)>
07-07 14:33:03.177 3967 3967 I <SOOT_TUTORIAL>: Counter's value: 3938
07-07 14:33:03.177 3967 3967 I <SOOT_TUTORIAL>: Beginning of method <com.numix.calculator.view.ScrollableDisplay: void onMeasure(int,int)>


In this blog post, we reviewed how Soot can reads/modifies/writes an Android APK and get familiar with Soot packs, in particular, Jimple Transformer. Feel free and play with the code, especially, to create more interesting applications. For example, you can log the running thread or count the execution of each method separately.

If you’re interested in this work and you want to use it in a real project, I suggest you take a look at Android Soot Instrumentor repository which is designed for CLI and is more configurable. I created this repository based on my experience in Software Engineering research projects that I was involved and it would be great if you can collaborate to make it more useful.




Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +756K followers.

Recommended from Medium

How to improve your daily work using proxy and mock tools

Jetpack’s Navigation Component (Complete Guide for Beginners)

How to install Android Studio on your Mac and launch Emulator.

Flutter Provider along with Http request

Android Architecture Pattern

Most Common Android Problems  — Android Pitfalls 🐭 🧀

Android: (Part 2) Real work of Coroutines.

Flutter: Custom tab indicator for TabBar

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Navid Salehnamadi

Navid Salehnamadi

I’m a Ph.D. student in Software Engineering at UCI. I like to automate things and play music.

More from Medium

Android — Intercept POST form data inside of WebView

Migrate and test your RoomDatabase pt. 1

Integration of Huawei Push Kit in Book Reading Android app (Kotlin) — Part 3

Basics for your first Android App: REST API, Database, and Fragment Navigation