-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdllmain.cpp
More file actions
149 lines (134 loc) · 6.35 KB
/
Copy pathdllmain.cpp
File metadata and controls
149 lines (134 loc) · 6.35 KB
1
2
3
4
5
6
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// SacredSDK — ijl15.dll proxy for Sacred Gold (i386).
//
// Build target: Win32 (x86), output filename: ijl15.dll.
// Exports are declared via #pragma comment(linker, "/EXPORT:…") below.
// Each forwards to the renamed real DLL (ijl15_real.dll), with the original
// ordinal preserved so Sacred.exe's ordinal-2..5 imports resolve correctly.
//
// On DLL_PROCESS_ATTACH we:
// 1. capture process metadata (exe path, cmdline, pid, base)
// 2. spawn the overlay thread (own D3D11 window + ImGui)
// 3. write a startup record to sdk\logs\sdk_loaded.log AND the in-memory ring
#include "sdk.h"
#include "engine/build_profile.h"
#include "core/config.h"
#include <stdlib.h> // atoi (sdk.ini flag parse)
// --- Exported forwarders ----------------------------------------------------
// /EXPORT:name=otherdll.name,@ordinal[,NONAME]
// Ordinals match the original ijl15.dll layout (verified by pefile).
#pragma comment(linker, "/EXPORT:ijlGetLibVersion=ijl15_real.ijlGetLibVersion,@1")
#pragma comment(linker, "/EXPORT:ijlInit=ijl15_real.ijlInit,@2")
#pragma comment(linker, "/EXPORT:ijlFree=ijl15_real.ijlFree,@3")
#pragma comment(linker, "/EXPORT:ijlRead=ijl15_real.ijlRead,@4")
#pragma comment(linker, "/EXPORT:ijlWrite=ijl15_real.ijlWrite,@5")
#pragma comment(linker, "/EXPORT:ijlErrorStr=ijl15_real.ijlErrorStr,@6")
namespace sdk {
LogRing g_log{};
AttachInfo g_attach{};
volatile HWND g_sacred_hwnd = nullptr;
// File log path resolved lazily so we don't do FS work in DllMain unless needed.
static char g_log_path[MAX_PATH] = {0};
static CRITICAL_SECTION g_file_cs;
static bool g_file_cs_init = false;
static void resolve_log_path() {
if (g_log_path[0]) return;
char exe_path[MAX_PATH] = {0};
GetModuleFileNameA(NULL, exe_path, MAX_PATH);
char* p = strrchr(exe_path, '\\');
if (p) *p = 0;
char dir[MAX_PATH];
_snprintf_s(dir, _TRUNCATE, "%s\\sdk\\logs", exe_path);
CreateDirectoryA(dir, NULL);
_snprintf_s(g_log_path, _TRUNCATE, "%s\\sdk_loaded.log", dir);
}
void sdk_log(const char* fmt, ...) {
// build the line once
char line[LogRing::LINE_MAX];
SYSTEMTIME st;
GetLocalTime(&st);
int n = _snprintf_s(line, _TRUNCATE,
"[%04d-%02d-%02d %02d:%02d:%02d.%03d] ",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
if (n < 0) return;
va_list args;
va_start(args, fmt);
_vsnprintf_s(line + n, LogRing::LINE_MAX - n, _TRUNCATE, fmt, args);
va_end(args);
// Push to ring (locked, fast)
g_log.push(line);
// Also append to file. Locked separately so overlay reads don't block on disk.
if (g_file_cs_init) {
EnterCriticalSection(&g_file_cs);
resolve_log_path();
FILE* f = nullptr;
fopen_s(&f, g_log_path, "ab");
if (f) { fputs(line, f); fputc('\n', f); fclose(f); }
LeaveCriticalSection(&g_file_cs);
}
}
static void capture_attach(HMODULE self) {
g_attach.pid = GetCurrentProcessId();
g_attach.attach_tid = GetCurrentThreadId();
g_attach.self_module = self;
g_attach.exe_module = GetModuleHandleA(NULL);
g_attach.attach_tick = GetTickCount();
GetModuleFileNameA(NULL, g_attach.exe_path, MAX_PATH);
LPSTR cmd = GetCommandLineA();
if (cmd) strncpy_s(g_attach.cmdline, _TRUNCATE, cmd, _TRUNCATE);
}
} // namespace sdk
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
using namespace sdk;
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
DisableThreadLibraryCalls(hModule);
InitializeCriticalSection(&g_file_cs); g_file_cs_init = true;
g_log.init();
capture_attach(hModule);
// Identify which Sacred.exe we are in BEFORE anything else runs.
// PE headers are not encrypted, so this is safe under loader lock,
// and every later decision about touching .text depends on it.
engine::build::detect();
config::init(); // one parser for sdk.ini + Settings.cfg
sdk_log("=== ijl15 proxy DllMain DLL_PROCESS_ATTACH ===");
sdk_log(" exe = %s", g_attach.exe_path);
sdk_log(" cmdline = %s", g_attach.cmdline);
sdk_log(" pid/tid = %lu / %lu", g_attach.pid, g_attach.attach_tid);
sdk_log(" self base = %p", g_attach.self_module);
sdk_log(" exe base = %p", g_attach.exe_module);
fs_override::install(); // CreateFileA IAT redirect (custom/ overrides any read)
hooks::install(); // IAT patches go in before EP, so Sacred sees us
// DO NOT install .text patches here — at DllMain
// time the .bind SafeDisc stub hasn't decrypted
// yet, so any byte we write into .text gets
// XOR'd into garbage. patches::install() is now
// chained off dumptext's entropy-trigger worker.
dumptext::start(); // worker: wait for .bind decryption, then dump
// AND call patches::install()
lua_bake::start_auto_bake(); // worker: walk custom/lua/, produce custom/*.bin
overlay::start();
// Dev self-tests are OFF by default (not everyone has PAX saves, and
// per-launch probes are log noise). Opt in via sdk.ini `selftest=1`.
// All functionality stays available on demand — the engine VAs and
// game-zlib resolve LAZILY on first sacred.read_save/globalres/etc.
if (config::get_bool("sdk", "selftest", false)) {
sdk_log("[startup] selftest=1 — running hero-save + engine-resolve self-tests");
start_hero_save_probe(); // worker: self-test the wired PAX hero-save port
engine_resolve::start_engine_resolve(); // worker: verify engine VAs + globalres probe
}
break;
}
case DLL_PROCESS_DETACH: {
sdk_log("=== DLL_PROCESS_DETACH (lpReserved=%p) ===", lpReserved);
overlay::stop();
g_log.shutdown();
if (g_file_cs_init) {
DeleteCriticalSection(&g_file_cs);
g_file_cs_init = false;
}
break;
}
}
return TRUE;
}