├── 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);
--------------------------------------------------------------------------------