OregonCore  revision 3611e8a-git
Your Favourite TBC server
WardenWin.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "Auth/Hmac.h"
20 #include "Common.h"
21 #include "WorldPacket.h"
22 #include "WorldSession.h"
23 #include "Log.h"
24 #include "Opcodes.h"
25 #include "ByteBuffer.h"
26 #include <openssl/md5.h>
27 #include "Database/DatabaseEnv.h"
28 #include "World.h"
29 #include "Player.h"
30 #include "Util.h"
31 #include "WardenWin.h"
32 #include "WardenModuleWin.h"
33 #include "WardenDataStorage.h"
34 
36 
38 {
39 }
40 
42 {
43 }
44 
46 {
47  Client = pClient;
48  // Generate Warden Key
49  SHA1Randx WK(K->AsByteArray(), K->GetNumBytes());
50  WK.generate(InputKey, 16);
51  WK.generate(OutputKey, 16);
52  /*
53  Seed: 4D808D2C77D905C41A6380EC08586AFE (0x05 packet)
54  Hash: 568C054C781A972A6037A2290C22B52571A06F4E (0x04 packet)
55  Module MD5: 79C0768D657977D697E10BAD956CCED1
56  New Client Key: 7F 96 EE FD A5 B6 3D 20 A4 DF 8E 00 CB F4 83 04
57  New Server Key: C2 B7 AD ED FC CC A9 C2 BF B3 F8 56 02 BA 80 9B
58  */
59  uint8 mod_seed[16] = { 0x4D, 0x80, 0x8D, 0x2C, 0x77, 0xD9, 0x05, 0xC4, 0x1A, 0x63, 0x80, 0xEC, 0x08, 0x58, 0x6A, 0xFE };
60 
61  memcpy(Seed, mod_seed, 16);
62 
65  sLog.outDebug("Server side warden for client %u initializing...", pClient->GetAccountId());
66  sLog.outDebug(" C->S Key: %s", ByteArrayToHexStr(InputKey, 16).c_str());
67  sLog.outDebug(" S->C Key: %s", ByteArrayToHexStr(OutputKey, 16).c_str());
68  sLog.outDebug(" Seed: %s", ByteArrayToHexStr(Seed, 16).c_str());
69  sLog.outDebug("Loading Module...");
70 
72 
73  sLog.outDebug(" Module Key: %s", ByteArrayToHexStr(Module->Key, 16).c_str());
74  sLog.outDebug(" Module ID: %s", ByteArrayToHexStr(Module->ID, 16).c_str());
75  RequestModule();
76 }
77 
79 {
81 
83 
84  // data assign
85  mod->CompressedSize = len;
86  mod->CompressedData = new uint8[len];
89 
90  // md5 hash
91  MD5_CTX ctx;
92  MD5_Init(&ctx);
93  MD5_Update(&ctx, mod->CompressedData, len);
94  MD5_Final((uint8*)&mod->ID, &ctx);
95 
96  return mod;
97 }
98 
100 {
101  sLog.outDebug("Initialize module");
102 
103  // Create packet structure
104  WardenInitModuleRequest Request;
106  Request.Size1 = 20;
107  Request.CheckSumm1 = BuildChecksum(&Request.Unk1, 20);
108  Request.Unk1 = 1;
109  Request.Unk2 = 0;
110  Request.Type = 1;
111  Request.String_library1 = 0;
112  Request.Function1[0] = 0x00024F80; // 0x00400000 + 0x00024F80 SFileOpenFile
113  Request.Function1[1] = 0x000218C0; // 0x00400000 + 0x000218C0 SFileGetFileSize
114  Request.Function1[2] = 0x00022530; // 0x00400000 + 0x00022530 SFileReadFile
115  Request.Function1[3] = 0x00022910; // 0x00400000 + 0x00022910 SFileCloseFile
116 
118  Request.Size2 = 8;
119  Request.CheckSumm2 = BuildChecksum(&Request.Unk2, 8);
120  Request.Unk3 = 4;
121  Request.Unk4 = 0;
122  Request.String_library2 = 0;
123  Request.Function2 = 0x00419D40; // 0x00400000 + 0x00419D40 FrameScript::GetText
124  Request.Function2_set = 1;
125 
127  Request.Size3 = 8;
128  Request.CheckSumm3 = BuildChecksum(&Request.Unk5, 8);
129  Request.Unk5 = 1;
130  Request.Unk6 = 1;
131  Request.String_library3 = 0;
132  Request.Function3 = 0x0046AE20; // 0x00400000 + 0x0046AE20 PerformanceCounter
133  Request.Function3_set = 1;
134 
135  // Encrypt with warden RC4 key.
136  EncryptData((uint8*)&Request, sizeof(WardenInitModuleRequest));
137 
139  pkt.append((uint8*)&Request, sizeof(WardenInitModuleRequest));
140  Client->SendPacket(&pkt);
141 }
142 
144 {
145  sLog.outDebug("Request hash");
146 
147  // Create packet structure
148  WardenHashRequest Request;
150  memcpy(Request.Seed, Seed, 16);
151 
152  // Encrypt with warden RC4 key.
153  EncryptData((uint8*)&Request, sizeof(WardenHashRequest));
154 
156  pkt.append((uint8*)&Request, sizeof(WardenHashRequest));
157  Client->SendPacket(&pkt);
158 }
159 
161 {
162  buff.rpos(buff.wpos());
163 
164  const uint8 validHash[20] = { 0x56, 0x8C, 0x05, 0x4C, 0x78, 0x1A, 0x97, 0x2A, 0x60, 0x37, 0xA2, 0x29, 0x0C, 0x22, 0xB5, 0x25, 0x71, 0xA0, 0x6F, 0x4E };
165 
166  // verify key not equal kick player
167  if (memcmp(buff.contents() + 1, validHash, sizeof(validHash)) != 0)
168  {
169  sLog.outWarden("Request hash reply: failed");
170  if (sWorld.getConfig(CONFIG_WARDEN_KICK))
171  Client->KickPlayer();
172  return;
173  }
174 
175  sLog.outDebug("Request hash reply: succeed");
176 
177  // client 7F96EEFDA5B63D20A4DF8E00CBF48304
178  const uint8 client_key[16] = { 0x7F, 0x96, 0xEE, 0xFD, 0xA5, 0xB6, 0x3D, 0x20, 0xA4, 0xDF, 0x8E, 0x00, 0xCB, 0xF4, 0x83, 0x04 };
179 
180  // server C2B7ADEDFCCCA9C2BFB3F85602BA809B
181  const uint8 server_key[16] = { 0xC2, 0xB7, 0xAD, 0xED, 0xFC, 0xCC, 0xA9, 0xC2, 0xBF, 0xB3, 0xF8, 0x56, 0x02, 0xBA, 0x80, 0x9B };
182 
183  // change keys here
184  memcpy(InputKey, client_key, 16);
185  memcpy(OutputKey, server_key, 16);
186 
189 
190  m_initialized = true;
191 
193 }
194 
196 {
197  sLog.outDebug("Request data");
198 
199  if (MemCheck.empty())
200  MemCheck.assign(WardenDataStorage.MemCheckIds.begin(), WardenDataStorage.MemCheckIds.end());
201 
203 
204  uint32 id;
205  uint8 type;
206  WardenData* wd;
207 
208  SendDataId.clear();
209 
210  for (uint32 i = 0; i < sWorld.getConfig(CONFIG_WARDEN_NUM_CHECKS); ++i) // for now include 3 MEM_CHECK's
211  {
212  if (MemCheck.empty())
213  break;
214  id = MemCheck.back();
215  SendDataId.push_back(id);
216  MemCheck.pop_back();
217  }
218 
219  ByteBuffer buff;
221 
222  // This doesn't apply for 2.4.3
223  //for (int i = 0; i < 5; ++i) // for now include 5 random checks
224  //{
225  // id = irand(1, maxid - 1);
226  // wd = WardenDataStorage.GetWardenDataById(id);
227  // SendDataId.push_back(id);
228  // switch (wd->Type)
229  // {
230  // case MPQ_CHECK:
231  // case LUA_STR_CHECK:
232  // case DRIVER_CHECK:
233  // buff << uint8(wd->str.size());
234  // buff.append(wd->str.c_str(), wd->str.size());
235  // break;
236  // default:
237  // break;
238  // }
239  //}
240 
241  uint8 xorByte = InputKey[0];
242 
243  buff << uint8(0x00);
244  buff << uint8(TIMING_CHECK ^ xorByte); // check TIMING_CHECK
245 
246  uint8 index = 1;
247 
248  for (std::vector<uint32>::iterator itr = SendDataId.begin(); itr != SendDataId.end(); ++itr)
249  {
250  wd = WardenDataStorage.GetWardenDataById(*itr);
251 
252  type = wd->Type;
253  buff << uint8(type ^ xorByte);
254  switch (type)
255  {
256  case MEM_CHECK:
257  {
258  buff << uint8(0x00);
259  buff << uint32(wd->Address);
260  buff << uint8(wd->Length);
261  break;
262  }
263  case PAGE_CHECK_A:
264  case PAGE_CHECK_B:
265  {
266  buff.append(wd->i.AsByteArray(0), wd->i.GetNumBytes());
267  buff << uint32(wd->Address);
268  buff << uint8(wd->Length);
269  break;
270  }
271  case MPQ_CHECK:
272  case LUA_STR_CHECK:
273  {
274  buff << uint8(index++);
275  break;
276  }
277  case DRIVER_CHECK:
278  {
279  buff.append(wd->i.AsByteArray(0), wd->i.GetNumBytes());
280  buff << uint8(index++);
281  break;
282  }
283  case MODULE_CHECK:
284  {
285  uint32 seed = static_cast<uint32>(rand32());
286  buff << uint32(seed);
287  HmacHash hmac(4, (uint8*)&seed);
288  hmac.UpdateData(wd->str);
289  hmac.Finalize();
290  buff.append(hmac.GetDigest(), hmac.GetLength());
291  break;
292  }
293  /*case PROC_CHECK:
294  {
295  buff.append(wd->i.AsByteArray(0, false), wd->i.GetNumBytes());
296  buff << uint8(index++);
297  buff << uint8(index++);
298  buff << uint32(wd->Address);
299  buff << uint8(wd->Length);
300  break;
301  }*/
302  default:
303  break; // should never happens
304  }
305  }
306  buff << uint8(xorByte);
307  buff.hexlike();
308 
309  // Encrypt with warden RC4 key.
310  EncryptData(const_cast<uint8*>(buff.contents()), buff.size());
311 
312  WorldPacket pkt(SMSG_WARDEN_DATA, buff.size());
313  pkt.append(buff);
314  Client->SendPacket(&pkt);
315 
316  m_WardenDataSent = true;
317 
318  std::stringstream stream;
319  stream << "Sent check id's: ";
320  for (std::vector<uint32>::iterator itr = SendDataId.begin(); itr != SendDataId.end(); ++itr)
321  stream << *itr << " ";
322  sLog.outDebug("%s", stream.str().c_str());
323 }
324 
326 {
327  sLog.outDebug("Handle data");
328 
329  m_WardenDataSent = false;
330  m_WardenKickTimer = 0;
331 
332  uint16 Length;
333  buff >> Length;
334  uint32 Checksum;
335  buff >> Checksum;
336 
337  if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length))
338  {
339  buff.rpos(buff.wpos());
340  if (sWorld.getConfig(CONFIG_WARDEN_KICK))
341  Client->KickPlayer();
342  return;
343  }
344 
345  bool found = false;
346 
347  //TIMING_CHECK
348  {
349  uint8 result;
350  buff >> result;
351  // @todo test it.
352  if (result == 0x00)
353  {
354  sLog.outWarden("TIMING CHECK FAIL result 0x00");
355  found = true;
356  }
357 
358  uint32 newClientTicks;
359  buff >> newClientTicks;
360 
361  uint32 ticksNow = getMSTime();
362  uint32 ourTicks = newClientTicks + (ticksNow - ServerTicks);
363 
364  sLog.outDebug("ServerTicks %u", ticksNow); // now
365  sLog.outDebug("RequestTicks %u", ServerTicks); // at request
366  sLog.outDebug("Ticks %u", newClientTicks); // at response
367  sLog.outDebug("Ticks diff %u", ourTicks - newClientTicks);
368  }
369 
370  WardenDataResult* rs;
371  WardenData* rd;
372  uint8 type;
373 
374  for (std::vector<uint32>::iterator itr = SendDataId.begin(); itr != SendDataId.end(); ++itr)
375  {
376  rd = WardenDataStorage.GetWardenDataById(*itr);
377  rs = WardenDataStorage.GetWardenResultById(*itr);
378 
379  type = rd->Type;
380  switch (type)
381  {
382  case MEM_CHECK:
383  {
384  uint8 Mem_Result;
385  buff >> Mem_Result;
386 
387  if (Mem_Result != 0)
388  {
389  sLog.outWarden("RESULT MEM_CHECK not 0x00, CheckId %u account Id %u", rd->id, Client->GetAccountId());
390  found = true;
391  continue;
392  }
393 
394  if (memcmp(buff.contents() + buff.rpos(), rs->res.AsByteArray(0, false), rd->Length) != 0)
395  {
396  sLog.outWarden("RESULT MEM_CHECK fail CheckId %u account Id %u", rd->id, Client->GetAccountId());
397  found = true;
398  buff.rpos(buff.rpos() + rd->Length);
399  continue;
400  }
401 
402  buff.rpos(buff.rpos() + rd->Length);
403  sLog.outDebug("RESULT MEM_CHECK passed CheckId %u account Id %u", rd->id, Client->GetAccountId());
404  break;
405  }
406  case PAGE_CHECK_A:
407  case PAGE_CHECK_B:
408  case DRIVER_CHECK:
409  case MODULE_CHECK:
410  {
411  const uint8 byte = 0xE9;
412  if (memcmp(buff.contents() + buff.rpos(), &byte, sizeof(uint8)) != 0)
413  {
414  if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
415  sLog.outWarden("RESULT PAGE_CHECK fail, CheckId %u account Id %u", rd->id, Client->GetAccountId());
416  if (type == MODULE_CHECK)
417  sLog.outWarden("RESULT MODULE_CHECK fail, CheckId %u account Id %u", rd->id, Client->GetAccountId());
418  if (type == DRIVER_CHECK)
419  sLog.outWarden("RESULT DRIVER_CHECK fail, CheckId %u account Id %u", rd->id, Client->GetAccountId());
420  found = true;
421  buff.rpos(buff.rpos() + 1);
422  continue;
423  }
424 
425  buff.rpos(buff.rpos() + 1);
426  if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
427  sLog.outDebug("RESULT PAGE_CHECK passed CheckId %u account Id %u", rd->id, Client->GetAccountId());
428  else if (type == MODULE_CHECK)
429  sLog.outDebug("RESULT MODULE_CHECK passed CheckId %u account Id %u", rd->id, Client->GetAccountId());
430  else if (type == DRIVER_CHECK)
431  sLog.outDebug("RESULT DRIVER_CHECK passed CheckId %u account Id %u", rd->id, Client->GetAccountId());
432  break;
433  }
434  case LUA_STR_CHECK:
435  {
436  uint8 Lua_Result;
437  buff >> Lua_Result;
438 
439  if (Lua_Result != 0)
440  {
441  sLog.outWarden("RESULT LUA_STR_CHECK fail, CheckId %u account Id %u", rd->id, Client->GetAccountId());
442  found = true;
443  continue;
444  }
445 
446  uint8 luaStrLen;
447  buff >> luaStrLen;
448 
449  if (luaStrLen != 0)
450  {
451  char* str = new char[luaStrLen + 1];
452  memset(str, 0, luaStrLen + 1);
453  memcpy(str, buff.contents() + buff.rpos(), luaStrLen);
454  sLog.outDebug("Lua string: %s", str);
455  delete[] str;
456  }
457  buff.rpos(buff.rpos() + luaStrLen); // skip string
458  sLog.outDebug("RESULT LUA_STR_CHECK passed, CheckId %u account Id %u", rd->id, Client->GetAccountId());
459  break;
460  }
461  case MPQ_CHECK:
462  {
463  uint8 Mpq_Result;
464  buff >> Mpq_Result;
465 
466  if (Mpq_Result != 0)
467  {
468  sLog.outWarden("RESULT MPQ_CHECK not 0x00 account id %u", Client->GetAccountId());
469  found = true;
470  continue;
471  }
472 
473  if (memcmp(buff.contents() + buff.rpos(), rs->res.AsByteArray(0), 20) != 0) // SHA1
474  {
475  sLog.outWarden("RESULT MPQ_CHECK fail, CheckId %u account Id %u", rd->id, Client->GetAccountId());
476  found = true;
477  buff.rpos(buff.rpos() + 20); // 20 bytes SHA1
478  continue;
479  }
480 
481  buff.rpos(buff.rpos() + 20); // 20 bytes SHA1
482  sLog.outDebug("RESULT MPQ_CHECK passed, CheckId %u account Id %u", rd->id, Client->GetAccountId());
483  break;
484  }
485  default: // should never happens
486  break;
487  }
488  }
489 
490  if (found && sWorld.getConfig(CONFIG_WARDEN_KICK))
491  Client->KickPlayer();
492 }
static uint32 BuildChecksum(const uint8 *data, uint32 dataLen)
Definition: WardenBase.cpp:179
ClientWardenModule * Module
Definition: WardenBase.h:126
void UpdateData(const uint8 *data, int length)
Definition: Hmac.cpp:46
const uint8 * contents() const
Definition: ByteBuffer.h:331
static bool IsValidCheckSum(uint32 checksum, const uint8 *Data, const uint16 Length)
Definition: WardenBase.cpp:163
bool m_WardenDataSent
Definition: WardenBase.h:124
uint8 * AsByteArray(int minSize=0, bool reverse=true)
Definition: BigNumber.cpp:166
int GetLength()
Definition: Hmac.h:44
CWardenDataStorage WardenDataStorage
Definition: WardenWin.cpp:35
int GetNumBytes(void)
Definition: BigNumber.cpp:151
ClientWardenModule * GetModuleForClient(WorldSession *session)
Definition: WardenWin.cpp:78
uint32 CompressedSize
Definition: WardenBase.h:82
uint32 getMSTime()
Definition: Timer.h:32
void Init(uint8 *seed)
Definition: SARC4.cpp:41
#define sLog
Log class singleton.
Definition: Log.h:187
uint8 Seed[16]
Definition: WardenBase.h:69
uint32 m_WardenKickTimer
Definition: WardenBase.h:123
SARC4 oCrypto
Definition: WardenBase.h:121
uint32 GetAccountId() const
Definition: WorldSession.h:100
Definition: Hmac.h:29
std::vector< uint32 > MemCheck
Definition: WardenWin.h:101
void SendPacket(WorldPacket const *packet)
std::vector< uint32 > MemCheckIds
uint32 m_WardenTimer
Definition: WardenBase.h:125
uint8 * CompressedData
Definition: WardenBase.h:83
void generate(uint8 *buf, uint32 sz)
size_t wpos() const
Definition: ByteBuffer.h:264
ACE_UINT8 uint8
Definition: Define.h:73
uint8 Module_79C0768D657977D697E10BAD956CCED1_Key[16]
size_t size() const
Definition: ByteBuffer.h:336
void RequestHash()
Definition: WardenWin.cpp:143
void RequestModule()
Definition: WardenBase.cpp:103
void HandleHashResult(ByteBuffer &buff)
Definition: WardenWin.cpp:160
std::string ByteArrayToHexStr(uint8 *bytes, uint32 length)
Definition: Util.cpp:493
std::string str
SARC4 iCrypto
Definition: WardenBase.h:120
void RequestData()
Definition: WardenWin.cpp:195
void hexlike() const
Definition: ByteBuffer.h:451
uint8 Module_79C0768D657977D697E10BAD956CCED1_Data[18756]
uint8 * GetDigest()
Definition: Hmac.h:40
WorldSession * Client
Definition: WardenBase.h:116
void Finalize()
Definition: Hmac.cpp:61
uint32 ServerTicks
Definition: WardenWin.h:99
void append(const std::string &str)
Definition: ByteBuffer.h:358
void Init(WorldSession *pClient, BigNumber *K)
Definition: WardenWin.cpp:45
void InitializeModule()
Definition: WardenWin.cpp:99
WardenDataResult * GetWardenResultById(uint32 Id)
#define sWorld
Definition: World.h:860
void EncryptData(uint8 *Buffer, uint32 Len)
Definition: WardenBase.cpp:158
ACE_UINT16 uint16
Definition: Define.h:72
size_t rpos() const
Definition: ByteBuffer.h:253
ACE_UINT32 uint32
Definition: Define.h:71
int32 rand32()
Definition: Util.cpp:81
uint8 InputKey[16]
Definition: WardenBase.h:117
bool m_initialized
Definition: WardenBase.h:127
uint8 OutputKey[16]
Definition: WardenBase.h:118
void HandleData(ByteBuffer &buff)
Definition: WardenWin.cpp:325
std::vector< uint32 > SendDataId
Definition: WardenWin.h:100
WardenData * GetWardenDataById(uint32 Id)
uint8 Seed[16]
Definition: WardenBase.h:119