├── LICENSE ├── cmakelists.txt ├── dllloader ├── cmakelists.txt ├── dllloader.cpp ├── dllloader.h ├── minhook │ ├── LICENSE.txt │ ├── include │ │ └── MinHook.h │ └── src │ │ ├── buffer.c │ │ ├── buffer.h │ │ ├── hde │ │ ├── hde32.c │ │ ├── hde32.h │ │ ├── hde64.c │ │ ├── hde64.h │ │ ├── pstdint.h │ │ ├── table32.h │ │ └── table64.h │ │ ├── hook.c │ │ ├── trampoline.c │ │ └── trampoline.h └── ntddk.h ├── managed ├── test_managed_dll │ ├── cmakelists.txt │ └── test_managed_dll.cpp └── test_managed_dllloader │ ├── cmakelists.txt │ └── test_managed_dllloader.cpp ├── native ├── test_dll │ ├── cmakelists.txt │ └── test_dll.cpp └── test_dllloader │ ├── cmakelists.txt │ └── test_dllloader.cpp └── readme.md /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2022 Scott Chacon and others 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /cmakelists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(dllloader) 4 | 5 | add_subdirectory(dllloader) 6 | add_subdirectory(native/test_dll) 7 | add_subdirectory(native/test_dllloader) 8 | 9 | add_subdirectory(managed/test_managed_dll) 10 | add_subdirectory(managed/test_managed_dllloader) 11 | -------------------------------------------------------------------------------- /dllloader/cmakelists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | set(CMAKE_CXX_STANDARD 20) 4 | #set(CMAKE_CXX_STANDARD 17) 5 | add_definitions(-DUNICODE -D_UNICODE) 6 | 7 | function(configPaths project) 8 | set(outDir ${CMAKE_SOURCE_DIR}/bin) 9 | 10 | set_target_properties( ${project} PROPERTIES 11 | RUNTIME_OUTPUT_DIRECTORY_DEBUG ${outDir} 12 | RUNTIME_OUTPUT_DIRECTORY_RELEASE ${outDir} 13 | RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${outDir} 14 | ) 15 | endfunction() 16 | 17 | 18 | add_library(dllloader SHARED 19 | dllloader.h 20 | dllloader.cpp 21 | minhook/src/buffer.c 22 | minhook/src/hook.c 23 | minhook/src/trampoline.c 24 | minhook/src/hde/hde64.c 25 | minhook/src/hde/hde32.c 26 | 27 | minhook/src/buffer.h 28 | minhook/src/hde/hde32.h 29 | minhook/src/hde/hde64.h 30 | minhook/include/MinHook.h 31 | minhook/src/hde/pstdint.h 32 | minhook/src/hde/table32.h 33 | minhook/src/hde/table64.h 34 | minhook/src/trampoline.h 35 | minhook/LICENSE.txt 36 | ntddk.h 37 | ) 38 | 39 | target_include_directories(dllloader PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/minhook/include) 40 | add_compile_definitions(dllloader DLLLOADER_EXPORT) 41 | 42 | configPaths(dllloader) 43 | 44 | if(MSVC) 45 | # Report __cplusplus correctly by VS compiler 46 | target_compile_options(dllloader PUBLIC "/Zc:__cplusplus") 47 | endif() 48 | 49 | -------------------------------------------------------------------------------- /dllloader/dllloader.cpp: -------------------------------------------------------------------------------- 1 | #include "dllloader.h" 2 | #include //temp_directory_path 3 | #include "MinHook.h" 4 | #define _NTDLL_SELF_ //No need for ntdll.dll linkage 5 | #include "ntddk.h" 6 | #include //CA2W 7 | #include //AtlGetErrorDescription 8 | #include //ifstream 9 | #include 10 | 11 | using namespace ATL; 12 | using namespace std; 13 | using namespace std::filesystem; 14 | 15 | static DllManager* g_dllmanager = nullptr; 16 | 17 | // detour function debugging does not always work in mixed mode, use native debug mode instead 18 | 19 | //------------------------------------------------------------------------------------------------------------- 20 | using NtOpenFile_pfunc = NTSTATUS(NTAPI*) 21 | (PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, 22 | PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions); 23 | 24 | NtOpenFile_pfunc NtOpenFile_origfunc; 25 | 26 | // 27 | // Gets accociated file handle for specific filename. 28 | // If not hooked, then return 0. 29 | // 30 | HANDLE GetAccociatedHandle(POBJECT_ATTRIBUTES ObjectAttributes) 31 | { 32 | if (g_dllmanager != nullptr && ObjectAttributes != nullptr) 33 | { 34 | wstring_view ntFileName(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length / sizeof(wchar_t)); 35 | #if __cplusplus >= 202002L 36 | if (ntFileName.starts_with(L"\\??\\")) 37 | #else 38 | if (ntFileName.rfind(L"\\??\\", 0) == 0) 39 | #endif 40 | { 41 | auto fileName = ntFileName.substr(4); 42 | auto it = g_dllmanager->path2handle.find(fileName); 43 | if (it != g_dllmanager->path2handle.end()) 44 | { 45 | return it->second; 46 | } 47 | } 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | NTSTATUS WINAPI NtOpenFile_detour(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, 54 | PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) 55 | { 56 | HANDLE h = GetAccociatedHandle(ObjectAttributes); 57 | if( h != 0 ) 58 | { 59 | *FileHandle = h; 60 | return STATUS_SUCCESS; 61 | } 62 | 63 | NTSTATUS r = NtOpenFile_origfunc(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); 64 | return r; 65 | } 66 | 67 | //------------------------------------------------------------------------------------------------------------- 68 | using CreateFileW_pfunc = HANDLE (WINAPI*) ( 69 | LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, 70 | LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile 71 | ); 72 | 73 | CreateFileW_pfunc CreateFileW_origfunc; 74 | 75 | HANDLE WINAPI CreateFileW_detour( 76 | LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, 77 | LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile 78 | ) 79 | { 80 | HANDLE h; 81 | if (g_dllmanager != nullptr && lpFileName != nullptr) 82 | { 83 | if (g_dllmanager->path2handle.find(lpFileName) != g_dllmanager->path2handle.end()) 84 | { 85 | h = g_dllmanager->transactionManager.CreateFileW(g_dllmanager->path2path[lpFileName].c_str(), dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE, 86 | lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 87 | return h; 88 | } 89 | } 90 | 91 | // detour function debugging does not always work in mixed mode, use native debug mode instead 92 | //if (std::wstring_view(lpFileName).ends_with(L".pdb")) 93 | //{ 94 | // MessageBoxA(0, "stop", "info", 0); 95 | //} 96 | 97 | h = CreateFileW_origfunc(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 98 | return h; 99 | } 100 | 101 | //------------------------------------------------------------------------------------------------------------- 102 | using GetFileAttributesExW_func = BOOL(WINAPI*)(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ); 103 | 104 | GetFileAttributesExW_func GetFileAttributesExW_origfunc; 105 | 106 | BOOL WINAPI GetFileAttributesExW_detour(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation) 107 | { 108 | BOOL r; 109 | 110 | if (g_dllmanager != nullptr && g_dllmanager->path2handle.find(lpFileName) != g_dllmanager->path2handle.end()) 111 | { 112 | r = g_dllmanager->transactionManager.GetFileAttributesExW(g_dllmanager->path2path[lpFileName].c_str(), fInfoLevelId, lpFileInformation); 113 | return r; 114 | } 115 | 116 | r = GetFileAttributesExW_origfunc(lpFileName, fInfoLevelId, lpFileInformation); 117 | return r; 118 | } 119 | 120 | //------------------------------------------------------------------------------------------------------------- 121 | 122 | using NtCreateSection_pfunc = NTSTATUS(NTAPI*) 123 | (PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, 124 | PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle); 125 | 126 | NtCreateSection_pfunc NtCreateSection_origfunc; 127 | 128 | NTSTATUS NTAPI NtCreateSection_detour(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, 129 | PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle) 130 | { 131 | if (g_dllmanager != nullptr && 132 | #if __cplusplus >= 202002L 133 | g_dllmanager->handle2path.contains(FileHandle) 134 | #else 135 | g_dllmanager->handle2path.find(FileHandle) != g_dllmanager->handle2path.end() 136 | #endif 137 | ) 138 | { 139 | return NtCreateSection_origfunc(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, PAGE_READONLY, AllocationAttributes, FileHandle); 140 | } 141 | 142 | return NtCreateSection_origfunc(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle); 143 | } 144 | 145 | //------------------------------------------------------------------------------------------------------------- 146 | using NtQueryAttributesFile_pfunc = NTSTATUS(NTAPI*)(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation); 147 | 148 | NtQueryAttributesFile_pfunc NtQueryAttributesFile_origfunc; 149 | 150 | NTSTATUS NTAPI NtQueryAttributesFile_detour(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation) 151 | { 152 | // Since .dll does not physically does not exists on disk - we need to intercept NtQueryAttributesFile 153 | // so it would report like file does exists. 154 | HANDLE h = GetAccociatedHandle(ObjectAttributes); 155 | if (h != 0) 156 | { 157 | if(FileInformation) 158 | { 159 | *FileInformation = {0}; // Don't care about .dll date/timestamps (probably unused) 160 | FileInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE; 161 | } 162 | 163 | return STATUS_SUCCESS; 164 | } 165 | 166 | return NtQueryAttributesFile_origfunc(ObjectAttributes, FileInformation); 167 | } 168 | 169 | //------------------------------------------------------------------------------------------------------------- 170 | using NtClose_pfunc = NTSTATUS(NTAPI*) (HANDLE Handle); 171 | 172 | NtClose_pfunc NtClose_origfunc; 173 | 174 | NTSTATUS NTAPI NtClose_detour(HANDLE Handle) 175 | { 176 | if (g_dllmanager != nullptr && 177 | #if __cplusplus >= 202002L 178 | g_dllmanager->handle2path.contains(Handle) 179 | #else 180 | g_dllmanager->handle2path.find(Handle) != g_dllmanager->handle2path.end() 181 | #endif 182 | ) 183 | { 184 | return 0; 185 | } 186 | 187 | auto r = NtClose_origfunc(Handle); 188 | return r; 189 | } 190 | 191 | //------------------------------------------------------------------------------------------------------------- 192 | 193 | 194 | DllManager::DllManager(): 195 | transactionManager(false, true), hooksEnabled(false) 196 | { 197 | GetLastError = []() -> wstring{ return L""; }; 198 | g_dllmanager = this; 199 | } 200 | 201 | bool DllManager::IsEnabled() const 202 | { 203 | return hooksEnabled; 204 | } 205 | 206 | DllManager::~DllManager() 207 | { 208 | g_dllmanager = nullptr; 209 | 210 | DisableDllRedirection(); 211 | 212 | for (auto const& [h, path] : handle2path) 213 | CloseHandle(h); 214 | 215 | handle2path.clear(); 216 | path2handle.clear(); 217 | 218 | transactionManager.Rollback(); 219 | } 220 | 221 | bool DllManager::MhCall(int r) 222 | { 223 | if (r != MH_OK) 224 | { 225 | GetLastError = [r]() -> wstring 226 | { 227 | return wstring(L"MinHook error: ") + CA2W(MH_StatusToString((MH_STATUS)r)).operator LPWSTR(); 228 | }; 229 | return false; 230 | } 231 | 232 | return true; 233 | } 234 | 235 | const wchar_t* ntdll_dll = L"ntdll.dll"; 236 | const wchar_t* kernel32dll_dll = L"kernel32.dll"; 237 | 238 | bool DllManager::EnableDllRedirection() 239 | { 240 | HMODULE ntdll = GetModuleHandle(ntdll_dll); 241 | HMODULE kernel32dll = GetModuleHandle(kernel32dll_dll); 242 | if(!MhCall(MH_Initialize())) 243 | { 244 | return false; 245 | } 246 | 247 | bool b = true; 248 | b &= MhCall(MH_CreateHookApi(ntdll_dll, "NtOpenFile", &NtOpenFile_detour, (LPVOID*)&NtOpenFile_origfunc)); 249 | b &= MhCall(MH_CreateHookApi(ntdll_dll, "NtClose", &NtClose_detour, (LPVOID*)&NtClose_origfunc)); 250 | b &= MhCall(MH_CreateHookApi(ntdll_dll, "NtCreateSection", &NtCreateSection_detour, (LPVOID*)&NtCreateSection_origfunc)); 251 | b &= MhCall(MH_CreateHookApi(ntdll_dll, "NtQueryAttributesFile", &NtQueryAttributesFile_detour, (LPVOID*)&NtQueryAttributesFile_origfunc)); 252 | b &= MhCall(MH_CreateHookApi(kernel32dll_dll, "CreateFileW", &CreateFileW_detour, (LPVOID*)&CreateFileW_origfunc)); 253 | b &= MhCall(MH_CreateHookApi(kernel32dll_dll, "GetFileAttributesExW", &GetFileAttributesExW_detour, (LPVOID*)&GetFileAttributesExW_origfunc)); 254 | 255 | if(b) 256 | { 257 | b &= MhCall(MH_EnableHook((LPVOID)GetProcAddress(ntdll, "NtOpenFile"))); 258 | b &= MhCall(MH_EnableHook((LPVOID)GetProcAddress(ntdll, "NtClose"))); 259 | b &= MhCall(MH_EnableHook((LPVOID)GetProcAddress(ntdll, "NtCreateSection"))); 260 | b &= MhCall(MH_EnableHook((LPVOID)GetProcAddress(ntdll, "NtQueryAttributesFile"))); 261 | b &= MhCall(MH_EnableHook((LPVOID)GetProcAddress(kernel32dll, "CreateFileW"))); 262 | b &= MhCall(MH_EnableHook((LPVOID)GetProcAddress(kernel32dll, "GetFileAttributesExW"))); 263 | 264 | hooksEnabled = b; 265 | if(!b) 266 | { 267 | DisableDllRedirection(); 268 | } 269 | } 270 | 271 | return b; 272 | } 273 | 274 | void DllManager::DisableDllRedirection() 275 | { 276 | HMODULE ntdll = GetModuleHandle(ntdll_dll); 277 | HMODULE kernel32dll = GetModuleHandle(kernel32dll_dll); 278 | 279 | MH_DisableHook((LPVOID)GetProcAddress(ntdll, "NtOpenFile")); 280 | MH_DisableHook((LPVOID)GetProcAddress(ntdll, "NtClose")); 281 | MH_DisableHook((LPVOID)GetProcAddress(ntdll, "NtCreateSection")); 282 | MH_DisableHook((LPVOID)GetProcAddress(ntdll, "NtQueryAttributesFile")); 283 | MH_DisableHook((LPVOID)GetProcAddress(kernel32dll, "CreateFileW")); 284 | MH_DisableHook((LPVOID)GetProcAddress(kernel32dll, "GetFileAttributesExW")); 285 | } 286 | 287 | 288 | bool DllManager::WinApiCall(bool cond) 289 | { 290 | if(cond) 291 | { 292 | return true; 293 | } 294 | 295 | DWORD errorCode = ::GetLastError(); 296 | if (errorCode != 0) 297 | { 298 | GetLastError = [errorCode]() -> wstring 299 | { 300 | return AtlGetErrorDescription(HRESULT_FROM_WIN32(errorCode)).GetBuffer(); 301 | }; 302 | return false; 303 | } 304 | 305 | return true; 306 | } 307 | 308 | HMODULE DllManager::RamLoadLibrary(const wchar_t* dll_path) 309 | { 310 | string dllBinary; 311 | 312 | path currentPath(dll_path); 313 | path newDllPath(temp_directory_path() / currentPath.filename()); 314 | 315 | if (!exists(dll_path)) 316 | { 317 | GetLastError = [dll_path]() -> wstring 318 | { 319 | return wstring(L"Dll does not exists: ") + dll_path; 320 | }; 321 | return 0; 322 | } 323 | 324 | ifstream is; 325 | is.exceptions(is.exceptions() | std::ios::failbit); //throw exception on failure 326 | 327 | try { 328 | is.open(dll_path, ios::binary); 329 | is.seekg(0, ios::end); 330 | int size = is.tellg(); 331 | is.seekg(0, ios::beg); 332 | dllBinary.resize(size); 333 | is.read(&dllBinary[0], size); 334 | is.close(); 335 | } 336 | catch (ios_base::failure& e) 337 | { 338 | wstring what(CA2W(e.what())); 339 | GetLastError = [what]() -> wstring 340 | { 341 | return what; 342 | }; 343 | return 0; 344 | } 345 | 346 | if (!SetDllFile(nullptr,newDllPath.c_str(), &dllBinary[0], dllBinary.size())) 347 | { 348 | return 0; 349 | } 350 | 351 | return LoadLibrary(newDllPath.c_str()); 352 | } 353 | 354 | 355 | bool DllManager::SetDllFile(const wchar_t* origpath, const wchar_t* newpath, const void* dll, int size) 356 | { 357 | HANDLE hFile = transactionManager.CreateFileW(newpath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 358 | if(!WinApiCall(hFile != 0)) 359 | { 360 | return false; 361 | } 362 | 363 | DWORD written = 0; 364 | bool b = WinApiCall(WriteFile(hFile, dll, size, &written, NULL)); 365 | b &= WinApiCall(FlushFileBuffers(hFile)); 366 | b &= WinApiCall(SetFilePointer(hFile, 0, 0, FILE_BEGIN) != INVALID_SET_FILE_POINTER); 367 | if(b) 368 | { 369 | handle2path[hFile] = newpath; 370 | path2handle[newpath] = hFile; 371 | path2path[newpath] = newpath; 372 | if (origpath != nullptr) 373 | { 374 | path2handle[origpath] = hFile; 375 | path2path[origpath] = newpath; 376 | } 377 | } 378 | else 379 | { 380 | CloseHandle(hFile); 381 | transactionManager.DeleteFileW(newpath); 382 | } 383 | 384 | return true; 385 | } 386 | 387 | HMODULE DllManager::LoadLibrary(const wchar_t* path) 388 | { 389 | HMODULE h = ::LoadLibrary(path); 390 | WinApiCall(h != 0); 391 | return h; 392 | } 393 | 394 | 395 | -------------------------------------------------------------------------------- /dllloader/dllloader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "atlcore.h" //AtlLoadSystemLibraryUsingFullPath 3 | #include "atltransactionmanager.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | #ifdef DLLLOADER_EXPORT 11 | #define DLLLOADER_ENTRY __declspec(dllexport) 12 | #else 13 | #define DLLLOADER_ENTRY __declspec(dllimport) 14 | #endif 15 | 16 | class DLLLOADER_ENTRY DllManager 17 | { 18 | public: 19 | DllManager(); 20 | ~DllManager(); 21 | 22 | bool IsEnabled() const; 23 | 24 | bool EnableDllRedirection(); 25 | void DisableDllRedirection(); 26 | 27 | std::function GetLastError; 28 | 29 | // Same as LoadLibrary, except loads .dll into ram avoiding lock to file. 30 | // returns 0 if failure, DllManager::GetLastError() can be used to retrieve error message. 31 | HMODULE RamLoadLibrary(const wchar_t* path); 32 | 33 | /// 34 | /// Sets dll contents for specific path 35 | /// 36 | /// origpath is used only by managed dll - since .dll itself contains assembly name. 37 | /// origpath will be redirected to path instead. use nullptr for native .dll's 38 | /// 39 | /// .dll path to fake 40 | /// dll binary itself 41 | /// dll size 42 | bool SetDllFile(const wchar_t* origpath,const wchar_t* path, const void* dll, int size); 43 | 44 | HMODULE LoadLibrary(const wchar_t* path); 45 | 46 | ATL::CAtlTransactionManager transactionManager; 47 | std::map > path2handle; 48 | std::map > path2path; 49 | std::map handle2path; 50 | 51 | bool WinApiCall(bool cond); 52 | 53 | private: 54 | bool MhCall(int r); 55 | bool hooksEnabled; 56 | }; 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dllloader/minhook/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MinHook - The Minimalistic API Hooking Library for x64/x86 2 | Copyright (C) 2009-2017 Tsuda Kageyu. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | ================================================================================ 28 | Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov. 29 | ================================================================================ 30 | Hacker Disassembler Engine 32 C 31 | Copyright (c) 2008-2009, Vyacheslav Patkov. 32 | All rights reserved. 33 | 34 | Redistribution and use in source and binary forms, with or without 35 | modification, are permitted provided that the following conditions 36 | are met: 37 | 38 | 1. Redistributions of source code must retain the above copyright 39 | notice, this list of conditions and the following disclaimer. 40 | 2. Redistributions in binary form must reproduce the above copyright 41 | notice, this list of conditions and the following disclaimer in the 42 | documentation and/or other materials provided with the distribution. 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 45 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 48 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 49 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 50 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 51 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 52 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 53 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 54 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | 56 | ------------------------------------------------------------------------------- 57 | Hacker Disassembler Engine 64 C 58 | Copyright (c) 2008-2009, Vyacheslav Patkov. 59 | All rights reserved. 60 | 61 | Redistribution and use in source and binary forms, with or without 62 | modification, are permitted provided that the following conditions 63 | are met: 64 | 65 | 1. Redistributions of source code must retain the above copyright 66 | notice, this list of conditions and the following disclaimer. 67 | 2. Redistributions in binary form must reproduce the above copyright 68 | notice, this list of conditions and the following disclaimer in the 69 | documentation and/or other materials provided with the distribution. 70 | 71 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 72 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 73 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 74 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 75 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 76 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 77 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 78 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 79 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 80 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 81 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82 | 83 | boostinspect:nolicense: minhook specific licensing 84 | -------------------------------------------------------------------------------- /dllloader/minhook/include/MinHook.h: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * MinHook - The Minimalistic API Hooking Library for x64/x86 5 | * Copyright (C) 2009-2017 Tsuda Kageyu. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 22 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #pragma once 32 | 33 | #if defined(_WIN32) //Windows only 34 | #include 35 | 36 | // MinHook Error Codes. 37 | typedef enum MH_STATUS 38 | { 39 | // Unknown error. Should not be returned. 40 | MH_UNKNOWN = -1, 41 | 42 | // Successful. 43 | MH_OK = 0, 44 | 45 | // MinHook is already initialized. 46 | MH_ERROR_ALREADY_INITIALIZED, 47 | 48 | // MinHook is not initialized yet, or already uninitialized. 49 | MH_ERROR_NOT_INITIALIZED, 50 | 51 | // The hook for the specified target function is already created. 52 | MH_ERROR_ALREADY_CREATED, 53 | 54 | // The hook for the specified target function is not created yet. 55 | MH_ERROR_NOT_CREATED, 56 | 57 | // The hook for the specified target function is already enabled. 58 | MH_ERROR_ENABLED, 59 | 60 | // The hook for the specified target function is not enabled yet, or already 61 | // disabled. 62 | MH_ERROR_DISABLED, 63 | 64 | // The specified pointer is invalid. It points the address of non-allocated 65 | // and/or non-executable region. 66 | MH_ERROR_NOT_EXECUTABLE, 67 | 68 | // The specified target function cannot be hooked. 69 | MH_ERROR_UNSUPPORTED_FUNCTION, 70 | 71 | // Failed to allocate memory. 72 | MH_ERROR_MEMORY_ALLOC, 73 | 74 | // Failed to change the memory protection. 75 | MH_ERROR_MEMORY_PROTECT, 76 | 77 | // The specified module is not loaded. 78 | MH_ERROR_MODULE_NOT_FOUND, 79 | 80 | // The specified function is not found. 81 | MH_ERROR_FUNCTION_NOT_FOUND 82 | } 83 | MH_STATUS; 84 | 85 | // Can be passed as a parameter to MH_EnableHook, MH_DisableHook, 86 | // MH_QueueEnableHook or MH_QueueDisableHook. 87 | #define MH_ALL_HOOKS NULL 88 | 89 | #ifdef __cplusplus 90 | extern "C" { 91 | #endif 92 | 93 | // Initialize the MinHook library. You must call this function EXACTLY ONCE 94 | // at the beginning of your program. 95 | MH_STATUS WINAPI MH_Initialize(VOID); 96 | 97 | // Uninitialize the MinHook library. You must call this function EXACTLY 98 | // ONCE at the end of your program. 99 | MH_STATUS WINAPI MH_Uninitialize(VOID); 100 | 101 | // Creates a Hook for the specified target function, in disabled state. 102 | // Parameters: 103 | // pTarget [in] A pointer to the target function, which will be 104 | // overridden by the detour function. 105 | // pDetour [in] A pointer to the detour function, which will override 106 | // the target function. 107 | // ppOriginal [out] A pointer to the trampoline function, which will be 108 | // used to call the original target function. 109 | // This parameter can be NULL. 110 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); 111 | 112 | // Creates a Hook for the specified API function, in disabled state. 113 | // Parameters: 114 | // pszModule [in] A pointer to the loaded module name which contains the 115 | // target function. 116 | // pszTarget [in] A pointer to the target function name, which will be 117 | // overridden by the detour function. 118 | // pDetour [in] A pointer to the detour function, which will override 119 | // the target function. 120 | // ppOriginal [out] A pointer to the trampoline function, which will be 121 | // used to call the original target function. 122 | // This parameter can be NULL. 123 | MH_STATUS WINAPI MH_CreateHookApi( 124 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); 125 | 126 | // Creates a Hook for the specified API function, in disabled state. 127 | // Parameters: 128 | // pszModule [in] A pointer to the loaded module name which contains the 129 | // target function. 130 | // pszTarget [in] A pointer to the target function name, which will be 131 | // overridden by the detour function. 132 | // pDetour [in] A pointer to the detour function, which will override 133 | // the target function. 134 | // ppOriginal [out] A pointer to the trampoline function, which will be 135 | // used to call the original target function. 136 | // This parameter can be NULL. 137 | // ppTarget [out] A pointer to the target function, which will be used 138 | // with other functions. 139 | // This parameter can be NULL. 140 | MH_STATUS WINAPI MH_CreateHookApiEx( 141 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); 142 | 143 | // Removes an already created hook. 144 | // Parameters: 145 | // pTarget [in] A pointer to the target function. 146 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); 147 | 148 | // Enables an already created hook. 149 | // Parameters: 150 | // pTarget [in] A pointer to the target function. 151 | // If this parameter is MH_ALL_HOOKS, all created hooks are 152 | // enabled in one go. 153 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); 154 | 155 | // Disables an already created hook. 156 | // Parameters: 157 | // pTarget [in] A pointer to the target function. 158 | // If this parameter is MH_ALL_HOOKS, all created hooks are 159 | // disabled in one go. 160 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); 161 | 162 | // Queues to enable an already created hook. 163 | // Parameters: 164 | // pTarget [in] A pointer to the target function. 165 | // If this parameter is MH_ALL_HOOKS, all created hooks are 166 | // queued to be enabled. 167 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); 168 | 169 | // Queues to disable an already created hook. 170 | // Parameters: 171 | // pTarget [in] A pointer to the target function. 172 | // If this parameter is MH_ALL_HOOKS, all created hooks are 173 | // queued to be disabled. 174 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); 175 | 176 | // Applies all queued changes in one go. 177 | MH_STATUS WINAPI MH_ApplyQueued(VOID); 178 | 179 | // Translates the MH_STATUS to its name as a string. 180 | const char * WINAPI MH_StatusToString(MH_STATUS status); 181 | 182 | #ifdef __cplusplus 183 | } 184 | #endif 185 | 186 | #endif //_WIN32 187 | -------------------------------------------------------------------------------- /dllloader/minhook/src/buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * MinHook - The Minimalistic API Hooking Library for x64/x86 5 | * Copyright (C) 2009-2017 Tsuda Kageyu. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 22 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #if defined(_WIN32) //Windows only 31 | #include 32 | #include "buffer.h" 33 | 34 | // Size of each memory block. (= page size of VirtualAlloc) 35 | #define MEMORY_BLOCK_SIZE 0x1000 36 | 37 | // Max range for seeking a memory block. (= 1024MB) 38 | #define MAX_MEMORY_RANGE 0x40000000 39 | 40 | // Memory protection flags to check the executable address. 41 | #define PAGE_EXECUTE_FLAGS \ 42 | (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) 43 | 44 | // Memory slot. 45 | typedef struct _MEMORY_SLOT 46 | { 47 | union 48 | { 49 | struct _MEMORY_SLOT *pNext; 50 | UINT8 buffer[MEMORY_SLOT_SIZE]; 51 | }u; 52 | } MEMORY_SLOT, *PMEMORY_SLOT; 53 | 54 | // Memory block info. Placed at the head of each block. 55 | typedef struct _MEMORY_BLOCK 56 | { 57 | struct _MEMORY_BLOCK *pNext; 58 | PMEMORY_SLOT pFree; // First element of the free slot list. 59 | UINT usedCount; 60 | } MEMORY_BLOCK, *PMEMORY_BLOCK; 61 | 62 | //------------------------------------------------------------------------- 63 | // Global Variables: 64 | //------------------------------------------------------------------------- 65 | 66 | // First element of the memory block list. 67 | PMEMORY_BLOCK g_pMemoryBlocks; 68 | 69 | //------------------------------------------------------------------------- 70 | VOID InitializeBuffer(VOID) 71 | { 72 | // Nothing to do for now. 73 | } 74 | 75 | //------------------------------------------------------------------------- 76 | VOID UninitializeBuffer(VOID) 77 | { 78 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks; 79 | g_pMemoryBlocks = NULL; 80 | 81 | while (pBlock) 82 | { 83 | PMEMORY_BLOCK pNext = pBlock->pNext; 84 | VirtualFree(pBlock, 0, MEM_RELEASE); 85 | pBlock = pNext; 86 | } 87 | } 88 | 89 | //------------------------------------------------------------------------- 90 | #if defined(_M_X64) || defined(__x86_64__) 91 | static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) 92 | { 93 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress; 94 | 95 | // Round down to the allocation granularity. 96 | tryAddr -= tryAddr % dwAllocationGranularity; 97 | 98 | // Start from the previous allocation granularity multiply. 99 | tryAddr -= dwAllocationGranularity; 100 | 101 | while (tryAddr >= (ULONG_PTR)pMinAddr) 102 | { 103 | MEMORY_BASIC_INFORMATION mbi; 104 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) 105 | break; 106 | 107 | if (mbi.State == MEM_FREE) 108 | return (LPVOID)tryAddr; 109 | 110 | if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) 111 | break; 112 | 113 | tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; 114 | } 115 | 116 | return NULL; 117 | } 118 | #endif 119 | 120 | //------------------------------------------------------------------------- 121 | #if defined(_M_X64) || defined(__x86_64__) 122 | static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) 123 | { 124 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress; 125 | 126 | // Round down to the allocation granularity. 127 | tryAddr -= tryAddr % dwAllocationGranularity; 128 | 129 | // Start from the next allocation granularity multiply. 130 | tryAddr += dwAllocationGranularity; 131 | 132 | while (tryAddr <= (ULONG_PTR)pMaxAddr) 133 | { 134 | MEMORY_BASIC_INFORMATION mbi; 135 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) 136 | break; 137 | 138 | if (mbi.State == MEM_FREE) 139 | return (LPVOID)tryAddr; 140 | 141 | tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; 142 | 143 | // Round up to the next allocation granularity. 144 | tryAddr += dwAllocationGranularity - 1; 145 | tryAddr -= tryAddr % dwAllocationGranularity; 146 | } 147 | 148 | return NULL; 149 | } 150 | #endif 151 | 152 | //------------------------------------------------------------------------- 153 | static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) 154 | { 155 | PMEMORY_BLOCK pBlock; 156 | #if defined(_M_X64) || defined(__x86_64__) 157 | ULONG_PTR minAddr; 158 | ULONG_PTR maxAddr; 159 | 160 | SYSTEM_INFO si; 161 | GetSystemInfo(&si); 162 | minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; 163 | maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; 164 | 165 | // pOrigin +- 512MB 166 | if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) 167 | minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; 168 | 169 | if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) 170 | maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; 171 | 172 | // Make room for MEMORY_BLOCK_SIZE bytes. 173 | maxAddr -= MEMORY_BLOCK_SIZE - 1; 174 | #endif 175 | 176 | // Look the registered blocks for a reachable one. 177 | for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) 178 | { 179 | #if defined(_M_X64) || defined(__x86_64__) 180 | // Ignore the blocks too far. 181 | if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) 182 | continue; 183 | #endif 184 | // The block has at least one unused slot. 185 | if (pBlock->pFree != NULL) 186 | return pBlock; 187 | } 188 | 189 | #if defined(_M_X64) || defined(__x86_64__) 190 | // Alloc a new block above if not found. 191 | { 192 | LPVOID pAlloc = pOrigin; 193 | while ((ULONG_PTR)pAlloc >= minAddr) 194 | { 195 | pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); 196 | if (pAlloc == NULL) 197 | break; 198 | 199 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 200 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 201 | if (pBlock != NULL) 202 | break; 203 | } 204 | } 205 | 206 | // Alloc a new block below if not found. 207 | if (pBlock == NULL) 208 | { 209 | LPVOID pAlloc = pOrigin; 210 | while ((ULONG_PTR)pAlloc <= maxAddr) 211 | { 212 | pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); 213 | if (pAlloc == NULL) 214 | break; 215 | 216 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 217 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 218 | if (pBlock != NULL) 219 | break; 220 | } 221 | } 222 | #else 223 | pOrigin; 224 | // In x86 mode, a memory block can be placed anywhere. 225 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 226 | NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 227 | #endif 228 | 229 | if (pBlock != NULL) 230 | { 231 | // Build a linked list of all the slots. 232 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; 233 | pBlock->pFree = NULL; 234 | pBlock->usedCount = 0; 235 | do 236 | { 237 | pSlot->u.pNext = pBlock->pFree; 238 | pBlock->pFree = pSlot; 239 | pSlot++; 240 | } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); 241 | 242 | pBlock->pNext = g_pMemoryBlocks; 243 | g_pMemoryBlocks = pBlock; 244 | } 245 | 246 | return pBlock; 247 | } 248 | 249 | //------------------------------------------------------------------------- 250 | LPVOID AllocateBuffer(LPVOID pOrigin) 251 | { 252 | PMEMORY_SLOT pSlot; 253 | PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); 254 | if (pBlock == NULL) 255 | return NULL; 256 | 257 | // Remove an unused slot from the list. 258 | pSlot = pBlock->pFree; 259 | pBlock->pFree = pSlot->u.pNext; 260 | pBlock->usedCount++; 261 | #ifdef _DEBUG 262 | // Fill the slot with INT3 for debugging. 263 | memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); 264 | #endif 265 | return pSlot; 266 | } 267 | 268 | //------------------------------------------------------------------------- 269 | VOID FreeBuffer(LPVOID pBuffer) 270 | { 271 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks; 272 | PMEMORY_BLOCK pPrev = NULL; 273 | ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; 274 | 275 | while (pBlock != NULL) 276 | { 277 | if ((ULONG_PTR)pBlock == pTargetBlock) 278 | { 279 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; 280 | #ifdef _DEBUG 281 | // Clear the released slot for debugging. 282 | memset(pSlot, 0x00, sizeof(*pSlot)); 283 | #endif 284 | // Restore the released slot to the list. 285 | pSlot->u.pNext = pBlock->pFree; 286 | pBlock->pFree = pSlot; 287 | pBlock->usedCount--; 288 | 289 | // Free if unused. 290 | if (pBlock->usedCount == 0) 291 | { 292 | if (pPrev) 293 | pPrev->pNext = pBlock->pNext; 294 | else 295 | g_pMemoryBlocks = pBlock->pNext; 296 | 297 | VirtualFree(pBlock, 0, MEM_RELEASE); 298 | } 299 | 300 | break; 301 | } 302 | 303 | pPrev = pBlock; 304 | pBlock = pBlock->pNext; 305 | } 306 | } 307 | 308 | //------------------------------------------------------------------------- 309 | BOOL IsExecutableAddress(LPVOID pAddress) 310 | { 311 | MEMORY_BASIC_INFORMATION mi; 312 | VirtualQuery(pAddress, &mi, sizeof(mi)); 313 | 314 | return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); 315 | } 316 | 317 | #endif //_WIN32 318 | 319 | -------------------------------------------------------------------------------- /dllloader/minhook/src/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * MinHook - The Minimalistic API Hooking Library for x64/x86 5 | * Copyright (C) 2009-2017 Tsuda Kageyu. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 22 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #pragma once 32 | 33 | #if defined(_WIN32) //Windows only 34 | 35 | // Size of each memory slot. 36 | #if defined(_M_X64) || defined(__x86_64__) 37 | #define MEMORY_SLOT_SIZE 64 38 | #else 39 | #define MEMORY_SLOT_SIZE 32 40 | #endif 41 | 42 | VOID InitializeBuffer(VOID); 43 | VOID UninitializeBuffer(VOID); 44 | LPVOID AllocateBuffer(LPVOID pOrigin); 45 | VOID FreeBuffer(LPVOID pBuffer); 46 | BOOL IsExecutableAddress(LPVOID pAddress); 47 | 48 | #endif //_WIN32 49 | -------------------------------------------------------------------------------- /dllloader/minhook/src/hde/hde32.c: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * Hacker Disassembler Engine 32 C 5 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 6 | * All rights reserved. 7 | * 8 | */ 9 | 10 | #if defined(_WIN32) && (defined(_M_IX86) || defined(__i386__)) 11 | 12 | #include "hde32.h" 13 | #include "table32.h" 14 | 15 | unsigned int hde32_disasm(const void *code, hde32s *hs) 16 | { 17 | uint8_t x, c = 0, *p = (uint8_t *)code, cflags, opcode, pref = 0; 18 | uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; 19 | 20 | // Avoid using memset to reduce the footprint. 21 | #ifndef _MSC_VER 22 | memset((LPBYTE)hs, 0, sizeof(hde32s)); 23 | #else 24 | __stosb((LPBYTE)hs, 0, sizeof(hde32s)); 25 | #endif 26 | 27 | for (x = 16; x; x--) 28 | switch (c = *p++) { 29 | case 0xf3: 30 | hs->p_rep = c; 31 | pref |= PRE_F3; 32 | break; 33 | case 0xf2: 34 | hs->p_rep = c; 35 | pref |= PRE_F2; 36 | break; 37 | case 0xf0: 38 | hs->p_lock = c; 39 | pref |= PRE_LOCK; 40 | break; 41 | case 0x26: case 0x2e: case 0x36: 42 | case 0x3e: case 0x64: case 0x65: 43 | hs->p_seg = c; 44 | pref |= PRE_SEG; 45 | break; 46 | case 0x66: 47 | hs->p_66 = c; 48 | pref |= PRE_66; 49 | break; 50 | case 0x67: 51 | hs->p_67 = c; 52 | pref |= PRE_67; 53 | break; 54 | default: 55 | goto pref_done; 56 | } 57 | pref_done: 58 | 59 | hs->flags = (uint32_t)pref << 23; 60 | 61 | if (!pref) 62 | pref |= PRE_NONE; 63 | 64 | if ((hs->opcode = c) == 0x0f) { 65 | hs->opcode2 = c = *p++; 66 | ht += DELTA_OPCODES; 67 | } else if (c >= 0xa0 && c <= 0xa3) { 68 | if (pref & PRE_67) 69 | pref |= PRE_66; 70 | else 71 | pref &= ~PRE_66; 72 | } 73 | 74 | opcode = c; 75 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 76 | 77 | if (cflags == C_ERROR) { 78 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 79 | cflags = 0; 80 | if ((opcode & -3) == 0x24) 81 | cflags++; 82 | } 83 | 84 | x = 0; 85 | if (cflags & C_GROUP) { 86 | uint16_t t; 87 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 88 | cflags = (uint8_t)t; 89 | x = (uint8_t)(t >> 8); 90 | } 91 | 92 | if (hs->opcode2) { 93 | ht = hde32_table + DELTA_PREFIXES; 94 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 95 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 96 | } 97 | 98 | if (cflags & C_MODRM) { 99 | hs->flags |= F_MODRM; 100 | hs->modrm = c = *p++; 101 | hs->modrm_mod = m_mod = c >> 6; 102 | hs->modrm_rm = m_rm = c & 7; 103 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 104 | 105 | if (x && ((x << m_reg) & 0x80)) 106 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 107 | 108 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 109 | uint8_t t = opcode - 0xd9; 110 | if (m_mod == 3) { 111 | ht = hde32_table + DELTA_FPU_MODRM + t*8; 112 | t = ht[m_reg] << m_rm; 113 | } else { 114 | ht = hde32_table + DELTA_FPU_REG; 115 | t = ht[t] << m_reg; 116 | } 117 | if (t & 0x80) 118 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 119 | } 120 | 121 | if (pref & PRE_LOCK) { 122 | if (m_mod == 3) { 123 | hs->flags |= F_ERROR | F_ERROR_LOCK; 124 | } else { 125 | uint8_t *table_end, op = opcode; 126 | if (hs->opcode2) { 127 | ht = hde32_table + DELTA_OP2_LOCK_OK; 128 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 129 | } else { 130 | ht = hde32_table + DELTA_OP_LOCK_OK; 131 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 132 | op &= -2; 133 | } 134 | for (; ht != table_end; ht++) 135 | if (*ht++ == op) { 136 | if (!((*ht << m_reg) & 0x80)) 137 | goto no_lock_error; 138 | else 139 | break; 140 | } 141 | hs->flags |= F_ERROR | F_ERROR_LOCK; 142 | no_lock_error: 143 | ; 144 | } 145 | } 146 | 147 | if (hs->opcode2) { 148 | switch (opcode) { 149 | case 0x20: case 0x22: 150 | m_mod = 3; 151 | if (m_reg > 4 || m_reg == 1) 152 | goto error_operand; 153 | else 154 | goto no_error_operand; 155 | case 0x21: case 0x23: 156 | m_mod = 3; 157 | if (m_reg == 4 || m_reg == 5) 158 | goto error_operand; 159 | else 160 | goto no_error_operand; 161 | } 162 | } else { 163 | switch (opcode) { 164 | case 0x8c: 165 | if (m_reg > 5) 166 | goto error_operand; 167 | else 168 | goto no_error_operand; 169 | case 0x8e: 170 | if (m_reg == 1 || m_reg > 5) 171 | goto error_operand; 172 | else 173 | goto no_error_operand; 174 | } 175 | } 176 | 177 | if (m_mod == 3) { 178 | uint8_t *table_end; 179 | if (hs->opcode2) { 180 | ht = hde32_table + DELTA_OP2_ONLY_MEM; 181 | table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; 182 | } else { 183 | ht = hde32_table + DELTA_OP_ONLY_MEM; 184 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 185 | } 186 | for (; ht != table_end; ht += 2) 187 | if (*ht++ == opcode) { 188 | if (*ht++ & pref && !((*ht << m_reg) & 0x80)) 189 | goto error_operand; 190 | else 191 | break; 192 | } 193 | goto no_error_operand; 194 | } else if (hs->opcode2) { 195 | switch (opcode) { 196 | case 0x50: case 0xd7: case 0xf7: 197 | if (pref & (PRE_NONE | PRE_66)) 198 | goto error_operand; 199 | break; 200 | case 0xd6: 201 | if (pref & (PRE_F2 | PRE_F3)) 202 | goto error_operand; 203 | break; 204 | case 0xc5: 205 | goto error_operand; 206 | } 207 | goto no_error_operand; 208 | } else 209 | goto no_error_operand; 210 | 211 | error_operand: 212 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 213 | no_error_operand: 214 | 215 | c = *p++; 216 | if (m_reg <= 1) { 217 | if (opcode == 0xf6) 218 | cflags |= C_IMM8; 219 | else if (opcode == 0xf7) 220 | cflags |= C_IMM_P66; 221 | } 222 | 223 | switch (m_mod) { 224 | case 0: 225 | if (pref & PRE_67) { 226 | if (m_rm == 6) 227 | disp_size = 2; 228 | } else 229 | if (m_rm == 5) 230 | disp_size = 4; 231 | break; 232 | case 1: 233 | disp_size = 1; 234 | break; 235 | case 2: 236 | disp_size = 2; 237 | if (!(pref & PRE_67)) 238 | disp_size <<= 1; 239 | } 240 | 241 | if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { 242 | hs->flags |= F_SIB; 243 | p++; 244 | hs->sib = c; 245 | hs->sib_scale = c >> 6; 246 | hs->sib_index = (c & 0x3f) >> 3; 247 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 248 | disp_size = 4; 249 | } 250 | 251 | p--; 252 | switch (disp_size) { 253 | case 1: 254 | hs->flags |= F_DISP8; 255 | hs->disp.disp8 = *p; 256 | break; 257 | case 2: 258 | hs->flags |= F_DISP16; 259 | hs->disp.disp16 = *(uint16_t *)p; 260 | break; 261 | case 4: 262 | hs->flags |= F_DISP32; 263 | hs->disp.disp32 = *(uint32_t *)p; 264 | } 265 | p += disp_size; 266 | } else if (pref & PRE_LOCK) 267 | hs->flags |= F_ERROR | F_ERROR_LOCK; 268 | 269 | if (cflags & C_IMM_P66) { 270 | if (cflags & C_REL32) { 271 | if (pref & PRE_66) { 272 | hs->flags |= F_IMM16 | F_RELATIVE; 273 | hs->imm.imm16 = *(uint16_t *)p; 274 | p += 2; 275 | goto disasm_done; 276 | } 277 | goto rel32_ok; 278 | } 279 | if (pref & PRE_66) { 280 | hs->flags |= F_IMM16; 281 | hs->imm.imm16 = *(uint16_t *)p; 282 | p += 2; 283 | } else { 284 | hs->flags |= F_IMM32; 285 | hs->imm.imm32 = *(uint32_t *)p; 286 | p += 4; 287 | } 288 | } 289 | 290 | if (cflags & C_IMM16) { 291 | if (hs->flags & F_IMM32) { 292 | hs->flags |= F_IMM16; 293 | hs->disp.disp16 = *(uint16_t *)p; 294 | } else if (hs->flags & F_IMM16) { 295 | hs->flags |= F_2IMM16; 296 | hs->disp.disp16 = *(uint16_t *)p; 297 | } else { 298 | hs->flags |= F_IMM16; 299 | hs->imm.imm16 = *(uint16_t *)p; 300 | } 301 | p += 2; 302 | } 303 | if (cflags & C_IMM8) { 304 | hs->flags |= F_IMM8; 305 | hs->imm.imm8 = *p++; 306 | } 307 | 308 | if (cflags & C_REL32) { 309 | rel32_ok: 310 | hs->flags |= F_IMM32 | F_RELATIVE; 311 | hs->imm.imm32 = *(uint32_t *)p; 312 | p += 4; 313 | } else if (cflags & C_REL8) { 314 | hs->flags |= F_IMM8 | F_RELATIVE; 315 | hs->imm.imm8 = *p++; 316 | } 317 | 318 | disasm_done: 319 | 320 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 321 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 322 | hs->len = 15; 323 | } 324 | 325 | return (unsigned int)hs->len; 326 | } 327 | 328 | #else 329 | #ifdef _MSC_VER 330 | #pragma warning(disable: 4206) //nonstandard extension used: translation unit is empty 331 | #endif 332 | #endif // defined(_WIN32) && (defined(_M_IX86) || defined(__i386__)) 333 | -------------------------------------------------------------------------------- /dllloader/minhook/src/hde/hde32.h: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * Hacker Disassembler Engine 32 5 | * Copyright (c) 2006-2009, Vyacheslav Patkov. 6 | * All rights reserved. 7 | * 8 | * hde32.h: C/C++ header file 9 | * 10 | */ 11 | 12 | #ifndef _HDE32_H_ 13 | #define _HDE32_H_ 14 | #if defined(_WIN32) //Windows only 15 | 16 | /* stdint.h - C99 standard header 17 | * http://en.wikipedia.org/wiki/stdint.h 18 | * 19 | * if your compiler doesn't contain "stdint.h" header (for 20 | * example, Microsoft Visual C++), you can download file: 21 | * http://www.azillionmonkeys.com/qed/pstdint.h 22 | * and change next line to: 23 | * #include "pstdint.h" 24 | */ 25 | #include "pstdint.h" 26 | 27 | #define F_MODRM 0x00000001 28 | #define F_SIB 0x00000002 29 | #define F_IMM8 0x00000004 30 | #define F_IMM16 0x00000008 31 | #define F_IMM32 0x00000010 32 | #define F_DISP8 0x00000020 33 | #define F_DISP16 0x00000040 34 | #define F_DISP32 0x00000080 35 | #define F_RELATIVE 0x00000100 36 | #define F_2IMM16 0x00000800 37 | #define F_ERROR 0x00001000 38 | #define F_ERROR_OPCODE 0x00002000 39 | #define F_ERROR_LENGTH 0x00004000 40 | #define F_ERROR_LOCK 0x00008000 41 | #define F_ERROR_OPERAND 0x00010000 42 | #define F_PREFIX_REPNZ 0x01000000 43 | #define F_PREFIX_REPX 0x02000000 44 | #define F_PREFIX_REP 0x03000000 45 | #define F_PREFIX_66 0x04000000 46 | #define F_PREFIX_67 0x08000000 47 | #define F_PREFIX_LOCK 0x10000000 48 | #define F_PREFIX_SEG 0x20000000 49 | #define F_PREFIX_ANY 0x3f000000 50 | 51 | #define PREFIX_SEGMENT_CS 0x2e 52 | #define PREFIX_SEGMENT_SS 0x36 53 | #define PREFIX_SEGMENT_DS 0x3e 54 | #define PREFIX_SEGMENT_ES 0x26 55 | #define PREFIX_SEGMENT_FS 0x64 56 | #define PREFIX_SEGMENT_GS 0x65 57 | #define PREFIX_LOCK 0xf0 58 | #define PREFIX_REPNZ 0xf2 59 | #define PREFIX_REPX 0xf3 60 | #define PREFIX_OPERAND_SIZE 0x66 61 | #define PREFIX_ADDRESS_SIZE 0x67 62 | 63 | #pragma pack(push,1) 64 | 65 | typedef struct { 66 | uint8_t len; 67 | uint8_t p_rep; 68 | uint8_t p_lock; 69 | uint8_t p_seg; 70 | uint8_t p_66; 71 | uint8_t p_67; 72 | uint8_t opcode; 73 | uint8_t opcode2; 74 | uint8_t modrm; 75 | uint8_t modrm_mod; 76 | uint8_t modrm_reg; 77 | uint8_t modrm_rm; 78 | uint8_t sib; 79 | uint8_t sib_scale; 80 | uint8_t sib_index; 81 | uint8_t sib_base; 82 | union { 83 | uint8_t imm8; 84 | uint16_t imm16; 85 | uint32_t imm32; 86 | } imm; 87 | union { 88 | uint8_t disp8; 89 | uint16_t disp16; 90 | uint32_t disp32; 91 | } disp; 92 | uint32_t flags; 93 | } hde32s; 94 | 95 | #pragma pack(pop) 96 | 97 | #ifdef __cplusplus 98 | extern "C" { 99 | #endif 100 | 101 | /* __cdecl */ 102 | unsigned int hde32_disasm(const void *code, hde32s *hs); 103 | 104 | #ifdef __cplusplus 105 | } 106 | #endif 107 | 108 | #endif //_WIN32 109 | #endif /* _HDE32_H_ */ 110 | -------------------------------------------------------------------------------- /dllloader/minhook/src/hde/hde64.c: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * Hacker Disassembler Engine 64 C 5 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 6 | * All rights reserved. 7 | * 8 | */ 9 | 10 | #if defined(_WIN32) && (defined(_M_X64) || defined(__x86_64__)) 11 | 12 | #include "hde64.h" 13 | #include "table64.h" 14 | 15 | unsigned int hde64_disasm(const void *code, hde64s *hs) 16 | { 17 | uint8_t x, c = 0, *p = (uint8_t *)code, cflags, opcode, pref = 0; 18 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; 19 | uint8_t op64 = 0; 20 | 21 | // Avoid using memset to reduce the footprint. 22 | #ifndef _MSC_VER 23 | memset((LPBYTE)hs, 0, sizeof(hde64s)); 24 | #else 25 | __stosb((LPBYTE)hs, 0, sizeof(hde64s)); 26 | #endif 27 | 28 | for (x = 16; x; x--) 29 | switch (c = *p++) { 30 | case 0xf3: 31 | hs->p_rep = c; 32 | pref |= PRE_F3; 33 | break; 34 | case 0xf2: 35 | hs->p_rep = c; 36 | pref |= PRE_F2; 37 | break; 38 | case 0xf0: 39 | hs->p_lock = c; 40 | pref |= PRE_LOCK; 41 | break; 42 | case 0x26: case 0x2e: case 0x36: 43 | case 0x3e: case 0x64: case 0x65: 44 | hs->p_seg = c; 45 | pref |= PRE_SEG; 46 | break; 47 | case 0x66: 48 | hs->p_66 = c; 49 | pref |= PRE_66; 50 | break; 51 | case 0x67: 52 | hs->p_67 = c; 53 | pref |= PRE_67; 54 | break; 55 | default: 56 | goto pref_done; 57 | } 58 | pref_done: 59 | 60 | hs->flags = (uint32_t)pref << 23; 61 | 62 | if (!pref) 63 | pref |= PRE_NONE; 64 | 65 | if ((c & 0xf0) == 0x40) { 66 | hs->flags |= F_PREFIX_REX; 67 | hs->rex_w = (c & 0xf) >> 3; 68 | if (hs->rex_w && (*p & 0xf8) == 0xb8) 69 | op64++; 70 | hs->rex_r = (c & 7) >> 2; 71 | hs->rex_x = (c & 3) >> 1; 72 | hs->rex_b = c & 1; 73 | if (((c = *p++) & 0xf0) == 0x40) { 74 | opcode = c; 75 | goto error_opcode; 76 | } 77 | } 78 | 79 | if ((hs->opcode = c) == 0x0f) { 80 | hs->opcode2 = c = *p++; 81 | ht += DELTA_OPCODES; 82 | } else if (c >= 0xa0 && c <= 0xa3) { 83 | op64++; 84 | if (pref & PRE_67) 85 | pref |= PRE_66; 86 | else 87 | pref &= ~PRE_66; 88 | } 89 | 90 | opcode = c; 91 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 92 | 93 | if (cflags == C_ERROR) { 94 | error_opcode: 95 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 96 | cflags = 0; 97 | if ((opcode & -3) == 0x24) 98 | cflags++; 99 | } 100 | 101 | x = 0; 102 | if (cflags & C_GROUP) { 103 | uint16_t t; 104 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 105 | cflags = (uint8_t)t; 106 | x = (uint8_t)(t >> 8); 107 | } 108 | 109 | if (hs->opcode2) { 110 | ht = hde64_table + DELTA_PREFIXES; 111 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 112 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 113 | } 114 | 115 | if (cflags & C_MODRM) { 116 | hs->flags |= F_MODRM; 117 | hs->modrm = c = *p++; 118 | hs->modrm_mod = m_mod = c >> 6; 119 | hs->modrm_rm = m_rm = c & 7; 120 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 121 | 122 | if (x && ((x << m_reg) & 0x80)) 123 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 124 | 125 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 126 | uint8_t t = opcode - 0xd9; 127 | if (m_mod == 3) { 128 | ht = hde64_table + DELTA_FPU_MODRM + t*8; 129 | t = ht[m_reg] << m_rm; 130 | } else { 131 | ht = hde64_table + DELTA_FPU_REG; 132 | t = ht[t] << m_reg; 133 | } 134 | if (t & 0x80) 135 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 136 | } 137 | 138 | if (pref & PRE_LOCK) { 139 | if (m_mod == 3) { 140 | hs->flags |= F_ERROR | F_ERROR_LOCK; 141 | } else { 142 | uint8_t *table_end, op = opcode; 143 | if (hs->opcode2) { 144 | ht = hde64_table + DELTA_OP2_LOCK_OK; 145 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 146 | } else { 147 | ht = hde64_table + DELTA_OP_LOCK_OK; 148 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 149 | op &= -2; 150 | } 151 | for (; ht != table_end; ht++) 152 | if (*ht++ == op) { 153 | if (!((*ht << m_reg) & 0x80)) 154 | goto no_lock_error; 155 | else 156 | break; 157 | } 158 | hs->flags |= F_ERROR | F_ERROR_LOCK; 159 | no_lock_error: 160 | ; 161 | } 162 | } 163 | 164 | if (hs->opcode2) { 165 | switch (opcode) { 166 | case 0x20: case 0x22: 167 | m_mod = 3; 168 | if (m_reg > 4 || m_reg == 1) 169 | goto error_operand; 170 | else 171 | goto no_error_operand; 172 | case 0x21: case 0x23: 173 | m_mod = 3; 174 | if (m_reg == 4 || m_reg == 5) 175 | goto error_operand; 176 | else 177 | goto no_error_operand; 178 | } 179 | } else { 180 | switch (opcode) { 181 | case 0x8c: 182 | if (m_reg > 5) 183 | goto error_operand; 184 | else 185 | goto no_error_operand; 186 | case 0x8e: 187 | if (m_reg == 1 || m_reg > 5) 188 | goto error_operand; 189 | else 190 | goto no_error_operand; 191 | } 192 | } 193 | 194 | if (m_mod == 3) { 195 | uint8_t *table_end; 196 | if (hs->opcode2) { 197 | ht = hde64_table + DELTA_OP2_ONLY_MEM; 198 | table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; 199 | } else { 200 | ht = hde64_table + DELTA_OP_ONLY_MEM; 201 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 202 | } 203 | for (; ht != table_end; ht += 2) 204 | if (*ht++ == opcode) { 205 | if (*ht++ & pref && !((*ht << m_reg) & 0x80)) 206 | goto error_operand; 207 | else 208 | break; 209 | } 210 | goto no_error_operand; 211 | } else if (hs->opcode2) { 212 | switch (opcode) { 213 | case 0x50: case 0xd7: case 0xf7: 214 | if (pref & (PRE_NONE | PRE_66)) 215 | goto error_operand; 216 | break; 217 | case 0xd6: 218 | if (pref & (PRE_F2 | PRE_F3)) 219 | goto error_operand; 220 | break; 221 | case 0xc5: 222 | goto error_operand; 223 | } 224 | goto no_error_operand; 225 | } else 226 | goto no_error_operand; 227 | 228 | error_operand: 229 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 230 | no_error_operand: 231 | 232 | c = *p++; 233 | if (m_reg <= 1) { 234 | if (opcode == 0xf6) 235 | cflags |= C_IMM8; 236 | else if (opcode == 0xf7) 237 | cflags |= C_IMM_P66; 238 | } 239 | 240 | switch (m_mod) { 241 | case 0: 242 | if (pref & PRE_67) { 243 | if (m_rm == 6) 244 | disp_size = 2; 245 | } else 246 | if (m_rm == 5) 247 | disp_size = 4; 248 | break; 249 | case 1: 250 | disp_size = 1; 251 | break; 252 | case 2: 253 | disp_size = 2; 254 | if (!(pref & PRE_67)) 255 | disp_size <<= 1; 256 | } 257 | 258 | if (m_mod != 3 && m_rm == 4) { 259 | hs->flags |= F_SIB; 260 | p++; 261 | hs->sib = c; 262 | hs->sib_scale = c >> 6; 263 | hs->sib_index = (c & 0x3f) >> 3; 264 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 265 | disp_size = 4; 266 | } 267 | 268 | p--; 269 | switch (disp_size) { 270 | case 1: 271 | hs->flags |= F_DISP8; 272 | hs->disp.disp8 = *p; 273 | break; 274 | case 2: 275 | hs->flags |= F_DISP16; 276 | hs->disp.disp16 = *(uint16_t *)p; 277 | break; 278 | case 4: 279 | hs->flags |= F_DISP32; 280 | hs->disp.disp32 = *(uint32_t *)p; 281 | } 282 | p += disp_size; 283 | } else if (pref & PRE_LOCK) 284 | hs->flags |= F_ERROR | F_ERROR_LOCK; 285 | 286 | if (cflags & C_IMM_P66) { 287 | if (cflags & C_REL32) { 288 | if (pref & PRE_66) { 289 | hs->flags |= F_IMM16 | F_RELATIVE; 290 | hs->imm.imm16 = *(uint16_t *)p; 291 | p += 2; 292 | goto disasm_done; 293 | } 294 | goto rel32_ok; 295 | } 296 | if (op64) { 297 | hs->flags |= F_IMM64; 298 | hs->imm.imm64 = *(uint64_t *)p; 299 | p += 8; 300 | } else if (!(pref & PRE_66)) { 301 | hs->flags |= F_IMM32; 302 | hs->imm.imm32 = *(uint32_t *)p; 303 | p += 4; 304 | } else 305 | goto imm16_ok; 306 | } 307 | 308 | 309 | if (cflags & C_IMM16) { 310 | imm16_ok: 311 | hs->flags |= F_IMM16; 312 | hs->imm.imm16 = *(uint16_t *)p; 313 | p += 2; 314 | } 315 | if (cflags & C_IMM8) { 316 | hs->flags |= F_IMM8; 317 | hs->imm.imm8 = *p++; 318 | } 319 | 320 | if (cflags & C_REL32) { 321 | rel32_ok: 322 | hs->flags |= F_IMM32 | F_RELATIVE; 323 | hs->imm.imm32 = *(uint32_t *)p; 324 | p += 4; 325 | } else if (cflags & C_REL8) { 326 | hs->flags |= F_IMM8 | F_RELATIVE; 327 | hs->imm.imm8 = *p++; 328 | } 329 | 330 | disasm_done: 331 | 332 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 333 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 334 | hs->len = 15; 335 | } 336 | 337 | return (unsigned int)hs->len; 338 | } 339 | 340 | #else 341 | #ifdef _MSC_VER 342 | #pragma warning(disable: 4206) //nonstandard extension used: translation unit is empty 343 | #endif 344 | #endif // defined(_WIN32) && (defined(_M_X64) || defined(__x86_64__)) 345 | -------------------------------------------------------------------------------- /dllloader/minhook/src/hde/hde64.h: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * Hacker Disassembler Engine 64 5 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 6 | * All rights reserved. 7 | * 8 | * hde64.h: C/C++ header file 9 | * 10 | */ 11 | 12 | #ifndef _HDE64_H_ 13 | #define _HDE64_H_ 14 | #if defined(_WIN32) //Windows only 15 | 16 | /* stdint.h - C99 standard header 17 | * http://en.wikipedia.org/wiki/stdint.h 18 | * 19 | * if your compiler doesn't contain "stdint.h" header (for 20 | * example, Microsoft Visual C++), you can download file: 21 | * http://www.azillionmonkeys.com/qed/pstdint.h 22 | * and change next line to: 23 | * #include "pstdint.h" 24 | */ 25 | #include "pstdint.h" 26 | 27 | #define F_MODRM 0x00000001 28 | #define F_SIB 0x00000002 29 | #define F_IMM8 0x00000004 30 | #define F_IMM16 0x00000008 31 | #define F_IMM32 0x00000010 32 | #define F_IMM64 0x00000020 33 | #define F_DISP8 0x00000040 34 | #define F_DISP16 0x00000080 35 | #define F_DISP32 0x00000100 36 | #define F_RELATIVE 0x00000200 37 | #define F_ERROR 0x00001000 38 | #define F_ERROR_OPCODE 0x00002000 39 | #define F_ERROR_LENGTH 0x00004000 40 | #define F_ERROR_LOCK 0x00008000 41 | #define F_ERROR_OPERAND 0x00010000 42 | #define F_PREFIX_REPNZ 0x01000000 43 | #define F_PREFIX_REPX 0x02000000 44 | #define F_PREFIX_REP 0x03000000 45 | #define F_PREFIX_66 0x04000000 46 | #define F_PREFIX_67 0x08000000 47 | #define F_PREFIX_LOCK 0x10000000 48 | #define F_PREFIX_SEG 0x20000000 49 | #define F_PREFIX_REX 0x40000000 50 | #define F_PREFIX_ANY 0x7f000000 51 | 52 | #define PREFIX_SEGMENT_CS 0x2e 53 | #define PREFIX_SEGMENT_SS 0x36 54 | #define PREFIX_SEGMENT_DS 0x3e 55 | #define PREFIX_SEGMENT_ES 0x26 56 | #define PREFIX_SEGMENT_FS 0x64 57 | #define PREFIX_SEGMENT_GS 0x65 58 | #define PREFIX_LOCK 0xf0 59 | #define PREFIX_REPNZ 0xf2 60 | #define PREFIX_REPX 0xf3 61 | #define PREFIX_OPERAND_SIZE 0x66 62 | #define PREFIX_ADDRESS_SIZE 0x67 63 | 64 | #pragma pack(push,1) 65 | 66 | typedef struct { 67 | uint8_t len; 68 | uint8_t p_rep; 69 | uint8_t p_lock; 70 | uint8_t p_seg; 71 | uint8_t p_66; 72 | uint8_t p_67; 73 | uint8_t rex; 74 | uint8_t rex_w; 75 | uint8_t rex_r; 76 | uint8_t rex_x; 77 | uint8_t rex_b; 78 | uint8_t opcode; 79 | uint8_t opcode2; 80 | uint8_t modrm; 81 | uint8_t modrm_mod; 82 | uint8_t modrm_reg; 83 | uint8_t modrm_rm; 84 | uint8_t sib; 85 | uint8_t sib_scale; 86 | uint8_t sib_index; 87 | uint8_t sib_base; 88 | union { 89 | uint8_t imm8; 90 | uint16_t imm16; 91 | uint32_t imm32; 92 | uint64_t imm64; 93 | } imm; 94 | union { 95 | uint8_t disp8; 96 | uint16_t disp16; 97 | uint32_t disp32; 98 | } disp; 99 | uint32_t flags; 100 | } hde64s; 101 | 102 | #pragma pack(pop) 103 | 104 | #ifdef __cplusplus 105 | extern "C" { 106 | #endif 107 | 108 | /* __cdecl */ 109 | unsigned int hde64_disasm(const void *code, hde64s *hs); 110 | 111 | #ifdef __cplusplus 112 | } 113 | #endif 114 | 115 | #endif //_WIN32 116 | #endif /* _HDE64_H_ */ 117 | -------------------------------------------------------------------------------- /dllloader/minhook/src/hde/pstdint.h: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * MinHook - The Minimalistic API Hooking Library for x64/x86 5 | * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | #if defined(_WIN32) //Windows only 31 | 32 | #include 33 | 34 | // Integer types for HDE. 35 | typedef INT8 int8_t; 36 | typedef INT16 int16_t; 37 | typedef INT32 int32_t; 38 | typedef INT64 int64_t; 39 | typedef UINT8 uint8_t; 40 | typedef UINT16 uint16_t; 41 | typedef UINT32 uint32_t; 42 | typedef UINT64 uint64_t; 43 | 44 | #endif //_WIN32 45 | -------------------------------------------------------------------------------- /dllloader/minhook/src/hde/table32.h: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * Hacker Disassembler Engine 32 C 5 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 6 | * All rights reserved. 7 | * 8 | */ 9 | 10 | #define C_NONE 0x00 11 | #define C_MODRM 0x01 12 | #define C_IMM8 0x02 13 | #define C_IMM16 0x04 14 | #define C_IMM_P66 0x10 15 | #define C_REL8 0x20 16 | #define C_REL32 0x40 17 | #define C_GROUP 0x80 18 | #define C_ERROR 0xff 19 | 20 | #define PRE_ANY 0x00 21 | #define PRE_NONE 0x01 22 | #define PRE_F2 0x02 23 | #define PRE_F3 0x04 24 | #define PRE_66 0x08 25 | #define PRE_67 0x10 26 | #define PRE_LOCK 0x20 27 | #define PRE_SEG 0x40 28 | #define PRE_ALL 0xff 29 | 30 | #define DELTA_OPCODES 0x4a 31 | #define DELTA_FPU_REG 0xf1 32 | #define DELTA_FPU_MODRM 0xf8 33 | #define DELTA_PREFIXES 0x130 34 | #define DELTA_OP_LOCK_OK 0x1a1 35 | #define DELTA_OP2_LOCK_OK 0x1b9 36 | #define DELTA_OP_ONLY_MEM 0x1cb 37 | #define DELTA_OP2_ONLY_MEM 0x1da 38 | 39 | unsigned char hde32_table[] = { 40 | 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, 41 | 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, 42 | 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, 43 | 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, 44 | 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, 45 | 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, 46 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, 47 | 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, 48 | 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, 49 | 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, 50 | 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, 51 | 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, 52 | 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, 53 | 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, 54 | 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, 55 | 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, 56 | 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, 58 | 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 59 | 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 60 | 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, 61 | 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, 62 | 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, 63 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, 64 | 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, 65 | 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, 66 | 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 67 | 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, 68 | 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, 69 | 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, 70 | 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, 71 | 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, 72 | 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, 73 | 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, 74 | 0xe7,0x08,0x00,0xf0,0x02,0x00 75 | }; 76 | -------------------------------------------------------------------------------- /dllloader/minhook/src/hde/table64.h: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * Hacker Disassembler Engine 64 C 5 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 6 | * All rights reserved. 7 | * 8 | */ 9 | 10 | #define C_NONE 0x00 11 | #define C_MODRM 0x01 12 | #define C_IMM8 0x02 13 | #define C_IMM16 0x04 14 | #define C_IMM_P66 0x10 15 | #define C_REL8 0x20 16 | #define C_REL32 0x40 17 | #define C_GROUP 0x80 18 | #define C_ERROR 0xff 19 | 20 | #define PRE_ANY 0x00 21 | #define PRE_NONE 0x01 22 | #define PRE_F2 0x02 23 | #define PRE_F3 0x04 24 | #define PRE_66 0x08 25 | #define PRE_67 0x10 26 | #define PRE_LOCK 0x20 27 | #define PRE_SEG 0x40 28 | #define PRE_ALL 0xff 29 | 30 | #define DELTA_OPCODES 0x4a 31 | #define DELTA_FPU_REG 0xfd 32 | #define DELTA_FPU_MODRM 0x104 33 | #define DELTA_PREFIXES 0x13c 34 | #define DELTA_OP_LOCK_OK 0x1ae 35 | #define DELTA_OP2_LOCK_OK 0x1c6 36 | #define DELTA_OP_ONLY_MEM 0x1d8 37 | #define DELTA_OP2_ONLY_MEM 0x1e7 38 | 39 | unsigned char hde64_table[] = { 40 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, 41 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, 42 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, 43 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, 44 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, 45 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, 46 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, 47 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, 48 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, 49 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, 50 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, 51 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, 52 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, 53 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, 54 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, 55 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, 56 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, 57 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, 58 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, 59 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 60 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, 61 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, 62 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, 63 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 64 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, 65 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, 66 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, 67 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 68 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, 69 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, 70 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, 71 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, 72 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, 73 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, 74 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, 75 | 0x00,0xf0,0x02,0x00 76 | }; 77 | -------------------------------------------------------------------------------- /dllloader/minhook/src/hook.c: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * MinHook - The Minimalistic API Hooking Library for x64/x86 5 | * Copyright (C) 2009-2017 Tsuda Kageyu. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 22 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #if defined(_WIN32) //Windows only 31 | #include 32 | #include 33 | #include 34 | 35 | #include "../include/MinHook.h" 36 | #include "buffer.h" 37 | #include "trampoline.h" 38 | 39 | #ifndef ARRAYSIZE 40 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 41 | #endif 42 | 43 | // Initial capacity of the HOOK_ENTRY buffer. 44 | #define INITIAL_HOOK_CAPACITY 32 45 | 46 | // Initial capacity of the thread IDs buffer. 47 | #define INITIAL_THREAD_CAPACITY 128 48 | 49 | // Special hook position values. 50 | #define INVALID_HOOK_POS UINT_MAX 51 | #define ALL_HOOKS_POS UINT_MAX 52 | 53 | // Freeze() action argument defines. 54 | #define ACTION_DISABLE 0 55 | #define ACTION_ENABLE 1 56 | #define ACTION_APPLY_QUEUED 2 57 | 58 | // Thread access rights for suspending/resuming threads. 59 | #define THREAD_ACCESS \ 60 | (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) 61 | 62 | // Hook information. 63 | typedef struct _HOOK_ENTRY 64 | { 65 | LPVOID pTarget; // Address of the target function. 66 | LPVOID pDetour; // Address of the detour or relay function. 67 | LPVOID pTrampoline; // Address of the trampoline function. 68 | UINT8 backup[8]; // Original prologue of the target function. 69 | 70 | UINT8 patchAbove; // Uses the hot patch area. 71 | UINT8 isEnabled; // Enabled. 72 | UINT8 queueEnable; // Queued for enabling/disabling when != isEnabled. 73 | 74 | UINT nIP : 4; // Count of the instruction boundaries. 75 | UINT8 oldIPs[8]; // Instruction boundaries of the target function. 76 | UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. 77 | } HOOK_ENTRY, *PHOOK_ENTRY; 78 | 79 | // Suspended threads for Freeze()/Unfreeze(). 80 | typedef struct _FROZEN_THREADS 81 | { 82 | LPDWORD pItems; // Data heap 83 | UINT capacity; // Size of allocated data heap, items 84 | UINT size; // Actual number of data items 85 | } FROZEN_THREADS, *PFROZEN_THREADS; 86 | 87 | //------------------------------------------------------------------------- 88 | // Global Variables: 89 | //------------------------------------------------------------------------- 90 | 91 | // Spin lock flag for EnterSpinLock()/LeaveSpinLock(). 92 | volatile LONG g_isLocked = FALSE; 93 | 94 | // Private heap handle. If not NULL, this library is initialized. 95 | HANDLE g_hHeap = NULL; 96 | 97 | // Hook entries. 98 | struct 99 | { 100 | PHOOK_ENTRY pItems; // Data heap 101 | UINT capacity; // Size of allocated data heap, items 102 | UINT size; // Actual number of data items 103 | } g_hooks; 104 | 105 | //------------------------------------------------------------------------- 106 | // Returns INVALID_HOOK_POS if not found. 107 | static UINT FindHookEntry(LPVOID pTarget) 108 | { 109 | UINT i; 110 | for (i = 0; i < g_hooks.size; ++i) 111 | { 112 | if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget) 113 | return i; 114 | } 115 | 116 | return INVALID_HOOK_POS; 117 | } 118 | 119 | //------------------------------------------------------------------------- 120 | static PHOOK_ENTRY AddHookEntry() 121 | { 122 | if (g_hooks.pItems == NULL) 123 | { 124 | g_hooks.capacity = INITIAL_HOOK_CAPACITY; 125 | g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( 126 | g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); 127 | if (g_hooks.pItems == NULL) 128 | return NULL; 129 | } 130 | else if (g_hooks.size >= g_hooks.capacity) 131 | { 132 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( 133 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); 134 | if (p == NULL) 135 | return NULL; 136 | 137 | g_hooks.capacity *= 2; 138 | g_hooks.pItems = p; 139 | } 140 | 141 | return &g_hooks.pItems[g_hooks.size++]; 142 | } 143 | 144 | //------------------------------------------------------------------------- 145 | static void DeleteHookEntry(UINT pos) 146 | { 147 | if (pos < g_hooks.size - 1) 148 | g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; 149 | 150 | g_hooks.size--; 151 | 152 | if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) 153 | { 154 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( 155 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); 156 | if (p == NULL) 157 | return; 158 | 159 | g_hooks.capacity /= 2; 160 | g_hooks.pItems = p; 161 | } 162 | } 163 | 164 | //------------------------------------------------------------------------- 165 | static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) 166 | { 167 | UINT i; 168 | 169 | if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) 170 | return (DWORD_PTR)pHook->pTarget; 171 | 172 | for (i = 0; i < pHook->nIP; ++i) 173 | { 174 | if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i])) 175 | return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; 176 | } 177 | 178 | #if defined(_M_X64) || defined(__x86_64__) 179 | // Check relay function. 180 | if (ip == (DWORD_PTR)pHook->pDetour) 181 | return (DWORD_PTR)pHook->pTarget; 182 | #endif 183 | 184 | return 0; 185 | } 186 | 187 | //------------------------------------------------------------------------- 188 | static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) 189 | { 190 | UINT i; 191 | for (i = 0; i < pHook->nIP; ++i) 192 | { 193 | if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) 194 | return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]; 195 | } 196 | 197 | return 0; 198 | } 199 | 200 | //------------------------------------------------------------------------- 201 | static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) 202 | { 203 | // If the thread suspended in the overwritten area, 204 | // move IP to the proper address. 205 | 206 | CONTEXT c; 207 | #if defined(_M_X64) || defined(__x86_64__) 208 | DWORD64 *pIP = &c.Rip; 209 | #else 210 | DWORD *pIP = &c.Eip; 211 | #endif 212 | UINT count; 213 | 214 | c.ContextFlags = CONTEXT_CONTROL; 215 | if (!GetThreadContext(hThread, &c)) 216 | return; 217 | 218 | if (pos == ALL_HOOKS_POS) 219 | { 220 | pos = 0; 221 | count = g_hooks.size; 222 | } 223 | else 224 | { 225 | count = pos + 1; 226 | } 227 | 228 | for (; pos < count; ++pos) 229 | { 230 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; 231 | BOOL enable; 232 | DWORD_PTR ip; 233 | 234 | switch (action) 235 | { 236 | case ACTION_DISABLE: 237 | enable = FALSE; 238 | break; 239 | 240 | case ACTION_ENABLE: 241 | enable = TRUE; 242 | break; 243 | 244 | default: // ACTION_APPLY_QUEUED 245 | enable = pHook->queueEnable; 246 | break; 247 | } 248 | if (pHook->isEnabled == enable) 249 | continue; 250 | 251 | if (enable) 252 | ip = FindNewIP(pHook, *pIP); 253 | else 254 | ip = FindOldIP(pHook, *pIP); 255 | 256 | if (ip != 0) 257 | { 258 | *pIP = ip; 259 | SetThreadContext(hThread, &c); 260 | } 261 | } 262 | } 263 | 264 | //------------------------------------------------------------------------- 265 | static VOID EnumerateThreads(PFROZEN_THREADS pThreads) 266 | { 267 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 268 | if (hSnapshot != INVALID_HANDLE_VALUE) 269 | { 270 | THREADENTRY32 te; 271 | te.dwSize = sizeof(THREADENTRY32); 272 | if (Thread32First(hSnapshot, &te)) 273 | { 274 | do 275 | { 276 | if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) 277 | && te.th32OwnerProcessID == GetCurrentProcessId() 278 | && te.th32ThreadID != GetCurrentThreadId()) 279 | { 280 | if (pThreads->pItems == NULL) 281 | { 282 | pThreads->capacity = INITIAL_THREAD_CAPACITY; 283 | pThreads->pItems 284 | = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD)); 285 | if (pThreads->pItems == NULL) 286 | break; 287 | } 288 | else if (pThreads->size >= pThreads->capacity) 289 | { 290 | LPDWORD p = (LPDWORD)HeapReAlloc( 291 | g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD)); 292 | if (p == NULL) 293 | break; 294 | 295 | pThreads->capacity *= 2; 296 | pThreads->pItems = p; 297 | } 298 | pThreads->pItems[pThreads->size++] = te.th32ThreadID; 299 | } 300 | 301 | te.dwSize = sizeof(THREADENTRY32); 302 | } while (Thread32Next(hSnapshot, &te)); 303 | } 304 | CloseHandle(hSnapshot); 305 | } 306 | } 307 | 308 | //------------------------------------------------------------------------- 309 | static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action) 310 | { 311 | pThreads->pItems = NULL; 312 | pThreads->capacity = 0; 313 | pThreads->size = 0; 314 | EnumerateThreads(pThreads); 315 | 316 | if (pThreads->pItems != NULL) 317 | { 318 | UINT i; 319 | for (i = 0; i < pThreads->size; ++i) 320 | { 321 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); 322 | if (hThread != NULL) 323 | { 324 | SuspendThread(hThread); 325 | ProcessThreadIPs(hThread, pos, action); 326 | CloseHandle(hThread); 327 | } 328 | } 329 | } 330 | } 331 | 332 | //------------------------------------------------------------------------- 333 | static VOID Unfreeze(PFROZEN_THREADS pThreads) 334 | { 335 | if (pThreads->pItems != NULL) 336 | { 337 | UINT i; 338 | for (i = 0; i < pThreads->size; ++i) 339 | { 340 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); 341 | if (hThread != NULL) 342 | { 343 | ResumeThread(hThread); 344 | CloseHandle(hThread); 345 | } 346 | } 347 | 348 | HeapFree(g_hHeap, 0, pThreads->pItems); 349 | } 350 | } 351 | 352 | //------------------------------------------------------------------------- 353 | static MH_STATUS EnableHookLL(UINT pos, BOOL enable) 354 | { 355 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; 356 | DWORD oldProtect; 357 | SIZE_T patchSize = sizeof(JMP_REL); 358 | LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; 359 | 360 | if (pHook->patchAbove) 361 | { 362 | pPatchTarget -= sizeof(JMP_REL); 363 | patchSize += sizeof(JMP_REL_SHORT); 364 | } 365 | 366 | if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) 367 | return MH_ERROR_MEMORY_PROTECT; 368 | 369 | if (enable) 370 | { 371 | PJMP_REL pJmp = (PJMP_REL)pPatchTarget; 372 | pJmp->opcode = 0xE9; 373 | pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL))); 374 | 375 | if (pHook->patchAbove) 376 | { 377 | PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; 378 | pShortJmp->opcode = 0xEB; 379 | pShortJmp->operand = (UINT8)(0 - ((UINT8)sizeof(JMP_REL_SHORT) + (UINT8)sizeof(JMP_REL))); 380 | } 381 | } 382 | else 383 | { 384 | if (pHook->patchAbove) 385 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); 386 | else 387 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); 388 | } 389 | 390 | VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); 391 | 392 | // Just-in-case measure. 393 | FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); 394 | 395 | pHook->isEnabled = (UINT8)enable; 396 | pHook->queueEnable = (UINT8)enable; 397 | 398 | return MH_OK; 399 | } 400 | 401 | //------------------------------------------------------------------------- 402 | static MH_STATUS EnableAllHooksLL(BOOL enable) 403 | { 404 | MH_STATUS status = MH_OK; 405 | UINT i, first = INVALID_HOOK_POS; 406 | 407 | for (i = 0; i < g_hooks.size; ++i) 408 | { 409 | if (g_hooks.pItems[i].isEnabled != enable) 410 | { 411 | first = i; 412 | break; 413 | } 414 | } 415 | 416 | if (first != INVALID_HOOK_POS) 417 | { 418 | FROZEN_THREADS threads; 419 | Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE); 420 | 421 | for (i = first; i < g_hooks.size; ++i) 422 | { 423 | if (g_hooks.pItems[i].isEnabled != enable) 424 | { 425 | status = EnableHookLL(i, enable); 426 | if (status != MH_OK) 427 | break; 428 | } 429 | } 430 | 431 | Unfreeze(&threads); 432 | } 433 | 434 | return status; 435 | } 436 | 437 | //------------------------------------------------------------------------- 438 | static VOID EnterSpinLock(VOID) 439 | { 440 | SIZE_T spinCount = 0; 441 | 442 | // Wait until the flag is FALSE. 443 | while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE) 444 | { 445 | // No need to generate a memory barrier here, since InterlockedCompareExchange() 446 | // generates a full memory barrier itself. 447 | 448 | // Prevent the loop from being too busy. 449 | if (spinCount < 32) 450 | Sleep(0); 451 | else 452 | Sleep(1); 453 | 454 | spinCount++; 455 | } 456 | } 457 | 458 | //------------------------------------------------------------------------- 459 | static VOID LeaveSpinLock(VOID) 460 | { 461 | // No need to generate a memory barrier here, since InterlockedExchange() 462 | // generates a full memory barrier itself. 463 | 464 | InterlockedExchange(&g_isLocked, FALSE); 465 | } 466 | 467 | //------------------------------------------------------------------------- 468 | MH_STATUS WINAPI MH_Initialize(VOID) 469 | { 470 | MH_STATUS status = MH_OK; 471 | 472 | EnterSpinLock(); 473 | 474 | if (g_hHeap == NULL) 475 | { 476 | g_hHeap = HeapCreate(0, 0, 0); 477 | if (g_hHeap != NULL) 478 | { 479 | // Initialize the internal function buffer. 480 | InitializeBuffer(); 481 | } 482 | else 483 | { 484 | status = MH_ERROR_MEMORY_ALLOC; 485 | } 486 | } 487 | else 488 | { 489 | status = MH_ERROR_ALREADY_INITIALIZED; 490 | } 491 | 492 | LeaveSpinLock(); 493 | 494 | return status; 495 | } 496 | 497 | //------------------------------------------------------------------------- 498 | MH_STATUS WINAPI MH_Uninitialize(VOID) 499 | { 500 | MH_STATUS status = MH_OK; 501 | 502 | EnterSpinLock(); 503 | 504 | if (g_hHeap != NULL) 505 | { 506 | status = EnableAllHooksLL(FALSE); 507 | if (status == MH_OK) 508 | { 509 | // Free the internal function buffer. 510 | 511 | // HeapFree is actually not required, but some tools detect a false 512 | // memory leak without HeapFree. 513 | 514 | UninitializeBuffer(); 515 | 516 | HeapFree(g_hHeap, 0, g_hooks.pItems); 517 | HeapDestroy(g_hHeap); 518 | 519 | g_hHeap = NULL; 520 | 521 | g_hooks.pItems = NULL; 522 | g_hooks.capacity = 0; 523 | g_hooks.size = 0; 524 | } 525 | } 526 | else 527 | { 528 | status = MH_ERROR_NOT_INITIALIZED; 529 | } 530 | 531 | LeaveSpinLock(); 532 | 533 | return status; 534 | } 535 | 536 | //------------------------------------------------------------------------- 537 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) 538 | { 539 | MH_STATUS status = MH_OK; 540 | 541 | EnterSpinLock(); 542 | 543 | if (g_hHeap != NULL) 544 | { 545 | if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) 546 | { 547 | UINT pos = FindHookEntry(pTarget); 548 | if (pos == INVALID_HOOK_POS) 549 | { 550 | LPVOID pBuffer = AllocateBuffer(pTarget); 551 | if (pBuffer != NULL) 552 | { 553 | TRAMPOLINE ct; 554 | 555 | ct.pTarget = pTarget; 556 | ct.pDetour = pDetour; 557 | ct.pTrampoline = pBuffer; 558 | if (CreateTrampolineFunction(&ct)) 559 | { 560 | PHOOK_ENTRY pHook = AddHookEntry(); 561 | if (pHook != NULL) 562 | { 563 | pHook->pTarget = ct.pTarget; 564 | #if defined(_M_X64) || defined(__x86_64__) 565 | pHook->pDetour = ct.pRelay; 566 | #else 567 | pHook->pDetour = ct.pDetour; 568 | #endif 569 | pHook->pTrampoline = ct.pTrampoline; 570 | pHook->patchAbove = (UINT8)ct.patchAbove; 571 | pHook->isEnabled = FALSE; 572 | pHook->queueEnable = FALSE; 573 | pHook->nIP = ct.nIP; 574 | memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); 575 | memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); 576 | 577 | // Back up the target function. 578 | 579 | if (ct.patchAbove) 580 | { 581 | memcpy( 582 | pHook->backup, 583 | (LPBYTE)pTarget - sizeof(JMP_REL), 584 | sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); 585 | } 586 | else 587 | { 588 | memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); 589 | } 590 | 591 | if (ppOriginal != NULL) 592 | *ppOriginal = pHook->pTrampoline; 593 | } 594 | else 595 | { 596 | status = MH_ERROR_MEMORY_ALLOC; 597 | } 598 | } 599 | else 600 | { 601 | status = MH_ERROR_UNSUPPORTED_FUNCTION; 602 | } 603 | 604 | if (status != MH_OK) 605 | { 606 | FreeBuffer(pBuffer); 607 | } 608 | } 609 | else 610 | { 611 | status = MH_ERROR_MEMORY_ALLOC; 612 | } 613 | } 614 | else 615 | { 616 | status = MH_ERROR_ALREADY_CREATED; 617 | } 618 | } 619 | else 620 | { 621 | status = MH_ERROR_NOT_EXECUTABLE; 622 | } 623 | } 624 | else 625 | { 626 | status = MH_ERROR_NOT_INITIALIZED; 627 | } 628 | 629 | LeaveSpinLock(); 630 | 631 | return status; 632 | } 633 | 634 | //------------------------------------------------------------------------- 635 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) 636 | { 637 | MH_STATUS status = MH_OK; 638 | 639 | EnterSpinLock(); 640 | 641 | if (g_hHeap != NULL) 642 | { 643 | UINT pos = FindHookEntry(pTarget); 644 | if (pos != INVALID_HOOK_POS) 645 | { 646 | if (g_hooks.pItems[pos].isEnabled) 647 | { 648 | FROZEN_THREADS threads; 649 | Freeze(&threads, pos, ACTION_DISABLE); 650 | 651 | status = EnableHookLL(pos, FALSE); 652 | 653 | Unfreeze(&threads); 654 | } 655 | 656 | if (status == MH_OK) 657 | { 658 | FreeBuffer(g_hooks.pItems[pos].pTrampoline); 659 | DeleteHookEntry(pos); 660 | } 661 | } 662 | else 663 | { 664 | status = MH_ERROR_NOT_CREATED; 665 | } 666 | } 667 | else 668 | { 669 | status = MH_ERROR_NOT_INITIALIZED; 670 | } 671 | 672 | LeaveSpinLock(); 673 | 674 | return status; 675 | } 676 | 677 | //------------------------------------------------------------------------- 678 | static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) 679 | { 680 | MH_STATUS status = MH_OK; 681 | 682 | EnterSpinLock(); 683 | 684 | if (g_hHeap != NULL) 685 | { 686 | if (pTarget == MH_ALL_HOOKS) 687 | { 688 | status = EnableAllHooksLL(enable); 689 | } 690 | else 691 | { 692 | FROZEN_THREADS threads; 693 | UINT pos = FindHookEntry(pTarget); 694 | if (pos != INVALID_HOOK_POS) 695 | { 696 | if (g_hooks.pItems[pos].isEnabled != enable) 697 | { 698 | Freeze(&threads, pos, ACTION_ENABLE); 699 | 700 | status = EnableHookLL(pos, enable); 701 | 702 | Unfreeze(&threads); 703 | } 704 | else 705 | { 706 | status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; 707 | } 708 | } 709 | else 710 | { 711 | status = MH_ERROR_NOT_CREATED; 712 | } 713 | } 714 | } 715 | else 716 | { 717 | status = MH_ERROR_NOT_INITIALIZED; 718 | } 719 | 720 | LeaveSpinLock(); 721 | 722 | return status; 723 | } 724 | 725 | //------------------------------------------------------------------------- 726 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) 727 | { 728 | return EnableHook(pTarget, TRUE); 729 | } 730 | 731 | //------------------------------------------------------------------------- 732 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) 733 | { 734 | return EnableHook(pTarget, FALSE); 735 | } 736 | 737 | //------------------------------------------------------------------------- 738 | static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) 739 | { 740 | MH_STATUS status = MH_OK; 741 | 742 | EnterSpinLock(); 743 | 744 | if (g_hHeap != NULL) 745 | { 746 | if (pTarget == MH_ALL_HOOKS) 747 | { 748 | UINT i; 749 | for (i = 0; i < g_hooks.size; ++i) 750 | g_hooks.pItems[i].queueEnable = (UINT8)queueEnable; 751 | } 752 | else 753 | { 754 | UINT pos = FindHookEntry(pTarget); 755 | if (pos != INVALID_HOOK_POS) 756 | { 757 | g_hooks.pItems[pos].queueEnable = (UINT8)queueEnable; 758 | } 759 | else 760 | { 761 | status = MH_ERROR_NOT_CREATED; 762 | } 763 | } 764 | } 765 | else 766 | { 767 | status = MH_ERROR_NOT_INITIALIZED; 768 | } 769 | 770 | LeaveSpinLock(); 771 | 772 | return status; 773 | } 774 | 775 | //------------------------------------------------------------------------- 776 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) 777 | { 778 | return QueueHook(pTarget, TRUE); 779 | } 780 | 781 | //------------------------------------------------------------------------- 782 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) 783 | { 784 | return QueueHook(pTarget, FALSE); 785 | } 786 | 787 | //------------------------------------------------------------------------- 788 | MH_STATUS WINAPI MH_ApplyQueued(VOID) 789 | { 790 | MH_STATUS status = MH_OK; 791 | UINT i, first = INVALID_HOOK_POS; 792 | 793 | EnterSpinLock(); 794 | 795 | if (g_hHeap != NULL) 796 | { 797 | for (i = 0; i < g_hooks.size; ++i) 798 | { 799 | if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) 800 | { 801 | first = i; 802 | break; 803 | } 804 | } 805 | 806 | if (first != INVALID_HOOK_POS) 807 | { 808 | FROZEN_THREADS threads; 809 | Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); 810 | 811 | for (i = first; i < g_hooks.size; ++i) 812 | { 813 | PHOOK_ENTRY pHook = &g_hooks.pItems[i]; 814 | if (pHook->isEnabled != pHook->queueEnable) 815 | { 816 | status = EnableHookLL(i, pHook->queueEnable); 817 | if (status != MH_OK) 818 | break; 819 | } 820 | } 821 | 822 | Unfreeze(&threads); 823 | } 824 | } 825 | else 826 | { 827 | status = MH_ERROR_NOT_INITIALIZED; 828 | } 829 | 830 | LeaveSpinLock(); 831 | 832 | return status; 833 | } 834 | 835 | //------------------------------------------------------------------------- 836 | MH_STATUS WINAPI MH_CreateHookApiEx( 837 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, 838 | LPVOID *ppOriginal, LPVOID *ppTarget) 839 | { 840 | HMODULE hModule; 841 | LPVOID pTarget; 842 | 843 | hModule = GetModuleHandleW(pszModule); 844 | if (hModule == NULL) 845 | return MH_ERROR_MODULE_NOT_FOUND; 846 | 847 | pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); 848 | if (pTarget == NULL) 849 | return MH_ERROR_FUNCTION_NOT_FOUND; 850 | 851 | if(ppTarget != NULL) 852 | *ppTarget = pTarget; 853 | 854 | return MH_CreateHook(pTarget, pDetour, ppOriginal); 855 | } 856 | 857 | //------------------------------------------------------------------------- 858 | MH_STATUS WINAPI MH_CreateHookApi( 859 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) 860 | { 861 | return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); 862 | } 863 | 864 | //------------------------------------------------------------------------- 865 | const char * WINAPI MH_StatusToString(MH_STATUS status) 866 | { 867 | #define MH_ST2STR(x) \ 868 | case x: \ 869 | return #x; 870 | 871 | switch (status) { 872 | MH_ST2STR(MH_UNKNOWN) 873 | MH_ST2STR(MH_OK) 874 | MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) 875 | MH_ST2STR(MH_ERROR_NOT_INITIALIZED) 876 | MH_ST2STR(MH_ERROR_ALREADY_CREATED) 877 | MH_ST2STR(MH_ERROR_NOT_CREATED) 878 | MH_ST2STR(MH_ERROR_ENABLED) 879 | MH_ST2STR(MH_ERROR_DISABLED) 880 | MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) 881 | MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) 882 | MH_ST2STR(MH_ERROR_MEMORY_ALLOC) 883 | MH_ST2STR(MH_ERROR_MEMORY_PROTECT) 884 | MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) 885 | MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) 886 | } 887 | 888 | #undef MH_ST2STR 889 | 890 | return "(unknown)"; 891 | } 892 | 893 | #endif //_WIN32 894 | -------------------------------------------------------------------------------- /dllloader/minhook/src/trampoline.c: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * MinHook - The Minimalistic API Hooking Library for x64/x86 5 | * Copyright (C) 2009-2017 Tsuda Kageyu. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 22 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #if defined(_WIN32) //Windows only 31 | #include 32 | 33 | #ifndef ARRAYSIZE 34 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 35 | #endif 36 | 37 | #if defined(_M_X64) || defined(__x86_64__) 38 | #include "./hde/hde64.h" 39 | typedef hde64s HDE; 40 | #define HDE_DISASM(code, hs) hde64_disasm(code, hs) 41 | #else 42 | #include "./hde/hde32.h" 43 | typedef hde32s HDE; 44 | #define HDE_DISASM(code, hs) hde32_disasm(code, hs) 45 | #endif 46 | 47 | #include "trampoline.h" 48 | #include "buffer.h" 49 | 50 | // Maximum size of a trampoline function. 51 | #if defined(_M_X64) || defined(__x86_64__) 52 | #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) 53 | #else 54 | #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE 55 | #endif 56 | 57 | //------------------------------------------------------------------------- 58 | static BOOL IsCodePadding(LPBYTE pInst, UINT size) 59 | { 60 | UINT i; 61 | 62 | if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) 63 | return FALSE; 64 | 65 | for (i = 1; i < size; ++i) 66 | { 67 | if (pInst[i] != pInst[0]) 68 | return FALSE; 69 | } 70 | return TRUE; 71 | } 72 | 73 | //------------------------------------------------------------------------- 74 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct) 75 | { 76 | #if defined(_M_X64) || defined(__x86_64__) 77 | CALL_ABS call = { 78 | 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] 79 | 0xEB, 0x08, // EB 08: JMP +10 80 | 0x0000000000000000ULL // Absolute destination address 81 | }; 82 | JMP_ABS jmp = { 83 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 84 | 0x0000000000000000ULL // Absolute destination address 85 | }; 86 | JCC_ABS jcc = { 87 | 0x70, 0x0E, // 7* 0E: J** +16 88 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 89 | 0x0000000000000000ULL // Absolute destination address 90 | }; 91 | #else 92 | CALL_REL call = { 93 | 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx 94 | 0x00000000 // Relative destination address 95 | }; 96 | JMP_REL jmp = { 97 | 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx 98 | 0x00000000 // Relative destination address 99 | }; 100 | JCC_REL jcc = { 101 | 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx 102 | 0x00000000 // Relative destination address 103 | }; 104 | #endif 105 | 106 | UINT8 oldPos = 0; 107 | UINT8 newPos = 0; 108 | ULONG_PTR jmpDest = 0; // Destination address of an internal jump. 109 | BOOL finished = FALSE; // Is the function completed? 110 | #if defined(_M_X64) || defined(__x86_64__) 111 | UINT8 instBuf[16]; 112 | #endif 113 | 114 | ct->patchAbove = FALSE; 115 | ct->nIP = 0; 116 | 117 | do 118 | { 119 | HDE hs; 120 | UINT copySize; 121 | LPVOID pCopySrc; 122 | ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; 123 | ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; 124 | 125 | copySize = HDE_DISASM((LPVOID)pOldInst, &hs); 126 | if (hs.flags & F_ERROR) 127 | return FALSE; 128 | 129 | pCopySrc = (LPVOID)pOldInst; 130 | if (oldPos >= sizeof(JMP_REL)) 131 | { 132 | // The trampoline function is long enough. 133 | // Complete the function with the jump to the target function. 134 | #if defined(_M_X64) || defined(__x86_64__) 135 | jmp.address = pOldInst; 136 | #else 137 | jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); 138 | #endif 139 | pCopySrc = &jmp; 140 | copySize = sizeof(jmp); 141 | 142 | finished = TRUE; 143 | } 144 | #if defined(_M_X64) || defined(__x86_64__) 145 | else if ((hs.modrm & 0xC7) == 0x05) 146 | { 147 | // Instructions using RIP relative addressing. (ModR/M = 00???101B) 148 | 149 | // Modify the RIP relative address. 150 | PUINT32 pRelAddr; 151 | 152 | // Avoid using memcpy to reduce the footprint. 153 | #ifndef _MSC_VER 154 | memcpy(instBuf, (LPBYTE)pOldInst, copySize); 155 | #else 156 | __movsb(instBuf, (LPBYTE)pOldInst, copySize); 157 | #endif 158 | pCopySrc = instBuf; 159 | 160 | // Relative address is stored at (instruction length - immediate value length - 4). 161 | pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); 162 | *pRelAddr 163 | = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); 164 | 165 | // Complete the function if JMP (FF /4). 166 | if (hs.opcode == 0xFF && hs.modrm_reg == 4) 167 | finished = TRUE; 168 | } 169 | #endif 170 | else if (hs.opcode == 0xE8) 171 | { 172 | // Direct relative CALL 173 | ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; 174 | #if defined(_M_X64) || defined(__x86_64__) 175 | call.address = dest; 176 | #else 177 | call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); 178 | #endif 179 | pCopySrc = &call; 180 | copySize = sizeof(call); 181 | } 182 | else if ((hs.opcode & 0xFD) == 0xE9) 183 | { 184 | // Direct relative JMP (EB or E9) 185 | ULONG_PTR dest = pOldInst + hs.len; 186 | 187 | if (hs.opcode == 0xEB) // isShort jmp 188 | dest += (INT8)hs.imm.imm8; 189 | else 190 | dest += (INT32)hs.imm.imm32; 191 | 192 | // Simply copy an internal jump. 193 | if ((ULONG_PTR)ct->pTarget <= dest 194 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 195 | { 196 | if (jmpDest < dest) 197 | jmpDest = dest; 198 | } 199 | else 200 | { 201 | #if defined(_M_X64) || defined(__x86_64__) 202 | jmp.address = dest; 203 | #else 204 | jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); 205 | #endif 206 | pCopySrc = &jmp; 207 | copySize = sizeof(jmp); 208 | 209 | // Exit the function If it is not in the branch 210 | finished = (pOldInst >= jmpDest); 211 | } 212 | } 213 | else if ((hs.opcode & 0xF0) == 0x70 214 | || (hs.opcode & 0xFC) == 0xE0 215 | || (hs.opcode2 & 0xF0) == 0x80) 216 | { 217 | // Direct relative Jcc 218 | ULONG_PTR dest = pOldInst + hs.len; 219 | 220 | if ((hs.opcode & 0xF0) == 0x70 // Jcc 221 | || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ 222 | dest += (INT8)hs.imm.imm8; 223 | else 224 | dest += (INT32)hs.imm.imm32; 225 | 226 | // Simply copy an internal jump. 227 | if ((ULONG_PTR)ct->pTarget <= dest 228 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 229 | { 230 | if (jmpDest < dest) 231 | jmpDest = dest; 232 | } 233 | else if ((hs.opcode & 0xFC) == 0xE0) 234 | { 235 | // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. 236 | return FALSE; 237 | } 238 | else 239 | { 240 | UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); 241 | #if defined(_M_X64) || defined(__x86_64__) 242 | // Invert the condition in x64 mode to simplify the conditional jump logic. 243 | jcc.opcode = 0x71 ^ cond; 244 | jcc.address = dest; 245 | #else 246 | jcc.opcode1 = 0x80 | cond; 247 | jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); 248 | #endif 249 | pCopySrc = &jcc; 250 | copySize = sizeof(jcc); 251 | } 252 | } 253 | else if ((hs.opcode & 0xFE) == 0xC2) 254 | { 255 | // RET (C2 or C3) 256 | 257 | // Complete the function if not in a branch. 258 | finished = (pOldInst >= jmpDest); 259 | } 260 | 261 | // Can't alter the instruction length in a branch. 262 | if (pOldInst < jmpDest && copySize != hs.len) 263 | return FALSE; 264 | 265 | // Trampoline function is too large. 266 | if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) 267 | return FALSE; 268 | 269 | // Trampoline function has too many instructions. 270 | if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) 271 | return FALSE; 272 | 273 | ct->oldIPs[ct->nIP] = oldPos; 274 | ct->newIPs[ct->nIP] = newPos; 275 | ct->nIP++; 276 | 277 | // Avoid using memcpy to reduce the footprint. 278 | #ifndef _MSC_VER 279 | memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); 280 | #else 281 | __movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); 282 | #endif 283 | newPos += (UINT8)copySize; 284 | oldPos += hs.len; 285 | } 286 | while (!finished); 287 | 288 | // Is there enough place for a long jump? 289 | if (oldPos < sizeof(JMP_REL) 290 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) 291 | { 292 | // Is there enough place for a short jump? 293 | if (oldPos < sizeof(JMP_REL_SHORT) 294 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) 295 | { 296 | return FALSE; 297 | } 298 | 299 | // Can we place the long jump above the function? 300 | if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) 301 | return FALSE; 302 | 303 | if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) 304 | return FALSE; 305 | 306 | ct->patchAbove = TRUE; 307 | } 308 | 309 | #if defined(_M_X64) || defined(__x86_64__) 310 | // Create a relay function. 311 | jmp.address = (ULONG_PTR)ct->pDetour; 312 | 313 | ct->pRelay = (LPBYTE)ct->pTrampoline + newPos; 314 | memcpy(ct->pRelay, &jmp, sizeof(jmp)); 315 | #endif 316 | 317 | return TRUE; 318 | } 319 | 320 | #endif //_WIN32 321 | -------------------------------------------------------------------------------- /dllloader/minhook/src/trampoline.h: -------------------------------------------------------------------------------- 1 | /* 2 | boostinspect:nolicense: minhook specific licensing 3 | 4 | * MinHook - The Minimalistic API Hooking Library for x64/x86 5 | * Copyright (C) 2009-2017 Tsuda Kageyu. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 22 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #pragma once 32 | #if defined(_WIN32) //Windows only 33 | #pragma pack(push, 1) 34 | 35 | // Structs for writing x86/x64 instructions. 36 | 37 | // 8-bit relative jump. 38 | typedef struct _JMP_REL_SHORT 39 | { 40 | UINT8 opcode; // EB xx: JMP +2+xx 41 | UINT8 operand; 42 | } JMP_REL_SHORT, *PJMP_REL_SHORT; 43 | 44 | // 32-bit direct relative jump/call. 45 | typedef struct _JMP_REL 46 | { 47 | UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx 48 | UINT32 operand; // Relative destination address 49 | } JMP_REL, *PJMP_REL, CALL_REL; 50 | 51 | // 64-bit indirect absolute jump. 52 | typedef struct _JMP_ABS 53 | { 54 | UINT8 opcode0; // FF25 00000000: JMP [+6] 55 | UINT8 opcode1; 56 | UINT32 dummy; 57 | UINT64 address; // Absolute destination address 58 | } JMP_ABS, *PJMP_ABS; 59 | 60 | // 64-bit indirect absolute call. 61 | typedef struct _CALL_ABS 62 | { 63 | UINT8 opcode0; // FF15 00000002: CALL [+6] 64 | UINT8 opcode1; 65 | UINT32 dummy0; 66 | UINT8 dummy1; // EB 08: JMP +10 67 | UINT8 dummy2; 68 | UINT64 address; // Absolute destination address 69 | } CALL_ABS; 70 | 71 | // 32-bit direct relative conditional jumps. 72 | typedef struct _JCC_REL 73 | { 74 | UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx 75 | UINT8 opcode1; 76 | UINT32 operand; // Relative destination address 77 | } JCC_REL; 78 | 79 | // 64bit indirect absolute conditional jumps that x64 lacks. 80 | typedef struct _JCC_ABS 81 | { 82 | UINT8 opcode; // 7* 0E: J** +16 83 | UINT8 dummy0; 84 | UINT8 dummy1; // FF25 00000000: JMP [+6] 85 | UINT8 dummy2; 86 | UINT32 dummy3; 87 | UINT64 address; // Absolute destination address 88 | } JCC_ABS; 89 | 90 | #pragma pack(pop) 91 | 92 | typedef struct _TRAMPOLINE 93 | { 94 | LPVOID pTarget; // [In] Address of the target function. 95 | LPVOID pDetour; // [In] Address of the detour function. 96 | LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function. 97 | 98 | #if defined(_M_X64) || defined(__x86_64__) 99 | LPVOID pRelay; // [Out] Address of the relay function. 100 | #endif 101 | BOOL patchAbove; // [Out] Should use the hot patch area? 102 | UINT nIP; // [Out] Number of the instruction boundaries. 103 | UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. 104 | UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. 105 | } TRAMPOLINE, *PTRAMPOLINE; 106 | 107 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct); 108 | 109 | #endif //_WIN32 110 | -------------------------------------------------------------------------------- /managed/test_managed_dll/cmakelists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(test_managed_dll SHARED test_managed_dll.cpp) 3 | 4 | target_compile_features(test_managed_dll PRIVATE cxx_std_17) 5 | target_compile_options(test_managed_dll PRIVATE /clr) 6 | set_property(TARGET test_managed_dll PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.8") 7 | set_property(TARGET test_managed_dll PROPERTY VS_DOTNET_REFERENCES "System" "System.Data" "System.Drawing" "System.Windows.Forms" "System.Xml") 8 | target_link_options(test_managed_dll PUBLIC /DEBUG /ASSEMBLYDEBUG) 9 | 10 | configPaths(test_managed_dll) 11 | 12 | -------------------------------------------------------------------------------- /managed/test_managed_dll/test_managed_dll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" __declspec(dllexport) void HelloWorld() 5 | { 6 | System::Windows::Forms::MessageBox::Show("Message"); 7 | } 8 | 9 | #pragma unmanaged 10 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 11 | { 12 | switch (fdwReason) 13 | { 14 | case DLL_PROCESS_ATTACH: 15 | printf("DLL_PROCESS_ATTACH\n"); 16 | break; 17 | 18 | case DLL_THREAD_ATTACH: 19 | printf("DLL_THREAD_DETACH\n"); 20 | break; 21 | 22 | case DLL_THREAD_DETACH: 23 | printf("DLL_THREAD_DETACH\n"); 24 | break; 25 | 26 | case DLL_PROCESS_DETACH: 27 | printf("DLL_PROCESS_DETACH\n"); 28 | break; 29 | } 30 | return TRUE; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /managed/test_managed_dllloader/cmakelists.txt: -------------------------------------------------------------------------------- 1 | #c1xx : warning C4857: C++/CLI mode does not support C++ versions newer than C++17; setting language to /std:c++17 2 | add_definitions(-DUNICODE -D_UNICODE) 3 | 4 | add_executable(test_managed_dllloader test_managed_dllloader.cpp) 5 | target_include_directories(test_managed_dllloader PRIVATE ${CMAKE_SOURCE_DIR}/dllloader) 6 | target_link_libraries(test_managed_dllloader dllloader) 7 | 8 | target_compile_options(test_managed_dllloader PRIVATE /clr) 9 | target_compile_options(test_managed_dllloader PRIVATE /Zc:twoPhase-) 10 | set_property(TARGET test_managed_dllloader PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.8") 11 | target_link_options(test_managed_dllloader PUBLIC /DEBUG /ASSEMBLYDEBUG) 12 | 13 | target_compile_features(test_managed_dllloader PRIVATE cxx_std_17) 14 | 15 | configPaths(test_managed_dllloader) 16 | 17 | -------------------------------------------------------------------------------- /managed/test_managed_dllloader/test_managed_dllloader.cpp: -------------------------------------------------------------------------------- 1 | #include "dllloader.h" 2 | #include //ifstream 3 | #include 4 | #include 5 | #include //weakly_canonical, path 6 | 7 | using namespace std; 8 | using namespace std::filesystem; 9 | 10 | 11 | bool LoadFile(path file, string& fileContents) 12 | { 13 | ifstream is; 14 | is.exceptions(is.exceptions() | std::ios::failbit); //throw exception on failure 15 | 16 | try { 17 | is.open(file, ios::binary); 18 | is.seekg(0, ios::end); 19 | int size = is.tellg(); 20 | is.seekg(0, ios::beg); 21 | fileContents.resize(size); 22 | is.read(&fileContents[0], size); 23 | is.close(); 24 | } 25 | catch (ios_base::failure& e) 26 | { 27 | std::cerr << e.what() << '\n'; 28 | return false; 29 | } 30 | 31 | return true; 32 | } 33 | 34 | 35 | int wmain(int argc, wchar_t** argv) 36 | { 37 | path baseDir = weakly_canonical(path(argv[0])).parent_path(); 38 | 39 | string testDllFile; 40 | string testPdbFile; 41 | path pdbFilePath = baseDir / L"test_managed_dll_new.pdb"; // redirected debug symbols path 42 | path pdbOrigFilePath = baseDir / L"test_managed_dll.pdb"; // official debug symbols path 43 | 44 | if (!LoadFile(baseDir / L"test_managed_dll.dll", testDllFile) ) 45 | { 46 | return -2; 47 | } 48 | 49 | LoadFile(pdbOrigFilePath, testPdbFile); 50 | 51 | //printf(".dll loaded, any key..."); 52 | //_getch(); 53 | 54 | DllManager dllm; 55 | path dllFilePath = baseDir / L"test_managed_dll_new.dll"; // redirected assembly path 56 | path dllOrigFilePath = baseDir / L"test_managed_dll.dll"; // official assembly path 57 | 58 | dllm.SetDllFile(dllOrigFilePath.c_str(), dllFilePath.c_str(), &testDllFile[0], testDllFile.size()); 59 | if (testPdbFile.length()) 60 | { 61 | dllm.SetDllFile(pdbOrigFilePath.c_str(), pdbFilePath.c_str(), &testPdbFile[0], testPdbFile.size()); 62 | } 63 | 64 | if( !dllm.EnableDllRedirection() ) 65 | { 66 | wprintf(L"%s\n", dllm.GetLastError().c_str()); 67 | return -2; 68 | } 69 | 70 | // Same as LoadLibrary, only with error handling 71 | HMODULE dll = dllm.LoadLibrary(dllFilePath.c_str()); 72 | if(dll == 0) 73 | { 74 | wprintf(L"%s\n", dllm.GetLastError().c_str()); 75 | return -2; 76 | } 77 | 78 | void(*helloworld)(); 79 | *((FARPROC*)&helloworld) = GetProcAddress(dll, "HelloWorld"); 80 | 81 | if(!dllm.WinApiCall(helloworld != nullptr)) 82 | { 83 | wprintf(L"%s\n", dllm.GetLastError().c_str()); 84 | } 85 | 86 | printf("- before helloworld()\n"); 87 | helloworld(); 88 | printf("- after helloworld()\n"); 89 | 90 | 91 | FreeLibrary(dll); 92 | _getch(); 93 | 94 | return 0; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /native/test_dll/cmakelists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(test_dll SHARED test_dll.cpp) 3 | 4 | configPaths(test_dll) 5 | 6 | -------------------------------------------------------------------------------- /native/test_dll/test_dll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" __declspec(dllexport) void HelloWorld() 5 | { 6 | printf("Hello world !\r\n"); 7 | } 8 | 9 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 10 | { 11 | switch (fdwReason) 12 | { 13 | case DLL_PROCESS_ATTACH: 14 | printf("DLL_PROCESS_ATTACH\n"); 15 | break; 16 | 17 | case DLL_THREAD_ATTACH: 18 | printf("DLL_THREAD_DETACH\n"); 19 | break; 20 | 21 | case DLL_THREAD_DETACH: 22 | printf("DLL_THREAD_DETACH\n"); 23 | break; 24 | 25 | case DLL_PROCESS_DETACH: 26 | printf("DLL_PROCESS_DETACH\n"); 27 | break; 28 | } 29 | return TRUE; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /native/test_dllloader/cmakelists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 20) 2 | add_definitions(-DUNICODE -D_UNICODE) 3 | 4 | add_executable(test_dllloader test_dllloader.cpp) 5 | target_include_directories(test_dllloader PRIVATE ${CMAKE_SOURCE_DIR}/dllloader) 6 | #target_link_libraries(test_dllloader ${CMAKE_CURRENT_BINARY_DIR}/$/dllloader.lib) 7 | target_link_libraries(test_dllloader dllloader) 8 | 9 | configPaths(test_dllloader) 10 | 11 | -------------------------------------------------------------------------------- /native/test_dllloader/test_dllloader.cpp: -------------------------------------------------------------------------------- 1 | #include "dllloader.h" 2 | #include //ifstream 3 | #include 4 | #include //weakly_canonical, path 5 | 6 | using namespace std; 7 | using namespace std::filesystem; 8 | 9 | int wmain(int argc, wchar_t** argv) 10 | { 11 | path baseDir = weakly_canonical(path(argv[0])).parent_path(); 12 | 13 | ifstream is; 14 | is.exceptions(is.exceptions() | std::ios::failbit); //throw exception on failure 15 | string testDllFile; 16 | 17 | try { 18 | is.open(baseDir / L"test_dll.dll", ios::binary); 19 | is.seekg(0, ios::end); 20 | int size = is.tellg(); 21 | is.seekg(0, ios::beg); 22 | testDllFile.resize(size); 23 | is.read(&testDllFile[0], size); 24 | is.close(); 25 | } 26 | catch (ios_base::failure& e) 27 | { 28 | std::cerr << e.what() << '\n'; 29 | } 30 | 31 | DllManager dllm; 32 | path dllFilePath = temp_directory_path() / L"new_test_dll.dll"; // Artificial name, does not need to match original dll name 33 | 34 | dllm.SetDllFile(nullptr, dllFilePath.c_str(), &testDllFile[0], testDllFile.size()); 35 | 36 | if( !dllm.EnableDllRedirection() ) 37 | { 38 | wprintf(L"%s\n", dllm.GetLastError().c_str()); 39 | return -2; 40 | } 41 | 42 | // Same as LoadLibrary, only with error handling 43 | HMODULE dll = dllm.LoadLibrary(dllFilePath.c_str()); 44 | if(dll == 0) 45 | { 46 | wprintf(L"%s\n", dllm.GetLastError().c_str()); 47 | return -2; 48 | } 49 | 50 | void(*helloworld)(); 51 | *((FARPROC*)&helloworld) = GetProcAddress(dll, "HelloWorld"); 52 | 53 | if(!dllm.WinApiCall(helloworld != nullptr)) 54 | { 55 | wprintf(L"%s\n", dllm.GetLastError().c_str()); 56 | } 57 | 58 | printf("- before helloworld()\n"); 59 | helloworld(); 60 | printf("- after helloworld()\n"); 61 | 62 | 63 | FreeLibrary(dll); 64 | 65 | return 0; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This git includes functionality for native .dll in-ram loading. 4 | 5 | Work is based on: 6 | - https://github.com/tapika/test_native_dll_loading/ 7 | - https://github.com/Hagrid29/PELoader 8 | 9 | Tested at least with: 10 | 11 | * Open `Developer Command Prompt for VS 2022` 12 | * Enter into currect folder (where you git cloned this repo) 13 | * Run `cmake .` 14 | * Open `dllloader.sln` 15 | * Compile and run. 16 | 17 | --------------------------------------------------------------------------------