Lua Decompiler Package

We are happy to announce the beta release of the Lua Decompiler package. It reconstructs readable Lua source code from compiled Lua bytecode (.luac) files, covering all major Lua versions from 5.0 through 5.4. This package requires the installation of the LUAC Format package.

Compiled Lua bytecode is common across game engines, embedded firmware, IoT devices, and malware payloads. Disassembly alone is often enough for a rough understanding of a function, but reading dozens of instructions per line does not scale when a script spans thousands of opcodes. A decompiler bridges that gap: it turns register-level bytecode back into control flow a human can read, making review, patch development, and malware triage dramatically faster.

This is a beta release. The core reconstruction pipeline is stable and validated against a broad sample set across all supported Lua versions, but complex control flow patterns and heavily optimized bytecode may still produce suboptimal output. Feedback is welcome.

LUAC Format Package

We are happy to announce support for Lua compiled bytecode (LUAC) files. The new LUAC Format package parses and disassembles Lua bytecode across all major Lua versions, from 5.0 through 5.4.

Lua is one of the most widely embedded scripting languages. It powers game engines, network appliances, IoT firmware, and malware payloads alike. Compiled Lua bytecode (.luac) files are frequently encountered during firmware analysis, game modding, and malware reverse engineering. Having native LUAC support in Cerbero Suite means analysts can inspect bytecode structure and disassembly without external tools.

Custom filters: Lua and misc/basic

Last year filters have been introduced and among them them the very useful ‘misc/basic‘. The upcoming 0.9.5 version of the Profiler improves this filter introducing the condition parameter.

For instance, let’s take the following filter:

Conditional misc/basic

It xors every byte if different than 0xFF and 0. The ‘misc/basic‘ filter can be used to express even more complex operations such as:

Advanced misc/basic

In this case the the filter xors every third dword with 0xAABBCCDD, following the pattern ‘xor skip skip’, in little endian mode and only if the value is different than 0 and 0xAABBCCDD. While lots of operations can be expressed with this filter, there are limits.

This is why Lua filters have been introduced. Right now there are two such filters available: ‘lua/custom‘ and ‘lua/loop‘. Let’s start with the second one which is just a shortcut.

lua/loop

if e ~= 0 and e ~= 0xFF then e = bit.bxor(e, 0xFF) end

This script does the exact same thing as the first example of the ‘misc/basic‘ filter: it xors every byte if different than 0xFF and 0. In this specific case there’s no reason to use a Lua filter. In fact, Lua filters are considerably slower than native filters. Thus, they should be used only when the operation is too complex to be expressed with any of the default filters.

While ‘lua/loop‘ is inteded for simple loop operations, ‘lua/custom‘, as the name suggests, can be used to implement a custom filter logic. Here’s an example, which again does the same thing as the previous example:

function run(filter)
    local c = filter:container()
    local size = c:size()
    local offset = 0
    local bsize = 16384
    while size ~= 0 do
        if bsize > size then bsize = size end
        local block = c:read(offset, bsize)
        local boffs = 0
        while boffs < bsize do
            local e = block:readU8(boffs)
            if e ~= 0 and e ~= 0xFF then e = bit.bxor(e, 0xFF) end
            block:writeU8(boffs, e)
            boffs = boffs + 1
        end
        c:write(offset, block)
        offset = offset + bsize
        size = size - bsize
    end
    return Base.FilterErr_None
end

The security of these scripting filters is very high. They run in a special sandboxed environment, have access only to a minimum set of secure functions, are limited in memory consumption (2 MBs by default, but it can be configured from the settings) and can be interrupted at any time by the user.

If you still don't wish to allow script filters, they can be disabled from the settings.

Lua filters settings

The Lua VM is almost vanilla, the only difference is that it allows for 64-bit numbers. As you can observe from the examples, the Lua library for bitwise operations has been renamed from 'bit32' to 'bit'.

We'll see some practical usage samples in the near future. Stay tuned!