All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.unidbg.hook.HookLoader Maven / Gradle / Ivy

The newest version!
package com.github.unidbg.hook;

import com.github.unidbg.AbstractEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Symbol;
import com.github.unidbg.arm.Arm64Svc;
import com.github.unidbg.arm.ArmSvc;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.ios.hook.FishHook;
import com.github.unidbg.ios.hook.Substrate;
import com.github.unidbg.memory.SvcMemory;
import com.sun.jna.Pointer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class HookLoader extends BaseHook {

    private static final Log log = LogFactory.getLog(HookLoader.class);

    public static HookLoader load(Emulator emulator) {
        Substrate.getInstance(emulator); // load substrate first
        FishHook.getInstance(emulator); // load fishhook

        HookLoader loader = emulator.get(HookLoader.class.getName());
        if (loader == null) {
            loader = new HookLoader(emulator);
            emulator.set(HookLoader.class.getName(), loader);
        }
        return loader;
    }

    private final Symbol _hook_objc_msgSend;
    private final Symbol _hook_dispatch_async;

    private HookLoader(Emulator emulator) {
        super(emulator, "libhook");

        _hook_objc_msgSend = module.findSymbolByName("_hook_objc_msgSend", false);
        if (_hook_objc_msgSend == null) {
            throw new IllegalStateException("find _hook_objc_msgSend failed");
        }

        _hook_dispatch_async = module.findSymbolByName("_hook_dispatch_async", false);
        if (_hook_dispatch_async == null) {
            throw new IllegalStateException("find _hook_dispatch_async failed");
        }
    }

    private boolean objcMsgSendHooked;

    public synchronized void hookObjcMsgSend(final MsgSendCallback callback) {
        if (objcMsgSendHooked) {
            throw new IllegalStateException("objc_msgSend already hooked.");
        }

        SvcMemory svcMemory = emulator.getSvcMemory();
        Pointer pointer = callback == null ? null : svcMemory.registerSvc(emulator.is64Bit() ? new Arm64Svc() {
            @Override
            public long handle(Emulator emulator) {
                return objc_msgSend_callback(emulator, callback);
            }
        } : new ArmSvc() {
            @Override
            public long handle(Emulator emulator) {
                return objc_msgSend_callback(emulator, callback);
            }
        });
        _hook_objc_msgSend.call(emulator, pointer);
        objcMsgSendHooked = true;
    }

    private boolean dispatchAsyncHooked;

    public synchronized void hookDispatchAsync(final DispatchAsyncCallback callback) {
        if (dispatchAsyncHooked) {
            throw new IllegalStateException("dispatch_async already hooked.");
        }
        if (emulator.is32Bit()) {
            throw new UnsupportedOperationException();
        }

        SvcMemory svcMemory = emulator.getSvcMemory();
        Pointer pointer = callback == null ? null : svcMemory.registerSvc(new Arm64Svc() {
            @Override
            public long handle(Emulator emulator) {
                return dispatch_callback(emulator, callback);
            }
        });
        _hook_dispatch_async.call(emulator, pointer);

        dispatchAsyncHooked = true;
    }

    private long dispatch_callback(Emulator emulator, DispatchAsyncCallback callback) {
        RegisterContext context = emulator.getContext();
        Pointer dq = context.getPointerArg(0);
        Pointer block = context.getPointerArg(1);
        Pointer fun = block.getPointer(0x10);
        boolean is_barrier_async = context.getIntArg(2) != 0;
        DispatchAsyncCallback.Result dispatch = callback.canDispatch(emulator, dq, fun, is_barrier_async);
        if (dispatch == null) {
            dispatch = DispatchAsyncCallback.Result.skip;
        }
        if (dispatch == DispatchAsyncCallback.Result.skip && (log.isDebugEnabled() || LogFactory.getLog(AbstractEmulator.class).isDebugEnabled())) {
            System.err.println("Skip dispatch_async dq=" + dq + ", fun=" + fun);
        }
        return dispatch.ordinal();
    }

    private long objc_msgSend_callback(Emulator emulator, MsgSendCallback callback) {
        RegisterContext context = emulator.getContext();
        boolean systemClass = context.getIntArg(0) != 0;
        Pointer classNamePointer = context.getPointerArg(1);
        String cmd = context.getPointerArg(2).getString(0);
        Pointer lr = context.getPointerArg(3);
        callback.onMsgSend(emulator, systemClass, classNamePointer == null ? null : classNamePointer.getString(0), cmd, lr);
        return 0;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy