-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpatch_memory.cpp
More file actions
168 lines (135 loc) · 5.04 KB
/
patch_memory.cpp
File metadata and controls
168 lines (135 loc) · 5.04 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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "hook.h"
// Dump memory range for verification
// Hex + ASCII memory dump using LogMessage
void DumpMemoryRange(BYTE* base_address, DWORD offset, int range, const char* description) {
BYTE* target = base_address + offset;
if (!target) {
LogMessage("ERROR: DumpMemoryRange called with NULL base address");
return;
}
LogMessage("%s", description);
LogMessage("Address range: 0x%p to 0x%p", (void*)target, (void*)(target + range));
if (IsBadReadPtr(target, range + 1)) {
LogMessage("ERROR: Cannot read memory range");
return;
}
// Print hex dump in rows of 16 bytes
for (int i = 0; i <= range; i += 16) {
char line[512] = {0};
char* p = line;
// Address prefix
p += sprintf(p, "0x%p: ", (void*)(target + i));
// Hex bytes
for (int j = 0; j < 16 && (i + j) <= range; j++) {
p += sprintf(p, "%02X ", target[i + j]);
}
// Pad if less than 16 bytes
int bytes_this_row = (range - i + 1 < 16) ? (range - i + 1) : 16;
for (int j = bytes_this_row; j < 16; j++) {
p += sprintf(p, " ");
}
// ASCII representation
p += sprintf(p, "| ");
for (int j = 0; j < bytes_this_row; j++) {
BYTE b = target[i + j];
*p++ = (b >= 32 && b <= 126) ? (char)b : '.';
}
*p = '\0';
LogMessage("%s", line);
}
}
// Pattern recognition to support updated game binary
void* FindPattern(const unsigned char* pattern, int pattern_length) {
if (!g_whgame_base) {
LogMessage("ERROR: g_whgame_base is NULL");
return NULL;
}
// Get module size
MODULEINFO mod_info;
if (!GetModuleInformation(GetCurrentProcess(), (HMODULE)g_whgame_base, &mod_info, sizeof(mod_info))) {
LogMessage("ERROR: Failed to get module info");
return NULL;
}
BYTE* base = (BYTE*)g_whgame_base;
size_t search_size = mod_info.SizeOfImage;
// Search for pattern
for (size_t i = 0; i < search_size - pattern_length; i++) {
bool found = true;
for (int j = 0; j < pattern_length; j++) {
if (base[i + j] != pattern[j]) {
found = false;
break;
}
}
if (found) {
void* result = (void*)(base + i);
DWORD64 offset = i;
LogMessage("Pattern found at: 0x%p (offset: 0x%llX)", result, offset);
return result;
}
}
LogMessage("Pattern NOT found");
return NULL;
}
// Generic memory patching function
BOOL PatchMemory(BYTE* base_address, DWORD offset, BYTE* patch_bytes, size_t patch_size) {
BYTE* target_address = base_address + offset;
if (IsBadReadPtr(target_address, patch_size)) {
LogMessage("ERROR: Cannot read target address 0x%p!", target_address);
return FALSE;
}
DWORD old_protect;
if (!VirtualProtect(target_address, patch_size, PAGE_EXECUTE_READWRITE, &old_protect)) {
LogMessage("ERROR: VirtualProtect failed! Error code: 0x%08X", GetLastError());
return FALSE;
}
DumpMemoryRange(base_address, offset, 0xF, "BEFORE PATCH:");
for (size_t i = 0; i < patch_size; i++) {
target_address[i] = patch_bytes[i];
}
DumpMemoryRange(base_address, offset, 0xF, "AFTER PATCH:");
VirtualProtect(target_address, patch_size, old_protect, &old_protect);
return TRUE;
}
// Apply memory patch
BOOL ApplyMemoryPatch() {
LogMessage("Starting ApplyMemoryPatch");
if (!g_whgame_base) {
LogMessage("ERROR: g_whgame_base is NULL!");
return FALSE;
}
BYTE patch[3];
BOOL success = true;
unsigned char pattern[] = {0x32, 0xc0, 0x38, 0x41, 0x45, 0x75, 0x07,
0x38, 0x41, 0x44, 0x75, 0x02, 0xb0, 0x01, 0xc3};
int pattern_length = sizeof(pattern);
void* isvalid_addr = FindPattern(pattern, pattern_length);
if (!isvalid_addr) {
LogMessage("Pattern not found");
char error_msg[512];
snprintf(error_msg, sizeof(error_msg),
"Failed to find IsValid pattern!\n\n"
"WHGame.dll base: 0x%p\n\n"
"The game engine may have been updated.\n"
"Please report this issue in github.com/AlvinHV/KCD2_mac_fix",
g_whgame_base);
MessageBoxA(NULL, error_msg, "Pattern Search Failed", MB_OK | MB_ICONERROR);
return FALSE;
}
// makes IsValid() from LoadMaterial always returns true since in macOS all resources marked as to be deleted
patch[0] = 0xb0;
patch[1] = 0x01;
patch[0] = 0xc3;
DWORD64 offset = (DWORD64)isvalid_addr - (DWORD64)g_whgame_base;
// success = PatchMemory((BYTE*)g_whgame_base, (DWORD) offset, patch, 3);
// if (!success) {
// return success;
// }
// patch[0] = 0xeb;
// patch[1] = 0x0a;
// success = PatchMemory((BYTE*)g_whgame_base, 0x56870C, patch, 2);
// patch[0] = 0x1C;
// patch[1] = 0x57;
// success = PatchMemory((BYTE*)g_whgame_base, 0x61C169, patch, 2);
return success;
}