Preventing Remote Events Logging

This thread is outdated and promotes bad practices, use informationally only.

Introduction

I feel like Roblox Developers’ biggest problem is when someone discovers a way to trick the system into doing an unwanted action. This is mostly done by logging remote event calls, which is possible with exploits.
This thread will in no way secure your Remote calls, and following it blindly will still leave opening spots for exploiters in your game. To ensure your game is safe, you shouldn’t ever trust the client, and should always make sure to do everything that matters on the server.

1. How do Remote Event loggers work?

Remote Event Loggers (or Remote Spies) work by setting the game’s metatable.
The game usually has locked metatable, but exploits can bypass it.

Remote Spies take advantage of __index and __namecall metamethod. Whenever object function is called, it gets indexed and executes whatever __index function returns.

Exploiters change __index function to display the Remote Event arguments and then call the original function to get the return values which are passed back to the client.

2. How to prevent?

There are a few ways that I know of:

1. Indexing the function

One way would be to index the function at the start.
The only down-side is only the fact you can’t call the remotes using :, but you have to pass the remote as the 1st argument (self). This method works for most exploits, but sadly not all of them, as new exploits have new ways of logging like binding functions to it without using metatables. As far as I know, some games use this method already.

Example :

local RemoteEvent = game:GetService('ReplicatedStorage'):WaitForChild('RemoteEvent')
local FireServer = RemoteEvent.FireServer

FireServer(RemoteEvent, Arguments) --> Won't trigger most loggers
RemoteEvent:FireServer(Arguments) --> Will trigger most loggers

2. Checking whether the function has changed

Another way would be to check whether the function has changed since the start of the game.
The downside to this method is the fact that the client can remove the script and therefore pass the security.
The workaround would be to have two scripts which check when another one gets removed.

Example :

local RemoteEvent = Instance.new('RemoteEvent')
local FireServer = RemoteEvent.FireServer

while wait(1) do
   if FireServer ~= RemoteEvent.FireServer then
      -- The function has changed, the player is logging remote events.
   end
end

If you have any questions or suggestions, feel free to comment and I’ll try to answer. :blush:

26 Likes

Exploits can still override the actual reference to RemoteEvent.FireServer while its stored in a variable, making this moot. Exploits can also override __eq to always return that the real one matches the fake one.

If your response is “yes, but most don’t”, no not right now they don’t. If methods like these become more popular then yes they will.

You shouldn’t care about event loggers. If your remotes are secure it doesn’t matter.

21 Likes

Great thread! However, it’s worth mentioning these ways of preventing remote spies could be patched by the exploit developer at any time.

3 Likes

If I’m not mistaken, a dedicated exploiter could save your game, then go through your client scripts to see how you fire remotes, yes?

1 Like

This is not meant to be a surefire exploit protection. It’s just a simple step you can do to make exploiter’s lives harder. Securing remote events and only doing necessary stuff as user input on the client should definitely be a priority when dealing with security.

1 Like

Most exploits have a function called “hookfunction” where you can hook any c function without “changing” it.

So basically,

hookfunction(Instance.new("RemoteEvent").FireServer, NewFunction)

On any RemoteEvent, whenever FireServer is called, NewFunction will always be called instead no matter what you do and you can’t detect this.

2 Likes

As far as I know, only one exploit currently has that ability (Synapse).
Although, that’s really useful to know. Thanks.

1 Like

Spam a few randomly named events to the server when you call so that when they log they don’t know which is correct and when they send the wrong one it kicks them. No way to stop spying other than trickery on your end. (Of course you need proper client-server connection so each knows the proper key without showing it to the client)

2 Likes

ProtoSmasher has detour_function (Which is like the same thing) and Visenya also has replace_closure (Same thing as hookfunction, but doesn’t work at the moment.)

2 Likes

Nice post, however you got the first part wrong. Most newer remote spy scripts use __namecall (which fires when you use the : operator on an instance) instead of __index. However this is easily beaten by localizing the FireServer function as you described in the post.

Another detection is by checking if it is still a c-function. Most remote spy scripts forget to mask their new FireServer functions with newcclosure (or protect_function for ProtoSmasher.)

local remote = Instance.new('RemoteEvent')
local dump = string.dump
local wait = wait
local pcall = pcall
while wait() do
    if pcall(dump, remote.FireServer) then
        -- // fireserver got changed
    end
end

Anyways, that’s all I have to say. ^.^

8 Likes

Fixed, thanks for letting me know.

For this case, couldn’t you call rawequals instead? It doesn’t invoke __eq.

Even though by default rawequal does return true, rawequal's behavior can be overriden just as easy.

2 Likes