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

com.github.unidbg.ios.Dyld64 Maven / Gradle / Ivy

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

import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.Svc;
import com.github.unidbg.Symbol;
import com.github.unidbg.arm.Arm64Hook;
import com.github.unidbg.arm.Arm64Svc;
import com.github.unidbg.arm.HookStatus;
import com.github.unidbg.arm.context.EditableArm64RegisterContext;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.ios.struct.DyldUnwindSections;
import com.github.unidbg.ios.struct.SystemVersion;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.MemoryBlock;
import com.github.unidbg.memory.SvcMemory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.pointer.UnidbgStructure;
import com.github.unidbg.spi.InitFunction;
import com.github.unidbg.unix.struct.DlInfo64;
import com.sun.jna.Pointer;
import keystone.Keystone;
import keystone.KeystoneArchitecture;
import keystone.KeystoneEncoded;
import keystone.KeystoneMode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import unicorn.Arm64Const;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Dyld64 extends Dyld {

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

    Dyld64(final MachOLoader loader, final SvcMemory svcMemory) {
        super(svcMemory);

        __dyld_register_thread_helpers = svcMemory.registerSvc(new Arm64Svc("dyld_register_thread_helpers") {
            @Override
            public long handle(Emulator emulator) {
                // the table passed to dyld containing thread helpers
                Pointer helpers = UnidbgPointer.register(emulator, Arm64Const.UC_ARM64_REG_X0);
                if (log.isDebugEnabled()) {
                    log.debug("registerThreadHelpers helpers=" + helpers + ", version=" + helpers.getLong(0));
                }
                return 0;
            }
        });
        __dyld_get_image_slide = svcMemory.registerSvc(new Arm64Svc("dyld_get_image_slide") {
            @Override
            public long handle(Emulator emulator) {
                UnidbgPointer mh = UnidbgPointer.register(emulator, Arm64Const.UC_ARM64_REG_X0);
                long slide = mh == null ? 0 : computeSlide(emulator, mh.peer);
                log.debug("__dyld_get_image_slide mh=" + mh + ", slide=0x" + Long.toHexString(slide));
                return slide;
            }
        });

        /*
         * _dyld_register_func_for_remove_image registers the specified function to be
         * called when an image is removed (a bundle or a dynamic shared library) from
         * the program.
         */
        __dyld_register_func_for_remove_image = svcMemory.registerSvc(new Arm64Svc("dyld_register_func_for_remove_image") {
            @Override
            public long handle(Emulator emulator) {
                Pointer callback = UnidbgPointer.register(emulator, Arm64Const.UC_ARM64_REG_X0);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_register_func_for_remove_image callback=" + callback);
                }
                return 0;
            }
        });
        __dyld_image_count = svcMemory.registerSvc(new Arm64Svc("dyld_image_count") {
            @Override
            public long handle(Emulator emulator) {
                return loader.getLoadedModulesNoVirtual().size();
            }
        });
        __dyld_get_image_name = svcMemory.registerSvc(new Arm64Svc("dyld_get_image_name") {
            @Override
            public long handle(Emulator emulator) {
                int image_index = emulator.getContext().getIntArg(0);
                Module[] modules = loader.getLoadedModulesNoVirtual().toArray(new Module[0]);
                if (image_index < 0 || image_index >= modules.length) {
                    return 0;
                }
                MachOModule module = (MachOModule) modules[image_index];
                return module.createPathMemory(svcMemory).peer;
            }
        });
        __dyld_get_image_header = svcMemory.registerSvc(new Arm64Svc("dyld_get_image_header") {
            @Override
            public long handle(Emulator emulator) {
                int image_index = emulator.getContext().getIntArg(0);
                Module[] modules = loader.getLoadedModulesNoVirtual().toArray(new Module[0]);
                if (image_index < 0 || image_index >= modules.length) {
                    return 0;
                }
                MachOModule module = (MachOModule) modules[image_index];
                return module.machHeader;
            }
        });
        __dyld_get_image_vmaddr_slide = svcMemory.registerSvc(new Arm64Svc("dyld_get_image_vmaddr_slide") {
            @Override
            public long handle(Emulator emulator) {
                int image_index = emulator.getContext().getIntArg(0);
                Module[] modules = loader.getLoadedModulesNoVirtual().toArray(new Module[0]);
                if (image_index < 0 || image_index >= modules.length) {
                    if (log.isDebugEnabled()) {
                        log.debug("__dyld_get_image_vmaddr_slide index=" + image_index);
                    }
                    return 0;
                }
                MachOModule module = (MachOModule) modules[image_index];
                long slide = computeSlide(emulator, module.machHeader);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_get_image_vmaddr_slide index=" + image_index + ", slide=0x" + Long.toHexString(slide) + ", module=" + module.name);
                }
                return slide;
            }
        });

        /*
         * _dyld_register_func_for_add_image registers the specified function to be
         * called when a new image is added (a bundle or a dynamic shared library) to
         * the program.  When this function is first registered it is called for once
         * for each image that is currently part of the program.
         */
        __dyld_register_func_for_add_image = svcMemory.registerSvc(new Arm64Svc("dyld_register_func_for_add_image") {
            @Override
            public UnidbgPointer onRegister(SvcMemory svcMemory, int svcNumber) {
                try (Keystone keystone = new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian)) {
                    KeystoneEncoded encoded = keystone.assemble(Arrays.asList(
                            "sub sp, sp, #0x10",
                            "stp x29, x30, [sp]",
                            "svc #0x" + Integer.toHexString(svcNumber),

                            "ldr x13, [sp]",
                            "add sp, sp, #0x8", // manipulated stack in __dyld_register_func_for_add_image
                            "cmp x13, #0",
                            "b.eq #0x38",
                            "adr lr, #-0xf", // jump to ldr x13, [sp]
                            "bic lr, lr, #0x1",

                            "ldr x0, [sp]",
                            "add sp, sp, #0x8",
                            "ldr x1, [sp]",
                            "add sp, sp, #0x8",
                            "br x13", // call (headerType *mh, unsigned long	vmaddr_slide)

                            "ldr x0, [sp]", // with return address
                            "add sp, sp, #0x8",

                            "ldp x29, x30, [sp]",
                            "add sp, sp, #0x10",
                            "ret"));
                    byte[] code = encoded.getMachineCode();
                    UnidbgPointer pointer = svcMemory.allocate(code.length, "__dyld_register_func_for_add_image");
                    pointer.write(0, code, 0, code.length);
                    return pointer;
                }
            }

            @Override
            public long handle(Emulator emulator) {
                EditableArm64RegisterContext context = emulator.getContext();

                UnidbgPointer callback = context.getPointerArg(0);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_register_func_for_add_image callback=" + callback);
                }

                Pointer pointer = context.getStackPointer();
                try {
                    pointer = pointer.share(-8); // return value
                    pointer.setLong(0, 0);

                    pointer = pointer.share(-8); // NULL-terminated
                    pointer.setLong(0, 0);

                    if (callback != null && !loader.addImageCallbacks.contains(callback)) {
                        loader.addImageCallbacks.add(callback);

                        List modules = loader.getLoadedModulesNoVirtual();
                        Collections.reverse(modules);
                        for (Module md : modules) {
                            Log log = LogFactory.getLog("com.github.unidbg.ios." + md.name);
                            MachOModule mm = (MachOModule) md;
                            if (mm.executable) {
                                continue;
                            }
                            mm.addImageCallSet.add(callback);

                            // (headerType *mh, unsigned long	vmaddr_slide)
                            pointer = pointer.share(-8);
                            pointer.setLong(0, mm.machHeader);
                            pointer = pointer.share(-8);
                            pointer.setLong(0, computeSlide(emulator, mm.machHeader));

                            String msg = "[" + md.name + "]PushAddImageFunction: 0x" + Long.toHexString(mm.machHeader);
                            if (log.isDebugEnabled()) {
                                log.debug(msg);
                            } else if (Dyld64.log.isDebugEnabled()) {
                                Dyld64.log.debug(msg);
                            }
                            pointer = pointer.share(-8); // callback
                            pointer.setPointer(0, callback);
                        }
                    }

                    return 0;
                } finally {
                    context.setStackPointer(pointer);
                }
            }
        });
        __dyld_dyld_register_image_state_change_handler = svcMemory.registerSvc(new Arm64Svc("dyld_dyld_register_image_state_change_handler") {
            @Override
            public UnidbgPointer onRegister(SvcMemory svcMemory, int svcNumber) {
                try (Keystone keystone = new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian)) {
                    KeystoneEncoded encoded = keystone.assemble(Arrays.asList(
                            "sub sp, sp, #0x10",
                            "stp x29, x30, [sp]",
                            "svc #0x" + Integer.toHexString(svcNumber),

                            "ldr x13, [sp]",
                            "add sp, sp, #0x8", // manipulated stack in dyld_image_state_change_handler
                            "cmp x13, #0",
                            "b.eq #0x40",
                            "adr lr, #-0xf", // jump to ldr x13, [sp]
                            "bic lr, lr, #0x1",

                            "ldr x0, [sp]",
                            "add sp, sp, #0x8",
                            "ldr x1, [sp]",
                            "add sp, sp, #0x8",
                            "ldr x2, [sp]",
                            "add sp, sp, #0x8",
                            "br x13", // call (*dyld_image_state_change_handler)(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])

                            "ldr x0, [sp]", // with return address
                            "add sp, sp, #0x8",

                            "ldp x29, x30, [sp]",
                            "add sp, sp, #0x10",
                            "ret"));
                    byte[] code = encoded.getMachineCode();
                    UnidbgPointer pointer = svcMemory.allocate(code.length, "dyld_image_state_change_handler");
                    pointer.write(0, code, 0, code.length);
                    return pointer;
                }
            }
            @Override
            public long handle(Emulator emulator) {
                EditableArm64RegisterContext context = emulator.getContext();
                int state = context.getIntArg(0);
                int batch = context.getIntArg(1);
                UnidbgPointer handler = context.getPointerArg(2);
                UnidbgStructure[] imageInfos;
                if (batch == 1) {
                    imageInfos = registerImageStateBatchChangeHandler(loader, state, handler, emulator);
                } else {
                    imageInfos = registerImageStateSingleChangeHandler(loader, state, handler, emulator);
                }

                Pointer pointer = context.getStackPointer();
                try {
                    pointer = pointer.share(-8); // return value
                    pointer.setLong(0, 0);

                    pointer = pointer.share(-8); // NULL-terminated
                    pointer.setLong(0, 0);

                    if (handler != null && imageInfos != null) {
                        // (*dyld_image_state_change_handler)(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
                        pointer = pointer.share(-8);
                        pointer.setPointer(0, imageInfos.length == 0 ? null : imageInfos[0].getPointer());
                        pointer = pointer.share(-8);
                        pointer.setLong(0, imageInfos.length);
                        pointer = pointer.share(-8);
                        pointer.setLong(0, state);

                        if (log.isDebugEnabled()) {
                            log.debug("PushImageHandlerFunction: " + handler + ", imageSize=" + imageInfos.length + ", batch=" + batch);
                        }
                        pointer = pointer.share(-8); // handler
                        pointer.setPointer(0, handler);
                    }

                    return 0;
                } finally {
                    context.setStackPointer(pointer);
                }
            }
        });
        __dyld_image_path_containing_address = svcMemory.registerSvc(new Arm64Svc("dyld_image_path_containing_address") {
            @Override
            public long handle(Emulator emulator) {
                UnidbgPointer address = UnidbgPointer.register(emulator, Arm64Const.UC_ARM64_REG_X0);
                MachOModule module = (MachOModule) loader.findModuleByAddress(address.peer);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_image_path_containing_address address=" + address + ", module=" + module);
                }
                if (module != null) {
                    return module.createPathMemory(svcMemory).peer;
                } else {
                    return 0;
                }
            }
        });
        __dyld__NSGetExecutablePath = svcMemory.registerSvc(new Arm64Svc("dyld__NSGetExecutablePath") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext context = emulator.getContext();
                Pointer buf = context.getPointerArg(0);
                Pointer bufSize = context.getPointerArg(1);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld__NSGetExecutablePath buf=" + buf + ", bufSize=" + bufSize);
                }
                byte[] str = emulator.getProcessName().getBytes(StandardCharsets.UTF_8);
                byte[] data = Arrays.copyOf(str, str.length + 1);
                if (bufSize.getInt(0) >= data.length) {
                    buf.write(0, data, 0, data.length);
                    return 0;
                }
                bufSize.setInt(0, data.length);
                return -1;
            }
        });
        __dyld_fast_stub_entry = svcMemory.registerSvc(new Arm64Svc("dyld_fast_stub_entry") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext context = emulator.getContext();
                UnidbgPointer imageLoaderCache = context.getPointerArg(0);
                long lazyBindingInfoOffset = context.getLongArg(1);
                MachOModule mm = (MachOModule) emulator.getMemory().findModuleByAddress(imageLoaderCache.peer);
                long result = mm.doBindFastLazySymbol(emulator, (int) lazyBindingInfoOffset);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_fast_stub_entry imageLoaderCache=" + imageLoaderCache + ", lazyBindingInfoOffset=0x" + Long.toHexString(lazyBindingInfoOffset) + ", result=0x" + Long.toHexString(result) + ", LR=" + context.getLRPointer());
                }
                return result;
            }
        });
        __dyld_find_unwind_sections = svcMemory.registerSvc(new Arm64Svc("dyld_find_unwind_sections") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext context = emulator.getContext();
                UnidbgPointer addr = context.getPointerArg(0);
                Pointer info = context.getPointerArg(1);
                MachOModule module = (MachOModule) emulator.getMemory().findModuleByAddress(addr.peer);
                if (module == null) {
                    log.info("__dyld_find_unwind_sections addr=" + addr + ", info=" + info);
                    return 0;
                } else {
                    if (log.isDebugEnabled()) {
                        log.debug("__dyld_find_unwind_sections addr=" + addr + ", info=" + info);
                    }
                    module.getUnwindInfo(new DyldUnwindSections(info));
                    return 1;
                }
            }
        });

        __dyld_dlopen = svcMemory.registerSvc(new Arm64Svc("dyld_dlopen") {
            @Override
            public UnidbgPointer onRegister(SvcMemory svcMemory, int svcNumber) {
                try (Keystone keystone = new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian)) {
                    KeystoneEncoded encoded = keystone.assemble(Arrays.asList(
                            "sub sp, sp, #0x10",
                            "stp x29, x30, [sp]",
                            "svc #0x" + Integer.toHexString(svcNumber),

                            "ldr x13, [sp]",
                            "add sp, sp, #0x8", // manipulated stack in dlopen
                            "cmp x13, #0",
                            "b.eq #0x28",
                            "adr lr, #-0xf", // jump to ldr x13, [sp]
                            "bic lr, lr, #0x1",
                            "br x13", // call init array

                            "ldr x0, [sp]", // with return address
                            "add sp, sp, #0x8",

                            "ldp x29, x30, [sp]",
                            "add sp, sp, #0x10",
                            "ret"));
                    byte[] code = encoded.getMachineCode();
                    UnidbgPointer pointer = svcMemory.allocate(code.length, "__dyld_dlopen");
                    pointer.write(0, code, 0, code.length);
                    return pointer;
                }
            }
            @Override
            public long handle(Emulator emulator) {
                RegisterContext context = emulator.getContext();
                Pointer path = context.getPointerArg(0);
                int mode = context.getIntArg(1);
                String str = path == null ? null : path.getString(0);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_dlopen path=" + str + ", mode=0x" + Integer.toHexString(mode));
                }
                return dlopen(emulator, str, mode);
            }
        });

        _os_trace_redirect_func = svcMemory.registerSvc(new Arm64Svc("os_trace_redirect_func") {
            @Override
            public long handle(Emulator emulator) {
                Pointer msg = emulator.getContext().getPointerArg(0);
                System.err.println("_os_trace_redirect_func msg=" + msg.getString(0));
                return 1;
            }
        }).peer;

        sandbox_check = svcMemory.registerSvc(new Arm64Svc("sandbox_check") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext ctx = emulator.getContext();
                int pid = ctx.getIntArg(0);
                Pointer operation = ctx.getPointerArg(1);
                int type = ctx.getIntArg(2);
                if (log.isDebugEnabled()) {
                    log.debug("sandbox_check pid=" + pid + ", operation=" + (operation == null ? null : operation.getString(0)) + ", type=" + type);
                }
                return 1;
            }
        }).peer;

        __availability_version_check = svcMemory.registerSvc(new Arm64Svc("availability_version_check") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext ctx = emulator.getContext();
                int count = ctx.getIntArg(0);
                Pointer versions = ctx.getPointerArg(1);
                if (log.isDebugEnabled()) {
                    log.debug("_availability_version_check count=" + count + ", versions=" + versions);
                }
                return 1;
            }
        }).peer;

        __dyld_dlsym = svcMemory.registerSvc(new Arm64Svc("dyld_dlsym") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext context = emulator.getContext();
                long handle = context.getLongArg(0);
                Pointer symbol = context.getPointerArg(1);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_dlsym handle=0x" + Long.toHexString(handle) + ", symbol=" + symbol.getString(0));
                }

                String symbolName = symbol.getString(0);
                if ((int) handle == Dyld.RTLD_MAIN_ONLY && "_os_trace_redirect_func".equals(symbolName)) {
                    return _os_trace_redirect_func;
                }
                if ("sandbox_check".equals(symbolName)) {
                    return sandbox_check;
                }
                if ("_availability_version_check".equals(symbolName)) {
                    return __availability_version_check;
                }
                if ("objc_addLoadImageFunc".equals(symbolName)) {
                    return __dyld_register_func_for_add_image.peer;
                }

                return dlsym(emulator, handle, "_" + symbolName);
            }
        });
        __dyld_dladdr = svcMemory.registerSvc(new Arm64Svc("dyld_dladdr") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext context = emulator.getContext();
                long addr = context.getLongArg(0);
                Pointer info = context.getPointerArg(1);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_dladdr addr=0x" + Long.toHexString(addr) + ", info=" + info);
                }
                MachOModule module = (MachOModule) loader.findModuleByAddress(addr);
                if (module == null) {
                    return 0;
                }

                Symbol symbol = module.findClosestSymbolByAddress(addr, true);

                DlInfo64 dlInfo = new DlInfo64(info);
                dlInfo.dli_fname = UnidbgPointer.nativeValue(module.createPathMemory(svcMemory));
                dlInfo.dli_fbase = module.machHeader;
                if (symbol != null) {
                    dlInfo.dli_sname = UnidbgPointer.nativeValue(symbol.createNameMemory(svcMemory));
                    dlInfo.dli_saddr = symbol.getAddress();
                }
                dlInfo.pack();
                return 1;
            }
        });
        __dyld_dlclose = svcMemory.registerSvc(new Arm64Svc("dyld_dlclose") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext context = emulator.getContext();
                long handler = context.getLongArg(0);
                if (log.isDebugEnabled()) {
                    log.debug("__dyld_dlclose handler=0x" + Long.toHexString(handler));
                }
                return 0;
            }
        });
        __dyld_dlopen_preflight = svcMemory.registerSvc(new Arm64Svc("dyld_dlopen_preflight") {
            @Override
            public long handle(Emulator emulator) {
                RegisterContext context = emulator.getContext();
                Pointer path = context.getPointerArg(0);
                String pathname = path.getString(0);
                MachOLoader loader = (MachOLoader) emulator.getMemory();
                boolean canLoad = loader.dlopen_preflight(pathname);
                if (log.isDebugEnabled()) {
                    log.debug("dlopen_preflight path=" + pathname + ", canLoad=" + canLoad);
                }
                return canLoad ? 1 : 0;
            }
        });
        __dyld_fork_child = svcMemory.registerSvc(new Arm64Svc("dyld_fork_child") {
            @Override
            public long handle(Emulator emulator) {
                if (log.isDebugEnabled()) {
                    log.debug("_dyld_fork_child");
                }
                return 0;
            }
        });
        __dyld_shared_cache_some_image_overridden = svcMemory.registerSvc(new Arm64Svc("dyld_shared_cache_some_image_overridden") {
            @Override
            public long handle(Emulator emulator) {
                return 0;
            }
        });
    }

    private final Pointer __dyld_image_count;
    private final Pointer __dyld_get_image_name;
    private final Pointer __dyld_get_image_header;
    private final Pointer __dyld_get_image_vmaddr_slide;
    private final Pointer __dyld_get_image_slide;
    private final UnidbgPointer __dyld_register_func_for_add_image;
    private final Pointer __dyld_register_func_for_remove_image;
    private final Pointer __dyld_register_thread_helpers;
    private final Pointer __dyld_dyld_register_image_state_change_handler;
    private final Pointer __dyld_image_path_containing_address;
    private final Pointer __dyld__NSGetExecutablePath;
    private final Pointer __dyld_fast_stub_entry;
    private final Pointer __dyld_find_unwind_sections;
    private final Pointer __dyld_fork_child;

    @Override
    final int _stub_binding_helper() {
        log.info("dyldLazyBinder");
        return 0;
    }

    private final Pointer __dyld_dlopen;
    private final Pointer __dyld_dlsym;
    private final Pointer __dyld_dladdr;
    private final Pointer __dyld_dlclose;
    private final Pointer __dyld_dlopen_preflight;
    private final Pointer __dyld_shared_cache_some_image_overridden;
    private final long _os_trace_redirect_func;
    private final long sandbox_check;
    private final long __availability_version_check;

    @Override
    final int _dyld_func_lookup(Emulator emulator, String name, Pointer address) {
        if (log.isDebugEnabled()) {
            log.debug("_dyld_func_lookup name=" + name);
        }
        switch (name) {
            case "__dyld_fast_stub_entry": // fastBindLazySymbol
                address.setPointer(0, __dyld_fast_stub_entry);
                return 1;
            case "__dyld__NSGetExecutablePath":
                address.setPointer(0, __dyld__NSGetExecutablePath);
                return 1;
            case "__dyld_get_image_name":
                address.setPointer(0, __dyld_get_image_name);
                return 1;
            case "__dyld_get_image_header":
                address.setPointer(0, __dyld_get_image_header);
                return 1;
            case "__dyld_get_image_slide":
                address.setPointer(0, __dyld_get_image_slide);
                return 1;
            case "__dyld_get_image_vmaddr_slide":
                address.setPointer(0, __dyld_get_image_vmaddr_slide);
                return 1;
            case "__dyld_image_count":
                address.setPointer(0, __dyld_image_count);
                return 1;
            case "__dyld_dlopen_preflight":
                address.setPointer(0, __dyld_dlopen_preflight);
                return 1;
            case "__dyld_dlopen":
                address.setPointer(0, __dyld_dlopen);
                return 1;
            case "__dyld_dladdr":
                address.setPointer(0, __dyld_dladdr);
                return 1;
            case "__dyld_dlclose":
                address.setPointer(0, __dyld_dlclose);
                return 1;
            case "__dyld_dlsym":
                address.setPointer(0, __dyld_dlsym);
                return 1;
            case "__dyld_register_thread_helpers":
                address.setPointer(0, __dyld_register_thread_helpers);
                return 1;
            case "__dyld_image_path_containing_address":
                address.setPointer(0, __dyld_image_path_containing_address);
                return 1;
            case "__dyld_register_func_for_remove_image":
                address.setPointer(0, __dyld_register_func_for_remove_image);
                return 1;
            case "__dyld_find_unwind_sections":
                address.setPointer(0, __dyld_find_unwind_sections);
                return 1;
            case "__dyld_register_func_for_add_image":
                address.setPointer(0, __dyld_register_func_for_add_image);
                return 1;
            case "__dyld_dyld_register_image_state_change_handler":
                address.setPointer(0, __dyld_dyld_register_image_state_change_handler);
                return 1;
            case "__dyld_fork_child":
                address.setPointer(0, __dyld_fork_child);
                return 1;
            case "__dyld_shared_cache_some_image_overridden":
                address.setPointer(0, __dyld_shared_cache_some_image_overridden);
                return 1;
            default:
                log.info("_dyld_func_lookup name=" + name + ", address=" + address);
                break;
        }
        address.setPointer(0, null);
        return 0;
    }

    private long dlopen(Emulator emulator, String path, int mode) {
        Memory memory = emulator.getMemory();
        EditableArm64RegisterContext context = emulator.getContext();
        Pointer pointer = context.getStackPointer();
        try {
            Collection loaded = memory.getLoadedModules();
            Module module = path == null ? null : memory.dlopen(path, false);
            if (module == null) {
                int ret;
                if (path == null) {
                    if ((mode & RTLD_FIRST) != 0) {
                        ret = RTLD_MAIN_ONLY;
                    } else {
                        ret = RTLD_DEFAULT;
                    }
                } else {
                    ret = 0;
                }

                pointer = pointer.share(-8); // return value
                pointer.setLong(0, ret);

                pointer = pointer.share(-8); // NULL-terminated
                pointer.setLong(0, 0);

                if (ret == 0) {
                    this.error.setString(0, "Resolve library " + path + " failed");
                    if ("/usr/sbin/aslmanager".equals(path) ||
                            "/System/Library/PrivateFrameworks/Librarian.framework/Librarian".equals(path) ||
                            "/System/Library/PrivateFrameworks/CloudDocs.framework/CloudDocs".equals(path)) {
                        return 0;
                    }
                    log.info("dlopen failed: " + path);
                    if (log.isDebugEnabled()) {
                        emulator.attach().debug();
                    }
                }
                return 0;
            } else {
                pointer = pointer.share(-8); // return value
                pointer.setLong(0, module.base);

                pointer = pointer.share(-8); // NULL-terminated
                pointer.setLong(0, 0);

                Set newLoaded = new HashSet<>(memory.getLoadedModules());
                newLoaded.removeAll(loaded);
                if (log.isDebugEnabled()) {
                    log.debug("newLoaded=" + newLoaded + ", contains=" + loaded.contains(module));
                }
                for (Module m : newLoaded) {
                    MachOModule mm = (MachOModule) m;
                    if (mm.hasUnresolvedSymbol()) {
                        continue;
                    }
                    for (InitFunction initFunction : mm.routines) {
                        if (log.isDebugEnabled()) {
                            log.debug("[" + mm.name + "]PushRoutineFunction: 0x" + Long.toHexString(initFunction.getAddress()));
                        }
                        pointer = pointer.share(-8); // routine
                        pointer.setLong(0, initFunction.getAddress());
                    }
                    mm.routines.clear();
                    for (InitFunction initFunction : mm.initFunctionList) {
                        if (log.isDebugEnabled()) {
                            log.debug("[" + mm.name + "]PushModInitFunction: 0x" + Long.toHexString(initFunction.getAddress()));
                        }
                        pointer = pointer.share(-8); // init array
                        pointer.setLong(0, initFunction.getAddress());
                    }
                    mm.initFunctionList.clear();
                }

                return ((MachOModule) module).machHeader;
            }
        } finally {
            context.setStackPointer(pointer);
        }
    }

    private long _abort;
    private long _asl_open;

    private long _dyld_program_sdk_at_least;
    private long __os_feature_enabled_simple_impl;
    private long __dyld_objc_notify_register;
    private long __dyld_get_shared_cache_range;
    private long __dyld_get_objc_selector;
    private long __dyld_get_prog_image_header;
    private long __dyld_for_each_objc_class;
    private long __dyld_for_each_objc_protocol;
    private long _os_unfair_recursive_lock_lock_with_options;
    private long _os_unfair_recursive_lock_tryunlock4objc;
    private long _os_unfair_recursive_lock_unlock;
    private long _os_unfair_lock_lock_with_options;
    private long _os_unfair_lock_unlock;
    private long _clock_gettime_nsec_np;
    private long _os_variant_allows_internal_security_policies;
    private long _abort_with_reason;
    private long __dyld_is_memory_immutable;

    private long _os_system_version_get_current_version;
    private long _dyld_get_active_platform;
    private long __os_log_set_nscf_formatter;
    private long _dyld_has_inserted_or_interposing_libraries;
    private long __pthread_setspecific_static;
    private long _os_log_shim_enabled;
    private long _os_unfair_lock_assert_owner;
    private long _os_unfair_lock_assert_not_owner;
    private long _os_log_create;
    private long _os_log_type_enabled;
    private long _xpc_copy_entitlement_for_self;
    private long _xpc_connection_activate;
    private long __CFNotificationCenterRegisterDependentNotificationList;
    private long __CFLogvEx3;
    private long _voucher_copy;
    private long _dyld_image_header_containing_address;

    @Override
    public long hook(final SvcMemory svcMemory, String libraryName, String symbolName, final long old) {
        if ("_dyld_image_header_containing_address".equals(symbolName)) {
            if (_dyld_image_header_containing_address == 0) {
                _dyld_image_header_containing_address = svcMemory.registerSvc(new Arm64Svc("dyld_image_header_containing_address") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        long address = context.getLongArg(0);
                        MachOModule mm = (MachOModule) emulator.getMemory().findModuleByAddress(address);
                        return mm == null ? 0L : mm.machHeader;
                    }
                }).peer;
            }
            return _dyld_image_header_containing_address;
        }
        if ("_voucher_copy".equals(symbolName)) {
            if (_voucher_copy == 0) {
                _voucher_copy = svcMemory.registerSvc(new Arm64Svc("voucher_copy") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _voucher_copy;
        }
        if ("__CFLogvEx3".equals(symbolName)) {
            if (__CFLogvEx3 == 0) {
                __CFLogvEx3 = svcMemory.registerSvc(new Arm64Svc("CFLogvEx3") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return __CFLogvEx3;
        }
        if ("__CFNotificationCenterRegisterDependentNotificationList".equals(symbolName)) {
            if (__CFNotificationCenterRegisterDependentNotificationList == 0) {
                __CFNotificationCenterRegisterDependentNotificationList = svcMemory.registerSvc(new Arm64Svc("CFNotificationCenterRegisterDependentNotificationList") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return __CFNotificationCenterRegisterDependentNotificationList;
        }
        if ("_xpc_connection_activate".equals(symbolName)) {
            if (_xpc_connection_activate == 0) {
                _xpc_connection_activate = svcMemory.registerSvc(new Arm64Svc("xpc_connection_activate") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _xpc_connection_activate;
        }
        if ("_xpc_copy_entitlement_for_self".equals(symbolName)) {
            if (_xpc_copy_entitlement_for_self == 0) {
                _xpc_copy_entitlement_for_self = svcMemory.registerSvc(new Arm64Svc("xpc_copy_entitlement_for_self") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _xpc_copy_entitlement_for_self;
        }
        if ("_os_log_type_enabled".equals(symbolName)) {
            if (_os_log_type_enabled == 0) {
                _os_log_type_enabled = svcMemory.registerSvc(new Arm64Svc("os_log_type_enabled") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _os_log_type_enabled;
        }
        if ("_os_log_create".equals(symbolName)) {
            if (_os_log_create == 0) {
                _os_log_create = svcMemory.registerSvc(new Arm64Svc("os_log_create") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _os_log_create;
        }
        if ("_os_unfair_lock_assert_not_owner".equals(symbolName)) {
            if (_os_unfair_lock_assert_not_owner == 0) {
                _os_unfair_lock_assert_not_owner = svcMemory.registerSvc(new Arm64Svc("os_unfair_lock_assert_not_owner") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _os_unfair_lock_assert_not_owner;
        }
        if ("_os_unfair_lock_assert_owner".equals(symbolName)) {
            if (_os_unfair_lock_assert_owner == 0) {
                _os_unfair_lock_assert_owner= svcMemory.registerSvc(new Arm64Svc("os_unfair_lock_assert_owner") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _os_unfair_lock_assert_owner;
        }
        if ("_os_log_shim_enabled".equals(symbolName)) {
            if (_os_log_shim_enabled == 0) {
                _os_log_shim_enabled = svcMemory.registerSvc(new Arm64Svc("os_log_shim_enabled") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _os_log_shim_enabled;
        }
        if ("__pthread_setspecific_static".equals(symbolName)) {
            if (__pthread_setspecific_static == 0) {
                __pthread_setspecific_static = svcMemory.registerSvc(new Arm64Svc("pthread_setspecific_static") {
                    private final long tsd[] = new long[128];
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        int key = context.getIntArg(0);
                        long value = context.getLongArg(1);
                        tsd[key] = value;
                        return 0;
                    }
                }).peer;
            }
            return __pthread_setspecific_static;
        }
        if ("_dyld_has_inserted_or_interposing_libraries".equals(symbolName)) {
            if (_dyld_has_inserted_or_interposing_libraries == 0) {
                _dyld_has_inserted_or_interposing_libraries = svcMemory.registerSvc(new Arm64Svc("dyld_has_inserted_or_interposing_libraries") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return _dyld_has_inserted_or_interposing_libraries;
        }
        if ("__os_log_set_nscf_formatter".equals(symbolName)) {
            if (__os_log_set_nscf_formatter == 0) {
                __os_log_set_nscf_formatter = svcMemory.registerSvc(new Arm64Svc("os_log_set_nscf_formatter") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                }).peer;
            }
            return __os_log_set_nscf_formatter;
        }
        if ("_dyld_get_active_platform".equals(symbolName)) {
            if (_dyld_get_active_platform == 0) {
                _dyld_get_active_platform = svcMemory.registerSvc(new Arm64Svc("dyld_get_active_platform") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 2; // PLATFORM_IOS
                    }
                }).peer;
            }
            return _dyld_get_active_platform;
        }
        if ("_os_unfair_lock_unlock".equals(symbolName)) {
            if (_os_unfair_lock_unlock == 0) {
                _os_unfair_lock_unlock = svcMemory.registerSvc(new Arm64Svc("os_unfair_lock_unlock") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        Pointer lock = context.getPointerArg(0);
                        if (log.isDebugEnabled()) {
                            log.debug("_os_unfair_lock_unlock lock=" + lock + ", LR=" + context.getLRPointer());
                        }
                        return 0;
                    }
                }).peer;
            }
            return _os_unfair_lock_unlock;
        }
        if ("_os_unfair_lock_lock_with_options".equals(symbolName)) {
            if (_os_unfair_lock_lock_with_options == 0) {
                _os_unfair_lock_lock_with_options = svcMemory.registerSvc(new Arm64Svc("os_unfair_lock_lock_with_options") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        Pointer lock = context.getPointerArg(0);
                        int options = context.getIntArg(1);
                        if (log.isDebugEnabled()) {
                            log.debug("_os_unfair_lock_lock_with_options lock=" + lock + ", options=0x" + Integer.toHexString(options));
                        }
                        return 0;
                    }
                }).peer;
            }
            return _os_unfair_lock_lock_with_options;
        }
        if ("_dyld_program_sdk_at_least".equals(symbolName)) {
            if (_dyld_program_sdk_at_least == 0) {
                _dyld_program_sdk_at_least = svcMemory.registerSvc(new Arm64Svc("_dyld_program_sdk_at_least") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        long version = context.getLongArg(0);
                        if (log.isDebugEnabled()) {
                            log.debug("_dyld_program_sdk_at_least version=0x" + Long.toHexString(version));
                        }
                        return 0;
                    }
                }).peer;
            }
            return _dyld_program_sdk_at_least;
        }
        if ("libswiftCore.dylib".equals(libraryName)) {
            if ("_os_system_version_get_current_version".equals(symbolName)) {
                if (_os_system_version_get_current_version == 0) {
                    _os_system_version_get_current_version = svcMemory.registerSvc(new Arm64Svc("os_system_version_get_current_version") {
                        @Override
                        public long handle(Emulator emulator) {
                            RegisterContext context = emulator.getContext();
                            Pointer pointer = context.getPointerArg(0);
                            // 7.1.0
                            SystemVersion systemVersion = new SystemVersion(pointer);
                            systemVersion.major = 7;
                            systemVersion.minor = 1;
                            systemVersion.patch = 0;
                            systemVersion.pack();
                            return 0;
                        }
                    }).peer;
                }
                return _os_system_version_get_current_version;
            }
        }
        if ("__dyld_is_memory_immutable".equals(symbolName)) {
            if (__dyld_is_memory_immutable == 0) {
                __dyld_is_memory_immutable = svcMemory.registerSvc(new Arm64Svc("dyld_is_memory_immutable") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        UnidbgPointer addr = context.getPointerArg(0);
                        long length = context.getIntArg(1);
                        if (log.isDebugEnabled()) {
                            log.debug("dyld_is_memory_immutable addr=" + addr + ", length=" + length);
                        }
                        return 0;
                    }
                }).peer;
            }
            return __dyld_is_memory_immutable;
        }
        if ("libobjc.A.dylib".equals(libraryName)) {
            if ("_abort_with_reason".equals(symbolName)) {
                if (_abort_with_reason == 0) {
                    _abort_with_reason = svcMemory.registerSvc(new Arm64Svc("abort_with_reason") {
                        @Override
                        public long handle(Emulator emulator) {
                            RegisterContext context = emulator.getContext();
                            int reason_namespace = context.getIntArg(0);
                            long reason_code = context.getLongArg(1);
                            Pointer reason_string = context.getPointerArg(2);
                            long reason_flags = context.getLongArg(3);
                            System.err.println("abort_with_reason namespace=" + reason_namespace + ", code=" + reason_code + ", string=" + reason_string.getString(0) + ", flags=0x" + Long.toHexString(reason_flags));
                            emulator.attach().debug();
                            return 0;
                        }
                    }).peer;
                }
                return _abort_with_reason;
            }
            if ("__dyld_for_each_objc_protocol".equals(symbolName)) {
                if (__dyld_for_each_objc_protocol == 0) {
                    __dyld_for_each_objc_protocol = svcMemory.registerSvc(new Arm64Svc("dyld_for_each_objc_protocol") {
                        @Override
                        public long handle(Emulator emulator) {
                            RegisterContext context = emulator.getContext();
                            Pointer protocolName = context.getPointerArg(0);
                            Pointer callback = context.getPointerArg(1);
                            if (log.isDebugEnabled()) {
                                log.debug("dyld_for_each_objc_protocol protocolName=" + protocolName.getString(0) + ", callback=" + callback);
                            }
                            return 0;
                        }
                    }).peer;
                }
                return __dyld_for_each_objc_protocol;
            }
            if ("__dyld_for_each_objc_class".equals(symbolName)) {
                if (__dyld_for_each_objc_class == 0) {
                    __dyld_for_each_objc_class = svcMemory.registerSvc(new Arm64Svc("dyld_for_each_objc_class") {
                        @Override
                        public long handle(Emulator emulator) {
                            RegisterContext context = emulator.getContext();
                            Pointer className = context.getPointerArg(0);
                            Pointer callback = context.getPointerArg(1);
                            if (log.isDebugEnabled()) {
                                log.debug("dyld_for_each_objc_class className=" + className.getString(0) + ", callback=" + callback);
                            }
                            return 0;
                        }
                    }).peer;
                }
                return __dyld_for_each_objc_class;
            }
            if ("_os_variant_allows_internal_security_policies".equals(symbolName)) {
                if (_os_variant_allows_internal_security_policies == 0) {
                    _os_variant_allows_internal_security_policies = svcMemory.registerSvc(new Arm64Svc("os_variant_allows_internal_security_policies") {
                        @Override
                        public long handle(Emulator emulator) {
                            RegisterContext context = emulator.getContext();
                            Pointer subsystem = context.getPointerArg(0);
                            if (log.isDebugEnabled()) {
                                log.debug("_os_variant_allows_internal_security_policies subsystem=" + subsystem.getString(0));
                            }
                            return 0;
                        }
                    }).peer;
                }
                return _os_variant_allows_internal_security_policies;
            }
            if ("__dyld_get_prog_image_header".equals(symbolName)) {
                if (__dyld_get_prog_image_header == 0) {
                    __dyld_get_prog_image_header = svcMemory.registerSvc(new Arm64Svc("dyld_get_prog_image_header") {
                        @Override
                        public long handle(Emulator emulator) {
                            MachOLoader loader = (MachOLoader) emulator.getMemory();
                            MachOModule mm = (MachOModule) loader.getExecutableModule();
                            if (mm == null) {
                                throw new IllegalStateException();
                            }
                            return mm.machHeader;
                        }
                    }).peer;
                }
                return __dyld_get_prog_image_header;
            }
            if ("__dyld_get_objc_selector".equals(symbolName)) {
                if (__dyld_get_objc_selector == 0) {
                    __dyld_get_objc_selector = svcMemory.registerSvc(new Arm64Svc("dyld_get_objc_selector") {
                        @Override
                        public long handle(Emulator emulator) {
                            EditableArm64RegisterContext context = emulator.getContext();
                            long selName = context.getLongArg(0);
                            if (log.isDebugEnabled()) {
                                log.debug("dyld_get_objc_selector selName=0x" + Long.toHexString(selName));
                            }
                            return 0;
                        }
                    }).peer;
                }
                return __dyld_get_objc_selector;
            }
            if ("__dyld_get_shared_cache_range".equals(symbolName)) {
                if (__dyld_get_shared_cache_range == 0) {
                    __dyld_get_shared_cache_range = svcMemory.registerSvc(new Arm64Svc("dyld_get_shared_cache_range") {
                        @Override
                        public long handle(Emulator emulator) {
                            return 0;
                        }
                    }).peer;
                }
                return __dyld_get_shared_cache_range;
            }
            /*
             * Note: only for use by objc runtime
             * Register handlers to be called when objc images are mapped, unmapped, and initialized.
             * Dyld will call back the "mapped" function with an array of images that contain an objc-image-info section.
             * Those images that are dylibs will have the ref-counts automatically bumped, so objc will no longer need to
             * call dlopen() on them to keep them from being unloaded.  During the call to _dyld_objc_notify_register(),
             * dyld will call the "mapped" function with already loaded objc images.  During any later dlopen() call,
             * dyld will also call the "mapped" function.  Dyld will call the "init" function when dyld would be called
             * initializers in that image.  This is when objc calls any +load methods in that image.
             */
            if ("__dyld_objc_notify_register".equals(symbolName)) {
                if (__dyld_objc_notify_register == 0) {
                    __dyld_objc_notify_register = svcMemory.registerSvc(new Arm64Svc("dyld_objc_notify_register") {
                        private MemoryBlock block;
                        private final List list = new ArrayList<>(10);
                        private final boolean objcNotifyInit = false;
                        @Override
                        public UnidbgPointer onRegister(SvcMemory svcMemory, int svcNumber) {
                            try (Keystone keystone = new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian)) {
                                KeystoneEncoded encoded = keystone.assemble(Arrays.asList(
                                        "sub sp, sp, #0x10",
                                        "stp x29, x30, [sp]",
                                        "svc #0x" + Integer.toHexString(svcNumber),

                                        "blr x13", // call (*_dyld_objc_notify_mapped)(unsigned count, const char* const paths[], const struct mach_header* const mh[]);

                                        "ldr x13, [sp]",
                                        "add sp, sp, #0x8", // manipulated stack in dyld_objc_notify_register
                                        "cmp x13, #0",
                                        "b.eq #0x30",
                                        "adr lr, #-0x10", // jump to ldr x13, [sp]
                                        "ldp x0, x1, [sp]",
                                        "add sp, sp, #0x10",
                                        "br x13", // call _dyld_objc_notify_init

                                        "mov x8, #0",
                                        "mov x12, #0x" + Integer.toHexString(svcNumber),
                                        "mov x16, #0x" + Integer.toHexString(Svc.POST_CALLBACK_SYSCALL_NUMBER),
                                        "svc #0",

                                        "ldp x29, x30, [sp]",
                                        "add sp, sp, #0x10",
                                        "ret"));
                                byte[] code = encoded.getMachineCode();
                                UnidbgPointer pointer = svcMemory.allocate(code.length, "dyld_objc_notify_register");
                                pointer.write(0, code, 0, code.length);
                                if (log.isDebugEnabled()) {
                                    log.debug("_dyld_objc_notify_register pointer=" + pointer);
                                }
                                return pointer;
                            }
                        }
                        @Override
                        public long handle(Emulator emulator) {
                            if (block != null) {
                                throw new IllegalStateException();
                            }

                            EditableArm64RegisterContext context = emulator.getContext();
                            UnidbgPointer mapped = context.getPointerArg(0);
                            UnidbgPointer init = context.getPointerArg(1);
                            UnidbgPointer unmapped = context.getPointerArg(2);
                            if (mapped == null || init == null) {
                                throw new IllegalStateException();
                            }

                            if (log.isDebugEnabled()) {
                                log.debug("__dyld_objc_notify_register mapped=" + mapped + ", init=" + init + ", unmapped=" + unmapped);
                            }
                            MachOLoader loader = (MachOLoader) emulator.getMemory();
                            loader._objcNotifyMapped = mapped;
                            loader._objcNotifyInit = init;
                            for (MachOModule mm : loader.modules.values()) {
                                if (!mm.isVirtual()) {
                                    list.add(mm);
                                }
                            }
                            Collections.reverse(list);

                            Pointer pointer = context.getStackPointer();
                            try {
                                pointer = pointer.share(-8); // NULL-terminated
                                pointer.setLong(0, 0);

                                if (objcNotifyInit) {
                                    for (MachOModule mm : list) {
                                        // typedef void (*_dyld_objc_notify_init)(const char* path, const struct mach_header* mh);
                                        pointer = pointer.share(-8);
                                        pointer.setLong(0, mm.machHeader);
                                        pointer = pointer.share(-8);
                                        pointer.setPointer(0, mm.createPathMemory(svcMemory));
                                        pointer = pointer.share(-8); // _dyld_objc_notify_init
                                        pointer.setPointer(0, init);
                                    }
                                }
                            } finally {
                                context.setStackPointer(pointer);
                            }

                            block = emulator.getMemory().malloc(16 * list.size(), true);
                            UnidbgPointer paths = block.getPointer();
                            UnidbgPointer mh = paths.share(8L * list.size(), 8L * list.size());
                            for (int i = 0; i < list.size(); i++) {
                                MachOModule mm = list.get(i);
                                paths.setPointer(i * 8L, mm.createPathMemory(svcMemory));
                                mh.setLong(i * 8L, mm.machHeader);
                            }

                            context.setXLong(1, UnidbgPointer.nativeValue(paths));
                            context.setXLong(2, UnidbgPointer.nativeValue(mh));
                            context.setXLong(13, UnidbgPointer.nativeValue(mapped));
                            return list.size();
                        }
                        @Override
                        public void handlePostCallback(Emulator emulator) {
                            super.handlePostCallback(emulator);

                            if (block == null) {
                                throw new IllegalStateException();
                            }
                            for (MachOModule mm : list) {
                                mm.objcNotifyMapped = true;
                                mm.objcNotifyInit = objcNotifyInit;
                            }
                            list.clear();
                            block.free();
                            block = null;
                        }
                    }).peer;
                }
                return __dyld_objc_notify_register;
            }
            if ("_clock_gettime_nsec_np".equals(symbolName)) {
                if (_clock_gettime_nsec_np == 0) {
                    _clock_gettime_nsec_np = svcMemory.registerSvc(new Arm64Svc("clock_gettime_nsec_np") {
                        @Override
                        public long handle(Emulator emulator) {
                            RegisterContext context = emulator.getContext();
                            int clock_id = context.getIntArg(0);
                            switch (clock_id) {
                                case DarwinSyscall.CLOCK_MONOTONIC_RAW:
                                    return System.nanoTime() - DarwinSyscall.nanoTime;
                                case DarwinSyscall.CLOCK_MONOTONIC:
                                default:
                                    throw new UnsupportedOperationException("clock_id=" + clock_id);
                            }
                        }
                    }).peer;
                }
                return _clock_gettime_nsec_np;
            }
            if ("_os_unfair_recursive_lock_tryunlock4objc".equals(symbolName)) {
                if (_os_unfair_recursive_lock_tryunlock4objc == 0) {
                    _os_unfair_recursive_lock_tryunlock4objc = svcMemory.registerSvc(new Arm64Svc("os_unfair_recursive_lock_tryunlock4objc") {
                        @Override
                        public long handle(Emulator emulator) {
                            if (log.isDebugEnabled()) {
                                log.debug("os_unfair_recursive_lock_tryunlock4objc");
                            }
                            return 1;
                        }
                    }).peer;
                }
                return _os_unfair_recursive_lock_tryunlock4objc;
            }
            if ("_os_unfair_recursive_lock_lock_with_options".equals(symbolName)) {
                if (_os_unfair_recursive_lock_lock_with_options == 0) {
                    _os_unfair_recursive_lock_lock_with_options = svcMemory.registerSvc(new Arm64Svc("os_unfair_recursive_lock_lock_with_options") {
                        @Override
                        public long handle(Emulator emulator) {
                            if (log.isDebugEnabled()) {
                                log.debug("os_unfair_recursive_lock_lock_with_options");
                            }
                            return 0;
                        }
                    }).peer;
                }
                return _os_unfair_recursive_lock_lock_with_options;
            }
            if ("_os_unfair_recursive_lock_unlock".equals(symbolName)) {
                if (_os_unfair_recursive_lock_unlock == 0) {
                    _os_unfair_recursive_lock_unlock = svcMemory.registerSvc(new Arm64Svc("os_unfair_recursive_lock_unlock") {
                        @Override
                        public long handle(Emulator emulator) {
                            if (log.isDebugEnabled()) {
                                log.debug("os_unfair_recursive_lock_unlock");
                            }
                            return 0;
                        }
                    }).peer;
                }
                return _os_unfair_recursive_lock_unlock;
            }
            if ("__os_feature_enabled_simple_impl".equals(symbolName)) {
                if (__os_feature_enabled_simple_impl == 0) {
                    __os_feature_enabled_simple_impl = svcMemory.registerSvc(new Arm64Svc("os_feature_enabled_simple_impl") {
                        @Override
                        public long handle(Emulator emulator) {
                            RegisterContext context = emulator.getContext();
                            Pointer domain = context.getPointerArg(0);
                            Pointer feature = context.getPointerArg(1);
                            int status = context.getIntArg(2);
                            if (log.isDebugEnabled()) {
                                log.debug("__os_feature_enabled_simple_impl domain=" + domain.getString(0) + ", feature=" + feature.getString(0) + ", status=" + status);
                            }
                            return 0;
                        }
                    }).peer;
                }
                return __os_feature_enabled_simple_impl;
            }
        }
        if ("libsystem_c.dylib".equals(libraryName)) {
            if ("_abort".equals(symbolName)) {
                if (_abort == 0) {
                    _abort = svcMemory.registerSvc(new Arm64Svc("abort") {
                        @Override
                        public long handle(Emulator emulator) {
                            System.err.println("abort");
                            emulator.attach().debug();
                            emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_LR, emulator.getReturnAddress());
                            return 0;
                        }
                    }).peer;
                }
                return _abort;
            }
        } else if ("libsystem_asl.dylib".equals(libraryName)) {
            if ("_asl_open".equals(symbolName)) {
                if (_asl_open == 0) {
                    _asl_open = svcMemory.registerSvc(new Arm64Hook() {
                        @Override
                        protected HookStatus hook(Emulator emulator) {
                            EditableArm64RegisterContext context = emulator.getContext();
                            Pointer ident = context.getPointerArg(0);
                            Pointer facility = context.getPointerArg(1);
                            int opts = context.getIntArg(2);
                            if (log.isDebugEnabled()) {
                                log.debug("_asl_open ident=" + (ident == null ? null : ident.getString(0)) + ", facility=" + facility.getString(0) + ", opts=0x" + Integer.toHexString(opts));
                            }
                            context.setXLong(2, opts | ASL_OPT_STDERR);
                            return HookStatus.RET(emulator, old);
                        }
                    }).peer;
                }
                return _asl_open;
            }
        }
        return 0;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy