Having trouble with exploiters? Unsigned can help!

Ok it’s a good idea and thought out but here’s a situation where it might not work:

I have a gun system where I need to have a remote event fired? It would be a bit hard to find the remote and a exploiter could look at that code and find it should I use this module or have my own detection?

Unsigned mitigates this issue by using the UnsignedEvent object that you create with Unsigned:AddEvent().

-- Get Unsigned Module
local Unsigned = require(path.to.Unsigned)

-- Get Event
local Event_Object = game.ReplicatedStorage:WaitForChild("Event")

-- Create UnsignedEvent object
local Event = Unsigned:AddEvent(Event_Object)

-- Initialize Unsigned
Unsigned:Init()

No matter what happens to the Event, you will always have access to it. The only difference is you have to create a UnsignedEvent object in order to interact with it.

If you have any questions, please do ask.

1 Like

Ok and in this local script a hacker could view this code and activate the Unsigned event?

While exploiters may be able to view the LocalScript, they are not able to inflict any harm onto the script. So, you should be fine.

1 Like

very good then I would see this being used in a fps or simulator

This module is waiting to be exploited, besides, this is completely unnecessary if you know how to protect your remotes in the first place. You don’t need to “hide” them (as stated here) if you just make server side checks which make it so firing the remote for exploitative purposes is rendered useless.
GUI detection is also a pointless endeavor, as you can just draw the GUI to the screen, making it impossible to detect, or it can be easily patched if anything.
The module is coded a little inefficiently, as the UnsignedLogger class literally has 3 almost copy-and-pasted functions, which is extremely redundant.

9 Likes

Really well thought out, this is very useful, I’ll try it out

1 Like

Your better off learning how to actually protect your remotes instead of thinking that you are safe just because you are using this module.

4 Likes

I never said I ai t going to do it, I know that learning things yourself is always better than getting a ready-to-use product

Also, I’m not an expert and I didn’t look at the code, but as you are an expert Programmer, what is wrong with this script?
(Asking this so I will learn in the future)

local logger = {}

function logger:Log(...: table)
    local message = ""

    if type(...) == "table" then
        for _, arg in pairs(...) do
            message = message..arg.." "
        end
    else
        message = ...
    end

    print(
        "Unsigned:",
        message
    )
end

function logger:Warn(...: table)
    local message = ""

    if type(...) == "table" then
        for _, arg in pairs(...) do
            message = message..arg.." "
        end
    else
        message = ...
    end

    warn(
        "Unsigned:",
        message
    )
end

function logger:Error(...)
    local message = ""

    if type(...) == "table" then
        for _, arg in pairs(...) do
            message = message..arg.." "
        end
    else
        message = ...
    end

    error("Unsigned: "..message)
end

return logger

This is quite literally 3 functions copy and pasted with a single line changed on each one (to specify if it is printing, warning, or erroring)

edit: It’s also pointless, because looking through init.lua, it is used exactly the same as the print, warn and error functions, which means this is just overcomplicating a simple function call.

1 Like

Okay, how is this even useful?
I don’t understand, simply send an Argument to the function and check the Argument, if it’s one print, else warn, else error
(That’s how you do it right?)

It’s not useful, it’s just clutter.

if self.Initialized then
        Logger:Error("Objects cannot be added after initialization.")
end

This line uses it exactly like error(), which makes the entire point of having some ‘custom logger’ class redundant. The extra work to do this makes it way slower than doing it in a normal way.

It doesn’t help that this module obfuscates remote names on RunService’s Heartbeat function, and not to mention that an exploiter doesn’t need the exact name of a Remote, as you can just iterate through ReplicatedStorage and assign a variable to each Instance you find returns true on the :IsA call.

2 Likes

Okay, I understand now, I wouldn’tve been able to see those with my current experience :sweat_smile:

1 Like

I programmed these with the intention of keeping it clean, but it seems that yes, you are right. Also, Unsigned is not going to single-handedly be only about hiding remotes while it may seem redundant, it restricts the environment that the attacker could use.

Your completely fine. You don’t realize this stuff unless you have seen how exploits work and understand the methods behind how it’s done. It makes you think differently about networking and protection.

1 Like

I actually didn’t thought of this!
It’s a pretty smart move to do this method

(Although I’ve never been in this situation)
I completely agree and understand, if you’ve been a criminal and you join the police you are gonna be way better, because you know how criminals do their work, and you have a bigger view of the system

While this is a good idea, there are flaws that can come into play here.

Synapse X for example has an advanced system – such system allows this entire module to be bypassed. One such way is this: remote event names are static; using any remote logger will allow you to receive the name of the RemoteEvent and it’s arguments. All you need to do is use getnilinstances().

local instances = getnilinstances()

for i,v in pairs(instances) do
    if v:IsA("RemoteEvent") then
        print(v.Name)    
    end
end

This allows you to call the FireServer() method on the RemoteEvent with no checks whatsoever

After testing, it appears you parent the RemoteEvent to game.ReplicatedStorage; all I need to do then is have a .ChildAdded or .DescendantAdded hook to determine the correct remote event.

local r = game.ReplicatedStorage

local event
r.DescendantAdded:Connect(function(m)
    if m:IsA("RemoteEvent") then
        event = m
    end
end)

while task.wait(2) do
    event.Parent = game.ReplicatedStorage
    event:FireServer()    
end

Your module is a great idea, but it unfortunately can’t stop exploiters in this way.

2 Likes

There’s no way to index the remote (Unless I screwed up royally somewhere). I have tested it thoroughly, even using you’re method that you mentioned. The Remote is parented to nothing, not even the game. It is only parented for when it is needed to be called even so, it doesn’t last long enough to be indexed. While I understand the better practice would be to just make the server the authority figure over the client, I found it helped overall, due to it causing a roadblock for exploits by not being indexable.

You’re explanation makes a lot more since. But my main goal is to at least disable the free executors. But also I didn’t know of getnilinstances() until now.