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.
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.
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.
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?)
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.
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.
(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.
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.