From 15f3b58d9b021c7bdf50e0afbc80af73149f51b0 Mon Sep 17 00:00:00 2001 From: lazymio Date: Fri, 11 Feb 2022 23:03:56 +0100 Subject: [PATCH] Implement coprocessor register read/write for python bindings --- bindings/python/sample_arm.py | 21 ++++++++++ bindings/python/sample_arm64.py | 20 ++++++++++ bindings/python/unicorn/unicorn.py | 61 +++++++++++++++++++++++++++++- 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/bindings/python/sample_arm.py b/bindings/python/sample_arm.py index 5fae6b6b..b906d538 100755 --- a/bindings/python/sample_arm.py +++ b/bindings/python/sample_arm.py @@ -98,8 +98,29 @@ def test_thumb(): except UcError as e: print("ERROR: %s" % e) +def test_read_sctlr(): + print("Read SCTLR") + try: + # Initialize emulator in thumb mode + mu = Uc(UC_ARCH_ARM, UC_MODE_ARM) + + # Read SCTLR + # cp = 15 + # is64 = 0 + # sec = 0 + # crn = 1 + # crm = 0 + # opc1 = 0 + # opc2 = 0 + val = mu.reg_read(UC_ARM_REG_CP_REG, (15, 0, 0, 1, 0, 0, 0)) + print(">>> SCTLR = 0x%x" % val) + + except UcError as e: + print("ERROR: %s" % e) if __name__ == '__main__': test_arm() print("=" * 26) test_thumb() + print("=" * 26) + test_read_sctlr() diff --git a/bindings/python/sample_arm64.py b/bindings/python/sample_arm64.py index de9768e7..999366fe 100755 --- a/bindings/python/sample_arm64.py +++ b/bindings/python/sample_arm64.py @@ -64,5 +64,25 @@ def test_arm64(): print("ERROR: %s" % e) +def test_arm64_read_sctlr(): + print("Read SCTLR_EL1") + try: + # Initialize emulator in ARM mode + mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM) + + # Read SCTLR_EL1 + # crn = 1; + # crm = 0; + # op0 = 3; + # op1 = 0; + # op2 = 0; + val = mu.reg_read(UC_ARM64_REG_CP_REG, (1, 0, 3, 0, 0)) + print(">>> SCTLR_EL1 = 0x%x" % val) + + except UcError as e: + print("ERROR: %s" % e) + if __name__ == '__main__': test_arm64() + print("=" * 26) + test_arm64_read_sctlr() diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index dcbd2cf3..9afd2fc7 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -11,7 +11,7 @@ import sys import weakref import functools -from . import x86_const, arm64_const, unicorn_const as uc +from . import x86_const, arm_const, arm64_const, unicorn_const as uc if not hasattr(sys.modules[__name__], "__file__"): __file__ = inspect.getfile(inspect.currentframe()) @@ -261,8 +261,29 @@ def reg_read(reg_read_func, arch, reg_id, opt=None): raise UcError(status) return reg.value + if arch == uc.UC_ARCH_ARM: + if reg_id == arm_const.UC_ARM_REG_CP_REG: + reg = uc_arm_cp_reg() + if not isinstance(opt, tuple) or len(opt) != 7: + raise UcError(uc.UC_ERR_ARG) + reg.cp, reg.is64, reg.sec, reg.crn, reg.crm, reg.opc1, reg.opc2 = opt + status = reg_read_func(reg_id, ctypes.byref(reg)) + if status != uc.UC_ERR_OK: + raise UcError(status) + return reg.val + if arch == uc.UC_ARCH_ARM64: - if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1): + if reg_id == arm64_const.UC_ARM64_REG_CP_REG: + reg = uc_arm64_cp_reg() + if not isinstance(opt, tuple) or len(opt) != 5: + raise UcError(uc.UC_ERR_ARG) + reg.crn, reg.crm, reg.op0, reg.op1, reg.op2 = opt + status = reg_read_func(reg_id, ctypes.byref(reg)) + if status != uc.UC_ERR_OK: + raise UcError(status) + return reg.val + + elif reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1): reg = uc_arm64_neon128() status = reg_read_func(reg_id, ctypes.byref(reg)) if status != uc.UC_ERR_OK: @@ -312,6 +333,19 @@ def reg_write(reg_write_func, arch, reg_id, value): reg.low_qword = value & 0xffffffffffffffff reg.high_qword = value >> 64 + if arch == uc.UC_ARCH_ARM: + if reg_id == arm64_const.UC_ARM64_REG_CP_REG: + reg = uc_arm64_cp_reg() + if not isinstance(value, tuple) or len(value) != 6: + raise UcError(uc.UC_ERR_ARG) + reg.crn, reg.crm, reg.op0, reg.op1, reg.op2, reg.val = value + + elif reg_id == arm_const.UC_ARM_REG_CP_REG: + reg = uc_arm_cp_reg() + if not isinstance(value, tuple) or len(value) != 8: + raise UcError(uc.UC_ERR_ARG) + reg.cp, reg.is64, reg.sec, reg.crn, reg.crm, reg.opc1, reg.opc2, reg.val = value + if reg is None: # convert to 64bit number to be safe reg = ctypes.c_uint64(value) @@ -342,6 +376,29 @@ def _catch_hook_exception(func): return wrapper +class uc_arm_cp_reg(ctypes.Structure): + """ARM coprocessors registers for instructions MRC, MCR, MRRC, MCRR""" + _fields_ = [ + ("cp", ctypes.c_uint32), + ("is64", ctypes.c_uint32), + ("sec", ctypes.c_uint32), + ("crn", ctypes.c_uint32), + ("crm", ctypes.c_uint32), + ("opc1", ctypes.c_uint32), + ("opc2", ctypes.c_uint32), + ("val", ctypes.c_uint64) + ] + +class uc_arm64_cp_reg(ctypes.Structure): + """ARM64 coprocessors registers for instructions MRS, MSR""" + _fields_ = [ + ("crn", ctypes.c_uint32), + ("crm", ctypes.c_uint32), + ("op0", ctypes.c_uint32), + ("op1", ctypes.c_uint32), + ("op2", ctypes.c_uint32), + ("val", ctypes.c_uint64) + ] class uc_x86_mmr(ctypes.Structure): """Memory-Management Register for instructions IDTR, GDTR, LDTR, TR."""