totem3
1/16/2018 - 11:52 PM

foo.c

#include <stdio.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include "osfmk/mach/machine.h"
#include "EXTERNAL_HEADERS/mach-o/loader.h"
#include <string.h>
#include <assert.h>

int main()
{
    unsigned int code_bytes = 640 * 1024;
    uint8_t* mem = (uint8_t*) mmap(
            NULL,
            code_bytes,
            PROT_READ | PROT_WRITE | PROT_EXEC,
            MAP_ANONYMOUS | MAP_PRIVATE,
            0,
            0);
    uint64_t offset = 0;
    uint64_t data_offset = 0;
    uint64_t ncmds = 0;
    uint64_t vmaddr = 0x0000000100000000;
    uint64_t vmsize = 0x0000000000001000;

    struct mach_header_64 *header = (struct mach_header_64*)mem;
    header->magic = MH_MAGIC_64;
    header->cputype = (CPU_ARCH_ABI64 | CPU_TYPE_X86);
    header->cpusubtype = CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_X86_64_ALL;
    header->ncmds = 0;
    header->sizeofcmds = 0;
    header->filetype = MH_EXECUTE;
    header->flags = MH_PIE | MH_TWOLEVEL | MH_PRELOAD;

    offset += sizeof(struct mach_header_64);

    printf("sizeof segment %lu\n", sizeof(struct segment_command_64));
    printf("sizeof section %lu\n", sizeof(struct section_64));
    printf("offset %llu\n", offset);
    struct segment_command_64 *zero = (struct segment_command_64*)(mem + offset);
    zero->cmd = LC_SEGMENT_64;
    zero->cmdsize = sizeof(struct segment_command_64);
    zero->vmsize = vmaddr;
    strcpy(zero->segname, SEG_PAGEZERO);
    offset += sizeof(struct segment_command_64);
    ncmds += 1;

    printf("offset %llu\n", offset);
    struct segment_command_64 *text = (struct segment_command_64*)(mem + offset);
    text->cmd = LC_SEGMENT_64;
    text->cmdsize = sizeof(struct segment_command_64);
    strncpy(text->segname, SEG_TEXT, 16);
    text->vmaddr = vmaddr;
    text->vmsize = vmsize;
    text->fileoff = 0;
    text->filesize = 4096;
    text->maxprot = 0x7;
    text->initprot = 0x5;
    uint32_t nsects = 0;
    text->nsects = nsects;
    text->flags = 0;

    offset += sizeof(struct segment_command_64);
    ncmds += 1;

    // section 0
    /* uint8_t prg[] = {0x48,0xc7,0xc0,0x00,0x00,0x00,0x00,0xc3}; */
    // 0x0000000100000fc8
    uint8_t prg[] = {
        0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x02,
        0x48, 0xc7, 0xc7, 0x01, 0x00, 0x00, 0x00,
        0x48, 0x8d, 0x35, 0x19, 0x00, 0x00, 0x00,
        0x48, 0xc7, 0xc2, 0x0d, 0x00, 0x00, 0x00,
        0x0f, 0x05,
        0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x02,
        0x48, 0xc7, 0xc7, 0x00, 0x00, 0x00, 0x00,
        0x0f, 0x05,
        0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0x00,
    };


    size_t prgsize = sizeof(prg);

    printf("offset %llu\n", offset);
    struct section_64 *text_sect = (struct section_64*)(mem + offset);
    strncpy(text_sect->sectname, SECT_TEXT, 16);
    strncpy(text_sect->segname, SEG_TEXT, 16);
    text_sect->addr = 0; //vmaddr + offset
    text_sect->size = prgsize;
    text_sect->offset = 0;
    text_sect->align = 0;
    text_sect->flags = 0x80000400;

    offset += sizeof(struct section_64);
    data_offset += text_sect->size;
    nsects += 1;

    text->nsects = nsects;
    text->cmdsize += (sizeof(struct section_64) * nsects);
    printf("text->nsects %d\n", text->nsects);
    printf("sizeof segment %lu\n", sizeof(struct segment_command_64));
    printf("sizeof section %lu\n", sizeof(struct section_64));
    printf("text->cmdsize %d\n", text->cmdsize);

    printf("offset %llu\n", offset);
    struct segment_command_64 *seg_data = (struct segment_command_64*)(mem + offset);
    seg_data->cmd = LC_SEGMENT_64;
    seg_data->cmdsize = sizeof(struct segment_command_64);
    strncpy(seg_data->segname, SEG_DATA, 16);
    seg_data->vmaddr = vmaddr+0x1000;
    seg_data->vmsize = vmsize;
    seg_data->fileoff = 0x1000;
    seg_data->filesize = 4096;
    seg_data->maxprot = 0x7;
    seg_data->initprot = 0x3;
    uint32_t ndata_sects = 1;
    seg_data->nsects = ndata_sects;
    seg_data->cmdsize = sizeof(struct segment_command_64) + sizeof(struct section_64);
    seg_data->flags = 0;

    offset += sizeof(struct segment_command_64);
    ncmds += 1;

    printf("offset %llu\n", offset);
    struct section_64 *cstr_sect = (struct section_64*)(mem + offset);
    strncpy(cstr_sect->sectname, "__cstring", 16);
    strncpy(cstr_sect->segname, SEG_DATA, 16);
    cstr_sect->addr = vmaddr + 0x1000; //vmaddr + offset
    cstr_sect->size = 0x10;
    cstr_sect->offset = 0x1000;
    cstr_sect->align = 1;
    cstr_sect->flags = 0x80000400;

    offset += sizeof(struct section_64);
    memcpy(mem+0x1000, "hello, world!\n", 0x10);

    printf("linkedit offset %llu\n", offset);
    struct segment_command_64 *linkedit = (struct segment_command_64*)(mem+offset);
    linkedit->cmd = LC_SEGMENT_64;
    linkedit->cmdsize = sizeof(struct segment_command_64);
    strncpy(linkedit->segname, SEG_LINKEDIT, 16);
    linkedit->vmaddr = 0; // vmdadr + offset
    linkedit->vmsize = 4096;
    linkedit->fileoff = 4096;
    linkedit->filesize = 152;
    linkedit->maxprot = 7;
    linkedit->initprot = 1;

    offset += sizeof(struct segment_command_64);
    data_offset += 152;
    ncmds += 1;

    struct dyld_info_command *dyld_info_only = (struct dyld_info_command*)(mem+offset);
    dyld_info_only->cmd = LC_DYLD_INFO_ONLY;
    dyld_info_only->cmdsize = sizeof(struct dyld_info_command);
    dyld_info_only->export_off = 0x2000;
    dyld_info_only->export_size = 0x30;

    offset += sizeof(struct dyld_info_command);
    ncmds += 1;

    struct symtab_command *symtab = (struct symtab_command*)(mem + offset);
    symtab->cmd = LC_SYMTAB;
    symtab->cmdsize = sizeof(struct symtab_command);
    symtab->symoff = 0x2030; // 0x1038
    symtab->nsyms = 0;
    symtab->stroff = 0x2030; // 0x1068
    symtab->strsize = 0;

    offset += sizeof(struct symtab_command);
    ncmds += 1;

    struct dysymtab_command *dysymtab = (struct dysymtab_command*)(mem + offset);
    dysymtab->cmd = LC_DYSYMTAB;
    dysymtab->cmdsize = sizeof(struct dysymtab_command);
    dysymtab->nextdefsym = 0;
    dysymtab->iundefsym = 0;
    dysymtab->nundefsym = 0;

    offset += sizeof(struct dysymtab_command);
    ncmds += 1;

    struct dylinker_command* dylinker = (struct dylinker_command*)(mem + offset);
    dylinker->cmd = LC_LOAD_DYLINKER;
    dylinker->cmdsize = sizeof(struct dylinker_command) + 20;
    union lc_str name = {0x0c};
    dylinker->name = name;
    offset += sizeof(struct dylinker_command);
    strncpy((char*)(mem+offset), "/usr/lib/dyld", 20);

    offset += 20;
    ncmds += 1;

    struct entry_point_command *entry = (struct entry_point_command*)(mem + offset);
    entry->cmd = LC_MAIN;
    entry->cmdsize = sizeof(struct entry_point_command);
    entry->entryoff = 4016;
    entry->stacksize = 0;

    offset += sizeof(struct entry_point_command);
    ncmds += 1;

    struct dylib_command *dylib = (struct dylib_command*)(mem + offset);
    dylib->cmd = LC_LOAD_DYLIB;
    dylib->cmdsize = 56;// sizeof(struct dylib_command) + 0;
    union lc_str libname = {24};
    struct dylib lib = {
        .name = libname,
        .timestamp = 2,
        .current_version = 81148930,
        .compatibility_version = 65536
    };
    dylib->dylib = lib;

    offset += sizeof(struct dylib_command);

    strncpy((char*)mem+offset, "/usr/lib/libSystem.B.dylib", 32);

    offset += 32;
    ncmds += 1;

    header->ncmds = ncmds;
    header->sizeofcmds = offset - sizeof(struct mach_header_64);
    /* assert(header->sizeofcmds == 728); */

    printf("offset %llx\n", offset);
    if (offset < 0xfb0) {
        offset += (0xfb0 - offset);
    }
    printf("offset %llx\n", offset);
    printf("header %lx\n", sizeof(struct mach_header_64));

    text_sect->addr = vmaddr + offset;
    text_sect->offset = offset;

    memcpy((mem+offset), prg, sizeof(prg));
    offset += text_sect->size;

    linkedit->fileoff = 0x2000; //offset;
    linkedit->vmaddr = vmaddr + linkedit->fileoff;


    char* filename = "foo";
    FILE *fp = fopen(filename, "wb");
    fwrite(mem, 1, code_bytes, fp);
    fclose(fp);
    chmod(filename, 0777);
    return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include "osfmk/mach/machine.h"
#include "EXTERNAL_HEADERS/mach-o/loader.h"
#include <string.h>

int main()
{
    unsigned int code_bytes = 8192;
    uint8_t* mem = (uint8_t*) mmap(
            NULL,
            code_bytes,
            PROT_READ | PROT_WRITE | PROT_EXEC,
            MAP_ANONYMOUS | MAP_PRIVATE,
            0,
            0);
    uint64_t offset = 0;
    uint64_t data_offset = 0;
    uint64_t ncmds = 0;
    uint64_t vmaddr = 0x0000000100000000;
    uint64_t vmsize = 0x0000000000001000;

    struct mach_header_64 *header = (struct mach_header_64*)mem;
    header->magic = MH_MAGIC_64;
    header->cputype = (CPU_ARCH_ABI64 | CPU_TYPE_X86);
    header->cpusubtype = CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_X86_64_ALL;
    header->ncmds = 0;
    header->sizeofcmds = 0;
    header->filetype = MH_EXECUTE;
    header->flags = MH_PIE | MH_TWOLEVEL | MH_PRELOAD;

    offset += sizeof(struct mach_header_64);

    struct segment_command_64 *zero = (struct segment_command_64*)(mem + offset);
    zero->cmd = LC_SEGMENT_64;
    zero->cmdsize = sizeof(struct segment_command_64);
    zero->vmsize = vmaddr;
    strcpy(zero->segname, SEG_PAGEZERO);
    offset += sizeof(struct segment_command_64);
    ncmds += 1;

    struct segment_command_64 *text = (struct segment_command_64*)(mem + offset);
    text->cmd = LC_SEGMENT_64;
    text->cmdsize = sizeof(struct segment_command_64);
    strncpy(text->segname, SEG_TEXT, 16);
    text->vmaddr = vmaddr;
    text->vmsize = vmsize;
    text->fileoff = 0;
    text->filesize = 4096;
    text->maxprot = 0x7;
    text->initprot = 0x5;
    uint32_t nsects = 0;
    text->nsects = nsects;
    text->flags = 0;

    offset += sizeof(struct segment_command_64);
    ncmds += 1;

    uint8_t prg[] = {
        0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x02,
        0x48, 0xc7, 0xc7, 0x01, 0x00, 0x00, 0x00,
        0x48, 0x8d, 0x35, 0x19, 0x00, 0x00, 0x00,
        0x48, 0xc7, 0xc2, 0x0d, 0x00, 0x00, 0x00,
        0x0f, 0x05,
        0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x02,
        0x48, 0xc7, 0xc7, 0x00, 0x00, 0x00, 0x00,
        0x0f, 0x05,
        0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0x00,
    };


    size_t prgsize = sizeof(prg);

    struct section_64 *text_sect = (struct section_64*)(mem + offset);
    strncpy(text_sect->sectname, SECT_TEXT, 16);
    strncpy(text_sect->segname, SEG_TEXT, 16);
    text_sect->addr = 0;
    text_sect->size = prgsize;
    text_sect->offset = 0;
    text_sect->align = 0;
    text_sect->flags = 0x80000400;

    offset += sizeof(struct section_64);
    data_offset += text_sect->size;
    nsects += 1;

    text->nsects = nsects;
    text->cmdsize += (sizeof(struct section_64) * nsects);

    uint8_t entry[] = {
        0x05, 0x00, 0x00, 0x00,
        0xb8, 0x00, 0x00, 0x00,
        0x04, 0x00, 0x00, 0x00,
        0x2a, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xb0, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    };
    memcpy(mem + offset, entry, 184);

    offset += 184;
    ncmds += 1;

    header->ncmds = ncmds;
    header->sizeofcmds = offset - sizeof(struct mach_header_64);
    if (offset < 0xfb0) {
        offset += (0xfb0 - offset);
    }

    text_sect->addr = vmaddr + offset;
    text_sect->offset = offset;

    memcpy((mem+offset), prg, sizeof(prg));
    offset += text_sect->size;

    char* filename = "foo";
    FILE *fp = fopen(filename, "wb");
    fwrite(mem, 1, code_bytes, fp);
    fclose(fp);
    chmod(filename, 0777);
    return 0;
}