Unlocking Lua Bytecode: A Deep Dive into Luac File Structure and 010 Editor Templates

This article explains the Lua 5.2 bytecode format, details each field of the Luac file header and function prototypes, and shows how to create a 010 Editor binary template to parse and edit Luac files for reverse‑engineering and security analysis.

360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
Unlocking Lua Bytecode: A Deep Dive into Luac File Structure and 010 Editor Templates
Luac overview
Luac overview

Lua is widely used in game development and mobile apps because of its efficiency, simplicity, and cross‑platform nature. Lua source files are compiled into a binary format called luac, which the Lua virtual machine loads and executes.

The article focuses on Lua 5.2 bytecode, describing the structure of a luac file, which consists of a global header followed by one or more function prototypes.

Luac File Header

The header is defined as:

typedef struct {
    char signature[4]; // "\033Lua" – magic number
    uchar version;    // 0x52 for Lua 5.2
    uchar format;     // 0 = official format
    uchar endian;     // 1 = LittleEndian, 0 = BigEndian
    uchar size_int;
    uchar size_size_t;
    uchar size_Instruction;
    uchar size_lua_Number;
    uchar lua_num_valid;
    uchar luac_tail[0x6]; // error‑catching bytes (present when version == 0x52)
} GlobalHeader;

Key fields:

signature : the magic number that identifies the file as a Luac binary.

version : indicates the Lua version used to compile the file.

format : 0 means the official format; any other value denotes a custom format.

endian : byte order of the file.

size_* fields describe the size of fundamental data types on the target platform, ensuring compatibility across 32‑bit and 64‑bit systems.

Function Prototype (Proto)

Each function is represented by a Proto structure:

typedef struct {
    ProtoHeader header;
    Code code;
    Constants constants;
    Protos protos;
    Upvaldescs upvaldescs;
    UpValueNames upvalnames;
    SourceName src_name;
    Lines lines;
    LocVars loc_vars;
} Proto;

The ProtoHeader contains:

typedef struct {
    uint32 linedefined;
    uint32 lastlinedefined;
    uchar numparams;
    uchar is_vararg;   // 1 if function has "..." parameters
    uchar maxstacksize;
} ProtoHeader;

The Code block stores the actual bytecode instructions:

struct Code {
    uint32 sizecode;   // number of instructions
    uint32 inst[];     // each instruction is a 32‑bit integer
};

Constants are stored in a Constants array, each entry being a Constant structure that records the data type ( LUA_DATATYPE) and the value ( TValue). The article shows how to decode booleans, numbers, and strings using Lua macros such as bvalue, nvalue, and rawtsvalue.

Upvalues and Nested Functions

Upvalues are captured variables that child functions (closures) reference. The Upvaldesc structure indicates whether an upvalue resides on the stack ( instack) and its index ( idx). UpValueNames stores the textual names of upvalues.

Lines and Local Variables

The Lines array holds line‑number information for debugging, while LocVars records each local variable’s name, start PC, and end PC.

Creating a 010 Editor Template

To facilitate binary analysis, the author builds a 010 Editor template ( luac.bt) that mirrors the C‑style structures above. The template begins with standard header comments and defines each structure using 010 Editor’s syntax, which is almost identical to C but supports additional attributes such as <format=hex> and <comment="..."> for better readability.

Example of the header definition in the template:

typedef struct {
    uint32 signature <format=hex>; // ".lua"
    uchar version <format=hex>;
    uchar format <comment="format (0=official)">;
    uchar endian <comment="1==LittleEndian; 0==BigEndian">;
    uchar size_int <comment="sizeof(int)">;
    uchar size_size_t <comment="sizeof(size_t)">;
    uchar size_Instruction <comment="sizeof(Instruction)">;
    uchar size_lua_Number <comment="sizeof(lua_Number)">;
    uchar lua_num_valid <comment="Usually 0">;
    if (version == 0x52) {
        uchar luac_tail[0x6] <format=hex, comment="error‑catching bytes">;
    }
} GlobalHeader;

The template also defines helper functions to convert Lua numbers to strings, emulate the bvalue and nvalue macros, and format constants for display. For example, the number2str function chooses a format string based on the instruction size (4 or 8 bytes) and prints the numeric value accordingly.

To parse constants, a ConstantRead function uses a switch on constant.const_type and returns a human‑readable representation (e.g., "true", "nil", numeric value, or quoted string).

After completing the template, the author demonstrates its usage: opening a compiled hello.luac file in 010 Editor displays the parsed header, prototype hierarchy, bytecode, constants, upvalues, and line information, as shown in the screenshot below.

Template result
Template result

The full luac.bt implementation is available at https://github.com/feicong/lua_re .

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

bytecodeInformation SecurityReverse engineering010 EditorBinary TemplateLuac
360 Zhihui Cloud Developer
Written by

360 Zhihui Cloud Developer

360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.