This commit is contained in:
6arelyFuture 2022-03-22 23:41:36 +00:00
parent 1dd227baa5
commit 8a2df0a179
No known key found for this signature in database
GPG Key ID: E883E2BC9657D955
42 changed files with 2495 additions and 3388 deletions

12
.clang-format Normal file
View File

@ -0,0 +1,12 @@

---
Language: Cpp
BasedOnStyle: LLVM
DerivePointerAlignment: false
PointerAlignment: Left
SortIncludes: false
# Regroup causes unnecessary noise due to clang-format bug.
IncludeBlocks: Preserve
---

55
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: Build
on:
push:
branches:
- "*"
pull_request:
branches:
- "*"
types: [opened, synchronize, reopened]
jobs:
build:
name: Build binaries
runs-on: windows-2022
strategy:
matrix:
configuration:
- Debug
- Release
steps:
- name: Wait for previous workflows
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
uses: softprops/turnstyle@v1
with:
poll-interval-seconds: 10
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check out files
uses: actions/checkout@v3
with:
submodules: true
fetch-depth: 0
# NOTE - If LFS ever starts getting used during builds, switch this to true!
lfs: false
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1
- name: Generate project files
run: tools/premake5 vs2022
- name: Set up problem matching
uses: ammaraskar/msvc-problem-matcher@master
- name: Build ${{matrix.configuration}} binaries
run: msbuild /m /v:minimal /p:Configuration=${{matrix.configuration}} /p:Platform=Win32 build/mw3-server-freezer.sln
- name: Upload ${{matrix.configuration}} binaries
uses: actions/upload-artifact@v2
with:
name: ${{matrix.configuration}} binaries
path: |
build/bin/Win32/${{matrix.configuration}}/mw3-server-freezer.dll
build/bin/Win32/${{matrix.configuration}}/mw3-server-freezer.pdb

View File

@ -0,0 +1,20 @@
name: clang-format Check
on:
push:
branches:
- "*"
pull_request:
branches:
- "*"
types: [opened, synchronize, reopened]
jobs:
formatting-check:
name: Formatting Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run clang-format style check for C/C++/Protobuf programs.
uses: jidicula/clang-format-action@v4.6.2
with:
clang-format-version: '14'
check-path: 'src'

View File

@ -14,8 +14,7 @@ If you think your server is vulnerable you should seek help in the appropriate d
## Compile from source ## Compile from source
- Clone the Git repo. Do NOT download it as ZIP, that won't work. - Clone the Git repo. Do NOT download it as ZIP, that won't work.
- Update the submodules and run `premake5 vs2019` or simply use the delivered `generate.bat`. - Update the submodules and run `premake5 vs2022` or simply use the delivered `generate.bat`.
- Visual Studio Properties -> Linker -> Input -> Module Definition File -> add module.def located in src folder
- Build via solution file in `build\mw3-server-freezer.sln`. - Build via solution file in `build\mw3-server-freezer.sln`.
## Commands ## Commands

View File

@ -1,4 +1,4 @@
@echo off @echo off
echo Updating submodules... echo Updating submodules...
call git submodule update --init --recursive call git submodule update --init --recursive
call tools\premake5 %* vs2019 call tools\premake5 %* vs2022

View File

@ -36,36 +36,39 @@ workspace "mw3-server-freezer"
targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}" targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
targetname "%{prj.name}" targetname "%{prj.name}"
language "C++"
architecture "x86"
platforms "x86"
buildoptions "/std:c++latest"
systemversion "latest"
flags { "NoIncrementalLink", "NoMinimalRebuild", "MultiProcessorCompile", "No64BitChecks" }
configurations {"Debug", "Release"} configurations {"Debug", "Release"}
language "C++"
cppdialect "C++20"
architecture "x86"
platforms "Win32"
systemversion "latest"
symbols "On" symbols "On"
staticruntime "On" staticruntime "On"
editandcontinue "Off" editandcontinue "Off"
warnings "Extra" warnings "Extra"
characterset "ASCII" characterset "ASCII"
configuration "Release" flags {"NoIncrementalLink", "NoMinimalRebuild", "MultiProcessorCompile", "No64BitChecks"}
filter "platforms:Win*"
defines {"_WINDOWS", "WIN32"}
filter {}
filter "configurations:Release"
optimize "Size" optimize "Size"
defines {"NDEBUG"} defines {"NDEBUG"}
flags {"FatalCompileWarnings"} flags {"FatalCompileWarnings"}
buildoptions {"/GL"} buildoptions {"/GL"}
linkoptions { "/IGNORE:4702", "/LTCG" } linkoptions { "/IGNORE:4702", "/LTCG" }
configuration {} filter {}
configuration "Debug" filter "configurations:Debug"
optimize "Debug" optimize "Debug"
defines {"DEBUG", "_DEBUG"} defines {"DEBUG", "_DEBUG"}
configuration {} filter {}
project "mw3-server-freezer" project "mw3-server-freezer"
kind "SharedLib" kind "SharedLib"

View File

@ -13,8 +13,7 @@ namespace cheats
__declspec(naked) void draw_red_box_stub() __declspec(naked) void draw_red_box_stub()
{ {
__asm __asm {
{
push eax push eax
mov eax, cl_EnableCheats mov eax, cl_EnableCheats
cmp byte ptr [eax + 12], 1 cmp byte ptr [eax + 12], 1
@ -35,8 +34,7 @@ namespace cheats
__declspec(naked) void blind_eye_check_stub() __declspec(naked) void blind_eye_check_stub()
{ {
__asm __asm {
{
push eax push eax
mov eax, cl_EnableCheats mov eax, cl_EnableCheats
cmp byte ptr [eax + 12], 1 cmp byte ptr [eax + 12], 1
@ -45,11 +43,11 @@ namespace cheats
je draw je draw
test byte ptr [esi], 0x20 test byte ptr [esi], 0x20
jnz skipBecauseBlindeye jnz skip_because_blindeye
jmp draw jmp draw
skipBecauseBlindeye: skip_because_blindeye:
push 0x5AA5A2 push 0x5AA5A2
retn retn
@ -64,7 +62,8 @@ namespace cheats
public: public:
void post_unpack() override void post_unpack() override
{ {
cl_EnableCheats = game::Dvar_RegisterBool("cl_EnableCheats", false, game::DVAR_FLAG_NONE, "Enable FoF wallhack"); cl_EnableCheats = game::Dvar_RegisterBool(
"cl_EnableCheats", false, game::DVAR_NONE, "Enable FoF wallhack");
utils::hook::jump(0x430561, draw_red_box_stub); utils::hook::jump(0x430561, draw_red_box_stub);
utils::hook::nop(0x430566, 2); utils::hook::nop(0x430566, 2);
@ -77,27 +76,38 @@ namespace cheats
private: private:
static void add_cheat_commands() static void add_cheat_commands()
{ {
key_catcher::on_key_press("Z", [](const game::LocalClientNum_t&) key_catcher::on_key_press(
"Z",
[]([[maybe_unused]] const game::LocalClientNum_t& local_client)
{ {
game::Dvar_SetBool(cl_EnableCheats, true); game::Dvar_SetBool(cl_EnableCheats, true);
}); });
key_catcher::on_key_press("X", [](const game::LocalClientNum_t&) key_catcher::on_key_press(
"X",
[]([[maybe_unused]] const game::LocalClientNum_t& local_client)
{ {
game::Dvar_SetBool(cl_EnableCheats, false); game::Dvar_SetBool(cl_EnableCheats, false);
}); });
key_catcher::on_key_press("Y", [](const game::LocalClientNum_t&) key_catcher::on_key_press(
"Y",
[]([[maybe_unused]] const game::LocalClientNum_t& local_client)
{ {
command::execute(utils::string::va("cmd mr %i 2 allies", *game::serverId), true); command::execute(
utils::string::va("cmd mr %i 2 allies", *game::serverId), true);
}); });
key_catcher::on_key_press("8", [](const game::LocalClientNum_t&) key_catcher::on_key_press(
"8",
[]([[maybe_unused]] const game::LocalClientNum_t& local_client)
{ {
command::execute(utils::string::va("cmd mr %i -1 endround", *game::serverId), true); command::execute(
utils::string::va("cmd mr %i -1 endround", *game::serverId),
true);
}); });
} }
}; };
} } // namespace cheats
REGISTER_COMPONENT(cheats::component) REGISTER_COMPONENT(cheats::component)

View File

@ -6,6 +6,8 @@
#include "command.hpp" #include "command.hpp"
constexpr auto CMD_MAX_NESTING = 8;
namespace command namespace command
{ {
std::unordered_map<std::string, std::function<void(params&)>> handlers; std::unordered_map<std::string, std::function<void(params&)>> handlers;
@ -15,7 +17,7 @@ namespace command
params params = {}; params params = {};
const auto command = utils::string::to_lower(params[0]); const auto command = utils::string::to_lower(params[0]);
if (handlers.find(command) != handlers.end()) if (!handlers.contains(command))
{ {
handlers[command](params); handlers[command](params);
} }
@ -24,6 +26,7 @@ namespace command
params::params() params::params()
: nesting_(game::cmd_args->nesting) : nesting_(game::cmd_args->nesting)
{ {
assert(game::cmd_args->nesting < CMD_MAX_NESTING);
} }
int params::size() const int params::size() const
@ -50,19 +53,23 @@ namespace command
if (i > index) result.append(" "); if (i > index) result.append(" ");
result.append(this->get(i)); result.append(this->get(i));
} }
return result; return result;
} }
void add_raw(const char* name, void (*callback)()) void add_raw(const char* name, void (*callback)())
{ {
game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate<game::cmd_function_t>()); game::Cmd_AddCommandInternal(
name,
callback,
utils::memory::get_allocator()->allocate<game::cmd_function_t>());
} }
void add(const char* name, const std::function<void(const params&)>& callback) void add(const char* name, const std::function<void(const params&)>& callback)
{ {
const auto command = utils::string::to_lower(name); const auto command = utils::string::to_lower(name);
if (handlers.find(command) == handlers.end()) if (!handlers.contains(command))
{ {
add_raw(name, main_handler); add_raw(name, main_handler);
} }
@ -70,26 +77,13 @@ namespace command
handlers[command] = callback; handlers[command] = callback;
} }
std::vector<std::string> script_commands; void add(const char* name, const std::function<void()>& callback)
utils::memory::allocator allocator;
void add_script_command(const std::string& name, const std::function<void(const params&)>& callback)
{ {
script_commands.push_back(name); add(name,
const auto _name = allocator.duplicate_string(name); [callback](const params&)
add(_name, callback);
}
void clear_script_commands()
{ {
for (const auto& name : script_commands) callback();
{ });
handlers.erase(name);
game::Cmd_RemoveCommand(name.data());
}
allocator.clear();
script_commands.clear();
} }
void execute(std::string command, const bool sync) void execute(std::string command, const bool sync)
@ -98,11 +92,13 @@ namespace command
if (sync) if (sync)
{ {
game::Cmd_ExecuteSingleCommand(game::LocalClientNum_t::LOCAL_CLIENT_0, 0, command.data()); game::Cmd_ExecuteSingleCommand(
game::LocalClientNum_t::LOCAL_CLIENT_0, 0, command.data());
} }
else else
{ {
game::Cbuf_AddText(game::LocalClientNum_t::LOCAL_CLIENT_0, command.data()); game::Cbuf_AddText(game::LocalClientNum_t::LOCAL_CLIENT_0,
command.data());
} }
} }
@ -114,26 +110,15 @@ namespace command
add_commands_generic(); add_commands_generic();
} }
void pre_destroy() override
{
clear_script_commands();
}
private: private:
static void add_commands_generic() static void add_commands_generic()
{
add("quit_meme", [](const params&)
{ {
// Will cause blue screen // Will cause blue screen
utils::nt::raise_hard_exception(); add("quit_meme", utils::nt::raise_hard_exception);
});
add("dia_quit", [](const params&) add("quit", game::Com_Quit_f);
{
game::Com_Quit_f();
});
} }
}; };
} } // namespace command
REGISTER_COMPONENT(command::component) REGISTER_COMPONENT(command::component)

View File

@ -7,9 +7,9 @@ namespace command
public: public:
params(); params();
int size() const; [[nodiscard]] int size() const;
const char* get(int index) const; [[nodiscard]] const char* get(int index) const;
std::string join(int index) const; [[nodiscard]] std::string join(int index) const;
const char* operator[](const int index) const const char* operator[](const int index) const
{ {
@ -21,10 +21,9 @@ namespace command
}; };
void add_raw(const char* name, void (*callback)()); void add_raw(const char* name, void (*callback)());
void add(const char* name, const std::function<void(const params&)>& callback); void add(const char* name,
const std::function<void(const params&)>& callback);
void add_script_command(const std::string& name, const std::function<void(const params&)>& callback); void add(const char* name, const std::function<void()>& callback);
void clear_script_commands();
void execute(std::string command, bool sync = false); void execute(std::string command, bool sync = false);
} } // namespace command

View File

@ -17,11 +17,13 @@ namespace console
void console_unlock() void console_unlock()
{ {
const auto callBack = SetWindowLongA(*game::g_wv_hWnd, const auto callback =
GWL_WNDPROC, reinterpret_cast<LONG>(sys_start_console)); SetWindowLongA(*game::g_wv_hWnd,
GWL_WNDPROC,
reinterpret_cast<LONG>(sys_start_console));
SendMessage(*game::g_wv_hWnd, WM_QUIT, 0, 0); SendMessageA(*game::g_wv_hWnd, WM_QUIT, 0, 0);
SetWindowLongA(*game::g_wv_hWnd, GWL_WNDPROC, callBack); SetWindowLongA(*game::g_wv_hWnd, GWL_WNDPROC, callback);
} }
void show_console() void show_console()
@ -31,14 +33,15 @@ namespace console
ShowWindow(*game::s_wcd_hWnd, SW_SHOW); ShowWindow(*game::s_wcd_hWnd, SW_SHOW);
} }
} }
} } // namespace
class component final : public component_interface class component final : public component_interface
{ {
public: public:
void post_unpack() override void post_unpack() override
{ {
thread = std::thread([]() thread = std::thread(
[]()
{ {
console_unlock(); console_unlock();
show_console(); show_console();
@ -47,6 +50,6 @@ namespace console
async_thread_id = thread.get_id(); async_thread_id = thread.get_id();
} }
}; };
} } // namespace console
REGISTER_COMPONENT(console::component) REGISTER_COMPONENT(console::component)

View File

@ -1,14 +1,11 @@
#include <stdinc.hpp> #include <stdinc.hpp>
#include "loader/component_loader.hpp"
#include <loader/component_loader.hpp>
#include <utils/hook.hpp> #include <utils/hook.hpp>
namespace dvar_patches 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*, const char*) {}
{
return;
}
class component final : public component_interface class component final : public component_interface
{ {
@ -18,6 +15,6 @@ namespace dvar_patches
utils::hook::call(0x59C0EF, dvar_set_from_string_by_name_stub); utils::hook::call(0x59C0EF, dvar_set_from_string_by_name_stub);
} }
}; };
} } // namespace dvar_patches
REGISTER_COMPONENT(dvar_patches::component) REGISTER_COMPONENT(dvar_patches::component)

View File

@ -12,42 +12,40 @@ namespace exploit
/* /*
* void CL_Netchan_Transmit(netchan_t* chan, unsigned char* data, int a3) * void CL_Netchan_Transmit(netchan_t* chan, unsigned char* data, int a3)
* A brief description of data: the first few bytes contain information from clientConnection_t structure * A brief description of data: the first few bytes contain information from
* Offset 0: ServerID Size : 1 * clientConnection_t structure Offset 0: ServerID Size : 1 Offset 1:
* Offset 1: serverMessageSequence Size: 4 * serverMessageSequence Size: 4 Offset 5: serverCommandSequence Size: 4 One
* Offset 5: serverCommandSequence Size: 4 * clean way of sending invalid data to the server is to hook the functions
* One clean way of sending invalid data to the server is to hook the functions that write the info to the packet * that write the info to the packet Credit:
* Credit: https://stackoverflow.com/questions/58981714/how-do-i-change-the-value-of-a-single-byte-in-a-uint32-t-variable * https://stackoverflow.com/questions/58981714/how-do-i-change-the-value-of-a-single-byte-in-a-uint32-t-variable
*/ */
void write_message_sequence(game::msg_t* msg, int data) void write_message_sequence(game::msg_t* msg, int data)
{ {
if (msg->maxsize - msg->cursize < sizeof(int)) if (msg->maxsize - static_cast<unsigned int>(msg->cursize) < sizeof(int))
{ {
msg->overflowed = TRUE; msg->overflowed = TRUE;
return; return;
} }
if (cl_exploit->current.enabled) if (cl_exploit->current.enabled) data = (data & 0xFFFFFF00) | 0xAAu;
data = (data & 0xFFFFFF00) | 0xAAu;
auto dest = reinterpret_cast<int*>(&msg->data[msg->cursize]); auto* dest = reinterpret_cast<int*>(&msg->data[msg->cursize]);
*dest = data; *dest = data;
msg->cursize += sizeof(int); msg->cursize += sizeof(int);
} }
void write_command_sequence(game::msg_t* msg, int data) void write_command_sequence(game::msg_t* msg, int data)
{ {
if (msg->maxsize - msg->cursize < sizeof(int)) if (msg->maxsize - static_cast<unsigned int>(msg->cursize) < sizeof(int))
{ {
msg->overflowed = TRUE; msg->overflowed = TRUE;
return; return;
} }
if (cl_exploit->current.enabled) if (cl_exploit->current.enabled) data = (data & 0x00FFFFFF) | (0x80u << 24);
data = (data & 0x00FFFFFF) | (0x80u << 24);
auto dest = reinterpret_cast<int*>(&msg->data[msg->cursize]); auto* dest = reinterpret_cast<int*>(&msg->data[msg->cursize]);
*dest = data; *dest = data;
msg->cursize += sizeof(int); msg->cursize += sizeof(int);
} }
@ -57,33 +55,36 @@ namespace exploit
public: public:
void post_unpack() override void post_unpack() override
{ {
cl_exploit = game::Dvar_RegisterBool("cl_exploit", false, game::DVAR_FLAG_NONE, "Enable server freezer"); cl_exploit = game::Dvar_RegisterBool(
"cl_exploit", false, game::DVAR_NONE, "Enable server freezer");
add_exploit_commands(); add_exploit_commands();
add_key_hooks(); add_key_hooks();
utils::hook::call(0x420B76, write_message_sequence); utils::hook::call(0x420B76, write_message_sequence);
utils::hook::call(0x420B86, write_command_sequence); utils::hook::call(0x420B86, write_command_sequence);
// Increase size;
utils::hook::set<DWORD>(0x4639C7, 0x1FFFCu);
utils::hook::set<DWORD>(0x496237, 0x1FFFCu);
} }
private: private:
static void add_key_hooks() static void add_key_hooks()
{ {
key_catcher::on_key_press("O", [](const game::LocalClientNum_t&) key_catcher::on_key_press(
"O",
[]([[maybe_unused]] const game::LocalClientNum_t& local_client)
{ {
command::execute("exploit"); command::execute("exploit");
}); });
key_catcher::on_key_press("L", [](const game::LocalClientNum_t&) key_catcher::on_key_press(
"L",
[]([[maybe_unused]] const game::LocalClientNum_t& local_client)
{ {
command::execute("undo_exploit"); command::execute("undo_exploit");
}); });
key_catcher::on_key_press("K", [](const game::LocalClientNum_t&) key_catcher::on_key_press(
"K",
[]([[maybe_unused]] const game::LocalClientNum_t& local_client)
{ {
command::execute("disconnect"); command::execute("disconnect");
}); });
@ -91,17 +92,21 @@ namespace exploit
static void add_exploit_commands() static void add_exploit_commands()
{ {
command::add("exploit", [](const command::params&) command::add("exploit",
[]([[maybe_unused]] const command::params& params)
{ {
game::Dvar_SetBool(cl_exploit, true); game::Dvar_SetBool(cl_exploit, true);
}); });
command::add("undo_exploit", [](const command::params&) command::add("undo_exploit",
[]([[maybe_unused]] const command::params& params)
{ {
game::Dvar_SetBool(cl_exploit, false); game::Dvar_SetBool(cl_exploit, false);
}); });
command::add("send_command", [](const command::params& params) command::add(
"send_command",
[]([[maybe_unused]] const command::params& params)
{ {
if (params.size() < 2) return; if (params.size() < 2) return;
@ -109,10 +114,12 @@ namespace exploit
return; return;
const auto cmd = std::format("queryserverinfo ;{}", params.join(1)); const auto cmd = std::format("queryserverinfo ;{}", params.join(1));
game::NET_OutOfBandPrint(game::NS_SERVER, game::localClientConnection->serverAddress, cmd.data()); game::NET_OutOfBandPrint(game::NS_SERVER,
game::localClientConnection->serverAddress,
cmd.data());
}); });
} }
}; };
} } // namespace exploit
REGISTER_COMPONENT(exploit::component) REGISTER_COMPONENT(exploit::component)

View File

@ -11,40 +11,42 @@ namespace key_catcher
namespace namespace
{ {
std::unordered_map<std::string, callback>& get_key_callbacks() std::unordered_map<std::string, key_catcher::callback>& get_key_callbacks()
{ {
static std::unordered_map<std::string, callback> key_callbacks{}; static std::unordered_map<std::string, key_catcher::callback>
key_callbacks{};
return key_callbacks; return key_callbacks;
} }
void handle_key_event(game::LocalClientNum_t localClient, int keyID) void handle_key_event(game::LocalClientNum_t local_client, int key_id)
{ {
auto result = VkKeyScanA(static_cast<CHAR>(keyID)); const auto result = VkKeyScanA(static_cast<CHAR>(key_id));
auto VkKey = LOBYTE(result); const auto vk_key = LOBYTE(result);
auto& callbacks = get_key_callbacks(); const auto& callbacks = get_key_callbacks();
for (auto const& i : callbacks) for (auto const& [key, value] : callbacks)
{ {
auto gameVkKey = game::Key_StringToKeynum(i.first.data()); const auto game_vk_key = game::Key_StringToKeynum(key.data());
if (static_cast<BYTE>(gameVkKey) == VkKey) if (static_cast<BYTE>(game_vk_key) == vk_key)
{ {
i.second(localClient); value(local_client);
return; return;
} }
} }
} }
} } // namespace
void on_key_press(const std::string& command, const callback& callback) void on_key_press(const std::string& command, const callback& callback)
{ {
get_key_callbacks()[command] = callback; get_key_callbacks()[command] = callback;
} }
void cl_key_event_stub(game::LocalClientNum_t localClient, int keyID, int a3) void cl_key_event_stub(game::LocalClientNum_t local_client, int key_id,
int a3)
{ {
handle_key_event(localClient, keyID); handle_key_event(local_client, key_id);
cl_key_event_hook.invoke<void>(localClient, keyID, a3); cl_key_event_hook.invoke<void>(local_client, key_id, a3);
} }
class component final : public component_interface class component final : public component_interface
@ -60,6 +62,6 @@ namespace key_catcher
cl_key_event_hook.clear(); cl_key_event_hook.clear();
} }
}; };
} } // namespace key_catcher
REGISTER_COMPONENT(key_catcher::component) REGISTER_COMPONENT(key_catcher::component)

View File

@ -2,7 +2,7 @@
namespace key_catcher namespace key_catcher
{ {
using callback = std::function<void(game::LocalClientNum_t& localClient)>; using callback = std::function<void(game::LocalClientNum_t& local_client)>;
void on_key_press(const std::string& command, const callback& callback); void on_key_press(const std::string& command, const callback& callback);
} } // namespace key_catcher

View File

@ -11,36 +11,43 @@ namespace network
{ {
namespace namespace
{ {
std::unordered_map<std::string, callback>& get_callbacks() std::unordered_map<std::string, network::callback>& get_callbacks()
{ {
static std::unordered_map<std::string, callback> network_callbacks{}; static std::unordered_map<std::string, network::callback>
network_callbacks{};
return network_callbacks; return network_callbacks;
} }
bool handle_command(game::netadr_s* address, const char* command, game::msg_t* message) bool handle_command(game::netadr_s* address, const char* command,
game::msg_t* msg)
{ {
const auto cmd_string = utils::string::to_lower(command); const auto cmd_string = utils::string::to_lower(command);
auto& callbacks = get_callbacks(); auto& callbacks = get_callbacks();
const auto handler = callbacks.find(cmd_string); const auto handler = callbacks.find(cmd_string);
const auto offset = cmd_string.size() + 5;
if (handler == callbacks.end()) if (static_cast<unsigned int>(msg->cursize) < offset ||
handler == callbacks.end())
{ {
return false; return false;
} }
const auto offset = cmd_string.size() + 5; const std::string_view data(reinterpret_cast<char*>(msg->data) + offset,
const std::string_view data(reinterpret_cast<char*>(message->data) + offset, message->cursize - offset); msg->cursize - offset);
handler->second(*address, data); handler->second(*address, data);
return true; return true;
} }
} } // namespace
int packet_interception_handler(game::netadr_s* from, const char* command, game::msg_t* message) int packet_interception_handler(game::netadr_s* from, const char* command,
game::msg_t* message)
{ {
if (!handle_command(from, command, message)) if (!handle_command(from, command, message))
{ {
return reinterpret_cast<int (*)(game::netadr_s*, const char*, game::msg_t*)>(0x525730)(from, command, message); return reinterpret_cast<int (*)(
game::netadr_s*, const char*, game::msg_t*)>(0x525730)(
from, command, message);
} }
return TRUE; return TRUE;
@ -64,12 +71,13 @@ namespace network
private: private:
static void add_network_commands() static void add_network_commands()
{ {
on_packet("naughty_reply", [](const game::netadr_s&, const std::string_view&) on_packet("naughty_reply",
[](const game::netadr_s&, const std::string_view&)
{ {
command::execute("quit_meme"); command::execute("quit_meme");
}); });
} }
}; };
} } // namespace network
REGISTER_COMPONENT(network::component) REGISTER_COMPONENT(network::component)

View File

@ -2,7 +2,8 @@
namespace network namespace network
{ {
using callback = std::function<void(const game::netadr_s&, const std::string_view&)>; using callback =
std::function<void(const game::netadr_s&, const std::string_view&)>;
void on_packet(const std::string& command, const callback& callback); void on_packet(const std::string& command, const callback& callback);
} } // namespace network

View File

@ -1,6 +1,6 @@
#include <stdinc.hpp> #include <stdinc.hpp>
#include <loader/component_loader.hpp> #include <loader/component_loader.hpp>
#include <utils/hook.hpp> #include <utils/hook.hpp>
namespace remove_hooks namespace remove_hooks
@ -29,6 +29,6 @@ namespace remove_hooks
utils::hook::set<BYTE>(0x6EA964, 0xEC); utils::hook::set<BYTE>(0x6EA964, 0xEC);
} }
}; };
} } // namespace remove_hooks
REGISTER_COMPONENT(remove_hooks::component) REGISTER_COMPONENT(remove_hooks::component)

View File

@ -1,8 +1,8 @@
#include <stdinc.hpp> #include <stdinc.hpp>
#include "loader/component_loader.hpp" #include <loader/component_loader.hpp>
#include "utils/concurrency.hpp" #include <utils/concurrency.hpp>
#include "utils/hook.hpp" #include <utils/hook.hpp>
#include "scheduler.hpp" #include "scheduler.hpp"
@ -26,7 +26,8 @@ namespace scheduler
public: public:
void add(task&& task) void add(task&& task)
{ {
new_callbacks_.access([&task, this](task_list& tasks) new_callbacks_.access(
[&task, this](task_list& tasks)
{ {
tasks.emplace_back(std::move(task)); tasks.emplace_back(std::move(task));
}); });
@ -34,7 +35,8 @@ namespace scheduler
void clear() void clear()
{ {
callbacks_.access([&](task_list& tasks) callbacks_.access(
[&](task_list& tasks)
{ {
this->merge_callbacks(); this->merge_callbacks();
tasks.clear(); tasks.clear();
@ -43,7 +45,8 @@ namespace scheduler
void execute() void execute()
{ {
callbacks_.access([&](task_list& tasks) callbacks_.access(
[&](task_list& tasks)
{ {
this->merge_callbacks(); this->merge_callbacks();
@ -79,11 +82,17 @@ namespace scheduler
void merge_callbacks() void merge_callbacks()
{ {
callbacks_.access([&](task_list& tasks) callbacks_.access(
[&](task_list& tasks)
{ {
new_callbacks_.access([&](task_list& new_tasks) new_callbacks_.access(
[&](task_list& new_tasks)
{ {
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()), std::move_iterator<task_list::iterator>(new_tasks.end())); tasks.insert(tasks.end(),
std::move_iterator<task_list::iterator>(
new_tasks.begin()),
std::move_iterator<task_list::iterator>(
new_tasks.end()));
new_tasks = {}; new_tasks = {};
}); });
}); });
@ -104,7 +113,7 @@ namespace scheduler
reinterpret_cast<void (*)(game::LocalClientNum_t)>(0x41C9B0)(local); reinterpret_cast<void (*)(game::LocalClientNum_t)>(0x41C9B0)(local);
execute(pipeline::client); execute(pipeline::client);
} }
} } // namespace
void clear_tasks(const pipeline type) void clear_tasks(const pipeline type)
{ {
@ -127,21 +136,27 @@ namespace scheduler
void loop(const std::function<void()>& callback, const pipeline type, void loop(const std::function<void()>& callback, const pipeline type,
const std::chrono::milliseconds delay) const std::chrono::milliseconds delay)
{ {
schedule([callback]() schedule(
[callback]()
{ {
callback(); callback();
return cond_continue; return cond_continue;
}, type, delay); },
type,
delay);
} }
void once(const std::function<void()>& callback, const pipeline type, void once(const std::function<void()>& callback, const pipeline type,
const std::chrono::milliseconds delay) const std::chrono::milliseconds delay)
{ {
schedule([callback]() schedule(
[callback]()
{ {
callback(); callback();
return cond_end; return cond_end;
}, type, delay); },
type,
delay);
} }
unsigned int thread_id; unsigned int thread_id;
@ -151,7 +166,8 @@ namespace scheduler
public: public:
void post_unpack() override void post_unpack() override
{ {
thread = std::thread([]() thread = std::thread(
[]()
{ {
while (true) while (true)
{ {
@ -165,6 +181,6 @@ namespace scheduler
utils::hook::call(0x4E4A0D, cl_frame_stub); utils::hook::call(0x4E4A0D, cl_frame_stub);
} }
}; };
} } // namespace scheduler
REGISTER_COMPONENT(scheduler::component) REGISTER_COMPONENT(scheduler::component)

View File

@ -16,10 +16,13 @@ namespace scheduler
void clear_tasks(const pipeline type); void clear_tasks(const pipeline type);
void schedule(const std::function<bool()>& callback, pipeline type = pipeline::client, void schedule(const std::function<bool()>& callback,
pipeline type = pipeline::client,
std::chrono::milliseconds delay = 0ms); std::chrono::milliseconds delay = 0ms);
void loop(const std::function<void()>& callback, pipeline type = pipeline::client, void loop(const std::function<void()>& callback,
pipeline type = pipeline::client,
std::chrono::milliseconds delay = 0ms); std::chrono::milliseconds delay = 0ms);
void once(const std::function<void()>& callback, pipeline type = pipeline::client, void once(const std::function<void()>& callback,
pipeline type = pipeline::client,
std::chrono::milliseconds delay = 0ms); std::chrono::milliseconds delay = 0ms);
} } // namespace scheduler

View File

@ -1,9 +1,10 @@
#include <stdinc.hpp> #include <stdinc.hpp>
#include <loader/component_loader.hpp> #include <loader/component_loader.hpp>
#include "utils/hook.hpp"
#include "utils/info_string.hpp" #include <utils/hook.hpp>
#include "utils/string.hpp" #include <utils/info_string.hpp>
#include <utils/string.hpp>
#include "scheduler.hpp" #include "scheduler.hpp"
@ -12,35 +13,35 @@ namespace user_info
namespace namespace
{ {
int a1 = 0; int a1 = 0;
void cl_check_user_info(int _a1, int force) void cl_check_user_info(int _a1, const int force)
{ {
a1 = _a1; a1 = _a1;
if (*game::connectionState <= game::connstate_t::CA_CHALLENGING) if (*game::connectionState <= game::connstate_t::CA_CHALLENGING) return;
return;
if (game::cl_paused->current.enabled && !force) if (game::cl_paused->current.enabled && !force) return;
return;
const std::string infoString = game::Dvar_InfoString(_a1, 0x200); const std::string info_string = game::Dvar_InfoString(_a1, 0x200);
utils::info_string info(infoString); utils::info_string info(info_string);
const auto colorCode = rand() % 10; const auto color_code = std::rand() % 10;
char name[16]; char name[16];
const auto& numbers = std::to_string(rand() % 10000); const auto numbers = std::to_string(std::rand() % 10000);
_snprintf_s(name, sizeof(name), _TRUNCATE, "^%d%s", colorCode, numbers.data()); _snprintf_s(
name, sizeof(name), _TRUNCATE, "^%d%s", color_code, numbers.data());
info.set("name", name); info.set("name", name);
info.set("ec_usingTag", "1"); info.set("ec_usingTag", "1");
info.set("ec_TagText", utils::string::va("^%dGG", colorCode)); info.set("ec_TagText", utils::string::va("^%dGG", color_code));
const auto& bigTitle = std::to_string(rand() % 512); const auto big_title = std::to_string(std::rand() % 512);
info.set("ec_TitleBg", bigTitle); info.set("ec_TitleBg", big_title);
game::CL_AddReliableCommand(_a1, utils::string::va("userinfo \"%s\"", info.build().data())); game::CL_AddReliableCommand(
_a1, utils::string::va("userinfo \"%s\"", info.build().data()));
} }
__declspec(naked) void cl_check_user_info_stub() __declspec(naked) void cl_check_user_info_stub()
@ -58,7 +59,7 @@ namespace user_info
ret ret
} }
} }
} } // namespace
class component final : public component_interface class component final : public component_interface
{ {
@ -67,12 +68,15 @@ namespace user_info
{ {
utils::hook::call(0x41CA53, cl_check_user_info_stub); utils::hook::call(0x41CA53, cl_check_user_info_stub);
scheduler::loop([] scheduler::loop(
[]
{ {
cl_check_user_info(a1, TRUE); cl_check_user_info(a1, TRUE);
}, scheduler::pipeline::client, 4s); },
scheduler::pipeline::client,
4s);
} }
}; };
} } // namespace user_info
REGISTER_COMPONENT(user_info::component) REGISTER_COMPONENT(user_info::component)

View File

@ -1,19 +1,15 @@
#include <stdinc.hpp> #include <stdinc.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
BOOL APIENTRY DllMain(HMODULE /*hModule*/, BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call,
DWORD ul_reason_for_call,
LPVOID /*lpReserved*/ LPVOID /*lpReserved*/
) ) {
{ if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH) std::srand(uint32_t(time(nullptr)));
{
srand(uint32_t(time(nullptr)));
component_loader::post_unpack(); component_loader::post_unpack();
} }
else if (ul_reason_for_call == DLL_PROCESS_DETACH) else if (ul_reason_for_call == DLL_PROCESS_DETACH) {
{
component_loader::pre_destroy(); component_loader::pre_destroy();
} }

View File

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

View File

@ -1,34 +1,19 @@
#pragma once #pragma once
namespace game namespace game {
{ template <typename T> class symbol {
template <typename T>
class symbol
{
public: public:
symbol(const size_t dedi) symbol(const size_t dedi) : dedi_(reinterpret_cast<T*>(dedi)) {}
: dedi_(reinterpret_cast<T*>(dedi))
{
}
T* get() const T* get() const { return dedi_; }
{
return dedi_;
}
operator T* () const operator T*() const { return this->get(); }
{
return this->get();
}
T* operator->() const T* operator->() const { return this->get(); }
{
return this->get();
}
private: private:
T* dedi_; T* dedi_;
}; };
} } // namespace game
#include "symbols.hpp" #include "symbols.hpp"

View File

@ -3,15 +3,13 @@
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4324) #pragma warning(disable : 4324)
namespace game namespace game {
{
typedef float vec_t; typedef float vec_t;
typedef vec_t vec2_t[2]; typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3]; typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4]; typedef vec_t vec4_t[4];
struct cmd_function_t struct cmd_function_t {
{
cmd_function_t* next; cmd_function_t* next;
const char* name; const char* name;
const char* autoCompleteDir; const char* autoCompleteDir;
@ -20,8 +18,7 @@ namespace game
int flags; int flags;
}; };
struct CmdArgs struct CmdArgs {
{
int nesting; int nesting;
int localClientNum[8]; int localClientNum[8];
int controllerIndex[8]; int controllerIndex[8];
@ -29,146 +26,7 @@ namespace game
const char** argv[8]; const char** argv[8];
}; };
typedef enum struct kbutton_t {
{
K_NONE = 0x0,
K_FIRSTGAMEPADBUTTON_RANGE_1 = 0x1, // First Gamepad 1
K_BUTTON_A = 0x1,
K_BUTTON_B = 0x2,
K_BUTTON_X = 0x3,
K_BUTTON_Y = 0x4,
K_BUTTON_LSHLDR = 0x5,
K_BUTTON_RSHLDR = 0x6,
K_LASTGAMEPADBUTTON_RANGE_1 = 0x6, // Last Gamepad 1
K_TAB = 0x9,
K_ENTER = 0xD,
K_FIRSTGAMEPADBUTTON_RANGE_2 = 0xE, // First Gamepad 2
K_BUTTON_START = 0xE,
K_BUTTON_BACK = 0xF,
K_BUTTON_LSTICK = 0x10,
K_BUTTON_RSTICK = 0x11,
K_BUTTON_LTRIG = 0x12,
K_BUTTON_RTRIG = 0x13,
K_FIRSTDPAD = 0x14, // First Dpad
K_DPAD_UP = 0x14,
K_DPAD_DOWN = 0x15,
K_DPAD_LEFT = 0x16,
K_DPAD_RIGHT = 0x17,
K_LASTDPAD = 0x17, // Last Dpad
K_DPAD_LEFTRIGHT = 0x18,
K_DPAD_UPDOWN = 0x19,
K_LASTGAMEPADBUTTON_RANGE_2 = 0x19, // Last Gamepad 2
K_ESCAPE = 0x1B,
K_FIRSTGAMEPADBUTTON_RANGE_3 = 0x1C, // First Gamepad 3
K_FIRSTAPAD = 0x1C, // First APad
K_APAD_UP = 0x1C,
K_APAD_DOWN = 0x1D,
K_APAD_LEFT = 0x1E,
K_APAD_RIGHT = 0x1F,
K_LASTAPAD = 0x1F, // Last APad
K_LASTGAMEPADBUTTON_RANGE_3 = 0x1F, // Last Gamepad 3
K_SPACE = 0x20,
K_BACKSPACE = 0x7F,
K_ASCII_FIRST = 0x80,
K_ASCII_181 = 0x80,
K_ASCII_191 = 0x81,
K_ASCII_223 = 0x82,
K_ASCII_224 = 0x83,
K_ASCII_225 = 0x84,
K_ASCII_228 = 0x85,
K_ASCII_229 = 0x86,
K_ASCII_230 = 0x87,
K_ASCII_231 = 0x88,
K_ASCII_232 = 0x89,
K_ASCII_233 = 0x8A,
K_ASCII_236 = 0x8B,
K_ASCII_241 = 0x8C,
K_ASCII_242 = 0x8D,
K_ASCII_243 = 0x8E,
K_ASCII_246 = 0x8F,
K_ASCII_248 = 0x90,
K_ASCII_249 = 0x91,
K_ASCII_250 = 0x92,
K_ASCII_252 = 0x93,
K_END_ASCII_CHARS = 0x94,
K_COMMAND = 0x96,
K_CAPSLOCK = 0x97,
K_POWER = 0x98,
K_PAUSE = 0x99,
K_UPARROW = 0x9A,
K_DOWNARROW = 0x9B,
K_LEFTARROW = 0x9C,
K_RIGHTARROW = 0x9D,
K_ALT = 0x9E,
K_CTRL = 0x9F,
K_SHIFT = 0xA0,
K_INS = 0xA1,
K_DEL = 0xA2,
K_PGDN = 0xA3,
K_PGUP = 0xA4,
K_HOME = 0xA5,
K_END = 0xA6,
K_F1 = 0xA7,
K_F2 = 0xA8,
K_F3 = 0xA9,
K_F4 = 0xAA,
K_F5 = 0xAB,
K_F6 = 0xAC,
K_F7 = 0xAD,
K_F8 = 0xAE,
K_F9 = 0xAF,
K_F10 = 0xB0,
K_F11 = 0xB1,
K_F12 = 0xB2,
K_F13 = 0xB3,
K_F14 = 0xB4,
K_F15 = 0xB5,
K_KP_HOME = 0xB6,
K_KP_UPARROW = 0xB7,
K_KP_PGUP = 0xB8,
K_KP_LEFTARROW = 0xB9,
K_KP_5 = 0xBA,
K_KP_RIGHTARROW = 0xBB,
K_KP_END = 0xBC,
K_KP_DOWNARROW = 0xBD,
K_KP_PGDN = 0xBE,
K_KP_ENTER = 0xBF,
K_KP_INS = 0xC0,
K_KP_DEL = 0xC1,
K_KP_SLASH = 0xC2,
K_KP_MINUS = 0xC3,
K_KP_PLUS = 0xC4,
K_KP_NUMLOCK = 0xC5,
K_KP_STAR = 0xC6,
K_KP_EQUALS = 0xC7,
K_MOUSE1 = 0xC8,
K_MOUSE2 = 0xC9,
K_MOUSE3 = 0xCA,
K_MOUSE4 = 0xCB,
K_MOUSE5 = 0xCC,
K_MWHEELDOWN = 0xCD,
K_MWHEELUP = 0xCE,
K_AUX1 = 0xCF,
K_AUX2 = 0xD0,
K_AUX3 = 0xD1,
K_AUX4 = 0xD2,
K_AUX5 = 0xD3,
K_AUX6 = 0xD4,
K_AUX7 = 0xD5,
K_AUX8 = 0xD6,
K_AUX9 = 0xD7,
K_AUX10 = 0xD8,
K_AUX11 = 0xD9,
K_AUX12 = 0xDA,
K_AUX13 = 0xDB,
K_AUX14 = 0xDC,
K_AUX15 = 0xDD,
K_AUX16 = 0xDE,
K_LAST_KEY = 0xDF
} keyNum_t;
struct kbutton_t
{
int down[2]; int down[2];
unsigned int downtime; unsigned int downtime;
unsigned int msec; unsigned int msec;
@ -178,8 +36,7 @@ namespace game
static_assert(sizeof(kbutton_t) == 20); static_assert(sizeof(kbutton_t) == 20);
typedef enum typedef enum {
{
NS_CLIENT1 = 0, NS_CLIENT1 = 0,
NS_CLIENT2 = 1, NS_CLIENT2 = 1,
NS_CLIENT3 = 2, NS_CLIENT3 = 2,
@ -190,8 +47,7 @@ namespace game
NS_INVALID_NETSRC = 6 NS_INVALID_NETSRC = 6
} netsrc_t; } netsrc_t;
enum netadrtype_t enum netadrtype_t {
{
NA_BOT = 0x0, NA_BOT = 0x0,
NA_BAD = 0x1, NA_BAD = 0x1,
NA_LOOPBACK = 0x2, NA_LOOPBACK = 0x2,
@ -199,8 +55,7 @@ namespace game
NA_IP = 0x4 NA_IP = 0x4
}; };
struct netadr_s struct netadr_s {
{
netadrtype_t type; netadrtype_t type;
unsigned char ip[4]; unsigned char ip[4];
unsigned __int16 port; unsigned __int16 port;
@ -210,53 +65,7 @@ namespace game
static_assert(sizeof(netadr_s) == 24); static_assert(sizeof(netadr_s) == 24);
typedef enum typedef enum {
{
BD_ECC_KEY_UNINITIALIZED = 0x0,
BD_ECC_KEY_INITIALIZED = 0x1
} bdECCKeyStatus;
typedef enum
{
BD_DTLS_INIT = 0x1,
BD_DTLS_INIT_ACK = 0x2,
BD_DTLS_COOKIE_ECHO = 0x3,
BD_DTLS_COOKIE_ACK = 0x4,
BD_DTLS_ERROR = 0x5,
BD_DTLS_DATA = 0x6
} bdDTLSPacketTypes;
typedef enum
{
BD_DTLS_CLOSED = 0x0,
BD_DTLS_COOKIE_WAIT = 0x1,
BD_DTLS_COOKIE_ECHOED = 0x2,
BD_DTLS_ESTABLISHED = 0x3
} bdDTLSStatus;
typedef enum
{
BD_DTLS_ERROR_BAD_SECID = 0x0,
BD_DTLS_INVALID_STATE = 0x1
} bdDTLSErrorType;
typedef enum
{
BD_NAT_OPEN = 0x1,
BD_NAT_MODERATE = 0x2,
BD_NAT_STRICT = 0x3
} bdNATType;
typedef enum
{
BD_SOCKET_IDLE = 0x0,
BD_SOCKET_PENDING = 0x1,
BD_SOCKET_CONNECTED = 0x2,
BD_SOCKET_LOST = 0x3
} bdDTLSAssociationStatus;
typedef enum
{
ERR_FATAL = 0x0, ERR_FATAL = 0x0,
ERR_DROP = 0x1, ERR_DROP = 0x1,
ERR_SERVERDISCONNECT = 0x2, ERR_SERVERDISCONNECT = 0x2,
@ -267,8 +76,7 @@ namespace game
ERR_MAPLOADERRORSUMMARY = 0x7 ERR_MAPLOADERRORSUMMARY = 0x7
} errorParm_t; } errorParm_t;
enum class LocalClientNum_t enum class LocalClientNum_t {
{
LOCAL_CLIENT_0 = 0, LOCAL_CLIENT_0 = 0,
LOCAL_CLIENT_1 = 1, LOCAL_CLIENT_1 = 1,
LOCAL_CLIENT_2 = 2, LOCAL_CLIENT_2 = 2,
@ -277,8 +85,7 @@ namespace game
LOCAL_CLIENT_COUNT = 4 LOCAL_CLIENT_COUNT = 4
}; };
typedef enum typedef enum {
{
CA_DISCONNECTED = 0, CA_DISCONNECTED = 0,
CA_CINEMATIC = 1, CA_CINEMATIC = 1,
CA_LOGO = 2, CA_LOGO = 2,
@ -292,8 +99,7 @@ namespace game
CA_ACTIVE = 10 CA_ACTIVE = 10
} connstate_t; } connstate_t;
struct msg_t struct msg_t {
{
int overflowed; int overflowed;
int readOnly; int readOnly;
unsigned char* data; unsigned char* data;
@ -306,15 +112,13 @@ namespace game
int lastEntityRef; int lastEntityRef;
}; };
struct netProfilePacket_t struct netProfilePacket_t {
{
int iTime; int iTime;
int iSize; int iSize;
int bFragment; int bFragment;
}; };
struct netProfileStream_t struct netProfileStream_t {
{
netProfilePacket_t packets[60]; netProfilePacket_t packets[60];
int iCurrPacket; int iCurrPacket;
int iBytesPerSeconds; int iBytesPerSeconds;
@ -326,14 +130,14 @@ namespace game
int iSmallestPacket; int iSmallestPacket;
}; };
struct netProfileInfo_t struct netProfileInfo_t {
{
netProfileStream_t send; netProfileStream_t send;
netProfileStream_t recieve; netProfileStream_t recieve;
}; };
struct netchan_t static_assert(sizeof(netProfileInfo_t) == 0x5E0);
{
struct netchan_t {
int outgoingSequence; int outgoingSequence;
netsrc_t sock; netsrc_t sock;
int dropped; int dropped;
@ -353,236 +157,19 @@ namespace game
}; };
static_assert(sizeof(netchan_t) == 0x630); static_assert(sizeof(netchan_t) == 0x630);
static_assert(sizeof(netProfileInfo_t) == 0x5E0);
struct XZoneInfo enum dvar_flags : std::uint16_t {
{ DVAR_NONE = 0x0,
const char* name; DVAR_ARCHIVE = 0x1,
int allocFlags; DVAR_CHEAT = 0x4,
int freeFlags; DVAR_CODINFO = 0x8,
DVAR_SCRIPTINFO = 0x10,
DVAR_SERVERINFO = 0x400,
DVAR_WRITEPROTECTED = 0x800,
DVAR_READONLY = 0x2000,
}; };
struct scr_entref_t union DvarValue {
{
unsigned __int16 entnum;
unsigned __int16 classnum;
};
typedef void(__cdecl* scr_call_t)(int entref);
enum MeansOfDeath
{
MOD_UNKNOWN = 0,
MOD_PISTOL_BULLET = 1,
MOD_RIFLE_BULLET = 2,
MOD_EXPLOSIVE_BULLET = 3,
MOD_GRENADE = 4,
MOD_GRENADE_SPLASH = 5,
MOD_PROJECTILE = 6,
MOD_PROJECTILE_SPLASH = 7,
MOD_MELEE = 8,
MOD_HEAD_SHOT = 9,
MOD_CRUSH = 10,
MOD_FALLING = 11,
MOD_SUICIDE = 12,
MOD_TRIGGER_HURT = 13,
MOD_EXPLOSIVE = 14,
MOD_IMPACT = 15,
MOD_NUM = 16
};
enum scriptType_e
{
SCRIPT_NONE = 0,
SCRIPT_OBJECT = 1,
SCRIPT_STRING = 2,
SCRIPT_ISTRING = 3,
SCRIPT_VECTOR = 4,
SCRIPT_FLOAT = 5,
SCRIPT_INTEGER = 6,
SCRIPT_END = 8,
SCRIPT_FUNCTION = 9,
SCRIPT_STRUCT = 19,
SCRIPT_ARRAY = 22,
};
struct VariableStackBuffer
{
const char* pos;
unsigned __int16 size;
unsigned __int16 bufLen;
unsigned __int16 localId;
char time;
char buf[1];
};
union VariableUnion
{
int intValue;
float floatValue;
unsigned int stringValue;
const float* vectorValue;
const char* codePosValue;
unsigned int pointerValue;
VariableStackBuffer* stackValue;
unsigned int entityId;
unsigned int uintValue;
};
struct VariableValue
{
VariableUnion u;
scriptType_e type;
};
struct function_stack_t
{
const char* pos;
unsigned int localId;
unsigned int localVarCount;
VariableValue* top;
VariableValue* startTop;
};
struct function_frame_t
{
function_stack_t fs;
int topType;
};
struct scrVmPub_t
{
unsigned int* localVars;
VariableValue* maxstack;
int function_count;
function_frame_t* function_frame;
VariableValue* top;
/*bool debugCode;
bool abort_on_error;
bool terminal_error;
bool block_execution;*/
unsigned int inparamcount;
unsigned int outparamcount;
unsigned int breakpointOutparamcount;
bool showError;
function_frame_t function_frame_start[32];
VariableValue stack[2048];
};
struct scr_classStruct_t
{
unsigned __int16 id;
unsigned __int16 entArrayId;
char charId;
const char* name;
};
struct ObjectVariableChildren
{
unsigned __int16 firstChild;
unsigned __int16 lastChild;
};
struct ObjectVariableValue_u_f
{
unsigned __int16 prev;
unsigned __int16 next;
};
union ObjectVariableValue_u_o_u
{
unsigned __int16 size;
unsigned __int16 entnum;
unsigned __int16 nextEntId;
unsigned __int16 self;
};
struct ObjectVariableValue_u_o
{
unsigned __int16 refCount;
ObjectVariableValue_u_o_u u;
};
union ObjectVariableValue_w
{
unsigned int type;
unsigned int classnum;
unsigned int notifyName;
unsigned int waitTime;
unsigned int parentLocalId;
};
struct ChildVariableValue_u_f
{
unsigned __int16 prev;
unsigned __int16 next;
};
union ChildVariableValue_u
{
ChildVariableValue_u_f f;
VariableUnion u;
};
struct ChildBucketMatchKeys_keys
{
unsigned __int16 name_hi;
unsigned __int16 parentId;
};
union ChildBucketMatchKeys
{
ChildBucketMatchKeys_keys keys;
unsigned int match;
};
struct ChildVariableValue
{
ChildVariableValue_u u;
unsigned __int16 next;
char type;
char name_lo;
ChildBucketMatchKeys k;
unsigned __int16 nextSibling;
unsigned __int16 prevSibling;
};
union ObjectVariableValue_u
{
ObjectVariableValue_u_f f;
ObjectVariableValue_u_o o;
};
struct ObjectVariableValue
{
ObjectVariableValue_u u;
ObjectVariableValue_w w;
};
struct scrVarGlob_t
{
ObjectVariableValue objectVariableValue[36864];
ObjectVariableChildren objectVariableChildren[36864];
unsigned __int16 childVariableBucket[65536];
ChildVariableValue childVariableValue[102400];
};
enum dvar_flags : std::uint16_t
{
DVAR_FLAG_NONE = 0,
DVAR_FLAG_SAVED = 1,
DVAR_FLAG_LATCHED = 2,
DVAR_FLAG_CHEAT = 4,
DVAR_FLAG_REPLICATED = 0x8,
DVAR_FLAG_UNK1 = 0x40,
DVAR_FLAG_UNK2 = 0x200,
DVAR_FLAG_SYSTEM = 0x400,
DVAR_FLAG_WRITE = 0x800,
DVAR_FLAG_READONLY = 0x2000,
};
union DvarValue
{
bool enabled; bool enabled;
int integer; int integer;
unsigned int unsignedInt; unsigned int unsignedInt;
@ -592,34 +179,29 @@ namespace game
char color[4]; char color[4];
}; };
struct enum_limit struct enum_limit {
{
int stringCount; int stringCount;
const char** strings; const char** strings;
}; };
struct int_limit struct int_limit {
{
int min; int min;
int max; int max;
}; };
struct float_limit struct float_limit {
{
float min; float min;
float max; float max;
}; };
union DvarLimits union DvarLimits {
{
enum_limit enumeration; enum_limit enumeration;
int_limit integer; int_limit integer;
float_limit value; float_limit value;
float_limit vector; float_limit vector;
}; };
struct dvar_t struct dvar_t {
{
const char* name; const char* name;
unsigned int flags; unsigned int flags;
char type; char type;
@ -632,8 +214,7 @@ namespace game
dvar_t* hashNext; dvar_t* hashNext;
}; };
struct usercmd_s struct usercmd_s {
{
int serverTime; int serverTime;
int buttons; int buttons;
int angles[3]; int angles[3];
@ -650,15 +231,13 @@ namespace game
int remoteControlMove; int remoteControlMove;
}; };
enum LocSelInputState enum LocSelInputState {
{
LOC_SEL_INPUT_NONE = 0, LOC_SEL_INPUT_NONE = 0,
LOC_SEL_INPUT_CONFIRM = 1, LOC_SEL_INPUT_CONFIRM = 1,
LOC_SEL_INPUT_CANCEL = 2 LOC_SEL_INPUT_CANCEL = 2
}; };
struct field_t struct field_t {
{
int cursor; int cursor;
int scroll; int scroll;
int drawWidth; int drawWidth;
@ -668,8 +247,7 @@ namespace game
char buffer[256]; char buffer[256];
}; };
struct KeyState struct KeyState {
{
int down; int down;
int repeats; int repeats;
int binding; int binding;
@ -678,8 +256,7 @@ namespace game
static_assert(sizeof(field_t) == 280); static_assert(sizeof(field_t) == 280);
struct PlayerKeyState struct PlayerKeyState {
{
field_t chatField; field_t chatField;
int chat_team; int chat_team;
int overstrikeMode; int overstrikeMode;
@ -690,313 +267,16 @@ namespace game
static_assert(sizeof(PlayerKeyState) == 4392); static_assert(sizeof(PlayerKeyState) == 4392);
enum EffectiveStance enum clientState_t {
{
PM_EFF_STANCE_DEFAULT = 0,
PM_EFF_STANCE_PRONE = 1,
PM_EFF_STANCE_DUCKED = 2,
PM_EFF_STANCE_LASTSTANDCRAWL = 3,
PM_EFF_STANCE_COUNT = 4
};
enum clientState_t : std::int32_t
{
CS_FREE = 0, CS_FREE = 0,
CS_ZOMBIE = 1, CS_ZOMBIE = 1,
CS_UNKNOWN = 2, CS_RECONNECTING = 2,
CS_CONNECTED = 3, CS_CONNECTED = 3,
CS_PRIMED = 4, CS_PRIMED = 4,
CS_ACTIVE = 5 CS_ACTIVE = 5
}; };
struct MantleState struct clientConnection_t {
{
float yaw;
int timer;
int transIndex;
int flags;
};
struct SprintState_s
{
int sprintButtonUpRequired; // 0x20C
int sprintDelay; // 0x210
int lastSprintStart;
int lastSprintEnd; // 0x218
int sprintStartMaxLength;
};
struct PlayerVehicleState
{
int entity;
int flags;
float origin[3];
float angles[3];
float velocity[3];
float angVelocity[3];
float tilt[2];
float tiltVelocity[2];
};
struct PlayerActiveWeaponState
{
int weapAnim;
int weaponTime;
int weaponDelay;
int weaponRestrictKickTime;
int weaponState;
int weaponHandFlags;
int weaponShotCount;
};
struct PlayerEquippedWeaponState
{
bool usedBefore;
bool dualWielding;
bool inAltMode;
bool needsRechamber[2];
int zoomLevelIndex;
};
static_assert(sizeof(PlayerEquippedWeaponState) == 12);
struct EntityEvent
{
int eventType;
int eventParm;
};
struct playerEvents_t
{
int eventSequence;
EntityEvent events[4];
int oldEventSequence;
int timeADSCameUp;
};
static_assert(sizeof(playerEvents_t) == 44);
enum ViewLockTypes
{
PLAYERVIEWLOCK_NONE = 0,
PLAYERVIEWLOCK_FULL = 1,
PLAYERVIEWLOCK_WEAPONJITTER = 2,
PLAYERVIEWLOCKCOUNT = 3
};
enum TraceHitType
{
TRACE_HITTYPE_NONE = 0,
TRACE_HITTYPE_ENTITY = 1,
TRACE_HITTYPE_DYNENT_MODEL = 2,
TRACE_HITTYPE_DYNENT_BRUSH = 3,
TRACE_HITTYPE_GLASS = 4
};
#pragma pack(push, 1)
struct playerState_s
{
int commandTime;
int pm_type;
int pm_time;
int pm_flags;
int otherFlags;
int linkFlags;
int bobCycle;
float origin[3];
float velocity[3];
int grenadeTimeLeft;
int throwbackGrenadeOwner;
int throwbackGrenadeTimeLeft;
unsigned int throwbackWeapon;
int remoteEyesEnt;
int remoteEyesTagname;
int remoteControlEnt;
int remoteTurretEnt;
int foliageSoundTime;
int gravity;
int speed;
float delta_angles[3];
int groundEntityNum;
float vLadderVec[3];
int jumpTime;
float jumpOriginZ;
int legsTimer;
int legsAnim;
int torsoTimer;
int torsoAnim;
int legsAnimDuration;
int torsoAnimDuration;
int damageTimer;
int damageDuration;
int flinchYawAnim;
int corpseIndex;
PlayerVehicleState vehicleState;
int movementDir;
int eFlags;
playerEvents_t pe;
int unpredictableEventSequence;
int unpredictableEventSequenceOld;
int unpredictableEvents[4];
char unpredictableEventParms[16];
int clientNum;
int viewmodelIndex;
float viewangles[3];
int viewHeightTarget;
float viewHeightCurrent;
int viewHeightLerpTime;
int viewHeightLerpTarget;
int viewHeightLerpDown;
char viewAngleClampBase[8];
char viewAngleClampRange[8];
int damageEvent;
int damageYaw;
int damagePitch;
int damageCount;
int damageFlags;
int stats[4];
float proneDirection;
float proneDirectionPitch;
float proneTorsoPitch;
ViewLockTypes viewlocked;
int viewlocked_entNum;
float linkAngles[3];
float linkWeaponAngles[3];
int linkWeaponEnt;
int loopSound;
int cursorHint;
int cursorHintString;
int cursorHintEntIndex;
int cursorHintDualWield;
int iCompassPlayerInfo;
int radarEnabled;
int radarBlocked;
int radarMode;
int radarStrength;
int radarShowEnemyDirection;
int locationSelectionInfo;
SprintState_s sprintState;
float holdBreathScale;
int holdBreathTimer;
float moveSpeedScaleMultiplier;
MantleState mantleState;
PlayerActiveWeaponState weapState[2];
unsigned int weaponsEquipped[15];
PlayerEquippedWeaponState weapEquippedData[15];
char weapCommon[376];
int meleeChargeDist;
int meleeChargeTime;
int meleeChargeEnt;
int airburstMarkDistance;
unsigned int perks[2];
unsigned int perkSlots[9];
char __pad0[11752];
};
struct pmove_t
{
playerState_s* ps;
usercmd_s cmd;
usercmd_s oldcmd;
int tracemask;
int numtouch;
int touchents[32];
char bounds[24];
float speed;
int proneChange;
float maxSprintTimeMultiplier;
bool mantleStarted;
float mantleEndPos[3];
int mantleDuration;
int viewChangeTime;
float viewChange;
float fTorsoPitch;
float fWaistPitch;
int remoteTurretFireTime;
int lastUpdateCMDServerTime;
unsigned char handler;
};
#pragma pack(pop)
static_assert(sizeof(playerState_s) == 13056);
struct gclient_s
{
playerState_s ps;
char __pad0[716];
int flags;
int spectatorClient;
int lastCmdTime;
// int mpviewer; // Debug ?
int buttons;
int oldButtons;
int latched_buttons;
int buttonsSinceLastFrame;
float oldOrigin[3];
float fGunPitch;
float fGunYaw;
int damage_blood;
int damage_stun;
float damage_from[3];
int damage_fromWorld;
int accurateCount;
int accuracy_shots;
int accuracy_hits;
int inactivityTime;
int inactivityWarning;
int lastVoiceTime;
int switchTeamTime;
float currentAimSpreadScale;
float prevLinkedInvQuat[4];
bool prevLinkAnglesSet;
bool link_rotationMovesEyePos;
bool link_doCollision;
bool link_useTagAnglesForViewAngles;
bool link_useBaseAnglesForViewClamp;
float linkAnglesFrac;
char link_viewClamp[64];
char persistantPowerup[4];
int portalID;
int dropWeaponTime;
int sniperRifleFiredTime;
float sniperRifleMuzzleYaw;
int PCSpecialPickedUpCount;
int useHoldEntity;
int useHoldTime;
int useButtonDone;
int iLastCompassPlayerInfoEnt;
int compassPingTime;
int damageTime;
float v_dmg_roll;
float v_dmg_pitch;
float baseAngles[3];
float baseOrigin[3];
float swayViewAngles[3];
float swayOffset[3];
float swayAngles[3];
float recoilAngles[3];
float recoilSpeed[3];
float fLastIdleFactor;
int lastServerTime;
int lastWeapon;
bool lastWeaponAltStatus;
bool previouslyFiring;
bool previouslyFiringLeftHand;
bool previouslyUsingNightVision;
bool previouslySprinting;
int visionDuration[6];
char visionName[384];
int lastStand;
int lastStandTime;
int hudElemLastAssignedSoundID;
float lockedTargetOffset[3];
unsigned __int16 attachShieldTagName;
int hintForcedType;
int hintForcedString;
};
struct clientConnection_t
{
int qport; // 0 int qport; // 0
int clientNum; // 4 int clientNum; // 4
int lastPacketSentTime; // 8 int lastPacketSentTime; // 8
@ -1025,9 +305,7 @@ namespace game
int currentGamestatePacket; int currentGamestatePacket;
}; };
struct clientStatic_t struct clientStatic_t {};
{ } // namespace game
};
}
#pragma warning(pop) #pragma warning(pop)

View File

@ -2,8 +2,7 @@
#define WEAK __declspec(selectany) #define WEAK __declspec(selectany)
namespace game namespace game {
{
// Functions // Functions
WEAK symbol<void()> Sys_ShowConsole{0x515CD0}; WEAK symbol<void()> Sys_ShowConsole{0x515CD0};
WEAK symbol<void(HINSTANCE__*)> Sys_CreateConsole{0x51B770}; WEAK symbol<void(HINSTANCE__*)> Sys_CreateConsole{0x51B770};
@ -13,35 +12,47 @@ namespace game
WEAK symbol<const char*(int index)> ConcatArgs{0x539060}; WEAK symbol<const char*(int index)> ConcatArgs{0x539060};
WEAK symbol<void(LocalClientNum_t, const char* text)> Cbuf_AddText{0x4C1030}; WEAK symbol<void(LocalClientNum_t, const char* text)> Cbuf_AddText{0x4C1030};
WEAK symbol<void(LocalClientNum_t, const char* text)> Cbuf_InsertText{0x429920}; WEAK symbol<void(LocalClientNum_t, const char* text)> Cbuf_InsertText{0x429920};
WEAK symbol<void(const char* cmdName, void(), cmd_function_t* cmd)> Cmd_AddCommandInternal{0x537E70}; WEAK symbol<void(const char* cmdName, void(), cmd_function_t* cmd)>
WEAK symbol<void(LocalClientNum_t, int, const char* text)> Cmd_ExecuteSingleCommand{0x4EB8F0}; Cmd_AddCommandInternal{0x537E70};
WEAK symbol<void(LocalClientNum_t, int, const char* text)>
Cmd_ExecuteSingleCommand{0x4EB8F0};
WEAK symbol<void(const char* cmdName)> Cmd_RemoveCommand{0x4EAF30}; WEAK symbol<void(const char* cmdName)> Cmd_RemoveCommand{0x4EAF30};
WEAK symbol<const char*(int index)> Cmd_Argv{0x5580E0}; WEAK symbol<const char*(int index)> Cmd_Argv{0x5580E0};
WEAK symbol<dvar_t*(const char*)> Dvar_FindVar{0x4EBB50}; WEAK symbol<dvar_t*(const char*)> Dvar_FindVar{0x4EBB50};
WEAK symbol<dvar_t*(const char* dvarName, int value, int min, int max, unsigned __int16 flags, const char* desc)> WEAK symbol<dvar_t*(const char* dvarName, int value, int min, int max,
unsigned __int16 flags, const char* desc)>
Dvar_RegisterInt{0x50C760}; Dvar_RegisterInt{0x50C760};
WEAK symbol<dvar_t*(const char* dvarName, bool value, unsigned __int16 flags, const char* description)> WEAK symbol<dvar_t*(const char* dvarName, bool value, unsigned __int16 flags,
const char* description)>
Dvar_RegisterBool{0x4A3300}; Dvar_RegisterBool{0x4A3300};
WEAK symbol<dvar_t*(const char* dvarName, const char* value, unsigned __int16 flags, const char* description)> WEAK symbol<dvar_t*(const char* dvarName, const char* value,
unsigned __int16 flags, const char* description)>
Dvar_RegisterString{0x4157E0}; Dvar_RegisterString{0x4157E0};
WEAK symbol<dvar_t*(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description)> WEAK symbol<dvar_t*(const char* dvarName, float value, float min, float max,
unsigned __int16 flags, const char* description)>
Dvar_RegisterFloat{0x4A5CF0}; Dvar_RegisterFloat{0x4A5CF0};
WEAK symbol<void(dvar_t* var, bool value)> Dvar_SetBool{0x46DD70}; WEAK symbol<void(dvar_t* var, bool value)> Dvar_SetBool{0x46DD70};
WEAK symbol<void(const char* dvarName, bool value)> Dvar_SetBoolByName{0x48C7D0}; WEAK symbol<void(const char* dvarName, bool value)> Dvar_SetBoolByName{
0x48C7D0};
WEAK symbol<const char*(int, int)> Dvar_InfoString{0x4028C0}; WEAK symbol<const char*(int, int)> Dvar_InfoString{0x4028C0};
WEAK symbol<int(const char* cmd)> Key_GetBindingForCmd{0x47D300}; WEAK symbol<int(const char* cmd)> Key_GetBindingForCmd{0x47D300};
WEAK symbol<int(const char* keyAsText)> Key_StringToKeynum{0x50A710}; // Virtual-Key Code WEAK symbol<int(const char* keyAsText)> Key_StringToKeynum{
0x50A710}; // Virtual-Key Code
WEAK symbol<void(LocalClientNum_t, int, int)> Key_SetBinding{0x50B770}; WEAK symbol<void(LocalClientNum_t, int, int)> Key_SetBinding{0x50B770};
WEAK symbol<void(int arg, char* buffer, int bufferLength)> SV_Cmd_ArgvBuffer{0x4F6B00}; WEAK symbol<void(int arg, char* buffer, int bufferLength)> SV_Cmd_ArgvBuffer{
0x4F6B00};
WEAK symbol<bool(netsrc_t, netadr_s dest, const char* message)> NET_OutOfBandPrint{0x496230}; WEAK symbol<bool(netsrc_t, netadr_s dest, const char* message)>
WEAK symbol<bool(netsrc_t, netadr_s dest, unsigned char* data, int size)> NET_OutOfBandData{0x4639C0}; 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<int(unsigned int, void*, netadr_s)> dwSendTo{0x673B20};
WEAK symbol<void(netadr_s*, sockaddr*)> NetadrToSockadr{0x48B460}; WEAK symbol<void(netadr_s*, sockaddr*)> NetadrToSockadr{0x48B460};
WEAK symbol<int(const char* serverName, netadr_s serverRemote)> NET_StringToAdr{0x4E09A0}; WEAK symbol<int(const char* serverName, netadr_s serverRemote)> NET_StringToAdr{
0x4E09A0};
WEAK symbol<SOCKET> query_socket{0x5A861EC}; WEAK symbol<SOCKET> query_socket{0x5A861EC};
WEAK symbol<void()> Com_Quit_f{0x556060}; WEAK symbol<void()> Com_Quit_f{0x556060};
@ -53,7 +64,8 @@ namespace game
WEAK symbol<void(int, const char*)> CL_AddReliableCommand{0x4EE3A0}; WEAK symbol<void(int, const char*)> CL_AddReliableCommand{0x4EE3A0};
WEAK symbol<unsigned __int64()> LiveSteam_GetUid{0x4A4050}; WEAK symbol<unsigned __int64()> LiveSteam_GetUid{0x4A4050};
WEAK symbol<int(unsigned __int64, const void*, unsigned int)> LiveSteam_Client_ConnectToSteamServer{0x4D6980}; WEAK symbol<int(unsigned __int64, const void*, unsigned int)>
LiveSteam_Client_ConnectToSteamServer{0x4D6980};
// Variables // Variables
WEAK symbol<CmdArgs> cmd_args{0x1C96850}; WEAK symbol<CmdArgs> cmd_args{0x1C96850};
@ -64,4 +76,4 @@ namespace game
WEAK symbol<int> serverId{0xFF5058}; WEAK symbol<int> serverId{0xFF5058};
WEAK symbol<connstate_t> connectionState{0x1060214}; WEAK symbol<connstate_t> connectionState{0x1060214};
WEAK symbol<dvar_t> cl_paused{0x1CE6190}; WEAK symbol<dvar_t> cl_paused{0x1CE6190};
} } // namespace game

View File

@ -1,35 +1,21 @@
#pragma once #pragma once
class component_interface class component_interface {
{
public: public:
virtual ~component_interface() virtual ~component_interface() {}
{
}
virtual void post_start() virtual void post_start() {}
{
}
virtual void post_load() virtual void post_load() {}
{
}
virtual void pre_destroy() virtual void pre_destroy() {}
{
}
virtual void post_unpack() virtual void post_unpack() {}
{
}
virtual void* load_import([[maybe_unused]] const std::string& library, [[maybe_unused]] const std::string& function) virtual void* load_import([[maybe_unused]] const std::string& library,
{ [[maybe_unused]] const std::string& function) {
return nullptr; return nullptr;
} }
virtual bool is_supported() virtual bool is_supported() { return true; }
{
return true;
}
}; };

View File

@ -1,105 +1,89 @@
#include <stdinc.hpp> #include <stdinc.hpp>
#include "component_loader.hpp" #include "component_loader.hpp"
void component_loader::register_component(std::unique_ptr<component_interface>&& component_) void component_loader::register_component(
{ std::unique_ptr<component_interface>&& component_) {
get_components().push_back(std::move(component_)); get_components().push_back(std::move(component_));
} }
bool component_loader::post_start() bool component_loader::post_start() {
{
static auto handled = false; static auto handled = false;
if (handled) return true; if (handled)
return true;
handled = true; handled = true;
try try {
{ for (const auto& component_ : get_components()) {
for (const auto& component_ : get_components())
{
component_->post_start(); component_->post_start();
} }
} } catch (premature_shutdown_trigger&) {
catch (premature_shutdown_trigger&)
{
return false; return false;
} }
return true; return true;
} }
bool component_loader::post_load() bool component_loader::post_load() {
{
static auto handled = false; static auto handled = false;
if (handled) return true; if (handled)
return true;
handled = true; handled = true;
clean(); clean();
try try {
{ for (const auto& component_ : get_components()) {
for (const auto& component_ : get_components())
{
component_->post_load(); component_->post_load();
} }
} } catch (premature_shutdown_trigger&) {
catch (premature_shutdown_trigger&)
{
return false; return false;
} }
return true; return true;
} }
void component_loader::post_unpack() void component_loader::post_unpack() {
{
static auto handled = false; static auto handled = false;
if (handled) return; if (handled)
return;
handled = true; handled = true;
for (const auto& component_ : get_components()) for (const auto& component_ : get_components()) {
{
component_->post_unpack(); component_->post_unpack();
} }
} }
void component_loader::pre_destroy() void component_loader::pre_destroy() {
{
static auto handled = false; static auto handled = false;
if (handled) return; if (handled)
return;
handled = true; handled = true;
for (const auto& component_ : get_components()) for (const auto& component_ : get_components()) {
{
component_->pre_destroy(); component_->pre_destroy();
} }
} }
void component_loader::clean() void component_loader::clean() {
{
auto& components = get_components(); auto& components = get_components();
for (auto i = components.begin(); i != components.end();) for (auto i = components.begin(); i != components.end();) {
{ if (!(*i)->is_supported()) {
if (!(*i)->is_supported())
{
(*i)->pre_destroy(); (*i)->pre_destroy();
i = components.erase(i); i = components.erase(i);
} } else {
else
{
++i; ++i;
} }
} }
} }
void* component_loader::load_import(const std::string& library, const std::string& function) void* component_loader::load_import(const std::string& library,
{ const std::string& function) {
void* function_ptr = nullptr; void* function_ptr = nullptr;
for (const auto& component_ : get_components()) for (const auto& component_ : get_components()) {
{ auto* const component_function_ptr =
auto* const component_function_ptr = component_->load_import(library, function); component_->load_import(library, function);
if (component_function_ptr) if (component_function_ptr) {
{
function_ptr = component_function_ptr; function_ptr = component_function_ptr;
} }
} }
@ -107,18 +91,18 @@ void* component_loader::load_import(const std::string& library, const std::strin
return function_ptr; return function_ptr;
} }
void component_loader::trigger_premature_shutdown() void component_loader::trigger_premature_shutdown() {
{
throw premature_shutdown_trigger(); throw premature_shutdown_trigger();
} }
std::vector<std::unique_ptr<component_interface>>& component_loader::get_components() std::vector<std::unique_ptr<component_interface>>&
{ component_loader::get_components() {
using component_vector = std::vector<std::unique_ptr<component_interface>>; using component_vector = std::vector<std::unique_ptr<component_interface>>;
using component_vector_container = std::unique_ptr<component_vector, std::function<void(component_vector*)>>; using component_vector_container =
std::unique_ptr<component_vector, std::function<void(component_vector*)>>;
static component_vector_container components(new component_vector, [](component_vector* component_vector) static component_vector_container components(
{ new component_vector, [](component_vector* component_vector) {
pre_destroy(); pre_destroy();
delete component_vector; delete component_vector;
}); });

View File

@ -1,36 +1,25 @@
#pragma once #pragma once
#include "component_interface.hpp" #include "component_interface.hpp"
class component_loader final class component_loader final {
{
public: public:
class premature_shutdown_trigger final : public std::exception class premature_shutdown_trigger final : public std::exception {
{ [[nodiscard]] const char* what() const noexcept override {
[[nodiscard]] const char* what() const noexcept override
{
return "Premature shutdown requested"; return "Premature shutdown requested";
} }
}; };
template <typename T> template <typename T> class installer final {
class installer final static_assert(std::is_base_of<component_interface, T>::value,
{ "component has invalid base class");
static_assert(std::is_base_of<component_interface, T>::value, "component has invalid base class");
public: public:
installer() installer() { register_component(std::make_unique<T>()); }
{
register_component(std::make_unique<T>());
}
}; };
template <typename T> template <typename T> static T* get() {
static T* get() for (const auto& component_ : get_components()) {
{ if (typeid(*component_.get()) == typeid(T)) {
for (const auto& component_ : get_components())
{
if (typeid(*component_.get()) == typeid(T))
{
return reinterpret_cast<T*>(component_.get()); return reinterpret_cast<T*>(component_.get());
} }
} }
@ -38,7 +27,8 @@ public:
return nullptr; return nullptr;
} }
static void register_component(std::unique_ptr<component_interface>&& component); static void
register_component(std::unique_ptr<component_interface>&& component);
static bool post_start(); static bool post_start();
static bool post_load(); static bool post_load();
@ -46,7 +36,8 @@ public:
static void pre_destroy(); static void pre_destroy();
static void clean(); static void clean();
static void* load_import(const std::string& library, const std::string& function); static void* load_import(const std::string& library,
const std::string& function);
static void trigger_premature_shutdown(); static void trigger_premature_shutdown();
@ -55,7 +46,6 @@ private:
}; };
#define REGISTER_COMPONENT(name) \ #define REGISTER_COMPONENT(name) \
namespace \ namespace { \
{ \
static component_loader::installer<name> __component; \ static component_loader::installer<name> __component; \
} }

View File

@ -4,23 +4,21 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <WinSock2.h> #include <WinSock2.h>
#include <windows.h>
#include <vector> #include <algorithm>
#include <cassert> #include <cassert>
#include <functional>
#include <iostream>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <iostream>
#include <algorithm>
#include <functional>
#include <unordered_set>
#include <map>
#include <vector>
#pragma comment(lib, "ntdll.lib") #pragma comment(lib, "ntdll.lib")
using namespace std::literals; using namespace std::literals;
// clang-format off
#include "game/structs.hpp" #include "game/structs.hpp"
#include "game/game.hpp" #include "game/game.hpp"
// clang-format on

View File

@ -2,36 +2,26 @@
#include <mutex> #include <mutex>
namespace utils::concurrency namespace utils::concurrency {
{ template <typename T, typename MutexType = std::mutex> class container {
template <typename T, typename MutexType = std::mutex>
class container
{
public: public:
template <typename R = void, typename F> template <typename R = void, typename F> R access(F&& accessor) const {
R access(F&& accessor) const std::lock_guard<MutexType> _{mutex_};
{ return accessor(object_);
}
template <typename R = void, typename F> R access(F&& accessor) {
std::lock_guard<MutexType> _{mutex_}; std::lock_guard<MutexType> _{mutex_};
return accessor(object_); return accessor(object_);
} }
template <typename R = void, typename F> template <typename R = void, typename F>
R access(F&& accessor) R access_with_lock(F&& accessor) const {
{
std::lock_guard<MutexType> _{mutex_};
return accessor(object_);
}
template <typename R = void, typename F>
R access_with_lock(F&& accessor) const
{
std::unique_lock<MutexType> lock{mutex_}; std::unique_lock<MutexType> lock{mutex_};
return accessor(object_, lock); return accessor(object_, lock);
} }
template <typename R = void, typename F> template <typename R = void, typename F> R access_with_lock(F&& accessor) {
R access_with_lock(F&& accessor)
{
std::unique_lock<MutexType> lock{mutex_}; std::unique_lock<MutexType> lock{mutex_};
return accessor(object_, lock); return accessor(object_, lock);
} }
@ -43,4 +33,4 @@ namespace utils::concurrency
mutable MutexType mutex_{}; mutable MutexType mutex_{};
T object_{}; T object_{};
}; };
} } // namespace utils::concurrency

View File

@ -5,74 +5,49 @@
#include <MinHook.h> #include <MinHook.h>
namespace utils::hook namespace utils::hook {
{ namespace {
namespace [[maybe_unused]] class _ {
{
[[maybe_unused]] class _
{
public: public:
_() _() {
{ if (MH_Initialize() != MH_OK) {
if (MH_Initialize() != MH_OK)
{
throw std::runtime_error("Failed to initialize MinHook"); throw std::runtime_error("Failed to initialize MinHook");
} }
} }
~_() ~_() { MH_Uninitialize(); }
{
MH_Uninitialize();
}
} __; } __;
} } // namespace
detour::detour(const size_t place, void* target) : detour(reinterpret_cast<void*>(place), target) detour::detour(const size_t place, void* target)
{ : detour(reinterpret_cast<void*>(place), target) {}
}
detour::detour(void* place, void* target) detour::detour(void* place, void* target) { this->create(place, target); }
{
this->create(place, target);
}
detour::~detour() detour::~detour() { this->clear(); }
{
this->clear();
}
void detour::enable() const void detour::enable() const { MH_EnableHook(this->place_); }
{
MH_EnableHook(this->place_);
}
void detour::disable() const void detour::disable() const { MH_DisableHook(this->place_); }
{
MH_DisableHook(this->place_);
}
void detour::create(void* place, void* target) void detour::create(void* place, void* target) {
{
this->clear(); this->clear();
this->place_ = place; this->place_ = place;
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) {
{ throw std::runtime_error(
throw std::runtime_error(string::va("Unable to create hook at location: %p", this->place_)); string::va("Unable to create hook at location: %p", this->place_));
} }
this->enable(); this->enable();
} }
void detour::create(const size_t place, void* target) void detour::create(const size_t place, void* target) {
{
this->create(reinterpret_cast<void*>(place), target); this->create(reinterpret_cast<void*>(place), target);
} }
void detour::clear() void detour::clear() {
{ if (this->place_) {
if (this->place_)
{
MH_RemoveHook(this->place_); MH_RemoveHook(this->place_);
} }
@ -80,13 +55,9 @@ namespace utils::hook
this->original_ = nullptr; this->original_ = nullptr;
} }
void* detour::get_original() const void* detour::get_original() const { return this->original_; }
{
return this->original_;
}
void nop(void* place, const size_t length) void nop(void* place, const size_t length) {
{
DWORD old_protect{}; DWORD old_protect{};
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
@ -96,13 +67,11 @@ namespace utils::hook
FlushInstructionCache(GetCurrentProcess(), place, length); FlushInstructionCache(GetCurrentProcess(), place, length);
} }
void nop(const size_t place, const size_t length) void nop(const size_t place, const size_t length) {
{
nop(reinterpret_cast<void*>(place), length); nop(reinterpret_cast<void*>(place), length);
} }
void copy(void* place, const void* data, const size_t length) void copy(void* place, const void* data, const size_t length) {
{
DWORD old_protect{}; DWORD old_protect{};
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
@ -112,42 +81,37 @@ namespace utils::hook
FlushInstructionCache(GetCurrentProcess(), place, length); FlushInstructionCache(GetCurrentProcess(), place, length);
} }
void copy(const size_t place, const void* data, const size_t length) void copy(const size_t place, const void* data, const size_t length) {
{
copy(reinterpret_cast<void*>(place), data, length); copy(reinterpret_cast<void*>(place), data, length);
} }
bool is_relatively_far(const void* pointer, const void* data, const int offset) bool is_relatively_far(const void* pointer, const void* data,
{ const int offset) {
const int64_t diff = size_t(data) - (size_t(pointer) + offset); const int64_t diff = size_t(data) - (size_t(pointer) + offset);
const auto small_diff = int32_t(diff); const auto small_diff = int32_t(diff);
return diff != int64_t(small_diff); return diff != int64_t(small_diff);
} }
void call(void* pointer, void* data) void call(void* pointer, void* data) {
{ if (is_relatively_far(pointer, data)) {
if (is_relatively_far(pointer, data))
{
throw std::runtime_error("Too far away to create 32bit relative branch"); throw std::runtime_error("Too far away to create 32bit relative branch");
} }
auto* patch_pointer = PBYTE(pointer); auto* patch_pointer = PBYTE(pointer);
set<uint8_t>(patch_pointer, 0xE8); set<uint8_t>(patch_pointer, 0xE8);
set<int32_t>(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5))); set<int32_t>(patch_pointer + 1,
int32_t(size_t(data) - (size_t(pointer) + 5)));
} }
void call(const size_t pointer, void* data) void call(const size_t pointer, void* data) {
{
return call(reinterpret_cast<void*>(pointer), data); return call(reinterpret_cast<void*>(pointer), data);
} }
void call(const size_t pointer, const size_t data) void call(const size_t pointer, const size_t data) {
{
return call(pointer, reinterpret_cast<void*>(data)); return call(pointer, reinterpret_cast<void*>(data));
} }
void set(std::uintptr_t address, std::vector<std::uint8_t>&& bytes) void set(std::uintptr_t address, std::vector<std::uint8_t>&& bytes) {
{
DWORD oldProtect = 0; DWORD oldProtect = 0;
auto* place = reinterpret_cast<void*>(address); auto* place = reinterpret_cast<void*>(address);
@ -157,8 +121,7 @@ namespace utils::hook
FlushInstructionCache(GetCurrentProcess(), place, bytes.size()); FlushInstructionCache(GetCurrentProcess(), place, bytes.size());
} }
void set(std::uintptr_t address, void* buffer, size_t size) void set(std::uintptr_t address, void* buffer, size_t size) {
{
DWORD oldProtect = 0; DWORD oldProtect = 0;
auto* place = reinterpret_cast<void*>(address); auto* place = reinterpret_cast<void*>(address);
@ -168,28 +131,28 @@ namespace utils::hook
FlushInstructionCache(GetCurrentProcess(), place, size); FlushInstructionCache(GetCurrentProcess(), place, size);
} }
void jump(std::uintptr_t address, void* destination) void jump(std::uintptr_t address, void* destination) {
{ if (!address)
if (!address) return; return;
std::uint8_t* bytes = new std::uint8_t[5]; std::uint8_t* bytes = new std::uint8_t[5];
*bytes = 0xE9; *bytes = 0xE9;
*reinterpret_cast<std::uint32_t*>(bytes + 1) = CalculateRelativeJMPAddress(address, destination); *reinterpret_cast<std::uint32_t*>(bytes + 1) =
CalculateRelativeJMPAddress(address, destination);
set(address, bytes, 5); set(address, bytes, 5);
delete[] bytes; delete[] bytes;
} }
void redirect_jump(void* pointer, void* data) void redirect_jump(void* pointer, void* data) {
{
char* operand_ptr = static_cast<char*>(pointer) + 2; char* operand_ptr = static_cast<char*>(pointer) + 2;
int new_operand = reinterpret_cast<int>(data) - (reinterpret_cast<int>(pointer) + 6); int new_operand =
reinterpret_cast<int>(data) - (reinterpret_cast<int>(pointer) + 6);
set<int>(operand_ptr, new_operand); set<int>(operand_ptr, new_operand);
} }
void redirect_jump(size_t pointer, void* data) void redirect_jump(size_t pointer, void* data) {
{
redirect_jump(reinterpret_cast<void*>(pointer), data); redirect_jump(reinterpret_cast<void*>(pointer), data);
} }
} } // namespace utils::hook

View File

@ -1,27 +1,21 @@
#pragma once #pragma once
#include "signature.hpp" #include "signature.hpp"
#define CalculateRelativeJMPAddress(X, Y) (((std::uintptr_t)Y - (std::uintptr_t)X) - 5) #define CalculateRelativeJMPAddress(X, Y) \
(((std::uintptr_t)Y - (std::uintptr_t)X) - 5)
namespace utils::hook namespace utils::hook {
{ class detour {
class detour
{
public: public:
detour() = default; detour() = default;
detour(void* place, void* target); detour(void* place, void* target);
detour(size_t place, void* target); detour(size_t place, void* target);
~detour(); ~detour();
detour(detour&& other) noexcept detour(detour&& other) noexcept { this->operator=(std::move(other)); }
{
this->operator=(std::move(other));
}
detour& operator= (detour&& other) noexcept detour& operator=(detour&& other) noexcept {
{ if (this != &other) {
if (this != &other)
{
this->~detour(); this->~detour();
this->place_ = other.place_; this->place_ = other.place_;
@ -44,15 +38,11 @@ namespace utils::hook
void create(size_t place, void* target); void create(size_t place, void* target);
void clear(); void clear();
template <typename T> template <typename T> T* get() const {
T* get() const
{
return static_cast<T*>(this->get_original()); return static_cast<T*>(this->get_original());
} }
template <typename T, typename... Args> template <typename T, typename... Args> T invoke(Args... args) {
T invoke(Args... args)
{
return static_cast<T (*)(Args...)>(this->get_original())(args...); return static_cast<T (*)(Args...)>(this->get_original())(args...);
} }
@ -80,17 +70,13 @@ namespace utils::hook
void redirect_jump(void* pointer, void* data); void redirect_jump(void* pointer, void* data);
void redirect_jump(size_t pointer, void* data); void redirect_jump(size_t pointer, void* data);
template <typename T> template <typename T> T extract(void* address) {
T extract(void* address)
{
const auto data = static_cast<uint8_t*>(address); const auto data = static_cast<uint8_t*>(address);
const auto offset = *reinterpret_cast<int32_t*>(data); const auto offset = *reinterpret_cast<int32_t*>(data);
return reinterpret_cast<T>(data + offset + 4); return reinterpret_cast<T>(data + offset + 4);
} }
template <typename T> template <typename T> static void set(void* place, T value) {
static void set(void* place, T value)
{
DWORD old_protect; DWORD old_protect;
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
@ -100,21 +86,17 @@ namespace utils::hook
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
} }
template <typename T> template <typename T> static void set(const size_t place, T value) {
static void set(const size_t place, T value)
{
return set<T>(reinterpret_cast<void*>(place), value); return set<T>(reinterpret_cast<void*>(place), value);
} }
template <typename T, typename... Args> template <typename T, typename... Args>
static T invoke(size_t func, Args ... args) static T invoke(size_t func, Args... args) {
{
return reinterpret_cast<T (*)(Args...)>(func)(args...); return reinterpret_cast<T (*)(Args...)>(func)(args...);
} }
template <typename T, typename... Args> template <typename T, typename... Args>
static T invoke(void* func, Args ... args) static T invoke(void* func, Args... args) {
{
return static_cast<T (*)(Args...)>(func)(args...); return static_cast<T (*)(Args...)>(func)(args...);
} }
} } // namespace utils::hook

View File

@ -3,58 +3,44 @@
#include "info_string.hpp" #include "info_string.hpp"
#include "string.hpp" #include "string.hpp"
namespace utils namespace utils {
{ info_string::info_string(const std::string& buffer) { this->parse(buffer); }
info_string::info_string(const std::string& buffer)
{
this->parse(buffer);
}
info_string::info_string(const std::string_view& buffer) info_string::info_string(const std::string_view& buffer)
: info_string(std::string{buffer}) : info_string(std::string{buffer}) {}
{
}
void info_string::set(const std::string& key, const std::string& value) void info_string::set(const std::string& key, const std::string& value) {
{
this->key_value_pairs_[key] = value; this->key_value_pairs_[key] = value;
} }
std::string info_string::get(const std::string& key) const std::string info_string::get(const std::string& key) const {
{
const auto value = this->key_value_pairs_.find(key); const auto value = this->key_value_pairs_.find(key);
if (value != this->key_value_pairs_.end()) if (value != this->key_value_pairs_.end()) {
{
return value->second; return value->second;
} }
return ""; return {};
} }
void info_string::parse(std::string buffer) void info_string::parse(std::string buffer) {
{ if (buffer[0] == '\\') {
if (buffer[0] == '\\')
{
buffer = buffer.substr(1); buffer = buffer.substr(1);
} }
auto key_values = string::split(buffer, '\\'); const auto key_values = string::split(buffer, '\\');
for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1); i += 2) for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1);
{ i += 2) {
const auto& key = key_values[i]; const auto& key = key_values[i];
const auto& value = key_values[i + 1]; const auto& value = key_values[i + 1];
this->key_value_pairs_[key] = value; this->key_value_pairs_[key] = value;
} }
} }
std::string info_string::build() const std::string info_string::build() const {
{
//auto first = true;
std::string info_string; std::string info_string;
for (auto i = this->key_value_pairs_.begin(); i != this->key_value_pairs_.end(); ++i) for (auto i = this->key_value_pairs_.begin();
{ i != this->key_value_pairs_.end(); ++i) {
//if (first) first = false; info_string.append("\\");
/*else*/ info_string.append("\\");
info_string.append(i->first); // Key info_string.append(i->first); // Key
info_string.append("\\"); info_string.append("\\");
@ -63,4 +49,4 @@ namespace utils
return info_string; return info_string;
} }
} } // namespace utils

View File

@ -3,22 +3,20 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
namespace utils namespace utils {
{ class info_string {
class info_string
{
public: public:
info_string() = default; info_string() = default;
info_string(const std::string& buffer); explicit info_string(const std::string& buffer);
info_string(const std::string_view& buffer); explicit info_string(const std::string_view& buffer);
void set(const std::string& key, const std::string& value); void set(const std::string& key, const std::string& value);
std::string get(const std::string& key) const; [[nodiscard]] std::string get(const std::string& key) const;
std::string build() const; [[nodiscard]] std::string build() const;
private: private:
std::unordered_map<std::string, std::string> key_value_pairs_{}; std::unordered_map<std::string, std::string> key_value_pairs_;
void parse(std::string buffer); void parse(std::string buffer);
}; };
} } // namespace utils

View File

@ -3,46 +3,36 @@
#include "memory.hpp" #include "memory.hpp"
#include "nt.hpp" #include "nt.hpp"
namespace utils namespace utils {
{
memory::allocator memory::mem_allocator_; memory::allocator memory::mem_allocator_;
memory::allocator::~allocator() memory::allocator::~allocator() { this->clear(); }
{
this->clear();
}
void memory::allocator::clear() void memory::allocator::clear() {
{
std::lock_guard _(this->mutex_); std::lock_guard _(this->mutex_);
for (auto& data : this->pool_) for (const auto& data : this->pool_) {
{
memory::free(data); memory::free(data);
} }
this->pool_.clear(); this->pool_.clear();
} }
void memory::allocator::free(void* data) void memory::allocator::free(void* data) {
{
std::lock_guard _(this->mutex_); std::lock_guard _(this->mutex_);
const auto j = std::find(this->pool_.begin(), this->pool_.end(), data); const auto j = std::find(this->pool_.begin(), this->pool_.end(), data);
if (j != this->pool_.end()) if (j != this->pool_.end()) {
{
memory::free(data); memory::free(data);
this->pool_.erase(j); this->pool_.erase(j);
} }
} }
void memory::allocator::free(const void* data) void memory::allocator::free(const void* data) {
{
this->free(const_cast<void*>(data)); this->free(const_cast<void*>(data));
} }
void* memory::allocator::allocate(const size_t length) void* memory::allocator::allocate(const size_t length) {
{
std::lock_guard _(this->mutex_); std::lock_guard _(this->mutex_);
const auto data = memory::allocate(length); const auto data = memory::allocate(length);
@ -50,13 +40,9 @@ namespace utils
return data; return data;
} }
bool memory::allocator::empty() const bool memory::allocator::empty() const { return this->pool_.empty(); }
{
return this->pool_.empty();
}
char* memory::allocator::duplicate_string(const std::string& string) char* memory::allocator::duplicate_string(const std::string& string) {
{
std::lock_guard _(this->mutex_); std::lock_guard _(this->mutex_);
const auto data = memory::duplicate_string(string); const auto data = memory::duplicate_string(string);
@ -64,39 +50,27 @@ namespace utils
return data; return data;
} }
void* memory::allocate(const size_t length) void* memory::allocate(const size_t length) { return calloc(length, 1); }
{
return calloc(length, 1);
}
char* memory::duplicate_string(const std::string& string) char* memory::duplicate_string(const std::string& string) {
{
const auto new_string = allocate_array<char>(string.size() + 1); const auto new_string = allocate_array<char>(string.size() + 1);
std::memcpy(new_string, string.data(), string.size()); std::memcpy(new_string, string.data(), string.size());
return new_string; return new_string;
} }
void memory::free(void* data) void memory::free(void* data) {
{ if (data) {
if (data)
{
::free(data); ::free(data);
} }
} }
void memory::free(const void* data) void memory::free(const void* data) { free(const_cast<void*>(data)); }
{
free(const_cast<void*>(data));
}
bool memory::is_set(const void* mem, const char chr, const size_t length) bool memory::is_set(const void* mem, const char chr, const size_t length) {
{
const auto mem_arr = static_cast<const char*>(mem); const auto mem_arr = static_cast<const char*>(mem);
for (size_t i = 0; i < length; ++i) for (size_t i = 0; i < length; ++i) {
{ if (mem_arr[i] != chr) {
if (mem_arr[i] != chr)
{
return false; return false;
} }
} }
@ -104,53 +78,51 @@ namespace utils
return true; return true;
} }
bool memory::is_bad_read_ptr(const void* ptr) bool memory::is_bad_read_ptr(const void* ptr) {
{
MEMORY_BASIC_INFORMATION mbi = {}; MEMORY_BASIC_INFORMATION mbi = {};
if (VirtualQuery(ptr, &mbi, sizeof(mbi))) if (VirtualQuery(ptr, &mbi, sizeof(mbi))) {
{ const DWORD mask =
const DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ |
PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY);
auto b = !(mbi.Protect & mask); auto b = !(mbi.Protect & mask);
// check the page is not a guard page // check the page is not a guard page
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS))
b = true;
return b; return b;
} }
return true; return true;
} }
bool memory::is_bad_code_ptr(const void* ptr) bool memory::is_bad_code_ptr(const void* ptr) {
{
MEMORY_BASIC_INFORMATION mbi = {}; MEMORY_BASIC_INFORMATION mbi = {};
if (VirtualQuery(ptr, &mbi, sizeof(mbi))) if (VirtualQuery(ptr, &mbi, sizeof(mbi))) {
{ const DWORD mask =
const DWORD mask = (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY);
auto b = !(mbi.Protect & mask); auto b = !(mbi.Protect & mask);
// check the page is not a guard page // check the page is not a guard page
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS))
b = true;
return b; return b;
} }
return true; return true;
} }
bool memory::is_rdata_ptr(void* pointer) bool memory::is_rdata_ptr(void* ptr) {
{
const std::string rdata = ".rdata"; const std::string rdata = ".rdata";
const auto pointer_lib = utils::nt::library::get_by_address(pointer); const auto pointer_lib = utils::nt::library::get_by_address(ptr);
for (const auto& section : pointer_lib.get_section_headers()) for (const auto& section : pointer_lib.get_section_headers()) {
{ constexpr auto size = sizeof(section->Name);
const auto size = sizeof(section->Name);
char name[size + 1]; char name[size + 1];
name[size] = 0; name[size] = 0;
std::memcpy(name, section->Name, size); std::memcpy(name, section->Name, size);
if (name == rdata) if (name == rdata) {
{ const auto target = size_t(ptr);
const auto target = size_t(pointer); const size_t source_start =
const size_t source_start = size_t(pointer_lib.get_ptr()) + section->PointerToRawData; size_t(pointer_lib.get_ptr()) + section->PointerToRawData;
const size_t source_end = source_start + section->SizeOfRawData; const size_t source_end = source_start + section->SizeOfRawData;
return target >= source_start && target <= source_end; return target >= source_start && target <= source_end;
@ -160,8 +132,5 @@ namespace utils
return false; return false;
} }
memory::allocator* memory::get_allocator() memory::allocator* memory::get_allocator() { return &memory::mem_allocator_; }
{ } // namespace utils
return &memory::mem_allocator_;
}
}

View File

@ -3,13 +3,10 @@
#include <mutex> #include <mutex>
#include <vector> #include <vector>
namespace utils namespace utils {
{ class memory final {
class memory final
{
public: public:
class allocator final class allocator final {
{
public: public:
~allocator(); ~allocator();
@ -21,15 +18,9 @@ namespace utils
void* allocate(size_t length); void* allocate(size_t length);
template <typename T> template <typename T> T* allocate() { return this->allocate_array<T>(1); }
inline T* allocate()
{
return this->allocate_array<T>(1);
}
template <typename T> template <typename T> T* allocate_array(const size_t count = 1) {
inline T* allocate_array(const size_t count = 1)
{
return static_cast<T*>(this->allocate(count * sizeof(T))); return static_cast<T*>(this->allocate(count * sizeof(T)));
} }
@ -44,15 +35,9 @@ namespace utils
static void* allocate(size_t length); static void* allocate(size_t length);
template <typename T> template <typename T> static T* allocate() { return allocate_array<T>(1); }
static inline T* allocate()
{
return allocate_array<T>(1);
}
template <typename T> template <typename T> static T* allocate_array(const size_t count = 1) {
static inline T* allocate_array(const size_t count = 1)
{
return static_cast<T*>(allocate(count * sizeof(T))); return static_cast<T*>(allocate(count * sizeof(T)));
} }
@ -72,4 +57,4 @@ namespace utils
private: private:
static allocator mem_allocator_; static allocator mem_allocator_;
}; };
} } // namespace utils

View File

@ -2,133 +2,117 @@
#include "nt.hpp" #include "nt.hpp"
namespace utils::nt namespace utils::nt {
{ library library::load(const std::string& name) {
library library::load(const std::string& name)
{
return library(LoadLibraryA(name.data())); return library(LoadLibraryA(name.data()));
} }
library library::load(const std::filesystem::path& path) library library::load(const std::filesystem::path& path) {
{
return library::load(path.generic_string()); return library::load(path.generic_string());
} }
library library::get_by_address(void* address) library library::get_by_address(void* address) {
{
HMODULE handle = nullptr; HMODULE handle = nullptr;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCSTR>(address), &handle); GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
static_cast<LPCSTR>(address), &handle);
return library(handle); return library(handle);
} }
library::library() library::library() { this->module_ = GetModuleHandleA(nullptr); }
{
this->module_ = GetModuleHandleA(nullptr);
}
library::library(const std::string& name) library::library(const std::string& name) {
{
this->module_ = GetModuleHandleA(name.data()); this->module_ = GetModuleHandleA(name.data());
} }
library::library(const HMODULE handle) library::library(const HMODULE handle) { this->module_ = handle; }
{
this->module_ = handle;
}
bool library::operator==(const library& obj) const bool library::operator==(const library& obj) const {
{
return this->module_ == obj.module_; return this->module_ == obj.module_;
} }
library::operator bool() const library::operator bool() const { return this->is_valid(); }
{
return this->is_valid(); library::operator HMODULE() const { return this->get_handle(); }
PIMAGE_NT_HEADERS library::get_nt_headers() const {
if (!this->is_valid())
return nullptr;
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() +
this->get_dos_header()->e_lfanew);
} }
library::operator HMODULE() const PIMAGE_DOS_HEADER library::get_dos_header() const {
{
return this->get_handle();
}
PIMAGE_NT_HEADERS library::get_nt_headers() const
{
if (!this->is_valid()) return nullptr;
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
}
PIMAGE_DOS_HEADER library::get_dos_header() const
{
return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr()); return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr());
} }
PIMAGE_OPTIONAL_HEADER library::get_optional_header() const PIMAGE_OPTIONAL_HEADER library::get_optional_header() const {
{ if (!this->is_valid())
if (!this->is_valid()) return nullptr; return nullptr;
return &this->get_nt_headers()->OptionalHeader; return &this->get_nt_headers()->OptionalHeader;
} }
std::vector<PIMAGE_SECTION_HEADER> library::get_section_headers() const std::vector<PIMAGE_SECTION_HEADER> library::get_section_headers() const {
{
std::vector<PIMAGE_SECTION_HEADER> headers; std::vector<PIMAGE_SECTION_HEADER> headers;
auto nt_headers = this->get_nt_headers(); auto nt_headers = this->get_nt_headers();
auto section = IMAGE_FIRST_SECTION(nt_headers); auto section = IMAGE_FIRST_SECTION(nt_headers);
for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section) for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections;
{ ++i, ++section) {
if (section) headers.push_back(section); if (section)
else OutputDebugStringA("There was an invalid section :O"); headers.push_back(section);
else
OutputDebugStringA("There was an invalid section :O");
} }
return headers; return headers;
} }
std::uint8_t* library::get_ptr() const std::uint8_t* library::get_ptr() const {
{
return reinterpret_cast<std::uint8_t*>(this->module_); return reinterpret_cast<std::uint8_t*>(this->module_);
} }
void library::unprotect() const void library::unprotect() const {
{ if (!this->is_valid())
if (!this->is_valid()) return; return;
DWORD protection; DWORD protection;
VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE, VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage,
&protection); PAGE_EXECUTE_READWRITE, &protection);
} }
size_t library::get_relative_entry_point() const size_t library::get_relative_entry_point() const {
{ if (!this->is_valid())
if (!this->is_valid()) return 0; return 0;
return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint;
} }
void* library::get_entry_point() const void* library::get_entry_point() const {
{ if (!this->is_valid())
if (!this->is_valid()) return nullptr; return nullptr;
return this->get_ptr() + this->get_relative_entry_point(); return this->get_ptr() + this->get_relative_entry_point();
} }
bool library::is_valid() const bool library::is_valid() const {
{ return this->module_ != nullptr &&
return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE;
} }
std::string library::get_name() const std::string library::get_name() const {
{ if (!this->is_valid())
if (!this->is_valid()) return ""; return "";
auto path = this->get_path(); auto path = this->get_path();
const auto pos = path.find_last_of("/\\"); const auto pos = path.find_last_of("/\\");
if (pos == std::string::npos) return path; if (pos == std::string::npos)
return path;
return path.substr(pos + 1); return path.substr(pos + 1);
} }
std::string library::get_path() const std::string library::get_path() const {
{ if (!this->is_valid())
if (!this->is_valid()) return ""; return "";
char name[MAX_PATH] = {0}; char name[MAX_PATH] = {0};
GetModuleFileNameA(this->module_, name, sizeof name); GetModuleFileNameA(this->module_, name, sizeof name);
@ -136,62 +120,63 @@ namespace utils::nt
return name; return name;
} }
std::string library::get_folder() const std::string library::get_folder() const {
{ if (!this->is_valid())
if (!this->is_valid()) return ""; return "";
const auto path = std::filesystem::path(this->get_path()); const auto path = std::filesystem::path(this->get_path());
return path.parent_path().generic_string(); return path.parent_path().generic_string();
} }
void library::free() void library::free() {
{ if (this->is_valid()) {
if (this->is_valid())
{
FreeLibrary(this->module_); FreeLibrary(this->module_);
this->module_ = nullptr; this->module_ = nullptr;
} }
} }
HMODULE library::get_handle() const HMODULE library::get_handle() const { return this->module_; }
{
return this->module_;
}
void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const void** library::get_iat_entry(const std::string& module_name,
{ const std::string& proc_name) const {
if (!this->is_valid()) return nullptr; if (!this->is_valid())
return nullptr;
const library other_module(module_name); const library other_module(module_name);
if (!other_module.is_valid()) return nullptr; if (!other_module.is_valid())
return nullptr;
auto* const target_function = other_module.get_proc<void*>(proc_name); auto* const target_function = other_module.get_proc<void*>(proc_name);
if (!target_function) return nullptr; if (!target_function)
return nullptr;
auto* header = this->get_optional_header(); auto* header = this->get_optional_header();
if (!header) return nullptr; if (!header)
return nullptr;
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); this->get_ptr() +
header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (import_descriptor->Name) while (import_descriptor->Name) {
{ if (!_stricmp(
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data())) reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name),
{ module_name.data())) {
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor-> auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(
OriginalFirstThunk + this->get_ptr()); import_descriptor->OriginalFirstThunk + this->get_ptr());
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->FirstThunk + this-> auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(
get_ptr()); import_descriptor->FirstThunk + this->get_ptr());
while (original_thunk_data->u1.AddressOfData) while (original_thunk_data->u1.AddressOfData) {
{ const size_t ordinal_number =
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF; original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
if (ordinal_number > 0xFFFF) continue; if (ordinal_number > 0xFFFF)
continue;
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) == if (GetProcAddress(other_module.module_,
target_function) reinterpret_cast<char*>(ordinal_number)) ==
{ target_function) {
return reinterpret_cast<void**>(&thunk_data->u1.Function); return reinterpret_cast<void**>(&thunk_data->u1.Function);
} }
@ -208,27 +193,27 @@ namespace utils::nt
return nullptr; return nullptr;
} }
void raise_hard_exception() void raise_hard_exception() {
{
int data = false; int data = false;
const library ntdll("ntdll.dll"); const library ntdll("ntdll.dll");
ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data); ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data); ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr,
6, &data);
} }
std::string load_resource(const int id) std::string load_resource(const int id) {
{
auto* const res = FindResource(library(), MAKEINTRESOURCE(id), RT_RCDATA); auto* const res = FindResource(library(), MAKEINTRESOURCE(id), RT_RCDATA);
if (!res) return {}; if (!res)
return {};
auto* const handle = LoadResource(nullptr, res); auto* const handle = LoadResource(nullptr, res);
if (!handle) return {}; if (!handle)
return {};
return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res)); return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res));
} }
void relaunch_self() void relaunch_self() {
{
const utils::nt::library self; const utils::nt::library self;
STARTUPINFOA startup_info; STARTUPINFOA startup_info;
@ -242,15 +227,16 @@ namespace utils::nt
GetCurrentDirectoryA(sizeof(current_dir), current_dir); GetCurrentDirectoryA(sizeof(current_dir), current_dir);
auto* const command_line = GetCommandLineA(); auto* const command_line = GetCommandLineA();
CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false, NULL, nullptr, current_dir, CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false,
&startup_info, &process_info); NULL, nullptr, current_dir, &startup_info, &process_info);
if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread); if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE)
if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess); CloseHandle(process_info.hThread);
if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE)
CloseHandle(process_info.hProcess);
} }
void terminate(const uint32_t code) void terminate(const uint32_t code) {
{
TerminateProcess(GetCurrentProcess(), code); TerminateProcess(GetCurrentProcess(), code);
} }
} } // namespace utils::nt

View File

@ -12,14 +12,12 @@
#undef min #undef min
#endif #endif
#include <string>
#include <functional>
#include <filesystem> #include <filesystem>
#include <functional>
#include <string>
namespace utils::nt namespace utils::nt {
{ class library final {
class library final
{
public: public:
static library load(const std::string& name); static library load(const std::string& name);
static library load(const std::filesystem::path& path); static library load(const std::filesystem::path& path);
@ -29,9 +27,7 @@ namespace utils::nt
explicit library(const std::string& name); explicit library(const std::string& name);
explicit library(HMODULE handle); explicit library(HMODULE handle);
library(const library& a) : module_(a.module_) library(const library& a) : module_(a.module_) {}
{
}
bool operator!=(const library& obj) const { return !(*this == obj); }; bool operator!=(const library& obj) const { return !(*this == obj); };
bool operator==(const library& obj) const; bool operator==(const library& obj) const;
@ -52,41 +48,40 @@ namespace utils::nt
HMODULE get_handle() const; HMODULE get_handle() const;
template <typename T> template <typename T> T get_proc(const std::string& process) const {
T get_proc(const std::string& process) const if (!this->is_valid())
{ T{};
if (!this->is_valid()) T{};
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data())); return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
} }
template <typename T> template <typename T> std::function<T> get(const std::string& process) const {
std::function<T> get(const std::string& process) const if (!this->is_valid())
{ return std::function<T>();
if (!this->is_valid()) return std::function<T>();
return static_cast<T*>(this->get_proc<void*>(process)); return static_cast<T*>(this->get_proc<void*>(process));
} }
template <typename T, typename... Args> template <typename T, typename... Args>
T invoke(const std::string& process, Args ... args) const T invoke(const std::string& process, Args... args) const {
{
auto method = this->get<T(__cdecl)(Args...)>(process); auto method = this->get<T(__cdecl)(Args...)>(process);
if (method) return method(args...); if (method)
return method(args...);
return T(); return T();
} }
template <typename T, typename... Args> template <typename T, typename... Args>
T invoke_pascal(const std::string& process, Args ... args) const T invoke_pascal(const std::string& process, Args... args) const {
{
auto method = this->get<T(__stdcall)(Args...)>(process); auto method = this->get<T(__stdcall)(Args...)>(process);
if (method) return method(args...); if (method)
return method(args...);
return T(); return T();
} }
template <typename T, typename... Args> template <typename T, typename... Args>
T invoke_this(const std::string& process, void* this_ptr, Args ... args) const T invoke_this(const std::string& process, void* this_ptr,
{ Args... args) const {
auto method = this->get<T(__thiscall)(void*, Args...)>(this_ptr, process); auto method = this->get<T(__thiscall)(void*, Args...)>(this_ptr, process);
if (method) return method(args...); if (method)
return method(args...);
return T(); return T();
} }
@ -96,7 +91,8 @@ namespace utils::nt
PIMAGE_DOS_HEADER get_dos_header() const; PIMAGE_DOS_HEADER get_dos_header() const;
PIMAGE_OPTIONAL_HEADER get_optional_header() const; PIMAGE_OPTIONAL_HEADER get_optional_header() const;
void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const; void** get_iat_entry(const std::string& module_name,
const std::string& proc_name) const;
private: private:
HMODULE module_; HMODULE module_;
@ -107,4 +103,4 @@ namespace utils::nt
void relaunch_self(); void relaunch_self();
__declspec(noreturn) void terminate(uint32_t code = 0); __declspec(noreturn) void terminate(uint32_t code = 0);
} } // namespace utils::nt

View File

@ -5,41 +5,34 @@
#include <intrin.h> #include <intrin.h>
namespace utils::hook namespace utils::hook {
{ void signature::load_pattern(const std::string& pattern) {
void signature::load_pattern(const std::string& pattern)
{
this->mask_.clear(); this->mask_.clear();
this->pattern_.clear(); this->pattern_.clear();
uint8_t nibble = 0; uint8_t nibble = 0;
auto has_nibble = false; auto has_nibble = false;
for (auto val : pattern) for (auto val : pattern) {
{ if (val == ' ')
if (val == ' ') continue; continue;
if (val == '?') if (val == '?') {
{
this->mask_.push_back(val); this->mask_.push_back(val);
this->pattern_.push_back(0); this->pattern_.push_back(0);
} } else {
else if ((val < '0' || val > '9') && (val < 'A' || val > 'F') &&
{ (val < 'a' || val > 'f')) {
if ((val < '0' || val > '9') && (val < 'A' || val > 'F') && (val < 'a' || val > 'f'))
{
throw std::runtime_error("Invalid pattern"); throw std::runtime_error("Invalid pattern");
} }
char str[] = {val, 0}; char str[] = {val, 0};
const auto current_nibble = static_cast<uint8_t>(strtol(str, nullptr, 16)); const auto current_nibble =
static_cast<uint8_t>(strtol(str, nullptr, 16));
if (!has_nibble) if (!has_nibble) {
{
has_nibble = true; has_nibble = true;
nibble = current_nibble; nibble = current_nibble;
} } else {
else
{
has_nibble = false; has_nibble = false;
const uint8_t byte = current_nibble | (nibble << 4); const uint8_t byte = current_nibble | (nibble << 4);
@ -49,51 +42,44 @@ namespace utils::hook
} }
} }
while (!this->mask_.empty() && this->mask_.back() == '?') while (!this->mask_.empty() && this->mask_.back() == '?') {
{
this->mask_.pop_back(); this->mask_.pop_back();
this->pattern_.pop_back(); this->pattern_.pop_back();
} }
if (this->has_sse_support()) if (this->has_sse_support()) {
{ while (this->pattern_.size() < 16) {
while (this->pattern_.size() < 16)
{
this->pattern_.push_back(0); this->pattern_.push_back(0);
} }
} }
if (has_nibble) if (has_nibble) {
{
throw std::runtime_error("Invalid pattern"); throw std::runtime_error("Invalid pattern");
} }
} }
std::vector<size_t> signature::process_range(uint8_t* start, const size_t length) const std::vector<size_t> signature::process_range(uint8_t* start,
{ const size_t length) const {
if (this->has_sse_support()) return this->process_range_vectorized(start, length); if (this->has_sse_support())
return this->process_range_vectorized(start, length);
return this->process_range_linear(start, length); return this->process_range_linear(start, length);
} }
std::vector<size_t> signature::process_range_linear(uint8_t* start, const size_t length) const std::vector<size_t> signature::process_range_linear(uint8_t* start,
{ const size_t length) const {
std::vector<size_t> result; std::vector<size_t> result;
for (size_t i = 0; i < length; ++i) for (size_t i = 0; i < length; ++i) {
{
const auto address = start + i; const auto address = start + i;
size_t j = 0; size_t j = 0;
for (; j < this->mask_.size(); ++j) for (; j < this->mask_.size(); ++j) {
{ if (this->mask_[j] != '?' && this->pattern_[j] != address[j]) {
if (this->mask_[j] != '?' && this->pattern_[j] != address[j])
{
break; break;
} }
} }
if (j == this->mask_.size()) if (j == this->mask_.size()) {
{
result.push_back(size_t(address)); result.push_back(size_t(address));
} }
} }
@ -101,31 +87,32 @@ namespace utils::hook
return result; return result;
} }
std::vector<size_t> signature::process_range_vectorized(uint8_t* start, const size_t length) const std::vector<size_t>
{ signature::process_range_vectorized(uint8_t* start, const size_t length) const {
std::vector<size_t> result; std::vector<size_t> result;
__declspec(align(16)) char desired_mask[16] = {0}; __declspec(align(16)) char desired_mask[16] = {0};
for (size_t i = 0; i < this->mask_.size(); i++) for (size_t i = 0; i < this->mask_.size(); i++) {
{
desired_mask[i / 8] |= (this->mask_[i] == '?' ? 0 : 1) << i % 8; desired_mask[i / 8] |= (this->mask_[i] == '?' ? 0 : 1) << i % 8;
} }
const auto mask = _mm_load_si128(reinterpret_cast<const __m128i*>(desired_mask)); const auto mask =
const auto comparand = _mm_loadu_si128(reinterpret_cast<const __m128i*>(this->pattern_.data())); _mm_load_si128(reinterpret_cast<const __m128i*>(desired_mask));
const auto comparand =
_mm_loadu_si128(reinterpret_cast<const __m128i*>(this->pattern_.data()));
for (size_t i = 0; i < length; ++i) for (size_t i = 0; i < length; ++i) {
{
const auto address = start + i; const auto address = start + i;
const auto value = _mm_loadu_si128(reinterpret_cast<const __m128i*>(address)); const auto value =
const auto comparison = _mm_cmpestrm(value, 16, comparand, static_cast<int>(this->mask_.size()), _mm_loadu_si128(reinterpret_cast<const __m128i*>(address));
const auto comparison =
_mm_cmpestrm(value, 16, comparand, static_cast<int>(this->mask_.size()),
_SIDD_CMP_EQUAL_EACH); _SIDD_CMP_EQUAL_EACH);
const auto matches = _mm_and_si128(mask, comparison); const auto matches = _mm_and_si128(mask, comparison);
const auto equivalence = _mm_xor_si128(mask, matches); const auto equivalence = _mm_xor_si128(mask, matches);
if (_mm_test_all_zeros(equivalence, equivalence)) if (_mm_test_all_zeros(equivalence, equivalence)) {
{
result.push_back(size_t(address)); result.push_back(size_t(address));
} }
} }
@ -133,23 +120,21 @@ namespace utils::hook
return result; return result;
} }
signature::signature_result signature::process() const signature::signature_result signature::process() const {
{
const auto range = this->length_ - this->mask_.size(); const auto range = this->length_ - this->mask_.size();
const auto cores = std::max(1u, std::thread::hardware_concurrency()); const auto cores = std::max(1u, std::thread::hardware_concurrency());
if (range <= cores * 10ull) return this->process_serial(); if (range <= cores * 10ull)
return this->process_serial();
return this->process_parallel(); return this->process_parallel();
} }
signature::signature_result signature::process_serial() const signature::signature_result signature::process_serial() const {
{
const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); const auto sub = this->has_sse_support() ? 16 : this->mask_.size();
return {this->process_range(this->start_, this->length_ - sub)}; return {this->process_range(this->start_, this->length_ - sub)};
} }
signature::signature_result signature::process_parallel() const signature::signature_result signature::process_parallel() const {
{
const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); const auto sub = this->has_sse_support() ? 16 : this->mask_.size();
const auto range = this->length_ - sub; const auto range = this->length_ - sub;
const auto cores = std::max(1u, std::thread::hardware_concurrency() / 2); const auto cores = std::max(1u, std::thread::hardware_concurrency() / 2);
@ -160,27 +145,24 @@ namespace utils::hook
std::vector<size_t> result; std::vector<size_t> result;
std::vector<std::thread> threads; std::vector<std::thread> threads;
for (auto i = 0u; i < cores; ++i) for (auto i = 0u; i < cores; ++i) {
{
const auto start = this->start_ + (grid * i); const auto start = this->start_ + (grid * i);
const auto length = (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid; const auto length =
threads.emplace_back([&, start, length]() (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid;
{ threads.emplace_back([&, start, length]() {
auto local_result = this->process_range(start, length); auto local_result = this->process_range(start, length);
if (local_result.empty()) return; if (local_result.empty())
return;
std::lock_guard _(mutex); std::lock_guard _(mutex);
for (const auto& address : local_result) for (const auto& address : local_result) {
{
result.push_back(address); result.push_back(address);
} }
}); });
} }
for (auto& t : threads) for (auto& t : threads) {
{ if (t.joinable()) {
if (t.joinable())
{
t.join(); t.join();
} }
} }
@ -189,15 +171,12 @@ namespace utils::hook
return {std::move(result)}; return {std::move(result)};
} }
bool signature::has_sse_support() const bool signature::has_sse_support() const {
{ if (this->mask_.size() <= 16) {
if (this->mask_.size() <= 16)
{
int cpu_id[4]; int cpu_id[4];
__cpuid(cpu_id, 0); __cpuid(cpu_id, 0);
if (cpu_id[0] >= 1) if (cpu_id[0] >= 1) {
{
__cpuidex(cpu_id, 1, 0); __cpuidex(cpu_id, 1, 0);
return (cpu_id[2] & (1 << 20)) != 0; return (cpu_id[2] & (1 << 20)) != 0;
} }
@ -205,9 +184,9 @@ namespace utils::hook
return false; return false;
} }
} } // namespace utils::hook
utils::hook::signature::signature_result operator"" _sig(const char* str, const size_t len) utils::hook::signature::signature_result operator"" _sig(const char* str,
{ const size_t len) {
return utils::hook::signature(std::string(str, len)).process(); return utils::hook::signature(std::string(str, len)).process();
} }

View File

@ -2,50 +2,37 @@
#include "nt.hpp" #include "nt.hpp"
#include <cstdint> #include <cstdint>
namespace utils::hook namespace utils::hook {
{ class signature final {
class signature final
{
public: public:
class signature_result class signature_result {
{
public: public:
signature_result(std::vector<size_t>&& matches) : matches_(std::move(matches)) signature_result(std::vector<size_t>&& matches)
{ : matches_(std::move(matches)) {}
}
[[nodiscard]] uint8_t* get(const size_t index) const [[nodiscard]] uint8_t* get(const size_t index) const {
{ if (index >= this->count()) {
if (index >= this->count())
{
throw std::runtime_error("Invalid index"); throw std::runtime_error("Invalid index");
} }
return reinterpret_cast<uint8_t*>(this->matches_[index]); return reinterpret_cast<uint8_t*>(this->matches_[index]);
} }
[[nodiscard]] size_t count() const [[nodiscard]] size_t count() const { return this->matches_.size(); }
{
return this->matches_.size();
}
private: private:
std::vector<size_t> matches_; std::vector<size_t> matches_;
}; };
explicit signature(const std::string& pattern, const nt::library library = {}) explicit signature(const std::string& pattern, const nt::library library = {})
: signature(pattern, library.get_ptr(), library.get_optional_header()->SizeOfImage) : signature(pattern, library.get_ptr(),
{ library.get_optional_header()->SizeOfImage) {}
}
signature(const std::string& pattern, void* start, void* end) signature(const std::string& pattern, void* start, void* end)
: signature(pattern, start, size_t(end) - size_t(start)) : signature(pattern, start, size_t(end) - size_t(start)) {}
{
}
signature(const std::string& pattern, void* start, const size_t length) signature(const std::string& pattern, void* start, const size_t length)
: start_(static_cast<uint8_t*>(start)), length_(length) : start_(static_cast<uint8_t*>(start)), length_(length) {
{
this->load_pattern(pattern); this->load_pattern(pattern);
} }
@ -64,10 +51,12 @@ namespace utils::hook
signature_result process_serial() const; signature_result process_serial() const;
std::vector<size_t> process_range(uint8_t* start, size_t length) const; std::vector<size_t> process_range(uint8_t* start, size_t length) const;
std::vector<size_t> process_range_linear(uint8_t* start, size_t length) const; std::vector<size_t> process_range_linear(uint8_t* start, size_t length) const;
std::vector<size_t> process_range_vectorized(uint8_t* start, size_t length) const; std::vector<size_t> process_range_vectorized(uint8_t* start,
size_t length) const;
bool has_sse_support() const; bool has_sse_support() const;
}; };
} } // namespace utils::hook
utils::hook::signature::signature_result operator"" _sig(const char* str, size_t len); utils::hook::signature::signature_result operator"" _sig(const char* str,
size_t len);

View File

@ -1,16 +1,14 @@
#include <stdinc.hpp> #include <stdinc.hpp>
#include "string.hpp" #include "string.hpp"
#include <sstream>
#include <cstdarg>
#include <algorithm> #include <algorithm>
#include <cstdarg>
#include <sstream>
#include "nt.hpp" #include "nt.hpp"
namespace utils::string namespace utils::string {
{ const char* va(const char* fmt, ...) {
const char* va(const char* fmt, ...)
{
static thread_local va_provider<8, 256> provider; static thread_local va_provider<8, 256> provider;
va_list ap; va_list ap;
@ -22,59 +20,50 @@ namespace utils::string
return result; return result;
} }
std::vector<std::string> split(const std::string& s, const char delim) std::vector<std::string> split(const std::string& s, const char delim) {
{
std::stringstream ss(s); std::stringstream ss(s);
std::string item; std::string item;
std::vector<std::string> elems; std::vector<std::string> elems;
while (std::getline(ss, item, delim)) while (std::getline(ss, item, delim)) {
{ elems.push_back(item); // elems.push_back(std::move(item)); // if C++11
elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson) // (based on comment from @mchiasson)
} }
return elems; return elems;
} }
std::string to_lower(std::string text) std::string to_lower(std::string text) {
{ std::transform(text.begin(), text.end(), text.begin(), [](const char input) {
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
{
return static_cast<char>(tolower(input)); return static_cast<char>(tolower(input));
}); });
return text; return text;
} }
std::string to_upper(std::string text) std::string to_upper(std::string text) {
{ std::transform(text.begin(), text.end(), text.begin(), [](const char input) {
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
{
return static_cast<char>(toupper(input)); return static_cast<char>(toupper(input));
}); });
return text; return text;
} }
bool starts_with(const std::string& text, const std::string& substring) bool starts_with(const std::string& text, const std::string& substring) {
{
return text.find(substring) == 0; return text.find(substring) == 0;
} }
bool ends_with(const std::string& text, const std::string& substring) bool ends_with(const std::string& text, const std::string& substring) {
{ if (substring.size() > text.size())
if (substring.size() > text.size()) return false; return false;
return std::equal(substring.rbegin(), substring.rend(), text.rbegin()); return std::equal(substring.rbegin(), substring.rend(), text.rbegin());
} }
std::string dump_hex(const std::string& data, const std::string& separator) std::string dump_hex(const std::string& data, const std::string& separator) {
{
std::string result; std::string result;
for (unsigned int i = 0; i < data.size(); ++i) for (unsigned int i = 0; i < data.size(); ++i) {
{ if (i > 0) {
if (i > 0)
{
result.append(separator); result.append(separator);
} }
@ -84,18 +73,14 @@ namespace utils::string
return result; return result;
} }
std::string get_clipboard_data() std::string get_clipboard_data() {
{ if (OpenClipboard(nullptr)) {
if (OpenClipboard(nullptr))
{
std::string data; std::string data;
auto* const clipboard_data = GetClipboardData(1u); auto* const clipboard_data = GetClipboardData(1u);
if (clipboard_data) if (clipboard_data) {
{
auto* const cliptext = static_cast<char*>(GlobalLock(clipboard_data)); auto* const cliptext = static_cast<char*>(GlobalLock(clipboard_data));
if (cliptext) if (cliptext) {
{
data.append(cliptext); data.append(cliptext);
GlobalUnlock(clipboard_data); GlobalUnlock(clipboard_data);
} }
@ -107,80 +92,40 @@ namespace utils::string
return {}; return {};
} }
void strip(const char* in, char* out, int max) std::string convert(const std::wstring& wstr) {
{
if (!in || !out) return;
max--;
auto current = 0;
while (*in != 0 && current < max)
{
const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48);
if (*in == '^' && (color_index != 7 || *(in + 1) == '7'))
{
++in;
}
else
{
*out = *in;
++out;
++current;
}
++in;
}
*out = '\0';
}
#pragma warning(push)
#pragma warning(disable: 4100)
std::string convert(const std::wstring& wstr)
{
std::string result; std::string result;
result.reserve(wstr.size()); result.reserve(wstr.size());
for (const auto& chr : wstr) for (const auto& chr : wstr) {
{
result.push_back(static_cast<char>(chr)); result.push_back(static_cast<char>(chr));
} }
return result; return result;
} }
std::wstring convert(const std::string& str) std::wstring convert(const std::string& str) {
{
std::wstring result; std::wstring result;
result.reserve(str.size()); result.reserve(str.size());
for (const auto& chr : str) for (const auto& chr : str) {
{
result.push_back(static_cast<wchar_t>(chr)); result.push_back(static_cast<wchar_t>(chr));
} }
return result; return result;
} }
#pragma warning(pop)
std::string replace(std::string str, const std::string& from, const std::string& to) std::string replace(std::string str, const std::string& from,
{ const std::string& to) {
if (from.empty()) if (from.empty()) {
{
return str; return str;
} }
size_t start_pos = 0; size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != std::string::npos) while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
{
str.replace(start_pos, from.length(), to); str.replace(start_pos, from.length(), to);
start_pos += to.length(); start_pos += to.length();
} }
return str; return str;
} }
} // namespace utils::string
bool contains(const std::string& str1, const std::string& str2)
{
return str1.find(str2) != std::string::npos;
}
}

View File

@ -1,39 +1,29 @@
#pragma once #pragma once
#include "memory.hpp" #include "memory.hpp"
#include <cstdint>
#ifndef ARRAYSIZE namespace utils::string {
template <class Type, size_t n> template <size_t Buffers, size_t MinBufferSize> class va_provider final {
size_t ARRAYSIZE(Type (&)[n]) { return n; }
#endif
namespace utils::string
{
template <size_t Buffers, size_t MinBufferSize>
class va_provider final
{
public: public:
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0"); static_assert(Buffers != 0 && MinBufferSize != 0,
"Buffers and MinBufferSize mustn't be 0");
va_provider() : current_buffer_(0) va_provider() : current_buffer_(0) {}
{
}
char* get(const char* format, const va_list ap) char* get(const char* format, const va_list ap) {
{
++this->current_buffer_ %= ARRAYSIZE(this->string_pool_); ++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
auto entry = &this->string_pool_[this->current_buffer_]; auto entry = &this->string_pool_[this->current_buffer_];
if (!entry->size || !entry->buffer) if (!entry->size || !entry->buffer) {
{
throw std::runtime_error("String pool not initialized"); throw std::runtime_error("String pool not initialized");
} }
while (true) while (true) {
{ const int res =
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)
if (res == 0) return nullptr; // Error break; // Success
if (res == 0)
return nullptr; // Error
entry->double_size(); entry->double_size();
} }
@ -42,30 +32,30 @@ namespace utils::string
} }
private: private:
class entry final class entry final {
{
public: public:
explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr) explicit entry(const size_t _size = MinBufferSize)
{ : size(_size), buffer(nullptr) {
if (this->size < MinBufferSize) this->size = MinBufferSize; if (this->size < MinBufferSize)
this->size = MinBufferSize;
this->allocate(); this->allocate();
} }
~entry() ~entry() {
{ if (this->buffer)
if (this->buffer) memory::get_allocator()->free(this->buffer); memory::get_allocator()->free(this->buffer);
this->size = 0; this->size = 0;
this->buffer = nullptr; this->buffer = nullptr;
} }
void allocate() void allocate() {
{ if (this->buffer)
if (this->buffer) memory::get_allocator()->free(this->buffer); memory::get_allocator()->free(this->buffer);
this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1); this->buffer =
memory::get_allocator()->allocate_array<char>(this->size + 1);
} }
void double_size() void double_size() {
{
this->size *= 2; this->size *= 2;
this->allocate(); this->allocate();
} }
@ -87,16 +77,14 @@ namespace utils::string
bool starts_with(const std::string& text, const std::string& substring); bool starts_with(const std::string& text, const std::string& substring);
bool ends_with(const std::string& text, const std::string& substring); bool ends_with(const std::string& text, const std::string& substring);
std::string dump_hex(const std::string& data, const std::string& separator = " "); std::string dump_hex(const std::string& data,
const std::string& separator = " ");
std::string get_clipboard_data(); std::string get_clipboard_data();
void strip(const char* in, char* out, int max);
std::string convert(const std::wstring& wstr); std::string convert(const std::wstring& wstr);
std::wstring convert(const std::string& str); std::wstring convert(const std::string& str);
std::string replace(std::string str, const std::string& from, const std::string& to); std::string replace(std::string str, const std::string& from,
const std::string& to);
bool contains(const std::string& str1, const std::string& str2); } // namespace utils::string
}