Slow update of Unidbg documents (2)
CallMethod
Execute JNI function
- Create a VM object, which is equivalent to the instance object of the class that calls the native function in the Java layer
DvmObject<?> obj = ProxyDvmObject.createObject(vm, this);
Note: Unidbg will match the JNI method according to the package name of the second parameter class, so the package name of the class to which this object belongs here should match the target function
- Use this object to call the JNI method
boolean result = obj.callJniMethodBoolean(emulator, "jnitest(Ljava/lang/String;)Z", str);
The second parameter is the signature of the method, and the corresponding function is found to execute according to the second parameter. Assuming that the package name of the class to which this object belongs at this time is: com.kanxue.test2, then it will be called at this time:
jboolean Java_com_kanxue_test2_jnitest(JNIEnv *env, jobject thiz, jstring str);
execute any function
When we want to execute any function in SO, we can also call it by address
//获取JNIEnv *
Pointer jniEnv = vm.getJNIEnv();
//创建jobject对象
DvmObject<?> thiz = vm.resolveClass("com.kanxue.test2").newObject(null);
//准备入参
List<Object> args = new ArrayList<>();
args.add(jniEnv);
args.add(vm.addLocalObject(thiz));
args.add(vm.addLocalObject(new StringObject(vm,"XuE")));
//根据地址调用
Number[] numbers = module.callFunction(emulator, 0x9180 + 1, args.toArray());
System.out.println(numbers[0].intValue());
When the input parameters are non-pointer and Number types, you need to add the objects to the VM before you can use these objects in the VM. When the
return value is an object, the Number at this time is the hash value of the object in the VM, which needs to be passed vm.getObject() takes the object out for use, for example:
DvmObject<?> object = vm.getObject(numbers[0].intValue());
String result = (String) object.getValue();
Execute the function whose return value is passed by the parameter pointer
like:
void md5(const uint8_t *initial_msg, size_t initial_len, uint8_t *digest);
Let's take a look at how we can actively execute this function
String initial = "unidbg";
int initial_length = initial.length();
//开辟一块的空间来存放第一个参数
MemoryBlock initial_msg = emulator.getMemory().malloc(initial_length+1, false);
UnidbgPointer initial_msg_ptr=initial_msg.getPointer();
//将参数1写入
initial_msg_ptr.write(initial.getBytes());
//开辟一块16字节的空间来存放第三个参数
MemoryBlock digest = emulator.getMemory().malloc(16, false);
UnidbgPointer digest_ptr=digest.getPointer();
//准备参数
List<Object> args = new ArrayList<>();
args.add(initial_msg);
args.add(initial_length);
args.add(digest_ptr);
//执行
module.callFunction(emulator, 0x7A8D + 1, args.toArray());
//打印结果
Inspector.inspect(digest_ptr.getByteArray(0, 0x10), "digest");
Hook
HookZz
HookZz is the predecessor of Dobby, it is recommended to use HookZz in 32-bit mode
wrap
HookZz hook = HookZz.getInstance(emulator);
hook.wrap(module.base + 0xC09D, new WrapCallback<RegisterContext>() {
@Override
public void preCall(Emulator<?> emulator, RegisterContext ctx, HookEntryInfo info) {
Pointer input = ctx.getPointerArg(0);
System.out.println(input.getString(0));
}
@Override
public void postCall(Emulator<?> emulator, RegisterContext ctx, HookEntryInfo info) {
Pointer result = ctx.getPointerArg(0);
System.out.println(result.getString(0));
}
});
replace
HookZz hook = HookZz.getInstance(emulator);
hook.replace(module.base + 0x1C61, new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
emulator.getBackend().reg_write(Unicorn.UC_ARM_REG_R0,1);
return HookStatus.RET(emulator,context.getLR());
}
@Override
public void postCall(Emulator<?> emulator, HookContext context) {
System.out.println("postCall!");
super.postCall(emulator, context);
}
},true);
instrument
HookZz hook = HookZz.getInstance(emulator);
hook.instrument(module.base + 0x1C61, new InstrumentCallback<RegisterContext>() {
@Override
public void dbiCall(Emulator<?> emulator, RegisterContext ctx, HookEntryInfo info) {
System.out.println(ctx.getIntArg(0));
}
});
Dobby
Dobby is recommended for 64-bit mode
replace
Dobby dobby = Dobby.getInstance(emulator);
dobby.replace(module.base+0xAC90, new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
Pointer result = context.getPointerArg(0);
System.out.println("input:" + result.getString(0));
return super.onCall(emulator, context, originFunction);
}
@Override
public void postCall(Emulator<?> emulator, HookContext context) {
super.postCall(emulator, context);
}
},true);
wrap
not support
xHook
The implementation principle of the xHook framework itself has limitations, and it can only hook symbol table functions, so here is just a way of thinking, you can learn about the implementation of this hook
IxHook hook = XHookImpl.getInstance(emulator);
hook.register("libutility.so", "free", new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("free called!");
return HookStatus.RET(emulator,context.getLR());
}
});
//使hook生效
hook.refresh();