void dump_fat_header(FILE *obj_file, int is_swap) { int header_size = sizeof(struct fat_header); int arch_size = sizeof(struct fat_arch); struct fat_header *header = load_bytes(obj_file, 0, header_size); if (is_swap) { swap_fat_header(header, 0); } int arch_offset = header_size; for (int i = 0; i < header->nfat_arch; i++) { struct fat_arch *arch = load_bytes(obj_file, arch_offset, arch_size); if (is_swap) { swap_fat_arch(arch, 1, 0); } int mach_header_offset = arch->offset; free(arch); arch_offset += arch_size; uint32_t magic = read_magic(obj_file, mach_header_offset); int is_64 = is_magic_64(magic); int is_swap_mach = should_swap_bytes(magic); dump_mach_header(obj_file, mach_header_offset, is_64, is_swap_mach); } free(header); }
//-------------------------------------------------------------------------- bool macho_file_t::parse_fat_header() { qlseek(li, start_offset); if ( qlread(li, &fheader, sizeof(fheader)) != sizeof(fheader) ) return false; int code = (fheader.magic == FAT_MAGIC); if ( fheader.magic == FAT_CIGAM ) { swap_fat_header(&fheader); code = 2; } if ( code == 0 || fheader.nfat_arch > 16 ) return false; uint32 fsize = qlsize(li); uint32 archs_size = fheader.nfat_arch * sizeof(fat_arch); if ( sizeof(fat_header) + archs_size >= fsize ) return false; fat_archs.resize(fheader.nfat_arch); if ( qlread(li, fat_archs.begin(), archs_size) != archs_size ) { fat_archs.clear(); return false; } for ( uint32_t i=0; i < fheader.nfat_arch; i++ ) { fat_arch *parch = &fat_archs[i]; if ( code == 2 ) swap_fat_arch(parch); if ( parch->size <= sizeof(mach_header) || parch->size >= fsize || parch->offset < sizeof(fat_header) + archs_size || parch->offset + parch->size > fsize ) { fat_archs.clear(); return false; } } return true; }
static int register_libraries(int fd, const char* build, const char* project, const char* filename, int* isMachO) { ssize_t res; uint32_t magic; res = read(fd, &magic, sizeof(uint32_t)); if (res < sizeof(uint32_t)) { goto error_out; } if (magic == FAT_MAGIC || magic == FAT_CIGAM) { struct fat_header fh; int swap = 0; res = read(fd, &fh.nfat_arch, sizeof(struct fat_header) - sizeof(uint32_t)); if (res < sizeof(uint32_t)) { goto error_out; } if (magic == FAT_CIGAM) { swap = 1; swap_fat_header(&fh, NXHostByteOrder()); } int i; for (i = 0; i < fh.nfat_arch; ++i) { struct fat_arch fa; res = read(fd, &fa, sizeof(fa)); if (res < sizeof(fa)) { goto error_out; } if (swap) swap_fat_arch(&fa, 1, NXHostByteOrder()); off_t save = lseek(fd, 0, SEEK_CUR); lseek(fd, (off_t)fa.offset, SEEK_SET); register_mach_header(build, project, filename, &fa, fd, isMachO); lseek(fd, save, SEEK_SET); } } else { lseek(fd, 0, SEEK_SET); register_mach_header(build, project, filename, NULL, fd, isMachO); } error_out: return 0; }
/** * \fn moa_error_t moa_read_fat_section(struct s_mach_file* ptr_mach_file) * \brief Read the fat section of a mach_file (fat_header + fat_arch). * * \param ptr_mach_file Pointer to mach archive. * * \return MOA_SUCCESS if all succeed, else error number. */ moa_error_t moa_read_fat_section(struct s_mach_file* ptr_mach_file) { if (NULL == ptr_mach_file) return MOA_ERR_NULLPTR; /// Reset file offset lseek(ptr_mach_file->fd, (off_t)0, SEEK_SET); /// Read the fat header const size_t mach_header_size = sizeof(ptr_mach_file->fat_section.fat_header); if (read(ptr_mach_file->fd, &ptr_mach_file->fat_section.fat_header, mach_header_size) != (ssize_t)mach_header_size) return MOA_ERR_READ_FAT_HEADER; /// Check if the file is actually a mach archive if (!moa_is_mach_archive(ptr_mach_file)) return MOA_ERR_NOT_MACH_ARCHIVE; /// Get host machine byte order /// If intel CPU, we need to change the byte order to lil endian enum NXByteOrder host_byte_order = NXHostByteOrder(); if (NX_LittleEndian == host_byte_order) swap_fat_header(&ptr_mach_file->fat_section.fat_header, NX_LittleEndian); else if (NX_UnknownByteOrder == NXHostByteOrder()) return MOA_ERR_UNKNOW_ARCH; /// Read the N fat archs if (ptr_mach_file->fat_section.fat_archs != NULL) free(ptr_mach_file->fat_section.fat_archs); const size_t fat_arch_size = ptr_mach_file->fat_section.fat_header.nfat_arch * sizeof(*ptr_mach_file->fat_section.fat_archs); if (NULL == (ptr_mach_file->fat_section.fat_archs = (struct fat_arch*)malloc(fat_arch_size))) return MOA_ERR_READ_FAT_ARCH; if (read(ptr_mach_file->fd, ptr_mach_file->fat_section.fat_archs, fat_arch_size) != (ssize_t)fat_arch_size) return MOA_ERR_READ_FAT_ARCH; if (NX_LittleEndian == host_byte_order) swap_fat_arch(ptr_mach_file->fat_section.fat_archs, ptr_mach_file->fat_section.fat_header.nfat_arch, NX_LittleEndian); return MOA_SUCCESS; }
NXStream *NXGetStreamOnSection(const char *fileName, const char *segmentName, const char *sectionName) { int fd; struct stat info; NXStream *s = NULL; struct fat_header *fh; struct mach_header *mh; const struct section *sect; vm_offset_t mh_page, sect_page; unsigned long archOffset; unsigned int cnt = HOST_BASIC_INFO_COUNT; struct host_basic_info hbi; if (host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)(&hbi), &cnt) != KERN_SUCCESS) return NULL; fd = open(fileName, O_RDONLY, 0444); if (fd < 0 || fstat(fd, &info) < 0) return NULL; if (((info.st_mode & S_IFMT) != S_IFREG) || (info.st_size < sizeof(*fh))) { close(fd); return NULL; } if (map_fd(fd, 0, (vm_offset_t *)&fh, TRUE, (vm_size_t)info.st_size) != KERN_SUCCESS) { close(fd); return NULL; } #ifdef __BIG_ENDIAN__ if (fh->magic == FAT_MAGIC) { #endif __BIG_ENDIAN__ #ifdef __LITTLE_ENDIAN__ if (fh->magic == NXSwapLong(FAT_MAGIC)) { #endif __LITTLE_ENDIAN__ int i; struct fat_arch *fa = (struct fat_arch*)(fh + 1); #ifdef __LITTLE_ENDIAN__ enum NXByteOrder host_byte_sex = NXHostByteOrder(); swap_fat_header(fh, host_byte_sex); #endif __LITTLE_ENDIAN__ if ((fh->nfat_arch <= 0) || (info.st_size < sizeof(*fh)+sizeof(*fa)*fh->nfat_arch)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } #ifdef __LITTLE_ENDIAN__ swap_fat_arch(fa, fh->nfat_arch, host_byte_sex); #endif __LITTLE_ENDIAN__ for (i = 0; i < fh->nfat_arch; i++, fa++) { if (fa->cputype == hbi.cpu_type) { //**** ** check for best cpu_subtype here ** (fa->cpusubtype == hbi.cpu_subtype) break; // for now, accept all subtypes } } if (i >= fh->nfat_arch) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } archOffset = fa->offset; mh = (struct mach_header*)((char*)fh + archOffset); } else { archOffset = 0L; mh = (struct mach_header*)fh; } if ((info.st_size < archOffset + sizeof(*mh)) || (mh->magic != MH_MAGIC) || (mh->cputype != hbi.cpu_type) || (info.st_size < archOffset + sizeof(*mh) + mh->sizeofcmds) || !check_wellformed_header(mh, info.st_size - archOffset, NO)) { // bug#21223 vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Get the section data. */ sect = getsectbynamefromheader(mh, segmentName, sectionName); if (sect == NULL || sect->size == 0 || (info.st_size < archOffset + sect->offset + sect->size)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Create the stream. */ s = NXOpenMemory((char *)mh + sect->offset, sect->size, NX_READONLY); s->flags &= ~NX_USER_OWNS_BUF; /* * Through away the parts of the file not needed. Assert that all * pages that the file lives on are used only by the file. */ sect_page = round_page((vm_offset_t)mh + sect->offset + sect->size); mh_page = round_page((vm_offset_t)fh + info.st_size); if (mh_page - sect_page) vm_deallocate(mach_task_self(), sect_page, mh_page - sect_page); mh_page = trunc_page((vm_offset_t)fh); sect_page = trunc_page((vm_offset_t)mh + sect->offset); if (sect_page - mh_page) vm_deallocate(mach_task_self(), mh_page, sect_page - mh_page); if (close(fd) < 0) { NXCloseMemory(s, NX_FREEBUFFER); s = NULL; } return s; } NXStream *NXGetStreamOnSectionForBestArchitecture( const char *fileName, const char *segmentName, const char *sectionName) { int fd; struct stat info; NXStream *s = NULL; struct fat_header *fh; struct mach_header *mh; const struct section *sect; vm_offset_t mh_page, sect_page; unsigned long archOffset; unsigned int cnt = HOST_BASIC_INFO_COUNT; struct host_basic_info hbi; int fSwap = NO; if (host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)(&hbi), &cnt) != KERN_SUCCESS) return NULL; fd = open(fileName, O_RDONLY, 0444); if (fd < 0 || fstat(fd, &info) < 0) return NULL; if (((info.st_mode & S_IFMT) != S_IFREG) || (info.st_size < sizeof(*fh))) { close(fd); return NULL; } if (map_fd(fd, 0, (vm_offset_t *)&fh, TRUE, (vm_size_t)info.st_size) != KERN_SUCCESS) { close(fd); return NULL; } #ifdef __BIG_ENDIAN__ if (fh->magic == FAT_MAGIC) { #endif __BIG_ENDIAN__ #ifdef __LITTLE_ENDIAN__ if (fh->magic == NXSwapLong(FAT_MAGIC)) { #endif __LITTLE_ENDIAN__ int i; struct fat_arch *fa = (struct fat_arch*)(fh + 1); #ifdef __LITTLE_ENDIAN__ enum NXByteOrder host_byte_sex = NXHostByteOrder(); swap_fat_header(fh, host_byte_sex); #endif __LITTLE_ENDIAN__ if ((fh->nfat_arch <= 0) || (info.st_size < sizeof(*fh)+sizeof(*fa)*fh->nfat_arch)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } #ifdef __LITTLE_ENDIAN__ swap_fat_arch(fa, fh->nfat_arch, host_byte_sex); #endif __LITTLE_ENDIAN__ for (i = 0; i < fh->nfat_arch; i++, fa++) { if (fa->cputype == hbi.cpu_type) { //**** ** check for best cpu_subtype here ** (fa->cpusubtype == hbi.cpu_subtype) break; // for now, accept all subtypes } } if (i >= fh->nfat_arch) { /* * If do not have the correct cpu_type, just use the last type * in file. * NOTE: we could have a list passed in, and choose the best * based upon that list. */ fa--; } archOffset = fa->offset; mh = (struct mach_header*)((char*)fh + archOffset); } else { archOffset = 0L; mh = (struct mach_header*)fh; } if (info.st_size < archOffset + sizeof(*mh)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Do we need to swap the header? Header is always in byte-order of machine it * was compiled for. */ if (mh->magic == NXSwapLong(MH_MAGIC)) { fSwap = YES; #ifdef __LITTLE_ENDIAN__ swap_mach_header(mh, NX_LittleEndian); #else swap_mach_header(mh, NX_BigEndian); #endif __LITTLE_ENDIAN__ } if ((mh->magic != MH_MAGIC) || (info.st_size < archOffset + sizeof(*mh) + mh->sizeofcmds) || !check_wellformed_header(mh, info.st_size - archOffset, fSwap)) { // bug#21223 vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Get the section data. */ sect = getsectbynamefromheaderwithswap(mh, segmentName, sectionName, fSwap); if (sect == NULL || sect->size == 0 || (info.st_size < archOffset + sect->offset + sect->size)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Create the stream. */ s = NXOpenMemory((char *)mh + sect->offset, sect->size, NX_READONLY); s->flags &= ~NX_USER_OWNS_BUF; /* * Through away the parts of the file not needed. Assert that all * pages that the file lives on are used only by the file. */ sect_page = round_page((vm_offset_t)mh + sect->offset + sect->size); mh_page = round_page((vm_offset_t)fh + info.st_size); if (mh_page - sect_page) vm_deallocate(mach_task_self(), sect_page, mh_page - sect_page); mh_page = trunc_page((vm_offset_t)fh); sect_page = trunc_page((vm_offset_t)mh + sect->offset); if (sect_page - mh_page) vm_deallocate(mach_task_self(), mh_page, sect_page - mh_page); if (close(fd) < 0) { NXCloseMemory(s, NX_FREEBUFFER); s = NULL; } return s; }