zhkl0228 / unidbg

Allows you to emulate an Android native library, and an experimental iOS emulation
Apache License 2.0
3.64k stars 924 forks source link

JniImpl里调了另一个Jni如何处理?Jni call another jni exception. #432

Open aeskkkey opened 2 years ago

aeskkkey commented 2 years ago

Jni impl calling another jni lead emulate error.

version

0.9.7-SNAPSHOT

example

A very simple app code as follow:

    static {
        System.loadLibrary("jni");
    }

    public static native void jniA(); // native call java()

    public static native void jniB();

    public static void java() {
        jniB();
    }

And the relate unidbg code:

vm.setJni(new AbstractJni() {
    @Override
    public void callStaticVoidMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        if ("com/example/MyApplication->java()V".equals(signature)) {
            vm.resolveClass("com/example/MyApplication").callStaticJniMethod(emulator, "jniB()V");
            return;
        }
        throw new UnsupportedOperationException(signature);
    }
});
vm.resolveClass("com/example/MyApplication").callStaticJniMethod(emulator, "jniA()V");

error stack

call AbstractEmulator.emulate twice.

java.lang.IllegalStateException: running
    at com.github.unidbg.AbstractEmulator.emulate(AbstractEmulator.java:352)
    at com.github.unidbg.thread.Function32.run(Function32.java:39)
    at com.github.unidbg.thread.MainTask.dispatch(MainTask.java:19)
    at com.github.unidbg.thread.UniThreadDispatcher.run(UniThreadDispatcher.java:172)
    at com.github.unidbg.thread.UniThreadDispatcher.runMainForResult(UniThreadDispatcher.java:96)
    at com.github.unidbg.AbstractEmulator.runMainForResult(AbstractEmulator.java:340)
    at com.github.unidbg.arm.AbstractARMEmulator.eFunc(AbstractARMEmulator.java:229)
    at com.github.unidbg.Module.emulateFunction(Module.java:163)
    at com.github.unidbg.linux.android.dvm.DvmObject.callJniMethod(DvmObject.java:135)
    at com.github.unidbg.linux.android.dvm.DvmClass.callStaticJniMethod(DvmClass.java:260)
    at TestJni$1.callStaticVoidMethodV(TestJni.java:25)
    at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticVoidMethodV(AbstractJni.java:607)
    at com.github.unidbg.linux.android.dvm.DvmMethod.callStaticVoidMethodV(DvmMethod.java:199)
    at com.github.unidbg.linux.android.dvm.DalvikVM$139.handle(DalvikVM.java:2197)
    at com.github.unidbg.linux.ARM32SyscallHandler.hook(ARM32SyscallHandler.java:132)
    at com.github.unidbg.arm.backend.UnicornBackend$11.hook(UnicornBackend.java:346)
    at unicorn.Unicorn$NewHook.onInterrupt(Unicorn.java:128)
    at unicorn.Unicorn.emu_start(Native Method)
    at com.github.unidbg.arm.backend.UnicornBackend.emu_start(UnicornBackend.java:377)
    at com.github.unidbg.AbstractEmulator.emulate(AbstractEmulator.java:380)
    at com.github.unidbg.thread.Function32.run(Function32.java:39)
    at com.github.unidbg.thread.MainTask.dispatch(MainTask.java:19)
    at com.github.unidbg.thread.UniThreadDispatcher.run(UniThreadDispatcher.java:172)
    at com.github.unidbg.thread.UniThreadDispatcher.runMainForResult(UniThreadDispatcher.java:96)
    at com.github.unidbg.AbstractEmulator.runMainForResult(AbstractEmulator.java:340)
    at com.github.unidbg.arm.AbstractARMEmulator.eFunc(AbstractARMEmulator.java:229)
    at com.github.unidbg.Module.emulateFunction(Module.java:163)
    at com.github.unidbg.linux.android.dvm.DvmObject.callJniMethod(DvmObject.java:135)
    at com.github.unidbg.linux.android.dvm.DvmClass.callStaticJniMethod(DvmClass.java:260)
    at TestJni.main(TestJni.java:31)

This will also lead to a ConcurrentModificationException of ArrayList.

[main]I/TEST: jni_0
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
    at java.util.ArrayList$Itr.remove(ArrayList.java:873)
    at com.github.unidbg.thread.UniThreadDispatcher.run(UniThreadDispatcher.java:179)
    at com.github.unidbg.thread.UniThreadDispatcher.runMainForResult(UniThreadDispatcher.java:96)
    at com.github.unidbg.AbstractEmulator.runMainForResult(AbstractEmulator.java:340)
    at com.github.unidbg.arm.AbstractARMEmulator.eFunc(AbstractARMEmulator.java:229)
    at com.github.unidbg.Module.emulateFunction(Module.java:163)
    at com.github.unidbg.linux.android.dvm.DvmObject.callJniMethod(DvmObject.java:135)
    at com.github.unidbg.linux.android.dvm.DvmClass.callStaticJniMethod(DvmClass.java:260)
    at TestJni.main(TestJni.java:31)

reason

AbstractEmulator.emulate is syncing by running.

public final Number emulate(long begin, long until) throws PopContextException {
  if (running) {
    backend.emu_stop();
    throw new IllegalStateException("running");
  }
}

UniThreadDispatcher handle multi-thread tasks one by one within a list, but not solve the task-in-task case. Then the emulate running sync conflic.

questions

Suggestion for jni call jni case?

Support or solve this in the future?

Pr0214 commented 2 years ago

Unidbg 不支持嵌套的这种call

prime89 commented 2 years ago

Unidbg 不支持嵌套的这种call

@Pr0214 大佬,有办法支持吗,能给个思路不?

fxh615 commented 6 months ago

@zhkl0228 貌似相同的问题,求更新

fxh615 commented 6 months ago

日志显示看上去是ArrayList 多线程不安全导致这个问题的。

2724635499 commented 6 months ago

应该不是多线程的问题,单纯的一个进程循环执行了多次。导致。

zhkl0228 commented 6 months ago

参考 https://github.com/zhkl0228/unidbg/commit/3c73988f5ea7378531a43bfe15f1462f860e945a

fxh615 commented 6 months ago

@zhkl0228 万分感谢回复,测试了一下,有一点不是很明白 32位中我看了下,看您的代码 i1 参数是不是丢失了? image

zhkl0228 commented 6 months ago

这种方式不支持修复堆栈中的参数,好像也不需要修复栈中的参数,所以值是正确的。如果对于CallXXXA以及CallXXXV的可能情况不一样。64位的参数支持到X7,所以一般的情形也够用。看图中setR4是错误的,setR3应该也是多余的,具体情况具体分析