diff --git a/.github/workflows/build-uc2.yml b/.github/workflows/build-uc2.yml index 5f34b64f..7ee95894 100644 --- a/.github/workflows/build-uc2.yml +++ b/.github/workflows/build-uc2.yml @@ -328,9 +328,9 @@ jobs: brew install p7zip cmake ninja mkdir build mkdir instdir - cmake . -DCMAKE_TOOLCHAIN_FILE="$ANDROID_HOME/ndk/25.0.8775105/build/cmake/android.toolchain.cmake" \ + cmake . -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK/build/cmake/android.toolchain.cmake" \ -DANDROID_PLATFORM=android-28 \ - -DANDROID_NDK="$ANDROID_HOME/ndk/25.0.8775105" \ + -DANDROID_NDK="$ANDROID_NDK" \ -DANDROID_ABI=${{ matrix.config.arch }} \ -DOLP_SDK_ENABLE_TESTING=NO \ -DOLP_SDK_BUILD_EXAMPLES=ON \ diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 51dfb9fe..f8948d62 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -26,7 +26,7 @@ ROOT_DIR = os.path.dirname(os.path.realpath(__file__)) LIBS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'lib') HEADERS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'include') SRC_DIR = os.path.join(ROOT_DIR, 'src') -UC_DIR = os.path.join(ROOT_DIR, '../..') +UC_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..') BUILD_DIR = os.path.join(UC_DIR, 'build_python') VERSION = "2.0.0" @@ -60,6 +60,9 @@ def copy_sources(): shutil.copytree(os.path.join(ROOT_DIR, '../../include'), os.path.join(SRC_DIR, 'include/')) # make -> configure -> clean -> clean tests fails unless tests is present shutil.copytree(os.path.join(ROOT_DIR, '../../tests'), os.path.join(SRC_DIR, 'tests/')) + shutil.copytree(os.path.join(ROOT_DIR, '../../samples'), os.path.join(SRC_DIR, 'samples/')) + shutil.copytree(os.path.join(ROOT_DIR, '../../glib_compat'), os.path.join(SRC_DIR, 'glib_compat/')) + try: # remove site-specific configuration file # might not exist @@ -69,6 +72,7 @@ def copy_sources(): src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.[ch]"))) src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.mk"))) + src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.cmake"))) src.extend(glob.glob(os.path.join(ROOT_DIR, "../../LICENSE*"))) src.extend(glob.glob(os.path.join(ROOT_DIR, "../../README.md"))) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 9dc308b3..a79519c4 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -315,7 +315,6 @@ class RegStateManager: raise NotImplementedError - def _do_reg_write(self, reg_id: int, reg_obj) -> int: """Private register write implementation. Must be implemented by the mixin object @@ -323,7 +322,6 @@ class RegStateManager: raise NotImplementedError - def _reg_read(self, reg_id: int, regtype, *args): """Register read helper method. """ @@ -336,7 +334,6 @@ class RegStateManager: return reg.value - def _reg_write(self, reg_id: int, regtype, value) -> None: """Register write helper method. """ @@ -347,7 +344,6 @@ class RegStateManager: if status != uc.UC_ERR_OK: raise UcError(status, reg_id) - def reg_read(self, reg_id: int, aux: Any = None): """Read architectural register value. @@ -362,7 +358,6 @@ class RegStateManager: return self._reg_read(reg_id, self._DEFAULT_REGTYPE) - def reg_write(self, reg_id: int, value) -> None: """Write to architectural register. @@ -439,7 +434,6 @@ class Uc(RegStateManager): return (uc_maj, uc_min) == (bnd_maj, bnd_min) - def __new__(cls, arch: int, mode: int): # verify version compatibility with the core before doing anything if not Uc.__is_compliant(): @@ -480,7 +474,6 @@ class Uc(RegStateManager): # return the appropriate unicorn subclass type return super(Uc, cls).__new__(subclass) - def __init__(self, arch: int, mode: int) -> None: """Initialize a Unicorn engine instance. @@ -511,7 +504,6 @@ class Uc(RegStateManager): # this instance undergoes garbage collection. self.__finalizer = weakref.finalize(self, Uc.release_handle, self._uch) - @staticmethod def release_handle(uch: uc_engine) -> None: # this method and its arguments must not have any reference to the Uc instance being @@ -568,7 +560,6 @@ class Uc(RegStateManager): if status != uc.UC_ERR_OK: raise UcError(status) - ########################### # CPU state accessors # ########################### @@ -580,7 +571,6 @@ class Uc(RegStateManager): return uclib.uc_reg_read(self._uch, reg_id, reg_obj) - def _do_reg_write(self, reg_id: int, reg_obj) -> int: """Private register write implementation. Do not call directly. @@ -588,7 +578,6 @@ class Uc(RegStateManager): return uclib.uc_reg_write(self._uch, reg_id, reg_obj) - ########################### # Memory management # ########################### @@ -611,7 +600,6 @@ class Uc(RegStateManager): if status != uc.UC_ERR_OK: raise UcError(status) - def mem_map_ptr(self, address: int, size: int, perms: int, ptr: int) -> None: """Map a memory range and point to existing data on host memory. @@ -631,7 +619,6 @@ class Uc(RegStateManager): if status != uc.UC_ERR_OK: raise UcError(status) - def mem_unmap(self, address: int, size: int) -> None: """Reclaim a mapped memory range. @@ -652,7 +639,6 @@ class Uc(RegStateManager): # might be splitted by 'map_protect' after they were mapped, so the # (start, end) tuple may not be suitable for retrieving the callbacks - def mem_protect(self, address: int, size: int, perms: int = uc.UC_PROT_ALL) -> None: """Modify access protection bitmask of a mapped memory range. @@ -671,7 +657,6 @@ class Uc(RegStateManager): if status != uc.UC_ERR_OK: raise UcError(status) - def mmio_map(self, address: int, size: int, read_cb: Optional[UC_MMIO_READ_TYPE], user_data_read: Any, write_cb: Optional[UC_MMIO_WRITE_TYPE], user_data_write: Any) -> None: @@ -702,7 +687,6 @@ class Uc(RegStateManager): self._mmio_callbacks[(rng_starts, rng_ends)] = (read_cb_fptr, write_cb_fptr) - def mem_regions(self) -> Iterator[Tuple[int, int, int]]: """Iterate through mapped memory regions. @@ -725,7 +709,6 @@ class Uc(RegStateManager): finally: uclib.uc_free(regions) - def mem_read(self, address: int, size: int) -> bytearray: """Read data from emulated memory subsystem. @@ -746,7 +729,6 @@ class Uc(RegStateManager): return bytearray(data) - def mem_write(self, address: int, data: bytes) -> None: """Write data to emulated memory subsystem. @@ -763,7 +745,6 @@ class Uc(RegStateManager): if status != uc.UC_ERR_OK: raise UcError(status, address, size) - ########################### # Event hooks management # ########################### @@ -794,7 +775,6 @@ class Uc(RegStateManager): return handle.value - def hook_add(self, htype: int, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0, aux1: int = 0, aux2: int = 0) -> int: """Hook emulated events of a certain type. @@ -913,7 +893,6 @@ class Uc(RegStateManager): return self.__do_hook_add(htype, fptr, begin, end, *aux) - def hook_del(self, handle: int) -> None: """Remove an existing hook. @@ -929,7 +908,6 @@ class Uc(RegStateManager): del self._callbacks[handle] - def query(self, prop: int) -> int: """Query an internal Unicorn property. @@ -947,7 +925,6 @@ class Uc(RegStateManager): return result.value - def context_save(self) -> UcContext: context = UcContext(self._uch, self._arch, self._mode) status = uclib.uc_context_save(self._uch, context.context) @@ -957,21 +934,18 @@ class Uc(RegStateManager): return context - def context_update(self, context: UcContext) -> None: status = uclib.uc_context_save(self._uch, context.context) if status != uc.UC_ERR_OK: raise UcError(status) - def context_restore(self, context: UcContext) -> None: status = uclib.uc_context_restore(self._uch, context.context) if status != uc.UC_ERR_OK: raise UcError(status) - @staticmethod def __ctl_encode(ctl: int, op: int, nargs: int) -> int: assert nargs and (nargs & ~0b1111) == 0 @@ -979,7 +953,6 @@ class Uc(RegStateManager): return (op << 30) | (nargs << 26) | ctl - def ctl(self, ctl: int, op: int, *args): code = Uc.__ctl_encode(ctl, op, len(args)) @@ -988,10 +961,8 @@ class Uc(RegStateManager): if status != uc.UC_ERR_OK: raise UcError(status) - Arg = Tuple[Type, Optional[int]] - def __ctl_r(self, ctl: int, arg0: Arg): atype, _ = arg0 carg = atype() @@ -1000,13 +971,11 @@ class Uc(RegStateManager): return carg.value - def __ctl_w(self, ctl: int, *args: Arg): cargs = (atype(avalue) for atype, avalue in args) self.ctl(ctl, uc.UC_CTL_IO_WRITE, *cargs) - def __ctl_wr(self, ctl: int, arg0: Arg, arg1: Arg): atype, avalue = arg0 carg0 = atype(avalue) @@ -1018,49 +987,41 @@ class Uc(RegStateManager): return carg1 - def ctl_get_mode(self) -> int: return self.__ctl_r(uc.UC_CTL_UC_MODE, (ctypes.c_int, None) ) - def ctl_get_page_size(self) -> int: return self.__ctl_r(uc.UC_CTL_UC_PAGE_SIZE, (ctypes.c_uint32, None) ) - def ctl_set_page_size(self, val: int) -> None: self.__ctl_w(uc.UC_CTL_UC_PAGE_SIZE, (ctypes.c_uint32, val) ) - def ctl_get_arch(self) -> int: return self.__ctl_r(uc.UC_CTL_UC_ARCH, (ctypes.c_int, None) ) - def ctl_get_timeout(self) -> int: return self.__ctl_r(uc.UC_CTL_UC_TIMEOUT, (ctypes.c_uint64, None) ) - def ctl_exits_enabled(self, val: bool) -> None: self.__ctl_w(uc.UC_CTL_UC_USE_EXITS, (ctypes.c_int, val) ) - def ctl_get_exits_cnt(self) -> int: return self.__ctl_r(uc.UC_CTL_UC_EXITS_CNT, (ctypes.c_size_t, None) ) - def ctl_get_exits(self) -> Sequence[int]: l = self.ctl_get_exits_cnt() arr = (ctypes.c_uint64 * l)() @@ -1069,7 +1030,6 @@ class Uc(RegStateManager): return tuple(i for i in arr) - def ctl_set_exits(self, exits: Sequence[int]) -> None: arr = (ctypes.c_uint64 * len(exits))() @@ -1078,33 +1038,28 @@ class Uc(RegStateManager): self.ctl(uc.UC_CTL_UC_EXITS, uc.UC_CTL_IO_WRITE, ctypes.cast(arr, ctypes.c_void_p), ctypes.c_size_t(len(exits))) - def ctl_get_cpu_model(self) -> int: return self.__ctl_r(uc.UC_CTL_CPU_MODEL, (ctypes.c_int, None) ) - def ctl_set_cpu_model(self, val: int) -> None: self.__ctl_w(uc.UC_CTL_CPU_MODEL, (ctypes.c_int, val) ) - def ctl_remove_cache(self, addr: int, end: int) -> None: self.__ctl_w(uc.UC_CTL_TB_REMOVE_CACHE, (ctypes.c_uint64, addr), (ctypes.c_uint64, end) ) - def ctl_request_cache(self, addr: int): return self.__ctl_wr(uc.UC_CTL_TB_REQUEST_CACHE, (ctypes.c_uint64, addr), (uc_tb, None) ) - def ctl_flush_tb(self) -> None: self.__ctl_w(uc.UC_CTL_TB_FLUSH) @@ -1134,12 +1089,11 @@ class UcContext(RegStateManager): @property def arch(self) -> int: return self._arch - + @property def mode(self) -> int: return self._mode - # RegStateManager mixin method implementation def _do_reg_read(self, reg_id: int, reg_obj) -> int: """Private register read implementation. @@ -1147,7 +1101,6 @@ class UcContext(RegStateManager): return uclib.uc_context_reg_read(self._context, reg_id, reg_obj) - # RegStateManager mixin method implementation def _do_reg_write(self, reg_id: int, reg_obj) -> int: """Private register write implementation. @@ -1155,12 +1108,10 @@ class UcContext(RegStateManager): return uclib.uc_context_reg_write(self._context, reg_id, reg_obj) - # Make UcContext picklable def __getstate__(self): return bytes(self), self.size, self.arch, self.mode - def __setstate__(self, state) -> None: context, size, arch, mode = state @@ -1172,11 +1123,9 @@ class UcContext(RegStateManager): # __init__ won't be invoked, so we are safe to set it here. self._to_free = False - def __bytes__(self) -> bytes: return ctypes.string_at(self.context, self.size) - def __del__(self) -> None: # We need this property since we shouldn't free it if the object is constructed from pickled bytes. if self._to_free: diff --git a/docs/COMPILE.md b/docs/COMPILE.md index c2e475d5..ad16bcdf 100644 --- a/docs/COMPILE.md +++ b/docs/COMPILE.md @@ -128,3 +128,17 @@ mkdir build; cd build cmake .. -DCMAKE_C_COMPILER=gcc-arm-linux-gnueabihf make ``` + +## Building from vcpkg + +The Unicorn port in vcpkg is kept up to date by Microsoft team members and community contributors. The url of vcpkg is: https://github.com/Microsoft/vcpkg . You can download and install unicorn using the vcpkg dependency manager: + +```bash +git clone https://github.com/Microsoft/vcpkg.git +cd vcpkg +./bootstrap-vcpkg.sh # ./bootstrap-vcpkg.bat for Windows +./vcpkg integrate install +./vcpkg install unicorn +``` + +If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. diff --git a/docs/FAQ.md b/docs/FAQ.md index 4bb568ce..20bb58e2 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -30,6 +30,13 @@ On x86, all available instructions are: `in` `out` `syscall` `sysenter` `cpuid`. If you are still using Unicorn1, please upgrade to Unicorn2 for better support. +## Memory hooks get called multiple times for a single instruction + +There are several possibilities, e.g.: + +- The instruction might access memory multiple times like `rep stos` in x86. +- The address to access is bad-aligned and thus the MMU emulation will split the access into several aligned memory access. In worst cases on some arch, it leads to byte by byte access. + ## I can't recover from unmapped read/write even I return `true` in the hook, why? This is a minor change in memory hooks behavior between Unicorn1 and Unicorn2. To gracefully recover from memory read/write error, you have to map the invalid memory before you return true. @@ -38,9 +45,11 @@ It is due to the fact that, if users return `true` without memory mapping set up See the [sample](https://github.com/unicorn-engine/unicorn/blob/c05fbb7e63aed0b60fc2888e08beceb17bce8ac4/samples/sample_x86.c#L1379-L1393) for details. -## My MIPS emulation gets weird read/write error and CPU exceptions. +## My emulation gets weird read/write error and CPU exceptions. -Note you might have an address that falls in MIPS `kseg` segments. In that case, MMU is bypassed and you have to make sure the corresponding physical memory is mapped. See [#217](https://github.com/unicorn-engine/unicorn/issues/217), [#1371](https://github.com/unicorn-engine/unicorn/issues/1371), [#1550](https://github.com/unicorn-engine/unicorn/issues/1371). +For MIPS, you might have an address that falls in MIPS `kseg` segments. In that case, MMU is bypassed and you have to make sure the corresponding physical memory is mapped. See [#217](https://github.com/unicorn-engine/unicorn/issues/217), [#1371](https://github.com/unicorn-engine/unicorn/issues/1371), [#1550](https://github.com/unicorn-engine/unicorn/issues/1371). + +For ARM, you might have an address that falls in some non-executable segments. For example, for m-class ARM cpu, some memory area is not executable according to [the ARM document](https://developer.arm.com/documentation/ddi0403/d/System-Level-Architecture/System-Address-Map/The-system-address-map?lang=en). ## KeyboardInterrupt is not raised during `uc.emu_start` diff --git a/qemu/exec.c b/qemu/exec.c index 719895a3..2a664788 100644 --- a/qemu/exec.c +++ b/qemu/exec.c @@ -1087,8 +1087,12 @@ RAMBlock *qemu_ram_alloc_from_ptr(struct uc_struct *uc, ram_addr_t size, void *h RAMBlock *new_block; ram_addr_t max_size = size; - size = HOST_PAGE_ALIGN(uc, size); - max_size = HOST_PAGE_ALIGN(uc, max_size); + // Don't resize pre-alloced memory as they are given by users. + if (!host) { + size = HOST_PAGE_ALIGN(uc, size); + max_size = HOST_PAGE_ALIGN(uc, max_size); + } + new_block = g_malloc0(sizeof(*new_block)); if (new_block == NULL) return NULL; diff --git a/qemu/include/qemu/atomic.h b/qemu/include/qemu/atomic.h index 3eb72dbe..84922100 100644 --- a/qemu/include/qemu/atomic.h +++ b/qemu/include/qemu/atomic.h @@ -31,41 +31,41 @@ * implicit promotion. int and larger types, as well as pointers, can be * converted to a non-qualified type just by applying a binary operator. */ -#define typeof_strip_qual(expr) \ - typeof( \ - __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(expr), bool) || \ - __builtin_types_compatible_p(typeof(expr), const bool) || \ - __builtin_types_compatible_p(typeof(expr), volatile bool) || \ - __builtin_types_compatible_p(typeof(expr), const volatile bool), \ - (bool)1, \ - __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(expr), signed char) || \ - __builtin_types_compatible_p(typeof(expr), const signed char) || \ - __builtin_types_compatible_p(typeof(expr), volatile signed char) || \ - __builtin_types_compatible_p(typeof(expr), const volatile signed char), \ - (signed char)1, \ - __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(expr), unsigned char) || \ - __builtin_types_compatible_p(typeof(expr), const unsigned char) || \ - __builtin_types_compatible_p(typeof(expr), volatile unsigned char) || \ - __builtin_types_compatible_p(typeof(expr), const volatile unsigned char), \ - (unsigned char)1, \ - __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(expr), signed short) || \ - __builtin_types_compatible_p(typeof(expr), const signed short) || \ - __builtin_types_compatible_p(typeof(expr), volatile signed short) || \ - __builtin_types_compatible_p(typeof(expr), const volatile signed short), \ - (signed short)1, \ - __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(expr), unsigned short) || \ - __builtin_types_compatible_p(typeof(expr), const unsigned short) || \ - __builtin_types_compatible_p(typeof(expr), volatile unsigned short) || \ - __builtin_types_compatible_p(typeof(expr), const volatile unsigned short), \ - (unsigned short)1, \ +#define typeof_strip_qual(expr) \ + __typeof__( \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(__typeof__(expr), bool) || \ + __builtin_types_compatible_p(__typeof__(expr), const bool) || \ + __builtin_types_compatible_p(__typeof__(expr), volatile bool) || \ + __builtin_types_compatible_p(__typeof__(expr), const volatile bool), \ + (bool)1, \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), const signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), volatile signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), const volatile signed char), \ + (signed char)1, \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char) || \ + __builtin_types_compatible_p(__typeof__(expr), const unsigned char) || \ + __builtin_types_compatible_p(__typeof__(expr), volatile unsigned char) || \ + __builtin_types_compatible_p(__typeof__(expr), const volatile unsigned char), \ + (unsigned char)1, \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), const signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), volatile signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), const volatile signed short), \ + (signed short)1, \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), const unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), volatile unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), const volatile unsigned short), \ + (unsigned short)1, \ (expr)+0)))))) -#ifdef __ATOMIC_RELAXED +#if defined(__ATOMIC_RELAXED) && !(defined(_MSC_VER) && defined(__clang__)) /* For C11 atomic ops */ /* Sanity check that the size of an atomic operation isn't "overly large". diff --git a/qemu/include/qemu/int128.h b/qemu/include/qemu/int128.h index d32511a6..d1d1ad44 100644 --- a/qemu/include/qemu/int128.h +++ b/qemu/include/qemu/int128.h @@ -146,7 +146,9 @@ static inline Int128 bswap128(Int128 a) #else /* !CONFIG_INT128 */ typedef struct Int128 Int128; +#if !(defined(_MSC_VER) && defined(__clang__)) typedef Int128 __int128_t; +#endif struct Int128 { uint64_t lo; diff --git a/qemu/target/ppc/excp_helper.c b/qemu/target/ppc/excp_helper.c index beaef6cd..f1114b5b 100644 --- a/qemu/target/ppc/excp_helper.c +++ b/qemu/target/ppc/excp_helper.c @@ -1061,7 +1061,11 @@ void helper_store_msr(CPUPPCState *env, target_ulong val) } #if defined(TARGET_PPC64) +#if defined(_MSC_VER) && defined(__clang__) +void helper_pminsn(CPUPPCState *env, uint32_t insn) +#else void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) +#endif { CPUState *cs; diff --git a/tests/unit/test_ctl.c b/tests/unit/test_ctl.c index b96d7cf5..5eef28d0 100644 --- a/tests/unit/test_ctl.c +++ b/tests/unit/test_ctl.c @@ -251,15 +251,22 @@ static void test_uc_hook_cached_uaf(void) uc_hook h; uint64_t count = 0; #ifndef _WIN32 - void *callback = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, + // Apple Silicon does not allow RWX pages. + void *callback = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + TEST_CHECK(callback != (void*)-1); #else void *callback = VirtualAlloc(NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + TEST_CHECK(callback != NULL); #endif memcpy(callback, (void *)test_uc_hook_cached_cb, 4096); +#ifndef _WIN32 + TEST_CHECK(mprotect(callback, 4096, PROT_READ | PROT_EXEC) == 0); +#endif + uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1); OK(uc_hook_add(uc, &h, UC_HOOK_CODE, (void *)callback, (void *)&count, 1, @@ -273,8 +280,16 @@ static void test_uc_hook_cached_uaf(void) // This will clear deleted hooks and SHOULD clear cache. OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); +#ifndef _WIN32 + TEST_CHECK(mprotect(callback, 4096, PROT_READ | PROT_WRITE) == 0); +#endif + memset(callback, 0, 4096); +#ifndef _WIN32 + TEST_CHECK(mprotect(callback, 4096, PROT_READ | PROT_EXEC) == 0); +#endif + // Now hooks are deleted and thus this will trigger a UAF OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); diff --git a/tests/unit/test_mem.c b/tests/unit/test_mem.c index a1db14e1..8910fdcf 100644 --- a/tests/unit/test_mem.c +++ b/tests/unit/test_mem.c @@ -184,8 +184,15 @@ static void test_map_big_memory(void) OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) + uint64_t requested_size = 0xfffffffffffff000; // assume 4K page size +#else + long ps = sysconf(_SC_PAGESIZE); + uint64_t requested_size = (uint64_t)(-ps); +#endif + uc_assert_err(UC_ERR_NOMEM, - uc_mem_map(uc, 0x0, 0xfffffffffffff000, UC_PROT_ALL)); + uc_mem_map(uc, 0x0, requested_size, UC_PROT_ALL)); OK(uc_close(uc)); }