Add files via upload

This commit is contained in:
Adam - Zyph. Tech.
2026-06-17 19:00:04 +02:00
committed by GitHub
parent ec6db89288
commit e56a256c7b
23 changed files with 675 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using System.Collections.Generic;
namespace MSILEmulator
{
public class Context
{
public Dictionary<int, object> Args = new();
public Dictionary<IField, object> Fields = new();
public Dictionary<int, object> Locals = new();
public Dictionary<uint, int> Offsets = new();
public Stack<object> Stack = new();
public Context(IList<Instruction> instructions)
{
for (int i = 0; i < instructions.Count; i++)
{
Offsets[instructions[i].Offset] = i;
}
}
}
}
+25
View File
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator
{
internal class EmulatorException : Exception
{
public EmulatorException()
{
}
public EmulatorException(string message) : base(message)
{
}
public EmulatorException(string message, Exception inner) : base(message, inner)
{
}
}
}
+217
View File
@@ -0,0 +1,217 @@
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using MSILEmulator.Instructions.Arithmetic;
using MSILEmulator.Instructions.Branch;
using MSILEmulator.Instructions.Load;
using MSILEmulator.Instructions.Logic;
using MSILEmulator.Instructions.Store;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MSILEmulator
{
public class ILMethod
{
private MethodDef? Method;
private List<Instruction> Instructions;
private Context Ctx;
public ILMethod(MethodDef method)
{
Method = method;
Instructions = Method.Body.Instructions.ToList();
Ctx = new(Instructions);
}
public ILMethod(MethodDef method, int start, int end)
{
Method = method;
Instructions = Method.Body.Instructions.Skip(start).Take(end - start).ToList();
Ctx = new(Instructions);
}
public ILMethod(IEnumerable<Instruction> instructions)
{
Method = null;
Instructions = instructions.ToList();
Ctx = new(Instructions);
}
public void SetArg(int index, object value)
{
Ctx.Args[index] = value;
}
public void SetLocal(int index, object value)
{
Ctx.Locals[index] = value;
}
public Context Emulate()
{
for (int i = 0; i < Instructions.Count; )
{
var instr = Instructions[i];
i = EmulateInstruction(Ctx, instr, i);
if (i == -1)
{
break;
}
}
return Ctx;
}
private int EmulateInstruction(Context ctx, Instruction instr, int index)
{
switch (instr.OpCode.Code)
{
// Load
case Code.Ldc_I4:
case Code.Ldc_I4_S:
ctx.Stack.Push(instr.GetLdcI4Value());
break;
case Code.Ldc_I4_0:
case Code.Ldc_I4_1:
case Code.Ldc_I4_2:
case Code.Ldc_I4_3:
case Code.Ldc_I4_4:
case Code.Ldc_I4_5:
case Code.Ldc_I4_6:
case Code.Ldc_I4_7:
case Code.Ldc_I4_8:
ctx.Stack.Push((int)instr.OpCode.Code - (int)Code.Ldc_I4_0);
break;
case Code.Ldc_I4_M1:
ctx.Stack.Push((int)-1);
break;
case Code.Ldc_I8:
ctx.Stack.Push((long)instr.Operand);
break;
case Code.Ldarg:
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
case Code.Ldarg_S:
Ldarg.Emulate(ctx, instr);
break;
case Code.Ldloc:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
case Code.Ldloc_S:
Ldloc.Emulate(ctx, instr);
break;
case Code.Ldelem_U4:
Ldelem.EmulateU4(ctx, instr);
break;
// Store
case Code.Stloc:
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
case Code.Stloc_S:
Stloc.Emulate(ctx, instr);
break;
case Code.Stelem_I4:
Stelem.Emulate(ctx, instr);
break;
case Code.Stfld:
ctx.Fields[(IField)instr.Operand] = ctx.Stack.Pop();
if (ctx.Stack.Count > 0)
{
ctx.Stack.Pop();
}
break;
// Arithmetic operators
case Code.Add:
Add.Emulate(ctx);
break;
case Code.Mul:
Mul.Emulate(ctx);
break;
case Code.Neg:
Neg.Emulate(ctx);
break;
case Code.Or:
Or.Emulate(ctx);
break;
case Code.Sub:
Sub.Emulate(ctx);
break;
// Logic operators
case Code.And:
And.Emulate(ctx);
break;
case Code.Not:
Not.Emulate(ctx);
break;
case Code.Shl:
Shl.Emulate(ctx);
break;
case Code.Shr:
Shr.Emulate(ctx);
break;
case Code.Shr_Un:
Shr_Un.Emulate(ctx);
break;
case Code.Xor:
Xor.Emulate(ctx);
break;
// Branching
case Code.Br:
case Code.Br_S:
return ctx.Offsets[((Instruction)instr.Operand).Offset];
case Code.Beq:
case Code.Beq_S:
return Beq.Emulate(ctx, instr);
case Code.Bne_Un:
case Code.Bne_Un_S:
return Bne.Emulate(ctx, instr);
// Conversion
case Code.Conv_U8:
var type = ctx.Stack.Peek().GetType();
if (type == typeof(int))
ctx.Stack.Push((long)(int)ctx.Stack.Pop());
else
throw new NotImplementedException();
break;
// Misc
case Code.Nop:
// ...No-op
break;
case Code.Ret:
return -1;
default:
throw new EmulatorException($"Unhandled OpCode {instr.OpCode}");
}
return ++index;
}
}
}
@@ -0,0 +1,20 @@
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Arithmetic
{
internal class Add
{
public static void Emulate(Context ctx)
{
int val2 = (int)ctx.Stack.Pop();
int val1 = (int)ctx.Stack.Pop();
ctx.Stack.Push(val1 + val2);
}
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Arithmetic
{
internal class Mul
{
public static void Emulate(Context ctx)
{
int val2 = (int)ctx.Stack.Pop();
int val1 = (int)ctx.Stack.Pop();
ctx.Stack.Push(val1 * val2);
}
}
}
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Arithmetic
{
internal class Neg
{
public static void Emulate(Context ctx)
{
int val = (int)ctx.Stack.Pop();
ctx.Stack.Push(-val);
}
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Arithmetic
{
internal class Sub
{
public static void Emulate(Context ctx)
{
int val2 = (int)ctx.Stack.Pop();
int val1 = (int)ctx.Stack.Pop();
ctx.Stack.Push(val1 - val2);
}
}
}
+12
View File
@@ -0,0 +1,12 @@
using dnlib.DotNet.Emit;
namespace MSILEmulator.Instructions.Branch
{
internal class Beq
{
public static int Emulate(Context ctx, Instruction instr)
{
return BranchCompare.Emulate(ctx, instr, static (left, right) => left == right, static (left, right) => left == right);
}
}
}
+12
View File
@@ -0,0 +1,12 @@
using dnlib.DotNet.Emit;
namespace MSILEmulator.Instructions.Branch
{
internal class Bne
{
public static int Emulate(Context ctx, Instruction instr)
{
return BranchCompare.Emulate(ctx, instr, static (left, right) => left != right, static (left, right) => left != right);
}
}
}
@@ -0,0 +1,30 @@
using dnlib.DotNet.Emit;
using System;
namespace MSILEmulator.Instructions.Branch
{
internal static class BranchCompare
{
public static int Emulate(Context ctx, Instruction instr, Func<int, int, bool> compareInt, Func<long, long, bool> compareLong)
{
object val2 = ctx.Stack.Pop();
object val1 = ctx.Stack.Pop();
if (val1.GetType() != val2.GetType())
{
throw new EmulatorException($"Attempted to compare different types {val1.GetType()} != {val2.GetType()}");
}
bool branch = val1 switch
{
int leftInt => compareInt(leftInt, (int)val2),
long leftLong => compareLong(leftLong, (long)val2),
_ => throw new NotImplementedException($"Comparison of {val1.GetType().Name} not handled")
};
return branch
? ctx.Offsets[((Instruction)instr.Operand).Offset]
: ctx.Offsets[instr.Offset] + 1;
}
}
}
+34
View File
@@ -0,0 +1,34 @@
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Load
{
internal class Ldarg
{
public static void Emulate(Context ctx, Instruction instr)
{
int index;
if (instr.Operand == null)
{
index = instr.OpCode.Code - Code.Ldarg_0;
}
else
{
index = (int)instr.Operand;
}
if (ctx.Args.TryGetValue(index, out var val))
{
ctx.Stack.Push(val);
}
else
{
ctx.Stack.Push(0);
}
}
}
}
+20
View File
@@ -0,0 +1,20 @@
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Load
{
internal class Ldelem
{
public static void EmulateU4(Context ctx, Instruction instr)
{
int index = (int)ctx.Stack.Pop();
var array = (uint[])ctx.Stack.Pop();
ctx.Stack.Push(unchecked((int)array[index]));
}
}
}
+35
View File
@@ -0,0 +1,35 @@
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Load
{
internal class Ldloc
{
public static void Emulate(Context ctx, Instruction instr)
{
int index;
if (instr.Operand == null)
{
index = instr.OpCode.Code - Code.Ldloc_0;
}
else
{
index = ((Local)instr.Operand).Index;
}
if (ctx.Locals.TryGetValue(index, out var local))
{
ctx.Stack.Push(local);
}
else
{
throw new NotImplementedException("Attempted to load local that hasn't been set.");
}
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Logic
{
internal class And
{
public static void Emulate(Context ctx)
{
int val2 = (int)ctx.Stack.Pop();
int val1 = (int)ctx.Stack.Pop();
ctx.Stack.Push(val1 & val2);
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Logic
{
internal class Not
{
public static void Emulate(Context ctx)
{
int val = (int)ctx.Stack.Pop();
ctx.Stack.Push(~val);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Logic
{
internal class Or
{
public static void Emulate(Context ctx)
{
int val2 = (int)ctx.Stack.Pop();
int val1 = (int)ctx.Stack.Pop();
ctx.Stack.Push(val1 | val2);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Logic
{
internal class Shl
{
public static void Emulate(Context ctx)
{
var shift = (int)ctx.Stack.Pop();
var val = (int)ctx.Stack.Pop();
ctx.Stack.Push(val << shift);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Logic
{
internal class Shr
{
public static void Emulate(Context ctx)
{
var shift = (int)ctx.Stack.Pop();
var val = (int)ctx.Stack.Pop();
ctx.Stack.Push(val >> shift);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Logic
{
internal class Shr_Un
{
public static void Emulate(Context ctx)
{
var shift = (int)ctx.Stack.Pop();
var val = (int)ctx.Stack.Pop();
ctx.Stack.Push(val >>> shift);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Logic
{
internal class Xor
{
public static void Emulate(Context ctx)
{
int val2 = (int)ctx.Stack.Pop();
int val1 = (int)ctx.Stack.Pop();
ctx.Stack.Push(val2 ^ val1);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Store
{
internal class Stelem
{
public static void Emulate(Context ctx, Instruction instr)
{
int value = (int)ctx.Stack.Pop();
int index = (int)ctx.Stack.Pop();
var array = (int[])ctx.Stack.Pop();
array[index] = value;
}
}
}
+27
View File
@@ -0,0 +1,27 @@
using dnlib.DotNet.Emit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MSILEmulator.Instructions.Store
{
internal class Stloc
{
public static void Emulate(Context ctx, Instruction instr)
{
int index;
if (instr.Operand == null)
{
index = instr.OpCode.Code - Code.Stloc_0;
}
else
{
index = ((Local)instr.Operand).Index;
}
ctx.Locals[index] = ctx.Stack.Pop();
}
}
}
+11
View File
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="dnlib" Version="4.4.0" />
</ItemGroup>
</Project>