Frida读取文件很慢

逆向工程 安卓 爪哇 函数挂钩 弗里达
2021-06-12 11:44:26

我需要将大约 2 MB 的文件读入字节数组。

var fis = Java.use("java.io.FileInputStream");
var file = fis.$new("/data/local/file.txt");
var fileBytes = new Uint8Array(file.available());
var x;
while ((x = file.read()) != -1)
    fileBytes.push(x);

我正在使用上面的代码,但它正在读取 ~100 kb/s,在我的情况下需要 ~20 秒。

我还尝试使用 ByteArrayOutputStream 和 1、4、16kb 缓冲区,但结果没有任何不同。

我相信采用 Inputfilestream 并返回 bytearray 的本机 Java 函数将解决我的问题,但我找不到任何问题。

我怎样才能使这个过程更快?

我实际上试图将它与okio.ByteString具有.read()方法的一起使用,但我无法从 Frida 访问它。它是未定义的。

2个回答

你的代码慢的原因不是 Frida 而是你的代码。在纯 J2SE Java 中执行时,您的代码也会很慢。

原因很简单,因为您正在使用无缓冲FileInputStream的方式逐字节读取文件,这是读取文件的最糟糕方式。通常 IO 操作处理至少 4096 字节的块(文件系统中的典型块站点)。

因此,一个简单的修改是将 包装FileInputStream在一个BufferedInputStream

var fis = Java.use("java.io.FileInputStream");
var bis = Java.use("java.io.BufferedInputStream");
var file = bis.$new(fis.$new("/data/local/file.txt"));
...

然而,这不是read需要大量时间调用。因此,以下代码读取字节块并对其进行处理。这应该快得多:

var fis = Java.use("java.io.FileInputStream");
var file = fis.$new("/data/local/file.txt");
var fileBytes = new Uint8Array(file.available());
const buffer = Java.array('byte', new Array(4096).fill(0));
var x;
while ((x = file.read(buffer)) != -1) {
    for (int i = 0; i < x; i++) {
        fileBytes.push(buffer[i]);
    } 
}

禁食的方法是,如果您的应用程序包含直接将文件读取到字节数组的 Java 代码。您需要执行的 Frida JavaScript 调用越少,结果就越快。

因此,请检查您的应用程序是否包含像 Apache 通用 IO 这样的库。然后就可以直接执行了org.apache.commons.io.IOUtils.toByteArray(java.io.InputStream)

不幸的是,使用缓冲区仍然没有帮助我。

我猜做 JS -> Java -> JS -> Java 需要一些时间。我找到了这个解决方案:

var Files = Java.use("java.nio.file.Files");
var Paths = Java.use("java.nio.file.Paths");
var URI = Java.use("java.net.URI");

var fileBytes = Files.readAllBytes(Paths.get(URI.create("file:///sdcard/file.jpg")));

它使用 Java 进行读取并返回一个非常快的字节数组。