From 75a325e8c6af81338ef204037cf35c32a12acca9 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sun, 29 Nov 2015 23:00:34 +0100 Subject: [PATCH 01/40] Crash case: Invalid read of size 8 in tb_flush_x86_64. --- .gitignore | 1 + tests/regress/Makefile | 1 + tests/regress/x86_16_segfault.c | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 tests/regress/x86_16_segfault.c diff --git a/.gitignore b/.gitignore index f58e52e7..70a55b91 100644 --- a/.gitignore +++ b/.gitignore @@ -113,6 +113,7 @@ eflags_noset mem_map_large invalid_read_in_cpu_tb_exec invalid_write_in_cpu_tb_exec_x86_64 +x86_16_segfault ################# diff --git a/tests/regress/Makefile b/tests/regress/Makefile index a438aeaf..5903b070 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -18,6 +18,7 @@ TESTS += eflags_noset TESTS += mem_map_large TESTS += invalid_read_in_cpu_tb_exec TESTS += invalid_write_in_cpu_tb_exec_x86_64 +TESTS += x86_16_segfault all: $(TESTS) diff --git a/tests/regress/x86_16_segfault.c b/tests/regress/x86_16_segfault.c new file mode 100644 index 00000000..d7d97b03 --- /dev/null +++ b/tests/regress/x86_16_segfault.c @@ -0,0 +1,22 @@ +#include + +#define BINARY "\x90" +#define MEMORY_SIZE 4 * 1024 +#define STARTING_ADDRESS 100 * 1024 + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(UC_ARCH_X86, UC_MODE_16, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, STARTING_ADDRESS, MEMORY_SIZE, UC_PROT_ALL); + if (uc_mem_write(uc, STARTING_ADDRESS, BINARY, sizeof(BINARY) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, STARTING_ADDRESS, STARTING_ADDRESS + sizeof(BINARY) - 1, 0, 20); + printf("done\n"); + return 0; +} From 7a1067ad4a5c874b601b250fcf4b001e2caff951 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Mon, 30 Nov 2015 23:44:49 +0100 Subject: [PATCH 02/40] Crash case: Invalid read of size 4 when tracing (MIPS32). See #282 --- .gitignore | 1 + tests/regress/Makefile | 1 + ...mips_invalid_read_of_size_4_when_tracing.c | 33 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/regress/mips_invalid_read_of_size_4_when_tracing.c diff --git a/.gitignore b/.gitignore index 70a55b91..6efa5142 100644 --- a/.gitignore +++ b/.gitignore @@ -114,6 +114,7 @@ mem_map_large invalid_read_in_cpu_tb_exec invalid_write_in_cpu_tb_exec_x86_64 x86_16_segfault +mips_invalid_read_of_size_4_when_tracing ################# diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 5903b070..33a5f089 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -19,6 +19,7 @@ TESTS += mem_map_large TESTS += invalid_read_in_cpu_tb_exec TESTS += invalid_write_in_cpu_tb_exec_x86_64 TESTS += x86_16_segfault +TESTS += mips_invalid_read_of_size_4_when_tracing all: $(TESTS) diff --git a/tests/regress/mips_invalid_read_of_size_4_when_tracing.c b/tests/regress/mips_invalid_read_of_size_4_when_tracing.c new file mode 100644 index 00000000..d912a604 --- /dev/null +++ b/tests/regress/mips_invalid_read_of_size_4_when_tracing.c @@ -0,0 +1,33 @@ +#include + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("tracing\n"); +} + +#define HARDWARE_ARCHITECTURE UC_ARCH_MIPS +#define HARDWARE_MODE UC_MODE_MIPS32 + +#define MEMORY_STARTING_ADDRESS 0x1000000 +#define MEMORY_SIZE 2 * 1024 * 1024 +#define MEMORY_PERMISSIONS UC_PROT_ALL + +#define BINARY_CODE "00000000000000000000000000AA" + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} From c50bf567c0e694691cbb577fb49833d519c25096 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Tue, 1 Dec 2015 22:41:51 +0100 Subject: [PATCH 03/40] Crash case: Invalid read of size 8 in tb_flush_x86_64 --- .../regress/invalid_read_in_tb_flush_x86_64.c | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/regress/invalid_read_in_tb_flush_x86_64.c diff --git a/tests/regress/invalid_read_in_tb_flush_x86_64.c b/tests/regress/invalid_read_in_tb_flush_x86_64.c new file mode 100644 index 00000000..dc2ca494 --- /dev/null +++ b/tests/regress/invalid_read_in_tb_flush_x86_64.c @@ -0,0 +1,27 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_X86 +#define HARDWARE_MODE UC_MODE_64 + +#define MEMORY_STARTING_ADDRESS 0x1000000 +#define MEMORY_SIZE 2 * 1024 * 1024 +#define MEMORY_PERMISSIONS UC_PROT_READ + +#define BINARY_CODE "\x90" + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 20); + printf("done\n"); + return 0; +} From 23aa6aa9a65ca8d4aaf20c05030da911469520ad Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 2 Dec 2015 07:15:44 +0100 Subject: [PATCH 04/40] Add invalid_read_in_tb_flush_x86_64 to .gitignore and Makefile --- .gitignore | 1 + tests/regress/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6efa5142..bea69ee4 100644 --- a/.gitignore +++ b/.gitignore @@ -115,6 +115,7 @@ invalid_read_in_cpu_tb_exec invalid_write_in_cpu_tb_exec_x86_64 x86_16_segfault mips_invalid_read_of_size_4_when_tracing +invalid_read_in_tb_flush_x86_64 ################# diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 33a5f089..a90b06fe 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -20,6 +20,7 @@ TESTS += invalid_read_in_cpu_tb_exec TESTS += invalid_write_in_cpu_tb_exec_x86_64 TESTS += x86_16_segfault TESTS += mips_invalid_read_of_size_4_when_tracing +TESTS += invalid_read_in_tb_flush_x86_64 all: $(TESTS) From 31e32d1734f096d2b4c2054512fd81f8aea0eb07 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 2 Dec 2015 21:55:13 +0100 Subject: [PATCH 05/40] Crash case: Jump to invalid address (0x0), sparc32 --- .gitignore | 1 + tests/regress/Makefile | 1 + tests/regress/sparc_jump_to_zero.c | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 tests/regress/sparc_jump_to_zero.c diff --git a/.gitignore b/.gitignore index bea69ee4..46c06b39 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,7 @@ invalid_write_in_cpu_tb_exec_x86_64 x86_16_segfault mips_invalid_read_of_size_4_when_tracing invalid_read_in_tb_flush_x86_64 +sparc_jump_to_zero ################# diff --git a/tests/regress/Makefile b/tests/regress/Makefile index a90b06fe..a2283d9d 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -21,6 +21,7 @@ TESTS += invalid_write_in_cpu_tb_exec_x86_64 TESTS += x86_16_segfault TESTS += mips_invalid_read_of_size_4_when_tracing TESTS += invalid_read_in_tb_flush_x86_64 +TESTS += sparc_jump_to_zero all: $(TESTS) diff --git a/tests/regress/sparc_jump_to_zero.c b/tests/regress/sparc_jump_to_zero.c new file mode 100644 index 00000000..ecef159a --- /dev/null +++ b/tests/regress/sparc_jump_to_zero.c @@ -0,0 +1,27 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_SPARC +#define HARDWARE_MODE UC_MODE_32 + +#define MEMORY_STARTING_ADDRESS 0x1000000 +#define MEMORY_SIZE 2 * 1024 * 1024 +#define MEMORY_PERMISSIONS UC_PROT_ALL + +#define BINARY_CODE "\x02\xbc" + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 20); + printf("done\n"); + return 0; +} From 032eb66908225a6af7296a366a03cfbbbdfbf33a Mon Sep 17 00:00:00 2001 From: xorstream Date: Fri, 4 Dec 2015 16:51:19 +1100 Subject: [PATCH 06/40] Added MIPS delay slot code hook test Tests that the code hook gets called for instructions in the branch delay slot for MIPS cpu. --- tests/regress/mips_delay_slot_code_hook.c | 130 ++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 tests/regress/mips_delay_slot_code_hook.c diff --git a/tests/regress/mips_delay_slot_code_hook.c b/tests/regress/mips_delay_slot_code_hook.c new file mode 100644 index 00000000..181b894b --- /dev/null +++ b/tests/regress/mips_delay_slot_code_hook.c @@ -0,0 +1,130 @@ +/* +Test for code hook being called for instructions in branch delay slot in MIPS cpu. +See issue https://github.com/unicorn-engine/unicorn/issues/290 + +The code hook should be called for every instruction executed. +This test checks that the code hook is correctly called for instructions in branch delay slots. +In this test the loop check value is decremented inside the branch delay shot. +This helps to show that the instruction in the branch delay slot is being executed, +but that the code hook is just not occurring. +*/ + +#include + +#ifdef _MSC_VER +#include +#else +#include +#include +#endif + +#ifdef DYNLOAD +#include +#else +#include +#endif + + +// Test MIPS little endian code. +// It should loop 3 times before ending. +const uint64_t addr = 0x100000; +const unsigned char loop_test_code[] = { + 0x02,0x00,0x04,0x24, // 100000: li $a0, 2 + // loop1 + 0x00,0x00,0x00,0x00, // 100004: nop + 0xFE,0xFF,0x80,0x14, // 100008: bnez $a0, loop1 + 0xFF,0xFF,0x84,0x24, // 10000C: addiu $a0, -1 +}; +bool test_passed_ok = false; +int loop_count = 0; + + +static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + if( address == 0x10000C ) + test_passed_ok = true; + if( address == 0x100004 ) + { + printf("\nloop %d:\n", loop_count); + loop_count++; + } + printf("Code: %llX\n", address); +} + + +int main(int argc, char **argv, char **envp) +{ + uc_engine *uc; + uc_err err; + uc_hook hhc; + uint32_t val; + + // dynamically load shared library +#ifdef DYNLOAD + uc_dyn_load(NULL, 0); +#endif + + // Initialize emulator in MIPS 32bit little endian mode + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); + if (err) + { + printf("Failed on uc_open() with error returned: %u\n", err); + return err; + } + + // map in a page of mem + err = uc_mem_map(uc, addr, 0x1000, UC_PROT_ALL); + if (err) + { + printf("Failed on uc_mem_map() with error returned: %u\n", err); + return err; + } + + // write machine code to be emulated to memory + err = uc_mem_write(uc, addr, loop_test_code, sizeof(loop_test_code)); + if( err ) + { + printf("Failed on uc_mem_write() with error returned: %u\n", err); + return err; + } + + // hook all instructions by having @begin > @end + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + if( err ) + { + printf("Failed on uc_hook_add(code) with error returned: %u\n", err); + return err; + } + + // execute code + printf("---- Executing Code ----\n"); + err = uc_emu_start(uc, addr, addr + sizeof(loop_test_code), 0, 0); + if (err) + { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + return err; + } + + // done executing, print some reg values as a test + printf("---- Execution Complete ----\n\n"); + uc_reg_read(uc, UC_MIPS_REG_PC, &val); printf("pc is %X\n", val); + uc_reg_read(uc, UC_MIPS_REG_A0, &val); printf("a0 is %X\n", val); + + // free resources + uc_close(uc); + + if( test_passed_ok ) + printf("\n\nTEST PASSED!\n\n"); + else + printf("\n\nTEST FAILED!\n\n"); + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} + + From 77f946f2fc02a27ea6a123d6ec3fa8d244e0ba42 Mon Sep 17 00:00:00 2001 From: xorstream Date: Fri, 4 Dec 2015 22:09:24 +1100 Subject: [PATCH 07/40] Added MSVC++ support for unicorn This lets you import the pre-built unicorn.dll files with Microsoft Visual C++ projects. There is support for static and dynamic linking of dlls. This has been tested as working for both 32bit and 64bit versions. The dynamic linking code should also work in Linux, though I have not tested it. --- .gitignore | 1 + bindings/msvc/README.TXT | 77 +++++++++ bindings/msvc/make_staload.bat | 3 + bindings/msvc/unicorn.def | 18 +++ bindings/msvc/unicorn_dynload.c | 249 ++++++++++++++++++++++++++++++ include/unicorn/unicorn_dynload.h | 67 ++++++++ 6 files changed, 415 insertions(+) create mode 100644 bindings/msvc/README.TXT create mode 100644 bindings/msvc/make_staload.bat create mode 100644 bindings/msvc/unicorn.def create mode 100644 bindings/msvc/unicorn_dynload.c create mode 100644 include/unicorn/unicorn_dynload.h diff --git a/.gitignore b/.gitignore index 46c06b39..e7c8f34b 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,7 @@ unicorn.pc unicorn.lib unicorn.dll unicorn_*.lib +unicorn_*.exp unicorn_*.dll diff --git a/bindings/msvc/README.TXT b/bindings/msvc/README.TXT new file mode 100644 index 00000000..7d2a9b31 --- /dev/null +++ b/bindings/msvc/README.TXT @@ -0,0 +1,77 @@ +This documentation explains how to use Unicorn with Microsoft Visual C++ (MSVC). +This will not build the Unicorn Engine itself, it just allows you to use the +prebuilt Windows binaries when writing projects in Microsoft Visual C++. + +The prebuilt windows binaries can be found under the "Windows Core engine" +heading on the following page. Be sure to use the 32bit package when making +32bit applications (even in 64bit windows). And use the 64bit package to +build 64bit applications. +http://www.unicorn-engine.org/download/ + + + +It is not possible to use the prebuilt static Unicorn library, unicorn.lib, +with Microsoft Visual C++ because it will complain about a bunch of missing +functions, variables etc. + +We therefore use the prebuilt dynamic Unicorn library, unicorn.dll. +There are two ways to use this with your Microsoft Visual C++ project: +1) By dynamically linking the dll into your project. +2) By statically linking the dll into your project. + + + +:: 1) Dynamic Linking + +The files unicorn_dynload.c and unicorn_dynload.h are used for dynamic linking. +Ensure that unicorn_dynload.h is in the main unicorn includes directory. +(It should be in the same directory as "unicorn.h".) +Then include unicorn_dynload.c in your project so that it gets build along +with your other project files. You could alternatively compile it first into a +static library and then link that library into your project. + +Now where you would normally include "unicorn.h" in your project you instead +include "unicorn_dynload.h". You should also define DYNLOAD above the include +of "unicorn_dynload.h", or instead add DYNLOAD to your project settings in: +Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions. + +Some example code for including this header is as follows: + +#define DYNLOAD 1 + +#ifdef DYNLOAD +#include +#else +#include +#endif + +Now build your application as normal. + + + +:: 2) Static Linking + +To perform static linking of unicorn.dll, you need to first generate some +static import libraries. To do this run "make_staload.bat". +You may need to edit the first line in "make_staload.bat" to point to the +location of your "vcvars32.bat" file. This will build separate import libraries +for importing the 32bit or 64bit version of the dlls. +unicorn_staload.lib is used to link to the 32bit version of unicorn.dll. +unicorn_staload64.lib is used to link to the 64bit version of unicorn.dll. + +Now you make a unicorn project like usual, including "unicorn.h", and +then you need to also link in "unicorn_staload.lib" or "unicorn_staload64.lib". + +The first step to doing this is to make sure the directory that contains +"unicorn_staload.lib" is added to your project by adding it in: +Configuration Properties -> C/C++ -> Linker -> General -> Additional Library Directories +(So for example add here "C:\unicorn\bindings\msvc" if that is where they are) + +The second step is to link in the library. You can do this by either adding +this line to your C sourcecode: +#pragma comment(lib, "unicorn_staload.lib") + +Or by adding "unicorn_staload.lib" to your project in: +Configuration Properties -> C/C++ -> Linker -> Input -> Additional Dependencies + + diff --git a/bindings/msvc/make_staload.bat b/bindings/msvc/make_staload.bat new file mode 100644 index 00000000..fb6e6985 --- /dev/null +++ b/bindings/msvc/make_staload.bat @@ -0,0 +1,3 @@ +call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\vcvars32.bat" +lib /DEF:unicorn.def /OUT:unicorn_staload.lib /MACHINE:X86 +lib /DEF:unicorn.def /OUT:unicorn_staload64.lib /MACHINE:X64 diff --git a/bindings/msvc/unicorn.def b/bindings/msvc/unicorn.def new file mode 100644 index 00000000..c8d88b3b --- /dev/null +++ b/bindings/msvc/unicorn.def @@ -0,0 +1,18 @@ +EXPORTS +uc_version +uc_arch_supported +uc_open +uc_close +uc_errno +uc_strerror +uc_reg_write +uc_reg_read +uc_mem_write +uc_mem_read +uc_emu_start +uc_emu_stop +uc_hook_add +uc_hook_del +uc_mem_map +uc_mem_unmap +uc_mem_protect diff --git a/bindings/msvc/unicorn_dynload.c b/bindings/msvc/unicorn_dynload.c new file mode 100644 index 00000000..7c63a823 --- /dev/null +++ b/bindings/msvc/unicorn_dynload.c @@ -0,0 +1,249 @@ +// +// Dynamic loader for unicorn shared library in windows and linux. +// This was made for v0.9 of unicorn. +// Newer versions of unicorn may require changes to these files. +// +// Windows Notes: +// If an absolute path to unicorn.dll is passed into uc_dyn_load() it will +// still try to load the rest of the dependent dlls (ie libglib-2.0-0.dll etc) +// from standard dll paths. This is usually the directory that the main +// exe file, that loaded unicorn.dll, is in. This is standard behaviour for +// Windows dll files, and not specific to unicorn dlls. +// +// So putting all dlls in their own directory and then attempting to load +// unicorn.dll from that directory via an absolute path will cause +// uc_dyn_load() to fail. +// +// The easiest way around this is to place all dlls in the same directory +// as your main exe file. Other ways around this are using various flags +// for LoadLibraryEx() or by calling SetDllDirectory(). +// +// LoadLibraryEx info: +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx +// SetDllDirectory() info: +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686203(v=vs.85).aspx +// +// Zak Escano - November 2015 +// + +// This is to detect whether we are loading a dll in windows or a so in linux. +#ifdef _MSC_VER +#define WINDOWS_DLL 1 +#endif + +#include + +#ifdef WINDOWS_DLL +#include +#define DYNLOAD_DEFPATH "unicorn.dll" +#define DYNLOAD_HANDLE HMODULE +#define DYNLOAD_LOADLIB(path, f)LoadLibraryEx(path, NULL, f) +#define DYNLOAD_FREELIB(handle) FreeLibrary(handle) +#define DYNLOAD_GETFUNC(h, n) GetProcAddress(h, n) +#define DYNLOAD_GETERROR() GetLastError() +#else +#include +#define DYNLOAD_DEFPATH "unicorn.so" +#define DYNLOAD_HANDLE void* +#define DYNLOAD_LOADLIB(path, f)dlopen(path, f) +#define DYNLOAD_FREELIB(handle) dlclose(handle) +#define DYNLOAD_GETFUNC(h, n) dlsym(h, n) +#define DYNLOAD_GETERROR() dlerror() +#endif + + +static DYNLOAD_HANDLE g_dyn_handle = NULL; + + +typedef unsigned int (*uc_version_t)(unsigned int *major, unsigned int *minor); +typedef bool (*uc_arch_supported_t)(uc_arch arch); +typedef uc_err (*uc_open_t)(uc_arch arch, uc_mode mode, uc_engine **uc); +typedef uc_err (*uc_close_t)(uc_engine *uc); +typedef uc_err (*uc_errno_t)(uc_engine *uc); +typedef const char* (*uc_strerror_t)(uc_err code); +typedef uc_err (*uc_reg_write_t)(uc_engine *uc, int regid, const void *value); +typedef uc_err (*uc_reg_read_t)(uc_engine *uc, int regid, void *value); +typedef uc_err (*uc_mem_write_t)(uc_engine *uc, uint64_t address, const void *bytes, size_t size); +typedef uc_err (*uc_mem_read_t)(uc_engine *uc, uint64_t address, void *bytes, size_t size); +typedef uc_err (*uc_emu_start_t)(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); +typedef uc_err (*uc_emu_stop_t)(uc_engine *uc); +typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...); +typedef uc_err (*uc_hook_del_t)(uc_engine *uc, uc_hook hh); +typedef uc_err (*uc_mem_map_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); +typedef uc_err (*uc_mem_unmap_t)(uc_engine *uc, uint64_t address, size_t size); +typedef uc_err (*uc_mem_protect_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); + + +static uc_version_t gp_uc_version = NULL; +static uc_arch_supported_t gp_uc_arch_supported = NULL; +static uc_open_t gp_uc_open = NULL; +static uc_close_t gp_uc_close = NULL; +static uc_errno_t gp_uc_errno = NULL; +static uc_strerror_t gp_uc_strerror = NULL; +static uc_reg_write_t gp_uc_reg_write = NULL; +static uc_reg_read_t gp_uc_reg_read = NULL; +static uc_mem_write_t gp_uc_mem_write = NULL; +static uc_mem_read_t gp_uc_mem_read = NULL; +static uc_emu_start_t gp_uc_emu_start = NULL; +static uc_emu_stop_t gp_uc_emu_stop = NULL; +static uc_hook_add_t gp_uc_hook_add = NULL; +static uc_hook_del_t gp_uc_hook_del = NULL; +static uc_mem_map_t gp_uc_mem_map = NULL; +static uc_mem_unmap_t gp_uc_mem_unmap = NULL; +static uc_mem_protect_t gp_uc_mem_protect = NULL; + + +bool uc_dyn_load(const char* path, int flags) +{ + if( path == NULL ) + { + path = DYNLOAD_DEFPATH; + } + + if( g_dyn_handle ) + { + if( !uc_dyn_free() ) + return false; + } + + g_dyn_handle = DYNLOAD_LOADLIB(path, flags); + if( g_dyn_handle == NULL ) + { + //int err = DYNLOAD_GETERROR(); + //printf("Error loading %s: Last error is %X\n", path, err); + return false; + } + + gp_uc_version = (uc_version_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_version"); + gp_uc_arch_supported = (uc_arch_supported_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_arch_supported"); + gp_uc_open = (uc_open_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_open"); + gp_uc_close = (uc_close_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_close"); + gp_uc_errno = (uc_errno_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_errno"); + gp_uc_strerror = (uc_strerror_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_strerror"); + gp_uc_reg_write = (uc_reg_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_write"); + gp_uc_reg_read = (uc_reg_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_read"); + gp_uc_mem_write = (uc_mem_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_write"); + gp_uc_mem_read = (uc_mem_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_read"); + gp_uc_emu_start = (uc_emu_start_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_start"); + gp_uc_emu_stop = (uc_emu_stop_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_stop"); + gp_uc_hook_add = (uc_hook_add_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_add"); + gp_uc_hook_del = (uc_hook_del_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_del"); + gp_uc_mem_map = (uc_mem_map_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map"); + gp_uc_mem_unmap = (uc_mem_unmap_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_unmap"); + gp_uc_mem_protect = (uc_mem_protect_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_protect"); + return true; +} + +bool uc_dyn_free(void) +{ + if( g_dyn_handle==NULL ) + return true; + + DYNLOAD_FREELIB(g_dyn_handle); + g_dyn_handle = NULL; + + gp_uc_version = NULL; + gp_uc_arch_supported = NULL; + gp_uc_open = NULL; + gp_uc_close = NULL; + gp_uc_errno = NULL; + gp_uc_strerror = NULL; + gp_uc_reg_write = NULL; + gp_uc_reg_read = NULL; + gp_uc_mem_write = NULL; + gp_uc_mem_read = NULL; + gp_uc_emu_start = NULL; + gp_uc_emu_stop = NULL; + gp_uc_hook_add = NULL; + gp_uc_hook_del = NULL; + gp_uc_mem_map = NULL; + gp_uc_mem_unmap = NULL; + gp_uc_mem_protect = NULL; + return true; +} + + +unsigned int uc_version(unsigned int *major, unsigned int *minor) +{ return gp_uc_version(major, minor); } + +bool uc_arch_supported(uc_arch arch) +{ return gp_uc_arch_supported(arch); } + +uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc) +{ return gp_uc_open(arch, mode, uc); } + +uc_err uc_close(uc_engine *uc) +{ return gp_uc_close(uc); } + +uc_err uc_errno(uc_engine *uc) +{ return gp_uc_errno(uc); } + +const char *uc_strerror(uc_err code) +{ return gp_uc_strerror(code); } + +uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) +{ return gp_uc_reg_write(uc, regid, value); } + +uc_err uc_reg_read(uc_engine *uc, int regid, void *value) +{ return gp_uc_reg_read(uc, regid, value); } + +uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size) +{ return gp_uc_mem_write(uc, address, bytes, size); } + +uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size) +{ return gp_uc_mem_read(uc, address, bytes, size); } + +uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) +{ return gp_uc_emu_start(uc, begin, until, timeout, count); } + +uc_err uc_emu_stop(uc_engine *uc) +{ return gp_uc_emu_stop(uc); } + +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...) +{ + va_list valist; + uc_err ret = UC_ERR_OK; + int id; + uint64_t begin, end; + va_start(valist, user_data); + + switch(type) { + default: + break; + case UC_HOOK_INTR: + // 0 extra args + ret = gp_uc_hook_add(uc, hh, type, callback, user_data); + break; + case UC_HOOK_INSN: + // 1 extra arg + id = va_arg(valist, int); + ret = gp_uc_hook_add(uc, hh, type, callback, user_data, id); + break; + case UC_HOOK_CODE: + case UC_HOOK_BLOCK: + case UC_HOOK_MEM_READ: + case UC_HOOK_MEM_WRITE: + case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE: + // 2 extra arg + begin = va_arg(valist, uint64_t); + end = va_arg(valist, uint64_t); + ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end); + break; + } + + va_end(valist); + return ret; +} + +uc_err uc_hook_del(uc_engine *uc, uc_hook hh) +{ return gp_uc_hook_del(uc, hh); } + +uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) +{ return gp_uc_mem_map(uc, address, size, perms); } + +uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size) +{ return gp_uc_mem_unmap(uc, address, size); } + +uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) +{ return gp_uc_mem_protect(uc, address, size, perms); } + diff --git a/include/unicorn/unicorn_dynload.h b/include/unicorn/unicorn_dynload.h new file mode 100644 index 00000000..73014d92 --- /dev/null +++ b/include/unicorn/unicorn_dynload.h @@ -0,0 +1,67 @@ +// +// Dynamic loader for unicorn shared library in windows and linux. +// This was made for v0.9 of unicorn. +// Newer versions of unicorn may require changes to these files. +// +// Windows Notes: +// If an absolute path to unicorn.dll is passed into uc_dyn_load() it will +// still try to load the rest of the dependent dlls (ie libglib-2.0-0.dll etc) +// from standard dll paths. This is usually the directory that the main +// exe file, that loaded unicorn.dll, is in. This is standard behaviour for +// Windows dll files, and not specific to unicorn dlls. +// +// So putting all dlls in their own directory and then attempting to load +// unicorn.dll from that directory via an absolute path will cause +// uc_dyn_load() to fail. +// +// The easiest way around this is to place all dlls in the same directory +// as your main exe file. Other ways around this are using various flags +// for LoadLibraryEx() or by calling SetDllDirectory(). +// +// LoadLibraryEx info: +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx +// SetDllDirectory() info: +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686203(v=vs.85).aspx +// +// Zak Escano - November 2015 +// + +#ifndef _UNICORN_DYNLOAD_H_ +#define _UNICORN_DYNLOAD_H_ + +// Undefine shared here so that functions aren't defined as: "__declspec(dllexport)" +#ifdef UNICORN_SHARED +#undef UNICORN_SHARED +#endif +#include "unicorn.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + Dynamically load shared library. + Check the notes at the top for info regarding dll file locations in windows. + + @path: path to shared library file. (NULL to use default path) + @flags: system specific flags for loading shared library file. (0 for default) + + @return true on success, false if failed. +*/ +bool uc_dyn_load(const char* path, int flags); + +/* + Free resources when done using shared library. + + @return true on success, false if failed. +*/ +bool uc_dyn_free(void); + + +#ifdef __cplusplus +} +#endif + +#endif // _UNICORN_DYNLOAD_H_ + From 3ce4f6f7a25e2edea48adf8e8331283e26888611 Mon Sep 17 00:00:00 2001 From: xorstream Date: Sat, 5 Dec 2015 09:58:49 +1100 Subject: [PATCH 08/40] Revert "Added MIPS delay slot code hook test" This reverts commit 032eb66908225a6af7296a366a03cfbbbdfbf33a. --- tests/regress/mips_delay_slot_code_hook.c | 130 ---------------------- 1 file changed, 130 deletions(-) delete mode 100644 tests/regress/mips_delay_slot_code_hook.c diff --git a/tests/regress/mips_delay_slot_code_hook.c b/tests/regress/mips_delay_slot_code_hook.c deleted file mode 100644 index 181b894b..00000000 --- a/tests/regress/mips_delay_slot_code_hook.c +++ /dev/null @@ -1,130 +0,0 @@ -/* -Test for code hook being called for instructions in branch delay slot in MIPS cpu. -See issue https://github.com/unicorn-engine/unicorn/issues/290 - -The code hook should be called for every instruction executed. -This test checks that the code hook is correctly called for instructions in branch delay slots. -In this test the loop check value is decremented inside the branch delay shot. -This helps to show that the instruction in the branch delay slot is being executed, -but that the code hook is just not occurring. -*/ - -#include - -#ifdef _MSC_VER -#include -#else -#include -#include -#endif - -#ifdef DYNLOAD -#include -#else -#include -#endif - - -// Test MIPS little endian code. -// It should loop 3 times before ending. -const uint64_t addr = 0x100000; -const unsigned char loop_test_code[] = { - 0x02,0x00,0x04,0x24, // 100000: li $a0, 2 - // loop1 - 0x00,0x00,0x00,0x00, // 100004: nop - 0xFE,0xFF,0x80,0x14, // 100008: bnez $a0, loop1 - 0xFF,0xFF,0x84,0x24, // 10000C: addiu $a0, -1 -}; -bool test_passed_ok = false; -int loop_count = 0; - - -static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) -{ - if( address == 0x10000C ) - test_passed_ok = true; - if( address == 0x100004 ) - { - printf("\nloop %d:\n", loop_count); - loop_count++; - } - printf("Code: %llX\n", address); -} - - -int main(int argc, char **argv, char **envp) -{ - uc_engine *uc; - uc_err err; - uc_hook hhc; - uint32_t val; - - // dynamically load shared library -#ifdef DYNLOAD - uc_dyn_load(NULL, 0); -#endif - - // Initialize emulator in MIPS 32bit little endian mode - err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); - if (err) - { - printf("Failed on uc_open() with error returned: %u\n", err); - return err; - } - - // map in a page of mem - err = uc_mem_map(uc, addr, 0x1000, UC_PROT_ALL); - if (err) - { - printf("Failed on uc_mem_map() with error returned: %u\n", err); - return err; - } - - // write machine code to be emulated to memory - err = uc_mem_write(uc, addr, loop_test_code, sizeof(loop_test_code)); - if( err ) - { - printf("Failed on uc_mem_write() with error returned: %u\n", err); - return err; - } - - // hook all instructions by having @begin > @end - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); - if( err ) - { - printf("Failed on uc_hook_add(code) with error returned: %u\n", err); - return err; - } - - // execute code - printf("---- Executing Code ----\n"); - err = uc_emu_start(uc, addr, addr + sizeof(loop_test_code), 0, 0); - if (err) - { - printf("Failed on uc_emu_start() with error returned %u: %s\n", - err, uc_strerror(err)); - return err; - } - - // done executing, print some reg values as a test - printf("---- Execution Complete ----\n\n"); - uc_reg_read(uc, UC_MIPS_REG_PC, &val); printf("pc is %X\n", val); - uc_reg_read(uc, UC_MIPS_REG_A0, &val); printf("a0 is %X\n", val); - - // free resources - uc_close(uc); - - if( test_passed_ok ) - printf("\n\nTEST PASSED!\n\n"); - else - printf("\n\nTEST FAILED!\n\n"); - - // dynamically free shared library -#ifdef DYNLOAD - uc_dyn_free(); -#endif - - return 0; -} - - From fc54007fab6962e85f1f00cdf5a9b756fb636fd8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 5 Dec 2015 10:55:28 +0700 Subject: [PATCH 09/40] msvc: code style --- bindings/msvc/unicorn_dynload.c | 209 ++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 90 deletions(-) diff --git a/bindings/msvc/unicorn_dynload.c b/bindings/msvc/unicorn_dynload.c index 7c63a823..fcf58ec9 100644 --- a/bindings/msvc/unicorn_dynload.c +++ b/bindings/msvc/unicorn_dynload.c @@ -95,127 +95,148 @@ static uc_mem_protect_t gp_uc_mem_protect = NULL; bool uc_dyn_load(const char* path, int flags) { - if( path == NULL ) - { - path = DYNLOAD_DEFPATH; - } - - if( g_dyn_handle ) - { - if( !uc_dyn_free() ) - return false; - } - - g_dyn_handle = DYNLOAD_LOADLIB(path, flags); - if( g_dyn_handle == NULL ) - { - //int err = DYNLOAD_GETERROR(); - //printf("Error loading %s: Last error is %X\n", path, err); - return false; - } - - gp_uc_version = (uc_version_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_version"); - gp_uc_arch_supported = (uc_arch_supported_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_arch_supported"); - gp_uc_open = (uc_open_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_open"); - gp_uc_close = (uc_close_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_close"); - gp_uc_errno = (uc_errno_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_errno"); - gp_uc_strerror = (uc_strerror_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_strerror"); - gp_uc_reg_write = (uc_reg_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_write"); - gp_uc_reg_read = (uc_reg_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_read"); - gp_uc_mem_write = (uc_mem_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_write"); - gp_uc_mem_read = (uc_mem_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_read"); - gp_uc_emu_start = (uc_emu_start_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_start"); - gp_uc_emu_stop = (uc_emu_stop_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_stop"); - gp_uc_hook_add = (uc_hook_add_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_add"); - gp_uc_hook_del = (uc_hook_del_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_del"); - gp_uc_mem_map = (uc_mem_map_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map"); - gp_uc_mem_unmap = (uc_mem_unmap_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_unmap"); - gp_uc_mem_protect = (uc_mem_protect_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_protect"); - return true; + if (path == NULL) { + path = DYNLOAD_DEFPATH; + } + + if (g_dyn_handle) { + if (!uc_dyn_free()) + return false; + } + + g_dyn_handle = DYNLOAD_LOADLIB(path, flags); + if (g_dyn_handle == NULL) { + //int err = DYNLOAD_GETERROR(); + //printf("Error loading %s: Last error is %X\n", path, err); + return false; + } + + gp_uc_version = (uc_version_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_version"); + gp_uc_arch_supported = (uc_arch_supported_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_arch_supported"); + gp_uc_open = (uc_open_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_open"); + gp_uc_close = (uc_close_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_close"); + gp_uc_errno = (uc_errno_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_errno"); + gp_uc_strerror = (uc_strerror_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_strerror"); + gp_uc_reg_write = (uc_reg_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_write"); + gp_uc_reg_read = (uc_reg_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_read"); + gp_uc_mem_write = (uc_mem_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_write"); + gp_uc_mem_read = (uc_mem_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_read"); + gp_uc_emu_start = (uc_emu_start_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_start"); + gp_uc_emu_stop = (uc_emu_stop_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_stop"); + gp_uc_hook_add = (uc_hook_add_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_add"); + gp_uc_hook_del = (uc_hook_del_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_del"); + gp_uc_mem_map = (uc_mem_map_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map"); + gp_uc_mem_unmap = (uc_mem_unmap_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_unmap"); + gp_uc_mem_protect = (uc_mem_protect_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_protect"); + return true; } bool uc_dyn_free(void) { - if( g_dyn_handle==NULL ) - return true; - - DYNLOAD_FREELIB(g_dyn_handle); - g_dyn_handle = NULL; - - gp_uc_version = NULL; - gp_uc_arch_supported = NULL; - gp_uc_open = NULL; - gp_uc_close = NULL; - gp_uc_errno = NULL; - gp_uc_strerror = NULL; - gp_uc_reg_write = NULL; - gp_uc_reg_read = NULL; - gp_uc_mem_write = NULL; - gp_uc_mem_read = NULL; - gp_uc_emu_start = NULL; - gp_uc_emu_stop = NULL; - gp_uc_hook_add = NULL; - gp_uc_hook_del = NULL; - gp_uc_mem_map = NULL; - gp_uc_mem_unmap = NULL; - gp_uc_mem_protect = NULL; - return true; + if (g_dyn_handle==NULL) + return true; + + DYNLOAD_FREELIB(g_dyn_handle); + g_dyn_handle = NULL; + + gp_uc_version = NULL; + gp_uc_arch_supported = NULL; + gp_uc_open = NULL; + gp_uc_close = NULL; + gp_uc_errno = NULL; + gp_uc_strerror = NULL; + gp_uc_reg_write = NULL; + gp_uc_reg_read = NULL; + gp_uc_mem_write = NULL; + gp_uc_mem_read = NULL; + gp_uc_emu_start = NULL; + gp_uc_emu_stop = NULL; + gp_uc_hook_add = NULL; + gp_uc_hook_del = NULL; + gp_uc_mem_map = NULL; + gp_uc_mem_unmap = NULL; + gp_uc_mem_protect = NULL; + return true; } unsigned int uc_version(unsigned int *major, unsigned int *minor) -{ return gp_uc_version(major, minor); } +{ + return gp_uc_version(major, minor); +} bool uc_arch_supported(uc_arch arch) -{ return gp_uc_arch_supported(arch); } +{ + return gp_uc_arch_supported(arch); +} uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc) -{ return gp_uc_open(arch, mode, uc); } +{ + return gp_uc_open(arch, mode, uc); +} uc_err uc_close(uc_engine *uc) -{ return gp_uc_close(uc); } +{ + return gp_uc_close(uc); +} uc_err uc_errno(uc_engine *uc) -{ return gp_uc_errno(uc); } +{ + return gp_uc_errno(uc); +} const char *uc_strerror(uc_err code) -{ return gp_uc_strerror(code); } +{ + return gp_uc_strerror(code); +} uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) -{ return gp_uc_reg_write(uc, regid, value); } +{ + return gp_uc_reg_write(uc, regid, value); +} uc_err uc_reg_read(uc_engine *uc, int regid, void *value) -{ return gp_uc_reg_read(uc, regid, value); } +{ + return gp_uc_reg_read(uc, regid, value); +} uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size) -{ return gp_uc_mem_write(uc, address, bytes, size); } +{ + return gp_uc_mem_write(uc, address, bytes, size); +} uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size) -{ return gp_uc_mem_read(uc, address, bytes, size); } +{ + return gp_uc_mem_read(uc, address, bytes, size); +} uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) -{ return gp_uc_emu_start(uc, begin, until, timeout, count); } +{ + return gp_uc_emu_start(uc, begin, until, timeout, count); +} uc_err uc_emu_stop(uc_engine *uc) -{ return gp_uc_emu_stop(uc); } +{ + return gp_uc_emu_stop(uc); +} uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...) { - va_list valist; + va_list valist; uc_err ret = UC_ERR_OK; - int id; + int id; uint64_t begin, end; - va_start(valist, user_data); - - switch(type) { + va_start(valist, user_data); + + switch(type) { default: break; case UC_HOOK_INTR: - // 0 extra args - ret = gp_uc_hook_add(uc, hh, type, callback, user_data); - break; - case UC_HOOK_INSN: - // 1 extra arg + // 0 extra args + ret = gp_uc_hook_add(uc, hh, type, callback, user_data); + break; + case UC_HOOK_INSN: + // 1 extra arg id = va_arg(valist, int); ret = gp_uc_hook_add(uc, hh, type, callback, user_data, id); break; @@ -224,26 +245,34 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *u case UC_HOOK_MEM_READ: case UC_HOOK_MEM_WRITE: case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE: - // 2 extra arg + // 2 extra arg begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end); break; } - va_end(valist); - return ret; + va_end(valist); + return ret; } uc_err uc_hook_del(uc_engine *uc, uc_hook hh) -{ return gp_uc_hook_del(uc, hh); } +{ + return gp_uc_hook_del(uc, hh); +} uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) -{ return gp_uc_mem_map(uc, address, size, perms); } +{ + return gp_uc_mem_map(uc, address, size, perms); +} uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size) -{ return gp_uc_mem_unmap(uc, address, size); } +{ + return gp_uc_mem_unmap(uc, address, size); +} uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) -{ return gp_uc_mem_protect(uc, address, size, perms); } +{ + return gp_uc_mem_protect(uc, address, size, perms); +} From c37b2582d7bcb37bfe00b9ae779a59fe4f54fcc4 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 5 Dec 2015 11:20:22 +0700 Subject: [PATCH 10/40] modify header guard of unicorn_dynload.h for consistency --- include/unicorn/unicorn_dynload.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/unicorn/unicorn_dynload.h b/include/unicorn/unicorn_dynload.h index 73014d92..138ad08e 100644 --- a/include/unicorn/unicorn_dynload.h +++ b/include/unicorn/unicorn_dynload.h @@ -26,8 +26,8 @@ // Zak Escano - November 2015 // -#ifndef _UNICORN_DYNLOAD_H_ -#define _UNICORN_DYNLOAD_H_ +#ifndef UNICORN_DYNLOAD_H +#define UNICORN_DYNLOAD_H // Undefine shared here so that functions aren't defined as: "__declspec(dllexport)" #ifdef UNICORN_SHARED @@ -63,5 +63,5 @@ bool uc_dyn_free(void); } #endif -#endif // _UNICORN_DYNLOAD_H_ +#endif // UNICORN_DYNLOAD_H From 638ff7a3f52e031593fc3ef85c20301d9afd2572 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 5 Dec 2015 11:24:56 -0800 Subject: [PATCH 11/40] Go binding: add mem_protect wrapper --- bindings/go/unicorn/unicorn.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 2cabac74..46802f46 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -28,6 +28,7 @@ func errReturn(err C.uc_err) error { type Unicorn interface { MemMap(addr, size uint64) error MemMapProt(addr, size uint64, prot int) error + MemProtect(addr, size uint64, prot int) error MemUnmap(addr, size uint64) error MemRead(addr, size uint64) ([]byte, error) MemReadInto(dst []byte, addr uint64) error @@ -128,6 +129,10 @@ func (u *uc) MemMap(addr, size uint64) error { return u.MemMapProt(addr, size, PROT_ALL) } +func (u *uc) MemProtect(addr, size uint64, prot int) error { + return errReturn(C.uc_mem_protect(u.handle, C.uint64_t(addr), C.size_t(size), C.uint32_t(prot))) +} + func (u *uc) MemUnmap(addr, size uint64) error { return errReturn(C.uc_mem_unmap(u.handle, C.uint64_t(addr), C.size_t(size))) } From c5c13e110abf0f5ab79c8e231efae28abd94e18c Mon Sep 17 00:00:00 2001 From: xorstream Date: Tue, 8 Dec 2015 18:21:32 +1100 Subject: [PATCH 12/40] Added samples projects for MSVC binding. Added MSVC support to unicorn samples. --- .gitignore | 3 + bindings/README | 3 +- bindings/msvc/README.TXT | 118 ++++++++++++- bindings/msvc/samples/dynload/dynload.vcxproj | 167 ++++++++++++++++++ .../samples/dynload/dynload.vcxproj.filters | 7 + bindings/msvc/samples/main.c | 134 ++++++++++++++ bindings/msvc/samples/samples.sln | 36 ++++ bindings/msvc/samples/staload/staload.vcxproj | 165 +++++++++++++++++ .../samples/staload/staload.vcxproj.filters | 6 + bindings/msvc/unicorn_dynload.c | 4 + samples/mem_apis.c | 49 ++++- samples/msvc/README.TXT | 141 +++++++++++++++ samples/msvc/msvc.sln | 96 ++++++++++ samples/sample_arm.c | 42 ++++- samples/sample_arm64.c | 42 ++++- samples/sample_m68k.c | 40 ++++- samples/sample_mips.c | 42 ++++- samples/sample_sparc.c | 42 ++++- samples/sample_x86.c | 47 ++++- samples/shellcode.c | 49 ++++- 20 files changed, 1199 insertions(+), 34 deletions(-) create mode 100644 bindings/msvc/samples/dynload/dynload.vcxproj create mode 100644 bindings/msvc/samples/dynload/dynload.vcxproj.filters create mode 100644 bindings/msvc/samples/main.c create mode 100644 bindings/msvc/samples/samples.sln create mode 100644 bindings/msvc/samples/staload/staload.vcxproj create mode 100644 bindings/msvc/samples/staload/staload.vcxproj.filters create mode 100644 samples/msvc/README.TXT create mode 100644 samples/msvc/msvc.sln diff --git a/.gitignore b/.gitignore index e7c8f34b..247b688e 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,8 @@ sparc_jump_to_zero ## files generated by popular Visual Studio add-ons. # User-specific files +*.opensdf +*.sdf *.suo *.user *.sln.docstates @@ -137,6 +139,7 @@ sparc_jump_to_zero [Dd]ebug/ [Rr]elease/ x64/ +Win32/ build/ [Bb]in/ [Oo]bj/ diff --git a/bindings/README b/bindings/README index d4145ea9..c3abec91 100644 --- a/bindings/README +++ b/bindings/README @@ -1,4 +1,4 @@ -This directory contains bindings & test code for Python, Java, Go and .NET. +This directory contains bindings & test code for Python, Java, Go, .NET and MSVC. See /README or /README.TXT for how to install each binding. The following bindings are contributed by community. @@ -6,6 +6,7 @@ The following bindings are contributed by community. - Java binding: by Chris Eagle. - Go binding: by Ryan Hileman. - .NET binding: by Antonio Parata. +- MSVC binding: by Zak Escano More bindings created & maintained externally by community are available as follows. diff --git a/bindings/msvc/README.TXT b/bindings/msvc/README.TXT index 7d2a9b31..29bc2508 100644 --- a/bindings/msvc/README.TXT +++ b/bindings/msvc/README.TXT @@ -1,3 +1,7 @@ + + +:: Overview + This documentation explains how to use Unicorn with Microsoft Visual C++ (MSVC). This will not build the Unicorn Engine itself, it just allows you to use the prebuilt Windows binaries when writing projects in Microsoft Visual C++. @@ -8,17 +12,19 @@ heading on the following page. Be sure to use the 32bit package when making build 64bit applications. http://www.unicorn-engine.org/download/ - - -It is not possible to use the prebuilt static Unicorn library, unicorn.lib, +It is not possible to use the prebuilt static Unicorn library "unicorn.lib" with Microsoft Visual C++ because it will complain about a bunch of missing functions, variables etc. -We therefore use the prebuilt dynamic Unicorn library, unicorn.dll. +We therefore use the prebuilt dynamic Unicorn library "unicorn.dll". There are two ways to use this with your Microsoft Visual C++ project: 1) By dynamically linking the dll into your project. 2) By statically linking the dll into your project. +There are pre-prepared sample projects that use each method, but in the event +you wish to set up your own projects there are details to do so below. + + :: 1) Dynamic Linking @@ -49,6 +55,7 @@ Now build your application as normal. + :: 2) Static Linking To perform static linking of unicorn.dll, you need to first generate some @@ -75,3 +82,106 @@ Or by adding "unicorn_staload.lib" to your project in: Configuration Properties -> C/C++ -> Linker -> Input -> Additional Dependencies + + +:: Notes about Visual Studio versions. + +These solution and project files were created using Visual Studio 2012. +They should be able to be opened in newer versions of Visual Studio. +For older versions of Visual Studio you could try a little hack of changing +the line in the solution file "samples.sln" from: + Microsoft Visual Studio Solution File, Format Version 12.00 +to + Microsoft Visual Studio Solution File, Format Version 11.00 + +Or whatever version number your Visual Studio version uses. +(Hint: Check an existing solution file you have created with your version + of Visual Studio to know what this value is expected to be.) + +Also note that all instructions below are for Visual Studio 2012. So if you +are using a different version then the settings may be located in different +areas or have different names. + + + + +:: Building the pre-prepared sample projects + +Some sample projects have been included in the bindings\msvc\samples directory. +The solution file in this directory is "samples.sln". +This was created with Visual Studio 2012 and once opened contains 2 projects +"dynload" and "staload". + +The "dynload" project is an example of a project that uses dynamic linking. +The "satload" project is an example of a project that uses static linking. + +Both projects have 32bit (win32) and 64bit (x64) target platforms. +The 32bit platform (win32) will create a 32bit app that can run on either +32bit or 64bit Windows. The 64bit platform (x64) can only run on 64bit Windows. + +All variants can be built at once by using the batch build function: +Go to "Build -> Batch Build" and tick all checkboxes, or at least the ones +that you wish to build. Then click on the Build or Rebuild button. +Note that when building the "staload" projects you must first have built +the static import libraries as mentioned above. + + + + +:: Running the pre-prepared sample projects + +When running the samples they will need to be able to load the unicorn dlls. + +The unicorn dlls required for 32bit apps are: + libgcc_s_dw2-1.dll + libglib-2.0-0.dll + libiconv-2.dll + libintl-8.dll + libwinpthread-1.dll + unicorn.dll + +The unicorn dlls required for 64bit apps are: + libgcc_s_seh-1.dll + libglib-2.0-0.dll + libiconv-2.dll + libintl-8.dll + libwinpthread-1.dll + unicorn.dll + +Note that while some of the 32bit and 64bit dlls have the same filename, +they are internally different in that they are either 32bit or 64bit files +themselves. So you will have to have separate directories to store them in. +I suggest using directory names such as "unicorn32" and "unicorn64" when +installing the prebuilt windows binaries. This will make it easy to +differentiate between them. + +If running the sample exe files from the command line or from Windows Explorer +then you need ensure that the exe file is in the same directory as either the +32bit or 64bit set of dlls. + +To run the samples from inside Visual Studio so that you can debug them or just +easily test various changes you should set the working directory to point to a +directory that contains all of the dlls. Assuming you are running a 32bit app +and have the 32bit unicorn dlls in the directory "C:\unicorn32" then do: + +1) Go to the Solution Explorer window in Visual Studio. +You can use "View -> Solution Explorer" to get to it. + +2) Highlight one or more projects that you want to run/debu from in +Visual Studio. Use hold control when selecting to select multiples, +or hold Shift to select ranges of projects. + +3) Right click on the selected projects and go to Properties. + +4) Now go to "Configuration Properties -> Debugging -> Working Directory". +Change the value for this to "C:\unicorn32". +You will need to change this for both Debug and Release configurations. +You can change between configurations on the top left of the Property Pages +dialog box that you are currently on. + +6) Click OK when done and then you are ready to run or debug the projects. +Do "Debug -> Start Debugging" or press F5 to debug the current project. +Do "Debug -> Start Without Debugging" or press Ctrl+F5 to run the current project. +You can change the current project by right clicking on a project in +Solution Explorer and selecting "Set as StartUp Project" + diff --git a/bindings/msvc/samples/dynload/dynload.vcxproj b/bindings/msvc/samples/dynload/dynload.vcxproj new file mode 100644 index 00000000..a73f04fc --- /dev/null +++ b/bindings/msvc/samples/dynload/dynload.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB} + Win32Proj + dynload + dynload + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + MultiThreadedDebug + ..\..;..\..\..\..\include + + + Console + true + ..\.. + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + MultiThreadedDebug + ..\..;..\..\..\..\include + + + Console + true + ..\.. + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + MultiThreaded + ..\..;..\..\..\..\include + + + Console + true + true + true + ..\.. + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + MultiThreaded + ..\..;..\..\..\..\include + + + Console + true + true + true + ..\.. + + + + + + + + + + \ No newline at end of file diff --git a/bindings/msvc/samples/dynload/dynload.vcxproj.filters b/bindings/msvc/samples/dynload/dynload.vcxproj.filters new file mode 100644 index 00000000..9dcdb716 --- /dev/null +++ b/bindings/msvc/samples/dynload/dynload.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/bindings/msvc/samples/main.c b/bindings/msvc/samples/main.c new file mode 100644 index 00000000..87cbbb55 --- /dev/null +++ b/bindings/msvc/samples/main.c @@ -0,0 +1,134 @@ +// +// Simple code as an example for building apps with MSVC++ using the Unicorn Engine. +// +// Zak Escano - December 2015 +// + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// Test MIPS little endian code. +// It should loop 3 times before ending. +const uint64_t addr = 0x100000; +const unsigned char loop_test_code[] = { + 0x02,0x00,0x04,0x24, // 100000: li $a0, 2 + // loop1 + 0x00,0x00,0x00,0x00, // 100004: nop + 0xFE,0xFF,0x80,0x14, // 100008: bnez $a0, loop1 + 0xFF,0xFF,0x84,0x24, // 10000C: addiu $a0, -1 +}; +bool test_passed_ok = false; +int loop_count = 0; + + +static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + if( address == 0x10000C ) + test_passed_ok = true; + if( address == 0x100004 ) + { + printf("\nloop %d:\n", loop_count); + loop_count++; + } + printf("Code: %llX\n", address); +} + + +int main(int argc, char **argv, char **envp) +{ + uc_engine *uc; + uc_err err; + uc_hook hhc; + uint32_t val; + + // dynamically load shared library +#ifdef DYNLOAD + if( !uc_dyn_load(NULL, 0) ) + { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // Initialize emulator in MIPS 32bit little endian mode + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); + if (err) + { + printf("Failed on uc_open() with error returned: %u\n", err); + return err; + } + + // map in a page of mem + err = uc_mem_map(uc, addr, 0x1000, UC_PROT_ALL); + if (err) + { + printf("Failed on uc_mem_map() with error returned: %u\n", err); + return err; + } + + // write machine code to be emulated to memory + err = uc_mem_write(uc, addr, loop_test_code, sizeof(loop_test_code)); + if( err ) + { + printf("Failed on uc_mem_write() with error returned: %u\n", err); + return err; + } + + // hook all instructions by having @begin > @end + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + if( err ) + { + printf("Failed on uc_hook_add(code) with error returned: %u\n", err); + return err; + } + + // execute code + printf("---- Executing Code ----\n"); + err = uc_emu_start(uc, addr, addr + sizeof(loop_test_code), 0, 0); + if (err) + { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + return err; + } + + // done executing, print some reg values as a test + printf("---- Execution Complete ----\n\n"); + uc_reg_read(uc, UC_MIPS_REG_PC, &val); printf("pc is %X\n", val); + uc_reg_read(uc, UC_MIPS_REG_A0, &val); printf("a0 is %X\n", val); + + // free resources + uc_close(uc); + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} + diff --git a/bindings/msvc/samples/samples.sln b/bindings/msvc/samples/samples.sln new file mode 100644 index 00000000..0594260e --- /dev/null +++ b/bindings/msvc/samples/samples.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dynload", "dynload\dynload.vcxproj", "{EBBC5CEA-1237-4E20-9E38-E610D3C529EB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "staload", "staload\staload.vcxproj", "{85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB}.Debug|Win32.ActiveCfg = Debug|Win32 + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB}.Debug|Win32.Build.0 = Debug|Win32 + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB}.Debug|x64.ActiveCfg = Debug|x64 + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB}.Debug|x64.Build.0 = Debug|x64 + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB}.Release|Win32.ActiveCfg = Release|Win32 + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB}.Release|Win32.Build.0 = Release|Win32 + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB}.Release|x64.ActiveCfg = Release|x64 + {EBBC5CEA-1237-4E20-9E38-E610D3C529EB}.Release|x64.Build.0 = Release|x64 + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}.Debug|Win32.ActiveCfg = Debug|Win32 + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}.Debug|Win32.Build.0 = Debug|Win32 + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}.Debug|x64.ActiveCfg = Debug|x64 + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}.Debug|x64.Build.0 = Debug|x64 + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}.Release|Win32.ActiveCfg = Release|Win32 + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}.Release|Win32.Build.0 = Release|Win32 + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}.Release|x64.ActiveCfg = Release|x64 + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/bindings/msvc/samples/staload/staload.vcxproj b/bindings/msvc/samples/staload/staload.vcxproj new file mode 100644 index 00000000..dd9ba821 --- /dev/null +++ b/bindings/msvc/samples/staload/staload.vcxproj @@ -0,0 +1,165 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {85FFC5E9-CC3D-41F6-8970-092FAC8E5E39} + Win32Proj + staload + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + ..\..;..\..\..\..\include + + + Console + true + ..\.. + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + ..\..;..\..\..\..\include + + + Console + true + ..\.. + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + ..\..;..\..\..\..\include + + + Console + true + true + true + ..\.. + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + ..\..;..\..\..\..\include + + + Console + true + true + true + ..\.. + + + + + + + + + \ No newline at end of file diff --git a/bindings/msvc/samples/staload/staload.vcxproj.filters b/bindings/msvc/samples/staload/staload.vcxproj.filters new file mode 100644 index 00000000..b2dc6e7d --- /dev/null +++ b/bindings/msvc/samples/staload/staload.vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/bindings/msvc/unicorn_dynload.c b/bindings/msvc/unicorn_dynload.c index fcf58ec9..ae136c17 100644 --- a/bindings/msvc/unicorn_dynload.c +++ b/bindings/msvc/unicorn_dynload.c @@ -26,6 +26,9 @@ // Zak Escano - November 2015 // +// Only use this if DYNLOAD is set in preprocessor definitions +#ifdef DYNLOAD + // This is to detect whether we are loading a dll in windows or a so in linux. #ifdef _MSC_VER #define WINDOWS_DLL 1 @@ -276,3 +279,4 @@ uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t per return gp_uc_mem_protect(uc, address, size, perms); } +#endif // DYNLOAD diff --git a/samples/mem_apis.c b/samples/mem_apis.c index 8ec4c715..b9356aff 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -19,14 +19,36 @@ */ #define __STDC_FORMAT_MACROS -#include -#include + +// windows specific includes +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific includes +#else // _MSC_VER #include +#include +#include +#endif // _MSC_VER + +// common includes +#include #include #include #include -#include static int insts_executed; @@ -337,9 +359,26 @@ static void unmap_test() int main(int argc, char **argv, char **envp) { - nx_test(); + // dynamically load shared library +#ifdef DYNLOAD + if( !uc_dyn_load(NULL, 0) ) + { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + nx_test(); perms_test(); unmap_test(); - return 0; + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; } diff --git a/samples/msvc/README.TXT b/samples/msvc/README.TXT new file mode 100644 index 00000000..ea431d55 --- /dev/null +++ b/samples/msvc/README.TXT @@ -0,0 +1,141 @@ + + +:: Notes about Visual Studio versions. + +These solution and project files were created using Visual Studio 2012. +They should be able to be opened in newer versions of Visual Studio. +For older versions of Visual Studio you could try a little hack of changing +the line in the solution file "msvc.sln" from: + Microsoft Visual Studio Solution File, Format Version 12.00 +to + Microsoft Visual Studio Solution File, Format Version 11.00 + +Or whatever version number your Visual Studio version uses. +(Hint: Check an existing solution file you have created with your version + of Visual Studio to know what this value is expected to be.) + +Also note that all instructions below are for Visual Studio 2012. So if you +are using a different version then the settings may be located in different +areas or have different names. + + + + +:: Notes about the building the sample projects + +The projects have 32bit (win32) and 64bit (x64) target platforms. +The 32bit platform (win32) will create a 32bit app that can run on either +32bit or 64bit Windows. The 64bit platform (x64) can only run on 64bit Windows. + +All variants can be built at once by using the batch build function: +Go to "Build -> Batch Build" and tick all checkboxes, or at least the ones +that you wish to build. Then click on the Build or Rebuild button. +Note that when building the "staload" projects you must first have built +the static import libraries as mentioned above. + +The samples projects all come preset to be built using dynamic loading of +the unicorn dlls. If you wish to use static loading of the unicorn dlls +then you need see the next section. + + + + +:: Using static linking of dlls + +It is possible to perform static linking of the unicorn dlls which will +load and import the dlls when the exe file itself is loaded. Personally +I prefer dynamic loading in which you load the dlls in your program code +at runtime. This way if it fails you have the opportunity to display a +more meaning error message. Dynamic loading also gives you more +advanced options for where to load the dll files from. + +If you do wish to do static linking of dlls then the following changes +need to be made to each project. Note that multiple projects can be +highlighted and have their settings changed at the one time. + +1) First ensure the static linking library has been built. +Run bindings\msvc\make_staload.bat to build these. +You may need to first alter this batch file to point to the correct +location of your "vcvars32.bat" file. +If successful you will now have the files "bindings\msvc\unicorn_staload.lib" +and "bindings\msvc\unicorn_staload64.lib". + +2) Go to the Solution Explorer window in Visual Studio. +You can use "View -> Solution Explorer" to get to it. + +3) Highlight one or more projects that you want to change to use +static linking. Use hold control when selecting to select multiples, +or hold Shift to select ranges of projects. + +4) Right click on the selected projects and go to Properties. + +5) Now go to "Configuration Properties -> C/C++ -> Preprocessor -> +Preprocessor Definitions". Remove the DYNLOAD entry and its preceeding +semi-colon. You will need to remove DYNLOAD for both Debug and Release +configurations. You can change between configurations on the top left +of the Property Pages dialog box that you are currently on. + +6) Click OK when done and then rebuild the altered projects. +Be sure to Rebuild and not just Build to ensure that the change you +made are used. + + + + +:: Running the samples + +When running the samples they will need to be able to load the unicorn dlls. + +The unicorn dlls required for 32bit apps are: + libgcc_s_dw2-1.dll + libglib-2.0-0.dll + libiconv-2.dll + libintl-8.dll + libwinpthread-1.dll + unicorn.dll + +The unicorn dlls required for 64bit apps are: + libgcc_s_seh-1.dll + libglib-2.0-0.dll + libiconv-2.dll + libintl-8.dll + libwinpthread-1.dll + unicorn.dll + +Note that while some of the 32bit and 64bit dlls have the same filename, +they are internally different in that they are either 32bit or 64bit files +themselves. So you will have to have separate directories to store them in. +I suggest using directory names such as "unicorn32" and "unicorn64" when +installing the prebuilt windows binaries. This will make it easy to +differentiate between them. + +If running the sample exe files from the command line or from Windows Explorer +then you need ensure that the exe file is in the same directory as either the +32bit or 64bit set of dlls. + +To run the samples from inside Visual Studio so that you can debug them or just +easily test various changes you should set the working directory to point to a +directory that contains all of the dlls. Assuming you are running a 32bit app +and have the 32bit unicorn dlls in the directory "C:\unicorn32" then do: + +1) Go to the Solution Explorer window in Visual Studio. +You can use "View -> Solution Explorer" to get to it. + +2) Highlight one or more projects that you want to run/debu from in +Visual Studio. Use hold control when selecting to select multiples, +or hold Shift to select ranges of projects. + +3) Right click on the selected projects and go to Properties. + +4) Now go to "Configuration Properties -> Debugging -> Working Directory". +Change the value for this to "C:\unicorn32". +You will need to change this for both Debug and Release configurations. +You can change between configurations on the top left of the Property Pages +dialog box that you are currently on. + +6) Click OK when done and then you are ready to run or debug the projects. +Do "Debug -> Start Debugging" or press F5 to debug the current project. +Do "Debug -> Start Without Debugging" or press Ctrl+F5 to run the current project. +You can change the current project by right clicking on a project in +Solution Explorer and selecting "Set as StartUp Project" + diff --git a/samples/msvc/msvc.sln b/samples/msvc/msvc.sln new file mode 100644 index 00000000..02ce0ae6 --- /dev/null +++ b/samples/msvc/msvc.sln @@ -0,0 +1,96 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mem_apis", "mem_apis\mem_apis.vcxproj", "{ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_arm", "sample_arm\sample_arm.vcxproj", "{8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_arm64", "sample_arm64\sample_arm64.vcxproj", "{43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_m68k", "sample_m68k\sample_m68k.vcxproj", "{39ABA118-6289-43D6-AB6C-8B3AB3CB9390}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_mips", "sample_mips\sample_mips.vcxproj", "{5E004A76-1625-44F1-A1EA-64C4FD15F642}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_x86", "sample_x86\sample_x86.vcxproj", "{F8AD989E-D273-42DA-80A6-B6466EB134CA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_sparc", "sample_sparc\sample_sparc.vcxproj", "{2906001D-9B80-4400-8B3A-4445CDAED54F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shellcode", "shellcode\shellcode.vcxproj", "{4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}.Debug|Win32.ActiveCfg = Debug|Win32 + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}.Debug|Win32.Build.0 = Debug|Win32 + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}.Debug|x64.ActiveCfg = Debug|x64 + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}.Debug|x64.Build.0 = Debug|x64 + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}.Release|Win32.ActiveCfg = Release|Win32 + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}.Release|Win32.Build.0 = Release|Win32 + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}.Release|x64.ActiveCfg = Release|x64 + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}.Release|x64.Build.0 = Release|x64 + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}.Debug|Win32.Build.0 = Debug|Win32 + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}.Debug|x64.ActiveCfg = Debug|x64 + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}.Debug|x64.Build.0 = Debug|x64 + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}.Release|Win32.ActiveCfg = Release|Win32 + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}.Release|Win32.Build.0 = Release|Win32 + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}.Release|x64.ActiveCfg = Release|x64 + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}.Release|x64.Build.0 = Release|x64 + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}.Debug|Win32.ActiveCfg = Debug|Win32 + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}.Debug|Win32.Build.0 = Debug|Win32 + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}.Debug|x64.ActiveCfg = Debug|x64 + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}.Debug|x64.Build.0 = Debug|x64 + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}.Release|Win32.ActiveCfg = Release|Win32 + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}.Release|Win32.Build.0 = Release|Win32 + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}.Release|x64.ActiveCfg = Release|x64 + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}.Release|x64.Build.0 = Release|x64 + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390}.Debug|Win32.ActiveCfg = Debug|Win32 + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390}.Debug|Win32.Build.0 = Debug|Win32 + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390}.Debug|x64.ActiveCfg = Debug|x64 + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390}.Debug|x64.Build.0 = Debug|x64 + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390}.Release|Win32.ActiveCfg = Release|Win32 + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390}.Release|Win32.Build.0 = Release|Win32 + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390}.Release|x64.ActiveCfg = Release|x64 + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390}.Release|x64.Build.0 = Release|x64 + {5E004A76-1625-44F1-A1EA-64C4FD15F642}.Debug|Win32.ActiveCfg = Debug|Win32 + {5E004A76-1625-44F1-A1EA-64C4FD15F642}.Debug|Win32.Build.0 = Debug|Win32 + {5E004A76-1625-44F1-A1EA-64C4FD15F642}.Debug|x64.ActiveCfg = Debug|x64 + {5E004A76-1625-44F1-A1EA-64C4FD15F642}.Debug|x64.Build.0 = Debug|x64 + {5E004A76-1625-44F1-A1EA-64C4FD15F642}.Release|Win32.ActiveCfg = Release|Win32 + {5E004A76-1625-44F1-A1EA-64C4FD15F642}.Release|Win32.Build.0 = Release|Win32 + {5E004A76-1625-44F1-A1EA-64C4FD15F642}.Release|x64.ActiveCfg = Release|x64 + {5E004A76-1625-44F1-A1EA-64C4FD15F642}.Release|x64.Build.0 = Release|x64 + {F8AD989E-D273-42DA-80A6-B6466EB134CA}.Debug|Win32.ActiveCfg = Debug|Win32 + {F8AD989E-D273-42DA-80A6-B6466EB134CA}.Debug|Win32.Build.0 = Debug|Win32 + {F8AD989E-D273-42DA-80A6-B6466EB134CA}.Debug|x64.ActiveCfg = Debug|x64 + {F8AD989E-D273-42DA-80A6-B6466EB134CA}.Debug|x64.Build.0 = Debug|x64 + {F8AD989E-D273-42DA-80A6-B6466EB134CA}.Release|Win32.ActiveCfg = Release|Win32 + {F8AD989E-D273-42DA-80A6-B6466EB134CA}.Release|Win32.Build.0 = Release|Win32 + {F8AD989E-D273-42DA-80A6-B6466EB134CA}.Release|x64.ActiveCfg = Release|x64 + {F8AD989E-D273-42DA-80A6-B6466EB134CA}.Release|x64.Build.0 = Release|x64 + {2906001D-9B80-4400-8B3A-4445CDAED54F}.Debug|Win32.ActiveCfg = Debug|Win32 + {2906001D-9B80-4400-8B3A-4445CDAED54F}.Debug|Win32.Build.0 = Debug|Win32 + {2906001D-9B80-4400-8B3A-4445CDAED54F}.Debug|x64.ActiveCfg = Debug|x64 + {2906001D-9B80-4400-8B3A-4445CDAED54F}.Debug|x64.Build.0 = Debug|x64 + {2906001D-9B80-4400-8B3A-4445CDAED54F}.Release|Win32.ActiveCfg = Release|Win32 + {2906001D-9B80-4400-8B3A-4445CDAED54F}.Release|Win32.Build.0 = Release|Win32 + {2906001D-9B80-4400-8B3A-4445CDAED54F}.Release|x64.ActiveCfg = Release|x64 + {2906001D-9B80-4400-8B3A-4445CDAED54F}.Release|x64.Build.0 = Release|x64 + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}.Debug|Win32.ActiveCfg = Debug|Win32 + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}.Debug|Win32.Build.0 = Debug|Win32 + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}.Debug|x64.ActiveCfg = Debug|x64 + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}.Debug|x64.Build.0 = Debug|x64 + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}.Release|Win32.ActiveCfg = Release|Win32 + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}.Release|Win32.Build.0 = Release|Win32 + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}.Release|x64.ActiveCfg = Release|x64 + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 48f3ebf2..96d031f9 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -3,9 +3,28 @@ /* Sample code to demonstrate how to emulate ARM code */ -#include - +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD #include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER // code to be emulated @@ -132,9 +151,26 @@ static void test_thumb(void) int main(int argc, char **argv, char **envp) { - test_arm(); + // dynamically load shared library +#ifdef DYNLOAD + if( !uc_dyn_load(NULL, 0) ) + { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + test_arm(); printf("==========================\n"); test_thumb(); + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + return 0; } diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index 6b0ee8db..b1e85cf2 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -3,9 +3,28 @@ /* Sample code to demonstrate how to emulate ARM64 code */ -#include - +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD #include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER // code to be emulated @@ -79,7 +98,24 @@ static void test_arm64(void) int main(int argc, char **argv, char **envp) { - test_arm64(); + // dynamically load shared library +#ifdef DYNLOAD + if( !uc_dyn_load(NULL, 0) ) + { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + test_arm64(); + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + return 0; } diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index cfebd8e0..204e503d 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -3,8 +3,28 @@ /* Sample code to demonstrate how to emulate m68k code */ +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include #include #include +#endif // _MSC_VER // code to be emulated #define M68K_CODE "\x76\xed" // movq #-19, %d3 @@ -140,6 +160,24 @@ static void test_m68k(void) int main(int argc, char **argv, char **envp) { - test_m68k(); + // dynamically load shared library +#ifdef DYNLOAD + if( !uc_dyn_load(NULL, 0) ) + { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + test_m68k(); + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + return 0; } diff --git a/samples/sample_mips.c b/samples/sample_mips.c index 60331737..578c688e 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -3,9 +3,28 @@ /* Sample code to demonstrate how to emulate Mips code (big endian) */ -#include - +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD #include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER // code to be emulated @@ -126,8 +145,25 @@ static void test_mips_el(void) int main(int argc, char **argv, char **envp) { - test_mips_eb(); + // dynamically load shared library +#ifdef DYNLOAD + if( !uc_dyn_load(NULL, 0) ) + { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + test_mips_eb(); test_mips_el(); + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + return 0; } diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index 45c185a5..1445e9d7 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -3,9 +3,28 @@ /* Sample code to demonstrate how to emulate Sparc code */ -#include - +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD #include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER // code to be emulated @@ -81,7 +100,24 @@ static void test_sparc(void) int main(int argc, char **argv, char **envp) { - test_sparc(); + // dynamically load shared library +#ifdef DYNLOAD + if( !uc_dyn_load(NULL, 0) ) + { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + test_sparc(); + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + return 0; } diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 5f33833f..fe8b1b5f 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -3,11 +3,31 @@ /* Sample code to demonstrate how to emulate X86 code */ -#include -#include -#include - +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD #include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + +// common includes +#include // code to be emulated @@ -792,7 +812,19 @@ static void test_x86_16(void) int main(int argc, char **argv, char **envp) { - if (argc == 2) { + // dynamically load shared library +#ifdef DYNLOAD + if( !uc_dyn_load(NULL, 0) ) + { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + if (argc == 2) { if (!strcmp(argv[1], "-32")) { test_i386(); test_i386_inout(); @@ -823,5 +855,10 @@ int main(int argc, char **argv, char **envp) printf("Syntax: %s <-16|-32|-64>\n", argv[0]); } + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + return 0; } diff --git a/samples/shellcode.c b/samples/shellcode.c index 5377ece9..234b361f 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -3,11 +3,31 @@ /* Sample code to trace code with Linux code with syscall */ -#include -#include -#include - +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD #include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + +// common includes +#include // code to be emulated @@ -32,7 +52,7 @@ static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user size = MIN(sizeof(tmp), size); if (!uc_mem_read(uc, address, tmp, size)) { - int i; + uint32_t i; for (i=0; i\n", argv[0]); } + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + return 0; } From 514715f7d51e2f8ab8cd6d25d158f61d0c2332d3 Mon Sep 17 00:00:00 2001 From: xorstream Date: Tue, 8 Dec 2015 19:26:53 +1100 Subject: [PATCH 13/40] Added previously ignored project dirs to MSVC support for unicorn samples. --- samples/msvc/msvc.sln | 16 +- samples/msvc/msvc_mem_apis/mem_apis.vcxproj | 167 ++++++++++++++++++ .../msvc_mem_apis/mem_apis.vcxproj.filters | 7 + .../msvc/msvc_sample_arm/sample_arm.vcxproj | 166 +++++++++++++++++ .../sample_arm.vcxproj.filters | 7 + .../msvc_sample_arm64/sample_arm64.vcxproj | 166 +++++++++++++++++ .../sample_arm64.vcxproj.filters | 7 + .../msvc/msvc_sample_m68k/sample_m68k.vcxproj | 166 +++++++++++++++++ .../sample_m68k.vcxproj.filters | 7 + .../msvc/msvc_sample_mips/sample_mips.vcxproj | 167 ++++++++++++++++++ .../sample_mips.vcxproj.filters | 7 + .../msvc_sample_sparc/sample_sparc.vcxproj | 166 +++++++++++++++++ .../sample_sparc.vcxproj.filters | 7 + .../msvc/msvc_sample_x86/sample_x86.vcxproj | 166 +++++++++++++++++ .../sample_x86.vcxproj.filters | 7 + samples/msvc/msvc_shellcode/shellcode.vcxproj | 166 +++++++++++++++++ .../msvc_shellcode/shellcode.vcxproj.filters | 7 + 17 files changed, 1394 insertions(+), 8 deletions(-) create mode 100644 samples/msvc/msvc_mem_apis/mem_apis.vcxproj create mode 100644 samples/msvc/msvc_mem_apis/mem_apis.vcxproj.filters create mode 100644 samples/msvc/msvc_sample_arm/sample_arm.vcxproj create mode 100644 samples/msvc/msvc_sample_arm/sample_arm.vcxproj.filters create mode 100644 samples/msvc/msvc_sample_arm64/sample_arm64.vcxproj create mode 100644 samples/msvc/msvc_sample_arm64/sample_arm64.vcxproj.filters create mode 100644 samples/msvc/msvc_sample_m68k/sample_m68k.vcxproj create mode 100644 samples/msvc/msvc_sample_m68k/sample_m68k.vcxproj.filters create mode 100644 samples/msvc/msvc_sample_mips/sample_mips.vcxproj create mode 100644 samples/msvc/msvc_sample_mips/sample_mips.vcxproj.filters create mode 100644 samples/msvc/msvc_sample_sparc/sample_sparc.vcxproj create mode 100644 samples/msvc/msvc_sample_sparc/sample_sparc.vcxproj.filters create mode 100644 samples/msvc/msvc_sample_x86/sample_x86.vcxproj create mode 100644 samples/msvc/msvc_sample_x86/sample_x86.vcxproj.filters create mode 100644 samples/msvc/msvc_shellcode/shellcode.vcxproj create mode 100644 samples/msvc/msvc_shellcode/shellcode.vcxproj.filters diff --git a/samples/msvc/msvc.sln b/samples/msvc/msvc.sln index 02ce0ae6..c900e078 100644 --- a/samples/msvc/msvc.sln +++ b/samples/msvc/msvc.sln @@ -1,21 +1,21 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mem_apis", "mem_apis\mem_apis.vcxproj", "{ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mem_apis", "msvc_mem_apis\mem_apis.vcxproj", "{ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_arm", "sample_arm\sample_arm.vcxproj", "{8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_arm", "msvc_sample_arm\sample_arm.vcxproj", "{8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_arm64", "sample_arm64\sample_arm64.vcxproj", "{43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_arm64", "msvc_sample_arm64\sample_arm64.vcxproj", "{43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_m68k", "sample_m68k\sample_m68k.vcxproj", "{39ABA118-6289-43D6-AB6C-8B3AB3CB9390}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_m68k", "msvc_sample_m68k\sample_m68k.vcxproj", "{39ABA118-6289-43D6-AB6C-8B3AB3CB9390}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_mips", "sample_mips\sample_mips.vcxproj", "{5E004A76-1625-44F1-A1EA-64C4FD15F642}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_mips", "msvc_sample_mips\sample_mips.vcxproj", "{5E004A76-1625-44F1-A1EA-64C4FD15F642}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_x86", "sample_x86\sample_x86.vcxproj", "{F8AD989E-D273-42DA-80A6-B6466EB134CA}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_x86", "msvc_sample_x86\sample_x86.vcxproj", "{F8AD989E-D273-42DA-80A6-B6466EB134CA}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_sparc", "sample_sparc\sample_sparc.vcxproj", "{2906001D-9B80-4400-8B3A-4445CDAED54F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_sparc", "msvc_sample_sparc\sample_sparc.vcxproj", "{2906001D-9B80-4400-8B3A-4445CDAED54F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shellcode", "shellcode\shellcode.vcxproj", "{4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shellcode", "msvc_shellcode\shellcode.vcxproj", "{4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/samples/msvc/msvc_mem_apis/mem_apis.vcxproj b/samples/msvc/msvc_mem_apis/mem_apis.vcxproj new file mode 100644 index 00000000..a8cbd077 --- /dev/null +++ b/samples/msvc/msvc_mem_apis/mem_apis.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {ECA2292F-FD4F-4943-B0FC-093B6D35FEBA} + Win32Proj + mem_apis + mem_apis + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_mem_apis/mem_apis.vcxproj.filters b/samples/msvc/msvc_mem_apis/mem_apis.vcxproj.filters new file mode 100644 index 00000000..2efbc67e --- /dev/null +++ b/samples/msvc/msvc_mem_apis/mem_apis.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_arm/sample_arm.vcxproj b/samples/msvc/msvc_sample_arm/sample_arm.vcxproj new file mode 100644 index 00000000..8e32da5e --- /dev/null +++ b/samples/msvc/msvc_sample_arm/sample_arm.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {8FF2F8F8-14CE-4899-998F-2C0BBE43FB6E} + Win32Proj + sample_arm + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_arm/sample_arm.vcxproj.filters b/samples/msvc/msvc_sample_arm/sample_arm.vcxproj.filters new file mode 100644 index 00000000..1ef90901 --- /dev/null +++ b/samples/msvc/msvc_sample_arm/sample_arm.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_arm64/sample_arm64.vcxproj b/samples/msvc/msvc_sample_arm64/sample_arm64.vcxproj new file mode 100644 index 00000000..e1ffaf90 --- /dev/null +++ b/samples/msvc/msvc_sample_arm64/sample_arm64.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD} + Win32Proj + sample_arm64 + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_arm64/sample_arm64.vcxproj.filters b/samples/msvc/msvc_sample_arm64/sample_arm64.vcxproj.filters new file mode 100644 index 00000000..e2779599 --- /dev/null +++ b/samples/msvc/msvc_sample_arm64/sample_arm64.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_m68k/sample_m68k.vcxproj b/samples/msvc/msvc_sample_m68k/sample_m68k.vcxproj new file mode 100644 index 00000000..272007e0 --- /dev/null +++ b/samples/msvc/msvc_sample_m68k/sample_m68k.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {39ABA118-6289-43D6-AB6C-8B3AB3CB9390} + Win32Proj + sample_m68k + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_m68k/sample_m68k.vcxproj.filters b/samples/msvc/msvc_sample_m68k/sample_m68k.vcxproj.filters new file mode 100644 index 00000000..75043431 --- /dev/null +++ b/samples/msvc/msvc_sample_m68k/sample_m68k.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_mips/sample_mips.vcxproj b/samples/msvc/msvc_sample_mips/sample_mips.vcxproj new file mode 100644 index 00000000..939fd38d --- /dev/null +++ b/samples/msvc/msvc_sample_mips/sample_mips.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {5E004A76-1625-44F1-A1EA-64C4FD15F642} + Win32Proj + sample_mips + sample_mips + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_mips/sample_mips.vcxproj.filters b/samples/msvc/msvc_sample_mips/sample_mips.vcxproj.filters new file mode 100644 index 00000000..ebe12868 --- /dev/null +++ b/samples/msvc/msvc_sample_mips/sample_mips.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_sparc/sample_sparc.vcxproj b/samples/msvc/msvc_sample_sparc/sample_sparc.vcxproj new file mode 100644 index 00000000..d08d913e --- /dev/null +++ b/samples/msvc/msvc_sample_sparc/sample_sparc.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2906001D-9B80-4400-8B3A-4445CDAED54F} + Win32Proj + sample_sparc + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_sparc/sample_sparc.vcxproj.filters b/samples/msvc/msvc_sample_sparc/sample_sparc.vcxproj.filters new file mode 100644 index 00000000..99e5ea18 --- /dev/null +++ b/samples/msvc/msvc_sample_sparc/sample_sparc.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_x86/sample_x86.vcxproj b/samples/msvc/msvc_sample_x86/sample_x86.vcxproj new file mode 100644 index 00000000..0c82c5cb --- /dev/null +++ b/samples/msvc/msvc_sample_x86/sample_x86.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F8AD989E-D273-42DA-80A6-B6466EB134CA} + Win32Proj + sample_x86 + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_sample_x86/sample_x86.vcxproj.filters b/samples/msvc/msvc_sample_x86/sample_x86.vcxproj.filters new file mode 100644 index 00000000..5e1d1445 --- /dev/null +++ b/samples/msvc/msvc_sample_x86/sample_x86.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_shellcode/shellcode.vcxproj b/samples/msvc/msvc_shellcode/shellcode.vcxproj new file mode 100644 index 00000000..820518f4 --- /dev/null +++ b/samples/msvc/msvc_shellcode/shellcode.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4A8F2E9A-C2D8-4A93-8451-5F3BD73A4227} + Win32Proj + shellcode + + + + Application + true + v110_xp + MultiByte + + + Application + true + v110_xp + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + Application + false + v110_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreadedDebug + + + Console + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);DYNLOAD + ..\..\..\include;..\..\..\bindings\msvc + MultiThreaded + + + Console + true + true + true + ..\..\..\bindings\msvc + + + + + + + + + + \ No newline at end of file diff --git a/samples/msvc/msvc_shellcode/shellcode.vcxproj.filters b/samples/msvc/msvc_shellcode/shellcode.vcxproj.filters new file mode 100644 index 00000000..61a9927c --- /dev/null +++ b/samples/msvc/msvc_shellcode/shellcode.vcxproj.filters @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From e4fe6b58b46ccc8e3967b856226e55533d060c0b Mon Sep 17 00:00:00 2001 From: coco Date: Tue, 8 Dec 2015 18:23:06 +0100 Subject: [PATCH 14/40] added test for memory quirks --- tests/unit/Makefile | 3 +- tests/unit/test_mem_high.c | 97 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_mem_high.c diff --git a/tests/unit/Makefile b/tests/unit/Makefile index ae66d08e..09890b59 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -4,7 +4,7 @@ CFLAGS += -L ../../ CFLAGS += -lcmocka -lunicorn CFLAGS += -I ../../include -ALL_TESTS = test_sanity test_x86 test_mem_map +ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high .PHONY: all all: ${ALL_TESTS} @@ -23,6 +23,7 @@ test: ${ALL_TESTS} test_sanity: test_sanity.c test_x86: test_x86.c test_mem_map: test_mem_map.c +test_mem_high: test_mem_high.c ${ALL_TESTS}: gcc ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_mem_high.c b/tests/unit/test_mem_high.c new file mode 100644 index 00000000..83fe312f --- /dev/null +++ b/tests/unit/test_mem_high.c @@ -0,0 +1,97 @@ +/** + * Unicorn memory API tests + * + * This tests memory read/write and map/unmap functionality. + * One is necessary for doing the other. + */ +#include "unicorn_test.h" +#include +#include + +/* Called before every test to set up a new instance */ +static int setup(void **state) +{ + uc_engine *uc; + + uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + + *state = uc; + return 0; +} + +/* Called after every test to clean up */ +static int teardown(void **state) +{ + uc_engine *uc = *state; + + uc_assert_success(uc_close(uc)); + + *state = NULL; + return 0; +} + +/******************************************************************************/ + +// mapping the last pages will silently fail +static void test_last_page_map(void **state) +{ + uc_engine *uc = *state; + + uint8_t writebuf[0x10]; + memset(writebuf, 0xCC, sizeof(writebuf)); + + const uint64_t mem_len = 0x1000; + const uint64_t last_page = 0xfffffffffffff000; + uc_assert_success(uc_mem_map(uc, last_page, mem_len, UC_PROT_NONE)); + uc_assert_success(uc_mem_write(uc, last_page, writebuf, sizeof(writebuf))); +} + +// segfaults with NULL-deref (caused by UC_PROT_NONE) +static void test_nullptr_deref_wrong_perms(void **state){ + uc_engine *uc = *state; + const uint64_t base_addr = 0x400000; + uc_assert_success(uc_mem_map(uc, base_addr, 4096, UC_PROT_NONE)); + uc_emu_start(uc, base_addr, base_addr + 1, 0, 0); +} + +static int number_of_memory_reads = 0; + +static void hook_mem64(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) +{ + number_of_memory_reads += 1; + printf(">>> Memory is being accessed at 0x%lx, data size = %u\n", address, size); +} + +//if a read is performed from a big address whith a non-zero last digit, multiple read events are triggered +static void test_high_address_reads(void **state) +{ + uc_engine *uc = *state; + uc_hook trace2; + + uint64_t addr = 0x0010000000000001; + //addr = 0x0010000000000000; // uncomment to fix wrong? behaviour + //addr = 90000000; // uncomment to fix wrong? behaviour + // + uc_mem_map(uc, addr-(addr%4096), 4096*2, UC_PROT_ALL); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RAX, &addr)); + const uint64_t base_addr = 0x40000; + uint8_t code[] = {0x48,0x8b,0x00,0x90,0x90,0x90,0x90}; // mov rax, [rax], nops + uc_assert_success(uc_mem_map(uc, base_addr, 4096, UC_PROT_ALL)); + uc_assert_success(uc_mem_write(uc, base_addr, code, 7)); + uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0)); + uc_assert_success(uc_emu_start(uc, base_addr, base_addr + 3, 0, 0)); + if(number_of_memory_reads != 1) { + fail_msg("wrong number of memory reads for instruction %i", number_of_memory_reads); + } +} + +int main(void) { +#define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown) + const struct CMUnitTest tests[] = { + test(test_last_page_map), + test(test_high_address_reads), + test(test_nullptr_deref_wrong_perms), + }; +#undef test + return cmocka_run_group_tests(tests, NULL, NULL); +} From 7f04b0f7721fdad898f7f435d08c75c6d3dca536 Mon Sep 17 00:00:00 2001 From: xorstream Date: Wed, 9 Dec 2015 18:06:53 +1100 Subject: [PATCH 15/40] Added MIPS delay slot code hook test. Tests that the code hook gets called for instructions in the branch delay slot for MIPS cpu. --- tests/regress/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/regress/Makefile b/tests/regress/Makefile index a2283d9d..d3ad7cee 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -22,6 +22,7 @@ TESTS += x86_16_segfault TESTS += mips_invalid_read_of_size_4_when_tracing TESTS += invalid_read_in_tb_flush_x86_64 TESTS += sparc_jump_to_zero +TESTS += mips_delay_slot_code_hook all: $(TESTS) From eb8d1b58c7dee0391a689ad398d79bcca347ecd4 Mon Sep 17 00:00:00 2001 From: xorstream Date: Wed, 9 Dec 2015 18:09:15 +1100 Subject: [PATCH 16/40] Added MIPS delay slot code hook test. Tests that the code hook gets called for instructions in the branch delay slot for MIPS cpu. --- tests/regress/mips_delay_slot_code_hook.c | 140 ++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 tests/regress/mips_delay_slot_code_hook.c diff --git a/tests/regress/mips_delay_slot_code_hook.c b/tests/regress/mips_delay_slot_code_hook.c new file mode 100644 index 00000000..d3bc0e23 --- /dev/null +++ b/tests/regress/mips_delay_slot_code_hook.c @@ -0,0 +1,140 @@ +/* +Test for code hook being called for instructions in branch delay slot in MIPS cpu. +See issue https://github.com/unicorn-engine/unicorn/issues/290 + +The code hook should be called for every instruction executed. +This test checks that the code hook is correctly called for instructions in branch delay slots. +In this test the loop check value is decremented inside the branch delay shot. +This helps to show that the instruction in the branch delay slot is being executed, +but that the code hook is just not occurring. +*/ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + +// common includes +#include + + +// Test MIPS little endian code. +// It should loop 3 times before ending. +const uint64_t addr = 0x100000; +const unsigned char loop_test_code[] = { + 0x02,0x00,0x04,0x24, // 100000: li $a0, 2 + // loop1 + 0x00,0x00,0x00,0x00, // 100004: nop + 0xFE,0xFF,0x80,0x14, // 100008: bnez $a0, loop1 + 0xFF,0xFF,0x84,0x24, // 10000C: addiu $a0, -1 +}; +bool test_passed_ok = false; +int loop_count = 0; + + +static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + if( address == 0x10000C ) + test_passed_ok = true; + if( address == 0x100004 ) + { + printf("\nloop %d:\n", loop_count); + loop_count++; + } + printf("Code: %llX\n", address); +} + + +int main(int argc, char **argv, char **envp) +{ + uc_engine *uc; + uc_err err; + uc_hook hhc; + uint32_t val; + + // dynamically load shared library +#ifdef DYNLOAD + uc_dyn_load(NULL, 0); +#endif + + // Initialize emulator in MIPS 32bit little endian mode + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); + if (err) + { + printf("Failed on uc_open() with error returned: %u\n", err); + return err; + } + + // map in a page of mem + err = uc_mem_map(uc, addr, 0x1000, UC_PROT_ALL); + if (err) + { + printf("Failed on uc_mem_map() with error returned: %u\n", err); + return err; + } + + // write machine code to be emulated to memory + err = uc_mem_write(uc, addr, loop_test_code, sizeof(loop_test_code)); + if( err ) + { + printf("Failed on uc_mem_write() with error returned: %u\n", err); + return err; + } + + // hook all instructions by having @begin > @end + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + if( err ) + { + printf("Failed on uc_hook_add(code) with error returned: %u\n", err); + return err; + } + + // execute code + printf("---- Executing Code ----\n"); + err = uc_emu_start(uc, addr, addr + sizeof(loop_test_code), 0, 0); + if (err) + { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + return err; + } + + // done executing, print some reg values as a test + printf("---- Execution Complete ----\n\n"); + uc_reg_read(uc, UC_MIPS_REG_PC, &val); printf("pc is %X\n", val); + uc_reg_read(uc, UC_MIPS_REG_A0, &val); printf("a0 is %X\n", val); + + // free resources + uc_close(uc); + + if( test_passed_ok ) + printf("\n\nTEST PASSED!\n\n"); + else + printf("\n\nTEST FAILED!\n\n"); + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} + From 1b145f431b610bb76d19813f886f6471fb9ef27a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 10 Dec 2015 00:53:48 +0800 Subject: [PATCH 17/40] code style --- samples/mem_apis.c | 15 +++++++-------- samples/sample_arm.c | 15 +++++++-------- samples/sample_arm64.c | 15 +++++++-------- samples/sample_m68k.c | 15 +++++++-------- samples/sample_mips.c | 15 +++++++-------- samples/sample_sparc.c | 15 +++++++-------- samples/sample_x86.c | 15 +++++++-------- samples/shellcode.c | 15 +++++++-------- 8 files changed, 56 insertions(+), 64 deletions(-) diff --git a/samples/mem_apis.c b/samples/mem_apis.c index b9356aff..0d933baa 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -361,14 +361,13 @@ int main(int argc, char **argv, char **envp) { // dynamically load shared library #ifdef DYNLOAD - if( !uc_dyn_load(NULL, 0) ) - { - printf("Error dynamically loading shared library.\n"); - printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); - printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); - return 1; - } + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } #endif nx_test(); diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 96d031f9..97c69da4 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -153,14 +153,13 @@ int main(int argc, char **argv, char **envp) { // dynamically load shared library #ifdef DYNLOAD - if( !uc_dyn_load(NULL, 0) ) - { - printf("Error dynamically loading shared library.\n"); - printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); - printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); - return 1; - } + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } #endif test_arm(); diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index b1e85cf2..ae89f5fe 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -100,14 +100,13 @@ int main(int argc, char **argv, char **envp) { // dynamically load shared library #ifdef DYNLOAD - if( !uc_dyn_load(NULL, 0) ) - { - printf("Error dynamically loading shared library.\n"); - printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); - printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); - return 1; - } + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } #endif test_arm64(); diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index 204e503d..b75d3af0 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -162,14 +162,13 @@ int main(int argc, char **argv, char **envp) { // dynamically load shared library #ifdef DYNLOAD - if( !uc_dyn_load(NULL, 0) ) - { - printf("Error dynamically loading shared library.\n"); - printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); - printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); - return 1; - } + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } #endif test_m68k(); diff --git a/samples/sample_mips.c b/samples/sample_mips.c index 578c688e..428b327f 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -147,14 +147,13 @@ int main(int argc, char **argv, char **envp) { // dynamically load shared library #ifdef DYNLOAD - if( !uc_dyn_load(NULL, 0) ) - { - printf("Error dynamically loading shared library.\n"); - printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); - printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); - return 1; - } + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } #endif test_mips_eb(); diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index 1445e9d7..a8f1a1e3 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -102,14 +102,13 @@ int main(int argc, char **argv, char **envp) { // dynamically load shared library #ifdef DYNLOAD - if( !uc_dyn_load(NULL, 0) ) - { - printf("Error dynamically loading shared library.\n"); - printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); - printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); - return 1; - } + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } #endif test_sparc(); diff --git a/samples/sample_x86.c b/samples/sample_x86.c index fe8b1b5f..6f8802cf 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -814,14 +814,13 @@ int main(int argc, char **argv, char **envp) { // dynamically load shared library #ifdef DYNLOAD - if( !uc_dyn_load(NULL, 0) ) - { - printf("Error dynamically loading shared library.\n"); - printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); - printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); - return 1; - } + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } #endif if (argc == 2) { diff --git a/samples/shellcode.c b/samples/shellcode.c index 234b361f..9476a770 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -159,14 +159,13 @@ int main(int argc, char **argv, char **envp) { // dynamically load shared library #ifdef DYNLOAD - if( !uc_dyn_load(NULL, 0) ) - { - printf("Error dynamically loading shared library.\n"); - printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); - printf("any other dependent dll/so files.\n"); - printf("The easiest way is to place them in the same directory as this app.\n"); - return 1; - } + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } #endif if (argc == 2) { From 0d98607121613bb2ead6f57552b41804040ff42f Mon Sep 17 00:00:00 2001 From: farmdve Date: Thu, 10 Dec 2015 00:08:07 +0200 Subject: [PATCH 18/40] Unmapped memory is not freed. While uc_mem_unmap does unmap memory regions from Unicorn, it does not free the memory. It accumulates over time when reusing a single Unicorn instance. --- .gitignore | 1 + tests/regress/Makefile | 1 + tests/regress/mem_nofree.c | 72 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 tests/regress/mem_nofree.c diff --git a/.gitignore b/.gitignore index 247b688e..0603b8c7 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,7 @@ x86_16_segfault mips_invalid_read_of_size_4_when_tracing invalid_read_in_tb_flush_x86_64 sparc_jump_to_zero +mem_nofree ################# diff --git a/tests/regress/Makefile b/tests/regress/Makefile index d3ad7cee..b7129f09 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -23,6 +23,7 @@ TESTS += mips_invalid_read_of_size_4_when_tracing TESTS += invalid_read_in_tb_flush_x86_64 TESTS += sparc_jump_to_zero TESTS += mips_delay_slot_code_hook +TESTS += mem_nofree all: $(TESTS) diff --git a/tests/regress/mem_nofree.c b/tests/regress/mem_nofree.c new file mode 100644 index 00000000..72add193 --- /dev/null +++ b/tests/regress/mem_nofree.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include + +#define ADDRESS1 0x1000000 +#define ADDRESS2 0x2000000 +#define SIZE (80 * 1024 * 1024) + +static void VM_exec() +{ + int c; + uc_engine *uc; + uc_err err; + + // Initialize emulator in X86-64bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + if(err) + { + printf("Failed on uc_open() with error returned: %s\n", uc_strerror(err)); + return; + } + +repeat: + err = uc_mem_map(uc, ADDRESS1, SIZE, UC_PROT_ALL); + if(err != UC_ERR_OK) + { + printf("Failed to map memory %s\n", uc_strerror(err)); + goto err; + } + + err = uc_mem_map(uc, ADDRESS2, SIZE, UC_PROT_ALL); + if(err != UC_ERR_OK) + { + printf("Failed to map memory %s\n", uc_strerror(err)); + goto err; + } + + err = uc_mem_unmap(uc, ADDRESS1, SIZE); + if(err != UC_ERR_OK) + { + printf("Failed to unmap memory %s\n", uc_strerror(err)); + goto err; + } + + err = uc_mem_unmap(uc, ADDRESS2, SIZE); + if(err != UC_ERR_OK) + { + printf("Failed to unmap memory %s\n", uc_strerror(err)); + goto err; + } + + for(;;) + { + c = getchar(); //pause here and analyse memory usage before exiting with a program like VMMap; + if(c != 'e') + goto repeat; + else + break; + } + +err: + uc_close(uc); +} + +int main(int argc, char *argv[]) +{ + VM_exec(); + return 0; +} From a6a62f6beac3e4826f0904632e961ec81db92b4e Mon Sep 17 00:00:00 2001 From: xorstream Date: Thu, 10 Dec 2015 12:06:57 +1100 Subject: [PATCH 19/40] Moved unicorn_dynload.h into bindings dir. --- {include/unicorn => bindings/msvc}/unicorn_dynload.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {include/unicorn => bindings/msvc}/unicorn_dynload.h (100%) diff --git a/include/unicorn/unicorn_dynload.h b/bindings/msvc/unicorn_dynload.h similarity index 100% rename from include/unicorn/unicorn_dynload.h rename to bindings/msvc/unicorn_dynload.h From 27128a95633bc00719dc28ab0736f7e528cfc61f Mon Sep 17 00:00:00 2001 From: xorstream Date: Thu, 10 Dec 2015 13:09:31 +1100 Subject: [PATCH 20/40] Added mnemonic printing to disasm function. --- tests/regress/mips_branch_delay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regress/mips_branch_delay.py b/tests/regress/mips_branch_delay.py index 2f90ef14..f710890c 100755 --- a/tests/regress/mips_branch_delay.py +++ b/tests/regress/mips_branch_delay.py @@ -11,7 +11,7 @@ class MipsBranchDelay(regress.RegressTest): def disas(code, addr): for i in md.disasm(code, addr): - print '0x%x: %s %s' % (i.address, str(i.bytes).encode('hex'), i.op_str) + print '0x%x: %s %-6s %s' % (i.address, str(i.bytes).encode('hex'), i.mnemonic, i.op_str) def hook_code(uc, addr, size, _): mem = str(uc.mem_read(addr, size)) From 14e75252a5402805150b4e7104d8d8fda670c27f Mon Sep 17 00:00:00 2001 From: coco Date: Thu, 10 Dec 2015 16:07:01 +0100 Subject: [PATCH 21/40] added testcase for the values read from high addresses --- tests/unit/test_mem_high.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/unit/test_mem_high.c b/tests/unit/test_mem_high.c index 83fe312f..dea20bdf 100644 --- a/tests/unit/test_mem_high.c +++ b/tests/unit/test_mem_high.c @@ -85,11 +85,38 @@ static void test_high_address_reads(void **state) } } +//if a read is performed from a big address whith a non-zero last digit, 0 will be read +static void test_high_address_read_values(void **state) +{ + uc_engine *uc = *state; + + uint64_t addr = 0x0010000000000001; + //addr = 0x000ffffffffffff8; // uncomment to fix wrong behaviour + //addr = 90000000; // uncomment to fix wrong behaviour + // + uint8_t content[] = {0x42,0x42,0x42,0x42, 0x42,0x42,0x42,0x42}; + uc_assert_success(uc_mem_map(uc, addr-(addr%4096), 4096*2, UC_PROT_ALL)); + uc_assert_success(uc_mem_write(uc, addr, content, 8)); + uc_assert_success(uc_reg_write(uc, UC_X86_REG_RAX, &addr)); + const uint64_t base_addr = 0x40000; + uint8_t code[] = {0x48,0x8b,0x00,0x90,0x90,0x90,0x90}; // mov rax, [rax], nops + uc_assert_success(uc_mem_map(uc, base_addr, 4096, UC_PROT_ALL)); + uc_assert_success(uc_mem_write(uc, base_addr, code, 7)); + uc_assert_success(uc_emu_start(uc, base_addr, base_addr + 3, 0, 0)); + uint64_t rax = 0; + uc_assert_success(uc_reg_read(uc, UC_X86_REG_RAX, &rax)); + if(rax != 0x4242424242424242) { + fail_msg("wrong memory read from code %lx", rax); + } +} + + int main(void) { #define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown) const struct CMUnitTest tests[] = { test(test_last_page_map), test(test_high_address_reads), + test(test_high_address_read_values), test(test_nullptr_deref_wrong_perms), }; #undef test From 3e57615c76b13c67e8c6ce8ce2296f509338a61e Mon Sep 17 00:00:00 2001 From: farmdve Date: Fri, 11 Dec 2015 02:42:31 +0200 Subject: [PATCH 22/40] Fix uc_mem_unmap memory leak and in uc_close. It appears the problem is that we are not calling the memory region destructor. After modifying memory_unmap to include the destructor call for the memory region, the memory is freed. Furthermore in uc_close we must explicitly free any blocks that were not unmapped by the user to prevent leaks. This should fix issue 305. --- qemu/memory.c | 5 +++++ uc.c | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/qemu/memory.c b/qemu/memory.c index eaab3ba6..33944404 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -68,6 +68,11 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) uc->mapped_block_count--; //shift remainder of array down over deleted pointer memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); + mr->destructor(mr); + if((char *)mr->name) + g_free((char *)mr->name); + if(mr->ioeventfds) + g_free(mr->ioeventfds); break; } } diff --git a/uc.c b/uc.c index 7ff96368..5d12298a 100644 --- a/uc.c +++ b/uc.c @@ -258,6 +258,9 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) UNICORN_EXPORT uc_err uc_close(uc_engine *uc) { + MemoryRegion *mr; + int i; + if (uc->release) uc->release(uc->tcg_ctx); @@ -271,11 +274,19 @@ uc_err uc_close(uc_engine *uc) g_free(uc->tcg_ctx); + for (i = 0; i < uc->mapped_block_count; i++) { + mr = uc->mapped_blocks[i]; + mr->destructor(mr); + if((char *)mr->name) + g_free((char *)mr->name); + if(mr->ioeventfds) + g_free(mr->ioeventfds); + } + free((void*) uc->system_memory->name); g_free(uc->system_memory); g_hash_table_destroy(uc->type_table); - int i; for (i = 0; i < DIRTY_MEMORY_NUM; i++) { free(uc->ram_list.dirty_memory[i]); } From 74986cc59a259d011410493e1d4a522cb00563b2 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 11 Dec 2015 11:25:35 +0800 Subject: [PATCH 23/40] g_free() can handle NULL pointer --- qemu/memory.c | 8 ++++---- uc.c | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/qemu/memory.c b/qemu/memory.c index 33944404..a767bf03 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -69,10 +69,8 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) //shift remainder of array down over deleted pointer memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); mr->destructor(mr); - if((char *)mr->name) - g_free((char *)mr->name); - if(mr->ioeventfds) - g_free(mr->ioeventfds); + g_free((char *)mr->name); + g_free(mr->ioeventfds); break; } } @@ -81,12 +79,14 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) int memory_free(struct uc_struct *uc) { int i; + get_system_memory(uc)->enabled = false; for (i = 0; i < uc->mapped_block_count; i++) { uc->mapped_blocks[i]->enabled = false; memory_region_del_subregion(get_system_memory(uc), uc->mapped_blocks[i]); g_free(uc->mapped_blocks[i]); } + return 0; } diff --git a/uc.c b/uc.c index 5d12298a..7e2d5fa1 100644 --- a/uc.c +++ b/uc.c @@ -277,10 +277,8 @@ uc_err uc_close(uc_engine *uc) for (i = 0; i < uc->mapped_block_count; i++) { mr = uc->mapped_blocks[i]; mr->destructor(mr); - if((char *)mr->name) - g_free((char *)mr->name); - if(mr->ioeventfds) - g_free(mr->ioeventfds); + g_free((char *)mr->name); + g_free(mr->ioeventfds); } free((void*) uc->system_memory->name); From 613d60119eea5d00dbc60e479775b97cd77f107b Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 11 Dec 2015 22:26:05 +0800 Subject: [PATCH 24/40] update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0603b8c7..895631c5 100644 --- a/.gitignore +++ b/.gitignore @@ -119,6 +119,7 @@ mips_invalid_read_of_size_4_when_tracing invalid_read_in_tb_flush_x86_64 sparc_jump_to_zero mem_nofree +mips_delay_slot_code_hook ################# From a142611f56724c6fc5b3b549a2f4afefcb989842 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 12 Dec 2015 00:41:09 +0800 Subject: [PATCH 25/40] sparc: set compute functions for icc_table[] & xcc_table[]. this fixes issue #289 --- qemu/target-sparc/cc_helper.c | 7 +++++++ tests/regress/sparc_jump_to_zero.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/qemu/target-sparc/cc_helper.c b/qemu/target-sparc/cc_helper.c index 35dab732..66ec0e61 100644 --- a/qemu/target-sparc/cc_helper.c +++ b/qemu/target-sparc/cc_helper.c @@ -20,6 +20,11 @@ #include "cpu.h" #include "exec/helper-proto.h" +static uint32_t compute_null(CPUSPARCState *env) +{ + return 0; +} + static uint32_t compute_all_flags(CPUSPARCState *env) { return env->psr & PSR_ICC; @@ -433,6 +438,7 @@ typedef struct CCTable { static const CCTable icc_table[CC_OP_NB] = { /* CC_OP_DYNAMIC should never happen */ + [CC_OP_DYNAMIC] = { compute_null, compute_null }, [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags }, [CC_OP_DIV] = { compute_all_div, compute_C_div }, [CC_OP_ADD] = { compute_all_add, compute_C_add }, @@ -449,6 +455,7 @@ static const CCTable icc_table[CC_OP_NB] = { #ifdef TARGET_SPARC64 static const CCTable xcc_table[CC_OP_NB] = { /* CC_OP_DYNAMIC should never happen */ + [CC_OP_DYNAMIC] = { compute_null, compute_null }, [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc }, [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic }, [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc }, diff --git a/tests/regress/sparc_jump_to_zero.c b/tests/regress/sparc_jump_to_zero.c index ecef159a..99148f2f 100644 --- a/tests/regress/sparc_jump_to_zero.c +++ b/tests/regress/sparc_jump_to_zero.c @@ -7,7 +7,7 @@ #define MEMORY_SIZE 2 * 1024 * 1024 #define MEMORY_PERMISSIONS UC_PROT_ALL -#define BINARY_CODE "\x02\xbc" +#define BINARY_CODE "\x02\xbc\x00\x00" int main(int argc, char **argv, char **envp) { uc_engine *uc; From 0e62ebc038c282394fd8bb1087d1262c8b5592f5 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 12 Dec 2015 00:58:49 +0800 Subject: [PATCH 26/40] unit: fix compilation warning for test_mem_high.c --- tests/unit/test_mem_high.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_mem_high.c b/tests/unit/test_mem_high.c index dea20bdf..5e2244e5 100644 --- a/tests/unit/test_mem_high.c +++ b/tests/unit/test_mem_high.c @@ -7,6 +7,7 @@ #include "unicorn_test.h" #include #include +#include /* Called before every test to set up a new instance */ static int setup(void **state) @@ -59,7 +60,7 @@ static int number_of_memory_reads = 0; static void hook_mem64(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { number_of_memory_reads += 1; - printf(">>> Memory is being accessed at 0x%lx, data size = %u\n", address, size); + printf(">>> Memory is being accessed at 0x%"PRIx64 ", data size = %u\n", address, size); } //if a read is performed from a big address whith a non-zero last digit, multiple read events are triggered @@ -106,7 +107,7 @@ static void test_high_address_read_values(void **state) uint64_t rax = 0; uc_assert_success(uc_reg_read(uc, UC_X86_REG_RAX, &rax)); if(rax != 0x4242424242424242) { - fail_msg("wrong memory read from code %lx", rax); + fail_msg("wrong memory read from code %"PRIx64, rax); } } From 3c728093736599625553bb4dde6d9c33afb5f981 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 12 Dec 2015 01:37:13 +0800 Subject: [PATCH 27/40] end address of mapping memory is not inclusive, and can wrap around to 0. fix issue #299 --- uc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/uc.c b/uc.c index 7e2d5fa1..2c8f9f1d 100644 --- a/uc.c +++ b/uc.c @@ -588,6 +588,10 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) // invalid memory mapping return UC_ERR_ARG; + // address cannot wrapp around + if (address + size - 1 < address) + return UC_ERR_ARG; + // address must be aligned to uc->target_page_size if ((address & uc->target_page_align) != 0) return UC_ERR_ARG; @@ -845,7 +849,7 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) return uc->mapped_blocks[i]; for(i = 0; i < uc->mapped_block_count; i++) { - if (address >= uc->mapped_blocks[i]->addr && address < uc->mapped_blocks[i]->end) { + if (address >= uc->mapped_blocks[i]->addr && address <= uc->mapped_blocks[i]->end - 1) { // cache this index for the next query uc->mapped_block_cache_index = i; return uc->mapped_blocks[i]; From 9b6701dc4d03d276e17cdc05a174408c5658f624 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 12 Dec 2015 01:39:59 +0800 Subject: [PATCH 28/40] update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 895631c5..8b24f7b9 100644 --- a/.gitignore +++ b/.gitignore @@ -121,6 +121,8 @@ sparc_jump_to_zero mem_nofree mips_delay_slot_code_hook +test_mem_high + ################# ## Visual Studio From f21fa3d966f7951a1d598d2d5fc6120afe6612f8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 12 Dec 2015 03:09:38 +0800 Subject: [PATCH 29/40] do not flush TB when l1_map is uninitialized. this fixes issue #280, #284 --- qemu/translate-all.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qemu/translate-all.c b/qemu/translate-all.c index 2e1acb1a..088e7b40 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -807,6 +807,9 @@ static void page_flush_tb(struct uc_struct *uc) { int i; + if (uc->l1_map == NULL) + return; + for (i = 0; i < V_L1_SIZE; i++) { page_flush_tb_1(V_L1_SHIFT / V_L2_BITS - 1, uc->l1_map + i); } From 8b79a872d0457c7a790af1374a53679edd14c8a7 Mon Sep 17 00:00:00 2001 From: farmdve Date: Fri, 11 Dec 2015 22:35:25 +0200 Subject: [PATCH 30/40] Fix segfault introduced in my previous commits. --- qemu/memory.c | 11 ++++++++--- uc.c | 8 -------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/qemu/memory.c b/qemu/memory.c index a767bf03..5e26d83d 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -78,13 +78,18 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) int memory_free(struct uc_struct *uc) { + MemoryRegion *mr; int i; get_system_memory(uc)->enabled = false; for (i = 0; i < uc->mapped_block_count; i++) { - uc->mapped_blocks[i]->enabled = false; - memory_region_del_subregion(get_system_memory(uc), uc->mapped_blocks[i]); - g_free(uc->mapped_blocks[i]); + mr = uc->mapped_blocks[i]; + mr->enabled = false; + memory_region_del_subregion(get_system_memory(uc), mr); + mr->destructor(mr); + g_free((char *)mr->name); + g_free(mr->ioeventfds); + g_free(mr); } return 0; diff --git a/uc.c b/uc.c index 2c8f9f1d..53bb682d 100644 --- a/uc.c +++ b/uc.c @@ -258,7 +258,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) UNICORN_EXPORT uc_err uc_close(uc_engine *uc) { - MemoryRegion *mr; int i; if (uc->release) @@ -274,13 +273,6 @@ uc_err uc_close(uc_engine *uc) g_free(uc->tcg_ctx); - for (i = 0; i < uc->mapped_block_count; i++) { - mr = uc->mapped_blocks[i]; - mr->destructor(mr); - g_free((char *)mr->name); - g_free(mr->ioeventfds); - } - free((void*) uc->system_memory->name); g_free(uc->system_memory); g_hash_table_destroy(uc->type_table); From 845392de1e179bcf9689ac76524c002c63f55a4d Mon Sep 17 00:00:00 2001 From: univm Date: Sat, 12 Dec 2015 00:48:46 +0200 Subject: [PATCH 31/40] Test for stack hooking. --- .gitignore | 1 + tests/regress/Makefile | 1 + tests/regress/rw_hookstack.c | 109 +++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 tests/regress/rw_hookstack.c diff --git a/.gitignore b/.gitignore index 8b24f7b9..86d5d104 100644 --- a/.gitignore +++ b/.gitignore @@ -122,6 +122,7 @@ mem_nofree mips_delay_slot_code_hook test_mem_high +rw_hookstack ################# diff --git a/tests/regress/Makefile b/tests/regress/Makefile index b7129f09..3221f939 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -24,6 +24,7 @@ TESTS += invalid_read_in_tb_flush_x86_64 TESTS += sparc_jump_to_zero TESTS += mips_delay_slot_code_hook TESTS += mem_nofree +TESTS += rw_hookstack all: $(TESTS) diff --git a/tests/regress/rw_hookstack.c b/tests/regress/rw_hookstack.c new file mode 100644 index 00000000..65caf1e4 --- /dev/null +++ b/tests/regress/rw_hookstack.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include + +#define ADDRESS 0x1000000 +#define STACK 0x0020D000 +#define STACK2 0x0030D000 +#define STACK_SIZE 16384 +#define SIZE (2 * 1024 * 1024) +#define CODE32 "\x8B\x04\x24\xA3\x40\x00\x00\x01\xA1\x40\x00\x00\x01" + +bool hook_mem_rw(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) +{ + unsigned int EIP; + + uc_reg_read(uc, UC_X86_REG_EIP, &EIP); + switch(type) + { + default: + return false; + break; + case UC_MEM_WRITE: + printf("Hooked write to address 0x%08"PRIX64" with value 0x%08"PRIX64" at EIP %08X\n", address, value, EIP); + + return true; + break; + case UC_MEM_READ: + printf("Hooked read from address 0x%08"PRIX64" with value 0x%08"PRIX64" at EIP %08X\n", address, value, EIP); + + return true; + break; + } +} + +int main(int argc, char *argv[]) +{ + uc_engine *uc; + uc_hook trace; + uc_err err; + unsigned int EAX, ESP, val = 0x0c0c0c0c, stkval = STACK; + + EAX = 0; + ESP = STACK+0x4; + + // Initialize emulator in X86-64bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + if(err) { + printf("Failed on uc_open() with error returned: %s\n", uc_strerror(err)); + return; + } + + err = uc_mem_map(uc, ADDRESS, SIZE, UC_PROT_ALL); + if(err != UC_ERR_OK) { + printf("Failed to map memory %s\n", uc_strerror(err)); + return; + } + + err = uc_mem_write(uc, ADDRESS, CODE32, sizeof(CODE32) - 1); + if(err != UC_ERR_OK) { + printf("Failed to write to memory %s\n", uc_strerror(err)); + return; + } + +loop: + err = uc_mem_map(uc, stkval, STACK_SIZE, UC_PROT_ALL); + if(err != UC_ERR_OK) { + printf("Failed to map memory %s\n", uc_strerror(err)); + return; + } + + err = uc_mem_write(uc, ESP, &val, sizeof(val)); + if(err != UC_ERR_OK) { + printf("Failed to write to memory %s\n", uc_strerror(err)); + return; + } + + + uc_hook_add(uc, &trace, UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, (void *)hook_mem_rw, NULL); + + uc_reg_write(uc, UC_X86_REG_EAX, &EAX); + uc_reg_write(uc, UC_X86_REG_ESP, &ESP); + + err = uc_emu_start(uc, ADDRESS, ADDRESS + (sizeof(CODE32) - 1), 0, 0); + if(err) { + printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); + + uc_close(uc); + return; + } + + uc_reg_read(uc, UC_X86_REG_EAX, &EAX); + + printf(">>> EAX = %08X\n", EAX); + + if(stkval != STACK2) + { + printf("=== Beginning test two ===\n"); + ESP = STACK2+0x4; + EAX = 0; + stkval = STACK2; + goto loop; + } + + uc_close(uc); + return 0; +} From bc63102e5041595cc8da3b843b0e54d970166b2c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 13 Dec 2015 13:11:40 +0800 Subject: [PATCH 32/40] mips: only patch instruction size when there is a callback on the instruction. this fixes issue #282 --- qemu/target-mips/translate.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index c1941505..ccf11255 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -11322,7 +11322,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) return 4; } -static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot) +static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot, bool *insn_need_patch) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; @@ -11345,8 +11345,10 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_s // Unicorn: trace this instruction on request if (!is_bc_slot && env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); - if (trace) + if (trace) { gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); + *insn_need_patch = true; + } // if requested to emulate only some instructions, check if // we need to exit immediately if (env->uc->emu_count > 0) { @@ -13928,7 +13930,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, } } -static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot) +static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot, bool *insn_need_patch) { TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; @@ -13945,8 +13947,10 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool is_b // Unicorn: trace this instruction on request if (!is_bc_slot && env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); - if (trace) + if (trace) { gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); + *insn_need_patch = true; + } // if requested to emulate only some instructions, check if // we need to exit immediately if (env->uc->emu_count > 0) { @@ -18503,7 +18507,7 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) } } -static void decode_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot) +static void decode_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot, bool *insn_need_patch) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; #if defined(TARGET_MIPS64) @@ -18514,7 +18518,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot) uint32_t op, op1; int16_t imm; - /* make sure instructions are on a word boundary */ if (ctx->pc & 0x3) { env->CP0_BadVAddr = ctx->pc; @@ -18525,8 +18528,10 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot) // Unicorn: trace this instruction on request if (!is_bc_slot && env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); - if (trace) + if (trace) { gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); + *insn_need_patch = true; + } // if requested to emulate only some instructions, check if // we need to exit immediately if (env->uc->emu_count > 0) { @@ -19268,6 +19273,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.bstate = BS_EXCP; break; } else { + bool insn_need_patch = false; // Unicorn: save param buffer if (env->uc->hook_insn) save_opparam_ptr = tcg_ctx->gen_opparam_ptr; @@ -19278,13 +19284,13 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, if (!(ctx.hflags & MIPS_HFLAG_M16)) { ctx.opcode = cpu_ldl_code(env, ctx.pc); insn_bytes = 4; - decode_opc(env, &ctx, is_bc_slot); + decode_opc(env, &ctx, is_bc_slot, &insn_need_patch); } else if (ctx.insn_flags & ASE_MICROMIPS) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_micromips_opc(env, &ctx, is_bc_slot); + insn_bytes = decode_micromips_opc(env, &ctx, is_bc_slot, &insn_need_patch); } else if (ctx.insn_flags & ASE_MIPS16) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_mips16_opc(env, &ctx, is_bc_slot); + insn_bytes = decode_mips16_opc(env, &ctx, is_bc_slot, &insn_need_patch); } else { generate_exception(&ctx, EXCP_RI); ctx.bstate = BS_STOP; @@ -19292,7 +19298,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, } // Unicorn: patch the callback for the instruction size - if (!is_bc_slot && env->uc->hook_insn) + if (insn_need_patch) *(save_opparam_ptr + 1) = insn_bytes; } From 395251d3e8139493fb35d5abae898d798d636cbf Mon Sep 17 00:00:00 2001 From: xorstream Date: Tue, 15 Dec 2015 17:02:56 +1100 Subject: [PATCH 33/40] Fix codehook for MIPS instructions in delay slot --- qemu/target-mips/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index ccf11255..2be3375d 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -11343,7 +11343,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_s n_bytes = 2; // Unicorn: trace this instruction on request - if (!is_bc_slot && env->uc->hook_insn) { + if (env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) { gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); @@ -13945,7 +13945,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool is_b } // Unicorn: trace this instruction on request - if (!is_bc_slot && env->uc->hook_insn) { + if (env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) { gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); @@ -18526,7 +18526,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot, b } // Unicorn: trace this instruction on request - if (!is_bc_slot && env->uc->hook_insn) { + if (env->uc->hook_insn) { struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) { gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); From f68077852f82e70bd009d5550611a002ffaabf65 Mon Sep 17 00:00:00 2001 From: xorstream Date: Tue, 15 Dec 2015 17:17:14 +1100 Subject: [PATCH 34/40] Fixed includes for moved unicorn_dynload.h file --- bindings/msvc/samples/main.c | 2 +- bindings/msvc/unicorn_dynload.c | 2 +- bindings/msvc/unicorn_dynload.h | 2 +- samples/mem_apis.c | 2 +- samples/sample_arm.c | 2 +- samples/sample_arm64.c | 2 +- samples/sample_m68k.c | 2 +- samples/sample_mips.c | 2 +- samples/sample_sparc.c | 2 +- samples/sample_x86.c | 2 +- samples/shellcode.c | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bindings/msvc/samples/main.c b/bindings/msvc/samples/main.c index 87cbbb55..c9a24001 100644 --- a/bindings/msvc/samples/main.c +++ b/bindings/msvc/samples/main.c @@ -10,7 +10,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 diff --git a/bindings/msvc/unicorn_dynload.c b/bindings/msvc/unicorn_dynload.c index ae136c17..0c6a7eee 100644 --- a/bindings/msvc/unicorn_dynload.c +++ b/bindings/msvc/unicorn_dynload.c @@ -34,7 +34,7 @@ #define WINDOWS_DLL 1 #endif -#include +#include "unicorn_dynload.h" #ifdef WINDOWS_DLL #include diff --git a/bindings/msvc/unicorn_dynload.h b/bindings/msvc/unicorn_dynload.h index 138ad08e..638f5250 100644 --- a/bindings/msvc/unicorn_dynload.h +++ b/bindings/msvc/unicorn_dynload.h @@ -33,7 +33,7 @@ #ifdef UNICORN_SHARED #undef UNICORN_SHARED #endif -#include "unicorn.h" +#include #ifdef __cplusplus extern "C" { diff --git a/samples/mem_apis.c b/samples/mem_apis.c index 0d933baa..50554eeb 100644 --- a/samples/mem_apis.c +++ b/samples/mem_apis.c @@ -26,7 +26,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 97c69da4..8a5067db 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -9,7 +9,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index ae89f5fe..39d500aa 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -9,7 +9,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index b75d3af0..efda5294 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -9,7 +9,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 diff --git a/samples/sample_mips.c b/samples/sample_mips.c index 428b327f..3f37b189 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -9,7 +9,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index a8f1a1e3..e966f5af 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -9,7 +9,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 6f8802cf..a0487e14 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -9,7 +9,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 diff --git a/samples/shellcode.c b/samples/shellcode.c index 9476a770..a6fd5221 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -9,7 +9,7 @@ #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include "unicorn_dynload.h" #else // DYNLOAD #include #ifdef _WIN64 From f111d7d1caab8500845c607ab7b1798f00743501 Mon Sep 17 00:00:00 2001 From: xorstream Date: Wed, 16 Dec 2015 12:59:30 +1100 Subject: [PATCH 35/40] Added support for building tests from MinGW. --- .gitignore | 1 + tests/regress/Makefile | 8 +++++++- tests/regress/mips_delay_slot_code_hook.c | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 86d5d104..05a649f5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.dSYM *.so *.so.* +*.exe qemu/config-all-devices.mak diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 3221f939..dd20749b 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -1,5 +1,11 @@ -CFLAGS += -I../include + +CFLAGS += -I../../include + +ifeq (MING,$(findstring MING,$(shell uname -s))) +LDFLAGS += ../../unicorn.lib $(shell pkg-config --libs glib-2.0) -lpthread -lm +else LDFLAGS += ../../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm +endif TESTS = map_crash map_write TESTS += sigill sigill2 diff --git a/tests/regress/mips_delay_slot_code_hook.c b/tests/regress/mips_delay_slot_code_hook.c index d3bc0e23..905cad8d 100644 --- a/tests/regress/mips_delay_slot_code_hook.c +++ b/tests/regress/mips_delay_slot_code_hook.c @@ -15,7 +15,7 @@ but that the code hook is just not occurring. #include #define PRIx64 "llX" #ifdef DYNLOAD -#include +#include #else // DYNLOAD #include #ifdef _WIN64 From 6aa33e835990f6adef00df9583978bf86d901ca6 Mon Sep 17 00:00:00 2001 From: xorstream Date: Wed, 16 Dec 2015 13:08:33 +1100 Subject: [PATCH 36/40] Added test for uc_open() and uc_emu_start() being called by different threads. --- tests/regress/Makefile | 1 + tests/regress/threaded_emu_start.c | 243 +++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 tests/regress/threaded_emu_start.c diff --git a/tests/regress/Makefile b/tests/regress/Makefile index dd20749b..cec787df 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -31,6 +31,7 @@ TESTS += sparc_jump_to_zero TESTS += mips_delay_slot_code_hook TESTS += mem_nofree TESTS += rw_hookstack +TESTS += threaded_emu_start all: $(TESTS) diff --git a/tests/regress/threaded_emu_start.c b/tests/regress/threaded_emu_start.c new file mode 100644 index 00000000..9a5a2fa9 --- /dev/null +++ b/tests/regress/threaded_emu_start.c @@ -0,0 +1,243 @@ +/* +Test for uc_open() and uc_emu_start() being called by different threads. + +This code will call uc_open() in the main thread and then attempt +to call uc_emu_start() from its own thread. This would enable the emulator +to run in the background while you do other things like handle user interface +etc in the foreground. + +Currently "uc->qemu_global_mutex" is locked by uc_open() and unlocked +by uc_emu_start(). This is a problem because the mutex implementation +must be locked and unlocked by the same thread. This means that uc_open() +and uc_emu_start() must be executed in the same thread. This is an unnecessary +limitation which prevents the emulator from being able to be executed in the +background. +*/ + +// windows specific +#ifdef _MSC_VER +#include +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#include "pthread.h" +#endif // _MSC_VER + +// for win32 threads in mingw +#ifdef _WIN32 +#include +#endif + +// common includes +#include + + +// Test MIPS little endian code. +// This should loop forever. +const uint64_t addr = 0x100000; +const unsigned char loop_test_code[] = { + 0x02,0x00,0x04,0x24, // 100000: li $a0, 2 + // loop1 + 0x00,0x00,0x00,0x00, // 100004: nop + 0xFE,0xFF,0x80,0x14, // 100008: bnez $a0, loop1 + 0x00,0x00,0x00,0x00, // 10000C: nop +}; +bool test_passed_ok = false; +int loop_count = 0; + + +// This hook is used to show that code is executing in the emulator. +static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf("Code: %llX\n", address); +} + + +typedef struct { + uc_engine *uc; + uint64_t startAddr; + uint64_t endAddr; +} EmuStarterParam_t; + +// This is a thread that just runs uc_emu_start() in it. +// The code that it is executing in this case will run forever until it is stopped by uc_emu_stop(). +static uc_err emu_starter(void* param) +{ + uc_engine *uc; + uint64_t start_addr; + uint64_t end_addr; + uc_err err; + + EmuStarterParam_t* starter_params = (EmuStarterParam_t *)param; + uc = starter_params->uc; + start_addr = starter_params->startAddr; + end_addr = starter_params->endAddr; + + printf("uc_emu_start()\n"); + err = uc_emu_start(uc, start_addr, end_addr, 0, 0); + if (err) + { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + } + + return err; +} + +#ifdef _WIN32 +static unsigned int __stdcall win32_emu_starter(void* param) +{ + uc_err err = emu_starter(param); + _endthreadex(err); + return err; +} +#else +static void* posix_emu_starter(void* param) +{ + uc_err err = emu_starter(param); + return (void*)err; +} +#endif + + +int main(int argc, char **argv, char **envp) +{ + uc_engine *uc; + uc_err err; + int ret; + uc_hook hhc; + uint32_t val; + EmuStarterParam_t starter_params; +#ifdef _WIN32 + HANDLE th = (HANDLE)-1; +#else + pthread_t th; +#endif + + // dynamically load shared library +#ifdef DYNLOAD + uc_dyn_load(NULL, 0); +#endif + + // Initialize emulator in MIPS 32bit little endian mode + printf("uc_open()\n"); + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); + if (err) + { + printf("Failed on uc_open() with error returned: %u\n", err); + return err; + } + + // map in a page of mem + printf("uc_mem_map()\n"); + err = uc_mem_map(uc, addr, 0x1000, UC_PROT_ALL); + if (err) + { + printf("Failed on uc_mem_map() with error returned: %u\n", err); + return err; + } + + // write machine code to be emulated to memory + printf("uc_mem_write()\n"); + err = uc_mem_write(uc, addr, loop_test_code, sizeof(loop_test_code)); + if( err ) + { + printf("Failed on uc_mem_write() with error returned: %u\n", err); + return err; + } + + // hook all instructions by having @begin > @end + printf("uc_hook_add()\n"); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + if( err ) + { + printf("Failed on uc_hook_add(code) with error returned: %u\n", err); + return err; + } + + + // start background thread + printf("---- Thread Starting ----\n"); + starter_params.uc = uc; + starter_params.startAddr = addr; + starter_params.endAddr = addr + sizeof(loop_test_code); + +#ifdef _WIN32 + // create thread + th = (HANDLE)_beginthreadex(NULL, 0, win32_emu_starter, &starter_params, CREATE_SUSPENDED, NULL); + if(th == (HANDLE)-1) + { + printf("Failed on _beginthreadex() with error returned: %u\n", _errno()); + return -1; + } + // start thread + ret = ResumeThread(th); + if( ret == -1 ) + { + printf("Failed on ResumeThread() with error returned: %u\n", _errno()); + return -2; + } + // wait 3 seconds + Sleep(3 * 1000); +#else + // add posix code to start the emu_starter() thread + ret = pthread_create(&th, NULL, posix_emu_starter, &starter_params); + if( ret ) + { + printf("Failed on pthread_create() with error returned: %u\n", err); + return -2; + } + // wait 3 seconds + sleep(3); +#endif + + + // Stop the thread after it has been let to run in the background for a while + printf("---- Thread Stopping ----\n"); + printf("uc_emu_stop()\n"); + err = uc_emu_stop(uc); + if( err ) + { + printf("Failed on uc_emu_stop() with error returned: %u\n", err); + return err; + } + test_passed_ok = true; + + + // done executing, print some reg values as a test + uc_reg_read(uc, UC_MIPS_REG_PC, &val); printf("pc is %X\n", val); + uc_reg_read(uc, UC_MIPS_REG_A0, &val); printf("a0 is %X\n", val); + + // free resources + printf("uc_close()\n"); + uc_close(uc); + + if( test_passed_ok ) + printf("\n\nTEST PASSED!\n\n"); + else + printf("\n\nTEST FAILED!\n\n"); + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} + From d871e17ffd79aab6245fda742494d98c822c845d Mon Sep 17 00:00:00 2001 From: xorstream Date: Wed, 16 Dec 2015 13:13:15 +1100 Subject: [PATCH 37/40] Added return values in main() to rw_hookstack.c so that it builds in MinGW. --- tests/regress/rw_hookstack.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/regress/rw_hookstack.c b/tests/regress/rw_hookstack.c index 65caf1e4..e04dd64c 100644 --- a/tests/regress/rw_hookstack.c +++ b/tests/regress/rw_hookstack.c @@ -49,32 +49,32 @@ int main(int argc, char *argv[]) err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if(err) { printf("Failed on uc_open() with error returned: %s\n", uc_strerror(err)); - return; + return 1; } err = uc_mem_map(uc, ADDRESS, SIZE, UC_PROT_ALL); if(err != UC_ERR_OK) { printf("Failed to map memory %s\n", uc_strerror(err)); - return; + return 1; } err = uc_mem_write(uc, ADDRESS, CODE32, sizeof(CODE32) - 1); if(err != UC_ERR_OK) { printf("Failed to write to memory %s\n", uc_strerror(err)); - return; + return 1; } loop: err = uc_mem_map(uc, stkval, STACK_SIZE, UC_PROT_ALL); if(err != UC_ERR_OK) { printf("Failed to map memory %s\n", uc_strerror(err)); - return; + return 1; } err = uc_mem_write(uc, ESP, &val, sizeof(val)); if(err != UC_ERR_OK) { printf("Failed to write to memory %s\n", uc_strerror(err)); - return; + return 1; } @@ -88,7 +88,7 @@ loop: printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); uc_close(uc); - return; + return 1; } uc_reg_read(uc, UC_X86_REG_EAX, &EAX); From 5acb454b7b59e55f35146681e9164126a971ae61 Mon Sep 17 00:00:00 2001 From: xorstream Date: Wed, 16 Dec 2015 13:46:14 +1100 Subject: [PATCH 38/40] Fixed the unicorn_dynload.c version of uc_hook_add() to handle UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED. --- bindings/msvc/unicorn_dynload.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bindings/msvc/unicorn_dynload.c b/bindings/msvc/unicorn_dynload.c index 0c6a7eee..ca9b4e2a 100644 --- a/bindings/msvc/unicorn_dynload.c +++ b/bindings/msvc/unicorn_dynload.c @@ -232,9 +232,17 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *u va_start(valist, user_data); switch(type) { + // note this default case will capture any combinations of + // UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED default: - break; case UC_HOOK_INTR: + case UC_HOOK_MEM_READ_UNMAPPED: + case UC_HOOK_MEM_WRITE_UNMAPPED: + case UC_HOOK_MEM_FETCH_UNMAPPED: + case UC_HOOK_MEM_READ_PROT: + case UC_HOOK_MEM_WRITE_PROT: + case UC_HOOK_MEM_FETCH_PROT: + case UC_HOOK_MEM_FETCH: // 0 extra args ret = gp_uc_hook_add(uc, hh, type, callback, user_data); break; @@ -248,7 +256,7 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *u case UC_HOOK_MEM_READ: case UC_HOOK_MEM_WRITE: case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE: - // 2 extra arg + // 2 extra args begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end); From 7b73a298c19e4e75d90c3b301c18eb16cab32b07 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 16 Dec 2015 23:00:42 +0800 Subject: [PATCH 39/40] update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 05a649f5..5a0db103 100644 --- a/.gitignore +++ b/.gitignore @@ -121,6 +121,7 @@ invalid_read_in_tb_flush_x86_64 sparc_jump_to_zero mem_nofree mips_delay_slot_code_hook +threaded_emu_start test_mem_high rw_hookstack From 8d3265d9e19495df069829dcc3621dcc1d12d166 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 16 Dec 2015 23:06:17 +0800 Subject: [PATCH 40/40] mips: remove unused variable is_bc_slot --- qemu/target-mips/translate.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index 2be3375d..e7b7e24c 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -11322,7 +11322,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) return 4; } -static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot, bool *insn_need_patch) +static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; @@ -13930,7 +13930,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, } } -static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot, bool *insn_need_patch) +static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch) { TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; @@ -18507,7 +18507,7 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) } } -static void decode_opc (CPUMIPSState *env, DisasContext *ctx, bool is_bc_slot, bool *insn_need_patch) +static void decode_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; #if defined(TARGET_MIPS64) @@ -19176,7 +19176,6 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, int max_insns; int insn_bytes; int is_slot = 0; - bool is_bc_slot = false; TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGArg *save_opparam_ptr = NULL; bool block_full = false; @@ -19279,18 +19278,17 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, save_opparam_ptr = tcg_ctx->gen_opparam_ptr; is_slot = ctx.hflags & MIPS_HFLAG_BMASK; - is_bc_slot = (is_slot & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BC; if (!(ctx.hflags & MIPS_HFLAG_M16)) { ctx.opcode = cpu_ldl_code(env, ctx.pc); insn_bytes = 4; - decode_opc(env, &ctx, is_bc_slot, &insn_need_patch); + decode_opc(env, &ctx, &insn_need_patch); } else if (ctx.insn_flags & ASE_MICROMIPS) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_micromips_opc(env, &ctx, is_bc_slot, &insn_need_patch); + insn_bytes = decode_micromips_opc(env, &ctx, &insn_need_patch); } else if (ctx.insn_flags & ASE_MIPS16) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_mips16_opc(env, &ctx, is_bc_slot, &insn_need_patch); + insn_bytes = decode_mips16_opc(env, &ctx, &insn_need_patch); } else { generate_exception(&ctx, EXCP_RI); ctx.bstate = BS_STOP;