ENet v1.0 🛜 release!

ENET V1.0 🛜

ENET is a package that I have made that makes networking harder for exploiters!
In the past exploiters use a script called “Remote Spy” to watch all the remotes that the client sent to the server so they could call them to make exploits. An example of this would be:

→ Player pressed button for coin and a remote is sent to the server

clickRemoteEvent:FireServer()

An exploiter could see this remote and fire it like 100 times per second.
Note: you should already be implementing server checks so this can’t happen

What ENET aims to do is prevent exploiters from knowing anything about your networking.

:nerd_face:How it works:

When you use ENET can send a publish request to the server a remote event is created and fired with a topic. Let’s use the example from before:

NetworkController:Publish("CoinButtonClicked", arguments)

This would create a remote event with a random id. Then it would fire that remote event with the topic of “CoinButtonClicked”. But wait, wouldn’t that defeat the purpose if the exploiters knew which topic we are firing? Yes, that’s why the topic is encrypted with MurmurHash3. Now the only thing the exploiter knows about are the arguments and a hash for the topic.

Note: Hash seed is synced when player joins.
Hash used.

When the client publishes a remote event is created (like i said before). Then the server starts listening for that remote and when it receives a event it is destroyed and all of the subscription callbacks with the matching hashed topic are called with player and the arguments passed.

local subscription = NetworkService:Subscribe("CoinButtonClicked", function()
    print("Coins!")
end)

Note: This system is pretty much the same from the server to the client as well.

:open_book:Documentation:

How to require ENet:

-- Server would be ENetServer.ENet
local ENet = require(ENetClient.ENet)

Client Methods:

ENet:Publish(topic: string, arguments: table) -> nil

ENet:Subscribe(topic: string, callback: function) -> Subscription

Server Methods:

ENet:Publish(player: player, topic: string, arguments: table) -> nil

ENet:PublishAll(topic: string, arguments: table) -> nil

ENet:Subscribe(topic: string, callback: function) -> Subscription

In both of the modules (server and client) you can enable/disable the option to print out network publishing.
Here is what it looks like:

Sending packet to server:
    Topic: ToggleBuilding[1848782386]
	Remote Id: 453B87AB-8BED-45B6-A3F3-98A773AA1B4F
	Data Size: 0.002KB -- Might not be accurate as it's using length of encoded JSON
	Data:  table: 0xb9ddb79222680c3b  {}

You can also change the lifetime of the remote event in case it never gets fired (default is 1s).

:arrow_down:Download

:cat2:Github

Note: Using ENet will be sending more data to the server(hashed topic) and 2 remotes every publish. This is meant for security and not performance.

Last Updated: 2024-03-19T05:00:00Z

Thanks for reading and if you have any feedback please let me know! :partying_face::balloon::tada::confetti_ball:

20 Likes

This sounds interesting but one thing I didn’t quite get is what if an exploiter runs the function? Like if a local script runs the function like:

NetworkController:Publish("CoinButtonClicked", arguments)

stated above, then can the exploiter not run the same function? Or I am just being stupid here… again.

5 Likes

I think you need to fix some of your codes, like on ENetServer/ENet, you do InvokeClient without player param, there is also no remoteEvent:Fire()

4 Likes

The exploiter won’t know the function thats being run. When they use remote spy they will see a remote event being fired and they wont know what the topic is because its encrypted.

I.E CoinButtonClicked → 12986319865

2 Likes

Just fixed! I forgot to test server to client but now it works fine :+1:

1 Like

Can the exploiter not look into our script?

2 Likes

Not currently, synapseX had a script de compiler but now that thats gone there is none. However in the future there might be one in which is why it’s still always good to remember to do you server checks. ENet helps prevent exploiters, but I can’t fix the source of the problem (roblox)

Edit:
Not to mention that the game that I made this for has it integrated with all of the other anti-tamper methods. This is just a stripped down version. For the game I’m a lead programmer for the services / controllers are all spoofed and if any of them are removed “AntiCheatController” then the player gets removed from the game.

image

Edit 2: Also no matter how hard you try people will always find a way around. Look what happened to apex thats using easyAntiCheat.

Edit 3: Also with the script decompiler the code is not like as we see it. It’s all hard to read. Also if you really want to stop exploiters than you can obfuscate your scripts. If you do that there is like a 0.0001% chance they can modify your remotes. That’s not stopping them from modifying other things tho, it’s just most exploits target remotes as that’s how they can interact with the world / other players.

6 Likes

Most of exploits support (or supported) advanced metatable manipulations, exploiters can find your module in gc table (or using a special function) and manipulate metamethods in order to log every call/index. It still requires a decent Lua knowledge and probably won’t be used by most of exploiters, especially when thier exploit can support decompiling.

Example of those functions:
https://fluxusrbx.gitbook.io/fluxus/table-functions
https://fluxusrbx.gitbook.io/fluxus/script-functions
(Exists in most exploits)

3 Likes

Btw I think you need to check on HashSeed if GetAttribute HashSeed is not nil then SetAttribute it , or else ignore it, since sometimes Client doesn’t receive the HashSeed which makes the seed becomes 0.

1 Like

Yeah obviously nothing I can do to prevent all exploits, this just helps prevent script kiddies / skids from easily manipulating your games remotes.

1 Like

This was fixed! :+1:Added hash check beofre calling hash module.

Can’t exploiters use hookfunction or replaceclosure to hook on the function and retrieve the arguments that way?
debug.getregistry will return a list of isolated C values represented as Lua values, completely isolating an attack and being virtually undetectable. getgc will virtually do the same, but getgc may have unstable results as old script instances don’t have their values cleaned from the garbage collector.

A good way, but not fool-proof, to combat this is to check the call stack by using debug.traceback as hookfunction/replaceclosure requires additional functions to be created, and since these functions are created through the executor, debug.traceback will catch this assuming the exploiter hasn’t hooked on that function either.
printidentity inside of the function will also catch this due to the executor often having an identity of RobloxScript or higher.
You can also intentionally use error to get the traceback that way, as a lot of exploiters don’t often think of hooking on error, but now that I’ve said it here they probably might if there’s a targeted attack against this script.

Also, most RemoteSpys nowadays use hookmetamethod or other hook functions to isolate itself from the Game metatable. Any good RemoteSpy will do this, and as long as you send a request to the server, it will be caught by such methods.

If you need, I can help you with anti-cheat measures to combat these and make it very difficult for exploiters to circumnavigate it. Not impossible, but just hard.


I do recommend making this a script for the server and client, where the server will have jobs to

  1. Sanitize Values - Ensure the server is getting what it should be getting from the client.
  2. Use Multiple Events - For a sort of “authoritative server system”. Not as secure, but will catch most skids. You should always queue these additional requests though (on the client and server), as sending a lot of requests to the server will quickly exhaust the OutgoingKBPSLimit on clients when multiple events are used (and will often cause the server to start ratelimiting clients and putting those events in a queue, often seen as a warning in server log "[playername] appears to be spamming remote events.").
  3. Immediately Flag Users - For when things go awry and request additional review. Should also give the developer the option to log it somewhere, but by default flags will be stored in a GlobalDataStore structure and whenever admins/developers or the owner joins the game, they will be notified about new events.
  4. Use GUIDs often - A randomized string that is extremely hard to predict. Also not as secure, as exploiters can just hook the HttpService:GenerateGUID namecall.

Keep in mind that if exploiters get access to the functions in this script, they can always see and modify constants that are declared with-in it with getconstants/getconstant and setconstant respectively. Declare everything outside of the function (as a local variable, as globals can also be retrieved with getsenv), if possible, and only declare constants with-in the function if there is no other choice.

Examples of constants:

  1. Variable declaration or value retrieval/assignment
    Such as:
    • local a = "Hello" Constant: "Hello"
    • local a = 4 Constant: 4
    • local a = sometable.somevalue/local a = sometable["somevalue"] Constant: somevalue (represented as a string) (is effective even when sometable is declared outside or with-in the function)
    • sometable.somevalue = "World" Constants: somevalue and "World"
  2. Function arguments
    Such as:
    • somefunc("Hello", "world!") Constants: "Hello" and "world!" (is effective even when somefunc is declared outside or with-in the function)

A constant is basically anything with-in a given stack that is expected to stay the same regardless of outside influence. Unfortunate thing is that this is all freely accessible in memory, so they can always be modified.

And be careful when setting local variables inside functions as well, as that’s what the entire upvalue programming interface aims to allow easy interfacing with (debug.getupvalues, debug.getupvalue, debug.setupvalue).

2 Likes

Yea, I was unaware of most of this as I have only seen stuff about exploiting and other exploit prevention scripts. I will take this into account when updating this module :+1:

1 Like

Good work though, as what I mentioned is just a hyper-analysis on secure events, not something to shut down completely valid work. Things like anti-cheats always require critical thinking, and that’s what I was aiming to achieve.

1 Like

why is it just a module script with children modules. it take to much space in explorer.

As the creator stated this is meant for security not performance or in this case Aesthetic

2 Likes

What are some ways that you can do server checks?

1 Like

Just check the data being sent in on the server. Make sure they are the right types and reasonable. If you set up your game correctly it will be hard for exploiters to manipulate data they are not supposed to.

2 Likes

HashUtility modulescript is exposed in ReplicatedStorage (doesn’t matter even if it was nil you could get it with exploits)

Exploiter can just hookfunction your :Hash() function to “decrypt” hashed string and that means your “security” is just useless at this point

1 Like

You cant decrypt it, thats the whole point of a hash.

1 Like