From ac82f2a9e829e4efa07b0f512506d5d2ec44ac94 Mon Sep 17 00:00:00 2001 From: praydog Date: Mon, 25 Dec 2023 08:21:37 -0800 Subject: [PATCH] SDK: Add FProperty::PropertyFlags bruteforcer --- shared/sdk/FProperty.cpp | 69 +++++++++++++++++++++++++++++++++++++ shared/sdk/FProperty.hpp | 7 ++++ shared/sdk/UObjectArray.cpp | 1 + 3 files changed, 77 insertions(+) diff --git a/shared/sdk/FProperty.cpp b/shared/sdk/FProperty.cpp index 27e4c9e0..83a2e7fa 100644 --- a/shared/sdk/FProperty.cpp +++ b/shared/sdk/FProperty.cpp @@ -1,5 +1,8 @@ #include +#include "UObjectArray.hpp" +#include "UFunction.hpp" + #include "UProperty.hpp" #include "FProperty.hpp" @@ -42,4 +45,70 @@ void FProperty::bruteforce_fproperty_offset(FProperty* x_prop, FProperty* y_prop SPDLOG_ERROR("[FProperty] Failed to bruteforce offset field"); } } + +void FProperty::update_offsets() try { + if (s_attempted_update_offsets) { + return; + } + + s_attempted_update_offsets = true; + SPDLOG_INFO("[FProperty] Updating offsets..."); + + // Get ActorComponent class + const auto actor_component_class = sdk::find_uobject(L"Class /Script/Engine.ActorComponent"); + + if (actor_component_class == nullptr) { + SPDLOG_ERROR("[FProperty] Failed to find ActorComponent class"); + return; + } + + // Find IsActive function + const auto is_active_function = actor_component_class->find_function(L"IsActive"); + + if (is_active_function == nullptr) { + SPDLOG_ERROR("[FProperty] Failed to find IsActive function"); + return; + } + + // Get first parameter + const auto first_param = is_active_function->get_child_properties(); + + if (first_param == nullptr) { + SPDLOG_ERROR("[FProperty] Failed to find first parameter"); + return; + } + + const auto start_raw = std::max(FField::s_next_offset, FField::s_name_offset) + sizeof(void*); + + // Alignup to sizeof(void*) + const auto start = (start_raw + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + constexpr auto cpf_param = 0x80; + constexpr auto cpf_out_param = 0x100; + constexpr auto cpf_return_param = 0x400; + constexpr auto cpf_is_pod = 0x40000000; // CPF_IsPlainOldData + + // 4 flags that will definitely always be set + const auto wanted_flags = cpf_param | cpf_out_param | cpf_return_param | cpf_is_pod; + + for (auto i = start; i < 0x200; i += sizeof(void*)) try { + const auto value = *(uint64_t*)((uintptr_t)first_param + i); + if ((value & wanted_flags) == wanted_flags) { + SPDLOG_INFO("[FProperty] Found PropertyFlags offset at 0x{:X} (full value {:x})", i, value); + s_property_flags_offset = i; + break; + } + } catch (...) { + continue; + } + + if (s_property_flags_offset == 0) { + SPDLOG_ERROR("[FProperty] Failed to find PropertyFlags offset"); + return; + } + + SPDLOG_INFO("[FProperty] done"); +} catch(...) { + SPDLOG_ERROR("[FProperty] Failed to update offsets"); +} } \ No newline at end of file diff --git a/shared/sdk/FProperty.hpp b/shared/sdk/FProperty.hpp index d4673536..88b8c68d 100644 --- a/shared/sdk/FProperty.hpp +++ b/shared/sdk/FProperty.hpp @@ -25,11 +25,18 @@ class FProperty : public FField { return (T*)((uintptr_t)object + get_offset()); } + uint64_t get_property_flags() const { + return *(uint64_t*)((uintptr_t)this + s_property_flags_offset); + } + // Given xyz props from FVector, find the offset which matches up with all of them static void bruteforce_fproperty_offset(FProperty* x_prop, FProperty* y_prop, FProperty* z_prop); + static void update_offsets(); // for other offsets like PropertyFlags protected: + static inline bool s_attempted_update_offsets{false}; static inline uint32_t s_offset_offset{0x0}; // idk + static inline uint32_t s_property_flags_offset{0x0}; // idk friend class UStruct; friend class UProperty; diff --git a/shared/sdk/UObjectArray.cpp b/shared/sdk/UObjectArray.cpp index 798904e3..c617aea2 100644 --- a/shared/sdk/UObjectArray.cpp +++ b/shared/sdk/UObjectArray.cpp @@ -419,6 +419,7 @@ FUObjectArray* FUObjectArray::get() try { sdk::FObjectProperty::update_offsets(); sdk::FArrayProperty::update_offsets(); sdk::FEnumProperty::update_offsets(); + sdk::FProperty::update_offsets(); //sdk::UObjectHashTables::get(); #ifdef TESTING_GUOBJECTARRAY