├── IronBrew2 CLI ├── IronBrew2 CLI.csproj └── Program.cs ├── IronBrew2 ├── Bytecode Library │ ├── Bytecode │ │ ├── Deserializer.cs │ │ ├── Opcode.cs │ │ ├── Serializer.cs │ │ └── VanillaSerializer.cs │ └── IR │ │ ├── Chunk.cs │ │ ├── Constant.cs │ │ ├── Enums.cs │ │ └── Instruction.cs ├── Extensions │ ├── IEnumerableExtensions.cs │ └── StringExtensions.cs ├── IronBrew2.csproj ├── Obfuscator │ ├── Control Flow │ │ ├── Blocks │ │ │ └── Block.cs │ │ ├── CFContext.cs │ │ ├── CFGenerator.cs │ │ └── Types │ │ │ ├── Bounce.cs │ │ │ ├── EqMutate.cs │ │ │ ├── Inlining.cs │ │ │ ├── NumberMutate.cs │ │ │ ├── TestFlip.cs │ │ │ ├── TestPreserve.cs │ │ │ └── TestSpam.cs │ ├── CustomInstructionData.cs │ ├── Encryption │ │ ├── ConstantEncryption.cs │ │ └── VMIntegrityCheck.cs │ ├── Macros │ │ ├── Crash.cs │ │ ├── SetFenv.cs │ │ └── StrEncrypt.cs │ ├── ObfuscationContext.cs │ ├── ObfuscationSettings.cs │ ├── Opcodes │ │ ├── OpAdd.cs │ │ ├── OpCall.cs │ │ ├── OpClose.cs │ │ ├── OpClosure.cs │ │ ├── OpConcat.cs │ │ ├── OpDiv.cs │ │ ├── OpEq.cs │ │ ├── OpForLoop.cs │ │ ├── OpForPrep.cs │ │ ├── OpGe.cs │ │ ├── OpGetGlobal.cs │ │ ├── OpGetTable.cs │ │ ├── OpGetUpval.cs │ │ ├── OpGt.cs │ │ ├── OpJmp.cs │ │ ├── OpLe.cs │ │ ├── OpLen.cs │ │ ├── OpLoadBool.cs │ │ ├── OpLoadK.cs │ │ ├── OpLoadNil.cs │ │ ├── OpLoadStr.cs │ │ ├── OpLt.cs │ │ ├── OpMod.cs │ │ ├── OpMove.cs │ │ ├── OpMul.cs │ │ ├── OpMutated.cs │ │ ├── OpNe.cs │ │ ├── OpNewStk.cs │ │ ├── OpNewTable.cs │ │ ├── OpNot.cs │ │ ├── OpPow.cs │ │ ├── OpPushStk.cs │ │ ├── OpReturn.cs │ │ ├── OpSelf.cs │ │ ├── OpSetFEnv.cs │ │ ├── OpSetGlobal.cs │ │ ├── OpSetList.cs │ │ ├── OpSetTable.cs │ │ ├── OpSetTop.cs │ │ ├── OpSetUpval.cs │ │ ├── OpSub.cs │ │ ├── OpSuperOperator.cs │ │ ├── OpTForLoop.cs │ │ ├── OpTailCall.cs │ │ ├── OpTest.cs │ │ ├── OpTestSet.cs │ │ ├── OpUnm.cs │ │ └── OpVarArg.cs │ ├── VM Generation │ │ ├── Generator.cs │ │ └── VMStrings.cs │ └── VOpcode.cs └── Program.cs └── Lua ├── Minifier ├── fs.lua ├── init.lua ├── llex.lua ├── lparser.lua ├── luasrcdiet.lua ├── optlex.lua ├── optparser.lua └── utils.lua └── compress.lua /IronBrew2 CLI/IronBrew2 CLI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.2 6 | IronBrew2_CLI 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /IronBrew2 CLI/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using IronBrew2; 5 | using IronBrew2.Obfuscator; 6 | 7 | namespace IronBrew2_CLI 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | Directory.CreateDirectory("temp"); 14 | if (!IB2.Obfuscate("temp", args[0], new ObfuscationSettings(), out string err)) 15 | { 16 | Console.WriteLine("ERR: " + err); 17 | return; 18 | } 19 | 20 | File.Delete("out.lua"); 21 | File.Move("temp/out.lua", "out.lua"); 22 | Directory.Delete("temp", true); 23 | Console.WriteLine("Done!"); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /IronBrew2/Bytecode Library/Bytecode/Deserializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using IronBrew2.Bytecode_Library.IR; 8 | 9 | namespace IronBrew2.Bytecode_Library.Bytecode 10 | { 11 | public class Deserializer 12 | { 13 | private MemoryStream _stream; 14 | 15 | private bool _bigEndian; 16 | private byte _sizeNumber; 17 | private byte _sizeSizeT; 18 | private Encoding _fuckingLua = Encoding.GetEncoding(28591); 19 | 20 | private bool _expectingSetlistData; 21 | 22 | public static Dictionary InstructionMappings = new Dictionary() 23 | { 24 | { Opcode.Move, InstructionType.ABC }, 25 | { Opcode.LoadConst, InstructionType.ABx }, 26 | { Opcode.LoadBool, InstructionType.ABC }, 27 | { Opcode.LoadNil, InstructionType.ABC }, 28 | { Opcode.GetUpval, InstructionType.ABC }, 29 | { Opcode.GetGlobal, InstructionType.ABx }, 30 | { Opcode.GetTable, InstructionType.ABC }, 31 | { Opcode.SetGlobal, InstructionType.ABx }, 32 | { Opcode.SetUpval, InstructionType.ABC }, 33 | { Opcode.SetTable, InstructionType.ABC }, 34 | { Opcode.NewTable, InstructionType.ABC }, 35 | { Opcode.Self, InstructionType.ABC }, 36 | { Opcode.Add, InstructionType.ABC }, 37 | { Opcode.Sub, InstructionType.ABC }, 38 | { Opcode.Mul, InstructionType.ABC }, 39 | { Opcode.Div, InstructionType.ABC }, 40 | { Opcode.Mod, InstructionType.ABC }, 41 | { Opcode.Pow, InstructionType.ABC }, 42 | { Opcode.Unm, InstructionType.ABC }, 43 | { Opcode.Not, InstructionType.ABC }, 44 | { Opcode.Len, InstructionType.ABC }, 45 | { Opcode.Concat, InstructionType.ABC }, 46 | { Opcode.Jmp, InstructionType.AsBx }, 47 | { Opcode.Eq, InstructionType.ABC }, 48 | { Opcode.Lt, InstructionType.ABC }, 49 | { Opcode.Le, InstructionType.ABC }, 50 | { Opcode.Test, InstructionType.ABC }, 51 | { Opcode.TestSet, InstructionType.ABC }, 52 | { Opcode.Call, InstructionType.ABC }, 53 | { Opcode.TailCall, InstructionType.ABC }, 54 | { Opcode.Return, InstructionType.ABC }, 55 | { Opcode.ForLoop, InstructionType.AsBx }, 56 | { Opcode.ForPrep, InstructionType.AsBx }, 57 | { Opcode.TForLoop, InstructionType.ABC }, 58 | { Opcode.SetList, InstructionType.ABC }, 59 | { Opcode.Close, InstructionType.ABC }, 60 | { Opcode.Closure, InstructionType.ABx }, 61 | { Opcode.VarArg, InstructionType.ABC } 62 | }; 63 | 64 | public Deserializer(byte[] input) => 65 | _stream = new MemoryStream(input); 66 | 67 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 68 | public byte[] Read(int size, bool factorEndianness = true) 69 | { 70 | byte[] bytes = new byte[size]; 71 | _stream.Read(bytes, 0, size); 72 | 73 | if (factorEndianness && (_bigEndian == BitConverter.IsLittleEndian)) //if factor in endianness AND endianness differs between the two versions 74 | bytes = bytes.Reverse().ToArray(); 75 | 76 | return bytes; 77 | } 78 | 79 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 80 | public long ReadSizeT() => 81 | _sizeSizeT == 4 ? ReadInt32() : ReadInt64(); 82 | 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | public long ReadInt64() => 85 | BitConverter.ToInt64(Read(8), 0); 86 | 87 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 88 | public int ReadInt32(bool factorEndianness = true) => 89 | BitConverter.ToInt32(Read(4, factorEndianness), 0); 90 | 91 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 92 | public byte ReadByte() => 93 | Read(1)[0]; 94 | 95 | public string ReadString() 96 | { 97 | long c = ReadSizeT(); 98 | int count = (int) c; 99 | 100 | if (count == 0) 101 | return ""; 102 | 103 | byte[] val = Read(count, false); 104 | return _fuckingLua.GetString(val, 0, count - 1); 105 | } 106 | 107 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 108 | public double ReadDouble() => 109 | BitConverter.ToDouble(Read(_sizeNumber), 0); 110 | 111 | public Instruction DecodeInstruction(Chunk chunk, int index) 112 | { 113 | int code = ReadInt32(); 114 | Instruction i = new Instruction(chunk, (Opcode) (code & 0x3F)); 115 | 116 | i.Data = code; 117 | 118 | if (_expectingSetlistData) 119 | { 120 | _expectingSetlistData = false; 121 | 122 | i.InstructionType = InstructionType.Data; 123 | return i; 124 | } 125 | 126 | i.A = (code >> 6) & 0xFF; 127 | 128 | switch (i.InstructionType) 129 | { 130 | //WHAT THE FUCK LUA 131 | case InstructionType.ABC: 132 | i.B = (code >> 6 + 8 + 9) & 0x1FF; 133 | i.C = (code >> 6 + 8) & 0x1FF; 134 | break; 135 | 136 | case InstructionType.ABx: 137 | i.B = (code >> 6 + 8) & 0x3FFFF; 138 | i.C = -1; 139 | break; 140 | 141 | case InstructionType.AsBx: 142 | i.B = ((code >> 6 + 8) & 0x3FFFF) - 131071; 143 | i.C = -1; 144 | break; 145 | } 146 | 147 | if (i.OpCode == Opcode.SetList && i.C == 0) 148 | _expectingSetlistData = true; 149 | 150 | return i; 151 | } 152 | 153 | public List DecodeInstructions(Chunk chunk) 154 | { 155 | List instructions = new List(); 156 | 157 | int Count = ReadInt32(); 158 | 159 | for (int i = 0; i < Count; i++) 160 | instructions.Add(DecodeInstruction(chunk, i)); 161 | 162 | return instructions; 163 | } 164 | 165 | public Constant DecodeConstant() 166 | { 167 | Constant c = new Constant(); 168 | byte Type = ReadByte(); 169 | //ALSO WHAT THE FUCK LUA 170 | switch (Type) 171 | { 172 | case 0: 173 | c.Type = ConstantType.Nil; 174 | c.Data = null; 175 | break; 176 | 177 | case 1: 178 | c.Type = ConstantType.Boolean; 179 | c.Data = ReadByte() != 0; 180 | break; 181 | 182 | case 3: 183 | c.Type = ConstantType.Number; 184 | c.Data = ReadDouble(); 185 | break; 186 | 187 | case 4: 188 | c.Type = ConstantType.String; 189 | c.Data = ReadString(); 190 | break; 191 | } 192 | 193 | return c; 194 | } 195 | 196 | public List DecodeConstants() 197 | { 198 | List constants = new List(); 199 | 200 | int Count = ReadInt32(); 201 | 202 | for (int i = 0; i < Count; i++) 203 | constants.Add(DecodeConstant()); 204 | 205 | return constants; 206 | } 207 | 208 | public Chunk DecodeChunk() 209 | { 210 | Chunk c = new Chunk 211 | { 212 | Name = ReadString(), 213 | Line = ReadInt32(), 214 | LastLine = ReadInt32(), 215 | UpvalueCount = ReadByte(), 216 | ParameterCount = ReadByte(), 217 | VarargFlag = ReadByte(), 218 | StackSize = ReadByte(), 219 | Upvalues = new List() 220 | }; 221 | 222 | c.Instructions = DecodeInstructions(c); 223 | c.Constants = DecodeConstants(); 224 | c.Functions = DecodeChunks(); 225 | 226 | c.UpdateMappings(); 227 | 228 | foreach (var inst in c.Instructions) 229 | inst.SetupRefs(); 230 | 231 | int count = ReadInt32(); 232 | for (int i = 0; i < count; i++) // source line pos list 233 | c.Instructions[i].Line = ReadInt32(); 234 | 235 | //skip other debug info cus fuckit.wav 236 | 237 | count = ReadInt32(); 238 | for (int i = 0; i < count; i++) // local list 239 | { 240 | ReadString(); 241 | ReadInt32(); 242 | ReadInt32(); 243 | } 244 | count = ReadInt32(); 245 | for (int i = 0; i < count; i++) // upvalues 246 | c.Upvalues.Add(ReadString()); 247 | 248 | return c; 249 | } 250 | 251 | public List DecodeChunks() 252 | { 253 | List Chunks = new List(); 254 | 255 | int count = ReadInt32(); 256 | 257 | for (int i = 0; i < count; i++) 258 | Chunks.Add(DecodeChunk()); 259 | 260 | return Chunks; 261 | } 262 | 263 | public Chunk DecodeFile() 264 | { 265 | int header = ReadInt32(); 266 | 267 | if (header != 0x1B4C7561 && header != 0x61754C1B) 268 | throw new Exception("Invalid luac file."); 269 | 270 | if (ReadByte() != 0x51) 271 | throw new Exception("Only Lua 5.1 is supported."); 272 | 273 | ReadByte(); //format official shit wtf 274 | 275 | _bigEndian = ReadByte() == 0; 276 | 277 | ReadByte(); //size of int (assume 4 fuck off) 278 | 279 | _sizeSizeT = ReadByte(); 280 | 281 | ReadByte(); //size of instruction (fuck it not supporting anything else than default) 282 | 283 | _sizeNumber = ReadByte(); 284 | 285 | ReadByte(); //not supporting integer number bullshit fuck off 286 | 287 | Chunk c = DecodeChunk(); 288 | return c; 289 | } 290 | } 291 | } -------------------------------------------------------------------------------- /IronBrew2/Bytecode Library/Bytecode/Opcode.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Bytecode_Library.Bytecode 2 | { 3 | public enum Opcode 4 | { 5 | Move, 6 | LoadConst, 7 | LoadBool, 8 | LoadNil, 9 | GetUpval, 10 | GetGlobal, 11 | GetTable, 12 | SetGlobal, 13 | SetUpval, 14 | SetTable, 15 | NewTable, 16 | Self, 17 | Add, 18 | Sub, 19 | Mul, 20 | Div, 21 | Mod, 22 | Pow, 23 | Unm, 24 | Not, 25 | Len, 26 | Concat, 27 | Jmp, 28 | Eq, 29 | Lt, 30 | Le, 31 | Test, 32 | TestSet, 33 | Call, 34 | TailCall, 35 | Return, 36 | ForLoop, 37 | ForPrep, 38 | TForLoop, 39 | SetList, 40 | Close, 41 | Closure, 42 | VarArg, 43 | 44 | //Custom VM opcodes 45 | SetTop, 46 | PushStack, 47 | NewStack, 48 | SetFenv 49 | } 50 | } -------------------------------------------------------------------------------- /IronBrew2/Bytecode Library/Bytecode/Serializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using IronBrew2.Bytecode_Library.IR; 6 | using IronBrew2.Obfuscator; 7 | 8 | namespace IronBrew2.Bytecode_Library.Bytecode 9 | { 10 | public class Serializer 11 | { 12 | private ObfuscationContext _context; 13 | private ObfuscationSettings _settings; 14 | private Random _r = new Random(); 15 | private Encoding _fuckingLua = Encoding.GetEncoding(28591); 16 | 17 | public Serializer(ObfuscationContext context, ObfuscationSettings settings) 18 | { 19 | _context = context; 20 | _settings = settings; 21 | } 22 | 23 | public byte[] SerializeLChunk(Chunk chunk, bool factorXor = true) 24 | { 25 | List bytes = new List(); 26 | 27 | void WriteByte(byte b) 28 | { 29 | if (factorXor) 30 | b ^= (byte) (_context.PrimaryXorKey); 31 | 32 | bytes.Add(b); 33 | } 34 | 35 | void Write(byte[] b, bool checkEndian = true) 36 | { 37 | if (!BitConverter.IsLittleEndian && checkEndian) 38 | b = b.Reverse().ToArray(); 39 | 40 | bytes.AddRange(b.Select(i => 41 | { 42 | if (factorXor) 43 | i ^= (byte) (_context.PrimaryXorKey); 44 | 45 | return i; 46 | })); 47 | } 48 | 49 | void WriteInt32(int i) => 50 | Write(BitConverter.GetBytes(i)); 51 | 52 | void WriteNumber(double d) => 53 | Write(BitConverter.GetBytes(d)); 54 | 55 | void WriteString(string s) 56 | { 57 | byte[] sBytes = _fuckingLua.GetBytes(s); 58 | 59 | WriteInt32(sBytes.Length); 60 | Write(sBytes, false); 61 | } 62 | 63 | void WriteBool(bool b) => 64 | Write(BitConverter.GetBytes(b)); 65 | 66 | int[] SerializeInstruction(Instruction inst) 67 | { 68 | inst.UpdateRegisters(); 69 | 70 | if (inst.InstructionType == InstructionType.Data) 71 | { 72 | return new[] 73 | { 74 | _r.Next(), 75 | inst.Data 76 | }; 77 | } 78 | 79 | var cData = inst.CustomData; 80 | int opCode = (int)inst.OpCode; 81 | 82 | if (cData != null) 83 | { 84 | var virtualOpcode = cData.Opcode; 85 | 86 | opCode = cData.WrittenOpcode?.VIndex ?? virtualOpcode.VIndex; 87 | virtualOpcode?.Mutate(inst); 88 | } 89 | 90 | int a = inst.A; 91 | int b = inst.B; 92 | int c = inst.C; 93 | 94 | int result_i1 = 0; 95 | int result_i2 = 0; 96 | 97 | if (inst.InstructionType == InstructionType.AsBx || inst.InstructionType == InstructionType.AsBxC) 98 | b += 1048575; 99 | 100 | result_i1 |= (byte) inst.InstructionType; 101 | result_i1 |= ((a & 0x1FF) << 2); 102 | result_i1 |= ((b & 0x1FF) << (2 + 9)); 103 | result_i1 |= (c << (2 + 9 + 9)); 104 | 105 | result_i2 |= opCode; 106 | result_i2 |= (b << 11); 107 | 108 | return new[] { result_i1, result_i2 }; 109 | } 110 | 111 | chunk.UpdateMappings(); 112 | 113 | for (int i = 0; i < (int) ChunkStep.StepCount; i++) 114 | { 115 | switch (_context.ChunkSteps[i]) 116 | { 117 | case ChunkStep.ParameterCount: 118 | WriteByte(chunk.ParameterCount); 119 | break; 120 | case ChunkStep.Constants: 121 | WriteInt32(chunk.Constants.Count); 122 | foreach (Constant c in chunk.Constants) 123 | { 124 | WriteByte((byte)_context.ConstantMapping[(int)c.Type]); 125 | switch (c.Type) 126 | { 127 | case ConstantType.Boolean: 128 | WriteBool(c.Data); 129 | break; 130 | case ConstantType.Number: 131 | WriteNumber(c.Data); 132 | break; 133 | case ConstantType.String: 134 | WriteString(c.Data); 135 | break; 136 | } 137 | } 138 | break; 139 | case ChunkStep.Instructions: 140 | WriteInt32(chunk.Instructions.Count); 141 | 142 | foreach (Instruction ins in chunk.Instructions) 143 | { 144 | int[] arr = SerializeInstruction(ins); 145 | 146 | //WriteByte((byte)ins.Instruction.InstructionType); 147 | WriteInt32(arr[0] ^ _context.IXorKey1); 148 | WriteInt32(arr[1] ^ _context.IXorKey2); 149 | } 150 | break; 151 | case ChunkStep.Functions: 152 | WriteInt32(chunk.Functions.Count); 153 | foreach (Chunk c in chunk.Functions) 154 | Write(SerializeLChunk(c, false)); 155 | 156 | break; 157 | case ChunkStep.LineInfo when _settings.PreserveLineInfo: 158 | WriteInt32(chunk.Instructions.Count); 159 | foreach (var instr in chunk.Instructions) 160 | WriteInt32(instr.Line); 161 | break; 162 | } 163 | } 164 | 165 | return bytes.ToArray(); 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /IronBrew2/Bytecode Library/Bytecode/VanillaSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using IronBrew2.Bytecode_Library.IR; 5 | 6 | namespace IronBrew2.Bytecode_Library.Bytecode 7 | { 8 | public class VanillaSerializer 9 | { 10 | private Chunk _chunk; 11 | private Encoding _fuckingLua = Encoding.GetEncoding(28591); 12 | 13 | public VanillaSerializer(Chunk chunk) => 14 | _chunk = chunk; 15 | 16 | public byte[] Serialize() 17 | { 18 | List res = new List(); 19 | 20 | void WriteByte(byte b) => 21 | res.Add(b); 22 | 23 | void WriteBytes(byte[] bs) => 24 | res.AddRange(bs); 25 | 26 | void WriteInt(int i) => 27 | WriteBytes(BitConverter.GetBytes(i)); 28 | 29 | void WriteUInt(uint i) => 30 | WriteBytes(BitConverter.GetBytes(i)); 31 | 32 | void WriteNum(double d) => 33 | WriteBytes(BitConverter.GetBytes(d)); 34 | 35 | void WriteString(string str) 36 | { 37 | byte[] bytes = _fuckingLua.GetBytes(str); 38 | 39 | WriteInt(bytes.Length + 1); 40 | WriteBytes(bytes); 41 | WriteByte(0); 42 | } 43 | 44 | void WriteChunk(Chunk chunk) 45 | { 46 | if (chunk.Name != "") 47 | WriteString(chunk.Name); 48 | else 49 | WriteInt(0); 50 | 51 | WriteInt(chunk.Line); 52 | WriteInt(chunk.LastLine); 53 | WriteByte(chunk.UpvalueCount); 54 | WriteByte(chunk.ParameterCount); 55 | WriteByte(chunk.VarargFlag); 56 | WriteByte(chunk.StackSize); 57 | 58 | chunk.UpdateMappings(); 59 | 60 | WriteInt(chunk.Instructions.Count); 61 | foreach (var i in chunk.Instructions) 62 | { 63 | i.UpdateRegisters(); 64 | 65 | ref int a = ref i.A; 66 | ref int b = ref i.B; 67 | ref int c = ref i.C; 68 | 69 | uint result = 0; 70 | 71 | result |= (uint) i.OpCode; 72 | result |= ((uint)a << 6); 73 | 74 | switch (i.InstructionType) 75 | { 76 | case InstructionType.ABx: 77 | result |= ((uint)b << (6 + 8)); 78 | break; 79 | 80 | case InstructionType.AsBx: 81 | b += 131071; 82 | result |= ((uint)b << (6 + 8)); 83 | break; 84 | 85 | case InstructionType.ABC: 86 | result |= ((uint)c << (6 + 8)); 87 | result |= ((uint)b << (6 + 8 + 9)); 88 | break; 89 | } 90 | 91 | WriteUInt(result); 92 | } 93 | 94 | WriteInt(chunk.Constants.Count); 95 | foreach (var constant in chunk.Constants) 96 | { 97 | switch (constant.Type) 98 | { 99 | case ConstantType.Nil: 100 | WriteByte(0); 101 | break; 102 | 103 | case ConstantType.Boolean: 104 | WriteByte(1); 105 | WriteByte((byte) ((bool) constant.Data ? 1 : 0)); 106 | break; 107 | 108 | case ConstantType.Number: 109 | WriteByte(3); 110 | WriteNum(constant.Data); 111 | break; 112 | 113 | case ConstantType.String: 114 | WriteByte(4); 115 | WriteString(constant.Data); 116 | break; 117 | } 118 | } 119 | 120 | WriteInt(chunk.Functions.Count); 121 | foreach (var sChunk in chunk.Functions) 122 | WriteChunk(sChunk); 123 | 124 | WriteInt(0); 125 | WriteInt(0); 126 | WriteInt(0); 127 | 128 | //WriteInt(chunk.Upvalues.Count); 129 | //foreach (var str in chunk.Upvalues) 130 | // WriteString(str); 131 | } 132 | 133 | WriteByte(27); 134 | WriteBytes(_fuckingLua.GetBytes("Lua")); 135 | WriteByte(0x51); 136 | WriteByte(0); 137 | WriteByte(1); 138 | WriteByte(4); 139 | WriteByte(4); 140 | WriteByte(4); 141 | WriteByte(8); 142 | WriteByte(0); 143 | 144 | WriteChunk(_chunk); 145 | 146 | return res.ToArray(); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /IronBrew2/Bytecode Library/IR/Chunk.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using IronBrew2.Bytecode_Library.Bytecode; 3 | 4 | namespace IronBrew2.Bytecode_Library.IR 5 | { 6 | public class Chunk 7 | { 8 | public string Name; 9 | public int Line; 10 | public int LastLine; 11 | public byte UpvalueCount; 12 | public byte ParameterCount; 13 | public byte VarargFlag; 14 | public byte StackSize; 15 | public int CurrentOffset = 0; 16 | public int CurrentParamOffset = 0; 17 | public List Instructions; 18 | public Dictionary InstructionMap = new Dictionary(); 19 | public List Constants; 20 | public Dictionary ConstantMap = new Dictionary(); 21 | public List Functions; 22 | public Dictionary FunctionMap = new Dictionary(); 23 | public List Upvalues; 24 | 25 | public void UpdateMappings() 26 | { 27 | InstructionMap.Clear(); 28 | ConstantMap.Clear(); 29 | FunctionMap.Clear(); 30 | 31 | for (int i = 0; i < Instructions.Count; i++) 32 | InstructionMap.Add(Instructions[i], i); 33 | 34 | for (int i = 0; i < Constants.Count; i++) 35 | ConstantMap.Add(Constants[i], i); 36 | 37 | for (int i = 0; i < Functions.Count; i++) 38 | FunctionMap.Add(Functions[i], i); 39 | } 40 | 41 | public int Rebase(int offset, int paramOffset = 0) 42 | { 43 | offset -= CurrentOffset; 44 | paramOffset -= CurrentParamOffset; 45 | 46 | CurrentOffset += offset; 47 | CurrentParamOffset += paramOffset; 48 | 49 | StackSize = (byte) (StackSize + offset); 50 | 51 | //thanks lua for not distinguishing parameters and regular stack values! 52 | var Params = ParameterCount - 1; 53 | for (var i = 0; i < Instructions.Count; i++) 54 | { 55 | var instr = Instructions[i]; 56 | 57 | switch (instr.OpCode) 58 | { 59 | case Opcode.Move: 60 | case Opcode.LoadNil: 61 | case Opcode.Unm: 62 | case Opcode.Not: 63 | case Opcode.Len: 64 | case Opcode.TestSet: 65 | { 66 | if (instr.A > Params) 67 | instr.A += offset; 68 | else 69 | instr.A += paramOffset; 70 | 71 | if (instr.B > Params) 72 | instr.B += offset; 73 | else 74 | instr.B += paramOffset; 75 | break; 76 | } 77 | case Opcode.LoadConst: 78 | case Opcode.LoadBool: 79 | case Opcode.GetGlobal: 80 | case Opcode.SetGlobal: 81 | case Opcode.GetUpval: 82 | case Opcode.SetUpval: 83 | case Opcode.Call: 84 | case Opcode.TailCall: 85 | case Opcode.Return: 86 | case Opcode.VarArg: 87 | case Opcode.Test: 88 | case Opcode.ForPrep: 89 | case Opcode.ForLoop: 90 | case Opcode.TForLoop: 91 | case Opcode.NewTable: 92 | case Opcode.SetList: 93 | case Opcode.Close: 94 | { 95 | if (instr.A > Params) 96 | instr.A += offset; 97 | else 98 | instr.A += paramOffset; 99 | break; 100 | } 101 | case Opcode.GetTable: 102 | case Opcode.SetTable: 103 | { 104 | if (instr.A > Params) 105 | instr.A += offset; 106 | else 107 | instr.A += paramOffset; 108 | 109 | if (instr.B < 255) 110 | { 111 | if (instr.B > Params) 112 | instr.B += offset; 113 | else 114 | instr.B += paramOffset; 115 | } 116 | 117 | if (instr.C > Params) 118 | instr.C += offset; 119 | else 120 | instr.C += paramOffset; 121 | 122 | break; 123 | } 124 | case Opcode.Add: 125 | case Opcode.Sub: 126 | case Opcode.Mul: 127 | case Opcode.Div: 128 | case Opcode.Mod: 129 | case Opcode.Pow: 130 | { 131 | if (instr.A > Params) 132 | instr.A += offset; 133 | else 134 | instr.A += paramOffset; 135 | 136 | if (instr.B < 255) 137 | { 138 | if (instr.B > Params) 139 | instr.B += offset; 140 | else 141 | instr.B += paramOffset; 142 | } 143 | 144 | if (instr.C < 255) 145 | { 146 | if (instr.C > Params) 147 | instr.C += offset; 148 | else 149 | instr.C += paramOffset; 150 | } 151 | 152 | break; 153 | } 154 | case Opcode.Concat: 155 | { 156 | if (instr.A > Params) 157 | instr.A += offset; 158 | else 159 | instr.A += paramOffset; 160 | 161 | if (instr.B > Params) 162 | instr.B += offset; 163 | else 164 | instr.B += paramOffset; 165 | 166 | if (instr.C > Params) 167 | instr.C += offset; 168 | else 169 | instr.C += paramOffset; 170 | 171 | break; 172 | } 173 | case Opcode.Self: 174 | { 175 | if (instr.A > Params) 176 | instr.A += offset; 177 | else 178 | instr.A += paramOffset; 179 | 180 | if (instr.B > Params) 181 | instr.B += offset; 182 | else 183 | instr.B += paramOffset; 184 | 185 | if (instr.C < 255) 186 | { 187 | if (instr.C > Params) 188 | instr.C += offset; 189 | else 190 | instr.C += paramOffset; 191 | } 192 | 193 | break; 194 | } 195 | case Opcode.Eq: 196 | case Opcode.Lt: 197 | case Opcode.Le: 198 | { 199 | if (instr.B < 255) 200 | { 201 | if (instr.B > Params) 202 | instr.B += offset; 203 | else 204 | instr.B += paramOffset; 205 | } 206 | 207 | if (instr.C < 255) 208 | { 209 | if (instr.C > Params) 210 | instr.C += offset; 211 | else 212 | instr.C += paramOffset; 213 | } 214 | 215 | break; 216 | } 217 | case Opcode.Closure: 218 | { 219 | if (instr.A > Params) 220 | instr.A += offset; 221 | else 222 | instr.A += paramOffset; 223 | 224 | var nProto = Functions[instr.B]; 225 | 226 | //fuck you lua 227 | for (var i2 = 0; i2 < nProto.UpvalueCount; i2++) 228 | { 229 | var cInst = Instructions[i + i2 + 1]; 230 | 231 | if (cInst.OpCode != Opcode.Move) 232 | continue; 233 | 234 | if (cInst.B > Params) 235 | cInst.B += offset; 236 | else 237 | cInst.B += paramOffset; 238 | } 239 | 240 | i += nProto.UpvalueCount; 241 | break; 242 | } 243 | } 244 | } 245 | 246 | return ParameterCount; 247 | } 248 | } 249 | } -------------------------------------------------------------------------------- /IronBrew2/Bytecode Library/IR/Constant.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace IronBrew2.Bytecode_Library.IR 5 | { 6 | public class Constant 7 | { 8 | public List BackReferences = new List(); 9 | 10 | public ConstantType Type; 11 | public dynamic Data; 12 | 13 | public Constant() { } 14 | 15 | public Constant(Constant other) 16 | { 17 | Type = other.Type; 18 | Data = other.Data; 19 | BackReferences = other.BackReferences.ToList(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /IronBrew2/Bytecode Library/IR/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Bytecode_Library.IR 2 | { 3 | public enum ConstantType 4 | { 5 | Nil, 6 | Boolean, 7 | Number, 8 | String 9 | } 10 | 11 | public enum InstructionType 12 | { 13 | ABC, 14 | ABx, 15 | AsBx, 16 | AsBxC, 17 | sAxBC, 18 | Data 19 | } 20 | } -------------------------------------------------------------------------------- /IronBrew2/Bytecode Library/IR/Instruction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using IronBrew2.Bytecode_Library.Bytecode; 5 | using IronBrew2.Obfuscator; 6 | 7 | namespace IronBrew2.Bytecode_Library.IR 8 | { 9 | public class Instruction 10 | { 11 | public object[] RefOperands = {null, null, null}; 12 | public List BackReferences = new List(); 13 | 14 | public Chunk Chunk; 15 | public Opcode OpCode; 16 | public InstructionType InstructionType; 17 | 18 | public int A; 19 | public int B; 20 | public int C; 21 | 22 | public int Data; 23 | public int PC; 24 | public int Line; 25 | 26 | public CustomInstructionData CustomData; 27 | 28 | public Instruction(Instruction other) 29 | { 30 | RefOperands = other.RefOperands.ToArray(); 31 | BackReferences = other.BackReferences.ToList(); 32 | Chunk = other.Chunk; 33 | OpCode = other.OpCode; 34 | InstructionType = other.InstructionType; 35 | A = other.A; 36 | B = other.B; 37 | C = other.C; 38 | Data = other.Data; 39 | PC = other.PC; 40 | Line = other.Line; 41 | } 42 | 43 | public Instruction(Chunk chunk, Opcode code, params object[] refOperands) 44 | { 45 | A = 0; 46 | B = 0; 47 | C = 0; 48 | Data = 0; 49 | 50 | Chunk = chunk; 51 | OpCode = code; 52 | 53 | if (Deserializer.InstructionMappings.TryGetValue(code, out InstructionType type)) 54 | InstructionType = type; 55 | else 56 | InstructionType = InstructionType.ABC; 57 | 58 | for (int i = 0; i < refOperands.Length; i++) 59 | { 60 | var op = refOperands[i]; 61 | RefOperands[i] = op; 62 | 63 | if (op is Instruction ins) 64 | ins.BackReferences.Add(this); 65 | } 66 | } 67 | 68 | public void UpdateRegisters() 69 | { 70 | if (InstructionType == InstructionType.Data) 71 | return; 72 | 73 | PC = Chunk.InstructionMap[this]; 74 | switch (OpCode) 75 | { 76 | case Opcode.LoadConst: 77 | case Opcode.GetGlobal: 78 | case Opcode.SetGlobal: 79 | B = Chunk.ConstantMap[(Constant)RefOperands[0]]; 80 | break; 81 | case Opcode.Jmp: 82 | case Opcode.ForLoop: 83 | case Opcode.ForPrep: 84 | B = Chunk.InstructionMap[(Instruction)RefOperands[0]] - PC - 1; 85 | break; 86 | case Opcode.Closure: 87 | B = Chunk.FunctionMap[(Chunk)RefOperands[0]]; 88 | break; 89 | case Opcode.GetTable: 90 | case Opcode.SetTable: 91 | case Opcode.Add: 92 | case Opcode.Sub: 93 | case Opcode.Mul: 94 | case Opcode.Div: 95 | case Opcode.Mod: 96 | case Opcode.Pow: 97 | case Opcode.Eq: 98 | case Opcode.Lt: 99 | case Opcode.Le: 100 | case Opcode.Self: 101 | if (RefOperands[0] is Constant cB) 102 | B = Chunk.ConstantMap[cB] + 256; 103 | 104 | if (RefOperands[1] is Constant cC) 105 | C = Chunk.ConstantMap[cC] + 256; 106 | break; 107 | } 108 | } 109 | 110 | public void SetupRefs() 111 | { 112 | RefOperands = new object[] {null, null, null}; 113 | switch (OpCode) 114 | { 115 | case Opcode.LoadConst: 116 | case Opcode.GetGlobal: 117 | case Opcode.SetGlobal: 118 | RefOperands[0] = Chunk.Constants[B]; 119 | ((Constant)RefOperands[0]).BackReferences.Add(this); 120 | break; 121 | case Opcode.Jmp: 122 | case Opcode.ForLoop: 123 | case Opcode.ForPrep: 124 | RefOperands[0] = Chunk.Instructions[Chunk.InstructionMap[this] + B + 1]; 125 | ((Instruction) RefOperands[0]).BackReferences.Add(this); 126 | break; 127 | case Opcode.Closure: 128 | RefOperands[0] = Chunk.Functions[B]; 129 | break; 130 | case Opcode.GetTable: 131 | case Opcode.SetTable: 132 | case Opcode.Add: 133 | case Opcode.Sub: 134 | case Opcode.Mul: 135 | case Opcode.Div: 136 | case Opcode.Mod: 137 | case Opcode.Pow: 138 | case Opcode.Eq: 139 | case Opcode.Lt: 140 | case Opcode.Le: 141 | case Opcode.Self: 142 | if (B > 255) 143 | RefOperands[0] = Chunk.Constants[B - 256]; 144 | 145 | if (C > 255) 146 | RefOperands[1] = Chunk.Constants[C - 256]; 147 | break; 148 | } 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /IronBrew2/Extensions/IEnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace IronBrew2.Extensions 5 | { 6 | public static class IEnumerableExtensions 7 | { 8 | private static Random _rnd = new Random(); 9 | 10 | public static void Shuffle(this IList list) 11 | { 12 | for(var i=0; i < list.Count; i++) 13 | list.Swap(i, _rnd.Next(i, list.Count)); 14 | } 15 | 16 | public static void Swap(this IList list, int i, int j) 17 | { 18 | var temp = list[i]; 19 | list[i] = list[j]; 20 | list[j] = temp; 21 | } 22 | 23 | public static T Random(this IList list) => 24 | list[_rnd.Next(0, list.Count)]; 25 | } 26 | } -------------------------------------------------------------------------------- /IronBrew2/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace IronBrew2.Extensions 4 | { 5 | public static class StringExtensions { 6 | /// 7 | /// takes a substring between two anchor strings (or the end of the string if that anchor is null) 8 | /// 9 | /// a string 10 | /// an optional string to search after 11 | /// an optional string to search before 12 | /// an optional comparison for the search 13 | /// a substring based on the search 14 | public static string Substring(this string @this, string from = null, string until = null, StringComparison comparison = StringComparison.InvariantCulture) 15 | { 16 | var fromLength = (from ?? string.Empty).Length; 17 | var startIndex = !string.IsNullOrEmpty(from) 18 | ? @this.IndexOf(from, comparison) + fromLength 19 | : 0; 20 | 21 | if (startIndex < fromLength) 22 | return null; 23 | 24 | var endIndex = !string.IsNullOrEmpty(until) 25 | ? @this.IndexOf(until, startIndex, comparison) 26 | : @this.Length; 27 | 28 | if (endIndex < 0) 29 | return null; 30 | 31 | var subString = @this.Substring(startIndex, endIndex - startIndex); 32 | return subString; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /IronBrew2/IronBrew2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.2 5 | latest 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/Blocks/Block.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using IronBrew2.Bytecode_Library.IR; 4 | 5 | namespace IronBrew2.Obfuscator.Control_Flow.Blocks 6 | { 7 | public class Block 8 | { 9 | public Chunk Chunk; 10 | public List Body = new List(); 11 | public Block Successor = null; 12 | 13 | public Block(Chunk c) => 14 | Chunk = c; 15 | } 16 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/CFContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection.Emit; 6 | using IronBrew2.Bytecode_Library.Bytecode; 7 | using IronBrew2.Bytecode_Library.IR; 8 | using IronBrew2.Obfuscator.Control_Flow.Types; 9 | 10 | namespace IronBrew2.Obfuscator.Control_Flow 11 | { 12 | public class CFContext 13 | { 14 | public Chunk lChunk; 15 | 16 | public void DoChunk(Chunk c) 17 | { 18 | bool chunkHasCflow = false; 19 | 20 | Instruction CBegin = null; 21 | 22 | var Instructs = c.Instructions.ToList(); 23 | for (var index = 0; index < Instructs.Count - 1; index++) 24 | { 25 | Instruction instr = Instructs[index]; 26 | if (instr.OpCode == Opcode.GetGlobal && Instructs[index + 1].OpCode == Opcode.Call) 27 | { 28 | string str = ((Constant) instr.RefOperands[0]).Data.ToString(); 29 | 30 | bool do_ = false; 31 | 32 | switch (str) 33 | { 34 | case "IB_MAX_CFLOW_START": 35 | { 36 | CBegin = instr; 37 | do_ = true; 38 | chunkHasCflow = true; 39 | break; 40 | } 41 | case "IB_MAX_CFLOW_END": 42 | { 43 | do_ = true; 44 | 45 | int cBegin = c.InstructionMap[CBegin]; 46 | int cEnd = c.InstructionMap[instr]; 47 | 48 | List nIns = c.Instructions.Skip(cBegin).Take(cEnd - cBegin).ToList(); 49 | 50 | cBegin = c.InstructionMap[CBegin]; 51 | cEnd = c.InstructionMap[instr]; 52 | nIns = c.Instructions.Skip(cBegin).Take(cEnd - cBegin).ToList(); 53 | 54 | Console.WriteLine("Test Spam"); 55 | TestSpam.DoInstructions(c, nIns); 56 | 57 | cBegin = c.InstructionMap[CBegin]; 58 | cEnd = c.InstructionMap[instr]; 59 | nIns = c.Instructions.Skip(cBegin).Take(cEnd - cBegin).ToList(); 60 | 61 | //BranchIntegrity.DoInstructions(c, nIns); 62 | 63 | //cBegin = c.InstructionMap[CBegin]; 64 | //cEnd = c.InstructionMap[instr]; 65 | //nIns = c.Instructions.Skip(cBegin).TakLOe(cEnd - cBegin).ToList(); 66 | 67 | Console.WriteLine("Bounce"); 68 | Bounce.DoInstructions(c, nIns); 69 | 70 | cBegin = c.InstructionMap[CBegin]; 71 | cEnd = c.InstructionMap[instr]; 72 | nIns = c.Instructions.Skip(cBegin).Take(cEnd - cBegin).ToList(); 73 | 74 | Console.WriteLine("Test Preserve"); 75 | TestPreserve.DoInstructions(c, nIns); 76 | 77 | Console.WriteLine("EQ Mutate"); 78 | EQMutate.DoInstructions(c, c.Instructions.ToList()); 79 | 80 | break; 81 | } 82 | } 83 | 84 | if (do_) 85 | { 86 | instr.OpCode = Opcode.Move; 87 | instr.A = 0; 88 | instr.B = 0; 89 | 90 | Instruction call = Instructs[index + 1]; 91 | call.OpCode = Opcode.Move; 92 | call.A = 0; 93 | call.B = 0; 94 | } 95 | } 96 | } 97 | 98 | TestFlip.DoInstructions(c, c.Instructions.ToList()); 99 | 100 | if (chunkHasCflow) 101 | c.Instructions.Insert(0, new Instruction(c, Opcode.NewStack)); 102 | 103 | foreach (Chunk _c in c.Functions) 104 | DoChunk(_c); 105 | } 106 | 107 | public void DoChunks() 108 | { 109 | new Inlining(lChunk).DoChunks(); 110 | DoChunk(lChunk); 111 | //File.WriteAllBytes("ok.luac", new VanillaSerializer(lChunk).Serialize()); 112 | } 113 | 114 | public CFContext(Chunk lChunk_) => 115 | lChunk = lChunk_; 116 | } 117 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/CFGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using IronBrew2.Bytecode_Library.Bytecode; 4 | using IronBrew2.Bytecode_Library.IR; 5 | 6 | namespace IronBrew2.Obfuscator.Control_Flow 7 | { 8 | public class CFGenerator 9 | { 10 | public Random Random = new Random(); 11 | 12 | public Instruction NextJMP(Chunk lc, Instruction Reference) => 13 | new Instruction(lc, Opcode.Jmp, Reference); 14 | 15 | public Instruction BelievableRandom(Chunk lc) 16 | { 17 | Instruction ins = new Instruction(lc, (Opcode)Random.Next(0, 37)); 18 | 19 | ins.A = Random.Next(0, 128); 20 | ins.B = Random.Next(0, 128); 21 | ins.C = Random.Next(0, 128); 22 | 23 | while (true) 24 | { 25 | switch (ins.OpCode) 26 | { 27 | case Opcode.LoadConst: 28 | case Opcode.GetGlobal: 29 | case Opcode.SetGlobal: 30 | case Opcode.Jmp: 31 | case Opcode.ForLoop: 32 | case Opcode.TForLoop: 33 | case Opcode.ForPrep: 34 | case Opcode.Closure: 35 | case Opcode.GetTable: 36 | case Opcode.SetTable: 37 | case Opcode.Add: 38 | case Opcode.Sub: 39 | case Opcode.Mul: 40 | case Opcode.Div: 41 | case Opcode.Mod: 42 | case Opcode.Pow: 43 | case Opcode.Test: 44 | case Opcode.TestSet: 45 | case Opcode.Eq: 46 | case Opcode.Lt: 47 | case Opcode.Le: 48 | case Opcode.Self: 49 | ins.OpCode = (Opcode) Random.Next(0, 37); 50 | continue; 51 | 52 | default: 53 | return ins; 54 | } 55 | } 56 | } 57 | 58 | public Constant GetOrAddConstant(Chunk chunk, ConstantType type, dynamic constant, out int constantIndex) 59 | { 60 | var current = 61 | chunk.Constants.FirstOrDefault(c => c.Type == type && 62 | c.Data == constant); // type checking to prevent errors i guess 63 | if (current != null) 64 | { 65 | constantIndex = chunk.Constants.IndexOf(current); 66 | return current; 67 | } 68 | 69 | Constant newConst = new Constant 70 | { 71 | Type = type, 72 | Data = constant 73 | }; 74 | 75 | 76 | constantIndex = chunk.Constants.Count; 77 | 78 | chunk.Constants.Add(newConst); 79 | chunk.ConstantMap.Add(newConst, constantIndex); 80 | 81 | return newConst; 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/Types/Bounce.cs: -------------------------------------------------------------------------------- 1 | /* 2 | May have broke syntax, couldn't test at school 3 | 4 | > not added to CFContext yet, I want to test it. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Reflection.Emit; 11 | using IronBrew2.Bytecode_Library.Bytecode; 12 | using IronBrew2.Bytecode_Library.IR; 13 | 14 | namespace IronBrew2.Obfuscator.Control_Flow.Types 15 | { 16 | public static class Bounce 17 | { 18 | public static Random Random = new Random(); 19 | public static CFGenerator CFGenerator = new CFGenerator(); 20 | 21 | public static void DoInstructions(Chunk chunk, List Instructions) 22 | { 23 | Instructions = Instructions.ToList(); 24 | foreach (Instruction l in Instructions) 25 | { 26 | if (l.OpCode != Opcode.Jmp) 27 | continue; 28 | 29 | Instruction First = CFGenerator.NextJMP(chunk, (Instruction) l.RefOperands[0]); 30 | chunk.Instructions.Add(First); 31 | l.RefOperands[0] = First; 32 | } 33 | 34 | chunk.UpdateMappings(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/Types/EqMutate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection.Emit; 5 | using IronBrew2.Bytecode_Library.Bytecode; 6 | using IronBrew2.Bytecode_Library.IR; 7 | 8 | namespace IronBrew2.Obfuscator.Control_Flow.Types 9 | { 10 | public static class EQMutate 11 | { 12 | public static Random Random = new Random(); 13 | public static CFGenerator CFGenerator = new CFGenerator(); 14 | 15 | public static void DoInstructions(Chunk chunk, List instructions) 16 | { 17 | chunk.UpdateMappings(); 18 | foreach (Instruction l in instructions) 19 | { 20 | if (l.OpCode != Opcode.Eq) 21 | continue; 22 | 23 | Instruction target = (Instruction) chunk.Instructions[chunk.InstructionMap[l] + 1].RefOperands[0]; 24 | Instruction target2 = chunk.Instructions[chunk.InstructionMap[l] + 2]; 25 | 26 | Instruction newLt = new Instruction(l); 27 | newLt.OpCode = Opcode.Lt; 28 | newLt.A = l.A; 29 | 30 | Instruction newLe = new Instruction(l); 31 | newLe.OpCode = Opcode.Le; 32 | newLe.A = l.A == 0 ? 1 : 0; 33 | 34 | int idx = chunk.InstructionMap[l]; 35 | 36 | Instruction j1 = CFGenerator.NextJMP(chunk, target2); 37 | Instruction j2 = CFGenerator.NextJMP(chunk, target2); 38 | Instruction j3 = CFGenerator.NextJMP(chunk, target); 39 | 40 | chunk.Instructions.InsertRange(idx, new[] {newLt, j1, newLe, j2, j3}); 41 | 42 | chunk.UpdateMappings(); 43 | foreach (Instruction i in chunk.Instructions) 44 | i.UpdateRegisters(); 45 | 46 | Instruction j = chunk.Instructions[chunk.InstructionMap[l] + 1]; 47 | 48 | chunk.Instructions.Remove(l); 49 | chunk.Instructions.Remove(j); 50 | 51 | foreach (Instruction br in l.BackReferences) 52 | br.RefOperands[0] = newLt; 53 | 54 | foreach (Instruction br in j.BackReferences) 55 | br.RefOperands[0] = newLt; 56 | chunk.UpdateMappings(); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/Types/Inlining.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection.Emit; 6 | using IronBrew2.Bytecode_Library.Bytecode; 7 | using IronBrew2.Bytecode_Library.IR; 8 | 9 | namespace IronBrew2.Obfuscator.Control_Flow.Types 10 | { 11 | public class Inlining 12 | { 13 | private Chunk _head; 14 | 15 | public Inlining(Chunk chunk) => 16 | _head = chunk; 17 | 18 | public bool ShouldInline(Chunk target, Chunk inlined, out List calls, out List closures, out bool inlineAll) 19 | { 20 | calls = new List(); 21 | closures = new List(); 22 | inlineAll = false; 23 | 24 | if (inlined.Instructions.Count < 3) 25 | return false; 26 | 27 | if (inlined.Instructions[0].OpCode != Opcode.GetGlobal || inlined.Instructions[1].OpCode != Opcode.LoadBool || inlined.Instructions[2].OpCode != Opcode.Call) 28 | return false; 29 | 30 | if (((Constant) inlined.Instructions[0].RefOperands[0]).Data.ToString() != "IB_INLINING_START") 31 | return false; 32 | 33 | inlineAll = inlined.Instructions[1].B == 1; 34 | 35 | inlined.Instructions[0].OpCode = Opcode.Move; 36 | inlined.Instructions[0].A = 0; 37 | inlined.Instructions[0].B = 0; 38 | 39 | inlined.Instructions[1].OpCode = Opcode.Move; 40 | inlined.Instructions[1].A = 0; 41 | inlined.Instructions[1].B = 0; 42 | 43 | inlined.Instructions[2].OpCode = Opcode.Move; 44 | inlined.Instructions[2].A = 0; 45 | inlined.Instructions[2].B = 0; 46 | 47 | inlined.Constants.Remove((Constant) inlined.Instructions[0].RefOperands[0]); 48 | 49 | if (target.StackSize + inlined.StackSize + 1 > 255) 50 | return false; 51 | 52 | if (inlined.Instructions.Any(i => i.OpCode == Opcode.GetUpval || i.OpCode == Opcode.SetUpval)) 53 | return false; 54 | 55 | bool[] registers = new bool[256]; 56 | bool res = false; 57 | 58 | for (var i = 0; i < target.Instructions.Count; i++) 59 | { 60 | var instr = target.Instructions[i]; 61 | switch (instr.OpCode) 62 | { 63 | case Opcode.Move: 64 | { 65 | registers[instr.A] = registers[instr.B]; 66 | break; 67 | } 68 | case Opcode.LoadNil: 69 | case Opcode.Unm: 70 | case Opcode.Not: 71 | case Opcode.Len: 72 | case Opcode.TestSet: 73 | { 74 | registers[instr.A] = false; 75 | registers[instr.B] = false; 76 | break; 77 | } 78 | case Opcode.LoadConst: 79 | case Opcode.LoadBool: 80 | case Opcode.GetGlobal: 81 | case Opcode.SetGlobal: 82 | case Opcode.Return: 83 | case Opcode.VarArg: 84 | case Opcode.Test: 85 | case Opcode.ForPrep: 86 | case Opcode.ForLoop: 87 | case Opcode.TForLoop: 88 | case Opcode.NewTable: 89 | case Opcode.SetList: 90 | case Opcode.Close: 91 | case Opcode.GetTable: 92 | case Opcode.SetTable: 93 | case Opcode.Add: 94 | case Opcode.Sub: 95 | case Opcode.Mul: 96 | case Opcode.Div: 97 | case Opcode.Mod: 98 | case Opcode.Pow: 99 | case Opcode.Concat: 100 | case Opcode.Self: 101 | { 102 | registers[instr.A] = false; 103 | break; 104 | } 105 | case Opcode.Closure: 106 | if (instr.RefOperands[0] == inlined) 107 | { 108 | closures.Add(instr); 109 | registers[instr.A] = true; 110 | } 111 | 112 | break; 113 | case Opcode.Call: 114 | case Opcode.TailCall: 115 | int limit = instr.A + instr.C - 1; 116 | 117 | if (instr.C == 0) 118 | limit = target.StackSize; 119 | 120 | if (registers[instr.A]) 121 | { 122 | calls.Add(instr); 123 | res = true; 124 | } 125 | 126 | for (int c = instr.A; c <= limit; c++) 127 | registers[c] = false; 128 | 129 | break; 130 | } 131 | } 132 | 133 | return res; 134 | } 135 | 136 | public void DoChunk(Chunk chunk) 137 | { 138 | foreach (Chunk sub in chunk.Functions.ToList()) 139 | { 140 | DoChunk(sub); 141 | if (ShouldInline(chunk, sub, out var locations, out var closures, out bool inlineAll)) 142 | { 143 | if (inlineAll) 144 | chunk.Functions.Remove(sub); 145 | 146 | foreach (var loc in locations) 147 | { 148 | int target = loc.A + loc.B + 1; 149 | if (loc.B == 0) 150 | target = chunk.StackSize + 1; 151 | 152 | sub.Rebase(target, target); 153 | 154 | List modified = new List(); 155 | 156 | int idx = chunk.Instructions.IndexOf(loc); 157 | chunk.Instructions.Remove(loc); 158 | 159 | foreach (var bRef in loc.BackReferences) 160 | bRef.SetupRefs(); 161 | 162 | chunk.UpdateMappings(); 163 | 164 | Instruction next = chunk.Instructions[idx]; 165 | 166 | int lim = sub.ParameterCount - 1; 167 | if (loc.B == 0) 168 | lim = chunk.StackSize - loc.A; 169 | 170 | for (int i = 0; i <= lim; i++) 171 | { 172 | chunk.Instructions.Insert(idx++, new Instruction(chunk, Opcode.Move) 173 | { 174 | A = target + i, 175 | B = loc.A + i + 1 176 | }); 177 | } 178 | 179 | Dictionary map = new Dictionary(); 180 | 181 | bool done = false; 182 | for (var i = 0; i < sub.Instructions.Count; i++) 183 | { 184 | var instr = new Instruction(sub.Instructions[i]); 185 | instr.Chunk = chunk; 186 | 187 | map.Add(sub.Instructions[i], instr); 188 | switch (instr.OpCode) 189 | { 190 | case Opcode.Return: 191 | { 192 | int callLimit = loc.C - 1; 193 | 194 | if (callLimit == -1) 195 | callLimit = instr.B - 2; 196 | 197 | if (callLimit <= -1) 198 | callLimit = sub.StackSize; 199 | 200 | List t = new List(); 201 | 202 | for (int j = 0; j <= callLimit; j++) 203 | t.Add(new Instruction(chunk, Opcode.Move) 204 | { 205 | A = loc.A + j, 206 | B = instr.A + j, 207 | }); 208 | 209 | Instruction setTop = new Instruction(chunk, Opcode.SetTop); 210 | setTop.A = loc.A + callLimit; 211 | 212 | t.Add(setTop); 213 | t.Add(new Instruction(chunk, Opcode.Jmp, next)); 214 | 215 | map[sub.Instructions[i]] = t.First(); 216 | modified.AddRange(t); 217 | done = true; 218 | break; 219 | } 220 | case Opcode.TailCall: 221 | { 222 | int callLimit = loc.C - 1; 223 | 224 | if (callLimit == -1) 225 | callLimit = instr.B - 1; 226 | 227 | if (callLimit == -1) 228 | callLimit = chunk.StackSize - loc.A + 1; 229 | 230 | List t = new List(); 231 | 232 | for (int j = 0; j <= callLimit; j++) 233 | t.Add(new Instruction(chunk, Opcode.Move) 234 | { 235 | A = loc.A + j, 236 | B = instr.A + j, 237 | }); 238 | 239 | instr.OpCode = Opcode.Call; 240 | instr.A = loc.A; 241 | 242 | t.Add(instr); 243 | t.Add(new Instruction(chunk, Opcode.Jmp, next)); 244 | 245 | map[sub.Instructions[i]] = t.First(); 246 | modified.AddRange(t); 247 | done = true; 248 | break; 249 | } 250 | default: 251 | modified.Add(instr); 252 | break; 253 | } 254 | 255 | if (done) 256 | break; 257 | } 258 | 259 | chunk.Instructions.InsertRange(idx, modified); 260 | 261 | foreach (Instruction k in map.Keys) 262 | { 263 | map[k].BackReferences.Clear(); 264 | for (int i = 0; i < k.BackReferences.Count; i++) 265 | map[k].BackReferences.Add(map[k.BackReferences[i]]); 266 | 267 | if (k.RefOperands[0] is Instruction i2) 268 | map[k].RefOperands[0] = map[i2]; 269 | } 270 | } 271 | 272 | chunk.UpdateMappings(); 273 | 274 | foreach (var clos in closures) 275 | { 276 | chunk.Instructions.RemoveRange(chunk.InstructionMap[clos], ((Chunk)clos.RefOperands[0]).UpvalueCount + 1); 277 | foreach (var bRef in clos.BackReferences) 278 | bRef.SetupRefs(); 279 | } 280 | 281 | foreach (Constant c in sub.Constants) 282 | { 283 | var nc = chunk.Constants.FirstOrDefault(c2 => c2.Type == c.Type && c2.Data == c.Data); 284 | if (nc == null) 285 | { 286 | nc = new Constant(c); 287 | chunk.Constants.Add(nc); 288 | } 289 | 290 | foreach (var inst in chunk.Instructions) 291 | { 292 | if (inst.RefOperands[0] is Constant c2 && c == c2) 293 | inst.RefOperands[0] = nc; 294 | 295 | 296 | if (inst.RefOperands[1] is Constant c3 && c == c3) 297 | inst.RefOperands[1] = nc; 298 | } 299 | } 300 | 301 | foreach (Chunk c in sub.Functions) 302 | chunk.Functions.Add(c); 303 | 304 | chunk.UpdateMappings(); 305 | foreach (var _ins in chunk.Instructions) 306 | _ins.UpdateRegisters(); 307 | } 308 | } 309 | } 310 | 311 | public void DoChunks() 312 | { 313 | DoChunk(_head); 314 | //File.WriteAllBytes("asd.luac", new VanillaSerializer(_head).Serialize()); 315 | } 316 | } 317 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/Types/NumberMutate.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.IR; 2 | 3 | namespace IronBrew2.Obfuscator.Control_Flow.Types 4 | { 5 | public static class NumberMutate 6 | { 7 | public static void DoInstructions(Chunk chunk) 8 | { 9 | 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/Types/TestFlip.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using IronBrew2.Bytecode_Library.Bytecode; 5 | using IronBrew2.Bytecode_Library.IR; 6 | using IronBrew2.Extensions; 7 | 8 | namespace IronBrew2.Obfuscator.Control_Flow.Types 9 | { 10 | public static class TestFlip 11 | { 12 | public static void DoInstructions(Chunk chunk, List instructions) 13 | { 14 | instructions = instructions.ToList(); 15 | 16 | CFGenerator generator = new CFGenerator(); 17 | Random r = new Random(); 18 | 19 | for (int idx = instructions.Count - 1; idx >= 0; idx--) 20 | { 21 | Instruction i = instructions[idx]; 22 | switch (i.OpCode) 23 | { 24 | case Opcode.Lt: 25 | case Opcode.Le: 26 | case Opcode.Eq: 27 | { 28 | if (r.Next(2) == 1) 29 | { 30 | i.A = i.A == 0 ? 1 : 0; 31 | Instruction nJmp = generator.NextJMP(chunk, instructions[idx + 2]); 32 | chunk.Instructions.Insert(chunk.InstructionMap[i] + 1, nJmp); 33 | } 34 | 35 | break; 36 | } 37 | 38 | case Opcode.Test: 39 | { 40 | if (r.Next(2) == 1) { 41 | i.C = i.C == 0 ? 1 : 0; 42 | Instruction nJmp = generator.NextJMP(chunk, instructions[idx + 2]); 43 | chunk.Instructions.Insert(chunk.InstructionMap[i] + 1, nJmp); 44 | } 45 | 46 | break; 47 | } 48 | } 49 | } 50 | 51 | chunk.UpdateMappings(); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/Types/TestPreserve.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using IronBrew2.Bytecode_Library.Bytecode; 5 | using IronBrew2.Bytecode_Library.IR; 6 | using IronBrew2.Extensions; 7 | 8 | namespace IronBrew2.Obfuscator.Control_Flow.Types 9 | { 10 | public static class TestPreserve 11 | { 12 | private static List used = new List(); 13 | 14 | private static int NIntND(int min, int max) 15 | { 16 | var x = Enumerable.Range(min, max - min).ToList(); 17 | x.RemoveAll(y => used.Contains(y)); 18 | x.Shuffle(); 19 | int n = x[0]; 20 | used.Add(n); 21 | return n; 22 | } 23 | 24 | public static void DoInstructions(Chunk chunk, List instructions) 25 | { 26 | for (int idx = 0; idx < instructions.Count; idx++) 27 | { 28 | used.Clear(); 29 | Instruction i = instructions[idx]; 30 | switch (i.OpCode) 31 | { 32 | case Opcode.Lt: 33 | case Opcode.Le: 34 | case Opcode.Eq: 35 | { 36 | int mReg1 = 250; 37 | int mReg2 = 251; 38 | 39 | Instruction ma, mb; 40 | 41 | if (i.RefOperands[0] is Constant c1) 42 | { 43 | ma = new Instruction(chunk, Opcode.LoadConst, c1); 44 | ma.A = mReg1; 45 | } 46 | else 47 | { 48 | ma = new Instruction(chunk, Opcode.Move); 49 | ma.A = mReg1; 50 | ma.B = i.B; 51 | } 52 | 53 | if (i.RefOperands[1] is Constant c2) 54 | { 55 | mb = new Instruction(chunk, Opcode.LoadConst, c2); 56 | mb.A = mReg2; 57 | } 58 | else 59 | { 60 | mb = new Instruction(chunk, Opcode.Move); 61 | mb.A = mReg2; 62 | mb.B = i.C; 63 | } 64 | 65 | Instruction loadbool1 = new Instruction(chunk, Opcode.LoadBool); 66 | loadbool1.A = mReg1; 67 | loadbool1.B = 0; 68 | 69 | Instruction loadbool2 = new Instruction(chunk, Opcode.LoadBool); 70 | loadbool2.A = mReg2; 71 | loadbool2.B = 0; 72 | 73 | i.B = mReg1; 74 | i.C = mReg2; 75 | 76 | i.SetupRefs(); 77 | 78 | chunk.Instructions.InsertRange(chunk.InstructionMap[i] + 2,new[]{new Instruction(loadbool1), new Instruction(loadbool2)}); //yed 79 | chunk.Instructions.InsertRange(chunk.InstructionMap[i], new[] {ma, mb}); 80 | chunk.UpdateMappings(); 81 | 82 | chunk.Instructions.InsertRange(chunk.InstructionMap[(Instruction)chunk.Instructions[chunk.InstructionMap[i] + 1].RefOperands[0]], new[]{loadbool1, loadbool2}); // 10/10 83 | chunk.Instructions[chunk.InstructionMap[i] + 1].RefOperands[0] = loadbool1; 84 | chunk.UpdateMappings(); 85 | 86 | foreach (Instruction ins in i.BackReferences) 87 | ins.RefOperands[0] = ma; 88 | 89 | break; 90 | } 91 | 92 | case Opcode.Test: 93 | case Opcode.TestSet: 94 | { 95 | int rReg = NIntND(0, 128); 96 | int pReg = NIntND(257, 512); 97 | 98 | Instruction m1 = new Instruction(chunk, Opcode.Move); 99 | m1.A = pReg; 100 | m1.B = rReg; 101 | 102 | Instruction m2 = new Instruction(chunk, Opcode.Move); 103 | m2.A = rReg; 104 | m2.B = i.A; 105 | 106 | Instruction lb = new Instruction(chunk, Opcode.LoadBool); 107 | lb.A = pReg; 108 | lb.B = 0; 109 | 110 | Instruction m3 = new Instruction(chunk, Opcode.Move); 111 | m3.A = rReg; 112 | m3.B = pReg; 113 | 114 | chunk.Instructions.InsertRange(chunk.InstructionMap[i] + 2,new[] {new Instruction(m3), new Instruction(lb) }); 115 | chunk.Instructions.InsertRange(chunk.InstructionMap[i], new[] {m1, m2}); 116 | chunk.UpdateMappings(); 117 | 118 | chunk.Instructions.InsertRange(chunk.InstructionMap[(Instruction)chunk.Instructions[chunk.InstructionMap[i] + 1].RefOperands[0]], new[]{m3, lb}); // 10/10 119 | chunk.Instructions[chunk.InstructionMap[i] + 1].RefOperands[0] = m3; 120 | chunk.UpdateMappings(); 121 | 122 | foreach (Instruction ins in i.BackReferences) 123 | ins.RefOperands[0] = m1; 124 | 125 | break; 126 | } 127 | } 128 | } 129 | } 130 | } 131 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Control Flow/Types/TestSpam.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using IronBrew2.Bytecode_Library.Bytecode; 5 | using IronBrew2.Bytecode_Library.IR; 6 | using IronBrew2.Extensions; 7 | 8 | namespace IronBrew2.Obfuscator.Control_Flow.Types 9 | { 10 | public static class TestSpam 11 | { 12 | private static List used = new List(); 13 | 14 | private static int NIntND(int min, int max) 15 | { 16 | var x = Enumerable.Range(min, max - min).ToList(); 17 | x.RemoveAll(y => used.Contains(y)); 18 | x.Shuffle(); 19 | int n = x[0]; 20 | used.Add(n); 21 | return n; 22 | } 23 | 24 | public static void DoInstructions(Chunk chunk, List Instructions) 25 | { 26 | Instructions = Instructions.ToList(); 27 | CFGenerator cg = new CFGenerator(); 28 | Random r = new Random(); 29 | 30 | for (int i = Instructions.Count - 1; i >= 0; i--) 31 | { 32 | used.Clear(); 33 | Instruction instr = Instructions[i]; 34 | 35 | List newInstructions = new List(); 36 | 37 | switch (instr.OpCode) 38 | { 39 | case Opcode.Eq: 40 | case Opcode.Lt: 41 | case Opcode.Le: 42 | { 43 | Instruction[] AddTVGroup(Instruction test) 44 | { 45 | Instruction cmp1, cmp2; 46 | { 47 | cmp1 = new Instruction(test); 48 | Instruction target = chunk.Instructions[chunk.InstructionMap[test] + 1]; 49 | 50 | Instruction jmpCorrect = cg.NextJMP(chunk, (Instruction) target.RefOperands[0]); 51 | Instruction jmpJunk = cg.NextJMP(chunk, Instructions[r.Next(0, i - 2)]); 52 | 53 | target.RefOperands[0] = cmp1; 54 | chunk.Instructions.AddRange(new[] {cmp1, jmpCorrect, jmpJunk}); 55 | } 56 | 57 | { 58 | cmp2 = new Instruction(test); 59 | 60 | Instruction target = chunk.Instructions[chunk.InstructionMap[test] + 2]; 61 | 62 | Instruction jmpCorrect = cg.NextJMP(chunk, target); 63 | Instruction jmpJunk = cg.NextJMP(chunk, Instructions[r.Next(0, i - 2)]); 64 | Instruction jmpStart = cg.NextJMP(chunk, cmp2); 65 | 66 | chunk.Instructions.Insert(chunk.InstructionMap[target], jmpStart); 67 | chunk.Instructions.AddRange(new[] {cmp2, jmpJunk, jmpCorrect}); 68 | } 69 | 70 | chunk.UpdateMappings(); 71 | return new[] {cmp1, cmp2}; 72 | } 73 | 74 | 75 | List tv1 = AddTVGroup(instr).ToList(); 76 | for (int j = 0; j < 3; j++) 77 | { 78 | List tv2 = new List(); 79 | foreach (Instruction ins in tv1) 80 | tv2.AddRange(AddTVGroup(ins)); 81 | tv1 = tv2; 82 | } 83 | break; 84 | } 85 | 86 | case Opcode.Test: 87 | case Opcode.TestSet: 88 | { 89 | Instruction[] AddTVGroup(Instruction test) 90 | { 91 | Instruction test1, test2; 92 | { 93 | test1 = new Instruction(test); 94 | 95 | Instruction target = chunk.Instructions[chunk.InstructionMap[test] + 1]; 96 | 97 | Instruction jmpCorrect = cg.NextJMP(chunk, (Instruction) target.RefOperands[0]); 98 | Instruction jmpJunk = cg.NextJMP(chunk, Instructions[r.Next(0, i - 2)]); 99 | 100 | target.RefOperands[0] = test1; 101 | chunk.Instructions.AddRange(new[] {test1, jmpCorrect, jmpJunk}); 102 | } 103 | 104 | { 105 | test2 = new Instruction(test); 106 | 107 | Instruction target = chunk.Instructions[chunk.InstructionMap[test] + 2]; 108 | 109 | Instruction jmpCorrect = cg.NextJMP(chunk, target); 110 | Instruction jmpJunk = cg.NextJMP(chunk, Instructions[r.Next(0, i - 2)]); 111 | Instruction jmpStart = cg.NextJMP(chunk, test2); 112 | 113 | chunk.Instructions.Insert(chunk.InstructionMap[target], jmpStart); 114 | chunk.Instructions.AddRange(new[] {test2, jmpJunk, jmpCorrect}); 115 | } 116 | 117 | chunk.UpdateMappings(); 118 | return new[] {test1, test2}; 119 | } 120 | 121 | List tv1 = AddTVGroup(instr).ToList(); 122 | for (int j = 0; j < 3; j++) 123 | { 124 | int x = tv1.Count; 125 | for (var index = 0; index < x; index++) 126 | { 127 | Instruction ins = tv1[index]; 128 | tv1.AddRange(AddTVGroup(ins)); 129 | } 130 | } 131 | break; 132 | } 133 | } 134 | } 135 | chunk.UpdateMappings(); 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/CustomInstructionData.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Obfuscator 2 | { 3 | public class CustomInstructionData 4 | { 5 | public VOpcode Opcode; 6 | public VOpcode WrittenOpcode; 7 | } 8 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Encryption/ConstantEncryption.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace IronBrew2.Obfuscator.Encryption 9 | { 10 | public class Decryptor 11 | { 12 | public int[] Table; 13 | public int SLen = 0; 14 | 15 | public string Name; 16 | 17 | public string Encrypt(byte[] bytes) 18 | { 19 | List encrypted = new List(); 20 | 21 | int L = Table.Length; 22 | 23 | for (var index = 0; index < bytes.Length; index++) 24 | encrypted.Add((byte) (bytes[index] ^ Table[index % L])); 25 | 26 | return $"((function(b)IB_INLINING_START(true);local function xor(b,c)IB_INLINING_START(true);local d,e=1,0;while b>0 and c>0 do local f,g=b%2,c%2;if f~=g then e=e+d end;b,c,d=(b-f)/2,(c-g)/2,d*2 end;if b0 do local f=b%2;if f>0 then e=e+d end;b,d=(b-f)/2,d*2 end;return e end;local c=\"\"local e=string.sub;local h=string.char;local t = {{}} for j=0, 255 do local x=h(j);t[j]=x;t[x]=j;end;local f=\"{string.Join("", Table.Select(t => "\\" + t.ToString()))}\" for g=1,#b do local x=(g-1) % {Table.Length}+1 c=c..t[xor(t[e(b,g,g)],t[e(f, x, x)])];end;return c;end)(\"{string.Join("", encrypted.Select(t => "\\" + t.ToString()))}\"))"; 27 | } 28 | 29 | public Decryptor(string name, int maxLen) 30 | { 31 | Random r = new Random(); 32 | 33 | Name = name; 34 | Table = Enumerable.Repeat(0, maxLen).Select(i => r.Next(0, 256)).ToArray(); 35 | } 36 | } 37 | 38 | public class ConstantEncryption 39 | { 40 | private string _src; 41 | private ObfuscationSettings _settings; 42 | private Encoding _fuckingLua = Encoding.GetEncoding(28591); 43 | 44 | public Decryptor GenerateGenericDecryptor(MatchCollection matches) 45 | { 46 | int len = 0; 47 | 48 | for (int i = 0; i < matches.Count; i++) 49 | { 50 | int l = matches[i].Length; 51 | if (l > len) 52 | len = l; 53 | } 54 | 55 | if (len > _settings.DecryptTableLen) 56 | len = _settings.DecryptTableLen; 57 | 58 | return new Decryptor("IRONBREW_STR_DEC_GENERIC", len); 59 | } 60 | 61 | public static byte[] UnescapeLuaString(string str) 62 | { 63 | List bytes = new List(); 64 | 65 | int i = 0; 66 | while (i < str.Length) 67 | { 68 | char cur = str[i++]; 69 | if (cur == '\\') 70 | { 71 | char next = str[i++]; 72 | 73 | switch (next) 74 | { 75 | case 'a': 76 | bytes.Add((byte) '\a'); 77 | break; 78 | 79 | case 'b': 80 | bytes.Add((byte) '\b'); 81 | break; 82 | 83 | case 'f': 84 | bytes.Add((byte) '\f'); 85 | break; 86 | 87 | case 'n': 88 | bytes.Add((byte) '\n'); 89 | break; 90 | 91 | case 'r': 92 | bytes.Add((byte) '\r'); 93 | break; 94 | 95 | case 't': 96 | bytes.Add((byte) '\t'); 97 | break; 98 | 99 | case 'v': 100 | bytes.Add((byte) '\v'); 101 | break; 102 | 103 | default: 104 | { 105 | if (!char.IsDigit(next)) 106 | bytes.Add((byte) next); 107 | else // \001, \55h, etc 108 | { 109 | string s = next.ToString(); 110 | for (int j = 0; j < 2; j++, i++) 111 | { 112 | if (i == str.Length) 113 | break; 114 | 115 | char n = str[i]; 116 | if (char.IsDigit(n)) 117 | s = s + n; 118 | else 119 | break; 120 | } 121 | 122 | bytes.Add((byte) int.Parse(s)); 123 | } 124 | 125 | break; 126 | } 127 | } 128 | } 129 | else 130 | bytes.Add((byte) cur); 131 | } 132 | 133 | return bytes.ToArray(); 134 | } 135 | 136 | public string EncryptStrings() 137 | { 138 | const string encRegex = @"(['""])?(?(1)((?:[^\\]|\\.)*?)\1|\[(=*)\[(.*?)\]\3\])"; 139 | 140 | if (_settings.EncryptStrings) 141 | { 142 | Regex r = new Regex(encRegex, RegexOptions.Singleline | RegexOptions.Compiled); 143 | 144 | int indDiff = 0; 145 | var matches = r.Matches(_src); 146 | 147 | Decryptor dec = GenerateGenericDecryptor(matches); 148 | 149 | foreach (Match m in matches) 150 | { 151 | string before = _src.Substring(0, m.Index + indDiff); 152 | string after = _src.Substring(m.Index + indDiff + m.Length); 153 | 154 | string captured = m.Groups[2].Value + m.Groups[4].Value; 155 | 156 | if (captured.StartsWith("[STR_ENCRYPT]")) 157 | captured = captured.Substring(13); 158 | 159 | string nStr = before + dec.Encrypt(m.Groups[2].Value != "" ? UnescapeLuaString(captured) : _fuckingLua.GetBytes(captured)); 160 | nStr += after; 161 | 162 | indDiff += nStr.Length - _src.Length; 163 | _src = nStr; 164 | } 165 | } 166 | 167 | else 168 | { 169 | Regex r = new Regex(encRegex, RegexOptions.Singleline | RegexOptions.Compiled); 170 | var matches = r.Matches(_src); 171 | 172 | int indDiff = 0; 173 | int n = 0; 174 | 175 | foreach (Match m in matches) 176 | { 177 | string captured = m.Groups[2].Value + m.Groups[4].Value; 178 | 179 | if (!captured.StartsWith("[STR_ENCRYPT]")) 180 | continue; 181 | 182 | captured = captured.Substring(13); 183 | Decryptor dec = new Decryptor("IRONBREW_STR_ENCRYPT" + n++, m.Length); 184 | 185 | string before = _src.Substring(0, m.Index + indDiff); 186 | string after = _src.Substring(m.Index + indDiff + m.Length); 187 | 188 | string nStr = before + dec.Encrypt(m.Groups[2].Value != "" 189 | ? UnescapeLuaString(captured) 190 | : _fuckingLua.GetBytes(captured)); 191 | nStr += after; 192 | 193 | indDiff += nStr.Length - _src.Length; 194 | _src = nStr; 195 | } 196 | } 197 | 198 | if (_settings.EncryptImportantStrings) 199 | { 200 | Regex r = new Regex(encRegex, RegexOptions.Singleline | RegexOptions.Compiled); 201 | var matches = r.Matches(_src); 202 | 203 | int indDiff = 0; 204 | int n = 0; 205 | 206 | List sTerms = new List() {"http", "function", "metatable", "local"}; 207 | 208 | foreach (Match m in matches) 209 | { 210 | string captured = m.Groups[2].Value + m.Groups[4].Value; 211 | if (captured.StartsWith("[STR_ENCRYPT]")) 212 | captured = captured.Substring(13); 213 | 214 | bool cont = false; 215 | 216 | foreach (string search in sTerms) 217 | { 218 | if (captured.ToLower().Contains(search.ToLower())) 219 | cont = true; 220 | } 221 | 222 | if (!cont) 223 | continue; 224 | 225 | Decryptor dec = new Decryptor("IRONBREW_STR_ENCRYPT_IMPORTANT" + n++, m.Length); 226 | 227 | string before = _src.Substring(0, m.Index + indDiff); 228 | string after = _src.Substring(m.Index + indDiff + m.Length); 229 | 230 | string nStr = before + dec.Encrypt(m.Groups[2].Value != "" 231 | ? UnescapeLuaString(captured) 232 | : _fuckingLua.GetBytes(captured)); 233 | 234 | nStr += after; 235 | 236 | indDiff += nStr.Length - _src.Length; 237 | _src = nStr; 238 | } 239 | } 240 | 241 | return _src; 242 | } 243 | 244 | public ConstantEncryption(ObfuscationSettings settings, string source) 245 | { 246 | _settings = settings; 247 | _src = source; 248 | } 249 | } 250 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Encryption/VMIntegrityCheck.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Obfuscator.Encryption 2 | { 3 | public class VMIntegrityCheck 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Macros/Crash.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Obfuscator.Macros 2 | { 3 | public class Crash 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Macros/SetFenv.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Obfuscator.Macros 2 | { 3 | public class SetFenv 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Macros/StrEncrypt.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Obfuscator.Macros 2 | { 3 | public class StrEncrypt 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/ObfuscationContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using IronBrew2.Bytecode_Library.Bytecode; 5 | using IronBrew2.Bytecode_Library.IR; 6 | using IronBrew2.Extensions; 7 | 8 | namespace IronBrew2.Obfuscator 9 | { 10 | public enum ChunkStep 11 | { 12 | ParameterCount, 13 | StringTable, 14 | Instructions, 15 | Constants, 16 | Functions, 17 | LineInfo, 18 | StepCount 19 | } 20 | 21 | public enum InstructionStep1 22 | { 23 | Type, 24 | A, 25 | B, 26 | C, 27 | StepCount 28 | } 29 | 30 | public enum InstructionStep2 31 | { 32 | Op, 33 | Bx, 34 | D, 35 | StepCount 36 | } 37 | 38 | public class ObfuscationContext 39 | { 40 | public Chunk HeadChunk; 41 | public ChunkStep[] ChunkSteps; 42 | public InstructionStep1[] InstructionSteps1; 43 | public InstructionStep2[] InstructionSteps2; 44 | public int[] ConstantMapping; 45 | 46 | public Dictionary InstructionMapping = new Dictionary(); 47 | 48 | public int PrimaryXorKey; 49 | 50 | public int IXorKey1; 51 | public int IXorKey2; 52 | 53 | public ObfuscationContext(Chunk chunk) 54 | { 55 | HeadChunk = chunk; 56 | ChunkSteps = Enumerable.Range(0, (int) ChunkStep.StepCount).Select(i => (ChunkStep) i).ToArray(); 57 | ChunkSteps.Shuffle(); 58 | 59 | InstructionSteps1 = Enumerable.Range(0, (int) InstructionStep1.StepCount).Select(i => (InstructionStep1) i).ToArray(); 60 | InstructionSteps1.Shuffle(); 61 | 62 | InstructionSteps2 = Enumerable.Range(0, (int) InstructionStep2.StepCount).Select(i => (InstructionStep2) i).ToArray(); 63 | InstructionSteps2.Shuffle(); 64 | 65 | ConstantMapping = Enumerable.Range(0, 4).ToArray(); 66 | ConstantMapping.Shuffle(); 67 | 68 | Random rand = new Random(); 69 | 70 | PrimaryXorKey = rand.Next(0, 256); 71 | IXorKey1 = rand.Next(0, 256); 72 | IXorKey2 = rand.Next(0, 256); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/ObfuscationSettings.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Obfuscator 2 | { 3 | public class ObfuscationSettings 4 | { 5 | public bool EncryptStrings; 6 | public bool EncryptImportantStrings; 7 | public bool ControlFlow; 8 | public bool BytecodeCompress; 9 | public int DecryptTableLen; 10 | public bool PreserveLineInfo; 11 | public bool Mutate; 12 | public bool SuperOperators; 13 | public int MaxMiniSuperOperators; 14 | public int MaxMegaSuperOperators; 15 | public int MaxMutations; 16 | 17 | public ObfuscationSettings() 18 | { 19 | EncryptStrings = false; 20 | EncryptImportantStrings = false; 21 | ControlFlow = true; 22 | BytecodeCompress = true; 23 | DecryptTableLen = 500; 24 | PreserveLineInfo = false; 25 | Mutate = true; 26 | SuperOperators = true; 27 | MaxMegaSuperOperators = 200; 28 | MaxMiniSuperOperators = 150; 29 | MaxMutations = 300; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpAdd.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpAdd : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Add && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]+Stk[Inst[OP_C]];"; 13 | } 14 | 15 | public class OpAddB : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.Add && instruction.B > 255 && instruction.C <= 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]+Stk[Inst[OP_C]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.B -= 255; 25 | } 26 | 27 | public class OpAddC : VOpcode 28 | { 29 | public override bool IsInstruction(Instruction instruction) => 30 | instruction.OpCode == Opcode.Add && instruction.B <= 255 && instruction.C > 255; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]+Const[Inst[OP_C]];"; 34 | 35 | public override void Mutate(Instruction instruction) => 36 | instruction.C -= 255; 37 | } 38 | 39 | public class OpAddBC : VOpcode 40 | { 41 | public override bool IsInstruction(Instruction instruction) => 42 | instruction.OpCode == Opcode.Add && instruction.B > 255 && instruction.C > 255; 43 | 44 | public override string GetObfuscated(ObfuscationContext context) => 45 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]+Const[Inst[OP_C]];"; 46 | 47 | public override void Mutate(Instruction instruction) 48 | { 49 | instruction.B -= 255; 50 | instruction.C -= 255; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpCall.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpCall : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Call && instruction.B > 1 && 10 | instruction.C > 1; 11 | 12 | public override string GetObfuscated(ObfuscationContext context) => 13 | "local A=Inst[OP_A];local Args={};local Edx=0;local Limit=A+Inst[OP_B]-1;for Idx=A+1,Limit do Edx=Edx+1;Args[Edx]=Stk[Idx];end;local Results={Stk[A](Unpack(Args,1,Limit-A))};local Limit=A+Inst[OP_C]-2;Edx=0;for Idx=A,Limit do Edx=Edx+1;Stk[Idx]=Results[Edx];end;Top=Limit;"; 14 | } 15 | 16 | public class OpCallB0 : VOpcode 17 | { 18 | public override bool IsInstruction(Instruction instruction) => 19 | instruction.OpCode == Opcode.Call && instruction.B == 0 && 20 | instruction.C > 1; 21 | 22 | public override string GetObfuscated(ObfuscationContext context) => 23 | "local A=Inst[OP_A];local Args={};local Edx=0;local Limit=Top;for Idx=A+1,Limit do Edx=Edx+1;Args[Edx]=Stk[Idx];end;local Results={Stk[A](Unpack(Args,1,Limit-A))};local Limit=A+Inst[OP_C]-2;Edx=0;for Idx=A,Limit do Edx=Edx+1;Stk[Idx]=Results[Edx];end;Top=Limit;"; 24 | } 25 | 26 | public class OpCallB1 : VOpcode 27 | { 28 | public override bool IsInstruction(Instruction instruction) => 29 | instruction.OpCode == Opcode.Call && instruction.B == 1 && 30 | instruction.C > 1; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "local A=Inst[OP_A];local Results,Limit={Stk[A]()};local Limit=A+Inst[OP_C]-2;local Edx=0;for Idx=A,Limit do Edx=Edx+1;Stk[Idx]=Results[Edx];end;Top=Limit;"; 34 | } 35 | 36 | public class OpCallC0 : VOpcode 37 | { 38 | public override bool IsInstruction(Instruction instruction) => 39 | instruction.OpCode == Opcode.Call && instruction.B > 1 && 40 | instruction.C == 0; 41 | 42 | public override string GetObfuscated(ObfuscationContext context) => 43 | "local A=Inst[OP_A];local Args={};local Edx=0;local Limit=A+Inst[OP_B]-1;for Idx=A+1,Limit do Edx=Edx+1;Args[Edx]=Stk[Idx];end;local Results,Limit=_R(Stk[A](Unpack(Args,1,Limit-A)));Limit=Limit+A-1;Edx=0;for Idx=A,Limit do Edx=Edx+1;Stk[Idx]=Results[Edx];end;Top=Limit;"; 44 | } 45 | 46 | public class OpCallC1 : VOpcode 47 | { 48 | public override bool IsInstruction(Instruction instruction) => 49 | instruction.OpCode == Opcode.Call && instruction.B > 1 && 50 | instruction.C == 1; 51 | 52 | public override string GetObfuscated(ObfuscationContext context) => 53 | "local A=Inst[OP_A];local Args={};local Edx=0;local Limit=A+Inst[OP_B]-1;for Idx=A+1,Limit do Edx=Edx+1;Args[Edx]=Stk[Idx];end;Stk[A](Unpack(Args,1,Limit-A));Top=A;"; 54 | } 55 | 56 | public class OpCallB0C0 : VOpcode 57 | { 58 | public override bool IsInstruction(Instruction instruction) => 59 | instruction.OpCode == Opcode.Call && instruction.B == 0 && 60 | instruction.C == 0; 61 | 62 | public override string GetObfuscated(ObfuscationContext context) => 63 | "local A=Inst[OP_A];local Args={};local Edx=0;local Limit=Top;for Idx=A+1,Limit do Edx=Edx+1;Args[Edx]=Stk[Idx];end;local Results,Limit=_R(Stk[A](Unpack(Args,1,Limit-A)));Limit=Limit+A-1;Edx=0;for Idx=A,Limit do Edx=Edx+1;Stk[Idx]=Results[Edx];end;Top=Limit;"; 64 | } 65 | 66 | public class OpCallB0C1 : VOpcode 67 | { 68 | public override bool IsInstruction(Instruction instruction) => 69 | instruction.OpCode == Opcode.Call && instruction.B == 0 && 70 | instruction.C == 1; 71 | 72 | public override string GetObfuscated(ObfuscationContext context) => 73 | "local A=Inst[OP_A];local Args={};local Edx=0;local Limit=Top;for Idx=A+1,Limit do Edx=Edx+1;Args[Edx]=Stk[Idx];end;Stk[A](Unpack(Args,1,Limit-A));Top=A;"; 74 | } 75 | 76 | public class OpCallB1C0 : VOpcode 77 | { 78 | public override bool IsInstruction(Instruction instruction) => 79 | instruction.OpCode == Opcode.Call && instruction.B == 1 && 80 | instruction.C == 0; 81 | 82 | public override string GetObfuscated(ObfuscationContext context) => 83 | "local A=Inst[OP_A];local Results,Limit=_R(Stk[A]());Top=A-1;Limit=Limit+A-1;local Edx=0;for Idx=A,Limit do Edx=Edx+1;Stk[Idx]=Results[Edx];end;Top=Limit;"; 84 | } 85 | 86 | public class OpCallB1C1 : VOpcode 87 | { 88 | public override bool IsInstruction(Instruction instruction) => 89 | instruction.OpCode == Opcode.Call && instruction.B == 1 && 90 | instruction.C == 1; 91 | 92 | public override string GetObfuscated(ObfuscationContext context) => 93 | "Stk[Inst[OP_A]]();Top=A;"; 94 | } 95 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpClose.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpClose : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Close; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local A=Inst[OP_A];local Cls={};for Idx=1,#Lupvals do local List=Lupvals[Idx];for Idz=0,#List do local Upv=List[Idz];local NStk=Upv[1];local Pos=Upv[2]; if NStk==Stk and Pos>=A then Cls[Pos]=NStk[Pos];Upv[1]=Cls;end;end;end;"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpClosure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IronBrew2.Bytecode_Library.Bytecode; 3 | using IronBrew2.Bytecode_Library.IR; 4 | 5 | namespace IronBrew2.Obfuscator.Opcodes 6 | { 7 | public class OpClosure : VOpcode 8 | { 9 | public override bool IsInstruction(Instruction instruction) => 10 | instruction.OpCode == Opcode.Closure && instruction.Chunk.Functions[instruction.B].UpvalueCount > 0; 11 | 12 | public override string GetObfuscated(ObfuscationContext context) 13 | { 14 | context.InstructionMapping.TryGetValue(Opcode.Move, out var i1); 15 | 16 | return 17 | "local NewProto=Proto[Inst[OP_B]];local NewUvals;local Indexes={};NewUvals=Setmetatable({},{__index=function(_,Key)local Val=Indexes[Key];return Val[1][Val[2]];end,__newindex=function(_,Key,Value)local Val=Indexes[Key] Val[1][Val[2]]=Value;end;});for Idx=1,Inst[OP_C] do InstrPoint=InstrPoint+1;local Mvm=Instr[InstrPoint];if Mvm[OP_ENUM]==OP_MOVE then Indexes[Idx-1]={Stk,Mvm[OP_B]};else Indexes[Idx-1]={Upvalues,Mvm[OP_B]};end;Lupvals[#Lupvals+1]=Indexes;end;Stk[Inst[OP_A]]=Wrap(NewProto,NewUvals,Env);" 18 | .Replace("OP_MOVE", i1?.VIndex.ToString() ?? "-1"); 19 | } 20 | 21 | public override void Mutate(Instruction instruction) 22 | { 23 | instruction.InstructionType = InstructionType.AsBxC; 24 | instruction.C = instruction.Chunk.Functions[instruction.B].UpvalueCount; 25 | } 26 | } 27 | 28 | public class OpClosureNU : VOpcode 29 | { 30 | public override bool IsInstruction(Instruction instruction) => 31 | instruction.OpCode == Opcode.Closure && instruction.Chunk.Functions[instruction.B].UpvalueCount == 0; 32 | 33 | public override string GetObfuscated(ObfuscationContext context) => 34 | "Stk[Inst[OP_A]]=Wrap(Proto[Inst[OP_B]],nil,Env);"; 35 | } 36 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpConcat.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpConcat : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Concat; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local B=Inst[OP_B];local K=Stk[B] for Idx=B+1,Inst[OP_C] do K=K..Stk[Idx];end;Stk[Inst[OP_A]]=K;"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpDiv.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpDiv : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Div && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]/Stk[Inst[OP_C]];"; 13 | } 14 | 15 | public class OpDivB : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.Div && instruction.B > 255 && instruction.C <= 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]/Stk[Inst[OP_C]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.B -= 255; 25 | } 26 | 27 | public class OpDivC : VOpcode 28 | { 29 | public override bool IsInstruction(Instruction instruction) => 30 | instruction.OpCode == Opcode.Div && instruction.B <= 255 && instruction.C > 255; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]/Const[Inst[OP_C]];"; 34 | 35 | public override void Mutate(Instruction instruction) => 36 | instruction.C -= 255; 37 | } 38 | 39 | public class OpDivBC : VOpcode 40 | { 41 | public override bool IsInstruction(Instruction instruction) => 42 | instruction.OpCode == Opcode.Div && instruction.B > 255 && instruction.C > 255; 43 | 44 | public override string GetObfuscated(ObfuscationContext context) => 45 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]/Const[Inst[OP_C]];"; 46 | 47 | public override void Mutate(Instruction instruction) 48 | { 49 | instruction.B -= 255; 50 | instruction.C -= 255; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpEq.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpEq : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Eq && instruction.A == 0 && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "if(Stk[Inst[OP_A]]==Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 13 | 14 | public override void Mutate(Instruction instruction) 15 | { 16 | instruction.A = instruction.B; 17 | 18 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 19 | instruction.InstructionType = InstructionType.AsBxC; 20 | } 21 | } 22 | 23 | public class OpEqB : VOpcode 24 | { 25 | public override bool IsInstruction(Instruction instruction) => 26 | instruction.OpCode == Opcode.Eq && instruction.A == 0 && instruction.B > 255 && instruction.C <= 255; 27 | 28 | public override string GetObfuscated(ObfuscationContext context) => 29 | "if(Const[Inst[OP_A]]==Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 30 | 31 | public override void Mutate(Instruction instruction) 32 | { 33 | instruction.A = instruction.B - 255; 34 | 35 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 36 | instruction.InstructionType = InstructionType.AsBxC; 37 | } 38 | } 39 | 40 | public class OpEqC : VOpcode 41 | { 42 | public override bool IsInstruction(Instruction instruction) => 43 | instruction.OpCode == Opcode.Eq && instruction.A == 0 && instruction.B <= 255 && instruction.C > 255; 44 | 45 | public override string GetObfuscated(ObfuscationContext context) => 46 | "if(Stk[Inst[OP_A]]==Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 47 | 48 | public override void Mutate(Instruction instruction) 49 | { 50 | instruction.A = instruction.B; 51 | instruction.C -= 255; 52 | 53 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 54 | instruction.InstructionType = InstructionType.AsBxC; 55 | } 56 | } 57 | 58 | public class OpEqBC : VOpcode 59 | { 60 | public override bool IsInstruction(Instruction instruction) => 61 | instruction.OpCode == Opcode.Eq && instruction.A == 0 && instruction.B > 255 && instruction.C > 255; 62 | 63 | public override string GetObfuscated(ObfuscationContext context) => 64 | "if(Const[Inst[OP_A]]==Const[Inst[OP_C]]) then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 65 | 66 | public override void Mutate(Instruction instruction) 67 | { 68 | instruction.A = instruction.B - 255; 69 | instruction.C -= 255; 70 | 71 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 72 | instruction.InstructionType = InstructionType.AsBxC; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpForLoop.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpForLoop : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.ForLoop; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local A=Inst[OP_A];local Step=Stk[A+2];local Index=Stk[A]+Step;Stk[A]=Index;if Step>0 then if Index<=Stk[A+1] then InstrPoint=InstrPoint+Inst[OP_B];Stk[A+3]=Index;end;elseif Index>=Stk[A+1] then InstrPoint=InstrPoint+Inst[OP_B];Stk[A+3]=Index;end;"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpForPrep.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpForPrep : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.ForPrep; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local A=Inst[OP_A];Stk[A]=Stk[A]-Stk[A+2];InstrPoint=InstrPoint+Inst[OP_B];"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpGe.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpGe : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Lt && instruction.A != 0 && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "if(Stk[Inst[OP_A]]>=Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 13 | 14 | public override void Mutate(Instruction instruction) 15 | { 16 | instruction.A = instruction.B; 17 | 18 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 19 | instruction.InstructionType = InstructionType.AsBxC; 20 | } 21 | } 22 | 23 | public class OpGeB : VOpcode 24 | { 25 | public override bool IsInstruction(Instruction instruction) => 26 | instruction.OpCode == Opcode.Lt && instruction.A != 0 && instruction.B > 255 && instruction.C <= 255; 27 | 28 | public override string GetObfuscated(ObfuscationContext context) => 29 | "if(Const[Inst[OP_A]]>=Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 30 | 31 | public override void Mutate(Instruction instruction) 32 | { 33 | instruction.A = instruction.B - 255; 34 | instruction.B -= 255; 35 | 36 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 37 | instruction.InstructionType = InstructionType.AsBxC; 38 | } 39 | } 40 | 41 | public class OpGeC : VOpcode 42 | { 43 | public override bool IsInstruction(Instruction instruction) => 44 | instruction.OpCode == Opcode.Lt && instruction.A != 0 && instruction.B <= 255 && instruction.C > 255; 45 | 46 | public override string GetObfuscated(ObfuscationContext context) => 47 | "if(Stk[Inst[OP_A]]>=Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 48 | 49 | public override void Mutate(Instruction instruction) 50 | { 51 | instruction.A = instruction.B; 52 | instruction.C -= 255; 53 | 54 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 55 | instruction.InstructionType = InstructionType.AsBxC; 56 | } 57 | } 58 | 59 | public class OpGeBC : VOpcode 60 | { 61 | public override bool IsInstruction(Instruction instruction) => 62 | instruction.OpCode == Opcode.Lt && instruction.A != 0 && instruction.B > 255 && instruction.C > 255; 63 | 64 | public override string GetObfuscated(ObfuscationContext context) => 65 | "if(Const[Inst[OP_A]]>=Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 66 | 67 | public override void Mutate(Instruction instruction) 68 | { 69 | instruction.A = instruction.B - 255; 70 | instruction.C -= 255; 71 | 72 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 73 | instruction.InstructionType = InstructionType.AsBxC; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpGetGlobal.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpGetGlobal : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.GetGlobal; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Env[Const[Inst[OP_B]]];"; 13 | 14 | public override void Mutate(Instruction instruction) => 15 | instruction.B++; 16 | } 17 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpGetTable.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpGetTable : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.GetTable && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]][Stk[Inst[OP_C]]];"; 13 | } 14 | 15 | public class OpGetTableConst : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.GetTable && instruction.C > 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]][Const[Inst[OP_C]]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.C -= 255; 25 | } 26 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpGetUpval.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpGetUpval : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.GetUpval; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Upvalues[Inst[OP_B]];"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpGt.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpGt : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Le && instruction.A != 0 && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "if(Stk[Inst[OP_A]]>Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 13 | 14 | public override void Mutate(Instruction instruction) 15 | { 16 | instruction.A = instruction.B; 17 | 18 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 19 | instruction.InstructionType = InstructionType.AsBxC; 20 | } 21 | } 22 | 23 | public class OpGtB : VOpcode 24 | { 25 | public override bool IsInstruction(Instruction instruction) => 26 | instruction.OpCode == Opcode.Le && instruction.A != 0 && instruction.B > 255 && instruction.C <= 255; 27 | 28 | public override string GetObfuscated(ObfuscationContext context) => 29 | "if(Const[Inst[OP_A]]>Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 30 | 31 | public override void Mutate(Instruction instruction) 32 | { 33 | instruction.A = instruction.B - 255; 34 | 35 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 36 | instruction.InstructionType = InstructionType.AsBxC; 37 | } 38 | } 39 | 40 | public class OpGtC : VOpcode 41 | { 42 | public override bool IsInstruction(Instruction instruction) => 43 | instruction.OpCode == Opcode.Le && instruction.A != 0 && instruction.B <= 255 && instruction.C > 255; 44 | 45 | public override string GetObfuscated(ObfuscationContext context) => 46 | "if(Stk[Inst[OP_A]]>Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 47 | 48 | public override void Mutate(Instruction instruction) 49 | { 50 | instruction.A = instruction.B; 51 | instruction.C -= 255; 52 | 53 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 54 | instruction.InstructionType = InstructionType.AsBxC; 55 | } 56 | } 57 | 58 | public class OpGtBC : VOpcode 59 | { 60 | public override bool IsInstruction(Instruction instruction) => 61 | instruction.OpCode == Opcode.Le && instruction.A != 0 && instruction.B > 255 && instruction.C > 255; 62 | 63 | public override string GetObfuscated(ObfuscationContext context) => 64 | "if(Const[Inst[OP_A]]>Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 65 | 66 | public override void Mutate(Instruction instruction) 67 | { 68 | instruction.A = instruction.B - 255; 69 | instruction.C -= 255; 70 | 71 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 72 | instruction.InstructionType = InstructionType.AsBxC; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpJmp.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpJmp : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Jmp; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "InstrPoint=InstrPoint+Inst[OP_B];"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpLe.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpLe : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Le && instruction.A == 0 && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "if(Stk[Inst[OP_A]]<=Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 13 | 14 | public override void Mutate(Instruction instruction) 15 | { 16 | instruction.A = instruction.B; 17 | 18 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 19 | instruction.InstructionType = InstructionType.AsBxC; 20 | } 21 | } 22 | 23 | public class OpLeB : VOpcode 24 | { 25 | public override bool IsInstruction(Instruction instruction) => 26 | instruction.OpCode == Opcode.Le && instruction.A == 0 && instruction.B > 255 && instruction.C <= 255; 27 | 28 | public override string GetObfuscated(ObfuscationContext context) => 29 | "if(Const[Inst[OP_A]]<=Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 30 | 31 | public override void Mutate(Instruction instruction) 32 | { 33 | instruction.A = instruction.B - 255; 34 | 35 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 36 | instruction.InstructionType = InstructionType.AsBxC; 37 | } 38 | } 39 | 40 | public class OpLeC : VOpcode 41 | { 42 | public override bool IsInstruction(Instruction instruction) => 43 | instruction.OpCode == Opcode.Le && instruction.A == 0 && instruction.B <= 255 && instruction.C > 255; 44 | 45 | public override string GetObfuscated(ObfuscationContext context) => 46 | "if(Stk[Inst[OP_A]]<=Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 47 | 48 | public override void Mutate(Instruction instruction) 49 | { 50 | instruction.A = instruction.B; 51 | instruction.C -= 255; 52 | 53 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 54 | instruction.InstructionType = InstructionType.AsBxC; 55 | } 56 | } 57 | 58 | public class OpLeBC : VOpcode 59 | { 60 | public override bool IsInstruction(Instruction instruction) => 61 | instruction.OpCode == Opcode.Le && instruction.A == 0 && instruction.B > 255 && instruction.C > 255; 62 | 63 | public override string GetObfuscated(ObfuscationContext context) => 64 | "if(Const[Inst[OP_A]]<=Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 65 | 66 | public override void Mutate(Instruction instruction) 67 | { 68 | instruction.A = instruction.B - 255; 69 | instruction.C -= 255; 70 | 71 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 72 | instruction.InstructionType = InstructionType.AsBxC; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpLen.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpLen : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Len; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=#Stk[Inst[OP_B]];"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpLoadBool.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpLoadBool : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.LoadBool && instruction.C == 0; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=(Inst[OP_B]~=0);"; 13 | } 14 | 15 | public class OpLoadBoolC : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.LoadBool && instruction.C != 0; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]=(Inst[OP_B]~=0);InstrPoint=InstrPoint+1;"; 22 | 23 | public override void Mutate(Instruction ins) => 24 | ins.C = 0; 25 | } 26 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpLoadK.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpLoadK : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.LoadConst; // && instruction.Chunk.Constants[instruction.B].Type != ConstantType.String; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]];"; 13 | 14 | public override void Mutate(Instruction instruction) => 15 | instruction.B++; 16 | } 17 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpLoadNil.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpLoadNil : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.LoadNil; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "for Idx=Inst[OP_A],Inst[OP_B] do Stk[Idx]=nil;end;"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpLoadStr.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | //public class OpLoadStr : VOpcode 7 | //{ 8 | //public override bool IsInstruction(Instruction instruction) => 9 | // instruction.OpCode == Opcode.LoadConst && instruction.Chunk.Constants[instruction.B].Type == ConstantType.String; 10 | // 11 | //public override string GetObfuscated(ObfuscationContext context) => 12 | // "Stk[Inst[OP_A]]=Strt[Inst[OP_B]];"; 13 | // 14 | //public override void Mutate(Instruction instruction) => 15 | // instruction.B++; 16 | //} 17 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpLt.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpLt : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Lt && instruction.A == 0 && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "if(Stk[Inst[OP_A]] 26 | instruction.OpCode == Opcode.Lt && instruction.A == 0 && instruction.B > 255 && instruction.C <= 255; 27 | 28 | public override string GetObfuscated(ObfuscationContext context) => 29 | "if(Const[Inst[OP_A]] 43 | instruction.OpCode == Opcode.Lt && instruction.A == 0 && instruction.B <= 255 && instruction.C > 255; 44 | 45 | public override string GetObfuscated(ObfuscationContext context) => 46 | "if(Stk[Inst[OP_A]] 61 | instruction.OpCode == Opcode.Lt && instruction.A == 0 && instruction.B > 255 && instruction.C > 255; 62 | 63 | public override string GetObfuscated(ObfuscationContext context) => 64 | "if(Const[Inst[OP_A]] 9 | instruction.OpCode == Opcode.Mod && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]%Stk[Inst[OP_C]];"; 13 | } 14 | 15 | public class OpModB : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.Mod && instruction.B > 255 && instruction.C <= 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]%Stk[Inst[OP_C]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.B -= 255; 25 | } 26 | 27 | public class OpModC : VOpcode 28 | { 29 | public override bool IsInstruction(Instruction instruction) => 30 | instruction.OpCode == Opcode.Mod && instruction.B <= 255 && instruction.C > 255; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]%Const[Inst[OP_C]];"; 34 | 35 | public override void Mutate(Instruction instruction) => 36 | instruction.C -= 255; 37 | } 38 | 39 | public class OpModBC : VOpcode 40 | { 41 | public override bool IsInstruction(Instruction instruction) => 42 | instruction.OpCode == Opcode.Mod && instruction.B > 255 && instruction.C > 255; 43 | 44 | public override string GetObfuscated(ObfuscationContext context) => 45 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]%Const[Inst[OP_C]];"; 46 | 47 | public override void Mutate(Instruction instruction) 48 | { 49 | instruction.B -= 255; 50 | instruction.C -= 255; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpMove.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpMove : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Move; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]];"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpMul.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpMul : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Mul && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]*Stk[Inst[OP_C]];"; 13 | } 14 | 15 | public class OpMulB : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.Mul && instruction.B > 255 && instruction.C <= 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]*Stk[Inst[OP_C]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.B -= 255; 25 | } 26 | 27 | public class OpMulC : VOpcode 28 | { 29 | public override bool IsInstruction(Instruction instruction) => 30 | instruction.OpCode == Opcode.Mul && instruction.B <= 255 && instruction.C > 255; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]*Const[Inst[OP_C]];"; 34 | 35 | public override void Mutate(Instruction instruction) => 36 | instruction.C -= 255; 37 | } 38 | 39 | public class OpMulBC : VOpcode 40 | { 41 | public override bool IsInstruction(Instruction instruction) => 42 | instruction.OpCode == Opcode.Mul && instruction.B > 255 && instruction.C > 255; 43 | 44 | public override string GetObfuscated(ObfuscationContext context) => 45 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]*Const[Inst[OP_C]];"; 46 | 47 | public override void Mutate(Instruction instruction) 48 | { 49 | instruction.B -= 255; 50 | instruction.C -= 255; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpMutated.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using IronBrew2.Bytecode_Library.IR; 5 | 6 | namespace IronBrew2.Obfuscator.Opcodes 7 | { 8 | public class OpMutated : VOpcode 9 | { 10 | public static Random rand = new Random(); 11 | 12 | public VOpcode Mutated; 13 | public int[] Registers; 14 | 15 | public static string[] RegisterReplacements = {"OP__A", "OP__B", "OP__C"}; 16 | 17 | public override bool IsInstruction(Instruction instruction) => 18 | false; 19 | 20 | public bool CheckInstruction() => 21 | rand.Next(1, 15) == 1; 22 | 23 | public override string GetObfuscated(ObfuscationContext context) 24 | { 25 | return Mutated.GetObfuscated(context); 26 | } 27 | 28 | public override void Mutate(Instruction instruction) 29 | { 30 | Mutated.Mutate(instruction); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpNe.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpNe : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Eq && instruction.A != 0 && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "if(Stk[Inst[OP_A]]~=Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 13 | 14 | public override void Mutate(Instruction instruction) 15 | { 16 | instruction.A = instruction.B; 17 | 18 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 19 | instruction.InstructionType = InstructionType.AsBxC; 20 | } 21 | } 22 | 23 | public class OpNeB : VOpcode 24 | { 25 | public override bool IsInstruction(Instruction instruction) => 26 | instruction.OpCode == Opcode.Eq && instruction.A != 0 && instruction.B > 255 && instruction.C <= 255; 27 | 28 | public override string GetObfuscated(ObfuscationContext context) => 29 | "if(Const[Inst[OP_A]]~=Stk[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 30 | 31 | public override void Mutate(Instruction instruction) 32 | { 33 | instruction.A = instruction.B - 255; 34 | 35 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 36 | instruction.InstructionType = InstructionType.AsBxC; 37 | } 38 | } 39 | 40 | public class OpNeC : VOpcode 41 | { 42 | public override bool IsInstruction(Instruction instruction) => 43 | instruction.OpCode == Opcode.Eq && instruction.A != 0 && instruction.B <= 255 && instruction.C > 255; 44 | 45 | public override string GetObfuscated(ObfuscationContext context) => 46 | "if(Stk[Inst[OP_A]]~=Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 47 | 48 | public override void Mutate(Instruction instruction) 49 | { 50 | instruction.A = instruction.B; 51 | instruction.C -= 255; 52 | 53 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 54 | instruction.InstructionType = InstructionType.AsBxC; 55 | } 56 | } 57 | 58 | public class OpNeBC : VOpcode 59 | { 60 | public override bool IsInstruction(Instruction instruction) => 61 | instruction.OpCode == Opcode.Eq && instruction.A != 0 && instruction.B > 255 && instruction.C > 255; 62 | 63 | public override string GetObfuscated(ObfuscationContext context) => 64 | "if(Const[Inst[OP_A]]~=Const[Inst[OP_C]])then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 65 | 66 | public override void Mutate(Instruction instruction) 67 | { 68 | instruction.A = instruction.B - 255; 69 | instruction.C -= 255; 70 | 71 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 72 | instruction.InstructionType = InstructionType.AsBxC; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpNewStk.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpNewStk : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.NewStack; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk = {};for Idx = 0, PCount do if Idx < Params then Stk[Idx] = Args[Idx + 1]; else break end; end;"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpNewTable.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpNewTableB0 : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.NewTable && instruction.B == 0; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]={};"; 13 | } 14 | 15 | public class OpNewTableB5000 : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.NewTable && instruction.B > 5000; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]={};"; 22 | } 23 | 24 | public class OpNewTableBElse : VOpcode 25 | { 26 | public override bool IsInstruction(Instruction instruction) => 27 | instruction.OpCode == Opcode.NewTable && instruction.B > 0 && instruction.B <= 5000; 28 | 29 | public override string GetObfuscated(ObfuscationContext context) => 30 | "Stk[Inst[OP_A]]={unpack({}, 1, Inst[OP_B])};"; 31 | } 32 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpNot.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpNot : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Not; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=(not Stk[Inst[OP_B]]);"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpPow.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpPow : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Pow && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]^Stk[Inst[OP_C]];"; 13 | } 14 | 15 | public class OpPowB : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.Pow && instruction.B > 255 && instruction.C <= 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]^Stk[Inst[OP_C]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.B -= 255; 25 | } 26 | 27 | public class OpPowC : VOpcode 28 | { 29 | public override bool IsInstruction(Instruction instruction) => 30 | instruction.OpCode == Opcode.Pow && instruction.B <= 255 && instruction.C > 255; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]^Const[Inst[OP_C]];"; 34 | 35 | public override void Mutate(Instruction instruction) => 36 | instruction.C -= 255; 37 | } 38 | 39 | public class OpPowBC : VOpcode 40 | { 41 | public override bool IsInstruction(Instruction instruction) => 42 | instruction.OpCode == Opcode.Pow && instruction.B > 255 && instruction.C > 255; 43 | 44 | public override string GetObfuscated(ObfuscationContext context) => 45 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]^Const[Inst[OP_C]];"; 46 | 47 | public override void Mutate(Instruction instruction) 48 | { 49 | instruction.B -= 255; 50 | instruction.C -= 255; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpPushStk.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpPushStk : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.PushStack; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]] = Stk"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpReturn.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpReturn : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Return && instruction.B > 1; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local A=Inst[OP_A];local Limit=A+Inst[OP_B]-2;local Output={};local Edx=0;for Idx=A,Limit do Edx=Edx+1;Output[Edx]=Stk[Idx];end; do return Unpack(Output,1,Edx) end;"; 13 | } 14 | 15 | public class OpReturnB0 : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.Return && instruction.B == 0; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "local A=Inst[OP_A];local Limit=Top;local Output={};local Edx=0;for Idx=A,Limit do Edx=Edx+1;Output[Edx]=Stk[Idx];end;do return Unpack(Output,1,Edx) end;"; 22 | } 23 | 24 | public class OpReturnB1 : VOpcode 25 | { 26 | public override bool IsInstruction(Instruction instruction) => 27 | instruction.OpCode == Opcode.Return && instruction.B == 1; 28 | 29 | public override string GetObfuscated(ObfuscationContext context) => 30 | "do return end;"; 31 | } 32 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSelf.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpSelf : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Self && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local A=Inst[OP_A];local B=Stk[Inst[OP_B]];Stk[A+1]=B;Stk[A]=B[Stk[Inst[OP_C]]];"; 13 | } 14 | 15 | public class OpSelfC : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction)=> 18 | instruction.OpCode == Opcode.Self && instruction.C > 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "local A=Inst[OP_A];local B=Stk[Inst[OP_B]];Stk[A+1]=B;Stk[A]=B[Const[Inst[OP_C]]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.C -= 255; 25 | } 26 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSetFEnv.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpSetFEnv : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.SetFenv; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Env = Stk[Inst[OP_A]]"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSetGlobal.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpSetGlobal : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.SetGlobal; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Env[Const[Inst[OP_B]]]=Stk[Inst[OP_A]];"; 13 | 14 | public override void Mutate(Instruction instruction) => 15 | instruction.B++; 16 | } 17 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSetList.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpSetList : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.SetList && instruction.B != 0 && 10 | instruction.C > 1; 11 | 12 | public override string GetObfuscated(ObfuscationContext context) => 13 | "local A=Inst[OP_A];local Offset=(Inst[OP_C]-1)*50;local T=Stk[A];local B=Inst[OP_B];for Idx=1,B do T[Offset+Idx]=Stk[A+Idx] end;"; 14 | } 15 | 16 | public class OpSetListC1 : VOpcode 17 | { 18 | public override bool IsInstruction(Instruction instruction) => 19 | instruction.OpCode == Opcode.SetList && instruction.B != 0 && 20 | instruction.C == 1; 21 | 22 | public override string GetObfuscated(ObfuscationContext context) => 23 | "local A=Inst[OP_A];local T=Stk[A];local B=Inst[OP_B];for Idx=1,B do T[Idx]=Stk[A+Idx] end;"; 24 | } 25 | 26 | public class OpSetListB0 : VOpcode 27 | { 28 | public override bool IsInstruction(Instruction instruction) => 29 | instruction.OpCode == Opcode.SetList && instruction.B == 0 && 30 | instruction.C != 0; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "local A=Inst[OP_A];local Offset=(Inst[OP_C]-1)*50;local T=Stk[A];local X=Top-A;for Idx=1,X do T[Offset+Idx]=Stk[A+Idx] end;"; 34 | } 35 | 36 | public class OpSetListC0 : VOpcode 37 | { 38 | public override bool IsInstruction(Instruction instruction) => 39 | instruction.OpCode == Opcode.SetList && instruction.B != 0 && 40 | instruction.C == 0; 41 | 42 | public override string GetObfuscated(ObfuscationContext context) => 43 | "local A=Inst[OP_A];InstrPoint=InstrPoint+1;local Offset=(Instr[InstrPoint][5]-1)*50;local T=Stk[A];local B=Inst[OP_B];for Idx=1,B do T[Offset+Idx]=Stk[A+Idx] end;"; 44 | } 45 | 46 | public class OpSetListB0C0 : VOpcode 47 | { 48 | public override bool IsInstruction(Instruction instruction) => 49 | instruction.OpCode == Opcode.SetList && instruction.B == 0 && 50 | instruction.C == 0; 51 | 52 | public override string GetObfuscated(ObfuscationContext context) => 53 | "local A=Inst[OP_A];InstrPoint=InstrPoint+1;local Offset=(Instr[InstrPoint][5]-1)*50;local T=Stk[A];local X=Top-A;for Idx=1,X do T[Offset+Idx]=Stk[A+Idx] end;"; 54 | } 55 | 56 | public class OpSetListB0C1 : VOpcode 57 | { 58 | public override bool IsInstruction(Instruction instruction) => 59 | instruction.OpCode == Opcode.SetList && instruction.B == 0 && 60 | instruction.C == 1; 61 | 62 | public override string GetObfuscated(ObfuscationContext context) => 63 | "local A=Inst[OP_A];local T=Stk[A];local X=Top-A;for Idx=1,X do T[Idx]=Stk[A+Idx] end;"; 64 | } 65 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSetTable.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpSetTable : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.SetTable && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]][Stk[Inst[OP_B]]]=Stk[Inst[OP_C]];"; 13 | } 14 | 15 | public class OpSetTableB : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.SetTable && instruction.B > 255 && instruction.C <= 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]][Const[Inst[OP_B]]]=Stk[Inst[OP_C]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.B -= 255; 25 | } 26 | 27 | public class OpSetTableC : VOpcode 28 | { 29 | public override bool IsInstruction(Instruction instruction) => 30 | instruction.OpCode == Opcode.SetTable && instruction.B <= 255 && instruction.C > 255; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "Stk[Inst[OP_A]][Stk[Inst[OP_B]]]=Const[Inst[OP_C]];"; 34 | 35 | public override void Mutate(Instruction instruction) => 36 | instruction.C -= 255; 37 | } 38 | 39 | public class OpSetTableBC : VOpcode 40 | { 41 | public override bool IsInstruction(Instruction instruction) => 42 | instruction.OpCode == Opcode.SetTable && instruction.B > 255 && instruction.C > 255; 43 | 44 | public override string GetObfuscated(ObfuscationContext context) => 45 | "Stk[Inst[OP_A]][Const[Inst[OP_B]]]=Const[Inst[OP_C]];"; 46 | 47 | public override void Mutate(Instruction instruction) 48 | { 49 | instruction.B -= 255; 50 | instruction.C -= 255; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSetTop.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | //custom VM opcode for inlining 7 | public class OpSetTop : VOpcode 8 | { 9 | public override bool IsInstruction(Instruction instruction) => 10 | instruction.OpCode == Opcode.SetTop; 11 | 12 | public override string GetObfuscated(ObfuscationContext context) => 13 | "Top=Inst[OP_A];"; 14 | } 15 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSetUpval.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpSetUpval : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.SetUpval; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Upvalues[Inst[OP_B]]=Stk[Inst[OP_A]];"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSub.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpSub : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Sub && instruction.B <= 255 && instruction.C <= 255; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]-Stk[Inst[OP_C]];"; 13 | } 14 | 15 | public class OpSubB : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.Sub && instruction.B > 255 && instruction.C <= 255; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]-Stk[Inst[OP_C]];"; 22 | 23 | public override void Mutate(Instruction instruction) => 24 | instruction.B -= 255; 25 | } 26 | 27 | public class OpSubC : VOpcode 28 | { 29 | public override bool IsInstruction(Instruction instruction) => 30 | instruction.OpCode == Opcode.Sub && instruction.B <= 255 && instruction.C > 255; 31 | 32 | public override string GetObfuscated(ObfuscationContext context) => 33 | "Stk[Inst[OP_A]]=Stk[Inst[OP_B]]-Const[Inst[OP_C]];"; 34 | 35 | public override void Mutate(Instruction instruction) => 36 | instruction.C -= 255; 37 | } 38 | 39 | public class OpSubBC : VOpcode 40 | { 41 | public override bool IsInstruction(Instruction instruction) => 42 | instruction.OpCode == Opcode.Sub && instruction.B > 255 && instruction.C > 255; 43 | 44 | public override string GetObfuscated(ObfuscationContext context) => 45 | "Stk[Inst[OP_A]]=Const[Inst[OP_B]]-Const[Inst[OP_C]];"; 46 | 47 | public override void Mutate(Instruction instruction) 48 | { 49 | instruction.B -= 255; 50 | instruction.C -= 255; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpSuperOperator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using IronBrew2.Bytecode_Library.IR; 6 | 7 | namespace IronBrew2.Obfuscator.Opcodes 8 | { 9 | public class OpSuperOperator : VOpcode 10 | { 11 | public VOpcode[] SubOpcodes; 12 | 13 | public override bool IsInstruction(Instruction instruction) => 14 | false; 15 | 16 | public bool IsInstruction(List instructions) 17 | { 18 | if (instructions.Count != SubOpcodes.Length) 19 | return false; 20 | 21 | for (int i = 0; i < SubOpcodes.Length; i++) 22 | { 23 | if (SubOpcodes[i] is OpMutated mut) 24 | { 25 | if (!mut.Mutated.IsInstruction(instructions[i])) 26 | return false; 27 | } 28 | 29 | else if (!SubOpcodes[i].IsInstruction(instructions[i])) 30 | return false; 31 | } 32 | 33 | return true; 34 | } 35 | 36 | public override string GetObfuscated(ObfuscationContext context) 37 | { 38 | string s = ""; 39 | List locals = new List(); 40 | 41 | for (var index = 0; index < SubOpcodes.Length; index++) 42 | { 43 | var subOpcode = SubOpcodes[index]; 44 | string s2 = subOpcode.GetObfuscated(context); 45 | 46 | Regex reg = new Regex("local(.*?)[;=]"); 47 | foreach (Match m in reg.Matches(s2)) 48 | { 49 | string loc = m.Groups[1].Value.Replace(" ", ""); 50 | if (!locals.Contains(loc)) 51 | locals.Add(loc); 52 | 53 | if (!m.Value.Contains(";")) 54 | s2 = s2.Replace($"local{m.Groups[1].Value}", loc); 55 | else 56 | s2 = s2.Replace($"local{m.Groups[1].Value};", ""); 57 | } 58 | 59 | s += s2; 60 | 61 | if (index + 1 < SubOpcodes.Length) 62 | s += "InstrPoint = InstrPoint + 1;Inst = Instr[InstrPoint];"; 63 | } 64 | 65 | foreach (string l in locals) 66 | s = "local " + l + ';' + s; 67 | 68 | return s; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpTForLoop.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpTForLoop : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.TForLoop; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local A=Inst[OP_A];local C=Inst[OP_C];local Offset=A+2;local Result={Stk[A](Stk[A+1],Stk[Offset])};for Idx=1,C do Stk[Offset+Idx]=Result[Idx];end;local R=Stk[A+3];if R then Stk[Offset]=R else InstrPoint=InstrPoint+1;end;"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpTailCall.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpTailCall : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.TailCall && instruction.B > 1; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local A=Inst[OP_A];local Args={};local Limit=A+Inst[OP_B]-1;for Idx=A+1,Limit do Args[#Args+1]=Stk[Idx];end;do return Stk[A](Unpack(Args,1,Limit-A)) end;"; 13 | } 14 | 15 | public class OpTailCallB0 : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.TailCall && instruction.B == 0; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "local A=Inst[OP_A];local Args={};local Limit=Top;for Idx=A+1,Limit do Args[#Args+1]=Stk[Idx];end;do return Stk[A](Unpack(Args,1,Limit-A)) end;"; 22 | } 23 | 24 | public class OpTailCallB1 : VOpcode 25 | { 26 | public override bool IsInstruction(Instruction instruction) => 27 | instruction.OpCode == Opcode.TailCall && instruction.B == 1; 28 | 29 | public override string GetObfuscated(ObfuscationContext context) => 30 | "local A=Inst[OP_A];do return Stk[A](); end;"; 31 | } 32 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpTest.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpTest : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Test && instruction.C == 0; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "if Stk[Inst[OP_A]] then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 13 | 14 | public override void Mutate(Instruction instruction) 15 | { 16 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 17 | instruction.InstructionType = InstructionType.AsBxC; 18 | } 19 | } 20 | 21 | public class OpTestC : VOpcode 22 | { 23 | public override bool IsInstruction(Instruction instruction) => 24 | instruction.OpCode == Opcode.Test && instruction.C != 0; 25 | 26 | public override string GetObfuscated(ObfuscationContext context) => 27 | "if not Stk[Inst[OP_A]] then InstrPoint=InstrPoint+1;else InstrPoint=InstrPoint+Inst[OP_B];end;"; 28 | 29 | public override void Mutate(Instruction instruction) 30 | { 31 | instruction.B = instruction.Chunk.Instructions[instruction.PC + 1].B + 1; 32 | instruction.InstructionType = InstructionType.AsBxC; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpTestSet.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpTestSet : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.TestSet && instruction.C == 0; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local B=Stk[Inst[OP_B]];if B then InstrPoint=InstrPoint+1;else Stk[Inst[OP_A]]=B;InstrPoint=InstrPoint+Instr[InstrPoint+1][OP_B]+1;end;"; 13 | } 14 | 15 | public class OpTestSetC : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.TestSet && instruction.C != 0; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "local B=Stk[Inst[OP_B]];if not B then InstrPoint=InstrPoint+1;else Stk[Inst[OP_A]]=B;InstrPoint=InstrPoint+Instr[InstrPoint+1][OP_B]+1;end;"; 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpUnm.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpUnm : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.Unm; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "Stk[Inst[OP_A]]=-Stk[Inst[OP_B]];"; 13 | } 14 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/Opcodes/OpVarArg.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.Bytecode; 2 | using IronBrew2.Bytecode_Library.IR; 3 | 4 | namespace IronBrew2.Obfuscator.Opcodes 5 | { 6 | public class OpVarArg : VOpcode 7 | { 8 | public override bool IsInstruction(Instruction instruction) => 9 | instruction.OpCode == Opcode.VarArg && instruction.B != 0; 10 | 11 | public override string GetObfuscated(ObfuscationContext context) => 12 | "local A=Inst[OP_A];local B=Inst[OP_B];for Idx=A,A+B-1 do Stk[Idx]=Vararg[Idx-A];end;"; 13 | } 14 | 15 | public class OpVarArgB0 : VOpcode 16 | { 17 | public override bool IsInstruction(Instruction instruction) => 18 | instruction.OpCode == Opcode.VarArg && instruction.B == 0; 19 | 20 | public override string GetObfuscated(ObfuscationContext context) => 21 | "local A=Inst[OP_A];Top=A+Varargsz-1;for Idx=A,Top do local VA=Vararg[Idx-A];Stk[Idx]=VA;end;"; 22 | } 23 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/VM Generation/Generator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Reflection.Emit; 7 | using System.Text; 8 | using IronBrew2.Bytecode_Library.Bytecode; 9 | using IronBrew2.Bytecode_Library.IR; 10 | using IronBrew2.Extensions; 11 | using IronBrew2.Obfuscator.Opcodes; 12 | 13 | namespace IronBrew2.Obfuscator.VM_Generation 14 | { 15 | public class Generator 16 | { 17 | private ObfuscationContext _context; 18 | 19 | public Generator(ObfuscationContext context) => 20 | _context = context; 21 | 22 | public bool IsUsed(Chunk chunk, VOpcode virt) 23 | { 24 | bool isUsed = false; 25 | foreach (Instruction ins in chunk.Instructions) 26 | if (virt.IsInstruction(ins)) 27 | { 28 | if (!_context.InstructionMapping.ContainsKey(ins.OpCode)) 29 | _context.InstructionMapping.Add(ins.OpCode, virt); 30 | 31 | ins.CustomData = new CustomInstructionData {Opcode = virt}; 32 | isUsed = true; 33 | } 34 | 35 | foreach (Chunk sChunk in chunk.Functions) 36 | isUsed |= IsUsed(sChunk, virt); 37 | 38 | return isUsed; 39 | } 40 | 41 | public static List Compress(byte[] uncompressed) 42 | { 43 | // build the dictionary 44 | Dictionary dictionary = new Dictionary(); 45 | for (int i = 0; i < 256; i++) 46 | dictionary.Add(((char)i).ToString(), i); 47 | 48 | string w = string.Empty; 49 | List compressed = new List(); 50 | 51 | foreach (byte b in uncompressed) 52 | { 53 | string wc = w + (char)b; 54 | if (dictionary.ContainsKey(wc)) 55 | w = wc; 56 | 57 | else 58 | { 59 | // write w to output 60 | compressed.Add(dictionary[w]); 61 | // wc is a new sequence; add it to the dictionary 62 | dictionary.Add(wc, dictionary.Count); 63 | w = ((char) b).ToString(); 64 | } 65 | } 66 | 67 | // write remaining output if necessary 68 | if (!string.IsNullOrEmpty(w)) 69 | compressed.Add(dictionary[w]); 70 | 71 | return compressed; 72 | } 73 | 74 | public static string ToBase36(ulong value) 75 | { 76 | const string base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 77 | var sb = new StringBuilder(13); 78 | do 79 | { 80 | sb.Insert(0, base36[(byte)(value % 36)]); 81 | value /= 36; 82 | } while (value != 0); 83 | return sb.ToString(); 84 | } 85 | 86 | public static string CompressedToString(List compressed) 87 | { 88 | StringBuilder sb = new StringBuilder(); 89 | foreach (int i in compressed) 90 | { 91 | string n = ToBase36((ulong)i); 92 | 93 | sb.Append(ToBase36((ulong)n.Length)); 94 | sb.Append(n); 95 | } 96 | 97 | return sb.ToString(); 98 | } 99 | 100 | public List GenerateMutations(List opcodes) 101 | { 102 | Random r = new Random(); 103 | List mutated = new List(); 104 | 105 | foreach (VOpcode opc in opcodes) 106 | { 107 | if (opc is OpSuperOperator) 108 | continue; 109 | 110 | for (int i = 0; i < r.Next(35, 50); i++) 111 | { 112 | int[] rand = {0, 1, 2}; 113 | rand.Shuffle(); 114 | 115 | OpMutated mut = new OpMutated(); 116 | 117 | mut.Registers = rand; 118 | mut.Mutated = opc; 119 | 120 | mutated.Add(mut); 121 | } 122 | } 123 | 124 | mutated.Shuffle(); 125 | return mutated; 126 | } 127 | 128 | public void FoldMutations(List mutations, HashSet used, Chunk chunk) 129 | { 130 | bool[] skip = new bool[chunk.Instructions.Count + 1]; 131 | 132 | for (int i = 0; i < chunk.Instructions.Count; i++) 133 | { 134 | Instruction opc = chunk.Instructions[i]; 135 | 136 | switch (opc.OpCode) 137 | { 138 | case Opcode.Closure: 139 | for (int j = 1; j <= ((Chunk) opc.RefOperands[0]).UpvalueCount; j++) 140 | skip[i + j] = true; 141 | 142 | break; 143 | } 144 | } 145 | 146 | for (int i = 0; i < chunk.Instructions.Count; i++) 147 | { 148 | if (skip[i]) 149 | continue; 150 | 151 | Instruction opc = chunk.Instructions[i]; 152 | CustomInstructionData data = opc.CustomData; 153 | 154 | foreach (OpMutated mut in mutations) 155 | if (data.Opcode == mut.Mutated && data.WrittenOpcode == null) 156 | { 157 | if (!used.Contains(mut)) 158 | used.Add(mut); 159 | 160 | data.Opcode = mut; 161 | break; 162 | } 163 | } 164 | 165 | foreach (Chunk _c in chunk.Functions) 166 | FoldMutations(mutations, used, _c); 167 | } 168 | 169 | public List GenerateSuperOperators(Chunk chunk, int maxSize, int minSize = 5) 170 | { 171 | List results = new List(); 172 | Random r = new Random(); 173 | 174 | bool[] skip = new bool[chunk.Instructions.Count + 1]; 175 | 176 | for (int i = 0; i < chunk.Instructions.Count - 1; i++) 177 | { 178 | switch (chunk.Instructions[i].OpCode) 179 | { 180 | case Opcode.Closure: 181 | { 182 | skip[i] = true; 183 | for (int j = 0; j < ((Chunk) chunk.Instructions[i].RefOperands[0]).UpvalueCount; j++) 184 | skip[i + j + 1] = true; 185 | 186 | break; 187 | } 188 | 189 | case Opcode.Eq: 190 | case Opcode.Lt: 191 | case Opcode.Le: 192 | case Opcode.Test: 193 | case Opcode.TestSet: 194 | case Opcode.TForLoop: 195 | case Opcode.SetList: 196 | case Opcode.LoadBool when chunk.Instructions[i].C != 0: 197 | skip[i + 1] = true; 198 | break; 199 | 200 | case Opcode.ForLoop: 201 | case Opcode.ForPrep: 202 | case Opcode.Jmp: 203 | chunk.Instructions[i].UpdateRegisters(); 204 | 205 | skip[i + 1] = true; 206 | skip[i + chunk.Instructions[i].B + 1] = true; 207 | break; 208 | } 209 | 210 | if (chunk.Instructions[i].CustomData.WrittenOpcode is OpSuperOperator su && su.SubOpcodes != null) 211 | for (int j = 0; j < su.SubOpcodes.Length; j++) 212 | skip[i + j] = true; 213 | } 214 | 215 | int c = 0; 216 | while (c < chunk.Instructions.Count) 217 | { 218 | int targetCount = maxSize; 219 | OpSuperOperator superOperator = new OpSuperOperator {SubOpcodes = new VOpcode[targetCount]}; 220 | 221 | bool d = true; 222 | int cutoff = targetCount; 223 | 224 | for (int j = 0; j < targetCount; j++) 225 | if (c + j > chunk.Instructions.Count - 1 || skip[c + j]) 226 | { 227 | cutoff = j; 228 | d = false; 229 | break; 230 | } 231 | 232 | if (!d) 233 | { 234 | if (cutoff < minSize) 235 | { 236 | c += cutoff + 1; 237 | continue; 238 | } 239 | 240 | targetCount = cutoff; 241 | superOperator = new OpSuperOperator {SubOpcodes = new VOpcode[targetCount]}; 242 | } 243 | 244 | for (int j = 0; j < targetCount; j++) 245 | superOperator.SubOpcodes[j] = 246 | chunk.Instructions[c + j].CustomData.Opcode; 247 | 248 | results.Add(superOperator); 249 | c += targetCount + 1; 250 | } 251 | 252 | foreach (var _c in chunk.Functions) 253 | results.AddRange(GenerateSuperOperators(_c, maxSize)); 254 | 255 | return results; 256 | } 257 | 258 | public void FoldAdditionalSuperOperators(Chunk chunk, List operators, ref int folded) 259 | { 260 | bool[] skip = new bool[chunk.Instructions.Count + 1]; 261 | for (int i = 0; i < chunk.Instructions.Count - 1; i++) 262 | { 263 | switch (chunk.Instructions[i].OpCode) 264 | { 265 | case Opcode.Closure: 266 | { 267 | skip[i] = true; 268 | for (int j = 0; j < ((Chunk) chunk.Instructions[i].RefOperands[0]).UpvalueCount; j++) 269 | skip[i + j + 1] = true; 270 | 271 | break; 272 | } 273 | 274 | case Opcode.Eq: 275 | case Opcode.Lt: 276 | case Opcode.Le: 277 | case Opcode.Test: 278 | case Opcode.TestSet: 279 | case Opcode.TForLoop: 280 | case Opcode.SetList: 281 | case Opcode.LoadBool when chunk.Instructions[i].C != 0: 282 | skip[i + 1] = true; 283 | break; 284 | 285 | case Opcode.ForLoop: 286 | case Opcode.ForPrep: 287 | case Opcode.Jmp: 288 | chunk.Instructions[i].UpdateRegisters(); 289 | skip[i + 1] = true; 290 | skip[i + chunk.Instructions[i].B + 1] = true; 291 | break; 292 | } 293 | 294 | if (chunk.Instructions[i].CustomData.WrittenOpcode is OpSuperOperator su && su.SubOpcodes != null) 295 | for (int j = 0; j < su.SubOpcodes.Length; j++) 296 | skip[i + j] = true; 297 | } 298 | 299 | int c = 0; 300 | while (c < chunk.Instructions.Count) 301 | { 302 | if (skip[c]) 303 | { 304 | c++; 305 | continue; 306 | } 307 | 308 | bool used = false; 309 | 310 | foreach (OpSuperOperator op in operators) 311 | { 312 | int targetCount = op.SubOpcodes.Length; 313 | bool cu = true; 314 | for (int j = 0; j < targetCount; j++) 315 | { 316 | if (c + j > chunk.Instructions.Count - 1 || skip[c + j]) 317 | { 318 | cu = false; 319 | break; 320 | } 321 | } 322 | 323 | if (!cu) 324 | continue; 325 | 326 | 327 | List taken = chunk.Instructions.Skip(c).Take(targetCount).ToList(); 328 | if (op.IsInstruction(taken)) 329 | { 330 | for (int j = 0; j < targetCount; j++) 331 | { 332 | skip[c + j] = true; 333 | chunk.Instructions[c + j].CustomData.WrittenOpcode = new OpSuperOperator {VIndex = 0}; 334 | } 335 | 336 | chunk.Instructions[c].CustomData.WrittenOpcode = op; 337 | 338 | used = true; 339 | break; 340 | } 341 | } 342 | 343 | if (!used) 344 | c++; 345 | else 346 | folded++; 347 | } 348 | 349 | foreach (var _c in chunk.Functions) 350 | FoldAdditionalSuperOperators(_c, operators, ref folded); 351 | } 352 | 353 | public string GenerateVM(ObfuscationSettings settings) 354 | { 355 | Random r = new Random(); 356 | 357 | List virtuals = Assembly.GetExecutingAssembly().GetTypes() 358 | .Where(t => t.IsSubclassOf(typeof(VOpcode))) 359 | .Select(Activator.CreateInstance) 360 | .Cast() 361 | .Where(t => IsUsed(_context.HeadChunk, t)) 362 | .ToList(); 363 | 364 | 365 | if (settings.Mutate) 366 | { 367 | List muts = GenerateMutations(virtuals).Take(settings.MaxMutations).ToList(); 368 | 369 | Console.WriteLine("Created " + muts.Count + " mutations."); 370 | 371 | HashSet used = new HashSet(); 372 | FoldMutations(muts, used, _context.HeadChunk); 373 | 374 | Console.WriteLine("Used " + used.Count + " mutations."); 375 | 376 | virtuals.AddRange(used); 377 | } 378 | 379 | if (settings.SuperOperators) 380 | { 381 | int folded = 0; 382 | 383 | var megaOperators = GenerateSuperOperators(_context.HeadChunk, 80, 60).OrderBy(t => r.Next()) 384 | .Take(settings.MaxMegaSuperOperators).ToList(); 385 | 386 | Console.WriteLine("Created " + megaOperators.Count + " mega super operators."); 387 | 388 | virtuals.AddRange(megaOperators); 389 | 390 | FoldAdditionalSuperOperators(_context.HeadChunk, megaOperators, ref folded); 391 | 392 | var miniOperators = GenerateSuperOperators(_context.HeadChunk, 10).OrderBy(t => r.Next()) 393 | .Take(settings.MaxMiniSuperOperators).ToList(); 394 | 395 | Console.WriteLine("Created " + miniOperators.Count + " mini super operators."); 396 | 397 | virtuals.AddRange(miniOperators); 398 | 399 | FoldAdditionalSuperOperators(_context.HeadChunk, miniOperators, ref folded); 400 | 401 | Console.WriteLine("Folded " + folded + " instructions into super operators."); 402 | } 403 | 404 | virtuals.Shuffle(); 405 | 406 | for (int i = 0; i < virtuals.Count; i++) 407 | virtuals[i].VIndex = i; 408 | 409 | string vm = ""; 410 | 411 | byte[] bs = new Serializer(_context, settings).SerializeLChunk(_context.HeadChunk); 412 | 413 | vm += @" 414 | local Byte = string.byte; 415 | local Char = string.char; 416 | local Sub = string.sub; 417 | local Concat = table.concat; 418 | local LDExp = math.ldexp; 419 | local GetFEnv = getfenv or function() return _ENV end; 420 | local Setmetatable = setmetatable; 421 | local Select = select; 422 | 423 | local Unpack = unpack; 424 | local ToNumber = tonumber;"; 425 | 426 | if (settings.BytecodeCompress) 427 | { 428 | vm += "local function decompress(b)local c,d,e=\"\",\"\",{}local f=256;local g={}for h=0,f-1 do g[h]=Char(h)end;local i=1;local function k()local l=ToNumber(Sub(b, i,i),36)i=i+1;local m=ToNumber(Sub(b, i,i+l-1),36)i=i+l;return m end;c=Char(k())e[1]=c;while i<#b do local n=k()if g[n]then d=g[n]else d=c..Sub(c, 1,1)end;g[f]=c..Sub(d, 1,1)e[#e+1],c,f=d,d,f+1 end;return table.concat(e)end;"; 429 | vm += "local ByteString=decompress('" + CompressedToString(Compress(bs)) + "');\n"; 430 | } 431 | else 432 | { 433 | vm += "ByteString='"; 434 | 435 | StringBuilder sb = new StringBuilder(); 436 | foreach (byte b in bs) 437 | { 438 | sb.Append('\\'); 439 | sb.Append(b); 440 | } 441 | 442 | vm += sb + "';\n"; 443 | } 444 | 445 | int maxConstants = 0; 446 | 447 | void ComputeConstants(Chunk c) 448 | { 449 | if (c.Constants.Count > maxConstants) 450 | maxConstants = c.Constants.Count; 451 | 452 | foreach (Chunk _c in c.Functions) 453 | ComputeConstants(_c); 454 | } 455 | 456 | ComputeConstants(_context.HeadChunk); 457 | 458 | vm += VMStrings.VMP1.Replace("XOR_KEY", _context.PrimaryXorKey.ToString()); 459 | 460 | for (int i = 0; i < (int) ChunkStep.StepCount; i++) 461 | { 462 | switch (_context.ChunkSteps[i]) 463 | { 464 | case ChunkStep.ParameterCount: 465 | vm += "Chunk[4] = gBits8();"; 466 | break; 467 | case ChunkStep.Constants: 468 | vm += 469 | $@" 470 | local ConstCount = gBits32() 471 | local Consts = {{{string.Join(",", Enumerable.Repeat(0, maxConstants).Select(x => "0"))}}}; 472 | 473 | for Idx=1,ConstCount do 474 | local Type=gBits8(); 475 | local Cons; 476 | 477 | if(Type=={_context.ConstantMapping[1]}) then Cons=(gBits8() ~= 0); 478 | elseif(Type=={_context.ConstantMapping[2]}) then Cons = gFloat(); 479 | elseif(Type=={_context.ConstantMapping[3]}) then Cons=gString(); 480 | end; 481 | 482 | Consts[Idx]=Cons; 483 | end; 484 | Chunk[2] = Consts 485 | "; 486 | break; 487 | case ChunkStep.Instructions: 488 | vm += 489 | $@"for Idx=1,gBits32() do 490 | local Data1=BitXOR(gBits32(),{_context.IXorKey1}); 491 | local Data2=BitXOR(gBits32(),{_context.IXorKey2}); 492 | 493 | local Type=gBit(Data1,1,2); 494 | local Opco=gBit(Data2,1,11); 495 | 496 | local Inst= 497 | {{ 498 | Opco, 499 | gBit(Data1,3,11), 500 | nil, 501 | nil, 502 | Data2 503 | }}; 504 | 505 | if (Type == 0) then Inst[OP_B]=gBit(Data1,12,20);Inst[OP_C]=gBit(Data1,21,29); 506 | elseif(Type==1) then Inst[OP_B]=gBit(Data2,12,33); 507 | elseif(Type==2) then Inst[OP_B]=gBit(Data2,12,32)-1048575; 508 | elseif(Type==3) then Inst[OP_B]=gBit(Data2,12,32)-1048575;Inst[OP_C]=gBit(Data1,21,29); 509 | end; 510 | 511 | Instrs[Idx]=Inst;end;"; 512 | break; 513 | case ChunkStep.Functions: 514 | vm += "for Idx=1,gBits32() do Functions[Idx-1]=Deserialize();end;"; 515 | break; 516 | case ChunkStep.LineInfo: 517 | if (settings.PreserveLineInfo) 518 | vm += "for Idx=1,gBits32() do Lines[Idx]=gBits32();end;"; 519 | break; 520 | } 521 | } 522 | 523 | vm += "return Chunk;end;"; 524 | vm += settings.PreserveLineInfo ? VMStrings.VMP2_LI : VMStrings.VMP2; 525 | 526 | int maxFunc = 0; 527 | 528 | void ComputeFuncs(Chunk c) 529 | { 530 | if (c.Functions.Count > maxFunc) 531 | maxFunc = c.Functions.Count; 532 | 533 | foreach (Chunk _c in c.Functions) 534 | ComputeFuncs(_c); 535 | } 536 | 537 | ComputeFuncs(_context.HeadChunk); 538 | 539 | vm = vm.Replace("FUNC_CNT", string.Join(",", Enumerable.Repeat(0, maxFunc).Select(x => "0"))); 540 | 541 | int maxInstrs = 0; 542 | 543 | void ComputeInstrs(Chunk c) 544 | { 545 | if (c.Instructions.Count > maxInstrs) 546 | maxInstrs = c.Instructions.Count; 547 | 548 | foreach (Chunk _c in c.Functions) 549 | ComputeInstrs(_c); 550 | } 551 | 552 | ComputeInstrs(_context.HeadChunk); 553 | 554 | vm = vm.Replace("INSTR_CNT", string.Join(",", Enumerable.Repeat(0, maxInstrs).Select(x => "0"))); 555 | 556 | string GetStr(List opcodes) 557 | { 558 | string str = ""; 559 | 560 | if (opcodes.Count == 1) 561 | str += $"{virtuals[opcodes[0]].GetObfuscated(_context)}"; 562 | 563 | else if (opcodes.Count == 2) 564 | { 565 | if (r.Next(2) == 0) 566 | { 567 | str += 568 | $"if Enum > {virtuals[opcodes[0]].VIndex} then {virtuals[opcodes[1]].GetObfuscated(_context)}"; 569 | str += $"else {virtuals[opcodes[0]].GetObfuscated(_context)}"; 570 | str += "end;"; 571 | } 572 | else 573 | { 574 | str += 575 | $"if Enum == {virtuals[opcodes[0]].VIndex} then {virtuals[opcodes[0]].GetObfuscated(_context)}"; 576 | str += $"else {virtuals[opcodes[1]].GetObfuscated(_context)}"; 577 | str += "end;"; 578 | } 579 | } 580 | else 581 | { 582 | List ordered = opcodes.OrderBy(o => o).ToList(); 583 | var sorted = new[] { ordered.Take(ordered.Count / 2).ToList(), ordered.Skip(ordered.Count / 2).ToList() }; 584 | 585 | str += "if Enum <= " + sorted[0].Last() + " then "; 586 | str += GetStr(sorted[0]); 587 | str += " else"; 588 | str += GetStr(sorted[1]); 589 | } 590 | 591 | return str; 592 | } 593 | 594 | vm += GetStr(Enumerable.Range(0, virtuals.Count).ToList()); 595 | vm += settings.PreserveLineInfo ? VMStrings.VMP3_LI : VMStrings.VMP3; 596 | 597 | vm = vm.Replace("OP_ENUM", "1") 598 | .Replace("OP_A", "2") 599 | .Replace("OP_B", "3") 600 | .Replace("OP_BX", "4") 601 | .Replace("OP_C", "5") 602 | .Replace("OP_DATA", "6"); 603 | 604 | 605 | return vm; 606 | } 607 | } 608 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/VM Generation/VMStrings.cs: -------------------------------------------------------------------------------- 1 | namespace IronBrew2.Obfuscator.VM_Generation 2 | { 3 | public static class VMStrings 4 | { 5 | public static string VMP1 = @" 6 | local BitXOR = bit and bit.bxor or function(a,b) 7 | local p,c=1,0 8 | while a>0 and b>0 do 9 | local ra,rb=a%2,b%2 10 | if ra~=rb then c=c+p end 11 | a,b,p=(a-ra)/2,(b-rb)/2,p*2 12 | end 13 | if a0 do 15 | local ra=a%2 16 | if ra>0 then c=c+p end 17 | a,p=(a-ra)/2,p*2 18 | end 19 | return c 20 | end 21 | 22 | local function gBit(Bit, Start, End) 23 | if End then 24 | local Res = (Bit / 2 ^ (Start - 1)) % 2 ^ ((End - 1) - (Start - 1) + 1); 25 | 26 | return Res - Res % 1; 27 | else 28 | local Plc = 2 ^ (Start - 1); 29 | 30 | return (Bit % (Plc + Plc) >= Plc) and 1 or 0; 31 | end; 32 | end; 33 | 34 | local Pos = 1; 35 | 36 | local function gBits32() 37 | local W, X, Y, Z = Byte(ByteString, Pos, Pos + 3); 38 | 39 | W = BitXOR(W, XOR_KEY) 40 | X = BitXOR(X, XOR_KEY) 41 | Y = BitXOR(Y, XOR_KEY) 42 | Z = BitXOR(Z, XOR_KEY) 43 | 44 | Pos = Pos + 4; 45 | return (Z*16777216) + (Y*65536) + (X*256) + W; 46 | end; 47 | 48 | local function gBits8() 49 | local F = BitXOR(Byte(ByteString, Pos, Pos), XOR_KEY); 50 | Pos = Pos + 1; 51 | return F; 52 | end; 53 | 54 | local function gFloat() 55 | local Left = gBits32(); 56 | local Right = gBits32(); 57 | local IsNormal = 1; 58 | local Mantissa = (gBit(Right, 1, 20) * (2 ^ 32)) 59 | + Left; 60 | local Exponent = gBit(Right, 21, 31); 61 | local Sign = ((-1) ^ gBit(Right, 32)); 62 | if (Exponent == 0) then 63 | if (Mantissa == 0) then 64 | return Sign * 0; -- +-0 65 | else 66 | Exponent = 1; 67 | IsNormal = 0; 68 | end; 69 | elseif (Exponent == 2047) then 70 | return (Mantissa == 0) and (Sign * (1 / 0)) or (Sign * (0 / 0)); 71 | end; 72 | return LDExp(Sign, Exponent - 1023) * (IsNormal + (Mantissa / (2 ^ 52))); 73 | end; 74 | 75 | local gSizet = gBits32; 76 | local function gString(Len) 77 | local Str; 78 | if (not Len) then 79 | Len = gSizet(); 80 | if (Len == 0) then 81 | return ''; 82 | end; 83 | end; 84 | 85 | Str = Sub(ByteString, Pos, Pos + Len - 1); 86 | Pos = Pos + Len; 87 | 88 | local FStr = {} 89 | for Idx = 1, #Str do 90 | FStr[Idx] = Char(BitXOR(Byte(Sub(Str, Idx, Idx)), XOR_KEY)) 91 | end 92 | 93 | return Concat(FStr); 94 | end; 95 | 96 | local gInt = gBits32; 97 | local function _R(...) return {...}, Select('#', ...) end 98 | 99 | local function Deserialize() 100 | local Instrs = { INSTR_CNT }; 101 | local Functions = { FUNC_CNT }; 102 | local Lines = {}; 103 | local Chunk = 104 | { 105 | Instrs, 106 | nil, 107 | Functions, 108 | nil, 109 | Lines 110 | };"; 111 | 112 | public static string VMP2 = @" 113 | local function Wrap(Chunk, Upvalues, Env) 114 | local Instr = Chunk[1]; 115 | local Const = Chunk[2]; 116 | local Proto = Chunk[3]; 117 | local Params = Chunk[4]; 118 | 119 | return function(...) 120 | local Instr = Instr; 121 | local Const = Const; 122 | local Proto = Proto; 123 | local Params = Params; 124 | 125 | local _R = _R 126 | local InstrPoint = 1; 127 | local Top = -1; 128 | 129 | local Vararg = {}; 130 | local Args = {...}; 131 | 132 | local PCount = Select('#', ...) - 1; 133 | 134 | local Lupvals = {}; 135 | local Stk = {}; 136 | 137 | for Idx = 0, PCount do 138 | if (Idx >= Params) then 139 | Vararg[Idx - Params] = Args[Idx + 1]; 140 | else 141 | Stk[Idx] = Args[Idx + 1]; 142 | end; 143 | end; 144 | 145 | local Varargsz = PCount - Params + 1 146 | 147 | local Inst; 148 | local Enum; 149 | 150 | while true do 151 | Inst = Instr[InstrPoint]; 152 | Enum = Inst[OP_ENUM];"; 153 | 154 | public static string VMP3 = @" 155 | InstrPoint = InstrPoint + 1; 156 | end; 157 | end; 158 | end; 159 | return Wrap(Deserialize(), {}, GetFEnv())(); 160 | "; 161 | public static string VMP2_LI = @" 162 | local PCall = pcall 163 | local function Wrap(Chunk, Upvalues, Env) 164 | local Instr = Chunk[1]; 165 | local Const = Chunk[2]; 166 | local Proto = Chunk[3]; 167 | local Params = Chunk[4]; 168 | 169 | return function(...) 170 | local InstrPoint = 1; 171 | local Top = -1; 172 | 173 | local Args = {...}; 174 | local PCount = Select('#', ...) - 1; 175 | 176 | local function Loop() 177 | local Instr = Instr; 178 | local Const = Const; 179 | local Proto = Proto; 180 | local Params = Params; 181 | 182 | local _R = _R 183 | local Vararg = {}; 184 | 185 | local Lupvals = {}; 186 | local Stk = {}; 187 | 188 | for Idx = 0, PCount do 189 | if (Idx >= Params) then 190 | Vararg[Idx - Params] = Args[Idx + 1]; 191 | else 192 | Stk[Idx] = Args[Idx + 1]; 193 | end; 194 | end; 195 | 196 | local Varargsz = PCount - Params + 1 197 | 198 | local Inst; 199 | local Enum; 200 | 201 | while true do 202 | Inst = Instr[InstrPoint]; 203 | Enum = Inst[OP_ENUM];"; 204 | 205 | public static string VMP3_LI = @" 206 | InstrPoint = InstrPoint + 1; 207 | end; 208 | end; 209 | 210 | A, B = _R(PCall(Loop)) 211 | if not A[1] then 212 | local line = Chunk[7][InstrPoint] or '?' 213 | error('ERROR IN IRONBREW SCRIPT [LINE ' .. line .. ']:' .. A[2]) 214 | else 215 | return Unpack(A, 2, B) 216 | end; 217 | end; 218 | end; 219 | return Wrap(Deserialize(), {}, GetFEnv())(); 220 | "; 221 | } 222 | } -------------------------------------------------------------------------------- /IronBrew2/Obfuscator/VOpcode.cs: -------------------------------------------------------------------------------- 1 | using IronBrew2.Bytecode_Library.IR; 2 | 3 | namespace IronBrew2.Obfuscator 4 | { 5 | public abstract class VOpcode 6 | { 7 | public int VIndex; 8 | 9 | public abstract bool IsInstruction(Instruction instruction); 10 | public abstract string GetObfuscated(ObfuscationContext context); 11 | public virtual void Mutate(Instruction instruction) { } 12 | } 13 | } -------------------------------------------------------------------------------- /IronBrew2/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using IronBrew2.Bytecode_Library.Bytecode; 7 | using IronBrew2.Bytecode_Library.IR; 8 | using IronBrew2.Obfuscator; 9 | using IronBrew2.Obfuscator.Control_Flow; 10 | using IronBrew2.Obfuscator.Encryption; 11 | using IronBrew2.Obfuscator.VM_Generation; 12 | 13 | namespace IronBrew2 14 | { 15 | public static class IB2 16 | { 17 | public static Random Random = new Random(); 18 | private static Encoding _fuckingLua = Encoding.GetEncoding(28591); 19 | 20 | public static bool Obfuscate(string path, string input, ObfuscationSettings settings, out string error) 21 | { 22 | try 23 | { 24 | error = ""; 25 | 26 | string OS = Environment.OSVersion.Platform == PlatformID.Unix ? "/usr/bin/" : ""; 27 | 28 | string l = Path.Combine(path, "luac.out"); 29 | 30 | if (!File.Exists(input)) 31 | throw new Exception("Invalid input file."); 32 | 33 | Console.WriteLine("Checking file..."); 34 | 35 | Process proc = new Process 36 | { 37 | StartInfo = 38 | { 39 | FileName = $"{OS}luac", 40 | Arguments = "-o \"" + l + "\" \"" + input + "\"", 41 | UseShellExecute = false, 42 | RedirectStandardError = true, 43 | RedirectStandardOutput = true 44 | } 45 | }; 46 | 47 | string err = ""; 48 | 49 | proc.OutputDataReceived += (sender, args) => { err += args.Data; }; 50 | proc.ErrorDataReceived += (sender, args) => { err += args.Data; }; 51 | 52 | proc.Start(); 53 | proc.BeginOutputReadLine(); 54 | proc.BeginErrorReadLine(); 55 | proc.WaitForExit(); 56 | 57 | error = err; 58 | 59 | if (!File.Exists(l)) 60 | return false; 61 | 62 | File.Delete(l); 63 | string t0 = Path.Combine(path, "t0.lua"); 64 | 65 | Console.WriteLine("Stripping comments..."); 66 | 67 | proc = new Process 68 | { 69 | StartInfo = 70 | { 71 | FileName = $"{OS}luajit", 72 | Arguments = 73 | "../Lua/Minifier/luasrcdiet.lua --noopt-whitespace --noopt-emptylines --noopt-numbers --noopt-locals --noopt-strings --opt-comments \"" + 74 | input + 75 | "\" -o \"" + t0 + "\"", 76 | UseShellExecute = false, 77 | RedirectStandardError = true, 78 | RedirectStandardOutput = true 79 | } 80 | }; 81 | 82 | proc.OutputDataReceived += (sender, args) => { err += args.Data; }; 83 | proc.ErrorDataReceived += (sender, args) => { err += args.Data; }; 84 | 85 | proc.Start(); 86 | proc.BeginOutputReadLine(); 87 | proc.BeginErrorReadLine(); 88 | proc.WaitForExit(); 89 | 90 | error = err; 91 | 92 | if (!File.Exists(t0)) 93 | return false; 94 | 95 | string t1 = Path.Combine(path, "t1.lua"); 96 | 97 | Console.WriteLine("Compiling..."); 98 | 99 | File.WriteAllText(t1, new ConstantEncryption(settings, File.ReadAllText(t0, _fuckingLua)).EncryptStrings()); 100 | proc = new Process 101 | { 102 | StartInfo = 103 | { 104 | FileName = $"{OS}luac", 105 | Arguments = "-o \"" + l + "\" \"" + t1 + "\"", 106 | UseShellExecute = false, 107 | RedirectStandardError = true, 108 | RedirectStandardOutput = true 109 | } 110 | }; 111 | 112 | proc.OutputDataReceived += (sender, args) => { err += args.Data; }; 113 | proc.ErrorDataReceived += (sender, args) => { err += args.Data; }; 114 | 115 | proc.Start(); 116 | proc.BeginOutputReadLine(); 117 | proc.BeginErrorReadLine(); 118 | proc.WaitForExit(); 119 | 120 | error = err; 121 | 122 | if (!File.Exists(l)) 123 | return false; 124 | 125 | Console.WriteLine("Obfuscating..."); 126 | 127 | Deserializer des = new Deserializer(File.ReadAllBytes(l)); 128 | Chunk lChunk = des.DecodeFile(); 129 | 130 | if (settings.ControlFlow) 131 | { 132 | CFContext cf = new CFContext(lChunk); 133 | cf.DoChunks(); 134 | } 135 | 136 | Console.WriteLine("Serializing..."); 137 | 138 | //shuffle stuff 139 | //lChunk.Constants.Shuffle(); 140 | //lChunk.Functions.Shuffle(); 141 | 142 | ObfuscationContext context = new ObfuscationContext(lChunk); 143 | 144 | string t2 = Path.Combine(path, "t2.lua"); 145 | string c = new Generator(context).GenerateVM(settings); 146 | 147 | //string byteLocal = c.Substring(null, "\n"); 148 | //string rest = c.Substring("\n"); 149 | 150 | File.WriteAllText(t2, c, _fuckingLua); 151 | 152 | string t3 = Path.Combine(path, "t3.lua"); 153 | 154 | Console.WriteLine("Minifying..."); 155 | 156 | proc = new Process 157 | { 158 | StartInfo = 159 | { 160 | FileName = $"{OS}luajit", 161 | Arguments = 162 | "../Lua/Minifier/luasrcdiet.lua --maximum --opt-entropy --opt-emptylines --opt-eols --opt-numbers --opt-whitespace --opt-locals --noopt-strings \"" + 163 | t2 + 164 | "\" -o \"" + 165 | t3 + 166 | "\"" 167 | , 168 | } 169 | }; 170 | 171 | proc.Start(); 172 | proc.WaitForExit(); 173 | 174 | if (!File.Exists(t3)) 175 | return false; 176 | 177 | Console.WriteLine("Watermark..."); 178 | 179 | File.WriteAllText(Path.Combine(path, "out.lua"), @"--[[ 180 | IronBrew:tm: obfuscation; Version 2.7.0 181 | 182 | ........................................................................................................................................................................................................ 183 | ........................................................................................................................................................................................................ 184 | .....,,...,............................................................................................................................................................................................. 185 | .... MMMMM,............................................................................................................................................................................................. 186 | ....MMMMMMM,............................................................................................................................................................................................ 187 | ....MMMMMMM,............................................................................................................................................................................................ 188 | ....,MMMMMO............................................................................................................................................................................................. 189 | ......,................................................................................................................................................................................................. 190 | ..................................................,,,,,,............................................Z$$................................................................................................. 191 | ...................................................:::::............................................MMMO................................................................................................ 192 | .....:???? ,.......:????....,.8MMMMM,.......,,,MMMMI???INMMM.,................,.?ZMMMMDI:,,.........MMM$................................................................................................ 193 | .....MMMMM?,.......MMMMM,,.OMMMMMMMM......, 7MM+?+++++++++?+DM$ .............MMMMMMMMMMMMMM ,,......MMM$................................................................................................ 194 | .....MMMMM?,.......MMMMM..NMMMMMMMMM.,...,$M7++++++++++++++++++M$ .........MMMMMMMMMMMMMMMMMN .,....MMM$................................................................................................ 195 | .....MMMMM?,.......MMMMMMMMMMM8..,,,.,..,MM?++++++++++++++++++++MM,,......MMMMMMMM~,.+MMMMMMMM......MMM$................................................................................................ 196 | .....MMMMM?,.......MMMMMMMMZ ,,.......MMMMMMMMMMMMMDZZZZMMMMMMMMMMMMM ...MMMMMM,,,....., MMMMMM.....MMM$................................,.,,............................................................ 197 | .....MMMMM?,.......MMMMMMM:............MMMMMMMMMMMMMMMMMMMMMMMMMMMMM....MMMMMD,...........MMMMMM.,..MMM$...:MMMMMMMM:,........8MMM:.,DMMMMM,......?MMMMMMMMI.........MMMM......... MMM,.........MMMI.... 198 | .....MMMMM?,.......MMMMMM+............,M?+MMMMMMMMMM++?DMMMMMMMMM?+M,...MMMMM,.............MMMMM,,..MMM$,NMMMMMMMMMMMM8,.,....MMMM,NMMMMMMM,..,,MMMMMMMMMMMMMM.,.....MMMM.........7MMM7.........MMM$.... 199 | .....MMMMM?,.......MMMMMM,............,M?++MMMMMMMM7++++MMMMMMMM$??MM,,+MMMMM,.............MMMMM=...MMM$,MMMZ...,?MMMMMM,.....MMMMMMMMM,......DMMMMM:,....MMMMMN,....MMMM.........7MMM7.........MMM$.... 200 | .....MMMMM?,.......MMMMMM.............MM+??+MMMMMMM?++++MMMMMMMD??+$M,.MMMMM?.............,MMMMM?...MMM$,M,.,...,,,,MMMMM,....MMMMMM,,,,....,MMMMM,..,....,.MDNN$....MMMM.........7MMM7.........MMM$.... 201 | .....MMMMM?,.......MMMMM?,............MM??++???????++++++?????+++++7M..$MMMM,.............,?MMMM.,..MMM$.............OMMMM....MMMMM.........$MMMM,....... MMMMMM.,...MMMM.........7MMM7.........MMM$.... 202 | .....MMMMM?,.......MMMMM=,............NM?+++++++++++++++++++++++++?$M..MMMMM+,............,+MMMM+,..NMN$..............MMMM+,..MMMMM.........MMMM......,?MMMMM?.,.....MMMM.........7MMM7.........MMM$.... 203 | .....MMMMM?,.......MMMMM,,............,M+?+++++++?++++++++?+?++++++M7,,DMMMM:...............MMMM:,..MMMN.,............$MMM7...MMMM=.........MMMM....,DMMMMM..........MMMM.........7MMM7.........MMM$.... 204 | .....MMMMM?,.......MMMMM,,............:M$?++++?MM+++++++++DM?+++++?M,,,DMMMM+,..............MMMM+,..MMMM.,............?NMM?,..ZMMM,,........MMMM.,.MMMMMM,,..........MMMM,........7MMM7.........MMM$.... 205 | .....MMMMM?,.......MMMMM,,.............,M=++++++DMD++?++DMM+++++++M:...$MMMM.,..............MMMM ,..MMMM..............OMMM,,..OMMM,,........MMMM.,MMMM?,,......MNZ,,,MMMM.........IMMM?,........MMM?.... 206 | .....MMMMM?,.......MMMMM,,...............M+?+++++?+ZMMMN+++?+++++M7,...$MMMM................MMMM.,..=MMMN,..........,,MNMM.,..OMMM,.........?MMMI.,M..........,MMM,.,NMMM,........IMMMI.........MMM?.... 207 | .....MMMMM?,.......MMMMM,,................M7+?+++++++++++++++++IM,,....$MMMM,...............MMMM,....MMMMN.,......,,.MMMM,....OMMM,,........,MMMMN..........,+MMM,...,MMMN,.....,,MMMMM,,,.....MMMM..... 208 | .....MMMMM?,.......MMMMM,,................,MM++++?++++++++????MM.......$MMMM,...............MMMM,.....MNMMM$,......MMMMM .....OMMM,,..........MMMMM~......,,MMMM ,....MMMMM,,,..~MMMMMMM~,,,.,MMMMM..... 209 | .....MMMMM?,.......MMMMM,,.................,,MMD+++++++++++$MM,.,......$MMMM,...............MMMM,.....,+NMMMMMMMMMMMMMM..,....OMMM,,.......... +NMMMMMMMMMMMMMM,.......MMMMMMMMMMMMN,NMMMMMMMMMMMN,..... 210 | .....MMMMM?........MMMMM,,.....................::MMMMMMMMM$.,.........,ZMMMM,,..............MMMM,,......, MMMMMMMMMM:.,,......+MMM................MMMMMMMMMM7,,,......,.,MMMMMMMMN.:...MMMMMMMMM,,...... 211 | ..........,.......,,.....,.........................,,,,.,...................................................,.,,.,,,...........,,,..................,,..,,,,..............,,..,,,.......,,.,,,,......... 212 | ........................................................................................................................................................................................................ 213 | ]] 214 | 215 | " + File.ReadAllText(t3, _fuckingLua).Replace("\n", " "), _fuckingLua); 216 | return true; 217 | } 218 | catch (Exception e) 219 | { 220 | Console.WriteLine("ERROR"); 221 | Console.WriteLine(e); 222 | 223 | error = e.ToString(); 224 | return false; 225 | } 226 | } 227 | } 228 | } -------------------------------------------------------------------------------- /Lua/Minifier/fs.lua: -------------------------------------------------------------------------------- 1 | --------- 2 | -- Utility functions for operations on a file system. 3 | -- 4 | -- **Note: This module is not part of public API!** 5 | ---- 6 | local fmt = string.format 7 | local open = io.open 8 | 9 | local UTF8_BOM = '\239\187\191' 10 | 11 | local function normalize_io_error (name, err) 12 | if err:sub(1, #name + 2) == name..': ' then 13 | err = err:sub(#name + 3) 14 | end 15 | return err 16 | end 17 | 18 | local M = {} 19 | 20 | --- Reads the specified file and returns its content as string. 21 | -- 22 | -- @tparam string filename Path of the file to read. 23 | -- @tparam string mode The mode in which to open the file, see @{io.open} (default: "r"). 24 | -- @treturn[1] string A content of the file. 25 | -- @treturn[2] nil 26 | -- @treturn[2] string An error message. 27 | function M.read_file (filename, mode) 28 | local handler, err = open(filename, mode or 'r') 29 | if not handler then 30 | return nil, fmt('Could not open %s for reading: %s', 31 | filename, normalize_io_error(filename, err)) 32 | end 33 | 34 | local content, err = handler:read('*a') --luacheck: ignore 411 35 | if not content then 36 | return nil, fmt('Could not read %s: %s', filename, normalize_io_error(filename, err)) 37 | end 38 | 39 | handler:close() 40 | 41 | if content:sub(1, #UTF8_BOM) == UTF8_BOM then 42 | content = content:sub(#UTF8_BOM + 1) 43 | end 44 | 45 | return content 46 | end 47 | 48 | --- Writes the given data to the specified file. 49 | -- 50 | -- @tparam string filename Path of the file to write. 51 | -- @tparam string data The data to write. 52 | -- @tparam ?string mode The mode in which to open the file, see @{io.open} (default: "w"). 53 | -- @treturn[1] true 54 | -- @treturn[2] nil 55 | -- @treturn[2] string An error message. 56 | function M.write_file (filename, data, mode) 57 | local handler, err = open(filename, mode or 'w') 58 | if not handler then 59 | return nil, fmt('Could not open %s for writing: %s', 60 | filename, normalize_io_error(filename, err)) 61 | end 62 | 63 | local _, err = handler:write(data) --luacheck: ignore 411 64 | if err then 65 | return nil, fmt('Could not write %s: %s', filename, normalize_io_error(filename, err)) 66 | end 67 | 68 | handler:flush() 69 | handler:close() 70 | 71 | return true 72 | end 73 | 74 | return M 75 | -------------------------------------------------------------------------------- /Lua/Minifier/init.lua: -------------------------------------------------------------------------------- 1 | --------- 2 | -- LuaSrcDiet API 3 | ---- 4 | 5 | package.path = package.path .. ";../Lua/Minifier/?.lua" 6 | 7 | local llex = require 'llex' 8 | local lparser = require 'lparser' 9 | local optlex = require 'optlex' 10 | local optparser = require 'optparser' 11 | local utils = require 'utils' 12 | 13 | local concat = table.concat 14 | local merge = utils.merge 15 | 16 | local _ -- placeholder 17 | 18 | 19 | local function noop () 20 | return 21 | end 22 | 23 | local function opts_to_legacy (opts) 24 | local res = {} 25 | for key, val in pairs(opts) do 26 | res['opt-'..key] = val 27 | end 28 | return res 29 | end 30 | 31 | 32 | local M = {} 33 | 34 | --- The module's name. 35 | M._NAME = 'luasrcdiet' 36 | 37 | --- The module's version number. 38 | M._VERSION = '1.0.0' 39 | 40 | --- The module's homepage. 41 | M._HOMEPAGE = 'https://github.com/jirutka/luasrcdiet' 42 | 43 | --- All optimizations disabled. 44 | M.NONE_OPTS = { 45 | binequiv = false, 46 | comments = false, 47 | emptylines = false, 48 | entropy = false, 49 | eols = false, 50 | experimental = false, 51 | locals = false, 52 | numbers = false, 53 | srcequiv = false, 54 | strings = false, 55 | whitespace = false, 56 | } 57 | 58 | --- Basic optimizations enabled. 59 | -- @table BASIC_OPTS 60 | M.BASIC_OPTS = merge(M.NONE_OPTS, { 61 | comments = true, 62 | emptylines = true, 63 | srcequiv = true, 64 | whitespace = true, 65 | }) 66 | 67 | --- Defaults. 68 | -- @table DEFAULT_OPTS 69 | M.DEFAULT_OPTS = merge(M.BASIC_OPTS, { 70 | locals = true, 71 | numbers = true, 72 | }) 73 | 74 | --- Maximum optimizations enabled (all except experimental). 75 | -- @table MAXIMUM_OPTS 76 | M.MAXIMUM_OPTS = merge(M.DEFAULT_OPTS, { 77 | entropy = true, 78 | eols = true, 79 | strings = true, 80 | }) 81 | 82 | --- Optimizes the given Lua source code. 83 | -- 84 | -- @tparam ?{[string]=bool,...} opts Optimizations to do (default is @{DEFAULT_OPTS}). 85 | -- @tparam string source The Lua source code to optimize. 86 | -- @treturn string Optimized source. 87 | -- @raise if the source is malformed, source equivalence test failed, or some 88 | -- other error occured. 89 | function M.optimize (opts, source) 90 | assert(source and type(source) == 'string', 91 | 'bad argument #2: expected string, got a '..type(source)) 92 | 93 | opts = opts and merge(M.NONE_OPTS, opts) or M.DEFAULT_OPTS 94 | local legacy_opts = opts_to_legacy(opts) 95 | 96 | local toklist, seminfolist, toklnlist = llex.lex(source) 97 | local xinfo = lparser.parse(toklist, seminfolist, toklnlist) 98 | 99 | optparser.print = noop 100 | optparser.optimize(legacy_opts, toklist, seminfolist, xinfo) 101 | 102 | local warn = optlex.warn -- use this as a general warning lookup 103 | optlex.print = noop 104 | _, seminfolist = optlex.optimize(legacy_opts, toklist, seminfolist, toklnlist) 105 | local optim_source = concat(seminfolist) 106 | 107 | return optim_source 108 | end 109 | 110 | return M 111 | -------------------------------------------------------------------------------- /Lua/Minifier/llex.lua: -------------------------------------------------------------------------------- 1 | --------- 2 | -- Lua 5.1+ lexical analyzer written in Lua. 3 | -- 4 | -- This file is part of LuaSrcDiet, based on Yueliang material. 5 | -- 6 | -- **Notes:** 7 | -- 8 | -- * This is a version of the native 5.1.x lexer from Yueliang 0.4.0, 9 | -- with significant modifications to handle LuaSrcDiet's needs: 10 | -- (1) llex.error is an optional error function handler, 11 | -- (2) seminfo for strings include their delimiters and no 12 | -- translation operations are performed on them. 13 | -- * ADDED shbang handling has been added to support executable scripts. 14 | -- * NO localized decimal point replacement magic. 15 | -- * NO limit to number of lines. 16 | -- * NO support for compatible long strings (LUA\_COMPAT_LSTR). 17 | -- * Added goto keyword and double-colon operator (Lua 5.2+). 18 | ---- 19 | local find = string.find 20 | local fmt = string.format 21 | local match = string.match 22 | local sub = string.sub 23 | local tonumber = tonumber 24 | 25 | local M = {} 26 | 27 | local kw = {} 28 | for v in ([[ 29 | and break do else elseif end false for function if in 30 | local nil not or repeat return then true until while]]):gmatch("%S+") do 31 | kw[v] = true 32 | end 33 | 34 | local z, -- source stream 35 | sourceid, -- name of source 36 | I, -- position of lexer 37 | buff, -- buffer for strings 38 | ln, -- line number 39 | tok, -- lexed token list 40 | seminfo, -- lexed semantic information list 41 | tokln -- line numbers for messages 42 | 43 | 44 | --- Adds information to token listing. 45 | -- 46 | -- @tparam string token 47 | -- @tparam string info 48 | local function addtoken(token, info) 49 | local i = #tok + 1 50 | tok[i] = token 51 | seminfo[i] = info 52 | tokln[i] = ln 53 | end 54 | 55 | --- Handles line number incrementation and end-of-line characters. 56 | -- 57 | -- @tparam int i Position of lexer in the source stream. 58 | -- @tparam bool is_tok 59 | -- @treturn int 60 | local function inclinenumber(i, is_tok) 61 | local old = sub(z, i, i) 62 | i = i + 1 -- skip '\n' or '\r' 63 | local c = sub(z, i, i) 64 | if (c == "\n" or c == "\r") and (c ~= old) then 65 | i = i + 1 -- skip '\n\r' or '\r\n' 66 | old = old..c 67 | end 68 | if is_tok then addtoken("TK_EOL", old) end 69 | ln = ln + 1 70 | I = i 71 | return i 72 | end 73 | 74 | --- Returns a chunk name or id, no truncation for long names. 75 | -- 76 | -- @treturn string 77 | local function chunkid() 78 | if sourceid and match(sourceid, "^[=@]") then 79 | return sub(sourceid, 2) -- remove first char 80 | end 81 | return "[string]" 82 | end 83 | 84 | --- Formats error message and throws error. 85 | -- 86 | -- A simplified version, does not report what token was responsible. 87 | -- 88 | -- @tparam string s 89 | -- @tparam int line The line number. 90 | -- @raise 91 | local function errorline(s, line) 92 | local e = M.error or error 93 | e(fmt("%s:%d: %s", chunkid(), line or ln, s)) 94 | end 95 | 96 | --- Counts separators (`="` in a long string delimiter. 97 | -- 98 | -- @tparam int i Position of lexer in the source stream. 99 | -- @treturn int 100 | local function skip_sep(i) 101 | local s = sub(z, i, i) 102 | i = i + 1 103 | local count = #match(z, "=*", i) 104 | i = i + count 105 | I = i 106 | return (sub(z, i, i) == s) and count or (-count) - 1 107 | end 108 | 109 | --- Reads a long string or long comment. 110 | -- 111 | -- @tparam bool is_str 112 | -- @tparam string sep 113 | -- @treturn string 114 | -- @raise if unfinished long string or comment. 115 | local function read_long_string(is_str, sep) 116 | local i = I + 1 -- skip 2nd '[' 117 | local c = sub(z, i, i) 118 | if c == "\r" or c == "\n" then -- string starts with a newline? 119 | i = inclinenumber(i) -- skip it 120 | end 121 | while true do 122 | local p, _, r = find(z, "([\r\n%]])", i) -- (long range match) 123 | if not p then 124 | errorline(is_str and "unfinished long string" or 125 | "unfinished long comment") 126 | end 127 | i = p 128 | if r == "]" then -- delimiter test 129 | if skip_sep(i) == sep then 130 | buff = sub(z, buff, I) 131 | I = I + 1 -- skip 2nd ']' 132 | return buff 133 | end 134 | i = I 135 | else -- newline 136 | buff = buff.."\n" 137 | i = inclinenumber(i) 138 | end 139 | end--while 140 | end 141 | 142 | --- Reads a string. 143 | -- 144 | -- @tparam string del The delimiter. 145 | -- @treturn string 146 | -- @raise if unfinished string or too large escape sequence. 147 | local function read_string(del) 148 | local i = I 149 | while true do 150 | local p, _, r = find(z, "([\n\r\\\"\'])", i) -- (long range match) 151 | if p then 152 | if r == "\n" or r == "\r" then 153 | errorline("unfinished string") 154 | end 155 | i = p 156 | if r == "\\" then -- handle escapes 157 | i = i + 1 158 | r = sub(z, i, i) 159 | if r == "" then break end -- (EOZ error) 160 | p = find("abfnrtv\n\r", r, 1, true) 161 | 162 | if p then -- special escapes 163 | if p > 7 then 164 | i = inclinenumber(i) 165 | else 166 | i = i + 1 167 | end 168 | 169 | elseif find(r, "%D") then -- other non-digits 170 | i = i + 1 171 | 172 | else -- \xxx sequence 173 | local _, q, s = find(z, "^(%d%d?%d?)", i) 174 | i = q + 1 175 | if s + 1 > 256 then -- UCHAR_MAX 176 | errorline("escape sequence too large") 177 | end 178 | 179 | end--if p 180 | else 181 | i = i + 1 182 | if r == del then -- ending delimiter 183 | I = i 184 | return sub(z, buff, i - 1) -- return string 185 | end 186 | end--if r 187 | else 188 | break -- (error) 189 | end--if p 190 | end--while 191 | errorline("unfinished string") 192 | end 193 | 194 | 195 | --- Initializes lexer for given source _z and source name _sourceid. 196 | -- 197 | -- @tparam string _z The source code. 198 | -- @tparam string _sourceid Name of the source. 199 | local function init(_z, _sourceid) 200 | z = _z -- source 201 | sourceid = _sourceid -- name of source 202 | I = 1 -- lexer's position in source 203 | ln = 1 -- line number 204 | tok = {} -- lexed token list* 205 | seminfo = {} -- lexed semantic information list* 206 | tokln = {} -- line numbers for messages* 207 | 208 | -- Initial processing (shbang handling). 209 | local p, _, q, r = find(z, "^(#[^\r\n]*)(\r?\n?)") 210 | if p then -- skip first line 211 | I = I + #q 212 | addtoken("TK_COMMENT", q) 213 | if #r > 0 then inclinenumber(I, true) end 214 | end 215 | end 216 | 217 | --- Runs lexer on the given source code. 218 | -- 219 | -- @tparam string source The Lua source to scan. 220 | -- @tparam ?string source_name Name of the source (optional). 221 | -- @treturn {string,...} A list of lexed tokens. 222 | -- @treturn {string,...} A list of semantic information (lexed strings). 223 | -- @treturn {int,...} A list of line numbers. 224 | function M.lex(source, source_name) 225 | init(source, source_name) 226 | 227 | while true do--outer 228 | local i = I 229 | -- inner loop allows break to be used to nicely section tests 230 | while true do --luacheck: ignore 512 231 | 232 | local p, _, r = find(z, "^([_%a][_%w]*)", i) 233 | if p then 234 | I = i + #r 235 | if kw[r] then 236 | addtoken("TK_KEYWORD", r) -- reserved word (keyword) 237 | else 238 | addtoken("TK_NAME", r) -- identifier 239 | end 240 | break -- (continue) 241 | end 242 | 243 | local p, _, r = find(z, "^(%.?)%d", i) 244 | if p then -- numeral 245 | if r == "." then i = i + 1 end 246 | local _, q, r = find(z, "^%d*[%.%d]*([eE]?)", i) --luacheck: ignore 421 247 | i = q + 1 248 | if #r == 1 then -- optional exponent 249 | if match(z, "^[%+%-]", i) then -- optional sign 250 | i = i + 1 251 | end 252 | end 253 | local _, q = find(z, "^[_%w]*", i) 254 | I = q + 1 255 | local v = sub(z, p, q) -- string equivalent 256 | if not tonumber(v) then -- handles hex test also 257 | errorline("malformed number") 258 | end 259 | addtoken("TK_NUMBER", v) 260 | break -- (continue) 261 | end 262 | 263 | local p, q, r, t = find(z, "^((%s)[ \t\v\f]*)", i) 264 | if p then 265 | if t == "\n" or t == "\r" then -- newline 266 | inclinenumber(i, true) 267 | else 268 | I = q + 1 -- whitespace 269 | addtoken("TK_SPACE", r) 270 | end 271 | break -- (continue) 272 | end 273 | 274 | local _, q = find(z, "^::", i) 275 | if q then 276 | I = q + 1 277 | addtoken("TK_OP", "::") 278 | break -- (continue) 279 | end 280 | 281 | local r = match(z, "^%p", i) 282 | if r then 283 | buff = i 284 | local p = find("-[\"\'.=<>~", r, 1, true) --luacheck: ignore 421 285 | if p then 286 | 287 | -- two-level if block for punctuation/symbols 288 | if p <= 2 then 289 | if p == 1 then -- minus 290 | local c = match(z, "^%-%-(%[?)", i) 291 | if c then 292 | i = i + 2 293 | local sep = -1 294 | if c == "[" then 295 | sep = skip_sep(i) 296 | end 297 | if sep >= 0 then -- long comment 298 | addtoken("TK_LCOMMENT", read_long_string(false, sep)) 299 | else -- short comment 300 | I = find(z, "[\n\r]", i) or (#z + 1) 301 | addtoken("TK_COMMENT", sub(z, buff, I - 1)) 302 | end 303 | break -- (continue) 304 | end 305 | -- (fall through for "-") 306 | else -- [ or long string 307 | local sep = skip_sep(i) 308 | if sep >= 0 then 309 | addtoken("TK_LSTRING", read_long_string(true, sep)) 310 | elseif sep == -1 then 311 | addtoken("TK_OP", "[") 312 | else 313 | errorline("invalid long string delimiter") 314 | end 315 | break -- (continue) 316 | end 317 | 318 | elseif p <= 5 then 319 | if p < 5 then -- strings 320 | I = i + 1 321 | addtoken("TK_STRING", read_string(r)) 322 | break -- (continue) 323 | end 324 | r = match(z, "^%.%.?%.?", i) -- .|..|... dots 325 | -- (fall through) 326 | 327 | else -- relational 328 | r = match(z, "^%p=?", i) 329 | -- (fall through) 330 | end 331 | end 332 | I = i + #r 333 | addtoken("TK_OP", r) -- for other symbols, fall through 334 | break -- (continue) 335 | end 336 | 337 | local r = sub(z, i, i) 338 | if r ~= "" then 339 | I = i + 1 340 | addtoken("TK_OP", r) -- other single-char tokens 341 | break 342 | end 343 | addtoken("TK_EOS", "") -- end of stream, 344 | return tok, seminfo, tokln -- exit here 345 | 346 | end--while inner 347 | end--while outer 348 | end 349 | 350 | return M 351 | -------------------------------------------------------------------------------- /Lua/Minifier/luasrcdiet.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | --------- 3 | -- LuaSrcDiet 4 | -- 5 | -- Compresses Lua source code by removing unnecessary characters. 6 | -- For Lua 5.1+ source code. 7 | -- 8 | -- **Notes:** 9 | -- 10 | -- * Remember to update version and date information below (MSG_TITLE). 11 | -- * TODO: passing data tables around is a horrific mess. 12 | -- * TODO: to implement pcall() to properly handle lexer etc. errors. 13 | -- * TODO: need some automatic testing for a semblance of sanity. 14 | -- * TODO: the plugin module is highly experimental and unstable. 15 | ---- 16 | 17 | package.path = package.path .. ";../Lua/Minifier/?.lua" 18 | 19 | local fs = require "fs" 20 | local llex = require "llex" 21 | local lparser = require "lparser" 22 | local luasrcdiet = require "init" 23 | local optlex = require "optlex" 24 | local optparser = require "optparser" 25 | 26 | local byte = string.byte 27 | local concat = table.concat 28 | local find = string.find 29 | local fmt = string.format 30 | local gmatch = string.gmatch 31 | local match = string.match 32 | local print = print 33 | local rep = string.rep 34 | local sub = string.sub 35 | 36 | local plugin 37 | 38 | local LUA_VERSION = match(_VERSION, " (5%.[123])$") or "5.1" 39 | 40 | -- Is --opt-binequiv available for this Lua version? 41 | local BIN_EQUIV_AVAIL = LUA_VERSION == "5.1" and not package.loaded.jit 42 | 43 | 44 | ---------------------- Messages and textual data ---------------------- 45 | 46 | local MSG_TITLE = fmt([[ 47 | LuaSrcDiet: Puts your Lua 5.1+ source code on a diet 48 | Version %s <%s> 49 | ]], luasrcdiet._VERSION, luasrcdiet._HOMEPAGE) 50 | 51 | local MSG_USAGE = [[ 52 | usage: luasrcdiet [options] [filenames] 53 | 54 | example: 55 | >luasrcdiet myscript.lua -o myscript_.lua 56 | 57 | options: 58 | -v, --version prints version information 59 | -h, --help prints usage information 60 | -o specify file name to write output 61 | -s suffix for output files (default '_') 62 | --keep keep block comment with inside 63 | --plugin run in plugin/ directory 64 | - stop handling arguments 65 | 66 | (optimization levels) 67 | --none all optimizations off (normalizes EOLs only) 68 | --basic lexer-based optimizations only 69 | --maximum maximize reduction of source 70 | 71 | (informational) 72 | --quiet process files quietly 73 | --read-only read file and print token stats only 74 | --dump-lexer dump raw tokens from lexer to stdout 75 | --dump-parser dump variable tracking tables from parser 76 | --details extra info (strings, numbers, locals) 77 | 78 | features (to disable, insert 'no' prefix like --noopt-comments): 79 | %s 80 | default settings: 81 | %s]] 82 | 83 | -- Optimization options, for ease of switching on and off. 84 | -- 85 | -- * Positive to enable optimization, negative (no) to disable. 86 | -- * These options should follow --opt-* and --noopt-* style for now. 87 | local OPTION = [[ 88 | --opt-comments,'remove comments and block comments' 89 | --opt-whitespace,'remove whitespace excluding EOLs' 90 | --opt-emptylines,'remove empty lines' 91 | --opt-eols,'all above, plus remove unnecessary EOLs' 92 | --opt-strings,'optimize strings and long strings' 93 | --opt-numbers,'optimize numbers' 94 | --opt-locals,'optimize local variable names' 95 | --opt-entropy,'tries to reduce symbol entropy of locals' 96 | --opt-srcequiv,'insist on source (lexer stream) equivalence' 97 | --opt-binequiv,'insist on binary chunk equivalence (only for PUC Lua 5.1)' 98 | --opt-experimental,'apply experimental optimizations' 99 | ]] 100 | 101 | -- Preset configuration. 102 | local DEFAULT_CONFIG = [[ 103 | --opt-comments --opt-whitespace --opt-emptylines 104 | --opt-numbers --opt-locals 105 | --opt-srcequiv --noopt-binequiv 106 | ]] 107 | -- Override configurations: MUST explicitly enable/disable everything. 108 | local BASIC_CONFIG = [[ 109 | --opt-comments --opt-whitespace --opt-emptylines 110 | --noopt-eols --noopt-strings --noopt-numbers 111 | --noopt-locals --noopt-entropy 112 | --opt-srcequiv --noopt-binequiv 113 | ]] 114 | local MAXIMUM_CONFIG = [[ 115 | --opt-comments --opt-whitespace --opt-emptylines 116 | --opt-eols --opt-strings --opt-numbers 117 | --opt-locals --opt-entropy 118 | --opt-srcequiv 119 | ]] .. (BIN_EQUIV_AVAIL and ' --opt-binequiv' or ' --noopt-binequiv') 120 | 121 | local NONE_CONFIG = [[ 122 | --noopt-comments --noopt-whitespace --noopt-emptylines 123 | --noopt-eols --noopt-strings --noopt-numbers 124 | --noopt-locals --noopt-entropy 125 | --opt-srcequiv --noopt-binequiv 126 | ]] 127 | 128 | local DEFAULT_SUFFIX = "_" -- default suffix for file renaming 129 | local PLUGIN_SUFFIX = "luasrcdiet.plugin." -- relative location of plugins 130 | 131 | 132 | ------------- Startup and initialize option list handling ------------- 133 | 134 | --- Simple error message handler; change to error if traceback wanted. 135 | -- 136 | -- @tparam string msg The message to print. 137 | local function die(msg) 138 | print("LuaSrcDiet (error): "..msg); os.exit(1) 139 | end 140 | --die = error--DEBUG 141 | 142 | -- Prepare text for list of optimizations, prepare lookup table. 143 | local MSG_OPTIONS = "" 144 | do 145 | local WIDTH = 24 146 | local o = {} 147 | for op, desc in gmatch(OPTION, "%s*([^,]+),'([^']+)'") do 148 | local msg = " "..op 149 | msg = msg..rep(" ", WIDTH - #msg)..desc.."\n" 150 | MSG_OPTIONS = MSG_OPTIONS..msg 151 | o[op] = true 152 | o["--no"..sub(op, 3)] = true 153 | end 154 | OPTION = o -- replace OPTION with lookup table 155 | end 156 | 157 | MSG_USAGE = fmt(MSG_USAGE, MSG_OPTIONS, DEFAULT_CONFIG) 158 | 159 | 160 | --------- Global variable initialization, option set handling --------- 161 | 162 | local suffix = DEFAULT_SUFFIX -- file suffix 163 | local option = {} -- program options 164 | local stat_c, stat_l -- statistics tables 165 | 166 | --- Sets option lookup table based on a text list of options. 167 | -- 168 | -- Note: additional forced settings for --opt-eols is done in optlex.lua. 169 | -- 170 | -- @tparam string CONFIG 171 | local function set_options(CONFIG) 172 | for op in gmatch(CONFIG, "(%-%-%S+)") do 173 | if sub(op, 3, 4) == "no" and -- handle negative options 174 | OPTION["--"..sub(op, 5)] then 175 | option[sub(op, 5)] = false 176 | else 177 | option[sub(op, 3)] = true 178 | end 179 | end 180 | end 181 | 182 | 183 | -------------------------- Support functions -------------------------- 184 | 185 | -- List of token types, parser-significant types are up to TTYPE_GRAMMAR 186 | -- while the rest are not used by parsers; arranged for stats display. 187 | local TTYPES = { 188 | "TK_KEYWORD", "TK_NAME", "TK_NUMBER", -- grammar 189 | "TK_STRING", "TK_LSTRING", "TK_OP", 190 | "TK_EOS", 191 | "TK_COMMENT", "TK_LCOMMENT", -- non-grammar 192 | "TK_EOL", "TK_SPACE", 193 | } 194 | local TTYPE_GRAMMAR = 7 195 | 196 | local EOLTYPES = { -- EOL names for token dump 197 | ["\n"] = "LF", ["\r"] = "CR", 198 | ["\n\r"] = "LFCR", ["\r\n"] = "CRLF", 199 | } 200 | 201 | --- Reads source code from the file. 202 | -- 203 | -- @tparam string fname Path of the file to read. 204 | -- @treturn string Content of the file. 205 | local function load_file(fname) 206 | local data, err = fs.read_file(fname, "rb") 207 | if not data then die(err) end 208 | return data 209 | end 210 | 211 | --- Saves source code to the file. 212 | -- 213 | -- @tparam string fname Path of the destination file. 214 | -- @tparam string dat The data to write into the file. 215 | local function save_file(fname, dat) 216 | local ok, err = fs.write_file(fname, dat, "wb") 217 | if not ok then die(err) end 218 | end 219 | 220 | 221 | ------------------ Functions to deal with statistics ------------------ 222 | 223 | --- Initializes the statistics table. 224 | local function stat_init() 225 | stat_c, stat_l = {}, {} 226 | for i = 1, #TTYPES do 227 | local ttype = TTYPES[i] 228 | stat_c[ttype], stat_l[ttype] = 0, 0 229 | end 230 | end 231 | 232 | --- Adds a token to the statistics table. 233 | -- 234 | -- @tparam string tok The token. 235 | -- @param seminfo 236 | local function stat_add(tok, seminfo) 237 | stat_c[tok] = stat_c[tok] + 1 238 | stat_l[tok] = stat_l[tok] + #seminfo 239 | end 240 | 241 | --- Computes totals for the statistics table, returns average table. 242 | -- 243 | -- @treturn table 244 | local function stat_calc() 245 | local function avg(c, l) -- safe average function 246 | if c == 0 then return 0 end 247 | return l / c 248 | end 249 | local stat_a = {} 250 | local c, l = 0, 0 251 | for i = 1, TTYPE_GRAMMAR do -- total grammar tokens 252 | local ttype = TTYPES[i] 253 | c = c + stat_c[ttype]; l = l + stat_l[ttype] 254 | end 255 | stat_c.TOTAL_TOK, stat_l.TOTAL_TOK = c, l 256 | stat_a.TOTAL_TOK = avg(c, l) 257 | c, l = 0, 0 258 | for i = 1, #TTYPES do -- total all tokens 259 | local ttype = TTYPES[i] 260 | c = c + stat_c[ttype]; l = l + stat_l[ttype] 261 | stat_a[ttype] = avg(stat_c[ttype], stat_l[ttype]) 262 | end 263 | stat_c.TOTAL_ALL, stat_l.TOTAL_ALL = c, l 264 | stat_a.TOTAL_ALL = avg(c, l) 265 | return stat_a 266 | end 267 | 268 | 269 | ----------------------------- Main tasks ----------------------------- 270 | 271 | --- A simple token dumper, minimal translation of seminfo data. 272 | -- 273 | -- @tparam string srcfl Path of the source file. 274 | local function dump_tokens(srcfl) 275 | -- Load file and process source input into tokens. 276 | local z = load_file(srcfl) 277 | local toklist, seminfolist = llex.lex(z) 278 | 279 | -- Display output. 280 | for i = 1, #toklist do 281 | local tok, seminfo = toklist[i], seminfolist[i] 282 | if tok == "TK_OP" and byte(seminfo) < 32 then 283 | seminfo = "("..byte(seminfo)..")" 284 | elseif tok == "TK_EOL" then 285 | seminfo = EOLTYPES[seminfo] 286 | else 287 | seminfo = "'"..seminfo.."'" 288 | end 289 | print(tok.." "..seminfo) 290 | end--for 291 | end 292 | 293 | --- Dumps globalinfo and localinfo tables. 294 | -- 295 | -- @tparam string srcfl Path of the source file. 296 | local function dump_parser(srcfl) 297 | -- Load file and process source input into tokens, 298 | local z = load_file(srcfl) 299 | local toklist, seminfolist, toklnlist = llex.lex(z) 300 | 301 | -- Do parser optimization here. 302 | local xinfo = lparser.parse(toklist, seminfolist, toklnlist) 303 | local globalinfo, localinfo = xinfo.globalinfo, xinfo.localinfo 304 | 305 | -- Display output. 306 | local hl = rep("-", 72) 307 | print("*** Local/Global Variable Tracker Tables ***") 308 | print(hl.."\n GLOBALS\n"..hl) 309 | -- global tables have a list of xref numbers only 310 | for i = 1, #globalinfo do 311 | local obj = globalinfo[i] 312 | local msg = "("..i..") '"..obj.name.."' -> " 313 | local xref = obj.xref 314 | for j = 1, #xref do msg = msg..xref[j].." " end 315 | print(msg) 316 | end 317 | -- Local tables have xref numbers and a few other special 318 | -- numbers that are specially named: decl (declaration xref), 319 | -- act (activation xref), rem (removal xref). 320 | print(hl.."\n LOCALS (decl=declared act=activated rem=removed)\n"..hl) 321 | for i = 1, #localinfo do 322 | local obj = localinfo[i] 323 | local msg = "("..i..") '"..obj.name.."' decl:"..obj.decl.. 324 | " act:"..obj.act.." rem:"..obj.rem 325 | if obj.is_special then 326 | msg = msg.." is_special" 327 | end 328 | msg = msg.." -> " 329 | local xref = obj.xref 330 | for j = 1, #xref do msg = msg..xref[j].." " end 331 | print(msg) 332 | end 333 | print(hl.."\n") 334 | end 335 | 336 | --- Reads source file(s) and reports some statistics. 337 | -- 338 | -- @tparam string srcfl Path of the source file. 339 | local function read_only(srcfl) 340 | -- Load file and process source input into tokens. 341 | local z = load_file(srcfl) 342 | local toklist, seminfolist = llex.lex(z) 343 | print(MSG_TITLE) 344 | print("Statistics for: "..srcfl.."\n") 345 | 346 | -- Collect statistics. 347 | stat_init() 348 | for i = 1, #toklist do 349 | local tok, seminfo = toklist[i], seminfolist[i] 350 | stat_add(tok, seminfo) 351 | end--for 352 | local stat_a = stat_calc() 353 | 354 | -- Display output. 355 | local function figures(tt) 356 | return stat_c[tt], stat_l[tt], stat_a[tt] 357 | end 358 | local tabf1, tabf2 = "%-16s%8s%8s%10s", "%-16s%8d%8d%10.2f" 359 | local hl = rep("-", 42) 360 | print(fmt(tabf1, "Lexical", "Input", "Input", "Input")) 361 | print(fmt(tabf1, "Elements", "Count", "Bytes", "Average")) 362 | print(hl) 363 | for i = 1, #TTYPES do 364 | local ttype = TTYPES[i] 365 | print(fmt(tabf2, ttype, figures(ttype))) 366 | if ttype == "TK_EOS" then print(hl) end 367 | end 368 | print(hl) 369 | print(fmt(tabf2, "Total Elements", figures("TOTAL_ALL"))) 370 | print(hl) 371 | print(fmt(tabf2, "Total Tokens", figures("TOTAL_TOK"))) 372 | print(hl.."\n") 373 | end 374 | 375 | --- Processes source file(s), writes output and reports some statistics. 376 | -- 377 | -- @tparam string srcfl Path of the source file. 378 | -- @tparam string destfl Path of the destination file where to write optimized source. 379 | local function process_file(srcfl, destfl) 380 | -- handle quiet option 381 | local function print(...) --luacheck: ignore 431 382 | if option.QUIET then return end 383 | _G.print(...) 384 | end 385 | if plugin and plugin.init then -- plugin init 386 | option.EXIT = false 387 | plugin.init(option, srcfl, destfl) 388 | if option.EXIT then return end 389 | end 390 | print(MSG_TITLE) -- title message 391 | 392 | -- Load file and process source input into tokens. 393 | local z = load_file(srcfl) 394 | if plugin and plugin.post_load then -- plugin post-load 395 | z = plugin.post_load(z) or z 396 | if option.EXIT then return end 397 | end 398 | local toklist, seminfolist, toklnlist = llex.lex(z) 399 | if plugin and plugin.post_lex then -- plugin post-lex 400 | plugin.post_lex(toklist, seminfolist, toklnlist) 401 | if option.EXIT then return end 402 | end 403 | 404 | -- Collect 'before' statistics. 405 | stat_init() 406 | for i = 1, #toklist do 407 | local tok, seminfo = toklist[i], seminfolist[i] 408 | stat_add(tok, seminfo) 409 | end--for 410 | local stat1_a = stat_calc() 411 | local stat1_c, stat1_l = stat_c, stat_l 412 | 413 | -- Do parser optimization here. 414 | optparser.print = print -- hack 415 | local xinfo = lparser.parse(toklist, seminfolist, toklnlist) 416 | if plugin and plugin.post_parse then -- plugin post-parse 417 | plugin.post_parse(xinfo.globalinfo, xinfo.localinfo) 418 | if option.EXIT then return end 419 | end 420 | optparser.optimize(option, toklist, seminfolist, xinfo) 421 | if plugin and plugin.post_optparse then -- plugin post-optparse 422 | plugin.post_optparse() 423 | if option.EXIT then return end 424 | end 425 | 426 | -- Do lexer optimization here, save output file. 427 | local warn = optlex.warn -- use this as a general warning lookup 428 | optlex.print = print -- hack 429 | toklist, seminfolist, toklnlist 430 | = optlex.optimize(option, toklist, seminfolist, toklnlist) 431 | if plugin and plugin.post_optlex then -- plugin post-optlex 432 | plugin.post_optlex(toklist, seminfolist, toklnlist) 433 | if option.EXIT then return end 434 | end 435 | local dat = concat(seminfolist) 436 | -- Depending on options selected, embedded EOLs in long strings and 437 | -- long comments may not have been translated to \n, tack a warning. 438 | if find(dat, "\r\n", 1, 1) or 439 | find(dat, "\n\r", 1, 1) then 440 | warn.MIXEDEOL = true 441 | end 442 | 443 | -- Save optimized source stream to output file. 444 | save_file(destfl, dat) 445 | 446 | -- Collect 'after' statistics. 447 | stat_init() 448 | for i = 1, #toklist do 449 | local tok, seminfo = toklist[i], seminfolist[i] 450 | stat_add(tok, seminfo) 451 | end--for 452 | local stat_a = stat_calc() 453 | 454 | -- Display output. 455 | print("Statistics for: "..srcfl.." -> "..destfl.."\n") 456 | local function figures(tt) 457 | return stat1_c[tt], stat1_l[tt], stat1_a[tt], 458 | stat_c[tt], stat_l[tt], stat_a[tt] 459 | end 460 | local tabf1, tabf2 = "%-16s%8s%8s%10s%8s%8s%10s", 461 | "%-16s%8d%8d%10.2f%8d%8d%10.2f" 462 | local hl = rep("-", 68) 463 | print("*** lexer-based optimizations summary ***\n"..hl) 464 | print(fmt(tabf1, "Lexical", 465 | "Input", "Input", "Input", 466 | "Output", "Output", "Output")) 467 | print(fmt(tabf1, "Elements", 468 | "Count", "Bytes", "Average", 469 | "Count", "Bytes", "Average")) 470 | print(hl) 471 | for i = 1, #TTYPES do 472 | local ttype = TTYPES[i] 473 | print(fmt(tabf2, ttype, figures(ttype))) 474 | if ttype == "TK_EOS" then print(hl) end 475 | end 476 | print(hl) 477 | print(fmt(tabf2, "Total Elements", figures("TOTAL_ALL"))) 478 | print(hl) 479 | print(fmt(tabf2, "Total Tokens", figures("TOTAL_TOK"))) 480 | print(hl) 481 | 482 | -- Report warning flags from optimizing process. 483 | if warn.LSTRING then 484 | print("* WARNING: "..warn.LSTRING) 485 | elseif warn.MIXEDEOL then 486 | print("* WARNING: ".."output still contains some CRLF or LFCR line endings") 487 | elseif warn.SRC_EQUIV then 488 | print("* WARNING: "..smsg) 489 | elseif warn.BIN_EQUIV then 490 | print("* WARNING: "..bmsg) 491 | end 492 | print() 493 | end 494 | 495 | 496 | ---------------------------- Main functions --------------------------- 497 | 498 | local arg = {...} -- program arguments 499 | set_options(DEFAULT_CONFIG) -- set to default options at beginning 500 | 501 | --- Does per-file handling, ship off to tasks. 502 | -- 503 | -- @tparam {string,...} fspec List of source files. 504 | local function do_files(fspec) 505 | for i = 1, #fspec do 506 | local srcfl = fspec[i] 507 | local destfl 508 | 509 | -- Find and replace extension for filenames. 510 | local extb, exte = find(srcfl, "%.[^%.%\\%/]*$") 511 | local basename, extension = srcfl, "" 512 | if extb and extb > 1 then 513 | basename = sub(srcfl, 1, extb - 1) 514 | extension = sub(srcfl, extb, exte) 515 | end 516 | destfl = basename..suffix..extension 517 | if #fspec == 1 and option.OUTPUT_FILE then 518 | destfl = option.OUTPUT_FILE 519 | end 520 | if srcfl == destfl then 521 | die("output filename identical to input filename") 522 | end 523 | 524 | -- Perform requested operations. 525 | if option.DUMP_LEXER then 526 | dump_tokens(srcfl) 527 | elseif option.DUMP_PARSER then 528 | dump_parser(srcfl) 529 | elseif option.READ_ONLY then 530 | read_only(srcfl) 531 | else 532 | process_file(srcfl, destfl) 533 | end 534 | end--for 535 | end 536 | 537 | --- The main function. 538 | local function main() 539 | local fspec = {} 540 | local argn, i = #arg, 1 541 | if argn == 0 then 542 | option.HELP = true 543 | end 544 | 545 | -- Handle arguments. 546 | while i <= argn do 547 | local o, p = arg[i], arg[i + 1] 548 | local dash = match(o, "^%-%-?") 549 | if dash == "-" then -- single-dash options 550 | if o == "-h" then 551 | option.HELP = true; break 552 | elseif o == "-v" then 553 | option.VERSION = true; break 554 | elseif o == "-s" then 555 | if not p then die("-s option needs suffix specification") end 556 | suffix = p 557 | i = i + 1 558 | elseif o == "-o" then 559 | if not p then die("-o option needs a file name") end 560 | option.OUTPUT_FILE = p 561 | i = i + 1 562 | elseif o == "-" then 563 | break -- ignore rest of args 564 | else 565 | die("unrecognized option "..o) 566 | end 567 | elseif dash == "--" then -- double-dash options 568 | if o == "--help" then 569 | option.HELP = true; break 570 | elseif o == "--version" then 571 | option.VERSION = true; break 572 | elseif o == "--keep" then 573 | if not p then die("--keep option needs a string to match for") end 574 | option.KEEP = p 575 | i = i + 1 576 | elseif o == "--plugin" then 577 | if not p then die("--plugin option needs a module name") end 578 | if option.PLUGIN then die("only one plugin can be specified") end 579 | option.PLUGIN = p 580 | plugin = require(PLUGIN_SUFFIX..p) 581 | i = i + 1 582 | elseif o == "--quiet" then 583 | option.QUIET = true 584 | elseif o == "--read-only" then 585 | option.READ_ONLY = true 586 | elseif o == "--basic" then 587 | set_options(BASIC_CONFIG) 588 | elseif o == "--maximum" then 589 | set_options(MAXIMUM_CONFIG) 590 | elseif o == "--none" then 591 | set_options(NONE_CONFIG) 592 | elseif o == "--dump-lexer" then 593 | option.DUMP_LEXER = true 594 | elseif o == "--dump-parser" then 595 | option.DUMP_PARSER = true 596 | elseif o == "--details" then 597 | option.DETAILS = true 598 | elseif OPTION[o] then -- lookup optimization options 599 | set_options(o) 600 | else 601 | die("unrecognized option "..o) 602 | end 603 | else 604 | fspec[#fspec + 1] = o -- potential filename 605 | end 606 | i = i + 1 607 | end--while 608 | if option.HELP then 609 | print(MSG_TITLE..MSG_USAGE); return true 610 | elseif option.VERSION then 611 | print(MSG_TITLE); return true 612 | end 613 | if option["opt-binequiv"] and not BIN_EQUIV_AVAIL then 614 | die("--opt-binequiv is available only for PUC Lua 5.1!") 615 | end 616 | if #fspec > 0 then 617 | if #fspec > 1 and option.OUTPUT_FILE then 618 | die("with -o, only one source file can be specified") 619 | end 620 | do_files(fspec) 621 | return true 622 | else 623 | die("nothing to do!") 624 | end 625 | end 626 | 627 | -- entry point -> main() -> do_files() 628 | if not main() then 629 | die("Please run with option -h or --help for usage information") 630 | end 631 | -------------------------------------------------------------------------------- /Lua/Minifier/utils.lua: -------------------------------------------------------------------------------- 1 | --------- 2 | -- General utility functions. 3 | -- 4 | -- **Note: This module is not part of public API!** 5 | ---- 6 | local ipairs = ipairs 7 | local pairs = pairs 8 | 9 | local M = {} 10 | 11 | --- Returns a new table containing the contents of all the given tables. 12 | -- Tables are iterated using @{pairs}, so this function is intended for tables 13 | -- that represent *associative arrays*. Entries with duplicate keys are 14 | -- overwritten with the values from a later table. 15 | -- 16 | -- @tparam {table,...} ... The tables to merge. 17 | -- @treturn table A new table. 18 | function M.merge (...) 19 | local result = {} 20 | 21 | for _, tab in ipairs{...} do 22 | for key, val in pairs(tab) do 23 | result[key] = val 24 | end 25 | end 26 | 27 | return result 28 | end 29 | 30 | return M 31 | -------------------------------------------------------------------------------- /Lua/compress.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | MIT License 3 | 4 | Copyright (c) 2016 Rochet2 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | ]] 24 | 25 | local char = string.char 26 | local type = type 27 | local select = select 28 | local sub = string.sub 29 | local tconcat = table.concat 30 | 31 | local basedictcompress = {} 32 | local basedictdecompress = {} 33 | for i = 0, 255 do 34 | local ic, iic = char(i), char(i, 0) 35 | basedictcompress[ic] = iic 36 | basedictdecompress[iic] = ic 37 | end 38 | 39 | local function dictAddA(str, dict, a, b) 40 | if a >= 256 then 41 | a, b = 0, b+1 42 | if b >= 256 then 43 | dict = {} 44 | b = 1 45 | end 46 | end 47 | dict[str] = char(a,b) 48 | a = a+1 49 | return dict, a, b 50 | end 51 | 52 | local function compress(input) 53 | if type(input) ~= "string" then 54 | return nil, "string expected, got "..type(input) 55 | end 56 | local len = #input 57 | if len <= 1 then 58 | return "u"..input 59 | end 60 | 61 | local dict = {} 62 | local a, b = 0, 1 63 | 64 | local result = {"c"} 65 | local resultlen = 1 66 | local n = 2 67 | local word = "" 68 | for i = 1, len do 69 | local c = sub(input, i, i) 70 | local wc = word..c 71 | if not (basedictcompress[wc] or dict[wc]) then 72 | local write = basedictcompress[word] or dict[word] 73 | if not write then 74 | return nil, "algorithm error, could not fetch word" 75 | end 76 | result[n] = write 77 | resultlen = resultlen + #write 78 | n = n+1 79 | if len <= resultlen then 80 | return "u"..input 81 | end 82 | dict, a, b = dictAddA(wc, dict, a, b) 83 | word = c 84 | else 85 | word = wc 86 | end 87 | end 88 | result[n] = basedictcompress[word] or dict[word] 89 | resultlen = resultlen+#result[n] 90 | n = n+1 91 | if len <= resultlen then 92 | return "u"..input 93 | end 94 | return tconcat(result) 95 | end 96 | 97 | local DecompStr = [=[ 98 | local char = string.char 99 | local type = type 100 | local select = select 101 | local sub = string.sub 102 | local tconcat = table.concat 103 | 104 | local basedictdecompress = {} 105 | for i = 0, 255 do 106 | local ic, iic = char(i), char(i, 0) 107 | basedictdecompress[iic] = ic 108 | end 109 | 110 | local function dictAddB(str, dict, a, b) 111 | if a >= 256 then 112 | a, b = 0, b+1 113 | if b >= 256 then 114 | dict = {} 115 | b = 1 116 | end 117 | end 118 | dict[char(a,b)] = str 119 | a = a+1 120 | return dict, a, b 121 | end 122 | 123 | local function decompress(input) 124 | local control = sub(input, 1, 1) 125 | input = sub(input, 2) 126 | local len = #input 127 | 128 | local dict = {} 129 | local a, b = 0, 1 130 | 131 | local result = {} 132 | local n = 1 133 | local last = sub(input, 1, 2) 134 | result[n] = basedictdecompress[last] or dict[last] 135 | n = n+1 136 | for i = 3, len, 2 do 137 | local code = sub(input, i, i+1) 138 | local lastStr = basedictdecompress[last] or dict[last] 139 | local toAdd = basedictdecompress[code] or dict[code] 140 | if toAdd then 141 | result[n] = toAdd 142 | n = n+1 143 | dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b) 144 | else 145 | local tmp = lastStr..sub(lastStr, 1, 1) 146 | result[n] = tmp 147 | n = n+1 148 | dict, a, b = dictAddB(tmp, dict, a, b) 149 | end 150 | last = code 151 | end 152 | return tconcat(result) 153 | end 154 | 155 | loadstring(decompress('STRING'))(); 156 | ]=]; 157 | 158 | local Args = {...}; 159 | local FN = Args[1]; 160 | 161 | local F = io.open(FN, 'r'); 162 | if (not F) then 163 | return print'-- FAILURE TO COMPRESS'; 164 | end; 165 | local Str = F:read'*all'; 166 | F:close(); 167 | 168 | local Comp = compress(Str); 169 | local NewS = ''; 170 | for Idx = 1, #Comp do 171 | NewS = NewS .. '\\' .. Comp:sub(Idx, Idx):byte(); 172 | end; 173 | 174 | DecompStr = DecompStr:gsub('STRING', NewS); 175 | package.path = package.path .. ";../Lua/?.lua" 176 | 177 | local Minify = require'minify'; 178 | 179 | local AST = Minify.CreateLuaParser(DecompStr); 180 | local GS, RS = Minify.AddVariableInfo(AST); 181 | Minify.MinifyVariables(GS, RS); 182 | Minify.StripAst(AST); 183 | Minify.PrintAst(AST); --------------------------------------------------------------------------------