Exemple #1
0
static int __fat_iterator_init(
    struct __fat_iterator * iter,
    const void * file_data,
    const void * file_end,
    int macho_only)
{
    int      result = -1;
    size_t   length = file_end - file_data;
    uint32_t magic;

    if (length < sizeof(magic)) {
        goto finish;
    }

    iter->file_start = (void *)file_data;
    iter->file_end   = (void *)file_end;

    magic = MAGIC32(file_data);

    if (ISFAT(magic)) {
        void * arches_end;

        if (length < sizeof(struct fat_header)) {
            goto finish;
        }

        iter->fat_header = (struct fat_header *)file_data;
        iter->fat_arches = (struct fat_arch *)((char *)iter->fat_header +
                                               sizeof(struct fat_header));
        iter->num_arches = OSSwapBigToHostInt32(
                               iter->fat_header->nfat_arch);
        arches_end = (void *)iter->fat_arches +
                     (iter->num_arches * sizeof(struct fat_arch));

        if (arches_end > iter->file_end) {

            goto finish;
        }

        iter->iterable = 1;

    } else if (ISMACHO(magic)) {

        if (length < sizeof(struct mach_header)) {
            goto finish;
        }

        iter->iterable = 1;
        iter->num_arches = 1;
        iter->arch_index = 0;

    } else if (macho_only) {
        goto finish;
    }

    result = 0;

finish:
    return result;
}
void * macho_find_section_numbered(
    const void * file_start,
    const void * file_end,
    uint8_t      sect_num)
{
    _sect_scan sect_data;

    bzero(&sect_data, sizeof(sect_data));

    sect_data.sect_num = sect_num;

    if (ISMACHO64(MAGIC32(file_start))) {
        sect_data.sixtyfourbit = 1;
    }

    if (macho_seek_result_found == macho_scan_load_commands(
        file_start, file_end, &__macho_sect_in_lc, &sect_data)) {

        return sect_data.sect_info;
    }

    return NULL;
}
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;
}
Exemple #6
0
ExitStatus printKextInfo(KctoolArgs * toolArgs)
{
    ExitStatus result         = EX_SOFTWARE;
    CFArrayRef kextPlistArray = NULL;
    CFIndex    i, count;
    
    if (CFArrayGetTypeID() == CFGetTypeID(toolArgs->kernelcacheInfoPlist)) {
        kextPlistArray = (CFArrayRef)toolArgs->kernelcacheInfoPlist;
    } else if (CFDictionaryGetTypeID() == CFGetTypeID(toolArgs->kernelcacheInfoPlist)){
        kextPlistArray = (CFArrayRef)CFDictionaryGetValue(toolArgs->kernelcacheInfoPlist,
            CFSTR("_PrelinkInfoDictionary"));
    } else {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Unrecognized kernelcache plist data.");
        goto finish;
    }
    
    count = CFArrayGetCount(kextPlistArray);
    for (i = 0; i < count; i++) {
        CFDictionaryRef kextInfoDict = (CFDictionaryRef)CFArrayGetValueAtIndex(kextPlistArray, i);
        CFStringRef     thisKextID = CFDictionaryGetValue(kextInfoDict, kCFBundleIdentifierKey);
        
        if (thisKextID && CFEqual(thisKextID, toolArgs->kextID)) {
            uint64_t      kextAddr   = 0;
            uint64_t      kextSize   = 0;
            u_long        kextOffset = 0;
            const UInt8 * kextMachO  = NULL;  // do not free
            void        * section    = NULL;  // do not free

            if (!getKextAddressAndSize(kextInfoDict, &kextAddr, &kextSize)) {
                goto finish;
            }

            if (ISMACHO64(MAGIC32(toolArgs->kernelcacheImageBytes))) {
                section = (void *)macho_get_section_by_name_64(
                    (struct mach_header_64 *)toolArgs->kernelcacheImageBytes,
                    kPrelinkTextSegment, kPrelinkTextSection);

            } else {
                section = (void *)macho_get_section_by_name(
                    (struct mach_header *)toolArgs->kernelcacheImageBytes,
                    kPrelinkTextSegment, kPrelinkTextSection);
            }

            if (!section) {
                OSKextLog(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                    "Cannot find %s,%s in kernelcache.",
                    kPrelinkTextSegment, kPrelinkTextSection);
                goto finish;
            }

            if (ISMACHO64(MAGIC32(toolArgs->kernelcacheImageBytes))) {
                kextOffset = ((struct section_64 *)section)->offset + (u_long)(kextAddr - ((struct section_64 *)section)->addr);
            } else {
                kextOffset = ((struct section *)section)->offset + (u_long)(kextAddr - ((struct section *)section)->addr);
            }
            kextMachO = toolArgs->kernelcacheImageBytes + kextOffset;

            /* Find the requested section's file offset and size */

            if (ISMACHO64(MAGIC32(toolArgs->kernelcacheImageBytes))) {
                section = (void *)macho_get_section_by_name_64(
                    (struct mach_header_64 *)kextMachO,
                    toolArgs->segmentName, toolArgs->sectionName);

            } else {
               /* macho_get_section_by_name doesn't work as the kexts don't have a __TEXT segment.
                * They just have a single segment named "" with all the sections dumped under it.
                */
                section = (void *)getSectionByName(
                    kextMachO,
                    toolArgs->segmentName, toolArgs->sectionName);
            }

            if (!section) {
                OSKextLogCFString(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                    CFSTR("Cannot find %s,%s in kext %@\n"),
                    toolArgs->segmentName, toolArgs->sectionName, toolArgs->kextID);
                goto finish;
            }

            if (ISMACHO64(MAGIC32(toolArgs->kernelcacheImageBytes))) {
                printf("%#llx %#lx %#llx\n",
                    ((struct section_64 *)section)->addr,
                    kextOffset + ((struct section_64 *)section)->offset,
                    ((struct section_64 *)section)->size);
            } else {
                printf("%#x %#lx %#x\n",
                    ((struct section *)section)->addr,
                    kextOffset + ((struct section *)section)->offset,
                    ((struct section *)section)->size);
            }

            result = EX_OK;
            break;
        }
    }

finish:
    return result;
}
Exemple #7
0
int main(int argc, char * const argv[])
{
    ExitStatus           result             = EX_SOFTWARE;
    KctoolArgs           toolArgs;
    int                  kernelcache_fd     = -1;  // must close()
    void               * fat_header         = NULL;  // must unmapFatHeaderPage()
    struct fat_arch    * fat_arch           = NULL;
    CFDataRef            rawKernelcache     = NULL;  // must release
    CFDataRef            kernelcacheImage   = NULL;  // must release

    void               * prelinkInfoSect    = NULL;

    const char         * prelinkInfoBytes   = NULL;
    CFPropertyListRef    prelinkInfoPlist   = NULL;  // must release

    bzero(&toolArgs, sizeof(toolArgs));

   /*****
    * Find out what the program was invoked as.
    */
    progname = rindex(argv[0], '/');
    if (progname) {
        progname++;   // go past the '/'
    } else {
        progname = (char *)argv[0];
    }

   /* Set the OSKext log callback right away.
    */
    OSKextSetLogOutputFunction(&tool_log);

   /*****
    * Process args & check for permission to load.
    */
    result = readArgs(&argc, &argv, &toolArgs);
    if (result != EX_OK) {
        if (result == kKctoolExitHelp) {
            result = EX_OK;
        }
        goto finish;
    }

    kernelcache_fd = open(toolArgs.kernelcachePath, O_RDONLY);
    if (kernelcache_fd == -1) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't open %s: %s.", toolArgs.kernelcachePath, strerror(errno));
        result = EX_OSERR;
        goto finish;
    }
    fat_header = mapAndSwapFatHeaderPage(kernelcache_fd);
    if (!fat_header) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't map %s: %s.", toolArgs.kernelcachePath, strerror(errno));
        result = EX_OSERR;
        goto finish;
    }
    
    fat_arch = getFirstFatArch(fat_header);
    if (fat_arch && !toolArgs.archInfo) {
        toolArgs.archInfo = NXGetArchInfoFromCpuType(fat_arch->cputype, fat_arch->cpusubtype);
    }
    
    rawKernelcache = readMachOSliceForArch(toolArgs.kernelcachePath, toolArgs.archInfo,
        /* checkArch */ FALSE);
    if (!rawKernelcache) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't read arch %s from %s.", toolArgs.archInfo->name, toolArgs.kernelcachePath);
        goto finish;
    }

    if (MAGIC32(CFDataGetBytePtr(rawKernelcache)) == OSSwapHostToBigInt32('comp')) {
        kernelcacheImage = uncompressPrelinkedSlice(rawKernelcache);
        if (!kernelcacheImage) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                "Can't uncompress kernelcache slice.");
            goto finish;
        }
    } else {
        kernelcacheImage = CFRetain(rawKernelcache);
    }

    toolArgs.kernelcacheImageBytes = CFDataGetBytePtr(kernelcacheImage);
    
    if (ISMACHO64(MAGIC32(toolArgs.kernelcacheImageBytes))) {
        prelinkInfoSect = (void *)macho_get_section_by_name_64(
            (struct mach_header_64 *)toolArgs.kernelcacheImageBytes,
            "__PRELINK_INFO", "__info");

    } else {
        prelinkInfoSect = (void *)macho_get_section_by_name(
            (struct mach_header *)toolArgs.kernelcacheImageBytes,
            "__PRELINK_INFO", "__info");
    }

    if (!prelinkInfoSect) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't find prelink info section.");
        goto finish;
    }

    if (ISMACHO64(MAGIC32(toolArgs.kernelcacheImageBytes))) {
        prelinkInfoBytes = ((char *)toolArgs.kernelcacheImageBytes) +
            ((struct section_64 *)prelinkInfoSect)->offset;
    } else {
        prelinkInfoBytes = ((char *)toolArgs.kernelcacheImageBytes) +
            ((struct section *)prelinkInfoSect)->offset;
    }

    toolArgs.kernelcacheInfoPlist = (CFPropertyListRef)IOCFUnserialize(prelinkInfoBytes,
        kCFAllocatorDefault, /* options */ 0, /* errorString */ NULL);
    if (!toolArgs.kernelcacheInfoPlist) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't unserialize prelink info.");
        goto finish;
    }

    result = printKextInfo(&toolArgs);
    if (result != EX_OK) {
        goto finish;
    }

    result = EX_OK;

finish:

    SAFE_RELEASE(toolArgs.kernelcacheInfoPlist);
    SAFE_RELEASE(kernelcacheImage);
    SAFE_RELEASE(rawKernelcache);

    if (fat_header) {
        unmapFatHeaderPage(fat_header);
    }

    if (kernelcache_fd != -1) {
        close(kernelcache_fd);
    }
    return result;
}