版权归作者所有,如有转发,请注明文章出处:cyrus-studio.github.io/blog/
env.js
常用的 JNI 函数在 frida 的 env.js 中都已经定义好了
通过下面代码获取 JNIEnv 引用,就可以调用相关的 JNI 函数
bash
let env = Java.vm.tryGetEnv()
获取数组长度
ini
let arrLen = env.getArrayLength(objArray)
console.log('array length is: ' + arrLen);
元素类型判断
通过 getObjectClassName 可以获取到对象的类名进而判断该元素的类型。
ini
// 获取对象的类名
let className = env.getObjectClassName(objArray)
console.log('className: ' + className);
// 判断是否 jobjectArray
if (className === '[Ljava.lang.Object;') {
}
获取数组元素
ini
let element = env.getObjectArrayElement(objArray, i)
Int 元素读取
javascript
let intElement = Java.cast(env.getObjectArrayElement(objArray, i), Java.use('java.lang.Integer'))
console.log(`element ${i} value: ${intElement}`);
Long 元素读取
javascript
let longElement = Java.cast(env.getObjectArrayElement(objArray, i), Java.use('java.lang.Long'))
console.log(`element ${i} value: ${longElement}`);
Float 元素读取
javascript
let floatElement = Java.cast(env.getObjectArrayElement(objArray, i), Java.use('java.lang.Float'))
console.log(`element ${i} value: ${floatElement}`);
Double 元素读取
javascript
let doubleElement = Java.cast(env.getObjectArrayElement(objArray, i), Java.use('java.lang.Double'))
console.log(`element ${i} value: ${doubleElement}`);
字符串 元素读取
通过 env.js 中定义的 stringFromJni 函数可以直接获取到字符串对象的值
javascript
let stringElement = env.stringFromJni(env.getObjectArrayElement(objArray, i))
console.log(`element ${i} value: ${stringElement}`);
Object 元素读取
javascript
let element = env.getObjectArrayElement(objArray, i)
let elementClassName = env.getObjectClassName(element)
// 元素类型转换
let castElement = Java.cast(element, Java.use(elementClassName))
console.log(`element ${i} value: ${castElement}`);
打印 jobjectArray
打印 jobjectArray 的元素类型和值
javascript
function printObjectArray(objArray) {
if (objArray.isNull()) {
console.log('Object array is null');
return null;
}
// 获取 JNIEnv
let env = Java.vm.tryGetEnv();
let className = env.getObjectClassName(objArray);
// 不是 jobjectArray,则直接打印类型
if (!className.startsWith('[L')) {
console.log(`Argument is not a jobjectArray, actual type: ${className}`);
return;
}
let arrLen = env.getArrayLength(objArray);
let result = `Object array of type ${className}, length: ${arrLen}\n`;
for (let i = 0; i < arrLen; i++) {
let element = env.getObjectArrayElement(objArray, i);
let elementClassName = env.getObjectClassName(element);
let castElement = Java.cast(element, Java.use(elementClassName));
result += ` [${i}] ${elementClassName}: ${castElement}\n`;
}
console.log(result.trim());
}
hook native 函数并打印 jobjectArray 传参
javascript
function hook_native_func(targetAddress) {
// Hook 目标地址
Interceptor.attach(targetAddress, {
onEnter: function (args) {
console.log('Entering native function at: ' + targetAddress);
printObjectArray(args[2])
},
onLeave: function (retval) {
console.log('Leaving native function');
}
});
}
setImmediate(function () {
Java.perform(function () {
var baseAddress = Module.findBaseAddress("libnative-lib.so");
hook_native_func(baseAddress.add(0x26058))
});
})
输出如下:
vbnet
Entering native function at: 0x77fe13c058
Object array of type [Ljava.lang.Object;, length: 3
[0] java.lang.Integer: 283
[1] com.cyrus.example.jniexample.JNIExampleActivity: com.cyrus.example.jniexample.JNIExampleActivity@b8df529
[2] java.lang.String: HelloWorld
Leaving native function