Skip to content

Coldzer0/LuaDecompiler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cLuaDecompiler

License: AGPL v3

cLuaDecompiler is a Free Pascal/Lazarus Lua bytecode disassembler and decompiler for Lua 5.1, 5.2, 5.3, 5.4, and 5.5 binary chunks.

The project focuses on version-aware bytecode parsing, semantic opcode mapping, SSA-based analysis, and Lua source emission that can be validated against the original program behavior when source is available.

Features

  • Disassembles Lua bytecode with version-aware opcode names and operands.
  • Decompiles .luac files to Lua-like source.
  • Dumps SSA IR for debugging control flow, register lifetimes, phi nodes, and decompiler decisions.
  • Supports built-in opcode tables for Lua 5.1 through 5.5.
  • Supports custom opcode-table loading for patched or obfuscated bytecode.
  • Includes runtime validation that compares original source output with decompiled output under the matching Lua version.
  • Includes source-less bytecode validation for cases where opcode/disassembly coverage is the source of truth.
  • Includes an optional VS Code extension for opening .luac files as decompiled Lua text.

Decompilation Examples

  • Check the examples folder.

Download

Requirements

  • Windows or another platform supported by Free Pascal/Lazarus.
  • Lazarus with LazBuild available in PATH.
  • Python 3 for the validation scripts.
  • Lua and luac binaries for validation, placed under the expected local layout when running the full suite:
lua/lua5.1/lua5.1.exe
lua/lua5.1/luac5.1.exe
lua/lua5.2/lua52.exe
lua/lua5.2/luac52.exe
lua/lua5.3/lua53.exe
lua/lua5.3/luac53.exe
lua/lua5.4/lua54.exe
lua/lua5.4/luac54.exe
lua/lua5.5/lua55.exe
lua/lua5.5/luac55.exe

Build

Build from the repository root with Lazarus:

LazBuild cLuaDecompiler.lpi

The main executable is produced as:

cLuaDecompiler.exe

Usage

.\cLuaDecompiler.exe [options] <file.luac>

Common commands:

.\cLuaDecompiler.exe --dis sample.luac
.\cLuaDecompiler.exe --dec sample.luac
.\cLuaDecompiler.exe --ssa-dump sample.luac
.\cLuaDecompiler.exe --dec --annotate sample.luac

Options:

--dis              Disassemble bytecode
--dec              Decompile to Lua-like source; default mode
--ssa-dump         Dump SSA IR for all protos
--annotate         Add disassembly comments during decompilation
--debug            Emit debug trace to stderr
--lua-version VER  Override detected Lua version: 51, 52, 53, 54, or 55
--opcode-table F   Load a custom opcode mapping from file F
--help             Show CLI help

Examples:

.\cLuaDecompiler.exe --dec script.luac > script.decompiled.lua
.\cLuaDecompiler.exe --dis script.luac > script.dis.txt
.\cLuaDecompiler.exe --ssa-dump script.luac > script.ssa.txt
.\cLuaDecompiler.exe --lua-version 51 --opcode-table opcode_tables\custom.txt patched.luac

Testing

Run the runtime and bytecode validation suite:

python run_decompiler_validation.py

Compile local Lua 5.1 fixtures manually:

tests\compile_luac.bat

run_decompiler_validation.py is the preferred validation path for decompiler correctness because it can:

  • compile source fixtures with the matching Lua version,
  • run the original source,
  • decompile the compiled bytecode,
  • run the decompiled output,
  • compare runtime output,
  • compile stripped-bytecode fixtures,
  • validate source-less bytecode through disassembly and opcode signatures.

Useful validation filters:

python run_decompiler_validation.py --versions 51
python run_decompiler_validation.py --timeout 10 --out-dir decompiled\validation_tmp

Adding Test Cases

Runtime-equivalence fixtures should either live in:

validation/fixtures/runtime/

or be referenced from:

validation/runtime_cases.json

Fixtures can declare supported versions at the top of the Lua file:

-- versions: 51 52 53 54 55

Source-less bytecode cases belong in:

validation/bytecode_cases.json

Use validation/stubs/ for small fake environments needed to load or compile decompiled source outside the original host application. For bytecode without source, compare disassembly and opcode signatures rather than pretending there is a source-level oracle.

Do not commit generated .luac files from compiled/ or decompiler output from decompiled/.

Architecture Notes

The main pipeline is:

LuaChunk.pas -> LuaOpcodes.pas -> LuaSSA.pas -> LuaDecomp.pas/LuaDecomp*.inc

When adding support for a Lua version or opcode pattern:

  1. Verify chunk and instruction decoding in LuaChunk.pas.
  2. Add or correct semantic opcode mapping in LuaOpcodes.pas.
  3. Lift the semantic operation in LuaSSA.pas.
  4. Prefer fixing value/control-flow facts in SSA before patching emitted text.
  5. Update decompiler emission in the matching LuaDecomp*.inc file.
  6. Add runtime validation or source-less bytecode validation.

Useful debug flow:

.\cLuaDecompiler.exe --dis sample.luac > sample.dis.txt
.\cLuaDecompiler.exe --ssa-dump sample.luac > sample.ssa.txt
.\cLuaDecompiler.exe --dec --annotate sample.luac > sample.lua

The official Lua source browser is useful when opcode behavior or chunk format details are unclear:

https://www.lua.org/source/

VS Code Extension

The optional extension in vscode_plugin/ opens .luac files through cLuaDecompiler.exe and presents the result as normal Lua text so the existing Lua syntax highlighter can be used.

The extension can auto-detect cLuaDecompiler.exe near the workspace, or you can set:

cluaDecompiler.executablePath

Current Limitations

Decompiler output is best treated as recovered source, not guaranteed original source formatting. Local variable names, closure names, control-flow shape, and expression ordering may differ from the original program while still preserving runtime behavior.

Stripped bytecode and source-less application bytecode should be validated with runtime stubs when possible and with disassembly/opcode coverage when no source oracle exists.

References

Some Of the analyses and algorithms in this project are based on the following public sources:

  • Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy, A Simple, Fast Dominance Algorithm, Rice University, 2001 - iterative dominator and immediate-dominator computation.
  • Ron Cytron, Jeanne Ferrante, Barry K. Rosen, Mark N. Wegman, and F. Kenneth Zadeck, Efficiently Computing Static Single Assignment Form and the Control Dependence Graph, ACM TOPLAS 13(4), 1991 - dominance frontiers, φ-function placement, and the SSA rename pass.
  • Keith D. Cooper and Linda Torczon, Engineering a Compiler - background material on iterative dataflow analysis used as the basis for the dominator and SSA construction passes.
  • The official Lua source browser at https://www.lua.org/source/, including the lopcodes.h, lopcodes.c, and lvm.c files for Lua 5.1, 5.2, 5.3, 5.4, and 5.5 - authoritative opcode tables, instruction formats, and VM semantics.
  • The unluac Lua decompiler project - used as an external comparison oracle for output formatting and structural recovery on shared fixtures.

Copyright

Copyright (C) 2019-present XENOM-X TECHNOLOGY LLC.

License

This project is licensed under the GNU Affero General Public License version 3. See LICENSE.txt for the full license text.

With ❤️ From Home.

About

Lua bytecode disassembler and decompiler for Lua 5.1, 5.2, 5.3, 5.4, and 5.5 binary chunks.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages