This commit is contained in:
Xpl0itR 2024-06-08 21:25:08 +00:00 committed by GitHub
commit 2be6148ff1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 105 additions and 1 deletions

View File

@ -0,0 +1,67 @@
// Copyright © 2024 Xpl0itR
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using SystemEx.Memory;
namespace LibProtodec;
public static class CilReader
{
// Temporary AOT incompatible method to fill the dictionary, TODO: replace with a source generator
private static readonly Dictionary<int, OpCode> OpCodeLookup =
typeof(OpCodes).GetFields(BindingFlags.Public | BindingFlags.Static)
.Select(field => (OpCode)field.GetValue(null)!)
.ToDictionary(opCode => (int)(ushort)opCode.Value);
public static OpCode ReadCilOpCode(this ref MemoryReader reader, out int operandLength)
{
byte opCodeByte = reader.ReadByte();
int opCodeInt = opCodeByte == OpCodes.Prefix1.Value
? (opCodeByte << 8) | reader.ReadByte()
: opCodeByte;
OpCode opCode = OpCodeLookup[opCodeInt];
operandLength = SizeOf(opCode.OperandType);
return opCode;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int SizeOf(OperandType operandType)
{
switch (operandType)
{
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
case OperandType.ShortInlineVar:
return 1;
case OperandType.InlineVar:
return 2;
case OperandType.InlineBrTarget:
case OperandType.InlineField:
case OperandType.InlineI:
case OperandType.InlineMethod:
case OperandType.InlineSig:
case OperandType.InlineString:
case OperandType.InlineSwitch:
case OperandType.InlineTok:
case OperandType.InlineType:
case OperandType.ShortInlineR:
return 4;
case OperandType.InlineI8:
case OperandType.InlineR:
return 8;
case OperandType.InlineNone:
default:
return 0;
}
}
}

View File

@ -20,7 +20,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" /> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="8.0.0" /> <PackageReference Include="System.Reflection.MetadataLoadContext" Version="8.0.0" />
<PackageReference Include="Xpl0itR.SystemEx" Version="1.1.0" /> <PackageReference Include="Xpl0itR.SystemEx" Version="1.2.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -11,12 +11,14 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit;
using SystemEx; using SystemEx;
using CommunityToolkit.Diagnostics; using CommunityToolkit.Diagnostics;
using LibProtodec.Models; using LibProtodec.Models;
using LibProtodec.Models.Fields; using LibProtodec.Models.Fields;
using LibProtodec.Models.TopLevels; using LibProtodec.Models.TopLevels;
using LibProtodec.Models.Types; using LibProtodec.Models.Types;
using SystemEx.Memory;
namespace LibProtodec; namespace LibProtodec;
@ -70,6 +72,8 @@ public sealed class ProtodecContext
Protobuf protobuf = GetProtobuf(messageClass, message, options); Protobuf protobuf = GetProtobuf(messageClass, message, options);
ParseWriteToMethodTesting(messageClass);
FieldInfo[] idFields = messageClass.GetFields(PublicStatic); FieldInfo[] idFields = messageClass.GetFields(PublicStatic);
PropertyInfo[] properties = messageClass.GetProperties(PublicInstanceDeclared); PropertyInfo[] properties = messageClass.GetProperties(PublicInstanceDeclared);
@ -128,6 +132,39 @@ public sealed class ProtodecContext
return message; return message;
} }
private static void ParseWriteToMethodTesting(Type messageClass)
{
MethodInfo writeTo = messageClass.GetMethod("WriteTo", BindingFlags.Public | BindingFlags.Instance)!;
MemoryReader reader = new(writeTo.GetMethodBody()!.GetILAsByteArray()!);
int fieldToken = 0;
while (reader.Remaining > 0)
{
OpCode opCode = reader.ReadCilOpCode(out int operandLength);
if (opCode == OpCodes.Ret) // DummyDLL from il2cppdumper will only have ret in method body
return;
if (opCode == OpCodes.Ldfld)
{
fieldToken = reader.ReadInt32LittleEndian();
}
else if (opCode == OpCodes.Call)
{
Guard.IsNotEqualTo(fieldToken, 0);
int methodToken = reader.ReadInt32LittleEndian();
MethodBase? method = messageClass.Module.ResolveMethod(methodToken); // System.NotSupportedException: 'Resolving tokens is not supported on assemblies loaded by a MetadataLoadContext.'
FieldInfo? field = messageClass.Module.ResolveField(fieldToken);
//TODO
}
else
{
reader.Position += operandLength;
}
}
}
public Enum ParseEnum(Type enumEnum, ParserOptions options = ParserOptions.None) public Enum ParseEnum(Type enumEnum, ParserOptions options = ParserOptions.None)
{ {
Guard.IsTrue(enumEnum.IsEnum); Guard.IsTrue(enumEnum.IsEnum);