Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions digi_analysis/debug_log.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "debug_log.h"

#include <windows.h>
#include <cstdio>
#include <cstdarg>
#include <fstream>

static std::ofstream g_logFile;
static bool g_consoleAllocated = false;

void InitDebugLog() {
if (!g_consoleAllocated) {
AllocConsole();
#ifdef _MSC_VER
FILE* out;
freopen_s(&out, "CONOUT$", "w", stdout);
freopen_s(&out, "CONOUT$", "w", stderr);
#else
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
#endif
g_consoleAllocated = true;
}
if (!g_logFile.is_open()) {
g_logFile.open("debug_log.txt", std::ios::out | std::ios::app);
}
}

void DebugLog(const char* fmt, ...) {
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
buf[sizeof(buf) - 1] = '\0';
OutputDebugStringA(buf);
fputs(buf, stdout);
fflush(stdout);
if (g_logFile.is_open()) {
g_logFile << buf;
g_logFile.flush();
}
}

void ShutdownDebugLog() {
if (g_logFile.is_open()) {
g_logFile.close();
}
if (g_consoleAllocated) {
FreeConsole();
g_consoleAllocated = false;
}
}

14 changes: 14 additions & 0 deletions digi_analysis/debug_log.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <cstdarg>

// Provide C linkage so the functions can be called from assembly.
extern "C" {
// Initialize logging by allocating a console window and opening a log file.
void InitDebugLog();
// Log a formatted message to debugger output, console and log file.
void DebugLog(const char* fmt, ...);
// Shut down logging and release resources.
void ShutdownDebugLog();
}

2 changes: 2 additions & 0 deletions digi_analysis/digi_analysis.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
<ClCompile Include="sub_004A1F8A.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="debug_log.cpp" />
<ClCompile Include="gdi_hooks.cpp" />
<ClCompile Include="text_renderer.cpp" />
<!-- Compile the MinHook sources as part of this project. -->
Expand All @@ -106,6 +107,7 @@
<ClInclude Include="hooks.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="text_renderer.h" />
<ClInclude Include="debug_log.h" />
</ItemGroup>
<ItemGroup>
<None Include="sub_004A1F8A.asm" />
Expand Down
6 changes: 6 additions & 0 deletions digi_analysis/digi_analysis.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="debug_log.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gdi_hooks.cpp">
<Filter>Source Files</Filter>
</ClCompile>
Expand Down Expand Up @@ -86,6 +89,9 @@
<ClInclude Include="opengl_utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="debug_log.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="sub_004A1F8A.asm">
Expand Down
51 changes: 37 additions & 14 deletions digi_analysis/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,27 @@
#include "MinHook.h"
#include <cstdint>
#include <cstring>
#include <cstdio>
#include "opengl_utils.h"
#include "d3d8_gl_bridge.h"
#include "debug_log.h"

// Store the module handle for potential future use.
static HINSTANCE g_hModule = nullptr;

// Forward declaration for InstallHooks function
void InstallHooks();

// Forward declaration for the initialization thread.
static DWORD WINAPI InitializationThread(LPVOID);

// Apply an in‑memory patch to bypass the CD check. The patch data
// and offsets were extracted from the original project. On success
// this routine writes a few bytes to specific offsets relative to
// the module base to disable the CD verification. If the patch
// cannot be applied nothing else is done.
static void ApplyNoCD() {
uintptr_t baseAddress = reinterpret_cast<uintptr_t>(GetModuleHandleA(NULL));
uintptr_t baseAddress = reinterpret_cast<uintptr_t>(GetModuleHandle(nullptr));
struct Patch {
uintptr_t offset;
unsigned char data[8];
Expand All @@ -30,25 +41,33 @@ static void ApplyNoCD() {
};
for (const auto& patch : patches) {
void* address = reinterpret_cast<void*>(baseAddress + patch.offset);
char buf[64];
std::snprintf(buf, sizeof(buf), "NoCD patch @ %p\n", address);
DebugLog("%s", buf);
DWORD oldProtect;
if (VirtualProtect(address, patch.size, PAGE_EXECUTE_READWRITE, &oldProtect)) {
std::memcpy(address, patch.data, patch.size);
VirtualProtect(address, patch.size, oldProtect, &oldProtect);
// Optionally log the patch application via debug output.
// OutputDebugStringA("Applied NoCD patch\n");
}
}
}

// Forward declaration for InstallHooks function
void InstallHooks();
// Perform initialization work once the DLL is fully loaded.
static DWORD WINAPI InitializationThread(LPVOID) {
InitDebugLog();
if (MH_Initialize() == MH_OK) {
InstallHooks();
ApplyNoCD();
}
return 0;
}

// Exported Direct3DCreate8 replacement. This function is exported from
// our DLL under both the decorated and undecorated names via the linker
// directive above. It simply allocates the bridge object and returns it
// to the caller.
extern "C" __declspec(dllexport) IDirect3D8* WINAPI Direct3DCreate8(UINT /*sdkVersion*/) {
OutputDebugStringA("Direct3DCreate8 called – OpenGL backend active\n");
DebugLog("Direct3DCreate8 called – OpenGL backend active\n");
return new IDirect3D8();
}

Expand All @@ -58,23 +77,27 @@ extern "C" __declspec(dllexport) IDirect3D8* WINAPI Direct3DCreate8(UINT /*sdkVe
// game's import table.
#pragma comment(linker, "/export:Direct3DCreate8=_Direct3DCreate8@4")

// DLL entry point. On process attach we install hooks and apply the
// No‑CD patch. On detach we remove hooks. The original Direct3D8
// library is no longer loaded.
// DLL entry point. On process attach we spin up a worker thread to
// perform initialization after the loader lock is released. On detach
// we remove hooks and clean up. The original Direct3D8 library is no
// longer loaded.
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
// Initialize MinHook
if (MH_Initialize() != MH_OK) {
return FALSE;
g_hModule = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
{
HANDLE thread = CreateThread(nullptr, 0, InitializationThread, nullptr, 0, nullptr);
if (thread) {
CloseHandle(thread);
}
}
InstallHooks();
ApplyNoCD();
break;
case DLL_PROCESS_DETACH:
MH_DisableHook(MH_ALL_HOOKS);
MH_Uninitialize();
ShutdownOpenGL();
ShutdownDebugLog();
break;
}
return TRUE;
Expand Down
6 changes: 3 additions & 3 deletions digi_analysis/gdi_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <unordered_map>

#include "text_renderer.h"
#include "debug_log.h"

// Forward declarations of the original functions. We store these in
// static variables so that the detours can call through after doing
Expand Down Expand Up @@ -52,12 +53,11 @@ static PFN_GetTextMetricsA orig_GetTextMetricsA = nullptr;
static PFN_SetTextColor orig_SetTextColor = nullptr;
static PFN_TextOutA orig_TextOutA = nullptr;

// Helper to log a message to the debugger. This avoids duplicating
// the OutputDebugStringA call in every detour.
// Helper to log a message. This avoids duplicating the DebugLog call in every detour.
static void LogCall(const char* funcName) {
char buf[128];
std::snprintf(buf, sizeof(buf), "[GDI hook] %s called\n", funcName);
OutputDebugStringA(buf);
DebugLog("%s", buf);
}

struct DCState {
Expand Down
Loading