How are half-decent anti-cheats made?

I’ve recently been trying to delve into the realm of Anti-Cheats as I am currently developing a game that, frankly, I don’t want skids running around killing everybody at the click of a button. From what I’ve heard, it’s an extremely complicated process full of Memory/Client Checks and a whole lot of other stuff; and it sounds like a very complicated and tedious process.

12 Likes

You don’t. Most anti cheats are scams, or jokes made by exploiters to derail threads about them. The ones that do work are made by specifically for one type of gameplay, and made by the developer of the place.

2 Likes

That’s a fair point, but what about stuff like Crystal Anticheat? Or Adonis’ built in anti remote spy? They both have worked wonders for me and have stumped a lot of pen tester’s/exploiters whenever they try to abuse a remote.

1 Like

Can you give some examples of how they have worked for you?

2 Likes

A couple months back I had some friends of mine test out Adonis’ Anti-Cheat and see what worked and what didn’t. From the experience I had, whenever they ran Synapse’s Remote Spy, Adonis instantly picked it up and kicked them from the game. Crystal Anticheat also prevented a Dex SaveInstance somehow (I think it was monitoring the players FPS and Memory and seeing whether or not the FPS crashed and the Client memory spiked.) That’s the best I’ve seen so far.

3 Likes

Not a very experienced developer, but I think there’s 1 universal thing for creating anti-exploits that all Developers would do:

  • Never use local scripts to detect whether a player is using cheats (or at least, don’t have just 1 LocalScript running as the anti-cheat).

It’s best if you try not to rely too much on Community Resources, since they’re open-source, meaning any Exploiter can always find a way to bypass it, and there’s not really such a thing as a “1 size fit all” anti-cheat.

On planning to create your own anti-exploits for your own games, all I have to say is - Good luck on your scripting! :melting_face:

9 Likes

Thank you! I learned the hard way about not using Local Scripts for really anything that can be done on the server, and let’s just say, it was very problematic; but I will definitely try and figure something out.

2 Likes

Actually, using local scripts to detect exploiters is the best thing you can do.
Server allows you for simple movement/ray cast checks which additionally may generate false positives due to lags.

A half-decent anticheat would use obfuscated local scripts to detect value changes, listen for suspicious objects inserted into the game etc. to then send encrypted data about the detections to the server which would handle the verification of this data.
A good anticheat would additionally implement non-public methods to detect things like metamethod hooks, GUIs, saveinstance etc.

2 Likes

I was thinking about implementing 2 local scripts that run all the client checks but also constantly check to see if one of them get’s disabled/deleted. Wouldn’t that work? I think I’ve seen other games that do this, but on a much larger scale (5-6 local scripts in various locations)

2 Likes

Using LocalScripts is fine its another layer of defence for your game

1 Like

I believe the key thing about anti cheats is you should only bother if exploiting is actually an issue on your game.

Ofcourse you should be sure that your remotes are secure, and if that’s the case the only thing they can do is local exploits: flying, faster running, etc.

Depending on your game this probably isn’t that game breaking.

1 Like

Yeah, you can do it but you should keep in mind it can still be disabled quite easily by a more experienced scripter.
For example, if you used Connections to detect the deletion of scripts (.Removing), then they could disable these connections.
If you used FindFirstChild in a loop in these scripts to detect the deletion, they could make a simple function hook so that FindFirstChild will always return true for certain arguments.

Way better method is mentioned earlier verification of local data.
You fire a remote each second and send the encrypted client data.
Then, you verify it on the server, and if the data hasn’t been sent for longer than 10 - 15 seconds, you can kick the player, because either they’re having heavy connection issues or they removed the script responsible for sending the data.

To keep your game safe from exploiters, frequent updates of the detection methods as well as encryption methods are recommended.

1 Like

As of right now, I have the server generate a random string (key) that is only sent to the client one time, that one time being when the player joins the game. Anytime the client fires a remote event/function, the key must be included. If a remote is fired and no key is sent, it kicks the player and logs their information to a discord server for further investigation.

The pros of this:

  1. The key is only obtained one time and cannot be obtained again.
  2. The key is different for each player
  3. Prevents remote abuse (I think)

The cons:

  1. If a player obtains their key through a remotespy script then the player can fire any remote they want.
  2. False detections may be common if a key cannot be generated or a remote event is fired before obtaining a key.

As for the script deletion, I have each local script loop a FindFirstChild event to verify that the script exists and isn’t disabled. I have a couple of other ideas for verifying the integrity of each local script, but I don’t know if they would work, nor do I know if they’re secure/working methods of checking.

Verifying client data every second could be a good idea, however Synapse comes with a built in remotespy script that could catch that encrypted data, which would allow them to manufacture fake client verifications meaning they could just delete the client checks without any repercussions. Although I do believe that remotespy is a fairly easy script to detect.

I think my best bet in the mean time is to go with the verification of client data because even though I explained how an exploiter could easily bypass it, I think I can still find a way to disallow them from doing so.

1 Like

I’m going to parody a saying used by DevForum members: “Never trust the client.”

So here’s what I’m going to say: “Never trust DevForum members.” This might come off as rude, but most of the time, they don’t know what they are doing and are just trying to act smart. I would bet that half of them have never even tried to make an anti-cheat and are simply using some knowledge they found out of ChatGPT to act smart without looking at any other sources.

Using memory checks would work, but they are very unreliable and shouldn’t be used in larger games.

This is easily detected by using LogService.MessageOut since Synapse Remote Spy prints all events into the console. However, Synapse now has an “internal GUI” which allows for output redirection, bypassing this.

This is a stupid idea. A lot of DevForum members, for some reason, lean towards it. Alternatively, what you could do is use a RemoteEvent. Every few seconds, fire the event to the server. If the server notices that the client didn’t fire the RemoteEvent after a few seconds, the LocalScript has been disabled or deleted, and you can take further action.

Check the above.

2 Likes

The key method you used is pointless, all they have to do is simply listen for remotes fired and get the key from there.

The verification method is the best method you can use and attempting to develop something new is obviously a good thing to do which improves your skills as a developer, but when you don’t have full knowledge about the subject, it’s usually better to follow known patterns.

The encrypted data is obviously dynamic, it’s different each time.
For example, in the anticheat solution I’ve developed, I’m using functions like GetServerTime, then put them encrypted into the verification string.
Then, this data is decrypted on the server and converted into a table so that the data can be easily read.
This forces the exploiter to reverse engineer the whole verification and encryption algorithm which is exceptionally hard due to solid obfuscation.
This makes the exploiters abandon the idea of cracking the verification script, and rather focus on bypassing the checks themselves.