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

SamboyCoding / Cpp2IL / 12074720245

28 Nov 2024 07:45PM UTC coverage: 28.371% (-0.02%) from 28.392%
12074720245

Pull #382

github

web-flow
Merge 697be1488 into 73abd20c0
Pull Request #382: Add a plugin for outputting Windows PDB files

1265 of 6204 branches covered (20.39%)

Branch coverage included in aggregate %.

2 of 53 new or added lines in 7 files covered. (3.77%)

3 existing lines in 3 files now uncovered.

3383 of 10179 relevant lines covered (33.24%)

126063.94 hits per line

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

0.0
/Cpp2IL.Core/Il2CppApiFunctions/BaseKeyFunctionAddresses.cs
1
using System.Collections.Generic;
2
using System.Diagnostics.CodeAnalysis;
3
using System.Linq;
4
using System.Runtime.CompilerServices;
5
using Cpp2IL.Core.Logging;
6
using Cpp2IL.Core.Model.Contexts;
7
using Cpp2IL.Core.Utils;
8
using Iced.Intel;
9
using LibCpp2IL;
10
using LibCpp2IL.Reflection;
11

12
namespace Cpp2IL.Core.Il2CppApiFunctions;
13

14
[SuppressMessage("ReSharper", "InconsistentNaming")]
15
public abstract class BaseKeyFunctionAddresses
16
{
17
    public ulong il2cpp_codegen_initialize_method; //Either this
18
    public ulong il2cpp_codegen_initialize_runtime_metadata; //Or this, are present, depending on metadata version, but not exported.
19
    public ulong il2cpp_vm_metadatacache_initializemethodmetadata; //This is thunked from the above (but only pre-27?)
20
    public ulong il2cpp_runtime_class_init_export; //Api function (exported)
21
    public ulong il2cpp_runtime_class_init_actual; //Thunked from above
22
    public ulong il2cpp_object_new; //Api Function (exported)
23
    public ulong il2cpp_vm_object_new; //Thunked from above
24
    public ulong il2cpp_codegen_object_new; //Thunked TO above
25
    public ulong il2cpp_array_new_specific; //Api function (exported)
26
    public ulong il2cpp_vm_array_new_specific; //Thunked from above
27
    public ulong SzArrayNew; //Thunked TO above.
28
    public ulong il2cpp_type_get_object; //Api function (exported)
29
    public ulong il2cpp_vm_reflection_get_type_object; //Thunked from above
30
    public ulong il2cpp_resolve_icall; //Api function (exported)
31
    public ulong InternalCalls_Resolve; //Thunked from above.
32

33
    public ulong il2cpp_string_new; //Api function (exported)
34
    public ulong il2cpp_vm_string_new; //Thunked from above
35
    public ulong il2cpp_string_new_wrapper; //Api function
36
    public ulong il2cpp_vm_string_newWrapper; //Thunked from above
37
    public ulong il2cpp_codegen_string_new_wrapper; //Not sure if actual name, used in ARM64 attribute gens, thunks TO above.
38

39
    public ulong il2cpp_value_box; //Api function (exported)
40
    public ulong il2cpp_vm_object_box; //Thunked from above
41

42
    public ulong il2cpp_object_unbox; //Api function
43
    public ulong il2cpp_vm_object_unbox; //Thunked from above
44

45
    public ulong il2cpp_raise_exception; //Api function (exported)
46
    public ulong il2cpp_vm_exception_raise; //Thunked from above
47
    public ulong il2cpp_codegen_raise_exception; //Thunked TO above. don't know real name.
48

49
    public ulong il2cpp_vm_object_is_inst; //Not exported, not thunked. Can be located via the Type#IsInstanceOfType icall.
50

51
    public ulong AddrPInvokeLookup; //TODO Re-find this and fix name
52

NEW
53
    public IEnumerable<KeyValuePair<string, ulong>> Pairs => resolvedAddressMap;
×
54

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

NEW
57
    private readonly Dictionary<string, ulong> resolvedAddressMap = [];
×
NEW
58
    private readonly HashSet<ulong> resolvedAddressSet = [];
×
59

60
    public bool IsKeyFunctionAddress(ulong address)
61
    {
NEW
62
        return address != 0 && resolvedAddressSet.Contains(address);
×
63
    }
64

65
    private void FindExport(string name, out ulong ptr)
66
    {
67
        Logger.Verbose($"\tLooking for Exported {name} function...");
×
68
        ptr = _appContext.Binary.GetVirtualAddressOfExportedFunctionByName(name);
×
69

70
        Logger.VerboseNewline(ptr == 0 ? "Not found" : $"Found at 0x{ptr:X}");
×
71
    }
×
72

73
    public virtual void Find(ApplicationAnalysisContext applicationAnalysisContext)
74
    {
75
        _appContext = applicationAnalysisContext;
×
76
        Init(applicationAnalysisContext);
×
77

78
        //Try to find System.Exception (should always be there)
79
        if (applicationAnalysisContext.Binary.InstructionSetId == DefaultInstructionSets.X86_32 || applicationAnalysisContext.Binary.InstructionSetId == DefaultInstructionSets.X86_64)
×
80
            //TODO make this abstract and implement in subclasses.
81
            TryGetInitMetadataFromException();
×
82

83
        //New Object
84
        FindExport("il2cpp_object_new", out il2cpp_object_new);
×
85

86
        //Type => Object
87
        FindExport("il2cpp_type_get_object", out il2cpp_type_get_object);
×
88

89
        //Resolve ICall
90
        FindExport("il2cpp_resolve_icall", out il2cpp_resolve_icall);
×
91

92
        //New String
93
        FindExport("il2cpp_string_new", out il2cpp_string_new);
×
94

95
        //New string wrapper
96
        FindExport("il2cpp_string_new_wrapper", out il2cpp_string_new_wrapper);
×
97

98
        //Box Value
99
        FindExport("il2cpp_value_box", out il2cpp_value_box);
×
100

101
        //Unbox Value
102
        FindExport("il2cpp_object_unbox", out il2cpp_object_unbox);
×
103

104
        //Raise Exception
105
        FindExport("il2cpp_raise_exception", out il2cpp_raise_exception);
×
106

107
        //Class Init
108
        FindExport("il2cpp_runtime_class_init", out il2cpp_runtime_class_init_export);
×
109

110
        //New array of fixed size
111
        FindExport("il2cpp_array_new_specific", out il2cpp_array_new_specific);
×
112

113
        //Object IsInst
114
        il2cpp_vm_object_is_inst = GetObjectIsInstFromSystemType();
×
115

116
        AttemptInstructionAnalysisToFillGaps();
×
117

118
        FindThunks();
×
119
        InitializeResolvedAddresses();
×
120
    }
×
121

122
    protected void TryGetInitMetadataFromException()
123
    {
124
        //Exception.get_Message() - first call is either to codegen_initialize_method (< v27) or codegen_initialize_runtime_metadata
125
        Logger.VerboseNewline("\tLooking for Type System.Exception, Method get_Message...");
×
126

127
        var type = LibCpp2IlReflection.GetType("Exception", "System")!;
×
128
        Logger.VerboseNewline("\t\tType Located. Ensuring method exists...");
×
129
        var targetMethod = type.Methods!.FirstOrDefault(m => m.Name == "get_Message");
×
130
        if (targetMethod != null) //Check struct contains valid data 
×
131
        {
132
            Logger.VerboseNewline($"\t\tTarget Method Located at {targetMethod.MethodPointer}. Taking first CALL as the (version-specific) metadata initialization function...");
×
133

134
            var disasm = X86Utils.GetMethodBodyAtVirtAddressNew(targetMethod.MethodPointer, false);
×
135
            var calls = disasm.Where(i => i.Mnemonic == Mnemonic.Call).ToList();
×
136

137
            if (calls.Count == 0)
×
138
            {
139
                Logger.WarnNewline("Couldn't find any call instructions in the method body. This is not expected. Will not have metadata initialization function.");
×
140
                return;
×
141
            }
142

143
            if (_appContext.MetadataVersion < 27)
×
144
            {
145
                il2cpp_codegen_initialize_method = calls.First().NearBranchTarget;
×
146
                Logger.VerboseNewline($"\t\til2cpp_codegen_initialize_method => 0x{il2cpp_codegen_initialize_method:X}");
×
147
            }
148
            else
149
            {
150
                il2cpp_codegen_initialize_runtime_metadata = calls.First().NearBranchTarget;
×
151
                Logger.VerboseNewline($"\t\til2cpp_codegen_initialize_runtime_metadata => 0x{il2cpp_codegen_initialize_runtime_metadata:X}");
×
152
            }
153
        }
154
    }
×
155

156
    protected virtual void AttemptInstructionAnalysisToFillGaps()
157
    {
158
    }
×
159

160
    private void FindThunks()
161
    {
162
        if (il2cpp_object_new != 0)
×
163
        {
164
            Logger.Verbose("\t\tMapping il2cpp_object_new to vm::Object::New...");
×
165
            il2cpp_vm_object_new = FindFunctionThisIsAThunkOf(il2cpp_object_new, true);
×
166
            Logger.VerboseNewline($"Found at 0x{il2cpp_vm_object_new:X}");
×
167
        }
168

169
        if (il2cpp_vm_object_new != 0)
×
170
        {
171
            Logger.Verbose("\t\tLooking for il2cpp_codegen_object_new as a thunk of vm::Object::New...");
×
172

173
            var potentialThunks = FindAllThunkFunctions(il2cpp_vm_object_new, 16);
×
174

175
            //Sort by caller count in ascending order
176
            var list = potentialThunks.Select(ptr => (ptr, count: GetCallerCount(ptr))).ToList();
×
177
            list.SortByExtractedKey(pair => pair.count);
×
178

179
            //Sort in descending order - most called first
180
            list.Reverse();
×
181

182
            //Take first as the target
183
            il2cpp_codegen_object_new = list.FirstOrDefault().ptr;
×
184

185
            Logger.VerboseNewline($"Found at 0x{il2cpp_codegen_object_new:X}");
×
186
        }
187

188
        if (il2cpp_type_get_object != 0)
×
189
        {
190
            Logger.Verbose("\t\tMapping il2cpp_resolve_icall to Reflection::GetTypeObject...");
×
191
            il2cpp_vm_reflection_get_type_object = FindFunctionThisIsAThunkOf(il2cpp_type_get_object);
×
192
            Logger.VerboseNewline($"Found at 0x{il2cpp_vm_reflection_get_type_object:X}");
×
193
        }
194

195
        if (il2cpp_resolve_icall != 0)
×
196
        {
197
            Logger.Verbose("\t\tMapping il2cpp_resolve_icall to InternalCalls::Resolve...");
×
198
            InternalCalls_Resolve = FindFunctionThisIsAThunkOf(il2cpp_resolve_icall);
×
199
            Logger.VerboseNewline($"Found at 0x{InternalCalls_Resolve:X}");
×
200
        }
201

202
        if (il2cpp_string_new != 0)
×
203
        {
204
            Logger.Verbose("\t\tMapping il2cpp_string_new to String::New...");
×
205
            il2cpp_vm_string_new = FindFunctionThisIsAThunkOf(il2cpp_string_new);
×
206
            Logger.VerboseNewline($"Found at 0x{il2cpp_vm_string_new:X}");
×
207
        }
208

209
        if (il2cpp_string_new_wrapper != 0)
×
210
        {
211
            Logger.Verbose("\t\tMapping il2cpp_string_new_wrapper to String::NewWrapper...");
×
212
            il2cpp_vm_string_newWrapper = FindFunctionThisIsAThunkOf(il2cpp_string_new_wrapper);
×
213
            Logger.VerboseNewline($"Found at 0x{il2cpp_vm_string_newWrapper:X}");
×
214
        }
215

216
        if (il2cpp_vm_string_newWrapper != 0)
×
217
        {
218
            Logger.Verbose("\t\tMapping String::NewWrapper to il2cpp_codegen_string_new_wrapper...");
×
219
            il2cpp_codegen_string_new_wrapper = FindAllThunkFunctions(il2cpp_vm_string_newWrapper, 0, il2cpp_string_new_wrapper).FirstOrDefault();
×
220
            Logger.VerboseNewline($"Found at 0x{il2cpp_codegen_string_new_wrapper:X}");
×
221
        }
222

223
        if (il2cpp_value_box != 0)
×
224
        {
225
            Logger.Verbose("\t\tMapping il2cpp_value_box to Object::Box...");
×
226
            il2cpp_vm_object_box = FindFunctionThisIsAThunkOf(il2cpp_value_box);
×
227
            Logger.VerboseNewline($"Found at 0x{il2cpp_vm_object_box:X}");
×
228
        }
229

230
        if (il2cpp_object_unbox != 0)
×
231
        {
232
            Logger.Verbose("\t\tMapping il2cpp_object_unbox to Object::Unbox...");
×
233
            il2cpp_vm_object_unbox = FindFunctionThisIsAThunkOf(il2cpp_object_unbox);
×
234
            Logger.VerboseNewline($"Found at 0x{il2cpp_vm_object_unbox:X}");
×
235
        }
236

237
        if (il2cpp_raise_exception != 0)
×
238
        {
239
            Logger.Verbose("\t\tMapping il2cpp_raise_exception to il2cpp::vm::Exception::Raise...");
×
240
            il2cpp_vm_exception_raise = FindFunctionThisIsAThunkOf(il2cpp_raise_exception, true);
×
241
            Logger.VerboseNewline($"Found at 0x{il2cpp_vm_exception_raise:X}");
×
242
        }
243

244
        if (il2cpp_vm_exception_raise != 0)
×
245
        {
246
            Logger.Verbose("\t\tMapping il2cpp::vm::Exception::Raise to il2cpp_codegen_raise_exception...");
×
247
            il2cpp_codegen_raise_exception = FindAllThunkFunctions(il2cpp_vm_exception_raise, 4, il2cpp_raise_exception).FirstOrDefault();
×
248
            Logger.VerboseNewline($"Found at 0x{il2cpp_codegen_raise_exception:X}");
×
249
        }
250

251
        if (il2cpp_runtime_class_init_export != 0)
×
252
        {
253
            Logger.Verbose("\t\tMapping il2cpp_runtime_class_init to il2cpp:vm::Runtime::ClassInit...");
×
254
            il2cpp_runtime_class_init_actual = FindFunctionThisIsAThunkOf(il2cpp_runtime_class_init_export);
×
255
            Logger.VerboseNewline($"Found at 0x{il2cpp_runtime_class_init_actual:X}");
×
256
        }
257

258
        if (il2cpp_array_new_specific != 0)
×
259
        {
260
            Logger.Verbose("\t\tMapping il2cpp_array_new_specific to vm::Array::NewSpecific...");
×
261
            il2cpp_vm_array_new_specific = FindFunctionThisIsAThunkOf(il2cpp_array_new_specific);
×
262
            Logger.VerboseNewline($"Found at 0x{il2cpp_vm_array_new_specific:X}");
×
263
        }
264

265
        if (il2cpp_vm_array_new_specific != 0)
×
266
        {
267
            Logger.Verbose("\t\tLooking for SzArrayNew as a thunk function proxying Array::NewSpecific...");
×
268
            SzArrayNew = FindAllThunkFunctions(il2cpp_vm_array_new_specific, 4, il2cpp_array_new_specific).FirstOrDefault();
×
269
            Logger.VerboseNewline($"Found at 0x{SzArrayNew:X}");
×
270
        }
271
    }
×
272

273
    protected abstract ulong GetObjectIsInstFromSystemType();
274

275
    /// <summary>
276
    /// Given a function at addr, find a function which serves no purpose other than to call addr.
277
    /// </summary>
278
    /// <param name="addr">The address of the function to call.</param>
279
    /// <param name="maxBytesBack">The maximum number of bytes to go back from any branching instructions to find the actual start of the thunk function.</param>
280
    /// <param name="addressesToIgnore">A list of function addresses which this function must not return</param>
281
    /// <returns>The address of the first function in the file which thunks addr, starts within maxBytesBack bytes of the branch, and is not contained within addressesToIgnore, else 0 if none can be found.</returns>
282
    protected abstract IEnumerable<ulong> FindAllThunkFunctions(ulong addr, uint maxBytesBack = 0, params ulong[] addressesToIgnore);
283

284
    /// <summary>
285
    /// Given a function at thunkPtr, return the address of the function that said function exists only to call.
286
    /// That is, given a function which performs no meaningful operations other than to call x, return the address of x.
287
    /// </summary>
288
    /// <param name="thunkPtr">The address of the thunk function</param>
289
    /// <param name="prioritiseCall">True to prioritise "call" statements - conditional flow transfer - over "jump" statements - unconditional flow transfer. False for the inverse.</param>
290
    /// <returns>The address of the thunked function, if it can be found, else 0</returns>
291
    protected abstract ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false);
292

293
    protected abstract int GetCallerCount(ulong toWhere);
294

295
    protected virtual void Init(ApplicationAnalysisContext context)
296
    {
297
    }
×
298

299
    private void InitializeResolvedAddresses()
300
    {
NEW
301
        resolvedAddressMap.Clear();
×
NEW
302
        resolvedAddressSet.Clear();
×
303

NEW
304
        AddResolved(il2cpp_codegen_initialize_method);
×
NEW
305
        AddResolved(il2cpp_codegen_initialize_runtime_metadata);
×
NEW
306
        AddResolved(il2cpp_vm_metadatacache_initializemethodmetadata);
×
NEW
307
        AddResolved(il2cpp_runtime_class_init_export);
×
NEW
308
        AddResolved(il2cpp_runtime_class_init_actual);
×
NEW
309
        AddResolved(il2cpp_object_new);
×
NEW
310
        AddResolved(il2cpp_vm_object_new);
×
NEW
311
        AddResolved(il2cpp_codegen_object_new);
×
NEW
312
        AddResolved(il2cpp_array_new_specific);
×
NEW
313
        AddResolved(il2cpp_vm_array_new_specific);
×
NEW
314
        AddResolved(SzArrayNew);
×
NEW
315
        AddResolved(il2cpp_type_get_object);
×
NEW
316
        AddResolved(il2cpp_vm_reflection_get_type_object);
×
NEW
317
        AddResolved(il2cpp_resolve_icall);
×
NEW
318
        AddResolved(InternalCalls_Resolve);
×
319

NEW
320
        AddResolved(il2cpp_string_new);
×
NEW
321
        AddResolved(il2cpp_vm_string_new);
×
NEW
322
        AddResolved(il2cpp_string_new_wrapper);
×
NEW
323
        AddResolved(il2cpp_vm_string_newWrapper);
×
NEW
324
        AddResolved(il2cpp_codegen_string_new_wrapper);
×
325

NEW
326
        AddResolved(il2cpp_value_box);
×
NEW
327
        AddResolved(il2cpp_vm_object_box);
×
328

NEW
329
        AddResolved(il2cpp_object_unbox);
×
NEW
330
        AddResolved(il2cpp_vm_object_unbox);
×
331

NEW
332
        AddResolved(il2cpp_raise_exception);
×
NEW
333
        AddResolved(il2cpp_vm_exception_raise);
×
NEW
334
        AddResolved(il2cpp_codegen_raise_exception);
×
335

NEW
336
        AddResolved(il2cpp_vm_object_is_inst);
×
337

NEW
338
        AddResolved(AddrPInvokeLookup);
×
339

340
        void AddResolved(ulong address, [CallerArgumentExpression(nameof(address))] string name = "")
341
        {
NEW
342
            resolvedAddressSet.Add(address);
×
NEW
343
            resolvedAddressMap[name] = address;
×
NEW
344
        }
×
UNCOV
345
    }
×
346
}
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