Client Anti Cheats: Aren't as bad as you think!

just use fireclient then respond with the arg encrypted or decrypted then verify on server

1 Like

I am twenty, and most people have a hobby to spend their time on haha

3 Likes

so you have been coding since you were 7? :sob:

Yeah, some people start learning pretty early. I started with Scratch when I was 6 :upside_down_face:

1 Like

But won’t exploiters just be able to read your localscript with the encryption and be able to submit to the handshake with their own scripting and stealing your own custom encryption?

You could use the env hide documented in the post and that won’t let exploiters decompile it.

Sounds a bit too good to be true. If it is true what you are saying, then this is huge. Although I’m still very skeptical. Even if you are wrong, this is still a very effective way to stop 99% of skids which imo is the point of a client-side anti-cheat(stopping people who can’t actually code). Even if it does get bypassed, I can just slightly change my encryption key/method to stop all the skids for a bit of time each update.

I am not wrong, this method is used by many big anticheats and in many games (however a bit modified).

Its the most effective method to hide the anticheat, they literally cannot reference it so they can’t decompile, destroy, or disable it.

Thank you for sharing this!
I’ve never made an anticheat and have heard to never trust player clients, but I think that handshakes and environmental hide are very smart!!

I am a bit confused about both getfenv and setfenv, if you have time could you please explain them (especially because they are deprecated, are there newer alternatives)??

1 Like

No there aren’t, debug.info is considered as the “alternative” for getfenv, however, it won’t work for what we are doing here.

2 Likes

i have a funny idea

local locations = game:GetChildren()
local count = #locations
script.Parent = locations(math.random(1, count))

replace GetChildren with GetDescendants :))

1 Like

Combined with hiding the script, random name (purely random like even random letters mixed with numbers),

-- Was the hiding thing smth like this i forgot
getfenv().script.Destroy
getfenv().script = nil

-- Me too lazy to make random letters
script.Name = tostring(math.random(0,99999999))

-- Random Parenting (If you don't wnna use hide env method thing)
local locations = game:GetDecendants()
script.Parent = locations[math.random(1, #locations)]

-- Then your actual anti cheat

RIP High-level exploits
You can only delete script if you have direct access to low level memory, but where in memory lol it would change alot

I’m no pro at anti cheat scripts, cuz my games have 0 hackers yet (max ccu : 10 if I invite)

Dont forgot to place this line of code in ur local scripts without the hide env thing :skull: (only if um other scripts don’t require modules inside the script)

Edit :

-- Serverscript
if Detected then
	Player:Kick('So you really thought you can cheat huh? (insert an essay for why not to cheat here)')
end

This would annoy exploiters but they can still hook the function (unless they need the script to hook first)

This is cool but why not have the owner just manually join the server the exploiter is in and tell them to stop? Before being told back that their game is trash simulator and that’s the first reason they exploited

I mean, exploiters are people too (unless they aren’t, idk much about Roblox) so the reason they might feel the cheat is because the ‘game’ is just unfair and has too many microtransactions and not good game design and piss poor anti-cheat (or lack there of)

Sorry, i rambled ain’t i? Anyway, cool anti-cheat. I think this combined with some server-side validation and you shouldn’t deal with any cheaters

1 Like

In my games, if your cheating means you can’t complete the basic driving tutorial :skull:
(it’s a train game)


Since when we have people with 1 iq to install a possible virus in their computer,


“unless they aren’t”

We ain’t living in 2099


Hook?? ight.

getfenv().script.Destroy
getfenv().script = nil

script.Name = tostring(math.random(0,99999999))

-- Why not :O
for i=0,math.random(10,100) do
	local s = script:Clone()
	s.Name = tostring(math.random(0,99999999))
	-- I messed up this should be after local locations var
	s.Parent = locations[1,#locations]
end

local locations = {
	game.Players,
	game.ReplicatedStorage,
	game.ReplicatedFirst,
	...
	-- just enter print(game:GetDecendants()) in command bar and copy result
}
script.Parent = locations[math.random(1, #locations)]

wait what I made discovery i think

Make the original anticheat script
in its logic, duplicate it x times, and if it detects any of its duplicate being destroyed, PoorExploiter:Kick()

This will not work, after doing the getfenv().script = nil you will not be able to use the script global.

The environment hide is enough, and you do not need to parent it anywhere else or rename it; as they can’t even get a reference to that script!

4 Likes
local Player = game:GetService("Players").LocalPlayer

local Old; Old = hookmetamethod(game, "__namecall", newcclosure(function(Self, ...)
   if Self == Player and getnamecallmethod():sub(1, 4) == "Kick" then
     return task.wait(9e9)
   end

  return Old(Self, ...)
end))

this would bypass kicking the player from the client entirely, although this sort of hook can be bypassed via just using Player.Kick(Player) instead ( I do not recommend cause that can be hooked aswell ). The best thing to secure your client anti-cheat right now is simply run it under an actor. ( scripts under an actor run on a seperate LuaVM so any hook the exploiter places won’t affect your script )

You could bypass this hook by doing player:kick(), or you could detect this hook all together by running :Kick() in a pcall and seeing if its successful or not (it will error if delayed)

or just fire a remote to the server to kick (like all other anticheats do)

Also hookable lol, I bypassed my friends anti-cheat by hooking the remote then deleting the AC script, of course he couldn’t patch this, so we decided that we would try to make better AC methods, but we never ended up finding a fix.

Heres an example for name-changing remotes.

-- remote name changer detection

local changesToREMnames = {}
local maxChanges = 10

for i, v in pairs(game.ReplicatedStorage:GetDescendants()) do
   if v:IsA("RemoteEvent") then
      rconsoleprint("ADDING: "..v.Name.." TO REMOTE CHANGE LIST") -- so we dont get detected
      changesToREMnames[v.Name] = 0
      v.Changed:Connect(function(a) 
         if a == "Name" then
            changesToREMnames[v.Name] += 1
         end
         if changesToREMnames[v.Name] == 10 then
            rconsoleprint("Anti-Cheat Remote Detected")
            hookfunction(v.FireServer, function(...)
               return
            end)
         end
      end)
   end
end)

-- find anti-cheat script, etc. (use same method if name changes)

Of course, I won’t test it because its cheats, but thats basically how you do it. To my knowledge there are no ways to detect hookfunction.

An simple handshake will easily detect this.