Skip to content
15 changes: 5 additions & 10 deletions Alien Isolation/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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
Expand Down
144 changes: 121 additions & 23 deletions Alien Isolation/Util/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@
#include "../AlienIsolation.h"
#include <MinHook.h>
#include <d3d11.h>
#include <dxgi1_2.h>
#include <DirectXMath.h>
#include <unordered_map>
#include <cstring>
#include <Windows.h>

#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*);
Expand All @@ -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<void**>(&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<void**>(&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 ////
//////////////////////////
Expand Down Expand Up @@ -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);
Expand All @@ -321,8 +381,28 @@ static bool CreateDXGIPresentHook()
}

void** vtbl = *reinterpret_cast<void***>(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<void**>(&pSwapChain1));
if (SUCCEEDED(qiHr) && pSwapChain1)
{
void** vtbl1 = *reinterpret_cast<void***>(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();
Expand All @@ -332,6 +412,7 @@ static bool CreateDXGIPresentHook()
return false;

g_presentHookCreated = true;
util::log::Ok("Installed DXGI Present hook via dummy device");
return true;
}

Expand Down Expand Up @@ -377,6 +458,11 @@ bool util::hooks::Init()
return true;
}

bool util::hooks::IsPresentHookInstalled()
{
return g_presentHookCreated;
}

void util::hooks::InstallGameHooks()
{
if (g_gameHooksInstalled)
Expand All @@ -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<void*>(addr), sizeof(preview)))
{
util::log::Warning("Skipping hook %s: target 0x%X unreadable", name, addr);
return;
}

memcpy(preview, reinterpret_cast<void*>(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);
};

Expand Down
1 change: 1 addition & 0 deletions Alien Isolation/Util/Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "");
Expand Down