Skip to content

Commit

Permalink
add standalone injector
Browse files Browse the repository at this point in the history
  • Loading branch information
xorpse committed Jun 9, 2021
1 parent 3f0f1a6 commit 3354518
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 0 deletions.
6 changes: 6 additions & 0 deletions arm64-injector-standalone/arm64-inject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include <sys/types.h>
#include <mach/error.h>

extern kern_return_t inject(pid_t pid);
14 changes: 14 additions & 0 deletions arm64-injector-standalone/extract.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

# assemble
as -o sa_arm64e.o sa_arm64e.s

# calculate size and offset
off=$(otool -l sa_arm64e.o | grep fileoff | sed 's/ fileoff //')
siz=$(otool -l sa_arm64e.o | grep filesize | sed 's/ filesize //')

# extract
dd if=sa_arm64e.o of=sa_arm64e bs=1 count=$siz skip=$off &> /dev/null

# build header
xxd -i -a sa_arm64e sa_arm64e.h
179 changes: 179 additions & 0 deletions arm64-injector-standalone/inject.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <mach/mach.h>
#include <mach/error.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <pthread.h>
#include <mach/mach_vm.h>

#include <mach/arm/thread_status.h>
#include <mach/arm/_structs.h>
#include <ptrauth.h>

#include "sa_arm64e.h"

const uint64_t STACK_SIZE = 0x10000;
const char *SA_POINTER_SENTINEL = "AAAAAAAA";

static void fixup_shellcode() {
uint64_t pthread_set_self_ptr = (uint64_t)ptrauth_strip((void (*)(void))dlsym(RTLD_DEFAULT, "_pthread_set_self"), ptrauth_key_asia);
uint64_t pthread_create_from_mach_thread_ptr = (uint64_t)ptrauth_strip((void (*)(void))dlsym(RTLD_DEFAULT, "pthread_create_from_mach_thread"), ptrauth_key_asia);
uint64_t mach_thread_self_ptr = (uint64_t)ptrauth_strip((void (*)(void))mach_thread_self, ptrauth_key_asia);
uint64_t thread_suspend_ptr = (uint64_t)ptrauth_strip((void (*)(void))thread_suspend, ptrauth_key_asia);
uint64_t dlopen_ptr = (uint64_t)ptrauth_strip((void (*)(void))dlopen, ptrauth_key_asia);
uint64_t dlerror_ptr = (uint64_t)ptrauth_strip((void (*)(void))dlerror, ptrauth_key_asia);

unsigned char *pointers = memmem(sa_arm64e, sizeof(sa_arm64e), SA_POINTER_SENTINEL, strlen(SA_POINTER_SENTINEL));
if (!pointers) {
return;
}

memcpy(pointers, &pthread_set_self_ptr, sizeof(uint64_t));
pointers += sizeof(uint64_t);

memcpy(pointers, &pthread_create_from_mach_thread_ptr, sizeof(uint64_t));
pointers += sizeof(uint64_t);

memcpy(pointers, &mach_thread_self_ptr, sizeof(uint64_t));
pointers += sizeof(uint64_t);

memcpy(pointers, &thread_suspend_ptr, sizeof(uint64_t));
pointers += sizeof(uint64_t);

memcpy(pointers, &dlopen_ptr, sizeof(uint64_t));
pointers += sizeof(uint64_t);

memcpy(pointers, &dlerror_ptr, sizeof(uint64_t));
}

static kern_return_t inject_task(task_t dock) {
kern_return_t kr = KERN_SUCCESS;

mach_vm_address_t stack_region = 0;
mach_vm_address_t code_region = 0;

if ((kr = mach_vm_allocate(dock, &stack_region, STACK_SIZE, VM_FLAGS_ANYWHERE)) != KERN_SUCCESS) {
fprintf(stderr, "could not allocate stack region\n");
return kr;
}

if ((kr = mach_vm_allocate(dock, &code_region, sizeof(sa_arm64e), VM_FLAGS_ANYWHERE)) != KERN_SUCCESS) {
fprintf(stderr, "could not allocate code region\n");
return kr;
}

if ((kr = mach_vm_write(dock, code_region, (vm_address_t)sa_arm64e, sizeof(sa_arm64e))) != KERN_SUCCESS) {
fprintf(stderr, "could not write code region\n");
return kr;
}

if ((kr = vm_protect(dock, code_region, sizeof(sa_arm64e), FALSE, VM_PROT_READ | VM_PROT_EXECUTE)) != KERN_SUCCESS) {
fprintf(stderr, "could not set permissions on code region\n");
return kr;
}

if ((kr = vm_protect(dock, stack_region, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE)) != KERN_SUCCESS) {
fprintf(stderr, "could not set permissions on stack region\n");
return kr;
}

struct arm_unified_thread_state thread_state = { };
struct arm_unified_thread_state machine_thread_state = { };

thread_state_flavor_t flavor = ARM_UNIFIED_THREAD_STATE;
mach_msg_type_number_t state_count = ARM_UNIFIED_THREAD_STATE_COUNT;
mach_msg_type_number_t machine_state_count = ARM_UNIFIED_THREAD_STATE_COUNT;

thread_act_t dock_thread = 0;

memset(&thread_state, 0, sizeof(thread_state));
memset(&machine_thread_state, 0, sizeof(machine_thread_state));

stack_region += STACK_SIZE >> 1;

thread_state.ash.flavor = ARM_THREAD_STATE64;
thread_state.ash.count = ARM_THREAD_STATE64_COUNT;

__darwin_arm_thread_state64_set_pc_fptr(
thread_state.ts_64,
ptrauth_sign_unauthenticated((void (*)(void))code_region, ptrauth_key_asia, 0)
);

__darwin_arm_thread_state64_set_sp(
thread_state.ts_64,
stack_region
);

if ((kr = thread_create(dock, &dock_thread)) != KERN_SUCCESS) {
fprintf(stderr, "could not create thread: error %s\n", mach_error_string(kr));
return kr;
}

void *module = dlopen("/usr/lib/system/libsystem_kernel.dylib", RTLD_GLOBAL | RTLD_LAZY);
if (!module) {
fprintf(stderr, "could not load `libsystem_kernel.dylib`\n");
return KERN_FAILURE;
}

kern_return_t (*_thread_convert_thread_state)(
thread_act_t, int, thread_state_flavor_t, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *
) = dlsym(module, "thread_convert_thread_state");

dlclose(module);

if (!_thread_convert_thread_state) {
fprintf(stderr, "could not get address of `thread_convert_thread_state`\n");
return KERN_FAILURE;
}

if ((kr = _thread_convert_thread_state(dock_thread, 2, flavor, (thread_state_t)&thread_state, state_count, (thread_state_t)&machine_thread_state, &machine_state_count)) != KERN_SUCCESS) {
fprintf(stderr, "could not convert thread state: error %d %s\n", kr, mach_error_string(kr));
return kr;
}

if ((kr = thread_set_state(dock_thread, flavor, (thread_state_t)&machine_thread_state, machine_state_count)) != KERN_SUCCESS) {
fprintf(stderr, "could not set thread state: error %s\n", mach_error_string(kr));
return kr;
}

if ((kr = thread_resume(dock_thread)) != KERN_SUCCESS) {
fprintf(stderr, "could not start thread: error %s\n", mach_error_string(kr));
return kr;
}

mach_port_deallocate(mach_task_self(), dock_thread);

return kr;
}

kern_return_t inject(pid_t pid) {
task_t task;
kern_return_t kr = KERN_SUCCESS;

fixup_shellcode();

if ((kr = task_for_pid(mach_task_self(), pid, &task)) != KERN_SUCCESS) {
return kr;
}

if ((kr = inject_task(task)) != KERN_SUCCESS) {
fprintf(stderr, "could not perform injection into %d (Dock)\n", pid);
}

mach_port_deallocate(mach_task_self(), task);
return kr;
}

int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s <pid-of-dock>\n", argv[0]);
return KERN_FAILURE;
}

pid_t pid = atoi(argv[1]);
return inject(pid);
}
9 changes: 9 additions & 0 deletions arm64-injector-standalone/makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
all: sa_arm64e.h
clang -o inject inject.c -arch arm64e -std=c99 -Wall -DNDEBUG -O2 -fvisibility=hidden -mmacosx-version-min=10.13

sa_arm64e.h:
./extract.sh

clean:
rm -f inject inject.o
rm -f sa_arm64e sa_arm64e.o sa_arm64e.h
68 changes: 68 additions & 0 deletions arm64-injector-standalone/sa_arm64e.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.global _start
.align 2

_start:
sub sp, sp, #0x20
stp x29, x30, [sp, #0x10]
add x29, sp, #10
add x0, sp, #0x8

adr x9, __pthread_set_self
ldr x9, [x9]
blr x9

adr x2, _payload
paciza x2

add x0, sp, #0x8
mov x1, #0
mov x3, #0
adr x9, _pthread_create_from_mach_thread
ldr x9, [x9]
blr x9

adr x9, _mach_thread_self
ldr x9, [x9]
blr x9

adr x9, _thread_suspend
ldr x9, [x9]
blr x9

ldp x29, x30, [sp, #0x10]
add sp, sp, #0x20
ret

_payload:
pacibsp
stp x29, x30, [sp, #-0x10]!
mov x29, sp

adr x0, _payload_path
mov w1, #0x2
adr x9, _dlopen
ldr x9, [x9]
blr x9

cbnz x0, _payload_done

adr x9, _dlerror
ldr x9, [x9]
blr x9

_payload_done:
mov x0, #0

ldp x29, x30, [sp], #0x10
retab

; function pointers
__pthread_set_self: .ascii "AAAAAAAA"
_pthread_create_from_mach_thread: .ascii "BBBBBBBB"
_mach_thread_self: .ascii "CCCCCCCC"
_thread_suspend: .ascii "DDDDDDDD"
_dlopen: .ascii "EEEEEEEE"
_dlerror: .ascii "FFFFFFFF"

; data
_payload_path: .ascii "/Library/ScriptingAdditions/yabai.osax/Contents/Resources/payload.bundle/Contents/MacOS/payload\0"

0 comments on commit 3354518

Please sign in to comment.