Skip to content
19 changes: 13 additions & 6 deletions src/EazyDevirt/Core/Architecture/InlineOperands/VMInlineOperand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace EazyDevirt.Core.Architecture.InlineOperands;
using EazyDevirt.Devirtualization;

namespace EazyDevirt.Core.Architecture.InlineOperands;

// thank you to saneki

Expand Down Expand Up @@ -85,15 +87,20 @@ public VMInlineOperand(ValueType valueType, int value)
ValueType = valueType;
Value = value;
}
public VMInlineOperand(BinaryReader reader)

public VMInlineOperand(ValueType valueType, VMInlineOperandData data)
{
ValueType = (ValueType)reader.ReadByte();
ValueType = valueType;
Data = data;
}

public static VMInlineOperand ReadInternal(DevirtualizationContext ctx, BinaryReader reader)
{
var ValueType = ctx.OperandReadOrder[reader.ReadByte()];
if (ValueType == ValueType.Token)
Value = reader.ReadInt32();
return new VMInlineOperand(ValueType, reader.ReadInt32());
else
Data = VMInlineOperandData.Read(reader);
return new VMInlineOperand(ValueType, VMInlineOperandData.Read(ctx, reader));
}

public static VMInlineOperand ReadInternal(BinaryReader reader) => new(ValueType.Position, reader.ReadInt32());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Reflection;
using EazyDevirt.Devirtualization;
using System.Reflection;

namespace EazyDevirt.Core.Architecture.InlineOperands;

Expand All @@ -19,10 +20,10 @@ internal abstract record VMInlineOperandData(VMInlineOperandType Type)
/// </summary>
/// <param name="reader">BinaryReader</param>
/// <returns>InlineOperandData</returns>
public static VMInlineOperandData Read(BinaryReader reader)
public static VMInlineOperandData Read(DevirtualizationContext ctx, BinaryReader reader)
{
var operandType = reader.ReadByte();
return (VMInlineOperandType)operandType switch
return ctx.VMOperandTypeOrder[operandType] switch
{
VMInlineOperandType.Type => new VMTypeData(reader),
VMInlineOperandType.Field => new VMFieldData(reader),
Expand Down
58 changes: 45 additions & 13 deletions src/EazyDevirt/Core/Architecture/VMMethod.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Code.Cil;
using AsmResolver.PE.DotNet.Cil;
using EazyDevirt.Devirtualization;

namespace EazyDevirt.Core.Architecture;

Expand Down Expand Up @@ -46,21 +47,42 @@ internal record VMMethodInfo

public ITypeDefOrRef DeclaringType { get; set; }
public ITypeDefOrRef ReturnType { get; set; }
public VMMethodInfo(BinaryReader reader)

public VMMethodInfo(DevirtualizationContext ctx, BinaryReader reader)
{
VMDeclaringType = reader.ReadInt32();
Name = reader.ReadString();
BindingFlags = reader.ReadByte();
VMReturnType = reader.ReadInt32();
foreach (VMMethodField field in ctx.VMMethodReadOrder)
{
switch (field)
{
case VMMethodField.VMDeclaringType:
VMDeclaringType = reader.ReadInt32();
break;

case VMMethodField.Name:
Name = reader.ReadString();
break;

case VMMethodField.BindingFlags:
BindingFlags = reader.ReadByte();
break;

case VMMethodField.ReturnType:
VMReturnType = reader.ReadInt32();
break;

VMLocals = new List<VMLocal>(reader.ReadInt16());
for (var i = 0; i < VMLocals.Capacity; i++)
VMLocals.Add(new VMLocal(reader.ReadInt32()));

VMParameters = new List<VMParameter>(reader.ReadInt16());
for (var i = 0; i < VMParameters.Capacity; i++)
VMParameters.Add(new VMParameter(reader.ReadInt32(), reader.ReadBoolean()));
case VMMethodField.Locals:
VMLocals = new List<VMLocal>(reader.ReadInt16());
for (var i = 0; i < VMLocals.Capacity; i++)
VMLocals.Add(new VMLocal(reader.ReadInt32()));
break;

case VMMethodField.Parameters:
VMParameters = new List<VMParameter>(reader.ReadInt16());
for (var i = 0; i < VMParameters.Capacity; i++)
VMParameters.Add(new VMParameter(reader.ReadInt32(), reader.ReadBoolean()));
break;
}
}
}

public override string ToString() =>
Expand All @@ -70,6 +92,16 @@ public override string ToString() =>
$"DeclaringType: {DeclaringType.FullName} | ReturnType: {ReturnType.FullName}";
}

internal enum VMMethodField
{
VMDeclaringType,
Name,
BindingFlags,
ReturnType,
Locals,
Parameters
}

internal record VMLocal(int VMType)
{
public int VMType { get; } = VMType;
Expand Down
21 changes: 14 additions & 7 deletions src/EazyDevirt/Core/IO/Resolver.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using AsmResolver.DotNet.Signatures.Types;
using AsmResolver.DotNet.Signatures.Types.Parsing;
using EazyDevirt.Core.Architecture;
using EazyDevirt.Core.Architecture.InlineOperands;
using EazyDevirt.Devirtualization;
Expand Down Expand Up @@ -40,10 +41,16 @@ private TypeSignature ApplySigModifiers(TypeSignature baseTypeSig, Stack<string>
{
Ctx.VMResolverStream.Seek(position, SeekOrigin.Begin);

var inlineOperand = new VMInlineOperand(VMStreamReader);
var inlineOperand = VMInlineOperand.ReadInternal(this.Ctx, VMStreamReader);
if (inlineOperand.IsToken)
return Ctx.Module.LookupMember<ITypeDefOrRef>(inlineOperand.Token);


if (inlineOperand.Data is VMUserStringData strData)
{
//attempt to resolve type from string (mabye not present in eaz 2020 and above)
return TypeNameParser.Parse(this.Ctx.Module, strData.Value).ToTypeDefOrRef();
}

if (!inlineOperand.HasData || inlineOperand.Data is not VMTypeData data)
throw new Exception("VM inline operand expected to have type data!");

Expand Down Expand Up @@ -108,7 +115,7 @@ private TypeSignature ApplySigModifiers(TypeSignature baseTypeSig, Stack<string>
{
Ctx.VMResolverStream.Seek(position, SeekOrigin.Begin);

var inlineOperand = new VMInlineOperand(VMStreamReader);
var inlineOperand = VMInlineOperand.ReadInternal(this.Ctx, VMStreamReader);
if (inlineOperand.IsToken)
return Ctx.Module.LookupMember<IFieldDescriptor>(inlineOperand.Token);

Expand Down Expand Up @@ -191,7 +198,7 @@ x.First.ParameterType is GenericParameterSignature or GenericInstanceTypeSignatu
{
Ctx.VMResolverStream.Seek(position, SeekOrigin.Begin);

var inlineOperand = new VMInlineOperand(VMStreamReader);
var inlineOperand = VMInlineOperand.ReadInternal(this.Ctx, VMStreamReader);
if (inlineOperand.IsToken)
return Ctx.Module.LookupMember<IMethodDescriptor>(inlineOperand.Token);

Expand Down Expand Up @@ -319,7 +326,7 @@ x.First.ParameterType is GenericParameterSignature or GenericInstanceTypeSignatu
{
Ctx.VMResolverStream.Seek(position, SeekOrigin.Begin);

var inlineOperand = new VMInlineOperand(VMStreamReader);
var inlineOperand = VMInlineOperand.ReadInternal(this.Ctx, VMStreamReader);
if (inlineOperand.IsToken)
{
var member = Ctx.Module.LookupMember(inlineOperand.Token);
Expand Down Expand Up @@ -362,7 +369,7 @@ x.First.ParameterType is GenericParameterSignature or GenericInstanceTypeSignatu
{
Ctx.VMResolverStream.Seek(position, SeekOrigin.Begin);

var methodInfo = new VMMethodInfo(VMStreamReader);
var methodInfo = new VMMethodInfo(this.Ctx, VMStreamReader);

var declaringType = ResolveType(methodInfo.VMDeclaringType);
if (declaringType is null)
Expand All @@ -389,7 +396,7 @@ public string ResolveString(int position)
{
Ctx.VMResolverStream.Seek(position, SeekOrigin.Begin);

var inlineOperand = new VMInlineOperand(VMStreamReader);
var inlineOperand = VMInlineOperand.ReadInternal(this.Ctx, VMStreamReader);
if (inlineOperand.IsToken)
return Ctx.Module.LookupString(inlineOperand.Token);

Expand Down
4 changes: 4 additions & 0 deletions src/EazyDevirt/Devirtualization/DevirtualizationContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using AsmResolver.DotNet;
using AsmResolver.PE.DotNet.Metadata.Tables;
using EazyDevirt.Core.Architecture;
using EazyDevirt.Core.Architecture.InlineOperands;
using EazyDevirt.Core.IO;
using EazyDevirt.Devirtualization.Options;
using EazyDevirt.Logging;
Expand Down Expand Up @@ -42,6 +43,9 @@ internal record DevirtualizationContext
public TypeDefinition VMDeclaringType { get; set; }
public VMCipherStream VMStream { get; set; }
public VMCipherStream VMResolverStream { get; set; }
public Dictionary<int, VMInlineOperandType> VMOperandTypeOrder { get; set; }
public List<VMMethodField> VMMethodReadOrder { get; set; }
public Dictionary<int, EazyDevirt.Core.Architecture.InlineOperands.ValueType> OperandReadOrder { get; set; }
public int PositionCryptoKey { get; set; }
public int MethodCryptoKey { get; set; }

Expand Down
1 change: 1 addition & 0 deletions src/EazyDevirt/Devirtualization/Devirtualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public Devirtualizer(DevirtualizationContext ctx)
new ResourceParsing(ctx),
new OpCodeMapping(ctx),
new MethodDiscovery(ctx),
new ReadOrderAnalyzer(ctx),
new MethodDevirtualizer(ctx),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public override bool Run()
foreach (var vmMethod in Ctx.VMMethods)
{
VMStream.Seek(vmMethod.MethodKey, SeekOrigin.Begin);

ReadVMMethod(vmMethod);

if (Ctx.Options.VeryVerbose)
Expand All @@ -37,7 +36,7 @@ public override bool Run()

private void ReadVMMethod(VMMethod vmMethod)
{
vmMethod.MethodInfo = new VMMethodInfo(VMStreamReader);
vmMethod.MethodInfo = new VMMethodInfo(this.Ctx, VMStreamReader);

ReadExceptionHandlers(vmMethod);

Expand Down
Loading