aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Warden/WardenWin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Warden/WardenWin.cpp')
-rw-r--r--src/server/game/Warden/WardenWin.cpp295
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