9
9
#include < algorithm>
10
10
#include < atomic>
11
11
#include < cctype>
12
+ #include < filesystem>
13
+ #include < fstream>
12
14
#include < functional>
13
15
#include < future>
14
16
#include < locale>
15
17
#include < mutex>
16
18
#include < sstream>
17
19
#include < vector>
18
- #include < fstream>
19
- #include < filesystem>
20
20
21
21
namespace anno
22
22
{
23
23
struct AddressInfo {
24
- std::function<uintptr_t (std::string_view)> pattern_lookup;
25
- uintptr_t address = 0 ;
24
+ std::function<uintptr_t (std::optional<std:: string_view> )> pattern_lookup;
25
+ uintptr_t address = 0 ;
26
26
};
27
27
28
28
static AddressInfo ADDRESSES[Address::SIZE] = {};
@@ -40,142 +40,259 @@ inline uint64_t adjust_address(uint64_t address)
40
40
return base_address + offset;
41
41
}
42
42
43
- bool FindAddresses () {
43
+ static uintptr_t RebaseFileOffsetToMemoryAddess (uintptr_t file_offset)
44
+ {
45
+ auto executable_address = GetModuleHandle (NULL );
46
+
47
+ PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)(executable_address);
48
+ if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
49
+ throw std::runtime_error (" Invalid DOS Signature" );
50
+ }
51
+
52
+ PIMAGE_NT_HEADERS header =
53
+ (PIMAGE_NT_HEADERS)(((char *)executable_address + (dosHeader->e_lfanew * sizeof (char ))));
54
+ if (header->Signature != IMAGE_NT_SIGNATURE) {
55
+ throw std::runtime_error (" Invalid NT Signature" );
56
+ }
57
+
58
+ PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION (header);
59
+
60
+ for (int32_t i = 0 ; i < header->FileHeader .NumberOfSections ; i++, section++) {
61
+ bool executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0 ;
62
+ bool readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0 ;
63
+ spdlog::debug (" {}, {} -> {}" , section->PointerToRawData ,
64
+ section->PointerToRawData + section->SizeOfRawData );
65
+ if (file_offset >= section->PointerToRawData
66
+ && file_offset <= section->PointerToRawData + section->SizeOfRawData ) {
67
+ return (uintptr_t )executable_address + file_offset
68
+ + ((intptr_t )section->VirtualAddress - (intptr_t )section->PointerToRawData );
69
+ }
70
+ }
71
+ return 0xDEAD ;
72
+ }
73
+
74
+ bool FindAddresses ()
75
+ {
44
76
if (!initialized) {
45
77
std::scoped_lock lk{initialization_mutex};
46
78
if (initialized) {
47
79
return true ;
48
80
}
49
81
initialized = true ;
50
82
51
- ADDRESSES[GET_CONTAINER_BLOCK_INFO] = {[](std::string_view game_file) {
52
- auto cont = meow_hook::pattern (
53
- " 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 48 83 79 78 00 44 89 C6" )
54
- .count (1 )
55
- .get (0 )
56
- .as <uintptr_t >();
57
- return cont;
83
+ ADDRESSES[GET_CONTAINER_BLOCK_INFO] = {[](std::optional<std::string_view> game_file) {
84
+ auto match = meow_hook::pattern (
85
+ " 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 48 83 79 78 00 44 89 C6" ,
86
+ game_file)
87
+ .count (1 )
88
+ .get (0 )
89
+ .as <uintptr_t >();
90
+ if (game_file) {
91
+ return RebaseFileOffsetToMemoryAddess (
92
+ match - reinterpret_cast <intptr_t >(game_file->data ()));
93
+ }
94
+ return match;
58
95
}}; //
59
96
60
- ADDRESSES[READ_FILE_FROM_CONTAINER] = {[](std::string_view game_file) {
97
+ ADDRESSES[READ_FILE_FROM_CONTAINER] = {[](std::optional<std:: string_view> game_file) {
61
98
// Post Game Update 7
62
99
try {
63
- return meow_hook::pattern (" E8 ? ? ? ? 0F B6 F8 48 8D 4D C0" )
64
- .count (1 )
65
- .get (0 )
66
- .extract_call ();
100
+ auto match = meow_hook::pattern (" E8 ? ? ? ? 0F B6 F8 48 8D 4D C0" , game_file)
101
+ .count (1 )
102
+ .get (0 );
103
+ if (game_file) {
104
+ match = match.adjust (
105
+ RebaseFileOffsetToMemoryAddess (
106
+ match.as <uintptr_t >() - reinterpret_cast <intptr_t >(game_file->data ()))
107
+ - match.as <uintptr_t >());
108
+ }
109
+ return match.extract_call ();
67
110
} catch (...) {
68
- return meow_hook::pattern (" E8 ? ? ? ? 0F B6 D8 48 8D 4D C0" )
69
- .count (1 )
70
- .get (0 )
71
- .extract_call ();
111
+ auto match = meow_hook::pattern (" E8 ? ? ? ? 0F B6 D8 48 8D 4D C0" , game_file)
112
+ .count (1 )
113
+ .get (0 );
114
+ if (game_file) {
115
+ match = match.adjust (
116
+ RebaseFileOffsetToMemoryAddess (
117
+ match.as <uintptr_t >() - reinterpret_cast <intptr_t >(game_file->data ()))
118
+ - match.as <uintptr_t >());
119
+ }
120
+ return match.extract_call ();
72
121
}
73
122
}};
74
123
75
- ADDRESSES[SOME_GLOBAL_STRUCTURE_ARCHIVE] = {[](std::string_view game_file) {
124
+ ADDRESSES[SOME_GLOBAL_STRUCTURE_ARCHIVE] = {[](std::optional<std:: string_view> game_file) {
76
125
// Post Game Update 7
77
126
try {
78
- return meow_hook::pattern (" 75 4F B9 18 00 00 00" )
79
- . count ( 1 )
80
- . get ( 0 )
81
- . adjust (- 8 )
82
- . adjust ( 3 )
83
- . add_disp ()
84
- . adjust ( 13 )
85
- .as <uintptr_t >();
127
+ auto match = meow_hook::pattern (" 75 4F B9 18 00 00 00" , game_file). count ( 1 ). get ( 0 );
128
+ if (game_file) {
129
+ match = match. adjust (
130
+ RebaseFileOffsetToMemoryAddess (
131
+ match. as < uintptr_t >() - reinterpret_cast < intptr_t >(game_file-> data ()) )
132
+ - match. as < uintptr_t >());
133
+ }
134
+ return match. adjust (- 8 ). adjust ( 3 ). add_disp (). adjust ( 13 ) .as <uintptr_t >();
86
135
} catch (...) {
87
- return meow_hook::pattern (" 75 3B B9 18 00 00 00" )
88
- . count ( 1 )
89
- . get ( 0 )
90
- . adjust (- 8 )
91
- . adjust ( 3 )
92
- . add_disp ()
93
- . adjust ( 13 )
94
- .as <uintptr_t >();
136
+ auto match = meow_hook::pattern (" 75 3B B9 18 00 00 00" , game_file). count ( 1 ). get ( 0 );
137
+ if (game_file) {
138
+ match = match. adjust (
139
+ RebaseFileOffsetToMemoryAddess (
140
+ match. as < uintptr_t >() - reinterpret_cast < intptr_t >(game_file-> data ()) )
141
+ - match. as < uintptr_t >());
142
+ }
143
+ return match. adjust (- 8 ). adjust ( 3 ). add_disp (). adjust ( 13 ) .as <uintptr_t >();
95
144
}
96
145
}};
97
- ADDRESSES[TOOL_ONE_DATA_HELPER_RELOAD_DATA] = {[](std::string_view game_file) {
98
- //
99
- // Post Game Update 7
100
- try {
101
- return meow_hook::pattern (
102
- " 48 8B C4 55 48 8D 68 A1 48 81 EC ? ? ? ? 48 C7 45 ? ? ? ? "
103
- " ? 48 89 58 08 48 89 70 18 48 89 78 20 48 8D 45 9F" )
104
- .count (1 )
105
- .get (0 )
106
- .as <uintptr_t >();
107
- } catch (...) {
108
- // Pre Game Update 7
146
+ ADDRESSES[TOOL_ONE_DATA_HELPER_RELOAD_DATA] = {
147
+ [](std::optional<std::string_view> game_file) {
148
+ //
149
+ // Post Game Update 7
109
150
try {
110
- return meow_hook::pattern (
111
- " 40 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 C7 45 ? ? ? ? ? 48 "
112
- " 89 9C 24 ? ? ? ? 48 8D 45 9F" )
113
- .count (1 )
114
- .get (0 )
115
- .as <uintptr_t >();
151
+ auto match = meow_hook::pattern (
152
+ " 48 8B C4 55 48 8D 68 A1 48 81 EC ? ? ? ? 48 C7 45 ? ? ? ? "
153
+ " ? 48 89 58 08 48 89 70 18 48 89 78 20 48 8D 45 9F" ,
154
+ game_file)
155
+ .count (1 )
156
+ .get (0 );
157
+ if (game_file) {
158
+ match = match.adjust (RebaseFileOffsetToMemoryAddess (
159
+ match.as <uintptr_t >()
160
+ - reinterpret_cast <intptr_t >(game_file->data ()))
161
+ - match.as <uintptr_t >());
162
+ }
163
+ return match.as <uintptr_t >();
116
164
} catch (...) {
117
- return meow_hook::pattern (" 48 8B C4 55 48 8D 68 A1 48 81 EC ? ? ? ? 48 C7 45 ? ? ? ? "
118
- " ? 48 89 58 08 48 89 70 18 48 89 78 20 48 8D 45 9F" )
119
- .count (1 )
120
- .get (0 )
121
- .as <uintptr_t >();
165
+ // Pre Game Update 7
166
+ try {
167
+ auto match =
168
+ meow_hook::pattern (
169
+ " 40 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 C7 45 ? ? ? ? ? 48 "
170
+ " 89 9C 24 ? ? ? ? 48 8D 45 9F" ,
171
+ game_file)
172
+ .count (1 )
173
+ .get (0 );
174
+ if (game_file) {
175
+ match =
176
+ match.adjust (RebaseFileOffsetToMemoryAddess (
177
+ match.as <uintptr_t >()
178
+ - reinterpret_cast <intptr_t >(game_file->data ()))
179
+ - match.as <uintptr_t >());
180
+ }
181
+ return match.as <uintptr_t >();
182
+ } catch (...) {
183
+ auto match =
184
+ meow_hook::pattern (
185
+ " 48 8B C4 55 48 8D 68 A1 48 81 EC ? ? ? ? 48 C7 45 ? ? ? ? "
186
+ " ? 48 89 58 08 48 89 70 18 48 89 78 20 48 8D 45 9F" ,
187
+ game_file)
188
+ .count (1 )
189
+ .get (0 );
190
+ if (game_file) {
191
+ match =
192
+ match.adjust (RebaseFileOffsetToMemoryAddess (
193
+ match.as <uintptr_t >()
194
+ - reinterpret_cast <intptr_t >(game_file->data ()))
195
+ - match.as <uintptr_t >());
196
+ }
197
+ return match.as <uintptr_t >();
198
+ }
122
199
}
200
+ }};
201
+ ADDRESSES[FILE_GET_FILE_SIZE] = {[](std::optional<std::string_view> game_file) {
202
+ auto match =
203
+ meow_hook::pattern (" E8 ? ? ? ? 0F B6 D8 48 8D 4D B0" , game_file).count (1 ).get (0 );
204
+ if (game_file) {
205
+ match = match.adjust (
206
+ RebaseFileOffsetToMemoryAddess (match.as <uintptr_t >()
207
+ - reinterpret_cast <intptr_t >(game_file->data ()))
208
+ - match.as <uintptr_t >());
123
209
}
210
+ return match.extract_call ();
124
211
}};
125
- ADDRESSES[FILE_GET_FILE_SIZE] = {[](std::string_view game_file) {
126
- return meow_hook::pattern (" E8 ? ? ? ? 0F B6 D8 48 8D 4D B0" )
127
- .count (1 )
128
- .get (0 )
129
- .extract_call ();
130
- }};
131
- ADDRESSES[READ_GAME_FILE] = {[](std::string_view game_file) {
132
- return meow_hook::pattern (" 48 89 5C 24 ? 48 89 6C 24 ? 56 48 83 EC 30 48 8B 81 ? ? ? ?" )
133
- .count (1 )
134
- .get (0 )
135
- .as <uintptr_t >();
212
+ ADDRESSES[READ_GAME_FILE] = {[](std::optional<std::string_view> game_file) {
213
+ auto match =
214
+ meow_hook::pattern (" 48 89 5C 24 ? 48 89 6C 24 ? 56 48 83 EC 30 48 8B 81 ? ? ? ?" ,
215
+ game_file)
216
+ .count (1 )
217
+ .get (0 );
218
+ if (game_file) {
219
+ match = match.adjust (
220
+ RebaseFileOffsetToMemoryAddess (match.as <uintptr_t >()
221
+ - reinterpret_cast <intptr_t >(game_file->data ()))
222
+ - match.as <uintptr_t >());
223
+ }
224
+ return match.as <uintptr_t >();
136
225
}};
137
- ADDRESSES[SOME_GLOBAL_STRUCT_TOOL_ONE_HELPER_MAYBE] = {[](std::string_view game_file) {
226
+ ADDRESSES[SOME_GLOBAL_STRUCT_TOOL_ONE_HELPER_MAYBE] = {[](std::optional<std::string_view>
227
+ game_file) {
138
228
// Post Game Update 7
139
- ;
140
- ;
141
229
try {
142
- return meow_hook::pattern (" 48 8B 3D ? ? ? ? 4C 8B 5D DF" )
143
- .count (1 )
144
- .get (0 )
145
- .adjust (3 )
146
- .add_disp ()
147
- .adjust (4 )
148
- .as <uintptr_t >();
230
+ auto match =
231
+ meow_hook::pattern (" 48 8B 3D ? ? ? ? 4C 8B 5D DF" , game_file).count (1 ).get (0 );
232
+ if (game_file) {
233
+ match = match.adjust (
234
+ RebaseFileOffsetToMemoryAddess (
235
+ match.as <uintptr_t >() - reinterpret_cast <intptr_t >(game_file->data ()))
236
+ - match.as <uintptr_t >());
237
+ }
238
+ return match.adjust (3 ).add_disp ().adjust (4 ).as <uintptr_t >();
149
239
} catch (...) {
150
240
// Pre Game Update 7
151
- return meow_hook::pattern (" 48 8B 0D ? ? ? ? E8 ? ? ? ? 90 48 8D 4D FF" )
152
- .count (1 )
153
- .get (0 )
154
- .adjust (3 )
155
- .add_disp ()
156
- .adjust (4 )
157
- .as <uintptr_t >(); }
241
+ auto match =
242
+ meow_hook::pattern (" 48 8B 0D ? ? ? ? E8 ? ? ? ? 90 48 8D 4D FF" , game_file)
243
+ .count (1 )
244
+ .get (0 );
245
+ if (game_file) {
246
+ match = match.adjust (
247
+ RebaseFileOffsetToMemoryAddess (
248
+ match.as <uintptr_t >() - reinterpret_cast <intptr_t >(game_file->data ()))
249
+ - match.as <uintptr_t >());
250
+ }
251
+ return match.adjust (3 ).add_disp ().adjust (4 ).as <uintptr_t >();
252
+ }
158
253
}};
159
254
255
+ std::filesystem::path process_file_path;
256
+
257
+ {
258
+ wchar_t process_name[1024 ] = {0 };
259
+ DWORD process_name_size = 1024 ;
260
+ QueryFullProcessImageNameW (GetCurrentProcess (), 0 , process_name, &process_name_size);
261
+ process_file_path = process_name;
262
+ }
263
+
264
+ std::fstream is (process_file_path, std::ios::in | std::ios::binary);
265
+ is.seekg (0 , std::ios::end);
266
+ size_t data_size = is.tellg ();
267
+ is.seekg (0 , std::ios::beg);
268
+ std::unique_ptr<char []> data (new char [data_size]);
269
+ is.read (data.get (), data_size);
270
+
271
+ std::string_view game_file (data.get (), data_size);
160
272
//
161
273
bool any_address_failed = false ;
162
274
for (int attempt = 0 ; attempt < 5 ; ++attempt) {
163
275
any_address_failed = false ;
164
- int index = 0 ;
276
+ int index = 0 ;
165
277
for (auto &address : ADDRESSES) {
166
278
uintptr_t pattern_matched_address = 0 ;
167
279
//
168
280
try {
169
281
pattern_matched_address = address.pattern_lookup ({});
170
282
} catch (...) {
171
- pattern_matched_address = 0xDEAD ;
283
+ try {
284
+ spdlog::debug (" Address search fallback to file search" );
285
+ pattern_matched_address = address.pattern_lookup (game_file);
286
+ } catch (...) {
287
+ pattern_matched_address = 0xDEAD ;
288
+ }
172
289
}
173
290
174
291
// If we fail to find an address, we are in trouble :)
175
292
// Mod loader needs updating
176
293
if (pattern_matched_address != 0xDEAD && pattern_matched_address != 0 ) {
177
294
address.address = pattern_matched_address;
178
- spdlog::debug (" Matched address {}" , (void *)pattern_matched_address);
295
+ spdlog::debug (" Matched address {}" , (void *)pattern_matched_address);
179
296
} else {
180
297
any_address_failed = true ;
181
298
spdlog::error (" Failed to find address, please create an issue on GitHub {}" ,
0 commit comments