Anti-Cheat Release : Visionary

all-seeing-eye-freemason-pierre-blanchard

Heavily inspired by @XoifailTheGod’s Valkyrie Anticheat, Anti-Cheat Release: Valkyrie | Roblox

Features:

  1. Secure Anti-Tamper

  2. Core Gui Script Detection

  3. Anti-game metamethod hooking

  4. Hook function detection

  5. Encrypted client-server handshake

  6. Ultra-fast performance

  7. Mobile-executor annihilator

  8. Anti-Sandbox

  9. Low false positives

Visionary Performance:
Intel(R) Core™ i7-14650HX
NVIDIA GeForce RTX 4070 Laptop GPU
32 GB RAM


Running:
0.000% Activity
2.0-17.0/s


Ferris Wheel:
0.000% Activity
2.0/s Rate


Zombie AI:
0.000% Activity
22.0/s Rate

Current Settings List 10/29/2024:

local Settings = {
	CAN_RUN_IN_STUDIO_OR_SANDBOXED = true,
	Enable_Watermark = true,
	DebugMode = true,
	MaxAnticheatFlags = 5,
	MaxValuesForProperty = {
		["WalkSpeed"] = 16,
		["JumpHeight"] = 7.2,
		["PlatformStand"] = false,
		["HipHeight"] = 2.952,
		["MaxHealth"] = 100,
		["MaxSlopeAngle"] = 89,
		["JumpPower"] = 50,
		["CanCollide"] = true,
		["Anchored"] = false,
		["CanTouch"] = true,
		["Shape"] = Enum.PartType.Block,
	},
	Anticheat_Detection_Methods = {
		Anti_Speed_Hacks = true,
		Anti_Fly_Hacks = true,
		Anti_Part_Tamper = true,
		Anti_Humanoid_Manipulation = true,
		Anti_Remove_Objects = true,
		Anti_Workspace_Manipulation = true,
		Run_AntiTamper_Checks = true,
		Anti_CoreGui_Scripts = false,
	},
	DoNotCheckTheseProperties = {
		Jump = true,
		JumpReplicate = true,
		MoveDirection = true,
		MoveDirectionInternal = true,
		NetworkIsSleeping = true,
		LocalTransparencyModifier = true,
		InternalDisplayName = true,
		Camera = true,
		Sound = true,
		IsLoaded = true,
		TextButton = true,
		TextLabel = true,
		ScreenGui = true,
		TextBox = true,
		AbsolutePosition = true,
		AbsoluteSize = true,
		AbsoluteCanvasSize = true,
		ScreenOrientation = true,
		InternalCharacterAppearanceLoaded = true,
		CurrentScreenOrientation = true,
		Playing = true,
		FloorMaterial = true,
		Frame = true,
		ImageLabel = true,
		ScrollingFrame = true,
		ForceField = true,
		UIGridLayout = true,
		PrimaryPart = true,
		Attachment0 = true,
		Attachment1 = true,
		AngularVelocity = true,
		Force = true,
		WalkToPoint = true,
		Health_XML = true,
	},
	FolderYouCantRemove = { -- Use for things that will never change/ never be touched
		--Folder1 = workspace:WaitForChild("Folder")
	},
	ClassNamesAndNamesYouCANRemove = {
		HumanoidRootPart = true,
	}
}

Decided not to make the server-anticheat due to the sheer amount of them. Just combine the server visionary code with whatever other server-side anticheat you have.

If you have any properties spamming the console you can add them to the DoNotCheckTheseProperties setting.

Banwaves coming in the future if this gets attention!

Visionary Anti Cheat.rbxm (34.4 KB)

28 Likes

Mobile executor annihillator

It’s not bad at all, pretty good

2 Likes

Cant client anti-cheats be bypassed if so i’d be happy to pair it with my client anti-cheat measures to secure it Client-Server Anti-Cheat System with Custom Encryption – Seeking Feedback!

It has a client side and server side handshake encryption already, thank you though.

Encryption? can you explain more how this process works im really interested i look through the code but i failed to pinpoint how it actually worked lol

Alright! I explained this more in my other community resource. Clientside Anti-Tamper Solution using a Car

Here is the code that is both on the client.

-- Client Anticheat
local randomNew = function()
	local m = 2^32               -- Modulus
	local a = 1103515245         -- Multiplier
	local c = 12345              -- Increment
	
	local serverTime = string.format("%.0f",workspace:GetServerTimeNow())
	local handshake = (math.floor(serverTime) % 100000000000) + (1) 
	handshake = (a * handshake + c) % m
		
	local Flag = (math.floor(serverTime) % 100000000000) + (1000)
	Flag = (a * Flag + c) % m


	return handshake,Flag
end

First, we index the server Time using workspace:GetServerTime.

Then, we use a Linear congruential generator, (Psuedo Random Number Generator) to turn that time into as a sort of authentication number.

local m = 2^32               -- Modulus
local a = 1103515245         -- Multiplier
local c = 12345              -- Increment

local serverTime = string.format("%.0f",workspace:GetServerTimeNow())
local handshake = (math.floor(serverTime) % 100000000000) + (1) 
handshake = (a * handshake + c) % m

This will be our handshake.

Third, we generate another authentication number. but this one will be our anticheat flag. Both the server and client generate this, if the client sends the anticheat flag the server will know the anticheat has been flagged and can send a subsequent ban.

local Flag = (math.floor(serverTime) % 100000000000) + (1000)
Flag = (a * Flag + c) % m

Here is the server sided version of the checks.

-- Server Anticheat
Remote.OnServerEvent:Connect(function(player : Player,handshakeNum)
	if os.clock() - debounce[player] < 0.5 then
		return
	end
	debounce[player] = os.clock()
	
	if not playersAuthenticated[player] then
		return
	end

	local handshake,Flag = randomNew() -- Generate handshake and client Flag

	Remote:FireClient(player,handshake,Flag) -- Send a new handshake back to the client to make sure the server is still alive

	if handshakeNum == handshake then -- if handshake is equal to generated handshake then we are good
		playersAuthenticated[player] = 0
		return
	end

	if handshakeNum == Flag then -- if the handshake is equal to the client sided flag then the client has been tampered with
		warn('Detected on Server: Player '..player.Name.." is cheating")
		playersAuthenticated[player] = 0
		return
	end

end)
1 Like

You have good intentions but please don’t spread misinformation, this isn’t encryption or real security. The Wikipedia page you linked clearly states LCGs are not cryptographically secure (you can predict future random values from previous ones), and it’s also statistically inferior to Roblox’s built in Random class. Checking if a PRNG on the server and client are synced is not a “handshake”.

6 Likes

It is infact a handshake because it establishes a secure link between the client and the server.

The client can know that the server is actually the server. The server can know that the client is there and functional. The client can also send an anticheat flag to the server which cant be detected that it was an anticheat flag by a cheater.

They are not cryptographically secure, but breaking the encryption is much harder than trying to break the implementation of the anticheat.

Computers are fast, change the modulus, multiplier, and increment. Multiplying and adding numbers is nothing to computers. I should’ve made the modulus and multipler bigger in the source code anyway.

local m = 5891237566232  -- Modulus
local a = 1827463912196 -- Multiplier
local c = 29498581723 -- Increment

Then, we can truncate the output to eliminate brute forcing.

local randomNew = function()
	local m = 5891237566232 -- Modulus
	local a = 1827463912196 -- Multiplier
	local c = 29498581723   -- Increment


	local handshake = (math.floor(workspace:GetServerTimeNow())) + (1) 
	handshake = (a * handshake + c) % m

	local Flag = (math.floor(workspace:GetServerTimeNow())) + (1000)
	Flag = (a * Flag + c) % m

	local truncatedHandshake = tostring(handshake):sub(2, -2)	-- Truncate the first and last number to break bruteforcing.
	local truncatedFlag = tostring(Flag):sub(2, -2)	

	return truncatedHandshake,truncatedFlag
end

  • Why can’t we use Roblox’s random funciton?

Roblox’s random class can be hookfunctioned.

-- Store the original Random.new function
local originalRandomNew = Random.new

-- Create the hook function
Random.new = function(...)
    -- Print arguments for debugging
    print("Random.new called with arguments:", ...)
    
    -- Call the original function and store the result
    local result = originalRandomNew(...)
    
    -- Print the result for debugging
    print("Random.new returned:", result)
    
    -- Return the result
    return result
end

These implementations make it so that it would probably never be cracked in a lifetime. You could also add a “seed” you can XOR the final truncated number with.

Here’s the final code that I will include in a new version of Visionary.

local randomNew = function(seed:string)
	local m = 5891237566232 -- Modulus
	local a = 1827463912196 -- Multiplier
	local c = 29498581723   -- Increment

	local handshake = (math.floor(workspace:GetServerTimeNow())) + (1) 
	handshake = (a * handshake + c) % m

	local Flag = (math.floor(workspace:GetServerTimeNow())) + (1000)
	Flag = (a * Flag + c) % m

	local truncatedHandshake = tostring(handshake):sub(2, -2)    -- Truncate the first and last number to break bruteforcing.
	local truncatedFlag = tostring(Flag):sub(2, -2)    

	-- Convert seed to a number for XOR operation
	local seedNum = 0
	for i = 1, #seed do
		seedNum = seedNum + string.byte(seed, i)
	end

	-- XOR operation
	local function xorStrings(str, seedNum)
		local result = ""
		for i = 1, #str do
			local charCode = string.byte(str, i)
			local xoredCode = bit32.bxor(charCode, seedNum)
			xoredCode = xoredCode % 256  -- Ensure valid byte range
			result = result .. string.char(xoredCode)
		end
		return result
	end

	-- Apply XOR to truncated strings
	truncatedHandshake = xorStrings(truncatedHandshake, seedNum)
	truncatedFlag = xorStrings(truncatedFlag, seedNum)

	-- Convert XORed strings to hex
	local hexHandshake = stringToHex(truncatedHandshake)
	local hexFlag = stringToHex(truncatedFlag)

	return truncatedHandshake, truncatedFlag
end

Result:

����������� �����������

Absolute gibberish to the Luau output.

Here’s the article I found for the improvement of the code and about cracking LCGs and PRNGs.
Cracking RNGs: Linear Congruential Generators // msm’s home

  • Change 1.1.0- Reinforced anti-bruteforcing.

New release:

visionary.rbxl (340.2 KB)

My mistake i’ll clarify; this “handshake” is not a secure way to authenticate actions.

A cheater can see the client-side randomNew function + what it sends to the server, and therefore can easily check

LCG is not encryption, and any anticheat relying on it as such will not be secure

This does not increase security or complexity. Any modulus, multiplier, increment, and future outputs can be calculated from previous outputs from the LCG.

Any changes like this are moot since your randomNew function is the same on the server and client, a cheater knows what the server is expecting by just checking the client-side version.

Yes, a cheater can also see your client-side code and modify it

If you’re trying to authenticate client actions on the server with a really simple PRNG + some simple transformations applied (that the cheater can see from the client-side copy), it’s already cracked.

My original outline for the anti-cheat was for the code to be obfuscated. Eliminating the cheater being able to see the client-side randomNew function. You are correct, LCGs are not encryption, and neither are LCGs not crackable. but they are less vulnerable to more advanced cryptanalytic techniques and require math (which skids dont like) to break.

The methods being used in this are pretty outdated, I’d like to also point out that creating an actor instance to parent the corescript with is not possible on a local script, i would also recommend you use better handshakes as the core one for this is very unreliable

1 Like

can you privde the rbxm file for this?
also it keeps saying that it detects the cheater but its notkicking or moving th eplayer back

allat yap just for citadel v3 to solo

anyway this sucks please stop writing code that makes my eyes hurt

your handshake is literally on a seperate thread defeating the whole point of having a handshake

bro prays nobody uses getgc to just brick his checks
addChangeListeners(Services.Workspace)
addChangeListeners(Services.Players)
addChangeListeners(script)
RunChecks()
addFolderToTable()

The code is to parent an actor instance to coregui is to detect an injection, it is supposed to be not possible and supposed to error. This used to be possible to detect some CoreGUI scripts. If doesn’t error than an injection was detected.

while AntiCheatListening do

Ah yes, not reading code.

Ah yes, not reading 2 messages before your comment.


never heard of it :skull: am i supposed to care?

2 Likes

The rbxm file is good. I purposefully left it so that it doesn’t kick players. The client disconnects itself and after a certain amount of time the server kicks the client for not giving a handshake.

If you really want to kick a person on detection, change this in the Server code.

if handshakeNum == Flag then
	warn('Detected on Server: Player '..player.Name.." is cheating")
	playersAuthenticated[player] = 0
	player:Kick() -- here
	return
end

thanks also wouldnt it make sense to make multiple fake remote events/ rename them so the person who is exploiting can just dlete them mid game

also i keep getting this kick message when i am just standing in game doing nothing (in studio) 17:12:36.204 Server Kick Message: Anticheat authentication failed. (or your cheating :3) - Studio

If the person deletes the Remote, the client cant talk to the server, so the server kicks the client. :+1: