Ctrl + E to execute Ctrl + S to save Ctrl + M to halt
/*
** basic types
*/
#define LUA_TNONE (-1)
#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
/*
** tags for Tagged Values have the following use of bits:
** bits 0-3: actual tag (a LUA_T* constant)
** bits 4-5: variant bits
** bit 6: whether value is collectable
*/
/* add variant bits to a type */
#define makevariant(t,v) ((t) | ((v) << 4))
/* Variant tags for strings */
#define LUA_VSHRSTR makevariant(LUA_TSTRING, 0) /* short strings */
#define LUA_VLNGSTR makevariant(LUA_TSTRING, 1) /* long strings */
/* Variant tags for functions */
#define LUA_VLCL makevariant(LUA_TFUNCTION, 0) /* Lua closure */
#define LUA_VLCF makevariant(LUA_TFUNCTION, 1) /* light C function */
#define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */
struct TValue {
+0: (typedef Value) value_
+8: (typedef lu_byte) tt_ // Type of the TValue. Ex: LUA_TNUMBER
}
struct TString {
+0: (struct GCObject *) next
+4: (typedef lu_byte) tt
+5: (typedef lu_byte) marked
+6: (typedef lu_byte) extra
+7: (typedef lu_byte) shrlen
+8: (unsigned int) hash
+12: (union {
size_t lnglen;
TString *hnext;
}) u
+16: (char[1]) contents
}
struct UpVal {
+0: (struct GCObject *) next
+4: (typedef lu_byte) tt
+5: (typedef lu_byte) marked
+8: (union {
TValue *p;
ptrdiff_t offset;
}) v
+16: (union {
struct {
UpVal *next;
UpVal **previous;
};
UpVal::(unnamed struct) open;
TValue value;
}) u
}
struct LClosure {
+0: (struct GCObject *) next
+4: (typedef lu_byte) tt
+5: (typedef lu_byte) marked
+6: (typedef lu_byte) nupvalues
+8: (GCObject *) gclist
+12: (struct Proto *) p
+16: (UpVal *[1]) upvals
}
struct CClosure {
+0: (struct GCObject *) next
+4: (typedef lu_byte) tt
+5: (typedef lu_byte) marked
+6: (typedef lu_byte) nupvalues
+8: (GCObject *) gclist
+12: (typedef lua_CFunction) f
+16: (TValue[1]) upvalue
}
typedef enum {
/*----------------------------------------------------------------------
name args description
------------------------------------------------------------------------*/
/* A B R[A] := R[B] */
OP_MOVE,
/* A sBx R[A] := sBx */
OP_LOADI,
/* A sBx R[A] := (lua_Number)sBx */
OP_LOADF,
/* A Bx R[A] := K[Bx] */
OP_LOADK,
/* A R[A] := K[extra arg] */
OP_LOADKX,
/* A R[A] := false */
OP_LOADFALSE,
/*A R[A] := false; pc++ (*) */
OP_LFALSESKIP,
/* A R[A] := true */
OP_LOADTRUE,
/* A B R[A], R[A+1], ..., R[A+B] := nil */
OP_LOADNIL,
/* A B R[A] := UpValue[B] */
OP_GETUPVAL,
/* A B UpValue[B] := R[A] */
OP_SETUPVAL,
/* A B C R[A] := UpValue[B][K[C]:string] */
OP_GETTABUP,
/* A B C R[A] := R[B][R[C]] */
OP_GETTABLE,
/* A B C R[A] := R[B][C] */
OP_GETI,
/* A B C R[A] := R[B][K[C]:string] */
OP_GETFIELD,
/* A B C UpValue[A][K[B]:string] := RK(C) */
OP_SETTABUP,
/* A B C R[A][R[B]] := RK(C) */
OP_SETTABLE,
/* A B C R[A][B] := RK(C) */
OP_SETI,
/* A B C R[A][K[B]:string] := RK(C) */
OP_SETFIELD,
/* A B C k R[A] := {} */
OP_NEWTABLE,
/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */
OP_SELF,
/* A B sC R[A] := R[B] + sC */
OP_ADDI,
/* A B C R[A] := R[B] + K[C]:number */
OP_ADDK,
/* A B C R[A] := R[B] - K[C]:number */
OP_SUBK,
/* A B C R[A] := R[B] * K[C]:number */
OP_MULK,
/* A B C R[A] := R[B] % K[C]:number */
OP_MODK,
/* A B C R[A] := R[B] ^ K[C]:number */
OP_POWK,
/* A B C R[A] := R[B] / K[C]:number */
OP_DIVK,
/* A B C R[A] := R[B] // K[C]:number */
OP_IDIVK,
/* A B C R[A] := R[B] & K[C]:integer */
OP_BANDK,
/* A B C R[A] := R[B] | K[C]:integer */
OP_BORK,
/* A B C R[A] := R[B] ~ K[C]:integer */
OP_BXORK,
/* A B sC R[A] := R[B] >> sC */
OP_SHRI,
/* A B sC R[A] := sC << R[B] */
OP_SHLI,
/* A B C R[A] := R[B] + R[C] */
OP_ADD,
/* A B C R[A] := R[B] - R[C] */
OP_SUB,
/* A B C R[A] := R[B] * R[C] */
OP_MUL,
/* A B C R[A] := R[B] % R[C] */
OP_MOD,
/* A B C R[A] := R[B] ^ R[C] */
OP_POW,
/* A B C R[A] := R[B] / R[C] */
OP_DIV,
/* A B C R[A] := R[B] // R[C] */
OP_IDIV,
/* A B C R[A] := R[B] & R[C] */
OP_BAND,
/* A B C R[A] := R[B] & R[C] */
OP_BOR,
/* A B C R[A] := R[B] ~ R[C] */
OP_BXOR,
/* A B C R[A] := R[B] << R[C] */
OP_SHL,
/* A B C R[A] := R[B] >> R[C] */
OP_SHR,
/* A B C call C metamethod over R[A] and R[B] (*) */
OP_MMBIN,
/* A sB C k call C metamethod over R[A] and sB */
OP_MMBINI,
/* A B C k call C metamethod over R[A] and K[B] */
OP_MMBINK,
/* A B R[A] := -R[B] */
OP_UNM,
/* A B R[A] := ~R[B] */
OP_BNOT,
/* A B R[A] := not R[B] */
OP_NOT,
/* A B R[A] := #R[B] (length operator) */
OP_LEN,
/* A B R[A] := R[A].. ... ..R[A + B - 1] */
OP_CONCAT,
/* A close all upvalues >= R[A] */
OP_CLOSE,
/* A mark variable A "to be closed" */
OP_TBC,
/* sJ pc += sJ */
OP_JMP,
/* A B k if ((R[A] == R[B]) ~= k) then pc++ */
OP_EQ,
/* A B k if ((R[A] < R[B]) ~= k) then pc++ */
OP_LT,
/* A B k if ((R[A] <= R[B]) ~= k) then pc++ */
OP_LE,
/* A B k if ((R[A] == K[B]) ~= k) then pc++ */
OP_EQK,
/* A sB k if ((R[A] == sB) ~= k) then pc++ */
OP_EQI,
/* A sB k if ((R[A] < sB) ~= k) then pc++ */
OP_LTI,
/* A sB k if ((R[A] <= sB) ~= k) then pc++ */
OP_LEI,
/* A sB k if ((R[A] > sB) ~= k) then pc++ */
OP_GTI,
/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
OP_GEI,
/* A k if (not R[A] == k) then pc++ */
OP_TEST,
/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */
OP_TESTSET,
/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
OP_CALL,
/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
OP_TAILCALL,
/* A B C k return R[A], ... ,R[A+B-2] (see note) */
OP_RETURN,
/* return */
OP_RETURN0,
/* A return R[A] */
OP_RETURN1,
/* A Bx update counters; if loop continues then pc-=Bx; */
OP_FORLOOP,
/* A Bx check values and prepare counters; if not to run then pc+=Bx+1; */
OP_FORPREP,
/* A Bx create upvalue for R[A + 3]; pc+=Bx */
OP_TFORPREP,
/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
OP_TFORCALL,
/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
OP_TFORLOOP,
/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */
OP_SETLIST,
/* A Bx R[A] := closure(KPROTO[Bx]) */
OP_CLOSURE,
/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
OP_VARARG,
/*A (adjust vararg parameters) */
OP_VARARGPREP,
/* Ax extra (larger) argument for previous opcode */
OP_EXTRAARG
} OpCode;
Goals:
❌ Wait, it's all TValues? Confuse Types in a loop to leak addresses
❌ Trust is the weakest link Point an upvalue to the previous Closure by abusing bytecode
❌ If it looks like a Closure Gain control of a Closure by confusing types
❌ Unleash the beast Craft Fake Objects to leverage the power of Lua
❌ The Great Escape Is there even an exit?