Client Anti Cheats: Aren't as bad as you think!

you could find the actor in the gc (since everything deleted goes in the GC) you could find it

you can’t bypass getgc, as the script/any object will always get garbage collected if destroyed, it’s just how lua works

I’m guessing that you need a name for it, so what happens if the actor and the local script has a random name?

From what I know they use something like this:

for _, f in next, getgc() do
    if not islclosure(f) then continue end

    for _, c in next, debug.getconstants(f) do
        if tostring(c) and tostring(c):lower():find("anti cheat") then
            hookfunction(f, function(...)
                return task.wait(math.huge);
            end);
            break;
        end;
    end;
end;

How would this work if the local script has a random name in every server, and It doesn’t error, the same goes for the actor.

And what happens if the local script is obfuscated, since it apparently effects the decompiler?, and what would happen if the hidden local script, creates new local scripts, with a random name and destroy them every microsecond?

Then again only synapse has run_on_actor, the free executors don’t have that function iirc.

nope, you just need to find a function in gc that is for the corresponding script and getinfo it as seen below:

for i, v in pairs(getgc()) do
    if type(v) == "function" then
        print(debug.getinfo(v).short_src) --if destroyed, will show original path (still can be decompiled)
    end
end

an exploiter could just hook the __namecall, __index, and __newindex to construct the anticheat based on these 3 metamethod calls (painful but done sometimes)

won’t be in gc (?) because no luau bytecode is associated with the localscript

1 Like

Funny story, but they have a cool little function called getgc() :wink:

The only way the actual client would be able to send a valid one then is a server needs some sort of salt if the intended scripts/client can receive the salt, so can the exploiter.

One script published and your done

Due to the fact this is usually a lengthy and stupid argument, I won’t continue this. Just secure the server

What if the local script has no local function, or doesn’t use functions or tables in general.

With obfuscating code, I meant using math operations, or using other techniques, how would __namecall or __index, __newindex affect the local script code?

roblox might make a function automatically (i forgot if they do or don’t) that will always go to the gc, you also might be able to find the original script environment in the GC too

if a exploiter hooked all three metamethods, they could reconstruct the script by doing what the localscript is doing (for ex: i call game.Workspace:FindFirstChild("abc"), __index will get fired for game and Workspace, __namecall will get fired with the self workspace, namecallmethod FindFirstChild, arg 1 being abc)

most exploits with decompilers can resolve the math equation automatically, a lua VM obfuscator like ironbrew 2 would work well for obfuscating, but it has to be modified to prevent constant dumping (which can be done by just hooking table.concat and printing what is sent to the func)

Well, I did some research, but apparently, as long the local script is on the actor (both “hidden”), exploiters aren’t going to be able to find the info or get the info of the script, unless they use synapse (Which like I said earlier, byfron pretty much killed paid exploits atm), “because actors run under entirely different global states”, so I’m assuming It’s the best way to secure a local script atm, even if they aren’t foolproof.

If an exploiter tries to “ignore” the handshake, such as by blocking the RemoteEvent, the server will kick them.

Handshakes work like this:

The server sets a tick value. The client fires a RemoteEvent with a randomly generated encrypted key. The server checks the key and resets the tick value.

Then, in a loop, the server checks if the tick value exceeds a certain time limit, such as 30 seconds, and will kick them.

Key should be randomly generated and encrypted, a new key each time a RemoteEvent gets fired.

1 Like

But even if you hide a local script parented on nil or destroyed (since Instance:Destroy() don’t really “destroy” just disable connexions and parent to nil), the client, with the correct programs will continue been able to delete the parented with nil scripts or edit them. No? I mean, he can also disable some parts of the script to make that the important things (that ones who fire the server) continues working.
Is that true or im bad informated?

This also completely removes it from its environment. The script will not be able to be seen in:

  1. getscripts()
  2. getnilinstances()
  3. saveinstance()
  4. Dex Explorer

And the script will continue to run completely fine.

1 Like

Yes but the program wich uses the client to hack, can use more than this methods, (can create or modify as much methods as want). So the script can be harder to find but not imposible, no?

They could hook getfenv() upon auto execution and stop the script from hiding itself, however, most environments hooks I’ve seen simply do not return the script so you could check if script.Parent errors which would detect it. its definitely possible for them to hook the environment hide and stop it from hiding itself however it can be prevented.

1 Like

Ok, thanks for the aclaration. Anyways I would prefer don’t using the client as manager of some things.

What if we just use the method he already mentioned at the very start of the conversation?

I’ve contacted 3 of my exploiting friends, just to test if the script is able to detect them injecting, and they all got caught red-handed.

Maybe we shouldn’t focus on hiding local scripts for exploiters to never get, but maybe using server scripts to check on the client’s behavior.

3 Likes

I am sorry, but how would you check for client exploits on the server?

1 Like

My friends told me that when they inject they lag for a split second so it can get access to everything client-sided in the game, which spikes the Client Memory Usage.

If it spikes, then we can check for that to then kick the player.

Even though this is in a local script, it kicks the player prior to attempting to inject, so nothing would get deleted.

Using memory checks is indeed effective however it can cause many false positives (also known as false detections) in big maps or laggy players

You don’t need to make the detection very strict. My friends said they usually get 300-700MB+, then back to normal.

If someone is still reading this, you can use this for simple detection methods, while being fully protected againts hookmetamethod or hookfunctions attacks, not even auto execute can destroy/Disable the local script, Exploiters can’t also find the actor with auto execute and loop in ReplicatedFirst.

The only bad thing is that you are not going to be able to detect hookmetamethods or hookfunctions, keep in mind destroying things still affects the local script, but yeah, this is useful if you want to make simple anti cheats while not having to worry about spoofs.

That means that player:Kick() on the client will still work even if they “hook” it.
I recommend making a server sided script inside ServerScriptService, that changes the name of the local script and actor.

local ReplicatedFirst = game:GetService("ReplicatedFirst")
local Actor = ReplicatedFirst:WaitForChild("ACTORNAMEHERE")
local LocalScript = Actor:FindFirstChild("LOCALSCRIPTNAMEHERE")

Actor.Name = ""
LocalScript.Name = ""
-- DONE :D

EDIT: Also forgot to mention but actors are immune to getconnections().


Apparently someone already bypassed byfron, with the exact same program, I don’t why this “Tool” isn’t in the blacklist, but yeah, they apparently bypassed it using the new version, my theory is, I think byfron is different in every client so that’s why there’s not an actual bypass, but that’s just a theory.

Hopefully, bitdancer decides to do something about this. :skull:

2 Likes