feat(Core/Warden): optimization + PQR detection (#3875)

* Update AuctionHouseHandler.cpp

* feat(warden): block PQR

* wip

* Update Warden.cpp

* Core/Warden: minor preperation

* Core/Misc: implemented some needed container wrapper functions

* Core/Warden: more preperations

* Core/Warden: more rework
* LUA checks now are splitted to seperate config
* LUA checks are always in front of queue
* Fixed "Other" checks
* Fixed PQR detection

* Core/Warden: adjusted and optimized

* Core/Warden: optimization

* Core/Warden: more optimization

* Core/Warden: use warden comments in ban reason

* Core/Warden: more warden work

* Core/Warden: more optimizations

* Core/Warden: more refactors

* Core/Warden: some more refactors + use default SHA definitions

* Core/Warden: more refactoring

* Core/Warden: fixed PQR detection again

* Core/Warden: improved detection logging

* Core/Misc: removed SmartEnums - we do not need it here + maybe should go as seperate commit

* Core/Warden: fixed some warnings

* Core/Warden: codestyle

* Core/Warden: include warden check comment to console logs

* Core/Warden: minor adjustment for previous commit

* Core/Warden: fixed static analysis warning

* Core/Warden: compilers, you're drunk this time... function is not unused...

* Core/Warden: minor correction for logs

* Core/Warden: one more improvement for logs

* Core/Warden: added missing overrides

* Core/Warden: some codestyle

* Core/Misc: more codestyle

* Core/Misc: more codestyle!

* Core/Warden: restored default config options... (if you change it, change in core source too)

* Core/Warden: addition to previous commit

* DB/Warden: added EWT and WOWPlus checks (provided by lineagedr)

* DB/Warden: addition to previous commit

* fix: codestyle

* Core/Warden: fixed build when extra logs are enabled in cmake

Co-authored-by: Stefano Borzì <stefanoborzi32@gmail.com>
Co-authored-by: Francesco Borzì <borzifrancesco@gmail.com>
This commit is contained in:
Andrius Peleckas
2021-01-17 19:36:35 +02:00
committed by GitHub
parent 17f2fdb537
commit 2794842553
15 changed files with 639 additions and 417 deletions

View File

@@ -27,6 +27,7 @@
#include "Util.h"
#include "ScriptMgr.h"
#include "AccountMgr.h"
#include "Warden.h"
#ifdef ELUNA
#include "LuaEngine.h"
@@ -280,6 +281,12 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
if (lang != LANG_ADDON && sWorld->getBoolConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
// Our Warden module also uses SendAddonMessage as a way to communicate Lua check results to the server, see if this is that
if ((type == CHAT_MSG_GUILD) && (lang == LANG_ADDON) && _warden && _warden->ProcessLuaCheckResponse(msg))
{
return;
}
// pussywizard:
if (msg.length() > 255 || (lang != LANG_ADDON && msg.find("|0") != std::string::npos))
return;

View File

@@ -391,12 +391,16 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
if (updater.ProcessLogout())
{
if (m_Socket && !m_Socket->IsClosed() && _warden)
{
_warden->Update(diff);
}
time_t currTime = time(nullptr);
if (ShouldLogOut(currTime) && !m_playerLoading)
{
LogoutPlayer(true);
if (m_Socket && !m_Socket->IsClosed() && _warden)
_warden->Update();
}
if (m_Socket && m_Socket->IsClosed())
{
@@ -405,7 +409,9 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
}
if (!m_Socket)
{
return false;
}
}
return true;

View File

@@ -18,9 +18,10 @@
#include "Warden.h"
#include "AccountMgr.h"
#include "BanManager.h"
#include "SharedDefines.h"
Warden::Warden() : _session(nullptr), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0),
_dataSent(false), _previousTimestamp(0), _module(nullptr), _initialized(false)
_dataSent(false), _module(nullptr), _initialized(false)
{
memset(_inputKey, 0, sizeof(_inputKey));
memset(_outputKey, 0, sizeof(_outputKey));
@@ -77,6 +78,8 @@ void Warden::RequestModule()
memcpy(request.ModuleKey, _module->Key, 16);
request.Size = _module->CompressedSize;
EndianConvert(request.Size);
// Encrypt with warden RC4 key.
EncryptData((uint8*)&request, sizeof(WardenModuleUse));
@@ -85,31 +88,37 @@ void Warden::RequestModule()
_session->SendPacket(&pkt);
}
void Warden::Update()
void Warden::Update(uint32 const diff)
{
if (_initialized)
if (!_initialized)
{
uint32 currentTimestamp = World::GetGameTimeMS();
uint32 diff = getMSTimeDiff(_previousTimestamp, currentTimestamp);
_previousTimestamp = currentTimestamp;
return;
}
if (_dataSent)
if (_dataSent)
{
uint32 maxClientResponseDelay = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_RESPONSE_DELAY);
if (maxClientResponseDelay > 0)
{
uint32 maxClientResponseDelay = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_RESPONSE_DELAY);
if (maxClientResponseDelay > 0)
if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS)
{
if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS)
_session->KickPlayer("clientResponseTimer > maxClientResponseDelay");
else
_clientResponseTimer += diff;
_session->KickPlayer("Warden: clientResponseTimer > maxClientResponseDelay (Warden::Update)");
}
else
{
_clientResponseTimer += diff;
}
}
}
else
{
if (diff >= _checkTimer)
{
RequestChecks();
}
else
{
if (diff >= _checkTimer)
RequestData();
else
_checkTimer -= diff;
_checkTimer -= diff;
}
}
}
@@ -166,136 +175,142 @@ uint32 Warden::BuildChecksum(const uint8* data, uint32 length)
SHA1(data, length, hash.bytes.bytes);
uint32 checkSum = 0;
for (uint8 i = 0; i < 5; ++i)
{
checkSum = checkSum ^ hash.ints.ints[i];
}
return checkSum;
}
std::string Warden::Penalty(WardenCheck* check /*= NULL*/, uint16 checkFailed /*= 0*/)
static std::string GetWardenActionStr(uint32 action)
{
WardenActions action;
switch (action)
{
case WARDEN_ACTION_LOG:
return "WARDEN_ACTION_LOG";
case WARDEN_ACTION_KICK:
return "WARDEN_ACTION_KICK";
case WARDEN_ACTION_BAN:
return "WARDEN_ACTION_BAN";
}
if (check)
action = check->Action;
else
action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION));
return "UNHANDLED ACTION";
}
std::string banReason = "Anticheat violation";
bool longBan = false; // 14d = 1209600s
if (checkFailed)
switch (checkFailed)
void Warden::ApplyPenalty(uint16 checkId, std::string const& reason)
{
WardenCheck const* checkData = sWardenCheckMgr->GetWardenDataById(checkId);
uint32 action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION));
std::string causeMsg;
if (checkId && checkData)
{
action = checkData->Action;
if (checkData->Comment.empty())
{
case 47:
banReason += " (FrameXML Signature Check)";
break;
case 51:
banReason += " (Lua DoString)";
break;
case 59:
banReason += " (Lua Protection Patch)";
break;
case 72:
banReason += " (Movement State related)";
break;
case 118:
banReason += " (Wall Climb)";
break;
case 121:
banReason += " (No Fall Damage Patch)";
break;
case 193:
banReason += " (Follow Unit Check)";
break;
case 209:
banReason += " (WoWEmuHacker Injection)";
longBan = true;
break;
case 237:
banReason += " (AddChatMessage)";
break;
case 246:
banReason += " (Language Patch)";
break;
case 260:
banReason += " (Jump Momentum)";
break;
case 288:
banReason += " (Language Patch)";
break;
case 308:
banReason += " (SendChatMessage)";
break;
case 312:
banReason += " (Jump Physics)";
break;
case 314:
banReason += " (GetCharacterInfo)";
break;
case 329:
banReason += " (Wall Climb)";
break;
case 343:
banReason += " (Login Password Pointer)";
break;
case 349:
banReason += " (Language Patch)";
break;
case 712:
banReason += " (WS2_32.Send)";
break;
case 780:
banReason += " (Lua Protection Remover)";
break;
case 781:
banReason += " (Walk on Water Patch)";
break;
case 782:
banReason += " (Collision M2 Special)";
longBan = true;
break;
case 783:
banReason += " (Collision M2 Regular)";
longBan = true;
break;
case 784:
banReason += " (Collision WMD)";
longBan = true;
break;
case 785:
banReason += " (Multi-Jump Patch)";
break;
case 786:
banReason += " (WPE PRO)";
longBan = true;
break;
case 787:
banReason += " (rEdoX Packet Editor)";
break;
causeMsg = "Warden id " + std::to_string(checkId) + " violation";
}
else
{
causeMsg = "Warden: " + checkData->Comment;
}
}
else
{
// if its not warden check id based, reason must be always provided
ASSERT(!reason.empty());
causeMsg = reason;
}
switch (action)
{
case WARDEN_ACTION_LOG:
return "None";
break;
case WARDEN_ACTION_KICK:
_session->KickPlayer("WARDEN_ACTION_KICK");
return "Kick";
{
_session->KickPlayer(causeMsg.find("Warden") != std::string::npos ? causeMsg : "Warden: " + causeMsg);
break;
}
case WARDEN_ACTION_BAN:
{
std::stringstream duration;
duration << sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION) << "s";
std::string accountName;
AccountMgr::GetName(_session->GetAccountId(), accountName);
sBan->BanAccount(accountName, ((longBan && false /*ZOMG!*/) ? "1209600s" : duration.str()), banReason, "Server");
return "Ban";
}
default:
{
std::stringstream duration;
duration << sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION) << "s";
std::string accountName;
AccountMgr::GetName(_session->GetAccountId(), accountName);
sBan->BanAccount(accountName, duration.str(), causeMsg, "Server");
break;
}
}
return "Undefined";
std::string reportMsg;
if (checkId)
{
if (Player const* plr = _session->GetPlayer())
{
std::string const reportFormat = "Player %s (guid %u, account id: %u) failed warden %u check (%s). Action: %s";
reportMsg = acore::StringFormat(reportFormat, plr->GetName().c_str(), plr->GetGUIDLow(), _session->GetAccountId(),
checkId, ((checkData && !checkData->Comment.empty()) ? checkData->Comment.c_str() : "<warden comment is not set>"),
GetWardenActionStr(action).c_str());
}
else
{
std::string const reportFormat = "Account id: %u failed warden %u check. Action: %s";
reportMsg = acore::StringFormat(reportFormat, _session->GetAccountId(), checkId, GetWardenActionStr(action).c_str());
}
}
else
{
if (Player const* plr = _session->GetPlayer())
{
std::string const reportFormat = "Player %s (guid %u, account id: %u) triggered warden penalty by reason: %s. Action: %s";
reportMsg = acore::StringFormat(reportFormat, plr->GetName().c_str(), plr->GetGUIDLow(), _session->GetAccountId(), causeMsg.c_str(), GetWardenActionStr(action).c_str());
}
else
{
std::string const reportFormat = "Account id: %u failed warden %u check. Action: %s";
reportMsg = acore::StringFormat(reportFormat, _session->GetAccountId(), causeMsg.c_str(), GetWardenActionStr(action).c_str());
}
}
reportMsg = "Warden: " + reportMsg;
sLog->outString(reportMsg.c_str());
}
bool Warden::ProcessLuaCheckResponse(std::string const& msg)
{
static constexpr char WARDEN_TOKEN[] = "_TW\t";
// if msg starts with WARDEN_TOKEN
if (!(msg.rfind(WARDEN_TOKEN, 0) == 0))
{
return false;
}
uint16 id = 0;
{
std::stringstream msg2(msg);
std::string temp;
while (msg2 >> temp)
{
// Found check id - stop loop
if (std::stringstream(temp) >> id)
break;
}
}
if (id < sWardenCheckMgr->GetMaxValidCheckId())
{
WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(id);
if (check && check->Type == LUA_EVAL_CHECK)
{
ApplyPenalty(id, "");
return true;
}
}
ApplyPenalty(0, "Sent bogus Lua check response for Warden");
return true;
}
void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData)

View File

@@ -38,7 +38,7 @@ enum WardenCheckType
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)
LUA_EVAL_CHECK = 139, // evaluate arbitrary Lua check
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)
@@ -101,21 +101,22 @@ public:
virtual ClientWardenModule* GetModuleForClient() = 0;
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 RequestChecks() = 0;
virtual void HandleData(ByteBuffer &buff) = 0;
bool ProcessLuaCheckResponse(std::string const& msg);
void SendModuleToClient();
void RequestModule();
void Update();
void Update(uint32 const diff);
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);
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 = NULL, uint16 checkFailed = 0);
void ApplyPenalty(uint16 checkId, std::string const& reason);
private:
WorldSession* _session;
@@ -127,7 +128,6 @@ private:
uint32 _checkTimer; // Timer for sending check requests
uint32 _clientResponseTimer; // Timer for client response delay
bool _dataSent;
uint32 _previousTimestamp;
ClientWardenModule* _module;
bool _initialized;
};

View File

@@ -19,11 +19,6 @@ 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;
}
WardenCheckMgr* WardenCheckMgr::instance()
@@ -67,6 +62,13 @@ void WardenCheckMgr::LoadWardenChecks()
uint16 id = fields[0].GetUInt16();
uint8 checkType = fields[1].GetUInt8();
if (checkType == LUA_EVAL_CHECK && id > 9999)
{
sLog->outError("sql.sql: Warden Lua check with id %u found in `warden_checks`. Lua checks may have four-digit IDs at most. Skipped.", id);
continue;
}
std::string data = fields[2].GetString();
std::string checkResult = fields[3].GetString();
uint32 address = fields[4].GetUInt32();
@@ -74,66 +76,96 @@ void WardenCheckMgr::LoadWardenChecks()
std::string str = fields[6].GetString();
std::string comment = fields[7].GetString();
WardenCheck* wardenCheck = new WardenCheck();
wardenCheck->Type = checkType;
wardenCheck->CheckId = id;
WardenCheck &wardenCheck = CheckStore.at(id);
wardenCheck.Type = checkType;
wardenCheck.CheckId = id;
// Initialize action with default action from config
wardenCheck->Action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION));
if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK)
wardenCheck.Action = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION);
if (wardenCheck.Action > MAX_WARDEN_ACTION)
{
wardenCheck->Data.SetHexStr(data.c_str());
int len = data.size() / 2;
if (wardenCheck->Data.GetNumBytes() < len)
{
uint8 temp[24];
memset(temp, 0, len);
memcpy(temp, wardenCheck->Data.AsByteArray().get(), wardenCheck->Data.GetNumBytes());
std::reverse(temp, temp + len);
wardenCheck->Data.SetBinary((uint8*)temp, len);
}
wardenCheck.Action = WARDEN_ACTION_BAN;
}
if (checkType == MEM_CHECK || checkType == MODULE_CHECK)
MemChecksIdPool.push_back(id);
else
OtherChecksIdPool.push_back(id);
if (checkType == MEM_CHECK || checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == PROC_CHECK)
{
wardenCheck->Address = address;
wardenCheck->Length = length;
wardenCheck.Address = address;
wardenCheck.Length = length;
}
// PROC_CHECK support missing
if (checkType == MEM_CHECK || checkType == MPQ_CHECK || checkType == LUA_STR_CHECK || checkType == DRIVER_CHECK || checkType == MODULE_CHECK)
wardenCheck->Str = str;
CheckStore[id] = wardenCheck;
if (checkType == MEM_CHECK || checkType == MPQ_CHECK || checkType == LUA_EVAL_CHECK || checkType == DRIVER_CHECK || checkType == MODULE_CHECK)
{
wardenCheck.Str = str;
}
if (checkType == MPQ_CHECK || checkType == MEM_CHECK)
{
WardenCheckResult* wr = new WardenCheckResult();
wr->Result.SetHexStr(checkResult.c_str());
int len = checkResult.size() / 2;
if (wr->Result.GetNumBytes() < len)
WardenCheckResult wr;
wr.Result.SetHexStr(checkResult.c_str());
int len = static_cast<int>(checkResult.size()) / 2;
if (wr.Result.GetNumBytes() < len)
{
uint8* temp = new uint8[len];
memset(temp, 0, len);
memcpy(temp, wr->Result.AsByteArray().get(), wr->Result.GetNumBytes());
memcpy(temp, wr.Result.AsByteArray().get(), wr.Result.GetNumBytes());
std::reverse(temp, temp + len);
wr->Result.SetBinary((uint8*)temp, len);
wr.Result.SetBinary((uint8*)temp, len);
delete [] temp;
}
CheckResultStore[id] = wr;
}
if (comment.empty())
wardenCheck->Comment = "Undocumented Check";
wardenCheck.Comment = "Undocumented Check";
else
wardenCheck->Comment = comment;
wardenCheck.Comment = comment;
// Prepare check pools
switch (checkType)
{
case MEM_CHECK:
case MODULE_CHECK:
{
CheckIdPool[WARDEN_CHECK_MEM_TYPE].push_back(id);
break;
}
case LUA_EVAL_CHECK:
{
if (wardenCheck.Length > WARDEN_MAX_LUA_CHECK_LENGTH)
{
sLog->outError("sql.sql: Found over-long Lua check for Warden check with id %u in `warden_checks`. Max length is %u. Skipped.", id, WARDEN_MAX_LUA_CHECK_LENGTH);
continue;
}
std::string str = fmt::sprintf("%04u", id);
ASSERT(str.size() == 4);
std::copy(str.begin(), str.end(), wardenCheck.IdStr.begin());
CheckIdPool[WARDEN_CHECK_LUA_TYPE].push_back(id);
break;
}
default:
{
if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK)
{
wardenCheck.Data.SetHexStr(data.c_str());
int len = static_cast<int>(data.size()) / 2;
if (wardenCheck.Data.GetNumBytes() < len)
{
uint8 temp[24];
memset(temp, 0, len);
memcpy(temp, wardenCheck.Data.AsByteArray().get(), wardenCheck.Data.GetNumBytes());
std::reverse(temp, temp + len);
wardenCheck.Data.SetBinary((uint8*)temp, len);
}
}
CheckIdPool[WARDEN_CHECK_OTHER_TYPE].push_back(id);
break;
}
}
++count;
} while (result->NextRow());
@@ -164,8 +196,6 @@ void WardenCheckMgr::LoadWardenOverrides()
uint32 count = 0;
ACE_WRITE_GUARD(ACE_RW_Mutex, g, _checkStoreLock);
do
{
Field* fields = result->Fetch();
@@ -181,7 +211,7 @@ void WardenCheckMgr::LoadWardenOverrides()
sLog->outError("Warden check action override for non-existing check (ID: %u, action: %u), skipped", checkId, action);
else
{
CheckStore[checkId]->Action = WardenActions(action);
CheckStore.at(checkId).Action = WardenActions(action);
++count;
}
} while (result->NextRow());
@@ -190,18 +220,22 @@ void WardenCheckMgr::LoadWardenOverrides()
sLog->outString();
}
WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 Id)
WardenCheck const* WardenCheckMgr::GetWardenDataById(uint16 Id)
{
if (Id < CheckStore.size())
return CheckStore[Id];
return &CheckStore.at(Id);
return nullptr;
}
WardenCheckResult* WardenCheckMgr::GetWardenResultById(uint16 Id)
WardenCheckResult const* WardenCheckMgr::GetWardenResultById(uint16 Id)
{
CheckResultContainer::const_iterator itr = CheckResultStore.find(Id);
if (itr != CheckResultStore.end())
return itr->second;
{
return &itr->second;
}
return nullptr;
}

View File

@@ -12,11 +12,22 @@
enum WardenActions
{
WARDEN_ACTION_LOG,
WARDEN_ACTION_KICK,
WARDEN_ACTION_BAN
WARDEN_ACTION_LOG = 0,
WARDEN_ACTION_KICK = 1,
WARDEN_ACTION_BAN = 2,
};
constexpr uint8 MAX_WARDEN_ACTION = 3;
enum WardenCheckTypes
{
WARDEN_CHECK_MEM_TYPE = 0,
WARDEN_CHECK_LUA_TYPE = 1,
WARDEN_CHECK_OTHER_TYPE = 2,
};
constexpr uint8 MAX_WARDEN_CHECK_TYPES = 3;
struct WardenCheck
{
uint8 Type;
@@ -26,9 +37,12 @@ struct WardenCheck
std::string Str; // LUA, MPQ, DRIVER
std::string Comment;
uint16 CheckId;
enum WardenActions Action;
std::array<char, 4> IdStr = {}; // LUA
uint32 Action;
};
constexpr uint8 WARDEN_MAX_LUA_CHECK_LENGTH = 170;
struct WardenCheckResult
{
BigNumber Result; // MEM_CHECK
@@ -43,23 +57,21 @@ 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;
typedef std::vector<WardenCheck> CheckContainer;
typedef std::map<uint32, WardenCheckResult> CheckResultContainer;
WardenCheck* GetWardenDataById(uint16 Id);
WardenCheckResult* GetWardenResultById(uint16 Id);
uint16 GetMaxValidCheckId() const { return static_cast<uint16>(CheckStore.size()); }
WardenCheck const* GetWardenDataById(uint16 Id);
WardenCheckResult const* GetWardenResultById(uint16 Id);
std::vector<uint16> MemChecksIdPool;
std::vector<uint16> OtherChecksIdPool;
std::vector<uint16> CheckIdPool[MAX_WARDEN_CHECK_TYPES];
void LoadWardenChecks();
void LoadWardenOverrides();
ACE_RW_Mutex _checkStoreLock;
private:
CheckContainer CheckStore;
CheckResultContainer CheckResultStore;
std::vector<WardenCheck> CheckStore;
std::map<uint32, WardenCheckResult> CheckResultStore;
};
#define sWardenCheckMgr WardenCheckMgr::instance()

View File

@@ -166,7 +166,7 @@ void WardenMac::HandleHashResult(ByteBuffer& buff)
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Request hash reply: failed");
#endif
Penalty();
ApplyPenalty(0, "Request hash reply: failed");
return;
}
@@ -188,11 +188,9 @@ void WardenMac::HandleHashResult(ByteBuffer& buff)
_outputCrypto.Init(_outputKey);
_initialized = true;
_previousTimestamp = World::GetGameTimeMS();
}
void WardenMac::RequestData()
void WardenMac::RequestChecks()
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Request data");

View File

@@ -27,7 +27,7 @@ public:
void InitializeModule() override;
void RequestHash() override;
void HandleHashResult(ByteBuffer& buff) override;
void RequestData() override;
void RequestChecks() override;
void HandleData(ByteBuffer& buff) override;
};

View File

@@ -22,23 +22,72 @@
#include "WardenCheckMgr.h"
#include "AccountMgr.h"
// GUILD is the shortest string that has no client validation (RAID only sends if in a raid group)
static constexpr char _luaEvalPrefix[] = "local S,T,R=SendAddonMessage,function()";
static constexpr char _luaEvalMidfix[] = " end R=S and T()if R then S('_TW',";
static constexpr char _luaEvalPostfix[] = ",'GUILD')end";
static_assert((sizeof(_luaEvalPrefix)-1 + sizeof(_luaEvalMidfix)-1 + sizeof(_luaEvalPostfix)-1 + WARDEN_MAX_LUA_CHECK_LENGTH) == 255);
static constexpr uint8 GetCheckPacketBaseSize(uint8 type)
{
switch (type)
{
case DRIVER_CHECK:
case MPQ_CHECK: return 1;
case LUA_EVAL_CHECK: return 1 + sizeof(_luaEvalPrefix) - 1 + sizeof(_luaEvalMidfix) - 1 + 4 + sizeof(_luaEvalPostfix) - 1;
case PAGE_CHECK_A: return (4 + 1);
case PAGE_CHECK_B: return (4 + 1);
case MODULE_CHECK: return (4 + SHA_DIGEST_LENGTH);
case MEM_CHECK: return (1 + 4 + 1);
default: return 0;
}
}
static uint16 GetCheckPacketSize(WardenCheck const* check)
{
if (!check)
{
return 0;
}
uint16 size = 1 + GetCheckPacketBaseSize(check->Type); // 1 byte check type
if (!check->Str.empty())
{
size += (static_cast<uint16>(check->Str.length()) + 1); // 1 byte string length
}
BigNumber tempNumber = check->Data;
if (!tempNumber.GetNumBytes())
{
size += tempNumber.GetNumBytes();
}
return size;
}
// Returns config id for specific type id
static WorldIntConfigs GetMaxWardenChecksForType(uint8 type)
{
// Should never be higher type than defined
ASSERT(type < MAX_WARDEN_CHECK_TYPES);
switch (type)
{
case WARDEN_CHECK_MEM_TYPE:
return CONFIG_WARDEN_NUM_MEM_CHECKS;
case WARDEN_CHECK_LUA_TYPE:
return CONFIG_WARDEN_NUM_LUA_CHECKS;
default:
break;
}
return CONFIG_WARDEN_NUM_OTHER_CHECKS;
}
WardenWin::WardenWin() : Warden(), _serverTicks(0) { }
WardenWin::~WardenWin()
{
// Xinef: ZOMG! CRASH DEBUG INFO
uint32 otherSize = _otherChecksTodo.size();
uint32 memSize = _memChecksTodo.size();
uint32 curSize = _currentChecks.size();
bool otherClear = _otherChecksTodo.empty();
bool memClear = _memChecksTodo.empty();
bool curClear = _currentChecks.empty();
sLog->outDebug(LOG_FILTER_POOLSYS, "IM DESTRUCTING MYSELF QQ, OTHERSIZE: %u, OTHEREM: %u, MEMSIZE: %u, MEMEM: %u, CURSIZE: %u, CUREM: %u!\n", otherSize, otherClear, memSize, memClear, curSize, curClear);
_otherChecksTodo.clear();
_memChecksTodo.clear();
_currentChecks.clear();
sLog->outDebug(LOG_FILTER_POOLSYS, "IM DESTRUCTING MYSELF QQ, OTHERSIZE: %u, OTHEREM: %u, MEMSIZE: %u, MEMEM: %u, CURSIZE: %u, CUREM: %u!\n", otherSize, otherClear, memSize, memClear, curSize, curClear);
}
void WardenWin::Init(WorldSession* session, BigNumber* k)
@@ -109,16 +158,16 @@ void WardenWin::InitializeModule()
Request.Function1[1] = 0x000218C0; // 0x00400000 + 0x000218C0 SFileGetFileSize
Request.Function1[2] = 0x00022530; // 0x00400000 + 0x00022530 SFileReadFile
Request.Function1[3] = 0x00022910; // 0x00400000 + 0x00022910 SFileCloseFile
Request.CheckSumm1 = BuildChecksum(&Request.Unk1, 20);
Request.CheckSumm1 = BuildChecksum(&Request.Unk1, SHA_DIGEST_LENGTH);
Request.Command2 = WARDEN_SMSG_MODULE_INITIALIZE;
Request.Size2 = 8;
Request.Unk3 = 4;
Request.Unk4 = 0;
Request.String_library2 = 0;
Request.Function2 = 0x00419D40; // 0x00400000 + 0x00419D40 FrameScript::GetText
Request.Function2 = 0x00419210; // 0x00400000 + 0x00419210 FrameScript::Execute
Request.Function2_set = 1;
Request.CheckSumm2 = BuildChecksum(&Request.Unk2, 8);
Request.CheckSumm2 = BuildChecksum(&Request.Unk3, 8);
Request.Command3 = WARDEN_SMSG_MODULE_INITIALIZE;
Request.Size3 = 8;
@@ -129,11 +178,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_WARDEN_DATA, sizeof(WardenInitModuleRequest));
pkt.append((uint8*)&Request, sizeof(WardenInitModuleRequest));
pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenInitModuleRequest));
_session->SendPacket(&pkt);
}
@@ -149,10 +211,10 @@ void WardenWin::RequestHash()
memcpy(Request.Seed, _seed, 16);
// Encrypt with warden RC4 key.
EncryptData((uint8*)&Request, sizeof(WardenHashRequest));
EncryptData(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest));
WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenHashRequest));
pkt.append((uint8*)&Request, sizeof(WardenHashRequest));
pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest));
_session->SendPacket(&pkt);
}
@@ -161,12 +223,12 @@ void WardenWin::HandleHashResult(ByteBuffer& buff)
buff.rpos(buff.wpos());
// Verify key
if (memcmp(buff.contents() + 1, Module.ClientKeySeedHash, 20) != 0)
if (memcmp(buff.contents() + 1, Module.ClientKeySeedHash, SHA_DIGEST_LENGTH) != 0)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Request hash reply: failed");
#endif
Penalty();
ApplyPenalty(0, "Request hash reply: failed");
return;
}
@@ -182,83 +244,135 @@ void WardenWin::HandleHashResult(ByteBuffer& buff)
_outputCrypto.Init(_outputKey);
_initialized = true;
_previousTimestamp = World::GetGameTimeMS();
}
void WardenWin::RequestData()
void WardenWin::RequestChecks()
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Request data");
#endif
// If all checks were done, fill the todo list again
if (_memChecksTodo.empty())
_memChecksTodo.assign(sWardenCheckMgr->MemChecksIdPool.begin(), sWardenCheckMgr->MemChecksIdPool.end());
if (_otherChecksTodo.empty())
_otherChecksTodo.assign(sWardenCheckMgr->OtherChecksIdPool.begin(), sWardenCheckMgr->OtherChecksIdPool.end());
for (uint8 i = 0; i < MAX_WARDEN_CHECK_TYPES; ++i)
{
if (_ChecksTodo[i].empty())
_ChecksTodo[i].assign(sWardenCheckMgr->CheckIdPool[i].begin(), sWardenCheckMgr->CheckIdPool[i].end());
}
_serverTicks = World::GetGameTimeMS();
_CurrentChecks.clear();
uint16 id;
uint8 type;
WardenCheck* wd;
_currentChecks.clear();
// Build check request
for (uint32 i = 0; i < sWorld->getIntConfig(CONFIG_WARDEN_NUM_MEM_CHECKS); ++i)
// No pending checks
if (_PendingChecks.empty())
{
// If todo list is done break loop (will be filled on next Update() run)
if (_memChecksTodo.empty())
break;
for (uint8 checkType = 0; checkType < MAX_WARDEN_CHECK_TYPES; ++checkType)
{
for (uint32 y = 0; y < sWorld->getIntConfig(GetMaxWardenChecksForType(checkType)); ++y)
{
// If todo list is done break loop (will be filled on next Update() run)
if (_ChecksTodo[checkType].empty())
{
break;
}
// Get check id from the end and remove it from todo
id = _memChecksTodo.back();
_memChecksTodo.pop_back();
// Get check id from the end and remove it from todo
uint16 const id = _ChecksTodo[checkType].back();
_ChecksTodo[checkType].pop_back();
// Add the id to the list sent in this cycle
if (id != 786 /*WPE PRO*/ && id != 209 /*WoWEmuHacker*/)
_currentChecks.push_back(id);
// Insert check to queue
if (checkType == WARDEN_CHECK_LUA_TYPE)
{
_CurrentChecks.push_front(id);
}
else
{
_CurrentChecks.push_back(id);
}
}
}
}
_currentChecks.push_back(786);
_currentChecks.push_back(209);
else
{
bool hasLuaChecks = false;
for (uint16 const checkId : _PendingChecks)
{
WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(checkId);
if (!hasLuaChecks && check->Type == LUA_EVAL_CHECK)
{
hasLuaChecks = true;
}
_CurrentChecks.push_back(checkId);
}
// Always include lua checks
if (!hasLuaChecks)
{
for (uint32 i = 0; i < sWorld->getIntConfig(GetMaxWardenChecksForType(WARDEN_CHECK_LUA_TYPE)); ++i)
{
// If todo list is done break loop (will be filled on next Update() run)
if (_ChecksTodo[WARDEN_CHECK_LUA_TYPE].empty())
{
break;
}
// Get check id from the end and remove it from todo
uint16 const id = _ChecksTodo[WARDEN_CHECK_LUA_TYPE].back();
_ChecksTodo[WARDEN_CHECK_LUA_TYPE].pop_back();
// Lua checks must be always in front
_CurrentChecks.push_front(id);
}
}
}
// Filter too high checks queue
// Filtered checks will get passed in next checks
uint16 expectedSize = 4;
_PendingChecks.clear();
acore::Containers::EraseIf(_CurrentChecks,
[this, &expectedSize](uint16 id)
{
uint16 const thisSize = GetCheckPacketSize(sWardenCheckMgr->GetWardenDataById(id));
if ((expectedSize + thisSize) > 500) // warden packets are truncated to 512 bytes clientside
{
_PendingChecks.push_back(id);
return true;
}
expectedSize += thisSize;
return false;
}
);
ByteBuffer buff;
buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST);
ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock);
for (uint32 i = 0; i < sWorld->getIntConfig(CONFIG_WARDEN_NUM_OTHER_CHECKS); ++i)
for (uint16 const checkId : _CurrentChecks)
{
// If todo list is done break loop (will be filled on next Update() run)
if (_otherChecksTodo.empty())
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);
wd = sWardenCheckMgr->GetWardenDataById(id);
if (wd)
switch (wd->Type)
WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(checkId);
switch (check->Type)
{
case LUA_EVAL_CHECK:
{
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(sizeof(_luaEvalPrefix) - 1 + check->Str.size() + sizeof(_luaEvalMidfix) - 1 + check->IdStr.size() + sizeof(_luaEvalPostfix) - 1);
buff.append(_luaEvalPrefix, sizeof(_luaEvalPrefix) - 1);
buff.append(check->Str.data(), check->Str.size());
buff.append(_luaEvalMidfix, sizeof(_luaEvalMidfix) - 1);
buff.append(check->IdStr.data(), check->IdStr.size());
buff.append(_luaEvalPostfix, sizeof(_luaEvalPostfix) - 1);
break;
}
case MPQ_CHECK:
case DRIVER_CHECK:
{
buff << uint8(check->Str.size());
buff.append(check->Str.c_str(), check->Str.size());
break;
}
}
}
uint8 xorByte = _inputKey[0];
uint8 const xorByte = _inputKey[0];
// Add TIMING_CHECK
buff << uint8(0x00);
@@ -266,51 +380,51 @@ void WardenWin::RequestData()
uint8 index = 1;
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
for (uint16 const checkId : _CurrentChecks)
{
wd = sWardenCheckMgr->GetWardenDataById(*itr);
type = wd->Type;
buff << uint8(type ^ xorByte);
switch (type)
WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(checkId);
buff << uint8(check->Type ^ xorByte);
switch (check->Type)
{
case MEM_CHECK:
{
buff << uint8(0x00);
buff << uint32(wd->Address);
buff << uint8(wd->Length);
break;
}
{
buff << uint8(0x00);
buff << uint32(check->Address);
buff << uint8(check->Length);
break;
}
case PAGE_CHECK_A:
case PAGE_CHECK_B:
{
buff.append(wd->Data.AsByteArray(0, false).get(), wd->Data.GetNumBytes());
buff << uint32(wd->Address);
buff << uint8(wd->Length);
break;
}
{
BigNumber tempNumber = check->Data;
buff.append(tempNumber.AsByteArray(0, false).get(), tempNumber.GetNumBytes());
buff << uint32(check->Address);
buff << uint8(check->Length);
break;
}
case MPQ_CHECK:
case LUA_STR_CHECK:
{
buff << uint8(index++);
break;
}
case LUA_EVAL_CHECK:
{
buff << uint8(index++);
break;
}
case DRIVER_CHECK:
{
buff.append(wd->Data.AsByteArray(0, false).get(), wd->Data.GetNumBytes());
buff << uint8(index++);
break;
}
{
BigNumber tempNumber = check->Data;
buff.append(tempNumber.AsByteArray(0, false).get(), tempNumber.GetNumBytes());
buff << uint8(index++);
break;
}
case MODULE_CHECK:
{
uint32 seed = rand32();
buff << uint32(seed);
HmacHash hmac(4, (uint8*)&seed);
hmac.UpdateData(wd->Str);
hmac.Finalize();
buff.append(hmac.GetDigest(), hmac.GetLength());
break;
}
{
uint32 seed = rand32();
buff << uint32(seed);
HmacHash hmac(4, (uint8*)&seed);
hmac.UpdateData(check->Str);
hmac.Finalize();
buff.append(hmac.GetDigest(), hmac.GetLength());
break;
}
/*case PROC_CHECK:
{
buff.append(wd->i.AsByteArray(0, false).get(), wd->i.GetNumBytes());
@@ -320,8 +434,6 @@ void WardenWin::RequestData()
buff << uint8(wd->Length);
break;
}*/
default:
break; // Should never happen
}
}
buff << uint8(xorByte);
@@ -336,12 +448,14 @@ void WardenWin::RequestData()
_dataSent = true;
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
std::stringstream stream;
stream << "Sent check id's: ";
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
stream << *itr << " ";
for (uint16 checkId : _currentChecks)
{
stream << checkId << " ";
}
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "%s", stream.str().c_str());
#endif
}
@@ -360,13 +474,20 @@ void WardenWin::HandleData(ByteBuffer& buff)
uint32 Checksum;
buff >> Checksum;
if (Length != (buff.size() - buff.rpos()))
{
buff.rfinish();
ApplyPenalty(0, "Failed size checks in HandleData");
return;
}
if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length))
{
buff.rpos(buff.wpos());
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "CHECKSUM FAIL");
#endif
Penalty();
ApplyPenalty(0, "Failed checksum in HandleData");
return;
}
@@ -380,7 +501,7 @@ void WardenWin::HandleData(ByteBuffer& buff)
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "TIMING CHECK FAIL result 0x00");
#endif
Penalty();
ApplyPenalty(0, "TIMING CHECK FAIL result");
return;
}
@@ -398,51 +519,46 @@ void WardenWin::HandleData(ByteBuffer& buff)
#endif
}
WardenCheckResult* rs;
WardenCheck* rd;
uint8 type;
uint16 checkFailed = 0;
ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock);
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
for (uint16 const checkId : _CurrentChecks)
{
rd = sWardenCheckMgr->GetWardenDataById(*itr);
rs = sWardenCheckMgr->GetWardenResultById(*itr);
type = rd->Type;
WardenCheck const* rd = sWardenCheckMgr->GetWardenDataById(checkId);
uint8 const type = rd->Type;
switch (type)
{
case MEM_CHECK:
{
uint8 Mem_Result;
buff >> Mem_Result;
if (Mem_Result != 0)
{
uint8 Mem_Result;
buff >> Mem_Result;
if (Mem_Result != 0)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MEM_CHECK not 0x00, CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MEM_CHECK not 0x00, CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif
checkFailed = *itr;
continue;
}
if (memcmp(buff.contents() + buff.rpos(), rs->Result.AsByteArray(0, false).get(), rd->Length) != 0)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MEM_CHECK fail CheckId %u account Id %u", *itr, _session->GetAccountId());
#endif
checkFailed = *itr;
buff.rpos(buff.rpos() + rd->Length);
continue;
}
buff.rpos(buff.rpos() + rd->Length);
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MEM_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId());
#endif
break;
checkFailed = checkId;
continue;
}
WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
BigNumber tempNumber = rs->Result;
if (memcmp(buff.contents() + buff.rpos(), tempNumber.AsByteArray(0, false).get(), rd->Length) != 0)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MEM_CHECK fail CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif
checkFailed = checkId;
buff.rpos(buff.rpos() + rd->Length);
continue;
}
buff.rpos(buff.rpos() + rd->Length);
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MEM_CHECK passed CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif
break;
}
case PAGE_CHECK_A:
case PAGE_CHECK_B:
case DRIVER_CHECK:
@@ -453,15 +569,15 @@ void WardenWin::HandleData(ByteBuffer& buff)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT PAGE_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT PAGE_CHECK fail, CheckId %u account Id %u", checkId, _session->GetAccountId());
if (type == MODULE_CHECK)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MODULE_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MODULE_CHECK fail, CheckId %u account Id %u", checkId, _session->GetAccountId());
if (type == DRIVER_CHECK)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT DRIVER_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT DRIVER_CHECK fail, CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif
checkFailed = *itr;
checkFailed = checkId;
buff.rpos(buff.rpos() + 1);
continue;
}
@@ -470,44 +586,24 @@ void WardenWin::HandleData(ByteBuffer& buff)
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT PAGE_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT PAGE_CHECK passed CheckId %u account Id %u", checkId, _session->GetAccountId());
else if (type == MODULE_CHECK)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MODULE_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MODULE_CHECK passed CheckId %u account Id %u", checkId, _session->GetAccountId());
else if (type == DRIVER_CHECK)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT DRIVER_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT DRIVER_CHECK passed CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif
break;
}
case LUA_STR_CHECK:
break;
}
case LUA_EVAL_CHECK:
{
uint8 const result = buff.read<uint8>();
if (result == 0)
{
uint8 Lua_Result;
buff >> Lua_Result;
buff.read_skip(buff.read<uint8>()); // discard attached string
}
if (Lua_Result != 0)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT LUA_STR_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
#endif
checkFailed = *itr;
continue;
}
uint8 luaStrLen;
buff >> luaStrLen;
if (luaStrLen != 0)
{
char* str = new char[luaStrLen + 1];
memcpy(str, buff.contents() + buff.rpos(), luaStrLen);
str[luaStrLen] = '\0'; // null terminator
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Lua string: %s", str);
#endif
delete[] str;
}
buff.rpos(buff.rpos() + luaStrLen); // Skip string
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT LUA_STR_CHECK passed, CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "LUA_EVAL_CHECK CheckId %u account Id %u got in-warden dummy response", checkId, _session->GetAccountId()/* , result */);
#endif
break;
}
@@ -521,38 +617,37 @@ void WardenWin::HandleData(ByteBuffer& buff)
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK not 0x00 account id %u", _session->GetAccountId());
#endif
checkFailed = *itr;
checkFailed = checkId;
continue;
}
if (memcmp(buff.contents() + buff.rpos(), rs->Result.AsByteArray(0, false).get(), 20) != 0) // SHA1
WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
BigNumber tempNumber = rs->Result;
if (memcmp(buff.contents() + buff.rpos(), tempNumber.AsByteArray(0, false).get(), SHA_DIGEST_LENGTH) != 0) // SHA1
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK fail, CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif
checkFailed = *itr;
buff.rpos(buff.rpos() + 20); // 20 bytes SHA1
checkFailed = checkId;
buff.rpos(buff.rpos() + SHA_DIGEST_LENGTH); // 20 bytes SHA1
continue;
}
buff.rpos(buff.rpos() + 20); // 20 bytes SHA1
buff.rpos(buff.rpos() + SHA_DIGEST_LENGTH); // 20 bytes SHA1
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK passed, CheckId %u account Id %u", *itr, _session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK passed, CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif
break;
}
default: // Should never happen
break;
}
}
if (checkFailed > 0)
{
WardenCheck* check = sWardenCheckMgr->GetWardenDataById(checkFailed);
Penalty(check, checkFailed);
ApplyPenalty(checkFailed, "");
}
// Set hold off timer, minimum timer should at least be 1 second
uint32 holdOff = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF);
uint32 const holdOff = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF);
_checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS;
}

View File

@@ -69,14 +69,15 @@ public:
void InitializeModule() override;
void RequestHash() override;
void HandleHashResult(ByteBuffer& buff) override;
void RequestData() override;
void RequestChecks() override;
void HandleData(ByteBuffer& buff) override;
private:
uint32 _serverTicks;
std::list<uint16> _otherChecksTodo;
std::list<uint16> _memChecksTodo;
std::list<uint16> _currentChecks;
std::list<uint16> _ChecksTodo[MAX_WARDEN_CHECK_TYPES];
std::list<uint16> _CurrentChecks;
std::list<uint16> _PendingChecks;
};
#endif
#endif // _WARDEN_WIN_H

View File

@@ -340,6 +340,7 @@ enum WorldIntConfigs
CONFIG_WARDEN_CLIENT_FAIL_ACTION,
CONFIG_WARDEN_CLIENT_BAN_DURATION,
CONFIG_WARDEN_NUM_MEM_CHECKS,
CONFIG_WARDEN_NUM_LUA_CHECKS,
CONFIG_WARDEN_NUM_OTHER_CHECKS,
CONFIG_BIRTHDAY_TIME,
CONFIG_SOCKET_TIMEOUTTIME_ACTIVE,

View File

@@ -1315,6 +1315,7 @@ void World::LoadConfigSettings(bool reload)
// Warden
m_bool_configs[CONFIG_WARDEN_ENABLED] = sConfigMgr->GetBoolDefault("Warden.Enabled", false);
m_int_configs[CONFIG_WARDEN_NUM_MEM_CHECKS] = sConfigMgr->GetIntDefault("Warden.NumMemChecks", 3);
m_int_configs[CONFIG_WARDEN_NUM_LUA_CHECKS] = sConfigMgr->GetIntDefault("Warden.NumLuaChecks", 1);
m_int_configs[CONFIG_WARDEN_NUM_OTHER_CHECKS] = sConfigMgr->GetIntDefault("Warden.NumOtherChecks", 7);
m_int_configs[CONFIG_WARDEN_CLIENT_BAN_DURATION] = sConfigMgr->GetIntDefault("Warden.BanDuration", 86400);
m_int_configs[CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF] = sConfigMgr->GetIntDefault("Warden.ClientCheckHoldOff", 30);

View File

@@ -1590,7 +1590,7 @@ IsPreloadedContinentTransport.Enabled = 0
# Default: 0 - (Disabled)
# 1 - (Enabled)
Warden.Enabled = 1
Warden.Enabled = 0
#
# Warden.NumMemChecks
@@ -1598,7 +1598,15 @@ Warden.Enabled = 1
# Default: 3 - (Enabled)
# 0 - (Disabled)
Warden.NumMemChecks = 2
Warden.NumMemChecks = 3
#
# Warden.NumLuaChecks
# Description: Number of Warden LUA checks that are sent to the client each cycle.
# Default: 1 - (Enabled)
# 0 - (Disabled)
Warden.NumLuaChecks = 1
#
# Warden.NumOtherChecks
@@ -1607,7 +1615,7 @@ Warden.NumMemChecks = 2
# Default: 7 - (Enabled)
# 0 - (Disabled)
Warden.NumOtherChecks = 5
Warden.NumOtherChecks = 7
#
# Warden.LogFile
@@ -1644,7 +1652,7 @@ Warden.ClientCheckHoldOff = 30
# 1 - (Kick)
# 2 - (Ban)
Warden.ClientCheckFailAction = 2
Warden.ClientCheckFailAction = 0
#
# Warden.BanDuration