Beispiel #1
0
int rdis_functions_bounds (struct _rdis * rdis)
{
    struct _map_it * it;
    int result = 0;

    for (it = map_iterator(rdis->functions); it != NULL; it = map_it_next(it)) {
        struct _function * function = map_it_data(it);

        result |= rdis_function_bounds(rdis, function->address);
    }

    return result;
}
Beispiel #2
0
void rdis_callback (struct _rdis * rdis, int type_mask)
{
    struct _map_it * it;

    for (it = map_iterator(rdis->callbacks); it != NULL; it = map_it_next(it)) {
        struct _rdis_callback * rc = map_it_data(it);

        if ((rc->type_mask & type_mask) == 0)
            continue;

        fflush(stdout);

        rc->callback(rc->data);
    }
}
Beispiel #3
0
struct _map * elf32_labels_functions (struct _elf32 * elf32,
                                      struct _map * memory,
                                      struct _map * functions)
{
    struct _map * labels_map = map_create();

    struct _map_it * it;
    for (it = map_iterator(functions); it != NULL; it = map_it_next(it)) {
        struct _function * function = map_it_data(it);

        struct _label * label = elf32_label_address(elf32, memory, function->address);
        map_insert(labels_map, function->address, label);
        object_delete(label);
    }

    return labels_map;
}
Beispiel #4
0
struct _graph * elf32_graph_functions (struct _elf32 * elf32,
                                       struct _map *   memory,
                                       struct _map *   functions)
{
    struct _graph  * graph;
    struct _wqueue * wqueue;

    // disassemble from entry point
    graph = x86_graph(elf32_entry(elf32), memory);

    struct _map_it * it;

    wqueue = wqueue_create();
    for (it  = map_iterator(functions);
            it != NULL;
            it  = map_it_next(it)) {
        struct _function * function = map_it_data(it);

        struct _x86_wqueue * x86w;
        x86w = x86_wqueue_create(function->address, memory);
        wqueue_push(wqueue, WQUEUE_CALLBACK(x86_graph_wqueue), x86w);
        object_delete(x86w);
    }

    wqueue_wait(wqueue);

    while (wqueue_peek(wqueue) != NULL) {
        graph_merge(graph, wqueue_peek(wqueue));
        wqueue_pop(wqueue);
    }

    object_delete(wqueue);

    remove_function_predecessors(graph, functions);
    graph_reduce(graph);

    return graph;
}
Beispiel #5
0
struct _map * elf32_functions_wqueue (struct _elf32 * elf32,
                                      struct _map *   memory,
                                      struct _list *  entries)
{
    struct _map * functions = map_create();
    struct _wqueue * wqueue = wqueue_create();
    struct _list_it * it;
    for (it = list_iterator(entries); it != NULL; it = it->next) {
        struct _function * function = it->data;

        if (map_fetch(functions, function->address) == NULL)
            map_insert(functions, function->address, function);

        struct _x86_wqueue * x86w;
        x86w = x86_wqueue_create(function->address, memory);

        wqueue_push(wqueue, WQUEUE_CALLBACK(x86_functions_wqueue), x86w);
        object_delete(x86w);
    }

    wqueue_wait(wqueue);

    struct _map * fmap;
    while ((fmap = wqueue_peek(wqueue)) != NULL) {
        struct _map_it * mit;
        for (mit = map_iterator(fmap); mit != NULL; mit = map_it_next(mit)) {
            struct _function * function = map_it_data(mit);

            if (map_fetch(functions, function->address) == NULL)
                map_insert(functions, function->address, function);
        }
        wqueue_pop(wqueue);
    }

    object_delete(wqueue);

    return functions;
}
Beispiel #6
0
int rdis_update_memory (struct _rdis *   rdis,
                        uint64_t         address,
                        struct _buffer * buffer)
{
    if (buffer == NULL)
        return -1;

    mem_map_set (rdis->memory, address, buffer);

    // we will regraph functions whose bounds fall within this updated memory,
    // and all functions whose bounds fall within the bounds of functions to be
    // regraphed (step 2 simplifies things later on)
    struct _queue * queue = queue_create();
    struct _map_it * it;
    for (it = map_iterator(rdis->functions); it != NULL; it = map_it_next(it)) {
        struct _function * function = map_it_data(it);
        if (    (    (function->bounds.lower >= address)
                  && (function->bounds.lower <  address + buffer->size))
             || (    (function->bounds.upper >= address)
                  && (function->bounds.upper <  address + buffer->size))
             || (    (function->bounds.lower <= address)
                  && (function->bounds.upper >= address + buffer->size))) {
            queue_push(queue, function);
        }
    }

    struct _map * regraph_functions = map_create();
    while (queue->size > 0) {
        struct _function * function = queue_peek(queue);

        if (map_fetch(regraph_functions, function->address) != NULL) {
            queue_pop(queue);
            continue;
        }

        printf("adding regraph function %llx\n",
               (unsigned long long) function->address);

        map_insert(regraph_functions, function->address, function);

        for (it = map_iterator(rdis->functions); it != NULL; it = map_it_next(it)) {
            struct _function * cmp_function = map_it_data(it);

            if (    (    (cmp_function->bounds.lower >= function->bounds.lower)
                      && (cmp_function->bounds.lower <  function->bounds.upper))
                 || (    (cmp_function->bounds.upper >= function->bounds.lower)
                      && (cmp_function->bounds.upper <  function->bounds.upper))
                 || (    (cmp_function->bounds.lower <= function->bounds.lower)
                      && (cmp_function->bounds.upper >= function->bounds.upper)))
                queue_push(queue, cmp_function);
        }
    }

    // regraph dem functions
    struct _graph * new_graph;
    new_graph = loader_graph_functions(rdis->loader,
                                       rdis->memory,
                                       regraph_functions);

    // We are now going to go through all nodes in our regraph functions. We
    // will copy over comments to the new instructions and then remove the
    // regraph function nodes from the original graph
    for (it = map_iterator(regraph_functions); it != NULL; it = map_it_next(it)) {
        struct _function * function = map_it_data(it);
        struct _graph    * family   = graph_family(rdis->graph, function->address);
        if (family == NULL)
            continue;

        struct _graph_it * git;
        for (git  = graph_iterator(family);
             git != NULL;
             git  = graph_it_next(git)) {
            struct _list * ins_list = graph_it_data(git);
            struct _list_it * iit;
            for (iit = list_iterator(ins_list); iit != NULL; iit = iit->next) {
                struct _ins * ins = iit->data;

                if (ins->comment == NULL)
                    continue;

                struct _ins * new_ins = graph_fetch_ins(new_graph, ins->address);

                if (ins->size != new_ins->size)
                    continue;

                if (memcmp(ins->bytes, new_ins->bytes, ins->size) == 0) {
                    printf("copy over comment from instruction at %llx\n",
                           (unsigned long long) ins->address);
                    ins_s_comment(new_ins, ins->comment);
                }
            }
            // add node for deletion
            struct _index * index = index_create(graph_it_index(git));
            queue_push(queue, index);
            object_delete(index);
        }

        object_delete(family);

        while (queue->size > 0) {
            struct _index * index = queue_peek(queue);
            graph_remove_node(rdis->graph, index->index);
            queue_pop(queue);
        }
    }

    // merge the new graph with the old graph
    graph_merge(rdis->graph, new_graph);

    // reset bounds of these functions
    for (it = map_iterator(regraph_functions); it != NULL; it = map_it_next(it)) {
        struct _function * function = map_it_data(it);
        rdis_function_bounds(rdis, function->address);
    }

    objects_delete(queue, new_graph, regraph_functions, NULL);

    rdis_callback(rdis, RDIS_CALLBACK_ALL);

    return 0;
}
Beispiel #7
0
int rdis_user_function (struct _rdis * rdis, uint64_t address)
{
    // get a tree of all functions reachable at this address
    struct _map * functions = loader_function_address(rdis->loader,
                                                      rdis->memory,
                                                      address);

    // add in this address as a new function as well
    struct _function * function = function_create(address);
    map_insert(functions, function->address, function);
    object_delete(function);

    // for each newly reachable function
    struct _map_it * mit;
    for (mit = map_iterator(functions); mit != NULL; mit = map_it_next(mit)) {
        struct _function * function = map_it_data(mit);
        uint64_t fitaddress = function->address;

        // if we already have this function, skip it
        if (map_fetch(rdis->functions, function->address) != NULL)
            continue;

        // add this function to the rdis->function_tree
        map_insert(rdis->functions, function->address, function);

        // add label
        struct _label * label = loader_label_address(rdis->loader,
                                                     rdis->memory,
                                                     fitaddress);
        map_insert(rdis->labels, fitaddress, label);
        object_delete(label);

        // if this function is already in our graph, all we need to do is make
        // sure its a separate node and then remove function predecessors
        struct _graph_node * node = graph_fetch_node_max(rdis->graph, fitaddress);
        if (node != NULL) {

            // already a node, remove function predecessors
            if (node->index == address) {
                remove_function_predecessors(rdis->graph, rdis->functions);
                continue;
            }

            // search for instruction with given address
            struct _list    * ins_list = node->data;
            struct _list_it * it;
            for (it = list_iterator(ins_list); it != NULL; it = it->next) {
                struct _ins * ins = it->data;
                // found instruction
                if (ins->address == fitaddress) {
                    // create a new instruction list.
                    // add remaining instructions to new list while removing them from
                    // the current list
                    struct _list * new_ins_list = list_create();
                    while (1) {
                        list_append(new_ins_list, it->data);
                        it = list_remove(ins_list, it);
                        if (it == NULL)
                            break;
                    }
                    // create a new graph node for this new function
                    graph_add_node(rdis->graph, fitaddress, new_ins_list);
                    // all graph successors from old node are added to new node
                    struct _queue   * queue      = queue_create();
                    struct _list    * successors = graph_node_successors(node);
                    struct _list_it * sit;
                    for (sit = list_iterator(successors);
                         sit != NULL;
                         sit = sit->next) {
                        struct _graph_edge * edge = sit->data;
                        graph_add_edge(rdis->graph,
                                       fitaddress,
                                       edge->tail,
                                       edge->data);
                        queue_push(queue, edge);
                    }
                    object_delete(successors);

                    // and removed from old node
                    while (queue->size > 0) {
                        struct _graph_edge * edge = queue_peek(queue);
                        graph_remove_edge(rdis->graph, edge->head, edge->tail);
                        queue_pop(queue);
                    }
                    object_delete(queue);

                    // that was easy
                    break;
                }
            }
            if (it != NULL)
                continue;
        }

        // we need to create a new graph for this node
        struct _graph * graph = loader_graph_address(rdis->loader,
                                                     rdis->memory,
                                                     fitaddress);
        graph_merge(rdis->graph, graph);
        object_delete(graph);
    }

    object_delete(functions);

    rdis_callback(rdis, RDIS_CALLBACK_ALL);

    return 0;
}
Beispiel #8
0
struct _map * elf32_functions (struct _elf32 * elf32, struct _map * memory)
{
    struct _list * entries   = list_create();

    // add the entry point
    struct _function * function = function_create(elf32_entry(elf32));
    list_append(entries, function);
    object_delete(function);

    // check for __libc_start_main loader
    uint64_t target_offset = elf32_entry(elf32) - elf32_base_address(elf32) + 0x17;
    if (target_offset + 0x10 < elf32->data_size) {
        uint8_t * data = &(elf32->data[target_offset]);
        size_t    size = elf32->data_size - target_offset;

        ud_t ud_obj;
        ud_init      (&ud_obj);
        ud_set_mode  (&ud_obj, 32);
        ud_set_syntax(&ud_obj, UD_SYN_INTEL);
        ud_set_input_buffer(&ud_obj, data, size);
        ud_disassemble(&ud_obj);
        if (ud_obj.mnemonic == UD_Ipush) {
            printf("found __libc_start_main loader, main at %llx\n",
                   (unsigned long long) udis86_sign_extend_lval(&(ud_obj.operand[0])));

            // add main to function tree
            struct _function * function;
            function = function_create(udis86_sign_extend_lval(&(ud_obj.operand[0])));
            list_append(entries, function);
            object_delete(function);

        }
        else
            printf("disassembled: %s\n disassembled at %llx\n",
                   ud_insn_asm(&ud_obj),
                   (unsigned long long) target_offset);
    }

    struct _map * functions = elf32_functions_wqueue(elf32, memory, entries);

    // these are the reachable functions
    struct _map_it * mit;
    for (mit = map_iterator(functions); mit != NULL; mit = map_it_next(mit)) {
        struct _function * function = map_it_data(mit);
        function->flags |= FUNCTION_REACHABLE;
    }

    // reset entries
    object_delete(entries);
    entries = list_create();

    // symbols are easy
    int sec_i;
    for (sec_i = 0; sec_i < elf32->ehdr->e_shnum; sec_i++) {
        Elf32_Shdr * shdr = elf32_shdr(elf32, sec_i);
        if (shdr == NULL)
            break;

        if ((shdr->sh_type != SHT_SYMTAB) && (shdr->sh_type != SHT_DYNSYM))
            continue;

        int sym_i;
        for (sym_i = 0; sym_i < shdr->sh_size / shdr->sh_entsize; sym_i++) {
            Elf32_Sym * sym = elf32_section_element(elf32, sec_i, sym_i);
            if (sym == NULL)
                break;

            if (ELF32_ST_TYPE(sym->st_info) != STT_FUNC)
                continue;

            if (sym->st_value == 0)
                continue;

            struct _function * function = function_create(sym->st_value);
            list_append(entries, function);
            object_delete(function);
        }
    }

    struct _map * sym_functions = elf32_functions_wqueue(elf32, memory, entries);
    for (mit = map_iterator(sym_functions); mit != NULL; mit = map_it_next(mit)) {
        struct _function * function = map_it_data(mit);
        if (map_fetch(functions, function->address) == NULL)
            map_insert(functions, function->address, function);
    }

    object_delete(sym_functions);
    object_delete(entries);

    return functions;
}
Beispiel #9
0
struct _graph * recursive_disassemble (const struct _map * mem_map,
                                       uint64_t entry,
                struct _ins * (* ins_callback) (const struct _map *, uint64_t))
{
    struct _queue * queue = queue_create();
    struct _map * map     = map_create();

    struct _index * index = index_create(entry);
    queue_push(queue, index);
    object_delete(index);

    while (queue->size > 0) {
        struct _index * index = queue_peek(queue);

        if (map_fetch(map, index->index)) {
            queue_pop(queue);
            continue;
        }

        struct _ins * ins = ins_callback(mem_map, index->index);
        if (ins == NULL) {
            queue_pop(queue);
            continue;
        }
        map_insert(map, index->index, ins);

        struct _list_it * lit;
        for (lit = list_iterator(ins->successors); lit != NULL; lit = lit->next) {
            struct _ins_value * successor = lit->data;
            if (successor->type == INS_SUC_CALL)
                continue;
            struct _index * index = index_create(successor->address);
            queue_push(queue, index);
            object_delete(index);
        }

        queue_pop(queue);
    }

    object_delete(queue);

    // create graph nodes
    struct _graph * graph = graph_create();

    struct _map_it * mit;
    for (mit = map_iterator(map); mit != NULL; mit = map_it_next(mit)) {
        graph_add_node(graph, map_it_key(mit), map_it_data(mit));
    }

    // create graph edges
    for (mit = map_iterator(map); mit != NULL; mit = map_it_next(mit)) {
        struct _ins * ins = map_it_data(mit);
        struct _list_it * lit;
        for (lit = list_iterator(ins->successors); lit != NULL; lit = lit->next) {
            struct _ins_value * successor = lit->data;
            // don't add call edges
            if (successor->type == INS_SUC_CALL)
                continue;
            graph_add_edge(graph, ins->address, successor->address, successor);
        }
    }

    object_delete(map);

    return graph;
}