Skip to content

Commit

Permalink
Added specific syscall overrides and partial super class support
Browse files Browse the repository at this point in the history
  • Loading branch information
AeonLucid committed Jun 3, 2019
1 parent a8c9eaf commit b574e31
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 42 deletions.
35 changes: 24 additions & 11 deletions androidemu/cpu/syscall_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
from androidemu.const.android import *
from androidemu.const.linux import *
from androidemu.cpu.syscall_handlers import SyscallHandlers
from androidemu.utils import memory_helpers

OVERRIDE_TIMEOFDAY = False
OVERRIDE_TIMEOFDAY_SEC = 0
OVERRIDE_TIMEOFDAY_USEC = 0

OVERRIDE_CLOCK = False
OVERRIDE_CLOCK_TIME = 0


class SyscallHooks:
Expand All @@ -35,12 +41,16 @@ def _handle_gettimeofday(self, uc, tv, tz):
"""

if tv != 0:
timestamp = time.time()
(usec, sec) = math.modf(timestamp)
usec = abs(int(usec * 100000))
if OVERRIDE_TIMEOFDAY:
uc.mem_write(tv + 0, int(OVERRIDE_TIMEOFDAY_SEC).to_bytes(4, byteorder='little'))
uc.mem_write(tv + 4, int(OVERRIDE_TIMEOFDAY_USEC).to_bytes(4, byteorder='little'))
else:
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'))
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
Expand Down Expand Up @@ -97,11 +107,14 @@ def _handle_clock_gettime(self, mu, clk_id, tp_ptr):
"""

if clk_id == CLOCK_MONOTONIC_COARSE:
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'))

if OVERRIDE_CLOCK:
mu.mem_write(tp_ptr + 0, int(OVERRIDE_CLOCK_TIME).to_bytes(4, byteorder='little'))
mu.mem_write(tp_ptr + 4, int(0).to_bytes(4, byteorder='little'))
else:
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))
Expand Down
5 changes: 1 addition & 4 deletions androidemu/emulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,7 @@ def call_native(self, addr, *argv):
if is_jni:
self.java_vm.jni_env.clear_locals()

def dump(self):
local_dir = os.path.dirname(__file__)
out_dir = os.path.join(local_dir, 'dump', str(int(time.time())))

def dump(self, out_dir):
os.makedirs(out_dir)

for begin, end, prot in [reg for reg in self.mu.mem_regions()]:
Expand Down
2 changes: 2 additions & 0 deletions androidemu/emulator_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class EmulatorError(Exception):
pass
5 changes: 4 additions & 1 deletion androidemu/java/classes/constructor.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from androidemu.java.classes.executable import Executable
from androidemu.java.java_class_def import JavaClassDef
from androidemu.java.java_field_def import JavaFieldDef
from androidemu.java.java_method_def import JavaMethodDef
Expand All @@ -8,10 +9,12 @@ class Constructor(metaclass=JavaClassDef,
jvm_fields=[
JavaFieldDef('slot', 'I', False),
JavaFieldDef('declaringClass', 'Ljava/lang/Class;', False)
]):
],
jvm_super=Executable):

def __init__(self, clazz: JavaClassDef, method: JavaMethodDef):
self._clazz = clazz
self._method = method
self.slot = method.jvm_id
self.declaringClass = self._clazz
self.accessFlags = method.modifier
12 changes: 12 additions & 0 deletions androidemu/java/classes/executable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from androidemu.java.java_class_def import JavaClassDef
from androidemu.java.java_field_def import JavaFieldDef


class Executable(metaclass=JavaClassDef,
jvm_name='java/lang/reflect/Executable',
jvm_fields=[
JavaFieldDef('accessFlags', 'I', False)
]):

def __init__(self):
pass
22 changes: 17 additions & 5 deletions androidemu/java/classes/method.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
from androidemu.java.classes.constructor import Constructor
import logging

from androidemu.emulator_error import EmulatorError
from androidemu.java.classes.executable import Executable
from androidemu.java.java_class_def import JavaClassDef
from androidemu.java.java_field_def import JavaFieldDef
from androidemu.java.java_method_def import java_method_def, JavaMethodDef

logger = logging.getLogger(__name__)


class Method(metaclass=JavaClassDef,
jvm_name='java/lang/reflect/Method',
jvm_fields=[
JavaFieldDef('slot', 'I', False),
JavaFieldDef('declaringClass', 'Ljava/lang/Class;', False),
]):
],
jvm_super=Executable):

def __init__(self, clazz: JavaClassDef, method: JavaMethodDef):
super().__init__()
self._clazz = clazz
self._method = method
self.slot = method.jvm_id
self.declaringClass = self._clazz
self.accessFlags = method.modifier

@staticmethod
@java_method_def(
name="getMethodModifiers",
signature="(Ljava/lang/Class;I)I",
args_list=['jobject', 'jint']
args_list=['jobject', 'jint'],
ignore=True
)
def get_method_modifiers(emu, clazz_obj, jvm_method_id):
clazz = clazz_obj.value
method = clazz.find_method_by_id(jvm_method_id)

# TODO: Implement
logger.debug('get_method_modifiers(%s, %s)' % (clazz.jvm_name, method.name))

if method.modifier is None:
raise EmulatorError('No modifier was given to class %s method %s' % (clazz.jvm_name, method.name))

return 0
return method.modifier
14 changes: 14 additions & 0 deletions androidemu/java/constant_values.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# https://docs.oracle.com/javase/7/docs/api/constant-values.html

MODIFIER_PUBLIC = 1
MODIFIER_PRIVATE = 2
MODIFIER_PROTECTED = 4
MODIFIER_STATIC = 8
MODIFIER_FINAL = 16
MODIFIER_SYNCHRONIZED = 32
MODIFIER_VOLATILE = 64
MODIFIER_TRANSIENT = 128
MODIFIER_NATIVE = 256
MODIFIER_INTERFACE = 512
MODIFIER_ABSTRACT = 1024
MODIFIER_STRICT = 2048
9 changes: 8 additions & 1 deletion androidemu/java/java_class_def.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ class JavaClassDef(type):
next_jvm_method_id = itertools.count(start=0xd2000000, step=4)
next_jvm_field_id = itertools.count(start=0xe2000000, step=4)

def __init__(cls, name, base, ns, jvm_name=None, jvm_fields=None, jvm_ignore=False):
def __init__(cls, name, base, ns, jvm_name=None, jvm_fields=None, jvm_ignore=False, jvm_super=None):
cls.jvm_id = next(JavaClassDef.next_jvm_id)
cls.jvm_name = jvm_name
cls.jvm_methods = dict()
cls.jvm_fields = dict()
cls.jvm_ignore = jvm_ignore
cls.jvm_super = jvm_super

# Register all defined Java methods.
for func in inspect.getmembers(cls, predicate=inspect.isfunction):
Expand Down Expand Up @@ -71,4 +72,10 @@ def find_field(cls, name, signature, is_static):
return None

def find_field_by_id(cls, jvm_id):
try:
if cls.jvm_super is not None:
return cls.jvm_super.find_field_by_id(jvm_id)
except KeyError:
pass

return cls.jvm_fields[jvm_id]
11 changes: 8 additions & 3 deletions androidemu/java/java_method_def.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class JavaMethodDef:

def __init__(self, func_name, func, name, signature, native, args_list=None):
def __init__(self, func_name, func, name, signature, native, args_list=None, modifier=None, ignore=None):
self.jvm_id = None # Assigned by JavaClassDef.
self.func_name = func_name
self.func = func
Expand All @@ -9,9 +9,11 @@ def __init__(self, func_name, func, name, signature, native, args_list=None):
self.native = native
self.native_addr = None
self.args_list = args_list
self.modifier = modifier
self.ignore = ignore


def java_method_def(name, signature, native=False, args_list=None):
def java_method_def(name, signature, native=False, args_list=None, modifier=None, ignore=False):
def java_method_def_real(func):
def native_wrapper(self, emulator, *argv):
return emulator.call_native(
Expand All @@ -27,7 +29,10 @@ 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, args_list=args_list)
wrapper.jvm_method = JavaMethodDef(func.__name__, wrapper, name, signature, native,
args_list=args_list,
modifier=modifier,
ignore=ignore)
return wrapper

return java_method_def_real
3 changes: 2 additions & 1 deletion androidemu/java/java_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ def attach_current_thread(self, mu):

@native_method
def detach_current_thread(self, mu):
raise NotImplementedError()
# TODO: NooOO idea.
pass

@native_method
def get_env(self, mu, java_vm, env, version):
Expand Down
16 changes: 15 additions & 1 deletion androidemu/java/jni_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from androidemu.hooker import Hooker
from androidemu.java.classes.constructor import Constructor
from androidemu.java.classes.method import Method
from androidemu.java.constant_values import MODIFIER_STATIC
from androidemu.java.helpers.native_method import native_method
from androidemu.java.java_classloader import JavaClassLoader
from androidemu.java.jni_const import *
Expand Down Expand Up @@ -379,7 +380,10 @@ def to_reflected_method(self, mu, env, class_idx, method_id, is_static):
if method is None:
raise RuntimeError("Could not find method ('%u') in class %s." % (method_id, clazz.value.jvm_name))

# TODO: Static check.
if method.modifier & MODIFIER_STATIC:
mu.mem_write(is_static, int(JNI_TRUE).to_bytes(4, byteorder='little'))
else:
mu.mem_write(is_static, int(JNI_FALSE).to_bytes(4, byteorder='little'))

logger.debug("JNIEnv->ToReflectedMethod(%s, %s, %u) was called" % (clazz.value.jvm_name,
method.name,
Expand Down Expand Up @@ -448,6 +452,9 @@ def new_global_ref(self, mu, env, obj):
"""
logger.debug("JNIEnv->NewGlobalRef(%d) was called" % obj)

if obj == 0:
return 0

obj = self.get_local_reference(obj)

if obj is None:
Expand All @@ -466,6 +473,10 @@ def delete_local_ref(self, mu, env, idx):
Deletes the local reference pointed to by localRef.
"""
logger.debug("JNIEnv->DeleteLocalRef(%d) was called" % idx)

if idx == 0:
return None

obj = self.get_local_reference(idx)
self.delete_local_reference(obj)

Expand Down Expand Up @@ -1013,6 +1024,9 @@ def get_static_method_id(self, mu, env, clazz_idx, name_ptr, sig_ptr):
raise RuntimeError(
"Could not find static method ('%s', '%s') in class %s." % (name, sig, clazz.value.jvm_name))

if method.ignore:
return 0

return method.jvm_id

@native_method
Expand Down
17 changes: 3 additions & 14 deletions androidemu/native/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,11 @@ def __init__(self, emu, memory, modules, hooker):
self.atexit = []

modules.add_symbol_hook('__system_property_get', hooker.write_function(self.system_property_get) + 1)
modules.add_symbol_hook('pthread_create', hooker.write_function(self.pthread_create) + 1)
modules.add_symbol_hook('fork', hooker.write_function(self.nop('fork')) + 1)
modules.add_symbol_hook('vfork', hooker.write_function(self.nop('vfork')) + 1)
modules.add_symbol_hook('dladdr', hooker.write_function(self.nop('dladdr')) + 1)
modules.add_symbol_hook('dlsym', hooker.write_function(self.nop('dlsym')) + 1)
modules.add_symbol_hook('tolower', hooker.write_function(self.tolower) + 1)
modules.add_symbol_hook('strcmpi', hooker.write_function(self.nop('strcmpi')) + 1)

@native_method
def tolower(self, uc, charr):
logger.debug("Called tolower(%s)" % chr(charr))
return ord(chr(charr).lower())
modules.add_symbol_hook('dlopen', hooker.write_function(self.nop('dlopen')) + 1)
modules.add_symbol_hook('pthread_create', hooker.write_function(self.nop('pthread_create')) + 1)
modules.add_symbol_hook('pthread_join', hooker.write_function(self.nop('pthread_join')) + 1)

@native_method
def system_property_get(self, uc, name_ptr, buf_ptr):
Expand All @@ -47,10 +40,6 @@ def system_property_get(self, uc, name_ptr, buf_ptr):

return None

@native_method
def pthread_create(self, uc, thread_ptr, attr, start_ptr, arg_ptr):
logger.debug("Called pthread_create(0x%x, 0x%x, 0x%x, 0x%x)" % (thread_ptr, attr, start_ptr, arg_ptr))

def nop(self, name):
@native_method
def nop_inside(emu):
Expand Down
14 changes: 13 additions & 1 deletion androidemu/vfs/file_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

logger = logging.getLogger(__name__)

OVERRIDE_URANDOM = False
OVERRIDE_URANDOM_BYTE = b"\x00"


class VirtualFile:

Expand Down Expand Up @@ -108,7 +111,10 @@ def _handle_read(self, mu, fd, buf_addr, count):
logger.info("Reading %d bytes from '%s'" % (count, file.name))

if file.descriptor == 'urandom':
buf = os.urandom(count)
if OVERRIDE_URANDOM:
buf = OVERRIDE_URANDOM_BYTE * count
else:
buf = os.urandom(count)
else:
buf = os.read(file.descriptor, count)

Expand Down Expand Up @@ -231,6 +237,12 @@ def _handle_fstatat64(self, mu, dirfd, pathname_ptr, buf, flags):
logger.info("File fstatat64 '%s'" % pathname)
pathname = self.translate_path(pathname)

if not os.path.exists(pathname):
logger.warning('> File was not found.')
return -1

logger.warning('> File was found.')

stat = file_helpers.stat64(path=pathname)
# stat = os.stat(path=file_path, dir_fd=None, follow_symlinks=False)
file_helpers.stat_to_memory(mu, buf, stat, WRITE_FSTAT_TIMES)
Expand Down

0 comments on commit b574e31

Please sign in to comment.