Skip to content

Commit

Permalink
Add support for IConsoleCommand differentiation
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed May 31, 2023
1 parent 4283a3c commit 70eeb57
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 10 deletions.
12 changes: 8 additions & 4 deletions shared/sdk/CVar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ float IConsoleVariable::GetFloat() {
return func(this);
}

std::optional<IConsoleVariable::VtableInfo> IConsoleVariable::locate_vtable_indices() {
std::optional<IConsoleObject::VtableInfo> IConsoleObject::locate_vtable_indices() {
std::scoped_lock _{ s_vtable_mutex };

const auto vtable = *(uintptr_t**)this;
Expand All @@ -708,16 +708,16 @@ std::optional<IConsoleVariable::VtableInfo> IConsoleVariable::locate_vtable_indi
// in most cases the +2 function will be the Set function (the +1 function is Release)
// from there, GetInt, GetFloat, etc will be the next subsequent functions
// THIS MUST BE CALLED FROM AN ACTUAL IConsoleVariable INSTANCE, NOT A CONSOLE COMMAND!!!
SPDLOG_INFO("Locating IConsoleVariable vtable indices...");
SPDLOG_INFO("Locating IConsoleObject vtable indices...");
std::optional<uint32_t> previous_nullptr_index{};

SPDLOG_INFO("Vtable: {:x} (cvar {:x})", (uintptr_t)vtable, (uintptr_t)this);
SPDLOG_INFO("Vtable: {:x} (console obj {:x})", (uintptr_t)vtable, (uintptr_t)this);

for (auto i = 0; i < 20; ++i) {
const auto func = vtable[i];

if (func == 0 || IsBadReadPtr((void*)func, 1)) {
SPDLOG_ERROR("Reached end of IConsoleVariable vtable at index {}", i);
SPDLOG_ERROR("Reached end of IConsoleObject vtable at index {}", i);
break;
}

Expand Down Expand Up @@ -815,6 +815,8 @@ std::optional<IConsoleVariable::VtableInfo> IConsoleVariable::locate_vtable_indi

auto& vtable_info = s_vtable_infos[vtable];

vtable_info.as_console_command_index = destructor_index - 1;
vtable_info.release_index = destructor_index;
vtable_info.set_vtable_index = destructor_index + 1;
auto potential_get_int_index = vtable_info.set_vtable_index + 1;

Expand Down Expand Up @@ -868,6 +870,8 @@ std::optional<IConsoleVariable::VtableInfo> IConsoleVariable::locate_vtable_indi
vtable_info.get_int_vtable_index = potential_get_int_index;
vtable_info.get_float_vtable_index = vtable_info.get_int_vtable_index + 1;
SPDLOG_INFO("Encountered final nullptr at index {}", *previous_nullptr_index);
SPDLOG_INFO("IConsoleObject::AsConsoleCommand vtable index: {}", vtable_info.as_console_command_index);
SPDLOG_INFO("IConsoleObject::Release vtable index: {}", vtable_info.release_index);
SPDLOG_INFO("IConsoleVariable::Set vtable index: {}", vtable_info.set_vtable_index);
SPDLOG_INFO("IConsoleVariable::GetInt vtable index: {}", vtable_info.get_int_vtable_index);
SPDLOG_INFO("IConsoleVariable::GetFloat vtable index: {}", vtable_info.get_float_vtable_index);
Expand Down
36 changes: 30 additions & 6 deletions shared/sdk/CVar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,34 @@ struct TConsoleVariableData {
T values[2];
};

struct IConsoleCommand;

// Dummy interface for IConsoleObject
// The functions will actually dynamically scan the vtable for the right index
struct IConsoleObject {
virtual ~IConsoleObject() {}
virtual wchar_t* GetHelp() const = 0;
};
virtual uint32_t GetFlags() const = 0;
virtual void SetFlags(uint32_t flags) = 0;

struct IConsoleVariable : IConsoleObject {
void Set(const wchar_t* in, uint32_t set_by_flags = 0x8000000);
int32_t GetInt();
float GetFloat();
// Everything past this point needs to be dynamically scanned
IConsoleCommand* AsCommand() {
const auto vtable_info = this->locate_vtable_indices();

private:
if (!vtable_info.has_value() || vtable_info->as_console_command_index == 0) {
return nullptr;
}

const auto vtable = *(void***)this;
const auto func = ((IConsoleCommand*(__thiscall*)(void*))vtable[vtable_info->as_console_command_index]);

return func(this);
}

protected:
struct VtableInfo {
uint32_t as_console_command_index;
uint32_t release_index;
uint32_t set_vtable_index;
uint32_t get_int_vtable_index;
uint32_t get_float_vtable_index;
Expand All @@ -76,6 +90,16 @@ struct IConsoleVariable : IConsoleObject {
static inline std::unordered_map<void*, VtableInfo> s_vtable_infos{};
};

struct IConsoleCommand : IConsoleObject {
// TODO: Implement
};

struct IConsoleVariable : IConsoleObject {
void Set(const wchar_t* in, uint32_t set_by_flags = 0x8000000);
int32_t GetInt();
float GetFloat();
};

struct FConsoleVariableBase : public IConsoleVariable {
struct {
wchar_t* data;
Expand Down
5 changes: 5 additions & 0 deletions shared/sdk/ConsoleManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ FConsoleManager* FConsoleManager::get() {
static auto result = []() -> FConsoleManager** {
SPDLOG_INFO("Finding IConsoleManager...");

const auto now = std::chrono::steady_clock::now();

const auto core_module = sdk::get_ue_module(L"Core");
const auto r_dumping_movie_string = utility::scan_string(core_module, L"r.DumpingMovie");

Expand Down Expand Up @@ -67,6 +69,9 @@ FConsoleManager* FConsoleManager::get() {
SPDLOG_INFO("Found IConsoleManager**: {:x}", (uintptr_t)std::get<0>(*highest_global_variable_reference));
SPDLOG_INFO("Points to IConsoleManager*: {:x}", *(uintptr_t*)std::get<0>(*highest_global_variable_reference));

const auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - now).count();
SPDLOG_INFO("Took {}ms to find IConsoleManager", diff);

return (FConsoleManager**)std::get<0>(*highest_global_variable_reference);
}();

Expand Down

0 comments on commit 70eeb57

Please sign in to comment.