• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 15144170590

20 May 2025 05:37PM UTC coverage: 34.277% (+0.2%) from 34.047%
15144170590

Pull #462

github

web-flow
Merge 4a307f12a into 5807d2b6c
Pull Request #462: Support overriding member types

1799 of 6648 branches covered (27.06%)

Branch coverage included in aggregate %.

115 of 202 new or added lines in 33 files covered. (56.93%)

22 existing lines in 6 files now uncovered.

4197 of 10845 relevant lines covered (38.7%)

186399.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.38
/LibCpp2IL/Il2CppBinary.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Diagnostics.CodeAnalysis;
4
using System.Globalization;
5
using System.IO;
6
using System.Linq;
7
using LibCpp2IL.BinaryStructures;
8
using LibCpp2IL.Logging;
9
using LibCpp2IL.Metadata;
10

11
namespace LibCpp2IL;
12

13
public abstract class Il2CppBinary(MemoryStream input) : ClassReadingBinaryReader(input)
32✔
14
{
15
    public delegate void RegistrationStructLocationFailureHandler(Il2CppBinary binary, Il2CppMetadata metadata, ref Il2CppCodeRegistration? codeReg, ref Il2CppMetadataRegistration? metaReg);
16

17
    public static event RegistrationStructLocationFailureHandler? OnRegistrationStructLocationFailure;
18

19
    protected const long VirtToRawInvalidNoMatch = long.MinValue + 1000;
20
    protected const long VirtToRawInvalidOutOfBounds = long.MinValue + 1001;
21

22
    public InstructionSetId InstructionSetId = null!;
23
    public readonly Dictionary<Il2CppMethodDefinition, List<Cpp2IlMethodRef>> ConcreteGenericMethods = new();
32✔
24
    public readonly Dictionary<ulong, List<Cpp2IlMethodRef>> ConcreteGenericImplementationsByAddress = new();
32✔
25
    public ulong[] TypeDefinitionSizePointers = [];
32✔
26

27
    private readonly long _maxMetadataUsages = LibCpp2IlMain.TheMetadata!.GetMaxMetadataUsages();
32✔
28
    private Il2CppMetadataRegistration _metadataRegistration = null!;
29
    private Il2CppCodeRegistration _codeRegistration = null!;
30

31
    private ulong[] _methodPointers = [];
32✔
32

33
    private ulong[] _genericMethodPointers = [];
32✔
34

35
    // private ulong[] _invokerPointers = Array.Empty<ulong>();
36
    private ulong[]? _customAttributeGenerators = []; //Pre-27 only
32✔
37
    private long[] _fieldOffsets = [];
32✔
38
    private ulong[] _metadataUsages = []; //Pre-27 only
32✔
39
    private ulong[][] _codeGenModuleMethodPointers = []; //24.2+
32✔
40

41
    private Il2CppType[] _types = [];
32✔
42
    private Il2CppGenericMethodFunctionsDefinitions[] _genericMethodTables = [];
32✔
43
    private Il2CppGenericInst[] _genericInsts = [];
32✔
44
    private Il2CppMethodSpec[] _methodSpecs = [];
32✔
45
    private Il2CppCodeGenModule[] _codeGenModules = []; //24.2+
32✔
46
    private Il2CppTokenRangePair[][] _codegenModuleRgctxRanges = [];
32✔
47
    private Il2CppRGCTXDefinition[][] _codegenModuleRgctxs = [];
32✔
48

49
    private Dictionary<string, Il2CppCodeGenModule> _codeGenModulesByName = new(); //24.2+
32✔
50
    private Dictionary<int, ulong> _genericMethodDictionary = new();
32✔
51
    private readonly Dictionary<ulong, Il2CppType> _typesByAddress = new();
32✔
52

53
    public abstract long RawLength { get; }
54
    public int NumTypes => _types.Length;
×
55

56
    public Il2CppType[] AllTypes => _types;
142,270✔
57

58
    /// <summary>
59
    /// Can be overriden if, like the wasm format, your data has to be unpacked and you need to use a different reader
60
    /// </summary>
61
    public virtual ClassReadingBinaryReader Reader => this;
11,978,238✔
62

63
    private float _metadataVersion;
64
    public sealed override float MetadataVersion => _metadataVersion; 
5,593,848✔
65

66
    public int InBinaryMetadataSize { get; private set; }
832✔
67

68
    public void Init(ulong pCodeRegistration, ulong pMetadataRegistration, Il2CppMetadata metadata)
69
    {
70
        _metadataVersion = metadata.MetadataVersion;
32✔
71
        
72
        var cr = pCodeRegistration > 0 ? ReadReadableAtVirtualAddress<Il2CppCodeRegistration>(pCodeRegistration) : null;
32!
73
        var mr = pMetadataRegistration > 0 ? ReadReadableAtVirtualAddress<Il2CppMetadataRegistration>(pMetadataRegistration) : null;
32!
74

75
        if (cr == null || mr == null)
32!
76
        {
77
            LibLogger.WarnNewline("At least one of the registration structs was not able to be found. Attempting to use fallback locator delegate to find them (this will fail unless you have a plugin that helps with this!)...");
×
78
            OnRegistrationStructLocationFailure?.Invoke(this, LibCpp2IlMain.TheMetadata!, ref cr, ref mr);
×
79
            LibLogger.VerboseNewline($"After fallback, code registration is {(cr == null ? "null" : "not null")} and metadata registration is {(mr == null ? "null" : "not null")}.");
×
80
        }
81

82
        if (cr == null || mr == null)
32!
83
            throw new("Failed to find code registration or metadata registration!");
×
84

85
        _codeRegistration = cr;
32✔
86
        _metadataRegistration = mr;
32✔
87

88
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
89

90
        LibLogger.Verbose("\tReading generic instances...");
32✔
91
        var start = DateTime.Now;
32✔
92
        _genericInsts = Array.ConvertAll(ReadNUintArrayAtVirtualAddress(_metadataRegistration.genericInsts, _metadataRegistration.genericInstsCount), ReadReadableAtVirtualAddress<Il2CppGenericInst>);
32✔
93
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
32✔
94

95
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
96

97
        if (_codeRegistration.genericMethodPointers != 0)
32!
98
        {
99
            LibLogger.Verbose("\tReading generic method pointers...");
32✔
100
            start = DateTime.Now;
32✔
101
            _genericMethodPointers = ReadNUintArrayAtVirtualAddress(_codeRegistration.genericMethodPointers, (long)_codeRegistration.genericMethodPointersCount);
32✔
102
            LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
32✔
103
        }
104
        else
105
        {
106
            LibLogger.WarnNewline("\tPointer to generic method array in CodeReg is null! This isn't inherently going to cause dumping to fail but there will be no generic method data in the dump.");
×
107
            _genericMethodPointers = [];
×
108
        }
109

110
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
111

112
        // These aren't actually used right now, and if we have a limited code reg (e.g. heavily inlined linux games) we can't read them anyway
113
        // LibLogger.Verbose("\tReading invoker pointers...");
114
        // start = DateTime.Now;
115
        // _invokerPointers = ReadNUintArrayAtVirtualAddress(_codeRegistration.invokerPointers, (long)_codeRegistration.invokerPointersCount);
116
        // LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
117

118
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
119

120
        if (metadata.MetadataVersion < 27)
32✔
121
        {
122
            LibLogger.Verbose("\tReading custom attribute generators...");
24✔
123
            start = DateTime.Now;
24✔
124
            _customAttributeGenerators = ReadNUintArrayAtVirtualAddress(_codeRegistration.customAttributeGeneratorListAddress, (long)_codeRegistration.customAttributeCount);
24✔
125
            LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
24✔
126
        }
127

128
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
129

130
        LibLogger.Verbose("\tReading field offsets...");
32✔
131
        start = DateTime.Now;
32✔
132
        _fieldOffsets = ReadClassArrayAtVirtualAddress<long>(_metadataRegistration.fieldOffsetListAddress, _metadataRegistration.fieldOffsetsCount);
32✔
133
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
32✔
134

135
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
136

137
        LibLogger.Verbose("\tReading types...");
32✔
138
        start = DateTime.Now;
32✔
139
        var typePtrs = ReadNUintArrayAtVirtualAddress(_metadataRegistration.typeAddressListAddress, _metadataRegistration.numTypes);
32✔
140
        _types = new Il2CppType[_metadataRegistration.numTypes];
32✔
141
        for (var i = 0; i < _metadataRegistration.numTypes; ++i)
2,043,864✔
142
        {
143
            _types[i] = ReadReadableAtVirtualAddress<Il2CppType>(typePtrs[i]);
1,021,900✔
144
            _typesByAddress[typePtrs[i]] = _types[i];
1,021,900✔
145
        }
146

147
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
148

149
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
32✔
150

151
        LibLogger.Verbose("\tReading type definition sizes...");
32✔
152
        start = DateTime.Now;
32✔
153
        TypeDefinitionSizePointers = ReadNUintArrayAtVirtualAddress(_metadataRegistration.typeDefinitionsSizes, _metadataRegistration.typeDefinitionsSizesCount);
32✔
154
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
32✔
155

156
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
157

158
        if (_metadataRegistration.metadataUsages != 0)
32✔
159
        {
160
            //Empty in v27
161
            LibLogger.Verbose("\tReading metadata usages...");
24✔
162
            start = DateTime.Now;
24✔
163
            _metadataUsages = ReadNUintArrayAtVirtualAddress(_metadataRegistration.metadataUsages, (long)Math.Max((decimal)_metadataRegistration.metadataUsagesCount, _maxMetadataUsages));
24✔
164
            LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
24✔
165
        }
166

167
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
168

169
        if (metadata.MetadataVersion >= 24.2f)
32✔
170
        {
171
            LibLogger.VerboseNewline("\tReading code gen modules...");
31✔
172
            start = DateTime.Now;
31✔
173

174
            var codeGenModulePtrs = ReadNUintArrayAtVirtualAddress(_codeRegistration.addrCodeGenModulePtrs, (long)_codeRegistration.codeGenModulesCount);
31✔
175
            _codeGenModules = new Il2CppCodeGenModule[codeGenModulePtrs.Length];
31✔
176
            _codeGenModuleMethodPointers = new ulong[codeGenModulePtrs.Length][];
31✔
177
            _codegenModuleRgctxRanges = new Il2CppTokenRangePair[codeGenModulePtrs.Length][];
31✔
178
            _codegenModuleRgctxs = new Il2CppRGCTXDefinition[codeGenModulePtrs.Length][];
31✔
179
            for (var i = 0; i < codeGenModulePtrs.Length; i++)
2,914✔
180
            {
181
                var codeGenModule = ReadReadableAtVirtualAddress<Il2CppCodeGenModule>(codeGenModulePtrs[i]);
1,426✔
182
                _codeGenModules[i] = codeGenModule;
1,426✔
183
                _codeGenModulesByName[codeGenModule.Name] = codeGenModule;
1,426✔
184
                var name = codeGenModule.Name;
1,426✔
185
                LibLogger.VerboseNewline($"\t\t-Read module data for {name}, contains {codeGenModule.methodPointerCount} method pointers starting at 0x{codeGenModule.methodPointers:X}");
1,426✔
186
                if (codeGenModule.methodPointerCount > 0)
1,426✔
187
                {
188
                    try
189
                    {
190
                        var ptrs = ReadNUintArrayAtVirtualAddress(codeGenModule.methodPointers, codeGenModule.methodPointerCount);
1,289✔
191
                        _codeGenModuleMethodPointers[i] = ptrs;
1,287✔
192
                        LibLogger.VerboseNewline($"\t\t\t-Read {codeGenModule.methodPointerCount} method pointers.");
1,287✔
193
                    }
1,287✔
194
                    catch (Exception e)
2✔
195
                    {
196
                        LibLogger.VerboseNewline($"\t\t\tWARNING: Unable to get function pointers for {name}: {e.Message}");
2✔
197
                        _codeGenModuleMethodPointers[i] = new ulong[codeGenModule.methodPointerCount];
2✔
198
                    }
2✔
199
                }
200

201
                if (codeGenModule.rgctxRangesCount > 0)
1,426✔
202
                {
203
                    try
204
                    {
205
                        var ranges = ReadReadableArrayAtVirtualAddress<Il2CppTokenRangePair>(codeGenModule.pRgctxRanges, codeGenModule.rgctxRangesCount);
367✔
206
                        _codegenModuleRgctxRanges[i] = ranges;
367✔
207
                        LibLogger.VerboseNewline($"\t\t\t-Read {codeGenModule.rgctxRangesCount} RGCTX ranges.");
367✔
208
                    }
367✔
209
                    catch (Exception e)
×
210
                    {
211
                        LibLogger.VerboseNewline($"\t\t\tWARNING: Unable to get RGCTX ranges for {name}: {e.Message}");
×
212
                        _codegenModuleRgctxRanges[i] = new Il2CppTokenRangePair[codeGenModule.rgctxRangesCount];
×
213
                    }
×
214
                }
215

216
                if (codeGenModule.rgctxsCount > 0)
1,426✔
217
                {
218
                    try
219
                    {
220
                        var rgctxs = ReadReadableArrayAtVirtualAddress<Il2CppRGCTXDefinition>(codeGenModule.rgctxs, codeGenModule.rgctxsCount);
367✔
221
                        _codegenModuleRgctxs[i] = rgctxs;
367✔
222
                        LibLogger.VerboseNewline($"\t\t\t-Read {codeGenModule.rgctxsCount} RGCTXs.");
367✔
223
                    }
367✔
224
                    catch (Exception e)
×
225
                    {
226
                        LibLogger.VerboseNewline($"\t\t\tWARNING: Unable to get RGCTXs for {name}: {e.Message}");
×
227
                        _codegenModuleRgctxs[i] = new Il2CppRGCTXDefinition[codeGenModule.rgctxsCount];
×
228
                    }
×
229
                }
230
            }
231

232
            LibLogger.VerboseNewline($"\tOK ({(DateTime.Now - start).TotalMilliseconds} ms)");
31✔
233
        }
234
        else
235
        {
236
            LibLogger.Verbose("\tReading method pointers...");
1✔
237
            start = DateTime.Now;
1✔
238
            _methodPointers = ReadNUintArrayAtVirtualAddress(_codeRegistration.methodPointers, (long)_codeRegistration.methodPointersCount);
1✔
239
            LibLogger.VerboseNewline($"Read {_methodPointers.Length} OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
1✔
240
        }
241

242
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
243

244
        LibLogger.Verbose("\tReading generic method tables...");
32✔
245
        start = DateTime.Now;
32✔
246
        _genericMethodTables = ReadReadableArrayAtVirtualAddress<Il2CppGenericMethodFunctionsDefinitions>(_metadataRegistration.genericMethodTable, _metadataRegistration.genericMethodTableCount);
32✔
247
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
32✔
248

249
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
250

251
        LibLogger.Verbose("\tReading method specifications...");
32✔
252
        start = DateTime.Now;
32✔
253
        _methodSpecs = ReadReadableArrayAtVirtualAddress<Il2CppMethodSpec>(_metadataRegistration.methodSpecs, _metadataRegistration.methodSpecsCount);
32✔
254
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
32✔
255

256
        InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
257

258
        if (_genericMethodPointers.Length > 0)
32!
259
        {
260
            LibLogger.Verbose("\tReading generic methods...");
32✔
261
            start = DateTime.Now;
32✔
262
            _genericMethodDictionary = new Dictionary<int, ulong>();
32✔
263
            foreach (var table in _genericMethodTables)
1,278,624✔
264
            {
265
                var genericMethodIndex = table.GenericMethodIndex;
639,280✔
266
                var genericMethodPointerIndex = table.Indices.methodIndex;
639,280✔
267

268
                var methodDefIndex = GetGenericMethodFromIndex(genericMethodIndex, genericMethodPointerIndex);
639,280✔
269

270
                if (!_genericMethodDictionary.ContainsKey(methodDefIndex) && genericMethodPointerIndex < _genericMethodPointers.Length)
639,280✔
271
                {
272
                    _genericMethodDictionary.TryAdd(methodDefIndex, _genericMethodPointers[genericMethodPointerIndex]);
58,092✔
273
                }
274
            }
275

276
            LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
32✔
277
            InBinaryMetadataSize += GetNumBytesReadSinceLastCallAndClear();
32✔
278
        }
279
        else
280
        {
281
            LibLogger.WarnNewline("\tNo generic method pointer data found, skipping generic mapping.");
×
282
        }
283

284
        _hasFinishedInitialRead = true;
32✔
285
    }
32✔
286

287
    private int GetGenericMethodFromIndex(int genericMethodIndex, int genericMethodPointerIndex)
288
    {
289
        Cpp2IlMethodRef? genericMethodRef;
290
        var methodSpec = GetMethodSpec(genericMethodIndex);
639,280✔
291
        var methodDefIndex = methodSpec.methodDefinitionIndex;
639,280✔
292
        genericMethodRef = new Cpp2IlMethodRef(methodSpec);
639,280✔
293

294
        if (genericMethodPointerIndex >= 0)
639,280✔
295
        {
296
            if (genericMethodPointerIndex < _genericMethodPointers.Length)
639,280✔
297
                genericMethodRef.GenericVariantPtr = _genericMethodPointers[genericMethodPointerIndex];
639,280✔
298
        }
299

300
        if (!ConcreteGenericMethods.ContainsKey(genericMethodRef.BaseMethod))
639,280✔
301
            ConcreteGenericMethods[genericMethodRef.BaseMethod] = [];
58,092✔
302

303
        ConcreteGenericMethods[genericMethodRef.BaseMethod].Add(genericMethodRef);
639,280✔
304

305
        if (genericMethodRef.GenericVariantPtr > 0)
639,280✔
306
        {
307
            if (!ConcreteGenericImplementationsByAddress.ContainsKey(genericMethodRef.GenericVariantPtr))
635,323✔
308
                ConcreteGenericImplementationsByAddress[genericMethodRef.GenericVariantPtr] = [];
281,233✔
309

310
            ConcreteGenericImplementationsByAddress[genericMethodRef.GenericVariantPtr].Add(genericMethodRef);
635,323✔
311
        }
312

313
        return methodDefIndex;
639,280✔
314
    }
315

316
    public abstract byte GetByteAtRawAddress(ulong addr);
317
    public abstract long MapVirtualAddressToRaw(ulong uiAddr, bool throwOnError = true);
318
    public abstract ulong MapRawAddressToVirtual(uint offset);
319
    public abstract ulong GetRva(ulong pointer);
320

321
    public bool TryMapRawAddressToVirtual(in uint offset, out ulong va)
322
    {
323
        try
324
        {
325
            va = MapRawAddressToVirtual(offset);
187✔
326
            return true;
172✔
327
        }
328
        catch (Exception)
15✔
329
        {
330
            va = 0;
15✔
331
            return false;
15✔
332
        }
333
    }
187✔
334

335
    public bool TryMapVirtualAddressToRaw(ulong virtAddr, out long result)
336
    {
337
        result = MapVirtualAddressToRaw(virtAddr, false);
723,319✔
338

339
        if (result != VirtToRawInvalidNoMatch)
723,319✔
340
            return true;
723,317✔
341

342
        result = 0;
2✔
343
        return false;
2✔
344
    }
345

346
    public T[] ReadClassArrayAtVirtualAddress<T>(ulong addr, long count) where T : new() => Reader.ReadClassArrayAtRawAddr<T>(MapVirtualAddressToRaw(addr), count);
32✔
347

348
    public T[] ReadReadableArrayAtVirtualAddress<T>(ulong va, long count) where T : ReadableClass, new() => Reader.ReadReadableArrayAtRawAddr<T>(MapVirtualAddressToRaw(va), count);
800✔
349

350
    public T ReadReadableAtVirtualAddress<T>(ulong va) where T : ReadableClass, new() => Reader.ReadReadable<T>(MapVirtualAddressToRaw(va));
1,491,526✔
351

352
    public ulong[] ReadNUintArrayAtVirtualAddress(ulong addr, long count) => Reader.ReadNUintArrayAtRawAddress(MapVirtualAddressToRaw(addr), (int)count);
991,083✔
353

354
    public override long ReadNInt() => is32Bit ? Reader.ReadInt32() : Reader.ReadInt64();
184,366✔
355

356
    public override ulong ReadNUint() => is32Bit ? Reader.ReadUInt32() : Reader.ReadUInt64();
9,310,415✔
357

358
    public ulong ReadPointerAtVirtualAddress(ulong addr)
359
    {
360
        return Reader.ReadNUintAtRawAddress(MapVirtualAddressToRaw(addr));
×
361
    }
362

363
    public Il2CppGenericInst GetGenericInst(int index) => _genericInsts[index];
811,434✔
364

365
    public Il2CppMethodSpec[] AllGenericMethodSpecs => _methodSpecs;
×
366

367
    public Il2CppMethodSpec GetMethodSpec(int index) => index >= _methodSpecs.Length
639,280!
368
        ? throw new ArgumentException($"GetMethodSpec: index {index} >= length {_methodSpecs.Length}")
639,280✔
369
        : index < 0
639,280✔
370
            ? throw new ArgumentException($"GetMethodSpec: index {index} < 0")
639,280✔
371
            : _methodSpecs[index];
639,280✔
372

373
    public Il2CppType GetType(int index) => _types[index];
16,848,229✔
374
    public ulong GetRawMetadataUsage(uint index) => _metadataUsages[index];
261,534✔
375
    public ulong[] GetCodegenModuleMethodPointers(int codegenModuleIndex) => _codeGenModuleMethodPointers[codegenModuleIndex];
×
376
    public Il2CppCodeGenModule? GetCodegenModuleByName(string name) => _codeGenModulesByName[name];
75,552✔
377
    public int GetCodegenModuleIndex(Il2CppCodeGenModule module) => Array.IndexOf(_codeGenModules, module);
74,454✔
378
    public int GetCodegenModuleIndexByName(string name) => GetCodegenModuleByName(name) is { } module ? GetCodegenModuleIndex(module) : -1;
74,454!
379
    public Il2CppTokenRangePair[] GetRgctxRangePairsForModule(Il2CppCodeGenModule module) => _codegenModuleRgctxRanges[GetCodegenModuleIndex(module)];
×
380
    public Il2CppRGCTXDefinition[] GetRgctxDataForPair(Il2CppCodeGenModule module, Il2CppTokenRangePair rangePair) => _codegenModuleRgctxs[GetCodegenModuleIndex(module)].Skip(rangePair.start).Take(rangePair.length).ToArray();
×
381

382
    public Il2CppType GetIl2CppTypeFromPointer(ulong pointer)
383
        => _typesByAddress[pointer];
1,340,707✔
384

385
    public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType, int fieldIndex, bool isValueType, bool isStatic)
386
    {
387
        try
388
        {
389
            var offset = -1;
300,321✔
390
            if (LibCpp2IlMain.MetadataVersion > 21)
300,321!
391
            {
392
                var ptr = (ulong)_fieldOffsets[typeIndex];
300,321✔
393
                if (ptr > 0)
300,321✔
394
                {
395
                    var offsetOffset = (ulong)MapVirtualAddressToRaw(ptr) + 4ul * (ulong)fieldIndexInType;
300,321✔
396
                    GetLockOrThrow();
300,321✔
397
                    try
398
                    {
399
                        Position = (long)offsetOffset;
300,321✔
400
                        offset = (int)ReadPrimitive(typeof(int))!; //Read 4 bytes. We can't just use ReadInt32 because that breaks e.g. Wasm. Hoping the JIT can optimize this as it knows the type.
300,321✔
401
                    }
300,321✔
402
                    finally
403
                    {
404
                        ReleaseLock();
300,321✔
405
                    }
300,321✔
406
                }
407
            }
408
            else
409
            {
UNCOV
410
                offset = (int)_fieldOffsets[fieldIndex];
×
411
            }
412

413
            if (offset > 0)
300,321✔
414
            {
415
                if (isValueType && !isStatic)
171,912✔
416
                {
417
                    if (is32Bit)
45,807!
418
                    {
UNCOV
419
                        offset -= 8;
×
420
                    }
421
                    else
422
                    {
423
                        offset -= 16;
45,807✔
424
                    }
425
                }
426
            }
427

428
            return offset;
300,321✔
429
        }
UNCOV
430
        catch
×
431
        {
UNCOV
432
            return -1;
×
433
        }
434
    }
300,321✔
435

436
    public ulong GetMethodPointer(int methodIndex, int methodDefinitionIndex, int imageIndex, uint methodToken)
437
    {
438
        if (LibCpp2IlMain.MetadataVersion >= 24.2f)
439,980!
439
        {
440
            if (_genericMethodDictionary.TryGetValue(methodDefinitionIndex, out var methodPointer))
439,980✔
441
            {
442
                return methodPointer;
32,721✔
443
            }
444

445
            var ptrs = _codeGenModuleMethodPointers[imageIndex];
407,259✔
446
            var methodPointerIndex = methodToken & 0x00FFFFFFu;
407,259✔
447
            return ptrs[methodPointerIndex - 1];
407,259✔
448
        }
449
        else
450
        {
UNCOV
451
            if (methodIndex >= 0)
×
452
            {
453
                return _methodPointers[methodIndex];
×
454
            }
455

UNCOV
456
            _genericMethodDictionary.TryGetValue(methodDefinitionIndex, out var methodPointer);
×
UNCOV
457
            return methodPointer;
×
458
        }
459
    }
460

461
    public ulong GetCustomAttributeGenerator(int index) => _customAttributeGenerators![index];
×
462

463
    public ulong[] AllCustomAttributeGenerators => LibCpp2IlMain.MetadataVersion >= 29 ? [] : LibCpp2IlMain.MetadataVersion >= 27 ? AllCustomAttributeGeneratorsV27 : _customAttributeGenerators!;
27!
464

465
    private ulong[] AllCustomAttributeGeneratorsV27 =>
466
        LibCpp2IlMain.TheMetadata!.imageDefinitions
×
UNCOV
467
            .Select(i => (image: i, cgm: GetCodegenModuleByName(i.Name!)!))
×
UNCOV
468
            .SelectMany(tuple => LibCpp2ILUtils.Range(0, (int)tuple.image.customAttributeCount).Select(o => tuple.cgm.customAttributeCacheGenerator + (ulong)o * PointerSize))
×
UNCOV
469
            .Select(ReadPointerAtVirtualAddress)
×
470
            .ToArray();
×
471

472
    public abstract byte[] GetRawBinaryContent();
473
    public abstract ulong GetVirtualAddressOfExportedFunctionByName(string toFind);
474
    public virtual bool IsExportedFunction(ulong addr) => false;
×
475

476
    public virtual bool TryGetExportedFunctionName(ulong addr, [NotNullWhen(true)] out string? name)
477
    {
UNCOV
478
        name = null;
×
UNCOV
479
        return false;
×
480
    }
481

UNCOV
482
    public virtual IEnumerable<KeyValuePair<string, ulong>> GetExportedFunctions() => [];
×
483

484
    public abstract byte[] GetEntirePrimaryExecutableSection();
485

486
    public abstract ulong GetVirtualAddressOfPrimaryExecutableSection();
487

488
    public virtual (ulong pCodeRegistration, ulong pMetadataRegistration) FindCodeAndMetadataReg(Il2CppMetadata metadata)
489
    {
490
        LibLogger.VerboseNewline("\tAttempting to locate code and metadata registration functions...");
30✔
491

492
        var methodCount = metadata.methodDefs.Count(x => x.methodIndex >= 0);
841,498✔
493
        var typeDefinitionsCount = metadata.typeDefs.Length;
30✔
494

495
        var plusSearch = new BinarySearcher(this, methodCount, typeDefinitionsCount);
30✔
496

497
        LibLogger.VerboseNewline("\t\t-Searching for MetadataReg...");
30✔
498

499
        var pMetadataRegistration = metadata.MetadataVersion < 24.5f
30✔
500
            ? plusSearch.FindMetadataRegistrationPre24_5()
30✔
501
            : plusSearch.FindMetadataRegistrationPost24_5(metadata);
30✔
502

503
        LibLogger.VerboseNewline("\t\t-Searching for CodeReg...");
30✔
504

505
        ulong pCodeRegistration;
506
        if (metadata.MetadataVersion >= 24.2f)
30✔
507
        {
508
            LibLogger.VerboseNewline("\t\t\tUsing mscorlib full-disassembly approach to get codereg, this may take a while...");
29✔
509
            pCodeRegistration = plusSearch.FindCodeRegistrationPost2019(metadata);
29✔
510
        }
511
        else
512
            pCodeRegistration = plusSearch.FindCodeRegistrationPre2019();
1✔
513

514
        if (pCodeRegistration == 0 && LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput)
30!
515
        {
516
            LibLogger.Info("Couldn't identify a CodeRegistration address. If you know it, enter it now, otherwise enter nothing or zero to fail: ");
×
517
            var crInput = Console.ReadLine();
×
UNCOV
518
            ulong.TryParse(crInput, NumberStyles.HexNumber, null, out pCodeRegistration);
×
519
        }
520

521
        if (pMetadataRegistration == 0 && LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput)
30!
522
        {
UNCOV
523
            LibLogger.Info("Couldn't identify a MetadataRegistration address. If you know it, enter it now, otherwise enter nothing or zero to fail: ");
×
UNCOV
524
            var mrInput = Console.ReadLine();
×
UNCOV
525
            ulong.TryParse(mrInput, NumberStyles.HexNumber, null, out pMetadataRegistration);
×
526
        }
527

528
        return (pCodeRegistration, pMetadataRegistration);
30✔
529
    }
530
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc