diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..532843b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,65 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +*.cpp diff + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d9981d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,160 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +.vs +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +bin.*/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +# Not needed anymore: !packages/*/build/ +packages/ +*.nupkg + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +!lib.*/*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/ + +#LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store diff --git a/InjectDll/InjectDll.vcxproj b/InjectDll/InjectDll.vcxproj new file mode 100644 index 0000000..74f933f --- /dev/null +++ b/InjectDll/InjectDll.vcxproj @@ -0,0 +1,181 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {9BB3F6F3-87B1-4541-A709-2C80967C97EE} + Win32Proj + InjectDll + 10.0.17134.0 + + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)bin\ + $(ProjectName)32 + + + true + $(SolutionDir)bin.$(PlatformTarget)\ + + + false + $(SolutionDir)bin.$(PlatformTarget)\ + $(ProjectName)32 + + + false + $(SolutionDir)bin.$(PlatformTarget)\ + + + + NotUsing + Level3 + Disabled + true + WIN32;_DEBUG;INJECTDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + MultiThreadedDebug + + + Windows + true + Source.def + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + true + _DEBUG;INJECTDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + + Windows + true + Source.def + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;INJECTDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + MultiThreaded + + + Windows + true + true + true + Source.def + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NDEBUG;INJECTDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + + Windows + true + true + true + Source.def + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/InjectDll/InjectDll.vcxproj.filters b/InjectDll/InjectDll.vcxproj.filters new file mode 100644 index 0000000..ee2d994 --- /dev/null +++ b/InjectDll/InjectDll.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/InjectDll/Source.def b/InjectDll/Source.def new file mode 100644 index 0000000..b3b601c --- /dev/null +++ b/InjectDll/Source.def @@ -0,0 +1,3 @@ +LIBRARY InjectDll32 +EXPORTS + DetourFinishHelperProcess @1 \ No newline at end of file diff --git a/InjectDll/dllmain.cpp b/InjectDll/dllmain.cpp new file mode 100644 index 0000000..a7d999f Binary files /dev/null and b/InjectDll/dllmain.cpp differ diff --git a/InjectDll/targetver.h b/InjectDll/targetver.h new file mode 100644 index 0000000..567cd34 Binary files /dev/null and b/InjectDll/targetver.h differ diff --git a/InjectDll64/InjectDll64.vcxproj b/InjectDll64/InjectDll64.vcxproj new file mode 100644 index 0000000..ae89d09 --- /dev/null +++ b/InjectDll64/InjectDll64.vcxproj @@ -0,0 +1,179 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {82864E7A-BBCC-47E5-9A85-A6999B1B1560} + Win32Proj + InjectDll + 10.0.17134.0 + + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)bin.$(PlatformTarget)\ + + + true + $(SolutionDir)bin\ + + + false + $(SolutionDir)bin.$(PlatformTarget)\ + + + false + $(SolutionDir)bin.$(PlatformTarget)\ + + + + NotUsing + Level3 + Disabled + true + WIN32;_DEBUG;INJECTDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + + Windows + true + Source.def + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + true + _DEBUG;INJECTDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + MultiThreadedDebug + + + Windows + true + Source.def + $(SolutionDir)lib.x64\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;INJECTDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + + Windows + true + true + true + Source.def + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NDEBUG;INJECTDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + MultiThreaded + + + Windows + true + true + true + Source.def + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/InjectDll64/InjectDll64.vcxproj.filters b/InjectDll64/InjectDll64.vcxproj.filters new file mode 100644 index 0000000..f1df2dd --- /dev/null +++ b/InjectDll64/InjectDll64.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/InjectDll64/Source.def b/InjectDll64/Source.def new file mode 100644 index 0000000..3753171 --- /dev/null +++ b/InjectDll64/Source.def @@ -0,0 +1,3 @@ +LIBRARY InjectDll64 +EXPORTS + DetourFinishHelperProcess @1 \ No newline at end of file diff --git a/InjectDll64/targetver.h b/InjectDll64/targetver.h new file mode 100644 index 0000000..567cd34 Binary files /dev/null and b/InjectDll64/targetver.h differ diff --git a/README.md b/README.md index d956918..68fa6f3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,98 @@ -# takedetour -A template (and a sample) for writing tracers on Windows. Based on the Detours library. + +# TakeDetour + +This project is a template for building tracers on Windows. It wraps the excellent [Microsoft Detours library](https://github.com/Microsoft/Detours) to create a self-contained, single binary with all the hooking functions you define. As an example, I hooked the `CreateDirectory` function so running the [TakeDetour.exe](https://github.com/lowleveldesign/takedetour/releases) with any application prints all the calls to this function on the Windows Debug Output (you may use [DebugView](https://docs.microsoft.com/en-us/sysinternals/downloads/debugview) to see it). For example: + +``` +PS> .\TakeDetour.exe -w c:\windows\system32\notepad.exe +INFO: Starting the 'c:\windows\system32\notepad.exe' process. + +Press Ctrl + C to stop the target process. +``` + +Start the DebugView and make sure **Capture -> Capture Global Win32** is checked. Then, open the **New File** dialog in notepad, and you should see trace messages appearing in the DebugView window: + +![DebugView output](dbgview_output.png) + +**The released executable works on all Windows system starting from 7 and can hook both 32-bit and 64-bit applications.** + +## What this project contains + +I implemented two ways of interacting with a target process. You may either **start a new process** or **attach to an existing process**. The first way uses the [`DetourCreateProcessWithDllEx`](https://github.com/Microsoft/Detours/wiki/DetourCreateProcessWithDllEx) function from the Detours library. The latter injects the DLL using the remote thread. + +Whether you start a new process or attach to an existing one, you may add the **-w** argument to control the injection process. This option makes the application to wait for a **Ctrl + C** event or a target process termination. When a user presses Ctrl + C after attaching to a process, the injected DLL is detached, and the target process continues running. Pressing Ctrl + C after starting a new process forces the target process to terminate. + +All the dependencies are embedded as binary resources, and TakeDetour unpacks them to a temporary folder (`%TEMP%\takedetour`) on start. The default executable is 32-bit. Thus, to hook a 64-bit process it needs to spawn a helper process. When running TakeDetour on a 64-bit system, remember that the Wow64 engine maps some folder paths. For example: `TakeDetour c:\Windows\System32\notepad.exe` will start a 32-bit notepad.exe. To start the 64-bit version, use `TakeDetour c:\Windows\sysnative\notepad.exe`. + +The injected dll name is InjectDll32.dll for 32-bit process and InjectDll64.dll for 64-bit processes. + +## How to add your hooks + +Open the TakeDetours.sln file in **Visual Studio 2017** and edit the **InjectDll\dllmain.cpp** file. You may want to check [Detours Wiki](https://github.com/Microsoft/Detours/wiki) first to learn how to hook methods with the Detours API. + +You usually start with the hook definition, for example: + +```cpp +static BOOL(WINAPI * TrueCreateDirectory)( + LPCWSTR lpPathName, + LPSECURITY_ATTRIBUTES lpSecurityAttributes +) = CreateDirectory; + +BOOL WINAPI TracedCreateDirectory( + LPCWSTR lpPathName, + LPSECURITY_ATTRIBUTES lpSecurityAttributes +) +{ + wostringstream output; + output << L"Traced CreateDirectory: " << lpPathName; + OutputDebugString(output.str().c_str()); + + return TrueCreateDirectory(lpPathName, lpSecurityAttributes); +} +``` + +Later, you need to enable your hooks in the DllMain method. Please modify only the `DLL_PROCESS_ATTACH` and `DLL_PROCESS_DETACH` blocks. For example: + +```cpp +BOOL APIENTRY DllMain(HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved +) +{ + ... + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + DetourRestoreAfterWith(); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourAttach(&(PVOID&)TrueCreateDirectory, TracedCreateDirectory); + // TODO: add your hooks here + error = DetourTransactionCommit(); + if (error != NO_ERROR) { + wostringstream output; + output << L"Error detouring: " << error; + OutputDebugString(output.str().c_str()); + } + break; + ... + case DLL_PROCESS_DETACH: + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourDetach(&(PVOID&)TrueCreateDirectory, TracedCreateDirectory); + // TODO: add your hooks here + error = DetourTransactionCommit(); + if (error != NO_ERROR) { + wostringstream output; + output << L"Error detouring: " << error; + OutputDebugString(output.str().c_str()); + } + break; + } + ... +} +``` + +## Reporting bugs + +If you find a bug or have an idea for improvement, please add it to the [Issues](https://github.com/lowleveldesign/takedetour/issues) list. diff --git a/TakeDetour.sln b/TakeDetour.sln new file mode 100644 index 0000000..2589c7b --- /dev/null +++ b/TakeDetour.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TakeDetour", "TakeDetour\TakeDetour.vcxproj", "{275575D6-7FA1-42CB-9119-BCC3C548989A}" + ProjectSection(ProjectDependencies) = postProject + {202EF952-2AF9-45D7-A7D2-CF08C16EAE1E} = {202EF952-2AF9-45D7-A7D2-CF08C16EAE1E} + {82864E7A-BBCC-47E5-9A85-A6999B1B1560} = {82864E7A-BBCC-47E5-9A85-A6999B1B1560} + {9BB3F6F3-87B1-4541-A709-2C80967C97EE} = {9BB3F6F3-87B1-4541-A709-2C80967C97EE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectDll", "InjectDll\InjectDll.vcxproj", "{9BB3F6F3-87B1-4541-A709-2C80967C97EE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectDll64", "InjectDll64\InjectDll64.vcxproj", "{82864E7A-BBCC-47E5-9A85-A6999B1B1560}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TakeDetour64", "TakeDetour64\TakeDetour64.vcxproj", "{202EF952-2AF9-45D7-A7D2-CF08C16EAE1E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {275575D6-7FA1-42CB-9119-BCC3C548989A}.Debug|x86.ActiveCfg = Debug|Win32 + {275575D6-7FA1-42CB-9119-BCC3C548989A}.Debug|x86.Build.0 = Debug|Win32 + {275575D6-7FA1-42CB-9119-BCC3C548989A}.Release|x86.ActiveCfg = Release|Win32 + {275575D6-7FA1-42CB-9119-BCC3C548989A}.Release|x86.Build.0 = Release|Win32 + {9BB3F6F3-87B1-4541-A709-2C80967C97EE}.Debug|x86.ActiveCfg = Debug|Win32 + {9BB3F6F3-87B1-4541-A709-2C80967C97EE}.Debug|x86.Build.0 = Debug|Win32 + {9BB3F6F3-87B1-4541-A709-2C80967C97EE}.Release|x86.ActiveCfg = Release|Win32 + {9BB3F6F3-87B1-4541-A709-2C80967C97EE}.Release|x86.Build.0 = Release|Win32 + {82864E7A-BBCC-47E5-9A85-A6999B1B1560}.Debug|x86.ActiveCfg = Debug|x64 + {82864E7A-BBCC-47E5-9A85-A6999B1B1560}.Debug|x86.Build.0 = Debug|x64 + {82864E7A-BBCC-47E5-9A85-A6999B1B1560}.Release|x86.ActiveCfg = Release|x64 + {82864E7A-BBCC-47E5-9A85-A6999B1B1560}.Release|x86.Build.0 = Release|x64 + {202EF952-2AF9-45D7-A7D2-CF08C16EAE1E}.Debug|x86.ActiveCfg = Debug|x64 + {202EF952-2AF9-45D7-A7D2-CF08C16EAE1E}.Debug|x86.Build.0 = Debug|x64 + {202EF952-2AF9-45D7-A7D2-CF08C16EAE1E}.Release|x86.ActiveCfg = Release|x64 + {202EF952-2AF9-45D7-A7D2-CF08C16EAE1E}.Release|x86.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2CDAF843-1DE6-4A47-95BA-58F6C3EC421F} + EndGlobalSection +EndGlobal diff --git a/TakeDetour/Detouring.cpp b/TakeDetour/Detouring.cpp new file mode 100644 index 0000000..b8e4fe4 --- /dev/null +++ b/TakeDetour/Detouring.cpp @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Detouring.h" +#include "../include/detours.h" + +using namespace std; + +string ws2s(const std::wstring& wstr) +{ + using convert_typeX = std::codecvt_utf8; + std::wstring_convert converterX; + + return converterX.to_bytes(wstr); +} + +//---------------------------------------------------------------- + +void ThrowWin32Exception(const char *funcname) +{ + DWORD dwError = GetLastError(); + ostringstream os; + os << funcname << " failed: 0x" << hex << dwError << endl; + throw exception(os.str().c_str()); +} + +//---------------------------------------------------------------- + +HANDLE StartProcess(const string& injectdll, const wstring& exe, const wstring& args) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + ZeroMemory(&pi, sizeof(pi)); + si.cb = sizeof(si); + + auto command = make_unique(args.length() + 1); + wmemcpy_s(command.get(), args.length(), args.c_str(), args.length()); + command.get()[args.length()] = L'\0'; + + if (!DetourCreateProcessWithDllEx(exe.c_str(), command.get(), + NULL, NULL, TRUE, + CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED, + NULL, NULL, &si, &pi, injectdll.c_str(), NULL)) { + ThrowWin32Exception("DetourCreateProcessWithDllEx"); + } + + ResumeThread(pi.hThread); + CloseHandle(pi.hThread); + + return pi.hProcess; +} + +//---------------------------------------------------------------- + +BOOL CALLBACK EnumerateExportCallback(PVOID pContext, ULONG nOrdinal, LPCSTR pszName, PVOID pCode) +{ + FunctionCharacteristics* func = reinterpret_cast(pContext); + if (strcmp(func->FunctionName, pszName) == 0) { + *(func->FunctionAddress) = pCode; + return FALSE; + } + return TRUE; +} + +//---------------------------------------------------------------- + +HMODULE LocateModuleInRemoteProcess(HANDLE hProcess, const wstring& modulePath) +{ + HMODULE modules[1024]; + DWORD cb = sizeof(modules); + DWORD requiredcb; + if (!EnumProcessModules(hProcess, modules, cb, &requiredcb)) { + ThrowWin32Exception("EnumProcessModules"); + } + + if (requiredcb > cb) { + throw exception("EnumProcessModules failed: the modules buffer was too small."); + } + + for (DWORD i = 0; i < requiredcb / sizeof(HMODULE); i++) { + wchar_t moduleName[MAX_PATH]; + DWORD moduleNameLength = GetModuleFileNameEx(hProcess, modules[i], moduleName, sizeof(moduleName) / sizeof(wchar_t)); + // FIXME: if moduleNameLength == MAX_PATH there is chance the module name array was too small + if (moduleNameLength == 0) { + ThrowWin32Exception("GetModuleFileNameEx"); + } + if (moduleNameLength >= modulePath.length() + && _wcsicmp(modulePath.c_str(), moduleName + moduleNameLength - modulePath.length()) == 0) { + return modules[i]; + } + } + return NULL; +} + +//---------------------------------------------------------------- + +// Return address of the LoadLibrary function in the remote process +PVOID LocateExportedFunctionInModule(HMODULE moduleHandle, const char* functionName) +{ + // we found the kernel32.dll + PVOID functionAddress = nullptr; + FunctionCharacteristics context = { functionName, &functionAddress }; + if (!DetourEnumerateExports(moduleHandle, &context, EnumerateExportCallback)) { + ThrowWin32Exception("DetourEnumerateExports"); + } + return functionAddress; +} + +//---------------------------------------------------------------- + +HANDLE AttachToProcess(DWORD pid, const wstring& injectdll) +{ + DWORD flags = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | PROCESS_VM_READ | SYNCHRONIZE; + HANDLE targetProcess = OpenProcess(flags, FALSE, pid); + if (targetProcess == NULL) { + ThrowWin32Exception("OpenProcess"); + } + + HMODULE kernel32 = LocateModuleInRemoteProcess(targetProcess, L"\\kernel32.dll"); + if (!kernel32) { + throw exception("Can't find kernel32.dll in the remote process."); + } + + PVOID LoadLibraryWAddress = LocateExportedFunctionInModule(kernel32, "LoadLibraryW"); + assert(LoadLibraryWAddress != NULL); + + // allocate injection buffer + SIZE_T injectdllLengthInBytes = (injectdll.length() + 1) * sizeof(wchar_t); + PBYTE injectionBuffer = (PBYTE)VirtualAllocEx(targetProcess, NULL, injectdllLengthInBytes, + MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (!injectionBuffer) { + ThrowWin32Exception("VirtualAllocEx"); + } + SIZE_T n; + if (!WriteProcessMemory(targetProcess, injectionBuffer, injectdll.c_str(), injectdllLengthInBytes, &n) + || n != injectdllLengthInBytes) { + ThrowWin32Exception("WriteProcessMemory"); + } + + HANDLE injectedThread; + DWORD injecteeThreadId; + injectedThread = CreateRemoteThread(targetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryWAddress, + injectionBuffer, 0, &injecteeThreadId); + if (!injectedThread) { + ThrowWin32Exception("CreateRemoteThread"); + } + + if (WaitForSingleObject(injectedThread, INFINITE) == WAIT_FAILED) { + ThrowWin32Exception("WaitForSingleObject (remote thread)"); + } + CloseHandle(injectedThread); + + if (!VirtualFreeEx(targetProcess, injectionBuffer, 0, MEM_RELEASE)) { + ThrowWin32Exception("VirtualFreeEx"); + } + + return targetProcess; +} + +//---------------------------------------------------------------- + +void DetachFromProcess(HANDLE targetProcess, const wstring& injectdll) +{ + HMODULE modules[1024]; + DWORD cb = sizeof(modules); + DWORD requiredcb; + if (!EnumProcessModules(targetProcess, modules, cb, &requiredcb)) { + ThrowWin32Exception("EnumProcessModules"); + } + + HMODULE kernel32 = LocateModuleInRemoteProcess(targetProcess, L"\\kernel32.dll"); + if (!kernel32) { + throw exception("Can't find kernel32.dll in the remote process."); + } + PVOID FreeLibraryAddress = LocateExportedFunctionInModule(kernel32, "FreeLibrary"); + assert(FreeLibraryAddress != NULL); + + HMODULE injectdllHandle = LocateModuleInRemoteProcess(targetProcess, injectdll); + if (injectdllHandle == NULL) { + throw exception("Can't find the injected dll in the remote process."); + } + + HANDLE injectedThread; + DWORD injecteeThreadId; + injectedThread = CreateRemoteThread(targetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibraryAddress, + injectdllHandle, 0, &injecteeThreadId); + if (!injectedThread) { + ThrowWin32Exception("CreateRemoteThread"); + } + + if (WaitForSingleObject(injectedThread, INFINITE) == WAIT_FAILED) { + ThrowWin32Exception("WaitForSingleObject (remote thread)"); + } + CloseHandle(injectedThread); +} \ No newline at end of file diff --git a/TakeDetour/Detouring.h b/TakeDetour/Detouring.h new file mode 100644 index 0000000..ba91920 --- /dev/null +++ b/TakeDetour/Detouring.h @@ -0,0 +1,12 @@ +#pragma once + +typedef struct { + PCCH FunctionName; + PVOID* FunctionAddress; +} FunctionCharacteristics; + +void ThrowWin32Exception(const char *funcname); +std::string ws2s(const std::wstring& wstr); +HANDLE StartProcess(const std::string& injectdll, const std::wstring& exe, const std::wstring& args); +HANDLE AttachToProcess(DWORD pid, const std::wstring& injectdll); +void DetachFromProcess(HANDLE targetProcess, const std::wstring& injectdll); diff --git a/TakeDetour/TakeDetour.cpp b/TakeDetour/TakeDetour.cpp new file mode 100644 index 0000000..4065fde Binary files /dev/null and b/TakeDetour/TakeDetour.cpp differ diff --git a/TakeDetour/TakeDetour.rc b/TakeDetour/TakeDetour.rc new file mode 100644 index 0000000..175f643 Binary files /dev/null and b/TakeDetour/TakeDetour.rc differ diff --git a/TakeDetour/TakeDetour.vcxproj b/TakeDetour/TakeDetour.vcxproj new file mode 100644 index 0000000..2dd7197 --- /dev/null +++ b/TakeDetour/TakeDetour.vcxproj @@ -0,0 +1,186 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {275575D6-7FA1-42CB-9119-BCC3C548989A} + Win32Proj + TakeDetour + 10.0.17134.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)bin\ + + + true + $(SolutionDir)bin.$(PlatformTarget)\ + + + false + $(SolutionDir)bin.$(PlatformTarget)\ + + + false + $(SolutionDir)bin.$(PlatformTarget)\ + + + + NotUsing + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + MultiThreadedDebug + + + Console + true + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_AMD64_ + true + + + + + Console + true + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + MultiThreaded + + + Console + true + true + true + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_AMD64_ + true + + + + + Console + true + true + true + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TakeDetour/TakeDetour.vcxproj.filters b/TakeDetour/TakeDetour.vcxproj.filters new file mode 100644 index 0000000..e575f13 --- /dev/null +++ b/TakeDetour/TakeDetour.vcxproj.filters @@ -0,0 +1,43 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + + + + + + \ No newline at end of file diff --git a/TakeDetour/resource.h b/TakeDetour/resource.h new file mode 100644 index 0000000..fb44f76 --- /dev/null +++ b/TakeDetour/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by TakeDetour.rc +// +#define IDR_BINARY2 102 +#define IDR_BINARY1 103 +#define IDR_BINARY3 104 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/TakeDetour64/TakeDetour.cpp b/TakeDetour64/TakeDetour.cpp new file mode 100644 index 0000000..b919cb8 --- /dev/null +++ b/TakeDetour64/TakeDetour.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../TakeDetour/Detouring.h" + +#include "../include/detours.h" + +using namespace std; + +bool stopRequested = false; + +BOOL WINAPI HandleConsoleInterrupt(DWORD dwCtrlType); + +int32_t wmain(int32_t argc, wchar_t *argv[]) +{ + assert(argc >= 2); + + int argumentIndex = 1; + bool waitForTarget = false; + if (wcscmp(argv[1], L"-w") == 0) { + waitForTarget = true; + argumentIndex++; + } + + DWORD pid = wcstoul(argv[argumentIndex], nullptr, 10); + // this version can only attach to a process + assert(pid != 0); + try { + wchar_t buffer[MAX_PATH]; + DWORD len = GetModuleFileName(NULL, buffer, MAX_PATH); + // FIXME: if moduleNameLength == MAX_PATH there is chance the module name array was too small + if (len == 0) { + ThrowWin32Exception("GetModuleFileName"); + } + wstring binaryPath = buffer; + auto separatorIndex = binaryPath.find_last_of(L"\\/"); + assert(separatorIndex != string::npos); + if (separatorIndex == string::npos) { + throw exception("Bad entry binary path"); + } + wstring injectdll = binaryPath.substr(0, separatorIndex) + L"\\InjectDll64.dll"; + cout << "INFO: Attaching to the target process (" << pid << ")." << endl; + HANDLE targetProcess = AttachToProcess(pid, injectdll); + + if (!SetConsoleCtrlHandler(HandleConsoleInterrupt, TRUE)) { + ThrowWin32Exception("SetConsoleCtrlHandler"); + } + if (waitForTarget) { + cout << endl << "Press Ctrl + C to stop and unload the DLL from the target process." << endl; + while (!stopRequested) { + DWORD waitResult = WaitForSingleObject(targetProcess, 200); + if (waitResult == WAIT_OBJECT_0) { + cout << "INFO: Target process exited. Stopping." << endl; + break; + } + if (waitResult == WAIT_FAILED) { + ThrowWin32Exception("WaitForSingleObject"); + } + } + + DWORD exitCode; + if (stopRequested && GetExitCodeProcess(targetProcess, &exitCode) && exitCode == STILL_ACTIVE) { + DetachFromProcess(targetProcess, injectdll); + } + } + CloseHandle(targetProcess); + } catch (exception& ex) { + cerr << endl << "ERROR: " << ex.what() << endl; + return 1; + } + + return 0; +} + +BOOL WINAPI HandleConsoleInterrupt(DWORD dwCtrlType) +{ + cout << "INFO: Received Ctrl + C. Stopping." << endl; + stopRequested = true; + return TRUE; +} \ No newline at end of file diff --git a/TakeDetour64/TakeDetour64.vcxproj b/TakeDetour64/TakeDetour64.vcxproj new file mode 100644 index 0000000..9f1ebe2 --- /dev/null +++ b/TakeDetour64/TakeDetour64.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + 15.0 + {202EF952-2AF9-45D7-A7D2-CF08C16EAE1E} + Win32Proj + TakeDetour + 10.0.17134.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)bin.$(PlatformTarget)\ + + + true + $(SolutionDir)bin\ + + + false + $(SolutionDir)bin.$(PlatformTarget)\ + + + false + $(SolutionDir)bin.$(PlatformTarget)\ + + + + NotUsing + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + + + Console + true + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_AMD64_ + true + + + MultiThreadedDebug + + + Console + true + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + + + Console + true + true + true + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_AMD64_ + true + + + MultiThreaded + + + Console + true + true + true + $(SolutionDir)lib.$(PlatformTarget)\detours.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/TakeDetour64/TakeDetour64.vcxproj.filters b/TakeDetour64/TakeDetour64.vcxproj.filters new file mode 100644 index 0000000..0a37d01 --- /dev/null +++ b/TakeDetour64/TakeDetour64.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/dbgview_output.png b/dbgview_output.png new file mode 100644 index 0000000..aab388a Binary files /dev/null and b/dbgview_output.png differ diff --git a/include/detours.h b/include/detours.h new file mode 100644 index 0000000..faff4fe --- /dev/null +++ b/include/detours.h @@ -0,0 +1,1075 @@ +///////////////////////////////////////////////////////////////////////////// +// +// Core Detours Functionality (detours.h of detours.lib) +// +// Microsoft Research Detours Package, Version 4.0.1 +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#pragma once +#ifndef _DETOURS_H_ +#define _DETOURS_H_ + +#define DETOURS_VERSION 0x4c0c1 // 0xMAJORcMINORcPATCH + +////////////////////////////////////////////////////////////////////////////// +// + +#undef DETOURS_X64 +#undef DETOURS_X86 +#undef DETOURS_IA64 +#undef DETOURS_ARM +#undef DETOURS_ARM64 +#undef DETOURS_BITS +#undef DETOURS_32BIT +#undef DETOURS_64BIT + +#if defined(_X86_) +#define DETOURS_X86 +#define DETOURS_OPTION_BITS 64 + +#elif defined(_AMD64_) +#define DETOURS_X64 +#define DETOURS_OPTION_BITS 32 + +#elif defined(_IA64_) +#define DETOURS_IA64 +#define DETOURS_OPTION_BITS 32 + +#elif defined(_ARM_) +#define DETOURS_ARM + +#elif defined(_ARM64_) +#define DETOURS_ARM64 + +#else +#error Unknown architecture (x86, amd64, ia64, arm, arm64) +#endif + +#ifdef _WIN64 +#undef DETOURS_32BIT +#define DETOURS_64BIT 1 +#define DETOURS_BITS 64 +// If all 64bit kernels can run one and only one 32bit architecture. +//#define DETOURS_OPTION_BITS 32 +#else +#define DETOURS_32BIT 1 +#undef DETOURS_64BIT +#define DETOURS_BITS 32 +// If all 64bit kernels can run one and only one 32bit architecture. +//#define DETOURS_OPTION_BITS 32 +#endif + +#define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) + +////////////////////////////////////////////////////////////////////////////// +// + +#if (_MSC_VER < 1299) +typedef LONG LONG_PTR; +typedef ULONG ULONG_PTR; +#endif + +///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. +// +// These definitions are include so that Detours will build even if the +// compiler doesn't have full SAL 2.0 support. +// +#ifndef DETOURS_DONT_REMOVE_SAL_20 + +#ifdef DETOURS_TEST_REMOVE_SAL_20 +#undef _Analysis_assume_ +#undef _Benign_race_begin_ +#undef _Benign_race_end_ +#undef _Field_range_ +#undef _Field_size_ +#undef _In_ +#undef _In_bytecount_ +#undef _In_count_ +#undef _In_opt_ +#undef _In_opt_bytecount_ +#undef _In_opt_count_ +#undef _In_opt_z_ +#undef _In_range_ +#undef _In_reads_ +#undef _In_reads_bytes_ +#undef _In_reads_opt_ +#undef _In_reads_opt_bytes_ +#undef _In_reads_or_z_ +#undef _In_z_ +#undef _Inout_ +#undef _Inout_opt_ +#undef _Inout_z_count_ +#undef _Out_ +#undef _Out_opt_ +#undef _Out_writes_ +#undef _Outptr_result_maybenull_ +#undef _Readable_bytes_ +#undef _Success_ +#undef _Writable_bytes_ +#undef _Pre_notnull_ +#endif + +#if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) +#define _Outptr_result_maybenull_ _Deref_out_opt_z_ +#endif + +#if defined(_In_count_) && !defined(_In_reads_) +#define _In_reads_(x) _In_count_(x) +#endif + +#if defined(_In_opt_count_) && !defined(_In_reads_opt_) +#define _In_reads_opt_(x) _In_opt_count_(x) +#endif + +#if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) +#define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) +#endif + +#if defined(_In_bytecount_) && !defined(_In_reads_bytes_) +#define _In_reads_bytes_(x) _In_bytecount_(x) +#endif + +#ifndef _In_ +#define _In_ +#endif + +#ifndef _In_bytecount_ +#define _In_bytecount_(x) +#endif + +#ifndef _In_count_ +#define _In_count_(x) +#endif + +#ifndef _In_opt_ +#define _In_opt_ +#endif + +#ifndef _In_opt_bytecount_ +#define _In_opt_bytecount_(x) +#endif + +#ifndef _In_opt_count_ +#define _In_opt_count_(x) +#endif + +#ifndef _In_opt_z_ +#define _In_opt_z_ +#endif + +#ifndef _In_range_ +#define _In_range_(x,y) +#endif + +#ifndef _In_reads_ +#define _In_reads_(x) +#endif + +#ifndef _In_reads_bytes_ +#define _In_reads_bytes_(x) +#endif + +#ifndef _In_reads_opt_ +#define _In_reads_opt_(x) +#endif + +#ifndef _In_reads_opt_bytes_ +#define _In_reads_opt_bytes_(x) +#endif + +#ifndef _In_reads_or_z_ +#define _In_reads_or_z_ +#endif + +#ifndef _In_z_ +#define _In_z_ +#endif + +#ifndef _Inout_ +#define _Inout_ +#endif + +#ifndef _Inout_opt_ +#define _Inout_opt_ +#endif + +#ifndef _Inout_z_count_ +#define _Inout_z_count_(x) +#endif + +#ifndef _Out_ +#define _Out_ +#endif + +#ifndef _Out_opt_ +#define _Out_opt_ +#endif + +#ifndef _Out_writes_ +#define _Out_writes_(x) +#endif + +#ifndef _Outptr_result_maybenull_ +#define _Outptr_result_maybenull_ +#endif + +#ifndef _Writable_bytes_ +#define _Writable_bytes_(x) +#endif + +#ifndef _Readable_bytes_ +#define _Readable_bytes_(x) +#endif + +#ifndef _Success_ +#define _Success_(x) +#endif + +#ifndef _Pre_notnull_ +#define _Pre_notnull_ +#endif + +#ifdef DETOURS_INTERNAL + +#pragma warning(disable:4615) // unknown warning type (suppress with older compilers) + +#ifndef _Benign_race_begin_ +#define _Benign_race_begin_ +#endif + +#ifndef _Benign_race_end_ +#define _Benign_race_end_ +#endif + +#ifndef _Field_size_ +#define _Field_size_(x) +#endif + +#ifndef _Field_range_ +#define _Field_range_(x,y) +#endif + +#ifndef _Analysis_assume_ +#define _Analysis_assume_(x) +#endif + +#endif // DETOURS_INTERNAL +#endif // DETOURS_DONT_REMOVE_SAL_20 + +////////////////////////////////////////////////////////////////////////////// +// +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[ 8 ]; +} GUID; + +#ifdef INITGUID +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name \ + = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name +#endif // INITGUID +#endif // !GUID_DEFINED + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#else // !__cplusplus +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID * const +#endif // !_REFGUID_DEFINED +#endif // !__cplusplus + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) +#endif + +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/////////////////////////////////////////////////// Instruction Target Macros. +// +#define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) +#define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) +#define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" + +extern const GUID DETOUR_EXE_RESTORE_GUID; +extern const GUID DETOUR_EXE_HELPER_GUID; + +#define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! +typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; + +/////////////////////////////////////////////////////////// Binary Structures. +// +#pragma pack(push, 8) +typedef struct _DETOUR_SECTION_HEADER +{ + DWORD cbHeaderSize; + DWORD nSignature; + DWORD nDataOffset; + DWORD cbDataSize; + + DWORD nOriginalImportVirtualAddress; + DWORD nOriginalImportSize; + DWORD nOriginalBoundImportVirtualAddress; + DWORD nOriginalBoundImportSize; + + DWORD nOriginalIatVirtualAddress; + DWORD nOriginalIatSize; + DWORD nOriginalSizeOfImage; + DWORD cbPrePE; + + DWORD nOriginalClrFlags; + DWORD reserved1; + DWORD reserved2; + DWORD reserved3; + + // Followed by cbPrePE bytes of data. +} DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; + +typedef struct _DETOUR_SECTION_RECORD +{ + DWORD cbBytes; + DWORD nReserved; + GUID guid; +} DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; + +typedef struct _DETOUR_CLR_HEADER +{ + // Header versioning + ULONG cb; + USHORT MajorRuntimeVersion; + USHORT MinorRuntimeVersion; + + // Symbol table and startup information + IMAGE_DATA_DIRECTORY MetaData; + ULONG Flags; + + // Followed by the rest of the IMAGE_COR20_HEADER +} DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER; + +typedef struct _DETOUR_EXE_RESTORE +{ + DWORD cb; + DWORD cbidh; + DWORD cbinh; + DWORD cbclr; + + PBYTE pidh; + PBYTE pinh; + PBYTE pclr; + + IMAGE_DOS_HEADER idh; + union { + IMAGE_NT_HEADERS inh; // all environments have this +#ifdef IMAGE_NT_OPTIONAL_HDR32_MAGIC // some environments do not have this + IMAGE_NT_HEADERS32 inh32; +#endif +#ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC // some environments do not have this + IMAGE_NT_HEADERS64 inh64; +#endif +#ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC // some environments do not have this + BYTE raw[sizeof(IMAGE_NT_HEADERS64) + + sizeof(IMAGE_SECTION_HEADER) * 32]; + C_ASSERT(sizeof(IMAGE_NT_HEADERS64) == 0x108); +#else + BYTE raw[0x108 + sizeof(IMAGE_SECTION_HEADER) * 32]; +#endif + }; + DETOUR_CLR_HEADER clr; + +} DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE; + +// The size can change, but assert for clarity due to the muddying #ifdefs. +#ifdef _WIN64 +C_ASSERT(sizeof(DETOUR_EXE_RESTORE) == 0x688); +#else +C_ASSERT(sizeof(DETOUR_EXE_RESTORE) == 0x678); +#endif + +typedef struct _DETOUR_EXE_HELPER +{ + DWORD cb; + DWORD pid; + DWORD nDlls; + CHAR rDlls[4]; +} DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER; + +#pragma pack(pop) + +#define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ +{ \ + sizeof(DETOUR_SECTION_HEADER),\ + DETOUR_SECTION_HEADER_SIGNATURE,\ + sizeof(DETOUR_SECTION_HEADER),\ + (cbSectionSize),\ + \ + 0,\ + 0,\ + 0,\ + 0,\ + \ + 0,\ + 0,\ + 0,\ + 0,\ +} + +/////////////////////////////////////////////////////////////// Helper Macros. +// +#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) +#define DETOURS_STRINGIFY_(x) #x + +///////////////////////////////////////////////////////////// Binary Typedefs. +// +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( + _In_opt_ PVOID pContext, + _In_opt_ LPCSTR pszFile, + _Outptr_result_maybenull_ LPCSTR *ppszOutFile); + +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( + _In_opt_ PVOID pContext, + _In_ LPCSTR pszOrigFile, + _In_ LPCSTR pszFile, + _Outptr_result_maybenull_ LPCSTR *ppszOutFile); + +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( + _In_opt_ PVOID pContext, + _In_ ULONG nOrigOrdinal, + _In_ ULONG nOrdinal, + _Out_ ULONG *pnOutOrdinal, + _In_opt_ LPCSTR pszOrigSymbol, + _In_opt_ LPCSTR pszSymbol, + _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); + +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( + _In_opt_ PVOID pContext); + +typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, + _In_ ULONG nOrdinal, + _In_opt_ LPCSTR pszName, + _In_opt_ PVOID pCode); + +typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, + _In_opt_ HMODULE hModule, + _In_opt_ LPCSTR pszFile); + +typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, + _In_ DWORD nOrdinal, + _In_opt_ LPCSTR pszFunc, + _In_opt_ PVOID pvFunc); + +// Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. +typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, + _In_ DWORD nOrdinal, + _In_opt_ LPCSTR pszFunc, + _In_opt_ PVOID* ppvFunc); + +typedef VOID * PDETOUR_BINARY; +typedef VOID * PDETOUR_LOADED_BINARY; + +//////////////////////////////////////////////////////////// Transaction APIs. +// +LONG WINAPI DetourTransactionBegin(VOID); +LONG WINAPI DetourTransactionAbort(VOID); +LONG WINAPI DetourTransactionCommit(VOID); +LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); + +LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); + +LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour); + +LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour, + _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, + _Out_opt_ PVOID *ppRealTarget, + _Out_opt_ PVOID *ppRealDetour); + +LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour); + +BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); +BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); +PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); +PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); + +////////////////////////////////////////////////////////////// Code Functions. +// +PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, + _In_ LPCSTR pszFunction); +PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, + _Out_opt_ PVOID *ppGlobals); +PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, + _Inout_opt_ PVOID *ppDstPool, + _In_ PVOID pSrc, + _Out_opt_ PVOID *ppTarget, + _Out_opt_ LONG *plExtra); +BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, + _In_ BOOL fLimitReferencesToModule); + +///////////////////////////////////////////////////// Loaded Binary Functions. +// +HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr); +HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); +PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule); +ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule); +BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, + _In_opt_ PVOID pContext, + _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport); +BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, + _In_opt_ PVOID pContext, + _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, + _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc); + +BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, + _In_opt_ PVOID pContext, + _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, + _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx); + +_Writable_bytes_(*pcbData) +_Readable_bytes_(*pcbData) +_Success_(return != NULL) +PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, + _In_ REFGUID rguid, + _Out_ DWORD *pcbData); + +_Writable_bytes_(*pcbData) +_Readable_bytes_(*pcbData) +_Success_(return != NULL) +PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, + _Out_ DWORD * pcbData); + +DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); + +///////////////////////////////////////////////// Persistent Binary Functions. +// + +PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile); + +_Writable_bytes_(*pcbData) +_Readable_bytes_(*pcbData) +_Success_(return != NULL) +PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, + _Out_opt_ GUID *pGuid, + _Out_ DWORD *pcbData, + _Inout_ DWORD *pnIterator); + +_Writable_bytes_(*pcbData) +_Readable_bytes_(*pcbData) +_Success_(return != NULL) +PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, + _In_ REFGUID rguid, + _Out_ DWORD *pcbData); + +PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, + _In_ REFGUID rguid, + _In_reads_opt_(cbData) PVOID pData, + _In_ DWORD cbData); +BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid); +BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary); +BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary); +BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary, + _In_opt_ PVOID pContext, + _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, + _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile, + _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, + _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit); +BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile); +BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary); + +/////////////////////////////////////////////////// Create Process & Load Dll. +// +typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( + _In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation); + +typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)( + _In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation); + +BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourCreateProcessWithDll DetourCreateProcessWithDllW +#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW +#else +#define DetourCreateProcessWithDll DetourCreateProcessWithDllA +#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA +#endif // !UNICODE + +BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExW +#else +#define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExA +#endif // !UNICODE + +BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourCreateProcessWithDlls DetourCreateProcessWithDllsW +#else +#define DetourCreateProcessWithDlls DetourCreateProcessWithDllsA +#endif // !UNICODE + +BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, + _In_ LPCSTR lpDllName, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, + _In_ LPCSTR lpDllName, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourProcessViaHelper DetourProcessViaHelperW +#else +#define DetourProcessViaHelper DetourProcessViaHelperA +#endif // !UNICODE + +BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourProcessViaHelperDlls DetourProcessViaHelperDllsW +#else +#define DetourProcessViaHelperDlls DetourProcessViaHelperDllsA +#endif // !UNICODE + +BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ DWORD nDlls); + +BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, + _In_ HMODULE hImage, + _In_ BOOL bIs32Bit, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ DWORD nDlls); + +BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, + _In_ REFGUID rguid, + _In_reads_bytes_(cbData) PVOID pvData, + _In_ DWORD cbData); +BOOL WINAPI DetourRestoreAfterWith(VOID); +BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, + _In_ DWORD cbData); +BOOL WINAPI DetourIsHelperProcess(VOID); +VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, + _In_ HINSTANCE, + _In_ LPSTR, + _In_ INT); + +// +////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} +#endif // __cplusplus + +//////////////////////////////////////////////// Detours Internal Definitions. +// +#ifdef __cplusplus +#ifdef DETOURS_INTERNAL + +#define NOTHROW +// #define NOTHROW (nothrow) + +////////////////////////////////////////////////////////////////////////////// +// +#if (_MSC_VER < 1299) +#include +typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; +typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; +typedef IMAGEHLP_SYMBOL SYMBOL_INFO; +typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO; + +static inline +LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) +{ + return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval); +} +#else +#pragma warning(push) +#pragma warning(disable:4091) // empty typedef +#include +#pragma warning(pop) +#endif + +#ifdef IMAGEAPI // defined by DBGHELP.H +typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion); + +typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess, + _In_opt_ LPCSTR UserSearchPath, + _In_ BOOL fInvadeProcess); +typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions); +typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); +typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess, + _In_opt_ HANDLE hFile, + _In_ LPSTR ImageName, + _In_opt_ LPSTR ModuleName, + _In_ DWORD64 BaseOfDll, + _In_opt_ DWORD SizeOfDll); +typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess, + _In_ DWORD64 qwAddr, + _Out_ PIMAGEHLP_MODULE64 ModuleInfo); +typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess, + _In_ LPSTR Name, + _Out_ PSYMBOL_INFO Symbol); + +typedef struct _DETOUR_SYM_INFO +{ + HANDLE hProcess; + HMODULE hDbgHelp; + PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; + PF_SymInitialize pfSymInitialize; + PF_SymSetOptions pfSymSetOptions; + PF_SymGetOptions pfSymGetOptions; + PF_SymLoadModule64 pfSymLoadModule64; + PF_SymGetModuleInfo64 pfSymGetModuleInfo64; + PF_SymFromName pfSymFromName; +} DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; + +PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); + +#endif // IMAGEAPI + +#if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) +#error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) +#endif +#define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 + +#ifndef DETOUR_TRACE +#if DETOUR_DEBUG +#define DETOUR_TRACE(x) printf x +#define DETOUR_BREAK() __debugbreak() +#include +#include +#else +#define DETOUR_TRACE(x) +#define DETOUR_BREAK() +#endif +#endif + +#if 1 || defined(DETOURS_IA64) + +// +// IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. +// + +#define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) + +#define DETOUR_IA64_TEMPLATE_OFFSET (0) +#define DETOUR_IA64_TEMPLATE_SIZE (5) + +#define DETOUR_IA64_INSTRUCTION_SIZE (41) +#define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) +#define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) +#define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) + +C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); + +__declspec(align(16)) struct DETOUR_IA64_BUNDLE +{ + public: + union + { + BYTE data[16]; + UINT64 wide[2]; + }; + + enum { + A_UNIT = 1u, + I_UNIT = 2u, + M_UNIT = 3u, + B_UNIT = 4u, + F_UNIT = 5u, + L_UNIT = 6u, + X_UNIT = 7u, + }; + struct DETOUR_IA64_METADATA + { + ULONG nTemplate : 8; // Instruction template. + ULONG nUnit0 : 4; // Unit for slot 0 + ULONG nUnit1 : 4; // Unit for slot 1 + ULONG nUnit2 : 4; // Unit for slot 2 + }; + + protected: + static const DETOUR_IA64_METADATA s_rceCopyTable[33]; + + UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; + + bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, + _In_ BYTE slot, + _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; + + // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 + // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. + + // 00 + // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. + // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] + // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] + // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] + // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] + // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] + // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] + // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] + BYTE GetTemplate() const; + // Get 4 bit opcodes. + BYTE GetInst0() const; + BYTE GetInst1() const; + BYTE GetInst2() const; + BYTE GetUnit(BYTE slot) const; + BYTE GetUnit0() const; + BYTE GetUnit1() const; + BYTE GetUnit2() const; + // Get 37 bit data. + UINT64 GetData0() const; + UINT64 GetData1() const; + UINT64 GetData2() const; + + // Get/set the full 41 bit instructions. + UINT64 GetInstruction(BYTE slot) const; + UINT64 GetInstruction0() const; + UINT64 GetInstruction1() const; + UINT64 GetInstruction2() const; + void SetInstruction(BYTE slot, UINT64 instruction); + void SetInstruction0(UINT64 instruction); + void SetInstruction1(UINT64 instruction); + void SetInstruction2(UINT64 instruction); + + // Get/set bitfields. + static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); + static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); + + // Get specific read-only fields. + static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode + static UINT64 GetX(UINT64 instruction); // 1bit opcode extension + static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension + static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension + + // Get/set specific fields. + static UINT64 GetImm7a(UINT64 instruction); + static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); + static UINT64 GetImm13c(UINT64 instruction); + static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); + static UINT64 GetSignBit(UINT64 instruction); + static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); + static UINT64 GetImm20a(UINT64 instruction); + static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); + static UINT64 GetImm20b(UINT64 instruction); + static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); + + static UINT64 SignExtend(UINT64 Value, UINT64 Offset); + + BOOL IsMovlGp() const; + + VOID SetInst(BYTE Slot, BYTE nInst); + VOID SetInst0(BYTE nInst); + VOID SetInst1(BYTE nInst); + VOID SetInst2(BYTE nInst); + VOID SetData(BYTE Slot, UINT64 nData); + VOID SetData0(UINT64 nData); + VOID SetData1(UINT64 nData); + VOID SetData2(UINT64 nData); + BOOL SetNop(BYTE Slot); + BOOL SetNop0(); + BOOL SetNop1(); + BOOL SetNop2(); + + public: + BOOL IsBrl() const; + VOID SetBrl(); + VOID SetBrl(UINT64 target); + UINT64 GetBrlTarget() const; + VOID SetBrlTarget(UINT64 target); + VOID SetBrlImm(UINT64 imm); + UINT64 GetBrlImm() const; + + UINT64 GetMovlGp() const; + VOID SetMovlGp(UINT64 gp); + + VOID SetStop(); + + UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; +}; +#endif // DETOURS_IA64 + +#ifdef DETOURS_ARM + +#define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) +#define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) + +#endif // DETOURS_ARM + +////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define DETOUR_OFFLINE_LIBRARY(x) \ +PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ + _Inout_opt_ PVOID *ppDstPool, \ + _In_ PVOID pSrc, \ + _Out_opt_ PVOID *ppTarget, \ + _Out_opt_ LONG *plExtra); \ + \ +BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ + _In_ BOOL fLimitReferencesToModule); \ + +DETOUR_OFFLINE_LIBRARY(X86) +DETOUR_OFFLINE_LIBRARY(X64) +DETOUR_OFFLINE_LIBRARY(ARM) +DETOUR_OFFLINE_LIBRARY(ARM64) +DETOUR_OFFLINE_LIBRARY(IA64) + +#undef DETOUR_OFFLINE_LIBRARY + +////////////////////////////////////////////////////////////////////////////// +// +// Helpers for manipulating page protection. +// + +_Success_(return != FALSE) +BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, + _In_ PVOID pAddress, + _In_ SIZE_T nSize, + _In_ DWORD dwNewProtect, + _Out_ PDWORD pdwOldProtect); + +_Success_(return != FALSE) +BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, + _In_ SIZE_T nSize, + _In_ DWORD dwNewProtect, + _Out_ PDWORD pdwOldProtect); +#ifdef __cplusplus +} +#endif // __cplusplus + +////////////////////////////////////////////////////////////////////////////// + +#define MM_ALLOCATION_GRANULARITY 0x10000 + +////////////////////////////////////////////////////////////////////////////// + +#endif // DETOURS_INTERNAL +#endif // __cplusplus + +#endif // _DETOURS_H_ +// +//////////////////////////////////////////////////////////////// End of File. diff --git a/include/detver.h b/include/detver.h new file mode 100644 index 0000000..f0aae9b --- /dev/null +++ b/include/detver.h @@ -0,0 +1,27 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Common version parameters. +// +// Microsoft Research Detours Package, Version 4.0.1 +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#define _USING_V110_SDK71_ 1 +#include "winver.h" +#if 0 +#include +#include +#else +#ifndef DETOURS_STRINGIFY +#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) +#define DETOURS_STRINGIFY_(x) #x +#endif + +#define VER_FILEFLAGSMASK 0x3fL +#define VER_FILEFLAGS 0x0L +#define VER_FILEOS 0x00040004L +#define VER_FILETYPE 0x00000002L +#define VER_FILESUBTYPE 0x00000000L +#endif +#define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) diff --git a/lib.x64/detours.lib b/lib.x64/detours.lib new file mode 100644 index 0000000..1808562 Binary files /dev/null and b/lib.x64/detours.lib differ diff --git a/lib.x64/detours.pdb b/lib.x64/detours.pdb new file mode 100644 index 0000000..242f95b Binary files /dev/null and b/lib.x64/detours.pdb differ diff --git a/lib.x86/detours.lib b/lib.x86/detours.lib new file mode 100644 index 0000000..29a2680 Binary files /dev/null and b/lib.x86/detours.lib differ diff --git a/lib.x86/detours.pdb b/lib.x86/detours.pdb new file mode 100644 index 0000000..24fa5ca Binary files /dev/null and b/lib.x86/detours.pdb differ