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.
This commit is contained in:
MDIC
2022-08-18 12:59:04 -04:00
parent 9e9105080b
commit a4e1ef2feb
4 changed files with 111 additions and 1 deletions

View File

@@ -85,6 +85,7 @@ Anticheat.DetectGravityHack = 1
Anticheat.AntiKnockBack = 1 Anticheat.AntiKnockBack = 1
Anticheat.NoFallDamage = 1 Anticheat.NoFallDamage = 1
Anticheat.DetectBGStartHack = 1 Anticheat.DetectBGStartHack = 1
Anticheat.OpAckOrderHack = 1
# Anticheat.StricterFlyHackCheck # Anticheat.StricterFlyHackCheck
# Description: Checks moveflag ascending (may give false positives) # Description: Checks moveflag ascending (may give false positives)

View File

@@ -35,6 +35,9 @@ constexpr auto LANG_ANTICHEAT_IGNORECONTROL = 30089;
constexpr auto LANG_ANTICHEAT_DUEL = 30090; constexpr auto LANG_ANTICHEAT_DUEL = 30090;
constexpr auto LANG_ANTICHEAT_BG_EXPLOIT = 30091; 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 enum Spells
{ {
SHACKLES = 38505, SHACKLES = 38505,
@@ -46,6 +49,29 @@ enum Spells
AnticheatMgr::AnticheatMgr() 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() AnticheatMgr::~AnticheatMgr()
@@ -384,7 +410,7 @@ void AnticheatMgr::TeleportHackDetection(Player* player, MovementInfo movementIn
if (player->IsFalling() || (player->IsFalling() && player->IsMounted())) if (player->IsFalling() || (player->IsFalling() && player->IsMounted()))
return; return;
if (player->duel) if (player->duel)
{ {
if ((xDiff >= 50.0f || yDiff >= 50.0f || (zDiff >= 10.0f && !player->IsFlying())) && !player->CanTeleport()) 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()); 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) void AnticheatMgr::SavePlayerData(Player* player)
{ {
AnticheatData playerData = m_Players[player->GetGUID()]; AnticheatData playerData = m_Players[player->GetGUID()];

View File

@@ -57,6 +57,21 @@ enum ReportTypes
// GUID is the key. // GUID is the key.
typedef std::map<ObjectGuid, AnticheatData> AnticheatPlayersDataMap; typedef std::map<ObjectGuid, AnticheatData> 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 class AnticheatMgr
{ {
AnticheatMgr(); AnticheatMgr();
@@ -76,6 +91,13 @@ class AnticheatMgr
void SavePlayerDataDaily(Player* player); void SavePlayerDataDaily(Player* player);
void HandlePlayerLogin(Player* player); void HandlePlayerLogin(Player* player);
void HandlePlayerLogout(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<ServerOrderData> _opackorders; // Packets sent by server, triggering *_ACK from client
uint32 GetTotalReports(ObjectGuid guid); uint32 GetTotalReports(ObjectGuid guid);
float GetAverage(ObjectGuid guid); float GetAverage(ObjectGuid guid);
@@ -105,6 +127,7 @@ class AnticheatMgr
bool MustCheckTempReports(uint8 type); bool MustCheckTempReports(uint8 type);
uint32 _counter = 0; uint32 _counter = 0;
uint32 _alertFrequency = 0; uint32 _alertFrequency = 0;
uint32 _updateCheckTimer = 4000;
AnticheatPlayersDataMap m_Players; ///< Player data AnticheatPlayersDataMap m_Players; ///< Player data
}; };

View File

@@ -51,6 +51,12 @@ public:
if (sConfigMgr->GetOption<bool>("Anticheat.LoginMessage", true)) if (sConfigMgr->GetOption<bool>("Anticheat.LoginMessage", true))
ChatHandler(player->GetSession()).PSendSysMessage("This server is running an Anticheat Module."); ChatHandler(player->GetSession()).PSendSysMessage("This server is running an Anticheat Module.");
} }
void OnUpdate(Player* player, uint32 diff) override
{
if (sConfigMgr->GetOption<bool>("Anticheat.OpAckOrderHack", true))
sAnticheatMgr->AckUpdate(player, diff);
}
}; };
class AnticheatWorldScript : public WorldScript class AnticheatWorldScript : public WorldScript