Skip to content

Commit

Permalink
SDK: Add FProperty::PropertyFlags bruteforcer
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Dec 25, 2023
1 parent 13f5155 commit ac82f2a
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
69 changes: 69 additions & 0 deletions shared/sdk/FProperty.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include <spdlog/spdlog.h>

#include "UObjectArray.hpp"
#include "UFunction.hpp"

#include "UProperty.hpp"
#include "FProperty.hpp"

Expand Down Expand Up @@ -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<sdk::UClass>(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");
}
}
7 changes: 7 additions & 0 deletions shared/sdk/FProperty.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions shared/sdk/UObjectArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit ac82f2a

Please sign in to comment.