Beispiel #1
0
int rdis_function_reachable (struct _rdis * rdis, uint64_t address)
{
    struct _function * function = map_fetch(rdis->functions, address);
    if (function == NULL)
        return -1;
    function->flags |= FUNCTION_REACHABLE;

    // get this function's call graph
    struct _graph * cg = create_call_graph(rdis->graph, address);
    struct _graph_it * git;
    // for each function in the graph
    for (git = graph_iterator(cg); git != NULL; git = graph_it_next(git)) {
        struct _list * ins_list = graph_it_data(git);
        struct _list_it * lit;
        // for each call in the function in the graph
        for (lit = list_iterator(ins_list); lit != NULL; lit = lit->next) {
            struct _ins * ins = lit->data;
            // insure function has correct flags
            if (    (ins->flags & (INS_TARGET_SET | INS_CALL))
                 == (INS_TARGET_SET | INS_CALL)) {

                function = map_fetch(rdis->functions, ins->target);
                if (function == NULL)
                    continue;
                function->flags |= FUNCTION_REACHABLE;
            }
        }
    }

    return 0;
}
Beispiel #2
0
int rdis_remove_function (struct _rdis * rdis, uint64_t address)
{
    map_remove(rdis->functions, address);
    map_remove(rdis->labels, address);

    struct _graph * family = graph_family(rdis->graph, address);
    if (family == NULL)
        return -1;

    struct _graph_it * it;

    for (it = graph_iterator(family); it != NULL; it = graph_it_next(it)) {
        struct _graph_node * node = graph_it_node(it);

        printf("rdis_remove_function %p %p %p %llx\n",
               node,
               node->data,
               node->edges,
               (unsigned long long) node->index);

        graph_remove_node(rdis->graph, node->index);
    }

    object_delete(family);

    rdis_callback(rdis, RDIS_CALLBACK_GRAPH
                        | RDIS_CALLBACK_FUNCTION
                        | RDIS_CALLBACK_LABEL);

    return 0;
}
Beispiel #3
0
void rdis_check_references (struct _rdis * rdis)
{
    struct _graph_it * git;
    // for each node
    for (git = graph_iterator(rdis->graph); git != NULL; git = graph_it_next(git)) {
        struct _graph_node * node = graph_it_node(git);
        struct _list_it * lit;

        // for each instruction
        for (lit = list_iterator(node->data); lit != NULL; lit = lit->next) {
            struct _ins * ins = lit->data;
            struct _list_it * rit;

            // for each reference
            for (rit = list_iterator(ins->references); rit != NULL; rit = rit->next) {
                struct _reference * reference = rit->data;

                if (reference->type == REFERENCE_CONSTANT) {
                    uint64_t lower = map_fetch_max_key(rdis->memory, reference->address);
                    struct _buffer * buffer = map_fetch(rdis->memory, lower);
                    if (buffer == NULL)
                        continue;
                    uint64_t upper = lower + buffer->size;
                    if (    (reference->address < lower)
                         || (reference->address >= upper))
                        continue;
                    reference->type = REFERENCE_CONSTANT_ADDRESSABLE;
                }
            }
        }
    }
}
Beispiel #4
0
/*
* In this pass, we are fixing the edges from jmp-like instructions and their
* targets
*/
void x8664_graph_1 (struct _graph * graph,
                    uint64_t        address)
{
    struct _graph_it * it;
    ud_t               ud_obj;

    for (it = graph_iterator(graph); it != NULL; it = graph_it_next(it)) {
        struct _list * ins_list = graph_it_data(it);
        struct _ins  * ins = list_first(ins_list);

        ud_init      (&ud_obj);
        ud_set_mode  (&ud_obj, 64);
        ud_set_input_buffer(&ud_obj, ins->bytes, ins->size);
        ud_disassemble(&ud_obj);

        struct ud_operand * operand;
        switch (ud_obj.mnemonic) {
        case UD_Ijmp  :
        case UD_Ijo   :
        case UD_Ijno  :
        case UD_Ijb   :
        case UD_Ijae  :
        case UD_Ijz   :
        case UD_Ijnz  :
        case UD_Ijbe  :
        case UD_Ija   :
        case UD_Ijs   :
        case UD_Ijns  :
        case UD_Ijp   :
        case UD_Ijnp  :
        case UD_Ijl   :
        case UD_Ijge  :
        case UD_Ijle  :
        case UD_Ijg   :
            operand = &(ud_obj.operand[0]);

            if (operand->type != UD_OP_JIMM)
                break;
            
            uint64_t head = graph_it_index(it);
            uint64_t tail = head
                             + ud_insn_len(&ud_obj)
                             + udis86_sign_extend_lval(operand);

            int type = INS_EDGE_JCC_TRUE;
            if (ud_obj.mnemonic == UD_Ijmp)
                type = INS_EDGE_JUMP;

            struct _ins_edge * ins_edge = ins_edge_create(type);
            graph_add_edge(graph, head, tail, ins_edge);
            object_delete(ins_edge);
            break;
        default :
            break;
        }
    }
}
Beispiel #5
0
struct _map * rdis_g_references (struct _rdis * rdis)
{
    struct _map * references = map_create();

    struct _graph_it * git;
    // for each node
    for (git = graph_iterator(rdis->graph); git != NULL; git = graph_it_next(git)) {
        struct _graph_node * node = graph_it_node(git);
        struct _list_it * lit;

        // for each instruction
        for (lit = list_iterator(node->data); lit != NULL; lit = lit->next) {
            struct _ins * ins = lit->data;
            struct _list_it * rit;

            // for each reference
            for (rit = list_iterator(ins->references); rit != NULL; rit = rit->next) {
                struct _reference * reference = rit->data;
                int delete_reference = 0;

                if (reference->type == REFERENCE_CONSTANT) {
                    uint64_t lower = map_fetch_max_key(rdis->memory, reference->address);
                    struct _buffer * buffer = map_fetch(rdis->memory, lower);
                    if (buffer == NULL)
                        continue;
                    uint64_t upper = lower + buffer->size;
                    if (    (reference->address < lower)
                         || (reference->address >= upper))
                        continue;
                    reference = object_copy(reference);
                    reference->type = REFERENCE_CONSTANT_ADDRESSABLE;
                    delete_reference = 1;
                }


                struct _list * ref_list = map_fetch(references, reference->address);
                if (ref_list == NULL) {
                    ref_list = list_create();
                    map_insert(references, reference->address, ref_list);
                    object_delete(ref_list);
                    ref_list = map_fetch(references, reference->address);
                }

                list_append(ref_list, reference);

                if (delete_reference)
                    object_delete(reference);
            }
        }
    }

    return references;
}
Beispiel #6
0
int rdis_function_bounds (struct _rdis * rdis, uint64_t address)
{
    struct _function * function = map_fetch(rdis->functions, address);
    
    if (function == NULL)
        return -1;

    struct _graph * family = graph_family(rdis->graph, address);

    if (family == NULL)
        return -1;

    uint64_t lower = -1;
    uint64_t upper = 0;

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

            if (ins->address < lower)
                lower = ins->address;
            if (ins->address + ins->size > upper)
                upper = ins->address + ins->size;
        }
    }

    object_delete(family);

    function->bounds.lower = lower;
    function->bounds.upper = upper;

    return 0;
}
Beispiel #7
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;
}