Search code examples
javaandroidandroid-instrumentationsoot

How to create and add a Java class in an APK using Soot?


I want to instrument an APK to count the number of executions of its callback methods (similar to this SO post).

To do so, I want to create a static class from scratch (similar to this link) which keeps the counting numbers. Then add this class to the APK, and finally instrument the beginning of callback methods to call a method of this static class (similar to this link).

I was able to do a similar thing with a Java application but I couldn't do it for an APK. Here is the part of the code that generates a new SootClass and adds it to Scene:

SootClass staticCls = generateClass("StaticCounter");
Scene.v().addClass(staticCls);
Scene.v().addBasicClass("StaticCounter", SootClass.SIGNATURES);
Scene.v().loadNecessaryClasses();

generateClass is adapted from here. But when I examined the modified APK, there was no sign of StaticCounter class. Moreover, I installed and ran the modified APK and got this error:

08-21 14:15:45.936 19917 19917 E AndroidRuntime:
 Caused by: java.lang.ClassNotFoundException:
  Didn't find class "StaticCounter" on path:
   DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/APKNAME-RdhHiJzxKyyUHh_KCi6RUA==/base.apk"],nativeLibraryDirectories=[/data/app/APKNAME-RdhHiJzxKyyUHh_KCi6RUA==/lib/x86, /system/lib]]

Which simply shows the generated class is not inside the APK.

Any solution to this problem?


Solution

  • I guess I found why the newly generated class was unknown to the app thanks to Martin Zitler's hint. The generated class must be in the package of the APK. Soot handles the package of a class by looking at the signatures of the class. As a result, the StaticCounter class must have a signature like

    com.example.app.StaticCounter
    

    which indicates that StaticCounter is in the package com.example.app.

    It is possible to find the package name using ProcessManifest class which can be found in FlowDroid:

    new ProcessManifest(apkPath).getPackageName();
    

    I simplified the working code and put it here. It creates a new class from scratch and adds a static integer field and a method that the field is the times that the static method is called, and the method prints this value. Then using a transformation pack, every method in the app will call this static method.