Skip to content

Commit

Permalink
Execute libmacho.dylib directly instead of hooking (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
sledgeh4w authored May 22, 2024
1 parent 073cdd9 commit 62889e0
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 63 deletions.
9 changes: 5 additions & 4 deletions src/chomper/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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])

Expand Down
1 change: 1 addition & 0 deletions src/chomper/os/ios/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 16 additions & 34 deletions src/chomper/os/ios/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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] = {}

Expand Down Expand Up @@ -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


Expand Down
1 change: 0 additions & 1 deletion src/chomper/os/ios/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
29 changes: 9 additions & 20 deletions src/chomper/os/ios/os.py
Original file line number Diff line number Diff line change
@@ -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


Expand Down Expand Up @@ -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")
Expand All @@ -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

Expand Down Expand Up @@ -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",
Expand Down
16 changes: 12 additions & 4 deletions src/chomper/os/ios/syscall.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down

0 comments on commit 62889e0

Please sign in to comment.