summaryrefslogtreecommitdiff
path: root/kernel_call/kernel_memory.c
blob: fba81b8116b6ce35a393fa8ff4e66077795a8567 (plain)
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
/*
 * kernel_memory.c
 * Brandon Azad
 */
#define KERNEL_MEMORY_EXTERN
#include "kernel_memory.h"

#include "log.h"
#include "mach_vm.h"
#include "parameters.h"

// ---- Kernel memory functions -------------------------------------------------------------------

bool
kernel_read(uint64_t address, void *data, size_t size) {
	mach_vm_size_t size_out;
	kern_return_t kr = mach_vm_read_overwrite(kernel_task_port, address,
			size, (mach_vm_address_t) data, &size_out);
	if (kr != KERN_SUCCESS) {
		ERROR("%s returned %d: %s", "mach_vm_read_overwrite", kr, mach_error_string(kr));
		ERROR("could not %s address 0x%016llx", "read", address);
		return false;
	}
	if (size_out != size) {
		ERROR("partial read of address 0x%016llx: %llu of %zu bytes",
				address, size_out, size);
		return false;
	}
	return true;
}

bool
kernel_write(uint64_t address, const void *data, size_t size) {
	kern_return_t kr = mach_vm_write(kernel_task_port, address,
			(mach_vm_address_t) data, (mach_msg_size_t) size);
	if (kr != KERN_SUCCESS) {
		ERROR("%s returned %d: %s", "mach_vm_write", kr, mach_error_string(kr));
		ERROR("could not %s address 0x%016llx", "write", address);
		return false;
	}
	return true;
}

uint8_t
kernel_read8(uint64_t address) {
	uint8_t value;
	bool ok = kernel_read(address, &value, sizeof(value));
	if (!ok) {
		return -1;
	}
	return value;
}

uint16_t
kernel_read16(uint64_t address) {
	uint16_t value;
	bool ok = kernel_read(address, &value, sizeof(value));
	if (!ok) {
		return -1;
	}
	return value;
}

uint32_t
kernel_read32(uint64_t address) {
	uint32_t value;
	bool ok = kernel_read(address, &value, sizeof(value));
	if (!ok) {
		return -1;
	}
	return value;
}

uint64_t
kernel_read64(uint64_t address) {
	uint64_t value;
	bool ok = kernel_read(address, &value, sizeof(value));
	if (!ok) {
		return -1;
	}
	return value;
}

bool
kernel_write8(uint64_t address, uint8_t value) {
	return kernel_write(address, &value, sizeof(value));
}

bool
kernel_write16(uint64_t address, uint16_t value) {
	return kernel_write(address, &value, sizeof(value));
}

bool
kernel_write32(uint64_t address, uint32_t value) {
	return kernel_write(address, &value, sizeof(value));
}

bool
kernel_write64(uint64_t address, uint64_t value) {
	return kernel_write(address, &value, sizeof(value));
}

// ---- Kernel utility functions ------------------------------------------------------------------

bool
kernel_ipc_port_lookup(uint64_t task, mach_port_name_t port_name,
		uint64_t *ipc_port, uint64_t *ipc_entry) {
	// Get the task's ipc_space.
	uint64_t itk_space = kernel_read64(task + OFFSET(task, itk_space));
	// Get the size of the table.
	uint32_t is_table_size = kernel_read32(itk_space + OFFSET(ipc_space, is_table_size));
	// Get the index of the port and check that it is in-bounds.
	uint32_t port_index = MACH_PORT_INDEX(port_name);
	if (port_index >= is_table_size) {
		return false;
	}
	// Get the space's is_table and compute the address of this port's entry.
	uint64_t is_table = kernel_read64(itk_space + OFFSET(ipc_space, is_table));
	uint64_t entry = is_table + port_index * SIZE(ipc_entry);
	if (ipc_entry != NULL) {
		*ipc_entry = entry;
	}
	// Get the address of the port if requested.
	if (ipc_port != NULL) {
		*ipc_port = kernel_read64(entry + OFFSET(ipc_entry, ie_object));
	}
	return true;
}