Sentinel Universal Anti-Cheat Release

:warning: I’m not updating this anti-cheat anymore, so it might be broken. The testing game will also remain closed. Most users on this forum are just wannabe coders that will trashtalk this anti-cheat no matter what and say some features don’t work without even testing them. Overall, this community is dumb and there is no point in continuing to work on this project as the community doesn’t deserve it. :warning:

Also I am looking for a project to work on so if anyone needs a scripter please dm me on my discord (Pinha#5428). I don’t need money I’m just doing this stuff for fun.

7 Likes

How did you do the CoreGui detection?

Server or client?

Also if client, how?

(server is probably not possible)

Client. The anti-cheat is open-source, you could just check it out yourself. But here is the code:

game.DescendantAdded:Connect(function(descendant)
	if descendant:IsDescendantOf(game:GetService("CoreGui")) then
		-- ban player
	end
end)
1 Like

Oh. Also where is it placed?

This text will be blurred

Place it inside of a LocalScript…

No, like server script service starter player

You could place it inside of StarterPlayer
Sentinel’s client-sided anti-cheat is stored inside a Script in ServerScriptService. Every time a player joins it will get cloned and placed inside his PlayerGui, and then enabled. After getting enabled it will set it’s own parent to nil to make it more difficult for exploiters to find it.

1 Like

Also, it seems clean. Cool! :grinning:

This text will be blurred

Nice. I suggest giving users the choice to clone the client-side script around every 45 seconds and destroy the old copies in case they decide to delete them. I’m not sure if you should or if it will create lag.

In this case PlayerGui as you can’t access PlayerScripts with a server sided Script.

I guess that’s a good idea for protecting the client-side anti-cheat. The server-sided anti-cheat could send new copies of the client-sided anti-cheat to all players every once in a while, which then would check if the old copy still exists and if it is enabled. If not then the player is exploiting. (also delete the old copy)

Yeah, bit unfortunately the old copy will still exist for the server. So delete the clone and then re clone it every 45 second. In case they delete it.

This detection is heavily outdated and doesn’t work. Other than that I would recommend adding sanity checks for connections as well as anything else. For example at the moment if an exploiter wanted to add a ui to PlayerGui for some reason they could disable the ChildAdded connection and do what they want. You could however simulate an Instance being added to PlayerGui in order to verify the connection hasn’t been disabled.

Also instead of firing a remote to the server with the raw values of the humanoid you can use some sort of client server encryption to make it harder to intercept the messages. This also however has faults, as values can easily be spoofed by hooking the __index metamethod and returning false values. It’d be more efficient to check these values on the client and then firing a single remote to flag them than all being compared on the server. Another suggestion to counter that would be checking more unknown properties, what I mean by this is properties such as humanoid root part velocity. Most speed scripts do spoof the humanoid walk speed but don’t manage to take into account that your velocity also increases.

Also quick side note for user id detection, the character appearance id has the same value as the user id so you can compare both of those values on the client and flag them if they aren’t matching.

One final tip would be adding a heartbeat to the client anti cheat. All these detection’s are great and all but what stops someone from hooking the remote from ever firing. By adding a heartbeat to the client script (means the client has to communicate to the server every X seconds) you can then pick up any abnormalities and detect if has tampered with your anti cheat remote.

4 Likes

A heartbeat would be your solution here.

1 Like

Nice story! I think this would improve it all, wouldn’t lt? Anyways I appreciate you creating this anti cheat.

Definitely make a GitHub page for this.

Summary

This text will be hidden

1 Like

Thanks, I’ll look into it.
About the HumanoidRootPart velocity, I’ve tried to get that to work for 3 days. I used Humanoid.Running to get the speed and also raycasting from feet to the ground to find the platform the player is standing on, so then I can get the speed of the platform and subtract it from the player’s speed in order to get the ‘real speed’. I also tried using workspace:GetPartsInPart(foot, overlapParams) instead of raycasting or even both at the same time for more accurate results. But I was never able to get it to work without causing false-positives in some situations.

The anti-cheat already does this.

The anti-cheat uses a different method for firing remotes:

local FireServer = Instance.new("RemoteEvent").FireServer
FireServer(Remote, Args)

I used a remote spy on the anti-cheat and it didn’t catch any remotes. While doing it the normal way would get intercepted.

The remote spy you used hooks the __namecall metamethod onlt meaning it only picks up the remotes if they are called like the following :FireServer and :InvokeServer etc. The method you used to fire a remote does help prevent beginner level exploiters from being able to see the remotes being fired however more experienced exploiters/developers will be able to tell that you index and call the function instead.

All remote events have the same functions at the end of the day, to demonstrate if you go into the game and write the following

print(Instance.new("RemoteEvent").FireServer == Instance.new("RemoteEvent").FireServer)

it would output true.

This means that exploiters can simply also create a remote event instance then hook the fire server function. It would look something like the following

local FS  = Instance.new("RemoteEvent").FireServer

local oldFS; oldFS = hookfunction(FS, function(...)
    print("Fire server was called.")
    return coroutine.yield()
end)

this hook would be able to pickup your remotes.