Skip to content

Commit

Permalink
Improved heap, added more JNI / syscall methods, proper arg writing
Browse files Browse the repository at this point in the history
  • Loading branch information
AeonLucid committed May 31, 2019
1 parent 5de75b6 commit 253ac70
Show file tree
Hide file tree
Showing 16 changed files with 514 additions and 118 deletions.
2 changes: 1 addition & 1 deletion androidemu/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@

BASE_ADDR = 0xCBBCB000

WRITE_FSTAT_TIMES = False
WRITE_FSTAT_TIMES = True
3 changes: 2 additions & 1 deletion androidemu/cpu/syscall_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ def _handle_syscall(self, mu):
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)))
logger.error("Unhandled syscall 0x%x (%u) at 0x%x, stopping emulation" % (idx, idx,
mu.reg_read(UC_ARM_REG_PC)))
mu.emu_stop()
36 changes: 35 additions & 1 deletion androidemu/cpu/syscall_hooks.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import math
import time
from random import randint

from unicorn import Uc

from androidemu.const.android import *
Expand All @@ -15,9 +19,35 @@ class SyscallHooks:
def __init__(self, mu, syscall_handler):
self._mu = mu
self._syscall_handler = syscall_handler
self._syscall_handler.set_handler(0x4E, "gettimeofday", 2, self._handle_gettimeofday)
self._syscall_handler.set_handler(0x5B, "fchmod", 2, self._handle_fchmod)
self._syscall_handler.set_handler(0xAC, "prctl", 5, self._handle_prctl)
self._syscall_handler.set_handler(0xF0, "futex", 6, self._handle_futex)
self._syscall_handler.set_handler(0x107, "clock_gettime", 2, self._handle_clock_gettime)
self._clock_start = time.time()
self._clock_offset = randint(1000, 2000)

def _handle_gettimeofday(self, uc, tv, tz):
"""
If either tv or tz is NULL, the corresponding structure is not set or returned.
"""

if tv != 0:
timestamp = time.time()
(usec, sec) = math.modf(timestamp)
usec = abs(int(usec * 100000))

uc.mem_write(tv + 0, int(sec).to_bytes(4, byteorder='little'))
uc.mem_write(tv + 4, int(usec).to_bytes(4, byteorder='little'))

if tz != 0:
uc.mem_write(tz + 0, int(-120).to_bytes(4, byteorder='little')) # minuteswest -(+GMT_HOURS) * 60
uc.mem_write(tz + 4, int().to_bytes(4, byteorder='little')) # dsttime

return 0

def _handle_fchmod(self, uc, fd, mode):
raise NotImplementedError()

def _handle_prctl(self, mu, option, arg2, arg3, arg4, arg5):
"""
Expand Down Expand Up @@ -68,7 +98,11 @@ def _handle_clock_gettime(self, mu, clk_id, tp_ptr):
"""

if clk_id == CLOCK_MONOTONIC_COARSE:
# TODO: Actually write time.
clock_add = time.time() - self._clock_start # Seconds passed since clock_start was set.

mu.mem_write(tp_ptr + 0, int(self._clock_start + clock_add).to_bytes(4, byteorder='little'))
mu.mem_write(tp_ptr + 4, int(0).to_bytes(4, byteorder='little'))

return 0
else:
raise NotImplementedError("Unsupported clk_id: %d (%x)" % (clk_id, clk_id))
4 changes: 2 additions & 2 deletions androidemu/emulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __init__(self, vfs_root=None, vfp_inst_set=False):

# JavaVM
self.java_classloader = JavaClassLoader()
self.java_vm = JavaVM(self.java_classloader, self.hooker)
self.java_vm = JavaVM(self, self.java_classloader, self.hooker)

# Native
self.native_memory = NativeMemory(self.mu, config.MEMORY_DYN_BASE, config.MEMORY_DYN_SIZE, self.syscall_handler)
Expand Down Expand Up @@ -122,7 +122,7 @@ def call_native(self, addr, *argv):

try:
# Execute native call.
native_write_args(self.mu, *argv)
native_write_args(self, *argv)
stop_pos = randint(MEMORY_BASE, MEMORY_BASE + MEMORY_SIZE) | 1
self.mu.reg_write(UC_ARM_REG_LR, stop_pos)
self.mu.emu_start(addr, stop_pos - 1)
Expand Down
63 changes: 44 additions & 19 deletions androidemu/java/helpers/native_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,56 @@

from androidemu.java.java_class_def import JavaClassDef
from androidemu.java.jni_const import JNI_ERR
from androidemu.java.jni_ref import jobject
from androidemu.java.jni_ref import jobject, jstring, jobjectArray, jbyteArray


def native_write_args(mu, *argv):
def native_write_args(emu, *argv):
amount = len(argv)

if amount == 0:
return

if amount >= 1:
native_write_arg_register(mu, UC_ARM_REG_R0, argv[0])
native_write_arg_register(emu, UC_ARM_REG_R0, argv[0])

if amount >= 2:
native_write_arg_register(mu, UC_ARM_REG_R1, argv[1])
native_write_arg_register(emu, UC_ARM_REG_R1, argv[1])

if amount >= 3:
native_write_arg_register(mu, UC_ARM_REG_R2, argv[2])
native_write_arg_register(emu, UC_ARM_REG_R2, argv[2])

if amount >= 4:
native_write_arg_register(mu, UC_ARM_REG_R3, argv[3])
native_write_arg_register(emu, UC_ARM_REG_R3, argv[3])

if amount >= 5:
raise NotImplementedError("We don't support more than 4 args yet, write to the stack.")
# TODO: I have no idea why this dark magic is required but it works (for me)..
sp_start = emu.mu.reg_read(UC_ARM_REG_SP)
sp_current = sp_start - 8

for arg in argv[4:]:
emu.mu.mem_write(sp_current - 8, native_translate_arg(emu, arg).to_bytes(4, byteorder='little'))
sp_current = sp_current - 4

def native_write_arg_register(mu, reg, val):
emu.mu.reg_write(UC_ARM_REG_SP, sp_current)


def native_translate_arg(emu, val):
if isinstance(val, int):
mu.reg_write(reg, val)
return val
elif isinstance(val, str):
return emu.java_vm.jni_env.add_local_reference(jstring(val))
elif isinstance(val, list):
return emu.java_vm.jni_env.add_local_reference(jobjectArray(val))
elif isinstance(val, bytearray):
return emu.java_vm.jni_env.add_local_reference(jbyteArray(val))
elif isinstance(type(val), JavaClassDef):
return emu.java_vm.jni_env.add_local_reference(jobject(val))
else:
raise ValueError('Unsupported val type.')
raise NotImplementedError("Unable to write response '%s' type '%s' to emulator." % (str(val), type(val)))


def native_write_arg_register(emu, reg, val):
emu.mu.reg_write(reg, native_translate_arg(emu, val))


def native_method(func):
Expand Down Expand Up @@ -69,22 +89,27 @@ def native_method_wrapper(*argv):
native_args.append(mu.reg_read(UC_ARM_REG_R3))

if args_count >= 5:
raise NotImplementedError("We don't support more than 4 args yet, read from the stack.")
native_args.append(mu.reg_read(UC_ARM_REG_R4))

if args_count >= 6:
native_args.append(mu.reg_read(UC_ARM_REG_R5))

if args_count >= 7:
native_args.append(mu.reg_read(UC_ARM_REG_R6))

if args_count >= 8:
native_args.append(mu.reg_read(UC_ARM_REG_R7))

if args_count >= 9:
raise NotImplementedError("We don't support more than 8 args yet, read from the stack.")

if len(argv) == 1:
result = func(mu, *native_args)
else:
result = func(argv[0], mu, *native_args)

if result is not None:
if isinstance(result, int):
mu.reg_write(UC_ARM_REG_R0, result)
elif isinstance(type(result), JavaClassDef):
# This is a Java class object, so we should probably respond with a local jobject reference.
ref = emu.java_vm.jni_env.add_local_reference(jobject(result))
mu.reg_write(UC_ARM_REG_R0, ref)
else:
raise NotImplementedError("Unable to write response '%s' to emulator." % str(result))
native_write_arg_register(emu, UC_ARM_REG_R0, result)
else:
mu.reg_write(UC_ARM_REG_R0, JNI_ERR)

Expand Down
6 changes: 5 additions & 1 deletion androidemu/java/java_field_def.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
class JavaFieldDef:

def __init__(self, name, signature, is_static):
def __init__(self, name, signature, is_static, static_value=None):
self.jvm_id = None # Assigned by JavaClassDef.
self.name = name
self.signature = signature
self.is_static = is_static
self.static_value = static_value

if self.is_static and self.static_value is None:
raise ValueError('Static value may not be None for a static field.')
7 changes: 4 additions & 3 deletions androidemu/java/java_method_def.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
class JavaMethodDef:

def __init__(self, func_name, func, name, signature, native):
def __init__(self, func_name, func, name, signature, native, args_list=None):
self.jvm_id = None # Assigned by JavaClassDef.
self.func_name = func_name
self.func = func
self.name = name
self.signature = signature
self.native = native
self.native_addr = None
self.args_list = args_list


def java_method_def(name, signature, native=False):
def java_method_def(name, signature, native=False, args_list=None):
def java_method_def_real(func):
def native_wrapper(self, emulator, *argv):
return emulator.call_native(
Expand All @@ -26,7 +27,7 @@ def normal_wrapper(*args, **kwargs):
return result

wrapper = native_wrapper if native else normal_wrapper
wrapper.jvm_method = JavaMethodDef(func.__name__, wrapper, name, signature, native)
wrapper.jvm_method = JavaMethodDef(func.__name__, wrapper, name, signature, native, args_list=args_list)
return wrapper

return java_method_def_real
4 changes: 2 additions & 2 deletions androidemu/java/java_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class JavaVM:
:type class_loader JavaClassLoader
:type hooker Hooker
"""
def __init__(self, class_loader, hooker):
def __init__(self, emu, class_loader, hooker):
(self.address_ptr, self.address) = hooker.write_function_table({
3: self.destroy_java_vm,
4: self.attach_current_thread,
Expand All @@ -26,7 +26,7 @@ def __init__(self, class_loader, hooker):
7: self.attach_current_thread
})

self.jni_env = JNIEnv(class_loader, hooker)
self.jni_env = JNIEnv(emu, class_loader, hooker)

@native_method
def destroy_java_vm(self, mu):
Expand Down
Loading

0 comments on commit 253ac70

Please sign in to comment.