mirror of
https://github.com/mangosone/server
synced 2026-08-18 22:26:15 -04:00
Remove legacy Warden runtime and preserve protocol boundary (#165)
* redesign: remove legacy Warden runtime * fix: align prepared Warden schema dependencies * fix: advance shared realmd locale follow-ups * fix: add standard headers to Warden removal sources * fix: remove stale Warden ARC4 commentary * fix: advance shared realmd patch test linkage * fix: preserve client OS admission without Warden * build: repoint realmd after squash merge
This commit is contained in:
parent
1b4682bcf4
commit
c13398162b
35 changed files with 265 additions and 4632 deletions
|
|
@ -68,14 +68,6 @@ source_group("Tool" FILES ${SRC_GRP_TOOL})
|
|||
|
||||
|
||||
|
||||
#Warden group
|
||||
file(GLOB SRC_GRP_WARDEN Warden/*.cpp Warden/*.h)
|
||||
source_group("Warden" FILES ${SRC_GRP_WARDEN})
|
||||
|
||||
#Warden Modules group
|
||||
file(GLOB SRC_GRP_WARDEN_MODULES Warden/Modules/*.cpp Warden/Modules/*.h)
|
||||
source_group("Warden\\Modules" FILES ${SRC_GRP_WARDEN_MODULES})
|
||||
|
||||
#World and Handlers group
|
||||
file(GLOB SRC_GRP_WORLD_HANDLERS WorldHandlers/*.cpp WorldHandlers/*.h)
|
||||
source_group("World\\Handlers" FILES ${SRC_GRP_WORLD_HANDLERS})
|
||||
|
|
@ -206,8 +198,6 @@ add_library(game STATIC
|
|||
${SRC_GRP_SERVER}
|
||||
${SRC_GRP_TIME}
|
||||
${SRC_GRP_TOOL}
|
||||
${SRC_GRP_WARDEN}
|
||||
${SRC_GRP_WARDEN_MODULES}
|
||||
${SRC_GRP_WORLD_HANDLERS}
|
||||
$<$<BOOL:${SCRIPT_LIB_ELUNA}>:${SRC_GRP_ELUNA}>
|
||||
$<$<BOOL:${PLAYERBOTS}>:${SRC_GRP_BOTS}>
|
||||
|
|
@ -234,8 +224,6 @@ target_include_directories(game
|
|||
Server
|
||||
Time
|
||||
Tools
|
||||
Warden
|
||||
Warden/Modules
|
||||
WorldHandlers
|
||||
$<$<BOOL:${SCRIPT_LIB_ELUNA}>:
|
||||
${CMAKE_SOURCE_DIR}/src/modules/Eluna
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@
|
|||
#include "SharedDefines.h"
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldGatewayAccount.h"
|
||||
|
||||
#ifdef ENABLE_ELUNA
|
||||
#include "LuaEngine.h"
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <openssl/crypto.h>
|
||||
#include <string>
|
||||
|
|
@ -33,7 +33,6 @@ struct AccountRow final : proto::AuthContext
|
|||
uint8 expansion = 0;
|
||||
time_t muteTime = 0;
|
||||
LocaleConstant locale = LOCALE_enUS;
|
||||
std::string os;
|
||||
BigNumber sessionKey;
|
||||
};
|
||||
|
||||
|
|
@ -105,14 +104,16 @@ proto::AuthLookup WorldGateway::LookupAccount(const proto::AuthRequest& request)
|
|||
return Rejected(proto::AuthStatus::UnknownAccount);
|
||||
|
||||
Field const* fields = result->Fetch();
|
||||
if (fields[11].GetUInt32() || fields[12].GetUInt32())
|
||||
AccountRestriction const restriction =
|
||||
EvaluateAccountRestriction(fields, request.peerAddress);
|
||||
if (restriction == AccountRestriction::Banned)
|
||||
return Rejected(proto::AuthStatus::Banned);
|
||||
|
||||
if (fields[4].GetBool()
|
||||
&& std::strcmp(fields[3].GetString(), request.peerAddress.c_str()) != 0)
|
||||
{
|
||||
if (restriction == AccountRestriction::LockedAddressMismatch)
|
||||
return Rejected(proto::AuthStatus::Failed);
|
||||
}
|
||||
|
||||
if (restriction == AccountRestriction::UnsupportedOperatingSystem)
|
||||
return Rejected(proto::AuthStatus::Reject);
|
||||
|
||||
uint32 security = fields[1].GetUInt16();
|
||||
if (security > SEC_ADMINISTRATOR)
|
||||
|
|
@ -122,12 +123,6 @@ proto::AuthLookup WorldGateway::LookupAccount(const proto::AuthRequest& request)
|
|||
if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
|
||||
return Rejected(proto::AuthStatus::Unavailable);
|
||||
|
||||
std::string const os = fields[10].GetString();
|
||||
bool const wardenActive = sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED)
|
||||
|| sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED);
|
||||
if (wardenActive && os != "Win" && os != "OSX")
|
||||
return Rejected(proto::AuthStatus::Reject);
|
||||
|
||||
auto row = std::make_shared<AccountRow>();
|
||||
row->id = fields[0].GetUInt32();
|
||||
row->security = AccountTypes(security);
|
||||
|
|
@ -136,7 +131,6 @@ proto::AuthLookup WorldGateway::LookupAccount(const proto::AuthRequest& request)
|
|||
row->muteTime = time_t(fields[8].GetUInt64());
|
||||
uint8 const locale = fields[9].GetUInt8();
|
||||
row->locale = locale >= MAX_LOCALE ? LOCALE_enUS : LocaleConstant(locale);
|
||||
row->os = os;
|
||||
row->sessionKey.SetHexStr(fields[2].GetString());
|
||||
|
||||
BigNumber verifier;
|
||||
|
|
@ -181,11 +175,6 @@ proto::SessionId WorldGateway::Attach(const proto::AuthRequest& request,
|
|||
if (!request.addonData.empty())
|
||||
addonSource.append(request.addonData.data(), request.addonData.size());
|
||||
|
||||
bool const wardenActive = sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED)
|
||||
|| sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED);
|
||||
if (wardenActive)
|
||||
session->InitWarden(uint16(request.build), &account->sessionKey, account->os);
|
||||
|
||||
WorldPacket addonResponse;
|
||||
if (sAddOnHandler.BuildAddonPacket(&addonSource, &addonResponse))
|
||||
{
|
||||
|
|
|
|||
68
src/game/Server/WorldGatewayAccount.cpp
Normal file
68
src/game/Server/WorldGatewayAccount.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "WorldGatewayAccount.h"
|
||||
#include "Database/Field.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
enum AccountFieldIndex
|
||||
{
|
||||
ACCOUNT_ID = 0,
|
||||
ACCOUNT_SECURITY = 1,
|
||||
ACCOUNT_SESSION_KEY = 2,
|
||||
ACCOUNT_LAST_IP = 3,
|
||||
ACCOUNT_LOCKED = 4,
|
||||
ACCOUNT_VERIFIER = 5,
|
||||
ACCOUNT_SALT = 6,
|
||||
ACCOUNT_EXPANSION = 7,
|
||||
ACCOUNT_MUTE_TIME = 8,
|
||||
ACCOUNT_LOCALE = 9,
|
||||
ACCOUNT_OPERATING_SYSTEM = 10,
|
||||
ACCOUNT_BANNED = 11,
|
||||
IP_BANNED = 12,
|
||||
ACCOUNT_FIELD_COUNT = 13
|
||||
};
|
||||
}
|
||||
|
||||
AccountRestriction EvaluateAccountRestriction(
|
||||
Field const* fields, std::string const& peerAddress)
|
||||
{
|
||||
if (fields[ACCOUNT_BANNED].GetUInt32() || fields[IP_BANNED].GetUInt32())
|
||||
return AccountRestriction::Banned;
|
||||
|
||||
if (fields[ACCOUNT_LOCKED].GetBool()
|
||||
&& fields[ACCOUNT_LAST_IP].GetCppString() != peerAddress)
|
||||
{
|
||||
return AccountRestriction::LockedAddressMismatch;
|
||||
}
|
||||
|
||||
std::string const operatingSystem =
|
||||
fields[ACCOUNT_OPERATING_SYSTEM].GetCppString();
|
||||
if (operatingSystem != "Win" && operatingSystem != "OSX")
|
||||
return AccountRestriction::UnsupportedOperatingSystem;
|
||||
|
||||
return AccountRestriction::None;
|
||||
}
|
||||
44
src/game/Server/WorldGatewayAccount.h
Normal file
44
src/game/Server/WorldGatewayAccount.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MANGOS_H_WORLDGATEWAY_ACCOUNT
|
||||
#define MANGOS_H_WORLDGATEWAY_ACCOUNT
|
||||
|
||||
#include <string>
|
||||
|
||||
class Field;
|
||||
|
||||
enum class AccountRestriction
|
||||
{
|
||||
None,
|
||||
Banned,
|
||||
LockedAddressMismatch,
|
||||
UnsupportedOperatingSystem
|
||||
};
|
||||
|
||||
AccountRestriction EvaluateAccountRestriction(
|
||||
Field const* fields, std::string const& peerAddress);
|
||||
|
||||
#endif
|
||||
|
|
@ -35,7 +35,6 @@
|
|||
* - Character management
|
||||
* - Movement and action handling
|
||||
* - Chat and social interactions
|
||||
* - Warden anti-cheat integration
|
||||
*
|
||||
* The session filters packets based on thread safety and context:
|
||||
* - Map::Update() context: Only process thread-safe packets
|
||||
|
|
@ -74,9 +73,6 @@
|
|||
#include "playerbot.h"
|
||||
#endif
|
||||
|
||||
// Warden
|
||||
#include "WardenWin.h"
|
||||
#include "WardenMac.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
|
|
@ -173,7 +169,7 @@ WorldSession::WorldSession(uint32 id, std::shared_ptr<proto::IClientLink> link,
|
|||
LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time),
|
||||
_player(NULL), m_link(std::move(link)),
|
||||
m_mailbox(mailbox ? std::move(mailbox) : std::make_shared<SessionMailbox>()),
|
||||
_security(sec), _accountId(id), m_expansion(expansion), _warden(NULL), _build(0), _logoutTime(0),
|
||||
_security(sec), _accountId(id), m_expansion(expansion), _logoutTime(0),
|
||||
m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_playerSave(false),
|
||||
m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(sObjectMgr.GetIndexForLocale(locale)),
|
||||
m_latency(0), m_tutorialState(TUTORIALDATA_UNCHANGED), m_clientTimeDelay(0),
|
||||
|
|
@ -206,12 +202,6 @@ WorldSession::~WorldSession()
|
|||
m_link.reset();
|
||||
}
|
||||
|
||||
// Warden
|
||||
if (_warden)
|
||||
{
|
||||
delete _warden;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -476,12 +466,6 @@ bool WorldSession::Update(PacketFilter& updater)
|
|||
m_link.reset();
|
||||
}
|
||||
|
||||
// Warden
|
||||
if (m_link && !m_link->IsClosed() && _warden)
|
||||
{
|
||||
_warden->Update();
|
||||
}
|
||||
|
||||
// check if we are safe to proceed with logout
|
||||
// logout procedure should happen only in World::UpdateSessions() method!!!
|
||||
if (updater.ProcessLogout())
|
||||
|
|
@ -493,12 +477,6 @@ bool WorldSession::Update(PacketFilter& updater)
|
|||
LogoutPlayer(true);
|
||||
}
|
||||
|
||||
// Warden
|
||||
if (m_link && GetPlayer() && _warden)
|
||||
{
|
||||
_warden->Update();
|
||||
}
|
||||
|
||||
if (!m_link)
|
||||
{
|
||||
return false; // Will remove this session from the world session map
|
||||
|
|
@ -1155,29 +1133,6 @@ void WorldSession::SendPlaySpellVisual(ObjectGuid guid, uint32 spellArtKit)
|
|||
SendPacket(&data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes Warden for the authenticated client platform.
|
||||
*
|
||||
* @param build The client build number.
|
||||
* @param k The session key material.
|
||||
* @param os The reported client operating system.
|
||||
*/
|
||||
void WorldSession::InitWarden(uint16 build, BigNumber* k, std::string const& os)
|
||||
{
|
||||
_build = build;
|
||||
|
||||
if (os == "Win" && sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED))
|
||||
{
|
||||
_warden = new WardenWin();
|
||||
_warden->Init(this, k);
|
||||
}
|
||||
else if (os == "OSX" && sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED))
|
||||
{
|
||||
_warden = new WardenMac();
|
||||
_warden->Init(this, k);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::ResetClientTimeDelay()
|
||||
{
|
||||
m_clientTimeDelay = 0;
|
||||
|
|
@ -1253,4 +1208,3 @@ void WorldSession::AdjustMovementInfoTime(MovementInfo& mi)
|
|||
+ int64(sWorld.getConfig(CONFIG_UINT32_MOVEMENT_PACKET_DELAY));
|
||||
mi.UpdateTime(uint32(wire));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ class Item;
|
|||
class Object;
|
||||
class Player;
|
||||
class Unit;
|
||||
class Warden;
|
||||
class WorldPacket;
|
||||
class SessionMailbox;
|
||||
class QueryResult;
|
||||
|
|
@ -357,9 +356,6 @@ class WorldSession
|
|||
}
|
||||
uint8 Expansion() const { return m_expansion; }
|
||||
|
||||
// Warden
|
||||
void InitWarden(uint16 build, BigNumber* k, std::string const& os);
|
||||
|
||||
/// Session in auth.queue currently
|
||||
void SetInQueue(bool state)
|
||||
{
|
||||
|
|
@ -950,9 +946,6 @@ class WorldSession
|
|||
void HandleBotPackets();
|
||||
#endif
|
||||
|
||||
// for Warden
|
||||
uint16 GetClientBuild() const { return _build; }
|
||||
|
||||
// Guild Bank
|
||||
void HandleGuildPermissions(WorldPacket& recv_data);
|
||||
void HandleGuildBankMoneyWithdrawn(WorldPacket& recv_data);
|
||||
|
|
@ -998,10 +991,6 @@ class WorldSession
|
|||
uint32 _accountId;
|
||||
uint8 m_expansion;
|
||||
|
||||
// Warden
|
||||
Warden* _warden; // Remains NULL if Warden system is not enabled by config
|
||||
uint16 _build; // connected client build
|
||||
|
||||
time_t _logoutTime;
|
||||
bool m_inQueue; // session wait in auth.queue
|
||||
bool m_playerLoading; // code processed in LoginPlayer
|
||||
|
|
|
|||
|
|
@ -1,624 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _WARDEN_MODULE_MAC_H
|
||||
#define _WARDEN_MODULE_MAC_H
|
||||
|
||||
#include "Platform/Define.h"
|
||||
|
||||
uint8 Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data[9318] =
|
||||
{
|
||||
0x07, 0x0C, 0x44, 0xCD, 0xC9, 0xFB, 0x99, 0xBC, 0x7C, 0x77, 0xDC, 0xE8, 0x8D, 0x07, 0xBE, 0x55,
|
||||
0x37, 0x5C, 0x84, 0x10, 0x23, 0xE1, 0x36, 0x5B, 0xF1, 0xBC, 0x60, 0xF3, 0x68, 0xBA, 0x60, 0x69,
|
||||
0xDF, 0x48, 0x54, 0xFF, 0x49, 0x1F, 0xA6, 0x28, 0x08, 0x5A, 0x77, 0xFE, 0x4C, 0x3A, 0x9A, 0x28,
|
||||
0xA5, 0x9E, 0x01, 0x93, 0x05, 0xE4, 0xCD, 0x26, 0x41, 0xD7, 0xD6, 0x73, 0x81, 0xFD, 0xF5, 0xDB,
|
||||
0xA5, 0xF7, 0xF9, 0x1D, 0xFE, 0xF4, 0x06, 0x7C, 0xD0, 0xF8, 0x5A, 0xE8, 0x11, 0xFF, 0xE5, 0xF9,
|
||||
0x54, 0x49, 0xF7, 0xF0, 0xF8, 0x66, 0x22, 0x97, 0xA4, 0xB2, 0x86, 0xFE, 0xA6, 0x3A, 0x7F, 0x3B,
|
||||
0xF6, 0x47, 0xB4, 0x14, 0xEB, 0x9E, 0xC9, 0xEA, 0x0B, 0x41, 0xB4, 0x5B, 0xC2, 0xFB, 0x63, 0x1C,
|
||||
0x46, 0xC4, 0xAB, 0x3F, 0x30, 0x70, 0x7F, 0x35, 0xA3, 0xD2, 0x1A, 0xDE, 0x36, 0x79, 0x02, 0x05,
|
||||
0x0E, 0x47, 0xFF, 0xDF, 0x1F, 0xB7, 0xE0, 0x11, 0x7F, 0xB8, 0x43, 0x8C, 0x46, 0xF0, 0x4D, 0x39,
|
||||
0x83, 0x7C, 0x44, 0xE7, 0xD0, 0x02, 0x54, 0xAB, 0x84, 0xB3, 0x64, 0xCA, 0xD2, 0xB6, 0xF5, 0xDC,
|
||||
0x06, 0x2B, 0x39, 0x27, 0x5B, 0x18, 0x82, 0xC4, 0xD6, 0x95, 0xB1, 0xDE, 0x2F, 0x0C, 0xAD, 0x96,
|
||||
0x12, 0xBF, 0x82, 0x0B, 0x78, 0x77, 0x7B, 0x42, 0x96, 0x87, 0xF6, 0x7B, 0xE2, 0x0B, 0x36, 0x2C,
|
||||
0x34, 0xCD, 0xFA, 0x01, 0x60, 0x3F, 0x52, 0x9B, 0xAB, 0xAC, 0x25, 0xF1, 0xDE, 0xD0, 0x61, 0x12,
|
||||
0x21, 0xF2, 0xDE, 0xB7, 0xA4, 0x5F, 0x5F, 0xA2, 0xA7, 0x31, 0xAC, 0x2D, 0xA3, 0x42, 0xCF, 0x73,
|
||||
0x88, 0x53, 0x02, 0x60, 0x9A, 0x11, 0xCB, 0xDF, 0xB9, 0x97, 0x10, 0x3F, 0xBD, 0xF6, 0x14, 0x38,
|
||||
0x1D, 0xAD, 0xC5, 0x22, 0x99, 0x40, 0x1C, 0xA3, 0x3D, 0x2E, 0x2E, 0x93, 0x70, 0xE4, 0x5B, 0x3E,
|
||||
0x9E, 0xDC, 0x6E, 0x4D, 0xC2, 0xDA, 0x2D, 0x54, 0x4A, 0xDF, 0xFD, 0x30, 0x4C, 0xAF, 0x5D, 0xDE,
|
||||
0xEB, 0xFF, 0xCF, 0xE3, 0x9A, 0x3C, 0x4F, 0xB3, 0x7D, 0x61, 0xEB, 0x66, 0xD8, 0xBC, 0x12, 0xC1,
|
||||
0xD4, 0x66, 0xBD, 0x89, 0x64, 0x8E, 0x68, 0xA6, 0xD4, 0xDC, 0xA4, 0x00, 0x84, 0x9A, 0x53, 0x1E,
|
||||
0x4D, 0x1B, 0x84, 0x19, 0xF8, 0x0A, 0x85, 0x96, 0x99, 0x64, 0xEB, 0xAE, 0x11, 0xFB, 0xC8, 0xBB,
|
||||
0xC0, 0x8E, 0x5B, 0x8E, 0xE3, 0x95, 0x50, 0x8A, 0xD4, 0x68, 0x0A, 0x11, 0xED, 0xC2, 0x8F, 0x87,
|
||||
0xA7, 0x3F, 0xB4, 0x99, 0xDF, 0x37, 0xF6, 0x4F, 0x32, 0x4E, 0x0B, 0x99, 0x35, 0xD0, 0x1E, 0x40,
|
||||
0x00, 0x8C, 0x3C, 0xCE, 0xC8, 0xE3, 0x89, 0x7B, 0x09, 0xA3, 0xA7, 0x35, 0x5B, 0x2B, 0x82, 0x98,
|
||||
0xC3, 0xEE, 0xD8, 0xAF, 0x59, 0x0C, 0xFB, 0x28, 0x57, 0x21, 0x79, 0x33, 0xDC, 0x3E, 0xD7, 0x66,
|
||||
0x02, 0x47, 0xC1, 0x1E, 0xB8, 0x85, 0x28, 0x1A, 0x1C, 0x5C, 0xA2, 0x11, 0x18, 0x9C, 0xB7, 0x54,
|
||||
0x4B, 0x97, 0x6D, 0x90, 0x93, 0x31, 0x6C, 0x07, 0x3B, 0xE9, 0x35, 0xD7, 0x3B, 0x59, 0x7A, 0x5B,
|
||||
0xEC, 0xE1, 0x63, 0xC4, 0xB6, 0x1A, 0x97, 0xEE, 0x1A, 0xD0, 0xF5, 0xF6, 0xBF, 0x10, 0x55, 0xCB,
|
||||
0x7F, 0xF7, 0x3C, 0x2D, 0x7D, 0xDF, 0x5C, 0xE1, 0x84, 0xF1, 0xD5, 0x87, 0x05, 0xEE, 0x94, 0xE3,
|
||||
0x55, 0xF3, 0x8B, 0xD1, 0x4B, 0xBF, 0x7E, 0x93, 0xEB, 0xAB, 0x09, 0x36, 0x3E, 0x8D, 0xA6, 0x90,
|
||||
0xC5, 0x2E, 0x0A, 0xF4, 0x2B, 0x9E, 0xBC, 0xDA, 0xC1, 0x3A, 0x77, 0x96, 0x8E, 0xA2, 0x28, 0x53,
|
||||
0x0B, 0x37, 0xEC, 0x3F, 0xA6, 0xED, 0xF7, 0x32, 0x3A, 0x7D, 0xE5, 0x64, 0x1C, 0xAE, 0x6B, 0xB4,
|
||||
0x08, 0xDA, 0xCD, 0x3E, 0x32, 0xC7, 0x0F, 0xDF, 0xDE, 0x9D, 0x4D, 0x20, 0xE0, 0x71, 0x7C, 0xB7,
|
||||
0xAF, 0x87, 0x99, 0x4B, 0xCC, 0x3B, 0xFB, 0x26, 0xAA, 0x01, 0xF3, 0x77, 0x01, 0x7E, 0x8C, 0x0D,
|
||||
0x09, 0x9D, 0x40, 0xFD, 0x3D, 0xA1, 0xEA, 0x53, 0x99, 0x68, 0x87, 0xE2, 0xCA, 0x1B, 0x1F, 0x45,
|
||||
0x83, 0xF1, 0x74, 0xBB, 0x65, 0x49, 0x46, 0xD2, 0x43, 0xDA, 0xE1, 0x4D, 0x29, 0x3A, 0x41, 0x81,
|
||||
0xF6, 0x46, 0x03, 0x43, 0x19, 0xBA, 0x2F, 0x79, 0xF0, 0xA3, 0xB4, 0x92, 0x08, 0x74, 0xE0, 0x61,
|
||||
0x0F, 0x26, 0xEF, 0xDE, 0x3B, 0x52, 0x9F, 0xB4, 0x06, 0x5D, 0xC6, 0xBC, 0x3C, 0xA5, 0x86, 0x7C,
|
||||
0x35, 0x21, 0xF7, 0x05, 0xCD, 0x05, 0x15, 0x31, 0xE0, 0xC0, 0xF6, 0x12, 0x70, 0x56, 0xF9, 0x25,
|
||||
0xB7, 0x91, 0x34, 0x85, 0x5D, 0xE9, 0x5D, 0xB8, 0x4F, 0x4C, 0xFB, 0xB5, 0xB6, 0x2F, 0xAE, 0xA3,
|
||||
0x2A, 0x99, 0x25, 0x4D, 0x17, 0x41, 0x47, 0xC3, 0xF5, 0x04, 0x52, 0xCC, 0xDE, 0x4E, 0xA3, 0x42,
|
||||
0x30, 0x19, 0xA5, 0xD5, 0x94, 0x46, 0xC0, 0x78, 0xF7, 0x7D, 0xD9, 0x9D, 0x0A, 0xCF, 0xEE, 0x0C,
|
||||
0x5C, 0x92, 0x85, 0x10, 0xF5, 0xEC, 0x2E, 0x48, 0xC1, 0x35, 0x86, 0x1E, 0x6A, 0xBE, 0xF0, 0x89,
|
||||
0x64, 0xF7, 0x4A, 0x71, 0xE7, 0x10, 0x6B, 0xEC, 0xC0, 0xC9, 0xB7, 0x94, 0x66, 0x27, 0x22, 0x2D,
|
||||
0xA2, 0x94, 0xAB, 0xBE, 0x36, 0xAC, 0x76, 0xB9, 0x2D, 0x8A, 0x04, 0xEF, 0x08, 0x3D, 0xA7, 0x9A,
|
||||
0xC7, 0x73, 0x78, 0xB2, 0xCD, 0x9E, 0x59, 0x90, 0x39, 0x1E, 0x54, 0x51, 0x18, 0x25, 0x22, 0x2A,
|
||||
0x38, 0x20, 0x73, 0xF1, 0x7F, 0x01, 0x07, 0x81, 0xA9, 0x3F, 0xE8, 0x90, 0x9C, 0xF6, 0x45, 0x14,
|
||||
0x8D, 0x82, 0xCB, 0xB0, 0x7D, 0x77, 0xA5, 0x97, 0x34, 0x81, 0x28, 0x6C, 0x1B, 0x0F, 0x60, 0x4B,
|
||||
0x35, 0xC5, 0x1C, 0xE4, 0xE2, 0x4C, 0x0A, 0xE1, 0xF9, 0xD0, 0xE8, 0xCC, 0x18, 0x25, 0xF6, 0xA0,
|
||||
0x41, 0xDF, 0x9B, 0x68, 0x75, 0x64, 0x0D, 0xE3, 0x1F, 0xA4, 0xA7, 0xFF, 0x02, 0xB5, 0x68, 0xA3,
|
||||
0x62, 0xAE, 0xD2, 0x1D, 0x36, 0x37, 0x18, 0x6C, 0xCE, 0x20, 0x25, 0xAF, 0xDD, 0x20, 0xB5, 0xF4,
|
||||
0xCF, 0x05, 0x3B, 0xF0, 0xD7, 0xB0, 0x43, 0xDB, 0xD7, 0xC7, 0x87, 0x1D, 0xD6, 0xD1, 0xD0, 0x33,
|
||||
0x20, 0x66, 0x10, 0x3C, 0x5E, 0x9D, 0xA8, 0x21, 0x48, 0x31, 0x65, 0x4C, 0xBD, 0xF5, 0x40, 0x97,
|
||||
0xC8, 0x0A, 0x87, 0x25, 0x0C, 0x54, 0x35, 0xCE, 0xEC, 0x76, 0xE8, 0xAD, 0x95, 0xCD, 0xC6, 0x7E,
|
||||
0xCD, 0x7C, 0xFD, 0x5F, 0x5B, 0xD6, 0x6B, 0xC6, 0xC4, 0x26, 0xA9, 0x16, 0xD7, 0xC8, 0xCE, 0x9E,
|
||||
0x3E, 0xB0, 0x81, 0xA1, 0x9A, 0xBE, 0x8A, 0xF9, 0x7D, 0xB0, 0x1B, 0x03, 0x9B, 0xBA, 0xF7, 0xF5,
|
||||
0x74, 0x13, 0x0F, 0x44, 0x51, 0x98, 0xAC, 0x56, 0x69, 0x24, 0xB1, 0xEA, 0xCD, 0x27, 0x25, 0xE5,
|
||||
0x58, 0x26, 0xCA, 0x44, 0xBA, 0x6D, 0xAA, 0x6E, 0x2F, 0xC8, 0x5E, 0x18, 0x6F, 0x08, 0xA0, 0xE8,
|
||||
0x57, 0xFB, 0x77, 0x99, 0x8A, 0xBD, 0x56, 0x1D, 0xD2, 0xD8, 0x63, 0x7A, 0xCE, 0xD3, 0xC9, 0xE2,
|
||||
0x99, 0xC2, 0x96, 0xB8, 0x8E, 0x88, 0x09, 0x80, 0xC6, 0x9A, 0xC3, 0xC5, 0xFB, 0xF5, 0x3C, 0x90,
|
||||
0x70, 0xAB, 0xF1, 0xA6, 0x80, 0x17, 0x2A, 0x25, 0xD3, 0xD2, 0x2B, 0xEE, 0xF5, 0xD2, 0x7F, 0xBD,
|
||||
0x2D, 0x83, 0xCC, 0x2A, 0x8C, 0xE2, 0xB4, 0xC4, 0xF4, 0x84, 0x34, 0x68, 0x04, 0xAD, 0x62, 0x27,
|
||||
0xE5, 0x19, 0x40, 0x17, 0xD7, 0x0A, 0xC4, 0x0A, 0x7E, 0x24, 0xBB, 0x38, 0xBC, 0xA3, 0x3B, 0x4A,
|
||||
0x58, 0x7C, 0x6B, 0xD2, 0x29, 0x46, 0xD6, 0xCF, 0x1C, 0x4B, 0xCC, 0x4E, 0x99, 0x28, 0xFC, 0x10,
|
||||
0xB1, 0x8B, 0x59, 0xF8, 0x2B, 0x6F, 0x43, 0x67, 0x01, 0x24, 0xFB, 0xCA, 0xB4, 0xBD, 0x35, 0x4B,
|
||||
0x7D, 0x50, 0xC0, 0x83, 0xD4, 0xB9, 0xC7, 0x37, 0x45, 0xB9, 0x24, 0xD7, 0x6D, 0x9D, 0xA6, 0x9C,
|
||||
0x7C, 0x1F, 0xE6, 0xB9, 0x97, 0x2C, 0x47, 0x5E, 0xCA, 0x30, 0xEB, 0xE5, 0xFD, 0x70, 0xD2, 0x37,
|
||||
0xE7, 0x6A, 0x3A, 0xEF, 0x00, 0xCF, 0x10, 0xF3, 0x3B, 0xA1, 0x62, 0xF0, 0x7D, 0xEA, 0x32, 0x50,
|
||||
0x87, 0x73, 0xAC, 0xB5, 0x61, 0x85, 0x6D, 0xDD, 0xD9, 0xD8, 0x84, 0xCD, 0x23, 0x3F, 0x11, 0x63,
|
||||
0xB1, 0xAB, 0xDF, 0x37, 0xAF, 0x84, 0x7C, 0x12, 0x77, 0x41, 0xFF, 0xF1, 0xF7, 0x5F, 0xF5, 0x40,
|
||||
0x23, 0xE1, 0x07, 0xC6, 0x89, 0x95, 0xF3, 0xA8, 0x5F, 0x1C, 0xE4, 0xE3, 0x86, 0x04, 0xD2, 0x17,
|
||||
0x52, 0xA3, 0x74, 0x51, 0x53, 0x6E, 0x44, 0x42, 0x92, 0x10, 0xBD, 0x7F, 0x5A, 0x13, 0x14, 0x85,
|
||||
0x59, 0x08, 0xF2, 0x87, 0x9A, 0x20, 0x98, 0xE8, 0x2E, 0xF1, 0x0F, 0x3D, 0x42, 0x79, 0x75, 0x88,
|
||||
0x45, 0x19, 0x8E, 0x6B, 0xF0, 0xCE, 0x22, 0x47, 0x30, 0x29, 0xC1, 0x94, 0xFE, 0x79, 0x4E, 0xDC,
|
||||
0xE3, 0x7F, 0x00, 0x4E, 0x67, 0x7D, 0xD7, 0x84, 0x2A, 0x01, 0x4E, 0x17, 0x07, 0x17, 0xD7, 0x1E,
|
||||
0x4D, 0xC5, 0x0B, 0x1C, 0x76, 0x8F, 0x02, 0x33, 0x26, 0xC6, 0x75, 0x35, 0xD2, 0x76, 0xAD, 0x8C,
|
||||
0xE9, 0x08, 0x9E, 0xCD, 0x07, 0x72, 0x3A, 0x61, 0x29, 0x2C, 0x99, 0xB9, 0x72, 0x6F, 0xF7, 0x69,
|
||||
0xAF, 0xEA, 0x3E, 0x56, 0xBE, 0xD8, 0x3A, 0xD7, 0xFC, 0x86, 0xE7, 0xB8, 0x45, 0x37, 0xF7, 0xE0,
|
||||
0x47, 0xD4, 0x0B, 0x36, 0xD4, 0xF1, 0x4B, 0x28, 0x2B, 0xE5, 0x1E, 0xB1, 0x06, 0x5B, 0x39, 0x59,
|
||||
0x34, 0x3D, 0x05, 0x23, 0x49, 0x8D, 0x9D, 0xC9, 0xEA, 0xC3, 0x42, 0x00, 0x65, 0x75, 0x09, 0xEC,
|
||||
0x30, 0xB6, 0xDB, 0xFB, 0x93, 0xFA, 0x93, 0x6D, 0x8D, 0xBE, 0xF5, 0x8D, 0x1E, 0x22, 0xB3, 0xAB,
|
||||
0x90, 0xB1, 0xA4, 0xE8, 0xCD, 0xB0, 0xBB, 0x2A, 0xF7, 0x39, 0xF2, 0x9C, 0x73, 0x18, 0xCF, 0xD4,
|
||||
0x14, 0xB5, 0xDD, 0x1A, 0x65, 0x6B, 0x47, 0x11, 0x16, 0xAD, 0xB4, 0xFC, 0xA3, 0x31, 0x56, 0xBD,
|
||||
0xBD, 0xB2, 0xC4, 0xCC, 0x39, 0xDA, 0x60, 0x86, 0x4E, 0x7F, 0x37, 0x99, 0xCF, 0x88, 0x47, 0x2A,
|
||||
0x1D, 0x09, 0xDA, 0xE1, 0x07, 0xF0, 0x1B, 0x97, 0x9E, 0x13, 0x43, 0x9E, 0x99, 0xA9, 0x2B, 0x1C,
|
||||
0x2D, 0xDB, 0xED, 0x0C, 0x58, 0xD2, 0xBE, 0x25, 0x25, 0x44, 0x62, 0x37, 0x7A, 0x50, 0x9A, 0x68,
|
||||
0x3E, 0x9A, 0xE5, 0xE2, 0xCA, 0x3F, 0xFF, 0x01, 0xF8, 0x17, 0xF4, 0xA8, 0xFF, 0x8E, 0x99, 0xDB,
|
||||
0x6E, 0x13, 0xD7, 0x7F, 0x1F, 0xDE, 0xDE, 0x2F, 0x9F, 0x37, 0x60, 0x41, 0xF0, 0xA0, 0xB7, 0x4F,
|
||||
0x80, 0x7D, 0xBA, 0xF9, 0xF1, 0xA6, 0x2C, 0x03, 0xD7, 0x3F, 0x3C, 0xC6, 0x45, 0x7C, 0xFF, 0x40,
|
||||
0x7C, 0x6D, 0x73, 0x6D, 0x42, 0x8F, 0x87, 0xDA, 0x66, 0xB3, 0xDF, 0x20, 0x17, 0x27, 0x86, 0x28,
|
||||
0xD6, 0x7F, 0x90, 0x0D, 0xFC, 0x62, 0x87, 0x59, 0x6B, 0x15, 0xB3, 0xBD, 0xF5, 0x15, 0x5F, 0x12,
|
||||
0x21, 0xE3, 0x50, 0x6A, 0xEA, 0x83, 0x9A, 0x1B, 0xC9, 0x29, 0x44, 0x32, 0xD7, 0x72, 0x68, 0x1B,
|
||||
0xA6, 0x1B, 0xDD, 0x65, 0xDB, 0x0A, 0xF7, 0xEE, 0xF1, 0xF2, 0xA6, 0x68, 0x6D, 0xEB, 0xB9, 0xF2,
|
||||
0x5A, 0xF9, 0xEE, 0xA3, 0xD0, 0xAE, 0xE2, 0x18, 0x29, 0xFF, 0xFD, 0x9B, 0x94, 0x6C, 0x03, 0xFC,
|
||||
0x3C, 0xF2, 0xEB, 0x3D, 0x50, 0x16, 0xA5, 0xB6, 0x64, 0x25, 0xFC, 0x3F, 0x79, 0xC0, 0x7F, 0x22,
|
||||
0x0C, 0x06, 0xFB, 0xAA, 0xAC, 0x2D, 0xC1, 0x1F, 0x24, 0x3F, 0x72, 0x87, 0xBE, 0xE5, 0xFD, 0x25,
|
||||
0x70, 0x65, 0x31, 0xA1, 0xD8, 0x63, 0xD3, 0xB6, 0x67, 0x99, 0xAF, 0xC4, 0x78, 0x44, 0xC7, 0x60,
|
||||
0x95, 0x9B, 0x2F, 0x3C, 0x0A, 0x44, 0xEB, 0x80, 0x34, 0x50, 0xE9, 0x01, 0x37, 0xF8, 0x55, 0x4D,
|
||||
0xE1, 0x73, 0x24, 0xC5, 0xF2, 0x9D, 0xCD, 0x70, 0x1A, 0x77, 0x57, 0x19, 0xF6, 0xA8, 0xEC, 0x69,
|
||||
0x25, 0xEF, 0xE4, 0xE2, 0x8C, 0x9A, 0x51, 0x90, 0x95, 0x21, 0xC5, 0xC1, 0x0C, 0xAD, 0x33, 0xF7,
|
||||
0x0E, 0xC5, 0xC4, 0xFF, 0x3D, 0xA9, 0xEA, 0x36, 0xCF, 0x15, 0x57, 0xB8, 0x37, 0xB7, 0x9A, 0x92,
|
||||
0x59, 0xDF, 0x91, 0x5C, 0x07, 0x78, 0xAD, 0xE6, 0xE0, 0x71, 0xD7, 0x17, 0x65, 0x8A, 0x62, 0x52,
|
||||
0x30, 0x95, 0xA1, 0xC5, 0x2F, 0xC7, 0x6D, 0x94, 0xDA, 0xA8, 0xFE, 0xF8, 0x28, 0x99, 0xC9, 0x9D,
|
||||
0x28, 0xFB, 0x6D, 0x22, 0xD0, 0x44, 0xAE, 0x02, 0x89, 0xEA, 0x93, 0xC6, 0x11, 0xC9, 0x19, 0x35,
|
||||
0x82, 0x7A, 0x76, 0x87, 0x9A, 0x5D, 0x39, 0x9E, 0x5A, 0x6B, 0x53, 0x45, 0x2F, 0x10, 0x6E, 0x86,
|
||||
0x95, 0xB5, 0x8F, 0x87, 0xB6, 0x37, 0x58, 0x48, 0x16, 0x01, 0x4D, 0xE1, 0xD1, 0x13, 0x21, 0xC3,
|
||||
0xAA, 0x8F, 0xDE, 0xE1, 0xFF, 0x5F, 0xEA, 0xBC, 0xBC, 0xDF, 0xF2, 0xB9, 0x0D, 0x96, 0x53, 0xF0,
|
||||
0x08, 0xB9, 0x01, 0x9E, 0x70, 0x87, 0xF3, 0x89, 0xFA, 0x1A, 0xB0, 0x06, 0xF3, 0xEC, 0x13, 0xC5,
|
||||
0x8D, 0x21, 0xF5, 0x2B, 0x47, 0x35, 0x48, 0x01, 0x34, 0xA2, 0x8D, 0x55, 0x24, 0x37, 0xFC, 0x5A,
|
||||
0x43, 0x0D, 0x0B, 0x3E, 0x0A, 0x95, 0x5B, 0xEF, 0x9F, 0x38, 0x41, 0x25, 0x52, 0xE3, 0x1C, 0xBF,
|
||||
0x7D, 0x3B, 0x1C, 0x32, 0x83, 0xBF, 0xBF, 0x69, 0xD2, 0xB5, 0x73, 0xD4, 0x5F, 0x4F, 0x0E, 0xBA,
|
||||
0xFF, 0x6C, 0xB6, 0xB4, 0xBB, 0x62, 0xD7, 0xEB, 0x5C, 0xC8, 0x44, 0x50, 0x38, 0xAD, 0x4F, 0xA0,
|
||||
0xB2, 0x90, 0x0F, 0x58, 0x2E, 0x93, 0x0F, 0xE8, 0xEB, 0x2F, 0x65, 0x76, 0x56, 0xD9, 0xDD, 0x79,
|
||||
0x75, 0xE1, 0xAD, 0x4A, 0x1A, 0x24, 0x5F, 0xE0, 0x82, 0x62, 0xF9, 0x96, 0x90, 0xD6, 0x4F, 0xFC,
|
||||
0xF6, 0x9E, 0xAE, 0x1C, 0xDA, 0x4D, 0x3B, 0xC4, 0x44, 0x4B, 0xAC, 0x69, 0xD7, 0x0E, 0x89, 0xAD,
|
||||
0xED, 0xF8, 0x6A, 0x8C, 0x4B, 0xAE, 0xC4, 0xEA, 0x02, 0x78, 0x0B, 0x41, 0xF6, 0x98, 0xE9, 0x1E,
|
||||
0xE2, 0x17, 0x0A, 0x0A, 0xA3, 0x1E, 0xE3, 0xF4, 0xEE, 0x7E, 0x3C, 0x81, 0x52, 0xCB, 0x2E, 0xF2,
|
||||
0x75, 0x0F, 0xD9, 0xD3, 0x58, 0xE0, 0xFF, 0x14, 0xA1, 0x4F, 0x7F, 0x19, 0xCA, 0xD1, 0xDA, 0x32,
|
||||
0x1F, 0xCD, 0x74, 0x41, 0x22, 0x8A, 0xBF, 0x96, 0x04, 0x35, 0xB7, 0x44, 0x86, 0x39, 0x59, 0xC6,
|
||||
0x96, 0x17, 0x99, 0x72, 0x72, 0xA1, 0x4E, 0x33, 0x65, 0x02, 0x1C, 0xA7, 0x1D, 0x6C, 0x24, 0xE1,
|
||||
0x85, 0x6A, 0x1E, 0x02, 0x88, 0xCE, 0x0E, 0x6D, 0x5F, 0x6B, 0x38, 0xD5, 0xA0, 0x5F, 0x15, 0x3C,
|
||||
0x4B, 0xBD, 0xD3, 0x6E, 0x0A, 0x70, 0x10, 0x3F, 0x6A, 0xB5, 0xAB, 0x72, 0x7D, 0x78, 0x42, 0x79,
|
||||
0x23, 0x16, 0x49, 0x4F, 0x97, 0x15, 0xF3, 0xA7, 0x6E, 0x73, 0x41, 0xB2, 0x78, 0x21, 0x3F, 0x32,
|
||||
0x17, 0x7F, 0x97, 0xBB, 0xA8, 0xDE, 0x17, 0xD6, 0xFB, 0x32, 0x95, 0x3D, 0x93, 0x07, 0x9D, 0xD2,
|
||||
0x5E, 0x99, 0xCD, 0x7C, 0x3E, 0x92, 0x1B, 0xCE, 0xA8, 0xA9, 0xAC, 0xF5, 0xFA, 0xAB, 0x23, 0xCB,
|
||||
0xA1, 0xD6, 0xF9, 0x09, 0x30, 0x5E, 0x7E, 0xF5, 0x24, 0x80, 0x5B, 0x5C, 0x5B, 0x3E, 0x76, 0xA6,
|
||||
0xE5, 0x21, 0x7E, 0xB3, 0x40, 0x5F, 0x75, 0xE7, 0x1D, 0x93, 0x41, 0x90, 0xF6, 0xAB, 0x98, 0x72,
|
||||
0x56, 0x8C, 0xFF, 0x06, 0xC5, 0x2C, 0xE0, 0xAE, 0xE6, 0xD0, 0x38, 0xC9, 0x3D, 0x88, 0x35, 0xF5,
|
||||
0x31, 0x36, 0x95, 0x49, 0x9C, 0x0C, 0x3F, 0x8D, 0xBC, 0xAA, 0xEC, 0x1B, 0x94, 0xCB, 0x77, 0x35,
|
||||
0xE8, 0xD8, 0xBF, 0x03, 0x81, 0xB2, 0x84, 0x06, 0x7C, 0x98, 0x58, 0x7D, 0x49, 0x7C, 0x87, 0xDF,
|
||||
0x69, 0xCB, 0xC7, 0xA4, 0x02, 0x68, 0xFD, 0x5F, 0x2C, 0x0B, 0xEB, 0xA5, 0x3A, 0xF3, 0x8F, 0x9A,
|
||||
0xA6, 0xA0, 0x10, 0x22, 0x05, 0x88, 0xFD, 0x85, 0x52, 0x14, 0x8F, 0x94, 0x2F, 0xA6, 0x1F, 0xE5,
|
||||
0x90, 0xE8, 0xFF, 0xEB, 0x1B, 0xD1, 0x76, 0x9B, 0xA2, 0x69, 0x83, 0x3F, 0x38, 0xC0, 0x58, 0x62,
|
||||
0xDA, 0x85, 0x7C, 0x59, 0xD1, 0xFD, 0x70, 0xCC, 0x16, 0xE8, 0xE5, 0x57, 0xBB, 0x2D, 0xE8, 0x99,
|
||||
0x5D, 0xC0, 0x9C, 0x07, 0x21, 0x56, 0x14, 0xEE, 0xA5, 0x28, 0x6B, 0x4E, 0x1A, 0x1E, 0x41, 0xBB,
|
||||
0x60, 0x63, 0x53, 0x5D, 0xAA, 0xB3, 0x9A, 0x7A, 0xB2, 0xAD, 0x6E, 0x2A, 0x2A, 0x6A, 0x00, 0xF7,
|
||||
0xEA, 0x92, 0xB8, 0x12, 0x73, 0x5D, 0xA7, 0x58, 0xA3, 0xE1, 0xB3, 0xB2, 0x6B, 0x79, 0x1E, 0xCD,
|
||||
0xD1, 0x1C, 0xFB, 0x89, 0xF9, 0xE5, 0xD8, 0xF9, 0x7C, 0xEA, 0xEF, 0x1D, 0x13, 0x86, 0x2E, 0xDD,
|
||||
0xFE, 0x52, 0x81, 0xC8, 0xF9, 0xE9, 0x42, 0x44, 0x36, 0x0B, 0x3C, 0xD9, 0x14, 0x09, 0x73, 0xCD,
|
||||
0x78, 0x19, 0xEF, 0x9D, 0xC5, 0x90, 0xB6, 0xE7, 0x45, 0x47, 0xEE, 0x0E, 0x7C, 0x0F, 0x5D, 0x4B,
|
||||
0xCC, 0x1D, 0x66, 0xC5, 0xC4, 0x4D, 0xAB, 0x55, 0xF0, 0x83, 0x68, 0xFE, 0x5C, 0xAB, 0x11, 0x71,
|
||||
0xB7, 0x45, 0xB4, 0x55, 0x1B, 0xDA, 0x77, 0x44, 0x07, 0x6A, 0x13, 0x99, 0xF4, 0x9D, 0x2B, 0xF8,
|
||||
0x78, 0x6B, 0x2E, 0x4C, 0x6B, 0xC5, 0x18, 0x9B, 0x7D, 0x26, 0xF8, 0x78, 0x53, 0x27, 0x14, 0x83,
|
||||
0x94, 0xA3, 0x9F, 0x5C, 0xAF, 0x84, 0x9B, 0x76, 0x9F, 0x77, 0xC8, 0x18, 0xA6, 0x00, 0x38, 0x67,
|
||||
0x6A, 0x08, 0xEE, 0xE3, 0x43, 0x3D, 0x09, 0xD9, 0xDD, 0xC9, 0x29, 0x33, 0x80, 0x56, 0x70, 0xD6,
|
||||
0x98, 0x50, 0x0C, 0x12, 0xC7, 0xF8, 0x3C, 0xC4, 0xFB, 0x9F, 0xFE, 0xFD, 0x5D, 0xAE, 0x9E, 0x1B,
|
||||
0x1E, 0x09, 0x99, 0xBC, 0xA5, 0x2A, 0x1A, 0xD0, 0x03, 0x41, 0x2D, 0xCC, 0xEB, 0x28, 0x6A, 0xCC,
|
||||
0xEE, 0x1F, 0x3F, 0x97, 0xDA, 0x97, 0xD5, 0x1A, 0xFF, 0x9B, 0xFD, 0xAC, 0x5A, 0x3F, 0xAB, 0x6F,
|
||||
0x73, 0x76, 0x5C, 0x28, 0xBE, 0x3D, 0x41, 0x01, 0x25, 0xFD, 0x3A, 0x72, 0x41, 0xA5, 0x8F, 0x99,
|
||||
0x03, 0x77, 0x11, 0x81, 0xEB, 0x35, 0x3D, 0x46, 0xA7, 0xA0, 0x1C, 0xDE, 0x9C, 0xD7, 0x8B, 0xD7,
|
||||
0x0A, 0x3C, 0x5D, 0x25, 0xEC, 0xF3, 0x3D, 0x54, 0xEF, 0x6A, 0x15, 0x59, 0x9B, 0xD5, 0x6F, 0xC5,
|
||||
0x1E, 0x7F, 0x55, 0x28, 0x50, 0x6F, 0xFA, 0xE8, 0x05, 0x59, 0x50, 0xD6, 0x80, 0x8C, 0xFD, 0x42,
|
||||
0x15, 0xEB, 0xC6, 0x0D, 0x62, 0xE2, 0xF3, 0x52, 0x76, 0xF7, 0x1A, 0xA0, 0x25, 0x34, 0x5F, 0x66,
|
||||
0xEA, 0xE7, 0xD9, 0x3A, 0x9C, 0x6C, 0x56, 0x7E, 0x13, 0x8F, 0xC7, 0xD1, 0xC1, 0x93, 0x69, 0x19,
|
||||
0x7C, 0xBE, 0xCE, 0x16, 0x6F, 0x4D, 0xDB, 0xC6, 0x80, 0x09, 0xCC, 0xB9, 0x72, 0xBA, 0x5B, 0xF3,
|
||||
0x49, 0xB1, 0x86, 0xBB, 0x49, 0xA0, 0x2C, 0xF1, 0x82, 0x88, 0x9F, 0xF7, 0x99, 0xB9, 0x2A, 0x94,
|
||||
0xE5, 0xA7, 0xB7, 0xDB, 0x7B, 0x7B, 0xBF, 0x6A, 0xDA, 0x69, 0xB5, 0x6B, 0xB9, 0x8A, 0x07, 0xF3,
|
||||
0xF8, 0x89, 0x1B, 0x9D, 0xA7, 0x46, 0x3A, 0x13, 0x04, 0xFD, 0x3A, 0x2D, 0x76, 0xCA, 0xD6, 0x00,
|
||||
0xF3, 0xED, 0x42, 0x1C, 0x98, 0x46, 0x1E, 0x50, 0xE0, 0x59, 0xE2, 0x67, 0x03, 0x7E, 0xAF, 0xEB,
|
||||
0xD3, 0x76, 0x7E, 0x01, 0xF8, 0x85, 0x33, 0x0F, 0x07, 0x99, 0x87, 0x6A, 0x37, 0xE9, 0x29, 0x30,
|
||||
0xA4, 0xE6, 0x04, 0xF0, 0x1E, 0x25, 0xE5, 0x88, 0x37, 0xF1, 0x18, 0x85, 0xE6, 0xD0, 0x53, 0x52,
|
||||
0x47, 0x45, 0xE0, 0x07, 0x0F, 0x27, 0xE1, 0x8D, 0xBB, 0x21, 0xBD, 0xA8, 0xC8, 0x93, 0xBD, 0xD3,
|
||||
0x66, 0x7C, 0xED, 0x24, 0x33, 0xE1, 0xC5, 0x5D, 0x7E, 0xE2, 0xDA, 0x71, 0x21, 0xD0, 0x3A, 0x70,
|
||||
0xB0, 0xB3, 0x70, 0x33, 0x64, 0x7B, 0x8D, 0x4E, 0x0F, 0xAA, 0x2B, 0x25, 0xBF, 0x54, 0x5C, 0x08,
|
||||
0xFD, 0x3B, 0x0A, 0xE0, 0x70, 0x2E, 0xFF, 0x4B, 0x1B, 0xA5, 0x6D, 0x19, 0x46, 0x1E, 0x84, 0xAF,
|
||||
0x32, 0x42, 0x55, 0xC9, 0xDB, 0x32, 0xC6, 0xCD, 0x06, 0x33, 0x53, 0xE5, 0x95, 0x71, 0x4E, 0xDE,
|
||||
0xE5, 0x83, 0xD2, 0x48, 0xCB, 0x32, 0x69, 0xA6, 0xFA, 0xA2, 0x8F, 0xC5, 0x45, 0x3A, 0x04, 0xEB,
|
||||
0x5B, 0xAB, 0x1B, 0x9F, 0xFF, 0xB7, 0x80, 0x50, 0x34, 0xB3, 0x17, 0xBC, 0xD3, 0x29, 0x5E, 0x53,
|
||||
0x0E, 0x98, 0xA7, 0x2D, 0x8D, 0xE0, 0xB5, 0x45, 0xEB, 0x24, 0x3D, 0xB6, 0x4E, 0xFF, 0x95, 0x6E,
|
||||
0x17, 0xAC, 0xA6, 0x8A, 0x1D, 0x6F, 0x7F, 0xDB, 0x74, 0x13, 0x81, 0x51, 0x40, 0x82, 0x8B, 0xAB,
|
||||
0x70, 0x71, 0x7F, 0x19, 0x63, 0x41, 0x1A, 0x12, 0x80, 0x97, 0x3E, 0x58, 0xFE, 0xE7, 0x9C, 0xA9,
|
||||
0x08, 0xB1, 0x41, 0x30, 0x69, 0xBA, 0xC0, 0x81, 0xE1, 0x0B, 0x87, 0x14, 0xBB, 0xD8, 0x9E, 0x4A,
|
||||
0x33, 0x92, 0x3B, 0xBD, 0x7F, 0xD4, 0x95, 0x3C, 0x2D, 0x45, 0xB1, 0x2A, 0x9B, 0x9B, 0xC2, 0x86,
|
||||
0xA0, 0x25, 0x7C, 0x94, 0x55, 0x05, 0xE5, 0x2D, 0xCB, 0xA4, 0x0B, 0x0B, 0x25, 0xBF, 0x8B, 0xFE,
|
||||
0xA0, 0xF2, 0x65, 0xA0, 0x9C, 0x90, 0x4F, 0xE1, 0xE9, 0x2B, 0x40, 0x60, 0x7F, 0x23, 0x82, 0x8A,
|
||||
0x89, 0x50, 0x72, 0x9C, 0x07, 0xBD, 0xD0, 0x84, 0x88, 0xA6, 0xB6, 0x3A, 0x43, 0x87, 0xBB, 0xDB,
|
||||
0x3E, 0x35, 0x6C, 0xBA, 0x51, 0x2E, 0xB4, 0xE7, 0xF6, 0xC4, 0x05, 0xE0, 0x95, 0x42, 0x96, 0x3E,
|
||||
0xE2, 0x39, 0xE9, 0x18, 0x8F, 0xD4, 0x9B, 0xEC, 0x18, 0x95, 0x8F, 0x79, 0xB8, 0xE3, 0xF4, 0x0D,
|
||||
0xD1, 0x15, 0x52, 0x26, 0xDA, 0x04, 0x9C, 0xA2, 0x08, 0xE4, 0x00, 0xB1, 0xD1, 0x38, 0x5C, 0x54,
|
||||
0x1E, 0xFB, 0x00, 0xFE, 0x22, 0xF8, 0x1D, 0xC6, 0x94, 0x8E, 0xA6, 0xEE, 0x6D, 0x07, 0x1F, 0x2B,
|
||||
0x06, 0x2C, 0x92, 0x6D, 0xEF, 0x86, 0x2F, 0x03, 0x7A, 0xBF, 0x05, 0x63, 0x2F, 0x43, 0x3E, 0xA7,
|
||||
0xF0, 0x5D, 0xD3, 0x82, 0xBF, 0x0B, 0xE6, 0x76, 0xEC, 0x8E, 0x5E, 0x6F, 0xD4, 0x88, 0xEF, 0xBB,
|
||||
0xED, 0xAF, 0x14, 0xC0, 0xA6, 0x51, 0x04, 0x7B, 0x60, 0x98, 0xB8, 0x7A, 0xF9, 0x1A, 0x5A, 0x28,
|
||||
0xC4, 0x40, 0x10, 0xBA, 0x4A, 0x8D, 0x0D, 0x30, 0xF9, 0x09, 0xDA, 0x6E, 0x1C, 0x78, 0xF7, 0x6A,
|
||||
0xAC, 0x2F, 0x49, 0xC6, 0x31, 0x56, 0x9D, 0x58, 0x63, 0x74, 0x6E, 0xAB, 0xA9, 0xD4, 0xF4, 0xC9,
|
||||
0x84, 0xA3, 0x9B, 0x97, 0x7A, 0x0E, 0x9E, 0xED, 0x7A, 0xC4, 0x01, 0xFB, 0xC3, 0xD6, 0x4F, 0x97,
|
||||
0x38, 0x84, 0x2F, 0x97, 0xF0, 0x33, 0x9B, 0x8A, 0x9C, 0x40, 0x23, 0x11, 0xDA, 0xC2, 0x5E, 0x28,
|
||||
0x5A, 0x78, 0x95, 0xF1, 0xB9, 0x41, 0x12, 0x4A, 0x77, 0x90, 0x86, 0xEC, 0xB3, 0xCC, 0x6D, 0x4C,
|
||||
0x40, 0x68, 0xAE, 0x40, 0x2F, 0x96, 0x9A, 0x1B, 0xA1, 0x46, 0x67, 0x1C, 0xE3, 0x54, 0xB7, 0x8A,
|
||||
0xF1, 0xAC, 0x38, 0x92, 0x1E, 0xBA, 0xD4, 0xD2, 0xCE, 0x46, 0x11, 0xA7, 0xCC, 0x73, 0xE3, 0x49,
|
||||
0x00, 0x9B, 0x93, 0xDE, 0xA6, 0x81, 0x3E, 0x85, 0x51, 0xB7, 0x43, 0x41, 0x64, 0xAC, 0x5B, 0x15,
|
||||
0xB7, 0xBC, 0x61, 0xF5, 0x87, 0xC4, 0x3D, 0xD1, 0x92, 0x57, 0x05, 0x27, 0x3E, 0x82, 0x5A, 0xCE,
|
||||
0xED, 0x5A, 0x59, 0x3B, 0x21, 0x01, 0x13, 0xB2, 0x67, 0x0F, 0x4D, 0xC4, 0x01, 0x9D, 0x19, 0x15,
|
||||
0x67, 0x02, 0xFF, 0xF7, 0xB7, 0xDD, 0xCB, 0xDB, 0x81, 0x13, 0xBA, 0x0C, 0x69, 0x32, 0x43, 0xBD,
|
||||
0x1A, 0x4F, 0xC8, 0x57, 0xD5, 0x3F, 0xE9, 0xBB, 0xC0, 0x0F, 0x98, 0xB5, 0x35, 0x65, 0x44, 0x7C,
|
||||
0x49, 0x05, 0x0B, 0x49, 0xE1, 0x6D, 0x34, 0x28, 0x2A, 0x77, 0xFE, 0x86, 0xC2, 0x87, 0x37, 0x2F,
|
||||
0x02, 0x53, 0x68, 0xC7, 0xDA, 0xF8, 0xAE, 0xA6, 0xE1, 0x47, 0xFA, 0xB8, 0xEE, 0x2D, 0x7E, 0xF0,
|
||||
0xB1, 0xE5, 0x64, 0xB6, 0x30, 0xC8, 0x0A, 0x5F, 0xB1, 0x6B, 0x11, 0xB2, 0x86, 0xD7, 0x4B, 0x0F,
|
||||
0x34, 0x4D, 0xEC, 0x5C, 0x72, 0x70, 0x05, 0xE8, 0xB4, 0x26, 0x76, 0x0F, 0x6E, 0x2D, 0x5E, 0x1E,
|
||||
0x80, 0x02, 0x6D, 0x4C, 0xCF, 0x92, 0x55, 0x5D, 0x2A, 0x2D, 0xDC, 0xBB, 0x01, 0xCD, 0x53, 0x06,
|
||||
0x02, 0xE7, 0x29, 0x1C, 0x34, 0x40, 0x88, 0x39, 0x8E, 0xD3, 0x58, 0x9A, 0x80, 0x18, 0xA1, 0xDD,
|
||||
0xC9, 0xB1, 0x59, 0x6B, 0x1D, 0xA2, 0xAE, 0xE6, 0x39, 0x1E, 0x37, 0x99, 0xFA, 0x1A, 0x88, 0x0F,
|
||||
0x26, 0x6A, 0x0D, 0xEF, 0x16, 0xE1, 0x2A, 0xEB, 0x22, 0x5D, 0x7B, 0xD3, 0x25, 0x93, 0x2C, 0x84,
|
||||
0xE5, 0x8D, 0xFA, 0xD6, 0x67, 0xE4, 0x36, 0x68, 0x80, 0x72, 0x78, 0xD3, 0x3B, 0xD1, 0xEF, 0xC0,
|
||||
0xA8, 0x1E, 0x32, 0x13, 0x2E, 0x02, 0xB1, 0xDF, 0x05, 0xA7, 0x3F, 0x7C, 0xAC, 0x5E, 0xC2, 0x15,
|
||||
0x4B, 0xD0, 0x94, 0xA1, 0x3C, 0x6C, 0x65, 0xDF, 0x6B, 0x05, 0x1F, 0x09, 0x09, 0x7D, 0xEA, 0x11,
|
||||
0x38, 0x85, 0x12, 0x7F, 0xE2, 0x0C, 0x8E, 0xF5, 0xED, 0xF8, 0x24, 0x6F, 0xCA, 0xDB, 0xDA, 0x65,
|
||||
0x08, 0xCA, 0x1F, 0x17, 0x3E, 0xFF, 0x68, 0x7B, 0xAA, 0x12, 0xDD, 0x98, 0x65, 0x94, 0x14, 0x63,
|
||||
0x8A, 0xC7, 0x56, 0xE2, 0x07, 0x2A, 0x53, 0xAB, 0xA9, 0x42, 0xB9, 0xF9, 0xBE, 0x38, 0x06, 0xB7,
|
||||
0xD1, 0xE6, 0xDF, 0x5A, 0xE3, 0x83, 0xFF, 0xE1, 0xAF, 0xE1, 0xF7, 0x89, 0xE9, 0x3B, 0xDC, 0x9A,
|
||||
0x23, 0x3B, 0x4C, 0xD1, 0xC6, 0xA0, 0xD5, 0x40, 0x01, 0x20, 0x7D, 0x2B, 0xEB, 0x60, 0x8E, 0x40,
|
||||
0x62, 0xC9, 0x26, 0xD7, 0x1C, 0xE6, 0x6D, 0xB6, 0x87, 0xC4, 0xCE, 0x19, 0xFC, 0xBB, 0x59, 0x3A,
|
||||
0x66, 0x21, 0x22, 0x91, 0x0C, 0x59, 0x66, 0x54, 0x4D, 0x86, 0xCA, 0xA2, 0x11, 0x72, 0xB6, 0xE6,
|
||||
0x04, 0x50, 0x25, 0x38, 0x9F, 0x87, 0x40, 0x9C, 0x5C, 0xB4, 0xFC, 0xD1, 0x04, 0xC0, 0xE1, 0xE2,
|
||||
0xC9, 0xFB, 0xD2, 0xBC, 0xE7, 0xB2, 0x38, 0x6B, 0x98, 0xAB, 0x90, 0x24, 0xBB, 0xB0, 0x45, 0xBA,
|
||||
0xEB, 0x29, 0xBD, 0xA6, 0xCD, 0xCC, 0x91, 0x7A, 0xEA, 0x2E, 0x84, 0x78, 0x6E, 0x07, 0x78, 0x1D,
|
||||
0x73, 0x14, 0xC4, 0x1F, 0x3D, 0x75, 0x72, 0x8E, 0xA0, 0x70, 0xE9, 0x93, 0xC2, 0x2C, 0x2F, 0x98,
|
||||
0x46, 0x07, 0x07, 0x12, 0x32, 0xFE, 0xDE, 0x2E, 0x24, 0xD5, 0xD0, 0xA3, 0x5A, 0x0C, 0xB4, 0x1D,
|
||||
0xD7, 0x57, 0xAB, 0x51, 0xAE, 0x0A, 0x19, 0xBD, 0x0D, 0x0B, 0xCA, 0x8A, 0x3B, 0x64, 0xFB, 0xF5,
|
||||
0x43, 0xC5, 0x04, 0xB1, 0x16, 0xC5, 0x34, 0xF7, 0x63, 0xEF, 0xC9, 0xBA, 0x94, 0x6A, 0xA4, 0x04,
|
||||
0x49, 0xB8, 0xF4, 0xF5, 0x3C, 0x0D, 0x84, 0xC3, 0x4B, 0xDE, 0xF1, 0xD5, 0x62, 0x15, 0x76, 0x84,
|
||||
0xED, 0xA4, 0x8A, 0x25, 0x3D, 0x87, 0xB7, 0xEA, 0x26, 0xDA, 0xCE, 0xB8, 0x7E, 0x8A, 0xDB, 0xAB,
|
||||
0x70, 0xB1, 0x18, 0x53, 0xEA, 0xF4, 0x74, 0xCB, 0x9A, 0x2B, 0x10, 0x5A, 0x4F, 0x06, 0x2B, 0x6B,
|
||||
0x4A, 0xF0, 0xF3, 0xB2, 0x10, 0x14, 0x9D, 0xBD, 0x18, 0x46, 0x3E, 0x7F, 0xAD, 0xB3, 0x03, 0xDD,
|
||||
0x80, 0xE2, 0xA5, 0x5D, 0x87, 0xAD, 0x67, 0x1C, 0x20, 0x06, 0xFD, 0x62, 0x65, 0x5D, 0x12, 0xC5,
|
||||
0x0A, 0x8C, 0x99, 0x8B, 0x97, 0xA1, 0x1F, 0x06, 0x8A, 0x78, 0x7A, 0xA5, 0x46, 0x65, 0xA8, 0xFA,
|
||||
0xC4, 0x81, 0x99, 0x02, 0x16, 0x7C, 0xB4, 0x09, 0xAD, 0xE8, 0x35, 0x2E, 0x6B, 0x4F, 0x55, 0xAC,
|
||||
0x23, 0x41, 0xA8, 0x5A, 0x0C, 0x71, 0x7E, 0x08, 0x3E, 0x6D, 0x5B, 0x46, 0x92, 0x3B, 0x8B, 0x8C,
|
||||
0xBE, 0x09, 0x52, 0xEA, 0xC5, 0xAE, 0x1B, 0x2A, 0xC8, 0x2D, 0x36, 0xE7, 0x2E, 0xCF, 0xA6, 0x30,
|
||||
0x9F, 0x14, 0xB2, 0xFA, 0xA2, 0xA3, 0xFF, 0xC7, 0x0B, 0xA6, 0xC8, 0x8C, 0xCD, 0xB3, 0x0B, 0xFC,
|
||||
0x76, 0x9F, 0xA1, 0xB9, 0x34, 0x86, 0xB5, 0x5B, 0x4C, 0x3D, 0x87, 0xA0, 0x5D, 0xE2, 0x95, 0x65,
|
||||
0xCF, 0xCD, 0x16, 0x40, 0x7D, 0x1B, 0xB1, 0xB8, 0x83, 0x37, 0x14, 0x6E, 0x02, 0xB2, 0x8E, 0x17,
|
||||
0x9E, 0x10, 0x87, 0x83, 0x62, 0x57, 0x60, 0x98, 0xA7, 0xE5, 0xCB, 0x82, 0x6E, 0xCC, 0xC7, 0x63,
|
||||
0x99, 0xB8, 0x1D, 0xA9, 0xED, 0x5B, 0xE9, 0x0E, 0xC8, 0x7D, 0xCE, 0x48, 0xE4, 0xE4, 0x3F, 0x1C,
|
||||
0x77, 0xBF, 0xEF, 0x3A, 0x63, 0x25, 0xAA, 0xDE, 0x2D, 0xC2, 0x42, 0x22, 0xEC, 0x99, 0xB6, 0xBF,
|
||||
0x65, 0xA0, 0x2A, 0x5C, 0x51, 0x63, 0x9D, 0xFB, 0x3F, 0xA0, 0x7E, 0x2B, 0xCC, 0x04, 0xE1, 0x74,
|
||||
0x13, 0x61, 0x80, 0x15, 0x3C, 0x2F, 0x9E, 0x3E, 0x63, 0x24, 0xA2, 0x13, 0xF9, 0xCD, 0xF6, 0xA9,
|
||||
0x88, 0x3A, 0xC9, 0x1F, 0xE9, 0xF2, 0x5F, 0x04, 0xD3, 0xE7, 0x00, 0x4B, 0xCD, 0xA5, 0x60, 0xBE,
|
||||
0x49, 0x89, 0xCC, 0x68, 0x48, 0x51, 0xEC, 0x7D, 0x8B, 0xDD, 0x23, 0xF0, 0x5D, 0xDC, 0x46, 0xA7,
|
||||
0x35, 0x77, 0xBF, 0x2D, 0x5C, 0xDB, 0x8B, 0x11, 0xE9, 0x15, 0xE6, 0xC7, 0x50, 0xEF, 0x01, 0x5A,
|
||||
0x4D, 0x04, 0x5D, 0xBF, 0xF9, 0x52, 0x36, 0xDE, 0x74, 0xE5, 0xF6, 0xF3, 0x37, 0x45, 0x28, 0x85,
|
||||
0x86, 0x9E, 0x1E, 0xFA, 0xF9, 0xB9, 0x1A, 0x04, 0xD7, 0xE7, 0xCB, 0xDC, 0x47, 0xFB, 0x49, 0x34,
|
||||
0x3A, 0x63, 0x26, 0x2D, 0x73, 0x6F, 0xC6, 0x28, 0xEE, 0x83, 0xBD, 0x8F, 0x2D, 0xF2, 0x1A, 0x19,
|
||||
0x75, 0x1B, 0xB6, 0x60, 0x4C, 0x38, 0x3D, 0xD7, 0x4D, 0x66, 0x7F, 0x01, 0xCF, 0x20, 0x1D, 0x45,
|
||||
0xD5, 0x32, 0x24, 0x96, 0x15, 0x0E, 0x5C, 0x6A, 0xD3, 0xE9, 0xC5, 0xD1, 0xF9, 0x11, 0x94, 0x41,
|
||||
0xD0, 0xC8, 0xBD, 0xBD, 0x17, 0xFB, 0x0A, 0x20, 0x89, 0x05, 0xBA, 0xCB, 0xF6, 0xBF, 0x9E, 0x83,
|
||||
0x44, 0x04, 0x54, 0x54, 0xA3, 0xDC, 0x1D, 0xEF, 0x3C, 0x01, 0x07, 0x80, 0x8A, 0x4F, 0x15, 0x3E,
|
||||
0x2D, 0xFE, 0xAF, 0xEB, 0x71, 0xA3, 0xE7, 0x20, 0x56, 0x2A, 0x19, 0x37, 0x8C, 0xDA, 0xE2, 0xB2,
|
||||
0xAB, 0xB4, 0x39, 0x3C, 0xC6, 0x7C, 0x7D, 0xD2, 0x91, 0xBE, 0x62, 0xF8, 0x4D, 0x01, 0x4E, 0xB4,
|
||||
0x3A, 0x19, 0xE2, 0x3E, 0x26, 0xD6, 0x2A, 0x55, 0x96, 0xC0, 0x0F, 0xA5, 0x35, 0x28, 0x0A, 0x5C,
|
||||
0xC1, 0x55, 0xD3, 0x72, 0x60, 0xF9, 0x65, 0xD0, 0xB2, 0x6C, 0x58, 0xAF, 0x8B, 0x00, 0x2B, 0x4C,
|
||||
0xF0, 0x4E, 0x8D, 0x15, 0x2F, 0xE5, 0x93, 0x05, 0x94, 0xF0, 0x02, 0x80, 0xDF, 0xFA, 0xEA, 0xA8,
|
||||
0xE8, 0x93, 0x50, 0xEB, 0xE1, 0x4D, 0x26, 0x34, 0xD3, 0x33, 0x83, 0x64, 0x30, 0x7D, 0x19, 0x51,
|
||||
0x50, 0x79, 0xF5, 0xF1, 0xD1, 0x2F, 0x7C, 0xC9, 0xF0, 0x3F, 0xF8, 0x60, 0x3B, 0x7E, 0x5D, 0x06,
|
||||
0x63, 0xED, 0x92, 0x0D, 0x0F, 0xD8, 0x9C, 0x6F, 0x74, 0x40, 0xF1, 0x40, 0xEC, 0x81, 0xAD, 0xAE,
|
||||
0xF0, 0xB2, 0x5E, 0x79, 0x71, 0x99, 0x89, 0x4F, 0xB9, 0xB2, 0x82, 0x15, 0x0D, 0x80, 0x7A, 0x68,
|
||||
0x13, 0x85, 0x4A, 0x6C, 0x6B, 0x1B, 0xD3, 0xA7, 0x67, 0x84, 0x14, 0xC5, 0xCE, 0xC9, 0xF2, 0x61,
|
||||
0x45, 0x7E, 0xEE, 0x7E, 0x6F, 0xD4, 0xB5, 0x15, 0xEE, 0x2C, 0x6C, 0xCC, 0x9D, 0x88, 0x38, 0x55,
|
||||
0x65, 0x78, 0xCF, 0x65, 0x8D, 0x2F, 0x22, 0xDD, 0xD9, 0x58, 0x9B, 0x60, 0x48, 0xEB, 0x96, 0xD5,
|
||||
0x17, 0xEE, 0x40, 0xFC, 0xA1, 0x9C, 0x70, 0x51, 0x2B, 0x0F, 0xCB, 0x80, 0x2C, 0x4A, 0x28, 0x4E,
|
||||
0x49, 0xAF, 0xA0, 0x6D, 0xA5, 0xF7, 0x58, 0x7E, 0x23, 0x30, 0xE9, 0x22, 0xE5, 0xC0, 0xD5, 0x65,
|
||||
0x13, 0xE6, 0xC1, 0x71, 0x94, 0xAF, 0xDE, 0x6A, 0x53, 0x4C, 0xDE, 0xB8, 0x35, 0xFE, 0x1F, 0xF0,
|
||||
0x51, 0x61, 0x5F, 0xC2, 0xA4, 0xA9, 0x66, 0x92, 0x93, 0x89, 0xC2, 0x4E, 0xDB, 0x7B, 0x9C, 0x11,
|
||||
0x62, 0xE5, 0xE6, 0xD7, 0x86, 0xD0, 0x8B, 0x33, 0x9E, 0x15, 0x78, 0x11, 0xF1, 0xC9, 0xA6, 0x4B,
|
||||
0xA9, 0xB8, 0x38, 0xDE, 0xB2, 0x55, 0xB6, 0x0E, 0xEF, 0x6E, 0xC9, 0xC8, 0x5A, 0x39, 0x1C, 0xEE,
|
||||
0x0F, 0x5C, 0x83, 0x2A, 0x46, 0x22, 0x4C, 0xA6, 0xD3, 0x38, 0xBA, 0x19, 0xA6, 0xB5, 0x70, 0x80,
|
||||
0xCF, 0x84, 0x6B, 0x02, 0x98, 0xAB, 0x4C, 0x48, 0x4F, 0xF2, 0x19, 0xDB, 0xBB, 0xB3, 0x1E, 0x21,
|
||||
0x41, 0xD2, 0x67, 0x16, 0x05, 0xC9, 0x21, 0x03, 0x3C, 0xC5, 0x7C, 0x0E, 0x85, 0xD8, 0x6F, 0x9D,
|
||||
0x57, 0x12, 0xE4, 0xC7, 0xCB, 0x73, 0xC3, 0xFE, 0xA3, 0x9E, 0xCD, 0x4D, 0x50, 0x4F, 0x4F, 0xDE,
|
||||
0x4A, 0x54, 0x17, 0x64, 0x6B, 0x13, 0x07, 0x7D, 0x48, 0x14, 0x92, 0x4D, 0x29, 0x1C, 0xF9, 0x4D,
|
||||
0xB9, 0xAE, 0x56, 0xF8, 0xF5, 0xCB, 0x8B, 0x8B, 0x0E, 0xD1, 0x91, 0xD5, 0xE5, 0xB9, 0x2B, 0xA5,
|
||||
0x1E, 0x55, 0x2C, 0xC3, 0x48, 0x31, 0x81, 0x7C, 0xD1, 0x36, 0x36, 0x52, 0x59, 0xC6, 0xCA, 0xEB,
|
||||
0x65, 0x8E, 0x89, 0x1A, 0x65, 0xC8, 0xF3, 0xC4, 0x67, 0x2B, 0x5A, 0xD3, 0xD4, 0x35, 0x01, 0x4A,
|
||||
0x2C, 0xA8, 0x7F, 0xA2, 0xC2, 0x52, 0xA1, 0x2C, 0xB2, 0x55, 0x7C, 0x5C, 0xF9, 0xC2, 0xD2, 0x77,
|
||||
0x5E, 0xF3, 0x31, 0xFD, 0xD7, 0x79, 0x8D, 0x0E, 0xE1, 0x37, 0x87, 0xC9, 0x47, 0x43, 0x4E, 0xA9,
|
||||
0x7D, 0x9E, 0x51, 0x83, 0x57, 0x15, 0x4E, 0x6A, 0x43, 0x1F, 0xC8, 0x83, 0xA3, 0x31, 0xE8, 0x19,
|
||||
0x7E, 0xC3, 0x0D, 0x2A, 0x3A, 0x15, 0x85, 0xBE, 0x16, 0xA3, 0x4C, 0xCD, 0xC6, 0x1A, 0xB1, 0x48,
|
||||
0xDB, 0x02, 0xED, 0xA6, 0xFF, 0x9B, 0xC2, 0x6E, 0x7C, 0x3B, 0xC6, 0xCC, 0x8F, 0x0C, 0xDB, 0xE0,
|
||||
0x11, 0x66, 0xDA, 0x0F, 0x85, 0x68, 0x25, 0x34, 0x7A, 0x7C, 0x4D, 0x13, 0x19, 0xA7, 0x37, 0xBA,
|
||||
0x1B, 0x8A, 0xBA, 0x99, 0x0B, 0x39, 0x7D, 0x37, 0xA6, 0x32, 0x81, 0xD3, 0x73, 0x21, 0x6E, 0x4A,
|
||||
0x32, 0x26, 0xC5, 0xE6, 0x8F, 0x33, 0x52, 0x48, 0x23, 0x4A, 0x21, 0xBD, 0xF9, 0x12, 0xC0, 0xFD,
|
||||
0xDC, 0x39, 0x1B, 0x4B, 0xCE, 0x56, 0x44, 0xC4, 0x9B, 0x9C, 0xF4, 0xBE, 0xC0, 0x9A, 0xFD, 0x28,
|
||||
0xA1, 0xB2, 0xAE, 0xA7, 0xFB, 0x31, 0xB6, 0xF6, 0x62, 0x68, 0xC9, 0x44, 0xCA, 0x0F, 0x51, 0xFF,
|
||||
0xCB, 0x7C, 0x67, 0xAE, 0xF4, 0xFD, 0xC0, 0x71, 0x50, 0x35, 0x65, 0xF3, 0x9C, 0x08, 0xA0, 0x1B,
|
||||
0x3B, 0x42, 0x69, 0x95, 0x42, 0x7A, 0xE3, 0x87, 0xF3, 0xD6, 0xE9, 0xA7, 0x22, 0x5B, 0x83, 0x0B,
|
||||
0x5B, 0xE9, 0x0A, 0x0A, 0xFA, 0x2D, 0x82, 0x42, 0x73, 0xDF, 0x76, 0xAF, 0xE6, 0xD3, 0x9D, 0xB1,
|
||||
0xA4, 0xD8, 0xB6, 0xC5, 0x5F, 0xC7, 0x98, 0xCC, 0x80, 0xA3, 0xB7, 0x67, 0xF4, 0x28, 0xA4, 0x98,
|
||||
0xB5, 0x5D, 0xB3, 0x0E, 0x77, 0xF4, 0xD0, 0x7E, 0xE2, 0x1C, 0xE2, 0x6B, 0xB4, 0x67, 0x42, 0x40,
|
||||
0xCB, 0x5A, 0x59, 0x43, 0x80, 0xA4, 0x92, 0xEC, 0xEB, 0x1E, 0xFB, 0x08, 0xFA, 0x17, 0xFE, 0x5E,
|
||||
0xF5, 0xD5, 0x1E, 0x12, 0xEB, 0xE8, 0x91, 0x78, 0x0E, 0x13, 0x67, 0xF9, 0x51, 0x0B, 0xBF, 0xA6,
|
||||
0x9B, 0x19, 0x26, 0x1D, 0xAE, 0xF7, 0x3A, 0xBB, 0xD7, 0x61, 0x62, 0xFA, 0xDB, 0x75, 0x26, 0x34,
|
||||
0xB7, 0xAF, 0x8C, 0xDD, 0xF5, 0xC1, 0x1C, 0x65, 0x23, 0xF2, 0xEC, 0x58, 0xA1, 0x9E, 0x82, 0x66,
|
||||
0x58, 0x4C, 0xF8, 0x44, 0x20, 0x87, 0x26, 0xCA, 0x09, 0xD6, 0xCD, 0x19, 0x4C, 0x39, 0x2A, 0x63,
|
||||
0xC8, 0xE2, 0x04, 0x18, 0x32, 0xBC, 0x87, 0x39, 0x7A, 0x0A, 0x59, 0xAA, 0xD5, 0xEB, 0xAE, 0x20,
|
||||
0x10, 0x9A, 0xBD, 0xB5, 0x14, 0xFC, 0x59, 0xCE, 0x86, 0x96, 0x42, 0x4A, 0xB0, 0xAE, 0xA5, 0x65,
|
||||
0x56, 0x34, 0x04, 0x13, 0x7C, 0xA0, 0x8B, 0x44, 0x11, 0xCE, 0xC3, 0x3C, 0x32, 0x56, 0xE4, 0xE0,
|
||||
0xFC, 0xAF, 0x7E, 0x89, 0xFB, 0x44, 0x4A, 0x34, 0x1C, 0x02, 0x7F, 0x69, 0xF1, 0x38, 0x8B, 0x3C,
|
||||
0x23, 0x54, 0x4A, 0xD8, 0xF5, 0x69, 0x70, 0xCA, 0x04, 0x99, 0x2A, 0xB0, 0x66, 0x22, 0x55, 0x14,
|
||||
0x82, 0x2A, 0x4B, 0x63, 0xA5, 0x05, 0x1E, 0x62, 0x49, 0x6B, 0xC1, 0x83, 0x6B, 0xA5, 0x74, 0xDD,
|
||||
0x20, 0x26, 0xAD, 0xDD, 0xD1, 0x37, 0x2C, 0x7E, 0x36, 0xE0, 0xBF, 0xC1, 0xEA, 0x37, 0x89, 0x5F,
|
||||
0x74, 0x6F, 0xAC, 0x05, 0x71, 0x94, 0x8D, 0x79, 0x1B, 0xAB, 0x03, 0xD9, 0x96, 0x9E, 0x40, 0x69,
|
||||
0x47, 0x23, 0x77, 0x35, 0x35, 0x60, 0x6C, 0xAA, 0x0B, 0x07, 0xC7, 0x64, 0xF7, 0x7F, 0x43, 0x6B,
|
||||
0x02, 0x69, 0x41, 0xCA, 0x1B, 0x51, 0xD9, 0x87, 0xEB, 0x36, 0xDD, 0x9E, 0xFF, 0xA1, 0x50, 0x6A,
|
||||
0x33, 0x5F, 0x25, 0x04, 0x97, 0x46, 0x99, 0x4D, 0xA4, 0x37, 0xD9, 0xA2, 0x23, 0x6E, 0x4C, 0x1B,
|
||||
0x36, 0xED, 0x9F, 0x09, 0x30, 0x26, 0xAB, 0x6F, 0x98, 0x0F, 0xF6, 0x13, 0x44, 0x4F, 0xF1, 0x61,
|
||||
0x73, 0x53, 0x39, 0x90, 0x88, 0xAE, 0x32, 0xC7, 0x33, 0x6B, 0x1A, 0xA1, 0xE8, 0x6F, 0x82, 0x99,
|
||||
0x73, 0x20, 0x44, 0xCF, 0x27, 0x17, 0xF8, 0x88, 0x19, 0x45, 0xD2, 0x41, 0x0A, 0xDB, 0x68, 0xA8,
|
||||
0x59, 0xBC, 0x73, 0xF7, 0xF1, 0x2D, 0x58, 0xBA, 0x60, 0x26, 0xA2, 0xB8, 0x93, 0x31, 0x32, 0xAB,
|
||||
0x13, 0xDE, 0x61, 0x0D, 0xD7, 0xA0, 0xFC, 0x44, 0x2A, 0xEE, 0xA3, 0xCF, 0x37, 0x17, 0xF9, 0xF8,
|
||||
0x63, 0x5A, 0x0C, 0x94, 0x78, 0x57, 0x24, 0xC0, 0x20, 0x12, 0xDA, 0xF0, 0x91, 0x22, 0x0D, 0x8E,
|
||||
0x3D, 0x48, 0xA0, 0x41, 0xFC, 0x65, 0x34, 0x0A, 0x4B, 0xE4, 0xFF, 0xEE, 0xB9, 0xF6, 0xD5, 0x48,
|
||||
0x60, 0xD1, 0x08, 0x75, 0x19, 0x7D, 0x23, 0xE6, 0x48, 0x80, 0xA4, 0x80, 0x72, 0x25, 0xE8, 0xF5,
|
||||
0x08, 0xFA, 0x70, 0xB5, 0x93, 0x6C, 0xA0, 0xFD, 0x28, 0xD4, 0xC6, 0xB5, 0xE3, 0x6D, 0x70, 0x6B,
|
||||
0x6D, 0x3F, 0x61, 0x01, 0xEB, 0xC9, 0xE7, 0xE1, 0x55, 0x67, 0x43, 0xE7, 0xBE, 0x1B, 0xE5, 0xA6,
|
||||
0xB7, 0x6C, 0x8F, 0x6D, 0xE4, 0x22, 0xCF, 0x8C, 0x6C, 0x67, 0xE6, 0xF3, 0xEC, 0x07, 0xB3, 0xE9,
|
||||
0x51, 0xBE, 0xBD, 0xC8, 0xCE, 0x67, 0xF2, 0x14, 0x7B, 0xDD, 0x8C, 0x70, 0x6E, 0x4C, 0x3E, 0x1E,
|
||||
0xA6, 0xCB, 0xD7, 0x4B, 0x0F, 0x61, 0x76, 0x39, 0x91, 0xE9, 0xD2, 0x43, 0x51, 0x8E, 0x86, 0x82,
|
||||
0x7B, 0xB2, 0xCD, 0xF6, 0x0E, 0x74, 0x0F, 0xA3, 0xD4, 0x25, 0xC2, 0x16, 0xCB, 0xFB, 0x8A, 0x2A,
|
||||
0x0B, 0xFA, 0xCF, 0xC0, 0x99, 0x38, 0x48, 0xCD, 0x87, 0xB6, 0x39, 0x74, 0x5C, 0x9F, 0x0A, 0x12,
|
||||
0xA7, 0x42, 0x1B, 0xF2, 0xBC, 0x9A, 0x38, 0x12, 0xA1, 0x5F, 0x64, 0x54, 0x2A, 0x0C, 0xFB, 0xF9,
|
||||
0xF0, 0xB3, 0x4B, 0xC5, 0xD1, 0xAE, 0x15, 0x52, 0x14, 0xDE, 0x91, 0x16, 0x38, 0xAF, 0x01, 0x16,
|
||||
0x8D, 0x29, 0x3E, 0xFE, 0x62, 0xF3, 0x57, 0x10, 0x6C, 0x21, 0x10, 0x9F, 0x8F, 0x4C, 0xF9, 0xE8,
|
||||
0x7F, 0x77, 0xFF, 0xF7, 0x01, 0x53, 0x7E, 0xB8, 0xC3, 0xFC, 0x88, 0xF1, 0xB1, 0x5A, 0x63, 0xAB,
|
||||
0xC2, 0x78, 0x8C, 0x15, 0x96, 0x61, 0xC7, 0x88, 0xC5, 0x45, 0x16, 0xE9, 0xE1, 0xD5, 0x77, 0xB4,
|
||||
0xC9, 0xA6, 0xAB, 0x47, 0xEE, 0x86, 0xFE, 0xD1, 0x2C, 0xAB, 0x23, 0x18, 0xA7, 0xB0, 0x4D, 0x18,
|
||||
0x52, 0xB7, 0xEF, 0x68, 0xCB, 0x80, 0xF9, 0x05, 0x15, 0x7A, 0xCB, 0x61, 0xC5, 0xCE, 0xCF, 0x92,
|
||||
0x3B, 0xCA, 0x7C, 0xEC, 0x02, 0x6F, 0x6B, 0x1E, 0x27, 0xAC, 0x07, 0xF2, 0x63, 0xB8, 0xDC, 0x1C,
|
||||
0x6A, 0x52, 0xB5, 0xF2, 0x90, 0xEB, 0x16, 0xA1, 0x2C, 0x9C, 0x3D, 0x20, 0x4B, 0xB3, 0xB9, 0x3B,
|
||||
0xD3, 0xE0, 0x7A, 0xCC, 0x9E, 0xF8, 0x95, 0x32, 0x2A, 0x34, 0x4A, 0xBC, 0x1E, 0x21, 0x05, 0x02,
|
||||
0x1A, 0xF4, 0x19, 0x32, 0x7B, 0x4A, 0x08, 0x15, 0x1B, 0xB1, 0xD5, 0x25, 0x53, 0x78, 0x99, 0xD8,
|
||||
0x9D, 0x8E, 0x45, 0xAE, 0x44, 0x52, 0x90, 0xC3, 0x89, 0xE7, 0xA5, 0x3E, 0xFA, 0xBC, 0x1C, 0x43,
|
||||
0x7B, 0x2E, 0x6B, 0x26, 0x84, 0x19, 0xA7, 0x4D, 0xDC, 0xD6, 0x4D, 0x29, 0x0F, 0x3A, 0xA5, 0xBC,
|
||||
0x09, 0x07, 0x53, 0x20, 0x8E, 0xE2, 0x91, 0x38, 0x73, 0x70, 0xA0, 0xAE, 0x10, 0xE0, 0x62, 0x49,
|
||||
0xAD, 0x71, 0x64, 0xC7, 0x8F, 0x15, 0x04, 0x42, 0xB4, 0xA6, 0x37, 0xEB, 0x9A, 0xB2, 0x00, 0x20,
|
||||
0xC6, 0x55, 0x3C, 0x14, 0xAB, 0xC2, 0x15, 0xF5, 0xB7, 0x79, 0x81, 0x5D, 0x36, 0xC2, 0xEC, 0xBA,
|
||||
0xC3, 0xB5, 0xAC, 0xF5, 0x2A, 0x92, 0x2A, 0xAC, 0x4D, 0x7F, 0x71, 0x5A, 0xFE, 0x74, 0xAC, 0xFE,
|
||||
0x70, 0x58, 0x9F, 0x61, 0x10, 0x95, 0xED, 0x04, 0xF7, 0x1E, 0x49, 0x99, 0xCD, 0xAB, 0x2C, 0x3A,
|
||||
0x8F, 0x00, 0x26, 0x48, 0x5F, 0x0F, 0x80, 0xFF, 0x72, 0x05, 0x82, 0xE4, 0xDD, 0x6F, 0x7C, 0xDA,
|
||||
0x42, 0x91, 0x94, 0x57, 0x8F, 0xC0, 0xA7, 0xBA, 0x46, 0x8C, 0x15, 0xE9, 0xEA, 0x5E, 0xCD, 0xE7,
|
||||
0x63, 0xB3, 0x15, 0x50, 0x5E, 0x71, 0x35, 0xEE, 0x84, 0xFA, 0x23, 0x4B, 0xEE, 0x5B, 0x99, 0xDF,
|
||||
0x0D, 0xE5, 0x69, 0xC7, 0xD7, 0xF7, 0x49, 0xC4, 0xEF, 0x19, 0x88, 0x57, 0xB5, 0x4F, 0x3E, 0x18,
|
||||
0xF9, 0x61, 0x1A, 0xFE, 0xFB, 0x15, 0xE3, 0x65, 0x49, 0x19, 0x17, 0xBA, 0xC0, 0x26, 0x8A, 0x5E,
|
||||
0x8D, 0x29, 0x50, 0x62, 0x19, 0x6E, 0xFA, 0x22, 0x7E, 0xEA, 0xE6, 0x2F, 0x90, 0xEF, 0x71, 0x21,
|
||||
0xAD, 0x2A, 0xFC, 0x97, 0xBA, 0xC7, 0x71, 0x7D, 0x68, 0x1C, 0x53, 0xB1, 0xD4, 0x59, 0xED, 0xE1,
|
||||
0x56, 0x54, 0xD1, 0x89, 0xC4, 0xB0, 0xB8, 0x88, 0x78, 0xCA, 0xF7, 0x85, 0x7E, 0xA0, 0xE8, 0xF4,
|
||||
0xE5, 0x12, 0xE8, 0x24, 0x9A, 0x51, 0xE9, 0xA3, 0x52, 0x96, 0x59, 0x47, 0x07, 0x63, 0xAE, 0x18,
|
||||
0x41, 0xAB, 0x17, 0xE8, 0x94, 0xDF, 0x94, 0x2F, 0x8F, 0x36, 0x34, 0x91, 0x20, 0x52, 0xE0, 0x11,
|
||||
0x2E, 0xFF, 0xBD, 0xBD, 0x6E, 0x49, 0xE2, 0x41, 0xA6, 0xD0, 0x10, 0xD0, 0x2C, 0xE4, 0x2E, 0x9F,
|
||||
0xBF, 0x36, 0xAD, 0xDA, 0xA5, 0xFE, 0xD9, 0xEC, 0xC1, 0x55, 0x20, 0xCB, 0x10, 0xAD, 0x4D, 0xE3,
|
||||
0xD2, 0xE7, 0x09, 0xFB, 0x14, 0xC2, 0x11, 0x33, 0x2C, 0xFA, 0xDE, 0x82, 0x15, 0x4D, 0xF0, 0xB6,
|
||||
0x71, 0x3C, 0x58, 0x80, 0xD2, 0x87, 0x05, 0x89, 0xEF, 0x00, 0x6C, 0x8A, 0xFB, 0x14, 0xF3, 0x65,
|
||||
0x22, 0xCD, 0xBF, 0x25, 0x03, 0x60, 0x12, 0x38, 0x2B, 0x0A, 0xF1, 0xFB, 0xCB, 0x80, 0x11, 0x3B,
|
||||
0x59, 0xE2, 0xEF, 0x07, 0xC8, 0x97, 0x50, 0xFE, 0x56, 0x4C, 0x52, 0x4F, 0x73, 0xD9, 0xCA, 0x89,
|
||||
0x7B, 0xEA, 0x50, 0x5E, 0xCB, 0xB9, 0xEE, 0xC8, 0xFF, 0xC5, 0x13, 0x62, 0x00, 0x9F, 0xBF, 0x61,
|
||||
0xC7, 0x2F, 0x0F, 0xBF, 0x75, 0xC3, 0x0E, 0x72, 0x2C, 0xF7, 0xDF, 0xA5, 0xAE, 0x94, 0x15, 0x8F,
|
||||
0xBB, 0x1D, 0x26, 0xA0, 0xCB, 0x8B, 0x40, 0x78, 0x48, 0xB4, 0x41, 0x47, 0x6B, 0x7D, 0x45, 0xBE,
|
||||
0x39, 0xA5, 0xE2, 0xB7, 0x11, 0xEF, 0xE8, 0x19, 0xA0, 0x62, 0x26, 0xE1, 0xD5, 0x94, 0x54, 0x9D,
|
||||
0xA4, 0x28, 0xEE, 0x7F, 0x7F, 0x25, 0xAD, 0xDB, 0x28, 0x2C, 0xDB, 0xA7, 0x63, 0xF8, 0x0E, 0x6E,
|
||||
0xE2, 0x0F, 0x8F, 0xC7, 0x17, 0x31, 0xB2, 0x8D, 0xA8, 0x92, 0x7A, 0x81, 0xD5, 0x88, 0x2E, 0xD3,
|
||||
0xF2, 0xE5, 0x08, 0x76, 0xC7, 0x93, 0xDB, 0xC0, 0x0B, 0x38, 0x58, 0xF7, 0x6F, 0xC4, 0x58, 0xAD,
|
||||
0xB0, 0x3B, 0xDC, 0xE6, 0xD1, 0xB3, 0xC2, 0x39, 0x25, 0xE7, 0x48, 0x19, 0xC8, 0x27, 0xD1, 0xDF,
|
||||
0x9F, 0x5F, 0xB8, 0x5A, 0x50, 0xE9, 0x0B, 0x51, 0x43, 0x2C, 0xA6, 0x09, 0x39, 0x14, 0xF5, 0x3E,
|
||||
0x03, 0x6E, 0x55, 0x7D, 0xE3, 0x42, 0xE5, 0xBB, 0x40, 0xA0, 0x71, 0xAA, 0xF1, 0xAF, 0x6E, 0xF2,
|
||||
0xE2, 0x59, 0x94, 0xF2, 0x9F, 0x79, 0x67, 0x23, 0x6F, 0xCA, 0x85, 0xF6, 0x1F, 0xA3, 0x87, 0x7B,
|
||||
0xE6, 0x62, 0xEE, 0x8F, 0x0D, 0x48, 0x89, 0x98, 0x37, 0x35, 0x91, 0x05, 0x58, 0xA3, 0x83, 0x28,
|
||||
0x13, 0xA2, 0x1E, 0xD1, 0x49, 0x5F, 0x68, 0x59, 0x47, 0x49, 0xED, 0x7B, 0xC2, 0x45, 0x58, 0xCB,
|
||||
0xB7, 0xC8, 0x91, 0x3B, 0xF5, 0xB4, 0xC4, 0x8C, 0x01, 0xE3, 0x78, 0x3A, 0x3D, 0xD9, 0x58, 0x0B,
|
||||
0xA3, 0xB2, 0x8C, 0xFA, 0xF1, 0x8C, 0xC5, 0x77, 0x93, 0xC9, 0x88, 0x80, 0x67, 0xB5, 0x62, 0x55,
|
||||
0x6E, 0x01, 0x74, 0xF3, 0x81, 0x9E, 0xAE, 0x27, 0xB0, 0x20, 0xC6, 0xE1, 0xAE, 0xE7, 0xBB, 0x8D,
|
||||
0x12, 0x27, 0x6D, 0x23, 0xF3, 0x1D, 0xCD, 0x5E, 0x20, 0xAC, 0x10, 0x06, 0x1D, 0x3C, 0xB4, 0x86,
|
||||
0xB7, 0x0E, 0x8C, 0x9D, 0x14, 0xD5, 0xAC, 0xFF, 0xFE, 0xE5, 0x6B, 0xEB, 0xED, 0x3F, 0xF5, 0x40,
|
||||
0xBA, 0x69, 0x66, 0x90, 0xFA, 0x54, 0xAC, 0xB9, 0xCB, 0x07, 0x38, 0xAF, 0xE4, 0x40, 0x41, 0x0C,
|
||||
0x0A, 0x44, 0x2D, 0x31, 0x46, 0x4E, 0x2B, 0x75, 0xFA, 0x06, 0xA3, 0x59, 0xC3, 0x27, 0x53, 0xFC,
|
||||
0xB6, 0xEF, 0xBA, 0x10, 0xAA, 0x65, 0x1D, 0x1C, 0xAB, 0x19, 0x8C, 0x54, 0x1D, 0x3B, 0xBB, 0x10,
|
||||
0x05, 0xAA, 0xAE, 0xEF, 0x80, 0x03, 0x28, 0xA7, 0x4D, 0xA9, 0xD8, 0xA8, 0x34, 0x75, 0xC6, 0x2B,
|
||||
0x43, 0x82, 0x59, 0x00, 0x2E, 0xEE, 0xF9, 0x8A, 0x8F, 0x8E, 0x1C, 0x21, 0xA0, 0xDC, 0xAA, 0xFC,
|
||||
0xBF, 0x15, 0x2F, 0x6D, 0x00, 0x33, 0x81, 0x24, 0x86, 0x58, 0xCF, 0xD5, 0x5A, 0xC4, 0xB3, 0x28,
|
||||
0x97, 0xC5, 0x45, 0xAB, 0x8D, 0x48, 0xDE, 0xEA, 0xB2, 0xFD, 0x1E, 0xD3, 0x13, 0x57, 0xFF, 0xFB,
|
||||
0x24, 0xDE, 0x7A, 0x9D, 0x43, 0xF8, 0xC7, 0xDD, 0x1A, 0x28, 0x7C, 0x39, 0xA4, 0xDA, 0x58, 0xB7,
|
||||
0xBD, 0x1D, 0x24, 0xDE, 0xCF, 0x85, 0x7E, 0xEF, 0x5A, 0x4F, 0xF1, 0xB4, 0xCB, 0xA6, 0x5E, 0xC0,
|
||||
0x80, 0xE6, 0x0B, 0xC0, 0x69, 0xAD, 0x5D, 0xB4, 0x88, 0xBD, 0xFB, 0x78, 0x2C, 0x3C, 0xA6, 0x69,
|
||||
0x77, 0x16, 0xD6, 0xA9, 0xFF, 0x4A, 0x6C, 0xC0, 0x48, 0x27, 0x64, 0x41, 0x51, 0x79, 0xC6, 0xF9,
|
||||
0x85, 0x71, 0x9C, 0x89, 0xD2, 0x68, 0xF5, 0xBB, 0xE5, 0x83, 0xF5, 0xD0, 0xEB, 0x25, 0xC7, 0x1E,
|
||||
0x50, 0xA8, 0x1F, 0x50, 0x86, 0xEE, 0x1F, 0xE9, 0x4A, 0xB3, 0xA0, 0x18, 0xF8, 0xCE, 0xD6, 0x0B,
|
||||
0xF2, 0x41, 0xFC, 0x21, 0x20, 0x1A, 0xA3, 0x9D, 0xB7, 0xD1, 0x49, 0x79, 0xE2, 0x7B, 0xF3, 0x8B,
|
||||
0x40, 0x6F, 0xE2, 0x45, 0x00, 0x5A, 0x81, 0x7D, 0x39, 0x93, 0x3B, 0x59, 0xE0, 0x3E, 0xCA, 0xC5,
|
||||
0x61, 0x80, 0x65, 0x2D, 0xC9, 0xAD, 0x2C, 0x26, 0x66, 0x11, 0x3A, 0xA6, 0xBA, 0xF5, 0x3B, 0x49,
|
||||
0xC5, 0xB1, 0xAA, 0xB6, 0xBC, 0x68, 0x00, 0x51, 0x82, 0x1A, 0x39, 0x2B, 0x28, 0x5C, 0x39, 0xF2,
|
||||
0xB4, 0x7E, 0x93, 0x63, 0xEA, 0xD7, 0xBE, 0x7F, 0xA0, 0xCC, 0x47, 0x31, 0x2E, 0xBA, 0x9C, 0xD0,
|
||||
0x67, 0xBF, 0xE0, 0xDE, 0x46, 0xCA, 0xA1, 0x84, 0x57, 0x6B, 0x15, 0x0A, 0xC6, 0xAB, 0x32, 0x74,
|
||||
0x37, 0x34, 0xDA, 0x1A, 0x95, 0xA6, 0xA4, 0xEE, 0xF6, 0xC6, 0xFB, 0x70, 0x56, 0x0C, 0xC4, 0xCA,
|
||||
0x0D, 0xD5, 0xCB, 0x03, 0xA3, 0x21, 0xF5, 0x6D, 0x0F, 0xD1, 0xEE, 0x77, 0x73, 0xA4, 0xF9, 0x95,
|
||||
0x34, 0x2F, 0x0C, 0x5B, 0x7F, 0x48, 0x6A, 0x02, 0x4A, 0xA4, 0x59, 0x68, 0x0F, 0xF4, 0x64, 0x73,
|
||||
0x84, 0xCE, 0xED, 0x43, 0x54, 0x46, 0xD9, 0x42, 0x4C, 0x84, 0xD5, 0xFE, 0x5B, 0xD3, 0x51, 0x17,
|
||||
0x4E, 0xB8, 0x7A, 0x42, 0x87, 0x45, 0xDB, 0xC3, 0x2C, 0xC8, 0x8B, 0x86, 0xB3, 0x95, 0x0B, 0xCF,
|
||||
0x27, 0xC4, 0xA8, 0xEE, 0x60, 0x13, 0xD3, 0x9F, 0xFC, 0xD0, 0x7F, 0x84, 0x5B, 0x24, 0x5D, 0xCF,
|
||||
0xE4, 0xA4, 0x83, 0x35, 0xD1, 0x7A, 0x72, 0x78, 0xB6, 0xB4, 0xA2, 0x32, 0x0F, 0x68, 0x61, 0x7C,
|
||||
0xB7, 0x46, 0x20, 0x1A, 0xA5, 0x94, 0x63, 0x71, 0xAA, 0xA0, 0x77, 0x95, 0x28, 0x63, 0xCE, 0xFE,
|
||||
0x69, 0xB6, 0x44, 0x10, 0xF6, 0xC1, 0xD7, 0xED, 0x11, 0x73, 0x9E, 0x46, 0xDE, 0xC3, 0xFF, 0x9E,
|
||||
0xB9, 0xEC, 0xEC, 0xE4, 0xE3, 0xFD, 0x1E, 0xD3, 0x55, 0x08, 0x36, 0xC8, 0xDC, 0xD1, 0x0E, 0x00,
|
||||
0xEE, 0x86, 0x78, 0x08, 0xB7, 0xAD, 0xD8, 0xE1, 0x59, 0x60, 0x33, 0x14, 0xF4, 0x5C, 0x55, 0xA4,
|
||||
0xF1, 0x0D, 0x0E, 0x16, 0xCD, 0x1C, 0x72, 0x6D, 0x89, 0xEB, 0x41, 0x42, 0xB1, 0xF5, 0x63, 0x80,
|
||||
0xD6, 0x06, 0xC3, 0x1C, 0xBE, 0x7B, 0x95, 0x2A, 0x5B, 0x27, 0x08, 0xDC, 0xB7, 0x2A, 0xDC, 0x8E,
|
||||
0x3C, 0xA0, 0x84, 0x5F, 0xA8, 0xF1, 0x7B, 0x1F, 0xE1, 0x70, 0x37, 0x2D, 0x28, 0xDC, 0x7C, 0xB8,
|
||||
0xA7, 0x47, 0x60, 0x77, 0xAC, 0x55, 0xE3, 0x97, 0x5A, 0xC1, 0xA6, 0xA2, 0xFF, 0xCB, 0xF6, 0x45,
|
||||
0x28, 0x1E, 0xD2, 0x1C, 0xE8, 0x9E, 0x45, 0xF7, 0x1E, 0xD5, 0x92, 0xB4, 0x5A, 0x5E, 0x6A, 0xE0,
|
||||
0xF7, 0x1A, 0x81, 0xD7, 0x96, 0x62, 0xB5, 0xD9, 0xE7, 0x0E, 0x3A, 0xA3, 0xE8, 0x60, 0x30, 0x45,
|
||||
0x96, 0x86, 0x58, 0xDD, 0xBA, 0x04, 0x5E, 0xF4, 0x5D, 0xE3, 0x82, 0x7D, 0x3B, 0xD5, 0xD6, 0x28,
|
||||
0xFF, 0xC6, 0xDE, 0x3A, 0x3D, 0xF8, 0xB5, 0x6A, 0x5A, 0x1D, 0x34, 0x63, 0x48, 0x6F, 0xE9, 0xC8,
|
||||
0x5F, 0x56, 0x17, 0x14, 0x56, 0xC7, 0xE4, 0xC2, 0x38, 0x68, 0x8A, 0x81, 0x0F, 0x4D, 0x4A, 0x91,
|
||||
0x79, 0x85, 0x40, 0xB1, 0x7A, 0xA5, 0x4A, 0xF1, 0xC2, 0xA2, 0x3B, 0x62, 0x4D, 0xD8, 0xD8, 0x41,
|
||||
0x80, 0x66, 0x48, 0x7A, 0x96, 0xF7, 0xB2, 0x05, 0xDC, 0xB2, 0xD7, 0xBF, 0xB8, 0xB3, 0x0C, 0xD5,
|
||||
0x12, 0x90, 0xBA, 0x86, 0xDB, 0x2D, 0x2D, 0x2F, 0x1A, 0xBE, 0xA8, 0xF0, 0x42, 0xA1, 0xE6, 0x9B,
|
||||
0x89, 0x57, 0x69, 0xFD, 0x1B, 0x18, 0x94, 0xC2, 0xE1, 0x53, 0xD3, 0xAD, 0x2D, 0x90, 0x8B, 0xEA,
|
||||
0xAB, 0x29, 0x47, 0x08, 0xE6, 0x4B, 0xAC, 0x3A, 0xFC, 0x8C, 0x40, 0xC3, 0x45, 0xD9, 0xCF, 0x24,
|
||||
0xA9, 0x17, 0xC4, 0xAD, 0x46, 0xAC, 0x27, 0xAD, 0xE6, 0xEE, 0xF2, 0xF7, 0x5F, 0x6C, 0xD7, 0xE7,
|
||||
0xF2, 0x01, 0xED, 0x98, 0x4E, 0x7A, 0x03, 0x94, 0x4C, 0x26, 0x69, 0x5E, 0x8D, 0xDC, 0x13, 0xD6,
|
||||
0x3A, 0x2D, 0x4A, 0x70, 0x0E, 0x39, 0x94, 0x63, 0xDE, 0x08, 0x7A, 0x72, 0x4D, 0xFE, 0x89, 0xCA,
|
||||
0x8C, 0x4D, 0x39, 0x6A, 0x99, 0xAD, 0xAC, 0xE7, 0x8F, 0x6E, 0xD2, 0x18, 0x98, 0xF4, 0x1B, 0xD7,
|
||||
0x0A, 0x60, 0xA2, 0x00, 0x1B, 0xB3, 0xE6, 0x37, 0xA1, 0x1F, 0x30, 0xBD, 0xFD, 0xA8, 0x58, 0xB7,
|
||||
0xFF, 0xF1, 0x45, 0x74, 0x9B, 0xE9, 0xA8, 0x80, 0x12, 0x0F, 0x98, 0xF7, 0x9E, 0x62, 0xF5, 0x4A,
|
||||
0x0C, 0x32, 0x58, 0x87, 0x65, 0x2D, 0xE4, 0x90, 0x44, 0xB2, 0xB1, 0x8A, 0xFB, 0x29, 0x99, 0x3C,
|
||||
0xE8, 0xEB, 0x4F, 0x99, 0x21, 0x47, 0x0D, 0xAA, 0x9F, 0x54, 0xAA, 0xFC, 0x47, 0xB6, 0x35, 0xFE,
|
||||
0x24, 0x73, 0xC2, 0x26, 0x18, 0x1E, 0x61, 0x18, 0xC7, 0xF5, 0xE1, 0xD9, 0x5C, 0x7E, 0xCA, 0x71,
|
||||
0xA5, 0xA6, 0x4D, 0x91, 0xC0, 0xC5, 0x0C, 0x65, 0x98, 0x69, 0x9B, 0x51, 0xDF, 0xC2, 0x88, 0x51,
|
||||
0x21, 0x49, 0x8D, 0x23, 0x52, 0x27, 0xAD, 0x83, 0xD7, 0xB3, 0x73, 0x34, 0x90, 0xD3, 0xA7, 0xDE,
|
||||
0x9D, 0x8C, 0x5F, 0xCA, 0xA6, 0x2C, 0x95, 0x01, 0xCC, 0x24, 0x59, 0x70, 0x74, 0xBB, 0x72, 0xD7,
|
||||
0x80, 0x25, 0x03, 0xD1, 0xB2, 0x0A, 0xF8, 0x0A, 0x53, 0x9E, 0x03, 0x6F, 0xA4, 0xFB, 0x20, 0x52,
|
||||
0x46, 0x0C, 0x2B, 0xD8, 0x25, 0x4D, 0xE8, 0xBA, 0xB7, 0x97, 0x8E, 0x77, 0x52, 0xA6, 0x18, 0x92,
|
||||
0xBE, 0x86, 0x89, 0x0B, 0x57, 0xBD, 0xBE, 0xAC, 0x74, 0xE5, 0x64, 0xEA, 0x0C, 0xEE, 0xA2, 0x70,
|
||||
0x09, 0x0A, 0x07, 0x97, 0xCD, 0x42, 0xD1, 0x91, 0x7E, 0x7F, 0xDE, 0xF5, 0x06, 0xBA, 0xBB, 0x91,
|
||||
0xF5, 0x90, 0x4D, 0x67, 0xDF, 0x02, 0x94, 0x7C, 0xAE, 0xC8, 0xD9, 0x80, 0x20, 0xF2, 0xFE, 0xA9,
|
||||
0x1B, 0x91, 0x34, 0x34, 0x18, 0xFE, 0xF2, 0xD1, 0xD2, 0xB6, 0xE4, 0xA6, 0x77, 0xD3, 0x63, 0x2C,
|
||||
0x82, 0x8A, 0xE0, 0x87, 0xEB, 0x30, 0xC5, 0x14, 0x7E, 0x55, 0x0E, 0x87, 0x7F, 0xD3, 0x5B, 0x88,
|
||||
0xA9, 0xA7, 0x1B, 0xB8, 0x55, 0xE1, 0x60, 0x1B, 0xF3, 0x09, 0x8D, 0xE4, 0x31, 0xFF, 0xAA, 0xB0,
|
||||
0xFC, 0x29, 0xD2, 0x3F, 0xEE, 0x8C, 0x99, 0x0B, 0x79, 0x1F, 0x60, 0x6F, 0xF7, 0xE0, 0x5A, 0x5E,
|
||||
0xD2, 0xB2, 0x52, 0x6C, 0xD4, 0xF5, 0x96, 0x76, 0xAC, 0x51, 0x07, 0xA0, 0xEC, 0x01, 0x34, 0x37,
|
||||
0xDB, 0xB0, 0xBE, 0x04, 0x2C, 0x1D, 0xCF, 0x1C, 0x8B, 0xF4, 0xAE, 0x03, 0x7A, 0x9C, 0x6A, 0xDA,
|
||||
0xC6, 0xD7, 0xB2, 0xE8, 0x9C, 0x2D, 0xCB, 0x42, 0x7C, 0xFA, 0x49, 0x3E, 0xCA, 0x93, 0xA3, 0x2E,
|
||||
0x34, 0x16, 0x35, 0xC7, 0xEB, 0x14, 0x65, 0x95, 0xDD, 0x50, 0x3F, 0xE2, 0xA7, 0xB8, 0x31, 0x30,
|
||||
0x19, 0xC5, 0x39, 0xE6, 0xD6, 0xD8, 0xCB, 0x8B, 0x35, 0x85, 0xB9, 0x2F, 0x5F, 0x72, 0x38, 0xA0,
|
||||
0x32, 0x7D, 0x0B, 0x30, 0x69, 0x4E, 0xEB, 0x97, 0x1B, 0x5A, 0xCC, 0xCB, 0x9F, 0x14, 0xD1, 0xC4,
|
||||
0x66, 0x03, 0xE3, 0xC9, 0xC8, 0x70, 0xD0, 0x08, 0xE6, 0x1B, 0x08, 0xEF, 0xB2, 0x13, 0xF3, 0xAE,
|
||||
0x61, 0x5E, 0xE2, 0xF9, 0x72, 0x7B, 0x20, 0x63, 0x86, 0x8A, 0x3A, 0xBD, 0xFB, 0x08, 0xA9, 0x90,
|
||||
0xA6, 0xFF, 0xC4, 0xF7, 0xDA, 0x6D, 0x2C, 0x96, 0x5F, 0xB8, 0xE0, 0x73, 0x7C, 0x92, 0xA1, 0xE5,
|
||||
0xF9, 0x10, 0x01, 0x6F, 0xCD, 0xFF, 0x16, 0xCE, 0x54, 0x2E, 0x16, 0x87, 0x65, 0xA4, 0xB1, 0xD4,
|
||||
0xA2, 0x7E, 0xD2, 0x09, 0xC5, 0x97, 0x7C, 0xDA, 0xAC, 0x7B, 0xA4, 0xA1, 0x0A, 0xD3, 0x84, 0x1E,
|
||||
0xEA, 0xE3, 0x8E, 0xA3, 0xB2, 0x30, 0x23, 0x84, 0x51, 0x0C, 0x78, 0x43, 0x46, 0x86, 0xF0, 0x10,
|
||||
0xED, 0xF6, 0x57, 0xA7, 0x40, 0x33, 0xCC, 0x19, 0xC6, 0xB7, 0xFA, 0x45, 0x7C, 0x22, 0x26, 0x07,
|
||||
0x0F, 0xC7, 0x6E, 0x86, 0xB7, 0x71, 0xA4, 0xC3, 0x1E, 0x54, 0x9F, 0xAF, 0x84, 0x94, 0xEB, 0x84,
|
||||
0x6E, 0xE8, 0xDE, 0xA6, 0xC8, 0xA6, 0xBB, 0x93, 0xF6, 0x06, 0x1B, 0x49, 0x82, 0x06, 0x01, 0xAC,
|
||||
0x6A, 0x69, 0x9C, 0x44, 0xC2, 0xFF, 0x84, 0xA0, 0xDD, 0x87, 0xD2, 0xF7, 0xFB, 0xF8, 0x05, 0x14,
|
||||
0x59, 0x3F, 0x6B, 0x68, 0x90, 0x11, 0x78, 0x8F, 0xA1, 0x6F, 0x0F, 0x7B, 0x62, 0x47, 0xD0, 0xB1,
|
||||
0xBB, 0x80, 0x7D, 0x3C, 0x1F, 0x09, 0x7B, 0xE9, 0x60, 0x32, 0x78, 0xB1, 0xE6, 0x1B, 0xD0, 0x9C,
|
||||
0x9D, 0xA5, 0x56, 0x47, 0xB7, 0x47, 0x4B, 0x42, 0xCA, 0xBA, 0x34, 0x40, 0x30, 0xE4, 0x80, 0x9F,
|
||||
0x74, 0xD9, 0x4F, 0x64, 0x4B, 0x3F, 0x7C, 0x04, 0x76, 0x45, 0x1C, 0x58, 0xA2, 0xC8, 0x5C, 0xC6,
|
||||
0x08, 0x5B, 0xD2, 0x80, 0x58, 0xC1, 0x22, 0x3F, 0x9C, 0x99, 0xCD, 0xB8, 0x4A, 0xF6, 0x3E, 0xD4,
|
||||
0xFF, 0x26, 0x4C, 0xBF, 0xD5, 0xA0, 0x38, 0x40, 0x30, 0x1D, 0x04, 0x9A, 0xE0, 0x8C, 0x04, 0x6A,
|
||||
0x87, 0xB6, 0x16, 0x3F, 0x0C, 0xF9, 0xC5, 0x85, 0x43, 0x77, 0x50, 0x9B, 0xF8, 0x75, 0xA3, 0x9A,
|
||||
0xAD, 0x2A, 0x1D, 0x7C, 0xF9, 0xD3, 0x00, 0x7D, 0xFC, 0xA8, 0x5F, 0x7C, 0xC8, 0xEB, 0x69, 0xC4,
|
||||
0xAC, 0x16, 0xEB, 0xED, 0x53, 0xBE, 0x66, 0x95, 0xFC, 0x81, 0x65, 0x17, 0x65, 0xEB, 0x0B, 0x7F,
|
||||
0xF7, 0x57, 0x35, 0x50, 0x43, 0xBB, 0xC5, 0x1A, 0xC9, 0xA2, 0xCF, 0x7B, 0x1D, 0xC0, 0x9E, 0x02,
|
||||
0x79, 0x29, 0x23, 0xB6, 0x24, 0xCF, 0x55, 0x5A, 0x52, 0x3A, 0x51, 0xCE, 0x03, 0xB9, 0x0F, 0xF7,
|
||||
0x45, 0x5F, 0x10, 0xE7, 0x78, 0xD6, 0x2B, 0xF8, 0xD0, 0x8C, 0x7F, 0xE8, 0xA1, 0xA5, 0x7F, 0x07,
|
||||
0x51, 0xE4, 0xF6, 0xB8, 0xC4, 0xB5, 0xF1, 0xC4, 0xC0, 0x18, 0x2A, 0xD2, 0xC3, 0x86, 0xB9, 0xB1,
|
||||
0x35, 0xD8, 0xDD, 0xD3, 0x77, 0x73, 0xAB, 0x01, 0x4A, 0xDE, 0x76, 0x5F, 0x3C, 0x6E, 0x56, 0xB3,
|
||||
0x82, 0xC3, 0x7B, 0x03, 0x81, 0x29, 0x7F, 0xE0, 0x83, 0x40, 0xF4, 0x52, 0xF5, 0x32, 0x6A, 0x12,
|
||||
0x32, 0x84, 0xBE, 0xBE, 0x92, 0xDA, 0x04, 0x32, 0x40, 0xCF, 0x13, 0xE8, 0x5E, 0x6D, 0x79, 0x71,
|
||||
0x5C, 0x98, 0x8C, 0x83, 0xEE, 0x37, 0xE2, 0x65, 0xAA, 0x83, 0xF9, 0xD5, 0xD8, 0xDF, 0x5B, 0x70,
|
||||
0x46, 0x64, 0xAB, 0xAA, 0x16, 0x53, 0x66, 0x4B, 0x7F, 0xA6, 0x79, 0x24, 0xBC, 0xD5, 0x35, 0xEF,
|
||||
0x14, 0xF6, 0xEA, 0x75, 0xF1, 0xD3, 0x41, 0x18, 0x44, 0x58, 0xD8, 0xA0, 0x49, 0x52, 0x99, 0x7B,
|
||||
0x25, 0x6B, 0x65, 0x4B, 0x1B, 0xC7, 0x1D, 0xFB, 0x87, 0x27, 0x8D, 0x3B, 0xBD, 0xC1, 0xF7, 0xD3,
|
||||
0x51, 0xED, 0x7F, 0x43, 0xB6, 0x23, 0xC2, 0x70, 0x61, 0xB3, 0xB0, 0x0D, 0xB2, 0xE9, 0x58, 0x5E,
|
||||
0xFA, 0x23, 0xD1, 0xC7, 0x06, 0x76, 0xBF, 0x48, 0x06, 0xF4, 0xF9, 0xFC, 0x1C, 0x6F, 0xD6, 0xF8,
|
||||
0xFF, 0x9E, 0x40, 0xCF, 0xAD, 0xB7, 0x95, 0xF7, 0x2C, 0x5B, 0xD2, 0xD5, 0x49, 0xA3, 0xAB, 0xCA,
|
||||
0x3E, 0x5B, 0xB0, 0x8B, 0x2E, 0x70, 0x27, 0x7D, 0x36, 0x88, 0xB5, 0x25, 0xBA, 0xE9, 0x67, 0x62,
|
||||
0xB0, 0xA8, 0x26, 0x8C, 0xA4, 0xB7, 0x14, 0xAE, 0xEC, 0xF1, 0x0D, 0xF1, 0x3E, 0xFC, 0x76, 0x5A,
|
||||
0x27, 0x32, 0x60, 0xBE, 0x71, 0x74, 0xE2, 0x54, 0x66, 0xC1, 0xAF, 0x6E, 0xBD, 0x11, 0x3A, 0x1F,
|
||||
0x0A, 0x0B, 0xF5, 0x61, 0x04, 0xF3, 0x0A, 0x2B, 0x8B, 0x90, 0x8F, 0x82, 0x42, 0x03, 0x18, 0x1B,
|
||||
0xC5, 0x08, 0x53, 0xB9, 0x53, 0x35, 0xB1, 0x05, 0x9F, 0x05, 0x59, 0x85, 0x2C, 0x25, 0x48, 0xD3,
|
||||
0x2C, 0xB6, 0xFE, 0xF8, 0x3B, 0x08, 0x49, 0xF3, 0xC1, 0x56, 0x87, 0x49, 0xEB, 0x4D, 0x05, 0x1F,
|
||||
0xE5, 0x0F, 0xB5, 0x99, 0xDA, 0xBF, 0x78, 0xC9, 0xFA, 0x1F, 0x62, 0x66, 0x4B, 0xB8, 0x76, 0xAF,
|
||||
0x69, 0xDD, 0x4A, 0x80, 0x52, 0x58, 0xB2, 0x04, 0x0B, 0x87, 0x66, 0xF9, 0xE2, 0xF0, 0x66, 0x15,
|
||||
0x7F, 0x4C, 0x40, 0x6B, 0x4A, 0xD6, 0x47, 0xD8, 0x81, 0xF1, 0x3B, 0xEF, 0x5C, 0xF7, 0x10, 0x7D,
|
||||
0x5C, 0xBC, 0x53, 0x11, 0xFF, 0x8B, 0x6D, 0x4C, 0x08, 0x16, 0x47, 0x48, 0xF2, 0xA0, 0x2C, 0xEF,
|
||||
0x33, 0x31, 0x90, 0x94, 0x45, 0x66, 0xC8, 0x3F, 0x84, 0x11, 0xDA, 0x8C, 0xD7, 0x90, 0x8F, 0xF0,
|
||||
0x3D, 0xF2, 0xBB, 0x86, 0xFF, 0x90, 0xF3, 0xFB, 0x52, 0xF5, 0x60, 0x3E, 0xF3, 0xBD, 0xAC, 0x3A,
|
||||
0x6C, 0x74, 0x7D, 0x03, 0x85, 0xB6, 0xFA, 0xA4, 0x75, 0xD6, 0x52, 0xDB, 0xD2, 0xB8, 0x30, 0xF1,
|
||||
0x78, 0x7B, 0xCF, 0xC5, 0x57, 0xDF, 0x52, 0xB9, 0xEF, 0xC5, 0xEF, 0xCA, 0x6D, 0x38, 0x0E, 0x28,
|
||||
0xC4, 0x9D, 0x93, 0x4D, 0x73, 0x0A, 0xD1, 0x11, 0xAD, 0x33, 0x27, 0xC9, 0x7E, 0xF8, 0x85, 0x1D,
|
||||
0x05, 0x41, 0x6A, 0xAA, 0x6A, 0xA5, 0xBE, 0xD0, 0x93, 0x05, 0x8A, 0x73, 0xF2, 0xF0, 0x61, 0x94,
|
||||
0x25, 0xF0, 0xA9, 0x12, 0x12, 0xD8, 0xFF, 0xB1, 0xF0, 0x06, 0xA5, 0x47, 0x69, 0x15, 0xCC, 0xE9,
|
||||
0x6B, 0x9D, 0x6E, 0xD9, 0x96, 0xA7, 0xEF, 0x9D, 0x75, 0x9A, 0xD0, 0xD7, 0x90, 0xFE, 0xAF, 0xEB,
|
||||
0xC1, 0xBA, 0x83, 0x48, 0x46, 0x54, 0x7C, 0x86, 0x4B, 0x45, 0x4B, 0xA6, 0xE4, 0x3A, 0x33, 0x52,
|
||||
0xFD, 0xAF, 0x45, 0x92, 0xF4, 0xB0, 0x88, 0x62, 0x28, 0x9D, 0x52, 0x14, 0xBE, 0x5F, 0xD8, 0xCB,
|
||||
0x32, 0x69, 0xC8, 0xB3, 0xB3, 0x27, 0xE4, 0xDC, 0x85, 0xCD, 0x3D, 0x84, 0x51, 0xC1, 0xB6, 0x1F,
|
||||
0x50, 0x9F, 0x80, 0x9B, 0xF2, 0xA8, 0xCE, 0x59, 0xAF, 0x25, 0xA7, 0x5A, 0xD6, 0x23, 0xDA, 0xFF,
|
||||
0xDC, 0x0A, 0xF1, 0xF8, 0x93, 0x1D, 0xE3, 0x00, 0x90, 0x64, 0x91, 0xCF, 0xEC, 0xDC, 0x40, 0xB8,
|
||||
0x64, 0x10, 0xBC, 0x1E, 0x07, 0xF6, 0x98, 0xC1, 0xDE, 0x1B, 0xF3, 0x7D, 0x3A, 0x63, 0x2D, 0x82,
|
||||
0xD0, 0x55, 0x0A, 0x45, 0x3F, 0x12, 0x9D, 0xF1, 0x97, 0x9E, 0x5C, 0xAD, 0x2F, 0x1E, 0x36, 0x13,
|
||||
0x56, 0xFC, 0xEF, 0xF5, 0x59, 0x9A, 0x2B, 0xE5, 0x99, 0xBB, 0x58, 0xD8, 0x18, 0xD4, 0xB0, 0x0C,
|
||||
0x6E, 0x84, 0x7A, 0x50, 0x4C, 0x37, 0x52, 0x32, 0x77, 0xE8, 0x4D, 0x4B, 0x98, 0x42, 0x74, 0x98,
|
||||
0x92, 0x42, 0xA9, 0x38, 0x78, 0xBE, 0x51, 0xC0, 0x87, 0x66, 0x5B, 0x20, 0x1C, 0xBC, 0xE6, 0x60,
|
||||
0xA4, 0x4F, 0x19, 0x13, 0x61, 0x5E, 0x85, 0x3B, 0xE4, 0xC6, 0x98, 0xCE, 0x13, 0x0A, 0xA1, 0x97,
|
||||
0xA8, 0x28, 0x6A, 0x8A, 0xFA, 0x9D, 0x55, 0xA6, 0x64, 0x23, 0x96, 0x1D, 0xB2, 0x2A, 0x51, 0x27,
|
||||
0xB6, 0x00, 0x83, 0x96, 0xF6, 0x05, 0x0F, 0x8F, 0xF4, 0x7D, 0x17, 0x20, 0x10, 0xB9, 0x7C, 0xA2,
|
||||
0x70, 0x81, 0x58, 0x15, 0x06, 0x49, 0xCA, 0xD1, 0x22, 0x21, 0xC4, 0x9E, 0x07, 0xD2, 0x1F, 0x34,
|
||||
0x57, 0x6F, 0xB5, 0xED, 0x81, 0x3D, 0x88, 0x5F, 0x8F, 0x9C, 0x0D, 0xEC, 0x65, 0xCC, 0x52, 0x7F,
|
||||
0x26, 0xCC, 0x3E, 0xB4, 0xEF, 0x7E, 0xD6, 0x6F, 0x18, 0xA8, 0xF7, 0xA0, 0xA8, 0x87, 0x78, 0x6A,
|
||||
0x4C, 0xFB, 0xEC, 0x5C, 0x4A, 0xE5, 0x2D, 0x99, 0xF2, 0x13, 0x0F, 0x6D, 0xA3, 0xD9, 0x0D, 0x40,
|
||||
0xFD, 0xF3, 0xC8, 0x5C, 0xE8, 0xCA, 0xF1, 0x10, 0xE7, 0x40, 0xAA, 0xE5, 0x26, 0x22, 0x6D, 0xF0,
|
||||
0xE9, 0x5B, 0xB0, 0x5F, 0x2F, 0x48, 0xD1, 0x74, 0x93, 0xC7, 0x62, 0x1E, 0x5D, 0xE8, 0x6B, 0xBA,
|
||||
0x3B, 0xC6, 0xB5, 0x0E, 0x7D, 0x5B, 0x0F, 0x1B, 0x4A, 0x9E, 0x28, 0xBC, 0x78, 0xDF, 0x8C, 0x61,
|
||||
0x3A, 0xCD, 0xB6, 0xEF, 0x9D, 0xAE, 0x35, 0x4F, 0xEB, 0x43, 0x9E, 0xCC, 0xA2, 0x1C, 0xAC, 0x40,
|
||||
0x94, 0xE8, 0x96, 0x97, 0x1C, 0x54, 0xBB, 0x59, 0x49, 0x01, 0x71, 0xA6, 0x95, 0xB2, 0x58, 0x2C,
|
||||
0xAD, 0x91, 0x01, 0x39, 0x53, 0x9B, 0xF4, 0x7F, 0xC3, 0x26, 0xFB, 0x95, 0x5D, 0x56, 0xB8, 0x98,
|
||||
0x30, 0x48, 0xC6, 0xE5, 0xC8, 0xBA, 0xE2, 0x88, 0x9C, 0x1F, 0x7B, 0x6F, 0xAD, 0x63, 0xB6, 0xAB,
|
||||
0x93, 0xB5, 0xEE, 0xBF, 0x42, 0xEC, 0x8F, 0xA6, 0x09, 0xC4, 0xB4, 0x6B, 0x5B, 0x16, 0x14, 0xCB,
|
||||
0xA4, 0xCC, 0x94, 0x62, 0xA7, 0x82, 0x6B, 0xED, 0xAC, 0x51, 0x23, 0x78, 0x8B, 0xF1, 0x48, 0xD6,
|
||||
0x12, 0x5F, 0xE7, 0x1D, 0x14, 0xD8, 0xF9, 0x42, 0xCA, 0xB9, 0x12, 0xFD, 0xDC, 0x29, 0xCB, 0x70,
|
||||
0xD8, 0x2B, 0x70, 0x75, 0xFC, 0x74, 0xAA, 0xA4, 0xEF, 0xFE, 0xD7, 0xF0, 0x29, 0xD5, 0xA8, 0xA7,
|
||||
0x9D, 0x9A, 0x88, 0x93, 0xE0, 0xFD, 0xC8, 0xD2, 0x4C, 0x81, 0x3D, 0x71, 0x25, 0x7A, 0x5C, 0xE8,
|
||||
0xC8, 0xBA, 0xBA, 0x15, 0x71, 0x1D, 0x77, 0x15, 0x3B, 0x34, 0x87, 0x61, 0xD1, 0xA5, 0xF4, 0x59,
|
||||
0x75, 0x18, 0x5D, 0x85, 0x4B, 0xE7, 0x15, 0x9B, 0xCE, 0xD0, 0x9C, 0x08, 0x90, 0x97, 0x55, 0x0B,
|
||||
0x06, 0x8E, 0xFA, 0x18, 0x99, 0xBC, 0xB1, 0x78, 0x80, 0xC7, 0x59, 0xEC, 0x43, 0x8C, 0x55, 0x32,
|
||||
0xCF, 0x2E, 0xDE, 0xC6, 0x23, 0xFA, 0xAE, 0xE5, 0xFC, 0x44, 0x78, 0x4A, 0xB9, 0xD2, 0xE5, 0xDC,
|
||||
0xE3, 0x47, 0x0D, 0xF2, 0x33, 0x77, 0xB3, 0xA7, 0x0A, 0x6B, 0xFC, 0xDA, 0xD3, 0x9B, 0x4A, 0x09,
|
||||
0x30, 0xC7, 0xE2, 0xB2, 0x9C, 0xE1, 0x46, 0xEA, 0xD7, 0xE5, 0x25, 0x1E, 0xA5, 0x08, 0xDD, 0x50,
|
||||
0xA3, 0x1F, 0x20, 0xCF, 0xF4, 0x85, 0x3F, 0xFD, 0x3C, 0xBC, 0xE5, 0xF3, 0x4A, 0xF9, 0xE8, 0x8C,
|
||||
0xF0, 0xAD, 0xCC, 0x27, 0x60, 0x29, 0xE2, 0xCD, 0x8C, 0xA0, 0x96, 0x0E, 0xD0, 0x2B, 0x9E, 0xB4,
|
||||
0x58, 0x11, 0x9C, 0x20, 0xC7, 0xB8, 0x3D, 0xB3, 0xA2, 0x85, 0x0F, 0x01, 0xBE, 0x19, 0x17, 0xC1,
|
||||
0x7E, 0x37, 0x75, 0xA1, 0xDB, 0x65, 0x85, 0x6F, 0xA0, 0x31, 0xE5, 0x11, 0x72, 0x1E, 0x91, 0x11,
|
||||
0x85, 0x88, 0xE1, 0x2F, 0xD6, 0xFC, 0xBA, 0x98, 0x13, 0x1E, 0xC5, 0xBF, 0xC1, 0xB6, 0xFA, 0xCC,
|
||||
0xBC, 0x73, 0x39, 0x2C, 0xC6, 0xFE, 0xF6, 0x4C, 0x70, 0xBC, 0xEA, 0x14, 0xEA, 0x61, 0x86, 0x93,
|
||||
0x38, 0x29, 0xFF, 0x1B, 0x83, 0x30, 0x0F, 0xEF, 0xE5, 0x58, 0xAF, 0x03, 0x72, 0x9F, 0xD3, 0x24,
|
||||
0xB3, 0x7E, 0x7F, 0x33, 0x76, 0x0E, 0x51, 0x5C, 0x41, 0x47, 0xBC, 0x30, 0x73, 0xF1, 0x64, 0xCA,
|
||||
0x87, 0x7F, 0xD0, 0xB7, 0x74, 0x03, 0x50, 0xA4, 0x0D, 0xBA, 0xB3, 0x24, 0x6F, 0x5E, 0x22, 0x89,
|
||||
0x6B, 0xD4, 0x07, 0xD3, 0x6B, 0x4D, 0x36, 0x5B, 0x8F, 0x85, 0xE6, 0xF3, 0x8A, 0x94, 0xDD, 0x60,
|
||||
0x70, 0x49, 0x14, 0x7F, 0x0A, 0xBC, 0x7B, 0xB2, 0xD0, 0x11, 0x87, 0x9E, 0xA2, 0x8D, 0xCF, 0x89,
|
||||
0x56, 0x34, 0x66, 0x71, 0x03, 0xB8, 0xF2, 0x93, 0xC3, 0x12, 0x10, 0x49, 0x29, 0x4B, 0x0A, 0xC8,
|
||||
0x88, 0x4C, 0x87, 0x0F, 0x84, 0x50, 0x74, 0x5B, 0x22, 0x78, 0xCF, 0xF7, 0xC8, 0xAB, 0x92, 0x4F,
|
||||
0x96, 0x54, 0x7B, 0xAB, 0xAE, 0xC2, 0x53, 0x8C, 0x5A, 0xF8, 0x0D, 0x8E, 0x8D, 0x25, 0x4A, 0xDA,
|
||||
0x94, 0xBE, 0x9A, 0x84, 0x56, 0x88, 0x08, 0x59, 0xA0, 0x44, 0x81, 0x48, 0x29, 0xF4, 0x38, 0x1B,
|
||||
0xD9, 0xBA, 0xB2, 0x1E, 0xA7, 0x9A, 0xA8, 0x06, 0x77, 0x76, 0x92, 0x7B, 0x25, 0x21, 0x4F, 0x41,
|
||||
0x3B, 0x2D, 0xE4, 0xD9, 0xC7, 0xE2, 0xE6, 0x43, 0x5A, 0x18, 0xA3, 0x92, 0xFE, 0xAB, 0x24, 0xC0,
|
||||
0x58, 0xC8, 0x02, 0xD8, 0xD1, 0x6C, 0xDD, 0xC9, 0x40, 0x1F, 0xD2, 0xF7, 0x90, 0xDB, 0x29, 0x22,
|
||||
0x26, 0x26, 0x83, 0xEA, 0xEB, 0xE2, 0x8A, 0x83, 0x56, 0x32, 0xDB, 0xE8, 0xF6, 0x06, 0x40, 0xE5,
|
||||
0x8B, 0xC4, 0xA8, 0xFC, 0x45, 0x2A, 0x22, 0xCF, 0xAB, 0xF6, 0x85, 0x73, 0x97, 0xC6, 0x91, 0xF1,
|
||||
0x2B, 0x31, 0xDC, 0x1C, 0xB2, 0x62, 0x9B, 0x6A, 0x02, 0xAC, 0x94, 0xDC, 0x5B, 0x39, 0xF0, 0xB6,
|
||||
0x57, 0xE8, 0x39, 0x9A, 0xA9, 0x87, 0x3F, 0x65, 0x5F, 0xD4, 0x49, 0x84, 0x91, 0x74, 0xEA, 0x7E,
|
||||
0xD2, 0x44, 0x74, 0x2A, 0xA7, 0x82, 0x28, 0x64, 0x85, 0x2E, 0x0D, 0xB1, 0x93, 0x51, 0x04, 0x0C,
|
||||
0x16, 0x3D, 0x42, 0xE2, 0x8F, 0xE9, 0x9F, 0x78, 0xD7, 0xD4, 0x18, 0xC2, 0x9F, 0x9C, 0x9A, 0x6B,
|
||||
0x03, 0x95, 0xF1, 0x23, 0xD1, 0x2B, 0x4C, 0x05, 0x1B, 0x8F, 0x21, 0x3B, 0x49, 0x91, 0xD6, 0xBB,
|
||||
0xE6, 0x7F, 0xF7, 0x41, 0x52, 0x67, 0x1E, 0x76, 0xDF, 0xF6, 0x8B, 0x7E, 0x84, 0xCD, 0x5A, 0x4F,
|
||||
0xB9, 0x7B, 0xEB, 0xBF, 0xFF, 0xC9, 0xC4, 0x69, 0x1D, 0x34, 0xDE, 0x2D, 0x33, 0xDE, 0x02, 0x4C,
|
||||
0x7F, 0x38, 0x7D, 0x84, 0xEF, 0x1E, 0x82, 0x6C, 0x28, 0x9E, 0x51, 0xB4, 0x94, 0x40, 0x1F, 0x93,
|
||||
0x20, 0x29, 0xE9, 0x6D, 0x61, 0x48, 0x19, 0x84, 0xC1, 0x70, 0xE5, 0xE1, 0x94, 0xAA, 0x43, 0x73,
|
||||
0xF6, 0x99, 0xC3, 0x1F, 0x5F, 0x52, 0xE6, 0x34, 0x70, 0x8C, 0x76, 0x26, 0xE7, 0xAA, 0x44, 0x26,
|
||||
0xB4, 0x00, 0x3F, 0x2D, 0xA0, 0x5B, 0xDE, 0xC6, 0x02, 0xE2, 0x5B, 0xF6, 0xDB, 0xB2, 0xA0, 0x76,
|
||||
0xFA, 0xA0, 0x95, 0x44, 0x11, 0xEE, 0x8D, 0x42, 0x16, 0x2E, 0x5E, 0xAC, 0xBB, 0xC5, 0x65, 0xE8,
|
||||
0x49, 0x29, 0xC1, 0x3B, 0x6A, 0x8D, 0x27, 0xEB, 0x25, 0x3B, 0x41, 0x19, 0x4A, 0xB3, 0x0A, 0x95,
|
||||
0x20, 0xEB, 0xA6, 0x0B, 0x20, 0xC3, 0xE1, 0xFC, 0x2A, 0x5C, 0xD6, 0xA2, 0x31, 0x70, 0xB0, 0xE6,
|
||||
0xEA, 0xC9, 0x11, 0xAB, 0xD2, 0x41, 0xF2, 0xB4, 0x13, 0xDC, 0x79, 0xAB, 0xA0, 0xF3, 0x3C, 0x13,
|
||||
0xC9, 0xE3, 0x19, 0xC0, 0x1F, 0x7A, 0x48, 0xEB, 0x06, 0x62, 0x4D, 0xEC, 0x67, 0x14, 0x60, 0x83,
|
||||
0xD6, 0xA8, 0xBF, 0xDF, 0x08, 0x21, 0xDF, 0x04, 0x94, 0x26, 0xC9, 0xDA, 0xD0, 0xA3, 0x04, 0xDC,
|
||||
0x03, 0x14, 0x90, 0x17, 0xB8, 0x5A, 0x4B, 0xF6, 0x75, 0x9B, 0xAB, 0xB3, 0xA5, 0xC3, 0xC9, 0xFE,
|
||||
0x75, 0xE1, 0x47, 0x59, 0xB5, 0xD4, 0x17, 0x94, 0xD5, 0xF4, 0x2A, 0x52, 0x7D, 0xCC, 0xC6, 0x4F,
|
||||
0x99, 0x14, 0x65, 0xDE, 0x5C, 0xD7, 0x32, 0xAB, 0x75, 0xA9, 0x6E, 0x82, 0xE3, 0xE7, 0xF4, 0xF3,
|
||||
0xC1, 0x4A, 0xE3, 0x19, 0x4F, 0xD2, 0xA7, 0xFE, 0xE5, 0x42, 0x6E, 0x38, 0xF4, 0x33, 0x6E, 0xF9,
|
||||
0x0C, 0x76, 0xF1, 0x89, 0x55, 0xAB, 0x08, 0x3D, 0xC5, 0x47, 0x4E, 0xB5, 0x2F, 0x00, 0x33, 0x84,
|
||||
0xCD, 0xCE, 0x24, 0xEA, 0xDB, 0x3D, 0x25, 0x9B, 0x24, 0xC1, 0xCA, 0xA3, 0xB6, 0x3A, 0x7D, 0xBF,
|
||||
0x8A, 0xB9, 0x60, 0xEF, 0xE6, 0x2B, 0x8C, 0x4A, 0xAC, 0x3F, 0xA4, 0x0D, 0x82, 0x8E, 0xD1, 0x70,
|
||||
0x67, 0x97, 0xA7, 0x17, 0xB9, 0x52, 0xB2, 0x5A, 0xE8, 0xEC, 0x8D, 0x94, 0xC5, 0x96, 0xFC, 0x9B,
|
||||
0xD3, 0x10, 0x7E, 0xD3, 0x06, 0xB4, 0xAA, 0xC7, 0x63, 0xA1, 0x56, 0x9F, 0x04, 0x7F, 0x96, 0xEE,
|
||||
0x39, 0xDC, 0x18, 0x60, 0x2F, 0x71, 0x2D, 0xEB, 0xF5, 0x1A, 0x4D, 0xFE, 0xB3, 0x49, 0x37, 0xFE,
|
||||
0xC5, 0x7F, 0x6C, 0xEE, 0x17, 0x48, 0xF5, 0xED, 0xA7, 0xB9, 0x95, 0x0B, 0x61, 0x2E, 0x2C, 0x87,
|
||||
0xA7, 0x5D, 0xA5, 0xAC, 0x89, 0xEC, 0x11, 0x0C, 0xD5, 0xCD, 0xE1, 0xB6, 0x9C, 0x4B, 0x8F, 0xCF,
|
||||
0x21, 0x75, 0xA1, 0x1B, 0x35, 0x41, 0x4D, 0x4E, 0x9B, 0xDE, 0xE2, 0xE8, 0x0E, 0x23, 0x9A, 0x9A,
|
||||
0x2B, 0xAC, 0x41, 0x6E, 0xEF, 0xD1, 0xAC, 0x7E, 0x74, 0xB7, 0x16, 0x83, 0x10, 0x85, 0x84, 0x60,
|
||||
0x28, 0xF0, 0xD1, 0xA0, 0x5E, 0xB7, 0x8E, 0xEF, 0x7B, 0x4C, 0x27, 0xAF, 0x8A, 0x9E, 0x3F, 0x29,
|
||||
0x1B, 0x12, 0x01, 0x07, 0xF1, 0xAA, 0xFE, 0x2E, 0xFF, 0x18, 0x9A, 0xCD, 0xF4, 0x0E, 0xC1, 0x74,
|
||||
0x6D, 0xD4, 0xCE, 0xF3, 0xF9, 0x3C, 0xE2, 0x12, 0x03, 0x07, 0x1B, 0x9D, 0x3D, 0x6E, 0xD9, 0x79,
|
||||
0xB3, 0x56, 0x14, 0xC5, 0xEA, 0x06, 0xD1, 0xAD, 0x2C, 0x07, 0x58, 0x90, 0x0E, 0x80, 0x6B, 0x60,
|
||||
0x43, 0x82, 0xAA, 0x0C, 0xEE, 0x1B
|
||||
};
|
||||
|
||||
uint8 Module_0DBBF209A27B1E279A9FEC5C168A15F7_Key[16] =
|
||||
{
|
||||
0x5B, 0x27, 0x27, 0x01, 0x24, 0x56, 0xB4, 0xD4, 0x2D, 0xD0, 0x96, 0x77, 0x49, 0x51, 0xDC, 0x0A
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,509 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Warden.cpp
|
||||
* @brief Warden anti-cheat system base implementation
|
||||
*
|
||||
* This file implements the base Warden class which provides anti-cheat
|
||||
* functionality for the World of Warcraft client. Warden is Blizzard's
|
||||
* anti-cheat system that runs on the client and reports back to the server.
|
||||
*
|
||||
* Key features:
|
||||
* - Module initialization and loading
|
||||
* - Encrypted communication using RC4
|
||||
* - Memory and process checks
|
||||
* - Hash verification
|
||||
* - Check timing and response handling
|
||||
*
|
||||
* @see Warden for the base class
|
||||
* @see WardenWin for Windows-specific implementation
|
||||
* @see WardenMac for macOS-specific implementation
|
||||
*/
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Common/TimeConstants.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include <openssl/sha.h>
|
||||
#include "World.h"
|
||||
#include "Util.h"
|
||||
#include "Warden.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "GameTime.h"
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief Warden constructor
|
||||
*
|
||||
* Initializes the Warden system with default values:
|
||||
* - Check timer: 10 seconds
|
||||
* - State: STATE_INITIAL
|
||||
* - Keys and seed: zeroed
|
||||
*/
|
||||
Warden::Warden() : _session(NULL), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0),
|
||||
_module(NULL), _state(WardenState::STATE_INITIAL)
|
||||
{
|
||||
memset(_inputKey, 0, sizeof(_inputKey));
|
||||
memset(_outputKey, 0, sizeof(_outputKey));
|
||||
memset(_seed, 0, sizeof(_seed));
|
||||
_previousTimestamp = GameTime::GetGameTimeMS();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Warden destructor
|
||||
*
|
||||
* Cleans up the Warden module data.
|
||||
*/
|
||||
Warden::~Warden()
|
||||
{
|
||||
delete[] _module->CompressedData;
|
||||
delete _module;
|
||||
_module = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize Warden module
|
||||
*
|
||||
* Sets the state to STATE_INITIALIZE_MODULE to begin
|
||||
* the module initialization process.
|
||||
*/
|
||||
void Warden::InitializeModule()
|
||||
{
|
||||
SetNewState(WardenState::STATE_INITIALIZE_MODULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request hash from client
|
||||
*
|
||||
* Sends a hash request packet to the client to verify
|
||||
* the module's integrity. The client will respond with
|
||||
* a hash computed using the provided seed.
|
||||
*/
|
||||
void Warden::RequestHash()
|
||||
{
|
||||
sLog.outWarden("Request hash");
|
||||
|
||||
// Create packet structure
|
||||
WardenHashRequest Request;
|
||||
Request.Command = WARDEN_SMSG_HASH_REQUEST;
|
||||
memcpy(Request.Seed, _seed, 16);
|
||||
|
||||
// Encrypt with warden RC4 key.
|
||||
EncryptData((uint8*)&Request, sizeof(WardenHashRequest));
|
||||
|
||||
WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenHashRequest));
|
||||
pkt.append((uint8*)&Request, sizeof(WardenHashRequest));
|
||||
_session->SendPacket(&pkt);
|
||||
|
||||
SetNewState(WardenState::STATE_REQUESTED_HASH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send Warden module to client
|
||||
*
|
||||
* Transfers the Warden module to the client in 500-byte bursts.
|
||||
* The module is sent encrypted using the Warden RC4 key.
|
||||
*/
|
||||
void Warden::SendModuleToClient()
|
||||
{
|
||||
sLog.outWarden("Send module to client");
|
||||
|
||||
// Create packet structure
|
||||
WardenModuleTransfer packet;
|
||||
|
||||
uint32 sizeLeft = _module->CompressedSize;
|
||||
uint32 pos = 0;
|
||||
uint16 burstSize;
|
||||
while (sizeLeft > 0)
|
||||
{
|
||||
burstSize = sizeLeft < 500 ? sizeLeft : 500;
|
||||
packet.Command = WARDEN_SMSG_MODULE_CACHE;
|
||||
packet.DataSize = burstSize;
|
||||
memcpy(packet.Data, &_module->CompressedData[pos], burstSize);
|
||||
sizeLeft -= burstSize;
|
||||
pos += burstSize;
|
||||
|
||||
EncryptData((uint8*)&packet, burstSize + 3);
|
||||
WorldPacket pkt1(SMSG_WARDEN_DATA, burstSize + 3);
|
||||
pkt1.append((uint8*)&packet, burstSize + 3);
|
||||
_session->SendPacket(&pkt1);
|
||||
}
|
||||
|
||||
SetNewState(WardenState::STATE_SENT_MODULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Requests that the client load and use the active Warden module.
|
||||
*/
|
||||
void Warden::RequestModule()
|
||||
{
|
||||
sLog.outWarden("Request module");
|
||||
|
||||
// Create packet structure
|
||||
WardenModuleUse request;
|
||||
request.Command = WARDEN_SMSG_MODULE_USE;
|
||||
|
||||
memcpy(request.ModuleId, _module->Id, 16);
|
||||
memcpy(request.ModuleKey, _module->Key, 16);
|
||||
request.Size = _module->CompressedSize;
|
||||
|
||||
// Encrypt with warden RC4 key.
|
||||
EncryptData((uint8*)&request, sizeof(WardenModuleUse));
|
||||
|
||||
WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenModuleUse));
|
||||
pkt.append((uint8*)&request, sizeof(WardenModuleUse));
|
||||
_session->SendPacket(&pkt);
|
||||
|
||||
SetNewState(WardenState::STATE_REQUESTED_MODULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Advances Warden timers and requests new checks when appropriate.
|
||||
*/
|
||||
void Warden::Update()
|
||||
{
|
||||
uint32 currentTimestamp = GameTime::GetGameTimeMS();
|
||||
uint32 diff = currentTimestamp - _previousTimestamp;
|
||||
_previousTimestamp = currentTimestamp;
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case WardenState::STATE_INITIAL:
|
||||
break;
|
||||
case WardenState::STATE_REQUESTED_MODULE:
|
||||
case WardenState::STATE_SENT_MODULE:
|
||||
case WardenState::STATE_REQUESTED_HASH:
|
||||
case WardenState::STATE_REQUESTED_DATA:
|
||||
{
|
||||
uint32 maxClientResponseDelay = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY);
|
||||
|
||||
if (maxClientResponseDelay > 0)
|
||||
{
|
||||
// Kick player if client response delays more than set in config
|
||||
if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS)
|
||||
{
|
||||
sLog.outWarden("%s (latency: %u, IP: %s) exceeded Warden module response delay on state %s for more than %s - disconnecting client",
|
||||
_session->GetPlayerName(), _session->GetLatency(), _session->GetRemoteAddress().c_str(), WardenState::to_string(_state), secsToTimeString(maxClientResponseDelay, TimeFormat::ShortText).c_str());
|
||||
_session->KickPlayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
_clientResponseTimer += diff;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WardenState::STATE_INITIALIZE_MODULE:
|
||||
case WardenState::STATE_RESTING:
|
||||
{
|
||||
if (diff >= _checkTimer)
|
||||
{
|
||||
RequestData();
|
||||
}
|
||||
else
|
||||
{
|
||||
_checkTimer -= diff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sLog.outWarden("Unimplemented warden state!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decrypts an incoming Warden payload.
|
||||
*
|
||||
* @param buffer The encrypted buffer.
|
||||
* @param length The buffer length.
|
||||
*/
|
||||
void Warden::DecryptData(uint8* buffer, uint32 length)
|
||||
{
|
||||
_inputCrypto.UpdateData(length, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encrypts an outgoing Warden payload.
|
||||
*
|
||||
* @param buffer The plaintext buffer.
|
||||
* @param length The buffer length.
|
||||
*/
|
||||
void Warden::EncryptData(uint8* buffer, uint32 length)
|
||||
{
|
||||
_outputCrypto.UpdateData(length, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes Warden runtime state and resets related timers.
|
||||
*
|
||||
* @param state The new Warden state.
|
||||
*/
|
||||
void Warden::SetNewState(WardenState::Value state)
|
||||
{
|
||||
//if we pass all initial checks, allow change
|
||||
if (state < WardenState::STATE_REQUESTED_DATA)
|
||||
{
|
||||
if (state < _state)
|
||||
{
|
||||
sLog.outWarden("Warden Error: jump from %s to %s which is lower by initialization routine", WardenState::to_string(_state), WardenState::to_string(state));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_state = state;
|
||||
|
||||
//Reset timers
|
||||
// Set hold off timer, minimum timer should at least be 1 second
|
||||
uint32 holdOff = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF);
|
||||
_checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS;
|
||||
|
||||
_clientResponseTimer = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validates a Warden payload checksum.
|
||||
*
|
||||
* @param checksum The received checksum.
|
||||
* @param data The payload data.
|
||||
* @param length The payload length.
|
||||
* @return true if the checksum matches; otherwise false.
|
||||
*/
|
||||
bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 length)
|
||||
{
|
||||
uint32 newChecksum = BuildChecksum(data, length);
|
||||
|
||||
if (checksum != newChecksum)
|
||||
{
|
||||
sLog.outWarden("CHECKSUM IS NOT VALID");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outWarden("CHECKSUM IS VALID");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
struct keyData {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8 bytes[20];
|
||||
} bytes;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 ints[5];
|
||||
} ints;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builds the XOR-folded SHA1 checksum used by Warden packets.
|
||||
*
|
||||
* @param data The payload data.
|
||||
* @param length The payload length.
|
||||
* @return uint32 The calculated checksum.
|
||||
*/
|
||||
uint32 Warden::BuildChecksum(const uint8* data, uint32 length)
|
||||
{
|
||||
keyData hash;
|
||||
SHA1(data, length, hash.bytes.bytes);
|
||||
uint32 checkSum = 0;
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
{
|
||||
checkSum = checkSum ^ hash.ints.ints[i];
|
||||
}
|
||||
|
||||
return checkSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Applies the configured penalty for a Warden failure.
|
||||
*
|
||||
* @param check The Warden check that triggered the penalty, if any.
|
||||
* @return std::string A textual description of the applied penalty.
|
||||
*/
|
||||
std::string Warden::Penalty(WardenCheck* check /*= NULL*/)
|
||||
{
|
||||
WardenActions action;
|
||||
|
||||
if (check)
|
||||
{
|
||||
action = check->Action;
|
||||
}
|
||||
else
|
||||
{
|
||||
action = WardenActions(sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_FAIL_ACTION));
|
||||
}
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case WARDEN_ACTION_LOG:
|
||||
return "None";
|
||||
break;
|
||||
case WARDEN_ACTION_KICK:
|
||||
_session->KickPlayer();
|
||||
return "Kick";
|
||||
break;
|
||||
case WARDEN_ACTION_BAN:
|
||||
{
|
||||
std::stringstream duration;
|
||||
std::string accountName;
|
||||
sAccountMgr.GetName(_session->GetAccountId(), accountName);
|
||||
std::stringstream banReason;
|
||||
banReason << "Warden Anticheat Violation";
|
||||
// Check can be NULL, for example if the client sent a wrong signature in the warden packet (CHECKSUM FAIL)
|
||||
if (check)
|
||||
{
|
||||
banReason << ": " << (check->Comment.empty() ? std::string("Undocumented Check") : check->Comment) << " (CheckId: " << check->CheckId << ")";
|
||||
}
|
||||
|
||||
sWorld.BanAccount(BAN_ACCOUNT, accountName, sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_BAN_DURATION), banReason.str(), "Warden");
|
||||
|
||||
return "Ban";
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Undefined";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles an incoming Warden data packet from the client.
|
||||
*
|
||||
* @param recvData The incoming Warden packet.
|
||||
*/
|
||||
void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData)
|
||||
{
|
||||
if (!_warden || recvData.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_warden->DecryptData(const_cast<uint8*>(recvData.contents()), recvData.size());
|
||||
uint8 opcode;
|
||||
recvData >> opcode;
|
||||
sLog.outWarden("Got packet, opcode %02X, size %u", opcode, uint32(recvData.size()));
|
||||
recvData.hexlike();
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case WARDEN_CMSG_MODULE_MISSING:
|
||||
_warden->SendModuleToClient();
|
||||
break;
|
||||
case WARDEN_CMSG_MODULE_OK:
|
||||
_warden->RequestHash();
|
||||
break;
|
||||
case WARDEN_CMSG_CHEAT_CHECKS_RESULT:
|
||||
_warden->HandleData(recvData);
|
||||
break;
|
||||
case WARDEN_CMSG_MEM_CHECKS_RESULT:
|
||||
sLog.outWarden("NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!");
|
||||
break;
|
||||
case WARDEN_CMSG_HASH_RESULT:
|
||||
_warden->HandleHashResult(recvData);
|
||||
_warden->InitializeModule();
|
||||
break;
|
||||
case WARDEN_CMSG_MODULE_FAILED:
|
||||
sLog.outWarden("NYI WARDEN_CMSG_MODULE_FAILED received!");
|
||||
break;
|
||||
default:
|
||||
sLog.outWarden("Got unknown warden opcode %02X of size %u.", opcode, uint32(recvData.size() - 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks Warden as waiting for the next data response.
|
||||
*/
|
||||
void Warden::RequestData()
|
||||
{
|
||||
SetNewState(WardenState::STATE_REQUESTED_DATA);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles a generic Warden data response and returns to resting state.
|
||||
*
|
||||
* @param buff The received payload buffer.
|
||||
*/
|
||||
void Warden::HandleData(ByteBuffer& /*buff*/)
|
||||
{
|
||||
SetNewState(WardenState::STATE_RESTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Logs a positive Warden detection to the database.
|
||||
*
|
||||
* @param check The Warden check that triggered logging.
|
||||
*/
|
||||
void Warden::LogPositiveToDB(WardenCheck* check)
|
||||
{
|
||||
if (!check || !_session)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (uint32(check->Action) < sWorld.getConfig(CONFIG_UINT32_WARDEN_DB_LOGLEVEL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static SqlStatementID insWardenPositive;
|
||||
|
||||
SqlStatement stmt = LoginDatabase.CreateStatement(insWardenPositive, "INSERT INTO `warden_log` (`check`, `action`, `account`, `guid`, `map`, `position_x`, `position_y`, `position_z`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
|
||||
stmt.addUInt16(check->CheckId);
|
||||
stmt.addInt8(check->Action);
|
||||
stmt.addUInt32(_session->GetAccountId());
|
||||
if (Player* pl = _session->GetPlayer())
|
||||
{
|
||||
stmt.addUInt64(pl->GetObjectGuid().GetRawValue());
|
||||
stmt.addUInt32(pl->GetMapId());
|
||||
stmt.addFloat(pl->Where().X());
|
||||
stmt.addFloat(pl->Where().Y());
|
||||
stmt.addFloat(pl->Where().Z());
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt.addUInt64(0);
|
||||
stmt.addUInt32(0xFFFFFFFF);
|
||||
stmt.addFloat(0.0f);
|
||||
stmt.addFloat(0.0f);
|
||||
stmt.addFloat(0.0f);
|
||||
}
|
||||
stmt.Execute();
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _WARDEN_BASE_H
|
||||
#define _WARDEN_BASE_H
|
||||
|
||||
#include "ARC4.h"
|
||||
#include "BigNumber.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include <string>
|
||||
|
||||
// the default client version with info in warden_checks; for other version checks, see warden_build_specific
|
||||
#define DEFAULT_CLIENT_BUILD 8606
|
||||
|
||||
/**
|
||||
* @brief Warden opcode enumeration
|
||||
*/
|
||||
enum WardenOpcodes
|
||||
{
|
||||
// Client->Server
|
||||
WARDEN_CMSG_MODULE_MISSING = 0, ///< Module missing
|
||||
WARDEN_CMSG_MODULE_OK = 1, ///< Module OK
|
||||
WARDEN_CMSG_CHEAT_CHECKS_RESULT = 2, ///< Cheat checks result
|
||||
WARDEN_CMSG_MEM_CHECKS_RESULT = 3, ///< Memory checks result (only sent if MEM_CHECK bytes doesn't match)
|
||||
WARDEN_CMSG_HASH_RESULT = 4, ///< Hash result
|
||||
WARDEN_CMSG_MODULE_FAILED = 5, ///< Module failed (sent when client failed to load uploaded module due to cache fail)
|
||||
|
||||
// Server->Client
|
||||
WARDEN_SMSG_MODULE_USE = 0, ///< Use module
|
||||
WARDEN_SMSG_MODULE_CACHE = 1, ///< Module cache
|
||||
WARDEN_SMSG_CHEAT_CHECKS_REQUEST = 2, ///< Cheat checks request
|
||||
WARDEN_SMSG_MODULE_INITIALIZE = 3, ///< Initialize module
|
||||
WARDEN_SMSG_MEM_CHECKS_REQUEST = 4, ///< Memory checks request (byte len; while (!EOF) { byte unk(1); byte index(++); string module(can be 0); int offset; byte len; byte[] bytes_to_compare[len]; })
|
||||
WARDEN_SMSG_HASH_REQUEST = 5 ///< Hash request
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Warden check type enumeration
|
||||
*/
|
||||
enum WardenCheckType
|
||||
{
|
||||
MEM_CHECK = 0xF3, ///< Memory check (243: byte moduleNameIndex + uint Offset + byte Len - check to ensure memory isn't modified)
|
||||
PAGE_CHECK_A = 0xB2, ///< Page check A (178: uint Seed + byte[20] SHA1 + uint Addr + byte Len - scans all pages for specified hash)
|
||||
PAGE_CHECK_B = 0xBF, ///< Page check B (191: uint Seed + byte[20] SHA1 + uint Addr + byte Len - scans only pages starts with MZ+PE headers for specified hash)
|
||||
MPQ_CHECK = 0x98, ///< MPQ check (152: byte fileNameIndex - check to ensure MPQ file isn't modified)
|
||||
LUA_STR_CHECK = 0x8B, ///< Lua string check (139: byte luaNameIndex - check to ensure LUA string isn't used)
|
||||
DRIVER_CHECK = 0x71, ///< Driver check (113: uint Seed + byte[20] SHA1 + byte driverNameIndex - check to ensure driver isn't loaded)
|
||||
TIMING_CHECK = 0x57, ///< Timing check (87: empty - check to ensure GetTickCount() isn't detoured)
|
||||
PROC_CHECK = 0x7E, ///< Procedure check (126: uint Seed + byte[20] SHA1 + byte moluleNameIndex + byte procNameIndex + uint Offset + byte Len - check to ensure proc isn't detoured)
|
||||
MODULE_CHECK = 0xD9 ///< Module check (217: uint Seed + byte[20] SHA1 - check to ensure module isn't injected)
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Warden module use structure
|
||||
*/
|
||||
struct WardenModuleUse
|
||||
{
|
||||
uint8 Command; ///< Command
|
||||
uint8 ModuleId[16]; ///< Module ID
|
||||
uint8 ModuleKey[16]; ///< Module key
|
||||
uint32 Size; ///< Size
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Warden module transfer structure
|
||||
*/
|
||||
struct WardenModuleTransfer
|
||||
{
|
||||
uint8 Command; ///< Command
|
||||
uint16 DataSize; ///< Data size
|
||||
uint8 Data[500]; ///< Data
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Warden hash request structure
|
||||
*/
|
||||
struct WardenHashRequest
|
||||
{
|
||||
uint8 Command; ///< Command
|
||||
uint8 Seed[16]; ///< Seed
|
||||
};
|
||||
|
||||
namespace WardenState
|
||||
{
|
||||
enum Value
|
||||
{
|
||||
STATE_INITIAL,
|
||||
STATE_REQUESTED_MODULE,
|
||||
STATE_SENT_MODULE,
|
||||
STATE_REQUESTED_HASH,
|
||||
STATE_INITIALIZE_MODULE,
|
||||
STATE_REQUESTED_DATA,
|
||||
STATE_RESTING
|
||||
};
|
||||
|
||||
inline const char* to_string(WardenState::Value value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case WardenState::STATE_INITIAL:
|
||||
return "STATE_INITIAL";
|
||||
case WardenState::STATE_REQUESTED_MODULE:
|
||||
return "STATE_REQUESTED_MODULE";
|
||||
case WardenState::STATE_SENT_MODULE:
|
||||
return "STATE_SENT_MODULE";
|
||||
case WardenState::STATE_REQUESTED_HASH:
|
||||
return "STATE_REQUESTED_HASH";
|
||||
case WardenState::STATE_INITIALIZE_MODULE:
|
||||
return "STATE_INITIALIZE_MODULE";
|
||||
case WardenState::STATE_REQUESTED_DATA:
|
||||
return "STATE_REQUESTED_DATA";
|
||||
case WardenState::STATE_RESTING:
|
||||
return "STATE_RESTING";
|
||||
}
|
||||
return "UNDEFINED STATE";
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
struct ClientWardenModule
|
||||
{
|
||||
uint8 Id[16];
|
||||
uint8 Key[16];
|
||||
uint32 CompressedSize;
|
||||
uint8* CompressedData;
|
||||
};
|
||||
|
||||
class WorldSession;
|
||||
|
||||
class Warden
|
||||
{
|
||||
public:
|
||||
Warden();
|
||||
virtual ~Warden();
|
||||
|
||||
virtual void Init(WorldSession* session, BigNumber* k) = 0;
|
||||
virtual ClientWardenModule* GetModuleForClient() = 0;
|
||||
virtual void InitializeModule();
|
||||
virtual void RequestHash();
|
||||
virtual void HandleHashResult(ByteBuffer &buff) = 0;
|
||||
virtual void RequestData();
|
||||
virtual void HandleData(ByteBuffer &buff);
|
||||
|
||||
void SendModuleToClient();
|
||||
void RequestModule();
|
||||
void Update();
|
||||
void DecryptData(uint8* buffer, uint32 length);
|
||||
void EncryptData(uint8* buffer, uint32 length);
|
||||
|
||||
void SetNewState(WardenState::Value state);
|
||||
|
||||
static bool IsValidCheckSum(uint32 checksum, const uint8 *data, const uint16 length);
|
||||
static uint32 BuildChecksum(const uint8 *data, uint32 length);
|
||||
|
||||
// If no check is passed, the default action from config is executed
|
||||
std::string Penalty(WardenCheck* check = NULL);
|
||||
|
||||
protected:
|
||||
void LogPositiveToDB(WardenCheck* check);
|
||||
|
||||
WorldSession* _session;
|
||||
uint8 _inputKey[16];
|
||||
uint8 _outputKey[16];
|
||||
uint8 _seed[16];
|
||||
ARC4 _inputCrypto;
|
||||
ARC4 _outputCrypto;
|
||||
uint32 _checkTimer; // Timer for sending check requests
|
||||
uint32 _clientResponseTimer; // Timer for client response delay
|
||||
uint32 _previousTimestamp;
|
||||
ClientWardenModule* _module;
|
||||
WardenState::Value _state;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,331 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file WardenCheckMgr.cpp
|
||||
* @brief Warden check manager implementation
|
||||
*
|
||||
* This file implements WardenCheckMgr which manages the database
|
||||
* of Warden anti-cheat checks. It loads checks from the database
|
||||
* and stores check results for analysis.
|
||||
*
|
||||
* Check types supported:
|
||||
* - Memory checks (PAGE_CHECK_A, PAGE_CHECK_B)
|
||||
* - Driver checks (DRIVER_CHECK)
|
||||
* - Lua checks (LUA_CHECK)
|
||||
* - Timing checks (TIMING_CHECK)
|
||||
*
|
||||
* @see WardenCheckMgr for the manager class
|
||||
* @see WardenCheck for individual check definitions
|
||||
*/
|
||||
|
||||
#include <shared_mutex>
|
||||
#include "Platform/Define.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Log.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "Warden.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* @brief WardenCheckMgr constructor
|
||||
*
|
||||
* Initializes the check manager with empty stores.
|
||||
*/
|
||||
WardenCheckMgr::WardenCheckMgr() : CheckStore(), CheckResultStore() { }
|
||||
|
||||
/**
|
||||
* @brief WardenCheckMgr destructor
|
||||
*
|
||||
* Cleans up all check and check result objects.
|
||||
*/
|
||||
WardenCheckMgr::~WardenCheckMgr()
|
||||
{
|
||||
for (CheckMap::iterator it = CheckStore.begin(); it != CheckStore.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
for (CheckResultMap::iterator it = CheckResultStore.begin(); it != CheckResultStore.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
CheckStore.clear();
|
||||
CheckResultStore.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load Warden checks from database
|
||||
*
|
||||
* Loads all Warden checks from the `warden` table in the
|
||||
* world database. Checks are organized by client build number.
|
||||
* Skips loading if Warden is disabled in config.
|
||||
*/
|
||||
void WardenCheckMgr::LoadWardenChecks()
|
||||
{
|
||||
// Check if Warden is enabled by config before loading anything
|
||||
if (!sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) && !sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED))
|
||||
{
|
||||
sLog.outString(">> Warden disabled, loading checks skipped.");
|
||||
return;
|
||||
}
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
QueryResult *result = WorldDatabase.Query("SELECT `id`, `build`, `type`, `data`, `result`, `address`, `length`, `str`, `comment` FROM `warden` ORDER BY `build` ASC, `id` ASC");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog.outString("[Warden]: >> Loaded 0 warden data and results");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
Field* fields;
|
||||
|
||||
do
|
||||
{
|
||||
fields = result->Fetch();
|
||||
|
||||
uint16 id = fields[0].GetUInt16();
|
||||
uint16 build = fields[1].GetUInt16();
|
||||
uint8 checkType = fields[2].GetUInt8();
|
||||
std::string data = fields[3].GetString();
|
||||
std::string checkResult = fields[4].GetString();
|
||||
uint32 address = fields[5].GetUInt32();
|
||||
uint8 length = fields[6].GetUInt8();
|
||||
std::string str = fields[7].GetString();
|
||||
std::string comment = fields[8].GetString();
|
||||
|
||||
WardenCheck* wardenCheck = new WardenCheck();
|
||||
wardenCheck->Type = checkType;
|
||||
wardenCheck->CheckId = id;
|
||||
|
||||
// Initialize action with default action from config
|
||||
wardenCheck->Action = WardenActions(sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_FAIL_ACTION));
|
||||
|
||||
if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK)
|
||||
{
|
||||
wardenCheck->Data.SetHexStr(data.c_str());
|
||||
int len = data.size() / 2;
|
||||
|
||||
if (wardenCheck->Data.GetNumBytes() < len)
|
||||
{
|
||||
uint8 temp[24];
|
||||
memset(temp, 0, len);
|
||||
memcpy(temp, wardenCheck->Data.AsByteArray(), wardenCheck->Data.GetNumBytes());
|
||||
std::reverse(temp, temp + len);
|
||||
wardenCheck->Data.SetBinary((uint8*)temp, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (checkType == MEM_CHECK || checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == PROC_CHECK)
|
||||
{
|
||||
wardenCheck->Address = address;
|
||||
wardenCheck->Length = length;
|
||||
}
|
||||
|
||||
// PROC_CHECK support missing
|
||||
if (checkType == MEM_CHECK || checkType == MPQ_CHECK || checkType == LUA_STR_CHECK || checkType == DRIVER_CHECK || checkType == MODULE_CHECK)
|
||||
{
|
||||
wardenCheck->Str = str;
|
||||
}
|
||||
|
||||
CheckStore.insert(std::pair<uint16, WardenCheck*>(build, wardenCheck));
|
||||
|
||||
if (checkType == MPQ_CHECK || checkType == MEM_CHECK)
|
||||
{
|
||||
WardenCheckResult* wr = new WardenCheckResult();
|
||||
wr->Id = id;
|
||||
wr->Result.SetHexStr(checkResult.c_str());
|
||||
int len = checkResult.size() / 2;
|
||||
if (wr->Result.GetNumBytes() < len)
|
||||
{
|
||||
uint8 *temp = new uint8[len];
|
||||
memset(temp, 0, len);
|
||||
memcpy(temp, wr->Result.AsByteArray(), wr->Result.GetNumBytes());
|
||||
std::reverse(temp, temp + len);
|
||||
wr->Result.SetBinary((uint8*)temp, len);
|
||||
delete[] temp;
|
||||
}
|
||||
CheckResultStore.insert(std::pair<uint16, WardenCheckResult*>(build, wr));
|
||||
}
|
||||
|
||||
if (comment.empty())
|
||||
{
|
||||
wardenCheck->Comment = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
wardenCheck->Comment = comment;
|
||||
}
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog.outString(">> Loaded %u warden checks.", count);
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads per-check Warden action overrides from the character database.
|
||||
*/
|
||||
void WardenCheckMgr::LoadWardenOverrides()
|
||||
{
|
||||
// Check if Warden is enabled by config before loading anything
|
||||
if (!sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) && !sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED))
|
||||
{
|
||||
sLog.outString(">> Warden disabled, loading check overrides skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 0 1
|
||||
QueryResult* result = CharacterDatabase.Query("SELECT `wardenId`, `action` FROM `warden_action`");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog.outString(">> Loaded 0 Warden action overrides. DB table `warden_action` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
std::unique_lock<LOCK> g(m_lock);
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint16 checkId = fields[0].GetUInt16();
|
||||
uint8 action = fields[1].GetUInt8();
|
||||
|
||||
// Check if action value is in range (0-2, see WardenActions enum)
|
||||
if (action > WARDEN_ACTION_BAN)
|
||||
{
|
||||
sLog.outWarden("Warden check override action out of range (ID: %u, action: %u)", checkId, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool found = false;
|
||||
for (CheckMap::iterator it = CheckStore.begin(); it != CheckStore.end(); ++it)
|
||||
{
|
||||
if (it->second->CheckId == checkId)
|
||||
{
|
||||
it->second->Action = WardenActions(action);
|
||||
++count;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
sLog.outWarden("Warden check action override for non-existing check (ID: %u, action: %u), skipped", checkId, action);
|
||||
}
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog.outString(">> Loaded %u warden action overrides.", count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds a Warden check definition by client build and check id.
|
||||
*
|
||||
* @param build The client build.
|
||||
* @param id The Warden check id.
|
||||
* @return WardenCheck* The matching Warden check, or NULL if not found.
|
||||
*/
|
||||
WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 build, uint16 id)
|
||||
{
|
||||
WardenCheck* result = NULL;
|
||||
|
||||
std::shared_lock<LOCK> g(m_lock);
|
||||
for (CheckMap::iterator it = CheckStore.lower_bound(build); it != CheckStore.upper_bound(build); ++it)
|
||||
{
|
||||
if (it->second->CheckId == id)
|
||||
{
|
||||
result = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an expected Warden check result by client build and check id.
|
||||
*
|
||||
* @param build The client build.
|
||||
* @param id The Warden result id.
|
||||
* @return WardenCheckResult* The matching expected result, or NULL if not found.
|
||||
*/
|
||||
WardenCheckResult* WardenCheckMgr::GetWardenResultById(uint16 build, uint16 id)
|
||||
{
|
||||
WardenCheckResult* result = NULL;
|
||||
|
||||
std::shared_lock<LOCK> g(m_lock);
|
||||
for (CheckResultMap::iterator it = CheckResultStore.lower_bound(build); it != CheckResultStore.upper_bound(build); ++it)
|
||||
{
|
||||
if (it->second->Id == id)
|
||||
{
|
||||
result = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Collects Warden check ids for a client build by memory or non-memory category.
|
||||
*
|
||||
* @param isMemCheck True to collect memory-related checks; false for other checks.
|
||||
* @param build The client build.
|
||||
* @param idl The list that receives matching check ids.
|
||||
*/
|
||||
void WardenCheckMgr::GetWardenCheckIds(bool isMemCheck, uint16 build, std::list<uint16>& idl)
|
||||
{
|
||||
idl.clear(); //just to be sure
|
||||
|
||||
std::shared_lock<LOCK> g(m_lock);
|
||||
for (CheckMap::iterator it = CheckStore.lower_bound(build); it != CheckStore.upper_bound(build); ++it)
|
||||
{
|
||||
if (isMemCheck)
|
||||
{
|
||||
if ((it->second->Type == MEM_CHECK) || (it->second->Type == MODULE_CHECK))
|
||||
{
|
||||
idl.push_back(it->second->CheckId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
idl.push_back(it->second->CheckId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _WARDENCHECKMGR_H
|
||||
#define _WARDENCHECKMGR_H
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <map>
|
||||
#include "BigNumber.h"
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief Warden actions enumeration
|
||||
*/
|
||||
enum WardenActions
|
||||
{
|
||||
WARDEN_ACTION_LOG, ///< Log action
|
||||
WARDEN_ACTION_KICK, ///< Kick action
|
||||
WARDEN_ACTION_BAN ///< Ban action
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Warden check structure
|
||||
*/
|
||||
struct WardenCheck
|
||||
{
|
||||
uint8 Type; ///< Check type
|
||||
BigNumber Data; ///< Data
|
||||
uint32 Address; ///< Address (PROC_CHECK, MEM_CHECK, PAGE_CHECK)
|
||||
uint8 Length; ///< Length (PROC_CHECK, MEM_CHECK, PAGE_CHECK)
|
||||
std::string Str; ///< String (LUA, MPQ, DRIVER)
|
||||
std::string Comment; ///< Comment
|
||||
uint16 CheckId; ///< Check ID
|
||||
enum WardenActions Action; ///< Action to take
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Warden check result structure
|
||||
*/
|
||||
struct WardenCheckResult
|
||||
{
|
||||
uint16 Id; ///< ID
|
||||
BigNumber Result; ///< Result (MEM_CHECK)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Warden check manager class
|
||||
*/
|
||||
class WardenCheckMgr
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
WardenCheckMgr();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~WardenCheckMgr();
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Get instance
|
||||
* @return Warden check manager instance
|
||||
*/
|
||||
static WardenCheckMgr* instance()
|
||||
{
|
||||
static WardenCheckMgr instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get warden data by ID
|
||||
* @param build Client build
|
||||
* @param id Check ID
|
||||
* @return Warden check
|
||||
*/
|
||||
WardenCheck* GetWardenDataById(uint16 /*build*/, uint16 /*id*/);
|
||||
|
||||
/**
|
||||
* @brief Get warden result by ID
|
||||
* @param build Client build
|
||||
* @param id Check ID
|
||||
* @return Warden check result
|
||||
*/
|
||||
WardenCheckResult* GetWardenResultById(uint16 /*build*/, uint16 /*id*/);
|
||||
|
||||
/**
|
||||
* @brief Get warden check IDs
|
||||
* @param isMemCheck True if memory check
|
||||
* @param build Client build
|
||||
* @param list Output list of check IDs
|
||||
*/
|
||||
void GetWardenCheckIds(bool isMemCheck /* true = MEM */, uint16 build, std::list<uint16>& list);
|
||||
|
||||
/**
|
||||
* @brief Load warden checks
|
||||
*/
|
||||
void LoadWardenChecks();
|
||||
|
||||
/**
|
||||
* @brief Load warden overrides
|
||||
*/
|
||||
void LoadWardenOverrides();
|
||||
|
||||
private:
|
||||
typedef std::shared_mutex LOCK;
|
||||
typedef std::multimap<uint16, WardenCheck*> CheckMap;
|
||||
typedef std::multimap<uint16, WardenCheckResult*> CheckResultMap;
|
||||
|
||||
LOCK m_lock; ///< Lock
|
||||
CheckMap CheckStore; ///< Check store
|
||||
CheckResultMap CheckResultStore; ///< Check result store
|
||||
};
|
||||
|
||||
#define sWardenCheckMgr WardenCheckMgr::instance()
|
||||
|
||||
#endif
|
||||
|
|
@ -1,332 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file WardenMac.cpp
|
||||
* @brief macOS-specific Warden implementation
|
||||
*
|
||||
* This file implements WardenMac which provides the macOS-specific
|
||||
* implementation of the Warden anti-cheat system for Mac clients.
|
||||
*
|
||||
* Key differences from Windows:
|
||||
* - Different module binary
|
||||
* - Different seed value
|
||||
* - MD5-based module verification
|
||||
*
|
||||
* @see WardenMac for the Mac-specific class
|
||||
* @see Warden for the base class
|
||||
*/
|
||||
|
||||
#include "WardenKeyGeneration.h"
|
||||
#include "Auth/Md5.h"
|
||||
#include "Platform/Define.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include <openssl/evp.h>
|
||||
#include "World.h"
|
||||
#include "Player.h"
|
||||
#include "Util.h"
|
||||
#include "WardenMac.h"
|
||||
#include "WardenModuleMac.h"
|
||||
#include "GameTime.h"
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief WardenMac constructor
|
||||
*
|
||||
* Initializes the Mac-specific Warden implementation.
|
||||
*/
|
||||
WardenMac::WardenMac() : Warden() { }
|
||||
|
||||
/**
|
||||
* @brief WardenMac destructor
|
||||
*/
|
||||
WardenMac::~WardenMac() { }
|
||||
|
||||
/**
|
||||
* @brief Initialize Mac Warden
|
||||
* @param pClient Client session
|
||||
* @param K Session key
|
||||
*
|
||||
* Initializes the Mac-specific Warden with:
|
||||
* - SHA1-based key generation from session key
|
||||
* - Fixed Mac-specific seed
|
||||
* - Mac-specific module loading
|
||||
*/
|
||||
void WardenMac::Init(WorldSession* pClient, BigNumber* K)
|
||||
{
|
||||
_session = pClient;
|
||||
// Generate Warden Key
|
||||
SHA1Randx WK(K->AsByteArray(), K->GetNumBytes());
|
||||
WK.Generate(_inputKey, 16);
|
||||
WK.Generate(_outputKey, 16);
|
||||
/*
|
||||
Seed: 4D808D2C77D905C41A6380EC08586AFE (0x05 packet)
|
||||
Hash: <?> (0x04 packet)
|
||||
Module MD5: 0DBBF209A27B1E279A9FEC5C168A15F7
|
||||
New Client Key: <?>
|
||||
New Cerver Key: <?>
|
||||
*/
|
||||
uint8 mod_seed[16] = { 0x4D, 0x80, 0x8D, 0x2C, 0x77, 0xD9, 0x05, 0xC4, 0x1A, 0x63, 0x80, 0xEC, 0x08, 0x58, 0x6A, 0xFE };
|
||||
|
||||
memcpy(_seed, mod_seed, 16);
|
||||
|
||||
_inputCrypto.Init(_inputKey);
|
||||
_outputCrypto.Init(_outputKey);
|
||||
sLog.outWarden("Server side Mac warden for client %u (build %u) initializing...", pClient->GetAccountId(), _session->GetClientBuild());
|
||||
sLog.outWarden("C->S Key: %s", ByteArrayToHexStr(_inputKey, 16).c_str());
|
||||
sLog.outWarden("S->C Key: %s", ByteArrayToHexStr(_outputKey, 16).c_str());
|
||||
sLog.outWarden(" Seed: %s", ByteArrayToHexStr(_seed, 16).c_str());
|
||||
sLog.outWarden("Loading Module...");
|
||||
|
||||
_module = GetModuleForClient();
|
||||
|
||||
sLog.outWarden("Module Key: %s", ByteArrayToHexStr(_module->Key, 16).c_str());
|
||||
sLog.outWarden("Module ID: %s", ByteArrayToHexStr(_module->Id, 16).c_str());
|
||||
RequestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Mac Warden module
|
||||
* @return Client Warden module
|
||||
*
|
||||
* Returns the Mac-specific Warden module with its
|
||||
* compressed data, key, and MD5 hash.
|
||||
*/
|
||||
ClientWardenModule* WardenMac::GetModuleForClient()
|
||||
{
|
||||
ClientWardenModule *mod = new ClientWardenModule;
|
||||
|
||||
uint32 len = sizeof(Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data);
|
||||
|
||||
// data assign
|
||||
mod->CompressedSize = len;
|
||||
mod->CompressedData = new uint8[len];
|
||||
memcpy(mod->CompressedData, Module_0DBBF209A27B1E279A9FEC5C168A15F7_Data, len);
|
||||
memcpy(mod->Key, Module_0DBBF209A27B1E279A9FEC5C168A15F7_Key, 16);
|
||||
|
||||
// md5 hash
|
||||
Md5Hash md5;
|
||||
md5.UpdateData(mod->CompressedData, len);
|
||||
md5.Finalize();
|
||||
memcpy(&mod->Id, md5.GetDigest(), Md5Hash::DigestLength);
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize Mac Warden module
|
||||
*
|
||||
* Initializes the Mac-specific Warden module on the client.
|
||||
*/
|
||||
void WardenMac::InitializeModule()
|
||||
{
|
||||
sLog.outWarden("Initialize module");
|
||||
Warden::InitializeModule();
|
||||
}
|
||||
|
||||
struct keyData {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8 bytes[16];
|
||||
} bytes;
|
||||
|
||||
struct
|
||||
{
|
||||
int ints[4];
|
||||
} ints;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Validates the Mac client hash reply and initializes the session crypto keys.
|
||||
*
|
||||
* @param buff The received Warden payload buffer.
|
||||
*/
|
||||
void WardenMac::HandleHashResult(ByteBuffer &buff)
|
||||
{
|
||||
|
||||
// test
|
||||
int keyIn[4];
|
||||
|
||||
keyData mod_seed = { { { { 0x4D, 0x80, 0x8D, 0x2C, 0x77, 0xD9, 0x05, 0xC4, 0x1A, 0x63, 0x80, 0xEC, 0x08, 0x58, 0x6A, 0xFE } } } };
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
keyIn[i] = mod_seed.ints.ints[i];
|
||||
}
|
||||
|
||||
int keyOut[4];
|
||||
int keyIn1, keyIn2;
|
||||
keyOut[0] = keyIn[0];
|
||||
keyIn[0] ^= 0xDEADBEEFu;
|
||||
keyIn1 = keyIn[1];
|
||||
keyIn[1] -= 0x35014542u;
|
||||
keyIn2 = keyIn[2];
|
||||
keyIn[2] += 0x5313F22u;
|
||||
keyIn[3] *= 0x1337F00Du;
|
||||
keyOut[1] = keyIn1 - 0x6A028A84;
|
||||
keyOut[2] = keyIn2 + 0xA627E44;
|
||||
keyOut[3] = 0x1337F00D * keyIn[3];
|
||||
// end test
|
||||
|
||||
buff.rpos(buff.wpos());
|
||||
|
||||
Sha1Hash sha1;
|
||||
sha1.UpdateData((uint8*)keyIn, 16);
|
||||
sha1.Finalize();
|
||||
|
||||
//const uint8 validHash[20] = { 0x56, 0x8C, 0x05, 0x4C, 0x78, 0x1A, 0x97, 0x2A, 0x60, 0x37, 0xA2, 0x29, 0x0C, 0x22, 0xB5, 0x25, 0x71, 0xA0, 0x6F, 0x4E };
|
||||
|
||||
// Verify key
|
||||
if (memcmp(buff.contents() + 1, sha1.GetDigest(), 20) != 0)
|
||||
{
|
||||
sLog.outWarden("%s failed hash reply. Action: %s", _session->GetPlayerName(), Penalty().c_str());
|
||||
if (sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_FAIL_ACTION) > uint32(WARDEN_ACTION_LOG))
|
||||
{
|
||||
_session->KickPlayer();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sLog.outWarden("Request hash reply: succeed");
|
||||
|
||||
// client 7F96EEFDA5B63D20A4DF8E00CBF48304
|
||||
//const uint8 client_key[16] = { 0x7F, 0x96, 0xEE, 0xFD, 0xA5, 0xB6, 0x3D, 0x20, 0xA4, 0xDF, 0x8E, 0x00, 0xCB, 0xF4, 0x83, 0x04 };
|
||||
|
||||
// server C2B7ADEDFCCCA9C2BFB3F85602BA809B
|
||||
//const uint8 server_key[16] = { 0xC2, 0xB7, 0xAD, 0xED, 0xFC, 0xCC, 0xA9, 0xC2, 0xBF, 0xB3, 0xF8, 0x56, 0x02, 0xBA, 0x80, 0x9B };
|
||||
|
||||
// change keys here
|
||||
memcpy(_inputKey, keyIn, 16);
|
||||
memcpy(_outputKey, keyOut, 16);
|
||||
|
||||
_inputCrypto.Init(_inputKey);
|
||||
_outputCrypto.Init(_outputKey);
|
||||
|
||||
_previousTimestamp = GameTime::GetGameTimeMS();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends a Mac Warden data request packet to the client.
|
||||
*/
|
||||
void WardenMac::RequestData()
|
||||
{
|
||||
sLog.outWarden("Request data");
|
||||
|
||||
ByteBuffer buff;
|
||||
buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST);
|
||||
|
||||
std::string str = "Test string!";
|
||||
|
||||
buff << uint8(str.size());
|
||||
buff.append(str.c_str(), str.size());
|
||||
|
||||
buff.hexlike();
|
||||
|
||||
// Encrypt with warden RC4 key.
|
||||
EncryptData(const_cast<uint8*>(buff.contents()), buff.size());
|
||||
|
||||
WorldPacket pkt(SMSG_WARDEN_DATA, buff.size());
|
||||
pkt.append(buff);
|
||||
_session->SendPacket(&pkt);
|
||||
|
||||
Warden::RequestData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes a Mac Warden data response from the client.
|
||||
*
|
||||
* @param buff The received Warden payload buffer.
|
||||
*/
|
||||
void WardenMac::HandleData(ByteBuffer &buff)
|
||||
{
|
||||
sLog.outWarden("Handle data");
|
||||
|
||||
//uint16 Length;
|
||||
//buff >> Length;
|
||||
//uint32 Checksum;
|
||||
//buff >> Checksum;
|
||||
|
||||
//if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length))
|
||||
//{
|
||||
// buff.rpos(buff.wpos());
|
||||
// if (sWorld->getBoolConfig(CONFIG_BOOL_WARDEN_KICK))
|
||||
// Client->KickPlayer();
|
||||
// return;
|
||||
//}
|
||||
|
||||
bool found = false;
|
||||
|
||||
std::string str = "Test string!";
|
||||
|
||||
Sha1Hash sha1;
|
||||
sha1.UpdateData(str);
|
||||
uint32 magic = 0xFEEDFACE; // unsure
|
||||
sha1.UpdateData((uint8*)&magic, 4);
|
||||
sha1.Finalize();
|
||||
|
||||
uint8 sha1Hash[20];
|
||||
buff.read(sha1Hash, 20);
|
||||
|
||||
if (memcmp(sha1Hash, sha1.GetDigest(), 20) != 0)
|
||||
{
|
||||
sLog.outWarden("Handle data failed: SHA1 hash is wrong!");
|
||||
found = true;
|
||||
}
|
||||
|
||||
Md5Hash md5;
|
||||
md5.UpdateData(str);
|
||||
md5.Finalize();
|
||||
uint8 ourMD5Hash[16];
|
||||
memcpy(ourMD5Hash, md5.GetDigest(), sizeof(ourMD5Hash));
|
||||
|
||||
uint8 theirsMD5Hash[16];
|
||||
buff.read(theirsMD5Hash, 16);
|
||||
|
||||
if (memcmp(ourMD5Hash, theirsMD5Hash, 16) != 0)
|
||||
{
|
||||
sLog.outWarden("Handle data failed: MD5 hash is wrong!");
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found && sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_FAIL_ACTION) > uint32(WARDEN_ACTION_LOG))
|
||||
{
|
||||
_session->KickPlayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outWarden("SHA1 and MD5 hash verified. Handle data passed.");
|
||||
}
|
||||
|
||||
Warden::HandleData(buff);
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _WARDEN_MAC_H
|
||||
#define _WARDEN_MAC_H
|
||||
|
||||
#include "Warden.h"
|
||||
|
||||
class WorldSession;
|
||||
|
||||
/**
|
||||
* @brief Warden Mac class
|
||||
*
|
||||
* Platform-specific Warden implementation for Mac clients.
|
||||
*/
|
||||
class WardenMac : public Warden
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
WardenMac();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~WardenMac();
|
||||
|
||||
/**
|
||||
* @brief Initialize Warden
|
||||
* @param session World session
|
||||
* @param k Key
|
||||
*/
|
||||
void Init(WorldSession* session, BigNumber* k) override;
|
||||
|
||||
/**
|
||||
* @brief Get module for client
|
||||
* @return Client warden module
|
||||
*/
|
||||
ClientWardenModule* GetModuleForClient() override;
|
||||
|
||||
/**
|
||||
* @brief Initialize module
|
||||
*/
|
||||
void InitializeModule() override;
|
||||
|
||||
/**
|
||||
* @brief Handle hash result
|
||||
* @param buff Byte buffer
|
||||
*/
|
||||
void HandleHashResult(ByteBuffer& buff) override;
|
||||
|
||||
/**
|
||||
* @brief Request data
|
||||
*/
|
||||
void RequestData() override;
|
||||
|
||||
/**
|
||||
* @brief Handle data
|
||||
* @param buff Byte buffer
|
||||
*/
|
||||
void HandleData(ByteBuffer& buff) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,572 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file WardenWin.cpp
|
||||
* @brief Windows-specific Warden implementation
|
||||
*
|
||||
* This file implements WardenWin which provides the Windows-specific
|
||||
* implementation of the Warden anti-cheat system for Windows clients.
|
||||
*
|
||||
* Key features:
|
||||
* - Module loading and initialization
|
||||
* - Memory scanning checks
|
||||
* - Timing-based checks
|
||||
* - Server tick tracking
|
||||
*
|
||||
* @see WardenWin for the Windows-specific class
|
||||
* @see Warden for the base class
|
||||
*/
|
||||
|
||||
#include "HMACSHA1.h"
|
||||
#include "Auth/Md5.h"
|
||||
#include "WardenKeyGeneration.h"
|
||||
#include "Platform/Define.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include <openssl/evp.h>
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "World.h"
|
||||
#include "Player.h"
|
||||
#include "Util.h"
|
||||
#include "WardenWin.h"
|
||||
#include "WardenModuleWin.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "GameTime.h"
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
|
||||
/**
|
||||
* @brief WardenWin constructor
|
||||
*
|
||||
* Initializes the Windows-specific Warden implementation.
|
||||
*/
|
||||
WardenWin::WardenWin() : Warden(), _serverTicks(0) {}
|
||||
|
||||
/**
|
||||
* @brief WardenWin destructor
|
||||
*/
|
||||
WardenWin::~WardenWin() { }
|
||||
|
||||
/**
|
||||
* @brief Initialize Windows Warden
|
||||
* @param session Client session
|
||||
* @param k Session key
|
||||
*
|
||||
* Initializes the Windows-specific Warden with:
|
||||
* - SHA1-based key generation from session key
|
||||
* - Module-specific seed
|
||||
* - Windows-specific module loading
|
||||
*/
|
||||
void WardenWin::Init(WorldSession* session, BigNumber* k)
|
||||
{
|
||||
_session = session;
|
||||
// Generate Warden Key
|
||||
SHA1Randx WK(k->AsByteArray(), k->GetNumBytes());
|
||||
WK.Generate(_inputKey, 16);
|
||||
WK.Generate(_outputKey, 16);
|
||||
|
||||
memcpy(_seed, Module.Seed, 16);
|
||||
|
||||
_inputCrypto.Init(_inputKey);
|
||||
_outputCrypto.Init(_outputKey);
|
||||
sLog.outWarden("Server side warden for client %u (build %u) initializing...", session->GetAccountId(), _session->GetClientBuild());
|
||||
sLog.outWarden("C->S Key: %s", ByteArrayToHexStr(_inputKey, 16).c_str());
|
||||
sLog.outWarden("S->C Key: %s", ByteArrayToHexStr(_outputKey, 16).c_str());
|
||||
sLog.outWarden(" Seed: %s", ByteArrayToHexStr(_seed, 16).c_str());
|
||||
sLog.outWarden("Loading Module...");
|
||||
|
||||
_module = GetModuleForClient();
|
||||
|
||||
sLog.outWarden("Module Key: %s", ByteArrayToHexStr(_module->Key, 16).c_str());
|
||||
sLog.outWarden("Module ID: %s", ByteArrayToHexStr(_module->Id, 16).c_str());
|
||||
RequestModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Windows Warden module
|
||||
* @return Client Warden module
|
||||
*
|
||||
* Returns the Windows-specific Warden module with its
|
||||
* compressed data, key, and MD5 hash.
|
||||
*/
|
||||
ClientWardenModule* WardenWin::GetModuleForClient()
|
||||
{
|
||||
ClientWardenModule *mod = new ClientWardenModule;
|
||||
|
||||
uint32 length = sizeof(Module.Module);
|
||||
|
||||
// data assign
|
||||
mod->CompressedSize = length;
|
||||
mod->CompressedData = new uint8[length];
|
||||
memcpy(mod->CompressedData, Module.Module, length);
|
||||
memcpy(mod->Key, Module.ModuleKey, 16);
|
||||
|
||||
// md5 hash
|
||||
Md5Hash md5;
|
||||
md5.UpdateData(mod->CompressedData, length);
|
||||
md5.Finalize();
|
||||
memcpy(&mod->Id, md5.GetDigest(), Md5Hash::DigestLength);
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize Windows Warden module
|
||||
*
|
||||
* Initializes the Windows-specific Warden module on the client.
|
||||
*/
|
||||
void WardenWin::InitializeModule()
|
||||
{
|
||||
sLog.outWarden("Initialize module");
|
||||
|
||||
// Create packet structure
|
||||
WardenInitModuleRequest Request;
|
||||
Request.Command1 = WARDEN_SMSG_MODULE_INITIALIZE;
|
||||
Request.Size1 = 20;
|
||||
Request.CheckSumm1 = BuildChecksum(&Request.Unk1, 20);
|
||||
Request.Unk1 = 1;
|
||||
Request.Unk2 = 0;
|
||||
Request.Type = 1;
|
||||
Request.String_library1 = 0;
|
||||
Request.Function1[0] = 0x002485F0; // 0x00400000 + 0x002485F0 SFileOpenFile
|
||||
Request.Function1[1] = 0x002487F0; // 0x00400000 + 0x002487F0 SFileGetFileSize
|
||||
Request.Function1[2] = 0x00248460; // 0x00400000 + 0x00248460 SFileReadFile
|
||||
Request.Function1[3] = 0x00248730; // 0x00400000 + 0x00248730 SFileCloseFile
|
||||
|
||||
Request.Command2 = WARDEN_SMSG_MODULE_INITIALIZE;
|
||||
Request.Size2 = 8;
|
||||
Request.CheckSumm2 = BuildChecksum(&Request.Unk2, 8);
|
||||
Request.Unk3 = 4;
|
||||
Request.Unk4 = 0;
|
||||
Request.String_library2 = 0;
|
||||
Request.Function2 = 0x00419D40; // 0x00400000 + 0x00419D40 FrameScript::GetText
|
||||
Request.Function2_set = 1;
|
||||
|
||||
Request.Command3 = WARDEN_SMSG_MODULE_INITIALIZE;
|
||||
Request.Size3 = 8;
|
||||
Request.CheckSumm3 = BuildChecksum(&Request.Unk5, 8);
|
||||
Request.Unk5 = 1;
|
||||
Request.Unk6 = 1;
|
||||
Request.String_library3 = 0;
|
||||
Request.Function3 = 0x0046AE20; // 0x00400000 + 0x0046AE20 PerformanceCounter
|
||||
Request.Function3_set = 1;
|
||||
|
||||
// Encrypt with warden RC4 key.
|
||||
EncryptData((uint8*)&Request, sizeof(WardenInitModuleRequest));
|
||||
|
||||
WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenInitModuleRequest));
|
||||
pkt.append((uint8*)&Request, sizeof(WardenInitModuleRequest));
|
||||
_session->SendPacket(&pkt);
|
||||
|
||||
Warden::InitializeModule();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validates the Windows client hash reply and initializes the session crypto keys.
|
||||
*
|
||||
* @param buff The received Warden payload buffer.
|
||||
*/
|
||||
void WardenWin::HandleHashResult(ByteBuffer &buff)
|
||||
{
|
||||
buff.rpos(buff.wpos());
|
||||
|
||||
// Verify key
|
||||
if (memcmp(buff.contents() + 1, Module.ClientKeySeedHash, sizeof(Module.ClientKeySeedHash)) != 0)
|
||||
{
|
||||
sLog.outWarden("%s failed hash reply. Action: %s", _session->GetPlayerName(), Penalty().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
sLog.outWarden("Request hash reply: succeed");
|
||||
|
||||
// Change keys here
|
||||
memcpy(_inputKey, Module.ClientKeySeed, 16);
|
||||
memcpy(_outputKey, Module.ServerKeySeed, 16);
|
||||
|
||||
_inputCrypto.Init(_inputKey);
|
||||
_outputCrypto.Init(_outputKey);
|
||||
|
||||
_previousTimestamp = GameTime::GetGameTimeMS();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Builds and sends the current batch of Windows Warden checks.
|
||||
*/
|
||||
void WardenWin::RequestData()
|
||||
{
|
||||
sLog.outWarden("Request data");
|
||||
|
||||
uint16 build = _session->GetClientBuild();
|
||||
uint16 id = 0;
|
||||
uint8 type = 0;
|
||||
WardenCheck* wd = NULL;
|
||||
|
||||
// If all checks were done, fill the todo list again
|
||||
if (_memChecksTodo.empty())
|
||||
{
|
||||
sWardenCheckMgr->GetWardenCheckIds(true, build, _memChecksTodo);
|
||||
}
|
||||
|
||||
if (_otherChecksTodo.empty())
|
||||
{
|
||||
sWardenCheckMgr->GetWardenCheckIds(false, build, _otherChecksTodo);
|
||||
}
|
||||
|
||||
_serverTicks = GameTime::GetGameTimeMS();
|
||||
|
||||
_currentChecks.clear();
|
||||
|
||||
// Build check request
|
||||
for (uint16 i = 0; i < sWorld.getConfig(CONFIG_UINT32_WARDEN_NUM_MEM_CHECKS); ++i)
|
||||
{
|
||||
// If todo list is done break loop (will be filled on next Update() run)
|
||||
if (_memChecksTodo.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get check id from the end and remove it from todo
|
||||
id = _memChecksTodo.back();
|
||||
_memChecksTodo.pop_back();
|
||||
|
||||
// Add the id to the list sent in this cycle
|
||||
_currentChecks.push_back(id);
|
||||
}
|
||||
|
||||
ByteBuffer buff;
|
||||
buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST);
|
||||
|
||||
for (uint16 i = 0; i < sWorld.getConfig(CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS); ++i)
|
||||
{
|
||||
// If todo list is done break loop (will be filled on next Update() run)
|
||||
if (_otherChecksTodo.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get check id from the end and remove it from todo
|
||||
id = _otherChecksTodo.back();
|
||||
_otherChecksTodo.pop_back();
|
||||
|
||||
// Add the id to the list sent in this cycle
|
||||
_currentChecks.push_back(id);
|
||||
|
||||
// if we are here, the function is guaranteed to not return NULL
|
||||
// but ... who knows
|
||||
wd = sWardenCheckMgr->GetWardenDataById(build, id);
|
||||
if (wd)
|
||||
{
|
||||
switch (wd->Type)
|
||||
{
|
||||
case MPQ_CHECK:
|
||||
case LUA_STR_CHECK:
|
||||
case DRIVER_CHECK:
|
||||
buff << uint8(wd->Str.size());
|
||||
buff.append(wd->Str.c_str(), wd->Str.size());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 xorByte = _inputKey[0];
|
||||
|
||||
// Add TIMING_CHECK
|
||||
buff << uint8(0x00);
|
||||
buff << uint8(TIMING_CHECK ^ xorByte);
|
||||
|
||||
uint8 index = 1;
|
||||
|
||||
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
|
||||
{
|
||||
wd = sWardenCheckMgr->GetWardenDataById(build, *itr);
|
||||
|
||||
type = wd->Type;
|
||||
buff << uint8(type ^ xorByte);
|
||||
switch (type)
|
||||
{
|
||||
case MEM_CHECK:
|
||||
{
|
||||
buff << uint8(0x00);
|
||||
buff << uint32(wd->Address);
|
||||
buff << uint8(wd->Length);
|
||||
break;
|
||||
}
|
||||
case PAGE_CHECK_A:
|
||||
case PAGE_CHECK_B:
|
||||
{
|
||||
buff.append(wd->Data.AsByteArray(0, false), wd->Data.GetNumBytes());
|
||||
buff << uint32(wd->Address);
|
||||
buff << uint8(wd->Length);
|
||||
break;
|
||||
}
|
||||
case MPQ_CHECK:
|
||||
case LUA_STR_CHECK:
|
||||
{
|
||||
buff << uint8(index++);
|
||||
break;
|
||||
}
|
||||
case DRIVER_CHECK:
|
||||
{
|
||||
buff.append(wd->Data.AsByteArray(0, false), wd->Data.GetNumBytes());
|
||||
buff << uint8(index++);
|
||||
break;
|
||||
}
|
||||
case MODULE_CHECK:
|
||||
{
|
||||
uint32 seed = rand32();
|
||||
buff << uint32(seed);
|
||||
HMACSHA1 hmac(4, (uint8*)&seed);
|
||||
hmac.UpdateData(wd->Str);
|
||||
hmac.Finalize();
|
||||
buff.append(hmac.GetDigest(), hmac.GetLength());
|
||||
break;
|
||||
}
|
||||
/*case PROC_CHECK:
|
||||
{
|
||||
buff.append(wd->i.AsByteArray(0, false).get(), wd->i.GetNumBytes());
|
||||
buff << uint8(index++);
|
||||
buff << uint8(index++);
|
||||
buff << uint32(wd->Address);
|
||||
buff << uint8(wd->Length);
|
||||
break;
|
||||
}*/
|
||||
default:
|
||||
break; // Should never happen
|
||||
}
|
||||
}
|
||||
buff << uint8(xorByte);
|
||||
buff.hexlike();
|
||||
|
||||
// Encrypt with warden RC4 key
|
||||
EncryptData((uint8*)buff.contents(), buff.size());
|
||||
|
||||
WorldPacket pkt(SMSG_WARDEN_DATA, buff.size());
|
||||
pkt.append(buff);
|
||||
_session->SendPacket(&pkt);
|
||||
|
||||
std::stringstream stream;
|
||||
stream << "Sent check id's: ";
|
||||
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
|
||||
{
|
||||
stream << *itr << " ";
|
||||
}
|
||||
|
||||
sLog.outWarden("%s", stream.str().c_str());
|
||||
|
||||
Warden::RequestData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes a Windows Warden data response and validates the reported checks.
|
||||
*
|
||||
* @param buff The received Warden payload buffer.
|
||||
*/
|
||||
void WardenWin::HandleData(ByteBuffer &buff)
|
||||
{
|
||||
sLog.outWarden("Handle data");
|
||||
|
||||
uint16 Length;
|
||||
buff >> Length;
|
||||
uint32 Checksum;
|
||||
buff >> Checksum;
|
||||
|
||||
if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length))
|
||||
{
|
||||
buff.rpos(buff.wpos());
|
||||
sLog.outWarden("%s failed checksum. Action: %s", _session->GetPlayerName(), Penalty().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// TIMING_CHECK
|
||||
{
|
||||
uint8 result;
|
||||
buff >> result;
|
||||
/// @todo test it.
|
||||
if (result == 0x00)
|
||||
{
|
||||
sLog.outWarden("%s failed timing check. Action: %s", _session->GetPlayerName(), Penalty().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 newClientTicks;
|
||||
buff >> newClientTicks;
|
||||
|
||||
uint32 ticksNow = GameTime::GetGameTimeMS();
|
||||
uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks);
|
||||
|
||||
sLog.outWarden("ServerTicks %u, RequestTicks %u, ClientTicks %u", ticksNow, _serverTicks, newClientTicks); // Now, At request, At response
|
||||
sLog.outWarden("Waittime %u", ourTicks - newClientTicks);
|
||||
|
||||
}
|
||||
|
||||
WardenCheckResult* rs;
|
||||
WardenCheck *rd;
|
||||
uint8 type;
|
||||
uint16 checkFailed = 0;
|
||||
|
||||
for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
|
||||
{
|
||||
rd = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), *itr);
|
||||
rs = sWardenCheckMgr->GetWardenResultById(_session->GetClientBuild(), *itr);
|
||||
|
||||
type = rd->Type;
|
||||
switch (type)
|
||||
{
|
||||
case MEM_CHECK:
|
||||
{
|
||||
uint8 Mem_Result;
|
||||
buff >> Mem_Result;
|
||||
|
||||
if (Mem_Result != 0)
|
||||
{
|
||||
sLog.outWarden("RESULT MEM_CHECK not 0x00, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
checkFailed = *itr;
|
||||
continue;
|
||||
}
|
||||
if (memcmp(buff.contents() + buff.rpos(), rs->Result.AsByteArray(0, false), rd->Length) != 0)
|
||||
{
|
||||
sLog.outWarden("RESULT MEM_CHECK fail CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
checkFailed = *itr;
|
||||
buff.rpos(buff.rpos() + rd->Length);
|
||||
continue;
|
||||
}
|
||||
|
||||
buff.rpos(buff.rpos() + rd->Length);
|
||||
sLog.outWarden("RESULT MEM_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
break;
|
||||
}
|
||||
case PAGE_CHECK_A:
|
||||
case PAGE_CHECK_B:
|
||||
case DRIVER_CHECK:
|
||||
case MODULE_CHECK:
|
||||
{
|
||||
const uint8 byte = 0xE9;
|
||||
if (memcmp(buff.contents() + buff.rpos(), &byte, sizeof(uint8)) != 0)
|
||||
{
|
||||
if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
|
||||
{
|
||||
sLog.outWarden("RESULT PAGE_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
}
|
||||
if (type == MODULE_CHECK)
|
||||
{
|
||||
sLog.outWarden("RESULT MODULE_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
}
|
||||
if (type == DRIVER_CHECK)
|
||||
{
|
||||
sLog.outWarden("RESULT DRIVER_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
}
|
||||
checkFailed = *itr;
|
||||
buff.rpos(buff.rpos() + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
buff.rpos(buff.rpos() + 1);
|
||||
if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
|
||||
{
|
||||
sLog.outWarden("RESULT PAGE_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
}
|
||||
else if (type == MODULE_CHECK)
|
||||
{
|
||||
sLog.outWarden("RESULT MODULE_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
}
|
||||
else if (type == DRIVER_CHECK)
|
||||
{
|
||||
sLog.outWarden("RESULT DRIVER_CHECK passed CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LUA_STR_CHECK:
|
||||
{
|
||||
uint8 Lua_Result;
|
||||
buff >> Lua_Result;
|
||||
|
||||
if (Lua_Result != 0)
|
||||
{
|
||||
sLog.outWarden("RESULT LUA_STR_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
checkFailed = *itr;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8 luaStrLen;
|
||||
buff >> luaStrLen;
|
||||
|
||||
if (luaStrLen != 0)
|
||||
{
|
||||
char *str = new char[luaStrLen + 1];
|
||||
memcpy(str, buff.contents() + buff.rpos(), luaStrLen);
|
||||
str[luaStrLen] = '\0'; // null terminator
|
||||
sLog.outWarden("Lua string: %s", str);
|
||||
delete[] str;
|
||||
}
|
||||
buff.rpos(buff.rpos() + luaStrLen); // Skip string
|
||||
sLog.outWarden("RESULT LUA_STR_CHECK passed, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
break;
|
||||
}
|
||||
case MPQ_CHECK:
|
||||
{
|
||||
uint8 Mpq_Result;
|
||||
buff >> Mpq_Result;
|
||||
|
||||
if (Mpq_Result != 0)
|
||||
{
|
||||
sLog.outWarden("RESULT MPQ_CHECK not 0x00 account id %u", _session->GetAccountId());
|
||||
checkFailed = *itr;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(buff.contents() + buff.rpos(), rs->Result.AsByteArray(0, false), 20) != 0) // SHA1
|
||||
{
|
||||
sLog.outWarden("RESULT MPQ_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
checkFailed = *itr;
|
||||
buff.rpos(buff.rpos() + 20); // 20 bytes SHA1
|
||||
continue;
|
||||
}
|
||||
|
||||
buff.rpos(buff.rpos() + 20); // 20 bytes SHA1
|
||||
sLog.outWarden("RESULT MPQ_CHECK passed, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
break;
|
||||
}
|
||||
default: // Should never happen
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkFailed > 0)
|
||||
{
|
||||
WardenCheck* check = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), checkFailed); //note it IS NOT NULL here
|
||||
sLog.outWarden("%s failed Warden check %u. Action: %s", _session->GetPlayerName(), checkFailed, Penalty(check).c_str());
|
||||
LogPositiveToDB(check);
|
||||
}
|
||||
|
||||
Warden::HandleData(buff);
|
||||
}
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _WARDEN_WIN_H
|
||||
#define _WARDEN_WIN_H
|
||||
|
||||
#include "Warden.h"
|
||||
#include <list>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Warden init module request structure
|
||||
*/
|
||||
struct WardenInitModuleRequest
|
||||
{
|
||||
uint8 Command1; ///< Command 1
|
||||
uint16 Size1; ///< Size 1
|
||||
uint32 CheckSumm1; ///< Checksum 1
|
||||
uint8 Unk1; ///< Unknown 1
|
||||
uint8 Unk2; ///< Unknown 2
|
||||
uint8 Type; ///< Type
|
||||
uint8 String_library1; ///< String library 1
|
||||
uint32 Function1[4]; ///< Function 1 array
|
||||
|
||||
uint8 Command2; ///< Command 2
|
||||
uint16 Size2; ///< Size 2
|
||||
uint32 CheckSumm2; ///< Checksum 2
|
||||
uint8 Unk3; ///< Unknown 3
|
||||
uint8 Unk4; ///< Unknown 4
|
||||
uint8 String_library2; ///< String library 2
|
||||
uint32 Function2; ///< Function 2
|
||||
uint8 Function2_set; ///< Function 2 set
|
||||
|
||||
uint8 Command3; ///< Command 3
|
||||
uint16 Size3; ///< Size 3
|
||||
uint32 CheckSumm3; ///< Checksum 3
|
||||
uint8 Unk5; ///< Unknown 5
|
||||
uint8 Unk6; ///< Unknown 6
|
||||
uint8 String_library3; ///< String library 3
|
||||
uint32 Function3; ///< Function 3
|
||||
uint8 Function3_set; ///< Function 3 set
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
class WorldSession;
|
||||
|
||||
/**
|
||||
* @brief Warden Windows class
|
||||
*
|
||||
* Platform-specific Warden implementation for Windows clients.
|
||||
*/
|
||||
class WardenWin : public Warden
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
WardenWin();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~WardenWin();
|
||||
|
||||
/**
|
||||
* @brief Initialize Warden
|
||||
* @param session World session
|
||||
* @param K Key
|
||||
*/
|
||||
void Init(WorldSession* session, BigNumber* K) override;
|
||||
|
||||
/**
|
||||
* @brief Get module for client
|
||||
* @return Client warden module
|
||||
*/
|
||||
ClientWardenModule* GetModuleForClient() override;
|
||||
|
||||
/**
|
||||
* @brief Initialize module
|
||||
*/
|
||||
void InitializeModule() override;
|
||||
|
||||
/**
|
||||
* @brief Handle hash result
|
||||
* @param buff Byte buffer
|
||||
*/
|
||||
void HandleHashResult(ByteBuffer &buff) override;
|
||||
|
||||
/**
|
||||
* @brief Request data
|
||||
*/
|
||||
void RequestData() override;
|
||||
|
||||
/**
|
||||
* @brief Handle data
|
||||
* @param buff Byte buffer
|
||||
*/
|
||||
void HandleData(ByteBuffer &buff) override;
|
||||
|
||||
private:
|
||||
uint32 _serverTicks; ///< Server ticks
|
||||
std::list<uint16> _otherChecksTodo; ///< Other checks to do
|
||||
std::list<uint16> _memChecksTodo; ///< Memory checks to do
|
||||
std::list<uint16> _currentChecks; ///< Current checks
|
||||
};
|
||||
|
||||
#endif
|
||||
32
src/game/WorldHandlers/WardenHandler.cpp
Normal file
32
src/game/WorldHandlers/WardenHandler.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData)
|
||||
{
|
||||
recvData.rfinish();
|
||||
}
|
||||
|
|
@ -113,9 +113,6 @@
|
|||
#include "RandomPlayerbotMgr.h"
|
||||
#endif
|
||||
|
||||
// WARDEN
|
||||
#include "WardenCheckMgr.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <atomic>
|
||||
|
|
@ -1057,15 +1054,6 @@ void World::SetInitialWorldSettings()
|
|||
sLog.outString("Loading Transports...");
|
||||
sMapMgr.LoadTransports();
|
||||
|
||||
// Initialize Warden
|
||||
sLog.outString("Loading Warden Checks...");
|
||||
sWardenCheckMgr->LoadWardenChecks();
|
||||
sLog.outString();
|
||||
|
||||
sLog.outString("Loading Warden Action Overrides...");
|
||||
sWardenCheckMgr->LoadWardenOverrides();
|
||||
sLog.outString();
|
||||
|
||||
sLog.outString("Deleting expired bans...");
|
||||
LoginDatabase.Execute("DELETE FROM `ip_banned` WHERE `unbandate`<=UNIX_TIMESTAMP() AND `unbandate`<>`bandate`");
|
||||
sLog.outString();
|
||||
|
|
@ -1129,7 +1117,7 @@ void World::SetInitialWorldSettings()
|
|||
|
||||
namespace
|
||||
{
|
||||
/// "Eluna, ScriptDev3, Warden" -- or "none" for an empty list.
|
||||
/// "Eluna, ScriptDev3" -- or "none" for an empty list.
|
||||
std::string JoinList(const std::vector<std::string>& items)
|
||||
{
|
||||
std::string joined;
|
||||
|
|
@ -1199,15 +1187,6 @@ void World::showFooter(uint32 startupMs)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) || getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED))
|
||||
{
|
||||
enabled.push_back("Warden");
|
||||
}
|
||||
else
|
||||
{
|
||||
disabled.push_back("Warden");
|
||||
}
|
||||
|
||||
char database[128];
|
||||
snprintf(database, sizeof(database), "Rel%s.%s.%s", GitRevision::GetWorldDBVersion(),
|
||||
GitRevision::GetWorldDBStructure(), GitRevision::GetWorldDBContent());
|
||||
|
|
|
|||
|
|
@ -211,14 +211,6 @@ enum eConfigUInt32Values
|
|||
CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT,
|
||||
CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY,
|
||||
CONFIG_UINT32_LOG_WHISPERS,
|
||||
// Warden
|
||||
CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY,
|
||||
CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF,
|
||||
CONFIG_UINT32_WARDEN_CLIENT_FAIL_ACTION,
|
||||
CONFIG_UINT32_WARDEN_CLIENT_BAN_DURATION,
|
||||
CONFIG_UINT32_WARDEN_NUM_MEM_CHECKS,
|
||||
CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS,
|
||||
CONFIG_UINT32_WARDEN_DB_LOGLEVEL,
|
||||
#ifdef ENABLE_PLAYERBOTS
|
||||
CONFIG_UINT32_PLAYERBOT_MAXBOTS,
|
||||
CONFIG_UINT32_PLAYERBOT_RESTRICTLEVEL,
|
||||
|
|
@ -404,9 +396,6 @@ enum eConfigBoolValues
|
|||
CONFIG_BOOL_PLAYERBOT_COLLECT_OBJECTS,
|
||||
CONFIG_BOOL_PLAYERBOT_SELL_TRASH,
|
||||
#endif
|
||||
// Warden
|
||||
CONFIG_BOOL_WARDEN_WIN_ENABLED,
|
||||
CONFIG_BOOL_WARDEN_OSX_ENABLED,
|
||||
CONFIG_BOOL_GM_TICKET_OFFLINE_CLOSING,
|
||||
|
||||
// Recommended Or New Flag
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@
|
|||
#include "GitRevision.h"
|
||||
#include "UpdateTime.h"
|
||||
#include "GameTime.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "SystemConfig.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
|
@ -593,18 +592,6 @@ void World::LoadConfigSettings(bool reload)
|
|||
setConfig(CONFIG_BOOL_PLAYERBOT_SHAREDBOTS, "PlayerbotAI.SharedBots", true);
|
||||
#endif
|
||||
|
||||
// WARDEN
|
||||
|
||||
setConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED, "Warden.WinEnabled", true);
|
||||
setConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED, "Warden.OSXEnabled", false);
|
||||
setConfig(CONFIG_UINT32_WARDEN_NUM_MEM_CHECKS, "Warden.NumMemChecks", 3);
|
||||
setConfig(CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS, "Warden.NumOtherChecks", 7);
|
||||
setConfig(CONFIG_UINT32_WARDEN_CLIENT_BAN_DURATION, "Warden.BanDuration", 86400);
|
||||
setConfig(CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF, "Warden.ClientCheckHoldOff", 30);
|
||||
setConfig(CONFIG_UINT32_WARDEN_CLIENT_FAIL_ACTION, "Warden.ClientCheckFailAction", 0);
|
||||
setConfig(CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY, "Warden.ClientResponseDelay", 600);
|
||||
setConfig(CONFIG_UINT32_WARDEN_DB_LOGLEVEL, "Warden.DBLogLevel", 0);
|
||||
|
||||
// Recommended Or New Flag
|
||||
setConfig(CONFIG_BOOL_REALM_RECOMMENDED_OR_NEW_ENABLED, "Realm.RecommendedOrNew.Enabled", false);
|
||||
setConfig(CONFIG_BOOL_REALM_RECOMMENDED_OR_NEW, "Realm.RecommendedOrNew", false);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@
|
|||
#include "GitRevision.h"
|
||||
#include "UpdateTime.h"
|
||||
#include "GameTime.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "SystemConfig.h"
|
||||
#include <iostream>
|
||||
#ifdef ENABLE_ELUNA
|
||||
|
|
|
|||
|
|
@ -394,11 +394,6 @@ CleanCharacterDB = 1
|
|||
# Default: "Ra.log"
|
||||
# "" - Empty name for disable
|
||||
#
|
||||
# WardenLogFile
|
||||
# Log file for warden-related output
|
||||
# Default: "" - no log file created
|
||||
# "warden.log" - recommended name to create a log file
|
||||
#
|
||||
# LogColors
|
||||
# Color for messages (format "normal_color details_color debug_color error_color")
|
||||
# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
|
||||
|
|
@ -449,8 +444,6 @@ GmLogFile = "world-gamemaster.log"
|
|||
GmLogTimestamp = 0
|
||||
GmLogPerAccount = 0
|
||||
RaLogFile = "world-remote-access.log"
|
||||
WardenLogFile = "warden.log"
|
||||
WardenLogTimestamp = 0
|
||||
LogColors = "13 7 11 9"
|
||||
SD3ErrorLogFile = "scriptdev3-errors.log"
|
||||
|
||||
|
|
@ -1889,74 +1882,6 @@ CharDelete.KeepDays = 30
|
|||
|
||||
QuestTracker.Enable = 0
|
||||
|
||||
###################################################################################################
|
||||
# WARDEN SETTINGS
|
||||
#
|
||||
# Warden.WinEnabled
|
||||
# Description: Enables Warden checks for Windows clients.
|
||||
# Default: 1 - (Enabled)
|
||||
# 0 - (Disabled)
|
||||
#
|
||||
# Warden.OSXEnabled
|
||||
# Description: Enables Warden checks for OSX clients.
|
||||
# Default: 0 - (Disabled)
|
||||
# 1 - (Enabled)
|
||||
#
|
||||
# Warden.NumMemChecks
|
||||
# Description: Number of Warden memory checks that are sent to the client each cycle.
|
||||
# Default: 3 - (Enabled)
|
||||
# 0 - (Disabled)
|
||||
#
|
||||
# Warden.NumOtherChecks
|
||||
# Description: Number of Warden checks other than memory checks that are added to request
|
||||
# each checking cycle.
|
||||
# Default: 7 - (Enabled)
|
||||
# 0 - (Disabled)
|
||||
#
|
||||
# Warden.ClientResponseDelay
|
||||
# Description: Time (in seconds) before client is getting disconnecting for not responding.
|
||||
# Default: 600 - (10 Minutes)
|
||||
# 0 - (Disabled, client won't be kicked)
|
||||
#
|
||||
# Warden.ClientCheckHoldOff
|
||||
# Description: Time (in seconds) to wait before sending the next check request to the client.
|
||||
# A low number increases traffic and load on client and server side.
|
||||
# Default: 30 - (30 Seconds)
|
||||
# 0 - (Send check as soon as possible)
|
||||
#
|
||||
# Warden.ClientCheckFailAction
|
||||
# Description: Default action being taken if a client check failed. Actions can be
|
||||
# overwritten for each single check via warden_action table in characters
|
||||
# database.
|
||||
# Default: 1 - (Kick)
|
||||
# 0 - (Disabled, Logging only)
|
||||
# 2 - (Ban)
|
||||
#
|
||||
# Warden.BanDuration
|
||||
# Description: Time (in seconds) an account will be banned if ClientCheckFailAction is set
|
||||
# to ban.
|
||||
# Default: 86400 - (24 hours)
|
||||
# 0 - (Permanent ban)
|
||||
#
|
||||
# Warden.DBLogLevel
|
||||
# Description: The minimal WardenActions value of Warden check to be logged into realmd.warden_log table.
|
||||
# WardenActions: 0 - log, 1 - kick, 2 - ban
|
||||
#
|
||||
# Deafult: 0 - (Logging any failed check)
|
||||
# 3 - (Disable DB logging)
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
Warden.WinEnabled = 1
|
||||
Warden.OSXEnabled = 0
|
||||
Warden.NumMemChecks = 3
|
||||
Warden.NumOtherChecks = 7
|
||||
Warden.ClientResponseDelay = 600
|
||||
Warden.ClientCheckHoldOff = 30
|
||||
Warden.ClientCheckFailAction = 1
|
||||
Warden.BanDuration = 86400
|
||||
Warden.DBLogLevel = 0
|
||||
|
||||
###################################################################################################
|
||||
# REALM STATUS FLAG
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 2b8b7f8a2ecb9c48d741d90f362feff4a4389988
|
||||
Subproject commit 095bc797730669f228d5126f4627b7d2a2e13a8f
|
||||
|
|
@ -63,14 +63,13 @@
|
|||
* are documented as using RC4-drop1024, and a reader who knows that will be tempted to
|
||||
* bake the drop into Init. It does not belong to the cipher: where the protocol wants
|
||||
* it, THE CALLER does it -- AuthCrypt keys both directions and then pushes 1024 zero
|
||||
* bytes through UpdateData, visibly, in its own source. Warden uses this same class and
|
||||
* performs no drop at all, so a discard inside Init would be right for one caller and
|
||||
* wrong for the other.
|
||||
* bytes through UpdateData, visibly, in its own source. The cipher must remain caller-
|
||||
* neutral: a discard inside Init would change every caller and double-apply any discard
|
||||
* already owned by the protocol layer.
|
||||
*
|
||||
* The failure it would cause is the nasty kind. World traffic would decrypt to garbage
|
||||
* and Warden would break in some different way, and both would present as a protocol
|
||||
* fault -- a client that connects and then cannot read a packet -- rather than as a
|
||||
* crypto one. Nobody would look here.
|
||||
* and present as a protocol fault -- a client that connects and then cannot read a
|
||||
* packet -- rather than as a crypto one. Nobody would look here.
|
||||
*
|
||||
* Arc4_TheKeystreamStartsAtByteZero exists to say so out loud if it ever happens.
|
||||
* =========================================================================
|
||||
|
|
|
|||
|
|
@ -37,11 +37,9 @@
|
|||
/**
|
||||
* @brief MD5 over OpenSSL's EVP interface.
|
||||
*
|
||||
* MD5 is used here only where the Warden protocol requires it -- identifying a
|
||||
* client module by the digest of its compressed image, and checking the digest
|
||||
* the client reports back. It is not used for anything security-bearing that
|
||||
* could be moved to a stronger digest: the algorithm is fixed by what the
|
||||
* 3.3.5a client does.
|
||||
* MD5 remains only for compatibility with legacy client protocols, including
|
||||
* the realmd patch catalogue. It must not be used for new security decisions;
|
||||
* the remaining algorithm choices are fixed by shipped clients.
|
||||
*
|
||||
* The point of this class is the *interface*, not the algorithm. The call sites
|
||||
* previously used OpenSSL's low-level MD5_Init/MD5_Update/MD5_Final, which
|
||||
|
|
|
|||
|
|
@ -1,109 +0,0 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "Auth/Sha1.h"
|
||||
#include <cstring>
|
||||
|
||||
#ifndef _WARDEN_KEY_GENERATION_H
|
||||
#define _WARDEN_KEY_GENERATION_H
|
||||
|
||||
/**
|
||||
* @brief SHA-1 based random number generator for Warden
|
||||
*
|
||||
* SHA1Randx generates a stream of pseudo-random bytes using SHA-1
|
||||
* hash algorithm. Used by Warden anti-cheat system for key generation.
|
||||
*/
|
||||
class SHA1Randx
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor - initializes with seed buffer
|
||||
* @param buff Pointer to seed buffer
|
||||
* @param size Size of seed buffer
|
||||
*/
|
||||
SHA1Randx(uint8* buff, uint32 size)
|
||||
{
|
||||
uint32 taken = size/2;
|
||||
|
||||
sh.Initialize();
|
||||
sh.UpdateData(buff, taken);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o1, sh.GetDigest(), 20);
|
||||
|
||||
sh.Initialize();
|
||||
sh.UpdateData(buff + taken, size - taken);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o2, sh.GetDigest(), 20);
|
||||
|
||||
memset(o0, 0x00, 20);
|
||||
|
||||
FillUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate random bytes
|
||||
* @param buf Buffer to store generated bytes
|
||||
* @param sz Number of bytes to generate
|
||||
*/
|
||||
void Generate(uint8* buf, uint32 sz)
|
||||
{
|
||||
for (uint32 i = 0; i < sz; ++i)
|
||||
{
|
||||
if (taken == 20)
|
||||
{
|
||||
FillUp();
|
||||
}
|
||||
|
||||
buf[i] = o0[taken];
|
||||
taken++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Refill the output buffer with new hash
|
||||
*/
|
||||
void FillUp()
|
||||
{
|
||||
sh.Initialize();
|
||||
sh.UpdateData(o1, 20);
|
||||
sh.UpdateData(o0, 20);
|
||||
sh.UpdateData(o2, 20);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o0, sh.GetDigest(), 20);
|
||||
|
||||
taken = 0;
|
||||
}
|
||||
|
||||
Sha1Hash sh; /**< SHA-1 hash instance */
|
||||
uint32 taken; /**< Number of bytes consumed from o0 */
|
||||
uint8 o0[20], o1[20], o2[20]; /**< Output buffers for hash chain */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -32,7 +32,6 @@ set(SRC_GRP_AUTH
|
|||
Auth/Md5.h
|
||||
Auth/Sha1.cpp
|
||||
Auth/Sha1.h
|
||||
Auth/WardenKeyGeneration.h
|
||||
)
|
||||
source_group("Auth" FILES ${SRC_GRP_AUTH})
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ Log::Log() :
|
|||
elunaErrLogfile(NULL),
|
||||
#endif /* ENABLE_ELUNA */
|
||||
|
||||
eventAiErLogfile(NULL), scriptErrLogFile(NULL), worldLogfile(NULL), wardenLogfile(NULL),
|
||||
eventAiErLogfile(NULL), scriptErrLogFile(NULL), worldLogfile(NULL),
|
||||
m_consoleBody(NULL), m_consoleThread(NULL), m_consoleAsync(false), m_colored(false),
|
||||
m_includeTime(false), m_gmlog_per_account(false), m_scriptLibName(NULL)
|
||||
{
|
||||
|
|
@ -337,11 +337,6 @@ void Log::CloseLogFiles()
|
|||
fclose(worldLogfile);
|
||||
worldLogfile = NULL;
|
||||
}
|
||||
if (wardenLogfile != NULL)
|
||||
{
|
||||
fclose(wardenLogfile);
|
||||
wardenLogfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Log::Flush()
|
||||
|
|
@ -589,8 +584,6 @@ void Log::Initialize()
|
|||
{
|
||||
worldLogfile = openLogFile("WorldLogFile", "WorldLogTimestamp", "a");
|
||||
}
|
||||
wardenLogfile = openLogFile("WardenLogFile", "WardenLogTimestamp", "a");
|
||||
|
||||
// Main log file settings
|
||||
m_includeTime = sConfig.GetBoolDefault("LogTime", false);
|
||||
m_logLevel = LogLevel(sConfig.GetIntDefault("LogLevel", 0));
|
||||
|
|
@ -1090,49 +1083,6 @@ void Log::outCommand(uint32 account, const char* str, ...)
|
|||
fflush(stdout);
|
||||
}
|
||||
|
||||
void Log::outWarden()
|
||||
{
|
||||
ConsoleEmitBlank(true);
|
||||
if (wardenLogfile)
|
||||
{
|
||||
outTimestamp(wardenLogfile);
|
||||
fprintf(wardenLogfile, "\n");
|
||||
fflush(wardenLogfile);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void Log::outWarden(const char* str, ...)
|
||||
{
|
||||
if (!str)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// FILE ONLY. Warden narrates six lines per check per player, every thirty seconds --
|
||||
// at LogLevel 3 that is a console nobody can read anything else in. It has a logfile of
|
||||
// its own, which is the whole point of having one; a real detection is reported through
|
||||
// outError and reaches the console that way.
|
||||
|
||||
if (wardenLogfile && m_logFileLevel >= LOG_LVL_DETAIL)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
outTimestamp(wardenLogfile);
|
||||
fprintf(wardenLogfile, "[Warden]: ");
|
||||
|
||||
va_start(ap, str);
|
||||
vfprintf(wardenLogfile, str, ap);
|
||||
fprintf(wardenLogfile, "\n");
|
||||
va_end(ap);
|
||||
|
||||
fflush(wardenLogfile);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void Log::outChar(const char* str, ...)
|
||||
{
|
||||
if (!str)
|
||||
|
|
|
|||
|
|
@ -336,17 +336,6 @@ class Log : public MaNGOS::Singleton<Log>
|
|||
* @param str...
|
||||
*/
|
||||
void outRALog(const char* str, ...) ATTR_PRINTF(2, 3);
|
||||
/**
|
||||
* @brief any log level
|
||||
*
|
||||
*/
|
||||
void outWarden();
|
||||
/**
|
||||
* @brief any log level
|
||||
*
|
||||
* @param str...
|
||||
*/
|
||||
void outWarden(const char* str, ...) ATTR_PRINTF(2, 3);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
|
|
@ -567,7 +556,6 @@ class Log : public MaNGOS::Singleton<Log>
|
|||
FILE* eventAiErLogfile; /**< TODO */
|
||||
FILE* scriptErrLogFile; /**< TODO */
|
||||
FILE* worldLogfile; /**< TODO */
|
||||
FILE* wardenLogfile; /**< TODO */
|
||||
std::mutex m_worldLogMtx; /**< Serializes packet-dump writes to worldLogfile */
|
||||
std::mutex m_fileMtx; /**< Serializes writes to the main logfile so concurrent map-update worker threads cannot tear lines */
|
||||
|
||||
|
|
|
|||
|
|
@ -45,19 +45,19 @@
|
|||
#define PROJECT_REVISION_NR "2203001"
|
||||
|
||||
#define REALMD_DB_VERSION_NR "22"
|
||||
#define REALMD_DB_STRUCTURE_NR "1"
|
||||
#define REALMD_DB_STRUCTURE_NR "4"
|
||||
#define REALMD_DB_CONTENT_NR "1"
|
||||
#define REALMD_DB_UPDATE_DESCRIPT "Release 22"
|
||||
#define REALMD_DB_UPDATE_DESCRIPT "Warden audit"
|
||||
|
||||
#define CHAR_DB_VERSION_NR "22"
|
||||
#define CHAR_DB_STRUCTURE_NR "7"
|
||||
#define CHAR_DB_STRUCTURE_NR "8"
|
||||
#define CHAR_DB_CONTENT_NR "1"
|
||||
#define CHAR_DB_UPDATE_DESCRIPT "Add_Quest_Tracker_Table"
|
||||
#define CHAR_DB_UPDATE_DESCRIPT "Remove_Warden_Action"
|
||||
|
||||
#define WORLD_DB_VERSION_NR "22"
|
||||
#define WORLD_DB_STRUCTURE_NR "6"
|
||||
#define WORLD_DB_STRUCTURE_NR "8"
|
||||
#define WORLD_DB_CONTENT_NR "1"
|
||||
#define WORLD_DB_UPDATE_DESCRIPT "creature_transport"
|
||||
#define WORLD_DB_UPDATE_DESCRIPT "Warden_Checks"
|
||||
|
||||
#define VER_COMPANY_NAME_STR "MaNGOS Developers"
|
||||
#define VER_LEGALCOPYRIGHT_STR "(c)2005-@rev_year@ MaNGOS"
|
||||
|
|
|
|||
|
|
@ -85,16 +85,16 @@ namespace
|
|||
* eventually be tempted to bake the discard into Init. It does not belong there. Where
|
||||
* the protocol wants a drop, THE CALLER does it -- AuthCrypt keys both directions and
|
||||
* then pushes 1024 zero bytes through UpdateData, in its own source, where it can be
|
||||
* seen. Warden uses this same class and drops nothing, so a discard inside Init would be
|
||||
* right for one caller and wrong for the other.
|
||||
* seen. The cipher must remain caller-neutral: a discard inside Init would change every
|
||||
* caller and double-apply any discard already owned by the protocol layer.
|
||||
*
|
||||
* The published vector would fail too, but it would fail as a hex mismatch, and whoever
|
||||
* added the drop would spend an afternoon doubting their key schedule. This one fails
|
||||
* with a name that says what happened.
|
||||
*
|
||||
* The stakes: world traffic decrypting to garbage and Warden breaking differently, both
|
||||
* presenting as a protocol fault -- a client that connects and then cannot read a single
|
||||
* packet -- rather than as a crypto one. Nobody would look at the cipher.
|
||||
* The stakes: world traffic decrypting to garbage and presenting as a protocol fault --
|
||||
* a client that connects and then cannot read a single packet -- rather than as a crypto
|
||||
* one. Nobody would look at the cipher.
|
||||
*/
|
||||
TEST(Arc4_TheKeystreamStartsAtByteZero)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ TEST(BigNumber_exact_length_needs_no_padding)
|
|||
TEST(BigNumber_session_key_sized_padding)
|
||||
{
|
||||
// The shape that actually bit: a 40-byte session key whose top byte is zero.
|
||||
// Warden and the login proof both ask for exactly 40 bytes.
|
||||
// The login proof asks for exactly 40 bytes.
|
||||
BigNumber n;
|
||||
n.SetDword(0xAABBCCDD);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ set(SRC_GRP_TESTS
|
|||
ByteBufferTest.cpp
|
||||
SessionMailboxTest.cpp
|
||||
SessionProtocolPolicyTest.cpp
|
||||
WorldGatewayAccountTest.cpp
|
||||
DatabaseConcurrencyTest.cpp
|
||||
ClientParserTest.cpp
|
||||
TerrainModelTest.cpp
|
||||
|
|
@ -56,6 +57,7 @@ set(SRC_GRP_TESTS
|
|||
${CMAKE_SOURCE_DIR}/src/game/WorldHandlers/DynamicCollision.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/game/WorldHandlers/GameObjectModel.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/game/Server/SessionMailbox.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/game/Server/WorldGatewayAccount.cpp
|
||||
ByteBufferStressTest.cpp
|
||||
CryptoStressTest.cpp
|
||||
# Re-keying, kept out of CryptoStressTest so that file stays the untouched proof
|
||||
|
|
|
|||
|
|
@ -156,8 +156,8 @@ TEST(Crypto_hmac_sha1_rfc2202_vector)
|
|||
TEST(Crypto_incremental_hashing_matches_one_shot)
|
||||
{
|
||||
// Feeding a digest in pieces must equal feeding it whole. This is the
|
||||
// property Warden and the login proof both rely on, since both build their
|
||||
// input from several appends.
|
||||
// property authentication and legacy-protocol code rely on when building
|
||||
// inputs from several appends.
|
||||
std::mt19937 rng(0x51A1u);
|
||||
std::uniform_int_distribution<int> byteDist(0, 255);
|
||||
std::uniform_int_distribution<size_t> chunkDist(1, 37);
|
||||
|
|
@ -307,29 +307,3 @@ TEST(Crypto_arc4_matches_the_published_vector)
|
|||
rc4.UpdateData(sizeof(data), data);
|
||||
CHECK_HEX(data, sizeof(data), "bbf316e8d940af0ad3");
|
||||
}
|
||||
|
||||
TEST(Crypto_warden_module_id_is_stable)
|
||||
{
|
||||
// Warden identifies a client module by the MD5 of its compressed image. The
|
||||
// same input must always give the same id -- this is the call that moved off
|
||||
// the deprecated MD5_* API, and a wrong id makes the client refuse the
|
||||
// module with nothing useful logged.
|
||||
std::vector<uint8> module(64 * 1024);
|
||||
for (size_t i = 0; i < module.size(); ++i)
|
||||
{
|
||||
module[i] = uint8((i * 7u) ^ 0xA5u);
|
||||
}
|
||||
|
||||
Md5Hash first;
|
||||
first.UpdateData(module.data(), module.size());
|
||||
first.Finalize();
|
||||
const std::string a = ToHex(first.GetDigest(), 16);
|
||||
|
||||
Md5Hash second;
|
||||
second.UpdateData(module.data(), module.size());
|
||||
second.Finalize();
|
||||
const std::string b = ToHex(second.GetDigest(), 16);
|
||||
|
||||
CHECK(a == b);
|
||||
CHECK_EQ(int(a.size()), 32);
|
||||
}
|
||||
|
|
|
|||
85
src/tests/WorldGatewayAccountTest.cpp
Normal file
85
src/tests/WorldGatewayAccountTest.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2026 MaNGOS <https://www.getmangos.eu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "TestHarness.h"
|
||||
#include "Database/Field.h"
|
||||
#include "WorldGatewayAccount.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
void SetClearRow(Field (&fields)[13])
|
||||
{
|
||||
for (Field& field : fields)
|
||||
field.SetValue("0");
|
||||
|
||||
fields[3].SetValue("192.0.2.10");
|
||||
fields[10].SetValue("Win");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WorldGatewayAccount_account_ban_follows_restored_os_field)
|
||||
{
|
||||
Field fields[13];
|
||||
SetClearRow(fields);
|
||||
fields[11].SetValue("1");
|
||||
CHECK_EQ(int(EvaluateAccountRestriction(fields, "192.0.2.10")),
|
||||
int(AccountRestriction::Banned));
|
||||
}
|
||||
|
||||
TEST(WorldGatewayAccount_ip_ban_follows_restored_os_field)
|
||||
{
|
||||
Field fields[13];
|
||||
SetClearRow(fields);
|
||||
fields[12].SetValue("1");
|
||||
CHECK_EQ(int(EvaluateAccountRestriction(fields, "192.0.2.10")),
|
||||
int(AccountRestriction::Banned));
|
||||
}
|
||||
|
||||
TEST(WorldGatewayAccount_locked_account_rejects_a_different_address)
|
||||
{
|
||||
Field fields[13];
|
||||
SetClearRow(fields);
|
||||
fields[4].SetValue("1");
|
||||
CHECK_EQ(int(EvaluateAccountRestriction(fields, "198.51.100.20")),
|
||||
int(AccountRestriction::LockedAddressMismatch));
|
||||
CHECK_EQ(int(EvaluateAccountRestriction(fields, "192.0.2.10")),
|
||||
int(AccountRestriction::None));
|
||||
}
|
||||
|
||||
TEST(WorldGatewayAccount_only_shipped_client_operating_systems_are_admitted)
|
||||
{
|
||||
Field fields[13];
|
||||
SetClearRow(fields);
|
||||
CHECK_EQ(int(EvaluateAccountRestriction(fields, "192.0.2.10")),
|
||||
int(AccountRestriction::None));
|
||||
|
||||
fields[10].SetValue("OSX");
|
||||
CHECK_EQ(int(EvaluateAccountRestriction(fields, "192.0.2.10")),
|
||||
int(AccountRestriction::None));
|
||||
|
||||
fields[10].SetValue("Linux");
|
||||
CHECK(EvaluateAccountRestriction(fields, "192.0.2.10") !=
|
||||
AccountRestriction::None);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue