-
-
Notifications
You must be signed in to change notification settings - Fork 212
/
Copy pathMiniArm64Decompiler.cs
130 lines (102 loc) · 3.72 KB
/
MiniArm64Decompiler.cs
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using System.Collections.Generic;
using LibCpp2IL.Elf;
namespace LibCpp2IL;
/// <summary>
/// Full credit for most of this file goes to djKaty in the il2cppinspector project.
/// </summary>
internal static class MiniArm64Decompiler
{
private static (uint reg, ulong page)? GetAdrp(uint inst, ulong pc)
{
if ((inst.Bits(24, 8) & 0b_1000_1111) != 1 << 7)
return null;
var addendLo = inst.Bits(29, 2);
var addendHi = inst.Bits(5, 19);
var addend = (addendHi << 14) + (addendLo << 12);
var page = pc & ~((1Lu << 12) - 1);
var reg = inst.Bits(0, 5);
return (reg, page + addend);
}
// https://static.docs.arm.com/100878/0100/fundamentals_of_armv8_a_100878_0100_en.pdf states:
// Unlike ARMv7-A, there is no implied offset of 4 or 8 bytes
private static (uint reg, ulong addr)? GetAdr(uint inst, ulong pc)
{
if (inst.Bits(24, 5) != 0b10000 || inst.Bits(31, 1) != 0)
return null;
ulong imm = (inst.Bits(5, 19) << 2) + inst.Bits(29, 2);
// Sign extend the 21-bit number to 64 bits
imm = (imm & (1 << 20)) == 0 ? imm : imm | unchecked((ulong)-(1 << 21));
var reg = inst.Bits(0, 5);
return (reg, pc + imm);
}
private static (uint reg_n, uint reg_d, uint imm)? GetAdd64(uint inst)
{
if (inst.Bits(22, 10) != 0b_1001_0001_00)
return null;
var imm = inst.Bits(10, 12);
var regN = inst.Bits(5, 5);
var regD = inst.Bits(0, 5);
return (regN, regD, imm);
}
private static (uint reg_t, uint reg_n, uint simm)? GetLdr64ImmOffset(uint inst)
{
if (inst.Bits(22, 10) != 0b_11_1110_0101)
return null;
var imm = inst.Bits(10, 12);
var regT = inst.Bits(0, 5);
var regN = inst.Bits(5, 5);
return (regT, regN, imm);
}
public static bool IsB(uint inst) => inst.Bits(26, 6) == 0b_000101;
public static Dictionary<uint, ulong> GetAddressesLoadedIntoRegisters(List<uint> funcBody, ulong baseAddress, ElfFile image)
{
var ret = new Dictionary<uint, ulong>();
var pc = baseAddress;
foreach (var inst in funcBody)
{
//ADRP Xn, #page instruction
if (GetAdrp(inst, pc) is var (reg, page))
{
ret[reg] = page;
}
//ADR Xn, addr
if (GetAdr(inst, pc) is var (adrReg, addr))
{
ret[adrReg] = addr;
}
//Add Xn, Xd, #imm
if (GetAdd64(inst) is var (regN, regD, imm))
{
//Check adding to self (n == d) and we have the register
if (regN == regD && ret.ContainsKey(regD))
ret[regD] += imm;
}
//LDR Xm, [Xn, #offset]
if (GetLdr64ImmOffset(inst) is var (regT, regLdrN, simm))
{
//Check ldr is to self and we have the reg
if (regT == regLdrN && ret.ContainsKey(regLdrN))
{
ret[regLdrN] += simm * 8;
//Dereference resulting pointer
ret[regLdrN] = image.ReadPointerAtVirtualAddress(ret[regLdrN]);
}
}
pc += 4;
}
return ret;
}
public static List<uint> ReadFunctionAtRawAddress(ElfFile file, uint loc, uint maxLength)
{
//Either we find a b (hard jump), or we exceed maxLength
var ret = new List<uint>();
uint inst;
file.Position = file.MapVirtualAddressToRaw(loc);
do
{
inst = file.ReadUInt32();
ret.Add(inst);
} while (!IsB(inst) && ret.Count < maxLength);
return ret;
}
}