├── Cheat.h ├── Config.h ├── Core.hpp ├── Device.h ├── GlobalSetting.hpp ├── HSR-GC.sln ├── HSR-GC.vcxproj ├── HSR-GC.vcxproj.filters ├── HSR-GC.vcxproj.user ├── README.md ├── Utils.h ├── dependencies ├── Direct3D │ ├── Direct3D.cpp │ └── Direct3D.h ├── ImGui │ ├── backends │ │ ├── imgui_impl_dx11.cpp │ │ ├── imgui_impl_dx11.h │ │ ├── imgui_impl_dx9.cpp │ │ ├── imgui_impl_dx9.h │ │ ├── imgui_impl_win32.cpp │ │ └── imgui_impl_win32.h │ ├── imconfig.h │ ├── imgui.cpp │ ├── imgui.h │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_internal.h │ ├── imgui_tables.cpp │ ├── imgui_widgets.cpp │ ├── imstb_rectpack.h │ ├── imstb_textedit.h │ ├── imstb_truetype.h │ └── misc │ │ └── cpp │ │ ├── imgui_stdlib.cpp │ │ └── imgui_stdlib.h ├── Json │ └── json.hpp └── MinHook │ ├── MinHook.h │ ├── buffer.c │ ├── buffer.h │ ├── hde │ ├── hde32.c │ ├── hde32.h │ ├── hde64.c │ ├── hde64.h │ ├── pstdint.h │ ├── table32.h │ └── table64.h │ ├── hook.c │ ├── trampoline.c │ └── trampoline.h ├── device.cpp ├── globals.cpp └── main.cpp /Cheat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Config.h" 4 | 5 | namespace Cheat 6 | { 7 | namespace hooks { 8 | __int64(__fastcall* o_setcurrentphase)(__int64 a1, int a2, __int64 a3, char a4) = nullptr; 9 | char(__fastcall* o_get_isindialog)(__int64 a1) = nullptr; 10 | __int64(__fastcall* o_isautobattle)(__int64 a1); 11 | char(__fastcall* o_setautobattleflag)(__int64 a1, unsigned __int8 a2); 12 | 13 | struct HookData { 14 | std::string name; 15 | DWORD rva; 16 | 17 | void* hook; 18 | void* original; 19 | }; 20 | 21 | namespace game { 22 | 23 | int phase = 0; 24 | 25 | std::chrono::steady_clock::time_point last_call_time; 26 | 27 | /* because get_isindialog returns 0 in some dialogs (HSR developers, please fix this) */ 28 | bool get_is_in_dialog() { 29 | auto current_time = std::chrono::steady_clock::now(); 30 | auto time_since_last_call = std::chrono::duration_cast(current_time - last_call_time); 31 | return time_since_last_call.count() < 25; 32 | } 33 | 34 | const char* get_phase_in_text() { 35 | const char* phaseText = "Indefinite"; 36 | 37 | 38 | phase == 12 ? phaseText = "World" : 0; 39 | phase == 15 ? phaseText = "Battle" : 0; 40 | hooks::game::get_is_in_dialog() ? phaseText = "Dialogue" : 0; 41 | 42 | return phaseText; 43 | } 44 | 45 | } 46 | 47 | char __fastcall h_setautobattleflag(__int64 a1, unsigned __int8 a2) { 48 | return o_setautobattleflag(a1, a2); 49 | } 50 | 51 | __int64 __fastcall h_isautobattle(__int64 a1) { 52 | auto ret = o_isautobattle(a1); 53 | 54 | if (!ret && GlobalSetting::battle::force_battle) { 55 | h_setautobattleflag(a1, 1); 56 | } 57 | 58 | return ret; 59 | } 60 | 61 | /* (RPG.Client.GamePhaseManager.SetCurrentPhase) */ 62 | __int64 __fastcall h_setcurrentphase(__int64 a1, int a2, __int64 a3, char a4) { 63 | printf("currect phase: %i\n", a2); 64 | game::phase = a2; 65 | return o_setcurrentphase(a1, a2, a3, a4); 66 | } 67 | 68 | /* (RPG.Client.DialogueManager.get_IsInDialog) */ 69 | char __fastcall h_get_isindialog(__int64 a1) { 70 | //printf("called->get_isindialog()\n"); 71 | game::last_call_time = std::chrono::steady_clock::now(); 72 | return o_get_isindialog(a1);; 73 | } 74 | 75 | inline void Setup() { 76 | 77 | std::vector v_hooks = {}; 78 | 79 | if (GlobalSetting::ChinaVersion) { 80 | v_hooks.push_back({ "setcurrentphase", 0x5B9DFD0, &h_setcurrentphase, &o_setcurrentphase }); 81 | v_hooks.push_back({ "get_isindialog", 0x5ADD450, &h_get_isindialog, &o_get_isindialog }); 82 | v_hooks.push_back({ "isautobattle", 0x512F580, &h_isautobattle, &o_isautobattle }); 83 | v_hooks.push_back({ "setautobattleflag", 0x5130040,&h_setautobattleflag,&o_setautobattleflag }); 84 | } 85 | else { 86 | v_hooks.push_back({ "setcurrentphase", 0x5B9E130, &h_setcurrentphase, &o_setcurrentphase }); 87 | v_hooks.push_back({ "get_isindialog", 0x5ADD460, &h_get_isindialog, &o_get_isindialog }); 88 | v_hooks.push_back({ "isautobattle", 0x512F580, &h_isautobattle, &o_isautobattle }); 89 | v_hooks.push_back({ "setautobattleflag", 0x5130040,&h_setautobattleflag,&o_setautobattleflag }); 90 | } 91 | 92 | static auto CreateHook = [](LPVOID pTarget, LPVOID pDetour, LPVOID* ppOriginal)->bool 93 | { 94 | return MH_CreateHook(pTarget, pDetour, ppOriginal) == MH_OK && MH_EnableHook(pTarget) == MH_OK; 95 | }; 96 | 97 | uint64_t game_assembly = 0; 98 | 99 | while (!game_assembly) 100 | game_assembly = reinterpret_cast(GetModuleHandleA("gameassembly.dll")); 101 | 102 | for (auto& hook : v_hooks) { 103 | if (!CreateHook(reinterpret_cast(game_assembly + hook.rva), hook.hook, reinterpret_cast(hook.original))) { 104 | printf("[-] Failed to create/enable hook for %s\n", hook.name.c_str()); 105 | } 106 | } 107 | } 108 | } 109 | 110 | inline void Update() 111 | { 112 | if (!GlobalSetting::ShowMenu) 113 | return; 114 | 115 | static ImGuiWindowFlags classFinderWindowFlags = ImGuiWindowFlags_AlwaysAutoResize; 116 | 117 | ImGui::Begin("HSR-GC", 0, classFinderWindowFlags); 118 | 119 | ImGui::BeginTabBar("##tabs"); 120 | 121 | if (ImGui::BeginTabItem("World")) 122 | { 123 | ImGui::Checkbox("Speed Modifier", &GlobalSetting::world::speed_hack); 124 | 125 | if (GlobalSetting::world::speed_hack) { 126 | ImGui::SliderFloat("Global", &GlobalSetting::world::global_speed, 0.1f, 10.f, "%.1f"); 127 | ImGui::SliderFloat("Dialogue", &GlobalSetting::world::dialogue_speed, 0.1f, 10.f, "%.1f"); 128 | } 129 | 130 | ImGui::Checkbox("Peeking", &GlobalSetting::world::peeking); 131 | 132 | ImGui::Checkbox("Auto-Dialogue", &GlobalSetting::world::auto_dialogue); 133 | 134 | if (GlobalSetting::world::auto_dialogue) { 135 | ImGui::Text("also works on hotkey (CAPSLOCK)"); 136 | ImGui::Checkbox("Mouse Mode", &GlobalSetting::world::mouse_mode); 137 | } 138 | 139 | ImGui::Checkbox("Invisibility", &GlobalSetting::world::invisibility); 140 | 141 | ImGui::EndTabItem(); 142 | } 143 | 144 | if (ImGui::BeginTabItem("Battle")) 145 | { 146 | ImGui::Checkbox("Speed Modifier", &GlobalSetting::battle::speed_hack); 147 | 148 | if (GlobalSetting::battle::speed_hack) { 149 | 150 | ImGui::SliderFloat("Battle", &GlobalSetting::battle::battle_speed, 0.1f, 100.f, "%.1f"); 151 | 152 | } 153 | 154 | //ImGui::Checkbox("Auto-Battle Unlock", &GlobalSetting::battle::auto_battle_unlock); 155 | 156 | ImGui::Checkbox("Force Auto-Battle", &GlobalSetting::battle::force_battle); 157 | 158 | if (GlobalSetting::battle::force_battle) { 159 | ImGui::Text("if you enabled it in battle then you need to do some action to make it work"); 160 | } 161 | 162 | ImGui::EndTabItem(); 163 | } 164 | 165 | if (ImGui::BeginTabItem("Other")) 166 | { 167 | ImGui::Checkbox("FPS Unlock", &GlobalSetting::other::fps_unlock); 168 | 169 | if (GlobalSetting::other::fps_unlock) { 170 | ImGui::InputInt("FPS", &GlobalSetting::other::fps); 171 | } 172 | 173 | ImGui::EndTabItem(); 174 | } 175 | 176 | if (ImGui::BeginTabItem("Debug")) 177 | { 178 | 179 | ImGui::Text("Phase: %s", hooks::game::get_phase_in_text()); 180 | ImGui::Text("FPS: %.1f", ImGui::GetIO().Framerate); 181 | 182 | ImGui::EndTabItem(); 183 | } 184 | 185 | if (ImGui::BeginTabItem("Settings")) 186 | { 187 | static bool pinWindow = false; 188 | 189 | if (ImGui::Checkbox("Pin Window", &pinWindow)) 190 | { 191 | if (pinWindow) 192 | { 193 | classFinderWindowFlags |= ImGuiWindowFlags_NoMove; 194 | classFinderWindowFlags |= ImGuiWindowFlags_NoResize; 195 | } 196 | else 197 | { 198 | classFinderWindowFlags &= ~ImGuiWindowFlags_NoMove; 199 | classFinderWindowFlags &= ~ImGuiWindowFlags_NoResize; 200 | } 201 | } 202 | 203 | ImGui::SameLine(); 204 | 205 | if (ImGui::Button("Reset Position")) 206 | ImGui::SetWindowPos(ImVec2(0, 0)); 207 | 208 | ImGui::SameLine(); 209 | 210 | if (ImGui::Button("Unload")) 211 | GlobalSetting::Unload = true; 212 | 213 | if (ImGui::Button("Save Config")) { 214 | Config::SaveConfig(); 215 | } 216 | 217 | ImGui::EndTabItem(); 218 | } 219 | 220 | ImGui::EndTabBar(); 221 | ImGui::End(); 222 | } 223 | 224 | 225 | 226 | inline void Dialogue() { 227 | HWND target_window = 0; 228 | 229 | while (!target_window) target_window = FindWindowA("UnityWndClass", nullptr); 230 | 231 | while (true) { 232 | if (hooks::game::phase != 12) { 233 | Sleep(500); 234 | continue; 235 | } 236 | 237 | if (GlobalSetting::world::auto_dialogue && !GlobalSetting::ShowMenu) { 238 | 239 | if (hooks::game::get_is_in_dialog() || GetAsyncKeyState(VK_CAPITAL)) { 240 | 241 | Sleep(16); 242 | 243 | if (GetForegroundWindow() == target_window) { 244 | if (!GlobalSetting::world::mouse_mode) { 245 | keybd_event(VK_SPACE, 0, 0, 0); 246 | Sleep(20); 247 | keybd_event(VK_SPACE, 0, KEYEVENTF_KEYUP, 0); 248 | } 249 | else { 250 | POINT cursor_pos; 251 | GetCursorPos(&cursor_pos); 252 | mouse_event(MOUSEEVENTF_LEFTDOWN, cursor_pos.x, cursor_pos.y, 0, 0); 253 | Sleep(10); 254 | mouse_event(MOUSEEVENTF_LEFTUP, cursor_pos.x, cursor_pos.y, 0, 0); 255 | } 256 | } 257 | } 258 | } 259 | else { 260 | Sleep(100); 261 | } 262 | } 263 | } 264 | 265 | inline void UpdateSpeed(const float speed, uint64_t game_assembly, uint64_t unity_player, const bool is_battle) { 266 | 267 | if (is_battle) { 268 | Utils::Write(Utils::Read<__int64>(Utils::Read<__int64>(game_assembly + 0x8CAA6A0) + 0xC0) + 0x1DC, speed); 269 | Utils::Write(Utils::Read<__int64>(unity_player + 0x1D21D78) + 0xFC, 1.f); 270 | } 271 | else { 272 | Utils::Write(Utils::Read<__int64>(Utils::Read<__int64>(game_assembly + 0x8CAA6A0) + 0xC0) + 0x1DC, 1.f); 273 | Utils::Write(Utils::Read<__int64>(unity_player + 0x1D21D78) + 0xFC, speed); 274 | } 275 | } 276 | 277 | inline void UpdateWorld(uint64_t game_assembly, uint64_t unity_player) { 278 | if (hooks::game::phase != 12) { 279 | return; 280 | } 281 | 282 | float speed = 1.f; 283 | 284 | if (GlobalSetting::world::speed_hack) { 285 | speed = hooks::game::get_is_in_dialog() || GetAsyncKeyState(VK_CAPITAL) ? GlobalSetting::world::dialogue_speed : GlobalSetting::world::global_speed; 286 | } 287 | 288 | UpdateSpeed(speed, game_assembly, unity_player, false); 289 | 290 | Utils::Write(game_assembly + 0x51292C0, GlobalSetting::world::peeking ? 0xC3 : 0x40); 291 | Utils::Write(game_assembly + 0x5800F40, GlobalSetting::world::invisibility ? 0xC3 : 0x40); 292 | } 293 | 294 | inline void UpdateBattle(uint64_t game_assembly, uint64_t unity_player) { 295 | if (hooks::game::phase != 15) { 296 | return; 297 | } 298 | 299 | UpdateSpeed(GlobalSetting::battle::speed_hack ? GlobalSetting::battle::battle_speed : 1.f, game_assembly, unity_player, true); 300 | 301 | Utils::Write(game_assembly + 0x5DA5F20, GlobalSetting::battle::auto_battle_unlock ? 0x90C3C031 : 0x83485340); 302 | } 303 | 304 | inline void UpdateOther(uint64_t unity_player) { 305 | if (GlobalSetting::other::fps_unlock) { 306 | if (GlobalSetting::other::fps > 59) { 307 | Utils::Write(unity_player + 0x1C4E000, GlobalSetting::other::fps); 308 | } 309 | } 310 | else { 311 | Utils::Write(unity_player + 0x1C4E000, 60); 312 | } 313 | } 314 | 315 | inline void Main() { 316 | uint64_t game_assembly = 0, unity_player = 0; 317 | 318 | while (!game_assembly && !unity_player) { 319 | game_assembly = reinterpret_cast(GetModuleHandleA("gameassembly.dll")); 320 | unity_player = reinterpret_cast(GetModuleHandleA("unityplayer.dll")); 321 | } 322 | 323 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Dialogue, 0, 0, 0); 324 | 325 | while (true) { 326 | UpdateWorld(game_assembly, unity_player); 327 | UpdateBattle(game_assembly, unity_player); 328 | UpdateOther(unity_player); 329 | 330 | Sleep(500); 331 | } 332 | } 333 | 334 | inline void Setup() 335 | { 336 | hooks::Setup(); 337 | 338 | auto hook = ImGuiContextHook(); 339 | hook.Callback = (ImGuiContextHookCallback)Update; 340 | hook.Type = ImGuiContextHookType_NewFramePost; 341 | ImGui::AddContextHook(ImGui::GetCurrentContext(), &hook); 342 | } 343 | } -------------------------------------------------------------------------------- /Config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "GlobalSetting.hpp" 7 | #include "dependencies/Json/json.hpp" 8 | 9 | using json = nlohmann::json; 10 | 11 | namespace Config 12 | { 13 | 14 | std::string GetModulePath(HMODULE hModule) 15 | { 16 | char path[MAX_PATH] = {}; 17 | GetModuleFileNameA(hModule, path, MAX_PATH); 18 | 19 | return std::filesystem::path(path).parent_path().string(); 20 | } 21 | 22 | static std::filesystem::path file_path; 23 | 24 | 25 | struct ConfigPreset 26 | { 27 | bool EnableWorldSpeedHack = false; 28 | float GlobalSpeed = 1.f; 29 | float DialogueSpeed = 1.f; 30 | 31 | bool DumpEnemies = false; 32 | bool Peeking = false; 33 | bool AutoDialogue = false; 34 | bool MouseMode = false; 35 | bool Invisibility = false; 36 | 37 | bool EnableBattleSpeedHack = false; 38 | float BattleSpeed = 1.f; 39 | bool AutoBattleUnlock = false; 40 | bool ForceBattle = false; 41 | 42 | bool FpsUnlock = false; 43 | int Fps = 60; 44 | }; 45 | 46 | NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( 47 | ConfigPreset, 48 | EnableWorldSpeedHack, 49 | GlobalSpeed, 50 | DialogueSpeed, 51 | DumpEnemies, 52 | Peeking, 53 | AutoDialogue, 54 | MouseMode, 55 | Invisibility, 56 | EnableBattleSpeedHack, 57 | BattleSpeed, 58 | AutoBattleUnlock, 59 | ForceBattle, 60 | FpsUnlock, 61 | Fps 62 | ) 63 | 64 | bool LoadConfig(HMODULE hModule) 65 | { 66 | json j; 67 | 68 | file_path = GetModulePath(hModule) + "\\config.json"; 69 | std::ifstream f(file_path, std::ifstream::binary); 70 | if (f.fail()) return false; 71 | 72 | f >> j; 73 | 74 | GlobalSetting::world::speed_hack = j.get().EnableWorldSpeedHack; 75 | GlobalSetting::world::global_speed = j.get().GlobalSpeed; 76 | GlobalSetting::world::dialogue_speed = j.get().DialogueSpeed; 77 | 78 | GlobalSetting::world::dump_enemys = j.get().DumpEnemies; 79 | GlobalSetting::world::peeking = j.get().Peeking; 80 | GlobalSetting::world::auto_dialogue = j.get().AutoDialogue; 81 | GlobalSetting::world::mouse_mode = j.get().MouseMode; 82 | GlobalSetting::world::invisibility = j.get().Invisibility; 83 | 84 | GlobalSetting::battle::speed_hack = j.get().EnableBattleSpeedHack; 85 | GlobalSetting::battle::battle_speed = j.get().BattleSpeed; 86 | GlobalSetting::battle::auto_battle_unlock = j.get().AutoBattleUnlock; 87 | GlobalSetting::battle::force_battle = j.get().ForceBattle; 88 | 89 | GlobalSetting::other::fps_unlock = j.get().FpsUnlock; 90 | GlobalSetting::other::fps = j.get().Fps; 91 | 92 | return true; 93 | } 94 | 95 | void SaveConfig() 96 | { 97 | const json j = ConfigPreset 98 | { 99 | GlobalSetting::world::speed_hack, 100 | GlobalSetting::world::global_speed, 101 | GlobalSetting::world::dialogue_speed, 102 | 103 | GlobalSetting::world::dump_enemys, 104 | GlobalSetting::world::peeking, 105 | GlobalSetting::world::auto_dialogue, 106 | GlobalSetting::world::mouse_mode, 107 | GlobalSetting::world::invisibility, 108 | 109 | GlobalSetting::battle::speed_hack, 110 | GlobalSetting::battle::battle_speed, 111 | GlobalSetting::battle::auto_battle_unlock, 112 | GlobalSetting::battle::force_battle, 113 | 114 | GlobalSetting::other::fps_unlock, 115 | GlobalSetting::other::fps 116 | }; 117 | 118 | std::ofstream o(file_path); 119 | o << std::setw(4) << j << std::endl; 120 | } 121 | } 122 | 123 | -------------------------------------------------------------------------------- /Core.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "Dependencies/Direct3D/Direct3D.h" 20 | 21 | //#include "Dependencies/Json/json.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "GlobalSetting.hpp" 30 | 31 | #include "Dependencies/MinHook/MinHook.h" 32 | 33 | inline ID3D11Device* pDevice = NULL; 34 | inline ID3D11DeviceContext* pContext = NULL; 35 | inline ID3D11RenderTargetView* mainRenderTargetView = NULL; 36 | inline WNDPROC oWndProc = NULL; 37 | inline HWND hWnd = NULL; 38 | 39 | #include "Utils.h" 40 | #include "Cheat.h" 41 | #include "Device.h" 42 | -------------------------------------------------------------------------------- /Device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND window, UINT message, WPARAM wideParam, LPARAM longParam); 4 | 5 | namespace Device 6 | { 7 | using PresentFn = HRESULT(__stdcall*) (IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags); 8 | using ResizeBuffersFn = HRESULT(__stdcall*) (IDXGISwapChain* pSwapChain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); 9 | inline PresentFn oPresent = nullptr; 10 | inline ResizeBuffersFn oResizeBuffers = nullptr; 11 | 12 | inline LRESULT WINAPI WndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 13 | { 14 | if (GlobalSetting::Unload) 15 | return CallWindowProc(oWndProc, hWnd, uMsg, wParam, lParam); 16 | 17 | if (uMsg == WM_KEYUP && wParam == VK_F1) 18 | { 19 | GlobalSetting::ShowMenu = !GlobalSetting::ShowMenu; 20 | } 21 | ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam); 22 | if (!GlobalSetting::ShowMenu) 23 | return CallWindowProc(oWndProc, hWnd, uMsg, wParam, lParam); 24 | return true; 25 | } 26 | 27 | inline HRESULT Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) 28 | { 29 | if (GlobalSetting::Unload) 30 | return oPresent(pSwapChain, SyncInterval, Flags); 31 | static auto bMakeOnce = [&]()->bool 32 | { 33 | if (FAILED(pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&pDevice))) 34 | { 35 | return false; 36 | } 37 | pDevice->GetImmediateContext(&pContext); 38 | DXGI_SWAP_CHAIN_DESC sd; 39 | pSwapChain->GetDesc(&sd); 40 | hWnd = sd.OutputWindow; 41 | ID3D11Texture2D* pBackBuffer = NULL; 42 | pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); 43 | D3D11_RENDER_TARGET_VIEW_DESC desc = {}; 44 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 45 | desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; 46 | pDevice->CreateRenderTargetView(pBackBuffer, &desc, &mainRenderTargetView); 47 | pBackBuffer->Release(); 48 | oWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc); 49 | ImGui::CreateContext(); 50 | ImGui::GetIO().IniFilename = nullptr; 51 | ImGui::GetIO().LogFilename = nullptr; 52 | ImGui::GetStyle().FrameRounding = 3.0f; 53 | ImGui::GetStyle().WindowRounding = 2.0f; 54 | ImGui::GetStyle().GrabRounding = 2.0f; 55 | ImGui::GetStyle().WindowRounding = 3.0f; 56 | ImGui::GetStyle().WindowTitleAlign = { 0.5f ,0.5f }; 57 | { 58 | ImGuiStyle* style = &ImGui::GetStyle(); 59 | ImVec4* colors = style->Colors; 60 | colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 61 | colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 62 | colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); 63 | colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 64 | colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); 65 | colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); 66 | colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 67 | colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.54f); 68 | colors[ImGuiCol_FrameBgHovered] = ImVec4(0.28f, 0.28f, 0.28f, 0.40f); 69 | colors[ImGuiCol_FrameBgActive] = ImVec4(0.17f, 0.17f, 0.17f, 0.67f); 70 | colors[ImGuiCol_TitleBg] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); 71 | colors[ImGuiCol_TitleBgActive] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); 72 | colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.22f, 0.22f, 0.22f, 0.51f); 73 | colors[ImGuiCol_MenuBarBg] = ImVec4(0.26f, 0.26f, 0.26f, 1.00f); 74 | colors[ImGuiCol_ScrollbarBg] = ImVec4(0.14f, 0.14f, 0.14f, 0.53f); 75 | colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); 76 | colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); 77 | colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); 78 | colors[ImGuiCol_CheckMark] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f); 79 | colors[ImGuiCol_SliderGrab] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f); 80 | colors[ImGuiCol_SliderGrabActive] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f); 81 | colors[ImGuiCol_Button] = ImVec4(0.44f, 0.44f, 0.44f, 0.40f); 82 | colors[ImGuiCol_ButtonHovered] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); 83 | colors[ImGuiCol_ButtonActive] = ImVec4(0.27f, 0.27f, 0.27f, 1.00f); 84 | colors[ImGuiCol_Header] = ImVec4(0.46f, 0.46f, 0.46f, 0.31f); 85 | colors[ImGuiCol_HeaderHovered] = ImVec4(0.32f, 0.32f, 0.32f, 0.80f); 86 | colors[ImGuiCol_HeaderActive] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); 87 | colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; 88 | colors[ImGuiCol_SeparatorHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.78f); 89 | colors[ImGuiCol_SeparatorActive] = ImVec4(0.71f, 0.71f, 0.71f, 1.00f); 90 | colors[ImGuiCol_ResizeGrip] = ImVec4(0.71f, 0.71f, 0.71f, 0.20f); 91 | colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.56f, 0.56f, 0.56f, 0.67f); 92 | colors[ImGuiCol_ResizeGripActive] = ImVec4(0.43f, 0.43f, 0.43f, 0.95f); 93 | colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.40f); 94 | colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; 95 | colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.80f); 96 | colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); 97 | colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); 98 | colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); 99 | colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.92f, 0.92f, 0.92f, 1.00f); 100 | colors[ImGuiCol_PlotHistogram] = ImVec4(0.43f, 0.43f, 0.43f, 1.00f); 101 | colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); 102 | colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); 103 | colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); 104 | colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); 105 | colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 106 | colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); 107 | colors[ImGuiCol_TextSelectedBg] = ImVec4(0.36f, 0.36f, 0.36f, 0.35f); 108 | colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 109 | colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.26f, 0.26f, 1.00f); 110 | colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 111 | colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); 112 | colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); 113 | } 114 | ImGui_ImplWin32_Init(hWnd); 115 | ImGui_ImplDX11_Init(pDevice, pContext); 116 | ImGui::GetIO().Fonts->AddFontFromFileTTF("c:\\windows\\fonts\\msyh.ttc", 16, NULL, ImGui::GetIO().Fonts->GetGlyphRangesChineseFull()); 117 | Cheat::Setup(); 118 | return true; 119 | } (); 120 | ImGui_ImplDX11_NewFrame(); 121 | ImGui_ImplWin32_NewFrame(); 122 | ImGui::NewFrame(); 123 | ImGui::Render(); 124 | pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL); 125 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 126 | return oPresent(pSwapChain, SyncInterval, Flags); 127 | } 128 | 129 | inline HRESULT ResizeBuffers(IDXGISwapChain* pSwapChain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) 130 | { 131 | if (GlobalSetting::Unload) 132 | return oResizeBuffers(pSwapChain, BufferCount, Width, Height, NewFormat, SwapChainFlags); 133 | if (mainRenderTargetView) 134 | { 135 | pContext->OMSetRenderTargets(0, 0, 0); 136 | mainRenderTargetView->Release(); 137 | mainRenderTargetView = NULL; 138 | } 139 | HRESULT hr = oResizeBuffers(pSwapChain, BufferCount, Width, Height, NewFormat, SwapChainFlags); 140 | ID3D11Texture2D* pBuffer = NULL; 141 | pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBuffer); 142 | pDevice->CreateRenderTargetView(pBuffer, nullptr, &mainRenderTargetView); 143 | pBuffer->Release(); 144 | pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL); 145 | D3D11_VIEWPORT vp; 146 | vp.Width = (FLOAT)Width; 147 | vp.Height = (FLOAT)Height; 148 | vp.MinDepth = 0.0f; 149 | vp.MaxDepth = 1.0f; 150 | vp.TopLeftX = 0; 151 | vp.TopLeftY = 0; 152 | pContext->RSSetViewports(1, &vp); 153 | return hr; 154 | } 155 | 156 | inline bool Setup() 157 | { 158 | static auto CreateHook = [](LPVOID pTarget, LPVOID pDetour, LPVOID* ppOriginal)->bool 159 | { 160 | return MH_CreateHook(pTarget, pDetour, ppOriginal) == MH_OK && MH_EnableHook(pTarget) == MH_OK; 161 | }; 162 | if (!CreateHook(Direct3D.Present, Device::Present, reinterpret_cast(&Device::oPresent))) 163 | return false; 164 | if (!CreateHook(Direct3D.ResizeBuffers, Device::ResizeBuffers, reinterpret_cast(&Device::oResizeBuffers))) 165 | return false; 166 | return true; 167 | } 168 | } -------------------------------------------------------------------------------- /GlobalSetting.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | namespace GlobalSetting 5 | { 6 | inline bool ShowMenu = true; 7 | inline bool Unload = false; 8 | inline bool ChinaVersion = false; 9 | 10 | namespace world 11 | { 12 | inline bool speed_hack = false; 13 | inline float global_speed = 1.f; 14 | inline float dialogue_speed = 1.f; 15 | 16 | inline bool dump_enemys = false; 17 | inline bool peeking = false; 18 | inline bool auto_dialogue = false; 19 | inline bool mouse_mode = false; 20 | inline bool invisibility = false; 21 | } 22 | 23 | namespace battle 24 | { 25 | inline bool speed_hack = false; 26 | inline float battle_speed = 1.f; 27 | 28 | inline bool auto_battle_unlock = false; 29 | bool force_battle = false; 30 | } 31 | 32 | namespace other 33 | { 34 | inline bool fps_unlock = false; 35 | inline int fps = 60; 36 | } 37 | } -------------------------------------------------------------------------------- /HSR-GC.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33530.505 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HSR-GC", "HSR-GC.vcxproj", "{35E08305-6E14-4A20-9B5A-8AEC0DD760CF}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x64 = Release|x64 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {35E08305-6E14-4A20-9B5A-8AEC0DD760CF}.Release|x64.ActiveCfg = Release|x64 14 | {35E08305-6E14-4A20-9B5A-8AEC0DD760CF}.Release|x64.Build.0 = Release|x64 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | SolutionGuid = {AAB7480C-255D-491D-B373-FBA30B1D3647} 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /HSR-GC.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Release 6 | x64 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 16.0 56 | Win32Proj 57 | {35e08305-6e14-4a20-9b5a-8aec0dd760cf} 58 | HSRGC 59 | 10.0 60 | 61 | 62 | 63 | DynamicLibrary 64 | false 65 | v143 66 | true 67 | Unicode 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | Level3 81 | true 82 | true 83 | true 84 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 85 | true 86 | $(SolutionDir)\dependencies\imgui;$(SolutionDir)\dependencies;%(AdditionalIncludeDirectories) 87 | stdcpp17 88 | stdc17 89 | 90 | 91 | Console 92 | true 93 | true 94 | true 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /HSR-GC.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {718a4501-3e3c-4c56-b0ec-0fe27cf30444} 6 | 7 | 8 | {8b07ef3d-cecb-4e64-a2e9-05b1d170f712} 9 | 10 | 11 | {1bf5e9fd-c57b-4426-9785-67f6ec96b8cb} 12 | 13 | 14 | {501cbef9-e77a-41f3-9e4a-d7f36968dc1d} 15 | 16 | 17 | {d6b87060-83e0-4379-bc59-247f2ef506b3} 18 | 19 | 20 | {63b05929-302e-4db9-a2bf-389bb9a6c6fd} 21 | 22 | 23 | {70eb5e18-b93c-490e-aa5f-ebad0731ec71} 24 | 25 | 26 | 27 | 28 | core\dependencies\Direct3D 29 | 30 | 31 | core\dependencies\ImGui 32 | 33 | 34 | core\dependencies\ImGui 35 | 36 | 37 | core\dependencies\ImGui 38 | 39 | 40 | core\dependencies\ImGui 41 | 42 | 43 | core\dependencies\ImGui 44 | 45 | 46 | core\dependencies\ImGui 47 | 48 | 49 | core\dependencies\ImGui 50 | 51 | 52 | core\dependencies\ImGui 53 | 54 | 55 | core\dependencies\ImGui 56 | 57 | 58 | core\dependencies\MinHook 59 | 60 | 61 | core\dependencies\MinHook 62 | 63 | 64 | core\dependencies\MinHook 65 | 66 | 67 | core\dependencies\MinHook\hde 68 | 69 | 70 | core\dependencies\MinHook\hde 71 | 72 | 73 | main 74 | 75 | 76 | 77 | 78 | core\dependencies\Direct3D 79 | 80 | 81 | core\dependencies\ImGui 82 | 83 | 84 | core\dependencies\ImGui 85 | 86 | 87 | core\dependencies\ImGui 88 | 89 | 90 | core\dependencies\ImGui 91 | 92 | 93 | core\dependencies\ImGui 94 | 95 | 96 | core\dependencies\ImGui 97 | 98 | 99 | core\dependencies\ImGui 100 | 101 | 102 | core\dependencies\ImGui 103 | 104 | 105 | core\dependencies\ImGui 106 | 107 | 108 | core\dependencies\ImGui 109 | 110 | 111 | core\dependencies\MinHook 112 | 113 | 114 | core\dependencies\MinHook 115 | 116 | 117 | core\dependencies\MinHook 118 | 119 | 120 | core\dependencies\MinHook\hde 121 | 122 | 123 | core\dependencies\MinHook\hde 124 | 125 | 126 | core\dependencies\MinHook\hde 127 | 128 | 129 | core\dependencies\MinHook\hde 130 | 131 | 132 | core\dependencies\MinHook\hde 133 | 134 | 135 | core 136 | 137 | 138 | core 139 | 140 | 141 | main 142 | 143 | 144 | main 145 | 146 | 147 | main 148 | 149 | 150 | main 151 | 152 | 153 | -------------------------------------------------------------------------------- /HSR-GC.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Honkai: Star Rail Simple Game Cheat: 2 | This repository provides code for a simple cheat for the game Honkai Star Rail. For informational purposes only. Use at your own risk. 3 | 4 | # Note 5 | The original Repository 6 | https://github.com/Z4ee/StarRail-S-GC/ 7 | I want to fork but it is now archived 8 | 9 | # Instruction: 10 | 11 | Step 1: Download the code 12 | 13 | ![image](https://user-images.githubusercontent.com/113752393/236731146-757deddc-a5d7-4d13-a3b9-235b23fe83bd.png) 14 | 15 | Step 2: Unzip the archive. 16 | 17 | Step 3: Compile code 18 | 19 | Step 5: Run compiled HSR-Launcher.exe 20 | 21 | Step 6: Select StarRail.exe. 22 | 23 | ![image](https://user-images.githubusercontent.com/113752393/236632851-b1e6cfa0-7854-477d-b486-730300b1ee9a.png) 24 | 25 | Step 7: Done! 26 | 27 | ![image](https://user-images.githubusercontent.com/113752393/236632880-84855a81-098e-4843-a4e5-877b78b8b110.png) 28 | 29 | Open/Close menu on F1 30 | 31 | Auto-Dialogue on CAPSLOCK (if not automatically detected) 32 | -------------------------------------------------------------------------------- /Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Utils { 4 | template 5 | void Write(__int64 address, T value) { 6 | DWORD oldProtection; 7 | VirtualProtect(reinterpret_cast(address), sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtection); 8 | *reinterpret_cast(address) = value; 9 | VirtualProtect(reinterpret_cast(address), sizeof(T), oldProtection, &oldProtection); 10 | } 11 | 12 | template 13 | K Read(__int64 address) { 14 | return *reinterpret_cast(address); 15 | } 16 | 17 | uint32_t CalculateChecksum(const uint8_t* data, size_t length) { 18 | uint32_t checksum = 0; 19 | for (size_t i = 0; i < length; i++) { 20 | checksum ^= data[i]; 21 | checksum += data[i]; 22 | } 23 | return checksum; 24 | } 25 | 26 | uint32_t GetTextSectionChecksum(uint64_t hModule) { 27 | PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; 28 | if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 29 | return 0; 30 | } 31 | 32 | PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((uint8_t*)hModule + dosHeader->e_lfanew); 33 | if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) { 34 | return 0; 35 | } 36 | 37 | PIMAGE_SECTION_HEADER sectionHeader = IMAGE_FIRST_SECTION(ntHeaders); 38 | for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++sectionHeader) { 39 | char sectionName[IMAGE_SIZEOF_SHORT_NAME + 1] = { 0 }; 40 | memcpy(sectionName, sectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME); 41 | 42 | if (strcmp(sectionName, ".text") == 0) { 43 | uint8_t* sectionData = (uint8_t*)hModule + sectionHeader->VirtualAddress; 44 | return CalculateChecksum(sectionData, sectionHeader->Misc.VirtualSize); 45 | } 46 | } 47 | 48 | return 0; 49 | } 50 | } -------------------------------------------------------------------------------- /dependencies/Direct3D/Direct3D.cpp: -------------------------------------------------------------------------------- 1 | #include "Direct3D.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | bool CDirect3D::Initialization() 15 | { 16 | WNDCLASSEX windowClass; 17 | windowClass.cbSize = sizeof(WNDCLASSEX); 18 | windowClass.style = CS_HREDRAW | CS_VREDRAW; 19 | windowClass.lpfnWndProc = DefWindowProc; 20 | windowClass.cbClsExtra = 0; 21 | windowClass.cbWndExtra = 0; 22 | windowClass.hInstance = GetModuleHandle(NULL); 23 | windowClass.hIcon = NULL; 24 | windowClass.hCursor = NULL; 25 | windowClass.hbrBackground = NULL; 26 | windowClass.lpszMenuName = NULL; 27 | windowClass.lpszClassName = L"DirectX"; 28 | windowClass.hIconSm = NULL; 29 | 30 | ::RegisterClassEx(&windowClass); 31 | 32 | HWND window = ::CreateWindow(windowClass.lpszClassName, L"DirectX", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, windowClass.hInstance, NULL); 33 | 34 | HMODULE libD3D11 = ::GetModuleHandle(L"d3d11.dll"); 35 | if (!libD3D11) 36 | { 37 | ::DestroyWindow(window); 38 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 39 | return false; 40 | } 41 | 42 | void* D3D11CreateDeviceAndSwapChain = ::GetProcAddress(libD3D11, "D3D11CreateDeviceAndSwapChain"); 43 | if (!D3D11CreateDeviceAndSwapChain) 44 | { 45 | ::DestroyWindow(window); 46 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 47 | return false; 48 | } 49 | 50 | D3D_FEATURE_LEVEL featureLevel; 51 | const D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0 }; 52 | 53 | DXGI_RATIONAL refreshRate; 54 | refreshRate.Numerator = 60; 55 | refreshRate.Denominator = 1; 56 | 57 | DXGI_MODE_DESC bufferDesc; 58 | bufferDesc.Width = 100; 59 | bufferDesc.Height = 100; 60 | bufferDesc.RefreshRate = refreshRate; 61 | bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 62 | bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 63 | bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 64 | 65 | DXGI_SAMPLE_DESC sampleDesc; 66 | sampleDesc.Count = 1; 67 | sampleDesc.Quality = 0; 68 | 69 | DXGI_SWAP_CHAIN_DESC swapChainDesc; 70 | swapChainDesc.BufferDesc = bufferDesc; 71 | swapChainDesc.SampleDesc = sampleDesc; 72 | swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 73 | swapChainDesc.BufferCount = 1; 74 | swapChainDesc.OutputWindow = window; 75 | swapChainDesc.Windowed = 1; 76 | swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 77 | swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 78 | 79 | IDXGISwapChain* swapChain; 80 | ID3D11Device* device; 81 | ID3D11DeviceContext* context; 82 | 83 | if (((long(__stdcall*)( 84 | IDXGIAdapter*, 85 | D3D_DRIVER_TYPE, 86 | HMODULE, 87 | UINT, 88 | const D3D_FEATURE_LEVEL*, 89 | UINT, 90 | UINT, 91 | const DXGI_SWAP_CHAIN_DESC*, 92 | IDXGISwapChain**, 93 | ID3D11Device**, 94 | D3D_FEATURE_LEVEL*, 95 | ID3D11DeviceContext**))(D3D11CreateDeviceAndSwapChain))(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 2, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, &featureLevel, &context) < 0) 96 | { 97 | ::DestroyWindow(window); 98 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 99 | return false; 100 | } 101 | 102 | uint64_t* methodsTable = (uint64_t*)::calloc(205, sizeof(uint64_t)); 103 | ::memcpy(methodsTable, *(uint64_t**)swapChain, 18 * sizeof(uint64_t)); 104 | ::memcpy(methodsTable + 18, *(uint64_t**)device, 43 * sizeof(uint64_t)); 105 | ::memcpy(methodsTable + 18 + 43, *(uint64_t**)context, 144 * sizeof(uint64_t)); 106 | 107 | swapChain->Release(); 108 | swapChain = NULL; 109 | 110 | device->Release(); 111 | device = NULL; 112 | 113 | context->Release(); 114 | context = NULL; 115 | 116 | ::DestroyWindow(window); 117 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 118 | 119 | Present = (void*)(methodsTable)[8]; 120 | ResizeBuffers = (void*)(methodsTable)[13]; 121 | return true; 122 | } 123 | 124 | void CDirect3D::Destroy() 125 | { 126 | ::free(Present); 127 | ::free(ResizeBuffers); 128 | } -------------------------------------------------------------------------------- /dependencies/Direct3D/Direct3D.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | class CDirect3D 7 | { 8 | public: 9 | void* Present; 10 | void* ResizeBuffers; 11 | bool Initialization(); 12 | void Destroy(); 13 | }; 14 | 15 | inline CDirect3D Direct3D; 16 | 17 | -------------------------------------------------------------------------------- /dependencies/ImGui/backends/imgui_impl_dx11.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for DirectX11 2 | // This needs to be used along with a Platform Backend (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. 7 | 8 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 9 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 10 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 11 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 12 | 13 | #pragma once 14 | #include // IMGUI_IMPL_API 15 | 16 | struct ID3D11Device; 17 | struct ID3D11DeviceContext; 18 | 19 | IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); 20 | IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown(); 21 | IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); 22 | IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); 23 | 24 | // Use if you want to reset your rendering device without losing Dear ImGui state. 25 | IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); 26 | IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); 27 | -------------------------------------------------------------------------------- /dependencies/ImGui/backends/imgui_impl_dx9.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for DirectX9 2 | // This needs to be used along with a Platform Backend (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. 7 | 8 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 9 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 10 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 11 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 12 | 13 | // CHANGELOG 14 | // (minor and older changes stripped away, please see git history for details) 15 | // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. 16 | // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). 17 | // 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1. 18 | // 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) 19 | // 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states. 20 | // 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857). 21 | // 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file. 22 | // 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer. 23 | // 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. 24 | // 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. 25 | // 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). 26 | // 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288. 27 | // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. 28 | // 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example. 29 | // 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. 30 | // 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud. 31 | // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself. 32 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. 33 | 34 | #include "imgui.h" 35 | #include "imgui_impl_dx9.h" 36 | 37 | // DirectX 38 | #include 39 | 40 | // DirectX data 41 | struct ImGui_ImplDX9_Data 42 | { 43 | LPDIRECT3DDEVICE9 pd3dDevice; 44 | LPDIRECT3DVERTEXBUFFER9 pVB; 45 | LPDIRECT3DINDEXBUFFER9 pIB; 46 | LPDIRECT3DTEXTURE9 FontTexture; 47 | int VertexBufferSize; 48 | int IndexBufferSize; 49 | 50 | ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } 51 | }; 52 | 53 | struct CUSTOMVERTEX 54 | { 55 | float pos[3]; 56 | D3DCOLOR col; 57 | float uv[2]; 58 | }; 59 | #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) 60 | 61 | #ifdef IMGUI_USE_BGRA_PACKED_COLOR 62 | #define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL) 63 | #else 64 | #define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16)) 65 | #endif 66 | 67 | // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts 68 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. 69 | static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData() 70 | { 71 | return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; 72 | } 73 | 74 | // Functions 75 | static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data) 76 | { 77 | ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); 78 | 79 | // Setup viewport 80 | D3DVIEWPORT9 vp; 81 | vp.X = vp.Y = 0; 82 | vp.Width = (DWORD)draw_data->DisplaySize.x; 83 | vp.Height = (DWORD)draw_data->DisplaySize.y; 84 | vp.MinZ = 0.0f; 85 | vp.MaxZ = 1.0f; 86 | bd->pd3dDevice->SetViewport(&vp); 87 | 88 | // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. 89 | bd->pd3dDevice->SetPixelShader(nullptr); 90 | bd->pd3dDevice->SetVertexShader(nullptr); 91 | bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); 92 | bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); 93 | bd->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); 94 | bd->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); 95 | bd->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); 96 | bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); 97 | bd->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); 98 | bd->pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); 99 | bd->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 100 | bd->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 101 | bd->pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); 102 | bd->pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); 103 | bd->pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA); 104 | bd->pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); 105 | bd->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); 106 | bd->pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE); 107 | bd->pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE); 108 | bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); 109 | bd->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE); 110 | bd->pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); 111 | bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); 112 | bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); 113 | bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); 114 | bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); 115 | bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); 116 | bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); 117 | bd->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); 118 | bd->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); 119 | bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 120 | bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 121 | 122 | // Setup orthographic projection matrix 123 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. 124 | // Being agnostic of whether or can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH() 125 | { 126 | float L = draw_data->DisplayPos.x + 0.5f; 127 | float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f; 128 | float T = draw_data->DisplayPos.y + 0.5f; 129 | float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f; 130 | D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } }; 131 | D3DMATRIX mat_projection = 132 | { { { 133 | 2.0f/(R-L), 0.0f, 0.0f, 0.0f, 134 | 0.0f, 2.0f/(T-B), 0.0f, 0.0f, 135 | 0.0f, 0.0f, 0.5f, 0.0f, 136 | (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f 137 | } } }; 138 | bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); 139 | bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); 140 | bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection); 141 | } 142 | } 143 | 144 | // Render function. 145 | void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) 146 | { 147 | // Avoid rendering when minimized 148 | if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) 149 | return; 150 | 151 | // Create and grow buffers if needed 152 | ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); 153 | if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) 154 | { 155 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } 156 | bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; 157 | if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0) 158 | return; 159 | } 160 | if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) 161 | { 162 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } 163 | bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; 164 | if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0) 165 | return; 166 | } 167 | 168 | // Backup the DX9 state 169 | IDirect3DStateBlock9* d3d9_state_block = nullptr; 170 | if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0) 171 | return; 172 | if (d3d9_state_block->Capture() < 0) 173 | { 174 | d3d9_state_block->Release(); 175 | return; 176 | } 177 | 178 | // Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to) 179 | D3DMATRIX last_world, last_view, last_projection; 180 | bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world); 181 | bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view); 182 | bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection); 183 | 184 | // Allocate buffers 185 | CUSTOMVERTEX* vtx_dst; 186 | ImDrawIdx* idx_dst; 187 | if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) 188 | { 189 | d3d9_state_block->Release(); 190 | return; 191 | } 192 | if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0) 193 | { 194 | bd->pVB->Unlock(); 195 | d3d9_state_block->Release(); 196 | return; 197 | } 198 | 199 | // Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format. 200 | // FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and 201 | // 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR 202 | // 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; } 203 | for (int n = 0; n < draw_data->CmdListsCount; n++) 204 | { 205 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 206 | const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data; 207 | for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) 208 | { 209 | vtx_dst->pos[0] = vtx_src->pos.x; 210 | vtx_dst->pos[1] = vtx_src->pos.y; 211 | vtx_dst->pos[2] = 0.0f; 212 | vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col); 213 | vtx_dst->uv[0] = vtx_src->uv.x; 214 | vtx_dst->uv[1] = vtx_src->uv.y; 215 | vtx_dst++; 216 | vtx_src++; 217 | } 218 | memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); 219 | idx_dst += cmd_list->IdxBuffer.Size; 220 | } 221 | bd->pVB->Unlock(); 222 | bd->pIB->Unlock(); 223 | bd->pd3dDevice->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX)); 224 | bd->pd3dDevice->SetIndices(bd->pIB); 225 | bd->pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); 226 | 227 | // Setup desired DX state 228 | ImGui_ImplDX9_SetupRenderState(draw_data); 229 | 230 | // Render command lists 231 | // (Because we merged all buffers into a single one, we maintain our own offset into them) 232 | int global_vtx_offset = 0; 233 | int global_idx_offset = 0; 234 | ImVec2 clip_off = draw_data->DisplayPos; 235 | for (int n = 0; n < draw_data->CmdListsCount; n++) 236 | { 237 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 238 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 239 | { 240 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 241 | if (pcmd->UserCallback != nullptr) 242 | { 243 | // User callback, registered via ImDrawList::AddCallback() 244 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) 245 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) 246 | ImGui_ImplDX9_SetupRenderState(draw_data); 247 | else 248 | pcmd->UserCallback(cmd_list, pcmd); 249 | } 250 | else 251 | { 252 | // Project scissor/clipping rectangles into framebuffer space 253 | ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); 254 | ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); 255 | if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) 256 | continue; 257 | 258 | // Apply Scissor/clipping rectangle, Bind texture, Draw 259 | const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; 260 | const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID(); 261 | bd->pd3dDevice->SetTexture(0, texture); 262 | bd->pd3dDevice->SetScissorRect(&r); 263 | bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3); 264 | } 265 | } 266 | global_idx_offset += cmd_list->IdxBuffer.Size; 267 | global_vtx_offset += cmd_list->VtxBuffer.Size; 268 | } 269 | 270 | // Restore the DX9 transform 271 | bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world); 272 | bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view); 273 | bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection); 274 | 275 | // Restore the DX9 state 276 | d3d9_state_block->Apply(); 277 | d3d9_state_block->Release(); 278 | } 279 | 280 | bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) 281 | { 282 | ImGuiIO& io = ImGui::GetIO(); 283 | IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); 284 | 285 | // Setup backend capabilities flags 286 | ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)(); 287 | io.BackendRendererUserData = (void*)bd; 288 | io.BackendRendererName = "imgui_impl_dx9"; 289 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. 290 | 291 | bd->pd3dDevice = device; 292 | bd->pd3dDevice->AddRef(); 293 | 294 | return true; 295 | } 296 | 297 | void ImGui_ImplDX9_Shutdown() 298 | { 299 | ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); 300 | IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); 301 | ImGuiIO& io = ImGui::GetIO(); 302 | 303 | ImGui_ImplDX9_InvalidateDeviceObjects(); 304 | if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } 305 | io.BackendRendererName = nullptr; 306 | io.BackendRendererUserData = nullptr; 307 | io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; 308 | IM_DELETE(bd); 309 | } 310 | 311 | static bool ImGui_ImplDX9_CreateFontsTexture() 312 | { 313 | // Build texture atlas 314 | ImGuiIO& io = ImGui::GetIO(); 315 | ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); 316 | unsigned char* pixels; 317 | int width, height, bytes_per_pixel; 318 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); 319 | 320 | // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) 321 | #ifndef IMGUI_USE_BGRA_PACKED_COLOR 322 | if (io.Fonts->TexPixelsUseColors) 323 | { 324 | ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); 325 | for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) 326 | *dst = IMGUI_COL_TO_DX9_ARGB(*src); 327 | pixels = (unsigned char*)dst_start; 328 | } 329 | #endif 330 | 331 | // Upload texture to graphics system 332 | bd->FontTexture = nullptr; 333 | if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) 334 | return false; 335 | D3DLOCKED_RECT tex_locked_rect; 336 | if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) 337 | return false; 338 | for (int y = 0; y < height; y++) 339 | memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel); 340 | bd->FontTexture->UnlockRect(0); 341 | 342 | // Store our identifier 343 | io.Fonts->SetTexID((ImTextureID)bd->FontTexture); 344 | 345 | #ifndef IMGUI_USE_BGRA_PACKED_COLOR 346 | if (io.Fonts->TexPixelsUseColors) 347 | ImGui::MemFree(pixels); 348 | #endif 349 | 350 | return true; 351 | } 352 | 353 | bool ImGui_ImplDX9_CreateDeviceObjects() 354 | { 355 | ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); 356 | if (!bd || !bd->pd3dDevice) 357 | return false; 358 | if (!ImGui_ImplDX9_CreateFontsTexture()) 359 | return false; 360 | return true; 361 | } 362 | 363 | void ImGui_ImplDX9_InvalidateDeviceObjects() 364 | { 365 | ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); 366 | if (!bd || !bd->pd3dDevice) 367 | return; 368 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } 369 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } 370 | if (bd->FontTexture) { bd->FontTexture->Release(); bd->FontTexture = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. 371 | } 372 | 373 | void ImGui_ImplDX9_NewFrame() 374 | { 375 | ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); 376 | IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX9_Init()?"); 377 | 378 | if (!bd->FontTexture) 379 | ImGui_ImplDX9_CreateDeviceObjects(); 380 | } 381 | -------------------------------------------------------------------------------- /dependencies/ImGui/backends/imgui_impl_dx9.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for DirectX9 2 | // This needs to be used along with a Platform Backend (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. 7 | 8 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 9 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 10 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 11 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 12 | 13 | #pragma once 14 | #include "imgui.h" // IMGUI_IMPL_API 15 | 16 | struct IDirect3DDevice9; 17 | 18 | IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device); 19 | IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown(); 20 | IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame(); 21 | IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data); 22 | 23 | // Use if you want to reset your rendering device without losing Dear ImGui state. 24 | IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects(); 25 | IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects(); 26 | -------------------------------------------------------------------------------- /dependencies/ImGui/backends/imgui_impl_win32.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | 4 | // Implemented features: 5 | // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) 6 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. 7 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] 8 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 9 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 10 | 11 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 12 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 13 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 14 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 15 | 16 | #pragma once 17 | #include // IMGUI_IMPL_API 18 | 19 | IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); 20 | IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd); 21 | IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); 22 | IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); 23 | 24 | // Win32 message handler your application need to call. 25 | // - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper. 26 | // - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. 27 | // - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. 28 | 29 | #if 0 30 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 31 | #endif 32 | 33 | // DPI-related helpers (optional) 34 | // - Use to enable DPI awareness without having to create an application manifest. 35 | // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. 36 | // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. 37 | // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, 38 | // neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. 39 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); 40 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd 41 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor 42 | 43 | // Transparency related helpers (optional) [experimental] 44 | // - Use to enable alpha compositing transparency with the desktop. 45 | // - Use together with e.g. clearing your framebuffer with zero-alpha. 46 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd 47 | -------------------------------------------------------------------------------- /dependencies/ImGui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 26 | //#define IMGUI_API __declspec( dllexport ) 27 | //#define IMGUI_API __declspec( dllimport ) 28 | 29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions. 32 | 33 | //---- Disable all of Dear ImGui or don't implement standard windows/tools. 34 | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. 35 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 36 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. 37 | //#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88). 38 | 39 | //---- Don't implement some functions to reduce linkage requirements. 40 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 41 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) 42 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) 43 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 44 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 45 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 46 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 47 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) 48 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 49 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 50 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available 51 | 52 | //---- Include imgui_user.h at the end of imgui.h as a convenience 53 | //#define IMGUI_INCLUDE_IMGUI_USER_H 54 | 55 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 56 | //#define IMGUI_USE_BGRA_PACKED_COLOR 57 | 58 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 59 | //#define IMGUI_USE_WCHAR32 60 | 61 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 62 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 63 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 64 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 65 | //#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled 66 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 67 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 68 | 69 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 70 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. 71 | //#define IMGUI_USE_STB_SPRINTF 72 | 73 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 74 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 75 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 76 | //#define IMGUI_ENABLE_FREETYPE 77 | 78 | //---- Use stb_truetype to build and rasterize the font atlas (default) 79 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 80 | //#define IMGUI_ENABLE_STB_TRUETYPE 81 | 82 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 83 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 84 | /* 85 | #define IM_VEC2_CLASS_EXTRA \ 86 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ 87 | operator MyVec2() const { return MyVec2(x,y); } 88 | 89 | #define IM_VEC4_CLASS_EXTRA \ 90 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ 91 | operator MyVec4() const { return MyVec4(x,y,z,w); } 92 | */ 93 | //---- ...Or use Dear ImGui's own very basic math operators. 94 | //#define IMGUI_DEFINE_MATH_OPERATORS 95 | 96 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 97 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 98 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 99 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 100 | //#define ImDrawIdx unsigned int 101 | 102 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 103 | //struct ImDrawList; 104 | //struct ImDrawCmd; 105 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 106 | //#define ImDrawCallback MyImDrawCallback 107 | 108 | //---- Debug Tools: Macro to break in Debugger 109 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 110 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 111 | //#define IM_DEBUG_BREAK __debugbreak() 112 | 113 | //---- Debug Tools: Enable slower asserts 114 | //#define IMGUI_DEBUG_PARANOID 115 | 116 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 117 | /* 118 | namespace ImGui 119 | { 120 | void MyFunction(const char* name, const MyMatrix44& v); 121 | } 122 | */ 123 | -------------------------------------------------------------------------------- /dependencies/ImGui/imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.01. 3 | // Grep for [DEAR IMGUI] to find the changes. 4 | // 5 | // stb_rect_pack.h - v1.01 - public domain - rectangle packing 6 | // Sean Barrett 2014 7 | // 8 | // Useful for e.g. packing rectangular textures into an atlas. 9 | // Does not do rotation. 10 | // 11 | // Before #including, 12 | // 13 | // #define STB_RECT_PACK_IMPLEMENTATION 14 | // 15 | // in the file that you want to have the implementation. 16 | // 17 | // Not necessarily the awesomest packing method, but better than 18 | // the totally naive one in stb_truetype (which is primarily what 19 | // this is meant to replace). 20 | // 21 | // Has only had a few tests run, may have issues. 22 | // 23 | // More docs to come. 24 | // 25 | // No memory allocations; uses qsort() and assert() from stdlib. 26 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 27 | // 28 | // This library currently uses the Skyline Bottom-Left algorithm. 29 | // 30 | // Please note: better rectangle packers are welcome! Please 31 | // implement them to the same API, but with a different init 32 | // function. 33 | // 34 | // Credits 35 | // 36 | // Library 37 | // Sean Barrett 38 | // Minor features 39 | // Martins Mozeiko 40 | // github:IntellectualKitty 41 | // 42 | // Bugfixes / warning fixes 43 | // Jeremy Jaussaud 44 | // Fabian Giesen 45 | // 46 | // Version history: 47 | // 48 | // 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section 49 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 50 | // 0.99 (2019-02-07) warning fixes 51 | // 0.11 (2017-03-03) return packing success/fail result 52 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 53 | // 0.09 (2016-08-27) fix compiler warnings 54 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 55 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 56 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 57 | // 0.05: added STBRP_ASSERT to allow replacing assert 58 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 59 | // 0.01: initial release 60 | // 61 | // LICENSE 62 | // 63 | // See end of file for license information. 64 | 65 | ////////////////////////////////////////////////////////////////////////////// 66 | // 67 | // INCLUDE SECTION 68 | // 69 | 70 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 71 | #define STB_INCLUDE_STB_RECT_PACK_H 72 | 73 | #define STB_RECT_PACK_VERSION 1 74 | 75 | #ifdef STBRP_STATIC 76 | #define STBRP_DEF static 77 | #else 78 | #define STBRP_DEF extern 79 | #endif 80 | 81 | #ifdef __cplusplus 82 | extern "C" { 83 | #endif 84 | 85 | typedef struct stbrp_context stbrp_context; 86 | typedef struct stbrp_node stbrp_node; 87 | typedef struct stbrp_rect stbrp_rect; 88 | 89 | typedef int stbrp_coord; 90 | 91 | #define STBRP__MAXVAL 0x7fffffff 92 | // Mostly for internal use, but this is the maximum supported coordinate value. 93 | 94 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 95 | // Assign packed locations to rectangles. The rectangles are of type 96 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 97 | // are 'num_rects' many of them. 98 | // 99 | // Rectangles which are successfully packed have the 'was_packed' flag 100 | // set to a non-zero value and 'x' and 'y' store the minimum location 101 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 102 | // if you imagine y increasing downwards). Rectangles which do not fit 103 | // have the 'was_packed' flag set to 0. 104 | // 105 | // You should not try to access the 'rects' array from another thread 106 | // while this function is running, as the function temporarily reorders 107 | // the array while it executes. 108 | // 109 | // To pack into another rectangle, you need to call stbrp_init_target 110 | // again. To continue packing into the same rectangle, you can call 111 | // this function again. Calling this multiple times with multiple rect 112 | // arrays will probably produce worse packing results than calling it 113 | // a single time with the full rectangle array, but the option is 114 | // available. 115 | // 116 | // The function returns 1 if all of the rectangles were successfully 117 | // packed and 0 otherwise. 118 | 119 | struct stbrp_rect 120 | { 121 | // reserved for your use: 122 | int id; 123 | 124 | // input: 125 | stbrp_coord w, h; 126 | 127 | // output: 128 | stbrp_coord x, y; 129 | int was_packed; // non-zero if valid packing 130 | 131 | }; // 16 bytes, nominally 132 | 133 | 134 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 135 | // Initialize a rectangle packer to: 136 | // pack a rectangle that is 'width' by 'height' in dimensions 137 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 138 | // 139 | // You must call this function every time you start packing into a new target. 140 | // 141 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 142 | // the following stbrp_pack_rects() call (or calls), but can be freed after 143 | // the call (or calls) finish. 144 | // 145 | // Note: to guarantee best results, either: 146 | // 1. make sure 'num_nodes' >= 'width' 147 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 148 | // 149 | // If you don't do either of the above things, widths will be quantized to multiples 150 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 151 | // 152 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 153 | // may run out of temporary storage and be unable to pack some rectangles. 154 | 155 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 156 | // Optionally call this function after init but before doing any packing to 157 | // change the handling of the out-of-temp-memory scenario, described above. 158 | // If you call init again, this will be reset to the default (false). 159 | 160 | 161 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 162 | // Optionally select which packing heuristic the library should use. Different 163 | // heuristics will produce better/worse results for different data sets. 164 | // If you call init again, this will be reset to the default. 165 | 166 | enum 167 | { 168 | STBRP_HEURISTIC_Skyline_default=0, 169 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 170 | STBRP_HEURISTIC_Skyline_BF_sortHeight 171 | }; 172 | 173 | 174 | ////////////////////////////////////////////////////////////////////////////// 175 | // 176 | // the details of the following structures don't matter to you, but they must 177 | // be visible so you can handle the memory allocations for them 178 | 179 | struct stbrp_node 180 | { 181 | stbrp_coord x,y; 182 | stbrp_node *next; 183 | }; 184 | 185 | struct stbrp_context 186 | { 187 | int width; 188 | int height; 189 | int align; 190 | int init_mode; 191 | int heuristic; 192 | int num_nodes; 193 | stbrp_node *active_head; 194 | stbrp_node *free_head; 195 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 196 | }; 197 | 198 | #ifdef __cplusplus 199 | } 200 | #endif 201 | 202 | #endif 203 | 204 | ////////////////////////////////////////////////////////////////////////////// 205 | // 206 | // IMPLEMENTATION SECTION 207 | // 208 | 209 | #ifdef STB_RECT_PACK_IMPLEMENTATION 210 | #ifndef STBRP_SORT 211 | #include 212 | #define STBRP_SORT qsort 213 | #endif 214 | 215 | #ifndef STBRP_ASSERT 216 | #include 217 | #define STBRP_ASSERT assert 218 | #endif 219 | 220 | #ifdef _MSC_VER 221 | #define STBRP__NOTUSED(v) (void)(v) 222 | #define STBRP__CDECL __cdecl 223 | #else 224 | #define STBRP__NOTUSED(v) (void)sizeof(v) 225 | #define STBRP__CDECL 226 | #endif 227 | 228 | enum 229 | { 230 | STBRP__INIT_skyline = 1 231 | }; 232 | 233 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 234 | { 235 | switch (context->init_mode) { 236 | case STBRP__INIT_skyline: 237 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 238 | context->heuristic = heuristic; 239 | break; 240 | default: 241 | STBRP_ASSERT(0); 242 | } 243 | } 244 | 245 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 246 | { 247 | if (allow_out_of_mem) 248 | // if it's ok to run out of memory, then don't bother aligning them; 249 | // this gives better packing, but may fail due to OOM (even though 250 | // the rectangles easily fit). @TODO a smarter approach would be to only 251 | // quantize once we've hit OOM, then we could get rid of this parameter. 252 | context->align = 1; 253 | else { 254 | // if it's not ok to run out of memory, then quantize the widths 255 | // so that num_nodes is always enough nodes. 256 | // 257 | // I.e. num_nodes * align >= width 258 | // align >= width / num_nodes 259 | // align = ceil(width/num_nodes) 260 | 261 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 262 | } 263 | } 264 | 265 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 266 | { 267 | int i; 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | context->extra[1].y = (1<<30); 287 | context->extra[1].next = NULL; 288 | } 289 | 290 | // find minimum y position if it starts at x1 291 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 292 | { 293 | stbrp_node *node = first; 294 | int x1 = x0 + width; 295 | int min_y, visited_width, waste_area; 296 | 297 | STBRP__NOTUSED(c); 298 | 299 | STBRP_ASSERT(first->x <= x0); 300 | 301 | #if 0 302 | // skip in case we're past the node 303 | while (node->next->x <= x0) 304 | ++node; 305 | #else 306 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 307 | #endif 308 | 309 | STBRP_ASSERT(node->x <= x0); 310 | 311 | min_y = 0; 312 | waste_area = 0; 313 | visited_width = 0; 314 | while (node->x < x1) { 315 | if (node->y > min_y) { 316 | // raise min_y higher. 317 | // we've accounted for all waste up to min_y, 318 | // but we'll now add more waste for everything we've visted 319 | waste_area += visited_width * (node->y - min_y); 320 | min_y = node->y; 321 | // the first time through, visited_width might be reduced 322 | if (node->x < x0) 323 | visited_width += node->next->x - x0; 324 | else 325 | visited_width += node->next->x - node->x; 326 | } else { 327 | // add waste area 328 | int under_width = node->next->x - node->x; 329 | if (under_width + visited_width > width) 330 | under_width = width - visited_width; 331 | waste_area += under_width * (min_y - node->y); 332 | visited_width += under_width; 333 | } 334 | node = node->next; 335 | } 336 | 337 | *pwaste = waste_area; 338 | return min_y; 339 | } 340 | 341 | typedef struct 342 | { 343 | int x,y; 344 | stbrp_node **prev_link; 345 | } stbrp__findresult; 346 | 347 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 348 | { 349 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 350 | stbrp__findresult fr; 351 | stbrp_node **prev, *node, *tail, **best = NULL; 352 | 353 | // align to multiple of c->align 354 | width = (width + c->align - 1); 355 | width -= width % c->align; 356 | STBRP_ASSERT(width % c->align == 0); 357 | 358 | // if it can't possibly fit, bail immediately 359 | if (width > c->width || height > c->height) { 360 | fr.prev_link = NULL; 361 | fr.x = fr.y = 0; 362 | return fr; 363 | } 364 | 365 | node = c->active_head; 366 | prev = &c->active_head; 367 | while (node->x + width <= c->width) { 368 | int y,waste; 369 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 370 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 371 | // bottom left 372 | if (y < best_y) { 373 | best_y = y; 374 | best = prev; 375 | } 376 | } else { 377 | // best-fit 378 | if (y + height <= c->height) { 379 | // can only use it if it first vertically 380 | if (y < best_y || (y == best_y && waste < best_waste)) { 381 | best_y = y; 382 | best_waste = waste; 383 | best = prev; 384 | } 385 | } 386 | } 387 | prev = &node->next; 388 | node = node->next; 389 | } 390 | 391 | best_x = (best == NULL) ? 0 : (*best)->x; 392 | 393 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 394 | // 395 | // e.g, if fitting 396 | // 397 | // ____________________ 398 | // |____________________| 399 | // 400 | // into 401 | // 402 | // | | 403 | // | ____________| 404 | // |____________| 405 | // 406 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 407 | // 408 | // This makes BF take about 2x the time 409 | 410 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 411 | tail = c->active_head; 412 | node = c->active_head; 413 | prev = &c->active_head; 414 | // find first node that's admissible 415 | while (tail->x < width) 416 | tail = tail->next; 417 | while (tail) { 418 | int xpos = tail->x - width; 419 | int y,waste; 420 | STBRP_ASSERT(xpos >= 0); 421 | // find the left position that matches this 422 | while (node->next->x <= xpos) { 423 | prev = &node->next; 424 | node = node->next; 425 | } 426 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 427 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 428 | if (y + height <= c->height) { 429 | if (y <= best_y) { 430 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 431 | best_x = xpos; 432 | //STBRP_ASSERT(y <= best_y); [DEAR IMGUI] 433 | best_y = y; 434 | best_waste = waste; 435 | best = prev; 436 | } 437 | } 438 | } 439 | tail = tail->next; 440 | } 441 | } 442 | 443 | fr.prev_link = best; 444 | fr.x = best_x; 445 | fr.y = best_y; 446 | return fr; 447 | } 448 | 449 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 450 | { 451 | // find best position according to heuristic 452 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 453 | stbrp_node *node, *cur; 454 | 455 | // bail if: 456 | // 1. it failed 457 | // 2. the best node doesn't fit (we don't always check this) 458 | // 3. we're out of memory 459 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 460 | res.prev_link = NULL; 461 | return res; 462 | } 463 | 464 | // on success, create new node 465 | node = context->free_head; 466 | node->x = (stbrp_coord) res.x; 467 | node->y = (stbrp_coord) (res.y + height); 468 | 469 | context->free_head = node->next; 470 | 471 | // insert the new node into the right starting point, and 472 | // let 'cur' point to the remaining nodes needing to be 473 | // stiched back in 474 | 475 | cur = *res.prev_link; 476 | if (cur->x < res.x) { 477 | // preserve the existing one, so start testing with the next one 478 | stbrp_node *next = cur->next; 479 | cur->next = node; 480 | cur = next; 481 | } else { 482 | *res.prev_link = node; 483 | } 484 | 485 | // from here, traverse cur and free the nodes, until we get to one 486 | // that shouldn't be freed 487 | while (cur->next && cur->next->x <= res.x + width) { 488 | stbrp_node *next = cur->next; 489 | // move the current node to the free list 490 | cur->next = context->free_head; 491 | context->free_head = cur; 492 | cur = next; 493 | } 494 | 495 | // stitch the list back in 496 | node->next = cur; 497 | 498 | if (cur->x < res.x + width) 499 | cur->x = (stbrp_coord) (res.x + width); 500 | 501 | #ifdef _DEBUG 502 | cur = context->active_head; 503 | while (cur->x < context->width) { 504 | STBRP_ASSERT(cur->x < cur->next->x); 505 | cur = cur->next; 506 | } 507 | STBRP_ASSERT(cur->next == NULL); 508 | 509 | { 510 | int count=0; 511 | cur = context->active_head; 512 | while (cur) { 513 | cur = cur->next; 514 | ++count; 515 | } 516 | cur = context->free_head; 517 | while (cur) { 518 | cur = cur->next; 519 | ++count; 520 | } 521 | STBRP_ASSERT(count == context->num_nodes+2); 522 | } 523 | #endif 524 | 525 | return res; 526 | } 527 | 528 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 529 | { 530 | const stbrp_rect *p = (const stbrp_rect *) a; 531 | const stbrp_rect *q = (const stbrp_rect *) b; 532 | if (p->h > q->h) 533 | return -1; 534 | if (p->h < q->h) 535 | return 1; 536 | return (p->w > q->w) ? -1 : (p->w < q->w); 537 | } 538 | 539 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 540 | { 541 | const stbrp_rect *p = (const stbrp_rect *) a; 542 | const stbrp_rect *q = (const stbrp_rect *) b; 543 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 544 | } 545 | 546 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 547 | { 548 | int i, all_rects_packed = 1; 549 | 550 | // we use the 'was_packed' field internally to allow sorting/unsorting 551 | for (i=0; i < num_rects; ++i) { 552 | rects[i].was_packed = i; 553 | } 554 | 555 | // sort according to heuristic 556 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 557 | 558 | for (i=0; i < num_rects; ++i) { 559 | if (rects[i].w == 0 || rects[i].h == 0) { 560 | rects[i].x = rects[i].y = 0; // empty rect needs no space 561 | } else { 562 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 563 | if (fr.prev_link) { 564 | rects[i].x = (stbrp_coord) fr.x; 565 | rects[i].y = (stbrp_coord) fr.y; 566 | } else { 567 | rects[i].x = rects[i].y = STBRP__MAXVAL; 568 | } 569 | } 570 | } 571 | 572 | // unsort 573 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 574 | 575 | // set was_packed flags and all_rects_packed status 576 | for (i=0; i < num_rects; ++i) { 577 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 578 | if (!rects[i].was_packed) 579 | all_rects_packed = 0; 580 | } 581 | 582 | // return the all_rects_packed status 583 | return all_rects_packed; 584 | } 585 | #endif 586 | 587 | /* 588 | ------------------------------------------------------------------------------ 589 | This software is available under 2 licenses -- choose whichever you prefer. 590 | ------------------------------------------------------------------------------ 591 | ALTERNATIVE A - MIT License 592 | Copyright (c) 2017 Sean Barrett 593 | Permission is hereby granted, free of charge, to any person obtaining a copy of 594 | this software and associated documentation files (the "Software"), to deal in 595 | the Software without restriction, including without limitation the rights to 596 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 597 | of the Software, and to permit persons to whom the Software is furnished to do 598 | so, subject to the following conditions: 599 | The above copyright notice and this permission notice shall be included in all 600 | copies or substantial portions of the Software. 601 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 602 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 603 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 604 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 605 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 606 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 607 | SOFTWARE. 608 | ------------------------------------------------------------------------------ 609 | ALTERNATIVE B - Public Domain (www.unlicense.org) 610 | This is free and unencumbered software released into the public domain. 611 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 612 | software, either in source code form or as a compiled binary, for any purpose, 613 | commercial or non-commercial, and by any means. 614 | In jurisdictions that recognize copyright laws, the author or authors of this 615 | software dedicate any and all copyright interest in the software to the public 616 | domain. We make this dedication for the benefit of the public at large and to 617 | the detriment of our heirs and successors. We intend this dedication to be an 618 | overt act of relinquishment in perpetuity of all present and future rights to 619 | this software under copyright law. 620 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 621 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 622 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 623 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 624 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 625 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 626 | ------------------------------------------------------------------------------ 627 | */ 628 | -------------------------------------------------------------------------------- /dependencies/ImGui/misc/cpp/imgui_stdlib.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.) 2 | // This is also an example of how you may wrap your own similar types. 3 | 4 | // Changelog: 5 | // - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string 6 | 7 | // See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki: 8 | // https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness 9 | 10 | #include "imgui.h" 11 | #include "imgui_stdlib.h" 12 | 13 | struct InputTextCallback_UserData 14 | { 15 | std::string* Str; 16 | ImGuiInputTextCallback ChainCallback; 17 | void* ChainCallbackUserData; 18 | }; 19 | 20 | static int InputTextCallback(ImGuiInputTextCallbackData* data) 21 | { 22 | InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData; 23 | if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) 24 | { 25 | // Resize string callback 26 | // If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want. 27 | std::string* str = user_data->Str; 28 | IM_ASSERT(data->Buf == str->c_str()); 29 | str->resize(data->BufTextLen); 30 | data->Buf = (char*)str->c_str(); 31 | } 32 | else if (user_data->ChainCallback) 33 | { 34 | // Forward to user callback, if any 35 | data->UserData = user_data->ChainCallbackUserData; 36 | return user_data->ChainCallback(data); 37 | } 38 | return 0; 39 | } 40 | 41 | bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 42 | { 43 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 44 | flags |= ImGuiInputTextFlags_CallbackResize; 45 | 46 | InputTextCallback_UserData cb_user_data; 47 | cb_user_data.Str = str; 48 | cb_user_data.ChainCallback = callback; 49 | cb_user_data.ChainCallbackUserData = user_data; 50 | return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); 51 | } 52 | 53 | bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 54 | { 55 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 56 | flags |= ImGuiInputTextFlags_CallbackResize; 57 | 58 | InputTextCallback_UserData cb_user_data; 59 | cb_user_data.Str = str; 60 | cb_user_data.ChainCallback = callback; 61 | cb_user_data.ChainCallbackUserData = user_data; 62 | return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data); 63 | } 64 | 65 | bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 66 | { 67 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 68 | flags |= ImGuiInputTextFlags_CallbackResize; 69 | 70 | InputTextCallback_UserData cb_user_data; 71 | cb_user_data.Str = str; 72 | cb_user_data.ChainCallback = callback; 73 | cb_user_data.ChainCallbackUserData = user_data; 74 | return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); 75 | } 76 | -------------------------------------------------------------------------------- /dependencies/ImGui/misc/cpp/imgui_stdlib.h: -------------------------------------------------------------------------------- 1 | // dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.) 2 | // This is also an example of how you may wrap your own similar types. 3 | 4 | // Changelog: 5 | // - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string 6 | 7 | // See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki: 8 | // https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness 9 | 10 | #pragma once 11 | 12 | #include 13 | 14 | namespace ImGui 15 | { 16 | // ImGui::InputText() with std::string 17 | // Because text input needs dynamic resizing, we need to setup a callback to grow the capacity 18 | IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); 19 | IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); 20 | IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); 21 | } 22 | -------------------------------------------------------------------------------- /dependencies/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 | #include 36 | 37 | // MinHook Error Codes. 38 | typedef enum MH_STATUS 39 | { 40 | // Unknown error. Should not be returned. 41 | MH_UNKNOWN = -1, 42 | 43 | // Successful. 44 | MH_OK = 0, 45 | 46 | // MinHook is already initialized. 47 | MH_ERROR_ALREADY_INITIALIZED, 48 | 49 | // MinHook is not initialized yet, or already uninitialized. 50 | MH_ERROR_NOT_INITIALIZED, 51 | 52 | // The hook for the specified target function is already created. 53 | MH_ERROR_ALREADY_CREATED, 54 | 55 | // The hook for the specified target function is not created yet. 56 | MH_ERROR_NOT_CREATED, 57 | 58 | // The hook for the specified target function is already enabled. 59 | MH_ERROR_ENABLED, 60 | 61 | // The hook for the specified target function is not enabled yet, or already 62 | // disabled. 63 | MH_ERROR_DISABLED, 64 | 65 | // The specified pointer is invalid. It points the address of non-allocated 66 | // and/or non-executable region. 67 | MH_ERROR_NOT_EXECUTABLE, 68 | 69 | // The specified target function cannot be hooked. 70 | MH_ERROR_UNSUPPORTED_FUNCTION, 71 | 72 | // Failed to allocate memory. 73 | MH_ERROR_MEMORY_ALLOC, 74 | 75 | // Failed to change the memory protection. 76 | MH_ERROR_MEMORY_PROTECT, 77 | 78 | // The specified module is not loaded. 79 | MH_ERROR_MODULE_NOT_FOUND, 80 | 81 | // The specified function is not found. 82 | MH_ERROR_FUNCTION_NOT_FOUND 83 | } 84 | MH_STATUS; 85 | 86 | // Can be passed as a parameter to MH_EnableHook, MH_DisableHook, 87 | // MH_QueueEnableHook or MH_QueueDisableHook. 88 | #define MH_ALL_HOOKS NULL 89 | 90 | #ifdef __cplusplus 91 | extern "C" { 92 | #endif 93 | 94 | // Initialize the MinHook library. You must call this function EXACTLY ONCE 95 | // at the beginning of your program. 96 | MH_STATUS WINAPI MH_Initialize(VOID); 97 | 98 | // Uninitialize the MinHook library. You must call this function EXACTLY 99 | // ONCE at the end of your program. 100 | MH_STATUS WINAPI MH_Uninitialize(VOID); 101 | 102 | // Creates a hook for the specified target function, in disabled state. 103 | // Parameters: 104 | // pTarget [in] A pointer to the target function, which will be 105 | // overridden by the detour function. 106 | // pDetour [in] A pointer to the detour function, which will override 107 | // the target function. 108 | // ppOriginal [out] A pointer to the trampoline function, which will be 109 | // used to call the original target function. 110 | // This parameter can be NULL. 111 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); 112 | 113 | // Creates a hook for the specified API function, in disabled state. 114 | // Parameters: 115 | // pszModule [in] A pointer to the loaded module name which contains the 116 | // target function. 117 | // pszProcName [in] A pointer to the target function name, which will be 118 | // overridden by the detour function. 119 | // pDetour [in] A pointer to the detour function, which will override 120 | // the target function. 121 | // ppOriginal [out] A pointer to the trampoline function, which will be 122 | // used to call the original target function. 123 | // This parameter can be NULL. 124 | MH_STATUS WINAPI MH_CreateHookApi( 125 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); 126 | 127 | // Creates a hook for the specified API function, in disabled state. 128 | // Parameters: 129 | // pszModule [in] A pointer to the loaded module name which contains the 130 | // target function. 131 | // pszProcName [in] A pointer to the target function name, which will be 132 | // overridden by the detour function. 133 | // pDetour [in] A pointer to the detour function, which will override 134 | // the target function. 135 | // ppOriginal [out] A pointer to the trampoline function, which will be 136 | // used to call the original target function. 137 | // This parameter can be NULL. 138 | // ppTarget [out] A pointer to the target function, which will be used 139 | // with other functions. 140 | // This parameter can be NULL. 141 | MH_STATUS WINAPI MH_CreateHookApiEx( 142 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); 143 | 144 | // Removes an already created hook. 145 | // Parameters: 146 | // pTarget [in] A pointer to the target function. 147 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); 148 | 149 | // Enables an already created hook. 150 | // Parameters: 151 | // pTarget [in] A pointer to the target function. 152 | // If this parameter is MH_ALL_HOOKS, all created hooks are 153 | // enabled in one go. 154 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); 155 | 156 | // Disables an already created hook. 157 | // Parameters: 158 | // pTarget [in] A pointer to the target function. 159 | // If this parameter is MH_ALL_HOOKS, all created hooks are 160 | // disabled in one go. 161 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); 162 | 163 | // Queues to enable an already created hook. 164 | // Parameters: 165 | // pTarget [in] A pointer to the target function. 166 | // If this parameter is MH_ALL_HOOKS, all created hooks are 167 | // queued to be enabled. 168 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); 169 | 170 | // Queues to disable an already created hook. 171 | // Parameters: 172 | // pTarget [in] A pointer to the target function. 173 | // If this parameter is MH_ALL_HOOKS, all created hooks are 174 | // queued to be disabled. 175 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); 176 | 177 | // Applies all queued changes in one go. 178 | MH_STATUS WINAPI MH_ApplyQueued(VOID); 179 | 180 | // Translates the MH_STATUS to its name as a string. 181 | const char * WINAPI MH_StatusToString(MH_STATUS status); 182 | 183 | #ifdef __cplusplus 184 | } 185 | #endif 186 | -------------------------------------------------------------------------------- /dependencies/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 | 29 | #include 30 | #include "buffer.h" 31 | 32 | // Size of each memory block. (= page size of VirtualAlloc) 33 | #define MEMORY_BLOCK_SIZE 0x1000 34 | 35 | // Max range for seeking a memory block. (= 1024MB) 36 | #define MAX_MEMORY_RANGE 0x40000000 37 | 38 | // Memory protection flags to check the executable address. 39 | #define PAGE_EXECUTE_FLAGS \ 40 | (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) 41 | 42 | // Memory slot. 43 | typedef struct _MEMORY_SLOT 44 | { 45 | union 46 | { 47 | struct _MEMORY_SLOT *pNext; 48 | UINT8 buffer[MEMORY_SLOT_SIZE]; 49 | }; 50 | } MEMORY_SLOT, *PMEMORY_SLOT; 51 | 52 | // Memory block info. Placed at the head of each block. 53 | typedef struct _MEMORY_BLOCK 54 | { 55 | struct _MEMORY_BLOCK *pNext; 56 | PMEMORY_SLOT pFree; // First element of the free slot list. 57 | UINT usedCount; 58 | } MEMORY_BLOCK, *PMEMORY_BLOCK; 59 | 60 | //------------------------------------------------------------------------- 61 | // Global Variables: 62 | //------------------------------------------------------------------------- 63 | 64 | // First element of the memory block list. 65 | PMEMORY_BLOCK g_pMemoryBlocks; 66 | 67 | //------------------------------------------------------------------------- 68 | VOID InitializeBuffer(VOID) 69 | { 70 | // Nothing to do for now. 71 | } 72 | 73 | //------------------------------------------------------------------------- 74 | VOID UninitializeBuffer(VOID) 75 | { 76 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks; 77 | g_pMemoryBlocks = NULL; 78 | 79 | while (pBlock) 80 | { 81 | PMEMORY_BLOCK pNext = pBlock->pNext; 82 | VirtualFree(pBlock, 0, MEM_RELEASE); 83 | pBlock = pNext; 84 | } 85 | } 86 | 87 | //------------------------------------------------------------------------- 88 | #if defined(_M_X64) || defined(__x86_64__) 89 | static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) 90 | { 91 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress; 92 | 93 | // Round down to the allocation granularity. 94 | tryAddr -= tryAddr % dwAllocationGranularity; 95 | 96 | // Start from the previous allocation granularity multiply. 97 | tryAddr -= dwAllocationGranularity; 98 | 99 | while (tryAddr >= (ULONG_PTR)pMinAddr) 100 | { 101 | MEMORY_BASIC_INFORMATION mbi; 102 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) 103 | break; 104 | 105 | if (mbi.State == MEM_FREE) 106 | return (LPVOID)tryAddr; 107 | 108 | if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) 109 | break; 110 | 111 | tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; 112 | } 113 | 114 | return NULL; 115 | } 116 | #endif 117 | 118 | //------------------------------------------------------------------------- 119 | #if defined(_M_X64) || defined(__x86_64__) 120 | static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) 121 | { 122 | ULONG_PTR tryAddr = (ULONG_PTR)pAddress; 123 | 124 | // Round down to the allocation granularity. 125 | tryAddr -= tryAddr % dwAllocationGranularity; 126 | 127 | // Start from the next allocation granularity multiply. 128 | tryAddr += dwAllocationGranularity; 129 | 130 | while (tryAddr <= (ULONG_PTR)pMaxAddr) 131 | { 132 | MEMORY_BASIC_INFORMATION mbi; 133 | if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) 134 | break; 135 | 136 | if (mbi.State == MEM_FREE) 137 | return (LPVOID)tryAddr; 138 | 139 | tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; 140 | 141 | // Round up to the next allocation granularity. 142 | tryAddr += dwAllocationGranularity - 1; 143 | tryAddr -= tryAddr % dwAllocationGranularity; 144 | } 145 | 146 | return NULL; 147 | } 148 | #endif 149 | 150 | //------------------------------------------------------------------------- 151 | static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) 152 | { 153 | PMEMORY_BLOCK pBlock; 154 | #if defined(_M_X64) || defined(__x86_64__) 155 | ULONG_PTR minAddr; 156 | ULONG_PTR maxAddr; 157 | 158 | SYSTEM_INFO si; 159 | GetSystemInfo(&si); 160 | minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; 161 | maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; 162 | 163 | // pOrigin ± 512MB 164 | if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) 165 | minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; 166 | 167 | if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) 168 | maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; 169 | 170 | // Make room for MEMORY_BLOCK_SIZE bytes. 171 | maxAddr -= MEMORY_BLOCK_SIZE - 1; 172 | #endif 173 | 174 | // Look the registered blocks for a reachable one. 175 | for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) 176 | { 177 | #if defined(_M_X64) || defined(__x86_64__) 178 | // Ignore the blocks too far. 179 | if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) 180 | continue; 181 | #endif 182 | // The block has at least one unused slot. 183 | if (pBlock->pFree != NULL) 184 | return pBlock; 185 | } 186 | 187 | #if defined(_M_X64) || defined(__x86_64__) 188 | // Alloc a new block above if not found. 189 | { 190 | LPVOID pAlloc = pOrigin; 191 | while ((ULONG_PTR)pAlloc >= minAddr) 192 | { 193 | pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); 194 | if (pAlloc == NULL) 195 | break; 196 | 197 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 198 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 199 | if (pBlock != NULL) 200 | break; 201 | } 202 | } 203 | 204 | // Alloc a new block below if not found. 205 | if (pBlock == NULL) 206 | { 207 | LPVOID pAlloc = pOrigin; 208 | while ((ULONG_PTR)pAlloc <= maxAddr) 209 | { 210 | pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); 211 | if (pAlloc == NULL) 212 | break; 213 | 214 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 215 | pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 216 | if (pBlock != NULL) 217 | break; 218 | } 219 | } 220 | #else 221 | // In x86 mode, a memory block can be placed anywhere. 222 | pBlock = (PMEMORY_BLOCK)VirtualAlloc( 223 | NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 224 | #endif 225 | 226 | if (pBlock != NULL) 227 | { 228 | // Build a linked list of all the slots. 229 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; 230 | pBlock->pFree = NULL; 231 | pBlock->usedCount = 0; 232 | do 233 | { 234 | pSlot->pNext = pBlock->pFree; 235 | pBlock->pFree = pSlot; 236 | pSlot++; 237 | } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); 238 | 239 | pBlock->pNext = g_pMemoryBlocks; 240 | g_pMemoryBlocks = pBlock; 241 | } 242 | 243 | return pBlock; 244 | } 245 | 246 | //------------------------------------------------------------------------- 247 | LPVOID AllocateBuffer(LPVOID pOrigin) 248 | { 249 | PMEMORY_SLOT pSlot; 250 | PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); 251 | if (pBlock == NULL) 252 | return NULL; 253 | 254 | // Remove an unused slot from the list. 255 | pSlot = pBlock->pFree; 256 | pBlock->pFree = pSlot->pNext; 257 | pBlock->usedCount++; 258 | #ifdef _DEBUG 259 | // Fill the slot with INT3 for debugging. 260 | memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); 261 | #endif 262 | return pSlot; 263 | } 264 | 265 | //------------------------------------------------------------------------- 266 | VOID FreeBuffer(LPVOID pBuffer) 267 | { 268 | PMEMORY_BLOCK pBlock = g_pMemoryBlocks; 269 | PMEMORY_BLOCK pPrev = NULL; 270 | ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; 271 | 272 | while (pBlock != NULL) 273 | { 274 | if ((ULONG_PTR)pBlock == pTargetBlock) 275 | { 276 | PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; 277 | #ifdef _DEBUG 278 | // Clear the released slot for debugging. 279 | memset(pSlot, 0x00, sizeof(MEMORY_SLOT)); 280 | #endif 281 | // Restore the released slot to the list. 282 | pSlot->pNext = pBlock->pFree; 283 | pBlock->pFree = pSlot; 284 | pBlock->usedCount--; 285 | 286 | // Free if unused. 287 | if (pBlock->usedCount == 0) 288 | { 289 | if (pPrev) 290 | pPrev->pNext = pBlock->pNext; 291 | else 292 | g_pMemoryBlocks = pBlock->pNext; 293 | 294 | VirtualFree(pBlock, 0, MEM_RELEASE); 295 | } 296 | 297 | break; 298 | } 299 | 300 | pPrev = pBlock; 301 | pBlock = pBlock->pNext; 302 | } 303 | } 304 | 305 | //------------------------------------------------------------------------- 306 | BOOL IsExecutableAddress(LPVOID pAddress) 307 | { 308 | MEMORY_BASIC_INFORMATION mi; 309 | VirtualQuery(pAddress, &mi, sizeof(mi)); 310 | 311 | return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); 312 | } 313 | -------------------------------------------------------------------------------- /dependencies/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 | -------------------------------------------------------------------------------- /dependencies/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 | -------------------------------------------------------------------------------- /dependencies/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 | -------------------------------------------------------------------------------- /dependencies/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 | -------------------------------------------------------------------------------- /dependencies/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 | -------------------------------------------------------------------------------- /dependencies/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 | #include 30 | 31 | // Integer types for HDE. 32 | typedef INT8 int8_t; 33 | typedef INT16 int16_t; 34 | typedef INT32 int32_t; 35 | typedef INT64 int64_t; 36 | typedef UINT8 uint8_t; 37 | typedef UINT16 uint16_t; 38 | typedef UINT32 uint32_t; 39 | typedef UINT64 uint64_t; 40 | -------------------------------------------------------------------------------- /dependencies/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 | -------------------------------------------------------------------------------- /dependencies/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 | -------------------------------------------------------------------------------- /dependencies/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 | #include 30 | #include 31 | #include 32 | 33 | #include "MinHook.h" 34 | #include "buffer.h" 35 | #include "trampoline.h" 36 | 37 | #ifndef ARRAYSIZE 38 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 39 | #endif 40 | 41 | // Initial capacity of the HOOK_ENTRY buffer. 42 | #define INITIAL_HOOK_CAPACITY 32 43 | 44 | // Initial capacity of the thread IDs buffer. 45 | #define INITIAL_THREAD_CAPACITY 128 46 | 47 | // Special hook position values. 48 | #define INVALID_HOOK_POS UINT_MAX 49 | #define ALL_HOOKS_POS UINT_MAX 50 | 51 | // Freeze() action argument defines. 52 | #define ACTION_DISABLE 0 53 | #define ACTION_ENABLE 1 54 | #define ACTION_APPLY_QUEUED 2 55 | 56 | // Thread access rights for suspending/resuming threads. 57 | #define THREAD_ACCESS \ 58 | (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) 59 | 60 | // Hook information. 61 | typedef struct _HOOK_ENTRY 62 | { 63 | LPVOID pTarget; // Address of the target function. 64 | LPVOID pDetour; // Address of the detour or relay function. 65 | LPVOID pTrampoline; // Address of the trampoline function. 66 | UINT8 backup[8]; // Original prologue of the target function. 67 | 68 | UINT8 patchAbove : 1; // Uses the hot patch area. 69 | UINT8 isEnabled : 1; // Enabled. 70 | UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled. 71 | 72 | UINT nIP : 4; // Count of the instruction boundaries. 73 | UINT8 oldIPs[8]; // Instruction boundaries of the target function. 74 | UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. 75 | } HOOK_ENTRY, *PHOOK_ENTRY; 76 | 77 | // Suspended threads for Freeze()/Unfreeze(). 78 | typedef struct _FROZEN_THREADS 79 | { 80 | LPDWORD pItems; // Data heap 81 | UINT capacity; // Size of allocated data heap, items 82 | UINT size; // Actual number of data items 83 | } FROZEN_THREADS, *PFROZEN_THREADS; 84 | 85 | //------------------------------------------------------------------------- 86 | // Global Variables: 87 | //------------------------------------------------------------------------- 88 | 89 | // Spin lock flag for EnterSpinLock()/LeaveSpinLock(). 90 | volatile LONG g_isLocked = FALSE; 91 | 92 | // Private heap handle. If not NULL, this library is initialized. 93 | HANDLE g_hHeap = NULL; 94 | 95 | // Hook entries. 96 | struct 97 | { 98 | PHOOK_ENTRY pItems; // Data heap 99 | UINT capacity; // Size of allocated data heap, items 100 | UINT size; // Actual number of data items 101 | } g_hooks; 102 | 103 | //------------------------------------------------------------------------- 104 | // Returns INVALID_HOOK_POS if not found. 105 | static UINT FindHookEntry(LPVOID pTarget) 106 | { 107 | UINT i; 108 | for (i = 0; i < g_hooks.size; ++i) 109 | { 110 | if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget) 111 | return i; 112 | } 113 | 114 | return INVALID_HOOK_POS; 115 | } 116 | 117 | //------------------------------------------------------------------------- 118 | static PHOOK_ENTRY AddHookEntry() 119 | { 120 | if (g_hooks.pItems == NULL) 121 | { 122 | g_hooks.capacity = INITIAL_HOOK_CAPACITY; 123 | g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( 124 | g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); 125 | if (g_hooks.pItems == NULL) 126 | return NULL; 127 | } 128 | else if (g_hooks.size >= g_hooks.capacity) 129 | { 130 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( 131 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); 132 | if (p == NULL) 133 | return NULL; 134 | 135 | g_hooks.capacity *= 2; 136 | g_hooks.pItems = p; 137 | } 138 | 139 | return &g_hooks.pItems[g_hooks.size++]; 140 | } 141 | 142 | //------------------------------------------------------------------------- 143 | static VOID DeleteHookEntry(UINT pos) 144 | { 145 | if (pos < g_hooks.size - 1) 146 | g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; 147 | 148 | g_hooks.size--; 149 | 150 | if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) 151 | { 152 | PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( 153 | g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); 154 | if (p == NULL) 155 | return; 156 | 157 | g_hooks.capacity /= 2; 158 | g_hooks.pItems = p; 159 | } 160 | } 161 | 162 | //------------------------------------------------------------------------- 163 | static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) 164 | { 165 | UINT i; 166 | 167 | if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) 168 | return (DWORD_PTR)pHook->pTarget; 169 | 170 | for (i = 0; i < pHook->nIP; ++i) 171 | { 172 | if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i])) 173 | return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; 174 | } 175 | 176 | #if defined(_M_X64) || defined(__x86_64__) 177 | // Check relay function. 178 | if (ip == (DWORD_PTR)pHook->pDetour) 179 | return (DWORD_PTR)pHook->pTarget; 180 | #endif 181 | 182 | return 0; 183 | } 184 | 185 | //------------------------------------------------------------------------- 186 | static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) 187 | { 188 | UINT i; 189 | for (i = 0; i < pHook->nIP; ++i) 190 | { 191 | if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) 192 | return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]; 193 | } 194 | 195 | return 0; 196 | } 197 | 198 | //------------------------------------------------------------------------- 199 | static VOID ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) 200 | { 201 | // If the thread suspended in the overwritten area, 202 | // move IP to the proper address. 203 | 204 | CONTEXT c; 205 | #if defined(_M_X64) || defined(__x86_64__) 206 | DWORD64 *pIP = &c.Rip; 207 | #else 208 | DWORD *pIP = &c.Eip; 209 | #endif 210 | UINT count; 211 | 212 | c.ContextFlags = CONTEXT_CONTROL; 213 | if (!GetThreadContext(hThread, &c)) 214 | return; 215 | 216 | if (pos == ALL_HOOKS_POS) 217 | { 218 | pos = 0; 219 | count = g_hooks.size; 220 | } 221 | else 222 | { 223 | count = pos + 1; 224 | } 225 | 226 | for (; pos < count; ++pos) 227 | { 228 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; 229 | BOOL enable; 230 | DWORD_PTR ip; 231 | 232 | switch (action) 233 | { 234 | case ACTION_DISABLE: 235 | enable = FALSE; 236 | break; 237 | 238 | case ACTION_ENABLE: 239 | enable = TRUE; 240 | break; 241 | 242 | default: // ACTION_APPLY_QUEUED 243 | enable = pHook->queueEnable; 244 | break; 245 | } 246 | if (pHook->isEnabled == enable) 247 | continue; 248 | 249 | if (enable) 250 | ip = FindNewIP(pHook, *pIP); 251 | else 252 | ip = FindOldIP(pHook, *pIP); 253 | 254 | if (ip != 0) 255 | { 256 | *pIP = ip; 257 | SetThreadContext(hThread, &c); 258 | } 259 | } 260 | } 261 | 262 | //------------------------------------------------------------------------- 263 | static BOOL EnumerateThreads(PFROZEN_THREADS pThreads) 264 | { 265 | BOOL succeeded = FALSE; 266 | 267 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 268 | if (hSnapshot != INVALID_HANDLE_VALUE) 269 | { 270 | THREADENTRY32 te; 271 | te.dwSize = sizeof(THREADENTRY32); 272 | if (Thread32First(hSnapshot, &te)) 273 | { 274 | succeeded = TRUE; 275 | do 276 | { 277 | if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) 278 | && te.th32OwnerProcessID == GetCurrentProcessId() 279 | && te.th32ThreadID != GetCurrentThreadId()) 280 | { 281 | if (pThreads->pItems == NULL) 282 | { 283 | pThreads->capacity = INITIAL_THREAD_CAPACITY; 284 | pThreads->pItems 285 | = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD)); 286 | if (pThreads->pItems == NULL) 287 | { 288 | succeeded = FALSE; 289 | break; 290 | } 291 | } 292 | else if (pThreads->size >= pThreads->capacity) 293 | { 294 | pThreads->capacity *= 2; 295 | LPDWORD p = (LPDWORD)HeapReAlloc( 296 | g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(DWORD)); 297 | if (p == NULL) 298 | { 299 | succeeded = FALSE; 300 | break; 301 | } 302 | 303 | pThreads->pItems = p; 304 | } 305 | pThreads->pItems[pThreads->size++] = te.th32ThreadID; 306 | } 307 | 308 | te.dwSize = sizeof(THREADENTRY32); 309 | } while (Thread32Next(hSnapshot, &te)); 310 | 311 | if (succeeded && GetLastError() != ERROR_NO_MORE_FILES) 312 | succeeded = FALSE; 313 | 314 | if (!succeeded && pThreads->pItems != NULL) 315 | { 316 | HeapFree(g_hHeap, 0, pThreads->pItems); 317 | pThreads->pItems = NULL; 318 | } 319 | } 320 | CloseHandle(hSnapshot); 321 | } 322 | 323 | return succeeded; 324 | } 325 | 326 | //------------------------------------------------------------------------- 327 | static MH_STATUS Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action) 328 | { 329 | MH_STATUS status = MH_OK; 330 | 331 | pThreads->pItems = NULL; 332 | pThreads->capacity = 0; 333 | pThreads->size = 0; 334 | if (!EnumerateThreads(pThreads)) 335 | { 336 | status = MH_ERROR_MEMORY_ALLOC; 337 | } 338 | else if (pThreads->pItems != NULL) 339 | { 340 | UINT i; 341 | for (i = 0; i < pThreads->size; ++i) 342 | { 343 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); 344 | if (hThread != NULL) 345 | { 346 | SuspendThread(hThread); 347 | ProcessThreadIPs(hThread, pos, action); 348 | CloseHandle(hThread); 349 | } 350 | } 351 | } 352 | 353 | return status; 354 | } 355 | 356 | //------------------------------------------------------------------------- 357 | static VOID Unfreeze(PFROZEN_THREADS pThreads) 358 | { 359 | if (pThreads->pItems != NULL) 360 | { 361 | UINT i; 362 | for (i = 0; i < pThreads->size; ++i) 363 | { 364 | HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); 365 | if (hThread != NULL) 366 | { 367 | ResumeThread(hThread); 368 | CloseHandle(hThread); 369 | } 370 | } 371 | 372 | HeapFree(g_hHeap, 0, pThreads->pItems); 373 | } 374 | } 375 | 376 | //------------------------------------------------------------------------- 377 | static MH_STATUS EnableHookLL(UINT pos, BOOL enable) 378 | { 379 | PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; 380 | DWORD oldProtect; 381 | SIZE_T patchSize = sizeof(JMP_REL); 382 | LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; 383 | 384 | if (pHook->patchAbove) 385 | { 386 | pPatchTarget -= sizeof(JMP_REL); 387 | patchSize += sizeof(JMP_REL_SHORT); 388 | } 389 | 390 | if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) 391 | return MH_ERROR_MEMORY_PROTECT; 392 | 393 | if (enable) 394 | { 395 | PJMP_REL pJmp = (PJMP_REL)pPatchTarget; 396 | pJmp->opcode = 0xE9; 397 | pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL))); 398 | 399 | if (pHook->patchAbove) 400 | { 401 | PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; 402 | pShortJmp->opcode = 0xEB; 403 | pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL))); 404 | } 405 | } 406 | else 407 | { 408 | if (pHook->patchAbove) 409 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); 410 | else 411 | memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); 412 | } 413 | 414 | VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); 415 | 416 | // Just-in-case measure. 417 | FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); 418 | 419 | pHook->isEnabled = enable; 420 | pHook->queueEnable = enable; 421 | 422 | return MH_OK; 423 | } 424 | 425 | //------------------------------------------------------------------------- 426 | static MH_STATUS EnableAllHooksLL(BOOL enable) 427 | { 428 | MH_STATUS status = MH_OK; 429 | UINT i, first = INVALID_HOOK_POS; 430 | 431 | for (i = 0; i < g_hooks.size; ++i) 432 | { 433 | if (g_hooks.pItems[i].isEnabled != enable) 434 | { 435 | first = i; 436 | break; 437 | } 438 | } 439 | 440 | if (first != INVALID_HOOK_POS) 441 | { 442 | FROZEN_THREADS threads; 443 | status = Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE); 444 | if (status == MH_OK) 445 | { 446 | for (i = first; i < g_hooks.size; ++i) 447 | { 448 | if (g_hooks.pItems[i].isEnabled != enable) 449 | { 450 | status = EnableHookLL(i, enable); 451 | if (status != MH_OK) 452 | break; 453 | } 454 | } 455 | 456 | Unfreeze(&threads); 457 | } 458 | } 459 | 460 | return status; 461 | } 462 | 463 | //------------------------------------------------------------------------- 464 | static VOID EnterSpinLock(VOID) 465 | { 466 | SIZE_T spinCount = 0; 467 | 468 | // Wait until the flag is FALSE. 469 | while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE) 470 | { 471 | // No need to generate a memory barrier here, since InterlockedCompareExchange() 472 | // generates a full memory barrier itself. 473 | 474 | // Prevent the loop from being too busy. 475 | if (spinCount < 32) 476 | Sleep(0); 477 | else 478 | Sleep(1); 479 | 480 | spinCount++; 481 | } 482 | } 483 | 484 | //------------------------------------------------------------------------- 485 | static VOID LeaveSpinLock(VOID) 486 | { 487 | // No need to generate a memory barrier here, since InterlockedExchange() 488 | // generates a full memory barrier itself. 489 | 490 | InterlockedExchange(&g_isLocked, FALSE); 491 | } 492 | 493 | //------------------------------------------------------------------------- 494 | MH_STATUS WINAPI MH_Initialize(VOID) 495 | { 496 | MH_STATUS status = MH_OK; 497 | 498 | EnterSpinLock(); 499 | 500 | if (g_hHeap == NULL) 501 | { 502 | g_hHeap = HeapCreate(0, 0, 0); 503 | if (g_hHeap != NULL) 504 | { 505 | // Initialize the internal function buffer. 506 | InitializeBuffer(); 507 | } 508 | else 509 | { 510 | status = MH_ERROR_MEMORY_ALLOC; 511 | } 512 | } 513 | else 514 | { 515 | status = MH_ERROR_ALREADY_INITIALIZED; 516 | } 517 | 518 | LeaveSpinLock(); 519 | 520 | return status; 521 | } 522 | 523 | //------------------------------------------------------------------------- 524 | MH_STATUS WINAPI MH_Uninitialize(VOID) 525 | { 526 | MH_STATUS status = MH_OK; 527 | 528 | EnterSpinLock(); 529 | 530 | if (g_hHeap != NULL) 531 | { 532 | status = EnableAllHooksLL(FALSE); 533 | if (status == MH_OK) 534 | { 535 | // Free the internal function buffer. 536 | 537 | // HeapFree is actually not required, but some tools detect a false 538 | // memory leak without HeapFree. 539 | 540 | UninitializeBuffer(); 541 | 542 | HeapFree(g_hHeap, 0, g_hooks.pItems); 543 | HeapDestroy(g_hHeap); 544 | 545 | g_hHeap = NULL; 546 | 547 | g_hooks.pItems = NULL; 548 | g_hooks.capacity = 0; 549 | g_hooks.size = 0; 550 | } 551 | } 552 | else 553 | { 554 | status = MH_ERROR_NOT_INITIALIZED; 555 | } 556 | 557 | LeaveSpinLock(); 558 | 559 | return status; 560 | } 561 | 562 | //------------------------------------------------------------------------- 563 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) 564 | { 565 | MH_STATUS status = MH_OK; 566 | 567 | EnterSpinLock(); 568 | 569 | if (g_hHeap != NULL) 570 | { 571 | if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) 572 | { 573 | UINT pos = FindHookEntry(pTarget); 574 | if (pos == INVALID_HOOK_POS) 575 | { 576 | LPVOID pBuffer = AllocateBuffer(pTarget); 577 | if (pBuffer != NULL) 578 | { 579 | TRAMPOLINE ct; 580 | 581 | ct.pTarget = pTarget; 582 | ct.pDetour = pDetour; 583 | ct.pTrampoline = pBuffer; 584 | if (CreateTrampolineFunction(&ct)) 585 | { 586 | PHOOK_ENTRY pHook = AddHookEntry(); 587 | if (pHook != NULL) 588 | { 589 | pHook->pTarget = ct.pTarget; 590 | #if defined(_M_X64) || defined(__x86_64__) 591 | pHook->pDetour = ct.pRelay; 592 | #else 593 | pHook->pDetour = ct.pDetour; 594 | #endif 595 | pHook->pTrampoline = ct.pTrampoline; 596 | pHook->patchAbove = ct.patchAbove; 597 | pHook->isEnabled = FALSE; 598 | pHook->queueEnable = FALSE; 599 | pHook->nIP = ct.nIP; 600 | memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); 601 | memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); 602 | 603 | // Back up the target function. 604 | 605 | if (ct.patchAbove) 606 | { 607 | memcpy( 608 | pHook->backup, 609 | (LPBYTE)pTarget - sizeof(JMP_REL), 610 | sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); 611 | } 612 | else 613 | { 614 | memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); 615 | } 616 | 617 | if (ppOriginal != NULL) 618 | *ppOriginal = pHook->pTrampoline; 619 | } 620 | else 621 | { 622 | status = MH_ERROR_MEMORY_ALLOC; 623 | } 624 | } 625 | else 626 | { 627 | status = MH_ERROR_UNSUPPORTED_FUNCTION; 628 | } 629 | 630 | if (status != MH_OK) 631 | { 632 | FreeBuffer(pBuffer); 633 | } 634 | } 635 | else 636 | { 637 | status = MH_ERROR_MEMORY_ALLOC; 638 | } 639 | } 640 | else 641 | { 642 | status = MH_ERROR_ALREADY_CREATED; 643 | } 644 | } 645 | else 646 | { 647 | status = MH_ERROR_NOT_EXECUTABLE; 648 | } 649 | } 650 | else 651 | { 652 | status = MH_ERROR_NOT_INITIALIZED; 653 | } 654 | 655 | LeaveSpinLock(); 656 | 657 | return status; 658 | } 659 | 660 | //------------------------------------------------------------------------- 661 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) 662 | { 663 | MH_STATUS status = MH_OK; 664 | 665 | EnterSpinLock(); 666 | 667 | if (g_hHeap != NULL) 668 | { 669 | UINT pos = FindHookEntry(pTarget); 670 | if (pos != INVALID_HOOK_POS) 671 | { 672 | if (g_hooks.pItems[pos].isEnabled) 673 | { 674 | FROZEN_THREADS threads; 675 | status = Freeze(&threads, pos, ACTION_DISABLE); 676 | if (status == MH_OK) 677 | { 678 | status = EnableHookLL(pos, FALSE); 679 | 680 | Unfreeze(&threads); 681 | } 682 | } 683 | 684 | if (status == MH_OK) 685 | { 686 | FreeBuffer(g_hooks.pItems[pos].pTrampoline); 687 | DeleteHookEntry(pos); 688 | } 689 | } 690 | else 691 | { 692 | status = MH_ERROR_NOT_CREATED; 693 | } 694 | } 695 | else 696 | { 697 | status = MH_ERROR_NOT_INITIALIZED; 698 | } 699 | 700 | LeaveSpinLock(); 701 | 702 | return status; 703 | } 704 | 705 | //------------------------------------------------------------------------- 706 | static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) 707 | { 708 | MH_STATUS status = MH_OK; 709 | 710 | EnterSpinLock(); 711 | 712 | if (g_hHeap != NULL) 713 | { 714 | if (pTarget == MH_ALL_HOOKS) 715 | { 716 | status = EnableAllHooksLL(enable); 717 | } 718 | else 719 | { 720 | UINT pos = FindHookEntry(pTarget); 721 | if (pos != INVALID_HOOK_POS) 722 | { 723 | if (g_hooks.pItems[pos].isEnabled != enable) 724 | { 725 | FROZEN_THREADS threads; 726 | status = Freeze(&threads, pos, ACTION_ENABLE); 727 | if (status == MH_OK) 728 | { 729 | status = EnableHookLL(pos, enable); 730 | 731 | Unfreeze(&threads); 732 | } 733 | } 734 | else 735 | { 736 | status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; 737 | } 738 | } 739 | else 740 | { 741 | status = MH_ERROR_NOT_CREATED; 742 | } 743 | } 744 | } 745 | else 746 | { 747 | status = MH_ERROR_NOT_INITIALIZED; 748 | } 749 | 750 | LeaveSpinLock(); 751 | 752 | return status; 753 | } 754 | 755 | //------------------------------------------------------------------------- 756 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) 757 | { 758 | return EnableHook(pTarget, TRUE); 759 | } 760 | 761 | //------------------------------------------------------------------------- 762 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) 763 | { 764 | return EnableHook(pTarget, FALSE); 765 | } 766 | 767 | //------------------------------------------------------------------------- 768 | static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) 769 | { 770 | MH_STATUS status = MH_OK; 771 | 772 | EnterSpinLock(); 773 | 774 | if (g_hHeap != NULL) 775 | { 776 | if (pTarget == MH_ALL_HOOKS) 777 | { 778 | UINT i; 779 | for (i = 0; i < g_hooks.size; ++i) 780 | g_hooks.pItems[i].queueEnable = queueEnable; 781 | } 782 | else 783 | { 784 | UINT pos = FindHookEntry(pTarget); 785 | if (pos != INVALID_HOOK_POS) 786 | { 787 | g_hooks.pItems[pos].queueEnable = queueEnable; 788 | } 789 | else 790 | { 791 | status = MH_ERROR_NOT_CREATED; 792 | } 793 | } 794 | } 795 | else 796 | { 797 | status = MH_ERROR_NOT_INITIALIZED; 798 | } 799 | 800 | LeaveSpinLock(); 801 | 802 | return status; 803 | } 804 | 805 | //------------------------------------------------------------------------- 806 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) 807 | { 808 | return QueueHook(pTarget, TRUE); 809 | } 810 | 811 | //------------------------------------------------------------------------- 812 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) 813 | { 814 | return QueueHook(pTarget, FALSE); 815 | } 816 | 817 | //------------------------------------------------------------------------- 818 | MH_STATUS WINAPI MH_ApplyQueued(VOID) 819 | { 820 | MH_STATUS status = MH_OK; 821 | UINT i, first = INVALID_HOOK_POS; 822 | 823 | EnterSpinLock(); 824 | 825 | if (g_hHeap != NULL) 826 | { 827 | for (i = 0; i < g_hooks.size; ++i) 828 | { 829 | if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) 830 | { 831 | first = i; 832 | break; 833 | } 834 | } 835 | 836 | if (first != INVALID_HOOK_POS) 837 | { 838 | FROZEN_THREADS threads; 839 | status = Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); 840 | if (status == MH_OK) 841 | { 842 | for (i = first; i < g_hooks.size; ++i) 843 | { 844 | PHOOK_ENTRY pHook = &g_hooks.pItems[i]; 845 | if (pHook->isEnabled != pHook->queueEnable) 846 | { 847 | status = EnableHookLL(i, pHook->queueEnable); 848 | if (status != MH_OK) 849 | break; 850 | } 851 | } 852 | 853 | Unfreeze(&threads); 854 | } 855 | } 856 | } 857 | else 858 | { 859 | status = MH_ERROR_NOT_INITIALIZED; 860 | } 861 | 862 | LeaveSpinLock(); 863 | 864 | return status; 865 | } 866 | 867 | //------------------------------------------------------------------------- 868 | MH_STATUS WINAPI MH_CreateHookApiEx( 869 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, 870 | LPVOID *ppOriginal, LPVOID *ppTarget) 871 | { 872 | HMODULE hModule; 873 | LPVOID pTarget; 874 | 875 | hModule = GetModuleHandleW(pszModule); 876 | if (hModule == NULL) 877 | return MH_ERROR_MODULE_NOT_FOUND; 878 | 879 | pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); 880 | if (pTarget == NULL) 881 | return MH_ERROR_FUNCTION_NOT_FOUND; 882 | 883 | if(ppTarget != NULL) 884 | *ppTarget = pTarget; 885 | 886 | return MH_CreateHook(pTarget, pDetour, ppOriginal); 887 | } 888 | 889 | //------------------------------------------------------------------------- 890 | MH_STATUS WINAPI MH_CreateHookApi( 891 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) 892 | { 893 | return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); 894 | } 895 | 896 | //------------------------------------------------------------------------- 897 | const char * WINAPI MH_StatusToString(MH_STATUS status) 898 | { 899 | #define MH_ST2STR(x) \ 900 | case x: \ 901 | return #x; 902 | 903 | switch (status) { 904 | MH_ST2STR(MH_UNKNOWN) 905 | MH_ST2STR(MH_OK) 906 | MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) 907 | MH_ST2STR(MH_ERROR_NOT_INITIALIZED) 908 | MH_ST2STR(MH_ERROR_ALREADY_CREATED) 909 | MH_ST2STR(MH_ERROR_NOT_CREATED) 910 | MH_ST2STR(MH_ERROR_ENABLED) 911 | MH_ST2STR(MH_ERROR_DISABLED) 912 | MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) 913 | MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) 914 | MH_ST2STR(MH_ERROR_MEMORY_ALLOC) 915 | MH_ST2STR(MH_ERROR_MEMORY_PROTECT) 916 | MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) 917 | MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) 918 | } 919 | 920 | #undef MH_ST2STR 921 | 922 | return "(unknown)"; 923 | } 924 | -------------------------------------------------------------------------------- /dependencies/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 | #include 30 | 31 | #ifdef _MSC_VER 32 | #include 33 | #endif 34 | 35 | #ifndef ARRAYSIZE 36 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 37 | #endif 38 | 39 | #if defined(_M_X64) || defined(__x86_64__) 40 | #include "./hde/hde64.h" 41 | typedef hde64s HDE; 42 | #define HDE_DISASM(code, hs) hde64_disasm(code, hs) 43 | #else 44 | #include "./hde/hde32.h" 45 | typedef hde32s HDE; 46 | #define HDE_DISASM(code, hs) hde32_disasm(code, hs) 47 | #endif 48 | 49 | #include "trampoline.h" 50 | #include "buffer.h" 51 | 52 | // Maximum size of a trampoline function. 53 | #if defined(_M_X64) || defined(__x86_64__) 54 | #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) 55 | #else 56 | #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE 57 | #endif 58 | 59 | //------------------------------------------------------------------------- 60 | static BOOL IsCodePadding(LPBYTE pInst, UINT size) 61 | { 62 | UINT i; 63 | 64 | if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) 65 | return FALSE; 66 | 67 | for (i = 1; i < size; ++i) 68 | { 69 | if (pInst[i] != pInst[0]) 70 | return FALSE; 71 | } 72 | return TRUE; 73 | } 74 | 75 | //------------------------------------------------------------------------- 76 | BOOL CreateTrampolineFunction(PTRAMPOLINE ct) 77 | { 78 | #if defined(_M_X64) || defined(__x86_64__) 79 | CALL_ABS call = { 80 | 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] 81 | 0xEB, 0x08, // EB 08: JMP +10 82 | 0x0000000000000000ULL // Absolute destination address 83 | }; 84 | JMP_ABS jmp = { 85 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 86 | 0x0000000000000000ULL // Absolute destination address 87 | }; 88 | JCC_ABS jcc = { 89 | 0x70, 0x0E, // 7* 0E: J** +16 90 | 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 91 | 0x0000000000000000ULL // Absolute destination address 92 | }; 93 | #else 94 | CALL_REL call = { 95 | 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx 96 | 0x00000000 // Relative destination address 97 | }; 98 | JMP_REL jmp = { 99 | 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx 100 | 0x00000000 // Relative destination address 101 | }; 102 | JCC_REL jcc = { 103 | 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx 104 | 0x00000000 // Relative destination address 105 | }; 106 | #endif 107 | 108 | UINT8 oldPos = 0; 109 | UINT8 newPos = 0; 110 | ULONG_PTR jmpDest = 0; // Destination address of an internal jump. 111 | BOOL finished = FALSE; // Is the function completed? 112 | #if defined(_M_X64) || defined(__x86_64__) 113 | UINT8 instBuf[16]; 114 | #endif 115 | 116 | ct->patchAbove = FALSE; 117 | ct->nIP = 0; 118 | 119 | do 120 | { 121 | HDE hs; 122 | UINT copySize; 123 | LPVOID pCopySrc; 124 | ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; 125 | ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; 126 | 127 | copySize = HDE_DISASM((LPVOID)pOldInst, &hs); 128 | if (hs.flags & F_ERROR) 129 | return FALSE; 130 | 131 | pCopySrc = (LPVOID)pOldInst; 132 | if (oldPos >= sizeof(JMP_REL)) 133 | { 134 | // The trampoline function is long enough. 135 | // Complete the function with the jump to the target function. 136 | #if defined(_M_X64) || defined(__x86_64__) 137 | jmp.address = pOldInst; 138 | #else 139 | jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); 140 | #endif 141 | pCopySrc = &jmp; 142 | copySize = sizeof(jmp); 143 | 144 | finished = TRUE; 145 | } 146 | #if defined(_M_X64) || defined(__x86_64__) 147 | else if ((hs.modrm & 0xC7) == 0x05) 148 | { 149 | // Instructions using RIP relative addressing. (ModR/M = 00???101B) 150 | 151 | // Modify the RIP relative address. 152 | PUINT32 pRelAddr; 153 | 154 | // Avoid using memcpy to reduce the footprint. 155 | #ifndef _MSC_VER 156 | memcpy(instBuf, (LPBYTE)pOldInst, copySize); 157 | #else 158 | __movsb(instBuf, (LPBYTE)pOldInst, copySize); 159 | #endif 160 | pCopySrc = instBuf; 161 | 162 | // Relative address is stored at (instruction length - immediate value length - 4). 163 | pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); 164 | *pRelAddr 165 | = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); 166 | 167 | // Complete the function if JMP (FF /4). 168 | if (hs.opcode == 0xFF && hs.modrm_reg == 4) 169 | finished = TRUE; 170 | } 171 | #endif 172 | else if (hs.opcode == 0xE8) 173 | { 174 | // Direct relative CALL 175 | ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; 176 | #if defined(_M_X64) || defined(__x86_64__) 177 | call.address = dest; 178 | #else 179 | call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); 180 | #endif 181 | pCopySrc = &call; 182 | copySize = sizeof(call); 183 | } 184 | else if ((hs.opcode & 0xFD) == 0xE9) 185 | { 186 | // Direct relative JMP (EB or E9) 187 | ULONG_PTR dest = pOldInst + hs.len; 188 | 189 | if (hs.opcode == 0xEB) // isShort jmp 190 | dest += (INT8)hs.imm.imm8; 191 | else 192 | dest += (INT32)hs.imm.imm32; 193 | 194 | // Simply copy an internal jump. 195 | if ((ULONG_PTR)ct->pTarget <= dest 196 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 197 | { 198 | if (jmpDest < dest) 199 | jmpDest = dest; 200 | } 201 | else 202 | { 203 | #if defined(_M_X64) || defined(__x86_64__) 204 | jmp.address = dest; 205 | #else 206 | jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); 207 | #endif 208 | pCopySrc = &jmp; 209 | copySize = sizeof(jmp); 210 | 211 | // Exit the function if it is not in the branch. 212 | finished = (pOldInst >= jmpDest); 213 | } 214 | } 215 | else if ((hs.opcode & 0xF0) == 0x70 216 | || (hs.opcode & 0xFC) == 0xE0 217 | || (hs.opcode2 & 0xF0) == 0x80) 218 | { 219 | // Direct relative Jcc 220 | ULONG_PTR dest = pOldInst + hs.len; 221 | 222 | if ((hs.opcode & 0xF0) == 0x70 // Jcc 223 | || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ 224 | dest += (INT8)hs.imm.imm8; 225 | else 226 | dest += (INT32)hs.imm.imm32; 227 | 228 | // Simply copy an internal jump. 229 | if ((ULONG_PTR)ct->pTarget <= dest 230 | && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) 231 | { 232 | if (jmpDest < dest) 233 | jmpDest = dest; 234 | } 235 | else if ((hs.opcode & 0xFC) == 0xE0) 236 | { 237 | // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. 238 | return FALSE; 239 | } 240 | else 241 | { 242 | UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); 243 | #if defined(_M_X64) || defined(__x86_64__) 244 | // Invert the condition in x64 mode to simplify the conditional jump logic. 245 | jcc.opcode = 0x71 ^ cond; 246 | jcc.address = dest; 247 | #else 248 | jcc.opcode1 = 0x80 | cond; 249 | jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); 250 | #endif 251 | pCopySrc = &jcc; 252 | copySize = sizeof(jcc); 253 | } 254 | } 255 | else if ((hs.opcode & 0xFE) == 0xC2) 256 | { 257 | // RET (C2 or C3) 258 | 259 | // Complete the function if not in a branch. 260 | finished = (pOldInst >= jmpDest); 261 | } 262 | 263 | // Can't alter the instruction length in a branch. 264 | if (pOldInst < jmpDest && copySize != hs.len) 265 | return FALSE; 266 | 267 | // Trampoline function is too large. 268 | if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) 269 | return FALSE; 270 | 271 | // Trampoline function has too many instructions. 272 | if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) 273 | return FALSE; 274 | 275 | ct->oldIPs[ct->nIP] = oldPos; 276 | ct->newIPs[ct->nIP] = newPos; 277 | ct->nIP++; 278 | 279 | // Avoid using memcpy to reduce the footprint. 280 | #ifndef _MSC_VER 281 | memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); 282 | #else 283 | __movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize); 284 | #endif 285 | newPos += copySize; 286 | oldPos += hs.len; 287 | } 288 | while (!finished); 289 | 290 | // Is there enough place for a long jump? 291 | if (oldPos < sizeof(JMP_REL) 292 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) 293 | { 294 | // Is there enough place for a short jump? 295 | if (oldPos < sizeof(JMP_REL_SHORT) 296 | && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) 297 | { 298 | return FALSE; 299 | } 300 | 301 | // Can we place the long jump above the function? 302 | if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) 303 | return FALSE; 304 | 305 | if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) 306 | return FALSE; 307 | 308 | ct->patchAbove = TRUE; 309 | } 310 | 311 | #if defined(_M_X64) || defined(__x86_64__) 312 | // Create a relay function. 313 | jmp.address = (ULONG_PTR)ct->pDetour; 314 | 315 | ct->pRelay = (LPBYTE)ct->pTrampoline + newPos; 316 | memcpy(ct->pRelay, &jmp, sizeof(jmp)); 317 | #endif 318 | 319 | return TRUE; 320 | } 321 | -------------------------------------------------------------------------------- /dependencies/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 | -------------------------------------------------------------------------------- /device.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "device.h" 4 | 5 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND window, UINT message, WPARAM wideParam, LPARAM longParam); 6 | 7 | namespace Device 8 | { 9 | using PresentFn = HRESULT(__stdcall*) (IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags); 10 | using ResizeBuffersFn = HRESULT(__stdcall*) (IDXGISwapChain* pSwapChain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); 11 | 12 | PresentFn oPresent = nullptr; 13 | ResizeBuffersFn oResizeBuffers = nullptr; 14 | 15 | LRESULT WINAPI WndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 16 | { 17 | if (globals::Unload) 18 | return CallWindowProc(oWndProc, hWnd, uMsg, wParam, lParam); 19 | if (uMsg == WM_KEYUP && wParam == VK_INSERT) 20 | { 21 | globals::ShowMenu = !globals::ShowMenu; 22 | } 23 | if (uMsg == WM_KEYUP && wParam == VK_F12) 24 | { 25 | globals::Unload = true; 26 | } 27 | ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam); 28 | if (!globals::ShowMenu) 29 | return CallWindowProc(oWndProc, hWnd, uMsg, wParam, lParam); 30 | return true; 31 | } 32 | 33 | HRESULT Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) 34 | { 35 | if (globals::Unload) 36 | return oPresent(pSwapChain, SyncInterval, Flags); 37 | static auto bMakeOnce = [&]()->bool 38 | { 39 | if (FAILED(pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&pDevice))) 40 | { 41 | return false; 42 | } 43 | pDevice->GetImmediateContext(&pContext); 44 | DXGI_SWAP_CHAIN_DESC sd; 45 | pSwapChain->GetDesc(&sd); 46 | hWnd = sd.OutputWindow; 47 | ID3D11Texture2D* pBackBuffer = NULL; 48 | pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); 49 | D3D11_RENDER_TARGET_VIEW_DESC desc = {}; 50 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 51 | desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; 52 | pDevice->CreateRenderTargetView(pBackBuffer, &desc, &mainRenderTargetView); 53 | pBackBuffer->Release(); 54 | oWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc); 55 | ImGui::CreateContext(); 56 | ImGui::GetIO().IniFilename = "gui.ini"; 57 | ImGui::GetIO().LogFilename = nullptr; 58 | ImGui::GetStyle().FrameRounding = 3.0f; 59 | ImGui::GetStyle().WindowRounding = 2.0f; 60 | ImGui::GetStyle().GrabRounding = 2.0f; 61 | ImGui::GetStyle().WindowRounding = 3.0f; 62 | ImGui::GetStyle().WindowTitleAlign = { 0.5f ,0.5f }; 63 | { 64 | ImGuiStyle* style = &ImGui::GetStyle(); 65 | ImVec4* colors = style->Colors; 66 | colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 67 | colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 68 | colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); 69 | colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 70 | colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); 71 | colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); 72 | colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 73 | colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.54f); 74 | colors[ImGuiCol_FrameBgHovered] = ImVec4(0.28f, 0.28f, 0.28f, 0.40f); 75 | colors[ImGuiCol_FrameBgActive] = ImVec4(0.17f, 0.17f, 0.17f, 0.67f); 76 | colors[ImGuiCol_TitleBg] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); 77 | colors[ImGuiCol_TitleBgActive] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); 78 | colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.22f, 0.22f, 0.22f, 0.51f); 79 | colors[ImGuiCol_MenuBarBg] = ImVec4(0.26f, 0.26f, 0.26f, 1.00f); 80 | colors[ImGuiCol_ScrollbarBg] = ImVec4(0.14f, 0.14f, 0.14f, 0.53f); 81 | colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); 82 | colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); 83 | colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); 84 | colors[ImGuiCol_CheckMark] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f); 85 | colors[ImGuiCol_SliderGrab] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f); 86 | colors[ImGuiCol_SliderGrabActive] = ImVec4(0.45f, 0.45f, 0.45f, 1.00f); 87 | colors[ImGuiCol_Button] = ImVec4(0.44f, 0.44f, 0.44f, 0.40f); 88 | colors[ImGuiCol_ButtonHovered] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); 89 | colors[ImGuiCol_ButtonActive] = ImVec4(0.27f, 0.27f, 0.27f, 1.00f); 90 | colors[ImGuiCol_Header] = ImVec4(0.46f, 0.46f, 0.46f, 0.31f); 91 | colors[ImGuiCol_HeaderHovered] = ImVec4(0.32f, 0.32f, 0.32f, 0.80f); 92 | colors[ImGuiCol_HeaderActive] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); 93 | colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; 94 | colors[ImGuiCol_SeparatorHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.78f); 95 | colors[ImGuiCol_SeparatorActive] = ImVec4(0.71f, 0.71f, 0.71f, 1.00f); 96 | colors[ImGuiCol_ResizeGrip] = ImVec4(0.71f, 0.71f, 0.71f, 0.20f); 97 | colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.56f, 0.56f, 0.56f, 0.67f); 98 | colors[ImGuiCol_ResizeGripActive] = ImVec4(0.43f, 0.43f, 0.43f, 0.95f); 99 | colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.40f); 100 | colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; 101 | colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.80f); 102 | colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); 103 | colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); 104 | colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); 105 | colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.92f, 0.92f, 0.92f, 1.00f); 106 | colors[ImGuiCol_PlotHistogram] = ImVec4(0.43f, 0.43f, 0.43f, 1.00f); 107 | colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); 108 | colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); 109 | colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); 110 | colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); 111 | colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 112 | colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); 113 | colors[ImGuiCol_TextSelectedBg] = ImVec4(0.36f, 0.36f, 0.36f, 0.35f); 114 | colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 115 | colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.26f, 0.26f, 1.00f); 116 | colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 117 | colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); 118 | colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); 119 | } 120 | ImGui_ImplWin32_Init(hWnd); 121 | ImGui_ImplDX11_Init(pDevice, pContext); 122 | ImGui::GetIO().Fonts->AddFontFromFileTTF("c:\\windows\\fonts\\msyh.ttc", 16, NULL, ImGui::GetIO().Fonts->GetGlyphRangesChineseFull()); 123 | 124 | //PacketSniffer::Setup(); 125 | 126 | return true; 127 | } (); 128 | ImGui_ImplDX11_NewFrame(); 129 | ImGui_ImplWin32_NewFrame(); 130 | ImGui::NewFrame(); 131 | ImGui::Render(); 132 | pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL); 133 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 134 | return oPresent(pSwapChain, SyncInterval, Flags); 135 | } 136 | 137 | HRESULT ResizeBuffers(IDXGISwapChain* pSwapChain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) 138 | { 139 | if (globals::Unload) 140 | return oResizeBuffers(pSwapChain, BufferCount, Width, Height, NewFormat, SwapChainFlags); 141 | if (mainRenderTargetView) 142 | { 143 | pContext->OMSetRenderTargets(0, 0, 0); 144 | mainRenderTargetView->Release(); 145 | mainRenderTargetView = NULL; 146 | } 147 | HRESULT hr = oResizeBuffers(pSwapChain, BufferCount, Width, Height, NewFormat, SwapChainFlags); 148 | ID3D11Texture2D* pBuffer = NULL; 149 | pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBuffer); 150 | pDevice->CreateRenderTargetView(pBuffer, nullptr, &mainRenderTargetView); 151 | pBuffer->Release(); 152 | pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL); 153 | D3D11_VIEWPORT vp; 154 | vp.Width = Width; 155 | vp.Height = Height; 156 | vp.MinDepth = 0.0f; 157 | vp.MaxDepth = 1.0f; 158 | vp.TopLeftX = 0; 159 | vp.TopLeftY = 0; 160 | pContext->RSSetViewports(1, &vp); 161 | return hr; 162 | } 163 | 164 | bool Setup() 165 | { 166 | if (MH_Initialize() != MH_OK) 167 | return false; 168 | static auto CreateHook = [](LPVOID pTarget, LPVOID pDetour, LPVOID* ppOriginal)->bool 169 | { 170 | return MH_CreateHook(pTarget, pDetour, ppOriginal) == MH_OK && MH_EnableHook(pTarget) == MH_OK; 171 | }; 172 | if (!CreateHook(Direct3D.Present, Device::Present, reinterpret_cast(&Device::oPresent))) 173 | return false; 174 | if (!CreateHook(Direct3D.ResizeBuffers, Device::ResizeBuffers, reinterpret_cast(&Device::oResizeBuffers))) 175 | return false; 176 | return true; 177 | } 178 | } -------------------------------------------------------------------------------- /globals.cpp: -------------------------------------------------------------------------------- 1 | #include "globals.h" 2 | 3 | namespace globals { 4 | bool ShowMenu = true; 5 | bool Unload = false; 6 | bool Init = false; 7 | } -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS 2 | 3 | #include "core.hpp" 4 | 5 | namespace anti_cheat { 6 | typedef HANDLE(WINAPI* CREATE_FILE_W)(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); 7 | CREATE_FILE_W p_CreateFileW = nullptr; 8 | CREATE_FILE_W t_CreateFileW; 9 | 10 | HANDLE WINAPI h_CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) 11 | { 12 | if (memcmp(lpFileName, L"\\\\.\\ACE-BASE", 24) == 0) { 13 | wprintf(L"Thread (%i) attempting to communicate with anti-cheat driver -> %s\n", GetCurrentThreadId(), lpFileName); 14 | 15 | SuspendThread(GetCurrentThread()); // 200iq bypass for memory protection 16 | } 17 | 18 | return p_CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 19 | } 20 | 21 | void Setup(uint64_t srbase) { 22 | if (MH_Initialize() != MH_OK) 23 | { 24 | puts("Error initializing MinHook library"); 25 | 26 | return; 27 | } 28 | 29 | if (MH_CreateHookApiEx(L"kernelbase", "CreateFileW", &anti_cheat::h_CreateFileW, reinterpret_cast(&p_CreateFileW), reinterpret_cast(&t_CreateFileW)) != MH_OK) 30 | { 31 | puts("Error creating hook for CreateFileW function"); 32 | 33 | return; 34 | } 35 | 36 | if (MH_EnableHook(t_CreateFileW) != MH_OK) 37 | { 38 | puts("Error enabling hook for CreateFileW function"); 39 | 40 | return; 41 | } 42 | 43 | Utils::Write(srbase + 0xFCDC0, 0xCCC3C031); 44 | Utils::Write(srbase + 0xF9940, 0xC3); 45 | Utils::Write(srbase + 0x1BCBA0, 0xFEEB); 46 | } 47 | } 48 | 49 | static HMODULE h_module = 0; 50 | 51 | void Setup() 52 | { 53 | system("cls"); 54 | 55 | if (!Config::LoadConfig(h_module)) 56 | { 57 | // first time user or invalid config 58 | puts("[-] Failed to read config"); 59 | // create new config 60 | Config::SaveConfig(); 61 | puts("[+] Creating new config"); 62 | Sleep(200); 63 | // re-attempt load 64 | puts("[>] Reload to read config"); 65 | if (!Config::LoadConfig(h_module)) 66 | return; 67 | } 68 | 69 | auto base_address = reinterpret_cast(GetModuleHandleA("starrailbase.dll")); 70 | 71 | 72 | 73 | if (Utils::GetTextSectionChecksum(base_address) != 0x1434A1A0) { 74 | 75 | GlobalSetting::ChinaVersion = true; 76 | 77 | puts("[>] China game version detected\n[>] If you don't have the Chinese game version, please create a GitHub issue"); 78 | } 79 | 80 | anti_cheat::Setup(base_address); 81 | puts("After the game opened press enter here"); 82 | system("pause>nul"); 83 | 84 | 85 | 86 | if (!Direct3D.Initialization()) 87 | puts("[-] Failed to setup Direct3D!"); 88 | else 89 | { 90 | puts("[+] Direct3D setup successfully!"); 91 | printf("[>] Direct3D Present: %p\n[>] Direct3D ResizeBuffers: %p\n", Direct3D.Present, Direct3D.ResizeBuffers); 92 | } 93 | if (!Device::Setup()) 94 | puts("[-] Failed to setup device hooks!"); 95 | else 96 | puts("[+] Device hooks setup successfully!"); 97 | 98 | return Cheat::Main(); 99 | } 100 | 101 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 102 | { 103 | 104 | 105 | if (ul_reason_for_call == DLL_PROCESS_ATTACH) 106 | { 107 | h_module = hModule; 108 | 109 | AllocConsole(); 110 | freopen("CONOUT$", "w", stdout); 111 | freopen("CONOUT$", "w", stderr); 112 | freopen("CONIN$", "r", stdin); 113 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Setup, 0, 0, 0); 114 | } 115 | return TRUE; 116 | } --------------------------------------------------------------------------------