public LuaScriptLine(LuaInstruction instr, LuaDecoder decoder, LuaFunction func) { this.Instr = instr; this.Func = func; this.Decoder = decoder; SetType(); SetMain(); }
private List <LuaInstruction> ReadInstructions() { List <LuaInstruction> Instructions = new List <LuaInstruction>(); int count = GetInt(); // 4 or 8? for (int i = 0; i < count; i++) { // TODO: handle CLOSURE?? LuaInstruction instr = new LuaInstruction(GetInt()); Instructions.Add(instr); } return(Instructions); }
public void RewriteVariables(int offset) { // Rewrite the variables x by adding mov prefix+x = x and then replacing all x by prefix+x List <int> changedVariables = new List <int>(); for (int i = 0; i < this.Lines.Count; i++) { LuaInstruction fake = new LuaInstruction(this.Lines[i].Instr.Data); changedVariables.AddRange(fake.OffsetVariables(offset)); this.Lines[i].SetMain(fake); } var vars = changedVariables.Distinct(); foreach (var v in vars) { // TODO: add instr to start! } }
public void SetMain(LuaInstruction Instr = null) { if (Instr == null) { Instr = this.Instr; } switch (Instr.OpCode) { case LuaOpcode.MOVE: this.Op1 = WriteIndex(Instr.A); this.Op2 = " = "; this.Op3 = WriteIndex(Instr.B); break; case LuaOpcode.LOADK: this.Op1 = WriteIndex(Instr.A); this.Op2 = " = "; this.Op3 = GetConstant(Instr.Bx); break; case LuaOpcode.LOADBOOL: this.Op1 = WriteIndex(Instr.A); this.Op2 = " = "; this.Op3 = Instr.B != 0 ? "true" : "false"; break; case LuaOpcode.LOADNIL: for (int i = Instr.A; i < Instr.B + 1; ++i) { this.Op2 += $"{WriteIndex(i)} = nil; "; // NOTE: wont conflict with 'local' keyword? //this.Op2 += $"{WriteIndex(i)}"; // NOTE: keep it clean? (TODO: figure out 'local' keyword) //if (i < Instr.B - 1) // this.Op2 += ", "; // inline } break; case LuaOpcode.GETUPVAL: // NOTE: child get local from parent this.Op1 = WriteIndex(Instr.A); this.Op2 = " = "; this.Op3 = WriteIndex(Instr.B); // TODO: figure if an upvalue is a function or not? if (this.Func.Upvalues.Count > Instr.B) { this.Op3 = this.Func.Upvalues[Instr.B].ToString(); } //this.Op3 = this.Func.Upvalues[Instr.B].ToString().Substring(1, this.Func.Upvalues[Instr.B].ToString().Length - 2); // this is legit for prototypes etc break; case LuaOpcode.GETGLOBAL: this.Op1 = $"{WriteIndex(Instr.A)} = _G["; this.Op2 = GetConstant(Instr.Bx); // may be used lateron this.Op3 = $"]"; break; case LuaOpcode.GETTABLE: this.Op1 = WriteIndex(Instr.A); this.Op2 = " = "; this.Op3 = $"var{Instr.B}[{WriteIndex(Instr.C)}]"; // TODO: fix??? break; case LuaOpcode.SETGLOBAL: this.Op1 = $"_G[{GetConstant(Instr.Bx)}]"; this.Op2 = " = "; this.Op3 = $"var{Instr.A}"; break; case LuaOpcode.SETUPVAL: // NOTE: child writes to parent locals this.Op1 = $"{WriteIndex(Instr.B)}"; // no? this.Op2 = " = "; this.Op3 = $"{GetConstant(Instr.A)}"; break; case LuaOpcode.SETTABLE: this.Op1 = $"{WriteIndex(Instr.A)}[{WriteIndex(Instr.B)}]"; this.Op2 = " = "; this.Op3 = WriteIndex(Instr.C); break; case LuaOpcode.NEWTABLE: this.Op1 = WriteIndex(Instr.A); this.Op2 = " = "; this.Op3 = "{}"; break; case LuaOpcode.SELF: this.Op1 = $"{WriteIndex(Instr.A+1)} = {WriteIndex(Instr.B)}; "; // set self this.Op2 = $"{WriteIndex(Instr.A)} = "; this.Op3 = $"var{Instr.B}[{WriteIndex(Instr.C)}]"; // A = element // B = ref to table // C = methode itself // TODO fix, multiline? break; case LuaOpcode.ADD: // NOTE these can be both variables and constants! this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = {WriteConstant(Instr.B)}"; this.Op3 = $" + {WriteConstant(Instr.C)}"; break; case LuaOpcode.SUB: this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = {WriteConstant(Instr.B)}"; this.Op3 = $" - {WriteConstant(Instr.C)}"; break; case LuaOpcode.MUL: this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = {WriteConstant(Instr.B)}"; this.Op3 = $" * {WriteConstant(Instr.C)}"; break; case LuaOpcode.DIV: this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = {WriteConstant(Instr.B)}"; this.Op3 = $" / {WriteConstant(Instr.C)}"; break; case LuaOpcode.MOD: this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = {WriteConstant(Instr.B)}"; this.Op3 = $" % {WriteConstant(Instr.C)}"; break; case LuaOpcode.POW: this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = {WriteConstant(Instr.B)}"; //this.Op3 = $" ^ var{Instr.C}"; // not always? this.Op3 = $" ^ {WriteConstant(Instr.C)}"; // not always? break; case LuaOpcode.UNM: this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = "; this.Op3 = $"-var{Instr.B}"; break; case LuaOpcode.NOT: this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = "; this.Op3 = $"not var{Instr.B}"; break; case LuaOpcode.LEN: this.Op1 = WriteIndex(Instr.A); this.Op2 = $" = "; this.Op3 = $"#var{Instr.B}"; break; case LuaOpcode.CONCAT: this.Op1 = $"{WriteIndex(Instr.A)} = "; for (int i = Instr.B; i <= Instr.C; ++i) { this.Op2 += $"{WriteIndex(i)}"; if (i < Instr.C) { this.Op2 += " .. "; } } break; case LuaOpcode.JMP: // Do nothing ;D? //this.Op3 = $"JMP {Instr.sBx}"; // NOTE: uncomment for debugging break; case LuaOpcode.EQ: this.Op1 = $"if"; //this.Op2 = $" ({WriteIndex(Instr.B)} == {WriteIndex(Instr.C)}) ~= {Instr.A} "; // A = and/or //if (Instr.A == 0) this.Op2 = $" {WriteIndex(Instr.B)} == {WriteIndex(Instr.C)} "; //else // this.Op2 = $" {WriteIndex(Instr.B)} ~= {WriteIndex(Instr.C)} "; this.Op3 = $"then"; break; case LuaOpcode.LT: this.Op1 = $"if"; //this.Op2 = $"({WriteIndex(Instr.B)} < {WriteIndex(Instr.C)}) ~= {Instr.A} "; //if(Instr.A == 0) this.Op2 = $" {WriteIndex(Instr.B)} < {WriteIndex(Instr.C)} "; //else // this.Op2 = $" {WriteIndex(Instr.B)} > {WriteIndex(Instr.C)} "; this.Op3 = $"then"; break; case LuaOpcode.LE: this.Op1 = $"if"; //this.Op2 = $" ({WriteIndex(Instr.B)} <= {WriteIndex(Instr.C)}) ~= {Instr.A} "; //if (Instr.A == 0) this.Op2 = $" {WriteIndex(Instr.B)} <= {WriteIndex(Instr.C)} "; //else // this.Op2 = $" {WriteIndex(Instr.B)} >= {WriteIndex(Instr.C)} "; this.Op3 = $"then"; break; case LuaOpcode.TEST: this.Op1 = $"if"; if (Instr.C == 1) { this.Op2 = $" not var{Instr.A} "; } else { this.Op2 = $" var{Instr.A} "; } this.Op3 = $"then"; break; case LuaOpcode.TESTSET: this.Op1 = $"if var{Instr.B} ~= {Instr.C} then; "; this.Op2 = $"var{Instr.A} = "; this.Op3 = $"var{Instr.B}; end"; break; case LuaOpcode.CALL: // TODO: there is something off here? // Function returns if (Instr.C == 0) { // top set to last_result+1 } else if (Instr.C == 1) { // no return values saved } else // 2 or more, multiple returns { //for (int i = Instr.A; i < Instr.A + Instr.C-1; ++i) for (int i = Instr.A; i < Instr.A + Instr.C - 1; i++) { this.Op1 += $"var{i}"; if (i < Instr.A + Instr.C - 2) { this.Op1 += ", "; } } this.Op1 += " = "; } // Function Name this.Op2 = $"var{Instr.A}"; // func name only (used lateron) // Function Args if (Instr.B == 0) { // func parms range from A+1 to B (B = top of stack) this.Op3 = "("; for (int i = Instr.A; i < Instr.B; i++) //for (int i = Instr.A; i < Instr.A + Instr.B - 1; ++i) { this.Op3 += $"var{i + 1}"; if (i < Instr.A + Instr.B - 2) { this.Op3 += ", "; } } this.Op3 += ")"; } else { this.Op3 = "("; for (int i = Instr.A; i < Instr.A + Instr.B - 1; i++) //for (int i = Instr.A; i < Instr.A + Instr.B - 1; ++i) { this.Op3 += $"var{i + 1}"; if (i < Instr.A + Instr.B - 2) { this.Op3 += ", "; } } this.Op3 += ")"; } break; case LuaOpcode.TAILCALL: // TODO: there is something off here? // NOTE: C functions have 2 returns while Lua functions only have 1 return? // Function Name this.Op1 = $"return var{Instr.A}"; // func name only (used lateron) //this.Op2 = $"({Instr.A+1}"; // Function Args if (Instr.B == 0) { // func parms range from A+1 to B (B = top of stack) this.Op3 = $"("; for (int i = Instr.A; i < Instr.B; i++) //for (int i = Instr.A; i < Instr.A + Instr.B - 1; ++i) { this.Op3 += $"var{i + 1}"; if (i < Instr.A + Instr.B - 2) { this.Op3 += ", "; } } this.Op3 += ")"; } else { this.Op3 = $"("; for (int i = Instr.A; i < Instr.A + Instr.B - 1; i++) //for (int i = Instr.A; i < Instr.A + Instr.B - 1; ++i) { this.Op3 += $"var{i + 1}"; if (i < Instr.A + Instr.B - 2) { this.Op3 += ", "; } } this.Op3 += ")"; } break; case LuaOpcode.RETURN: // this gets overwritten by an 'end' afterwards in case its the last RETURN value of a func this.Op1 = $"return"; if (Instr.B == 1) { break; // no arguments } else if (Instr.B > 1) { for (int j = 0; j < Instr.B - 1; j++) { this.Op2 += $" {WriteIndex(Instr.A + j)}"; // args from A to A+(B-2) if (j < Instr.B - 2) { this.Op2 += ","; } } } else { for (int j = Instr.A; j < this.Func.MaxStackSize; j++) { this.Op2 += $"{WriteIndex(Instr.A + j)}"; // args from A to top if (j < this.Func.MaxStackSize - 1) { this.Op2 += ","; } } } break; case LuaOpcode.FORLOOP: //this.Op1 = "end"; // performs a negative jump to start of loop based on condition break; case LuaOpcode.FORPREP: // A+0: i = // A+1: max // A+2: += // A+3: external index this.Op1 = $"for {WriteIndex(Instr.A + 3, false)}={WriteIndex(Instr.A)}, {WriteIndex(Instr.A + 1)}, {WriteIndex(Instr.A + 2)} do"; break; case LuaOpcode.TFORLOOP: this.Op1 = WriteIndex(Instr.A + 1) + ", " + WriteIndex(Instr.A + 2); // state for (int i = Instr.A + 3; i <= Instr.A + 2 + Instr.C; i++) // local loop variable result, A+3 up to A+2+C { this.Op2 += WriteIndex(i); if (i < Instr.A + 2 + Instr.C) { this.Op2 += ", "; } } this.Op3 = WriteIndex(Instr.A); // iterator func break; case LuaOpcode.SETLIST: this.Op1 = $"{WriteIndex(Instr.A)} = {{"; for (int i = 1; i <= Instr.B; i++) { this.Op2 += $"{WriteIndex(Instr.A + i)}"; if (i < Instr.B) { this.Op2 += ", "; } } this.Op3 = "}"; break; case LuaOpcode.CLOSE: // NOTE: close all variables in the stack up to (>=) R(A) // this.FunctionRef = ... // TODO: print this one out right here break; case LuaOpcode.CLOSURE: // NOTE: obfuscator can inline to give mindfuck ;D? // crates closutre for function prototype Bx this.Op1 = $"{WriteIndex(Instr.A)}"; this.Op2 = " = "; if (this.Func.Functions[Instr.Bx].ScriptFunction != null) { this.Op3 = this.Func.Functions[Instr.Bx].ScriptFunction.Name; } else { this.Op3 = $"IDK_SHIT_WENT_MISSING_BRO"; // TODO fix } break; case LuaOpcode.VARARG: this.Func.ScriptFunction.HasVarargs = true; this.Op1 = "local "; for (int i = Instr.A; i < Instr.A + Instr.B - 1; i++) { this.Op2 += $"var{i}"; if (i < Instr.B - 2) { this.Op2 += ", "; } } this.Op2 += " = ..."; break; default: this.Op1 = "unk"; this.Op2 = "_"; this.Op3 = Instr.OpCode.ToString(); break; } }