Compare commits
28 Commits
master
...
refactored
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d43157cab5 | ||
|
|
97cbf243b5 | ||
|
|
e6307d009c | ||
|
|
2bd24b9c12 | ||
|
|
226d0dfd1d | ||
|
|
5cd94784f5 | ||
|
|
bcbf4f47e2 | ||
|
|
3982e5fd99 | ||
|
|
e0e8d052ea | ||
|
|
08431b774a | ||
|
|
5715760e8b | ||
|
|
792268f52f | ||
|
|
8895979388 | ||
|
|
daa80bcffe | ||
|
|
d59f67216a | ||
|
|
095bfa16e8 | ||
|
|
e67f856299 | ||
|
|
7632ff2283 | ||
|
|
1a12cf5081 | ||
|
|
e6c51b47d6 | ||
|
|
5d827fe881 | ||
|
|
a7081ccfa9 | ||
|
|
43d7433e12 | ||
|
|
6c59434984 | ||
|
|
2d3b186b4d | ||
|
|
23e873280d | ||
|
|
22ecdc3612 | ||
|
|
30c019c4ef |
96
.github/workflows/build.yml
vendored
96
.github/workflows/build.yml
vendored
@@ -1,57 +1,77 @@
|
|||||||
name: Il2CppInspectorRedux Build
|
name: Il2CppInspectorRedux Build
|
||||||
|
|
||||||
on:
|
on: [push, workflow_dispatch]
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build-gui:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- uses: microsoft/setup-msbuild@v1.1
|
- name: Setup .NET SDK
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '9.0.x'
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.nuget/packages
|
||||||
|
key: ${{ runner.os }}-nuget-gui-${{ hashFiles('**/packages.lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-nuget-gui-
|
||||||
|
|
||||||
|
- name: Restore NuGet packages
|
||||||
|
run: dotnet restore -r win-x64 ./Il2CppInspector.GUI
|
||||||
|
|
||||||
|
- name: Build GUI
|
||||||
|
run: dotnet publish ./Il2CppInspector.GUI/Il2CppInspector.GUI.csproj -c Release -r win-x64 --no-self-contained
|
||||||
|
|
||||||
|
- name: Upload GUI Artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Il2CppInspectorRedux.GUI
|
||||||
|
path: Il2CppInspector.GUI/bin/Release/net9.0-windows/win-x64/publish
|
||||||
|
|
||||||
|
build-cli:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
dotnet-version: [ '9.0.x' ]
|
||||||
|
rid: ['win-x64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
|
- name: Setup .NET SDK
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '9.0.x'
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/.nuget/packages
|
path: ~/.nuget/packages
|
||||||
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
key: ${{ runner.os }}-nuget-cli-${{ matrix.rid }}-${{ hashFiles('**/packages.lock.json') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-nuget-
|
${{ runner.os }}-nuget-cli-${{ matrix.rid }}-
|
||||||
|
|
||||||
- name: Restore NuGet packages
|
- name: Setup .NET SDK ${{ matrix.dotnet-version }}
|
||||||
run: nuget restore
|
uses: actions/setup-dotnet@v3
|
||||||
|
|
||||||
- name: Build GUI
|
|
||||||
run: msbuild /t:Il2CppInspector_GUI:publish /p:Configuration=Release /p:Platform="Any CPU" /p:TargetFramework=net8.0-windows /p:SelfContained=false /verbosity:minimal
|
|
||||||
|
|
||||||
- name: Build CLI
|
|
||||||
run: msbuild /t:Il2CppInspector_CLI:publish /p:Configuration=Release /p:Platform="Any CPU" /p:TargetFramework=net8.0 /p:SelfContained=false /verbosity:minimal
|
|
||||||
|
|
||||||
- name: Add Plugins folder (GUI)
|
|
||||||
shell: pwsh
|
|
||||||
working-directory: Il2CppInspector.GUI/bin/Release/net8.0-windows/win-x64/publish
|
|
||||||
run: ../../../../../../get-plugins.ps1
|
|
||||||
|
|
||||||
- name: Add Plugins folder (CLI)
|
|
||||||
shell: pwsh
|
|
||||||
working-directory: Il2CppInspector.CLI/bin/Release/net8.0/win-x64/publish
|
|
||||||
run: ../../../../../../get-plugins.ps1
|
|
||||||
|
|
||||||
- name: Upload GUI Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
with:
|
||||||
name: Il2CppInspectorRedux.GUI
|
dotnet-version: ${{ matrix.dotnet-version }}
|
||||||
path: Il2CppInspector.GUI/bin/Release/net8.0-windows/win-x64/publish
|
|
||||||
|
|
||||||
- name: Upload CLI Artifact
|
- name: Install dependencies
|
||||||
uses: actions/upload-artifact@v2
|
run: dotnet restore -r ${{ matrix.rid }} ./Il2CppInspector.CLI
|
||||||
|
|
||||||
|
- name: Build & Publish
|
||||||
|
run: dotnet publish -c Release --no-self-contained --no-restore -o ./${{ matrix.rid }} -r ${{ matrix.rid }} ./Il2CppInspector.CLI/Il2CppInspector.CLI.csproj
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Il2CppInspectorRedux.CLI
|
name: Il2CppInspectorRedux.CLI-${{ matrix.rid }}
|
||||||
path: Il2CppInspector.CLI/bin/Release/net8.0/win-x64/publish
|
path: ./${{ matrix.rid }}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
<!-- Plugins may require bass class library assemblies we're not using so disable trimming -->
|
<!-- Plugins may require bass class library assemblies we're not using so disable trimming -->
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommandLineParser" Version="2.6.0" />
|
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -342,10 +343,10 @@ namespace Il2CppInspector
|
|||||||
// In v21 and later, R0-R2 + PC will be set and they will be the only registers set
|
// In v21 and later, R0-R2 + PC will be set and they will be the only registers set
|
||||||
// Pre-v21, R0-R1 + PC will be the only registers set
|
// Pre-v21, R0-R1 + PC will be the only registers set
|
||||||
|
|
||||||
if (image.Version >= 21 && regs.Count == 4 && regs.TryGetValue(0, out r0) && regs.TryGetValue(1, out r1) && regs.TryGetValue(2, out uint _))
|
if (image.Version >= MetadataVersions.V210 && regs.Count == 4 && regs.TryGetValue(0, out r0) && regs.TryGetValue(1, out r1) && regs.TryGetValue(2, out uint _))
|
||||||
return (r0 & 0xffff_fffe, r1 & 0xffff_fffe);
|
return (r0 & 0xffff_fffe, r1 & 0xffff_fffe);
|
||||||
|
|
||||||
if (image.Version < 21 && regs.Count == 3 && regs.TryGetValue(0, out r0) && regs.TryGetValue(1, out r1))
|
if (image.Version < MetadataVersions.V210 && regs.Count == 3 && regs.TryGetValue(0, out r0) && regs.TryGetValue(1, out r1))
|
||||||
return (r0 & 0xffff_fffe, r1 & 0xffff_fffe);
|
return (r0 & 0xffff_fffe, r1 & 0xffff_fffe);
|
||||||
|
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
@@ -168,10 +169,10 @@ namespace Il2CppInspector
|
|||||||
// Is it Il2CppCodegenRegistration(void)?
|
// Is it Il2CppCodegenRegistration(void)?
|
||||||
// In v21 and later, X0-X2 will be set and they will be the only registers set
|
// In v21 and later, X0-X2 will be set and they will be the only registers set
|
||||||
// Pre-v21, X0-X1 will be the only registers set
|
// Pre-v21, X0-X1 will be the only registers set
|
||||||
if (image.Version >= 21 && regs.Count == 3 && regs.TryGetValue(0, out ulong x0) && regs.TryGetValue(1, out x1) && regs.TryGetValue(2, out ulong _))
|
if (image.Version >= MetadataVersions.V210 && regs.Count == 3 && regs.TryGetValue(0, out ulong x0) && regs.TryGetValue(1, out x1) && regs.TryGetValue(2, out ulong _))
|
||||||
return (x0, x1);
|
return (x0, x1);
|
||||||
|
|
||||||
if (image.Version < 21 && regs.Count == 2 && regs.TryGetValue(0, out x0) && regs.TryGetValue(1, out x1))
|
if (image.Version < MetadataVersions.V210 && regs.Count == 2 && regs.TryGetValue(0, out x0) && regs.TryGetValue(1, out x1))
|
||||||
return (x0, x1);
|
return (x0, x1);
|
||||||
|
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
@@ -216,7 +217,7 @@ namespace Il2CppInspector
|
|||||||
offset = nextLea?.foundOffset + leaSize ?? buff2Size;
|
offset = nextLea?.foundOffset + leaSize ?? buff2Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((image.Version < 21 && leas.Count == 2) || (image.Version >= 21 && leas.Count == 3)) {
|
if ((image.Version < MetadataVersions.V210 && leas.Count == 2) || (image.Version >= MetadataVersions.V210 && leas.Count == 3)) {
|
||||||
// Register-based argument passing?
|
// Register-based argument passing?
|
||||||
var leaRSI = leas.FirstOrDefault(l => l.Value == RSI).Key.address;
|
var leaRSI = leas.FirstOrDefault(l => l.Value == RSI).Key.address;
|
||||||
var leaRDI = leas.FirstOrDefault(l => l.Value == RDI).Key.address;
|
var leaRDI = leas.FirstOrDefault(l => l.Value == RDI).Key.address;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ namespace Il2CppInspector
|
|||||||
return (0, 0);
|
return (0, 0);
|
||||||
|
|
||||||
// Jump to Il2CppCodegenRegistration
|
// Jump to Il2CppCodegenRegistration
|
||||||
if(image.Version < 21) {
|
if(image.Version < MetadataVersions.V210) {
|
||||||
image.Position = image.MapVATR((ulong)pCgr + 1);
|
image.Position = image.MapVATR((ulong)pCgr + 1);
|
||||||
metadata = image.ReadUInt32();
|
metadata = image.ReadUInt32();
|
||||||
image.Position = image.MapVATR((ulong)pCgr + 6);
|
image.Position = image.MapVATR((ulong)pCgr + 6);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,8 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
namespace Il2CppInspector.Cpp.UnityHeaders
|
namespace Il2CppInspector.Cpp.UnityHeaders
|
||||||
{
|
{
|
||||||
@@ -19,7 +21,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
public class UnityHeaders : IEquatable<UnityHeaders>
|
public class UnityHeaders : IEquatable<UnityHeaders>
|
||||||
{
|
{
|
||||||
// Metadata version for which this group of headers are valid. Multiple headers may have the same metadata version
|
// Metadata version for which this group of headers are valid. Multiple headers may have the same metadata version
|
||||||
public double MetadataVersion { get; }
|
public StructVersion MetadataVersion { get; }
|
||||||
|
|
||||||
// Range of Unity versions for which this group of headers are valid
|
// Range of Unity versions for which this group of headers are valid
|
||||||
public UnityVersionRange VersionRange { get; }
|
public UnityVersionRange VersionRange { get; }
|
||||||
@@ -114,7 +116,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
|
|
||||||
if (metadataVersion != binary.Image.Version)
|
if (metadataVersion != binary.Image.Version)
|
||||||
continue;
|
continue;
|
||||||
if (metadataVersion == 21) {
|
if (metadataVersion == MetadataVersions.V210) {
|
||||||
/* Special version logic for metadata version 21 based on the Il2CppMetadataRegistration.fieldOffsets field */
|
/* Special version logic for metadata version 21 based on the Il2CppMetadataRegistration.fieldOffsets field */
|
||||||
var headerFieldOffsetsArePointers = r.VersionRange.Min.CompareTo("5.3.7") >= 0 && r.VersionRange.Min.CompareTo("5.4.0") != 0;
|
var headerFieldOffsetsArePointers = r.VersionRange.Min.CompareTo("5.3.7") >= 0 && r.VersionRange.Min.CompareTo("5.4.0") != 0;
|
||||||
var binaryFieldOffsetsArePointers = binary.FieldOffsets == null;
|
var binaryFieldOffsetsArePointers = binary.FieldOffsets == null;
|
||||||
@@ -194,8 +196,8 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the metadata version from a type header resource name
|
// Get the metadata version from a type header resource name
|
||||||
private static double GetMetadataVersionFromFilename(string resourceName)
|
private static StructVersion GetMetadataVersionFromFilename(string resourceName)
|
||||||
=> double.Parse(resourceName.Substring(typeof(UnityHeaders).Namespace.Length + 1).Split('-')[0], NumberFormatInfo.InvariantInfo);
|
=> resourceName[(typeof(UnityHeaders).Namespace!.Length + 1)..].Split('-')[0];
|
||||||
|
|
||||||
// Equality comparisons
|
// Equality comparisons
|
||||||
public static bool operator ==(UnityHeaders first, UnityHeaders second) {
|
public static bool operator ==(UnityHeaders first, UnityHeaders second) {
|
||||||
|
|||||||
@@ -528,11 +528,28 @@ namespace Il2CppInspector
|
|||||||
// Note if uiAddr is a valid segment but filesz < memsz and the adjusted uiAddr falls between the range of filesz and memsz,
|
// Note if uiAddr is a valid segment but filesz < memsz and the adjusted uiAddr falls between the range of filesz and memsz,
|
||||||
// an exception will be thrown. This area of memory is assumed to contain all zeroes.
|
// an exception will be thrown. This area of memory is assumed to contain all zeroes.
|
||||||
public override uint MapVATR(ulong uiAddr) {
|
public override uint MapVATR(ulong uiAddr) {
|
||||||
|
// Additions in the argument to MapVATR may cause an overflow which should be discarded for 32-bit files
|
||||||
|
if (!TryMapVATR(uiAddr, out var offset))
|
||||||
|
throw new InvalidOperationException("Failed to map virtual address");
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool TryMapVATR(ulong uiAddr, out uint fileOffset)
|
||||||
|
{
|
||||||
// Additions in the argument to MapVATR may cause an overflow which should be discarded for 32-bit files
|
// Additions in the argument to MapVATR may cause an overflow which should be discarded for 32-bit files
|
||||||
if (Bits == 32)
|
if (Bits == 32)
|
||||||
uiAddr &= 0xffff_ffff;
|
uiAddr &= 0xffff_ffff;
|
||||||
var program_header_table = this.PHT.First(x => uiAddr >= conv.ULong(x.p_vaddr) && uiAddr <= conv.ULong(conv.Add(x.p_vaddr, x.p_filesz)));
|
|
||||||
return (uint) (uiAddr - conv.ULong(conv.Sub(program_header_table.p_vaddr, program_header_table.p_offset)));
|
var phtEntry = PHT.FirstOrDefault(x => uiAddr >= conv.ULong(x.p_vaddr) && uiAddr <= conv.ULong(conv.Add(x.p_vaddr, x.p_filesz)));
|
||||||
|
if (phtEntry == null)
|
||||||
|
{
|
||||||
|
fileOffset = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileOffset = (uint)(uiAddr - conv.ULong(conv.Sub(phtEntry.p_vaddr, phtEntry.p_offset)));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ulong MapFileOffsetToVA(uint offset) {
|
public override ulong MapFileOffsetToVA(uint offset) {
|
||||||
|
|||||||
@@ -6,17 +6,20 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using NoisyCowStudios.Bin2Object;
|
using NoisyCowStudios.Bin2Object;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
public interface IFileFormatStream
|
public interface IFileFormatStream
|
||||||
{
|
{
|
||||||
double Version { get; set; }
|
StructVersion Version { get; set; }
|
||||||
long Length { get; }
|
long Length { get; }
|
||||||
uint NumImages { get; }
|
uint NumImages { get; }
|
||||||
string DefaultFilename { get; }
|
string DefaultFilename { get; }
|
||||||
@@ -91,6 +94,9 @@ namespace Il2CppInspector
|
|||||||
long[] ReadMappedWordArray(ulong uiAddr, int count);
|
long[] ReadMappedWordArray(ulong uiAddr, int count);
|
||||||
List<U> ReadMappedObjectPointerArray<U>(ulong uiAddr, int count) where U : new();
|
List<U> ReadMappedObjectPointerArray<U>(ulong uiAddr, int count) where U : new();
|
||||||
|
|
||||||
|
ulong ReadMappedUWord(ulong uiAddr);
|
||||||
|
ulong[] ReadMappedUWordArray(ulong uiAddr, int count);
|
||||||
|
|
||||||
void WriteEndianBytes(byte[] bytes);
|
void WriteEndianBytes(byte[] bytes);
|
||||||
void Write(long int64);
|
void Write(long int64);
|
||||||
void Write(ulong uint64);
|
void Write(ulong uint64);
|
||||||
@@ -120,6 +126,30 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
public void AddPrimitiveMapping(Type objType, Type streamType);
|
public void AddPrimitiveMapping(Type objType, Type streamType);
|
||||||
public void CopyTo(Stream stream);
|
public void CopyTo(Stream stream);
|
||||||
|
|
||||||
|
public TType ReadMappedPrimitive<TType>(ulong addr) where TType : unmanaged;
|
||||||
|
public TType ReadPrimitive<TType>(long addr) where TType : unmanaged;
|
||||||
|
public TType ReadPrimitive<TType>() where TType : unmanaged;
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadMappedPrimitiveArray<TType>(ulong addr, long count) where TType : unmanaged;
|
||||||
|
public ImmutableArray<TType> ReadPrimitiveArray<TType>(long addr, long count) where TType : unmanaged;
|
||||||
|
public ImmutableArray<TType> ReadPrimitiveArray<TType>(long count) where TType : unmanaged;
|
||||||
|
|
||||||
|
public TType ReadMappedVersionedObject<TType>(ulong addr) where TType : IReadable, new();
|
||||||
|
public TType ReadVersionedObject<TType>(long addr) where TType : IReadable, new();
|
||||||
|
public TType ReadVersionedObject<TType>() where TType : IReadable, new();
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadMappedVersionedObjectArray<TType>(ulong addr, long count)
|
||||||
|
where TType : IReadable, new();
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadVersionedObjectArray<TType>(long addr, long count)
|
||||||
|
where TType : IReadable, new();
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadVersionedObjectArray<TType>(long count)
|
||||||
|
where TType : IReadable, new();
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadMappedVersionedObjectPointerArray<TType>(ulong addr, int count)
|
||||||
|
where TType : IReadable, new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FileFormatStream
|
public class FileFormatStream
|
||||||
@@ -160,7 +190,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class FileFormatStream<T> : BinaryObjectStream, IFileFormatStream where T : FileFormatStream<T>
|
public abstract class FileFormatStream<T> : BinaryObjectStreamReader, IFileFormatStream where T : FileFormatStream<T>
|
||||||
{
|
{
|
||||||
public abstract string DefaultFilename { get; }
|
public abstract string DefaultFilename { get; }
|
||||||
|
|
||||||
@@ -254,7 +284,7 @@ namespace Il2CppInspector
|
|||||||
public virtual uint MapVATR(ulong uiAddr) => (uint) uiAddr;
|
public virtual uint MapVATR(ulong uiAddr) => (uint) uiAddr;
|
||||||
|
|
||||||
// Try to map an RVA to an offset in the file image
|
// Try to map an RVA to an offset in the file image
|
||||||
public bool TryMapVATR(ulong uiAddr, out uint fileOffset) {
|
public virtual bool TryMapVATR(ulong uiAddr, out uint fileOffset) {
|
||||||
try {
|
try {
|
||||||
fileOffset = MapVATR(uiAddr);
|
fileOffset = MapVATR(uiAddr);
|
||||||
return true;
|
return true;
|
||||||
@@ -322,5 +352,42 @@ namespace Il2CppInspector
|
|||||||
array.Add(ReadMappedObject<U>(pointers[i]));
|
array.Add(ReadMappedObject<U>(pointers[i]));
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TType ReadMappedPrimitive<TType>(ulong addr) where TType : unmanaged => ReadPrimitive<TType>(MapVATR(addr));
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadMappedPrimitiveArray<TType>(ulong addr, long count) where TType : unmanaged
|
||||||
|
=> ReadPrimitiveArray<TType>(MapVATR(addr), count);
|
||||||
|
|
||||||
|
public TType ReadMappedVersionedObject<TType>(ulong addr) where TType : IReadable, new() => ReadVersionedObject<TType>(MapVATR(addr));
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadMappedVersionedObjectArray<TType>(ulong addr, long count) where TType : IReadable, new()
|
||||||
|
=> ReadVersionedObjectArray<TType>(MapVATR(addr), count);
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadMappedVersionedObjectPointerArray<TType>(ulong addr, int count)
|
||||||
|
where TType : IReadable, new()
|
||||||
|
{
|
||||||
|
var pointers = ReadMappedUWordArray(addr, count);
|
||||||
|
var builder = ImmutableArray.CreateBuilder<TType>((int)count);
|
||||||
|
for (long i = 0; i < count; i++)
|
||||||
|
builder.Add(ReadMappedVersionedObject<TType>(pointers[i]));
|
||||||
|
|
||||||
|
return builder.MoveToImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong ReadMappedUWord(ulong uiAddr)
|
||||||
|
{
|
||||||
|
Position = MapVATR(uiAddr);
|
||||||
|
return ReadNUInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong[] ReadMappedUWordArray(ulong uiAddr, int count)
|
||||||
|
{
|
||||||
|
Position = MapVATR(uiAddr);
|
||||||
|
var arr = new ulong[count];
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
arr[i] = ReadNUInt();
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,76 +140,10 @@ namespace Il2CppInspector
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load DLL into memory and save it as a new PE stream
|
|
||||||
private void load() {
|
|
||||||
// Check that the process is running in the same word size as the DLL
|
|
||||||
// One way round this in future would be to spawn a new process of the correct word size
|
|
||||||
if ((Environment.Is64BitProcess && Bits == 32) || (!Environment.Is64BitProcess && Bits == 64))
|
|
||||||
throw new InvalidOperationException($"Cannot unpack a {Bits}-bit DLL from within a {(Environment.Is64BitProcess ? 64 : 32)}-bit process. Use the {Bits}-version of Il2CppInspector to unpack this DLL.");
|
|
||||||
|
|
||||||
// Get file path
|
|
||||||
// This error should never occur with the bundled CLI and GUI; only when used as a library by a 3rd party tool
|
|
||||||
if (LoadOptions == null || !(LoadOptions.BinaryFilePath is string dllPath))
|
|
||||||
throw new InvalidOperationException("To load a packed PE file, you must specify the DLL file path in LoadOptions");
|
|
||||||
|
|
||||||
// Attempt to load DLL and run startup functions
|
|
||||||
// NOTE: This can cause a CSE (AccessViolation) for certain types of protection
|
|
||||||
// so only try to unpack as the final load strategy
|
|
||||||
IntPtr hModule = LoadLibrary(dllPath);
|
|
||||||
if (hModule == IntPtr.Zero) {
|
|
||||||
var lastErrorCode = Marshal.GetLastWin32Error();
|
|
||||||
throw new InvalidOperationException($"Unable to load the DLL for unpacking: error code {lastErrorCode}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maximum image size
|
|
||||||
var size = sections.Last().VirtualAddress + sections.Last().VirtualSize;
|
|
||||||
|
|
||||||
// Allocate memory for unpacked image
|
|
||||||
var peBytes = new byte[size];
|
|
||||||
|
|
||||||
// Copy relevant sections from unmanaged memory
|
|
||||||
foreach (var section in sections.Where(s => wantedSectionTypes.Keys.Contains(s.Characteristics)))
|
|
||||||
Marshal.Copy(IntPtr.Add(hModule, (int) section.VirtualAddress), peBytes, (int) section.VirtualAddress, (int) section.VirtualSize);
|
|
||||||
|
|
||||||
// Decrease reference count for unload
|
|
||||||
FreeLibrary(hModule);
|
|
||||||
|
|
||||||
// Rebase
|
|
||||||
pe.ImageBase = (ulong) hModule.ToInt64();
|
|
||||||
|
|
||||||
// Rewrite sections to match memory layout
|
|
||||||
foreach (var section in sections) {
|
|
||||||
section.PointerToRawData = section.VirtualAddress;
|
|
||||||
section.SizeOfRawData = section.VirtualSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Truncate memory stream at start of COFF header
|
|
||||||
var endOfSignature = ReadUInt32(0x3C) + 4; // DOS header + 4-byte PE signature
|
|
||||||
SetLength(endOfSignature);
|
|
||||||
|
|
||||||
// Re-write the stream (the headers are only necessary in case the user wants to save)
|
|
||||||
Position = endOfSignature;
|
|
||||||
WriteObject(coff);
|
|
||||||
if (Bits == 32) WriteObject((PEOptHeader32) pe);
|
|
||||||
else WriteObject((PEOptHeader64) pe);
|
|
||||||
WriteArray(sections);
|
|
||||||
Write(peBytes, (int) Position, peBytes.Length - (int) Position);
|
|
||||||
|
|
||||||
IsModified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raw file / unpacked file load strategies
|
// Raw file / unpacked file load strategies
|
||||||
public override IEnumerable<IFileFormatStream> TryNextLoadStrategy() {
|
public override IEnumerable<IFileFormatStream> TryNextLoadStrategy() {
|
||||||
// First load strategy: the regular file
|
// First load strategy: the regular file
|
||||||
yield return this;
|
yield return this;
|
||||||
|
|
||||||
// Second load strategy: load the DLL into memory to unpack it
|
|
||||||
if (mightBePacked) {
|
|
||||||
Console.WriteLine("IL2CPP binary appears to be packed - attempting to unpack and retrying");
|
|
||||||
StatusUpdate("Unpacking binary");
|
|
||||||
load();
|
|
||||||
yield return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override uint[] GetFunctionTable() {
|
public override uint[] GetFunctionTable() {
|
||||||
@@ -227,12 +161,17 @@ namespace Il2CppInspector
|
|||||||
return addrs.ToArray();
|
return addrs.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<Export> GetExports() {
|
public override IEnumerable<Export> GetExports()
|
||||||
|
{
|
||||||
|
var exportDirectory = pe.DataDirectory[0];
|
||||||
|
if (exportDirectory.Size == 0)
|
||||||
|
return [];
|
||||||
|
|
||||||
// Get exports table
|
// Get exports table
|
||||||
var ETStart = pe.DataDirectory[0].VirtualAddress + pe.ImageBase;
|
var exportTableStart = exportDirectory.VirtualAddress + pe.ImageBase;
|
||||||
|
|
||||||
// Get export RVAs
|
// Get export RVAs
|
||||||
var exportDirectoryTable = ReadObject<PEExportDirectory>(MapVATR(ETStart));
|
var exportDirectoryTable = ReadObject<PEExportDirectory>(MapVATR(exportTableStart));
|
||||||
var exportCount = (int) exportDirectoryTable.NumberOfFunctions;
|
var exportCount = (int) exportDirectoryTable.NumberOfFunctions;
|
||||||
var exportAddresses = ReadArray<uint>(MapVATR(exportDirectoryTable.AddressOfFunctions + pe.ImageBase), exportCount);
|
var exportAddresses = ReadArray<uint>(MapVATR(exportDirectoryTable.AddressOfFunctions + pe.ImageBase), exportCount);
|
||||||
var exports = exportAddresses.Select((a, i) => new Export {
|
var exports = exportAddresses.Select((a, i) => new Export {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace Il2CppInspector
|
|||||||
Position = arch.Offset;
|
Position = arch.Offset;
|
||||||
Endianness = Endianness.Little;
|
Endianness = Endianness.Little;
|
||||||
|
|
||||||
using var s = new BinaryObjectStream(ReadBytes((int) arch.Size));
|
using var s = new BinaryObjectStream(ReadBytes((int) arch.Size).ToArray());
|
||||||
return (IFileFormatStream) MachOReader32.Load(s, LoadOptions, OnStatusUpdate) ?? MachOReader64.Load(s, LoadOptions, OnStatusUpdate);
|
return (IFileFormatStream) MachOReader32.Load(s, LoadOptions, OnStatusUpdate) ?? MachOReader64.Load(s, LoadOptions, OnStatusUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
|
using Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
using Il2CppInspector.Reflection;
|
using Il2CppInspector.Reflection;
|
||||||
using Il2CppInspector.Utils;
|
using Il2CppInspector.Utils;
|
||||||
using NoisyCowStudios.Bin2Object;
|
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
@@ -14,7 +16,7 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
private readonly Il2CppInspector _inspector;
|
private readonly Il2CppInspector _inspector;
|
||||||
private readonly Assembly _assembly;
|
private readonly Assembly _assembly;
|
||||||
private readonly BinaryObjectStream _data;
|
private readonly BinaryObjectStreamReader _data;
|
||||||
|
|
||||||
private readonly uint _start;
|
private readonly uint _start;
|
||||||
private readonly uint _end;
|
private readonly uint _end;
|
||||||
@@ -24,7 +26,7 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
public uint Count { get; }
|
public uint Count { get; }
|
||||||
|
|
||||||
public CustomAttributeDataReader(Il2CppInspector inspector, Assembly assembly, BinaryObjectStream data, uint startOffset, uint endOffset)
|
public CustomAttributeDataReader(Il2CppInspector inspector, Assembly assembly, BinaryObjectStreamReader data, uint startOffset, uint endOffset)
|
||||||
{
|
{
|
||||||
_inspector = inspector;
|
_inspector = inspector;
|
||||||
_assembly = assembly;
|
_assembly = assembly;
|
||||||
@@ -143,9 +145,9 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TypeInfo ConvertTypeDef(Il2CppTypeDefinition typeDef, Il2CppTypeEnum type)
|
private TypeInfo ConvertTypeDef(Il2CppTypeDefinition typeDef, Il2CppTypeEnum type)
|
||||||
=> typeDef == null
|
=> typeDef.IsValid
|
||||||
? _assembly.Model.GetTypeDefinitionFromTypeEnum(type)
|
? _assembly.Model.TypesByDefinitionIndex[_inspector.TypeDefinitions.IndexOf(typeDef)]
|
||||||
: _assembly.Model.TypesByDefinitionIndex[Array.IndexOf(_inspector.TypeDefinitions, typeDef)];
|
: _assembly.Model.GetTypeDefinitionFromTypeEnum(type);
|
||||||
|
|
||||||
private (TypeInfo, int) ReadCustomAttributeNamedArgumentClassAndIndex(TypeInfo attrInfo)
|
private (TypeInfo, int) ReadCustomAttributeNamedArgumentClassAndIndex(TypeInfo attrInfo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,13 +5,14 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using Il2CppInspector.Next;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
@@ -34,16 +35,16 @@ namespace Il2CppInspector
|
|||||||
public ulong CodeRegistrationPointer { get; private set; }
|
public ulong CodeRegistrationPointer { get; private set; }
|
||||||
public ulong MetadataRegistrationPointer { get; private set; }
|
public ulong MetadataRegistrationPointer { get; private set; }
|
||||||
public ulong RegistrationFunctionPointer { get; private set; }
|
public ulong RegistrationFunctionPointer { get; private set; }
|
||||||
public Dictionary<string, ulong> CodeGenModulePointers { get; } = new Dictionary<string, ulong>();
|
public Dictionary<string, ulong> CodeGenModulePointers { get; } = new();
|
||||||
|
|
||||||
// Only for <=v24.1
|
// Only for <=v24.1
|
||||||
public ulong[] GlobalMethodPointers { get; set; }
|
public ulong[] GlobalMethodPointers { get; set; }
|
||||||
|
|
||||||
// Only for >=v24.2
|
// Only for >=v24.2
|
||||||
public Dictionary<Il2CppCodeGenModule, ulong[]> ModuleMethodPointers { get; set; } = new Dictionary<Il2CppCodeGenModule, ulong[]>();
|
public Dictionary<Il2CppCodeGenModule, ulong[]> ModuleMethodPointers { get; set; } = new();
|
||||||
|
|
||||||
// Only for >=v24.2. In earlier versions, invoker indices are stored in Il2CppMethodDefinition in the metadata file
|
// Only for >=v24.2. In earlier versions, invoker indices are stored in Il2CppMethodDefinition in the metadata file
|
||||||
public Dictionary<Il2CppCodeGenModule, int[]> MethodInvokerIndices { get; set; } = new Dictionary<Il2CppCodeGenModule, int[]>();
|
public Dictionary<Il2CppCodeGenModule, ImmutableArray<int>> MethodInvokerIndices { get; set; } = new();
|
||||||
|
|
||||||
// NOTE: In versions <21 and earlier releases of v21, use FieldOffsets:
|
// NOTE: In versions <21 and earlier releases of v21, use FieldOffsets:
|
||||||
// global field index => field offset
|
// global field index => field offset
|
||||||
@@ -51,7 +52,7 @@ namespace Il2CppInspector
|
|||||||
// type index => RVA in image where the list of field offsets for the type start (4 bytes per field)
|
// type index => RVA in image where the list of field offsets for the type start (4 bytes per field)
|
||||||
|
|
||||||
// Negative field offsets from start of each function
|
// Negative field offsets from start of each function
|
||||||
public uint[] FieldOffsets { get; private set; }
|
public ImmutableArray<uint> FieldOffsets { get; private set; }
|
||||||
|
|
||||||
// Pointers to field offsets
|
// Pointers to field offsets
|
||||||
public long[] FieldOffsetPointers { get; private set; }
|
public long[] FieldOffsetPointers { get; private set; }
|
||||||
@@ -65,13 +66,13 @@ namespace Il2CppInspector
|
|||||||
public ulong[] MethodInvokePointers { get; private set; }
|
public ulong[] MethodInvokePointers { get; private set; }
|
||||||
|
|
||||||
// Version 16 and below: method references for vtable
|
// Version 16 and below: method references for vtable
|
||||||
public uint[] VTableMethodReferences { get; private set; }
|
public ImmutableArray<uint> VTableMethodReferences { get; private set; }
|
||||||
|
|
||||||
// Generic method specs for vtables
|
// Generic method specs for vtables
|
||||||
public Il2CppMethodSpec[] MethodSpecs { get; private set; }
|
public ImmutableArray<Il2CppMethodSpec> MethodSpecs { get; private set; }
|
||||||
|
|
||||||
// List of run-time concrete generic class and method signatures
|
// List of run-time concrete generic class and method signatures
|
||||||
public List<Il2CppGenericInst> GenericInstances { get; private set; }
|
public ImmutableArray<Il2CppGenericInst> GenericInstances { get; private set; }
|
||||||
|
|
||||||
// List of constructed generic method function pointers corresponding to each possible method instantiation
|
// List of constructed generic method function pointers corresponding to each possible method instantiation
|
||||||
public Dictionary<Il2CppMethodSpec, ulong> GenericMethodPointers { get; } = new Dictionary<Il2CppMethodSpec, ulong>();
|
public Dictionary<Il2CppMethodSpec, ulong> GenericMethodPointers { get; } = new Dictionary<Il2CppMethodSpec, ulong>();
|
||||||
@@ -80,7 +81,7 @@ namespace Il2CppInspector
|
|||||||
public Dictionary<Il2CppMethodSpec, int> GenericMethodInvokerIndices { get; } = new Dictionary<Il2CppMethodSpec, int>();
|
public Dictionary<Il2CppMethodSpec, int> GenericMethodInvokerIndices { get; } = new Dictionary<Il2CppMethodSpec, int>();
|
||||||
|
|
||||||
// Every type reference (TypeRef) sorted by index
|
// Every type reference (TypeRef) sorted by index
|
||||||
public List<Il2CppType> TypeReferences { get; private set; }
|
public ImmutableArray<Il2CppType> TypeReferences { get; private set; }
|
||||||
|
|
||||||
// Every type reference index sorted by virtual address
|
// Every type reference index sorted by virtual address
|
||||||
public Dictionary<ulong, int> TypeReferenceIndicesByAddress { get; private set; }
|
public Dictionary<ulong, int> TypeReferenceIndicesByAddress { get; private set; }
|
||||||
@@ -89,7 +90,7 @@ namespace Il2CppInspector
|
|||||||
// One assembly may contain multiple modules
|
// One assembly may contain multiple modules
|
||||||
public Dictionary<string, Il2CppCodeGenModule> Modules { get; private set; }
|
public Dictionary<string, Il2CppCodeGenModule> Modules { get; private set; }
|
||||||
|
|
||||||
public List<Il2CppTypeDefinitionSizes> TypeDefinitionSizes { get; private set; }
|
public ImmutableArray<Il2CppTypeDefinitionSizes> TypeDefinitionSizes { get; private set; }
|
||||||
|
|
||||||
// Status update callback
|
// Status update callback
|
||||||
private EventHandler<string> OnStatusUpdate { get; set; }
|
private EventHandler<string> OnStatusUpdate { get; set; }
|
||||||
@@ -135,7 +136,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load binary without a global-metadata.dat available
|
// Load binary without a global-metadata.dat available
|
||||||
public static Il2CppBinary Load(IFileFormatStream stream, double metadataVersion, EventHandler<string> statusCallback = null) {
|
public static Il2CppBinary Load(IFileFormatStream stream, StructVersion metadataVersion, EventHandler<string> statusCallback = null) {
|
||||||
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
|
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
|
||||||
var inst = LoadImpl(stream, statusCallback);
|
var inst = LoadImpl(stream, statusCallback);
|
||||||
if (inst.FindRegistrationStructs(metadataVersion))
|
if (inst.FindRegistrationStructs(metadataVersion))
|
||||||
@@ -167,7 +168,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize binary without a global-metadata.dat available
|
// Initialize binary without a global-metadata.dat available
|
||||||
public bool FindRegistrationStructs(double metadataVersion) {
|
public bool FindRegistrationStructs(StructVersion metadataVersion) {
|
||||||
Image.Version = metadataVersion;
|
Image.Version = metadataVersion;
|
||||||
|
|
||||||
StatusUpdate("Searching for binary metadata");
|
StatusUpdate("Searching for binary metadata");
|
||||||
@@ -277,29 +278,8 @@ namespace Il2CppInspector
|
|||||||
Console.WriteLine("MetadataRegistration struct found at 0x{0:X16} (file offset 0x{1:X8})", Image.Bits == 32 ? metadataRegistration & 0xffff_ffff : metadataRegistration, Image.MapVATR(metadataRegistration));
|
Console.WriteLine("MetadataRegistration struct found at 0x{0:X16} (file offset 0x{1:X8})", Image.Bits == 32 ? metadataRegistration & 0xffff_ffff : metadataRegistration, Image.MapVATR(metadataRegistration));
|
||||||
|
|
||||||
// Root structures from which we find everything else
|
// Root structures from which we find everything else
|
||||||
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
CodeRegistration = Image.ReadMappedVersionedObject<Il2CppCodeRegistration>(codeRegistration);
|
||||||
MetadataRegistration = Image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
|
MetadataRegistration = Image.ReadMappedVersionedObject<Il2CppMetadataRegistration>(metadataRegistration);
|
||||||
|
|
||||||
// genericAdjustorThunks was inserted before invokerPointersCount in 24.5 and 27.1
|
|
||||||
// pointer expected if we need to bump version
|
|
||||||
if (Image.Version == 24.4 && CodeRegistration.invokerPointersCount > 0x50000)
|
|
||||||
{
|
|
||||||
Image.Version = 24.5;
|
|
||||||
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Image.Version == 24.4 && CodeRegistration.reversePInvokeWrapperCount > 0x50000) {
|
|
||||||
Image.Version = 24.5;
|
|
||||||
codeRegistration -= 1 * pointerSize;
|
|
||||||
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Image.Version is 29 or 31 && (long)CodeRegistration.genericMethodPointersCount - MetadataRegistration.genericMethodTableCount > 0x10000)
|
|
||||||
{
|
|
||||||
Image.Version += 0.1;
|
|
||||||
codeRegistration -= 2 * pointerSize;
|
|
||||||
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin hook to pre-process binary
|
// Plugin hook to pre-process binary
|
||||||
isModified |= PluginHooks.PreProcessBinary(this).IsStreamModified;
|
isModified |= PluginHooks.PreProcessBinary(this).IsStreamModified;
|
||||||
@@ -313,36 +293,36 @@ namespace Il2CppInspector
|
|||||||
* typeRefPointers must be a series of pointers in __const
|
* typeRefPointers must be a series of pointers in __const
|
||||||
* MethodInvokePointers must be a series of pointers in __text or .text, and in sequential order
|
* MethodInvokePointers must be a series of pointers in __text or .text, and in sequential order
|
||||||
*/
|
*/
|
||||||
if ((Metadata != null && Metadata.Types.Length != MetadataRegistration.typeDefinitionsSizesCount)
|
if ((Metadata != null && Metadata.Types.Length != MetadataRegistration.TypeDefinitionsSizesCount)
|
||||||
|| CodeRegistration.reversePInvokeWrapperCount > 0x10000
|
|| CodeRegistration.ReversePInvokeWrapperCount > 0x10000
|
||||||
|| CodeRegistration.unresolvedVirtualCallCount > 0x4000 // >= 22
|
|| CodeRegistration.UnresolvedVirtualCallCount > 0x4000 // >= 22
|
||||||
|| CodeRegistration.interopDataCount > 0x1000 // >= 23
|
|| CodeRegistration.InteropDataCount > 0x1000 // >= 23
|
||||||
|| (Image.Version <= 24.1 && CodeRegistration.invokerPointersCount > CodeRegistration.methodPointersCount))
|
|| (Image.Version <= MetadataVersions.V241 && CodeRegistration.InvokerPointersCount > CodeRegistration.MethodPointersCount))
|
||||||
throw new NotSupportedException("The detected Il2CppCodeRegistration / Il2CppMetadataRegistration structs do not pass validation. This may mean that their fields have been re-ordered as a form of obfuscation and Il2CppInspector has not been able to restore the original order automatically. Consider re-ordering the fields in Il2CppBinaryClasses.cs and try again.");
|
throw new NotSupportedException("The detected Il2CppCodeRegistration / Il2CppMetadataRegistration structs do not pass validation. This may mean that their fields have been re-ordered as a form of obfuscation and Il2CppInspector has not been able to restore the original order automatically. Consider re-ordering the fields in Il2CppBinaryClasses.cs and try again.");
|
||||||
|
|
||||||
// The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule
|
// The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule
|
||||||
if (Image.Version <= 24.1)
|
if (Image.Version <= MetadataVersions.V241)
|
||||||
GlobalMethodPointers = Image.ReadMappedArray<ulong>(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount);
|
GlobalMethodPointers = Image.ReadMappedUWordArray(CodeRegistration.MethodPointers, (int) CodeRegistration.MethodPointersCount);
|
||||||
|
|
||||||
// After v24 method pointers and RGCTX data were stored in Il2CppCodeGenModules
|
// After v24 method pointers and RGCTX data were stored in Il2CppCodeGenModules
|
||||||
if (Image.Version >= 24.2) {
|
if (Image.Version >= MetadataVersions.V242) {
|
||||||
Modules = new Dictionary<string, Il2CppCodeGenModule>();
|
Modules = new Dictionary<string, Il2CppCodeGenModule>();
|
||||||
|
|
||||||
// In v24.3, windowsRuntimeFactoryTable collides with codeGenModules. So far no samples have had windowsRuntimeFactoryCount > 0;
|
// In v24.3, windowsRuntimeFactoryTable collides with codeGenModules. So far no samples have had windowsRuntimeFactoryCount > 0;
|
||||||
// if this changes we'll have to get smarter about disambiguating these two.
|
// if this changes we'll have to get smarter about disambiguating these two.
|
||||||
if (CodeRegistration.codeGenModulesCount == 0) {
|
if (CodeRegistration.CodeGenModulesCount == 0) {
|
||||||
Image.Version = 24.3;
|
Image.Version = MetadataVersions.V243;
|
||||||
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
CodeRegistration = Image.ReadMappedVersionedObject<Il2CppCodeRegistration>(codeRegistration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array of pointers to Il2CppCodeGenModule
|
// Array of pointers to Il2CppCodeGenModule
|
||||||
var codeGenModulePointers = Image.ReadMappedArray<ulong>(CodeRegistration.pcodeGenModules, (int) CodeRegistration.codeGenModulesCount);
|
var codeGenModulePointers = Image.ReadMappedUWordArray(CodeRegistration.CodeGenModules, (int) CodeRegistration.CodeGenModulesCount);
|
||||||
var modules = Image.ReadMappedObjectPointerArray<Il2CppCodeGenModule>(CodeRegistration.pcodeGenModules, (int) CodeRegistration.codeGenModulesCount);
|
var modules = Image.ReadMappedVersionedObjectPointerArray<Il2CppCodeGenModule>(CodeRegistration.CodeGenModules, (int) CodeRegistration.CodeGenModulesCount);
|
||||||
|
|
||||||
foreach (var mp in modules.Zip(codeGenModulePointers, (m, p) => new { Module = m, Pointer = p })) {
|
foreach (var mp in modules.Zip(codeGenModulePointers, (m, p) => new { Module = m, Pointer = p })) {
|
||||||
var module = mp.Module;
|
var module = mp.Module;
|
||||||
|
|
||||||
var name = Image.ReadMappedNullTerminatedString(module.moduleName);
|
var name = Image.ReadMappedNullTerminatedString(module.ModuleName);
|
||||||
Modules.Add(name, module);
|
Modules.Add(name, module);
|
||||||
CodeGenModulePointers.Add(name, mp.Pointer);
|
CodeGenModulePointers.Add(name, mp.Pointer);
|
||||||
|
|
||||||
@@ -351,24 +331,24 @@ namespace Il2CppInspector
|
|||||||
// the entire method pointer array will be NULL values, causing the methodPointer to be mapped to .bss
|
// the entire method pointer array will be NULL values, causing the methodPointer to be mapped to .bss
|
||||||
// and therefore out of scope of the binary image
|
// and therefore out of scope of the binary image
|
||||||
try {
|
try {
|
||||||
ModuleMethodPointers.Add(module, Image.ReadMappedArray<ulong>(module.methodPointers, (int) module.methodPointerCount));
|
ModuleMethodPointers.Add(module, Image.ReadMappedUWordArray(module.MethodPointers, (int) module.MethodPointerCount));
|
||||||
} catch (InvalidOperationException) {
|
} catch (InvalidOperationException) {
|
||||||
ModuleMethodPointers.Add(module, new ulong[module.methodPointerCount]);
|
ModuleMethodPointers.Add(module, new ulong[module.MethodPointerCount]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read method invoker pointer indices - one per method
|
// Read method invoker pointer indices - one per method
|
||||||
MethodInvokerIndices.Add(module, Image.ReadMappedArray<int>(module.invokerIndices, (int) module.methodPointerCount));
|
MethodInvokerIndices.Add(module, Image.ReadMappedPrimitiveArray<int>(module.InvokerIndices, (int) module.MethodPointerCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field offset data. Metadata <=21.x uses a value-type array; >=21.x uses a pointer array
|
// Field offset data. Metadata <=21.x uses a value-type array; >=21.x uses a pointer array
|
||||||
|
|
||||||
// Versions from 22 onwards use an array of pointers in Binary.FieldOffsetData
|
// Versions from 22 onwards use an array of pointers in Binary.FieldOffsetData
|
||||||
bool fieldOffsetsArePointers = (Image.Version >= 22);
|
bool fieldOffsetsArePointers = (Image.Version >= MetadataVersions.V220);
|
||||||
|
|
||||||
// Some variants of 21 also use an array of pointers
|
// Some variants of 21 also use an array of pointers
|
||||||
if (Image.Version == 21) {
|
if (Image.Version == MetadataVersions.V210) {
|
||||||
var fieldTest = Image.ReadMappedWordArray(MetadataRegistration.pfieldOffsets, 6);
|
var fieldTest = Image.ReadMappedWordArray(MetadataRegistration.FieldOffsets, 6);
|
||||||
|
|
||||||
// We detect this by relying on the fact Module, Object, ValueType, Attribute, _Attribute and Int32
|
// We detect this by relying on the fact Module, Object, ValueType, Attribute, _Attribute and Int32
|
||||||
// are always the first six defined types, and that all but Int32 have no fields
|
// are always the first six defined types, and that all but Int32 have no fields
|
||||||
@@ -377,29 +357,66 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// All older versions use values directly in the array
|
// All older versions use values directly in the array
|
||||||
if (!fieldOffsetsArePointers)
|
if (!fieldOffsetsArePointers)
|
||||||
FieldOffsets = Image.ReadMappedArray<uint>(MetadataRegistration.pfieldOffsets, (int)MetadataRegistration.fieldOffsetsCount);
|
FieldOffsets = Image.ReadMappedPrimitiveArray<uint>(MetadataRegistration.FieldOffsets, (int)MetadataRegistration.FieldOffsetsCount);
|
||||||
else
|
else
|
||||||
FieldOffsetPointers = Image.ReadMappedWordArray(MetadataRegistration.pfieldOffsets, (int)MetadataRegistration.fieldOffsetsCount);
|
FieldOffsetPointers = Image.ReadMappedWordArray(MetadataRegistration.FieldOffsets, (int)MetadataRegistration.FieldOffsetsCount);
|
||||||
|
|
||||||
// Type references (pointer array)
|
// Type references (pointer array)
|
||||||
var typeRefPointers = Image.ReadMappedArray<ulong>(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount);
|
var typeRefPointers = Image.ReadMappedUWordArray(MetadataRegistration.Types, (int) MetadataRegistration.TypesCount);
|
||||||
TypeReferenceIndicesByAddress = typeRefPointers.Zip(Enumerable.Range(0, typeRefPointers.Length), (a, i) => new { a, i }).ToDictionary(x => x.a, x => x.i);
|
TypeReferenceIndicesByAddress = typeRefPointers.Zip(Enumerable.Range(0, typeRefPointers.Length), (a, i) => new { a, i }).ToDictionary(x => x.a, x => x.i);
|
||||||
|
|
||||||
TypeReferences =
|
TypeReferences = Image.ReadMappedVersionedObjectPointerArray<Il2CppType>(MetadataRegistration.Types, (int)MetadataRegistration.TypesCount);
|
||||||
Image.Version >= 27.2
|
|
||||||
? Image.ReadMappedObjectPointerArray<Il2CppTypeV272>(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount)
|
if (TypeReferences.Any(x =>
|
||||||
.Cast<Il2CppType>()
|
x.Type.IsTypeDefinitionEnum()
|
||||||
.ToList()
|
&& (uint)x.Data.KlassIndex >= (uint)Metadata.Types.Length))
|
||||||
: Image.ReadMappedObjectPointerArray<Il2CppType>(MetadataRegistration.ptypes, (int)MetadataRegistration.typesCount);
|
{
|
||||||
|
// This is a memory-dumped binary.
|
||||||
|
// We need to fix the remapped type indices from their pointer form back to the indices.
|
||||||
|
var baseDefinitionPtr = ulong.MaxValue;
|
||||||
|
var baseGenericPtr = ulong.MaxValue;
|
||||||
|
|
||||||
|
foreach (var entry in TypeReferences)
|
||||||
|
{
|
||||||
|
if (entry.Type.IsTypeDefinitionEnum())
|
||||||
|
{
|
||||||
|
baseDefinitionPtr = Math.Min(baseDefinitionPtr, entry.Data.Type.PointerValue);
|
||||||
|
}
|
||||||
|
else if (entry.Type.IsGenericParameterEnum())
|
||||||
|
{
|
||||||
|
baseGenericPtr = Math.Min(baseGenericPtr, entry.Data.GenericParameterHandle.PointerValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var definitionSize = (ulong)Il2CppTypeDefinition.Size(Image.Version);
|
||||||
|
var genericParameterSize = (ulong)Il2CppGenericParameter.Size(Image.Version);
|
||||||
|
|
||||||
|
var builder = ImmutableArray.CreateBuilder<Il2CppType>(TypeReferences.Length);
|
||||||
|
for (var i = 0; i < TypeReferences.Length; i++)
|
||||||
|
{
|
||||||
|
var type = TypeReferences[i];
|
||||||
|
if (type.Type.IsTypeDefinitionEnum())
|
||||||
|
{
|
||||||
|
type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize;
|
||||||
|
}
|
||||||
|
else if (type.Type.IsGenericParameterEnum())
|
||||||
|
{
|
||||||
|
type.Data.Value = (type.Data.Type.PointerValue - baseGenericPtr) / genericParameterSize;
|
||||||
|
}
|
||||||
|
builder.Add(type);
|
||||||
|
}
|
||||||
|
TypeReferences = builder.MoveToImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
// Custom attribute constructors (function pointers)
|
// Custom attribute constructors (function pointers)
|
||||||
// This is managed in Il2CppInspector for metadata >= 27
|
// This is managed in Il2CppInspector for metadata >= 27
|
||||||
if (Image.Version < 27) {
|
if (Image.Version < MetadataVersions.V270) {
|
||||||
CustomAttributeGenerators = Image.ReadMappedArray<ulong>(CodeRegistration.customAttributeGenerators, (int) CodeRegistration.customAttributeCount);
|
CustomAttributeGenerators = Image.ReadMappedUWordArray(CodeRegistration.CustomAttributeGenerators, (int) CodeRegistration.CustomAttributeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method.Invoke function pointers
|
// Method.Invoke function pointers
|
||||||
MethodInvokePointers = Image.ReadMappedArray<ulong>(CodeRegistration.invokerPointers, (int) CodeRegistration.invokerPointersCount);
|
MethodInvokePointers = Image.ReadMappedUWordArray(CodeRegistration.InvokerPointers, (int) CodeRegistration.InvokerPointersCount);
|
||||||
|
|
||||||
// TODO: Function pointers as shown below
|
// TODO: Function pointers as shown below
|
||||||
// reversePInvokeWrappers
|
// reversePInvokeWrappers
|
||||||
@@ -408,26 +425,26 @@ namespace Il2CppInspector
|
|||||||
// >=22: unresolvedVirtualCallPointers
|
// >=22: unresolvedVirtualCallPointers
|
||||||
// >=23: interopData
|
// >=23: interopData
|
||||||
|
|
||||||
if (Image.Version < 19) {
|
if (Image.Version < MetadataVersions.V190) {
|
||||||
VTableMethodReferences = Image.ReadMappedArray<uint>(MetadataRegistration.methodReferences, (int)MetadataRegistration.methodReferencesCount);
|
VTableMethodReferences = Image.ReadMappedPrimitiveArray<uint>(MetadataRegistration.MethodReferences, (int)MetadataRegistration.MethodReferencesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic type and method specs (open and closed constructed types)
|
// Generic type and method specs (open and closed constructed types)
|
||||||
MethodSpecs = Image.ReadMappedArray<Il2CppMethodSpec>(MetadataRegistration.methodSpecs, (int) MetadataRegistration.methodSpecsCount);
|
MethodSpecs = Image.ReadMappedVersionedObjectArray<Il2CppMethodSpec>(MetadataRegistration.MethodSpecs, (int) MetadataRegistration.MethodSpecsCount);
|
||||||
|
|
||||||
// Concrete generic class and method signatures
|
// Concrete generic class and method signatures
|
||||||
GenericInstances = Image.ReadMappedObjectPointerArray<Il2CppGenericInst>(MetadataRegistration.genericInsts, (int) MetadataRegistration.genericInstsCount);
|
GenericInstances = Image.ReadMappedVersionedObjectPointerArray<Il2CppGenericInst>(MetadataRegistration.GenericInsts, (int) MetadataRegistration.GenericInstsCount);
|
||||||
|
|
||||||
// Concrete generic method pointers
|
// Concrete generic method pointers
|
||||||
var genericMethodPointers = Image.ReadMappedArray<ulong>(CodeRegistration.genericMethodPointers, (int) CodeRegistration.genericMethodPointersCount);
|
var genericMethodPointers = Image.ReadMappedUWordArray(CodeRegistration.GenericMethodPointers, (int) CodeRegistration.GenericMethodPointersCount);
|
||||||
var genericMethodTable = Image.ReadMappedArray<Il2CppGenericMethodFunctionsDefinitions>(MetadataRegistration.genericMethodTable, (int) MetadataRegistration.genericMethodTableCount);
|
var genericMethodTable = Image.ReadMappedVersionedObjectArray<Il2CppGenericMethodFunctionsDefinitions>(MetadataRegistration.GenericMethodTable, (int) MetadataRegistration.GenericMethodTableCount);
|
||||||
foreach (var tableEntry in genericMethodTable) {
|
foreach (var tableEntry in genericMethodTable) {
|
||||||
GenericMethodPointers.Add(MethodSpecs[tableEntry.genericMethodIndex], genericMethodPointers[tableEntry.indices.methodIndex]);
|
GenericMethodPointers.Add(MethodSpecs[tableEntry.GenericMethodIndex], genericMethodPointers[tableEntry.Indices.MethodIndex]);
|
||||||
GenericMethodInvokerIndices.Add(MethodSpecs[tableEntry.genericMethodIndex], tableEntry.indices.invokerIndex);
|
GenericMethodInvokerIndices.Add(MethodSpecs[tableEntry.GenericMethodIndex], tableEntry.Indices.InvokerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDefinitionSizes = Image.ReadMappedObjectPointerArray<Il2CppTypeDefinitionSizes>(
|
TypeDefinitionSizes = Image.ReadMappedVersionedObjectPointerArray<Il2CppTypeDefinitionSizes>(
|
||||||
MetadataRegistration.typeDefinitionsSizes, (int) MetadataRegistration.typeDefinitionsSizesCount);
|
MetadataRegistration.TypeDefinitionsSizes, (int) MetadataRegistration.TypeDefinitionsSizesCount);
|
||||||
|
|
||||||
// Plugin hook to pre-process binary
|
// Plugin hook to pre-process binary
|
||||||
isModified |= PluginHooks.PostProcessBinary(this).IsStreamModified;
|
isModified |= PluginHooks.PostProcessBinary(this).IsStreamModified;
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper
|
|
||||||
Copyright 2017-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using NoisyCowStudios.Bin2Object;
|
|
||||||
|
|
||||||
namespace Il2CppInspector
|
|
||||||
{
|
|
||||||
// From class-internals.h / il2cpp-class-internals.h
|
|
||||||
public class Il2CppCodeRegistration
|
|
||||||
{
|
|
||||||
// Moved to Il2CppCodeGenModule in v24.2
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public ulong methodPointersCount;
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public ulong pmethodPointers;
|
|
||||||
|
|
||||||
public ulong reversePInvokeWrapperCount; // (was renamed from delegateWrappersFromNativeToManagedCount in v22)
|
|
||||||
public ulong reversePInvokeWrappers; // (was renamed from delegateWrappersFromNativeToManaged in v22)
|
|
||||||
|
|
||||||
// Removed in metadata v23
|
|
||||||
[Version(Max = 22)]
|
|
||||||
public ulong delegateWrappersFromManagedToNativeCount;
|
|
||||||
[Version(Max = 22)]
|
|
||||||
public ulong delegateWrappersFromManagedToNative;
|
|
||||||
[Version(Max = 22)]
|
|
||||||
public ulong marshalingFunctionsCount;
|
|
||||||
[Version(Max = 22)]
|
|
||||||
public ulong marshalingFunctions;
|
|
||||||
[Version(Min = 21, Max = 22)]
|
|
||||||
public ulong ccwMarshalingFunctionsCount;
|
|
||||||
[Version(Min = 21, Max = 22)]
|
|
||||||
public ulong ccwMarshalingFunctions;
|
|
||||||
|
|
||||||
public ulong genericMethodPointersCount;
|
|
||||||
public ulong genericMethodPointers;
|
|
||||||
[Version(Min = 24.5, Max = 24.5)]
|
|
||||||
[Version(Min = 27.1)]
|
|
||||||
public ulong genericAdjustorThunks;
|
|
||||||
|
|
||||||
public ulong invokerPointersCount;
|
|
||||||
public ulong invokerPointers;
|
|
||||||
|
|
||||||
// Removed in metadata v27
|
|
||||||
[Version(Max = 24.5)]
|
|
||||||
public long customAttributeCount;
|
|
||||||
[Version(Max = 24.5)]
|
|
||||||
public ulong customAttributeGenerators;
|
|
||||||
|
|
||||||
// Removed in metadata v23
|
|
||||||
[Version(Min = 21, Max = 22)]
|
|
||||||
public long guidCount;
|
|
||||||
[Version(Min = 21, Max = 22)]
|
|
||||||
public ulong guids; // Il2CppGuid
|
|
||||||
|
|
||||||
// Added in metadata v22
|
|
||||||
[Version(Min = 22, Max = 29)]
|
|
||||||
public ulong unresolvedVirtualCallCount;
|
|
||||||
|
|
||||||
[Version(Min = 29.1, Max = 29.1)]
|
|
||||||
[Version(Min = 31.1, Max = 31.1)]
|
|
||||||
public ulong unresolvedIndirectCallCount;
|
|
||||||
|
|
||||||
[Version(Min = 22)]
|
|
||||||
public ulong unresolvedVirtualCallPointers;
|
|
||||||
|
|
||||||
[Version(Min = 29.1, Max = 29.1)]
|
|
||||||
[Version(Min = 31.1, Max = 31.1)]
|
|
||||||
public ulong unresolvedInstanceCallPointers;
|
|
||||||
|
|
||||||
[Version(Min = 29.1, Max = 29.1)]
|
|
||||||
[Version(Min = 31.1, Max = 31.1)]
|
|
||||||
public ulong unresolvedStaticCallPointers;
|
|
||||||
|
|
||||||
// Added in metadata v23
|
|
||||||
[Version(Min = 23)]
|
|
||||||
public ulong interopDataCount;
|
|
||||||
[Version(Min = 23)]
|
|
||||||
public ulong interopData;
|
|
||||||
|
|
||||||
[Version(Min = 24.3)]
|
|
||||||
public ulong windowsRuntimeFactoryCount;
|
|
||||||
[Version(Min = 24.3)]
|
|
||||||
public ulong windowsRuntimeFactoryTable;
|
|
||||||
|
|
||||||
// Added in metadata v24.2 to replace methodPointers and methodPointersCount
|
|
||||||
[Version(Min = 24.2)]
|
|
||||||
public ulong codeGenModulesCount;
|
|
||||||
[Version(Min = 24.2)]
|
|
||||||
public ulong pcodeGenModules;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Introduced in metadata v24.2 (replaces method pointers in Il2CppCodeRegistration)
|
|
||||||
public class Il2CppCodeGenModule
|
|
||||||
{
|
|
||||||
public ulong moduleName;
|
|
||||||
public ulong methodPointerCount;
|
|
||||||
public ulong methodPointers;
|
|
||||||
[Version(Min = 24.5, Max = 24.5)]
|
|
||||||
[Version(Min = 27.1)]
|
|
||||||
public long adjustorThunkCount;
|
|
||||||
[Version(Min = 24.5, Max = 24.5)]
|
|
||||||
[Version(Min = 27.1)]
|
|
||||||
public ulong adjustorThunks; //Pointer
|
|
||||||
public ulong invokerIndices;
|
|
||||||
public ulong reversePInvokeWrapperCount;
|
|
||||||
public ulong reversePInvokeWrapperIndices;
|
|
||||||
public ulong rgctxRangesCount;
|
|
||||||
public ulong rgctxRanges;
|
|
||||||
public ulong rgctxsCount;
|
|
||||||
public ulong rgctxs;
|
|
||||||
public ulong debuggerMetadata;
|
|
||||||
|
|
||||||
// Added in metadata v27
|
|
||||||
[Version(Min = 27, Max = 27.2)]
|
|
||||||
public ulong customAttributeCacheGenerator; // CustomAttributesCacheGenerator*
|
|
||||||
[Version(Min = 27)]
|
|
||||||
public ulong moduleInitializer; // Il2CppMethodPointer
|
|
||||||
[Version(Min = 27)]
|
|
||||||
public ulong staticConstructorTypeIndices; // TypeDefinitionIndex*
|
|
||||||
[Version(Min = 27)]
|
|
||||||
public ulong metadataRegistration; // Il2CppMetadataRegistration* // Per-assembly mode only
|
|
||||||
[Version(Min = 27)]
|
|
||||||
public ulong codeRegistration; // Il2CppCodeRegistration* // Per-assembly mode only
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CS0649
|
|
||||||
public class Il2CppMetadataRegistration
|
|
||||||
{
|
|
||||||
public long genericClassesCount;
|
|
||||||
public ulong genericClasses;
|
|
||||||
public long genericInstsCount;
|
|
||||||
public ulong genericInsts;
|
|
||||||
public long genericMethodTableCount;
|
|
||||||
public ulong genericMethodTable; // Il2CppGenericMethodFunctionsDefinitions
|
|
||||||
public long typesCount;
|
|
||||||
public ulong ptypes;
|
|
||||||
public long methodSpecsCount;
|
|
||||||
public ulong methodSpecs;
|
|
||||||
[Version(Max = 16)]
|
|
||||||
public long methodReferencesCount;
|
|
||||||
[Version(Max = 16)]
|
|
||||||
public ulong methodReferences;
|
|
||||||
|
|
||||||
public long fieldOffsetsCount;
|
|
||||||
public ulong pfieldOffsets; // Changed from int32_t* to int32_t** after 5.4.0f3, before 5.5.0f3
|
|
||||||
|
|
||||||
public long typeDefinitionsSizesCount;
|
|
||||||
public ulong typeDefinitionsSizes;
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public ulong metadataUsagesCount;
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public ulong metadataUsages;
|
|
||||||
}
|
|
||||||
#pragma warning restore CS0649
|
|
||||||
|
|
||||||
// From blob.h / il2cpp-blob.h
|
|
||||||
public enum Il2CppTypeEnum
|
|
||||||
{
|
|
||||||
IL2CPP_TYPE_END = 0x00, /* End of List */
|
|
||||||
IL2CPP_TYPE_VOID = 0x01,
|
|
||||||
IL2CPP_TYPE_BOOLEAN = 0x02,
|
|
||||||
IL2CPP_TYPE_CHAR = 0x03,
|
|
||||||
IL2CPP_TYPE_I1 = 0x04,
|
|
||||||
IL2CPP_TYPE_U1 = 0x05,
|
|
||||||
IL2CPP_TYPE_I2 = 0x06,
|
|
||||||
IL2CPP_TYPE_U2 = 0x07,
|
|
||||||
IL2CPP_TYPE_I4 = 0x08,
|
|
||||||
IL2CPP_TYPE_U4 = 0x09,
|
|
||||||
IL2CPP_TYPE_I8 = 0x0a,
|
|
||||||
IL2CPP_TYPE_U8 = 0x0b,
|
|
||||||
IL2CPP_TYPE_R4 = 0x0c,
|
|
||||||
IL2CPP_TYPE_R8 = 0x0d,
|
|
||||||
IL2CPP_TYPE_STRING = 0x0e,
|
|
||||||
IL2CPP_TYPE_PTR = 0x0f, /* arg: <type> token */
|
|
||||||
IL2CPP_TYPE_BYREF = 0x10, /* arg: <type> token */
|
|
||||||
IL2CPP_TYPE_VALUETYPE = 0x11, /* arg: <type> token */
|
|
||||||
IL2CPP_TYPE_CLASS = 0x12, /* arg: <type> token */
|
|
||||||
IL2CPP_TYPE_VAR = 0x13, /* Generic parameter in a generic type definition, represented as number (compressed unsigned integer) number */
|
|
||||||
IL2CPP_TYPE_ARRAY = 0x14, /* type, rank, boundsCount, bound1, loCount, lo1 */
|
|
||||||
IL2CPP_TYPE_GENERICINST = 0x15, /* <type> <type-arg-count> <type-1> \x{2026} <type-n> */
|
|
||||||
IL2CPP_TYPE_TYPEDBYREF = 0x16,
|
|
||||||
IL2CPP_TYPE_I = 0x18,
|
|
||||||
IL2CPP_TYPE_U = 0x19,
|
|
||||||
IL2CPP_TYPE_FNPTR = 0x1b, /* arg: full method signature */
|
|
||||||
IL2CPP_TYPE_OBJECT = 0x1c,
|
|
||||||
IL2CPP_TYPE_SZARRAY = 0x1d, /* 0-based one-dim-array */
|
|
||||||
IL2CPP_TYPE_MVAR = 0x1e, /* Generic parameter in a generic method definition, represented as number (compressed unsigned integer) */
|
|
||||||
IL2CPP_TYPE_CMOD_REQD = 0x1f, /* arg: typedef or typeref token */
|
|
||||||
IL2CPP_TYPE_CMOD_OPT = 0x20, /* optional arg: typedef or typref token */
|
|
||||||
IL2CPP_TYPE_INTERNAL = 0x21, /* CLR internal type */
|
|
||||||
|
|
||||||
IL2CPP_TYPE_MODIFIER = 0x40, /* Or with the following types */
|
|
||||||
IL2CPP_TYPE_SENTINEL = 0x41, /* Sentinel for varargs method signature */
|
|
||||||
IL2CPP_TYPE_PINNED = 0x45, /* Local var that points to pinned object */
|
|
||||||
|
|
||||||
IL2CPP_TYPE_ENUM = 0x55, /* an enumeration */
|
|
||||||
IL2CPP_TYPE_IL2CPP_TYPE_INDEX = 0xff /* Type index metadata table */
|
|
||||||
}
|
|
||||||
|
|
||||||
// From metadata.h / il2cpp-runtime-metadata.h
|
|
||||||
public class Il2CppType
|
|
||||||
{
|
|
||||||
public ulong datapoint;
|
|
||||||
public ulong bits; // this should be private but we need it to be public for BinaryObjectReader to work
|
|
||||||
//public Union data { get; set; }
|
|
||||||
|
|
||||||
public virtual uint attrs => (uint) bits & 0xffff;
|
|
||||||
public virtual Il2CppTypeEnum type => (Il2CppTypeEnum)((bits >> 16) & 0xff);
|
|
||||||
|
|
||||||
public virtual uint num_mods => (uint) (bits >> 24) & 0x3f;
|
|
||||||
public virtual bool byref => ((bits >> 30) & 1) == 1;
|
|
||||||
public virtual bool pinned => ((bits >> 31) & 1) == 1;
|
|
||||||
public virtual bool valuetype => false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
union
|
|
||||||
{
|
|
||||||
TypeDefinitionIndex klassIndex; // for VALUETYPE and CLASS (<v27; v27: at startup)
|
|
||||||
Il2CppMetadataTypeHandle typeHandle; // for VALUETYPE and CLASS (added in v27: at runtime)
|
|
||||||
const Il2CppType* type; // for PTR and SZARRAY
|
|
||||||
Il2CppArrayType* array; // for ARRAY
|
|
||||||
GenericParameterIndex genericParameterIndex; // for VAR and MVAR (<v27; v27: at startup)
|
|
||||||
Il2CppMetadataGenericParameterHandle genericParameterHandle; // for VAR and MVAR (added in v27: at runtime)
|
|
||||||
Il2CppGenericClass* generic_class; // for GENERICINST
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unity 2021.1 (v27.2): num_mods becomes 1 bit shorter, shifting byref and pinned left 1 bit, valuetype bit added
|
|
||||||
public class Il2CppTypeV272 : Il2CppType
|
|
||||||
{
|
|
||||||
public override uint num_mods => (uint) (bits >> 24) & 0x1f;
|
|
||||||
public override bool byref => ((bits >> 29) & 1) == 1;
|
|
||||||
public override bool pinned => ((bits >> 30) & 1) == 1;
|
|
||||||
public override bool valuetype => ((bits >> 31) & 1) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppGenericClass
|
|
||||||
{
|
|
||||||
[Version(Max = 24.5)]
|
|
||||||
public long typeDefinitionIndex; /* the generic type definition */
|
|
||||||
[Version(Min = 27)]
|
|
||||||
public ulong type; // Il2CppType* /* the generic type definition */
|
|
||||||
|
|
||||||
public Il2CppGenericContext context; /* a context that contains the type instantiation doesn't contain any method instantiation */
|
|
||||||
public ulong cached_class; /* if present, the Il2CppClass corresponding to the instantiation. */
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppGenericContext
|
|
||||||
{
|
|
||||||
/* The instantiation corresponding to the class generic parameters */
|
|
||||||
public ulong class_inst;
|
|
||||||
/* The instantiation corresponding to the method generic parameters */
|
|
||||||
public ulong method_inst;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppGenericInst
|
|
||||||
{
|
|
||||||
public ulong type_argc;
|
|
||||||
public ulong type_argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppArrayType
|
|
||||||
{
|
|
||||||
public ulong etype;
|
|
||||||
public byte rank;
|
|
||||||
public byte numsizes;
|
|
||||||
public byte numlobounds;
|
|
||||||
public ulong sizes;
|
|
||||||
public ulong lobounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppMethodSpec
|
|
||||||
{
|
|
||||||
public int methodDefinitionIndex;
|
|
||||||
public int classIndexIndex;
|
|
||||||
public int methodIndexIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppGenericMethodFunctionsDefinitions
|
|
||||||
{
|
|
||||||
public int genericMethodIndex;
|
|
||||||
public Il2CppGenericMethodIndices indices;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppGenericMethodIndices
|
|
||||||
{
|
|
||||||
public int methodIndex;
|
|
||||||
public int invokerIndex;
|
|
||||||
[Version(Min = 24.5, Max = 24.5)]
|
|
||||||
[Version(Min = 27.1)]
|
|
||||||
public int adjustorThunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppTypeDefinitionSizes
|
|
||||||
{
|
|
||||||
public uint instanceSize;
|
|
||||||
public int nativeSize;
|
|
||||||
public uint staticFieldsSize;
|
|
||||||
public uint threadStaticFieldsSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,14 +4,19 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using Il2CppInspector.Utils;
|
using Il2CppInspector.Utils;
|
||||||
using NoisyCowStudios.Bin2Object;
|
using NoisyCowStudios.Bin2Object;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
@@ -31,42 +36,44 @@ namespace Il2CppInspector
|
|||||||
public List<MetadataUsage> MetadataUsages { get; }
|
public List<MetadataUsage> MetadataUsages { get; }
|
||||||
|
|
||||||
// Shortcuts
|
// Shortcuts
|
||||||
public double Version => Math.Max(Metadata.Version, Binary.Image.Version);
|
public StructVersion Version => Metadata.Version > Binary.Image.Version
|
||||||
|
? Metadata.Version
|
||||||
|
: Binary.Image.Version;
|
||||||
|
|
||||||
public Dictionary<int, string> Strings => Metadata.Strings;
|
public Dictionary<int, string> Strings => Metadata.Strings;
|
||||||
public string[] StringLiterals => Metadata.StringLiterals;
|
public string[] StringLiterals => Metadata.StringLiterals;
|
||||||
public Il2CppTypeDefinition[] TypeDefinitions => Metadata.Types;
|
public ImmutableArray<Il2CppTypeDefinition> TypeDefinitions => Metadata.Types;
|
||||||
public Il2CppAssemblyDefinition[] Assemblies => Metadata.Assemblies;
|
public ImmutableArray<Il2CppAssemblyDefinition> Assemblies => Metadata.Assemblies;
|
||||||
public Il2CppImageDefinition[] Images => Metadata.Images;
|
public ImmutableArray<Il2CppImageDefinition> Images => Metadata.Images;
|
||||||
public Il2CppMethodDefinition[] Methods => Metadata.Methods;
|
public ImmutableArray<Il2CppMethodDefinition> Methods => Metadata.Methods;
|
||||||
public Il2CppParameterDefinition[] Params => Metadata.Params;
|
public ImmutableArray<Il2CppParameterDefinition> Params => Metadata.Params;
|
||||||
public Il2CppFieldDefinition[] Fields => Metadata.Fields;
|
public ImmutableArray<Il2CppFieldDefinition> Fields => Metadata.Fields;
|
||||||
public Il2CppPropertyDefinition[] Properties => Metadata.Properties;
|
public ImmutableArray<Il2CppPropertyDefinition> Properties => Metadata.Properties;
|
||||||
public Il2CppEventDefinition[] Events => Metadata.Events;
|
public ImmutableArray<Il2CppEventDefinition> Events => Metadata.Events;
|
||||||
public Il2CppGenericContainer[] GenericContainers => Metadata.GenericContainers;
|
public ImmutableArray<Il2CppGenericContainer> GenericContainers => Metadata.GenericContainers;
|
||||||
public Il2CppGenericParameter[] GenericParameters => Metadata.GenericParameters;
|
public ImmutableArray<Il2CppGenericParameter> GenericParameters => Metadata.GenericParameters;
|
||||||
public int[] GenericConstraintIndices => Metadata.GenericConstraintIndices;
|
public ImmutableArray<int> GenericConstraintIndices => Metadata.GenericConstraintIndices;
|
||||||
public Il2CppCustomAttributeTypeRange[] AttributeTypeRanges => Metadata.AttributeTypeRanges;
|
public ImmutableArray<Il2CppCustomAttributeTypeRange> AttributeTypeRanges => Metadata.AttributeTypeRanges;
|
||||||
public Il2CppCustomAttributeDataRange[] AttributeDataRanges => Metadata.AttributeDataRanges;
|
public ImmutableArray<Il2CppCustomAttributeDataRange> AttributeDataRanges => Metadata.AttributeDataRanges;
|
||||||
public Il2CppInterfaceOffsetPair[] InterfaceOffsets => Metadata.InterfaceOffsets;
|
public ImmutableArray<Il2CppInterfaceOffsetPair> InterfaceOffsets => Metadata.InterfaceOffsets;
|
||||||
public int[] InterfaceUsageIndices => Metadata.InterfaceUsageIndices;
|
public ImmutableArray<int> InterfaceUsageIndices => Metadata.InterfaceUsageIndices;
|
||||||
public int[] NestedTypeIndices => Metadata.NestedTypeIndices;
|
public ImmutableArray<int> NestedTypeIndices => Metadata.NestedTypeIndices;
|
||||||
public int[] AttributeTypeIndices => Metadata.AttributeTypeIndices;
|
public ImmutableArray<int> AttributeTypeIndices => Metadata.AttributeTypeIndices;
|
||||||
public uint[] VTableMethodIndices => Metadata.VTableMethodIndices;
|
public ImmutableArray<uint> VTableMethodIndices => Metadata.VTableMethodIndices;
|
||||||
public Il2CppFieldRef[] FieldRefs => Metadata.FieldRefs;
|
public ImmutableArray<Il2CppFieldRef> FieldRefs => Metadata.FieldRefs;
|
||||||
public Dictionary<int, (ulong, object)> FieldDefaultValue { get; } = new Dictionary<int, (ulong, object)>();
|
public Dictionary<int, (ulong, object)> FieldDefaultValue { get; } = new Dictionary<int, (ulong, object)>();
|
||||||
public Dictionary<int, (ulong, object)> ParameterDefaultValue { get; } = new Dictionary<int, (ulong, object)>();
|
public Dictionary<int, (ulong, object)> ParameterDefaultValue { get; } = new Dictionary<int, (ulong, object)>();
|
||||||
public List<long> FieldOffsets { get; }
|
public List<long> FieldOffsets { get; }
|
||||||
public List<Il2CppType> TypeReferences => Binary.TypeReferences;
|
public ImmutableArray<Il2CppType> TypeReferences => Binary.TypeReferences;
|
||||||
public Dictionary<ulong, int> TypeReferenceIndicesByAddress => Binary.TypeReferenceIndicesByAddress;
|
public Dictionary<ulong, int> TypeReferenceIndicesByAddress => Binary.TypeReferenceIndicesByAddress;
|
||||||
public List<Il2CppGenericInst> GenericInstances => Binary.GenericInstances;
|
public ImmutableArray<Il2CppGenericInst> GenericInstances => Binary.GenericInstances;
|
||||||
public Dictionary<string, Il2CppCodeGenModule> Modules => Binary.Modules;
|
public Dictionary<string, Il2CppCodeGenModule> Modules => Binary.Modules;
|
||||||
public ulong[] CustomAttributeGenerators { get; }
|
public ulong[] CustomAttributeGenerators { get; }
|
||||||
public ulong[] MethodInvokePointers { get; }
|
public ulong[] MethodInvokePointers { get; }
|
||||||
public Il2CppMethodSpec[] MethodSpecs => Binary.MethodSpecs;
|
public ImmutableArray<Il2CppMethodSpec> MethodSpecs => Binary.MethodSpecs;
|
||||||
public Dictionary<Il2CppMethodSpec, ulong> GenericMethodPointers { get; }
|
public Dictionary<Il2CppMethodSpec, ulong> GenericMethodPointers { get; }
|
||||||
public Dictionary<Il2CppMethodSpec, int> GenericMethodInvokerIndices => Binary.GenericMethodInvokerIndices;
|
public Dictionary<Il2CppMethodSpec, int> GenericMethodInvokerIndices => Binary.GenericMethodInvokerIndices;
|
||||||
public List<Il2CppTypeDefinitionSizes> TypeDefinitionSizes => Binary.TypeDefinitionSizes;
|
public ImmutableArray<Il2CppTypeDefinitionSizes> TypeDefinitionSizes => Binary.TypeDefinitionSizes;
|
||||||
|
|
||||||
// TODO: Finish all file access in the constructor and eliminate the need for this
|
// TODO: Finish all file access in the constructor and eliminate the need for this
|
||||||
public IFileFormatStream BinaryImage => Binary.Image;
|
public IFileFormatStream BinaryImage => Binary.Image;
|
||||||
@@ -77,7 +84,7 @@ namespace Il2CppInspector
|
|||||||
return (0ul, null);
|
return (0ul, null);
|
||||||
|
|
||||||
// Get pointer in binary to default value
|
// Get pointer in binary to default value
|
||||||
var pValue = Metadata.Header.fieldAndParameterDefaultValueDataOffset + dataIndex;
|
var pValue = Metadata.Header.FieldAndParameterDefaultValueDataOffset + dataIndex;
|
||||||
var typeRef = TypeReferences[typeIndex];
|
var typeRef = TypeReferences[typeIndex];
|
||||||
|
|
||||||
// Default value is null
|
// Default value is null
|
||||||
@@ -85,7 +92,7 @@ namespace Il2CppInspector
|
|||||||
return (0ul, null);
|
return (0ul, null);
|
||||||
|
|
||||||
Metadata.Position = pValue;
|
Metadata.Position = pValue;
|
||||||
var value = BlobReader.GetConstantValueFromBlob(this, typeRef.type, Metadata);
|
var value = BlobReader.GetConstantValueFromBlob(this, typeRef.Type, Metadata);
|
||||||
|
|
||||||
return ((ulong) pValue, value);
|
return ((ulong) pValue, value);
|
||||||
}
|
}
|
||||||
@@ -93,21 +100,21 @@ namespace Il2CppInspector
|
|||||||
private List<MetadataUsage> buildMetadataUsages()
|
private List<MetadataUsage> buildMetadataUsages()
|
||||||
{
|
{
|
||||||
// No metadata usages for versions < 19
|
// No metadata usages for versions < 19
|
||||||
if (Version < 19)
|
if (Version < MetadataVersions.V190)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Metadata usages are lazily initialized during runtime for versions >= 27
|
// Metadata usages are lazily initialized during runtime for versions >= 27
|
||||||
if (Version >= 27)
|
if (Version >= MetadataVersions.V270)
|
||||||
return buildLateBindingMetadataUsages();
|
return buildLateBindingMetadataUsages();
|
||||||
|
|
||||||
// Version >= 19 && < 27
|
// Version >= 19 && < 27
|
||||||
var usages = new Dictionary<uint, MetadataUsage>();
|
var usages = new Dictionary<uint, uint>();
|
||||||
foreach (var metadataUsageList in Metadata.MetadataUsageLists)
|
foreach (var metadataUsageList in Metadata.MetadataUsageLists)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < metadataUsageList.count; i++)
|
for (var i = 0; i < metadataUsageList.Count; i++)
|
||||||
{
|
{
|
||||||
var metadataUsagePair = Metadata.MetadataUsagePairs[metadataUsageList.start + i];
|
var metadataUsagePair = Metadata.MetadataUsagePairs[metadataUsageList.Start + i];
|
||||||
usages.TryAdd(metadataUsagePair.destinationindex, MetadataUsage.FromEncodedIndex(this, metadataUsagePair.encodedSourceIndex));
|
usages.TryAdd(metadataUsagePair.DestinationIndex, metadataUsagePair.EncodedSourceIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,11 +122,13 @@ namespace Il2CppInspector
|
|||||||
// Unfortunately the value supplied in MetadataRegistration.matadataUsagesCount seems to be incorrect,
|
// Unfortunately the value supplied in MetadataRegistration.matadataUsagesCount seems to be incorrect,
|
||||||
// so we have to calculate the correct number of usages above before reading the usage address list from the binary
|
// so we have to calculate the correct number of usages above before reading the usage address list from the binary
|
||||||
var count = usages.Keys.Max() + 1;
|
var count = usages.Keys.Max() + 1;
|
||||||
var addresses = Binary.Image.ReadMappedArray<ulong>(Binary.MetadataRegistration.metadataUsages, (int) count);
|
var addresses = Binary.Image.ReadMappedUWordArray(Binary.MetadataRegistration.MetadataUsages, (int) count);
|
||||||
foreach (var usage in usages)
|
|
||||||
usage.Value.SetAddress(addresses[usage.Key]);
|
|
||||||
|
|
||||||
return usages.Values.ToList();
|
var metadataUsages = new List<MetadataUsage>();
|
||||||
|
foreach (var (index, encodedUsage) in usages)
|
||||||
|
metadataUsages.Add(MetadataUsage.FromEncodedIndex(this, encodedUsage, addresses[index]));
|
||||||
|
|
||||||
|
return metadataUsages;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MetadataUsage> buildLateBindingMetadataUsages()
|
private List<MetadataUsage> buildLateBindingMetadataUsages()
|
||||||
@@ -142,10 +151,7 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
if (CheckMetadataUsageSanity(usage)
|
if (CheckMetadataUsageSanity(usage)
|
||||||
&& BinaryImage.TryMapFileOffsetToVA(i * ((uint)BinaryImage.Bits / 8), out var va))
|
&& BinaryImage.TryMapFileOffsetToVA(i * ((uint)BinaryImage.Bits / 8), out var va))
|
||||||
{
|
usages.Add(MetadataUsage.FromEncodedIndex(this, encodedToken, va));
|
||||||
usage.SetAddress(va);
|
|
||||||
usages.Add(usage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +161,7 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
return usage.Type switch
|
return usage.Type switch
|
||||||
{
|
{
|
||||||
MetadataUsageType.TypeInfo or MetadataUsageType.Type => TypeReferences.Count > usage.SourceIndex,
|
MetadataUsageType.TypeInfo or MetadataUsageType.Type => TypeReferences.Length > usage.SourceIndex,
|
||||||
MetadataUsageType.MethodDef => Methods.Length > usage.SourceIndex,
|
MetadataUsageType.MethodDef => Methods.Length > usage.SourceIndex,
|
||||||
MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => FieldRefs.Length > usage.SourceIndex,
|
MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => FieldRefs.Length > usage.SourceIndex,
|
||||||
MetadataUsageType.StringLiteral => StringLiterals.Length > usage.SourceIndex,
|
MetadataUsageType.StringLiteral => StringLiterals.Length > usage.SourceIndex,
|
||||||
@@ -180,11 +186,11 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// Get all field default values
|
// Get all field default values
|
||||||
foreach (var fdv in Metadata.FieldDefaultValues)
|
foreach (var fdv in Metadata.FieldDefaultValues)
|
||||||
FieldDefaultValue.Add(fdv.fieldIndex, ((ulong,object)) getDefaultValue(fdv.typeIndex, fdv.dataIndex));
|
FieldDefaultValue.Add(fdv.FieldIndex, ((ulong,object)) getDefaultValue(fdv.TypeIndex, fdv.DataIndex));
|
||||||
|
|
||||||
// Get all parameter default values
|
// Get all parameter default values
|
||||||
foreach (var pdv in Metadata.ParameterDefaultValues)
|
foreach (var pdv in Metadata.ParameterDefaultValues)
|
||||||
ParameterDefaultValue.Add(pdv.parameterIndex, ((ulong,object)) getDefaultValue(pdv.typeIndex, pdv.dataIndex));
|
ParameterDefaultValue.Add(pdv.ParameterIndex, ((ulong,object)) getDefaultValue(pdv.TypeIndex, pdv.DataIndex));
|
||||||
|
|
||||||
// Get all field offsets
|
// Get all field offsets
|
||||||
if (Binary.FieldOffsets != null) {
|
if (Binary.FieldOffsets != null) {
|
||||||
@@ -197,19 +203,21 @@ namespace Il2CppInspector
|
|||||||
for (var i = 0; i < TypeDefinitions.Length; i++) {
|
for (var i = 0; i < TypeDefinitions.Length; i++) {
|
||||||
var def = TypeDefinitions[i];
|
var def = TypeDefinitions[i];
|
||||||
var pFieldOffsets = Binary.FieldOffsetPointers[i];
|
var pFieldOffsets = Binary.FieldOffsetPointers[i];
|
||||||
if (pFieldOffsets != 0) {
|
if (pFieldOffsets != 0)
|
||||||
bool available = true;
|
{
|
||||||
|
|
||||||
// If the target address range is not mapped in the file, assume zeroes
|
// If the target address range is not mapped in the file, assume zeroes
|
||||||
try {
|
if (BinaryImage.TryMapVATR((ulong)pFieldOffsets, out var fieldOffsetPosition))
|
||||||
BinaryImage.Position = BinaryImage.MapVATR((ulong) pFieldOffsets);
|
{
|
||||||
|
BinaryImage.Position = fieldOffsetPosition;
|
||||||
|
var fieldOffsets = BinaryImage.ReadArray<uint>(def.FieldCount);
|
||||||
|
for (var fieldIndex = 0; fieldIndex < def.FieldCount; fieldIndex++)
|
||||||
|
offsets.Add(def.FieldIndex + fieldIndex, fieldOffsets[fieldIndex]);
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException) {
|
else
|
||||||
available = false;
|
{
|
||||||
|
for (var fieldIndex = 0; fieldIndex < def.FieldCount; fieldIndex++)
|
||||||
|
offsets.Add(def.FieldIndex + fieldIndex, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var f = 0; f < def.field_count; f++)
|
|
||||||
offsets.Add(def.fieldStart + f, available? BinaryImage.ReadUInt32() : 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,20 +225,20 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build list of custom attribute generators
|
// Build list of custom attribute generators
|
||||||
if (Version < 27)
|
if (Version < MetadataVersions.V270)
|
||||||
CustomAttributeGenerators = Binary.CustomAttributeGenerators;
|
CustomAttributeGenerators = Binary.CustomAttributeGenerators;
|
||||||
else if (Version < 29)
|
else if (Version < MetadataVersions.V290)
|
||||||
{
|
{
|
||||||
var cagCount = Images.Sum(i => i.customAttributeCount);
|
var cagCount = Images.Sum(i => i.CustomAttributeCount);
|
||||||
CustomAttributeGenerators = new ulong[cagCount];
|
CustomAttributeGenerators = new ulong[cagCount];
|
||||||
|
|
||||||
foreach (var image in Images)
|
foreach (var image in Images)
|
||||||
{
|
{
|
||||||
// Get CodeGenModule for this image
|
// Get CodeGenModule for this image
|
||||||
var codeGenModule = Binary.Modules[Strings[image.nameIndex]];
|
var codeGenModule = Binary.Modules[Strings[image.NameIndex]];
|
||||||
var cags = BinaryImage.ReadMappedWordArray(codeGenModule.customAttributeCacheGenerator,
|
var cags = BinaryImage.ReadMappedWordArray(codeGenModule.CustomAttributeCacheGenerator,
|
||||||
(int) image.customAttributeCount);
|
(int) image.CustomAttributeCount);
|
||||||
cags.CopyTo(CustomAttributeGenerators, image.customAttributeStart);
|
cags.CopyTo(CustomAttributeGenerators, image.CustomAttributeStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -243,7 +251,7 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// Get sorted list of function pointers from all sources
|
// Get sorted list of function pointers from all sources
|
||||||
// TODO: This does not include IL2CPP API functions
|
// TODO: This does not include IL2CPP API functions
|
||||||
var sortedFunctionPointers = (Version <= 24.1)?
|
var sortedFunctionPointers = (Version <= MetadataVersions.V241) ?
|
||||||
Binary.GlobalMethodPointers.Select(getDecodedAddress).ToList() :
|
Binary.GlobalMethodPointers.Select(getDecodedAddress).ToList() :
|
||||||
Binary.ModuleMethodPointers.SelectMany(module => module.Value).Select(getDecodedAddress).ToList();
|
Binary.ModuleMethodPointers.SelectMany(module => module.Value).Select(getDecodedAddress).ToList();
|
||||||
|
|
||||||
@@ -261,20 +269,20 @@ namespace Il2CppInspector
|
|||||||
FunctionAddresses.Add(sortedFunctionPointers[^1], sortedFunctionPointers[^1]);
|
FunctionAddresses.Add(sortedFunctionPointers[^1], sortedFunctionPointers[^1]);
|
||||||
|
|
||||||
// Organize custom attribute indices
|
// Organize custom attribute indices
|
||||||
if (Version >= 24.1) {
|
if (Version >= MetadataVersions.V241) {
|
||||||
AttributeIndicesByToken = [];
|
AttributeIndicesByToken = [];
|
||||||
foreach (var image in Images)
|
foreach (var image in Images)
|
||||||
{
|
{
|
||||||
var attsByToken = new Dictionary<uint, int>();
|
var attsByToken = new Dictionary<uint, int>();
|
||||||
for (int i = 0; i < image.customAttributeCount; i++)
|
for (int i = 0; i < image.CustomAttributeCount; i++)
|
||||||
{
|
{
|
||||||
var index = image.customAttributeStart + i;
|
var index = image.CustomAttributeStart + i;
|
||||||
var token = Version >= 29 ? AttributeDataRanges[index].token : AttributeTypeRanges[index].token;
|
var token = Version >= MetadataVersions.V290 ? AttributeDataRanges[index].Token : AttributeTypeRanges[index].Token;
|
||||||
attsByToken.Add(token, index);
|
attsByToken.Add(token, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attsByToken.Count > 0)
|
if (attsByToken.Count > 0)
|
||||||
AttributeIndicesByToken.Add(image.customAttributeStart, attsByToken);
|
AttributeIndicesByToken.Add(image.CustomAttributeStart, attsByToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,20 +296,20 @@ namespace Il2CppInspector
|
|||||||
// Get a method pointer if available
|
// Get a method pointer if available
|
||||||
public (ulong Start, ulong End)? GetMethodPointer(Il2CppCodeGenModule module, Il2CppMethodDefinition methodDef) {
|
public (ulong Start, ulong End)? GetMethodPointer(Il2CppCodeGenModule module, Il2CppMethodDefinition methodDef) {
|
||||||
// Find method pointer
|
// Find method pointer
|
||||||
if (methodDef.methodIndex < 0)
|
if (methodDef.MethodIndex < 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
ulong start = 0;
|
ulong start = 0;
|
||||||
|
|
||||||
// Global method pointer array
|
// Global method pointer array
|
||||||
if (Version <= 24.1) {
|
if (Version <= MetadataVersions.V241) {
|
||||||
start = Binary.GlobalMethodPointers[methodDef.methodIndex];
|
start = Binary.GlobalMethodPointers[methodDef.MethodIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per-module method pointer array uses the bottom 24 bits of the method's metadata token
|
// Per-module method pointer array uses the bottom 24 bits of the method's metadata token
|
||||||
// Derived from il2cpp::vm::MetadataCache::GetMethodPointer
|
// Derived from il2cpp::vm::MetadataCache::GetMethodPointer
|
||||||
if (Version >= 24.2) {
|
if (Version >= MetadataVersions.V242) {
|
||||||
var method = (methodDef.token & 0xffffff);
|
var method = (methodDef.Token & 0xffffff);
|
||||||
if (method == 0)
|
if (method == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -335,19 +343,19 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// Get a method invoker index from a method definition
|
// Get a method invoker index from a method definition
|
||||||
public int GetInvokerIndex(Il2CppCodeGenModule module, Il2CppMethodDefinition methodDef) {
|
public int GetInvokerIndex(Il2CppCodeGenModule module, Il2CppMethodDefinition methodDef) {
|
||||||
if (Version <= 24.1) {
|
if (Version <= MetadataVersions.V241) {
|
||||||
return methodDef.invokerIndex;
|
return methodDef.InvokerIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version >= 24.2
|
// Version >= 24.2
|
||||||
var methodInModule = (methodDef.token & 0xffffff);
|
var methodInModule = (methodDef.Token & 0xffffff);
|
||||||
return Binary.MethodInvokerIndices[module][methodInModule - 1];
|
return Binary.MethodInvokerIndices[module][(int)methodInModule - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataUsage[] GetVTable(Il2CppTypeDefinition definition) {
|
public MetadataUsage[] GetVTable(Il2CppTypeDefinition definition) {
|
||||||
MetadataUsage[] res = new MetadataUsage[definition.vtable_count];
|
MetadataUsage[] res = new MetadataUsage[definition.VTableCount];
|
||||||
for (int i = 0; i < definition.vtable_count; i++) {
|
for (int i = 0; i < definition.VTableCount; i++) {
|
||||||
var encodedIndex = VTableMethodIndices[definition.vtableStart + i];
|
var encodedIndex = VTableMethodIndices[definition.VTableIndex + i];
|
||||||
MetadataUsage usage = MetadataUsage.FromEncodedIndex(this, encodedIndex);
|
MetadataUsage usage = MetadataUsage.FromEncodedIndex(this, encodedIndex);
|
||||||
if (usage.SourceIndex != 0)
|
if (usage.SourceIndex != 0)
|
||||||
res[i] = usage;
|
res[i] = usage;
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ using System.Buffers;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
|
using Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
@@ -120,7 +123,7 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// Find CodeRegistration
|
// Find CodeRegistration
|
||||||
// >= 24.2
|
// >= 24.2
|
||||||
if (metadata.Version >= 24.2) {
|
if (metadata.Version >= MetadataVersions.V242) {
|
||||||
|
|
||||||
// < 27: mscorlib.dll is always the first CodeGenModule
|
// < 27: mscorlib.dll is always the first CodeGenModule
|
||||||
// >= 27: mscorlib.dll is always the last CodeGenModule (Assembly-CSharp.dll is always the first but non-Unity builds don't have this DLL)
|
// >= 27: mscorlib.dll is always the last CodeGenModule (Assembly-CSharp.dll is always the first but non-Unity builds don't have this DLL)
|
||||||
@@ -137,7 +140,7 @@ namespace Il2CppInspector
|
|||||||
// Unwind from string pointer -> CodeGenModule -> CodeGenModules + x
|
// Unwind from string pointer -> CodeGenModule -> CodeGenModules + x
|
||||||
foreach (var potentialCodeGenModules in FindAllPointerChains(imageBytes, va, 2))
|
foreach (var potentialCodeGenModules in FindAllPointerChains(imageBytes, va, 2))
|
||||||
{
|
{
|
||||||
if (metadata.Version >= 27)
|
if (metadata.Version >= MetadataVersions.V270)
|
||||||
{
|
{
|
||||||
for (int i = imagesCount - 1; i >= 0; i--)
|
for (int i = imagesCount - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
@@ -145,7 +148,7 @@ namespace Il2CppInspector
|
|||||||
potentialCodeGenModules - (ulong) i * ptrSize, 1))
|
potentialCodeGenModules - (ulong) i * ptrSize, 1))
|
||||||
{
|
{
|
||||||
var expectedImageCountPtr = potentialCodeRegistrationPtr - ptrSize;
|
var expectedImageCountPtr = potentialCodeRegistrationPtr - ptrSize;
|
||||||
var expectedImageCount = ptrSize == 4 ? Image.ReadMappedInt32(expectedImageCountPtr) : Image.ReadMappedInt64(expectedImageCountPtr);
|
var expectedImageCount = Image.ReadMappedWord(expectedImageCountPtr);
|
||||||
if (expectedImageCount == imagesCount)
|
if (expectedImageCount == imagesCount)
|
||||||
return potentialCodeRegistrationPtr;
|
return potentialCodeRegistrationPtr;
|
||||||
}
|
}
|
||||||
@@ -203,24 +206,42 @@ namespace Il2CppInspector
|
|||||||
return (0, 0);
|
return (0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
var codeGenEndPtr = codeRegVa + ptrSize;
|
||||||
// pCodeGenModules is the last field in CodeRegistration so we subtract the size of one pointer from the struct size
|
// pCodeGenModules is the last field in CodeRegistration so we subtract the size of one pointer from the struct size
|
||||||
codeRegistration = codeRegVa - ((ulong) metadata.Sizeof(typeof(Il2CppCodeRegistration), Image.Version, Image.Bits / 8) - ptrSize);
|
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
|
||||||
|
|
||||||
// In v24.3, windowsRuntimeFactoryTable collides with codeGenModules. So far no samples have had windowsRuntimeFactoryCount > 0;
|
// In v24.3, windowsRuntimeFactoryTable collides with codeGenModules. So far no samples have had windowsRuntimeFactoryCount > 0;
|
||||||
// if this changes we'll have to get smarter about disambiguating these two.
|
// if this changes we'll have to get smarter about disambiguating these two.
|
||||||
var cr = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
var cr = Image.ReadMappedVersionedObject<Il2CppCodeRegistration>(codeRegistration);
|
||||||
|
|
||||||
if (Image.Version == 24.2 && cr.interopDataCount == 0) {
|
if (Image.Version == MetadataVersions.V242 && cr.InteropDataCount == 0) {
|
||||||
Image.Version = 24.3;
|
Image.Version = MetadataVersions.V243;
|
||||||
codeRegistration -= ptrSize * 2; // two extra words for WindowsRuntimeFactory
|
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Image.Version == 27 && cr.reversePInvokeWrapperCount > 0x30000)
|
if (Image.Version == MetadataVersions.V270 && cr.ReversePInvokeWrapperCount > 0x30000)
|
||||||
{
|
{
|
||||||
// If reversePInvokeWrapperCount is a pointer, then it's because we're actually on 27.1 and there's a genericAdjustorThunks pointer interfering.
|
// If reversePInvokeWrapperCount is a pointer, then it's because we're actually on 27.1 and there's a genericAdjustorThunks pointer interfering.
|
||||||
// We need to bump version to 27.1 and back up one more pointer.
|
// We need to bump version to 27.1 and back up one more pointer.
|
||||||
Image.Version = 27.1;
|
Image.Version = MetadataVersions.V271;
|
||||||
codeRegistration -= ptrSize;
|
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
|
||||||
|
cr = Image.ReadMappedVersionedObject<Il2CppCodeRegistration>(codeRegistration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// genericAdjustorThunks was inserted before invokerPointersCount in 24.5 and 27.1
|
||||||
|
// pointer expected if we need to bump version
|
||||||
|
if (Image.Version == MetadataVersions.V244 && cr.InvokerPointersCount > 0x50000)
|
||||||
|
{
|
||||||
|
Image.Version = MetadataVersions.V245;
|
||||||
|
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
|
||||||
|
cr = Image.ReadMappedVersionedObject<Il2CppCodeRegistration>(codeRegistration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Image.Version == MetadataVersions.V290 || Image.Version == MetadataVersions.V310) &&
|
||||||
|
cr.GenericMethodPointersCount >= cr.GenericMethodPointers)
|
||||||
|
{
|
||||||
|
Image.Version = new StructVersion(Image.Version.Major, 0, MetadataVersions.Tag2022);
|
||||||
|
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,18 +249,15 @@ namespace Il2CppInspector
|
|||||||
// <= 24.1
|
// <= 24.1
|
||||||
else {
|
else {
|
||||||
// The first item in CodeRegistration is the total number of method pointers
|
// The first item in CodeRegistration is the total number of method pointers
|
||||||
vas = FindAllMappedWords(imageBytes, (ulong) metadata.Methods.Count(m => (uint) m.methodIndex != 0xffff_ffff));
|
vas = FindAllMappedWords(imageBytes, (ulong) metadata.Methods.Count(m => (uint) m.MethodIndex != 0xffff_ffff));
|
||||||
|
|
||||||
if (!vas.Any())
|
|
||||||
return (0, 0);
|
|
||||||
|
|
||||||
// The count of method pointers will be followed some bytes later by
|
// The count of method pointers will be followed some bytes later by
|
||||||
// the count of custom attribute generators; the distance between them
|
// the count of custom attribute generators; the distance between them
|
||||||
// depends on the il2cpp version so we just use ReadMappedObject to simplify the math
|
// depends on the il2cpp version so we just use ReadMappedObject to simplify the math
|
||||||
foreach (var va in vas) {
|
foreach (var va in vas) {
|
||||||
var cr = Image.ReadMappedObject<Il2CppCodeRegistration>(va);
|
var cr = Image.ReadMappedVersionedObject<Il2CppCodeRegistration>(va);
|
||||||
|
|
||||||
if (cr.customAttributeCount == metadata.AttributeTypeRanges.Length)
|
if (cr.CustomAttributeCount == metadata.AttributeTypeRanges.Length)
|
||||||
codeRegistration = va;
|
codeRegistration = va;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,16 +271,17 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// Find TypeDefinitionsSizesCount (4th last field) then work back to the start of the struct
|
// Find TypeDefinitionsSizesCount (4th last field) then work back to the start of the struct
|
||||||
// This saves us from guessing where metadataUsagesCount is later
|
// This saves us from guessing where metadataUsagesCount is later
|
||||||
var mrSize = (ulong) metadata.Sizeof(typeof(Il2CppMetadataRegistration), Image.Version, Image.Bits / 8);
|
var mrSize = (ulong)Il2CppMetadataRegistration.Size(Image.Version, Image.Bits == 32);
|
||||||
var typesLength = (ulong) metadata.Types.Length;
|
var typesLength = (ulong) metadata.Types.Length;
|
||||||
|
|
||||||
vas = FindAllMappedWords(imageBytes, typesLength).Select(a => a - mrSize + ptrSize * 4);
|
vas = FindAllMappedWords(imageBytes, typesLength).Select(a => a - mrSize + ptrSize * 4);
|
||||||
|
|
||||||
// >= 19 && < 27
|
// >= 19 && < 27
|
||||||
if (Image.Version < 27)
|
if (Image.Version < MetadataVersions.V270)
|
||||||
foreach (var va in vas) {
|
foreach (var va in vas)
|
||||||
var mr = Image.ReadMappedObject<Il2CppMetadataRegistration>(va);
|
{
|
||||||
if (mr.metadataUsagesCount == (ulong) metadata.MetadataUsageLists.Length)
|
var mr = Image.ReadMappedVersionedObject<Il2CppMetadataRegistration>(va);
|
||||||
|
if (mr.MetadataUsagesCount == (ulong) metadata.MetadataUsageLists.Length)
|
||||||
metadataRegistration = va;
|
metadataRegistration = va;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,22 +290,17 @@ namespace Il2CppInspector
|
|||||||
// Synonyms: copying, piracy, theft, strealing, infringement of copyright
|
// Synonyms: copying, piracy, theft, strealing, infringement of copyright
|
||||||
|
|
||||||
// >= 27
|
// >= 27
|
||||||
else {
|
else
|
||||||
// We're going to just sanity check all of the fields
|
{
|
||||||
// All counts should be under a certain threshold
|
foreach (var va in vas)
|
||||||
// All pointers should be mappable to the binary
|
{
|
||||||
|
var mr = Image.ReadMappedVersionedObject<Il2CppMetadataRegistration>(va);
|
||||||
var mrFieldCount = mrSize / (ulong) (Image.Bits / 8);
|
if (mr.TypeDefinitionsSizesCount == metadata.Types.Length
|
||||||
foreach (var va in vas) {
|
&& mr.FieldOffsetsCount == metadata.Types.Length)
|
||||||
var mrWords = Image.ReadMappedWordArray(va, (int) mrFieldCount);
|
{
|
||||||
|
|
||||||
// Even field indices are counts, odd field indices are pointers
|
|
||||||
bool ok = true;
|
|
||||||
for (var i = 0; i < mrWords.Length && ok; i++) {
|
|
||||||
ok = i % 2 == 0 || Image.TryMapVATR((ulong) mrWords[i], out _);
|
|
||||||
}
|
|
||||||
if (ok)
|
|
||||||
metadataRegistration = va;
|
metadataRegistration = va;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (metadataRegistration == 0)
|
if (metadataRegistration == 0)
|
||||||
|
|||||||
@@ -7,41 +7,45 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
using NoisyCowStudios.Bin2Object;
|
using NoisyCowStudios.Bin2Object;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
public class Metadata : BinaryObjectStream
|
public class Metadata : BinaryObjectStreamReader
|
||||||
{
|
{
|
||||||
public Il2CppGlobalMetadataHeader Header { get; set; }
|
public Il2CppGlobalMetadataHeader Header { get; set; }
|
||||||
|
|
||||||
public Il2CppAssemblyDefinition[] Assemblies { get; set; }
|
public ImmutableArray<Il2CppAssemblyDefinition> Assemblies { get; set; }
|
||||||
public Il2CppImageDefinition[] Images { get; set; }
|
public ImmutableArray<Il2CppImageDefinition> Images { get; set; }
|
||||||
public Il2CppTypeDefinition[] Types { get; set; }
|
public ImmutableArray<Il2CppTypeDefinition> Types { get; set; }
|
||||||
public Il2CppMethodDefinition[] Methods { get; set; }
|
public ImmutableArray<Il2CppMethodDefinition> Methods { get; set; }
|
||||||
public Il2CppParameterDefinition[] Params { get; set; }
|
public ImmutableArray<Il2CppParameterDefinition> Params { get; set; }
|
||||||
public Il2CppFieldDefinition[] Fields { get; set; }
|
public ImmutableArray<Il2CppFieldDefinition> Fields { get; set; }
|
||||||
public Il2CppFieldDefaultValue[] FieldDefaultValues { get; set; }
|
public ImmutableArray<Il2CppFieldDefaultValue> FieldDefaultValues { get; set; }
|
||||||
public Il2CppParameterDefaultValue[] ParameterDefaultValues { get; set; }
|
public ImmutableArray<Il2CppParameterDefaultValue> ParameterDefaultValues { get; set; }
|
||||||
public Il2CppPropertyDefinition[] Properties { get; set; }
|
public ImmutableArray<Il2CppPropertyDefinition> Properties { get; set; }
|
||||||
public Il2CppEventDefinition[] Events { get; set; }
|
public ImmutableArray<Il2CppEventDefinition> Events { get; set; }
|
||||||
public Il2CppGenericContainer[] GenericContainers { get; set; }
|
public ImmutableArray<Il2CppGenericContainer> GenericContainers { get; set; }
|
||||||
public Il2CppGenericParameter[] GenericParameters { get; set; }
|
public ImmutableArray<Il2CppGenericParameter> GenericParameters { get; set; }
|
||||||
public Il2CppCustomAttributeTypeRange[] AttributeTypeRanges { get; set; }
|
public ImmutableArray<Il2CppCustomAttributeTypeRange> AttributeTypeRanges { get; set; }
|
||||||
public Il2CppCustomAttributeDataRange[] AttributeDataRanges { get; set; }
|
public ImmutableArray<Il2CppCustomAttributeDataRange> AttributeDataRanges { get; set; }
|
||||||
public Il2CppInterfaceOffsetPair[] InterfaceOffsets { get; set; }
|
public ImmutableArray<Il2CppInterfaceOffsetPair> InterfaceOffsets { get; set; }
|
||||||
public Il2CppMetadataUsageList[] MetadataUsageLists { get; set; }
|
public ImmutableArray<Il2CppMetadataUsageList> MetadataUsageLists { get; set; }
|
||||||
public Il2CppMetadataUsagePair[] MetadataUsagePairs { get; set; }
|
public ImmutableArray<Il2CppMetadataUsagePair> MetadataUsagePairs { get; set; }
|
||||||
public Il2CppFieldRef[] FieldRefs { get; set; }
|
public ImmutableArray<Il2CppFieldRef> FieldRefs { get; set; }
|
||||||
|
|
||||||
public int[] InterfaceUsageIndices { get; set; }
|
public ImmutableArray<int> InterfaceUsageIndices { get; set; }
|
||||||
public int[] NestedTypeIndices { get; set; }
|
public ImmutableArray<int> NestedTypeIndices { get; set; }
|
||||||
public int[] AttributeTypeIndices { get; set; }
|
public ImmutableArray<int> AttributeTypeIndices { get; set; }
|
||||||
public int[] GenericConstraintIndices { get; set; }
|
public ImmutableArray<int> GenericConstraintIndices { get; set; }
|
||||||
public uint[] VTableMethodIndices { get; set; }
|
public ImmutableArray<uint> VTableMethodIndices { get; set; }
|
||||||
public string[] StringLiterals { get; set; }
|
public string[] StringLiterals { get; set; }
|
||||||
|
|
||||||
public Dictionary<int, string> Strings { get; private set; } = new Dictionary<int, string>();
|
public Dictionary<int, string> Strings { get; private set; } = new Dictionary<int, string>();
|
||||||
@@ -78,22 +82,22 @@ namespace Il2CppInspector
|
|||||||
StatusUpdate("Processing metadata");
|
StatusUpdate("Processing metadata");
|
||||||
|
|
||||||
// Read metadata header
|
// Read metadata header
|
||||||
Header = ReadObject<Il2CppGlobalMetadataHeader>(0);
|
Header = ReadVersionedObject<Il2CppGlobalMetadataHeader>(0);
|
||||||
|
|
||||||
// Check for correct magic bytes
|
// Check for correct magic bytes
|
||||||
if (Header.signature != Il2CppConstants.MetadataSignature) {
|
if (!Header.SanityValid) {
|
||||||
throw new InvalidOperationException("The supplied metadata file is not valid.");
|
throw new InvalidOperationException("The supplied metadata file is not valid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set object versioning for Bin2Object from metadata version
|
// Set object versioning for Bin2Object from metadata version
|
||||||
Version = Header.version;
|
Version = new StructVersion(Header.Version);
|
||||||
|
|
||||||
if (Version < 16 || Version > 31) {
|
if (Version < MetadataVersions.V160 || Version > MetadataVersions.V310) {
|
||||||
throw new InvalidOperationException($"The supplied metadata file is not of a supported version ({Header.version}).");
|
throw new InvalidOperationException($"The supplied metadata file is not of a supported version ({Header.Version}).");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewind and read metadata header with the correct version settings
|
// Rewind and read metadata header with the correct version settings
|
||||||
Header = ReadObject<Il2CppGlobalMetadataHeader>(0);
|
Header = ReadVersionedObject<Il2CppGlobalMetadataHeader>(0);
|
||||||
|
|
||||||
// Sanity checking
|
// Sanity checking
|
||||||
// Unity.IL2CPP.MetadataCacheWriter.WriteLibIl2CppMetadata always writes the metadata information in the same order it appears in the header,
|
// Unity.IL2CPP.MetadataCacheWriter.WriteLibIl2CppMetadata always writes the metadata information in the same order it appears in the header,
|
||||||
@@ -105,109 +109,90 @@ namespace Il2CppInspector
|
|||||||
// we can use this value to determine the actual header length and therefore narrow down the metadata version to 24.0/24.1 or 24.2.
|
// we can use this value to determine the actual header length and therefore narrow down the metadata version to 24.0/24.1 or 24.2.
|
||||||
|
|
||||||
if (!pluginResult.SkipValidation) {
|
if (!pluginResult.SkipValidation) {
|
||||||
var realHeaderLength = Header.stringLiteralOffset;
|
var realHeaderLength = Header.StringLiteralOffset;
|
||||||
|
|
||||||
if (realHeaderLength != Sizeof(typeof(Il2CppGlobalMetadataHeader))) {
|
if (realHeaderLength != Sizeof<Il2CppGlobalMetadataHeader>()) {
|
||||||
if (Version == 24.0) {
|
if (Version == MetadataVersions.V240) {
|
||||||
Version = 24.2;
|
Version = MetadataVersions.V242;
|
||||||
Header = ReadObject<Il2CppGlobalMetadataHeader>(0);
|
Header = ReadVersionedObject<Il2CppGlobalMetadataHeader>(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (realHeaderLength != Sizeof(typeof(Il2CppGlobalMetadataHeader))) {
|
if (realHeaderLength != Sizeof<Il2CppGlobalMetadataHeader>()) {
|
||||||
throw new InvalidOperationException("Could not verify the integrity of the metadata file or accurately identify the metadata sub-version");
|
throw new InvalidOperationException("Could not verify the integrity of the metadata file or accurately identify the metadata sub-version");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all the relevant metadata using offsets provided in the header
|
// Load all the relevant metadata using offsets provided in the header
|
||||||
if (Version >= 16)
|
if (Version >= MetadataVersions.V160)
|
||||||
Images = ReadArray<Il2CppImageDefinition>(Header.imagesOffset, Header.imagesCount / Sizeof(typeof(Il2CppImageDefinition)));
|
Images = ReadVersionedObjectArray<Il2CppImageDefinition>(Header.ImagesOffset, Header.ImagesSize / Sizeof<Il2CppImageDefinition>());
|
||||||
|
|
||||||
// As an additional sanity check, all images in the metadata should have Mono.Cecil.MetadataToken == 1
|
// As an additional sanity check, all images in the metadata should have Mono.Cecil.MetadataToken == 1
|
||||||
// In metadata v24.1, two extra fields were added which will cause the below test to fail.
|
// In metadata v24.1, two extra fields were added which will cause the below test to fail.
|
||||||
// In that case, we can then adjust the version number and reload
|
// In that case, we can then adjust the version number and reload
|
||||||
// Tokens were introduced in v19 - we don't bother testing earlier versions
|
// Tokens were introduced in v19 - we don't bother testing earlier versions
|
||||||
if (Version >= 19 && Images.Any(x => x.token != 1))
|
if (Version >= MetadataVersions.V190 && Images.Any(x => x.Token != 1))
|
||||||
if (Version == 24.0) {
|
if (Version == MetadataVersions.V240) {
|
||||||
Version = 24.1;
|
Version = MetadataVersions.V241;
|
||||||
|
|
||||||
// No need to re-read the header, it's the same for both sub-versions
|
// No need to re-read the header, it's the same for both sub-versions
|
||||||
Images = ReadArray<Il2CppImageDefinition>(Header.imagesOffset, Header.imagesCount / Sizeof(typeof(Il2CppImageDefinition)));
|
Images = ReadVersionedObjectArray<Il2CppImageDefinition>(Header.ImagesOffset, Header.ImagesSize / Sizeof<Il2CppImageDefinition>());
|
||||||
|
|
||||||
if (Images.Any(x => x.token != 1))
|
if (Images.Any(x => x.Token != 1))
|
||||||
throw new InvalidOperationException("Could not verify the integrity of the metadata file image list");
|
throw new InvalidOperationException("Could not verify the integrity of the metadata file image list");
|
||||||
}
|
}
|
||||||
|
|
||||||
Types = ReadArray<Il2CppTypeDefinition>(Header.typeDefinitionsOffset, Header.typeDefinitionsCount / Sizeof(typeof(Il2CppTypeDefinition)));
|
Types = ReadVersionedObjectArray<Il2CppTypeDefinition>(Header.TypeDefinitionsOffset, Header.TypeDefinitionsSize / Sizeof<Il2CppTypeDefinition>());
|
||||||
Methods = ReadArray<Il2CppMethodDefinition>(Header.methodsOffset, Header.methodsCount / Sizeof(typeof(Il2CppMethodDefinition)));
|
Methods = ReadVersionedObjectArray<Il2CppMethodDefinition>(Header.MethodsOffset, Header.MethodsSize / Sizeof<Il2CppMethodDefinition>());
|
||||||
Params = ReadArray<Il2CppParameterDefinition>(Header.parametersOffset, Header.parametersCount / Sizeof(typeof(Il2CppParameterDefinition)));
|
Params = ReadVersionedObjectArray<Il2CppParameterDefinition>(Header.ParametersOffset, Header.ParametersSize / Sizeof<Il2CppParameterDefinition>());
|
||||||
Fields = ReadArray<Il2CppFieldDefinition>(Header.fieldsOffset, Header.fieldsCount / Sizeof(typeof(Il2CppFieldDefinition)));
|
Fields = ReadVersionedObjectArray<Il2CppFieldDefinition>(Header.FieldsOffset, Header.FieldsSize / Sizeof<Il2CppFieldDefinition>());
|
||||||
FieldDefaultValues = ReadArray<Il2CppFieldDefaultValue>(Header.fieldDefaultValuesOffset, Header.fieldDefaultValuesCount / Sizeof(typeof(Il2CppFieldDefaultValue)));
|
FieldDefaultValues = ReadVersionedObjectArray<Il2CppFieldDefaultValue>(Header.FieldDefaultValuesOffset, Header.FieldDefaultValuesSize / Sizeof<Il2CppFieldDefaultValue>());
|
||||||
Properties = ReadArray<Il2CppPropertyDefinition>(Header.propertiesOffset, Header.propertiesCount / Sizeof(typeof(Il2CppPropertyDefinition)));
|
Properties = ReadVersionedObjectArray<Il2CppPropertyDefinition>(Header.PropertiesOffset, Header.PropertiesSize / Sizeof<Il2CppPropertyDefinition>());
|
||||||
Events = ReadArray<Il2CppEventDefinition>(Header.eventsOffset, Header.eventsCount / Sizeof(typeof(Il2CppEventDefinition)));
|
Events = ReadVersionedObjectArray<Il2CppEventDefinition>(Header.EventsOffset, Header.EventsSize / Sizeof<Il2CppEventDefinition>());
|
||||||
InterfaceUsageIndices = ReadArray<int>(Header.interfacesOffset, Header.interfacesCount / sizeof(int));
|
InterfaceUsageIndices = ReadPrimitiveArray<int>(Header.InterfacesOffset, Header.InterfacesSize / sizeof(int));
|
||||||
NestedTypeIndices = ReadArray<int>(Header.nestedTypesOffset, Header.nestedTypesCount / sizeof(int));
|
NestedTypeIndices = ReadPrimitiveArray<int>(Header.NestedTypesOffset, Header.NestedTypesSize / sizeof(int));
|
||||||
GenericContainers = ReadArray<Il2CppGenericContainer>(Header.genericContainersOffset, Header.genericContainersCount / Sizeof(typeof(Il2CppGenericContainer)));
|
GenericContainers = ReadVersionedObjectArray<Il2CppGenericContainer>(Header.GenericContainersOffset, Header.GenericContainersSize / Sizeof<Il2CppGenericContainer>());
|
||||||
GenericParameters = ReadArray<Il2CppGenericParameter>(Header.genericParametersOffset, Header.genericParametersCount / Sizeof(typeof(Il2CppGenericParameter)));
|
GenericParameters = ReadVersionedObjectArray<Il2CppGenericParameter>(Header.GenericParametersOffset, Header.GenericParametersSize / Sizeof<Il2CppGenericParameter>());
|
||||||
GenericConstraintIndices = ReadArray<int>(Header.genericParameterConstraintsOffset, Header.genericParameterConstraintsCount / sizeof(int));
|
GenericConstraintIndices = ReadPrimitiveArray<int>(Header.GenericParameterConstraintsOffset, Header.GenericParameterConstraintsSize / sizeof(int));
|
||||||
InterfaceOffsets = ReadArray<Il2CppInterfaceOffsetPair>(Header.interfaceOffsetsOffset, Header.interfaceOffsetsCount / Sizeof(typeof(Il2CppInterfaceOffsetPair)));
|
InterfaceOffsets = ReadVersionedObjectArray<Il2CppInterfaceOffsetPair>(Header.InterfaceOffsetsOffset, Header.InterfaceOffsetsSize / Sizeof<Il2CppInterfaceOffsetPair>());
|
||||||
VTableMethodIndices = ReadArray<uint>(Header.vtableMethodsOffset, Header.vtableMethodsCount / sizeof(uint));
|
VTableMethodIndices = ReadPrimitiveArray<uint>(Header.VTableMethodsOffset, Header.VTableMethodsSize / sizeof(uint));
|
||||||
|
|
||||||
if (Version >= 16) {
|
if (Version >= MetadataVersions.V160) {
|
||||||
// In v24.4 hashValueIndex was removed from Il2CppAssemblyNameDefinition, which is a field in Il2CppAssemblyDefinition
|
// In v24.4 hashValueIndex was removed from Il2CppAssemblyNameDefinition, which is a field in Il2CppAssemblyDefinition
|
||||||
// The number of images and assemblies should be the same. If they are not, we deduce that we are using v24.4
|
// The number of images and assemblies should be the same. If they are not, we deduce that we are using v24.4
|
||||||
// Note the version comparison matches both 24.2 and 24.3 here since 24.3 is tested for during binary loading
|
// Note the version comparison matches both 24.2 and 24.3 here since 24.3 is tested for during binary loading
|
||||||
var assemblyCount = Header.assembliesCount / Sizeof(typeof(Il2CppAssemblyDefinition));
|
var assemblyCount = Header.AssembliesSize / Sizeof<Il2CppAssemblyDefinition>();
|
||||||
var changedAssemblyDefStruct = false;
|
var changedAssemblyDefStruct = false;
|
||||||
if ((Version == 24.1 || Version == 24.2 || Version == 24.3) && assemblyCount < Images.Length)
|
if ((Version == MetadataVersions.V241 || Version == MetadataVersions.V242 || Version == MetadataVersions.V243) && assemblyCount < Images.Length)
|
||||||
{
|
{
|
||||||
if (Version == 24.1)
|
if (Version == MetadataVersions.V241)
|
||||||
changedAssemblyDefStruct = true;
|
changedAssemblyDefStruct = true;
|
||||||
Version = 24.4;
|
Version = MetadataVersions.V244;
|
||||||
}
|
}
|
||||||
|
|
||||||
Assemblies = ReadArray<Il2CppAssemblyDefinition>(Header.assembliesOffset, Images.Length);
|
Assemblies = ReadVersionedObjectArray<Il2CppAssemblyDefinition>(Header.AssembliesOffset, Images.Length);
|
||||||
|
|
||||||
if (changedAssemblyDefStruct)
|
if (changedAssemblyDefStruct)
|
||||||
Version = 24.1;
|
Version = MetadataVersions.V241;
|
||||||
|
|
||||||
ParameterDefaultValues = ReadArray<Il2CppParameterDefaultValue>(Header.parameterDefaultValuesOffset, Header.parameterDefaultValuesCount / Sizeof(typeof(Il2CppParameterDefaultValue)));
|
ParameterDefaultValues = ReadVersionedObjectArray<Il2CppParameterDefaultValue>(Header.ParameterDefaultValuesOffset, Header.ParameterDefaultValuesSize / Sizeof<Il2CppParameterDefaultValue>());
|
||||||
}
|
}
|
||||||
if (Version >= 19 && Version < 27) {
|
if (Version >= MetadataVersions.V190 && Version < MetadataVersions.V270) {
|
||||||
MetadataUsageLists = ReadArray<Il2CppMetadataUsageList>(Header.metadataUsageListsOffset, Header.metadataUsageListsCount / Sizeof(typeof(Il2CppMetadataUsageList)));
|
MetadataUsageLists = ReadVersionedObjectArray<Il2CppMetadataUsageList>(Header.MetadataUsageListsOffset, Header.MetadataUsageListsCount / Sizeof<Il2CppMetadataUsageList>());
|
||||||
MetadataUsagePairs = ReadArray<Il2CppMetadataUsagePair>(Header.metadataUsagePairsOffset, Header.metadataUsagePairsCount / Sizeof(typeof(Il2CppMetadataUsagePair)));
|
MetadataUsagePairs = ReadVersionedObjectArray<Il2CppMetadataUsagePair>(Header.MetadataUsagePairsOffset, Header.MetadataUsagePairsCount / Sizeof<Il2CppMetadataUsagePair>());
|
||||||
}
|
}
|
||||||
if (Version >= 19) {
|
if (Version >= MetadataVersions.V190) {
|
||||||
FieldRefs = ReadArray<Il2CppFieldRef>(Header.fieldRefsOffset, Header.fieldRefsCount / Sizeof(typeof(Il2CppFieldRef)));
|
FieldRefs = ReadVersionedObjectArray<Il2CppFieldRef>(Header.FieldRefsOffset, Header.FieldRefsSize / Sizeof<Il2CppFieldRef>());
|
||||||
}
|
}
|
||||||
if (Version >= 21 && Version < 29) {
|
if (Version >= MetadataVersions.V210 && Version < MetadataVersions.V290) {
|
||||||
AttributeTypeIndices = ReadArray<int>(Header.attributeTypesOffset, Header.attributeTypesCount / sizeof(int));
|
AttributeTypeIndices = ReadPrimitiveArray<int>(Header.AttributesTypesOffset, Header.AttributesTypesCount / sizeof(int));
|
||||||
AttributeTypeRanges = ReadArray<Il2CppCustomAttributeTypeRange>(Header.attributesInfoOffset, Header.attributesInfoCount / Sizeof(typeof(Il2CppCustomAttributeTypeRange)));
|
AttributeTypeRanges = ReadVersionedObjectArray<Il2CppCustomAttributeTypeRange>(Header.AttributesInfoOffset, Header.AttributesInfoCount / Sizeof<Il2CppCustomAttributeTypeRange>());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Version >= 29)
|
if (Version >= MetadataVersions.V290)
|
||||||
{
|
{
|
||||||
AttributeDataRanges = ReadArray<Il2CppCustomAttributeDataRange>(Header.attributeDataRangeOffset,
|
AttributeDataRanges = ReadVersionedObjectArray<Il2CppCustomAttributeDataRange>(Header.AttributeDataRangeOffset,
|
||||||
Header.attributeDataRangeSize / Sizeof(typeof(Il2CppCustomAttributeDataRange)));
|
Header.AttributeDataRangeSize / Sizeof<Il2CppCustomAttributeDataRange>());
|
||||||
}
|
|
||||||
|
|
||||||
if (Version is 29 or 31)
|
|
||||||
{
|
|
||||||
// 29.2/31.2 added a new isUnmanagedCallersOnly flag to Il2CppMethodDefinition.
|
|
||||||
// This offsets all subsequent entries by one - we can detect this by checking the
|
|
||||||
// top token byte (which should always be 0x06).
|
|
||||||
|
|
||||||
if (Methods.Length >= 2)
|
|
||||||
{
|
|
||||||
var secondToken = Methods[1].token;
|
|
||||||
if (secondToken >> 24 != 0x6)
|
|
||||||
{
|
|
||||||
Version += 0.2;
|
|
||||||
|
|
||||||
Methods = ReadArray<Il2CppMethodDefinition>(Header.methodsOffset,
|
|
||||||
Header.methodsCount / Sizeof(typeof(Il2CppMethodDefinition)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all metadata strings
|
// Get all metadata strings
|
||||||
@@ -216,10 +201,10 @@ namespace Il2CppInspector
|
|||||||
Strings = pluginGetStringsResult.Strings;
|
Strings = pluginGetStringsResult.Strings;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
Position = Header.stringOffset;
|
Position = Header.StringOffset;
|
||||||
|
|
||||||
while (Position < Header.stringOffset + Header.stringCount)
|
while (Position < Header.StringOffset + Header.StringSize)
|
||||||
Strings.Add((int) Position - Header.stringOffset, ReadNullTerminatedString());
|
Strings.Add((int) Position - Header.StringOffset, ReadNullTerminatedString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all string literals
|
// Get all string literals
|
||||||
@@ -228,11 +213,11 @@ namespace Il2CppInspector
|
|||||||
StringLiterals = pluginGetStringLiteralsResult.StringLiterals.ToArray();
|
StringLiterals = pluginGetStringLiteralsResult.StringLiterals.ToArray();
|
||||||
|
|
||||||
else {
|
else {
|
||||||
var stringLiteralList = ReadArray<Il2CppStringLiteral>(Header.stringLiteralOffset, Header.stringLiteralCount / Sizeof(typeof(Il2CppStringLiteral)));
|
var stringLiteralList = ReadVersionedObjectArray<Il2CppStringLiteral>(Header.StringLiteralOffset, Header.StringLiteralSize / Sizeof<Il2CppStringLiteral>());
|
||||||
|
|
||||||
StringLiterals = new string[stringLiteralList.Length];
|
StringLiterals = new string[stringLiteralList.Length];
|
||||||
for (var i = 0; i < stringLiteralList.Length; i++)
|
for (var i = 0; i < stringLiteralList.Length; i++)
|
||||||
StringLiterals[i] = ReadFixedLengthString(Header.stringLiteralDataOffset + stringLiteralList[i].dataIndex, stringLiteralList[i].length);
|
StringLiterals[i] = ReadFixedLengthString(Header.StringLiteralDataOffset + stringLiteralList[i].DataIndex, (int)stringLiteralList[i].Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post-processing hook
|
// Post-processing hook
|
||||||
@@ -246,40 +231,6 @@ namespace Il2CppInspector
|
|||||||
CopyTo(outFile);
|
CopyTo(outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Sizeof(Type type) => Sizeof(type, Version);
|
public int Sizeof<T>() where T : IReadable => T.Size(Version, Is32Bit);
|
||||||
|
|
||||||
public int Sizeof(Type type, double metadataVersion, int longSizeBytes = 8) {
|
|
||||||
|
|
||||||
if (Reader.ObjectMappings.TryGetValue(type, out var streamType))
|
|
||||||
type = streamType;
|
|
||||||
|
|
||||||
int size = 0;
|
|
||||||
foreach (var i in type.GetTypeInfo().GetFields())
|
|
||||||
{
|
|
||||||
// Only process fields for our selected object versioning (always process if none supplied)
|
|
||||||
var versions = i.GetCustomAttributes<VersionAttribute>(false).Select(v => (v.Min, v.Max)).ToList();
|
|
||||||
if (versions.Any() && !versions.Any(v => (v.Min <= metadataVersion || v.Min == -1) && (v.Max >= metadataVersion || v.Max == -1)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (i.FieldType == typeof(long) || i.FieldType == typeof(ulong))
|
|
||||||
size += longSizeBytes;
|
|
||||||
else if (i.FieldType == typeof(int) || i.FieldType == typeof(uint))
|
|
||||||
size += 4;
|
|
||||||
else if (i.FieldType == typeof(short) || i.FieldType == typeof(ushort))
|
|
||||||
size += 2;
|
|
||||||
|
|
||||||
// Fixed-length array
|
|
||||||
else if (i.FieldType.IsArray) {
|
|
||||||
var attr = i.GetCustomAttribute<ArrayLengthAttribute>(false) ??
|
|
||||||
throw new InvalidOperationException("Array field " + i.Name + " must have ArrayLength attribute");
|
|
||||||
size += attr.FixedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Embedded object
|
|
||||||
else
|
|
||||||
size += Sizeof(i.FieldType, metadataVersion);
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,483 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper
|
|
||||||
Copyright 2017-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using NoisyCowStudios.Bin2Object;
|
|
||||||
|
|
||||||
namespace Il2CppInspector
|
|
||||||
{
|
|
||||||
// Unity 4.6.1p5 - first release, no global-metadata.dat
|
|
||||||
// Unity 5.2.0f3 -> v15
|
|
||||||
// Unity 5.3.0f4 -> v16
|
|
||||||
// Unity 5.3.2f1 -> v19
|
|
||||||
// Unity 5.3.3f1 -> v20
|
|
||||||
// Unity 5.3.5f1 -> v21
|
|
||||||
// Unity 5.5.0f3 -> v22
|
|
||||||
// Unity 5.6.0f3 -> v23
|
|
||||||
// Unity 2017.1.0f3 -> v24
|
|
||||||
// Unity 2018.3.0f2 -> v24.1
|
|
||||||
// Unity 2019.1.0f2 -> v24.2
|
|
||||||
// Unity 2019.3.7f1 -> v24.3
|
|
||||||
// Unity 2019.4.15f1 -> v24.4
|
|
||||||
// Unity 2019.4.21f1 -> v24.5
|
|
||||||
// Unity 2020.1.0f1 -> v24.3
|
|
||||||
// Unity 2020.1.11f1 -> v24.4
|
|
||||||
// Unity 2020.2.0f1 -> v27
|
|
||||||
// Unity 2020.2.4f1 -> v27.1
|
|
||||||
// Unity 2021.1.0f1 -> v27.2
|
|
||||||
// https://unity3d.com/get-unity/download/archive
|
|
||||||
// Metadata version is written at the end of Unity.IL2CPP.MetadataCacheWriter.WriteLibIl2CppMetadata or WriteMetadata (Unity.IL2CPP.dll)
|
|
||||||
|
|
||||||
// From il2cpp-metadata.h
|
|
||||||
#pragma warning disable CS0649
|
|
||||||
public class Il2CppGlobalMetadataHeader
|
|
||||||
{
|
|
||||||
public uint signature;
|
|
||||||
public int version;
|
|
||||||
public int stringLiteralOffset; // string data for managed code
|
|
||||||
public int stringLiteralCount;
|
|
||||||
public int stringLiteralDataOffset;
|
|
||||||
public int stringLiteralDataCount;
|
|
||||||
public int stringOffset; // string data for metadata
|
|
||||||
public int stringCount;
|
|
||||||
public int eventsOffset; // Il2CppEventDefinition
|
|
||||||
public int eventsCount;
|
|
||||||
public int propertiesOffset; // Il2CppPropertyDefinition
|
|
||||||
public int propertiesCount;
|
|
||||||
public int methodsOffset; // Il2CppMethodDefinition
|
|
||||||
public int methodsCount;
|
|
||||||
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int parameterDefaultValuesOffset; // Il2CppParameterDefaultValue
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int parameterDefaultValuesCount;
|
|
||||||
|
|
||||||
public int fieldDefaultValuesOffset; // Il2CppFieldDefaultValue
|
|
||||||
public int fieldDefaultValuesCount;
|
|
||||||
public int fieldAndParameterDefaultValueDataOffset; // uint8_t
|
|
||||||
public int fieldAndParameterDefaultValueDataCount;
|
|
||||||
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int fieldMarshaledSizesCount;
|
|
||||||
|
|
||||||
public int parametersOffset; // Il2CppParameterDefinition
|
|
||||||
public int parametersCount;
|
|
||||||
public int fieldsOffset; // Il2CppFieldDefinition
|
|
||||||
public int fieldsCount;
|
|
||||||
public int genericParametersOffset; // Il2CppGenericParameter
|
|
||||||
public int genericParametersCount;
|
|
||||||
public int genericParameterConstraintsOffset; // TypeIndex
|
|
||||||
public int genericParameterConstraintsCount;
|
|
||||||
public int genericContainersOffset; // Il2CppGenericContainer
|
|
||||||
public int genericContainersCount;
|
|
||||||
public int nestedTypesOffset; // TypeDefinitionIndex
|
|
||||||
public int nestedTypesCount;
|
|
||||||
public int interfacesOffset; // TypeIndex
|
|
||||||
public int interfacesCount;
|
|
||||||
public int vtableMethodsOffset; // EncodedMethodIndex
|
|
||||||
public int vtableMethodsCount;
|
|
||||||
public int interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair
|
|
||||||
public int interfaceOffsetsCount;
|
|
||||||
public int typeDefinitionsOffset; // Il2CppTypeDefinition
|
|
||||||
public int typeDefinitionsCount;
|
|
||||||
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int rgctxEntriesOffset; // Il2CppRGCTXDefinition
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int rgctxEntriesCount;
|
|
||||||
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int imagesOffset; // Il2CppImageDefinition
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int imagesCount;
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int assembliesOffset; // Il2CppAssemblyDefinition
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int assembliesCount;
|
|
||||||
|
|
||||||
[Version(Min = 19, Max = 24.5)]
|
|
||||||
public int metadataUsageListsOffset; // Il2CppMetadataUsageList
|
|
||||||
[Version(Min = 19, Max = 24.5)]
|
|
||||||
public int metadataUsageListsCount;
|
|
||||||
[Version(Min = 19, Max = 24.5)]
|
|
||||||
public int metadataUsagePairsOffset; // Il2CppMetadataUsagePair
|
|
||||||
[Version(Min = 19, Max = 24.5)]
|
|
||||||
public int metadataUsagePairsCount;
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public int fieldRefsOffset; // Il2CppFieldRef
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public int fieldRefsCount;
|
|
||||||
[Version(Min = 20)]
|
|
||||||
public int referencedAssembliesOffset; // int32_t
|
|
||||||
[Version(Min = 20)]
|
|
||||||
public int referencedAssembliesCount;
|
|
||||||
|
|
||||||
[Version(Min = 21, Max = 27.2)]
|
|
||||||
public int attributesInfoOffset; // Il2CppCustomAttributeTypeRange
|
|
||||||
[Version(Min = 21, Max = 27.2)]
|
|
||||||
public int attributesInfoCount;
|
|
||||||
[Version(Min = 21, Max = 27.2)]
|
|
||||||
public int attributeTypesOffset; // TypeIndex
|
|
||||||
[Version(Min = 21, Max = 27.2)]
|
|
||||||
public int attributeTypesCount;
|
|
||||||
[Version(Min = 29)]
|
|
||||||
public uint attributeDataOffset;
|
|
||||||
[Version(Min = 29)]
|
|
||||||
public int attributeDataSize;
|
|
||||||
[Version(Min = 29)]
|
|
||||||
public uint attributeDataRangeOffset;
|
|
||||||
[Version(Min = 29)]
|
|
||||||
public int attributeDataRangeSize;
|
|
||||||
|
|
||||||
// Added in metadata v22
|
|
||||||
[Version(Min = 22)]
|
|
||||||
public int unresolvedVirtualCallParameterTypesOffset; // TypeIndex
|
|
||||||
[Version(Min = 22)]
|
|
||||||
public int unresolvedVirtualCallParameterTypesCount;
|
|
||||||
[Version(Min = 22)]
|
|
||||||
public int unresolvedVirtualCallParameterRangesOffset; // Il2CppRange
|
|
||||||
[Version(Min = 22)]
|
|
||||||
public int unresolvedVirtualCallParameterRangesCount;
|
|
||||||
|
|
||||||
// Added in metadata v23
|
|
||||||
[Version(Min = 23)]
|
|
||||||
public int windowsRuntimeTypeNamesOffset; // Il2CppWindowsRuntimeTypeNamePair
|
|
||||||
[Version(Min = 23)]
|
|
||||||
public int windowsRuntimeTypeNamesSize;
|
|
||||||
|
|
||||||
// Added in metadata v27
|
|
||||||
[Version(Min = 27)]
|
|
||||||
public int windowsRuntimeStringsOffset; // const char*
|
|
||||||
[Version(Min = 27)]
|
|
||||||
public int windowsRuntimeStringsSize;
|
|
||||||
|
|
||||||
// Added in metadata v24
|
|
||||||
[Version(Min = 24)]
|
|
||||||
public int exportedTypeDefinitionsOffset; // TypeDefinitionIndex
|
|
||||||
[Version(Min = 24)]
|
|
||||||
public int exportedTypeDefinitionsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppImageDefinition
|
|
||||||
{
|
|
||||||
public int nameIndex;
|
|
||||||
public int assemblyIndex;
|
|
||||||
|
|
||||||
public int typeStart;
|
|
||||||
public uint typeCount;
|
|
||||||
|
|
||||||
[Version(Min = 24)]
|
|
||||||
public int exportedTypeStart;
|
|
||||||
[Version(Min = 24)]
|
|
||||||
public uint exportedTypeCount;
|
|
||||||
|
|
||||||
public int entryPointIndex;
|
|
||||||
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public uint token;
|
|
||||||
|
|
||||||
[Version(Min = 24.1)]
|
|
||||||
public int customAttributeStart;
|
|
||||||
[Version(Min = 24.1)]
|
|
||||||
public uint customAttributeCount;
|
|
||||||
}
|
|
||||||
#pragma warning restore CS0649
|
|
||||||
|
|
||||||
// Renamed from Il2CppAssembly somewhere after Unity 2017.2f3 up to Unity 2018.2.0f2
|
|
||||||
public class Il2CppAssemblyDefinition
|
|
||||||
{
|
|
||||||
// They moved the position of aname in v16 from the top to the bottom of the struct
|
|
||||||
public Il2CppAssemblyNameDefinition aname => aname_pre16 ?? aname_post16;
|
|
||||||
|
|
||||||
[Version(Max = 15)]
|
|
||||||
public Il2CppAssemblyNameDefinition aname_pre16;
|
|
||||||
|
|
||||||
public int imageIndex;
|
|
||||||
|
|
||||||
[Version(Min = 24.1)]
|
|
||||||
public uint token;
|
|
||||||
|
|
||||||
[Version(Max = 24.0)]
|
|
||||||
public int customAttributeIndex;
|
|
||||||
|
|
||||||
[Version(Min = 20)]
|
|
||||||
public int referencedAssemblyStart;
|
|
||||||
[Version(Min = 20)]
|
|
||||||
public int referencedAssemblyCount;
|
|
||||||
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public Il2CppAssemblyNameDefinition aname_post16;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renamed from Il2CppAssemblyName somewhere after Unity 2017.2f3 up to Unity 2018.2.0f2
|
|
||||||
public class Il2CppAssemblyNameDefinition
|
|
||||||
{
|
|
||||||
// They moved the position of publicKeyToken in v16 from the middle to the bottom of the struct
|
|
||||||
public byte[] publicKeyToken => publicKeyToken_post16;
|
|
||||||
|
|
||||||
public int nameIndex;
|
|
||||||
public int cultureIndex;
|
|
||||||
[Version(Max = 24.3)]
|
|
||||||
public int hashValueIndex;
|
|
||||||
public int publicKeyIndex;
|
|
||||||
[Version(Max = 15), ArrayLength(FixedSize = 8)]
|
|
||||||
public byte[] publicKeyToken_pre16;
|
|
||||||
public uint hash_alg;
|
|
||||||
public int hash_len;
|
|
||||||
public uint flags;
|
|
||||||
public int major;
|
|
||||||
public int minor;
|
|
||||||
public int build;
|
|
||||||
public int revision;
|
|
||||||
[Version(Min = 16), ArrayLength(FixedSize = 8)]
|
|
||||||
public byte[] publicKeyToken_post16;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppTypeDefinition
|
|
||||||
{
|
|
||||||
public int nameIndex;
|
|
||||||
public int namespaceIndex;
|
|
||||||
|
|
||||||
// Removed in metadata v24.1
|
|
||||||
[Version(Max = 24.0)]
|
|
||||||
public int customAttributeIndex;
|
|
||||||
|
|
||||||
public int byvalTypeIndex;
|
|
||||||
[Version(Max = 24.5)]
|
|
||||||
public int byrefTypeIndex;
|
|
||||||
|
|
||||||
public int declaringTypeIndex;
|
|
||||||
public int parentIndex;
|
|
||||||
public int elementTypeIndex; // we can probably remove this one. Only used for enums
|
|
||||||
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int rgctxStartIndex;
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int rgctxCount;
|
|
||||||
|
|
||||||
public int genericContainerIndex;
|
|
||||||
|
|
||||||
// Removed in metadata v23
|
|
||||||
[Version(Max = 22)]
|
|
||||||
public int delegateWrapperFromManagedToNativeIndex; // (was renamed to reversePInvokeWrapperIndex in v22)
|
|
||||||
[Version(Max = 22)]
|
|
||||||
public int marshalingFunctionsIndex;
|
|
||||||
[Version(Min = 21, Max = 22)]
|
|
||||||
public int ccwFunctionIndex;
|
|
||||||
[Version(Min = 21, Max = 22)]
|
|
||||||
public int guidIndex;
|
|
||||||
|
|
||||||
public uint flags;
|
|
||||||
|
|
||||||
public int fieldStart;
|
|
||||||
public int methodStart;
|
|
||||||
public int eventStart;
|
|
||||||
public int propertyStart;
|
|
||||||
public int nestedTypesStart;
|
|
||||||
public int interfacesStart;
|
|
||||||
public int vtableStart;
|
|
||||||
public int interfaceOffsetsStart;
|
|
||||||
|
|
||||||
public ushort method_count;
|
|
||||||
public ushort property_count;
|
|
||||||
public ushort field_count;
|
|
||||||
public ushort event_count;
|
|
||||||
public ushort nested_type_count;
|
|
||||||
public ushort vtable_count;
|
|
||||||
public ushort interfaces_count;
|
|
||||||
public ushort interface_offsets_count;
|
|
||||||
|
|
||||||
// bitfield to portably encode boolean values as single bits
|
|
||||||
// 01 - valuetype;
|
|
||||||
// 02 - enumtype;
|
|
||||||
// 03 - has_finalize;
|
|
||||||
// 04 - has_cctor;
|
|
||||||
// 05 - is_blittable;
|
|
||||||
// 06 - is_import; (from v22: is_import_or_windows_runtime)
|
|
||||||
// 07-10 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128)
|
|
||||||
public uint bitfield;
|
|
||||||
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public uint token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppMethodDefinition
|
|
||||||
{
|
|
||||||
public int nameIndex;
|
|
||||||
|
|
||||||
[Version(Min = 16)]
|
|
||||||
public int declaringType;
|
|
||||||
|
|
||||||
public int returnType;
|
|
||||||
|
|
||||||
[Version(Min = 31)]
|
|
||||||
public int returnParameterToken;
|
|
||||||
|
|
||||||
public int parameterStart;
|
|
||||||
|
|
||||||
[Version(Max = 24.0)]
|
|
||||||
public int customAttributeIndex;
|
|
||||||
|
|
||||||
public int genericContainerIndex;
|
|
||||||
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int methodIndex;
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int invokerIndex;
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int reversePInvokeWrapperIndex; // (was renamed from delegateWrapperIndex in v22)
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int rgctxStartIndex;
|
|
||||||
[Version(Max = 24.1)]
|
|
||||||
public int rgctxCount;
|
|
||||||
|
|
||||||
public uint token;
|
|
||||||
public ushort flags;
|
|
||||||
public ushort iflags;
|
|
||||||
public ushort slot;
|
|
||||||
public ushort parameterCount;
|
|
||||||
|
|
||||||
[Version(Min = 29.2, Max = 29.2)]
|
|
||||||
[Version(Min = 31.2, Max = 31.2)]
|
|
||||||
public byte isUnmanagedCallersOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppParameterDefinition
|
|
||||||
{
|
|
||||||
public int nameIndex;
|
|
||||||
public uint token;
|
|
||||||
|
|
||||||
[Version(Max = 24.0)]
|
|
||||||
public int customAttributeIndex;
|
|
||||||
|
|
||||||
public int typeIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppParameterDefaultValue
|
|
||||||
{
|
|
||||||
public int parameterIndex;
|
|
||||||
public int typeIndex;
|
|
||||||
public int dataIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppFieldDefinition
|
|
||||||
{
|
|
||||||
public int nameIndex;
|
|
||||||
public int typeIndex;
|
|
||||||
|
|
||||||
[Version(Max = 24.0)]
|
|
||||||
public int customAttributeIndex;
|
|
||||||
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public uint token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppFieldDefaultValue
|
|
||||||
{
|
|
||||||
public int fieldIndex;
|
|
||||||
public int typeIndex;
|
|
||||||
public int dataIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppPropertyDefinition
|
|
||||||
{
|
|
||||||
public int nameIndex;
|
|
||||||
public int get;
|
|
||||||
public int set;
|
|
||||||
public uint attrs;
|
|
||||||
|
|
||||||
[Version(Max = 24.0)]
|
|
||||||
public int customAttributeIndex;
|
|
||||||
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public uint token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppEventDefinition
|
|
||||||
{
|
|
||||||
public int nameIndex;
|
|
||||||
public int typeIndex;
|
|
||||||
public int add;
|
|
||||||
public int remove;
|
|
||||||
public int raise;
|
|
||||||
|
|
||||||
[Version(Max = 24.0)]
|
|
||||||
public int customAttributeIndex;
|
|
||||||
|
|
||||||
[Version(Min = 19)]
|
|
||||||
public uint token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppGenericContainer
|
|
||||||
{
|
|
||||||
/* index of the generic type definition or the generic method definition corresponding to this container */
|
|
||||||
public int ownerIndex; // either index into Il2CppClass metadata array or Il2CppMethodDefinition array
|
|
||||||
public int type_argc;
|
|
||||||
/* If true, we're a generic method, otherwise a generic type definition. */
|
|
||||||
public int is_method;
|
|
||||||
/* Our type parameters. */
|
|
||||||
public uint genericParameterStart; // GenericParameterIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppGenericParameter
|
|
||||||
{
|
|
||||||
public int ownerIndex; /* Type or method this parameter was defined in. */ // GenericContainerIndex
|
|
||||||
public int nameIndex; // StringIndex
|
|
||||||
public short constraintsStart; // GenericParameterConstraintIndex
|
|
||||||
public short constraintsCount;
|
|
||||||
public ushort num; // Generic parameter position
|
|
||||||
public ushort flags; // GenericParameterAttributes
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppCustomAttributeTypeRange
|
|
||||||
{
|
|
||||||
[Version(Min = 24.1)]
|
|
||||||
public uint token;
|
|
||||||
|
|
||||||
public int start;
|
|
||||||
public int count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppInterfaceOffsetPair
|
|
||||||
{
|
|
||||||
public int interfaceTypeIndex;
|
|
||||||
public int offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removed in metadata v27
|
|
||||||
public class Il2CppMetadataUsageList
|
|
||||||
{
|
|
||||||
public uint start;
|
|
||||||
public uint count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removed in metadata v27
|
|
||||||
public class Il2CppMetadataUsagePair
|
|
||||||
{
|
|
||||||
public uint destinationindex;
|
|
||||||
public uint encodedSourceIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppStringLiteral
|
|
||||||
{
|
|
||||||
public int length;
|
|
||||||
public int dataIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppFieldRef
|
|
||||||
{
|
|
||||||
public int typeIndex;
|
|
||||||
public int fieldIndex; // local offset into type fields
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Il2CppCustomAttributeDataRange
|
|
||||||
{
|
|
||||||
public uint token;
|
|
||||||
public uint startOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using Il2CppInspector.Next;
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
public enum MetadataUsageType
|
public enum MetadataUsageType
|
||||||
@@ -19,11 +21,13 @@ namespace Il2CppInspector
|
|||||||
FieldRva = 7
|
FieldRva = 7
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MetadataUsage
|
public record struct MetadataUsage
|
||||||
{
|
{
|
||||||
public MetadataUsageType Type { get; }
|
public MetadataUsageType Type { get; }
|
||||||
public int SourceIndex { get; }
|
public int SourceIndex { get; }
|
||||||
public ulong VirtualAddress { get; private set; }
|
public ulong VirtualAddress { get; }
|
||||||
|
|
||||||
|
public readonly bool IsValid => Type != 0;
|
||||||
|
|
||||||
public MetadataUsage(MetadataUsageType type, int sourceIndex, ulong virtualAddress = 0) {
|
public MetadataUsage(MetadataUsageType type, int sourceIndex, ulong virtualAddress = 0) {
|
||||||
Type = type;
|
Type = type;
|
||||||
@@ -34,10 +38,10 @@ namespace Il2CppInspector
|
|||||||
public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex, ulong virtualAddress = 0) {
|
public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex, ulong virtualAddress = 0) {
|
||||||
uint index;
|
uint index;
|
||||||
MetadataUsageType usageType;
|
MetadataUsageType usageType;
|
||||||
if (package.Version < 19) {
|
if (package.Version < MetadataVersions.V190) {
|
||||||
/* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */
|
/* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */
|
||||||
var isGeneric = encodedIndex & 0x80000000;
|
var isGeneric = encodedIndex & 0x80000000;
|
||||||
index = package.Binary.VTableMethodReferences[encodedIndex & 0x7FFFFFFF];
|
index = package.Binary.VTableMethodReferences[(int)(encodedIndex & 0x7FFFFFFF)];
|
||||||
usageType = (isGeneric != 0) ? MetadataUsageType.MethodRef : MetadataUsageType.MethodDef;
|
usageType = (isGeneric != 0) ? MetadataUsageType.MethodRef : MetadataUsageType.MethodDef;
|
||||||
} else {
|
} else {
|
||||||
/* These encoded indices appear in metadata usages, and are decoded by GetEncodedIndexType/GetDecodedMethodIndex */
|
/* These encoded indices appear in metadata usages, and are decoded by GetEncodedIndexType/GetDecodedMethodIndex */
|
||||||
@@ -46,12 +50,10 @@ namespace Il2CppInspector
|
|||||||
index = encodedIndex & 0x1FFFFFFF;
|
index = encodedIndex & 0x1FFFFFFF;
|
||||||
|
|
||||||
// From v27 the bottom bit is set to indicate the usage token hasn't been replaced with a pointer at runtime yet
|
// From v27 the bottom bit is set to indicate the usage token hasn't been replaced with a pointer at runtime yet
|
||||||
if (package.Version >= 27)
|
if (package.Version >= MetadataVersions.V270)
|
||||||
index >>= 1;
|
index >>= 1;
|
||||||
}
|
}
|
||||||
return new MetadataUsage(usageType, (int)index, virtualAddress);
|
return new MetadataUsage(usageType, (int)index, virtualAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAddress(ulong virtualAddress) => VirtualAddress = virtualAddress;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
<AssemblyName>Il2CppInspector.Common</AssemblyName>
|
<AssemblyName>Il2CppInspector.Common</AssemblyName>
|
||||||
<Authors>Katy Coe</Authors>
|
<Authors>Katy Coe</Authors>
|
||||||
<Version>2023.1</Version>
|
<Version>2023.1</Version>
|
||||||
@@ -38,8 +40,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="dnlib" Version="4.3.0" />
|
<PackageReference Include="dnlib" Version="4.4.0" />
|
||||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.3.1" />
|
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||||
<PackageReference Include="CxxDemangler" Version="0.2.4.11">
|
<PackageReference Include="CxxDemangler" Version="0.2.4.11">
|
||||||
<NoWarn>NU1605</NoWarn>
|
<NoWarn>NU1605</NoWarn>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -47,6 +49,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Bin2Object\Bin2Object\Bin2Object.csproj" PrivateAssets="all" />
|
<ProjectReference Include="..\Bin2Object\Bin2Object\Bin2Object.csproj" PrivateAssets="all" />
|
||||||
|
<ProjectReference Include="..\VersionedSerialization.Generator\VersionedSerialization.Generator.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
|
||||||
|
<ProjectReference Include="..\VersionedSerialization\VersionedSerialization.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Il2CppInspector.Cpp;
|
using Il2CppInspector.Cpp;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using Il2CppInspector.Reflection;
|
using Il2CppInspector.Reflection;
|
||||||
|
|
||||||
namespace Il2CppInspector.Model
|
namespace Il2CppInspector.Model
|
||||||
@@ -123,9 +124,9 @@ namespace Il2CppInspector.Model
|
|||||||
Add(binary.CodeRegistrationPointer, binary.CodeRegistration);
|
Add(binary.CodeRegistrationPointer, binary.CodeRegistration);
|
||||||
Add(binary.MetadataRegistrationPointer, binary.MetadataRegistration);
|
Add(binary.MetadataRegistrationPointer, binary.MetadataRegistration);
|
||||||
|
|
||||||
if (Model.Package.Version >= 24.2) {
|
if (Model.Package.Version >= MetadataVersions.V242) {
|
||||||
// TODO: Add some kind of AppArray composite type for arrays as we'll be adding more later
|
// TODO: Add some kind of AppArray composite type for arrays as we'll be adding more later
|
||||||
Add(binary.CodeRegistration.pcodeGenModules, binary.CodeGenModulePointers);
|
Add(binary.CodeRegistration.CodeGenModules, binary.CodeGenModulePointers);
|
||||||
|
|
||||||
foreach (var ptr in binary.CodeGenModulePointers)
|
foreach (var ptr in binary.CodeGenModulePointers)
|
||||||
Add(ptr.Value, binary.Modules[ptr.Key]);
|
Add(ptr.Value, binary.Modules[ptr.Key]);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using System.Linq;
|
|||||||
using Aron.Weiler;
|
using Aron.Weiler;
|
||||||
using Il2CppInspector.Cpp;
|
using Il2CppInspector.Cpp;
|
||||||
using Il2CppInspector.Cpp.UnityHeaders;
|
using Il2CppInspector.Cpp.UnityHeaders;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using Il2CppInspector.Reflection;
|
using Il2CppInspector.Reflection;
|
||||||
|
|
||||||
namespace Il2CppInspector.Model
|
namespace Il2CppInspector.Model
|
||||||
@@ -54,7 +55,7 @@ namespace Il2CppInspector.Model
|
|||||||
public Dictionary<ulong, (FieldInfo Field, string Value)> Fields { get; } = [];
|
public Dictionary<ulong, (FieldInfo Field, string Value)> Fields { get; } = [];
|
||||||
public Dictionary<ulong, (FieldInfo Field, string Value)> FieldRvas { get; } = [];
|
public Dictionary<ulong, (FieldInfo Field, string Value)> FieldRvas { get; } = [];
|
||||||
|
|
||||||
public bool StringIndexesAreOrdinals => Package.Version < 19;
|
public bool StringIndexesAreOrdinals => Package.Version < MetadataVersions.V190;
|
||||||
|
|
||||||
// The .NET type model for the application
|
// The .NET type model for the application
|
||||||
public TypeModel TypeModel { get; }
|
public TypeModel TypeModel { get; }
|
||||||
@@ -104,7 +105,8 @@ namespace Il2CppInspector.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
public AppModel(TypeModel model, bool makeDefaultBuild = true) {
|
public AppModel(TypeModel model, bool makeDefaultBuild = true)
|
||||||
|
{
|
||||||
// Save .NET type model
|
// Save .NET type model
|
||||||
TypeModel = model;
|
TypeModel = model;
|
||||||
|
|
||||||
@@ -252,11 +254,11 @@ namespace Il2CppInspector.Model
|
|||||||
case MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva:
|
case MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva:
|
||||||
var fieldRef = TypeModel.Package.FieldRefs[usage.SourceIndex];
|
var fieldRef = TypeModel.Package.FieldRefs[usage.SourceIndex];
|
||||||
var fieldType = TypeModel.GetMetadataUsageType(usage);
|
var fieldType = TypeModel.GetMetadataUsageType(usage);
|
||||||
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.fieldStart + fieldRef.fieldIndex);
|
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.FieldIndex + fieldRef.FieldIndex);
|
||||||
|
|
||||||
var value = field.HasFieldRVA
|
var value = field.HasFieldRVA
|
||||||
? Convert.ToHexString(Package.Metadata.ReadBytes(
|
? Convert.ToHexString(Package.Metadata.ReadBytes(
|
||||||
(long) field.DefaultValueMetadataAddress, field.FieldType.Sizes.nativeSize))
|
(long) field.DefaultValueMetadataAddress, field.FieldType.Sizes.NativeSize))
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
|
|
||||||
@@ -270,7 +272,7 @@ namespace Il2CppInspector.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add string literals for metadata <19 to the model
|
// Add string literals for metadata <19 to the model
|
||||||
if (Package.Version < 19) {
|
if (Package.Version < MetadataVersions.V190) {
|
||||||
/* Version < 19 calls `il2cpp_codegen_string_literal_from_index` to get string literals.
|
/* Version < 19 calls `il2cpp_codegen_string_literal_from_index` to get string literals.
|
||||||
* Unfortunately, metadata references are just loose globals in Il2CppMetadataUsage.cpp
|
* Unfortunately, metadata references are just loose globals in Il2CppMetadataUsage.cpp
|
||||||
* so we can't automatically name those. Next best thing is to define an enum for the strings. */
|
* so we can't automatically name those. Next best thing is to define an enum for the strings. */
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppArrayType
|
||||||
|
{
|
||||||
|
public Pointer<Il2CppType> ElementType;
|
||||||
|
public byte Rank;
|
||||||
|
public byte NumSizes;
|
||||||
|
public byte NumLowerBound;
|
||||||
|
|
||||||
|
public PrimitivePointer<int> Sizes;
|
||||||
|
public PrimitivePointer<int> LoBounds;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppCodeGenModule
|
||||||
|
{
|
||||||
|
public PrimitivePointer<byte> ModuleName; // const char*
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public uint MethodPointerCount;
|
||||||
|
|
||||||
|
public Pointer<Il2CppMethodPointer> MethodPointers;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(EqualTo = "24.5")]
|
||||||
|
[VersionCondition(GreaterThan = "27.1")]
|
||||||
|
public uint AdjustorThunksCount;
|
||||||
|
|
||||||
|
[VersionCondition(EqualTo = "24.5")]
|
||||||
|
[VersionCondition(GreaterThan = "27.1")]
|
||||||
|
public Pointer<Il2CppTokenAdjustorThunkPair> AdjustorThunks;
|
||||||
|
|
||||||
|
public PrimitivePointer<int> InvokerIndices; // int*
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public uint ReversePInvokeWrapperCount;
|
||||||
|
|
||||||
|
public Pointer<Il2CppTokenIndexMethodTuple> ReversePInvokeWrapperIndices;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public uint RgctxRangesCount;
|
||||||
|
public Pointer<Il2CppTokenRangePair> RgctxRanges;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public uint RgctxsCount;
|
||||||
|
public Pointer<Il2CppRgctxDefinition> Rgctxs;
|
||||||
|
|
||||||
|
public PrimitivePointer<byte> DebuggerMetadata; // Pointer<Il2CppDebuggerMetadataRegistration> DebuggerMetadata;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "27.0", LessThan = "27.2")]
|
||||||
|
public Pointer<Il2CppMethodPointer> CustomAttributeCacheGenerator;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "27.0")]
|
||||||
|
public Il2CppMethodPointer ModuleInitializer;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "27.0")]
|
||||||
|
public PrimitivePointer<int> StaticConstructorTypeIndices; // TypeDefinitionIndex*
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "27.0")]
|
||||||
|
public PrimitivePointer<byte> MetadataRegistration; // Pointer<Il2CppMetadataRegistration>
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "27.0")]
|
||||||
|
public PrimitivePointer<byte> CodeRegistration; // Pointer<Il2CppCodeRegistration>
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using InvokerMethod = Il2CppMethodPointer;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppCodeRegistration
|
||||||
|
{
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public uint MethodPointersCount;
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public Pointer<Il2CppMethodPointer> MethodPointers;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public uint ReversePInvokeWrapperCount;
|
||||||
|
|
||||||
|
public Pointer<Il2CppMethodPointer> ReversePInvokeWrappers;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(LessThan = "22.0")]
|
||||||
|
public uint DelegateWrappersFromManagedToNativeCount;
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "22.0")]
|
||||||
|
public Pointer<Il2CppMethodPointer> DelegateWrappersFromManagedToNative;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(LessThan = "22.0")]
|
||||||
|
public uint MarshalingFunctionsCount;
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "22.0")]
|
||||||
|
public Pointer<Il2CppMethodPointer> MarshalingFunctions;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "22.0")]
|
||||||
|
public uint CcwMarshalingFunctionsCount;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "22.0")]
|
||||||
|
public Pointer<Il2CppMethodPointer> CcwMarshalingFunctions;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public uint GenericMethodPointersCount;
|
||||||
|
|
||||||
|
public Pointer<Il2CppMethodPointer> GenericMethodPointers;
|
||||||
|
|
||||||
|
[VersionCondition(EqualTo = "24.5")]
|
||||||
|
[VersionCondition(GreaterThan = "27.1")]
|
||||||
|
public Pointer<Il2CppMethodPointer> GenericAdjustorThunks;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public uint InvokerPointersCount;
|
||||||
|
|
||||||
|
public Pointer<InvokerMethod> InvokerPointers;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(LessThan = "24.5")]
|
||||||
|
public int CustomAttributeCount;
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.5")]
|
||||||
|
public Pointer<Il2CppMethodPointer> CustomAttributeGenerators;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "22.0")]
|
||||||
|
public int GuidCount;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "22.0")]
|
||||||
|
public Pointer<Il2CppGuid> Guids;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(GreaterThan = "22.0", LessThan = "27.2")]
|
||||||
|
[VersionCondition(EqualTo = "29.0", IncludingTag = "")]
|
||||||
|
[VersionCondition(EqualTo = "31.0", IncludingTag = "")]
|
||||||
|
public int UnresolvedVirtualCallCount;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(EqualTo = "29.0", IncludingTag = "2022"), VersionCondition(EqualTo = "31.0", IncludingTag = "2022")]
|
||||||
|
[VersionCondition(EqualTo = "29.0", IncludingTag = "2023"), VersionCondition(EqualTo = "31.0", IncludingTag = "2023")]
|
||||||
|
public uint UnresolvedIndirectCallCount; // UnresolvedVirtualCallCount pre 29.1
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "22.0")]
|
||||||
|
public Pointer<Il2CppMethodPointer> UnresolvedVirtualCallPointers;
|
||||||
|
|
||||||
|
[VersionCondition(EqualTo = "29.0", IncludingTag = "2022"), VersionCondition(EqualTo = "31.0", IncludingTag = "2022")]
|
||||||
|
[VersionCondition(EqualTo = "29.0", IncludingTag = "2023"), VersionCondition(EqualTo = "31.0", IncludingTag = "2023")]
|
||||||
|
public Pointer<Il2CppMethodPointer> UnresolvedInstanceCallWrappers;
|
||||||
|
|
||||||
|
[VersionCondition(EqualTo = "29.0", IncludingTag = "2022"), VersionCondition(EqualTo = "31.0", IncludingTag = "2022")]
|
||||||
|
[VersionCondition(EqualTo = "29.0", IncludingTag = "2023"), VersionCondition(EqualTo = "31.0", IncludingTag = "2023")]
|
||||||
|
public Pointer<Il2CppMethodPointer> UnresolvedStaticCallPointers;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(GreaterThan = "23.0")]
|
||||||
|
public uint InteropDataCount;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "23.0")]
|
||||||
|
public Pointer<Il2CppInteropData> InteropData;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(GreaterThan = "24.3")]
|
||||||
|
public uint WindowsRuntimeFactoryCount;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "24.3")]
|
||||||
|
public Pointer<Il2CppWindowsRuntimeFactoryTableEntry> WindowsRuntimeFactoryTable;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(GreaterThan = "24.2")]
|
||||||
|
public uint CodeGenModulesCount;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "24.2")]
|
||||||
|
public Pointer<Pointer<Il2CppCodeGenModule>> CodeGenModules;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppGenericClass
|
||||||
|
{
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(LessThan = "24.5")]
|
||||||
|
public int TypeDefinitionIndex;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "27.0")]
|
||||||
|
public Pointer<Il2CppType> Type;
|
||||||
|
|
||||||
|
public Il2CppGenericContext Context;
|
||||||
|
|
||||||
|
public PrimitivePointer<byte> CachedClass; // Il2CppClass*, optional
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppGenericContext
|
||||||
|
{
|
||||||
|
public Pointer<Il2CppGenericInst> ClassInst;
|
||||||
|
public Pointer<Il2CppGenericInst> MethodInst;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppGenericInst
|
||||||
|
{
|
||||||
|
public readonly bool Valid => TypeArgc > 0;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public uint TypeArgc;
|
||||||
|
|
||||||
|
public Pointer<Pointer<Il2CppType>> TypeArgv;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using GenericMethodIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppGenericMethodFunctionsDefinitions
|
||||||
|
{
|
||||||
|
public GenericMethodIndex GenericMethodIndex;
|
||||||
|
public Il2CppGenericMethodIndices Indices;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using MethodIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppGenericMethodIndices
|
||||||
|
{
|
||||||
|
public MethodIndex MethodIndex;
|
||||||
|
public MethodIndex InvokerIndex;
|
||||||
|
|
||||||
|
[VersionCondition(EqualTo = "24.5")]
|
||||||
|
[VersionCondition(GreaterThan = "27.1")]
|
||||||
|
public MethodIndex AdjustorThunkIndex;
|
||||||
|
}
|
||||||
21
Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGuid.cs
Normal file
21
Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGuid.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
public record struct Il2CppGuid : IReadable
|
||||||
|
{
|
||||||
|
public Guid Value;
|
||||||
|
|
||||||
|
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
|
||||||
|
{
|
||||||
|
var guid = reader.ReadBytes(16);
|
||||||
|
Value = new Guid(guid, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Size(in StructVersion version = default, bool is32Bit = false)
|
||||||
|
{
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Guid(Il2CppGuid value) => value.Value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using PInvokeMarshalToNativeFunc = Il2CppMethodPointer;
|
||||||
|
using PInvokeMarshalFromNativeFunc = Il2CppMethodPointer;
|
||||||
|
using PInvokeMarshalCleanupFunc = Il2CppMethodPointer;
|
||||||
|
using CreateCCWFunc = Il2CppMethodPointer;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppInteropData
|
||||||
|
{
|
||||||
|
public Il2CppMethodPointer DelegatePInvokeWrapperFunction;
|
||||||
|
public PInvokeMarshalToNativeFunc PInvokeMarshalToNativeFunction;
|
||||||
|
public PInvokeMarshalFromNativeFunc PInvokeMarshalFromNativeFunction;
|
||||||
|
public PInvokeMarshalCleanupFunc PInvokeMarshalCleanupFunction;
|
||||||
|
public CreateCCWFunc CreateCCWFunction;
|
||||||
|
public Pointer<Il2CppGuid> Guid;
|
||||||
|
public Pointer<Il2CppType> Type;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using FieldIndex = int;
|
||||||
|
using TypeDefinitionIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppMetadataRegistration
|
||||||
|
{
|
||||||
|
[NativeInteger]
|
||||||
|
public int GenericClassesCount;
|
||||||
|
|
||||||
|
public Pointer<Pointer<Il2CppGenericClass>> GenericClasses;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public int GenericInstsCount;
|
||||||
|
|
||||||
|
public Pointer<Pointer<Il2CppGenericInst>> GenericInsts;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public int GenericMethodTableCount;
|
||||||
|
|
||||||
|
public Pointer<Il2CppGenericMethodFunctionsDefinitions> GenericMethodTable;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public int TypesCount;
|
||||||
|
|
||||||
|
public Pointer<Pointer<Il2CppType>> Types;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public int MethodSpecsCount;
|
||||||
|
|
||||||
|
public Pointer<Il2CppMethodSpec> MethodSpecs;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(LessThan = "16.0")]
|
||||||
|
public int MethodReferencesCount;
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "16.0")]
|
||||||
|
public PrimitivePointer<PrimitivePointer<uint>> MethodReferences; // uint**
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public FieldIndex FieldOffsetsCount;
|
||||||
|
|
||||||
|
public PrimitivePointer<PrimitivePointer<int>> FieldOffsets; // int**
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public TypeDefinitionIndex TypeDefinitionsSizesCount;
|
||||||
|
public Pointer<Pointer<Il2CppTypeDefinitionSizes>> TypeDefinitionsSizes;
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public ulong MetadataUsagesCount;
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public Pointer<Pointer<Il2CppMetadataUsage>> MetadataUsages;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppMethodPointer(ulong addr = 0)
|
||||||
|
{
|
||||||
|
public static readonly Il2CppMethodPointer Null = new();
|
||||||
|
|
||||||
|
[NativeInteger]
|
||||||
|
public ulong Value { get; set; } = addr;
|
||||||
|
|
||||||
|
public readonly bool IsNull => Value == 0;
|
||||||
|
|
||||||
|
public readonly override string ToString() => $"0x{Value:X}";
|
||||||
|
|
||||||
|
public static implicit operator ulong(Il2CppMethodPointer ptr) => ptr.Value;
|
||||||
|
public static implicit operator Il2CppMethodPointer(ulong ptr) => new(ptr);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using MethodIndex = int;
|
||||||
|
using GenericInstIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppMethodSpec
|
||||||
|
{
|
||||||
|
public MethodIndex MethodDefinitionIndex;
|
||||||
|
public GenericInstIndex ClassIndexIndex;
|
||||||
|
public GenericInstIndex MethodIndexIndex;
|
||||||
|
}
|
||||||
10
Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRange.cs
Normal file
10
Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRange.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppRange
|
||||||
|
{
|
||||||
|
public int Start;
|
||||||
|
public int Length;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using TypeIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppRgctxConstrainedData
|
||||||
|
{
|
||||||
|
public TypeIndex TypeIndex;
|
||||||
|
public Il2CppMetadataUsage EncodedMethodIndex;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
public enum Il2CppRgctxDataType
|
||||||
|
{
|
||||||
|
IL2CPP_RGCTX_DATA_INVALID,
|
||||||
|
IL2CPP_RGCTX_DATA_TYPE,
|
||||||
|
IL2CPP_RGCTX_DATA_CLASS,
|
||||||
|
IL2CPP_RGCTX_DATA_METHOD,
|
||||||
|
IL2CPP_RGCTX_DATA_ARRAY,
|
||||||
|
IL2CPP_RGCTX_DATA_CONSTRAINED,
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppRgctxDefinition
|
||||||
|
{
|
||||||
|
[NativeInteger]
|
||||||
|
public Il2CppRgctxDataType Type;
|
||||||
|
|
||||||
|
public PrimitivePointer<byte> Data; // void*
|
||||||
|
|
||||||
|
public readonly Pointer<Il2CppRgctxDefinitionData> Definition => Data.PointerValue;
|
||||||
|
public readonly Pointer<Il2CppRgctxConstrainedData> Constrained => Data.PointerValue;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using MethodIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppRgctxDefinitionData
|
||||||
|
{
|
||||||
|
public int Value;
|
||||||
|
|
||||||
|
public readonly MethodIndex MethodIndex => Value;
|
||||||
|
public readonly TypeIndex TypeIndex => Value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppTokenAdjustorThunkPair
|
||||||
|
{
|
||||||
|
[NativeInteger]
|
||||||
|
public uint Token;
|
||||||
|
|
||||||
|
public Il2CppMethodPointer AdjustorThunk;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppTokenIndexMethodTuple
|
||||||
|
{
|
||||||
|
public uint Token;
|
||||||
|
public int Index;
|
||||||
|
|
||||||
|
public PrimitivePointer<Il2CppMethodPointer> Method; // void**
|
||||||
|
|
||||||
|
public uint GenericMethodIndex;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppTokenRangePair
|
||||||
|
{
|
||||||
|
public uint Token;
|
||||||
|
public Il2CppRange Range;
|
||||||
|
}
|
||||||
111
Il2CppInspector.Common/Next/BinaryMetadata/Il2CppType.cs
Normal file
111
Il2CppInspector.Common/Next/BinaryMetadata/Il2CppType.cs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
using System.Reflection;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
using TypeDefinitionIndex = int;
|
||||||
|
using GenericParameterIndex = int;
|
||||||
|
using Il2CppMetadataTypeHandle = Pointer<Il2CppTypeDefinition>;
|
||||||
|
using Il2CppMetadataGenericParameterHandle = Pointer<Il2CppGenericParameter>;
|
||||||
|
|
||||||
|
public record struct Il2CppType : IReadable
|
||||||
|
{
|
||||||
|
public record struct DataUnion : IReadable
|
||||||
|
{
|
||||||
|
public ulong Value;
|
||||||
|
|
||||||
|
public readonly TypeDefinitionIndex KlassIndex => (int)Value;
|
||||||
|
public readonly Il2CppMetadataTypeHandle TypeHandle => Value;
|
||||||
|
public readonly Pointer<Il2CppType> Type => Value;
|
||||||
|
public readonly Pointer<Il2CppArrayType> ArrayType => Value;
|
||||||
|
public readonly GenericParameterIndex GenericParameterIndex => (int)Value;
|
||||||
|
public readonly Il2CppMetadataGenericParameterHandle GenericParameterHandle => Value;
|
||||||
|
public readonly Pointer<Il2CppGenericClass> GenericClass => Value;
|
||||||
|
|
||||||
|
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
|
||||||
|
{
|
||||||
|
Value = reader.ReadNUInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Size(in StructVersion version = default, bool is32Bit = false)
|
||||||
|
{
|
||||||
|
return is32Bit ? 4 : 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataUnion Data;
|
||||||
|
public uint Value;
|
||||||
|
|
||||||
|
public TypeAttributes Attrs
|
||||||
|
{
|
||||||
|
readonly get => (TypeAttributes)(Value & 0xFFFF);
|
||||||
|
set => Value = (Value & 0xFFFF0000) | (uint)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Il2CppTypeEnum Type
|
||||||
|
{
|
||||||
|
readonly get => (Il2CppTypeEnum)((Value >> 16) & 0b11111111);
|
||||||
|
set => Value = (Value & 0xFF00FFFF) | ((uint)value) << 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint NumModifiers
|
||||||
|
{
|
||||||
|
readonly get => (Value >> 24) & 0b11111;
|
||||||
|
set => Value = (Value & 0xE0FFFFFF) | value << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ByRef
|
||||||
|
{
|
||||||
|
readonly get => ((Value >> 29) & 1) == 1;
|
||||||
|
set => Value = (Value & 0xDFFFFFFF) | (value ? 1u : 0u) << 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Pinned
|
||||||
|
{
|
||||||
|
readonly get => ((Value >> 30) & 1) == 1;
|
||||||
|
set => Value = (Value & 0xBFFFFFFF) | (value ? 1u : 0u) << 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ValueType
|
||||||
|
{
|
||||||
|
readonly get => ((Value >> 31) & 1) == 1;
|
||||||
|
set => Value = (Value & 0x7FFFFFFF) | (value ? 1u : 0u) << 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
|
||||||
|
{
|
||||||
|
Data.Read(ref reader, version);
|
||||||
|
Value = reader.ReadPrimitive<uint>();
|
||||||
|
|
||||||
|
if (MetadataVersions.V272 > version)
|
||||||
|
{
|
||||||
|
// Versions pre-27.2 had NumModifiers at 6 bits and no ValueType bit
|
||||||
|
var numModifiers = (Value >> 24) & 0b111111;
|
||||||
|
|
||||||
|
// If NumModifiers > 31, we throw here (as the old behavior isn't implemented
|
||||||
|
if (numModifiers > 31)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Versions pre-27.2 with a type having more than 31 modifiers are not supported yet");
|
||||||
|
|
||||||
|
// Else, we do some bit-juggling to convert the old value into the new format:
|
||||||
|
Value =
|
||||||
|
(Value & 0xFFFFFF) | // Attributes + Type
|
||||||
|
(((Value >> 24) & 0b111111) << 24) | // 5 Bits for the modifiers
|
||||||
|
(((Value >> 30) & 1) << 29) | // Shifted ByRef
|
||||||
|
(((Value >> 31) & 1) << 30) | // Shifted Pinned
|
||||||
|
0; // 0 ValueType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Size(in StructVersion version = default, bool is32Bit = false)
|
||||||
|
{
|
||||||
|
return DataUnion.Size(version, is32Bit) + sizeof(uint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Il2CppType FromTypeEnum(Il2CppTypeEnum type)
|
||||||
|
=> new()
|
||||||
|
{
|
||||||
|
Value = (uint)type << 16
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppTypeDefinitionSizes
|
||||||
|
{
|
||||||
|
public uint InstanceSize;
|
||||||
|
public int NativeSize;
|
||||||
|
public uint StaticFieldsSize;
|
||||||
|
public uint ThreadStaticFieldsSize;
|
||||||
|
}
|
||||||
76
Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTypeEnum.cs
Normal file
76
Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTypeEnum.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
public enum Il2CppTypeEnum : byte
|
||||||
|
{
|
||||||
|
Il2CPP_TYPE_END,
|
||||||
|
IL2CPP_TYPE_VOID,
|
||||||
|
IL2CPP_TYPE_BOOLEAN,
|
||||||
|
IL2CPP_TYPE_CHAR,
|
||||||
|
IL2CPP_TYPE_I1,
|
||||||
|
IL2CPP_TYPE_U1,
|
||||||
|
IL2CPP_TYPE_I2,
|
||||||
|
IL2CPP_TYPE_U2,
|
||||||
|
IL2CPP_TYPE_I4,
|
||||||
|
IL2CPP_TYPE_U4,
|
||||||
|
IL2CPP_TYPE_I8,
|
||||||
|
IL2CPP_TYPE_U8,
|
||||||
|
IL2CPP_TYPE_R4,
|
||||||
|
IL2CPP_TYPE_R8,
|
||||||
|
IL2CPP_TYPE_STRING,
|
||||||
|
IL2CPP_TYPE_PTR,
|
||||||
|
IL2CPP_TYPE_BYREF,
|
||||||
|
IL2CPP_TYPE_VALUETYPE,
|
||||||
|
IL2CPP_TYPE_CLASS,
|
||||||
|
IL2CPP_TYPE_VAR,
|
||||||
|
IL2CPP_TYPE_ARRAY,
|
||||||
|
IL2CPP_TYPE_GENERICINST,
|
||||||
|
IL2CPP_TYPE_TYPEDBYREF,
|
||||||
|
IL2CPP_TYPE_I = 0x18,
|
||||||
|
IL2CPP_TYPE_U,
|
||||||
|
IL2CPP_TYPE_FNPTR = 0x1b,
|
||||||
|
IL2CPP_TYPE_OBJECT,
|
||||||
|
IL2CPP_TYPE_SZARRAY,
|
||||||
|
IL2CPP_TYPE_MVAR,
|
||||||
|
IL2CPP_TYPE_CMOD_REQD,
|
||||||
|
IL2CPP_TYPE_CMOD_OPT,
|
||||||
|
IL2CPP_TYPE_INTERNAL,
|
||||||
|
|
||||||
|
IL2CPP_TYPE_MODIFIER = 0x40,
|
||||||
|
IL2CPP_TYPE_SENTINEL = 0x41,
|
||||||
|
IL2CPP_TYPE_PINNED = 0x45,
|
||||||
|
|
||||||
|
IL2CPP_TYPE_ENUM = 0x55,
|
||||||
|
IL2CPP_TYPE_IL2CPP_TYPE_INDEX = 0xff
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Il2CppTypeEnumExtensions
|
||||||
|
{
|
||||||
|
public static bool IsTypeDefinitionEnum(this Il2CppTypeEnum value)
|
||||||
|
=> value
|
||||||
|
is Il2CppTypeEnum.IL2CPP_TYPE_VOID
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_CHAR
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_I1
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_U1
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_I2
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_U2
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_I4
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_U4
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_I8
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_U8
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_R4
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_R8
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_STRING
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_CLASS
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_I
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_U
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_OBJECT
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF;
|
||||||
|
|
||||||
|
public static bool IsGenericParameterEnum(this Il2CppTypeEnum value)
|
||||||
|
=> value
|
||||||
|
is Il2CppTypeEnum.IL2CPP_TYPE_VAR
|
||||||
|
or Il2CppTypeEnum.IL2CPP_TYPE_MVAR;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppWindowsRuntimeFactoryTableEntry
|
||||||
|
{
|
||||||
|
public Pointer<Il2CppType> Type;
|
||||||
|
public Il2CppMethodPointer CreateFactoryFunction;
|
||||||
|
}
|
||||||
147
Il2CppInspector.Common/Next/BinaryObjectStreamReader.cs
Normal file
147
Il2CppInspector.Common/Next/BinaryObjectStreamReader.cs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using NoisyCowStudios.Bin2Object;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next;
|
||||||
|
|
||||||
|
public class BinaryObjectStreamReader : BinaryObjectStream, IReader
|
||||||
|
{
|
||||||
|
public new StructVersion Version
|
||||||
|
{
|
||||||
|
get => _version;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_version = value;
|
||||||
|
base.Version = _version.AsDouble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StructVersion _version;
|
||||||
|
|
||||||
|
public virtual int Bits { get; set; }
|
||||||
|
public bool Is32Bit => Bits == 32;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static TTo Cast<TFrom, TTo>(in TFrom from) => Unsafe.As<TFrom, TTo>(ref Unsafe.AsRef(in from));
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private T ReadInternal<T>() where T : unmanaged
|
||||||
|
{
|
||||||
|
var size = Unsafe.SizeOf<T>();
|
||||||
|
var value = MemoryMarshal.Read<T>(ReadBytes(size));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T ReadPrimitive<T>() where T : unmanaged
|
||||||
|
{
|
||||||
|
if (typeof(T) == typeof(sbyte))
|
||||||
|
return Cast<byte, T>(ReadByte());
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(short))
|
||||||
|
return Cast<short, T>(ReadInt16());
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(int))
|
||||||
|
return Cast<int, T>(ReadInt32());
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(long))
|
||||||
|
return Cast<long, T>(ReadInt64());
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(byte))
|
||||||
|
return Cast<byte, T>(ReadByte());
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(ushort))
|
||||||
|
return Cast<ushort, T>(ReadUInt16());
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(uint))
|
||||||
|
return Cast<uint, T>(ReadUInt32());
|
||||||
|
|
||||||
|
if (typeof(T) == typeof(ulong))
|
||||||
|
return Cast<ulong, T>(ReadUInt64());
|
||||||
|
|
||||||
|
return ReadInternal<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableArray<T> ReadPrimitiveArray<T>(long count) where T : unmanaged
|
||||||
|
{
|
||||||
|
var array = ImmutableArray.CreateBuilder<T>(checked((int)count));
|
||||||
|
for (long i = 0; i < count; i++)
|
||||||
|
array.Add(ReadPrimitive<T>());
|
||||||
|
|
||||||
|
return array.MoveToImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T ReadVersionedObject<T>() where T : IReadable, new() => ReadVersionedObject<T>(Version);
|
||||||
|
|
||||||
|
public T ReadVersionedObject<T>(in StructVersion version = default) where T : IReadable, new()
|
||||||
|
{
|
||||||
|
var obj = new T();
|
||||||
|
var a = this;
|
||||||
|
obj.Read(ref a, in version);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableArray<T> ReadVersionedObjectArray<T>(long count) where T : IReadable, new() => ReadVersionedObjectArray<T>(count, Version);
|
||||||
|
|
||||||
|
public ImmutableArray<T> ReadVersionedObjectArray<T>(long count, in StructVersion version = default) where T : IReadable, new()
|
||||||
|
{
|
||||||
|
var array = ImmutableArray.CreateBuilder<T>(checked((int)count));
|
||||||
|
for (long i = 0; i < count; i++)
|
||||||
|
array.Add(ReadVersionedObject<T>(in version));
|
||||||
|
|
||||||
|
return array.MoveToImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ReadNInt()
|
||||||
|
=> Is32Bit ? ReadPrimitive<int>() : ReadPrimitive<long>();
|
||||||
|
|
||||||
|
public ulong ReadNUInt()
|
||||||
|
=> Is32Bit ? ReadPrimitive<uint>() : ReadPrimitive<ulong>();
|
||||||
|
|
||||||
|
public string ReadString() => ReadNullTerminatedString();
|
||||||
|
|
||||||
|
public new ReadOnlySpan<byte> ReadBytes(int length)
|
||||||
|
{
|
||||||
|
return base.ReadBytes(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Align(int alignment = 0)
|
||||||
|
{
|
||||||
|
if (alignment == 0)
|
||||||
|
alignment = Is32Bit ? 4 : 8;
|
||||||
|
|
||||||
|
var rem = Position % alignment;
|
||||||
|
if (rem != 0)
|
||||||
|
Position += alignment - rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TType ReadPrimitive<TType>(long addr) where TType : unmanaged
|
||||||
|
{
|
||||||
|
Position = addr;
|
||||||
|
return ReadPrimitive<TType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadPrimitiveArray<TType>(long addr, long count) where TType : unmanaged
|
||||||
|
{
|
||||||
|
Position = addr;
|
||||||
|
return ReadPrimitiveArray<TType>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TType ReadVersionedObject<TType>(long addr) where TType : IReadable, new()
|
||||||
|
{
|
||||||
|
Position = addr;
|
||||||
|
return ReadVersionedObject<TType>(Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableArray<TType> ReadVersionedObjectArray<TType>(long addr, long count) where TType : IReadable, new()
|
||||||
|
{
|
||||||
|
Position = addr;
|
||||||
|
return ReadVersionedObjectArray<TType>(count, Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Skip(int count)
|
||||||
|
{
|
||||||
|
Position += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using ImageIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public partial record struct Il2CppAssemblyDefinition
|
||||||
|
{
|
||||||
|
[FieldOffset(20)]
|
||||||
|
[VersionCondition(LessThan = "15.0")]
|
||||||
|
public Il2CppAssemblyNameDefinition LegacyAname;
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public ImageIndex ImageIndex;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
[VersionCondition(GreaterThan = "24.1")]
|
||||||
|
public uint Token;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
[VersionCondition(LessThan = "24.0")]
|
||||||
|
public int CustomAttributeIndex;
|
||||||
|
|
||||||
|
[FieldOffset(12)]
|
||||||
|
[VersionCondition(GreaterThan = "20.0")]
|
||||||
|
public int ReferencedAssemblyStart;
|
||||||
|
|
||||||
|
[FieldOffset(16)]
|
||||||
|
[VersionCondition(GreaterThan = "20.0")]
|
||||||
|
public int ReferencedAssemblyCount;
|
||||||
|
|
||||||
|
[FieldOffset(20)]
|
||||||
|
public Il2CppAssemblyNameDefinition Aname;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using StringIndex = int;
|
||||||
|
|
||||||
|
[InlineArray(PublicKeyLength)]
|
||||||
|
public struct PublicKeyToken
|
||||||
|
{
|
||||||
|
private const int PublicKeyLength = 8;
|
||||||
|
|
||||||
|
private byte _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public partial record struct Il2CppAssemblyNameDefinition
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public StringIndex NameIndex;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public StringIndex CultureIndex;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
[VersionCondition(LessThan = "24.3")]
|
||||||
|
public int HashValueIndex;
|
||||||
|
|
||||||
|
[FieldOffset(12)]
|
||||||
|
public StringIndex PublicKeyIndex;
|
||||||
|
|
||||||
|
[FieldOffset(44)]
|
||||||
|
[VersionCondition(LessThan = "15.0")]
|
||||||
|
[CustomSerialization("reader.ReadPrimitive<PublicKeyToken>();", "8")]
|
||||||
|
private PublicKeyToken _legacyPublicKeyToken;
|
||||||
|
|
||||||
|
[FieldOffset(16)]
|
||||||
|
public AssemblyHashAlgorithm HashAlg;
|
||||||
|
|
||||||
|
[FieldOffset(20)]
|
||||||
|
public int HashLen;
|
||||||
|
|
||||||
|
[FieldOffset(24)]
|
||||||
|
public AssemblyNameFlags Flags;
|
||||||
|
|
||||||
|
[FieldOffset(28)]
|
||||||
|
public int Major;
|
||||||
|
|
||||||
|
[FieldOffset(32)]
|
||||||
|
public int Minor;
|
||||||
|
|
||||||
|
[FieldOffset(36)]
|
||||||
|
public int Build;
|
||||||
|
|
||||||
|
[FieldOffset(40)]
|
||||||
|
public int Revision;
|
||||||
|
|
||||||
|
[FieldOffset(44)]
|
||||||
|
[CustomSerialization("reader.ReadPrimitive<PublicKeyToken>();", "8")]
|
||||||
|
public PublicKeyToken PublicKeyToken;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppCustomAttributeDataRange
|
||||||
|
{
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
public uint StartOffset { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppCustomAttributeTypeRange
|
||||||
|
{
|
||||||
|
[VersionCondition(GreaterThan = "24.1")]
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
|
||||||
|
public int Start { get; private set; }
|
||||||
|
public int Count { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using StringIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
using MethodIndex = int;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppEventDefinition
|
||||||
|
{
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
public TypeIndex TypeIndex { get; private set; }
|
||||||
|
public MethodIndex Add { get; private set; }
|
||||||
|
public MethodIndex Remove { get; private set; }
|
||||||
|
public MethodIndex Raise { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.0")]
|
||||||
|
public int CustomAttributeIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
|
||||||
|
public readonly bool IsValid => NameIndex != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using FieldIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
using DefaultValueDataIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppFieldDefaultValue
|
||||||
|
{
|
||||||
|
public FieldIndex FieldIndex { get; private set; }
|
||||||
|
public TypeIndex TypeIndex { get; private set; }
|
||||||
|
public DefaultValueDataIndex DataIndex { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
using StringIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppFieldDefinition
|
||||||
|
{
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
public TypeIndex TypeIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.0")]
|
||||||
|
public int CustomAttributeIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
|
||||||
|
public readonly bool IsValid => NameIndex != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
using FieldIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppFieldMarshaledSize
|
||||||
|
{
|
||||||
|
public FieldIndex FieldIndex { get; private set; }
|
||||||
|
public TypeIndex TypeIndex { get; private set; }
|
||||||
|
public int MarshaledSize { get; private set; }
|
||||||
|
}
|
||||||
13
Il2CppInspector.Common/Next/Metadata/Il2CppFieldRef.cs
Normal file
13
Il2CppInspector.Common/Next/Metadata/Il2CppFieldRef.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using FieldIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppFieldRef
|
||||||
|
{
|
||||||
|
public TypeIndex TypeIndex { get; private set; }
|
||||||
|
public FieldIndex FieldIndex { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
using GenericParameterIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppGenericContainer
|
||||||
|
{
|
||||||
|
public int OwnerIndex { get; private set; }
|
||||||
|
public int TypeArgc { get; private set; }
|
||||||
|
public int IsMethod { get; private set; }
|
||||||
|
public GenericParameterIndex GenericParameterStart { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using GenericContainerIndex = int;
|
||||||
|
using StringIndex = int;
|
||||||
|
using GenericParameterConstraintIndex = short;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppGenericParameter
|
||||||
|
{
|
||||||
|
public GenericContainerIndex OwnerIndex { get; private set; }
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
public GenericParameterConstraintIndex ConstraintsStart { get; private set; }
|
||||||
|
public short ConstraintsCount { get; private set; }
|
||||||
|
public ushort Num { get; private set; }
|
||||||
|
public ushort Flags { get; private set; }
|
||||||
|
|
||||||
|
public readonly GenericParameterAttributes Attributes => (GenericParameterAttributes)Flags;
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
// Unity 4.6.1p5 - first release, no global-metadata.dat
|
||||||
|
// Unity 5.2.0f3 -> v15
|
||||||
|
// Unity 5.3.0f4 -> v16
|
||||||
|
// Unity 5.3.2f1 -> v19
|
||||||
|
// Unity 5.3.3f1 -> v20
|
||||||
|
// Unity 5.3.5f1 -> v21
|
||||||
|
// Unity 5.5.0f3 -> v22
|
||||||
|
// Unity 5.6.0f3 -> v23
|
||||||
|
// Unity 2017.1.0f3 -> v24
|
||||||
|
// Unity 2018.3.0f2 -> v24.1
|
||||||
|
// Unity 2019.1.0f2 -> v24.2
|
||||||
|
// Unity 2019.3.7f1 -> v24.3
|
||||||
|
// Unity 2019.4.15f1 -> v24.4
|
||||||
|
// Unity 2019.4.21f1 -> v24.5
|
||||||
|
// Unity 2020.1.0f1 -> v24.3
|
||||||
|
// Unity 2020.1.11f1 -> v24.4
|
||||||
|
// Unity 2020.2.0f1 -> v27
|
||||||
|
// Unity 2020.2.4f1 -> v27.1
|
||||||
|
// Unity 2021.1.0f1 -> v27.2
|
||||||
|
// https://unity3d.com/get-unity/download/archive
|
||||||
|
// Metadata version is written at the end of Unity.IL2CPP.MetadataCacheWriter.WriteLibIl2CppMetadata or WriteMetadata (Unity.IL2CPP.dll)
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppGlobalMetadataHeader
|
||||||
|
{
|
||||||
|
public int Sanity { get; private set; }
|
||||||
|
public int Version { get; private set; }
|
||||||
|
public int StringLiteralOffset { get; private set; }
|
||||||
|
public int StringLiteralSize { get; private set; }
|
||||||
|
public int StringLiteralDataOffset { get; private set; }
|
||||||
|
public int StringLiteralDataSize { get; private set; }
|
||||||
|
public int StringOffset { get; private set; }
|
||||||
|
public int StringSize { get; private set; }
|
||||||
|
public int EventsOffset { get; private set; }
|
||||||
|
public int EventsSize { get; private set; }
|
||||||
|
public int PropertiesOffset { get; private set; }
|
||||||
|
public int PropertiesSize { get; private set; }
|
||||||
|
public int MethodsOffset { get; private set; }
|
||||||
|
public int MethodsSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
[VersionCondition(EqualTo = "16.0")]
|
||||||
|
public int ParameterDefaultValuesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
[VersionCondition(EqualTo = "16.0")]
|
||||||
|
public int ParameterDefaultValuesSize { get; private set; }
|
||||||
|
public int FieldDefaultValuesOffset { get; private set; }
|
||||||
|
public int FieldDefaultValuesSize { get; private set; }
|
||||||
|
public int FieldAndParameterDefaultValueDataOffset { get; private set; }
|
||||||
|
public int FieldAndParameterDefaultValueDataSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
public int FieldMarshaledSizesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
public int FieldMarshaledSizesSize { get; private set; }
|
||||||
|
public int ParametersOffset { get; private set; }
|
||||||
|
public int ParametersSize { get; private set; }
|
||||||
|
public int FieldsOffset { get; private set; }
|
||||||
|
public int FieldsSize { get; private set; }
|
||||||
|
public int GenericParametersOffset { get; private set; }
|
||||||
|
public int GenericParametersSize { get; private set; }
|
||||||
|
public int GenericParameterConstraintsOffset { get; private set; }
|
||||||
|
public int GenericParameterConstraintsSize { get; private set; }
|
||||||
|
public int GenericContainersOffset { get; private set; }
|
||||||
|
public int GenericContainersSize { get; private set; }
|
||||||
|
public int NestedTypesOffset { get; private set; }
|
||||||
|
public int NestedTypesSize { get; private set; }
|
||||||
|
public int InterfacesOffset { get; private set; }
|
||||||
|
public int InterfacesSize { get; private set; }
|
||||||
|
public int VTableMethodsOffset { get; private set; }
|
||||||
|
public int VTableMethodsSize { get; private set; }
|
||||||
|
public int InterfaceOffsetsOffset { get; private set; }
|
||||||
|
public int InterfaceOffsetsSize { get; private set; }
|
||||||
|
public int TypeDefinitionsOffset { get; private set; }
|
||||||
|
public int TypeDefinitionsSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int RgctxEntriesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int RgctxEntriesCount { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
public int ImagesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
public int ImagesSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
public int AssembliesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
public int AssembliesSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0", LessThan = "24.5")]
|
||||||
|
public int MetadataUsageListsOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0", LessThan = "24.5")]
|
||||||
|
public int MetadataUsageListsCount { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0", LessThan = "24.5")]
|
||||||
|
public int MetadataUsagePairsOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0", LessThan = "24.5")]
|
||||||
|
public int MetadataUsagePairsCount { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public int FieldRefsOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public int FieldRefsSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "20.0")]
|
||||||
|
public int ReferencedAssembliesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "20.0")]
|
||||||
|
public int ReferencedAssembliesSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "27.2")]
|
||||||
|
public int AttributesInfoOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "27.2")]
|
||||||
|
public int AttributesInfoCount { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "27.2")]
|
||||||
|
public int AttributesTypesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "27.2")]
|
||||||
|
public int AttributesTypesCount { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "29.0")]
|
||||||
|
public int AttributeDataOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "29.0")]
|
||||||
|
public int AttributeDataSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "29.0")]
|
||||||
|
public int AttributeDataRangeOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "29.0")]
|
||||||
|
public int AttributeDataRangeSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "22.0")]
|
||||||
|
public int UnresolvedIndirectCallParameterTypesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "22.0")]
|
||||||
|
public int UnresolvedIndirectCallParameterTypesSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "22.0")]
|
||||||
|
public int UnresolvedIndirectCallParameterRangesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "22.0")]
|
||||||
|
public int UnresolvedIndirectCallParameterRangesSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "23.0")]
|
||||||
|
public int WindowsRuntimeTypeNamesOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "23.0")]
|
||||||
|
public int WindowsRuntimeTypeNamesSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "27.0")]
|
||||||
|
public int WindowsRuntimeStringsOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "27.0")]
|
||||||
|
public int WindowsRuntimeStringsSize { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "24.0")]
|
||||||
|
public int ExportedTypeDefinitionsOffset { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "24.0")]
|
||||||
|
public int ExportedTypeDefinitionsSize { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
public const int ExpectedSanity = unchecked((int)0xFAB11BAF);
|
||||||
|
public readonly bool SanityValid => Sanity == ExpectedSanity;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using StringIndex = int;
|
||||||
|
using AssemblyIndex = int;
|
||||||
|
using TypeDefinitionIndex = int;
|
||||||
|
using MethodIndex = int;
|
||||||
|
using CustomAttributeIndex = int;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppImageDefinition
|
||||||
|
{
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
public AssemblyIndex AssemblyIndex { get; private set; }
|
||||||
|
|
||||||
|
public TypeDefinitionIndex TypeStart { get; private set; }
|
||||||
|
public uint TypeCount { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "24.0")]
|
||||||
|
public TypeDefinitionIndex ExportedTypeStart { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "24.0")]
|
||||||
|
public uint ExportedTypeCount { get; private set; }
|
||||||
|
|
||||||
|
public MethodIndex EntryPointIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "24.1")]
|
||||||
|
public CustomAttributeIndex CustomAttributeStart { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "24.1")]
|
||||||
|
public uint CustomAttributeCount { get; private set; }
|
||||||
|
|
||||||
|
public readonly bool IsValid => NameIndex != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using TypeIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppInterfaceOffsetPair
|
||||||
|
{
|
||||||
|
public TypeIndex InterfaceTypeIndex { get; private set; }
|
||||||
|
public int Offset { get; private set; }
|
||||||
|
}
|
||||||
10
Il2CppInspector.Common/Next/Metadata/Il2CppMetadataRange.cs
Normal file
10
Il2CppInspector.Common/Next/Metadata/Il2CppMetadataRange.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppMetadataRange
|
||||||
|
{
|
||||||
|
public int Start { get; private set; }
|
||||||
|
public int Length { get; private set; }
|
||||||
|
}
|
||||||
64
Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsage.cs
Normal file
64
Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsage.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
using EncodedMethodIndex = uint;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppMetadataUsage
|
||||||
|
{
|
||||||
|
private const uint TypeMask = 0b111u << 29;
|
||||||
|
private const uint InflatedMask = 0b1;
|
||||||
|
private const uint IndexMask = ~(TypeMask | InflatedMask);
|
||||||
|
|
||||||
|
public readonly Il2CppMetadataUsageType Type => (Il2CppMetadataUsageType)((EncodedValue & TypeMask) >> 29);
|
||||||
|
public readonly uint Index => (EncodedValue & IndexMask) >> 1;
|
||||||
|
public readonly bool Inflated => (EncodedValue & InflatedMask) == 1;
|
||||||
|
|
||||||
|
public EncodedMethodIndex EncodedValue;
|
||||||
|
|
||||||
|
public static Il2CppMetadataUsage FromValue(in StructVersion version, uint encodedValue)
|
||||||
|
{
|
||||||
|
if (version >= MetadataVersions.V270)
|
||||||
|
{
|
||||||
|
return new Il2CppMetadataUsage
|
||||||
|
{
|
||||||
|
EncodedValue = encodedValue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version >= MetadataVersions.V190)
|
||||||
|
{
|
||||||
|
// Below v27 we need to fake the 'inflated' flag, so shift the value by one
|
||||||
|
|
||||||
|
var type = (encodedValue & TypeMask) >> 29;
|
||||||
|
var value = encodedValue & (IndexMask | 1);
|
||||||
|
Debug.Assert((value & 0x10000000) == 0);
|
||||||
|
|
||||||
|
return new Il2CppMetadataUsage
|
||||||
|
{
|
||||||
|
EncodedValue = (type << 29) | (value << 1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */
|
||||||
|
var methodType = (encodedValue >> 31) != 0
|
||||||
|
? Il2CppMetadataUsageType.MethodRef
|
||||||
|
: Il2CppMetadataUsageType.MethodDef;
|
||||||
|
|
||||||
|
var index = encodedValue & 0x7FFFFFFF;
|
||||||
|
Debug.Assert((index & 0x60000000) == 0);
|
||||||
|
|
||||||
|
return new Il2CppMetadataUsage
|
||||||
|
{
|
||||||
|
EncodedValue = ((uint)methodType << 29) | (index << 1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Type} @ 0x{Index:X}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppMetadataUsageList
|
||||||
|
{
|
||||||
|
public int Start { get; private set; }
|
||||||
|
public int Count { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppMetadataUsagePair
|
||||||
|
{
|
||||||
|
public uint DestinationIndex { get; private set; }
|
||||||
|
public uint EncodedSourceIndex { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
public enum Il2CppMetadataUsageType
|
||||||
|
{
|
||||||
|
Invalid = 0b000,
|
||||||
|
TypeInfo = 0b001,
|
||||||
|
Il2CppType = 0b010,
|
||||||
|
MethodDef = 0b011,
|
||||||
|
FieldInfo = 0b100,
|
||||||
|
StringLiteral = 0b101,
|
||||||
|
MethodRef = 0b110,
|
||||||
|
FieldRva = 0b111,
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using StringIndex = int;
|
||||||
|
using TypeDefinitionIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
using ParameterIndex = int;
|
||||||
|
using GenericContainerIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppMethodDefinition
|
||||||
|
{
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "16.0")]
|
||||||
|
public TypeDefinitionIndex DeclaringType { get; private set; }
|
||||||
|
public TypeIndex ReturnType { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(EqualTo = "31.0")]
|
||||||
|
public uint ReturnParameterToken { get; private set; }
|
||||||
|
|
||||||
|
public ParameterIndex ParameterStart { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.0")]
|
||||||
|
public int CustomAttributeIndex { get; private set; }
|
||||||
|
|
||||||
|
public GenericContainerIndex GenericContainerIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int MethodIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int InvokerIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int ReversePInvokeWrapperIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int RgctxStartIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int RgctxCount { get; private set; }
|
||||||
|
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
public ushort Flags { get; private set; }
|
||||||
|
public ushort ImplFlags { get; private set; }
|
||||||
|
public ushort Slot { get; private set; }
|
||||||
|
public ushort ParameterCount { get; private set; }
|
||||||
|
|
||||||
|
public readonly MethodAttributes Attributes => (MethodAttributes)Flags;
|
||||||
|
public readonly MethodImplAttributes ImplAttributes => (MethodImplAttributes)ImplFlags;
|
||||||
|
|
||||||
|
public readonly bool IsValid => NameIndex != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using ParameterIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
using DefaultValueDataIndex = int;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppParameterDefaultValue
|
||||||
|
{
|
||||||
|
public ParameterIndex ParameterIndex { get; private set; }
|
||||||
|
public TypeIndex TypeIndex { get; private set; }
|
||||||
|
public DefaultValueDataIndex DataIndex { get; private set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
using StringIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppParameterDefinition
|
||||||
|
{
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.0")]
|
||||||
|
public int CustomAttributeIndex { get; private set; }
|
||||||
|
|
||||||
|
public TypeIndex TypeIndex { get; private set; }
|
||||||
|
|
||||||
|
public readonly bool IsValid => NameIndex != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using StringIndex = int;
|
||||||
|
using MethodIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppPropertyDefinition
|
||||||
|
{
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
public MethodIndex Get { get; private set; }
|
||||||
|
public MethodIndex Set { get; private set; }
|
||||||
|
public PropertyAttributes Attrs { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.0")]
|
||||||
|
public int CustomAttributeIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
|
||||||
|
public readonly bool IsValid => NameIndex != 0;
|
||||||
|
}
|
||||||
11
Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs
Normal file
11
Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
using StringLiteralIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppStringLiteral
|
||||||
|
{
|
||||||
|
public uint Length { get; private set; }
|
||||||
|
public StringLiteralIndex DataIndex { get; private set; }
|
||||||
|
}
|
||||||
83
Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs
Normal file
83
Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using StringIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
using GenericContainerIndex = int;
|
||||||
|
using FieldIndex = int;
|
||||||
|
using MethodIndex = int;
|
||||||
|
using EventIndex = int;
|
||||||
|
using PropertyIndex = int;
|
||||||
|
using NestedTypeIndex = int;
|
||||||
|
using InterfacesIndex = int;
|
||||||
|
using VTableIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppTypeDefinition
|
||||||
|
{
|
||||||
|
public const TypeIndex InvalidTypeIndex = -1;
|
||||||
|
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
public StringIndex NamespaceIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.0")]
|
||||||
|
public int CustomAttributeIndex { get; private set; }
|
||||||
|
|
||||||
|
public TypeIndex ByValTypeIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.5")]
|
||||||
|
public TypeIndex ByRefTypeIndex { get; private set; }
|
||||||
|
|
||||||
|
public TypeIndex DeclaringTypeIndex { get; private set; }
|
||||||
|
public TypeIndex ParentIndex { get; private set; }
|
||||||
|
public TypeIndex ElementTypeIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int RgctxStartIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "24.1")]
|
||||||
|
public int RgctxCount { get; private set; }
|
||||||
|
|
||||||
|
public GenericContainerIndex GenericContainerIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "22.0")]
|
||||||
|
public int ReversePInvokeWrapperIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(LessThan = "22.0")]
|
||||||
|
public int MarshalingFunctionsIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "22.0")]
|
||||||
|
public int CcwFunctionIndex { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "21.0", LessThan = "22.0")]
|
||||||
|
public int GuidIndex { get; private set; }
|
||||||
|
|
||||||
|
public TypeAttributes Flags { get; private set; }
|
||||||
|
|
||||||
|
public FieldIndex FieldIndex { get; private set; }
|
||||||
|
public MethodIndex MethodIndex { get; private set; }
|
||||||
|
public EventIndex EventIndex { get; private set; }
|
||||||
|
public PropertyIndex PropertyIndex { get; private set; }
|
||||||
|
public NestedTypeIndex NestedTypeIndex { get; private set; }
|
||||||
|
public InterfacesIndex InterfacesIndex { get; private set; }
|
||||||
|
public VTableIndex VTableIndex { get; private set; }
|
||||||
|
public InterfacesIndex InterfaceOffsetsStart { get; private set; }
|
||||||
|
|
||||||
|
public ushort MethodCount { get; private set; }
|
||||||
|
public ushort PropertyCount { get; private set; }
|
||||||
|
public ushort FieldCount { get; private set; }
|
||||||
|
public ushort EventCount { get; private set; }
|
||||||
|
public ushort NestedTypeCount { get; private set; }
|
||||||
|
public ushort VTableCount { get; private set; }
|
||||||
|
public ushort InterfacesCount { get; private set; }
|
||||||
|
public ushort InterfaceOffsetsCount { get; private set; }
|
||||||
|
|
||||||
|
public Il2CppTypeDefinitionBitfield Bitfield { get; private set; }
|
||||||
|
|
||||||
|
[VersionCondition(GreaterThan = "19.0")]
|
||||||
|
public uint Token { get; private set; }
|
||||||
|
|
||||||
|
public readonly bool IsValid => NameIndex != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppTypeDefinitionBitfield
|
||||||
|
{
|
||||||
|
private uint _value;
|
||||||
|
|
||||||
|
public bool ValueType => ((_value >> 0) & 1) == 1;
|
||||||
|
public bool EnumType => ((_value >> 1) & 1) == 1;
|
||||||
|
public bool HasFinalize => ((_value >> 2) & 1) == 1;
|
||||||
|
public bool HasCctor => ((_value >> 3) & 1) == 1;
|
||||||
|
public bool IsBlittable => ((_value >> 4) & 1) == 1;
|
||||||
|
public bool IsImportOrWindowsRuntime => ((_value >> 5) & 1) == 1;
|
||||||
|
public PackingSize PackingSize => (PackingSize)((_value >> 6) & 0b1111);
|
||||||
|
public bool DefaultPackingSize => ((_value >> 10) & 1) == 1;
|
||||||
|
public bool DefaultClassSize => ((_value >> 11) & 1) == 1;
|
||||||
|
public PackingSize ClassSize => (PackingSize)((_value >> 12) & 0b1111);
|
||||||
|
public bool IsByRefLike => ((_value >> 13) & 1) == 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
using StringIndex = int;
|
||||||
|
using TypeIndex = int;
|
||||||
|
|
||||||
|
[VersionedStruct]
|
||||||
|
public partial record struct Il2CppWindowsRuntimeTypeNamePair
|
||||||
|
{
|
||||||
|
public StringIndex NameIndex { get; private set; }
|
||||||
|
public TypeIndex TypeIndex { get; private set; }
|
||||||
|
}
|
||||||
14
Il2CppInspector.Common/Next/Metadata/PackingSize.cs
Normal file
14
Il2CppInspector.Common/Next/Metadata/PackingSize.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
|
public enum PackingSize
|
||||||
|
{
|
||||||
|
Zero,
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
Four,
|
||||||
|
Eight,
|
||||||
|
Sixteen,
|
||||||
|
ThirtyTwo,
|
||||||
|
SixtyFour,
|
||||||
|
OneHundredTwentyEight
|
||||||
|
}
|
||||||
31
Il2CppInspector.Common/Next/MetadataVersions.cs
Normal file
31
Il2CppInspector.Common/Next/MetadataVersions.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using VersionedSerialization;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next;
|
||||||
|
|
||||||
|
public static class MetadataVersions
|
||||||
|
{
|
||||||
|
public static readonly StructVersion V160 = new(16);
|
||||||
|
|
||||||
|
public static readonly StructVersion V190 = new(19);
|
||||||
|
|
||||||
|
public static readonly StructVersion V210 = new(21);
|
||||||
|
public static readonly StructVersion V220 = new(22);
|
||||||
|
|
||||||
|
public static readonly StructVersion V240 = new(24);
|
||||||
|
public static readonly StructVersion V241 = new(24, 1);
|
||||||
|
public static readonly StructVersion V242 = new(24, 2);
|
||||||
|
public static readonly StructVersion V243 = new(24, 3);
|
||||||
|
public static readonly StructVersion V244 = new(24, 4);
|
||||||
|
public static readonly StructVersion V245 = new(24, 5);
|
||||||
|
|
||||||
|
public static readonly StructVersion V270 = new(27);
|
||||||
|
public static readonly StructVersion V271 = new(27, 1);
|
||||||
|
public static readonly StructVersion V272 = new(27, 2);
|
||||||
|
|
||||||
|
// These two versions have two variations:
|
||||||
|
public static readonly StructVersion V290 = new(29);
|
||||||
|
public static readonly StructVersion V310 = new(31);
|
||||||
|
|
||||||
|
// No tag - 29.0/31.0
|
||||||
|
public static readonly string Tag2022 = "2022"; // 29.1/31.1
|
||||||
|
}
|
||||||
60
Il2CppInspector.Common/Next/Pointer.cs
Normal file
60
Il2CppInspector.Common/Next/Pointer.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using VersionedSerialization;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next;
|
||||||
|
|
||||||
|
public struct Pointer<T>(ulong value = 0) : IReadable, IEquatable<Pointer<T>> where T : struct, IReadable
|
||||||
|
{
|
||||||
|
[NativeInteger]
|
||||||
|
private ulong _value = value;
|
||||||
|
|
||||||
|
public readonly ulong PointerValue => _value;
|
||||||
|
public readonly bool Null => _value == 0;
|
||||||
|
|
||||||
|
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
|
||||||
|
{
|
||||||
|
_value = reader.ReadNUInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Size(in StructVersion version = default, bool is32Bit = false)
|
||||||
|
{
|
||||||
|
return is32Bit ? 4 : 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly T Read(ref SpanReader reader, in StructVersion version)
|
||||||
|
{
|
||||||
|
reader.Offset = (int)PointerValue;
|
||||||
|
return reader.ReadVersionedObject<T>(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly ImmutableArray<T> ReadArray(ref SpanReader reader, long count, in StructVersion version)
|
||||||
|
{
|
||||||
|
reader.Offset = (int)PointerValue;
|
||||||
|
return reader.ReadVersionedObjectArray<T>(count, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Pointer<T>(ulong value) => new(value);
|
||||||
|
public static implicit operator ulong(Pointer<T> ptr) => ptr.PointerValue;
|
||||||
|
|
||||||
|
#region Equality operators + ToString
|
||||||
|
|
||||||
|
public static bool operator ==(Pointer<T> left, Pointer<T> right)
|
||||||
|
=> left._value == right._value;
|
||||||
|
|
||||||
|
public static bool operator !=(Pointer<T> left, Pointer<T> right)
|
||||||
|
=> !(left == right);
|
||||||
|
|
||||||
|
public readonly override bool Equals(object? obj)
|
||||||
|
=> obj is Pointer<T> other && Equals(other);
|
||||||
|
|
||||||
|
public readonly bool Equals(Pointer<T> other)
|
||||||
|
=> this == other;
|
||||||
|
|
||||||
|
public readonly override int GetHashCode()
|
||||||
|
=> HashCode.Combine(_value);
|
||||||
|
|
||||||
|
public readonly override string ToString() => $"0x{_value:X} <{typeof(T).Name}>";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
60
Il2CppInspector.Common/Next/PrimitivePointer.cs
Normal file
60
Il2CppInspector.Common/Next/PrimitivePointer.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using VersionedSerialization;
|
||||||
|
using VersionedSerialization.Attributes;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Next;
|
||||||
|
|
||||||
|
public struct PrimitivePointer<T>(ulong value = 0) : IReadable, IEquatable<PrimitivePointer<T>> where T : unmanaged
|
||||||
|
{
|
||||||
|
[NativeInteger]
|
||||||
|
private ulong _value = value;
|
||||||
|
|
||||||
|
public readonly ulong PointerValue => _value;
|
||||||
|
public readonly bool Null => _value == 0;
|
||||||
|
|
||||||
|
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
|
||||||
|
{
|
||||||
|
_value = reader.ReadNUInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Size(in StructVersion version = default, bool is32Bit = false)
|
||||||
|
{
|
||||||
|
return is32Bit ? 4 : 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly T Read(ref SpanReader reader)
|
||||||
|
{
|
||||||
|
reader.Offset = (int)PointerValue;
|
||||||
|
return reader.ReadPrimitive<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly ImmutableArray<T> ReadArray(ref SpanReader reader, long count)
|
||||||
|
{
|
||||||
|
reader.Offset = (int)PointerValue;
|
||||||
|
return reader.ReadPrimitiveArray<T>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator PrimitivePointer<T>(ulong value) => new(value);
|
||||||
|
public static implicit operator ulong(PrimitivePointer<T> ptr) => ptr.PointerValue;
|
||||||
|
|
||||||
|
#region Equality operators + ToString
|
||||||
|
|
||||||
|
public static bool operator ==(PrimitivePointer<T> left, PrimitivePointer<T> right)
|
||||||
|
=> left._value == right._value;
|
||||||
|
|
||||||
|
public static bool operator !=(PrimitivePointer<T> left, PrimitivePointer<T> right)
|
||||||
|
=> !(left == right);
|
||||||
|
|
||||||
|
public readonly override bool Equals(object? obj)
|
||||||
|
=> obj is PrimitivePointer<T> other && Equals(other);
|
||||||
|
|
||||||
|
public readonly bool Equals(PrimitivePointer<T> other)
|
||||||
|
=> this == other;
|
||||||
|
|
||||||
|
public readonly override int GetHashCode()
|
||||||
|
=> HashCode.Combine(_value);
|
||||||
|
|
||||||
|
public readonly override string ToString() => $"0x{_value:X} <{typeof(T).Name}>";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
using dnlib.DotNet.Emit;
|
using dnlib.DotNet.Emit;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using Il2CppInspector.Reflection;
|
using Il2CppInspector.Reflection;
|
||||||
|
|
||||||
namespace Il2CppInspector.Outputs
|
namespace Il2CppInspector.Outputs
|
||||||
@@ -186,7 +187,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (mType.IsExplicitLayout || mType.IsSequentialLayout)
|
if (mType.IsExplicitLayout || mType.IsSequentialLayout)
|
||||||
mType.ClassLayout = new ClassLayoutUser(1, (uint)type.Sizes.nativeSize);
|
mType.ClassLayout = new ClassLayoutUser(1, (uint)type.Sizes.NativeSize);
|
||||||
|
|
||||||
// Add nested types
|
// Add nested types
|
||||||
foreach (var nestedType in type.DeclaredNestedTypes)
|
foreach (var nestedType in type.DeclaredNestedTypes)
|
||||||
@@ -241,7 +242,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
AddMethod(module, mType, method);
|
AddMethod(module, mType, method);
|
||||||
|
|
||||||
// Add token attribute
|
// Add token attribute
|
||||||
if (type.Definition != null)
|
if (type.Definition.IsValid)
|
||||||
mType.AddAttribute(module, tokenAttribute, ("Token", $"0x{type.MetadataToken:X8}"));
|
mType.AddAttribute(module, tokenAttribute, ("Token", $"0x{type.MetadataToken:X8}"));
|
||||||
|
|
||||||
// Add custom attribute attributes
|
// Add custom attribute attributes
|
||||||
@@ -269,7 +270,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
if (field.HasFieldRVA) {
|
if (field.HasFieldRVA) {
|
||||||
// Attempt to get field size
|
// Attempt to get field size
|
||||||
|
|
||||||
var fieldSize = field.FieldType.Sizes.nativeSize;
|
var fieldSize = field.FieldType.Sizes.NativeSize;
|
||||||
var preview = model.Package.Metadata.ReadBytes((long) field.DefaultValueMetadataAddress, fieldSize);
|
var preview = model.Package.Metadata.ReadBytes((long) field.DefaultValueMetadataAddress, fieldSize);
|
||||||
|
|
||||||
mField.InitialValue = preview;
|
mField.InitialValue = preview;
|
||||||
@@ -310,7 +311,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
|
|
||||||
// Add token attribute
|
// Add token attribute
|
||||||
// Generic properties and constructed properties (from disperate get/set methods) have no definition
|
// Generic properties and constructed properties (from disperate get/set methods) have no definition
|
||||||
if (prop.Definition != null)
|
if (prop.Definition.IsValid)
|
||||||
mProp.AddAttribute(module, tokenAttribute, ("Token", $"0x{prop.MetadataToken:X8}"));
|
mProp.AddAttribute(module, tokenAttribute, ("Token", $"0x{prop.MetadataToken:X8}"));
|
||||||
|
|
||||||
// Add custom attribute attributes
|
// Add custom attribute attributes
|
||||||
@@ -432,8 +433,8 @@ namespace Il2CppInspector.Outputs
|
|||||||
("Offset", string.Format("0x{0:X}", model.Package.BinaryImage.MapVATR(method.VirtualAddress.Value.Start))),
|
("Offset", string.Format("0x{0:X}", model.Package.BinaryImage.MapVATR(method.VirtualAddress.Value.Start))),
|
||||||
("VA", method.VirtualAddress.Value.Start.ToAddressString())
|
("VA", method.VirtualAddress.Value.Start.ToAddressString())
|
||||||
};
|
};
|
||||||
if (method.Definition.slot != ushort.MaxValue)
|
if (method.Definition.Slot != ushort.MaxValue)
|
||||||
args.Add(("Slot", method.Definition.slot.ToString()));
|
args.Add(("Slot", method.Definition.Slot.ToString()));
|
||||||
|
|
||||||
mMethod.AddAttribute(module, addressAttribute, args.ToArray());
|
mMethod.AddAttribute(module, addressAttribute, args.ToArray());
|
||||||
}
|
}
|
||||||
@@ -591,7 +592,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
// Create folder for DLLs
|
// Create folder for DLLs
|
||||||
Directory.CreateDirectory(outputPath);
|
Directory.CreateDirectory(outputPath);
|
||||||
|
|
||||||
if (model.Package.Version >= 29)
|
if (model.Package.Version >= MetadataVersions.V290)
|
||||||
{
|
{
|
||||||
// We can now apply all attributes directly.
|
// We can now apply all attributes directly.
|
||||||
directApplyAttributes = model.TypesByDefinitionIndex
|
directApplyAttributes = model.TypesByDefinitionIndex
|
||||||
@@ -648,7 +649,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
AddCustomAttribute(module, module.Assembly, ca);
|
AddCustomAttribute(module, module.Assembly, ca);
|
||||||
|
|
||||||
// Add token attributes
|
// Add token attributes
|
||||||
module.AddAttribute(module, tokenAttribute, ("Token", $"0x{asm.ImageDefinition.token:X8}"));
|
module.AddAttribute(module, tokenAttribute, ("Token", $"0x{asm.ImageDefinition.Token:X8}"));
|
||||||
module.Assembly.AddAttribute(module, tokenAttribute, ("Token", $"0x{asm.MetadataToken:X8}"));
|
module.Assembly.AddAttribute(module, tokenAttribute, ("Token", $"0x{asm.MetadataToken:X8}"));
|
||||||
|
|
||||||
if (types.TryGetValue(module, out var shallowTypes))
|
if (types.TryGetValue(module, out var shallowTypes))
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
foreach (var asm in assemblies) {
|
foreach (var asm in assemblies) {
|
||||||
text.Append($"// Image {asm.Index}: {asm.ShortName} - Assembly: {asm.FullName}");
|
text.Append($"// Image {asm.Index}: {asm.ShortName} - Assembly: {asm.FullName}");
|
||||||
if (!SuppressMetadata)
|
if (!SuppressMetadata)
|
||||||
text.Append($" - Types {asm.ImageDefinition.typeStart}-{asm.ImageDefinition.typeStart + asm.ImageDefinition.typeCount - 1}");
|
text.Append($" - Types {asm.ImageDefinition.TypeStart}-{asm.ImageDefinition.TypeStart + asm.ImageDefinition.TypeCount - 1}");
|
||||||
text.AppendLine();
|
text.AppendLine();
|
||||||
|
|
||||||
// Assembly-level attributes
|
// Assembly-level attributes
|
||||||
@@ -426,7 +426,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
sb.Append($" // Metadata: {field.DefaultValueMetadataAddress.ToAddressString()}");
|
sb.Append($" // Metadata: {field.DefaultValueMetadataAddress.ToAddressString()}");
|
||||||
// For static array initializers, output metadata address and preview
|
// For static array initializers, output metadata address and preview
|
||||||
if (field.HasFieldRVA && !SuppressMetadata) {
|
if (field.HasFieldRVA && !SuppressMetadata) {
|
||||||
var preview = model.Package.Metadata.ReadBytes((long) field.DefaultValueMetadataAddress, field.FieldType.Sizes.nativeSize);
|
var preview = model.Package.Metadata.ReadBytes((long) field.DefaultValueMetadataAddress, field.FieldType.Sizes.NativeSize);
|
||||||
sb.Append($" // Static value (base64): {Convert.ToBase64String(preview)} - Metadata: {field.DefaultValueMetadataAddress.ToAddressString()}");
|
sb.Append($" // Static value (base64): {Convert.ToBase64String(preview)} - Metadata: {field.DefaultValueMetadataAddress.ToAddressString()}");
|
||||||
}
|
}
|
||||||
sb.Append("\n");
|
sb.Append("\n");
|
||||||
|
|||||||
@@ -38,14 +38,15 @@ namespace Il2CppInspector.Outputs
|
|||||||
using var fs = new FileStream(typeHeaderFile, FileMode.Create);
|
using var fs = new FileStream(typeHeaderFile, FileMode.Create);
|
||||||
_writer = new StreamWriter(fs, Encoding.ASCII);
|
_writer = new StreamWriter(fs, Encoding.ASCII);
|
||||||
|
|
||||||
const string decompilerIfDef = "#if !defined(_GHIDRA_) && !defined(_IDA_) && !defined(_IDACLANG_)";
|
|
||||||
|
|
||||||
using (_writer)
|
using (_writer)
|
||||||
{
|
{
|
||||||
writeHeader();
|
writeHeader();
|
||||||
|
|
||||||
// Write primitive type definitions for when we're not including other headers
|
// Write primitive type definitions for when we're not including other headers
|
||||||
writeCode($"""
|
writeCode($"""
|
||||||
|
#define IS_LIBCLANG_DECOMPILER (defined(_IDACLANG_) || defined(_BINARYNINJA_))
|
||||||
|
#define IS_DECOMPILER (defined(_GHIDRA_) || defined(_IDA_) || IS_LIBCLANG_DECOMPILER)
|
||||||
|
|
||||||
#if defined(_GHIDRA_) || defined(_IDA_)
|
#if defined(_GHIDRA_) || defined(_IDA_)
|
||||||
typedef unsigned __int8 uint8_t;
|
typedef unsigned __int8 uint8_t;
|
||||||
typedef unsigned __int16 uint16_t;
|
typedef unsigned __int16 uint16_t;
|
||||||
@@ -57,7 +58,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
typedef __int64 int64_t;
|
typedef __int64 int64_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _IDACLANG_
|
#if IS_LIBCLANG_DECOMPILER
|
||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
typedef unsigned short uint16_t;
|
typedef unsigned short uint16_t;
|
||||||
typedef unsigned int uint32_t;
|
typedef unsigned int uint32_t;
|
||||||
@@ -68,13 +69,13 @@ namespace Il2CppInspector.Outputs
|
|||||||
typedef long int64_t;
|
typedef long int64_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_GHIDRA_) || defined(_IDACLANG_)
|
#if defined(_GHIDRA_) || IS_LIBCLANG_DECOMPILER
|
||||||
typedef int{_model.Package.BinaryImage.Bits}_t intptr_t;
|
typedef int{_model.Package.BinaryImage.Bits}_t intptr_t;
|
||||||
typedef uint{_model.Package.BinaryImage.Bits}_t uintptr_t;
|
typedef uint{_model.Package.BinaryImage.Bits}_t uintptr_t;
|
||||||
typedef uint{_model.Package.BinaryImage.Bits}_t size_t;
|
typedef uint{_model.Package.BinaryImage.Bits}_t size_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{decompilerIfDef}
|
#if !IS_DECOMPILER
|
||||||
#define _CPLUSPLUS_
|
#define _CPLUSPLUS_
|
||||||
#endif
|
#endif
|
||||||
""");
|
""");
|
||||||
@@ -114,7 +115,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
}
|
}
|
||||||
|
|
||||||
// C does not support namespaces
|
// C does not support namespaces
|
||||||
writeCode($"{decompilerIfDef}");
|
writeCode("#if !IS_DECOMPILER");
|
||||||
writeCode("namespace app {");
|
writeCode("namespace app {");
|
||||||
writeCode("#endif");
|
writeCode("#endif");
|
||||||
writeLine("");
|
writeLine("");
|
||||||
@@ -124,7 +125,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
writeTypesForGroup("Application types from usages", "types_from_usages");
|
writeTypesForGroup("Application types from usages", "types_from_usages");
|
||||||
writeTypesForGroup("Application unused value types", "unused_concrete_types");
|
writeTypesForGroup("Application unused value types", "unused_concrete_types");
|
||||||
|
|
||||||
writeCode($"{decompilerIfDef}");
|
writeCode("#if !IS_DECOMPILER");
|
||||||
writeCode("}");
|
writeCode("}");
|
||||||
writeCode("#endif");
|
writeCode("#endif");
|
||||||
}
|
}
|
||||||
@@ -248,7 +249,7 @@ namespace Il2CppInspector.Outputs
|
|||||||
using (_writer)
|
using (_writer)
|
||||||
{
|
{
|
||||||
writeHeader();
|
writeHeader();
|
||||||
writeCode($"#define __IL2CPP_METADATA_VERSION {_model.Package.Version * 10:F0}");
|
writeCode($"#define __IL2CPP_METADATA_VERSION {_model.Package.Version.Major * 10 + _model.Package.Version.Minor * 10:F0}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write boilerplate code
|
// Write boilerplate code
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.IO;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Il2CppInspector.Reflection;
|
using Il2CppInspector.Reflection;
|
||||||
using Il2CppInspector.Model;
|
using Il2CppInspector.Model;
|
||||||
|
using Il2CppInspector.Next;
|
||||||
|
|
||||||
namespace Il2CppInspector.Outputs
|
namespace Il2CppInspector.Outputs
|
||||||
{
|
{
|
||||||
@@ -182,8 +183,8 @@ namespace Il2CppInspector.Outputs
|
|||||||
|
|
||||||
// TODO: In the future, add data ranges for the entire IL2CPP metadata tree
|
// TODO: In the future, add data ranges for the entire IL2CPP metadata tree
|
||||||
writeArray("arrayMetadata", () => {
|
writeArray("arrayMetadata", () => {
|
||||||
if (model.Package.Version >= 24.2) {
|
if (model.Package.Version >= MetadataVersions.V242) {
|
||||||
writeObject(() => writeTypedArray(binary.CodeRegistration.pcodeGenModules, binary.Modules.Count, "struct Il2CppCodeGenModule *", "g_CodeGenModules"));
|
writeObject(() => writeTypedArray(binary.CodeRegistration.CodeGenModules, binary.Modules.Count, "struct Il2CppCodeGenModule *", "g_CodeGenModules"));
|
||||||
}
|
}
|
||||||
}, "IL2CPP Array Metadata");
|
}, "IL2CPP Array Metadata");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ namespace Il2CppInspector.Outputs
|
|||||||
public static IEnumerable<string> GetAvailableTargets() {
|
public static IEnumerable<string> GetAvailableTargets() {
|
||||||
var ns = typeof(PythonScript).Namespace + ".ScriptResources.Targets";
|
var ns = typeof(PythonScript).Namespace + ".ScriptResources.Targets";
|
||||||
var res = ResourceHelper.GetNamesForNamespace(ns);
|
var res = ResourceHelper.GetNamesForNamespace(ns);
|
||||||
return res.Select(s => Path.GetFileNameWithoutExtension(s.Substring(ns.Length + 1))).OrderBy(s => s);
|
return res
|
||||||
|
.Select(s => Path.GetFileNameWithoutExtension(s[(ns.Length + 1)..]))
|
||||||
|
.OrderBy(s => s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output script file
|
// Output script file
|
||||||
@@ -52,12 +54,11 @@ namespace Il2CppInspector.Outputs
|
|||||||
|
|
||||||
var jsonMetadataRelativePath = getRelativePath(outputFile, jsonMetadataFile);
|
var jsonMetadataRelativePath = getRelativePath(outputFile, jsonMetadataFile);
|
||||||
|
|
||||||
var ns = typeof(PythonScript).Namespace + ".ScriptResources";
|
var ns = $"{typeof(PythonScript).Namespace}.ScriptResources";
|
||||||
var preamble = ResourceHelper.GetText(ns + ".shared-preamble.py");
|
var baseScipt = ResourceHelper.GetText($"{ns}.shared_base.py");
|
||||||
var main = ResourceHelper.GetText(ns + ".shared-main.py");
|
var impl = ResourceHelper.GetText($"{ns}.Targets.{target}.py");
|
||||||
var api = ResourceHelper.GetText($"{ns}.Targets.{target}.py");
|
|
||||||
|
|
||||||
var script = string.Join("\n", new [] { preamble, api, main })
|
var script = string.Join("\n", baseScipt, impl)
|
||||||
.Replace("%SCRIPTFILENAME%", Path.GetFileName(outputFile))
|
.Replace("%SCRIPTFILENAME%", Path.GetFileName(outputFile))
|
||||||
.Replace("%TYPE_HEADER_RELATIVE_PATH%", typeHeaderRelativePath.ToEscapedString())
|
.Replace("%TYPE_HEADER_RELATIVE_PATH%", typeHeaderRelativePath.ToEscapedString())
|
||||||
.Replace("%JSON_METADATA_RELATIVE_PATH%", jsonMetadataRelativePath.ToEscapedString())
|
.Replace("%JSON_METADATA_RELATIVE_PATH%", jsonMetadataRelativePath.ToEscapedString())
|
||||||
|
|||||||
@@ -0,0 +1,284 @@
|
|||||||
|
from binaryninja import *
|
||||||
|
|
||||||
|
#try:
|
||||||
|
# from typing import TYPE_CHECKING
|
||||||
|
# if TYPE_CHECKING:
|
||||||
|
# from ..shared_base import BaseStatusHandler, BaseDisassemblerInterface, ScriptContext
|
||||||
|
# import json
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# from datetime import datetime
|
||||||
|
#except:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
||||||
|
# this is implemented,
|
||||||
|
# however the write API does not seem to work properly here (possibly a bug),
|
||||||
|
# so this is disabled for now
|
||||||
|
supports_fake_string_segment: bool = False
|
||||||
|
|
||||||
|
_status: BaseStatusHandler
|
||||||
|
|
||||||
|
_view: BinaryView
|
||||||
|
_undo_id: str
|
||||||
|
_components: dict[str, Component]
|
||||||
|
_type_cache: dict[str, Type]
|
||||||
|
_function_type_cache: dict[str, Type]
|
||||||
|
|
||||||
|
_address_size: int
|
||||||
|
_endianness: Literal["little", "big"]
|
||||||
|
|
||||||
|
def __init__(self, status: BaseStatusHandler):
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
def _get_or_create_type(self, type: str) -> Type:
|
||||||
|
if type.startswith("struct "):
|
||||||
|
type = type[len("struct "):]
|
||||||
|
elif type.startswith("class "):
|
||||||
|
type = type[len("class "):]
|
||||||
|
|
||||||
|
if type in self._type_cache:
|
||||||
|
return self._type_cache[type]
|
||||||
|
|
||||||
|
if type.endswith("*"):
|
||||||
|
base_type = self._get_or_create_type(type[:-1].strip())
|
||||||
|
|
||||||
|
parsed = PointerType.create(self._view.arch, base_type) # type: ignore
|
||||||
|
else:
|
||||||
|
parsed = self._view.get_type_by_name(type)
|
||||||
|
if parsed is None:
|
||||||
|
parsed, errors = self._view.parse_type_string(type)
|
||||||
|
|
||||||
|
self._type_cache[type] = parsed
|
||||||
|
return parsed
|
||||||
|
|
||||||
|
def get_script_directory(self) -> str:
|
||||||
|
return CURRENT_PATH
|
||||||
|
|
||||||
|
def on_start(self):
|
||||||
|
self._view = bv # type: ignore
|
||||||
|
self._undo_id = self._view.begin_undo_actions()
|
||||||
|
self._view.set_analysis_hold(True)
|
||||||
|
self._components = {}
|
||||||
|
self._type_cache = {}
|
||||||
|
self._function_type_cache = {}
|
||||||
|
|
||||||
|
self._address_size = self._view.address_size
|
||||||
|
self._endianness = "little" if self._view.endianness == Endianness.LittleEndian else "big"
|
||||||
|
|
||||||
|
self._status.update_step("Parsing header")
|
||||||
|
|
||||||
|
with open(os.path.join(self.get_script_directory(), "il2cpp.h"), "r") as f:
|
||||||
|
parsed_types, errors = TypeParser.default.parse_types_from_source(
|
||||||
|
f.read(),
|
||||||
|
"il2cpp.h",
|
||||||
|
self._view.platform if self._view.platform is not None else Platform["windows-x86_64"],
|
||||||
|
self._view,
|
||||||
|
[
|
||||||
|
"--target=x86_64-pc-linux",
|
||||||
|
"-x", "c++",
|
||||||
|
"-D_BINARYNINJA_=1"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
if parsed_types is None:
|
||||||
|
log_error("Failed to import header")
|
||||||
|
log_error(errors)
|
||||||
|
return
|
||||||
|
|
||||||
|
self._status.update_step("Importing header types", len(parsed_types.types))
|
||||||
|
|
||||||
|
def import_progress_func(progress: int, total: int):
|
||||||
|
self._status.update_progress(1)
|
||||||
|
return True
|
||||||
|
|
||||||
|
self._view.define_user_types([(x.name, x.type) for x in parsed_types.types], import_progress_func)
|
||||||
|
|
||||||
|
def on_finish(self):
|
||||||
|
self._view.commit_undo_actions(self._undo_id)
|
||||||
|
self._view.set_analysis_hold(False)
|
||||||
|
self._view.update_analysis()
|
||||||
|
|
||||||
|
def define_function(self, address: int, end: int | None = None):
|
||||||
|
if self._view.get_function_at(address) is not None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._view.create_user_function(address)
|
||||||
|
|
||||||
|
def define_data_array(self, address: int, type: str, count: int):
|
||||||
|
parsed_type = self._get_or_create_type(type)
|
||||||
|
array_type = ArrayType.create(parsed_type, count)
|
||||||
|
var = self._view.get_data_var_at(address)
|
||||||
|
if var is None:
|
||||||
|
self._view.define_user_data_var(address, array_type)
|
||||||
|
else:
|
||||||
|
var.type = array_type
|
||||||
|
|
||||||
|
def set_data_type(self, address: int, type: str):
|
||||||
|
var = self._view.get_data_var_at(address)
|
||||||
|
dtype = self._get_or_create_type(type)
|
||||||
|
if var is None:
|
||||||
|
self._view.define_user_data_var(address, dtype)
|
||||||
|
else:
|
||||||
|
var.type = dtype
|
||||||
|
|
||||||
|
def set_function_type(self, address: int, type: str):
|
||||||
|
function = self._view.get_function_at(address)
|
||||||
|
if function is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if type in self._function_type_cache:
|
||||||
|
function.type = self._function_type_cache[type] # type: ignore
|
||||||
|
else:
|
||||||
|
#log_info(f"skipping function type setting for {address}, {type}")
|
||||||
|
#pass
|
||||||
|
function.type = type.replace("this", "`this`")
|
||||||
|
|
||||||
|
def set_data_comment(self, address: int, cmt: str):
|
||||||
|
self._view.set_comment_at(address, cmt)
|
||||||
|
|
||||||
|
def set_function_comment(self, address: int, cmt: str):
|
||||||
|
function = self._view.get_function_at(address)
|
||||||
|
if function is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
function.comment = cmt
|
||||||
|
|
||||||
|
def set_data_name(self, address: int, name: str):
|
||||||
|
var = self._view.get_data_var_at(address)
|
||||||
|
if var is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if name.startswith("_Z"):
|
||||||
|
type, demangled = demangle_gnu3(self._view.arch, name, self._view)
|
||||||
|
var.name = get_qualified_name(demangled)
|
||||||
|
else:
|
||||||
|
var.name = name
|
||||||
|
|
||||||
|
def set_function_name(self, address: int, name: str):
|
||||||
|
function = self._view.get_function_at(address)
|
||||||
|
if function is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if name.startswith("_Z"):
|
||||||
|
type, demangled = demangle_gnu3(self._view.arch, name, self._view)
|
||||||
|
function.name = get_qualified_name(demangled)
|
||||||
|
#function.type = type - this does not work due to the generated types not being namespaced. :(
|
||||||
|
else:
|
||||||
|
function.name = name
|
||||||
|
|
||||||
|
def add_cross_reference(self, from_address: int, to_address: int):
|
||||||
|
self._view.add_user_data_ref(from_address, to_address)
|
||||||
|
|
||||||
|
def import_c_typedef(self, type_def: str):
|
||||||
|
self._view.define_user_type(None, type_def)
|
||||||
|
|
||||||
|
# optional
|
||||||
|
def _get_or_create_component(self, name: str):
|
||||||
|
if name in self._components:
|
||||||
|
return self._components[name]
|
||||||
|
|
||||||
|
current = name
|
||||||
|
if current.count("/") != 0:
|
||||||
|
split_idx = current.rindex("/")
|
||||||
|
parent, child = current[:split_idx], current[split_idx:]
|
||||||
|
parent = self._get_or_create_component(name)
|
||||||
|
component = self._view.create_component(child, parent)
|
||||||
|
else:
|
||||||
|
component = self._view.create_component(name)
|
||||||
|
|
||||||
|
self._components[name] = component
|
||||||
|
return component
|
||||||
|
|
||||||
|
def add_function_to_group(self, address: int, group: str):
|
||||||
|
return
|
||||||
|
function = self._view.get_function_at(address)
|
||||||
|
if function is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._get_or_create_component(group).add_function(function)
|
||||||
|
|
||||||
|
def cache_function_types(self, signatures: list[str]):
|
||||||
|
function_sigs = set(signatures)
|
||||||
|
if len(function_sigs) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
typestr = ";\n".join(function_sigs).replace("this", "_this") + ";"
|
||||||
|
res = self._view.parse_types_from_string(typestr)
|
||||||
|
for function_sig, function in zip(function_sigs, res.functions.values()): # type: ignore
|
||||||
|
self._function_type_cache[function_sig] = function
|
||||||
|
|
||||||
|
# only required if supports_fake_string_segment == True
|
||||||
|
def create_fake_segment(self, name: str, size: int) -> int:
|
||||||
|
last_end_addr = self._view.mapped_address_ranges[-1].end
|
||||||
|
if last_end_addr % 0x1000 != 0:
|
||||||
|
last_end_addr += (0x1000 - (last_end_addr % 0x1000))
|
||||||
|
|
||||||
|
self._view.add_user_segment(last_end_addr, size, 0, 0, SegmentFlag.SegmentContainsData)
|
||||||
|
self._view.add_user_section(name, last_end_addr, size, SectionSemantics.ReadOnlyDataSectionSemantics)
|
||||||
|
return last_end_addr
|
||||||
|
|
||||||
|
def write_string(self, address: int, value: str):
|
||||||
|
self._view.write(address, value.encode() + b"\x00")
|
||||||
|
|
||||||
|
def write_address(self, address: int, value: int):
|
||||||
|
self._view.write(address, value.to_bytes(self._address_size, self._endianness))
|
||||||
|
|
||||||
|
|
||||||
|
class BinaryNinjaStatusHandler(BaseStatusHandler):
|
||||||
|
def __init__(self, thread: BackgroundTaskThread):
|
||||||
|
self.step = "Initializing"
|
||||||
|
self.max_items = 0
|
||||||
|
self.current_items = 0
|
||||||
|
self.start_time = datetime.now()
|
||||||
|
self.step_start_time = self.start_time
|
||||||
|
self.last_updated_time = datetime.min
|
||||||
|
self._thread = thread
|
||||||
|
|
||||||
|
def initialize(self): pass
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
if self.was_cancelled():
|
||||||
|
raise RuntimeError("Cancelled script.")
|
||||||
|
|
||||||
|
current_time = datetime.now()
|
||||||
|
if 0.5 > (current_time - self.last_updated_time).total_seconds():
|
||||||
|
return
|
||||||
|
|
||||||
|
self.last_updated_time = current_time
|
||||||
|
|
||||||
|
step_time = current_time - self.step_start_time
|
||||||
|
total_time = current_time - self.start_time
|
||||||
|
self._thread.progress = f"Processing IL2CPP metadata: {self.step} ({self.current_items}/{self.max_items}), elapsed: {step_time} ({total_time})"
|
||||||
|
|
||||||
|
def update_step(self, step, max_items = 0):
|
||||||
|
self.step = step
|
||||||
|
self.max_items = max_items
|
||||||
|
self.current_items = 0
|
||||||
|
self.step_start_time = datetime.now()
|
||||||
|
self.last_updated_time = datetime.min
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update_progress(self, new_progress = 1):
|
||||||
|
self.current_items += new_progress
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def was_cancelled(self): return False
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Entry point
|
||||||
|
class Il2CppTask(BackgroundTaskThread):
|
||||||
|
def __init__(self):
|
||||||
|
BackgroundTaskThread.__init__(self, "Processing IL2CPP metadata...", False)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
status = BinaryNinjaStatusHandler(self)
|
||||||
|
backend = BinaryNinjaDisassemblerInterface(status)
|
||||||
|
context = ScriptContext(backend, status)
|
||||||
|
context.process()
|
||||||
|
|
||||||
|
Il2CppTask().start()
|
||||||
@@ -1,106 +1,124 @@
|
|||||||
# Ghidra-specific implementation
|
# Ghidra-specific implementation
|
||||||
from ghidra.app.cmd.function import ApplyFunctionSignatureCmd
|
from ghidra.app.cmd.function import ApplyFunctionSignatureCmd
|
||||||
from ghidra.app.script import GhidraScriptUtil
|
|
||||||
from ghidra.app.util.cparser.C import CParserUtils
|
from ghidra.app.util.cparser.C import CParserUtils
|
||||||
from ghidra.program.model.data import ArrayDataType
|
from ghidra.program.model.data import ArrayDataType
|
||||||
from ghidra.program.model.symbol import SourceType
|
from ghidra.program.model.symbol import SourceType
|
||||||
from ghidra.program.model.symbol import RefType
|
from ghidra.program.model.symbol import RefType
|
||||||
from ghidra.app.cmd.label import DemanglerCmd
|
from ghidra.app.cmd.label import DemanglerCmd
|
||||||
|
|
||||||
xrefs = currentProgram.getReferenceManager()
|
#try:
|
||||||
|
# from typing import TYPE_CHECKING
|
||||||
|
# if TYPE_CHECKING:
|
||||||
|
# from ..shared_base import BaseStatusHandler, BaseDisassemblerInterface, ScriptContext
|
||||||
|
# import json
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# from datetime import datetime
|
||||||
|
#except:
|
||||||
|
# pass
|
||||||
|
|
||||||
def set_name(addr, name):
|
class GhidraDisassemblerInterface(BaseDisassemblerInterface):
|
||||||
if not name.startswith("_ZN"):
|
supports_fake_string_segment = False
|
||||||
createLabel(toAddr(addr), name, True)
|
|
||||||
return
|
|
||||||
cmd = DemanglerCmd(currentAddress.getAddress(hex(addr)), name)
|
|
||||||
if not cmd.applyTo(currentProgram, monitor):
|
|
||||||
print("Failed to apply demangled name to %s at %s due %s, falling back to mangled" % (name, hex(addr), cmd.getStatusMsg()))
|
|
||||||
createLabel(toAddr(addr), name, True)
|
|
||||||
|
|
||||||
def make_function(start, end = None):
|
def get_script_directory(self) -> str:
|
||||||
addr = toAddr(start)
|
return getSourceFile().getParentFile().toString()
|
||||||
# Don't override existing functions
|
|
||||||
fn = getFunctionAt(addr)
|
|
||||||
if fn is None:
|
|
||||||
# Create new function if none exists
|
|
||||||
createFunction(addr, None)
|
|
||||||
|
|
||||||
def make_array(addr, numItems, cppType):
|
def on_start(self):
|
||||||
if cppType.startswith('struct '):
|
self.xrefs = currentProgram.getReferenceManager()
|
||||||
cppType = cppType[7:]
|
|
||||||
|
|
||||||
t = getDataTypes(cppType)[0]
|
|
||||||
a = ArrayDataType(t, numItems, t.getLength())
|
|
||||||
addr = toAddr(addr)
|
|
||||||
removeDataAt(addr)
|
|
||||||
createData(addr, a)
|
|
||||||
|
|
||||||
def define_code(code):
|
# Check that the user has parsed the C headers first
|
||||||
# Code declarations are not supported in Ghidra
|
if len(getDataTypes('Il2CppObject')) == 0:
|
||||||
# This only affects string literals for metadata version < 19
|
print('STOP! You must import the generated C header file (%TYPE_HEADER_RELATIVE_PATH%) before running this script.')
|
||||||
# TODO: Replace with creating a DataType for enums
|
print('See https://github.com/djkaty/Il2CppInspector/blob/master/README.md#adding-metadata-to-your-ghidra-workflow for instructions.')
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
# Ghidra sets the image base for ELF to 0x100000 for some reason
|
||||||
|
# https://github.com/NationalSecurityAgency/ghidra/issues/1020
|
||||||
|
# Make sure that the base address is 0
|
||||||
|
# Without this, Ghidra may not analyze the binary correctly and you will just waste your time
|
||||||
|
# If 0 doesn't work for you, replace it with the base address from the output of the CLI or GUI
|
||||||
|
if currentProgram.getExecutableFormat().endswith('(ELF)'):
|
||||||
|
currentProgram.setImageBase(toAddr(0), True)
|
||||||
|
|
||||||
|
# Don't trigger decompiler
|
||||||
|
setAnalysisOption(currentProgram, "Call Convention ID", "false")
|
||||||
|
|
||||||
|
def on_finish(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def define_function(self, address: int, end: int | None = None):
|
||||||
|
address = toAddr(address)
|
||||||
|
# Don't override existing functions
|
||||||
|
fn = getFunctionAt(address)
|
||||||
|
if fn is None:
|
||||||
|
# Create new function if none exists
|
||||||
|
createFunction(address, None)
|
||||||
|
|
||||||
|
def define_data_array(self, address: int, type: str, count: int):
|
||||||
|
if type.startswith('struct '):
|
||||||
|
type = type[7:]
|
||||||
|
|
||||||
|
t = getDataTypes(type)[0]
|
||||||
|
a = ArrayDataType(t, count, t.getLength())
|
||||||
|
address = toAddr(address)
|
||||||
|
removeDataAt(address)
|
||||||
|
createData(address, a)
|
||||||
|
|
||||||
|
def set_data_type(self, address: int, type: str):
|
||||||
|
if type.startswith('struct '):
|
||||||
|
type = type[7:]
|
||||||
|
|
||||||
|
try:
|
||||||
|
t = getDataTypes(type)[0]
|
||||||
|
address = toAddr(address)
|
||||||
|
removeDataAt(address)
|
||||||
|
createData(address, t)
|
||||||
|
except:
|
||||||
|
print("Failed to set type: %s" % type)
|
||||||
|
|
||||||
|
def set_function_type(self, address: int, type: str):
|
||||||
|
make_function(address)
|
||||||
|
typeSig = CParserUtils.parseSignature(None, currentProgram, type)
|
||||||
|
ApplyFunctionSignatureCmd(toAddr(address), typeSig, SourceType.USER_DEFINED, False, True).applyTo(currentProgram)
|
||||||
|
|
||||||
|
def set_data_comment(self, address: int, cmt: str):
|
||||||
|
setEOLComment(toAddr(address), cmt)
|
||||||
|
|
||||||
|
def set_function_comment(self, address: int, cmt: str):
|
||||||
|
setPlateComment(toAddr(address), cmt)
|
||||||
|
|
||||||
|
def set_data_name(self, address: int, name: str):
|
||||||
|
address = toAddr(address)
|
||||||
|
|
||||||
|
if len(name) > 2000:
|
||||||
|
print("Name length exceeds 2000 characters, skipping (%s)" % name)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not name.startswith("_ZN"):
|
||||||
|
createLabel(address, name, True)
|
||||||
|
return
|
||||||
|
|
||||||
|
cmd = DemanglerCmd(address, name)
|
||||||
|
if not cmd.applyTo(currentProgram, monitor):
|
||||||
|
print(f"Failed to apply demangled name to {name} at {address} due {cmd.getStatusMsg()}, falling back to mangled")
|
||||||
|
createLabel(address, name, True)
|
||||||
|
|
||||||
|
def set_function_name(self, address: int, name: str):
|
||||||
|
return self.set_data_name(address, name)
|
||||||
|
|
||||||
|
def add_cross_reference(self, from_address: int, to_address: int):
|
||||||
|
self.xrefs.addMemoryReference(toAddr(from_address), toAddr(to_address), RefType.DATA, SourceType.USER_DEFINED, 0)
|
||||||
|
|
||||||
|
def import_c_typedef(self, type_def: str):
|
||||||
|
# Code declarations are not supported in Ghidra
|
||||||
|
# This only affects string literals for metadata version < 19
|
||||||
|
# TODO: Replace with creating a DataType for enums
|
||||||
|
pass
|
||||||
|
|
||||||
|
class GhidraStatusHandler(BaseStatusHandler):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_function_type(addr, sig):
|
status = GhidraStatusHandler()
|
||||||
make_function(addr)
|
backend = GhidraDisassemblerInterface()
|
||||||
typeSig = CParserUtils.parseSignature(None, currentProgram, sig)
|
context = ScriptContext(backend, status)
|
||||||
ApplyFunctionSignatureCmd(toAddr(addr), typeSig, SourceType.USER_DEFINED, False, True).applyTo(currentProgram)
|
context.process()
|
||||||
|
|
||||||
def set_type(addr, cppType):
|
|
||||||
if cppType.startswith('struct '):
|
|
||||||
cppType = cppType[7:]
|
|
||||||
|
|
||||||
try:
|
|
||||||
t = getDataTypes(cppType)[0]
|
|
||||||
addr = toAddr(addr)
|
|
||||||
removeDataAt(addr)
|
|
||||||
createData(addr, t)
|
|
||||||
except:
|
|
||||||
print("Failed to set type: %s" % cppType)
|
|
||||||
|
|
||||||
def set_comment(addr, text):
|
|
||||||
setEOLComment(toAddr(addr), text)
|
|
||||||
|
|
||||||
def set_header_comment(addr, text):
|
|
||||||
setPlateComment(toAddr(addr), text)
|
|
||||||
|
|
||||||
def script_prologue(status):
|
|
||||||
# Check that the user has parsed the C headers first
|
|
||||||
if len(getDataTypes('Il2CppObject')) == 0:
|
|
||||||
print('STOP! You must import the generated C header file (%TYPE_HEADER_RELATIVE_PATH%) before running this script.')
|
|
||||||
print('See https://github.com/djkaty/Il2CppInspector/blob/master/README.md#adding-metadata-to-your-ghidra-workflow for instructions.')
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
# Ghidra sets the image base for ELF to 0x100000 for some reason
|
|
||||||
# https://github.com/NationalSecurityAgency/ghidra/issues/1020
|
|
||||||
# Make sure that the base address is 0
|
|
||||||
# Without this, Ghidra may not analyze the binary correctly and you will just waste your time
|
|
||||||
# If 0 doesn't work for you, replace it with the base address from the output of the CLI or GUI
|
|
||||||
if currentProgram.getExecutableFormat().endswith('(ELF)'):
|
|
||||||
currentProgram.setImageBase(toAddr(0), True)
|
|
||||||
|
|
||||||
# Don't trigger decompiler
|
|
||||||
setAnalysisOption(currentProgram, "Call Convention ID", "false")
|
|
||||||
|
|
||||||
def get_script_directory(): return getSourceFile().getParentFile().toString()
|
|
||||||
|
|
||||||
def script_epilogue(status): pass
|
|
||||||
def add_function_to_group(addr, group): pass
|
|
||||||
def add_xref(addr, to):
|
|
||||||
xrefs.addMemoryReference(currentAddress.getAddress(hex(addr)), currentAddress.getAddress(hex(to)), RefType.DATA, SourceType.USER_DEFINED, 0)
|
|
||||||
|
|
||||||
def process_string_literals(status, data):
|
|
||||||
for d in jsonData['stringLiterals']:
|
|
||||||
define_string(d)
|
|
||||||
|
|
||||||
# I don't know how to make inline strings in Ghidra
|
|
||||||
# Just revert back original impl
|
|
||||||
addr = parse_address(d)
|
|
||||||
set_name(addr, d['name'])
|
|
||||||
set_type(addr, r'struct String *')
|
|
||||||
set_comment(addr, d['string'])
|
|
||||||
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
class StatusHandler(BaseStatusHandler): pass
|
|
||||||
@@ -8,6 +8,8 @@ import ida_nalt
|
|||||||
import ida_ida
|
import ida_ida
|
||||||
import ida_ua
|
import ida_ua
|
||||||
import ida_segment
|
import ida_segment
|
||||||
|
import ida_funcs
|
||||||
|
import ida_xref
|
||||||
|
|
||||||
try: # 7.7+
|
try: # 7.7+
|
||||||
import ida_srclang
|
import ida_srclang
|
||||||
@@ -23,206 +25,205 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
FOLDERS_AVAILABLE = False
|
FOLDERS_AVAILABLE = False
|
||||||
|
|
||||||
cached_genflags = 0
|
#try:
|
||||||
skip_make_function = False
|
# from typing import TYPE_CHECKING
|
||||||
func_dirtree = None
|
# if TYPE_CHECKING:
|
||||||
is_32_bit = False
|
# from ..shared_base import BaseStatusHandler, BaseDisassemblerInterface, ScriptContext
|
||||||
fake_segments_base = None
|
# import json
|
||||||
|
# import os
|
||||||
def script_prologue(status):
|
# from datetime import datetime
|
||||||
global cached_genflags, skip_make_function, func_dirtree, is_32_bit, fake_segments_base
|
#except:
|
||||||
# Disable autoanalysis
|
# pass
|
||||||
cached_genflags = ida_ida.inf_get_genflags()
|
|
||||||
ida_ida.inf_set_genflags(cached_genflags & ~ida_ida.INFFL_AUTO)
|
|
||||||
|
|
||||||
# Unload type libraries we know to cause issues - like the c++ linux one
|
|
||||||
PLATFORMS = ["x86", "x64", "arm", "arm64"]
|
|
||||||
PROBLEMATIC_TYPELIBS = ["gnulnx"]
|
|
||||||
|
|
||||||
for lib in PROBLEMATIC_TYPELIBS:
|
|
||||||
for platform in PLATFORMS:
|
|
||||||
ida_typeinf.del_til(f"{lib}_{platform}")
|
|
||||||
|
|
||||||
# Set name mangling to GCC 3.x and display demangled as default
|
|
||||||
ida_ida.inf_set_demnames(ida_ida.DEMNAM_GCC3 | ida_ida.DEMNAM_NAME)
|
|
||||||
|
|
||||||
status.update_step('Processing Types')
|
|
||||||
|
|
||||||
if IDACLANG_AVAILABLE:
|
|
||||||
header_path = os.path.join(get_script_directory(), "%TYPE_HEADER_RELATIVE_PATH%")
|
|
||||||
ida_srclang.set_parser_argv("clang", "-target x86_64-pc-linux -x c++ -D_IDACLANG_=1") # -target required for 8.3+
|
|
||||||
ida_srclang.parse_decls_with_parser("clang", None, header_path, True)
|
|
||||||
else:
|
|
||||||
original_macros = ida_typeinf.get_c_macros()
|
|
||||||
ida_typeinf.set_c_macros(original_macros + ";_IDA_=1")
|
|
||||||
ida_typeinf.idc_parse_types(os.path.join(get_script_directory(), "%TYPE_HEADER_RELATIVE_PATH%"), ida_typeinf.PT_FILE)
|
|
||||||
ida_typeinf.set_c_macros(original_macros)
|
|
||||||
|
|
||||||
# Skip make_function on Windows GameAssembly.dll files due to them predefining all functions through pdata which makes the method very slow
|
|
||||||
skip_make_function = ida_segment.get_segm_by_name(".pdata") is not None
|
|
||||||
if skip_make_function:
|
|
||||||
print(".pdata section found, skipping function boundaries")
|
|
||||||
|
|
||||||
if FOLDERS_AVAILABLE:
|
|
||||||
func_dirtree = ida_dirtree.get_std_dirtree(ida_dirtree.DIRTREE_FUNCS)
|
|
||||||
|
|
||||||
is_32_bit = ida_ida.inf_is_32bit_exactly()
|
|
||||||
|
|
||||||
def script_epilogue(status):
|
|
||||||
# Reenable auto-analysis
|
|
||||||
global cached_genflags
|
|
||||||
ida_ida.inf_set_genflags(cached_genflags)
|
|
||||||
|
|
||||||
# Utility methods
|
|
||||||
|
|
||||||
def set_name(addr, name):
|
|
||||||
ida_name.set_name(addr, name, ida_name.SN_NOWARN | ida_name.SN_NOCHECK | ida_name.SN_FORCE)
|
|
||||||
|
|
||||||
def make_function(start, end = None):
|
|
||||||
global skip_make_function
|
|
||||||
if skip_make_function:
|
|
||||||
return
|
|
||||||
|
|
||||||
ida_bytes.del_items(start, ida_bytes.DELIT_SIMPLE, 12) # Undefine x bytes which should hopefully be enough for the first instruction
|
|
||||||
ida_ua.create_insn(start) # Create instruction at start
|
|
||||||
if not ida_funcs.add_func(start, end if end is not None else ida_idaapi.BADADDR): # This fails if the function doesn't start with an instruction
|
|
||||||
print(f"failed to mark function {hex(start)}-{hex(end) if end is not None else '???'} as function")
|
|
||||||
|
|
||||||
TYPE_CACHE = {}
|
|
||||||
|
|
||||||
def get_type(typeName):
|
|
||||||
if typeName not in TYPE_CACHE:
|
|
||||||
info = ida_typeinf.idc_parse_decl(None, typeName, ida_typeinf.PT_RAWARGS)
|
|
||||||
if info is None:
|
|
||||||
print(f"Failed to create type {typeName}.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
TYPE_CACHE[typeName] = info[1:]
|
|
||||||
|
|
||||||
return TYPE_CACHE[typeName]
|
|
||||||
|
|
||||||
TINFO_DEFINITE = 0x0001 # These only exist in idc for some reason, so we redefine it here
|
TINFO_DEFINITE = 0x0001 # These only exist in idc for some reason, so we redefine it here
|
||||||
|
DEFAULT_TIL: "til_t" = None # type: ignore
|
||||||
|
|
||||||
def set_type(addr, cppType):
|
class IDADisassemblerInterface(BaseDisassemblerInterface):
|
||||||
cppType += ';'
|
supports_fake_string_segment = True
|
||||||
|
|
||||||
info = get_type(cppType)
|
_status: BaseStatusHandler
|
||||||
if info is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
if ida_typeinf.apply_type(None, info[0], info[1], addr, TINFO_DEFINITE) is None:
|
_type_cache: dict
|
||||||
print(f"set_type({hex(addr)}, {cppType}); failed!")
|
_folders: list
|
||||||
|
|
||||||
def set_function_type(addr, sig):
|
|
||||||
set_type(addr, sig)
|
|
||||||
|
|
||||||
def make_array(addr, numItems, cppType):
|
|
||||||
set_type(addr, cppType)
|
|
||||||
|
|
||||||
flags = ida_bytes.get_flags(addr)
|
|
||||||
if ida_bytes.is_struct(flags):
|
|
||||||
opinfo = ida_nalt.opinfo_t()
|
|
||||||
ida_bytes.get_opcode(opinfo, addr, 0, flags)
|
|
||||||
entrySize = ida_bytes.get_data_elsize(addr, flags, opinfo)
|
|
||||||
tid = opinfo.tid
|
|
||||||
else:
|
|
||||||
entrySize = ida_bytes.get_item_size(addr)
|
|
||||||
tid = ida_idaapi.BADADDR
|
|
||||||
|
|
||||||
ida_bytes.create_data(addr, flags, numItems * entrySize, tid)
|
|
||||||
|
|
||||||
def define_code(code):
|
|
||||||
ida_typeinf.idc_parse_types(code)
|
|
||||||
|
|
||||||
def set_comment(addr, comment, repeatable = True):
|
|
||||||
ida_bytes.set_cmt(addr, comment, repeatable)
|
|
||||||
|
|
||||||
def set_header_comment(addr, comment):
|
|
||||||
func = ida_funcs.get_func(addr)
|
|
||||||
if func is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
ida_funcs.set_func_cmt(func, comment, True)
|
|
||||||
|
|
||||||
def get_script_directory():
|
|
||||||
return os.path.dirname(os.path.realpath(__file__))
|
|
||||||
|
|
||||||
folders = []
|
|
||||||
def add_function_to_group(addr, group):
|
|
||||||
global func_dirtree, folders
|
|
||||||
return
|
|
||||||
|
|
||||||
if not FOLDERS_AVAILABLE:
|
|
||||||
return
|
|
||||||
|
|
||||||
if group not in folders:
|
|
||||||
folders.append(group)
|
|
||||||
func_dirtree.mkdir(group)
|
|
||||||
|
|
||||||
name = ida_funcs.get_func_name(addr)
|
|
||||||
func_dirtree.rename(name, f"{group}/{name}")
|
|
||||||
|
|
||||||
def add_xref(addr, to):
|
|
||||||
ida_xref.add_dref(addr, to, ida_xref.XREF_USER | ida_xref.dr_I)
|
|
||||||
|
|
||||||
def write_string(addr, string):
|
|
||||||
encoded_string = string.encode() + b'\x00'
|
|
||||||
string_length = len(encoded_string)
|
|
||||||
ida_bytes.put_bytes(addr, encoded_string)
|
|
||||||
ida_bytes.create_strlit(addr, string_length, ida_nalt.STRTYPE_C)
|
|
||||||
|
|
||||||
def write_address(addr, value):
|
|
||||||
global is_32_bit
|
|
||||||
|
|
||||||
if is_32_bit:
|
|
||||||
ida_bytes.put_dword(addr, value)
|
|
||||||
else:
|
|
||||||
ida_bytes.put_qword(addr, value)
|
|
||||||
|
|
||||||
def create_fake_segment(name, size):
|
|
||||||
global is_32_bit
|
|
||||||
|
|
||||||
start = ida_ida.inf_get_max_ea()
|
|
||||||
end = start + size
|
|
||||||
|
|
||||||
ida_segment.add_segm(0, start, end, name, "DATA")
|
|
||||||
segment = ida_segment.get_segm_by_name(name)
|
|
||||||
segment.bitness = 1 if is_32_bit else 2
|
|
||||||
segment.perm = ida_segment.SEGPERM_READ
|
|
||||||
segment.update()
|
|
||||||
|
|
||||||
return start
|
|
||||||
|
|
||||||
def process_string_literals(status, data):
|
|
||||||
total_string_length = 0
|
|
||||||
for d in data['stringLiterals']:
|
|
||||||
total_string_length += len(d["string"]) + 1
|
|
||||||
|
|
||||||
aligned_length = total_string_length + (4096 - (total_string_length % 4096))
|
_function_dirtree: "ida_dirtree.dirtree_t"
|
||||||
segment_base = create_fake_segment(".fake_strings", aligned_length)
|
_cached_genflags: int
|
||||||
|
_skip_function_creation: bool
|
||||||
|
_is_32_bit: bool
|
||||||
|
_fake_segments_base: int
|
||||||
|
|
||||||
current_string_address = segment_base
|
def __init__(self, status: BaseStatusHandler):
|
||||||
for d in data['stringLiterals']:
|
self._status = status
|
||||||
define_string(d)
|
|
||||||
|
self._type_cache = {}
|
||||||
|
self._folders = []
|
||||||
|
|
||||||
ref_addr = parse_address(d)
|
self._cached_genflags = 0
|
||||||
write_string(current_string_address, d["string"])
|
self._skip_function_creation = False
|
||||||
write_address(ref_addr, current_string_address)
|
self._is_32_bit = False
|
||||||
set_type(ref_addr, r'const char* const')
|
self._fake_segments_base = 0
|
||||||
|
|
||||||
current_string_address += len(d["string"]) + 1
|
def _get_type(self, type: str):
|
||||||
status.update_progress()
|
if type not in self._type_cache:
|
||||||
|
info = ida_typeinf.idc_parse_decl(DEFAULT_TIL, type, ida_typeinf.PT_RAWARGS)
|
||||||
|
if info is None:
|
||||||
|
print(f"Failed to create type {type}.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
self._type_cache[type] = info[1:]
|
||||||
|
|
||||||
|
return self._type_cache[type]
|
||||||
|
|
||||||
|
def get_script_directory(self) -> str:
|
||||||
|
return os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
def on_start(self):
|
||||||
|
# Disable autoanalysis
|
||||||
|
self._cached_genflags = ida_ida.inf_get_genflags()
|
||||||
|
ida_ida.inf_set_genflags(self._cached_genflags & ~ida_ida.INFFL_AUTO)
|
||||||
|
|
||||||
|
# Unload type libraries we know to cause issues - like the c++ linux one
|
||||||
|
PLATFORMS = ["x86", "x64", "arm", "arm64"]
|
||||||
|
PROBLEMATIC_TYPELIBS = ["gnulnx"]
|
||||||
|
|
||||||
|
for lib in PROBLEMATIC_TYPELIBS:
|
||||||
|
for platform in PLATFORMS:
|
||||||
|
ida_typeinf.del_til(f"{lib}_{platform}")
|
||||||
|
|
||||||
|
# Set name mangling to GCC 3.x and display demangled as default
|
||||||
|
ida_ida.inf_set_demnames(ida_ida.DEMNAM_GCC3 | ida_ida.DEMNAM_NAME)
|
||||||
|
|
||||||
|
self._status.update_step('Processing Types')
|
||||||
|
|
||||||
|
if IDACLANG_AVAILABLE:
|
||||||
|
header_path = os.path.join(self.get_script_directory(), "%TYPE_HEADER_RELATIVE_PATH%")
|
||||||
|
ida_srclang.set_parser_argv("clang", "-target x86_64-pc-linux -x c++ -D_IDACLANG_=1") # -target required for 8.3+
|
||||||
|
ida_srclang.parse_decls_with_parser("clang", None, header_path, True)
|
||||||
|
else:
|
||||||
|
original_macros = ida_typeinf.get_c_macros()
|
||||||
|
ida_typeinf.set_c_macros(original_macros + ";_IDA_=1")
|
||||||
|
ida_typeinf.idc_parse_types(os.path.join(self.get_script_directory(), "%TYPE_HEADER_RELATIVE_PATH%"), ida_typeinf.PT_FILE)
|
||||||
|
ida_typeinf.set_c_macros(original_macros)
|
||||||
|
|
||||||
|
# Skip make_function on Windows GameAssembly.dll files due to them predefining all functions through pdata which makes the method very slow
|
||||||
|
skip_make_function = ida_segment.get_segm_by_name(".pdata") is not None
|
||||||
|
if skip_make_function:
|
||||||
|
print(".pdata section found, skipping function boundaries")
|
||||||
|
|
||||||
|
if FOLDERS_AVAILABLE:
|
||||||
|
self._function_dirtree = ida_dirtree.get_std_dirtree(ida_dirtree.DIRTREE_FUNCS)
|
||||||
|
|
||||||
|
self._is_32_bit = ida_ida.inf_is_32bit_exactly()
|
||||||
|
|
||||||
|
def on_finish(self):
|
||||||
|
ida_ida.inf_set_genflags(self._cached_genflags)
|
||||||
|
|
||||||
|
def define_function(self, address: int, end: int | None = None):
|
||||||
|
if self._skip_function_creation:
|
||||||
|
return
|
||||||
|
|
||||||
|
ida_bytes.del_items(address, ida_bytes.DELIT_SIMPLE, 12) # Undefine x bytes which should hopefully be enough for the first instruction
|
||||||
|
ida_ua.create_insn(address) # Create instruction at start
|
||||||
|
if not ida_funcs.add_func(address, end if end is not None else ida_idaapi.BADADDR): # This fails if the function doesn't start with an instruction
|
||||||
|
print(f"failed to mark function {hex(address)}-{hex(end) if end is not None else '???'} as function")
|
||||||
|
|
||||||
|
def define_data_array(self, address: int, type: str, count: int):
|
||||||
|
self.set_data_type(address, type)
|
||||||
|
|
||||||
|
flags = ida_bytes.get_flags(address)
|
||||||
|
if ida_bytes.is_struct(flags):
|
||||||
|
opinfo = ida_nalt.opinfo_t()
|
||||||
|
ida_bytes.get_opinfo(opinfo, address, 0, flags)
|
||||||
|
entrySize = ida_bytes.get_data_elsize(address, flags, opinfo)
|
||||||
|
tid = opinfo.tid
|
||||||
|
else:
|
||||||
|
entrySize = ida_bytes.get_item_size(address)
|
||||||
|
tid = ida_idaapi.BADADDR
|
||||||
|
|
||||||
|
ida_bytes.create_data(address, flags, count * entrySize, tid)
|
||||||
|
|
||||||
|
def set_data_type(self, address: int, type: str):
|
||||||
|
type += ';'
|
||||||
|
|
||||||
|
info = self._get_type(type)
|
||||||
|
if info is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if ida_typeinf.apply_type(DEFAULT_TIL, info[0], info[1], address, TINFO_DEFINITE) is None:
|
||||||
|
print(f"set_type({hex(address)}, {type}); failed!")
|
||||||
|
|
||||||
|
def set_function_type(self, address: int, type: str):
|
||||||
|
self.set_data_type(address, type)
|
||||||
|
|
||||||
|
def set_data_comment(self, address: int, cmt: str):
|
||||||
|
ida_bytes.set_cmt(address, cmt, False)
|
||||||
|
|
||||||
|
def set_function_comment(self, address: int, cmt: str):
|
||||||
|
func = ida_funcs.get_func(address)
|
||||||
|
if func is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
ida_funcs.set_func_cmt(func, cmt, True)
|
||||||
|
|
||||||
|
def set_data_name(self, address: int, name: str):
|
||||||
|
ida_name.set_name(address, name, ida_name.SN_NOWARN | ida_name.SN_NOCHECK | ida_name.SN_FORCE)
|
||||||
|
|
||||||
|
def set_function_name(self, address: int, name: str):
|
||||||
|
self.set_data_name(address, name)
|
||||||
|
|
||||||
|
def add_cross_reference(self, from_address: int, to_address: int):
|
||||||
|
ida_xref.add_dref(from_address, to_address, ida_xref.XREF_USER | ida_xref.dr_I)
|
||||||
|
|
||||||
|
def import_c_typedef(self, type_def: str):
|
||||||
|
ida_typeinf.idc_parse_types(type_def, 0)
|
||||||
|
|
||||||
|
# optional
|
||||||
|
def add_function_to_group(self, address: int, group: str):
|
||||||
|
if not FOLDERS_AVAILABLE or True: # enable at your own risk - this is slow
|
||||||
|
return
|
||||||
|
|
||||||
|
if group not in self._folders:
|
||||||
|
self._folders.append(group)
|
||||||
|
self._function_dirtree.mkdir(group)
|
||||||
|
|
||||||
|
name = ida_funcs.get_func_name(address)
|
||||||
|
self._function_dirtree.rename(name, f"{group}/{name}")
|
||||||
|
|
||||||
|
# only required if supports_fake_string_segment == True
|
||||||
|
def create_fake_segment(self, name: str, size: int) -> int:
|
||||||
|
start = ida_ida.inf_get_max_ea()
|
||||||
|
end = start + size
|
||||||
|
|
||||||
|
ida_segment.add_segm(0, start, end, name, "DATA")
|
||||||
|
segment = ida_segment.get_segm_by_name(name)
|
||||||
|
segment.bitness = 1 if self._is_32_bit else 2
|
||||||
|
segment.perm = ida_segment.SEGPERM_READ
|
||||||
|
segment.update()
|
||||||
|
|
||||||
|
return start
|
||||||
|
|
||||||
|
def write_string(self, address: int, value: str):
|
||||||
|
encoded_string = value.encode() + b'\x00'
|
||||||
|
string_length = len(encoded_string)
|
||||||
|
ida_bytes.put_bytes(address, encoded_string)
|
||||||
|
ida_bytes.create_strlit(address, string_length, ida_nalt.STRTYPE_C)
|
||||||
|
|
||||||
|
def write_address(self, address: int, value: int):
|
||||||
|
if self._is_32_bit:
|
||||||
|
ida_bytes.put_dword(address, value)
|
||||||
|
else:
|
||||||
|
ida_bytes.put_qword(address, value)
|
||||||
|
|
||||||
# Status handler
|
# Status handler
|
||||||
|
|
||||||
class StatusHandler(BaseStatusHandler):
|
class IDAStatusHandler(BaseStatusHandler):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.step = "Initializing"
|
self.step = "Initializing"
|
||||||
self.max_items = 0
|
self.max_items = 0
|
||||||
self.current_items = 0
|
self.current_items = 0
|
||||||
self.start_time = datetime.datetime.now()
|
self.start_time = datetime.now()
|
||||||
self.step_start_time = self.start_time
|
self.step_start_time = self.start_time
|
||||||
self.last_updated_time = datetime.datetime.min
|
self.last_updated_time = datetime.min
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
ida_kernwin.show_wait_box("Processing")
|
ida_kernwin.show_wait_box("Processing")
|
||||||
@@ -231,7 +232,7 @@ class StatusHandler(BaseStatusHandler):
|
|||||||
if self.was_cancelled():
|
if self.was_cancelled():
|
||||||
raise RuntimeError("Cancelled script.")
|
raise RuntimeError("Cancelled script.")
|
||||||
|
|
||||||
current_time = datetime.datetime.now()
|
current_time = datetime.now()
|
||||||
if 0.5 > (current_time - self.last_updated_time).total_seconds():
|
if 0.5 > (current_time - self.last_updated_time).total_seconds():
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -254,8 +255,8 @@ Elapsed: {step_time} ({total_time})
|
|||||||
self.step = step
|
self.step = step
|
||||||
self.max_items = max_items
|
self.max_items = max_items
|
||||||
self.current_items = 0
|
self.current_items = 0
|
||||||
self.step_start_time = datetime.datetime.now()
|
self.step_start_time = datetime.now()
|
||||||
self.last_updated_time = datetime.datetime.min
|
self.last_updated_time = datetime.min
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def update_progress(self, new_progress = 1):
|
def update_progress(self, new_progress = 1):
|
||||||
@@ -265,5 +266,10 @@ Elapsed: {step_time} ({total_time})
|
|||||||
def was_cancelled(self):
|
def was_cancelled(self):
|
||||||
return ida_kernwin.user_cancelled()
|
return ida_kernwin.user_cancelled()
|
||||||
|
|
||||||
def close(self):
|
def shutdown(self):
|
||||||
ida_kernwin.hide_wait_box()
|
ida_kernwin.hide_wait_box()
|
||||||
|
|
||||||
|
status = IDAStatusHandler()
|
||||||
|
backend = IDADisassemblerInterface(status)
|
||||||
|
context = ScriptContext(backend, status)
|
||||||
|
context.process()
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
# Shared interface
|
|
||||||
def from_hex(addr): return int(addr, 0)
|
|
||||||
|
|
||||||
def parse_address(d): return from_hex(d['virtualAddress'])
|
|
||||||
|
|
||||||
def define_il_method(jsonDef):
|
|
||||||
addr = parse_address(jsonDef)
|
|
||||||
set_name(addr, jsonDef['name'])
|
|
||||||
set_function_type(addr, jsonDef['signature'])
|
|
||||||
set_header_comment(addr, jsonDef['dotNetSignature'])
|
|
||||||
add_function_to_group(addr, jsonDef['group'])
|
|
||||||
|
|
||||||
def define_il_method_info(jsonDef):
|
|
||||||
addr = parse_address(jsonDef)
|
|
||||||
set_name(addr, jsonDef['name'])
|
|
||||||
set_comment(addr, jsonDef['dotNetSignature'])
|
|
||||||
set_type(addr, r'struct MethodInfo *')
|
|
||||||
if 'methodAddress' in jsonDef:
|
|
||||||
add_xref(from_hex(jsonDef["methodAddress"]), addr)
|
|
||||||
|
|
||||||
|
|
||||||
def define_cpp_function(jsonDef):
|
|
||||||
addr = parse_address(jsonDef)
|
|
||||||
set_name(addr, jsonDef['name'])
|
|
||||||
set_function_type(addr, jsonDef['signature'])
|
|
||||||
|
|
||||||
def define_string(jsonDef):
|
|
||||||
addr = parse_address(jsonDef)
|
|
||||||
set_name(addr, jsonDef['name'])
|
|
||||||
set_comment(addr, jsonDef['string'])
|
|
||||||
|
|
||||||
def define_field(addr, name, type, ilType = None):
|
|
||||||
addr = from_hex(addr)
|
|
||||||
set_name(addr, name)
|
|
||||||
set_type(addr, type)
|
|
||||||
if ilType is not None:
|
|
||||||
set_comment(addr, ilType)
|
|
||||||
|
|
||||||
def define_field_from_json(jsonDef):
|
|
||||||
define_field(jsonDef['virtualAddress'], jsonDef['name'], jsonDef['type'], jsonDef['dotNetType'])
|
|
||||||
|
|
||||||
def define_array(jsonDef):
|
|
||||||
addr = parse_address(jsonDef)
|
|
||||||
make_array(addr, int(jsonDef['count']), jsonDef['type'])
|
|
||||||
set_name(addr, jsonDef['name'])
|
|
||||||
|
|
||||||
def define_field_with_value(jsonDef):
|
|
||||||
addr = parse_address(jsonDef)
|
|
||||||
set_name(addr, jsonDef['name'])
|
|
||||||
set_comment(addr, jsonDef['value'])
|
|
||||||
|
|
||||||
# Process JSON
|
|
||||||
def process_json(jsonData, status):
|
|
||||||
# Function boundaries
|
|
||||||
functionAddresses = jsonData['functionAddresses']
|
|
||||||
functionAddresses.sort()
|
|
||||||
count = len(functionAddresses)
|
|
||||||
|
|
||||||
status.update_step('Processing function boundaries', count)
|
|
||||||
for i in range(count):
|
|
||||||
start = from_hex(functionAddresses[i])
|
|
||||||
if start == 0:
|
|
||||||
status.update_progress()
|
|
||||||
continue
|
|
||||||
|
|
||||||
end = from_hex(functionAddresses[i + 1]) if i + 1 != count else None
|
|
||||||
|
|
||||||
make_function(start, end)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# Method definitions
|
|
||||||
status.update_step('Processing method definitions', len(jsonData['methodDefinitions']))
|
|
||||||
for d in jsonData['methodDefinitions']:
|
|
||||||
define_il_method(d)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# Constructed generic methods
|
|
||||||
status.update_step('Processing constructed generic methods', len(jsonData['constructedGenericMethods']))
|
|
||||||
for d in jsonData['constructedGenericMethods']:
|
|
||||||
define_il_method(d)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# Custom attributes generators
|
|
||||||
status.update_step('Processing custom attributes generators', len(jsonData['customAttributesGenerators']))
|
|
||||||
for d in jsonData['customAttributesGenerators']:
|
|
||||||
define_cpp_function(d)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# Method.Invoke thunks
|
|
||||||
status.update_step('Processing Method.Invoke thunks', len(jsonData['methodInvokers']))
|
|
||||||
for d in jsonData['methodInvokers']:
|
|
||||||
define_cpp_function(d)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# String literals for version >= 19
|
|
||||||
if 'virtualAddress' in jsonData['stringLiterals'][0]:
|
|
||||||
status.update_step('Processing string literals (V19+)', len(jsonData['stringLiterals']))
|
|
||||||
|
|
||||||
process_string_literals(status, jsonData)
|
|
||||||
|
|
||||||
# String literals for version < 19
|
|
||||||
else:
|
|
||||||
status.update_step('Processing string literals (pre-V19)')
|
|
||||||
litDecl = 'enum StringLiteralIndex {\n'
|
|
||||||
for d in jsonData['stringLiterals']:
|
|
||||||
litDecl += " " + d['name'] + ",\n"
|
|
||||||
litDecl += '};\n'
|
|
||||||
define_code(litDecl)
|
|
||||||
|
|
||||||
# Il2CppClass (TypeInfo) pointers
|
|
||||||
status.update_step('Processing Il2CppClass (TypeInfo) pointers', len(jsonData['typeInfoPointers']))
|
|
||||||
for d in jsonData['typeInfoPointers']:
|
|
||||||
define_field_from_json(d)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# Il2CppType (TypeRef) pointers
|
|
||||||
status.update_step('Processing Il2CppType (TypeRef) pointers', len(jsonData['typeRefPointers']))
|
|
||||||
for d in jsonData['typeRefPointers']:
|
|
||||||
define_field(d['virtualAddress'], d['name'], r'struct Il2CppType *', d['dotNetType'])
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# MethodInfo pointers
|
|
||||||
status.update_step('Processing MethodInfo pointers', len(jsonData['methodInfoPointers']))
|
|
||||||
for d in jsonData['methodInfoPointers']:
|
|
||||||
define_il_method_info(d)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# FieldInfo pointers, add the contents as a comment
|
|
||||||
status.update_step('Processing FieldInfo pointers', len(jsonData['fields']))
|
|
||||||
for d in jsonData['fields']:
|
|
||||||
define_field_with_value(d)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# FieldRva pointers, add the contents as a comment
|
|
||||||
status.update_step('Processing FieldRva pointers', len(jsonData['fieldRvas']))
|
|
||||||
for d in jsonData['fieldRvas']:
|
|
||||||
define_field_with_value(d)
|
|
||||||
status.update_progress()
|
|
||||||
|
|
||||||
# IL2CPP type metadata
|
|
||||||
status.update_step('Processing IL2CPP type metadata', len(jsonData['typeMetadata']))
|
|
||||||
for d in jsonData['typeMetadata']:
|
|
||||||
define_field(d['virtualAddress'], d['name'], d['type'])
|
|
||||||
|
|
||||||
# IL2CPP function metadata
|
|
||||||
status.update_step('Processing IL2CPP function metadata', len(jsonData['functionMetadata']))
|
|
||||||
for d in jsonData['functionMetadata']:
|
|
||||||
define_cpp_function(d)
|
|
||||||
|
|
||||||
# IL2CPP array metadata
|
|
||||||
status.update_step('Processing IL2CPP array metadata', len(jsonData['arrayMetadata']))
|
|
||||||
for d in jsonData['arrayMetadata']:
|
|
||||||
define_array(d)
|
|
||||||
|
|
||||||
# IL2CPP API functions
|
|
||||||
status.update_step('Processing IL2CPP API functions', len(jsonData['apis']))
|
|
||||||
for d in jsonData['apis']:
|
|
||||||
define_cpp_function(d)
|
|
||||||
|
|
||||||
# Entry point
|
|
||||||
print('Generated script file by Il2CppInspectorRedux - https://github.com/LukeFZ (Original Il2CppInspector by http://www.djkaty.com - https://github.com/djkaty)')
|
|
||||||
status = StatusHandler()
|
|
||||||
status.initialize()
|
|
||||||
|
|
||||||
try:
|
|
||||||
start_time = datetime.datetime.now()
|
|
||||||
|
|
||||||
status.update_step("Running script prologue")
|
|
||||||
script_prologue(status)
|
|
||||||
|
|
||||||
with open(os.path.join(get_script_directory(), "%JSON_METADATA_RELATIVE_PATH%"), "r") as jsonFile:
|
|
||||||
status.update_step("Loading JSON metadata")
|
|
||||||
jsonData = json.load(jsonFile)['addressMap']
|
|
||||||
process_json(jsonData, status)
|
|
||||||
|
|
||||||
status.update_step("Running script epilogue")
|
|
||||||
script_epilogue(status)
|
|
||||||
|
|
||||||
status.update_step('Script execution complete.')
|
|
||||||
print("Took: %s" % (datetime.datetime.now() - start_time))
|
|
||||||
except RuntimeError: pass
|
|
||||||
finally: status.close()
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Generated script file by Il2CppInspectorRedux - https://github.com/LukeFZ (Original Il2CppInspector by http://www.djkaty.com - https://github.com/djkaty)
|
|
||||||
# Target Unity version: %TARGET_UNITY_VERSION%
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
class BaseStatusHandler:
|
|
||||||
def initialize(self): pass
|
|
||||||
def update_step(self, name, max_items = 0): print(name)
|
|
||||||
def update_progress(self, progress = 1): pass
|
|
||||||
def was_cancelled(self): return False
|
|
||||||
def close(self): pass
|
|
||||||
290
Il2CppInspector.Common/Outputs/ScriptResources/shared_base.py
Normal file
290
Il2CppInspector.Common/Outputs/ScriptResources/shared_base.py
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
# Generated script file by Il2CppInspectorRedux - https://github.com/LukeFZ (Original Il2CppInspector by http://www.djkaty.com - https://github.com/djkaty)
|
||||||
|
# Target Unity version: %TARGET_UNITY_VERSION%
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
import abc
|
||||||
|
|
||||||
|
class BaseStatusHandler(abc.ABC):
|
||||||
|
def initialize(self): pass
|
||||||
|
def shutdown(self): pass
|
||||||
|
|
||||||
|
def update_step(self, name: str, max_items: int = 0): print(name)
|
||||||
|
def update_progress(self, progress: int = 1): pass
|
||||||
|
|
||||||
|
def was_cancelled(self): return False
|
||||||
|
|
||||||
|
class BaseDisassemblerInterface(abc.ABC):
|
||||||
|
supports_fake_string_segment: bool = False
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_script_directory(self) -> str: return ""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def on_start(self): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def on_finish(self): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def define_function(self, address: int, end: int | None = None): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def define_data_array(self, address: int, type: str, count: int): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_data_type(self, address: int, type: str): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_function_type(self, address: int, type: str): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_data_comment(self, address: int, cmt: str): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_function_comment(self, address: int, cmt: str): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_data_name(self, address: int, name: str): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_function_name(self, address: int, name: str): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def add_cross_reference(self, from_address: int, to_address: int): pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def import_c_typedef(self, type_def: str): pass
|
||||||
|
|
||||||
|
# optional
|
||||||
|
def add_function_to_group(self, address: int, group: str): pass
|
||||||
|
def cache_function_types(self, function_types: list[str]): pass
|
||||||
|
|
||||||
|
# only required if supports_fake_string_segment == True
|
||||||
|
def create_fake_segment(self, name: str, size: int) -> int: return 0
|
||||||
|
|
||||||
|
def write_string(self, address: int, value: str): pass
|
||||||
|
def write_address(self, address: int, value: int): pass
|
||||||
|
|
||||||
|
class ScriptContext:
|
||||||
|
_backend: BaseDisassemblerInterface
|
||||||
|
_status: BaseStatusHandler
|
||||||
|
|
||||||
|
def __init__(self, backend: BaseDisassemblerInterface, status: BaseStatusHandler) -> None:
|
||||||
|
self._backend = backend
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
def from_hex(self, addr: str):
|
||||||
|
return int(addr, 0)
|
||||||
|
|
||||||
|
def parse_address(self, d: dict):
|
||||||
|
return self.from_hex(d['virtualAddress'])
|
||||||
|
|
||||||
|
def define_il_method(self, definition: dict):
|
||||||
|
addr = self.parse_address(definition)
|
||||||
|
self._backend.set_function_name(addr, definition['name'])
|
||||||
|
self._backend.set_function_type(addr, definition['signature'])
|
||||||
|
self._backend.set_function_comment(addr, definition['dotNetSignature'])
|
||||||
|
self._backend.add_function_to_group(addr, definition['group'])
|
||||||
|
|
||||||
|
def define_il_method_info(self, definition: dict):
|
||||||
|
addr = self.parse_address(definition)
|
||||||
|
self._backend.set_data_type(addr, r'struct MethodInfo *')
|
||||||
|
self._backend.set_data_name(addr, definition['name'])
|
||||||
|
self._backend.set_data_comment(addr, definition['dotNetSignature'])
|
||||||
|
if 'methodAddress' in definition:
|
||||||
|
method_addr = self.from_hex(definition["methodAddress"])
|
||||||
|
self._backend.add_cross_reference(method_addr, addr)
|
||||||
|
|
||||||
|
def define_cpp_function(self, definition: dict):
|
||||||
|
addr = self.parse_address(definition)
|
||||||
|
self._backend.set_function_name(addr, definition['name'])
|
||||||
|
self._backend.set_function_type(addr, definition['signature'])
|
||||||
|
|
||||||
|
def define_string(self, definition: dict):
|
||||||
|
addr = self.parse_address(definition)
|
||||||
|
self._backend.set_data_type(addr, r'struct String *')
|
||||||
|
self._backend.set_data_name(addr, definition['name'])
|
||||||
|
self._backend.set_data_comment(addr, definition['string'])
|
||||||
|
|
||||||
|
def define_field(self, addr: str, name: str, type: str, il_type: str | None = None):
|
||||||
|
address = self.from_hex(addr)
|
||||||
|
self._backend.set_data_type(address, type)
|
||||||
|
self._backend.set_data_name(address, name)
|
||||||
|
if il_type is not None:
|
||||||
|
self._backend.set_data_comment(address, il_type)
|
||||||
|
|
||||||
|
def define_field_from_json(self, definition: dict):
|
||||||
|
self.define_field(definition['virtualAddress'], definition['name'], definition['type'], definition['dotNetType'])
|
||||||
|
|
||||||
|
def define_array(self, definition: dict):
|
||||||
|
addr = self.parse_address(definition)
|
||||||
|
self._backend.define_data_array(addr, definition['type'], int(definition['count']))
|
||||||
|
self._backend.set_data_name(addr, definition['name'])
|
||||||
|
|
||||||
|
def define_field_with_value(self, definition: dict):
|
||||||
|
addr = self.parse_address(definition)
|
||||||
|
self._backend.set_data_name(addr, definition['name'])
|
||||||
|
self._backend.set_data_comment(addr, definition['value'])
|
||||||
|
|
||||||
|
def process_metadata(self, metadata: dict):
|
||||||
|
# Function boundaries
|
||||||
|
function_addresses = metadata['functionAddresses']
|
||||||
|
function_addresses.sort()
|
||||||
|
count = len(function_addresses)
|
||||||
|
|
||||||
|
self._status.update_step('Processing function boundaries', count)
|
||||||
|
for i in range(count):
|
||||||
|
start = self.from_hex(function_addresses[i])
|
||||||
|
if start == 0:
|
||||||
|
self._status.update_progress()
|
||||||
|
continue
|
||||||
|
|
||||||
|
end = self.from_hex(function_addresses[i + 1]) if i + 1 != count else None
|
||||||
|
|
||||||
|
self._backend.define_function(start, end)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# Method definitions
|
||||||
|
self._status.update_step('Processing method definitions', len(metadata['methodDefinitions']))
|
||||||
|
self._backend.cache_function_types([x["signature"] for x in metadata['methodDefinitions']])
|
||||||
|
for d in metadata['methodDefinitions']:
|
||||||
|
self.define_il_method(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# Constructed generic methods
|
||||||
|
self._status.update_step('Processing constructed generic methods', len(metadata['constructedGenericMethods']))
|
||||||
|
self._backend.cache_function_types([x["signature"] for x in metadata['constructedGenericMethods']])
|
||||||
|
for d in metadata['constructedGenericMethods']:
|
||||||
|
self.define_il_method(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# Custom attributes generators
|
||||||
|
self._status.update_step('Processing custom attributes generators', len(metadata['customAttributesGenerators']))
|
||||||
|
self._backend.cache_function_types([x["signature"] for x in metadata['customAttributesGenerators']])
|
||||||
|
for d in metadata['customAttributesGenerators']:
|
||||||
|
self.define_cpp_function(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# Method.Invoke thunks
|
||||||
|
self._status.update_step('Processing Method.Invoke thunks', len(metadata['methodInvokers']))
|
||||||
|
self._backend.cache_function_types([x["signature"] for x in metadata['methodInvokers']])
|
||||||
|
for d in metadata['methodInvokers']:
|
||||||
|
self.define_cpp_function(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# String literals for version >= 19
|
||||||
|
if 'virtualAddress' in metadata['stringLiterals'][0]:
|
||||||
|
self._status.update_step('Processing string literals (V19+)', len(metadata['stringLiterals']))
|
||||||
|
|
||||||
|
if self._backend.supports_fake_string_segment:
|
||||||
|
total_string_length = 0
|
||||||
|
for d in metadata['stringLiterals']:
|
||||||
|
total_string_length += len(d["string"]) + 1
|
||||||
|
|
||||||
|
aligned_length = total_string_length + (4096 - (total_string_length % 4096))
|
||||||
|
segment_base = self._backend.create_fake_segment(".fake_strings", aligned_length)
|
||||||
|
|
||||||
|
current_string_address = segment_base
|
||||||
|
for d in metadata['stringLiterals']:
|
||||||
|
self.define_string(d)
|
||||||
|
|
||||||
|
ref_addr = self.parse_address(d)
|
||||||
|
self._backend.write_string(current_string_address, d["string"])
|
||||||
|
self._backend.set_data_type(ref_addr, r'const char* const')
|
||||||
|
self._backend.write_address(ref_addr, current_string_address)
|
||||||
|
|
||||||
|
current_string_address += len(d["string"]) + 1
|
||||||
|
self._status.update_progress()
|
||||||
|
else:
|
||||||
|
for d in metadata['stringLiterals']:
|
||||||
|
self.define_string(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# String literals for version < 19
|
||||||
|
else:
|
||||||
|
self._status.update_step('Processing string literals (pre-V19)')
|
||||||
|
litDecl = 'enum StringLiteralIndex {\n'
|
||||||
|
for d in metadata['stringLiterals']:
|
||||||
|
litDecl += " " + d['name'] + ",\n"
|
||||||
|
litDecl += '};\n'
|
||||||
|
|
||||||
|
self._backend.import_c_typedef(litDecl)
|
||||||
|
|
||||||
|
# Il2CppClass (TypeInfo) pointers
|
||||||
|
self._status.update_step('Processing Il2CppClass (TypeInfo) pointers', len(metadata['typeInfoPointers']))
|
||||||
|
for d in metadata['typeInfoPointers']:
|
||||||
|
self.define_field_from_json(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# Il2CppType (TypeRef) pointers
|
||||||
|
self._status.update_step('Processing Il2CppType (TypeRef) pointers', len(metadata['typeRefPointers']))
|
||||||
|
for d in metadata['typeRefPointers']:
|
||||||
|
self.define_field(d['virtualAddress'], d['name'], r'struct Il2CppType *', d['dotNetType'])
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# MethodInfo pointers
|
||||||
|
self._status.update_step('Processing MethodInfo pointers', len(metadata['methodInfoPointers']))
|
||||||
|
for d in metadata['methodInfoPointers']:
|
||||||
|
self.define_il_method_info(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# FieldInfo pointers, add the contents as a comment
|
||||||
|
self._status.update_step('Processing FieldInfo pointers', len(metadata['fields']))
|
||||||
|
for d in metadata['fields']:
|
||||||
|
self.define_field_with_value(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# FieldRva pointers, add the contents as a comment
|
||||||
|
self._status.update_step('Processing FieldRva pointers', len(metadata['fieldRvas']))
|
||||||
|
for d in metadata['fieldRvas']:
|
||||||
|
self.define_field_with_value(d)
|
||||||
|
self._status.update_progress()
|
||||||
|
|
||||||
|
# IL2CPP type metadata
|
||||||
|
self._status.update_step('Processing IL2CPP type metadata', len(metadata['typeMetadata']))
|
||||||
|
for d in metadata['typeMetadata']:
|
||||||
|
self.define_field(d['virtualAddress'], d['name'], d['type'])
|
||||||
|
|
||||||
|
# IL2CPP function metadata
|
||||||
|
self._status.update_step('Processing IL2CPP function metadata', len(metadata['functionMetadata']))
|
||||||
|
for d in metadata['functionMetadata']:
|
||||||
|
self.define_cpp_function(d)
|
||||||
|
|
||||||
|
# IL2CPP array metadata
|
||||||
|
self._status.update_step('Processing IL2CPP array metadata', len(metadata['arrayMetadata']))
|
||||||
|
for d in metadata['arrayMetadata']:
|
||||||
|
self.define_array(d)
|
||||||
|
|
||||||
|
# IL2CPP API functions
|
||||||
|
self._status.update_step('Processing IL2CPP API functions', len(metadata['apis']))
|
||||||
|
self._backend.cache_function_types([x["signature"] for x in metadata['apis']])
|
||||||
|
for d in metadata['apis']:
|
||||||
|
self.define_cpp_function(d)
|
||||||
|
|
||||||
|
def process(self):
|
||||||
|
self._status.initialize()
|
||||||
|
|
||||||
|
try:
|
||||||
|
start_time = datetime.now()
|
||||||
|
|
||||||
|
self._status.update_step("Running script prologue")
|
||||||
|
self._backend.on_start()
|
||||||
|
|
||||||
|
metadata_path = os.path.join(self._backend.get_script_directory(), "%JSON_METADATA_RELATIVE_PATH%")
|
||||||
|
with open(metadata_path, "r") as f:
|
||||||
|
self._status.update_step("Loading JSON metadata")
|
||||||
|
metadata = json.load(f)['addressMap']
|
||||||
|
self.process_metadata(metadata)
|
||||||
|
|
||||||
|
self._status.update_step("Running script epilogue")
|
||||||
|
self._backend.on_finish()
|
||||||
|
|
||||||
|
self._status.update_step('Script execution complete.')
|
||||||
|
|
||||||
|
end_time = datetime.now()
|
||||||
|
print(f"Took: {end_time - start_time}")
|
||||||
|
|
||||||
|
except RuntimeError: pass
|
||||||
|
finally: self._status.shutdown()
|
||||||
@@ -113,7 +113,8 @@ namespace Il2CppInspector
|
|||||||
// Global enable/disable flag for entire plugin system
|
// Global enable/disable flag for entire plugin system
|
||||||
// If set to false, all plugins will be unloaded
|
// If set to false, all plugins will be unloaded
|
||||||
// Disable this if you want to create standalone apps using the API but without plugins
|
// Disable this if you want to create standalone apps using the API but without plugins
|
||||||
private static bool _enabled = true;
|
private static bool _enabled = false;
|
||||||
|
|
||||||
public static bool Enabled {
|
public static bool Enabled {
|
||||||
get => _enabled;
|
get => _enabled;
|
||||||
set {
|
set {
|
||||||
@@ -123,7 +124,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// All of the detected plugins, including invalid/incompatible/non-loaded plugins
|
// All of the detected plugins, including invalid/incompatible/non-loaded plugins
|
||||||
public ObservableCollection<ManagedPlugin> ManagedPlugins { get; } = new ObservableCollection<ManagedPlugin>();
|
public ObservableCollection<ManagedPlugin> ManagedPlugins { get; } = [];
|
||||||
|
|
||||||
// All of the plugins that are loaded and available for use
|
// All of the plugins that are loaded and available for use
|
||||||
public static IEnumerable<IPlugin> AvailablePlugins => AsInstance.ManagedPlugins.Where(p => p.Available).Select(p => p.Plugin);
|
public static IEnumerable<IPlugin> AvailablePlugins => AsInstance.ManagedPlugins.Where(p => p.Available).Select(p => p.Plugin);
|
||||||
@@ -136,7 +137,7 @@ namespace Il2CppInspector
|
|||||||
=> AsInstance.ManagedPlugins.Where(p => p.Available).ToDictionary(p => p.Plugin.Id, p => p);
|
=> AsInstance.ManagedPlugins.Where(p => p.Available).ToDictionary(p => p.Plugin.Id, p => p);
|
||||||
|
|
||||||
// The relative path from the executable that we'll search for plugins
|
// The relative path from the executable that we'll search for plugins
|
||||||
private static string pluginFolder = Path.GetFullPath(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + Path.DirectorySeparatorChar + "plugins");
|
private static string pluginFolder = Path.GetFullPath(Path.GetDirectoryName(Environment.ProcessPath) + Path.DirectorySeparatorChar + "plugins");
|
||||||
|
|
||||||
// A placeholder plugin to be used when the real plugin cannot be loaded for some reason
|
// A placeholder plugin to be used when the real plugin cannot be loaded for some reason
|
||||||
private class InvalidPlugin : IPlugin
|
private class InvalidPlugin : IPlugin
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
namespace Il2CppInspector.Reflection {
|
namespace Il2CppInspector.Reflection {
|
||||||
public class Assembly
|
public class Assembly
|
||||||
@@ -43,37 +45,38 @@ namespace Il2CppInspector.Reflection {
|
|||||||
public Assembly(TypeModel model, int imageIndex) {
|
public Assembly(TypeModel model, int imageIndex) {
|
||||||
Model = model;
|
Model = model;
|
||||||
ImageDefinition = Model.Package.Images[imageIndex];
|
ImageDefinition = Model.Package.Images[imageIndex];
|
||||||
AssemblyDefinition = Model.Package.Assemblies[ImageDefinition.assemblyIndex];
|
AssemblyDefinition = Model.Package.Assemblies[ImageDefinition.AssemblyIndex];
|
||||||
|
|
||||||
if (AssemblyDefinition.imageIndex != imageIndex)
|
if (AssemblyDefinition.ImageIndex != imageIndex)
|
||||||
throw new InvalidOperationException("Assembly/image index mismatch");
|
throw new InvalidOperationException("Assembly/image index mismatch");
|
||||||
|
|
||||||
MetadataToken = (int) AssemblyDefinition.token;
|
MetadataToken = (int) AssemblyDefinition.Token;
|
||||||
Index = ImageDefinition.assemblyIndex;
|
Index = ImageDefinition.AssemblyIndex;
|
||||||
ShortName = Model.Package.Strings[ImageDefinition.nameIndex];
|
ShortName = Model.Package.Strings[ImageDefinition.NameIndex];
|
||||||
|
|
||||||
// Get full assembly name
|
// Get full assembly name
|
||||||
var nameDef = AssemblyDefinition.aname;
|
var nameDef = AssemblyDefinition.Aname;
|
||||||
var name = Regex.Replace(Model.Package.Strings[nameDef.nameIndex], @"[^A-Za-z0-9_\-\.()]", "");
|
var name = Regex.Replace(Model.Package.Strings[nameDef.NameIndex], @"[^A-Za-z0-9_\-\.()]", "");
|
||||||
var culture = Model.Package.Strings[nameDef.cultureIndex];
|
var culture = Model.Package.Strings[nameDef.CultureIndex];
|
||||||
if (string.IsNullOrEmpty(culture))
|
if (string.IsNullOrEmpty(culture))
|
||||||
culture = "neutral";
|
culture = "neutral";
|
||||||
var pkt = BitConverter.ToString(nameDef.publicKeyToken).Replace("-", "");
|
var pkt = Convert.ToHexString(nameDef.PublicKeyToken);
|
||||||
if (pkt == "0000000000000000")
|
if (pkt == "0000000000000000")
|
||||||
pkt = "null";
|
pkt = "null";
|
||||||
var version = string.Format($"{nameDef.major}.{nameDef.minor}.{nameDef.build}.{nameDef.revision}");
|
var version = string.Format($"{nameDef.Major}.{nameDef.Minor}.{nameDef.Build}.{nameDef.Revision}");
|
||||||
|
|
||||||
FullName = string.Format($"{name}, Version={version}, Culture={culture}, PublicKeyToken={pkt.ToLower()}");
|
FullName = string.Format($"{name}, Version={version}, Culture={culture}, PublicKeyToken={pkt.ToLower()}");
|
||||||
|
|
||||||
if (ImageDefinition.entryPointIndex != -1) {
|
if (ImageDefinition.EntryPointIndex != -1) {
|
||||||
// TODO: Generate EntryPoint method from entryPointIndex
|
// TODO: Generate EntryPoint method from entryPointIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find corresponding module (we'll need this for method pointers)
|
// Find corresponding module (we'll need this for method pointers on V24.2+)
|
||||||
ModuleDefinition = Model.Package.Modules?[ShortName];
|
if (Model.Package.Modules != null)
|
||||||
|
ModuleDefinition = Model.Package.Modules[ShortName];
|
||||||
|
|
||||||
// Generate types in DefinedTypes from typeStart to typeStart+typeCount-1
|
// Generate types in DefinedTypes from typeStart to typeStart+typeCount-1
|
||||||
for (var t = ImageDefinition.typeStart; t < ImageDefinition.typeStart + ImageDefinition.typeCount; t++) {
|
for (var t = ImageDefinition.TypeStart; t < ImageDefinition.TypeStart + ImageDefinition.TypeCount; t++) {
|
||||||
var type = new TypeInfo(t, this);
|
var type = new TypeInfo(t, this);
|
||||||
|
|
||||||
// Don't add empty module definitions
|
// Don't add empty module definitions
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using Il2CppInspector.Next;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -88,13 +89,13 @@ namespace Il2CppInspector.Reflection
|
|||||||
var pkg = asm.Model.Package;
|
var pkg = asm.Model.Package;
|
||||||
|
|
||||||
// Attribute type ranges weren't included before v21 (customASttributeGenerators was though)
|
// Attribute type ranges weren't included before v21 (customASttributeGenerators was though)
|
||||||
if (pkg.Version < 21)
|
if (pkg.Version < MetadataVersions.V210)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
if (pkg.Version < 29)
|
if (pkg.Version < MetadataVersions.V290)
|
||||||
{
|
{
|
||||||
var range = pkg.AttributeTypeRanges[customAttributeIndex];
|
var range = pkg.AttributeTypeRanges[customAttributeIndex];
|
||||||
for (var i = range.start; i < range.start + range.count; i++)
|
for (var i = range.Start; i < range.Start + range.Count; i++)
|
||||||
{
|
{
|
||||||
var typeIndex = pkg.AttributeTypeIndices[i];
|
var typeIndex = pkg.AttributeTypeIndices[i];
|
||||||
|
|
||||||
@@ -117,8 +118,8 @@ namespace Il2CppInspector.Reflection
|
|||||||
var range = pkg.Metadata.AttributeDataRanges[customAttributeIndex];
|
var range = pkg.Metadata.AttributeDataRanges[customAttributeIndex];
|
||||||
var next = pkg.Metadata.AttributeDataRanges[customAttributeIndex + 1];
|
var next = pkg.Metadata.AttributeDataRanges[customAttributeIndex + 1];
|
||||||
|
|
||||||
var startOffset = pkg.Metadata.Header.attributeDataOffset + range.startOffset;
|
var startOffset = (uint)pkg.Metadata.Header.AttributeDataOffset + range.StartOffset;
|
||||||
var endOffset = pkg.Metadata.Header.attributeDataOffset + next.startOffset;
|
var endOffset = (uint)pkg.Metadata.Header.AttributeDataOffset + next.StartOffset;
|
||||||
|
|
||||||
var reader = new CustomAttributeDataReader(pkg, asm, pkg.Metadata, startOffset, endOffset);
|
var reader = new CustomAttributeDataReader(pkg, asm, pkg.Metadata, startOffset, endOffset);
|
||||||
if (reader.Count == 0)
|
if (reader.Count == 0)
|
||||||
@@ -142,13 +143,17 @@ namespace Il2CppInspector.Reflection
|
|||||||
public static IList<CustomAttributeData> GetCustomAttributes(Assembly asm, int token, int customAttributeIndex) =>
|
public static IList<CustomAttributeData> GetCustomAttributes(Assembly asm, int token, int customAttributeIndex) =>
|
||||||
getCustomAttributes(asm, asm.Model.GetCustomAttributeIndex(asm, token, customAttributeIndex)).ToList();
|
getCustomAttributes(asm, asm.Model.GetCustomAttributeIndex(asm, token, customAttributeIndex)).ToList();
|
||||||
|
|
||||||
public static IList<CustomAttributeData> GetCustomAttributes(Assembly asm) => GetCustomAttributes(asm, asm.MetadataToken, asm.AssemblyDefinition.customAttributeIndex);
|
public static IList<CustomAttributeData> GetCustomAttributes(Assembly asm) => GetCustomAttributes(asm, asm.MetadataToken, asm.AssemblyDefinition.CustomAttributeIndex);
|
||||||
public static IList<CustomAttributeData> GetCustomAttributes(EventInfo evt) => GetCustomAttributes(evt.Assembly, evt.MetadataToken, evt.Definition.customAttributeIndex);
|
public static IList<CustomAttributeData> GetCustomAttributes(EventInfo evt) => GetCustomAttributes(evt.Assembly, evt.MetadataToken, evt.Definition.CustomAttributeIndex);
|
||||||
public static IList<CustomAttributeData> GetCustomAttributes(FieldInfo field) => GetCustomAttributes(field.Assembly, field.MetadataToken, field.Definition.customAttributeIndex);
|
public static IList<CustomAttributeData> GetCustomAttributes(FieldInfo field) => GetCustomAttributes(field.Assembly, field.MetadataToken, field.Definition.CustomAttributeIndex);
|
||||||
public static IList<CustomAttributeData> GetCustomAttributes(MethodBase method) => GetCustomAttributes(method.Assembly, method.MetadataToken, method.Definition.customAttributeIndex);
|
public static IList<CustomAttributeData> GetCustomAttributes(MethodBase method) => GetCustomAttributes(method.Assembly, method.MetadataToken, method.Definition.CustomAttributeIndex);
|
||||||
public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo param) => GetCustomAttributes(param.DeclaringMethod.Assembly, param.MetadataToken, param.Definition.customAttributeIndex);
|
public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo param) => GetCustomAttributes(param.DeclaringMethod.Assembly, param.MetadataToken, param.Definition.CustomAttributeIndex);
|
||||||
public static IList<CustomAttributeData> GetCustomAttributes(PropertyInfo prop)
|
public static IList<CustomAttributeData> GetCustomAttributes(PropertyInfo prop)
|
||||||
=> prop.Definition != null ? GetCustomAttributes(prop.Assembly, prop.MetadataToken, prop.Definition.customAttributeIndex) : new List<CustomAttributeData>();
|
=> prop.Definition.IsValid
|
||||||
public static IList<CustomAttributeData> GetCustomAttributes(TypeInfo type) => type.Definition != null? GetCustomAttributes(type.Assembly, type.MetadataToken, type.Definition.customAttributeIndex) : new List<CustomAttributeData>();
|
? GetCustomAttributes(prop.Assembly, prop.MetadataToken, prop.Definition.CustomAttributeIndex)
|
||||||
|
: new List<CustomAttributeData>();
|
||||||
|
public static IList<CustomAttributeData> GetCustomAttributes(TypeInfo type) => type.Definition.IsValid
|
||||||
|
? GetCustomAttributes(type.Assembly, type.MetadataToken, type.Definition.CustomAttributeIndex)
|
||||||
|
: new List<CustomAttributeData>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
namespace Il2CppInspector.Reflection
|
namespace Il2CppInspector.Reflection
|
||||||
{
|
{
|
||||||
@@ -41,25 +42,25 @@ namespace Il2CppInspector.Reflection
|
|||||||
public EventInfo(Il2CppInspector pkg, int eventIndex, TypeInfo declaringType) :
|
public EventInfo(Il2CppInspector pkg, int eventIndex, TypeInfo declaringType) :
|
||||||
base(declaringType) {
|
base(declaringType) {
|
||||||
Definition = pkg.Events[eventIndex];
|
Definition = pkg.Events[eventIndex];
|
||||||
MetadataToken = (int) Definition.token;
|
MetadataToken = (int) Definition.Token;
|
||||||
Index = eventIndex;
|
Index = eventIndex;
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.NameIndex];
|
||||||
rootDefinition = this;
|
rootDefinition = this;
|
||||||
|
|
||||||
eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex);
|
eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.TypeIndex);
|
||||||
var eventType = pkg.TypeReferences[Definition.typeIndex];
|
var eventType = pkg.TypeReferences[Definition.TypeIndex];
|
||||||
|
|
||||||
// Copy attributes
|
// Copy attributes
|
||||||
Attributes = (EventAttributes) eventType.attrs;
|
Attributes = (EventAttributes) eventType.Attrs;
|
||||||
|
|
||||||
// NOTE: This relies on methods being added to TypeInfo.DeclaredMethods in the same order they are defined in the Il2Cpp metadata
|
// NOTE: This relies on methods being added to TypeInfo.DeclaredMethods in the same order they are defined in the Il2Cpp metadata
|
||||||
// add, remove and raise are method indices from the first method of the declaring type
|
// add, remove and raise are method indices from the first method of the declaring type
|
||||||
if (Definition.add >= 0)
|
if (Definition.Add >= 0)
|
||||||
AddMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.add);
|
AddMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Add);
|
||||||
if (Definition.remove >= 0)
|
if (Definition.Remove >= 0)
|
||||||
RemoveMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.remove);
|
RemoveMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Remove);
|
||||||
if (Definition.raise >= 0)
|
if (Definition.Raise >= 0)
|
||||||
RaiseMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.raise);
|
RaiseMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Raise);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventInfo(EventInfo eventDef, TypeInfo declaringType) : base(declaringType) {
|
public EventInfo(EventInfo eventDef, TypeInfo declaringType) : base(declaringType) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
namespace Il2CppInspector.Reflection {
|
namespace Il2CppInspector.Reflection {
|
||||||
public class FieldInfo : MemberInfo // L-TODO: Add support for [ThreadLocal] fields
|
public class FieldInfo : MemberInfo // L-TODO: Add support for [ThreadLocal] fields
|
||||||
@@ -96,9 +97,9 @@ namespace Il2CppInspector.Reflection {
|
|||||||
public FieldInfo(Il2CppInspector pkg, int fieldIndex, TypeInfo declaringType) :
|
public FieldInfo(Il2CppInspector pkg, int fieldIndex, TypeInfo declaringType) :
|
||||||
base(declaringType) {
|
base(declaringType) {
|
||||||
Definition = pkg.Fields[fieldIndex];
|
Definition = pkg.Fields[fieldIndex];
|
||||||
MetadataToken = (int) Definition.token;
|
MetadataToken = (int) Definition.Token;
|
||||||
Index = fieldIndex;
|
Index = fieldIndex;
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.NameIndex];
|
||||||
|
|
||||||
rawOffset = pkg.FieldOffsets[fieldIndex];
|
rawOffset = pkg.FieldOffsets[fieldIndex];
|
||||||
if (0 > rawOffset)
|
if (0 > rawOffset)
|
||||||
@@ -109,11 +110,11 @@ namespace Il2CppInspector.Reflection {
|
|||||||
|
|
||||||
rootDefinition = this;
|
rootDefinition = this;
|
||||||
|
|
||||||
fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex);
|
fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.TypeIndex);
|
||||||
var fieldType = pkg.TypeReferences[Definition.typeIndex];
|
var fieldType = pkg.TypeReferences[Definition.TypeIndex];
|
||||||
|
|
||||||
// Copy attributes
|
// Copy attributes
|
||||||
Attributes = (FieldAttributes) fieldType.attrs;
|
Attributes = (FieldAttributes) fieldType.Attrs;
|
||||||
|
|
||||||
// Default initialization value if present
|
// Default initialization value if present
|
||||||
if (pkg.FieldDefaultValue.TryGetValue(fieldIndex, out (ulong address, object variant) value)) {
|
if (pkg.FieldDefaultValue.TryGetValue(fieldIndex, out (ulong address, object variant) value)) {
|
||||||
@@ -123,7 +124,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public FieldInfo(FieldInfo fieldDef, TypeInfo declaringType) : base(declaringType) {
|
public FieldInfo(FieldInfo fieldDef, TypeInfo declaringType) : base(declaringType) {
|
||||||
if (fieldDef.Definition == null)
|
if (!fieldDef.Definition.IsValid)
|
||||||
throw new ArgumentException("Argument must be a bare field definition");
|
throw new ArgumentException("Argument must be a bare field definition");
|
||||||
|
|
||||||
rootDefinition = fieldDef;
|
rootDefinition = fieldDef;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
namespace Il2CppInspector.Reflection
|
namespace Il2CppInspector.Reflection
|
||||||
{
|
{
|
||||||
@@ -117,9 +118,9 @@ namespace Il2CppInspector.Reflection
|
|||||||
// Initialize a method from a method definition (MethodDef)
|
// Initialize a method from a method definition (MethodDef)
|
||||||
protected MethodBase(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(declaringType) {
|
protected MethodBase(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(declaringType) {
|
||||||
Definition = pkg.Methods[methodIndex];
|
Definition = pkg.Methods[methodIndex];
|
||||||
MetadataToken = (int) Definition.token;
|
MetadataToken = (int) Definition.Token;
|
||||||
Index = methodIndex;
|
Index = methodIndex;
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.NameIndex];
|
||||||
|
|
||||||
// Find method pointer
|
// Find method pointer
|
||||||
VirtualAddress = pkg.GetMethodPointer(Assembly.ModuleDefinition, Definition);
|
VirtualAddress = pkg.GetMethodPointer(Assembly.ModuleDefinition, Definition);
|
||||||
@@ -130,28 +131,28 @@ namespace Il2CppInspector.Reflection
|
|||||||
rootDefinition = this;
|
rootDefinition = this;
|
||||||
|
|
||||||
// Generic method definition?
|
// Generic method definition?
|
||||||
if (Definition.genericContainerIndex >= 0) {
|
if (Definition.GenericContainerIndex >= 0) {
|
||||||
IsGenericMethod = true;
|
IsGenericMethod = true;
|
||||||
|
|
||||||
// Store the generic type parameters for later instantiation
|
// Store the generic type parameters for later instantiation
|
||||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
var container = pkg.GenericContainers[Definition.GenericContainerIndex];
|
||||||
genericArguments = Enumerable.Range((int)container.genericParameterStart, container.type_argc)
|
genericArguments = Enumerable.Range(container.GenericParameterStart, container.TypeArgc)
|
||||||
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
||||||
genericMethodInstances = new Dictionary<TypeInfo[], MethodBase>(new TypeInfo.TypeArgumentsComparer());
|
genericMethodInstances = new Dictionary<TypeInfo[], MethodBase>(new TypeInfo.TypeArgumentsComparer());
|
||||||
genericMethodInstances[genericArguments] = this;
|
genericMethodInstances[genericArguments] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy attributes
|
// Copy attributes
|
||||||
Attributes = (MethodAttributes) Definition.flags;
|
Attributes = (MethodAttributes) Definition.Flags;
|
||||||
MethodImplementationFlags = (MethodImplAttributes) Definition.iflags;
|
MethodImplementationFlags = (MethodImplAttributes) Definition.ImplFlags;
|
||||||
|
|
||||||
// Add arguments
|
// Add arguments
|
||||||
for (var p = Definition.parameterStart; p < Definition.parameterStart + Definition.parameterCount; p++)
|
for (var p = Definition.ParameterStart; p < Definition.ParameterStart + Definition.ParameterCount; p++)
|
||||||
DeclaredParameters.Add(new ParameterInfo(pkg, p, this));
|
DeclaredParameters.Add(new ParameterInfo(pkg, p, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MethodBase(MethodBase methodDef, TypeInfo declaringType) : base(declaringType) {
|
protected MethodBase(MethodBase methodDef, TypeInfo declaringType) : base(declaringType) {
|
||||||
if (methodDef.Definition == null)
|
if (!methodDef.Definition.IsValid)
|
||||||
throw new ArgumentException("Argument must be a bare method definition");
|
throw new ArgumentException("Argument must be a bare method definition");
|
||||||
|
|
||||||
rootDefinition = methodDef;
|
rootDefinition = methodDef;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
namespace Il2CppInspector.Reflection
|
namespace Il2CppInspector.Reflection
|
||||||
{
|
{
|
||||||
@@ -64,28 +65,28 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
if (paramIndex == -1) {
|
if (paramIndex == -1) {
|
||||||
Position = -1;
|
Position = -1;
|
||||||
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, declaringMethod.Definition.returnType);
|
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, declaringMethod.Definition.ReturnType);
|
||||||
MetadataToken = declaringMethod.Definition.returnParameterToken;
|
MetadataToken = (int)declaringMethod.Definition.ReturnParameterToken;
|
||||||
Attributes |= ParameterAttributes.Retval;
|
Attributes |= ParameterAttributes.Retval;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Definition = pkg.Params[Index];
|
Definition = pkg.Params[Index];
|
||||||
MetadataToken = (int) Definition.token;
|
MetadataToken = (int) Definition.Token;
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.NameIndex];
|
||||||
rootDefinition = this;
|
rootDefinition = this;
|
||||||
|
|
||||||
// Handle unnamed/obfuscated parameter names
|
// Handle unnamed/obfuscated parameter names
|
||||||
if (string.IsNullOrEmpty(Name))
|
if (string.IsNullOrEmpty(Name))
|
||||||
Name = string.Format($"param_{Index:x8}");
|
Name = string.Format($"param_{Index:x8}");
|
||||||
|
|
||||||
Position = paramIndex - declaringMethod.Definition.parameterStart;
|
Position = paramIndex - declaringMethod.Definition.ParameterStart;
|
||||||
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, Definition.typeIndex);
|
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, Definition.TypeIndex);
|
||||||
|
|
||||||
var paramType = pkg.TypeReferences[Definition.typeIndex];
|
var paramType = pkg.TypeReferences[Definition.TypeIndex];
|
||||||
|
|
||||||
// Copy attributes
|
// Copy attributes
|
||||||
Attributes = (ParameterAttributes) paramType.attrs;
|
Attributes = (ParameterAttributes) paramType.Attrs;
|
||||||
|
|
||||||
// Default initialization value if present
|
// Default initialization value if present
|
||||||
if (pkg.ParameterDefaultValue.TryGetValue(paramIndex, out (ulong address, object variant) value)) {
|
if (pkg.ParameterDefaultValue.TryGetValue(paramIndex, out (ulong address, object variant) value)) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
namespace Il2CppInspector.Reflection {
|
namespace Il2CppInspector.Reflection {
|
||||||
public class PropertyInfo : MemberInfo
|
public class PropertyInfo : MemberInfo
|
||||||
@@ -52,25 +53,24 @@ namespace Il2CppInspector.Reflection {
|
|||||||
base(declaringType) {
|
base(declaringType) {
|
||||||
Index = propIndex;
|
Index = propIndex;
|
||||||
Definition = pkg.Properties[propIndex];
|
Definition = pkg.Properties[propIndex];
|
||||||
MetadataToken = (int) Definition.token;
|
MetadataToken = (int) Definition.Token;
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.NameIndex];
|
||||||
rootDefinition = this;
|
rootDefinition = this;
|
||||||
|
|
||||||
// Copy attributes
|
// Copy attributes
|
||||||
Attributes = (PropertyAttributes) Definition.attrs;
|
Attributes = (PropertyAttributes) Definition.Attrs;
|
||||||
|
|
||||||
// prop.get and prop.set are method indices from the first method of the declaring type
|
// prop.get and prop.set are method indices from the first method of the declaring type
|
||||||
if (Definition.get >= 0)
|
if (Definition.Get >= 0)
|
||||||
GetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.get);
|
GetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Get);
|
||||||
if (Definition.set >= 0)
|
if (Definition.Set >= 0)
|
||||||
SetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.set);
|
SetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Set);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a property based on a get and set method
|
// Create a property based on a get and set method
|
||||||
public PropertyInfo(MethodInfo getter, MethodInfo setter, TypeInfo declaringType) :
|
public PropertyInfo(MethodInfo getter, MethodInfo setter, TypeInfo declaringType) :
|
||||||
base(declaringType) {
|
base(declaringType) {
|
||||||
Index = -1;
|
Index = -1;
|
||||||
Definition = null;
|
|
||||||
rootDefinition = this;
|
rootDefinition = this;
|
||||||
|
|
||||||
Name = (getter ?? setter).Name.Replace(".get_", ".").Replace(".set_", ".");
|
Name = (getter ?? setter).Name.Replace(".get_", ".").Replace(".set_", ".");
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Il2CppInspector.Next.BinaryMetadata;
|
||||||
|
using Il2CppInspector.Next.Metadata;
|
||||||
|
|
||||||
namespace Il2CppInspector.Reflection
|
namespace Il2CppInspector.Reflection
|
||||||
{
|
{
|
||||||
@@ -53,9 +55,9 @@ namespace Il2CppInspector.Reflection
|
|||||||
return null;
|
return null;
|
||||||
if (IsArray)
|
if (IsArray)
|
||||||
return Assembly.Model.TypesByFullName["System.Array"];
|
return Assembly.Model.TypesByFullName["System.Array"];
|
||||||
if (Definition != null) {
|
if (Definition.IsValid) {
|
||||||
if (Definition.parentIndex >= 0)
|
if (Definition.ParentIndex >= 0)
|
||||||
return Assembly.Model.TypesByReferenceIndex[Definition.parentIndex];
|
return Assembly.Model.TypesByReferenceIndex[Definition.ParentIndex];
|
||||||
}
|
}
|
||||||
if (genericTypeDefinition != null) {
|
if (genericTypeDefinition != null) {
|
||||||
return genericTypeDefinition.BaseType.SubstituteGenericArguments(genericArguments);
|
return genericTypeDefinition.BaseType.SubstituteGenericArguments(genericArguments);
|
||||||
@@ -73,15 +75,15 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
public override TypeInfo DeclaringType {
|
public override TypeInfo DeclaringType {
|
||||||
get {
|
get {
|
||||||
if (Definition != null) {
|
if (Definition.IsValid) {
|
||||||
/* Type definition */
|
/* Type definition */
|
||||||
if (Definition.declaringTypeIndex == -1)
|
if (Definition.DeclaringTypeIndex == -1)
|
||||||
return null;
|
return null;
|
||||||
var type = Assembly.Model.TypesByReferenceIndex[Definition.declaringTypeIndex];
|
var type = Assembly.Model.TypesByReferenceIndex[Definition.DeclaringTypeIndex];
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
/* This might happen while initially setting up the types */
|
/* This might happen while initially setting up the types */
|
||||||
var typeRef = Assembly.Model.Package.TypeReferences[Definition.declaringTypeIndex];
|
var typeRef = Assembly.Model.Package.TypeReferences[Definition.DeclaringTypeIndex];
|
||||||
type = Assembly.Model.TypesByDefinitionIndex[(int)typeRef.datapoint];
|
type = Assembly.Model.TypesByDefinitionIndex[typeRef.Data.KlassIndex];
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@@ -253,11 +255,11 @@ namespace Il2CppInspector.Reflection
|
|||||||
public PropertyInfo GetProperty(string name) => DeclaredProperties.FirstOrDefault(p => p.Name == name);
|
public PropertyInfo GetProperty(string name) => DeclaredProperties.FirstOrDefault(p => p.Name == name);
|
||||||
|
|
||||||
public MethodBase[] GetVTable() {
|
public MethodBase[] GetVTable() {
|
||||||
if (Definition != null) {
|
if (!Definition.IsValid) {
|
||||||
MetadataUsage[] vt = Assembly.Model.Package.GetVTable(Definition);
|
MetadataUsage[] vt = Assembly.Model.Package.GetVTable(Definition);
|
||||||
MethodBase[] res = new MethodBase[vt.Length];
|
MethodBase[] res = new MethodBase[vt.Length];
|
||||||
for (int i = 0; i < vt.Length; i++) {
|
for (int i = 0; i < vt.Length; i++) {
|
||||||
if (vt[i] != null)
|
if (vt[i].IsValid)
|
||||||
res[i] = Assembly.Model.GetMetadataUsageMethod(vt[i]);
|
res[i] = Assembly.Model.GetMetadataUsageMethod(vt[i]);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
@@ -667,7 +669,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
private readonly TypeRef[] implementedInterfaceReferences;
|
private readonly TypeRef[] implementedInterfaceReferences;
|
||||||
public IEnumerable<TypeInfo> ImplementedInterfaces {
|
public IEnumerable<TypeInfo> ImplementedInterfaces {
|
||||||
get {
|
get {
|
||||||
if (Definition != null)
|
if (Definition.IsValid)
|
||||||
return implementedInterfaceReferences.Select(x => x.Value);
|
return implementedInterfaceReferences.Select(x => x.Value);
|
||||||
if (genericTypeDefinition != null)
|
if (genericTypeDefinition != null)
|
||||||
return genericTypeDefinition.ImplementedInterfaces.Select(t => t.SubstituteGenericArguments(genericArguments));
|
return genericTypeDefinition.ImplementedInterfaces.Select(t => t.SubstituteGenericArguments(genericArguments));
|
||||||
@@ -687,7 +689,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
public bool IsEnum { get; }
|
public bool IsEnum { get; }
|
||||||
public bool IsGenericParameter { get; }
|
public bool IsGenericParameter { get; }
|
||||||
public bool IsGenericType { get; }
|
public bool IsGenericType { get; }
|
||||||
public bool IsGenericTypeDefinition => (Definition != null) && genericArguments.Any();
|
public bool IsGenericTypeDefinition => (Definition.IsValid) && genericArguments.Any();
|
||||||
public bool IsImport => (Attributes & TypeAttributes.Import) == TypeAttributes.Import;
|
public bool IsImport => (Attributes & TypeAttributes.Import) == TypeAttributes.Import;
|
||||||
public bool IsInterface => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
|
public bool IsInterface => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
|
||||||
public bool IsNested => (MemberType & MemberTypes.NestedType) == MemberTypes.NestedType;
|
public bool IsNested => (MemberType & MemberTypes.NestedType) == MemberTypes.NestedType;
|
||||||
@@ -746,13 +748,13 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
Definition = pkg.TypeDefinitions[typeIndex];
|
Definition = pkg.TypeDefinitions[typeIndex];
|
||||||
Sizes = pkg.TypeDefinitionSizes[typeIndex];
|
Sizes = pkg.TypeDefinitionSizes[typeIndex];
|
||||||
MetadataToken = (int) Definition.token;
|
MetadataToken = (int) Definition.Token;
|
||||||
Index = typeIndex;
|
Index = typeIndex;
|
||||||
Namespace = Regex.Replace(pkg.Strings[Definition.namespaceIndex], @"[^A-Za-z0-9_\-\.<>{}]", "");
|
Namespace = Regex.Replace(pkg.Strings[Definition.NamespaceIndex], @"[^A-Za-z0-9_\-\.<>{}]", "");
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.NameIndex];
|
||||||
|
|
||||||
// Nested type?
|
// Nested type?
|
||||||
if (Definition.declaringTypeIndex >= 0) {
|
if (Definition.DeclaringTypeIndex >= 0) {
|
||||||
MemberType |= MemberTypes.NestedType;
|
MemberType |= MemberTypes.NestedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -760,14 +762,14 @@ namespace Il2CppInspector.Reflection
|
|||||||
Assembly.Model.TypesByDefinitionIndex[Index] = this;
|
Assembly.Model.TypesByDefinitionIndex[Index] = this;
|
||||||
|
|
||||||
// Generic type definition?
|
// Generic type definition?
|
||||||
if (Definition.genericContainerIndex >= 0) {
|
if (Definition.GenericContainerIndex >= 0) {
|
||||||
IsGenericType = true;
|
IsGenericType = true;
|
||||||
IsGenericParameter = false;
|
IsGenericParameter = false;
|
||||||
|
|
||||||
// Store the generic type parameters for later instantiation
|
// Store the generic type parameters for later instantiation
|
||||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
var container = pkg.GenericContainers[Definition.GenericContainerIndex];
|
||||||
|
|
||||||
genericArguments = Enumerable.Range((int)container.genericParameterStart, container.type_argc)
|
genericArguments = Enumerable.Range((int)container.GenericParameterStart, container.TypeArgc)
|
||||||
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
||||||
genericTypeInstances = new Dictionary<TypeInfo[], TypeInfo>(new TypeArgumentsComparer());
|
genericTypeInstances = new Dictionary<TypeInfo[], TypeInfo>(new TypeArgumentsComparer());
|
||||||
genericTypeInstances[genericArguments] = this;
|
genericTypeInstances[genericArguments] = this;
|
||||||
@@ -777,12 +779,12 @@ namespace Il2CppInspector.Reflection
|
|||||||
Assembly.Model.TypesByFullName[FullName] = this;
|
Assembly.Model.TypesByFullName[FullName] = this;
|
||||||
|
|
||||||
// Copy attributes
|
// Copy attributes
|
||||||
Attributes = (TypeAttributes) Definition.flags;
|
Attributes = (TypeAttributes) Definition.Flags;
|
||||||
|
|
||||||
// Enumerations - bit 1 of bitfield indicates this (also the baseTypeReference will be System.Enum)
|
// Enumerations - bit 1 of bitfield indicates this (also the baseTypeReference will be System.Enum)
|
||||||
if (((Definition.bitfield >> 1) & 1) == 1) {
|
if (Definition.Bitfield.EnumType) {
|
||||||
IsEnum = true;
|
IsEnum = true;
|
||||||
enumUnderlyingTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.elementTypeIndex);
|
enumUnderlyingTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.ElementTypeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass-by-reference type
|
// Pass-by-reference type
|
||||||
@@ -792,24 +794,24 @@ namespace Il2CppInspector.Reflection
|
|||||||
IsByRef = false;
|
IsByRef = false;
|
||||||
|
|
||||||
// Add all implemented interfaces
|
// Add all implemented interfaces
|
||||||
implementedInterfaceReferences = new TypeRef[Definition.interfaces_count];
|
implementedInterfaceReferences = new TypeRef[Definition.InterfacesCount];
|
||||||
for (var i = 0; i < Definition.interfaces_count; i++)
|
for (var i = 0; i < Definition.InterfacesCount; i++)
|
||||||
implementedInterfaceReferences[i] = TypeRef.FromReferenceIndex(Assembly.Model, pkg.InterfaceUsageIndices[Definition.interfacesStart + i]);
|
implementedInterfaceReferences[i] = TypeRef.FromReferenceIndex(Assembly.Model, pkg.InterfaceUsageIndices[Definition.InterfacesIndex + i]);
|
||||||
|
|
||||||
// Add all nested types
|
// Add all nested types
|
||||||
declaredNestedTypes = new TypeRef[Definition.nested_type_count];
|
declaredNestedTypes = new TypeRef[Definition.NestedTypeCount];
|
||||||
for (var n = 0; n < Definition.nested_type_count; n++)
|
for (var n = 0; n < Definition.NestedTypeCount; n++)
|
||||||
declaredNestedTypes[n] = TypeRef.FromDefinitionIndex(Assembly.Model, pkg.NestedTypeIndices[Definition.nestedTypesStart + n]);
|
declaredNestedTypes[n] = TypeRef.FromDefinitionIndex(Assembly.Model, pkg.NestedTypeIndices[Definition.NestedTypeIndex + n]);
|
||||||
|
|
||||||
// Add all fields
|
// Add all fields
|
||||||
declaredFields = new List<FieldInfo>();
|
declaredFields = new List<FieldInfo>();
|
||||||
for (var f = Definition.fieldStart; f < Definition.fieldStart + Definition.field_count; f++)
|
for (var f = Definition.FieldIndex; f < Definition.FieldIndex + Definition.FieldCount; f++)
|
||||||
declaredFields.Add(new FieldInfo(pkg, f, this));
|
declaredFields.Add(new FieldInfo(pkg, f, this));
|
||||||
|
|
||||||
// Add all methods
|
// Add all methods
|
||||||
declaredConstructors = new List<ConstructorInfo>();
|
declaredConstructors = new List<ConstructorInfo>();
|
||||||
declaredMethods = new List<MethodInfo>();
|
declaredMethods = new List<MethodInfo>();
|
||||||
for (var m = Definition.methodStart; m < Definition.methodStart + Definition.method_count; m++) {
|
for (var m = Definition.MethodIndex; m < Definition.MethodIndex + Definition.MethodCount; m++) {
|
||||||
var method = new MethodInfo(pkg, m, this);
|
var method = new MethodInfo(pkg, m, this);
|
||||||
if (method.Name == ConstructorInfo.ConstructorName || method.Name == ConstructorInfo.TypeConstructorName)
|
if (method.Name == ConstructorInfo.ConstructorName || method.Name == ConstructorInfo.TypeConstructorName)
|
||||||
declaredConstructors.Add(new ConstructorInfo(pkg, m, this));
|
declaredConstructors.Add(new ConstructorInfo(pkg, m, this));
|
||||||
@@ -819,7 +821,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
// Add all properties
|
// Add all properties
|
||||||
declaredProperties = new List<PropertyInfo>();
|
declaredProperties = new List<PropertyInfo>();
|
||||||
for (var p = Definition.propertyStart; p < Definition.propertyStart + Definition.property_count; p++)
|
for (var p = Definition.PropertyIndex; p < Definition.PropertyIndex + Definition.PropertyCount; p++)
|
||||||
declaredProperties.Add(new PropertyInfo(pkg, p, this));
|
declaredProperties.Add(new PropertyInfo(pkg, p, this));
|
||||||
|
|
||||||
// There are rare cases when explicitly implemented interface properties
|
// There are rare cases when explicitly implemented interface properties
|
||||||
@@ -856,7 +858,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
// Add all events
|
// Add all events
|
||||||
declaredEvents = new List<EventInfo>();
|
declaredEvents = new List<EventInfo>();
|
||||||
for (var e = Definition.eventStart; e < Definition.eventStart + Definition.event_count; e++)
|
for (var e = Definition.EventIndex; e < Definition.EventIndex + Definition.EventCount; e++)
|
||||||
declaredEvents.Add(new EventInfo(pkg, e, this));
|
declaredEvents.Add(new EventInfo(pkg, e, this));
|
||||||
|
|
||||||
// TODO: Events have the same edge case issue as properties above, eg. PoGo 0.35.0
|
// TODO: Events have the same edge case issue as properties above, eg. PoGo 0.35.0
|
||||||
@@ -937,21 +939,21 @@ namespace Il2CppInspector.Reflection
|
|||||||
Namespace = declaringType.Namespace;
|
Namespace = declaringType.Namespace;
|
||||||
|
|
||||||
// Special constraints
|
// Special constraints
|
||||||
GenericParameterAttributes = (GenericParameterAttributes)param.flags;
|
GenericParameterAttributes = (GenericParameterAttributes)param.Flags;
|
||||||
|
|
||||||
// Type constraints
|
// Type constraints
|
||||||
genericParameterConstraints = new TypeRef[param.constraintsCount];
|
genericParameterConstraints = new TypeRef[param.ConstraintsCount];
|
||||||
for (int c = 0; c < param.constraintsCount; c++)
|
for (int c = 0; c < param.ConstraintsCount; c++)
|
||||||
genericParameterConstraints[c] = TypeRef.FromReferenceIndex(Assembly.Model, Assembly.Model.Package.GenericConstraintIndices[param.constraintsStart + c]);
|
genericParameterConstraints[c] = TypeRef.FromReferenceIndex(Assembly.Model, Assembly.Model.Package.GenericConstraintIndices[param.ConstraintsStart + c]);
|
||||||
|
|
||||||
// Base type of object (set by default)
|
// Base type of object (set by default)
|
||||||
// TODO: ImplementedInterfaces should be set to interface types constraints
|
// TODO: ImplementedInterfaces should be set to interface types constraints
|
||||||
|
|
||||||
// Name of parameter
|
// Name of parameter
|
||||||
Name = Assembly.Model.Package.Strings[param.nameIndex];
|
Name = Assembly.Model.Package.Strings[param.NameIndex];
|
||||||
|
|
||||||
// Position
|
// Position
|
||||||
GenericParameterPosition = param.num;
|
GenericParameterPosition = param.Num;
|
||||||
|
|
||||||
IsGenericParameter = true;
|
IsGenericParameter = true;
|
||||||
IsGenericType = false;
|
IsGenericType = false;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user