diff --git a/.appveyor.yml b/.appveyor.yml index 96d9d7fa..dc41ecbb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,36 +1,32 @@ # Appveyor configuration file for CI build of Unicorn Engine on Windows (under Cygwin) environment: + CYG_MIRROR: http://cygwin.mirror.constant.com + CYG_PACKAGES: make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake,python-setuptools,ruby,mingw64-i686-gcc-core,mingw64-x86_64-gcc-core + MSYS_PACKAGES: mingw-w64-x86_64-glib2 mingw-w64-i686-glib2 cmake matrix: + - MSYSTEM: MINGW64 + BASH: C:\msys64\usr\bin\bash + MSYS_CACHE: C:\msys64\var\cache\pacman\pkg + CC: x86_64-w64-mingw32-gcc + - MSYSTEM: MINGW32 + BASH: C:\msys64\usr\bin\bash + MSYS_CACHE: C:\msys64\var\cache\pacman\pkg + CC: i686-w64-mingw32-gcc - CYG_ROOT: C:\cygwin64 - CYG_SETUP: setup-x86_64.exe - CYG_MIRROR: http://cygwin.mirror.constant.com CYG_CACHE: C:\cygwin64\var\cache\setup - CYG_BASH: C:\cygwin64\bin\bash + CYG_SETUP: setup-x86_64.exe + BASH: C:\cygwin64\bin\bash CC: gcc -# TODO: Uncomment -# - CYG_ROOT: C:\cygwin64 -# CYG_SETUP: setup-x86_64.exe -# CYG_MIRROR: http://cygwin.mirror.constant.com -# CYG_CACHE: C:\cygwin64\var\cache\setup -# CYG_BASH: C:\cygwin64\bin\bash -# CC: clang - CYG_ROOT: C:\cygwin - CYG_SETUP: setup-x86.exe - CYG_MIRROR: http://cygwin.mirror.constant.com CYG_CACHE: C:\cygwin\var\cache\setup - CYG_BASH: C:\cygwin\bin\bash + CYG_SETUP: setup-x86.exe + BASH: C:\cygwin\bin\bash CC: gcc -# TODO: Uncomment -# - CYG_ROOT: C:\cygwin -# CYG_SETUP: setup-x86.exe -# CYG_MIRROR: http://cygwin.mirror.constant.com -# CYG_CACHE: C:\cygwin\var\cache\setup -# CYG_BASH: C:\cygwin\bin\bash -# CC: clang -# Cache Cygwin files to speed up build +# Cache Cygwin/MSYS files to speed up build cache: - '%CYG_CACHE%' + - '%MSYS_CACHE%' clone_depth: 1 # Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail @@ -41,19 +37,20 @@ init: # Install needed build dependencies install: - - ps: 'if ($env:CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" }' - - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake --upgrade-also' - - '%CYG_BASH% -lc "cygcheck -dc cygwin"' - + - ps: if (Test-Path Env:\CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" } + - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages "%CYG_PACKAGES%" --upgrade-also) + - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm ${MSYS_PACKAGES}") + - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm") build_script: - # TODO: uncomment and enable tests - - '%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; ./make.sh; export PATH=$PATH:../../:../../cmocka/src; make test"' - #- '%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; ./make.sh"' + - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}) && make") + - if "%MSYSTEM%" == "MINGW64" (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}) && make -C bindings/go") + # make test #- 'cd %APPVEYOR_BUILD_FOLDER% && cd bindings\dotnet && msbuild UnicornDotNet.sln' # Allows RDP #on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) -# Disable tests for now +# Test cygwin only # -test: off +test_script: + - if defined CYG_ROOT (%BASH% -lc "cd $APPVEYOR_BUILD_FOLDER && ./install-cmocka-linux.sh && export PATH=$PATH:$APPVEYOR_BUILD_FOLDER:$APPVEYOR_BUILD_FOLDER/cmocka/src && make test") diff --git a/.travis.yml b/.travis.yml index 3f12f302..543cbb42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,42 +2,26 @@ language: c sudo: false before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib cmocka; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" && "$MACOS_UNIVERSAL" != "yes" ]]; then brew install glib cmocka; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" && "$MACOS_UNIVERSAL" == "yes" ]]; then brew install glib --universal cmocka; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./install-cmocka-linux.sh; fi script: - - if [[ $CC == *"x86_64"* ]]; then ./make.sh cross-win64; elif [[ $CC == *"i686"* ]]; then ./make.sh cross-win32; else ./make.sh && make test; fi -# TODO make bindings enabled -# - ./make.sh && make test && make bindings -# TODO make universal build -# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew remove glib && brew install glib --universal && make clean && ./make.sh macos-universal && make test; fi -# TODO test iOS builds -# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make clean && ./make.sh ios; fi + - make && make -C bindings/go && make -C bindings/go test && make test compiler: - clang - gcc -# TODO update mingw32 to gcc 4.7+ for compilation -# - i686-w64-mingw32-gcc -# - x86_64-w64-mingw32-gcc os: - linux - osx -#matrix: -# exclude: -# - os: osx -# compiler: i686-w64-mingw32-gcc -# - os: osx -# compiler: x86_64-w64-mingw32-gcc +matrix: + include: + - os: osx + compiler: clang + env: MACOS_UNIVERSAL=yes + - os: osx + compiler: gcc + env: MACOS_UNIVERSAL=yes addons: apt: packages: - - mingw-w64 - - gcc-mingw-w64 - - mingw-w64-dev - - gcc-mingw-w64-i686 - - gcc-mingw-w64-x86-64 - - binutils-mingw-w64-i686 - - binutils-mingw-w64-x86-64 -# TODO are mingw32 builds necessary? -# - mingw32 -# - mingw32-binutils -# - mingw32-runtime + # mingw-w64 packages too old in precise diff --git a/Makefile b/Makefile index c9b6b908..09e0b200 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,7 @@ include pkgconfig.mk # package version LIBNAME = unicorn UNAME_S := $(shell uname -s) -GENOBJ = $(shell find qemu/$(1) -name "*.o" 2>/dev/null) $(wildcard qemu/util/*.o) $(wildcard qemu/*.o) $(wildcard qemu/qom/*.o)\ - $(wildcard qemu/hw/core/*.o) $(wildcard qemu/qapi/*.o) $(wildcard qemu/qobject/*.o) +GENOBJ = $(shell find qemu/$(1) -name "*.o" 2>/dev/null) ifneq (,$(findstring x86,$(UNICORN_ARCHS))) UC_TARGET_OBJ += $(call GENOBJ,x86_64-softmmu) @@ -63,6 +62,7 @@ ifeq ($(UNICORN_DEBUG),yes) CFLAGS += -g else CFLAGS += -O3 +UNICORN_QEMU_FLAGS += --disable-debug-info endif ifeq ($(UNICORN_ASAN),yes) @@ -97,9 +97,6 @@ PKG_VERSION = $(PKG_MAJOR).$(PKG_MINOR).$(PKG_EXTRA) endif API_MAJOR=$(shell echo `grep -e UC_API_MAJOR include/unicorn/unicorn.h | grep -v = | awk '{print $$3}'` | awk '{print $$1}') -VERSION_EXT = - -BIN_EXT = # Apple? ifeq ($(UNAME_S),Darwin) @@ -141,27 +138,25 @@ endif ifeq ($(UNICORN_SHARED),yes) ifneq ($(filter MINGW%,$(UNAME_S)),) -LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT) +LIBRARY = $(LIBNAME).$(EXT) else ifneq ($(filter CYGWIN%,$(UNAME_S)),) -LIBRARY = $(BLDIR)/cyg$(LIBNAME).$(EXT) -LIBRARY_DLLA = $(BLDIR)/lib$(LIBNAME).$(EXT).$(AR_EXT) +LIBRARY = cyg$(LIBNAME).$(EXT) +LIBRARY_DLLA = lib$(LIBNAME).$(EXT).$(AR_EXT) $(LIBNAME)_LDFLAGS += -Wl,--out-implib=$(LIBRARY_DLLA) $(LIBNAME)_LDFLAGS += -lssp # Linux, Darwin else -LIBRARY = $(BLDIR)/lib$(LIBNAME).$(VERSION_EXT) -LIBRARY_SYMLINK = $(BLDIR)/lib$(LIBNAME).$(EXT) +LIBRARY = lib$(LIBNAME).$(VERSION_EXT) +LIBRARY_SYMLINK = lib$(LIBNAME).$(EXT) endif endif ifeq ($(UNICORN_STATIC),yes) ifneq ($(filter MINGW%,$(UNAME_S)),) -ARCHIVE = $(BLDIR)/$(LIBNAME).$(AR_EXT) -else ifneq ($(filter CYGWIN%,$(UNAME_S)),) -ARCHIVE = $(BLDIR)/lib$(LIBNAME).$(AR_EXT) -# Linux, Darwin +ARCHIVE = $(LIBNAME).$(AR_EXT) +# Cygwin, Linux, Darwin else -ARCHIVE = $(BLDIR)/lib$(LIBNAME).$(AR_EXT) +ARCHIVE = lib$(LIBNAME).$(AR_EXT) endif endif @@ -171,8 +166,6 @@ INSTALL_LIB ?= $(INSTALL_BIN) -m0755 PKGCFGF = $(LIBNAME).pc PREFIX ?= /usr DESTDIR ?= -BLDIR = . -OBJDIR = . LIBDIRARCH ?= lib # Uncomment the below line to installs x86_64 libs to lib64/ directory. @@ -202,77 +195,39 @@ else PKGCFGDIR ?= $(LIBDATADIR)/pkgconfig endif -all: compile_lib -ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY))) -ifeq ($(UNICORN_SHARED),yes) -ifeq ($(V),0) - @$(INSTALL_LIB) $(LIBRARY) $(BLDIR)/samples/ -else - $(INSTALL_LIB) $(LIBRARY) $(BLDIR)/samples/ -endif -endif +$(LIBNAME)_LDFLAGS += $(GLIB) -lm - @cd samples && $(MAKE) -endif - -config: - if [ "$(UNICORN_ARCHS)" != "`cat config.log`" ]; then $(MAKE) clean; fi +.PHONY: all +all: unicorn + $(MAKE) -C samples qemu/config-host.h-timestamp: -ifeq ($(UNICORN_DEBUG),yes) cd qemu && \ ./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log -else - cd qemu && \ - ./configure --cc="${CC}" --disable-debug-info --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} - printf "$(UNICORN_ARCHS)" > config.log -endif - -compile_lib: config qemu/config-host.h-timestamp - cd qemu && $(MAKE) -j 4 - $(MAKE) unicorn + $(MAKE) -C qemu -j 4 + $(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) -$(LIBRARY): $(UC_TARGET_OBJ) uc.o list.o -ifeq ($(UNICORN_SHARED),yes) -ifeq ($(V),0) - $(call log,GEN,$(LIBRARY)) - @$(CC) $(CFLAGS) -shared $^ -o $(LIBRARY) $(GLIB) -lm $($(LIBNAME)_LDFLAGS) -else - $(CC) $(CFLAGS) -shared $^ -o $(LIBRARY) $(GLIB) -lm $($(LIBNAME)_LDFLAGS) -endif -ifneq (,$(LIBRARY_SYMLINK)) - @ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) -endif -endif - -$(ARCHIVE): $(UC_TARGET_OBJ) uc.o list.o -ifeq ($(UNICORN_STATIC),yes) -ifeq ($(V),0) - $(call log,GEN,$(ARCHIVE)) - @$(create-archive) -else - $(create-archive) -endif -endif +$(LIBRARY): qemu/config-host.h-timestamp uc.o list.o + $(CC) $(CFLAGS) -shared $(UC_TARGET_OBJ) uc.o list.o -o $(LIBRARY) $($(LIBNAME)_LDFLAGS) + -ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) +$(ARCHIVE): qemu/config-host.h-timestamp uc.o list.o + $(AR) q $(ARCHIVE) $(UC_TARGET_OBJ) uc.o list.o + $(RANLIB) $(ARCHIVE) $(PKGCFGF): -ifeq ($(V),0) - $(call log,GEN,$(@:$(BLDIR)/%=%)) - @$(generate-pkgcfg) -else $(generate-pkgcfg) -endif - .PHONY: test test: all $(MAKE) -C tests/unit test + $(MAKE) -C tests/regress test + $(MAKE) -C bindings test -install: compile_lib $(PKGCFGF) +install: qemu/config-host.h-timestamp $(PKGCFGF) mkdir -p $(DESTDIR)$(LIBDIR) ifeq ($(UNICORN_SHARED),yes) ifneq ($(filter CYGWIN%,$(UNAME_S)),) @@ -302,7 +257,7 @@ else DIST_VERSION = $(TAG) endif -bindings: compile_lib +bindings: qemu/config-host.h-timestamp $(MAKE) -C bindings build $(MAKE) -C bindings samples @@ -311,7 +266,7 @@ dist: git archive --format=zip --prefix=unicorn-$(DIST_VERSION)/ $(TAG) > unicorn-$(DIST_VERSION).zip -header: FORCE +header: $(eval TARGETS := m68k arm aarch64 mips mipsel mips64 mips64el\ powerpc sparc sparc64 x86_64) $(foreach var,$(TARGETS),\ @@ -330,10 +285,7 @@ clean: $(MAKE) -C qemu clean rm -rf *.d *.o rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll cyg$(LIBNAME)*.dll -ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY))) - cd samples && $(MAKE) clean - rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT) -endif + $(MAKE) -C samples clean $(MAKE) -C tests/unit clean @@ -353,10 +305,3 @@ define log @printf " %-7s %s\n" "$(1)" "$(2)" endef - -define create-archive - $(AR) q $(ARCHIVE) $^ - $(RANLIB) $(ARCHIVE) -endef - -FORCE: diff --git a/bindings/Makefile b/bindings/Makefile index dee75187..ed958f75 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -1,19 +1,17 @@ # Unicorn Engine # By Nguyen Anh Quynh & Dang Hoang Vu, 2015 -TMP_DIR = /tmp/unicorn_sample +DIFF = diff -DIFF = diff -u -w - -SAMPLE_ARM = $(TMP_DIR)/sample_arm -SAMPLE_ARM64 = $(TMP_DIR)/sample_arm64 -SAMPLE_MIPS = $(TMP_DIR)/sample_mips -SAMPLE_M68K = $(TMP_DIR)/sample_m68k -SAMPLE_SPARC = $(TMP_DIR)/sample_sparc -SAMPLE_X86 = $(TMP_DIR)/sample_x86 +SAMPLE_SOURCE = $(wildcard ../samples/*.c) +SAMPLE = $(SAMPLE_SOURCE:../samples/%.c=%) +SAMPLE := $(SAMPLE:mem_apis=) +SAMPLE := $(SAMPLE:sample_batch_reg=) +SAMPLE := $(SAMPLE:sample_x86_32_gdt_and_seg_regs=) +SAMPLE := $(SAMPLE:shellcode=) ENV_VARS = LD_LIBRARY_PATH=../ DYLD_LIBRARY_PATH=../ -.PHONY: build install samples sample_python expected python sample_diff clean check +.PHONY: build install python c clean check test build: $(MAKE) -C python gen_const @@ -26,44 +24,24 @@ install: build $(MAKE) -C python install $(MAKE) -C java install -samples: expected python +test: $(SAMPLE:%=%.py.test) -sample_python: expected python - -expected: +c: $(MAKE) -C ../samples - mkdir -p $(TMP_DIR) - $(ENV_VARS) ../samples/sample_arm > $(SAMPLE_ARM)_e - $(ENV_VARS) ../samples/sample_arm64 > $(SAMPLE_ARM64)_e - $(ENV_VARS) ../samples/sample_mips > $(SAMPLE_MIPS)_e - $(ENV_VARS) ../samples/sample_sparc > $(SAMPLE_SPARC)_e - $(ENV_VARS) ../samples/sample_m68k > $(SAMPLE_M68K)_e - $(ENV_VARS) ../samples/sample_x86 > $(SAMPLE_X86)_e - -python: FORCE +python: $(MAKE) -C python - $(ENV_VARS) python python/sample_arm.py > $(SAMPLE_ARM)_o - $(ENV_VARS) python python/sample_arm64.py > $(SAMPLE_ARM64)_o - $(ENV_VARS) python python/sample_mips.py > $(SAMPLE_MIPS)_o - $(ENV_VARS) python python/sample_sparc.py > $(SAMPLE_SPARC)_o - $(ENV_VARS) python python/sample_m68k.py > $(SAMPLE_M68K)_o - $(ENV_VARS) python python/sample_x86.py > $(SAMPLE_X86)_o - $(MAKE) sample_diff +%.c.txt: c + $(ENV_VARS) ../samples/$(@:%.c.txt=%) > $@ +%.py.txt: python + $(ENV_VARS) python python/$(@:%.txt=%) > $@ -sample_diff: FORCE - $(DIFF) $(SAMPLE_ARM)_e $(SAMPLE_ARM)_o - $(DIFF) $(SAMPLE_ARM64)_e $(SAMPLE_ARM64)_o - $(DIFF) $(SAMPLE_MIPS)_e $(SAMPLE_MIPS)_o - $(DIFF) $(SAMPLE_SPARC)_e $(SAMPLE_SPARC)_o - $(DIFF) $(SAMPLE_M68K)_e $(SAMPLE_M68K)_o - $(DIFF) $(SAMPLE_X86)_e $(SAMPLE_X86)_o +%.py.test: %.c.txt %.py.txt + $(DIFF) $(@:%.py.test=%.c.txt) $(@:%.py.test=%.py.txt) clean: - rm -rf $(TMP_DIR) +# rm -rf *.txt $(MAKE) -C python clean $(MAKE) -C java clean check: make -C python check - -FORCE: diff --git a/bindings/go/Makefile b/bindings/go/Makefile index 17e450c2..fe898ae1 100644 --- a/bindings/go/Makefile +++ b/bindings/go/Makefile @@ -1,14 +1,12 @@ # Go binding for Unicorn engine. Ryan Hileman -.PHONY: gen_const test +.PHONY: all gen_const test -all: - $(MAKE) gen_const +all: gen_const cd unicorn && go build - $(MAKE) test gen_const: cd .. && python const_generator.py go -test: - cd unicorn && go test +test: all + cd unicorn && LD_LIBRARY_PATH=../../../ DYLD_LIBRARY_PATH=../../../ go test diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 58e28939..6ac3ecce 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -7,8 +7,8 @@ import ( ) /* -#cgo CFLAGS: -O3 -#cgo LDFLAGS: -lunicorn +#cgo CFLAGS: -O3 -Wall -Werror -I../../../include +#cgo LDFLAGS: -L../../../ -lunicorn -lglib-2.0 #include #include "uc.h" */ diff --git a/bindings/python/sample_arm.py b/bindings/python/sample_arm.py index e910defc..13292320 100755 --- a/bindings/python/sample_arm.py +++ b/bindings/python/sample_arm.py @@ -21,7 +21,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test ARM @@ -46,7 +46,7 @@ def test_arm(): mu.hook_add(UC_HOOK_BLOCK, hook_block) # tracing all instructions with customized callback - mu.hook_add(UC_HOOK_CODE, hook_code) + mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS) # emulate machine code in infinite time mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE)) @@ -100,5 +100,5 @@ def test_thumb(): if __name__ == '__main__': test_arm() - print("=" * 20) + print("=" * 26) test_thumb() diff --git a/bindings/python/sample_arm64.py b/bindings/python/sample_arm64.py index 2afee8c4..0270a401 100755 --- a/bindings/python/sample_arm64.py +++ b/bindings/python/sample_arm64.py @@ -21,7 +21,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test ARM64 diff --git a/bindings/python/sample_m68k.py b/bindings/python/sample_m68k.py index d9579f66..7e35cf59 100755 --- a/bindings/python/sample_m68k.py +++ b/bindings/python/sample_m68k.py @@ -20,7 +20,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test ARM @@ -51,8 +51,34 @@ def test_m68k(): # now print out some registers print(">>> Emulation done. Below is the CPU context") + a0 = mu.reg_read(UC_M68K_REG_A0) + a1 = mu.reg_read(UC_M68K_REG_A1) + a2 = mu.reg_read(UC_M68K_REG_A2) + a3 = mu.reg_read(UC_M68K_REG_A3) + a4 = mu.reg_read(UC_M68K_REG_A4) + a5 = mu.reg_read(UC_M68K_REG_A5) + a6 = mu.reg_read(UC_M68K_REG_A6) + a7 = mu.reg_read(UC_M68K_REG_A7) + d0 = mu.reg_read(UC_M68K_REG_D0) + d1 = mu.reg_read(UC_M68K_REG_D1) + d2 = mu.reg_read(UC_M68K_REG_D2) d3 = mu.reg_read(UC_M68K_REG_D3) - print(">>> D3 = 0x%x" %d3) + d4 = mu.reg_read(UC_M68K_REG_D4) + d5 = mu.reg_read(UC_M68K_REG_D5) + d6 = mu.reg_read(UC_M68K_REG_D6) + d7 = mu.reg_read(UC_M68K_REG_D7) + pc = mu.reg_read(UC_M68K_REG_PC) + sr = mu.reg_read(UC_M68K_REG_SR) + print(">>> A0 = 0x%x\t\t>>> D0 = 0x%x" % (a0, d0)) + print(">>> A1 = 0x%x\t\t>>> D1 = 0x%x" % (a1, d1)) + print(">>> A2 = 0x%x\t\t>>> D2 = 0x%x" % (a2, d2)) + print(">>> A3 = 0x%x\t\t>>> D3 = 0x%x" % (a3, d3)) + print(">>> A4 = 0x%x\t\t>>> D4 = 0x%x" % (a4, d4)) + print(">>> A5 = 0x%x\t\t>>> D5 = 0x%x" % (a5, d5)) + print(">>> A6 = 0x%x\t\t>>> D6 = 0x%x" % (a6, d6)) + print(">>> A7 = 0x%x\t\t>>> D7 = 0x%x" % (a7, d7)) + print(">>> PC = 0x%x" % pc) + print(">>> SR = 0x%x" % sr) except UcError as e: print("ERROR: %s" % e) diff --git a/bindings/python/sample_mips.py b/bindings/python/sample_mips.py index 9b9f9e8f..7199b631 100755 --- a/bindings/python/sample_mips.py +++ b/bindings/python/sample_mips.py @@ -22,7 +22,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test MIPS EB @@ -54,7 +54,7 @@ def test_mips_eb(): print(">>> Emulation done. Below is the CPU context") r1 = mu.reg_read(UC_MIPS_REG_1) - print(">>> r1 = 0x%x" %r1) + print(">>> R1 = 0x%x" %r1) except UcError as e: print("ERROR: %s" % e) @@ -89,7 +89,7 @@ def test_mips_el(): print(">>> Emulation done. Below is the CPU context") r1 = mu.reg_read(UC_MIPS_REG_1) - print(">>> r1 = 0x%x" %r1) + print(">>> R1 = 0x%x" %r1) except UcError as e: print("ERROR: %s" % e) @@ -97,5 +97,5 @@ def test_mips_el(): if __name__ == '__main__': test_mips_eb() - print("=" * 20) + print("=" * 27) test_mips_el() diff --git a/bindings/python/sample_sparc.py b/bindings/python/sample_sparc.py index f6f154d6..5dbe746e 100755 --- a/bindings/python/sample_sparc.py +++ b/bindings/python/sample_sparc.py @@ -20,7 +20,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test SPARC diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index 81027b2a..a6a54615 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -8,6 +8,8 @@ from unicorn.x86_const import * X86_CODE32 = b"\x41\x4a\x66\x0f\xef\xc1" # INC ecx; DEC edx; PXOR xmm0, xmm1 X86_CODE32_LOOP = b"\x41\x4a\xeb\xfe" # INC ecx; DEC edx; JMP self-loop +X86_CODE32_JUMP = b"\xeb\x02\x90\x90\x90\x90\x90\x90" # jmp 4; nop; nop; nop; nop; nop; nop +X86_CODE32_JMP_INVALID = b"\xe9\xe9\xee\xee\xee\x41\x4a" # JMP outside; INC ecx; DEC edx X86_CODE32_MEM_READ = b"\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx X86_CODE32_MEM_WRITE = b"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; DEC edx X86_CODE64 = b"\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59" @@ -26,9 +28,14 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) - #eip = uc.reg_read(UC_X86_REG_EIP) - #print(">>> EIP = 0x%x" %(eip)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) + eip = uc.reg_read(UC_X86_REG_EFLAGS) + print(">>> --- EFLAGS is 0x%x" %(eip)) + +def hook_code64(uc, address, size, user_data): + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) + rip = uc.reg_read(UC_X86_REG_RIP) + print(">>> RIP is 0x%x" %rip); # callback for tracing invalid memory access (READ or WRITE) @@ -128,21 +135,21 @@ def test_i386(): r_xmm0 = mu.reg_read(UC_X86_REG_XMM0) print(">>> ECX = 0x%x" %r_ecx) print(">>> EDX = 0x%x" %r_edx) - print(">>> XMM0 = 0x%x" %r_xmm0) + print(">>> XMM0 = 0x%.32x" %r_xmm0) # read from memory - tmp = mu.mem_read(ADDRESS, 2) - print(">>> Read 2 bytes from [0x%x] =" %(ADDRESS), end="") - for i in tmp: - print(" 0x%x" %i, end="") + tmp = mu.mem_read(ADDRESS, 4) + print(">>> Read 4 bytes from [0x%x] = 0x" %(ADDRESS), end="") + for i in reversed(tmp): + print("%x" %(i), end="") print("") except UcError as e: print("ERROR: %s" % e) -def test_i386_loop(): - print("Emulate i386 code with infinite loop - wait for 2 seconds then stop emulation") +def test_i386_map_ptr(): + print("Emulate i386 code - use uc_mem_map_ptr()") try: # Initialize emulator in X86-32bit mode mu = Uc(UC_ARCH_X86, UC_MODE_32) @@ -151,14 +158,20 @@ def test_i386_loop(): mu.mem_map(ADDRESS, 2 * 1024 * 1024) # write machine code to be emulated to memory - mu.mem_write(ADDRESS, X86_CODE32_LOOP) + mu.mem_write(ADDRESS, X86_CODE32) # initialize machine registers mu.reg_write(UC_X86_REG_ECX, 0x1234) mu.reg_write(UC_X86_REG_EDX, 0x7890) + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code) + # emulate machine code in infinite time - mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_LOOP), 2 * UC_SECOND_SCALE) + mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32), 2 * UC_SECOND_SCALE) # now print out some registers print(">>> Emulation done. Below is the CPU context") @@ -168,6 +181,13 @@ def test_i386_loop(): print(">>> ECX = 0x%x" %r_ecx) print(">>> EDX = 0x%x" %r_edx) + # read from memory + tmp = mu.mem_read(ADDRESS, 4) + print(">>> Read 4 bytes from [0x%x] = 0x" %(ADDRESS), end="") + for i in reversed(tmp): + print("%x" %(i), end="") + print("") + except UcError as e: print("ERROR: %s" % e) @@ -198,7 +218,7 @@ def test_i386_invalid_mem_read(): # emulate machine code in infinite time mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_READ)) except UcError as e: - print("ERROR: %s" % e) + print("Failed on uc_emu_start() with error returned 6: %s" % e) # now print out some registers print(">>> Emulation done. Below is the CPU context") @@ -211,6 +231,35 @@ def test_i386_invalid_mem_read(): except UcError as e: print("ERROR: %s" % e) +def test_i386_jump(): + print("Emulate i386 code with jump") + try: + # Initialize emulator in X86-32bit mode + mu = Uc(UC_ARCH_X86, UC_MODE_32) + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_JUMP) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block, begin=ADDRESS, end=ADDRESS) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS) + + try: + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_JUMP)) + except UcError as e: + print("ERROR: %s" % e) + + print(">>> Emulation done. Below is the CPU context") + + except UcError as e: + print("ERROR: %s" % e) + def test_i386_invalid_mem_write(): print("Emulate i386 code that write to invalid memory") @@ -229,10 +278,10 @@ def test_i386_invalid_mem_write(): mu.reg_write(UC_X86_REG_EDX, 0x7890) # tracing all basic blocks with customized callback - #mu.hook_add(UC_HOOK_BLOCK, hook_block) + mu.hook_add(UC_HOOK_BLOCK, hook_block) # tracing all instructions with customized callback - #mu.hook_add(UC_HOOK_CODE, hook_code) + mu.hook_add(UC_HOOK_CODE, hook_code) # intercept invalid memory events mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid) @@ -251,25 +300,92 @@ def test_i386_invalid_mem_write(): print(">>> ECX = 0x%x" %r_ecx) print(">>> EDX = 0x%x" %r_edx) + # read from memory + print(">>> Read 4 bytes from [0x%x] = 0x" %(0xaaaaaaaa), end="") + tmp = mu.mem_read(0xaaaaaaaa, 4) + for i in reversed(tmp): + if i != 0: + print("%x" %i, end="") + print("") + try: - # read from memory - print(">>> Read 4 bytes from [0x%x] = " %(0xaaaaaaaa), end="") - tmp = mu.mem_read(0xaaaaaaaa, 4) - for i in tmp: - print(" 0x%x" %i, end="") + tmp = mu.mem_read(0xffffffaa, 4) + print(">>> Read 4 bytes from [0x%x] = 0x" %(0xffffffaa), end="") + for i in reversed(tmp): + print("%x" %i, end="") print("") - print(">>> Read 4 bytes from [0x%x] = " %(0xffffffaa), end="") - tmp = mu.mem_read(0xffffffaa, 4) - for i in tmp: - print(" 0x%x" %i, end="") - print("") except UcError as e: - print("ERROR: %s" % e) + print(">>> Failed to read 4 bytes from [0xffffffaa]") except UcError as e: print("ERROR: %s" % e) +def test_i386_jump_invalid(): + print("Emulate i386 code that jumps to invalid memory") + try: + # Initialize emulator in X86-32bit mode + mu = Uc(UC_ARCH_X86, UC_MODE_32) + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_JMP_INVALID) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code) + + try: + mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_JMP_INVALID)) + except UcError as e: + print("Failed on uc_emu_start() with error returned 8: %s" %e) + + print(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + print(">>> ECX = 0x%x" %r_ecx) + print(">>> EDX = 0x%x" %r_edx) + + except UcError as e: + print("ERROR %s" % e) + +def test_i386_loop(): + print("Emulate i386 code that loop forever") + try: + # Initialize emulator in X86-32bit mode + mu = Uc(UC_ARCH_X86, UC_MODE_32) + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_LOOP) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_LOOP), timeout=2*UC_SECOND_SCALE) + + print(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + print(">>> ECX = 0x%x" %r_ecx) + print(">>> EDX = 0x%x" %r_edx) + + + except UcError as e: + print("ERROR: %s" % e) # Test X86 32 bit with IN/OUT instruction def test_i386_inout(): @@ -326,38 +442,25 @@ def test_i386_context_save(): # write machine code to be emulated to memory mu.mem_write(address, code) - print(">>> set eax to 1") + # set eax to 1 mu.reg_write(UC_X86_REG_EAX, 1) - print(">>> execute 'inc eax'") + print(">>> Running emulation for the first time") mu.emu_start(address, address+1) - print(">>> save the CPU context") + print(">>> Emulation done. Below is the CPU context") + print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX))) + print(">>> Saving CPU context") saved_context = mu.context_save() - print(">>> execute 'inc eax'") + print(">>> Running emulation for the second time") mu.emu_start(address, address+1) + print(">>> Emulation done. Below is the CPU context") + print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX))) - print(">>> assert eax == 3") - assert mu.reg_read(UC_X86_REG_EAX) == 3 - - print(">>> restore the CPU context") + print(">>> CPU context restored. Below is the CPU context") mu.context_restore(saved_context) - - print(">>> assert eax == 2") - assert mu.reg_read(UC_X86_REG_EAX) == 2 - - print(">>> execute 'inc eax'") - mu.emu_start(address, address+1) - - print(">>> assert eax == 3") - assert mu.reg_read(UC_X86_REG_EAX) == 3 - - print(">>> restore the CPU context") - mu.context_restore(saved_context) - - print(">>> assert eax == 2") - assert mu.reg_read(UC_X86_REG_EAX) == 2 + print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX))) except UcError as e: print("ERROR: %s" % e) @@ -397,7 +500,7 @@ def test_x86_64(): mu.hook_add(UC_HOOK_BLOCK, hook_block) # tracing all instructions in range [ADDRESS, ADDRESS+20] - mu.hook_add(UC_HOOK_CODE, hook_code, None, ADDRESS, ADDRESS+20) + mu.hook_add(UC_HOOK_CODE, hook_code64, None, ADDRESS, ADDRESS+20) # tracing all memory READ & WRITE access mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access) @@ -429,23 +532,21 @@ def test_x86_64(): r14 = mu.reg_read(UC_X86_REG_R14) r15 = mu.reg_read(UC_X86_REG_R15) - print(">>> RAX = %x" %rax) - print(">>> RBX = %x" %rbx) - print(">>> RCX = %x" %rcx) - print(">>> RDX = %x" %rdx) - print(">>> RSI = %x" %rsi) - print(">>> RDI = %x" %rdi) - print(">>> R8 = %x" %r8) - print(">>> R9 = %x" %r9) - print(">>> R10 = %x" %r10) - print(">>> R11 = %x" %r11) - print(">>> R12 = %x" %r12) - print(">>> R13 = %x" %r13) - print(">>> R14 = %x" %r14) - print(">>> R15 = %x" %r15) + print(">>> RAX = 0x%x" %rax) + print(">>> RBX = 0x%x" %rbx) + print(">>> RCX = 0x%x" %rcx) + print(">>> RDX = 0x%x" %rdx) + print(">>> RSI = 0x%x" %rsi) + print(">>> RDI = 0x%x" %rdi) + print(">>> R8 = 0x%x" %r8) + print(">>> R9 = 0x%x" %r9) + print(">>> R10 = 0x%x" %r10) + print(">>> R11 = 0x%x" %r11) + print(">>> R12 = 0x%x" %r12) + print(">>> R13 = 0x%x" %r13) + print(">>> R14 = 0x%x" %r14) + print(">>> R15 = 0x%x" %r15) - #BUG - mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE64)) except UcError as e: print("ERROR: %s" % e) @@ -516,27 +617,31 @@ def test_x86_16(): print(">>> Emulation done. Below is the CPU context") tmp = mu.mem_read(11, 1) - print("[0x%x] = 0x%x" %(11, tmp[0])) + print(">>> Read 1 bytes from [0x%x] = 0x%x" %(11, tmp[0])) except UcError as e: print("ERROR: %s" % e) if __name__ == '__main__': - test_i386() - print("=" * 20) - test_i386_loop() - print("=" * 20) - test_i386_invalid_mem_read() - print("=" * 20) - test_i386_invalid_mem_write() - print("=" * 20) - test_i386_inout() - print("=" * 20) - test_i386_context_save() - print("=" * 20) - test_x86_64() - print("=" * 20) - test_x86_64_syscall() - print("=" * 20) test_x86_16() + test_i386() + print("=" * 35) + test_i386_map_ptr() + print("=" * 35) + test_i386_inout() + print("=" * 35) + test_i386_context_save() + print("=" * 35) + test_i386_jump() + print("=" * 35) + test_i386_loop() + print("=" * 35) + test_i386_invalid_mem_read() + print("=" * 35) + test_i386_invalid_mem_write() + print("=" * 35) + test_i386_jump_invalid() + test_x86_64() + print("=" * 35) + test_x86_64_syscall() diff --git a/bindings/python/shellcode.py b/bindings/python/shellcode.py index 898ada7b..ed65effa 100755 --- a/bindings/python/shellcode.py +++ b/bindings/python/shellcode.py @@ -21,7 +21,7 @@ def hook_code(uc, address, size, user_data): print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # read this instruction code from memory tmp = uc.mem_read(address, size) - print(">>> Instruction code at [0x%x] =" %(address), end="") + print("*** EIP = %x *** :" %(address), end="") for i in tmp: print(" %02x" %i, end="") print("") diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 9c54edff..45056726 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -17,12 +17,11 @@ _python2 = sys.version_info[0] < 3 if _python2: range = xrange -if sys.platform == 'darwin': - _lib = "libunicorn.dylib" -elif sys.platform in ('win32', 'cygwin'): - _lib = "unicorn.dll" -else: - _lib = "libunicorn.so" +_lib = { 'darwin': 'libunicorn.dylib', + 'win32': 'unicorn.dll', + 'cygwin': 'cygunicorn.dll', + 'linux': 'libunicorn.so', + 'linux2': 'libunicorn.so' } # Windows DLL in dependency order _all_windows_dlls = ( @@ -45,7 +44,7 @@ def _load_lib(path): if sys.platform in ('win32', 'cygwin'): _load_win_support(path) - lib_file = os.path.join(path, _lib) + lib_file = os.path.join(path, _lib[sys.platform]) return ctypes.cdll.LoadLibrary(lib_file) except OSError: return None @@ -63,8 +62,8 @@ _path_list = [pkg_resources.resource_filename(__name__, 'lib'), os.path.join(os.path.split(__file__)[0], 'lib'), '', distutils.sysconfig.get_python_lib(), - "/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64'] -#print("DEBUG _path_list = %s\n" %_path_list) + "/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64', + os.environ['PATH']] for _path in _path_list: _uc = _load_lib(_path) diff --git a/bindings/ruby/Makefile b/bindings/ruby/Makefile index 6e801fc6..6fa1faf3 100644 --- a/bindings/ruby/Makefile +++ b/bindings/ruby/Makefile @@ -2,8 +2,8 @@ .PHONY: gen_const -install: - $(MAKE) gen_const +# Use bundle install && rake to install gem and test +install: gen_const cd unicorn_gem && rake build cd unicorn_gem && gem install --local pkg/unicorn-0.9.0.gem diff --git a/install-cmocka-linux.sh b/install-cmocka-linux.sh index feb9bd36..46b405a4 100755 --- a/install-cmocka-linux.sh +++ b/install-cmocka-linux.sh @@ -3,6 +3,10 @@ set -ex mkdir cmocka wget https://cmocka.org/files/1.1/cmocka-1.1.0.tar.xz -O /tmp/cmocka-1.1.0.tar.xz tar -xf /tmp/cmocka-1.1.0.tar.xz -C /tmp -cd cmocka && cmake /tmp/cmocka-1.1.0 && make -#cmocka does not include headers in build +cd cmocka && cmake -DUNIT_TESTING=On /tmp/cmocka-1.1.0 && make && make test +# cmake builds an so instead of a dll in mingw/msys +if [[ ! -z $MSYSTEM ]]; then +cp src/cmocka.so src/cmocka.dll +fi +# cmocka does not include headers in build cp -R /tmp/cmocka-1.1.0/include/ . diff --git a/make.sh b/make.sh index a41a7c8a..048df624 100755 --- a/make.sh +++ b/make.sh @@ -36,17 +36,6 @@ build_iOS() { ${MAKE} } -build() { - [ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64" - ${MAKE} -} - -build_macos_universal() { - [ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64" - MACOS_UNIVERSAL=yes \ - ${MAKE} -} - build_cross() { [ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64" CROSS=$1 @@ -112,17 +101,14 @@ fi export CC INSTALL_BIN PREFIX PKGCFGDIR LIBDIRARCH LIBARCHS CFLAGS LDFLAGS case "$1" in - "" ) build;; - "macos-universal" ) build_macos_universal;; + "" ) ${MAKE};; "asan" ) asan;; - "default" ) build;; "install" ) install;; "uninstall" ) uninstall;; + "macos-universal" ) MACOS_UNIVERSAL=yes ${MAKE};; "cross-win32" ) build_cross i686-w64-mingw32;; "cross-win64" ) build_cross x86_64-w64-mingw32;; - "cross-android" ) CROSS=arm-linux-androideabi build;; - "clang" ) CC=clang build;; - "gcc" ) CC=gcc build;; + "cross-android" ) CROSS=arm-linux-androideabi ${MAKE};; "ios" ) build_iOS;; "ios_armv7" ) build_iOS armv7;; "ios_armv7s" ) build_iOS armv7s;; diff --git a/samples/Makefile b/samples/Makefile index e32afc93..830cd68b 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -3,7 +3,6 @@ include ../config.mk -LIBNAME = unicorn UNAME_S := $(shell uname -s) # Find GLIB @@ -11,70 +10,34 @@ ifndef GLIB GLIB = $(shell pkg-config --libs glib-2.0) endif -UNICORN_DEP_LIBS_STATIC += -lpthread -lm $(GLIB) - # Verbose output? V ?= 0 -INCDIR = ../include -SAMPLEDIR = . -OBJDIR = . -LIBDIR = .. +CFLAGS += -Wall -Werror -I../include +LDFLAGS += -L.. +LDLIBS += -lpthread -lunicorn -lm $(GLIB) -CFLAGS += -Wall -Werror -I$(INCDIR) -LDFLAGS += -lpthread -L$(LIBDIR) -l$(LIBNAME) -LDFLAGS_STATIC += $(UNICORN_DEP_LIBS_STATIC) - -ifeq ($(CROSS),) -CC ?= cc -LDFLAGS += -lm $(GLIB) -else +ifneq ($(CROSS),) CC = $(CROSS)gcc endif ifeq ($(UNICORN_ASAN),yes) -CC = clang -fsanitize=address -fno-omit-frame-pointer -CXX = clang++ -fsanitize=address -fno-omit-frame-pointer +CC = clang +CXX = clang++ AR = llvm-ar -LDFLAGS := -fsanitize=address ${LDFLAGS} +CFLAGS += -fsanitize=address -fno-omit-frame-pointer endif - -#CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) -#LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) - -BIN_EXT = -AR_EXT = a - # Cygwin? ifneq ($(filter CYGWIN%,$(UNAME_S)),) CFLAGS := $(CFLAGS:-fPIC=) -LDFLAGS += -lssp -LDFLAGS_STATIC += -lssp -BIN_EXT = .exe -AR_EXT = a +LDLIBS += -lssp # mingw? else ifneq ($(filter MINGW%,$(UNAME_S)),) CFLAGS := $(CFLAGS:-fPIC=) -BIN_EXT = .exe -AR_EXT = lib endif - -ifeq ($(UNICORN_STATIC),yes) -ifneq ($(filter MINGW%,$(UNAME_S)),) -ARCHIVE = $(LIBDIR)/$(LIBNAME).$(AR_EXT) -else ifneq ($(filter CYGWIN%,$(UNAME_S)),) -ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) -else -ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) -#ARCHIVE_X86 = $(LIBDIR)/lib$(LIBNAME)_x86.$(AR_EXT) -#ARCHIVE_ARM = $(LIBDIR)/lib$(LIBNAME)_arm.$(AR_EXT) -#ARCHIVE_ARM64 = $(LIBDIR)/lib$(LIBNAME)_arm64.$(AR_EXT) -endif -endif - -.PHONY: all clean clean_bins clean_libs +.PHONY: all clean UNICORN_ARCHS := $(shell if [ -e ../config.log ]; then cat ../config.log;\ else printf "$(UNICORN_ARCHS)"; fi) @@ -89,9 +52,9 @@ endif ifneq (,$(findstring mips,$(UNICORN_ARCHS))) SOURCES += sample_mips.c endif -ifneq (,$(findstring ppc,$(UNICORN_ARCHS))) +#ifneq (,$(findstring ppc,$(UNICORN_ARCHS))) #SOURCES += sample_ppc.c -endif +#endif ifneq (,$(findstring sparc,$(UNICORN_ARCHS))) SOURCES += sample_sparc.c endif @@ -106,73 +69,9 @@ ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c endif -OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o)) -OBJS_ELF = $(addprefix $(OBJDIR)/,$(SOURCES:.c=)) -BINARY = $(addprefix $(SAMPLEDIR)/,$(SOURCES:.c=$(BIN_EXT))) +BINS = $(SOURCES:.c=) -all: $(BINARY) +all: $(BINS) -clean_bins: - rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* - rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis sample_x86_32_gdt_and_seg_regs sample_batch_reg - -clean_libs: - rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib - -clean: clean_bins clean_libs - -$(BINARY): $(OBJS) - -$(SAMPLEDIR)/%$(BIN_EXT): $(OBJDIR)/%.o - @mkdir -p $(@D) -ifeq ($(V),0) -ifeq ($(UNICORN_SHARED),yes) - $(call log,LINK,$(notdir $@)) - @$(link-dynamic) -endif -ifeq ($(UNICORN_STATIC),yes) -ifneq ($(filter MINGW%,$(UNAME_S)),) - $(call log,LINK,$(notdir $(call staticname,$@))) - @$(link-static) -endif -endif -else -ifeq ($(UNICORN_SHARED),yes) - $(link-dynamic) -endif -ifeq ($(UNICORN_STATIC),yes) -ifneq ($(filter MINGW%,$(UNAME_S)),) - $(link-static) -endif -endif -endif - -$(OBJDIR)/%.o: %.c - @mkdir -p $(@D) -ifeq ($(V),0) - $(call log,CC,$(@:$(OBJDIR)/%=%)) - @$(compile) -else - $(compile) -endif - - -define link-dynamic - $(CC) $< $(LDFLAGS) -o $@ -endef - - -define link-static - $(CC) $< $(ARCHIVE) $(LDFLAGS_STATIC) -o $(call staticname,$@) -endef - - -staticname = $(subst $(BIN_EXT),,$(1)).static$(BIN_EXT) - -define log - @printf " %-7s %s\n" "$(1)" "$(2)" -endef - -define compile - ${CC} ${CFLAGS} -c $< -o $@ -endef +clean: + rm -rf *.o $(BINS) diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 4c5da3e3..12af8372 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -996,13 +996,15 @@ int main(int argc, char **argv, char **envp) printf("Error dynamically loading shared library.\n"); printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); return 1; } #endif - if (argc == 2) { - if (!strcmp(argv[1], "-32")) { + if (argc == 2) { + if (!strcmp(argv[1], "-16")) { + test_x86_16(); + } + else if (!strcmp(argv[1], "-32")) { test_i386(); test_i386_map_ptr(); test_i386_inout(); @@ -1013,19 +1015,29 @@ int main(int argc, char **argv, char **envp) test_i386_invalid_mem_write(); test_i386_jump_invalid(); } - - if (!strcmp(argv[1], "-64")) { + else if (!strcmp(argv[1], "-64")) { test_x86_64(); test_x86_64_syscall(); } - - if (!strcmp(argv[1], "-16")) { - test_x86_16(); + else if (!strcmp(argv[1], "-h")) { + printf("Syntax: %s <-16|-32|-64>\n", argv[0]); } - } else { - printf("Syntax: %s <-16|-32|-64>\n", argv[0]); - } + } + else { + test_x86_16(); + test_i386(); + test_i386_map_ptr(); + test_i386_inout(); + test_i386_context_save(); + test_i386_jump(); + test_i386_loop(); + test_i386_invalid_mem_read(); + test_i386_invalid_mem_write(); + test_i386_jump_invalid(); + test_x86_64(); + test_x86_64_syscall(); + } // dynamically free shared library #ifdef DYNLOAD uc_dyn_free(); diff --git a/samples/shellcode.c b/samples/shellcode.c index 8ad0c69b..ee706a6e 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -168,12 +168,15 @@ int main(int argc, char **argv, char **envp) } #endif - if (argc == 2) { + if (argc == 2) { if (!strcmp(argv[1], "-32")) { test_i386(); } + else if (!strcmp(argv[1], "-h")) { + printf("Syntax: %s <-32|-64>\n", argv[0]); + } } else { - printf("Syntax: %s <-32|-64>\n", argv[0]); + test_i386(); } // dynamically free shared library diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 532f6da0..f9ff4a8b 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -1,65 +1,16 @@ +CFLAGS += -Wall -Werror -I../../include +LDLIBS += -L../../ $(shell pkg-config --libs glib-2.0) -lpthread -lm -lunicorn -CFLAGS += -I../../include +EXECUTE_VARS = LD_LIBRARY_PATH=../../cmocka/src:../../ DYLD_LIBRARY_PATH=../../ -ifeq (MING,$(findstring MING,$(shell uname -s))) -LDFLAGS += ../../unicorn.lib $(shell pkg-config --libs glib-2.0) -lpthread -lm -else -LDFLAGS += ../../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm -endif +TESTS_SOURCE = $(wildcard *.c) +TESTS = $(TESTS_SOURCE:%.c=%) -TESTS = map_crash map_write -TESTS += sigill sigill2 -TESTS += block_test -TESTS += ro_mem_test nr_mem_test -TESTS += timeout_segfault -TESTS += rep_movsb -TESTS += mem_unmap -TESTS += mem_double_unmap -TESTS += mem_protect -TESTS += mem_exec -TESTS += mips_kseg0_1 -TESTS += eflags_nosync -TESTS += 00opcode_uc_crash -TESTS += eflags_noset -TESTS += mem_map_large -TESTS += invalid_read_in_cpu_tb_exec -TESTS += invalid_write_in_cpu_tb_exec_x86_64 -TESTS += x86_16_segfault -TESTS += mips_invalid_read_of_size_4_when_tracing -TESTS += invalid_read_in_tb_flush_x86_64 -TESTS += sparc_jump_to_zero -TESTS += mips_delay_slot_code_hook -TESTS += mem_nofree -TESTS += rw_hookstack -TESTS += threaded_emu_start -TESTS += emu_stop_in_hook_overrun -TESTS += mips_branch_likely_issue -TESTS += hook_extrainvoke -TESTS += sysenter_hook_x86 -TESTS += emu_clear_errors -TESTS += mem_fuzz -TESTS += 001-bad_condition_code_0xe -TESTS += 002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0 -TESTS += 003-qemu__fatal__wdebug_not_implemented -TESTS += 004-segmentation_fault_1 -TESTS += 005-qemu__fatal__illegal_instruction__0000___00000404 -TESTS += 006-qemu__fatal__illegal_instruction__0421___00040026 -TESTS += mem_64_c -TESTS += mem_map_0x100000000 +.PHONY: all clean test -TESTS += memleak_x86 -TESTS += memleak_arm -TESTS += memleak_arm64 -TESTS += memleak_mips -TESTS += memleak_m68k -TESTS += memleak_sparc +test: $(TESTS) all: $(TESTS) clean: rm -f $(TESTS) - -%: %.c - $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ - -.PHONY: all clean diff --git a/tests/regress/block_test.c b/tests/regress/block_test.c index 71d1021f..979d989f 100644 --- a/tests/regress/block_test.c +++ b/tests/regress/block_test.c @@ -63,7 +63,7 @@ int main() { } fprintf(stderr, "ok %d - uc_mem_write\n", count++); - uc_hook h1, h2; + uc_hook h1; err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, 1, 0); if (err != UC_ERR_OK) { diff --git a/tests/regress/eflags_nosync.c b/tests/regress/eflags_nosync.c index 3510b499..433dcfbc 100644 --- a/tests/regress/eflags_nosync.c +++ b/tests/regress/eflags_nosync.c @@ -11,7 +11,7 @@ #define PAGE_4K (1 << 12) #define TARGET_PAGE_MASK ~(PAGE_4K - 1) #define TARGET_PAGE_PREPARE(addr) (((addr) + PAGE_4K - 1) & TARGET_PAGE_MASK) -#define TARGET_PAGE_ALIGN(addr) (addr - (TARGET_PAGE_PREPARE(addr) - addr) & TARGET_PAGE_MASK) +#define TARGET_PAGE_ALIGN(addr) ((addr - (TARGET_PAGE_PREPARE(addr) - addr)) & TARGET_PAGE_MASK) static uint64_t instructions = 0; @@ -69,7 +69,6 @@ static void VM_exec() { uc_engine *uc; uc_err err; - uint32_t tmp; uc_hook trace1, trace2; unsigned int r_eax, r_ebx, r_ecx, r_edx, r_ebp, r_esp, r_esi, r_edi, r_eip, eflags; unsigned int tr_eax, tr_ebx, tr_ecx, tr_edx, tr_ebp, tr_esp, tr_esi, tr_edi, tr_eip, t_eflags; diff --git a/tests/regress/emu_stop_in_hook_overrun.c b/tests/regress/emu_stop_in_hook_overrun.c index 9b962a25..2336fc4b 100644 --- a/tests/regress/emu_stop_in_hook_overrun.c +++ b/tests/regress/emu_stop_in_hook_overrun.c @@ -60,7 +60,6 @@ int main(int argc, char **argv, char **envp) { uc_engine *uc; uc_err err; - int ret; uc_hook hhc; uint32_t val; diff --git a/tests/regress/mem_64_c.c b/tests/regress/mem_64_c.c index e09a90da..b760fd08 100644 --- a/tests/regress/mem_64_c.c +++ b/tests/regress/mem_64_c.c @@ -1,4 +1,5 @@ #include +#include #include uint64_t starts[] = {0x10000000, 0x110004000ll}; @@ -24,10 +25,10 @@ int main(int argc, char **argv, char **envp) { err = uc_mem_regions(uc, ®ions, &count); if (err == UC_ERR_OK) { for (i = 0; i < count; i++) { - fprintf(stderr, "region %d: 0x%llx-0x%llx (%d)\n", i, regions[i].begin, regions[i].end - 1, regions[i].perms); + fprintf(stderr, "region %d: 0x%"PRIx64"-0x%"PRIx64" (%d)\n", i, regions[i].begin, regions[i].end - 1, regions[i].perms); if (regions[i].begin != starts[i]) { err_count++; - fprintf(stderr, " ERROR: region start does not match requested start address, expected 0x%llx, found 0x%llx\n", + fprintf(stderr, " ERROR: region start does not match requested start address, expected 0x%"PRIx64", found 0x%"PRIx64"\n", starts[i], regions[i].begin); } } diff --git a/tests/regress/mem_double_unmap.c b/tests/regress/mem_double_unmap.c index 3373a5cc..e7203ab8 100644 --- a/tests/regress/mem_double_unmap.c +++ b/tests/regress/mem_double_unmap.c @@ -11,7 +11,6 @@ int main(int argc, char **argv, char **envp) { uc_engine *uc; - uc_hook trace1, trace2; uc_err err; // Initialize emulator in X86-32bit mode diff --git a/tests/regress/mem_fuzz.c b/tests/regress/mem_fuzz.c index bbf37eec..c62d74c0 100644 --- a/tests/regress/mem_fuzz.c +++ b/tests/regress/mem_fuzz.c @@ -84,7 +84,6 @@ void perform_fuzz_step(uc_engine *uc){ int main(int argc, char **argv, char **envp) { uc_engine *uc; - uc_hook trace1, trace2; uc_err err; if(argc<2){ printf("usage: mem_fuzz $seed\n"); diff --git a/tests/regress/mem_map_large.c b/tests/regress/mem_map_large.c index 33f754a4..f0f4cdbf 100644 --- a/tests/regress/mem_map_large.c +++ b/tests/regress/mem_map_large.c @@ -8,7 +8,7 @@ int main() { printf("uc_open() failed: %s\n", uc_strerror(err)); } printf("Trying large map.\n"); - if ((err = uc_mem_map(u, 0x60802000, 0x28bd211200004000, UC_PROT_ALL)) != UC_ERR_OK) { + if ((err = uc_mem_map(u, 0x60802000, (unsigned) 0x28bd211200004000, UC_PROT_ALL)) != UC_ERR_OK) { printf("uc_mem_map() failed: %s\n", uc_strerror(err)); return -1; } diff --git a/tests/regress/nr_mem_test.c b/tests/regress/nr_mem_test.c index b6ab8d8e..40ffa39f 100644 --- a/tests/regress/nr_mem_test.c +++ b/tests/regress/nr_mem_test.c @@ -55,7 +55,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { uc_engine *uc; - uc_hook trace1, trace2; + uc_hook trace1; uc_err err; uint32_t eax, ebx; diff --git a/tests/regress/ro_mem_test.c b/tests/regress/ro_mem_test.c index 845859b1..b5b26393 100644 --- a/tests/regress/ro_mem_test.c +++ b/tests/regress/ro_mem_test.c @@ -46,7 +46,7 @@ bottom: */ // callback for tracing instruction -static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +/*static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { uint32_t esp; printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); @@ -55,6 +55,7 @@ static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user printf(">>> --- ESP is 0x%x\n", esp); } +*/ // callback for tracing memory access (READ or WRITE) static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, @@ -95,11 +96,10 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { uc_engine *uc; - uc_hook trace1, trace2; + uc_hook trace1; uc_err err; uint8_t bytes[8]; uint32_t esp; - int result; int map_stack = 0; if (argc == 2 && strcmp(argv[1], "--map-stack") == 0) { diff --git a/tests/regress/sigill2.c b/tests/regress/sigill2.c index 1e5b7284..8e6ad560 100644 --- a/tests/regress/sigill2.c +++ b/tests/regress/sigill2.c @@ -9,7 +9,6 @@ int main() { int size; - uint8_t *buf; uc_engine *uc; uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); diff --git a/tests/unit/Makefile b/tests/unit/Makefile index ebf8eb30..0768210a 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -1,11 +1,9 @@ - CFLAGS += -Wall -Werror -Wno-unused-function -g -CFLAGS += -L ../../ -CFLAGS += -I ../../include +CFLAGS += -L ../../ -I ../../include CFLAGS += -L ../../cmocka/src -I ../../cmocka/include -EXECUTE_VARS = LD_LIBRARY_PATH=../../cmocka/src:../../ DYLD_LIBRARY_PATH=../../ +LDLIBS += -lcmocka -lunicorn -LIBS += -lcmocka -lunicorn +EXECUTE_VARS = LD_LIBRARY_PATH=../../cmocka/src:../../ DYLD_LIBRARY_PATH=../../ ifeq ($(UNICORN_ASAN),yes) CC = clang -fsanitize=address -fno-omit-frame-pointer @@ -14,9 +12,8 @@ AR = llvm-ar LDFLAGS := -fsanitize=address ${LDFLAGS} endif -ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \ - test_tb_x86 test_multihook test_pc_change test_x86_soft_paging \ - test_hookcounts test_hang test_x86_shl_enter_leave test_x86_rip_bug +ALL_TESTS_SOURCES = $(wildcard *.c) +ALL_TESTS = $(ALL_TESTS_SOURCES:%.c=%) .PHONY: all all: ${ALL_TESTS} @@ -32,28 +29,11 @@ test: ${ALL_TESTS} ${EXECUTE_VARS} ./test_mem_map ${EXECUTE_VARS} ./test_mem_map_ptr ${EXECUTE_VARS} ./test_mem_high - echo "skipping test_tb_x86" #${EXECUTE_VARS} ./test_tb_x86 ${EXECUTE_VARS} ./test_multihook ${EXECUTE_VARS} ./test_pc_change - echo "skipping test_x86_soft_paging" #${EXECUTE_VARS} ./test_x86_soft_paging ${EXECUTE_VARS} ./test_hookcounts - echo "skipping test_hang" #${EXECUTE_VARS} ./test_hang - echo "skipping test_x86_sh1_enter_leave" #${EXECUTE_VARS} ./test_x86_shl_enter_leave - echo "skipping test_x86_rip_bug" #${EXECUTE_VARS} ./test_x86_rip_bug - -test_sanity: test_sanity.c -test_x86: test_x86.c -test_mem_map: test_mem_map.c -test_mem_map_ptr: test_mem_map_ptr.c -test_mem_high: test_mem_high.c -test_tb_x86: test_tb_x86.c -test_multihook: test_multihook.c -test_pc_change: test_pc_change.c -test_x86_soft_paging: test_x86_soft_paging.c -test_hookcounts: test_hookcounts.c -test_hang: test_hang.c -test_x86_shl_enter_leave: test_x86_shl_enter_leave.c -test_x86_rip_bug: test_x86_rip_bug.c - -${ALL_TESTS}: - ${CC} ${CFLAGS} -o $@ $^ ${LIBS} + echo "skipping test_tb_x86" + echo "skipping test_x86_soft_paging" + echo "skipping test_hang" + echo "skipping test_x86_sh1_enter_leave" + echo "skipping test_x86_rip_bug"