diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..0baecbc --- /dev/null +++ b/.clang-format @@ -0,0 +1,11 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +DerivePointerAlignment: false +PointerAlignment: Left +SortIncludes: false + +# Regroup causes unnecessary noise due to clang-format bug. +IncludeBlocks: Preserve + +--- diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..90b0b49 --- /dev/null +++ b/.github/workflows/build.yml @@ -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@v2 + 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.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=x86 build/black-ops-plugin.sln + + - name: Upload ${{matrix.configuration}} binaries + uses: actions/upload-artifact@v2 + with: + name: ${{matrix.configuration}} binaries + path: | + build/bin/x86/${{matrix.configuration}}/black-ops-plugin.dll + build/bin/x86/${{matrix.configuration}}/black-ops-plugin.pdb diff --git a/README.md b/README.md index 4c3af42..e43ed6f 100644 --- a/README.md +++ b/README.md @@ -11,5 +11,5 @@ This software has been created purely for the purposes of academic research. It ## Compile from source - 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`. - Build via solution file found inside the build folder. diff --git a/generate.bat b/generate.bat index 1b7a9f4..3c756a8 100644 --- a/generate.bat +++ b/generate.bat @@ -1,4 +1,4 @@ @echo off echo Updating submodules... call git submodule update --init --recursive -tools\premake5 %* vs2019 +tools\premake5 %* vs2022 diff --git a/src/component/ban.cpp b/src/component/ban.cpp index cdce783..8639eba 100644 --- a/src/component/ban.cpp +++ b/src/component/ban.cpp @@ -3,41 +3,43 @@ #include "loader/component_loader.hpp" #include "utils/hook.hpp" -namespace ban -{ - namespace - { - const game::dvar_t* sv_discord = nullptr; - const game::dvar_t* sv_clanWebsite = nullptr; +namespace ban { +namespace { +const game::dvar_t* sv_discord = nullptr; +const game::dvar_t* sv_clanWebsite = nullptr; - bool out_of_band_print_hk(game::netsrc_t src, game::netadr_s to, const char* msg) - { - // Proof of concept patch. Please ignore - if (msg != "error\nPATCH_BANNED_FROM_SERVER"s) - { - return game::NET_OutOfBandPrint(src, to, msg); - } +bool out_of_band_print_hk(game::netsrc_t src, game::netadr_s to, + const char* msg) { + // Proof of concept patch. Please ignore + if (msg != "error\nPATCH_BANNED_FROM_SERVER"s) { + return game::NET_OutOfBandPrint(src, to, msg); + } - const auto errorMsg = std::format("error\nPermanently banned\nDiscord: {}\nWebsite: {}", - sv_discord->current.string, sv_clanWebsite->current.string); + const auto errorMsg = + std::format("error\nPermanently banned\nDiscord: {}\nWebsite: {}", + sv_discord->current.string, sv_clanWebsite->current.string); - return game::NET_OutOfBandPrint(src, to, errorMsg.data()); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::current == game::gamemode::zombies) return; - - sv_discord = game::Dvar_RegisterString("sv_discord", "https://www.discord.gg/", game::DVAR_FLAG_SAVED, "Discord invitation link"); - sv_clanWebsite = game::Dvar_RegisterString("sv_clanWebsite", "https://www.google.com/", game::DVAR_FLAG_SAVED, "Website link"); - - utils::hook::call(0x48B7E2, out_of_band_print_hk); - } - }; + return game::NET_OutOfBandPrint(src, to, errorMsg.data()); } +} // namespace + +class component final : public component_interface { +public: + void post_unpack() override { + if (game::current == game::gamemode::zombies) + return; + + sv_discord = game::Dvar_RegisterString( + "sv_discord", "https://www.discord.gg/", game::DVAR_ARCHIVE, + "Discord invitation link"); + + sv_clanWebsite = + game::Dvar_RegisterString("sv_clanWebsite", "https://www.google.com/", + game::DVAR_ARCHIVE, "Website link"); + + utils::hook::call(0x48B7E2, out_of_band_print_hk); + } +}; +} // namespace ban REGISTER_COMPONENT(ban::component) diff --git a/src/component/bots.cpp b/src/component/bots.cpp index 3fb0129..f8098d6 100644 --- a/src/component/bots.cpp +++ b/src/component/bots.cpp @@ -5,97 +5,93 @@ #include "utils/hook.hpp" #include "utils/io.hpp" -namespace bots -{ - namespace - { - typedef std::pair bot_entry; +namespace bots { +namespace { +typedef std::pair bot_entry; - std::vector bot_names; - utils::hook::detour sv_bot_name_random_hook; +std::vector bot_names; +utils::hook::detour sv_bot_name_random_hook; - // Json file is expected to contain a key for the bot's name. Value should be a string for the clantag - void load_bot_data() - { - const auto path = game::Dvar_FindVar("fs_homepath")->current.string; - std::filesystem::current_path(path); +// Json file is expected to contain a key for the bot's name. Value should be a +// string for the clantag +void load_bot_data() { + const auto path = game::Dvar_FindVar("fs_homepath")->current.string; + std::filesystem::current_path(path); - if (!utils::io::file_exists("bots/bots.json")) - { - game::Com_Printf(game::CON_CHANNEL_SERVER, "bots.json was not found\n"); - return; - } + if (!utils::io::file_exists("bots/bots.json")) { + game::Com_Printf(game::CON_CHANNEL_SERVER, "bots.json was not found\n"); + return; + } - rapidjson::Document obj; - rapidjson::ParseResult result = obj.Parse(utils::io::read_file("bots/bots.json").data()); + rapidjson::Document obj; + rapidjson::ParseResult result = + obj.Parse(utils::io::read_file("bots/bots.json").data()); - if (!result || !obj.IsObject()) - { - game::Com_Printf(game::CON_CHANNEL_SERVER, "Failed to parse ban file. Empty?\n"); - return; - } + if (!result || !obj.IsObject()) { + game::Com_Printf(game::CON_CHANNEL_SERVER, + "Failed to parse ban file. Empty?\n"); + return; + } - for (rapidjson::Value::ConstMemberIterator itr = obj.MemberBegin(); - itr != obj.MemberEnd(); ++itr) - { - if (itr->value.GetType() == rapidjson::Type::kStringType) - { - bot_names.emplace_back(std::make_pair(itr->name.GetString(), itr->value.GetString())); - } - } - } - - const char* sv_bot_name_random_stub() - { - if (bot_names.empty()) - { - load_bot_data(); - } - - static auto bot_id = 0; - if (!bot_names.empty()) - { - bot_id %= bot_names.size(); - const auto& entry = bot_names.at(bot_id++); - return entry.first.data(); - } - - return sv_bot_name_random_hook.invoke(); - } - - int build_connect_string(char* buf, const char* connect_string, const char* name, const char* xuid, - int protocol, int port) - { - // Default - auto clan_tag = "3arc"s; - for (const auto& entry : bot_names) - { - if (entry.first == name) - { - clan_tag = entry.second; - break; - } - } - - return _snprintf_s(buf, 0x400, _TRUNCATE, connect_string, name, - clan_tag.data(), xuid, protocol, port); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - if (game::current == game::gamemode::zombies) return; - - utils::hook::set(0x6B6294, "connect \"\\cg_predictItems\\1\\cl_punkbuster\\0\\cl_anonymous\\0\\color\\4\\head\\" - "default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\clanAbbrev\\%s\\bdOnlineUserID\\%s\\protocol\\%d\\qport\\%d\""); - - sv_bot_name_random_hook.create(0x49ED80, &sv_bot_name_random_stub); - utils::hook::call(0x6B6299, build_connect_string); - } - }; + for (rapidjson::Value::ConstMemberIterator itr = obj.MemberBegin(); + itr != obj.MemberEnd(); ++itr) { + if (itr->value.GetType() == rapidjson::Type::kStringType) { + bot_names.emplace_back( + std::make_pair(itr->name.GetString(), itr->value.GetString())); + } + } } +const char* sv_bot_name_random_stub() { + if (bot_names.empty()) { + load_bot_data(); + } + + static auto bot_id = 0; + if (!bot_names.empty()) { + bot_id %= bot_names.size(); + const auto& entry = bot_names.at(bot_id++); + return entry.first.data(); + } + + return sv_bot_name_random_hook.invoke(); +} + +int build_connect_string(char* buf, const char* connect_string, + const char* name, const char* xuid, int protocol, + int port) { + // Default + auto clan_tag = "3arc"s; + for (const auto& entry : bot_names) { + if (entry.first == name) { + clan_tag = entry.second; + break; + } + } + + return _snprintf_s(buf, 0x400, _TRUNCATE, connect_string, name, + clan_tag.data(), xuid, protocol, port); +} +} // namespace + +class component final : public component_interface { +public: + void post_unpack() override { + if (game::current == game::gamemode::zombies) + return; + + utils::hook::set( + 0x6B6294, + "connect " + "\"\\cg_predictItems\\1\\cl_punkbuster\\0\\cl_" + "anonymous\\0\\color\\4\\head\\" + "default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\clanAbbrev\\%" + "s\\bdOnlineUserID\\%s\\protocol\\%d\\qport\\%d\""); + + sv_bot_name_random_hook.create(0x49ED80, &sv_bot_name_random_stub); + utils::hook::call(0x6B6299, build_connect_string); + } +}; +} // namespace bots + REGISTER_COMPONENT(bots::component) diff --git a/src/component/chat.cpp b/src/component/chat.cpp index d18ff73..20df257 100644 --- a/src/component/chat.cpp +++ b/src/component/chat.cpp @@ -6,142 +6,128 @@ #include "command.hpp" -namespace chat -{ - namespace - { - std::mutex chat_mutex; - std::unordered_set mute_list{}; +namespace chat { +namespace { +std::mutex chat_mutex; +std::unordered_set mute_list{}; - void mute_player(const game::client_s* cl) - { - std::unique_lock _(chat_mutex); - if (mute_list.contains(cl->xuid)) - { - game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"%s is already muted\"", 0x65, cl->name)); - return; - } +void mute_player(const game::client_s* cl) { + std::unique_lock _(chat_mutex); + if (mute_list.contains(cl->xuid)) { + game::SV_GameSendServerCommand( + -1, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"%s is already muted\"", 0x65, cl->name)); + return; + } - mute_list.insert(cl->xuid); - } - - void unmute_player(const game::client_s* cl) - { - std::unique_lock _(chat_mutex); - mute_list.erase(cl->xuid); - - game::SV_GameSendServerCommand(cl->gentity->entnum, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"You were unmuted\"", 0x65)); - } - - void client_command(int clientNumber) - { - char buf[1024] = {0}; - - if (game::g_entities[clientNumber].client == nullptr) - { - // Not in game - return; - } - - game::SV_Cmd_ArgvBuffer(0, buf, sizeof(buf)); - - std::unique_lock _(chat_mutex); - if (utils::string::starts_with(buf, "say") && - mute_list.contains(game::svs_clients[clientNumber].xuid)) - { - game::SV_GameSendServerCommand(clientNumber, game::SV_CMD_CAN_IGNORE, - utils::string::va("%c \"You are muted\"", 0x65)); - return; - } - - game::ClientCommand(clientNumber); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - utils::hook::call(SELECT(0x58DA1C, 0x4FB3BD), client_command); - - add_chat_commands(); - } - - private: - static void add_chat_commands() - { - command::add("sayAs", [](const command::params& params) - { - if (params.size() < 3) - { - game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, - "Usage: sayAs \n"); - return; - } - - const auto* client = game::SV_GetPlayerByNum(); - - if (client == nullptr) - return; - - auto* gentity = client->gentity; - assert(gentity != nullptr); - - if (gentity->client == nullptr) - return; - - const auto message = params.join(2); - game::G_Say(gentity, nullptr, 0, message.data()); - }); - - command::add("mutePlayer", [](const command::params& params) - { - if (params.size() < 2) - { - game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, - "Usage: mutePlayer \n"); - return; - } - - const auto* client = game::SV_GetPlayerByNum(); - - if (client == nullptr) - return; - - assert(client->gentity != nullptr); - - if (client->gentity->client == nullptr) - return; - - mute_player(client); - }); - - command::add("unmutePlayer", [](const command::params& params) - { - if (params.size() < 2) - { - game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, - "Usage: unmutePlayer \n"); - return; - } - - const auto* client = game::SV_GetPlayerByNum(); - - if (client == nullptr) - return; - - assert(client->gentity != nullptr); - - if (client->gentity->client == nullptr) - return; - - unmute_player(client); - }); - } - }; + mute_list.insert(cl->xuid); } +void unmute_player(const game::client_s* cl) { + std::unique_lock _(chat_mutex); + mute_list.erase(cl->xuid); + + game::SV_GameSendServerCommand( + cl->gentity->entnum, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"You were unmuted\"", 0x65)); +} + +void client_command(int clientNumber) { + char buf[1024] = {0}; + + if (game::g_entities[clientNumber].client == nullptr) { + // Not in game + return; + } + + game::SV_Cmd_ArgvBuffer(0, buf, sizeof(buf)); + + std::unique_lock _(chat_mutex); + if (utils::string::starts_with(buf, "say") && + mute_list.contains(game::svs_clients[clientNumber].xuid)) { + game::SV_GameSendServerCommand( + clientNumber, game::SV_CMD_CAN_IGNORE, + utils::string::va("%c \"You are muted\"", 0x65)); + return; + } + + game::ClientCommand(clientNumber); +} +} // namespace + +class component final : public component_interface { +public: + void post_unpack() override { + utils::hook::call(SELECT(0x58DA1C, 0x4FB3BD), client_command); + + add_chat_commands(); + } + +private: + static void add_chat_commands() { + command::add("sayAs", [](const command::params& params) { + if (params.size() < 3) { + game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, + "Usage: sayAs \n"); + return; + } + + const auto* client = game::SV_GetPlayerByNum(); + + if (client == nullptr) + return; + + auto* gentity = client->gentity; + assert(gentity != nullptr); + + if (gentity->client == nullptr) + return; + + const auto message = params.join(2); + game::G_Say(gentity, nullptr, 0, message.data()); + }); + + command::add("mutePlayer", [](const command::params& params) { + if (params.size() < 2) { + game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, + "Usage: mutePlayer \n"); + return; + } + + const auto* client = game::SV_GetPlayerByNum(); + + if (client == nullptr) + return; + + assert(client->gentity != nullptr); + + if (client->gentity->client == nullptr) + return; + + mute_player(client); + }); + + command::add("unmutePlayer", [](const command::params& params) { + if (params.size() < 2) { + game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, + "Usage: unmutePlayer \n"); + return; + } + + const auto* client = game::SV_GetPlayerByNum(); + + if (client == nullptr) + return; + + assert(client->gentity != nullptr); + + if (client->gentity->client == nullptr) + return; + + unmute_player(client); + }); + } +}; +} // namespace chat + REGISTER_COMPONENT(chat::component) diff --git a/src/component/command.cpp b/src/component/command.cpp index f5f8ada..20d2432 100644 --- a/src/component/command.cpp +++ b/src/component/command.cpp @@ -9,129 +9,100 @@ constexpr auto CMD_MAX_NESTING = 8; -namespace command -{ - std::unordered_map> handlers; +namespace command { +std::unordered_map> handlers; - void main_handler() - { - params params = {}; +void main_handler() { + params params = {}; - const auto command = utils::string::to_lower(params[0]); - if (handlers.find(command) != handlers.end()) - { - handlers[command](params); - } - } - - params::params() - : nesting_(game::sv_cmd_args->nesting) - { - assert(game::sv_cmd_args->nesting < CMD_MAX_NESTING); - } - - int params::size() const - { - return game::sv_cmd_args->argc[this->nesting_]; - } - - const char* params::get(const int index) const - { - if (index >= this->size()) - { - return ""; - } - - return game::sv_cmd_args->argv[this->nesting_][index]; - } - - std::string params::join(const int index) const - { - std::string result = {}; - - for (auto i = index; i < this->size(); i++) - { - if (i > index) result.append(" "); - result.append(this->get(i)); - } - return result; - } - - void add_raw(const char* name, void (*callback)()) - { - game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate()); - } - - void add(const char* name, const std::function& callback) - { - const auto command = utils::string::to_lower(name); - - if (handlers.find(command) == handlers.end()) - { - add_raw(name, main_handler); - } - - handlers[command] = callback; - } - - std::vector script_commands; - utils::memory::allocator allocator; - - void add_script_command(const std::string& name, const std::function& callback) - { - script_commands.push_back(name); - const auto _name = allocator.duplicate_string(name); - add(_name, callback); - } - - void clear_script_commands() - { - for (const auto& name : script_commands) - { - handlers.erase(name); - game::Cmd_RemoveCommand(name.data()); - } - - allocator.clear(); - script_commands.clear(); - } - - void execute(std::string command, const bool sync) - { - command += "\n"; - - if (sync) - { - game::Cmd_ExecuteSingleCommand(game::LOCAL_CLIENT_0, 0, command.data()); - } - else - { - game::Cbuf_AddText(game::LOCAL_CLIENT_0, command.data()); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - add_commands_generic(); - } - - void pre_destroy() override - { - clear_script_commands(); - } - - private: - static void add_commands_generic() - { - add("properQuit", [](const params&) - { - utils::nt::raise_hard_exception(); - }); - } - }; + const auto command = utils::string::to_lower(params[0]); + if (handlers.find(command) != handlers.end()) { + handlers[command](params); + } } +params::params() : nesting_(game::sv_cmd_args->nesting) { + assert(game::sv_cmd_args->nesting < CMD_MAX_NESTING); +} + +int params::size() const { return game::sv_cmd_args->argc[this->nesting_]; } + +const char* params::get(const int index) const { + if (index >= this->size()) { + return ""; + } + + return game::sv_cmd_args->argv[this->nesting_][index]; +} + +std::string params::join(const int index) const { + std::string result = {}; + + for (auto i = index; i < this->size(); i++) { + if (i > index) + result.append(" "); + result.append(this->get(i)); + } + return result; +} + +void add_raw(const char* name, void (*callback)()) { + game::Cmd_AddCommandInternal( + name, callback, + utils::memory::get_allocator()->allocate()); +} + +void add(const char* name, const std::function& callback) { + const auto command = utils::string::to_lower(name); + + if (handlers.find(command) == handlers.end()) { + add_raw(name, main_handler); + } + + handlers[command] = callback; +} + +std::vector script_commands; +utils::memory::allocator allocator; + +void add_script_command(const std::string& name, + const std::function& callback) { + script_commands.push_back(name); + const auto _name = allocator.duplicate_string(name); + add(_name, callback); +} + +void clear_script_commands() { + for (const auto& name : script_commands) { + handlers.erase(name); + game::Cmd_RemoveCommand(name.data()); + } + + allocator.clear(); + script_commands.clear(); +} + +void execute(std::string command, const bool sync) { + command += "\n"; + + if (sync) { + game::Cmd_ExecuteSingleCommand(game::LOCAL_CLIENT_0, 0, command.data()); + } else { + game::Cbuf_AddText(game::LOCAL_CLIENT_0, command.data()); + } +} + +class component final : public component_interface { +public: + void post_unpack() override { add_commands_generic(); } + + void pre_destroy() override { clear_script_commands(); } + +private: + static void add_commands_generic() { + add("properQuit", [](const params&) { utils::nt::raise_hard_exception(); }); + } +}; +} // namespace command + REGISTER_COMPONENT(command::component) diff --git a/src/component/command.hpp b/src/component/command.hpp index 84a3bab..fde7f96 100644 --- a/src/component/command.hpp +++ b/src/component/command.hpp @@ -1,30 +1,26 @@ #pragma once -namespace command -{ - class params - { - public: - params(); +namespace command { +class params { +public: + params(); - int size() const; - const char* get(int index) const; - std::string join(int index) const; + int size() const; + const char* get(int index) const; + std::string join(int index) const; - const char* operator[](const int index) const - { - return this->get(index); - } + const char* operator[](const int index) const { return this->get(index); } - private: - int nesting_; - }; +private: + int nesting_; +}; - void add_raw(const char* name, void (*callback)()); - void add(const char* name, const std::function& callback); +void add_raw(const char* name, void (*callback)()); +void add(const char* name, const std::function& callback); - void add_script_command(const std::string& name, const std::function& callback); - void clear_script_commands(); +void add_script_command(const std::string& name, + const std::function& callback); +void clear_script_commands(); - void execute(std::string command, bool sync = false); -} +void execute(std::string command, bool sync = false); +} // namespace command diff --git a/src/component/gameplay.cpp b/src/component/gameplay.cpp index ddbea54..8d96dfc 100644 --- a/src/component/gameplay.cpp +++ b/src/component/gameplay.cpp @@ -3,32 +3,29 @@ #include "loader/component_loader.hpp" #include "utils/hook.hpp" -namespace gameplay -{ - namespace - { - const game::dvar_s* player_meleeRange = nullptr; - utils::hook::detour fire_weapon_melee_hook; +namespace gameplay { +namespace { +const game::dvar_s* player_meleeRange = nullptr; +utils::hook::detour fire_weapon_melee_hook; - void fire_weapon_melee_stub(game::gentity_s* ent, int time) - { - if (player_meleeRange->current.value == 0.0f) - return; +void fire_weapon_melee_stub(game::gentity_s* ent, int time) { + if (player_meleeRange->current.value == 0.0f) + return; - fire_weapon_melee_hook.invoke(ent, time); - } - } - - class component final : public component_interface - { - public: - void post_unpack() override - { - player_meleeRange = *reinterpret_cast(SELECT(0xC51990, 0xBCAFE4)); - - fire_weapon_melee_hook.create(SELECT(0x401E00, 0x465E40), &fire_weapon_melee_stub); - } - }; + fire_weapon_melee_hook.invoke(ent, time); } +} // namespace + +class component final : public component_interface { +public: + void post_unpack() override { + player_meleeRange = + *reinterpret_cast(SELECT(0xC51990, 0xBCAFE4)); + + fire_weapon_melee_hook.create(SELECT(0x401E00, 0x465E40), + &fire_weapon_melee_stub); + } +}; +} // namespace gameplay REGISTER_COMPONENT(gameplay::component) diff --git a/src/game/game.cpp b/src/game/game.cpp index 00a8071..4ebdc63 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1,21 +1,13 @@ #include -namespace game -{ - gamemode current = reinterpret_cast(0xA6840C) == "multiplayer"s - ? gamemode::multiplayer - : gamemode::zombies; +namespace game { +gamemode current = reinterpret_cast(0xA6840C) == "multiplayer"s + ? gamemode::multiplayer + : gamemode::zombies; - namespace environment - { - bool t5mp() - { - return current == gamemode::multiplayer; - } +namespace environment { +bool t5mp() { return current == gamemode::multiplayer; } - bool t5zm() - { - return current == gamemode::zombies; - } - } -} +bool t5zm() { return current == gamemode::zombies; } +} // namespace environment +} // namespace game diff --git a/src/game/game.hpp b/src/game/game.hpp index bd5e09a..d690d06 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -2,58 +2,38 @@ #define SELECT(mp, zm) (game::environment::t5mp() ? mp : zm) -namespace game -{ - enum gamemode - { - none, - multiplayer, - zombies - }; +namespace game { +enum gamemode { none, multiplayer, zombies }; - extern gamemode current; +extern gamemode current; - namespace environment - { - bool t5mp(); - bool t5zm(); - } +namespace environment { +bool t5mp(); +bool t5zm(); +} // namespace environment - template - class symbol - { - public: - symbol(const size_t t5mp, const size_t t5zm) - : t5mp_(reinterpret_cast(t5mp)) - , t5zm_(reinterpret_cast(t5zm)) - { - } +template class symbol { +public: + symbol(const size_t t5mp, const size_t t5zm) + : t5mp_(reinterpret_cast(t5mp)), t5zm_(reinterpret_cast(t5zm)) {} - T* get() const - { - if (environment::t5mp()) - { - return t5mp_; - } + T* get() const { + if (environment::t5mp()) { + return t5mp_; + } - return t5zm_; - } + return t5zm_; + } - operator T* () const - { - return this->get(); - } + operator T*() const { return this->get(); } - T* operator->() const - { - return this->get(); - } + T* operator->() const { return this->get(); } - private: - T* t5mp_; - T* t5zm_; - }; +private: + T* t5mp_; + T* t5zm_; +}; -} +} // namespace game #include "symbols.hpp" diff --git a/src/game/structs.hpp b/src/game/structs.hpp index 18dcef0..a3ec7ce 100644 --- a/src/game/structs.hpp +++ b/src/game/structs.hpp @@ -1,558 +1,499 @@ #pragma once -namespace game +namespace game { +typedef float vec_t; +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; + +enum FsListBehavior_e { FS_LIST_PURE_ONLY = 0x0, FS_LIST_ALL = 0x1 }; + +enum svscmd_type { SV_CMD_CAN_IGNORE, SV_CMD_RELIABLE }; + +typedef enum { + ERR_FATAL = 0x0, + ERR_DROP = 0x1, + ERR_SERVERDISCONNECT = 0x2, + ERR_DISCONNECT = 0x3, + ERR_SCRIPT = 0x4, + ERR_SCRIPT_DROP = 0x5, + ERR_LOCALIZATION = 0x6 +} errorParm_t; + +typedef enum { + LOCAL_CLIENT_INVALID = -1, + LOCAL_CLIENT_0 = 0, + LOCAL_CLIENT_1 = 1, + LOCAL_CLIENT_2 = 2, + LOCAL_CLIENT_3 = 3, + LOCAL_CLIENT_LAST = 3, + LOCAL_CLIENT_COUNT = 4 +} LocalClientNum_t; + +typedef enum { + CON_CHANNEL_DONT_FILTER = 0x0, + CON_CHANNEL_ERROR = 0x1, + CON_CHANNEL_GAMENOTIFY = 0x2, + CON_CHANNEL_BOLDGAME = 0x3, + CON_CHANNEL_SUBTITLE = 0x4, + CON_CHANNEL_OBITUARY = 0x5, + CON_CHANNEL_LOGFILEONLY = 0x6, + CON_CHANNEL_CONSOLEONLY = 0x7, + CON_CHANNEL_GFX = 0x8, + CON_CHANNEL_SOUND = 0x9, + CON_CHANNEL_FILES = 0xA, + CON_CHANNEL_DEVGUI = 0xB, + CON_CHANNEL_PROFILE = 0xC, + CON_CHANNEL_UI = 0xD, + CON_CHANNEL_CLIENT = 0xE, + CON_CHANNEL_SERVER = 0xF, + CON_CHANNEL_SYSTEM = 0x10, + CON_CHANNEL_PLAYERWEAP = 0x11, + CON_CHANNEL_AI = 0x12, + CON_CHANNEL_ANIM = 0x13, + CON_CHANNEL_PHYS = 0x14, + CON_CHANNEL_FX = 0x15, + CON_CHANNEL_LEADERBOARDS = 0x16, + CON_CHANNEL_LIVE = 0x17, + CON_CHANNEL_PARSERSCRIPT = 0x18, + CON_CHANNEL_SCRIPT = 0x19, + CON_CHANNEL_SPAWNSYSTEM = 0x1A, + CON_CHANNEL_COOPINFO = 0x1B, + CON_CHANNEL_SERVERDEMO = 0x1C, + CON_CHANNEL_DDL = 0x1D, + CON_CHANNEL_NETWORK = 0x1E, + CON_CHANNEL_SCHEDULER = 0x1F, + CON_FIRST_DEBUG_CHANNEL = 0x1F, + CON_CHANNEL_TASK = 0x20, + CON_CHANNEL_SPU = 0x21, + CON_BUILTIN_CHANNEL_COUNT = 0x22 +} conChannel_t; + +typedef enum { + CON_DEST_CONSOLE = 0, + CON_DEST_MINICON = 1, + CON_DEST_ERROR = 2, + CON_DEST_GAME_FIRST = 3, + CON_DEST_GAME1 = 3, + CON_DEST_GAME2 = 4, + CON_DEST_GAME3 = 5, + CON_DEST_GAME_LAST = 5, + CON_DEST_COUNT = 6 +} print_msg_dest_t; + +typedef enum { + NS_CLIENT1 = 0x0, + NS_SERVER = 0x1, + NS_MAXCLIENTS = 0x1, + NS_PACKET = 0x2 +} netsrc_t; + +typedef enum { CS_MOTD = 11, CS_TIMESCALE = 14 } ConfigString; + +typedef enum { + FS_READ = 0, + FS_WRITE = 1, + FS_APPEND = 2, + FS_APPEND_SYNC = 3 +} fsMode_t; + +struct PrintChannel { + char name[32]; + bool allowScript; +}; + +static_assert(sizeof(PrintChannel) == 33); + +struct PrintChannelGlob { + PrintChannel openChannels[256]; + unsigned int filters[6][8]; +}; + +struct usercmd_s { + int serverTime; + int button_bits[2]; + int angles[3]; + unsigned __int16 weapon; + unsigned __int16 offHandIndex; + unsigned __int16 lastWeaponAltModeSwitch; + char forwardmove; + char rightmove; + char upmove; + char pitchmove; + char yawmove; + float meleeChargeYaw; + unsigned char meleeChargeDist; + float rollmove; + char selectedLocation[2]; + unsigned char selectedYaw; +}; + +static_assert(sizeof(usercmd_s) == 52); + +struct cmd_function_t { + cmd_function_t* next; + const char* name; + const char* autoCompleteDir; + const char* autoCompleteExt; + void(__cdecl* function)(); + bool consoleAccess; +}; + +static_assert(sizeof(cmd_function_t) == 24); + +struct CmdArgs { + int nesting; + int localClientNum[8]; + int controllerIndex[8]; + void* itemDef[8]; + int argshift[8]; + int argc[8]; + const char** argv[8]; + char textPool[8192]; + const char* argvPool[512]; + int usedTextPool[8]; + int totalUsedArgvPool; + int totalUsedTextPool; +}; + +static_assert(sizeof(CmdArgs) == 10476); + +typedef enum { + NA_BOT = 0x0, + NA_BAD = 0x1, + NA_LOOPBACK = 0x2, + NA_BROADCAST = 0x3, + NA_IP = 0x4 +} netadrtype_t; + +struct netadr_s // Confirm nigga { - typedef float vec_t; - typedef vec_t vec2_t[2]; - typedef vec_t vec3_t[3]; - typedef vec_t vec4_t[4]; + netadrtype_t type; + unsigned char ip[4]; + unsigned __int16 port; + int addrHandleIndex; +}; - enum FsListBehavior_e - { - FS_LIST_PURE_ONLY = 0x0, - FS_LIST_ALL = 0x1 - }; +static_assert(sizeof(netadr_s) == 16); - enum svscmd_type - { - SV_CMD_CAN_IGNORE, - SV_CMD_RELIABLE - }; +struct msg_t { + int overflowed; + int readOnly; + unsigned char* data; + unsigned char* splitData; + int maxsize; + int cursize; + int splitSize; + int readcount; + int bit; + int lastEntityRef; + int flush; + netsrc_t targetLocalNetID; +}; - typedef enum - { - ERR_FATAL = 0x0, - ERR_DROP = 0x1, - ERR_SERVERDISCONNECT = 0x2, - ERR_DISCONNECT = 0x3, - ERR_SCRIPT = 0x4, - ERR_SCRIPT_DROP = 0x5, - ERR_LOCALIZATION = 0x6 - } errorParm_t; +static_assert(sizeof(msg_t) == 48); - typedef enum - { - LOCAL_CLIENT_INVALID = -1, - LOCAL_CLIENT_0 = 0, - LOCAL_CLIENT_1 = 1, - LOCAL_CLIENT_2 = 2, - LOCAL_CLIENT_3 = 3, - LOCAL_CLIENT_LAST = 3, - LOCAL_CLIENT_COUNT = 4 - } LocalClientNum_t; +typedef enum { + SCRIPTINSTANCE_SERVER, + SCRIPTINSTANCE_CLIENT, + SCRIPT_INSTANCE_MAX +} scriptInstance_t; - typedef enum - { - CON_CHANNEL_DONT_FILTER = 0x0, - CON_CHANNEL_ERROR = 0x1, - CON_CHANNEL_GAMENOTIFY = 0x2, - CON_CHANNEL_BOLDGAME = 0x3, - CON_CHANNEL_SUBTITLE = 0x4, - CON_CHANNEL_OBITUARY = 0x5, - CON_CHANNEL_LOGFILEONLY = 0x6, - CON_CHANNEL_CONSOLEONLY = 0x7, - CON_CHANNEL_GFX = 0x8, - CON_CHANNEL_SOUND = 0x9, - CON_CHANNEL_FILES = 0xA, - CON_CHANNEL_DEVGUI = 0xB, - CON_CHANNEL_PROFILE = 0xC, - CON_CHANNEL_UI = 0xD, - CON_CHANNEL_CLIENT = 0xE, - CON_CHANNEL_SERVER = 0xF, - CON_CHANNEL_SYSTEM = 0x10, - CON_CHANNEL_PLAYERWEAP = 0x11, - CON_CHANNEL_AI = 0x12, - CON_CHANNEL_ANIM = 0x13, - CON_CHANNEL_PHYS = 0x14, - CON_CHANNEL_FX = 0x15, - CON_CHANNEL_LEADERBOARDS = 0x16, - CON_CHANNEL_LIVE = 0x17, - CON_CHANNEL_PARSERSCRIPT = 0x18, - CON_CHANNEL_SCRIPT = 0x19, - CON_CHANNEL_SPAWNSYSTEM = 0x1A, - CON_CHANNEL_COOPINFO = 0x1B, - CON_CHANNEL_SERVERDEMO = 0x1C, - CON_CHANNEL_DDL = 0x1D, - CON_CHANNEL_NETWORK = 0x1E, - CON_CHANNEL_SCHEDULER = 0x1F, - CON_FIRST_DEBUG_CHANNEL = 0x1F, - CON_CHANNEL_TASK = 0x20, - CON_CHANNEL_SPU = 0x21, - CON_BUILTIN_CHANNEL_COUNT = 0x22 - } conChannel_t; +enum dvar_flags : unsigned __int16 { + DVAR_ARCHIVE = 0x1, + DVAR_WRITEPROTECTED = 0x10, + DVAR_READONLY = 0x40, + DVAR_CHEAT = 0x80, + DVAR_CODINFO = 0x100, +}; - typedef enum - { - CON_DEST_CONSOLE = 0, - CON_DEST_MINICON = 1, - CON_DEST_ERROR = 2, - CON_DEST_GAME_FIRST = 3, - CON_DEST_GAME1 = 3, - CON_DEST_GAME2 = 4, - CON_DEST_GAME3 = 5, - CON_DEST_GAME_LAST = 5, - CON_DEST_COUNT = 6 - } print_msg_dest_t; +typedef enum : char { + DVAR_TYPE_BOOL = 0x0, + DVAR_TYPE_FLOAT = 0x1, + DVAR_TYPE_FLOAT_2 = 0x2, + DVAR_TYPE_FLOAT_3 = 0x3, + DVAR_TYPE_FLOAT_4 = 0x4, + DVAR_TYPE_INT = 0x5, + DVAR_TYPE_ENUM = 0x6, + DVAR_TYPE_STRING = 0x7, + DVAR_TYPE_COLOR = 0x8, + DVAR_TYPE_INT64 = 0x9, + DVAR_TYPE_LINEAR_COLOR_RGB = 0xA, + DVAR_TYPE_COLOR_XYZ = 0xB, + DVAR_TYPE_COUNT = 0xC +} dvarType_t; - typedef enum - { - NS_CLIENT1 = 0x0, - NS_SERVER = 0x1, - NS_MAXCLIENTS = 0x1, - NS_PACKET = 0x2 - } netsrc_t; +union DvarValue { + bool enabled; + int integer; + unsigned int unsignedInt; + __int64 integer64; + unsigned __int64 unsignedInt64; + float value; + float vector[4]; + const char* string; + unsigned char color[4]; +}; - typedef enum - { - CS_MOTD = 11, - CS_TIMESCALE = 14 - } ConfigString; +struct enum_limit { + int stringCount; + const char** strings; +}; - typedef enum - { - FS_READ = 0, - FS_WRITE = 1, - FS_APPEND = 2, - FS_APPEND_SYNC = 3 - } fsMode_t; +struct int_limit { + int min; + int max; +}; - struct PrintChannel - { - char name[32]; - bool allowScript; - }; +struct int64_limit { + __int64 min; + __int64 max; +}; - static_assert(sizeof(PrintChannel) == 33); +struct float_limit { + float min; + float max; +}; - struct PrintChannelGlob - { - PrintChannel openChannels[256]; - unsigned int filters[6][8]; - }; +union DvarLimits { + enum_limit enumeration; + int_limit integer; + float_limit value; + float_limit vector; +}; - struct usercmd_s - { - int serverTime; - int button_bits[2]; - int angles[3]; - unsigned __int16 weapon; - unsigned __int16 offHandIndex; - unsigned __int16 lastWeaponAltModeSwitch; - char forwardmove; - char rightmove; - char upmove; - char pitchmove; - char yawmove; - float meleeChargeYaw; - unsigned char meleeChargeDist; - float rollmove; - char selectedLocation[2]; - unsigned char selectedYaw; - }; +typedef struct dvar_s { + const char* name; + const char* description; + long hash; + unsigned int flags; + dvarType_t type; + bool modified; + bool loadedFromSaveGame; + DvarValue current; + DvarValue latched; + DvarValue reset; + DvarValue saved; + DvarLimits domain; + dvar_s* hashNext; + unsigned char pad0[8]; +} dvar_t; - static_assert(sizeof(usercmd_s) == 52); +static_assert(sizeof(dvar_s) == 112); - struct cmd_function_t - { - cmd_function_t* next; - const char* name; - const char* autoCompleteDir; - const char* autoCompleteExt; - void(__cdecl* function)(); - bool consoleAccess; - }; +enum playerFlag { + PLAYER_FLAG_NOCLIP = 1 << 0, + PLAYER_FLAG_UFO = 1 << 1, + PLAYER_FLAG_FROZEN = 1 << 2, +}; - static_assert(sizeof(cmd_function_t) == 24); +struct playerState_s { + int commandTime; + int pm_type; + int bobCycle; + int pm_flags; + int weapFlags; + int otherFlags; + int pm_time; +}; - struct CmdArgs - { - int nesting; - int localClientNum[8]; - int controllerIndex[8]; - void* itemDef[8]; - int argshift[8]; - int argc[8]; - const char** argv[8]; - char textPool[8192]; - const char* argvPool[512]; - int usedTextPool[8]; - int totalUsedArgvPool; - int totalUsedTextPool; - }; +struct pmove_t { + playerState_s* ps; +}; - static_assert(sizeof(CmdArgs) == 10476); +struct gclient_s { + char __pad0[10396]; + int flags; + char __pad1[320]; +}; - typedef enum - { - NA_BOT = 0x0, - NA_BAD = 0x1, - NA_LOOPBACK = 0x2, - NA_BROADCAST = 0x3, - NA_IP = 0x4 - } netadrtype_t; +static_assert(sizeof(gclient_s) == 10720); - struct netadr_s // Confirm nigga - { - netadrtype_t type; - unsigned char ip[4]; - unsigned __int16 port; - int addrHandleIndex; - }; +enum entityFlag { + FL_GODMODE = 1, + FL_DEMI_GODMODE = 2, + FL_NOTARGET = 4, + FL_NO_KNOCKBACK = 8, + FL_DROPPED_ITEM = 16, + FL_NO_BOTS = 32, + FL_NO_HUMANS = 64, + FL_TOGGLE = 128, + FL_SOFTACTIVATE = 256, + FL_LOW_PRIORITY_USEABLE = 512, + FL_NO_HEADCHECK = 1024, + FL_DYNAMICPATH = 2048, + FL_SUPPORTS_LINKTO = 4096, + FL_NO_AUTO_ANIM_UPDATE = 8192, + FL_GRENADE_TOUCH_DAMAGE = 16384, + FL_GRENADE_MARTYRDOM = 32768, + FL_MISSILE_DESTABILIZED = 65536, + FL_STABLE_MISSILES = 131072, + FL_REPEAT_ANIM_UPDATE = 262144, + FL_VEHICLE_TARGET = 524288, + FL_GROUND_ENT = 1048576, + FL_CURSOR_HINT = 2097152, + FL_USE_TURRET = 4194304, + FL_MISSILE_ATTRACTOR = 8388608, + FL_TARGET = 16777216, + FL_WEAPON_BEING_GRABBED = 33554432, + FL_OBSTACLE = 67108864, + FL_DODGE_LEFT = 134217728, + FL_DODGE_RIGHT = 268435456, + FL_BADPLACE_VOLUME = 536870912, + FL_AUTO_BLOCKPATHS = 1073741824 +}; - static_assert(sizeof(netadr_s) == 16); +enum playerStateFlag { PMF_PRONE = 0x1, PMF_DUCKED = 0x2, PMF_MANTLE = 0x4 }; - struct msg_t - { - int overflowed; - int readOnly; - unsigned char* data; - unsigned char* splitData; - int maxsize; - int cursize; - int splitSize; - int readcount; - int bit; - int lastEntityRef; - int flush; - netsrc_t targetLocalNetID; - }; +struct gentity_s { + int entnum; + char __pad0[320]; + gclient_s* client; + char __pad1[44]; + int flags; + char __pad2[384]; +}; - static_assert(sizeof(msg_t) == 48); +static_assert(sizeof(gentity_s) == 760); - typedef enum - { - SCRIPTINSTANCE_SERVER, - SCRIPTINSTANCE_CLIENT, - SCRIPT_INSTANCE_MAX - } scriptInstance_t; +struct netProfilePacket_t { + int iTime; + int iSize; + int bFragment; +}; - enum dvar_flags : unsigned __int16 - { - DVAR_FLAG_SAVED = 0x1, - DVAR_FLAG_WRITEPROTECTED = 0x10, - DVAR_FLAG_READONLY = 0x40, - DVAR_FLAG_CHEAT = 0x80, - DVAR_FLAG_REPLICATED = 0x100, - }; +struct netProfileStream_t { + netProfilePacket_t packets[60]; + int iCurrPacket; + int iBytesPerSecond; + int iLastBPSCalcTime; + int iCountedPackets; + int iCountedFragments; + int iFragmentPercentage; + int iLargestPacket; + int iSmallestPacket; +}; - typedef enum : char - { - DVAR_TYPE_BOOL = 0x0, - DVAR_TYPE_FLOAT = 0x1, - DVAR_TYPE_FLOAT_2 = 0x2, - DVAR_TYPE_FLOAT_3 = 0x3, - DVAR_TYPE_FLOAT_4 = 0x4, - DVAR_TYPE_INT = 0x5, - DVAR_TYPE_ENUM = 0x6, - DVAR_TYPE_STRING = 0x7, - DVAR_TYPE_COLOR = 0x8, - DVAR_TYPE_INT64 = 0x9, - DVAR_TYPE_LINEAR_COLOR_RGB = 0xA, - DVAR_TYPE_COLOR_XYZ = 0xB, - DVAR_TYPE_COUNT = 0xC - } dvarType_t; +struct netProfileInfo_t { + netProfileStream_t send; + netProfileStream_t recieve; +}; - union DvarValue - { - bool enabled; - int integer; - unsigned int unsignedInt; - __int64 integer64; - unsigned __int64 unsignedInt64; - float value; - float vector[4]; - const char* string; - unsigned char color[4]; - }; +static_assert(sizeof(netProfileInfo_t) == 1504); - struct enum_limit - { - int stringCount; - const char** strings; - }; +struct netchan_t { + int outgoingSequence; + netsrc_t sock; + int dropped; + int incomingSequence; + netadr_s remoteAddress; + int qport; + int fragmentSequence; + int fragmentLength; + unsigned char* fragmentBuffer; + int fragmentBufferSize; + int unsentFragments; + int unsentFragmentStart; + int unsentLength; + unsigned char* unsentBuffer; + int unsentBufferSize; + int reliable_fragments; + unsigned char fragment_send_count[128]; + unsigned int fragment_ack[4]; + int lowest_send_count; + netProfileInfo_t prof; +}; - struct int_limit - { - int min; - int max; - }; +static_assert(sizeof(netchan_t) == 1728); - struct int64_limit - { - __int64 min; - __int64 max; - }; +struct MantleState { + float yaw; + int timer; + int transIndex; + int flags; +}; - struct float_limit - { - float min; - float max; - }; +enum ViewLockTypes { + PLAYERVIEWLOCK_NONE = 0, + PLAYERVIEWLOCK_FULL = 1, + PLAYERVIEWLOCK_WEAPONJITTER = 2, + PLAYERVIEWLOCKCOUNT = 3 +}; - union DvarLimits - { - enum_limit enumeration; - int_limit integer; - float_limit value; - float_limit vector; - }; +typedef enum { + PM_NORMAL = 0, + PM_NORMAL_LINKED = 1, + PM_NOCLIP = 2, + PM_UFO = 3, + PM_SPECTATOR = 4, + PM_INTERMISSION = 5, + PM_LASTSTAND = 6, + PM_REVIVEE = 7, + PM_LASTSTAND_TRANSITION = 8, + PM_DEAD = 9, + PM_DEAD_LINKED = 10 +} pmtype_t; - typedef struct dvar_s - { - const char* name; - const char* description; - long hash; - unsigned int flags; - dvarType_t type; - bool modified; - bool loadedFromSaveGame; - DvarValue current; - DvarValue latched; - DvarValue reset; - DvarValue saved; - DvarLimits domain; - dvar_s* hashNext; - unsigned char pad0[8]; - } dvar_t; +enum clientState_t { + CS_FREE = 0, + CS_ZOMBIE = 1, + CS_RECONNECTING = 2, + CS_CONNECTED = 3, + CS_CLIENTLOADING = 4, + CS_ACTIVE = 5 +}; - static_assert(sizeof(dvar_s) == 112); +struct PredictedVehicleInfo { + bool inVehicle; + vec3_t origin; + vec3_t angles; + vec3_t tVel; + vec3_t aVel; +}; - enum playerFlag - { - PLAYER_FLAG_NOCLIP = 1 << 0, - PLAYER_FLAG_UFO = 1 << 1, - PLAYER_FLAG_FROZEN = 1 << 2, - }; +static_assert(sizeof(PredictedVehicleInfo) == 52); - struct playerState_s - { - int commandTime; - int pm_type; - int bobCycle; - int pm_flags; - int weapFlags; - int otherFlags; - int pm_time; - }; +struct clientHeader_t { + clientState_t state; + int sendAsActive; + int deltaMessage; + int rateDealyed; + netchan_t netchan; + vec3_t predictedOrigin; + int predictedOriginServerTime; + PredictedVehicleInfo vehicle; +}; - struct pmove_t - { - playerState_s* ps; - }; +static_assert(sizeof(clientHeader_t) == 1812); - struct gclient_s - { - char __pad0[10396]; - int flags; - char __pad1[320]; - }; +struct svscmd_info_t { + const char* cmd; + int time; + int type; +}; - static_assert(sizeof(gclient_s) == 10720); +struct client_s { + clientHeader_t header; + const char* dropReason; // 1812 + char userinfo[1024]; // 1816 + char reliableCommandBuffer[16384]; // 2840 + int reliableCommandBufferNext; // 19224 + svscmd_info_t reliableCommandInfo[128]; // 19228 + int reliableSequence; // 20764 + int reliableAcknowledge; // 20768 + int reliableSent; // 20772 + int messageAcknowledge; // 20776 + int gamestateMessageNum; // 20780 + int challenge; // 20784 + usercmd_s lastUsercmd; // 20788 + int lastClientCommand; // 20840 + char lastClientCommandString[1024]; // 20844 + gentity_s* gentity; // 21868 + char name[32]; // 21872 + char clanAbbrev[5]; // 21904 + unsigned __int64 xuid; // 21912 + unsigned char __pad0[0x76D48]; +}; - enum entityFlag - { - FL_GODMODE = 1, - FL_DEMI_GODMODE = 2, - FL_NOTARGET = 4, - FL_NO_KNOCKBACK = 8, - FL_DROPPED_ITEM = 16, - FL_NO_BOTS = 32, - FL_NO_HUMANS = 64, - FL_TOGGLE = 128, - FL_SOFTACTIVATE = 256, - FL_LOW_PRIORITY_USEABLE = 512, - FL_NO_HEADCHECK = 1024, - FL_DYNAMICPATH = 2048, - FL_SUPPORTS_LINKTO = 4096, - FL_NO_AUTO_ANIM_UPDATE = 8192, - FL_GRENADE_TOUCH_DAMAGE = 16384, - FL_GRENADE_MARTYRDOM = 32768, - FL_MISSILE_DESTABILIZED = 65536, - FL_STABLE_MISSILES = 131072, - FL_REPEAT_ANIM_UPDATE = 262144, - FL_VEHICLE_TARGET = 524288, - FL_GROUND_ENT = 1048576, - FL_CURSOR_HINT = 2097152, - FL_USE_TURRET = 4194304, - FL_MISSILE_ATTRACTOR = 8388608, - FL_TARGET = 16777216, - FL_WEAPON_BEING_GRABBED = 33554432, - FL_OBSTACLE = 67108864, - FL_DODGE_LEFT = 134217728, - FL_DODGE_RIGHT = 268435456, - FL_BADPLACE_VOLUME = 536870912, - FL_AUTO_BLOCKPATHS = 1073741824 - }; - - enum playerStateFlag - { - PMF_PRONE = 0x1, - PMF_DUCKED = 0x2, - PMF_MANTLE = 0x4 - }; - - struct gentity_s - { - int entnum; - char __pad0[320]; - gclient_s* client; - char __pad1[44]; - int flags; - char __pad2[384]; - }; - - static_assert(sizeof(gentity_s) == 760); - - struct netProfilePacket_t - { - int iTime; - int iSize; - int bFragment; - }; - - struct netProfileStream_t - { - netProfilePacket_t packets[60]; - int iCurrPacket; - int iBytesPerSecond; - int iLastBPSCalcTime; - int iCountedPackets; - int iCountedFragments; - int iFragmentPercentage; - int iLargestPacket; - int iSmallestPacket; - }; - - struct netProfileInfo_t - { - netProfileStream_t send; - netProfileStream_t recieve; - }; - - static_assert(sizeof(netProfileInfo_t) == 1504); - - struct netchan_t - { - int outgoingSequence; - netsrc_t sock; - int dropped; - int incomingSequence; - netadr_s remoteAddress; - int qport; - int fragmentSequence; - int fragmentLength; - unsigned char* fragmentBuffer; - int fragmentBufferSize; - int unsentFragments; - int unsentFragmentStart; - int unsentLength; - unsigned char* unsentBuffer; - int unsentBufferSize; - int reliable_fragments; - unsigned char fragment_send_count[128]; - unsigned int fragment_ack[4]; - int lowest_send_count; - netProfileInfo_t prof; - }; - - static_assert(sizeof(netchan_t) == 1728); - - struct MantleState - { - float yaw; - int timer; - int transIndex; - int flags; - }; - - enum ViewLockTypes - { - PLAYERVIEWLOCK_NONE = 0, - PLAYERVIEWLOCK_FULL = 1, - PLAYERVIEWLOCK_WEAPONJITTER = 2, - PLAYERVIEWLOCKCOUNT = 3 - }; - - typedef enum - { - PM_NORMAL = 0, - PM_NORMAL_LINKED = 1, - PM_NOCLIP = 2, - PM_UFO = 3, - PM_SPECTATOR = 4, - PM_INTERMISSION = 5, - PM_LASTSTAND = 6, - PM_REVIVEE = 7, - PM_LASTSTAND_TRANSITION = 8, - PM_DEAD = 9, - PM_DEAD_LINKED = 10 - } pmtype_t; - - enum clientState_t - { - CS_FREE = 0, - CS_ZOMBIE = 1, - CS_RECONNECTING = 2, - CS_CONNECTED = 3, - CS_CLIENTLOADING = 4, - CS_ACTIVE = 5 - }; - - struct PredictedVehicleInfo - { - bool inVehicle; - vec3_t origin; - vec3_t angles; - vec3_t tVel; - vec3_t aVel; - }; - - static_assert(sizeof(PredictedVehicleInfo) == 52); - - struct clientHeader_t - { - clientState_t state; - int sendAsActive; - int deltaMessage; - int rateDealyed; - netchan_t netchan; - vec3_t predictedOrigin; - int predictedOriginServerTime; - PredictedVehicleInfo vehicle; - }; - - static_assert(sizeof(clientHeader_t) == 1812); - - struct svscmd_info_t - { - const char* cmd; - int time; - int type; - }; - - struct client_s - { - clientHeader_t header; - const char* dropReason; // 1812 - char userinfo[1024]; // 1816 - char reliableCommandBuffer[16384]; // 2840 - int reliableCommandBufferNext; // 19224 - svscmd_info_t reliableCommandInfo[128]; // 19228 - int reliableSequence; // 20764 - int reliableAcknowledge; // 20768 - int reliableSent; // 20772 - int messageAcknowledge; // 20776 - int gamestateMessageNum; // 20780 - int challenge; // 20784 - usercmd_s lastUsercmd; // 20788 - int lastClientCommand; // 20840 - char lastClientCommandString[1024]; // 20844 - gentity_s* gentity; // 21868 - char name[32]; // 21872 - char clanAbbrev[5]; // 21904 - unsigned __int64 xuid; // 21912 - unsigned char __pad0[0x76D48]; - }; - - static_assert(sizeof(client_s) == 0x7C2E8); -} +static_assert(sizeof(client_s) == 0x7C2E8); +} // namespace game diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 55791f6..a3e24a8 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -2,59 +2,76 @@ #define WEAK __declspec(selectany) -namespace game -{ - WEAK symbol Com_Error{0x627380, 0x651D90}; - WEAK symbol Com_Printf{0x4126C0, 0x43BF30}; - WEAK symbol Com_DPrintf{0x4E3FA0, 0x60F7F0}; - WEAK symbol Com_PrintError{0x568B90, 0x5DFC40}; +namespace game { +WEAK symbol Com_Error{0x627380, 0x651D90}; +WEAK symbol Com_Printf{0x4126C0, + 0x43BF30}; +WEAK symbol Com_DPrintf{0x4E3FA0, + 0x60F7F0}; +WEAK symbol Com_PrintError{0x568B90, + 0x5DFC40}; - WEAK symbol Cbuf_AddText{0x56EF70, 0x49B930}; - WEAK symbol Cbuf_InsertText{0x695E10, 0x5B3EB0}; - WEAK symbol Cmd_ExecuteSingleCommand{0x50B470, 0x829AD0}; +WEAK symbol Cbuf_AddText{0x56EF70, + 0x49B930}; +WEAK symbol Cbuf_InsertText{0x695E10, + 0x5B3EB0}; +WEAK symbol + Cmd_ExecuteSingleCommand{0x50B470, 0x829AD0}; - WEAK symbol SV_SendServerCommand{0x588B10, 0x6106E0}; - WEAK symbol SV_GameSendServerCommand{0x6B8730, 0x543CF0}; - WEAK symbol SV_Cmd_ArgvBuffer{0x462CB0, 0x4DF5A0}; - WEAK symbol SV_DelayDropClient{0x4A8DC0, 0x4A2EB0}; - WEAK symbol SV_GetPlayerByName{0x875180, 0x87C350}; - WEAK symbol SV_GetPlayerByNum{0x875260, 0x87C430}; +WEAK symbol + SV_SendServerCommand{0x588B10, 0x6106E0}; +WEAK symbol SV_GameSendServerCommand{ + 0x6B8730, 0x543CF0}; +WEAK symbol SV_Cmd_ArgvBuffer{0x462CB0, 0x4DF5A0}; +WEAK symbol SV_DelayDropClient{0x4A8DC0, + 0x4A2EB0}; +WEAK symbol SV_GetPlayerByName{0x875180, 0x87C350}; +WEAK symbol SV_GetPlayerByNum{0x875260, 0x87C430}; - WEAK symbol NET_OutOfBandPrint{0x560BB0, 0x472850}; - WEAK symbol NET_AdrToString{0x49F970, 0x40D790}; +WEAK symbol NET_OutOfBandPrint{0x560BB0, + 0x472850}; +WEAK symbol NET_AdrToString{0x49F970, 0x40D790}; - WEAK symbol Dvar_FindVar{0x512F70, 0x5AE810}; - WEAK symbol Dvar_DisplayableValue{0x681DD0, 0x5B56F0}; - WEAK symbol Dvar_DisplayableLatchedValue{0x4AE1A0, 0x675850}; - WEAK symbol Dvar_RegisterString{0x4E3410, 0x59B3B0}; - WEAK symbol Dvar_RegisterFloat{0x670020, 0x679020}; - WEAK symbol Dvar_RegisterBool{0x5A5350, 0x45BB20}; - WEAK symbol Dvar_RegisterInt{0x58D900, 0x651910}; +WEAK symbol Dvar_FindVar{0x512F70, 0x5AE810}; +WEAK symbol Dvar_DisplayableValue{0x681DD0, + 0x5B56F0}; +WEAK symbol Dvar_DisplayableLatchedValue{0x4AE1A0, + 0x675850}; +WEAK symbol + Dvar_RegisterString{0x4E3410, 0x59B3B0}; +WEAK symbol + Dvar_RegisterFloat{0x670020, 0x679020}; +WEAK symbol + Dvar_RegisterBool{0x5A5350, 0x45BB20}; +WEAK symbol + Dvar_RegisterInt{0x58D900, 0x651910}; - WEAK symbol Cmd_AddCommandInternal{0x6AD580, 0x661400}; - WEAK symbol Cmd_RemoveCommand{0x527EA0, 0x5F1A90}; - WEAK symbol Cmd_FindCommand{0x445B60, 0x479DD0}; +WEAK symbol Cmd_AddCommandInternal{ + 0x6AD580, 0x661400}; +WEAK symbol Cmd_RemoveCommand{0x527EA0, 0x5F1A90}; +WEAK symbol Cmd_FindCommand{0x445B60, 0x479DD0}; - WEAK symbol I_CleanStr{0x4B0700, 0x0}; +WEAK symbol I_CleanStr{0x4B0700, 0x0}; - WEAK symbol ConcatArgs{0x5D5F10, 0x4FB210}; - WEAK symbol ClientCommand{0x63DB70, 0x4AF770}; - WEAK symbol G_Say{0x51BBD0, 0x49A790}; +WEAK symbol ConcatArgs{0x5D5F10, 0x4FB210}; +WEAK symbol ClientCommand{0x63DB70, 0x4AF770}; +WEAK symbol G_Say{0x51BBD0, + 0x49A790}; - WEAK symbol Scr_Notify{0x458D30, 0x0}; - WEAK symbol Scr_AddInt{0x49F830, 0x0}; - WEAK symbol Scr_AddVector{0x532EF0, 0x0}; +WEAK symbol Scr_Notify{ + 0x458D30, 0x0}; +WEAK symbol Scr_AddInt{0x49F830, 0x0}; +WEAK symbol Scr_AddVector{0x532EF0, 0x0}; - WEAK symbol PM_GetEffectiveStance{0x659590, 0x0}; +WEAK symbol PM_GetEffectiveStance{0x659590, 0x0}; - WEAK symbol sv_cmd_args{0x355BD88, 0x243D208}; - WEAK symbol dvarCount{0x385BE74, 0x261CBD4}; - WEAK symbol sortedDvars{0x385BE88, 0x261CBE8}; - WEAK symbol svs_clients{0x372D11C, 0x286D01C}; - WEAK symbol g_entities{0x32E5640, 0x1A796F8}; - WEAK symbol level_time{0x3443F4C, 0xC2078C}; -} +WEAK symbol sv_cmd_args{0x355BD88, 0x243D208}; +WEAK symbol dvarCount{0x385BE74, 0x261CBD4}; +WEAK symbol sortedDvars{0x385BE88, 0x261CBE8}; +WEAK symbol svs_clients{0x372D11C, 0x286D01C}; +WEAK symbol g_entities{0x32E5640, 0x1A796F8}; +WEAK symbol level_time{0x3443F4C, 0xC2078C}; +} // namespace game diff --git a/src/loader/component_interface.hpp b/src/loader/component_interface.hpp index e1ee433..e839963 100644 --- a/src/loader/component_interface.hpp +++ b/src/loader/component_interface.hpp @@ -1,35 +1,21 @@ #pragma once -class component_interface -{ +class component_interface { 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) - { - return nullptr; - } + virtual void* load_import([[maybe_unused]] const std::string& library, + [[maybe_unused]] const std::string& function) { + return nullptr; + } - virtual bool is_supported() - { - return true; - } + virtual bool is_supported() { return true; } }; diff --git a/src/loader/component_loader.cpp b/src/loader/component_loader.cpp index d6a0090..c6e3f18 100644 --- a/src/loader/component_loader.cpp +++ b/src/loader/component_loader.cpp @@ -1,127 +1,111 @@ #include #include "component_loader.hpp" -void component_loader::register_component(std::unique_ptr&& component_) -{ - get_components().push_back(std::move(component_)); +void component_loader::register_component( + std::unique_ptr&& component_) { + get_components().push_back(std::move(component_)); } -bool component_loader::post_start() -{ - static auto handled = false; - if (handled) return true; - handled = true; +bool component_loader::post_start() { + static auto handled = false; + if (handled) + return true; + handled = true; - try - { - for (const auto& component_ : get_components()) - { - component_->post_start(); - } - } - catch (premature_shutdown_trigger&) - { - return false; - } + try { + for (const auto& component_ : get_components()) { + component_->post_start(); + } + } catch (premature_shutdown_trigger&) { + return false; + } - return true; + return true; } -bool component_loader::post_load() -{ - static auto handled = false; - if (handled) return true; - handled = true; +bool component_loader::post_load() { + static auto handled = false; + if (handled) + return true; + handled = true; - clean(); + clean(); - try - { - for (const auto& component_ : get_components()) - { - component_->post_load(); - } - } - catch (premature_shutdown_trigger&) - { - return false; - } + try { + for (const auto& component_ : get_components()) { + component_->post_load(); + } + } catch (premature_shutdown_trigger&) { + return false; + } - return true; + return true; } -void component_loader::post_unpack() -{ - static auto handled = false; - if (handled) return; - handled = true; +void component_loader::post_unpack() { + static auto handled = false; + if (handled) + return; + handled = true; - for (const auto& component_ : get_components()) - { - component_->post_unpack(); - } + for (const auto& component_ : get_components()) { + component_->post_unpack(); + } } -void component_loader::pre_destroy() -{ - static auto handled = false; - if (handled) return; - handled = true; +void component_loader::pre_destroy() { + static auto handled = false; + if (handled) + return; + handled = true; - for (const auto& component_ : get_components()) - { - component_->pre_destroy(); - } + for (const auto& component_ : get_components()) { + component_->pre_destroy(); + } } -void component_loader::clean() -{ - auto& components = get_components(); - for (auto i = components.begin(); i != components.end();) - { - if (!(*i)->is_supported()) - { - (*i)->pre_destroy(); - i = components.erase(i); - } - else - { - ++i; - } - } +void component_loader::clean() { + auto& components = get_components(); + for (auto i = components.begin(); i != components.end();) { + if (!(*i)->is_supported()) { + (*i)->pre_destroy(); + i = components.erase(i); + } else { + ++i; + } + } } -void* component_loader::load_import(const std::string& library, const std::string& function) -{ - void* function_ptr = nullptr; +void* component_loader::load_import(const std::string& library, + const std::string& function) { + void* function_ptr = nullptr; - for (const auto& component_ : get_components()) - { - auto* const component_function_ptr = component_->load_import(library, function); - if (component_function_ptr) - { - function_ptr = component_function_ptr; - } - } + for (const auto& component_ : get_components()) { + auto* const component_function_ptr = + component_->load_import(library, function); + if (component_function_ptr) { + function_ptr = component_function_ptr; + } + } - return function_ptr; + return function_ptr; } -void component_loader::trigger_premature_shutdown() -{ - throw premature_shutdown_trigger(); +void component_loader::trigger_premature_shutdown() { + throw premature_shutdown_trigger(); } -std::vector>& component_loader::get_components() -{ - using component_vector = std::vector>; - using component_vector_container = std::unique_ptr>; +std::vector>& +component_loader::get_components() { + using component_vector = std::vector>; + using component_vector_container = + std::unique_ptr>; - static component_vector_container components(new component_vector, [](component_vector* component_vector) - { - pre_destroy(); - delete component_vector; - }); + static component_vector_container components( + new component_vector, [](component_vector* component_vector) { + pre_destroy(); + delete component_vector; + }); - return *components; + return *components; } diff --git a/src/loader/component_loader.hpp b/src/loader/component_loader.hpp index 1f6b4d1..5d94b52 100644 --- a/src/loader/component_loader.hpp +++ b/src/loader/component_loader.hpp @@ -1,61 +1,51 @@ #pragma once #include "component_interface.hpp" -class component_loader final -{ +class component_loader final { public: - class premature_shutdown_trigger final : public std::exception - { - [[nodiscard]] const char* what() const noexcept override - { - return "Premature shutdown requested"; - } - }; + class premature_shutdown_trigger final : public std::exception { + [[nodiscard]] const char* what() const noexcept override { + return "Premature shutdown requested"; + } + }; - template - class installer final - { - static_assert(std::is_base_of::value, "component has invalid base class"); + template class installer final { + static_assert(std::is_base_of::value, + "component has invalid base class"); - public: - installer() - { - register_component(std::make_unique()); - } - }; + public: + installer() { register_component(std::make_unique()); } + }; - template - static T* get() - { - for (const auto& component_ : get_components()) - { - if (typeid(*component_.get()) == typeid(T)) - { - return reinterpret_cast(component_.get()); - } - } + template static T* get() { + for (const auto& component_ : get_components()) { + if (typeid(*component_.get()) == typeid(T)) { + return reinterpret_cast(component_.get()); + } + } - return nullptr; - } + return nullptr; + } - static void register_component(std::unique_ptr&& component); + static void + register_component(std::unique_ptr&& component); - static bool post_start(); - static bool post_load(); - static void post_unpack(); - static void pre_destroy(); - static void clean(); + static bool post_start(); + static bool post_load(); + static void post_unpack(); + static void pre_destroy(); + 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(); private: - static std::vector>& get_components(); + static std::vector>& get_components(); }; -#define REGISTER_COMPONENT(name) \ -namespace \ -{ \ - static component_loader::installer __component; \ -} +#define REGISTER_COMPONENT(name) \ + namespace { \ + static component_loader::installer __component; \ + } diff --git a/src/main.cpp b/src/main.cpp index f872a88..2a94104 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,13 @@ #include #include "loader/component_loader.hpp" -BOOL APIENTRY DllMain(HMODULE /*module_*/, DWORD ul_reason_for_call, LPVOID /*reserved_*/) -{ - if (ul_reason_for_call == DLL_PROCESS_ATTACH) - { - component_loader::post_unpack(); - } - else if (ul_reason_for_call == DLL_PROCESS_DETACH) - { - component_loader::pre_destroy(); - } +BOOL APIENTRY DllMain(HMODULE /*module_*/, DWORD ul_reason_for_call, + LPVOID /*reserved_*/) { + if (ul_reason_for_call == DLL_PROCESS_ATTACH) { + component_loader::post_unpack(); + } else if (ul_reason_for_call == DLL_PROCESS_DETACH) { + component_loader::pre_destroy(); + } - return TRUE; + return TRUE; } \ No newline at end of file diff --git a/src/stdinc.hpp b/src/stdinc.hpp index 3360ac5..7907a24 100644 --- a/src/stdinc.hpp +++ b/src/stdinc.hpp @@ -9,17 +9,18 @@ #include -#include +#include #include +#include +#include +#include #include #include -#include -#include -#include #include -#include #include +#pragma warning(disable : 26812) + #include #include #include @@ -28,5 +29,7 @@ using namespace std::literals; +// clang-format off #include "game/structs.hpp" #include "game/game.hpp" +// clang-format on diff --git a/src/utils/concurrency.hpp b/src/utils/concurrency.hpp index 05c5d3a..cfcb6cc 100644 --- a/src/utils/concurrency.hpp +++ b/src/utils/concurrency.hpp @@ -2,45 +2,35 @@ #include -namespace utils::concurrency -{ - template - class container - { - public: - template - R access(F&& accessor) const - { - std::lock_guard _{mutex_}; - return accessor(object_); - } +namespace utils::concurrency { +template class container { +public: + template R access(F&& accessor) const { + std::lock_guard _{mutex_}; + return accessor(object_); + } - template - R access(F&& accessor) - { - std::lock_guard _{mutex_}; - return accessor(object_); - } + template R access(F&& accessor) { + std::lock_guard _{mutex_}; + return accessor(object_); + } - template - R access_with_lock(F&& accessor) const - { - std::unique_lock lock{mutex_}; - return accessor(object_, lock); - } + template + R access_with_lock(F&& accessor) const { + std::unique_lock lock{mutex_}; + return accessor(object_, lock); + } - template - R access_with_lock(F&& accessor) - { - std::unique_lock lock{mutex_}; - return accessor(object_, lock); - } + template R access_with_lock(F&& accessor) { + std::unique_lock lock{mutex_}; + return accessor(object_, lock); + } - T& get_raw() { return object_; } - const T& get_raw() const { return object_; } + T& get_raw() { return object_; } + const T& get_raw() const { return object_; } - private: - mutable MutexType mutex_{}; - T object_{}; - }; -} +private: + mutable MutexType mutex_{}; + T object_{}; +}; +} // namespace utils::concurrency diff --git a/src/utils/cryptography.cpp b/src/utils/cryptography.cpp index f90839d..bfdf040 100644 --- a/src/utils/cryptography.cpp +++ b/src/utils/cryptography.cpp @@ -1,26 +1,22 @@ #include "string.hpp" #include "cryptography.hpp" -namespace jenkins_one_at_a_time -{ - unsigned int jenkins_one_at_a_time::compute(const std::string& data) - { - return compute(data.data(), data.size()); - } - - unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len) - { - unsigned int hash, i; - for (hash = i = 0; i < len; ++i) - { - hash += key[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; - } +namespace jenkins_one_at_a_time { +unsigned int jenkins_one_at_a_time::compute(const std::string& data) { + return compute(data.data(), data.size()); } + +unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len) { + unsigned int hash, i; + for (hash = i = 0; i < len; ++i) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} +} // namespace jenkins_one_at_a_time diff --git a/src/utils/cryptography.hpp b/src/utils/cryptography.hpp index 86e23b5..fa9ceda 100644 --- a/src/utils/cryptography.hpp +++ b/src/utils/cryptography.hpp @@ -1,7 +1,6 @@ #pragma once -namespace jenkins_one_at_a_time -{ - unsigned int compute(const std::string& data); - unsigned int compute(const char* key, size_t len); -} +namespace jenkins_one_at_a_time { +unsigned int compute(const std::string& data); +unsigned int compute(const char* key, size_t len); +} // namespace jenkins_one_at_a_time diff --git a/src/utils/hook.cpp b/src/utils/hook.cpp index a3bb596..4cd9cf9 100644 --- a/src/utils/hook.cpp +++ b/src/utils/hook.cpp @@ -3,191 +3,154 @@ #include -namespace utils::hook -{ - namespace - { - [[maybe_unused]] class _ - { - public: - _() - { - if (MH_Initialize() != MH_OK) - { - throw std::runtime_error("Failed to initialize MinHook"); - } - } +namespace utils::hook { +namespace { +[[maybe_unused]] class _ { +public: + _() { + if (MH_Initialize() != MH_OK) { + throw std::runtime_error("Failed to initialize MinHook"); + } + } - ~_() - { - MH_Uninitialize(); - } - } __; - } + ~_() { MH_Uninitialize(); } +} __; +} // namespace - detour::detour(const size_t place, void* target) : detour(reinterpret_cast(place), target) - { - } +detour::detour(const size_t place, void* target) + : detour(reinterpret_cast(place), target) {} - detour::detour(void* place, void* target) - { - this->create(place, target); - } +detour::detour(void* place, void* target) { this->create(place, target); } - detour::~detour() - { - this->clear(); - } +detour::~detour() { this->clear(); } - void detour::enable() const - { - MH_EnableHook(this->place_); - } +void detour::enable() const { MH_EnableHook(this->place_); } - void detour::disable() const - { - MH_DisableHook(this->place_); - } +void detour::disable() const { MH_DisableHook(this->place_); } - void detour::create(void* place, void* target) - { - this->clear(); - this->place_ = place; +void detour::create(void* place, void* target) { + this->clear(); + this->place_ = place; - if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) - { - throw std::runtime_error(string::va("Unable to create hook at location: %p", this->place_)); - } + if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) { + throw std::runtime_error( + string::va("Unable to create hook at location: %p", this->place_)); + } - this->enable(); - } - - void detour::create(const size_t place, void* target) - { - this->create(reinterpret_cast(place), target); - } - - void detour::clear() - { - if (this->place_) - { - MH_RemoveHook(this->place_); - } - - this->place_ = nullptr; - this->original_ = nullptr; - } - - void* detour::get_original() const - { - return this->original_; - } - - void nop(void* place, const size_t length) - { - DWORD old_protect{}; - VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); - - std::memset(place, 0x90, length); - - VirtualProtect(place, length, old_protect, &old_protect); - FlushInstructionCache(GetCurrentProcess(), place, length); - } - - void nop(const size_t place, const size_t length) - { - nop(reinterpret_cast(place), length); - } - - void copy(void* place, const void* data, const size_t length) - { - DWORD old_protect{}; - VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); - - std::memmove(place, data, length); - - VirtualProtect(place, length, old_protect, &old_protect); - FlushInstructionCache(GetCurrentProcess(), place, length); - } - - void copy(const size_t place, const void* data, const size_t length) - { - copy(reinterpret_cast(place), data, length); - } - - bool is_relatively_far(const void* pointer, const void* data, const int offset) - { - const std::int64_t diff = size_t(data) - (size_t(pointer) + offset); - const auto small_diff = std::int32_t(diff); - return diff != std::int64_t(small_diff); - } - - void call(void* pointer, void* data) - { - if (is_relatively_far(pointer, data)) - { - throw std::runtime_error("Too far away to create 32bit relative branch"); - } - - auto* patch_pointer = PBYTE(pointer); - set(patch_pointer, 0xE8); - set(patch_pointer + 1, std::int32_t(size_t(data) - (size_t(pointer) + 5))); - } - - void call(const size_t pointer, void* data) - { - return call(reinterpret_cast(pointer), data); - } - - void call(const size_t pointer, const size_t data) - { - return call(pointer, reinterpret_cast(data)); - } - - void set(std::uintptr_t address, std::vector&& bytes) - { - DWORD oldProtect = 0; - - auto* place = reinterpret_cast(address); - VirtualProtect(place, bytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect); - memcpy(place, bytes.data(), bytes.size()); - VirtualProtect(place, bytes.size(), oldProtect, &oldProtect); - FlushInstructionCache(GetCurrentProcess(), place, bytes.size()); - } - - void set(std::uintptr_t address, void* buffer, size_t size) - { - DWORD oldProtect = 0; - - auto* place = reinterpret_cast(address); - VirtualProtect(place, size, PAGE_EXECUTE_READWRITE, &oldProtect); - memcpy(place, buffer, size); - VirtualProtect(place, size, oldProtect, &oldProtect); - FlushInstructionCache(GetCurrentProcess(), place, size); - } - - void jump(std::uintptr_t address, void* destination) - { - if (!address) return; - - std::uint8_t* bytes = new std::uint8_t[5]; - *bytes = 0xE9; - *reinterpret_cast(bytes + 1) = CalculateRelativeJMPAddress(address, destination); - - set(address, bytes, 5); - - delete[] bytes; - } - - void redirect_jump(void* pointer, void* data) - { - char* operand_ptr = static_cast(pointer) + 2; - std::int32_t new_operand = reinterpret_cast(data) - (reinterpret_cast(pointer) + 6); - set(operand_ptr, new_operand); - } - - void redirect_jump(size_t pointer, void* data) - { - redirect_jump(reinterpret_cast(pointer), data); - } + this->enable(); } + +void detour::create(const size_t place, void* target) { + this->create(reinterpret_cast(place), target); +} + +void detour::clear() { + if (this->place_) { + MH_RemoveHook(this->place_); + } + + this->place_ = nullptr; + this->original_ = nullptr; +} + +void* detour::get_original() const { return this->original_; } + +void nop(void* place, const size_t length) { + DWORD old_protect{}; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + std::memset(place, 0x90, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); +} + +void nop(const size_t place, const size_t length) { + nop(reinterpret_cast(place), length); +} + +void copy(void* place, const void* data, const size_t length) { + DWORD old_protect{}; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + std::memmove(place, data, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); +} + +void copy(const size_t place, const void* data, const size_t length) { + copy(reinterpret_cast(place), data, length); +} + +bool is_relatively_far(const void* pointer, const void* data, + const int offset) { + const std::int64_t diff = size_t(data) - (size_t(pointer) + offset); + const auto small_diff = std::int32_t(diff); + return diff != std::int64_t(small_diff); +} + +void call(void* pointer, void* data) { + if (is_relatively_far(pointer, data)) { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + auto* patch_pointer = PBYTE(pointer); + set(patch_pointer, 0xE8); + set(patch_pointer + 1, + std::int32_t(size_t(data) - (size_t(pointer) + 5))); +} + +void call(const size_t pointer, void* data) { + return call(reinterpret_cast(pointer), data); +} + +void call(const size_t pointer, const size_t data) { + return call(pointer, reinterpret_cast(data)); +} + +void set(std::uintptr_t address, std::vector&& bytes) { + DWORD oldProtect = 0; + + auto* place = reinterpret_cast(address); + VirtualProtect(place, bytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect); + memcpy(place, bytes.data(), bytes.size()); + VirtualProtect(place, bytes.size(), oldProtect, &oldProtect); + FlushInstructionCache(GetCurrentProcess(), place, bytes.size()); +} + +void set(std::uintptr_t address, void* buffer, size_t size) { + DWORD oldProtect = 0; + + auto* place = reinterpret_cast(address); + VirtualProtect(place, size, PAGE_EXECUTE_READWRITE, &oldProtect); + memcpy(place, buffer, size); + VirtualProtect(place, size, oldProtect, &oldProtect); + FlushInstructionCache(GetCurrentProcess(), place, size); +} + +void jump(std::uintptr_t address, void* destination) { + if (!address) + return; + + std::uint8_t* bytes = new std::uint8_t[5]; + *bytes = 0xE9; + *reinterpret_cast(bytes + 1) = + CalculateRelativeJMPAddress(address, destination); + + set(address, bytes, 5); + + delete[] bytes; +} + +void redirect_jump(void* pointer, void* data) { + char* operand_ptr = static_cast(pointer) + 2; + std::int32_t new_operand = reinterpret_cast(data) - + (reinterpret_cast(pointer) + 6); + set(operand_ptr, new_operand); +} + +void redirect_jump(size_t pointer, void* data) { + redirect_jump(reinterpret_cast(pointer), data); +} +} // namespace utils::hook diff --git a/src/utils/hook.hpp b/src/utils/hook.hpp index a80740e..6cae5d3 100644 --- a/src/utils/hook.hpp +++ b/src/utils/hook.hpp @@ -1,120 +1,102 @@ #pragma once #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 -{ - class detour - { - public: - detour() = default; - detour(void* place, void* target); - detour(size_t place, void* target); - ~detour(); +namespace utils::hook { +class detour { +public: + detour() = default; + detour(void* place, void* target); + detour(size_t place, void* target); + ~detour(); - detour(detour&& other) noexcept - { - this->operator=(std::move(other)); - } + detour(detour&& other) noexcept { this->operator=(std::move(other)); } - detour& operator= (detour&& other) noexcept - { - if (this != &other) - { - this->~detour(); + detour& operator=(detour&& other) noexcept { + if (this != &other) { + this->~detour(); - this->place_ = other.place_; - this->original_ = other.original_; + this->place_ = other.place_; + this->original_ = other.original_; - other.place_ = nullptr; - other.original_ = nullptr; - } + other.place_ = nullptr; + other.original_ = nullptr; + } - return *this; - } + return *this; + } - detour(const detour&) = delete; - detour& operator= (const detour&) = delete; + detour(const detour&) = delete; + detour& operator=(const detour&) = delete; - void enable() const; - void disable() const; + void enable() const; + void disable() const; - void create(void* place, void* target); - void create(size_t place, void* target); - void clear(); + void create(void* place, void* target); + void create(size_t place, void* target); + void clear(); - template - T* get() const - { - return static_cast(this->get_original()); - } + template T* get() const { + return static_cast(this->get_original()); + } - template - T invoke(Args... args) - { - return static_cast(this->get_original())(args...); - } + template T invoke(Args... args) { + return static_cast(this->get_original())(args...); + } - [[nodiscard]] void* get_original() const; + [[nodiscard]] void* get_original() const; - private: - void* place_{}; - void* original_{}; - }; +private: + void* place_{}; + void* original_{}; +}; - void nop(void* place, size_t length); - void nop(size_t place, size_t length); +void nop(void* place, size_t length); +void nop(size_t place, size_t length); - void copy(void* place, const void* data, size_t length); - void copy(size_t place, const void* data, size_t length); +void copy(void* place, const void* data, size_t length); +void copy(size_t place, const void* data, size_t length); - bool is_relatively_far(const void* pointer, const void* data, int offset = 5); +bool is_relatively_far(const void* pointer, const void* data, int offset = 5); - void call(void* pointer, void* data); - void call(size_t pointer, void* data); - void call(size_t pointer, size_t data); +void call(void* pointer, void* data); +void call(size_t pointer, void* data); +void call(size_t pointer, size_t data); - void jump(std::uintptr_t address, void* destination); +void jump(std::uintptr_t address, void* destination); - void redirect_jump(void* pointer, void* data); - void redirect_jump(size_t pointer, void* data); +void redirect_jump(void* pointer, void* data); +void redirect_jump(size_t pointer, void* data); - template - T extract(void* address) - { - const auto data = static_cast(address); - const auto offset = *reinterpret_cast(data); - return reinterpret_cast(data + offset + 4); - } - - template - static void set(void* place, T value) - { - DWORD old_protect; - VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); - - *static_cast(place) = value; - - VirtualProtect(place, sizeof(T), old_protect, &old_protect); - FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); - } - - template - static void set(const size_t place, T value) - { - return set(reinterpret_cast(place), value); - } - - template - static T invoke(size_t func, Args ... args) - { - return reinterpret_cast(func)(args...); - } - - template - static T invoke(void* func, Args ... args) - { - return static_cast(func)(args...); - } +template T extract(void* address) { + const auto data = static_cast(address); + const auto offset = *reinterpret_cast(data); + return reinterpret_cast(data + offset + 4); } + +template static void set(void* place, T value) { + DWORD old_protect; + VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); + + *static_cast(place) = value; + + VirtualProtect(place, sizeof(T), old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); +} + +template static void set(const size_t place, T value) { + return set(reinterpret_cast(place), value); +} + +template +static T invoke(size_t func, Args... args) { + return reinterpret_cast(func)(args...); +} + +template +static T invoke(void* func, Args... args) { + return static_cast(func)(args...); +} +} // namespace utils::hook diff --git a/src/utils/info_string.cpp b/src/utils/info_string.cpp index e6199d7..703ff44 100644 --- a/src/utils/info_string.cpp +++ b/src/utils/info_string.cpp @@ -1,65 +1,50 @@ #include "info_string.hpp" #include "string.hpp" -namespace utils -{ - info_string::info_string(const std::string& buffer) - { - this->parse(buffer); - } +namespace utils { +info_string::info_string(const std::string& buffer) { this->parse(buffer); } - info_string::info_string(const std::string_view& buffer) - : info_string(std::string{ buffer }) - { - } +info_string::info_string(const std::string_view& buffer) + : info_string(std::string{buffer}) {} - void info_string::set(const std::string& key, const std::string& value) - { - this->key_value_pairs_[key] = value; - } - - std::string info_string::get(const std::string& key) const - { - const auto value = this->key_value_pairs_.find(key); - if (value != this->key_value_pairs_.end()) - { - return value->second; - } - - return ""; - } - - void info_string::parse(std::string buffer) - { - if (buffer[0] == '\\') - { - buffer = buffer.substr(1); - } - - auto key_values = string::split(buffer, '\\'); - for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1); i += 2) - { - const auto& key = key_values[i]; - const auto& value = key_values[i + 1]; - this->key_value_pairs_[key] = value; - } - } - - std::string info_string::build() const - { - //auto first = true; - std::string info_string; - for (auto i = this->key_value_pairs_.begin(); i != this->key_value_pairs_.end(); ++i) - { - //if (first) first = false; - /*else*/ - info_string.append("\\"); - - info_string.append(i->first); // Key - info_string.append("\\"); - info_string.append(i->second); // Value - } - - return info_string; - } +void info_string::set(const std::string& key, const std::string& value) { + this->key_value_pairs_[key] = value; } + +std::string info_string::get(const std::string& key) const { + const auto value = this->key_value_pairs_.find(key); + if (value != this->key_value_pairs_.end()) { + return value->second; + } + + return ""; +} + +void info_string::parse(std::string buffer) { + if (buffer[0] == '\\') { + buffer = buffer.substr(1); + } + + auto key_values = string::split(buffer, '\\'); + for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1); + i += 2) { + const auto& key = key_values[i]; + const auto& value = key_values[i + 1]; + this->key_value_pairs_[key] = value; + } +} + +std::string info_string::build() const { + std::string info_string; + for (auto i = this->key_value_pairs_.begin(); + i != this->key_value_pairs_.end(); ++i) { + info_string.append("\\"); + + info_string.append(i->first); // Key + info_string.append("\\"); + info_string.append(i->second); // Value + } + + return info_string; +} +} // namespace utils diff --git a/src/utils/info_string.hpp b/src/utils/info_string.hpp index 7391041..9a2027c 100644 --- a/src/utils/info_string.hpp +++ b/src/utils/info_string.hpp @@ -3,22 +3,20 @@ #include #include -namespace utils -{ - class info_string - { - public: - info_string() = default; - info_string(const std::string& buffer); - info_string(const std::string_view& buffer); +namespace utils { +class info_string { +public: + info_string() = default; + info_string(const std::string& buffer); + info_string(const std::string_view& buffer); - void set(const std::string& key, const std::string& value); - std::string get(const std::string& key) const; - std::string build() const; + void set(const std::string& key, const std::string& value); + std::string get(const std::string& key) const; + std::string build() const; - private: - std::unordered_map key_value_pairs_{}; +private: + std::unordered_map key_value_pairs_{}; - void parse(std::string buffer); - }; -} + void parse(std::string buffer); +}; +} // namespace utils diff --git a/src/utils/io.cpp b/src/utils/io.cpp index 4968f44..11049d3 100644 --- a/src/utils/io.cpp +++ b/src/utils/io.cpp @@ -2,124 +2,106 @@ #include "nt.hpp" #include -namespace utils::io -{ - bool remove_file(const std::string& file) - { - return DeleteFileA(file.data()) == TRUE; - } - - bool move_file(const std::string& src, const std::string& target) - { - return MoveFileA(src.data(), target.data()) == TRUE; - } - - bool file_exists(const std::string& file) - { - return std::ifstream(file).good(); - } - - bool write_file(const std::string& file, const std::string& data, const bool append) - { - const auto pos = file.find_last_of("/\\"); - if (pos != std::string::npos) - { - create_directory(file.substr(0, pos)); - } - - std::ofstream stream( - file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0)); - - if (stream.is_open()) - { - stream.write(data.data(), data.size()); - stream.close(); - return true; - } - - return false; - } - - std::string read_file(const std::string& file) - { - std::string data; - read_file(file, &data); - return data; - } - - bool read_file(const std::string& file, std::string* data) - { - if (!data) return false; - data->clear(); - - if (file_exists(file)) - { - std::ifstream stream(file, std::ios::binary); - if (!stream.is_open()) return false; - - stream.seekg(0, std::ios::end); - const std::streamsize size = stream.tellg(); - stream.seekg(0, std::ios::beg); - - if (size > -1) - { - data->resize(static_cast(size)); - stream.read(const_cast(data->data()), size); - stream.close(); - return true; - } - } - - return false; - } - - size_t file_size(const std::string& file) - { - if (file_exists(file)) - { - std::ifstream stream(file, std::ios::binary); - - if (stream.good()) - { - stream.seekg(0, std::ios::end); - return static_cast(stream.tellg()); - } - } - - return 0; - } - - bool create_directory(const std::string& directory) - { - return std::filesystem::create_directories(directory); - } - - bool directory_exists(const std::string& directory) - { - return std::filesystem::is_directory(directory); - } - - bool directory_is_empty(const std::string& directory) - { - return std::filesystem::is_empty(directory); - } - - std::vector list_files(const std::string& directory) - { - std::vector files; - - for (auto& file : std::filesystem::directory_iterator(directory)) - { - files.push_back(file.path().generic_string()); - } - - return files; - } - - void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target) - { - std::filesystem::copy(src, target, - std::filesystem::copy_options::overwrite_existing | - std::filesystem::copy_options::recursive); - } +namespace utils::io { +bool remove_file(const std::string& file) { + return DeleteFileA(file.data()) == TRUE; } + +bool move_file(const std::string& src, const std::string& target) { + return MoveFileA(src.data(), target.data()) == TRUE; +} + +bool file_exists(const std::string& file) { return std::ifstream(file).good(); } + +bool write_file(const std::string& file, const std::string& data, + const bool append) { + const auto pos = file.find_last_of("/\\"); + if (pos != std::string::npos) { + create_directory(file.substr(0, pos)); + } + + std::ofstream stream(file, std::ios::binary | std::ofstream::out | + (append ? std::ofstream::app : 0)); + + if (stream.is_open()) { + stream.write(data.data(), data.size()); + stream.close(); + return true; + } + + return false; +} + +std::string read_file(const std::string& file) { + std::string data; + read_file(file, &data); + return data; +} + +bool read_file(const std::string& file, std::string* data) { + if (!data) + return false; + data->clear(); + + if (file_exists(file)) { + std::ifstream stream(file, std::ios::binary); + if (!stream.is_open()) + return false; + + stream.seekg(0, std::ios::end); + const std::streamsize size = stream.tellg(); + stream.seekg(0, std::ios::beg); + + if (size > -1) { + data->resize(static_cast(size)); + stream.read(const_cast(data->data()), size); + stream.close(); + return true; + } + } + + return false; +} + +size_t file_size(const std::string& file) { + if (file_exists(file)) { + std::ifstream stream(file, std::ios::binary); + + if (stream.good()) { + stream.seekg(0, std::ios::end); + return static_cast(stream.tellg()); + } + } + + return 0; +} + +bool create_directory(const std::string& directory) { + return std::filesystem::create_directories(directory); +} + +bool directory_exists(const std::string& directory) { + return std::filesystem::is_directory(directory); +} + +bool directory_is_empty(const std::string& directory) { + return std::filesystem::is_empty(directory); +} + +std::vector list_files(const std::string& directory) { + std::vector files; + + for (auto& file : std::filesystem::directory_iterator(directory)) { + files.push_back(file.path().generic_string()); + } + + return files; +} + +void copy_folder(const std::filesystem::path& src, + const std::filesystem::path& target) { + std::filesystem::copy(src, target, + std::filesystem::copy_options::overwrite_existing | + std::filesystem::copy_options::recursive); +} +} // namespace utils::io diff --git a/src/utils/io.hpp b/src/utils/io.hpp index ab4ebaa..8f04086 100644 --- a/src/utils/io.hpp +++ b/src/utils/io.hpp @@ -1,21 +1,22 @@ #pragma once +#include #include #include -#include -namespace utils::io -{ - bool remove_file(const std::string& file); - bool move_file(const std::string& src, const std::string& target); - bool file_exists(const std::string& file); - bool write_file(const std::string& file, const std::string& data, bool append = false); - bool read_file(const std::string& file, std::string* data); - std::string read_file(const std::string& file); - size_t file_size(const std::string& file); - bool create_directory(const std::string& directory); - bool directory_exists(const std::string& directory); - bool directory_is_empty(const std::string& directory); - std::vector list_files(const std::string& directory); - void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target); -} +namespace utils::io { +bool remove_file(const std::string& file); +bool move_file(const std::string& src, const std::string& target); +bool file_exists(const std::string& file); +bool write_file(const std::string& file, const std::string& data, + bool append = false); +bool read_file(const std::string& file, std::string* data); +std::string read_file(const std::string& file); +size_t file_size(const std::string& file); +bool create_directory(const std::string& directory); +bool directory_exists(const std::string& directory); +bool directory_is_empty(const std::string& directory); +std::vector list_files(const std::string& directory); +void copy_folder(const std::filesystem::path& src, + const std::filesystem::path& target); +} // namespace utils::io diff --git a/src/utils/memory.cpp b/src/utils/memory.cpp index 52d4677..89787b7 100644 --- a/src/utils/memory.cpp +++ b/src/utils/memory.cpp @@ -1,165 +1,134 @@ #include "memory.hpp" #include "nt.hpp" -namespace utils -{ - memory::allocator memory::mem_allocator_; +namespace utils { +memory::allocator memory::mem_allocator_; - memory::allocator::~allocator() - { - this->clear(); - } +memory::allocator::~allocator() { this->clear(); } - void memory::allocator::clear() - { - std::lock_guard _(this->mutex_); +void memory::allocator::clear() { + std::lock_guard _(this->mutex_); - for (auto& data : this->pool_) - { - memory::free(data); - } + for (auto& data : this->pool_) { + memory::free(data); + } - this->pool_.clear(); - } - - void memory::allocator::free(void* data) - { - std::lock_guard _(this->mutex_); - - const auto j = std::find(this->pool_.begin(), this->pool_.end(), data); - if (j != this->pool_.end()) - { - memory::free(data); - this->pool_.erase(j); - } - } - - void memory::allocator::free(const void* data) - { - this->free(const_cast(data)); - } - - void* memory::allocator::allocate(const size_t length) - { - std::lock_guard _(this->mutex_); - - const auto data = memory::allocate(length); - this->pool_.push_back(data); - return data; - } - - bool memory::allocator::empty() const - { - return this->pool_.empty(); - } - - char* memory::allocator::duplicate_string(const std::string& string) - { - std::lock_guard _(this->mutex_); - - const auto data = memory::duplicate_string(string); - this->pool_.push_back(data); - return data; - } - - void* memory::allocate(const size_t length) - { - return calloc(length, 1); - } - - char* memory::duplicate_string(const std::string& string) - { - const auto new_string = allocate_array(string.size() + 1); - std::memcpy(new_string, string.data(), string.size()); - return new_string; - } - - void memory::free(void* data) - { - if (data) - { - ::free(data); - } - } - - void memory::free(const void* data) - { - free(const_cast(data)); - } - - bool memory::is_set(const void* mem, const char chr, const size_t length) - { - const auto mem_arr = static_cast(mem); - - for (size_t i = 0; i < length; ++i) - { - if (mem_arr[i] != chr) - { - return false; - } - } - - return true; - } - - bool memory::is_bad_read_ptr(const void* ptr) - { - MEMORY_BASIC_INFORMATION mbi = {}; - if (VirtualQuery(ptr, &mbi, sizeof(mbi))) - { - const DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | - PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); - auto b = !(mbi.Protect & mask); - // check the page is not a guard page - if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; - - return b; - } - return true; - } - - bool memory::is_bad_code_ptr(const void* ptr) - { - MEMORY_BASIC_INFORMATION mbi = {}; - if (VirtualQuery(ptr, &mbi, sizeof(mbi))) - { - const DWORD mask = (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); - auto b = !(mbi.Protect & mask); - // check the page is not a guard page - if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; - - return b; - } - return true; - } - - bool memory::is_rdata_ptr(void* pointer) - { - const std::string rdata = ".rdata"; - const auto pointer_lib = utils::nt::library::get_by_address(pointer); - - for (const auto& section : pointer_lib.get_section_headers()) - { - const auto size = sizeof(section->Name); - char name[size + 1]; - name[size] = 0; - std::memcpy(name, section->Name, size); - - if (name == rdata) - { - const auto target = size_t(pointer); - const size_t source_start = size_t(pointer_lib.get_ptr()) + section->PointerToRawData; - const size_t source_end = source_start + section->SizeOfRawData; - - return target >= source_start && target <= source_end; - } - } - - return false; - } - - memory::allocator* memory::get_allocator() - { - return &memory::mem_allocator_; - } + this->pool_.clear(); } + +void memory::allocator::free(void* data) { + std::lock_guard _(this->mutex_); + + const auto j = std::find(this->pool_.begin(), this->pool_.end(), data); + if (j != this->pool_.end()) { + memory::free(data); + this->pool_.erase(j); + } +} + +void memory::allocator::free(const void* data) { + this->free(const_cast(data)); +} + +void* memory::allocator::allocate(const size_t length) { + std::lock_guard _(this->mutex_); + + const auto data = memory::allocate(length); + this->pool_.push_back(data); + return data; +} + +bool memory::allocator::empty() const { return this->pool_.empty(); } + +char* memory::allocator::duplicate_string(const std::string& string) { + std::lock_guard _(this->mutex_); + + const auto data = memory::duplicate_string(string); + this->pool_.push_back(data); + return data; +} + +void* memory::allocate(const size_t length) { return calloc(length, 1); } + +char* memory::duplicate_string(const std::string& string) { + const auto new_string = allocate_array(string.size() + 1); + std::memcpy(new_string, string.data(), string.size()); + return new_string; +} + +void memory::free(void* data) { + if (data) { + ::free(data); + } +} + +void memory::free(const void* data) { free(const_cast(data)); } + +bool memory::is_set(const void* mem, const char chr, const size_t length) { + const auto mem_arr = static_cast(mem); + + for (size_t i = 0; i < length; ++i) { + if (mem_arr[i] != chr) { + return false; + } + } + + return true; +} + +bool memory::is_bad_read_ptr(const void* ptr) { + MEMORY_BASIC_INFORMATION mbi = {}; + if (VirtualQuery(ptr, &mbi, sizeof(mbi))) { + const DWORD mask = + (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | + PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + auto b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) + b = true; + + return b; + } + return true; +} + +bool memory::is_bad_code_ptr(const void* ptr) { + MEMORY_BASIC_INFORMATION mbi = {}; + if (VirtualQuery(ptr, &mbi, sizeof(mbi))) { + const DWORD mask = + (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + auto b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) + b = true; + + return b; + } + return true; +} + +bool memory::is_rdata_ptr(void* pointer) { + const std::string rdata = ".rdata"; + const auto pointer_lib = utils::nt::library::get_by_address(pointer); + + for (const auto& section : pointer_lib.get_section_headers()) { + const auto size = sizeof(section->Name); + char name[size + 1]; + name[size] = 0; + std::memcpy(name, section->Name, size); + + if (name == rdata) { + const auto target = size_t(pointer); + const size_t source_start = + size_t(pointer_lib.get_ptr()) + section->PointerToRawData; + const size_t source_end = source_start + section->SizeOfRawData; + + return target >= source_start && target <= source_end; + } + } + + return false; +} + +memory::allocator* memory::get_allocator() { return &memory::mem_allocator_; } +} // namespace utils diff --git a/src/utils/memory.hpp b/src/utils/memory.hpp index 5af5645..b12f238 100644 --- a/src/utils/memory.hpp +++ b/src/utils/memory.hpp @@ -3,73 +3,63 @@ #include #include -namespace utils -{ - class memory final - { - public: - class allocator final - { - public: - ~allocator(); +namespace utils { +class memory final { +public: + class allocator final { + public: + ~allocator(); - void clear(); + void clear(); - void free(void* data); + void free(void* data); - void free(const void* data); + void free(const void* data); - void* allocate(size_t length); + void* allocate(size_t length); - template - inline T* allocate() - { - return this->allocate_array(1); - } + template inline T* allocate() { + return this->allocate_array(1); + } - template - inline T* allocate_array(const size_t count = 1) - { - return static_cast(this->allocate(count * sizeof(T))); - } + template inline T* allocate_array(const size_t count = 1) { + return static_cast(this->allocate(count * sizeof(T))); + } - bool empty() const; + bool empty() const; - char* duplicate_string(const std::string& string); + char* duplicate_string(const std::string& string); - private: - std::mutex mutex_; - std::vector pool_; - }; + private: + std::mutex mutex_; + std::vector pool_; + }; - static void* allocate(size_t length); + static void* allocate(size_t length); - template - static inline T* allocate() - { - return allocate_array(1); - } + template static inline T* allocate() { + return allocate_array(1); + } - template - static inline T* allocate_array(const size_t count = 1) - { - return static_cast(allocate(count * sizeof(T))); - } + template + static inline T* allocate_array(const size_t count = 1) { + return static_cast(allocate(count * sizeof(T))); + } - static char* duplicate_string(const std::string& string); + static char* duplicate_string(const std::string& string); - static void free(void* data); - static void free(const void* data); + static void free(void* data); + static void free(const void* data); - static bool is_set(const void* mem, char chr, size_t length); + static bool is_set(const void* mem, char chr, size_t length); - static bool is_bad_read_ptr(const void* ptr); - static bool is_bad_code_ptr(const void* ptr); - static bool is_rdata_ptr(void* ptr); + static bool is_bad_read_ptr(const void* ptr); + static bool is_bad_code_ptr(const void* ptr); + static bool is_rdata_ptr(void* ptr); - static allocator* get_allocator(); + static allocator* get_allocator(); - private: - static allocator mem_allocator_; - }; -} +private: + static allocator mem_allocator_; +}; +} // namespace utils diff --git a/src/utils/nt.cpp b/src/utils/nt.cpp index 3d12c9e..da93ba8 100644 --- a/src/utils/nt.cpp +++ b/src/utils/nt.cpp @@ -1,254 +1,240 @@ #include "nt.hpp" -namespace utils::nt -{ - library library::load(const std::string& name) - { - return library(LoadLibraryA(name.data())); - } - - library library::load(const std::filesystem::path& path) - { - return library::load(path.generic_string()); - } - - library library::get_by_address(void* address) - { - HMODULE handle = nullptr; - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(address), &handle); - return library(handle); - } - - library::library() - { - this->module_ = GetModuleHandleA(nullptr); - } - - library::library(const std::string& name) - { - this->module_ = GetModuleHandleA(name.data()); - } - - library::library(const HMODULE handle) - { - this->module_ = handle; - } - - bool library::operator==(const library& obj) const - { - return this->module_ == obj.module_; - } - - library::operator bool() const - { - 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(this->get_ptr() + this->get_dos_header()->e_lfanew); - } - - PIMAGE_DOS_HEADER library::get_dos_header() const - { - return reinterpret_cast(this->get_ptr()); - } - - PIMAGE_OPTIONAL_HEADER library::get_optional_header() const - { - if (!this->is_valid()) return nullptr; - return &this->get_nt_headers()->OptionalHeader; - } - - std::vector library::get_section_headers() const - { - std::vector headers; - - auto nt_headers = this->get_nt_headers(); - auto section = IMAGE_FIRST_SECTION(nt_headers); - - for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section) - { - if (section) headers.push_back(section); - else OutputDebugStringA("There was an invalid section :O"); - } - - return headers; - } - - std::uint8_t* library::get_ptr() const - { - return reinterpret_cast(this->module_); - } - - void library::unprotect() const - { - if (!this->is_valid()) return; - - DWORD protection; - VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE, - &protection); - } - - size_t library::get_relative_entry_point() const - { - if (!this->is_valid()) return 0; - return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; - } - - void* library::get_entry_point() const - { - if (!this->is_valid()) return nullptr; - return this->get_ptr() + this->get_relative_entry_point(); - } - - bool library::is_valid() const - { - return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; - } - - std::string library::get_name() const - { - if (!this->is_valid()) return ""; - - auto path = this->get_path(); - const auto pos = path.find_last_of("/\\"); - if (pos == std::string::npos) return path; - - return path.substr(pos + 1); - } - - std::string library::get_path() const - { - if (!this->is_valid()) return ""; - - char name[MAX_PATH] = {0}; - GetModuleFileNameA(this->module_, name, sizeof name); - - return name; - } - - std::string library::get_folder() const - { - if (!this->is_valid()) return ""; - - const auto path = std::filesystem::path(this->get_path()); - return path.parent_path().generic_string(); - } - - void library::free() - { - if (this->is_valid()) - { - FreeLibrary(this->module_); - this->module_ = nullptr; - } - } - - HMODULE library::get_handle() const - { - return this->module_; - } - - void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const - { - if (!this->is_valid()) return nullptr; - - const library other_module(module_name); - if (!other_module.is_valid()) return nullptr; - - auto* const target_function = other_module.get_proc(proc_name); - if (!target_function) return nullptr; - - auto* header = this->get_optional_header(); - if (!header) return nullptr; - - auto* import_descriptor = reinterpret_cast(this->get_ptr() + header->DataDirectory - [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); - - while (import_descriptor->Name) - { - if (!_stricmp(reinterpret_cast(this->get_ptr() + import_descriptor->Name), module_name.data())) - { - auto* original_thunk_data = reinterpret_cast(import_descriptor-> - OriginalFirstThunk + this->get_ptr()); - auto* thunk_data = reinterpret_cast(import_descriptor->FirstThunk + this-> - get_ptr()); - - while (original_thunk_data->u1.AddressOfData) - { - const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF; - - if (ordinal_number > 0xFFFF) continue; - - if (GetProcAddress(other_module.module_, reinterpret_cast(ordinal_number)) == - target_function) - { - return reinterpret_cast(&thunk_data->u1.Function); - } - - ++original_thunk_data; - ++thunk_data; - } - - //break; - } - - ++import_descriptor; - } - - return nullptr; - } - - void raise_hard_exception() - { - int data = false; - const library ntdll("ntdll.dll"); - ntdll.invoke_pascal("RtlAdjustPrivilege", 19, true, false, &data); - ntdll.invoke_pascal("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data); - } - - std::string load_resource(const int id) - { - auto* const res = FindResource(library(), MAKEINTRESOURCE(id), RT_RCDATA); - if (!res) return {}; - - auto* const handle = LoadResource(nullptr, res); - if (!handle) return {}; - - return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res)); - } - - void relaunch_self() - { - const utils::nt::library self; - - STARTUPINFOA startup_info; - PROCESS_INFORMATION process_info; - - ZeroMemory(&startup_info, sizeof(startup_info)); - ZeroMemory(&process_info, sizeof(process_info)); - startup_info.cb = sizeof(startup_info); - - char current_dir[MAX_PATH]; - GetCurrentDirectoryA(sizeof(current_dir), current_dir); - auto* const command_line = GetCommandLineA(); - - CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false, 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.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess); - } - - void terminate(const uint32_t code) - { - TerminateProcess(GetCurrentProcess(), code); - } +namespace utils::nt { +library library::load(const std::string& name) { + return library(LoadLibraryA(name.data())); } + +library library::load(const std::filesystem::path& path) { + return library::load(path.generic_string()); +} + +library library::get_by_address(void* address) { + HMODULE handle = nullptr; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + static_cast(address), &handle); + return library(handle); +} + +library::library() { this->module_ = GetModuleHandleA(nullptr); } + +library::library(const std::string& name) { + this->module_ = GetModuleHandleA(name.data()); +} + +library::library(const HMODULE handle) { this->module_ = handle; } + +bool library::operator==(const library& obj) const { + return this->module_ == obj.module_; +} + +library::operator bool() const { 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(this->get_ptr() + + this->get_dos_header()->e_lfanew); +} + +PIMAGE_DOS_HEADER library::get_dos_header() const { + return reinterpret_cast(this->get_ptr()); +} + +PIMAGE_OPTIONAL_HEADER library::get_optional_header() const { + if (!this->is_valid()) + return nullptr; + return &this->get_nt_headers()->OptionalHeader; +} + +std::vector library::get_section_headers() const { + std::vector headers; + + auto nt_headers = this->get_nt_headers(); + auto section = IMAGE_FIRST_SECTION(nt_headers); + + for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; + ++i, ++section) { + if (section) + headers.push_back(section); + else + OutputDebugStringA("There was an invalid section :O"); + } + + return headers; +} + +std::uint8_t* library::get_ptr() const { + return reinterpret_cast(this->module_); +} + +void library::unprotect() const { + if (!this->is_valid()) + return; + + DWORD protection; + VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, + PAGE_EXECUTE_READWRITE, &protection); +} + +size_t library::get_relative_entry_point() const { + if (!this->is_valid()) + return 0; + return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; +} + +void* library::get_entry_point() const { + if (!this->is_valid()) + return nullptr; + return this->get_ptr() + this->get_relative_entry_point(); +} + +bool library::is_valid() const { + return this->module_ != nullptr && + this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; +} + +std::string library::get_name() const { + if (!this->is_valid()) + return ""; + + auto path = this->get_path(); + const auto pos = path.find_last_of("/\\"); + if (pos == std::string::npos) + return path; + + return path.substr(pos + 1); +} + +std::string library::get_path() const { + if (!this->is_valid()) + return ""; + + char name[MAX_PATH] = {0}; + GetModuleFileNameA(this->module_, name, sizeof name); + + return name; +} + +std::string library::get_folder() const { + if (!this->is_valid()) + return ""; + + const auto path = std::filesystem::path(this->get_path()); + return path.parent_path().generic_string(); +} + +void library::free() { + if (this->is_valid()) { + FreeLibrary(this->module_); + this->module_ = nullptr; + } +} + +HMODULE library::get_handle() const { return this->module_; } + +void** library::get_iat_entry(const std::string& module_name, + const std::string& proc_name) const { + if (!this->is_valid()) + return nullptr; + + const library other_module(module_name); + if (!other_module.is_valid()) + return nullptr; + + auto* const target_function = other_module.get_proc(proc_name); + if (!target_function) + return nullptr; + + auto* header = this->get_optional_header(); + if (!header) + return nullptr; + + auto* import_descriptor = reinterpret_cast( + this->get_ptr() + + header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + + while (import_descriptor->Name) { + if (!_stricmp( + reinterpret_cast(this->get_ptr() + import_descriptor->Name), + module_name.data())) { + auto* original_thunk_data = reinterpret_cast( + import_descriptor->OriginalFirstThunk + this->get_ptr()); + auto* thunk_data = reinterpret_cast( + import_descriptor->FirstThunk + this->get_ptr()); + + while (original_thunk_data->u1.AddressOfData) { + const size_t ordinal_number = + original_thunk_data->u1.AddressOfData & 0xFFFFFFF; + + if (ordinal_number > 0xFFFF) + continue; + + if (GetProcAddress(other_module.module_, + reinterpret_cast(ordinal_number)) == + target_function) { + return reinterpret_cast(&thunk_data->u1.Function); + } + + ++original_thunk_data; + ++thunk_data; + } + + // break; + } + + ++import_descriptor; + } + + return nullptr; +} + +void raise_hard_exception() { + int data = false; + const library ntdll("ntdll.dll"); + ntdll.invoke_pascal("RtlAdjustPrivilege", 19, true, false, &data); + ntdll.invoke_pascal("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, + 6, &data); +} + +std::string load_resource(const int id) { + auto* const res = FindResource(library(), MAKEINTRESOURCE(id), RT_RCDATA); + if (!res) + return {}; + + auto* const handle = LoadResource(nullptr, res); + if (!handle) + return {}; + + return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res)); +} + +void relaunch_self() { + const utils::nt::library self; + + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + char current_dir[MAX_PATH]; + GetCurrentDirectoryA(sizeof(current_dir), current_dir); + auto* const command_line = GetCommandLineA(); + + CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false, + 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.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) + CloseHandle(process_info.hProcess); +} + +void terminate(const uint32_t code) { + TerminateProcess(GetCurrentProcess(), code); +} +} // namespace utils::nt diff --git a/src/utils/nt.hpp b/src/utils/nt.hpp index 86001be..5cfd331 100644 --- a/src/utils/nt.hpp +++ b/src/utils/nt.hpp @@ -12,99 +12,95 @@ #undef min #endif -#include -#include #include +#include +#include -namespace utils::nt -{ - class library final - { - public: - static library load(const std::string& name); - static library load(const std::filesystem::path& path); - static library get_by_address(void* address); +namespace utils::nt { +class library final { +public: + static library load(const std::string& name); + static library load(const std::filesystem::path& path); + static library get_by_address(void* address); - library(); - explicit library(const std::string& name); - explicit library(HMODULE handle); + library(); + explicit library(const std::string& name); + 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; + bool operator!=(const library& obj) const { return !(*this == obj); }; + bool operator==(const library& obj) const; - operator bool() const; - operator HMODULE() const; + operator bool() const; + operator HMODULE() const; - void unprotect() const; - void* get_entry_point() const; - size_t get_relative_entry_point() const; + void unprotect() const; + void* get_entry_point() const; + size_t get_relative_entry_point() const; - bool is_valid() const; - std::string get_name() const; - std::string get_path() const; - std::string get_folder() const; - std::uint8_t* get_ptr() const; - void free(); + bool is_valid() const; + std::string get_name() const; + std::string get_path() const; + std::string get_folder() const; + std::uint8_t* get_ptr() const; + void free(); - HMODULE get_handle() const; + HMODULE get_handle() const; - template - T get_proc(const std::string& process) const - { - if (!this->is_valid()) T{}; - return reinterpret_cast(GetProcAddress(this->module_, process.data())); - } + template T get_proc(const std::string& process) const { + if (!this->is_valid()) + T{}; + return reinterpret_cast(GetProcAddress(this->module_, process.data())); + } - template - std::function get(const std::string& process) const - { - if (!this->is_valid()) return std::function(); - return static_cast(this->get_proc(process)); - } + template std::function get(const std::string& process) const { + if (!this->is_valid()) + return std::function(); + return static_cast(this->get_proc(process)); + } - template - T invoke(const std::string& process, Args ... args) const - { - auto method = this->get(process); - if (method) return method(args...); - return T(); - } + template + T invoke(const std::string& process, Args... args) const { + auto method = this->get(process); + if (method) + return method(args...); + return T(); + } - template - T invoke_pascal(const std::string& process, Args ... args) const - { - auto method = this->get(process); - if (method) return method(args...); - return T(); - } + template + T invoke_pascal(const std::string& process, Args... args) const { + auto method = this->get(process); + if (method) + return method(args...); + return T(); + } - template - T invoke_this(const std::string& process, void* this_ptr, Args ... args) const - { - auto method = this->get(this_ptr, process); - if (method) return method(args...); - return T(); - } + template + T invoke_this(const std::string& process, void* this_ptr, + Args... args) const { + auto method = this->get(this_ptr, process); + if (method) + return method(args...); + return T(); + } - std::vector get_section_headers() const; + std::vector get_section_headers() const; - PIMAGE_NT_HEADERS get_nt_headers() const; - PIMAGE_DOS_HEADER get_dos_header() const; - PIMAGE_OPTIONAL_HEADER get_optional_header() const; + PIMAGE_NT_HEADERS get_nt_headers() const; + PIMAGE_DOS_HEADER get_dos_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: - HMODULE module_; - }; +private: + HMODULE module_; +}; - __declspec(noreturn) void raise_hard_exception(); - std::string load_resource(int id); +__declspec(noreturn) void raise_hard_exception(); +std::string load_resource(int id); - void relaunch_self(); - __declspec(noreturn) void terminate(uint32_t code = 0); -} +void relaunch_self(); +__declspec(noreturn) void terminate(uint32_t code = 0); +} // namespace utils::nt diff --git a/src/utils/signature.cpp b/src/utils/signature.cpp index 9bb8c62..bca9983 100644 --- a/src/utils/signature.cpp +++ b/src/utils/signature.cpp @@ -1,212 +1,191 @@ #include "signature.hpp" -#include #include +#include #include -namespace utils::hook -{ - void signature::load_pattern(const std::string& pattern) - { - this->mask_.clear(); - this->pattern_.clear(); +namespace utils::hook { +void signature::load_pattern(const std::string& pattern) { + this->mask_.clear(); + this->pattern_.clear(); - uint8_t nibble = 0; - auto has_nibble = false; + uint8_t nibble = 0; + auto has_nibble = false; - for (auto val : pattern) - { - if (val == ' ') continue; - if (val == '?') - { - this->mask_.push_back(val); - this->pattern_.push_back(0); - } - else - { - if ((val < '0' || val > '9') && (val < 'A' || val > 'F') && (val < 'a' || val > 'f')) - { - throw std::runtime_error("Invalid pattern"); - } + for (auto val : pattern) { + if (val == ' ') + continue; + if (val == '?') { + this->mask_.push_back(val); + this->pattern_.push_back(0); + } else { + if ((val < '0' || val > '9') && (val < 'A' || val > 'F') && + (val < 'a' || val > 'f')) { + throw std::runtime_error("Invalid pattern"); + } - char str[] = {val, 0}; - const auto current_nibble = static_cast(strtol(str, nullptr, 16)); + char str[] = {val, 0}; + const auto current_nibble = + static_cast(strtol(str, nullptr, 16)); - if (!has_nibble) - { - has_nibble = true; - nibble = current_nibble; - } - else - { - has_nibble = false; - const uint8_t byte = current_nibble | (nibble << 4); + if (!has_nibble) { + has_nibble = true; + nibble = current_nibble; + } else { + has_nibble = false; + const uint8_t byte = current_nibble | (nibble << 4); - this->mask_.push_back('x'); - this->pattern_.push_back(byte); - } - } - } + this->mask_.push_back('x'); + this->pattern_.push_back(byte); + } + } + } - while (!this->mask_.empty() && this->mask_.back() == '?') - { - this->mask_.pop_back(); - this->pattern_.pop_back(); - } + while (!this->mask_.empty() && this->mask_.back() == '?') { + this->mask_.pop_back(); + this->pattern_.pop_back(); + } - if (this->has_sse_support()) - { - while (this->pattern_.size() < 16) - { - this->pattern_.push_back(0); - } - } + if (this->has_sse_support()) { + while (this->pattern_.size() < 16) { + this->pattern_.push_back(0); + } + } - if (has_nibble) - { - throw std::runtime_error("Invalid pattern"); - } - } - - std::vector signature::process_range(uint8_t* start, const size_t length) const - { - if (this->has_sse_support()) return this->process_range_vectorized(start, length); - return this->process_range_linear(start, length); - } - - std::vector signature::process_range_linear(uint8_t* start, const size_t length) const - { - std::vector result; - - for (size_t i = 0; i < length; ++i) - { - const auto address = start + i; - - size_t j = 0; - for (; j < this->mask_.size(); ++j) - { - if (this->mask_[j] != '?' && this->pattern_[j] != address[j]) - { - break; - } - } - - if (j == this->mask_.size()) - { - result.push_back(size_t(address)); - } - } - - return result; - } - - std::vector signature::process_range_vectorized(uint8_t* start, const size_t length) const - { - std::vector result; - __declspec(align(16)) char desired_mask[16] = {0}; - - for (size_t i = 0; i < this->mask_.size(); i++) - { - desired_mask[i / 8] |= (this->mask_[i] == '?' ? 0 : 1) << i % 8; - } - - const auto mask = _mm_load_si128(reinterpret_cast(desired_mask)); - const auto comparand = _mm_loadu_si128(reinterpret_cast(this->pattern_.data())); - - for (size_t i = 0; i < length; ++i) - { - const auto address = start + i; - const auto value = _mm_loadu_si128(reinterpret_cast(address)); - const auto comparison = _mm_cmpestrm(value, 16, comparand, static_cast(this->mask_.size()), - _SIDD_CMP_EQUAL_EACH); - - const auto matches = _mm_and_si128(mask, comparison); - const auto equivalence = _mm_xor_si128(mask, matches); - - if (_mm_test_all_zeros(equivalence, equivalence)) - { - result.push_back(size_t(address)); - } - } - - return result; - } - - signature::signature_result signature::process() const - { - const auto range = this->length_ - this->mask_.size(); - const auto cores = std::max(1u, std::thread::hardware_concurrency()); - - if (range <= cores * 10ull) return this->process_serial(); - return this->process_parallel(); - } - - signature::signature_result signature::process_serial() const - { - const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); - return {this->process_range(this->start_, this->length_ - sub)}; - } - - signature::signature_result signature::process_parallel() const - { - const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); - const auto range = this->length_ - sub; - const auto cores = std::max(1u, std::thread::hardware_concurrency() / 2); - // Only use half of the available cores - const auto grid = range / cores; - - std::mutex mutex; - std::vector result; - std::vector threads; - - for (auto i = 0u; i < cores; ++i) - { - const auto start = this->start_ + (grid * i); - const auto length = (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid; - threads.emplace_back([&, start, length]() - { - auto local_result = this->process_range(start, length); - if (local_result.empty()) return; - - std::lock_guard _(mutex); - for (const auto& address : local_result) - { - result.push_back(address); - } - }); - } - - for (auto& t : threads) - { - if (t.joinable()) - { - t.join(); - } - } - - std::sort(result.begin(), result.end()); - return {std::move(result)}; - } - - bool signature::has_sse_support() const - { - if (this->mask_.size() <= 16) - { - int cpu_id[4]; - __cpuid(cpu_id, 0); - - if (cpu_id[0] >= 1) - { - __cpuidex(cpu_id, 1, 0); - return (cpu_id[2] & (1 << 20)) != 0; - } - } - - return false; - } + if (has_nibble) { + throw std::runtime_error("Invalid pattern"); + } } -utils::hook::signature::signature_result operator"" _sig(const char* str, const size_t len) -{ - return utils::hook::signature(std::string(str, len)).process(); +std::vector signature::process_range(uint8_t* start, + const size_t length) const { + if (this->has_sse_support()) + return this->process_range_vectorized(start, length); + return this->process_range_linear(start, length); +} + +std::vector signature::process_range_linear(uint8_t* start, + const size_t length) const { + std::vector result; + + for (size_t i = 0; i < length; ++i) { + const auto address = start + i; + + size_t j = 0; + for (; j < this->mask_.size(); ++j) { + if (this->mask_[j] != '?' && this->pattern_[j] != address[j]) { + break; + } + } + + if (j == this->mask_.size()) { + result.push_back(size_t(address)); + } + } + + return result; +} + +std::vector +signature::process_range_vectorized(uint8_t* start, const size_t length) const { + std::vector result; + __declspec(align(16)) char desired_mask[16] = {0}; + + for (size_t i = 0; i < this->mask_.size(); i++) { + desired_mask[i / 8] |= (this->mask_[i] == '?' ? 0 : 1) << i % 8; + } + + const auto mask = + _mm_load_si128(reinterpret_cast(desired_mask)); + const auto comparand = + _mm_loadu_si128(reinterpret_cast(this->pattern_.data())); + + for (size_t i = 0; i < length; ++i) { + const auto address = start + i; + const auto value = + _mm_loadu_si128(reinterpret_cast(address)); + const auto comparison = + _mm_cmpestrm(value, 16, comparand, static_cast(this->mask_.size()), + _SIDD_CMP_EQUAL_EACH); + + const auto matches = _mm_and_si128(mask, comparison); + const auto equivalence = _mm_xor_si128(mask, matches); + + if (_mm_test_all_zeros(equivalence, equivalence)) { + result.push_back(size_t(address)); + } + } + + return result; +} + +signature::signature_result signature::process() const { + const auto range = this->length_ - this->mask_.size(); + const auto cores = std::max(1u, std::thread::hardware_concurrency()); + + if (range <= cores * 10ull) + return this->process_serial(); + return this->process_parallel(); +} + +signature::signature_result signature::process_serial() const { + const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); + return {this->process_range(this->start_, this->length_ - sub)}; +} + +signature::signature_result signature::process_parallel() const { + const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); + const auto range = this->length_ - sub; + const auto cores = std::max(1u, std::thread::hardware_concurrency() / 2); + // Only use half of the available cores + const auto grid = range / cores; + + std::mutex mutex; + std::vector result; + std::vector threads; + + for (auto i = 0u; i < cores; ++i) { + const auto start = this->start_ + (grid * i); + const auto length = + (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid; + threads.emplace_back([&, start, length]() { + auto local_result = this->process_range(start, length); + if (local_result.empty()) + return; + + std::lock_guard _(mutex); + for (const auto& address : local_result) { + result.push_back(address); + } + }); + } + + for (auto& t : threads) { + if (t.joinable()) { + t.join(); + } + } + + std::sort(result.begin(), result.end()); + return {std::move(result)}; +} + +bool signature::has_sse_support() const { + if (this->mask_.size() <= 16) { + int cpu_id[4]; + __cpuid(cpu_id, 0); + + if (cpu_id[0] >= 1) { + __cpuidex(cpu_id, 1, 0); + return (cpu_id[2] & (1 << 20)) != 0; + } + } + + return false; +} +} // namespace utils::hook + +utils::hook::signature::signature_result operator"" _sig(const char* str, + const size_t len) { + return utils::hook::signature(std::string(str, len)).process(); } diff --git a/src/utils/signature.hpp b/src/utils/signature.hpp index a372832..d5b1531 100644 --- a/src/utils/signature.hpp +++ b/src/utils/signature.hpp @@ -2,72 +2,61 @@ #include "nt.hpp" #include -namespace utils::hook -{ - class signature final - { - public: - class signature_result - { - public: - signature_result(std::vector&& matches) : matches_(std::move(matches)) - { - } +namespace utils::hook { +class signature final { +public: + class signature_result { + public: + signature_result(std::vector&& matches) + : matches_(std::move(matches)) {} - [[nodiscard]] uint8_t* get(const size_t index) const - { - if (index >= this->count()) - { - throw std::runtime_error("Invalid index"); - } + [[nodiscard]] uint8_t* get(const size_t index) const { + if (index >= this->count()) { + throw std::runtime_error("Invalid index"); + } - return reinterpret_cast(this->matches_[index]); - } + return reinterpret_cast(this->matches_[index]); + } - [[nodiscard]] size_t count() const - { - return this->matches_.size(); - } + [[nodiscard]] size_t count() const { return this->matches_.size(); } - private: - std::vector matches_; - }; + private: + std::vector matches_; + }; - explicit signature(const std::string& pattern, const nt::library library = {}) - : signature(pattern, library.get_ptr(), library.get_optional_header()->SizeOfImage) - { - } + explicit signature(const std::string& pattern, const nt::library library = {}) + : signature(pattern, library.get_ptr(), + library.get_optional_header()->SizeOfImage) {} - signature(const std::string& pattern, void* start, void* end) - : signature(pattern, start, size_t(end) - size_t(start)) - { - } + signature(const std::string& pattern, void* start, void* end) + : signature(pattern, start, size_t(end) - size_t(start)) {} - signature(const std::string& pattern, void* start, const size_t length) - : start_(static_cast(start)), length_(length) - { - this->load_pattern(pattern); - } + signature(const std::string& pattern, void* start, const size_t length) + : start_(static_cast(start)), length_(length) { + this->load_pattern(pattern); + } - signature_result process() const; + signature_result process() const; - private: - std::string mask_; - std::basic_string pattern_; +private: + std::string mask_; + std::basic_string pattern_; - uint8_t* start_; - size_t length_; + uint8_t* start_; + size_t length_; - void load_pattern(const std::string& pattern); + void load_pattern(const std::string& pattern); - signature_result process_parallel() const; - signature_result process_serial() const; - std::vector process_range(uint8_t* start, size_t length) const; - std::vector process_range_linear(uint8_t* start, size_t length) const; - std::vector process_range_vectorized(uint8_t* start, size_t length) const; + signature_result process_parallel() const; + signature_result process_serial() const; + std::vector process_range(uint8_t* start, size_t length) const; + std::vector process_range_linear(uint8_t* start, size_t length) const; + std::vector 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); diff --git a/src/utils/string.cpp b/src/utils/string.cpp index 26c59f6..89cf17d 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -1,179 +1,151 @@ #include "string.hpp" -#include -#include #include +#include +#include #include "nt.hpp" -namespace utils::string -{ - const char* va(const char* fmt, ...) - { - static thread_local va_provider<8, 256> provider; +namespace utils::string { +const char* va(const char* fmt, ...) { + static thread_local va_provider<8, 256> provider; - va_list ap; - va_start(ap, fmt); + va_list ap; + va_start(ap, fmt); - const char* result = provider.get(fmt, ap); + const char* result = provider.get(fmt, ap); - va_end(ap); - return result; - } - - std::vector split(const std::string& s, const char delim) - { - std::stringstream ss(s); - std::string item; - std::vector elems; - - while (std::getline(ss, item, delim)) - { - elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson) - } - - return elems; - } - - std::string to_lower(std::string text) - { - std::transform(text.begin(), text.end(), text.begin(), [](const char input) - { - return static_cast(tolower(input)); - }); - - return text; - } - - std::string to_upper(std::string text) - { - std::transform(text.begin(), text.end(), text.begin(), [](const char input) - { - return static_cast(toupper(input)); - }); - - return text; - } - - bool starts_with(const std::string& text, const std::string& substring) - { - return text.find(substring) == 0; - } - - bool ends_with(const std::string& text, const std::string& substring) - { - if (substring.size() > text.size()) return false; - return std::equal(substring.rbegin(), substring.rend(), text.rbegin()); - } - - std::string dump_hex(const std::string& data, const std::string& separator) - { - std::string result; - - for (unsigned int i = 0; i < data.size(); ++i) - { - if (i > 0) - { - result.append(separator); - } - - result.append(va("%02X", data[i] & 0xFF)); - } - - return result; - } - - std::string get_clipboard_data() - { - if (OpenClipboard(nullptr)) - { - std::string data; - - auto* const clipboard_data = GetClipboardData(1u); - if (clipboard_data) - { - auto* const cliptext = static_cast(GlobalLock(clipboard_data)); - if (cliptext) - { - data.append(cliptext); - GlobalUnlock(clipboard_data); - } - } - CloseClipboard(); - - return data; - } - return {}; - } - - void strip(const char* in, char* out, int max) - { - 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; - result.reserve(wstr.size()); - - for (const auto& chr : wstr) - { - result.push_back(static_cast(chr)); - } - - return result; - } - - std::wstring convert(const std::string& str) - { - std::wstring result; - result.reserve(str.size()); - - for (const auto& chr : str) - { - result.push_back(static_cast(chr)); - } - - return result; - } -#pragma warning(pop) - - std::string replace(std::string str, const std::string& from, const std::string& to) - { - if (from.empty()) - { - return str; - } - - size_t start_pos = 0; - while ((start_pos = str.find(from, start_pos)) != std::string::npos) - { - str.replace(start_pos, from.length(), to); - start_pos += to.length(); - } - - return str; - } + va_end(ap); + return result; } + +std::vector split(const std::string& s, const char delim) { + std::stringstream ss(s); + std::string item; + std::vector elems; + + while (std::getline(ss, item, delim)) { + elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 + // (based on comment from @mchiasson) + } + + return elems; +} + +std::string to_lower(std::string text) { + std::transform(text.begin(), text.end(), text.begin(), [](const char input) { + return static_cast(tolower(input)); + }); + + return text; +} + +std::string to_upper(std::string text) { + std::transform(text.begin(), text.end(), text.begin(), [](const char input) { + return static_cast(toupper(input)); + }); + + return text; +} + +bool starts_with(const std::string& text, const std::string& substring) { + return text.find(substring) == 0; +} + +bool ends_with(const std::string& text, const std::string& substring) { + if (substring.size() > text.size()) + return false; + return std::equal(substring.rbegin(), substring.rend(), text.rbegin()); +} + +std::string dump_hex(const std::string& data, const std::string& separator) { + std::string result; + + for (unsigned int i = 0; i < data.size(); ++i) { + if (i > 0) { + result.append(separator); + } + + result.append(va("%02X", data[i] & 0xFF)); + } + + return result; +} + +std::string get_clipboard_data() { + if (OpenClipboard(nullptr)) { + std::string data; + + auto* const clipboard_data = GetClipboardData(1u); + if (clipboard_data) { + auto* const cliptext = static_cast(GlobalLock(clipboard_data)); + if (cliptext) { + data.append(cliptext); + GlobalUnlock(clipboard_data); + } + } + CloseClipboard(); + + return data; + } + return {}; +} + +void strip(const char* in, char* out, int max) { + 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'; +} + +std::string convert(const std::wstring& wstr) { + std::string result; + result.reserve(wstr.size()); + + for (const auto& chr : wstr) { + result.push_back(static_cast(chr)); + } + + return result; +} + +std::wstring convert(const std::string& str) { + std::wstring result; + result.reserve(str.size()); + + for (const auto& chr : str) { + result.push_back(static_cast(chr)); + } + + return result; +} + +std::string replace(std::string str, const std::string& from, + const std::string& to) { + if (from.empty()) { + return str; + } + + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + + return str; +} +} // namespace utils::string diff --git a/src/utils/string.hpp b/src/utils/string.hpp index 6eb25cd..1193fb5 100644 --- a/src/utils/string.hpp +++ b/src/utils/string.hpp @@ -3,98 +3,95 @@ #include #ifndef ARRAYSIZE -template -size_t ARRAYSIZE(Type(&)[n]) { return n; } +template size_t ARRAYSIZE(Type (&)[n]) { return n; } #endif -namespace utils::string -{ - template - class va_provider final - { - public: - static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0"); +namespace utils::string { +template class va_provider final { +public: + 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) - { - ++this->current_buffer_ %= ARRAYSIZE(this->string_pool_); - auto entry = &this->string_pool_[this->current_buffer_]; + char* get(const char* format, const va_list ap) { + ++this->current_buffer_ %= ARRAYSIZE(this->string_pool_); + auto entry = &this->string_pool_[this->current_buffer_]; - if (!entry->size || !entry->buffer) - { - throw std::runtime_error("String pool not initialized"); - } + if (!entry->size || !entry->buffer) { + throw std::runtime_error("String pool not initialized"); + } - while (true) - { - const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); - if (res > 0) break; // Success - if (res == 0) return nullptr; // Error + while (true) { + const int res = + vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); + if (res > 0) + break; // Success + if (res == 0) + return nullptr; // Error - entry->double_size(); - } + entry->double_size(); + } - return entry->buffer; - } + return entry->buffer; + } - private: - class entry final - { - public: - explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr) - { - if (this->size < MinBufferSize) this->size = MinBufferSize; - this->allocate(); - } +private: + class entry final { + public: + explicit entry(const size_t _size = MinBufferSize) + : size(_size), buffer(nullptr) { + if (this->size < MinBufferSize) + this->size = MinBufferSize; + this->allocate(); + } - ~entry() - { - if (this->buffer) memory::get_allocator()->free(this->buffer); - this->size = 0; - this->buffer = nullptr; - } + ~entry() { + if (this->buffer) + memory::get_allocator()->free(this->buffer); + this->size = 0; + this->buffer = nullptr; + } - void allocate() - { - if (this->buffer) memory::get_allocator()->free(this->buffer); - this->buffer = memory::get_allocator()->allocate_array(this->size + 1); - } + void allocate() { + if (this->buffer) + memory::get_allocator()->free(this->buffer); + this->buffer = + memory::get_allocator()->allocate_array(this->size + 1); + } - void double_size() - { - this->size *= 2; - this->allocate(); - } + void double_size() { + this->size *= 2; + this->allocate(); + } - size_t size; - char* buffer; - }; + size_t size; + char* buffer; + }; - size_t current_buffer_; - entry string_pool_[Buffers]; - }; + size_t current_buffer_; + entry string_pool_[Buffers]; +}; - const char* va(const char* fmt, ...); +const char* va(const char* fmt, ...); - std::vector split(const std::string& s, char delim); +std::vector split(const std::string& s, char delim); - std::string to_lower(std::string text); - std::string to_upper(std::string text); - bool starts_with(const std::string& text, const std::string& substring); - bool ends_with(const std::string& text, const std::string& substring); +std::string to_lower(std::string text); +std::string to_upper(std::string text); +bool starts_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); +void strip(const char* in, char* out, int max); - std::string convert(const std::wstring& wstr); - std::wstring convert(const std::string& str); +std::string convert(const std::wstring& wstr); +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); +} // namespace utils::string