Skip to content

Commit

Permalink
testing
Browse files Browse the repository at this point in the history
  • Loading branch information
Xpl0itR committed Jul 11, 2024
1 parent e94fecc commit 40694c8
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 3 deletions.
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;
}
}
}
5 changes: 5 additions & 0 deletions src/LibProtodec/Models/Cil/Clr/ClrMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using System.Collections.Generic;
using System.Reflection;
using CommunityToolkit.Diagnostics;

namespace LibProtodec.Models.Cil.Clr;

Expand Down Expand Up @@ -35,4 +36,8 @@ public IEnumerable<ICilType> GetParameterTypes()
parameter.ParameterType);
}
}

public byte[] GetMethodBodyILAsByteArray() =>
clrMethod.GetMethodBody()?.GetILAsByteArray()
?? ThrowHelper.ThrowNotSupportedException<byte[]>();
}
27 changes: 27 additions & 0 deletions src/LibProtodec/Models/Cil/Clr/ClrModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Collections.Concurrent;
using System.Reflection;

namespace LibProtodec.Models.Cil.Clr;

public sealed class ClrModule : ICilModule
{
private readonly Module _module;

private ClrModule(Module module) =>
_module = module;

public string ResolveFieldName(int token) =>
_module.ResolveField(token).Name;

public string ResolveMethodName(int token) =>
_module.ResolveMethod(token).Name;


private static readonly ConcurrentDictionary<string, ClrModule> ModuleLookup = [];

public static ICilModule GetOrCreate(Module clrModule) =>
ModuleLookup.GetOrAdd(
clrModule.FullyQualifiedName,
static (_, clrModule) => new ClrModule(clrModule),
clrModule);
}
4 changes: 4 additions & 0 deletions src/LibProtodec/Models/Cil/Clr/ClrType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ private ClrType(Type clrType) : base(clrType) =>
public string DeclaringAssemblyName =>
_clrType.Assembly.FullName!;

public ICilModule DeclaringModule =>
ClrModule.GetOrCreate(
_clrType.Module);

public ICilType? BaseType =>
_clrType.BaseType is null
? null
Expand Down
2 changes: 2 additions & 0 deletions src/LibProtodec/Models/Cil/ICilMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ public interface ICilMethod
IList<ICilAttribute> CustomAttributes { get; }

IEnumerable<ICilType> GetParameterTypes();

byte[] GetMethodBodyILAsByteArray();
}
14 changes: 14 additions & 0 deletions src/LibProtodec/Models/Cil/ICilModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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/.

namespace LibProtodec.Models.Cil;

public interface ICilModule
{
string ResolveFieldName(int token);

string ResolveMethodName(int token);
}
7 changes: 4 additions & 3 deletions src/LibProtodec/Models/Cil/ICilType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ public interface ICilType
string FullName { get; }
string? Namespace { get; }

string DeclaringAssemblyName { get; }
ICilType? DeclaringType { get; }
ICilType? BaseType { get; }
string DeclaringAssemblyName { get; }
ICilModule DeclaringModule { get; }
ICilType? DeclaringType { get; }
ICilType? BaseType { get; }

bool IsAbstract { get; }
bool IsClass { get; }
Expand Down
37 changes: 37 additions & 0 deletions src/LibProtodec/ProtodecContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection.Emit;
using SystemEx;
using SystemEx.Memory;
using CommunityToolkit.Diagnostics;
using LibProtodec.Models.Cil;
using LibProtodec.Models.Protobuf;
Expand Down Expand Up @@ -69,6 +71,8 @@ public virtual Message ParseMessage(ICilType messageClass, ParserOptions options

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

ParseWriteToMethodTesting(messageClass);

List<ICilField> idFields = messageClass.GetFields()
.Where(static field => field is { IsPublic: true, IsStatic: true, IsLiteral: true })
.ToList();
Expand Down Expand Up @@ -137,6 +141,39 @@ public virtual Message ParseMessage(ICilType messageClass, ParserOptions options
return message;
}

private static void ParseWriteToMethodTesting(ICilType messageClass)
{
ICilMethod writeTo = messageClass.GetMethods().Single(static method => method.Name == "WriteTo");
MemoryReader reader = new(writeTo.GetMethodBodyILAsByteArray());

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();

string methodName = messageClass.DeclaringModule.ResolveMethodName(methodToken); // System.NotSupportedException: 'Resolving tokens is not supported on assemblies loaded by a MetadataLoadContext.'
string fieldName = messageClass.DeclaringModule.ResolveFieldName(fieldToken);

//TODO
}
else
{
reader.Position += operandLength;
}
}
}

public virtual Enum ParseEnum(ICilType enumEnum, ParserOptions options = ParserOptions.None)
{
Guard.IsTrue(enumEnum.IsEnum);
Expand Down

0 comments on commit 40694c8

Please sign in to comment.