mirror of
https://github.com/Zypherion-Technologies/UnConfuserEx
synced 2026-06-23 09:25:30 +00:00
Add files via upload
This commit is contained in:
committed by
GitHub
parent
e56a256c7b
commit
d5c520e888
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace X86Emulator
|
||||
{
|
||||
internal class EmulatorException : Exception
|
||||
{
|
||||
public EmulatorException()
|
||||
{
|
||||
}
|
||||
|
||||
public EmulatorException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public EmulatorException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using SharpDisasm;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class Add : Instruction
|
||||
{
|
||||
private Operand[] Operands;
|
||||
|
||||
public Add(Operand[] operands)
|
||||
{
|
||||
Operands = operands;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
int src = ReadOperand(Operands[1], registers);
|
||||
int dst = ReadOperand(Operands[0], registers);
|
||||
|
||||
int result = dst + src;
|
||||
registers.SetValue(Operands[0].Base, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using SharpDisasm;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class IMul : Instruction
|
||||
{
|
||||
private Operand[] Operands;
|
||||
|
||||
public IMul(Operand[] operands)
|
||||
{
|
||||
Operands = operands;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
if (Operands.Length == 1)
|
||||
{
|
||||
long eax = registers.GetValue(Registers.Register.EAX);
|
||||
long val = ReadOperand(Operands[0], registers);
|
||||
|
||||
long result = eax * val;
|
||||
|
||||
registers.SetValue(SharpDisasm.Udis86.ud_type.UD_R_EDX, (int)(result >> 32));
|
||||
registers.SetValue(SharpDisasm.Udis86.ud_type.UD_R_EAX, (int)result);
|
||||
}
|
||||
else if (Operands.Length == 2)
|
||||
{
|
||||
int dst = registers.GetValue(Operands[0].Base);
|
||||
int src = ReadOperand(Operands[1], registers);
|
||||
|
||||
int result = dst * src;
|
||||
registers.SetValue(Operands[0].Base, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
int val0 = ReadOperand(Operands[1], registers);
|
||||
int val1 = ReadOperand(Operands[2], registers);
|
||||
|
||||
int result = val0 * val1;
|
||||
registers.SetValue(Operands[0].Base, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using SharpDisasm;
|
||||
using SharpDisasm.Udis86;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal abstract class Instruction
|
||||
{
|
||||
public abstract void Emulate(Stack<int> stack, Registers registers);
|
||||
|
||||
protected static int ReadOperand(Operand operand, Registers registers)
|
||||
{
|
||||
return operand.Type == ud_type.UD_OP_REG
|
||||
? registers.GetValue(operand.Base)
|
||||
: operand.LvalSDWord;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using SharpDisasm;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class Mov : Instruction
|
||||
{
|
||||
private Operand[] Operands;
|
||||
|
||||
public Mov(Operand[] operands)
|
||||
{
|
||||
Operands = operands;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
Operand to = Operands[0];
|
||||
int val = ReadOperand(Operands[1], registers);
|
||||
|
||||
registers.SetValue(to.Base, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using SharpDisasm;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class Neg : Instruction
|
||||
{
|
||||
private Operand Operand;
|
||||
|
||||
public Neg(Operand operand)
|
||||
{
|
||||
Operand = operand;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
int val = registers.GetValue(Operand.Base);
|
||||
|
||||
val = -val;
|
||||
|
||||
registers.SetValue(Operand.Base, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using SharpDisasm;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class Not : Instruction
|
||||
{
|
||||
private Operand Operand;
|
||||
|
||||
public Not(Operand operand)
|
||||
{
|
||||
Operand = operand;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
int val = registers.GetValue(Operand.Base);
|
||||
|
||||
val = ~val;
|
||||
|
||||
registers.SetValue(Operand.Base, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using SharpDisasm;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class Pop : Instruction
|
||||
{
|
||||
private Operand? Operand = null;
|
||||
|
||||
public Pop(Operand? operand)
|
||||
{
|
||||
Operand = operand;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
int val = stack.Pop();
|
||||
|
||||
if (Operand != null)
|
||||
{
|
||||
registers.SetValue(Operand.Base, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using SharpDisasm;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class Push : Instruction
|
||||
{
|
||||
private Operand Operand;
|
||||
|
||||
public Push(Operand operand)
|
||||
{
|
||||
Operand = operand;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
stack.Push(ReadOperand(Operand, registers));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using SharpDisasm;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class Sub : Instruction
|
||||
{
|
||||
private Operand[] Operands;
|
||||
|
||||
public Sub(Operand[] operands)
|
||||
{
|
||||
Operands = operands;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
int src = ReadOperand(Operands[1], registers);
|
||||
int dst = ReadOperand(Operands[0], registers);
|
||||
|
||||
int result = dst - src;
|
||||
registers.SetValue(Operands[0].Base, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using SharpDisasm;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace X86Emulator.Instructions
|
||||
{
|
||||
internal class Xor : Instruction
|
||||
{
|
||||
private Operand[] Operands;
|
||||
|
||||
public Xor(Operand[] operands)
|
||||
{
|
||||
Operands = operands;
|
||||
}
|
||||
|
||||
public override void Emulate(Stack<int> stack, Registers registers)
|
||||
{
|
||||
int dst = registers.GetValue(Operands[0].Base);
|
||||
int src = ReadOperand(Operands[1], registers);
|
||||
|
||||
int result = src ^ dst;
|
||||
registers.SetValue(Operands[0].Base, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using SharpDisasm.Udis86;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace X86Emulator
|
||||
{
|
||||
internal class Registers
|
||||
{
|
||||
public int[] Values = new int[(int)Register.MAX];
|
||||
|
||||
|
||||
public int GetValue(Register register)
|
||||
{
|
||||
return Values[(int)register];
|
||||
}
|
||||
|
||||
public int GetValue(ud_type register)
|
||||
{
|
||||
return register switch
|
||||
{
|
||||
ud_type.UD_R_EAX => Values[(int)Register.EAX],
|
||||
ud_type.UD_R_ECX => Values[(int)Register.ECX],
|
||||
ud_type.UD_R_EDX => Values[(int)Register.EDX],
|
||||
ud_type.UD_R_EBX => Values[(int)Register.EBX],
|
||||
ud_type.UD_R_ESP => Values[(int)Register.ESP],
|
||||
ud_type.UD_R_EBP => Values[(int)Register.EBP],
|
||||
ud_type.UD_R_ESI => Values[(int)Register.ESI],
|
||||
ud_type.UD_R_EDI => Values[(int)Register.EDI],
|
||||
_ => throw new EmulatorException($"Unhandled register type {register}"),
|
||||
};
|
||||
}
|
||||
|
||||
public void SetValue(ud_type register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
case ud_type.UD_R_EAX:
|
||||
Values[(int)Register.EAX] = value;
|
||||
break;
|
||||
case ud_type.UD_R_ECX:
|
||||
Values[(int)Register.ECX] = value;
|
||||
break;
|
||||
case ud_type.UD_R_EDX:
|
||||
Values[(int)Register.EDX] = value;
|
||||
break;
|
||||
case ud_type.UD_R_EBX:
|
||||
Values[(int)Register.EBX] = value;
|
||||
break;
|
||||
case ud_type.UD_R_ESP:
|
||||
Values[(int)Register.ESP] = value;
|
||||
break;
|
||||
case ud_type.UD_R_EBP:
|
||||
Values[(int)Register.EBP] = value;
|
||||
break;
|
||||
case ud_type.UD_R_ESI:
|
||||
Values[(int)Register.ESI] = value;
|
||||
break;
|
||||
case ud_type.UD_R_EDI:
|
||||
Values[(int)Register.EDI] = value;
|
||||
break;
|
||||
default:
|
||||
throw new EmulatorException($"Unhandled register type {register}");
|
||||
};
|
||||
}
|
||||
|
||||
public enum Register
|
||||
{
|
||||
EAX,
|
||||
ECX,
|
||||
EDX,
|
||||
EBX,
|
||||
ESP,
|
||||
EBP,
|
||||
ESI,
|
||||
EDI,
|
||||
|
||||
MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="dnlib" Version="4.4.0" />
|
||||
<PackageReference Include="SharpDisasm" Version="1.1.11" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,133 @@
|
||||
using dnlib.DotNet;
|
||||
using dnlib.PE;
|
||||
using System.Collections.Generic;
|
||||
using X86Emulator.Instructions;
|
||||
using System.Linq;
|
||||
using SharpDisasm.Udis86;
|
||||
|
||||
namespace X86Emulator
|
||||
{
|
||||
public class X86Method
|
||||
{
|
||||
private ModuleDefMD Module;
|
||||
private MethodDef Method;
|
||||
private List<Instruction> Instructions = new();
|
||||
private int NumArgs = 0;
|
||||
|
||||
public X86Method(ModuleDefMD module, MethodDef method)
|
||||
{
|
||||
Module = module;
|
||||
Method = method;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public int Emulate(int[] args)
|
||||
{
|
||||
if (args.Length != NumArgs)
|
||||
{
|
||||
throw new EmulatorException($"Incorrect number of args passed to method. Expected {NumArgs} got {args.Length}");
|
||||
}
|
||||
|
||||
var stack = new Stack<int>();
|
||||
var registers = new Registers();
|
||||
|
||||
if (args.Length == 1)
|
||||
{
|
||||
registers.SetValue(ud_type.UD_R_ECX, args[0]);
|
||||
stack.Push(args[0]);
|
||||
}
|
||||
else if (args.Length > 1)
|
||||
{
|
||||
registers.SetValue(ud_type.UD_R_ECX, args[0]);
|
||||
registers.SetValue(ud_type.UD_R_EDX, args[1]);
|
||||
foreach (var arg in args.Skip(2))
|
||||
{
|
||||
stack.Push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var instr in Instructions)
|
||||
{
|
||||
instr.Emulate(stack, registers);
|
||||
}
|
||||
|
||||
return registers.GetValue(Registers.Register.EAX);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
NumArgs = Method.Parameters.Count;
|
||||
var body = ReadNativeBody();
|
||||
|
||||
var disassembler = new SharpDisasm.Disassembler(body, SharpDisasm.ArchitectureMode.x86_32);
|
||||
var instructions = disassembler.Disassemble();
|
||||
|
||||
foreach (var instr in instructions)
|
||||
{
|
||||
if (instr.Mnemonic == ud_mnemonic_code.UD_Iret)
|
||||
{
|
||||
// Need to remove the final pops before a ret
|
||||
Instructions.RemoveRange(Instructions.Count - 3, 3);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (instr.Mnemonic)
|
||||
{
|
||||
case ud_mnemonic_code.UD_Ipush:
|
||||
Instructions.Add(new Push(instr.Operands[0]));
|
||||
break;
|
||||
case ud_mnemonic_code.UD_Ipop:
|
||||
Instructions.Add(new Pop(instr.Operands.Length == 0 ? null : instr.Operands[0]));
|
||||
break;
|
||||
case ud_mnemonic_code.UD_Imov:
|
||||
Instructions.Add(new Mov(instr.Operands));
|
||||
break;
|
||||
case ud_mnemonic_code.UD_Inot:
|
||||
Instructions.Add(new Not(instr.Operands[0]));
|
||||
break;
|
||||
case ud_mnemonic_code.UD_Iimul:
|
||||
Instructions.Add(new IMul(instr.Operands));
|
||||
break;
|
||||
case ud_mnemonic_code.UD_Ineg:
|
||||
Instructions.Add(new Neg(instr.Operands[0]));
|
||||
break;
|
||||
case ud_mnemonic_code.UD_Ixor:
|
||||
Instructions.Add(new Xor(instr.Operands));
|
||||
break;
|
||||
case ud_mnemonic_code.UD_Isub:
|
||||
Instructions.Add(new Sub(instr.Operands));
|
||||
break;
|
||||
case ud_mnemonic_code.UD_Iadd:
|
||||
Instructions.Add(new Add(instr.Operands));
|
||||
break;
|
||||
|
||||
|
||||
case ud_mnemonic_code.UD_Inop:
|
||||
// no-op ...
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw new EmulatorException($"Unhandled instruction type {instr.Mnemonic}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private byte[] ReadNativeBody()
|
||||
{
|
||||
var reader = Module.Metadata.PEImage.CreateReader();
|
||||
var fileOffset = Module.Metadata.PEImage.ToFileOffset(Method.NativeBody.RVA) + 0x14;
|
||||
reader.Position = (uint)fileOffset;
|
||||
|
||||
Module.TablesStream.TryReadMethodRow(Method.Rid + 1, out var nextMethod);
|
||||
var size = Module.Metadata.PEImage.ToFileOffset((RVA)nextMethod.RVA) - fileOffset;
|
||||
var bytes = ((nextMethod.ImplFlags & (ushort)MethodImplAttributes.Native) != 0) ? new byte[size] : new byte[2048];
|
||||
|
||||
|
||||
reader.ReadBytes(bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user