diff options
Diffstat (limited to 'src/server/game/Warden/WardenWin.cpp')
-rw-r--r-- | src/server/game/Warden/WardenWin.cpp | 295 |
1 files changed, 137 insertions, 158 deletions
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 |