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?