@@ -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 ();
0 commit comments