Advice on anti cheat idea

So I know that making anti-cheats for the client is a foolhardy idea, since exploiters have absolute control over their clients. Exploiters can stop any remote event and any client script from executing. That said, they cant just stop all remotes, and they cant just delete all the scripts. They need all that stuff to play the game. Therefore, it stands to reason that they can only delete a script or stop a remote if they know what to look for.

The idea is this:

  • create a screengui object with a randomized name, with a localscript inside of it with another randomized name (things like ammoCounter, canInspect, jumpDisplay) that would be unassuming when inspected. A remoteEvent is also created in replicated storage, neatly nested where all the other remotes should be. This remote is also given a randomized name, and this randomized name is passed to the script which is being sent to the client. The script searches for any evidence of exploits, and then fires “true” through the remote if it finds anything.

Recognized flaws with this idea:

  • cheaters could still find a way to bypass this
  • cheats that operate outside of the roblox client exist

The point of the idea is not to be an absolute guard against cheaters, no anticheat is afterall. The purpose of this is to flag their account as soon as possible, then ban them before they have any opportunity to react. Most other forms of anticheat are prone to false flagging, but this form of anticheat is capable of certainty due to us developers knowing exactly what should or shouldnt exist on the client.

What do you guys think, would this actually catch anybody? is it worth doing? Even if it only catches 25% of exploiters, i still think it would be worthwhile

1 Like

all client anticheats are bypassable but that doesnt mean you cant try. a simple and effective way is just to have a “givemoney” remoteevent that bans you if you fire it :joy:

4 Likes

oh thats way simpler and genius, i should add that

put a sign up somewhere near spawn that says “no hack” and it will usually ward off 100% of potential hackers

1 Like

I get this isn’t supposed to be 100% undetectable, but you can definitely make some improvements to this system.

1 - Don’t use a remote. Instead of trying to tell the server, just don’t. Have a crash method within your local script instead, it is much more reliable. You could try with both, but obviously it’s hard to secure such a remote and it seems redundant.

An experienced exploiter will observe at first and just look for patterns in your anticheat, and they will most likely stumble across the gui and the remote and quickly realise what they are for.

So:
2 - Don’t use a “perfectly normal” gui. You can use the gc trick to try and hide the script as best as possible - destroy the script and set its script global to nil (only works for Script with RunContext of Client). This causes the associated userdata to be garbage collected hence making the script instance itself invisible to getnilinstances, getcallingscript, and others like that. Obviously an exploiter can just run before ReplicatedFirst, or else use RBX::Instance::PushInstance from the C++ side to access it, but it is much more long winded and unlikely.

Within this script:
3 - Do not rely on connections (getconnections, connection.Disable, etc.), and if you want to go really in-depth, use closure techniques to try and mask your upvalues (I wouldn’t recommend this though).

I wouldn’t go too in-depth on this, especially since you’re aiming to catch amateur exploiters with this. Most script kiddies wouldn’t just be messing around, they would probably copy and paste a script, and if that script is written badly, then they’re basically done for.

These are a few basic techniques, there are others like timing checks and hook vulnerabilities which can be used too, but I hope this helps.

4 Likes

if only that ever worked😭

i wish it did work

Putting “Cheating is bannable!” in the experience description would scare away ~0.1% of skids. It’s better than nothing!

Im gonna take this a step further. I wont tell the cheater that i banned them for taking bait. Instead, im going to make the event actually DO what it says it does, so that the cheater thinks that it worked. Then 20-30 seconds later (random interval just to be sure) I will ban them with a message saying “Fly/Teleport Exploit Detected” so that they think they got banned for flying instead of taking the bait

1 Like

Why would i want to crash them instead of send a remote? Wouldnt i miss the opportunity to ban them if i did that?

cuz the code doesn’t fully stop If you just kick them the script keeps running even after they been kicked from the game If you want it to actually stop the code

1 Like

also, like this?

script.Parent = nil
script:Destroy()

--code here

What Suvry1 said, and also that they can very easily intercept that remote no matter how you hide it.

One more line:

--getfenv to deoptimise the script bytecode 
script.Parent = nil
getfenv().script:Destroy()
getfenv().script = nil

--code here

so, for example, lets say I have a remote that fires very regularly. It fires a camera CFrame to the server, allowing the server to tilt your character towards the camera direction for a “Looking” animation. The purpose of this remote is for a cosmetic effect, which is completely unrelated to anticheats. Then, when this script here detects something suspicious, it just sends another remote along the stream, tacking one more parameter to the end. The client would send cframe, cframe, cframe every update. Then when something suspicious happens, it sends cframe, cframe, cframe, cframe, cframe + true, cframe, cframe, etc etc. You are saying this can be easily intercepted?

maybe instead, we could change a replicated property that the server doesnt use in any of its code, like enabling platformstand on the character’s humanoid if the game doesnt normally use the platformstand property.

Also, hypothetically, lets say they do intercept it. Does this affect my ability to crash them immediately after sending the remote? Am I jeopardizing my ability to punish them after detection if i send a remote beforehand?

Yes, quite easily.

local expected = x --where x is the number of normal parameters

local old; old = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
    --checks if its the remote...
    local params = {...}
    if (#params ~= expected) then
        --detected.
    end
    return old(self, ...)
end))

That code above will detect the abnormal number of parameters alone.

Potentially, but it’s not as much of a risk. By firing the remote and giving them that path, you indirectly give them direct control of your script thread which they could quite easily manipulate (e.g. yield). For client anticheats, instead of trying to tell the server through a remote, it’s just safer to crash the client (not kick).

1 Like

This is a safer option even if its still interceptable. Just remember anything you do can be bypassed if someone is dedicated enough to it, and just proceed with mild caution.

2 Likes

All this said and done, I was playing around with scripts for a little while trying to find a way to identify injected scripts. I was originally going to connect a DescendantAdded event to all of the containers where localscripts can execute (playerscripts, replicatedfirst, etc) and then compare them against the scripts in StarterPlayerScripts which are expected to be there. The issue is, you cant access the source of a script in another script. Since i have no way to do this (Roblox doesnt even give scripts a UUID or something to represent the contents) I have no way to detect a foreign script and thus this may all be pointless.

Roblox also doesnt let us access CoreGui, they couldnt even just make it readonly. Due to these limitations, I dont know if there’s any way to actually do anything about instances injected into the client.

A lot of exploits will also just create a scriptless thread, essentially one without an associated script container, or they will just hide the script as you mentioned.

Look for the effects of the exploits rather than the cause, I would say.

1 Like

Ah. If im just looking for effects, then is there any point in searching from the client? I suppose i could look for things like illegal walkspeed, or highlight objects and billboards which would be created by ESP. The only issue though is that i would have no way to discern whether a highlight/billboard was created by the game or by the exploiter

One thing I could do is have a unique and randomized string on the server that gets passed to this client script, then the script would flag any highlight or billboard GUI which doesnt have this string set as an attribute. It would be a decent way to catch highlights as highlights have to be parented to the thing they are highlighting, billboards might be a bit trickier though since the exploiter could just parent them to coregui and then adorn them to the characters in the game. Another issue as well is that highlights/billboards created by the client would have no way to access this unique string, and thus would have no way of making themselves exempt. Lastly, if an exploiter knew about this system beforehand, they could just grab the unique string from highlights that the server creates, then apply that string to anything new that they create.

By effects, I more meant just not trying to find the script itself, just abnormalities it creates, which can range a lot from what you mentioned to smaller things too. For example, some exploits may incorrectly implement hooks, or their injection might leave abnormalities in behaviour which you can look for. These are executor-specific. There are other checks, ranging from weak table attacks (seeing if an instance that should not be referenced is referenced), through to character checks. Feel free to basically check anything that isn’t you looking for the script itself - they are far too easy to hide.