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_ +