/* ================================================================================ modified from this: https://github.com/its-a-feature/macos_execute_from_memory (supports only bundle) code injection : https://github.com/CylanceVulnResearch/osx_runbin by Stephanie Archibald (does not support m1 x64 emulation and FAT header) added FAT header (universal Macho) parsing script-kiddied, debugged, etc. by @exploitpreacher ================================================================================ */ #include #include #include #include #include // for close #include #include #include #include #include #include int find_macho(unsigned long addr, unsigned long *base, unsigned int increment, unsigned int dereference) { unsigned long ptr; printf("in find_macho\n"); *base = 0; printf("set base pointer to 0\n"); for (int i=0; i<100000000; i++) { printf("i: %d\n", i); ptr = addr; printf("1\n"); if(dereference) ptr = *(unsigned long *)ptr; printf("2\n"); // chmod returns EFAULT if the path pointer is // outside the process's allocated address space; // it returns ENOENT if the path doesn't exist... // so it's WITHIN process's allocated addr space chmod((char *)ptr, 0777); if(errno == 2 /*ENOENT*/ && ((int *)ptr)[0] == 0xfeedfacf /*MH_MAGIC_64*/) { *base = ptr; return 0; } addr += increment; } return 1; } int find_epc(unsigned long base, struct entry_point_command **entry) { // find the entry point command by searching through base's load commands struct mach_header_64 *mh; struct load_command *lc; unsigned long text = 0; *entry = NULL; mh = (struct mach_header_64 *)base; lc = (struct load_command *)(base + sizeof(struct mach_header_64)); for(int i=0; incmds; i++) { if(lc->cmd == LC_MAIN) { //0x80000028 *entry = (struct entry_point_command *)lc; return 0; } lc = (struct load_command *)((unsigned long)lc + lc->cmdsize); } return 1; } uint32_t swap_endian(uint32_t wrong_endian) { uint32_t swapped = ((wrong_endian>>24)&0xff) | // move byte 3 to byte 0 ((wrong_endian<<8)&0xff0000) | // move byte 1 to byte 2 ((wrong_endian>>8)&0xff00) | // move byte 2 to byte 1 ((wrong_endian<<24)&0xff000000); // byte 0 to byte 3 return swapped; } int main(int argc, char **argv) { char filename[] = "/tmp/loadmacho"; char *tokenBuf = NULL; int numTokens = 0; NSObjectFileImage fileImage = NULL; NSModule module = NULL; NSSymbol symbol = NULL; struct stat stat_buf1, stat_buf2; int fd1, fd2; void *codeAddr = NULL; void *machoAddr = NULL; uint32_t type; uint32_t offset = 0; uint32_t machoBufSize; // load the command file if ((fd1 = open(filename, O_RDONLY, 0)) == -1) { printf("Error opening the file %s\n", filename); return 1; } if (fstat(fd1, &stat_buf1)){ return 1; } tokenBuf = mmap(NULL, stat_buf1.st_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, fd1, 0); close(fd1); // remove newline tokenBuf[strcspn(tokenBuf, "\n")] = 0; char *tokenArray[256]; int max_tokens = 256; char *saveptr = NULL; char *p = strtok_r(tokenBuf, " ", &saveptr); while (p != NULL && numTokens < max_tokens) { tokenArray[numTokens++] = p; p = strtok_r(NULL, " ", &saveptr); } for(int j=0;jcputype); offset = swap_endian(fa->offset); printf("offset: %x\n", offset); machoAddr = codeAddr + offset; printf("after offset: %x\n", ((uint32_t *)machoAddr)[0]); if (((int *)codeAddr)[0] != 0xfeedfacf /* MAGIC for MACHO 64 */) { printf("x64 macho found...\n"); break; } } if (!machoAddr) { goto err; } } else if (((int *)codeAddr)[0] == 0xfeedfacf) /* MAGIC for MACHO x64 */ { machoAddr = codeAddr; } else { printf("Not supported yet\n"); goto err; } type = ((int *)machoAddr)[3]; printf("type = %x\n", type); machoBufSize = stat_buf2.st_size - offset; if (type == 0x8) { // bundle - nothing to do void (*function)(); printf("bundle...no need to find the main function"); NSCreateObjectFileImageFromMemory(machoAddr, machoBufSize, &fileImage); module = NSLinkModule(fileImage, "module", NSLINKMODULE_OPTION_NONE); symbol = NSLookupSymbolInModule(module, "_main"); function = NSAddressOfSymbol(symbol); function(); } else { // we have to find the main function unsigned long execute_base; struct entry_point_command *epc; ((int *)machoAddr)[3] = 0x8; // first change to mh_bundle type printf("type changed = %x\n", ((int *)machoAddr)[3]); NSCreateObjectFileImageFromMemory(machoAddr, machoBufSize, &fileImage); module = NSLinkModule(fileImage, "module", NSLINKMODULE_OPTION_NONE); printf("got NSLinkModule ret: %p\n", module); printf("got NSLinkModule ret: %p\n", (uint32_t)module); module = ((uintptr_t)(module)) >> 1; printf("got NSLinkModule ret: %p\n", module); printf("searching for main\n"); //if(find_macho((unsigned long)module, &execute_base, sizeof(uint32_t), 1)) { if(find_macho((unsigned long)module, &execute_base, sizeof(uint32_t), 1)) { printf("Could not find execute_base.\n"); goto err; } printf("found base=%lx\n", execute_base); if(find_epc(execute_base, &epc)) { printf("Could not find epc.\n"); goto err; } printf("found epc=%lx\n", epc); int(*main)(int, char**, char**, char**) = (int(*)(int, char**, char**, char**))(execute_base + epc->entryoff); char *env[] = {NULL}; char *apple[] = {NULL}; main(numTokens, tokenArray, env, apple); } err: NSUnLinkModule(module, NSUNLINKMODULE_OPTION_NONE); NSDestroyObjectFileImage(fileImage); return 0; }