diff --git a/angr/state_plugins/unicorn_engine.py b/angr/state_plugins/unicorn_engine.py index 0d1fe759456..afb7ccbd9de 100644 --- a/angr/state_plugins/unicorn_engine.py +++ b/angr/state_plugins/unicorn_engine.py @@ -2,7 +2,7 @@ import binascii import copy import ctypes -import importlib.resources +import importlib import itertools import logging import sys @@ -242,7 +242,7 @@ class StopDetails(ctypes.Structure): ] -class SimOSEnum: +class SimOSEnum(IntEnum): """ enum simos_t """ @@ -392,176 +392,10 @@ class _VexArchInfo(ctypes.Structure): ] -def _load_native(): - if sys.platform == "darwin": - libfile = "unicornlib.dylib" - elif sys.platform in {"win32", "cygwin"}: - libfile = "unicornlib.dll" - else: - libfile = "unicornlib.so" - - try: - angr_path = str(importlib.resources.files("angr") / libfile) - h = ctypes.CDLL(angr_path) - - VexArch = ctypes.c_int - uc_err = ctypes.c_int - state_t = ctypes.c_void_p - stop_t = ctypes.c_int - uc_engine_t = ctypes.c_void_p - - def _setup_prototype(handle, func, restype, *argtypes): - realname = "simunicorn_" + func - _setup_prototype_explicit(handle, realname, restype, *argtypes) - setattr(handle, func, getattr(handle, realname)) - - def _setup_prototype_explicit(handle, func, restype, *argtypes): - getattr(handle, func).restype = restype - getattr(handle, func).argtypes = argtypes - - # _setup_prototype_explicit(h, 'logSetLogLevel', None, ctypes.c_uint64) - _setup_prototype(h, "setup_imports", ctypes.c_bool, ctypes.c_char_p) - _setup_prototype( - h, - "alloc", - state_t, - uc_engine_t, - ctypes.c_uint64, - ctypes.c_uint64, - ctypes.c_bool, - ctypes.c_bool, - ctypes.c_bool, - ) - _setup_prototype(h, "dealloc", None, state_t) - _setup_prototype(h, "hook", None, state_t) - _setup_prototype(h, "unhook", None, state_t) - _setup_prototype(h, "start", uc_err, state_t, ctypes.c_uint64, ctypes.c_uint64) - _setup_prototype(h, "stop", None, state_t, stop_t) - _setup_prototype(h, "sync", ctypes.POINTER(MEM_PATCH), state_t) - _setup_prototype(h, "bbl_addrs", ctypes.POINTER(ctypes.c_uint64), state_t) - _setup_prototype(h, "stack_pointers", ctypes.POINTER(ctypes.c_uint64), state_t) - _setup_prototype(h, "bbl_addr_count", ctypes.c_uint64, state_t) - _setup_prototype(h, "syscall_count", ctypes.c_uint64, state_t) - _setup_prototype(h, "step", ctypes.c_uint64, state_t) - _setup_prototype(h, "activate_page", None, state_t, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p) - _setup_prototype(h, "set_last_block_details", None, state_t, ctypes.c_uint64, ctypes.c_int64, ctypes.c_int64) - _setup_prototype(h, "set_stops", None, state_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_uint64)) - _setup_prototype( - h, "cache_page", ctypes.c_bool, state_t, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_char_p, ctypes.c_uint64 - ) - _setup_prototype(h, "uncache_pages_touching_region", None, state_t, ctypes.c_uint64, ctypes.c_uint64) - _setup_prototype(h, "clear_page_cache", None, state_t) - _setup_prototype(h, "enable_symbolic_reg_tracking", None, state_t, VexArch, _VexArchInfo) - _setup_prototype(h, "disable_symbolic_reg_tracking", None, state_t) - _setup_prototype(h, "symbolic_register_data", None, state_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_uint64)) - _setup_prototype(h, "get_symbolic_registers", ctypes.c_uint64, state_t, ctypes.POINTER(ctypes.c_uint64)) - _setup_prototype(h, "is_interrupt_handled", ctypes.c_bool, state_t) - _setup_prototype( - h, - "set_cgc_syscall_details", - None, - state_t, - ctypes.c_uint32, - ctypes.c_uint64, - ctypes.c_uint32, - ctypes.c_uint64, - ctypes.c_uint64, - ctypes.c_uint32, - ctypes.c_uint64, - ) - _setup_prototype(h, "process_transmit", ctypes.POINTER(TRANSMIT_RECORD), state_t, ctypes.c_uint32) - _setup_prototype(h, "set_tracking", None, state_t, ctypes.c_bool, ctypes.c_bool) - _setup_prototype(h, "executed_pages", ctypes.c_uint64, state_t) - _setup_prototype(h, "in_cache", ctypes.c_bool, state_t, ctypes.c_uint64) - if unicorn is not None: - _setup_prototype(h, "set_map_callback", None, state_t, unicorn.unicorn.UC_HOOK_MEM_INVALID_CB) - _setup_prototype( - h, - "set_vex_to_unicorn_reg_mappings", - None, - state_t, - ctypes.POINTER(ctypes.c_uint64), - ctypes.POINTER(ctypes.c_uint64), - ctypes.POINTER(ctypes.c_uint64), - ctypes.c_uint64, - ) - _setup_prototype(h, "set_artificial_registers", None, state_t, ctypes.POINTER(ctypes.c_uint64), ctypes.c_uint64) - _setup_prototype(h, "get_count_of_blocks_with_symbolic_vex_stmts", ctypes.c_uint64, state_t) - _setup_prototype( - h, "get_details_of_blocks_with_symbolic_vex_stmts", None, state_t, ctypes.POINTER(BlockDetails) - ) - _setup_prototype(h, "get_stop_details", StopDetails, state_t) - _setup_prototype(h, "set_register_blacklist", None, state_t, ctypes.POINTER(ctypes.c_uint64), ctypes.c_uint64) - _setup_prototype( - h, - "set_cpu_flags_details", - None, - state_t, - ctypes.POINTER(ctypes.c_uint64), - ctypes.POINTER(ctypes.c_uint64), - ctypes.POINTER(ctypes.c_uint64), - ctypes.c_uint64, - ) - _setup_prototype( - h, - "set_fd_bytes", - state_t, - ctypes.c_uint64, - ctypes.c_void_p, - ctypes.c_void_p, - ctypes.c_uint64, - ctypes.c_uint64, - ) - _setup_prototype( - h, - "set_random_syscall_data", - None, - state_t, - ctypes.POINTER(ctypes.c_uint64), - ctypes.POINTER(ctypes.c_uint64), - ctypes.c_uint64, - ) - _setup_prototype( - h, - "set_vex_cc_reg_data", - None, - state_t, - ctypes.POINTER(ctypes.c_uint64), - ctypes.POINTER(ctypes.c_uint64), - ctypes.c_uint64, - ) - _setup_prototype(h, "get_count_of_writes_to_reexecute", ctypes.c_uint64, state_t) - _setup_prototype( - h, - "get_concrete_writes_to_reexecute", - None, - state_t, - ctypes.POINTER(ctypes.c_uint64), - ctypes.POINTER(ctypes.c_uint8), - ) - _setup_prototype( - h, - "set_fp_regs_fp_ops_vex_codes", - None, - state_t, - ctypes.c_uint64, - ctypes.c_uint64, - ctypes.POINTER(ctypes.c_uint64), - ctypes.c_uint32, - ) - - l.info("native plugin is enabled") - - return h - except (OSError, AttributeError) as e: - l.error('failed loading "%s", unicorn support disabled (%s)', libfile, e) - raise ImportError("Unable to import native SimUnicorn support") from e - - try: - _UC_NATIVE = _load_native() - # _UC_NATIVE.logSetLogLevel(2) + _UC_NATIVE = importlib.import_module("angr.unicornlib") except ImportError: + print("Unable to import native unicorn support", file=sys.stderr) _UC_NATIVE = None if _uc is not None and _UC_NATIVE is not None and not _UC_NATIVE.setup_imports(_uc._name.encode()): diff --git a/angr/unicornlib.pyi b/angr/unicornlib.pyi new file mode 100644 index 00000000000..0c8b503fd0a --- /dev/null +++ b/angr/unicornlib.pyi @@ -0,0 +1,137 @@ +from collections.abc import Sequence +from enum import Enum + +class State: ... + +class SimOS(Enum): + CGC: int + LINUX: int + OTHER: int + +class StopReason(Enum): + NORMAL: int + STOPPOINT: int + ERROR: int + SYSCALL: int + EXECNONE: int + ZEROPAGE: int + NOSTART: int + SEGFAULT: int + ZERO_DIV: int + NODECODE: int + HLT: int + VEX_LIFT_FAILED: int + SYMBOLIC_PC: int + SYMBOLIC_READ_ADDR: int + SYMBOLIC_READ_SYMBOLIC_TRACKING_DISABLED: int + SYMBOLIC_WRITE_ADDR: int + SYMBOLIC_BLOCK_EXIT_CONDITION: int + SYMBOLIC_BLOCK_EXIT_TARGET: int + UNSUPPORTED_STMT_PUTI: int + UNSUPPORTED_STMT_STOREG: int + UNSUPPORTED_STMT_LOADG: int + UNSUPPORTED_STMT_CAS: int + UNSUPPORTED_STMT_LLSC: int + UNSUPPORTED_STMT_DIRTY: int + UNSUPPORTED_STMT_UNKNOWN: int + UNSUPPORTED_EXPR_GETI: int + UNSUPPORTED_EXPR_UNKNOWN: int + UNKNOWN_MEMORY_WRITE_SIZE: int + SYSCALL_ARM: int + X86_CPUID: int + +class StopDetails: + stop_reason: int + block_addr: int + block_size: int + +class RegisterValue: + offset: int + # value: bytes # Not exposed due to pybind11 limitation + size: int + +class SymVexStmtDetails: + stmt_idx: int + has_memory_dep: bool + memory_values: object # pointer/array, not directly exposed + memory_values_count: int + +class SymBlockDetailsRet: + block_addr: int + block_size: int + block_trace_ind: int + has_symbolic_exit: bool + symbolic_stmts: object # pointer/array, not directly exposed + symbolic_stmts_count: int + register_values: object # pointer/array, not directly exposed + register_values_count: int + +class TransmitRecord: + fd: int + data: object # pointer/array, not directly exposed + count: int + +def alloc( + uc: object, + cache_key: int, + simos: object, + handle_symbolic_addrs: bool, + handle_symb_cond: bool, + handle_symb_syscalls: bool, +) -> State: ... +def dealloc(state: State) -> None: ... +def bbl_addrs(state: State) -> Sequence[int]: ... +def stack_pointers(state: State) -> Sequence[int]: ... +def bbl_addr_count(state: State) -> int: ... +def syscall_count(state: State) -> int: ... +def hook(state: State) -> None: ... +def unhook(state: State) -> None: ... +def start(state: State, pc: int, step: int) -> int: ... +def stop(state: State, reason: int) -> None: ... +def sync(state: State) -> object: ... +def step(state: State) -> int: ... +def set_last_block_details(state: State, block_addr: int, curr_count: int, total_count: int) -> None: ... +def set_random_syscall_data(state: State, values: Sequence[int], sizes: Sequence[int], count: int) -> None: ... +def set_stops(state: State, count: int, stops: Sequence[int]) -> None: ... +def activate_page(state: State, address: int, taint: bytes, data: bytes) -> None: ... +def executed_pages(state: State) -> int: ... +def get_stop_details(state: State) -> object: ... +def symbolic_register_data(state: State, count: int, offsets: Sequence[int]) -> None: ... +def get_symbolic_registers(state: State, output: Sequence[int]) -> int: ... +def enable_symbolic_reg_tracking(state: State, guest: int, archinfo: int) -> None: ... +def disable_symbolic_reg_tracking(state: State) -> None: ... +def is_interrupt_handled(state: State) -> bool: ... +def set_cgc_syscall_details( + state: State, + transmit_num: int, + transmit_bbl: int, + receive_num: int, + receive_bbl: int, + receive_size: int, + random_num: int, + random_bbl: int, +) -> None: ... +def process_transmit(state: State, num: int) -> object: ... +def set_fd_bytes(state: State, fd: int, input: bytes, taints: bytes, len: int, read_pos: int) -> None: ... +def cache_page(state: State, address: int, length: int, bytes: bytes, permissions: int) -> bool: ... +def uncache_pages_touching_region(state: State, address: int, length: int) -> None: ... +def clear_page_cache(state: State) -> None: ... +def set_tracking(state: State, track_bbls: bool, track_stack: bool) -> None: ... +def in_cache(state: State, address: int) -> bool: ... +def set_map_callback(state: State, cb: object) -> None: ... +def set_artificial_registers(state: State, offsets: Sequence[int], count: int) -> None: ... +def set_vex_to_unicorn_reg_mappings( + state: State, vex_offsets: Sequence[int], unicorn_ids: Sequence[int], reg_sizes: Sequence[int], count: int +) -> None: ... +def set_cpu_flags_details( + state: State, flag_vex_id: Sequence[int], uc_reg_id: Sequence[int], bitmasks: Sequence[int], count: int +) -> None: ... +def set_register_blacklist(state: State, reg_list: Sequence[int], count: int) -> None: ... +def set_vex_cc_reg_data(state: State, reg_offsets: Sequence[int], reg_sizes: Sequence[int], count: int) -> None: ... +def get_count_of_blocks_with_symbolic_vex_stmts(state: State) -> int: ... +def get_details_of_blocks_with_symbolic_vex_stmts(state: State, ret_block_details: object) -> None: ... +def get_count_of_writes_to_reexecute(state: State) -> int: ... +def get_concrete_writes_to_reexecute(state: State, addrs: Sequence[int], values: bytes) -> None: ... +def set_fp_regs_fp_ops_vex_codes( + state: State, start_offset: int, size: int, ops: Sequence[int], op_count: int +) -> None: ... diff --git a/native/unicornlib/Makefile b/native/unicornlib/Makefile deleted file mode 100644 index 5dab017b2e6..00000000000 --- a/native/unicornlib/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -UNAME := $(shell uname) -ifeq ($(UNAME), Darwin) - LIB_UNICORNLIB=unicornlib.dylib -endif -ifeq ($(UNAME), FreeBSD) - LIB_UNICORNLIB=unicornlib.so -endif -ifeq ($(UNAME), Linux) - LIB_UNICORNLIB=unicornlib.so -endif -ifeq ($(UNAME), OpenBSD) - LIB_UNICORNLIB=unicornlib.so -endif - -CC ?= gcc -CXX ?= g++ -CFLAGS ?= -O3 -CFLAGS += -fPIC -CXXFLAGS ?= -O3 -CXXFLAGS += -fPIC -std=c++11 -ifneq ($(DEBUG), ) - CFLAGS += -O0 -g - CXXFLAGS += -O0 -g -endif -CPPFLAGS += -I vendor -I "${PYVEX_INCLUDE_PATH}" -CFLAGS += -I vendor -LDFLAGS += -L "${PYVEX_LIB_PATH}" -shared - -OBJS := log.o unicorn_dynamic.o -LDLIBS := -lpyvex -ifeq ($(UNAME), Darwin) - LDFLAGS += -Wl,-rpath,"${PYVEX_LIB_PATH}" -endif - -ifeq ($(UNAME), Linux) - LDLIBS += -ldl -endif - -all: ${LIB_UNICORNLIB} - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< - -${LIB_UNICORNLIB}: ${OBJS} sim_unicorn.cpp - ${CXX} ${CXXFLAGS} ${CPPFLAGS} -o $@ $^ ${LDLIBS} ${LDFLAGS} - -clean: - rm -f "${LIB_UNICORNLIB}" *.o arch/*.o diff --git a/native/unicornlib/Makefile-win b/native/unicornlib/Makefile-win deleted file mode 100644 index a91f8d7f167..00000000000 --- a/native/unicornlib/Makefile-win +++ /dev/null @@ -1,8 +0,0 @@ -CC=cl -INCFLAGS=/I "$(PYVEX_INCLUDE_PATH)" /I vendor -CFLAGS=/EHsc /MD /LD /O2 $(INCFLAGS) /Zi -LDFLAGS=/link "$(PYVEX_LIB_FILE)" /DEF:unicornlib.def /DEBUG - -unicornlib.dll: sim_unicorn.cpp unicornlib.def - $(CC) $(CFLAGS) sim_unicorn.cpp unicorn_dynamic.c $(LDFLAGS) /OUT:unicornlib.dll - diff --git a/native/unicornlib/pymodule.cpp b/native/unicornlib/pymodule.cpp new file mode 100644 index 00000000000..d9fc223b042 --- /dev/null +++ b/native/unicornlib/pymodule.cpp @@ -0,0 +1,454 @@ +#include +#include +#include +#include +#include + +#include +#include + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) +#include +#elif defined(_WIN32) +#include +#else +#error "Unsupported platform - need dlopen equivalent" +#endif + +#define ANGR_UNICORN_API +#include "sim_unicorn.hpp" + +bool simunicorn_setup_imports(char *uc_path) { + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) + void *handle = dlopen(uc_path, RTLD_NOW | RTLD_GLOBAL); + if (!handle) { + return false; + } +#define XX(x) *((void**)&x) = (void*)dlsym(handle, #x); if (!x) { return false; } +#include "uc_macro.h" + +#elif defined(_WIN32) + HMODULE handle = LoadLibraryA(uc_path); + if (!handle) { + return false; + } +#define XX(x) *((void**)&x) = (void*)GetProcAddress(handle, #x); if (!x) { return false; } +#include "uc_macro.h" + +#endif + + return true; +} + + +State *simunicorn_alloc(void *uc, uint64_t cache_key, simos_t simos, bool handle_symbolic_addrs, + bool handle_symb_cond, bool handle_symb_syscalls) { + State *state = new State((uc_engine *)uc, cache_key, simos, handle_symbolic_addrs, handle_symb_cond, handle_symb_syscalls); + return state; +} + +void simunicorn_dealloc(State *state) { + delete state; +} + +uint64_t *simunicorn_bbl_addrs(State *state) { + return &(state->bbl_addrs[0]); +} + +uint64_t *simunicorn_stack_pointers(State *state) { + return &(state->stack_pointers[0]); +} + +uint64_t simunicorn_bbl_addr_count(State *state) { + return state->bbl_addrs.size(); +} + +uint64_t simunicorn_syscall_count(State *state) { + return state->syscall_count; +} + +void simunicorn_hook(State *state) { + state->hook(); +} + +void simunicorn_unhook(State *state) { + state->unhook(); +} + +uc_err simunicorn_start(State *state, uint64_t pc, uint64_t step) { + return state->start(pc, step); +} + +void simunicorn_stop(State *state, stop_t reason) { + state->stop(reason); +} + +mem_update_t *simunicorn_sync(State *state) { + return state->sync(); +} + +uint64_t simunicorn_step(State *state) { + return state->cur_steps; +} + +void simunicorn_set_last_block_details(State *state, address_t block_addr, uint64_t curr_count, uint64_t total_count) { + state->set_last_block_details(block_addr, curr_count, total_count); +} + +void simunicorn_set_random_syscall_data(State *state, uint64_t *values, uint64_t *sizes, uint64_t count) { + state->init_random_bytes(values, sizes, count); +} + +void simunicorn_set_stops(State *state, uint64_t count, uint64_t *stops) +{ + state->set_stops(count, stops); +} + +void simunicorn_activate_page(State *state, uint64_t address, uint8_t *taint, uint8_t *data) { + state->page_activate(address, taint, data); +} + +uint64_t simunicorn_executed_pages(State *state) { // this is HORRIBLE + if (state->executed_pages_iterator == NULL) { + state->executed_pages_iterator = new std::unordered_set::iterator; + *state->executed_pages_iterator = state->executed_pages.begin(); + } + + if (*state->executed_pages_iterator == state->executed_pages.end()) { + delete state->executed_pages_iterator; + state->executed_pages_iterator = NULL; + return -1; + } + + uint64_t out = **state->executed_pages_iterator; + (*state->executed_pages_iterator)++; + return out; +} + +// +// Stop analysis +// + +stop_details_t simunicorn_get_stop_details(State *state) { + return state->stop_details; +} + +// +// Symbolic register tracking +// + +void simunicorn_symbolic_register_data(State *state, uint64_t count, uint64_t *offsets) +{ + state->symbolic_registers.clear(); + for (auto i = 0; i < count; i++) { + state->symbolic_registers.insert(offsets[i]); + } +} + +uint64_t simunicorn_get_symbolic_registers(State *state, uint64_t *output) +{ + int i = 0; + for (auto r : state->symbolic_registers) { + output[i] = r; + i++; + } + return i; +} + +void simunicorn_enable_symbolic_reg_tracking(State *state, VexArch guest, VexArchInfo archinfo) { + state->vex_guest = guest; + state->vex_archinfo = archinfo; +} + +void simunicorn_disable_symbolic_reg_tracking(State *state) { + state->vex_guest = VexArch_INVALID; +} + +// +// Concrete transmits +// + +bool simunicorn_is_interrupt_handled(State *state) { + return state->interrupt_handled; +} + +void simunicorn_set_cgc_syscall_details(State *state, uint32_t transmit_num, uint64_t transmit_bbl, + uint32_t receive_num, uint64_t receive_bbl, uint64_t receive_size, uint32_t random_num, uint64_t random_bbl) { + state->cgc_random_sysno = random_num; + state->cgc_random_bbl = random_bbl; + state->cgc_receive_sysno = receive_num; + state->cgc_receive_bbl = receive_bbl; + state->cgc_receive_max_size = receive_size; + state->cgc_transmit_sysno = transmit_num; + state->cgc_transmit_bbl = transmit_bbl; +} + +transmit_record_t *simunicorn_process_transmit(State *state, uint32_t num) { + if (num >= state->transmit_records.size()) { + for (auto record_iter = state->transmit_records.begin(); + record_iter != state->transmit_records.end(); + record_iter++) { + free(record_iter->data); + } + state->transmit_records.clear(); + return NULL; + } else { + transmit_record_t *out = &state->transmit_records[num]; + return out; + } +} + +/* + * Set concrete bytes of an open file for use in tracing + */ + +void simunicorn_set_fd_bytes(State *state, uint64_t fd, char *input, taint_t *taints, uint64_t len, uint64_t read_pos) { + state->fd_init_bytes(fd, input, taints, len, read_pos); + return; +} + +/* + * Page cache + */ + +bool simunicorn_cache_page(State *state, uint64_t address, uint64_t length, char *bytes, uint64_t permissions) { + //LOG_I("caching [%#lx, %#lx]", address, address + length); + + auto actual = state->cache_page(address, length, bytes, permissions); + if (!state->map_cache(actual.first, actual.second)) { + return false; + } + return true; +} + +void simunicorn_uncache_pages_touching_region(State *state, uint64_t address, uint64_t length) { + state->uncache_pages_touching_region(address, length); +} + +void simunicorn_clear_page_cache(State *state) { + state->clear_page_cache(); +} + +// Tracking settings +void simunicorn_set_tracking(State *state, bool track_bbls, bool track_stack) { + state->track_bbls = track_bbls; + state->track_stack = track_stack; +} + +bool simunicorn_in_cache(State *state, uint64_t address) { + return state->in_cache(address); +} + +void simunicorn_set_map_callback(State *state, uc_cb_eventmem_t cb) { + state->py_mem_callback = cb; +} + +// VEX artificial registers list +void simunicorn_set_artificial_registers(State *state, uint64_t *offsets, uint64_t count) { + state->artificial_vex_registers.clear(); + for (auto i = 0; i < count; i++) { + state->artificial_vex_registers.emplace(offsets[i]); + } + return; +} + +// VEX register offsets to unicorn register ID mappings +void simunicorn_set_vex_to_unicorn_reg_mappings(State *state, uint64_t *vex_offsets, uint64_t *unicorn_ids, + uint64_t *reg_sizes, uint64_t count) { + state->vex_to_unicorn_map.clear(); + for (auto i = 0; i < count; i++) { + state->vex_to_unicorn_map.emplace(vex_offsets[i], std::make_pair(unicorn_ids[i], reg_sizes[i])); + } + return; +} + +// Mapping details for flags registers +void simunicorn_set_cpu_flags_details(State *state, uint64_t *flag_vex_id, uint64_t *uc_reg_id, uint64_t *bitmasks, uint64_t count) { + state->cpu_flags.clear(); + for (auto i = 0; i < count; i++) { + state->cpu_flags.emplace(flag_vex_id[i], std::make_pair(uc_reg_id[i], bitmasks[i])); + } + return; +} + +void simunicorn_set_register_blacklist(State *state, uint64_t *reg_list, uint64_t count) { + state->blacklisted_registers.clear(); + for (auto i = 0; i < count; i++) { + state->blacklisted_registers.emplace(reg_list[i]); + } + return; +} + +void simunicorn_set_vex_cc_reg_data(State *state, uint64_t *reg_offsets, uint64_t *reg_sizes, uint64_t count) { + state->vex_cc_regs.clear(); + for (auto i = 0; i < count; i++) { + state->vex_cc_regs.emplace(reg_offsets[i], reg_sizes[i]); + } + return; +} + +// VEX re-execution data + +uint64_t simunicorn_get_count_of_blocks_with_symbolic_vex_stmts(State *state) { + return state->block_details_to_return.size(); +} + +void simunicorn_get_details_of_blocks_with_symbolic_vex_stmts(State *state, sym_block_details_ret_t *ret_block_details) { + for (auto i = 0; i < state->block_details_to_return.size(); i++) { + ret_block_details[i].block_addr = state->block_details_to_return[i].block_addr; + ret_block_details[i].block_size = state->block_details_to_return[i].block_size; + ret_block_details[i].block_trace_ind = state->block_details_to_return[i].block_trace_ind; + ret_block_details[i].has_symbolic_exit = state->block_details_to_return[i].has_symbolic_exit; + ret_block_details[i].symbolic_stmts = &(state->block_details_to_return[i].symbolic_stmts[0]); + ret_block_details[i].symbolic_stmts_count = state->block_details_to_return[i].symbolic_stmts.size(); + ret_block_details[i].register_values = &(state->block_details_to_return[i].register_values[0]); + ret_block_details[i].register_values_count = state->block_details_to_return[i].register_values.size(); + } + return; +} + +// Concrete writes to re-execute +uint64_t simunicorn_get_count_of_writes_to_reexecute(State *state) { + return state->concrete_writes_to_reexecute.size(); +} + +void simunicorn_get_concrete_writes_to_reexecute(State *state, uint64_t *addrs, uint8_t *values) { + uint64_t count = 0; + for (auto &entry: state->concrete_writes_to_reexecute) { + addrs[count] = entry.first; + values[count] = entry.second; + count++; + } + return; + } + +void simunicorn_set_fp_regs_fp_ops_vex_codes(State *state, uint64_t start_offset, uint64_t size, uint64_t *ops, uint32_t op_count) { + state->fp_reg_vex_data.first = start_offset; + state->fp_reg_vex_data.second = size; + for (auto i = 0; i < op_count; i++) { + state->fp_ops_to_avoid.emplace(ops[i]); + } +} + +PYBIND11_MODULE(unicornlib, m) { + m.doc() = "C++ bits for unicorn integration"; + + pybind11::enum_(m, "SimOS") + .value("CGC", SIMOS_CGC) + .value("LINUX", SIMOS_LINUX) + .value("OTHER", SIMOS_OTHER) + .export_values(); + + pybind11::enum_(m, "StopReason") + .value("NORMAL", STOP_NORMAL) + .value("STOPPOINT", STOP_STOPPOINT) + .value("ERROR", STOP_ERROR) + .value("SYSCALL", STOP_SYSCALL) + .value("EXECNONE", STOP_EXECNONE) + .value("ZEROPAGE", STOP_ZEROPAGE) + .value("NOSTART", STOP_NOSTART) + .value("SEGFAULT", STOP_SEGFAULT) + .value("ZERO_DIV", STOP_ZERO_DIV) + .value("NODECODE", STOP_NODECODE) + .value("HLT", STOP_HLT) + .value("VEX_LIFT_FAILED", STOP_VEX_LIFT_FAILED) + .value("SYMBOLIC_PC", STOP_SYMBOLIC_PC) + .value("SYMBOLIC_READ_ADDR", STOP_SYMBOLIC_READ_ADDR) + .value("SYMBOLIC_READ_SYMBOLIC_TRACKING_DISABLED", STOP_SYMBOLIC_READ_SYMBOLIC_TRACKING_DISABLED) + .value("SYMBOLIC_WRITE_ADDR", STOP_SYMBOLIC_WRITE_ADDR) + .value("SYMBOLIC_BLOCK_EXIT_CONDITION", STOP_SYMBOLIC_BLOCK_EXIT_CONDITION) + .value("SYMBOLIC_BLOCK_EXIT_TARGET", STOP_SYMBOLIC_BLOCK_EXIT_TARGET) + .value("UNSUPPORTED_STMT_PUTI", STOP_UNSUPPORTED_STMT_PUTI) + .value("UNSUPPORTED_STMT_STOREG", STOP_UNSUPPORTED_STMT_STOREG) + .value("UNSUPPORTED_STMT_LOADG", STOP_UNSUPPORTED_STMT_LOADG) + .value("UNSUPPORTED_STMT_CAS", STOP_UNSUPPORTED_STMT_CAS) + .value("UNSUPPORTED_STMT_LLSC", STOP_UNSUPPORTED_STMT_LLSC) + .value("UNSUPPORTED_STMT_DIRTY", STOP_UNSUPPORTED_STMT_DIRTY) + .value("UNSUPPORTED_STMT_UNKNOWN", STOP_UNSUPPORTED_STMT_UNKNOWN) + .value("UNSUPPORTED_EXPR_GETI", STOP_UNSUPPORTED_EXPR_GETI) + .value("UNSUPPORTED_EXPR_UNKNOWN", STOP_UNSUPPORTED_EXPR_UNKNOWN) + .value("UNKNOWN_MEMORY_WRITE_SIZE", STOP_UNKNOWN_MEMORY_WRITE_SIZE) + .value("SYSCALL_ARM", STOP_SYSCALL_ARM) + .value("X86_CPUID", STOP_X86_CPUID) + .export_values(); + + pybind11::class_(m, "StopDetails") + .def_readwrite("stop_reason", &stop_details_t::stop_reason) + .def_readwrite("block_addr", &stop_details_t::block_addr) + .def_readwrite("block_size", &stop_details_t::block_size); + + pybind11::class_(m, "RegisterValue") + .def_readwrite("offset", ®ister_value_t::offset) + // FIXME: fixed-sized arrays can't be used with pybind11, need to use + // a property instead to do a runtime check + // .def_readwrite("value", ®ister_value_t::value) + .def_readwrite("size", ®ister_value_t::size); + + pybind11::class_(m, "SymVexStmtDetails") + .def_readwrite("stmt_idx", &sym_vex_stmt_details_t::stmt_idx) + .def_readwrite("has_memory_dep", &sym_vex_stmt_details_t::has_memory_dep) + .def_readwrite("memory_values", &sym_vex_stmt_details_t::memory_values) + .def_readwrite("memory_values_count", &sym_vex_stmt_details_t::memory_values_count); + + pybind11::class_(m, "SymBlockDetailsRet") + .def_readwrite("block_addr", &sym_block_details_ret_t::block_addr) + .def_readwrite("block_size", &sym_block_details_ret_t::block_size) + .def_readwrite("block_trace_ind", &sym_block_details_ret_t::block_trace_ind) + .def_readwrite("has_symbolic_exit", &sym_block_details_ret_t::has_symbolic_exit) + .def_readwrite("symbolic_stmts", &sym_block_details_ret_t::symbolic_stmts) + .def_readwrite("symbolic_stmts_count", &sym_block_details_ret_t::symbolic_stmts_count) + .def_readwrite("register_values", &sym_block_details_ret_t::register_values) + .def_readwrite("register_values_count", &sym_block_details_ret_t::register_values_count); + + pybind11::class_(m, "TransmitRecord") + .def_readwrite("fd", &transmit_record_t::fd) + .def_readwrite("data", &transmit_record_t::data) + .def_readwrite("count", &transmit_record_t::count); + + pybind11::class_(m, "State"); + + m.def("setup_imports", &simunicorn_setup_imports); + m.def("alloc", &simunicorn_alloc, pybind11::return_value_policy::reference); + m.def("dealloc", &simunicorn_dealloc); + m.def("bbl_addrs", &simunicorn_bbl_addrs, pybind11::return_value_policy::reference); + m.def("stack_pointers", &simunicorn_stack_pointers, pybind11::return_value_policy::reference); + m.def("bbl_addr_count", &simunicorn_bbl_addr_count); + m.def("syscall_count", &simunicorn_syscall_count); + m.def("hook", &simunicorn_hook); + m.def("unhook", &simunicorn_unhook); + m.def("start", &simunicorn_start); + m.def("stop", &simunicorn_stop); + m.def("sync", &simunicorn_sync, pybind11::return_value_policy::reference); + m.def("step", &simunicorn_step); + m.def("set_last_block_details", &simunicorn_set_last_block_details); + m.def("set_random_syscall_data", &simunicorn_set_random_syscall_data); + m.def("set_stops", &simunicorn_set_stops); + m.def("activate_page", &simunicorn_activate_page); + m.def("executed_pages", &simunicorn_executed_pages); + m.def("get_stop_details", &simunicorn_get_stop_details); + m.def("symbolic_register_data", &simunicorn_symbolic_register_data); + m.def("get_symbolic_registers", &simunicorn_get_symbolic_registers); + m.def("enable_symbolic_reg_tracking", &simunicorn_enable_symbolic_reg_tracking); + m.def("disable_symbolic_reg_tracking", &simunicorn_disable_symbolic_reg_tracking); + m.def("is_interrupt_handled", &simunicorn_is_interrupt_handled); + m.def("set_cgc_syscall_details", &simunicorn_set_cgc_syscall_details); + m.def("process_transmit", &simunicorn_process_transmit, pybind11::return_value_policy::reference); + m.def("set_fd_bytes", &simunicorn_set_fd_bytes); + m.def("cache_page", &simunicorn_cache_page); + m.def("uncache_pages_touching_region", &simunicorn_uncache_pages_touching_region); + m.def("clear_page_cache", &simunicorn_clear_page_cache); + m.def("set_tracking", &simunicorn_set_tracking); + m.def("in_cache", &simunicorn_in_cache); + m.def("set_map_callback", &simunicorn_set_map_callback); + m.def("set_artificial_registers", &simunicorn_set_artificial_registers); + m.def("set_vex_to_unicorn_reg_mappings", &simunicorn_set_vex_to_unicorn_reg_mappings); + m.def("set_cpu_flags_details", &simunicorn_set_cpu_flags_details); + m.def("set_register_blacklist", &simunicorn_set_register_blacklist); + m.def("set_vex_cc_reg_data", &simunicorn_set_vex_cc_reg_data); + m.def("get_count_of_blocks_with_symbolic_vex_stmts", &simunicorn_get_count_of_blocks_with_symbolic_vex_stmts); + m.def("get_details_of_blocks_with_symbolic_vex_stmts", &simunicorn_get_details_of_blocks_with_symbolic_vex_stmts); + m.def("get_count_of_writes_to_reexecute", &simunicorn_get_count_of_writes_to_reexecute); + m.def("get_concrete_writes_to_reexecute", &simunicorn_get_concrete_writes_to_reexecute); + m.def("set_fp_regs_fp_ops_vex_codes", &simunicorn_set_fp_regs_fp_ops_vex_codes); +} diff --git a/native/unicornlib/sim_unicorn.cpp b/native/unicornlib/sim_unicorn.cpp index 6894c18cbb8..528698fecff 100644 --- a/native/unicornlib/sim_unicorn.cpp +++ b/native/unicornlib/sim_unicorn.cpp @@ -25,6 +25,8 @@ extern "C" { #include "sim_unicorn.hpp" //#include "log.h" +std::map global_cache; + State::State(uc_engine *_uc, uint64_t cache_key, simos_t curr_os, bool symb_addrs, bool symb_cond, bool symb_syscalls): uc(_uc), simos(curr_os), handle_symbolic_addrs(symb_addrs), handle_symbolic_conditions(symb_cond), handle_symbolic_syscalls(symb_syscalls) { @@ -2894,338 +2896,3 @@ static bool hook_mem_prot(uc_engine *uc, uc_mem_type type, uint64_t address, int state->stop(STOP_SEGFAULT); return false; } - -/* - * C style bindings makes it simple and dirty - */ - -extern "C" -State *simunicorn_alloc(uc_engine *uc, uint64_t cache_key, simos_t simos, bool handle_symbolic_addrs, - bool handle_symb_cond, bool handle_symb_syscalls) { - State *state = new State(uc, cache_key, simos, handle_symbolic_addrs, handle_symb_cond, handle_symb_syscalls); - return state; -} - -extern "C" -void simunicorn_dealloc(State *state) { - delete state; -} - -extern "C" -uint64_t *simunicorn_bbl_addrs(State *state) { - return &(state->bbl_addrs[0]); -} - -extern "C" -uint64_t *simunicorn_stack_pointers(State *state) { - return &(state->stack_pointers[0]); -} - -extern "C" -uint64_t simunicorn_bbl_addr_count(State *state) { - return state->bbl_addrs.size(); -} - -extern "C" -uint64_t simunicorn_syscall_count(State *state) { - return state->syscall_count; -} - -extern "C" -void simunicorn_hook(State *state) { - state->hook(); -} - -extern "C" -void simunicorn_unhook(State *state) { - state->unhook(); -} - -extern "C" -uc_err simunicorn_start(State *state, uint64_t pc, uint64_t step) { - return state->start(pc, step); -} - -extern "C" -void simunicorn_stop(State *state, stop_t reason) { - state->stop(reason); -} - -extern "C" -mem_update_t *simunicorn_sync(State *state) { - return state->sync(); -} - -extern "C" -uint64_t simunicorn_step(State *state) { - return state->cur_steps; -} - -extern "C" -void simunicorn_set_last_block_details(State *state, address_t block_addr, uint64_t curr_count, uint64_t total_count) { - state->set_last_block_details(block_addr, curr_count, total_count); -} - -extern "C" -void simunicorn_set_random_syscall_data(State *state, uint64_t *values, uint64_t *sizes, uint64_t count) { - state->init_random_bytes(values, sizes, count); -} - -extern "C" -void simunicorn_set_stops(State *state, uint64_t count, uint64_t *stops) -{ - state->set_stops(count, stops); -} - -extern "C" -void simunicorn_activate_page(State *state, uint64_t address, uint8_t *taint, uint8_t *data) { - state->page_activate(address, taint, data); -} - -extern "C" -uint64_t simunicorn_executed_pages(State *state) { // this is HORRIBLE - if (state->executed_pages_iterator == NULL) { - state->executed_pages_iterator = new std::unordered_set::iterator; - *state->executed_pages_iterator = state->executed_pages.begin(); - } - - if (*state->executed_pages_iterator == state->executed_pages.end()) { - delete state->executed_pages_iterator; - state->executed_pages_iterator = NULL; - return -1; - } - - uint64_t out = **state->executed_pages_iterator; - (*state->executed_pages_iterator)++; - return out; -} - -// -// Stop analysis -// - -extern "C" -stop_details_t simunicorn_get_stop_details(State *state) { - return state->stop_details; -} - -// -// Symbolic register tracking -// - -extern "C" -void simunicorn_symbolic_register_data(State *state, uint64_t count, uint64_t *offsets) -{ - state->symbolic_registers.clear(); - for (auto i = 0; i < count; i++) { - state->symbolic_registers.insert(offsets[i]); - } -} - -extern "C" -uint64_t simunicorn_get_symbolic_registers(State *state, uint64_t *output) -{ - int i = 0; - for (auto r : state->symbolic_registers) { - output[i] = r; - i++; - } - return i; -} - -extern "C" -void simunicorn_enable_symbolic_reg_tracking(State *state, VexArch guest, VexArchInfo archinfo) { - state->vex_guest = guest; - state->vex_archinfo = archinfo; -} - -extern "C" -void simunicorn_disable_symbolic_reg_tracking(State *state) { - state->vex_guest = VexArch_INVALID; -} - -// -// Concrete transmits -// - -extern "C" -bool simunicorn_is_interrupt_handled(State *state) { - return state->interrupt_handled; -} - -extern "C" -void simunicorn_set_cgc_syscall_details(State *state, uint32_t transmit_num, uint64_t transmit_bbl, - uint32_t receive_num, uint64_t receive_bbl, uint64_t receive_size, uint32_t random_num, uint64_t random_bbl) { - state->cgc_random_sysno = random_num; - state->cgc_random_bbl = random_bbl; - state->cgc_receive_sysno = receive_num; - state->cgc_receive_bbl = receive_bbl; - state->cgc_receive_max_size = receive_size; - state->cgc_transmit_sysno = transmit_num; - state->cgc_transmit_bbl = transmit_bbl; -} - -extern "C" -transmit_record_t *simunicorn_process_transmit(State *state, uint32_t num) { - if (num >= state->transmit_records.size()) { - for (auto record_iter = state->transmit_records.begin(); - record_iter != state->transmit_records.end(); - record_iter++) { - free(record_iter->data); - } - state->transmit_records.clear(); - return NULL; - } else { - transmit_record_t *out = &state->transmit_records[num]; - return out; - } -} - -/* - * Set concrete bytes of an open file for use in tracing - */ - -extern "C" -void simunicorn_set_fd_bytes(State *state, uint64_t fd, char *input, taint_t *taints, uint64_t len, uint64_t read_pos) { - state->fd_init_bytes(fd, input, taints, len, read_pos); - return; -} - -/* - * Page cache - */ - -extern "C" -bool simunicorn_cache_page(State *state, uint64_t address, uint64_t length, char *bytes, uint64_t permissions) { - //LOG_I("caching [%#lx, %#lx]", address, address + length); - - auto actual = state->cache_page(address, length, bytes, permissions); - if (!state->map_cache(actual.first, actual.second)) { - return false; - } - return true; -} - -extern "C" -void simunicorn_uncache_pages_touching_region(State *state, uint64_t address, uint64_t length) { - state->uncache_pages_touching_region(address, length); -} - -extern "C" -void simunicorn_clear_page_cache(State *state) { - state->clear_page_cache(); -} - -// Tracking settings -extern "C" -void simunicorn_set_tracking(State *state, bool track_bbls, bool track_stack) { - state->track_bbls = track_bbls; - state->track_stack = track_stack; -} - -extern "C" -bool simunicorn_in_cache(State *state, uint64_t address) { - return state->in_cache(address); -} - -extern "C" -void simunicorn_set_map_callback(State *state, uc_cb_eventmem_t cb) { - state->py_mem_callback = cb; -} - -// VEX artificial registers list -extern "C" -void simunicorn_set_artificial_registers(State *state, uint64_t *offsets, uint64_t count) { - state->artificial_vex_registers.clear(); - for (auto i = 0; i < count; i++) { - state->artificial_vex_registers.emplace(offsets[i]); - } - return; -} - -// VEX register offsets to unicorn register ID mappings -extern "C" -void simunicorn_set_vex_to_unicorn_reg_mappings(State *state, uint64_t *vex_offsets, uint64_t *unicorn_ids, - uint64_t *reg_sizes, uint64_t count) { - state->vex_to_unicorn_map.clear(); - for (auto i = 0; i < count; i++) { - state->vex_to_unicorn_map.emplace(vex_offsets[i], std::make_pair(unicorn_ids[i], reg_sizes[i])); - } - return; -} - -// Mapping details for flags registers -extern "C" -void simunicorn_set_cpu_flags_details(State *state, uint64_t *flag_vex_id, uint64_t *uc_reg_id, uint64_t *bitmasks, uint64_t count) { - state->cpu_flags.clear(); - for (auto i = 0; i < count; i++) { - state->cpu_flags.emplace(flag_vex_id[i], std::make_pair(uc_reg_id[i], bitmasks[i])); - } - return; -} - -extern "C" -void simunicorn_set_register_blacklist(State *state, uint64_t *reg_list, uint64_t count) { - state->blacklisted_registers.clear(); - for (auto i = 0; i < count; i++) { - state->blacklisted_registers.emplace(reg_list[i]); - } - return; -} - -extern "C" -void simunicorn_set_vex_cc_reg_data(State *state, uint64_t *reg_offsets, uint64_t *reg_sizes, uint64_t count) { - state->vex_cc_regs.clear(); - for (auto i = 0; i < count; i++) { - state->vex_cc_regs.emplace(reg_offsets[i], reg_sizes[i]); - } - return; -} - -// VEX re-execution data - -extern "C" -uint64_t simunicorn_get_count_of_blocks_with_symbolic_vex_stmts(State *state) { - return state->block_details_to_return.size(); -} - -extern "C" -void simunicorn_get_details_of_blocks_with_symbolic_vex_stmts(State *state, sym_block_details_ret_t *ret_block_details) { - for (auto i = 0; i < state->block_details_to_return.size(); i++) { - ret_block_details[i].block_addr = state->block_details_to_return[i].block_addr; - ret_block_details[i].block_size = state->block_details_to_return[i].block_size; - ret_block_details[i].block_trace_ind = state->block_details_to_return[i].block_trace_ind; - ret_block_details[i].has_symbolic_exit = state->block_details_to_return[i].has_symbolic_exit; - ret_block_details[i].symbolic_stmts = &(state->block_details_to_return[i].symbolic_stmts[0]); - ret_block_details[i].symbolic_stmts_count = state->block_details_to_return[i].symbolic_stmts.size(); - ret_block_details[i].register_values = &(state->block_details_to_return[i].register_values[0]); - ret_block_details[i].register_values_count = state->block_details_to_return[i].register_values.size(); - } - return; -} - -// Concrete writes to re-execute -extern "C" -uint64_t simunicorn_get_count_of_writes_to_reexecute(State *state) { - return state->concrete_writes_to_reexecute.size(); -} - -extern "C" -void simunicorn_get_concrete_writes_to_reexecute(State *state, uint64_t *addrs, uint8_t *values) { - uint64_t count = 0; - for (auto &entry: state->concrete_writes_to_reexecute) { - addrs[count] = entry.first; - values[count] = entry.second; - count++; - } - return; - } - -extern "C" -void simunicorn_set_fp_regs_fp_ops_vex_codes(State *state, uint64_t start_offset, uint64_t size, uint64_t *ops, uint32_t op_count) { - state->fp_reg_vex_data.first = start_offset; - state->fp_reg_vex_data.second = size; - for (auto i = 0; i < op_count; i++) { - state->fp_ops_to_avoid.emplace(ops[i]); - } -} \ No newline at end of file diff --git a/native/unicornlib/sim_unicorn.hpp b/native/unicornlib/sim_unicorn.hpp index 616870b32ea..4c42d915986 100644 --- a/native/unicornlib/sim_unicorn.hpp +++ b/native/unicornlib/sim_unicorn.hpp @@ -1,6 +1,8 @@ #ifndef SIM_UNICORN_HPP #define SIM_UNICORN_HPP +#include + extern "C" { #include } @@ -481,7 +483,6 @@ struct caches_t { typedef taint_t PageBitmap[ANGR_PAGE_SIZE]; typedef std::unordered_map BlockTaintCache; -std::map global_cache; typedef std::unordered_set RegisterSet; typedef std::unordered_set TempSet; diff --git a/native/unicornlib/unicorn_dynamic.c b/native/unicornlib/unicorn_dynamic.c deleted file mode 100644 index 8d65ed8f1a5..00000000000 --- a/native/unicornlib/unicorn_dynamic.c +++ /dev/null @@ -1,35 +0,0 @@ -#include - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) -#include -#elif defined(_WIN32) -#include -#else -#error "Unsupported platform - need dlopen equivalent" -#endif - -#define ANGR_UNICORN_API -#include - -bool simunicorn_setup_imports(char *uc_path) { - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) - void *handle = dlopen(uc_path, RTLD_NOW | RTLD_GLOBAL); - if (!handle) { - return false; - } -#define XX(x) *((void**)&x) = (void*)dlsym(handle, #x); if (!x) { return false; } -#include "uc_macro.h" - -#elif defined(_WIN32) - HMODULE handle = LoadLibraryA(uc_path); - if (!handle) { - return false; - } -#define XX(x) *((void**)&x) = (void*)GetProcAddress(handle, #x); if (!x) { return false; } -#include "uc_macro.h" - -#endif - - return true; -} diff --git a/native/unicornlib/unicornlib.def b/native/unicornlib/unicornlib.def deleted file mode 100644 index d0dcf6db335..00000000000 --- a/native/unicornlib/unicornlib.def +++ /dev/null @@ -1,48 +0,0 @@ -LIBRARY unicornlib.dll - -EXPORTS - simunicorn_setup_imports - simunicorn_alloc - simunicorn_dealloc - simunicorn_hook - simunicorn_unhook - simunicorn_start - simunicorn_stop - simunicorn_sync - simunicorn_bbl_addrs - simunicorn_stack_pointers - simunicorn_bbl_addr_count - simunicorn_syscall_count - simunicorn_step - simunicorn_activate_page - simunicorn_set_last_block_details - simunicorn_set_stops - simunicorn_set_map_callback - simunicorn_cache_page - simunicorn_uncache_pages_touching_region - simunicorn_clear_page_cache - simunicorn_enable_symbolic_reg_tracking - simunicorn_disable_symbolic_reg_tracking - simunicorn_symbolic_register_data - simunicorn_get_symbolic_registers - simunicorn_is_interrupt_handled - simunicorn_process_transmit - simunicorn_set_tracking - simunicorn_executed_pages - simunicorn_in_cache - simunicorn_get_count_of_blocks_with_symbolic_vex_stmts - simunicorn_get_details_of_blocks_with_symbolic_vex_stmts - simunicorn_get_stop_details - simunicorn_set_artificial_registers - simunicorn_set_cpu_flags_details - simunicorn_set_register_blacklist - simunicorn_set_vex_to_unicorn_reg_mappings - simunicorn_is_interrupt_handled - simunicorn_set_cgc_syscall_details - simunicorn_process_transmit - simunicorn_set_fd_bytes - simunicorn_set_random_syscall_data - simunicorn_set_vex_cc_reg_data - simunicorn_get_count_of_writes_to_reexecute - simunicorn_get_concrete_writes_to_reexecute - simunicorn_set_fp_regs_fp_ops_vex_codes diff --git a/pyproject.toml b/pyproject.toml index ed3299a0dbd..c5c8b5206f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.2", "setuptools-rust", "pyvex==9.2.160.dev0"] +requires = ["setuptools>=61.2", "setuptools-rust", "pybind11>=2.13.6,<3", "pyvex==9.2.160.dev0"] build-backend = "setuptools.build_meta" [project] @@ -75,7 +75,7 @@ extras = ["angr[angrdb,keystone]"] [tool.setuptools] include-package-data = true -license-files = ["LICENSE"] +license-files = ["COPYRIGHT", "LICENSE"] [tool.setuptools.packages.find] exclude = ["tests*"] diff --git a/setup.py b/setup.py index edc406ae4f1..1f95887f92a 100644 --- a/setup.py +++ b/setup.py @@ -1,132 +1,41 @@ -# pylint: disable=missing-class-docstring from __future__ import annotations -import glob -import importlib -import importlib.resources -import os -import platform -import shutil -import subprocess -import sys -from distutils.command.build import build as st_build -from distutils.util import get_platform - -from setuptools import Command, setup -from setuptools.command.develop import develop as st_develop -from setuptools.errors import LibError - -# Import setuptools_rust to ensure an error is raised if not installed -try: - _ = importlib.import_module("setuptools_rust") -except ImportError as err: - raise Exception("angr requires setuptools-rust to build") from err - -if sys.platform == "darwin": - library_file = "unicornlib.dylib" -elif sys.platform in ("win32", "cygwin"): - library_file = "unicornlib.dll" -else: - library_file = "unicornlib.so" - - -def build_unicornlib(): - try: - importlib.import_module("pyvex") - except ImportError as e: - raise LibError("You must install pyvex before building angr") from e - - env = os.environ.copy() - env_data = ( - ("PYVEX_INCLUDE_PATH", "pyvex", "include"), - ("PYVEX_LIB_PATH", "pyvex", "lib"), - ("PYVEX_LIB_FILE", "pyvex", "lib\\pyvex.lib"), - ) - for var, pkg, fnm in env_data: - base = importlib.resources.files(pkg) - for child in fnm.split("\\"): - base = base.joinpath(child) - env[var] = str(base) - - if sys.platform == "win32": - cmd = ["nmake", "/f", "Makefile-win"] - elif shutil.which("gmake") is not None: - cmd = ["gmake"] - else: - cmd = ["make"] - try: - subprocess.run(cmd, cwd="native/unicornlib", env=env, check=True) - except FileNotFoundError as err: - raise LibError("Couldn't find " + cmd[0] + " in PATH") from err - except subprocess.CalledProcessError as err: - raise LibError("Error while building unicornlib: " + str(err)) from err - - shutil.rmtree("angr/lib", ignore_errors=True) - os.mkdir("angr/lib") - shutil.copy(os.path.join("native/unicornlib", library_file), "angr") - - -def clean_unicornlib(): - oglob = glob.glob("native/*.o") - oglob += glob.glob("native/*.obj") - oglob += glob.glob("native/*.so") - oglob += glob.glob("native/*.dll") - oglob += glob.glob("native/*.dylib") - for fname in oglob: - os.unlink(fname) - - -class build(st_build): - def run(self, *args): - self.execute(build_unicornlib, (), msg="Building unicornlib") - super().run(*args) +import platform +from os.path import dirname, join -class clean(Command): - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - self.execute(clean, (), msg="Cleaning unicornlib") - - -class develop(st_develop): - def run(self): - self.run_command("build") - super().run() - - -cmdclass = { - "build": build, - "clean_unicornlib": clean, - "develop": develop, -} - +from pybind11.setup_helpers import Pybind11Extension +from setuptools import setup +# This try-except block is a workaround for older versions of setuptools which +# will attempt to import setup.py without all build dependencies installed. It +# should be able to be removed once the minimum required version of setuptools +# is new enough. try: - from setuptools.command.editable_wheel import editable_wheel as st_editable_wheel - - class editable_wheel(st_editable_wheel): - def run(self): - self.run_command("build") - super().run() - - cmdclass["editable_wheel"] = editable_wheel -except ModuleNotFoundError: - pass - - -if "bdist_wheel" in sys.argv and "--plat-name" not in sys.argv: - sys.argv.append("--plat-name") - name = get_platform() - if "linux" in name: - sys.argv.append("manylinux2014_" + platform.machine()) - else: - # https://www.python.org/dev/peps/pep-0425/ - sys.argv.append(name.replace(".", "_").replace("-", "_")) - -setup(cmdclass=cmdclass) + import pyvex + + PYVEX_LIB_DIR = join(dirname(pyvex.__file__), "lib") + PYVEX_INCLUDE_DIR = join(dirname(pyvex.__file__), "include") +except ImportError: + PYVEX_LIB_DIR = None + PYVEX_INCLUDE_DIR = None + +VENDOR_INCLUDE_DIR = join(dirname(__file__), "native", "unicornlib", "vendor") + +setup( + ext_modules=[ + Pybind11Extension( + "angr.unicornlib", + [ + "native/unicornlib/pymodule.cpp", + "native/unicornlib/sim_unicorn.cpp", + ], + include_dirs=[PYVEX_INCLUDE_DIR, VENDOR_INCLUDE_DIR], + library_dirs=[PYVEX_LIB_DIR], + libraries=["pyvex"], + cxx_std=17, + # FIXME: This is a workaround for duplicate symbols originating from + # sim_unicorn.hpp, included in both sim_unicorn.cpp and pymodule.cpp. + extra_link_args=["/FORCE:MULTIPLE"] if platform.system() == "Windows" else [], + ), + ], +)