├── src ├── sdk │ ├── interfaces │ │ ├── mdlcache.h │ │ ├── baseclient.h │ │ ├── filesystem.h │ │ └── engineclient.h │ ├── classes │ │ └── interfacereg.h │ └── sdk.h ├── core │ ├── interfaces.h │ ├── hooks.h │ ├── interfaces.cpp │ └── hooks.cpp ├── helper │ ├── memory.h │ └── memory.cpp └── dllmain.cpp ├── README.md ├── LICENSE ├── model-frog.sln ├── external └── minhook │ ├── hde │ ├── pstdint.h │ ├── hde32.h │ ├── hde64.h │ ├── table32.h │ ├── table64.h │ ├── hde32.c │ └── hde64.c │ ├── buffer.h │ ├── trampoline.h │ ├── minhook.h │ ├── buffer.c │ ├── trampoline.c │ └── hook.c ├── .gitattributes ├── model-frog.vcxproj.filters ├── model-frog.vcxproj └── .gitignore /src/sdk/interfaces/mdlcache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class MdlCache 4 | { 5 | public: 6 | 7 | }; 8 | -------------------------------------------------------------------------------- /src/sdk/interfaces/baseclient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class BaseClient 4 | { 5 | public: 6 | 7 | }; 8 | -------------------------------------------------------------------------------- /src/sdk/interfaces/filesystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class FileSystem 4 | { 5 | public: 6 | 7 | }; 8 | -------------------------------------------------------------------------------- /src/sdk/interfaces/engineclient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../helper/memory.h" 3 | 4 | class EngineClient 5 | { 6 | public: 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /src/sdk/classes/interfacereg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using InstantiateInterfaceFn = void* (__cdecl*)(); 4 | 5 | class InterfaceReg 6 | { 7 | public: 8 | InstantiateInterfaceFn CreateInterface; 9 | const char* name; 10 | InterfaceReg* next; 11 | }; 12 | -------------------------------------------------------------------------------- /src/sdk/sdk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Expose sdk through this header 4 | 5 | #include "classes/interfacereg.h" 6 | 7 | #include "interfaces/baseclient.h" 8 | #include "interfaces/engineclient.h" 9 | #include "interfaces/filesystem.h" 10 | #include "interfaces/mdlcache.h" 11 | -------------------------------------------------------------------------------- /src/core/interfaces.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "../sdk/sdk.h" 5 | 6 | // Namespace used to capture and access global interface pointers 7 | namespace i 8 | { 9 | void Init(); 10 | 11 | template 12 | T* Get(const char* module, const std::string_view version) noexcept; 13 | 14 | // Pointers 15 | inline BaseClient* client = nullptr; 16 | inline EngineClient* engine = nullptr; 17 | inline FileSystem* fileSystem = nullptr; 18 | inline MdlCache* mdlCache = nullptr; 19 | } 20 | -------------------------------------------------------------------------------- /src/core/hooks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "interfaces.h" 3 | 4 | namespace h 5 | { 6 | void Init(); 7 | void Shutdown() noexcept; 8 | 9 | using FindMdlFn = unsigned long(__thiscall*)(void*, const char*); 10 | inline FindMdlFn FindMdlOriginal = nullptr; 11 | unsigned long __stdcall FindMdl(const char* path) noexcept; 12 | 13 | using LooseFilesAllowedFn = bool(__thiscall*)(void*); 14 | inline LooseFilesAllowedFn LooseFilesAllowedOriginal = nullptr; 15 | bool __stdcall LooseFilesAllowed() noexcept; 16 | 17 | using CL_CheckForPureServerWhitelistFn = void(__thiscall*)(void*); 18 | inline CL_CheckForPureServerWhitelistFn CL_CheckForPureServerWhitelistOriginal = nullptr; 19 | void __fastcall CL_CheckForPureServerWhitelist(void* edx, void* ecx) noexcept; 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🐸 About 2 | A very simple internal CS:GO model changer with an included `sv_pure` bypass. 3 | 4 | ## Usage 5 | 1. Getting Models 6 | - Models can be found [here](https://gamebanana.com/mods/cats/7370) 7 | - Extract into `game_dir\csgo\` 8 | 9 | 2. Adding the Models 10 | - In the [FindMdl](https://github.com/cazzwastaken/model-frog/blob/master/src/core/hooks.cpp) hook, replace your desired models (see hooks.cpp) 11 | - Complile as `Release | x86` 12 | - `model-frog.dll` will be found in `build\` directory 13 | 14 | 3. Using the Cheat 15 | - Inject model-frog into `csgo.exe` *before* loading into a map 16 | - Enjoy! 17 | 18 | ## Todo 19 | - [ ] Add a UI instead of hard-coding the models 20 | - [ ] Use precached models instead of FindMdl to allow for instant model updates [link](https://www.unknowncheats.me/forum/counterstrike-global-offensive/214919-precache-models.html) 21 | 22 | ## Disclaimer 23 | I am not responsible for anything that happens while using this software. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 cazzwastaken 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/helper/memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Namespace holding memory related functions 6 | namespace m 7 | { 8 | void Init(); 9 | 10 | // Return pointer to virtual function 11 | constexpr void* Get(void* thisptr, const size_t index) noexcept 12 | { 13 | return (*static_cast(thisptr))[index]; 14 | } 15 | 16 | // Wrapper to call virtual functions 17 | template 18 | constexpr T Call(void* thisptr, const size_t index, U ... params) noexcept 19 | { 20 | using Fn = T(__thiscall*)(void*, decltype(params)...); 21 | return (*static_cast(thisptr))[index](thisptr, params...); 22 | } 23 | 24 | // Convert and address from relative to absolute 25 | template 26 | constexpr T RelativeToAbsolute(const uintptr_t address) noexcept 27 | { 28 | return static_cast(address + 4 + *reinterpret_cast(address)); 29 | } 30 | 31 | // Put sigs here fam 32 | inline struct Signatures 33 | { 34 | uint8_t* clCheckPureServerWhiteList = nullptr; 35 | }sigs; 36 | 37 | // Signature scanner :) 38 | uint8_t* Scan(const char* module, const char* pattern) noexcept; 39 | } 40 | -------------------------------------------------------------------------------- /model-frog.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31612.314 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "model-frog", "model-frog.vcxproj", "{5809B3FA-78D7-4A65-A26E-68ECC50BF867}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {5809B3FA-78D7-4A65-A26E-68ECC50BF867}.Debug|x64.ActiveCfg = Debug|x64 17 | {5809B3FA-78D7-4A65-A26E-68ECC50BF867}.Debug|x64.Build.0 = Debug|x64 18 | {5809B3FA-78D7-4A65-A26E-68ECC50BF867}.Debug|x86.ActiveCfg = Debug|Win32 19 | {5809B3FA-78D7-4A65-A26E-68ECC50BF867}.Debug|x86.Build.0 = Debug|Win32 20 | {5809B3FA-78D7-4A65-A26E-68ECC50BF867}.Release|x64.ActiveCfg = Release|x64 21 | {5809B3FA-78D7-4A65-A26E-68ECC50BF867}.Release|x64.Build.0 = Release|x64 22 | {5809B3FA-78D7-4A65-A26E-68ECC50BF867}.Release|x86.ActiveCfg = Release|Win32 23 | {5809B3FA-78D7-4A65-A26E-68ECC50BF867}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {91BA4728-62E1-4935-9B31-D0FED9ADDF15} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "core/hooks.h" 5 | 6 | // Error macro 7 | #define MESSAGE(message) \ 8 | MessageBeep(MB_ICONSTOP); \ 9 | MessageBoxA(NULL, message, "model-frog error", MB_OK | MB_ICONERROR) 10 | 11 | 12 | void Initialize(HMODULE module) 13 | { 14 | while (!GetModuleHandle("serverbrowser")) 15 | std::this_thread::sleep_for(std::chrono::milliseconds(200)); 16 | 17 | // Initialize cheat 18 | try 19 | { 20 | // find sigs 21 | m::Init(); 22 | 23 | // capture interfaces 24 | i::Init(); 25 | 26 | // emplace hooks 27 | h::Init(); 28 | } 29 | catch (const std::exception& error) 30 | { 31 | h::Shutdown(); 32 | MESSAGE(error.what()); 33 | FreeLibraryAndExitThread(module, EXIT_SUCCESS); 34 | } 35 | 36 | #ifdef _DEBUG 37 | while (!GetAsyncKeyState(VK_END)) 38 | std::this_thread::sleep_for(std::chrono::milliseconds(200)); 39 | 40 | // Shutdown 41 | h::Shutdown(); 42 | 43 | FreeLibraryAndExitThread(module, EXIT_SUCCESS); 44 | #endif 45 | } 46 | 47 | // Entry point 48 | BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) 49 | { 50 | if (reason == DLL_PROCESS_ATTACH) 51 | { 52 | DisableThreadLibraryCalls(instance); 53 | 54 | // Create our initialization thread 55 | const auto thread = CreateThread(nullptr, 56 | NULL, 57 | reinterpret_cast(Initialize), 58 | instance, 59 | NULL, 60 | nullptr); 61 | 62 | // Cleanup our handle 63 | if (thread) 64 | CloseHandle(thread); 65 | } 66 | 67 | return TRUE; 68 | } 69 | -------------------------------------------------------------------------------- /src/core/interfaces.cpp: -------------------------------------------------------------------------------- 1 | #include "interfaces.h" 2 | 3 | #include 4 | #include 5 | 6 | void i::Init() 7 | { 8 | if (!(client = Get("client", "VClient"))) 9 | throw std::runtime_error("Failed to get client interface."); 10 | 11 | if (!(engine = Get("engine", "VEngineClient"))) 12 | throw std::runtime_error("Failed to get engine interface."); 13 | 14 | if (!(fileSystem = Get("filesystem_stdio", "VFileSystem"))) 15 | throw std::runtime_error("Failed to get fileSystem interface."); 16 | 17 | if (!(mdlCache = Get("datacache", "MDLCache"))) 18 | throw std::runtime_error("Failed to get mdlCache interface."); 19 | } 20 | 21 | template 22 | T* i::Get(const char* module, const std::string_view version) noexcept 23 | { 24 | const auto handle = GetModuleHandle(module); 25 | 26 | if (!handle) 27 | return nullptr; 28 | 29 | const auto createInterface = reinterpret_cast(GetProcAddress(handle, "CreateInterface")); 30 | 31 | if (!createInterface) 32 | return nullptr; 33 | 34 | const auto relative = createInterface + 5; 35 | const auto address = m::RelativeToAbsolute(relative); 36 | const auto interfaces = **reinterpret_cast(address + 6); 37 | 38 | if (!interfaces) 39 | return nullptr; 40 | 41 | for (auto item = interfaces; item; item = item->next) 42 | { 43 | if ((!std::string_view(item->name).compare(0U, version.length(), version) && 44 | std::atoi(item->name + version.length()) > 0) || 45 | !version.compare(item->name)) 46 | { 47 | const auto pointer = item->CreateInterface(); 48 | 49 | if (!pointer) 50 | return nullptr; 51 | 52 | return static_cast(pointer); 53 | } 54 | } 55 | 56 | return nullptr; 57 | } 58 | -------------------------------------------------------------------------------- /external/minhook/hde/pstdint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 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 AUTHOR "AS IS" AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #pragma once 28 | 29 | #define WIN32_LEAN_AND_MEAN 30 | #include 31 | 32 | // Integer types for HDE. 33 | typedef INT8 int8_t; 34 | typedef INT16 int16_t; 35 | typedef INT32 int32_t; 36 | typedef INT64 int64_t; 37 | typedef UINT8 uint8_t; 38 | typedef UINT16 uint16_t; 39 | typedef UINT32 uint32_t; 40 | typedef UINT64 uint64_t; 41 | -------------------------------------------------------------------------------- /external/minhook/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | // Size of each memory slot. 32 | #if defined(_M_X64) || defined(__x86_64__) 33 | #define MEMORY_SLOT_SIZE 64 34 | #else 35 | #define MEMORY_SLOT_SIZE 32 36 | #endif 37 | 38 | VOID InitializeBuffer(VOID); 39 | VOID UninitializeBuffer(VOID); 40 | LPVOID AllocateBuffer(LPVOID pOrigin); 41 | VOID FreeBuffer(LPVOID pBuffer); 42 | BOOL IsExecutableAddress(LPVOID pAddress); 43 | -------------------------------------------------------------------------------- /src/core/hooks.cpp: -------------------------------------------------------------------------------- 1 | #include "hooks.h" 2 | 3 | #include "../../external/minhook/minhook.h" 4 | #include 5 | 6 | void h::Init() 7 | { 8 | if (MH_Initialize()) 9 | throw std::runtime_error("Unable to initialize minhook"); 10 | 11 | if (MH_CreateHook(m::Get(i::mdlCache, 10), &FindMdl, reinterpret_cast(&FindMdlOriginal))) 12 | throw std::runtime_error("Unable to hook FindMdl()."); 13 | 14 | if (MH_CreateHook(m::Get(i::fileSystem, 128), &LooseFilesAllowed, reinterpret_cast(&LooseFilesAllowedOriginal))) 15 | throw std::runtime_error("Unable to hook LooseFilesAllowed()."); 16 | 17 | if (MH_CreateHook(m::sigs.clCheckPureServerWhiteList, 18 | &CL_CheckForPureServerWhitelist, 19 | reinterpret_cast(&CL_CheckForPureServerWhitelistOriginal))) 20 | throw std::runtime_error("Unable to hook CL_CheckForPureServerWhitelist()."); 21 | 22 | if (MH_EnableHook(MH_ALL_HOOKS)) 23 | throw std::runtime_error("Unable to enable hooks"); 24 | } 25 | 26 | void h::Shutdown() noexcept 27 | { 28 | MH_DisableHook(MH_ALL_HOOKS); 29 | MH_RemoveHook(MH_ALL_HOOKS); 30 | MH_Uninitialize(); 31 | } 32 | 33 | // https://www.unknowncheats.me/forum/counterstrike-global-offensive/214760-hooking-findmdl.html 34 | unsigned long __stdcall h::FindMdl(const char* path) noexcept 35 | { 36 | // Do sneaky model stuff here 37 | 38 | if (strstr(path, "knife_default_ct.mdl")) 39 | return FindMdlOriginal(i::mdlCache, "models/weapons/v_minecraft_pickaxe.mdl"); 40 | else if (strstr(path, "knife_default_t.mdl")) 41 | return FindMdlOriginal(i::mdlCache, "models/weapons/v_knife_dildo_test.mdl"); 42 | 43 | return FindMdlOriginal(i::mdlCache, path); 44 | } 45 | 46 | // https://www.unknowncheats.me/forum/counterstrike-global-offensive/394153-fixing-chams-sv_pure_allow_loose_file_loads.html 47 | bool __stdcall h::LooseFilesAllowed() noexcept 48 | { 49 | // Allow the files :think: 50 | return true; 51 | } 52 | 53 | // https://gitlab.com/KittenPopo/csgo-2018-source/-/blob/main/engine/cl_main.cpp#L1510 54 | void __fastcall h::CL_CheckForPureServerWhitelist(void* edx, void* ecx) noexcept 55 | { 56 | // Stop the game from checking the whitelist lmao 57 | return; 58 | } 59 | -------------------------------------------------------------------------------- /src/helper/memory.cpp: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void m::Init() 8 | { 9 | if (!(sigs.clCheckPureServerWhiteList = Scan("engine", "8B 0D ? ? ? ? 56 83 B9 ? ? ? ? ? 7E 6E "))) 10 | throw std::runtime_error("Outdated pattern for clCheckPureServerWhiteList"); 11 | } 12 | 13 | uint8_t* m::Scan(const char* module, const char* pattern) noexcept 14 | { 15 | const auto handle = ::GetModuleHandle(module); 16 | 17 | if (!handle) 18 | return nullptr; 19 | 20 | static auto patternToByte = [](const char* pattern) 21 | { 22 | auto bytes = std::vector{}; 23 | auto start = const_cast(pattern); 24 | auto end = const_cast(pattern) + std::strlen(pattern); 25 | 26 | for (auto current = start; current < end; ++current) 27 | { 28 | if (*current == '?') { 29 | ++current; 30 | 31 | if (*current == '?') 32 | ++current; 33 | 34 | bytes.push_back(-1); 35 | } 36 | else 37 | { 38 | bytes.push_back(std::strtoul(current, ¤t, 16)); 39 | } 40 | } 41 | return bytes; 42 | }; 43 | 44 | 45 | auto dosHeader = reinterpret_cast(handle); 46 | auto ntHeaders = 47 | reinterpret_cast(reinterpret_cast(handle) + dosHeader->e_lfanew); 48 | 49 | auto size = ntHeaders->OptionalHeader.SizeOfImage; 50 | auto bytes = patternToByte(pattern); 51 | auto scanBytes = reinterpret_cast(handle); 52 | 53 | auto s = bytes.size(); 54 | auto d = bytes.data(); 55 | 56 | for (auto i = 0ul; i < size - s; ++i) 57 | { 58 | bool found = true; 59 | 60 | for (auto j = 0ul; j < s; ++j) 61 | { 62 | if (scanBytes[i + j] != d[j] && d[j] != -1) 63 | { 64 | found = false; 65 | break; 66 | } 67 | } 68 | 69 | if (found) 70 | return &scanBytes[i]; 71 | } 72 | 73 | return nullptr; 74 | } 75 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /external/minhook/hde/hde32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 32 3 | * Copyright (c) 2006-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde32.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE32_H_ 11 | #define _HDE32_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include "pstdint.h" 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_DISP8 0x00000020 30 | #define F_DISP16 0x00000040 31 | #define F_DISP32 0x00000080 32 | #define F_RELATIVE 0x00000100 33 | #define F_2IMM16 0x00000800 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_ANY 0x3f000000 47 | 48 | #define PREFIX_SEGMENT_CS 0x2e 49 | #define PREFIX_SEGMENT_SS 0x36 50 | #define PREFIX_SEGMENT_DS 0x3e 51 | #define PREFIX_SEGMENT_ES 0x26 52 | #define PREFIX_SEGMENT_FS 0x64 53 | #define PREFIX_SEGMENT_GS 0x65 54 | #define PREFIX_LOCK 0xf0 55 | #define PREFIX_REPNZ 0xf2 56 | #define PREFIX_REPX 0xf3 57 | #define PREFIX_OPERAND_SIZE 0x66 58 | #define PREFIX_ADDRESS_SIZE 0x67 59 | 60 | #pragma pack(push,1) 61 | 62 | typedef struct { 63 | uint8_t len; 64 | uint8_t p_rep; 65 | uint8_t p_lock; 66 | uint8_t p_seg; 67 | uint8_t p_66; 68 | uint8_t p_67; 69 | uint8_t opcode; 70 | uint8_t opcode2; 71 | uint8_t modrm; 72 | uint8_t modrm_mod; 73 | uint8_t modrm_reg; 74 | uint8_t modrm_rm; 75 | uint8_t sib; 76 | uint8_t sib_scale; 77 | uint8_t sib_index; 78 | uint8_t sib_base; 79 | union { 80 | uint8_t imm8; 81 | uint16_t imm16; 82 | uint32_t imm32; 83 | } imm; 84 | union { 85 | uint8_t disp8; 86 | uint16_t disp16; 87 | uint32_t disp32; 88 | } disp; 89 | uint32_t flags; 90 | } hde32s; 91 | 92 | #pragma pack(pop) 93 | 94 | #ifdef __cplusplus 95 | extern "C" { 96 | #endif 97 | 98 | /* __cdecl */ 99 | unsigned int hde32_disasm(const void *code, hde32s *hs); 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif /* _HDE32_H_ */ 106 | -------------------------------------------------------------------------------- /external/minhook/hde/hde64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde64.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE64_H_ 11 | #define _HDE64_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include "pstdint.h" 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_IMM64 0x00000020 30 | #define F_DISP8 0x00000040 31 | #define F_DISP16 0x00000080 32 | #define F_DISP32 0x00000100 33 | #define F_RELATIVE 0x00000200 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_REX 0x40000000 47 | #define F_PREFIX_ANY 0x7f000000 48 | 49 | #define PREFIX_SEGMENT_CS 0x2e 50 | #define PREFIX_SEGMENT_SS 0x36 51 | #define PREFIX_SEGMENT_DS 0x3e 52 | #define PREFIX_SEGMENT_ES 0x26 53 | #define PREFIX_SEGMENT_FS 0x64 54 | #define PREFIX_SEGMENT_GS 0x65 55 | #define PREFIX_LOCK 0xf0 56 | #define PREFIX_REPNZ 0xf2 57 | #define PREFIX_REPX 0xf3 58 | #define PREFIX_OPERAND_SIZE 0x66 59 | #define PREFIX_ADDRESS_SIZE 0x67 60 | 61 | #pragma pack(push,1) 62 | 63 | typedef struct { 64 | uint8_t len; 65 | uint8_t p_rep; 66 | uint8_t p_lock; 67 | uint8_t p_seg; 68 | uint8_t p_66; 69 | uint8_t p_67; 70 | uint8_t rex; 71 | uint8_t rex_w; 72 | uint8_t rex_r; 73 | uint8_t rex_x; 74 | uint8_t rex_b; 75 | uint8_t opcode; 76 | uint8_t opcode2; 77 | uint8_t modrm; 78 | uint8_t modrm_mod; 79 | uint8_t modrm_reg; 80 | uint8_t modrm_rm; 81 | uint8_t sib; 82 | uint8_t sib_scale; 83 | uint8_t sib_index; 84 | uint8_t sib_base; 85 | union { 86 | uint8_t imm8; 87 | uint16_t imm16; 88 | uint32_t imm32; 89 | uint64_t imm64; 90 | } imm; 91 | union { 92 | uint8_t disp8; 93 | uint16_t disp16; 94 | uint32_t disp32; 95 | } disp; 96 | uint32_t flags; 97 | } hde64s; 98 | 99 | #pragma pack(pop) 100 | 101 | #ifdef __cplusplus 102 | extern "C" { 103 | #endif 104 | 105 | /* __cdecl */ 106 | unsigned int hde64_disasm(const void *code, hde64s *hs); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* _HDE64_H_ */ 113 | -------------------------------------------------------------------------------- /external/minhook/hde/table32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 32 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xf1 30 | #define DELTA_FPU_MODRM 0xf8 31 | #define DELTA_PREFIXES 0x130 32 | #define DELTA_OP_LOCK_OK 0x1a1 33 | #define DELTA_OP2_LOCK_OK 0x1b9 34 | #define DELTA_OP_ONLY_MEM 0x1cb 35 | #define DELTA_OP2_ONLY_MEM 0x1da 36 | 37 | unsigned char hde32_table[] = { 38 | 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, 39 | 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, 40 | 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, 41 | 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, 42 | 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, 43 | 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, 44 | 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, 45 | 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, 46 | 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, 47 | 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, 48 | 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, 49 | 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, 50 | 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, 51 | 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, 52 | 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, 53 | 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, 54 | 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, 55 | 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, 56 | 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 57 | 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 58 | 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, 59 | 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, 60 | 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, 61 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, 62 | 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, 63 | 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, 64 | 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 65 | 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, 66 | 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, 67 | 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, 68 | 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, 69 | 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, 70 | 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, 71 | 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, 72 | 0xe7,0x08,0x00,0xf0,0x02,0x00 73 | }; 74 | -------------------------------------------------------------------------------- /external/minhook/hde/table64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xfd 30 | #define DELTA_FPU_MODRM 0x104 31 | #define DELTA_PREFIXES 0x13c 32 | #define DELTA_OP_LOCK_OK 0x1ae 33 | #define DELTA_OP2_LOCK_OK 0x1c6 34 | #define DELTA_OP_ONLY_MEM 0x1d8 35 | #define DELTA_OP2_ONLY_MEM 0x1e7 36 | 37 | unsigned char hde64_table[] = { 38 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, 39 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, 40 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, 41 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, 42 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, 43 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, 44 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, 45 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, 46 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, 47 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, 48 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, 49 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, 50 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, 51 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, 52 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, 53 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, 54 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, 55 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, 56 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 58 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, 59 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, 60 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, 61 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 62 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, 63 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, 64 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, 65 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 66 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, 67 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, 68 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, 69 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, 70 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, 71 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, 72 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, 73 | 0x00,0xf0,0x02,0x00 74 | }; 75 | -------------------------------------------------------------------------------- /model-frog.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | -------------------------------------------------------------------------------- /external/minhook/trampoline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #pragma pack(push, 1) 32 | 33 | // Structs for writing x86/x64 instructions. 34 | 35 | // 8-bit relative jump. 36 | typedef struct _JMP_REL_SHORT 37 | { 38 | UINT8 opcode; // EB xx: JMP +2+xx 39 | UINT8 operand; 40 | } JMP_REL_SHORT, *PJMP_REL_SHORT; 41 | 42 | // 32-bit direct relative jump/call. 43 | typedef struct _JMP_REL 44 | { 45 | UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx 46 | UINT32 operand; // Relative destination address 47 | } JMP_REL, *PJMP_REL, CALL_REL; 48 | 49 | // 64-bit indirect absolute jump. 50 | typedef struct _JMP_ABS 51 | { 52 | UINT8 opcode0; // FF25 00000000: JMP [+6] 53 | UINT8 opcode1; 54 | UINT32 dummy; 55 | UINT64 address; // Absolute destination address 56 | } JMP_ABS, *PJMP_ABS; 57 | 58 | // 64-bit indirect absolute call. 59 | typedef struct _CALL_ABS 60 | { 61 | UINT8 opcode0; // FF15 00000002: CALL [+6] 62 | UINT8 opcode1; 63 | UINT32 dummy0; 64 | UINT8 dummy1; // EB 08: JMP +10 65 | UINT8 dummy2; 66 | UINT64 address; // Absolute destination address 67 | } CALL_ABS; 68 | 69 | // 32-bit direct relative conditional jumps. 70 | typedef struct _JCC_REL 71 | { 72 | UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx 73 | UINT8 opcode1; 74 | UINT32 operand; // Relative destination address 75 | } JCC_REL; 76 | 77 | // 64bit indirect absolute conditional jumps that x64 lacks. 78 | typedef struct _JCC_ABS 79 | { 80 | UINT8 opcode; // 7* 0E: J** +16 81 | UINT8 dummy0; 82 | UINT8 dummy1; // FF25 00000000: JMP [+6] 83 | UINT8 dummy2; 84 | UINT32 dummy3; 85 | UINT64 address; // Absolute destination address 86 | } JCC_ABS; 87 | 88 | #pragma pack(pop) 89 | 90 | typedef struct _TRAMPOLINE 91 | { 92 | LPVOID pTarget; // [In] Address of the target function. 93 | LPVOID pDetour; // [In] Address of the detour function. 94 | LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function. 95 | 96 | #if defined(_M_X64) || defined(__x86_64__) 97 | LPVOID pRelay; // [Out] Address of the relay function. 98 | #endif 99 | BOOL patchAbove; // [Out] Should use the hot patch area? 100 | UINT nIP; // [Out] Number of the instruction boundaries. 101 | UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. 102 | UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. 103 | } TRAMPOLINE, *PTRAMPOLINE; 104 | 105 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct); 106 | -------------------------------------------------------------------------------- /external/minhook/minhook.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) 32 | #error MinHook supports only x86 and x64 systems. 33 | #endif 34 | 35 | #define WIN32_LEAN_AND_MEAN 36 | #include 37 | 38 | // MinHook Error Codes. 39 | typedef enum MH_STATUS 40 | { 41 | // Unknown error. Should not be returned. 42 | MH_UNKNOWN = -1, 43 | 44 | // Successful. 45 | MH_OK = 0, 46 | 47 | // MinHook is already initialized. 48 | MH_ERROR_ALREADY_INITIALIZED, 49 | 50 | // MinHook is not initialized yet, or already uninitialized. 51 | MH_ERROR_NOT_INITIALIZED, 52 | 53 | // The hook for the specified target function is already created. 54 | MH_ERROR_ALREADY_CREATED, 55 | 56 | // The hook for the specified target function is not created yet. 57 | MH_ERROR_NOT_CREATED, 58 | 59 | // The hook for the specified target function is already enabled. 60 | MH_ERROR_ENABLED, 61 | 62 | // The hook for the specified target function is not enabled yet, or already 63 | // disabled. 64 | MH_ERROR_DISABLED, 65 | 66 | // The specified pointer is invalid. It points the address of non-allocated 67 | // and/or non-executable region. 68 | MH_ERROR_NOT_EXECUTABLE, 69 | 70 | // The specified target function cannot be hooked. 71 | MH_ERROR_UNSUPPORTED_FUNCTION, 72 | 73 | // Failed to allocate memory. 74 | MH_ERROR_MEMORY_ALLOC, 75 | 76 | // Failed to change the memory protection. 77 | MH_ERROR_MEMORY_PROTECT, 78 | 79 | // The specified module is not loaded. 80 | MH_ERROR_MODULE_NOT_FOUND, 81 | 82 | // The specified function is not found. 83 | MH_ERROR_FUNCTION_NOT_FOUND 84 | } 85 | MH_STATUS; 86 | 87 | // Can be passed as a parameter to MH_EnableHook, MH_DisableHook, 88 | // MH_QueueEnableHook or MH_QueueDisableHook. 89 | #define MH_ALL_HOOKS NULL 90 | 91 | #ifdef __cplusplus 92 | extern "C" { 93 | #endif 94 | 95 | // Initialize the MinHook library. You must call this function EXACTLY ONCE 96 | // at the beginning of your program. 97 | MH_STATUS WINAPI MH_Initialize(VOID); 98 | 99 | // Uninitialize the MinHook library. You must call this function EXACTLY 100 | // ONCE at the end of your program. 101 | MH_STATUS WINAPI MH_Uninitialize(VOID); 102 | 103 | // Creates a hook for the specified target function, in disabled state. 104 | // Parameters: 105 | // pTarget [in] A pointer to the target function, which will be 106 | // overridden by the detour function. 107 | // pDetour [in] A pointer to the detour function, which will override 108 | // the target function. 109 | // ppOriginal [out] A pointer to the trampoline function, which will be 110 | // used to call the original target function. 111 | // This parameter can be NULL. 112 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); 113 | 114 | // Creates a hook for the specified API function, in disabled state. 115 | // Parameters: 116 | // pszModule [in] A pointer to the loaded module name which contains the 117 | // target function. 118 | // pszProcName [in] A pointer to the target function name, which will be 119 | // overridden by the detour function. 120 | // pDetour [in] A pointer to the detour function, which will override 121 | // the target function. 122 | // ppOriginal [out] A pointer to the trampoline function, which will be 123 | // used to call the original target function. 124 | // This parameter can be NULL. 125 | MH_STATUS WINAPI MH_CreateHookApi( 126 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); 127 | 128 | // Creates a hook for the specified API function, in disabled state. 129 | // Parameters: 130 | // pszModule [in] A pointer to the loaded module name which contains the 131 | // target function. 132 | // pszProcName [in] A pointer to the target function name, which will be 133 | // overridden by the detour function. 134 | // pDetour [in] A pointer to the detour function, which will override 135 | // the target function. 136 | // ppOriginal [out] A pointer to the trampoline function, which will be 137 | // used to call the original target function. 138 | // This parameter can be NULL. 139 | // ppTarget [out] A pointer to the target function, which will be used 140 | // with other functions. 141 | // This parameter can be NULL. 142 | MH_STATUS WINAPI MH_CreateHookApiEx( 143 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); 144 | 145 | // Removes an already created hook. 146 | // Parameters: 147 | // pTarget [in] A pointer to the target function. 148 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); 149 | 150 | // Enables an already created hook. 151 | // Parameters: 152 | // pTarget [in] A pointer to the target function. 153 | // If this parameter is MH_ALL_HOOKS, all created hooks are 154 | // enabled in one go. 155 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); 156 | 157 | // Disables an already created hook. 158 | // Parameters: 159 | // pTarget [in] A pointer to the target function. 160 | // If this parameter is MH_ALL_HOOKS, all created hooks are 161 | // disabled in one go. 162 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); 163 | 164 | // Queues to enable an already created hook. 165 | // Parameters: 166 | // pTarget [in] A pointer to the target function. 167 | // If this parameter is MH_ALL_HOOKS, all created hooks are 168 | // queued to be enabled. 169 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); 170 | 171 | // Queues to disable an already created hook. 172 | // Parameters: 173 | // pTarget [in] A pointer to the target function. 174 | // If this parameter is MH_ALL_HOOKS, all created hooks are 175 | // queued to be disabled. 176 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); 177 | 178 | // Applies all queued changes in one go. 179 | MH_STATUS WINAPI MH_ApplyQueued(VOID); 180 | 181 | // Translates the MH_STATUS to its name as a string. 182 | const char * WINAPI MH_StatusToString(MH_STATUS status); 183 | 184 | #ifdef __cplusplus 185 | } 186 | #endif 187 | -------------------------------------------------------------------------------- /model-frog.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {5809b3fa-78d7-4a65-a26e-68ecc50bf867} 25 | modelfrog 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v143 33 | MultiByte 34 | 35 | 36 | DynamicLibrary 37 | false 38 | v143 39 | true 40 | MultiByte 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)build\ 76 | $(SolutionDir)build\intermediates\ 77 | 78 | 79 | false 80 | $(SolutionDir)build\ 81 | $(SolutionDir)build\intermediates\ 82 | 83 | 84 | true 85 | 86 | 87 | false 88 | 89 | 90 | 91 | Level3 92 | true 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | stdcpplatest 96 | 97 | 98 | Windows 99 | true 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | true 107 | true 108 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | true 110 | stdcpplatest 111 | 112 | 113 | Windows 114 | true 115 | true 116 | true 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | true 125 | 126 | 127 | Console 128 | true 129 | 130 | 131 | 132 | 133 | Level3 134 | true 135 | true 136 | true 137 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 138 | true 139 | 140 | 141 | Console 142 | true 143 | true 144 | true 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/windows,c++,visualstudio,executable 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=windows,c++,visualstudio,executable 4 | 5 | ### C++ ### 6 | # Prerequisites 7 | *.d 8 | 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Compiled Dynamic libraries 20 | *.so 21 | *.dylib 22 | *.dll 23 | 24 | # Fortran module files 25 | *.mod 26 | *.smod 27 | 28 | # Compiled Static libraries 29 | *.lai 30 | *.la 31 | *.a 32 | 33 | # Executables 34 | *.exe 35 | *.out 36 | *.app 37 | 38 | ### Executable ### 39 | *.bat 40 | *.cgi 41 | *.com 42 | *.gadget 43 | *.jar 44 | *.pif 45 | *.vb 46 | *.wsf 47 | 48 | ### Windows ### 49 | # Windows thumbnail cache files 50 | Thumbs.db 51 | Thumbs.db:encryptable 52 | ehthumbs.db 53 | ehthumbs_vista.db 54 | 55 | # Dump file 56 | *.stackdump 57 | 58 | # Folder config file 59 | [Dd]esktop.ini 60 | 61 | # Recycle Bin used on file shares 62 | $RECYCLE.BIN/ 63 | 64 | # Windows Installer files 65 | *.cab 66 | *.msi 67 | *.msix 68 | *.msm 69 | *.msp 70 | 71 | # Windows shortcuts 72 | *.lnk 73 | 74 | ### VisualStudio ### 75 | ## Ignore Visual Studio temporary files, build results, and 76 | ## files generated by popular Visual Studio add-ons. 77 | ## 78 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 79 | 80 | # User-specific files 81 | *.rsuser 82 | *.suo 83 | *.user 84 | *.userosscache 85 | *.sln.docstates 86 | 87 | # User-specific files (MonoDevelop/Xamarin Studio) 88 | *.userprefs 89 | 90 | # Mono auto generated files 91 | mono_crash.* 92 | 93 | # Build results 94 | [Dd]ebug/ 95 | [Dd]ebugPublic/ 96 | [Rr]elease/ 97 | [Rr]eleases/ 98 | x64/ 99 | x86/ 100 | [Ww][Ii][Nn]32/ 101 | [Aa][Rr][Mm]/ 102 | [Aa][Rr][Mm]64/ 103 | bld/ 104 | [Bb]in/ 105 | [Oo]bj/ 106 | [Ll]og/ 107 | [Ll]ogs/ 108 | 109 | # Visual Studio 2015/2017 cache/options directory 110 | .vs/ 111 | # Uncomment if you have tasks that create the project's static files in wwwroot 112 | #wwwroot/ 113 | 114 | # Visual Studio 2017 auto generated files 115 | Generated\ Files/ 116 | 117 | # MSTest test Results 118 | [Tt]est[Rr]esult*/ 119 | [Bb]uild[Ll]og.* 120 | 121 | # NUnit 122 | *.VisualState.xml 123 | TestResult.xml 124 | nunit-*.xml 125 | 126 | # Build Results of an ATL Project 127 | [Dd]ebugPS/ 128 | [Rr]eleasePS/ 129 | dlldata.c 130 | 131 | # Benchmark Results 132 | BenchmarkDotNet.Artifacts/ 133 | 134 | # .NET Core 135 | project.lock.json 136 | project.fragment.lock.json 137 | artifacts/ 138 | 139 | # ASP.NET Scaffolding 140 | ScaffoldingReadMe.txt 141 | 142 | # StyleCop 143 | StyleCopReport.xml 144 | 145 | # Files built by Visual Studio 146 | *_i.c 147 | *_p.c 148 | *_h.h 149 | *.ilk 150 | *.meta 151 | *.iobj 152 | *.pdb 153 | *.ipdb 154 | *.pgc 155 | *.pgd 156 | *.rsp 157 | *.sbr 158 | *.tlb 159 | *.tli 160 | *.tlh 161 | *.tmp 162 | *.tmp_proj 163 | *_wpftmp.csproj 164 | *.log 165 | *.tlog 166 | *.vspscc 167 | *.vssscc 168 | .builds 169 | *.pidb 170 | *.svclog 171 | *.scc 172 | *.recipe 173 | 174 | # Chutzpah Test files 175 | _Chutzpah* 176 | 177 | # Visual C++ cache files 178 | ipch/ 179 | *.aps 180 | *.ncb 181 | *.opendb 182 | *.opensdf 183 | *.sdf 184 | *.cachefile 185 | *.VC.db 186 | *.VC.VC.opendb 187 | 188 | # Visual Studio profiler 189 | *.psess 190 | *.vsp 191 | *.vspx 192 | *.sap 193 | 194 | # Visual Studio Trace Files 195 | *.e2e 196 | 197 | # TFS 2012 Local Workspace 198 | $tf/ 199 | 200 | # Guidance Automation Toolkit 201 | *.gpState 202 | 203 | # ReSharper is a .NET coding add-in 204 | _ReSharper*/ 205 | *.[Rr]e[Ss]harper 206 | *.DotSettings.user 207 | 208 | # TeamCity is a build add-in 209 | _TeamCity* 210 | 211 | # DotCover is a Code Coverage Tool 212 | *.dotCover 213 | 214 | # AxoCover is a Code Coverage Tool 215 | .axoCover/* 216 | !.axoCover/settings.json 217 | 218 | # Coverlet is a free, cross platform Code Coverage Tool 219 | coverage*.json 220 | coverage*.xml 221 | coverage*.info 222 | 223 | # Visual Studio code coverage results 224 | *.coverage 225 | *.coveragexml 226 | 227 | # NCrunch 228 | _NCrunch_* 229 | .*crunch*.local.xml 230 | nCrunchTemp_* 231 | 232 | # MightyMoose 233 | *.mm.* 234 | AutoTest.Net/ 235 | 236 | # Web workbench (sass) 237 | .sass-cache/ 238 | 239 | # Installshield output folder 240 | [Ee]xpress/ 241 | 242 | # DocProject is a documentation generator add-in 243 | DocProject/buildhelp/ 244 | DocProject/Help/*.HxT 245 | DocProject/Help/*.HxC 246 | DocProject/Help/*.hhc 247 | DocProject/Help/*.hhk 248 | DocProject/Help/*.hhp 249 | DocProject/Help/Html2 250 | DocProject/Help/html 251 | 252 | # Click-Once directory 253 | publish/ 254 | 255 | # Publish Web Output 256 | *.[Pp]ublish.xml 257 | *.azurePubxml 258 | # Note: Comment the next line if you want to checkin your web deploy settings, 259 | # but database connection strings (with potential passwords) will be unencrypted 260 | *.pubxml 261 | *.publishproj 262 | 263 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 264 | # checkin your Azure Web App publish settings, but sensitive information contained 265 | # in these scripts will be unencrypted 266 | PublishScripts/ 267 | 268 | # NuGet Packages 269 | *.nupkg 270 | # NuGet Symbol Packages 271 | *.snupkg 272 | # The packages folder can be ignored because of Package Restore 273 | **/[Pp]ackages/* 274 | # except build/, which is used as an MSBuild target. 275 | !**/[Pp]ackages/build/ 276 | # Uncomment if necessary however generally it will be regenerated when needed 277 | #!**/[Pp]ackages/repositories.config 278 | # NuGet v3's project.json files produces more ignorable files 279 | *.nuget.props 280 | *.nuget.targets 281 | 282 | # Nuget personal access tokens and Credentials 283 | # nuget.config 284 | 285 | # Microsoft Azure Build Output 286 | csx/ 287 | *.build.csdef 288 | 289 | # Microsoft Azure Emulator 290 | ecf/ 291 | rcf/ 292 | 293 | # Windows Store app package directories and files 294 | AppPackages/ 295 | BundleArtifacts/ 296 | Package.StoreAssociation.xml 297 | _pkginfo.txt 298 | *.appx 299 | *.appxbundle 300 | *.appxupload 301 | 302 | # Visual Studio cache files 303 | # files ending in .cache can be ignored 304 | *.[Cc]ache 305 | # but keep track of directories ending in .cache 306 | !?*.[Cc]ache/ 307 | 308 | # Others 309 | ClientBin/ 310 | ~$* 311 | *~ 312 | *.dbmdl 313 | *.dbproj.schemaview 314 | *.jfm 315 | *.pfx 316 | *.publishsettings 317 | orleans.codegen.cs 318 | 319 | # Including strong name files can present a security risk 320 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 321 | #*.snk 322 | 323 | # Since there are multiple workflows, uncomment next line to ignore bower_components 324 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 325 | #bower_components/ 326 | 327 | # RIA/Silverlight projects 328 | Generated_Code/ 329 | 330 | # Backup & report files from converting an old project file 331 | # to a newer Visual Studio version. Backup files are not needed, 332 | # because we have git ;-) 333 | _UpgradeReport_Files/ 334 | Backup*/ 335 | UpgradeLog*.XML 336 | UpgradeLog*.htm 337 | ServiceFabricBackup/ 338 | *.rptproj.bak 339 | 340 | # SQL Server files 341 | *.mdf 342 | *.ldf 343 | *.ndf 344 | 345 | # Business Intelligence projects 346 | *.rdl.data 347 | *.bim.layout 348 | *.bim_*.settings 349 | *.rptproj.rsuser 350 | *- [Bb]ackup.rdl 351 | *- [Bb]ackup ([0-9]).rdl 352 | *- [Bb]ackup ([0-9][0-9]).rdl 353 | 354 | # Microsoft Fakes 355 | FakesAssemblies/ 356 | 357 | # GhostDoc plugin setting file 358 | *.GhostDoc.xml 359 | 360 | # Node.js Tools for Visual Studio 361 | .ntvs_analysis.dat 362 | node_modules/ 363 | 364 | # Visual Studio 6 build log 365 | *.plg 366 | 367 | # Visual Studio 6 workspace options file 368 | *.opt 369 | 370 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 371 | *.vbw 372 | 373 | # Visual Studio LightSwitch build output 374 | **/*.HTMLClient/GeneratedArtifacts 375 | **/*.DesktopClient/GeneratedArtifacts 376 | **/*.DesktopClient/ModelManifest.xml 377 | **/*.Server/GeneratedArtifacts 378 | **/*.Server/ModelManifest.xml 379 | _Pvt_Extensions 380 | 381 | # Paket dependency manager 382 | .paket/paket.exe 383 | paket-files/ 384 | 385 | # FAKE - F# Make 386 | .fake/ 387 | 388 | # CodeRush personal settings 389 | .cr/personal 390 | 391 | # Python Tools for Visual Studio (PTVS) 392 | __pycache__/ 393 | *.pyc 394 | 395 | # Cake - Uncomment if you are using it 396 | # tools/** 397 | # !tools/packages.config 398 | 399 | # Tabs Studio 400 | *.tss 401 | 402 | # Telerik's JustMock configuration file 403 | *.jmconfig 404 | 405 | # BizTalk build output 406 | *.btp.cs 407 | *.btm.cs 408 | *.odx.cs 409 | *.xsd.cs 410 | 411 | # OpenCover UI analysis results 412 | OpenCover/ 413 | 414 | # Azure Stream Analytics local run output 415 | ASALocalRun/ 416 | 417 | # MSBuild Binary and Structured Log 418 | *.binlog 419 | 420 | # NVidia Nsight GPU debugger configuration file 421 | *.nvuser 422 | 423 | # MFractors (Xamarin productivity tool) working folder 424 | .mfractor/ 425 | 426 | # Local History for Visual Studio 427 | .localhistory/ 428 | 429 | # BeatPulse healthcheck temp database 430 | healthchecksdb 431 | 432 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 433 | MigrationBackup/ 434 | 435 | # Ionide (cross platform F# VS Code tools) working folder 436 | .ionide/ 437 | 438 | # Fody - auto-generated XML schema 439 | FodyWeavers.xsd 440 | 441 | # VS Code files for those working on multiple tools 442 | .vscode/* 443 | !.vscode/settings.json 444 | !.vscode/tasks.json 445 | !.vscode/launch.json 446 | !.vscode/extensions.json 447 | *.code-workspace 448 | 449 | # Local History for Visual Studio Code 450 | .history/ 451 | 452 | # Windows Installer files from build outputs 453 | 454 | # JetBrains Rider 455 | .idea/ 456 | *.sln.iml 457 | 458 | ### VisualStudio Patch ### 459 | # Additional files built by Visual Studio 460 | 461 | # End of https://www.toptal.com/developers/gitignore/api/windows,c++,visualstudio,executable 462 | -------------------------------------------------------------------------------- /external/minhook/hde/hde32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 32 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #if defined(_M_IX86) || defined(__i386__) 9 | 10 | #include 11 | #include "hde32.h" 12 | #include "table32.h" 13 | 14 | unsigned int hde32_disasm(const void *code, hde32s *hs) 15 | { 16 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; 17 | uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; 18 | 19 | memset(hs, 0, sizeof(hde32s)); 20 | 21 | for (x = 16; x; x--) 22 | switch (c = *p++) { 23 | case 0xf3: 24 | hs->p_rep = c; 25 | pref |= PRE_F3; 26 | break; 27 | case 0xf2: 28 | hs->p_rep = c; 29 | pref |= PRE_F2; 30 | break; 31 | case 0xf0: 32 | hs->p_lock = c; 33 | pref |= PRE_LOCK; 34 | break; 35 | case 0x26: case 0x2e: case 0x36: 36 | case 0x3e: case 0x64: case 0x65: 37 | hs->p_seg = c; 38 | pref |= PRE_SEG; 39 | break; 40 | case 0x66: 41 | hs->p_66 = c; 42 | pref |= PRE_66; 43 | break; 44 | case 0x67: 45 | hs->p_67 = c; 46 | pref |= PRE_67; 47 | break; 48 | default: 49 | goto pref_done; 50 | } 51 | pref_done: 52 | 53 | hs->flags = (uint32_t)pref << 23; 54 | 55 | if (!pref) 56 | pref |= PRE_NONE; 57 | 58 | if ((hs->opcode = c) == 0x0f) { 59 | hs->opcode2 = c = *p++; 60 | ht += DELTA_OPCODES; 61 | } else if (c >= 0xa0 && c <= 0xa3) { 62 | if (pref & PRE_67) 63 | pref |= PRE_66; 64 | else 65 | pref &= ~PRE_66; 66 | } 67 | 68 | opcode = c; 69 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 70 | 71 | if (cflags == C_ERROR) { 72 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 73 | cflags = 0; 74 | if ((opcode & -3) == 0x24) 75 | cflags++; 76 | } 77 | 78 | x = 0; 79 | if (cflags & C_GROUP) { 80 | uint16_t t; 81 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 82 | cflags = (uint8_t)t; 83 | x = (uint8_t)(t >> 8); 84 | } 85 | 86 | if (hs->opcode2) { 87 | ht = hde32_table + DELTA_PREFIXES; 88 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 89 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 90 | } 91 | 92 | if (cflags & C_MODRM) { 93 | hs->flags |= F_MODRM; 94 | hs->modrm = c = *p++; 95 | hs->modrm_mod = m_mod = c >> 6; 96 | hs->modrm_rm = m_rm = c & 7; 97 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 98 | 99 | if (x && ((x << m_reg) & 0x80)) 100 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 101 | 102 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 103 | uint8_t t = opcode - 0xd9; 104 | if (m_mod == 3) { 105 | ht = hde32_table + DELTA_FPU_MODRM + t*8; 106 | t = ht[m_reg] << m_rm; 107 | } else { 108 | ht = hde32_table + DELTA_FPU_REG; 109 | t = ht[t] << m_reg; 110 | } 111 | if (t & 0x80) 112 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 113 | } 114 | 115 | if (pref & PRE_LOCK) { 116 | if (m_mod == 3) { 117 | hs->flags |= F_ERROR | F_ERROR_LOCK; 118 | } else { 119 | uint8_t *table_end, op = opcode; 120 | if (hs->opcode2) { 121 | ht = hde32_table + DELTA_OP2_LOCK_OK; 122 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 123 | } else { 124 | ht = hde32_table + DELTA_OP_LOCK_OK; 125 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 126 | op &= -2; 127 | } 128 | for (; ht != table_end; ht++) 129 | if (*ht++ == op) { 130 | if (!((*ht << m_reg) & 0x80)) 131 | goto no_lock_error; 132 | else 133 | break; 134 | } 135 | hs->flags |= F_ERROR | F_ERROR_LOCK; 136 | no_lock_error: 137 | ; 138 | } 139 | } 140 | 141 | if (hs->opcode2) { 142 | switch (opcode) { 143 | case 0x20: case 0x22: 144 | m_mod = 3; 145 | if (m_reg > 4 || m_reg == 1) 146 | goto error_operand; 147 | else 148 | goto no_error_operand; 149 | case 0x21: case 0x23: 150 | m_mod = 3; 151 | if (m_reg == 4 || m_reg == 5) 152 | goto error_operand; 153 | else 154 | goto no_error_operand; 155 | } 156 | } else { 157 | switch (opcode) { 158 | case 0x8c: 159 | if (m_reg > 5) 160 | goto error_operand; 161 | else 162 | goto no_error_operand; 163 | case 0x8e: 164 | if (m_reg == 1 || m_reg > 5) 165 | goto error_operand; 166 | else 167 | goto no_error_operand; 168 | } 169 | } 170 | 171 | if (m_mod == 3) { 172 | uint8_t *table_end; 173 | if (hs->opcode2) { 174 | ht = hde32_table + DELTA_OP2_ONLY_MEM; 175 | table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; 176 | } else { 177 | ht = hde32_table + DELTA_OP_ONLY_MEM; 178 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 179 | } 180 | for (; ht != table_end; ht += 2) 181 | if (*ht++ == opcode) { 182 | if ((*ht++ & pref) && !((*ht << m_reg) & 0x80)) 183 | goto error_operand; 184 | else 185 | break; 186 | } 187 | goto no_error_operand; 188 | } else if (hs->opcode2) { 189 | switch (opcode) { 190 | case 0x50: case 0xd7: case 0xf7: 191 | if (pref & (PRE_NONE | PRE_66)) 192 | goto error_operand; 193 | break; 194 | case 0xd6: 195 | if (pref & (PRE_F2 | PRE_F3)) 196 | goto error_operand; 197 | break; 198 | case 0xc5: 199 | goto error_operand; 200 | } 201 | goto no_error_operand; 202 | } else 203 | goto no_error_operand; 204 | 205 | error_operand: 206 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 207 | no_error_operand: 208 | 209 | c = *p++; 210 | if (m_reg <= 1) { 211 | if (opcode == 0xf6) 212 | cflags |= C_IMM8; 213 | else if (opcode == 0xf7) 214 | cflags |= C_IMM_P66; 215 | } 216 | 217 | switch (m_mod) { 218 | case 0: 219 | if (pref & PRE_67) { 220 | if (m_rm == 6) 221 | disp_size = 2; 222 | } else 223 | if (m_rm == 5) 224 | disp_size = 4; 225 | break; 226 | case 1: 227 | disp_size = 1; 228 | break; 229 | case 2: 230 | disp_size = 2; 231 | if (!(pref & PRE_67)) 232 | disp_size <<= 1; 233 | break; 234 | } 235 | 236 | if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { 237 | hs->flags |= F_SIB; 238 | p++; 239 | hs->sib = c; 240 | hs->sib_scale = c >> 6; 241 | hs->sib_index = (c & 0x3f) >> 3; 242 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 243 | disp_size = 4; 244 | } 245 | 246 | p--; 247 | switch (disp_size) { 248 | case 1: 249 | hs->flags |= F_DISP8; 250 | hs->disp.disp8 = *p; 251 | break; 252 | case 2: 253 | hs->flags |= F_DISP16; 254 | hs->disp.disp16 = *(uint16_t *)p; 255 | break; 256 | case 4: 257 | hs->flags |= F_DISP32; 258 | hs->disp.disp32 = *(uint32_t *)p; 259 | break; 260 | } 261 | p += disp_size; 262 | } else if (pref & PRE_LOCK) 263 | hs->flags |= F_ERROR | F_ERROR_LOCK; 264 | 265 | if (cflags & C_IMM_P66) { 266 | if (cflags & C_REL32) { 267 | if (pref & PRE_66) { 268 | hs->flags |= F_IMM16 | F_RELATIVE; 269 | hs->imm.imm16 = *(uint16_t *)p; 270 | p += 2; 271 | goto disasm_done; 272 | } 273 | goto rel32_ok; 274 | } 275 | if (pref & PRE_66) { 276 | hs->flags |= F_IMM16; 277 | hs->imm.imm16 = *(uint16_t *)p; 278 | p += 2; 279 | } else { 280 | hs->flags |= F_IMM32; 281 | hs->imm.imm32 = *(uint32_t *)p; 282 | p += 4; 283 | } 284 | } 285 | 286 | if (cflags & C_IMM16) { 287 | if (hs->flags & F_IMM32) { 288 | hs->flags |= F_IMM16; 289 | hs->disp.disp16 = *(uint16_t *)p; 290 | } else if (hs->flags & F_IMM16) { 291 | hs->flags |= F_2IMM16; 292 | hs->disp.disp16 = *(uint16_t *)p; 293 | } else { 294 | hs->flags |= F_IMM16; 295 | hs->imm.imm16 = *(uint16_t *)p; 296 | } 297 | p += 2; 298 | } 299 | if (cflags & C_IMM8) { 300 | hs->flags |= F_IMM8; 301 | hs->imm.imm8 = *p++; 302 | } 303 | 304 | if (cflags & C_REL32) { 305 | rel32_ok: 306 | hs->flags |= F_IMM32 | F_RELATIVE; 307 | hs->imm.imm32 = *(uint32_t *)p; 308 | p += 4; 309 | } else if (cflags & C_REL8) { 310 | hs->flags |= F_IMM8 | F_RELATIVE; 311 | hs->imm.imm8 = *p++; 312 | } 313 | 314 | disasm_done: 315 | 316 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 317 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 318 | hs->len = 15; 319 | } 320 | 321 | return (unsigned int)hs->len; 322 | } 323 | 324 | #endif // defined(_M_IX86) || defined(__i386__) 325 | -------------------------------------------------------------------------------- /external/minhook/hde/hde64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #if defined(_M_X64) || defined(__x86_64__) 9 | 10 | #include 11 | #include "hde64.h" 12 | #include "table64.h" 13 | 14 | unsigned int hde64_disasm(const void *code, hde64s *hs) 15 | { 16 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; 17 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; 18 | uint8_t op64 = 0; 19 | 20 | memset(hs, 0, sizeof(hde64s)); 21 | 22 | for (x = 16; x; x--) 23 | switch (c = *p++) { 24 | case 0xf3: 25 | hs->p_rep = c; 26 | pref |= PRE_F3; 27 | break; 28 | case 0xf2: 29 | hs->p_rep = c; 30 | pref |= PRE_F2; 31 | break; 32 | case 0xf0: 33 | hs->p_lock = c; 34 | pref |= PRE_LOCK; 35 | break; 36 | case 0x26: case 0x2e: case 0x36: 37 | case 0x3e: case 0x64: case 0x65: 38 | hs->p_seg = c; 39 | pref |= PRE_SEG; 40 | break; 41 | case 0x66: 42 | hs->p_66 = c; 43 | pref |= PRE_66; 44 | break; 45 | case 0x67: 46 | hs->p_67 = c; 47 | pref |= PRE_67; 48 | break; 49 | default: 50 | goto pref_done; 51 | } 52 | pref_done: 53 | 54 | hs->flags = (uint32_t)pref << 23; 55 | 56 | if (!pref) 57 | pref |= PRE_NONE; 58 | 59 | if ((c & 0xf0) == 0x40) { 60 | hs->flags |= F_PREFIX_REX; 61 | if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) 62 | op64++; 63 | hs->rex_r = (c & 7) >> 2; 64 | hs->rex_x = (c & 3) >> 1; 65 | hs->rex_b = c & 1; 66 | if (((c = *p++) & 0xf0) == 0x40) { 67 | opcode = c; 68 | goto error_opcode; 69 | } 70 | } 71 | 72 | if ((hs->opcode = c) == 0x0f) { 73 | hs->opcode2 = c = *p++; 74 | ht += DELTA_OPCODES; 75 | } else if (c >= 0xa0 && c <= 0xa3) { 76 | op64++; 77 | if (pref & PRE_67) 78 | pref |= PRE_66; 79 | else 80 | pref &= ~PRE_66; 81 | } 82 | 83 | opcode = c; 84 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 85 | 86 | if (cflags == C_ERROR) { 87 | error_opcode: 88 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 89 | cflags = 0; 90 | if ((opcode & -3) == 0x24) 91 | cflags++; 92 | } 93 | 94 | x = 0; 95 | if (cflags & C_GROUP) { 96 | uint16_t t; 97 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 98 | cflags = (uint8_t)t; 99 | x = (uint8_t)(t >> 8); 100 | } 101 | 102 | if (hs->opcode2) { 103 | ht = hde64_table + DELTA_PREFIXES; 104 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 105 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 106 | } 107 | 108 | if (cflags & C_MODRM) { 109 | hs->flags |= F_MODRM; 110 | hs->modrm = c = *p++; 111 | hs->modrm_mod = m_mod = c >> 6; 112 | hs->modrm_rm = m_rm = c & 7; 113 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 114 | 115 | if (x && ((x << m_reg) & 0x80)) 116 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 117 | 118 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 119 | uint8_t t = opcode - 0xd9; 120 | if (m_mod == 3) { 121 | ht = hde64_table + DELTA_FPU_MODRM + t*8; 122 | t = ht[m_reg] << m_rm; 123 | } else { 124 | ht = hde64_table + DELTA_FPU_REG; 125 | t = ht[t] << m_reg; 126 | } 127 | if (t & 0x80) 128 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 129 | } 130 | 131 | if (pref & PRE_LOCK) { 132 | if (m_mod == 3) { 133 | hs->flags |= F_ERROR | F_ERROR_LOCK; 134 | } else { 135 | uint8_t *table_end, op = opcode; 136 | if (hs->opcode2) { 137 | ht = hde64_table + DELTA_OP2_LOCK_OK; 138 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 139 | } else { 140 | ht = hde64_table + DELTA_OP_LOCK_OK; 141 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 142 | op &= -2; 143 | } 144 | for (; ht != table_end; ht++) 145 | if (*ht++ == op) { 146 | if (!((*ht << m_reg) & 0x80)) 147 | goto no_lock_error; 148 | else 149 | break; 150 | } 151 | hs->flags |= F_ERROR | F_ERROR_LOCK; 152 | no_lock_error: 153 | ; 154 | } 155 | } 156 | 157 | if (hs->opcode2) { 158 | switch (opcode) { 159 | case 0x20: case 0x22: 160 | m_mod = 3; 161 | if (m_reg > 4 || m_reg == 1) 162 | goto error_operand; 163 | else 164 | goto no_error_operand; 165 | case 0x21: case 0x23: 166 | m_mod = 3; 167 | if (m_reg == 4 || m_reg == 5) 168 | goto error_operand; 169 | else 170 | goto no_error_operand; 171 | } 172 | } else { 173 | switch (opcode) { 174 | case 0x8c: 175 | if (m_reg > 5) 176 | goto error_operand; 177 | else 178 | goto no_error_operand; 179 | case 0x8e: 180 | if (m_reg == 1 || m_reg > 5) 181 | goto error_operand; 182 | else 183 | goto no_error_operand; 184 | } 185 | } 186 | 187 | if (m_mod == 3) { 188 | uint8_t *table_end; 189 | if (hs->opcode2) { 190 | ht = hde64_table + DELTA_OP2_ONLY_MEM; 191 | table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; 192 | } else { 193 | ht = hde64_table + DELTA_OP_ONLY_MEM; 194 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 195 | } 196 | for (; ht != table_end; ht += 2) 197 | if (*ht++ == opcode) { 198 | if (*ht++ & pref && !((*ht << m_reg) & 0x80)) 199 | goto error_operand; 200 | else 201 | break; 202 | } 203 | goto no_error_operand; 204 | } else if (hs->opcode2) { 205 | switch (opcode) { 206 | case 0x50: case 0xd7: case 0xf7: 207 | if (pref & (PRE_NONE | PRE_66)) 208 | goto error_operand; 209 | break; 210 | case 0xd6: 211 | if (pref & (PRE_F2 | PRE_F3)) 212 | goto error_operand; 213 | break; 214 | case 0xc5: 215 | goto error_operand; 216 | } 217 | goto no_error_operand; 218 | } else 219 | goto no_error_operand; 220 | 221 | error_operand: 222 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 223 | no_error_operand: 224 | 225 | c = *p++; 226 | if (m_reg <= 1) { 227 | if (opcode == 0xf6) 228 | cflags |= C_IMM8; 229 | else if (opcode == 0xf7) 230 | cflags |= C_IMM_P66; 231 | } 232 | 233 | switch (m_mod) { 234 | case 0: 235 | if (pref & PRE_67) { 236 | if (m_rm == 6) 237 | disp_size = 2; 238 | } else 239 | if (m_rm == 5) 240 | disp_size = 4; 241 | break; 242 | case 1: 243 | disp_size = 1; 244 | break; 245 | case 2: 246 | disp_size = 2; 247 | if (!(pref & PRE_67)) 248 | disp_size <<= 1; 249 | } 250 | 251 | if (m_mod != 3 && m_rm == 4) { 252 | hs->flags |= F_SIB; 253 | p++; 254 | hs->sib = c; 255 | hs->sib_scale = c >> 6; 256 | hs->sib_index = (c & 0x3f) >> 3; 257 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 258 | disp_size = 4; 259 | } 260 | 261 | p--; 262 | switch (disp_size) { 263 | case 1: 264 | hs->flags |= F_DISP8; 265 | hs->disp.disp8 = *p; 266 | break; 267 | case 2: 268 | hs->flags |= F_DISP16; 269 | hs->disp.disp16 = *(uint16_t *)p; 270 | break; 271 | case 4: 272 | hs->flags |= F_DISP32; 273 | hs->disp.disp32 = *(uint32_t *)p; 274 | } 275 | p += disp_size; 276 | } else if (pref & PRE_LOCK) 277 | hs->flags |= F_ERROR | F_ERROR_LOCK; 278 | 279 | if (cflags & C_IMM_P66) { 280 | if (cflags & C_REL32) { 281 | if (pref & PRE_66) { 282 | hs->flags |= F_IMM16 | F_RELATIVE; 283 | hs->imm.imm16 = *(uint16_t *)p; 284 | p += 2; 285 | goto disasm_done; 286 | } 287 | goto rel32_ok; 288 | } 289 | if (op64) { 290 | hs->flags |= F_IMM64; 291 | hs->imm.imm64 = *(uint64_t *)p; 292 | p += 8; 293 | } else if (!(pref & PRE_66)) { 294 | hs->flags |= F_IMM32; 295 | hs->imm.imm32 = *(uint32_t *)p; 296 | p += 4; 297 | } else 298 | goto imm16_ok; 299 | } 300 | 301 | 302 | if (cflags & C_IMM16) { 303 | imm16_ok: 304 | hs->flags |= F_IMM16; 305 | hs->imm.imm16 = *(uint16_t *)p; 306 | p += 2; 307 | } 308 | if (cflags & C_IMM8) { 309 | hs->flags |= F_IMM8; 310 | hs->imm.imm8 = *p++; 311 | } 312 | 313 | if (cflags & C_REL32) { 314 | rel32_ok: 315 | hs->flags |= F_IMM32 | F_RELATIVE; 316 | hs->imm.imm32 = *(uint32_t *)p; 317 | p += 4; 318 | } else if (cflags & C_REL8) { 319 | hs->flags |= F_IMM8 | F_RELATIVE; 320 | hs->imm.imm8 = *p++; 321 | } 322 | 323 | disasm_done: 324 | 325 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 326 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 327 | hs->len = 15; 328 | } 329 | 330 | return (unsigned int)hs->len; 331 | } 332 | 333 | #endif // defined(_M_X64) || defined(__x86_64__) 334 | -------------------------------------------------------------------------------- /external/minhook/buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #define WIN32_LEAN_AND_MEAN 29 | 30 | #include 31 | #include "buffer.h" 32 | 33 | // Size of each memory block. (= page size of VirtualAlloc) 34 | #define MEMORY_BLOCK_SIZE 0x1000 35 | 36 | // Max range for seeking a memory block. (= 1024MB) 37 | #define MAX_MEMORY_RANGE 0x40000000 38 | 39 | // Memory protection flags to check the executable address. 40 | #define PAGE_EXECUTE_FLAGS \ 41 | (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) 42 | 43 | // Memory slot. 44 | typedef struct _MEMORY_SLOT 45 | { 46 | union 47 | { 48 | struct _MEMORY_SLOT *pNext; 49 | UINT8 buffer[MEMORY_SLOT_SIZE]; 50 | }; 51 | } MEMORY_SLOT, *PMEMORY_SLOT; 52 | 53 | // Memory block info. Placed at the head of each block. 54 | typedef struct _MEMORY_BLOCK 55 | { 56 | struct _MEMORY_BLOCK *pNext; 57 | PMEMORY_SLOT pFree; // First element of the free slot list. 58 | UINT usedCount; 59 | } MEMORY_BLOCK, *PMEMORY_BLOCK; 60 | 61 | //------------------------------------------------------------------------- 62 | // Global Variables: 63 | //------------------------------------------------------------------------- 64 | 65 | // First element of the memory block list. 66 | PMEMORY_BLOCK g_pMemoryBlocks; 67 | 68 | //------------------------------------------------------------------------- 69 | VOID InitializeBuffer(VOID) 70 | { 71 | // Nothing to do for now. 72 | } 73 | 74 | //------------------------------------------------------------------------- 75 | VOID UninitializeBuffer(VOID) 76 | { 77 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks; 78 | g_pMemoryBlocks = NULL; 79 | 80 | while (pBlock) 81 | { 82 | PMEMORY_BLOCK pNext = pBlock->pNext; 83 | VirtualFree(pBlock, 0, MEM_RELEASE); 84 | pBlock = pNext; 85 | } 86 | } 87 | 88 | //------------------------------------------------------------------------- 89 | #if defined(_M_X64) || defined(__x86_64__) 90 | static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) 91 | { 92 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress; 93 | 94 | // Round down to the allocation granularity. 95 | tryAddr -= tryAddr % dwAllocationGranularity; 96 | 97 | // Start from the previous allocation granularity multiply. 98 | tryAddr -= dwAllocationGranularity; 99 | 100 | while (tryAddr >= (ULONG_PTR)pMinAddr) 101 | { 102 | MEMORY_BASIC_INFORMATION mbi; 103 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) 104 | break; 105 | 106 | if (mbi.State == MEM_FREE) 107 | return (LPVOID)tryAddr; 108 | 109 | if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) 110 | break; 111 | 112 | tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; 113 | } 114 | 115 | return NULL; 116 | } 117 | #endif 118 | 119 | //------------------------------------------------------------------------- 120 | #if defined(_M_X64) || defined(__x86_64__) 121 | static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) 122 | { 123 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress; 124 | 125 | // Round down to the allocation granularity. 126 | tryAddr -= tryAddr % dwAllocationGranularity; 127 | 128 | // Start from the next allocation granularity multiply. 129 | tryAddr += dwAllocationGranularity; 130 | 131 | while (tryAddr <= (ULONG_PTR)pMaxAddr) 132 | { 133 | MEMORY_BASIC_INFORMATION mbi; 134 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) 135 | break; 136 | 137 | if (mbi.State == MEM_FREE) 138 | return (LPVOID)tryAddr; 139 | 140 | tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; 141 | 142 | // Round up to the next allocation granularity. 143 | tryAddr += dwAllocationGranularity - 1; 144 | tryAddr -= tryAddr % dwAllocationGranularity; 145 | } 146 | 147 | return NULL; 148 | } 149 | #endif 150 | 151 | //------------------------------------------------------------------------- 152 | static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) 153 | { 154 | PMEMORY_BLOCK pBlock; 155 | #if defined(_M_X64) || defined(__x86_64__) 156 | ULONG_PTR minAddr; 157 | ULONG_PTR maxAddr; 158 | 159 | SYSTEM_INFO si; 160 | GetSystemInfo(&si); 161 | minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; 162 | maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; 163 | 164 | // pOrigin ± 512MB 165 | if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) 166 | minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; 167 | 168 | if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) 169 | maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; 170 | 171 | // Make room for MEMORY_BLOCK_SIZE bytes. 172 | maxAddr -= MEMORY_BLOCK_SIZE - 1; 173 | #endif 174 | 175 | // Look the registered blocks for a reachable one. 176 | for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) 177 | { 178 | #if defined(_M_X64) || defined(__x86_64__) 179 | // Ignore the blocks too far. 180 | if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) 181 | continue; 182 | #endif 183 | // The block has at least one unused slot. 184 | if (pBlock->pFree != NULL) 185 | return pBlock; 186 | } 187 | 188 | #if defined(_M_X64) || defined(__x86_64__) 189 | // Alloc a new block above if not found. 190 | { 191 | LPVOID pAlloc = pOrigin; 192 | while ((ULONG_PTR)pAlloc >= minAddr) 193 | { 194 | pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); 195 | if (pAlloc == NULL) 196 | break; 197 | 198 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 199 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 200 | if (pBlock != NULL) 201 | break; 202 | } 203 | } 204 | 205 | // Alloc a new block below if not found. 206 | if (pBlock == NULL) 207 | { 208 | LPVOID pAlloc = pOrigin; 209 | while ((ULONG_PTR)pAlloc <= maxAddr) 210 | { 211 | pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); 212 | if (pAlloc == NULL) 213 | break; 214 | 215 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 216 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 217 | if (pBlock != NULL) 218 | break; 219 | } 220 | } 221 | #else 222 | // In x86 mode, a memory block can be placed anywhere. 223 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 224 | NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 225 | #endif 226 | 227 | if (pBlock != NULL) 228 | { 229 | // Build a linked list of all the slots. 230 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; 231 | pBlock->pFree = NULL; 232 | pBlock->usedCount = 0; 233 | do 234 | { 235 | pSlot->pNext = pBlock->pFree; 236 | pBlock->pFree = pSlot; 237 | pSlot++; 238 | } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); 239 | 240 | pBlock->pNext = g_pMemoryBlocks; 241 | g_pMemoryBlocks = pBlock; 242 | } 243 | 244 | return pBlock; 245 | } 246 | 247 | //------------------------------------------------------------------------- 248 | LPVOID AllocateBuffer(LPVOID pOrigin) 249 | { 250 | PMEMORY_SLOT pSlot; 251 | PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); 252 | if (pBlock == NULL) 253 | return NULL; 254 | 255 | // Remove an unused slot from the list. 256 | pSlot = pBlock->pFree; 257 | pBlock->pFree = pSlot->pNext; 258 | pBlock->usedCount++; 259 | #ifdef _DEBUG 260 | // Fill the slot with INT3 for debugging. 261 | memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); 262 | #endif 263 | return pSlot; 264 | } 265 | 266 | //------------------------------------------------------------------------- 267 | VOID FreeBuffer(LPVOID pBuffer) 268 | { 269 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks; 270 | PMEMORY_BLOCK pPrev = NULL; 271 | ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; 272 | 273 | while (pBlock != NULL) 274 | { 275 | if ((ULONG_PTR)pBlock == pTargetBlock) 276 | { 277 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; 278 | #ifdef _DEBUG 279 | // Clear the released slot for debugging. 280 | memset(pSlot, 0x00, sizeof(MEMORY_SLOT)); 281 | #endif 282 | // Restore the released slot to the list. 283 | pSlot->pNext = pBlock->pFree; 284 | pBlock->pFree = pSlot; 285 | pBlock->usedCount--; 286 | 287 | // Free if unused. 288 | if (pBlock->usedCount == 0) 289 | { 290 | if (pPrev) 291 | pPrev->pNext = pBlock->pNext; 292 | else 293 | g_pMemoryBlocks = pBlock->pNext; 294 | 295 | VirtualFree(pBlock, 0, MEM_RELEASE); 296 | } 297 | 298 | break; 299 | } 300 | 301 | pPrev = pBlock; 302 | pBlock = pBlock->pNext; 303 | } 304 | } 305 | 306 | //------------------------------------------------------------------------- 307 | BOOL IsExecutableAddress(LPVOID pAddress) 308 | { 309 | MEMORY_BASIC_INFORMATION mi; 310 | VirtualQuery(pAddress, &mi, sizeof(mi)); 311 | 312 | return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); 313 | } 314 | -------------------------------------------------------------------------------- /external/minhook/trampoline.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #define WIN32_LEAN_AND_MEAN 30 | #include 31 | 32 | #ifdef _MSC_VER 33 | #include 34 | #endif 35 | 36 | #ifndef ARRAYSIZE 37 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 38 | #endif 39 | 40 | #if defined(_M_X64) || defined(__x86_64__) 41 | #include "./hde/hde64.h" 42 | typedef hde64s HDE; 43 | #define HDE_DISASM(code, hs) hde64_disasm(code, hs) 44 | #else 45 | #include "./hde/hde32.h" 46 | typedef hde32s HDE; 47 | #define HDE_DISASM(code, hs) hde32_disasm(code, hs) 48 | #endif 49 | 50 | #include "trampoline.h" 51 | #include "buffer.h" 52 | 53 | // Maximum size of a trampoline function. 54 | #if defined(_M_X64) || defined(__x86_64__) 55 | #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) 56 | #else 57 | #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE 58 | #endif 59 | 60 | //------------------------------------------------------------------------- 61 | static BOOL IsCodePadding(LPBYTE pInst, UINT size) 62 | { 63 | UINT i; 64 | 65 | if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) 66 | return FALSE; 67 | 68 | for (i = 1; i < size; ++i) 69 | { 70 | if (pInst[i] != pInst[0]) 71 | return FALSE; 72 | } 73 | return TRUE; 74 | } 75 | 76 | //------------------------------------------------------------------------- 77 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct) 78 | { 79 | #if defined(_M_X64) || defined(__x86_64__) 80 | CALL_ABS call = { 81 | 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] 82 | 0xEB, 0x08, // EB 08: JMP +10 83 | 0x0000000000000000ULL // Absolute destination address 84 | }; 85 | JMP_ABS jmp = { 86 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 87 | 0x0000000000000000ULL // Absolute destination address 88 | }; 89 | JCC_ABS jcc = { 90 | 0x70, 0x0E, // 7* 0E: J** +16 91 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 92 | 0x0000000000000000ULL // Absolute destination address 93 | }; 94 | #else 95 | CALL_REL call = { 96 | 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx 97 | 0x00000000 // Relative destination address 98 | }; 99 | JMP_REL jmp = { 100 | 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx 101 | 0x00000000 // Relative destination address 102 | }; 103 | JCC_REL jcc = { 104 | 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx 105 | 0x00000000 // Relative destination address 106 | }; 107 | #endif 108 | 109 | UINT8 oldPos = 0; 110 | UINT8 newPos = 0; 111 | ULONG_PTR jmpDest = 0; // Destination address of an internal jump. 112 | BOOL finished = FALSE; // Is the function completed? 113 | #if defined(_M_X64) || defined(__x86_64__) 114 | UINT8 instBuf[16]; 115 | #endif 116 | 117 | ct->patchAbove = FALSE; 118 | ct->nIP = 0; 119 | 120 | do 121 | { 122 | HDE hs; 123 | UINT copySize; 124 | LPVOID pCopySrc; 125 | ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; 126 | ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; 127 | 128 | copySize = HDE_DISASM((LPVOID)pOldInst, &hs); 129 | if (hs.flags & F_ERROR) 130 | return FALSE; 131 | 132 | pCopySrc = (LPVOID)pOldInst; 133 | if (oldPos >= sizeof(JMP_REL)) 134 | { 135 | // The trampoline function is long enough. 136 | // Complete the function with the jump to the target function. 137 | #if defined(_M_X64) || defined(__x86_64__) 138 | jmp.address = pOldInst; 139 | #else 140 | jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); 141 | #endif 142 | pCopySrc = &jmp; 143 | copySize = sizeof(jmp); 144 | 145 | finished = TRUE; 146 | } 147 | #if defined(_M_X64) || defined(__x86_64__) 148 | else if ((hs.modrm & 0xC7) == 0x05) 149 | { 150 | // Instructions using RIP relative addressing. (ModR/M = 00???101B) 151 | 152 | // Modify the RIP relative address. 153 | PUINT32 pRelAddr; 154 | 155 | // Avoid using memcpy to reduce the footprint. 156 | #ifndef _MSC_VER 157 | memcpy(instBuf, (LPBYTE)pOldInst, copySize); 158 | #else 159 | __movsb(instBuf, (LPBYTE)pOldInst, copySize); 160 | #endif 161 | pCopySrc = instBuf; 162 | 163 | // Relative address is stored at (instruction length - immediate value length - 4). 164 | pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); 165 | *pRelAddr 166 | = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); 167 | 168 | // Complete the function if JMP (FF /4). 169 | if (hs.opcode == 0xFF && hs.modrm_reg == 4) 170 | finished = TRUE; 171 | } 172 | #endif 173 | else if (hs.opcode == 0xE8) 174 | { 175 | // Direct relative CALL 176 | ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; 177 | #if defined(_M_X64) || defined(__x86_64__) 178 | call.address = dest; 179 | #else 180 | call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); 181 | #endif 182 | pCopySrc = &call; 183 | copySize = sizeof(call); 184 | } 185 | else if ((hs.opcode & 0xFD) == 0xE9) 186 | { 187 | // Direct relative JMP (EB or E9) 188 | ULONG_PTR dest = pOldInst + hs.len; 189 | 190 | if (hs.opcode == 0xEB) // isShort jmp 191 | dest += (INT8)hs.imm.imm8; 192 | else 193 | dest += (INT32)hs.imm.imm32; 194 | 195 | // Simply copy an internal jump. 196 | if ((ULONG_PTR)ct->pTarget <= dest 197 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 198 | { 199 | if (jmpDest < dest) 200 | jmpDest = dest; 201 | } 202 | else 203 | { 204 | #if defined(_M_X64) || defined(__x86_64__) 205 | jmp.address = dest; 206 | #else 207 | jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); 208 | #endif 209 | pCopySrc = &jmp; 210 | copySize = sizeof(jmp); 211 | 212 | // Exit the function If it is not in the branch 213 | finished = (pOldInst >= jmpDest); 214 | } 215 | } 216 | else if ((hs.opcode & 0xF0) == 0x70 217 | || (hs.opcode & 0xFC) == 0xE0 218 | || (hs.opcode2 & 0xF0) == 0x80) 219 | { 220 | // Direct relative Jcc 221 | ULONG_PTR dest = pOldInst + hs.len; 222 | 223 | if ((hs.opcode & 0xF0) == 0x70 // Jcc 224 | || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ 225 | dest += (INT8)hs.imm.imm8; 226 | else 227 | dest += (INT32)hs.imm.imm32; 228 | 229 | // Simply copy an internal jump. 230 | if ((ULONG_PTR)ct->pTarget <= dest 231 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 232 | { 233 | if (jmpDest < dest) 234 | jmpDest = dest; 235 | } 236 | else if ((hs.opcode & 0xFC) == 0xE0) 237 | { 238 | // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. 239 | return FALSE; 240 | } 241 | else 242 | { 243 | UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); 244 | #if defined(_M_X64) || defined(__x86_64__) 245 | // Invert the condition in x64 mode to simplify the conditional jump logic. 246 | jcc.opcode = 0x71 ^ cond; 247 | jcc.address = dest; 248 | #else 249 | jcc.opcode1 = 0x80 | cond; 250 | jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); 251 | #endif 252 | pCopySrc = &jcc; 253 | copySize = sizeof(jcc); 254 | } 255 | } 256 | else if ((hs.opcode & 0xFE) == 0xC2) 257 | { 258 | // RET (C2 or C3) 259 | 260 | // Complete the function if not in a branch. 261 | finished = (pOldInst >= jmpDest); 262 | } 263 | 264 | // Can't alter the instruction length in a branch. 265 | if (pOldInst < jmpDest && copySize != hs.len) 266 | return FALSE; 267 | 268 | // Trampoline function is too large. 269 | if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) 270 | return FALSE; 271 | 272 | // Trampoline function has too many instructions. 273 | if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) 274 | return FALSE; 275 | 276 | ct->oldIPs[ct->nIP] = oldPos; 277 | ct->newIPs[ct->nIP] = newPos; 278 | ct->nIP++; 279 | 280 | // Avoid using memcpy to reduce the footprint. 281 | #ifndef _MSC_VER 282 | memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); 283 | #else 284 | __movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); 285 | #endif 286 | newPos += copySize; 287 | oldPos += hs.len; 288 | } 289 | while (!finished); 290 | 291 | // Is there enough place for a long jump? 292 | if (oldPos < sizeof(JMP_REL) 293 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) 294 | { 295 | // Is there enough place for a short jump? 296 | if (oldPos < sizeof(JMP_REL_SHORT) 297 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) 298 | { 299 | return FALSE; 300 | } 301 | 302 | // Can we place the long jump above the function? 303 | if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) 304 | return FALSE; 305 | 306 | if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) 307 | return FALSE; 308 | 309 | ct->patchAbove = TRUE; 310 | } 311 | 312 | #if defined(_M_X64) || defined(__x86_64__) 313 | // Create a relay function. 314 | jmp.address = (ULONG_PTR)ct->pDetour; 315 | 316 | ct->pRelay = (LPBYTE)ct->pTrampoline + newPos; 317 | memcpy(ct->pRelay, &jmp, sizeof(jmp)); 318 | #endif 319 | 320 | return TRUE; 321 | } 322 | -------------------------------------------------------------------------------- /external/minhook/hook.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #define WIN32_LEAN_AND_MEAN 30 | #include 31 | #include 32 | #include 33 | 34 | #include "minhook.h" 35 | #include "buffer.h" 36 | #include "trampoline.h" 37 | 38 | #ifndef ARRAYSIZE 39 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 40 | #endif 41 | 42 | // Initial capacity of the HOOK_ENTRY buffer. 43 | #define INITIAL_HOOK_CAPACITY 32 44 | 45 | // Initial capacity of the thread IDs buffer. 46 | #define INITIAL_THREAD_CAPACITY 128 47 | 48 | // Special hook position values. 49 | #define INVALID_HOOK_POS UINT_MAX 50 | #define ALL_HOOKS_POS UINT_MAX 51 | 52 | // Freeze() action argument defines. 53 | #define ACTION_DISABLE 0 54 | #define ACTION_ENABLE 1 55 | #define ACTION_APPLY_QUEUED 2 56 | 57 | // Thread access rights for suspending/resuming threads. 58 | #define THREAD_ACCESS \ 59 | (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) 60 | 61 | // Hook information. 62 | typedef struct _HOOK_ENTRY 63 | { 64 | LPVOID pTarget; // Address of the target function. 65 | LPVOID pDetour; // Address of the detour or relay function. 66 | LPVOID pTrampoline; // Address of the trampoline function. 67 | UINT8 backup[8]; // Original prologue of the target function. 68 | 69 | UINT8 patchAbove : 1; // Uses the hot patch area. 70 | UINT8 isEnabled : 1; // Enabled. 71 | UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled. 72 | 73 | UINT nIP : 4; // Count of the instruction boundaries. 74 | UINT8 oldIPs[8]; // Instruction boundaries of the target function. 75 | UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. 76 | } HOOK_ENTRY, *PHOOK_ENTRY; 77 | 78 | // Suspended threads for Freeze()/Unfreeze(). 79 | typedef struct _FROZEN_THREADS 80 | { 81 | LPDWORD pItems; // Data heap 82 | UINT capacity; // Size of allocated data heap, items 83 | UINT size; // Actual number of data items 84 | } FROZEN_THREADS, *PFROZEN_THREADS; 85 | 86 | //------------------------------------------------------------------------- 87 | // Global Variables: 88 | //------------------------------------------------------------------------- 89 | 90 | // Spin lock flag for EnterSpinLock()/LeaveSpinLock(). 91 | volatile LONG g_isLocked = FALSE; 92 | 93 | // Private heap handle. If not NULL, this library is initialized. 94 | HANDLE g_hHeap = NULL; 95 | 96 | // Hook entries. 97 | struct 98 | { 99 | PHOOK_ENTRY pItems; // Data heap 100 | UINT capacity; // Size of allocated data heap, items 101 | UINT size; // Actual number of data items 102 | } g_hooks; 103 | 104 | //------------------------------------------------------------------------- 105 | // Returns INVALID_HOOK_POS if not found. 106 | static UINT FindHookEntry(LPVOID pTarget) 107 | { 108 | UINT i; 109 | for (i = 0; i < g_hooks.size; ++i) 110 | { 111 | if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget) 112 | return i; 113 | } 114 | 115 | return INVALID_HOOK_POS; 116 | } 117 | 118 | //------------------------------------------------------------------------- 119 | static PHOOK_ENTRY AddHookEntry() 120 | { 121 | if (g_hooks.pItems == NULL) 122 | { 123 | g_hooks.capacity = INITIAL_HOOK_CAPACITY; 124 | g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( 125 | g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); 126 | if (g_hooks.pItems == NULL) 127 | return NULL; 128 | } 129 | else if (g_hooks.size >= g_hooks.capacity) 130 | { 131 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( 132 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); 133 | if (p == NULL) 134 | return NULL; 135 | 136 | g_hooks.capacity *= 2; 137 | g_hooks.pItems = p; 138 | } 139 | 140 | return &g_hooks.pItems[g_hooks.size++]; 141 | } 142 | 143 | //------------------------------------------------------------------------- 144 | static void DeleteHookEntry(UINT pos) 145 | { 146 | if (pos < g_hooks.size - 1) 147 | g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; 148 | 149 | g_hooks.size--; 150 | 151 | if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) 152 | { 153 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( 154 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); 155 | if (p == NULL) 156 | return; 157 | 158 | g_hooks.capacity /= 2; 159 | g_hooks.pItems = p; 160 | } 161 | } 162 | 163 | //------------------------------------------------------------------------- 164 | static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) 165 | { 166 | UINT i; 167 | 168 | if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) 169 | return (DWORD_PTR)pHook->pTarget; 170 | 171 | for (i = 0; i < pHook->nIP; ++i) 172 | { 173 | if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i])) 174 | return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; 175 | } 176 | 177 | #if defined(_M_X64) || defined(__x86_64__) 178 | // Check relay function. 179 | if (ip == (DWORD_PTR)pHook->pDetour) 180 | return (DWORD_PTR)pHook->pTarget; 181 | #endif 182 | 183 | return 0; 184 | } 185 | 186 | //------------------------------------------------------------------------- 187 | static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) 188 | { 189 | UINT i; 190 | for (i = 0; i < pHook->nIP; ++i) 191 | { 192 | if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) 193 | return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]; 194 | } 195 | 196 | return 0; 197 | } 198 | 199 | //------------------------------------------------------------------------- 200 | static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) 201 | { 202 | // If the thread suspended in the overwritten area, 203 | // move IP to the proper address. 204 | 205 | CONTEXT c; 206 | #if defined(_M_X64) || defined(__x86_64__) 207 | DWORD64 *pIP = &c.Rip; 208 | #else 209 | DWORD *pIP = &c.Eip; 210 | #endif 211 | UINT count; 212 | 213 | c.ContextFlags = CONTEXT_CONTROL; 214 | if (!GetThreadContext(hThread, &c)) 215 | return; 216 | 217 | if (pos == ALL_HOOKS_POS) 218 | { 219 | pos = 0; 220 | count = g_hooks.size; 221 | } 222 | else 223 | { 224 | count = pos + 1; 225 | } 226 | 227 | for (; pos < count; ++pos) 228 | { 229 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; 230 | BOOL enable; 231 | DWORD_PTR ip; 232 | 233 | switch (action) 234 | { 235 | case ACTION_DISABLE: 236 | enable = FALSE; 237 | break; 238 | 239 | case ACTION_ENABLE: 240 | enable = TRUE; 241 | break; 242 | 243 | default: // ACTION_APPLY_QUEUED 244 | enable = pHook->queueEnable; 245 | break; 246 | } 247 | if (pHook->isEnabled == enable) 248 | continue; 249 | 250 | if (enable) 251 | ip = FindNewIP(pHook, *pIP); 252 | else 253 | ip = FindOldIP(pHook, *pIP); 254 | 255 | if (ip != 0) 256 | { 257 | *pIP = ip; 258 | SetThreadContext(hThread, &c); 259 | } 260 | } 261 | } 262 | 263 | //------------------------------------------------------------------------- 264 | static VOID EnumerateThreads(PFROZEN_THREADS pThreads) 265 | { 266 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 267 | if (hSnapshot != INVALID_HANDLE_VALUE) 268 | { 269 | THREADENTRY32 te; 270 | te.dwSize = sizeof(THREADENTRY32); 271 | if (Thread32First(hSnapshot, &te)) 272 | { 273 | do 274 | { 275 | if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) 276 | && te.th32OwnerProcessID == GetCurrentProcessId() 277 | && te.th32ThreadID != GetCurrentThreadId()) 278 | { 279 | if (pThreads->pItems == NULL) 280 | { 281 | pThreads->capacity = INITIAL_THREAD_CAPACITY; 282 | pThreads->pItems 283 | = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD)); 284 | if (pThreads->pItems == NULL) 285 | break; 286 | } 287 | else if (pThreads->size >= pThreads->capacity) 288 | { 289 | LPDWORD p = (LPDWORD)HeapReAlloc( 290 | g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD)); 291 | if (p == NULL) 292 | break; 293 | 294 | pThreads->capacity *= 2; 295 | pThreads->pItems = p; 296 | } 297 | pThreads->pItems[pThreads->size++] = te.th32ThreadID; 298 | } 299 | 300 | te.dwSize = sizeof(THREADENTRY32); 301 | } while (Thread32Next(hSnapshot, &te)); 302 | } 303 | CloseHandle(hSnapshot); 304 | } 305 | } 306 | 307 | //------------------------------------------------------------------------- 308 | static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action) 309 | { 310 | pThreads->pItems = NULL; 311 | pThreads->capacity = 0; 312 | pThreads->size = 0; 313 | EnumerateThreads(pThreads); 314 | 315 | if (pThreads->pItems != NULL) 316 | { 317 | UINT i; 318 | for (i = 0; i < pThreads->size; ++i) 319 | { 320 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); 321 | if (hThread != NULL) 322 | { 323 | SuspendThread(hThread); 324 | ProcessThreadIPs(hThread, pos, action); 325 | CloseHandle(hThread); 326 | } 327 | } 328 | } 329 | } 330 | 331 | //------------------------------------------------------------------------- 332 | static VOID Unfreeze(PFROZEN_THREADS pThreads) 333 | { 334 | if (pThreads->pItems != NULL) 335 | { 336 | UINT i; 337 | for (i = 0; i < pThreads->size; ++i) 338 | { 339 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); 340 | if (hThread != NULL) 341 | { 342 | ResumeThread(hThread); 343 | CloseHandle(hThread); 344 | } 345 | } 346 | 347 | HeapFree(g_hHeap, 0, pThreads->pItems); 348 | } 349 | } 350 | 351 | //------------------------------------------------------------------------- 352 | static MH_STATUS EnableHookLL(UINT pos, BOOL enable) 353 | { 354 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; 355 | DWORD oldProtect; 356 | SIZE_T patchSize = sizeof(JMP_REL); 357 | LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; 358 | 359 | if (pHook->patchAbove) 360 | { 361 | pPatchTarget -= sizeof(JMP_REL); 362 | patchSize += sizeof(JMP_REL_SHORT); 363 | } 364 | 365 | if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) 366 | return MH_ERROR_MEMORY_PROTECT; 367 | 368 | if (enable) 369 | { 370 | PJMP_REL pJmp = (PJMP_REL)pPatchTarget; 371 | pJmp->opcode = 0xE9; 372 | pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL))); 373 | 374 | if (pHook->patchAbove) 375 | { 376 | PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; 377 | pShortJmp->opcode = 0xEB; 378 | pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL))); 379 | } 380 | } 381 | else 382 | { 383 | if (pHook->patchAbove) 384 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); 385 | else 386 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); 387 | } 388 | 389 | VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); 390 | 391 | // Just-in-case measure. 392 | FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); 393 | 394 | pHook->isEnabled = enable; 395 | pHook->queueEnable = enable; 396 | 397 | return MH_OK; 398 | } 399 | 400 | //------------------------------------------------------------------------- 401 | static MH_STATUS EnableAllHooksLL(BOOL enable) 402 | { 403 | MH_STATUS status = MH_OK; 404 | UINT i, first = INVALID_HOOK_POS; 405 | 406 | for (i = 0; i < g_hooks.size; ++i) 407 | { 408 | if (g_hooks.pItems[i].isEnabled != enable) 409 | { 410 | first = i; 411 | break; 412 | } 413 | } 414 | 415 | if (first != INVALID_HOOK_POS) 416 | { 417 | FROZEN_THREADS threads; 418 | Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE); 419 | 420 | for (i = first; i < g_hooks.size; ++i) 421 | { 422 | if (g_hooks.pItems[i].isEnabled != enable) 423 | { 424 | status = EnableHookLL(i, enable); 425 | if (status != MH_OK) 426 | break; 427 | } 428 | } 429 | 430 | Unfreeze(&threads); 431 | } 432 | 433 | return status; 434 | } 435 | 436 | //------------------------------------------------------------------------- 437 | static VOID EnterSpinLock(VOID) 438 | { 439 | SIZE_T spinCount = 0; 440 | 441 | // Wait until the flag is FALSE. 442 | while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE) 443 | { 444 | // No need to generate a memory barrier here, since InterlockedCompareExchange() 445 | // generates a full memory barrier itself. 446 | 447 | // Prevent the loop from being too busy. 448 | if (spinCount < 32) 449 | Sleep(0); 450 | else 451 | Sleep(1); 452 | 453 | spinCount++; 454 | } 455 | } 456 | 457 | //------------------------------------------------------------------------- 458 | static VOID LeaveSpinLock(VOID) 459 | { 460 | // No need to generate a memory barrier here, since InterlockedExchange() 461 | // generates a full memory barrier itself. 462 | 463 | InterlockedExchange(&g_isLocked, FALSE); 464 | } 465 | 466 | //------------------------------------------------------------------------- 467 | MH_STATUS WINAPI MH_Initialize(VOID) 468 | { 469 | MH_STATUS status = MH_OK; 470 | 471 | EnterSpinLock(); 472 | 473 | if (g_hHeap == NULL) 474 | { 475 | g_hHeap = HeapCreate(0, 0, 0); 476 | if (g_hHeap != NULL) 477 | { 478 | // Initialize the internal function buffer. 479 | InitializeBuffer(); 480 | } 481 | else 482 | { 483 | status = MH_ERROR_MEMORY_ALLOC; 484 | } 485 | } 486 | else 487 | { 488 | status = MH_ERROR_ALREADY_INITIALIZED; 489 | } 490 | 491 | LeaveSpinLock(); 492 | 493 | return status; 494 | } 495 | 496 | //------------------------------------------------------------------------- 497 | MH_STATUS WINAPI MH_Uninitialize(VOID) 498 | { 499 | MH_STATUS status = MH_OK; 500 | 501 | EnterSpinLock(); 502 | 503 | if (g_hHeap != NULL) 504 | { 505 | status = EnableAllHooksLL(FALSE); 506 | if (status == MH_OK) 507 | { 508 | // Free the internal function buffer. 509 | 510 | // HeapFree is actually not required, but some tools detect a false 511 | // memory leak without HeapFree. 512 | 513 | UninitializeBuffer(); 514 | 515 | HeapFree(g_hHeap, 0, g_hooks.pItems); 516 | HeapDestroy(g_hHeap); 517 | 518 | g_hHeap = NULL; 519 | 520 | g_hooks.pItems = NULL; 521 | g_hooks.capacity = 0; 522 | g_hooks.size = 0; 523 | } 524 | } 525 | else 526 | { 527 | status = MH_ERROR_NOT_INITIALIZED; 528 | } 529 | 530 | LeaveSpinLock(); 531 | 532 | return status; 533 | } 534 | 535 | //------------------------------------------------------------------------- 536 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) 537 | { 538 | MH_STATUS status = MH_OK; 539 | 540 | EnterSpinLock(); 541 | 542 | if (g_hHeap != NULL) 543 | { 544 | if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) 545 | { 546 | UINT pos = FindHookEntry(pTarget); 547 | if (pos == INVALID_HOOK_POS) 548 | { 549 | LPVOID pBuffer = AllocateBuffer(pTarget); 550 | if (pBuffer != NULL) 551 | { 552 | TRAMPOLINE ct; 553 | 554 | ct.pTarget = pTarget; 555 | ct.pDetour = pDetour; 556 | ct.pTrampoline = pBuffer; 557 | if (CreateTrampolineFunction(&ct)) 558 | { 559 | PHOOK_ENTRY pHook = AddHookEntry(); 560 | if (pHook != NULL) 561 | { 562 | pHook->pTarget = ct.pTarget; 563 | #if defined(_M_X64) || defined(__x86_64__) 564 | pHook->pDetour = ct.pRelay; 565 | #else 566 | pHook->pDetour = ct.pDetour; 567 | #endif 568 | pHook->pTrampoline = ct.pTrampoline; 569 | pHook->patchAbove = ct.patchAbove; 570 | pHook->isEnabled = FALSE; 571 | pHook->queueEnable = FALSE; 572 | pHook->nIP = ct.nIP; 573 | memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); 574 | memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); 575 | 576 | // Back up the target function. 577 | 578 | if (ct.patchAbove) 579 | { 580 | memcpy( 581 | pHook->backup, 582 | (LPBYTE)pTarget - sizeof(JMP_REL), 583 | sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); 584 | } 585 | else 586 | { 587 | memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); 588 | } 589 | 590 | if (ppOriginal != NULL) 591 | *ppOriginal = pHook->pTrampoline; 592 | } 593 | else 594 | { 595 | status = MH_ERROR_MEMORY_ALLOC; 596 | } 597 | } 598 | else 599 | { 600 | status = MH_ERROR_UNSUPPORTED_FUNCTION; 601 | } 602 | 603 | if (status != MH_OK) 604 | { 605 | FreeBuffer(pBuffer); 606 | } 607 | } 608 | else 609 | { 610 | status = MH_ERROR_MEMORY_ALLOC; 611 | } 612 | } 613 | else 614 | { 615 | status = MH_ERROR_ALREADY_CREATED; 616 | } 617 | } 618 | else 619 | { 620 | status = MH_ERROR_NOT_EXECUTABLE; 621 | } 622 | } 623 | else 624 | { 625 | status = MH_ERROR_NOT_INITIALIZED; 626 | } 627 | 628 | LeaveSpinLock(); 629 | 630 | return status; 631 | } 632 | 633 | //------------------------------------------------------------------------- 634 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) 635 | { 636 | MH_STATUS status = MH_OK; 637 | 638 | EnterSpinLock(); 639 | 640 | if (g_hHeap != NULL) 641 | { 642 | UINT pos = FindHookEntry(pTarget); 643 | if (pos != INVALID_HOOK_POS) 644 | { 645 | if (g_hooks.pItems[pos].isEnabled) 646 | { 647 | FROZEN_THREADS threads; 648 | Freeze(&threads, pos, ACTION_DISABLE); 649 | 650 | status = EnableHookLL(pos, FALSE); 651 | 652 | Unfreeze(&threads); 653 | } 654 | 655 | if (status == MH_OK) 656 | { 657 | FreeBuffer(g_hooks.pItems[pos].pTrampoline); 658 | DeleteHookEntry(pos); 659 | } 660 | } 661 | else 662 | { 663 | status = MH_ERROR_NOT_CREATED; 664 | } 665 | } 666 | else 667 | { 668 | status = MH_ERROR_NOT_INITIALIZED; 669 | } 670 | 671 | LeaveSpinLock(); 672 | 673 | return status; 674 | } 675 | 676 | //------------------------------------------------------------------------- 677 | static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) 678 | { 679 | MH_STATUS status = MH_OK; 680 | 681 | EnterSpinLock(); 682 | 683 | if (g_hHeap != NULL) 684 | { 685 | if (pTarget == MH_ALL_HOOKS) 686 | { 687 | status = EnableAllHooksLL(enable); 688 | } 689 | else 690 | { 691 | FROZEN_THREADS threads; 692 | UINT pos = FindHookEntry(pTarget); 693 | if (pos != INVALID_HOOK_POS) 694 | { 695 | if (g_hooks.pItems[pos].isEnabled != enable) 696 | { 697 | Freeze(&threads, pos, ACTION_ENABLE); 698 | 699 | status = EnableHookLL(pos, enable); 700 | 701 | Unfreeze(&threads); 702 | } 703 | else 704 | { 705 | status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; 706 | } 707 | } 708 | else 709 | { 710 | status = MH_ERROR_NOT_CREATED; 711 | } 712 | } 713 | } 714 | else 715 | { 716 | status = MH_ERROR_NOT_INITIALIZED; 717 | } 718 | 719 | LeaveSpinLock(); 720 | 721 | return status; 722 | } 723 | 724 | //------------------------------------------------------------------------- 725 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) 726 | { 727 | return EnableHook(pTarget, TRUE); 728 | } 729 | 730 | //------------------------------------------------------------------------- 731 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) 732 | { 733 | return EnableHook(pTarget, FALSE); 734 | } 735 | 736 | //------------------------------------------------------------------------- 737 | static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) 738 | { 739 | MH_STATUS status = MH_OK; 740 | 741 | EnterSpinLock(); 742 | 743 | if (g_hHeap != NULL) 744 | { 745 | if (pTarget == MH_ALL_HOOKS) 746 | { 747 | UINT i; 748 | for (i = 0; i < g_hooks.size; ++i) 749 | g_hooks.pItems[i].queueEnable = queueEnable; 750 | } 751 | else 752 | { 753 | UINT pos = FindHookEntry(pTarget); 754 | if (pos != INVALID_HOOK_POS) 755 | { 756 | g_hooks.pItems[pos].queueEnable = queueEnable; 757 | } 758 | else 759 | { 760 | status = MH_ERROR_NOT_CREATED; 761 | } 762 | } 763 | } 764 | else 765 | { 766 | status = MH_ERROR_NOT_INITIALIZED; 767 | } 768 | 769 | LeaveSpinLock(); 770 | 771 | return status; 772 | } 773 | 774 | //------------------------------------------------------------------------- 775 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) 776 | { 777 | return QueueHook(pTarget, TRUE); 778 | } 779 | 780 | //------------------------------------------------------------------------- 781 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) 782 | { 783 | return QueueHook(pTarget, FALSE); 784 | } 785 | 786 | //------------------------------------------------------------------------- 787 | MH_STATUS WINAPI MH_ApplyQueued(VOID) 788 | { 789 | MH_STATUS status = MH_OK; 790 | UINT i, first = INVALID_HOOK_POS; 791 | 792 | EnterSpinLock(); 793 | 794 | if (g_hHeap != NULL) 795 | { 796 | for (i = 0; i < g_hooks.size; ++i) 797 | { 798 | if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) 799 | { 800 | first = i; 801 | break; 802 | } 803 | } 804 | 805 | if (first != INVALID_HOOK_POS) 806 | { 807 | FROZEN_THREADS threads; 808 | Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); 809 | 810 | for (i = first; i < g_hooks.size; ++i) 811 | { 812 | PHOOK_ENTRY pHook = &g_hooks.pItems[i]; 813 | if (pHook->isEnabled != pHook->queueEnable) 814 | { 815 | status = EnableHookLL(i, pHook->queueEnable); 816 | if (status != MH_OK) 817 | break; 818 | } 819 | } 820 | 821 | Unfreeze(&threads); 822 | } 823 | } 824 | else 825 | { 826 | status = MH_ERROR_NOT_INITIALIZED; 827 | } 828 | 829 | LeaveSpinLock(); 830 | 831 | return status; 832 | } 833 | 834 | //------------------------------------------------------------------------- 835 | MH_STATUS WINAPI MH_CreateHookApiEx( 836 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, 837 | LPVOID *ppOriginal, LPVOID *ppTarget) 838 | { 839 | HMODULE hModule; 840 | LPVOID pTarget; 841 | 842 | hModule = GetModuleHandleW(pszModule); 843 | if (hModule == NULL) 844 | return MH_ERROR_MODULE_NOT_FOUND; 845 | 846 | pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); 847 | if (pTarget == NULL) 848 | return MH_ERROR_FUNCTION_NOT_FOUND; 849 | 850 | if(ppTarget != NULL) 851 | *ppTarget = pTarget; 852 | 853 | return MH_CreateHook(pTarget, pDetour, ppOriginal); 854 | } 855 | 856 | //------------------------------------------------------------------------- 857 | MH_STATUS WINAPI MH_CreateHookApi( 858 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) 859 | { 860 | return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); 861 | } 862 | 863 | //------------------------------------------------------------------------- 864 | const char * WINAPI MH_StatusToString(MH_STATUS status) 865 | { 866 | #define MH_ST2STR(x) \ 867 | case x: \ 868 | return #x; 869 | 870 | switch (status) { 871 | MH_ST2STR(MH_UNKNOWN) 872 | MH_ST2STR(MH_OK) 873 | MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) 874 | MH_ST2STR(MH_ERROR_NOT_INITIALIZED) 875 | MH_ST2STR(MH_ERROR_ALREADY_CREATED) 876 | MH_ST2STR(MH_ERROR_NOT_CREATED) 877 | MH_ST2STR(MH_ERROR_ENABLED) 878 | MH_ST2STR(MH_ERROR_DISABLED) 879 | MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) 880 | MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) 881 | MH_ST2STR(MH_ERROR_MEMORY_ALLOC) 882 | MH_ST2STR(MH_ERROR_MEMORY_PROTECT) 883 | MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) 884 | MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) 885 | } 886 | 887 | #undef MH_ST2STR 888 | 889 | return "(unknown)"; 890 | } 891 | --------------------------------------------------------------------------------