19:32
This commit is contained in:
parent
c15cdd13cf
commit
d2c45727f6
Binary file not shown.
Binary file not shown.
@ -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}
|
||||
|
||||
|
||||
@ -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
56
verify_syntax.py
Normal 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]}...")
|
||||
Loading…
x
Reference in New Issue
Block a user