diff options
author | Treeston <treeston.mmoc@gmail.com> | 2020-08-11 18:04:36 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-01-26 19:42:11 +0100 |
commit | 319ddd9bcdeab13b07c992e05bef5698af090ee0 (patch) | |
tree | 1d4ebb9e0fadefbd6effdf1c10769e3488c94840 | |
parent | cf369301c42773d104121820a8d131bb502e81d8 (diff) |
Core/Warden: Warden refactors (PR #25235)
(cherry picked from commit 6116e5b38522ccfb00f6c941c75482e05b4c0799)
-rw-r--r-- | sql/base/auth_database.sql | 3 | ||||
-rw-r--r-- | sql/updates/auth/master/2020_08_11_00_auth.sql | 5 | ||||
-rw-r--r-- | sql/updates/world/master/2022_01_26_31_world_2020_08_11_00_world_335.sql | 15 | ||||
-rw-r--r-- | src/common/Utilities/Util.h | 9 | ||||
-rw-r--r-- | src/server/game/Accounts/RBAC.h | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Warden/Modules/WardenModuleMac.h | 2 | ||||
-rw-r--r-- | src/server/game/Warden/Modules/WardenModuleWin.h | 17 | ||||
-rw-r--r-- | src/server/game/Warden/Warden.cpp | 166 | ||||
-rw-r--r-- | src/server/game/Warden/Warden.h | 67 | ||||
-rw-r--r-- | src/server/game/Warden/WardenCheckMgr.cpp | 95 | ||||
-rw-r--r-- | src/server/game/Warden/WardenCheckMgr.h | 60 | ||||
-rw-r--r-- | src/server/game/Warden/WardenMac.cpp | 67 | ||||
-rw-r--r-- | src/server/game/Warden/WardenMac.h | 6 | ||||
-rw-r--r-- | src/server/game/Warden/WardenWin.cpp | 295 | ||||
-rw-r--r-- | src/server/game/Warden/WardenWin.h | 16 | ||||
-rw-r--r-- | src/server/game/Warden/enuminfo_WardenCheckMgr.cpp | 100 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_reload.cpp | 17 |
18 files changed, 503 insertions, 447 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 86f4ab20ae5..098319b982c 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -1193,7 +1193,6 @@ INSERT INTO `rbac_linked_permissions` VALUES (196,702), (196,703), (196,704), -(196,705), (196,706), (196,707), (196,708), @@ -2032,7 +2031,6 @@ INSERT INTO `rbac_permissions` VALUES (702,'Command: reload spell_threats'), (703,'Command: reload spell_group_stack_rules'), (704,'Command: reload trinity_string'), -(705,'Command: reload warden_action'), (706,'Command: reload waypoint_scripts'), (707,'Command: reload waypoint_data'), (708,'Command: reload vehicle_accessory'), @@ -2486,6 +2484,7 @@ INSERT INTO `updates` VALUES ('2020_08_03_01_auth.sql','EC1063396CA20A2303D83238470D41EF4439EC72','ARCHIVED','2020-08-03 00:00:01',0), ('2020_08_06_00_auth.sql','5D3C5B25132DAFCA3933E9CBE14F5E8A290C4AFA','ARCHIVED','2020-08-06 20:26:11',0), ('2020_08_08_00_auth.sql','BC6A08BE42A6F2C30C9286CBDD47D57B718C4635','ARCHIVED','2020-08-08 00:16:57',0), +('2020_08_11_00_auth.sql','14C99177E43003D83A4D6F2227722F15FC15A1D0','ARCHIVED','2020-08-11 00:00:00',0), ('2020_08_14_00_auth.sql','DFB9B07A7846FC0E124EE4CC099E49FE5742FB66','ARCHIVED','2020-08-14 21:41:24',0), ('2020_08_26_00_auth.sql','D5EF787DECB41D898379588F101A0453B46F04D9','ARCHIVED','2020-08-26 21:00:34',0), ('2020_09_25_00_auth.sql','3CCA78EF89223724BA6784A4F3783DED30416637','ARCHIVED','2020-09-25 19:52:40',0), diff --git a/sql/updates/auth/master/2020_08_11_00_auth.sql b/sql/updates/auth/master/2020_08_11_00_auth.sql new file mode 100644 index 00000000000..16296ac7c90 --- /dev/null +++ b/sql/updates/auth/master/2020_08_11_00_auth.sql @@ -0,0 +1,5 @@ +-- +DELETE FROM `rbac_permissions` WHERE `id`=705; +DELETE FROM `rbac_linked_permissions` WHERE `linkedId`=705; +DELETE FROM `rbac_account_permissions` WHERE `permissionId`=705; +DELETE FROM `rbac_default_permissions` WHERE `permissionId`=705; diff --git a/sql/updates/world/master/2022_01_26_31_world_2020_08_11_00_world_335.sql b/sql/updates/world/master/2022_01_26_31_world_2020_08_11_00_world_335.sql new file mode 100644 index 00000000000..6e66caa8855 --- /dev/null +++ b/sql/updates/world/master/2022_01_26_31_world_2020_08_11_00_world_335.sql @@ -0,0 +1,15 @@ +-- +ALTER TABLE `warden_checks` + CHANGE COLUMN `data` `oldData` VARCHAR(48), + CHANGE COLUMN `result` `oldResult` VARCHAR(24), + ADD COLUMN `data` BINARY(24) DEFAULT NULL, + ADD COLUMN `result` VARBINARY(12) DEFAULT NULL; + +UPDATE `warden_checks` SET `data`=UNHEX(`oldData`) WHERE `type` IN (113,178,191); +UPDATE `warden_checks` SET `result`=UNHEX(`oldResult`) WHERE `type` IN (152,243); + +ALTER TABLE `warden_checks` + DROP COLUMN `oldData`, + DROP COLUMN `oldResult`; + +DELETE FROM `command` WHERE `name`='reload warden_action'; diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 18a380ea9b4..a7f6619838a 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -365,6 +365,15 @@ std::array<uint8, Size> HexStrToByteArray(std::string const& str, bool reverse = return arr; } +inline std::vector<uint8> HexStrToByteVector(std::string const& str, bool reverse = false) +{ + std::vector<uint8> buf; + size_t const sz = (str.size() / 2); + buf.resize(sz); + Trinity::Impl::HexStrToByteArray(str, buf.data(), sz, reverse); + return buf; +} + TC_COMMON_API bool StringToBool(std::string const& str); TC_COMMON_API float DegToRad(float degrees); diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 355af8cb740..95f1df06e1b 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -610,7 +610,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_SPELL_THREATS = 702, RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP_STACK_RULES = 703, RBAC_PERM_COMMAND_RELOAD_TRINITY_STRING = 704, - RBAC_PERM_COMMAND_RELOAD_WARDEN_ACTION = 705, + // 705 unused RBAC_PERM_COMMAND_RELOAD_WAYPOINT_SCRIPTS = 706, RBAC_PERM_COMMAND_RELOAD_WAYPOINT_DATA = 707, RBAC_PERM_COMMAND_RELOAD_VEHICLE_ACCESORY = 708, diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index ede413d824d..7d06c95b42a 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -475,7 +475,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) _recvQueue.readd(requeuePackets.begin(), requeuePackets.end()); if (m_Socket[CONNECTION_TYPE_REALM] && m_Socket[CONNECTION_TYPE_REALM]->IsOpen() && _warden) - _warden->Update(); + _warden->Update(diff); if (!updater.ProcessUnsafe()) // <=> updater is of type MapSessionFilter { @@ -499,13 +499,13 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (ShouldLogOut(currentTime) && m_playerLoading.IsEmpty()) LogoutPlayer(true); - if (m_Socket[CONNECTION_TYPE_REALM] && GetPlayer() && _warden) - _warden->Update(); - ///- Cleanup socket pointer if need if ((m_Socket[CONNECTION_TYPE_REALM] && !m_Socket[CONNECTION_TYPE_REALM]->IsOpen()) || (m_Socket[CONNECTION_TYPE_INSTANCE] && !m_Socket[CONNECTION_TYPE_INSTANCE]->IsOpen())) { + if (GetPlayer() && _warden) + _warden->Update(diff); + expireTime -= expireTime > diff ? diff : expireTime; if (expireTime < diff || forceExit || !GetPlayer()) { diff --git a/src/server/game/Warden/Modules/WardenModuleMac.h b/src/server/game/Warden/Modules/WardenModuleMac.h index 8efdf401b8c..a699261a284 100644 --- a/src/server/game/Warden/Modules/WardenModuleMac.h +++ b/src/server/game/Warden/Modules/WardenModuleMac.h @@ -18,7 +18,7 @@ #ifndef _WARDEN_MODULE_MAC_H #define _WARDEN_MODULE_MAC_H -uint8 Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data[9318] = +std::array<uint8, 9318> Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data = { 0x07, 0x0C, 0x44, 0xCD, 0xC9, 0xFB, 0x99, 0xBC, 0x7C, 0x77, 0xDC, 0xE8, 0x8D, 0x07, 0xBE, 0x55, 0x37, 0x5C, 0x84, 0x10, 0x23, 0xE1, 0x36, 0x5B, 0xF1, 0xBC, 0x60, 0xF3, 0x68, 0xBA, 0x60, 0x69, diff --git a/src/server/game/Warden/Modules/WardenModuleWin.h b/src/server/game/Warden/Modules/WardenModuleWin.h index d282e0090b5..faf9bf44d4e 100644 --- a/src/server/game/Warden/Modules/WardenModuleWin.h +++ b/src/server/game/Warden/Modules/WardenModuleWin.h @@ -18,22 +18,25 @@ #ifndef _WARDEN_MODULE_WIN_H #define _WARDEN_MODULE_WIN_H +#include "CryptoHash.h" +#include <array> + /* Seed: 4D808D2C77D905C41A6380EC08586AFE (0x05 packet) Hash: 568C054C781A972A6037A2290C22B52571A06F4E (0x04 packet) Module MD5: 79C0768D657977D697E10BAD956CCED1 New Client Key: 7F 96 EE FD A5 B6 3D 20 A4 DF 8E 00 CB F4 83 04 -New Cerver Key: C2 B7 AD ED FC CC A9 C2 BF B3 F8 56 02 BA 80 9B +New Server Key: C2 B7 AD ED FC CC A9 C2 BF B3 F8 56 02 BA 80 9B */ struct Module_79C0768D657977D697E10BAD956CCED1 { - uint8 Module[18756]; - uint8 ModuleKey[16]; - uint8 Seed[16]; - uint8 ServerKeySeed[16]; - uint8 ClientKeySeed[16]; - uint8 ClientKeySeedHash[20]; + std::array<uint8, 18756> Module; + std::array<uint8, 16> ModuleKey; + std::array<uint8, 16> Seed; + std::array<uint8, 16> ServerKeySeed; + std::array<uint8, 16> ClientKeySeed; + Trinity::Crypto::SHA1::Digest ClientKeySeedHash; } Module = { { diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp index a938533ea5a..105460ca44b 100644 --- a/src/server/game/Warden/Warden.cpp +++ b/src/server/game/Warden/Warden.cpp @@ -29,23 +29,29 @@ #include "WardenPackets.h" #include <openssl/sha.h> +#include <openssl/md5.h> -Warden::Warden() : _session(nullptr), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0), - _dataSent(false), _previousTimestamp(0), _module(nullptr), _initialized(false) +Warden::Warden() : _session(nullptr), _checkTimer(10 * IN_MILLISECONDS), _clientResponseTimer(0), + _dataSent(false), _initialized(false) { - memset(_inputKey, 0, sizeof(_inputKey)); - memset(_outputKey, 0, sizeof(_outputKey)); - memset(_seed, 0, sizeof(_seed)); } Warden::~Warden() { - delete[] _module->CompressedData; - delete _module; - _module = nullptr; _initialized = false; } +void Warden::MakeModuleForClient() +{ + TC_LOG_DEBUG("warden", "Make module for client"); + InitializeModuleForClient(_module.emplace()); + + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, _module->CompressedData, _module->CompressedSize); + MD5_Final(_module->Id.data(), &ctx); +} + void Warden::SendModuleToClient() { TC_LOG_DEBUG("warden", "Send module to client"); @@ -61,13 +67,15 @@ void Warden::SendModuleToClient() burstSize = sizeLeft < 500 ? sizeLeft : 500; packet.Command = WARDEN_SMSG_MODULE_CACHE; packet.DataSize = burstSize; - memcpy(packet.Data, &_module->CompressedData[pos], burstSize); + memcpy(packet.Data, _module->CompressedData + pos, burstSize); sizeLeft -= burstSize; pos += burstSize; - EncryptData((uint8*)&packet, burstSize + 3); + EndianConvert(packet.DataSize); + + EncryptData(reinterpret_cast<uint8*>(&packet), burstSize + 3); WorldPacket pkt1(SMSG_WARDEN3_DATA, burstSize + 3); - pkt1.append((uint8*)&packet, burstSize + 3); + pkt1.append(reinterpret_cast<uint8*>(&packet), burstSize + 3); _session->SendPacket(&pkt1); } } @@ -80,53 +88,49 @@ void Warden::RequestModule() WardenModuleUse request; request.Command = WARDEN_SMSG_MODULE_USE; - memcpy(request.ModuleId, _module->Id, 16); - memcpy(request.ModuleKey, _module->Key, 16); + request.ModuleId = _module->Id; + request.ModuleKey = _module->Key; request.Size = _module->CompressedSize; + EndianConvert(request.Size); + // Encrypt with warden RC4 key. - EncryptData((uint8*)&request, sizeof(WardenModuleUse)); + EncryptData(reinterpret_cast<uint8*>(&request), sizeof(WardenModuleUse)); WorldPacket pkt(SMSG_WARDEN3_DATA, sizeof(WardenModuleUse)); - pkt.append((uint8*)&request, sizeof(WardenModuleUse)); + pkt.append(reinterpret_cast<uint8*>(&request), sizeof(WardenModuleUse)); _session->SendPacket(&pkt); } -void Warden::Update() +void Warden::Update(uint32 diff) { - if (_initialized) - { - uint32 currentTimestamp = GameTime::GetGameTimeMS(); - uint32 diff = currentTimestamp - _previousTimestamp; - _previousTimestamp = currentTimestamp; + if (!_initialized) + return; - if (_dataSent) - { - uint32 maxClientResponseDelay = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_RESPONSE_DELAY); + if (_dataSent) + { + uint32 maxClientResponseDelay = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_RESPONSE_DELAY); - if (maxClientResponseDelay > 0) - { - // Kick player if client response delays more than set in config - if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS) - { - TC_LOG_WARN("warden", "%s (latency: %u, IP: %s) exceeded Warden module response delay for more than %s - disconnecting client", - _session->GetPlayerInfo().c_str(), _session->GetLatency(), _session->GetRemoteAddress().c_str(), secsToTimeString(maxClientResponseDelay, TimeFormat::ShortText).c_str()); - _session->KickPlayer("Warden::Update Warden module response delay exceeded"); - } - else - _clientResponseTimer += diff; - } - } - else + if (maxClientResponseDelay > 0) { - if (diff >= _checkTimer) + // Kick player if client response delays more than set in config + if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS) { - RequestData(); + TC_LOG_WARN("warden", "%s (latency: %u, IP: %s) exceeded Warden module response delay (%s) - disconnecting client", + _session->GetPlayerInfo().c_str(), _session->GetLatency(), _session->GetRemoteAddress().c_str(), secsToTimeString(maxClientResponseDelay, TimeFormat::ShortText).c_str()); + _session->KickPlayer("Warden::Update Warden module response delay exceeded"); } else - _checkTimer -= diff; + _clientResponseTimer += diff; } } + else + { + if (diff >= _checkTimer) + RequestChecks(); + else + _checkTimer -= diff; + } } void Warden::DecryptData(uint8* buffer, uint32 length) @@ -181,7 +185,7 @@ uint32 Warden::BuildChecksum(uint8 const* data, uint32 length) return checkSum; } -std::string Warden::Penalty(WardenCheck* check /*= nullptr*/) +char const* Warden::ApplyPenalty(WardenCheck const* check) { WardenActions action; @@ -192,12 +196,8 @@ std::string Warden::Penalty(WardenCheck* check /*= nullptr*/) switch (action) { - case WARDEN_ACTION_LOG: - return "None"; - break; case WARDEN_ACTION_KICK: _session->KickPlayer("Warden::Penalty"); - return "Kick"; break; case WARDEN_ACTION_BAN: { @@ -208,50 +208,56 @@ std::string Warden::Penalty(WardenCheck* check /*= nullptr*/) if (check) banReason += Trinity::StringFormat(": %s (CheckId: %u", check->Comment, uint32(check->CheckId)); - sWorld->BanAccount(BAN_ACCOUNT, accountName, Trinity::StringFormat("%ds", sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION)), banReason, "Server"); + sWorld->BanAccount(BAN_ACCOUNT, accountName, sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION), banReason, "Server"); - return "Ban"; + break; } + case WARDEN_ACTION_LOG: default: - break; + return "None"; } - return "Undefined"; + return EnumUtils::ToTitle(action); } -void WorldSession::HandleWardenData(WorldPackets::Warden::WardenData& packet) +void Warden::HandleData(ByteBuffer& buff) { - if (!_warden || packet.Data.empty()) - return; - - _warden->DecryptData(packet.Data.contents(), packet.Data.size()); + DecryptData(buff.contents(), buff.size()); uint8 opcode; - packet.Data >> opcode; - TC_LOG_DEBUG("warden", "Got packet, opcode %02X, size %u", opcode, uint32(packet.Data.size())); - packet.Data.hexlike(); + buff >> opcode; + TC_LOG_DEBUG("warden", "Got packet, opcode %02X, size %u", opcode, uint32(buff.size() - 1)); + buff.hexlike(); switch (opcode) { - case WARDEN_CMSG_MODULE_MISSING: - _warden->SendModuleToClient(); - break; - case WARDEN_CMSG_MODULE_OK: - _warden->RequestHash(); - break; - case WARDEN_CMSG_CHEAT_CHECKS_RESULT: - _warden->HandleData(packet.Data); - break; - case WARDEN_CMSG_MEM_CHECKS_RESULT: - TC_LOG_DEBUG("warden", "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!"); - break; - case WARDEN_CMSG_HASH_RESULT: - _warden->HandleHashResult(packet.Data); - _warden->InitializeModule(); - break; - case WARDEN_CMSG_MODULE_FAILED: - TC_LOG_DEBUG("warden", "NYI WARDEN_CMSG_MODULE_FAILED received!"); - break; - default: - TC_LOG_DEBUG("warden", "Got unknown warden opcode %02X of size %u.", opcode, uint32(packet.Data.size() - 1)); - break; + case WARDEN_CMSG_MODULE_MISSING: + SendModuleToClient(); + break; + case WARDEN_CMSG_MODULE_OK: + RequestHash(); + break; + case WARDEN_CMSG_CHEAT_CHECKS_RESULT: + HandleCheckResult(buff); + break; + case WARDEN_CMSG_MEM_CHECKS_RESULT: + TC_LOG_DEBUG("warden", "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!"); + break; + case WARDEN_CMSG_HASH_RESULT: + HandleHashResult(buff); + InitializeModule(); + break; + case WARDEN_CMSG_MODULE_FAILED: + TC_LOG_DEBUG("warden", "NYI WARDEN_CMSG_MODULE_FAILED received!"); + break; + default: + TC_LOG_WARN("warden", "Got unknown warden opcode %02X of size %u.", opcode, uint32(buff.size() - 1)); + break; } } + +void WorldSession::HandleWardenData(WorldPackets::Warden::WardenData& packet) +{ + if (!_warden || packet.Data.empty()) + return; + + _warden->HandleData(packet.Data); +} diff --git a/src/server/game/Warden/Warden.h b/src/server/game/Warden/Warden.h index a5fe29fe889..bcf3cd92122 100644 --- a/src/server/game/Warden/Warden.h +++ b/src/server/game/Warden/Warden.h @@ -21,6 +21,7 @@ #include "ARC4.h" #include "AuthDefines.h" #include "ByteBuffer.h" +#include "Optional.h" #include "WardenCheckMgr.h" #include <array> @@ -43,28 +44,16 @@ enum WardenOpcodes WARDEN_SMSG_HASH_REQUEST = 5 }; -enum WardenCheckType -{ - MEM_CHECK = 0xF3, // 243: byte moduleNameIndex + uint Offset + byte Len (check to ensure memory isn't modified) - PAGE_CHECK_A = 0xB2, // 178: uint Seed + byte[20] SHA1 + uint Addr + byte Len (scans all pages for specified hash) - PAGE_CHECK_B = 0xBF, // 191: uint Seed + byte[20] SHA1 + uint Addr + byte Len (scans only pages starts with MZ+PE headers for specified hash) - MPQ_CHECK = 0x98, // 152: byte fileNameIndex (check to ensure MPQ file isn't modified) - LUA_STR_CHECK = 0x8B, // 139: byte luaNameIndex (check to ensure LUA string isn't used) - DRIVER_CHECK = 0x71, // 113: uint Seed + byte[20] SHA1 + byte driverNameIndex (check to ensure driver isn't loaded) - TIMING_CHECK = 0x57, // 87: empty (check to ensure GetTickCount() isn't detoured) - PROC_CHECK = 0x7E, // 126: uint Seed + byte[20] SHA1 + byte moluleNameIndex + byte procNameIndex + uint Offset + byte Len (check to ensure proc isn't detoured) - MODULE_CHECK = 0xD9 // 217: uint Seed + byte[20] SHA1 (check to ensure module isn't injected) -}; - #pragma pack(push, 1) struct WardenModuleUse { uint8 Command; - uint8 ModuleId[16]; - uint8 ModuleKey[16]; + std::array<uint8, 16> ModuleId; + std::array<uint8, 16> ModuleKey; uint32 Size; }; +static_assert(sizeof(WardenModuleUse) == (1 + 16 + 16 + 4)); struct WardenModuleTransfer { @@ -72,66 +61,68 @@ struct WardenModuleTransfer uint16 DataSize; uint8 Data[500]; }; +static_assert(sizeof(WardenModuleTransfer) == (1 + 2 + 500)); struct WardenHashRequest { uint8 Command; - uint8 Seed[16]; + std::array<uint8, 16> Seed; }; +static_assert(sizeof(WardenHashRequest) == (1 + 16)); #pragma pack(pop) struct ClientWardenModule { - uint8 Id[16]; - uint8 Key[16]; - uint32 CompressedSize; - uint8* CompressedData; + std::array<uint8, 16> Id; + std::array<uint8, 16> Key; + uint8 const* CompressedData; + size_t CompressedSize; }; class WorldSession; class TC_GAME_API Warden { - friend class WardenWin; - friend class WardenMac; - public: Warden(); virtual ~Warden(); virtual void Init(WorldSession* session, SessionKey const& K) = 0; - virtual ClientWardenModule* GetModuleForClient() = 0; + void Update(uint32 diff); + void HandleData(ByteBuffer& buff); + + protected: + void DecryptData(uint8* buffer, uint32 length); + void EncryptData(uint8* buffer, uint32 length); + virtual void InitializeModule() = 0; virtual void RequestHash() = 0; - virtual void HandleHashResult(ByteBuffer &buff) = 0; - virtual void RequestData() = 0; - virtual void HandleData(ByteBuffer &buff) = 0; + virtual void HandleHashResult(ByteBuffer& buff) = 0; + virtual void HandleCheckResult(ByteBuffer& buff) = 0; + virtual void InitializeModuleForClient(ClientWardenModule& module) = 0; + virtual void RequestChecks() = 0; + void MakeModuleForClient(); void SendModuleToClient(); void RequestModule(); - void Update(); - void DecryptData(uint8* buffer, uint32 length); - void EncryptData(uint8* buffer, uint32 length); static bool IsValidCheckSum(uint32 checksum, const uint8 *data, const uint16 length); static uint32 BuildChecksum(const uint8 *data, uint32 length); - // If no check is passed, the default action from config is executed - std::string Penalty(WardenCheck* check = nullptr); + // If nullptr is passed, the default action from config is executed + char const* ApplyPenalty(WardenCheck const* check); - private: WorldSession* _session; - uint8 _inputKey[16]; - uint8 _outputKey[16]; - uint8 _seed[16]; + std::array<uint8, 16> _inputKey = {}; + std::array<uint8, 16> _outputKey = {}; + std::array<uint8, 16> _seed = {}; Trinity::Crypto::ARC4 _inputCrypto; Trinity::Crypto::ARC4 _outputCrypto; uint32 _checkTimer; // Timer for sending check requests uint32 _clientResponseTimer; // Timer for client response delay bool _dataSent; - uint32 _previousTimestamp; - ClientWardenModule* _module; + Optional<ClientWardenModule> _module; bool _initialized; }; diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp index b23f53f927a..b328eaee6ca 100644 --- a/src/server/game/Warden/WardenCheckMgr.cpp +++ b/src/server/game/Warden/WardenCheckMgr.cpp @@ -15,28 +15,21 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "WardenCheckMgr.h" + #include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" +#include "DatabaseEnv.h" +#include "Errors.h" #include "Log.h" -#include "Database/DatabaseEnv.h" -#include "WardenCheckMgr.h" #include "Warden.h" #include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" WardenCheckMgr::WardenCheckMgr() { } -WardenCheckMgr::~WardenCheckMgr() -{ - for (uint16 i = 0; i < CheckStore.size(); ++i) - delete CheckStore[i]; - - for (CheckResultContainer::iterator itr = CheckResultStore.begin(); itr != CheckResultStore.end(); ++itr) - delete itr->second; -} - void WardenCheckMgr::LoadWardenChecks() { uint32 oldMSTime = getMSTime(); @@ -70,53 +63,40 @@ void WardenCheckMgr::LoadWardenChecks() { fields = result->Fetch(); - uint16 id = fields[0].GetUInt16(); - uint8 checkType = fields[1].GetUInt8(); - std::string data = fields[2].GetString(); - std::string checkResult = fields[3].GetString(); - uint32 address = fields[4].GetUInt32(); - uint8 length = fields[5].GetUInt8(); - std::string str = fields[6].GetString(); - std::string comment = fields[7].GetString(); + uint16 const id = fields[0].GetUInt16(); + uint8 const type = fields[1].GetUInt8(); - WardenCheck* wardenCheck = new WardenCheck(); - wardenCheck->Type = checkType; - wardenCheck->CheckId = id; + WardenCheck& wardenCheck = CheckStore[id]; + wardenCheck.CheckId = id; + wardenCheck.Type = WardenCheckType(type); // Initialize action with default action from config - wardenCheck->Action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION)); + wardenCheck.Action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION)); - if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK) - wardenCheck->Data.SetHexStr(data.c_str()); + if (type == PAGE_CHECK_A || type == PAGE_CHECK_B || type == DRIVER_CHECK) + wardenCheck.Data = fields[2].GetBinary(); - if (checkType == MEM_CHECK || checkType == MODULE_CHECK) - MemChecksIdPool.push_back(id); - else - OtherChecksIdPool.push_back(id); + if (type == MPQ_CHECK || type == MEM_CHECK) + CheckResultStore.emplace(id, fields[3].GetBinary()); - if (checkType == MEM_CHECK || checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == PROC_CHECK) + if (type == MEM_CHECK || type == PAGE_CHECK_A || type == PAGE_CHECK_B || type == PROC_CHECK) { - wardenCheck->Address = address; - wardenCheck->Length = length; + wardenCheck.Address = fields[4].GetUInt32(); + wardenCheck.Length = fields[5].GetUInt8(); } // PROC_CHECK support missing - if (checkType == MEM_CHECK || checkType == MPQ_CHECK || checkType == LUA_STR_CHECK || checkType == DRIVER_CHECK || checkType == MODULE_CHECK) - wardenCheck->Str = str; + if (type == MEM_CHECK || type == MPQ_CHECK || type == LUA_STR_CHECK || type == DRIVER_CHECK || type == MODULE_CHECK) + wardenCheck.Str = fields[6].GetString(); - CheckStore[id] = wardenCheck; - - if (checkType == MPQ_CHECK || checkType == MEM_CHECK) - { - WardenCheckResult* wr = new WardenCheckResult(); - wr->Result.SetHexStr(checkResult.c_str()); - CheckResultStore[id] = wr; - } + wardenCheck.Comment = fields[7].GetString(); + if (wardenCheck.Comment.empty()) + wardenCheck.Comment = "Undocumented Check"; - if (comment.empty()) - wardenCheck->Comment = "Undocumented Check"; + if (type == MEM_CHECK || type == MODULE_CHECK) + MemChecksIdPool.push_back(id); else - wardenCheck->Comment = comment; + OtherChecksIdPool.push_back(id); ++count; } @@ -147,8 +127,6 @@ void WardenCheckMgr::LoadWardenOverrides() uint32 count = 0; - std::unique_lock<std::shared_mutex> lock(sWardenCheckMgr->_checkStoreLock); - do { Field* fields = result->Fetch(); @@ -164,7 +142,7 @@ void WardenCheckMgr::LoadWardenOverrides() TC_LOG_ERROR("warden", "Warden check action override for non-existing check (ID: %u, action: %u), skipped", checkId, action); else { - CheckStore[checkId]->Action = WardenActions(action); + CheckStore[checkId].Action = WardenActions(action); ++count; } } @@ -179,18 +157,15 @@ WardenCheckMgr* WardenCheckMgr::instance() return &instance; } -WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 Id) +WardenCheck const& WardenCheckMgr::GetCheckDataById(uint16 Id) const { - if (Id < CheckStore.size()) - return CheckStore[Id]; - - return nullptr; + ASSERT(Id < CheckStore.size(), "Requested Warden data for invalid check ID %u", uint32(Id)); + return CheckStore[Id]; } -WardenCheckResult* WardenCheckMgr::GetWardenResultById(uint16 Id) +WardenCheckResult const& WardenCheckMgr::GetCheckResultById(uint16 Id) const { - CheckResultContainer::const_iterator itr = CheckResultStore.find(Id); - if (itr != CheckResultStore.end()) - return itr->second; - return nullptr; + auto it = CheckResultStore.find(Id); + ASSERT(it != CheckResultStore.end(), "Requested Warden result for invalid check ID %u", uint32(Id)); + return it->second; } diff --git a/src/server/game/Warden/WardenCheckMgr.h b/src/server/game/Warden/WardenCheckMgr.h index 99006aeb3bd..bee75667095 100644 --- a/src/server/game/Warden/WardenCheckMgr.h +++ b/src/server/game/Warden/WardenCheckMgr.h @@ -18,61 +18,69 @@ #ifndef _WARDENCHECKMGR_H #define _WARDENCHECKMGR_H -#include "Cryptography/BigNumber.h" -#include <map> +#include "Define.h" #include <shared_mutex> +#include <unordered_map> +#include <vector> -enum WardenActions +// EnumUtils: DESCRIBE THIS +enum WardenActions : uint8 { - WARDEN_ACTION_LOG, - WARDEN_ACTION_KICK, - WARDEN_ACTION_BAN + WARDEN_ACTION_LOG, // TITLE Log + WARDEN_ACTION_KICK, // TITLE Kick + WARDEN_ACTION_BAN // TITLE Ban +}; + +// EnumUtils: DESCRIBE THIS +enum WardenCheckType : uint8 +{ + MEM_CHECK = 0xF3, // 243: byte moduleNameIndex + uint Offset + byte Len (check to ensure memory isn't modified) + PAGE_CHECK_A = 0xB2, // 178: uint Seed + byte[20] SHA1 + uint Addr + byte Len (scans all pages for specified hash) + PAGE_CHECK_B = 0xBF, // 191: uint Seed + byte[20] SHA1 + uint Addr + byte Len (scans only pages starts with MZ+PE headers for specified hash) + MPQ_CHECK = 0x98, // 152: byte fileNameIndex (check to ensure MPQ file isn't modified) + LUA_STR_CHECK = 0x8B, // 139: byte luaNameIndex (check to ensure LUA string isn't used) + DRIVER_CHECK = 0x71, // 113: uint Seed + byte[20] SHA1 + byte driverNameIndex (check to ensure driver isn't loaded) + TIMING_CHECK = 0x57, // 87: empty (check to ensure GetTickCount() isn't detoured) + PROC_CHECK = 0x7E, // 126: uint Seed + byte[20] SHA1 + byte moluleNameIndex + byte procNameIndex + uint Offset + byte Len (check to ensure proc isn't detoured) + MODULE_CHECK = 0xD9 // 217: uint Seed + byte[20] SHA1 (check to ensure module isn't injected) }; struct WardenCheck { - uint8 Type; - BigNumber Data; + WardenCheckType Type; + std::vector<uint8> Data; uint32 Address; // PROC_CHECK, MEM_CHECK, PAGE_CHECK uint8 Length; // PROC_CHECK, MEM_CHECK, PAGE_CHECK std::string Str; // LUA, MPQ, DRIVER std::string Comment; uint16 CheckId; - enum WardenActions Action; + WardenActions Action; }; -struct WardenCheckResult -{ - BigNumber Result; // MEM_CHECK -}; +using WardenCheckResult = std::vector<uint8>; class TC_GAME_API WardenCheckMgr { private: WardenCheckMgr(); - ~WardenCheckMgr(); public: static WardenCheckMgr* instance(); - // We have a linear key without any gaps, so we use vector for fast access - typedef std::vector<WardenCheck*> CheckContainer; - typedef std::map<uint32, WardenCheckResult*> CheckResultContainer; + WardenCheck const& GetCheckDataById(uint16 Id) const; + WardenCheckResult const& GetCheckResultById(uint16 Id) const; - WardenCheck* GetWardenDataById(uint16 Id); - WardenCheckResult* GetWardenResultById(uint16 Id); - - std::vector<uint16> MemChecksIdPool; - std::vector<uint16> OtherChecksIdPool; + std::vector<uint16> const& GetAvailableMemoryChecks() const { return MemChecksIdPool; } + std::vector<uint16> const& GetAvailableOtherChecks() const { return OtherChecksIdPool; } void LoadWardenChecks(); void LoadWardenOverrides(); - std::shared_mutex _checkStoreLock; - private: - CheckContainer CheckStore; - CheckResultContainer CheckResultStore; + std::vector<WardenCheck> CheckStore; + std::unordered_map<uint32, WardenCheckResult> CheckResultStore; + std::vector<uint16> MemChecksIdPool; + std::vector<uint16> OtherChecksIdPool; }; #define sWardenCheckMgr WardenCheckMgr::instance() diff --git a/src/server/game/Warden/WardenMac.cpp b/src/server/game/Warden/WardenMac.cpp index 56c2942cb65..12293c76b91 100644 --- a/src/server/game/Warden/WardenMac.cpp +++ b/src/server/game/Warden/WardenMac.cpp @@ -29,6 +29,7 @@ #include "WorldSession.h" #include <openssl/md5.h> +#include <array> WardenMac::WardenMac() : Warden() { } @@ -39,8 +40,8 @@ void WardenMac::Init(WorldSession* pClient, SessionKey const& K) _session = pClient; // Generate Warden Key SessionKeyGenerator<Trinity::Crypto::SHA1> WK(K); - WK.Generate(_inputKey, 16); - WK.Generate(_outputKey, 16); + WK.Generate(_inputKey.data(), 16); + WK.Generate(_outputKey.data(), 16); /* Seed: 4D808D2C77D905C41A6380EC08586AFE (0x05 packet) Hash: <?> (0x04 packet) @@ -48,9 +49,8 @@ void WardenMac::Init(WorldSession* pClient, SessionKey const& K) New Client Key: <?> New Cerver Key: <?> */ - uint8 mod_seed[16] = { 0x4D, 0x80, 0x8D, 0x2C, 0x77, 0xD9, 0x05, 0xC4, 0x1A, 0x63, 0x80, 0xEC, 0x08, 0x58, 0x6A, 0xFE }; - memcpy(_seed, mod_seed, 16); + _seed = { 0x4D, 0x80, 0x8D, 0x2C, 0x77, 0xD9, 0x05, 0xC4, 0x1A, 0x63, 0x80, 0xEC, 0x08, 0x58, 0x6A, 0xFE }; _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); @@ -60,32 +60,18 @@ void WardenMac::Init(WorldSession* pClient, SessionKey const& K) TC_LOG_DEBUG("warden", " Seed: %s", ByteArrayToHexStr(_seed).c_str()); TC_LOG_DEBUG("warden", "Loading Module..."); - _module = GetModuleForClient(); + MakeModuleForClient(); TC_LOG_DEBUG("warden", "Module Key: %s", ByteArrayToHexStr(_module->Key).c_str()); TC_LOG_DEBUG("warden", "Module ID: %s", ByteArrayToHexStr(_module->Id).c_str()); RequestModule(); } -ClientWardenModule* WardenMac::GetModuleForClient() +void WardenMac::InitializeModuleForClient(ClientWardenModule& module) { - ClientWardenModule *mod = new ClientWardenModule; - - uint32 len = sizeof(Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data); - // data assign - mod->CompressedSize = len; - mod->CompressedData = new uint8[len]; - memcpy(mod->CompressedData, Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data, len); - memcpy(mod->Key, Module_0DBBF209A27B1E279A9FEC5C168A15F7_Key, 16); - - // md5 hash - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, mod->CompressedData, len); - MD5_Final((uint8*)&mod->Id, &ctx); - - return mod; + module.CompressedData = Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data.data(); + module.CompressedSize = Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data.size(); } void WardenMac::InitializeModule() @@ -100,7 +86,7 @@ void WardenMac::RequestHash() // Create packet structure WardenHashRequest Request; Request.Command = WARDEN_SMSG_HASH_REQUEST; - memcpy(Request.Seed, _seed, 16); + Request.Seed = _seed; // Encrypt with warden RC4 key. EncryptData((uint8*)&Request, sizeof(WardenHashRequest)); @@ -152,18 +138,15 @@ void WardenMac::HandleHashResult(ByteBuffer &buff) keyOut[3] = 0x1337F00D * keyIn[3]; // end test - buff.rpos(buff.wpos()); - - Trinity::Crypto::SHA1 sha1; - sha1.UpdateData((uint8*)keyIn, 16); - sha1.Finalize(); - //const uint8 validHash[20] = { 0x56, 0x8C, 0x05, 0x4C, 0x78, 0x1A, 0x97, 0x2A, 0x60, 0x37, 0xA2, 0x29, 0x0C, 0x22, 0xB5, 0x25, 0x71, 0xA0, 0x6F, 0x4E }; // Verify key - if (memcmp(buff.contents() + 1, sha1.GetDigest().data(), 20) != 0) + Trinity::Crypto::SHA1::Digest result; + buff.read(result); + if (result != Trinity::Crypto::SHA1::GetDigestOf(reinterpret_cast<uint8*>(keyIn), 16)) { - TC_LOG_WARN("warden", "%s failed hash reply. Action: %s", _session->GetPlayerInfo().c_str(), Penalty().c_str()); + char const* penalty = ApplyPenalty(nullptr); + TC_LOG_WARN("warden", "%s failed hash reply. Action: %s", _session->GetPlayerInfo().c_str(), penalty); return; } @@ -176,18 +159,16 @@ void WardenMac::HandleHashResult(ByteBuffer &buff) //const uint8 server_key[16] = { 0xC2, 0xB7, 0xAD, 0xED, 0xFC, 0xCC, 0xA9, 0xC2, 0xBF, 0xB3, 0xF8, 0x56, 0x02, 0xBA, 0x80, 0x9B }; // change keys here - memcpy(_inputKey, keyIn, 16); - memcpy(_outputKey, keyOut, 16); + memcpy(_inputKey.data(), keyIn, 16); + memcpy(_outputKey.data(), keyOut, 16); _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); _initialized = true; - - _previousTimestamp = GameTime::GetGameTimeMS(); } -void WardenMac::RequestData() +void WardenMac::RequestChecks() { TC_LOG_DEBUG("warden", "Request data"); @@ -211,7 +192,7 @@ void WardenMac::RequestData() _dataSent = true; } -void WardenMac::HandleData(ByteBuffer &buff) +void WardenMac::HandleCheckResult(ByteBuffer &buff) { TC_LOG_DEBUG("warden", "Handle data"); @@ -253,17 +234,17 @@ void WardenMac::HandleData(ByteBuffer &buff) MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, str.c_str(), str.size()); - uint8 ourMD5Hash[16]; - MD5_Final(ourMD5Hash, &ctx); + std::array<uint8, 16> ourMD5Hash; + MD5_Final(ourMD5Hash.data(), &ctx); - uint8 theirsMD5Hash[16]; - buff.read(theirsMD5Hash, 16); + std::array<uint8, 16> theirsMD5Hash; + buff.read(theirsMD5Hash); - if (memcmp(ourMD5Hash, theirsMD5Hash, 16) != 0) + if (ourMD5Hash != theirsMD5Hash) { TC_LOG_DEBUG("warden", "Handle data failed: MD5 hash is wrong!"); //found = true; } - _session->KickPlayer("WardenMac::HandleData"); + _session->KickPlayer("WardenMac::HandleCheckResult"); } diff --git a/src/server/game/Warden/WardenMac.h b/src/server/game/Warden/WardenMac.h index 18cf5c09fe6..d9fbf2a9870 100644 --- a/src/server/game/Warden/WardenMac.h +++ b/src/server/game/Warden/WardenMac.h @@ -32,12 +32,12 @@ class TC_GAME_API WardenMac : public Warden ~WardenMac(); void Init(WorldSession* session, SessionKey const& k) override; - ClientWardenModule* GetModuleForClient() override; + void InitializeModuleForClient(ClientWardenModule& module) override; void InitializeModule() override; void RequestHash() override; void HandleHashResult(ByteBuffer& buff) override; - void RequestData() override; - void HandleData(ByteBuffer& buff) override; + void RequestChecks() override; + void HandleCheckResult(ByteBuffer& buff) override; }; #endif diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index 42b718723a0..1118eb1113c 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -18,6 +18,7 @@ #include "WardenWin.h" #include "Common.h" #include "ByteBuffer.h" +#include "Containers.h" #include "CryptoRandom.h" #include "DatabaseEnv.h" #include "GameTime.h" @@ -27,28 +28,35 @@ #include "Player.h" #include "Random.h" #include "SessionKeyGenerator.h" +#include "SmartEnum.h" #include "Util.h" #include "WardenModuleWin.h" #include "WardenCheckMgr.h" #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" -#include <openssl/md5.h> #include <sstream> -WardenWin::WardenWin() : Warden(), _serverTicks(0) {} +WardenWin::WardenWin() : Warden(), _serverTicks(0) +{ + _memChecks = sWardenCheckMgr->GetAvailableMemoryChecks(); + Trinity::Containers::RandomShuffle(_memChecks); + _memChecksIt = _memChecks.begin(); -WardenWin::~WardenWin() { } + _otherChecks = sWardenCheckMgr->GetAvailableOtherChecks(); + Trinity::Containers::RandomShuffle(_otherChecks); + _otherChecksIt = _otherChecks.begin(); +} void WardenWin::Init(WorldSession* session, SessionKey const& K) { _session = session; // Generate Warden Key SessionKeyGenerator<Trinity::Crypto::SHA1> WK(K); - WK.Generate(_inputKey, 16); - WK.Generate(_outputKey, 16); + WK.Generate(_inputKey.data(), _inputKey.size()); + WK.Generate(_outputKey.data(), _outputKey.size()); - memcpy(_seed, Module.Seed, 16); + _seed = Module.Seed; _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); @@ -58,32 +66,19 @@ void WardenWin::Init(WorldSession* session, SessionKey const& K) TC_LOG_DEBUG("warden", " Seed: %s", ByteArrayToHexStr(_seed).c_str()); TC_LOG_DEBUG("warden", "Loading Module..."); - _module = GetModuleForClient(); + MakeModuleForClient(); TC_LOG_DEBUG("warden", "Module Key: %s", ByteArrayToHexStr(_module->Key).c_str()); TC_LOG_DEBUG("warden", "Module ID: %s", ByteArrayToHexStr(_module->Id).c_str()); RequestModule(); } -ClientWardenModule* WardenWin::GetModuleForClient() +void WardenWin::InitializeModuleForClient(ClientWardenModule& module) { - ClientWardenModule *mod = new ClientWardenModule; - - uint32 length = sizeof(Module.Module); - // data assign - mod->CompressedSize = length; - mod->CompressedData = new uint8[length]; - memcpy(mod->CompressedData, Module.Module, length); - memcpy(mod->Key, Module.ModuleKey, 16); - - // md5 hash - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, mod->CompressedData, length); - MD5_Final((uint8*)&mod->Id, &ctx); - - return mod; + module.CompressedData = Module.Module.data(); + module.CompressedSize = Module.Module.size(); + module.Key = Module.ModuleKey; } void WardenWin::InitializeModule() @@ -122,11 +117,24 @@ void WardenWin::InitializeModule() Request.Function3_set = 1; Request.CheckSumm3 = BuildChecksum(&Request.Unk5, 8); + EndianConvert(Request.Size1); + EndianConvert(Request.CheckSumm1); + EndianConvert(Request.Function1[0]); + EndianConvert(Request.Function1[1]); + EndianConvert(Request.Function1[2]); + EndianConvert(Request.Function1[3]); + EndianConvert(Request.Size2); + EndianConvert(Request.CheckSumm2); + EndianConvert(Request.Function2); + EndianConvert(Request.Size3); + EndianConvert(Request.CheckSumm3); + EndianConvert(Request.Function3); + // Encrypt with warden RC4 key. - EncryptData((uint8*)&Request, sizeof(WardenInitModuleRequest)); + EncryptData(reinterpret_cast<uint8*>(&Request), sizeof(WardenInitModuleRequest)); WorldPacket pkt(SMSG_WARDEN3_DATA, sizeof(WardenInitModuleRequest)); - pkt.append((uint8*)&Request, sizeof(WardenInitModuleRequest)); + pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenInitModuleRequest)); _session->SendPacket(&pkt); } @@ -137,105 +145,91 @@ void WardenWin::RequestHash() // Create packet structure WardenHashRequest Request; Request.Command = WARDEN_SMSG_HASH_REQUEST; - memcpy(Request.Seed, _seed, 16); + Request.Seed = _seed; // Encrypt with warden RC4 key. - EncryptData((uint8*)&Request, sizeof(WardenHashRequest)); + EncryptData(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest)); WorldPacket pkt(SMSG_WARDEN3_DATA, sizeof(WardenHashRequest)); - pkt.append((uint8*)&Request, sizeof(WardenHashRequest)); + pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest)); _session->SendPacket(&pkt); } void WardenWin::HandleHashResult(ByteBuffer &buff) { - buff.rpos(buff.wpos()); - // Verify key - if (memcmp(buff.contents() + 1, Module.ClientKeySeedHash, 20) != 0) + Trinity::Crypto::SHA1::Digest response; + buff.read(response); + if (response != Module.ClientKeySeedHash) { - TC_LOG_WARN("warden", "%s failed hash reply. Action: %s", _session->GetPlayerInfo().c_str(), Penalty().c_str()); + char const* penalty = ApplyPenalty(nullptr); + TC_LOG_WARN("warden", "%s failed hash reply. Action: %s", _session->GetPlayerInfo().c_str(), penalty); return; } TC_LOG_DEBUG("warden", "Request hash reply: succeed"); // Change keys here - memcpy(_inputKey, Module.ClientKeySeed, 16); - memcpy(_outputKey, Module.ServerKeySeed, 16); + _inputKey = Module.ClientKeySeed; + _outputKey = Module.ServerKeySeed; _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); _initialized = true; - - _previousTimestamp = GameTime::GetGameTimeMS(); } -void WardenWin::RequestData() +void WardenWin::RequestChecks() { TC_LOG_DEBUG("warden", "Request data"); // If all checks were done, fill the todo list again - if (_memChecksTodo.empty()) - _memChecksTodo.assign(sWardenCheckMgr->MemChecksIdPool.begin(), sWardenCheckMgr->MemChecksIdPool.end()); + if (_memChecksIt == _memChecks.end()) + { + TC_LOG_DEBUG("warden", "Finished all mem checks, re-shuffling"); + Trinity::Containers::RandomShuffle(_memChecks); + _memChecksIt = _memChecks.begin(); + } - if (_otherChecksTodo.empty()) - _otherChecksTodo.assign(sWardenCheckMgr->OtherChecksIdPool.begin(), sWardenCheckMgr->OtherChecksIdPool.end()); + if (_otherChecksIt == _otherChecks.end()) + { + TC_LOG_DEBUG("warden", "Finished all other checks, re-shuffling"); + Trinity::Containers::RandomShuffle(_otherChecks); + _otherChecksIt = _otherChecks.begin(); + } _serverTicks = GameTime::GetGameTimeMS(); - uint16 id; - uint8 type; - WardenCheck* wd; _currentChecks.clear(); // Build check request + ByteBuffer buff; + buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST); + for (uint32 i = 0; i < sWorld->getIntConfig(CONFIG_WARDEN_NUM_MEM_CHECKS); ++i) { // If todo list is done break loop (will be filled on next Update() run) - if (_memChecksTodo.empty()) + if (_memChecksIt == _memChecks.end()) break; - // Get check id from the end and remove it from todo - id = _memChecksTodo.back(); - _memChecksTodo.pop_back(); - - // Add the id to the list sent in this cycle - _currentChecks.push_back(id); + _currentChecks.push_back(*(_memChecksIt++)); } - ByteBuffer buff; - buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST); - - std::shared_lock<std::shared_mutex> lock(sWardenCheckMgr->_checkStoreLock); - for (uint32 i = 0; i < sWorld->getIntConfig(CONFIG_WARDEN_NUM_OTHER_CHECKS); ++i) { // If todo list is done break loop (will be filled on next Update() run) - if (_otherChecksTodo.empty()) + if (_otherChecksIt == _otherChecks.end()) break; - // Get check id from the end and remove it from todo - id = _otherChecksTodo.back(); - _otherChecksTodo.pop_back(); - - // Add the id to the list sent in this cycle - _currentChecks.push_back(id); + uint16 const id = *(_otherChecksIt++); - wd = sWardenCheckMgr->GetWardenDataById(id); - - switch (wd->Type) + WardenCheck const& check = sWardenCheckMgr->GetCheckDataById(id); + if (!check.Str.empty()) { - case MPQ_CHECK: - case LUA_STR_CHECK: - case DRIVER_CHECK: - buff << uint8(wd->Str.size()); - buff.append(wd->Str.c_str(), wd->Str.size()); - break; - default: - break; + buff << uint8(check.Str.size()); + buff.append(check.Str.data(), check.Str.size()); } + _currentChecks.push_back(id); } uint8 xorByte = _inputKey[0]; @@ -246,28 +240,27 @@ void WardenWin::RequestData() uint8 index = 1; - for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) + for (uint16 const id : _currentChecks) { - wd = sWardenCheckMgr->GetWardenDataById(*itr); + WardenCheck const& check = sWardenCheckMgr->GetCheckDataById(id); - type = wd->Type; + WardenCheckType const type = check.Type; buff << uint8(type ^ xorByte); switch (type) { case MEM_CHECK: { buff << uint8(0x00); - buff << uint32(wd->Address); - buff << uint8(wd->Length); + buff << uint32(check.Address); + buff << uint8(check.Length); break; } case PAGE_CHECK_A: case PAGE_CHECK_B: { - std::vector<uint8> data = wd->Data.ToByteVector(0, false); - buff.append(data.data(), data.size()); - buff << uint32(wd->Address); - buff << uint8(wd->Length); + buff.append(check.Data.data(), check.Data.size()); + buff << uint32(check.Address); + buff << uint8(check.Length); break; } case MPQ_CHECK: @@ -278,8 +271,7 @@ void WardenWin::RequestData() } case DRIVER_CHECK: { - std::vector<uint8> data = wd->Data.ToByteVector(0, false); - buff.append(data.data(), data.size()); + buff.append(check.Data.data(), check.Data.size()); buff << uint8(index++); break; } @@ -287,16 +279,16 @@ void WardenWin::RequestData() { std::array<uint8, 4> seed = Trinity::Crypto::GetRandomBytes<4>(); buff.append(seed); - buff.append(Trinity::Crypto::HMAC_SHA1::GetDigestOf(seed, wd->Str)); + buff.append(Trinity::Crypto::HMAC_SHA1::GetDigestOf(seed, check.Str)); break; } /*case PROC_CHECK: { - buff.append(wd->i.AsByteArray(0, false).get(), wd->i.GetNumBytes()); + buff.append(check->i.AsByteArray(0, false).get(), check->i.GetNumBytes()); buff << uint8(index++); buff << uint8(index++); - buff << uint32(wd->Address); - buff << uint8(wd->Length); + buff << uint32(check->Address); + buff << uint8(check->Length); break; }*/ default: @@ -317,13 +309,13 @@ void WardenWin::RequestData() std::stringstream stream; stream << "Sent check id's: "; - for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) - stream << *itr << " "; + for (uint16 const id : _currentChecks) + stream << id << " "; TC_LOG_DEBUG("warden", "%s", stream.str().c_str()); } -void WardenWin::HandleData(ByteBuffer &buff) +void WardenWin::HandleCheckResult(ByteBuffer &buff) { TC_LOG_DEBUG("warden", "Handle data"); @@ -335,10 +327,19 @@ void WardenWin::HandleData(ByteBuffer &buff) uint32 Checksum; buff >> Checksum; + if (Length != (buff.size() - buff.rpos())) + { + buff.rfinish(); + char const* penalty = ApplyPenalty(nullptr); + TC_LOG_WARN("warden", "%s sends manipulated warden packet. Action: %s", _session->GetPlayerInfo().c_str(), penalty); + return; + } + if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length)) { - buff.rpos(buff.wpos()); - TC_LOG_WARN("warden", "%s failed checksum. Action: %s", _session->GetPlayerInfo().c_str(), Penalty().c_str()); + buff.rfinish(); + char const* penalty = ApplyPenalty(nullptr); + TC_LOG_WARN("warden", "%s failed checksum. Action: %s", _session->GetPlayerInfo().c_str(), penalty); return; } @@ -349,7 +350,8 @@ void WardenWin::HandleData(ByteBuffer &buff) /// @todo test it. if (result == 0x00) { - TC_LOG_WARN("warden", "%s failed timing check. Action: %s", _session->GetPlayerInfo().c_str(), Penalty().c_str()); + char const* penalty = ApplyPenalty(nullptr); + TC_LOG_WARN("warden", "%s failed timing check. Action: %s", _session->GetPlayerInfo().c_str(), penalty); return; } @@ -359,26 +361,18 @@ void WardenWin::HandleData(ByteBuffer &buff) uint32 ticksNow = GameTime::GetGameTimeMS(); uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks); - TC_LOG_DEBUG("warden", "ServerTicks %u", ticksNow); // Now - TC_LOG_DEBUG("warden", "RequestTicks %u", _serverTicks); // At request - TC_LOG_DEBUG("warden", "Ticks %u", newClientTicks); // At response - TC_LOG_DEBUG("warden", "Ticks diff %u", ourTicks - newClientTicks); + TC_LOG_DEBUG("warden", "Server tick count now: %u", ticksNow); + TC_LOG_DEBUG("warden", "Server tick count at req: %u", _serverTicks); + TC_LOG_DEBUG("warden", "Client ticks in response: %u", newClientTicks); + TC_LOG_DEBUG("warden", "Round trip response time: %u ms", ourTicks - newClientTicks); } - WardenCheckResult* rs; - WardenCheck *rd; - uint8 type; uint16 checkFailed = 0; - - std::shared_lock<std::shared_mutex> lock(sWardenCheckMgr->_checkStoreLock); - - for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) + for (uint16 const id : _currentChecks) { - rd = sWardenCheckMgr->GetWardenDataById(*itr); - rs = sWardenCheckMgr->GetWardenResultById(*itr); + WardenCheck const& check = sWardenCheckMgr->GetCheckDataById(id); - type = rd->Type; - switch (type) + switch (check.Type) { case MEM_CHECK: { @@ -387,22 +381,22 @@ void WardenWin::HandleData(ByteBuffer &buff) if (Mem_Result != 0) { - TC_LOG_DEBUG("warden", "RESULT MEM_CHECK not 0x00, CheckId %u account Id %u", *itr, _session->GetAccountId()); - checkFailed = *itr; + TC_LOG_DEBUG("warden", "RESULT MEM_CHECK not 0x00, CheckId %u account Id %u", id, _session->GetAccountId()); + checkFailed = id; continue; } - std::vector<uint8> result = rs->Result.ToByteVector(0, false); - if (memcmp(buff.contents() + buff.rpos(), result.data(), rd->Length) != 0) + std::vector<uint8> response; + response.resize(check.Length); + buff.read(response.data(), response.size()); + if (response != sWardenCheckMgr->GetCheckResultById(id)) { - TC_LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId %u account Id %u", *itr, _session->GetAccountId()); - checkFailed = *itr; - buff.rpos(buff.rpos() + rd->Length); + TC_LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId %u account Id %u", id, _session->GetAccountId()); + checkFailed = id; continue; } - buff.rpos(buff.rpos() + rd->Length); - TC_LOG_DEBUG("warden", "RESULT MEM_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId()); + TC_LOG_DEBUG("warden", "RESULT MEM_CHECK passed CheckId %u account Id %u", id, _session->GetAccountId()); break; } case PAGE_CHECK_A: @@ -410,27 +404,14 @@ void WardenWin::HandleData(ByteBuffer &buff) case DRIVER_CHECK: case MODULE_CHECK: { - const uint8 byte = 0xE9; - if (memcmp(buff.contents() + buff.rpos(), &byte, sizeof(uint8)) != 0) + if (buff.read<uint8>() != 0xE9) { - if (type == PAGE_CHECK_A || type == PAGE_CHECK_B) - TC_LOG_DEBUG("warden", "RESULT PAGE_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId()); - if (type == MODULE_CHECK) - TC_LOG_DEBUG("warden", "RESULT MODULE_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId()); - if (type == DRIVER_CHECK) - TC_LOG_DEBUG("warden", "RESULT DRIVER_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId()); - checkFailed = *itr; - buff.rpos(buff.rpos() + 1); + TC_LOG_DEBUG("warden", "RESULT %s fail, CheckId %u account Id %u", EnumUtils::ToConstant(check.Type), id, _session->GetAccountId()); + checkFailed = id; continue; } - buff.rpos(buff.rpos() + 1); - if (type == PAGE_CHECK_A || type == PAGE_CHECK_B) - TC_LOG_DEBUG("warden", "RESULT PAGE_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId()); - else if (type == MODULE_CHECK) - TC_LOG_DEBUG("warden", "RESULT MODULE_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId()); - else if (type == DRIVER_CHECK) - TC_LOG_DEBUG("warden", "RESULT DRIVER_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId()); + TC_LOG_DEBUG("warden", "RESULT %s passed CheckId %u account Id %u", EnumUtils::ToConstant(check.Type), id, _session->GetAccountId()); break; } case LUA_STR_CHECK: @@ -440,24 +421,20 @@ void WardenWin::HandleData(ByteBuffer &buff) if (Lua_Result != 0) { - TC_LOG_DEBUG("warden", "RESULT LUA_STR_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId()); - checkFailed = *itr; + TC_LOG_DEBUG("warden", "RESULT LUA_STR_CHECK fail, CheckId %u account Id %u", id, _session->GetAccountId()); + checkFailed = id; continue; } - uint8 luaStrLen; - buff >> luaStrLen; - + uint8 luaStrLen = buff.read<uint8>(); if (luaStrLen != 0) { - char *str = new char[luaStrLen + 1]; - memcpy(str, buff.contents() + buff.rpos(), luaStrLen); - str[luaStrLen] = '\0'; // null terminator - TC_LOG_DEBUG("warden", "Lua string: %s", str); - delete[] str; + std::string str; + str.resize(luaStrLen); + buff.read(reinterpret_cast<uint8*>(str.data()), luaStrLen); + TC_LOG_DEBUG("warden", "Lua string: %s", str.c_str()); } - buff.rpos(buff.rpos() + luaStrLen); // Skip string - TC_LOG_DEBUG("warden", "RESULT LUA_STR_CHECK passed, CheckId %u account Id %u", *itr, _session->GetAccountId()); + TC_LOG_DEBUG("warden", "RESULT LUA_STR_CHECK passed, CheckId %u account Id %u", id, _session->GetAccountId()); break; } case MPQ_CHECK: @@ -468,20 +445,21 @@ void WardenWin::HandleData(ByteBuffer &buff) if (Mpq_Result != 0) { TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK not 0x00 account id %u", _session->GetAccountId()); - checkFailed = *itr; + checkFailed = id; continue; } - if (memcmp(buff.contents() + buff.rpos(), rs->Result.ToByteArray<20>(false).data(), 20) != 0) // SHA1 + std::vector<uint8> result; + result.resize(Trinity::Crypto::SHA1::DIGEST_LENGTH); + buff.read(result.data(), result.size()); + if (result != sWardenCheckMgr->GetCheckResultById(id)) // SHA1 { - TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId()); - checkFailed = *itr; - buff.rpos(buff.rpos() + 20); // 20 bytes SHA1 + TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId %u account Id %u", id, _session->GetAccountId()); + checkFailed = id; continue; } - buff.rpos(buff.rpos() + 20); // 20 bytes SHA1 - TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK passed, CheckId %u account Id %u", *itr, _session->GetAccountId()); + TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK passed, CheckId %u account Id %u", id, _session->GetAccountId()); break; } default: // Should never happen @@ -491,8 +469,9 @@ void WardenWin::HandleData(ByteBuffer &buff) if (checkFailed > 0) { - WardenCheck* check = sWardenCheckMgr->GetWardenDataById(checkFailed); - TC_LOG_WARN("warden", "%s failed Warden check %u. Action: %s", _session->GetPlayerInfo().c_str(), checkFailed, Penalty(check).c_str()); + WardenCheck const& check = sWardenCheckMgr->GetCheckDataById(checkFailed); + char const* penalty = ApplyPenalty(&check); + TC_LOG_WARN("warden", "%s failed Warden check %u (%s). Action: %s", _session->GetPlayerInfo().c_str(), checkFailed, EnumUtils::ToConstant(check.Type), penalty); } // Set hold off timer, minimum timer should at least be 1 second diff --git a/src/server/game/Warden/WardenWin.h b/src/server/game/Warden/WardenWin.h index ff4093738df..e8bcbd56e9f 100644 --- a/src/server/game/Warden/WardenWin.h +++ b/src/server/game/Warden/WardenWin.h @@ -55,6 +55,7 @@ struct WardenInitModuleRequest uint32 Function3; uint8 Function3_set; }; +static_assert(sizeof(WardenInitModuleRequest) == (1 + 2 + 4 + 1 + 1 + 1 + 1 + (4 * 4) + 1 + 2 + 4 + 1 + 1 + 1 + 4 + 1 + 1 + 2 + 4 + 1 + 1 + 1 + 4 + 1)); #pragma pack(pop) @@ -65,21 +66,22 @@ class TC_GAME_API WardenWin : public Warden { public: WardenWin(); - ~WardenWin(); void Init(WorldSession* session, SessionKey const& K) override; - ClientWardenModule* GetModuleForClient() override; + void InitializeModuleForClient(ClientWardenModule& module) override; void InitializeModule() override; void RequestHash() override; void HandleHashResult(ByteBuffer &buff) override; - void RequestData() override; - void HandleData(ByteBuffer &buff) override; + void RequestChecks() override; + void HandleCheckResult(ByteBuffer &buff) override; private: uint32 _serverTicks; - std::list<uint16> _otherChecksTodo; - std::list<uint16> _memChecksTodo; - std::list<uint16> _currentChecks; + std::vector<uint16> _memChecks; + std::vector<uint16>::const_iterator _memChecksIt; + std::vector<uint16> _otherChecks; + std::vector<uint16>::const_iterator _otherChecksIt; + std::vector<uint16> _currentChecks; }; #endif diff --git a/src/server/game/Warden/enuminfo_WardenCheckMgr.cpp b/src/server/game/Warden/enuminfo_WardenCheckMgr.cpp new file mode 100644 index 00000000000..e4c5fc4efa3 --- /dev/null +++ b/src/server/game/Warden/enuminfo_WardenCheckMgr.cpp @@ -0,0 +1,100 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "WardenCheckMgr.h" +#include "Define.h" +#include "SmartEnum.h" +#include <stdexcept> + +namespace Trinity +{ +namespace Impl +{ + +/**********************************************************************\ +|* data for enum 'WardenActions' in 'WardenCheckMgr.h' auto-generated *| +\**********************************************************************/ +template <> +TC_API_EXPORT EnumText EnumUtils<WardenActions>::ToString(WardenActions value) +{ + switch (value) + { + case WARDEN_ACTION_LOG: return { "WARDEN_ACTION_LOG", "Log", "" }; + case WARDEN_ACTION_KICK: return { "WARDEN_ACTION_KICK", "Kick", "" }; + case WARDEN_ACTION_BAN: return { "WARDEN_ACTION_BAN", "Ban", "" }; + default: throw std::out_of_range("value"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils<WardenActions>::Count() { return 3; } + +template <> +TC_API_EXPORT WardenActions EnumUtils<WardenActions>::FromIndex(size_t index) +{ + switch (index) + { + case 0: return WARDEN_ACTION_LOG; + case 1: return WARDEN_ACTION_KICK; + case 2: return WARDEN_ACTION_BAN; + default: throw std::out_of_range("index"); + } +} + +/************************************************************************\ +|* data for enum 'WardenCheckType' in 'WardenCheckMgr.h' auto-generated *| +\************************************************************************/ +template <> +TC_API_EXPORT EnumText EnumUtils<WardenCheckType>::ToString(WardenCheckType value) +{ + switch (value) + { + case MEM_CHECK: return { "MEM_CHECK", "MEM_CHECK", "243: byte moduleNameIndex + uint Offset + byte Len (check to ensure memory isn't modified)" }; + case PAGE_CHECK_A: return { "PAGE_CHECK_A", "PAGE_CHECK_A", "178: uint Seed + byte[20] SHA1 + uint Addr + byte Len (scans all pages for specified hash)" }; + case PAGE_CHECK_B: return { "PAGE_CHECK_B", "PAGE_CHECK_B", "191: uint Seed + byte[20] SHA1 + uint Addr + byte Len (scans only pages starts with MZ+PE headers for specified hash)" }; + case MPQ_CHECK: return { "MPQ_CHECK", "MPQ_CHECK", "152: byte fileNameIndex (check to ensure MPQ file isn't modified)" }; + case LUA_STR_CHECK: return { "LUA_STR_CHECK", "LUA_STR_CHECK", "139: byte luaNameIndex (check to ensure LUA string isn't used)" }; + case DRIVER_CHECK: return { "DRIVER_CHECK", "DRIVER_CHECK", "113: uint Seed + byte[20] SHA1 + byte driverNameIndex (check to ensure driver isn't loaded)" }; + case TIMING_CHECK: return { "TIMING_CHECK", "TIMING_CHECK", "87: empty (check to ensure GetTickCount() isn't detoured)" }; + case PROC_CHECK: return { "PROC_CHECK", "PROC_CHECK", "126: uint Seed + byte[20] SHA1 + byte moluleNameIndex + byte procNameIndex + uint Offset + byte Len (check to ensure proc isn't detoured)" }; + case MODULE_CHECK: return { "MODULE_CHECK", "MODULE_CHECK", "217: uint Seed + byte[20] SHA1 (check to ensure module isn't injected)" }; + default: throw std::out_of_range("value"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils<WardenCheckType>::Count() { return 9; } + +template <> +TC_API_EXPORT WardenCheckType EnumUtils<WardenCheckType>::FromIndex(size_t index) +{ + switch (index) + { + case 0: return MEM_CHECK; + case 1: return PAGE_CHECK_A; + case 2: return PAGE_CHECK_B; + case 3: return MPQ_CHECK; + case 4: return LUA_STR_CHECK; + case 5: return DRIVER_CHECK; + case 6: return TIMING_CHECK; + case 7: return PROC_CHECK; + case 8: return MODULE_CHECK; + default: throw std::out_of_range("index"); + } +} +} +} diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 16bfea63ad5..17992ddddba 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -47,7 +47,6 @@ EndScriptData */ #include "SmartAI.h" #include "SpellMgr.h" #include "SupportMgr.h" -#include "WardenCheckMgr.h" #include "WaypointManager.h" #include "World.h" @@ -160,7 +159,6 @@ public: { "support", rbac::RBAC_PERM_COMMAND_RELOAD_SUPPORT_SYSTEM, true, &HandleReloadSupportSystemCommand, "" }, { "trainer", rbac::RBAC_PERM_COMMAND_RELOAD_TRAINER, true, &HandleReloadTrainerCommand, "" }, { "trinity_string", rbac::RBAC_PERM_COMMAND_RELOAD_TRINITY_STRING, true, &HandleReloadTrinityStringCommand, "" }, - { "warden_action", rbac::RBAC_PERM_COMMAND_RELOAD_WARDEN_ACTION, true, &HandleReloadWardenactionCommand, "" }, { "waypoint_scripts", rbac::RBAC_PERM_COMMAND_RELOAD_WAYPOINT_SCRIPTS, true, &HandleReloadWpScriptsCommand, "" }, { "waypoint_data", rbac::RBAC_PERM_COMMAND_RELOAD_WAYPOINT_DATA, true, &HandleReloadWpCommand, "" }, { "vehicle_template", rbac::RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE, true, &HandleReloadVehicleTemplateCommand, "" }, @@ -697,21 +695,6 @@ public: return true; } - static bool HandleReloadWardenactionCommand(ChatHandler* handler, char const* /*args*/) - { - if (!sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED)) - { - handler->SendSysMessage("Warden system disabled by config - reloading warden_action skipped."); - handler->SetSentErrorMessage(true); - return false; - } - - TC_LOG_INFO("misc", "Re-Loading warden_action Table!"); - sWardenCheckMgr->LoadWardenOverrides(); - handler->SendGlobalGMSysMessage("DB table `warden_action` reloaded."); - return true; - } - static bool HandleReloadTrainerCommand(ChatHandler* handler, char const* /*args*/) { TC_LOG_INFO("misc", "Re-Loading `trainer` Table!"); |