Skip to content

Commit

Permalink
SDK: Bruteforce UScriptStruct::StructOps offset
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Jul 7, 2023
1 parent 53e45fa commit b9288ee
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 2 deletions.
84 changes: 84 additions & 0 deletions shared/sdk/UClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@ UClass* UClass::static_class() {
return (UClass*)sdk::find_uobject(L"Class /Script/CoreUObject.Class");
}

void UField::update_offsets() {
if (s_attempted_update_offsets) {
return;
}

s_attempted_update_offsets = true;

SPDLOG_INFO("[UField] Bruteforcing offsets...");

UStruct::update_offsets();

// best thing i can come up with for now.
s_next_offset = UStruct::s_super_struct_offset - sizeof(void*);

SPDLOG_INFO("[UField] Found Next at offset 0x{:X}", s_next_offset);
}

void UStruct::update_offsets() {
if (s_attempted_update_offsets) {
return;
Expand Down Expand Up @@ -55,6 +72,8 @@ void UStruct::update_offsets() {
} else {
SPDLOG_ERROR("[UStruct] Failed to find classes!");
}

UField::update_offsets();
}

void UClass::update_offsets() {
Expand Down Expand Up @@ -105,4 +124,69 @@ void UClass::update_offsets() {
continue;
}
}

UClass* UScriptStruct::static_class() {
return (UClass*)sdk::find_uobject(L"Class /Script/CoreUObject.ScriptStruct");
}

void UScriptStruct::update_offsets() {
if (s_attempted_update_offsets) {
return;
}

s_attempted_update_offsets = true;

UStruct::update_offsets();

SPDLOG_INFO("[UScriptStruct] Bruteforcing offsets...");

const auto matrix_scriptstruct = sdk::find_uobject(L"ScriptStruct /Script/CoreUObject.Matrix");
const auto vector_scriptstruct = sdk::find_uobject(L"ScriptStruct /Script/CoreUObject.Vector");

if (matrix_scriptstruct == nullptr || vector_scriptstruct == nullptr) {
SPDLOG_ERROR("[UScriptStruct] Failed to find Matrix/Vector!");
return;
}

constexpr auto MAT4_SIZE_FLOAT = 4 * 4 * sizeof(float);
constexpr auto MAT4_SIZE_DOUBLE = 4 * 4 * sizeof(double);
constexpr auto VECTOR_SIZE_FLOAT = 3 * sizeof(float);
constexpr auto VECTOR_SIZE_DOUBLE = 3 * sizeof(double);

for (auto i = UStruct::s_super_struct_offset; i < 0x300; i += sizeof(void*)) try {
const auto value = *(sdk::UScriptStruct::StructOps**)((uintptr_t)matrix_scriptstruct + i);

if (value == nullptr || IsBadReadPtr(value, sizeof(void*)) || ((uintptr_t)value & 1) != 0) {
continue;
}

const auto potential_vtable = *(void**)value;

if (potential_vtable == nullptr || IsBadReadPtr(potential_vtable, sizeof(void*)) || ((uintptr_t)potential_vtable & 1) != 0) {
continue;
}

const auto potential_vfunc = *(void**)potential_vtable;

if (potential_vfunc == nullptr || IsBadReadPtr(potential_vfunc, sizeof(void*))) {
continue;
}

const auto value2 = *(sdk::UScriptStruct::StructOps**)((uintptr_t)vector_scriptstruct + i);

if (value2 == nullptr || IsBadReadPtr(value2, sizeof(void*)) || ((uintptr_t)value2 & 1) != 0) {
continue;
}

if ((value->size == MAT4_SIZE_FLOAT && value2->size == VECTOR_SIZE_FLOAT) ||
(value->size == MAT4_SIZE_DOUBLE && value2->size == VECTOR_SIZE_DOUBLE))
{
SPDLOG_INFO("[UScriptStruct] Found StructOps at offset 0x{:X}", i);
s_struct_ops_offset = i;
break;
}
} catch(...) {
continue;
}
}
}
51 changes: 49 additions & 2 deletions shared/sdk/UClass.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ class UClass;
class UField : public UObject {
public:
static UClass* static_class();
static void update_offsets();

protected:
static inline bool s_attempted_update_offsets{false};
static inline uint32_t s_next_offset{0x30}; // not correct always, we bruteforce it later
};

class UStruct : public UField {
Expand All @@ -19,9 +24,21 @@ class UStruct : public UField {
return *(UStruct**)((uintptr_t)this + s_super_struct_offset);
}

private:
bool is_a(UStruct* other) const {
for (auto super = this; super != nullptr; super = super->get_super_struct()) {
if (super == other) {
return true;
}
}

return false;
}

protected:
static inline bool s_attempted_update_offsets{false};
static inline uint32_t s_super_struct_offset{0x40}; // not correct always, we bruteforce it later

friend class UField;
};

class UClass : public UStruct {
Expand All @@ -33,8 +50,38 @@ class UClass : public UStruct {
return *(UObject**)((uintptr_t)this + s_default_object_offset);
}

private:
protected:
static inline bool s_attempted_update_offsets{false};
static inline uint32_t s_default_object_offset{0x118}; // not correct always, we bruteforce it later
};

class UScriptStruct : public UStruct {
public:
struct StructOps {
virtual ~StructOps() {};

int32_t size;
int32_t alignment;
};

static UClass* static_class();
static void update_offsets();

StructOps* get_struct_ops() const {
return *(StructOps**)((uintptr_t)this + s_struct_ops_offset);
}

int32_t get_struct_size() const {
const auto ops = get_struct_ops();
if (ops == nullptr) {
return 0;
}

return ops->size;
}

protected:
static inline bool s_attempted_update_offsets{false};
static inline uint32_t s_struct_ops_offset{0xB8}; // not correct always, we bruteforce it later
};
}
5 changes: 5 additions & 0 deletions shared/sdk/UObject.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
#include "UObjectArray.hpp"

#include "UClass.hpp"
#include "UObject.hpp"

namespace sdk {
UClass* UObject::static_class() {
return (UClass*)sdk::find_uobject(L"Class /Script/CoreUObject.Object");
}

bool UObject::is_a(UClass* other) const {
return get_class()->is_a((UStruct*)other);
}
}
7 changes: 7 additions & 0 deletions shared/sdk/UObject.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,12 @@ class UClass;
class UObject : public UObjectBase {
public:
static UClass* static_class();

template <typename T>
bool is_a() const {
return is_a(T::static_class());
}

bool is_a(UClass* cmp) const;
};
}
1 change: 1 addition & 0 deletions shared/sdk/UObjectArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ FUObjectArray* FUObjectArray::get() {
// Attempt to find the SuperStruct offset
sdk::UStruct::update_offsets();
sdk::UClass::update_offsets();
sdk::UScriptStruct::update_offsets();

for (auto i = 0; i < result->get_object_count(); ++i) {
auto item = result->get_object(i);
Expand Down

0 comments on commit b9288ee

Please sign in to comment.