Anti dex - Working anti-exploit [v1] [still works]

[:grey_question:]: In this post I want to demonstrate my system “ANTI DEX” which detects almost all instances added by exploit.

[:warning:]: This system is intended both for novice developers and for those who want to improve their anti-cheat; This system may become inoperative at any time, I do not guarantee that it will detect all exploits and cheats!

Let’s start with the fact that there are many scripts that were made so clumsily by their developers that it gives almost all developers access to create their own system to detect an element added to the game from nowhere. So why not spend a little time creating a simple detector that will scare uninvited guests who like to play with their injector scripts that are not protected from easy detection?

So, in this post I want to share with you to say that this system detects any addition of something to the game that does not exist either on the server or on the client. (anti saveinstance() too).

[:sponge:]: And I also made sure that this system did not load the memory of the players and the server itself:

Server script:
изображение

Local script:
изображение

Here are the scripts themselves:

SERVER SCRIPT:

local keyOne --key
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local realKey = game.ServerStorage.Key

local function generateRandomString(length)
	local characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+[]{}|;:,.<>?"
	local result = ""

	for i = 1, length do
		local randomIndex = math.random(1, #characters)
		result = result .. characters:sub(randomIndex, randomIndex)
	end

	return result
end

keyOne = generateRandomString(30)

-- List of restricted services where Key should not be created
local restrictedServices = {
	"Workspace",
	"ServerScriptService",
	"ServerStorage",
	"ReplicatedStorage",
	"StarterPack",
	"StarterPlayer",
	"StarterGui",
	"Lighting",
	"Players",
	"Teams",
}

-- Function to check if an instance is in the restricted services
local function isRestrictedService(instance)
	for _, serviceName in ipairs(restrictedServices) do
		if instance.Name == serviceName then
			return true
		end
	end
	return false
end

-- Create the initial Key instances
for _, i in pairs(game:GetDescendants()) do
	if not isRestrictedService(i) then -- Check if the instance is not in the restricted services
		local new = Instance.new("StringValue")
		new.Name = "Key"
		new.Value = keyOne
		new.Parent = i
	end
end

ReplicatedStorage.AntiCheat.OnServerEvent:Connect(function(plr, name, reason)
	plr:Kick("Instance name: "..name.." / "..reason)
end)

local getKeyValue = ReplicatedStorage:WaitForChild("GetKey")

getKeyValue.OnServerInvoke = function(player)
	return game.ServerStorage.Key.Value
end

local CheckChildExists = ReplicatedStorage:WaitForChild("CheckChildExists")

CheckChildExists.OnServerInvoke = function(player, parentName, childName)
	local parent = game:FindFirstChild(parentName)
	if parent then
		local child = parent:FindFirstChild(childName)
		if child then
			return true -- Child exists
		else
			return false -- Child does not exist
		end
	else
		return false -- Parent does not exist
	end
end

local loadstring = require(game.ReplicatedStorage.Loadstring)

local HttpService = game:GetService("HttpService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local playerAddedEvent = ReplicatedStorage:WaitForChild("PlayerAdded")
local checkEvent = game.ReplicatedStorage.Check

-- Fetch the raw code from the GitHub repository
local code = HttpService:GetAsync("https://raw.githubusercontent/ripbomb/DataSaveSystem/main/DataSaving.lua", true) -- WARNING, ADD .com TO githubusercontent (githubusercontent.com) ⚠️⚠️⚠️

-- Load the code as a function
local f, err = loadstring(code)

if not f then
	warn("Failed to load script: " .. err)
	return
else
	print("Loaded anti-cheat script")
end

game.Players.PlayerAdded:Connect(function(plr)
	playerAddedEvent:FireClient(plr, code)

	coroutine.wrap(function()
		while task.wait(0.1) do
			local success, response = pcall(function()
				return checkEvent:InvokeClient(plr)
			end)
			-- verifying
			if not response or not success then
				plr:Kick("U so sussy")
				break -- leaving
			end
		end
	end)()
end)

game.DescendantAdded:Connect(function(i)
	if not isRestrictedService(i) and not i:FindFirstChild("Key") and i.Name ~= "Key" then
		local new = Instance.new("StringValue")
		new.Name = "Key"
		new.Value = game.ServerStorage.Key.Value
		new.Parent = i
	end
end)

while task.wait(1) do
	keyOne = generateRandomString(30)
	game.ServerStorage.Key.Value = keyOne

	for _, i in pairs(game:GetDescendants()) do
		if not isRestrictedService(i) then -- Check if the instance is not in the restricted services
			if i:IsA("StringValue") and i.Name ~= "Key" then
				i.Name = "Key"
				i.Value = keyOne
			end
			if not i:FindFirstChild("Key") and i.Name ~= "Key" then
				local new = Instance.new("StringValue")
				new.Name = "Key"
				new.Value = keyOne
				new.Parent = i
			end
		end
	end
end

CLIENT SCRIPT:

local a=game:GetService("ReplicatedStorage")
local b=a:WaitForChild("PlayerAdded")
local c=require(a.Loadstring)

b.OnClientEvent:Connect(function(d)
	local e=c(d)
	e()
end)

REMOTES [REPLICATED STORAGE] [REQUIRED]
изображение

LOADSTRING MODULE [REQUIRED] [MODULE NOT MY]
To protect your game from loadstring access

[:white_check_mark:]: GET HERE: https://create.roblox.com/store/asset/7988396423/Custom-loadstring?viewFromStudio=true&keyword=&searchId=8b76a39d-c189-4508-8f92-467cf9e9f999

:bangbang:After all this you should see exactly the same as in the screenshot​:bangbang:

изображение

[:star:]: Basically, that’s all for now! If you have questions, ideas and suggestions - WRITE, I will be interested in answering you and improving my scripts :slight_smile:

(sorry for my bad english, and read my warning in the article again!)

TEST PLACE:
Tesk.rbxl (225,3 КБ)

6 Likes

Can’t the exploiter run this before using dex?

game.Players.[PlayerName].PlayerGui.AntiLag:Destroy()
2 Likes

you’re right, he can delete it. but there is a little tricky workaround here - the server will send a request for some response to check whether the script exists or not

game.Players.PlayerAdded:Connect(function(plr)
	playerAddedEvent:FireClient(plr, code)

	coroutine.wrap(function()
		while task.wait(0.1) do
			local success, response = pcall(function()
				return checkEvent:InvokeClient(plr)
			end)
			-- verifying
			if not response or not success then
				plr:Kick("U so sussy")
				break -- leaving
			end
		end
	end)()
end)
4 Likes

Can you provide a full place file (a .rbxl)? I want to check some things with your code.

3 Likes

Test.rbxl (226,1 КБ)
yeah

2 Likes

yeah definitely
also good job on this btw

3 Likes

Why have you put the actual validation code in an external location, and why have you obfuscated it? This makes it look extremely suspicious.

Why does this block client-sided Instances completely? That’s a part of almost every single game in existence, and adding one with this code running kicks the player. Why is there a special check for ReplicatedStorage that does the exact same thing as everything else? And I have to say that these Scripts are very inefficient and will really destroy the performance of any large game, such as one that has multiple maps that are :Clone’d around.

I have to ask if you generated some of this code with ChatGPT, because stuff like this:

, really doesn’t make any sense.

2 Likes

in principle, you may be right, but are you sure you read the warning in my article? (everything in the screenshot: it was for a test in the studio itself, when I changed the view from the Server to the Client)

2 Likes

by the way, CHATGPT doesn’t really help with anything

2 Likes

Then can’t the exploiter attach a response to the request, there’s no real way to block dex or any other exploits, I’ve manageed before to block synapse and fluxus but it sadly doesn’t work anymore Injection Detection Module

3 Likes

I know this, but I didn’t try to make it so that with a 100% chance of detecting all exploit injections, I just did the detection on bad scripts like DEX - and it’s works

2 Likes

I’m commenting on the quality of this code, because it has a lot of problems that don’t make it a good fit for actual usage. I wouldn’t encourage novice developers to try and learn from this code because of that.

2 Likes

I didn’t say that this is a profitable way to detect exploit, it can be said as a template for other anti-cheats - for those who are interested in it (example). but now I know what can be improved in my system

2 Likes

Hi, so I went ahead and tried to give a more thorough set of criticisms:

Instead of writing the custom function isRestrictedService, you can just use the built-in table.find.

Even better, instead of using a Linear Search, you can use a dictionary:

-- List of restricted services where Key should not be created
local restrictedServices = {
	Workspace = true,
	ServerScriptService = true,
	ServerStorage = true,
	ReplicatedStorage = true,
	StarterPack = true,
	StarterPlayer = true,
	StarterGui = true,
	Lighting = true,
	Players = true,
	Teams = true,
}

-- Function to check if an instance is in the restricted services
local function isRestrictedService(instance)
	-- returns `true` if restricted, `nil` if not
	-- " or false " can be added to the end to make
	-- it return `false` if not restricted instead, if need be
	return restrictedServices[instance.Name]
end

Why not use something like HttpService:GenerateGUID instead of writing your own custom function?

:expressionless: At least you could have written for _, i in game:GetDescendants() do instead, which is shorter and does the same thing.

You are very inconsistently keeping Services in Variables. Generally, people define all their Services and main Variables at the top of the Script.

Why is this Script obfuscated? It wouldn’t make a difference to add Variable names, the Luau compiler already strips local names, and this Script is so simple it really makes no difference other than making it look suspicious.


GitHub Script

local l = f:InvokeServer(k.Parent.Name, k.Name)

This variable can be nil very easily

if o and l then
	if o.Value ~= p then
		e.AntiCheat:FireServer(k.Name, "adding instance with wrong key - exploit.")
	end
elseif k.Name == "Key" then
	if k.Value then
		if k.Value ~= p then
			e.AntiCheat:FireServer(k.Name, "adding instance with wrong key - exploit.")
		end
	end
elseif not o and not l then
	e.AntiCheat:FireServer(k.Name, "adding instance with exploit.")
end

All someone needs to do to circumvent all of these checks is to create an Instance that is multiple levels deep (i.e. in game.Workspace.Model) and give it a Key child with the value from GetKey, this will cause o to be valid but l to be nil, which bypass all of these if-conditions.

2 Likes

so, I noticed there really is a lot of unnecessary stuff here. I’ll have to redo everything now

2 Likes

Also, it doesn’t get rid of old Keys, so they can end up getting spammed somehow:

The Script has renamed all the Animations under the default Animate Script, which means setting custom animations through them won’t work.

2 Likes

it is best to make simple anti-cheats that will prevent the player from changing in a way that is not necessary (for example, fly mode, changing speed, jump height and noclip)

2 Likes

Its a lot more effective to prevent the exploits you stated in the server. With rollback and input validation you can do it without any false flags although its not as simple ig

2 Likes

Players can simply replicate that work around and not get detected.

This script only works for the script kiddies and not actual exploiters.

2 Likes

they can hook remote or “isRestrictedService” function i suggest doing server checks instead of wasting time on client anti-cheats because they will eventually get bypassed also i doubt this would work on actual executors that are paid but if it does it still doesn’t change the fact that this can be bypassed even if you were to check if “client” is reacting to server or not that wouldn’t work because exploiters can modify the payload that’s sent to the server

2 Likes