Exploiters and how they spoof stuff in your own game

I’ve recently started noticing that people on the devforum are unaware of the true power exploits have and in this tutorial i wanna educate you on how powerful they really are.

So let’s start from a recent post i saw about walkspeed. People were doing walkspeed checks by just doing like:

if Humanoid.WalkSpeed>16 then
	LocalPlayer:Kick("Cheater")
end

Now there are 3 problems with this script. Let’s start with the easiest one:

The exploiter could delete the script - this is true but if you hide this deep in one of your casual scripts, they can’t delete it without breaking anything else.

Now this is where it gets complicated:

The exploiter could spoof the WalkSpeed - Many developers are unaware of spoofing with exploits. So i’m gonna explain it right now.

The exploiter has access to the games metatable. Now with that, you can actually spoof many returns. The exploiter could set the WalkSpeed to 20 but when a script indexes it, it will return 16. Here’s how they do it:

local mt = getrawmetatable(game) -- This gets the game's metatable
local oldindex = mt.__index -- This saves what it does normally when you index a property
setreadonly(mt,false) -- makes it so you can edit the games metatable

mt.__index = function(indexed,property) -- detects if a part is indexed (Referring to Humanoid.WalkSpeed)
	if indexed == "Humanoid" and property == "WalkSpeed" then -- checks if the part indexed (Humanoid) is a humanoid and checks if the property is walkspeed
		return 16 -- returns a fake value of 16
	end
	return oldindex(indexed,property) -- if the indexed isnt humanoid and the property isnt walkspeed then do what it does normally
end

setreadonly(mt,true) -- locks the metatable again

Now what the exploiter could do is just set the walkspeed to whatever, and it will always return 16. Now this is always gonna be like this and sadly with the tools roblox gives us you can’t detect this.

Okay fine ill use a velocity check and then do LocalPlayer:Kick() - Now this is another mistake people do, kicking on the client. As i just showed you, you can spoof anything really. That happens to also include calling functions on parts.

Here’s a simple antikick you can make within a minute:

local mt = getrawmetatable(game) -- This gets the game's metatable
local oldnc = mt.__namecall -- This saves what it does normally when you call a part's function
setreadonly(mt,false) -- makes it so you can edit the games metatable

local LocalPlayer = game:GetService("Players").LocalPlayer

mt.__namecall = function(self,...) -- detects if a part's function is called
	local method = getnamecallmethod() -- gets the method that's called (Like :Kick or :FindFirstChild)
	if method == "Kick" and self == LocalPlayer then -- checks if the function called is :Kick and its called on LocalPlayer (so it detects if its LocalPlayer:Kick())
		return -- this will just return and do nothing (making it so the player actually doesn't get kicked)
	end
	return oldnc(self,...) -- if it isnt kicking the localplayer then it does what it casually does
end

setreadonly(mt,true) -- locks the metatable again

Now do you see how easy it is for a cheater to spoof anything?

There’s also upvalues but that’s a bit more complicated and i’m not gonna talk about it in this thread.

Conclusion:
Client-Sided anticheat is unreliable, i suggest not wasting time on one, a decent cheater can bypass it within minutes.

118 Likes

Wouldn’t sever sided checks work fine? Sure it won’t be as fine grained, but they can’t modify how we handle kicks on the sever or velocity checks

3 Likes

They would totally but they wouldn’t be as accurate due to the amount of serverlag it would cause to run a check every heartbeat. Also do distance checks, velocity checks are unreliable and exploiters can replicate velocity by just moving the player forward every heartbeat by studspersecond/30

5 Likes

The 2nd script you provided can be detected by checking:

local succ = pcall(function()
	print(game.WalkSpeed)
end)

if succ then
--Kick player
end

Most exploiters who are competent won’t do metatable hooking like that.

6 Likes

You’re missing out on the main gist of the post. This is not to tutor you on how to exploit, but to explain why client-side anti-exploits are mostly unreliable.

7 Likes

Nothing wrong with suggesting a realistic example, OP even said:

which is untrue, there are multiple ways to detect that:

  1. Since they’re hooking game, check if they index game.WalkSpeed
  2. Even if the exploiter did it properly and hooked the Humanoid, you could set the Humanoid’s WalkSpeed to something random, index it, and see if it constantly returns 16.
7 Likes

There’s still ways around your method though. The point of the post is to let people know that “Hey, be careful when making client-sided stuff”, not to just keep patching stuff and keep fighting the cheaters forever, because its just tiring and they’re always gonna win. Unless you make your anticheat serversided.

6 Likes

Yes, and I’m not saying I don’t agree with you. Client side detection will always be bypassed, but I’m just saying the examples you provided can be detected, and someone who is a skid won’t understand how to get around it.

4 Likes

Good point, a realistic example would’ve been great

Doesn’t distance checks can give out false positives sometimes?

That’s why you lag them back, instead of banning them, banning cheaters won’t work anyway due to the amount of alts they have.

5 Likes

You’re right - only exploiters who are competent will make a script like that… and then they will upload a script like that to a forum… and then any exploiters can use a script like that.

The ideology that only a few exploiters will be able to do X because it’s complicated (e.g. metatable hooking) is severely flawed because all it takes is one competent exploiter to distribute the script to whoever they want and then anyone can do it.

8 Likes

Yeah, don’t trust the client ever is the moral of the story. Assume the data has been modified, especially if it’d be of interest to a hacker. Server sided checks are fine and preferable - the hacker can’t touch this.

2 Likes

By the way the script just needs to check if indexed:IsA("Humanoid"). So this won’t really be effective either.

2 Likes

Yeah, i made a typo in the original script with indexed == “Humanoid” instead of index == Humanoid (instance)

2 Likes

I have a question. Ofc a hacker can bypass the Kick by setting the function etc to something else. But in your example, You can detect the difference if you were to do

if type(game.Players.LocalPlayer.Kick) == "function" then ... else ... end

Though. In my AntiCheat system, For the client (Yes IK there’s no point etc. But it helps, I can detect it on the server. But having a client can always annoy/bug the hackers nevertheless.)

Either way. Would doing the following help patch that Kick?

function self:SafeKickClient(Message)
	local Success, Error = pcall(function() game:GetService("Players").LocalPlayer:Kick(Message) end)
	local StatsService = game:GetService("Stats")
	
	RunService.RenderStepped:Wait()
	
	if not Success or StatsService.DataSendKbps ~= 0 then
		repeat until true ~= true
	end
end

Personally my AntiCheat already has a setting. Allowing you to enforce a brutal shutdown. Or you can Call SafeKick, Either way it’s going to stop the client?

Edit: I’ve tested, The stats service and the network flow. It near enough disconnects it instantly. Hence you can tell if they’re still connected or not.

5 Likes

Most “skids” are copy and pasting scripts from an online internet forum. The people who know what they are doing are making those scripts.

You shouldn’t spend a large amount of time coding security checks on the client.

4 Likes

this is awewome i didnt even know objects had metatables

client-sided isn’t very good

but my method using a module script in replicated storage and a local script in starterplayerscripts isn’t useful anymore if they can stop my exploits

You shouldn’t worry, at all, since most exploiters are skiddies and they just won’t know how to get through it. They don’t know how to use hookfunctions or metatables or those things. Anyways, since you can’t run a good anticheat on the server, and the clientsided anticheats are easy to bypass. Just try to make a mix, but never relying 100% on the client. You can try to make the main check in the client side but you can always keep a little thing server sided. Like a humanoid walkspeed check every 30 - 60 seconds or those things that wouldn’t bother much. Another method is rubberbanding :slight_smile:

1 Like