如何使用 Soot 在 APK 中创建和添加 Java class?

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

我想检测 APK 以计算其回调方法的执行次数(类似于此 SO post)。

为此,我想从头开始创建静态 class(类似于此 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)。

我可以对 Java 应用程序做类似的事情,但我不能对 APK 做。这是生成新 SootClass 并将其添加到 Scene:

的代码部分
SootClass staticCls = generateClass("StaticCounter");
Scene.v().addClass(staticCls);
Scene.v().addBasicClass("StaticCounter", SootClass.SIGNATURES);
Scene.v().loadNecessaryClasses();

generateClass改编自here。但是当我检查修改后的 APK 时,没有 StaticCounter class 的迹象。此外,我安装并 运行 修改后的 APK 并收到此错误:

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]]

这只是表明生成的 class 不在 APK 中。

这个问题有什么解决办法吗?

您可能需要提供它所需的依赖项:

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

它无法构建的原因可能是,StaticCounter 在编译时是未知的 - 因为它可能 而不是 在应用程序包中被引用, 哪个不知道呢。看看这个 blog post,显然来自 Soot 作者...驱动程序 class 可能是成功的关键:

//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);

这是整个示例:AndroidInstrument.java

除非您将其标记为应用程序 class,否则 Soot 不会发出 class。你能试试吗?

我想我找到了为什么新生成的 class 对应用程序来说是未知的,这要归功于 的提示。生成的 class 必须在 APK 的包中。 Soot 通过查看 class 的签名来处理 class 的包。因此,StaticCounter class 必须具有类似

的签名
com.example.app.StaticCounter

表示StaticCounter在包com.example.app.

可以在FlowDroid中找到ProcessManifest class包名:

new ProcessManifest(apkPath).getPackageName();

我简化了工作代码并把它放在here。它从头开始创建一个新的 class 并添加一个静态整数字段和一个方法,该字段是调用静态方法的次数,该方法打印此值。然后使用一个转换包,应用程序中的每个方法都会调用这个静态方法。