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;
}
Exemple #3
0
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;
}