diff --git a/.gitignore b/.gitignore index f58e52e7..5a0db103 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.dSYM *.so *.so.* +*.exe qemu/config-all-devices.mak @@ -77,6 +78,7 @@ unicorn.pc unicorn.lib unicorn.dll unicorn_*.lib +unicorn_*.exp unicorn_*.dll @@ -113,6 +115,16 @@ eflags_noset 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 +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 ################# @@ -123,6 +135,8 @@ invalid_write_in_cpu_tb_exec_x86_64 ## files generated by popular Visual Studio add-ons. # User-specific files +*.opensdf +*.sdf *.suo *.user *.sln.docstates @@ -132,6 +146,7 @@ invalid_write_in_cpu_tb_exec_x86_64 [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/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index a9aeca2d..4f6f1f99 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -29,6 +29,7 @@ type Unicorn interface { MemMap(addr, size uint64) error MemMapProt(addr, size uint64, prot int) error MemMapPtr(addr, size uint64, prot int, ptr unsafe.Pointer) 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 @@ -133,6 +134,10 @@ func (u *uc) MemMapPtr(addr, size uint64, prot int, ptr unsafe.Pointer) error { return errReturn(C.uc_mem_map_ptr(u.handle, C.uint64_t(addr), C.size_t(size), C.uint32_t(prot), ptr)) } +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))) } diff --git a/bindings/msvc/README.TXT b/bindings/msvc/README.TXT new file mode 100644 index 00000000..29bc2508 --- /dev/null +++ b/bindings/msvc/README.TXT @@ -0,0 +1,187 @@ + + +:: 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++. + +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. + +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 + +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 + + + + +:: 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/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/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..c9a24001 --- /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 "unicorn_dynload.h" +#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.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..ca9b4e2a --- /dev/null +++ b/bindings/msvc/unicorn_dynload.c @@ -0,0 +1,290 @@ +// +// 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 +// + +// 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 +#endif + +#include "unicorn_dynload.h" + +#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) { + // note this default case will capture any combinations of + // UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED + default: + 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; + 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 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); + 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); +} + +#endif // DYNLOAD diff --git a/bindings/msvc/unicorn_dynload.h b/bindings/msvc/unicorn_dynload.h new file mode 100644 index 00000000..638f5250 --- /dev/null +++ b/bindings/msvc/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 + +#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 + diff --git a/qemu/memory.c b/qemu/memory.c index 2d2e21a4..26683230 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -86,6 +86,9 @@ 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); + g_free((char *)mr->name); + g_free(mr->ioeventfds); break; } } @@ -93,13 +96,20 @@ 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/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index c1941505..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) +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; @@ -11343,10 +11343,12 @@ 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) + 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 *insn_need_patch) { TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; @@ -13943,10 +13945,12 @@ 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) + 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 *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; @@ -18523,10 +18526,12 @@ 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) { + if (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) { @@ -19171,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; @@ -19268,23 +19272,23 @@ 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; 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); + 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_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_bytes = decode_mips16_opc(env, &ctx, &insn_need_patch); } else { generate_exception(&ctx, EXCP_RI); ctx.bstate = BS_STOP; @@ -19292,7 +19296,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; } 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/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); } diff --git a/samples/mem_apis.c b/samples/mem_apis.c index 8ec4c715..50554eeb 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 "unicorn_dynload.h" +#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,25 @@ 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..c900e078 --- /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", "msvc_mem_apis\mem_apis.vcxproj", "{ECA2292F-FD4F-4943-B0FC-093B6D35FEBA}" +EndProject +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", "msvc_sample_arm64\sample_arm64.vcxproj", "{43AEBCD7-BD18-4F0D-8AF8-536F62F92AAD}" +EndProject +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", "msvc_sample_mips\sample_mips.vcxproj", "{5E004A76-1625-44F1-A1EA-64C4FD15F642}" +EndProject +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", "msvc_sample_sparc\sample_sparc.vcxproj", "{2906001D-9B80-4400-8B3A-4445CDAED54F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shellcode", "msvc_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/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 diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 48f3ebf2..8a5067db 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 "unicorn_dynload.h" +#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,25 @@ 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..39d500aa 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 "unicorn_dynload.h" +#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,23 @@ 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..efda5294 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 "unicorn_dynload.h" +#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,23 @@ 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..3f37b189 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 "unicorn_dynload.h" +#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,24 @@ 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..e966f5af 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 "unicorn_dynload.h" +#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,23 @@ 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 910af989..c57043d2 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 "unicorn_dynload.h" +#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 @@ -862,7 +882,18 @@ 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_map_ptr(); @@ -894,5 +925,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..a6fd5221 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 "unicorn_dynload.h" +#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; } diff --git a/tests/regress/Makefile b/tests/regress/Makefile index a438aeaf..cec787df 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 @@ -18,6 +24,14 @@ TESTS += eflags_noset TESTS += mem_map_large TESTS += invalid_read_in_cpu_tb_exec TESTS += invalid_write_in_cpu_tb_exec_x86_64 +TESTS += x86_16_segfault +TESTS += mips_invalid_read_of_size_4_when_tracing +TESTS += invalid_read_in_tb_flush_x86_64 +TESTS += sparc_jump_to_zero +TESTS += mips_delay_slot_code_hook +TESTS += mem_nofree +TESTS += rw_hookstack +TESTS += threaded_emu_start all: $(TESTS) 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; +} 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; +} 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)) 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..905cad8d --- /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; +} + 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; +} diff --git a/tests/regress/rw_hookstack.c b/tests/regress/rw_hookstack.c new file mode 100644 index 00000000..e04dd64c --- /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 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 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 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 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 1; + } + + + 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 1; + } + + 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; +} diff --git a/tests/regress/sparc_jump_to_zero.c b/tests/regress/sparc_jump_to_zero.c new file mode 100644 index 00000000..99148f2f --- /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\x00\x00" + +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; +} 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; +} + 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; +} diff --git a/tests/unit/Makefile b/tests/unit/Makefile index ea3c43f9..2b53e8e8 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 test_mem_map_ptr +ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr .PHONY: all all: ${ALL_TESTS} @@ -24,6 +24,7 @@ test_sanity: test_sanity.c test_x86: test_x86.c test_mem_map: test_mem_map.c test_mem_map_ptr: test_mem_map_ptr.c +test_mem_high: test_mem_high.c ${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..5e2244e5 --- /dev/null +++ b/tests/unit/test_mem_high.c @@ -0,0 +1,125 @@ +/** + * 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 +#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%"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 +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); + } +} + +//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 %"PRIx64, 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 + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/uc.c b/uc.c index 603cf068..a2944630 100644 --- a/uc.c +++ b/uc.c @@ -258,6 +258,8 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) UNICORN_EXPORT uc_err uc_close(uc_engine *uc) { + int i; + if (uc->release) uc->release(uc->tcg_ctx); @@ -275,7 +277,6 @@ uc_err uc_close(uc_engine *uc) 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]); } @@ -579,6 +580,10 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per // 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; @@ -851,7 +856,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];