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

SamboyCoding / Cpp2IL / 25641285720

10 May 2026 10:18PM UTC coverage: 35.104% (-0.2%) from 35.33%
25641285720

Pull #542

github

web-flow
Merge 9249bcb5b into 6af99f218
Pull Request #542: Remove static mutable state from LibCpp2IL 2: Electric Boogaloo

1877 of 6693 branches covered (28.04%)

Branch coverage included in aggregate %.

303 of 569 new or added lines in 66 files covered. (53.25%)

12 existing lines in 11 files now uncovered.

4394 of 11171 relevant lines covered (39.33%)

268486.35 hits per line

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

0.0
/Cpp2IL.Core/Il2CppApiFunctions/X86KeyFunctionAddresses.cs
1
using System.Collections.Generic;
2
using System.Linq;
3
using Cpp2IL.Core.Logging;
4
using Cpp2IL.Core.Model.Contexts;
5
using Cpp2IL.Core.Utils;
6
using Iced.Intel;
7

8
namespace Cpp2IL.Core.Il2CppApiFunctions;
9

10
public class X86KeyFunctionAddresses : BaseKeyFunctionAddresses
11
{
12
    private InstructionList? _cachedDisassembledBytes;
13

14
    private InstructionList DisassembleTextSection()
15
    {
16
        if (_cachedDisassembledBytes == null)
×
17
        {
NEW
18
            var binary = _appContext.Binary;
×
NEW
19
            var toDisasm = binary.GetEntirePrimaryExecutableSection();
×
NEW
20
            _cachedDisassembledBytes = X86Utils.Disassemble(toDisasm, binary.GetVirtualAddressOfPrimaryExecutableSection(), binary.is32Bit);
×
21
        }
22

23
        return _cachedDisassembledBytes;
×
24
    }
25

26
    public override void Find(ApplicationAnalysisContext applicationAnalysisContext)
27
    {
28
        base.Find(applicationAnalysisContext);
×
29

30
        _cachedDisassembledBytes = null; //Clean up once we're done finding everything
×
31
    }
×
32

33
    protected override IEnumerable<ulong> FindAllThunkFunctions(ulong addr, uint maxBytesBack = 0, params ulong[] addressesToIgnore)
34
    {
35
        //Disassemble .text
36
        var allInstructions = DisassembleTextSection();
×
37

38
        //Find all jumps to the target address
39
        var matchingJmps = allInstructions.Where(i => i.Mnemonic is Mnemonic.Jmp or Mnemonic.Call && i.NearBranchTarget == addr).ToList();
×
40

41
        foreach (var matchingJmp in matchingJmps)
×
42
        {
43
            if (addressesToIgnore.Contains(matchingJmp.IP)) continue;
×
44

45
            //Find this instruction in the raw file
NEW
46
            var binary = _appContext.Binary;
×
NEW
47
            var offsetInPe = (ulong)binary.MapVirtualAddressToRaw(matchingJmp.IP);
×
NEW
48
            if (offsetInPe == 0 || offsetInPe == (ulong)(binary.RawLength - 1))
×
49
                continue;
50

51
            //get next and previous bytes
NEW
52
            var previousByte = binary.GetByteAtRawAddress(offsetInPe - 1);
×
NEW
53
            var nextByte = binary.GetByteAtRawAddress(offsetInPe + (ulong)matchingJmp.Length);
×
54

55
            //Double-cc = thunk
56
            if (previousByte == 0xCC && nextByte == 0xCC)
×
57
            {
58
                yield return matchingJmp.IP;
×
59
                continue;
×
60
            }
61

62
            if (nextByte == 0xCC && maxBytesBack > 0)
×
63
            {
64
                for (ulong backtrack = 1; backtrack < maxBytesBack && offsetInPe - backtrack > 0; backtrack++)
×
65
                {
66
                    if (addressesToIgnore.Contains(matchingJmp.IP - (backtrack - 1)))
×
67
                        //Move to next jmp
68
                        break;
69

NEW
70
                    if (binary.GetByteAtRawAddress(offsetInPe - backtrack) == 0xCC)
×
71
                    {
72
                        yield return matchingJmp.IP - (backtrack - 1);
×
73
                        break;
×
74
                    }
75
                }
76
            }
77
        }
78
    }
×
79

80
    protected override ulong GetObjectIsInstFromSystemType()
81
    {
82
        Logger.Verbose("\tTrying to use System.Type::IsInstanceOfType to find il2cpp::vm::Object::IsInst...");
×
NEW
83
        var typeIsInstanceOfType = ReflectionCache.GetType("Type", "System")?.Methods?.FirstOrDefault(m => m.Name == "IsInstanceOfType");
×
84
        if (typeIsInstanceOfType == null)
×
85
        {
86
            Logger.VerboseNewline("Type or method not found, aborting.");
×
87
            return 0;
×
88
        }
89

90
        //IsInstanceOfType is a very simple ICall, that looks like this:
91
        //  Il2CppClass* klass = vm::Class::FromIl2CppType(type->type.type);
92
        //  return il2cpp::vm::Object::IsInst(obj, klass) != NULL;
93
        //The last call is to Object::IsInst
94

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

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

100
        if (lastCall.Mnemonic == Mnemonic.INVALID)
×
101
        {
102
            Logger.VerboseNewline("Method does not match expected signature. Aborting.");
×
103
            return 0;
×
104
        }
105

106
        Logger.VerboseNewline($"Success. IsInst found at 0x{lastCall.NearBranchTarget:X}");
×
107
        return lastCall.NearBranchTarget;
×
108
    }
109

110
    protected override ulong FindFunctionThisIsAThunkOf(ulong thunkPtr, bool prioritiseCall = false)
111
    {
NEW
112
        var instructions = X86Utils.GetMethodBodyAtVirtAddressNew(thunkPtr, true, _appContext.Binary);
×
113

114
        var target = prioritiseCall ? Mnemonic.Call : Mnemonic.Jmp;
×
115
        var matchingCall = instructions.FirstOrDefault(i => i.Mnemonic == target);
×
116

117
        if (matchingCall.Mnemonic == Mnemonic.INVALID)
×
118
        {
119
            target = target == Mnemonic.Call ? Mnemonic.Jmp : Mnemonic.Call;
×
120
            matchingCall = instructions.FirstOrDefault(i => i.Mnemonic == target);
×
121
        }
122

123
        return matchingCall.Mnemonic != Mnemonic.INVALID ? matchingCall.NearBranchTarget : 0;
×
124
    }
125

126
    protected override int GetCallerCount(ulong toWhere)
127
    {
128
        //Disassemble .text
129
        var allInstructions = DisassembleTextSection();
×
130

131
        //Find all jumps to the target address
132
        return allInstructions.Count(i => i.Mnemonic == Mnemonic.Jmp || i.Mnemonic == Mnemonic.Call && i.NearBranchTarget == toWhere);
×
133
    }
134
}
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