This commit is contained in:
Flatlogic Bot 2026-01-31 13:48:46 +00:00
parent bfe3f1d544
commit a998fae926
4 changed files with 98 additions and 173 deletions

View File

@ -14,26 +14,40 @@ class LuauVMObfuscator:
"LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL", "RETURN",
"FORLOOP", "FORPREP", "TFORLOOP", "SETLIST", "CLOSE", "CLOSURE", "VARARG"
]
self.op_map = list(range(len(self.opcodes)))
random.shuffle(self.op_map)
self.op_to_id = {name: self.op_map[i] for i, name in enumerate(self.opcodes)}
# Randomize opcode mapping
self.op_order = list(range(len(self.opcodes)))
random.shuffle(self.op_order)
# Arithmetic keys for opcode decoding
self.k1 = random.randint(10, 100)
self.k2 = random.randint(10, 100)
# Opcode to encoded ID: (real_index + k1) ^ k2
self.op_to_id = {name: ((self.opcodes.index(name) + self.k1) ^ self.k2) % 256 for name in self.opcodes}
def encrypt_constant(self, value):
if isinstance(value, str):
# Remove quotes if present
if (value.startswith('"') and value.endswith('"')) or (value.startswith("'" ) and value.endswith("'" )):
value = value[1:-1]
return {"type": "string", "value": base64.b64encode(value.encode()).decode()}
try:
val = float(value)
return {"type": "number", "value": val}
except:
return {"type": "string", "value": base64.b64encode(str(value).encode()).decode()}
def encrypt_string(self, s, key):
return "".join(chr(ord(c) ^ ((key + i) % 256)) for i, c in enumerate(s))
def generate_vm_source(self, bytecode):
# Pack instructions into a string
inst_str = "".join(chr(i) for inst in bytecode['instructions'] for i in inst)
inst_b64 = base64.b64encode(inst_str.encode('latin-1')).decode()
# Prepare constants
encrypted_consts = []
for i, c in enumerate(bytecode['constants']):
if c['type'] == 'string':
# Encrypt with index-based key
key = (i * 137 + 42) % 256
enc_val = self.encrypt_string(c['value'], key)
encrypted_consts.append({"t": 1, "v": base64.b64encode(enc_val.encode('latin-1')).decode()})
else:
encrypted_consts.append({"t": 2, "v": c['value']})
consts_json = json.dumps(encrypted_consts)
def generate_vm_source(self, bytecode_json):
# Hardened VM for Luau
vm_lua = f"""
-- [[ VM-LUAU HARDENED ]]
-- [[ LUAU-VM PROTECTED ]]
local _ENV = getfenv()
local _B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
local _D = function(data)
@ -50,61 +64,60 @@ local _D = function(data)
end))
end
local _BYTECODE = [[{bytecode_json}]]
local _INST_RAW = _D('{inst_b64}')
local _CONSTS = game:GetService("HttpService"):JSONDecode('{consts_json}')
local function _VM_LIFECYCLE()
local bc = game:GetService("HttpService"):JSONDecode(_BYTECODE)
local insts = bc.instructions
local consts = bc.constants
local op_map = bc.op_map
local function _EXECUTE()
local registers = {{}}
local vip = 1
local dispatch = {{}}
local running = true
local function set_r(i, v) registers[i] = v end
local function get_r(i) return registers[i] end
dispatch[op_map[{self.opcodes.index("MOVE")+1}]] = function(a, b)
set_r(a, get_r(b))
end
dispatch[op_map[{self.opcodes.index("LOADK")+1}]] = function(a, b)
local c = consts[b+1]
set_r(a, c.type == "string" and _D(c.value) or c.value)
end
dispatch[op_map[{self.opcodes.index("GETGLOBAL")+1}]] = function(a, b)
local n = _D(consts[b+1].value)
set_r(a, _ENV[n])
end
dispatch[op_map[{self.opcodes.index("SETGLOBAL")+1}]] = function(a, b)
local n = _D(consts[b+1].value)
_ENV[n] = get_r(a)
end
dispatch[op_map[{self.opcodes.index("CALL")+1}]] = function(a, b, c)
local f = get_r(a)
local args = {{}}
if b > 1 then for i=1, b-1 do args[i] = get_r(a+i) end end
local res = {{f(unpack(args))}}
if c > 1 then for i=1, c-1 do set_r(a+i-1, res[i]) end end
end
dispatch[op_map[{self.opcodes.index("RETURN")+1}]] = function()
vip = #insts + 1
local function get_const(idx)
local c = _CONSTS[idx + 1]
if not c then return nil end
if c.t == 1 then
local raw = _D(c.v)
local key = (idx * 137 + 42) % 256
local res = ""
for i=1, #raw do
res = res .. string.char(bit32.bxor(string.byte(raw, i), (key + i - 1) % 256))
end
return res
end
return c.v
end
while vip <= #insts do
local inst = insts[vip]
local f = dispatch[inst[1]]
if f then f(inst[2], inst[3], inst[4]) end
vip = vip + 1
while running and vip <= #_INST_RAW do
local op_raw = string.byte(_INST_RAW, vip)
local a = string.byte(_INST_RAW, vip + 1)
local b = string.byte(_INST_RAW, vip + 2)
local c = string.byte(_INST_RAW, vip + 3)
vip = vip + 4
-- Arithmetic Opcode Decoding
local op = bit32.bxor(op_raw, {self.k2}) - {self.k1}
if op == {self.opcodes.index('MOVE')} then
registers[a] = registers[b]
elseif op == {self.opcodes.index('LOADK')} then
registers[a] = get_const(b)
elseif op == {self.opcodes.index('GETGLOBAL')} then
registers[a] = _ENV[get_const(b)]
elseif op == {self.opcodes.index('SETGLOBAL')} then
_ENV[get_const(b)] = registers[a]
elseif op == {self.opcodes.index('CALL')} then
local f = registers[a]
local args = {{}}
if b > 1 then for i=1, b-1 do args[i] = registers[a+i] end end
local res = {{f(unpack(args))}}
if c > 1 then for i=1, c-1 do registers[a+i-1] = res[i] end end
elseif op == {self.opcodes.index('RETURN')} then
running = false
end
end
end
task.spawn(_VM_LIFECYCLE)
task.spawn(_EXECUTE)
"""
return vm_lua
@ -115,34 +128,38 @@ task.spawn(_VM_LIFECYCLE)
next_reg = 0
def add_const(val):
enc = self.encrypt_constant(val)
if isinstance(val, str):
if (val.startswith('"') and val.endswith('"')) or (val.startswith("'" ) and val.endswith("'" )):
val = val[1:-1]
for i, c in enumerate(constants):
if c == enc: return i
constants.append(enc)
if c['value'] == val: return i
t = 'string' if isinstance(val, str) else 'number'
constants.append({'type': t, 'value': val})
return len(constants) - 1
def load_expr_to_reg(expr, reg):
if expr['type'] == 'IDENT':
if expr['value'] in locals_map:
instructions.append([self.op_to_id["MOVE"], reg, locals_map[expr['value']]])
instructions.append([self.op_to_id["MOVE"], reg, locals_map[expr['value']], 0])
else:
instructions.append([self.op_to_id["GETGLOBAL"], reg, add_const(expr['value'])])
instructions.append([self.op_to_id["GETGLOBAL"], reg, add_const(expr['value']), 0])
elif expr['type'] in ['STRING', 'NUMBER']:
instructions.append([self.op_to_id["LOADK"], reg, add_const(expr['value'])])
val = expr['value']
if expr['type'] == 'NUMBER':
try: val = float(val)
except: pass
instructions.append([self.op_to_id["LOADK"], reg, add_const(val), 0])
for node in ast:
if node['type'] == 'call':
func_reg = next_reg
# func_reg might be used, so we need to be careful if we have many locals
# For this simple obfuscator, we use registers above the current locals
# Load function
if node['name'] in locals_map:
instructions.append([self.op_to_id["MOVE"], func_reg, locals_map[node['name']]])
instructions.append([self.op_to_id["MOVE"], func_reg, locals_map[node['name']], 0])
else:
instructions.append([self.op_to_id["GETGLOBAL"], func_reg, add_const(node['name'])])
instructions.append([self.op_to_id["GETGLOBAL"], func_reg, add_const(node['name']), 0])
# Load args
for i, arg_expr in enumerate(node['args']):
load_expr_to_reg(arg_expr, func_reg + 1 + i)
@ -156,10 +173,10 @@ task.spawn(_VM_LIFECYCLE)
locals_map[node['name']] = val_reg
next_reg += 1
else:
instructions.append([self.op_to_id["SETGLOBAL"], val_reg, add_const(node['name'])])
instructions.append([self.op_to_id["SETGLOBAL"], val_reg, add_const(node['name']), 0])
instructions.append([self.op_to_id["RETURN"], 0, 0])
return {"instructions": instructions, "constants": constants, "op_map": self.op_map}
instructions.append([self.op_to_id["RETURN"], 0, 0, 0])
return {"instructions": instructions, "constants": constants}
def obfuscate(self, code):
if not code.strip(): return "-- No input"
@ -170,10 +187,10 @@ task.spawn(_VM_LIFECYCLE)
ast = parser.parse()
if not ast: return "-- VM Parser: No valid structures found."
bytecode = self.compile_to_bytecode(ast)
return self.generate_vm_source(json.dumps(bytecode))
return self.generate_vm_source(bytecode)
except Exception as e:
import traceback
return f"-- Error: {str(e)}\n{traceback.format_exc()}"
def obfuscate(code):
return LuauVMObfuscator().obfuscate(code)
return LuauVMObfuscator().obfuscate(code)

View File

@ -1,82 +0,0 @@
# fixer.py
content = """import re
class Lexer:
def __init__(self, code):
self.code = code
self.tokens = []
self.pos = 0
self.rules = [
('COMMENT', r'--\[\[.*?\].*?--.*'),
('STRING', r'\"(?:\\.|[^\"\\])*\"|\'(?:\\.|[^\'\])*\'|\\[\\[.*?\\]\\].*?'),
('NUMBER', r'\d+\.?\d*'),
('KEYWORD', r'\b(and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b'),
('IDENT', r'[a-zA-Z_][a-zA-Z0-9_]*'),
('OP', r'==|~=|<=|>=|\.\.\.|\.\.|>>|<<|[\+\-\*/%^#=\<\>\(\)\{\}\[\];:,.\.]'),
('SPACE', r'\s+')
]
def tokenize(self):
while self.pos < len(self.code):
match = None
for name, pattern in self.rules:
regex = re.compile(pattern, re.DOTALL)
match = regex.match(self.code, self.pos)
if match:
if name != 'SPACE' and name != 'COMMENT':
self.tokens.append((name, match.group(0)))
self.pos = match.end()
break
if not match:
self.pos += 1
return self.tokens
class Parser:
def __init__(self, tokens):
self.tokens = tokens
self.pos = 0
def peek(self):
return self.tokens[self.pos] if self.pos < len(self.tokens) else (None, None)
def consume(self, expected_type=None):
token = self.peek()
if expected_type and token[0] != expected_type:
return None
self.pos += 1
return token
def parse(self):
nodes = []
while self.pos < len(self.tokens):
node = self.parse_statement()
if node:
nodes.append(node)
else:
self.pos += 1
return nodes
def parse_statement(self):
token = self.peek()
if token[0] == 'IDENT':
ident = self.consume()[1]
next_token = self.peek()
if next_token[1] == '(':
self.consume()
args = []
while self.peek()[1] != ')':
args.append(self.peek()[1])
self.consume()
if self.peek()[1] == ',':
self.consume()
self.consume()
return {'type': 'call', 'name': ident, 'args': args}
elif next_token[1] == '=':
self.consume()
value = self.consume()[1]
return {'type': 'assign', 'name': ident, 'value': value}
return None
"""
with open("core/parser.py", "w") as f:
f.write(content)

View File

@ -1,10 +0,0 @@
from core.obfuscator import obfuscate
test_code = """
local x = 10
print(x)
print("Hello, Luau!")
"""
result = obfuscate(test_code)
print(result)