[Feature] Client Checksum Verification (Resubmit old 1678) (#1922)

* [Feature] Client Checksum Verification (Resubmit old 1678)

* Updated db version

* Add new updatechecksum to CmakeLists.txt

* Removed magic number and used constant

* Fix new command to have access to worldserver

* spacing, more venbose desc and remove unneeded check

* Cleanup, refactoring

Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
Paul Coene
2022-03-06 21:26:29 -05:00
committed by GitHub
parent eca2ed0321
commit 2a5ddde78a
23 changed files with 356 additions and 33 deletions
+147 -3
View File
@@ -47,6 +47,7 @@
#include "wguild_mgr.h"
#include "sof_char_create_data.h"
#include "world_store.h"
#include "../common/repositories/account_repository.h"
#include <iostream>
#include <iomanip>
@@ -1013,15 +1014,18 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
switch(opcode)
{
case OP_World_Client_CRC1:
case OP_World_Client_CRC2:
case OP_World_Client_CRC1: // eqgame.exe
case OP_World_Client_CRC2: // SkillCaps.txt
case OP_World_Client_CRC3: // BaseData.txt
{
// There is no obvious entry in the CC struct to indicate that the 'Start Tutorial button
// is selected when a character is created. I have observed that in this case, OP_EnterWorld is sent
// before OP_World_Client_CRC1. Therefore, if we receive OP_World_Client_CRC1 before OP_EnterWorld,
// then 'Start Tutorial' was not chosen.
StartInTutorial = false;
return true;
return HandleChecksumPacket(app);
}
case OP_SendLoginInfo:
{
@@ -1142,6 +1146,146 @@ bool Client::Process() {
return ret;
}
bool Client::HandleChecksumPacket(const EQApplicationPacket *app)
{
// Is checksum verification turned on
if (!RuleB(World, EnableChecksumVerification)) {
return true;
}
// Get packet structure
auto *cs = (Checksum_Struct *)app->pBuffer;
// Determine which checksum to process
switch (app->GetOpcode()) {
case OP_World_Client_CRC1: // eqgame.exe
{
bool passes_checksum_validation = (
ChecksumVerificationCRCEQGame(cs->checksum) ||
(GetAdmin() >= RuleI(GM, MinStatusToBypassCheckSumVerification))
);
LogChecksumVerification(
"eqgame.exe validation [{}] client [{}] ({}) has [{}] status [{}]",
passes_checksum_validation ? "Passed" : "Failed",
GetAccountName(),
GetAccountID(),
cs->checksum,
GetAdmin()
);
return passes_checksum_validation;
}
case OP_World_Client_CRC2: // SkillCaps.txt
{
bool passes_checksum_validation = (
ChecksumVerificationCRCSkillCaps(cs->checksum) ||
(GetAdmin() >= RuleI(GM, MinStatusToBypassCheckSumVerification))
);
LogChecksumVerification(
"SkillCaps.txt validation [{}] client [{}] ({}) has [{}] status [{}]",
passes_checksum_validation ? "Passed" : "Failed",
GetAccountName(),
GetAccountID(),
cs->checksum,
GetAdmin()
);
return passes_checksum_validation;
}
case OP_World_Client_CRC3: // BaseData.txt
{
bool passes_checksum_validation = (
ChecksumVerificationCRCBaseData(cs->checksum) ||
(GetAdmin() >= RuleI(GM, MinStatusToBypassCheckSumVerification))
);
LogChecksumVerification(
"BaseData.txt validation [{}] client [{}] ({}) has [{}] status [{}]",
passes_checksum_validation ? "Passed" : "Failed",
GetAccountName(),
GetAccountID(),
cs->checksum,
GetAdmin()
);
return passes_checksum_validation;
}
}
return false;
}
bool Client::ChecksumVerificationCRCEQGame(uint64 checksum)
{
database.SetAccountCRCField(GetAccountID(), "crc_eqgame", checksum);
// Get checksum variable for eqgame.exe
std::string checksumvar;
uint64_t checksumint;
if (database.GetVariable("crc_eqgame", checksumvar)) {
checksumint = atoll(checksumvar.c_str());
}
else {
LogChecksumVerification("[checksum_crc1_eqgame] variable not set in variables table.");
return true;
}
// Verify checksums match
if (checksumint == checksum) {
return true;
}
return false;
}
bool Client::ChecksumVerificationCRCSkillCaps(uint64 checksum)
{
database.SetAccountCRCField(GetAccountID(), "crc_skillcaps", checksum);
// Get checksum variable for eqgame.exe
std::string checksumvar;
uint64_t checksumint;
if (database.GetVariable("crc_skillcaps", checksumvar)) {
checksumint = atoll(checksumvar.c_str());
}
else {
LogChecksumVerification("[checksum_crc2_skillcaps] variable not set in variables table.");
return true;
}
// Verify checksums match
if (checksumint == checksum) {
return true;
}
return false;
}
bool Client::ChecksumVerificationCRCBaseData(uint64 checksum)
{
database.SetAccountCRCField(GetAccountID(), "crc_basedata", checksum);
// Get checksum variable for skill_caps.txt
std::string checksumvar;
uint64_t checksumint;
if (database.GetVariable("crc_basedata", checksumvar)) {
checksumint = atoll(checksumvar.c_str());
}
else {
LogChecksumVerification("[checksum_crc3_basedata] variable not set in variables table.");
return true;
}
// Verify checksums match
if (checksumint == checksum) {
return true;
}
return false;
}
void Client::EnterWorld(bool TryBootup) {
if (zone_id == 0)
return;