The fight against exploiters in videos games
A lot of games, in specific Roblox, have a cheating issue.
Cheating in video games has always been an issue with Player VS Player video games. A big one that has been noticed is Roblox, one of the worst scenes when it comes to exploiting.
How it works;
Cheaters use a DLL injector, also known as an "Executor", which hides what it's doing to Roblox by editing and messing with the files on the local machine it's being ran on.
The injector can inject code, Lua. The Lua code must be written as if it's a client script, it cannot inject server code. A good example is, you can make yourself fly, but only YOU can see it, no one else. They can see you flying, but it won't look special if you're just floating.
This is because Roblox is split between the client and the server. The client is basically what the player has control over, while the server is what controls the actual game and what everyone should see. Because of this, an exploiter can change things on their own client, but that doesn't automatically mean the server will accept those changes.
For example, if someone uses an exploit to give themselves a weapon, they might see the weapon on their screen, but that doesn't mean the server actually gave them the weapon. Other players may not see it, and the exploiter may not actually be able to use it properly against the server.
However, this is where exploiting becomes more complicated.
Exploiters can also hook onto functions. A hook basically allows them to intercept a function before or while it is being called, allowing them to observe, modify, or sometimes prevent what the function is doing. This can be used to change the behavior of functions that the game relies on.
For example, if a game has a function that performs a raycast to determine what a player is aiming at, an exploiter may try to interfere with that process on their own client. Instead of allowing the original result to be used, the exploiter can attempt to make the game behave as if the player was aiming at something else.
One example of this is something commonly called "Silent Aim."
Silent aim is an exploit technique where the cheater doesn't necessarily have to visibly move their crosshair onto another player. Instead, the cheat attempts to manipulate the game's targeting or hit-detection process so that a shot which appears to be aimed somewhere else can be registered against a different target.
A common part of this involves Raycasting.
A Raycast is basically a way for a game to shoot an invisible line from one point toward another point and check what that line hits. Roblox games commonly use raycasts for things such as guns, visibility checks, interaction systems, and determining whether something is between two objects.
For example, a normal gun could perform a raycast from the weapon or player's camera toward the direction the player is aiming. The result tells the game what the shot hit.
The problem is that if the important parts of this process happen entirely on the client, an exploiter can potentially interfere with the information being sent to the server.
This is why simply having an anti-cheat that checks whether somebody is using an executor isn't enough. Developers also need to make sure that important game decisions are validated by the server.
!!!!!NEVER TRUST THE CLIENT!!!!!
If you're a Roblox developer, one of the biggest rules you should follow is:
Never trust the client.
Anything running on the player's computer should be considered potentially modified.
For example, don't let the client decide how much damage another player takes.
-- BAD EXAMPLE
RemoteEvent.OnServerEvent:Connect(function(player, damage)
targetHumanoid:TakeDamage(damage)
end)The problem here is that the server is accepting the damage amount directly from the client.
If the normal game expects the client to send 25, the client could simply send a different value.
Instead, the server should decide how much damage the weapon is actually supposed to do.
-- BETTER EXAMPLE
local WEAPON_DAMAGE = {
Pistol = 25,
Rifle = 15,
Shotgun = 10
}
RemoteEvent.OnServerEvent:Connect(function(player, weaponName, target)
if typeof(weaponName) ~= "string" then
return
end
local damage = WEAPON_DAMAGE[weaponName]
if not damage then
return
end
if not target or not target:IsA("Humanoid") then
return
end
target:TakeDamage(damage)
end)
Now the client isn't deciding the damage amount. It only tells the server what weapon it claims to be using, and the server determines the actual damage.
You also shouldn't trust the client when it comes to money.
For example, don't allow the client to tell the server how much an item costs.
-- BAD EXAMPLE
BuyEvent.OnServerEvent:Connect(function(player, price)
player.leaderstats.Cash.Value -= price
end)
The client could potentially send whatever price it wants.
Instead, the server should have its own prices and determine the actual cost of the item.
-- BETTER EXAMPLE
local PRICES = {
Sword = 500,
Shield = 750,
Potion = 100
}
BuyEvent.OnServerEvent:Connect(function(player, itemName)
local price = PRICES[itemName]
if not price then
return
end
local cash = player.leaderstats.Cash
if cash.Value < price then
return
end
cash.Value -= price
-- Give the item here
end)
The same concept applies to movement.
If the client says:
"I moved 500 studs in 0.1 seconds."
the server shouldn't automatically believe it.
The server can check whether that movement makes sense based on the game's rules.
The same applies to things such as:
Damage
Money
Inventory
Weapons
Purchases
Teleporting
XP
Trading
Cooldowns
Abilities
Important movement checks
The client should mostly be responsible for things that are visual or input-related, while the server should be responsible for important game state.
For example, a client can say:
"I pressed the fire button."
But the server should determine:
Does this player actually have the weapon?
Is the weapon equipped?
Is the weapon off cooldown?
Is the target valid?
Is the shot physically possible?
How much damage should it do?
This is also important for preventing things like silent aim.
If the client is allowed to simply tell the server:
"I shot Player123."
then the server is trusting the client to decide who was hit.
A more secure design is for the server to validate the shot using information it can independently verify, such as the player's position, weapon state, timing, and other game rules.
The goal isn't to make the client impossible to modify. You generally can't assume that the player's computer is trustworthy.
The goal is to make modifying the client not enough to break the actual game.
That is one of the most important concepts when developing a multiplayer game:
Assume the client is compromised. Protect the important stuff on the server.
(tbh trust the client, let them destroy your games)
Comments
Log in to leave a comment.
