From 62889e02c21fa7117745342cf863d0597d3dedf8 Mon Sep 17 00:00:00 2001 From: Sh4w <36655200+sledgeh4w@users.noreply.github.com> Date: Thu, 23 May 2024 00:09:03 +0800 Subject: [PATCH] Execute libmacho.dylib directly instead of hooking (#78) --- src/chomper/base.py | 9 ++++--- src/chomper/os/ios/const.py | 1 + src/chomper/os/ios/hooks.py | 50 +++++++++++------------------------ src/chomper/os/ios/loader.py | 1 - src/chomper/os/ios/os.py | 29 +++++++------------- src/chomper/os/ios/syscall.py | 16 ++++++++--- 6 files changed, 43 insertions(+), 63 deletions(-) diff --git a/src/chomper/base.py b/src/chomper/base.py index 371cdf5..876b2e8 100644 --- a/src/chomper/base.py +++ b/src/chomper/base.py @@ -64,11 +64,12 @@ def add_symbol_hooks(self, symbols: List[Symbol], trace_symbol_calls: bool = Fal # Hook symbol if self.emu.hooks.get(symbol.name): - message = 'Hook export symbol "{}" at {}'.format( - symbol.name, - self.emu.debug_symbol(symbol.address), + self.emu.logger.info( + 'Hook export symbol "{}" at {}'.format( + symbol.name, + self.emu.debug_symbol(symbol.address), + ) ) - self.emu.logger.info(message) self.emu.add_interceptor(symbol.address, self.emu.hooks[symbol.name]) diff --git a/src/chomper/os/ios/const.py b/src/chomper/os/ios/const.py index 397353b..92a5c68 100644 --- a/src/chomper/os/ios/const.py +++ b/src/chomper/os/ios/const.py @@ -29,6 +29,7 @@ SYS_GETEGID = 0x2B SYS_GETTIMEOFDAY = 0x74 SYS_CSOPS = 0xA9 +SYS_RLIMIT = 0xC2 SYS_SYSCTL = 0xCA SYS_SHM_OPEN = 0x10A SYS_SYSCTLBYNAME = 0x112 diff --git a/src/chomper/os/ios/hooks.py b/src/chomper/os/ios/hooks.py index 4141bb9..0b5f6dc 100644 --- a/src/chomper/os/ios/hooks.py +++ b/src/chomper/os/ios/hooks.py @@ -7,8 +7,9 @@ from unicorn.unicorn import UC_HOOK_CODE_TYPE -from chomper.utils import pyobj2cfobj +from chomper.exceptions import SymbolMissingException from chomper.objc import ObjC +from chomper.utils import pyobj2cfobj hooks: Dict[str, UC_HOOK_CODE_TYPE] = {} @@ -323,47 +324,28 @@ def hook_posix_memalign(uc, address, size, user_data): return 0 -@register_hook("_getsectiondata") -def hook_getsectiondata(uc, address, size, user_data): - emu = user_data["emu"] - module = emu.modules[-1] - - section_name = emu.read_string(emu.get_arg(2)) - size_ptr = emu.get_arg(3) - - section = module.binary.get_section(section_name) - if not section: - return 0 +@register_hook("__os_activity_initiate") +def hook_os_activity_initiate(uc, address, size, user_data): + return 0 - emu.write_u64(size_ptr, section.size) - return module.base - module.image_base + section.virtual_address +@register_hook("_notify_register_dispatch") +def hook_notify_register_dispatch(uc, address, size, user_data): + return 0 -@register_hook("_getsegmentdata") -def hook_getsegmentdata(uc, address, size, user_data): +@register_hook("_dlsym") +def hook_dlsym(uc, address, size, user_data): emu = user_data["emu"] - module = emu.modules[-1] - segment_name = emu.read_string(emu.get_arg(1)) - size_ptr = emu.get_arg(2) + symbol_name = f"_{emu.read_string(emu.get_arg(1))}" - segment = module.binary.get_segment(segment_name) - if not segment: - return 0 - - emu.write_u64(size_ptr, segment.virtual_size) - - return module.base - module.image_base + segment.virtual_address + try: + symbol = emu.find_symbol(symbol_name) + return symbol.address + except SymbolMissingException: + pass - -@register_hook("__os_activity_initiate") -def hook_os_activity_initiate(uc, address, size, user_data): - return 0 - - -@register_hook("_notify_register_dispatch") -def hook_notify_register_dispatch(uc, address, size, user_data): return 0 diff --git a/src/chomper/os/ios/loader.py b/src/chomper/os/ios/loader.py index d1d0da7..697d6e9 100644 --- a/src/chomper/os/ios/loader.py +++ b/src/chomper/os/ios/loader.py @@ -211,7 +211,6 @@ def _get_init_array(self, binary: lief.MachO.Binary, module_base: int): begin = module_base + section.virtual_address end = begin + section.size - values = self.emu.read_array(begin, end) return [addr for addr in values if addr] diff --git a/src/chomper/os/ios/os.py b/src/chomper/os/ios/os.py index 803fc33..cfa80a1 100644 --- a/src/chomper/os/ios/os.py +++ b/src/chomper/os/ios/os.py @@ -1,15 +1,12 @@ import os -from ctypes import sizeof from typing import List from chomper.base import BaseOs from chomper.types import Module -from chomper.utils import struct2bytes from chomper.os.ios import const from chomper.os.ios.fixup import SystemModuleFixup from chomper.os.ios.hooks import get_hooks from chomper.os.ios.loader import MachoLoader -from chomper.os.ios.structs import MachHeader64 from chomper.os.ios.syscall import get_syscall_handlers @@ -144,7 +141,10 @@ def init_objc(self, module: Module): Calling `map_images` and `load_images` of `libobjc.A.dylib`. """ - if not self.emu.find_module("libobjc.A.dylib") or not module.binary: + if not module.binary or not module.image_base: + return + + if not self.emu.find_module("libobjc.A.dylib"): return initialized = self.emu.find_symbol("__ZZ10_objc_initE11initialized") @@ -155,31 +155,19 @@ def init_objc(self, module: Module): self._init_dyld_vars() self._init_objc_vars() - mach_header = MachHeader64( - magic=module.binary.header.magic.value, - cputype=module.binary.header.cpu_type.value, - cpusubtype=module.binary.header.cpu_subtype, - filetype=module.binary.header.file_type.value, - ncmds=module.binary.header.nb_cmds, - sizeofcmds=module.binary.header.sizeof_cmds, - flags=module.binary.header.flags, - reserved=module.binary.header.reserved, - ) - - mach_header_ptr = self.emu.create_buffer(sizeof(MachHeader64)) - self.emu.write_bytes(mach_header_ptr, struct2bytes(mach_header)) + text_segment = module.binary.get_segment("__TEXT") + mach_header_ptr = module.base - module.image_base + text_segment.virtual_address mach_header_ptrs = self.emu.create_buffer(self.emu.arch.addr_size) + self.emu.write_pointer(mach_header_ptrs, mach_header_ptr) try: self.emu.call_symbol("_map_images", 1, 0, mach_header_ptrs) - self.emu.call_symbol("_load_images") - + self.emu.call_symbol("_load_images", 0, mach_header_ptr) except Exception as e: self.emu.logger.error("Initialize Objective-C failed.") self.emu.logger.exception(e) - finally: module.binary = None @@ -243,6 +231,7 @@ def _enable_objc(self): "libcommonCrypto.dylib", "libc++abi.dylib", "libc++.1.dylib", + "libmacho.dylib", "libdyld.dylib", "libobjc.A.dylib", "libdispatch.dylib", diff --git a/src/chomper/os/ios/syscall.py b/src/chomper/os/ios/syscall.py index 49d364a..e204268 100644 --- a/src/chomper/os/ios/syscall.py +++ b/src/chomper/os/ios/syscall.py @@ -89,6 +89,11 @@ def handle_sys_csops(emu): return 0 +@register_syscall_handler(const.SYS_RLIMIT) +def handle_sys_rlimit(emu): + return 0 + + @register_syscall_handler(const.SYS_SYSCTL) def handle_sys_sysctl(emu): return 0 @@ -139,12 +144,15 @@ def handle_sys_issetugid(emu): @register_syscall_handler(const.SYS_PROC_INFO) def handle_sys_proc_info(emu): + # pid = emu.get_arg(1) + flavor = emu.get_arg(2) buffer = emu.get_arg(4) - process_path = ( - "/private/var/containers/Bundle/Application/%s/App.app" % uuid.uuid4() - ) - emu.write_string(buffer, process_path) + if flavor == 11: + emu.write_string( + buffer, + "/private/var/containers/Bundle/Application/%s/App.app" % uuid.uuid4(), + ) clear_carry_flag(emu)