From 02e6c14e125ae26d02a37a820124d26f4e79a1ac Mon Sep 17 00:00:00 2001 From: Ahmed Samy Date: Fri, 24 Feb 2017 15:37:19 +0200 Subject: [PATCH 01/15] x86: add MSR API via reg API (#755) Writing / reading to model specific registers should be as easy as calling a function, it's a bit stupid to write shell code and run them just to write/read to a MSR, and even worse, you need more than just a shellcode to read... So, add a special register ID called UC_X86_REG_MSR, which should be passed to uc_reg_write()/uc_reg_read() as the register ID, and then a data structure which is uc_x86_msr (12 bytes), as the value (always), where: Byte Value Size 0 MSR ID 4 4 MSR val 8 --- bindings/python/unicorn/unicorn.py | 28 ++++++++++++- bindings/python/unicorn/x86_const.py | 3 +- include/uc_priv.h | 1 + include/unicorn/x86.h | 9 +++- qemu/target-i386/unicorn.c | 61 ++++++++++++++++++++++++++++ uc.c | 2 - 6 files changed, 99 insertions(+), 5 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 18751ae4..7bd297b6 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -202,6 +202,11 @@ class uc_x86_mmr(ctypes.Structure): ("flags", ctypes.c_uint32), # not used by GDTR and IDTR ] +class uc_x86_msr(ctypes.Structure): + _fields_ = [ + ("rid", ctypes.c_uint32), + ("value", ctypes.c_uint64), + ] class uc_x86_float80(ctypes.Structure): """Float80""" @@ -282,7 +287,7 @@ class Uc(object): raise UcError(status) # return the value of a register - def reg_read(self, reg_id): + def reg_read(self, reg_id, opt=None): if self._arch == uc.UC_ARCH_X86: if reg_id in [x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: reg = uc_x86_mmr() @@ -302,6 +307,15 @@ class Uc(object): if status != uc.UC_ERR_OK: raise UcError(status) return reg.low_qword | (reg.high_qword << 64) + if reg_id is x86_const.UC_X86_REG_MSR: + if opt is None: + raise UcError(uc.UC_ERR_ARG) + reg = uc_x86_msr() + reg.rid = opt + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != uc.UC_ERR_OK: + raise UcError(status) + return reg.value # read to 64bit number to be safe reg = ctypes.c_uint64(0) @@ -330,6 +344,10 @@ class Uc(object): reg = uc_x86_xmm() reg.low_qword = value & 0xffffffffffffffff reg.high_qword = value >> 64 + if reg_id is x86_const.UC_X86_REG_MSR: + reg = uc_x86_msr() + reg.rid = value[0] + reg.value = value[1] if reg is None: # convert to 64bit number to be safe @@ -339,6 +357,14 @@ class Uc(object): if status != uc.UC_ERR_OK: raise UcError(status) + # read from MSR + def msr_read(self, msr_id): + return self.reg_read(x86_const.UC_X86_REG_MSR, msr_id) + + # write to MSR + def msr_write(self, msr_id, value): + return self.reg_write(x86_const.UC_X86_REG_MSR, (msr_id, value)) + # read data from memory def mem_read(self, address, size): data = ctypes.create_string_buffer(size) diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index ee5ba38f..5642c543 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -250,7 +250,8 @@ UC_X86_REG_LDTR = 244 UC_X86_REG_TR = 245 UC_X86_REG_FPCW = 246 UC_X86_REG_FPTAG = 247 -UC_X86_REG_ENDING = 248 +UC_X86_REG_MSR = 248 +UC_X86_REG_ENDING = 249 # X86 instructions diff --git a/include/uc_priv.h b/include/uc_priv.h index 4fcb7531..009c2e58 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -251,3 +251,4 @@ struct uc_context { MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address); #endif +/* vim: set ts=4 noet: */ diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index b0e02d8d..59fd17e5 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -19,6 +19,13 @@ typedef struct uc_x86_mmr { uint32_t flags; /* not used by GDTR and IDTR */ } uc_x86_mmr; +// Model-Specific Register structure, use this with UC_X86_REG_MSR (as the register ID) in +// call to uc_reg_write/uc_reg_read() to manipulate MSRs. +typedef struct uc_x86_msr { + uint32_t rid; + uint64_t value; +} uc_x86_msr; + // Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) // @user_data: user data passed to tracing APIs. typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data); @@ -76,7 +83,7 @@ typedef enum uc_x86_reg { UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, - UC_X86_REG_FPTAG, + UC_X86_REG_FPTAG, UC_X86_REG_MSR, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 817799db..5f26617d 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -17,6 +17,10 @@ static void load_seg_16_helper(CPUX86State *env, int seg, uint32_t selector) cpu_x86_load_seg_cache(env, seg, selector, (selector << 4), 0xffff, X86_NON_CS_FLAGS); } + +extern void helper_wrmsr(CPUX86State *env); +extern void helper_rdmsr(CPUX86State *env); + const int X86_REGS_STORAGE_SIZE = offsetof(CPUX86State, tlb_table); static void x86_set_pc(struct uc_struct *uc, uint64_t address) @@ -156,6 +160,49 @@ void x86_reg_reset(struct uc_struct *uc) } } +static int x86_msr_read(struct uc_struct *uc, uc_x86_msr *msr) +{ + CPUX86State *env = (CPUX86State *)uc->cpu->env_ptr; + uint64_t ecx = env->regs[R_ECX]; + uint64_t eax = env->regs[R_EAX]; + uint64_t edx = env->regs[R_EDX]; + + env->regs[R_ECX] = msr->rid; + helper_rdmsr(env); + + msr->value = ((uint32_t)env->regs[R_EAX]) | + ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32); + + env->regs[R_EAX] = eax; + env->regs[R_ECX] = ecx; + env->regs[R_EDX] = edx; + + /* The implementation doesn't throw exception or return an error if there is one, so + * we will return 0. */ + return 0; +} + +static int x86_msr_write(struct uc_struct *uc, uc_x86_msr *msr) +{ + CPUX86State *env = (CPUX86State *)uc->cpu->env_ptr; + uint64_t ecx = env->regs[R_ECX]; + uint64_t eax = env->regs[R_EAX]; + uint64_t edx = env->regs[R_EDX]; + + env->regs[R_ECX] = msr->rid; + env->regs[R_EAX] = (unsigned int)msr->value; + env->regs[R_EDX] = (unsigned int)(msr->value >> 32); + helper_wrmsr(env); + + env->regs[R_ECX] = ecx; + env->regs[R_EAX] = eax; + env->regs[R_EDX] = edx; + + /* The implementation doesn't throw exception or return an error if there is one, so + * we will return 0. */ + return 0; +} + int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = uc->cpu; @@ -376,6 +423,9 @@ int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int coun ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; break; + case UC_X86_REG_MSR: + x86_msr_read(uc, (uc_x86_msr *)value); + break; } break; @@ -644,6 +694,9 @@ int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int coun ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; break; + case UC_X86_REG_MSR: + x86_msr_read(uc, (uc_x86_msr *)value); + break; } break; #endif @@ -863,6 +916,9 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, i X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; break; + case UC_X86_REG_MSR: + x86_msr_write(uc, (uc_x86_msr *)value); + break; } break; @@ -1141,6 +1197,9 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, i X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; break; + case UC_X86_REG_MSR: + x86_msr_write(uc, (uc_x86_msr *)value); + break; } break; #endif @@ -1185,3 +1244,5 @@ void x86_uc_init(struct uc_struct* uc) uc->stop_interrupt = x86_stop_interrupt; uc_common_init(uc); } + +/* vim: set ts=4 sts=4 sw=4 et: */ diff --git a/uc.c b/uc.c index 744aa589..eabf7cb3 100644 --- a/uc.c +++ b/uc.c @@ -380,14 +380,12 @@ uc_err uc_reg_read(uc_engine *uc, int regid, void *value) return uc_reg_read_batch(uc, ®id, &value, 1); } - UNICORN_EXPORT uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { return uc_reg_write_batch(uc, ®id, (void *const *)&value, 1); } - // check if a memory area is mapped // this is complicated because an area can overlap adjacent blocks static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size) From fc72622ba820ba8d81145af63290dff394890d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Neal=20Gompa=20=28=E3=83=8B=E3=83=BC=E3=83=AB=E3=83=BB?= =?UTF-8?q?=E3=82=B4=E3=83=B3=E3=83=91=29?= Date: Fri, 24 Feb 2017 08:49:29 -0500 Subject: [PATCH 02/15] Makefile: Allow for overriding job threads for making 'qemu' dir (#762) Providing a default level of parallelism is perfectly fine, but it should also be possible to set higher or lower levels of parallelism easily. This is particularly beneficial for people packaging the software for Linux distributions. --- Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bc79b8b3..fa458470 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,13 @@ include pkgconfig.mk # package version LIBNAME = unicorn UNAME_S := $(shell uname -s) +# SMP_MFLAGS is used for controlling the amount of parallelism used +# in external 'make' invocations. If the user doesn't override it, it +# does "-j4". That is, it uses 4 job threads. If you want to use more or less, +# pass in a different -jX, with X being the number of threads. +# For example, to completely disable parallel building, pass "-j1". +# If you want to use 16 job threads, use "-j16". +SMP_MFLAGS := -j4 GENOBJ = $(shell find qemu/$(1) -name "*.o" 2>/dev/null) @@ -204,7 +211,7 @@ qemu/config-host.h-timestamp: cd qemu && \ ./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log - $(MAKE) -C qemu -j 4 + $(MAKE) -C qemu $(SMP_MFLAGS) $(eval UC_TARGET_OBJ += $$(wildcard qemu/util/*.o) $$(wildcard qemu/*.o) $$(wildcard qemu/qom/*.o) $$(wildcard qemu/hw/core/*.o) $$(wildcard qemu/qapi/*.o) $$(wildcard qemu/qobject/*.o)) unicorn: $(LIBRARY) $(ARCHIVE) From f4325f8c4e546f357bd8b2b747fc5d3d15ebb3b6 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 24 Feb 2017 21:51:01 +0800 Subject: [PATCH 03/15] bindings: update to support X86 MSR id --- bindings/dotnet/UnicornManaged/Const/X86.fs | 3 ++- bindings/go/unicorn/x86_const.go | 3 ++- bindings/java/unicorn/X86Const.java | 3 ++- bindings/python/unicorn/unicorn.py | 4 ++-- bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb | 3 ++- include/unicorn/x86.h | 7 ++++--- 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/bindings/dotnet/UnicornManaged/Const/X86.fs b/bindings/dotnet/UnicornManaged/Const/X86.fs index d0526f87..2dc3f61f 100644 --- a/bindings/dotnet/UnicornManaged/Const/X86.fs +++ b/bindings/dotnet/UnicornManaged/Const/X86.fs @@ -257,7 +257,8 @@ module X86 = let UC_X86_REG_TR = 245 let UC_X86_REG_FPCW = 246 let UC_X86_REG_FPTAG = 247 - let UC_X86_REG_ENDING = 248 + let UC_X86_REG_MSR = 248 + let UC_X86_REG_ENDING = 249 // X86 instructions diff --git a/bindings/go/unicorn/x86_const.go b/bindings/go/unicorn/x86_const.go index ef18c08e..bd47e3e2 100644 --- a/bindings/go/unicorn/x86_const.go +++ b/bindings/go/unicorn/x86_const.go @@ -252,7 +252,8 @@ const ( X86_REG_TR = 245 X86_REG_FPCW = 246 X86_REG_FPTAG = 247 - X86_REG_ENDING = 248 + X86_REG_MSR = 248 + X86_REG_ENDING = 249 // X86 instructions diff --git a/bindings/java/unicorn/X86Const.java b/bindings/java/unicorn/X86Const.java index 7afed1f9..c41ccfc9 100644 --- a/bindings/java/unicorn/X86Const.java +++ b/bindings/java/unicorn/X86Const.java @@ -254,7 +254,8 @@ public interface X86Const { public static final int UC_X86_REG_TR = 245; public static final int UC_X86_REG_FPCW = 246; public static final int UC_X86_REG_FPTAG = 247; - public static final int UC_X86_REG_ENDING = 248; + public static final int UC_X86_REG_MSR = 248; + public static final int UC_X86_REG_ENDING = 249; // X86 instructions diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 7bd297b6..e2cb6a5d 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -357,11 +357,11 @@ class Uc(object): if status != uc.UC_ERR_OK: raise UcError(status) - # read from MSR + # read from MSR - X86 only def msr_read(self, msr_id): return self.reg_read(x86_const.UC_X86_REG_MSR, msr_id) - # write to MSR + # write to MSR - X86 only def msr_write(self, msr_id, value): return self.reg_write(x86_const.UC_X86_REG_MSR, (msr_id, value)) diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb index 2226de17..f85ae21a 100644 --- a/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb +++ b/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb @@ -252,7 +252,8 @@ module Unicorn UC_X86_REG_TR = 245 UC_X86_REG_FPCW = 246 UC_X86_REG_FPTAG = 247 - UC_X86_REG_ENDING = 248 + UC_X86_REG_MSR = 248 + UC_X86_REG_ENDING = 249 # X86 instructions diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 59fd17e5..e4b1a3b2 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -22,8 +22,8 @@ typedef struct uc_x86_mmr { // Model-Specific Register structure, use this with UC_X86_REG_MSR (as the register ID) in // call to uc_reg_write/uc_reg_read() to manipulate MSRs. typedef struct uc_x86_msr { - uint32_t rid; - uint64_t value; + uint32_t rid; // MSR id + uint64_t value; // MSR value } uc_x86_msr; // Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) @@ -83,7 +83,8 @@ typedef enum uc_x86_reg { UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, - UC_X86_REG_FPTAG, UC_X86_REG_MSR, + UC_X86_REG_FPTAG, + UC_X86_REG_MSR, // Model-Specific Register UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; From b12ce92468309d5eaf645406db8ea2f2d33733d1 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 25 Feb 2017 01:14:47 +0800 Subject: [PATCH 04/15] regress: eflags_noset.c should only asm x86 code on x86 platform. fix #764 --- tests/regress/eflags_noset.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/regress/eflags_noset.c b/tests/regress/eflags_noset.c index 80afb495..8cc15d6b 100644 --- a/tests/regress/eflags_noset.c +++ b/tests/regress/eflags_noset.c @@ -34,17 +34,20 @@ uint32_t realEflags() "pushf\n\t" "pop %0\n\t" "popf" -#else + : "=r"(val) + : "r"(i) + : "%0"); +#elif defined(__x86_64__) __asm__("pushfq\n\t" "pushq %0\n\t" "popfq\n\t" "pushfq\n\t" "popq %0\n\t" "popfq" -#endif : "=r"(val) : "r"(i) : "%0"); +#endif printf("Real system eflags: 0x%08"PRIX3264"\n", val); From a40e5aae092781b6ddba003e8ac7ef29152f39cf Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 25 Feb 2017 11:20:26 +0800 Subject: [PATCH 05/15] regress: fix warning on compilation on eflags_noset.c. see #764 --- tests/regress/eflags_noset.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/regress/eflags_noset.c b/tests/regress/eflags_noset.c index 8cc15d6b..187484bd 100644 --- a/tests/regress/eflags_noset.c +++ b/tests/regress/eflags_noset.c @@ -25,9 +25,10 @@ typedef uint64_t puint; uint32_t realEflags() { puint val = 0; - puint i = 0xFFFFFEFF; //attempt to set ALL bits except trap flag. #if defined(__i386__) + puint i = 0xFFFFFEFF; //attempt to set ALL bits except trap flag. + __asm__("pushf\n\t" "push %0\n\t" "popf\n\t" @@ -38,6 +39,8 @@ uint32_t realEflags() : "r"(i) : "%0"); #elif defined(__x86_64__) + puint i = 0xFFFFFEFF; //attempt to set ALL bits except trap flag. + __asm__("pushfq\n\t" "pushq %0\n\t" "popfq\n\t" @@ -56,7 +59,7 @@ uint32_t realEflags() static void VM_exec() { - +#if defined(__i386__) || defined(__x86_64__) uc_engine *uc; uc_err err; unsigned int r_eax, eflags, r_esp, realflags = 0; @@ -115,6 +118,7 @@ static void VM_exec() realflags = realEflags(); assert(r_eax == realflags); +#endif } int main(int argc, char *argv[]) From c090f198ad557ec9ee197a55b564e7ed62cf150e Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Sun, 26 Feb 2017 02:27:35 +0100 Subject: [PATCH 06/15] Haskell bindings update (#767) * haskell: Properly handle invalid memory access * haskell: source cleanup * haskell: added support for batch reg read/write --- bindings/haskell/.gitignore | 1 + bindings/haskell/samples/SampleBatchReg.hs | 99 +++++++++++++++++++ bindings/haskell/samples/SampleX86.hs | 2 +- bindings/haskell/src/Unicorn.hs | 55 ++++++++--- .../haskell/src/Unicorn/Internal/Hook.chs | 4 +- .../haskell/src/Unicorn/Internal/Unicorn.chs | 70 ++++++++++--- bindings/haskell/src/cbits/unicorn_wrapper.c | 38 +++++++ .../haskell/src/include/unicorn_wrapper.h | 9 ++ 8 files changed, 250 insertions(+), 28 deletions(-) create mode 100644 bindings/haskell/samples/SampleBatchReg.hs diff --git a/bindings/haskell/.gitignore b/bindings/haskell/.gitignore index 3b5b7859..9966d825 100644 --- a/bindings/haskell/.gitignore +++ b/bindings/haskell/.gitignore @@ -21,3 +21,4 @@ SampleMips SampleSparc SampleX86 Shellcode +SampleBatchReg diff --git a/bindings/haskell/samples/SampleBatchReg.hs b/bindings/haskell/samples/SampleBatchReg.hs new file mode 100644 index 00000000..9b40b3f5 --- /dev/null +++ b/bindings/haskell/samples/SampleBatchReg.hs @@ -0,0 +1,99 @@ +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.X86 as X86 + +import Control.Monad.Trans.Class (lift) +import qualified Data.ByteString as BS +import Data.Int +import Data.List (intercalate) +import Data.Word +import qualified Numeric as N (showHex) +import System.IO (hPutStrLn, stderr) + +syscallABI :: [X86.Register] +syscallABI = [ X86.Rax + , X86.Rdi + , X86.Rsi + , X86.Rdx + , X86.R10 + , X86.R8 + , X86.R9 + ] + +vals :: [Int64] +vals = [ 200 + , 10 + , 11 + , 12 + , 13 + , 14 + , 15 + ] + +ucPerror :: Error + -> IO () +ucPerror err = + hPutStrLn stderr $ "Error " ++ ": " ++ strerror err + +base :: Word64 +base = 0x10000 + +-- mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall +code :: BS.ByteString +code = BS.pack [ 0x48, 0xc7, 0xc0, 0x64, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc7 + , 0x01, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x02, 0x00, 0x00 + , 0x00, 0x48, 0xc7, 0xc2, 0x03, 0x00, 0x00, 0x00, 0x49, 0xc7 + , 0xc2, 0x04, 0x00, 0x00, 0x00, 0x49, 0xc7, 0xc0, 0x05, 0x00 + , 0x00, 0x00, 0x49, 0xc7, 0xc1, 0x06, 0x00, 0x00, 0x00, 0x0f + , 0x05 + ] + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex i = + N.showHex (fromIntegral i :: Word64) "" + +-- Write a string (with a newline character) to standard output in the emulator +emuPutStrLn :: String -> Emulator () +emuPutStrLn = + lift . putStrLn + +hookSyscall :: SyscallHook () +hookSyscall uc _ = do + runEmulator $ do + readVals <- regReadBatch uc syscallABI + emuPutStrLn $ "syscall: {" + ++ intercalate ", " (map show readVals) + ++ "}" + return () + +hookCode :: CodeHook () +hookCode _ addr size _ = do + putStrLn $ "HOOK_CODE: 0x" ++ showHex addr ++ ", 0x" ++ + maybe "0" showHex size + +main :: IO () +main = do + result <- runEmulator $ do + uc <- open ArchX86 [Mode64] + + -- regWriteBatch + emuPutStrLn "regWriteBatch {200, 10, 11, 12, 13, 14, 15}" + regWriteBatch uc syscallABI vals + + readVals <- regReadBatch uc syscallABI + + emuPutStrLn $ "regReadBatch = {" + ++ intercalate ", " (map show readVals) + ++ "}" + + -- syscall + emuPutStrLn "running syscall shellcode" + syscallHookAdd uc hookSyscall () 1 0 + memMap uc base (0x1000) [ProtAll] + memWrite uc base code + let codeLen = fromIntegral $ BS.length code + start uc base (base + codeLen) Nothing Nothing + case result of + Right _ -> return () + Left err -> ucPerror err diff --git a/bindings/haskell/samples/SampleX86.hs b/bindings/haskell/samples/SampleX86.hs index e395ed75..5f4640e6 100644 --- a/bindings/haskell/samples/SampleX86.hs +++ b/bindings/haskell/samples/SampleX86.hs @@ -98,7 +98,7 @@ hookCode :: CodeHook () hookCode uc addr size _ = do runEmulator $ do emuPutStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ - ", instruction size = 0x" ++ (maybe "0" showHex size) + ", instruction size = 0x" ++ maybe "0" showHex size eflags <- regRead uc X86.Eflags emuPutStrLn $ ">>> --- EFLAGS is 0x" ++ showHex eflags diff --git a/bindings/haskell/src/Unicorn.hs b/bindings/haskell/src/Unicorn.hs index 19c07f8c..a605015d 100644 --- a/bindings/haskell/src/Unicorn.hs +++ b/bindings/haskell/src/Unicorn.hs @@ -25,6 +25,8 @@ module Unicorn -- * Register operations , regWrite , regRead + , regWriteBatch + , regReadBatch -- * Memory operations , MemoryPermission(..) @@ -140,13 +142,11 @@ stop uc = do -- | Write to register. regWrite :: Reg r => Engine -- ^ 'Unicorn' engine handle - -> r -- ^ Register ID to write to + -> r -- ^ Register to write to -> Int64 -- ^ Value to write to register -> Emulator () -- ^ An 'Error' on failure -regWrite uc regId value = do - err <- lift . alloca $ \ptr -> do - poke ptr value - ucRegWrite uc regId ptr +regWrite uc reg value = do + err <- lift $ ucRegWrite uc reg value if err == ErrOk then right () else @@ -155,16 +155,49 @@ regWrite uc regId value = do -- | Read register value. regRead :: Reg r => Engine -- ^ 'Unicorn' engine handle - -> r -- ^ Register ID to read from + -> r -- ^ Register to read from -> Emulator Int64 -- ^ The value read from the register on success, -- or an 'Error' on failure -regRead uc regId = do - (err, val) <- lift $ ucRegRead uc regId +regRead uc reg = do + (err, val) <- lift $ ucRegRead uc reg if err == ErrOk then right val else left err +-- | Write multiple register values. +regWriteBatch :: Reg r + => Engine -- ^ 'Unicorn' engine handle + -> [r] -- ^ List of registers to write to + -> [Int64] -- ^ List of values to write to the registers + -> Emulator () -- ^ An 'Error' on failure +regWriteBatch uc regs vals = do + err <- lift $ ucRegWriteBatch uc regs vals (length regs) + if err == ErrOk then + right () + else + left err + +-- | Read multiple register values. +regReadBatch :: Reg r + => Engine -- ^ 'Unicorn' engine handle + -> [r] -- ^ List of registers to read from + -> Emulator [Int64] -- ^ A list of register values on success, + -- or an 'Error' on failure +regReadBatch uc regs = do + -- Allocate an array of the given size + let size = length regs + result <- lift . allocaArray size $ \array -> do + err <- ucRegReadBatch uc regs array size + if err == ErrOk then + -- If ucRegReadBatch completed successfully, pack the contents of + -- the array into a list and return it + liftM Right (peekArray size array) + else + -- Otherwise return the error + return $ Left err + hoistEither result + ------------------------------------------------------------------------------- -- Memory operations ------------------------------------------------------------------------------- @@ -190,12 +223,12 @@ memRead :: Engine -- ^ 'Unicorn' engine handle -- an 'Error' on failure memRead uc address size = do -- Allocate an array of the given size - result <- lift . allocaArray size $ \ptr -> do - err <- ucMemRead uc address ptr size + result <- lift . allocaArray size $ \array -> do + err <- ucMemRead uc address array size if err == ErrOk then -- If ucMemRead completed successfully, pack the contents of the -- array into a ByteString and return it - liftM (Right . pack) (peekArray size ptr) + liftM (Right . pack) (peekArray size array) else -- Otherwise return the error return $ Left err diff --git a/bindings/haskell/src/Unicorn/Internal/Hook.chs b/bindings/haskell/src/Unicorn/Internal/Hook.chs index affed872..261adf12 100644 --- a/bindings/haskell/src/Unicorn/Internal/Hook.chs +++ b/bindings/haskell/src/Unicorn/Internal/Hook.chs @@ -314,7 +314,7 @@ marshalMemoryHook memoryHook = maybeValue = case memAccess of MemRead -> Nothing MemWrite -> Just $ fromIntegral value - _ -> undefined -- XX Handle this? + _ -> error "Invalid memory access" memoryHook uc memAccess address (fromIntegral size) maybeValue userData -- | Callback function for hooking memory reads. @@ -390,7 +390,7 @@ marshalMemoryEventHook eventMemoryHook = MemReadProt -> Nothing MemWriteUnmapped -> Just $ fromIntegral value MemWriteProt -> Just $ fromIntegral value - _ -> undefined -- XX Handle this? + _ -> error "Invalid memory access" res <- eventMemoryHook uc memAccess address (fromIntegral size) maybeValue userData return $ boolToInt res diff --git a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs index bfe8bd37..db975520 100644 --- a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs +++ b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs @@ -28,6 +28,8 @@ module Unicorn.Internal.Unicorn , ucEmuStop , ucRegWrite , ucRegRead + , ucRegWriteBatch + , ucRegReadBatch , ucMemWrite , ucMemRead , ucMemMap @@ -154,7 +156,8 @@ mkContext ptr = , `Word64' , `Word64' , `Int' - , `Int'} -> `Error' + , `Int' + } -> `Error' #} {# fun uc_emu_stop as ^ @@ -166,19 +169,37 @@ mkContext ptr = -- Register operations ------------------------------------------------------------------------------- -{# fun uc_reg_write as ^ +{# fun uc_reg_write_wrapper as ucRegWrite `Reg r' => { `Engine' , enumToNum `r' - , castPtr `Ptr Int64' + , withIntegral* `Int64' } -> `Error' #} -{# fun uc_reg_read as ^ +{# fun uc_reg_read_wrapper as ucRegRead `Reg r' => { `Engine' , enumToNum `r' - , allocaInt64ToVoid- `Int64' castPtrAndPeek* + , alloca- `Int64' castPtrAndPeek* + } -> `Error' +#} + +{# fun uc_reg_write_batch_wrapper as ucRegWriteBatch + `Reg r' => + { `Engine' + , withEnums* `[r]' + , integralListToArray* `[Int64]' + , `Int' + } -> `Error' +#} + +{# fun uc_reg_read_batch_wrapper as ucRegReadBatch + `Reg r' => + { `Engine' + , withEnums* `[r]' + , castPtr `Ptr Int64' + , `Int' } -> `Error' #} @@ -197,7 +218,8 @@ mkContext ptr = { `Engine' , `Word64' , castPtr `Ptr Word8' - , `Int'} -> `Error' + , `Int' + } -> `Error' #} {# fun uc_mem_map as ^ @@ -205,7 +227,8 @@ mkContext ptr = , `Word64' , `Int' , combineEnums `[MemoryPermission]' - } -> `Error' #} + } -> `Error' +#} {# fun uc_mem_unmap as ^ { `Engine' @@ -296,13 +319,32 @@ expandMemPerms perms = checkRWE _ [] = [] -allocaInt64ToVoid :: (Ptr () -> IO b) - -> IO b -allocaInt64ToVoid f = - alloca $ \(ptr :: Ptr Int64) -> poke ptr 0 >> f (castPtr ptr) +withIntegral :: (Integral a, Num b, Storable b) + => a + -> (Ptr b -> IO c) + -> IO c +withIntegral = + with . fromIntegral -withByteStringLen :: ByteString - -> ((Ptr (), CULong) -> IO a) - -> IO a +withByteStringLen :: Integral a + => ByteString + -> ((Ptr (), a) -> IO b) + -> IO b withByteStringLen bs f = useAsCStringLen bs $ \(ptr, len) -> f (castPtr ptr, fromIntegral len) + +withEnums :: Enum a + => [a] + -> (Ptr b -> IO c) + -> IO c +withEnums l f = + let ints :: [CInt] = map enumToNum l in + withArray ints $ \ptr -> f (castPtr ptr) + +integralListToArray :: (Integral a, Storable b, Num b) + => [a] + -> (Ptr b -> IO c) + -> IO c +integralListToArray l f = + let l' = map fromIntegral l in + withArray l' $ \array -> f array diff --git a/bindings/haskell/src/cbits/unicorn_wrapper.c b/bindings/haskell/src/cbits/unicorn_wrapper.c index 92251a7c..878518ee 100644 --- a/bindings/haskell/src/cbits/unicorn_wrapper.c +++ b/bindings/haskell/src/cbits/unicorn_wrapper.c @@ -1,3 +1,5 @@ +#include + #include "unicorn_wrapper.h" void uc_close_wrapper(uc_engine *uc) { @@ -7,6 +9,42 @@ void uc_close_wrapper(uc_engine *uc) { void uc_close_dummy(uc_engine *uc) { } +uc_err uc_reg_write_wrapper(uc_engine *uc, int regid, const int64_t *value) { + return uc_reg_write(uc, regid, (const void*) value); +} + +uc_err uc_reg_read_wrapper(uc_engine *uc, int regid, int64_t *value) { + return uc_reg_read(uc, regid, (void*) value); +} + +uc_err uc_reg_write_batch_wrapper(uc_engine *uc, int *regs, int64_t *vals, int count) { + void **valsPtr = malloc(sizeof(void*) * count); + int i; + + for (i = 0; i < count; ++i) { + valsPtr[i] = (void*) &vals[i]; + } + + uc_err ret = uc_reg_write_batch(uc, regs, (void *const*) valsPtr, count); + free(valsPtr); + + return ret; +} + +uc_err uc_reg_read_batch_wrapper(uc_engine *uc, int *regs, int64_t *vals, int count) { + void **valsPtr = malloc(sizeof(void*) * count); + int i; + + for (i = 0; i < count; ++i) { + valsPtr[i] = (void*) &vals[i]; + } + + uc_err ret = uc_reg_read_batch(uc, regs, valsPtr, count); + free(valsPtr); + + return ret; +} + void uc_free_wrapper(void *mem) { uc_free(mem); } diff --git a/bindings/haskell/src/include/unicorn_wrapper.h b/bindings/haskell/src/include/unicorn_wrapper.h index 77174750..31757163 100644 --- a/bindings/haskell/src/include/unicorn_wrapper.h +++ b/bindings/haskell/src/include/unicorn_wrapper.h @@ -1,6 +1,7 @@ #ifndef UNICORN_WRAPPER_H #define UNICORN_WRAPPER_H +#include #include /* @@ -13,6 +14,14 @@ void uc_close_wrapper(uc_engine *uc); */ void uc_close_dummy(uc_engine *uc); +/* + * Wrappers for register read/write functions that accept int64_t pointers. + */ +uc_err uc_reg_write_wrapper(uc_engine *uc, int regid, const int64_t *value); +uc_err uc_reg_read_wrapper(uc_engine *uc, int regid, int64_t *value); +uc_err uc_reg_write_batch_wrapper(uc_engine *uc, int *regs, int64_t *vals, int count); +uc_err uc_reg_read_batch_wrapper(uc_engine *uc, int *regs, int64_t *vals, int count); + /* * Wrap Unicorn's uc_free function and ignore the returned error code. */ From d52f85d16e0c1165274dd43ad6e9fd25740a4ee8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 26 Feb 2017 09:39:11 +0800 Subject: [PATCH 07/15] add back missing ELF symbols reported in #766 --- qemu/include/elf.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qemu/include/elf.h b/qemu/include/elf.h index 61dd1fb9..b56c20a1 100644 --- a/qemu/include/elf.h +++ b/qemu/include/elf.h @@ -126,11 +126,15 @@ /* Bits present in AT_HWCAP for Sparc. */ #define HWCAP_SPARC_VIS3 0x00020000 +/* Bits present in AT_HWCAP for PowerPC. */ +#define PPC_FEATURE_ARCH_2_06 0x00000100 + /* Symbolic values for the entries in the auxiliary table put on the initial stack */ #define AT_PLATFORM 15 /* string identifying CPU for optimizations */ #define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ - +#define AT_DCACHEBSIZE 19 /* data cache block size */ +#define AT_ICACHEBSIZE 20 /* instruction cache block size */ /* * 68k ELF relocation types From e65fef70dc5a3ad75574dbd617bf4b04038ab755 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 26 Feb 2017 09:47:40 +0800 Subject: [PATCH 08/15] add missing TCG context arg to few functions in tcg.c. see #766 --- qemu/tcg/tcg.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/qemu/tcg/tcg.c b/qemu/tcg/tcg.c index 6c0a09cf..e5fe9167 100644 --- a/qemu/tcg/tcg.c +++ b/qemu/tcg/tcg.c @@ -715,8 +715,8 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, int is_64bit = sizemask & (1 << (i+1)*2); if (is_64bit) { TCGv_i64 orig = MAKE_TCGV_I64(args[i]); - TCGv_i32 h = tcg_temp_new_i32(); - TCGv_i32 l = tcg_temp_new_i32(); + TCGv_i32 h = tcg_temp_new_i32(s); + TCGv_i32 l = tcg_temp_new_i32(s); tcg_gen_extr_i64_i32(l, h, orig); split_args[real_args++] = GET_TCGV_I32(h); split_args[real_args++] = GET_TCGV_I32(l); @@ -736,11 +736,11 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, TCGv_i64 temp = tcg_temp_new_i64(s); TCGv_i64 orig = MAKE_TCGV_I64(args[i]); if (is_signed) { - tcg_gen_ext32s_i64(temp, orig); + tcg_gen_ext32s_i64(s, temp, orig); } else { - tcg_gen_ext32u_i64(temp, orig); + tcg_gen_ext32u_i64(s, temp, orig); } - args[i] = GET_TCGV_I64(temp); + args[i] = GET_TCGV_I64(s, temp); } } #endif /* TCG_TARGET_EXTEND_ARGS */ @@ -832,8 +832,8 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, if (is_64bit) { TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]); TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]); - tcg_temp_free_i32(h); - tcg_temp_free_i32(l); + tcg_temp_free_i32(s, h); + tcg_temp_free_i32(s, l); } else { real_args++; } @@ -843,15 +843,15 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, Note that describing these as TCGv_i64 eliminates an unnecessary zero-extension that tcg_gen_concat_i32_i64 would create. */ tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth); - tcg_temp_free_i64(retl); - tcg_temp_free_i64(reth); + tcg_temp_free_i64(s, retl); + tcg_temp_free_i64(s, reth); } #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 for (i = 0; i < nargs; ++i) { int is_64bit = sizemask & (1 << (i+1)*2); if (!is_64bit) { TCGv_i64 temp = MAKE_TCGV_I64(args[i]); - tcg_temp_free_i64(temp); + tcg_temp_free_i64(s, temp); } } #endif /* TCG_TARGET_EXTEND_ARGS */ From 70db329749c97d8a5a5ce72893b5b2bb45131c3e Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 26 Feb 2017 10:50:18 +0800 Subject: [PATCH 09/15] regress: ignore arm_enable_vfp --- tests/regress/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/regress/.gitignore b/tests/regress/.gitignore index 00144a35..ca97ad9b 100644 --- a/tests/regress/.gitignore +++ b/tests/regress/.gitignore @@ -1,5 +1,6 @@ !*.c +arm_enable_vfp map_crash sigill sigill2 From c3808179e1dda77073d577ef52ef6d3f85d08700 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 26 Feb 2017 15:22:24 +0800 Subject: [PATCH 10/15] another attempt to fix #766 --- qemu/aarch64.h | 1 + qemu/arm.h | 1 + qemu/header_gen.py | 1 + qemu/m68k.h | 1 + qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/powerpc.h | 1 + qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/tcg/tcg.c | 2 +- qemu/x86_64.h | 1 + 13 files changed, 13 insertions(+), 1 deletion(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 6cb47c34..7a7a5ea7 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_AARCH64_H #define UNICORN_AUTOGEN_AARCH64_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_aarch64 +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_aarch64 #define use_idiv_instructions_rt use_idiv_instructions_rt_aarch64 #define tcg_target_deposit_valid tcg_target_deposit_valid_aarch64 #define helper_power_down helper_power_down_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index 5ab27471..80225bdd 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_ARM_H #define UNICORN_AUTOGEN_ARM_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_arm +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_arm #define use_idiv_instructions_rt use_idiv_instructions_rt_arm #define tcg_target_deposit_valid tcg_target_deposit_valid_arm #define helper_power_down helper_power_down_arm diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 0561817d..047f6358 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -8,6 +8,7 @@ import sys symbols = ( 'aarch64_tb_set_jmp_target', + 'ppc_tb_set_jmp_target', 'use_idiv_instructions_rt', 'tcg_target_deposit_valid', 'helper_power_down', diff --git a/qemu/m68k.h b/qemu/m68k.h index 9a265549..f40a8dc4 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_M68K_H #define UNICORN_AUTOGEN_M68K_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_m68k +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_m68k #define use_idiv_instructions_rt use_idiv_instructions_rt_m68k #define tcg_target_deposit_valid tcg_target_deposit_valid_m68k #define helper_power_down helper_power_down_m68k diff --git a/qemu/mips.h b/qemu/mips.h index 57bb375a..1b8e9e2b 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_MIPS_H #define UNICORN_AUTOGEN_MIPS_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_mips #define use_idiv_instructions_rt use_idiv_instructions_rt_mips #define tcg_target_deposit_valid tcg_target_deposit_valid_mips #define helper_power_down helper_power_down_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index a6af4eeb..06b30666 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_MIPS64_H #define UNICORN_AUTOGEN_MIPS64_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips64 +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_mips64 #define use_idiv_instructions_rt use_idiv_instructions_rt_mips64 #define tcg_target_deposit_valid tcg_target_deposit_valid_mips64 #define helper_power_down helper_power_down_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index c453400d..87cc74c8 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_MIPS64EL_H #define UNICORN_AUTOGEN_MIPS64EL_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips64el +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_mips64el #define use_idiv_instructions_rt use_idiv_instructions_rt_mips64el #define tcg_target_deposit_valid tcg_target_deposit_valid_mips64el #define helper_power_down helper_power_down_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 4ad7be8d..a8a3fb4f 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_MIPSEL_H #define UNICORN_AUTOGEN_MIPSEL_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mipsel +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_mipsel #define use_idiv_instructions_rt use_idiv_instructions_rt_mipsel #define tcg_target_deposit_valid tcg_target_deposit_valid_mipsel #define helper_power_down helper_power_down_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 80520561..fd831d98 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_POWERPC_H #define UNICORN_AUTOGEN_POWERPC_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_powerpc +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_powerpc #define use_idiv_instructions_rt use_idiv_instructions_rt_powerpc #define tcg_target_deposit_valid tcg_target_deposit_valid_powerpc #define helper_power_down helper_power_down_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index b3c6d853..fda21bf4 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_SPARC_H #define UNICORN_AUTOGEN_SPARC_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_sparc +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_sparc #define use_idiv_instructions_rt use_idiv_instructions_rt_sparc #define tcg_target_deposit_valid tcg_target_deposit_valid_sparc #define helper_power_down helper_power_down_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index c8860863..aaafd634 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_SPARC64_H #define UNICORN_AUTOGEN_SPARC64_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_sparc64 +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_sparc64 #define use_idiv_instructions_rt use_idiv_instructions_rt_sparc64 #define tcg_target_deposit_valid tcg_target_deposit_valid_sparc64 #define helper_power_down helper_power_down_sparc64 diff --git a/qemu/tcg/tcg.c b/qemu/tcg/tcg.c index e5fe9167..7715aa66 100644 --- a/qemu/tcg/tcg.c +++ b/qemu/tcg/tcg.c @@ -740,7 +740,7 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret, } else { tcg_gen_ext32u_i64(s, temp, orig); } - args[i] = GET_TCGV_I64(s, temp); + args[i] = GET_TCGV_I64(temp); } } #endif /* TCG_TARGET_EXTEND_ARGS */ diff --git a/qemu/x86_64.h b/qemu/x86_64.h index df86439d..71025141 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -2,6 +2,7 @@ #ifndef UNICORN_AUTOGEN_X86_64_H #define UNICORN_AUTOGEN_X86_64_H #define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_x86_64 +#define ppc_tb_set_jmp_target ppc_tb_set_jmp_target_x86_64 #define use_idiv_instructions_rt use_idiv_instructions_rt_x86_64 #define tcg_target_deposit_valid tcg_target_deposit_valid_x86_64 #define helper_power_down helper_power_down_x86_64 From 117b48c33c44a1e1897d2dc0ac06d63b7652963a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 26 Feb 2017 16:52:06 +0800 Subject: [PATCH 11/15] bindings: use diff -u in Makefile --- bindings/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/Makefile b/bindings/Makefile index 14e88df8..1e3c179a 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -42,7 +42,7 @@ python: $(ENV_VARS) python python/$(@:%.txt=%) > $@ %.py.test: %.c.txt %.py.txt - $(DIFF) $(@:%.py.test=%.c.txt) $(@:%.py.test=%.py.txt) + $(DIFF) -u $(@:%.py.test=%.c.txt) $(@:%.py.test=%.py.txt) clean: # rm -rf *.txt From b3a5eae81c47d46c3a6beaf90050c81de9841f5e Mon Sep 17 00:00:00 2001 From: stevielavern Date: Tue, 7 Mar 2017 14:29:34 +0100 Subject: [PATCH 12/15] uc_reg_read & uc_reg_write now support ARM64 Neon registers (#774) * uc_reg_read & uc_reg_write now support ARM64 Neon registers * Do not reuse uc_x86_xmm for uc_arm64_neon128. TODO: refactor both classes to use the same parent. --- bindings/python/unicorn/unicorn.py | 25 ++++++++++++++++++++-- qemu/target-arm/unicorn_aarch64.c | 33 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index e2cb6a5d..fa50ad1f 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -9,7 +9,7 @@ import os.path import sys import weakref -from . import x86_const, unicorn_const as uc +from . import x86_const, arm64_const, unicorn_const as uc if not hasattr(sys.modules[__name__], "__file__"): __file__ = inspect.getfile(inspect.currentframe()) @@ -223,6 +223,13 @@ class uc_x86_xmm(ctypes.Structure): ("high_qword", ctypes.c_uint64), ] +class uc_arm64_neon128(ctypes.Structure): + """128-bit neon register""" + _fields_ = [ + ("low_qword", ctypes.c_uint64), + ("high_qword", ctypes.c_uint64), + ] + # Subclassing ref to allow property assignment. class UcRef(weakref.ref): pass @@ -317,6 +324,14 @@ class Uc(object): raise UcError(status) return reg.value + if self._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): + reg = uc_arm64_neon128() + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != uc.UC_ERR_OK: + raise UcError(status) + return reg.low_qword | (reg.high_qword << 64) + # read to 64bit number to be safe reg = ctypes.c_uint64(0) status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) @@ -349,6 +364,12 @@ class Uc(object): reg.rid = value[0] reg.value = value[1] + if self._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): + reg = uc_arm64_neon128() + reg.low_qword = value & 0xffffffffffffffff + reg.high_qword = value >> 64 + if reg is None: # convert to 64bit number to be safe reg = ctypes.c_uint64(value) @@ -364,7 +385,7 @@ class Uc(object): # write to MSR - X86 only def msr_write(self, msr_id, value): return self.reg_write(x86_const.UC_X86_REG_MSR, (msr_id, value)) - + # read data from memory def mem_read(self, address, size): data = ctypes.create_string_buffer(size) diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index 9955b42e..5b9980f1 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -50,10 +50,27 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int co for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; + // V & Q registers are the same + if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) { + regid += UC_ARM64_REG_Q0 - UC_ARM64_REG_V0; + } if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) { *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; } else if (regid >= UC_ARM64_REG_W0 && regid <= UC_ARM64_REG_W30) { *(int32_t *)value = READ_DWORD(ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_W0]); + } else if (regid >= UC_ARM64_REG_Q0 && regid <= UC_ARM64_REG_Q31) { + float64 *dst = (float64*) value; + uint32_t reg_index = 2*(regid - UC_ARM64_REG_Q0); + dst[0] = ARM_CPU(uc, mycpu)->env.vfp.regs[reg_index]; + dst[1] = ARM_CPU(uc, mycpu)->env.vfp.regs[reg_index+1]; + } else if (regid >= UC_ARM64_REG_D0 && regid <= UC_ARM64_REG_D31) { + *(float64*)value = ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_D0)]; + } else if (regid >= UC_ARM64_REG_S0 && regid <= UC_ARM64_REG_S31) { + *(int32_t*)value = READ_DWORD(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_S0)]); + } else if (regid >= UC_ARM64_REG_H0 && regid <= UC_ARM64_REG_H31) { + *(int16_t*)value = READ_WORD(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_H0)]); + } else if (regid >= UC_ARM64_REG_B0 && regid <= UC_ARM64_REG_B31) { + *(int8_t*)value = READ_BYTE_L(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_B0)]); } else { switch(regid) { default: break; @@ -84,10 +101,26 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; + if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) { + regid += UC_ARM64_REG_Q0 - UC_ARM64_REG_V0; + } if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) { ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value; } else if (regid >= UC_ARM64_REG_W0 && regid <= UC_ARM64_REG_W30) { WRITE_DWORD(ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_W0], *(uint32_t *)value); + } else if (regid >= UC_ARM64_REG_Q0 && regid <= UC_ARM64_REG_Q31) { + float64 *src = (float64*) value; + uint32_t reg_index = 2*(regid - UC_ARM64_REG_Q0); + ARM_CPU(uc, mycpu)->env.vfp.regs[reg_index] = src[0]; + ARM_CPU(uc, mycpu)->env.vfp.regs[reg_index+1] = src[1]; + } else if (regid >= UC_ARM64_REG_D0 && regid <= UC_ARM64_REG_D31) { + ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_D0)] = * (float64*) value; + } else if (regid >= UC_ARM64_REG_S0 && regid <= UC_ARM64_REG_S31) { + WRITE_DWORD(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_S0)], *(int32_t*) value); + } else if (regid >= UC_ARM64_REG_H0 && regid <= UC_ARM64_REG_H31) { + WRITE_WORD(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_H0)], *(int16_t*) value); + } else if (regid >= UC_ARM64_REG_B0 && regid <= UC_ARM64_REG_B31) { + WRITE_BYTE_L(ARM_CPU(uc, mycpu)->env.vfp.regs[2*(regid - UC_ARM64_REG_B0)], *(int8_t*) value); } else { switch(regid) { default: break; From 2749b8412e51c6915f2f3587116d2fe533a27428 Mon Sep 17 00:00:00 2001 From: Matt Thomas Date: Tue, 7 Mar 2017 19:40:30 -0500 Subject: [PATCH 13/15] fix register widths for MIPS64 reg_read/write (#775) * fix register widths for MIPS64 reg_read/write * fix preprocessor typedef error for qemu/target-mips --- qemu/target-mips/unicorn.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 3ca24390..71f43608 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -18,6 +18,12 @@ const int MIPS_REGS_STORAGE_SIZE = offsetof(CPUMIPSState, tlb_table); #endif #endif +#ifdef TARGET_MIPS64 +typedef uint64_t mipsreg_t; +#else +typedef uint32_t mipsreg_t; +#endif + static uint64_t mips_mem_redirect(uint64_t address) { // kseg0 range masks off high address bit @@ -89,7 +95,7 @@ int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int cou switch(regid) { default: break; case UC_MIPS_REG_PC: - *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.PC; + *(mipsreg_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.PC; break; } } @@ -107,12 +113,12 @@ int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, unsigned int regid = regs[i]; const void *value = vals[i]; if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) - MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(uint32_t *)value; + MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(mipsreg_t *)value; else { switch(regid) { default: break; case UC_MIPS_REG_PC: - MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value; + MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(mipsreg_t *)value; // force to quit execution and flush TB uc->quit_request = true; uc_emu_stop(uc); From 0150ca24b1770ada58377817bc9c2c8b210a4da3 Mon Sep 17 00:00:00 2001 From: feliam Date: Thu, 9 Mar 2017 11:28:03 -0300 Subject: [PATCH 14/15] Add support for ARM application flags - APSR register (#776) --- bindings/python/sample_arm.py | 3 ++- qemu/target-arm/unicorn_arm.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bindings/python/sample_arm.py b/bindings/python/sample_arm.py index 402ba57a..5fae6b6b 100755 --- a/bindings/python/sample_arm.py +++ b/bindings/python/sample_arm.py @@ -41,7 +41,8 @@ def test_arm(): mu.reg_write(UC_ARM_REG_R0, 0x1234) mu.reg_write(UC_ARM_REG_R2, 0x6789) mu.reg_write(UC_ARM_REG_R3, 0x3333) - + mu.reg_write(UC_ARM_REG_APSR, 0xFFFFFFFF) #All application flags turned on + # tracing all basic blocks with customized callback mu.hook_add(UC_HOOK_BLOCK, hook_block) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 7bb985e2..1dffb432 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -62,6 +62,9 @@ int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int coun *(float64 *)value = ARM_CPU(uc, mycpu)->env.vfp.regs[regid - UC_ARM_REG_D0]; else { switch(regid) { + case UC_ARM_REG_APSR: + *(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env) & CPSR_NZCV; + break; case UC_ARM_REG_CPSR: *(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env); break; @@ -107,6 +110,9 @@ int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, i ARM_CPU(uc, mycpu)->env.vfp.regs[regid - UC_ARM_REG_D0] = *(float64 *)value; else { switch(regid) { + case UC_ARM_REG_APSR: + cpsr_write(&ARM_CPU(uc, mycpu)->env, *(uint32_t *)value, CPSR_NZCV); + break; case UC_ARM_REG_CPSR: cpsr_write(&ARM_CPU(uc, mycpu)->env, *(uint32_t *)value, ~0); break; From f2e75422e8cfce5d2cbc21d7641a81c6af6e080d Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 10 Mar 2017 21:02:29 +0800 Subject: [PATCH 15/15] samples: add all sample code to sample_all.sh --- samples/sample_all.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/samples/sample_all.sh b/samples/sample_all.sh index 502171d4..026e0107 100755 --- a/samples/sample_all.sh +++ b/samples/sample_all.sh @@ -42,3 +42,18 @@ if test -e $DIR/sample_m68k; then echo "==========================" $DIR/sample_m68k fi + +if test -e $DIR/mem_apis; then + echo "==========================" + $DIR/mem_apis +fi + +if test -e $DIR/sample_batch_reg; then + echo "==========================" + $DIR/sample_batch_reg +fi + +if test -e $DIR/sample_x86_32_gdt_and_seg_regs; then + echo "==========================" + $DIR/sample_x86_32_gdt_and_seg_regs +fi