void *RemapPage(void * va){ kern_return_t kr; mach_vm_address_t target_addr=0; mach_vm_address_t source_addr; vm_prot_t prot_cur = VM_PROT_READ | VM_PROT_WRITE; vm_prot_t prot_max = VM_PROT_READ | VM_PROT_WRITE; source_addr = (mach_vm_address_t) va; kr = mach_vm_remap (mach_task_self(), &target_addr, PageSize, 0, TRUE, mach_task_self(), source_addr, FALSE, &prot_cur, &prot_max, VM_INHERIT_SHARE); if (kr != KERN_SUCCESS) { printf(" mremap error: %d \n", kr); printf(" no of pages used %d %d %d\n", AddressSpaceUsage1, AddressSpaceUsage2, AddressSpaceUsage2+AddressSpaceUsage1); abort(); } va = (void *) target_addr; return va; #ifdef FILESTATISTIC logusage(); #endif #ifdef STATISTIC AddressSpaceUsage2++; #endif }
static int get_foreign_image_export(mach_port_t task, uint64_t hdr_addr, void **linkedit_p, size_t *linkedit_size_p, void **export_p, size_t *export_size_p, cpu_type_t *cputype_p, char **error) { mach_vm_offset_t hdr_buf = 0; mach_vm_size_t hdr_buf_size; int ret; vm_prot_t cur, max; hdr_buf_size = PAGE_SIZE; kern_return_t kr = mach_vm_remap(mach_task_self(), &hdr_buf, hdr_buf_size, 0, VM_FLAGS_ANYWHERE, task, hdr_addr, /*copy*/ true, &cur, &max, VM_INHERIT_NONE); if (kr) { asprintf(error, "mach_vm_remap(libdyld header): kr=%d", kr); return SUBSTITUTE_ERR_MISC; } struct mach_header *mh = (void *) hdr_buf; if (mh->magic != MH_MAGIC && mh->magic != MH_MAGIC_64) { asprintf(error, "bad magic in libdyld mach_header"); ret = SUBSTITUTE_ERR_MISC; goto fail; } *cputype_p = mh->cputype; size_t mh_size = mh->magic == MH_MAGIC_64 ? sizeof(struct mach_header_64) : sizeof(struct mach_header); if (mh->sizeofcmds < mh_size || mh->sizeofcmds > 128*1024) goto badmach; size_t total_size = mh_size + mh->sizeofcmds; if (total_size > hdr_buf_size) { vm_deallocate(mach_task_self(), (vm_offset_t) hdr_buf, (vm_size_t) hdr_buf_size); hdr_buf_size = total_size; hdr_buf = 0; kr = mach_vm_remap(mach_task_self(), &hdr_buf, hdr_buf_size, 0, VM_FLAGS_ANYWHERE, task, hdr_addr, /*copy*/ true, &cur, &max, VM_INHERIT_NONE); if (kr) { asprintf(error, "mach_vm_remap(libdyld header) #2: kr=%d", kr); ret = SUBSTITUTE_ERR_MISC; goto fail; } mh = (void *) hdr_buf; } struct load_command *lc = (void *) mh + mh_size; uint32_t export_off = 0, export_size = 0; uint64_t slide = 0; for (uint32_t i = 0; i < mh->ncmds; i++, lc = (void *) lc + lc->cmdsize) { size_t remaining = total_size - ((void *) lc - (void *) mh); if (remaining < sizeof(*lc) || remaining < lc->cmdsize) goto badmach; if (lc->cmd == LC_DYLD_INFO || lc->cmd == LC_DYLD_INFO_ONLY) { struct dyld_info_command *dc = (void *) lc; if (lc->cmdsize < sizeof(*dc)) goto badmach; export_off = dc->export_off; export_size = dc->export_size; } else if (lc->cmd == LC_SEGMENT) { struct segment_command *sc = (void *) lc; if (lc->cmdsize < sizeof(*sc)) goto badmach; if (sc->fileoff == 0) slide = hdr_addr - sc->vmaddr; } else if (lc->cmd == LC_SEGMENT_64) { struct segment_command_64 *sc = (void *) lc; if (lc->cmdsize < sizeof(*sc)) goto badmach; if (sc->fileoff == 0) slide = hdr_addr - sc->vmaddr; } } if (export_off == 0) { asprintf(error, "no LC_DYLD_INFO in libdyld header"); ret = SUBSTITUTE_ERR_MISC; goto fail; } lc = (void *) mh + mh_size; uint64_t export_segoff, vmaddr, fileoff, filesize; for (uint32_t i = 0; i < mh->ncmds; i++, lc = (void *) lc + lc->cmdsize) { if (lc->cmd == LC_SEGMENT) { struct segment_command *sc = (void *) lc; vmaddr = sc->vmaddr; fileoff = sc->fileoff; filesize = sc->filesize; } else if (lc->cmd == LC_SEGMENT_64) { struct segment_command_64 *sc = (void *) lc; vmaddr = sc->vmaddr; fileoff = sc->fileoff; filesize = sc->filesize; } else { continue; } export_segoff = (uint64_t) export_off - fileoff; if (export_segoff < filesize) { if (export_size > filesize - export_segoff) goto badmach; break; } } uint64_t linkedit_addr = vmaddr + slide; mach_vm_address_t linkedit_buf = 0; kr = mach_vm_remap(mach_task_self(), &linkedit_buf, filesize, 0, VM_FLAGS_ANYWHERE, task, linkedit_addr, /*copy*/ true, &cur, &max, VM_INHERIT_NONE); if (kr) { asprintf(error, "mach_vm_remap(libdyld linkedit): kr=%d", kr); ret = SUBSTITUTE_ERR_MISC; goto fail; } *linkedit_p = (void *) linkedit_buf; *linkedit_size_p = (size_t) filesize; *export_p = (void *) linkedit_buf + export_segoff; *export_size_p = export_size; ret = SUBSTITUTE_OK; goto fail; badmach: asprintf(error, "bad Mach-O data in libdyld header"); ret = SUBSTITUTE_ERR_MISC; goto fail; fail: vm_deallocate(mach_task_self(), (vm_offset_t) hdr_buf, (vm_size_t) hdr_buf_size); return ret; }