Is there's any ways to prevent exploiters from reading Local Scripts?

I’m making 2D game, which consist of 2 scripts. 1 of them - GIANT local script, which handles almost all gameplay, but second NOT LOCAL script handles DataStore, MarketplaceService, and etc. Is there any way to “hide” Local script from exploiter, so he won’t be able to stole my game? (My game really consists of only 2 scripts, local script creates all GUI objects with which player can interact with game. There’s no any characters, parts in Workspace and etc.)

3 Likes

Unfortunately, no there’s not. The most you can do is obfuscate your code, but that’s not immune to tampering. In the end, never trust the client. If you’re worried about exploiters cheating, just make sure to handle any relevant secure data server-side. If it’s about exploiters stealing your game, you’re kind of out of luck. Best you can do is obfuscate your code and put a GameId check, but that won’t work forever.

4 Likes

From what I know, you practically cannot do anything about this. Data has to be sent to the client in order for it to show and do anything.

If your 2d game is multiplayer, the best you could do is add some sanity checks on the server to make sure the player isn’t doing anything fishy.

3 Likes

Is it multiplayer? If so, you can have the server move the character and tell the other players the server character’s position, and only have the client tell the server the player’s inputs. This is what most 3D games outside of Roblox do.

Ah, sorry.

@GamEditoPro specifically mentioned wanting to prevent exploiters from reading a LocalScript. That’s what I was referring to.

1 Like

It’s also a major cause of either rubberbanding or input lag, depending on how you handle it. There are advantages to allowing local control over characters, and using a loose speed and position verification on the server to catch noclipping, teleporting, speeding, etc.

Nope, my game is singleplayer.

You can always move the local version of the character first and wait for the server’s response afterwards, if the server character is in a different place (which is going to happen very little most of the time) then move the local character to the correct position.

That is how many games outside of Roblox do it

https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking#Input_prediction

I have been working on large custom 2D gui pixel based games for about a year now and I all can say is that there isnt much you can do.

One of my 2D games is pretty large and consists of a single local script with 2000+ lines of code, and obviously you wouldn’t want some random exploiter to take your whole game.

Even though your games are already technically protected from being stolen and claimed as someones else, it sometimes wont be enough.

So what I would do is ensure the game cant be stolen from someone who can’t script (or is not experienced)

Some methods you can use are;

  • Add a feature to the game that NEEDS a server script (such as a saving/loading system)
  • Add checks to the game in your code to ensure its in your game (as mentioned above from other users)
  • Build your game using lots of modules/scripts (decompiling heaps of scripts can be tedious and will usually take a long time)
  • Thread in as much checks into the code as possible to ensure your game wont run on other places (you can even go ahead and somehow link your code to these checks so the exploiter cant just delete the line of code, otherwise the game will just break)

That’s what rubberbanding is. I’m fully aware that this is common practice in games where the networking is written by the developers, but Roblox is a special case because the developers generally have less experience with networking concepts and development in general, and the majority of our needs are handled by the platform. In creating a 2D engine on Roblox you will need to create your own network system, but I really don’t think it matters enough in this scenario to be the deciding factor. Client-authoritative systems are more intuitive and have their own advantages, and It wouldn’t take that much work to change it later.

Nope, not possible. However, Roblox does automatically obfuscate your code and better protects it, making it harder for exploiters to edit it.

Sorry for the late response, I was researching this topic and I think the best thing you could do is
obfuscate. It may not be the most effective if you’re trying to write code and should only be done after the fact.

I hope this helps.

Many exploits can get around the obfuscation, however, you yourself can use more secure means of obfuscation.

There are plenty of methods, there’s even a basic tutorial on how to obfuscate (Obfuscating Lua · GitHub).

Similarly to a fork bomb, using string.dump() can make your code really hard to read.

Hope this helped!

Screenshot 2023-01-04 184943
what is string.dump() and you cant change script source i think

what year do you live in

There are a few ways to prevent exploiters from reading your local scripts. Here are a few options you can try:

  1. Obfuscation: This involves making your code difficult to read by humans by using techniques like variable renaming and code splitting. This can make it harder for exploiters to understand what your code is doing and make it more difficult for them to find vulnerabilities.
  2. Encryption: You can also encrypt your code so that it is unreadable without a key. This can make it more difficult for exploiters to access your code, but it is important to keep in mind that encryption is not foolproof and can potentially be hacked.
  3. Access controls: You can use Roblox’s built-in access controls to limit who can access certain parts of your game or certain functions in your code. For example, you can set up a whitelist of approved players who are allowed to access certain features of your game.

Here is an example of how you might use these techniques in a script.

Obfuscation example
-- Obfuscation:
local secretNumber = math.random(1, 100)

local function getSecretNumber()
    return secretNumber
end

-- Encryption example:
local encryptedCode = "f89a8f9a8f9a8f9a"

local function decrypt(key)
    -- Decrypt the code using the key
end

-- Access control example:
local approvedPlayers = {
    ["player1"] = true,
    ["player2"] = true,
    ["player3"] = true
}

local function checkIfPlayerIsApproved(player)
    if approvedPlayers[player.Name] then
        return true
    end
    return false
end

game.Players.PlayerAdded:Connect(function(player)
    if checkIfPlayerIsApproved(player) then
        -- Allow player to access game features
    else
        -- Block player from accessing game features
    end
end)

Encrypting your code can help to prevent exploiters from reading it, as it makes the code unreadable without a key. However, it is important to keep in mind that encryption is not foolproof and can potentially be hacked.

Here is an example of how you might use encryption in a script:

Encryption example

local function decrypt(key)
    -- Decrypt the code using the key
end

local function runEncryptedCode()
    local decryptedCode = decrypt(encryptedCode, key)
    run(decryptedCode)
end

In this example, the encryptedCode variable contains the encrypted version of your code. The decrypt function takes the encrypted code and a key as input, and returns the decrypted code. The runEncryptedCode function calls the decrypt function to get the decrypted code, and then runs it using the run function.

To use this code, you would need to provide the key that is used to decrypt the code. This key could be stored in a separate file or passed in as a command-line argument, for example.

Access controls allow you to limit who can access certain parts of your game or certain functions in your code. For example, you can set up a whitelist of approved players who are allowed to access certain features of your game.

Here is an example of how you might use access controls in a script.

Access controls example
local approvedPlayers = {
    ["player1"] = true,
    ["player2"] = true,
    ["player3"] = true
}

local function checkIfPlayerIsApproved(player)
    if approvedPlayers[player.Name] then
        return true
    end
    return false
end


game.Players.PlayerAdded:Connect(function(player)
    if checkIfPlayerIsApproved(player) then
        -- Allow player to access game features
    else
        -- Block player from accessing game features
    end
end)

In this example, the approvedPlayers table contains a list of players who are approved to access certain game features. The checkIfPlayerIsApproved function takes a player as input and returns true if the player is on the approved list, and false otherwise.

The PlayerAdded event is triggered whenever a new player joins the game. The event handler function checks if the player is approved using the checkIfPlayerIsApproved function. If the player is approved, they are allowed to access certain game features. If the player is not approved, they are blocked from accessing these features.

Here let me show you an alternative. I’m used to Luajit, not Luau I apologize.

string.dump() doesn’t work because I believe it was depreciated. (Look here for more info).

You can use an alternative such as string.sub() or string.gmatch(), they work just as well.

2 Likes

The name of variables are not saved in compiled Luau bytecode, exploits already do not have access to variable names.

What, are you going to use loadstring() on the client too? Exploits can very easily look at the localscript’s memory for the decryption key, or just hook the decryption function to look at what data it is returning.

All of your suggestions won’t prevent a localscript from being read, unless you want to restrict features to developers or something.

1 Like
                                               ⚠️ Warning ⚠️

I’m only trying to help

This code was made by AI

You are correct that the names of variables are not saved in compiled Luau bytecode, so exploiters will not be able to see the names of your variables. However, obfuscating your code by renaming your variables can still make it more difficult for exploiters to understand what your code is doing.

For example, consider the following code:

local secretNumber = math.random(1, 100)

local function getSecretNumber()
    return secretNumber
end

print(getSecretNumber())

Even though the name of the secretNumber variable is not saved in the compiled bytecode, an exploiter could still figure out what the code does by reading the function names and the function bodies.

Now consider the following code:

local a = math.random(1, 100)

local function b()
    return a
end

print(b())

In this version of the code, the names of the variables have been changed to single letters. This makes the code more difficult to read and understand, as it is not immediately clear what each variable represents. An exploiter would have to spend more time and effort trying to understand what the code is doing, which can make it harder for them to find vulnerabilities.

It is important to note that obfuscation is not a foolproof method for preventing exploits, as determined exploiters may still be able to reverse engineer your code. However, it can make it more difficult for them to do so and may deter some exploiters from attempting to exploit your game.

You are correct that the methods I suggested will not completely prevent a local script from being read. While obfuscation, encryption, and access controls can make it more difficult for exploiters to read and understand your code, they may not be foolproof and determined exploiters may still be able to reverse engineer your code or find ways to access it.

One option you could consider is restricting certain features to developers or trusted users. For example, you could set up a system where only developers or trusted users are allowed to access certain parts of your game or certain functions in your code. This can help to prevent exploiters from accessing these features, as they are not likely to have developer or trusted user status.

It is also a good idea to keep your code as simple and secure as possible. This can help to reduce the number of vulnerabilities in your code and make it less likely that exploiters will be able to find and exploit them. You should also stay up to date with the latest security best practices and make sure to apply them to your code.

Finally, you should also monitor your game for suspicious activity and take steps to ban or otherwise prevent exploiters from accessing your game. This can help to protect your game and your players from exploits.

Neat contradiction. What’s the point of renaming your variables to single letters (and making it harder to edit for yourself) if they aren’t even saved in the bytecode, making it completely useless to do? All the exploiter will always see is simply something like “local_1” for the variable names, a sort of “automatic” obfuscation if I may.