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

SamboyCoding / Cpp2IL / 15052278841

15 May 2025 06:16PM UTC coverage: 34.038% (-0.4%) from 34.453%
15052278841

push

github

SamboyCoding
Support injecting anything
* Nested types
* Events
* Properties
* Assemblies

Support additional metadata in injected assemblies

Make setter for TypeAnalysisContext::OverrideBaseType public

TypeAnalysisContext::InterfaceContexts as list rather than array

Fix sign bug

Support generic parameters on type contexts and method contexts

Make GenericParameterTypeAnalysisContext instances unique

Revert change to Il2CppGenericParameter::Index

Use attributes to determine if injected methods are static
* Also add hide by sig attribute for injected constructors

Support overrides on injected methods

In ControlFlowGraphOutputFormat, exclude injected assemblies

Ensure injected assemblies can't delete existing assemblies

Backing field on .NET Standard for injected method overrides

Implement requested change

1774 of 6622 branches covered (26.79%)

Branch coverage included in aggregate %.

147 of 196 new or added lines in 27 files covered. (75.0%)

53 existing lines in 2 files now uncovered.

4155 of 10797 relevant lines covered (38.48%)

188267.61 hits per line

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

75.4
/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Diagnostics;
4
using System.Linq;
5
using AssetRipper.Primitives;
6
using Cpp2IL.Core.Api;
7
using Cpp2IL.Core.Exceptions;
8
using Cpp2IL.Core.Il2CppApiFunctions;
9
using Cpp2IL.Core.Logging;
10
using Cpp2IL.Core.Utils;
11
using LibCpp2IL;
12
using LibCpp2IL.Metadata;
13

14
namespace Cpp2IL.Core.Model.Contexts;
15

16
/// <summary>
17
/// Top-level class to represent an individual il2cpp application that has been loaded into cpp2il.
18
/// </summary>
19
public class ApplicationAnalysisContext : ContextWithDataStorage
20
{
21
    /// <summary>
22
    /// The IL2CPP binary file this application was loaded from
23
    /// </summary>
24
    public Il2CppBinary Binary;
25

26
    /// <summary>
27
    /// The IL2CPP global-metadata file this application was loaded from.
28
    /// </summary>
29
    public Il2CppMetadata Metadata;
30

31
    /// <summary>
32
    /// The version of the IL2CPP metadata file this application was loaded from.
33
    /// </summary>
34
    public float MetadataVersion => Metadata.MetadataVersion;
1,400,319✔
35
    
36
    /// <summary>
37
    /// The Unity version this application was compiled with.
38
    /// </summary>
39
    public UnityVersion UnityVersion => Metadata.UnityVersion;
×
40

41
    /// <summary>
42
    /// The instruction set helper class associated with the instruction set that this application was compiled with.
43
    /// </summary>
44
    public Cpp2IlInstructionSet InstructionSet;
45

46
    /// <summary>
47
    /// Contains references to some commonly-used System types.
48
    /// </summary>
49
    public SystemTypesContext SystemTypes;
50

51
    /// <summary>
52
    /// All the managed assemblies contained within the metadata file.
53
    /// </summary>
54
    public readonly List<AssemblyAnalysisContext> Assemblies = [];
27✔
55

56
    /// <summary>
57
    /// A dictionary of all the managed assemblies, by their name.
58
    /// </summary>
59
    public readonly Dictionary<string, AssemblyAnalysisContext> AssembliesByName = new();
27✔
60

61
    /// <summary>
62
    /// A dictionary of method pointers to the corresponding method, which may or may not be generic.
63
    /// </summary>
64
    public readonly Dictionary<ulong, List<MethodAnalysisContext>> MethodsByAddress = new();
27✔
65

66
    /// <summary>
67
    /// A dictionary of all the generic method variants to their corresponding analysis contexts.
68
    /// </summary>
69
    public readonly Dictionary<Cpp2IlMethodRef, ConcreteGenericMethodAnalysisContext> ConcreteGenericMethodsByRef = new();
27✔
70

71
    /// <summary>
72
    /// Key Function Addresses for the binary file. Populated on-demand
73
    /// </summary>
74
    private BaseKeyFunctionAddresses? _keyFunctionAddresses;
75

76
    /// <summary>
77
    /// True if this ApplicationAnalysisContext has finished initialization of all of its child contexts, else false.
78
    /// </summary>
79
    public bool HasFinishedInitializing { get; private set; }
27✔
80

81
    public ApplicationAnalysisContext(Il2CppBinary binary, Il2CppMetadata metadata)
27✔
82
    {
83
        Binary = binary;
27✔
84
        Metadata = metadata;
27✔
85

86
        try
87
        {
88
            InstructionSet = InstructionSetRegistry.GetInstructionSet(binary.InstructionSetId);
27✔
89
        }
27✔
90
        catch (Exception)
×
91
        {
92
            throw new InstructionSetHandlerNotRegisteredException(binary.InstructionSetId);
×
93
        }
94

95
        Logger.VerboseNewline("\tUsing instruction set handler: " + InstructionSet.GetType().FullName);
27✔
96

97
        foreach (var assemblyDefinition in Metadata.AssemblyDefinitions)
2,250✔
98
        {
99
            Logger.VerboseNewline($"\tProcessing assembly: {assemblyDefinition.AssemblyName.Name}...");
1,098✔
100
            var aac = new AssemblyAnalysisContext(assemblyDefinition, this);
1,098✔
101
            Assemblies.Add(aac);
1,098✔
102
            AssembliesByName[assemblyDefinition.AssemblyName.Name] = aac;
1,098✔
103
        }
104

105
        SystemTypes = new(this);
27✔
106
        
107
        MiscUtils.InitFunctionStarts(this);
27✔
108

109
        PopulateMethodsByAddressTable();
27✔
110

111
        HasFinishedInitializing = true;
27✔
112
    }
27✔
113

114
    /// <summary>
115
    /// Populates the <see cref="MethodsByAddress"/> dictionary with all the methods in the application, including concrete generic ones.
116
    /// </summary>
117
    private void PopulateMethodsByAddressTable()
118
    {
119
        Assemblies.SelectMany(a => a.Types).SelectMany(t => t.Methods).ToList().ForEach(m =>
77,379✔
120
        {
27✔
121
            m.EnsureRawBytes();
439,980✔
122
            var ptr = InstructionSet.GetPointerForMethod(m);
439,980✔
123

27✔
124
            if (!MethodsByAddress.ContainsKey(ptr))
439,980✔
125
                MethodsByAddress.Add(ptr, []);
350,547✔
126

27✔
127
            MethodsByAddress[ptr].Add(m);
439,980✔
128
        });
440,007✔
129

130
        Logger.VerboseNewline("\tProcessing concrete generic methods...");
27✔
131
        foreach (var methodRef in Binary.ConcreteGenericMethods.Values.SelectMany(v => v))
629,391✔
132
        {
133
#if !DEBUG
134
            try
135
            {
136
#endif
137
            var gm = new ConcreteGenericMethodAnalysisContext(methodRef, this);
298,308✔
138

139
            var ptr = InstructionSet.GetPointerForMethod(gm);
298,308✔
140

141
            if (!MethodsByAddress.ContainsKey(ptr))
298,308✔
142
                MethodsByAddress[ptr] = [];
99,918✔
143

144
            MethodsByAddress[ptr].Add(gm);
298,308✔
145
            ConcreteGenericMethodsByRef[methodRef] = gm;
298,308✔
146
#if !DEBUG
147
            }
298,308✔
148
            catch (Exception e)
×
149
            {
150
                throw new("Failed to process concrete generic method: " + methodRef, e);
×
151
            }
152
#endif
153
        }
154
    }
27✔
155

156
    /// <summary>
157
    /// Finds an assembly by its name and returns the analysis context for it.
158
    /// </summary>
159
    /// <param name="name">The name of the assembly (without any extension)</param>
160
    /// <returns>An assembly analysis context if one can be found which matches the given name, else null.</returns>
161
    public AssemblyAnalysisContext? GetAssemblyByName(string name)
162
    {
163
        if (name.Length >= 4 && name[^4] == '.' && name[^3] == 'd')
2,334,310✔
164
            //Trim .dll extension
165
            name = name[..^4];
2,318,593✔
166
        else if (name.Length >= 6 && name[^6] == '.' && name[^5] == 'w')
15,717!
167
            //Trim .winmd extension
168
            name = name[..^6];
×
169

170
        return AssembliesByName[name];
2,334,310✔
171
    }
172

173
    public TypeAnalysisContext? ResolveContextForType(Il2CppTypeDefinition? typeDefinition)
174
    {
175
        return typeDefinition is not null
2,035,969!
176
            ? GetAssemblyByName(typeDefinition.DeclaringAssembly!.Name!)?.GetTypeByDefinition(typeDefinition)
2,035,969✔
177
            : null;
2,035,969✔
178
    }
179

180
    public MethodAnalysisContext? ResolveContextForMethod(Il2CppMethodDefinition? methodDefinition)
181
    {
182
        return ResolveContextForType(methodDefinition?.DeclaringType)?.Methods.FirstOrDefault(m => m.Definition == methodDefinition);
6,595,268!
183
    }
184

185
    public FieldAnalysisContext? ResolveContextForField(Il2CppFieldDefinition? field)
186
    {
187
        return ResolveContextForType(field?.DeclaringType)?.Fields.FirstOrDefault(f => f.BackingData?.Field == field);
2!
188
    }
189

190
    public EventAnalysisContext? ResolveContextForEvent(Il2CppEventDefinition? eventDefinition)
191
    {
192
        return ResolveContextForType(eventDefinition?.DeclaringType)?.Events.FirstOrDefault(e => e.Definition == eventDefinition);
2!
193
    }
194

195
    public PropertyAnalysisContext? ResolveContextForProperty(Il2CppPropertyDefinition? propertyDefinition)
196
    {
197
        return ResolveContextForType(propertyDefinition?.DeclaringType)?.Properties.FirstOrDefault(p => p.Definition == propertyDefinition);
2!
198
    }
199

200
    public GenericParameterTypeAnalysisContext? ResolveContextForGenericParameter(Il2CppGenericParameter? genericParameter)
201
    {
202
        if (genericParameter is null)
404,404!
NEW
203
            return null;
×
204

205
        if (genericParameter.Owner.TypeOwner is { } typeOwner)
404,404✔
206
        {
207
            return ResolveContextForType(typeOwner)?.GenericParameters[genericParameter.genericParameterIndexInOwner];
310,081!
208
        }
209
        else
210
        {
211
            Debug.Assert(genericParameter.Owner.MethodOwner is not null);
212
            return ResolveContextForMethod(genericParameter.Owner.MethodOwner)?.GenericParameters[genericParameter.genericParameterIndexInOwner];
94,323!
213
        }
214
    }
215

216
    public BaseKeyFunctionAddresses GetOrCreateKeyFunctionAddresses()
217
    {
218
        lock (InstructionSet)
×
219
        {
220
            if (_keyFunctionAddresses == null)
×
221
                (_keyFunctionAddresses = InstructionSet.CreateKeyFunctionAddressesInstance()).Find(this);
×
222

223
            return _keyFunctionAddresses;
×
224
        }
225
    }
×
226

227
    public MultiAssemblyInjectedType InjectTypeIntoAllAssemblies(string ns, string name, TypeAnalysisContext? baseType)
228
    {
229
        var types = Assemblies.Select(a => (InjectedTypeAnalysisContext)a.InjectType(ns, name, baseType)).ToArray();
344✔
230

231
        return new(types);
8✔
232
    }
233

234
    public InjectedAssemblyAnalysisContext InjectAssembly(
235
        string name,
236
        Version? version = null,
237
        uint hashAlgorithm = 0,
238
        uint flags = 0,
239
        string? culture = null,
240
        byte[]? publicKeyToken = null,
241
        byte[]? publicKey = null)
242
    {
243
        var assembly = new InjectedAssemblyAnalysisContext(name, this, version, hashAlgorithm, flags, culture, publicKeyToken, publicKey);
1✔
244
        Assemblies.Add(assembly);
1✔
245
        AssembliesByName.Add(name, assembly);
1✔
246
        return assembly;
1✔
247
    }
248

249
    public IEnumerable<TypeAnalysisContext> AllTypes => Assemblies.SelectMany(a => a.Types);
280✔
250
}
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

© 2026 Coveralls, Inc