anti cheat tips
#1

I was going to make an AntiCheat but then I decided not to because the people that would use an anticheat from the forum would just use one of the more popular ones so I decided to give out tips to those that are creating one for themselves.

Using Stocks or Hooks
I use a lot of stocks, these replace default functions in the script such as GivePlayerMoney and GivePlayerWeapon and even SetPlayerPos, this is so I can set, check and delete variables that will be used to detect whether a player is cheating.
Instead of using stocks you might decide to add hooks, these allow you to add code to the original functions, just like stocks.
here's an example provided by ******
pawn Code:
stock My_GivePlayerMoney(playerid, money)
{
    // Record the value however you like.
    // ...
    // Call the real GivePlayerMoney
    return GivePlayerMoney(playerid, money);
}

#if defined _ALS_GivePlayerMoney
    #undef GivePlayerMoney
#else
    #define _ALS_GivePlayerMoney
#endif
#define GivePlayerMoney My_GivePlayerMoney
The Alive Check
one of the handiest things that's used is a variable that says whether the player is alive or dead, when they join the server, request spawn, or die the variable is set to dead, and when they spawn it is set to alive, then I always check if they are alive before any anticheat checks are done.
I found in older sa-mp versions it may say that a player has brass knuckles when they are at skin selection.

Health Checks
I use this to get rid of all the vending machines when a player connects to the server
pawn Code:
RemoveBuildingForPlayer(playerid, 1302, 0.0, 0.0, 0.0, 6000.0);
    RemoveBuildingForPlayer(playerid, 1209, 0.0, 0.0, 0.0, 6000.0);
    RemoveBuildingForPlayer(playerid, 955, 0.0, 0.0, 0.0, 6000.0);
    RemoveBuildingForPlayer(playerid, 956, 0.0, 0.0, 0.0, 6000.0);
    RemoveBuildingForPlayer(playerid, 1775, 0.0, 0.0, 0.0, 6000.0);
    RemoveBuildingForPlayer(playerid, 1776, 0.0, 0.0, 0.0, 6000.0);
    RemoveBuildingForPlayer(playerid, 1977, 0.0, 0.0, 0.0, 6000.0);
When the player spawns I set their health to 99, wait for it to sync and then monitor it for changes, also I use data from OnPlayerTakeDamage to check that they take damage by reducing the variables of what their health should be and waiting for sync, if they don't sync for a few seconds I'll set their health via SetPlayerHealth and let the admins know.

Timing Out A Player
the idea I found was posted here
and here's the example script I made.
pawn Code:
OnPlayerConnect(playerid)
{
    new IP[20];
    GetPlayerIp(playerid,IP,sizeof(IP));
    SetPVarString(playerid,"ip",IP);
}
OnPlayerBugged(playerid)
{
    SetPVarInt(playerid,"bugban",1);
    new IP[24];
    GetPlayerIp(playerid,IP,sizeof(IP));
    format(IP,sizeof(IP),"banip %s",IP);
    SendRconCommand(IP);
}
OnPlayerDisconnect(playerid)
{
    if(GetPVarInt(playerid,"bugban") == 1)
    {
        new string[24];
        GetPVarString(playerid,"ip",string,sizeof(string));
        format(string,sizeof(string),"unbanip %s",string);
        SendRconCommand(string);
    }
}
Instead of kicking players for possible cheats I make them timeout, it's less hassle if they are innocent.

Armour Checks
I personally never set my armour to 100 when giving players armour, the maximum I ever give is 99, so if a player has 100 armour then they are most likely 99.9% cheating.
note that if you're using default ammunations then players will be able to buy 100 armour.
Also to add, when a player does buy armour or the script gives them armour, set an armour variables to 1, so the script knows the player has bought armour at least once. If a player has armour and the armour variables is 0 then they are most likely cheating.

Complete Server Side Money
This one is obvious, using only your own variables to increase and decrease player variables and never setting variables from GetPlayerMoney.
I use ResetPlayerMoney and then GivePlayerMoney to show money on their screen.
As well as this my GiveCash function also has a check to see if the player will be getting more money then they have ever got on the server since they connected last, here's an example.
pawn Code:
stock GiveCash(playerid,amount)
{
    ResetPlayerMoney(playerid);//this is just for display purposes
    SetPVarInt(playerid,"cash",GetPVarInt(playerid,"cash") + amount);//add to the variables
    if(GetPVarInt(playerid,"cash") > GetPVarInt(playerid,"maxcash")) SetPVarInt(playerid,"maxcash",GetPVarInt(playerid,"cash"));//if they have a new maximum cash then set it.
    GivePlayerMoney(playerid,GetPVarInt(playerid,"cash"));//again, for display purposes.
}
So in a anticheat cash check, if they have more cash then their max cash then they are most likely 99.9% cheating.
also if their money is greater than their variable but less than their max cash then they might be bugged, I wouldn't bother timing them out since if they're going to cheat they'll probably get themselves banned soon.
Also if your script never allows money to be under $0 then ban them if the players money does dip below.
In sa-mp you cannot go below $0 unless it's scripted or the player used cheats.
EDIT: I forgot about Casinos, if you have casino interiors then players might use the casino features and go in debt.
I know some people wouldn't bother to add this but I have heard from Blacklite that some cheaters made their money go so negative that the variable wrapped around and became a huge number.

Weapon Checking
Under my GiveWeapon stock I set a few variables:
1. they got that weapon.
2. setting the weapon to their weapon slot.
example.
pawn Code:
stock GiveWeapon(playerid,weapon,ammo)
{
    new str[10];
    format(str,sizeof(str),"weap%d",weapon); //format to set the variable
    SetPVarInt(playerid,str,1); //the script now know that the player has had this weapon
    format(str,sizeof(str),"wslot%d",GetWeaponSlot(weapon)); //what weapon is in which slot
    SetPVarInt(playerid,str,weapon);
    GivePlayerWeapon(playerid,weapon,ammo);
}
now in a weapon check in an anticheat, if they spawned an m4 and the PVar weap31 was equal to 0 then they are 98% likely to be cheating, however if they have had that weapon before and the script says they are meant to have an ak47 in that weapon slot, then they might be lagging or bugged and timing them out should fix them.
Note that parachutes will be given by the game to players when you jump out of helicopter or plane high up.
Also note that while entering or exiting a vehicle the server may say they have a weapon which they do not have.

Ammo
I set this up in the GiveWeapon stock, I also add ammo variables of what their ammo should be and what the maximum ammo the script ever gave them is, if they magically get more ammo then the maximum for that weapon then they could be cheating, but I have found a lot of cheaters make their ammo negative, or at least the script reads it as negative, so if you find anyone with ammo less than -1 then they're most likely cheating.
Why less than -1? I'm not sure if the problem was fully fixed but sometimes if GetPlayerWeaponData failed then the ammo would return -1.
You can also use the callback OnPlayerGiveDamage to see if they're shooting someone, and if they are then you can see if they're also losing ammo, if they're not then they may be cheating, however if a player is de-synced then their ammo will not change.

Airbrake & Teleporting
In my SetPlayerPosition hook I have it set a variable saying that the players position is desynced, then it will check if their position is within a small area of where they should be teleported to.
If it is, then set the variable to synced.
If they don't get to the position within 15 seconds (checked in OPU) then they are probably desynced from the server so I'd time them out.

If they go over a certain speed then I'd send a message to the admins to keep an eye on them, timeout or kick them (in case of a false-positives).

Detecting false-positives:
-Jumping off a moving vehicle/object
I ignore their speed while they are surfing on a vehicle and set a variable to say they were recently surfing.
When they stop surfing:
If they are travelling at a reasonable speed, unset the recently surfing variable.
If they are speeding I'll ignore it until they are travelling at a reasonable speed.

-Falling through the map:
I check their Z speed to see if they are falling and set a variable saying that they are, I use to have animation and x & y checks but these proved unreliable and caused false-positives anyway. If they are falling their fall speed shouldn't exceed ~100 units per second.
If they teleport suddenly, and they were just falling then there's a good chance that they fell below the map.

also, here's a handy stock I use, I think from Gabrielle Lucard?
pawn Code:
stock Float:GetDistanceBetweenPoints(Float:rx1,Float:ry1,Float:rz1,Float:rx2,Float:ry2,Float:rz2)
{
    return floatadd(floatadd(floatsqroot(floatpower(floatsub(rx1,rx2),2)),floatsqroot(floatpower(floatsub(ry1,ry2),2))),floatsqroot(floatpower(floatsub(rz1,rz2),2)));
}
For players that teleport by clicking on the map you can save their x and y position when OnPlayerClickMap is called.
Then if your anticheat detects them as teleporting compare their last x and y to the x and y saved from OnPlayerClickMap, if it's within a small enough distance then they've probably cheated to get there.

Added Tips:
Quote:
Originally Posted by playbox12
View Post
It seems that the velocity with airbreak enabled doesn't change. When going in airbreak you use the jogging animation, and your velocity is the same as when you're walking without airbreak (same with running and slow walk). However it does set your position real fast, more than 1 per second. If you toggle the player uncontrollable and he uses airbreak his velocity is 0 but his position will still update.
Quote:

Redirect_Left > You can airbrake at any speed and your velocity is usually still recorded as 0 (technically its usually 5, it occasionally goes very slightly above 0)
Redirect_Left > but using some checks you can see if they're going at a velocity that makes their changed position actually doable at the speed being reported, which for airbrake is always "No"

Animation mods
Animation id 959 is skydiving which is one of the popular cheats, I checked if they were using that id, then if they were I'd check if they were falling and set warnings if they were not, when they got 2 warnings in a row then they'd be banned.
The warnings are because during tests skydiving hitting the ground would trigger the AC due to the animation being skydiving and you wouldn't be detecting as falling because you stop falling when you hit the ground

Another popular one is where they use swimming animation, for this I used the animations ids: 1539, 1538 and 1543
then if they were detected using one of those animations I'd check if they were either speeding, or travelling +5 or -5 on the z axis (because I haven't seen waves (or recorded them) in gta that have a difference of 5 on the z axis).
I'd also use warnings for this, can't remember why though, but I had the warnings set to 3 at 1 second interval checks.

All non gta animations that are synced will return a positive number for GetPlayerAnimationIndex, so a negative return would either mean the animation is not synced (some of the sex animations) or that they were using mods.

Paused Players
Blacklite taught me that players that are paused don't send OnPlayerUpdate, so under OnPlayerUpdate I have it delete a PVar, and I run a timer to increase that PVar, if the PVar rises over x then they have been paused for y.

Rejoin/Flooder Check
Players Rejoining within 20 seconds after a kick or a quit, these players are most likely cheaters and very troublesome. You can create a simple check to see if a player rejoins after a Kick or Quit, timeouts usually rejoin within 30seconds so only check for Kicks or Quits.
I save the last x ips and time they left and check under OnPlayerConnect to see when they quit/were kicked last.
For flooders I check under OnPlayerConnect the last x ips and join times, it's pretty similar to the rejoiners however all the script is under OnPlayerConnect.

Sync System
A thing I've been keeping a secret for a while is a sync system to check that a player is syncing right, it takes the method of the health checking system and applies it to armour, ammo and position ect.
here's an example of how it works with armour.
variables:
1. what their armour should be (armourShouldBe)
2. what their last updated armour was (lastArmourChecked)
3. is the player's armour synced (armourSynced)
4. the armour on the check (currentArmour)

every time you set a players armour, set armourShouldBe to the new value and set armourSynced to 0 (false)
then every x you check the player's armour, if the armourSynced is set to 0 then check if currentArmour is the same as armourShouldBe, if it is then set armourSynced to 1.

if armourSynced is set to 1 then check currentArmour to lastArmourChecked, if currentArmour is larger than lastArmourChecked they used a non scripted way to get armour, if its less set lastArmourChecked to currentArmour.

Break down into steps:
1. SetPlayerArmour sets armourShouldBe to the new value, sets armourSynced to 0
2. Your AC check goes off and stores their current armour as currentArmour
3a. If armourSynced is 0 check if currentArmour is the same as armourShouldBe, if it is then set armourSynced to 1
3b. If armourSynced is set to 1 then check currentArmour against lastArmourChecked, if currentArmour is less than lastArmourChecked then set lastArmourChecked to currentArmour.
If currentArmour is larger than lastArmourChecked then flag the player for a possible cheater

script:
I've changed variable names and inserted a lot of comments to make it more clearer, so sorry if I've made a mistake
pawn Code:
//I had mine set up as an include for every script to use, then I could use SetPlayerHealth in any script without worrying about the AC, all I had to do was #include <anticheat>
//so this is inside the include, it's a hook for SetPlayerHealth
stock AC_SetPlayerHealth(playerid,Float:amount)
{
    if(amount > 99.0) amount = 99.0;
    if(amount < 0.0) amount = 0.0;
   
    DeletePVar(playerid,"healthSynched");
    SetPVarFloat(playerid,"healthShouldBe",amount);//what the player's health SHOULD be in the future
    return SetPlayerHealth(playerid,amount);
}

#if defined _ALS_SetPlayerHealth
    #undef SetPlayerHealth
#else
    #define _ALS_SetPlayerHealth
#endif
#define SetPlayerHealth AC_SetPlayerHealth
pawn Code:
public OnPlayerUpdate(playerid)
{
    if(GetPVarInt(playerid,"banned")) return 1;//no need to accept any more updates, I had a 1000ms timer from the time they were banned to the time they were kicked from the server so they got any messages I sent them
    if(GetPVarInt(playerid,"specid") != -1) return 1;//for admins, otherwise it'd trigger speed AC
    if(GetPVarInt(playerid,"dead")) return 0;//I had server side health and damage from other players using OnPlayerGiveDamage, players that had "dead" set to 1 could not harm others with attacks

    new time = gettime();
    SetPVarInt(playerid,"ACUpdated",time);//so you can use in another script to display the players last update, incase someone was pausing or having inconsistant updates

    if(lastHealthUpdate[playerid] < time)//to make sure it would only check once per second max
    {
        //1 second intervals
        lastHealthUpdate[playerid] = time;

        new Float:currentHealth;
        GetPlayerHealth(playerid,currentHealth);//gets the players current health as last reported to the server

        new currentHealthInt = floatround(currentHealth,floatround_round);//gets the current health as an integer, they are easier to work with

        new healthShouldBeInt = floatround(GetPVarFloat(playerid,"healthShouldBe"),floatround_round);
        SetPVarFloat(playerid,"currentHealth",currentHealth);//what the players current health is, I used this to show in admin information on players

        if(currentHealthInt == healthShouldBeInt) SetPVarInt(playerid,"healthSynched",1); //if their health is synced

        if(!GetPVarInt(playerid,"healthSynched"))//health is not synched
        {
            if(currentHealthInt > healthShouldBeInt)//health is greater than what it should be
            {
                healthUpdateFail{playerid}++;//increase a variable to count to x
                switch(healthUpdateFail{playerid})//depending on how long it's been, do something
                {
                    case 30, 45:
                    {
                        MessageAdminsEx("%d %n Health Desynced For %ds Attempting To Resync %d/%d",playerid,playerid,healthUpdateFail{playerid},currentHealthInt,healthShouldBeInt);//warn the admins about players health being desynched, this is a custom function, don't complain when it doesn't work for you
                        SetPlayerHealth(playerid,GetPVarFloat(playerid,"healthShouldBe"));//try to set the players health to what it should be
                    }
                    case 60:
                    {
                        TimeOut(playerid,"Health Desynced For Over 1min");//if they don't resynch their health for x then they probably won't ever, just make them rejoin
                        return 1;
                    }
                }
            }
        }
        else //health IS synched
        {
            healthUpdateFail{playerid} = 0;//reset the variable as they are now synched
            if(healthShouldBeInt > currentHealthInt)// if their health has dropped and they are synched
            {
                SetPVarFloat(playerid,"healthShouldBe",currentHealth); //drop the variable to their current health
            }
            if(currentHealthInt > healthShouldBeInt && currentHealthInt <= 100 && currentHealthInt  > 0)//if health is in sane limits, and it's gotten higher somehow, set it to what it should be
            {
                SetPlayerHealth(playerid,GetPVarFloat(playerid,"healthShouldBe"));
                /*I found that even with these checks you still cannot be 99% certain that they were cheating,
                so I set their health to what it should be.
                If they are cheating and they keep setting their health to high amounts then they'd get kicked anyway*/

            }
            //if their health is above 100 or below 0 bans
            if(currentHealthInt > 100 || currentHealthInt < 0)
            {
                BanPlayerEx(playerid,BanAC,"Invalid Health: %f",currentHealth);//another custom function, I found anyone with health higher than 100 or less than 0 to be a cheater
                return 1;
            }
        }
    }
}
I use the sync system for health, armour, weapons, ammo, vehicleids, vehicle health, position, vehicle position

Checking if a player is AFK or not can also help
http://forum.sa-mp.com/showpost.php?...8&postcount=43

For an example implementation
http://forum.sa-mp.com/showpost.php?...6&postcount=46

Vehicle Health
I have vehicle health saved to a variable frequently to check health increases or decreases and update the variables.
If a vehicles health has increased I check if they are near a pay'n'spray with a low speed or they are in one of the transfender interiors, which you can check with OnEnterExitModShop or a simple GetPlayerInterior

remote-jacking (also detects people controlling remote cars issue)
https://sampforum.blast.hk/showthread.php?tid=259745

How To Use OPU In An AC
the following script has checks to optimize the ACs OPU, so that it doesn't check banned players, doesn't do more than one check per update and has time limits between last checks
pawn Code:
public OnPlayerUpdate(playerid)
{
    //don't need to keep checking if they are banned
    //they may send some more updates while they are being kicked
    if(GetPVarInt(playerid,"banned")) return 1;

    new time = gettime();
    //check number 1
    if(GetPVarInt(playerid,"LastCheck1") < time)
    {
        //1 second intervals
        SetPVarInt(playerid,"LastCheck1",time);
        //blah blah checks
        return 1;//so it does 1 check max per OPU
    }
    if(GetPVarInt(playerid,"LastCheck2") < time)
    {
        //3 second intervals
        SetPVarInt(playerid,"LastCheck2",time + 2);
        //blah blah checks
        return 1;//so it does 1 check max per OPU
    }
    if(GetPVarInt(playerid,"LastSpeedCheck") < time)
    {
        //the following checks that they updated last second too,
        //if not then they might be lagging or coming back from pausing
        if(GetPVarInt(playerid,"LastSpeedCheck") + 1 == time)
        {
            //blah blah checks
        }
        //1 second intervals
        SetPVarInt(playerid,"LastSpeedCheck",time);
        return 1;//so it does 1 check max per OPU
    }
    return 1;
}
notes:
*It's recommended to not use default menus for shops, this way you can control everything the player buys, this covers money, health, armour and weapons.
*AddStaticPickup won't call OnPlayerPickUpPickup and might cause some false positives, it's recommended to script pickups using CreatePickup and OnPlayerPickUpPickup.

Please add any more you have.
Reply
#2

Great work Cessil, this is awesome. Found out some better methods of doing stuff, especially the server side money tricks. After only checking if they have more money then their max money I haven't had a fault yet.
Reply
#3

serverside money thanks man good job
Reply
#4

my anticheat tutorial was done awhile ago and since then I have figured out smarter and accurate ways of detecting cheats.
Reply
#5

Another tip I think you should include.

Airbreak:
Using the MapAndreas plugin by Kalcor, you can check the player's z height compared to the z height of the land and tell if he is airbreaking or not. It's a simple way and effective way to detect airbreaking, provided you also check that the player is not in a flying vehicle(heli, plane).
Reply
#6

nice this can be really useful to the newbies out there instead of they making threads.
Reply
#7

I haven't done much to combat airbrakers because I don't have the tools and I won't get them either, but from what I can tell they have the falling animation and they're going upwards, or they stay at the same z level and move on the x and y, I'd need someone to verify they work like that though.
Reply
#8

Thanks for the tips. Thought of one thing that wasn't mentioned could be quite important. The health/armour (%99) antihacks would be bugged if a player either gets armour from ammu, or buys drinks from vending machines. So you would need to block (or range check) all the vending machines/bugershot ect, and maybe DisableInteriorEnterExits too. Should be common knowledge, i know but some might not think of that.

Nice tips btw.
Reply
#9

thanks, iggy I added more on the health, armour and money. I'll make it look pretty tomorrow
Reply
#10

Quote:
Originally Posted by cessil
View Post
In sa-mp you cannot go below $0 unless it's scripted or the player used cheats.
Casinos?
Reply
#11

thanks y_less and vince, I've updated it
Reply
#12

This, sir, is genious.
Reply
#13

Anti god mode:

get player health and store it to X variable
decrease player variable X and decrease player health
Check is player health same or lover than in variable X ,if player healths are same or lower than player is clean else he has good mod
if player is clean increase player health variable (X) and increase player health for same amount you decreased it

And about airbreak there is some FS but its check player velocity and if its rely high then its airbreak
Reply
#14

Quote:
Originally Posted by DRIFT_HUNTER
View Post
Anti god mode:

get player health and store it to X variable
decrease player variable X and decrease player health
Check is player health same or lover than in variable X ,if player healths are same or lower than player is clean else he has good mod
I described this already, since players spawn with 100 health by default, use SetPlayerHealth to 99, then you keep checking to see if the health has dropped to 99, if it hasn't then they are probably bugged

Quote:
Originally Posted by DRIFT_HUNTER
View Post
And about airbreak there is some FS but its check player velocity and if its rely high then its airbreak
I already went into this, but with teleporting which would pick up what velocity might not, I believe velocity is based on how fast the player is moving and not if they are teleporting, correct me if I'm wrong.
Reply
#15

Nice, i like the health hacks option
Reply
#16

I hate that good things like this is getting posted, so the cheat mod developers can see it, then find a way to not get detected.

Therefor, I like the good old eye.
Reply
#17

Quote:
Originally Posted by [oG]Smitherz
View Post
I hate that good things like this is getting posted, so the cheat mod developers can see it, then find a way to not get detected.

Therefor, I like the good old eye.
I hate that people like you bump topics from months ago.
Reply
#18

How to download this anti-cheat ??
Reply
#19

They're tips not a system. So download the tips and compile one of your own.
For Armour: You could check if the player is not at the position of the checkpoints in the Ammunation (considering virtual worlds and interiors) and their armour goes to 100.0, then ban them - This could work but might fail in one in ever 1,000,000 players in all sa-mp servers.
Reply
#20

Quote:
Originally Posted by Tee
View Post
They're tips not a system. So download the tips and compile one of your own.
For Armour: You could check if the player is not at the position of the checkpoints in the Ammunation (considering virtual worlds and interiors) and their armour goes to 100.0, then ban them - This could work but might fail in one in ever 1,000,000 players in all sa-mp servers.
For armor...the best way is probably just creating your own ammunation menu/dialog...that way you can control that sort of thing...same with HP and stuff(though with HP machines you can probably check their animation if they're in a certain position instead of removing every sprunk machine/healer)


With timing out a player, I'm not sure if it was fixed in 0.3d however you use to be able to do something like...

pawn Code:
GameTextForPlayer(playerid, ~ryeah, 1000, 0);
If that's fixed in 0.3d disregard it..

You also use to be able to use invalid Object IDs & weather IDs however i'm not sure if the objects one was fixed...the weather one i believe is dependent on the time too
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)