Created
June 8, 2021 18:35
-
-
Save johnkhbaek/d9f7c7db926b516f2a64daa12a26eb1e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
================================================================================ | |
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 <mach-o/dyld.h> | |
#include <sys/stat.h> | |
#include <sys/mman.h> | |
#include <fcntl.h> | |
#include <unistd.h> // for close | |
#include <stdio.h> | |
#include <errno.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <mach-o/fat.h> | |
int find_macho(unsigned long addr, unsigned long *base, unsigned int increment, unsigned int dereference) { | |
unsigned long ptr; | |
*base = 0; | |
for (int i=0; i<100000000; i++) { | |
ptr = addr; | |
if(dereference) ptr = *(unsigned long *)ptr; | |
// 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; i<mh->ncmds; 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) | |
{ | |
NSObjectFileImage fileImage = NULL; | |
NSModule module = NULL; | |
NSSymbol symbol = NULL; | |
struct stat stat_buf; | |
int fd; | |
void *codeAddr = NULL; | |
void *machoAddr = NULL; | |
uint32_t type; | |
uint32_t offset = 0; | |
uint32_t machoBufSize; | |
if (argc < 2) { | |
printf("must supply filename\n"); | |
return -1; | |
} | |
if ((fd = open(argv[1], O_RDONLY, 0)) == -1) { | |
return 1; | |
} | |
if (fstat(fd, &stat_buf)){ | |
return 1; | |
} | |
codeAddr = mmap(NULL, | |
stat_buf.st_size, | |
PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, | |
fd, | |
0); | |
close(fd); | |
// we loaded the file | |
// determine the type of the file we loaded | |
if (((int *)codeAddr)[0] == 0xbebafeca) /* MAGIC for FAT */ { | |
struct fat_arch *fa; | |
uint32_t num_arch = swap_endian(((uint32_t *)codeAddr)[1]); | |
printf("%x\n", num_arch); | |
for (int i=0;i<num_arch;i++) { | |
fa = (struct fat_arch *)(codeAddr + (sizeof(uint32_t) * 2)); | |
printf("cpu type: %x\n", fa->cputype); | |
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_buf.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("searching for main\n"); | |
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 ec.\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}; | |
char *argv[]={"test", NULL}; | |
int argc = 1; | |
main(argc, argv, env, apple); | |
} | |
err: | |
NSUnLinkModule(module, NSUNLINKMODULE_OPTION_NONE); | |
NSDestroyObjectFileImage(fileImage); | |
if(codeAddr) {free(codeAddr);} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment