mirror of https://github.com/Xpl0itR/protodec.git
Merge 40694c833d
into e94fecce66
This commit is contained in:
commit
9c9121920a
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using CommunityToolkit.Diagnostics;
|
||||
|
||||
namespace LibProtodec.Models.Cil.Clr;
|
||||
|
||||
|
@ -35,4 +36,8 @@ public sealed class ClrMethod(MethodInfo clrMethod) : ClrMember(clrMethod), ICil
|
|||
parameter.ParameterType);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetMethodBodyILAsByteArray() =>
|
||||
clrMethod.GetMethodBody()?.GetILAsByteArray()
|
||||
?? ThrowHelper.ThrowNotSupportedException<byte[]>();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -31,6 +31,10 @@ public sealed class ClrType : ClrMember, ICilType
|
|||
public string DeclaringAssemblyName =>
|
||||
_clrType.Assembly.FullName!;
|
||||
|
||||
public ICilModule DeclaringModule =>
|
||||
ClrModule.GetOrCreate(
|
||||
_clrType.Module);
|
||||
|
||||
public ICilType? BaseType =>
|
||||
_clrType.BaseType is null
|
||||
? null
|
||||
|
|
|
@ -23,4 +23,6 @@ public interface ICilMethod
|
|||
IList<ICilAttribute> CustomAttributes { get; }
|
||||
|
||||
IEnumerable<ICilType> GetParameterTypes();
|
||||
|
||||
byte[] GetMethodBodyILAsByteArray();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -15,6 +15,7 @@ public interface ICilType
|
|||
string? Namespace { get; }
|
||||
|
||||
string DeclaringAssemblyName { get; }
|
||||
ICilModule DeclaringModule { get; }
|
||||
ICilType? DeclaringType { get; }
|
||||
ICilType? BaseType { get; }
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ using System.Collections.Generic;
|
|||
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;
|
||||
|
@ -69,6 +71,8 @@ public class ProtodecContext
|
|||
|
||||
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();
|
||||
|
@ -137,6 +141,39 @@ public class ProtodecContext
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue