int main() { // NSObjectFileImage APIs are only available on Mac OS X - not iPhone OS #if __MAC_OS_X_VERSION_MIN_REQUIRED int fd = open("test.bundle", O_RDONLY, 0); if ( fd == -1 ) { FAIL("open() failed"); return 1; } struct stat stat_buf; if ( fstat(fd, &stat_buf) == -1) { FAIL("fstat() failed"); return 0; } void* loadAddress = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); if ( loadAddress == ((void*)(-1)) ) { FAIL("mmap() failed"); return 0; } close(fd); NSObjectFileImage ofi; if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) != NSObjectFileImageSuccess ) { FAIL("NSCreateObjectFileImageFromMemory failed"); return 0; } NSModule mod = NSLinkModule(ofi, "he_he", NSLINKMODULE_OPTION_NONE); if ( mod == NULL ) { FAIL("NSLinkModule failed"); return 0; } // look for he_he string in list of images loaded struct dyld_all_image_infos* infos = getImageInfosFromKernel(); if ( infos->infoArrayCount < 2 ) { FAIL("bundle-memory-load-all-images: dyld_all_image_infos.infoArrayCount is < 2"); return 0; } bool found = false; for( int i=0; i < infos->infoArrayCount; ++i) { //fprintf(stderr, "infos->infoArray[%d].imageLoadAddress=%p %s\n", i, infos->infoArray[i].imageLoadAddress, infos->infoArray[i].imageFilePath); if ( infos->infoArray[i].imageFilePath == NULL ) { FAIL("bundle-memory-load-all-images: NULL image path found"); exit(0); } if ( strcmp(infos->infoArray[i].imageFilePath, "he_he") == 0 ) found = true; } if ( !found ) { FAIL("bundle-memory-load-all-images: loaded memory bundle 'he_he' nout found"); return 0; } if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) { FAIL("NSUnLinkModule failed"); return 0; } if ( !NSDestroyObjectFileImage(ofi) ) { FAIL("NSDestroyObjectFileImage failed"); return 0; } // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage) #endif PASS("bundle-memory-load-all-images"); return 0; }
static void checkBundle(const char* path, bool unlinkBeforeDestroy) { int fd = open(path, O_RDONLY, 0); if ( fd == -1 ) { printf("[FAIL] open(%s) failed", path); exit(0); } struct stat stat_buf; if ( fstat(fd, &stat_buf) == -1) { printf("[FAIL] fstat() failed\n"); exit(0); } void* loadAddress = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); if ( loadAddress == ((void*)(-1)) ) { printf("[FAIL] mmap() failed\n"); exit(0); } close(fd); NSObjectFileImage ofi; if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) != NSObjectFileImageSuccess ) { printf("[FAIL] NSCreateObjectFileImageFromMemory failed\n"); exit(0); } NSModule mod = NSLinkModule(ofi, path, NSLINKMODULE_OPTION_NONE); if ( mod == NULL ) { printf("[FAIL] NSLinkModule failed\n"); exit(0); } if ( !unlinkBeforeDestroy ) { // API lets you destroy ofi and NSModule lives on if ( !NSDestroyObjectFileImage(ofi) ) { printf("[FAIL] NSDestroyObjectFileImage failed\n"); exit(0); } } NSSymbol sym = NSLookupSymbolInModule(mod, "_fooInBundle"); if ( sym == NULL ) { printf("[FAIL] NSLookupSymbolInModule failed\n"); exit(0); } void* func = NSAddressOfSymbol(sym); if ( func == NULL ) { printf("[FAIL] NSAddressOfSymbol failed\n"); exit(0); } Dl_info info; if ( dladdr(func, &info) == 0 ) { printf("[FAIL] dladdr(&p, xx) failed\n"); exit(0); } //printf("_fooInBundle found in %s\n", info.dli_fname); if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) { printf("[FAIL] NSUnLinkModule failed\n"); exit(0); } if ( dladdr(func, &info) != 0 ) { printf("[FAIL] dladdr(&p, xx) found but should not have\n"); exit(0); } if ( unlinkBeforeDestroy ) { if ( !NSDestroyObjectFileImage(ofi) ) { printf("[FAIL] NSDestroyObjectFileImage failed\n"); exit(0); } } }
MODULE_SCOPE int TclpLoadMemory( Tcl_Interp *interp, /* Used for error reporting. */ void *buffer, /* Buffer containing the desired code * (allocated with TclpLoadMemoryGetBuffer). */ int size, /* Allocation size of buffer. */ int codeSize, /* Size of code data read into buffer or -1 if * an error occurred and the buffer should * just be freed. */ Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr) /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ { Tcl_DyldLoadHandle *dyldLoadHandle; NSObjectFileImage dyldObjFileImage = NULL; Tcl_DyldModuleHandle *modulePtr; NSModule module; const char *objFileImageErrMsg = NULL; /* * Try to create an object file image that we can load from. */ if (codeSize >= 0) { NSObjectFileImageReturnCode err = NSObjectFileImageSuccess; const struct fat_header *fh = buffer; uint32_t ms = 0; #ifndef __LP64__ const struct mach_header *mh = NULL; #define mh_size sizeof(struct mach_header) #define mh_magic MH_MAGIC #define arch_abi 0 #else const struct mach_header_64 *mh = NULL; #define mh_size sizeof(struct mach_header_64) #define mh_magic MH_MAGIC_64 #define arch_abi CPU_ARCH_ABI64 #endif if ((size_t) codeSize >= sizeof(struct fat_header) && fh->magic == OSSwapHostToBigInt32(FAT_MAGIC)) { uint32_t fh_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch); /* * Fat binary, try to find mach_header for our architecture */ TclLoadDbgMsg("Fat binary, %d archs", fh_nfat_arch); if ((size_t) codeSize >= sizeof(struct fat_header) + fh_nfat_arch * sizeof(struct fat_arch)) { void *fatarchs = (char*)buffer + sizeof(struct fat_header); const NXArchInfo *arch = NXGetLocalArchInfo(); struct fat_arch *fa; if (fh->magic != FAT_MAGIC) { swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder); } fa = NXFindBestFatArch(arch->cputype | arch_abi, arch->cpusubtype, fatarchs, fh_nfat_arch); if (fa) { TclLoadDbgMsg("NXFindBestFatArch() successful: " "local cputype %d subtype %d, " "fat cputype %d subtype %d", arch->cputype | arch_abi, arch->cpusubtype, fa->cputype, fa->cpusubtype); mh = (void*)((char*)buffer + fa->offset); ms = fa->size; } else { TclLoadDbgMsg("NXFindBestFatArch() failed"); err = NSObjectFileImageInappropriateFile; } if (fh->magic != FAT_MAGIC) { swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder); } } else { TclLoadDbgMsg("Fat binary header failure"); err = NSObjectFileImageInappropriateFile; } } else { /* * Thin binary */ TclLoadDbgMsg("Thin binary"); mh = buffer; ms = codeSize; } if (ms && !(ms >= mh_size && mh->magic == mh_magic && mh->filetype == MH_BUNDLE)) { TclLoadDbgMsg("Inappropriate file: magic %x filetype %d", mh->magic, mh->filetype); err = NSObjectFileImageInappropriateFile; } if (err == NSObjectFileImageSuccess) { err = NSCreateObjectFileImageFromMemory(buffer, codeSize, &dyldObjFileImage); if (err == NSObjectFileImageSuccess) { TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() " "successful"); } else { objFileImageErrMsg = DyldOFIErrorMsg(err); TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() failed: %s", objFileImageErrMsg); } } else { objFileImageErrMsg = DyldOFIErrorMsg(err); } } /* * If it went wrong (or we were asked to just deallocate), get rid of the * memory block and create an error message. */ if (dyldObjFileImage == NULL) { vm_deallocate(mach_task_self(), (vm_address_t) buffer, size); if (objFileImageErrMsg != NULL) { Tcl_AppendResult(interp, "NSCreateObjectFileImageFromMemory() " "error: ", objFileImageErrMsg, NULL); } return TCL_ERROR; } /* * Extract the module we want from the image of the object file. */ module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]", NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR); NSDestroyObjectFileImage(dyldObjFileImage); if (module) { TclLoadDbgMsg("NSLinkModule() successful"); } else { NSLinkEditErrors editError; int errorNumber; const char *errorName, *errMsg; NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg); Tcl_AppendResult(interp, errMsg, NULL); return TCL_ERROR; } /* * Stash the module reference within the load handle we create and return. */ modulePtr = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle)); modulePtr->module = module; modulePtr->nextPtr = NULL; dyldLoadHandle = (Tcl_DyldLoadHandle *) ckalloc(sizeof(Tcl_DyldLoadHandle)); #if TCL_DYLD_USE_DLFCN dyldLoadHandle->dlHandle = NULL; #endif dyldLoadHandle->dyldLibHeader = NULL; dyldLoadHandle->modulePtr = modulePtr; *loadHandle = (Tcl_LoadHandle) dyldLoadHandle; *unloadProcPtr = &TclpUnloadFile; return TCL_OK; }
__attribute__ ((constructor)) init(void) { /* load the target file into our buffer */ int fd = -1; if ((fd = open(TARGET, O_RDONLY)) == -1) { ERROR_MSG("Can't open target %s.", TARGET); return; } struct stat stat = {0}; if (fstat(fd, &stat) < 0) { ERROR_MSG("Can't fstat target %s.", TARGET); close(fd); return; } void *target_buf = NULL; kern_return_t kr = 0; /* allocate memory with mach_vm_allocate (requisite) and copy the file into it */ kr = mach_vm_allocate(mach_task_self(), (mach_vm_address_t*)&target_buf, stat.st_size, VM_FLAGS_ANYWHERE); if (kr != KERN_SUCCESS) { ERROR_MSG("Can't allocate buffer for target."); close(fd); return; } ssize_t bytes_read = 0; bytes_read = pread(fd, target_buf, stat.st_size, 0); if (bytes_read == -1 || bytes_read < stat.st_size) { ERROR_MSG("Failed to read target."); close(fd); return; } /* modify file type to MH_BUNDLE if necessary */ /* the file type must be MH_BUNDLE but we can convert it on the fly */ struct mach_header *mh = (struct mach_header*)target_buf; if (mh->magic != MH_MAGIC_64) { ERROR_MSG("Invalid Mach-O target."); close(fd); return; } if (mh->filetype != MH_BUNDLE) { mh->filetype = MH_BUNDLE; } /* now we are ready to call the dyld NS* stuff and get our binary executed */ NSObjectFileImageReturnCode dyld_err; NSObjectFileImage ofi; dyld_err = NSCreateObjectFileImageFromMemory(target_buf, stat.st_size, &ofi); if (dyld_err != NSObjectFileImageSuccess) { ERROR_MSG("Failed to create object file with error %d", dyld_err); } const char *moduleName; uint32_t options = NSLINKMODULE_OPTION_BINDNOW; NSModule m = NULL; /* a name for the module so it can be identified by the image observer */ moduleName = INJECTED_MODULE_NAME; /* finally link the module */ m = NSLinkModule(ofi, moduleName, options); if (m == NULL) { ERROR_MSG("Failed to link module!"); } else { /* register a dyld image observer * we need it because we don't know where the injected image was loaded at * it's not our allocated buffer but a new copy of it * so we can find that image via the name and execute it from there */ _dyld_register_func_for_add_image(image_observer); } close(fd); // /* we can deallocate memory because NSLinkModule will create its own copy */ // target_buf = NULL; // mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)target_buf, stat.st_size); }