From c15cdd13cf1c8b251a70035c0b15417a1456ec57 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 31 Jan 2026 17:58:08 +0000 Subject: [PATCH] 18:58 --- core/__pycache__/obfuscator.cpython-311.pyc | Bin 29488 -> 31624 bytes core/__pycache__/parser.cpython-311.pyc | Bin 9693 -> 10864 bytes core/obfuscator.py | 143 ++++++++++++-------- core/parser.py | 39 ++++-- 4 files changed, 114 insertions(+), 68 deletions(-) diff --git a/core/__pycache__/obfuscator.cpython-311.pyc b/core/__pycache__/obfuscator.cpython-311.pyc index b54a4f09541d3cfeb16da2f1bae8a07a3bb45462..0913f676008cda5fdb57e5fafc748c9b4169a87d 100644 GIT binary patch delta 11467 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 NmwS;r5;$~Q_kT^l2_ygj diff --git a/core/__pycache__/parser.cpython-311.pyc b/core/__pycache__/parser.cpython-311.pyc index c444df74937e7529f695d45d91cfda77b4524e92..95de243432907caacb90c4c570d05b838ce4318d 100644 GIT binary patch delta 2330 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 iKUF9t7L|JzmRRiJlYtkS2yXu@EV0=', '=', r'\+', '-', r'\*', '/', '>', '<', r'\(', r'\)', r'\{', r'\}', r'\[', r'\]', ',', ';', ':']: + for op in ['==', '~=', '<=', '>=', '=', r'\+', r'\*', '/', '>', '<', ',', ';', ':']: code = re.sub(r'\s*' + op + r'\s*', op.replace('\\', ''), code) return code.strip() @@ -69,7 +69,7 @@ class LuauVMObfuscator: k = (i * 149 + salt) % 256; enc = self.encrypt_string(c['value'], k) consts.append({"t": 1, "v": base64.b64encode(enc.encode('latin-1')).decode()}) elif c['type'] == 'number': consts.append({"t": 2, "v": c['value']}) - else: consts.append({"t": 3, "v": c['value']}) + else: consts.append({"t": 3, "v": str(c['value'])}) v = { "BIT": "bit32", "ENV": self.get_var("env"), "DEC": self.get_var("dec"), @@ -81,59 +81,64 @@ class LuauVMObfuscator: "CHARS": self.get_var("chars"), "LOOKUP": self.get_var("lookup"), "GETC": self.get_var("getc") } - vm_lua = f"""local {v['ENV']}=setmetatable({{}},{{__index=getfenv()}}) -local {v['CHARS']}='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -local {v['LOOKUP']}={{}} -for i=1,64 do {v['LOOKUP']}[{v['CHARS']}:sub(i,i)]=i-1 end + # Using triple single quotes to avoid confusion + vm_lua = f'''local {v['ENV']}=setmetatable({{}},{{__index=getfenv()}}); +local {v['CHARS']}='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; +local {v['LOOKUP']}={{}}; +for i=1,64 do {v['LOOKUP']}[{v['CHARS']}:sub(i,i)]=i-1 end; local function {v['DEC']}(data) - data=data:gsub('[^%a%d%+/]','') - local res={{}} + data=data:gsub('[^%a%d%+/]',''); + local res={{}}; for i=1,#data,4 do - local a,b,c,d={v['LOOKUP']}[data:sub(i,i)],{v['LOOKUP']}[data:sub(i+1,i+1)],{v['LOOKUP']}[data:sub(i+2,i+2)],{v['LOOKUP']}[data:sub(i+3,i+3)] - local n={v['BIT']}.lshift(a or 0,18)+{v['BIT']}.lshift(b or 0,12)+{v['BIT']}.lshift(c or 0,6)+(d or 0) - res[#res+1]=string.char({v['BIT']}.extract(n,16,8)) - if c then res[#res+1]=string.char({v['BIT']}.extract(n,8,8)) end - if d then res[#res+1]=string.char({v['BIT']}.extract(n,0,8)) end - end - return table.concat(res) -end -local {v['INST']}={v['DEC']}('{inst_b64}') -local {v['CONSTS']}={v['JSON']}:JSONDecode([=[{json.dumps(consts)}]=]) + local a,b,c,d={v['LOOKUP']}[data:sub(i,i)],{v['LOOKUP']}[data:sub(i+1,i+1)],{v['LOOKUP']}[data:sub(i+2,i+2)],{v['LOOKUP']}[data:sub(i+3,i+3)]; + local n={v['BIT']}.lshift(a or 0,18)+{v['BIT']}.lshift(b or 0,12)+{v['BIT']}.lshift(c or 0,6)+(d or 0); + res[#res+1]=string.char({v['BIT']}.extract(n,16,8)); + if c then res[#res+1]=string.char({v['BIT']}.extract(n,8,8)) end; + if d then res[#res+1]=string.char({v['BIT']}.extract(n,0,8)) end; + end; + return table.concat(res); +end; +local {v['INST']}={v['DEC']}(''{inst_b64}'); +local {v['CONSTS']}={v['JSON']}:JSONDecode([=[{json.dumps(consts)}]=]); local {v['EXEC']}=function() - local {v['REGS']}={{}} - local {v['CURR']}={self.to_expr(pos_map[0])} + local {v['REGS']}={{}}; + local {v['CURR']}={self.to_expr(pos_map[0])}; local function {v['GETC']}(idx) - local c={v['CONSTS']}[idx+1] - if not c then return end + local c={v['CONSTS']}[idx+1]; + if not c then return end; if c.t==1 then - local r,k={v['DEC']}(c.v),(idx*149+{v['SALT']})%256 - local res,lst={{}},k%256 + local r,k={v['DEC']}(c.v),(idx*149+{v['SALT']})%256; + local res,lst={{}},k%256; for i=1,#r do - local char={v['BIT']}.bxor(string.byte(r,i),(k+i+lst-1)%256) - res[i]=string.char(char) - lst=char - end - return table.concat(res) - elseif c.t==3 then return c.v=='true' and true or (c.v=='false' and false or nil) end - return c.v - end + local char={v['BIT']}.bxor(string.byte(r,i),(k+i+lst-1)%256); + res[i]=string.char(char); + lst=char; + end; + return table.concat(res); + elseif c.t==3 then return c.v=='true' and true or (c.v=='false' and false or nil) end; + return c.v; + end; while true do - local {v['PTR']}={v['CURR']}*7+1 - local b1,b2,b3,b4,b5,b6,b7=string.byte({v['INST']},{v['PTR']},{v['PTR']}+6) - if not b1 then break end - {v['CURR']}=b6+({v['BIT']}.lshift(b7,8)) - local {v['OP']}={v['BIT']}.bxor(b1+{v['BIT']}.lshift(b2,8),{self.to_expr(self.k2)})-{self.to_expr(self.k1)} - local {v['A']},{v['B']},{v['C']}=b3,b4,b5 + local {v['PTR']}={v['CURR']}*7+1; + local b1,b2,b3,b4,b5,b6,b7=string.byte({v['INST']},{v['PTR']},{v['PTR']}+6); + if not b1 then break end; + {v['CURR']}=b6+({v['BIT']}.lshift(b7,8)); + local {v['OP']}={v['BIT']}.bxor(b1+{v['BIT']}.lshift(b2,8),{self.to_expr(self.k2)})-{self.to_expr(self.k1)}; + local {v['A']},{v['B']},{v['C']}=b3,b4,b5; if {v['OP']}=={self.opcodes.index('MOVE')} then {v['REGS']}[{v['A']}]={v['REGS']}[{v['B']}] elseif {v['OP']}=={self.opcodes.index('LOADK')} then {v['REGS']}[{v['A']}]={v['GETC']}({v['B']}) elseif {v['OP']}=={self.opcodes.index('GETGLOBAL')} then {v['REGS']}[{v['A']}]={v['ENV']}[{v['GETC']}({v['B']})] elseif {v['OP']}=={self.opcodes.index('SETGLOBAL')} then {v['ENV']}[{v['GETC']}({v['B']})]={v['REGS']}[{v['A']}] elseif {v['OP']}=={self.opcodes.index('GETTABLE')} then - local b={v['REGS']}[{v['B']}] + local b={v['REGS']}[{v['B']}]; if b then {v['REGS']}[{v['A']}]=b[{v['REGS']}[{v['C']}] or {v['GETC']}({v['C']})] end elseif {v['OP']}=={self.opcodes.index('SETTABLE')} then - local a={v['REGS']}[{v['A']}] + local a={v['REGS']}[{v['A']}]; 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']})]; 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) @@ -142,24 +147,24 @@ local {v['EXEC']}=function() elseif {v['OP']}=={self.opcodes.index('NOT')} then {v['REGS']}[{v['A']}]=not {v['REGS']}[{v['B']}] elseif {v['OP']}=={self.opcodes.index('LEN')} then {v['REGS']}[{v['A']}]=#{v['REGS']}[{v['B']}] or 0 elseif {v['OP']}=={self.opcodes.index('CALL')} then - local f={v['REGS']}[{v['A']}] + local f={v['REGS']}[{v['A']}]; if f then - local args={{}} - if {v['B']}>1 then for i=1,{v['B']}-1 do args[i]={v['REGS']}[{v['A']}+i] end end - local res={{f(({v['UNP']})(args))}} - if {v['C']}>1 then for i=1,{v['C']}-1 do {v['REGS']}[{v['A']}+i-1]=res[i] end end + local args={{}}; + if {v['B']}>1 then for i=1,{v['B']}-1 do args[i]={v['REGS']}[{v['A']} + i] end end; + local res={{f(({v['UNP']})(args))}}; + if {v['C']}>1 then for i=1,{v['C']}-1 do {v['REGS']}[{v['A']} + i - 1]=res[i] end end; end - elseif {v['OP']}=={self.opcodes.index('RETURN')} then break end - end -end -{v['SPW']}({v['EXEC']})""" + elseif {v['OP']}=={self.opcodes.index('RETURN')} then break end; + end; +end; +{v['SPW']}({v['EXEC']});''' return self.minify(vm_lua) def compile_to_bytecode(self, ast): constants, instructions, locals_map = [], [], {} self.next_reg = 0 def add_const(val): - if isinstance(val, str) and ((val.startswith("'") and val.endswith("'")) or (val.startswith('"') and val.endswith('"'))): val = val[1:-1] + if isinstance(val, str) and ((val.startswith("'" ) and val.endswith("'" )) or (val.startswith('"') and val.endswith('"'))): val = val[1:-1] for i, c in enumerate(constants): if c['value'] == val: return i t = 'string' if isinstance(val, str) else 'number' @@ -177,8 +182,12 @@ end else: emit("GETGLOBAL", target, add_const(expr['name'])) elif expr['type'] == 'index': br = self.next_reg; self.next_reg += 1; gen_expr(expr['base'], br) - kr = self.next_reg; self.next_reg += 1; gen_expr(expr['key'], kr) - emit("GETTABLE", target, br, kr); self.next_reg -= 2 + if expr['key']['type'] == 'STRING': + emit("GETTABLE", target, br, add_const(expr['key']['value'])) + else: + kr = self.next_reg; self.next_reg += 1; gen_expr(expr['key'], kr) + emit("GETTABLE", target, br, kr); self.next_reg -= 1 + self.next_reg -= 1 elif expr['type'] == 'binary': lr = self.next_reg; self.next_reg += 1; gen_expr(expr['left'], lr) rr = self.next_reg; self.next_reg += 1; gen_expr(expr['right'], rr) @@ -189,16 +198,25 @@ end op_m = {'-': 'UNM', '#': 'LEN', 'not': 'NOT'} emit(op_m.get(expr['op'], 'UNM'), target, or_reg); self.next_reg -= 1 elif expr['type'] == 'call': gen_call(expr, target) + elif expr['type'] == 'method_call': gen_method_call(expr, target) def gen_call(node, target): fr = self.next_reg; self.next_reg += 1 - if node['func']['type'] == 'variable': - if node['func']['name'] in locals_map: emit("MOVE", fr, locals_map[node['func']['name']]) - else: emit("GETGLOBAL", fr, add_const(node['func']['name'])) - else: gen_expr(node['func'], fr) + gen_expr(node['func'], fr) for i, arg in enumerate(node['args']): ar = self.next_reg; self.next_reg += 1; gen_expr(arg, ar) emit("CALL", fr, len(node['args']) + 1, 2) - emit("MOVE", target, fr) + if target != fr: emit("MOVE", target, fr) + self.next_reg = fr + def gen_method_call(node, target): + fr = self.next_reg; self.next_reg += 1 + br = self.next_reg; self.next_reg += 1 + gen_expr(node['base'], br) + emit("SELF", fr, br, add_const(node['method'])) + self.next_reg = fr + 2 + for i, arg in enumerate(node['args']): + ar = self.next_reg; self.next_reg += 1; gen_expr(arg, ar) + emit("CALL", fr, len(node['args']) + 2, 2) + if target != fr: emit("MOVE", target, fr) self.next_reg = fr for node in ast: if node['type'] == 'assign': @@ -208,10 +226,15 @@ end t = node['target'] if t['type'] == 'index': br = self.next_reg; self.next_reg += 1; gen_expr(t['base'], br) - kr = self.next_reg; self.next_reg += 1; gen_expr(t['key'], kr) - emit("SETTABLE", br, kr, vr); self.next_reg -= 2 + if t['key']['type'] == 'STRING': + emit("SETTABLE", br, add_const(t['key']['value']), vr) + else: + 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 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) emit("RETURN") return {"instructions": instructions, "constants": constants} @@ -230,4 +253,4 @@ end return f"-- Obfuscation Error: {traceback.format_exc()}" def obfuscate(code): - return LuauVMObfuscator().obfuscate(code) \ No newline at end of file + return LuauVMObfuscator().obfuscate(code) diff --git a/core/parser.py b/core/parser.py index ee0fcda..2b977fb 100644 --- a/core/parser.py +++ b/core/parser.py @@ -6,6 +6,7 @@ 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)), @@ -43,7 +44,7 @@ class Parser: while self.pos < len(self.tokens): node = self.parse_statement() if node: nodes.append(node) - else: self.pos += 1 + else: self.pos += 1 # Still skipping, but hopefully parse_statement is better return nodes def parse_statement(self): tk = self.peek() @@ -51,12 +52,15 @@ class Parser: if tk[1] == 'local': self.consume(); ident = self.consume('IDENT') if ident: - if self.peek()[1] == '=': self.consume(); return {'type': 'assign', 'name': ident[1], 'value': self.parse_expression(), 'local': True} + if self.peek()[1] == '=': + 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 start = self.pos; expr = self.parse_prefix_expression() if expr: - if self.peek()[1] == '=': self.consume(); return {'type': 'assign', 'target': expr, 'value': self.parse_expression()} - elif expr['type'] == 'call': return expr + if self.peek()[1] == '=': + self.consume(); return {'type': 'assign', 'target': expr, 'value': self.parse_expression()} + elif expr['type'] in ['call', 'method_call']: return expr self.pos = start; return None def parse_prefix_expression(self): tk = self.peek() @@ -65,8 +69,24 @@ class Parser: while True: nt = self.peek() if nt[1] == '.': - self.consume(); m = self.consume('IDENT'); expr = {'type': 'index', 'base': expr, 'key': {'type': 'STRING', 'value': '"'+m[1]+'"'}} - elif nt[1] == '[': self.consume(); key = self.parse_expression(); self.consume('OP', ']'); expr = {'type': 'index', 'base': expr, 'key': key} + self.consume(); m = self.consume('IDENT') + if m: expr = {'type': 'index', 'base': expr, 'key': {'type': 'STRING', 'value': '"'+m[1]+'"'}} + else: break + 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: break + elif nt[1] == '[': + self.consume(); key = self.parse_expression(); self.consume('OP', ']'); expr = {'type': 'index', 'base': expr, 'key': key} elif nt[1] == '(': self.consume(); args = [] if self.peek()[1] != ')': @@ -77,16 +97,19 @@ class Parser: return expr def parse_expression(self): left = self.parse_primary_expression() + if not left: return None while self.peek()[1] in ['+', '-', '*', '/', '..', '==', '<', '>', '<=', '>=', '~=']: op = self.consume()[1]; right = self.parse_primary_expression() + if not right: break left = {'type': 'binary', 'op': op, 'left': left, 'right': right} return left def parse_primary_expression(self): tk = self.peek() if not tk: return None if tk[1] in ['-', '#', 'not']: - op = self.consume()[1]; return {'type': 'unary', 'op': op, 'operand': self.parse_primary_expression()} + op = self.consume()[1]; sub = self.parse_primary_expression() + return {'type': 'unary', 'op': op, 'operand': sub} if sub else None 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() \ No newline at end of file + return self.parse_prefix_expression()