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.cpp560
1 files changed, 0 insertions, 560 deletions
diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp
deleted file mode 100644
index 92266e20830..00000000000
--- a/src/server/game/Warden/WardenWin.cpp
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * 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 "WardenWin.h"
-#include "Common.h"
-#include "ByteBuffer.h"
-#include "Containers.h"
-#include "CryptoRandom.h"
-#include "DatabaseEnv.h"
-#include "GameTime.h"
-#include "HMAC.h"
-#include "Log.h"
-#include "Opcodes.h"
-#include "Player.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 <sstream>
-
- // 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);
-
-WardenWin::WardenWin() : Warden(), _serverTicks(0)
-{
- for (WardenCheckCategory category : EnumUtils::Iterate<WardenCheckCategory>())
- {
- auto& [checks, checksIt] = _checks[category];
- checks = sWardenCheckMgr->GetAvailableChecks(category);
- Trinity::Containers::RandomShuffle(checks);
- checksIt = checks.begin();
- }
-}
-
-void WardenWin::Init(WorldSession* session, SessionKey const& K)
-{
- _session = session;
- // Generate Warden Key
- SessionKeyGenerator<Trinity::Crypto::SHA1> WK(K);
- WK.Generate(_inputKey.data(), _inputKey.size());
- WK.Generate(_outputKey.data(), _outputKey.size());
-
- _seed = Module.Seed;
-
- _inputCrypto.Init(_inputKey);
- _outputCrypto.Init(_outputKey);
- TC_LOG_DEBUG("warden", "Server side warden for client {} initializing...", session->GetAccountId());
- TC_LOG_DEBUG("warden", "C->S Key: {}", ByteArrayToHexStr(_inputKey));
- TC_LOG_DEBUG("warden", "S->C Key: {}", ByteArrayToHexStr(_outputKey));
- TC_LOG_DEBUG("warden", " Seed: {}", ByteArrayToHexStr(_seed));
- TC_LOG_DEBUG("warden", "Loading Module...");
-
- MakeModuleForClient();
-
- TC_LOG_DEBUG("warden", "Module Key: {}", ByteArrayToHexStr(_module->Key));
- TC_LOG_DEBUG("warden", "Module ID: {}", ByteArrayToHexStr(_module->Id));
- RequestModule();
-}
-
-void WardenWin::InitializeModuleForClient(ClientWardenModule& module)
-{
- // data assign
- module.CompressedData = Module.Module.data();
- module.CompressedSize = Module.Module.size();
- module.Key = Module.ModuleKey;
-}
-
-void WardenWin::InitializeModule()
-{
- TC_LOG_DEBUG("warden", "Initialize module");
-
- // Create packet structure
- WardenInitModuleRequest Request;
- Request.Command1 = WARDEN_SMSG_MODULE_INITIALIZE;
- Request.Size1 = 20;
- Request.Unk1 = 1;
- Request.Unk2 = 0;
- Request.Type = 1;
- Request.String_library1 = 0;
- Request.Function1[0] = 0x00024F80; // 0x00400000 + 0x00024F80 SFileOpenFile
- 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.Command2 = WARDEN_SMSG_MODULE_INITIALIZE;
- Request.Size2 = 8;
- Request.Unk3 = 4;
- Request.Unk4 = 0;
- Request.String_library2 = 0;
- Request.Function2 = 0x00419210; // 0x00400000 + 0x00419210 FrameScript::Execute
- Request.Function2_set = 1;
- Request.CheckSumm2 = BuildChecksum(&Request.Unk3, 8);
-
- Request.Command3 = WARDEN_SMSG_MODULE_INITIALIZE;
- Request.Size3 = 8;
- Request.Unk5 = 1;
- Request.Unk6 = 1;
- Request.String_library3 = 0;
- Request.Function3 = 0x0046AE20; // 0x00400000 + 0x0046AE20 PerformanceCounter
- 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(reinterpret_cast<uint8*>(&Request), sizeof(WardenInitModuleRequest));
-
- WorldPacket pkt(SMSG_WARDEN3_DATA, sizeof(WardenInitModuleRequest));
- pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenInitModuleRequest));
- _session->SendPacket(&pkt);
-}
-
-void WardenWin::RequestHash()
-{
- TC_LOG_DEBUG("warden", "Request hash");
-
- // Create packet structure
- WardenHashRequest Request;
- Request.Command = WARDEN_SMSG_HASH_REQUEST;
- Request.Seed = _seed;
-
- // Encrypt with warden RC4 key.
- EncryptData(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest));
-
- WorldPacket pkt(SMSG_WARDEN3_DATA, sizeof(WardenHashRequest));
- pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest));
- _session->SendPacket(&pkt);
-}
-
-void WardenWin::HandleHashResult(ByteBuffer &buff)
-{
- // Verify key
- Trinity::Crypto::SHA1::Digest response;
- buff.read(response);
- if (response != Module.ClientKeySeedHash)
- {
- char const* penalty = ApplyPenalty(nullptr);
- TC_LOG_WARN("warden", "{} failed hash reply. Action: {}", _session->GetPlayerInfo(), penalty);
- return;
- }
-
- TC_LOG_DEBUG("warden", "Request hash reply: succeed");
-
- // Change keys here
- _inputKey = Module.ClientKeySeed;
- _outputKey = Module.ServerKeySeed;
-
- _inputCrypto.Init(_inputKey);
- _outputCrypto.Init(_outputKey);
-
- _initialized = true;
-}
-
-static constexpr uint8 GetCheckPacketBaseSize(WardenCheckType type)
-{
- switch (type)
- {
- case DRIVER_CHECK: return 1;
- case LUA_EVAL_CHECK: return 1 + sizeof(_luaEvalPrefix)-1 + sizeof(_luaEvalMidfix)-1 + 4 + sizeof(_luaEvalPostfix)-1;
- case MPQ_CHECK: return 1;
- case PAGE_CHECK_A: return (4 + 1);
- case PAGE_CHECK_B: return (4 + 1);
- case MODULE_CHECK: return (4 + Trinity::Crypto::HMAC_SHA1::DIGEST_LENGTH);
- case MEM_CHECK: return (1 + 4 + 1);
- default: return 0;
- }
-}
-
-static uint16 GetCheckPacketSize(WardenCheck const& check)
-{
- uint16 size = 1 + GetCheckPacketBaseSize(check.Type); // 1 byte check type
- if (!check.Str.empty())
- size += (check.Str.length() + 1); // 1 byte string length
- if (!check.Data.empty())
- size += check.Data.size();
- return size;
-}
-
-void WardenWin::RequestChecks()
-{
- TC_LOG_DEBUG("warden", "Request data from {} (account {}) - loaded: {}", _session->GetPlayerName(), _session->GetAccountId(), _session->GetPlayer() && !_session->PlayerLoading());
-
- // If all checks for a category are done, fill its todo list again
- for (WardenCheckCategory category : EnumUtils::Iterate<WardenCheckCategory>())
- {
- auto& [checks, checksIt] = _checks[category];
- if ((checksIt == checks.end()) && !checks.empty())
- {
- TC_LOG_DEBUG("warden", "Finished all {} checks, re-shuffling", EnumUtils::ToConstant(category));
- Trinity::Containers::RandomShuffle(checks);
- checksIt = checks.begin();
- }
- }
-
- _serverTicks = GameTime::GetGameTimeMS();
- _currentChecks.clear();
-
- // Build check request
- ByteBuffer buff;
- buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST);
-
- for (WardenCheckCategory category : EnumUtils::Iterate<WardenCheckCategory>())
- {
- if (IsWardenCategoryInWorldOnly(category) && !_session->GetPlayer())
- continue;
-
- auto& [checks, checksIt] = _checks[category];
- for (uint32 i = 0, n = sWorld->getIntConfig(GetWardenCategoryCountConfig(category)); i < n; ++i)
- {
- if (checksIt == checks.end()) // all checks were already sent, list will be re-filled on next Update() run
- break;
- _currentChecks.push_back(*(checksIt++));
- }
- }
-
- Trinity::Containers::RandomShuffle(_currentChecks);
-
- uint16 expectedSize = 4;
- Trinity::Containers::EraseIf(_currentChecks,
- [&expectedSize](uint16 id)
- {
- uint8 const thisSize = GetCheckPacketSize(sWardenCheckMgr->GetCheckData(id));
- if ((expectedSize + thisSize) > 450) // warden packets are truncated to 512 bytes clientside
- return true;
- expectedSize += thisSize;
- return false;
- }
- );
-
- for (uint16 const id : _currentChecks)
- {
- WardenCheck const& check = sWardenCheckMgr->GetCheckData(id);
- if (check.Type == LUA_EVAL_CHECK)
- {
- 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);
- }
- else if (!check.Str.empty())
- {
- buff << uint8(check.Str.size());
- buff.append(check.Str.data(), check.Str.size());
- }
- }
-
- uint8 xorByte = _inputKey[0];
-
- // Add TIMING_CHECK
- buff << uint8(0x00);
- buff << uint8(TIMING_CHECK ^ xorByte);
-
- uint8 index = 1;
-
- for (uint16 const id : _currentChecks)
- {
- WardenCheck const& check = sWardenCheckMgr->GetCheckData(id);
-
- WardenCheckType const type = check.Type;
- buff << uint8(type ^ xorByte);
- switch (type)
- {
- case MEM_CHECK:
- {
- buff << uint8(0x00);
- buff << uint32(check.Address);
- buff << uint8(sWardenCheckMgr->GetCheckResult(id).size());
- break;
- }
- case PAGE_CHECK_A:
- case PAGE_CHECK_B:
- {
- buff.append(check.Data.data(), check.Data.size());
- buff << uint32(check.Address);
- buff << uint8(check.Length);
- break;
- }
- case MPQ_CHECK:
- case LUA_EVAL_CHECK:
- {
- buff << uint8(index++);
- break;
- }
- case DRIVER_CHECK:
- {
- buff.append(check.Data.data(), check.Data.size());
- buff << uint8(index++);
- break;
- }
- case MODULE_CHECK:
- {
- std::array<uint8, 4> seed = Trinity::Crypto::GetRandomBytes<4>();
- buff.append(seed);
- buff.append(Trinity::Crypto::HMAC_SHA1::GetDigestOf(seed, check.Str));
- break;
- }
- /*case PROC_CHECK:
- {
- buff.append(check->i.AsByteArray(0, false).get(), check->i.GetNumBytes());
- buff << uint8(index++);
- buff << uint8(index++);
- buff << uint32(check->Address);
- buff << uint8(check->Length);
- break;
- }*/
- default:
- break; // Should never happen
- }
- }
- buff << uint8(xorByte);
- buff.hexlike();
-
- auto idstring = [this]() -> std::string
- {
- std::stringstream stream;
- for (uint16 const id : _currentChecks)
- stream << id << " ";
- return stream.str();
- };
-
- if (buff.size() == expectedSize)
- {
- TC_LOG_DEBUG("warden", "Finished building warden packet, size is {} bytes", buff.size());
- TC_LOG_DEBUG("warden", "Sent checks: {}", idstring());
- }
- else
- {
- TC_LOG_WARN("warden", "Finished building warden packet, size is {} bytes, but expected {} bytes!", buff.size(), expectedSize);
- TC_LOG_WARN("warden", "Sent checks: {}", idstring());
- }
-
- // Encrypt with warden RC4 key
- EncryptData(buff.data(), buff.size());
-
- WorldPacket pkt(SMSG_WARDEN3_DATA, buff.size());
- pkt.append(buff);
- _session->SendPacket(&pkt);
-
- _dataSent = true;
-}
-
-void WardenWin::HandleCheckResult(ByteBuffer &buff)
-{
- TC_LOG_DEBUG("warden", "Handle data");
-
- _dataSent = false;
- _clientResponseTimer = 0;
-
- uint16 Length;
- buff >> Length;
- uint32 Checksum;
- buff >> Checksum;
-
- if (Length != (buff.size() - buff.rpos()))
- {
- buff.rfinish();
- char const* penalty = ApplyPenalty(nullptr);
- TC_LOG_WARN("warden", "{} sends manipulated warden packet. Action: {}", _session->GetPlayerInfo(), penalty);
- return;
- }
-
- if (!IsValidCheckSum(Checksum, buff.data() + buff.rpos(), Length))
- {
- buff.rfinish();
- char const* penalty = ApplyPenalty(nullptr);
- TC_LOG_WARN("warden", "{} failed checksum. Action: {}", _session->GetPlayerInfo(), penalty);
- return;
- }
-
- // TIMING_CHECK
- {
- uint8 result;
- buff >> result;
- /// @todo test it.
- if (result == 0x00)
- {
- char const* penalty = ApplyPenalty(nullptr);
- TC_LOG_WARN("warden", "{} failed timing check. Action: {}", _session->GetPlayerInfo(), penalty);
- return;
- }
-
- uint32 newClientTicks;
- buff >> newClientTicks;
-
- uint32 ticksNow = GameTime::GetGameTimeMS();
- uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks);
-
- TC_LOG_DEBUG("warden", "Server tick count now: {}", ticksNow);
- TC_LOG_DEBUG("warden", "Server tick count at req: {}", _serverTicks);
- TC_LOG_DEBUG("warden", "Client ticks in response: {}", newClientTicks);
- TC_LOG_DEBUG("warden", "Round trip response time: {} ms", ourTicks - newClientTicks);
- }
-
- uint16 checkFailed = 0;
- for (uint16 const id : _currentChecks)
- {
- WardenCheck const& check = sWardenCheckMgr->GetCheckData(id);
-
- switch (check.Type)
- {
- case MEM_CHECK:
- {
- uint8 Mem_Result;
- buff >> Mem_Result;
-
- if (Mem_Result != 0)
- {
- TC_LOG_DEBUG("warden", "RESULT MEM_CHECK not 0x00, CheckId {} account Id {}", id, _session->GetAccountId());
- checkFailed = id;
- continue;
- }
-
- WardenCheckResult const& expected = sWardenCheckMgr->GetCheckResult(id);
-
- std::vector<uint8> response;
- response.resize(expected.size());
- buff.read(response.data(), response.size());
-
- if (response != expected)
- {
- TC_LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId {} account Id {}", id, _session->GetAccountId());
- TC_LOG_DEBUG("warden", "Expected: {}", ByteArrayToHexStr(expected));
- TC_LOG_DEBUG("warden", "Got: {}", ByteArrayToHexStr(response));
- checkFailed = id;
- continue;
- }
-
- TC_LOG_DEBUG("warden", "RESULT MEM_CHECK passed CheckId {} account Id {}", id, _session->GetAccountId());
- break;
- }
- case PAGE_CHECK_A:
- case PAGE_CHECK_B:
- case DRIVER_CHECK:
- case MODULE_CHECK:
- {
- if (buff.read<uint8>() != 0xE9)
- {
- TC_LOG_DEBUG("warden", "RESULT {} fail, CheckId {} account Id {}", EnumUtils::ToConstant(check.Type), id, _session->GetAccountId());
- checkFailed = id;
- continue;
- }
-
- TC_LOG_DEBUG("warden", "RESULT {} passed CheckId {} account Id {}", EnumUtils::ToConstant(check.Type), id, _session->GetAccountId());
- break;
- }
- case LUA_EVAL_CHECK:
- {
- uint8 const result = buff.read<uint8>();
- if (result == 0)
- buff.read_skip(buff.read<uint8>()); // discard attached string
-
- TC_LOG_DEBUG("warden", "LUA_EVAL_CHECK CheckId {} account Id {} got in-warden dummy response ({})", id, _session->GetAccountId(), result);
- break;
- }
- case MPQ_CHECK:
- {
- uint8 Mpq_Result;
- buff >> Mpq_Result;
-
- if (Mpq_Result != 0)
- {
- TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK not 0x00 account id {}", _session->GetAccountId());
- checkFailed = id;
- continue;
- }
-
- std::vector<uint8> result;
- result.resize(Trinity::Crypto::SHA1::DIGEST_LENGTH);
- buff.read(result.data(), result.size());
- if (result != sWardenCheckMgr->GetCheckResult(id)) // SHA1
- {
- TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId {} account Id {}", id, _session->GetAccountId());
- checkFailed = id;
- continue;
- }
-
- TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK passed, CheckId {} account Id {}", id, _session->GetAccountId());
- break;
- }
- default: // Should never happen
- break;
- }
- }
-
- if (checkFailed > 0)
- {
- WardenCheck const& check = sWardenCheckMgr->GetCheckData(checkFailed);
- char const* penalty = ApplyPenalty(&check);
- TC_LOG_WARN("warden", "{} failed Warden check {} ({}). Action: {}", _session->GetPlayerInfo(), checkFailed, EnumUtils::ToConstant(check.Type), penalty);
- }
-
- // Set hold off timer, minimum timer should at least be 1 second
- uint32 holdOff = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF);
- _checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS;
-}
-
-size_t WardenWin::DEBUG_ForceSpecificChecks(std::vector<uint16> const& checks)
-{
- std::array<std::vector<uint16>::iterator, NUM_CHECK_CATEGORIES> swapPositions;
- for (WardenCheckCategory category : EnumUtils::Iterate<WardenCheckCategory>())
- swapPositions[category] = _checks[category].first.begin();
-
- size_t n = 0;
- for (uint16 check : checks)
- {
- for (WardenCheckCategory category : EnumUtils::Iterate<WardenCheckCategory>())
- {
- std::vector<uint16>& checks = _checks[category].first;
- std::vector<uint16>::iterator& swapPos = swapPositions[category];
- if (auto it = std::find(swapPos, checks.end(), check); it != checks.end())
- {
- std::iter_swap(swapPos, it);
- ++swapPos;
- ++n;
- break;
- }
- }
- }
-
- for (WardenCheckCategory category : EnumUtils::Iterate<WardenCheckCategory>())
- _checks[category].second = _checks[category].first.begin();
-
- return n;
-}