14:48
This commit is contained in:
parent
bfe3f1d544
commit
a998fae926
Binary file not shown.
@ -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)
|
||||
82
fixer.py
82
fixer.py
@ -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)
|
||||
|
||||
@ -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)
|
||||
Loading…
x
Reference in New Issue
Block a user