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