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; }
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; }
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; } } } } }
/* * 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; } } }
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; }
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; }
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; }