maint: January Update

Co-authored-by: Anomaly <jkohler@treyarch.com>
This commit is contained in:
6arelyFuture 2025-01-11 10:37:10 +01:00
parent 079f90631c
commit 4dd9eb2419
Signed by: Future
GPG Key ID: F2000F181A4F7C85
10 changed files with 146 additions and 43 deletions

2
deps/GSL vendored

@ -1 +1 @@
Subproject commit b8ac820fe1efde9c63ca290f4ae8670f938a7dae
Subproject commit 355982daf6c54ccb11bef8a1c511be2622dec402

2
deps/gsc-tool vendored

@ -1 +1 @@
Subproject commit 9ff3b871ef59b14eb8b32d258bf18347e14a3e18
Subproject commit e4cb6a7819726d9ea33cd6a52f0dcd9382258b47

2
deps/libtomcrypt vendored

@ -1 +1 @@
Subproject commit c900951dab1bb94bab803fc57688dac18e3b71f9
Subproject commit 2e9f2b5e44dd498dba60e5175c6c7effa5ff3728

View File

@ -36,11 +36,8 @@ namespace auth
auto hw_profile_path = (utils::properties::get_appdata_path() / "s1-guid.dat").generic_string();
if (utils::io::file_exists(hw_profile_path))
{
std::string hw_profile_info;
if (utils::io::read_file(hw_profile_path, &hw_profile_info) && !hw_profile_info.empty())
{
return hw_profile_info;
}
// Migration
utils::io::remove_file(hw_profile_path);
}
HW_PROFILE_INFO info;
@ -50,8 +47,6 @@ namespace auth
}
auto hw_profile_info = std::string{ info.szHwProfileGuid, sizeof(info.szHwProfileGuid) };
utils::io::write_file(hw_profile_path, hw_profile_info);
return hw_profile_info;
}
@ -62,7 +57,7 @@ namespace auth
DATA_BLOB data_in{}, data_out{};
data_in.pbData = reinterpret_cast<uint8_t*>(input.data());
data_in.cbData = static_cast<DWORD>(input.size());
if(CryptProtectData(&data_in, nullptr, nullptr, nullptr, nullptr, CRYPTPROTECT_LOCAL_MACHINE, &data_out) != TRUE)
if (CryptProtectData(&data_in, nullptr, nullptr, nullptr, nullptr, CRYPTPROTECT_LOCAL_MACHINE, &data_out) != TRUE)
{
return {};
}
@ -91,9 +86,72 @@ namespace auth
return entropy;
}
utils::cryptography::ecc::key& get_key()
bool load_key(utils::cryptography::ecc::key& key)
{
static auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy());
std::string data{};
auto key_path = (utils::properties::get_appdata_path() / "s1-private.key").generic_string();
if (!utils::io::read_file(key_path, &data))
{
return false;
}
key.deserialize(data);
if (!key.is_valid())
{
console::error("Loaded key is invalid!\n");
return false;
}
return true;
}
utils::cryptography::ecc::key generate_key()
{
auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy());
if (!key.is_valid())
{
throw std::runtime_error("Failed to generate cryptographic key!");
}
auto key_path = (utils::properties::get_appdata_path() / "s1-private.key").generic_string();
if (!utils::io::write_file(key_path, key.serialize()))
{
console::error("Failed to write cryptographic key!\n");
}
console::info("Generated cryptographic key: %llX\n", key.get_hash());
return key;
}
utils::cryptography::ecc::key load_or_generate_key()
{
utils::cryptography::ecc::key key{};
if (load_key(key))
{
console::info("Loaded cryptographic key: %llX\n", key.get_hash());
return key;
}
return generate_key();
}
utils::cryptography::ecc::key get_key_internal()
{
auto key = load_or_generate_key();
auto key_path = (utils::properties::get_appdata_path() / "s1-public.key").generic_string();
if (!utils::io::write_file(key_path, key.get_public_key()))
{
console::error("Failed to write public key!\n");
}
return key;
}
const utils::cryptography::ecc::key& get_key()
{
static auto key = get_key_internal();
return key;
}
@ -101,7 +159,7 @@ namespace auth
{
std::string connect_string(format, len);
game::SV_Cmd_TokenizeString(connect_string.data());
const auto _ = gsl::finally([]()
const auto _0 = gsl::finally([]()
{
game::SV_Cmd_EndTokenizedString();
});
@ -124,7 +182,7 @@ namespace auth
proto::network::connect_info info;
info.set_publickey(get_key().get_public_key());
info.set_signature(sign_message(get_key(), challenge));
info.set_signature(utils::cryptography::ecc::sign_message(get_key(), challenge));
info.set_infostring(connect_string);
network::send(*adr, "connect", info.SerializeAsString());
@ -166,14 +224,14 @@ namespace auth
utils::cryptography::ecc::key key;
key.set(info.publickey());
const auto xuid = strtoull(steam_id.data(), nullptr, 16);
const auto xuid = std::strtoull(steam_id.data(), nullptr, 16);
if (xuid != key.get_hash())
{
network::send(*from, "error", utils::string::va("XUID doesn't match the certificate: %llX != %llX", xuid, key.get_hash()), '\n');
return;
}
if (!key.is_valid() || !verify_message(key, challenge, info.signature()))
if (!key.is_valid() || !utils::cryptography::ecc::verify_message(key, challenge, info.signature()))
{
network::send(*from, "error", "Challenge signature was invalid!", '\n');
return;
@ -233,7 +291,7 @@ namespace auth
utils::hook::call(0x140208C54, send_connect_data_stub);
}
command::add("guid", []
command::add("guid", []() -> void
{
console::info("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits);
});

View File

@ -82,7 +82,16 @@ namespace colors
void com_clean_name_stub(const char* in, char* out, const int out_size)
{
strncpy_s(out, out_size, in, _TRUNCATE);
// Check that the name is at least 3 char without colors
char name[32]{};
game::I_strncpyz(out, in, std::min<int>(out_size, sizeof(name)));
utils::string::strip(out, name, std::strlen(out) + 1);
if (std::strlen(name) < 3)
{
game::I_strncpyz(out, "UnnamedPlayer", std::min<int>(out_size, sizeof(name)));
}
}
char* i_clean_str_stub(char* string)
@ -92,14 +101,12 @@ namespace colors
return string;
}
size_t get_client_name_stub(const int local_client_num, const int index, char* buf, const int size,
const size_t unk, const size_t unk2)
int cl_get_client_name_and_clan_tag_stub(const int local_client_num, const int index, char* name_buf, const int name_size, char* clan_tag_buf, int clan_tag_size)
{
// CL_GetClientName (CL_GetClientNameAndClantag?)
const auto result = reinterpret_cast<size_t(*)(int, int, char*, int, size_t, size_t)>(0x140213E60)(
local_client_num, index, buf, size, unk, unk2);
// CL_GetClientNameAndClanTag -> CL_GetClientNameAndClanTagColorize
const auto result = utils::hook::invoke<int>(0x140213E60, local_client_num, index, name_buf, name_size, clan_tag_buf, clan_tag_size);
utils::string::strip(buf, buf, static_cast<size_t>(size));
utils::string::strip(name_buf, name_buf, name_size);
return result;
}
@ -148,10 +155,11 @@ namespace colors
if (!game::environment::is_sp())
{
// allows colored name in-game
utils::hook::jump(0x1404C9510, com_clean_name_stub);
utils::hook::call(0x1402DBD28, com_clean_name_stub);
utils::hook::call(0x1402DBD6D, com_clean_name_stub);
// don't apply colors to overhead names
utils::hook::call(0x1401891B0, get_client_name_stub);
utils::hook::call(0x1401891B0, cl_get_client_name_and_clan_tag_stub);
// patch I_CleanStr
utils::hook::jump(0x1404C99A0, i_clean_str_stub);

View File

@ -113,7 +113,7 @@ namespace map_rotation
console::error("%s: %s contains invalid data!\n", ex.what(), sv_map_rotation->name);
}
#ifdef _DEBUG
console::info("dedicated_rotation size after parsing is '%zu'", dedicated_rotation.get_entries_size());
console::info("dedicated_rotation size after parsing is '%zu'\n", dedicated_rotation.get_entries_size());
#endif
}

View File

@ -80,23 +80,25 @@ namespace rcon
{
const auto client = &game::mp::svs_clients[i];
if (client->header.state == game::CA_DISCONNECTED)
{
continue;
}
char clean_name[32]{};
strncpy_s(clean_name, client->name, _TRUNCATE);
game::I_CleanStr(clean_name);
if (client->header.state > game::CA_DISCONNECTED)
{
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",
i,
game::G_GetClientScore(i),
game::SV_BotIsBot(i) ? "Yes" : "No",
(client->header.state == 2) ? "CNCT" : (client->header.state == 1) ? "ZMBI" : utils::string::va("%4i", game::SV_GetClientPing(i)),
game::SV_GetGuid(i),
clean_name,
network::net_adr_to_string(client->header.remoteAddress),
client->header.remoteAddress.port)
);
}
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",
i,
game::G_GetClientScore(i),
game::SV_BotIsBot(i) ? "Yes" : "No",
(client->header.state == 2) ? "CNCT" : (client->header.state == 1) ? "ZMBI" : utils::string::va("%4i", game::SV_GetClientPing(i)),
game::SV_GetGuid(i),
clean_name,
network::net_adr_to_string(client->header.remoteAddress),
client->header.remoteAddress.port)
);
}
return buffer;

View File

@ -10,6 +10,8 @@ namespace security
{
namespace
{
utils::hook::detour ui_replace_directive_hook;
void set_cached_playerdata_stub(const int localclient, const int index1, const int index2)
{
if (index1 >= 0 && index1 < 18 && index2 >= 0 && index2 < 42)
@ -53,6 +55,35 @@ namespace security
utils::hook::invoke<void>(0x14043AA90, client, msg);
}
void ui_replace_directive_stub(const int local_client_num, const char* src_string, char* dst_string, const int dst_buffer_size)
{
assert(src_string);
if (!src_string)
{
return;
}
assert(dst_string);
if (!dst_string)
{
return;
}
assert(dst_buffer_size > 0);
if (dst_buffer_size <= 0)
{
return;
}
constexpr std::size_t MAX_HUDELEM_TEXT_LEN = 0x100;
if (std::strlen(src_string) > MAX_HUDELEM_TEXT_LEN)
{
return;
}
ui_replace_directive_hook.invoke<void>(local_client_num, src_string, dst_string, dst_buffer_size);
}
}
class component final : public component_interface
@ -70,6 +101,8 @@ namespace security
// It is possible to make the server hang if left unchecked
utils::hook::call(0x140443051, sv_execute_client_message_stub);
ui_replace_directive_hook.create(0x1404A9640, ui_replace_directive_stub);
}
};
}

View File

@ -219,6 +219,8 @@ namespace game
WEAK symbol<void(unsigned __int64 markPos)> LargeLocalResetToMark{0x140369C40, 0x1404B6790};
WEAK symbol<void(char* dest, const char* src, int destsize)> I_strncpyz{0x1403793B0, 0x1404C9E60};
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14059C5C0, 0x1406FD930};
WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x14059CD00, 0x1406FE070};

View File

@ -109,13 +109,13 @@ namespace utils::string
void strip(const char* in, char* out, size_t max)
{
if (!in || !out) return;
if (!in || !out || !max) return;
max--;
auto current = 0u;
while (*in != 0 && current < max)
{
const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48);
const auto color_index = (static_cast<size_t>(*(in + 1) - 48)) >= 0xC ? 7 : (*(in + 1) - 48);
if (*in == '^' && (color_index != 7 || *(in + 1) == '7'))
{