Hello, I Initially wanted to sell this detection as it is something unique, unexpected and effective, but i decided to release this publicly as my long-term goal is to attract the attention of game developers who may be interested in collaborating with me or even hiring me for my expertise.
Game to test: https://www.roblox.com/games/106169718540953
Visual Representation: https://www.youtube.com/watch?v=lr3tvHcHWck
Keep in mind the script i am posting is case specific to MY game that i have linked, you would need to update specific things to adapt it for your own game (Whitelisted script names, .DescendantAdded on different services if you create new script instances in them etc)
script.Parent = nil
repeat task.wait() until game.Players.LocalPlayer and game.Players.LocalPlayer.Character and game:IsLoaded() --Mandatory
task.wait(1)
--[[BOOT SCRIPTS]]--
if game:GetService("RunService"):IsStudio() then return end
--[[SERVICES]]--
local Stepped = game:GetService("RunService").PreRender --ONLY PreRender or RenderStepped can be used mainly due to "Give Feedback" feature from the InGameMenu disabling them while the frame is frozen, this is because it spikes your script memory ^ source : https://devforum.roblox.com/t/introducing-translation-feedback/2935975
--[[FUNCTIONS]]--
local function GetInstanceMemory()
local succ, err = pcall(function()
game:GetService("Stats"):GetMemoryUsageMbForTag("Script")
end)
if err then
game.Players.LocalPlayer:Kick("Detected")
task.spawn(function()
task.wait(1)
for i = 1, 500000 do
print()
end
end)
task.spawn(function()
task.wait(0.5)
while true do end
end)
script:Destroy()
else
return game:GetService("Stats"):GetMemoryUsageMbForTag("Script")
end
end
--[[VARIABLES]]--
local val = 0
local Paused = false
local TimeThreshold = 5
local LastScrAdded = 0
local WhitelistedScripts = {"CharacterLeanScript", "Health", "Animate"} --MUST contain every script name used in your game
local runtimeval = GetInstanceMemory()
workspace.DescendantAdded:Connect(function(v)
if v:IsA("LocalScript") or v:IsA("Script") and table.find(WhitelistedScripts, v.Name) then
Paused = true
LastScrAdded = tick()
repeat Stepped:Wait()
runtimeval = GetInstanceMemory()
if not Paused then Paused = true end
until runtimeval == val
if not Paused and runtimeval ~= val then runtimeval = GetInstanceMemory() end --to not cause overlapping
Paused = false
end
end)
workspace.DescendantRemoving:Connect(function(v) --players leaving can cause them to fluctuate after some time
if v:IsA("LocalScript") or v:IsA("Script") and table.find(WhitelistedScripts, v.Name) then
Paused = true
LastScrAdded = tick()
repeat Stepped:Wait()
runtimeval = GetInstanceMemory()
if not Paused then Paused = true end
until runtimeval == val
if not Paused and runtimeval ~= val then runtimeval = GetInstanceMemory() end --to not cause overlapping
Paused = false
end
end)
task.spawn(function()
pcall(function() --prevent users from breaking the script by breaking functions in roblox env
while true do task.wait(0.5) --considering slower devices
local CurrentTime = tick()
local TimeDiff = math.abs(CurrentTime - LastScrAdded)
val = GetInstanceMemory()
if not val then val = runtimeval + 5 end
if val ~= runtimeval and not Paused and (TimeDiff > TimeThreshold and runtimeval < val) then
game.Players.LocalPlayer:Kick("Detected")
task.spawn(function()
task.wait(1)
for i = 1, 500000 do --incase exploiter does ScriptContext:SetTimeOut()
print()
end
end)
task.spawn(function()
task.wait(0.5)
while true do end
end)
script:Destroy()
else
runtimeval = GetInstanceMemory()
end
end
end)
end)
game:GetService("GuiService"):SetInspectMenuEnabled(false) --Avatar Menu creates a new script instance causing memory to INCREASE (Decreased value happen after some time when deleted scripts are cleaned from the memory)
Understanding the Detection
When a script instance is created in a game, the script memory increases. Likewise, when a script is terminated, the memory usage decreases after some time. This fundamental principle is the basis for the script memory detection mechanism.
Monitoring Script Instances
The script keeps an eye on the Workspace service, where script instances are added in this particular game. If a new script instance is detected, and itâs listed in the WhitelistedScripts, the script updates the runtime value of the script memory.
Detection Logic
Hereâs where things get interesting. If the script memory increases without a corresponding new script instance being added to the Workspace (i.e., a nil instance or any other service that doesnât have a .DescendantAdded listener or is not Whitelisted), the script kicks the player. This suggests that an executor or exploiter is attempting to run scripts
Countering Exploitation Attempts
Some exploiters might try to bypass this detection by hooking the function to return a fake value. To counter this, the script could forcefully add a script instance to the Workspace and expect an increase in script memory. If the memory doesnât increase, detect the player.
Limitations and Potential Workarounds
One important consideration is that this detection method is not foolproof. Exploiters can find ways to fully bypass this in the future, such as using the autoexecute feature to run scripts as soon as theyâre loaded, or creating an internal executor in Luau that uses loadstring to execute scripts without leaving a trace (the loadstring would be used from the same script instance). In these cases, the script memory wouldnât increase, allowing the exploit to go undetected.
Either way i hope this can be used as an educational source for the developers wanting to learn how to detect executors and think outside the box!
[EDIT] MUST READ!
StreamingEnabled MUST be turned off in Workspace otherwise localscripts parented under parts would clean from memory.