AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
WardenWin Class Reference

#include "WardenWin.h"

Inheritance diagram for WardenWin:
Warden

Public Member Functions

 WardenWin ()
 
 ~WardenWin () override
 
void Init (WorldSession *session, SessionKey const &K) override
 
ClientWardenModuleGetModuleForClient () override
 
void InitializeModule () override
 
void RequestHash () override
 
void HandleHashResult (ByteBuffer &buff) override
 
void RequestChecks () override
 
bool IsCheckInProgress () override
 Gets the warden check state.
 
void ForceChecks () override
 Force call RequestChecks() so they are sent immediately, this interrupts warden and breaks result.
 
void HandleData (ByteBuffer &buff) override
 
- Public Member Functions inherited from Warden
 Warden ()
 
virtual ~Warden ()
 
virtual bool IsInitialized ()
 
bool ProcessLuaCheckResponse (std::string const &msg)
 
void SendModuleToClient ()
 
void RequestModule ()
 
void Update (uint32 const diff)
 
void DecryptData (uint8 *buffer, uint32 length)
 
void EncryptData (uint8 *buffer, uint32 length)
 
void ApplyPenalty (uint16 checkId, std::string const &reason)
 
WardenPayloadMgrGetPayloadMgr ()
 

Private Attributes

uint32 _serverTicks
 
std::list< uint16_ChecksTodo [MAX_WARDEN_CHECK_TYPES]
 
std::list< uint16_CurrentChecks
 
std::list< uint16_PendingChecks
 

Additional Inherited Members

- Static Public Member Functions inherited from Warden
static bool IsValidCheckSum (uint32 checksum, uint8 const *data, const uint16 length)
 
static uint32 BuildChecksum (uint8 const *data, uint32 length)
 

Detailed Description

Constructor & Destructor Documentation

◆ WardenWin()

WardenWin::WardenWin ( )
109: Warden(), _serverTicks(0) { }
uint32 _serverTicks
Definition WardenWin.h:87
Warden()
Definition Warden.cpp:31

◆ ~WardenWin()

WardenWin::~WardenWin ( )
overridedefault

Member Function Documentation

◆ ForceChecks()

void WardenWin::ForceChecks ( )
overridevirtual

Force call RequestChecks() so they are sent immediately, this interrupts warden and breaks result.

Implements Warden.

267{
268 if (_dataSent)
269 {
270 _interrupted = true;
272 }
273
275}
void RequestChecks() override
Definition WardenWin.cpp:277
uint32 _interruptCounter
Definition Warden.h:152
bool _dataSent
Definition Warden.h:147
bool _interrupted
Definition Warden.h:150

References Warden::_dataSent, Warden::_interruptCounter, Warden::_interrupted, and RequestChecks().

◆ GetModuleForClient()

ClientWardenModule * WardenWin::GetModuleForClient ( )
overridevirtual

Implements Warden.

139{
140 auto mod = new ClientWardenModule;
141
142 uint32 length = sizeof(Module.Module);
143
144 // data assign
145 mod->CompressedSize = length;
146 mod->CompressedData = new uint8[length];
147 memcpy(mod->CompressedData, Module.Module, length);
148 memcpy(mod->Key.data(), Module.ModuleKey, 16);
149
150 // md5 hash
151 mod->Id = Acore::Crypto::MD5::GetDigestOf(mod->CompressedData, mod->CompressedSize);
152
153 return mod;
154}
std::uint8_t uint8
Definition Define.h:109
std::uint32_t uint32
Definition Define.h:107
struct Module_79C0768D657977D697E10BAD956CCED1 Module
static Digest GetDigestOf(uint8 const *data, std::size_t len)
Definition CryptoHash.h:48
Definition Warden.h:93
uint32 CompressedSize
Definition Warden.h:96
uint8 Module[18756]
Definition WardenModuleWin.h:31
uint8 ModuleKey[16]
Definition WardenModuleWin.h:32

References ClientWardenModule::CompressedSize, Acore::Impl::GenericHash< HashCreator, DigestLength >::GetDigestOf(), Module_79C0768D657977D697E10BAD956CCED1::Module, Module, and Module_79C0768D657977D697E10BAD956CCED1::ModuleKey.

Referenced by Init().

◆ HandleData()

void WardenWin::HandleData ( ByteBuffer buff)
overridevirtual
Todo:
: test it.

Implements Warden.

564{
565 LOG_DEBUG("warden", "Handle data");
566
567 _dataSent = false;
569
570 uint16 Length;
571 buff >> Length;
572 uint32 Checksum;
573 buff >> Checksum;
574
575 if (Length != (buff.size() - buff.rpos()))
576 {
577 buff.rfinish();
578
579 if (!_interrupted)
580 {
581 ApplyPenalty(0, "Failed size checks in HandleData");
582 }
583
584 return;
585 }
586
587 if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length))
588 {
589 buff.rpos(buff.wpos());
590 LOG_DEBUG("warden", "CHECKSUM FAIL");
591
592 if (!_interrupted)
593 {
594 ApplyPenalty(0, "Failed checksum in HandleData");
595 }
596
597 return;
598 }
599
600 // TIMING_CHECK
601 {
602 uint8 result;
603 buff >> result;
605 if (result == 0x00)
606 {
607 LOG_DEBUG("warden", "TIMING CHECK FAIL result 0x00");
608 // ApplyPenalty(0, "TIMING CHECK FAIL result"); Commented out because of too many false postives. Mostly caused by client stutter.
609 return;
610 }
611
612 uint32 newClientTicks;
613 buff >> newClientTicks;
614
615 uint32 ticksNow = GameTime::GetGameTimeMS().count();
616 uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks);
617
618 LOG_DEBUG("warden", "ServerTicks {}", ticksNow); // Now
619 LOG_DEBUG("warden", "RequestTicks {}", _serverTicks); // At request
620 LOG_DEBUG("warden", "Ticks {}", newClientTicks); // At response
621 LOG_DEBUG("warden", "Ticks diff {}", ourTicks - newClientTicks);
622 }
623
624 uint16 checkFailed = 0;
625
626 for (uint16 const checkId : _CurrentChecks)
627 {
628 WardenCheck const* rd = sWardenCheckMgr->GetWardenDataById(checkId);
629
630 // Custom payload should be loaded in if equal to over offset.
631 if (!rd && checkId >= WardenPayloadMgr::WardenPayloadOffsetMin)
632 {
633 rd = &_payloadMgr.CachedChecks.at(checkId);
634 }
635
636 uint8 const type = rd->Type;
637 switch (type)
638 {
639 case MEM_CHECK:
640 {
641 uint8 Mem_Result;
642 buff >> Mem_Result;
643
644 if (Mem_Result != 0)
645 {
646 LOG_DEBUG("warden", "RESULT MEM_CHECK not 0x00, CheckId {} account Id {}", checkId, _session->GetAccountId());
647 checkFailed = checkId;
648 continue;
649 }
650
651 WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
652
653 std::vector<uint8> result = rs->Result.ToByteVector(0, false);
654 if (CRYPTO_memcmp(buff.contents() + buff.rpos(), result.data(), rd->Length) != 0)
655 {
656 LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId {} account Id {}", checkId, _session->GetAccountId());
657 checkFailed = checkId;
658 buff.rpos(buff.rpos() + rd->Length);
659 continue;
660 }
661
662 buff.rpos(buff.rpos() + rd->Length);
663 LOG_DEBUG("warden", "RESULT MEM_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
664 break;
665 }
666 case PAGE_CHECK_A:
667 case PAGE_CHECK_B:
668 case DRIVER_CHECK:
669 case MODULE_CHECK:
670 {
671 uint8 const byte = 0xE9;
672 if (CRYPTO_memcmp(buff.contents() + buff.rpos(), &byte, sizeof(uint8)) != 0)
673 {
674 if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
675 {
676 LOG_DEBUG("warden", "RESULT PAGE_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
677 }
678
679 if (type == MODULE_CHECK)
680 {
681 LOG_DEBUG("warden", "RESULT MODULE_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
682 }
683
684 if (type == DRIVER_CHECK)
685 {
686 LOG_DEBUG("warden", "RESULT DRIVER_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
687 }
688
689 checkFailed = checkId;
690 buff.rpos(buff.rpos() + 1);
691 continue;
692 }
693
694 buff.rpos(buff.rpos() + 1);
695
696 if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
697 {
698 LOG_DEBUG("warden", "RESULT PAGE_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
699 }
700 else if (type == MODULE_CHECK)
701 {
702 LOG_DEBUG("warden", "RESULT MODULE_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
703 }
704 else if (type == DRIVER_CHECK)
705 {
706 LOG_DEBUG("warden", "RESULT DRIVER_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
707 }
708 break;
709 }
710 case LUA_EVAL_CHECK:
711 {
712 uint8 const result = buff.read<uint8>();
713
714 if (result == 0)
715 {
716 buff.read_skip(buff.read<uint8>()); // discard attached string
717 }
718
719 LOG_DEBUG("warden", "LUA_EVAL_CHECK CheckId {} account Id {} got in-warden dummy response", checkId, _session->GetAccountId()/* , result */);
720 break;
721 }
722 case MPQ_CHECK:
723 {
724 uint8 Mpq_Result;
725 buff >> Mpq_Result;
726
727 if (Mpq_Result != 0)
728 {
729 LOG_DEBUG("warden", "RESULT MPQ_CHECK not 0x00 account id {}", _session->GetAccountId());
730 checkFailed = checkId;
731 continue;
732 }
733
734 WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
735 if (CRYPTO_memcmp(buff.contents() + buff.rpos(), rs->Result.ToByteArray<20>(false).data(), Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES) != 0)
736 {
737 LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
738 checkFailed = checkId;
739 buff.rpos(buff.rpos() + Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
740 continue;
741 }
742
743 buff.rpos(buff.rpos() + Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
744 LOG_DEBUG("warden", "RESULT MPQ_CHECK passed, CheckId {} account Id {}", checkId, _session->GetAccountId());
745 break;
746 }
747 }
748 }
749
750 if (checkFailed > 0 && !_interrupted)
751 {
752 ApplyPenalty(checkFailed, "");
753 }
754
755 if (_interrupted)
756 {
757 LOG_DEBUG("warden", "Warden was interrupted by ForceChecks, ignoring results.");
758
760
761 if (_interruptCounter == 0)
762 {
763 _interrupted = false;
764 }
765 }
766
767 // Set hold off timer, minimum timer should at least be 1 second
768 uint32 const holdOff = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF);
769 _checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS;
770
771 _checkInProgress = false;
772}
constexpr auto IN_MILLISECONDS
Definition Common.h:53
std::uint16_t uint16
Definition Define.h:108
@ CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF
Definition IWorld.h:377
#define LOG_DEBUG(filterType__,...)
Definition Log.h:169
#define sWardenCheckMgr
Definition WardenCheckMgr.h:89
@ DRIVER_CHECK
Definition Warden.h:53
@ PAGE_CHECK_A
Definition Warden.h:49
@ PAGE_CHECK_B
Definition Warden.h:50
@ LUA_EVAL_CHECK
Definition Warden.h:52
@ MPQ_CHECK
Definition Warden.h:51
@ MEM_CHECK
Definition Warden.h:48
@ MODULE_CHECK
Definition Warden.h:56
std::vector< uint8 > ToByteVector(int32 minSize=0, bool littleEndian=true) const
Definition BigNumber.cpp:191
std::array< uint8, Size > ToByteArray(bool littleEndian=true) const
Definition BigNumber.h:123
std::size_t size() const
Definition ByteBuffer.h:444
void read_skip()
Definition ByteBuffer.h:339
void rfinish()
Definition ByteBuffer.h:325
std::size_t wpos() const
Definition ByteBuffer.h:330
std::size_t rpos() const
Definition ByteBuffer.h:317
uint8 * contents()
Definition ByteBuffer.h:424
T read()
Definition ByteBuffer.h:351
std::map< uint16, WardenCheck > CachedChecks
The cached payloads that are accessed by payload id.
Definition WardenPayloadMgr.h:135
static uint16 constexpr WardenPayloadOffsetMin
The minimum id available for custom payloads.
Definition WardenPayloadMgr.h:115
std::list< uint16 > _CurrentChecks
Definition WardenWin.h:90
uint32 _checkTimer
Definition Warden.h:145
uint32 _clientResponseTimer
Definition Warden.h:146
void ApplyPenalty(uint16 checkId, std::string const &reason)
Definition Warden.cpp:196
WardenPayloadMgr _payloadMgr
Definition Warden.h:139
bool _checkInProgress
Definition Warden.h:151
static bool IsValidCheckSum(uint32 checksum, uint8 const *data, const uint16 length)
Definition Warden.cpp:140
WorldSession * _session
Definition Warden.h:138
uint32 GetAccountId() const
Definition WorldSession.h:375
#define sWorld
Definition World.h:363
Milliseconds GetGameTimeMS()
Definition GameTime.cpp:43
static constexpr std::size_t SHA1_DIGEST_LENGTH_BYTES
Definition CryptoConstants.h:26
Definition WardenCheckMgr.h:59
BigNumber Result
Definition WardenCheckMgr.h:60
Definition WardenCheckMgr.h:44
uint8 Length
Definition WardenCheckMgr.h:48
uint8 Type
Definition WardenCheckMgr.h:45

References Warden::_checkInProgress, Warden::_checkTimer, Warden::_clientResponseTimer, _CurrentChecks, Warden::_dataSent, Warden::_interruptCounter, Warden::_interrupted, Warden::_payloadMgr, _serverTicks, Warden::_session, Warden::ApplyPenalty(), WardenPayloadMgr::CachedChecks, CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF, ByteBuffer::contents(), DRIVER_CHECK, WorldSession::GetAccountId(), GameTime::GetGameTimeMS(), IN_MILLISECONDS, Warden::IsValidCheckSum(), WardenCheck::Length, LOG_DEBUG, LUA_EVAL_CHECK, MEM_CHECK, MODULE_CHECK, MPQ_CHECK, PAGE_CHECK_A, PAGE_CHECK_B, ByteBuffer::read(), ByteBuffer::read_skip(), WardenCheckResult::Result, ByteBuffer::rfinish(), ByteBuffer::rpos(), Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES, ByteBuffer::size(), sWardenCheckMgr, sWorld, BigNumber::ToByteArray(), BigNumber::ToByteVector(), WardenCheck::Type, WardenPayloadMgr::WardenPayloadOffsetMin, and ByteBuffer::wpos().

◆ HandleHashResult()

void WardenWin::HandleHashResult ( ByteBuffer buff)
overridevirtual

Implements Warden.

231{
232 buff.rpos(buff.wpos());
233
234 // Verify key using constant-time comparison
236 {
237 LOG_DEBUG("warden", "Request hash reply: failed");
238 ApplyPenalty(0, "Request hash reply: failed");
239 return;
240 }
241
242 LOG_DEBUG("warden", "Request hash reply: succeed");
243
244 // Change keys here
245 memcpy(_inputKey, Module.ClientKeySeed, 16);
246 memcpy(_outputKey, Module.ServerKeySeed, 16);
247
250
251 _initialized = true;
252}
void Init(uint8 const *seed, std::size_t len)
Definition ARC4.cpp:36
Acore::Crypto::ARC4 _inputCrypto
Definition Warden.h:143
Acore::Crypto::ARC4 _outputCrypto
Definition Warden.h:144
uint8 _inputKey[16]
Definition Warden.h:140
uint8 _outputKey[16]
Definition Warden.h:141
bool _initialized
Definition Warden.h:149
uint8 ClientKeySeed[16]
Definition WardenModuleWin.h:35
uint8 ServerKeySeed[16]
Definition WardenModuleWin.h:34
uint8 ClientKeySeedHash[20]
Definition WardenModuleWin.h:36

References Warden::_initialized, Warden::_inputCrypto, Warden::_inputKey, Warden::_outputCrypto, Warden::_outputKey, Warden::ApplyPenalty(), Module_79C0768D657977D697E10BAD956CCED1::ClientKeySeed, Module_79C0768D657977D697E10BAD956CCED1::ClientKeySeedHash, ByteBuffer::contents(), Acore::Crypto::ARC4::Init(), LOG_DEBUG, Module, ByteBuffer::rpos(), Module_79C0768D657977D697E10BAD956CCED1::ServerKeySeed, Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES, and ByteBuffer::wpos().

◆ Init()

void WardenWin::Init ( WorldSession session,
SessionKey const &  K 
)
overridevirtual

Implements Warden.

114{
115 _session = session;
116 // Generate Warden Key
118 WK.Generate(_inputKey, 16);
119 WK.Generate(_outputKey, 16);
120
121 memcpy(_seed, Module.Seed, 16);
122
125 LOG_DEBUG("warden", "Server side warden for client {} initializing...", session->GetAccountId());
126 LOG_DEBUG("warden", "C->S Key: {}", Acore::Impl::ByteArrayToHexStr(_inputKey, 16));
127 LOG_DEBUG("warden", "S->C Key: {}", Acore::Impl::ByteArrayToHexStr(_outputKey,16));
128 LOG_DEBUG("warden", " Seed: {}", Acore::Impl::ByteArrayToHexStr(_seed, 16));
129 LOG_DEBUG("warden", "Loading Module...");
130
132
133 LOG_DEBUG("warden", "Module Key: {}", ByteArrayToHexStr(_module->Key));
134 LOG_DEBUG("warden", "Module ID: {}", ByteArrayToHexStr(_module->Id));
136}
std::string ByteArrayToHexStr(Container const &c, bool reverse=false)
Definition Util.h:381
Definition SessionKeyGenerator.h:23
ClientWardenModule * GetModuleForClient() override
Definition WardenWin.cpp:138
uint8 _seed[16]
Definition Warden.h:142
void RequestModule()
Definition Warden.cpp:73
ClientWardenModule * _module
Definition Warden.h:148
AC_COMMON_API std::string ByteArrayToHexStr(uint8 const *bytes, std::size_t length, bool reverse=false)
Definition Util.cpp:545
std::array< uint8, 16 > Key
Definition Warden.h:95
std::array< uint8, 16 > Id
Definition Warden.h:94
uint8 Seed[16]
Definition WardenModuleWin.h:33

References Warden::_inputCrypto, Warden::_inputKey, Warden::_module, Warden::_outputCrypto, Warden::_outputKey, Warden::_seed, Warden::_session, ByteArrayToHexStr(), Acore::Impl::ByteArrayToHexStr(), SessionKeyGenerator< Hash >::Generate(), WorldSession::GetAccountId(), GetModuleForClient(), ClientWardenModule::Id, Acore::Crypto::ARC4::Init(), ClientWardenModule::Key, LOG_DEBUG, Module, Warden::RequestModule(), and Module_79C0768D657977D697E10BAD956CCED1::Seed.

◆ InitializeModule()

void WardenWin::InitializeModule ( )
overridevirtual

Implements Warden.

157{
158 LOG_DEBUG("warden", "Initialize module");
159
160 // Create packet structure
161 WardenInitModuleRequest Request{};
163 Request.Size1 = 20;
164 Request.Unk1 = 1;
165 Request.Unk2 = 0;
166 Request.Type = 1;
167 Request.String_library1 = 0;
168 Request.Function1[0] = 0x00024F80; // 0x00400000 + 0x00024F80 SFileOpenFile
169 Request.Function1[1] = 0x000218C0; // 0x00400000 + 0x000218C0 SFileGetFileSize
170 Request.Function1[2] = 0x00022530; // 0x00400000 + 0x00022530 SFileReadFile
171 Request.Function1[3] = 0x00022910; // 0x00400000 + 0x00022910 SFileCloseFile
172 Request.CheckSumm1 = BuildChecksum(&Request.Unk1, Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES);
173
174 Request.Command2 = WARDEN_SMSG_MODULE_INITIALIZE;
175 Request.Size2 = 8;
176 Request.Unk3 = 4;
177 Request.Unk4 = 0;
178 Request.String_library2 = 0;
179 Request.Function2 = 0x00419210; // 0x00400000 + 0x00419210 FrameScript::Execute
180 Request.Function2_set = 1;
181 Request.CheckSumm2 = BuildChecksum(&Request.Unk3, 8);
182
183 Request.Command3 = WARDEN_SMSG_MODULE_INITIALIZE;
184 Request.Size3 = 8;
185 Request.Unk5 = 1;
186 Request.Unk6 = 1;
187 Request.String_library3 = 0;
188 Request.Function3 = 0x0046AE20; // 0x00400000 + 0x0046AE20 PerformanceCounter
189 Request.Function3_set = 1;
190 Request.CheckSumm3 = BuildChecksum(&Request.Unk5, 8);
191
192 EndianConvert(Request.Size1);
193 EndianConvert(Request.CheckSumm1);
194 EndianConvert(Request.Function1[0]);
195 EndianConvert(Request.Function1[1]);
196 EndianConvert(Request.Function1[2]);
197 EndianConvert(Request.Function1[3]);
198 EndianConvert(Request.Size2);
199 EndianConvert(Request.CheckSumm2);
200 EndianConvert(Request.Function2);
201 EndianConvert(Request.Size3);
202 EndianConvert(Request.CheckSumm3);
203 EndianConvert(Request.Function3);
204
205 // Encrypt with warden RC4 key.
206 EncryptData(reinterpret_cast<uint8*>(&Request), sizeof(WardenInitModuleRequest));
207
209 pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenInitModuleRequest));
210 _session->SendPacket(&pkt);
211}
void EndianConvert(T &val)
Definition ByteConverter.h:47
@ WARDEN_SMSG_MODULE_INITIALIZE
Definition Warden.h:41
void EncryptData(uint8 *buffer, uint32 length)
Definition Warden.cpp:135
static uint32 BuildChecksum(uint8 const *data, uint32 length)
Definition Warden.cpp:167
Definition WorldPacket.h:26
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
Definition WorldSession.cpp:226
@ SMSG_WARDEN_DATA
Definition Opcodes.h:772
Definition WardenWin.h:32
uint8 Command1
Definition WardenWin.h:33

References Warden::_session, ByteBuffer::append(), Warden::BuildChecksum(), WardenInitModuleRequest::Command1, Warden::EncryptData(), EndianConvert(), LOG_DEBUG, WorldSession::SendPacket(), Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES, SMSG_WARDEN_DATA, and WARDEN_SMSG_MODULE_INITIALIZE.

◆ IsCheckInProgress()

bool WardenWin::IsCheckInProgress ( )
overridevirtual

Gets the warden check state.

Returns
The warden check state.

Implements Warden.

259{
260 return _checkInProgress;
261}

References Warden::_checkInProgress.

◆ RequestChecks()

void WardenWin::RequestChecks ( )
overridevirtual

Implements Warden.

278{
279 LOG_DEBUG("warden", "Request data");
280
281 _checkInProgress = true;
282
283 // If all checks were done, fill the todo list again
284 for (uint8 i = 0; i < MAX_WARDEN_CHECK_TYPES; ++i)
285 {
286 if (_ChecksTodo[i].empty())
287 _ChecksTodo[i].assign(sWardenCheckMgr->CheckIdPool[i].begin(), sWardenCheckMgr->CheckIdPool[i].end());
288 }
289
291 _CurrentChecks.clear();
292
293 // Erase any nullptrs.
295 [this](uint16 id)
296 {
297 WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(id);
298
299 // Custom payload should be loaded in if equal to over offset.
301 {
302 if (_payloadMgr.CachedChecks.find(id) != _payloadMgr.CachedChecks.end())
303 {
304 check = &_payloadMgr.CachedChecks.at(id);
305 }
306 }
307
308 if (!check)
309 {
310 return true;
311 }
312
313 return false;
314 }
315 );
316
317 // No pending checks
318 if (_PendingChecks.empty())
319 {
320 for (uint8 checkType = 0; checkType < MAX_WARDEN_CHECK_TYPES; ++checkType)
321 {
322 for (uint32 y = 0; y < sWorld->getIntConfig(GetMaxWardenChecksForType(checkType)); ++y)
323 {
324 // If todo list is done break loop (will be filled on next Update() run)
325 if (_ChecksTodo[checkType].empty())
326 {
327 break;
328 }
329
330 // Load in any custom payloads if available.
331 if (checkType == WARDEN_CHECK_LUA_TYPE && !_payloadMgr.QueuedPayloads.empty())
332 {
333 uint16 payloadId = _payloadMgr.QueuedPayloads.front();
334
335 LOG_DEBUG("warden", "Adding custom warden payload '{}' to CurrentChecks.", payloadId);
336
337 _payloadMgr.QueuedPayloads.pop_front();
338 _CurrentChecks.push_front(payloadId);
339
340 continue;
341 }
342
343 // Get check id from the end and remove it from todo
344 uint16 const id = _ChecksTodo[checkType].back();
345 _ChecksTodo[checkType].pop_back();
346
347 // Insert check to queue
348 if (checkType == WARDEN_CHECK_LUA_TYPE)
349 {
350 _CurrentChecks.push_front(id);
351 }
352 else
353 {
354 _CurrentChecks.push_back(id);
355 }
356 }
357 }
358 }
359 else
360 {
361 bool hasLuaChecks = false;
362 for (uint16 const checkId : _PendingChecks)
363 {
364 WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(checkId);
365
366 // Custom payload should be loaded in if equal to over offset.
367 if (!check && checkId >= WardenPayloadMgr::WardenPayloadOffsetMin)
368 {
369 check = &_payloadMgr.CachedChecks.at(checkId);
370 }
371
372 if (!hasLuaChecks && check->Type == LUA_EVAL_CHECK)
373 {
374 hasLuaChecks = true;
375 }
376
377 _CurrentChecks.push_back(checkId);
378 }
379
380 // Always include lua checks
381 if (!hasLuaChecks)
382 {
383 for (uint32 i = 0; i < sWorld->getIntConfig(GetMaxWardenChecksForType(WARDEN_CHECK_LUA_TYPE)); ++i)
384 {
385 // If todo list is done break loop (will be filled on next Update() run)
387 {
388 break;
389 }
390
391 // Get check id from the end and remove it from todo
392 uint16 const id = _ChecksTodo[WARDEN_CHECK_LUA_TYPE].back();
394
395 // Lua checks must be always in front
396 _CurrentChecks.push_front(id);
397 }
398 }
399 }
400
401 // Filter too high checks queue
402 // Filtered checks will get passed in next checks
403 uint16 expectedSize = 4;
404 _PendingChecks.clear();
406 [this, &expectedSize](uint16 id)
407 {
408 WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(id);
409
410 // Custom payload should be loaded in if equal to over offset.
412 {
413 check = &_payloadMgr.CachedChecks.at(id);
414 }
415
416 // Remove nullptr if it snuck in from earlier check.
417 if (!check)
418 {
419 return true;
420 }
421
422 uint16 const thisSize = GetCheckPacketSize(check);
423 if ((expectedSize + thisSize) > 500) // warden packets are truncated to 512 bytes clientside
424 {
425 _PendingChecks.push_back(id);
426 return true;
427 }
428 expectedSize += thisSize;
429 return false;
430 }
431 );
432
433 ByteBuffer buff;
435
436 for (uint16 const checkId : _CurrentChecks)
437 {
438 WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(checkId);
439
440 // Custom payloads do not have prefix, midfix, postfix.
441 if (!check && checkId >= WardenPayloadMgr::WardenPayloadOffsetMin)
442 {
443 check = &_payloadMgr.CachedChecks.at(checkId);
444
445 buff << uint8(check->Str.size());
446 buff.append(check->Str.data(), check->Str.size());
447
448 continue;
449 }
450
451 switch (check->Type)
452 {
453 case LUA_EVAL_CHECK:
454 {
455 buff << uint8(sizeof(_luaEvalPrefix) - 1 + check->Str.size() + sizeof(_luaEvalMidfix) - 1 + check->IdStr.size() + sizeof(_luaEvalPostfix) - 1);
456 buff.append(_luaEvalPrefix, sizeof(_luaEvalPrefix) - 1);
457 buff.append(check->Str.data(), check->Str.size());
458 buff.append(_luaEvalMidfix, sizeof(_luaEvalMidfix) - 1);
459 buff.append(check->IdStr.data(), check->IdStr.size());
460 buff.append(_luaEvalPostfix, sizeof(_luaEvalPostfix) - 1);
461 break;
462 }
463 case MPQ_CHECK:
464 case DRIVER_CHECK:
465 {
466 buff << uint8(check->Str.size());
467 buff.append(check->Str.c_str(), check->Str.size());
468 break;
469 }
470 }
471 }
472
473 uint8 const xorByte = _inputKey[0];
474
475 // Add TIMING_CHECK
476 buff << uint8(0x00);
477 buff << uint8(TIMING_CHECK ^ xorByte);
478
479 uint8 index = 1;
480
481 for (uint16 const checkId : _CurrentChecks)
482 {
483 WardenCheck const* check = sWardenCheckMgr->GetWardenDataById(checkId);
484
485 // Custom payload should be loaded in if equal to over offset.
486 if (!check && checkId >= WardenPayloadMgr::WardenPayloadOffsetMin)
487 {
488 check = &_payloadMgr.CachedChecks.at(checkId);
489 }
490
491 buff << uint8(check->Type ^ xorByte);
492 switch (check->Type)
493 {
494 case MEM_CHECK:
495 {
496 buff << uint8(0x00);
497 buff << uint32(check->Address);
498 buff << uint8(check->Length);
499 break;
500 }
501 case PAGE_CHECK_A:
502 case PAGE_CHECK_B:
503 {
504 std::vector<uint8> data = check->Data.ToByteVector(24, false);
505 buff.append(data.data(), data.size());
506 buff << uint32(check->Address);
507 buff << uint8(check->Length);
508 break;
509 }
510 case MPQ_CHECK:
511 case LUA_EVAL_CHECK:
512 {
513 buff << uint8(index++);
514 break;
515 }
516 case DRIVER_CHECK:
517 {
518 std::vector<uint8> data = check->Data.ToByteVector(24, false);
519 buff.append(data.data(), data.size());
520 buff << uint8(index++);
521 break;
522 }
523 case MODULE_CHECK:
524 {
525 std::array<uint8, 4> seed = Acore::Crypto::GetRandomBytes<4>();
526 buff.append(seed);
527 buff.append(Acore::Crypto::HMAC_SHA1::GetDigestOf(seed, check->Str));
528 break;
529 }
530 /*case PROC_CHECK:
531 {
532 buff.append(wd->i.AsByteArray(0, false).get(), wd->i.GetNumBytes());
533 buff << uint8(index++);
534 buff << uint8(index++);
535 buff << uint32(wd->Address);
536 buff << uint8(wd->Length);
537 break;
538 }*/
539 }
540 }
541 buff << uint8(xorByte);
542 buff.hexlike();
543
544 // Encrypt with warden RC4 key
545 EncryptData(buff.contents(), buff.size());
546
547 WorldPacket pkt(SMSG_WARDEN_DATA, buff.size());
548 pkt.append(buff);
549 _session->SendPacket(&pkt);
550
551 _dataSent = true;
552
553 std::stringstream stream;
554 stream << "Sent check id's: ";
555 for (uint16 checkId : _CurrentChecks)
556 {
557 stream << checkId << " ";
558 }
559
560 LOG_DEBUG("warden", "{}", stream.str());
561}
constexpr uint8 MAX_WARDEN_CHECK_TYPES
Definition WardenCheckMgr.h:41
@ WARDEN_CHECK_LUA_TYPE
Definition WardenCheckMgr.h:37
static WorldIntConfigs GetMaxWardenChecksForType(uint8 type)
Definition WardenWin.cpp:91
static constexpr char _luaEvalPrefix[]
Definition WardenWin.cpp:37
static constexpr char _luaEvalMidfix[]
Definition WardenWin.cpp:38
static constexpr char _luaEvalPostfix[]
Definition WardenWin.cpp:39
static uint16 GetCheckPacketSize(WardenCheck const *check)
Definition WardenWin.cpp:58
@ TIMING_CHECK
Definition Warden.h:54
@ WARDEN_SMSG_CHEAT_CHECKS_REQUEST
Definition Warden.h:40
static Digest GetDigestOf(Container const &seed, uint8 const *data, std::size_t len)
Definition HMAC.h:40
Definition ByteBuffer.h:70
std::list< uint16 > QueuedPayloads
The list of currently queued payload ids to be sent through Warden.
Definition WardenPayloadMgr.h:130
std::list< uint16 > _PendingChecks
Definition WardenWin.h:91
std::list< uint16 > _ChecksTodo[MAX_WARDEN_CHECK_TYPES]
Definition WardenWin.h:88
void EraseIf(Container &c, Predicate p)
Definition Containers.h:253
std::array< char, 4 > IdStr
Definition WardenCheckMgr.h:52
std::string Str
Definition WardenCheckMgr.h:49
BigNumber Data
Definition WardenCheckMgr.h:46
uint32 Address
Definition WardenCheckMgr.h:47

References Warden::_checkInProgress, _ChecksTodo, _CurrentChecks, Warden::_dataSent, Warden::_inputKey, _luaEvalMidfix, _luaEvalPostfix, _luaEvalPrefix, Warden::_payloadMgr, _PendingChecks, _serverTicks, Warden::_session, WardenCheck::Address, ByteBuffer::append(), WardenPayloadMgr::CachedChecks, WardenCheck::Data, DRIVER_CHECK, Warden::EncryptData(), Acore::Containers::EraseIf(), GetCheckPacketSize(), Acore::Impl::GenericHMAC< HashCreator, DigestLength >::GetDigestOf(), GameTime::GetGameTimeMS(), GetMaxWardenChecksForType(), WardenCheck::IdStr, WardenCheck::Length, LOG_DEBUG, LUA_EVAL_CHECK, MAX_WARDEN_CHECK_TYPES, MEM_CHECK, MODULE_CHECK, MPQ_CHECK, PAGE_CHECK_A, PAGE_CHECK_B, WardenPayloadMgr::QueuedPayloads, WorldSession::SendPacket(), SMSG_WARDEN_DATA, WardenCheck::Str, sWardenCheckMgr, sWorld, TIMING_CHECK, BigNumber::ToByteVector(), WardenCheck::Type, WARDEN_CHECK_LUA_TYPE, WARDEN_SMSG_CHEAT_CHECKS_REQUEST, and WardenPayloadMgr::WardenPayloadOffsetMin.

Referenced by ForceChecks().

◆ RequestHash()

void WardenWin::RequestHash ( )
overridevirtual

Implements Warden.

214{
215 LOG_DEBUG("warden", "Request hash");
216
217 // Create packet structure
218 WardenHashRequest Request{};
220 memcpy(Request.Seed, _seed, 16);
221
222 // Encrypt with warden RC4 key.
223 EncryptData(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest));
224
226 pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest));
227 _session->SendPacket(&pkt);
228}
@ WARDEN_SMSG_HASH_REQUEST
Definition Warden.h:43
Definition Warden.h:81
uint8 Command
Definition Warden.h:82

References Warden::_seed, Warden::_session, ByteBuffer::append(), WardenHashRequest::Command, Warden::EncryptData(), LOG_DEBUG, WorldSession::SendPacket(), SMSG_WARDEN_DATA, and WARDEN_SMSG_HASH_REQUEST.

Member Data Documentation

◆ _ChecksTodo

std::list<uint16> WardenWin::_ChecksTodo[MAX_WARDEN_CHECK_TYPES]
private

Referenced by RequestChecks().

◆ _CurrentChecks

std::list<uint16> WardenWin::_CurrentChecks
private

Referenced by HandleData(), and RequestChecks().

◆ _PendingChecks

std::list<uint16> WardenWin::_PendingChecks
private

Referenced by RequestChecks().

◆ _serverTicks

uint32 WardenWin::_serverTicks
private

Referenced by HandleData(), and RequestChecks().


The documentation for this class was generated from the following files: