diff --git a/Alien Isolation/Main.cpp b/Alien Isolation/Main.cpp index 258836c..cc4ec3f 100644 --- a/Alien Isolation/Main.cpp +++ b/Alien Isolation/Main.cpp @@ -196,6 +196,9 @@ bool Main::Initialize() if (!g_d3d11Device || !g_d3d11Context || !g_dxgiSwapChain) { util::log::Error("Failed to capture DirectX interfaces via Present hook fallback"); + util::log::Error("Present hook installed: %s | Device 0x%p | Context 0x%p | SwapChain 0x%p", + util::hooks::IsPresentHookInstalled() ? "yes" : "no", + g_d3d11Device, g_d3d11Context, g_dxgiSwapChain); return false; } @@ -205,17 +208,9 @@ bool Main::Initialize() // This disables the object glow thing // Apply small byte patch, but only if target lies within module image { - BYTE GlowPatch[7] = { 0x80, 0xB9, 0x65, 0x70, 0x02, 0x00, 0x01 }; void* patchAddr = (void*)((int)g_gameHandle + 0x3A3494); - if (util::IsAddressInModule(g_gameHandle, patchAddr, sizeof(GlowPatch))) - { - if (!util::WriteMemory((DWORD_PTR)patchAddr, GlowPatch, (DWORD)sizeof(GlowPatch))) - util::log::Warning("Glow patch VirtualProtect/WriteMemory failed at %p", patchAddr); - } - else - { - util::log::Warning("Skipping glow patch: address %p outside module image (possible version mismatch)", patchAddr); - } + if (util::IsAddressInModule(g_gameHandle, patchAddr, 7)) + util::log::Warning("Skipping legacy glow patch at %p (offset 0x3A3494) to avoid version mismatch", patchAddr); } // Make timescale writable diff --git a/Alien Isolation/Util/Hooks.cpp b/Alien Isolation/Util/Hooks.cpp index dcc16c4..bd03b4b 100644 --- a/Alien Isolation/Util/Hooks.cpp +++ b/Alien Isolation/Util/Hooks.cpp @@ -4,12 +4,17 @@ #include "../AlienIsolation.h" #include #include +#include #include #include +#include #include +#pragma comment(lib, "d3d11.lib") + // Function definitions typedef HRESULT(__stdcall* tIDXGISwapChain_Present)(IDXGISwapChain*, UINT, UINT); +typedef HRESULT(__stdcall* tIDXGISwapChain1_Present1)(IDXGISwapChain1*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*); typedef BOOL(WINAPI* tSetCursorPos)(int, int); typedef int(__thiscall* tCameraUpdate)(CATHODE::AICameraManager*); @@ -29,45 +34,94 @@ typedef bool(__thiscall* tCombatManagerUpdate)(void*, CATHODE::Character*); // on top, like the tools UI. tIDXGISwapChain_Present oIDXGISwapChain_Present = nullptr; +tIDXGISwapChain1_Present1 oIDXGISwapChain1_Present1 = nullptr; -HRESULT __stdcall hIDXGISwapChain_Present(IDXGISwapChain* pSwapchain, UINT SyncInterval, UINT Flags) +namespace { - static bool loggedDeviceFailure = false; + void HandlePresent(IDXGISwapChain* pSwapchain, UINT SyncInterval, UINT Flags) + { + static bool loggedDeviceFailure = false; + static bool loggedFirstPresent = false; + static bool loggedSwapChainCapture = false; - if (!g_dxgiSwapChain) - g_dxgiSwapChain = pSwapchain; + if (!loggedFirstPresent) + { + util::log::Write(">>> Present hook CALLED! pSwapchain=0x%p SyncInterval=%u Flags=%u", pSwapchain, SyncInterval, Flags); + loggedFirstPresent = true; + } - if (!g_d3d11Device) - { - HRESULT hr = pSwapchain->GetDevice(__uuidof(ID3D11Device), reinterpret_cast(&g_d3d11Device)); - if (FAILED(hr) && !loggedDeviceFailure) + if (!g_dxgiSwapChain) + g_dxgiSwapChain = pSwapchain; + + if (g_dxgiSwapChain == pSwapchain && !loggedSwapChainCapture) { - util::log::Warning("SwapChain::GetDevice failed while capturing interfaces, HRESULT 0x%X", hr); - loggedDeviceFailure = true; + util::log::Ok("Captured IDXGISwapChain from Present hook (0x%p)", g_dxgiSwapChain); + loggedSwapChainCapture = true; } - } - if (g_d3d11Device && !g_d3d11Context) - g_d3d11Device->GetImmediateContext(&g_d3d11Context); + if (!g_d3d11Device) + { + ID3D11Device* pDevice = nullptr; + HRESULT hr = pSwapchain->GetDevice(__uuidof(ID3D11Device), reinterpret_cast(&pDevice)); + if (FAILED(hr)) + { + if (!loggedDeviceFailure) + { + util::log::Warning("SwapChain::GetDevice failed while capturing interfaces, HRESULT 0x%X", hr); + loggedDeviceFailure = true; + } + } + else if (!pDevice) + { + if (!loggedDeviceFailure) + { + util::log::Warning("SwapChain::GetDevice succeeded but returned null device pointer"); + loggedDeviceFailure = true; + } + } + else + { + g_d3d11Device = pDevice; + util::log::Ok("Captured ID3D11Device from Present hook (0x%p)", g_d3d11Device); + } + } - if (!g_shutdown && g_mainHandle) - { - CTRenderer* pRenderer = g_mainHandle->GetRenderer(); - UI* pUI = g_mainHandle->GetUI(); - CameraManager* pCameraManager = g_mainHandle->GetCameraManager(); + if (g_d3d11Device && !g_d3d11Context) + { + g_d3d11Device->GetImmediateContext(&g_d3d11Context); + if (g_d3d11Context) + util::log::Ok("Captured ID3D11DeviceContext from Present hook (0x%p)", g_d3d11Context); + } - if (pRenderer && pRenderer->IsReady() && pUI && pUI->IsReady() && pCameraManager) + if (!g_shutdown && g_mainHandle) { - pUI->BindRenderTarget(); - pRenderer->UpdateMatrices(); - //g_mainHandle->GetCameraManager()->DrawTrack(); - pUI->Draw(); + CTRenderer* pRenderer = g_mainHandle->GetRenderer(); + UI* pUI = g_mainHandle->GetUI(); + CameraManager* pCameraManager = g_mainHandle->GetCameraManager(); + + if (pRenderer && pRenderer->IsReady() && pUI && pUI->IsReady() && pCameraManager) + { + pUI->BindRenderTarget(); + pRenderer->UpdateMatrices(); + //g_mainHandle->GetCameraManager()->DrawTrack(); + pUI->Draw(); + } } } +} +HRESULT __stdcall hIDXGISwapChain_Present(IDXGISwapChain* pSwapchain, UINT SyncInterval, UINT Flags) +{ + HandlePresent(pSwapchain, SyncInterval, Flags); return oIDXGISwapChain_Present(pSwapchain, SyncInterval, Flags); } +HRESULT __stdcall hIDXGISwapChain1_Present1(IDXGISwapChain1* pSwapchain, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters) +{ + HandlePresent(pSwapchain, SyncInterval, Flags); + return oIDXGISwapChain1_Present1(pSwapchain, SyncInterval, Flags, pPresentParameters); +} + ////////////////////////// //// CAMERA HOOKS //// ////////////////////////// @@ -313,6 +367,12 @@ static bool CreateDXGIPresentHook() featureLevels, _countof(featureLevels), D3D11_SDK_VERSION, &desc, &pSwapChain, &pDevice, &obtainedLevel, &pContext); } + if (FAILED(hr)) + { + hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_REFERENCE, nullptr, createFlags, + featureLevels, _countof(featureLevels), D3D11_SDK_VERSION, &desc, &pSwapChain, &pDevice, &obtainedLevel, &pContext); + } + if (FAILED(hr)) { util::log::Error("Failed to create dummy D3D11 device for Present hook, HRESULT 0x%X", hr); @@ -321,8 +381,28 @@ static bool CreateDXGIPresentHook() } void** vtbl = *reinterpret_cast(pSwapChain); + util::log::Write("SwapChain vtable at 0x%p, Present at slot 8 is 0x%p", vtbl, vtbl[8]); + bool hookCreated = CreateHook("SwapChainPresent", (int)vtbl[8], hIDXGISwapChain_Present, &oIDXGISwapChain_Present); + if (hookCreated) + { + IDXGISwapChain1* pSwapChain1 = nullptr; + HRESULT qiHr = pSwapChain->QueryInterface(__uuidof(IDXGISwapChain1), reinterpret_cast(&pSwapChain1)); + if (SUCCEEDED(qiHr) && pSwapChain1) + { + void** vtbl1 = *reinterpret_cast(pSwapChain1); + util::log::Write("SwapChain1 vtable at 0x%p, Present1 at slot 22 is 0x%p", vtbl1, vtbl1[22]); + if (CreateHook("SwapChainPresent1", (int)vtbl1[22], hIDXGISwapChain1_Present1, &oIDXGISwapChain1_Present1)) + util::log::Ok("Installed DXGI Present1 hook via dummy device"); + pSwapChain1->Release(); + } + else + { + util::log::Warning("IDXGISwapChain1 interface unavailable for Present1 hook, HRESULT 0x%X", qiHr); + } + } + pSwapChain->Release(); pDevice->Release(); pContext->Release(); @@ -332,6 +412,7 @@ static bool CreateDXGIPresentHook() return false; g_presentHookCreated = true; + util::log::Ok("Installed DXGI Present hook via dummy device"); return true; } @@ -377,6 +458,11 @@ bool util::hooks::Init() return true; } +bool util::hooks::IsPresentHookInstalled() +{ + return g_presentHookCreated; +} + void util::hooks::InstallGameHooks() { if (g_gameHooksInstalled) @@ -393,6 +479,18 @@ void util::hooks::InstallGameHooks() util::log::Warning("Skipping hook %s: address 0x%X outside module image", name, addr); return; } + + BYTE preview[6] = { 0 }; + if (!util::IsPtrReadable(reinterpret_cast(addr), sizeof(preview))) + { + util::log::Warning("Skipping hook %s: target 0x%X unreadable", name, addr); + return; + } + + memcpy(preview, reinterpret_cast(addr), sizeof(preview)); + util::log::Write("Hook %s targeting 0x%X bytes %02X %02X %02X %02X %02X %02X", name, addr, + preview[0], preview[1], preview[2], preview[3], preview[4], preview[5]); + CreateHook(name, addr, hook, original); }; diff --git a/Alien Isolation/Util/Util.h b/Alien Isolation/Util/Util.h index 66a3c72..8da4225 100644 --- a/Alien Isolation/Util/Util.h +++ b/Alien Isolation/Util/Util.h @@ -26,6 +26,7 @@ namespace util bool Init(); void InstallGameHooks(); + bool IsPresentHookInstalled(); // if name is empty, then perform on all hooks void SetHookState(bool enabled, std::string const& name = "");