Anti-Exploit Assistance

Ok guys, so you know how most people, maybe even you, say that its impossible for the server to see what’s going on on the client, and without some weird Vector/Position checking nonsense, it’s impossible to make a working anti-exploit, but I have came up with a solution.

The good ol’ phrase, “Never Trust The Client” right?

So I found a way to make the client send the server the players humanoid details, i.e. WalkSpeed, JumpPower, Health to the server for it to check. Basically by sending a request from the server to the client via a RemoteEvent, then waiting for the client to send back the data, (I use remote events cause remote functions are just, idk, hard for me to understand), but here’s the twist, the client can’t just delete the script that does that, because the server counts up to a certain amount of time (Normally about a second) and if the server hasn’t heard a response from the client, say bye bye to our nice hacker. Now yes, someone could alter the script so that the client only sends back correct data but it would be very hard and you would hit some roadblocks, such as not knowing what the past WalkSpeed was.

Now this is great and all, but I have sort of an embarrassing problem. My code doesn’t work LOL, but in theory it should, I think I just need a second set of eyes to look at it.

Current Code (Server Side)
-- Variables --
local RequiredWalkSpeed = 16
local RequiredJumpPower = 50
local RequiredHealth = 100
-- More Variables --
local Replicated = game:GetService("ReplicatedStorage")

wait(7) -- Wait for the client to fully load
warn("Server Side Initialized") -- Let us know that it's ready to start checking clients

local function timeCheck(start, v) -- This counts the amount of time since the request was sent
	if start then
		local toggle = true
		currentMSec = 0
		while toggle do
			wait(0.001)
			currentMSec = currentMSec + 1
		end
	else
		local toggle = false
		if currentMSec > 2000 then -- More than 2 seconds
			v:Kick("Anti-Exploit: Exploit Detected, Server Request Return never was returned. This could also be caused by a bad connection, if you were not exploiting, please check your internet connection and try again.") -- Ahahah dont delete my scripts 'tard
		end
	end
end


Replicated.AntiExEventClientServer.OnServerEvent:Connect(function(plr, plrstats) -- Catches the reply from the client and checks humanoid stats
	local v = nil -- Prevents errors, look at client script for more details
	timeCheck(false, v) -- Stop the clock
	local WalkSpeed = plrstats[1]
	local JumpPower = plrstats[2]
	local Health = plrstats[3]
	if WalkSpeed ~= RequiredWalkSpeed or JumpPower ~= RequiredJumpPower or Health ~= RequiredHealth then
		plr:Kick("Anti-Exploit: Exploit Detected, One or more humanoid characteristics are incorrect.") -- haha get caught suckas
	end 
end)

-- Main Loop

while true do  -- This loop is giving me a crap ton of headaches :(
	wait(0.5) -- No crashing the server pls
	for _, v in pairs(game.Players:GetChildren()) do -- Loop though the players
		timeCheck(true, v) -- Start the clock
		Replicated.AntiExEventServerClient:FireClient(v) -- Politely ask the client for it's humanoid information
		print("Client Fired,",v.Name,"was fired successfully, awaiting Player Stats Response...") 
	end
end
Current Code (Client Side)
warn("Local Side Initialized")
local ClientServer = game:GetService("ReplicatedStorage"):WaitForChild("AntiExEventClientServer")
local ServerClient = game:GetService("ReplicatedStorage"):WaitForChild("AntiExEventServerClient")

ServerClient.OnClientEvent:Connect(function()
	local Humanoid = game.Players.LocalPlayer.Character.Humanoid
	local tablePackaged = {Humanoid.WalkSpeed, Humanoid.JumpPower, Humanoid.Health}
	ClientServer:FireServer(tablePackaged)
end)

Help me please!

1 Like

First of all, you have a problem with your code. On the line when you wrote timeCheck(true, v), it will pause the thread and keep waiting in that timeCheck function and never running your remote event line, so you should move the timeCheck(true, v) below the print line. Secondly, a wait with a argument less than 1 is extremely inaccurate and will probably have an extra 0.1 second delay each time it runs the loop. Instead, you should use os.clock(). You can implement this by adding a dictionary with player instances as the key and the os.clock() of the time when you fire the remote to the client. Like this:

local osclockDictionary = {}
game.Players.PlayerAdded:Connect(function(player)
	osclockDictionary[player] = 0
end)
game.Players.PlayerRemoving:Connect(function(player)
	osclockDictionary[player] = nil
end)

Just set osclockDictionary[player] to os.clock() every time you are firing it to the client.

Okay onto the next thing. There’s a logic flaw within your code. If you look closely, you only check if the player exceeded the maximum amount of time when the client “fires” the remote event. So if the exploiter delete the client script, it will never send any information to the server and it will never check if the time exceeded, so instead of checking if the time exceeded on the server, just do the check before you fire the remote event to the client in the loop under for _,v in pairs(game.Players:GetChildren()) do. Lastly, I would increase the rate of the loop to 5 seconds. Don’t put too much stress on your server. Here’s the final code for the server:

-- Variables --
local RequiredWalkSpeed = 16
local RequiredJumpPower = 50
local RequiredHealth = 100
local osclockDictionary = {}
-- More Variables --
local Replicated = game:GetService("ReplicatedStorage")

warn("Server Side Initialized") -- Let us know that it's ready to start checking clients

game.Players.PlayerAdded:Connect(function(player)
	wait(7)
	if game.Players:FindFirstChild(player.Name) then -- Make sure the player is still in the server
		osclockDictionary[player] = os.clock()
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	osclockDictionary[player] = nil
end)

local function timeCheck(start, v) -- This counts the amount of time since the request was sent
	if start then
		-- This part actually not needed
	else
		local toggle = false
		if (os.clock() - osclockDictionary[v]) > 2 then -- More than 2 seconds
			v:Kick("Anti-Exploit: Exploit Detected, Server Request Return never was returned. This could also be caused by a bad connection, if you were not exploiting, please check your internet connection and try again.") -- Ahahah dont delete my scripts 'tard
		end
	end
end


Replicated.AntiExEventClientServer.OnServerEvent:Connect(function(plr, plrstats) -- Catches the reply from the client and checks humanoid stats
	local v = nil -- Prevents errors, look at client script for more details
	local WalkSpeed = plrstats[1]
	local JumpPower = plrstats[2]
	local Health = plrstats[3]
	if WalkSpeed ~= RequiredWalkSpeed or JumpPower ~= RequiredJumpPower or Health ~= RequiredHealth then
		plr:Kick("Anti-Exploit: Exploit Detected, One or more humanoid characteristics are incorrect.") -- haha get caught suckas
	end 
end)

-- Main Loop

while true do  -- This loop is giving me a crap ton of headaches :(
	wait(5) -- No crashing the server pls
	for _, v in pairs(game.Players:GetChildren()) do -- Loop though the players
		if osclockDictionary[v] then -- Check if player is loaded
			timeCheck(false, v) -- Stop the clock
			osclockDictionary[v] = os.clock()
			Replicated.AntiExEventServerClient:FireClient(v) -- Politely ask the client for it's humanoid information
			print("Client Fired,",v.Name,"was fired successfully, awaiting Player Stats Response...")
		end
	end
end

After writing this, I made some additional edits that I didn’t mention above. For example, your toggle variable is actually local to the scope, the the toggle variable will never change and it will be in an infinite loop, which means that only one player would be looped through in your for loop since the next loop will only happen after the current loop is finished. Anyways, I might not be there to respond if there’s a problem since I need to go to sleep now. Good luck with your anti-exploit! :slight_smile:

2 Likes

You also forgot that exploiter can run the same while loop like your local script that is firing server and give your server false informations so yeah like you said Never Trust The Client, this won’t help you against exploiters, so your only option is the “weird position checking”.

I don’t get why the exploiter couldn’t simply spoof the values on the client to be normal using some metamethod trick. They can simply get the metatable of game and modify the __index and __newindex property so that if it tries to index their humanoid and any of the properties found here it sends a fake one.

2 Likes