Need help with basic anti-cheat

I wanted to make a simple anti-cheat that just perma-bans users who have certain cvars that vary from what the servers have. I get excessive lag and server crash while using this script and I can’t figure out what’s wrong with it.

[lua]
local BannedCVars = {
“sv_cheats”,
“sv_allowcslua”,
“mat_fullbright”,
“mat_proxy”,
“mat_wireframe”,
“host_timescale”,
}

local first = true
local function RefreshCVars()
for k, v in pairs(BannedCVars) do
BannedCVars[k] = GetConVar(v)
if first then
cvars.AddChangeCallback( BannedCVars[k]:GetName(), RefreshCVars() )
end
end
if first then
first = false
end
end
RefreshCVars()

local function GetCheatCVar()
for k, v in pairs(player.GetAll()) do
v:SendLua( [[
local LBannedCVars = ]] … BannedCVars … [[
local GetConVarNumber = GetConVarNumber
for k,v in pairs(LBannedCVars) do
if GetConVarNumber( v:GetName() ) ~= v:GetString() then
RunConsoleCommand( “banmeimafag”, v:GetName() )
end
end
]] )
end
end
timer.Create(‘GetCheatCVars’,5,0, GetCheatCVar)

concommand.Add(‘banmeimafag’, function( ply, convar )
ply:Ban( 0, “AntiCheat: Recieved unsynced cvar ( " … convar … " )” )
RunConsoleCommand( “ulx”, “banid”, ply:SteamID() , 0, “AntiCheat: Recieved unsynced cvar ( " … convar … " )” )
RunConsoleCommand( “writeid” )
end)
[/lua]

  1. SendLua should NEVER be used.

  2. Never include a function inside itself.

  3. A table is NOT a string. You can’t use “<string> … <table>”. That’s not how it works. A client and a server don’t have the same values, so you have to send the tables data back and forth.

  4. Never trust the client … 90% are blocking GetConVarNumber.

  5. Learn the net library: http://wiki.garrysmod.com/page/Net_Library_Usage

  6. You can convert a table to a string and back using: http://wiki.garrysmod.com/page/util/TableToJSON. But don’t do it every 5 seconds … do it once.

  7. There are plenty of anticheats and scripts that helps (Best those that aren’t public) … the best way to fight the hackers are admins.

Okay, I haven’t tested this yet because I haven’t had any victims or crashes yet… but I wrote it in the net library like I should have the first time.

SERVERSIDE CODE:
[lua]
util.AddNetworkString( “ValidateCVars” )
util.AddNetworkString( “CheckServerVars” )

local BannedCVars = {
“sv_cheats”,
“sv_allowcslua”,
“mat_fullbright”,
“mat_proxy”,
“mat_wireframe”,
“host_timescale”,
}

local first = true
local function RefreshCVars()
for k, v in pairs(BannedCVars) do
BannedCVars[k] = GetConVar(v)
if first then
cvars.AddChangeCallback( BannedCVars[k]:GetName(), RefreshCVars() )
end
end
if first then
first = false
end
end
RefreshCVars()

local function SendBannedCVars(ply)
for k, var in pairs(BannedCVars) do
net.Start(“ValidateCVars”)
net.WriteTable( { VarName = var:GetName(), VarString = var:GetString() } )
net.Send(ply)
end
end
net.Receive( “CheckServerVars”, function(l, ply) SendBannedCVars(ply) end )

local function ValidateCVar(ply, ServerValue, ClientValue)
if GetConVar(ServerValue):GetString() ~= (ClientValue or “”) then
ply:Ban( 0, “AntiCheat: Recieved unsynced cvar ( " … convar … " )” )
RunConsoleCommand( “ulx”, “banid”, ply:SteamID() , 1, “AntiCheat: Recieved unsynced cvar ( " … convar … " )” )
RunConsoleCommand( “writeid” )
end
end

net.Receive(
“ValidateCVars”,
function(len, ply)
ValidateCVar(ply, net.ReadTable().ServerValue, net.ReadTable().ClientValue)
end
)
[/lua]

CLIENTSIDE CODE:
[lua]
local function CheckCVars()
net.Start(“CheckServerVars”)
net.WriteBit()
net.SendToServer()
end
timer.Simple(5, CheckCVars)

local function ValidateCVar(ServerValue, ClientValue)
net.Send(“ValidateCVars”)
net.WriteTable({ServerValue = ServerValue, ClientValue = ClientValue})
net.SendToServer()
end

local function RefreshCVar(CVar, OldVal, NewVal)
timer.Simple(1, function() – Wait 1 incase server changed its var too.
ValidateCVar(CVar, NewVal)
end)
end

local BannedCVars = { }
net.Receive( “ValidateCVars”,
function()
local ConVar = GetConVar(net.ReadTable().VarName)
local Value = (ConVar ~= nil and ConVar:GetString() or “0”)
BannedCVars[ConVar] = Value
cvars.AddChangeCallback(net.ReadTable().VarName, RefreshCVar)
if Value ~= net.ReadTable().VarString then
ValidateCVar(net.ReadTable().VarString, Value)
end
end
)
[/lua]