1

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?

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
noidsirius
  • 409
  • 2
  • 12

3 Answers3

1

You might need to provide the dependency it demands:

android {
    useLibrary "org.apache.http.legacy"
}

The reason why it won't build might be, that StaticCounter is unknown at compile time - because it likely should not be referenced from within the application package, which does not know it. Check out this blog post, apparently from the Soot author... the driver class might be key to success:

//prefer Android APK files// -src-prec apk
Options.v().set_src_prec(Options.src_prec_apk);

//output as APK, too//-f J
Options.v().set_output_format(Options.output_format_dex);

// resolve the PrintStream and System soot-classes
Scene.v().addBasicClass("java.io.PrintStream", SootClass.SIGNATURES);
Scene.v().addBasicClass("java.lang.System", SootClass.SIGNATURES);

here's the whole example: AndroidInstrument.java

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • Thanks. But I've already followed the steps from the blog post. It works fine when there is no extra class: after running the app, it will print a log whenever I perform one of the callbacks. However, I'm interested to add a new class (`StaticCounter`) to the package. I think there should be a way to change the configurations of APK itself to let the newly introduced class will be visible for all the methods. – noidsirius Aug 22 '19 at 17:13
  • @noidsirius you could possibly add it into the test-application by adding it into the `androidTest` source-set, or use a `TestSuite` and add it into there... `Soot` seems rather specialized for desktop Java, which is a whole other animal - and therefore there might be certain limitations. – Martin Zeitler Aug 22 '19 at 18:21
0

Soot will not emit the class unless you have flagged it as application class. Can you try that?

Eric
  • 1,343
  • 1
  • 11
  • 19
0

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.

noidsirius
  • 409
  • 2
  • 12