From 90caea00e4544d21bc540407001856275122050a Mon Sep 17 00:00:00 2001 From: praydog Date: Sat, 8 Jul 2023 23:39:34 -0700 Subject: [PATCH] SDK: Bruteforce UFunction::Func offset --- shared/sdk/UClass.cpp | 47 +++++++++++++++++++++++++++++++++++++++- shared/sdk/UFunction.hpp | 10 ++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/shared/sdk/UClass.cpp b/shared/sdk/UClass.cpp index 8e98f5b1..ea860483 100644 --- a/shared/sdk/UClass.cpp +++ b/shared/sdk/UClass.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "UObjectArray.hpp" #include "UFunction.hpp" @@ -256,7 +257,7 @@ void UStruct::resolve_field_offsets(uint32_t child_search_start) { } } -void UStruct::resolve_function_offsets(uint32_t child_search_start) { +void UStruct::resolve_function_offsets(uint32_t child_search_start) try { // This object has a bunch of functions so we can use it to find the function offsets // and the UField Next offset for the games that have FField const auto gameplay_statics = (sdk::UClass*)sdk::find_uobject(L"Class /Script/Engine.GameplayStatics"); @@ -344,6 +345,50 @@ void UStruct::resolve_function_offsets(uint32_t child_search_start) { continue; } } + + std::unordered_map offsets_with_ptr_within_module{}; + + for (auto next = gameplay_statics->get_children(); next != nullptr; next = next->get_next()) try { + if (!next->is_a()) { + continue; + } + + for (auto i = UStruct::s_child_properties_offset + sizeof(void*); i < 0x200; i += sizeof(void*)) try { + const auto possible_native_fn = *(void**)((uintptr_t)next + i); + + if (possible_native_fn == nullptr || IsBadReadPtr(possible_native_fn, sizeof(void*))) { + continue; + } + + if (utility::get_module_within(possible_native_fn)) { + offsets_with_ptr_within_module[i]++; + } + } catch(...) { + continue; + } + } catch(...) { + continue; + } + + // Check which offset has the most pointers to a module + uint32_t most_ptrs = 0; + uint32_t most_ptrs_offset = 0; + + for (const auto& [offset, ptr_count] : offsets_with_ptr_within_module) { + if (ptr_count > most_ptrs) { + most_ptrs = ptr_count; + most_ptrs_offset = offset; + } + } + + if (most_ptrs > 0) { + UFunction::s_native_function_offset = most_ptrs_offset; + SPDLOG_INFO("[UStruct] Found native function offset at 0x{:X}", most_ptrs_offset); + } else { + SPDLOG_ERROR("[UStruct] Failed to find native function offset!"); + } +} catch(...) { + SPDLOG_ERROR("[UStruct::resolve_function_offsets] Failed to resolve function offsets! (unknown exception)"); } void UStruct::update_offsets() { diff --git a/shared/sdk/UFunction.hpp b/shared/sdk/UFunction.hpp index 46275b34..c4bc2024 100644 --- a/shared/sdk/UFunction.hpp +++ b/shared/sdk/UFunction.hpp @@ -3,10 +3,18 @@ #include "UClass.hpp" namespace sdk { -class UFunction : public UField { +class UFunction : public UStruct { public: static UClass* static_class(); + using NativeFunction = void(*)(sdk::UObject*, void*, void*); + NativeFunction get_native_function() const { + return *(NativeFunction*)((uintptr_t)this + s_native_function_offset); + } + private: + static inline uint32_t s_native_function_offset{0x0}; + + friend class UStruct; }; } \ No newline at end of file