view mach-o-loader/loader.c @ 2:747f68297ba5 default tip

add c language mach-O loader program. this program only analize, can't still load now.
author taiki <taiki@cr.ie.u-ryukyu.ac.jp>
date Tue, 04 Mar 2014 14:41:35 +0900
parents
children
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#include <sys/stat.h>
#include <sys/mman.h>

#include <mach-o/loader.h>
#include "loader.h"

#define MAX_COMMAND_LEN 10000
#define MAX_SECTION_LEN 10000

int analyze(char* head)
{
    struct mach_header_64 *mh64 = (struct mach_header_64 *)head;

    // mach header is 32 bytes
    int com_index = sizeof(struct mach_header_64); 

    for (int cmds = 0; cmds < mh64->ncmds; cmds++) {

        struct load_command *com = (struct load_command *) (head + com_index);

        switch(com->cmd) {
            case LC_SEGMENT_64:
            {
                struct segment_command_64 *sc = 
                    (struct segment_command_64 *) (head + com_index);
                com_index += sizeof(struct segment_command_64);

                printf("segment command:\n");
                printf("\tcmd :%0xd \n", sc->cmd);
                printf("\tcmdsize :%d \n", sc->cmdsize);
                printf("\tsegname :%s \n", sc->segname);
                printf("\tvmaddr :%0llx \n", sc->vmaddr);
                printf("\tnsects :%d \n", sc->nsects);

                int nsects = sc->nsects;
                printf("sections:\n");
                for (int sects = 0; sects < nsects; sects++) {
                    struct section_64 *sc64 = (struct section_64*) (head + com_index);
                    printf("\t%s\n", sc64->sectname);
                    com_index += sizeof(struct section_64); 
                }
                break;
            }
            case LC_UUID:
            {
                struct uuid_command *uc = 
                    (struct uuid_command*) (head + com_index);
                com_index += sizeof(struct uuid_command);

                printf("uuid command\n");
                for(int i = 0; i < 16; i++) {
                    printf("%u", uc->uuid[i]);
                }
                printf("\n");
                break;
            }
            case LC_SYMTAB:
            {
                struct symtab_command *syt = 
                    (struct symtab_command*) (head + com_index);
                com_index += sizeof(struct symtab_command);

                printf("symtab_command\n");
                printf("\tsymoff %d\n", syt->symoff);
                printf("\tnsyms %d\n", syt->nsyms);
                break;
            }
            case LC_DYSYMTAB:
            {
                struct dysymtab_command *dysyt = 
                    (struct dysymtab_command*) (head + com_index);
                com_index += sizeof(struct dysymtab_command);

                printf("dysymtab_command\n");
                printf("symtab_command\n");
                printf("\tsymoff %d\n", dysyt->cmd);
                printf("\tnsyms %d\n", dysyt->cmdsize);
                break;
            }
            case LC_THREAD:
            {
                printf("thread\n");
                break;
            }
            case LC_UNIXTHREAD:
            {
                printf("unix thread\n");
                break;
            }
            case LC_ID_DYLIB:
            {
                printf("unix thread\n");
                break;
            }
            case LC_PREBOUND_DYLIB:
            {
                printf("unix thread\n");
                break;
            }
            case LC_LOAD_DYLINKER:
            {
                struct dylinker_command *dylc = (struct dylinker_command *) (head + com_index);
                printf("load dylinker\n");
                printf("\tcmdsize: %d\n", dylc->cmdsize);
                printf("\tdylc->name.offset: %d\n", dylc->name.offset);
                char *name = (head + com_index) + sizeof(struct dylinker_command);
                printf("\tname: %s\n", name);
                com_index = com_index + dylc->cmdsize;
                break;
            }
            case LC_ID_DYLINKER:
            {
                printf("id dylinker\n");
                break;
            }
            case LC_ROUTINES:
            {
                printf("routines\n");
                break;
            }
            case LC_ROUTINES_64:
            {
                printf("iroutines 64\n");
                break;
            }
            case LC_TWOLEVEL_HINTS:
            {
                printf("two level hints\n");
                break;
            }
            case LC_SUB_FRAMEWORK:
            {
                printf("sub framework\n");
                break;
            }
            case LC_SUB_UMBRELLA:
            {
                printf("sub umbrella\n");
                break;
            }
            case LC_SUB_LIBRARY:
            {
                printf("sub library\n");
                break;
            }
            case LC_SUB_CLIENT:
            {

                printf("sub client\n");
                break;
            }
            case LC_DYLD_INFO_ONLY:
            {
                struct dyld_info_command *dyldi_com = (struct dyld_info_command *) (head + com_index);
                com_index += sizeof(struct dyld_info_command);
                printf("dyld info only\n");
                printf("\tcmdsize: %d\n", dyldi_com->cmdsize);
                break;
            }
            case LC_VERSION_MIN_MACOSX:
            {
                struct version_min_command *vm_com = (struct version_min_command *) (head +  com_index);
                com_index += sizeof(struct version_min_command); 
                printf("version min macosx\n");
                break;
            }
            case LC_SOURCE_VERSION:
            {
                struct source_version_command *sv_com = (struct source_version_command *) (head + com_index);
                com_index += sizeof(struct source_version_command);
                printf("source version\n");
                break;
            }
            case LC_DATA_IN_CODE:
            {
                struct linkedit_data_command *ld_com = (struct linkedit_data_command*) (head + com_index);
                com_index += sizeof(struct linkedit_data_command);
                printf("data in code\n");
                break;
            }
            case LC_DYLIB_CODE_SIGN_DRS:
            {
                printf("cylib code sign drs\n");
                break;
            }
            case LC_LOAD_DYLIB:
            {
                struct dylib_command *dl_com = (struct dylib_command *) (head + com_index);
                printf("lc load dylib\n");
                int offset = dl_com->dylib.name.offset;
                printf("\tname offset: %d\n",offset);
                char *name = (head + com_index) + sizeof(struct dylib_command);
                printf("\tname: %s\n", name);
                com_index = com_index + dl_com->cmdsize;
                break;
            }
            case LC_MAIN:
            {
                struct entry_point_command *ep_com = (struct entry_point_command *) (head + com_index);
                com_index += sizeof(struct entry_point_command); 
                printf("lc main\n");
                break;
            }
            case LC_FUNCTION_STARTS:
            {
                struct linkedit_data_command *ld_com = (struct linkedit_data_command*) (head + com_index);
                com_index += sizeof(struct linkedit_data_command);
                printf("lc functions starts\n");
                break;
            }
            default:
                printf("no suitable cmd:%d\n", com->cmd);
                break;
        }
    }
    
    return 0;
}

int check_header(int fp, struct stat sb, char* head)
{
    struct mach_header_64 *mh64 = (struct mach_header_64 *)head;
    if (MH_MAGIC_64 != mh64->magic) {
        fprintf(stderr, "This is no mach header 64.\n");
        return -1;
    }

    if (MH_EXECUTE != mh64->filetype) {
        fprintf(stderr, "This isn't executable file.\n");
        return -1;
    }

    if (CPU_TYPE_X86_64 != mh64->cputype) {
        fprintf(stderr, "No suitable cpu type.\n");
        return -1;
    }

    printf("numbler of load commands : %d\n", mh64->ncmds);
    printf("size of cmds : %d\n", mh64->sizeofcmds);

    return 0;
} 

int main(int argc, char *argv[])
{
    
    char *filename = argv[1];
    int fp = 0;
    
    if ((fp = open(filename, O_RDONLY)) < 0) {
        fprintf(stderr, "can not open file\t: %s\n", filename);
        return -1;
    }

    struct stat sb;
    if (fstat(fp, &sb) < 0) {
        fprintf(stderr, "can not get stat\t: %s\n", filename);
        return -1;
    }

    char *head = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fp, 0);
    if ((int)head < 0) {
        fprintf(stderr, "can't map memory.\n"); 
        return -1;
    }

    if (check_header(fp, sb, head) < 0) {
        return -1;
    }

    analyze(head);

    close(fp); /* close file */

    return 0;
}