This commit is contained in:
Flatlogic Bot 2026-01-31 18:32:21 +00:00
parent c15cdd13cf
commit d2c45727f6
5 changed files with 76 additions and 11 deletions

View File

@ -46,7 +46,7 @@ class LuauVMObfuscator:
def minify(self, code):
code = re.sub(r'--.*', '', code)
code = re.sub(r'\s+', ' ', code)
for op in ['==', '~=', '<=', '>=', '=', r'\+', r'\*', '/', '>', '<', ',', ';', ':']:
for op in ['==', '~=', '<=', '>=', '=', r'\+', r'\*', '/', '>', '<', ',', ';', ':', '-']:
code = re.sub(r'\s*' + op + r'\s*', op.replace('\\', ''), code)
return code.strip()
@ -81,7 +81,6 @@ class LuauVMObfuscator:
"CHARS": self.get_var("chars"), "LOOKUP": self.get_var("lookup"), "GETC": self.get_var("getc")
}
# Using triple single quotes to avoid confusion
vm_lua = f'''local {v['ENV']}=setmetatable({{}},{{__index=getfenv()}});
local {v['CHARS']}='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
local {v['LOOKUP']}={{}};
@ -137,8 +136,10 @@ local {v['EXEC']}=function()
if a then a[{v['REGS']}[{v['B']}] or {v['GETC']}({v['B']})]={v['REGS']}[{v['C']}] end
elseif {v['OP']}=={self.opcodes.index('SELF')} then
local b={v['REGS']}[{v['B']}];
{v['REGS']}[{v['A']}+1]=b;
{v['REGS']}[{v['A']}]=b[{v['GETC']}({v['C']})];
if b then
{v['REGS']}[{v['A']}+1]=b;
{v['REGS']}[{v['A']}]=b[{v['GETC']}({v['C']})];
end
elseif {v['OP']}=={self.opcodes.index('ADD')} then {v['REGS']}[{v['A']}]=({v['REGS']}[{v['B']}] or 0)+({v['REGS']}[{v['C']}] or 0)
elseif {v['OP']}=={self.opcodes.index('SUB')} then {v['REGS']}[{v['A']}]=({v['REGS']}[{v['B']}] or 0)-({v['REGS']}[{v['C']}] or 0)
elseif {v['OP']}=={self.opcodes.index('MUL')} then {v['REGS']}[{v['A']}]=({v['REGS']}[{v['B']}] or 0)*({v['REGS']}[{v['C']}] or 0)
@ -157,7 +158,7 @@ local {v['EXEC']}=function()
elseif {v['OP']}=={self.opcodes.index('RETURN')} then break end;
end;
end;
{v['SPW']}({v['EXEC']});'''
({v['SPW']})({v['EXEC']});'''
return self.minify(vm_lua)
def compile_to_bytecode(self, ast):
@ -232,9 +233,15 @@ end;
kr = self.next_reg; self.next_reg += 1; gen_expr(t['key'], kr)
emit("SETTABLE", br, kr, vr); self.next_reg -= 1
self.next_reg -= 1
elif t['type'] == 'variable':
emit("SETGLOBAL", vr, add_const(t['name']))
else: emit("SETGLOBAL", vr, add_const(node['name']))
elif node['type'] == 'call': gen_call(node, self.next_reg)
elif node['type'] == 'method_call': gen_method_call(node, self.next_reg)
elif node['type'] == 'return':
vr = self.next_reg; self.next_reg += 1; gen_expr(node['value'], vr)
emit("RETURN", vr, 2)
self.next_reg -= 1
emit("RETURN")
return {"instructions": instructions, "constants": constants}

View File

@ -6,7 +6,6 @@ class Lexer:
self.tokens = []
self.pos = 0
LB, RB, DQ, SQ, BS = chr(91), chr(93), chr(34), chr(39), chr(92)
# Added : to OP_LIST
OP_LIST = r'==|~=|<=|>=|\.\.\.|\.\.|>>|<<|\+|\-|\*|/|%|\^|#|=|\<|\>|\(|\)|\{|\}|' + BS + LB + '|' + BS + RB + '|;|:|,|\.'
self.rules = [
('COMMENT', re.compile('--' + LB + LB + '.*?' + RB + RB + '|--.*', re.DOTALL)),
@ -44,7 +43,7 @@ class Parser:
while self.pos < len(self.tokens):
node = self.parse_statement()
if node: nodes.append(node)
else: self.pos += 1 # Still skipping, but hopefully parse_statement is better
else: self.pos += 1
return nodes
def parse_statement(self):
tk = self.peek()
@ -56,6 +55,11 @@ class Parser:
self.consume(); return {'type': 'assign', 'name': ident[1], 'value': self.parse_expression(), 'local': True}
return {'type': 'assign', 'name': ident[1], 'value': {'type': 'KEYWORD', 'value': 'nil'}, 'local': True}
return None
if tk[1] == 'return':
self.consume()
return {'type': 'return', 'value': self.parse_expression()}
if tk[1] == ';':
self.consume(); return None
start = self.pos; expr = self.parse_prefix_expression()
if expr:
if self.peek()[1] == '=':
@ -75,15 +79,13 @@ class Parser:
elif nt[1] == ':':
self.consume(); m = self.consume('IDENT')
if m:
# Method call
if self.peek()[1] == '(':
self.consume(); args = []
if self.peek()[1] != ')':
args.append(self.parse_expression())
while self.peek()[1] == ',': self.consume(); args.append(self.parse_expression())
self.consume('OP', ')'); expr = {'type': 'method_call', 'base': expr, 'method': m[1], 'args': args}
else: # Not a call, just a colon access? (Rare in Lua, usually an error, but let's be safe)
expr = {'type': 'index', 'base': expr, 'key': {'type': 'STRING', 'value': '"'+m[1]+'"'}}
else: expr = {'type': 'index', 'base': expr, 'key': {'type': 'STRING', 'value': '"'+m[1]+'"'}}
else: break
elif nt[1] == '[':
self.consume(); key = self.parse_expression(); self.consume('OP', ']'); expr = {'type': 'index', 'base': expr, 'key': key}
@ -112,4 +114,4 @@ class Parser:
if tk[0] in ['STRING', 'NUMBER']: v = tk[1]; self.consume(); return {'type': tk[0], 'value': v}
if tk[1] in ['true', 'false', 'nil']: return {'type': 'KEYWORD', 'value': self.consume()[1]}
if tk[1] == '(': self.consume(); e = self.parse_expression(); self.consume('OP', ')'); return e
return self.parse_prefix_expression()
return self.parse_prefix_expression()

56
verify_syntax.py Normal file
View File

@ -0,0 +1,56 @@
from core.obfuscator import obfuscate
import re
test_cases = [
"""
local a = 10
print(a)
""",
"""
game:GetService("Players").LocalPlayer:Kick("Test")
""",
"""
return 123
""",
"""
x = 5
x = x + 1
print(x)
""",
"""
local t = {a = 1}
t.a = 2
print(t.a)
"""
]
def check_syntax(lua_code):
# Basic check for balanced quotes and parens in the generated code
# Also check for the specific patterns we fixed
if "''" in lua_code and "(''" not in lua_code: # Check for the fixed inst_b64 part
# Note: ('' is fine for DEC function call if it was meant to be that, but we changed it to (')
pass
# Check for "task and task.spawn or spawn(" without surrounding parens
# Our fix: (task and task.spawn or spawn)(...
if "task and task.spawn or spawn(" in lua_code:
if "(task and task.spawn or spawn)(" not in lua_code:
return False, "Missing parentheses around SPW"
# Check for empty string (failed obfuscation)
if not lua_code.strip():
return False, "Empty output"
# Check for error comments
if "-- Obfuscation Error" in lua_code:
return False, "Obfuscation Error detected"
return True, "OK"
for i, code in enumerate(test_cases):
obfuscated = obfuscate(code)
success, msg = check_syntax(obfuscated)
print(f"Test {i}: {success} - {msg}")
if not success:
print(f"Code: {code}")
print(f"Obfuscated snippet: {obfuscated[:200]}...")