mirror of https://github.com/Xpl0itR/protodec.git
Merge 40694c833d
into bf2feae2e9
This commit is contained in:
commit
424975d5a2
|
@ -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.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using CommunityToolkit.Diagnostics;
|
||||||
|
|
||||||
namespace LibProtodec.Models.Cil.Clr;
|
namespace LibProtodec.Models.Cil.Clr;
|
||||||
|
|
||||||
|
@ -35,4 +36,8 @@ public sealed class ClrMethod(MethodInfo clrMethod) : ClrMember(clrMethod), ICil
|
||||||
parameter.ParameterType);
|
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 =>
|
public string DeclaringAssemblyName =>
|
||||||
_clrType.Assembly.FullName!;
|
_clrType.Assembly.FullName!;
|
||||||
|
|
||||||
|
public ICilModule DeclaringModule =>
|
||||||
|
ClrModule.GetOrCreate(
|
||||||
|
_clrType.Module);
|
||||||
|
|
||||||
public ICilType? BaseType =>
|
public ICilType? BaseType =>
|
||||||
_clrType.BaseType is null
|
_clrType.BaseType is null
|
||||||
? null
|
? null
|
||||||
|
|
|
@ -23,4 +23,6 @@ public interface ICilMethod
|
||||||
IList<ICilAttribute> CustomAttributes { get; }
|
IList<ICilAttribute> CustomAttributes { get; }
|
||||||
|
|
||||||
IEnumerable<ICilType> GetParameterTypes();
|
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);
|
||||||
|
}
|
|
@ -14,9 +14,10 @@ public interface ICilType
|
||||||
string FullName { get; }
|
string FullName { get; }
|
||||||
string? Namespace { get; }
|
string? Namespace { get; }
|
||||||
|
|
||||||
string DeclaringAssemblyName { get; }
|
string DeclaringAssemblyName { get; }
|
||||||
ICilType? DeclaringType { get; }
|
ICilModule DeclaringModule { get; }
|
||||||
ICilType? BaseType { get; }
|
ICilType? DeclaringType { get; }
|
||||||
|
ICilType? BaseType { get; }
|
||||||
|
|
||||||
bool IsAbstract { get; }
|
bool IsAbstract { get; }
|
||||||
bool IsClass { get; }
|
bool IsClass { get; }
|
||||||
|
|
|
@ -10,7 +10,9 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
using SystemEx;
|
using SystemEx;
|
||||||
|
using SystemEx.Memory;
|
||||||
using CommunityToolkit.Diagnostics;
|
using CommunityToolkit.Diagnostics;
|
||||||
using LibProtodec.Models.Cil;
|
using LibProtodec.Models.Cil;
|
||||||
using LibProtodec.Models.Protobuf;
|
using LibProtodec.Models.Protobuf;
|
||||||
|
@ -69,6 +71,8 @@ public class ProtodecContext
|
||||||
|
|
||||||
Protobuf protobuf = GetProtobuf(messageClass, message, options);
|
Protobuf protobuf = GetProtobuf(messageClass, message, options);
|
||||||
|
|
||||||
|
ParseWriteToMethodTesting(messageClass);
|
||||||
|
|
||||||
List<ICilField> idFields = messageClass.GetFields()
|
List<ICilField> idFields = messageClass.GetFields()
|
||||||
.Where(static field => field is { IsPublic: true, IsStatic: true, IsLiteral: true })
|
.Where(static field => field is { IsPublic: true, IsStatic: true, IsLiteral: true })
|
||||||
.ToList();
|
.ToList();
|
||||||
|
@ -137,6 +141,39 @@ public class ProtodecContext
|
||||||
return message;
|
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)
|
public virtual Enum ParseEnum(ICilType enumEnum, ParserOptions options = ParserOptions.None)
|
||||||
{
|
{
|
||||||
Guard.IsTrue(enumEnum.IsEnum);
|
Guard.IsTrue(enumEnum.IsEnum);
|
||||||
|
|
Loading…
Reference in New Issue