From d00473fca676a77b92f2d03170326d57908f2fe6 Mon Sep 17 00:00:00 2001 From: praydog Date: Tue, 22 Aug 2023 01:09:20 -0700 Subject: [PATCH] GUObjectArray try catch blocks to prevent premature crashes --- shared/sdk/FName.cpp | 66 ++++++++++++----------- shared/sdk/UObjectArray.cpp | 102 +++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 33 deletions(-) diff --git a/shared/sdk/FName.cpp b/shared/sdk/FName.cpp index a95a95fa..bbcd2069 100644 --- a/shared/sdk/FName.cpp +++ b/shared/sdk/FName.cpp @@ -349,47 +349,51 @@ std::optional standard_find_to_string() { ctx.ctx->Registers.RegRip = (uintptr_t)*result; ctx.ctx->Registers.RegRcx = 0x12345678; // magic number - utility::emulate(module, (uintptr_t)*result, 100, ctx, [&](const utility::ShemuContextExtended& ctx) -> utility::ExhaustionResult { - if (ctx.next.writes_to_memory || std::string_view{ctx.next.ix.Mnemonic}.starts_with("CALL")) { - return utility::ExhaustionResult::STEP_OVER; - } - - const auto& nix = ctx.next.ix; + try { + utility::emulate(module, (uintptr_t)*result, 100, ctx, [&](const utility::ShemuContextExtended& ctx) -> utility::ExhaustionResult { + if (ctx.next.writes_to_memory || std::string_view{ctx.next.ix.Mnemonic}.starts_with("CALL")) { + return utility::ExhaustionResult::STEP_OVER; + } + + const auto& nix = ctx.next.ix; - if (nix.OperandsCount < 2) { - return utility::ExhaustionResult::CONTINUE; - } + if (nix.OperandsCount < 2) { + return utility::ExhaustionResult::CONTINUE; + } - if (nix.Operands[1].Type == ND_OP_MEM && nix.Operands[1].Info.Memory.HasBase && - nix.Operands[1].Info.Memory.HasDisp && nix.Operands[1].Info.Memory.Disp >= 8) - { - const auto reg_value = ((ND_UINT64*)&ctx.ctx->ctx->Registers)[nix.Operands[1].Info.Memory.Base]; + if (nix.Operands[1].Type == ND_OP_MEM && nix.Operands[1].Info.Memory.HasBase && + nix.Operands[1].Info.Memory.HasDisp && nix.Operands[1].Info.Memory.Disp >= 8) + { + const auto reg_value = ((ND_UINT64*)&ctx.ctx->ctx->Registers)[nix.Operands[1].Info.Memory.Base]; - if (reg_value == 0x12345678) { - char text[ND_MIN_BUF_SIZE]; - NdToText(&nix, 0, sizeof(text), text); - SPDLOG_INFO("{}", text); - SPDLOG_INFO("FName::get_to_string: Found function is not inlined (UClass::GetName)"); + if (reg_value == 0x12345678) { + char text[ND_MIN_BUF_SIZE]; + NdToText(&nix, 0, sizeof(text), text); + SPDLOG_INFO("{}", text); + SPDLOG_INFO("FName::get_to_string: Found function is not inlined (UClass::GetName)"); - const auto next_call = utility::scan_mnemonic(ctx.ctx->ctx->Registers.RegRip, 20, "CALL"); + const auto next_call = utility::scan_mnemonic(ctx.ctx->ctx->Registers.RegRip, 20, "CALL"); - if (next_call) { - const auto resolved_call = utility::resolve_displacement(*next_call); + if (next_call) { + const auto resolved_call = utility::resolve_displacement(*next_call); - if (resolved_call) { - *result = (FName::ToStringFn)utility::calculate_absolute(*next_call + 1); - SPDLOG_INFO("FName::get_to_string: Found function to use instead {:x}", (uintptr_t)*result); - } else { - SPDLOG_ERROR("FName::get_to_string: Failed to resolve displacement for next call"); + if (resolved_call) { + *result = (FName::ToStringFn)utility::calculate_absolute(*next_call + 1); + SPDLOG_INFO("FName::get_to_string: Found function to use instead {:x}", (uintptr_t)*result); + } else { + SPDLOG_ERROR("FName::get_to_string: Failed to resolve displacement for next call"); + } } - } - return utility::ExhaustionResult::BREAK; + return utility::ExhaustionResult::BREAK; + } } - } - return utility::ExhaustionResult::CONTINUE; - }); + return utility::ExhaustionResult::CONTINUE; + }); + } catch(...) { + SPDLOG_ERROR("FName::get_to_string: Failed to emulate"); + } SPDLOG_INFO("FName::get_to_string: result={:x}", (uintptr_t)*result); diff --git a/shared/sdk/UObjectArray.cpp b/shared/sdk/UObjectArray.cpp index 97894d3d..1c555354 100644 --- a/shared/sdk/UObjectArray.cpp +++ b/shared/sdk/UObjectArray.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -6,11 +7,15 @@ #include #include "EngineModule.hpp" +#include "UEngine.hpp" +#include "UGameplayStatics.hpp" +#include "APlayerController.hpp" #include "UObject.hpp" #include "UClass.hpp" #include "UProperty.hpp" #include "FName.hpp" +#include "FField.hpp" #include "UObjectArray.hpp" namespace sdk { @@ -55,7 +60,7 @@ UObjectBase* find_uobject(const std::wstring& full_name, bool cached) { return nullptr; } -FUObjectArray* FUObjectArray::get() { +FUObjectArray* FUObjectArray::get() try { static auto result = []() -> FUObjectArray* { SPDLOG_INFO("[FUObjectArray::get] Searching for FUObjectArray..."); @@ -356,7 +361,90 @@ FUObjectArray* FUObjectArray::get() { sdk::UScriptStruct::update_offsets(); sdk::UProperty::update_offsets(); - for (auto i = 0; i < result->get_object_count(); ++i) { + try { + const auto world = sdk::UEngine::get()->get_world(); + + SPDLOG_INFO("[FUObjectArray::get] World: 0x{:x}", (uintptr_t)world); + + // Testing caching + const auto world2 = sdk::UEngine::get()->get_world(); + + SPDLOG_INFO("[FUObjectArray::get] World2: 0x{:x}", (uintptr_t)world2); + + const auto world_name = world->get_full_name(); + SPDLOG_INFO("[FUObjectArray::get] World name: {}", utility::narrow(world_name)); + + const auto player_controller = sdk::UGameplayStatics::get()->get_player_controller(world, 0); + SPDLOG_INFO("[FUObjectArray::get] PlayerController: 0x{:x}", (uintptr_t)player_controller); + + const auto pawn = sdk::UEngine::get()->get_localpawn(0); + SPDLOG_INFO("[FUObjectArray::get] Pawn: 0x{:x}", (uintptr_t)pawn); + + if (player_controller != nullptr) { + SPDLOG_INFO("[FUObjectArray::get] Pawn2: 0x{:x}", (uintptr_t)player_controller->get_acknowledged_pawn()); + } + } catch(...) { + SPDLOG_ERROR("[FUObjectArray::get] Unknown exception occurred while performing tests on GUObjectArray"); + } + + std::unordered_set possible_field_types{}; + + const auto class_t = sdk::UClass::static_class(); + + for (auto i = 0; i < result->get_object_count(); ++i) try { + const auto item = result->get_object(i); + if (item == nullptr) { + continue; + } + + const auto obj = (sdk::UObject*)item->object; + + if (obj == nullptr) { + continue; + } + + if (!obj->is_a(class_t)) { + continue; + } + + const auto c = (sdk::UClass*)obj; + + for (auto f = c->get_child_properties(); f != nullptr; f = f->get_next()) { + // TODO: the other one + if (FField::is_ufield_only()) { + const auto ufield = (sdk::UField*)f; + const auto f_class = ufield->get_class(); + + if (f_class == nullptr) { + continue; + } + + const auto f_class_name = f_class->get_full_name(); + + if (!possible_field_types.contains(f_class_name)) { + SPDLOG_INFO("[FUObjectArray::get] Possible field type: {}", utility::narrow(f_class_name)); + possible_field_types.insert(f_class_name); + } + } else { + const auto f_class = f->get_class(); + + if (f_class == nullptr) { + continue; + } + + const auto f_class_name = f_class->get_name().to_string(); + + if (!possible_field_types.contains(f_class_name)) { + SPDLOG_INFO("[FUObjectArray::get] Possible field type: {}", utility::narrow(f_class_name)); + possible_field_types.insert(f_class_name); + } + } + } + } catch(...) { + continue; + } + + for (auto i = 0; i < result->get_object_count(); ++i) try { auto item = result->get_object(i); if (item == nullptr) { continue; @@ -375,9 +463,19 @@ FUObjectArray* FUObjectArray::get() { } catch(...) { SPDLOG_ERROR("Failed to get name {}", i); } + } catch(...) { + SPDLOG_ERROR("[FUObjectArray::get] Exception: failed to get object {}", i); } }; return result; +} catch(...) { + static bool once = true; + if (once) { + SPDLOG_ERROR("[FUObjectArray::get] Failed to get GUObjectArray, prevented a crash"); + once = false; + } + + return nullptr; } } \ No newline at end of file