From 7001c2a2a18bee2537946f4d490be1c7eef6a138 Mon Sep 17 00:00:00 2001 From: spv Date: Sun, 19 Mar 2023 17:56:17 -0400 Subject: glhf --- interpose/Makefile | 29 +++ interpose/ent.xml | 17 ++ interpose/src/envbypass.c | 431 +++++++++++++++++++++++++++++++++ interpose/src/envbypass.h | 13 + interpose/src/game_over.c | 591 +++++++++++++++++++++++++++++++++++++++++++++ interpose/src/game_over.m | 600 ++++++++++++++++++++++++++++++++++++++++++++++ interpose/src/main.mm | 1 + 7 files changed, 1682 insertions(+) create mode 100755 interpose/Makefile create mode 100755 interpose/ent.xml create mode 100755 interpose/src/envbypass.c create mode 100755 interpose/src/envbypass.h create mode 100755 interpose/src/game_over.c create mode 100755 interpose/src/game_over.m create mode 100755 interpose/src/main.mm (limited to 'interpose') diff --git a/interpose/Makefile b/interpose/Makefile new file mode 100755 index 0000000..f8f2803 --- /dev/null +++ b/interpose/Makefile @@ -0,0 +1,29 @@ +CC=clang +CC_ARM=xcrun -sdk iphoneos clang -arch armv7 +CFLAGS_DYLIB=-dynamiclib +CFLAGS= +CFLAGS_OBJC=-fobjc-arc -fmodules -framework Foundation + +all: clean dylib bin/envbypass + +dylib: + ${CC} ${CFLAGS_DYLIB} ${CFLAGS_OBJC} -o bin/game_over.dylib src/game_over.m + ${CC_ARM} ${CFLAGS_DYLIB} ${CFLAGS_OBJC} -o bin/game_over_armv7.dylib src/game_over.m + +old: clean + ${CC} ${CFLAGS} ${CFLAGS_DYLIB} -o bin/game_over_old.dylib src/game_over.c + ${CC_ARM} ${CFLAGS} ${CFLAGS_DYLIB} -o bin/game_over_old_armv7.dylib src/game_over.c + +bin/envbypass: + ${CC_ARM} ${CFLAGS} -o bin/envbypass src/envbypass.c + ldid -Sent.xml bin/envbypass + #${CC} ${CFLAGS} -o test test.c + +clean: + sh -c "rm -rf bin; echo" + mkdir bin + +install: +# cat bin/game_over_objc_armv7.dylib | ssh root@localhost -p 2222 "cat > /untether/game_over_objc_armv7.dylib2; mv /untether/game_over_objc_armv7.dylib2 /untether/game_over_objc_armv7.dylib1" + cat bin/game_over_armv7.dylib | ssh root@localhost -p 2222 "cat > /untether/game_over_armv7.dylib2; mv /untether/game_over_armv7.dylib2 /untether/game_over_armv7.dylib1" + cat bin/envbypass | ssh root@localhost -p 2222 "cat > envbypass" \ No newline at end of file diff --git a/interpose/ent.xml b/interpose/ent.xml new file mode 100755 index 0000000..35e74c1 --- /dev/null +++ b/interpose/ent.xml @@ -0,0 +1,17 @@ + + + + com.apple.springboard.debugapplications + + get-task-allow + + proc_info-allow + + task_for_pid-allow + + run-unsigned-code + + + + + diff --git a/interpose/src/envbypass.c b/interpose/src/envbypass.c new file mode 100755 index 0000000..db0355e --- /dev/null +++ b/interpose/src/envbypass.c @@ -0,0 +1,431 @@ +#include +#include +#include +#include +#include +#include +#include "envbypass.h" + +task_t tfp1; + +uint32_t lread_uint32(uint32_t addr) { + vm_size_t bytesRead=0; + uint32_t ret = 0; + vm_read_overwrite(tfp1, addr, 4, (vm_address_t)&ret, &bytesRead); + return ret; +} + +int lwrite_uint32(uint32_t addr, uint32_t value) { + return vm_write(tfp1, addr, (vm_offset_t)&value, 4); +} + +bool page_allocated(uint32_t addr) { + vm_size_t bytesRead=0; + uint32_t ret = 0; + return vm_read_overwrite(tfp1, addr, 4, (vm_address_t)&ret, &bytesRead) == 0; +} + +extern char **environ; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* kernel HACKED */ +task_t tfp0; + +/* KASLR shit */ +#define LC_SIZE 0x0000000f +#define UNSLID_BASE 0x80001000 + +/* fuck you apple let me use syscall(...) */ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#ifndef USLEEP_TIME_IN_US +#define USLEEP_TIME_IN_US 250 +#endif + +/* slip-n-slide into bullshit :tm: */ +uint32_t slide; + +uint32_t kread_uint32(uint32_t addr) { + vm_size_t bytesRead=0; + uint32_t ret = 0; + vm_read_overwrite(tfp0, addr, 4, (vm_address_t)&ret, &bytesRead); + return ret; +} + +void kwrite_uint32(uint32_t addr, uint32_t value) { + vm_write(tfp0, addr, (vm_offset_t)&value, 4); +} + +void kwrite_uint16(uint32_t addr, uint16_t value) { + vm_write(tfp0, addr, (vm_offset_t)&value, 2); +} + +uint32_t get_kernel_slide(){ + uint32_t slide; + uint32_t base = 0x80001000; + uint32_t slid_base; + + /* + * slide = 0x1000000 + (0x200000 * random byte) + * start at 256 so we don't get the kernel mad at us for reading unmapped memory + * or something idk + */ + + for (int slide_byte = 256; slide_byte >= 1; slide_byte--) { + slide = 0x01000000 + 0x00200000 * slide_byte; + slid_base = base + slide; + + if (kread_uint32(slid_base) == 0xfeedface) { + /* + * this looks like a kernel base + */ + + if (kread_uint32(slid_base + 0x10) == LC_SIZE) { + /* + * we found it bae + */ + + return slide; + } + } + } + return -1; +} + +uint8_t* dump_kernel(uint8_t* kdata, uint32_t len) { + vm_size_t segment = 4; + + /* + * this code is stolen from jailbreak.m in p0laris, + * which was stolen from internal Athenus Dev Team tools :P + */ + + printf("[*] finding acceptable segment size...\n"); + + for (int i = 0; i < 16384; i++) { + /* + * basically, continuously increment `segment` we're reading by by 4. + * re-read from the kernel base until vm_read_overwrite fails. + * + * now, technically, there's probably a better way to get this value, + * and also likely and a better way to check that won't run into issues + * if vm_read_overwrite fails for other reasons, but i CBA. :P + */ + + int ret = vm_read_overwrite(tfp0, + UNSLID_BASE + slide, + segment, + (vm_address_t)kdata + (i * segment), + &segment); + + if (ret == 0) { + /* + * no fail, increase by 4. + */ + + segment += 4; + } else { + /* + * it failed at a length of `segment`, and we increase by 4 in the loop. + * so, subtracting 4 will give us the last value we used that succeeded. + */ + + printf("[*] mach_vm_read_overwrite returned %d at segment %d\n", + ret, + segment); + segment -= 4; + break; + } + } + + /* + * we found the max segment size! + */ + + printf("[*] acceptable segment size: %d\n", segment); + + for (int i = 0; i < len / segment; i++) { + /* + * DUMP DUMP DUMP + */ + + vm_read_overwrite(tfp0, + UNSLID_BASE + slide + (i * segment), + segment, + (vm_address_t)kdata + (i * segment), + &segment); + } + + return kdata; +} + +uint32_t find_syscall0(uint32_t region, uint8_t* kdata, size_t ksize) { + uint32_t addy = -1; + char* hfs_private_directory_data = memmem(kdata, + ksize, + ".HFS+ Private Directory Data\r", + strlen(".HFS+ Private Directory Data\r")); + printf("[*] hfs_private_directory_data = %p\n", + hfs_private_directory_data); + uint32_t hfs_private_directory_data_addy = (uintptr_t)hfs_private_directory_data + - (uintptr_t)kdata + + region; + char* hfs_private_directory_data_addy_ptr = memmem(kdata, + ksize, + (char*)&hfs_private_directory_data_addy, + sizeof(hfs_private_directory_data_addy)); + printf("[*] hfs_private_directory_data_addy_ptr = %p\n", + hfs_private_directory_data_addy_ptr); + uint32_t hfs_private_directory_data_ptr_addy = (uintptr_t)hfs_private_directory_data_addy_ptr + - (uintptr_t)kdata; + addy = hfs_private_directory_data_ptr_addy + 0x4; + + return addy; +} + +uint32_t syscall0_addr = -1; +#define DEBUG_SYSCALLS 0 + +uint32_t function_addr(int syscall_id, uint32_t slide) { + uint32_t function_entry_addr = syscall0_addr + (syscall_id * 0xc); + uint32_t function_addr = kread_uint32(function_entry_addr); + printf("[*] function_entry_addr = 0x08%x, function_addr = 0x%08x\n", function_entry_addr, function_addr); + return function_addr; +} + +void replace_syscall_with_addr(int syscall_id, uint32_t addr, uint32_t slide, uint16_t num_args, uint32_t arg_bytes) { + uint32_t function_entry_addr = syscall0_addr + (syscall_id * 0xc); +#if DEBUG_SYSCALLS + printf("[*] function_entry_addr = 0x%08x, function_addr = 0x%08x\n", function_entry_addr, kread_uint32(function_entry_addr)); +#endif + kwrite_uint32(function_entry_addr, addr | 1); + kwrite_uint16(function_entry_addr + 0x8, num_args); + kwrite_uint32(function_entry_addr + 0xa, arg_bytes); +#if DEBUG_SYSCALLS + printf("[*] function_entry_addr = 0x%08x, function_addr = 0x%08x\n", function_entry_addr, kread_uint32(function_entry_addr)); +#endif +} + +void replace_syscall(int syscall_id, uint8_t* code, uint32_t length, uint32_t slide, uint16_t num_args, uint32_t arg_bytes) { + uint32_t where = slide + 0x80001b00; + vm_write(tfp0, where, (vm_offset_t)code, length); + replace_syscall_with_addr(syscall_id, where, slide, num_args, arg_bytes); +} + +#define ownage_syscall 379 + +void csbypass(int offset_) { + uint32_t* comm_page_time; + kern_return_t ret; + uint8_t* kdata; + + uint8_t payload420[] = { + 0x08, 0x68, // ldr r0, [r1] + 0x44, 0xf2, 0x44, 0x44, // movw r4, #0x4048 + 0xcf, 0xf6, 0xff, 0x74, // movt r4, #0xffff + 0x20, 0x60, // str r0, [r4] + 0x4f, 0xf0, 0x00, 0x00, // mov r0, #0x0 + 0x70, 0x47 // bx lr + }; + + int syscall_ret = 0; + uint32_t sret = 0; + + printf("[*] offset=%d\n", offset_); + + ret = task_for_pid(mach_task_self(), 0, &tfp0); + printf("[*] ret=%d, tfp0=%x\n", ret, tfp0); + + slide = get_kernel_slide(); + printf("[*] slide=0x%08x\n", slide); + + kdata = (uint8_t*)malloc(32 * 1024 * 1024); + printf("[*] kdata=%p\n", kdata); + + dump_kernel(kdata, 32 * 1024 * 1024); + syscall0_addr = find_syscall0(slide + 0x80001000, + kdata, + 32 * 1024 * 1024) + + 0x80001000 + + slide; + + free(kdata); + kdata = NULL; + + printf("[*] 0x%08x\n", syscall0_addr); + + printf("[*] 0x%08x\n", function_addr(ownage_syscall, slide)); + + replace_syscall(ownage_syscall, payload420, sizeof(payload420), slide, 1, 4); + + printf("[*] 0x%08x\n", function_addr(ownage_syscall, slide)); + + syscall_ret = syscall(ownage_syscall, offset_); + sret = errno; + + printf("[*] syscall(%d); = %d. errno(dec) = %d, errno(hex) = 0x%x. \n", ownage_syscall, syscall_ret, sret, sret); +} + +char swaggang[] = "swaggang"; + +bool _0wn(char* global_inject_dylib) { + task_for_pid(mach_task_self(), 1, &tfp1); + printf("[*] launchd DYLD env bypass by @__spv\n"); + printf("[*] tfp1=0x%x\n", tfp1); + vm_size_t size; + uint32_t addy; + uint8_t* page = malloc(0x1000); + uint32_t address_of_string = 0; + + char* replace_me = "SMOKETREESCSBYSPV1337"; + + for (int i = 0; i < 10; i++) { + printf("[*] setting %s=%s\n", replace_me, global_inject_dylib); + pid_t pid; + char *argv[] = {"/bin/launchctl", "setenv", replace_me, global_inject_dylib, NULL}; + + int status; + status = posix_spawn(&pid, "/bin/launchctl", NULL, NULL, argv, environ); + if (status == 0) { + do { + if (waitpid(pid, &status, 0) != -1) { + // + } else { + perror("waitpid"); + goto out; + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + } + else { + printf("posix_spawn: %s\n", strerror(status)); + } + } + + char* hax = "DYLD_INSERT_LIBRARIES"; + + printf("[*] searching teh pages\n"); + + bool found_one = false; + uint32_t num_found = 0; + + char* read_data; + + for (uint32_t pagen = 0x0; pagen < (0xffffffff >> 12); pagen++) { + + if (pagen % ((0xffffffff >> 12) / 100) == 0) { + //printf("%d\n", pagen / ((0xffffffff >> 12) / 100)); + } + + uint32_t page_start = pagen << 12; + if (vm_read_overwrite(tfp1, page_start, 0x1000, (vm_address_t)page, &size)) + continue; // page isn't allocated + + ; + + uint8_t* find = (uint8_t*)memmem(page, 0x1000, replace_me, 21); + + if (!find) + continue; // not in this page + + /* if we reach here, we have found a page that is allocated in launchd, containing our string. */ + uint32_t offset = (uint32_t)(find - page); + address_of_string = page_start + offset; + + printf("[*] found an addy 0x%08x\n", address_of_string); + printf("[*] lread_uint32(addy) = 0x%08x\n", lread_uint32(address_of_string)); + printf("[*] vm_write(0x%08x) = 0x%x\n", addy, vm_write(tfp1, (vm_address_t)address_of_string, (vm_offset_t)hax, 21)); + printf("[*] lread_uint32(addy) = 0x%08x\n", lread_uint32(address_of_string)); + + num_found++; + found_one = true; + + pid_t pid; + char *argv[] = {"/bin/sh", "-c", "launchctl getenv DYLD_INSERT_LIBRARIES 2>&1 > /tmp/env", NULL}; + + int status; + status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ); + if (status == 0) { + do { + if (waitpid(pid, &status, 0) != -1) { + // + } else { + perror("waitpid"); + goto out; + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + } + else { + printf("posix_spawn: %s\n", strerror(status)); + } + + FILE* fp = fopen("/tmp/env", "r"); + + if (!fp) continue; + + fseek(fp, 0, SEEK_END); + size_t len = ftell(fp); + fseek(fp, 0, SEEK_SET); + + read_data = (char*)malloc(len); + fread(read_data, len, 1, fp); + fclose(fp); + + if (strstr(read_data, "dylib")) { + // prolly good, right? + break; + } + + } + + unlink("/tmp/env"); + + free(page); + if (read_data) + free(read_data); + +out: + if (found_one) { + printf("[*] done\n"); + return true; + } + else { + printf("[*] didn't find any. whatever, let's try again\n"); + return _0wn(); + } +} + +int main(int argc, char* argv[]) { + _0wn(); + + uint32_t offset = 0; + time_t val; + FILE* fp; + syslog(LOG_SYSLOG, "game over"); + + if (argc >= 2) { + offset = atoi(argv[1]); + goto do_it; + } + + fp = fopen("/untether/offset", "rb"); + if (fp) { + fread(&val, sizeof(val), 1, fp); + fclose(fp); + offset = val; + } + +do_it: + csbypass(offset); + + return 0; +} diff --git a/interpose/src/envbypass.h b/interpose/src/envbypass.h new file mode 100755 index 0000000..a970cbe --- /dev/null +++ b/interpose/src/envbypass.h @@ -0,0 +1,13 @@ +#ifndef ENVBYPASS_H +#define ENVBYPASS_H + +#ifndef __cplusplus +#define bool unsigned char +#define true 1 +#define false 0 +#endif + +bool _0wn(); + +#endif + diff --git a/interpose/src/game_over.c b/interpose/src/game_over.c new file mode 100755 index 0000000..bc43740 --- /dev/null +++ b/interpose/src/game_over.c @@ -0,0 +1,591 @@ +/* + game_over, part 2 - the game-over-en-ing + + offsets time & provides global env injection + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SYSLOG 1 +#define SYSLOG_OTHER 0 +#define SYSLOG_TIME_LOG 0 + +#define CLOCK_GETTIME_DO 0 + +#ifdef SYSLOG +#if SYSLOG +#define _syslog(log_level, str, args...) do { syslog(log_level, str, ##args); printf(str "\n", ##args); } while(0) +#else +#define _syslog(log_level, str, args...) do {} while(0) +#endif +#endif + +#ifdef SYSLOG_OTHER +#if SYSLOG_OTHER +#define _syslog_other(log_level, str, args...) do { syslog(log_level, str, ##args); printf(str "\n", ##args); } while(0) +#else +#define _syslog_other(log_level, str, args...) do {} while(0) +#endif +#endif + +#ifdef SYSLOG_TIME_LOG +#if SYSLOG_TIME_LOG +#define _syslog_time_log(log_level, str, args...) do { syslog(log_level, str, ##args); printf(str "\n", ##args); } while(0) +#else +#define _syslog_time_log(log_level, str, args...) do {} while(0) +#endif +#endif + +#define __32_BIT__ (UINTPTR_MAX == 0xffffffff) + +#if __32_BIT___ +#define POINTER_SIZE 4 +#else +#define POINTER_SIZE 8 +#endif + +#if __arm__ || __arm64__ +#define UNTETHER_STRING "/untether/game_over_armv7.dylib1" +#else +#define UNTETHER_STRING "./bin/game_over.dylib" +#endif + +//typedef enum { false, true } bool; + +bool interpose_hax(); + +extern char** environ; + +bool do_it = true; +bool syslog_it = true; + +void ensure_env() { + if (syslog_it) + _syslog_other(LOG_SYSLOG, "setting envs, just in case"); // THIS CAUSES A SEGFAULT IN gettimeofday! IT RECURSIVELY FUCKS UP EVERYTHING!!! + char* DYLD_INSERT_LIBRARIES = getenv("DYLD_INSERT_LIBRARIES"); + if (!DYLD_INSERT_LIBRARIES) + setenv("DYLD_INSERT_LIBRARIES", UNTETHER_STRING, 0); + else { + char* set_me; + if (strstr(DYLD_INSERT_LIBRARIES, UNTETHER_STRING) == NULL) + asprintf(&set_me, "%s:" UNTETHER_STRING, DYLD_INSERT_LIBRARIES); + else + asprintf(&set_me, "%s", DYLD_INSERT_LIBRARIES); + + if (set_me) + setenv("DYLD_INSERT_LIBRARIES", set_me, 1); + + free(set_me); + } +} + +uint32_t get_offset() { + char* __OFFSET = getenv("__OFFSET"); + int offset = 0; + if (__OFFSET) { + offset = atoi(__OFFSET); +// free(__OFFSET); + } + if (!offset) { + offset = 42069; + } + return offset; +} + +void __before_hook() { + ensure_env(); + printf("[*] before_hook\n"); +} + +void __before_exec(int line, const char* s) { + /* + before_exec hook + */ +} + +#if CLOCK_GETTIME_DO +int _clock_gettime(clockid_t clk_id, struct timespec *tp) { + __before_hook(); // fix up stuff + + clockid_t clk_id_ = clk_id; // recreate variables + struct timespec tp_; + int ret; // return val + + long old_tv_sec; // for logging + + ret = clock_gettime(clk_id_, &tp_); // call original + + old_tv_sec = tp_.tv_sec; // set old + + if (do_it) { + tp_.tv_sec += get_offset(); // get offset, and add it + } + + _syslog_time_log(LOG_SYSLOG, "[c] %ld, %ld", old_tv_sec, tp_.tv_sec); + + memcpy(tp, &tp_, sizeof(struct timespec)); + return ret; +} +#endif + +time_t _time(time_t* t) { + __before_hook(); // fix up stuff + + time_t t_; // recreate variables + time_t ret; // return val + ret = time(&t_); // get time + + time_t old_t_ = t_; // for logging + + if (do_it) { + t_ +=get_offset(); // get offset, and add it + } + + _syslog_time_log(LOG_SYSLOG, "[t] %ld, %ld\n", old_t_, t_); + + if (t) + *t = t_; // gawd damn segfaults! + + return t_; +} + +uint64_t _mach_absolute_time(void) { + /* + mach_absolute_time hook is disabled for now, creates weird (read: fun) + UI bugs + */ + + __before_hook(); // fix up stuff + uint64_t at = mach_absolute_time(); // get return + +#if 0 + long old_tv_sec; + + uint64_t add = get_offset(); + add *= 1000000000; // seconds -> nanoseconds + + uint64_t ret = at; + + uint64_t old_ret = ret; + + if (do_it) { + ret += add; + }; + + _syslog_time_log(LOG_SYSLOG, "[m] %llu, %llu", old_ret, ret); + + return ret; +#else + return at; +#endif +} + +int _gettimeofday(struct timeval *restrict tv, + struct timezone *restrict tz) { + + syslog_it = false; // syslog uses gettimeofday, using + // syslog in this function causes + // a recursive loop + + __before_hook(); + syslog_it = true; + struct timeval tv_; + struct timezone tz_; + gettimeofday(&tv_, &tz_); + + long old_tv_sec = tv_.tv_sec; + + tv_.tv_sec += get_offset(); + tv_.tv_usec += 0; + +// _syslog(LOG_SYSLOG, "[g] %ld, %ld", old_tv_sec, tv_.tv_sec); + + /* + SYSLOG CAN NOT BE CALLED IN THIS FUNCTION + IT ENTERS AN INFINITE LOOP + */ + + if(tv)memcpy(tv, &tv_, sizeof(struct timeval)); + if(tz)memcpy(tz, &tz_, sizeof(struct timezone)); + + return 0; +} + +int _setenv(const char *var_name, const char *new_value, int change_flag) { + __before_hook(); // fix up stuff + + int ret = setenv(var_name, new_value, change_flag); // call original function + + ensure_env(); // fix up again + return ret; +} + +int _putenv(char *var_name) { + __before_hook(); // fix up stuff + + int ret = putenv(var_name); // call original function + + ensure_env(); // fix up again + return ret; +} + +#if !__arm__ && !__arm64__ +int _system(const char *command) { + /* + this is dumb, system isn't even on iOS, and if it is, + it's gotten from dlsym, so this won't work! + */ + __before_hook(); + __before_exec(__LINE__, command); + return system(command); +} +#endif + +int _execv(const char *filename, char *const argv[]) { + __before_hook(); // fix up stuff + __before_exec(__LINE__, filename); // more hooks + return execv(filename, argv); // call original +} + +int _execl(const char *filename, const char *arg0, ...) { + __before_hook(); // fix up stuff + __before_exec(__LINE__, filename); // more hooks + + /* + let's do a code rundown. + + first, it takes the arg0 pointer, and uses it as an array/vector of + pointers (which it essentially is, just that it's the first (0th) item) + + it then counts how many pointers it takes to get to the NULL pointer, + the end of the list for execl and co + + then, it allocates a new array, and puts those pointers in the array. + + then it calls execv with that array. + */ + + char** _argv = NULL; + int count = 0; + int ret; + + while (*(arg0 + (count * POINTER_SIZE))) + count++; + + _argv = (char**)malloc(count * POINTER_SIZE); + + for (int i = 0; i < count; i++) { + _argv[i] = (char*)(arg0 + POINTER_SIZE); + } + + ret = execv(filename, _argv); + free(_argv); + + return ret; +} + +int _execve(const char *filename, char *const argv[], char *const env[]) { + __before_hook(); + __before_exec(__LINE__, filename); + return execve(filename, argv, environ); +} + +int _execle(const char *filename, const char *arg0, ...) { + __before_hook(); + __before_exec(__LINE__, filename); + + char** _argv = NULL; + int count = 0; + int ret; + + while (*(arg0 + (count * POINTER_SIZE))) + count++; + + _argv = (char**)malloc(count * POINTER_SIZE); + + for (int i = 0; i < count; i++) { + _argv[i] = (char*)(arg0 + POINTER_SIZE); + } + + ret = execve(filename, _argv, (char**)(arg0 + (((count + 2) * POINTER_SIZE)))); + free(_argv); + + return ret; +} + +int _execvp(const char *filename, char *const argv[]) { + __before_hook(); + __before_exec(__LINE__, filename); + return execvp(filename, argv); +} + +int _execlp(const char *filename, const char *arg0, ...) { + __before_hook(); + __before_exec(__LINE__, filename); + + char** _argv = NULL; + int count = 0; + int ret; + + while (*(arg0 + (count * POINTER_SIZE))) + count++; + + _argv = (char**)malloc(count * POINTER_SIZE); + + for (int i = 0; i < count; i++) { + _argv[i] = (char*)(arg0 + POINTER_SIZE); + } + + ret = execvp(filename, _argv); + + return ret; +} + +int _posix_spawn(pid_t *restrict pid, const char *restrict path, + const posix_spawn_file_actions_t *restrict file_actions, + const posix_spawnattr_t *restrict attrp, + char *const argv[restrict], + char *const envp[restrict]) { + __before_hook(); + __before_exec(__LINE__, path); + return posix_spawn(pid, path, file_actions, attrp, argv, environ); +} +int _posix_spawnp(pid_t *restrict pid, const char *restrict file, + const posix_spawn_file_actions_t *restrict file_actions, + const posix_spawnattr_t *restrict attrp, + char *const argv[restrict], + char *const envp[restrict]) { + __before_hook(); + __before_exec(__LINE__, file); + return posix_spawnp(pid, file, file_actions, attrp, argv, environ); +} + +/* substitute */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __LP64__ +#define nlist_native nlist_64 +#define LC_SEGMENT_NATIVE LC_SEGMENT_64 +#define segment_command_native segment_command_64 +#define mach_header_native mach_header_64 +#define section_native section_64 +#define PAGEZERO_SIZE 0x100000000; +#else +#define nlist_native nlist +#define LC_SEGMENT_NATIVE LC_SEGMENT +#define segment_command_native segment_command +#define mach_header_native mach_header +#define section_native section +#define PAGEZERO_SIZE 0x1000 +#endif + +__attribute__((noinline)) +static void *find_lazy(uint32_t ncmds, const struct load_command *cmds, uintptr_t slide, const char *desired) { + uint32_t symoff = 0, stroff = 0, isymoff = 0, lazy_index = 0, lazy_size = 0; + void **lazy = 0; + uint32_t cmdsleft; + const struct load_command *lc; + + uintptr_t thisimage = (uintptr_t) &find_lazy - slide; + + for(lc = cmds, cmdsleft = ncmds; cmdsleft--;) { + if(lc->cmd == LC_SYMTAB) { + const struct symtab_command *sc = (void *) lc; + stroff = sc->stroff; + symoff = sc->symoff; + } else if(lc->cmd == LC_DYSYMTAB) { + const struct dysymtab_command *dc = (void *) lc; + isymoff = dc->indirectsymoff; + } else if(lc->cmd == LC_SEGMENT_NATIVE) { + const struct segment_command_native *sc = (void *) lc; + const struct section_native *sect = (void *) (sc + 1); + uint32_t i; + if(sc->vmaddr <= thisimage && thisimage < (sc->vmaddr + sc->vmsize)) return 0; + for(i = 0; i < sc->nsects; i++) { + if((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { + lazy_index = sect->reserved1; + lazy_size = sect->size / sizeof(*lazy); + lazy = (void *) sect->addr + slide; + } + sect++; + } + } + lc = (void *) ((char *) lc + lc->cmdsize); + } + + if(!stroff || !symoff || !isymoff || !lazy_index) return 0; + +#define CATCH(off, addr) if(sc->fileoff <= (off) && (sc->fileoff + sc->filesize) >= (off)) (addr) = (void *) (sc->vmaddr + slide + (off) - sc->fileoff); + struct nlist_native *syms = 0; + const char *strs = 0; + uint32_t *isyms = 0; + + for(lc = cmds, cmdsleft = ncmds; cmdsleft--;) { + if(lc->cmd == LC_SEGMENT_NATIVE) { + struct segment_command_native *sc = (void *) lc; + CATCH(symoff, syms); + CATCH(stroff, strs); + CATCH(isymoff, isyms); + } + lc = (void *) ((char *) lc + lc->cmdsize); + } + + if(!syms || !strs || !isyms) return 0; + + uint32_t i; + for(i = lazy_index; i < lazy_index + lazy_size; i++) { + const struct nlist_native *sym = syms + isyms[i]; + if(!strcmp(strs + sym->n_un.n_strx, desired)) { + return lazy; + } + lazy++; + } + + return 0; +} + +bool interpose(const char *name, void *impl) { + const struct mach_header_native *mach_hdr; + bool result = false; + uint32_t i; + for(i = 0; (mach_hdr = (void *) _dyld_get_image_header(i)); i++) { + void **lazy = find_lazy(mach_hdr->ncmds, (void *) (mach_hdr + 1), _dyld_get_image_vmaddr_slide(i), name); + if(lazy) { +// printf("%s\n", _dyld_get_image_name(i)); + result = true; +// mprotect((void*)(((uintptr_t)lazy) & (~0x1000)), 0x1000, PROT_READ | PROT_WRITE); + *lazy = impl; + } + } + return result; +} + +bool interpose_hdr(const char *name, void *impl, const struct mach_header *mach_hdr, uintptr_t slide) { + bool result = false; + void **lazy = find_lazy(mach_hdr->ncmds, (void *) (mach_hdr + 1), slide, name); + if(lazy) { + result = true; +// printf("hdr %s %s\n", _dyld_get_image_name(i), name); +// mprotect((void*)(((uintptr_t)lazy) & (~0x1000)), 0x1000, PROT_READ | PROT_WRITE); + *lazy = impl; + } + return result; +} + +bool interpose_hax() { + _syslog(LOG_SYSLOG, "hax teh envs"); + interpose("_setenv", &_setenv); + interpose("_putenv", &_putenv); + + _syslog(LOG_SYSLOG, "haxing exec shit"); + interpose("_execl", &_execl); + interpose("_execlp", &_execlp); + interpose("_execle", &_execle); + interpose("_execv", &_execv); + interpose("_execve", &_execve); + interpose("_execvp", &_execvp); + interpose("_posix_spawn", &_posix_spawn); + interpose("_posix_spawnp", &_posix_spawnp); + + _syslog(LOG_SYSLOG, "haxing mach_absolute_time"); + interpose("_mach_absolute_time", &_mach_absolute_time); + + _syslog(LOG_SYSLOG, "haxing time shit"); +#if CLOCK_GETTIME_DO + interpose("_clock_gettime", &_clock_gettime); +#endif + interpose("_gettimeofday", &_gettimeofday); + interpose("_time", &_time); + + return true; +} + +bool interpose_hax_hdr(const struct mach_header* mh, uintptr_t slide) { +// printf("interpose_hax_hdr\n"); +// _syslog(LOG_SYSLOG, "hax teh envs"); + interpose_hdr("_setenv", &_setenv, mh, slide); + interpose_hdr("_putenv", &_putenv, mh, slide); + +// _syslog(LOG_SYSLOG, "haxing exec shit"); + interpose_hdr("_execl", &_execl, mh, slide); + interpose_hdr("_execlp", &_execlp, mh, slide); + interpose_hdr("_execle", &_execle, mh, slide); + interpose_hdr("_execv", &_execv, mh, slide); + interpose_hdr("_execve", &_execve, mh, slide); + interpose_hdr("_execvp", &_execvp, mh, slide); + interpose_hdr("_posix_spawn", &_posix_spawn, mh, slide); + interpose_hdr("_posix_spawnp", &_posix_spawnp, mh, slide); + +// _syslog(LOG_SYSLOG, "haxing mach_absolute_time"); + interpose_hdr("_mach_absolute_time", &_mach_absolute_time, mh, slide); + +// _syslog(LOG_SYSLOG, "haxing time shit"); +#if CLOCK_GETTIME_DO + interpose_hdr("_clock_gettime", &_clock_gettime, mh, slide); +#endif + interpose_hdr("_gettimeofday", &_gettimeofday, mh, slide); + interpose_hdr("_time", &_time, mh, slide); + + return true; +} + +void _dyld_wrapper(const struct mach_header* mh, intptr_t vmaddr_slide) { +// _syslog(LOG_SYSLOG, "_dyld_wrapper: %p 0x%08lx", mh, vmaddr_slide); + interpose_hax_hdr(mh, vmaddr_slide); +} + +void* _dlopen(const char *filename, int flags) { + _syslog(LOG_SYSLOG, "hooking dlopen"); + interpose_hax(); + return dlopen(filename, flags); +} + +/* my code */ +__attribute__((constructor)) static +void game_over(int argc, const char **argv) { + _syslog(LOG_SYSLOG, "0wn'd %d", getpid()); + _syslog(LOG_SYSLOG, "offset=%d", get_offset()); + _syslog(LOG_SYSLOG, "interposition..."); + + interpose_hax(); + interpose("__dlopen", &_dlopen); + interpose("_dlopen", &_dlopen); + interpose("dlopen", &_dlopen); +#if __arm__ || __arm64__ + _dyld_register_func_for_add_image(&_dyld_wrapper); +#endif + + ensure_env(); + + _syslog(LOG_SYSLOG, "enabling offsetting..."); + + do_it = true; +} + +__attribute__((destructor)) static +void game_is_actually_over(int argc, const char **argv) { + _syslog(LOG_SYSLOG, "todo"); +} diff --git a/interpose/src/game_over.m b/interpose/src/game_over.m new file mode 100755 index 0000000..735f1bf --- /dev/null +++ b/interpose/src/game_over.m @@ -0,0 +1,600 @@ +/* + game_over.m - game_over part 3, the game_over-en-ing-420 + + blaze it + */ + + +#import +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SYSLOG 0 +#define SYSLOG_OTHER 0 +#define SYSLOG_TIME_LOG 0 + +#define DO_CF 1 + +#define IS_ARM_OF_SOME_KIND (__arm__ || __arm64__) + +#ifdef SYSLOG +#if SYSLOG +#define _syslog(str, args...) do { syslog(str, ##args); } while(0) +#else +#define _syslog(str, args...) do {} while(0) +#endif +#endif + +#ifdef SYSLOG_OTHER +#if SYSLOG_OTHER +#define _syslog_other(str, args...) do { syslog(str, ##args); } while(0) +#else +#define _syslog_other(str, args...) do {} while(0) +#endif +#endif + +#ifdef SYSLOG_TIME_LOG +#if SYSLOG_TIME_LOG +#define _syslog_time_log(str, args...) do { syslog(str, ##args); } while(0) +#else +#define _syslog_time_log(str, args...) do {} while(0) +#endif +#endif + +#define __32_BIT__ (UINTPTR_MAX == 0xffffffff) + +#if __32_BIT___ +#define POINTER_SIZE 4 +#else +#define POINTER_SIZE 8 +#endif + +#if IS_ARM_OF_SOME_KIND +#define UNTETHER_STRING "/untether/game_over_armv7.dylib1" +#else +#define UNTETHER_STRING "./bin/game_over.dylib" +#endif + +//typedef enum { false, true } bool; + +bool interpose_hax(); + +extern char** environ; + +bool do_it = true; +bool syslog_it = true; + +void ensure_env() { + if (syslog_it) + _syslog_other(LOG_SYSLOG, "setting envs, just in case"); // THIS CAUSES A SEGFAULT IN gettimeofday! IT RECURSIVELY FUCKS UP EVERYTHING!!! + char* DYLD_INSERT_LIBRARIES = getenv("DYLD_INSERT_LIBRARIES"); + if (!DYLD_INSERT_LIBRARIES) + setenv("DYLD_INSERT_LIBRARIES", UNTETHER_STRING, 0); + else { + char* set_me; + if (strstr(DYLD_INSERT_LIBRARIES, UNTETHER_STRING) == NULL) + asprintf(&set_me, "%s:" UNTETHER_STRING, DYLD_INSERT_LIBRARIES); + else + asprintf(&set_me, "%s", DYLD_INSERT_LIBRARIES); + + if (set_me) + setenv("DYLD_INSERT_LIBRARIES", set_me, 1); + + free(set_me); + } +} + +int get_offset() { + char* __OFFSET = getenv("__OFFSET"); + int offset = 0; + if (__OFFSET) { + offset = atoi(__OFFSET); + } + return offset; +} + +void __before_hook() { + //ensure_env(); +} + +void __before_exec(int line, const char* s) { + /* + before_exec hook + example would be for tracing execs + + printf("%d: %s\n", line, s); + */ +} + +int _clock_gettime(clockid_t clk_id, struct timespec *tp) { + __before_hook(); // fix up stuff + + clockid_t clk_id_ = clk_id; // recreate variables + struct timespec tp_; + int ret; // return val + + long old_tv_sec; // for logging + + ret = clock_gettime(clk_id_, &tp_); // call original + + old_tv_sec = tp_.tv_sec; // set old + + if (do_it) { + tp_.tv_sec += get_offset(); // get offset, and add it + } + + _syslog_time_log(LOG_SYSLOG, "[c] %ld, %ld", old_tv_sec, tp_.tv_sec); + + memcpy(tp, &tp_, sizeof(struct timespec)); + return ret; +} + +time_t _time(time_t* t) { + __before_hook(); // fix up stuff + + time_t t_; // recreate variables + time_t ret; // return val + ret = time(&t_); // get time + + time_t old_t_ = t_; // for logging + + if (do_it) { + t_ +=get_offset(); // get offset, and add it + } + + _syslog_time_log(LOG_SYSLOG, "[t] %ld, %ld\n", old_t_, t_); + + if (t) + *t = t_; // gawd damn segfaults! + + return t_; +} + +#if 0 +uint64_t _mach_absolute_time(void) { + /* + mach_absolute_time hook is disabled for now, creates weird (read: fun) + UI bugs + */ + + __before_hook(); // fix up stuff + uint64_t at = mach_absolute_time(); // get return + +#if 0 + long old_tv_sec; + + uint64_t add = get_offset(); + add *= 1000000000; // seconds -> nanoseconds + + uint64_t ret = at; + + uint64_t old_ret = ret; + + if (do_it) { + ret += add; + }; + + _syslog_time_log(LOG_SYSLOG, "[m] %llu, %llu", old_ret, ret); + + return ret; +#else + return at; +#endif +} +#endif + +int _gettimeofday(struct timeval *restrict tv, + struct timezone *restrict tz) { + + syslog_it = false; // syslog uses gettimeofday, using + // syslog in this function causes + // a recursive loop + __before_hook(); + syslog_it = true; + struct timeval tv_; + struct timezone tz_; + gettimeofday(&tv_, &tz_); + + long old_tv_sec = tv_.tv_sec; + + tv_.tv_sec += get_offset(); + tv_.tv_usec += 0; + + /* + SYSLOG CAN NOT BE CALLED IN THIS FUNCTION + IT ENTERS AN INFINITE LOOP + */ + + if(tv)memcpy(tv, &tv_, sizeof(struct timeval)); + if(tz)memcpy(tz, &tz_, sizeof(struct timezone)); + + return 0; +} + +int _setenv(const char *var_name, const char *new_value, int change_flag) { + __before_hook(); // fix up stuff + + int ret = setenv(var_name, new_value, change_flag); // call original function + + ensure_env(); // fix up again + return ret; +} + +int _putenv(char *var_name) { + __before_hook(); // fix up stuff + + int ret = putenv(var_name); // call original function + + ensure_env(); // fix up again + return ret; +} + +#if !IS_ARM_OF_SOME_KIND +int _system(const char *command) { + /* + this is dumb, system isn't even on iOS, and if it is, + it's gotten from dlsym, so this won't work! + */ + __before_hook(); + __before_exec(__LINE__, command); + return system(command); +} +#endif + +int _execv(const char *filename, char *const argv[]) { + __before_hook(); // fix up stuff + __before_exec(__LINE__, filename); // more hooks + return execv(filename, argv); // call original +} + +int _execl(const char *filename, const char *arg0, ...) { + __before_hook(); // fix up stuff + __before_exec(__LINE__, filename); // more hooks + + /* + let's do a code rundown. + + first, it takes the arg0 pointer, and uses it as an array/vector of + pointers (which it essentially is, just that it's the first (0th) item) + + it then counts how many pointers it takes to get to the NULL pointer, + the end of the list for execl and co + + then, it allocates a new array, and puts those pointers in the array. + + then it calls execv with that array. + */ + + char** _argv = NULL; + int count = 0; + int ret; + + while (*(arg0 + (count * POINTER_SIZE))) + count++; + + _argv = (char**)malloc(count * POINTER_SIZE); + + for (int i = 0; i < count; i++) { + _argv[i] = (char*)(arg0 + POINTER_SIZE); + } + + ret = execv(filename, _argv); + free(_argv); + + return ret; +} + +int _execve(const char *filename, char *const argv[], char *const env[]) { + __before_hook(); + __before_exec(__LINE__, filename); + return execve(filename, argv, environ); +} + +int _execle(const char *filename, const char *arg0, ...) { + __before_hook(); + __before_exec(__LINE__, filename); + + char** _argv = NULL; + int count = 0; + int ret; + + while (*(arg0 + (count * POINTER_SIZE))) + count++; + + _argv = (char**)malloc(count * POINTER_SIZE); + + for (int i = 0; i < count; i++) { + _argv[i] = (char*)(arg0 + POINTER_SIZE); + } + + ret = execve(filename, _argv, (char**)(arg0 + (((count + 2) * POINTER_SIZE)))); + free(_argv); + + return ret; +} + +int _execvp(const char *filename, char *const argv[]) { + __before_hook(); + __before_exec(__LINE__, filename); + return execvp(filename, argv); +} + +int _execlp(const char *filename, const char *arg0, ...) { + __before_hook(); + __before_exec(__LINE__, filename); + + char** _argv = NULL; + int count = 0; + int ret; + + while (*(arg0 + (count * POINTER_SIZE))) + count++; + + _argv = (char**)malloc(count * POINTER_SIZE); + + for (int i = 0; i < count; i++) { + _argv[i] = (char*)(arg0 + POINTER_SIZE); + } + + ret = execvp(filename, _argv); + + return ret; +} + +int _posix_spawn(pid_t *restrict pid, const char *restrict path, + const posix_spawn_file_actions_t *restrict file_actions, + const posix_spawnattr_t *restrict attrp, + char *const argv[restrict], + char *const envp[restrict]) { + __before_hook(); + __before_exec(__LINE__, path); + return posix_spawn(pid, path, file_actions, attrp, argv, environ); +} +int _posix_spawnp(pid_t *restrict pid, const char *restrict file, + const posix_spawn_file_actions_t *restrict file_actions, + const posix_spawnattr_t *restrict attrp, + char *const argv[restrict], + char *const envp[restrict]) { + __before_hook(); + __before_exec(__LINE__, file); + return posix_spawnp(pid, file, file_actions, attrp, argv, environ); +} + +/* substitute */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __LP64__ +#define nlist_native nlist_64 +#define LC_SEGMENT_NATIVE LC_SEGMENT_64 +#define segment_command_native segment_command_64 +#define mach_header_native mach_header_64 +#define section_native section_64 +#define PAGEZERO_SIZE 0x100000000; +#else +#define nlist_native nlist +#define LC_SEGMENT_NATIVE LC_SEGMENT +#define segment_command_native segment_command +#define mach_header_native mach_header +#define section_native section +#define PAGEZERO_SIZE 0x1000 +#endif + +__attribute__((noinline)) +static void *find_lazy(uint32_t ncmds, const struct load_command *cmds, uintptr_t slide, const char *desired) { + uint32_t symoff = 0, stroff = 0, isymoff = 0, lazy_index = 0, lazy_size = 0; + void **lazy = 0; + uint32_t cmdsleft; + const struct load_command *lc; + + uintptr_t thisimage = (uintptr_t) &find_lazy - slide; + + for(lc = cmds, cmdsleft = ncmds; cmdsleft--;) { + if(lc->cmd == LC_SYMTAB) { + const struct symtab_command *sc = (void *) lc; + stroff = sc->stroff; + symoff = sc->symoff; + } else if(lc->cmd == LC_DYSYMTAB) { + const struct dysymtab_command *dc = (void *) lc; + isymoff = dc->indirectsymoff; + } else if(lc->cmd == LC_SEGMENT_NATIVE) { + const struct segment_command_native *sc = (void *) lc; + const struct section_native *sect = (void *) (sc + 1); + uint32_t i; + if(sc->vmaddr <= thisimage && thisimage < (sc->vmaddr + sc->vmsize)) return 0; + for(i = 0; i < sc->nsects; i++) { + if((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { + lazy_index = sect->reserved1; + lazy_size = sect->size / sizeof(*lazy); + lazy = (void *) sect->addr + slide; + } + sect++; + } + } + lc = (void *) ((char *) lc + lc->cmdsize); + } + + if(!stroff || !symoff || !isymoff || !lazy_index) return 0; + +#define CATCH(off, addr) if(sc->fileoff <= (off) && (sc->fileoff + sc->filesize) >= (off)) (addr) = (void *) (sc->vmaddr + slide + (off) - sc->fileoff); + struct nlist_native *syms = 0; + const char *strs = 0; + uint32_t *isyms = 0; + + for(lc = cmds, cmdsleft = ncmds; cmdsleft--;) { + if(lc->cmd == LC_SEGMENT_NATIVE) { + struct segment_command_native *sc = (void *) lc; + CATCH(symoff, syms); + CATCH(stroff, strs); + CATCH(isymoff, isyms); + } + lc = (void *) ((char *) lc + lc->cmdsize); + } + + if(!syms || !strs || !isyms) return 0; + + uint32_t i; + for(i = lazy_index; i < lazy_index + lazy_size; i++) { + const struct nlist_native *sym = syms + isyms[i]; + if(!strcmp(strs + sym->n_un.n_strx, desired)) { + return lazy; + } + lazy++; + } + + return 0; +} + +bool interpose(const char *name, void *impl) { + const struct mach_header_native *mach_hdr; + bool result = false; + uint32_t i; + for(i = 0; (mach_hdr = (void *) _dyld_get_image_header(i)); i++) { + void **lazy = find_lazy(mach_hdr->ncmds, (void *) (mach_hdr + 1), _dyld_get_image_vmaddr_slide(i), name); + if(lazy) { + result = true; + mprotect((void*)(((uintptr_t)lazy) & (~0x1000)), 0x1000, PROT_READ | PROT_WRITE); + *lazy = impl; + } + } + return result; +} + +bool interpose_hdr(const char *name, void *impl, const struct mach_header *mach_hdr, uintptr_t slide) { + bool result = false; + void **lazy = find_lazy(mach_hdr->ncmds, (void *) (mach_hdr + 1), slide, name); + if(lazy) { + result = true; + mprotect((void*)(((uintptr_t)lazy) & (~0x1000)), 0x1000, PROT_READ | PROT_WRITE); + *lazy = impl; + } + return result; +} + + +#if DO_CF +CFAbsoluteTime _CFAbsoluteTimeGetCurrent() { + return CFAbsoluteTimeGetCurrent() + get_offset(); +} +#endif + +bool interpose_hax() { + _syslog(LOG_SYSLOG, "hax teh envs"); + interpose("_setenv", &_setenv); + interpose("_putenv", &_putenv); + + _syslog(LOG_SYSLOG, "haxing exec shit"); + interpose("_execl", &_execl); + interpose("_execlp", &_execlp); + interpose("_execle", &_execle); + interpose("_execv", &_execv); + interpose("_execve", &_execve); + interpose("_execvp", &_execvp); + interpose("_posix_spawn", &_posix_spawn); + interpose("_posix_spawnp", &_posix_spawnp); + + _syslog(LOG_SYSLOG, "haxing time shit"); + interpose("_clock_gettime", &_clock_gettime); + interpose("_gettimeofday", &_gettimeofday); + interpose("_time", &_time); +#if DO_CF + interpose("_CFAbsoluteTimeGetCurrent", &_CFAbsoluteTimeGetCurrent); +#endif + + return true; +} + +bool interpose_hax_hdr(const struct mach_header* mh, uintptr_t slide) { + interpose_hdr("_setenv", &_setenv, mh, slide); + interpose_hdr("_putenv", &_putenv, mh, slide); + interpose_hdr("_execl", &_execl, mh, slide); + interpose_hdr("_execlp", &_execlp, mh, slide); + interpose_hdr("_execle", &_execle, mh, slide); + interpose_hdr("_execv", &_execv, mh, slide); + interpose_hdr("_execve", &_execve, mh, slide); + interpose_hdr("_execvp", &_execvp, mh, slide); + interpose_hdr("_posix_spawn", &_posix_spawn, mh, slide); + interpose_hdr("_posix_spawnp", &_posix_spawnp, mh, slide); + interpose_hdr("_clock_gettime", &_clock_gettime, mh, slide); + interpose_hdr("_gettimeofday", &_gettimeofday, mh, slide); + interpose_hdr("_time", &_time, mh, slide); +#if DO_CF + interpose("_CFAbsoluteTimeGetCurrent", &_CFAbsoluteTimeGetCurrent); +#endif + + return true; +} + +void _dyld_wrapper(const struct mach_header* mh, intptr_t vmaddr_slide) { + _syslog(LOG_SYSLOG, "_dyld_wrapper: %p 0x%08lx", mh, vmaddr_slide); + interpose_hax_hdr(mh, vmaddr_slide); +} + +__attribute__((constructor)) static +void game_over(int argc, const char **argv) { + _syslog(LOG_SYSLOG, "0wn'd %d", getpid()); + _syslog(LOG_SYSLOG, "offset=%d", get_offset()); + _syslog(LOG_SYSLOG, "interposition..."); + + interpose_hax(); + _dyld_register_func_for_add_image(&_dyld_wrapper); + + ensure_env(); + + _syslog(LOG_SYSLOG, "enabling offsetting..."); + + do_it = true; +} + +__attribute__((destructor)) static +void game_is_actually_over(int argc, const char **argv) { + _syslog(LOG_SYSLOG, "todo"); +} + +@interface NSDate (hax) +@end + +@implementation NSDate (hax) + ++ (NSDate*)date { + double time_ = (double)time(NULL); + + return [NSDate dateWithTimeIntervalSince1970:time_]; +} + ++ (NSDate*)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs { + double time_ = (double)time(NULL); + + time_ += secs; + return [NSDate dateWithTimeIntervalSince1970:time_]; +} + +- (NSDate*)initWithTimeIntervalSinceNow:(NSTimeInterval)secs { + double time_ = (double)time(NULL); + + time_ += secs; + return [NSDate dateWithTimeIntervalSince1970:time_]; +} + +@end diff --git a/interpose/src/main.mm b/interpose/src/main.mm new file mode 100755 index 0000000..10efc39 --- /dev/null +++ b/interpose/src/main.mm @@ -0,0 +1 @@ +#include "envbypass.h" \ No newline at end of file -- cgit v1.2.3