in cortado/rtas/src/thread_injector_intel.c [28:149]
int inject(pid_t pid)
{
task_t remoteTask;
mach_error_t kr = 0;
/**
* Second - the critical part - we need task_for_pid in order to get the task port of the target
* pid. This is our do-or-die: If we get the port, we can do *ANYTHING* we want. If we don't, we're
* #$%#$%.
*/
kr = task_for_pid(mach_task_self(), pid, &remoteTask);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Unable to call task_for_pid on pid %d: %s. Cannot continue!\n", pid, mach_error_string(kr));
return (-1);
}
mach_vm_address_t remoteStack64 = (vm_address_t)NULL;
mach_vm_address_t remoteCode64 = (vm_address_t)NULL;
kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr));
return (-2);
}
else {
fprintf(stderr, "Allocated remote stack @0x%llx\n", remoteStack64);
}
/**
* Then we allocate the memory for the thread
*/
remoteCode64 = (vm_address_t)NULL;
kr = mach_vm_allocate(remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr));
return (-2);
}
/**
* Write the (now patched) code
*/
kr = mach_vm_write(remoteTask, // Task port
remoteCode64, // Virtual Address (Destination)
(vm_address_t)injectedCode, // Source
sizeof(injectedCode)); // Length of the source
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Unable to write remote thread memory: Error %s\n", mach_error_string(kr));
return (-3);
}
/*
* Mark code as executable - This also requires a workaround on iOS, btw.
*/
kr = vm_protect(remoteTask, remoteCode64, sizeof(injectedCode), FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
/*
* Mark stack as writable - not really necessary
*/
kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Unable to set memory permissions for remote thread: Error %s\n", mach_error_string(kr));
return (-4);
}
/*
* Create thread - This is obviously hardware specific.
*/
x86_thread_state64_t remoteThreadState64;
thread_act_t remoteThread;
memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64));
remoteStack64 += (STACK_SIZE / 2); // this is the real stack
//remoteStack64 -= 8; // need alignment of 16
const char *p = (const char *)remoteCode64;
remoteThreadState64.__rip = (u_int64_t)(vm_address_t)remoteCode64;
// set remote Stack Pointer
remoteThreadState64.__rsp = (u_int64_t)remoteStack64;
remoteThreadState64.__rbp = (u_int64_t)remoteStack64;
printf("Remote Stack 64 0x%llx, Remote code is %p\n", remoteStack64, p);
/*
* create thread and launch it in one go
*/
kr = thread_create_running(remoteTask, x86_THREAD_STATE64,
(thread_state_t)&remoteThreadState64, x86_THREAD_STATE64_COUNT, &remoteThread);
//kr = thread_create(remoteTask, &remoteThread);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Unable to create remote thread: error %s", mach_error_string(kr));
return (-3);
}
// Wait for mach thread to finish
/* mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT;
for (;;) {
kr = thread_get_state(remoteThread, x86_THREAD_STATE64, (thread_state_t)&remoteThreadState64, &thread_state_count);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Error getting stub thread state: error %s", mach_error_string(kr));
break;
}
if (remoteThreadState64.__rax == 0xD13) {
printf("Stub thread finished\n");
kr = thread_terminate(remoteThread);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Error terminating stub thread: error %s", mach_error_string(kr));
}
break;
}
}*/
sleep(5);
return 0;
}