Skip to content

Commit

Permalink
big improvement.
Browse files Browse the repository at this point in the history
- Add multi-thread support
- Add Arm64 support
- Add Function hook support
- many many misc bug fix
  • Loading branch information
my committed Jan 27, 2022
1 parent 56b5921 commit 7ef8820
Show file tree
Hide file tree
Showing 68 changed files with 4,408 additions and 942 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ This is a personal improved version of [AndroidNativeEmu](https://github.com/Aeo
- Fix R_ARM_ABS32 relocation bug.
- Use program header to load so instead of section header
- Support Java reflection
- Support Arm64
- Support multi-threaded like pthread_create etc.
- Add Function hook feature

## TODO
- Simulate linker TLS initialization.
Expand Down
39 changes: 25 additions & 14 deletions androidemu/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,38 @@
STACK_ADDR = 0x10000000
STACK_SIZE = 0x00100000

HOOK_MEMORY_BASE = 0x01000000
HOOK_MEMORY_SIZE = 0x00200000
BRIDGE_MEMORY_BASE = 0x01000000
BRIDGE_MEMORY_SIZE = 0x00200000

TLS_BASE = 0x02000000
TLS_SIZE = 0x1000

STOP_MEMORY_BASE = 0x03000000
STOP_MEMORY_SIZE = 0x00001000

TLS_SIZE = 0x1000

MAP_ALLOC_BASE = 0x30000000
MAP_ALLOC_SIZE = 0xA0000000-MAP_ALLOC_BASE

JMETHOD_ID_BASE = 0xd2000000
JFIELD_ID_BASE = 0xe2000000
BASE_ADDR = 0xCBBCB000

WRITE_FSTAT_TIMES = True

_configs = {}
import json
def global_config_init(cfg_path):
global _configs
with open(cfg_path, "r") as f:
js = f.read()
_configs = json.loads(js)
class Config:

def __init__(self, cfg_path):
with open(cfg_path, "r") as f:
js = f.read()
self.__configs = json.loads(js)
#
#
#

def global_config_get(key):
global _configs
return _configs[key]
#
def get(self, key, def_val = None):
if (key in self.__configs):
return self.__configs[key]
return def_val
#
#
3 changes: 3 additions & 0 deletions androidemu/const/emu_const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

ARCH_ARM32 = 1
ARCH_ARM64 = 2
34 changes: 34 additions & 0 deletions androidemu/const/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,37 @@
F_WAIT=0x010 #/* Wait until lock is granted */
F_FLOCK=0x020 #/* Use flock(2) semantics for lock */
F_POSIX=0x040 #/* Use POSIX semantics for lock */



#dirfd
AT_FDCWD = -100






AT_NULL= 0
AT_IGNORE= 1
AT_EXECFD= 2
AT_PHDR= 3
AT_PHENT= 4
AT_PHNUM= 5
AT_PAGESZ= 6
AT_BASE= 7
AT_FLAGS= 8
AT_ENTRY= 9
AT_NOTELF= 10
AT_UID= 11
AT_EUID= 12
AT_GID= 13
AT_EGID= 14
AT_PLATFORM= 15
AT_HWCAP= 16
AT_CLKTCK= 17
AT_SECURE= 23
AT_BASE_PLATFORM= 24
AT_RANDOM= 25
AT_HWCAP2= 26
AT_EXECFN= 31
16 changes: 15 additions & 1 deletion androidemu/cpu/interrupt_handler.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import logging
import traceback
import inspect

from unicorn import *
from unicorn.arm_const import *
from unicorn.arm64_const import *

import sys

logger = logging.getLogger(__name__)
Expand All @@ -23,8 +26,19 @@ 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)))
pc = 0
arch = self._mu.query(UC_QUERY_ARCH)
if arch == UC_ARCH_ARM:
pc = self._mu.reg_read(UC_ARM_REG_PC)
elif arch == UC_ARCH_ARM64:
pc = self._mu.reg_read(UC_ARM64_REG_PC)
#
logger.error("Unhandled interrupt %d at %x, stopping emulation" % (intno, pc))
traceback.print_stack()
frame = inspect.currentframe()
stack_trace = traceback.format_stack(frame)
logging.error("catch error on _hook_interrupt")
logging.error(stack_trace[:-1])
self._mu.emu_stop()
sys.exit(-1)
except Exception as e:
Expand Down
65 changes: 52 additions & 13 deletions androidemu/cpu/syscall_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,98 @@

from unicorn import *
from unicorn.arm_const import *
from unicorn.arm64_const import *

from .interrupt_handler import InterruptHandler
from .syscall_handler import SyscallHandler
from ..utils import memory_helpers
from ..const import emu_const
import unicorn
import traceback
import sys

logger = logging.getLogger(__name__)


class SyscallHandlers:

"""
:type interrupt_handler InterruptHandler
"""
def __init__(self, interrupt_handler):
def __init__(self, mu, schduler, arch):
self._handlers = dict()
interrupt_handler.set_handler(2, self._handle_syscall)
self.__sch = schduler
self.__interrupt_handler = InterruptHandler(mu)
if (arch == emu_const.ARCH_ARM32):
self.__interrupt_handler.set_handler(2, self._handle_syscall)
else:
#arm64
self.__interrupt_handler.set_handler(2, self._handle_syscall64)
#
#

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)
lr = mu.reg_read(UC_ARM_REG_LR)
logger.info("syscall %d lr=0x%08X", idx, lr)
tid = self.__sch.get_current_tid()
logging.debug("%d syscall %d lr=0x%08X", tid, idx, lr)
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(["0x%08X" % arg for arg in args])
logger.debug("Executing syscall %s(%s) at 0x%08X" % (handler.name, args_formatted,
mu.reg_read(UC_ARM_REG_PC)))

logging.debug("%d Executing syscall %s(%s) at 0x%08X" % (tid, handler.name, args_formatted, mu.reg_read(UC_ARM_REG_PC)))
try:
result = handler.callback(mu, *args)
except:
logger.exception("An error occured during in %x syscall hander, stopping emulation" % idx)
logging.exception("%d An error occured during in %x syscall hander, stopping emulation" % (tid, idx))
mu.emu_stop()
raise

if result is not None:
mu.reg_write(UC_ARM_REG_R0, result)
else:

args_formatted = ", ".join(["0x%08X" % arg for arg in args])
error = "Unhandled syscall 0x%x (%u) at 0x%x, args(%s) stopping emulation" % (idx, idx,
error = "%d Unhandled syscall 0x%x (%u) at 0x%x, args(%s) stopping emulation" % (tid, idx, idx,
mu.reg_read(UC_ARM_REG_PC), args_formatted)

logger.exception(error)
logging.exception(error)
mu.emu_stop()
raise RuntimeError(error)
#
#
def _handle_syscall64(self, mu):
idx = mu.reg_read(UC_ARM64_REG_X8)
lr = mu.reg_read(UC_ARM64_REG_LR)
tid = self.__sch.get_current_tid()

logging.debug("%d syscall %d lr=0x%016X", tid, idx, lr)
args = [mu.reg_read(reg_idx) for reg_idx in range(UC_ARM64_REG_X0, UC_ARM64_REG_X6 + 1)]

if idx in self._handlers:
handler = self._handlers[idx]
args = args[:handler.arg_count]
args_formatted = ", ".join(["0x%016X" % arg for arg in args])
logging.debug("%d Executing syscall %s(%s) at 0x%016X" % (tid, handler.name, args_formatted, mu.reg_read(UC_ARM64_REG_PC)))
try:
result = handler.callback(mu, *args)
except:
logging.exception("%d An error occured during in %x syscall hander, stopping emulation" % (tid, idx))
mu.emu_stop()
raise

if result is not None:
mu.reg_write(UC_ARM64_REG_X0, result)
else:
args_formatted = ", ".join(["0x%016X" % arg for arg in args])
error = "%d Unhandled syscall 0x%x (%u) at 0x%x, args(%s) stopping emulation" % (tid, idx, idx,
mu.reg_read(UC_ARM64_REG_PC), args_formatted)

logging.exception(error)
mu.emu_stop()
raise RuntimeError(error)
#
#
#
Loading

0 comments on commit 7ef8820

Please sign in to comment.