Method with argument of type array of array cannot be instrumented
Hello, I run into a problem while trying to instrument methods that take an array of array of byte as argument. For exemple:
package com.example.testclassloader;
public class TestA {
public static int array_of_array(byte[][] arrays) {
int size = 0;
for (byte[] arr: arrays) {
size += arr.length;
}
return size;
}
}
[Android Emulator 5554::TestClassLoader ]-> Java.performNow(() => { })
[Android Emulator 5554::TestClassLoader ]-> TestA = Java.use("com.example.testclassloader.TestA")
"<class: com.example.testclassloader.TestA>"
[Android Emulator 5554::TestClassLoader ]-> method = TestA.array_of_array
function
[Android Emulator 5554::TestClassLoader ]-> method.argumentTypes
[
{
"className": "[[B",
"defaultValue": "0x0",
"name": "[[B",
"size": 1,
"type": "pointer"
}
]
[Android Emulator 5554::TestClassLoader ]-> method.overload('[[B').implementation = function(arrays) { s =
method(arrays); console.log(s); return s; };
function
# after triggering the method in the app:
[Android Emulator 5554::TestClassLoader ]-> Process crashed: java.lang.ClassNotFoundException: Didn't find class "[L[B;" on path: DexPathList[[dex file "/data/data/com.example.testclassloader/code_cache/.overlay/base.apk/classes3.dex", zip file "/data/app/~~NRqmDlxjA4t3ccEvxe4Qlw==/com.example.testclassloader-JhUO40ypsrxE2AIa8f1k4A==/base.apk"],nativeLibraryDirectories=[/data/app/~~NRqmDlxjA4t3ccEvxe4Qlw==/com.example.testclassloader-JhUO40ypsrxE2AIa8f1k4A==/lib/x86_64, /system/lib64, /system_ext/lib64]]
I believe the issue comes from here: https://github.com/frida/frida-java-bridge/blob/1e23abb71fd26726d59627e4da3ad8e10ba849aa/lib/types.js#L480
I think something like this could be a rough solution, but I did not manage to get frida to use patched version of frida-java-bridge:
diff --git a/lib/types.js b/lib/types.js
index 6a0f977..9b8d91f 100644
--- a/lib/types.js
+++ b/lib/types.js
@@ -477,7 +477,13 @@ function getArrayType (typeName, unbox, factory) {
}
// The type name we get is not always the correct representation of the type so we make it so here.
- const internalTypeName = '[L' + elementTypeName.replace(/\./g, '/') + ';';
+ let internalElementTypeName = '';
+ if (elementTypeName.replace[0] === '[') {
+ internalElementTypeName = elementTypeName.replace(/\./g, '/');
+ } else {
+ internalElementTypeName = 'L' + elementTypeName.replace(/\./g, '/') + ';';
+ }
+ const internalTypeName = '[' + internalElementTypeName;
try {
result.$w = factory.cast(arr, factory.use(internalTypeName), owned);
} catch (e) {
PS: Is there some documentation for running a patched java-bridge? I tried https://github.com/frida/frida-tools?tab=readme-ov-file#loading-your-custom-frida-java-bridge and failled
I fixed the problem that the jni type name was wrong for arrays of type primary. Here's my fix
https://zhuanlan.zhihu.com/p/696631835
function makeBaseJniObjectTypeName(typeName) { if (typeName.length === 1) return typeName let convertType = typeName.replace(/./g, '/') if (convertType[0] !== 'L'){ convertType = 'L' + convertType +';' } return convertType }
function makeJniObjectTypeName(typeName) { let arrayCount = 0; while (typeName[arrayCount] === '[') { arrayCount += 1; } if (typeName.length === arrayCount + 1) { return typeName } if (arrayCount > 0) { const baseType = makeBaseJniObjectTypeName(typeName.slice(arrayCount)); return "[".repeat(arrayCount) + baseType; } return makeBaseJniObjectTypeName(typeName); }
// const internalTypeName = '[L' + elementTypeName.replace(/\./g, '/') + ';';
const internalTypeName = '[' + makeJniObjectTypeName(elementTypeName);