developer console
+ added in-game developer console + added dvar definitions and helping class + list of known game dvars can be found inside variables.cpp + adjusted logger component + re-enabled com_frame hook + some minor code formatting
This commit is contained in:
parent
8b85399de5
commit
2358dcf30b
@ -5,7 +5,7 @@
|
||||
#include <utils/string.hpp>
|
||||
|
||||
|
||||
namespace integrity
|
||||
namespace arxan
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@ -107,7 +107,7 @@ namespace integrity
|
||||
if (current_checksum != correct_checksum)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
/*printf("Adjusting checksum (%llX): %X -> %X\n", handler_address,
|
||||
/*logger::write(logger::LOG_TYPE_DEBUG, "Adjusting checksum (%llX): %X -> %X\n", handler_address,
|
||||
current_checksum, correct_checksum);*/
|
||||
#endif
|
||||
}
|
||||
@ -303,6 +303,158 @@ namespace integrity
|
||||
|
||||
return get_thread_context_hook.invoke<BOOL>(thread_handle, context);
|
||||
}
|
||||
|
||||
utils::hook::detour create_mutex_ex_a_hook;
|
||||
HANDLE create_mutex_ex_a_stub(const LPSECURITY_ATTRIBUTES attributes, const LPCSTR name, const DWORD flags,
|
||||
const DWORD access)
|
||||
{
|
||||
if (name == "$ IDA trusted_idbs"s || name == "$ IDA registry mutex $"s)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return create_mutex_ex_a_hook.invoke<HANDLE>(attributes, name, flags, access);
|
||||
}
|
||||
|
||||
bool remove_evil_keywords_from_string(const UNICODE_STRING& string)
|
||||
{
|
||||
static const std::wstring evil_keywords[] =
|
||||
{
|
||||
L"IDA",
|
||||
L"ida",
|
||||
L"HxD",
|
||||
L"cheatengine",
|
||||
L"Cheat Engine",
|
||||
L"x96dbg",
|
||||
L"x32dbg",
|
||||
L"x64dbg",
|
||||
L"Wireshark",
|
||||
};
|
||||
|
||||
if (!string.Buffer || !string.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::wstring_view path(string.Buffer, string.Length / sizeof(string.Buffer[0]));
|
||||
|
||||
bool modified = false;
|
||||
for (const auto& keyword : evil_keywords)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const auto pos = path.find(keyword);
|
||||
if (pos == std::wstring::npos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
modified = true;
|
||||
|
||||
for (size_t i = 0; i < keyword.size(); ++i)
|
||||
{
|
||||
string.Buffer[pos + i] = L'a';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool remove_evil_keywords_from_string(wchar_t* str, const size_t length)
|
||||
{
|
||||
UNICODE_STRING unicode_string{};
|
||||
unicode_string.Buffer = str;
|
||||
unicode_string.Length = static_cast<uint16_t>(length);
|
||||
unicode_string.MaximumLength = unicode_string.Length;
|
||||
|
||||
return remove_evil_keywords_from_string(unicode_string);
|
||||
}
|
||||
|
||||
bool remove_evil_keywords_from_string(char* str, const size_t length)
|
||||
{
|
||||
std::string_view str_view(str, length);
|
||||
std::wstring wstr(str_view.begin(), str_view.end());
|
||||
|
||||
if (!remove_evil_keywords_from_string(wstr.data(), wstr.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string regular_str(wstr.begin(), wstr.end());
|
||||
memcpy(str, regular_str.data(), length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int WINAPI get_window_text_a_stub(const HWND wnd, const LPSTR str, const int max_count)
|
||||
{
|
||||
std::wstring wstr{};
|
||||
wstr.resize(max_count);
|
||||
|
||||
const auto res = GetWindowTextW(wnd, wstr.data(), max_count);
|
||||
if (res)
|
||||
{
|
||||
remove_evil_keywords_from_string(wstr.data(), res);
|
||||
|
||||
const std::string regular_str(wstr.begin(), wstr.end());
|
||||
memset(str, 0, max_count);
|
||||
memcpy(str, regular_str.data(), res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
utils::hook::detour nt_query_system_information_hook;
|
||||
NTSTATUS NTAPI nt_query_system_information_stub(const SYSTEM_INFORMATION_CLASS system_information_class,
|
||||
const PVOID system_information,
|
||||
const ULONG system_information_length,
|
||||
const PULONG return_length)
|
||||
{
|
||||
const auto status = nt_query_system_information_hook.invoke<NTSTATUS>(
|
||||
system_information_class, system_information, system_information_length, return_length);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if (system_information_class == SystemProcessInformation && !utils::nt::is_shutdown_in_progress())
|
||||
{
|
||||
auto addr = static_cast<uint8_t*>(system_information);
|
||||
while (true)
|
||||
{
|
||||
const auto info = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(addr);
|
||||
remove_evil_keywords_from_string(info->ImageName);
|
||||
|
||||
if (!info->NextEntryOffset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
addr = addr + info->NextEntryOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
utils::hook::detour nt_query_information_process_hook;
|
||||
NTSTATUS WINAPI nt_query_information_process_stub(const HANDLE handle, const PROCESSINFOCLASS info_class,
|
||||
const PVOID info,
|
||||
const ULONG info_length, const PULONG ret_length)
|
||||
{
|
||||
NTSTATUS status = nt_query_information_process_hook.invoke<NTSTATUS>(handle, info_class, info, info_length,
|
||||
ret_length);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if (info_class == ProcessImageFileName || static_cast<int>(info_class) == 43 /*ProcessImageFileNameWin32*/)
|
||||
{
|
||||
remove_evil_keywords_from_string(*static_cast<UNICODE_STRING*>(info));
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
@ -316,6 +468,22 @@ namespace integrity
|
||||
auto* get_thread_context_func = utils::nt::library("kernelbase.dll").get_proc<void*>("GetThreadContext");
|
||||
get_thread_context_hook.create(get_thread_context_func, get_thread_context_stub);
|
||||
|
||||
create_mutex_ex_a_hook.create(CreateMutexExA, create_mutex_ex_a_stub);
|
||||
|
||||
utils::hook::copy(this->window_text_buffer_, GetWindowTextA, sizeof(this->window_text_buffer_));
|
||||
utils::hook::jump(GetWindowTextA, get_window_text_a_stub, true, true);
|
||||
utils::hook::move_hook(GetWindowTextA);
|
||||
|
||||
const utils::nt::library ntdll("ntdll.dll");
|
||||
|
||||
const auto nt_query_information_process = ntdll.get_proc<void*>("NtQueryInformationProcess");
|
||||
nt_query_information_process_hook.create(nt_query_information_process,
|
||||
nt_query_information_process_stub);
|
||||
|
||||
const auto nt_query_system_information = ntdll.get_proc<void*>("NtQuerySystemInformation");
|
||||
nt_query_system_information_hook.create(nt_query_system_information, nt_query_system_information_stub);
|
||||
nt_query_system_information_hook.move();
|
||||
|
||||
|
||||
/*************************************************************************************************************
|
||||
** TODO : There is some kind of dormant defence mechanism. works so random makes it harder to investigate
|
||||
@ -335,7 +503,10 @@ namespace integrity
|
||||
{
|
||||
return 9999;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t window_text_buffer_[15]{};
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(integrity::component)
|
||||
REGISTER_COMPONENT(arxan::component)
|
@ -1,6 +1,6 @@
|
||||
#include <std_include.hpp>
|
||||
#include "definitions/game.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "definitions/t8_engine.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
|
@ -1,137 +1,59 @@
|
||||
#include <std_include.hpp>
|
||||
#include "definitions/game.hpp"
|
||||
#include "component/scheduler.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "definitions/t8_engine.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace debugging
|
||||
{
|
||||
typedef short(__fastcall* UI_Model_GetModelForController_t)(int controllerIndex);
|
||||
UI_Model_GetModelForController_t UI_Model_GetModelForController = (UI_Model_GetModelForController_t)0x143AD0200_g;
|
||||
|
||||
typedef short(__fastcall* UI_Model_CreateModelFromPath_t)(short parentNodeIndex, const char* path);
|
||||
UI_Model_CreateModelFromPath_t UI_Model_CreateModelFromPath = (UI_Model_CreateModelFromPath_t)0x143ACFC10_g;
|
||||
|
||||
typedef bool(__fastcall* UI_Model_SetString_t)(short nodeIndex, const char* newValue);
|
||||
UI_Model_SetString_t UI_Model_SetString = (UI_Model_SetString_t)0x143AD18C0_g;
|
||||
|
||||
typedef bool(__fastcall* UI_Model_SetInt_t)(short nodeIndex, int newValue);
|
||||
UI_Model_SetInt_t UI_Model_SetInt = (UI_Model_SetInt_t)0x143AD1820_g;
|
||||
|
||||
typedef bool(__fastcall* UI_Model_SetBool_t)(short nodeIndex, bool newValue);
|
||||
UI_Model_SetBool_t UI_Model_SetBool = (UI_Model_SetBool_t)0x143AD1780_g;
|
||||
|
||||
typedef bool(__fastcall* UI_Model_SetReal_t)(short nodeIndex, float newValue);
|
||||
UI_Model_SetReal_t UI_Model_SetReal = (UI_Model_SetReal_t)0x143AD1870_g;
|
||||
|
||||
void LUI_ShowToast(const char* title, const char* desc, const char* icon)
|
||||
{
|
||||
short main_model = UI_Model_GetModelForController(0);
|
||||
short toast_model = UI_Model_CreateModelFromPath(main_model, "FrontendToast");
|
||||
|
||||
short sub_model = UI_Model_CreateModelFromPath(toast_model, "state");
|
||||
UI_Model_SetString(sub_model, "DefaultState");
|
||||
|
||||
sub_model = UI_Model_CreateModelFromPath(toast_model, "kicker");
|
||||
UI_Model_SetString(sub_model, title);
|
||||
|
||||
sub_model = UI_Model_CreateModelFromPath(toast_model, "description");
|
||||
UI_Model_SetString(sub_model, desc);
|
||||
|
||||
sub_model = UI_Model_CreateModelFromPath(toast_model, "contentIcon");
|
||||
UI_Model_SetString(sub_model, icon);
|
||||
|
||||
sub_model = UI_Model_CreateModelFromPath(toast_model, "functionIcon");
|
||||
UI_Model_SetString(sub_model, "blacktransparent");
|
||||
|
||||
sub_model = UI_Model_CreateModelFromPath(toast_model, "backgroundId");
|
||||
UI_Model_SetInt(sub_model, 0);
|
||||
|
||||
sub_model = UI_Model_CreateModelFromPath(toast_model, "emblemDecal");
|
||||
UI_Model_SetReal(sub_model, 0.000000);
|
||||
|
||||
sub_model = UI_Model_CreateModelFromPath(toast_model, "notify");
|
||||
UI_Model_SetBool(sub_model, true);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* s_connectivityNames[] =
|
||||
const char* get_connectivity_info_string(int infoBitmask)
|
||||
{
|
||||
"user is non-guest", // 0x1
|
||||
"connected to live", // 0x2
|
||||
"user has multiplayer privs", // 0x4
|
||||
"networking initialized", // 0x8
|
||||
"connected to demonware", // 0x10
|
||||
"lpc ready", // 0x20
|
||||
"retrieved ffotd", // 0x40
|
||||
"retrieved playlists", // 0x80
|
||||
"publisher variables inited", // 0x100
|
||||
"ffotd is valid", // 0x200
|
||||
"user has stats and loadouts", // 0x400
|
||||
"time is synced", // 0x800
|
||||
"retrieved geo location", // 0x1000
|
||||
"dedicated pings done", // 0x2000
|
||||
"dedicated ping responses ok", // 0x4000
|
||||
"literally unlisted", // 0x8000
|
||||
"unknown - lpc related", // 0x10000
|
||||
"inventory fetched", // 0x20000
|
||||
"marketing messages received", // 0x40000
|
||||
"bnet initialized", // 0x80000
|
||||
"achievements fetched" // 0x100000
|
||||
};
|
||||
char connectionInfoString[64];
|
||||
|
||||
std::string GetConnectivityInfo()
|
||||
for (int bitNumber = 0; bitNumber < 21; bitNumber++)
|
||||
{
|
||||
if ((1 << bitNumber) & infoBitmask)
|
||||
{
|
||||
connectionInfoString[bitNumber * 2] = bitNumber + 0x41;
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionInfoString[bitNumber * 2] = 0x2D;
|
||||
}
|
||||
|
||||
connectionInfoString[(bitNumber * 2) + 1] = 0x2E;
|
||||
}
|
||||
|
||||
connectionInfoString[42] = NULL;
|
||||
|
||||
return utils::string::va("%s", connectionInfoString);
|
||||
}
|
||||
|
||||
void draw_debug_info()
|
||||
{
|
||||
int infoBitmask = 0; int requiredMask = 0x1337FA;
|
||||
game::Live_GetConnectivityInformation(0, &infoBitmask);
|
||||
bool connected = (requiredMask & infoBitmask) == requiredMask;
|
||||
|
||||
std::string result{};
|
||||
//result.append(std::format("Can play online (controller: {}): {}\n", 0, connected ? "true" : "false"));
|
||||
void* font = reinterpret_cast<void*>(game::sharedUiInfo->assets.bigFont); if (!font) return;
|
||||
|
||||
for (int i = 1; i < 21; ++i)
|
||||
if (!connected)
|
||||
{
|
||||
if (i == 15) continue; // unlisted bit
|
||||
float color[4] = { 0.8f, 1.0f, 0.3, 0.8f };
|
||||
|
||||
const char* v13;
|
||||
const char* v14;
|
||||
const char* v15;
|
||||
sz = get_connectivity_info_string(infoBitmask);
|
||||
|
||||
if (((1 << i) & infoBitmask) != 0 || (requiredMask & (1 << i)) == 0)
|
||||
v13 = "^7";
|
||||
else
|
||||
v13 = "^1";
|
||||
if ((requiredMask & (1 << i)) != 0)
|
||||
v14 = "required";
|
||||
else
|
||||
v14 = "optional";
|
||||
if (((1 << i) & infoBitmask) != 0)
|
||||
v15 = "true";
|
||||
else
|
||||
v15 = "false";
|
||||
|
||||
result.append(std::format("{}{}({}) - {}\n", v13, s_connectivityNames[i], v14, v15));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void draw_debug_info()
|
||||
{
|
||||
static bool should_draw_debugging_info = false;
|
||||
if (GetAsyncKeyState(VK_INSERT) & 0x01) should_draw_debugging_info ^= 1;
|
||||
|
||||
if (!should_draw_debugging_info) return;
|
||||
|
||||
|
||||
float color[4] = { 0.666f, 0.666f, 0.666f, 1.0f };
|
||||
game::ScreenPlacement* scrPlace = game::ScrPlace_GetView(0);
|
||||
void* font = game::UI_GetFontHandle(scrPlace, 0, 1.0f); if (!font) return;
|
||||
|
||||
std::string sz = GetConnectivityInfo();
|
||||
game::R_AddCmdDrawText(sz.data(), 0x7FFFFFFF, font, 18.0f, 1.0f * (game::R_TextHeight(font) * 0.45f) + 4.0f, 0.45f, 0.45f, 0.0f, color, game::ITEM_TEXTSTYLE_BORDERED);
|
||||
float offset_x = scrPlace->realViewportSize[0] - 8.0f
|
||||
- game::UI_TextWidth(0, sz, 0x7FFFFFFF, font, 0.45f);
|
||||
float offset_y = scrPlace->realViewportSize[1] - 8.0f;
|
||||
|
||||
game::R_AddCmdDrawText(sz, 0x7FFFFFFF, font, offset_x, offset_y, 0.45f, 0.45f, 0.0f, color, game::ITEM_TEXTSTYLE_BORDERED);
|
||||
}
|
||||
}
|
||||
|
||||
void test_key_catcher()
|
||||
@ -140,20 +62,21 @@ namespace debugging
|
||||
if ((GetAsyncKeyState(VK_HOME) & 0x01)/* && (static_cast<uint32_t>(time(nullptr)) - last_press_time) > 1*/)
|
||||
{
|
||||
last_press_time = static_cast<uint32_t>(time(nullptr));
|
||||
LUI_ShowToast("Title", "Description", "uie_bookmark");
|
||||
|
||||
/* ACTION_PLACE_HOLDER */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::loop(draw_debug_info, scheduler::renderer);
|
||||
scheduler::loop(test_key_catcher, scheduler::main);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(debugging::component)
|
@ -1,6 +1 @@
|
||||
#pragma once
|
||||
|
||||
namespace debugging
|
||||
{
|
||||
void LUI_ShowToast(const char* title, const char* desc, const char* icon = "blacktransparent");
|
||||
}
|
||||
|
289
source/proxy-dll/component/dvars.cpp
Normal file
289
source/proxy-dll/component/dvars.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
#include <std_include.hpp>
|
||||
#include "dvars.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "spoofer/spoofcall.hpp"
|
||||
#include "definitions/variables.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace dvars
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void fetch_dvar_pointers()
|
||||
{
|
||||
for (auto& dvar : variables::dvars_record)
|
||||
{
|
||||
dvar.pointer = spoofcall::invoke<uintptr_t>(game::Dvar_FindVar, dvar.name.data());
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_vector_string(const int components, const game::DvarLimits& domain)
|
||||
{
|
||||
if (domain.vector.min == -FLT_MAX)
|
||||
{
|
||||
if (domain.vector.max == FLT_MAX)
|
||||
{
|
||||
return utils::string::va("Domain is any %iD vector", components);
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any %iD vector with components %g or smaller", components,
|
||||
domain.vector.max);
|
||||
}
|
||||
}
|
||||
else if (domain.vector.max == FLT_MAX)
|
||||
{
|
||||
return utils::string::va("Domain is any %iD vector with components %g or bigger", components,
|
||||
domain.vector.min);
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any %iD vector with components from %g to %g", components,
|
||||
domain.vector.min, domain.vector.max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_domain_string(const game::dvarType_t type, const game::DvarLimits& domain)
|
||||
{
|
||||
std::string str;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case game::DVAR_TYPE_BOOL:
|
||||
return "Domain is 0 or 1"s;
|
||||
|
||||
case game::DVAR_TYPE_FLOAT:
|
||||
if (domain.value.min == -FLT_MAX)
|
||||
{
|
||||
if (domain.value.max == FLT_MAX)
|
||||
{
|
||||
return "Domain is any number"s;
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any number %g or smaller", domain.value.max);
|
||||
}
|
||||
}
|
||||
else if (domain.value.max == FLT_MAX)
|
||||
{
|
||||
return utils::string::va("Domain is any number %g or bigger", domain.value.min);
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any number from %g to %g", domain.value.min, domain.value.max);
|
||||
}
|
||||
|
||||
case game::DVAR_TYPE_FLOAT_2:
|
||||
return get_vector_string(2, domain);
|
||||
|
||||
case game::DVAR_TYPE_FLOAT_3:
|
||||
case game::DVAR_TYPE_LINEAR_COLOR_RGB:
|
||||
case game::DVAR_TYPE_COLOR_XYZ:
|
||||
case game::DVAR_TYPE_COLOR_LAB:
|
||||
return get_vector_string(3, domain);
|
||||
|
||||
case game::DVAR_TYPE_FLOAT_4:
|
||||
return get_vector_string(4, domain);
|
||||
|
||||
case game::DVAR_TYPE_INT:
|
||||
if (domain.integer.min == INT_MIN)
|
||||
{
|
||||
if (domain.integer.max == INT_MAX)
|
||||
{
|
||||
return "Domain is any integer"s;
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any integer %i or smaller", domain.integer.max);
|
||||
}
|
||||
}
|
||||
else if (domain.integer.max == INT_MAX)
|
||||
{
|
||||
return utils::string::va("Domain is any integer %i or bigger", domain.integer.min);
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any integer from %i to %i", domain.integer.min, domain.integer.max);
|
||||
}
|
||||
|
||||
case game::DVAR_TYPE_ENUM:
|
||||
str = "Domain is one of the following:"s;
|
||||
|
||||
for (auto string_index = 0; string_index < domain.enumeration.stringCount; ++string_index)
|
||||
{
|
||||
str += utils::string::va("\n %2i: %s", string_index, domain.enumeration.strings[string_index]);
|
||||
}
|
||||
|
||||
return str;
|
||||
|
||||
case game::DVAR_TYPE_STRING:
|
||||
return "Domain is any text"s;
|
||||
|
||||
case game::DVAR_TYPE_COLOR:
|
||||
return "Domain is any 4-component color, in RGBA format"s;
|
||||
|
||||
case game::DVAR_TYPE_INT64:
|
||||
if (domain.integer64.min == _I64_MIN)
|
||||
{
|
||||
if (domain.integer64.max == _I64_MAX)
|
||||
{
|
||||
return "Domain is any integer"s;
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any integer %lli or smaller", domain.integer64.max);
|
||||
}
|
||||
}
|
||||
else if (domain.integer64.max == _I64_MAX)
|
||||
{
|
||||
return utils::string::va("Domain is any integer %lli or bigger", domain.integer64.min);
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any integer from %lli to %lli", domain.integer64.min, domain.integer64.max);
|
||||
}
|
||||
|
||||
case game::DVAR_TYPE_UINT64:
|
||||
if (domain.unsignedInt64.min)
|
||||
{
|
||||
if (domain.unsignedInt64.max == _UI64_MAX)
|
||||
{
|
||||
return utils::string::va("Domain is any unsigned integer %zu or bigger", domain.unsignedInt64.min);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any unsigned integer from %zu to %zu", domain.unsignedInt64.min, domain.unsignedInt64.max);
|
||||
}
|
||||
}
|
||||
else if (domain.unsignedInt64.max == _UI64_MAX)
|
||||
{
|
||||
return "Domain is any integer"s;
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::string::va("Domain is any integer %zu or smaller", domain.unsignedInt64.max);
|
||||
}
|
||||
|
||||
default:
|
||||
return utils::string::va("unhandled dvar type '%i'", type);
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_value_string(const game::dvar_t * dvar, game::DvarValue * value)
|
||||
{
|
||||
std::string result = "N/A";
|
||||
|
||||
switch (dvar->type)
|
||||
{
|
||||
case game::DVAR_TYPE_BOOL:
|
||||
if (value->naked.enabled)
|
||||
{
|
||||
result = "1"s;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = "0"s;
|
||||
}
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_FLOAT:
|
||||
result = std::format("{:.2f}", value->naked.value);
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_FLOAT_2:
|
||||
result = std::format("{:.2f} {:.2f}", value->naked.vector[0], value->naked.vector[1]);
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_FLOAT_3:
|
||||
case game::DVAR_TYPE_LINEAR_COLOR_RGB:
|
||||
case game::DVAR_TYPE_COLOR_XYZ:
|
||||
case game::DVAR_TYPE_COLOR_LAB:
|
||||
result = std::format("{:.2f} {:.2f} {:.2f}", value->naked.vector[0], value->naked.vector[1], value->naked.vector[2]);
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_FLOAT_4:
|
||||
result = std::format("{:.2f} {:.2f} {:.2f} {:.2f}", value->naked.vector[0], value->naked.vector[1], value->naked.vector[2], value->naked.vector[3]);
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_INT:
|
||||
result = std::format("{}", value->naked.integer);
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_ENUM:
|
||||
if (dvar->domain.enumeration.stringCount)
|
||||
{
|
||||
result = std::string(dvar->domain.enumeration.strings[value->naked.integer]);
|
||||
}
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_STRING:
|
||||
result = std::string(value->naked.string);
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_COLOR:
|
||||
result = std::format("{:.2f} {:.2f} {:.2f} {:.2f}", (float)value->naked.color[0] * 0.0039215689, (float)value->naked.color[1] * 0.0039215689, (float)value->naked.color[2] * 0.0039215689, (float)value->naked.color[3] * 0.0039215689);
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_INT64:
|
||||
result = std::format("{}", value->naked.integer64);
|
||||
break;
|
||||
|
||||
case game::DVAR_TYPE_UINT64:
|
||||
result = std::format("{}", value->naked.unsignedInt64);
|
||||
break;
|
||||
|
||||
default:
|
||||
result = "ERROR:DVAR_TYPE_UNKNOWN"s;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
game::dvar_t* find_dvar(uint64_t hashRef)
|
||||
{
|
||||
if (hashRef == 0) return NULL;
|
||||
|
||||
auto it = std::find_if(variables::dvars_record.begin(), variables::dvars_record.end(), [&hashRef](variables::varEntry& i) { return i.fnv1a == hashRef; });
|
||||
|
||||
if (it != variables::dvars_record.end() && it->pointer)
|
||||
{
|
||||
return reinterpret_cast<game::dvar_t*>(it->pointer);
|
||||
}
|
||||
|
||||
return spoofcall::invoke<game::dvar_t*>(game::Dvar_FindVar_Hash, game::AssetRef(hashRef));
|
||||
}
|
||||
|
||||
game::dvar_t* find_dvar(const char* nameRef)
|
||||
{
|
||||
return spoofcall::invoke<game::dvar_t*>(game::Dvar_FindVar, nameRef);
|
||||
}
|
||||
|
||||
game::dvar_t* find_dvar(const std::string& nameRef)
|
||||
{
|
||||
auto it = std::find_if(variables::dvars_record.begin(), variables::dvars_record.end(), [&nameRef](variables::varEntry& i) { return utils::string::compare(i.name, nameRef); });
|
||||
|
||||
if (it != variables::dvars_record.end() && it->pointer)
|
||||
{
|
||||
return reinterpret_cast<game::dvar_t*>(it->pointer);
|
||||
}
|
||||
|
||||
return spoofcall::invoke<game::dvar_t*>(game::Dvar_FindVar, nameRef.data());
|
||||
}
|
||||
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::once(fetch_dvar_pointers, scheduler::pipeline::main);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(dvars::component)
|
13
source/proxy-dll/component/dvars.hpp
Normal file
13
source/proxy-dll/component/dvars.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "definitions\game.hpp"
|
||||
|
||||
namespace dvars
|
||||
{
|
||||
std::string get_value_string(const game::dvar_t* dvar, game::DvarValue* value);
|
||||
std::string get_domain_string(const game::dvarType_t type, const game::DvarLimits& domain);
|
||||
|
||||
game::dvar_t* find_dvar(uint64_t hashRef);
|
||||
game::dvar_t* find_dvar(const char* nameRef);
|
||||
game::dvar_t* find_dvar(const std::string& nameRef);
|
||||
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
#include <std_include.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
namespace experimental
|
||||
{
|
||||
namespace
|
||||
|
734
source/proxy-dll/component/game_console.cpp
Normal file
734
source/proxy-dll/component/game_console.cpp
Normal file
@ -0,0 +1,734 @@
|
||||
#include <std_include.hpp>
|
||||
#include "game_console.hpp"
|
||||
#include "definitions/game.hpp"
|
||||
#include "definitions/variables.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "component/dvars.hpp"
|
||||
#include "component/scheduler.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
#define R_DrawTextFont reinterpret_cast<void*>(game::sharedUiInfo->assets.bigFont)
|
||||
#define R_WhiteMaterial reinterpret_cast<void*>(game::sharedUiInfo->assets.whiteMaterial)
|
||||
|
||||
namespace game_console
|
||||
{
|
||||
namespace
|
||||
{
|
||||
game::vec4_t con_inputBoxColor = { 0.1f, 0.1f, 0.1f, 0.9f };
|
||||
game::vec4_t con_inputHintBoxColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||
game::vec4_t con_outputBarColor = { 0.8f, 0.8f, 0.8f, 0.6f };
|
||||
game::vec4_t con_outputSliderColor = { 0.8f, 0.8f, 0.8f, 1.0f };
|
||||
game::vec4_t con_outputWindowColor = { 0.15f, 0.15f, 0.15f, 0.85f };
|
||||
game::vec4_t con_inputWriteDownColor = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
game::vec4_t con_inputDvarMatchColor = { 0.1f, 0.8f, 0.8f, 1.0f };
|
||||
game::vec4_t con_inputDvarInactiveValueColor = { 0.4f, 0.8f, 0.7f, 1.0f };
|
||||
game::vec4_t con_inputCmdMatchColor = { 0.9f, 0.6f, 0.2f, 1.0f };
|
||||
game::vec4_t con_inputDescriptionColor = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
game::vec4_t con_inputAltDescriptionColor = { 0.9f, 0.6f, 0.2f, 1.0f };
|
||||
game::vec4_t con_inputExtraInfoColor = { 1.0f, 0.5f, 0.5f, 1.0f };
|
||||
game::vec4_t con_outputVersionStringColor = { 0.92f, 1.0f, 0.65f, 1.0f };
|
||||
|
||||
using suggestion_t = variables::varEntry;
|
||||
using output_queue = std::deque<std::string>;
|
||||
|
||||
struct ingame_console
|
||||
{
|
||||
char buffer[256]{};
|
||||
int cursor{};
|
||||
float font_scale{};
|
||||
float font_height{};
|
||||
int max_suggestions{};
|
||||
int visible_line_count{};
|
||||
float screen_min[2]{};
|
||||
float screen_max[2]{};
|
||||
struct {
|
||||
float x{}, y{};
|
||||
} screen_pointer;
|
||||
bool may_auto_complete{};
|
||||
char auto_complete_choice[64]{};
|
||||
bool output_visible{};
|
||||
int display_line_offset{};
|
||||
int total_line_count{};
|
||||
utils::concurrency::container<output_queue, std::recursive_mutex> output{};
|
||||
};
|
||||
|
||||
ingame_console con{};
|
||||
|
||||
std::int32_t history_index = -1;
|
||||
std::deque<std::string> history{};
|
||||
|
||||
std::string fixed_input{};
|
||||
std::vector<suggestion_t> matches{};
|
||||
|
||||
void clear_input()
|
||||
{
|
||||
strncpy_s(con.buffer, "", sizeof(con.buffer));
|
||||
con.cursor = 0;
|
||||
|
||||
fixed_input = "";
|
||||
matches.clear();
|
||||
}
|
||||
|
||||
void clear_output()
|
||||
{
|
||||
con.total_line_count = 0;
|
||||
con.display_line_offset = 0;
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
output.clear();
|
||||
});
|
||||
history_index = -1;
|
||||
history.clear();
|
||||
}
|
||||
|
||||
void print_internal(const std::string& data)
|
||||
{
|
||||
con.output.access([&](output_queue& output)
|
||||
{
|
||||
if (con.visible_line_count > 0
|
||||
&& con.display_line_offset == (output.size() - con.visible_line_count))
|
||||
{
|
||||
con.display_line_offset++;
|
||||
}
|
||||
output.push_back(data);
|
||||
if (output.size() > 512)
|
||||
{
|
||||
output.pop_front();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void toggle_console()
|
||||
{
|
||||
clear_input();
|
||||
|
||||
con.output_visible = false;
|
||||
*game::keyCatchers ^= 1;
|
||||
}
|
||||
|
||||
void toggle_console_output()
|
||||
{
|
||||
con.output_visible = con.output_visible == 0;
|
||||
}
|
||||
|
||||
bool is_renderer_ready()
|
||||
{
|
||||
return (R_DrawTextFont && R_WhiteMaterial);
|
||||
}
|
||||
|
||||
void calculate_window_size()
|
||||
{
|
||||
con.screen_min[0] = 6.0f;
|
||||
con.screen_min[1] = 6.0f;
|
||||
con.screen_max[0] = game::ScrPlace_GetView(0)->realViewportSize[0] - 6.0f;
|
||||
con.screen_max[1] = game::ScrPlace_GetView(0)->realViewportSize[1] - 6.0f;
|
||||
|
||||
con.font_height = static_cast<float>(game::UI_TextHeight(R_DrawTextFont, con.font_scale));
|
||||
con.visible_line_count = static_cast<int>((con.screen_max[1] - con.screen_min[1] - (con.font_height * 2)) - 24.0f) / con.font_height;
|
||||
}
|
||||
|
||||
void draw_box(const float x, const float y, const float w, const float h, float* color)
|
||||
{
|
||||
game::vec4_t outline_color;
|
||||
|
||||
outline_color[0] = color[0] * 0.5f;
|
||||
outline_color[1] = color[1] * 0.5f;
|
||||
outline_color[2] = color[2] * 0.5f;
|
||||
outline_color[3] = color[3];
|
||||
|
||||
game::R_AddCmdDrawStretchPic(x, y, w, h, 0.0f, 0.0f, 0.0f, 0.0f, color, R_WhiteMaterial);
|
||||
game::R_AddCmdDrawStretchPic(x, y, 2.0f, h, 0.0f, 0.0f, 0.0f, 0.0f, outline_color, R_WhiteMaterial);
|
||||
game::R_AddCmdDrawStretchPic((x + w) - 2.0f, y, 2.0f, h, 0.0f, 0.0f, 0.0f, 0.0f, outline_color, R_WhiteMaterial);
|
||||
game::R_AddCmdDrawStretchPic(x, y, w, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, outline_color, R_WhiteMaterial);
|
||||
game::R_AddCmdDrawStretchPic(x, (y + h) - 2.0f, w, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, outline_color, R_WhiteMaterial);
|
||||
}
|
||||
|
||||
void draw_input_box(const int lines, float* color)
|
||||
{
|
||||
draw_box( con.screen_pointer.x - 6.0f, con.screen_pointer.y - 6.0f,
|
||||
(con.screen_max[0] - con.screen_min[0]) - ((con.screen_pointer.x - 6.0f) - con.screen_min[0]),
|
||||
(lines * con.font_height) + 12.0f, color);
|
||||
}
|
||||
|
||||
void draw_input_text_and_over(const char* str, float* color)
|
||||
{
|
||||
game::R_AddCmdDrawText(str, 0x7FFFFFFF, R_DrawTextFont, con.screen_pointer.x,
|
||||
con.screen_pointer.y + con.font_height, con.font_scale, con.font_scale, 0.0f, color, 0);
|
||||
|
||||
con.screen_pointer.x = game::UI_TextWidth(0, str, 0x7FFFFFFF, R_DrawTextFont, con.font_scale) + con.screen_pointer.x + 6.0f;
|
||||
}
|
||||
|
||||
float draw_hint_box(const int lines, float* color, [[maybe_unused]] float offset_x = 0.0f,
|
||||
[[maybe_unused]] float offset_y = 0.0f)
|
||||
{
|
||||
const auto _h = lines * con.font_height + 12.0f;
|
||||
const auto _y = con.screen_pointer.y - 3.0f + con.font_height + 12.0f + offset_y;
|
||||
const auto _w = (con.screen_max[0] - con.screen_min[0]) - ((con.screen_pointer.x - 6.0f) - con.screen_min[0]);
|
||||
|
||||
draw_box(con.screen_pointer.x - 6.0f, _y, _w, _h, color);
|
||||
return _h;
|
||||
}
|
||||
|
||||
void draw_hint_text(const int line, const char* text, float* color, const float offset_x = 0.0f, const float offset_y = 0.0f)
|
||||
{
|
||||
const auto _y = con.font_height + con.screen_pointer.y + (con.font_height * (line + 1)) + 15.0f + offset_y;
|
||||
|
||||
game::R_AddCmdDrawText(text, 0x7FFFFFFF, R_DrawTextFont, con.screen_pointer.x + offset_x, _y, con.font_scale, con.font_scale, 0.0f, color, 0);
|
||||
}
|
||||
|
||||
void find_matches(const std::string& input, std::vector<suggestion_t>& suggestions, bool exact)
|
||||
{
|
||||
double required_ratio = exact ? 1.00 : 0.01;
|
||||
|
||||
for (const auto& dvar : variables::dvars_record)
|
||||
{
|
||||
if (dvars::find_dvar(dvar.fnv1a) && utils::string::match(input, dvar.name) >= required_ratio)
|
||||
{
|
||||
suggestions.push_back(dvar);
|
||||
}
|
||||
|
||||
if (exact && suggestions.size() > 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (suggestions.size() == 0 && dvars::find_dvar(input))
|
||||
{
|
||||
suggestions.push_back({ input, "", fnv1a::generate_hash(input.data()), reinterpret_cast<uintptr_t>(dvars::find_dvar(input)) });
|
||||
}
|
||||
|
||||
for (const auto& cmd : variables::commands_record)
|
||||
{
|
||||
if (utils::string::match(input, cmd.name) >= required_ratio)
|
||||
{
|
||||
suggestions.push_back(cmd);
|
||||
}
|
||||
|
||||
if (exact && suggestions.size() > 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_input()
|
||||
{
|
||||
con.screen_pointer.x = con.screen_min[0] + 6.0f;
|
||||
con.screen_pointer.y = con.screen_min[1] + 6.0f;
|
||||
|
||||
draw_input_box(1, con_inputBoxColor);
|
||||
draw_input_text_and_over("PROJECT-BO4 >", con_inputWriteDownColor);
|
||||
|
||||
con.auto_complete_choice[0] = 0;
|
||||
|
||||
game::R_AddCmdDrawTextWithCursor(con.buffer, 0x7FFFFFFF, R_DrawTextFont, con.screen_pointer.x, con.screen_pointer.y + con.font_height, con.font_scale, con.font_scale, 0, con_inputWriteDownColor, 0, con.cursor, '|');
|
||||
|
||||
// check if using a prefixed '/' or not
|
||||
const auto input = con.buffer[1] && (con.buffer[0] == '/' || con.buffer[0] == '\\')
|
||||
? std::string(con.buffer).substr(1) : std::string(con.buffer);
|
||||
|
||||
if (!input.length())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (input != fixed_input)
|
||||
{
|
||||
matches.clear();
|
||||
|
||||
if (input.find(" ") != std::string::npos)
|
||||
{
|
||||
find_matches(input.substr(0, input.find(" ")), matches, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
find_matches(input, matches, false);
|
||||
|
||||
if (matches.size() <= con.max_suggestions)
|
||||
{
|
||||
std::sort(matches.begin(), matches.end(), [&input](suggestion_t& lhs, suggestion_t& rhs) {
|
||||
return utils::string::match(input, lhs.name) > utils::string::match(input, rhs.name);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fixed_input = input;
|
||||
}
|
||||
|
||||
con.may_auto_complete = false;
|
||||
|
||||
if (matches.size() > con.max_suggestions)
|
||||
{
|
||||
draw_hint_box(1, con_inputHintBoxColor);
|
||||
draw_hint_text(0, utils::string::va("%i matches (too many to show here)", matches.size()), con_inputDvarMatchColor);
|
||||
}
|
||||
else if (matches.size() == 1)
|
||||
{
|
||||
auto* dvar = dvars::find_dvar(matches[0].fnv1a);
|
||||
auto line_count = dvar ? 3 : 1;
|
||||
|
||||
auto height = draw_hint_box(line_count, con_inputHintBoxColor);
|
||||
draw_hint_text(0, matches[0].name.data(), dvar ? con_inputDvarMatchColor : con_inputCmdMatchColor);
|
||||
|
||||
if (dvar)
|
||||
{
|
||||
auto offset_x = (con.screen_max[0] - con.screen_pointer.x) / 4.f;
|
||||
|
||||
draw_hint_text(0, dvars::get_value_string(dvar, &dvar->value->current).data(), con_inputDvarMatchColor, offset_x);
|
||||
draw_hint_text(1, " default", con_inputDvarInactiveValueColor);
|
||||
draw_hint_text(1, dvars::get_value_string(dvar, &dvar->value->reset).data(), con_inputDvarInactiveValueColor, offset_x);
|
||||
draw_hint_text(2, matches[0].desc, con_inputDescriptionColor, 0);
|
||||
|
||||
auto offset_y = height + 3.f;
|
||||
auto domain_lines = 1;
|
||||
if (dvar->type == game::DVAR_TYPE_ENUM)
|
||||
domain_lines = dvar->domain.enumeration.stringCount + 1;
|
||||
|
||||
draw_hint_box(domain_lines, con_inputHintBoxColor, 0, offset_y);
|
||||
draw_hint_text(0, dvars::get_domain_string(dvar->type, dvar->domain).data(), con_inputAltDescriptionColor, 0, offset_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto offset_x = (con.screen_max[0] - con.screen_pointer.x) / 4.f;
|
||||
|
||||
draw_hint_text(0, matches[0].desc, con_inputCmdMatchColor, offset_x);
|
||||
}
|
||||
|
||||
strncpy_s(con.auto_complete_choice, matches[0].name.data(), 64);
|
||||
con.may_auto_complete = true;
|
||||
}
|
||||
else if (matches.size() > 1)
|
||||
{
|
||||
draw_hint_box(static_cast<int>(matches.size()), con_inputHintBoxColor);
|
||||
|
||||
auto offset_x = (con.screen_max[0] - con.screen_pointer.x) / 4.f;
|
||||
|
||||
for (size_t i = 0; i < matches.size(); i++)
|
||||
{
|
||||
auto* const dvar = dvars::find_dvar(matches[i].fnv1a);
|
||||
|
||||
draw_hint_text(static_cast<int>(i), matches[i].name.data(), dvar ? con_inputDvarMatchColor : con_inputCmdMatchColor);
|
||||
draw_hint_text(static_cast<int>(i), matches[i].desc, dvar ? con_inputDvarMatchColor : con_inputCmdMatchColor, offset_x * 1.5f);
|
||||
|
||||
if (dvar)
|
||||
{
|
||||
draw_hint_text(static_cast<int>(i), dvars::get_value_string(dvar, &dvar->value->current).data(), con_inputDvarMatchColor, offset_x);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy_s(con.auto_complete_choice, matches[0].name.data(), 64);
|
||||
con.may_auto_complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_output_scrollbar(const float x, float y, const float width, const float height, output_queue& output)
|
||||
{
|
||||
auto _x = (x + width) - 10.0f;
|
||||
draw_box(_x, y, 10.0f, height, con_outputBarColor);
|
||||
|
||||
auto _height = height;
|
||||
if (output.size() > con.visible_line_count)
|
||||
{
|
||||
auto percentage = static_cast<float>(con.visible_line_count) / output.size();
|
||||
_height *= percentage;
|
||||
|
||||
auto remainingSpace = height - _height;
|
||||
auto percentageAbove = static_cast<float>(con.display_line_offset) / (output.size() - con.visible_line_count);
|
||||
|
||||
y = y + (remainingSpace * percentageAbove);
|
||||
}
|
||||
|
||||
draw_box(_x, y, 10.0f, _height, con_outputSliderColor);
|
||||
}
|
||||
|
||||
void draw_output_text(const float x, float y, output_queue& output)
|
||||
{
|
||||
auto offset = output.size() >= con.visible_line_count ? 0.0f : (con.font_height * (con.visible_line_count - output.size()));
|
||||
|
||||
for (auto i = 0; i < con.visible_line_count; i++)
|
||||
{
|
||||
auto index = i + con.display_line_offset;
|
||||
if (index >= output.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
game::R_AddCmdDrawText(output.at(index).data(), 0x400, R_DrawTextFont, x, y + offset + ((i + 1) * con.font_height), con.font_scale, con.font_scale, 0.0f, con_inputWriteDownColor, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_output_window()
|
||||
{
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
draw_box(con.screen_min[0], con.screen_min[1] + 32.0f, con.screen_max[0] - con.screen_min[0], (con.screen_max[1] - con.screen_min[1]) - 32.0f, con_outputWindowColor);
|
||||
|
||||
auto x = con.screen_min[0] + 6.0f;
|
||||
auto y = (con.screen_min[1] + 32.0f) + 6.0f;
|
||||
auto width = (con.screen_max[0] - con.screen_min[0]) - 12.0f;
|
||||
auto height = ((con.screen_max[1] - con.screen_min[1]) - 32.0f) - 12.0f;
|
||||
|
||||
game::R_AddCmdDrawText(game::version_string.data(), 0x7FFFFFFF, R_DrawTextFont, x, ((height - 16.0f) + y) + con.font_height, con.font_scale, con.font_scale, 0.0f, con_outputVersionStringColor, 0);
|
||||
|
||||
draw_output_scrollbar(x, y, width, height, output);
|
||||
draw_output_text(x, y, output);
|
||||
});
|
||||
}
|
||||
|
||||
void draw_console()
|
||||
{
|
||||
if (!is_renderer_ready()) return;
|
||||
|
||||
calculate_window_size();
|
||||
|
||||
if (*game::keyCatchers & 1)
|
||||
{
|
||||
if (!(*game::keyCatchers & 1))
|
||||
{
|
||||
con.output_visible = false;
|
||||
}
|
||||
|
||||
if (con.output_visible)
|
||||
{
|
||||
draw_output_window();
|
||||
}
|
||||
|
||||
draw_input();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print(const char* fmt, ...)
|
||||
{
|
||||
char va_buffer[0x200] = { 0 };
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf_s(va_buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
const auto formatted = std::string(va_buffer);
|
||||
const auto lines = utils::string::split(formatted, '\n');
|
||||
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
print_internal(line);
|
||||
}
|
||||
}
|
||||
|
||||
void print(const std::string& data)
|
||||
{
|
||||
const auto lines = utils::string::split(data, '\n');
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
print_internal(line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool console_char_event(const int local_client_num, const int key)
|
||||
{
|
||||
if (key == game::keyNum_t::K_GRAVE ||
|
||||
key == game::keyNum_t::K_TILDE ||
|
||||
key == '|' ||
|
||||
key == '\\')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key > 127)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*game::keyCatchers & 1)
|
||||
{
|
||||
if (key == game::keyNum_t::K_TAB) // tab (auto complete)
|
||||
{
|
||||
if (con.may_auto_complete)
|
||||
{
|
||||
const auto first_char = con.buffer[0];
|
||||
|
||||
clear_input();
|
||||
|
||||
if (first_char == '\\' || first_char == '/')
|
||||
{
|
||||
con.buffer[0] = first_char;
|
||||
con.buffer[1] = '\0';
|
||||
}
|
||||
|
||||
strncat_s(con.buffer, con.auto_complete_choice, 64);
|
||||
con.cursor = static_cast<int>(std::string(con.buffer).length());
|
||||
|
||||
if (con.cursor != 254)
|
||||
{
|
||||
con.buffer[con.cursor++] = ' ';
|
||||
con.buffer[con.cursor] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key == 'v' - 'a' + 1) // paste
|
||||
{
|
||||
const auto clipboard = utils::string::get_clipboard_data();
|
||||
if (clipboard.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < clipboard.length(); i++)
|
||||
{
|
||||
console_char_event(local_client_num, clipboard[i]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key == 'c' - 'a' + 1) // clear
|
||||
{
|
||||
clear_input();
|
||||
con.total_line_count = 0;
|
||||
con.display_line_offset = 0;
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
output.clear();
|
||||
});
|
||||
history_index = -1;
|
||||
history.clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key == 'h' - 'a' + 1) // backspace
|
||||
{
|
||||
if (con.cursor > 0)
|
||||
{
|
||||
memmove(con.buffer + con.cursor - 1, con.buffer + con.cursor,
|
||||
strlen(con.buffer) + 1 - con.cursor);
|
||||
con.cursor--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key < 32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (con.cursor == 256 - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(con.buffer + con.cursor + 1, con.buffer + con.cursor, strlen(con.buffer) + 1 - con.cursor);
|
||||
con.buffer[con.cursor] = static_cast<char>(key);
|
||||
con.cursor++;
|
||||
|
||||
if (con.cursor == strlen(con.buffer) + 1)
|
||||
{
|
||||
con.buffer[con.cursor] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool console_key_event(const int local_client_num, const int key, const int down)
|
||||
{
|
||||
if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE)
|
||||
{
|
||||
if (!down)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto shift_down = game::playerKeys[local_client_num].keys[game::keyNum_t::K_LSHIFT].down;
|
||||
if (shift_down)
|
||||
{
|
||||
if (!(*game::keyCatchers & 1))
|
||||
{
|
||||
toggle_console();
|
||||
}
|
||||
|
||||
toggle_console_output();
|
||||
return false;
|
||||
}
|
||||
|
||||
toggle_console();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*game::keyCatchers & 1)
|
||||
{
|
||||
if (down)
|
||||
{
|
||||
if (key == game::keyNum_t::K_UPARROW)
|
||||
{
|
||||
if (++history_index >= history.size())
|
||||
{
|
||||
history_index = static_cast<int>(history.size()) - 1;
|
||||
}
|
||||
|
||||
clear_input();
|
||||
|
||||
if (history_index != -1)
|
||||
{
|
||||
strncpy_s(con.buffer, history.at(history_index).c_str(), 0x100);
|
||||
con.cursor = static_cast<int>(strlen(con.buffer));
|
||||
}
|
||||
}
|
||||
else if (key == game::keyNum_t::K_DOWNARROW)
|
||||
{
|
||||
if (--history_index < -1)
|
||||
{
|
||||
history_index = -1;
|
||||
}
|
||||
|
||||
clear_input();
|
||||
|
||||
if (history_index != -1)
|
||||
{
|
||||
strncpy_s(con.buffer, history.at(history_index).c_str(), 0x100);
|
||||
con.cursor = static_cast<int>(strlen(con.buffer));
|
||||
}
|
||||
}
|
||||
|
||||
if (key == game::keyNum_t::K_RIGHTARROW)
|
||||
{
|
||||
if (con.cursor < strlen(con.buffer))
|
||||
{
|
||||
con.cursor++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key == game::keyNum_t::K_LEFTARROW)
|
||||
{
|
||||
if (con.cursor > 0)
|
||||
{
|
||||
con.cursor--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//scroll through output
|
||||
if (key == game::keyNum_t::K_MWHEELUP || key == game::keyNum_t::K_PGUP)
|
||||
{
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
if (output.size() > con.visible_line_count && con.display_line_offset > 0)
|
||||
{
|
||||
con.display_line_offset--;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (key == game::keyNum_t::K_MWHEELDOWN || key == game::keyNum_t::K_PGDN)
|
||||
{
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
if (output.size() > con.visible_line_count
|
||||
&& con.display_line_offset < (output.size() - con.visible_line_count))
|
||||
{
|
||||
con.display_line_offset++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (key == game::keyNum_t::K_ENTER)
|
||||
{
|
||||
//game::Cbuf_AddText(0, utils::string::va("%s \n", fixed_input.data()));
|
||||
|
||||
if (history_index != -1)
|
||||
{
|
||||
const auto itr = history.begin() + history_index;
|
||||
|
||||
if (*itr == con.buffer)
|
||||
{
|
||||
history.erase(history.begin() + history_index);
|
||||
}
|
||||
}
|
||||
|
||||
history.push_front(con.buffer);
|
||||
|
||||
print("]%s\n", con.buffer);
|
||||
game::Cbuf_AddText(0, utils::string::va("%s \n", fixed_input.data()));
|
||||
|
||||
if (history.size() > 10)
|
||||
{
|
||||
history.erase(history.begin() + 10);
|
||||
}
|
||||
|
||||
history_index = -1;
|
||||
|
||||
clear_input();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
utils::hook::detour cl_key_event_hook;
|
||||
void cl_key_event_stub(int localClientNum, int key, bool down, unsigned int time)
|
||||
{
|
||||
if (!game_console::console_key_event(localClientNum, key, down))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cl_key_event_hook.invoke<void>(localClientNum, key, down, time);
|
||||
}
|
||||
|
||||
utils::hook::detour cl_char_event_hook;
|
||||
void cl_char_event_stub(const int localClientNum, const int key, bool isRepeated)
|
||||
{
|
||||
if (!game_console::console_char_event(localClientNum, key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cl_char_event_hook.invoke<void>(localClientNum, key, isRepeated);
|
||||
}
|
||||
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::loop(draw_console, scheduler::renderer);
|
||||
|
||||
cl_key_event_hook.create(0x142839250_g, cl_key_event_stub);
|
||||
cl_char_event_hook.create(0x142836F80_g, cl_char_event_stub);
|
||||
|
||||
|
||||
// initialize our structs
|
||||
con.cursor = 0;
|
||||
con.visible_line_count = 0;
|
||||
con.output_visible = false;
|
||||
con.display_line_offset = 0;
|
||||
con.total_line_count = 0;
|
||||
strncpy_s(con.buffer, "", 256);
|
||||
|
||||
con.screen_pointer.x = 0.0f;
|
||||
con.screen_pointer.y = 0.0f;
|
||||
con.may_auto_complete = false;
|
||||
strncpy_s(con.auto_complete_choice, "", 64);
|
||||
|
||||
con.font_scale = 0.38f;
|
||||
con.max_suggestions = 24;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(game_console::component)
|
7
source/proxy-dll/component/game_console.hpp
Normal file
7
source/proxy-dll/component/game_console.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace game_console
|
||||
{
|
||||
void print(const char* fmt, ...);
|
||||
void print(const std::string& data);
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
#include <std_include.hpp>
|
||||
#include "logger.hpp"
|
||||
#include "game_console.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
#define OUTPUT_DEBUG_API
|
||||
#define PREPEND_TIMESTAMP
|
||||
#define OUTPUT_GAME_CONSOLE
|
||||
|
||||
namespace logger
|
||||
{
|
||||
@ -22,20 +24,25 @@ namespace logger
|
||||
if (type == LOG_TYPE_DEBUG) return;
|
||||
#endif // _DEBUG
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "[ " << LogTypeNames[type] << " ] " << str << std::endl;
|
||||
|
||||
std::string text = ss.str();
|
||||
|
||||
#ifdef OUTPUT_GAME_CONSOLE
|
||||
game_console::print(text);
|
||||
#endif // OUTPUT_GAME_CONSOLE
|
||||
|
||||
#ifdef OUTPUT_DEBUG_API
|
||||
OutputDebugStringA(str.c_str());
|
||||
OutputDebugStringA(text.c_str());
|
||||
#endif // OUTPUT_DEBUG_API
|
||||
|
||||
std::ofstream stream;
|
||||
stream.open("project-bo4.log", std::ios_base::app);
|
||||
std::ofstream fs;
|
||||
fs.open("project-bo4.log", std::ios_base::app);
|
||||
|
||||
#ifdef PREPEND_TIMESTAMP
|
||||
time_t now = time(0);
|
||||
std::tm* t = std::localtime(&now);
|
||||
stream << "" << std::put_time(t, "%Y-%m-%d %H:%M:%S") << "\t";
|
||||
#endif // PREPEND_TIMESTAMP
|
||||
|
||||
stream << "[ " << LogTypeNames[type] << " ] " << str << std::endl;
|
||||
fs << "" << std::put_time(t, "%Y-%m-%d %H:%M:%S") << "\t" << text;
|
||||
}
|
||||
|
||||
void write(const int type, const char* fmt, ...)
|
||||
@ -51,11 +58,6 @@ namespace logger
|
||||
write(type, formatted);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/* PLACE_HOLDER */
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
|
@ -1,13 +1,14 @@
|
||||
#include <std_include.hpp>
|
||||
#include "platform.hpp"
|
||||
#include "definitions/game.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/identity.hpp>
|
||||
#include <utils/json_config.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
#include "WinReg.hpp"
|
||||
#include "definitions/t8_engine.hpp"
|
||||
#include <WinReg.hpp>
|
||||
|
||||
namespace platform
|
||||
{
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "scheduler.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <utils/hook.hpp>
|
||||
@ -166,7 +165,7 @@ namespace scheduler
|
||||
void post_unpack() override
|
||||
{
|
||||
r_end_frame_hook.create(0x14361E260_g, r_end_frame_stub); // R_EndFrame
|
||||
//main_frame_hook.create(0x14288BAE0_g, main_frame_stub); // Com_Frame
|
||||
main_frame_hook.create(0x14288BAE0_g, main_frame_stub); // Com_Frame
|
||||
//g_run_frame_hook.create(0x142D08FC0_g, server_frame_stub); // G_RunFrame
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <std_include.hpp>
|
||||
#include "splash.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "splash.hpp"
|
||||
#include "resource.hpp"
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <std_include.hpp>
|
||||
#include "definitions\discovery.hpp"
|
||||
#include "discovery.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/signature.hpp>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <std_include.hpp>
|
||||
#include "definitions\t8_engine.hpp"
|
||||
#include "game.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
namespace game
|
507
source/proxy-dll/definitions/game.hpp
Normal file
507
source/proxy-dll/definitions/game.hpp
Normal file
@ -0,0 +1,507 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions\discovery.hpp"
|
||||
|
||||
#define WEAK __declspec(selectany)
|
||||
|
||||
namespace game
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// VARIABLES //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern std::string version_string;
|
||||
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// STRUCTS //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct BO4_AssetRef_t
|
||||
{
|
||||
__int64 hash;
|
||||
__int64 null;
|
||||
};
|
||||
|
||||
inline BO4_AssetRef_t
|
||||
AssetRef(uint64_t hashRef)
|
||||
{
|
||||
BO4_AssetRef_t m128i;
|
||||
m128i.hash = hashRef;
|
||||
|
||||
return m128i;
|
||||
}
|
||||
|
||||
enum keyNum_t
|
||||
{
|
||||
K_NONE = 0x00,
|
||||
K_BUTTON_A = 0x01,
|
||||
K_BUTTON_B = 0x02,
|
||||
K_BUTTON_X = 0x03,
|
||||
K_BUTTON_Y = 0x04,
|
||||
K_BUTTON_LSHLDR = 0x05,
|
||||
K_BUTTON_RSHLDR = 0x06,
|
||||
K_UNK7 = 0x07,
|
||||
K_UNK8 = 0x08,
|
||||
K_TAB = 0x09,
|
||||
K_UNK10 = 0x0A,
|
||||
K_UNK11 = 0x0B,
|
||||
K_UNK12 = 0x0C,
|
||||
K_ENTER = 0x0D,
|
||||
K_BUTTON_START = 0x0E,
|
||||
K_BUTTON_BACK = 0x0F,
|
||||
K_BUTTON_LSTICK = 0x10,
|
||||
K_BUTTON_RSTICK = 0x11,
|
||||
K_BUTTON_LTRIG = 0x12,
|
||||
K_BUTTON_RTRIG = 0x13,
|
||||
K_UNK20 = 0x14,
|
||||
K_UNK21 = 0x15,
|
||||
K_DPAD_UP = 0x16,
|
||||
K_DPAD_DOWN = 0x17,
|
||||
K_DPAD_LEFT = 0x18,
|
||||
K_DPAD_RIGHT = 0x19,
|
||||
K_UNK26 = 0x1A,
|
||||
K_ESCAPE = 0x1B,
|
||||
K_APAD_UP = 0x1C,
|
||||
K_APAD_DOWN = 0x1D,
|
||||
K_APAD_LEFT = 0x1E,
|
||||
K_APAD_RIGHT = 0x1F,
|
||||
K_SPACE = 0x20,
|
||||
K_UNK33 = 0x21,
|
||||
K_UNK34 = 0x22,
|
||||
K_UNK35 = 0x23,
|
||||
K_UNK36 = 0x24,
|
||||
K_UNK37 = 0x25,
|
||||
K_UNK38 = 0x26,
|
||||
K_UNK39 = 0x27,
|
||||
K_UNK40 = 0x28,
|
||||
K_UNK41 = 0x29,
|
||||
K_UNK42 = 0x2A,
|
||||
K_UNK43 = 0x2B,
|
||||
K_UNK44 = 0x2C,
|
||||
K_UNK45 = 0x2D,
|
||||
K_UNK46 = 0x2E,
|
||||
K_UNK47 = 0x2F,
|
||||
K_UNK48 = 0x30,
|
||||
K_UNK49 = 0x31,
|
||||
K_UNK50 = 0x32,
|
||||
K_UNK51 = 0x33,
|
||||
K_UNK52 = 0x34,
|
||||
K_UNK53 = 0x35,
|
||||
K_UNK54 = 0x36,
|
||||
K_UNK55 = 0x37,
|
||||
K_UNK56 = 0x38,
|
||||
K_UNK57 = 0x39,
|
||||
K_UNK58 = 0x3A,
|
||||
K_SEMICOLON = 0x3B,
|
||||
K_UNK60 = 0x3C,
|
||||
K_UNK61 = 0x3D,
|
||||
K_UNK62 = 0x3E,
|
||||
K_UNK63 = 0x3F,
|
||||
K_UNK64 = 0x40,
|
||||
K_UNK65 = 0x41,
|
||||
K_UNK66 = 0x42,
|
||||
K_UNK67 = 0x43,
|
||||
K_UNK68 = 0x44,
|
||||
K_UNK69 = 0x45,
|
||||
K_UNK70 = 0x46,
|
||||
K_UNK71 = 0x47,
|
||||
K_UNK72 = 0x48,
|
||||
K_UNK73 = 0x49,
|
||||
K_UNK74 = 0x4A,
|
||||
K_UNK75 = 0x4B,
|
||||
K_UNK76 = 0x4C,
|
||||
K_UNK77 = 0x4D,
|
||||
K_UNK78 = 0x4E,
|
||||
K_UNK79 = 0x4F,
|
||||
K_UNK80 = 0x50,
|
||||
K_UNK81 = 0x51,
|
||||
K_UNK82 = 0x52,
|
||||
K_UNK83 = 0x53,
|
||||
K_UNK84 = 0x54,
|
||||
K_UNK85 = 0x55,
|
||||
K_UNK86 = 0x56,
|
||||
K_UNK87 = 0x57,
|
||||
K_UNK88 = 0x58,
|
||||
K_UNK89 = 0x59,
|
||||
K_UNK90 = 0x5A,
|
||||
K_UNK91 = 0x5B,
|
||||
K_UNK92 = 0x5C,
|
||||
K_UNK93 = 0x5D,
|
||||
K_UNK94 = 0x5E,
|
||||
K_UNK95 = 0x5F,
|
||||
K_GRAVE = 0x60,
|
||||
K_UNK97 = 0x61,
|
||||
K_UNK98 = 0x62,
|
||||
K_UNK99 = 0x63,
|
||||
K_UNK100 = 0x64,
|
||||
K_UNK101 = 0x65,
|
||||
K_UNK102 = 0x66,
|
||||
K_UNK103 = 0x67,
|
||||
K_UNK104 = 0x68,
|
||||
K_UNK105 = 0x69,
|
||||
K_UNK106 = 0x6A,
|
||||
K_UNK107 = 0x6B,
|
||||
K_UNK108 = 0x6C,
|
||||
K_UNK109 = 0x6D,
|
||||
K_UNK110 = 0x6E,
|
||||
K_UNK111 = 0x6F,
|
||||
K_UNK112 = 0x70,
|
||||
K_UNK113 = 0x71,
|
||||
K_UNK114 = 0x72,
|
||||
K_UNK115 = 0x73,
|
||||
K_UNK116 = 0x74,
|
||||
K_UNK117 = 0x75,
|
||||
K_UNK118 = 0x76,
|
||||
K_UNK119 = 0x77,
|
||||
K_UNK120 = 0x78,
|
||||
K_UNK121 = 0x79,
|
||||
K_UNK122 = 0x7A,
|
||||
K_UNK123 = 0x7B,
|
||||
K_UNK124 = 0x7C,
|
||||
K_UNK125 = 0x7D,
|
||||
K_TILDE = 0x7E,
|
||||
K_BACKSPACE = 0x7F,
|
||||
K_CAPSLOCK = 0x80,
|
||||
K_PAUSE = 0x81,
|
||||
K_PRINTSCREEN = 0x82,
|
||||
K_SCROLLLOCK = 0x83,
|
||||
K_UPARROW = 0x84,
|
||||
K_DOWNARROW = 0x85,
|
||||
K_LEFTARROW = 0x86,
|
||||
K_RIGHTARROW = 0x87,
|
||||
K_LALT = 0x88,
|
||||
K_RALT = 0x89,
|
||||
K_LCTRL = 0x8A,
|
||||
K_RCTRL = 0x8B,
|
||||
K_LSHIFT = 0x8C,
|
||||
K_RSHIFT = 0x8D,
|
||||
K_HIRAGANA = 0x8E,
|
||||
K_HENKAN = 0x8F,
|
||||
K_MUHENKAN = 0x90,
|
||||
K_LWIN = 0x91,
|
||||
K_RWIN = 0x92,
|
||||
K_MENU = 0x93,
|
||||
K_INS = 0x94,
|
||||
K_DEL = 0x95,
|
||||
K_PGDN = 0x96,
|
||||
K_PGUP = 0x97,
|
||||
K_HOME = 0x98,
|
||||
K_END = 0x99,
|
||||
K_F1 = 0x9A,
|
||||
K_F2 = 0x9B,
|
||||
K_F3 = 0x9C,
|
||||
K_F4 = 0x9D,
|
||||
K_F5 = 0x9E,
|
||||
K_F6 = 0x9F,
|
||||
K_F7 = 0xA0,
|
||||
K_F8 = 0xA1,
|
||||
K_F9 = 0xA2,
|
||||
K_F10 = 0xA3,
|
||||
K_F11 = 0xA4,
|
||||
K_F12 = 0xA5,
|
||||
K_UNK166 = 0xA6,
|
||||
K_UNK167 = 0xA7,
|
||||
K_UNK168 = 0xA8,
|
||||
K_KP_HOME = 0xA9,
|
||||
K_KP_UPARROW = 0xAA,
|
||||
K_KP_PGUP = 0xAB,
|
||||
K_KP_LEFTARROW = 0xAC,
|
||||
K_KP_5 = 0xAD,
|
||||
K_KP_RIGHTARROW = 0xAE,
|
||||
K_KP_END = 0xAF,
|
||||
K_KP_DOWNARROW = 0xB0,
|
||||
K_KP_PGDN = 0xB1,
|
||||
K_KP_ENTER = 0xB2,
|
||||
K_KP_INS = 0xB3,
|
||||
K_KP_DEL = 0xB4,
|
||||
K_KP_SLASH = 0xB5,
|
||||
K_KP_MINUS = 0xB6,
|
||||
K_KP_PLUS = 0xB7,
|
||||
K_KP_NUMLOCK = 0xB8,
|
||||
K_KP_STAR = 0xB9,
|
||||
K_MOUSE1 = 0xBA,
|
||||
K_MOUSE2 = 0xBB,
|
||||
K_MOUSE3 = 0xBC,
|
||||
K_MOUSE4 = 0xBD,
|
||||
K_MOUSE5 = 0xBE,
|
||||
K_MWHEELDOWN = 0xBF,
|
||||
K_MWHEELUP = 0xC0
|
||||
};
|
||||
|
||||
struct KeyState
|
||||
{
|
||||
int down;
|
||||
int repeats;
|
||||
int binding;
|
||||
char pad[20];
|
||||
}; // size = 32
|
||||
|
||||
struct PlayerKeyState
|
||||
{
|
||||
bool overstrikeMode;
|
||||
int anyKeyDown;
|
||||
KeyState keys[256];
|
||||
};
|
||||
|
||||
struct AssetCache
|
||||
{
|
||||
uintptr_t whiteMaterial;
|
||||
uintptr_t cursor;
|
||||
uintptr_t blur;
|
||||
uintptr_t devFont; // TTF
|
||||
uintptr_t defaultFont; // TTF
|
||||
uintptr_t bigFont;
|
||||
uintptr_t smallFont;
|
||||
uintptr_t consoleFont;
|
||||
uintptr_t boldFont;
|
||||
uintptr_t textFont;
|
||||
uintptr_t extraBigFont;
|
||||
uintptr_t extraSmallFont;
|
||||
uintptr_t fxFont;
|
||||
};
|
||||
|
||||
struct sharedUiInfo_t
|
||||
{
|
||||
AssetCache assets;
|
||||
};
|
||||
|
||||
struct ScreenPlacement
|
||||
{
|
||||
vec2_t scaleVirtualToReal;
|
||||
vec2_t scaleVirtualToFull;
|
||||
vec2_t scaleRealToVirtual;
|
||||
vec2_t virtualViewableMin;
|
||||
vec2_t virtualViewableMax;
|
||||
vec2_t virtualTweakableMin;
|
||||
vec2_t virtualTweakableMax;
|
||||
vec2_t realViewportBase;
|
||||
vec2_t realViewportSize;
|
||||
vec2_t realViewportMid;
|
||||
vec2_t realViewableMin;
|
||||
vec2_t realViewableMax;
|
||||
vec2_t realTweakableMin;
|
||||
vec2_t realTweakableMax;
|
||||
vec2_t subScreen;
|
||||
float hudSplitscreenScale;
|
||||
};
|
||||
|
||||
enum itemTextStyle
|
||||
{
|
||||
ITEM_TEXTSTYLE_NORMAL = 0,
|
||||
ITEM_TEXTSTYLE_SHADOWED = 3,
|
||||
ITEM_TEXTSTYLE_SHADOWEDMORE = 6,
|
||||
ITEM_TEXTSTYLE_BORDERED = 7,
|
||||
ITEM_TEXTSTYLE_BORDEREDMORE = 8,
|
||||
ITEM_TEXTSTYLE_MONOSPACE = 128,
|
||||
ITEM_TEXTSTYLE_MONOSPACESHADOWED = 132,
|
||||
};
|
||||
|
||||
enum errorParm
|
||||
{
|
||||
ERR_FATAL = 0,
|
||||
ERR_DROP = 1,
|
||||
ERR_SERVERDISCONNECT = 2,
|
||||
ERR_DISCONNECT = 3,
|
||||
ERR_SCRIPT = 4,
|
||||
ERR_SCRIPT_DROP = 5,
|
||||
ERR_LOCALIZATION = 6,
|
||||
ERR_MAPLOADERRORSUMMARY = 7,
|
||||
};
|
||||
|
||||
enum dvarType_t
|
||||
{
|
||||
DVAR_TYPE_INVALID = 0x0,
|
||||
DVAR_TYPE_BOOL = 0x1,
|
||||
DVAR_TYPE_FLOAT = 0x2,
|
||||
DVAR_TYPE_FLOAT_2 = 0x3,
|
||||
DVAR_TYPE_FLOAT_3 = 0x4,
|
||||
DVAR_TYPE_FLOAT_4 = 0x5,
|
||||
DVAR_TYPE_INT = 0x6,
|
||||
DVAR_TYPE_ENUM = 0x7,
|
||||
DVAR_TYPE_STRING = 0x8,
|
||||
DVAR_TYPE_COLOR = 0x9,
|
||||
DVAR_TYPE_INT64 = 0xA,
|
||||
DVAR_TYPE_UINT64 = 0xB,
|
||||
DVAR_TYPE_LINEAR_COLOR_RGB = 0xC,
|
||||
DVAR_TYPE_COLOR_XYZ = 0xD,
|
||||
DVAR_TYPE_COLOR_LAB = 0xE,
|
||||
DVAR_TYPE_SESSIONMODE_BASE_DVAR = 0xF,
|
||||
DVAR_TYPE_COUNT = 0x10,
|
||||
};
|
||||
|
||||
enum dvarFlags_e
|
||||
{
|
||||
DVAR_NONE = 0,
|
||||
DVAR_ARCHIVE = 1 << 0,
|
||||
DVAR_USERINFO = 1 << 1,
|
||||
DVAR_SERVERINFO = 1 << 2,
|
||||
DVAR_SYSTEMINFO = 1 << 3,
|
||||
DVAR_LATCH = 1 << 4,
|
||||
DVAR_ROM = 1 << 5,
|
||||
DVAR_SAVED = 1 << 6,
|
||||
DVAR_INIT = 1 << 7,
|
||||
DVAR_CHEAT = 1 << 8,
|
||||
//DVAR_UNKNOWN = 1 << 9,
|
||||
DVAR_EXTERNAL = 1 << 10,
|
||||
//DVAR_UNKNOWN3x = 1 << 11-13,
|
||||
DVAR_SESSIONMODE = 1 << 15
|
||||
};
|
||||
|
||||
union DvarLimits
|
||||
{
|
||||
struct
|
||||
{
|
||||
int stringCount;
|
||||
const char** strings;
|
||||
} enumeration;
|
||||
|
||||
struct
|
||||
{
|
||||
int min;
|
||||
int max;
|
||||
} integer;
|
||||
|
||||
struct
|
||||
{
|
||||
int64_t min;
|
||||
int64_t max;
|
||||
} integer64;
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t min;
|
||||
uint64_t max;
|
||||
} unsignedInt64;
|
||||
|
||||
struct
|
||||
{
|
||||
float min;
|
||||
float max;
|
||||
} value;
|
||||
|
||||
struct
|
||||
{
|
||||
vec_t min;
|
||||
vec_t max;
|
||||
} vector;
|
||||
};
|
||||
|
||||
struct dvar_t;
|
||||
|
||||
struct DvarValue
|
||||
{
|
||||
union
|
||||
{
|
||||
bool enabled;
|
||||
int integer;
|
||||
uint32_t unsignedInt;
|
||||
int64_t integer64;
|
||||
uint64_t unsignedInt64;
|
||||
float value;
|
||||
vec4_t vector;
|
||||
const char* string;
|
||||
byte color[4];
|
||||
const dvar_t* indirect[3];
|
||||
} naked;
|
||||
|
||||
uint64_t encrypted;
|
||||
};
|
||||
|
||||
struct DvarData
|
||||
{
|
||||
DvarValue current;
|
||||
DvarValue latched;
|
||||
DvarValue reset;
|
||||
};
|
||||
|
||||
struct dvar_t
|
||||
{
|
||||
BO4_AssetRef_t name;
|
||||
char padding_unk1[8];
|
||||
DvarData* value;
|
||||
dvarType_t type;
|
||||
unsigned int flags;
|
||||
DvarLimits domain;
|
||||
char padding_unk2[8];
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SYMBOLS //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T>
|
||||
class symbol
|
||||
{
|
||||
public:
|
||||
symbol(const size_t address)
|
||||
: address_(reinterpret_cast<T*>(address))
|
||||
{
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return address_;
|
||||
}
|
||||
|
||||
operator T* () const
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
|
||||
private:
|
||||
T* address_;
|
||||
};
|
||||
|
||||
// Main Functions
|
||||
WEAK symbol<void(const char* file, int line, int code, const char* fmt, ...)> Com_Error_{ 0x14288B410_g };
|
||||
|
||||
// CMD
|
||||
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{ 0x143CDE880_g };
|
||||
|
||||
// Dvar
|
||||
WEAK symbol<void* (const char* dvarName)> Dvar_FindVar{ 0x143CEBE40_g };
|
||||
WEAK symbol<void* (void* dvarHash)> Dvar_FindVar_Hash{ 0x143CEBED0_g };
|
||||
|
||||
// Live Functions
|
||||
WEAK symbol<bool(uint64_t, int*)> Live_GetConnectivityInformation{ 0x1437FA460_g };
|
||||
|
||||
// Rendering Functions
|
||||
WEAK symbol<void(const char* text, int maxChars, void* font, float x, float y, float xScale, float yScale, float rotation, float* color, int style, int cursorPos, char cursor, float padding)> T8_AddBaseDrawTextCmd{ 0x143616B60_g };
|
||||
WEAK symbol<void(float x, float y, float w, float h, float, float, float, float, float* color, void* material)> R_AddCmdDrawStretchPic{ 0x143616790_g };
|
||||
|
||||
WEAK symbol<int(void* font)> R_TextHeight{ 0x1435B2350_g };
|
||||
WEAK symbol<int(void* font, float scale)> UI_TextHeight{ 0x143CD6560_g };
|
||||
|
||||
WEAK symbol<int(int localClientNum, const char* text, int maxChars, void* font)> R_TextWidth{ 0x1435B2530_g };
|
||||
WEAK symbol<int(int localClientNum, const char* text, int maxChars, void* font, float scale)> UI_TextWidth{ 0x143CD65B0_g };
|
||||
|
||||
WEAK symbol<ScreenPlacement* (int localClientNum)> ScrPlace_GetView{ 0x142876E70_g };
|
||||
|
||||
WEAK symbol<bool()> Com_IsInGame{ 0x14288FDB0_g };
|
||||
|
||||
WEAK symbol<int> keyCatchers{ 0x148A53F84_g };
|
||||
WEAK symbol<PlayerKeyState> playerKeys{ 0x148A3EF80_g };
|
||||
|
||||
WEAK symbol<sharedUiInfo_t> sharedUiInfo{ 0x14F956850_g };
|
||||
|
||||
|
||||
#define R_AddCmdDrawText(TXT, MC, F, X, Y, XS, YS, R, C, S) \
|
||||
T8_AddBaseDrawTextCmd(TXT, MC, F, X, Y, XS, YS, R, C, S, -1, 0, 0)
|
||||
|
||||
#define R_AddCmdDrawTextWithCursor(TXT, MC, F, X, Y, XS, YS, R, C, S, CP, CC) \
|
||||
T8_AddBaseDrawTextCmd(TXT, MC, F, X, Y, XS, YS, R, C, S, CP, CC, 0)
|
||||
|
||||
#define Com_Error(code, fmt, ...) \
|
||||
Com_Error_(__FILE__, __LINE__, code, fmt, ##__VA_ARGS__)
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions\discovery.hpp"
|
||||
|
||||
#define WEAK __declspec(selectany)
|
||||
|
||||
namespace game
|
||||
{
|
||||
extern std::string version_string;
|
||||
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
|
||||
struct T8_Hash_t
|
||||
{
|
||||
int64_t value;
|
||||
int64_t wtf;
|
||||
};
|
||||
|
||||
struct ScreenPlacement
|
||||
{
|
||||
vec2_t scaleVirtualToReal;
|
||||
vec2_t scaleVirtualToFull;
|
||||
vec2_t scaleRealToVirtual;
|
||||
vec2_t virtualViewableMin;
|
||||
vec2_t virtualViewableMax;
|
||||
vec2_t virtualTweakableMin;
|
||||
vec2_t virtualTweakableMax;
|
||||
vec2_t realViewportBase;
|
||||
vec2_t realViewportSize;
|
||||
vec2_t realViewportMid;
|
||||
vec2_t realViewableMin;
|
||||
vec2_t realViewableMax;
|
||||
vec2_t realTweakableMin;
|
||||
vec2_t realTweakableMax;
|
||||
vec2_t subScreen;
|
||||
float hudSplitscreenScale;
|
||||
};
|
||||
|
||||
enum itemTextStyle
|
||||
{
|
||||
ITEM_TEXTSTYLE_NORMAL = 0,
|
||||
ITEM_TEXTSTYLE_SHADOWED = 3,
|
||||
ITEM_TEXTSTYLE_SHADOWEDMORE = 6,
|
||||
ITEM_TEXTSTYLE_BORDERED = 7,
|
||||
ITEM_TEXTSTYLE_BORDEREDMORE = 8,
|
||||
ITEM_TEXTSTYLE_MONOSPACE = 128,
|
||||
ITEM_TEXTSTYLE_MONOSPACESHADOWED = 132,
|
||||
};
|
||||
|
||||
enum errorParm
|
||||
{
|
||||
ERR_FATAL = 0,
|
||||
ERR_DROP = 1,
|
||||
ERR_SERVERDISCONNECT = 2,
|
||||
ERR_DISCONNECT = 3,
|
||||
ERR_SCRIPT = 4,
|
||||
ERR_SCRIPT_DROP = 5,
|
||||
ERR_LOCALIZATION = 6,
|
||||
ERR_MAPLOADERRORSUMMARY = 7,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class symbol
|
||||
{
|
||||
public:
|
||||
symbol(const size_t address)
|
||||
: address_(reinterpret_cast<T*>(address))
|
||||
{
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return address_;
|
||||
}
|
||||
|
||||
operator T* () const
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
|
||||
private:
|
||||
T* address_;
|
||||
};
|
||||
|
||||
// Main Functions
|
||||
WEAK symbol<void(const char* file, int line, int code, const char* fmt, ...)> Com_Error_{ 0x14288B410_g };
|
||||
|
||||
// Live Functions
|
||||
WEAK symbol<bool(uint64_t, int*)> Live_GetConnectivityInformation{ 0x1437FA460_g };
|
||||
|
||||
// Rendering Functions
|
||||
WEAK symbol<void(const char* text, int maxChars, void* font, float x, float y, float xScale, float yScale, float rotation, float* color, int style, int cursorPos, char cursor, float padding)> T8_AddBaseDrawTextCmd{ 0x143616B60_g };
|
||||
WEAK symbol<void*(ScreenPlacement* scrPlace, int fontEnum, float scale)> UI_GetFontHandle{ 0x143CD0A30_g };
|
||||
WEAK symbol<int(void* font)> R_TextHeight{ 0x1435B2350_g }; // [BO4-BNET-2023]
|
||||
|
||||
WEAK symbol<ScreenPlacement* (int localClientNum)> ScrPlace_GetView{ 0x142876E70_g };
|
||||
|
||||
|
||||
#define R_AddCmdDrawText(TXT, MC, F, X, Y, XS, YS, R, C, S) \
|
||||
T8_AddBaseDrawTextCmd(TXT, MC, F, X, Y, XS, YS, R, C, S, -1, 0, 0)
|
||||
|
||||
#define R_AddCmdDrawTextWithCursor(TXT, MC, F, X, Y, XS, YS, R, C, S, CP, CC) \
|
||||
T8_AddBaseDrawTextCmd(TXT, MC, F, X, Y, XS, YS, R, C, S, CP, CC, 0)
|
||||
|
||||
#define Com_Error(code, fmt, ...) \
|
||||
Com_Error_(__FILE__, __LINE__, code, fmt, ##__VA_ARGS__)
|
||||
}
|
6510
source/proxy-dll/definitions/variables.cpp
Normal file
6510
source/proxy-dll/definitions/variables.cpp
Normal file
File diff suppressed because it is too large
Load Diff
27
source/proxy-dll/definitions/variables.hpp
Normal file
27
source/proxy-dll/definitions/variables.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
namespace fnv1a
|
||||
{
|
||||
uint64_t generate_hash(const char* string);
|
||||
}
|
||||
|
||||
namespace variables
|
||||
{
|
||||
struct varInfo
|
||||
{
|
||||
std::string name;
|
||||
const char* desc;
|
||||
uint64_t fnv1a;
|
||||
};
|
||||
|
||||
struct varEntry : varInfo
|
||||
{
|
||||
uintptr_t pointer = 0;
|
||||
};
|
||||
|
||||
extern std::vector<varEntry> dvars_record;
|
||||
extern std::vector<varEntry> commands_record;
|
||||
|
||||
std::vector<const char*> get_dvars_list();
|
||||
std::vector<const char*> get_commands_list();
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
#include <std_include.hpp>
|
||||
#include "objects.hpp"
|
||||
|
||||
#include "protobuf_helper.hpp"
|
||||
|
||||
#include "resource.hpp"
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <component/platform.hpp>
|
||||
#include "protobuf_helper.hpp"
|
||||
|
||||
#include "objects.hpp"
|
||||
|
||||
#include "resource.hpp"
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
#define PUBLISHER_OBJECTS_ENUMERATE_LPC_DIR
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
#include <picoproto.h>
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include "../objects.hpp"
|
||||
|
||||
#include <picoproto.h>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <component/platform.hpp>
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <component/platform.hpp>
|
||||
|
||||
|
92
source/proxy-dll/spoofer/spoofcall.cpp
Normal file
92
source/proxy-dll/spoofer/spoofcall.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <stack>
|
||||
|
||||
namespace spoofcall
|
||||
{
|
||||
void* callstack_proxy_addr{ nullptr };
|
||||
static thread_local const void* address_to_call{};
|
||||
|
||||
namespace
|
||||
{
|
||||
thread_local std::stack<uint64_t> address_stack{};
|
||||
|
||||
const void* get_address_to_call()
|
||||
{
|
||||
return address_to_call;
|
||||
}
|
||||
|
||||
void store_address(const uint64_t address)
|
||||
{
|
||||
address_stack.push(address);
|
||||
}
|
||||
|
||||
uint64_t get_stored_address()
|
||||
{
|
||||
const auto res = address_stack.top();
|
||||
address_stack.pop();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void callstack_return_stub(utils::hook::assembler& a)
|
||||
{
|
||||
a.push(rax);
|
||||
a.pushad64();
|
||||
|
||||
a.call_aligned(get_stored_address);
|
||||
a.mov(qword_ptr(rsp, 0x80), rax);
|
||||
|
||||
a.popad64();
|
||||
|
||||
a.add(rsp, 8);
|
||||
|
||||
a.jmp(qword_ptr(rsp, -8));
|
||||
}
|
||||
|
||||
uint64_t get_callstack_return_stub()
|
||||
{
|
||||
const auto placeholder = 0x1403CF1C6_g;
|
||||
|
||||
utils::hook::set<uint8_t>(placeholder - 2, 0xFF); // fakes a call
|
||||
utils::hook::nop(placeholder, 1);
|
||||
utils::hook::jump(placeholder + 1, utils::hook::assemble(callstack_return_stub));
|
||||
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
void callstack_stub(utils::hook::assembler& a)
|
||||
{
|
||||
a.push(rax);
|
||||
|
||||
a.pushad64();
|
||||
a.call_aligned(get_address_to_call);
|
||||
a.mov(qword_ptr(rsp, 0x80), rax);
|
||||
|
||||
a.mov(rcx, qword_ptr(rsp, 0x88));
|
||||
a.call_aligned(store_address);
|
||||
|
||||
a.mov(rax, get_callstack_return_stub());
|
||||
a.mov(qword_ptr(rsp, 0x88), rax);
|
||||
|
||||
a.popad64();
|
||||
|
||||
a.add(rsp, 8);
|
||||
|
||||
a.jmp(qword_ptr(rsp, -8));
|
||||
}
|
||||
}
|
||||
|
||||
void* get_spoofcall_proxy(const void* funcAddr)
|
||||
{
|
||||
static bool spoofer_initialized = false;
|
||||
if (!spoofer_initialized)
|
||||
{
|
||||
callstack_proxy_addr = utils::hook::assemble(callstack_stub);
|
||||
}
|
||||
|
||||
address_to_call = funcAddr;
|
||||
return callstack_proxy_addr;
|
||||
}
|
||||
}
|
18
source/proxy-dll/spoofer/spoofcall.hpp
Normal file
18
source/proxy-dll/spoofer/spoofcall.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
namespace spoofcall
|
||||
{
|
||||
void* get_spoofcall_proxy(const void* funcAddr);
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static T invoke(size_t funcAddr, Args ... args)
|
||||
{
|
||||
return static_cast<T(*)(Args ...)>(get_spoofcall_proxy(reinterpret_cast<void*>(funcAddr)))(args...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static T invoke(void* funcAddr, Args ... args)
|
||||
{
|
||||
return static_cast<T(*)(Args ...)>(get_spoofcall_proxy(funcAddr))(args...);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user