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
 
ClientWardenModule * GetModuleForClient () 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)
 
WardenPayloadMgr * GetPayloadMgr ()
 

Private Member Functions

std::vector< uint8 > GetExpectedResult (WardenCheck const &check) const
 

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 ( )
110: Warden(), _serverTicks(0) { }
uint32 _serverTicks
Definition WardenWin.h:89
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.

268{
269 if (_dataSent)
270 {
271 _interrupted = true;
273 }
274
276}
void RequestChecks() override
Definition WardenWin.cpp:278
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().

◆ GetExpectedResult()

std::vector< uint8 > WardenWin::GetExpectedResult ( WardenCheck const &  check) const
private
565{
566 std::size_t const length = check.Type == MPQ_CHECK
568
569 std::vector<uint8> expected;
570 if (sScriptMgr->OnWardenCheckExpectedResult(_session, check, expected))
571 {
572 if (expected.size() == length)
573 return expected;
574
575 LOG_ERROR("warden", "Script returned {} expected bytes for CheckId {}, {} required, using the stored result",
576 expected.size(), check.CheckId, length);
577 }
578
579 // BigNumber drops leading zero bytes, pad to the check length so the comparison stays in bounds.
580 return sWardenCheckMgr->GetWardenResultById(check.CheckId)->Result.ToByteVector(static_cast<int32>(length), false);
581}
std::int32_t int32
Definition Define.h:103
#define LOG_ERROR(filterType__,...)
Definition Log.h:145
#define sScriptMgr
Definition ScriptMgr.h:769
#define sWardenCheckMgr
Definition WardenCheckMgr.h:89
@ MPQ_CHECK
Definition Warden.h:51
WorldSession * _session
Definition Warden.h:138
static constexpr std::size_t SHA1_DIGEST_LENGTH_BYTES
Definition CryptoConstants.h:26

References Warden::_session, WardenCheck::CheckId, WardenCheck::Length, LOG_ERROR, MPQ_CHECK, Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES, sScriptMgr, sWardenCheckMgr, and WardenCheck::Type.

Referenced by HandleData().

◆ GetModuleForClient()

ClientWardenModule * WardenWin::GetModuleForClient ( )
overridevirtual

Implements Warden.

140{
141 auto mod = new ClientWardenModule;
142
143 uint32 length = sizeof(Module.Module);
144
145 // data assign
146 mod->CompressedSize = length;
147 mod->CompressedData = new uint8[length];
148 memcpy(mod->CompressedData, Module.Module, length);
149 memcpy(mod->Key.data(), Module.ModuleKey, 16);
150
151 // md5 hash
152 mod->Id = Acore::Crypto::MD5::GetDigestOf(mod->CompressedData, mod->CompressedSize);
153
154 return mod;
155}
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.

584{
585 LOG_DEBUG("warden", "Handle data");
586
587 _dataSent = false;
589
590 uint16 Length;
591 buff >> Length;
592 uint32 Checksum;
593 buff >> Checksum;
594
595 if (Length != (buff.size() - buff.rpos()))
596 {
597 buff.rfinish();
598
599 if (!_interrupted)
600 {
601 ApplyPenalty(0, "Failed size checks in HandleData");
602 }
603
604 return;
605 }
606
607 if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length))
608 {
609 buff.rpos(buff.wpos());
610 LOG_DEBUG("warden", "CHECKSUM FAIL");
611
612 if (!_interrupted)
613 {
614 ApplyPenalty(0, "Failed checksum in HandleData");
615 }
616
617 return;
618 }
619
620 // TIMING_CHECK
621 {
622 uint8 result;
623 buff >> result;
625 if (result == 0x00)
626 {
627 LOG_DEBUG("warden", "TIMING CHECK FAIL result 0x00");
628 // ApplyPenalty(0, "TIMING CHECK FAIL result"); Commented out because of too many false postives. Mostly caused by client stutter.
629 return;
630 }
631
632 uint32 newClientTicks;
633 buff >> newClientTicks;
634
635 uint32 ticksNow = GameTime::GetGameTimeMS().count();
636 uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks);
637
638 LOG_DEBUG("warden", "ServerTicks {}", ticksNow); // Now
639 LOG_DEBUG("warden", "RequestTicks {}", _serverTicks); // At request
640 LOG_DEBUG("warden", "Ticks {}", newClientTicks); // At response
641 LOG_DEBUG("warden", "Ticks diff {}", ourTicks - newClientTicks);
642 }
643
644 uint16 checkFailed = 0;
645
646 for (uint16 const checkId : _CurrentChecks)
647 {
648 WardenCheck const* rd = sWardenCheckMgr->GetWardenDataById(checkId);
649
650 // Custom payload should be loaded in if equal to over offset.
651 if (!rd && checkId >= WardenPayloadMgr::WardenPayloadOffsetMin)
652 {
653 rd = &_payloadMgr.CachedChecks.at(checkId);
654 }
655
656 uint8 const type = rd->Type;
657 switch (type)
658 {
659 case MEM_CHECK:
660 {
661 uint8 Mem_Result;
662 buff >> Mem_Result;
663
664 if (Mem_Result != 0)
665 {
666 LOG_DEBUG("warden", "RESULT MEM_CHECK not 0x00, CheckId {} account Id {}", checkId, _session->GetAccountId());
667 checkFailed = checkId;
668 continue;
669 }
670
671 std::vector<uint8> const expected = GetExpectedResult(*rd);
672 if (CRYPTO_memcmp(buff.contents() + buff.rpos(), expected.data(), rd->Length) != 0)
673 {
674 LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId {} account Id {} locale {}", checkId,
676 checkFailed = checkId;
677 buff.rpos(buff.rpos() + rd->Length);
678 continue;
679 }
680
681 buff.rpos(buff.rpos() + rd->Length);
682 LOG_DEBUG("warden", "RESULT MEM_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
683 break;
684 }
685 case PAGE_CHECK_A:
686 case PAGE_CHECK_B:
687 case DRIVER_CHECK:
688 case MODULE_CHECK:
689 {
690 uint8 const byte = 0xE9;
691 if (CRYPTO_memcmp(buff.contents() + buff.rpos(), &byte, sizeof(uint8)) != 0)
692 {
693 if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
694 {
695 LOG_DEBUG("warden", "RESULT PAGE_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
696 }
697
698 if (type == MODULE_CHECK)
699 {
700 LOG_DEBUG("warden", "RESULT MODULE_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
701 }
702
703 if (type == DRIVER_CHECK)
704 {
705 LOG_DEBUG("warden", "RESULT DRIVER_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
706 }
707
708 checkFailed = checkId;
709 buff.rpos(buff.rpos() + 1);
710 continue;
711 }
712
713 buff.rpos(buff.rpos() + 1);
714
715 if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
716 {
717 LOG_DEBUG("warden", "RESULT PAGE_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
718 }
719 else if (type == MODULE_CHECK)
720 {
721 LOG_DEBUG("warden", "RESULT MODULE_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
722 }
723 else if (type == DRIVER_CHECK)
724 {
725 LOG_DEBUG("warden", "RESULT DRIVER_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
726 }
727 break;
728 }
729 case LUA_EVAL_CHECK:
730 {
731 uint8 const result = buff.read<uint8>();
732
733 if (result == 0)
734 {
735 buff.read_skip(buff.read<uint8>()); // discard attached string
736 }
737
738 LOG_DEBUG("warden", "LUA_EVAL_CHECK CheckId {} account Id {} got in-warden dummy response", checkId, _session->GetAccountId()/* , result */);
739 break;
740 }
741 case MPQ_CHECK:
742 {
743 uint8 Mpq_Result;
744 buff >> Mpq_Result;
745
746 if (Mpq_Result != 0)
747 {
748 LOG_DEBUG("warden", "RESULT MPQ_CHECK not 0x00 account id {}", _session->GetAccountId());
749 checkFailed = checkId;
750 continue;
751 }
752
753 std::vector<uint8> const expected = GetExpectedResult(*rd);
754 if (CRYPTO_memcmp(buff.contents() + buff.rpos(), expected.data(),
756 {
757 LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId {} account Id {} locale {}", checkId,
759 checkFailed = checkId;
760 buff.rpos(buff.rpos() + Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
761 continue;
762 }
763
764 buff.rpos(buff.rpos() + Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
765 LOG_DEBUG("warden", "RESULT MPQ_CHECK passed, CheckId {} account Id {}", checkId, _session->GetAccountId());
766 break;
767 }
768 }
769 }
770
771 if (checkFailed > 0 && !_interrupted)
772 {
773 ApplyPenalty(checkFailed, "");
774 }
775
776 if (_interrupted)
777 {
778 LOG_DEBUG("warden", "Warden was interrupted by ForceChecks, ignoring results.");
779
781
782 if (_interruptCounter == 0)
783 {
784 _interrupted = false;
785 }
786 }
787
788 // Set hold off timer, minimum timer should at least be 1 second
789 uint32 const holdOff = sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF);
790 _checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS;
791
792 _checkInProgress = false;
793}
const std::string GetNameByLocaleConstant(LocaleConstant localeConstant)
Definition Common.cpp:87
constexpr auto IN_MILLISECONDS
Definition Common.h:53
std::uint16_t uint16
Definition Define.h:108
#define LOG_DEBUG(filterType__,...)
Definition Log.h:157
@ 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
@ MEM_CHECK
Definition Warden.h:48
@ MODULE_CHECK
Definition Warden.h:56
@ CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF
Definition WorldConfig.h:347
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:92
std::vector< uint8 > GetExpectedResult(WardenCheck const &check) const
Definition WardenWin.cpp:564
uint32 _checkTimer
Definition Warden.h:145
uint32 _clientResponseTimer
Definition Warden.h:146
void ApplyPenalty(uint16 checkId, std::string const &reason)
Definition Warden.cpp:199
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:143
LocaleConstant GetSessionDbLocaleIndex() const
Definition WorldSession.h:647
uint32 GetAccountId() const
Definition WorldSession.h:502
#define sWorld
Definition World.h:337
Milliseconds GetGameTimeMS()
Definition GameTime.cpp:44
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(), GetExpectedResult(), GameTime::GetGameTimeMS(), GetNameByLocaleConstant(), WorldSession::GetSessionDbLocaleIndex(), 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(), ByteBuffer::rfinish(), ByteBuffer::rpos(), Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES, ByteBuffer::size(), sWardenCheckMgr, sWorld, WardenCheck::Type, WardenPayloadMgr::WardenPayloadOffsetMin, and ByteBuffer::wpos().

◆ HandleHashResult()

void WardenWin::HandleHashResult ( ByteBuffer &  buff)
overridevirtual

Implements Warden.

232{
233 buff.rpos(buff.wpos());
234
235 // Verify key using constant-time comparison
237 {
238 LOG_DEBUG("warden", "Request hash reply: failed");
239 ApplyPenalty(0, "Request hash reply: failed");
240 return;
241 }
242
243 LOG_DEBUG("warden", "Request hash reply: succeed");
244
245 // Change keys here
246 memcpy(_inputKey, Module.ClientKeySeed, 16);
247 memcpy(_outputKey, Module.ServerKeySeed, 16);
248
251
252 _initialized = true;
253}
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.

115{
116 _session = session;
117 // Generate Warden Key
119 WK.Generate(_inputKey, 16);
120 WK.Generate(_outputKey, 16);
121
122 memcpy(_seed, Module.Seed, 16);
123
126 LOG_DEBUG("warden", "Server side warden for client {} initializing...", session->GetAccountId());
127 LOG_DEBUG("warden", "C->S Key: {}", Acore::Impl::ByteArrayToHexStr(_inputKey, 16));
128 LOG_DEBUG("warden", "S->C Key: {}", Acore::Impl::ByteArrayToHexStr(_outputKey,16));
129 LOG_DEBUG("warden", " Seed: {}", Acore::Impl::ByteArrayToHexStr(_seed, 16));
130 LOG_DEBUG("warden", "Loading Module...");
131
133
134 LOG_DEBUG("warden", "Module Key: {}", ByteArrayToHexStr(_module->Key));
135 LOG_DEBUG("warden", "Module ID: {}", ByteArrayToHexStr(_module->Id));
137}
std::string ByteArrayToHexStr(Container const &c, bool reverse=false)
Definition Util.h:372
Definition SessionKeyGenerator.h:23
ClientWardenModule * GetModuleForClient() override
Definition WardenWin.cpp:139
uint8 _seed[16]
Definition Warden.h:142
void RequestModule()
Definition Warden.cpp:76
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.

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

260{
261 return _checkInProgress;
262}

References Warden::_checkInProgress.

◆ RequestChecks()

void WardenWin::RequestChecks ( )
overridevirtual

Implements Warden.

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

215{
216 LOG_DEBUG("warden", "Request hash");
217
218 // Create packet structure
219 WardenHashRequest Request{};
221 memcpy(Request.Seed, _seed, 16);
222
223 // Encrypt with warden RC4 key.
224 EncryptData(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest));
225
227 pkt.append(reinterpret_cast<uint8*>(&Request), sizeof(WardenHashRequest));
228 _session->SendPacket(&pkt);
229}
@ 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: