Skip to content

Commit

Permalink
testing
Browse files Browse the repository at this point in the history
  • Loading branch information
Xpl0itR committed Jun 8, 2024
1 parent d43deef commit 54ba50b
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 1 deletion.
67 changes: 67 additions & 0 deletions src/LibProtodec/CilReader.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
2 changes: 1 addition & 1 deletion src/LibProtodec/LibProtodec.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<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>

</Project>
37 changes: 37 additions & 0 deletions src/LibProtodec/ProtodecContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using SystemEx;
using CommunityToolkit.Diagnostics;
using LibProtodec.Models;
using LibProtodec.Models.Fields;
using LibProtodec.Models.TopLevels;
using LibProtodec.Models.Types;
using SystemEx.Memory;

namespace LibProtodec;

Expand Down Expand Up @@ -70,6 +72,8 @@ public Message ParseMessage(Type messageClass, ParserOptions options = ParserOpt

Protobuf protobuf = GetProtobuf(messageClass, message, options);

ParseWriteToMethodTesting(messageClass);

FieldInfo[] idFields = messageClass.GetFields(PublicStatic);
PropertyInfo[] properties = messageClass.GetProperties(PublicInstanceDeclared);

Expand Down Expand Up @@ -128,6 +132,39 @@ public Message ParseMessage(Type messageClass, ParserOptions options = ParserOpt
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)
{
Guard.IsTrue(enumEnum.IsEnum);
Expand Down

0 comments on commit 54ba50b

Please sign in to comment.