Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Lua Deobfuscation

ASecurity

Deobfuscate commercial Lua obfuscators (MoonVeil, Luraph).

2 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentpythongobashdebugginggitsecurity

Works with

cli

Security Analysis

A100/100

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add harezadmm/hermes-brutal-mod --skill lua-deobfuscation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Lua Deobfuscation?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Lua Deobfuscation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/harezadmm-lua-deobfuscation/badge)](https://www.skillsdirectory.com/skills/harezadmm-lua-deobfuscation)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: lua-deobfuscation
description: Deobfuscate commercial Lua obfuscators (MoonVeil, Luraph).
version: 1.0.0
triggers:
  - Lua script obfuscation
  - MoonVeil deobfuscation
  - Encrypted Lua strings
  - Obfuscated Roblox scripts
  - Commercial Lua obfuscators
category: security
tags:
  - lua
  - deobfuscation
  - reverse-engineering
  - moonveil
  - string-decryption
related_skills:
  - reverse-engineering-gokil
---

# Lua Script Deobfuscation

Deobfuscate commercial Lua obfuscators: MoonVeil, Luraph, Ironbrew, PSU (Pro Script Utilities). Common in Roblox exploit scripts and protected Lua codebases.

## When to Use

- User provides obfuscated Lua script (minified single line, random variable names)
- Script contains encrypted string patterns like `Kb('\\206\\186','\\25')`
- References commercial obfuscator (MoonVeil, Luraph, Ironbrew)
- User requests "decode", "deobfuscate", "decrypt", or "unpack" Lua source

## MoonVeil Obfuscator (v1.4+)

### Key Pattern Recognition

```lua
-- Header comment
-- This script was generated using the MoonVeil Obfuscator v1.4.5

-- First line: variable mappings
local xe,Kd,ed,Wc = type,bit32.bxor,getmetatable,pairs

-- String decoder function (name varies: Kb, decode, etc)
Kb = function(Fc,Ed)
  -- XOR decryption logic
end

-- Encrypted strings throughout
local x = Kb('\\206\\186\\25', '\\b\\128')
```

### Critical Discovery: Decimal Byte Escapes

**MoonVeil uses DECIMAL byte values in `\ddd` escapes, NOT octal.**

Standard Lua: `\ddd` is octal (max `\377` = 255 decimal)  
MoonVeil: `\ddd` is decimal (`\186` = byte 186 directly)

This breaks 70%+ of strings if you assume octal parsing. Values like `\186`, `\206`, `\248`, `\255` are DECIMAL.

### Deobfuscation Steps

#### Step 1: Parse Lua String Literals (Decimal Escapes)

```python
def parse_lua_string(code, start):
    """Parse Lua string from position, handling DECIMAL escapes"""
    if code[start] not in ["'", '"']:
        return None, start
    
    quote = code[start]
    result = []
    i = start + 1
    
    while i < len(code):
        if code[i] == quote:
            return bytes(result), i + 1
        
        elif code[i] == '\\' and i + 1 < len(code):
            i += 1
            ch = code[i]
            
            if ch.isdigit():
                # Numeric escape - collect up to 3 digits
                num = ''
                while i < len(code) and code[i].isdigit() and len(num) < 3:
                    num += code[i]
                    i += 1
                
                # DECIMAL not octal
                val = int(num, 10)
                if val <= 255:
                    result.append(val)
                    continue
            
            # Standard escapes
            elif ch == 'n': result.append(ord('\n'))
            elif ch == 't': result.append(ord('\t'))
            elif ch == 'r': result.append(ord('\r'))
            elif ch == '\\': result.append(ord('\\'))
            elif ch in ["'", '"']: result.append(ord(ch))
            else: result.append(ord(ch))
            
            i += 1
        else:
            result.append(ord(code[i]))
            i += 1
    
    return None, start  # Unterminated
```

#### Step 2: Extract Decoder Calls

Character-by-character parsing (regex fails on escape sequences):

```python
def extract_decoder_calls(code, func_name='Kb'):
    """Extract all decoder function calls with positions"""
    calls = []
    i = 0
    
    while i < len(code):
        pos = code.find(f'{func_name}(', i)
        if pos == -1:
            break
        
        start_pos = pos
        i = pos + len(func_name) + 1
        
        # Skip whitespace
        while i < len(code) and code[i] in ' \t\n':
            i += 1
        
        # Parse first string argument
        str1, end1 = parse_lua_string(code, i)
        if str1 is None:
            i = pos + 3
            continue
        
        # Skip comma
        i = end1
        while i < len(code) and code[i] in ' ,\t\n':
            i += 1
        
        # Parse second string argument
        str2, end2 = parse_lua_string(code, i)
        if str2 is None:
            i = pos + 3
            continue
        
        # Check closing paren
        i = end2
        while i < len(code) and code[i] in ' \t\n':
            i += 1
        
        if i < len(code) and code[i] == ')':
            end_pos = i + 1
            calls.append({
                'start': start_pos,
                'end': end_pos,
                'bytes1': str1,
                'bytes2': str2,
                'original': code[start_pos:end_pos]
            })
            i += 1
        else:
            i = pos + 3
    
    return calls
```

#### Step 3: XOR Decode Strings

```python
def xor_decode(bytes1, bytes2):
    """XOR decode with cycling key"""
    if not bytes2:
        return bytes1
    
    result = []
    for i, b in enumerate(bytes1):
        key_byte = bytes2[i % len(bytes2)]
        result.append(b ^ key_byte)
    
    return bytes(result)
```

#### Step 4: Replace in Source

```python
# Decode all calls
decoded_map = []
for call in decoder_calls:
    decoded_bytes = xor_decode(call['bytes1'], call['bytes2'])
    decoded_str = decoded_bytes.decode('utf-8', errors='replace')
    
    # Create Lua string literal
    escaped = decoded_str.replace('\\', '\\\\').replace("'", "\\'")
    replacement = f"'{escaped}'"
    
    decoded_map.append({
        'pos': (call['start'], call['end']),
        'replacement': replacement
    })

# Replace backwards to preserve positions
deobfuscated = code
for item in reversed(decoded_map):
    start, end = item['pos']
    deobfuscated = deobfuscated[:start] + item['replacement'] + deobfuscated[end:]
```

#### Step 5: Variable Renaming

Extract variable mappings from first line:

```python
# Pattern: local a,b,c,d = builtin1,builtin2,builtin3,builtin4
var_map = {
    'xe': 'type',
    'Kd': 'bit32_bxor',
    'ed': 'getmetatable',
    'Wc': 'pairs',
    # Extract more from Ya['module']['func'] patterns
}

# Replace with word boundaries
for old_var in sorted(var_map.keys(), key=len, reverse=True):
    new_var = var_map[old_var]
    pattern = r'\b' + re.escape(old_var) + r'\b'
    deobfuscated = re.sub(pattern, new_var, deobfuscated)
```

## Typical Results

**Input:**
- 194KB minified single-line Lua
- 165 encrypted string calls
- All variables 1-3 chars

**Output:**
- 197KB readable source
- 1700+ formatted lines
- 165/165 strings decoded (100%)
- Builtin functions visible
- Main logic identifiable

**Time:** ~5 minutes (includes parser debugging iterations)

## Other Obfuscators

### Luraph
- Similar XOR pattern
- May use octal escapes (standard Lua)
- Stronger VM obfuscation
- Decoder function name varies

### Ironbrew
- Older, simpler
- Base64 + XOR layers
- Less control flow obfuscation
- Easier to crack

### PSU (Pro Script Utilities)
- Variable obfuscation only
- No string encryption
- Minification focused

## Pitfalls

1. **Assuming Octal:** MoonVeil's decimal escapes will fail 70% of strings. Always try decimal first.

2. **Regex Extraction:** Backslash escapes break regex. Must parse character-by-character.

3. **Control Flow Remains:** String + variable deobfuscation makes code readable, but state machine logic (`lc=P[14840]or S(...)`) stays obfuscated. That's expected - full VM deobfuscation requires bytecode analysis.

4. **Hardcoded XOR Keys:** Decoder functions have session-specific keys (e.g., 63785, 46458). If different keys appear, the pattern still holds - just different constants.

5. **Incomplete Decoding:** Some binary data (like embedded bytecode) won't decode to UTF-8. Mark those as `[binary]` and keep original.

## Success Indicators

- ✅ All decoder calls replaced with string literals
- ✅ Builtin function names visible (`string.char`, `bit32.bxor`, `table.concat`)
- ✅ Valid Lua syntax (`luac -p` passes)
- ✅ Function boundaries identifiable
- ✅ Main execution flow traceable

## Tools Required

- Python 3.11+ (no external deps)
- Optional: Lua interpreter for validation

## Verification

```bash
# Check syntax
luac -p deobfuscated.lua

# Compare structure
wc -l original.lua deobfuscated.lua

# Grep for decoder calls (should be 0)
grep -c 'Kb(' deobfuscated.lua
```

## Next Steps After Deobfuscation

Once strings decoded and variables renamed:
1. **Trace entry point** - find main execution (usually at end)
2. **Identify key functions** - look for game interaction, HTTP calls, crypto
3. **Map control flow** - state machine variables (lc, state, etc)
4. **Extract embedded data** - Base64 blobs, bytecode chunks
5. **Test modifications** - inject logging, change behavior

Attribution

harezadmmharezadmm
View sourceMore from harezadmm →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →