├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── external └── kiero │ ├── CMakeLists.txt │ ├── kiero.cpp │ └── kiero.h ├── helpers └── injector.exe └── src ├── common.h ├── hook ├── hook.cpp └── hook.h └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | /.idea/ 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/minhook"] 2 | path = external/minhook 3 | url = https://github.com/TsudaKageyu/minhook 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.25) 2 | project(DirectXPlayground) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h") 7 | 8 | add_library(DirectXPlayground SHARED ${SOURCES}) 9 | 10 | add_subdirectory(external/minhook) 11 | add_subdirectory(external/kiero) 12 | 13 | target_include_directories(DirectXPlayground PRIVATE external/minhook/include) 14 | target_include_directories(DirectXPlayground PRIVATE external/kiero) 15 | 16 | target_link_libraries(DirectXPlayground PRIVATE minhook) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DirectXPlayground 2 | my playground for hooking DirectX in Minecraft for Windows 3 | 4 | ## paster warning 5 | DO NOT USE THIS PROJECT AS A BASE 6 | 7 | this repository is only meant to be used as a resource, and building a client directly from this code would be very impractical 8 | 9 | ## more info 10 | i organized the different experiments into different branches 11 | 12 | right now you're on the main branch, which just has a basic hooking example 13 | -------------------------------------------------------------------------------- /external/kiero/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(DirectXPlayground PRIVATE kiero.cpp kiero.h) -------------------------------------------------------------------------------- /external/kiero/kiero.cpp: -------------------------------------------------------------------------------- 1 | #include "kiero.h" 2 | #include 3 | #include 4 | 5 | #if KIERO_INCLUDE_D3D9 6 | # include 7 | #endif 8 | 9 | #if KIERO_INCLUDE_D3D10 10 | # include 11 | # include 12 | # include 13 | #endif 14 | 15 | #if KIERO_INCLUDE_D3D11 16 | # include 17 | # include 18 | #endif 19 | 20 | #if KIERO_INCLUDE_D3D12 21 | # include 22 | # include 23 | #endif 24 | 25 | #if KIERO_INCLUDE_OPENGL 26 | # include 27 | #endif 28 | 29 | #if KIERO_INCLUDE_VULKAN 30 | # include 31 | #endif 32 | 33 | #if KIERO_USE_MINHOOK 34 | # include 35 | #endif 36 | 37 | #ifdef _UNICODE 38 | # define KIERO_TEXT(text) L##text 39 | #else 40 | # define KIERO_TEXT(text) text 41 | #endif 42 | 43 | #define KIERO_ARRAY_SIZE(arr) ((size_t)(sizeof(arr)/sizeof(arr[0]))) 44 | 45 | static kiero::RenderType::Enum g_renderType = kiero::RenderType::None; 46 | static uint150_t* g_methodsTable = NULL; 47 | 48 | kiero::Status::Enum kiero::init(RenderType::Enum _renderType) 49 | { 50 | if (g_renderType != RenderType::None) 51 | { 52 | return Status::AlreadyInitializedError; 53 | } 54 | 55 | if (_renderType != RenderType::None) 56 | { 57 | if (_renderType >= RenderType::D3D9 && _renderType <= RenderType::D3D12) 58 | { 59 | WNDCLASSEX windowClass; 60 | windowClass.cbSize = sizeof(WNDCLASSEX); 61 | windowClass.style = CS_HREDRAW | CS_VREDRAW; 62 | windowClass.lpfnWndProc = DefWindowProc; 63 | windowClass.cbClsExtra = 0; 64 | windowClass.cbWndExtra = 0; 65 | windowClass.hInstance = GetModuleHandle(NULL); 66 | windowClass.hIcon = NULL; 67 | windowClass.hCursor = NULL; 68 | windowClass.hbrBackground = NULL; 69 | windowClass.lpszMenuName = NULL; 70 | windowClass.lpszClassName = KIERO_TEXT("Kiero"); 71 | windowClass.hIconSm = NULL; 72 | 73 | ::RegisterClassEx(&windowClass); 74 | 75 | HWND window = ::CreateWindow(windowClass.lpszClassName, KIERO_TEXT("Kiero DirectX Window"), WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, windowClass.hInstance, NULL); 76 | 77 | if (_renderType == RenderType::D3D9) 78 | { 79 | #if KIERO_INCLUDE_D3D9 80 | HMODULE libD3D9; 81 | if ((libD3D9 = ::GetModuleHandle(KIERO_TEXT("d3d9.dll"))) == NULL) 82 | { 83 | ::DestroyWindow(window); 84 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 85 | return Status::ModuleNotFoundError; 86 | } 87 | 88 | void* Direct3DCreate9; 89 | if ((Direct3DCreate9 = ::GetProcAddress(libD3D9, "Direct3DCreate9")) == NULL) 90 | { 91 | ::DestroyWindow(window); 92 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 93 | return Status::UnknownError; 94 | } 95 | 96 | LPDIRECT3D9 direct3D9; 97 | if ((direct3D9 = ((LPDIRECT3D9(__stdcall*)(uint32_t))(Direct3DCreate9))(D3D_SDK_VERSION)) == NULL) 98 | { 99 | ::DestroyWindow(window); 100 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 101 | return Status::UnknownError; 102 | } 103 | 104 | D3DPRESENT_PARAMETERS params; 105 | params.BackBufferWidth = 0; 106 | params.BackBufferHeight = 0; 107 | params.BackBufferFormat = D3DFMT_UNKNOWN; 108 | params.BackBufferCount = 0; 109 | params.MultiSampleType = D3DMULTISAMPLE_NONE; 110 | params.MultiSampleQuality = NULL; 111 | params.SwapEffect = D3DSWAPEFFECT_DISCARD; 112 | params.hDeviceWindow = window; 113 | params.Windowed = 1; 114 | params.EnableAutoDepthStencil = 0; 115 | params.AutoDepthStencilFormat = D3DFMT_UNKNOWN; 116 | params.Flags = NULL; 117 | params.FullScreen_RefreshRateInHz = 0; 118 | params.PresentationInterval = 0; 119 | 120 | LPDIRECT3DDEVICE9 device; 121 | if (direct3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT, ¶ms, &device) < 0) 122 | { 123 | direct3D9->Release(); 124 | ::DestroyWindow(window); 125 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 126 | return Status::UnknownError; 127 | } 128 | 129 | g_methodsTable = (uint150_t*)::calloc(119, sizeof(uint150_t)); 130 | ::memcpy(g_methodsTable, *(uint150_t**)device, 119 * sizeof(uint150_t)); 131 | 132 | #if KIERO_USE_MINHOOK 133 | MH_Initialize(); 134 | #endif 135 | 136 | device->Release(); 137 | device = NULL; 138 | 139 | direct3D9->Release(); 140 | direct3D9 = NULL; 141 | 142 | g_renderType = RenderType::D3D9; 143 | 144 | ::DestroyWindow(window); 145 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 146 | 147 | return Status::Success; 148 | #endif 149 | } 150 | else if (_renderType == RenderType::D3D10) 151 | { 152 | #if KIERO_INCLUDE_D3D10 153 | HMODULE libDXGI; 154 | HMODULE libD3D10; 155 | if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL || (libD3D10 = ::GetModuleHandle(KIERO_TEXT("d3d10.dll"))) == NULL) 156 | { 157 | ::DestroyWindow(window); 158 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 159 | return Status::ModuleNotFoundError; 160 | } 161 | 162 | void* CreateDXGIFactory; 163 | if ((CreateDXGIFactory = ::GetProcAddress(libDXGI, "CreateDXGIFactory")) == NULL) 164 | { 165 | ::DestroyWindow(window); 166 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 167 | return Status::UnknownError; 168 | } 169 | 170 | IDXGIFactory* factory; 171 | if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0) 172 | { 173 | ::DestroyWindow(window); 174 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 175 | return Status::UnknownError; 176 | } 177 | 178 | IDXGIAdapter* adapter; 179 | if (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND) 180 | { 181 | ::DestroyWindow(window); 182 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 183 | return Status::UnknownError; 184 | } 185 | 186 | void* D3D10CreateDeviceAndSwapChain; 187 | if ((D3D10CreateDeviceAndSwapChain = ::GetProcAddress(libD3D10, "D3D10CreateDeviceAndSwapChain")) == NULL) 188 | { 189 | ::DestroyWindow(window); 190 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 191 | return Status::UnknownError; 192 | } 193 | 194 | DXGI_RATIONAL refreshRate; 195 | refreshRate.Numerator = 60; 196 | refreshRate.Denominator = 1; 197 | 198 | DXGI_MODE_DESC bufferDesc; 199 | bufferDesc.Width = 100; 200 | bufferDesc.Height = 100; 201 | bufferDesc.RefreshRate = refreshRate; 202 | bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 203 | bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 204 | bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 205 | 206 | DXGI_SAMPLE_DESC sampleDesc; 207 | sampleDesc.Count = 1; 208 | sampleDesc.Quality = 0; 209 | 210 | DXGI_SWAP_CHAIN_DESC swapChainDesc; 211 | swapChainDesc.BufferDesc = bufferDesc; 212 | swapChainDesc.SampleDesc = sampleDesc; 213 | swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 214 | swapChainDesc.BufferCount = 1; 215 | swapChainDesc.OutputWindow = window; 216 | swapChainDesc.Windowed = 1; 217 | swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 218 | swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 219 | 220 | IDXGISwapChain* swapChain; 221 | ID3D10Device* device; 222 | 223 | if (((long(__stdcall*)( 224 | IDXGIAdapter*, 225 | D3D10_DRIVER_TYPE, 226 | HMODULE, 227 | UINT, 228 | UINT, 229 | DXGI_SWAP_CHAIN_DESC*, 230 | IDXGISwapChain**, 231 | ID3D10Device**))(D3D10CreateDeviceAndSwapChain))(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &swapChainDesc, &swapChain, &device) < 0) 232 | { 233 | ::DestroyWindow(window); 234 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 235 | return Status::UnknownError; 236 | } 237 | 238 | g_methodsTable = (uint150_t*)::calloc(116, sizeof(uint150_t)); 239 | ::memcpy(g_methodsTable, *(uint150_t**)swapChain, 18 * sizeof(uint150_t)); 240 | ::memcpy(g_methodsTable + 18, *(uint150_t**)device, 98 * sizeof(uint150_t)); 241 | 242 | #if KIERO_USE_MINHOOK 243 | MH_Initialize(); 244 | #endif 245 | 246 | swapChain->Release(); 247 | swapChain = NULL; 248 | 249 | device->Release(); 250 | device = NULL; 251 | 252 | ::DestroyWindow(window); 253 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 254 | 255 | g_renderType = RenderType::D3D10; 256 | 257 | return Status::Success; 258 | #endif 259 | } 260 | else if (_renderType == RenderType::D3D11) 261 | { 262 | #if KIERO_INCLUDE_D3D11 263 | HMODULE libD3D11; 264 | if ((libD3D11 = ::GetModuleHandle(KIERO_TEXT("d3d11.dll"))) == NULL) 265 | { 266 | ::DestroyWindow(window); 267 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 268 | return Status::ModuleNotFoundError; 269 | } 270 | 271 | void* D3D11CreateDeviceAndSwapChain; 272 | if ((D3D11CreateDeviceAndSwapChain = ::GetProcAddress(libD3D11, "D3D11CreateDeviceAndSwapChain")) == NULL) 273 | { 274 | ::DestroyWindow(window); 275 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 276 | return Status::UnknownError; 277 | } 278 | 279 | D3D_FEATURE_LEVEL featureLevel; 280 | const D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0 }; 281 | 282 | DXGI_RATIONAL refreshRate; 283 | refreshRate.Numerator = 60; 284 | refreshRate.Denominator = 1; 285 | 286 | DXGI_MODE_DESC bufferDesc; 287 | bufferDesc.Width = 100; 288 | bufferDesc.Height = 100; 289 | bufferDesc.RefreshRate = refreshRate; 290 | bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 291 | bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 292 | bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 293 | 294 | DXGI_SAMPLE_DESC sampleDesc; 295 | sampleDesc.Count = 1; 296 | sampleDesc.Quality = 0; 297 | 298 | DXGI_SWAP_CHAIN_DESC swapChainDesc; 299 | swapChainDesc.BufferDesc = bufferDesc; 300 | swapChainDesc.SampleDesc = sampleDesc; 301 | swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 302 | swapChainDesc.BufferCount = 1; 303 | swapChainDesc.OutputWindow = window; 304 | swapChainDesc.Windowed = 1; 305 | swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 306 | swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 307 | 308 | IDXGISwapChain* swapChain; 309 | ID3D11Device* device; 310 | ID3D11DeviceContext* context; 311 | 312 | if (((long(__stdcall*)( 313 | IDXGIAdapter*, 314 | D3D_DRIVER_TYPE, 315 | HMODULE, 316 | UINT, 317 | const D3D_FEATURE_LEVEL*, 318 | UINT, 319 | UINT, 320 | const DXGI_SWAP_CHAIN_DESC*, 321 | IDXGISwapChain**, 322 | ID3D11Device**, 323 | D3D_FEATURE_LEVEL*, 324 | ID3D11DeviceContext**))(D3D11CreateDeviceAndSwapChain))(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 2, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, &featureLevel, &context) < 0) 325 | { 326 | ::DestroyWindow(window); 327 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 328 | return Status::UnknownError; 329 | } 330 | 331 | g_methodsTable = (uint150_t*)::calloc(205, sizeof(uint150_t)); 332 | ::memcpy(g_methodsTable, *(uint150_t**)swapChain, 18 * sizeof(uint150_t)); 333 | ::memcpy(g_methodsTable + 18, *(uint150_t**)device, 43 * sizeof(uint150_t)); 334 | ::memcpy(g_methodsTable + 18 + 43, *(uint150_t**)context, 144 * sizeof(uint150_t)); 335 | 336 | #if KIERO_USE_MINHOOK 337 | MH_Initialize(); 338 | #endif 339 | 340 | swapChain->Release(); 341 | swapChain = NULL; 342 | 343 | device->Release(); 344 | device = NULL; 345 | 346 | context->Release(); 347 | context = NULL; 348 | 349 | ::DestroyWindow(window); 350 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 351 | 352 | g_renderType = RenderType::D3D11; 353 | 354 | return Status::Success; 355 | #endif 356 | } 357 | else if (_renderType == RenderType::D3D12) 358 | { 359 | #if KIERO_INCLUDE_D3D12 360 | HMODULE libDXGI; 361 | HMODULE libD3D12; 362 | if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL || (libD3D12 = ::GetModuleHandle(KIERO_TEXT("d3d12.dll"))) == NULL) 363 | { 364 | ::DestroyWindow(window); 365 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 366 | return Status::ModuleNotFoundError; 367 | } 368 | 369 | void* CreateDXGIFactory; 370 | if ((CreateDXGIFactory = ::GetProcAddress(libDXGI, "CreateDXGIFactory")) == NULL) 371 | { 372 | ::DestroyWindow(window); 373 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 374 | return Status::UnknownError; 375 | } 376 | 377 | IDXGIFactory* factory; 378 | if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0) 379 | { 380 | ::DestroyWindow(window); 381 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 382 | return Status::UnknownError; 383 | } 384 | 385 | IDXGIAdapter* adapter; 386 | if (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND) 387 | { 388 | ::DestroyWindow(window); 389 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 390 | return Status::UnknownError; 391 | } 392 | 393 | void* D3D12CreateDevice; 394 | if ((D3D12CreateDevice = ::GetProcAddress(libD3D12, "D3D12CreateDevice")) == NULL) 395 | { 396 | ::DestroyWindow(window); 397 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 398 | return Status::UnknownError; 399 | } 400 | 401 | ID3D12Device* device; 402 | if (((long(__stdcall*)(IUnknown*, D3D_FEATURE_LEVEL, const IID&, void**))(D3D12CreateDevice))(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&device) < 0) 403 | { 404 | ::DestroyWindow(window); 405 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 406 | return Status::UnknownError; 407 | } 408 | 409 | D3D12_COMMAND_QUEUE_DESC queueDesc; 410 | queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 411 | queueDesc.Priority = 0; 412 | queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; 413 | queueDesc.NodeMask = 0; 414 | 415 | ID3D12CommandQueue* commandQueue; 416 | if (device->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue), (void**)&commandQueue) < 0) 417 | { 418 | ::DestroyWindow(window); 419 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 420 | return Status::UnknownError; 421 | } 422 | 423 | ID3D12CommandAllocator* commandAllocator; 424 | if (device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&commandAllocator) < 0) 425 | { 426 | ::DestroyWindow(window); 427 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 428 | return Status::UnknownError; 429 | } 430 | 431 | ID3D12GraphicsCommandList* commandList; 432 | if (device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator, NULL, __uuidof(ID3D12GraphicsCommandList), (void**)&commandList) < 0) 433 | { 434 | ::DestroyWindow(window); 435 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 436 | return Status::UnknownError; 437 | } 438 | 439 | DXGI_RATIONAL refreshRate; 440 | refreshRate.Numerator = 60; 441 | refreshRate.Denominator = 1; 442 | 443 | DXGI_MODE_DESC bufferDesc; 444 | bufferDesc.Width = 100; 445 | bufferDesc.Height = 100; 446 | bufferDesc.RefreshRate = refreshRate; 447 | bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 448 | bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 449 | bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 450 | 451 | DXGI_SAMPLE_DESC sampleDesc; 452 | sampleDesc.Count = 1; 453 | sampleDesc.Quality = 0; 454 | 455 | DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; 456 | swapChainDesc.BufferDesc = bufferDesc; 457 | swapChainDesc.SampleDesc = sampleDesc; 458 | swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 459 | swapChainDesc.BufferCount = 2; 460 | swapChainDesc.OutputWindow = window; 461 | swapChainDesc.Windowed = 1; 462 | swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; 463 | swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 464 | 465 | IDXGISwapChain* swapChain; 466 | if (factory->CreateSwapChain(commandQueue, &swapChainDesc, &swapChain) < 0) 467 | { 468 | ::DestroyWindow(window); 469 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 470 | return Status::UnknownError; 471 | } 472 | 473 | g_methodsTable = (uint150_t*)::calloc(150, sizeof(uint150_t)); 474 | ::memcpy(g_methodsTable, *(uint150_t**)device, 44 * sizeof(uint150_t)); 475 | ::memcpy(g_methodsTable + 44, *(uint150_t**)commandQueue, 19 * sizeof(uint150_t)); 476 | ::memcpy(g_methodsTable + 44 + 19, *(uint150_t**)commandAllocator, 9 * sizeof(uint150_t)); 477 | ::memcpy(g_methodsTable + 44 + 19 + 9, *(uint150_t**)commandList, 60 * sizeof(uint150_t)); 478 | ::memcpy(g_methodsTable + 44 + 19 + 9 + 60, *(uint150_t**)swapChain, 18 * sizeof(uint150_t)); 479 | 480 | #if KIERO_USE_MINHOOK 481 | MH_Initialize(); 482 | #endif 483 | 484 | device->Release(); 485 | device = NULL; 486 | 487 | commandQueue->Release(); 488 | commandQueue = NULL; 489 | 490 | commandAllocator->Release(); 491 | commandAllocator = NULL; 492 | 493 | commandList->Release(); 494 | commandList = NULL; 495 | 496 | swapChain->Release(); 497 | swapChain = NULL; 498 | 499 | ::DestroyWindow(window); 500 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 501 | 502 | g_renderType = RenderType::D3D12; 503 | 504 | return Status::Success; 505 | #endif 506 | } 507 | 508 | ::DestroyWindow(window); 509 | ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); 510 | 511 | return Status::NotSupportedError; 512 | } 513 | else if (_renderType != RenderType::Auto) 514 | { 515 | if (_renderType == RenderType::OpenGL) 516 | { 517 | #if KIERO_INCLUDE_OPENGL 518 | HMODULE libOpenGL32; 519 | if ((libOpenGL32 = ::GetModuleHandle(KIERO_TEXT("opengl32.dll"))) == NULL) 520 | { 521 | return Status::ModuleNotFoundError; 522 | } 523 | 524 | const char* const methodsNames[] = { 525 | "glAccum", "glAlphaFunc", "glAreTexturesResident", "glArrayElement", "glBegin", "glBindTexture", "glBitmap", "glBlendFunc", "glCallList", "glCallLists", "glClear", "glClearAccum", 526 | "glClearColor", "glClearDepth", "glClearIndex", "glClearStencil", "glClipPlane", "glColor3b", "glColor3bv", "glColor3d", "glColor3dv", "glColor3f", "glColor3fv", "glColor3i", "glColor3iv", 527 | "glColor3s", "glColor3sv", "glColor3ub", "glColor3ubv", "glColor3ui", "glColor3uiv", "glColor3us", "glColor3usv", "glColor4b", "glColor4bv", "glColor4d", "glColor4dv", "glColor4f", 528 | "glColor4fv", "glColor4i", "glColor4iv", "glColor4s", "glColor4sv", "glColor4ub", "glColor4ubv", "glColor4ui", "glColor4uiv", "glColor4us", "glColor4usv", "glColorMask", "glColorMaterial", 529 | "glColorPointer", "glCopyPixels", "glCopyTexImage1D", "glCopyTexImage2D", "glCopyTexSubImage1D", "glCopyTexSubImage2D", "glCullFaceglCullFace", "glDeleteLists", "glDeleteTextures", 530 | "glDepthFunc", "glDepthMask", "glDepthRange", "glDisable", "glDisableClientState", "glDrawArrays", "glDrawBuffer", "glDrawElements", "glDrawPixels", "glEdgeFlag", "glEdgeFlagPointer", 531 | "glEdgeFlagv", "glEnable", "glEnableClientState", "glEnd", "glEndList", "glEvalCoord1d", "glEvalCoord1dv", "glEvalCoord1f", "glEvalCoord1fv", "glEvalCoord2d", "glEvalCoord2dv", 532 | "glEvalCoord2f", "glEvalCoord2fv", "glEvalMesh1", "glEvalMesh2", "glEvalPoint1", "glEvalPoint2", "glFeedbackBuffer", "glFinish", "glFlush", "glFogf", "glFogfv", "glFogi", "glFogiv", 533 | "glFrontFace", "glFrustum", "glGenLists", "glGenTextures", "glGetBooleanv", "glGetClipPlane", "glGetDoublev", "glGetError", "glGetFloatv", "glGetIntegerv", "glGetLightfv", "glGetLightiv", 534 | "glGetMapdv", "glGetMapfv", "glGetMapiv", "glGetMaterialfv", "glGetMaterialiv", "glGetPixelMapfv", "glGetPixelMapuiv", "glGetPixelMapusv", "glGetPointerv", "glGetPolygonStipple", 535 | "glGetString", "glGetTexEnvfv", "glGetTexEnviv", "glGetTexGendv", "glGetTexGenfv", "glGetTexGeniv", "glGetTexImage", "glGetTexLevelParameterfv", "glGetTexLevelParameteriv", 536 | "glGetTexParameterfv", "glGetTexParameteriv", "glHint", "glIndexMask", "glIndexPointer", "glIndexd", "glIndexdv", "glIndexf", "glIndexfv", "glIndexi", "glIndexiv", "glIndexs", "glIndexsv", 537 | "glIndexub", "glIndexubv", "glInitNames", "glInterleavedArrays", "glIsEnabled", "glIsList", "glIsTexture", "glLightModelf", "glLightModelfv", "glLightModeli", "glLightModeliv", "glLightf", 538 | "glLightfv", "glLighti", "glLightiv", "glLineStipple", "glLineWidth", "glListBase", "glLoadIdentity", "glLoadMatrixd", "glLoadMatrixf", "glLoadName", "glLogicOp", "glMap1d", "glMap1f", 539 | "glMap2d", "glMap2f", "glMapGrid1d", "glMapGrid1f", "glMapGrid2d", "glMapGrid2f", "glMaterialf", "glMaterialfv", "glMateriali", "glMaterialiv", "glMatrixMode", "glMultMatrixd", 540 | "glMultMatrixf", "glNewList", "glNormal3b", "glNormal3bv", "glNormal3d", "glNormal3dv", "glNormal3f", "glNormal3fv", "glNormal3i", "glNormal3iv", "glNormal3s", "glNormal3sv", 541 | "glNormalPointer", "glOrtho", "glPassThrough", "glPixelMapfv", "glPixelMapuiv", "glPixelMapusv", "glPixelStoref", "glPixelStorei", "glPixelTransferf", "glPixelTransferi", "glPixelZoom", 542 | "glPointSize", "glPolygonMode", "glPolygonOffset", "glPolygonStipple", "glPopAttrib", "glPopClientAttrib", "glPopMatrix", "glPopName", "glPrioritizeTextures", "glPushAttrib", 543 | "glPushClientAttrib", "glPushMatrix", "glPushName", "glRasterPos2d", "glRasterPos2dv", "glRasterPos2f", "glRasterPos2fv", "glRasterPos2i", "glRasterPos2iv", "glRasterPos2s", 544 | "glRasterPos2sv", "glRasterPos3d", "glRasterPos3dv", "glRasterPos3f", "glRasterPos3fv", "glRasterPos3i", "glRasterPos3iv", "glRasterPos3s", "glRasterPos3sv", "glRasterPos4d", 545 | "glRasterPos4dv", "glRasterPos4f", "glRasterPos4fv", "glRasterPos4i", "glRasterPos4iv", "glRasterPos4s", "glRasterPos4sv", "glReadBuffer", "glReadPixels", "glRectd", "glRectdv", "glRectf", 546 | "glRectfv", "glRecti", "glRectiv", "glRects", "glRectsv", "glRenderMode", "glRotated", "glRotatef", "glScaled", "glScalef", "glScissor", "glSelectBuffer", "glShadeModel", "glStencilFunc", 547 | "glStencilMask", "glStencilOp", "glTexCoord1d", "glTexCoord1dv", "glTexCoord1f", "glTexCoord1fv", "glTexCoord1i", "glTexCoord1iv", "glTexCoord1s", "glTexCoord1sv", "glTexCoord2d", 548 | "glTexCoord2dv", "glTexCoord2f", "glTexCoord2fv", "glTexCoord2i", "glTexCoord2iv", "glTexCoord2s", "glTexCoord2sv", "glTexCoord3d", "glTexCoord3dv", "glTexCoord3f", "glTexCoord3fv", 549 | "glTexCoord3i", "glTexCoord3iv", "glTexCoord3s", "glTexCoord3sv", "glTexCoord4d", "glTexCoord4dv", "glTexCoord4f", "glTexCoord4fv", "glTexCoord4i", "glTexCoord4iv", "glTexCoord4s", 550 | "glTexCoord4sv", "glTexCoordPointer", "glTexEnvf", "glTexEnvfv", "glTexEnvi", "glTexEnviv", "glTexGend", "glTexGendv", "glTexGenf", "glTexGenfv", "glTexGeni", "glTexGeniv", "glTexImage1D", 551 | "glTexImage2D", "glTexParameterf", "glTexParameterfv", "glTexParameteri", "glTexParameteriv", "glTexSubImage1D", "glTexSubImage2D", "glTranslated", "glTranslatef", "glVertex2d", 552 | "glVertex2dv", "glVertex2f", "glVertex2fv", "glVertex2i", "glVertex2iv", "glVertex2s", "glVertex2sv", "glVertex3d", "glVertex3dv", "glVertex3f", "glVertex3fv", "glVertex3i", "glVertex3iv", 553 | "glVertex3s", "glVertex3sv", "glVertex4d", "glVertex4dv", "glVertex4f", "glVertex4fv", "glVertex4i", "glVertex4iv", "glVertex4s", "glVertex4sv", "glVertexPointer", "glViewport" 554 | }; 555 | 556 | size_t size = KIERO_ARRAY_SIZE(methodsNames); 557 | 558 | g_methodsTable = (uint150_t*)::calloc(size, sizeof(uint150_t)); 559 | 560 | for (int i = 0; i < size; i++) 561 | { 562 | g_methodsTable[i] = (uint150_t)::GetProcAddress(libOpenGL32, methodsNames[i]); 563 | } 564 | 565 | #if KIERO_USE_MINHOOK 566 | MH_Initialize(); 567 | #endif 568 | 569 | g_renderType = RenderType::OpenGL; 570 | 571 | return Status::Success; 572 | #endif 573 | } 574 | else if (_renderType == RenderType::Vulkan) 575 | { 576 | #if KIERO_INCLUDE_VULKAN 577 | HMODULE libVulkan; 578 | if ((libVulkan = GetModuleHandle(KIERO_TEXT("vulkan-1.dll"))) == NULL) 579 | { 580 | return Status::ModuleNotFoundError; 581 | } 582 | 583 | const char* const methodsNames[] = { 584 | "vkCreateInstance", "vkDestroyInstance", "vkEnumeratePhysicalDevices", "vkGetPhysicalDeviceFeatures", "vkGetPhysicalDeviceFormatProperties", "vkGetPhysicalDeviceImageFormatProperties", 585 | "vkGetPhysicalDeviceProperties", "vkGetPhysicalDeviceQueueFamilyProperties", "vkGetPhysicalDeviceMemoryProperties", "vkGetInstanceProcAddr", "vkGetDeviceProcAddr", "vkCreateDevice", 586 | "vkDestroyDevice", "vkEnumerateInstanceExtensionProperties", "vkEnumerateDeviceExtensionProperties", "vkEnumerateDeviceLayerProperties", "vkGetDeviceQueue", "vkQueueSubmit", "vkQueueWaitIdle", 587 | "vkDeviceWaitIdle", "vkAllocateMemory", "vkFreeMemory", "vkMapMemory", "vkUnmapMemory", "vkFlushMappedMemoryRanges", "vkInvalidateMappedMemoryRanges", "vkGetDeviceMemoryCommitment", 588 | "vkBindBufferMemory", "vkBindImageMemory", "vkGetBufferMemoryRequirements", "vkGetImageMemoryRequirements", "vkGetImageSparseMemoryRequirements", "vkGetPhysicalDeviceSparseImageFormatProperties", 589 | "vkQueueBindSparse", "vkCreateFence", "vkDestroyFence", "vkResetFences", "vkGetFenceStatus", "vkWaitForFences", "vkCreateSemaphore", "vkDestroySemaphore", "vkCreateEvent", "vkDestroyEvent", 590 | "vkGetEventStatus", "vkSetEvent", "vkResetEvent", "vkCreateQueryPool", "vkDestroyQueryPool", "vkGetQueryPoolResults", "vkCreateBuffer", "vkDestroyBuffer", "vkCreateBufferView", "vkDestroyBufferView", 591 | "vkCreateImage", "vkDestroyImage", "vkGetImageSubresourceLayout", "vkCreateImageView", "vkDestroyImageView", "vkCreateShaderModule", "vkDestroyShaderModule", "vkCreatePipelineCache", 592 | "vkDestroyPipelineCache", "vkGetPipelineCacheData", "vkMergePipelineCaches", "vkCreateGraphicsPipelines", "vkCreateComputePipelines", "vkDestroyPipeline", "vkCreatePipelineLayout", 593 | "vkDestroyPipelineLayout", "vkCreateSampler", "vkDestroySampler", "vkCreateDescriptorSetLayout", "vkDestroyDescriptorSetLayout", "vkCreateDescriptorPool", "vkDestroyDescriptorPool", 594 | "vkResetDescriptorPool", "vkAllocateDescriptorSets", "vkFreeDescriptorSets", "vkUpdateDescriptorSets", "vkCreateFramebuffer", "vkDestroyFramebuffer", "vkCreateRenderPass", "vkDestroyRenderPass", 595 | "vkGetRenderAreaGranularity", "vkCreateCommandPool", "vkDestroyCommandPool", "vkResetCommandPool", "vkAllocateCommandBuffers", "vkFreeCommandBuffers", "vkBeginCommandBuffer", "vkEndCommandBuffer", 596 | "vkResetCommandBuffer", "vkCmdBindPipeline", "vkCmdSetViewport", "vkCmdSetScissor", "vkCmdSetLineWidth", "vkCmdSetDepthBias", "vkCmdSetBlendConstants", "vkCmdSetDepthBounds", 597 | "vkCmdSetStencilCompareMask", "vkCmdSetStencilWriteMask", "vkCmdSetStencilReference", "vkCmdBindDescriptorSets", "vkCmdBindIndexBuffer", "vkCmdBindVertexBuffers", "vkCmdDraw", "vkCmdDrawIndexed", 598 | "vkCmdDrawIndirect", "vkCmdDrawIndexedIndirect", "vkCmdDispatch", "vkCmdDispatchIndirect", "vkCmdCopyBuffer", "vkCmdCopyImage", "vkCmdBlitImage", "vkCmdCopyBufferToImage", "vkCmdCopyImageToBuffer", 599 | "vkCmdUpdateBuffer", "vkCmdFillBuffer", "vkCmdClearColorImage", "vkCmdClearDepthStencilImage", "vkCmdClearAttachments", "vkCmdResolveImage", "vkCmdSetEvent", "vkCmdResetEvent", "vkCmdWaitEvents", 600 | "vkCmdPipelineBarrier", "vkCmdBeginQuery", "vkCmdEndQuery", "vkCmdResetQueryPool", "vkCmdWriteTimestamp", "vkCmdCopyQueryPoolResults", "vkCmdPushConstants", "vkCmdBeginRenderPass", "vkCmdNextSubpass", 601 | "vkCmdEndRenderPass", "vkCmdExecuteCommands" 602 | }; 603 | 604 | size_t size = KIERO_ARRAY_SIZE(methodsNames); 605 | 606 | g_methodsTable = (uint150_t*)::calloc(size, sizeof(uint150_t)); 607 | 608 | for (int i = 0; i < size; i++) 609 | { 610 | g_methodsTable[i] = (uint150_t)::GetProcAddress(libVulkan, methodsNames[i]); 611 | } 612 | 613 | #if KIERO_USE_MINHOOK 614 | MH_Initialize(); 615 | #endif 616 | 617 | g_renderType = RenderType::Vulkan; 618 | 619 | return Status::Success; 620 | #endif 621 | } 622 | 623 | return Status::NotSupportedError; 624 | } 625 | else 626 | { 627 | RenderType::Enum type = RenderType::None; 628 | 629 | if (::GetModuleHandle(KIERO_TEXT("d3d9.dll")) != NULL) 630 | { 631 | type = RenderType::D3D9; 632 | } 633 | else if (::GetModuleHandle(KIERO_TEXT("d3d10.dll")) != NULL) 634 | { 635 | type = RenderType::D3D10; 636 | } 637 | else if (::GetModuleHandle(KIERO_TEXT("d3d11.dll")) != NULL) 638 | { 639 | type = RenderType::D3D11; 640 | } 641 | else if (::GetModuleHandle(KIERO_TEXT("d3d12.dll")) != NULL) 642 | { 643 | type = RenderType::D3D12; 644 | } 645 | else if (::GetModuleHandle(KIERO_TEXT("opengl32.dll")) != NULL) 646 | { 647 | type = RenderType::OpenGL; 648 | } 649 | else if (::GetModuleHandle(KIERO_TEXT("vulkan-1.dll")) != NULL) 650 | { 651 | type = RenderType::Vulkan; 652 | } 653 | else 654 | { 655 | return Status::NotSupportedError; 656 | } 657 | 658 | return init(type); 659 | } 660 | } 661 | 662 | return Status::Success; 663 | } 664 | 665 | void kiero::shutdown() 666 | { 667 | if (g_renderType != RenderType::None) 668 | { 669 | #if KIERO_USE_MINHOOK 670 | MH_DisableHook(MH_ALL_HOOKS); 671 | #endif 672 | 673 | ::free(g_methodsTable); 674 | g_methodsTable = NULL; 675 | g_renderType = RenderType::None; 676 | } 677 | } 678 | 679 | kiero::Status::Enum kiero::bind(uint16_t _index, void** _original, void* _function) 680 | { 681 | // TODO: Need own detour function 682 | 683 | assert(_original != NULL && _function != NULL); 684 | 685 | if (g_renderType != RenderType::None) 686 | { 687 | #if KIERO_USE_MINHOOK 688 | void* target = (void*)g_methodsTable[_index]; 689 | if (MH_CreateHook(target, _function, _original) != MH_OK || MH_EnableHook(target) != MH_OK) 690 | { 691 | return Status::UnknownError; 692 | } 693 | #endif 694 | 695 | return Status::Success; 696 | } 697 | 698 | return Status::NotInitializedError; 699 | } 700 | 701 | void kiero::unbind(uint16_t _index) 702 | { 703 | if (g_renderType != RenderType::None) 704 | { 705 | #if KIERO_USE_MINHOOK 706 | MH_DisableHook((void*)g_methodsTable[_index]); 707 | #endif 708 | } 709 | } 710 | 711 | kiero::RenderType::Enum kiero::getRenderType() 712 | { 713 | return g_renderType; 714 | } 715 | 716 | uint150_t* kiero::getMethodsTable() 717 | { 718 | return g_methodsTable; 719 | } -------------------------------------------------------------------------------- /external/kiero/kiero.h: -------------------------------------------------------------------------------- 1 | #ifndef __KIERO_H__ 2 | #define __KIERO_H__ 3 | 4 | #include 5 | 6 | #define KIERO_VERSION "1.2.12" 7 | 8 | #define KIERO_INCLUDE_D3D9 0 // 1 if you need D3D9 hook 9 | #define KIERO_INCLUDE_D3D10 0 // 1 if you need D3D10 hook 10 | #define KIERO_INCLUDE_D3D11 1 // 1 if you need D3D11 hook 11 | #define KIERO_INCLUDE_D3D12 1 // 1 if you need D3D12 hook 12 | #define KIERO_INCLUDE_OPENGL 0 // 1 if you need OpenGL hook 13 | #define KIERO_INCLUDE_VULKAN 0 // 1 if you need Vulkan hook 14 | #define KIERO_USE_MINHOOK 1 // 1 if you will use kiero::bind function 15 | 16 | #define KIERO_ARCH_X64 0 17 | #define KIERO_ARCH_X86 0 18 | 19 | #if defined(_M_X64) 20 | # undef KIERO_ARCH_X64 21 | # define KIERO_ARCH_X64 1 22 | #else 23 | # undef KIERO_ARCH_X86 24 | # define KIERO_ARCH_X86 1 25 | #endif 26 | 27 | #if KIERO_ARCH_X64 28 | typedef uint64_t uint150_t; 29 | #else 30 | typedef uint32_t uint150_t; 31 | #endif 32 | 33 | namespace kiero 34 | { 35 | struct Status 36 | { 37 | enum Enum 38 | { 39 | UnknownError = -1, 40 | NotSupportedError = -2, 41 | ModuleNotFoundError = -3, 42 | 43 | AlreadyInitializedError = -4, 44 | NotInitializedError = -5, 45 | 46 | Success = 0, 47 | }; 48 | }; 49 | 50 | struct RenderType 51 | { 52 | enum Enum 53 | { 54 | None, 55 | 56 | D3D9, 57 | D3D10, 58 | D3D11, 59 | D3D12, 60 | 61 | OpenGL, 62 | Vulkan, 63 | 64 | Auto 65 | }; 66 | }; 67 | 68 | Status::Enum init(RenderType::Enum renderType); 69 | void shutdown(); 70 | 71 | Status::Enum bind(uint16_t index, void** original, void* function); 72 | void unbind(uint16_t index); 73 | 74 | RenderType::Enum getRenderType(); 75 | uint150_t* getMethodsTable(); 76 | } 77 | 78 | #endif // __KIERO_H__ -------------------------------------------------------------------------------- /helpers/injector.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasephasephase/DirectXPlayground/6bd9cca822a9e024c471037b2ebce17b5fe3b196/helpers/injector.exe -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // windows related includes 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // standard includes 10 | #include 11 | #include -------------------------------------------------------------------------------- /src/hook/hook.cpp: -------------------------------------------------------------------------------- 1 | #include "hook.h" 2 | 3 | typedef HRESULT(__thiscall* present_t)(IDXGISwapChain3*, UINT, UINT); 4 | present_t original_present; 5 | 6 | typedef HRESULT(__thiscall* resize_buffers_t)(IDXGISwapChain3*, UINT, UINT, UINT, DXGI_FORMAT, UINT); 7 | resize_buffers_t original_resize_buffers; 8 | 9 | HRESULT present_callback(IDXGISwapChain3* swap_chain, UINT sync_interval, UINT flags) { 10 | static bool once = false; 11 | if (!once) { 12 | // you could do initialization here 13 | printf("IDXGISwapChain::Present() was called.\n"); 14 | 15 | once = true; 16 | } 17 | 18 | return original_present(swap_chain, sync_interval, flags); 19 | } 20 | 21 | HRESULT resize_buffers_callback(IDXGISwapChain3* swap_chain, UINT buffer_count, UINT width, 22 | UINT height, DXGI_FORMAT new_format, UINT swap_chain_flags) { 23 | // reinitialize your renderer here 24 | printf("IDXGISwapChain::ResizeBuffers() was called.\n"); 25 | 26 | return original_resize_buffers(swap_chain, buffer_count, width, height, new_format, swap_chain_flags); 27 | } 28 | 29 | void install_hook() { 30 | // the game prefers using D3D12 over D3D11, so we'll try to hook in that same order 31 | if (kiero::init(kiero::RenderType::D3D12) == kiero::Status::Success) { 32 | // Present and ResizeBuffers live at indexes 140 and 145 respectively 33 | kiero::bind(140, (void**)&original_present, present_callback); 34 | kiero::bind(145, (void**)&original_resize_buffers, resize_buffers_callback); 35 | printf("Hooked D3D12.\n"); 36 | return; 37 | } 38 | 39 | if (kiero::init(kiero::RenderType::D3D11) == kiero::Status::Success) { 40 | // indexes are 8 and 13 for D3D11 instead 41 | kiero::bind(8, (void**)&original_present, present_callback); 42 | kiero::bind(13, (void**)&original_resize_buffers, resize_buffers_callback); 43 | printf("Hooked D3D11.\n"); 44 | return; 45 | } 46 | 47 | // something weird happened 48 | printf("Failed to hook.\n"); 49 | } -------------------------------------------------------------------------------- /src/hook/hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../common.h" 3 | 4 | #include 5 | 6 | void install_hook(); -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "hook/hook.h" 3 | 4 | void entry() { 5 | AllocConsole(); 6 | AttachConsole(GetCurrentProcessId()); 7 | SetConsoleTitleA("DirectX Playground"); 8 | 9 | FILE* in; 10 | freopen_s(&in, "CONIN$", "r", stdin); 11 | FILE* out; 12 | freopen_s(&out, "CONOUT$", "w", stdout); 13 | FILE* err; 14 | freopen_s(&err, "CONOUT$", "w", stderr); 15 | 16 | printf("Injected.\n"); 17 | install_hook(); 18 | } 19 | 20 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) 21 | { 22 | if (dwReason == DLL_PROCESS_ATTACH) 23 | { 24 | std::thread entryThread(entry); 25 | entryThread.detach(); 26 | } 27 | 28 | return TRUE; 29 | } --------------------------------------------------------------------------------