From a4e1ef2feb29a32fa8053644d977e57b5ce001e8 Mon Sep 17 00:00:00 2001 From: MDIC Date: Thu, 18 Aug 2022 12:59:04 -0400 Subject: [PATCH] feat (experimential\conf): Op Code Ack Hack Check New conf: Anticheat.OpAckOrderHack = 1 This is experimental. It will run with just the new conf. This checks for the more advance hacks of op code manipulation sent to the server. It will not alert the GMs and will not add to the collumn counts at the current moment. It will only log into the log file when the conf is enabled. This is experimental until we get feed back on performance impact. --- conf/Anticheat.conf.dist | 1 + src/AnticheatMgr.cpp | 82 +++++++++++++++++++++++++++++++++++++++- src/AnticheatMgr.h | 23 +++++++++++ src/AnticheatScripts.cpp | 6 +++ 4 files changed, 111 insertions(+), 1 deletion(-) diff --git a/conf/Anticheat.conf.dist b/conf/Anticheat.conf.dist index 745ee72..fe35e07 100644 --- a/conf/Anticheat.conf.dist +++ b/conf/Anticheat.conf.dist @@ -85,6 +85,7 @@ Anticheat.DetectGravityHack = 1 Anticheat.AntiKnockBack = 1 Anticheat.NoFallDamage = 1 Anticheat.DetectBGStartHack = 1 +Anticheat.OpAckOrderHack = 1 # Anticheat.StricterFlyHackCheck # Description: Checks moveflag ascending (may give false positives) diff --git a/src/AnticheatMgr.cpp b/src/AnticheatMgr.cpp index 1dc50fd..6ffa299 100644 --- a/src/AnticheatMgr.cpp +++ b/src/AnticheatMgr.cpp @@ -35,6 +35,9 @@ constexpr auto LANG_ANTICHEAT_IGNORECONTROL = 30089; constexpr auto LANG_ANTICHEAT_DUEL = 30090; constexpr auto LANG_ANTICHEAT_BG_EXPLOIT = 30091; +// Time between server sends acknowledgement, and client is actually acknowledged +constexpr auto ALLOWED_ACK_LAG = 2000; + enum Spells { SHACKLES = 38505, @@ -46,6 +49,29 @@ enum Spells AnticheatMgr::AnticheatMgr() { + _opackorders = + { + { SMSG_FORCE_WALK_SPEED_CHANGE, CMSG_FORCE_WALK_SPEED_CHANGE_ACK }, + { SMSG_FORCE_RUN_SPEED_CHANGE, CMSG_FORCE_RUN_SPEED_CHANGE_ACK }, + { SMSG_FORCE_RUN_BACK_SPEED_CHANGE, CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK }, + { SMSG_FORCE_SWIM_SPEED_CHANGE, CMSG_FORCE_SWIM_SPEED_CHANGE_ACK }, + { SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK }, + { SMSG_FORCE_TURN_RATE_CHANGE, CMSG_FORCE_TURN_RATE_CHANGE_ACK }, + { SMSG_FORCE_PITCH_RATE_CHANGE, CMSG_FORCE_PITCH_RATE_CHANGE_ACK }, + { SMSG_FORCE_FLIGHT_SPEED_CHANGE, CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK }, + { SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK }, + { SMSG_FORCE_MOVE_ROOT, CMSG_FORCE_MOVE_ROOT_ACK }, + { SMSG_FORCE_MOVE_UNROOT, CMSG_FORCE_MOVE_UNROOT_ACK }, + { SMSG_MOVE_KNOCK_BACK, CMSG_MOVE_KNOCK_BACK_ACK }, + { SMSG_MOVE_FEATHER_FALL, SMSG_MOVE_NORMAL_FALL, CMSG_MOVE_FEATHER_FALL_ACK }, + { SMSG_MOVE_SET_HOVER, SMSG_MOVE_UNSET_HOVER, CMSG_MOVE_HOVER_ACK }, + { SMSG_MOVE_SET_CAN_FLY, SMSG_MOVE_UNSET_CAN_FLY, CMSG_MOVE_SET_CAN_FLY_ACK }, + { SMSG_MOVE_WATER_WALK, SMSG_MOVE_LAND_WALK, CMSG_MOVE_WATER_WALK_ACK }, + { SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK }, + { SMSG_MOVE_GRAVITY_ENABLE, CMSG_MOVE_GRAVITY_ENABLE_ACK }, + { SMSG_MOVE_GRAVITY_DISABLE, CMSG_MOVE_GRAVITY_DISABLE_ACK }, + { SMSG_MOVE_SET_COLLISION_HGT, CMSG_MOVE_SET_COLLISION_HGT_ACK } + }; } AnticheatMgr::~AnticheatMgr() @@ -384,7 +410,7 @@ void AnticheatMgr::TeleportHackDetection(Player* player, MovementInfo movementIn if (player->IsFalling() || (player->IsFalling() && player->IsMounted())) return; - + if (player->duel) { if ((xDiff >= 50.0f || yDiff >= 50.0f || (zDiff >= 10.0f && !player->IsFlying())) && !player->CanTeleport()) @@ -1226,6 +1252,60 @@ void AnticheatMgr::HandlePlayerLogout(Player* player) m_Players.erase(player->GetGUID()); } +void AnticheatMgr::AckUpdate(Player* player, uint32 diff) +{ + if (_updateCheckTimer <= diff) + { + DoActions(player); + _updateCheckTimer = 4000; + } + else + { + _updateCheckTimer -= diff; + } +} + +void AnticheatMgr::DoActions(Player* player) +{ + auto const now = getMSTime(); + + for (auto& order : _opackorders) + { + if (order.counter > 0 && order.lastRcvd < order.lastSent && (now - order.lastSent) > ALLOWED_ACK_LAG) + { + uint32 latency = 0; + latency = player->GetSession()->GetLatency(); + LOG_INFO("anticheat.module", "Opcode Manipulation Hack detected player {} ({}) - Latency: {} ms", player->GetName(), player->GetGUID().ToString(), latency); + order.counter = 0; + } + } +} + +void AnticheatMgr::OrderSent(WorldPacket const* data) +{ + for (auto& order : _opackorders) + { + if (order.serverOpcode1 == data->GetOpcode() || order.serverOpcode2 == data->GetOpcode()) + { + order.lastSent = getMSTime(); + ++order.counter; + break; + } + } +} + +void AnticheatMgr::CheckForOrderAck(uint32 opcode) +{ + for (auto& order : _opackorders) + { + if (order.clientResp == opcode) + { + --order.counter; + break; + } + } +} + void AnticheatMgr::SavePlayerData(Player* player) { AnticheatData playerData = m_Players[player->GetGUID()]; diff --git a/src/AnticheatMgr.h b/src/AnticheatMgr.h index 910b469..4e1b28c 100644 --- a/src/AnticheatMgr.h +++ b/src/AnticheatMgr.h @@ -57,6 +57,21 @@ enum ReportTypes // GUID is the key. typedef std::map AnticheatPlayersDataMap; +class ServerOrderData +{ +public: + ServerOrderData(uint32 serv, uint32 resp) : serverOpcode1(serv), serverOpcode2(0), clientResp(resp), lastSent(0), lastRcvd(0), counter(0) {} + ServerOrderData(uint32 serv1, uint32 serv2, uint32 resp) : serverOpcode1(serv1), serverOpcode2(serv2), clientResp(resp), lastSent(0), lastRcvd(0), counter(0) {} + + uint32 serverOpcode1; + uint32 serverOpcode2; + uint32 clientResp; + + uint32 lastSent; + uint32 lastRcvd; + int32 counter; +}; + class AnticheatMgr { AnticheatMgr(); @@ -76,6 +91,13 @@ class AnticheatMgr void SavePlayerDataDaily(Player* player); void HandlePlayerLogin(Player* player); void HandlePlayerLogout(Player* player); + void AckUpdate(Player* player, uint32 diff); + void DoActions(Player* player); + + // orders + void OrderSent(WorldPacket const* data); + void CheckForOrderAck(uint32 opcode); + std::vector _opackorders; // Packets sent by server, triggering *_ACK from client uint32 GetTotalReports(ObjectGuid guid); float GetAverage(ObjectGuid guid); @@ -105,6 +127,7 @@ class AnticheatMgr bool MustCheckTempReports(uint8 type); uint32 _counter = 0; uint32 _alertFrequency = 0; + uint32 _updateCheckTimer = 4000; AnticheatPlayersDataMap m_Players; ///< Player data }; diff --git a/src/AnticheatScripts.cpp b/src/AnticheatScripts.cpp index f4b21d1..5a19803 100644 --- a/src/AnticheatScripts.cpp +++ b/src/AnticheatScripts.cpp @@ -51,6 +51,12 @@ public: if (sConfigMgr->GetOption("Anticheat.LoginMessage", true)) ChatHandler(player->GetSession()).PSendSysMessage("This server is running an Anticheat Module."); } + + void OnUpdate(Player* player, uint32 diff) override + { + if (sConfigMgr->GetOption("Anticheat.OpAckOrderHack", true)) + sAnticheatMgr->AckUpdate(player, diff); + } }; class AnticheatWorldScript : public WorldScript