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

com.github.unidbg.ios.ipa.SymbolResolver Maven / Gradle / Ivy

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

import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.Symbol;
import com.github.unidbg.arm.Arm64Hook;
import com.github.unidbg.arm.Arm64Svc;
import com.github.unidbg.arm.ArmHook;
import com.github.unidbg.arm.ArmSvc;
import com.github.unidbg.arm.HookStatus;
import com.github.unidbg.arm.context.EditableArm32RegisterContext;
import com.github.unidbg.arm.context.EditableArm64RegisterContext;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.file.ios.DarwinFileIO;
import com.github.unidbg.hook.HookListener;
import com.github.unidbg.ios.struct.DispatchSourceType;
import com.github.unidbg.memory.MemoryBlock;
import com.github.unidbg.memory.SvcMemory;
import com.github.unidbg.pointer.UnidbgPointer;
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 java.util.Arrays;

public class SymbolResolver implements HookListener {

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

    private final Emulator emulator;
    private UnidbgPointer _os_unfair_lock_lock, _os_unfair_lock_unlock;
    private UnidbgPointer _objc_readClassPair;
    private UnidbgPointer _objc_unsafeClaimAutoreleasedReturnValue;
    private UnidbgPointer __tlv_bootstrap;

    private UnidbgPointer __dispatch_source_type_memorypressure;
    private UnidbgPointer dispatch_source_type_memorypressure_init;
    private UnidbgPointer dispatch_queue_attr_make_with_qos_class;
    private UnidbgPointer dispatch_queue_attr_make_with_autorelease_frequency;
    private UnidbgPointer dispatch_queue_attr_make_initially_inactive;
    private UnidbgPointer ___chkstk_darwin;
    private UnidbgPointer _clock_gettime;
    private UnidbgPointer _pthread_attr_set_qos_class_np;
    private UnidbgPointer _pthread_set_qos_class_self_np;
    private UnidbgPointer _qos_class_self;
    private UnidbgPointer _dispatch_assert_queue$V2;
    private UnidbgPointer _dispatch_assert_queue_not$V2;
    private UnidbgPointer _dispatch_block_create;
    private UnidbgPointer _dispatch_get_global_queue;
    private UnidbgPointer _dispatch_group_async;

    public SymbolResolver(Emulator emulator) {
        this.emulator = emulator;
    }

    private final long nanoTime = System.nanoTime();

    private static final int CLOCK_REALTIME = 0;
    private static final int CLOCK_MONOTONIC_RAW = 4;
    private static final int CLOCK_MONOTONIC = 6;

    private long old_dispatch_sync;

    @Override
    public long hook(final SvcMemory svcMemory, String libraryName, String symbolName, final long old) {
        /*if (symbolName.contains("dispatch_block_create")) {
            System.out.println("libraryName=" + libraryName + ", symbolName=" + symbolName + ", old=0x" + Long.toHexString(old));
        }*/
        if ("_dispatch_sync".equals(symbolName) && "libdispatch.dylib".equals(libraryName)) {
            old_dispatch_sync = old;
        }
        if ("_dispatch_group_async".equals(symbolName)) {
            if (_dispatch_group_async == null) {
                if (old_dispatch_sync == 0L) {
                    Module dispatch = emulator.getMemory().findModule("libdispatch.dylib");
                    Symbol symbol = dispatch.findSymbolByName("_dispatch_sync", false);
                    old_dispatch_sync = symbol.getAddress();
                }
                if (emulator.is64Bit()) {
                    _dispatch_group_async = svcMemory.registerSvc(new Arm64Hook() {
                        @Override
                        protected HookStatus hook(Emulator emulator) {
                            EditableArm64RegisterContext context = emulator.getContext();
                            Pointer group = context.getPointerArg(0);
                            UnidbgPointer queue = context.getPointerArg(1);
                            UnidbgPointer block = context.getPointerArg(2);
                            log.info("Patch dispatch_group_async to dispatch_sync group=" + group + ", queue=" + queue + ", block=" + block + ", LR=" + context.getLRPointer());
                            context.setXLong(0, queue == null ? 0 : queue.peer);
                            context.setXLong(1, block == null ? 0 : block.peer);
                            return HookStatus.RET(emulator, old_dispatch_sync);
                        }
                    });
                } else {
                    _dispatch_group_async = svcMemory.registerSvc(new ArmHook() {
                        @Override
                        protected HookStatus hook(Emulator emulator) {
                            EditableArm32RegisterContext context = emulator.getContext();
                            Pointer group = context.getPointerArg(0);
                            UnidbgPointer queue = context.getPointerArg(1);
                            UnidbgPointer block = context.getPointerArg(2);
                            log.info("Patch dispatch_group_async to dispatch_sync group=" + group + ", queue=" + queue + ", block=" + block + ", LR=" + context.getLRPointer());
                            context.setR0(queue == null ? 0 : queue.toIntPeer());
                            context.setR1(block == null ? 0 : block.toIntPeer());
                            return HookStatus.RET(emulator, old_dispatch_sync);
                        }
                    });
                }
            }
            return _dispatch_group_async.peer;
        }
        if ("_dispatch_get_global_queue".equals(symbolName)) {
            if (_dispatch_get_global_queue == null) {
                if (emulator.is64Bit()) {
                    _dispatch_get_global_queue = svcMemory.registerSvc(new Arm64Hook() {
                        @Override
                        protected HookStatus hook(Emulator emulator) {
                            EditableArm64RegisterContext context = emulator.getContext();
                            int identifier = context.getIntArg(0);
                            int flags = context.getIntArg(1);
                            if (log.isDebugEnabled()) {
                                log.debug("dispatch_get_global_queue identifier=0x" + Integer.toHexString(identifier) + ", flags=0x" + Integer.toHexString(flags));
                            }
                            int QOS_CLASS_USER_INTERACTIVE = 0x21;
                            int QOS_CLASS_USER_INITIATED = 0x19;
                            int QOS_CLASS_DEFAULT = 0x15;
                            int QOS_CLASS_UTILITY = 0x11;
                            int QOS_CLASS_BACKGROUND = 0x9;
                            int DISPATCH_QUEUE_PRIORITY_DEFAULT = 0x0;
                            if (identifier == QOS_CLASS_BACKGROUND ||
                                    identifier == QOS_CLASS_DEFAULT ||
                                    identifier == QOS_CLASS_USER_INITIATED ||
                                    identifier == QOS_CLASS_UTILITY ||
                                    identifier == QOS_CLASS_USER_INTERACTIVE) {
                                context.setXLong(0, DISPATCH_QUEUE_PRIORITY_DEFAULT);
                            }
                            return HookStatus.RET(emulator, old);
                        }
                    });
                } else {
                    _dispatch_get_global_queue = svcMemory.registerSvc(new ArmHook() {
                        @Override
                        protected HookStatus hook(Emulator emulator) {
                            EditableArm32RegisterContext context = emulator.getContext();
                            int identifier = context.getIntArg(0);
                            int flags = context.getIntArg(1);
                            if (log.isDebugEnabled()) {
                                log.debug("dispatch_get_global_queue identifier=0x" + Integer.toHexString(identifier) + ", flags=0x" + Integer.toHexString(flags));
                            }
                            int QOS_CLASS_USER_INTERACTIVE = 0x21;
                            int QOS_CLASS_USER_INITIATED = 0x19;
                            int QOS_CLASS_DEFAULT = 0x15;
                            int QOS_CLASS_UTILITY = 0x11;
                            int QOS_CLASS_BACKGROUND = 0x9;
                            int DISPATCH_QUEUE_PRIORITY_DEFAULT = 0x0;
                            if (identifier == QOS_CLASS_BACKGROUND ||
                                    identifier == QOS_CLASS_DEFAULT ||
                                    identifier == QOS_CLASS_USER_INITIATED ||
                                    identifier == QOS_CLASS_UTILITY ||
                                    identifier == QOS_CLASS_USER_INTERACTIVE) {
                                context.setR0(DISPATCH_QUEUE_PRIORITY_DEFAULT);
                            }
                            return HookStatus.RET(emulator, old);
                        }
                    });
                }
            }
            return _dispatch_get_global_queue.peer;
        }
        if ("_dispatch_block_create".equals(symbolName) && emulator.is64Bit()) {
            if (_dispatch_block_create == null) {
                _dispatch_block_create = svcMemory.registerSvc(new Arm64Svc("dispatch_block_create") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        int flags = context.getIntArg(0);
                        UnidbgPointer block = context.getPointerArg(1);
                        log.info("_dispatch_block_create flags=0x" + Integer.toHexString(flags) + ", block=" + block);
                        return block == null ? 0 : block.peer;
                    }
                });
            }
            return _dispatch_block_create.peer;
        }
        if ("_dispatch_assert_queue$V2".equals(symbolName) && emulator.is64Bit()) {
            if (_dispatch_assert_queue$V2 == null) {
                _dispatch_assert_queue$V2 = svcMemory.registerSvc(new Arm64Svc("dispatch_assert_queue$V2") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        log.info("_dispatch_assert_queue$V2 queue=" + context.getPointerArg(0));
                        return 0;
                    }
                });
            }
            return _dispatch_assert_queue$V2.peer;
        }
        if ("_dispatch_assert_queue_not$V2".equals(symbolName)) {
            if (_dispatch_assert_queue_not$V2 == null) {
                _dispatch_assert_queue_not$V2 = svcMemory.registerSvc(new Arm64Svc("dispatch_assert_queue_not$V2") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        log.info("_dispatch_assert_queue_not$V2 queue=" + context.getPointerArg(0));
                        return 0;
                    }
                });
            }
            return _dispatch_assert_queue_not$V2.peer;
        }
        if ("_qos_class_self".equals(symbolName) && emulator.is64Bit()) {
            if (_qos_class_self == null) {
                _qos_class_self = svcMemory.registerSvc(new Arm64Svc("qos_class_self") {
                    @Override
                    public long handle(Emulator emulator) {
                        log.info("_qos_class_self");
                        return 0;
                    }
                });
            }
            return _qos_class_self.peer;
        }
        if ("_pthread_set_qos_class_self_np".equals(symbolName) && emulator.is64Bit()) {
            if (_pthread_set_qos_class_self_np == null) {
                _pthread_set_qos_class_self_np = svcMemory.registerSvc(new Arm64Svc("pthread_set_qos_class_self_np") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        int __qos_class = context.getIntArg(0);
                        int __relative_priority = context.getIntArg(1);
                        if (log.isDebugEnabled()) {
                            log.debug("_pthread_set_qos_class_self_np __qos_class=" + __qos_class + ", __relative_priority=" + __relative_priority);
                        }
                        return 0;
                    }
                });
            }
            return _pthread_set_qos_class_self_np.peer;
        }
        if ("_pthread_attr_set_qos_class_np".equals(symbolName) && emulator.is64Bit()) {
            if (_pthread_attr_set_qos_class_np == null) {
                _pthread_attr_set_qos_class_np = svcMemory.registerSvc(new Arm64Svc("pthread_attr_set_qos_class_np") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        Pointer __attr = context.getPointerArg(0);
                        int __qos_class = context.getIntArg(1);
                        int __relative_priority = context.getIntArg(2);
                        if (log.isDebugEnabled()) {
                            log.debug("_pthread_attr_set_qos_class_np __attr=" + __attr + ", __qos_class=" + __qos_class + ", __relative_priority=" + __relative_priority);
                        }
                        return 0;
                    }
                });
            }
            return _pthread_attr_set_qos_class_np.peer;
        }
        if ("_clock_gettime".equals(symbolName) && emulator.is64Bit()) {
            if (_clock_gettime == null) {
                _clock_gettime = svcMemory.registerSvc(new Arm64Svc("clock_gettime") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        int clk_id = context.getIntArg(0);
                        Pointer tp = context.getPointerArg(1);
                        long offset = clk_id == CLOCK_REALTIME ? System.currentTimeMillis() * 1000000L : System.nanoTime() - nanoTime;
                        long tv_sec = offset / 1000000000L;
                        long tv_nsec = offset % 1000000000L;
                        if (log.isDebugEnabled()) {
                            log.debug("clock_gettime clk_id=" + clk_id + ", tp=" + tp + ", offset=" + offset + ", tv_sec=" + tv_sec + ", tv_nsec=" + tv_nsec);
                        }
                        switch (clk_id) {
                            case CLOCK_REALTIME:
                            case CLOCK_MONOTONIC:
                            case CLOCK_MONOTONIC_RAW:
                                tp.setLong(0, tv_sec);
                                tp.setLong(8, tv_nsec);
                                return 0;
                        }
                        throw new UnsupportedOperationException("clk_id=" + clk_id);
                    }
                });
            }
            return _clock_gettime.peer;
        }
        if ("___chkstk_darwin".equals(symbolName) && emulator.is64Bit()) {
            if (___chkstk_darwin == null) {
                ___chkstk_darwin = svcMemory.registerSvc(new Arm64Svc("chkstk_darwin") {
                    @Override
                    public long handle(Emulator emulator) {
                        return emulator.getContext().getLongArg(0);
                    }
                });
            }
            return ___chkstk_darwin.peer;
        }
        if ("_dispatch_queue_attr_make_with_qos_class".equals(symbolName) && emulator.is64Bit()) {
            if (dispatch_queue_attr_make_with_qos_class == null) {
                dispatch_queue_attr_make_with_qos_class = svcMemory.registerSvc(new Arm64Svc("dispatch_queue_attr_make_with_qos_class") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        UnidbgPointer attr = context.getPointerArg(0);
//                        System.out.println("dispatch_queue_attr_make_with_qos_class attr=" + attr);
                        return attr == null ? 0 : attr.peer;
                    }
                });
            }
            return dispatch_queue_attr_make_with_qos_class.peer;
        }
        if ("_dispatch_queue_attr_make_with_autorelease_frequency".equals(symbolName) && emulator.is64Bit()) {
            if (dispatch_queue_attr_make_with_autorelease_frequency == null) {
                dispatch_queue_attr_make_with_autorelease_frequency = svcMemory.registerSvc(new Arm64Svc("dispatch_queue_attr_make_with_autorelease_frequency") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        UnidbgPointer attr = context.getPointerArg(0);
                        return attr == null ? 0 : attr.peer;
                    }
                });
            }
            return dispatch_queue_attr_make_with_autorelease_frequency.peer;
        }
        if ("_dispatch_queue_attr_make_initially_inactive".equals(symbolName) && emulator.is64Bit()) {
            if (dispatch_queue_attr_make_initially_inactive == null) {
                dispatch_queue_attr_make_initially_inactive = svcMemory.registerSvc(new Arm64Svc("dispatch_queue_attr_make_initially_inactive") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        UnidbgPointer attr = context.getPointerArg(0);
//                        System.out.println("dispatch_queue_attr_make_initially_inactive attr=" + attr);
                        return attr == null ? 0 : attr.peer;
                    }
                });
            }
            return dispatch_queue_attr_make_initially_inactive.peer;
        }
        if ("__dispatch_source_type_memorypressure".equals(symbolName) && emulator.is64Bit()) {
            if (dispatch_source_type_memorypressure_init == null) {
                dispatch_source_type_memorypressure_init = svcMemory.registerSvc(new Arm64Svc("dispatch_source_type_memorypressure") {
                    @Override
                    public long handle(Emulator emulator) {
                        System.out.println("dispatch_source_type_memorypressure_init");
                        return 0;
                    }
                });
            }
            if (__dispatch_source_type_memorypressure == null) {
                final short EVFILT_MEMORYSTATUS = (-14); /* Memorystatus events */
                final short EV_DISPATCH = 0x0080; /* disable event after reporting */
                final int NOTE_MEMORYSTATUS_PRESSURE_NORMAL = 0x00000001; /* system memory pressure has returned to normal */
                final int NOTE_MEMORYSTATUS_PRESSURE_WARN = 0x00000002; /* system memory pressure has changed to the warning state */
                final int NOTE_MEMORYSTATUS_PRESSURE_CRITICAL = 0x00000004; /* system memory pressure has changed to the critical state */
                __dispatch_source_type_memorypressure = svcMemory.allocate(128, "__dispatch_source_type_memorypressure");
                DispatchSourceType dispatchSourceType = new DispatchSourceType(__dispatch_source_type_memorypressure);
                dispatchSourceType.ke.filter = EVFILT_MEMORYSTATUS;
                dispatchSourceType.ke.flags = EV_DISPATCH;
                dispatchSourceType.mask = NOTE_MEMORYSTATUS_PRESSURE_NORMAL | NOTE_MEMORYSTATUS_PRESSURE_WARN | NOTE_MEMORYSTATUS_PRESSURE_CRITICAL;
                dispatchSourceType.init = dispatch_source_type_memorypressure_init.peer;
                dispatchSourceType.pack();
            }
            return __dispatch_source_type_memorypressure.peer;
        }
        if ("_objc_unsafeClaimAutoreleasedReturnValue".equals(symbolName)) {
            if (_objc_unsafeClaimAutoreleasedReturnValue == null) {
                _objc_unsafeClaimAutoreleasedReturnValue = svcMemory.registerSvc(emulator.is64Bit() ? new Arm64Svc("objc_unsafeClaimAutoreleasedReturnValue") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        return context.getLongArg(0);
                    }
                } : new ArmSvc() {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        return context.getIntArg(0);
                    }
                });
            }
            return _objc_unsafeClaimAutoreleasedReturnValue.peer;
        }
        if ("_os_unfair_lock_lock".equals(symbolName)) {
            if (_os_unfair_lock_lock == null) {
                _os_unfair_lock_lock = svcMemory.registerSvc(emulator.is64Bit() ? new Arm64Svc("os_unfair_lock_lock") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                } : new ArmSvc() {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                });
            }
            return _os_unfair_lock_lock.peer;
        }
        if ("_os_unfair_lock_unlock".equals(symbolName)) {
            if (_os_unfair_lock_unlock == null) {
                _os_unfair_lock_unlock = svcMemory.registerSvc(emulator.is64Bit() ? new Arm64Svc("os_unfair_lock_unlock") {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                } : new ArmSvc() {
                    @Override
                    public long handle(Emulator emulator) {
                        return 0;
                    }
                });
            }
            return _os_unfair_lock_unlock.peer;
        }
        if ("__tlv_bootstrap".equals(symbolName)) {
            if (__tlv_bootstrap == null) {
                __tlv_bootstrap = svcMemory.registerSvc(emulator.is64Bit() ? new Arm64Svc("tlv_bootstrap") {
                    @Override
                    public long handle(Emulator emulator) {
                        RegisterContext context = emulator.getContext();
                        UnidbgPointer self = context.getPointerArg(0);
                        UnidbgPointer var = self.getPointer(8);
                        if (var == null) {
                            long size = self.getLong(16);
                            MemoryBlock block = emulator.getMemory().malloc((int) size, true);
                            var = block.getPointer();
                            self.setPointer(8, var);
                        }
                        return var.peer;
                    }
                } : new ArmSvc() {
                    @Override
                    public long handle(Emulator emulator) {
                        throw new UnsupportedOperationException();
                    }
                });
            }
            return __tlv_bootstrap.peer;
        }
        if ("_objc_readClassPair".equals(symbolName)) {
            if (_objc_readClassPair == null) {
                _objc_readClassPair = svcMemory.registerSvc(emulator.is64Bit() ? new Arm64Svc("objc_readClassPair") {
                    @Override
                    public long handle(Emulator emulator) {
                        throw new UnsupportedOperationException();
                    }
                    @Override
                    public UnidbgPointer onRegister(SvcMemory svcMemory, int svcNumber) {
                        try (Keystone keystone = new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian)) {
                            KeystoneEncoded encoded = keystone.assemble(Arrays.asList(
                                    "nop",
                                    "ret"));
                            byte[] code = encoded.getMachineCode();
                            UnidbgPointer pointer = svcMemory.allocate(code.length, "objc_readClassPair");
                            pointer.write(0, code, 0, code.length);
                            return pointer;
                        }
                    }
                } : new ArmSvc() {
                    @Override
                    public long handle(Emulator emulator) {
                        throw new UnsupportedOperationException();
                    }
                    @Override
                    public UnidbgPointer onRegister(SvcMemory svcMemory, int svcNumber) {
                        try (Keystone keystone = new Keystone(KeystoneArchitecture.Arm, KeystoneMode.Arm)) {
                            KeystoneEncoded encoded = keystone.assemble(Arrays.asList(
                                    "nop",
                                    "bx lr"));
                            byte[] code = encoded.getMachineCode();
                            UnidbgPointer pointer = svcMemory.allocate(code.length, "objc_readClassPair");
                            pointer.write(0, code, 0, code.length);
                            return pointer;
                        }
                    }
                });
            }
            return old == WEAK_BIND ? _objc_readClassPair.peer : 0;
        }
        return 0;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy