Skip to content

Instantly share code, notes, and snippets.

@jLn0n
Last active March 16, 2026 03:04
Show Gist options
  • Select an option

  • Save jLn0n/58068c181bdc4ad1906f6f53a87293cf to your computer and use it in GitHub Desktop.

Select an option

Save jLn0n/58068c181bdc4ad1906f6f53a87293cf to your computer and use it in GitHub Desktop.
imhex pattern formats
#pragma author jLn0n
#pragma description Luau bytecode V6
import std.io;
import std.mem;
import std.math;
import std.sys;
import type.base;
namespace VarInt32 {
fn transform_bytes(ref auto bytes) {
u128 res = 0;
for(u8 i = 0, (i < sizeof(bytes)), i += 1) {
res |= u128(bytes[i] & 0x7F) << i * 7;
if ((bytes[i] & 0x80) == 0) break;
}
return res;
};
fn transform(auto value) {
return VarInt32::transform_bytes(value.bytes);
};
fn format(auto value) {
u128 res = VarInt32::transform_bytes(value.bytes);
return std::format("{} ({:#x})", res, res);
};
fn size(auto addy) {
u8 len = 0;
while (len < 5) {
if ((std::mem::read_unsigned(addy + len, 1) & 0x80) == 0) {
len += 1;
break;
}
len += 1;
}
return len;
};
}
struct VarInt32 {
u8 bytes[VarInt32::size($)] [[hidden]];
} [[sealed, format("VarInt32::format"), transform("VarInt32::transform")]];
namespace Luau {
enum Opcode: u8 {
NOP = 0,
BREAK = 1,
LOADNIL = 2,
LOADB = 3,
LOADN = 4,
LOADK = 5,
MOVE = 6,
GETGLOBAL = 7,
SETGLOBAL = 8,
GETUPVAL = 9,
SETUPVAL = 10,
CLOSEUPVALS = 11,
GETIMPORT = 12,
GETTABLE = 13,
SETTABLE = 14,
GETTABLEKS = 15,
SETTABLEKS = 16,
GETTABLEN = 17,
SETTABLEN = 18,
NEWCLOSURE = 19,
NAMECALL = 20,
CALL = 21,
RETURN = 22,
JUMP = 23,
JUMPBACK = 24,
JUMPIF = 25,
JUMPIFNOT = 26,
JUMPIFEQ = 27,
JUMPIFLE = 28,
JUMPIFLT = 29,
JUMPIFNOTEQ = 30,
JUMPIFNOTLE = 31,
JUMPIFNOTLT = 32,
ADD = 33,
SUB = 34,
MUL = 35,
DIV = 36,
MOD = 37,
POW = 38,
ADDK = 39,
SUBK = 40,
MULK = 41,
DIVK = 42,
MODK = 43,
POWK = 44,
AND = 45,
OR = 46,
ANDK = 47,
ORK = 48,
CONCAT = 49,
NOT = 50,
MINUS = 51,
LENGTH = 52,
NEWTABLE = 53,
DUPTABLE = 54,
SETLIST = 55,
FORNPREP = 56,
FORNLOOP = 57,
FORGLOOP = 58,
FORGPREP_INEXT = 59,
FASTCALL3 = 60,
FORGPREP_NEXT = 61,
DEP_FORGLOOP_NEXT = 62,
GETVARARGS = 63,
DUPCLOSURE = 64,
PREPVARARGS = 65,
LOADKX = 66,
JUMPX = 67,
FASTCALL = 68,
COVERAGE = 69,
CAPTURE = 70,
SUBRK = 71,
DIVRK = 72,
FASTCALL1 = 73,
FASTCALL2 = 74,
FASTCALL2K = 75,
FORGPREP = 76,
JUMPXEQKNIL = 77,
JUMPXEQKB = 78,
JUMPXEQKN = 79,
JUMPXEQKS = 80,
IDIV = 81,
IDIVK = 82,
};
enum ConstantType: u8 {
Nil = 0,
Boolean = 1,
Number = 2,
String = 3,
Import = 4,
Table = 5,
Closure = 6,
Vector = 7,
};
fn opcodeHasAux(Opcode opcode) {
return (
opcode == Opcode::GETGLOBAL ||
opcode == Opcode::SETGLOBAL ||
opcode == Opcode::GETIMPORT ||
opcode == Opcode::GETTABLEKS ||
opcode == Opcode::SETTABLEKS ||
opcode == Opcode::NAMECALL ||
opcode == Opcode::JUMPIFEQ ||
opcode == Opcode::JUMPIFLE ||
opcode == Opcode::JUMPIFLT ||
opcode == Opcode::JUMPIFNOTEQ ||
opcode == Opcode::JUMPIFNOTLE ||
opcode == Opcode::JUMPIFNOTLT ||
opcode == Opcode::NEWTABLE ||
opcode == Opcode::SETLIST ||
opcode == Opcode::FORGLOOP ||
opcode == Opcode::FASTCALL3 ||
opcode == Opcode::LOADKX ||
opcode == Opcode::FASTCALL2 ||
opcode == Opcode::FASTCALL2K ||
opcode == Opcode::JUMPXEQKNIL ||
opcode == Opcode::JUMPXEQKB ||
opcode == Opcode::JUMPXEQKN ||
opcode == Opcode::JUMPXEQKS
);
};
fn getInstructionPopulation(auto size, auto addy) {
u32 result = size;
for (u32 i = 0, i < size, i += 1) {
u8 opcode = std::mem::read_unsigned(addy + (i * 4), 1);
if (Luau::opcodeHasAux(opcode)) {
i += 1;
result -= 1;
}
}
return result;
};
fn format_LuauString(auto string) {
if (string.size == 0) {
return "None";
}
return std::format("({} bytes) {}", sizeof(string.data), string.data);
};
fn colorify_LuauString(auto string) {
if (string.size < 1) {
return "FFFFFF";
}
u128 lsb_addy = $ - string.size;
u8 lsb_size = std::math::min(string.size, 16);
u128 lsb1 = std::mem::read_unsigned(lsb_addy, lsb_size, std::mem::Endian::Little);
u128 lsb2 = std::mem::read_unsigned(lsb_addy, lsb_size, std::mem::Endian::Big);
u128 rsb1 = 0;
u128 rsb2 = 0;
if (string.size > 16) {
u8 rsb_size = std::math::min(string.size - 16, 16);
u128 rsb_addy = $ - rsb_size;
rsb1 = std::mem::read_unsigned(rsb_addy, rsb_size, std::mem::Endian::Little);
rsb2 = std::mem::read_unsigned(rsb_addy, rsb_size, std::mem::Endian::Big);
}
u32 hash = (lsb1 ^ lsb2) | (string.size << 5);
hash = ((hash << 5) - hash);
if (string.size > 16) {
hash ^= (rsb1 ^ rsb2);
hash = ((hash << 5) - hash);
}
return std::format("{:08X}", hash);
};
fn format_LuauConstant(auto constant) {
str value = "";
if (constant.type == ConstantType::Nil) {
value = "nil";
} else if (constant.type == ConstantType::String) {
value = std::format("strings[{}]", constant.data);
} else if (constant.type == ConstantType::Import) {
value = std::format("import[{:#x}]", constant.data);
} else if (constant.type == ConstantType::Table) {
value = "{}";
} else if (constant.type == ConstantType::Closure) {
value = std::format("proto[{}]", constant.data);
} else if (constant.type == ConstantType::Vector) {
value = std::format(
"({}, {}, {}, {})",
constant.data.x,
constant.data.y,
constant.data.z,
constant.data.w
);
} else {
value = std::format("{}", constant.data);
}
return std::format("({}) {}", constant.type, value);
};
fn colorify_LuauConstant(ConstantType type) {
if (type == ConstantType::Nil) {
return "9E9E9E";
} else if (type == ConstantType::Boolean) {
return "FF6A00";
} else if (type == ConstantType::Number) {
return "007BFF";
} else if (type == ConstantType::String) {
return "00D84A";
} else if (type == ConstantType::Import) {
return "A000FF";
} else if (type == ConstantType::Table) {
return "00E5E5";
} else if (type == ConstantType::Closure) {
return "FF007F";
} else if (type == ConstantType::Vector) {
return "FFE600";
}
return "FFFFFF";
};
fn format_LuauInstruction(auto instruction) {
return std::format("{}", instruction.opcode);
};
}
struct Vector<T> {
VarInt32 size;
if (size > 0) {
T values[size];
}
};
namespace Luau {
namespace Constants {
struct String {
VarInt32 size;
if (size > 0) {
char data[size];
}
} [[sealed, format("Luau::format_LuauString"), color(Luau::colorify_LuauString(this))]];
struct Table {
VarInt32 size;
VarInt32 kidx[size];
};
struct Vector {
float x, y, z, w;
} [[static]];
}
namespace Prototype {
bitfield Flags {
bool nativeModule: 1;
bool nativeCold: 1;
bool nativeFunction: 1;
};
bitfield Constant {
ConstantType type: 8;
match (type) {
(ConstantType::Nil): data: 0;
(ConstantType::Boolean): bool data;
(ConstantType::Number): double data;
(ConstantType::String): VarInt32 data;
(ConstantType::Import): u32 data;
(ConstantType::Table): Constants::Table data;
(ConstantType::Closure): VarInt32 data;
(ConstantType::Vector): Constants::Vector data;
}
} [[sealed, format("Luau::format_LuauConstant"), color(Luau::colorify_LuauConstant(type))]];
bitfield Instruction {
Luau::Opcode opcode: 8 [[color("00FFFF")]];
data: 24 [[color("008080")]];
if (Luau::opcodeHasAux(opcode)) {
u32 aux [[color("40FF40")]];
}
} [[format("Luau::format_LuauInstruction")]];
struct Instructions {
VarInt32 size;
Instruction data[Luau::getInstructionPopulation(size, $)];
};
namespace TypeInfo {
struct Local {
u8 type;
u8 reg;
VarInt32 startpc;
VarInt32 endpc;
};
}
struct TypeInfo {
VarInt32 size;
if (size > 0) {
VarInt32 upvalssize;
VarInt32 localssize;
u8 upvalues[upvalssize];
TypeInfo::Local locals[localssize];
}
};
struct LineInfo<auto codesize> {
bool enabled [[color("676740")]];
if (enabled) {
u8 linegaplog2;
u8 lineinfo[codesize];
u32 abslineinfo[((codesize - 1) >> linegaplog2) + 1];
}
};
namespace DebugInfo {
struct Local {
VarInt32 name;
VarInt32 startpc;
VarInt32 endpc;
u8 reg;
};
struct Upvalue {
VarInt32 name;
};
}
struct DebugInfo {
bool enabled;
if (enabled) {
Vector<DebugInfo::Local> locals;
Vector<DebugInfo::Upvalue> upvals;
}
};
}
struct Prototype {
u8 maxstacksize;
u8 numparams;
u8 numupvalues;
bool isvararg;
Prototype::Flags flags;
Prototype::TypeInfo typeinfo;
Prototype::Instructions code;
Vector<Prototype::Constant> constants;
Vector<VarInt32> protos;
VarInt32 linedefined;
VarInt32 debugnameindex;
Prototype::LineInfo<code.size> lineinfo;
Prototype::DebugInfo debuginfo;
};
struct Header {
u8 version;
std::assert(version == 6, "Luau bytecode v6 is only supported.");
u8 typesVersion;
} [[static]];
struct File {
Header header [[color("FF00FF")]];
Vector<Constants::String> strings [[color("80FF00")]];
if (header.typesVersion == 3) {
// skipped
u8 userdataRemapIndex;
if (userdataRemapIndex != 0) {
$ += VarInt32::size($);
continue;
}
}
Vector<Prototype> protos;
VarInt32 mainproto;
};
}
Luau::File file @ 0;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment