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 void Init (WorldSession *session, SessionKey const &k)=0
 
virtual ClientWardenModuleGetModuleForClient ()=0
 
virtual void InitializeModule ()=0
 
virtual void RequestHash ()=0
 
virtual void HandleHashResult (ByteBuffer &buff)=0
 
virtual bool IsCheckInProgress ()=0
 
virtual bool IsInitialized ()
 
virtual void ForceChecks ()=0
 
virtual void RequestChecks ()=0
 
virtual void HandleData (ByteBuffer &buff)=0
 
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, const uint8 *data, const uint16 length)
 
static uint32 BuildChecksum (const uint8 *data, uint32 length)
 

Detailed Description

Constructor & Destructor Documentation

◆ WardenWin()

WardenWin::WardenWin ( )
108: Warden(), _serverTicks(0) { }
Warden()
Definition: Warden.cpp:32
uint32 _serverTicks
Definition: WardenWin.h:89

◆ ~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.

266{
267 if (_dataSent)
268 {
269 _interrupted = true;
271 }
272
274}
uint32 _interruptCounter
Definition: Warden.h:153
bool _dataSent
Definition: Warden.h:148
bool _interrupted
Definition: Warden.h:151
void RequestChecks() override
Definition: WardenWin.cpp:276

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

◆ GetModuleForClient()

ClientWardenModule * WardenWin::GetModuleForClient ( )
overridevirtual

Implements Warden.

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

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.

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

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.

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

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.

113{
114 _session = session;
115 // Generate Warden Key
117 WK.Generate(_inputKey, 16);
118 WK.Generate(_outputKey, 16);
119
120 memcpy(_seed, Module.Seed, 16);
121
124 LOG_DEBUG("warden", "Server side warden for client {} initializing...", session->GetAccountId());
125 LOG_DEBUG("warden", "C->S Key: {}", Acore::Impl::ByteArrayToHexStr(_inputKey, 16));
126 LOG_DEBUG("warden", "S->C Key: {}", Acore::Impl::ByteArrayToHexStr(_outputKey,16));
127 LOG_DEBUG("warden", " Seed: {}", Acore::Impl::ByteArrayToHexStr(_seed, 16));
128 LOG_DEBUG("warden", "Loading Module...");
129
131
132 LOG_DEBUG("warden", "Module Key: {}", ByteArrayToHexStr(_module->Key));
133 LOG_DEBUG("warden", "Module ID: {}", ByteArrayToHexStr(_module->Id));
135}
std::string ByteArrayToHexStr(Container const &c, bool reverse=false)
Definition: Util.h:376
AC_COMMON_API std::string ByteArrayToHexStr(uint8 const *bytes, size_t length, bool reverse=false)
Definition: Util.cpp:541
Definition: SessionKeyGenerator.h:26
uint8 Seed[16]
Definition: WardenModuleWin.h:33
std::array< uint8, 16 > Key
Definition: Warden.h:96
std::array< uint8, 16 > Id
Definition: Warden.h:95
uint8 _seed[16]
Definition: Warden.h:143
void RequestModule()
Definition: Warden.cpp:74
ClientWardenModule * _module
Definition: Warden.h:149
ClientWardenModule * GetModuleForClient() override
Definition: WardenWin.cpp:137

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.

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

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.

258{
259 return _checkInProgress;
260}

References Warden::_checkInProgress.

◆ RequestChecks()

void WardenWin::RequestChecks ( )
overridevirtual

Implements Warden.

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

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.

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

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().