├── dnlib.dll ├── MemeVM.Runtime ├── NoMoreStackItem.cs ├── Engine │ ├── VMState.cs │ ├── LocalStorage.cs │ ├── Stack.cs │ └── VM.cs ├── Instruction.cs ├── IHandler.cs ├── Handlers │ ├── Pop.cs │ ├── Null.cs │ ├── Ret.cs │ ├── Jmp.cs │ ├── Int.cs │ ├── Long.cs │ ├── Ldarg.cs │ ├── Ldloc.cs │ ├── Stloc.cs │ ├── Add.cs │ ├── Cgt.cs │ ├── Clt.cs │ ├── Cmp.cs │ ├── Dup.cs │ ├── Jf.cs │ ├── Jt.cs │ ├── String.cs │ ├── Ldfld.cs │ ├── Newarr.cs │ ├── Stfld.cs │ └── Call.cs ├── Entry.cs ├── OpCode.cs ├── Dispatcher.cs ├── Helpers │ └── Map.cs ├── Properties │ └── AssemblyInfo.cs ├── Body.cs └── MemeVM.Runtime.csproj ├── Confuser.Core.dll ├── MemeVM.Confuser ├── Program.cs ├── App.config ├── MemeVMProtection.cs ├── Properties │ └── AssemblyInfo.cs └── MemeVM.Confuser.csproj ├── MemeVM ├── Translation │ ├── Helpers │ │ ├── Offset.cs │ │ ├── TokenGetter.cs │ │ ├── Offsets.cs │ │ └── Map.cs │ ├── VMInstruction.cs │ ├── IHandler.cs │ ├── Handlers │ │ ├── Dup.cs │ │ ├── Ret.cs │ │ ├── Ldelem.cs │ │ ├── Add.cs │ │ ├── Pop.cs │ │ ├── Useless.cs │ │ ├── Ldnull.cs │ │ ├── Int.cs │ │ ├── Long.cs │ │ ├── Ldarg.cs │ │ ├── Ldloc.cs │ │ ├── Starg.cs │ │ ├── Stloc.cs │ │ ├── Ldstr.cs │ │ ├── Ldfld.cs │ │ ├── Stfld.cs │ │ ├── Newarr.cs │ │ ├── Comparisons.cs │ │ ├── Call.cs │ │ └── Branching.cs │ ├── VMOpCode.cs │ ├── Dispatcher.cs │ └── VMBody.cs ├── Context.cs ├── Properties │ └── AssemblyInfo.cs ├── InjectPhase.cs ├── MemeVM.csproj └── VirtualizatonPhase.cs ├── README.md ├── MemeVM.sln ├── .gitattributes └── .gitignore /dnlib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobitoFatitoRE/MemeVM/HEAD/dnlib.dll -------------------------------------------------------------------------------- /MemeVM.Runtime/NoMoreStackItem.cs: -------------------------------------------------------------------------------- 1 | namespace MemeVM.Runtime { struct NoMoreStackItem { } } -------------------------------------------------------------------------------- /Confuser.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobitoFatitoRE/MemeVM/HEAD/Confuser.Core.dll -------------------------------------------------------------------------------- /MemeVM.Runtime/Engine/VMState.cs: -------------------------------------------------------------------------------- 1 | namespace MemeVM.Runtime.Engine { 2 | enum VMState { 3 | Next, 4 | Exception, 5 | Rethrow, 6 | Return 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /MemeVM.Confuser/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MemeVM.Confuser { 4 | class Program { 5 | static void Main(string[] args) { 6 | // 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /MemeVM.Confuser/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MemeVM/Translation/Helpers/Offset.cs: -------------------------------------------------------------------------------- 1 | namespace MemeVM.Translation.Helpers { 2 | struct Offset { 3 | internal Offset(int start, int val) { 4 | Starts = start; 5 | Value = val; 6 | } 7 | 8 | internal int Starts; 9 | internal int Value; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Instruction.cs: -------------------------------------------------------------------------------- 1 | namespace MemeVM.Runtime { 2 | struct Instruction { 3 | internal Instruction(OpCode code, object op = null) { 4 | Code = code; 5 | Operand = op; 6 | } 7 | 8 | internal OpCode Code; 9 | internal object Operand; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MemeVM.Runtime/IHandler.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime { 5 | interface IHandler { 6 | OpCode Handles { get; } 7 | void Handle(VM machine, Body body, Instruction instruction); 8 | Instruction Deserialize(BinaryReader reader); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MemeVM/Translation/VMInstruction.cs: -------------------------------------------------------------------------------- 1 | namespace MemeVM.Translation { 2 | struct VMInstruction { 3 | internal VMInstruction(VMOpCode code, object op = null) { 4 | OpCode = code; 5 | Operand = op; 6 | } 7 | 8 | internal VMOpCode OpCode; 9 | internal object Operand; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MemeVM/Translation/Helpers/TokenGetter.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Writer; 3 | 4 | namespace MemeVM.Translation.Helpers { 5 | static class TokenGetter { 6 | internal static ModuleWriterBase Writer; 7 | 8 | internal static int GetMdToken(IMemberDef member) => 9 | Writer.Module == member.Module ? Writer.MetaData.GetToken(member).ToInt32() : member.MDToken.ToInt32(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Pop.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Pop : IHandler { 6 | public OpCode Handles => OpCode.Pop; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.Stack.Pop(); 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Pop); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Null.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Null : IHandler { 6 | public OpCode Handles => OpCode.Null; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.Stack.Push(null); 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Null); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Ret.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Ret : IHandler { 6 | public OpCode Handles => OpCode.Ret; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.State = VMState.Return; 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Ret); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM/Context.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet; 4 | using MemeVM.Translation; 5 | 6 | namespace MemeVM { 7 | static class Context { 8 | internal static IMethod Entry; 9 | internal static ModuleDef RuntimeModule; 10 | internal static readonly Random Random = new Random(); 11 | internal static readonly Dictionary Bodies = new Dictionary(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM/Translation/IHandler.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using MemeVM.Translation.Helpers; 4 | 5 | namespace MemeVM.Translation { 6 | interface IHandler { 7 | OpCode[] Translates { get; } 8 | VMOpCode Output { get; } 9 | VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success); 10 | byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Jmp.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Jmp : IHandler { 6 | public OpCode Handles => OpCode.Jmp; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.Ip = (int) instruction.Operand; 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Jmp, reader.ReadInt32()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Int.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Int : IHandler { 6 | public OpCode Handles => OpCode.Int32; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.Stack.Push(instruction.Operand); 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Int32, reader.ReadInt32()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Long.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Long : IHandler { 6 | public OpCode Handles => OpCode.Int64; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.Stack.Push(instruction.Operand); 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Int64, reader.ReadInt64()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Ldarg.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Ldarg : IHandler { 6 | public OpCode Handles => OpCode.Ldarg; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.Stack.Push(machine.Parameters[(short)instruction.Operand]); 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Ldarg, reader.ReadInt16()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Ldloc.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Ldloc : IHandler { 6 | public OpCode Handles => OpCode.Ldloc; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.Stack.Push(machine.Locals.Get((short)instruction.Operand)); 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Ldloc, reader.ReadInt16()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Stloc.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Stloc : IHandler { 6 | public OpCode Handles => OpCode.Stloc; 7 | public void Handle(VM machine, Body body, Instruction instruction) => 8 | machine.Locals.Set((short) instruction.Operand, machine.Stack.Pop()); 9 | 10 | public Instruction Deserialize(BinaryReader reader) => 11 | new Instruction(OpCode.Stloc, reader.ReadInt16()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Add.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Add : IHandler { 6 | public OpCode Handles => OpCode.Add; 7 | public void Handle(VM machine, Body body, Instruction instruction) { 8 | dynamic one = machine.Stack.Pop(), two = machine.Stack.Pop(); 9 | 10 | machine.Stack.Push(one + two); 11 | } 12 | 13 | public Instruction Deserialize(BinaryReader reader) => 14 | new Instruction(OpCode.Add); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Cgt.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Cgt : IHandler { 6 | public OpCode Handles => OpCode.Cgt; 7 | public void Handle(VM machine, Body body, Instruction instruction) { 8 | dynamic one = machine.Stack.Pop(), two = machine.Stack.Pop(); 9 | 10 | machine.Stack.Push(one > two); 11 | } 12 | 13 | public Instruction Deserialize(BinaryReader reader) => 14 | new Instruction(OpCode.Cgt); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Clt.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Clt : IHandler { 6 | public OpCode Handles => OpCode.Clt; 7 | public void Handle(VM machine, Body body, Instruction instruction) { 8 | dynamic one = machine.Stack.Pop(), two = machine.Stack.Pop(); 9 | 10 | machine.Stack.Push(one < two); 11 | } 12 | 13 | public Instruction Deserialize(BinaryReader reader) => 14 | new Instruction(OpCode.Clt); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Cmp.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Cmp : IHandler { 6 | public OpCode Handles => OpCode.Cmp; 7 | public void Handle(VM machine, Body body, Instruction instruction) { 8 | dynamic one = machine.Stack.Pop(), two = machine.Stack.Pop(); 9 | 10 | machine.Stack.Push(one == two); 11 | } 12 | 13 | public Instruction Deserialize(BinaryReader reader) => 14 | new Instruction(OpCode.Cmp); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Dup.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Dup : IHandler { 6 | public OpCode Handles => OpCode.Dup; 7 | public void Handle(VM machine, Body body, Instruction instruction) { 8 | var value = machine.Stack.Pop(); 9 | machine.Stack.Push(value); 10 | machine.Stack.Push(value); 11 | } 12 | 13 | public Instruction Deserialize(BinaryReader reader) => 14 | new Instruction(OpCode.Dup); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MemeVM/Translation/Helpers/Offsets.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace MemeVM.Translation.Helpers { 5 | class Offsets { 6 | internal Offsets() => 7 | _offsets = new List(); 8 | 9 | readonly List _offsets; 10 | 11 | internal void Add(int index, int offset) => 12 | _offsets.Add(new Offset(index, offset)); 13 | 14 | internal int Get(int index) => 15 | _offsets.Where(o => o.Starts < index).Sum(off => off.Value) - 1 + index; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MemeVM 2 | A small virtualizer for .NET which works together with ConfuserEx 3 | 4 | ## Wtf is this???! 5 | 6 | This projects takes your existing .NET MSIL code and "translates" it to instructions only our virtual machine will understand. 7 | 8 | ## Limitations 9 | 10 | - Can be slow 11 | - Lots of unimplemented OpCodes 12 | - Branching is buggy 13 | - No support for typed references 14 | - No support for pointers 15 | 16 | # Note 17 | 18 | This is not meant to be used as a serious layer of Obfuscation, it was just an experiment. 19 | Feel free to commit if you have any improvements 20 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Jf.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Jf : IHandler { 6 | public OpCode Handles => OpCode.Jf; 7 | public void Handle(VM machine, Body body, Instruction instruction) { 8 | var value = machine.Stack.Pop(); 9 | if (value == null || !(bool)value) 10 | machine.Ip = (int)instruction.Operand; 11 | } 12 | 13 | public Instruction Deserialize(BinaryReader reader) => 14 | new Instruction(OpCode.Jf, reader.ReadInt32()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Jt.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using MemeVM.Runtime.Engine; 3 | 4 | namespace MemeVM.Runtime.Handlers { 5 | class Jt : IHandler { 6 | public OpCode Handles => OpCode.Jt; 7 | public void Handle(VM machine, Body body, Instruction instruction) { 8 | var value = machine.Stack.Pop(); 9 | if (value != null && (bool) value) 10 | machine.Ip = (int)instruction.Operand; 11 | } 12 | 13 | public Instruction Deserialize(BinaryReader reader) => 14 | new Instruction(OpCode.Jt, reader.ReadInt32()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Entry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MemeVM.Runtime 4 | { 5 | public static class Entry { 6 | public static T Run(RuntimeTypeHandle handle, int index, object[] parameters) { 7 | var result = Dispatcher.Run(Type.GetTypeFromHandle(handle).Assembly, index, parameters); 8 | 9 | if (result is NoMoreStackItem) 10 | return default(T); 11 | 12 | if (typeof(T).IsEnum) 13 | return (T)Enum.ToObject(typeof(T), result); 14 | 15 | return (T)Convert.ChangeType(result, typeof(T)); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/String.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | using MemeVM.Runtime.Engine; 4 | 5 | namespace MemeVM.Runtime.Handlers { 6 | class String : IHandler { 7 | public OpCode Handles => OpCode.String; 8 | public void Handle(VM machine, Body body, Instruction instruction) => 9 | machine.Stack.Push(instruction.Operand); 10 | 11 | public Instruction Deserialize(BinaryReader reader) { 12 | var len = reader.ReadInt32(); 13 | 14 | return new Instruction(OpCode.String, Encoding.UTF8.GetString(reader.ReadBytes(len))); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Dup.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using MemeVM.Translation.Helpers; 4 | 5 | namespace MemeVM.Translation.Handlers { 6 | class Dup : IHandler { 7 | public OpCode[] Translates => new[] { OpCodes.Dup }; 8 | public VMOpCode Output => VMOpCode.Dup; 9 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 10 | success = true; 11 | return new VMInstruction(VMOpCode.Dup); 12 | } 13 | 14 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) => 15 | new[] { (byte)VMOpCode.Dup }; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Ret.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using MemeVM.Translation.Helpers; 4 | 5 | namespace MemeVM.Translation.Handlers { 6 | class Ret : IHandler { 7 | public OpCode[] Translates => new[] { OpCodes.Ret }; 8 | public VMOpCode Output => VMOpCode.Ret; 9 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 10 | success = true; 11 | return new VMInstruction(VMOpCode.Ret); 12 | } 13 | 14 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 15 | return new[] { (byte)VMOpCode.Ret }; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Ldelem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | /*class Ldelem : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Ldelem, OpCodes.Ldelem_Ref }; 9 | public VMOpCode Output => VMOpCode.Ldelem; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | throw new NotImplementedException(); 12 | } 13 | 14 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 15 | throw new NotImplementedException(); 16 | } 17 | }*/ 18 | } 19 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Add.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using MemeVM.Translation.Helpers; 4 | 5 | namespace MemeVM.Translation.Handlers { 6 | class Add : IHandler { 7 | public OpCode[] Translates => new[] { OpCodes.Add, OpCodes.Add_Ovf, OpCodes.Add_Ovf_Un }; 8 | public VMOpCode Output => VMOpCode.Add; 9 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 10 | success = true; 11 | return new VMInstruction(VMOpCode.Add); 12 | } 13 | 14 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 15 | return new[] { (byte)VMOpCode.Add }; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Pop.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using MemeVM.Translation.Helpers; 4 | 5 | namespace MemeVM.Translation.Handlers { 6 | class Pop : IHandler { 7 | public OpCode[] Translates => new[] { OpCodes.Pop }; 8 | public VMOpCode Output => VMOpCode.Pop; 9 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 10 | success = true; 11 | return new VMInstruction(VMOpCode.Pop); 12 | } 13 | 14 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 15 | var buf = new byte[1]; 16 | buf[0] = (byte)VMOpCode.Pop; 17 | return buf; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Useless.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Useless : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Nop, OpCodes.Break }; 9 | public VMOpCode Output => VMOpCode.UNUSED; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | helper.Add(index, -1); 12 | success = true; 13 | return new VMInstruction(VMOpCode.UNUSED); 14 | } 15 | 16 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) => 17 | Array.Empty(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Ldnull.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using MemeVM.Translation.Helpers; 4 | 5 | namespace MemeVM.Translation.Handlers { 6 | class Ldnull : IHandler { 7 | public OpCode[] Translates => new[] { OpCodes.Ldnull }; 8 | public VMOpCode Output => VMOpCode.Null; 9 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 10 | success = true; 11 | return new VMInstruction(VMOpCode.Null); 12 | } 13 | 14 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 15 | var buf = new byte[1]; 16 | buf[0] = (byte)VMOpCode.Null; 17 | return buf; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MemeVM.Runtime/OpCode.cs: -------------------------------------------------------------------------------- 1 | namespace MemeVM.Runtime { 2 | enum OpCode : byte { 3 | Int32, 4 | Int64, 5 | Float, 6 | Double, 7 | String, 8 | Null, 9 | 10 | Add, 11 | Sub, 12 | Mul, 13 | Div, 14 | Rem, 15 | 16 | Dup, 17 | Pop, 18 | 19 | Jmp, 20 | Jt, 21 | Jf, 22 | Je, 23 | Jne, 24 | Jge, 25 | Jgt, 26 | Jle, 27 | Jlt, 28 | 29 | Cmp, 30 | Cgt, 31 | Clt, 32 | 33 | Newarr, 34 | 35 | Ldarg, 36 | Ldloc, 37 | Ldfld, 38 | Ldelem, 39 | 40 | Starg, 41 | Stloc, 42 | Stfld, 43 | Stelem, 44 | 45 | Call, 46 | 47 | Ret 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Engine/LocalStorage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MemeVM.Runtime.Engine { 4 | class LocalStorage { 5 | object[] _locals; 6 | 7 | internal LocalStorage() => 8 | _locals = new object[10]; 9 | 10 | ~LocalStorage() { 11 | Array.Clear(_locals, 0, _locals.Length); 12 | _locals = null; 13 | } 14 | 15 | internal object Get(short index) => 16 | _locals[index]; 17 | 18 | internal void Set(short index, object val) { 19 | if (index >= _locals.Length) { 20 | var arr = new object[2 * _locals.Length]; 21 | Array.Copy(_locals, 0, arr, 0, _locals.Length); 22 | _locals = arr; 23 | } 24 | 25 | _locals[index] = val; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Dispatcher.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | using MemeVM.Runtime.Engine; 4 | 5 | namespace MemeVM.Runtime { 6 | static class Dispatcher { 7 | static readonly Dictionary Bodies = new Dictionary(); 8 | 9 | internal static object Run(Assembly asm, int index, object[] parameters) { 10 | var body = GetBody(asm); 11 | body.CurrentAssembly = asm; 12 | 13 | var instance = new VM(body.GetMethod(index).ToArray(), body, parameters); 14 | return instance.Run(); 15 | } 16 | 17 | internal static Body GetBody(Assembly asm) { 18 | if (!Bodies.ContainsKey(asm)) 19 | Bodies.Add(asm, new Body(asm.GetManifestResourceStream(" "))); 20 | 21 | return Bodies[asm]; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MemeVM/Translation/VMOpCode.cs: -------------------------------------------------------------------------------- 1 | namespace MemeVM.Translation { 2 | enum VMOpCode : byte { 3 | Int32, 4 | Int64, 5 | Float, 6 | Double, 7 | String, 8 | Null, 9 | 10 | Add, 11 | Sub, 12 | Mul, 13 | Div, 14 | Rem, 15 | 16 | Dup, 17 | Pop, 18 | 19 | Jmp, 20 | Jt, 21 | Jf, 22 | Je, 23 | Jne, 24 | Jge, 25 | Jgt, 26 | Jle, 27 | Jlt, 28 | 29 | Cmp, 30 | Cgt, 31 | Clt, 32 | 33 | Newarr, 34 | 35 | Ldarg, 36 | Ldloc, 37 | Ldfld, 38 | Ldelem, 39 | 40 | Starg, 41 | Stloc, 42 | Stfld, 43 | Stelem, 44 | 45 | Call, 46 | 47 | Ret, 48 | 49 | //DONT CHANGE 50 | UNUSED 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Helpers/Map.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MemeVM.Runtime.Helpers { 6 | static class Map { 7 | static Map() { 8 | foreach (var type in typeof(Map).Module.GetTypes()) { 9 | if (type.IsInterface) 10 | continue; 11 | 12 | if (!typeof(IHandler).IsAssignableFrom(type)) 13 | continue; 14 | 15 | var instance = (IHandler)Activator.CreateInstance(type); 16 | OpCodeToHandler.Add(instance.Handles, instance); 17 | } 18 | } 19 | 20 | private static readonly Dictionary OpCodeToHandler = new Dictionary(); 21 | 22 | internal static IHandler Lookup(OpCode code) => 23 | OpCodeToHandler[code]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Ldfld.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using MemeVM.Runtime.Engine; 4 | 5 | namespace MemeVM.Runtime.Handlers { 6 | class Ldfld : IHandler { 7 | public OpCode Handles => OpCode.Ldfld; 8 | public void Handle(VM machine, Body body, Instruction instruction) { 9 | var id = ((Tuple)instruction.Operand).Item1; 10 | var token = ((Tuple)instruction.Operand).Item2; 11 | 12 | var asm = body.GetReference(id); 13 | var field = asm.ManifestModule.ResolveField(token); 14 | var obj = field.IsStatic ? null : machine.Stack.Pop(); 15 | machine.Stack.Push(field.GetValue(obj)); 16 | } 17 | 18 | public Instruction Deserialize(BinaryReader reader) => 19 | new Instruction(OpCode.Ldfld, new Tuple(reader.ReadInt16(), reader.ReadInt32())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Newarr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using MemeVM.Runtime.Engine; 4 | 5 | namespace MemeVM.Runtime.Handlers { 6 | class Newarr : IHandler { 7 | public OpCode Handles => OpCode.Newarr; 8 | public void Handle(VM machine, Body body, Instruction instruction) { 9 | var tuple = (Tuple)instruction.Operand; 10 | 11 | var refid = tuple.Item1; 12 | var token = tuple.Item2; 13 | 14 | var asm = body.GetReference(refid).ManifestModule; 15 | var type = asm.ResolveType(token); 16 | var length = (int)machine.Stack.Pop(); 17 | 18 | machine.Stack.Push(Array.CreateInstance(type, length)); 19 | } 20 | 21 | public Instruction Deserialize(BinaryReader reader) => 22 | new Instruction(OpCode.Newarr, new Tuple(reader.ReadInt16(), reader.ReadInt32())); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MemeVM.Confuser/MemeVMProtection.cs: -------------------------------------------------------------------------------- 1 | using Confuser.Core; 2 | 3 | namespace MemeVM.Confuser { 4 | [BeforeProtection("Ki.Resources", "Ki.Constants", "Ki.AntiTamper", "Ki.ControlFlow")] 5 | public class MemeVMProtection : Protection { 6 | public override string Name => "MemeVM"; 7 | public override string Description => "Virtualization for .NET"; 8 | public override string Id => "memevm"; 9 | public override string FullId => "xsilent007.MemeVM"; 10 | public override ProtectionPreset Preset => ProtectionPreset.None; 11 | 12 | protected override void Initialize(ConfuserContext context) { } 13 | 14 | protected override void PopulatePipeline(ProtectionPipeline pipeline) { 15 | pipeline.InsertPostStage(PipelineStage.Inspection, new InjectPhase(this)); 16 | pipeline.InsertPreStage(PipelineStage.ProcessModule, new VirtualizatonPhase(this)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Int.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Int : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Ldc_I4 }; 9 | public VMOpCode Output => VMOpCode.Int32; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | success = true; 12 | return new VMInstruction(VMOpCode.Int32, (int)method.Body.Instructions[index].Operand); 13 | } 14 | 15 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 16 | var buf = new byte[5]; 17 | buf[0] = (byte)VMOpCode.Int32; 18 | Array.Copy(BitConverter.GetBytes((int)instruction.Operand), 0, buf, 1, 4); 19 | 20 | return buf; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Long.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Long : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Ldc_I8 }; 9 | public VMOpCode Output => VMOpCode.Int64; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | success = true; 12 | return new VMInstruction(VMOpCode.Int32, (long)method.Body.Instructions[index].Operand); 13 | } 14 | 15 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 16 | var buf = new byte[9]; 17 | buf[0] = (byte)VMOpCode.Int64; 18 | 19 | Array.Copy(BitConverter.GetBytes((long)instruction.Operand), 0, buf, 1, 8); 20 | return buf; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Stfld.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using MemeVM.Runtime.Engine; 4 | 5 | namespace MemeVM.Runtime.Handlers { 6 | class Stfld : IHandler { 7 | public OpCode Handles => OpCode.Stfld; 8 | public void Handle(VM machine, Body body, Instruction instruction) { 9 | var id = ((Tuple)instruction.Operand).Item1; 10 | var token = ((Tuple)instruction.Operand).Item2; 11 | 12 | var asm = body.GetReference(id); 13 | var field = asm.ManifestModule.ResolveField(token); 14 | var obj = field.IsStatic ? null : machine.Stack.Pop(); 15 | field.SetValue(obj, Convert.ChangeType(machine.Stack.Pop(), field.FieldType)); 16 | } 17 | 18 | public Instruction Deserialize(BinaryReader reader) => 19 | new Instruction(OpCode.Stfld, new Tuple(reader.ReadInt16(), reader.ReadInt32())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MemeVM/Translation/Dispatcher.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using dnlib.DotNet; 3 | using MemeVM.Translation.Helpers; 4 | 5 | namespace MemeVM.Translation { 6 | static class Dispatcher { 7 | internal static List TranslateMethod(VMBody body, MethodDef method) { 8 | var list = new List(); 9 | 10 | for (var i = 0; i < method.Body.Instructions.Count; i++) { 11 | var translator = Map.Lookup(method.Body.Instructions[i].OpCode); 12 | if (translator == null) 13 | return null; 14 | 15 | var res = translator.Translate(body, method, i, body.OffsetHelper, out var good); 16 | if (res.OpCode != VMOpCode.UNUSED) list.Add(res); 17 | if (!good) 18 | return null; 19 | } 20 | 21 | //TODO: Exception handlers 22 | 23 | return list; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Ldarg.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Ldarg : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Ldarg }; 9 | public VMOpCode Output => VMOpCode.Ldarg; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | var arg = (short)method.Parameters.IndexOf((Parameter)method.Body.Instructions[index].Operand); 12 | success = true; 13 | return new VMInstruction(VMOpCode.Ldarg, arg); 14 | } 15 | 16 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 17 | var buf = new byte[3]; 18 | buf[0] = (byte)VMOpCode.Ldarg; 19 | Array.Copy(BitConverter.GetBytes((short)instruction.Operand), 0, buf, 1, 2); 20 | return buf; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Ldloc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Ldloc : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Ldloc }; 9 | public VMOpCode Output => VMOpCode.Ldloc; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | var loc = (short)method.Body.Variables.IndexOf((Local)method.Body.Instructions[index].Operand); 12 | success = true; 13 | return new VMInstruction(VMOpCode.Ldloc, loc); 14 | } 15 | 16 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 17 | var buf = new byte[3]; 18 | buf[0] = (byte)VMOpCode.Ldloc; 19 | Array.Copy(BitConverter.GetBytes((short)instruction.Operand), 0, buf, 1, 2); 20 | return buf; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Starg.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Starg : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Starg }; 9 | public VMOpCode Output => VMOpCode.Starg; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | var arg = (short)method.Parameters.IndexOf((Parameter)method.Body.Instructions[index].Operand); 12 | success = true; 13 | return new VMInstruction(VMOpCode.Starg, arg); 14 | } 15 | 16 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 17 | var buf = new byte[3]; 18 | buf[0] = (byte)VMOpCode.Starg; 19 | Array.Copy(BitConverter.GetBytes((short)instruction.Operand), 0, buf, 1, 2); 20 | return buf; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Stloc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Stloc : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Stloc }; 9 | public VMOpCode Output => VMOpCode.Stloc; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | var loc = (short)method.Body.Variables.IndexOf((Local)method.Body.Instructions[index].Operand); 12 | success = true; 13 | return new VMInstruction(VMOpCode.Stloc, loc); 14 | } 15 | 16 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 17 | var buf = new byte[3]; 18 | buf[0] = (byte)VMOpCode.Stloc; 19 | Array.Copy(BitConverter.GetBytes((short)instruction.Operand), 0, buf, 1, 2); 20 | return buf; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Engine/Stack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MemeVM.Runtime.Engine { 4 | class Stack { 5 | object[] _array; 6 | uint _index; 7 | 8 | internal Stack() { 9 | _array = new object[10]; 10 | _index = 0; 11 | } 12 | 13 | ~Stack() { 14 | Array.Clear(_array, 0, _array.Length); 15 | _array = null; 16 | _index = 0; 17 | } 18 | 19 | internal void Push(object val) { 20 | if (_index == _array.Length) { 21 | var arr = new object[2 * _array.Length]; 22 | Array.Copy(_array, 0, arr, 0, _index); 23 | _array = arr; 24 | } 25 | 26 | _array[_index++] = val; 27 | } 28 | 29 | internal object Pop() { 30 | if (_index == 0) 31 | return new NoMoreStackItem(); 32 | 33 | var res = _array[--_index]; 34 | _array[_index] = null; 35 | return res; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Engine/VM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MemeVM.Runtime.Helpers; 3 | 4 | namespace MemeVM.Runtime.Engine { 5 | class VM { 6 | readonly Instruction[] _instructions; 7 | 8 | internal int Ip; 9 | internal VMState State; 10 | internal readonly Stack Stack; 11 | internal readonly LocalStorage Locals; 12 | internal readonly Body VMBody; 13 | internal object[] Parameters; 14 | 15 | internal VM(Instruction[] program, Body body, object[] parameters) { 16 | _instructions = program; 17 | 18 | Ip = 0; 19 | State = VMState.Next; 20 | Stack = new Stack(); 21 | Locals = new LocalStorage(); 22 | VMBody = body; 23 | Parameters = parameters; 24 | } 25 | 26 | internal object Run() { 27 | for (;State == VMState.Next; ++Ip) 28 | Map.Lookup(_instructions[Ip].Code).Handle(this, VMBody, _instructions[Ip]); 29 | 30 | if (State == VMState.Return) 31 | return Stack.Pop(); 32 | 33 | throw (Exception)Stack.Pop(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Ldstr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using dnlib.DotNet; 7 | using dnlib.DotNet.Emit; 8 | using MemeVM.Translation.Helpers; 9 | 10 | namespace MemeVM.Translation.Handlers { 11 | class Ldstr : IHandler { 12 | public OpCode[] Translates => new[] { OpCodes.Ldstr }; 13 | public VMOpCode Output => VMOpCode.String; 14 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 15 | var operand = (string)method.Body.Instructions[index].Operand; 16 | 17 | success = true; 18 | return new VMInstruction(VMOpCode.String, operand); 19 | } 20 | 21 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 22 | var str = Encoding.UTF8.GetBytes((string)instruction.Operand); 23 | var buf = new byte[5 + str.Length]; 24 | buf[0] = (byte)VMOpCode.String; 25 | Array.Copy(BitConverter.GetBytes(str.Length), 0, buf, 1, 4); 26 | Array.Copy(str, 0, buf, 5, str.Length); 27 | return buf; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /MemeVM/Translation/Helpers/Map.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet.Emit; 4 | 5 | namespace MemeVM.Translation.Helpers { 6 | static class Map { 7 | static Map() { 8 | foreach (var type in typeof(Map).Assembly.DefinedTypes) { 9 | if (type.IsInterface) 10 | continue; 11 | 12 | if (!typeof(IHandler).IsAssignableFrom(type)) 13 | continue; 14 | 15 | var instance = (IHandler)Activator.CreateInstance(type); 16 | 17 | foreach (var regular in instance.Translates) 18 | OpCodeToHandler.Add(regular, instance); 19 | 20 | VMOpCodeToHandler.Add(instance.Output, instance); 21 | } 22 | } 23 | 24 | static readonly Dictionary OpCodeToHandler = new Dictionary(); 25 | static readonly Dictionary VMOpCodeToHandler = new Dictionary(); 26 | 27 | internal static IHandler Lookup(OpCode opcode) => 28 | OpCodeToHandler.ContainsKey(opcode) ? OpCodeToHandler[opcode] : null; 29 | 30 | internal static IHandler Lookup(VMOpCode opcode) => 31 | VMOpCodeToHandler.ContainsKey(opcode) ? VMOpCodeToHandler[opcode] : null; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /MemeVM/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MemeVM")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MemeVM")] 13 | [assembly: AssemblyCopyright("Copyright © xsilent007 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ef18f7f2-1f03-481c-98f9-4a18a2f12c11")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Ldfld.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Ldfld : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Ldfld, OpCodes.Ldsfld }; 9 | public VMOpCode Output => VMOpCode.Ldfld; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | var op = ((IField)method.Body.Instructions[index].Operand).ResolveFieldDef(); 12 | if (op == null) { 13 | success = false; 14 | return new VMInstruction(VMOpCode.UNUSED); 15 | } 16 | 17 | var fqname = op.Module.Assembly.FullName; 18 | if (!body.References.Contains(fqname)) 19 | body.References.Add(fqname); 20 | 21 | success = true; 22 | return new VMInstruction(VMOpCode.Ldfld, new Tuple((short)body.References.IndexOf(fqname), op)); 23 | } 24 | 25 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 26 | var buf = new byte[7]; 27 | buf[0] = (byte)VMOpCode.Ldfld; 28 | var (refid, field) = (Tuple)instruction.Operand; 29 | Array.Copy(BitConverter.GetBytes(refid), 0, buf, 1, 2); 30 | Array.Copy(BitConverter.GetBytes(TokenGetter.GetMdToken(field)), 0, buf, 3, 4); 31 | return buf; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Stfld.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Stfld : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Stfld, OpCodes.Stsfld }; 9 | public VMOpCode Output => VMOpCode.Stfld; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | var op = ((IField)method.Body.Instructions[index].Operand).ResolveFieldDef(); 12 | if (op == null) { 13 | success = false; 14 | return new VMInstruction(VMOpCode.UNUSED); 15 | } 16 | 17 | var fqname = op.Module.Assembly.FullName; 18 | if (!body.References.Contains(fqname)) 19 | body.References.Add(fqname); 20 | 21 | success = true; 22 | return new VMInstruction(VMOpCode.Stfld, new Tuple((short)body.References.IndexOf(fqname), op)); 23 | } 24 | 25 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 26 | var buf = new byte[7]; 27 | buf[0] = (byte)VMOpCode.Stfld; 28 | var (refid, field) = (Tuple)instruction.Operand; 29 | Array.Copy(BitConverter.GetBytes(refid), 0, buf, 1, 2); 30 | Array.Copy(BitConverter.GetBytes(TokenGetter.GetMdToken(field)), 0, buf, 3, 4); 31 | return buf; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /MemeVM.Confuser/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MemeVM.Confuser")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MemeVM.Confuser")] 13 | [assembly: AssemblyCopyright("Copyright © xsilent007 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("77b2c83b-ca34-4738-9384-c52f0121647c")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | 38 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Newarr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | //TODO: Generics 8 | class Newarr : IHandler { 9 | public OpCode[] Translates => new[] { OpCodes.Newarr }; 10 | public VMOpCode Output => VMOpCode.Newarr; 11 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 12 | var type = ((ITypeDefOrRef)method.Body.Instructions[index].Operand).ResolveTypeDef(); 13 | if (type == null) { 14 | success = false; 15 | return new VMInstruction(VMOpCode.UNUSED); 16 | } 17 | 18 | var fqname = type.Module.Assembly.FullName; 19 | if (!body.References.Contains(fqname)) 20 | body.References.Add(fqname); 21 | 22 | success = true; 23 | return new VMInstruction(VMOpCode.Newarr, new Tuple((short)body.References.IndexOf(fqname), type)); 24 | } 25 | 26 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 27 | var buf = new byte[7]; 28 | buf[0] = (byte)VMOpCode.Newarr; 29 | var (referenceid, type) = (Tuple)instruction.Operand; 30 | Array.Copy(BitConverter.GetBytes(referenceid), 0, buf, 1, 2); 31 | Array.Copy(BitConverter.GetBytes(TokenGetter.GetMdToken(type)), 0, buf, 3, 4); 32 | return buf; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /MemeVM/Translation/VMBody.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using dnlib.DotNet; 5 | using MemeVM.Translation.Helpers; 6 | 7 | namespace MemeVM.Translation { 8 | class VMBody { 9 | internal VMBody() { 10 | References = new List(); 11 | MethodToIndex = new Dictionary(); 12 | Translated = new Dictionary>(); 13 | OffsetHelper = new Offsets(); 14 | } 15 | 16 | internal List References; 17 | internal Dictionary MethodToIndex; 18 | internal Dictionary> Translated; 19 | internal Offsets OffsetHelper; 20 | 21 | internal byte[] Serialize() { 22 | var arr = new List(); 23 | 24 | var rCount = References.Count; 25 | arr.AddRange(BitConverter.GetBytes(rCount)); 26 | foreach (var reference in References) { 27 | arr.AddRange(BitConverter.GetBytes(reference.Length)); 28 | arr.AddRange(Encoding.UTF8.GetBytes(reference)); 29 | } 30 | 31 | var mCount = Translated.Count; 32 | arr.AddRange(BitConverter.GetBytes(mCount)); 33 | foreach (var method in Translated.Values) { 34 | arr.AddRange(BitConverter.GetBytes(method.Count)); 35 | foreach (var instruction in method) { 36 | arr.AddRange(Map.Lookup(instruction.OpCode).Serialize(this, instruction, OffsetHelper)); 37 | } 38 | } 39 | 40 | return arr.ToArray(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Comparisons.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using MemeVM.Translation.Helpers; 4 | 5 | namespace MemeVM.Translation.Handlers { 6 | class Ceq : IHandler { 7 | public OpCode[] Translates => new[] { OpCodes.Ceq }; 8 | public VMOpCode Output => VMOpCode.Cmp; 9 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 10 | success = true; 11 | return new VMInstruction(VMOpCode.Cmp); 12 | } 13 | 14 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) => 15 | new[] { (byte)VMOpCode.Cmp }; 16 | } 17 | 18 | class Cgt : IHandler { 19 | public OpCode[] Translates => new[] { OpCodes.Cgt }; 20 | public VMOpCode Output => VMOpCode.Cgt; 21 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 22 | success = true; 23 | return new VMInstruction(VMOpCode.Cgt); 24 | } 25 | 26 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) => 27 | new[] { (byte)VMOpCode.Cgt }; 28 | } 29 | 30 | class Clt : IHandler { 31 | public OpCode[] Translates => new[] { OpCodes.Clt }; 32 | public VMOpCode Output => VMOpCode.Clt; 33 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 34 | success = true; 35 | return new VMInstruction(VMOpCode.Clt); 36 | } 37 | 38 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) => 39 | new[] { (byte)VMOpCode.Clt }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MemeVM.Runtime")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MemeVM.Runtime")] 13 | [assembly: AssemblyCopyright("Copyright © xsilent007 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("14d5d12e-9a32-4516-904e-df3393626317")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | 38 | [assembly: Obfuscation(Exclude = false, Feature = "+ref proxy(mode=strong,encoding=expression,internal=true,typeErasure=true);+ctrl flow(predicate=expression);+rename(renEnum=true);+constants(mode=dynamic,elements=SNPI,cfg=true)")] 39 | -------------------------------------------------------------------------------- /MemeVM/InjectPhase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using Confuser.Core; 7 | using dnlib.DotNet; 8 | 9 | namespace MemeVM { 10 | public class InjectPhase : ProtectionPhase { 11 | public InjectPhase(ConfuserComponent parent) : base(parent) { } 12 | public override string Name => "MemeVM.Injection"; 13 | public override ProtectionTargets Targets => ProtectionTargets.Methods; 14 | 15 | protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { 16 | if (!parameters.Targets.Any()) 17 | return; 18 | 19 | var current = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException(); 20 | var runtimePath = Path.Combine(current, "MemeVM.Runtime.dll"); 21 | var newPath = Path.Combine(context.OutputDirectory, "MemeVM.Runtime.dll"); 22 | 23 | var cliPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Confuser.CLI.exe"); 24 | 25 | Directory.CreateDirectory(Path.GetDirectoryName(newPath)); 26 | File.Copy(runtimePath, newPath, true); 27 | 28 | context.Logger.Info("Protecting VM runtime..."); 29 | var info = new ProcessStartInfo { 30 | FileName = cliPath, 31 | Arguments = "-n -o " + context.OutputDirectory + " " + newPath, 32 | CreateNoWindow = true, 33 | UseShellExecute = false, 34 | WindowStyle = ProcessWindowStyle.Hidden 35 | }; 36 | Process.Start(info)?.WaitForExit(); 37 | 38 | Context.RuntimeModule = ModuleDefMD.Load(newPath); 39 | Context.Entry = Context.RuntimeModule.Types.Single(t => t.IsPublic).Methods[0]; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Call.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | //TODO: Generic methods... 8 | class Call : IHandler { 9 | public OpCode[] Translates => new[] { OpCodes.Call, OpCodes.Callvirt, OpCodes.Newobj }; 10 | public VMOpCode Output => VMOpCode.Call; 11 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 12 | var operand = method.Body.Instructions[index].Operand; 13 | if (operand is MethodSpec) { 14 | success = false; 15 | return new VMInstruction(VMOpCode.UNUSED); 16 | } 17 | 18 | var target = ((IMethod)operand).ResolveMethodDef(); 19 | var fqname = target.Module.Assembly.FullName; 20 | if (!body.References.Contains(fqname)) 21 | body.References.Add(fqname); 22 | 23 | success = true; 24 | return new VMInstruction(VMOpCode.Call, new Tuple((short)body.References.IndexOf(fqname), target)); 25 | } 26 | 27 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 28 | var buf = new byte[8]; 29 | buf[0] = (byte)VMOpCode.Call; 30 | var (referenceId, method) = (Tuple)instruction.Operand; 31 | 32 | if (!body.Translated.ContainsKey(method)) { 33 | Array.Copy(BitConverter.GetBytes(referenceId), 0, buf, 1, 2); 34 | Array.Copy(BitConverter.GetBytes(TokenGetter.GetMdToken(method)), 0, buf, 3, 4); 35 | buf[7] = 0; 36 | return buf; 37 | } 38 | 39 | Array.Copy(BitConverter.GetBytes((short)body.MethodToIndex[method]), 0, buf, 1, 2); 40 | Array.Copy(BitConverter.GetBytes(method.Parameters.Count), 0, buf, 3, 4); 41 | buf[7] = 1; 42 | return buf; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Body.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using MemeVM.Runtime.Helpers; 9 | 10 | namespace MemeVM.Runtime { 11 | class Body { 12 | internal Body(Stream resourceStream) { 13 | _references = new Dictionary(); 14 | _methods = new List>(); 15 | 16 | using (var def = new DeflateStream(resourceStream, CompressionMode.Decompress)) { 17 | using (var reader = new BinaryReader(def)) { 18 | var rCount = reader.ReadInt32(); 19 | for (var i = 0; i < rCount; i++) { 20 | var len = reader.ReadInt32(); 21 | _references.Add(Encoding.UTF8.GetString(reader.ReadBytes(len)), null); 22 | } 23 | 24 | var mCount = reader.ReadInt32(); 25 | for (var i = 0; i < mCount; i++) { 26 | var len = reader.ReadInt32(); 27 | var list = new List(); 28 | for (var j = 0; j < len; j++) { 29 | var code = (OpCode)reader.ReadByte(); 30 | list.Add(Map.Lookup(code).Deserialize(reader)); 31 | } 32 | 33 | _methods.Add(list); 34 | } 35 | } 36 | } 37 | } 38 | 39 | readonly Dictionary _references; 40 | readonly List> _methods; 41 | 42 | internal Assembly CurrentAssembly { get; set; } 43 | 44 | internal Assembly GetReference(short index) { 45 | var pair = _references.ElementAt(index); 46 | 47 | if (pair.Value == null) 48 | _references[pair.Key] = AppDomain.CurrentDomain.Load(new AssemblyName(pair.Key)); 49 | 50 | return _references[pair.Key]; 51 | } 52 | 53 | internal List GetMethod(int index) => 54 | _methods[index]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MemeVM.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.572 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MemeVM.Confuser", "MemeVM.Confuser\MemeVM.Confuser.csproj", "{77B2C83B-CA34-4738-9384-C52F0121647C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MemeVM", "MemeVM\MemeVM.csproj", "{EF18F7F2-1F03-481C-98F9-4A18A2F12C11}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MemeVM.Runtime", "MemeVM.Runtime\MemeVM.Runtime.csproj", "{14D5D12E-9A32-4516-904E-DF3393626317}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {77B2C83B-CA34-4738-9384-C52F0121647C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {77B2C83B-CA34-4738-9384-C52F0121647C}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {77B2C83B-CA34-4738-9384-C52F0121647C}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {77B2C83B-CA34-4738-9384-C52F0121647C}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {EF18F7F2-1F03-481C-98F9-4A18A2F12C11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {EF18F7F2-1F03-481C-98F9-4A18A2F12C11}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {EF18F7F2-1F03-481C-98F9-4A18A2F12C11}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {EF18F7F2-1F03-481C-98F9-4A18A2F12C11}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {14D5D12E-9A32-4516-904E-DF3393626317}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {14D5D12E-9A32-4516-904E-DF3393626317}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {14D5D12E-9A32-4516-904E-DF3393626317}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {14D5D12E-9A32-4516-904E-DF3393626317}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {29EFAB72-200E-43AA-B91F-043CE66650CC} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /MemeVM.Runtime/Handlers/Call.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Reflection; 5 | using MemeVM.Runtime.Engine; 6 | 7 | namespace MemeVM.Runtime.Handlers { 8 | //TODO: Generic methods 9 | class Call : IHandler { 10 | public OpCode Handles => OpCode.Call; 11 | public void Handle(VM machine, Body body, Instruction instruction) { 12 | var op = (Tuple)instruction.Operand; 13 | 14 | if (!op.Item3) { 15 | HandleNormal(machine, body, instruction); 16 | return; 17 | } 18 | 19 | var index = op.Item1; 20 | var pcount = op.Item2; 21 | 22 | var parameters = new object[pcount]; 23 | for (var i = parameters.Length - 1; i >= 0; i--) 24 | parameters[i] = machine.Stack.Pop(); 25 | 26 | var res = Dispatcher.Run(body.CurrentAssembly, index, parameters); 27 | if (!(res is NoMoreStackItem)) 28 | machine.Stack.Push(res); 29 | } 30 | 31 | static void HandleNormal(VM machine, Body body, Instruction instruction) { 32 | var op = (Tuple)instruction.Operand; 33 | 34 | var asm = body.GetReference(op.Item1); 35 | var info = asm.ManifestModule.ResolveMember(op.Item2); 36 | var target = asm.ManifestModule.ResolveMethod(op.Item2); 37 | 38 | var rawparams = target.GetParameters(); 39 | var paramscount = rawparams.Length; 40 | var parameters = new object[paramscount]; 41 | for (var i = parameters.Length - 1; i >= 0; i--) 42 | parameters[i] = machine.Stack.Pop(); 43 | 44 | if ((info.MemberType & MemberTypes.Constructor) == MemberTypes.Constructor) { 45 | var ctorinfo = (ConstructorInfo)info; 46 | machine.Stack.Push(ctorinfo.Invoke(parameters)); 47 | return; 48 | } 49 | 50 | var methodinfo = (MethodInfo)info; 51 | var parent = methodinfo.IsStatic ? null : machine.Stack.Pop(); 52 | var res = target.Invoke(parent, parameters); 53 | if (methodinfo.ReturnType != typeof(void)) 54 | machine.Stack.Push(res); 55 | } 56 | 57 | public Instruction Deserialize(BinaryReader reader) => 58 | new Instruction(OpCode.Call, new Tuple(reader.ReadInt16(), reader.ReadInt32(), reader.ReadBoolean())); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /MemeVM.Confuser/MemeVM.Confuser.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {77B2C83B-CA34-4738-9384-C52F0121647C} 8 | Exe 9 | MemeVM.Confuser 10 | MemeVM.Confuser 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\Confuser.Core.dll 38 | 39 | 40 | ..\dnlib.dll 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | {ef18f7f2-1f03-481c-98f9-4a18a2f12c11} 62 | MemeVM 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /MemeVM/Translation/Handlers/Branching.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using MemeVM.Translation.Helpers; 5 | 6 | namespace MemeVM.Translation.Handlers { 7 | class Br : IHandler { 8 | public OpCode[] Translates => new[] { OpCodes.Br }; 9 | public VMOpCode Output => VMOpCode.Jmp; 10 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 11 | var operand = method.Body.Instructions.IndexOf((Instruction)method.Body.Instructions[index].Operand); 12 | success = true; 13 | return new VMInstruction(VMOpCode.Jmp, operand); 14 | } 15 | 16 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 17 | var buf = new byte[5]; 18 | buf[0] = (byte)VMOpCode.Jmp; 19 | Array.Copy(BitConverter.GetBytes(helper.Get((int)instruction.Operand)), 0, buf, 1, 4); 20 | return buf; 21 | } 22 | } 23 | 24 | class Brtrue : IHandler { 25 | public OpCode[] Translates => new[] { OpCodes.Brtrue }; 26 | public VMOpCode Output => VMOpCode.Jt; 27 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 28 | var operand = method.Body.Instructions.IndexOf((Instruction)method.Body.Instructions[index].Operand); 29 | success = true; 30 | return new VMInstruction(VMOpCode.Jt, operand); 31 | } 32 | 33 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 34 | var buf = new byte[5]; 35 | buf[0] = (byte)VMOpCode.Jt; 36 | Array.Copy(BitConverter.GetBytes(helper.Get((int)instruction.Operand)), 0, buf, 1, 4); 37 | return buf; 38 | } 39 | } 40 | 41 | class Brfalse : IHandler { 42 | public OpCode[] Translates => new[] { OpCodes.Brfalse }; 43 | public VMOpCode Output => VMOpCode.Jf; 44 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 45 | var operand = method.Body.Instructions.IndexOf((Instruction)method.Body.Instructions[index].Operand); 46 | success = true; 47 | return new VMInstruction(VMOpCode.Jf, operand); 48 | } 49 | 50 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 51 | var buf = new byte[5]; 52 | buf[0] = (byte)VMOpCode.Jf; 53 | Array.Copy(BitConverter.GetBytes(helper.Get((int)instruction.Operand)), 0, buf, 1, 4); 54 | return buf; 55 | } 56 | } 57 | 58 | class Beq : IHandler { 59 | public OpCode[] Translates => new[] { OpCodes.Beq }; 60 | public VMOpCode Output => VMOpCode.Je; 61 | public VMInstruction Translate(VMBody body, MethodDef method, int index, Offsets helper, out bool success) { 62 | success = true; 63 | return new VMInstruction(VMOpCode.Je, method.Body.Instructions.IndexOf(method.Body.Instructions[index])); 64 | } 65 | 66 | public byte[] Serialize(VMBody body, VMInstruction instruction, Offsets helper) { 67 | var buf = new byte[5]; 68 | buf[0] = (byte)VMOpCode.Je; 69 | Array.Copy(BitConverter.GetBytes(helper.Get((int)instruction.Operand)), 0, buf, 1, 4); 70 | return buf; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /MemeVM.Runtime/MemeVM.Runtime.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {14D5D12E-9A32-4516-904E-DF3393626317} 8 | Library 9 | Properties 10 | MemeVM.Runtime 11 | MemeVM.Runtime 12 | v4.0 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /MemeVM/MemeVM.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EF18F7F2-1F03-481C-98F9-4A18A2F12C11} 8 | Library 9 | Properties 10 | MemeVM 11 | MemeVM 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\Confuser.Core.dll 36 | 37 | 38 | ..\dnlib.dll 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | ConfuserEx/* -------------------------------------------------------------------------------- /MemeVM/VirtualizatonPhase.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.IO.Compression; 3 | using System.Linq; 4 | using Confuser.Core; 5 | using Confuser.Core.Services; 6 | using dnlib.DotNet; 7 | using dnlib.DotNet.Emit; 8 | using dnlib.DotNet.Writer; 9 | using MemeVM.Translation; 10 | using MemeVM.Translation.Helpers; 11 | 12 | namespace MemeVM { 13 | public class VirtualizatonPhase : ProtectionPhase { 14 | public VirtualizatonPhase(ConfuserComponent parent) : base(parent) { } 15 | public override string Name => "MemeVM.Virtualization"; 16 | public override ProtectionTargets Targets => ProtectionTargets.Methods; 17 | 18 | protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { 19 | if (!parameters.Targets.Any()) 20 | return; 21 | 22 | context.CurrentModuleWriterListener.OnWriterEvent += InsertVMBodies; 23 | 24 | // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop 25 | foreach (MethodDef method in parameters.Targets.WithProgress(context.Logger)) { 26 | if (!method.HasBody || method.DeclaringType.IsGlobalModuleType || method.Body.HasExceptionHandlers) 27 | continue; 28 | 29 | var module = method.Module; 30 | 31 | if (!Context.Bodies.ContainsKey(module)) 32 | Context.Bodies.Add(module, new VMBody()); 33 | 34 | var translated = Dispatcher.TranslateMethod(Context.Bodies[module], method); 35 | if (translated == null) 36 | continue; 37 | 38 | Context.Bodies[module].Translated.Add(method, translated); 39 | Context.Bodies[module].MethodToIndex.Add(method, Context.Bodies[module].Translated.Count - 1); 40 | context.CheckCancellation(); 41 | } 42 | 43 | foreach (var pair in Context.Bodies) { 44 | if (pair.Value.Translated.Count < 1) 45 | continue; 46 | 47 | var target = pair.Key.Import(Context.Entry); 48 | foreach (var translated in pair.Value.Translated.WithProgress(context.Logger)) { 49 | var method = translated.Key; 50 | method.Body = new CilBody { MaxStack = 1 }; 51 | var body = method.Body.Instructions; 52 | 53 | body.Add(OpCodes.Ldtoken.ToInstruction(method.DeclaringType)); 54 | body.Add(OpCodes.Ldc_I4.ToInstruction(pair.Value.MethodToIndex[method])); 55 | 56 | AddParameters(method); 57 | 58 | var genericType = method.ReturnType == method.Module.CorLibTypes.Void ? target.DeclaringType.ToTypeSig() : method.ReturnType; 59 | var sig = new MethodSpecUser((MemberRef)target, new GenericInstMethodSig(genericType)); 60 | body.Add(OpCodes.Call.ToInstruction(sig)); 61 | 62 | if (method.ReturnType == method.Module.CorLibTypes.Void) 63 | body.Add(OpCodes.Pop.ToInstruction()); 64 | 65 | body.Add(OpCodes.Ret.ToInstruction()); 66 | context.CheckCancellation(); 67 | } 68 | } 69 | 70 | Context.RuntimeModule.Dispose(); 71 | } 72 | 73 | static void InsertVMBodies(object sender, ModuleWriterListenerEventArgs e) { 74 | var writer = (ModuleWriterBase)sender; 75 | if (e.WriterEvent != ModuleWriterEvent.MDMemberDefRidsAllocated) 76 | return; 77 | 78 | TokenGetter.Writer = writer; 79 | 80 | var body = Context.Bodies[writer.Module]; 81 | var data = body.Serialize(); 82 | writer.Module.Resources.Add(new EmbeddedResource(" ", Compress(data))); 83 | } 84 | 85 | static byte[] Compress(byte[] array) { 86 | using (var ms = new MemoryStream()) { 87 | using (var def = new DeflateStream(ms, CompressionLevel.Optimal)) { 88 | def.Write(array, 0, array.Length); 89 | } 90 | 91 | return ms.ToArray(); 92 | } 93 | } 94 | 95 | static void AddParameters(MethodDef method) { 96 | if (method.Parameters.Count == 0) { 97 | method.Body.Instructions.Add(OpCodes.Ldnull.ToInstruction()); 98 | return; 99 | } 100 | 101 | method.Body.Instructions.Add(OpCodes.Ldc_I4.ToInstruction(method.Parameters.Count)); 102 | method.Body.Instructions.Add(OpCodes.Newarr.ToInstruction(method.Module.CorLibTypes.Object)); 103 | method.Body.Instructions.Add(OpCodes.Dup.ToInstruction()); 104 | 105 | for (var i = 0; i < method.Parameters.Count; i++) { 106 | method.Body.Instructions.Add(OpCodes.Ldc_I4.ToInstruction(i)); 107 | method.Body.Instructions.Add(OpCodes.Ldarg.ToInstruction(method.Parameters[i])); 108 | 109 | var cor = method.Module.CorLibTypes; 110 | var param = method.Parameters[i]; 111 | if (!param.IsHiddenThisParameter) { 112 | if (param.Type != cor.String && param.Type != cor.Object && param.Type != cor.TypedReference) { 113 | var spec = new TypeSpecUser(param.Type); 114 | method.Body.Instructions.Add(new Instruction(OpCodes.Box, spec)); 115 | } 116 | } 117 | 118 | method.Body.Instructions.Add(OpCodes.Stelem_Ref.ToInstruction()); 119 | method.Body.Instructions.Add(OpCodes.Dup.ToInstruction()); 120 | } 121 | 122 | method.Body.Instructions.Remove(method.Body.Instructions.Last()); 123 | } 124 | } 125 | } 126 | --------------------------------------------------------------------------------