diff --git a/README.md b/README.md index ae8c04b..08166d3 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,10 @@ This is an educational project to learn more about the ELF file format and [Unic - Emulation of the [JNI Invocation API](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html) so `JNI_OnLoad` can be called properly. - Emulation of native memory for malloc / memcpy. +- Emulation of syscalls (SVC #0) instruction. - Hooking through the symbol table. - All JavaVM, JNIEnv and hooked functions are handled by python. +- Enable VFP support. > The first two are still being worked on, please contribute if you can! :) @@ -30,3 +32,4 @@ All resources used while developing AndroidNativeEmu. ### Code sources - https://github.com/lunixbochs/usercorn +- https://github.com/slick1015/pad_unpacker (SVC 0 instruction) diff --git a/androidemu/config.py b/androidemu/config.py index 9318aba..f23d3ce 100644 --- a/androidemu/config.py +++ b/androidemu/config.py @@ -5,6 +5,6 @@ MEMORY_SIZE = 0x0200000 # 2 * 1024 * 1024 - 2MB MEMORY_DYN_BASE = 0x2000000 -MEMORY_DYN_SIZE = 0x0200000 # 2 * 1024 * 1024 - 2MB +MEMORY_DYN_SIZE = 0x0200000 # 2 * 1024 * 1024 - 2MB BASE_ADDR = 0xCBBCB000 diff --git a/androidemu/const/__init__.py b/androidemu/const/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/androidemu/const/android.py b/androidemu/const/android.py new file mode 100644 index 0000000..03eb0a6 --- /dev/null +++ b/androidemu/const/android.py @@ -0,0 +1 @@ +PR_SET_VMA = 0x53564d41 diff --git a/androidemu/const/linux.py b/androidemu/const/linux.py new file mode 100644 index 0000000..f6ab697 --- /dev/null +++ b/androidemu/const/linux.py @@ -0,0 +1,10 @@ +CLOCK_REALTIME = 0 +CLOCK_MONOTONIC = 1 +CLOCK_PROCESS_CPUTIME_ID = 2 +CLOCK_THREAD_CPUTIME_ID = 3 +CLOCK_MONOTONIC_RAW = 4 +CLOCK_REALTIME_COARSE = 5 +CLOCK_MONOTONIC_COARSE = 6 +CLOCK_BOOTTIME = 7 +CLOCK_REALTIME_ALARM = 8 +CLOCK_BOOTTIME_ALARM = 9 diff --git a/androidemu/cpu/__init__.py b/androidemu/cpu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/androidemu/cpu/interrupt_handler.py b/androidemu/cpu/interrupt_handler.py new file mode 100644 index 0000000..2b707cf --- /dev/null +++ b/androidemu/cpu/interrupt_handler.py @@ -0,0 +1,27 @@ +import logging + +from unicorn import * +from unicorn.arm_const import * + +logger = logging.getLogger(__name__) + + +class InterruptHandler: + + """ + :type mu Uc + """ + def __init__(self, mu): + self._mu = mu + self._mu.hook_add(UC_HOOK_INTR, self._hook_interrupt) + self._handlers = dict() + + def _hook_interrupt(self, uc, intno, data): + if intno in self._handlers: + self._handlers[intno](uc) + else: + logger.error("Unhandled interrupt %d at %x, stopping emulation" % (intno, self._mu.reg_read(UC_ARM_REG_PC))) + self._mu.emu_stop() + + def set_handler(self, intno, handler): + self._handlers[intno] = handler diff --git a/androidemu/cpu/syscall_handler.py b/androidemu/cpu/syscall_handler.py new file mode 100644 index 0000000..db938ad --- /dev/null +++ b/androidemu/cpu/syscall_handler.py @@ -0,0 +1,7 @@ +class SyscallHandler: + + def __init__(self, idx, name, arg_count, callback): + self.idx = idx + self.name = name + self.arg_count = arg_count + self.callback = callback diff --git a/androidemu/cpu/syscall_handlers.py b/androidemu/cpu/syscall_handlers.py new file mode 100644 index 0000000..c6886f4 --- /dev/null +++ b/androidemu/cpu/syscall_handlers.py @@ -0,0 +1,46 @@ +import logging + +from unicorn import * +from unicorn.arm_const import * + +from androidemu.cpu.interrupt_handler import InterruptHandler +from androidemu.cpu.syscall_handler import SyscallHandler +from androidemu.utils import memory_helpers + +logger = logging.getLogger(__name__) + + +class SyscallHandlers: + + """ + :type interrupt_handler InterruptHandler + """ + def __init__(self, interrupt_handler): + self._handlers = dict() + interrupt_handler.set_handler(2, self._handle_syscall) + + def set_handler(self, idx, name, arg_count, callback): + self._handlers[idx] = SyscallHandler(idx, name, arg_count, callback) + + def _handle_syscall(self, mu): + idx = mu.reg_read(UC_ARM_REG_R7) + args = [mu.reg_read(reg_idx) for reg_idx in range(UC_ARM_REG_R0, UC_ARM_REG_R6 + 1)] + + if idx in self._handlers: + handler = self._handlers[idx] + args = args[:handler.arg_count] + args_formatted = ", ".join(["%08x" % arg for arg in args]) + logger.info("Executing syscall %s(%s)" % (handler.name, args_formatted)) + + try: + result = handler.callback(mu, *args) + except: + logger.error("An error occured during in %x syscall hander, stopping emulation" % idx) + mu.emu_stop() + raise + + if result is not None: + mu.reg_write(UC_ARM_REG_R0, result) + else: + logger.error("Unhandled syscall 0x%x at 0x%x, stopping emulation" % (idx, mu.reg_read(UC_ARM_REG_PC))) + mu.emu_stop() diff --git a/androidemu/cpu/syscall_hooks.py b/androidemu/cpu/syscall_hooks.py new file mode 100644 index 0000000..ced4b71 --- /dev/null +++ b/androidemu/cpu/syscall_hooks.py @@ -0,0 +1,54 @@ +from unicorn import Uc + +from androidemu.const.android import PR_SET_VMA +from androidemu.const.linux import CLOCK_MONOTONIC_COARSE +from androidemu.cpu.syscall_handlers import SyscallHandlers +from androidemu.utils import memory_helpers + + +class SyscallHooks: + + """ + :type mu Uc + :type syscall_handler SyscallHandlers + """ + def __init__(self, mu, syscall_handler): + self._mu = mu + self._syscall_handler = syscall_handler + self._syscall_handler.set_handler(0xAC, "prctl", 5, self._handle_prctl) + self._syscall_handler.set_handler(0x107, "clock_gettime", 2, self._handle_clock_gettime) + + def _handle_prctl(self, mu, option, arg2, arg3, arg4, arg5): + """ + int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); + See: + - https://linux.die.net/man/2/prctl + - https://github.com/torvalds/linux/blob/master/include/uapi/linux/prctl.h + + For PR_SET_VMA: + - https://android.googlesource.com/platform/bionic/+/263325d/libc/include/sys/prctl.h + - https://sourceforge.net/p/strace/mailman/message/34329772/ + """ + + if option == PR_SET_VMA: + # arg5 contains ptr to a name. + return 0 + else: + raise NotImplementedError("Unsupported prctl option %d (0x%x)" % (option, option)) + + def _handle_clock_gettime(self, mu, clk_id, tp_ptr): + """ + The functions clock_gettime() retrieve the time of the specified clock clk_id. + + The clk_id argument is the identifier of the particular clock on which to act. A clock may be system-wide and + hence visible for all processes, or per-process if it measures time only within a single process. + + clock_gettime(), clock_settime() and clock_getres() return 0 for success, or -1 for failure (in which case + errno is set appropriately). + """ + + if clk_id == CLOCK_MONOTONIC_COARSE: + # TODO: Actually write time. + return 0 + else: + raise NotImplementedError("Unsupported clk_id: %d (%x)" % (clk_id, clk_id)) diff --git a/androidemu/emulator.py b/androidemu/emulator.py index b43fc78..705fa5e 100644 --- a/androidemu/emulator.py +++ b/androidemu/emulator.py @@ -2,12 +2,16 @@ from unicorn.arm_const import UC_ARM_REG_SP from androidemu import config +from androidemu.cpu.interrupt_handler import InterruptHandler +from androidemu.cpu.syscall_handlers import SyscallHandlers +from androidemu.cpu.syscall_hooks import SyscallHooks from androidemu.hooker import Hooker from androidemu.internal.memory import Memory from androidemu.internal.modules import Modules from androidemu.java.java_vm import JavaVM from androidemu.native.hooks import NativeHooks from androidemu.native.memory import NativeMemory +from androidemu.vfs.file_system import VirtualFileSystem class Emulator: @@ -17,10 +21,13 @@ class Emulator: :type modules Modules :type memory Memory """ - def __init__(self): + def __init__(self, vfs_root=None, vfp_inst_set=False): # Unicorn. self.mu = Uc(UC_ARCH_ARM, UC_MODE_ARM) + if vfp_inst_set: + self._enable_vfp() + # Stack. self.mu.mem_map(config.STACK_ADDR, config.STACK_SIZE) self.mu.reg_write(UC_ARM_REG_SP, config.STACK_ADDR + config.STACK_SIZE) @@ -29,6 +36,17 @@ def __init__(self): self.modules = Modules(self) self.memory = Memory(self) + # CPU + self.interrupt_handler = InterruptHandler(self.mu) + self.syscall_handler = SyscallHandlers(self.interrupt_handler) + self.syscall_hooks = SyscallHooks(self.mu, self.syscall_handler) + + # File System + if vfs_root is not None: + self.vfs = VirtualFileSystem(vfs_root, self.syscall_handler) + else: + self.vfs = None + # Hooker self.mu.mem_map(config.MEMORY_BASE, config.MEMORY_SIZE) self.hooker = Hooker(self.mu, config.MEMORY_BASE, config.MEMORY_SIZE) @@ -37,8 +55,40 @@ def __init__(self): self.java_vm = JavaVM(self.hooker) # Native - self.native_memory = NativeMemory(config.MEMORY_BASE, config.MEMORY_SIZE) + self.native_memory = NativeMemory(self.mu, config.MEMORY_DYN_BASE, config.MEMORY_DYN_SIZE, self.syscall_handler) self.native_hooks = NativeHooks(self.native_memory, self.modules, self.hooker) + # https://github.com/unicorn-engine/unicorn/blob/8c6cbe3f3cabed57b23b721c29f937dd5baafc90/tests/regress/arm_fp_vfp_disabled.py#L15 + def _enable_vfp(self): + # MRC p15, #0, r1, c1, c0, #2 + # ORR r1, r1, #(0xf << 20) + # MCR p15, #0, r1, c1, c0, #2 + # MOV r1, #0 + # MCR p15, #0, r1, c7, c5, #4 + # MOV r0,#0x40000000 + # FMXR FPEXC, r0 + code = '11EE501F' + code += '41F47001' + code += '01EE501F' + code += '4FF00001' + code += '07EE951F' + code += '4FF08040' + code += 'E8EE100A' + # vpush {d8} + code += '2ded028b' + + address = 0x1000 + mem_size = 0x1000 + code_bytes = bytes.fromhex(code) + + try: + self.mu.mem_map(address, mem_size) + self.mu.mem_write(address, code_bytes) + self.mu.reg_write(UC_ARM_REG_SP, address + mem_size) + + self.mu.emu_start(address | 1, address + len(code_bytes)) + finally: + self.mu.mem_unmap(address, mem_size) + def load_library(self, filename): return self.modules.load_module(filename) diff --git a/androidemu/internal/memory.py b/androidemu/internal/memory.py index cb350b6..fac39a8 100644 --- a/androidemu/internal/memory.py +++ b/androidemu/internal/memory.py @@ -32,3 +32,5 @@ def mem_map(self, address, size, prot): def mem_write(self, address, data): self.emu.mu.mem_write(address, data) + + diff --git a/androidemu/java/jni_env.py b/androidemu/java/jni_env.py index 757e6b6..335ac18 100644 --- a/androidemu/java/jni_env.py +++ b/androidemu/java/jni_env.py @@ -260,11 +260,10 @@ def find_class(self, mu, env, name_ptr): """ Returns a class object from a fully-qualified name, or NULL if the class cannot be found. """ - - # TODO: Actually retrieve a class id from a class map. name = memory_helpers.read_utf8(mu, name_ptr) - logger.debug(name) - return 0xFF + logger.debug("JNIEnv->FindClass(%s) was called" % name) + # TODO: Actually retrieve a class id from a class map. + return 0xFA @native_method def from_reflected_method(self, mu, env): @@ -323,20 +322,34 @@ def pop_local_frame(self, mu, env): raise NotImplementedError() @native_method - def new_global_ref(self, mu, env): - raise NotImplementedError() + def new_global_ref(self, mu, env, obj): + """ + Creates a new global reference to the object referred to by the obj argument. The obj argument may be a + global or local reference. Global references must be explicitly disposed of by calling DeleteGlobalRef(). + """ + logger.debug("JNIEnv->NewGlobalRef(%d) was called" % obj) + # TODO: Implement + return obj + 1 @native_method def delete_global_ref(self, mu, env): raise NotImplementedError() @native_method - def delete_local_ref(self, mu, env): - raise NotImplementedError() + def delete_local_ref(self, mu, env, local_ref): + """ + Deletes the local reference pointed to by localRef. + """ + logger.debug("JNIEnv->DeleteLocalRef(%d) was called" % local_ref) + # TODO: Implement @native_method - def is_same_object(self, mu, env): - raise NotImplementedError() + def is_same_object(self, mu, env, ref1, ref2): + """ + Returns JNI_TRUE if ref1 and ref2 refer to the same Java object, or are both NULL; otherwise, returns JNI_FALSE. + """ + logger.debug("JNIEnv->IsSameObject(%d, %d) was called" % (ref1, ref2)) + return JNI_FALSE @native_method def new_local_ref(self, mu, env): @@ -371,8 +384,16 @@ def is_instance_of(self, mu, env): raise NotImplementedError() @native_method - def get_method_id(self, mu, env): - raise NotImplementedError() + def get_method_id(self, mu, env, clazz, name_ptr, sig_ptr): + """ + Returns the method ID for an instance (nonstatic) method of a class or interface. The method may be defined + in one of the clazz’s superclasses and inherited by clazz. The method is determined by its name and signature. + """ + name = memory_helpers.read_utf8(mu, name_ptr) + sig = memory_helpers.read_utf8(mu, sig_ptr) + logger.debug("JNIEnv->GetMethodId(%d, %s, %s) was called" % (clazz, name, sig)) + # TODO: Implement + return 0xFC @native_method def call_object_method(self, mu, env): @@ -615,8 +636,17 @@ def call_nonvirtual_void_method_a(self, mu, env): raise NotImplementedError() @native_method - def get_field_id(self, mu, env): - raise NotImplementedError() + def get_field_id(self, mu, env, clazz, name_ptr, sig_ptr): + """ + Returns the field ID for an instance (nonstatic) field of a class. The field is specified by its name and + signature. The Get<type>Field and Set<type>Field families of accessor functions use field IDs to retrieve + object fields. + """ + name = memory_helpers.read_utf8(mu, name_ptr) + sig = memory_helpers.read_utf8(mu, sig_ptr) + logger.debug("JNIEnv->GetFieldId(%d, %s, %s) was called" % (clazz, name, sig)) + # TODO: Implement + return 0xFD @native_method def get_object_field(self, mu, env): @@ -691,8 +721,15 @@ def set_double_field(self, mu, env): raise NotImplementedError() @native_method - def get_static_method_id(self, mu, env): - raise NotImplementedError() + def get_static_method_id(self, mu, env, clazz, name_ptr, sig_ptr): + """ + Returns the method ID for a static method of a class. The method is specified by its name and signature. + """ + name = memory_helpers.read_utf8(mu, name_ptr) + sig = memory_helpers.read_utf8(mu, sig_ptr) + logger.debug("JNIEnv->GetStaticMethodId(%d, %s, %s) was called" % (clazz, name, sig)) + # TODO: Implement + return 0xFB @native_method def call_static_object_method(self, mu, env): @@ -815,8 +852,17 @@ def call_static_void_method_a(self, mu, env): raise NotImplementedError() @native_method - def get_static_field_id(self, mu, env): - raise NotImplementedError() + def get_static_field_id(self, mu, env, clazz, name_ptr, sig_ptr): + """ + Returns the field ID for a static field of a class. The field is specified by its name and signature. The + GetStatic<type>Field and SetStatic<type>Field families of accessor functions use field IDs to retrieve static + fields. + """ + name = memory_helpers.read_utf8(mu, name_ptr) + sig = memory_helpers.read_utf8(mu, sig_ptr) + logger.debug("JNIEnv->GetStaticFieldId(%d, %s, %s) was called" % (clazz, name, sig)) + # TODO: Implement + return 0xFE @native_method def get_static_object_field(self, mu, env): @@ -1164,7 +1210,13 @@ def delete_weak_global_ref(self, mu, env): @native_method def exception_check(self, mu, env): - raise NotImplementedError() + """ + Returns JNI_TRUE when there is a pending exception; otherwise, returns JNI_FALSE. + """ + logger.debug("JNIEnv->ExceptionCheck() was called") + # TODO: Implement + + return JNI_FALSE @native_method def new_direct_byte_buffer(self, mu, env): diff --git a/androidemu/native/hooks.py b/androidemu/native/hooks.py index 37416be..87f3c31 100644 --- a/androidemu/native/hooks.py +++ b/androidemu/native/hooks.py @@ -18,17 +18,5 @@ class NativeHooks: def __init__(self, memory, modules, hooker): self._memory = memory - modules.add_symbol_hook('malloc', hooker.write_function(self.malloc) + 1) - modules.add_symbol_hook('memcpy', hooker.write_function(self.memcpy) + 1) - - @native_method - def malloc(self, mu, size): - # TODO: Actually reserve memory with checks. - logger.warning("Application requested %d bytes." % size) - return 0x10 - - @native_method - def memcpy(self, mu, dst, src, count): - # TODO: Actually copy memory with checks. - logger.warning("Application copies %d bytes from 0x%x to 0x%x." % (count, src, dst)) - return 0x10 + # modules.add_symbol_hook('malloc', hooker.write_function(self.malloc) + 1) + # modules.add_symbol_hook('memcpy', hooker.write_function(self.memcpy) + 1) diff --git a/androidemu/native/memory.py b/androidemu/native/memory.py index 35d901b..1d7636a 100644 --- a/androidemu/native/memory.py +++ b/androidemu/native/memory.py @@ -1,5 +1,44 @@ +from unicorn import Uc +from androidemu.cpu.syscall_handlers import SyscallHandlers + + class NativeMemory: - def __init__(self, memory_base, memory_size): + """ + :type mu Uc + :type syscall_handler SyscallHandlers + """ + def __init__(self, mu, memory_base, memory_size, syscall_handler): + self._mu = mu self._memory_base = memory_base + self._memory_current = memory_base self._memory_size = memory_size + self._syscall_handler = syscall_handler + self._syscall_handler.set_handler(0xC0, "mmap2", 6, self._handle_mmap2) + self._syscall_handler.set_handler(0xDC, "madvise", 3, self._handle_madvise) + + def allocate(self, length, prot=7): + alloc_base = self._memory_current + + if alloc_base + length > self._memory_base + self._memory_size: + raise OverflowError("Our native memory is overflowing..") + + self._mu.mem_map(alloc_base, length, perms=prot) + self._memory_current += length + + return alloc_base + + def _handle_mmap2(self, mu, addr, length, prot, flags, fd, offset): + """ + void *mmap2(void *addr, size_t length, int prot, int flags, int fd, off_t pgoffset); + """ + return self.allocate(length, prot=prot) + + def _handle_madvise(self, mu, start, len_in, behavior): + """ + int madvise(void *addr, size_t length, int advice); + The kernel is free to ignore the advice. + On success madvise() returns zero. On error, it returns -1 and errno is set appropriately. + """ + # We don't need your advise. + return 0 diff --git a/androidemu/vfs/__init__.py b/androidemu/vfs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/androidemu/vfs/file_system.py b/androidemu/vfs/file_system.py new file mode 100644 index 0000000..401ef0f --- /dev/null +++ b/androidemu/vfs/file_system.py @@ -0,0 +1,94 @@ +import logging +import os +import posixpath + +from androidemu.cpu.syscall_handlers import SyscallHandlers +from androidemu.utils import memory_helpers + +logger = logging.getLogger(__name__) + + +class VirtualFileSystem: + + """ + :type syscall_handler SyscallHandlers + """ + def __init__(self, root_path, syscall_handler): + self._root_path = root_path + self._file_descriptors = [0, 1, 2] + syscall_handler.set_handler(0x3, "read", 3, self._handle_read) + syscall_handler.set_handler(0x6, "close", 1, self._handle_close) + syscall_handler.set_handler(0x142, "openat", 4, self._handle_openat) + + def _handle_read(self, mu, fd, buf_addr, count): + """ + ssize_t read(int fd, void *buf, size_t count); + + On files that support seeking, the read operation commences at the current file offset, and the file offset + is incremented by the number of bytes read. If the current file offset is at or past the end of file, + no bytes are read, and read() returns zero. + + If count is zero, read() may detect the errors described below. In the absence of any errors, or if read() + does not check for errors, a read() with a count of 0 returns zero and has no other effects. + + If count is greater than SSIZE_MAX, the result is unspecified. + """ + if fd <= 2: + raise NotImplementedError("Unsupported read operation for file descriptor %d." % fd) + + if fd not in self._file_descriptors: + # TODO: Return valid error. + raise NotImplementedError() + + file_handle = self._file_descriptors[fd] + buf = os.read(file_handle, count) + result = len(buf) + mu.mem_write(buf_addr, buf) + return result + + def _handle_close(self, mu, fd): + """ + int close(int fd); + + close() closes a file descriptor, so that it no longer refers to any file and may be reused. Any record locks + (see fcntl(2)) held on the file it was associated with, and owned by the process, are removed (regardless of + the file descriptor that was used to obtain the lock). + + close() returns zero on success. On error, -1 is returned, and errno is set appropriately. + """ + if fd not in self._file_descriptors: + return 0 + + os.close(self._file_descriptors[fd]) + return 0 + + def _handle_openat(self, mu, dfd, filename_ptr, flags, mode): + """ + int openat(int dirfd, const char *pathname, int flags, mode_t mode); + + On success, openat() returns a new file descriptor. + On error, -1 is returned and errno is set to indicate the error. + + EBADF + dirfd is not a valid file descriptor. + ENOTDIR + pathname is relative and dirfd is a file descriptor referring to a file other than a directory. + """ + filename = memory_helpers.read_utf8(mu, filename_ptr) + + if filename.startswith("/"): + filename = filename[1:] + + file_path = posixpath.join(self._root_path, filename) + file_path = posixpath.normpath(file_path) + + if posixpath.commonpath([file_path, self._root_path]) != self._root_path: + raise RuntimeError("Emulated binary tried to escape vfs jail.") + + if os.path.isfile(file_path): + logger.info("File opened '%s'" % filename) + self._file_descriptors.append(os.open(file_path, flags=os.O_RDWR | os.O_BINARY)) + return len(self._file_descriptors) - 1 + else: + logger.info("File does not exist %s" % file_path) + return -1 diff --git a/debug_utils.py b/debug_utils.py index 462307a..c20acfb 100644 --- a/debug_utils.py +++ b/debug_utils.py @@ -33,3 +33,8 @@ def hook_mem_write(uc, access, address, size, value, user_data): def hook_mem_read(uc, access, address, size, value, user_data): pc = uc.reg_read(UC_ARM_REG_PC) logger.debug(">>> Memory READ at 0x%x, data size = %u, pc: %x" % (address, size, pc)) + + +def hook_interrupt(uc, intno, data): + logger.debug(">>> Triggering interrupt %d" % intno) + return diff --git a/example_jni.py b/example_jni.py index 9b5ac32..eb82b1c 100644 --- a/example_jni.py +++ b/example_jni.py @@ -1,6 +1,9 @@ import logging +import os import sys +import posixpath +from unicorn import UC_HOOK_CODE, UcError from unicorn.arm_const import * import debug_utils @@ -16,7 +19,10 @@ logger = logging.getLogger(__name__) # Initialize emulator -emulator = Emulator() +emulator = Emulator( + vfp_inst_set=True, + vfs_root=posixpath.join(posixpath.dirname(__file__), "vfs") +) # Load all libraries. emulator.load_library("example_binaries/libdl.so") @@ -42,6 +48,10 @@ emulator.mu.reg_write(UC_ARM_REG_R1, 0x00) # void* reserved # Run JNI_OnLoad. -emulator.mu.emu_start(base_address + 0x7DEC + 1, base_address + 0x7EEA) +try: + emulator.mu.emu_start(base_address + 0x7DEC + 1, base_address + 0x7EEA) +except UcError as e: + print("Exit at %x" % emulator.mu.reg_read(UC_ARM_REG_PC)) + raise logger.info("Exited EMU.") diff --git a/vfs/proc/sys/vm/overcommit_memory b/vfs/proc/sys/vm/overcommit_memory new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/vfs/proc/sys/vm/overcommit_memory @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/vfs/sys/devices/system/cpu/online b/vfs/sys/devices/system/cpu/online new file mode 100644 index 0000000..8b0ad1b --- /dev/null +++ b/vfs/sys/devices/system/cpu/online @@ -0,0 +1 @@ +0-3 \ No newline at end of file