Skip to content

Commit cb63dc9

Browse files
committed
UE5.1: Fix rare crash
1 parent 91f0cdf commit cb63dc9

File tree

2 files changed

+97
-11
lines changed

2 files changed

+97
-11
lines changed

src/mods/vr/FFakeStereoRenderingHook.cpp

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6142,7 +6142,7 @@ bool VRRenderTargetManager_Base::need_reallocate_depth_texture(const void* Depth
61426142
return false;
61436143
}
61446144

6145-
void VRRenderTargetManager_Base::pre_texture_hook_callback(safetyhook::Context& ctx) {
6145+
void VRRenderTargetManager_Base::pre_texture_hook_callback(safetyhook::Context& ctx, bool from_second) {
61466146
SPDLOG_INFO("PreTextureHook called! {}", ctx.r8);
61476147

61486148
// maybe do some work later to bruteforce the registers/offsets for these
@@ -6178,7 +6178,9 @@ void VRRenderTargetManager_Base::pre_texture_hook_callback(safetyhook::Context&
61786178

61796179
SPDLOG_INFO("Attempting to JIT a function to call the original function!");
61806180

6181-
const auto ix = utility::decode_one(rtm->texture_create_insn_bytes.data(), rtm->texture_create_insn_bytes.size());
6181+
auto insn_bytes = !from_second ? rtm->texture_create_insn_bytes : rtm->texture_create_insn_bytes2;
6182+
6183+
const auto ix = utility::decode_one(insn_bytes.data(), insn_bytes.size());
61826184

61836185
if (!ix) {
61846186
SPDLOG_ERROR("Failed to decode instruction!");
@@ -6194,8 +6196,8 @@ void VRRenderTargetManager_Base::pre_texture_hook_callback(safetyhook::Context&
61946196
// Set up the emulator. We will use it to emulate the function call.
61956197
// All we need from it is where the function call lands, so we can call it for real.
61966198
auto emu_ctx = utility::ShemuContext(
6197-
(uintptr_t)rtm->texture_create_insn_bytes.data(),
6198-
rtm->texture_create_insn_bytes.size());
6199+
(uintptr_t)insn_bytes.data(),
6200+
insn_bytes.size());
61996201

62006202
emu_ctx.ctx->Registers.RegRcx = ctx.rcx;
62016203
emu_ctx.ctx->Registers.RegRdx = ctx.rdx;
@@ -6211,9 +6213,10 @@ void VRRenderTargetManager_Base::pre_texture_hook_callback(safetyhook::Context&
62116213
emu_ctx.ctx->Registers.RegR13 = ctx.r13;
62126214
emu_ctx.ctx->Registers.RegR14 = ctx.r14;
62136215
emu_ctx.ctx->Registers.RegR15 = ctx.r15;
6216+
emu_ctx.ctx->Registers.RegRsp = ctx.rsp;
62146217
emu_ctx.ctx->MemThreshold = 1;
62156218

6216-
if (emu_ctx.emulate((uintptr_t)rtm->texture_create_insn_bytes.data(), 1) != SHEMU_SUCCESS) {
6219+
if (emu_ctx.emulate((uintptr_t)insn_bytes.data(), 1) != SHEMU_SUCCESS) {
62176220
SPDLOG_ERROR("Failed to emulate instruction!: {} RIP: {:x}", emu_ctx.status, emu_ctx.ctx->Registers.RegRip);
62186221
return;
62196222
}
@@ -6222,7 +6225,7 @@ void VRRenderTargetManager_Base::pre_texture_hook_callback(safetyhook::Context&
62226225
func_ptr = emu_ctx.ctx->Registers.RegRip;
62236226
} else {
62246227
const auto target = g_hook->get_render_target_manager()->pre_texture_hook.target_address();
6225-
func_ptr = target + 5 + *(int32_t*)&rtm->texture_create_insn_bytes.data()[1];
6228+
func_ptr = target + 5 + *(int32_t*)&insn_bytes.data()[1];
62266229
}
62276230

62286231
SPDLOG_INFO("Function pointer: {:x}", func_ptr);
@@ -6790,7 +6793,7 @@ void VRRenderTargetManager_Base::pre_texture_hook_callback(safetyhook::Context&
67906793
VR::get()->reinitialize_renderer();
67916794
}
67926795

6793-
void VRRenderTargetManager_Base::texture_hook_callback(safetyhook::Context& ctx) {
6796+
void VRRenderTargetManager_Base::texture_hook_callback(safetyhook::Context& ctx, bool from_second) {
67946797
auto rtm = g_hook->get_render_target_manager();
67956798

67966799
SPDLOG_INFO("Post texture hook called!");
@@ -7568,6 +7571,7 @@ bool VRRenderTargetManager_Base::allocate_render_target_texture(uintptr_t return
75687571

75697572
while(true) {
75707573
if (emu.ctx->InstructionsCount > 200) {
7574+
SPDLOG_WARN("Emulated too many instructions without finding the call, aborting!");
75717575
break;
75727576
}
75737577

@@ -7643,6 +7647,27 @@ bool VRRenderTargetManager_Base::allocate_render_target_texture(uintptr_t return
76437647
next_call_is_not_the_right_one = true;
76447648
}
76457649
}
7650+
} else {
7651+
// Check how many instructions are in the call. If there's <= 30 AND there's no call/jmp in it, this is not the right one
7652+
size_t insn_count = 0;
7653+
bool encountered_branch = false;
7654+
utility::exhaustive_decode((uint8_t*)fn, 200, [&](const utility::ExhaustionContext& ctx) -> utility::ExhaustionResult {
7655+
if (++insn_count >= 30) {
7656+
return utility::ExhaustionResult::BREAK;
7657+
}
7658+
7659+
if (std::string_view{ctx.instrux.Mnemonic}.starts_with("CALL") || std::string_view{ctx.instrux.Mnemonic}.starts_with("JMP")) {
7660+
encountered_branch = true;
7661+
return utility::ExhaustionResult::BREAK;
7662+
}
7663+
7664+
return utility::ExhaustionResult::CONTINUE;
7665+
});
7666+
7667+
if (insn_count <= 30 && !encountered_branch) {
7668+
SPDLOG_INFO("Function at {:x} only has {} instructions and no calls/branches, skipping this call!", fn, insn_count);
7669+
next_call_is_not_the_right_one = true;
7670+
}
76467671
}
76477672
}
76487673
} catch(...) {
@@ -7670,7 +7695,62 @@ bool VRRenderTargetManager_Base::allocate_render_target_texture(uintptr_t return
76707695
this->texture_create_insn_bytes.resize(decoded->Length);
76717696
memcpy(this->texture_create_insn_bytes.data(), (void*)ip, decoded->Length);
76727697

7673-
auto texture_hook_result = safetyhook::MidHook::create((void*)post_call, &VRRenderTargetManager::texture_hook_callback);
7698+
if (this->is_version_greq_5_1 && !this->is_pre_texture_call_e8 && bytes[-7] == 0x48 && bytes[-6] == 0x8B && bytes[-5] == 0x0D && bytes[0] == 0xFF && bytes[1] == 0x94) {
7699+
// Scan forward for a similar one and also hook that
7700+
auto second_call = utility::scan((uintptr_t)ip + decoded->Length, 0x60, "48 8B 0D ? ? ? ? FF 94 ? ? ? ? ?");
7701+
7702+
if (second_call) {
7703+
// So we can call the original texture create function again.
7704+
this->texture_create_insn_bytes2.resize(decoded->Length);
7705+
memcpy(this->texture_create_insn_bytes2.data(), (void*)(*second_call + 7), decoded->Length);
7706+
7707+
SPDLOG_INFO("Found second call at {:x}", *second_call);
7708+
auto post_second_call = *second_call + 7 + decoded->Length;
7709+
//auto texture_hook_result = safetyhook::MidHook::create((void*)post_second_call, &VRRenderTargetManager::texture_hook_callback);
7710+
auto texture_hook_result = safetyhook::MidHook::create((void*)post_second_call, +[](safetyhook::Context& ctx) -> void {
7711+
VRRenderTargetManager::texture_hook_callback(ctx, true);
7712+
});
7713+
7714+
if (!texture_hook_result.has_value()) {
7715+
const auto e = texture_hook_result.error();
7716+
7717+
if (e.type == safetyhook::MidHook::Error::BAD_ALLOCATION) {
7718+
SPDLOG_ERROR("Failed to create post second texture hook: BAD_ALLOCATION: {}", (uint8_t)e.allocator_error);
7719+
} else {
7720+
SPDLOG_ERROR("Failed to create post second texture hook: BAD_INLINE_HOOK: {}", (uint8_t)e.inline_hook_error.type);
7721+
}
7722+
} else {
7723+
this->texture_hook2 = std::move(texture_hook_result.value());
7724+
SPDLOG_INFO("Successfully created second texture hook!");
7725+
}
7726+
7727+
auto pre_second_call = *second_call + 7;
7728+
//auto pre_texure_hook_result = safetyhook::MidHook::create((void*)pre_second_call, &VRRenderTargetManager::pre_texture_hook_callback);
7729+
auto pre_texure_hook_result = safetyhook::MidHook::create((void*)pre_second_call, +[](safetyhook::Context& ctx) -> void {
7730+
VRRenderTargetManager::pre_texture_hook_callback(ctx, true);
7731+
});
7732+
7733+
if (!pre_texure_hook_result.has_value()) {
7734+
const auto e = pre_texure_hook_result.error();
7735+
7736+
if (e.type == safetyhook::MidHook::Error::BAD_ALLOCATION) {
7737+
SPDLOG_ERROR("Failed to create pre second texture hook: BAD_ALLOCATION: {}", (uint8_t)e.allocator_error);
7738+
} else {
7739+
SPDLOG_ERROR("Failed to create pre second texture hook: BAD_INLINE_HOOK: {}", (uint8_t)e.inline_hook_error.type);
7740+
}
7741+
} else {
7742+
this->pre_texture_hook2 = std::move(pre_texure_hook_result.value());
7743+
SPDLOG_INFO("Successfully created second pre texture hook!");
7744+
}
7745+
} else {
7746+
SPDLOG_INFO("Second call not detected! Continuing...");
7747+
}
7748+
}
7749+
7750+
//auto texture_hook_result = safetyhook::MidHook::create((void*)post_call, &VRRenderTargetManager::texture_hook_callback);
7751+
auto texture_hook_result = safetyhook::MidHook::create((void*)post_call, +[](safetyhook::Context& ctx) -> void {
7752+
VRRenderTargetManager::texture_hook_callback(ctx, false);
7753+
});
76747754

76757755
if (!texture_hook_result.has_value()) {
76767756
const auto e = texture_hook_result.error();
@@ -7684,7 +7764,10 @@ bool VRRenderTargetManager_Base::allocate_render_target_texture(uintptr_t return
76847764
this->texture_hook = std::move(texture_hook_result.value());
76857765
}
76867766

7687-
auto pre_texure_hook_result = safetyhook::MidHook::create((void*)ip, &VRRenderTargetManager::pre_texture_hook_callback);
7767+
//auto pre_texure_hook_result = safetyhook::MidHook::create((void*)ip, &VRRenderTargetManager::pre_texture_hook_callback);
7768+
auto pre_texure_hook_result = safetyhook::MidHook::create((void*)ip, +[](safetyhook::Context& ctx) -> void {
7769+
VRRenderTargetManager::pre_texture_hook_callback(ctx, false);
7770+
});
76887771

76897772
if (!pre_texure_hook_result.has_value()) {
76907773
const auto e = pre_texure_hook_result.error();

src/mods/vr/FFakeStereoRenderingHook.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,15 @@ struct VRRenderTargetManager_Base {
133133

134134
VerifiedFTexture2D ui_target{};
135135
VerifiedFTexture2D render_target{};
136-
static void pre_texture_hook_callback(safetyhook::Context& ctx); // only used if pixel format cvar is missing
137-
static void texture_hook_callback(safetyhook::Context& ctx);
136+
static void pre_texture_hook_callback(safetyhook::Context& ctx, bool from_second = false); // only used if pixel format cvar is missing
137+
static void texture_hook_callback(safetyhook::Context& ctx, bool from_second = false);
138138

139139
FTexture2DRHIRef* texture_hook_ref{nullptr};
140140
FTexture2DRHIRef* shader_resource_hook_ref{nullptr};
141141
safetyhook::MidHook pre_texture_hook{}; // only used if pixel format cvar is missing
142+
safetyhook::MidHook pre_texture_hook2{}; // only used if pixel format cvar is missing
142143
safetyhook::MidHook texture_hook{};
144+
safetyhook::MidHook texture_hook2{};
143145
uint32_t last_texture_index{0};
144146
bool allocated_views{false};
145147
bool set_up_texture_hook{false};
@@ -154,6 +156,7 @@ struct VRRenderTargetManager_Base {
154156
uint32_t last_height{0};
155157

156158
std::vector<uint8_t> texture_create_insn_bytes{};
159+
std::vector<uint8_t> texture_create_insn_bytes2{};
157160

158161
std::optional<size_t> m_viewport_force_separate_rt_offset{};
159162
bool m_attempted_find_force_separate_rt{false};

0 commit comments

Comments
 (0)