Refactor this (tekno gods dont sue please)

This commit is contained in:
6arelyFuture 2022-04-22 15:35:14 +02:00
parent 4e1dfcfc3c
commit b48ab294b8
Signed by: Future
GPG Key ID: FA77F074E98D98A5
46 changed files with 341 additions and 201 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "deps/minhook"]
path = deps/minhook
url = https://github.com/TsudaKageyu/minhook.git
[submodule "deps/GSL"]
path = deps/GSL
url = https://github.com/microsoft/GSL.git

1
deps/GSL vendored Submodule

@ -0,0 +1 @@
Subproject commit 2bfd4950802a223dde37a08a205812b6dfdfeb61

19
deps/premake/gsl.lua vendored Normal file
View File

@ -0,0 +1,19 @@
gsl = {
source = path.join(dependencies.basePath, "GSL")
}
function gsl.import()
gsl.includes()
end
function gsl.includes()
includedirs {
path.join(gsl.source, "include")
}
end
function gsl.project()
end
table.insert(dependencies, gsl)

View File

@ -34,7 +34,6 @@ workspace "mw3-server-freezer"
location "./build"
objdir "%{wks.location}/obj"
targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
targetname "%{prj.name}"
configurations {"Debug", "Release"}
@ -70,16 +69,36 @@ workspace "mw3-server-freezer"
defines {"DEBUG", "_DEBUG"}
filter {}
project "mw3-server-freezer"
project "common"
kind "StaticLib"
language "C++"
files {"./src/common/**.hpp", "./src/common/**.cpp"}
includedirs {"./src/common", "%{prj.location}/src"}
resincludedirs {"$(ProjectDir)src"}
dependencies.imports()
project "client"
kind "SharedLib"
language "C++"
pchheader "stdinc.hpp"
pchsource "src/stdinc.cpp"
targetname "mw3-server-freezer"
files { "./src/**.hpp", "./src/**.cpp" }
pchheader "std_include.hpp"
pchsource "src/client/std_include.cpp"
includedirs { "src" }
linkoptions {"/IGNORE:4254", "/PDBCompress"}
files {"./src/client/**.hpp", "./src/client/**.cpp"}
includedirs {"./src/client", "./src/common", "%{prj.location}/src"}
resincludedirs {"$(ProjectDir)src"}
links {"common"}
dependencies.imports()

View File

@ -1,6 +1,6 @@
#include <stdinc.hpp>
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <loader/component_loader.hpp>
#include <utils/hook.hpp>
#include <utils/string.hpp>
@ -49,7 +49,7 @@ __declspec(naked) void blind_eye_check_stub() {
retn
draw:
push 0x05AA529
push 0x5AA529
retn
}
}

View File

@ -1,6 +1,6 @@
#include <stdinc.hpp>
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <loader/component_loader.hpp>
#include <utils/string.hpp>
#include <utils/nt.hpp>
@ -84,8 +84,7 @@ public:
private:
static void add_commands_generic() {
// Will cause blue screen
add("quit_meme", utils::nt::raise_hard_exception);
add("quitMeme", utils::nt::raise_hard_exception);
add("quit", game::Com_Quit_f);
}
};

View File

@ -1,6 +1,5 @@
#include <stdinc.hpp>
#include <loader/component_loader.hpp>
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
namespace console {
namespace {

View File

@ -1,10 +1,11 @@
#include <stdinc.hpp>
#include "loader/component_loader.hpp"
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <utils/hook.hpp>
namespace dvar_patches {
void dvar_set_from_string_by_name_stub(const char*, const char*) {}
void dvar_set_from_string_by_name_stub(const char* /*dvarName*/,
const char* /*string*/) {}
class component final : public component_interface {
public:

View File

@ -1,6 +1,6 @@
#include <stdinc.hpp>
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <loader/component_loader.hpp>
#include <utils/hook.hpp>
#include "command.hpp"

View File

@ -1,6 +1,6 @@
#include <stdinc.hpp>
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <loader/component_loader.hpp>
#include <utils/hook.hpp>
#include "key_catcher.hpp"

View File

@ -1,6 +1,6 @@
#include <stdinc.hpp>
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <loader/component_loader.hpp>
#include <utils/hook.hpp>
#include <utils/string.hpp>
@ -18,6 +18,7 @@ bool handle_command(game::netadr_s* address, const char* command,
game::msg_t* msg) {
const auto cmd_string = utils::string::to_lower(command);
auto& callbacks = get_callbacks();
const auto handler = callbacks.find(cmd_string);
const auto offset = cmd_string.size() + 5;
@ -37,9 +38,7 @@ bool handle_command(game::netadr_s* address, const char* command,
int packet_interception_handler(game::netadr_s* from, const char* command,
game::msg_t* message) {
if (!handle_command(from, command, message)) {
return reinterpret_cast<int (*)(game::netadr_s*, const char*,
game::msg_t*)>(0x525730)(from, command,
message);
return utils::hook::invoke<int>(0x525730, from, command, message);
}
return TRUE;
@ -61,7 +60,7 @@ private:
static void add_network_commands() {
on_packet("naughty_reply",
[](const game::netadr_s&, const std::string_view&) {
command::execute("quit_meme");
command::execute("quitMeme");
});
}
};

View File

@ -0,0 +1,69 @@
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <utils/hook.hpp>
namespace remove_hooks {
namespace {
int msg_read_bits_compress_check_sv(const char* from, char* to, int size) {
static char buffer[0x8000];
if (size > 0x800) {
return 0;
}
size = game::MSG_ReadBitsCompress(from, buffer, size);
if (size > 0x800) {
return 0;
}
std::memcpy(to, buffer, size);
return size;
}
int msg_read_bits_compress_check_cl(const char* from, char* to, int size) {
static char buffer[0x100000];
if (size > 0x20000) {
return 0;
}
size = game::MSG_ReadBitsCompress(from, buffer, size);
if (size > 0x20000) {
return 0;
}
std::memcpy(to, buffer, size);
return size;
}
} // namespace
class component final : public component_interface {
public:
void post_start() override { remove_tekno_hooks(); }
void post_unpack() override {
utils::hook::call(0x4E3D42, msg_read_bits_compress_check_sv);
utils::hook::call(0x4A9F56, msg_read_bits_compress_check_cl);
}
private:
static void remove_tekno_hooks() {
utils::hook::set<BYTE>(0x4E3D42, 0xE8);
utils::hook::set<BYTE>(0x4E3D43, 0xA9);
utils::hook::set<BYTE>(0x4E3D44, 0x25);
utils::hook::set<BYTE>(0x4E3D45, 0xFE);
utils::hook::set<BYTE>(0x4E3D46, 0xFF);
utils::hook::set<BYTE>(0x6EA960, 0x55);
utils::hook::set<BYTE>(0x6EA961, 0x8B);
utils::hook::set<BYTE>(0x6EA962, 0xEC);
utils::hook::set<BYTE>(0x6EA963, 0x81);
utils::hook::set<BYTE>(0x6EA964, 0xEC);
}
};
} // namespace remove_hooks
REGISTER_COMPONENT(remove_hooks::component)

View File

@ -1,14 +1,13 @@
#include <stdinc.hpp>
#include <loader/component_loader.hpp>
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <utils/concurrency.hpp>
#include <utils/hook.hpp>
#include <utils/thread.hpp>
#include "scheduler.hpp"
namespace scheduler {
std::thread::id async_thread_id;
namespace {
struct task {
std::function<bool()> handler{};
@ -74,6 +73,7 @@ private:
}
};
volatile bool kill = false;
std::thread thread;
task_pipeline pipelines[pipeline::count];
@ -82,10 +82,15 @@ void execute(const pipeline type) {
pipelines[type].execute();
}
void cl_frame_stub(game::LocalClientNum_t local) {
reinterpret_cast<void (*)(game::LocalClientNum_t)>(0x41C9B0)(local);
void cl_frame_stub(game::LocalClientNum_t localClientNum) {
utils::hook::invoke<void>(0x41C9B0, localClientNum);
execute(pipeline::client);
}
void main_frame_stub() {
utils::hook::invoke<void>(0x4E46A0);
execute(pipeline::main);
}
} // namespace
void clear_tasks(const pipeline type) { return pipelines[type].clear(); }
@ -127,16 +132,22 @@ unsigned int thread_id;
class component final : public component_interface {
public:
void post_unpack() override {
thread = std::thread([]() {
while (true) {
thread = utils::thread::create_named_thread("Async Scheduler", []() {
while (!kill) {
execute(pipeline::async);
std::this_thread::sleep_for(10ms);
}
});
async_thread_id = thread.get_id();
utils::hook::call(0x4E4A0D, cl_frame_stub);
utils::hook::call(0x543B0E, main_frame_stub);
}
void pre_destroy() override {
kill = true;
if (thread.joinable()) {
thread.join();
}
}
};
} // namespace scheduler

View File

@ -1,11 +1,10 @@
#pragma once
namespace scheduler {
extern std::thread::id async_thread_id;
enum pipeline {
client,
async,
main,
count,
};

View File

@ -1,4 +1,4 @@
#include <stdinc.hpp>
#include "std_include.hpp"
#include "loader/component_loader.hpp"
BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call,
@ -6,6 +6,7 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call,
) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
std::srand(uint32_t(time(nullptr)));
component_loader::post_start();
component_loader::post_unpack();
}

3
src/client/game/game.cpp Normal file
View File

@ -0,0 +1,3 @@
#include <std_include.hpp>
namespace game {}

View File

@ -49,7 +49,6 @@ WEAK symbol<bool(netsrc_t, netadr_s dest, const char* message)>
NET_OutOfBandPrint{0x496230};
WEAK symbol<bool(netsrc_t, netadr_s dest, unsigned char* data, int size)>
NET_OutOfBandData{0x4639C0};
WEAK symbol<int(unsigned int, void*, netadr_s)> dwSendTo{0x673B20};
WEAK symbol<void(netadr_s*, sockaddr*)> NetadrToSockadr{0x48B460};
WEAK symbol<int(const char* serverName, netadr_s serverRemote)> NET_StringToAdr{
0x4E09A0};
@ -63,6 +62,9 @@ WEAK symbol<void(const msg_t*, int)> MSG_WriteShort{0x4ACD80};
WEAK symbol<void(const msg_t*, const void*, int)> MSG_WriteData{0x4F8C20};
WEAK symbol<void(int, const char*)> CL_AddReliableCommand{0x4EE3A0};
WEAK symbol<int(const char* from, char* to, int size)> MSG_ReadBitsCompress{
0x4C62F0};
WEAK symbol<unsigned __int64()> LiveSteam_GetUid{0x4A4050};
WEAK symbol<int(unsigned __int64, const void*, unsigned int)>
LiveSteam_Client_ConnectToSteamServer{0x4D6980};
@ -75,5 +77,4 @@ WEAK symbol<HWND> g_wv_hWnd{0x5A86AF0};
WEAK symbol<HWND> s_wcd_hWnd{0x5A86330};
WEAK symbol<int> serverId{0xFF5058};
WEAK symbol<connstate_t> connectionState{0x1060214};
WEAK symbol<dvar_t> cl_paused{0x1CE6190};
} // namespace game

View File

@ -1,4 +1,4 @@
#include <stdinc.hpp>
#include <std_include.hpp>
#include "component_loader.hpp"
void component_loader::register_component(

View File

@ -0,0 +1 @@
#include "std_include.hpp"

View File

@ -5,7 +5,7 @@
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>
#include <windows.h>
#include <Windows.h>
#include <algorithm>
#include <cassert>

View File

@ -1,5 +1,3 @@
#include <stdinc.hpp>
#include "hook.hpp"
#include "string.hpp"

View File

@ -1,5 +1,3 @@
#include <stdinc.hpp>
#include "info_string.hpp"
#include "string.hpp"
@ -38,13 +36,12 @@ void info_string::parse(std::string buffer) {
std::string info_string::build() const {
std::string info_string;
for (auto i = this->key_value_pairs_.begin();
i != this->key_value_pairs_.end(); ++i) {
for (const auto& [key, val] : this->key_value_pairs_) {
info_string.append("\\");
info_string.append(i->first); // Key
info_string.append(key);
info_string.append("\\");
info_string.append(i->second); // Value
info_string.append(val);
}
return info_string;

View File

@ -1,5 +1,3 @@
#include <stdinc.hpp>
#include "memory.hpp"
#include "nt.hpp"
@ -50,7 +48,7 @@ char* memory::allocator::duplicate_string(const std::string& string) {
return data;
}
void* memory::allocate(const size_t length) { return calloc(length, 1); }
void* memory::allocate(const size_t length) { return std::calloc(length, 1); }
char* memory::duplicate_string(const std::string& string) {
const auto new_string = allocate_array<char>(string.size() + 1);
@ -60,7 +58,7 @@ char* memory::duplicate_string(const std::string& string) {
void memory::free(void* data) {
if (data) {
::free(data);
std::free(data);
}
}

View File

@ -1,5 +1,3 @@
#include <stdinc.hpp>
#include "nt.hpp"
namespace utils::nt {

View File

@ -1,7 +1,6 @@
#include <stdinc.hpp>
#include "signature.hpp"
#include <thread>
#include <mutex>
#include <intrin.h>

View File

@ -1,9 +1,7 @@
#include <stdinc.hpp>
#include "string.hpp"
#include <algorithm>
#include <cstdarg>
#include <sstream>
#include <cstdarg>
#include <algorithm>
#include "nt.hpp"

View File

@ -1,6 +1,10 @@
#pragma once
#include "memory.hpp"
#ifndef ARRAYSIZE
template <class Type, size_t n> size_t ARRAYSIZE(Type (&)[n]) { return n; }
#endif
namespace utils::string {
template <size_t Buffers, size_t MinBufferSize> class va_provider final {
public:
@ -19,7 +23,7 @@ public:
while (true) {
const int res =
vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
_vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
if (res > 0)
break; // Success
if (res == 0)

105
src/common/utils/thread.cpp Normal file
View File

@ -0,0 +1,105 @@
#include <thread>
#include "nt.hpp"
#include "string.hpp"
#include "thread.hpp"
#include <TlHelp32.h>
#include <gsl/gsl>
namespace utils::thread {
bool set_name(const HANDLE t, const std::string& name) {
const nt::library kernel32("kernel32.dll");
if (!kernel32) {
return false;
}
const auto set_description =
kernel32.get_proc<HRESULT(WINAPI*)(HANDLE, PCWSTR)>(
"SetThreadDescription");
if (!set_description) {
return false;
}
return SUCCEEDED(set_description(t, string::convert(name).data()));
}
bool set_name(const DWORD id, const std::string& name) {
auto* const t = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, id);
if (!t)
return false;
const auto _ = gsl::finally([t]() { CloseHandle(t); });
return set_name(t, name);
}
bool set_name(std::thread& t, const std::string& name) {
return set_name(t.native_handle(), name);
}
bool set_name(const std::string& name) {
return set_name(GetCurrentThread(), name);
}
std::vector<DWORD> get_thread_ids() {
auto* const h =
CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());
if (h == INVALID_HANDLE_VALUE) {
return {};
}
const auto _ = gsl::finally([h]() { CloseHandle(h); });
THREADENTRY32 entry{};
entry.dwSize = sizeof(entry);
if (!Thread32First(h, &entry)) {
return {};
}
std::vector<DWORD> ids;
do {
const auto check_size =
entry.dwSize < FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) +
sizeof(entry.th32OwnerProcessID);
entry.dwSize = sizeof(entry);
if (check_size && entry.th32OwnerProcessID == GetCurrentProcessId()) {
ids.emplace_back(entry.th32ThreadID);
}
} while (Thread32Next(h, &entry));
return ids;
}
void for_each_thread(const std::function<void(HANDLE)>& callback) {
const auto ids = get_thread_ids();
for (const auto& id : ids) {
auto* const thread = OpenThread(THREAD_ALL_ACCESS, FALSE, id);
if (thread != nullptr) {
const auto _ = gsl::finally([thread]() { CloseHandle(thread); });
callback(thread);
}
}
}
void suspend_other_threads() {
for_each_thread([](const HANDLE thread) {
if (GetThreadId(thread) != GetCurrentThreadId()) {
SuspendThread(thread);
}
});
}
void resume_other_threads() {
for_each_thread([](const HANDLE thread) {
if (GetThreadId(thread) != GetCurrentThreadId()) {
ResumeThread(thread);
}
});
}
} // namespace utils::thread

View File

@ -0,0 +1,21 @@
#pragma once
namespace utils::thread {
bool set_name(HANDLE t, const std::string& name);
bool set_name(DWORD id, const std::string& name);
bool set_name(std::thread& t, const std::string& name);
bool set_name(const std::string& name);
template <typename... Args>
std::thread create_named_thread(const std::string& name, Args&&... args) {
auto t = std::thread(std::forward<Args>(args)...);
set_name(t, name);
return t;
}
std::vector<DWORD> get_thread_ids();
void for_each_thread(const std::function<void(HANDLE)>& callback);
void suspend_other_threads();
void resume_other_threads();
} // namespace utils::thread

View File

@ -1,28 +0,0 @@
#include <stdinc.hpp>
#include <loader/component_loader.hpp>
#include <utils/hook.hpp>
namespace remove_hooks {
class component final : public component_interface {
public:
void post_unpack() override { remove_tekno_hooks(); }
private:
static void remove_tekno_hooks() {
utils::hook::set<BYTE>(0x4E3D42, 0xE8);
utils::hook::set<BYTE>(0x4E3D43, 0xA9);
utils::hook::set<BYTE>(0x4E3D44, 0x25);
utils::hook::set<BYTE>(0x4E3D45, 0xFE);
utils::hook::set<BYTE>(0x4E3D46, 0xFF);
utils::hook::set<BYTE>(0x6EA960, 0x55);
utils::hook::set<BYTE>(0x6EA961, 0x8B);
utils::hook::set<BYTE>(0x6EA962, 0xEC);
utils::hook::set<BYTE>(0x6EA963, 0x81);
utils::hook::set<BYTE>(0x6EA964, 0xEC);
}
};
} // namespace remove_hooks
REGISTER_COMPONENT(remove_hooks::component)

View File

@ -1,71 +0,0 @@
#include <stdinc.hpp>
#include <loader/component_loader.hpp>
#include <utils/hook.hpp>
#include <utils/info_string.hpp>
#include <utils/string.hpp>
#include "scheduler.hpp"
namespace user_info {
namespace {
int a1 = 0;
void cl_check_user_info(int _a1, const int force) {
a1 = _a1;
if (*game::connectionState <= game::connstate_t::CA_CHALLENGING)
return;
if (game::cl_paused->current.enabled && !force)
return;
const std::string info_string = game::Dvar_InfoString(_a1, 0x200);
utils::info_string info(info_string);
const auto color_code = std::rand() % 10;
char name[32];
const auto numbers = std::to_string(std::rand() % 10000);
_snprintf_s(name, _TRUNCATE, "^%d%s", color_code, numbers.data());
info.set("name", name);
info.set("ec_usingTag", "1");
info.set("ec_TagText", utils::string::va("^%dGG", color_code));
const auto big_title = std::to_string(std::rand() % 512);
info.set("ec_TitleBg", big_title);
game::CL_AddReliableCommand(
_a1, utils::string::va("userinfo \"%s\"", info.build().data()));
}
__declspec(naked) void cl_check_user_info_stub() {
__asm {
pushad
push 0
push esi
call cl_check_user_info
add esp, 8
popad
ret
}
}
} // namespace
class component final : public component_interface {
public:
void post_unpack() override {
utils::hook::call(0x41CA53, cl_check_user_info_stub);
scheduler::loop([] { cl_check_user_info(a1, TRUE); },
scheduler::pipeline::client, 4s);
}
};
} // namespace user_info
REGISTER_COMPONENT(user_info::component)

View File

@ -1,3 +0,0 @@
#include <stdinc.hpp>
namespace game {}

View File

@ -1 +0,0 @@
#include <stdinc.hpp>