mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-06-02 02:40:35 +00:00
make cleanup
This commit is contained in:
parent
4d5738eeb5
commit
186540e160
|
@ -7,26 +7,15 @@ environment:
|
||||||
CYG_CACHE: C:\cygwin64\var\cache\setup
|
CYG_CACHE: C:\cygwin64\var\cache\setup
|
||||||
CYG_BASH: C:\cygwin64\bin\bash
|
CYG_BASH: C:\cygwin64\bin\bash
|
||||||
CC: gcc
|
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_ROOT: C:\cygwin
|
||||||
CYG_SETUP: setup-x86.exe
|
CYG_SETUP: setup-x86.exe
|
||||||
CYG_MIRROR: http://cygwin.mirror.constant.com
|
CYG_MIRROR: http://cygwin.mirror.constant.com
|
||||||
CYG_CACHE: C:\cygwin\var\cache\setup
|
CYG_CACHE: C:\cygwin\var\cache\setup
|
||||||
CYG_BASH: C:\cygwin\bin\bash
|
CYG_BASH: C:\cygwin\bin\bash
|
||||||
CC: gcc
|
CC: gcc
|
||||||
# TODO: Uncomment
|
# - MSYS_ROOT: C:\msys64
|
||||||
# - CYG_ROOT: C:\cygwin
|
# MSYS_BASH: C:\msys64\mingw64\bin\sh
|
||||||
# CYG_SETUP: setup-x86.exe
|
# CC: x86_64-w64-mingw32-gcc
|
||||||
# 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 files to speed up build
|
||||||
cache:
|
cache:
|
||||||
|
@ -42,13 +31,11 @@ init:
|
||||||
# Install needed build dependencies
|
# Install needed build dependencies
|
||||||
install:
|
install:
|
||||||
- ps: 'if ($env:CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" }'
|
- 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'
|
- if defined CYG_ROOT (%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,python-setuptools --upgrade-also)
|
||||||
- '%CYG_BASH% -lc "cygcheck -dc cygwin"'
|
- if defined MSYS_ROOT (%MSYS_BASH% -lc "pacman -S --noconfirm mingw-w64-x86_64-glib2")
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
# TODO: uncomment and enable tests
|
- if defined CYG_ROOT (%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; make; export PATH=$PATH:../../:../../cmocka/src:../:../cmocka/src; make test")
|
||||||
- '%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; ./make.sh; export PATH=$PATH:../../:../../cmocka/src; make test"'
|
- if defined MSYS_ROOT (%MSYS_BASH% -lc "MSYS=winsymlinks, cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); x86_64-w64-mingw32-gcc --version; ./install-cmocka-linux.sh; make")
|
||||||
#- '%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; ./make.sh"'
|
|
||||||
#- 'cd %APPVEYOR_BUILD_FOLDER% && cd bindings\dotnet && msbuild UnicornDotNet.sln'
|
#- 'cd %APPVEYOR_BUILD_FOLDER% && cd bindings\dotnet && msbuild UnicornDotNet.sln'
|
||||||
# Allows RDP
|
# Allows RDP
|
||||||
#on_finish:
|
#on_finish:
|
||||||
|
|
36
.travis.yml
36
.travis.yml
|
@ -2,42 +2,30 @@ language: c
|
||||||
sudo: false
|
sudo: false
|
||||||
before_install:
|
before_install:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
- 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
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./install-cmocka-linux.sh; fi
|
||||||
script:
|
script:
|
||||||
- if [[ $CC == *"x86_64"* ]]; then ./make.sh cross-win64; elif [[ $CC == *"i686"* ]]; then ./make.sh cross-win32; else ./make.sh && make test; fi
|
- make && make test
|
||||||
# TODO make bindings enabled
|
# 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
|
# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make clean && ./make.sh ios; fi
|
||||||
compiler:
|
compiler:
|
||||||
- clang
|
- clang
|
||||||
- gcc
|
- gcc
|
||||||
# TODO update mingw32 to gcc 4.7+ for compilation
|
|
||||||
# - i686-w64-mingw32-gcc
|
|
||||||
# - x86_64-w64-mingw32-gcc
|
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
- osx
|
||||||
#matrix:
|
matrix:
|
||||||
# exclude:
|
include:
|
||||||
# - os: osx
|
- os: osx
|
||||||
# compiler: i686-w64-mingw32-gcc
|
compiler: clang
|
||||||
|
env: MACOS_UNIVERSAL=yes
|
||||||
|
- os: osx
|
||||||
|
compiler: gcc
|
||||||
|
env: MACOS_UNIVERSAL=yes
|
||||||
# - os: osx
|
# - os: osx
|
||||||
# compiler: x86_64-w64-mingw32-gcc
|
# compiler: x86_64-w64-mingw32-gcc
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- mingw-w64
|
# mingw-w64 packages too old in precise
|
||||||
- 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
|
|
||||||
|
|
98
Makefile
98
Makefile
|
@ -63,6 +63,7 @@ ifeq ($(UNICORN_DEBUG),yes)
|
||||||
CFLAGS += -g
|
CFLAGS += -g
|
||||||
else
|
else
|
||||||
CFLAGS += -O3
|
CFLAGS += -O3
|
||||||
|
UNICORN_QEMU_FLAGS += --disable-debug-info
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(UNICORN_ASAN),yes)
|
ifeq ($(UNICORN_ASAN),yes)
|
||||||
|
@ -97,9 +98,6 @@ PKG_VERSION = $(PKG_MAJOR).$(PKG_MINOR).$(PKG_EXTRA)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
API_MAJOR=$(shell echo `grep -e UC_API_MAJOR include/unicorn/unicorn.h | grep -v = | awk '{print $$3}'` | awk '{print $$1}')
|
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?
|
# Apple?
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
@ -127,6 +125,8 @@ else ifneq ($(filter MINGW%,$(UNAME_S)),)
|
||||||
EXT = dll
|
EXT = dll
|
||||||
AR_EXT = lib
|
AR_EXT = lib
|
||||||
BIN_EXT = .exe
|
BIN_EXT = .exe
|
||||||
|
UNICORN_QEMU_FLAGS += --disable-stack-protector
|
||||||
|
UNICORN_CFLAGS := $(UNICORN_CFLAGS:-fPIC=)
|
||||||
|
|
||||||
# Linux, Darwin
|
# Linux, Darwin
|
||||||
else
|
else
|
||||||
|
@ -139,27 +139,25 @@ endif
|
||||||
|
|
||||||
ifeq ($(UNICORN_SHARED),yes)
|
ifeq ($(UNICORN_SHARED),yes)
|
||||||
ifneq ($(filter MINGW%,$(UNAME_S)),)
|
ifneq ($(filter MINGW%,$(UNAME_S)),)
|
||||||
LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT)
|
LIBRARY = $(LIBNAME).$(EXT)
|
||||||
else ifneq ($(filter CYGWIN%,$(UNAME_S)),)
|
else ifneq ($(filter CYGWIN%,$(UNAME_S)),)
|
||||||
LIBRARY = $(BLDIR)/cyg$(LIBNAME).$(EXT)
|
LIBRARY = cyg$(LIBNAME).$(EXT)
|
||||||
LIBRARY_DLLA = $(BLDIR)/lib$(LIBNAME).$(EXT).$(AR_EXT)
|
LIBRARY_DLLA = lib$(LIBNAME).$(EXT).$(AR_EXT)
|
||||||
$(LIBNAME)_LDFLAGS += -Wl,--out-implib=$(LIBRARY_DLLA)
|
$(LIBNAME)_LDFLAGS += -Wl,--out-implib=$(LIBRARY_DLLA)
|
||||||
$(LIBNAME)_LDFLAGS += -lssp
|
$(LIBNAME)_LDFLAGS += -lssp
|
||||||
# Linux, Darwin
|
# Linux, Darwin
|
||||||
else
|
else
|
||||||
LIBRARY = $(BLDIR)/lib$(LIBNAME).$(VERSION_EXT)
|
LIBRARY = lib$(LIBNAME).$(VERSION_EXT)
|
||||||
LIBRARY_SYMLINK = $(BLDIR)/lib$(LIBNAME).$(EXT)
|
LIBRARY_SYMLINK = lib$(LIBNAME).$(EXT)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(UNICORN_STATIC),yes)
|
ifeq ($(UNICORN_STATIC),yes)
|
||||||
ifneq ($(filter MINGW%,$(UNAME_S)),)
|
ifneq ($(filter MINGW%,$(UNAME_S)),)
|
||||||
ARCHIVE = $(BLDIR)/$(LIBNAME).$(AR_EXT)
|
ARCHIVE = $(LIBNAME).$(AR_EXT)
|
||||||
else ifneq ($(filter CYGWIN%,$(UNAME_S)),)
|
# Cygwin, Linux, Darwin
|
||||||
ARCHIVE = $(BLDIR)/lib$(LIBNAME).$(AR_EXT)
|
|
||||||
# Linux, Darwin
|
|
||||||
else
|
else
|
||||||
ARCHIVE = $(BLDIR)/lib$(LIBNAME).$(AR_EXT)
|
ARCHIVE = lib$(LIBNAME).$(AR_EXT)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -169,8 +167,6 @@ INSTALL_LIB ?= $(INSTALL_BIN) -m0755
|
||||||
PKGCFGF = $(LIBNAME).pc
|
PKGCFGF = $(LIBNAME).pc
|
||||||
PREFIX ?= /usr
|
PREFIX ?= /usr
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
BLDIR = .
|
|
||||||
OBJDIR = .
|
|
||||||
|
|
||||||
LIBDIRARCH ?= lib
|
LIBDIRARCH ?= lib
|
||||||
# Uncomment the below line to installs x86_64 libs to lib64/ directory.
|
# Uncomment the below line to installs x86_64 libs to lib64/ directory.
|
||||||
|
@ -200,75 +196,39 @@ else
|
||||||
PKGCFGDIR ?= $(LIBDATADIR)/pkgconfig
|
PKGCFGDIR ?= $(LIBDATADIR)/pkgconfig
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: compile_lib
|
.PHONY: all
|
||||||
ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY)))
|
all: unicorn
|
||||||
ifeq ($(UNICORN_SHARED),yes)
|
$(MAKE) -C samples
|
||||||
ifeq ($(V),0)
|
|
||||||
@$(INSTALL_LIB) $(LIBRARY) $(BLDIR)/samples/
|
|
||||||
else
|
|
||||||
$(INSTALL_LIB) $(LIBRARY) $(BLDIR)/samples/
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
@cd samples && $(MAKE)
|
|
||||||
endif
|
|
||||||
|
|
||||||
config:
|
config:
|
||||||
if [ "$(UNICORN_ARCHS)" != "`cat config.log`" ]; then $(MAKE) clean; fi
|
if [ "$(UNICORN_ARCHS)" != "`cat config.log`" ]; then $(MAKE) clean; fi
|
||||||
|
|
||||||
qemu/config-host.h-timestamp:
|
qemu/config-host.h-timestamp:
|
||||||
ifeq ($(UNICORN_DEBUG),yes)
|
|
||||||
cd qemu && \
|
cd qemu && \
|
||||||
./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS}
|
./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS}
|
||||||
printf "$(UNICORN_ARCHS)" > config.log
|
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
|
compile_lib: config qemu/config-host.h-timestamp
|
||||||
cd qemu && $(MAKE) -j 4
|
$(MAKE) -C qemu -j 4
|
||||||
$(MAKE) unicorn
|
|
||||||
|
|
||||||
unicorn: $(LIBRARY) $(ARCHIVE)
|
unicorn: compile_lib $(LIBRARY) $(ARCHIVE)
|
||||||
|
|
||||||
$(LIBRARY): $(UC_TARGET_OBJ) uc.o list.o
|
$(LIBRARY): $(UC_TARGET_OBJ)
|
||||||
ifeq ($(UNICORN_SHARED),yes)
|
$(CC) $(CFLAGS) -shared $(GENOBJ) uc.o list.o -o $(LIBRARY) $(GLIB) -lm $($(LIBNAME)_LDFLAGS)
|
||||||
ifeq ($(V),0)
|
ln -sf $(LIBRARY) $(LIBRARY_SYMLINK)
|
||||||
$(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
|
$(ARCHIVE): $(UC_TARGET_OBJ) uc.o list.o
|
||||||
ifeq ($(UNICORN_STATIC),yes)
|
$(AR) q $(ARCHIVE) $^
|
||||||
ifeq ($(V),0)
|
$(RANLIB) $(ARCHIVE)
|
||||||
$(call log,GEN,$(ARCHIVE))
|
|
||||||
@$(create-archive)
|
|
||||||
else
|
|
||||||
$(create-archive)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
$(PKGCFGF):
|
$(PKGCFGF):
|
||||||
ifeq ($(V),0)
|
|
||||||
$(call log,GEN,$(@:$(BLDIR)/%=%))
|
|
||||||
@$(generate-pkgcfg)
|
|
||||||
else
|
|
||||||
$(generate-pkgcfg)
|
$(generate-pkgcfg)
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: all
|
test: all
|
||||||
$(MAKE) -C tests/unit test
|
$(MAKE) -C tests/unit test
|
||||||
|
$(MAKE) -C bindings test
|
||||||
|
|
||||||
install: compile_lib $(PKGCFGF)
|
install: compile_lib $(PKGCFGF)
|
||||||
mkdir -p $(DESTDIR)$(LIBDIR)
|
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||||
|
@ -309,7 +269,7 @@ dist:
|
||||||
git archive --format=zip --prefix=unicorn-$(DIST_VERSION)/ $(TAG) > unicorn-$(DIST_VERSION).zip
|
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\
|
$(eval TARGETS := m68k arm aarch64 mips mipsel mips64 mips64el\
|
||||||
powerpc sparc sparc64 x86_64)
|
powerpc sparc sparc64 x86_64)
|
||||||
$(foreach var,$(TARGETS),\
|
$(foreach var,$(TARGETS),\
|
||||||
|
@ -328,10 +288,7 @@ clean:
|
||||||
$(MAKE) -C qemu clean
|
$(MAKE) -C qemu clean
|
||||||
rm -rf *.d *.o
|
rm -rf *.d *.o
|
||||||
rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll cyg$(LIBNAME)*.dll
|
rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll cyg$(LIBNAME)*.dll
|
||||||
ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY)))
|
$(MAKE) -C samples clean
|
||||||
cd samples && $(MAKE) clean
|
|
||||||
rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT)
|
|
||||||
endif
|
|
||||||
$(MAKE) -C tests/unit clean
|
$(MAKE) -C tests/unit clean
|
||||||
|
|
||||||
|
|
||||||
|
@ -351,10 +308,3 @@ define log
|
||||||
@printf " %-7s %s\n" "$(1)" "$(2)"
|
@printf " %-7s %s\n" "$(1)" "$(2)"
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define create-archive
|
|
||||||
$(AR) q $(ARCHIVE) $^
|
|
||||||
$(RANLIB) $(ARCHIVE)
|
|
||||||
endef
|
|
||||||
|
|
||||||
FORCE:
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ SAMPLE_X86 = $(TMP_DIR)/sample_x86
|
||||||
|
|
||||||
ENV_VARS = LD_LIBRARY_PATH=../ DYLD_LIBRARY_PATH=../
|
ENV_VARS = LD_LIBRARY_PATH=../ DYLD_LIBRARY_PATH=../
|
||||||
|
|
||||||
.PHONY: build install samples sample_python expected python sample_diff clean check
|
.PHONY: build install expected python sample_diff clean check test
|
||||||
|
|
||||||
build:
|
build:
|
||||||
$(MAKE) -C python gen_const
|
$(MAKE) -C python gen_const
|
||||||
|
@ -26,9 +26,7 @@ install: build
|
||||||
$(MAKE) -C python install
|
$(MAKE) -C python install
|
||||||
$(MAKE) -C java install
|
$(MAKE) -C java install
|
||||||
|
|
||||||
samples: expected python
|
test: expected python sample_diff
|
||||||
|
|
||||||
sample_python: expected python
|
|
||||||
|
|
||||||
expected:
|
expected:
|
||||||
$(MAKE) -C ../samples
|
$(MAKE) -C ../samples
|
||||||
|
@ -38,9 +36,11 @@ expected:
|
||||||
$(ENV_VARS) ../samples/sample_mips > $(SAMPLE_MIPS)_e
|
$(ENV_VARS) ../samples/sample_mips > $(SAMPLE_MIPS)_e
|
||||||
$(ENV_VARS) ../samples/sample_sparc > $(SAMPLE_SPARC)_e
|
$(ENV_VARS) ../samples/sample_sparc > $(SAMPLE_SPARC)_e
|
||||||
$(ENV_VARS) ../samples/sample_m68k > $(SAMPLE_M68K)_e
|
$(ENV_VARS) ../samples/sample_m68k > $(SAMPLE_M68K)_e
|
||||||
$(ENV_VARS) ../samples/sample_x86 > $(SAMPLE_X86)_e
|
$(ENV_VARS) ../samples/sample_x86 -16 > $(SAMPLE_X86)_e
|
||||||
|
$(ENV_VARS) ../samples/sample_x86 -32 >> $(SAMPLE_X86)_e
|
||||||
|
$(ENV_VARS) ../samples/sample_x86 -64 >> $(SAMPLE_X86)_e
|
||||||
|
|
||||||
python: FORCE
|
python:
|
||||||
$(MAKE) -C python
|
$(MAKE) -C python
|
||||||
$(ENV_VARS) python python/sample_arm.py > $(SAMPLE_ARM)_o
|
$(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_arm64.py > $(SAMPLE_ARM64)_o
|
||||||
|
@ -48,9 +48,8 @@ python: FORCE
|
||||||
$(ENV_VARS) python python/sample_sparc.py > $(SAMPLE_SPARC)_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_m68k.py > $(SAMPLE_M68K)_o
|
||||||
$(ENV_VARS) python python/sample_x86.py > $(SAMPLE_X86)_o
|
$(ENV_VARS) python python/sample_x86.py > $(SAMPLE_X86)_o
|
||||||
$(MAKE) sample_diff
|
|
||||||
|
|
||||||
sample_diff: FORCE
|
sample_diff:
|
||||||
$(DIFF) $(SAMPLE_ARM)_e $(SAMPLE_ARM)_o
|
$(DIFF) $(SAMPLE_ARM)_e $(SAMPLE_ARM)_o
|
||||||
$(DIFF) $(SAMPLE_ARM64)_e $(SAMPLE_ARM64)_o
|
$(DIFF) $(SAMPLE_ARM64)_e $(SAMPLE_ARM64)_o
|
||||||
$(DIFF) $(SAMPLE_MIPS)_e $(SAMPLE_MIPS)_o
|
$(DIFF) $(SAMPLE_MIPS)_e $(SAMPLE_MIPS)_o
|
||||||
|
@ -65,5 +64,3 @@ clean:
|
||||||
|
|
||||||
check:
|
check:
|
||||||
make -C python check
|
make -C python check
|
||||||
|
|
||||||
FORCE:
|
|
||||||
|
|
28
bindings/go/unicorn/context.go
Normal file
28
bindings/go/unicorn/context.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package unicorn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include <unicorn/unicorn.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type Context **C.uc_context
|
||||||
|
|
||||||
|
func (u *uc) ContextSave(reuse Context) (Context, error) {
|
||||||
|
ctx := reuse
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = new(*C.uc_context)
|
||||||
|
}
|
||||||
|
if err := errReturn(C.uc_context_alloc(u.handle, ctx)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
runtime.SetFinalizer(ctx, func(p Context) { C.uc_context_free(*p) })
|
||||||
|
if err := errReturn(C.uc_context_save(u.handle, *ctx)); err != nil {
|
||||||
|
}
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *uc) ContextRestore(ctx Context) error {
|
||||||
|
return errReturn(C.uc_context_restore(u.handle, *ctx))
|
||||||
|
}
|
26
bindings/go/unicorn/context_test.go
Normal file
26
bindings/go/unicorn/context_test.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package unicorn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContext(t *testing.T) {
|
||||||
|
u, err := NewUnicorn(ARCH_X86, MODE_32)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
u.RegWrite(X86_REG_EBP, 100)
|
||||||
|
ctx, err := u.ContextSave(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
u.RegWrite(X86_REG_EBP, 200)
|
||||||
|
err = u.ContextRestore(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
val, _ := u.RegRead(X86_REG_EBP)
|
||||||
|
if val != 100 {
|
||||||
|
t.Fatal("context restore failed")
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,6 +55,9 @@ type Unicorn interface {
|
||||||
HookDel(hook Hook) error
|
HookDel(hook Hook) error
|
||||||
Query(queryType int) (uint64, error)
|
Query(queryType int) (uint64, error)
|
||||||
Close() error
|
Close() error
|
||||||
|
|
||||||
|
ContextSave(reuse Context) (Context, error)
|
||||||
|
ContextRestore(Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type uc struct {
|
type uc struct {
|
||||||
|
|
|
@ -40,6 +40,10 @@ x86Code32JmpInvalid = BS.pack [0xe9, 0xe9, 0xee, 0xee, 0xee, 0x41, 0x4a]
|
||||||
x86Code32InOut :: BS.ByteString
|
x86Code32InOut :: BS.ByteString
|
||||||
x86Code32InOut = BS.pack [0x41, 0xe4, 0x3f, 0x4a, 0xe6, 0x46, 0x43]
|
x86Code32InOut = BS.pack [0x41, 0xe4, 0x3f, 0x4a, 0xe6, 0x46, 0x43]
|
||||||
|
|
||||||
|
-- inc eax
|
||||||
|
x86Code32Inc :: BS.ByteString
|
||||||
|
x86Code32Inc = BS.pack [0x40]
|
||||||
|
|
||||||
x86Code64 :: BS.ByteString
|
x86Code64 :: BS.ByteString
|
||||||
x86Code64 = BS.pack [0x41, 0xbc, 0x3b, 0xb0, 0x28, 0x2a, 0x49, 0x0f, 0xc9,
|
x86Code64 = BS.pack [0x41, 0xbc, 0x3b, 0xb0, 0x28, 0x2a, 0x49, 0x0f, 0xc9,
|
||||||
0x90, 0x4d, 0x0f, 0xad, 0xcf, 0x49, 0x87, 0xfd, 0x90,
|
0x90, 0x4d, 0x0f, 0xad, 0xcf, 0x49, 0x87, 0xfd, 0x90,
|
||||||
|
@ -494,6 +498,70 @@ testI386InOut = do
|
||||||
Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++
|
Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++
|
||||||
strerror err
|
strerror err
|
||||||
|
|
||||||
|
-- Emulate code and save/restore the CPU context
|
||||||
|
testI386ContextSave :: IO ()
|
||||||
|
testI386ContextSave = do
|
||||||
|
putStrLn "==================================="
|
||||||
|
putStrLn "Save/restore CPU context in opaque blob"
|
||||||
|
|
||||||
|
result <- runEmulator $ do
|
||||||
|
-- Initialize emulator in X86-32bit mode
|
||||||
|
uc <- open ArchX86 [Mode32]
|
||||||
|
|
||||||
|
-- Map 8KB memory for this emulation
|
||||||
|
memMap uc address (8 * 1024) [ProtAll]
|
||||||
|
|
||||||
|
-- Write machine code to be emulated to memory
|
||||||
|
memWrite uc address x86Code32Inc
|
||||||
|
|
||||||
|
-- Initialize machine registers
|
||||||
|
regWrite uc X86.Eax 0x1
|
||||||
|
|
||||||
|
-- Emulate machine code in infinite time
|
||||||
|
emuPutStrLn ">>> Running emulation for the first time"
|
||||||
|
|
||||||
|
let codeLen = codeLength x86Code32Inc
|
||||||
|
start uc address (address + codeLen) Nothing Nothing
|
||||||
|
|
||||||
|
-- Now print out some registers
|
||||||
|
emuPutStrLn ">>> Emulation done. Below is the CPU context"
|
||||||
|
|
||||||
|
eax <- regRead uc X86.Eax
|
||||||
|
|
||||||
|
emuPutStrLn $ ">>> EAX = 0x" ++ showHex eax
|
||||||
|
|
||||||
|
-- Allocate and save the CPU context
|
||||||
|
emuPutStrLn ">>> Saving CPU context"
|
||||||
|
|
||||||
|
context <- contextAllocate uc
|
||||||
|
contextSave uc context
|
||||||
|
|
||||||
|
-- Emulate machine code again
|
||||||
|
emuPutStrLn ">>> Running emulation for the second time"
|
||||||
|
|
||||||
|
start uc address (address + codeLen) Nothing Nothing
|
||||||
|
|
||||||
|
-- Now print out some registers
|
||||||
|
emuPutStrLn ">>> Emulation done. Below is the CPU context"
|
||||||
|
|
||||||
|
eax <- regRead uc X86.Eax
|
||||||
|
|
||||||
|
emuPutStrLn $ ">>> EAX = 0x" ++ showHex eax
|
||||||
|
|
||||||
|
-- Restore CPU context
|
||||||
|
contextRestore uc context
|
||||||
|
|
||||||
|
-- Now print out some registers
|
||||||
|
emuPutStrLn ">>> Emulation done. Below is the CPU context"
|
||||||
|
|
||||||
|
eax <- regRead uc X86.Eax
|
||||||
|
|
||||||
|
emuPutStrLn $ ">>> EAX = 0x" ++ showHex eax
|
||||||
|
case result of
|
||||||
|
Right _ -> return ()
|
||||||
|
Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++
|
||||||
|
strerror err
|
||||||
|
|
||||||
testX8664 :: IO ()
|
testX8664 :: IO ()
|
||||||
testX8664 = do
|
testX8664 = do
|
||||||
putStrLn "Emulate x86_64 code"
|
putStrLn "Emulate x86_64 code"
|
||||||
|
@ -660,6 +728,7 @@ main = do
|
||||||
["-32"] -> do
|
["-32"] -> do
|
||||||
testI386
|
testI386
|
||||||
testI386InOut
|
testI386InOut
|
||||||
|
testI386ContextSave
|
||||||
testI386Jump
|
testI386Jump
|
||||||
testI386Loop
|
testI386Loop
|
||||||
testI386InvalidMemRead
|
testI386InvalidMemRead
|
||||||
|
|
|
@ -9,41 +9,47 @@ framework based on QEMU.
|
||||||
|
|
||||||
Further information is available at <http://www.unicorn-engine.org>.
|
Further information is available at <http://www.unicorn-engine.org>.
|
||||||
-}
|
-}
|
||||||
module Unicorn (
|
module Unicorn
|
||||||
-- * Emulator control
|
( -- * Emulator control
|
||||||
Emulator,
|
Emulator
|
||||||
Engine,
|
, Engine
|
||||||
Architecture(..),
|
, Architecture(..)
|
||||||
Mode(..),
|
, Mode(..)
|
||||||
QueryType(..),
|
, QueryType(..)
|
||||||
runEmulator,
|
, runEmulator
|
||||||
open,
|
, open
|
||||||
query,
|
, query
|
||||||
start,
|
, start
|
||||||
stop,
|
, stop
|
||||||
|
|
||||||
-- * Register operations
|
-- * Register operations
|
||||||
regWrite,
|
, regWrite
|
||||||
regRead,
|
, regRead
|
||||||
|
|
||||||
-- * Memory operations
|
-- * Memory operations
|
||||||
MemoryPermission(..),
|
, MemoryPermission(..)
|
||||||
MemoryRegion(..),
|
, MemoryRegion(..)
|
||||||
memWrite,
|
, memWrite
|
||||||
memRead,
|
, memRead
|
||||||
memMap,
|
, memMap
|
||||||
memUnmap,
|
, memUnmap
|
||||||
memProtect,
|
, memProtect
|
||||||
memRegions,
|
, memRegions
|
||||||
|
|
||||||
-- * Error handling
|
-- * Context operations
|
||||||
Error(..),
|
, Context
|
||||||
errno,
|
, contextAllocate
|
||||||
strerror,
|
, contextSave
|
||||||
|
, contextRestore
|
||||||
|
|
||||||
-- * Misc.
|
-- * Error handling
|
||||||
version,
|
, Error(..)
|
||||||
) where
|
, errno
|
||||||
|
, strerror
|
||||||
|
|
||||||
|
-- * Misc.
|
||||||
|
, version
|
||||||
|
) where
|
||||||
|
|
||||||
import Control.Monad (liftM)
|
import Control.Monad (liftM)
|
||||||
import Control.Monad.Trans.Class (lift)
|
import Control.Monad.Trans.Class (lift)
|
||||||
|
@ -132,8 +138,8 @@ stop uc = do
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- | Write to register.
|
-- | Write to register.
|
||||||
regWrite :: Reg r =>
|
regWrite :: Reg r
|
||||||
Engine -- ^ 'Unicorn' engine handle
|
=> Engine -- ^ 'Unicorn' engine handle
|
||||||
-> r -- ^ Register ID to write to
|
-> r -- ^ Register ID to write to
|
||||||
-> Int64 -- ^ Value to write to register
|
-> Int64 -- ^ Value to write to register
|
||||||
-> Emulator () -- ^ An 'Error' on failure
|
-> Emulator () -- ^ An 'Error' on failure
|
||||||
|
@ -147,8 +153,8 @@ regWrite uc regId value = do
|
||||||
left err
|
left err
|
||||||
|
|
||||||
-- | Read register value.
|
-- | Read register value.
|
||||||
regRead :: Reg r =>
|
regRead :: Reg r
|
||||||
Engine -- ^ 'Unicorn' engine handle
|
=> Engine -- ^ 'Unicorn' engine handle
|
||||||
-> r -- ^ Register ID to read from
|
-> r -- ^ Register ID to read from
|
||||||
-> Emulator Int64 -- ^ The value read from the register on success,
|
-> Emulator Int64 -- ^ The value read from the register on success,
|
||||||
-- or an 'Error' on failure
|
-- or an 'Error' on failure
|
||||||
|
@ -259,6 +265,46 @@ memRegions uc = do
|
||||||
else
|
else
|
||||||
left err
|
left err
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Context operations
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- | Allocate a region that can be used to perform quick save/rollback of the
|
||||||
|
-- CPU context, which includes registers and some internal metadata. Contexts
|
||||||
|
-- may not be shared across engine instances with differing architectures or
|
||||||
|
-- modes.
|
||||||
|
contextAllocate :: Engine -- ^ 'Unicon' engine handle
|
||||||
|
-> Emulator Context -- ^ A CPU context
|
||||||
|
contextAllocate uc = do
|
||||||
|
(err, contextPtr) <- lift $ ucContextAlloc uc
|
||||||
|
if err == ErrOk then
|
||||||
|
-- Return a CPU context if ucContextAlloc completed successfully
|
||||||
|
lift $ mkContext contextPtr
|
||||||
|
else
|
||||||
|
left err
|
||||||
|
|
||||||
|
-- | Save a copy of the internal CPU context.
|
||||||
|
contextSave :: Engine -- ^ 'Unicorn' engine handle
|
||||||
|
-> Context -- ^ A CPU context
|
||||||
|
-> Emulator () -- ^ An error on failure
|
||||||
|
contextSave uc context = do
|
||||||
|
err <- lift $ ucContextSave uc context
|
||||||
|
if err == ErrOk then
|
||||||
|
right ()
|
||||||
|
else
|
||||||
|
left err
|
||||||
|
|
||||||
|
-- | Restore the current CPU context from a saved copy.
|
||||||
|
contextRestore :: Engine -- ^ 'Unicorn' engine handle
|
||||||
|
-> Context -- ^ A CPU context
|
||||||
|
-> Emulator () -- ^ An error on failure
|
||||||
|
contextRestore uc context = do
|
||||||
|
err <- lift $ ucContextRestore uc context
|
||||||
|
if err == ErrOk then
|
||||||
|
right ()
|
||||||
|
else
|
||||||
|
left err
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Misc.
|
-- Misc.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
|
@ -8,22 +8,25 @@ License : GPL-2
|
||||||
|
|
||||||
Definitions for the ARM architecture.
|
Definitions for the ARM architecture.
|
||||||
-}
|
-}
|
||||||
module Unicorn.CPU.Arm (
|
module Unicorn.CPU.Arm
|
||||||
Register(..),
|
(
|
||||||
) where
|
Register(..)
|
||||||
|
) where
|
||||||
|
|
||||||
import Unicorn.Internal.Core (Reg)
|
import Unicorn.Internal.Core (Reg)
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/arm.h>
|
#include <unicorn/arm.h>
|
||||||
|
|
||||||
-- | ARM registers.
|
-- | ARM registers.
|
||||||
{# enum uc_arm_reg as Register
|
{# enum uc_arm_reg as Register
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_ARM_REG_INVALID,
|
omit ( UC_ARM_REG_INVALID
|
||||||
UC_ARM_REG_ENDING)
|
, UC_ARM_REG_ENDING
|
||||||
with prefix="UC_ARM_REG_"
|
)
|
||||||
deriving (Show, Eq, Bounded) #}
|
with prefix = "UC_ARM_REG_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
instance Reg Register
|
instance Reg Register
|
||||||
|
|
|
@ -8,22 +8,25 @@ License : GPL-2
|
||||||
|
|
||||||
Definitions for the ARM64 (ARMv8) architecture.
|
Definitions for the ARM64 (ARMv8) architecture.
|
||||||
-}
|
-}
|
||||||
module Unicorn.CPU.Arm64 (
|
module Unicorn.CPU.Arm64
|
||||||
Register(..),
|
(
|
||||||
) where
|
Register(..)
|
||||||
|
) where
|
||||||
|
|
||||||
import Unicorn.Internal.Core (Reg)
|
import Unicorn.Internal.Core (Reg)
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/arm64.h>
|
#include <unicorn/arm64.h>
|
||||||
|
|
||||||
-- | ARM64 registers.
|
-- | ARM64 registers.
|
||||||
{# enum uc_arm64_reg as Register
|
{# enum uc_arm64_reg as Register
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_ARM64_REG_INVALID,
|
omit ( UC_ARM64_REG_INVALID
|
||||||
UC_ARM64_REG_ENDING)
|
, UC_ARM64_REG_ENDING
|
||||||
with prefix="UC_ARM64_REG_"
|
)
|
||||||
deriving (Show, Eq, Bounded) #}
|
with prefix = "UC_ARM64_REG_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
instance Reg Register
|
instance Reg Register
|
||||||
|
|
|
@ -8,22 +8,25 @@ License : GPL-2
|
||||||
|
|
||||||
Definitions for the MK68K architecture.
|
Definitions for the MK68K architecture.
|
||||||
-}
|
-}
|
||||||
module Unicorn.CPU.M68k (
|
module Unicorn.CPU.M68k
|
||||||
Register(..),
|
(
|
||||||
) where
|
Register(..)
|
||||||
|
) where
|
||||||
|
|
||||||
import Unicorn.Internal.Core (Reg)
|
import Unicorn.Internal.Core (Reg)
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/m68k.h>
|
#include <unicorn/m68k.h>
|
||||||
|
|
||||||
-- | M68K registers.
|
-- | M68K registers.
|
||||||
{# enum uc_m68k_reg as Register
|
{# enum uc_m68k_reg as Register
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_M68K_REG_INVALID,
|
omit ( UC_M68K_REG_INVALID
|
||||||
UC_M68K_REG_ENDING)
|
, UC_M68K_REG_ENDING
|
||||||
with prefix="UC_M68K_REG_"
|
)
|
||||||
deriving (Show, Eq, Bounded) #}
|
with prefix = "UC_M68K_REG_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
instance Reg Register
|
instance Reg Register
|
||||||
|
|
|
@ -8,54 +8,58 @@ License : GPL-2
|
||||||
|
|
||||||
Definitions for the MIPS architecture.
|
Definitions for the MIPS architecture.
|
||||||
-}
|
-}
|
||||||
module Unicorn.CPU.Mips (
|
module Unicorn.CPU.Mips
|
||||||
Register(..),
|
(
|
||||||
) where
|
Register(..)
|
||||||
|
) where
|
||||||
|
|
||||||
import Unicorn.Internal.Core (Reg)
|
import Unicorn.Internal.Core (Reg)
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/mips.h>
|
#include <unicorn/mips.h>
|
||||||
|
|
||||||
-- | MIPS registers.
|
-- | MIPS registers.
|
||||||
{# enum UC_MIPS_REG as Register
|
{# enum UC_MIPS_REG as Register
|
||||||
{underscoreToCase,
|
{ underscoreToCase
|
||||||
UC_MIPS_REG_0 as Reg0,
|
, UC_MIPS_REG_0 as Reg0g
|
||||||
UC_MIPS_REG_1 as Reg1,
|
, UC_MIPS_REG_1 as Reg1g
|
||||||
UC_MIPS_REG_2 as Reg2,
|
, UC_MIPS_REG_2 as Reg2g
|
||||||
UC_MIPS_REG_3 as Reg3,
|
, UC_MIPS_REG_3 as Reg3g
|
||||||
UC_MIPS_REG_4 as Reg4,
|
, UC_MIPS_REG_4 as Reg4g
|
||||||
UC_MIPS_REG_5 as Reg5,
|
, UC_MIPS_REG_5 as Reg5g
|
||||||
UC_MIPS_REG_6 as Reg6,
|
, UC_MIPS_REG_6 as Reg6g
|
||||||
UC_MIPS_REG_7 as Reg7,
|
, UC_MIPS_REG_7 as Reg7g
|
||||||
UC_MIPS_REG_8 as Reg8,
|
, UC_MIPS_REG_8 as Reg8g
|
||||||
UC_MIPS_REG_9 as Reg9,
|
, UC_MIPS_REG_9 as Reg9g
|
||||||
UC_MIPS_REG_10 as Reg10,
|
, UC_MIPS_REG_10 as Reg10g
|
||||||
UC_MIPS_REG_11 as Reg11,
|
, UC_MIPS_REG_11 as Reg11g
|
||||||
UC_MIPS_REG_12 as Reg12,
|
, UC_MIPS_REG_12 as Reg12g
|
||||||
UC_MIPS_REG_13 as Reg13,
|
, UC_MIPS_REG_13 as Reg13g
|
||||||
UC_MIPS_REG_14 as Reg14,
|
, UC_MIPS_REG_14 as Reg14g
|
||||||
UC_MIPS_REG_15 as Reg15,
|
, UC_MIPS_REG_15 as Reg15g
|
||||||
UC_MIPS_REG_16 as Reg16,
|
, UC_MIPS_REG_16 as Reg16g
|
||||||
UC_MIPS_REG_17 as Reg17,
|
, UC_MIPS_REG_17 as Reg17g
|
||||||
UC_MIPS_REG_18 as Reg18,
|
, UC_MIPS_REG_18 as Reg18g
|
||||||
UC_MIPS_REG_19 as Reg19,
|
, UC_MIPS_REG_19 as Reg19g
|
||||||
UC_MIPS_REG_20 as Reg20,
|
, UC_MIPS_REG_20 as Reg20g
|
||||||
UC_MIPS_REG_21 as Reg21,
|
, UC_MIPS_REG_21 as Reg21g
|
||||||
UC_MIPS_REG_22 as Reg22,
|
, UC_MIPS_REG_22 as Reg22g
|
||||||
UC_MIPS_REG_23 as Reg23,
|
, UC_MIPS_REG_23 as Reg23g
|
||||||
UC_MIPS_REG_24 as Reg24,
|
, UC_MIPS_REG_24 as Reg24g
|
||||||
UC_MIPS_REG_25 as Reg25,
|
, UC_MIPS_REG_25 as Reg25g
|
||||||
UC_MIPS_REG_26 as Reg26,
|
, UC_MIPS_REG_26 as Reg26g
|
||||||
UC_MIPS_REG_27 as Reg27,
|
, UC_MIPS_REG_27 as Reg27g
|
||||||
UC_MIPS_REG_28 as Reg28,
|
, UC_MIPS_REG_28 as Reg28g
|
||||||
UC_MIPS_REG_29 as Reg29,
|
, UC_MIPS_REG_29 as Reg29g
|
||||||
UC_MIPS_REG_30 as Reg30,
|
, UC_MIPS_REG_30 as Reg30g
|
||||||
UC_MIPS_REG_31 as Reg31}
|
, UC_MIPS_REG_31 as Reg31
|
||||||
omit (UC_MIPS_REG_INVALID,
|
}
|
||||||
UC_MIPS_REG_ENDING)
|
omit ( UC_MIPS_REG_INVALID
|
||||||
with prefix="UC_MIPS_REG_"
|
, UC_MIPS_REG_ENDING
|
||||||
deriving (Show, Eq, Bounded) #}
|
)
|
||||||
|
with prefix = "UC_MIPS_REG_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
instance Reg Register
|
instance Reg Register
|
||||||
|
|
|
@ -8,22 +8,25 @@ License : GPL-2
|
||||||
|
|
||||||
Definitions for the SPARC architecture.
|
Definitions for the SPARC architecture.
|
||||||
-}
|
-}
|
||||||
module Unicorn.CPU.Sparc (
|
module Unicorn.CPU.Sparc
|
||||||
Register(..),
|
(
|
||||||
) where
|
Register(..)
|
||||||
|
) where
|
||||||
|
|
||||||
import Unicorn.Internal.Core (Reg)
|
import Unicorn.Internal.Core (Reg)
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/sparc.h>
|
#include <unicorn/sparc.h>
|
||||||
|
|
||||||
-- | SPARC registers.
|
-- | SPARC registers.
|
||||||
{# enum uc_sparc_reg as Register
|
{# enum uc_sparc_reg as Register
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_SPARC_REG_INVALID,
|
omit (UC_SPARC_REG_INVALID
|
||||||
UC_SPARC_REG_ENDING)
|
, UC_SPARC_REG_ENDING
|
||||||
with prefix="UC_SPARC_REG_"
|
)
|
||||||
deriving (Show, Eq, Bounded) #}
|
with prefix = "UC_SPARC_REG_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
instance Reg Register
|
instance Reg Register
|
||||||
|
|
|
@ -8,11 +8,12 @@ License : GPL-2
|
||||||
|
|
||||||
Definitions for the X86 architecture.
|
Definitions for the X86 architecture.
|
||||||
-}
|
-}
|
||||||
module Unicorn.CPU.X86 (
|
module Unicorn.CPU.X86
|
||||||
Mmr(..),
|
(
|
||||||
Register(..),
|
Mmr(..)
|
||||||
Instruction(..),
|
, Register(..)
|
||||||
) where
|
, Instruction(..)
|
||||||
|
) where
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Data.Word
|
import Data.Word
|
||||||
|
@ -20,18 +21,18 @@ import Foreign
|
||||||
|
|
||||||
import Unicorn.Internal.Core (Reg)
|
import Unicorn.Internal.Core (Reg)
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/x86.h>
|
#include <unicorn/x86.h>
|
||||||
|
|
||||||
-- | Memory-managemen Register for instructions IDTR, GDTR, LDTR, TR.
|
-- | Memory-managemen Register for instructions IDTR, GDTR, LDTR, TR.
|
||||||
-- Borrow from SegmentCache in qemu/target-i386/cpu.h
|
-- Borrow from SegmentCache in qemu/target-i386/cpu.h
|
||||||
data Mmr = Mmr {
|
data Mmr = Mmr
|
||||||
mmrSelector :: Word16, -- ^ Not used by GDTR and IDTR
|
{ mmrSelector :: Word16 -- ^ Not used by GDTR and IDTR
|
||||||
mmrBase :: Word64, -- ^ Handle 32 or 64 bit CPUs
|
, mmrBase :: Word64 -- ^ Handle 32 or 64 bit CPUs
|
||||||
mmrLimit :: Word32,
|
, mmrLimit :: Word32
|
||||||
mmrFlags :: Word32 -- ^ Not used by GDTR and IDTR
|
, mmrFlags :: Word32 -- ^ Not used by GDTR and IDTR
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Storable Mmr where
|
instance Storable Mmr where
|
||||||
sizeOf _ = {# sizeof uc_x86_mmr #}
|
sizeOf _ = {# sizeof uc_x86_mmr #}
|
||||||
|
@ -48,18 +49,22 @@ instance Storable Mmr where
|
||||||
|
|
||||||
-- | X86 registers.
|
-- | X86 registers.
|
||||||
{# enum uc_x86_reg as Register
|
{# enum uc_x86_reg as Register
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_X86_REG_INVALID,
|
omit ( UC_X86_REG_INVALID
|
||||||
UC_X86_REG_ENDING)
|
, UC_X86_REG_ENDING
|
||||||
with prefix="UC_X86_REG_"
|
)
|
||||||
deriving (Show, Eq, Bounded) #}
|
with prefix = "UC_X86_REG_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
instance Reg Register
|
instance Reg Register
|
||||||
|
|
||||||
-- | X86 instructions.
|
-- | X86 instructions.
|
||||||
{# enum uc_x86_insn as Instruction
|
{# enum uc_x86_insn as Instruction
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_X86_INS_INVALID,
|
omit ( UC_X86_INS_INVALID
|
||||||
UC_X86_INS_ENDING)
|
, UC_X86_INS_ENDING
|
||||||
with prefix="UC_X86_INS_"
|
)
|
||||||
deriving (Show, Eq, Bounded) #}
|
with prefix = "UC_X86_INS_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
|
@ -6,36 +6,36 @@ License : GPL-2
|
||||||
|
|
||||||
Insert hook points into the Unicorn emulator engine.
|
Insert hook points into the Unicorn emulator engine.
|
||||||
-}
|
-}
|
||||||
module Unicorn.Hook (
|
module Unicorn.Hook
|
||||||
-- * Hook types
|
( -- * Hook types
|
||||||
Hook,
|
Hook
|
||||||
MemoryHookType(..),
|
, MemoryHookType(..)
|
||||||
MemoryEventHookType(..),
|
, MemoryEventHookType(..)
|
||||||
MemoryAccess(..),
|
, MemoryAccess(..)
|
||||||
|
|
||||||
-- * Hook callbacks
|
-- * Hook callbacks
|
||||||
CodeHook,
|
, CodeHook
|
||||||
InterruptHook,
|
, InterruptHook
|
||||||
BlockHook,
|
, BlockHook
|
||||||
InHook,
|
, InHook
|
||||||
OutHook,
|
, OutHook
|
||||||
SyscallHook,
|
, SyscallHook
|
||||||
MemoryHook,
|
, MemoryHook
|
||||||
MemoryReadHook,
|
, MemoryReadHook
|
||||||
MemoryWriteHook,
|
, MemoryWriteHook
|
||||||
MemoryEventHook,
|
, MemoryEventHook
|
||||||
|
|
||||||
-- * Hook callback management
|
-- * Hook callback management
|
||||||
codeHookAdd,
|
, codeHookAdd
|
||||||
interruptHookAdd,
|
, interruptHookAdd
|
||||||
blockHookAdd,
|
, blockHookAdd
|
||||||
inHookAdd,
|
, inHookAdd
|
||||||
outHookAdd,
|
, outHookAdd
|
||||||
syscallHookAdd,
|
, syscallHookAdd
|
||||||
memoryHookAdd,
|
, memoryHookAdd
|
||||||
memoryEventHookAdd,
|
, memoryEventHookAdd
|
||||||
hookDel,
|
, hookDel
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Trans.Class
|
import Control.Monad.Trans.Class
|
||||||
|
@ -213,7 +213,8 @@ hookDel uc hook = do
|
||||||
-- Takes the tuple returned by `ucHookAdd`, an IO (Error, Hook), and
|
-- Takes the tuple returned by `ucHookAdd`, an IO (Error, Hook), and
|
||||||
-- returns either a `Right Hook` if no error occurred or a `Left Error` if an
|
-- returns either a `Right Hook` if no error occurred or a `Left Error` if an
|
||||||
-- error occurred
|
-- error occurred
|
||||||
getResult :: IO (Error, Hook) -> IO (Either Error Hook)
|
getResult :: IO (Error, Hook)
|
||||||
|
-> IO (Either Error Hook)
|
||||||
getResult =
|
getResult =
|
||||||
liftM (uncurry checkResult)
|
liftM (uncurry checkResult)
|
||||||
where checkResult err hook =
|
where checkResult err hook =
|
||||||
|
|
|
@ -17,31 +17,34 @@ import Control.Monad
|
||||||
import Control.Monad.Trans.Either (EitherT)
|
import Control.Monad.Trans.Either (EitherT)
|
||||||
import Foreign
|
import Foreign
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include "unicorn_wrapper.h"
|
#include "unicorn_wrapper.h"
|
||||||
|
|
||||||
-- | The Unicorn engine.
|
-- | The Unicorn engine.
|
||||||
{# pointer *uc_engine as Engine
|
{# pointer *uc_engine as Engine
|
||||||
foreign finalizer uc_close_wrapper as close
|
foreign finalizer uc_close_wrapper as close
|
||||||
newtype #}
|
newtype
|
||||||
|
#}
|
||||||
|
|
||||||
-- | A pointer to a Unicorn engine.
|
-- | A pointer to a Unicorn engine.
|
||||||
{# pointer *uc_engine as EnginePtr -> Engine #}
|
{# pointer *uc_engine as EnginePtr -> Engine #}
|
||||||
|
|
||||||
-- | Make a new Unicorn engine out of an engine pointer. The returned Unicorn
|
-- | Make a new Unicorn engine out of an engine pointer. The returned Unicorn
|
||||||
-- engine will automatically call 'uc_close_wrapper' when it goes out of scope.
|
-- engine will automatically call 'uc_close_wrapper' when it goes out of scope.
|
||||||
mkEngine :: EnginePtr -> IO Engine
|
mkEngine :: EnginePtr
|
||||||
|
-> IO Engine
|
||||||
mkEngine ptr =
|
mkEngine ptr =
|
||||||
liftM Engine (newForeignPtr close ptr)
|
liftM Engine (newForeignPtr close ptr)
|
||||||
|
|
||||||
-- | Errors encountered by the Unicorn API. These values are returned by
|
-- | Errors encountered by the Unicorn API. These values are returned by
|
||||||
-- 'errno'.
|
-- 'errno'.
|
||||||
{# enum uc_err as Error
|
{# enum uc_err as Error
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
with prefix="UC_"
|
with prefix = "UC_"
|
||||||
deriving (Show, Eq, Bounded) #}
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
-- | The emulator runs in the IO monad and allows for the handling of errors
|
-- | The emulator runs in the IO monad and allows for the handling of errors
|
||||||
-- "under the hood".
|
-- "under the hood".
|
||||||
|
|
|
@ -11,54 +11,54 @@ Low-level bindings for inserting hook points into the Unicorn emulator engine.
|
||||||
This module should not be directly imported; it is only exposed because of the
|
This module should not be directly imported; it is only exposed because of the
|
||||||
way cabal handles ordering of chs files.
|
way cabal handles ordering of chs files.
|
||||||
-}
|
-}
|
||||||
module Unicorn.Internal.Hook (
|
module Unicorn.Internal.Hook
|
||||||
-- * Types
|
( -- * Types
|
||||||
Hook,
|
Hook
|
||||||
HookType(..),
|
, HookType(..)
|
||||||
MemoryHookType(..),
|
, MemoryHookType(..)
|
||||||
MemoryEventHookType(..),
|
, MemoryEventHookType(..)
|
||||||
MemoryAccess(..),
|
, MemoryAccess(..)
|
||||||
|
|
||||||
-- * Hook callback bindings
|
-- * Hook callback bindings
|
||||||
CodeHook,
|
, CodeHook
|
||||||
InterruptHook,
|
, InterruptHook
|
||||||
BlockHook,
|
, BlockHook
|
||||||
InHook,
|
, InHook
|
||||||
OutHook,
|
, OutHook
|
||||||
SyscallHook,
|
, SyscallHook
|
||||||
MemoryHook,
|
, MemoryHook
|
||||||
MemoryReadHook,
|
, MemoryReadHook
|
||||||
MemoryWriteHook,
|
, MemoryWriteHook
|
||||||
MemoryEventHook,
|
, MemoryEventHook
|
||||||
|
|
||||||
-- * Hook marshalling
|
-- * Hook marshallin
|
||||||
marshalCodeHook,
|
, marshalCodeHook
|
||||||
marshalInterruptHook,
|
, marshalInterruptHook
|
||||||
marshalBlockHook,
|
, marshalBlockHook
|
||||||
marshalInHook,
|
, marshalInHook
|
||||||
marshalOutHook,
|
, marshalOutHook
|
||||||
marshalSyscallHook,
|
, marshalSyscallHook
|
||||||
marshalMemoryHook,
|
, marshalMemoryHook
|
||||||
marshalMemoryReadHook,
|
, marshalMemoryReadHook
|
||||||
marshalMemoryWriteHook,
|
, marshalMemoryWriteHook
|
||||||
marshalMemoryEventHook,
|
, marshalMemoryEventHook
|
||||||
|
|
||||||
-- * Hook registration and deletion bindings
|
-- * Hook registration and deletion bindings
|
||||||
ucHookAdd,
|
, ucHookAdd
|
||||||
ucInsnHookAdd,
|
, ucInsnHookAdd
|
||||||
ucHookDel,
|
, ucHookDel
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Foreign
|
import Foreign
|
||||||
|
|
||||||
import Unicorn.Internal.Util
|
import Unicorn.Internal.Util
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
|
||||||
|
|
||||||
{# import Unicorn.Internal.Core #}
|
{# import Unicorn.Internal.Core #}
|
||||||
{# import Unicorn.CPU.X86 #}
|
{# import Unicorn.CPU.X86 #}
|
||||||
|
|
||||||
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include "unicorn_wrapper.h"
|
#include "unicorn_wrapper.h"
|
||||||
|
|
||||||
|
@ -79,7 +79,8 @@ import Unicorn.Internal.Util
|
||||||
foreign import ccall "&uc_close_dummy"
|
foreign import ccall "&uc_close_dummy"
|
||||||
closeDummy :: FunPtr (EnginePtr -> IO ())
|
closeDummy :: FunPtr (EnginePtr -> IO ())
|
||||||
|
|
||||||
mkEngineNC :: EnginePtr -> IO Engine
|
mkEngineNC :: EnginePtr
|
||||||
|
-> IO Engine
|
||||||
mkEngineNC ptr =
|
mkEngineNC ptr =
|
||||||
liftM Engine (newForeignPtr closeDummy ptr)
|
liftM Engine (newForeignPtr closeDummy ptr)
|
||||||
|
|
||||||
|
@ -92,47 +93,55 @@ type Hook = {# type uc_hook #}
|
||||||
-- Note that the both valid and invalid memory access hooks are omitted from
|
-- Note that the both valid and invalid memory access hooks are omitted from
|
||||||
-- this enum (and are exposed to the user).
|
-- this enum (and are exposed to the user).
|
||||||
{# enum uc_hook_type as HookType
|
{# enum uc_hook_type as HookType
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_HOOK_MEM_READ_UNMAPPED,
|
omit ( UC_HOOK_MEM_READ_UNMAPPED
|
||||||
UC_HOOK_MEM_WRITE_UNMAPPED,
|
, UC_HOOK_MEM_WRITE_UNMAPPED
|
||||||
UC_HOOK_MEM_FETCH_UNMAPPED,
|
, UC_HOOK_MEM_FETCH_UNMAPPED
|
||||||
UC_HOOK_MEM_READ_PROT,
|
, UC_HOOK_MEM_READ_PROT
|
||||||
UC_HOOK_MEM_WRITE_PROT,
|
, UC_HOOK_MEM_WRITE_PROT
|
||||||
UC_HOOK_MEM_FETCH_PROT,
|
, UC_HOOK_MEM_FETCH_PROT
|
||||||
UC_HOOK_MEM_READ,
|
, UC_HOOK_MEM_READ
|
||||||
UC_HOOK_MEM_WRITE,
|
, UC_HOOK_MEM_WRITE
|
||||||
UC_HOOK_MEM_FETCH)
|
, UC_HOOK_MEM_FETCH
|
||||||
with prefix="UC_"
|
, UC_HOOK_MEM_READ_AFTER
|
||||||
deriving (Show, Eq, Bounded) #}
|
)
|
||||||
|
with prefix = "UC_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
-- | Memory hook types (for valid memory accesses).
|
-- | Memory hook types (for valid memory accesses).
|
||||||
{# enum uc_hook_type as MemoryHookType
|
{# enum uc_hook_type as MemoryHookType
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_HOOK_INTR,
|
omit ( UC_HOOK_INTR
|
||||||
UC_HOOK_INSN,
|
, UC_HOOK_INSN
|
||||||
UC_HOOK_CODE,
|
, UC_HOOK_CODE
|
||||||
UC_HOOK_BLOCK,
|
, UC_HOOK_BLOCK
|
||||||
UC_HOOK_MEM_READ_UNMAPPED,
|
, UC_HOOK_MEM_READ_UNMAPPED
|
||||||
UC_HOOK_MEM_WRITE_UNMAPPED,
|
, UC_HOOK_MEM_WRITE_UNMAPPED
|
||||||
UC_HOOK_MEM_FETCH_UNMAPPED,
|
, UC_HOOK_MEM_FETCH_UNMAPPED
|
||||||
UC_HOOK_MEM_READ_PROT,
|
, UC_HOOK_MEM_READ_PROT
|
||||||
UC_HOOK_MEM_WRITE_PROT,
|
, UC_HOOK_MEM_WRITE_PROT
|
||||||
UC_HOOK_MEM_FETCH_PROT)
|
, UC_HOOK_MEM_FETCH_PROT
|
||||||
with prefix="UC_"
|
)
|
||||||
deriving (Show, Eq, Bounded) #}
|
with prefix = "UC_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
-- | Memory event hook types (for invalid memory accesses).
|
-- | Memory event hook types (for invalid memory accesses).
|
||||||
{# enum uc_hook_type as MemoryEventHookType
|
{# enum uc_hook_type as MemoryEventHookType
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
omit (UC_HOOK_INTR,
|
omit ( UC_HOOK_INTR
|
||||||
UC_HOOK_INSN,
|
, UC_HOOK_INSN
|
||||||
UC_HOOK_CODE,
|
, UC_HOOK_CODE
|
||||||
UC_HOOK_BLOCK,
|
, UC_HOOK_BLOCK
|
||||||
UC_HOOK_MEM_READ,
|
, UC_HOOK_MEM_READ
|
||||||
UC_HOOK_MEM_WRITE,
|
, UC_HOOK_MEM_WRITE
|
||||||
UC_HOOK_MEM_FETCH)
|
, UC_HOOK_MEM_FETCH
|
||||||
with prefix="UC_"
|
, UC_HOOK_MEM_READ_AFTER
|
||||||
deriving (Show, Eq, Bounded) #}
|
)
|
||||||
|
with prefix = "UC_"
|
||||||
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
-- | Unify the hook types with a type class
|
-- | Unify the hook types with a type class
|
||||||
class Enum a => HookTypeC a
|
class Enum a => HookTypeC a
|
||||||
|
@ -143,9 +152,10 @@ instance HookTypeC MemoryEventHookType
|
||||||
|
|
||||||
-- | Memory access.
|
-- | Memory access.
|
||||||
{# enum uc_mem_type as MemoryAccess
|
{# enum uc_mem_type as MemoryAccess
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
with prefix="UC_"
|
with prefix = "UC_"
|
||||||
deriving (Show, Eq, Bounded) #}
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Hook callbacks
|
-- Hook callbacks
|
||||||
|
@ -159,16 +169,18 @@ type CodeHook a = Engine -- ^ 'Unicorn' engine handle
|
||||||
-> a -- ^ User data passed to tracing APIs
|
-> a -- ^ User data passed to tracing APIs
|
||||||
-> IO ()
|
-> IO ()
|
||||||
|
|
||||||
type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO ()
|
type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO ()
|
||||||
|
|
||||||
foreign import ccall "wrapper"
|
foreign import ccall "wrapper"
|
||||||
mkCodeHook :: CCodeHook -> IO {# type uc_cb_hookcode_t #}
|
mkCodeHook :: CCodeHook
|
||||||
|
-> IO {# type uc_cb_hookcode_t #}
|
||||||
|
|
||||||
marshalCodeHook :: Storable a
|
marshalCodeHook :: Storable a
|
||||||
=> CodeHook a -> IO {# type uc_cb_hookcode_t #}
|
=> CodeHook a
|
||||||
|
-> IO {# type uc_cb_hookcode_t #}
|
||||||
marshalCodeHook codeHook =
|
marshalCodeHook codeHook =
|
||||||
mkCodeHook $ \ucPtr address size userDataPtr -> do
|
mkCodeHook $ \ucPtr address size userDataPtr -> do
|
||||||
uc <- mkEngineNC ucPtr
|
uc <- mkEngineNC ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
let maybeSize = if size == 0 then Nothing
|
let maybeSize = if size == 0 then Nothing
|
||||||
else Just $ fromIntegral size
|
else Just $ fromIntegral size
|
||||||
|
@ -186,10 +198,11 @@ foreign import ccall "wrapper"
|
||||||
mkInterruptHook :: CInterruptHook -> IO {# type uc_cb_hookintr_t #}
|
mkInterruptHook :: CInterruptHook -> IO {# type uc_cb_hookintr_t #}
|
||||||
|
|
||||||
marshalInterruptHook :: Storable a
|
marshalInterruptHook :: Storable a
|
||||||
=> InterruptHook a -> IO {# type uc_cb_hookintr_t #}
|
=> InterruptHook a
|
||||||
|
-> IO {# type uc_cb_hookintr_t #}
|
||||||
marshalInterruptHook interruptHook =
|
marshalInterruptHook interruptHook =
|
||||||
mkInterruptHook $ \ucPtr intNo userDataPtr -> do
|
mkInterruptHook $ \ucPtr intNo userDataPtr -> do
|
||||||
uc <- mkEngineNC ucPtr
|
uc <- mkEngineNC ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
interruptHook uc (fromIntegral intNo) userData
|
interruptHook uc (fromIntegral intNo) userData
|
||||||
|
|
||||||
|
@ -197,7 +210,8 @@ marshalInterruptHook interruptHook =
|
||||||
type BlockHook a = CodeHook a
|
type BlockHook a = CodeHook a
|
||||||
|
|
||||||
marshalBlockHook :: Storable a
|
marshalBlockHook :: Storable a
|
||||||
=> BlockHook a -> IO {# type uc_cb_hookcode_t #}
|
=> BlockHook a
|
||||||
|
-> IO {# type uc_cb_hookcode_t #}
|
||||||
marshalBlockHook =
|
marshalBlockHook =
|
||||||
marshalCodeHook
|
marshalCodeHook
|
||||||
|
|
||||||
|
@ -214,10 +228,11 @@ foreign import ccall "wrapper"
|
||||||
mkInHook :: CInHook -> IO {# type uc_cb_insn_in_t #}
|
mkInHook :: CInHook -> IO {# type uc_cb_insn_in_t #}
|
||||||
|
|
||||||
marshalInHook :: Storable a
|
marshalInHook :: Storable a
|
||||||
=> InHook a -> IO {# type uc_cb_insn_in_t #}
|
=> InHook a
|
||||||
|
-> IO {# type uc_cb_insn_in_t #}
|
||||||
marshalInHook inHook =
|
marshalInHook inHook =
|
||||||
mkInHook $ \ucPtr port size userDataPtr -> do
|
mkInHook $ \ucPtr port size userDataPtr -> do
|
||||||
uc <- mkEngineNC ucPtr
|
uc <- mkEngineNC ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
inHook uc (fromIntegral port) (fromIntegral size) userData
|
inHook uc (fromIntegral port) (fromIntegral size) userData
|
||||||
|
|
||||||
|
@ -232,13 +247,15 @@ type OutHook a = Engine -- ^ 'Unicorn' engine handle
|
||||||
type COutHook = EnginePtr -> Word32 -> Int32 -> Word32 -> Ptr () -> IO ()
|
type COutHook = EnginePtr -> Word32 -> Int32 -> Word32 -> Ptr () -> IO ()
|
||||||
|
|
||||||
foreign import ccall "wrapper"
|
foreign import ccall "wrapper"
|
||||||
mkOutHook :: COutHook -> IO {# type uc_cb_insn_out_t #}
|
mkOutHook :: COutHook
|
||||||
|
-> IO {# type uc_cb_insn_out_t #}
|
||||||
|
|
||||||
marshalOutHook :: Storable a
|
marshalOutHook :: Storable a
|
||||||
=> OutHook a -> IO {# type uc_cb_insn_out_t #}
|
=> OutHook a
|
||||||
|
-> IO {# type uc_cb_insn_out_t #}
|
||||||
marshalOutHook outHook =
|
marshalOutHook outHook =
|
||||||
mkOutHook $ \ucPtr port size value userDataPtr -> do
|
mkOutHook $ \ucPtr port size value userDataPtr -> do
|
||||||
uc <- mkEngineNC ucPtr
|
uc <- mkEngineNC ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
outHook uc (fromIntegral port) (fromIntegral size) (fromIntegral value)
|
outHook uc (fromIntegral port) (fromIntegral size) (fromIntegral value)
|
||||||
userData
|
userData
|
||||||
|
@ -251,13 +268,15 @@ type SyscallHook a = Engine -- ^ 'Unicorn' engine handle
|
||||||
type CSyscallHook = Ptr () -> Ptr () -> IO ()
|
type CSyscallHook = Ptr () -> Ptr () -> IO ()
|
||||||
|
|
||||||
foreign import ccall "wrapper"
|
foreign import ccall "wrapper"
|
||||||
mkSyscallHook :: CSyscallHook -> IO {# type uc_cb_insn_syscall_t #}
|
mkSyscallHook :: CSyscallHook
|
||||||
|
-> IO {# type uc_cb_insn_syscall_t #}
|
||||||
|
|
||||||
marshalSyscallHook :: Storable a
|
marshalSyscallHook :: Storable a
|
||||||
=> SyscallHook a -> IO {# type uc_cb_insn_syscall_t #}
|
=> SyscallHook a
|
||||||
|
-> IO {# type uc_cb_insn_syscall_t #}
|
||||||
marshalSyscallHook syscallHook =
|
marshalSyscallHook syscallHook =
|
||||||
mkSyscallHook $ \ucPtr userDataPtr -> do
|
mkSyscallHook $ \ucPtr userDataPtr -> do
|
||||||
uc <- mkEngineNC $ castPtr ucPtr
|
uc <- mkEngineNC $ castPtr ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
syscallHook uc userData
|
syscallHook uc userData
|
||||||
|
|
||||||
|
@ -281,13 +300,15 @@ type CMemoryHook = EnginePtr
|
||||||
-> IO ()
|
-> IO ()
|
||||||
|
|
||||||
foreign import ccall "wrapper"
|
foreign import ccall "wrapper"
|
||||||
mkMemoryHook :: CMemoryHook -> IO {# type uc_cb_hookmem_t #}
|
mkMemoryHook :: CMemoryHook
|
||||||
|
-> IO {# type uc_cb_hookmem_t #}
|
||||||
|
|
||||||
marshalMemoryHook :: Storable a
|
marshalMemoryHook :: Storable a
|
||||||
=> MemoryHook a -> IO {# type uc_cb_hookmem_t #}
|
=> MemoryHook a
|
||||||
|
-> IO {# type uc_cb_hookmem_t #}
|
||||||
marshalMemoryHook memoryHook =
|
marshalMemoryHook memoryHook =
|
||||||
mkMemoryHook $ \ucPtr memAccessI address size value userDataPtr -> do
|
mkMemoryHook $ \ucPtr memAccessI address size value userDataPtr -> do
|
||||||
uc <- mkEngineNC ucPtr
|
uc <- mkEngineNC ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
let memAccess = toMemAccess memAccessI
|
let memAccess = toMemAccess memAccessI
|
||||||
maybeValue = case memAccess of
|
maybeValue = case memAccess of
|
||||||
|
@ -304,10 +325,11 @@ type MemoryReadHook a = Engine -- ^ 'Unicorn' engine handle
|
||||||
-> IO ()
|
-> IO ()
|
||||||
|
|
||||||
marshalMemoryReadHook :: Storable a
|
marshalMemoryReadHook :: Storable a
|
||||||
=> MemoryReadHook a -> IO {# type uc_cb_hookmem_t #}
|
=> MemoryReadHook a
|
||||||
|
-> IO {# type uc_cb_hookmem_t #}
|
||||||
marshalMemoryReadHook memoryReadHook =
|
marshalMemoryReadHook memoryReadHook =
|
||||||
mkMemoryHook $ \ucPtr _ address size _ userDataPtr -> do
|
mkMemoryHook $ \ucPtr _ address size _ userDataPtr -> do
|
||||||
uc <- mkEngineNC ucPtr
|
uc <- mkEngineNC ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
memoryReadHook uc address (fromIntegral size) userData
|
memoryReadHook uc address (fromIntegral size) userData
|
||||||
|
|
||||||
|
@ -321,10 +343,11 @@ type MemoryWriteHook a = Engine -- ^ 'Unicorn' engine handle
|
||||||
-> IO ()
|
-> IO ()
|
||||||
|
|
||||||
marshalMemoryWriteHook :: Storable a
|
marshalMemoryWriteHook :: Storable a
|
||||||
=> MemoryWriteHook a -> IO {# type uc_cb_hookmem_t #}
|
=> MemoryWriteHook a
|
||||||
|
-> IO {# type uc_cb_hookmem_t #}
|
||||||
marshalMemoryWriteHook memoryWriteHook =
|
marshalMemoryWriteHook memoryWriteHook =
|
||||||
mkMemoryHook $ \ucPtr _ address size value userDataPtr -> do
|
mkMemoryHook $ \ucPtr _ address size value userDataPtr -> do
|
||||||
uc <- mkEngineNC ucPtr
|
uc <- mkEngineNC ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
memoryWriteHook uc address (fromIntegral size) (fromIntegral value)
|
memoryWriteHook uc address (fromIntegral size) (fromIntegral value)
|
||||||
userData
|
userData
|
||||||
|
@ -351,15 +374,17 @@ type CMemoryEventHook = EnginePtr
|
||||||
-> IO Int32
|
-> IO Int32
|
||||||
|
|
||||||
foreign import ccall "wrapper"
|
foreign import ccall "wrapper"
|
||||||
mkMemoryEventHook :: CMemoryEventHook -> IO {# type uc_cb_eventmem_t #}
|
mkMemoryEventHook :: CMemoryEventHook
|
||||||
|
-> IO {# type uc_cb_eventmem_t #}
|
||||||
|
|
||||||
marshalMemoryEventHook :: Storable a
|
marshalMemoryEventHook :: Storable a
|
||||||
=> MemoryEventHook a -> IO {# type uc_cb_eventmem_t #}
|
=> MemoryEventHook a
|
||||||
|
-> IO {# type uc_cb_eventmem_t #}
|
||||||
marshalMemoryEventHook eventMemoryHook =
|
marshalMemoryEventHook eventMemoryHook =
|
||||||
mkMemoryEventHook $ \ucPtr memAccessI address size value userDataPtr -> do
|
mkMemoryEventHook $ \ucPtr memAccessI address size value userDataPtr -> do
|
||||||
uc <- mkEngineNC ucPtr
|
uc <- mkEngineNC ucPtr
|
||||||
userData <- castPtrAndPeek userDataPtr
|
userData <- castPtrAndPeek userDataPtr
|
||||||
let memAccess = toMemAccess memAccessI
|
let memAccess = toMemAccess memAccessI
|
||||||
maybeValue = case memAccess of
|
maybeValue = case memAccess of
|
||||||
MemReadUnmapped -> Nothing
|
MemReadUnmapped -> Nothing
|
||||||
MemReadProt -> Nothing
|
MemReadProt -> Nothing
|
||||||
|
@ -369,7 +394,7 @@ marshalMemoryEventHook eventMemoryHook =
|
||||||
res <- eventMemoryHook uc memAccess address (fromIntegral size)
|
res <- eventMemoryHook uc memAccess address (fromIntegral size)
|
||||||
maybeValue userData
|
maybeValue userData
|
||||||
return $ boolToInt res
|
return $ boolToInt res
|
||||||
where boolToInt True = 1
|
where boolToInt True = 1
|
||||||
boolToInt False = 0
|
boolToInt False = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -378,38 +403,43 @@ marshalMemoryEventHook eventMemoryHook =
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
{# fun variadic uc_hook_add as ucHookAdd
|
{# fun variadic uc_hook_add as ucHookAdd
|
||||||
`(Storable a, HookTypeC h)' =>
|
`HookTypeC h' =>
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
alloca- `Hook' peek*,
|
, alloca- `Hook' peek*
|
||||||
enumToNum `h',
|
, enumToNum `h'
|
||||||
castFunPtrToPtr `FunPtr b',
|
, castFunPtrToPtr `FunPtr b'
|
||||||
castPtr `Ptr a',
|
, castPtr `Ptr a'
|
||||||
`Word64',
|
, `Word64'
|
||||||
`Word64'}
|
, `Word64'
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun variadic uc_hook_add[int] as ucInsnHookAdd
|
{# fun variadic uc_hook_add[int] as ucInsnHookAdd
|
||||||
`(Storable a, HookTypeC h)' =>
|
`HookTypeC h' =>
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
alloca- `Hook' peek*,
|
, alloca- `Hook' peek*
|
||||||
enumToNum `h',
|
, enumToNum `h'
|
||||||
castFunPtrToPtr `FunPtr b',
|
, castFunPtrToPtr `FunPtr b'
|
||||||
castPtr `Ptr a',
|
, castPtr `Ptr a'
|
||||||
`Word64',
|
, `Word64'
|
||||||
`Word64',
|
, `Word64'
|
||||||
enumToNum `Instruction'}
|
, enumToNum `Instruction'
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
-- | Unregister (remove) a hook callback.
|
-- | Unregister (remove) a hook callback.
|
||||||
{# fun uc_hook_del as ^
|
{# fun uc_hook_del as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
fromIntegral `Hook'}
|
, fromIntegral `Hook'
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Helper functions
|
-- Helper functions
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
toMemAccess :: Integral a => a -> MemoryAccess
|
toMemAccess :: Integral a
|
||||||
|
=> a
|
||||||
|
-> MemoryAccess
|
||||||
toMemAccess =
|
toMemAccess =
|
||||||
toEnum . fromIntegral
|
toEnum . fromIntegral
|
||||||
|
|
|
@ -12,33 +12,39 @@ Low-level bindings for the Unicorn CPU emulator framework.
|
||||||
This module should not be directly imported; it is only exposed because of the
|
This module should not be directly imported; it is only exposed because of the
|
||||||
way cabal handles ordering of chs files.
|
way cabal handles ordering of chs files.
|
||||||
-}
|
-}
|
||||||
module Unicorn.Internal.Unicorn (
|
module Unicorn.Internal.Unicorn
|
||||||
-- * Types
|
( -- * Types
|
||||||
Architecture(..),
|
Architecture(..)
|
||||||
Mode(..),
|
, Mode(..)
|
||||||
MemoryPermission(..),
|
, MemoryPermission(..)
|
||||||
MemoryRegion(..),
|
, MemoryRegion(..)
|
||||||
QueryType(..),
|
, QueryType(..)
|
||||||
|
, Context
|
||||||
|
|
||||||
-- * Function bindings
|
-- * Function bindings
|
||||||
ucOpen,
|
, ucOpen
|
||||||
ucQuery,
|
, ucQuery
|
||||||
ucEmuStart,
|
, ucEmuStart
|
||||||
ucEmuStop,
|
, ucEmuStop
|
||||||
ucRegWrite,
|
, ucRegWrite
|
||||||
ucRegRead,
|
, ucRegRead
|
||||||
ucMemWrite,
|
, ucMemWrite
|
||||||
ucMemRead,
|
, ucMemRead
|
||||||
ucMemMap,
|
, ucMemMap
|
||||||
ucMemUnmap,
|
, ucMemUnmap
|
||||||
ucMemProtect,
|
, ucMemProtect
|
||||||
ucMemRegions,
|
, ucMemRegions
|
||||||
ucVersion,
|
, mkContext
|
||||||
ucErrno,
|
, ucContextAlloc
|
||||||
ucStrerror,
|
, ucContextSave
|
||||||
) where
|
, ucContextRestore
|
||||||
|
, ucVersion
|
||||||
|
, ucErrno
|
||||||
|
, ucStrerror
|
||||||
|
) where
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
|
import Control.Monad
|
||||||
import Data.ByteString (ByteString, useAsCStringLen)
|
import Data.ByteString (ByteString, useAsCStringLen)
|
||||||
import Foreign
|
import Foreign
|
||||||
import Foreign.C
|
import Foreign.C
|
||||||
|
@ -46,11 +52,12 @@ import Prelude hiding (until)
|
||||||
|
|
||||||
import Unicorn.Internal.Util
|
import Unicorn.Internal.Util
|
||||||
|
|
||||||
{# context lib="unicorn" #}
|
|
||||||
|
|
||||||
{# import Unicorn.Internal.Core #}
|
{# import Unicorn.Internal.Core #}
|
||||||
|
|
||||||
|
{# context lib = "unicorn" #}
|
||||||
|
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
|
#include "unicorn_wrapper.h"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Types
|
-- Types
|
||||||
|
@ -58,29 +65,33 @@ import Unicorn.Internal.Util
|
||||||
|
|
||||||
-- | CPU architecture.
|
-- | CPU architecture.
|
||||||
{# enum uc_arch as Architecture
|
{# enum uc_arch as Architecture
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
with prefix="UC_"
|
with prefix = "UC_"
|
||||||
deriving (Show, Eq, Bounded) #}
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
-- | CPU hardware mode.
|
-- | CPU hardware mode.
|
||||||
{# enum uc_mode as Mode
|
{# enum uc_mode as Mode
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
with prefix="UC_"
|
with prefix = "UC_"
|
||||||
deriving (Show, Eq, Bounded) #}
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
-- | Memory permissions.
|
-- | Memory permissions.
|
||||||
{# enum uc_prot as MemoryPermission
|
{# enum uc_prot as MemoryPermission
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
with prefix="UC_"
|
with prefix = "UC_"
|
||||||
deriving (Show, Eq, Bounded) #}
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
-- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with
|
-- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with
|
||||||
-- 'memRegions'.
|
-- 'memRegions'.
|
||||||
data MemoryRegion = MemoryRegion {
|
data MemoryRegion = MemoryRegion
|
||||||
mrBegin :: Word64, -- ^ Begin address of the region (inclusive)
|
{
|
||||||
mrEnd :: Word64, -- ^ End address of the region (inclusive)
|
mrBegin :: Word64 -- ^ Begin address of the region (inclusive)
|
||||||
mrPerms :: [MemoryPermission] -- ^ Memory permissions of the region
|
, mrEnd :: Word64 -- ^ End address of the region (inclusive)
|
||||||
}
|
, mrPerms :: [MemoryPermission] -- ^ Memory permissions of the region
|
||||||
|
}
|
||||||
|
|
||||||
instance Storable MemoryRegion where
|
instance Storable MemoryRegion where
|
||||||
sizeOf _ = {# sizeof uc_mem_region #}
|
sizeOf _ = {# sizeof uc_mem_region #}
|
||||||
|
@ -99,121 +110,174 @@ instance Storable MemoryRegion where
|
||||||
|
|
||||||
-- | Query types for the 'query' API.
|
-- | Query types for the 'query' API.
|
||||||
{# enum uc_query_type as QueryType
|
{# enum uc_query_type as QueryType
|
||||||
{underscoreToCase}
|
{ underscoreToCase }
|
||||||
with prefix="UC_"
|
with prefix = "UC_"
|
||||||
deriving (Show, Eq, Bounded) #}
|
deriving (Show, Eq, Bounded)
|
||||||
|
#}
|
||||||
|
|
||||||
|
-- | Opaque storage for CPU context, used with the context functions.
|
||||||
|
{# pointer *uc_context as Context
|
||||||
|
foreign finalizer uc_context_free_wrapper as contextFree
|
||||||
|
newtype
|
||||||
|
#}
|
||||||
|
|
||||||
|
-- | A pointer to a CPU context.
|
||||||
|
{# pointer *uc_context as ContextPtr -> Context #}
|
||||||
|
|
||||||
|
-- | Make a CPU context out of a context pointer. The returned CPU context will
|
||||||
|
-- automatically call 'uc_context_free' when it goes out of scope.
|
||||||
|
mkContext :: ContextPtr
|
||||||
|
-> IO Context
|
||||||
|
mkContext ptr =
|
||||||
|
liftM Context (newForeignPtr contextFree ptr)
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Emulator control
|
-- Emulator control
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
{# fun uc_open as ^
|
{# fun uc_open as ^
|
||||||
{`Architecture',
|
{ `Architecture'
|
||||||
combineEnums `[Mode]',
|
, combineEnums `[Mode]'
|
||||||
alloca- `EnginePtr' peek*}
|
, alloca- `EnginePtr' peek*
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun uc_query as ^
|
{# fun uc_query as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
`QueryType',
|
, `QueryType'
|
||||||
alloca- `Int' castPtrAndPeek*}
|
, alloca- `Int' castPtrAndPeek*
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun uc_emu_start as ^
|
{# fun uc_emu_start as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
`Word64',
|
, `Word64'
|
||||||
`Word64',
|
, `Word64'
|
||||||
`Int',
|
, `Int'
|
||||||
`Int'}
|
, `Int'} -> `Error'
|
||||||
-> `Error' #}
|
#}
|
||||||
|
|
||||||
{# fun uc_emu_stop as ^
|
{# fun uc_emu_stop as ^
|
||||||
{`Engine'}
|
{ `Engine'
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Register operations
|
-- Register operations
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
{# fun uc_reg_write as ^
|
{# fun uc_reg_write as ^
|
||||||
`Reg r' =>
|
`Reg r' =>
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
enumToNum `r',
|
, enumToNum `r'
|
||||||
castPtr `Ptr Int64'}
|
, castPtr `Ptr Int64'
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun uc_reg_read as ^
|
{# fun uc_reg_read as ^
|
||||||
`Reg r' =>
|
`Reg r' =>
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
enumToNum `r',
|
, enumToNum `r'
|
||||||
allocaInt64ToVoid- `Int64' castPtrAndPeek*}
|
, allocaInt64ToVoid- `Int64' castPtrAndPeek*
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Memory operations
|
-- Memory operations
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
{# fun uc_mem_write as ^
|
{# fun uc_mem_write as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
`Word64',
|
, `Word64'
|
||||||
withByteStringLen* `ByteString'&}
|
, withByteStringLen* `ByteString'&
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun uc_mem_read as ^
|
{# fun uc_mem_read as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
`Word64',
|
, `Word64'
|
||||||
castPtr `Ptr Word8',
|
, castPtr `Ptr Word8'
|
||||||
`Int'}
|
, `Int'} -> `Error'
|
||||||
-> `Error' #}
|
#}
|
||||||
|
|
||||||
{# fun uc_mem_map as ^
|
{# fun uc_mem_map as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
`Word64',
|
, `Word64'
|
||||||
`Int',
|
, `Int'
|
||||||
combineEnums `[MemoryPermission]'}
|
, combineEnums `[MemoryPermission]'
|
||||||
-> `Error' #}
|
} -> `Error' #}
|
||||||
|
|
||||||
{# fun uc_mem_unmap as ^
|
{# fun uc_mem_unmap as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
`Word64',
|
, `Word64'
|
||||||
`Int'}
|
, `Int'
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun uc_mem_protect as ^
|
{# fun uc_mem_protect as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
`Word64',
|
, `Word64'
|
||||||
`Int',
|
, `Int'
|
||||||
combineEnums `[MemoryPermission]'}
|
, combineEnums `[MemoryPermission]'
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun uc_mem_regions as ^
|
{# fun uc_mem_regions as ^
|
||||||
{`Engine',
|
{ `Engine'
|
||||||
alloca- `MemoryRegionPtr' peek*,
|
, alloca- `MemoryRegionPtr' peek*
|
||||||
alloca- `Int' castPtrAndPeek*}
|
, alloca- `Int' castPtrAndPeek*
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Context
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
{# fun uc_context_alloc as ^
|
||||||
|
{ `Engine'
|
||||||
|
, alloca- `ContextPtr' peek*
|
||||||
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
|
{# fun uc_context_save as ^
|
||||||
|
{ `Engine'
|
||||||
|
, `Context'
|
||||||
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
|
{# fun uc_context_restore as ^
|
||||||
|
{ `Engine'
|
||||||
|
, `Context'
|
||||||
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Misc.
|
-- Misc.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
{# fun pure unsafe uc_version as ^
|
{# fun pure unsafe uc_version as ^
|
||||||
{id `Ptr CUInt',
|
{ id `Ptr CUInt'
|
||||||
id `Ptr CUInt'}
|
, id `Ptr CUInt'
|
||||||
-> `Int' #}
|
} -> `Int'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun unsafe uc_errno as ^
|
{# fun unsafe uc_errno as ^
|
||||||
{`Engine'}
|
{ `Engine'
|
||||||
-> `Error' #}
|
} -> `Error'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun pure unsafe uc_strerror as ^
|
{# fun pure unsafe uc_strerror as ^
|
||||||
{`Error'}
|
{ `Error'
|
||||||
-> `String' #}
|
} -> `String'
|
||||||
|
#}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Helper functions
|
-- Helper functions
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
expandMemPerms :: (Integral a, Bits a) => a -> [MemoryPermission]
|
expandMemPerms :: (Integral a, Bits a)
|
||||||
|
=> a
|
||||||
|
-> [MemoryPermission]
|
||||||
expandMemPerms perms =
|
expandMemPerms perms =
|
||||||
-- Only interested in the 3 least-significant bits
|
-- Only interested in the 3 least-significant bits
|
||||||
let maskedPerms = fromIntegral $ perms .&. 0x7 in
|
let maskedPerms = fromIntegral $ perms .&. 0x7 in
|
||||||
|
@ -232,10 +296,13 @@ expandMemPerms perms =
|
||||||
checkRWE _ [] =
|
checkRWE _ [] =
|
||||||
[]
|
[]
|
||||||
|
|
||||||
allocaInt64ToVoid :: (Ptr () -> IO b) -> IO b
|
allocaInt64ToVoid :: (Ptr () -> IO b)
|
||||||
|
-> IO b
|
||||||
allocaInt64ToVoid f =
|
allocaInt64ToVoid f =
|
||||||
alloca $ \(ptr :: Ptr Int64) -> poke ptr 0 >> f (castPtr ptr)
|
alloca $ \(ptr :: Ptr Int64) -> poke ptr 0 >> f (castPtr ptr)
|
||||||
|
|
||||||
withByteStringLen :: ByteString -> ((Ptr (), CULong) -> IO a) -> IO a
|
withByteStringLen :: ByteString
|
||||||
|
-> ((Ptr (), CULong) -> IO a)
|
||||||
|
-> IO a
|
||||||
withByteStringLen bs f =
|
withByteStringLen bs f =
|
||||||
useAsCStringLen bs $ \(ptr, len) -> f (castPtr ptr, fromIntegral len)
|
useAsCStringLen bs $ \(ptr, len) -> f (castPtr ptr, fromIntegral len)
|
||||||
|
|
|
@ -10,16 +10,22 @@ import Data.Bits
|
||||||
import Foreign
|
import Foreign
|
||||||
|
|
||||||
-- | Combine a list of Enums by performing a bitwise-OR.
|
-- | Combine a list of Enums by performing a bitwise-OR.
|
||||||
combineEnums :: (Enum a, Num b, Bits b) => [a] -> b
|
combineEnums :: (Enum a, Num b, Bits b)
|
||||||
|
=> [a]
|
||||||
|
-> b
|
||||||
combineEnums =
|
combineEnums =
|
||||||
foldr ((.|.) <$> enumToNum) 0
|
foldr ((.|.) <$> enumToNum) 0
|
||||||
|
|
||||||
-- | Cast a pointer and then peek inside it.
|
-- | Cast a pointer and then peek inside it.
|
||||||
castPtrAndPeek :: Storable a => Ptr b -> IO a
|
castPtrAndPeek :: Storable a
|
||||||
|
=> Ptr b
|
||||||
|
-> IO a
|
||||||
castPtrAndPeek =
|
castPtrAndPeek =
|
||||||
peek . castPtr
|
peek . castPtr
|
||||||
|
|
||||||
-- | Convert an 'Eum' to a 'Num'.
|
-- | Convert an 'Eum' to a 'Num'.
|
||||||
enumToNum :: (Enum a, Num b) => a -> b
|
enumToNum :: (Enum a, Num b)
|
||||||
|
=> a
|
||||||
|
-> b
|
||||||
enumToNum =
|
enumToNum =
|
||||||
fromIntegral . fromEnum
|
fromIntegral . fromEnum
|
||||||
|
|
|
@ -6,3 +6,7 @@ void uc_close_wrapper(uc_engine *uc) {
|
||||||
|
|
||||||
void uc_close_dummy(uc_engine *uc) {
|
void uc_close_dummy(uc_engine *uc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uc_context_free_wrapper(uc_context *context) {
|
||||||
|
uc_context_free(context);
|
||||||
|
}
|
||||||
|
|
|
@ -13,4 +13,9 @@ void uc_close_wrapper(uc_engine *uc);
|
||||||
*/
|
*/
|
||||||
void uc_close_dummy(uc_engine *uc);
|
void uc_close_dummy(uc_engine *uc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrap Unicorn's uc_context_free function and ignore the returned error code.
|
||||||
|
*/
|
||||||
|
void uc_context_free_wrapper(uc_context *context);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,8 +13,9 @@ copyright: (c) 2016, Adrian Herrera
|
||||||
category: System
|
category: System
|
||||||
build-type: Simple
|
build-type: Simple
|
||||||
stability: experimental
|
stability: experimental
|
||||||
cabal-version: >=1.10
|
cabal-version: >= 1.10
|
||||||
extra-source-files: cbits/, include/
|
extra-source-files: cbits/
|
||||||
|
, include/
|
||||||
|
|
||||||
library
|
library
|
||||||
exposed-modules: Unicorn.Internal.Core
|
exposed-modules: Unicorn.Internal.Core
|
||||||
|
@ -29,10 +30,10 @@ library
|
||||||
Unicorn.Hook
|
Unicorn.Hook
|
||||||
Unicorn
|
Unicorn
|
||||||
other-modules: Unicorn.Internal.Util
|
other-modules: Unicorn.Internal.Util
|
||||||
build-depends: base >=4 && <5,
|
build-depends: base >=4 && <5
|
||||||
bytestring >= 0.9.1,
|
, bytestring >= 0.9.1
|
||||||
transformers < 0.6,
|
, transformers < 0.6
|
||||||
either >= 4.4
|
, either >= 4.4
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
c-sources: src/cbits/unicorn_wrapper.c
|
c-sources: src/cbits/unicorn_wrapper.c
|
||||||
include-dirs: src/include
|
include-dirs: src/include
|
||||||
|
|
|
@ -21,7 +21,7 @@ def hook_block(uc, address, size, user_data):
|
||||||
|
|
||||||
# callback for tracing instructions
|
# callback for tracing instructions
|
||||||
def hook_code(uc, address, size, user_data):
|
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
|
# Test ARM
|
||||||
|
@ -46,7 +46,7 @@ def test_arm():
|
||||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||||
|
|
||||||
# tracing all instructions with customized callback
|
# 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
|
# emulate machine code in infinite time
|
||||||
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))
|
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))
|
||||||
|
@ -100,5 +100,5 @@ def test_thumb():
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_arm()
|
test_arm()
|
||||||
print("=" * 20)
|
print("=" * 26)
|
||||||
test_thumb()
|
test_thumb()
|
||||||
|
|
|
@ -21,7 +21,7 @@ def hook_block(uc, address, size, user_data):
|
||||||
|
|
||||||
# callback for tracing instructions
|
# callback for tracing instructions
|
||||||
def hook_code(uc, address, size, user_data):
|
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
|
# Test ARM64
|
||||||
|
|
|
@ -20,7 +20,7 @@ def hook_block(uc, address, size, user_data):
|
||||||
|
|
||||||
# callback for tracing instructions
|
# callback for tracing instructions
|
||||||
def hook_code(uc, address, size, user_data):
|
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
|
# Test ARM
|
||||||
|
@ -51,8 +51,34 @@ def test_m68k():
|
||||||
# now print out some registers
|
# now print out some registers
|
||||||
print(">>> Emulation done. Below is the CPU context")
|
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)
|
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:
|
except UcError as e:
|
||||||
print("ERROR: %s" % e)
|
print("ERROR: %s" % e)
|
||||||
|
|
|
@ -22,7 +22,7 @@ def hook_block(uc, address, size, user_data):
|
||||||
|
|
||||||
# callback for tracing instructions
|
# callback for tracing instructions
|
||||||
def hook_code(uc, address, size, user_data):
|
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
|
# Test MIPS EB
|
||||||
|
@ -54,7 +54,7 @@ def test_mips_eb():
|
||||||
print(">>> Emulation done. Below is the CPU context")
|
print(">>> Emulation done. Below is the CPU context")
|
||||||
|
|
||||||
r1 = mu.reg_read(UC_MIPS_REG_1)
|
r1 = mu.reg_read(UC_MIPS_REG_1)
|
||||||
print(">>> r1 = 0x%x" %r1)
|
print(">>> R1 = 0x%x" %r1)
|
||||||
|
|
||||||
except UcError as e:
|
except UcError as e:
|
||||||
print("ERROR: %s" % e)
|
print("ERROR: %s" % e)
|
||||||
|
@ -89,7 +89,7 @@ def test_mips_el():
|
||||||
print(">>> Emulation done. Below is the CPU context")
|
print(">>> Emulation done. Below is the CPU context")
|
||||||
|
|
||||||
r1 = mu.reg_read(UC_MIPS_REG_1)
|
r1 = mu.reg_read(UC_MIPS_REG_1)
|
||||||
print(">>> r1 = 0x%x" %r1)
|
print(">>> R1 = 0x%x" %r1)
|
||||||
|
|
||||||
except UcError as e:
|
except UcError as e:
|
||||||
print("ERROR: %s" % e)
|
print("ERROR: %s" % e)
|
||||||
|
@ -97,5 +97,5 @@ def test_mips_el():
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_mips_eb()
|
test_mips_eb()
|
||||||
print("=" * 20)
|
print("=" * 27)
|
||||||
test_mips_el()
|
test_mips_el()
|
||||||
|
|
|
@ -20,7 +20,7 @@ def hook_block(uc, address, size, user_data):
|
||||||
|
|
||||||
# callback for tracing instructions
|
# callback for tracing instructions
|
||||||
def hook_code(uc, address, size, user_data):
|
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
|
# Test SPARC
|
||||||
|
|
|
@ -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 = 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_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_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_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"
|
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
|
# callback for tracing instructions
|
||||||
def hook_code(uc, address, size, user_data):
|
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))
|
||||||
#eip = uc.reg_read(UC_X86_REG_EIP)
|
eip = uc.reg_read(UC_X86_REG_EFLAGS)
|
||||||
#print(">>> EIP = 0x%x" %(eip))
|
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)
|
# 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)
|
r_xmm0 = mu.reg_read(UC_X86_REG_XMM0)
|
||||||
print(">>> ECX = 0x%x" %r_ecx)
|
print(">>> ECX = 0x%x" %r_ecx)
|
||||||
print(">>> EDX = 0x%x" %r_edx)
|
print(">>> EDX = 0x%x" %r_edx)
|
||||||
print(">>> XMM0 = 0x%x" %r_xmm0)
|
print(">>> XMM0 = 0x%.32x" %r_xmm0)
|
||||||
|
|
||||||
# read from memory
|
# read from memory
|
||||||
tmp = mu.mem_read(ADDRESS, 2)
|
tmp = mu.mem_read(ADDRESS, 4)
|
||||||
print(">>> Read 2 bytes from [0x%x] =" %(ADDRESS), end="")
|
print(">>> Read 4 bytes from [0x%x] = 0x" %(ADDRESS), end="")
|
||||||
for i in tmp:
|
for i in reversed(tmp):
|
||||||
print(" 0x%x" %i, end="")
|
print("%x" %(i), end="")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
except UcError as e:
|
except UcError as e:
|
||||||
print("ERROR: %s" % e)
|
print("ERROR: %s" % e)
|
||||||
|
|
||||||
|
|
||||||
def test_i386_loop():
|
def test_i386_map_ptr():
|
||||||
print("Emulate i386 code with infinite loop - wait for 2 seconds then stop emulation")
|
print("Emulate i386 code - use uc_mem_map_ptr()")
|
||||||
try:
|
try:
|
||||||
# Initialize emulator in X86-32bit mode
|
# Initialize emulator in X86-32bit mode
|
||||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||||
|
@ -151,14 +158,20 @@ def test_i386_loop():
|
||||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||||
|
|
||||||
# write machine code to be emulated to memory
|
# write machine code to be emulated to memory
|
||||||
mu.mem_write(ADDRESS, X86_CODE32_LOOP)
|
mu.mem_write(ADDRESS, X86_CODE32)
|
||||||
|
|
||||||
# initialize machine registers
|
# initialize machine registers
|
||||||
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||||
mu.reg_write(UC_X86_REG_EDX, 0x7890)
|
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
|
# 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
|
# now print out some registers
|
||||||
print(">>> Emulation done. Below is the CPU context")
|
print(">>> Emulation done. Below is the CPU context")
|
||||||
|
@ -168,6 +181,13 @@ def test_i386_loop():
|
||||||
print(">>> ECX = 0x%x" %r_ecx)
|
print(">>> ECX = 0x%x" %r_ecx)
|
||||||
print(">>> EDX = 0x%x" %r_edx)
|
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:
|
except UcError as e:
|
||||||
print("ERROR: %s" % e)
|
print("ERROR: %s" % e)
|
||||||
|
|
||||||
|
@ -198,7 +218,7 @@ def test_i386_invalid_mem_read():
|
||||||
# emulate machine code in infinite time
|
# emulate machine code in infinite time
|
||||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_READ))
|
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_READ))
|
||||||
except UcError as e:
|
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
|
# now print out some registers
|
||||||
print(">>> Emulation done. Below is the CPU context")
|
print(">>> Emulation done. Below is the CPU context")
|
||||||
|
@ -211,6 +231,35 @@ def test_i386_invalid_mem_read():
|
||||||
except UcError as e:
|
except UcError as e:
|
||||||
print("ERROR: %s" % 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():
|
def test_i386_invalid_mem_write():
|
||||||
print("Emulate i386 code that write to invalid memory")
|
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)
|
mu.reg_write(UC_X86_REG_EDX, 0x7890)
|
||||||
|
|
||||||
# tracing all basic blocks with customized callback
|
# 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
|
# 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
|
# intercept invalid memory events
|
||||||
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid)
|
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(">>> ECX = 0x%x" %r_ecx)
|
||||||
print(">>> EDX = 0x%x" %r_edx)
|
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:
|
try:
|
||||||
# read from memory
|
tmp = mu.mem_read(0xffffffaa, 4)
|
||||||
print(">>> Read 4 bytes from [0x%x] = " %(0xaaaaaaaa), end="")
|
print(">>> Read 4 bytes from [0x%x] = 0x" %(0xffffffaa), end="")
|
||||||
tmp = mu.mem_read(0xaaaaaaaa, 4)
|
for i in reversed(tmp):
|
||||||
for i in tmp:
|
print("%x" %i, end="")
|
||||||
print(" 0x%x" %i, end="")
|
|
||||||
print("")
|
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:
|
except UcError as e:
|
||||||
print("ERROR: %s" % e)
|
print(">>> Failed to read 4 bytes from [0xffffffaa]")
|
||||||
|
|
||||||
except UcError as e:
|
except UcError as e:
|
||||||
print("ERROR: %s" % 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
|
# Test X86 32 bit with IN/OUT instruction
|
||||||
def test_i386_inout():
|
def test_i386_inout():
|
||||||
|
@ -397,7 +513,7 @@ def test_x86_64():
|
||||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||||
|
|
||||||
# tracing all instructions in range [ADDRESS, ADDRESS+20]
|
# 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
|
# tracing all memory READ & WRITE access
|
||||||
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)
|
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)
|
||||||
|
@ -429,23 +545,21 @@ def test_x86_64():
|
||||||
r14 = mu.reg_read(UC_X86_REG_R14)
|
r14 = mu.reg_read(UC_X86_REG_R14)
|
||||||
r15 = mu.reg_read(UC_X86_REG_R15)
|
r15 = mu.reg_read(UC_X86_REG_R15)
|
||||||
|
|
||||||
print(">>> RAX = %x" %rax)
|
print(">>> RAX = 0x%x" %rax)
|
||||||
print(">>> RBX = %x" %rbx)
|
print(">>> RBX = 0x%x" %rbx)
|
||||||
print(">>> RCX = %x" %rcx)
|
print(">>> RCX = 0x%x" %rcx)
|
||||||
print(">>> RDX = %x" %rdx)
|
print(">>> RDX = 0x%x" %rdx)
|
||||||
print(">>> RSI = %x" %rsi)
|
print(">>> RSI = 0x%x" %rsi)
|
||||||
print(">>> RDI = %x" %rdi)
|
print(">>> RDI = 0x%x" %rdi)
|
||||||
print(">>> R8 = %x" %r8)
|
print(">>> R8 = 0x%x" %r8)
|
||||||
print(">>> R9 = %x" %r9)
|
print(">>> R9 = 0x%x" %r9)
|
||||||
print(">>> R10 = %x" %r10)
|
print(">>> R10 = 0x%x" %r10)
|
||||||
print(">>> R11 = %x" %r11)
|
print(">>> R11 = 0x%x" %r11)
|
||||||
print(">>> R12 = %x" %r12)
|
print(">>> R12 = 0x%x" %r12)
|
||||||
print(">>> R13 = %x" %r13)
|
print(">>> R13 = 0x%x" %r13)
|
||||||
print(">>> R14 = %x" %r14)
|
print(">>> R14 = 0x%x" %r14)
|
||||||
print(">>> R15 = %x" %r15)
|
print(">>> R15 = 0x%x" %r15)
|
||||||
|
|
||||||
#BUG
|
|
||||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE64))
|
|
||||||
|
|
||||||
except UcError as e:
|
except UcError as e:
|
||||||
print("ERROR: %s" % e)
|
print("ERROR: %s" % e)
|
||||||
|
@ -516,27 +630,29 @@ def test_x86_16():
|
||||||
print(">>> Emulation done. Below is the CPU context")
|
print(">>> Emulation done. Below is the CPU context")
|
||||||
|
|
||||||
tmp = mu.mem_read(11, 1)
|
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:
|
except UcError as e:
|
||||||
print("ERROR: %s" % e)
|
print("ERROR: %s" % e)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
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_x86_16()
|
||||||
|
test_i386()
|
||||||
|
print("=" * 35)
|
||||||
|
test_i386_map_ptr()
|
||||||
|
print("=" * 35)
|
||||||
|
test_i386_inout()
|
||||||
|
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()
|
||||||
|
|
|
@ -23,7 +23,7 @@ if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32):
|
||||||
PKG_NAME = 'unicorn-windows'
|
PKG_NAME = 'unicorn-windows'
|
||||||
|
|
||||||
SYSTEM = sys.platform
|
SYSTEM = sys.platform
|
||||||
VERSION = '1.0'
|
VERSION = '1.0.0'
|
||||||
|
|
||||||
# adapted from commit e504b81 of Nguyen Tan Cong
|
# adapted from commit e504b81 of Nguyen Tan Cong
|
||||||
# Reference: https://docs.python.org/2/library/platform.html#cross-platform
|
# Reference: https://docs.python.org/2/library/platform.html#cross-platform
|
||||||
|
|
|
@ -63,7 +63,8 @@ _path_list = [pkg_resources.resource_filename(__name__, 'lib'),
|
||||||
os.path.join(os.path.split(__file__)[0], 'lib'),
|
os.path.join(os.path.split(__file__)[0], 'lib'),
|
||||||
'',
|
'',
|
||||||
distutils.sysconfig.get_python_lib(),
|
distutils.sysconfig.get_python_lib(),
|
||||||
"/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64']
|
"/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64',
|
||||||
|
os.environ['PATH']]
|
||||||
|
|
||||||
for _path in _path_list:
|
for _path in _path_list:
|
||||||
_uc = _load_lib(_path)
|
_uc = _load_lib(_path)
|
||||||
|
@ -105,7 +106,6 @@ _setup_prototype(_uc, "uc_context_alloc", ucerr, uc_engine, ctypes.POINTER(uc_co
|
||||||
_setup_prototype(_uc, "uc_context_free", ucerr, uc_context)
|
_setup_prototype(_uc, "uc_context_free", ucerr, uc_context)
|
||||||
_setup_prototype(_uc, "uc_context_save", ucerr, uc_engine, uc_context)
|
_setup_prototype(_uc, "uc_context_save", ucerr, uc_engine, uc_context)
|
||||||
_setup_prototype(_uc, "uc_context_restore", ucerr, uc_engine, uc_context)
|
_setup_prototype(_uc, "uc_context_restore", ucerr, uc_engine, uc_context)
|
||||||
_setup_prototype(_uc, "free", None, ctypes.c_voidp)
|
|
||||||
|
|
||||||
# uc_hook_add is special due to variable number of arguments
|
# uc_hook_add is special due to variable number of arguments
|
||||||
_uc.uc_hook_add = _uc.uc_hook_add
|
_uc.uc_hook_add = _uc.uc_hook_add
|
||||||
|
|
|
@ -73,11 +73,11 @@ VALUE m_uc_emu_start(int argc, VALUE* argv, VALUE self){
|
||||||
Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc);
|
Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc);
|
||||||
|
|
||||||
rb_scan_args(argc, argv, "22",&begin, &until, &timeout, &count);
|
rb_scan_args(argc, argv, "22",&begin, &until, &timeout, &count);
|
||||||
if (NIL_P(timeout))
|
if (NIL_P(timeout))
|
||||||
timeout = INT2NUM(0);
|
timeout = INT2NUM(0);
|
||||||
|
|
||||||
if (NIL_P(count))
|
if (NIL_P(count))
|
||||||
count = INT2NUM(0);
|
count = INT2NUM(0);
|
||||||
|
|
||||||
err = uc_emu_start(_uc, NUM2ULL(begin), NUM2ULL(until), NUM2INT(timeout), NUM2INT(count));
|
err = uc_emu_start(_uc, NUM2ULL(begin), NUM2ULL(until), NUM2INT(timeout), NUM2INT(count));
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
|
@ -133,7 +133,7 @@ VALUE m_uc_reg_read(VALUE self, VALUE reg_id){
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
rb_raise(UcError, "%s", uc_strerror(err));
|
rb_raise(UcError, "%s", uc_strerror(err));
|
||||||
}
|
}
|
||||||
return LL2NUM(reg_value);
|
return ULL2NUM(reg_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ VALUE m_uc_reg_write(VALUE self, VALUE reg_id, VALUE reg_value){
|
||||||
err = uc_reg_write(_uc, NUM2INT(reg_id), &tmp);
|
err = uc_reg_write(_uc, NUM2INT(reg_id), &tmp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
rb_raise(UcError, "%s", uc_strerror(err));
|
rb_raise(UcError, "%s", uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
@ -205,8 +205,8 @@ VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self){
|
||||||
uc_engine *_uc;
|
uc_engine *_uc;
|
||||||
Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc);
|
Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc);
|
||||||
rb_scan_args(argc, argv, "21",&address, &size, &perms);
|
rb_scan_args(argc, argv, "21",&address, &size, &perms);
|
||||||
if (NIL_P(perms))
|
if (NIL_P(perms))
|
||||||
perms = INT2NUM(UC_PROT_ALL);
|
perms = INT2NUM(UC_PROT_ALL);
|
||||||
|
|
||||||
err = uc_mem_map(_uc, NUM2ULL(address), NUM2UINT(size), NUM2UINT(perms));
|
err = uc_mem_map(_uc, NUM2ULL(address), NUM2UINT(size), NUM2UINT(perms));
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
|
@ -332,14 +332,14 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){
|
||||||
uc_engine *_uc;
|
uc_engine *_uc;
|
||||||
Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc);
|
Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc);
|
||||||
rb_scan_args(argc, argv, "24",&hook_type, &callback, &user_data, &begin, &end, &arg1);
|
rb_scan_args(argc, argv, "24",&hook_type, &callback, &user_data, &begin, &end, &arg1);
|
||||||
if (NIL_P(begin))
|
if (NIL_P(begin))
|
||||||
begin = ULL2NUM(1);
|
begin = ULL2NUM(1);
|
||||||
|
|
||||||
if (NIL_P(end))
|
if (NIL_P(end))
|
||||||
end = ULL2NUM(0);
|
end = ULL2NUM(0);
|
||||||
|
|
||||||
if (NIL_P(arg1))
|
if (NIL_P(arg1))
|
||||||
arg1 = INT2NUM(0);
|
arg1 = INT2NUM(0);
|
||||||
|
|
||||||
VALUE passthrough;
|
VALUE passthrough;
|
||||||
uc_hook trace;
|
uc_hook trace;
|
||||||
|
@ -374,12 +374,12 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){
|
||||||
else if(htype == UC_HOOK_CODE || htype == UC_HOOK_BLOCK){
|
else if(htype == UC_HOOK_CODE || htype == UC_HOOK_BLOCK){
|
||||||
err = uc_hook_add(_uc, &trace, htype, cb_hook_code,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end));
|
err = uc_hook_add(_uc, &trace, htype, cb_hook_code,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end));
|
||||||
}
|
}
|
||||||
else if (htype & UC_HOOK_MEM_READ_UNMAPPED
|
else if (htype & UC_HOOK_MEM_READ_UNMAPPED
|
||||||
|| htype & UC_HOOK_MEM_WRITE_UNMAPPED
|
|| htype & UC_HOOK_MEM_WRITE_UNMAPPED
|
||||||
|| htype & UC_HOOK_MEM_FETCH_UNMAPPED
|
|| htype & UC_HOOK_MEM_FETCH_UNMAPPED
|
||||||
|| htype & UC_HOOK_MEM_READ_PROT
|
|| htype & UC_HOOK_MEM_READ_PROT
|
||||||
|| htype & UC_HOOK_MEM_WRITE_PROT
|
|| htype & UC_HOOK_MEM_WRITE_PROT
|
||||||
|| htype & UC_HOOK_MEM_FETCH_PROT
|
|| htype & UC_HOOK_MEM_FETCH_PROT
|
||||||
|| htype & UC_HOOK_MEM_READ_INVALID
|
|| htype & UC_HOOK_MEM_READ_INVALID
|
||||||
|| htype & UC_HOOK_MEM_WRITE_INVALID
|
|| htype & UC_HOOK_MEM_WRITE_INVALID
|
||||||
|| htype & UC_HOOK_MEM_FETCH_INVALID
|
|| htype & UC_HOOK_MEM_FETCH_INVALID
|
||||||
|
@ -387,7 +387,7 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){
|
||||||
|| htype & UC_HOOK_MEM_PROT
|
|| htype & UC_HOOK_MEM_PROT
|
||||||
|| htype & UC_HOOK_MEM_INVALID) {
|
|| htype & UC_HOOK_MEM_INVALID) {
|
||||||
err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_invalid,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end));
|
err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_invalid,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_access,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end));
|
err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_access,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end));
|
||||||
}
|
}
|
||||||
|
|
20
make.sh
20
make.sh
|
@ -36,17 +36,6 @@ build_iOS() {
|
||||||
${MAKE}
|
${MAKE}
|
||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
|
||||||
[ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64"
|
|
||||||
${MAKE}
|
|
||||||
}
|
|
||||||
|
|
||||||
build_macos_universal() {
|
|
||||||
[ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64"
|
|
||||||
MACOS_UNIVERSAL=yes \
|
|
||||||
${MAKE}
|
|
||||||
}
|
|
||||||
|
|
||||||
build_cross() {
|
build_cross() {
|
||||||
[ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64"
|
[ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64"
|
||||||
CROSS=$1
|
CROSS=$1
|
||||||
|
@ -112,17 +101,14 @@ fi
|
||||||
export CC INSTALL_BIN PREFIX PKGCFGDIR LIBDIRARCH LIBARCHS CFLAGS LDFLAGS
|
export CC INSTALL_BIN PREFIX PKGCFGDIR LIBDIRARCH LIBARCHS CFLAGS LDFLAGS
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
"" ) build;;
|
"" ) ${MAKE};;
|
||||||
"macos-universal" ) build_macos_universal;;
|
|
||||||
"asan" ) asan;;
|
"asan" ) asan;;
|
||||||
"default" ) build;;
|
|
||||||
"install" ) install;;
|
"install" ) install;;
|
||||||
"uninstall" ) uninstall;;
|
"uninstall" ) uninstall;;
|
||||||
|
"macos-universal" ) MACOS_UNIVERSAL=yes ${MAKE};;
|
||||||
"cross-win32" ) build_cross i686-w64-mingw32;;
|
"cross-win32" ) build_cross i686-w64-mingw32;;
|
||||||
"cross-win64" ) build_cross x86_64-w64-mingw32;;
|
"cross-win64" ) build_cross x86_64-w64-mingw32;;
|
||||||
"cross-android" ) CROSS=arm-linux-androideabi build;;
|
"cross-android" ) CROSS=arm-linux-androideabi ${MAKE};;
|
||||||
"clang" ) CC=clang build;;
|
|
||||||
"gcc" ) CC=gcc build;;
|
|
||||||
"ios" ) build_iOS;;
|
"ios" ) build_iOS;;
|
||||||
"ios_armv7" ) build_iOS armv7;;
|
"ios_armv7" ) build_iOS armv7;;
|
||||||
"ios_armv7s" ) build_iOS armv7s;;
|
"ios_armv7s" ) build_iOS armv7s;;
|
||||||
|
|
131
samples/Makefile
131
samples/Makefile
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
include ../config.mk
|
include ../config.mk
|
||||||
|
|
||||||
LIBNAME = unicorn
|
|
||||||
UNAME_S := $(shell uname -s)
|
UNAME_S := $(shell uname -s)
|
||||||
|
|
||||||
# Find GLIB
|
# Find GLIB
|
||||||
|
@ -11,70 +10,34 @@ ifndef GLIB
|
||||||
GLIB = $(shell pkg-config --libs glib-2.0)
|
GLIB = $(shell pkg-config --libs glib-2.0)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
UNICORN_DEP_LIBS_STATIC += -lpthread -lm $(GLIB)
|
|
||||||
|
|
||||||
# Verbose output?
|
# Verbose output?
|
||||||
V ?= 0
|
V ?= 0
|
||||||
|
|
||||||
INCDIR = ../include
|
CFLAGS += -Wall -Werror -I../include
|
||||||
SAMPLEDIR = .
|
LDFLAGS += -L..
|
||||||
OBJDIR = .
|
LDLIBS += -lpthread -lunicorn -lm $(GLIB)
|
||||||
LIBDIR = ..
|
|
||||||
|
|
||||||
CFLAGS += -Wall -Werror -I$(INCDIR)
|
ifneq ($(CROSS),)
|
||||||
LDFLAGS += -lpthread -L$(LIBDIR) -l$(LIBNAME)
|
|
||||||
LDFLAGS_STATIC += $(UNICORN_DEP_LIBS_STATIC)
|
|
||||||
|
|
||||||
ifeq ($(CROSS),)
|
|
||||||
CC ?= cc
|
|
||||||
LDFLAGS += -lm $(GLIB)
|
|
||||||
else
|
|
||||||
CC = $(CROSS)gcc
|
CC = $(CROSS)gcc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(UNICORN_ASAN),yes)
|
ifeq ($(UNICORN_ASAN),yes)
|
||||||
CC = clang -fsanitize=address -fno-omit-frame-pointer
|
CC = clang
|
||||||
CXX = clang++ -fsanitize=address -fno-omit-frame-pointer
|
CXX = clang++
|
||||||
AR = llvm-ar
|
AR = llvm-ar
|
||||||
LDFLAGS := -fsanitize=address ${LDFLAGS}
|
CFLAGS += -fsanitize=address -fno-omit-frame-pointer
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
#CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch))
|
|
||||||
#LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch))
|
|
||||||
|
|
||||||
BIN_EXT =
|
|
||||||
AR_EXT = a
|
|
||||||
|
|
||||||
# Cygwin?
|
# Cygwin?
|
||||||
ifneq ($(filter CYGWIN%,$(UNAME_S)),)
|
ifneq ($(filter CYGWIN%,$(UNAME_S)),)
|
||||||
CFLAGS := $(CFLAGS:-fPIC=)
|
CFLAGS := $(CFLAGS:-fPIC=)
|
||||||
LDFLAGS += -lssp
|
LDLIBS += -lssp
|
||||||
LDFLAGS_STATIC += -lssp
|
|
||||||
BIN_EXT = .exe
|
|
||||||
AR_EXT = a
|
|
||||||
# mingw?
|
# mingw?
|
||||||
else ifneq ($(filter MINGW%,$(UNAME_S)),)
|
else ifneq ($(filter MINGW%,$(UNAME_S)),)
|
||||||
CFLAGS := $(CFLAGS:-fPIC=)
|
CFLAGS := $(CFLAGS:-fPIC=)
|
||||||
BIN_EXT = .exe
|
|
||||||
AR_EXT = lib
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
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
|
|
||||||
|
|
||||||
UNICORN_ARCHS := $(shell if [ -e ../config.log ]; then cat ../config.log;\
|
UNICORN_ARCHS := $(shell if [ -e ../config.log ]; then cat ../config.log;\
|
||||||
else printf "$(UNICORN_ARCHS)"; fi)
|
else printf "$(UNICORN_ARCHS)"; fi)
|
||||||
|
@ -89,9 +52,9 @@ endif
|
||||||
ifneq (,$(findstring mips,$(UNICORN_ARCHS)))
|
ifneq (,$(findstring mips,$(UNICORN_ARCHS)))
|
||||||
SOURCES += sample_mips.c
|
SOURCES += sample_mips.c
|
||||||
endif
|
endif
|
||||||
ifneq (,$(findstring ppc,$(UNICORN_ARCHS)))
|
#ifneq (,$(findstring ppc,$(UNICORN_ARCHS)))
|
||||||
#SOURCES += sample_ppc.c
|
#SOURCES += sample_ppc.c
|
||||||
endif
|
#endif
|
||||||
ifneq (,$(findstring sparc,$(UNICORN_ARCHS)))
|
ifneq (,$(findstring sparc,$(UNICORN_ARCHS)))
|
||||||
SOURCES += sample_sparc.c
|
SOURCES += sample_sparc.c
|
||||||
endif
|
endif
|
||||||
|
@ -106,73 +69,9 @@ ifneq (,$(findstring m68k,$(UNICORN_ARCHS)))
|
||||||
SOURCES += sample_m68k.c
|
SOURCES += sample_m68k.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o))
|
BINS = $(SOURCES:.c=)
|
||||||
OBJS_ELF = $(addprefix $(OBJDIR)/,$(SOURCES:.c=))
|
|
||||||
BINARY = $(addprefix $(SAMPLEDIR)/,$(SOURCES:.c=$(BIN_EXT)))
|
|
||||||
|
|
||||||
all: $(BINARY)
|
all: $(BINS)
|
||||||
|
|
||||||
clean_bins:
|
clean:
|
||||||
rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)*
|
rm -rf *.o $(BINS)
|
||||||
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
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#define X86_CODE32_JMP_INVALID "\xe9\xe9\xee\xee\xee\x41\x4a" // JMP outside; INC ecx; DEC edx
|
#define X86_CODE32_JMP_INVALID "\xe9\xe9\xee\xee\xee\x41\x4a" // JMP outside; INC ecx; DEC edx
|
||||||
#define X86_CODE32_INOUT "\x41\xE4\x3F\x4a\xE6\x46\x43" // INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
|
#define X86_CODE32_INOUT "\x41\xE4\x3F\x4a\xE6\x46\x43" // INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
|
||||||
|
#define X86_CODE32_INC "\x40" // INC eax
|
||||||
|
|
||||||
//#define X86_CODE64 "\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" // <== still crash
|
//#define X86_CODE64 "\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" // <== still crash
|
||||||
//#define X86_CODE64 "\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"
|
//#define X86_CODE64 "\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"
|
||||||
|
@ -668,6 +669,105 @@ static void test_i386_inout(void)
|
||||||
uc_close(uc);
|
uc_close(uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// emulate code and save/restore the CPU context
|
||||||
|
static void test_i386_context_save(void)
|
||||||
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
uc_context *context;
|
||||||
|
uc_err err;
|
||||||
|
|
||||||
|
int r_eax = 0x1; // EAX register
|
||||||
|
|
||||||
|
printf("===================================\n");
|
||||||
|
printf("Save/restore CPU context in opaque blob\n");
|
||||||
|
|
||||||
|
// initialize emulator in X86-32bit mode
|
||||||
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// map 8KB memory for this emulation
|
||||||
|
uc_mem_map(uc, ADDRESS, 8 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
|
// write machine code to be emulated to memory
|
||||||
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_INC, sizeof(X86_CODE32_INC) - 1)) {
|
||||||
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize machine registers
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EAX, &r_eax);
|
||||||
|
|
||||||
|
// emulate machine code in infinite time
|
||||||
|
printf(">>> Running emulation for the first time\n");
|
||||||
|
|
||||||
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
||||||
|
err, uc_strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
// now print out some registers
|
||||||
|
printf(">>> Emulation done. Below is the CPU context\n");
|
||||||
|
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
||||||
|
printf(">>> EAX = 0x%x\n", r_eax);
|
||||||
|
|
||||||
|
// allocate and save the CPU context
|
||||||
|
printf(">>> Saving CPU context\n");
|
||||||
|
|
||||||
|
err = uc_context_alloc(uc, &context);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_context_alloc() with error returned: %u\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = uc_context_save(uc, context);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_context_save() with error returned: %u\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// emulate machine code again
|
||||||
|
printf(">>> Running emulation for the second time\n");
|
||||||
|
|
||||||
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
||||||
|
err, uc_strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
// now print out some registers
|
||||||
|
printf(">>> Emulation done. Below is the CPU context\n");
|
||||||
|
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
||||||
|
printf(">>> EAX = 0x%x\n", r_eax);
|
||||||
|
|
||||||
|
// restore CPU context
|
||||||
|
err = uc_context_restore(uc, context);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_context_restore() with error returned: %u\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now print out some registers
|
||||||
|
printf(">>> CPU context restored. Below is the CPU context\n");
|
||||||
|
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
||||||
|
printf(">>> EAX = 0x%x\n", r_eax);
|
||||||
|
|
||||||
|
// free the CPU context
|
||||||
|
err = uc_context_free(context);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_context_free() with error returned: %u\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc_close(uc);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_x86_64(void)
|
static void test_x86_64(void)
|
||||||
{
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
|
@ -906,6 +1006,7 @@ int main(int argc, char **argv, char **envp)
|
||||||
test_i386();
|
test_i386();
|
||||||
test_i386_map_ptr();
|
test_i386_map_ptr();
|
||||||
test_i386_inout();
|
test_i386_inout();
|
||||||
|
test_i386_context_save();
|
||||||
test_i386_jump();
|
test_i386_jump();
|
||||||
test_i386_loop();
|
test_i386_loop();
|
||||||
test_i386_invalid_mem_read();
|
test_i386_invalid_mem_read();
|
||||||
|
|
|
@ -269,7 +269,7 @@ static void gdt_demo()
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
fprintf(stderr, "%02hhx", buf[i]);
|
fprintf(stderr, "%02x", buf[i]);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
|
|
||||||
CFLAGS += -Wall -Werror -Wno-unused-function -g
|
CFLAGS += -Wall -Werror -Wno-unused-function -g
|
||||||
CFLAGS += -L ../../
|
CFLAGS += -L ../../ -I ../../include
|
||||||
CFLAGS += -I ../../include
|
|
||||||
CFLAGS += -L ../../cmocka/src -I ../../cmocka/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)
|
ifeq ($(UNICORN_ASAN),yes)
|
||||||
CC = clang -fsanitize=address -fno-omit-frame-pointer
|
CC = clang -fsanitize=address -fno-omit-frame-pointer
|
||||||
|
@ -14,9 +12,8 @@ AR = llvm-ar
|
||||||
LDFLAGS := -fsanitize=address ${LDFLAGS}
|
LDFLAGS := -fsanitize=address ${LDFLAGS}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \
|
ALL_TESTS_SOURCES = $(wildcard *.c)
|
||||||
test_tb_x86 test_multihook test_pc_change test_x86_soft_paging \
|
ALL_TESTS = $(ALL_TESTS_SOURCES:%.c=%)
|
||||||
test_hookcounts test_hang test_x86_shl_enter_leave test_x86_rip_bug
|
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: ${ALL_TESTS}
|
all: ${ALL_TESTS}
|
||||||
|
@ -32,28 +29,11 @@ test: ${ALL_TESTS}
|
||||||
${EXECUTE_VARS} ./test_mem_map
|
${EXECUTE_VARS} ./test_mem_map
|
||||||
${EXECUTE_VARS} ./test_mem_map_ptr
|
${EXECUTE_VARS} ./test_mem_map_ptr
|
||||||
${EXECUTE_VARS} ./test_mem_high
|
${EXECUTE_VARS} ./test_mem_high
|
||||||
echo "skipping test_tb_x86" #${EXECUTE_VARS} ./test_tb_x86
|
|
||||||
${EXECUTE_VARS} ./test_multihook
|
${EXECUTE_VARS} ./test_multihook
|
||||||
${EXECUTE_VARS} ./test_pc_change
|
${EXECUTE_VARS} ./test_pc_change
|
||||||
echo "skipping test_x86_soft_paging" #${EXECUTE_VARS} ./test_x86_soft_paging
|
|
||||||
${EXECUTE_VARS} ./test_hookcounts
|
${EXECUTE_VARS} ./test_hookcounts
|
||||||
echo "skipping test_hang" #${EXECUTE_VARS} ./test_hang
|
echo "skipping test_tb_x86"
|
||||||
echo "skipping test_x86_sh1_enter_leave" #${EXECUTE_VARS} ./test_x86_shl_enter_leave
|
echo "skipping test_x86_soft_paging"
|
||||||
echo "skipping test_x86_rip_bug" #${EXECUTE_VARS} ./test_x86_rip_bug
|
echo "skipping test_hang"
|
||||||
|
echo "skipping test_x86_sh1_enter_leave"
|
||||||
test_sanity: test_sanity.c
|
echo "skipping test_x86_rip_bug"
|
||||||
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}
|
|
||||||
|
|
15
uc.c
15
uc.c
|
@ -1,9 +1,6 @@
|
||||||
/* Unicorn Emulator Engine */
|
/* Unicorn Emulator Engine */
|
||||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||||
|
|
||||||
#if defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)
|
|
||||||
#pragma warning(disable:4996)
|
|
||||||
#endif
|
|
||||||
#if defined(UNICORN_HAS_OSXKERNEL)
|
#if defined(UNICORN_HAS_OSXKERNEL)
|
||||||
#include <libkern/libkern.h>
|
#include <libkern/libkern.h>
|
||||||
#else
|
#else
|
||||||
|
@ -1162,12 +1159,24 @@ static size_t cpu_context_size(uc_arch arch, uc_mode mode)
|
||||||
// tbl_table is the first entry in the CPU_COMMON macro, so it marks the end
|
// tbl_table is the first entry in the CPU_COMMON macro, so it marks the end
|
||||||
// of the interesting CPU registers
|
// of the interesting CPU registers
|
||||||
switch (arch) {
|
switch (arch) {
|
||||||
|
#ifdef UNICORN_HAS_M68K
|
||||||
case UC_ARCH_M68K: return M68K_REGS_STORAGE_SIZE;
|
case UC_ARCH_M68K: return M68K_REGS_STORAGE_SIZE;
|
||||||
|
#endif
|
||||||
|
#ifdef UNICORN_HAS_X86
|
||||||
case UC_ARCH_X86: return X86_REGS_STORAGE_SIZE;
|
case UC_ARCH_X86: return X86_REGS_STORAGE_SIZE;
|
||||||
|
#endif
|
||||||
|
#ifdef UNICORN_HAS_ARM
|
||||||
case UC_ARCH_ARM: return ARM_REGS_STORAGE_SIZE;
|
case UC_ARCH_ARM: return ARM_REGS_STORAGE_SIZE;
|
||||||
|
#endif
|
||||||
|
#ifdef UNICORN_HAS_ARM64
|
||||||
case UC_ARCH_ARM64: return ARM64_REGS_STORAGE_SIZE;
|
case UC_ARCH_ARM64: return ARM64_REGS_STORAGE_SIZE;
|
||||||
|
#endif
|
||||||
|
#ifdef UNICORN_HAS_MIPS
|
||||||
case UC_ARCH_MIPS: return mode & UC_MODE_MIPS64 ? MIPS64_REGS_STORAGE_SIZE : MIPS_REGS_STORAGE_SIZE;
|
case UC_ARCH_MIPS: return mode & UC_MODE_MIPS64 ? MIPS64_REGS_STORAGE_SIZE : MIPS_REGS_STORAGE_SIZE;
|
||||||
|
#endif
|
||||||
|
#ifdef UNICORN_HAS_SPARC
|
||||||
case UC_ARCH_SPARC: return mode & UC_MODE_SPARC64 ? SPARC64_REGS_STORAGE_SIZE : SPARC_REGS_STORAGE_SIZE;
|
case UC_ARCH_SPARC: return mode & UC_MODE_SPARC64 ? SPARC64_REGS_STORAGE_SIZE : SPARC_REGS_STORAGE_SIZE;
|
||||||
|
#endif
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue