-
-
Notifications
You must be signed in to change notification settings - Fork 297
Expand file tree
/
Copy pathArmV7Utils.cs
More file actions
91 lines (72 loc) · 3.47 KB
/
ArmV7Utils.cs
File metadata and controls
91 lines (72 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using System;
using System.Collections.Generic;
using System.Linq;
using Cpp2IL.Core.Extensions;
using Gee.External.Capstone;
using Gee.External.Capstone.Arm;
using LibCpp2IL;
namespace Cpp2IL.Core.Utils;
public static class ArmV7Utils
{
private static CapstoneArmDisassembler? _armDisassembler;
private static void InitArmDecompilation()
{
var disassembler = CapstoneDisassembler.CreateArmDisassembler(ArmDisassembleMode.Arm);
disassembler.EnableInstructionDetails = true;
disassembler.EnableSkipDataMode = true;
disassembler.DisassembleSyntax = DisassembleSyntax.Intel;
_armDisassembler = disassembler;
}
public static ReadOnlyMemory<byte>? TryGetMethodBodyBytesFast(ulong virtAddress, bool isCAGen)
{
var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress);
var length = (startOfNext - virtAddress);
if (isCAGen && length > 50_000)
return null;
if (startOfNext <= 0)
//We have to fall through to default behavior for the last method because we cannot accurately pinpoint its end
return null;
var rawStartOfNextMethod = LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(startOfNext);
var rawStart = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress);
if (rawStartOfNextMethod < rawStart)
rawStartOfNextMethod = LibCpp2IlMain.Binary.RawLength;
return LibCpp2IlMain.Binary.GetRawBinaryContent()[(int)rawStart..(int)rawStartOfNextMethod];
}
public static List<ArmInstruction> GetArmV7MethodBodyAtVirtualAddress(ulong virtAddress, bool managed = true, int count = -1)
{
if (_armDisassembler == null)
InitArmDecompilation();
//We can't use CppMethodBodyBytes to get the byte array, because ARMv7 doesn't have filler bytes like x86 does.
//So we can't work out the end of the method.
//But we can find the start of the next one! (If managed)
if (managed)
{
var startOfNext = MiscUtils.GetAddressOfNextFunctionStart(virtAddress);
//We have to fall through to default behavior for the last method because we cannot accurately pinpoint its end
if (startOfNext > 0)
{
var rawStartOfNextMethod = LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(startOfNext);
var rawStart = LibCpp2IlMain.Binary.MapVirtualAddressToRaw(virtAddress);
if (rawStartOfNextMethod < rawStart)
rawStartOfNextMethod = LibCpp2IlMain.Binary.RawLength;
byte[] bytes = LibCpp2IlMain.Binary.GetRawBinaryContent()[(int)rawStart..(int)rawStartOfNextMethod].ToArray();
var iter = _armDisassembler!.Iterate(bytes, (long)virtAddress);
if (count > 0)
iter = iter.Take(count);
return iter.ToList();
}
}
//Unmanaged function, look for first b or bl
var pos = (int)LibCpp2IlMain.Binary!.MapVirtualAddressToRaw(virtAddress);
var allBytes = LibCpp2IlMain.Binary.GetRawBinaryContent();
List<ArmInstruction> ret = [];
while (!ret.Any(i => i.Mnemonic is "b" or ".byte") && (count == -1 || ret.Count < count))
{
//All arm64 instructions are 4 bytes
ret.AddRange(_armDisassembler!.Iterate(allBytes[pos..(pos + 4)].ToArray(), (long)virtAddress));
virtAddress += 4;
pos += 4;
}
return ret;
}
}