diff --git a/src/client/component/binding.cpp b/src/client/component/binding.cpp index 44b47c0..5d5638a 100644 --- a/src/client/component/binding.cpp +++ b/src/client/component/binding.cpp @@ -25,9 +25,7 @@ namespace binding if (value && value < 100) { - const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), - "bind %s \"%s\"\n", key_button, game::command_whitelist[value]); - + const auto len = game::Com_sprintf(&buffer[bytes_used], (buffer_size_align - bytes_used), "bind %s \"%s\"\n", key_button, game::command_whitelist[value]); if (len < 0) { return bytes_used; @@ -40,9 +38,7 @@ namespace binding value -= 100; if (static_cast(value) < custom_binds.size() && !custom_binds[value].empty()) { - const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), - "bind %s \"%s\"\n", key_button, custom_binds[value].data()); - + const auto len = game::Com_sprintf(&buffer[bytes_used], (buffer_size_align - bytes_used), "bind %s \"%s\"\n", key_button, custom_binds[value].data()); if (len < 0) { return bytes_used; diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp index 9391656..6ea61b2 100644 --- a/src/client/component/colors.cpp +++ b/src/client/component/colors.cpp @@ -107,7 +107,7 @@ namespace colors int com_sprintf_stub(char* dest, int size, const char* fmt, const char* name) { - const auto len = sprintf_s(dest, size, fmt, name); + const auto len = game::Com_sprintf(dest, size, fmt, name); if (len < 0) { game::I_strncpyz(dest, "UnnamedAgent", size); diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp index 3e37281..2cc9c22 100644 --- a/src/client/component/console.cpp +++ b/src/client/component/console.cpp @@ -84,15 +84,14 @@ namespace console void print_stub(const char* fmt, ...) { + char buffer[4096]{}; + va_list ap; va_start(ap, fmt); - - char buffer[4096]{}; - const auto res = vsnprintf_s(buffer, _TRUNCATE, fmt, ap); - (void)res; - print_message(buffer); - + [[maybe_unused]] const auto len = vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); + + print_message(buffer); } void append_text(const char* text) diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp index fca1521..81bf2c3 100644 --- a/src/client/component/demonware.cpp +++ b/src/client/component/demonware.cpp @@ -222,7 +222,7 @@ namespace demonware va_list ap; va_start(ap, msg); - vsnprintf_s(buffer, _TRUNCATE, msg, ap); + vsnprintf(buffer, sizeof(buffer), msg, ap); printf("%s: %s\n", function, buffer); va_end(ap); diff --git a/src/client/component/game_console.cpp b/src/client/component/game_console.cpp index 5b8fe91..9a5bc32 100644 --- a/src/client/component/game_console.cpp +++ b/src/client/component/game_console.cpp @@ -63,7 +63,7 @@ namespace game_console void clear() { - strncpy_s(con.buffer, "", sizeof(con.buffer)); + game::I_strncpyz(con.buffer, "", sizeof(con.buffer)); con.cursor = 0; fixed_input = ""; @@ -249,7 +249,7 @@ namespace game_console dvars::con_inputDvarInactiveValueColor->current.vector, offset); } - strncpy_s(con.globals.auto_complete_choice, matches[0].data(), sizeof(con.globals.auto_complete_choice)); + game::I_strncpyz(con.globals.auto_complete_choice, matches[0].data(), sizeof(con.globals.auto_complete_choice)); con.globals.may_auto_complete = true; } else if (matches.size() > 1) @@ -274,7 +274,7 @@ namespace game_console } } - strncpy_s(con.globals.auto_complete_choice, matches[0].data(), sizeof(con.globals.auto_complete_choice)); + game::I_strncpyz(con.globals.auto_complete_choice, matches[0].data(), sizeof(con.globals.auto_complete_choice)); con.globals.may_auto_complete = true; } } @@ -364,11 +364,11 @@ namespace game_console void print_internal(const char* fmt, ...) { - char va_buffer[0x200] = { 0 }; + char va_buffer[1024]{}; va_list ap; va_start(ap, fmt); - vsprintf_s(va_buffer, fmt, ap); + vsnprintf(va_buffer, sizeof(va_buffer), fmt, ap); va_end(ap); const auto formatted = std::string(va_buffer); @@ -424,7 +424,7 @@ namespace game_console con.buffer[1] = '\0'; } - strncat_s(con.buffer, con.globals.auto_complete_choice, 64); + game::I_strncat(con.buffer, sizeof(con.buffer), con.globals.auto_complete_choice); con.cursor = static_cast(std::string(con.buffer).length()); if (con.cursor != 254) @@ -549,7 +549,7 @@ namespace game_console if (history_index != -1) { - strncpy_s(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer)); + game::I_strncpyz(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer)); con.cursor = static_cast(strlen(con.buffer)); } } @@ -564,7 +564,7 @@ namespace game_console if (history_index != -1) { - strncpy_s(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer)); + game::I_strncpyz(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer)); con.cursor = static_cast(strlen(con.buffer)); } } @@ -721,7 +721,7 @@ namespace game_console con.output_visible = false; con.display_line_offset = 0; con.line_count = 0; - strncpy_s(con.buffer, "", sizeof(con.buffer)); + game::I_strncpyz(con.buffer, "", sizeof(con.buffer)); con.globals.x = 0.0f; con.globals.y = 0.0f; @@ -729,7 +729,7 @@ namespace game_console con.globals.font_height = 0.0f; con.globals.may_auto_complete = false; con.globals.info_line_count = 0; - strncpy_s(con.globals.auto_complete_choice, "", sizeof(con.globals.auto_complete_choice)); + game::I_strncpyz(con.globals.auto_complete_choice, "", sizeof(con.globals.auto_complete_choice)); // add clear command command::add("clear", [&]() diff --git a/src/client/component/game_log.cpp b/src/client/component/game_log.cpp index e8262b0..0697c1c 100644 --- a/src/client/component/game_log.cpp +++ b/src/client/component/game_log.cpp @@ -3,12 +3,10 @@ #include "game/game.hpp" #include "game/dvars.hpp" -#include "scheduler.hpp" -#include "scripting.hpp" #include "console.hpp" #include "game_log.hpp" - -#include "gsc/script_extension.hpp" +#include "scheduler.hpp" +#include "scripting.hpp" #include #include @@ -23,7 +21,7 @@ namespace game_log char buf[1024]{}; std::size_t out_chars = 0; - for (auto i = 0u; i < game::Scr_GetNumParam(); ++i) + for (std::uint32_t i = 0; i < game::Scr_GetNumParam(); ++i) { const auto* value = game::Scr_GetString(i); const auto len = std::strlen(value); @@ -34,7 +32,7 @@ namespace game_log break; } - strncat_s(buf, value, _TRUNCATE); + game::I_strncat(buf, sizeof(buf), value); } g_log_printf("%s", buf); @@ -49,22 +47,15 @@ namespace game_log return; } - char buffer[0x400]{}; + char buffer[1024]{}; va_list ap; va_start(ap, fmt); - - vsprintf_s(buffer, fmt, ap); - + vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); const auto time = *game::level_time / 1000; - utils::io::write_file(log, utils::string::va("%3i:%i%i %s", - time / 60, - time % 60 / 10, - time % 60 % 10, - buffer - ), true); + utils::io::write_file(log, utils::string::va("%3i:%i%i %s", time / 60, time % 60 / 10, time % 60 % 10, buffer), true); } class component final : public component_interface diff --git a/src/client/component/logger.cpp b/src/client/component/logger.cpp index 1449658..b36a374 100644 --- a/src/client/component/logger.cpp +++ b/src/client/component/logger.cpp @@ -10,43 +10,15 @@ namespace logger { namespace { - utils::hook::detour com_error_hook; - const game::dvar_t* logger_dev = nullptr; - void print_com_error(int, const char* msg, ...) - { - char buffer[2048]{}; - va_list ap; - - va_start(ap, msg); - vsnprintf_s(buffer, _TRUNCATE, msg, ap); - va_end(ap); - - console::error("%s", buffer); - } - - void com_error_stub(const int error, const char* msg, ...) - { - char buffer[2048]{}; - va_list ap; - - va_start(ap, msg); - vsnprintf_s(buffer, _TRUNCATE, msg, ap); - va_end(ap); - - console::error("Error: %s\n", buffer); - - com_error_hook.invoke(error, "%s", buffer); - } - void print_warning(const char* msg, ...) { char buffer[2048]{}; va_list ap; va_start(ap, msg); - vsnprintf_s(buffer, _TRUNCATE, msg, ap); + vsnprintf(buffer, sizeof(buffer), msg, ap); va_end(ap); console::warn("%s", buffer); @@ -58,7 +30,7 @@ namespace logger va_list ap; va_start(ap, msg); - vsnprintf_s(buffer, _TRUNCATE, msg, ap); + vsnprintf(buffer, sizeof(buffer), msg, ap); va_end(ap); console::info("%s", buffer); @@ -75,7 +47,7 @@ namespace logger va_list ap; va_start(ap, msg); - vsnprintf_s(buffer, _TRUNCATE, msg, ap); + vsnprintf(buffer, sizeof(buffer), msg, ap); va_end(ap); console::info("%s", buffer); @@ -141,13 +113,6 @@ namespace logger sub_1401DAA40(); } - if (!game::environment::is_sp()) - { - utils::hook::call(0x140501AE3, print_com_error); - } - - com_error_hook.create(game::Com_Error, com_error_stub); - // Make havok script's print function actually print utils::hook::jump(SELECT_VALUE(0x1406283A4, 0x140732184), print); diff --git a/src/client/component/mods.cpp b/src/client/component/mods.cpp index e6612a3..d992e82 100644 --- a/src/client/component/mods.cpp +++ b/src/client/component/mods.cpp @@ -16,24 +16,24 @@ namespace mods { utils::hook::detour sys_create_file_hook; - void db_build_os_path_from_source(const char* zone_name, game::FF_DIR source, unsigned int size, char* filename) + void db_build_os_path_from_source(const char* zone_name, game::FF_DIR source, int size, char* filename) { char user_map[MAX_PATH]{}; switch (source) { case game::FFD_DEFAULT: - (void)sprintf_s(filename, size, "%s\\%s.ff", std::filesystem::current_path().string().c_str(), zone_name); + (void)game::Com_sprintf(filename, size, "%s\\%s.ff", std::filesystem::current_path().string().c_str(), zone_name); break; case game::FFD_MOD_DIR: assert(mods::is_using_mods()); - (void)sprintf_s(filename, size, "%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), (*dvars::fs_gameDirVar)->current.string, zone_name); + (void)game::Com_sprintf(filename, size, "%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), (*dvars::fs_gameDirVar)->current.string, zone_name); break; case game::FFD_USER_MAP: - strncpy_s(user_map, zone_name, _TRUNCATE); + game::I_strncpyz(user_map, zone_name, sizeof(user_map)); - (void)sprintf_s(filename, size, "%s\\%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), "usermaps", user_map, zone_name); + (void)game::Com_sprintf(filename, size, "%s\\%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), "usermaps", user_map, zone_name); break; default: assert(false && "inconceivable"); diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 4b964f4..723f5d5 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -181,18 +181,21 @@ namespace party { for (auto i = 0; !name.empty() && i < *game::mp::svs_clientCount; ++i) { - if (game::mp::g_entities[i].client) + if (!game::mp::g_entities[i].client) { - char client_name[16] = {0}; - strncpy_s(client_name, game::mp::g_entities[i].client->sess.cs.name, sizeof(client_name)); - game::I_CleanStr(client_name); + continue; + } - if (client_name == name) - { - return i; - } + char client_name[16]{}; + game::I_strncpyz(client_name, game::mp::g_entities[i].client->sess.cs.name, sizeof(client_name)); + game::I_CleanStr(client_name); + + if (client_name == name) + { + return i; } } + return -1; } diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index fa4735a..640fe03 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -73,8 +73,10 @@ namespace patches if (exec_params.size() == 2) { std::string file_name = exec_params.get(1); - if (file_name.find(".cfg") == std::string::npos) + if (!file_name.ends_with(".cfg")) + { file_name.append(".cfg"); + } const auto file = filesystem::file(file_name); if (file.exists()) @@ -368,6 +370,9 @@ namespace patches utils::hook::nop(0x1403A1A0F, 1); // ^^ utils::hook::nop(0x1403A072F, 5); // LiveStorage_RecordMovementInMatchdata + + // Disable Com_Error in NET_SendPacket + utils::hook::nop(0x140501AE3, 5); } static void patch_sp() diff --git a/src/client/component/rcon.cpp b/src/client/component/rcon.cpp index 7fd3cd8..6f740ce 100644 --- a/src/client/component/rcon.cpp +++ b/src/client/component/rcon.cpp @@ -59,7 +59,7 @@ namespace rcon } char clean_name[32]{}; - strncpy_s(clean_name, self->client->sess.cs.name, sizeof(clean_name)); + game::I_strncpyz(clean_name, self->client->sess.cs.name, sizeof(clean_name)); game::I_CleanStr(clean_name); buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n", diff --git a/src/client/component/security.cpp b/src/client/component/security.cpp index 03e0cac..581107e 100644 --- a/src/client/component/security.cpp +++ b/src/client/component/security.cpp @@ -61,6 +61,42 @@ namespace security ui_replace_directive_hook.invoke(local_client_num, src_string, dst_string, dst_buffer_size); } + + int hud_elem_set_enum_string_stub(char* string, const char* format, ...) + { + va_list ap; + va_start(ap, format); + const auto len = vsnprintf(string, 0x800, format, ap); + va_end(ap); + + string[0x800 - 1] = '\0'; + + return len; + } + + int sv_add_bot_stub(char* string, const char* format, ...) + { + va_list ap; + va_start(ap, format); + const auto len = vsnprintf(string, 0x400, format, ap); + va_end(ap); + + string[0x400 - 1] = '\0'; + + return len; + } + + int sv_add_test_client_stub(char* string, const char* format, ...) + { + va_list ap; + va_start(ap, format); + const auto len = vsnprintf(string, 0x400, format, ap); + va_end(ap); + + string[0x400 - 1] = '\0'; + + return len; + } } class component final : public component_interface @@ -68,11 +104,18 @@ namespace security public: void post_unpack() override { + // sprinf + utils::hook::call(SELECT_VALUE(0x140310D0F, 0x140399B0F), hud_elem_set_enum_string_stub); + if (game::environment::is_sp()) return; // Patch vulnerability in PlayerCards_SetCachedPlayerData utils::hook::call(0x140287C5C, set_cached_playerdata_stub); + // sprinf + utils::hook::call(0x140470A88, sv_add_bot_stub); + utils::hook::call(0x140470F68, sv_add_test_client_stub); + // It is possible to make the server hang if left unchecked utils::hook::call(0x14047A29A, sv_execute_client_message_stub); diff --git a/src/client/game/engine/sv_game.cpp b/src/client/game/engine/sv_game.cpp index 950d401..dca8050 100644 --- a/src/client/game/engine/sv_game.cpp +++ b/src/client/game/engine/sv_game.cpp @@ -136,7 +136,7 @@ namespace game::engine const auto server_command_buf_large = std::make_unique(0x20000); va_start(va, fmt); - len = vsnprintf_s(server_command_buf_large.get(), 0x20000, _TRUNCATE, fmt, va); + len = vsnprintf(server_command_buf_large.get(), 0x20000, fmt, va); va_end(va); assert(len >= 0); diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 93e694b..b90bd78 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -31,6 +31,7 @@ namespace game WEAK symbol Com_TokenizeString{0x1403B4150, 0x1403F7CC0}; WEAK symbol Com_EndTokenizeString{0x1403B37C0, 0x1403F7330}; WEAK symbol Com_StreamSync_UpdateLaunchData{0x0, 0x140411B50}; + WEAK symbol Com_sprintf{0x140432310, 0x1404F6260}; WEAK symbol Conbuf_AppendText{0x14043DDE0, 0x1405028C0}; @@ -114,10 +115,10 @@ namespace game WEAK symbol I_CleanStr{0x140432460, 0x1404F63C0}; WEAK symbol I_strncpyz{0x140432810, 0x1404F67A0}; + WEAK symbol I_strncat{0x140432740, 0x1404F66D0}; WEAK symbol - Image_Setup{0x140517910, 0x1405E4380}; + uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const void* initData)> Image_Setup{0x140517910, 0x1405E4380}; WEAK symbol Key_KeynumToString{0x14023D9A0, 0x1402C40E0}; diff --git a/src/client/main.cpp b/src/client/main.cpp index e50f1cc..2412db9 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -64,9 +64,7 @@ LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info) &exception_information, nullptr, nullptr)) { char buf[4096]{}; - sprintf_s(buf, "An exception 0x%08X occurred at location 0x%p\n", - exception_info->ExceptionRecord->ExceptionCode, - exception_info->ExceptionRecord->ExceptionAddress); + sprintf_s(buf, "An exception 0x%08X occurred at location 0x%p\n", exception_info->ExceptionRecord->ExceptionCode, exception_info->ExceptionRecord->ExceptionAddress); game::show_error(buf); } diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index 6a50c3e..c579118 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -29,7 +29,7 @@ namespace utils::string while (true) { - const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); + const int res = vsnprintf(entry->buffer, entry->size, format, ap); if (res > 0) break; // Success if (res == 0) return nullptr; // Error