Skip to content

Commit d652c89

Browse files
committed
FaultyFileDetector: Enable in RE9/TDB81+
1 parent 4c4cdb6 commit d652c89

3 files changed

Lines changed: 37 additions & 15 deletions

File tree

src/Mods.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Mods::Mods() {
3535
m_mods.emplace_back(Hooks::get());
3636
m_mods.emplace_back(LooseFileLoader::get());
3737

38-
#if defined(MHWILDS)
38+
#if TDB_VER >= 81
3939
m_mods.emplace_back(FaultyFileDetector::get());
4040
#endif
4141

src/REFramework.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ REFramework::REFramework(HMODULE reframework_module)
504504
startup_lookup_thread->detach();
505505
#endif
506506

507-
#if defined(MHWILDS)
507+
#if TDB_VER >= 81
508508
FaultyFileDetector::early_init();
509509
#endif
510510

src/mods/FaultyFileDetector.cpp

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -198,45 +198,65 @@ bool FaultyFileDetector::scan_resource_process_parse_and_hook() {
198198
const int first_call_vtable_offset = 0x20;
199199
const int second_call_vtable_offset = 0x48;
200200
const int third_call_vtable_offset = 0x38;
201+
bool found[3]{false, false, false};
201202

202-
const int max_instructions_search_range = 60;
203+
const int max_instructions_search_range = 100;
203204

204205
int current_calls_found = 0;
205206

206207
std::uint8_t *parse_call_ptr = nullptr;
207208
std::uint8_t *parse_call_return_address = nullptr;
208209
std::uint8_t *start_searching_resource_access_ptr = nullptr;
209210

210-
for (int i = 0; i < max_instructions_search_range; i++) {
211-
auto instr = utility::decode_one(after_call_ptr);
212-
if (!instr.has_value()) {
213-
break;
211+
//for (int i = 0; i < max_instructions_search_range; i++) {
212+
//auto instr = utility::decode_one(after_call_ptr);
213+
//if (!instr.has_value()) {
214+
//break;
215+
//}
216+
// exhaustive_decode instead. seen to be using non contiguous control flow in some games.
217+
utility::exhaustive_decode((uint8_t*)after_call_ptr, max_instructions_search_range, [&](utility::ExhaustionContext& ctx) -> utility::ExhaustionResult {
218+
if (current_calls_found >= 3) {
219+
return utility::ExhaustionResult::BREAK;
214220
}
221+
222+
auto* instr = &ctx.instrux;
215223

216224
if (instr->Instruction == ND_INS_CALLNI) {
217225
if (instr->OperandsCount >= 1 && instr->Operands[0].Type == ND_OP_MEM) {
218226
auto mem_operand = instr->Operands[0].Info.Memory;
219227
if (mem_operand.Base == NDR_RAX) {
220-
if (current_calls_found == 0 && mem_operand.Disp == first_call_vtable_offset) {
228+
if (mem_operand.Disp == first_call_vtable_offset && !found[0]) {
221229
// First call found
222230
current_calls_found++;
223231
start_searching_resource_access_ptr = after_call_ptr + instr->Length;
224-
} else if (current_calls_found == 1 && mem_operand.Disp == second_call_vtable_offset) {
232+
found[0] = true;
233+
spdlog::info("[FaultyFileDetector]: Found first call at 0x{:X}", (uintptr_t)after_call_ptr);
234+
} else if (mem_operand.Disp == second_call_vtable_offset && !found[1]) {
225235
// Second call found
226236
current_calls_found++;
227237
parse_call_ptr = after_call_ptr;
228238
parse_call_return_address = after_call_ptr + instr->Length;
229-
} else if (current_calls_found == 2 && mem_operand.Disp == third_call_vtable_offset) {
239+
found[1] = true;
240+
spdlog::info("[FaultyFileDetector]: Found second call at 0x{:X}", (uintptr_t)after_call_ptr);
241+
} else if (mem_operand.Disp == third_call_vtable_offset && !found[2]) {
230242
// Third call found
231243
current_calls_found++;
232-
break;
244+
found[2] = true;
245+
spdlog::info("[FaultyFileDetector]: Found third call at 0x{:X}", (uintptr_t)after_call_ptr);
233246
}
234247
}
235248
}
236249
}
237250

238251
after_call_ptr += instr->Length;
239-
}
252+
253+
// step over calls.
254+
if (instr->Category == ND_CAT_CALL) {
255+
return utility::ExhaustionResult::STEP_OVER;
256+
}
257+
258+
return utility::ExhaustionResult::CONTINUE;
259+
});
240260

241261
if (current_calls_found == 3) {
242262
// Definitively what we are looking for
@@ -249,13 +269,15 @@ bool FaultyFileDetector::scan_resource_process_parse_and_hook() {
249269
std::uint8_t *resource_argument_assigned_ptr = nullptr;
250270

251271
// Very fragile way, but it works for now
252-
for (int i = 0; i < resource_register_search_max_num_instructions && instr_ptr < parse_call_ptr; i++) {
272+
for (int i = 0; i < resource_register_search_max_num_instructions; i++) {
253273
auto instrux = utility::decode_one(instr_ptr);
254-
if (instrux && instrux->Instruction == ND_INS_MOV) {
274+
if (instrux && std::string_view(instrux->Mnemonic).starts_with("MOV")) {
255275
bool is_first_operator_first_arg = instrux->OperandsCount >= 1 && instrux->Operands[0].Type == ND_OP_REG && instrux->Operands[0].Info.Register.Reg == NDR_RCX;
256276
bool is_second_operator_register = instrux->OperandsCount >= 2 && instrux->Operands[1].Type == ND_OP_REG;
277+
// Seen in RE9
278+
bool is_second_operator_rsp_based = instrux->OperandsCount >= 2 && instrux->Operands[1].Type == ND_OP_MEM && instrux->Operands[1].Info.Memory.Base == NDR_RSP;
257279

258-
if (is_first_operator_first_arg && is_second_operator_register) {
280+
if (is_first_operator_first_arg && (is_second_operator_register || is_second_operator_rsp_based)) {
259281
resource_argument_assigned_ptr = instr_ptr + instrux->Length;
260282
spdlog::info("[FaultyFileDetector]: Found resource argument assign at 0x{:x}, hooking to extract it at: 0x{:x}", (uintptr_t)instr_ptr, (uintptr_t)resource_argument_assigned_ptr);
261283

0 commit comments

Comments
 (0)