static macho_seek_result __macho_lc_is_dysymtab( struct load_command * lc_cmd, const void * file_end, uint8_t swap, void * user_data) { macho_seek_result result = macho_seek_result_not_found; _dysymtab_scan * dysym_data = (_dysymtab_scan *)user_data; uint32_t cmd; if ((void *)(lc_cmd + sizeof(struct load_command)) > file_end) { result = macho_seek_result_error; goto finish; } cmd = CondSwapInt32(swap, lc_cmd->cmd); if (cmd == LC_DYSYMTAB) { uint32_t cmd_size = CondSwapInt32(swap, lc_cmd->cmdsize); if ((cmd_size != sizeof(struct dysymtab_command)) || ((void *)(lc_cmd + sizeof(struct dysymtab_command)) > file_end)) { result = macho_seek_result_error; goto finish; } dysym_data->dysymtab = (struct dysymtab_command *)lc_cmd; result = macho_seek_result_found; goto finish; } finish: return result; }
void printKextArches( OSKextRef theKext, char lineEnd, Boolean printLineEnd) { fat_iterator fiter = NULL; struct mach_header * farch = NULL; const NXArchInfo * archinfo = NULL; Boolean printedOne = false; fiter = createFatIteratorForKext(theKext); if (!fiter) { goto finish; } while ((farch = fat_iterator_next_arch(fiter, NULL))) { int swap = ISSWAPPEDMACHO(farch->magic); archinfo = NXGetArchInfoFromCpuType(CondSwapInt32(swap, farch->cputype), CondSwapInt32(swap, farch->cpusubtype)); if (archinfo) { fprintf(stdout, "%s%s", printedOne ? "," : "", archinfo->name); printedOne = true; } } finish: if (printLineEnd && printedOne) { fprintf(stdout, "%c", lineEnd); } if (fiter) fat_iterator_close(fiter); return; }
int fat_iterator_find_fat_arch( fat_iterator iter, cpu_type_t cputype, cpu_subtype_t cpusubtype, struct fat_arch * fat_arch_out) { int result = 0; uint32_t magic; uint32_t nfat_arch; struct fat_arch * fat_arches; struct fat_arch * fat_arches_copy = NULL; // must free struct fat_arch * found_arch; magic = MAGIC32(iter->file_start); if (iter->fat_header) { uint32_t fat_arches_size; uint32_t index; nfat_arch = iter->num_arches; fat_arches_size = nfat_arch * sizeof(struct fat_arch); fat_arches_copy = (struct fat_arch *)(malloc(fat_arches_size)); if (!fat_arches_copy) { goto finish; } fat_arches = fat_arches_copy; memcpy(fat_arches, iter->fat_arches, fat_arches_size); /* NXFindBestFatArch() requires all the fat info to be in host * byte order. */ for (index = 0; index < nfat_arch; index++) { fat_arches[index].cputype = OSSwapBigToHostInt32(fat_arches[index].cputype); fat_arches[index].cpusubtype = OSSwapBigToHostInt32(fat_arches[index].cpusubtype); fat_arches[index].offset = OSSwapBigToHostInt32(fat_arches[index].offset); fat_arches[index].size = OSSwapBigToHostInt32(fat_arches[index].size); fat_arches[index].align = OSSwapBigToHostInt32(fat_arches[index].align); } } else { struct fat_arch fake_fat_arches; uint8_t swap; struct mach_header * mach_hdr; nfat_arch = 1; bzero(&fake_fat_arches, sizeof(fake_fat_arches)); fat_arches = &fake_fat_arches; swap = ISSWAPPEDMACHO(magic); mach_hdr = (struct mach_header *)iter->file_start; fat_arches[0].cputype = CondSwapInt32(swap, mach_hdr->cputype); fat_arches[0].cpusubtype = CondSwapInt32(swap, mach_hdr->cpusubtype); fat_arches[0].offset = 0; fat_arches[0].size = iter->file_end - iter->file_start; fat_arches[0].align = 1; // not used anyhow } found_arch = NXFindBestFatArch(cputype, cpusubtype, fat_arches, nfat_arch); if (found_arch) { result = 1; if (fat_arch_out) { memcpy(fat_arch_out, found_arch, sizeof(*fat_arch_out)); } } finish: if (fat_arches_copy) { free(fat_arches_copy); } return result; }
macho_seek_result macho_scan_load_commands( const void * file_start, const void * file_end, macho_lc_callback lc_callback, void * user_data) { macho_seek_result result = macho_seek_result_not_found; struct mach_header * mach_header = (struct mach_header *)file_start; uint8_t swap = 0; uint32_t cmdsize_mult = CMDSIZE_MULT_32; uint32_t num_cmds; uint32_t sizeofcmds; char * cmds_end; uint32_t cmd_index; struct load_command * load_commands; struct load_command * seek_lc; switch (MAGIC32(file_start)) { case MH_MAGIC_64: cmdsize_mult = CMDSIZE_MULT_64; break; case MH_CIGAM_64: cmdsize_mult = CMDSIZE_MULT_64; swap = 1; break; case MH_CIGAM: swap = 1; break; case MH_MAGIC: break; default: result = macho_seek_result_error; goto finish; break; } if (cmdsize_mult == CMDSIZE_MULT_64) { load_commands = (struct load_command *) (file_start + sizeof(struct mach_header_64)); } else { load_commands = (struct load_command *) (file_start + sizeof(struct mach_header)); } if (file_start >= file_end || (((void *)load_commands) > file_end)) { result = macho_seek_result_error; goto finish; } num_cmds = CondSwapInt32(swap, mach_header->ncmds); sizeofcmds = CondSwapInt32(swap, mach_header->sizeofcmds); cmds_end = (char *)load_commands + sizeofcmds; if (cmds_end > (char *)file_end) { result = macho_seek_result_error; goto finish; } seek_lc = load_commands; for (cmd_index = 0; cmd_index < num_cmds; cmd_index++) { uint32_t cmd_size; char * lc_end; cmd_size = CondSwapInt32(swap, seek_lc->cmdsize); lc_end = (char *)seek_lc + cmd_size; if ((cmd_size % cmdsize_mult != 0) || (lc_end > cmds_end)) { result = macho_seek_result_error; goto finish; } result = lc_callback(seek_lc, file_end, swap, user_data); switch (result) { case macho_seek_result_not_found: /* Not found, keep scanning. */ break; case macho_seek_result_stop: /* Definitely found that it isn't there. */ result = macho_seek_result_not_found; goto finish; break; case macho_seek_result_found: /* Found it! */ goto finish; break; default: /* Error, fall through default case. */ result = macho_seek_result_error; goto finish; break; } seek_lc = (struct load_command *)((char *)seek_lc + cmd_size); } finish: return result; }
macho_seek_result macho_find_symbol( const void * file_start, const void * file_end, const char * name, uint8_t * nlist_type, const void ** symbol_address) { macho_seek_result result = macho_seek_result_not_found; macho_seek_result symtab_result = macho_seek_result_not_found; uint8_t swap = 0; char sixtyfourbit = 0; struct symtab_command * symtab = NULL; struct nlist * syms_address; struct nlist_64 * syms_address_64; const void * string_list; char * symbol_name; unsigned int symtab_offset; unsigned int str_offset; unsigned int num_syms; unsigned int syms_bytes; unsigned int sym_index; if (symbol_address) { *symbol_address = 0; } symtab_result = macho_find_symtab(file_start, file_end, &symtab); if (symtab_result != macho_seek_result_found) { goto finish; } if (ISSWAPPEDMACHO(MAGIC32(file_start))) { swap = 1; } if (ISMACHO64(MAGIC32(file_start))) { sixtyfourbit = 1; } symtab_offset = CondSwapInt32(swap, symtab->symoff); str_offset = CondSwapInt32(swap, symtab->stroff); num_syms = CondSwapInt32(swap, symtab->nsyms); syms_address = (struct nlist *)(file_start + symtab_offset); syms_address_64 = (struct nlist_64 *)(file_start + symtab_offset); string_list = file_start + str_offset; if (sixtyfourbit) { syms_bytes = num_syms * sizeof(struct nlist_64); } else { syms_bytes = num_syms * sizeof(struct nlist); } if ((char *)syms_address + syms_bytes > (char *)file_end) { result = macho_seek_result_error; goto finish; } for (sym_index = 0; sym_index < num_syms; sym_index++) { struct nlist * seekptr; struct nlist_64 * seekptr_64; uint32_t string_index; uint8_t n_type; uint8_t n_sect; uint64_t n_value; if (sixtyfourbit) { seekptr_64 = &syms_address_64[sym_index]; string_index = CondSwapInt32(swap, seekptr_64->n_un.n_strx); n_type = seekptr_64->n_type; n_sect = seekptr_64->n_sect; n_value = CondSwapInt64(swap, seekptr_64->n_value); } else { seekptr = &syms_address[sym_index]; string_index = CondSwapInt32(swap, seekptr->n_un.n_strx); n_type = seekptr->n_type; n_sect = seekptr->n_sect; n_value = (uint64_t)CondSwapInt32(swap, seekptr->n_value); } if (string_index == 0 || n_type & N_STAB) { continue; } symbol_name = (char *)(string_list + string_index); if (strcmp(name, symbol_name) == 0) { if (nlist_type) { *nlist_type = n_type; } switch (n_type & N_TYPE) { case N_SECT: { void * v_sect_info = macho_find_section_numbered( file_start, file_end, n_sect); if (!v_sect_info) { break; // out of the switch } if (symbol_address) { if (sixtyfourbit) { struct section_64 * sect_info_64 = (struct section_64 *)v_sect_info; // this isn't right for 64bit? compare below size_t reloffset = (n_value - CondSwapInt64(swap, sect_info_64->addr)); *symbol_address = file_start; *symbol_address += CondSwapInt32(swap, sect_info_64->offset); *symbol_address += reloffset; } else { struct section * sect_info = (struct section *)v_sect_info; size_t reloffset = (n_value - CondSwapInt32(swap, sect_info->addr)); *symbol_address = file_start; *symbol_address += CondSwapInt32(swap, sect_info->offset); *symbol_address += reloffset; } } result = macho_seek_result_found; goto finish; } break; case N_UNDF: result = macho_seek_result_found_no_value; goto finish; break; case N_ABS: result = macho_seek_result_found_no_value; goto finish; break; /* We don't chase indirect symbols as they can be external. */ case N_INDR: result = macho_seek_result_found_no_value; goto finish; break; default: goto finish; break; } } } finish: return result; }
static macho_seek_result __macho_sect_in_lc( struct load_command * lc_cmd, const void * file_end, uint8_t swap, void * user_data) { macho_seek_result result = macho_seek_result_not_found; _sect_scan * sect_data = (_sect_scan *)user_data; uint32_t cmd; if (sect_data->sect_counter > sect_data->sect_num) { result = macho_seek_result_stop; goto finish; } if ((void *)(lc_cmd + sizeof(struct load_command)) > file_end) { result = macho_seek_result_error; goto finish; } cmd = CondSwapInt32(swap, lc_cmd->cmd); if (cmd == LC_SEGMENT_64) { struct segment_command_64 * seg_cmd = (struct segment_command_64 *)lc_cmd; uint32_t cmd_size; uint32_t num_sects; uint32_t sects_size; struct section_64 * seek_sect; uint32_t sect_index; cmd_size = CondSwapInt32(swap, seg_cmd->cmdsize); num_sects = CondSwapInt32(swap, seg_cmd->nsects); sects_size = num_sects * sizeof(*seek_sect); if (cmd_size != (sizeof(*seg_cmd) + sects_size)) { result = macho_seek_result_error; goto finish; } if (((void *)lc_cmd + cmd_size) > file_end) { result = macho_seek_result_error; goto finish; } for (sect_index = 0; sect_index < num_sects; sect_index++) { seek_sect = (struct section_64 *)((void *)lc_cmd + sizeof(*seg_cmd) + (sect_index * sizeof(*seek_sect))); sect_data->sect_counter++; if (sect_data->sect_counter == sect_data->sect_num) { sect_data->sect_info = seek_sect; result = macho_seek_result_found; goto finish; } } } else if (cmd == LC_SEGMENT) { struct segment_command * seg_cmd = (struct segment_command *)lc_cmd; uint32_t cmd_size; uint32_t num_sects; uint32_t sects_size; struct section * seek_sect; uint32_t sect_index; cmd_size = CondSwapInt32(swap, seg_cmd->cmdsize); num_sects = CondSwapInt32(swap, seg_cmd->nsects); sects_size = num_sects * sizeof(*seek_sect); if (cmd_size != (sizeof(*seg_cmd) + sects_size)) { result = macho_seek_result_error; goto finish; } if (((void *)lc_cmd + cmd_size) > file_end) { result = macho_seek_result_error; goto finish; } for (sect_index = 0; sect_index < num_sects; sect_index++) { seek_sect = (struct section *)((void *)lc_cmd + sizeof(*seg_cmd) + (sect_index * sizeof(*seek_sect))); sect_data->sect_counter++; if (sect_data->sect_counter == sect_data->sect_num) { sect_data->sect_info = seek_sect; result = macho_seek_result_found; goto finish; } } } finish: return result; }