Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 10 additions & 41 deletions Cpp2IL.Core/Cpp2IlApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static void ConfigureLib(bool allowUserToInputAddresses)
LibCpp2IlMain.Settings.MetadataFixupFunc = Cpp2IlPluginManager.MetadataFixupFuncs is { } funcs ? (originalBytes, version) =>
{
Logger.InfoNewline("Received request for metadata fixup from LibCpp2Il. Calling registered plugin fixup functions...");

foreach (var func in funcs)
{
try
Expand All @@ -68,7 +68,7 @@ public static void ConfigureLib(bool allowUserToInputAddresses)
Logger.ErrorNewline($"Metadata fixup function threw an exception: {e}. Ignoring and trying next fixup function, if any...");
}
}

//only get here if every fixup function returns null or throws.
return null;
} : null;
Expand All @@ -89,16 +89,15 @@ public static void InitializeLibCpp2Il(string assemblyPath, string metadataPath,
try
{
#endif
if (!LibCpp2IlMain.LoadFromFile(assemblyPath, metadataPath, unityVersion))
throw new Exception("Initialization with LibCpp2Il failed");
var context = LibCpp2IlMain.LoadFromFileAsContext(assemblyPath, metadataPath, unityVersion);
OnLibInitialized(context);
#if !DEBUG
}
catch (Exception e)
{
throw new LibCpp2ILInitializationException("Fatal Exception initializing LibCpp2IL!", e);
}
#endif
OnLibInitialized();
}

[MemberNotNull(nameof(CurrentAppContext))]
Expand All @@ -112,27 +111,24 @@ public static void InitializeLibCpp2Il(byte[] assemblyData, byte[] metadataData,

try
{
if (!LibCpp2IlMain.Initialize(assemblyData, metadataData, unityVersion))
throw new Exception("Initialization with LibCpp2Il failed");
var context = LibCpp2IlMain.InitializeAsContext(assemblyData, metadataData, unityVersion);
OnLibInitialized(context);
}
catch (Exception e)
{
throw new LibCpp2ILInitializationException("Fatal Exception initializing LibCpp2IL!", e);
}

OnLibInitialized();
}

[MemberNotNull(nameof(CurrentAppContext))]
private static void OnLibInitialized()
private static void OnLibInitialized(LibCpp2IlContext libContext)
{
MiscUtils.Init();
LibCpp2IlMain.Binary!.AllCustomAttributeGenerators.ToList()
libContext.Binary.AllCustomAttributeGenerators.ToList()
.ForEach(ptr => SharedState.AttributeGeneratorStarts.Add(ptr));

var start = DateTime.Now;
Logger.InfoNewline("Creating application model...");
CurrentAppContext = new(LibCpp2IlMain.Binary, LibCpp2IlMain.TheMetadata!);
CurrentAppContext = new(libContext.Binary, libContext.Metadata);
Logger.InfoNewline($"Application model created in {(DateTime.Now - start).TotalMilliseconds}ms");
}

Expand All @@ -144,38 +140,11 @@ public static void ResetInternalState()

AsmResolverUtils.Reset();

LibCpp2IlMain.Reset();

CurrentAppContext = null;
}

// public static void PopulateConcreteImplementations()
// {
// CheckLibInitialized();
//
// Logger.InfoNewline("Populating Concrete Implementation Table...");
//
// foreach (var def in LibCpp2IlMain.TheMetadata!.typeDefs)
// {
// if (def.IsAbstract)
// continue;
//
// var baseTypeReflectionData = def.BaseType;
// while (baseTypeReflectionData != null)
// {
// if (baseTypeReflectionData.baseType == null)
// break;
//
// if (baseTypeReflectionData.isType && baseTypeReflectionData.baseType.IsAbstract && !SharedState.ConcreteImplementations.ContainsKey(baseTypeReflectionData.baseType))
// SharedState.ConcreteImplementations[baseTypeReflectionData.baseType] = def;
//
// baseTypeReflectionData = baseTypeReflectionData.baseType.BaseType;
// }
// }
// }

private static bool IsLibInitialized()
{
return LibCpp2IlMain.Binary != null && LibCpp2IlMain.TheMetadata != null;
return CurrentAppContext != null;
}
}
7 changes: 3 additions & 4 deletions Cpp2IL.Core/Exceptions/UnsupportedInstructionSetException.cs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

boilerplate ahh... primary ctors exist

Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System;
using LibCpp2IL;
using System;

namespace Cpp2IL.Core.Exceptions;

public class UnsupportedInstructionSetException : Exception
public class UnsupportedInstructionSetException(string? instructionSetId = null) : Exception
{
public override string Message => $"This action is not supported on the {LibCpp2IlMain.Binary?.InstructionSetId} instruction set yet. If running the CLI, try adding the --skip-analysis argument.";
public override string Message => $"This action is not supported on the {instructionSetId ?? "unknown"} instruction set yet. If running the CLI, try adding the --skip-analysis argument.";
}
5 changes: 2 additions & 3 deletions Cpp2IL.Core/Graphs/Processors/MetadataProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Cpp2IL.Core.ISIL;
using Cpp2IL.Core.Model.Contexts;
using Cpp2IL.Core.Utils;
using LibCpp2IL;

namespace Cpp2IL.Core.Graphs.Processors;

Expand All @@ -26,11 +25,11 @@ public void Process(MethodAnalysisContext methodAnalysisContext, Block block)
var memoryOp = (IsilMemoryOperand)instruction.Operands[1].Data;
if (memoryOp.Base == null && memoryOp.Index == null && memoryOp.Scale == 0)
{
var val = LibCpp2IlMain.GetLiteralByAddress((ulong)memoryOp.Addend);
var val = methodAnalysisContext.AppContext.LibCpp2IlContext?.GetLiteralByAddress((ulong)memoryOp.Addend);
if (val == null)
{
// Try instead check if its type metadata usage
var metadataUsage = LibCpp2IlMain.GetTypeGlobalByAddress((ulong)memoryOp.Addend);
var metadataUsage = methodAnalysisContext.AppContext.LibCpp2IlContext?.GetTypeGlobalByAddress((ulong)memoryOp.Addend);
if (metadataUsage != null && methodAnalysisContext.DeclaringType is not null)
{
var typeAnalysisContext = metadataUsage.ToContext(methodAnalysisContext.DeclaringType!.DeclaringAssembly);
Expand Down
4 changes: 2 additions & 2 deletions Cpp2IL.Core/Il2CppApiFunctions/Arm64KeyFunctionAddresses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ protected override ulong GetObjectIsInstFromSystemType()
//The last call is to Object::IsInst

Logger.Verbose($"IsInstanceOfType found at 0x{typeIsInstanceOfType.MethodPointer:X}...");
var instructions = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(typeIsInstanceOfType.MethodPointer, false);
var instructions = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(_appContext, typeIsInstanceOfType.MethodPointer, false);

var lastCall = instructions.LastOrDefault(i => i.Mnemonic == "bl");

Expand Down Expand Up @@ -258,7 +258,7 @@ protected override void AttemptInstructionAnalysisToFillGaps()
if (arrayTypeDef.Methods!.FirstOrDefault(m => m.Name == "GetEnumerator") is { } methodDef)
{
var ptr = methodDef.MethodPointer;
var body = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(ptr);
var body = Arm64Utils.GetArm64MethodBodyAtVirtualAddress(_appContext, ptr);

//Looking for adrp, ldr, ldr, bl. Probably more than one - the first will be initializing the method, second will be the constructor call
var probableResult = 0L;
Expand Down
4 changes: 2 additions & 2 deletions Cpp2IL.Core/Il2CppApiFunctions/BaseKeyFunctionAddresses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public abstract class BaseKeyFunctionAddresses

public IEnumerable<KeyValuePair<string, ulong>> Pairs => resolvedAddressMap;

private ApplicationAnalysisContext _appContext = null!; //Always initialized before used
protected ApplicationAnalysisContext _appContext = null!; //Always initialized before used

private readonly Dictionary<string, ulong> resolvedAddressMap = [];
private readonly HashSet<ulong> resolvedAddressSet = [];
Expand Down Expand Up @@ -131,7 +131,7 @@ protected void TryGetInitMetadataFromException()
{
Logger.VerboseNewline($"\t\tTarget Method Located at {targetMethod.MethodPointer}. Taking first CALL as the (version-specific) metadata initialization function...");

var disasm = X86Utils.GetMethodBodyAtVirtAddressNew(targetMethod.MethodPointer, false);
var disasm = X86Utils.GetMethodBodyAtVirtAddressNew(targetMethod.MethodPointer, false, _appContext.Binary);
var calls = disasm.Where(i => i.Mnemonic == Mnemonic.Call).ToList();

if (calls.Count == 0)
Expand Down
21 changes: 11 additions & 10 deletions Cpp2IL.Core/Il2CppApiFunctions/NewArm64KeyFunctionAddresses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Disarm;
using Cpp2IL.Core.Logging;
using Cpp2IL.Core.Utils;
using LibCpp2IL;
using LibCpp2IL.Reflection;

namespace Cpp2IL.Core.Il2CppApiFunctions;
Expand All @@ -17,8 +16,9 @@ private List<Arm64Instruction> DisassembleTextSection()
{
if (_cachedDisassembledBytes == null)
{
var toDisasm = LibCpp2IlMain.Binary!.GetEntirePrimaryExecutableSection();
_cachedDisassembledBytes = Disassembler.Disassemble(toDisasm, LibCpp2IlMain.Binary.GetVirtualAddressOfPrimaryExecutableSection(), new(true, true, false)).ToList();
var binary = _appContext.Binary;
var toDisasm = binary.GetEntirePrimaryExecutableSection();
_cachedDisassembledBytes = Disassembler.Disassemble(toDisasm, binary.GetVirtualAddressOfPrimaryExecutableSection(), new(true, true, false)).ToList();
}

return _cachedDisassembledBytes;
Expand All @@ -37,13 +37,14 @@ protected override IEnumerable<ulong> FindAllThunkFunctions(ulong addr, uint max
if (addressesToIgnore.Contains(matchingJmp.Address)) continue;

//Find this instruction in the raw file
var offsetInPe = (ulong)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(matchingJmp.Address);
if (offsetInPe == 0 || offsetInPe == (ulong)(LibCpp2IlMain.Binary.RawLength - 1))
var binary = _appContext.Binary;
var offsetInPe = (ulong)binary.MapVirtualAddressToRaw(matchingJmp.Address);
if (offsetInPe == 0 || offsetInPe == (ulong)(binary.RawLength - 1))
continue;

//get next and previous bytes
var previousByte = LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe - 1);
var nextByte = LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe + 4);
var previousByte = binary.GetByteAtRawAddress(offsetInPe - 1);
var nextByte = binary.GetByteAtRawAddress(offsetInPe + 4);

//Double-cc = thunk
if (previousByte == 0xCC && nextByte == 0xCC)
Expand All @@ -60,7 +61,7 @@ protected override IEnumerable<ulong> FindAllThunkFunctions(ulong addr, uint max
//Move to next jmp
break;

if (LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC)
if (binary.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC)
{
yield return matchingJmp.Address - (backtrack - 1);
break;
Expand All @@ -86,7 +87,7 @@ protected override ulong GetObjectIsInstFromSystemType()
//The last call is to Object::IsInst

Logger.Verbose($"IsInstanceOfType found at 0x{typeIsInstanceOfType.MethodPointer:X}...");
var instructions = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(typeIsInstanceOfType.MethodPointer, true);
var instructions = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(_appContext.Binary, typeIsInstanceOfType.MethodPointer, true);

var lastCall = instructions.LastOrDefault(i => i.Mnemonic == Arm64Mnemonic.BL);

Expand All @@ -102,7 +103,7 @@ protected override ulong GetObjectIsInstFromSystemType()

protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false)
{
var instructions = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(thunkPtr, true);
var instructions = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(_appContext.Binary, thunkPtr, true);

var target = prioritiseCall ? Arm64Mnemonic.BL : Arm64Mnemonic.B;
var matchingCall = instructions.FirstOrDefault(i => i.Mnemonic == target);
Expand Down
21 changes: 11 additions & 10 deletions Cpp2IL.Core/Il2CppApiFunctions/X86KeyFunctionAddresses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Cpp2IL.Core.Model.Contexts;
using Cpp2IL.Core.Utils;
using Iced.Intel;
using LibCpp2IL;
using LibCpp2IL.Reflection;

namespace Cpp2IL.Core.Il2CppApiFunctions;
Expand All @@ -18,8 +17,9 @@ private InstructionList DisassembleTextSection()
{
if (_cachedDisassembledBytes == null)
{
var toDisasm = LibCpp2IlMain.Binary!.GetEntirePrimaryExecutableSection();
_cachedDisassembledBytes = X86Utils.Disassemble(toDisasm, LibCpp2IlMain.Binary.GetVirtualAddressOfPrimaryExecutableSection());
var binary = _appContext.Binary;
var toDisasm = binary.GetEntirePrimaryExecutableSection();
_cachedDisassembledBytes = X86Utils.Disassemble(toDisasm, binary.GetVirtualAddressOfPrimaryExecutableSection(), binary.is32Bit);
}

return _cachedDisassembledBytes;
Expand All @@ -45,13 +45,14 @@ protected override IEnumerable<ulong> FindAllThunkFunctions(ulong addr, uint max
if (addressesToIgnore.Contains(matchingJmp.IP)) continue;

//Find this instruction in the raw file
var offsetInPe = (ulong)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(matchingJmp.IP);
if (offsetInPe == 0 || offsetInPe == (ulong)(LibCpp2IlMain.Binary!.RawLength - 1))
var binary = _appContext.Binary;
var offsetInPe = (ulong)binary.MapVirtualAddressToRaw(matchingJmp.IP);
if (offsetInPe == 0 || offsetInPe == (ulong)(binary.RawLength - 1))
continue;

//get next and previous bytes
var previousByte = LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe - 1);
var nextByte = LibCpp2IlMain.Binary.GetByteAtRawAddress(offsetInPe + (ulong)matchingJmp.Length);
var previousByte = binary.GetByteAtRawAddress(offsetInPe - 1);
var nextByte = binary.GetByteAtRawAddress(offsetInPe + (ulong)matchingJmp.Length);

//Double-cc = thunk
if (previousByte == 0xCC && nextByte == 0xCC)
Expand All @@ -68,7 +69,7 @@ protected override IEnumerable<ulong> FindAllThunkFunctions(ulong addr, uint max
//Move to next jmp
break;

if (LibCpp2IlMain.Binary!.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC)
if (binary.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC)
{
yield return matchingJmp.IP - (backtrack - 1);
break;
Expand All @@ -94,7 +95,7 @@ protected override ulong GetObjectIsInstFromSystemType()
//The last call is to Object::IsInst

Logger.Verbose($"IsInstanceOfType found at 0x{typeIsInstanceOfType.MethodPointer:X}...");
var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(typeIsInstanceOfType.MethodPointer, true);
var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(typeIsInstanceOfType.MethodPointer, true, _appContext.Binary);

var lastCall = instructions.LastOrDefault(i => i.Mnemonic == Mnemonic.Call);

Expand All @@ -110,7 +111,7 @@ protected override ulong GetObjectIsInstFromSystemType()

protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false)
{
var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(thunkPtr, true);
var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(thunkPtr, true, _appContext.Binary);

var target = prioritiseCall ? Mnemonic.Call : Mnemonic.Jmp;
var matchingCall = instructions.FirstOrDefault(i => i.Mnemonic == target);
Expand Down
16 changes: 8 additions & 8 deletions Cpp2IL.Core/Il2CppArrayUtils.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using LibCpp2IL;
Expand All @@ -7,7 +7,7 @@ namespace Cpp2IL.Core;

public static class Il2CppArrayUtils
{
public static uint FirstItemOffset = (uint)(LibCpp2IlMain.Binary!.is32Bit ? 0x10 : 0x20);
public static uint GetFirstItemOffset(Il2CppBinary binary) => (uint)(binary.is32Bit ? 0x10 : 0x20);
//32-bit:
//0x0: klass ptr
//0x4: monitor ptr
Expand All @@ -23,21 +23,21 @@ public static class Il2CppArrayUtils
new UsefulOffset("length", 0x18, typeof(int), false)
];

public static string? GetOffsetName(uint offset)
public static string? GetOffsetName(uint offset, Il2CppBinary binary)
{
var is32Bit = LibCpp2IlMain.Binary!.is32Bit;
var is32Bit = binary.is32Bit;

return UsefulOffsets.FirstOrDefault(o => o.is32Bit == is32Bit && o.offset == offset)?.name;
}

public static bool IsIl2cppLengthAccessor(uint offset)
public static bool IsIl2cppLengthAccessor(uint offset, Il2CppBinary binary)
{
return GetOffsetName(offset) == "length";
return GetOffsetName(offset, binary) == "length";
}

public static bool IsAtLeastFirstItemPtr(uint offset)
public static bool IsAtLeastFirstItemPtr(uint offset, Il2CppBinary binary)
{
return offset >= FirstItemOffset;
return offset >= GetFirstItemOffset(binary);
}

public class UsefulOffset(string name, uint offset, Type type, bool is32Bit)
Expand Down
Loading