mangos/src/game/Warden/WardenMac.cpp
Giperionn 1ff6c40b0d Several fixes (#10)
* * Fixed dereferencing nullptr, when sending CMSG_LOOT guid with HIGHGUID_GAMEOBJECT, but invalid in general.

* * Don't allow sending LANG_UNIVERSAL by player
* Don't allow messages with more that 255 symbols (server side check)

* * Prevent cheaters cast honorless target on self

* * Now warden reacts on client delay when initialization in progress or strange behaviour with initialization logic

* Remove default case from switch

This allows compilers to detect if a case for the WardenState enum is missing when using -Wall flag

* Make the intention of the IF case more clear

Make the intention of the IF case more clear and suppress a compiler warning when using -Wall or /W4 flags
2017-03-01 18:44:11 +00:00

263 lines
7.4 KiB
C++

/**
* 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-2017 MaNGOS project <https://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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
* and lore are copyrighted by Blizzard Entertainment, Inc.
*/
#include "WardenKeyGeneration.h"
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Log.h"
#include "Opcodes.h"
#include "ByteBuffer.h"
#include <openssl/md5.h>
#include "World.h"
#include "Player.h"
#include "Util.h"
#include "WardenMac.h"
#include "WardenModuleMac.h"
WardenMac::WardenMac() : Warden() { }
WardenMac::~WardenMac() { }
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();
}
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
MD5_CTX ctx;
MD5_Init(&ctx);
MD5_Update(&ctx, mod->CompressedData, len);
MD5_Final((uint8*)&mod->Id, &ctx);
return mod;
}
void WardenMac::InitializeModule()
{
sLog.outWarden("Initialize module");
Warden::InitializeModule();
}
struct keyData {
union
{
struct
{
uint8 bytes[16];
} bytes;
struct
{
int ints[4];
} ints;
};
};
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 = WorldTimer::getMSTime();
}
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();
}
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;
}
MD5_CTX ctx;
MD5_Init(&ctx);
MD5_Update(&ctx, str.c_str(), str.size());
uint8 ourMD5Hash[16];
MD5_Final(ourMD5Hash, &ctx);
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);
}