Help needed with basic understanding of encrypting stuff in Roblox

Hi pros. I am such a noob. Jk. Not really. But I feel pretty dumb for not knowing the answer to a question that I have despite having been coding on Roblox for so many years.

Let’s say you have a table like this.

local table = {

[1] = "Apple",

[2] = "Banana"

}

How do you make the values and strings in this table encrypted to where it would show something like this when decompiled?

local v1 = {

[1] = v2,

[2] = v3

}

I just want it to where the words apple and banana are not visible in the script any longer by encrypting it but I’m not exactly sure the best way to do that.

Yout cannot hide strings from being decompiled so long as they exist on the client side. Strings are one of the easiest things to extract.

1 Like
local function xorEncode(text, key)
    local result = ""
    for i = 1, #text do
        local charCode = string.byte(text, i)
        local keyCharCode = string.byte(key, (i % #key) + 1)
        result = result .. string.char(bit32.bxor(charCode, keyCharCode))
    end
    return result
end

local originalTable = {
    [1] = "Apple",
    [2] = "Banana"
}

local key = "MySecretKey"

local encodedTable = {}
for i, str in pairs(originalTable) do
    encodedTable[i] = xorEncode(str, key)
end
1 Like

ok I have this decompiled script of a bunch of code that is from an encryption module that supposedly encrypts the entire script somehow so I want you to take a look at it and explain how it works

-- Time to decompile: 0.2666795999975875 seconds

-- Debug Info
-- # of Constants: 24
-- # of Protos: 16

-- Constants
-- [1] (number) = game (string)
-- [3] (number) = HttpService (string)
-- [4] (number) = GetService (string)
-- [5] (number) = userdata: 0xd8be5b8c6a889be6 (userdata)
-- [6] (number) = userdata: 0x97314c5a416a1196 (userdata)
-- [7] (number) = userdata: 0x611472c99fcc8786 (userdata)
-- [8] (number) = userdata: 0x3317123d906d01b6 (userdata)
-- [9] (number) = userdata: 0x874a350d48018ba6 (userdata)
-- [10] (number) = userdata: 0x3dfda8d160601556 (userdata)
-- [11] (number) = userdata: 0x7280877109c29c46 (userdata)
-- [12] (number) = userdata: 0x86e3fffcd37fe576 (userdata)
-- [13] (number) = userdata: 0xee46c66edefcb266 (userdata)
-- [14] (number) = userdata: 0x2a282cd886667916 (userdata)
-- [15] (number) = userdata: 0x863b382e6bc9c006 (userdata)
-- [16] (number) = userdata: 0xde2e5d3c3d68c936 (userdata)
-- [17] (number) = userdata: 0xdbd1722ff70e5226 (userdata)
-- [18] (number) = userdata: 0x89947340236ba6d6 (userdata)
-- [19] (number) = userdata: 0x4ef79bee5dd6ecc6 (userdata)
-- [20] (number) = userdata: 0xe37ab87c9411b4f6 (userdata)
-- [21] (number) = EncryptData (string)
-- [22] (number) = DecryptData (string)
-- [23] (number) = generateKey (string)
-- [24] (number) = table: 0x99930e859fd20de6 (table)
--   ['EncryptData'] (string) = 0 (number)
--   ['generateKey'] (string) = 0 (number)
--   ['DecryptData'] (string) = 0 (number)

-- Proto Info
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x8ecf156fdfd05a76
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0xadb5c38b039790f6
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0xc0d0ea27610f0c36
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x204f0f36ec11dfb6
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x81a66bc4b9638f36
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x659cd7bb6a583eb6
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0xbc75dabdd534ee36
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0xece29cbf30c061b6
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x33d3e697324f5f16
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x0c054f54ec72fc16
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0xbb7eafaeff3abb56
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x4c350c6fd4b7eb16
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0xecfa390ce71ba6f6
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x63a8a6c186ee5456
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0xab98937395fb1e36
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 
-- ''
--   ['source'] = 
--   ['what'] = Lua
--   ['numparams'] = 0
--   ['func'] = function: 0x90cfdfeaa294c196
--   ['short_src'] = [string ""]
--   ['currentline'] = 1
--   ['nups'] = 0
--   ['is_vararg'] = 1
--   ['name'] = 

local u1 = game:GetService("HttpService")
local function u10(p2) --[[Anonymous function at line 7]]
    return (p2:gsub(".", function(p3) --[[Anonymous function at line 9]]
        local v4 = p3:byte()
        local v5 = ""
        for v6 = 8, 1, -1 do
            v5 = v5 .. (v4 % 2 ^ v6 - v4 % 2 ^ (v6 - 1) > 0 and "1" or "0")
        end
        return v5
    end) .. "0000"):gsub("%d%d%d?%d?%d?%d?", function(p7) --[[Anonymous function at line 13]]
        if #p7 < 6 then
            return ""
        end
        local v8 = 0
        for v9 = 1, 6 do
            v8 = v8 + (p7:sub(v9, v9) == "1" and (2 ^ (6 - v9) or 0) or 0)
        end
        return ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"):sub(v8 + 1, v8 + 1)
    end) .. ({ "", "==", "=" })[#p2 % 3 + 1]
end
local function u19(p11) --[[Anonymous function at line 22]]
    return string.gsub(p11, "[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=]", ""):gsub(".", function(p12) --[[Anonymous function at line 25]]
        if p12 == "=" then
            return ""
        end
        local v13 = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"):find(p12) - 1
        local v14 = ""
        for v15 = 6, 1, -1 do
            v14 = v14 .. (v13 % 2 ^ v15 - v13 % 2 ^ (v15 - 1) > 0 and "1" or "0")
        end
        return v14
    end):gsub("%d%d%d?%d?%d?%d?%d?%d?", function(p16) --[[Anonymous function at line 30]]
        if #p16 ~= 8 then
            return ""
        end
        local v17 = 0
        for v18 = 1, 8 do
            v17 = v17 + (p16:sub(v18, v18) == "1" and (2 ^ (8 - v18) or 0) or 0)
        end
        return string.char(v17)
    end)
end
local function u26(p20, p21) --[[Anonymous function at line 39]]
    local v22 = 1
    local v23 = 0
    while p20 > 0 or p21 > 0 do
        if p20 % 2 ~= p21 % 2 then
            v23 = v23 + v22
        end
        local v24 = p20 / 2
        p20 = math.floor(v24)
        local v25 = p21 / 2
        p21 = math.floor(v25)
        v22 = v22 * 2
    end
    return v23
end
local function u31(p27) --[[Anonymous function at line 56]]
    --[[
    Upvalues:
        [1] = u26
    --]]
    local v28 = 4294967295
    for v29 = 1, #p27 do
        v28 = u26(v28, (string.byte(p27, v29)))
        for _ = 1, 8 do
            if v28 % 2 == 0 then
                v28 = v28 // 2
            else
                v28 = u26(v28 // 2, 3988292384)
            end
        end
    end
    local v30 = v28 % 256
    return string.char(v30)
end
local function u38(p32, p33) --[[Anonymous function at line 73]]
    local v34 = p32
    for v35 = 0, 7 do
        bit32.band(p32, 1)
        local v36 = bit32.band(p33, 1)
        local v37 = bit32.lshift(v36, v35)
        v34 = bit32.bxor(v34, v37)
        p32 = bit32.rshift(p32, 1)
        p33 = bit32.rshift(p33, 1)
    end
    return v34
end
local function u47(p39, p40) --[[Anonymous function at line 86]]
    --[[
    Upvalues:
        [1] = u38
    --]]
    local v41 = {}
    for v42 = 1, #p39 do
        local v43 = string.byte(p39, v42)
        local v44 = (v42 - 1) % #p40 + 1
        local v45 = u38(v43, (string.byte(p40, v44)))
        local v46 = string.char(v45)
        table.insert(v41, v46)
    end
    return table.concat(v41)
end
local function u55(p48, p49) --[[Anonymous function at line 98]]
    local v50 = ""
    for v51 = 1, #p48 do
        local v52 = p48:byte(v51)
        local v53 = p49:byte((v51 - 1) % #p49 + 1)
        local v54 = bit32.bxor(v52, v53)
        v50 = v50 .. string.char(v54)
    end
    return v50
end
local function u62(p56, p57) --[[Anonymous function at line 109]]
    --[[
    Upvalues:
        [1] = u55
    --]]
    local v58 = 16 - #p56 % 16
    local v59 = p56 .. string.char(v58):rep(16 - #p56 % 16)
    local v60 = ""
    for v61 = 1, #v59, 16 do
        v60 = v60 .. u55(v59:sub(v61, v61 + 16 - 1), p57)
    end
    return v60
end
local function u67(p63, p64) --[[Anonymous function at line 120]]
    --[[
    Upvalues:
        [1] = u55
    --]]
    local v65 = ""
    for v66 = 1, #p63, 16 do
        v65 = v65 .. u55(p63:sub(v66, v66 + 16 - 1), p64)
    end
    return v65:sub(1, -v65:byte(-1) - 1)
end
local function u85(p68, p69) --[[Anonymous function at line 132]]
    --[[
    Upvalues:
        [1] = u47
        [2] = u62
        [3] = u55
        [4] = u31
        [5] = u10
    --]]
    local v84 = (function(p70) --[[Function name: bitwiseSwap, line 155]]
        local v71 = ""
        for v72 = 1, #p70, 2 do
            local v73 = p70:byte(v72)
            local v74 = p70:byte(v72 + 1) or 0
            v71 = v71 .. string.char(v74) .. string.char(v73)
        end
        return v71
    end)((u55((function(p75, p76) --[[Function name: rotateBits, line 140]]
        local v77 = ""
        for v78 = 1, #p75 do
            local v79 = p75:byte(v78)
            local v80 = bit32.lshift(v79, p76)
            local v81 = 8 - p76
            local v82 = bit32.rshift(v79, v81)
            local v83 = bit32.bor(v80, v82) % 256
            v77 = v77 .. string.char(v83)
        end
        return v77
    end)(u62(u47(p68, p69), p69:sub(1, 16)), 3), p69:sub(1, 16))))
    return u10(v84 .. u31(v84))
end
local function u108(p86, p87) --[[Anonymous function at line 175]]
    --[[
    Upvalues:
        [1] = u19
        [2] = u31
        [3] = u55
        [4] = u67
        [5] = u47
    --]]
    local v88 = u19(p86)
    local v89 = #v88
    local v90 = v88:sub(1, v89 - 1)
    local v91 = v88:sub(v89)
    local v92 = u31(v90)
    local v107 = u47(u67((function(p93, p94) --[[Function name: rotateBits, line 198]]
        local v95 = ""
        for v96 = 1, #p93 do
            local v97 = p93:byte(v96)
            local v98 = bit32.rshift(v97, p94)
            local v99 = 8 - p94
            local v100 = bit32.lshift(v97, v99)
            local v101 = bit32.bor(v98, v100) % 256
            v95 = v95 .. string.char(v101)
        end
        return v95
    end)(u55((function(p102) --[[Function name: bitwiseSwap, line 183]]
        local v103 = ""
        for v104 = 1, #p102, 2 do
            local v105 = p102:byte(v104)
            local v106 = p102:byte(v104 + 1) or 0
            v103 = v103 .. string.char(v106) .. string.char(v105)
        end
        return v103
    end)(v90), p87:sub(1, 16)), 3), p87:sub(1, 16)), p87:sub(1, 16))
    if v91 == v92 then
        return v107
    end
    warn("Data integrity check failed.")
    return nil
end
local function u114(p109) --[[Anonymous function at line 225]]
    --[[
    Upvalues:
        [1] = u10
    --]]
    local v110 = p109 == nil and 16 or p109
    local v111 = {}
    for _ = 1, math.min(v110, 16) do
        local v112 = math.random(0, 255)
        local v113 = string.char(v112)
        table.insert(v111, v113)
    end
    return u10(table.concat(v111))
end
game:GetService("HttpService")
return {
    ["EncryptData"] = function(u115, p116) --[[Function name: EncryptData, line 271]]
        --[[
        Upvalues:
            [1] = u114
            [2] = u1
            [3] = u19
            [4] = u85
        --]]
        if p116 == nil then
            p116 = u114(16)
        end
        local v117
        if type(u115) == "table" then
            local v118
            v118, v117 = pcall(function() --[[Anonymous function at line 240]]
                --[[
                Upvalues:
                    [1] = u1
                    [2] = u115
                --]]
                return u1:JSONEncode(u115)
            end)
            if not v118 then
                warn("Failed to serialize table: " .. v117)
                v117 = nil
            end
        else
            v117 = u115
        end
        return v117 and {
            ["Status"] = "SUCCESS",
            ["Message"] = "Data was encrypted successfully",
            ["Key"] = p116,
            ["Original"] = u115,
            ["EncryptedResult"] = u85(v117, (u19(p116)))
        } or {
            ["Status"] = "ERROR",
            ["Message"] = "Data encryption FAILED.",
            ["Key"] = nil,
            ["Original"] = u115,
            ["EncryptedResult"] = nil
        }
    end,
    ["DecryptData"] = function(p119, p120) --[[Function name: DecryptData, line 319]]
        --[[
        Upvalues:
            [1] = u19
            [2] = u108
            [3] = u1
        --]]
        local u121 = u108(p119, (u19(p120)))
        if not u121 then
            return {
                ["Status"] = "ERROR",
                ["Message"] = "Data decryption FAILED.",
                ["Key"] = nil,
                ["OriginalEncrypted"] = p119,
                ["DecryptedResult"] = nil
            }
        end
        local v122, v123 = pcall(function() --[[Anonymous function at line 252]]
            --[[
            Upvalues:
                [1] = u1
                [2] = u121
            --]]
            return u1:JSONDecode(u121)
        end)
        if not v122 then
            v123 = u121
        end
        return {
            ["Status"] = "SUCCESS",
            ["Message"] = "Data Decryption Success.",
            ["Key"] = p120,
            ["OriginalEncrypted"] = p119,
            ["DecryptedResult"] = v123 or u121
        }
    end,
    ["generateKey"] = u114
}```

What is the point of all of this? I get that you want to encrypt the table, but why? can’t you just put it on the server side and verify who gets to access it?

I mean, code that clients can see should be non-revealing. So why would you want to do this?

2 Likes
local function v9(p1, p2) --[[Anonymous function at line 1]]
    local v3 = ""
    for v4 = 1, #p1 do
        local v5 = string.byte(p1, v4)
        local v6 = v4 % #p2 + 1
        local v7 = string.byte(p2, v6)
        local v8 = bit32.bxor(v5, v7)
        v3 = v3 .. string.char(v8)
    end
    return v3
end
local v10 = {}
for v11, v12 in pairs({ "Apple", "Banana" }) do
    v10[v11] = v9(v12, "MySecretKey")
end

cooked cus they can easily see this from a decompiler so i dont really get it honestly lol

I love my client anti cheat and i’m trying to perfect it but with the fact they can see stuff like strings from decompiler it makes it more challenging thats for sure

This looks like obfuscation, which is not encryption. You can’t change the strings without changing what the program does, while you can change the names of variables.
Let me promise you 100% that any code that is on the client can be reverse engineered no matter how much you obfuscate it. That should not be your priority.

it’s decompiled. Not intentionally obfuscated. That is all that the decompiler can grab. But it’s a lot. Because if you use apple and banana for something important on the client side, the decompiler becomes very tedious to deal with when trying to make a secure client anti cheat. I have my ways… and i’m certainly not worried about anyone bypassing mine. It’s pretty darn strong. But it could definitely be stronger if there is some way to encrypt the information

image
man what

Nightmare Anti Cheat[NAC] - Roblox my anti cheat is client sided = it can detect things that the server cannot

It is 100% my priority and reverse engineering is a fat waste of time if it’s too difficult to where exploiters won’t even bother which is why im trying to make mine the best I possibly can

\it will be about as effective as treating the deadly psyllium disease.

1 Like

Hey I appreciate the baseless feedback man. Just makes it look great. Can’t give feedback on something you know absolutely nothing about :joy:

The fact is that the client anti-cheat has fundamental limitations due to where it is executed. Everything that works on the client side can be changed or disabled by the player. This is not my opinion, this is the principle of the client-server architecture.
What’s to stop a cheater from just disabling your anti-cheat?
How are you going to protect your code from being modified by a cheater?
Do you realize that a cheat can literally substitute the values of variables?

A cheater can literally just disable your anti-cheat.

Nope R.I.P in detected :headstone:

It has a very complex handshake that completely prevents that from occurring

It already is protected and I’m gatekeeping any important info about it

the only fundamental limitations are the ones that the poor exploiters who try to bypass it will have after getting jumpscared and kicked from being detected :rofl:

Just saying that it is “impossible" is not enough
How do you protect the code? Obfuscation? It slows down, but it doesn’t stop.

1 Like

Dude I just said I’m gatekeeping any important info about it. I’m not stupid people obviously will look to figure out how it works in order to bypass it. The funny thing is I haven’t even completely bypassed it and I’m the developer of it :joy: Trust me when I tell you I know a LOT about exploits and I’ve already decompiled it to know what it looks like when decompiled. I pity anyone who actually manages to decompile it :rofl:

correct me if I am wrong but don’t variable names become anonymous when decompiled?

for example, smt like this

local myString = "Hello"

local apples = 5

local Hello = function()
	
end

would be smt like this ?

local 0x10 = "Hello"

local 0x12 = 5

local 0x32 = function()
	
end

but variables values specifically strings would be non-anonymous unless you obfuscate them which would become useless when someone deobfuscates them
note that they can see the returned value from the example below

local mystring = `72 73`

local function simpleObfuscate(str)
	local result = ""
	for number in str:gmatch("%d+") do 
		result = result .. string.char(tonumber(number))
	end
	return result
end

print(simpleObfuscate(mystring)) -- HI
1 Like

yes they do and that’s what i’m trying to do. I’m trying to make it so that the decompiler gets completely cooked as much as possible lol

1 Like