Esempio n. 1
0
void test(void)
{
    gadget_t gadgets;
    gadget_init(&gadgets);
    gadget_add(&gadgets, (unsigned char*)TEST_INSTRS, TEST_INSTRS_LEN, 0);
    gadget_print(&gadgets);
    gadget_destroy(&gadgets);
}
Esempio n. 2
0
// Work backwards from an instruction to find the instructions that come before it.
// gadgets - the gadget_t for the instruction that comes next.
// buffer - the buffer of program code.
// offset - the virtual memory address that buffer starts at.
// position - the index into buffer of the previously-located instruction.
// count - the number of instructions to find (recursively).
void
work_backwards(gadget_t *gadgets, unsigned char *buffer, uint32_t offset, int position, int count)
{
    if (count <= 0) {
        return;
    }

    int instr_start;
    int instr_size, instr_actual_size;
    x86_insn_t instr;

    // Work back from the known instruction one byte at a time.
    for (instr_size = 1; instr_size <= MAX_INSTRUCTION_BYTES; instr_size++) {
        // Disassemble the bytes between our position and the first byte of the
        // known instruction.
        instr_start = position - instr_size;
        if (instr_start < 0)
            break;
        instr_actual_size = x86_disasm(buffer + instr_start, instr_size, 0, 0, &instr);

        /* 
         * If *all* of those bytes make up one instruction, and it's not
         * a return (gadgets should not contain a RET other than at the end),
         * add it to the tree.
         */
        if (instr_actual_size == instr_size &&
                !(instr_size == 1 && *(buffer + instr_start) == RET)) {

            // If we've already seen this sequence of instructions...
            gadget_t *g;
            if ((g = gadget_list_find_instr(&gadgets->previous, buffer + instr_start, instr_actual_size)) != NULL) {
                // ...see if the address of this one is better.
                if (has_zero_byte(g->virtual_address)) {
                    g->virtual_address = offset + instr_start;
                }
                continue;
            }

            // Otherwise, add it to the list.
            gadget_t *newgadget = malloc(sizeof(gadget_t));
            gadget_init(newgadget);
            memcpy(newgadget->instr, buffer + instr_start, instr_actual_size);
            newgadget->instr_len = instr_size;
            newgadget->virtual_address = offset + instr_start;
            // The next instruction (in execution order) is the one this one
            // comes before.
            newgadget->next = gadgets;
            // The instruction we just found is previous (in execution order) to
            // the one we already know about.
            gadget_list_add(&gadgets->previous, newgadget);

            work_backwards(newgadget, buffer, offset, instr_start, count - 1);
        }
    }

}
Esempio n. 3
0
int main(int argc, char **argv)
{
    if (argc != 2) {
        print_usage();
        return 1;
    }

    if (strcmp(argv[1], "demo") == 0) {
        test();
        return 0;
    }


    /* Code below adapted from 'libelf by Example' */
    Elf *e;
    GElf_Phdr phdr;
    int fd;
    size_t n, i;

    if (elf_version(EV_CURRENT) == EV_NONE) {
        printf("Error with elf library [%s]\n", elf_errmsg(-1));
        exit(1);
    }

    if ((fd = open(argv[1], O_RDONLY, 0)) < 0) {
        printf("Error reading file.\n");
        exit(1);
    }

    if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
        printf("elf_begin() failed [%s]\n", elf_errmsg(-1));
        exit(1);
    }

    if (elf_kind(e) != ELF_K_ELF) {
        printf("File is not an ELF object.\n");
        exit(1);
    }

    if (elf_getphdrnum(e, &n) != 0) {
        printf("elf_getphdrnum() failed [%s]\n", elf_errmsg(-1));
        exit(1);
    }

    /* Initialize libdis */
    x86_init(opt_none, NULL, NULL);

    gadget_t gadgets;
    gadget_init(&gadgets);

    /* Loop over each program header (segment) */
    for (i = 0; i < n; i++) {
        if (gelf_getphdr(e, i, &phdr) != &phdr) {
            printf("gelf_getphdr() failed [%s]\n", elf_errmsg(-1));
            exit(1);
        }

        /* If the segment is loaded into memory AND is executable */
        if (phdr.p_type == PT_LOAD && phdr.p_flags & PF_X) {
            /* Load the segment from the ELF file */
            unsigned char *buffer = malloc(phdr.p_filesz);
            lseek(fd, phdr.p_offset, SEEK_SET);
            ssize_t count = read(fd, buffer, phdr.p_filesz);
            if (count != phdr.p_filesz) {
                printf("read sucks.\n"); // FIXME: EINTR etc.
                exit(1);
            }
            /* Add all gadgets in the segment to our gadget tree */
            gadget_add(&gadgets, buffer, phdr.p_filesz, phdr.p_vaddr);
            free(buffer);
        }
    }

    elf_end(e);
    close(fd);

    gadget_print(&gadgets);
    gadget_destroy(&gadgets);

    return 0;
}
Esempio n. 4
0
// find valid instructions offsets before ret
int _ropit_x86_find_gadgets (uint8_t *bytes, int len, int64_t *rets, int n_rets) {
    int sz_inst;                /* size of instruction */
    x86_insn_t insn;         /* instruction */
    int idx_ret, sz_ret;
    int valid_gadget;
    // back track instruction count
    int n_backtrack_inst, n_backtrack_bytes;
    // start for rop search
    uint8_t *start, *gadget_start;
    // disassemble
    int len_disasm;
    int sz_dst;
    char disassembled[DISASSEMBLED_SIZE_MAX] = {0};
    // cache
    FILE *fp_cache;
    struct cache_t *caches;
    int idx_caches, n_caches;
    struct gadget_t *gadgets;
    int idx_gadgets, n_gadgets;
    // cache queue
    struct gadget_cache_queue_t *cache_queue;
    // count
    int count_gadgets;

    // check params
    if (!bytes || len <= 0) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Bytes null or len <= 0\n");
        return NULL;
    }

    // search rets
    if (!rets || n_rets <= 0) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): No rets\n");
        return NULL;
    }

    // init gadget_cache
    fp_cache = fopen("tmp/gadget_cache", "w");
    if (!fp_cache) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed open (w)\n");
        return NULL;
    }

    // init cache_queue
    cache_queue = NULL;
    if (!gadget_cache_queue_init(&cache_queue)) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Cache queue allocation failed\n");
        return NULL;
    }
    gadget_cache_queue_set_file (cache_queue, fp_cache);

    // init gadgets
    n_gadgets = 1024;
    gadgets = calloc(sizeof(struct gadget_t), n_gadgets);
    if (!gadgets) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed allocating caches\n");
        return NULL;
    }

    for (idx_gadgets = 0; idx_gadgets < n_gadgets; idx_gadgets++)
        gadget_init(&(gadgets[idx_gadgets]), DISASSEMBLED_SIZE_MAX);

    // init caches
    n_caches = 1;
    caches = calloc(sizeof(struct cache_t), n_caches);
    if (!caches) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed allocating caches\n");
        return NULL;
    }

    for (idx_caches = 0; idx_caches < n_caches; idx_caches++) {
        cache_init(&(caches[idx_caches]), 1024);
    }

    // init disasm
    x86_init(opt_none, NULL, NULL);

    idx_caches = 0;
    idx_gadgets = 0;
    count_gadgets = 0;
    for (idx_ret = 0; idx_ret < n_rets; idx_ret++) {
        start = bytes + rets[idx_ret];

        n_backtrack_inst = 0;
        n_backtrack_bytes = 0;
        while ( bytes <= start && start <= bytes + len ) {
            /* disassemble address */
            sz_inst = x86_disasm(start, len - (start - bytes), 0, 0, &insn);
            x86_oplist_free(&insn);

            if (sz_inst <= 0) {
                // printf("not found inst\n");
                n_backtrack_bytes++;
            }
            else {
                // printf("found inst\n");
                n_backtrack_bytes = 0;

                valid_gadget = 0;
                //
                gadget_start = start;
                if (gadget_start == bytes + rets[idx_ret])
                    valid_gadget = 1;
                else {
                    n_backtrack_inst = 0;
                    // check gadget validity
                    while (bytes <= gadget_start && gadget_start <= bytes + rets[idx_ret]) {
                        /* disassemble address */
                        sz_inst = x86_disasm(gadget_start, gadget_start - bytes, 0, 0, &insn);
                        x86_oplist_free(&insn);
                        if (sz_inst <= 0)
                            break;
                        else {
                            n_backtrack_inst++;
                            gadget_start += sz_inst;
                            if (gadget_start == bytes + rets[idx_ret]) {
                                valid_gadget = 1;
                                break;
                            }
                        }
                    }
                }

                if (valid_gadget == 1) {
                    //
                    ++count_gadgets;

                    // get ret size
                    sz_ret = x86_disasm(bytes + rets[idx_ret], 10, 0, 0, &insn);
                    x86_oplist_free(&insn);

                    // fill gadget structure
                    gadgets[idx_gadgets].ret_addr = rets[idx_ret];
                    gadgets[idx_gadgets].ret_bytes = rets[idx_ret] + bytes;
                    gadgets[idx_gadgets].address = start - bytes;
                    gadgets[idx_gadgets].len_bytes = (rets[idx_ret] - (start - bytes)) + sz_ret;
                    if (gadgets[idx_gadgets].sz_bytes < gadgets[idx_gadgets].len_bytes) {
                        gadgets[idx_gadgets].bytes = realloc (gadgets[idx_gadgets].bytes, gadgets[idx_gadgets].len_bytes);
                        gadgets[idx_gadgets].sz_bytes = gadgets[idx_gadgets].len_bytes;
                    }
                    memcpy(gadgets[idx_gadgets].bytes, start, gadgets[idx_gadgets].len_bytes);

                    if (cache_add (&(caches[idx_caches]), &(gadgets[idx_gadgets])) == -ERR_CACHE_FULL) {
                        gadget_cache_queue_add (cache_queue, &(caches[idx_caches]));
                        gadget_cache_queue_fwrite_worker (cache_queue);
                        cache_reset (&(caches[idx_caches]));
                    }

                    idx_gadgets = (idx_gadgets + 1) % n_gadgets;
                }
            }
            --start;

            // maximum intel instruction size is 15
            // maximum instructions in a gadget is hardcoded to 8 here
            /* TODO : Get more gadgets with n_backtrack_inst instructions
             * Effectively, we stop at the first gadget which has
             * n_backtrack_inst instructions while there might be multiple
             * possibilities.
             */
            if (n_backtrack_bytes >= 15 || n_backtrack_inst == 8)
                break;
        }
    }
    x86_cleanup();

    // write remaining gadgets
    gadget_cache_queue_add (cache_queue, &(caches[idx_caches]));
    gadget_cache_queue_fwrite_worker (cache_queue);
    cache_reset (&(caches[idx_caches]));

    // clean up
    for (idx_caches = 0; idx_caches < n_caches; idx_caches++)
        free(caches[idx_caches].objects);
    free(caches);

    for (idx_gadgets = 0; idx_gadgets < n_gadgets; idx_gadgets++) {
        // gadget_free(&(gadgets[idx_gadgets]));
        // free (gadgets[idx_gadgets].repr);
        free (gadgets[idx_gadgets].bytes);
    }
    free(gadgets);

    gadget_cache_queue_destroy (&cache_queue);

    fclose (fp_cache);

    return count_gadgets;
}