Skip to content

Commit

Permalink
this is a bad idea
Browse files Browse the repository at this point in the history
  • Loading branch information
comex committed Apr 8, 2011
1 parent 1711e37 commit 62499f9
Show file tree
Hide file tree
Showing 9 changed files with 560 additions and 401 deletions.
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ GCC ?= /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -arch ar
CFLAGS += -g3 -std=gnu99 -Os -I. -fno-builtin-printf -fno-builtin-memset -fno-builtin-memcpy -Wall -Wno-parentheses -Wno-pointer-to-int-cast
all: stuff white_loader kcode.dylib mem.dylib serialplease.dylib
%.o: %.c kinc.h
echo "CFLAGS: $(CFLAGS)"
$(GCC) $(CFLAGS) -c -o $@ $< -DIMG3_SUPPORT -Wreturn-type
%.o: %.S
$(GCC) $(CFLAGS) -c -o $@ $< -DIMG3_SUPPORT
Expand Down
154 changes: 100 additions & 54 deletions black.c
Original file line number Diff line number Diff line change
@@ -1,88 +1,134 @@
#include "kinc.h"
#define cast(a, b) ((a) (b))

void *hook(void *addr, void *replacement, bool force, void *tag) {
if(0 == (cast(uint32_t, addr) & 1)) {
IOLog("Hooking ARM functions is not supported\n");
return NULL;
}
uint32_t *storeto = cast(void *, cast(char *, addr) - 1);
uint32_t value = *storeto;
void *hook(void *addr, void *replacement, int mode, void *tag) {
bool thumb = cast(uint32_t, addr) & 1;
uint32_t *storeto = cast(void *, cast(uint32_t, addr) & ~1);
uint32_t value = storeto[0];
uint32_t value2 = 0;
uint32_t *p;
uint32_t alloc;
uint32_t insn;

// Verify that it's safe to hook.
// We expect PUSH {regs, LR}; ADD Rn, SP, #x
if(!( ((value & 0xff00) == 0xb500) && ((value & 0xf8000000) == 0xa8000000) )) {
IOLog("I couldn't hook %p because its prolog is weird (%08x)\n", addr, value);
if(force) {
IOLog("...but I'll do it anyway\n");
} else {
return NULL;
// We expect PUSH {regs, LR}; ADD R7, SP, #x
if(thumb) {
if((value & 0xff00ff00) != 0xaf00b500) {
IOLog("I couldn't hook %p because its prolog is weird (%08x)\n", addr, value);
if(mode) {
IOLog("...but I'll do it anyway\n");
} else {
return NULL;
}
}
}

// PSA: MOV PC, #x just does nothing.
int i = 0;
uint32_t number, alloc;
do {
// PSA: MOV PC, #x just does nothing.
int i = 1;
uint32_t number;
uint32_t *pcrel = cast(void *, cast(uint32_t, addr) & ~3);
do {
number = storeto[++i];
if(i == 1025) {
IOLog("hook: no suitable address found\n");
do {
number = pcrel[++i];
if(i == 1024) {
IOLog("hook: no suitable address found\n");
return NULL;
}
} while((number & 3) == 2);
alloc = number & 0xfffff000;
} while(vm_allocate(kernel_map, (vm_offset_t *) &alloc, 0x2000, 0));


insn = 0xf000f8df | ((i - 1) << 18);
IOLog("hook: I got insn=%08x storeto=%p number=%08x\n", insn, storeto, number);

if(number & 1) {
*cast(uint16_t *, number & ~1) = 0x4778; // bx pc
}
p = cast(void *, (number + 3) & ~3);
} else {
value2 = storeto[1];

if((value & 0xffd04000) != 0xe9004000 || (value2 & 0xffeff000) != 0xe28d7000) {
IOLog("I couldn't hook %p because its prolog is weird (%08x, %08x)\n", addr, value, value2);
if(mode) {
IOLog("...but I'll do it anyway\n");
} else {
return NULL;
}
} while((number & 3) == 2);
alloc = number & 0xfffff000;
} while(vm_allocate(kernel_map, (vm_offset_t *) &alloc, 0x2000, 0));

}

uint32_t insn = 0xf000f8df | ((i - 1) << 18);
IOLog("hook: I got insn=%08x storeto=%p number=%08x\n", insn, storeto, number);
if(vm_allocate(kernel_map, (vm_offset_t *) &alloc, 0x1000, 1)) {
IOLog("couldn't allocate\n");
return NULL;
}
p = cast(void *, alloc);
insn = 0xe51ff004;
}

if(number & 1) {
*cast(uint16_t *, number & ~1) = 0x4778; // bx pc
if(mode == 2) {
// push {r0-r12, lr}; mov r0, sp; ldr r1, addr; mov lr, pc; ldr pc, a; pop {r0-r12, lr}; adr pc, b+1; addr: .long 0; a: .long 0; b: .long 0
*p++ = 0xe92d5fff;
*p++ = 0xe1a0000d;
*p++ = 0xe59f100c;
*p++ = 0xe1a0e00f;
*p++ = 0xe59ff008;
*p++ = 0xe8bd5fff;
*p++ = thumb ? 0xe28ff005 : 0xe28ff004;
*p++ = cast(uint32_t, addr); // dumb
} else {
// push {r0-r3, r7, lr}; add r1, sp, #24; add r7, sp, #16; push {r1}; adr r0, b+1; mov r1, sp; ldr r12, a; blx r12; add sp, #20; pop {r7, pc}; a: .long 0; b: .long 0'
*p++ = 0xe92d408f;
*p++ = 0xe28d1018;
*p++ = 0xe28d7010;
*p++ = 0xe92d0002;
*p++ = thumb ? 0xe28f0015 : 0xe28f0014;
*p++ = 0xe1a0100d;
*p++ = 0xe59fc008;
*p++ = 0xe12fff3c;
*p++ = 0xe28dd014;
*p++ = 0xe8bd8080;
}
uint32_t *p = cast(void *, (number + 3) & ~3);
// push {r0-r3, r7, lr}; add r1, sp, #24; add r7, sp, #16; push {r1}; adr r0, b+1; mov r1, sp; ldr r12, a; blx r12; add sp, #20; pop {r7, pc}; a: .long 0; b: .long 0'
*p++ = 0xe92d408f;
*p++ = 0xe28d1018;
*p++ = 0xe28d7010;
*p++ = 0xe92d0002;
*p++ = 0xe28f0015;
*p++ = 0xe1a0100d;
*p++ = 0xe59fc008;
*p++ = 0xe12fff3c;
*p++ = 0xe28dd014;
*p++ = 0xe8bd8080;

*p++ = cast(uint32_t, replacement);

// The return stub
*p++ = value;
*p++ = 0xf000f8df; // ldr pc, [pc]
*p++ = cast(uint32_t, addr) + 4;
if(!thumb) {
*p++ = value2;
}
*p++ = thumb ? 0xf000f8df : 0xe51ff004; // ldr pc, [pc]
*p++ = cast(uint32_t, addr) + (thumb ? 4 : 8);

// bookkeeping
uint32_t *ret = p;
*p++ = cast(uint32_t, tag);
*p++ = alloc;
*p++ = cast(uint32_t, storeto);
*p++ = cast(uint32_t, addr);
*p++ = value;
*p++ = value2;

vm_protect(kernel_map, cast(vm_address_t, alloc), 0x2000, 1, 5);
vm_protect(kernel_map, cast(vm_address_t, alloc), 0x2000, 0, 5);
vm_protect(kernel_map, cast(vm_address_t, alloc), thumb ? 0x2000 : 0x1000, 1, 5);
vm_protect(kernel_map, cast(vm_address_t, alloc), thumb ? 0x2000 : 0x1000, 0, 5);

*storeto = insn;
flush_cache(storeto, 4);
storeto[0] = insn;
if(!thumb) {
// unsafe!
storeto[1] = alloc;
}
flush_cache(storeto, 8);
return ret;
}

void *unhook(uint32_t *stuff) {
void *tag = cast(void *, stuff[0]);
uint32_t *storeto = cast(void *, stuff[2]);
*storeto = stuff[3];
flush_cache(storeto, 4);
bool thumb = stuff[2] & 1;
uint32_t *storeto = cast(void *, stuff[2] & ~1);
storeto[0] = stuff[3];
if(!thumb) {
storeto[1] = stuff[4];
}
flush_cache(storeto, 8);

if(vm_deallocate(kernel_map, cast(vm_address_t, stuff[1]), 0x2000)) {
if(vm_deallocate(kernel_map, cast(vm_address_t, stuff[1]), thumb ? 0x2000 : 0x1000)) {
IOLog("vm_deallocate failed!\n");
}
IOLog("unhooked %p\n", storeto);
Expand Down
77 changes: 46 additions & 31 deletions kcode.c
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
#include "kinc.h"
// black.c
void *hook(void *addr, void *replacement, bool force, void *tag);
void *unhook(void *stub);
// creep.c
int creep_go(void *start, int size);
void creep_get_records(user_addr_t buf, uint32_t bufsize);
void creep_stop();
// protoss.c
int protoss_go();
int protoss_go_watch(uint32_t address, uint32_t mask);
int protoss_get_records(int type, user_addr_t buf, uint32_t bufsize);
void protoss_stop();
void protoss_unload();
uint32_t protoss_dump_debug_reg(uint32_t reg);
int protoss_write_debug_reg(uint32_t reg, uint32_t val);
// failsafe.S
int run_failsafe(void *result, void *func, uint32_t arg1, uint32_t arg2);
#include "kcode.h"

static void *hook_tag;

Expand All @@ -29,6 +13,10 @@ struct apply_args {
void *r7; // not actually part of the __builtin_apply_args() struct
};

struct apply_result {
void *r0, *r1, *r2, *r3;
};

struct frame {
struct frame *r7;
void *lr;
Expand All @@ -37,19 +25,19 @@ struct frame {
static void get_return_addresses(struct frame *frame, void **returns, int n) {
while(n--) {
if(!frame || frame == (void *) 0xffffffff) {
*returns++ = 0xeeeeeeee;
*returns++ = (void *) 0xeeeeeeee;
} else {
*returns++ = frame->lr;
frame = frame->r7;
}
}
}

static void *hook_generic(bool should_trace, void *old, struct apply_args *args) {
static void *generic_hook(bool should_trace, void *old, struct apply_args *args) {
if(should_trace) {
protoss_go();
}
void *result = __builtin_apply(old, args, 60);
struct apply_result *result = __builtin_apply(old, args, 60);
if(should_trace) {
protoss_stop();
}
Expand All @@ -59,24 +47,41 @@ static void *hook_generic(bool should_trace, void *old, struct apply_args *args)
should_trace ? " (traced)" : "",
returns[0], returns[1], returns[2], returns[3], returns[4], returns[5],
args->r0, args->r1, args->r2, args->r3, args->sp[0], args->sp[1], args->sp[2],
result,
result->r0,
proc_pid(current_proc()));
return result;
}

static void noreturn_hook(uint32_t regs[14], uint32_t pc) {
#if 0
// meant for hooking syscall
static uint32_t skipped, count[0x1000];
if(++count[regs[12] & 0xfff] > 10) {
skipped++; // we get it already!
return;
} else if(skipped) {
IOLog("(skipped %u entries)\n", skipped);
memset(count, 0, sizeof(count));
skipped = 0;
}
#endif
IOLog("[%d] @%x hook: r0=0x%x r1=0x%x r2=0x%x r3=0x%x r4=0x%x r5=0x%x r6=0x%x r7=0x%x r8=0x%x r9=0x%x r10=0x%x r11=0x%x r12=0x%x sp=%p lr=0x%x\n", proc_pid(current_proc()), pc, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], regs[8], regs[9], regs[10], regs[11], regs[12], regs + 14, regs[13]);
}

static void *logger_hook(void *old, struct apply_args *args) {
__builtin_return(hook_generic(false, old, args));
__builtin_return(generic_hook(false, old, args));
}

static void *tracer_hook(void *old, struct apply_args *args) {
lck_mtx_lock(tracer_lck);
bool should_trace = !tracer_ticks--;
void *result = hook_generic(should_trace, old, args);
void *result = generic_hook(should_trace, old, args);
lck_mtx_unlock(tracer_lck);
__builtin_return(result);
}

static void *weird_hook(void *old, struct apply_args *args) {
//IOLog("weird_hook: %d: %p, %p, %p, %p\n", args->sp[12], args->sp[0], args->sp[1], args->sp[2], args->sp[3]);
__builtin_return(__builtin_apply(old, args, 60));
}

Expand Down Expand Up @@ -165,6 +170,17 @@ static int poke_mem(void *kaddr, uint32_t uaddr, uint32_t size, bool write, bool
return retval;
}

static int add_hook(void *addr, void *replacement, int mode) {
void *tag = hook(addr, replacement, mode, hook_tag);
if(tag) {
IOLog("tag: %p\n", tag);
hook_tag = tag;
return 0;
} else {
return -1;
}
}


int do_something() {
uint32_t time, microtime;
Expand Down Expand Up @@ -233,10 +249,7 @@ struct regs {

int mysyscall(void *p, struct mysyscall_args *uap, int32_t *retval)
{
//IOLog("Hi mode=%d\n", uap->mode);
//IOLog("kernel_pmap = %p nx_enabled = %d\n", kernel_pmap, kernel_pmap[0x420/4]);
// Turn off nx_enabled so we can make pages executable in kernel land.
kernel_pmap[0x420/4] = 0;
IOLog("%p called me\n", __builtin_return_address(1));
switch(uap->mode) {
case 0: { // get regs
struct regs regs;
Expand Down Expand Up @@ -271,11 +284,13 @@ int mysyscall(void *p, struct mysyscall_args *uap, int32_t *retval)
fini_();
break;
case 7: // hook a function, log args
*retval = (hook_tag = hook((void *) uap->b, logger_hook, uap->c, hook_tag)) ? 0 : -1;
IOLog("hook_tag = %p\n", hook_tag);
*retval = add_hook((void *) uap->b, logger_hook, uap->c);
break;
case 8: // noreturn
*retval = add_hook((void *) uap->b, noreturn_hook, 2);
break;
case 9: // hook weird
*retval = (hook_tag = hook((void *) uap->b, weird_hook, uap->c, hook_tag)) ? 0 : -1;
*retval = add_hook((void *) uap->b, weird_hook, uap->c);
break;
case 10:
*retval = creep_go((void *) uap->b, (int) uap->c);
Expand All @@ -301,7 +316,7 @@ int mysyscall(void *p, struct mysyscall_args *uap, int32_t *retval)
break;
case 20: // tracer
tracer_ticks = uap->d;
*retval = (hook_tag = hook((void *) uap->b, tracer_hook, uap->c, hook_tag)) ? 0 : -1;
*retval = add_hook((void *) uap->b, tracer_hook, uap->c);
break;
case 21:
*retval = lookup_metaclass(uap->b);
Expand Down
17 changes: 17 additions & 0 deletions kcode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// black.c
void *hook(void *addr, void *replacement, int mode, void *tag);
void *unhook(void *stub);
// creep.c
int creep_go(void *start, int size);
void creep_get_records(user_addr_t buf, uint32_t bufsize);
void creep_stop();
// protoss.c
int protoss_go();
int protoss_go_watch(uint32_t address, uint32_t mask);
int protoss_get_records(int type, user_addr_t buf, uint32_t bufsize);
void protoss_stop();
void protoss_unload();
uint32_t protoss_dump_debug_reg(uint32_t reg);
int protoss_write_debug_reg(uint32_t reg, uint32_t val);
// failsafe.S
int run_failsafe(void *result, void *func, uint32_t arg1, uint32_t arg2);
Loading

0 comments on commit 62499f9

Please sign in to comment.