diff --git a/Hex-Rays Plugin contest release/HexRaysCodeXplorer v1.0.pdf b/Hex-Rays Plugin contest/2013/HexRaysCodeXplorer v1.0.pdf similarity index 100% rename from Hex-Rays Plugin contest release/HexRaysCodeXplorer v1.0.pdf rename to Hex-Rays Plugin contest/2013/HexRaysCodeXplorer v1.0.pdf diff --git a/Hex-Rays Plugin contest release/HexRaysCodeXplorer.plw b/Hex-Rays Plugin contest/2013/HexRaysCodeXplorer.plw similarity index 100% rename from Hex-Rays Plugin contest release/HexRaysCodeXplorer.plw rename to Hex-Rays Plugin contest/2013/HexRaysCodeXplorer.plw diff --git a/beta-test/Beta1_21-07-2013/HexRaysCodeXplorer.plw b/beta-test/Beta1_21-07-2013/HexRaysCodeXplorer.plw deleted file mode 100644 index 869ba40..0000000 Binary files a/beta-test/Beta1_21-07-2013/HexRaysCodeXplorer.plw and /dev/null differ diff --git a/beta-test/Beta2_02-09-2013/HexRaysCodeXplorer.plw b/beta-test/Beta2_02-09-2013/HexRaysCodeXplorer.plw deleted file mode 100644 index 5f1bdf6..0000000 Binary files a/beta-test/Beta2_02-09-2013/HexRaysCodeXplorer.plw and /dev/null differ diff --git a/sources/HexRaysCodeXplorer.sln b/sources/HexRaysCodeXplorer.sln new file mode 100644 index 0000000..375b23b --- /dev/null +++ b/sources/HexRaysCodeXplorer.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HexRaysCodeXplorer", "HexRaysCodeXplorer\HexRaysCodeXplorer.vcxproj", "{F7E6B557-41F3-444A-BCA4-3527547DD665}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|Win32.ActiveCfg = Debug|Win32 + {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|Win32.Build.0 = Debug|Win32 + {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|Win32.ActiveCfg = Release|Win32 + {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + VisualSVNWorkingCopyRoot = . + EndGlobalSection +EndGlobal diff --git a/sources/HexRaysCodeXplorer.suo b/sources/HexRaysCodeXplorer.suo new file mode 100644 index 0000000..04be78e Binary files /dev/null and b/sources/HexRaysCodeXplorer.suo differ diff --git a/sources/HexRaysCodeXplorer/CodeXplorer.cpp b/sources/HexRaysCodeXplorer/CodeXplorer.cpp new file mode 100644 index 0000000..775478d --- /dev/null +++ b/sources/HexRaysCodeXplorer/CodeXplorer.cpp @@ -0,0 +1,375 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + . +*/ + + +#include "Common.h" +#include "GraphBuilder.h" +#include "ObjectExplorer.h" +#include "ObjectType.h" + + +// Hex-Rays API pointer +hexdsp_t *hexdsp = NULL; + +static bool inited = false; + +// Hotkey for the new command +static const char hotkey_dg[] = "G"; +static ushort hotcode_dg; + +static const char hotkey_ce[] = "E"; +static ushort hotcode_ce; + +static const char hotkey_rt[] = "R"; +static ushort hotcode_rt; + + + +//-------------------------------------------------------------------------- +// Helper class to build graph from ctree. +struct graph_builder_t : public ctree_parentee_t +{ + callgraph_t &cg; + std::map reverse; // Reverse mapping for tests and adding edges + + graph_builder_t(callgraph_t &_cg) : cg(_cg) {} + + // overriding functions + int add_node(citem_t *i); + int process(citem_t *i); + + // We treat expressions and statements the same way: add them to the graph + int idaapi visit_insn(cinsn_t *i) { return process(i); } + int idaapi visit_expr(cexpr_t *e) { return process(e); } +}; + +// Add a new node to the graph +int graph_builder_t::add_node(citem_t *i) +{ + // Check if the item has already been encountered during the traversal + if ( reverse.find(i) != reverse.end() ) + { + warning("bad ctree - duplicate nodes!"); + return -1; + } + + // Add a node to the graph + int n = cg.add(i); + + // Also remember the reverse mapping (citem_t* -> n) + reverse[i] = n; + + return n; +} + +// Process a ctree item +int graph_builder_t::process(citem_t *item) +{ + // Add a node for citem + int n = add_node(item); + if ( n == -1 ) + return -1; // error + + if ( parents.size() > 1 ) // The current item has a parent? + { + int p = reverse[parents.back()]; // Parent node number + // cg.add_edge(p, n); // Add edge from the parent to the current item + cg.create_edge(p, n); + } + + return 0; +} + +#define DECLARE_GI_VAR \ + graph_info_t *gi = (graph_info_t *) ud + +#define DECLARE_GI_VARS \ + DECLARE_GI_VAR; \ + callgraph_t *fg = &gi->fg + +//-------------------------------------------------------------------------- +static int idaapi gr_callback(void *ud, int code, va_list va) +{ + bool result = false; + switch ( code ) + { + // refresh user-defined graph nodes and edges + case grcode_user_refresh: + // in: mutable_graph_t *g + // out: success + { + DECLARE_GI_VARS; + func_t *f = get_func(gi->func_ea); + if (f == NULL) + break; + + graph_builder_t gb(*fg); // Graph builder helper class + //fg->walk_func(f); + gb.apply_to(&gi->vu->cfunc->body, NULL); + + mutable_graph_t *mg = va_arg(va, mutable_graph_t *); + + // we have to resize + mg->resize(fg->count()); + + callgraph_t::edge_iterator end = fg->end_edges(); + for ( callgraph_t::edge_iterator it=fg->begin_edges(); + it != end; + ++it ) + { + mg->add_edge(it->id1, it->id2, NULL); + } + + fg->clear_edges(); + result = true; + } + break; + + // retrieve text for user-defined graph node + case grcode_user_text: + //mutable_graph_t *g + // int node + // const char **result + // bgcolor_t *bg_color (maybe NULL) + // out: must return 0, result must be filled + // NB: do not use anything calling GDI! + { + DECLARE_GI_VARS; + va_arg(va, mutable_graph_t *); + int node = va_arg(va, int); + const char **text = va_arg(va, const char **); + bgcolor_t *bgcolor = va_arg(va, bgcolor_t *); + + callgraph_t::nodeinfo_t *ni = fg->get_info(node); + result = ni != NULL; + if ( result ) + { + *text = ni->name.c_str(); + if ( bgcolor != NULL ) + *bgcolor = ni->color; + } + } + break; + } + return (int)result; +} + + +static bool idaapi display_graph(void *ud) +{ + vdui_t &vu = *(vdui_t *)ud; + + // Determine the ctree item to highlight + vu.get_current_item(USE_KEYBOARD); + citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; + + graph_info_t *gi = graph_info_t::create(vu.cfunc->entry_ea, highlight); + + netnode id; + id.create(); + + // get function name + qstring title = gi->title;//"Funcion ctree graph"; + + HWND hwnd = NULL; + TForm *form = create_tform(title.c_str(), &hwnd); + + gi->vu = (vdui_t *)ud; + gi->form = form; + gi->gv = create_graph_viewer(form, id, gr_callback, gi, 0); + open_tform(form, FORM_TAB | FORM_MENU | FORM_QWIDGET); + viewer_fit_window(gi->gv); + + return true; +} + +// Get poinyter to func_t by routine name +func_t * get_func_by_name(const char *func_name) +{ + func_t * result_func = NULL; + size_t func_total = get_func_qty(); + if(func_total > 0) + { + char tmp[1024]; + for (unsigned int i = 0 ; i < func_total - 1 ; i ++) + { + func_t * func = getn_func(i); + if(func != NULL) + { + memset(tmp, 0x00, sizeof(tmp)); + char *func_n = get_func_name(func->startEA, tmp, sizeof(tmp)); + if(func_n != NULL) + { + if(!strcmp(func_name, func_n)) + { + result_func = func; + break; + } + } + } + } + } + return result_func; +} + +static bool idaapi decompile_func(vdui_t &vu) +{ + // Determine the ctree item to highlight + vu.get_current_item(USE_KEYBOARD); + citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; + + if(highlight != NULL) + { + // if it is an expression + if(highlight->is_expr()) + { + cexpr_t *e = (cexpr_t *)highlight; + + // retireve the name of the routine + char tmp[1024]; + memset(tmp, 0x00, sizeof(tmp)); + e->print1(tmp, sizeof(tmp), NULL); + tag_remove(tmp, tmp, sizeof(tmp)); + + char *proc_name = tmp + strlen(tmp); + + while((proc_name > tmp) && (*(proc_name - 1) != '>')) + proc_name --; + + func_t * func = get_func_by_name(proc_name); + if(func != NULL) + { + vdui_t * decompiled_window = open_pseudocode(func->startEA, -1); + } + } + } + + return true; +} + +//display Class Explorer +static bool idaapi display_objects(void *ud) +{ + vdui_t &vu = *(vdui_t *)ud; + search_vtbl(); + custom_form_init(); + + return true; +} + +//-------------------------------------------------------------------------- +// This callback handles various hexrays events. +static int idaapi callback(void *, hexrays_event_t event, va_list va) +{ + switch ( event ) + { + case hxe_right_click: + { + vdui_t &vu = *va_arg(va, vdui_t *); + // add new command to the popup menu + add_custom_viewer_popup_item(vu.ct, "Display Graph", hotkey_dg, display_graph, &vu); + add_custom_viewer_popup_item(vu.ct, "Object Explorer", hotkey_ce, display_objects, &vu); + add_custom_viewer_popup_item(vu.ct, "REconstruct Type", hotkey_rt, reconstruct_type, &vu); + } + break; + + case hxe_keyboard: + { + vdui_t &vu = *va_arg(va, vdui_t *); + int keycode = va_arg(va, int); + int shift = va_arg(va, int); + // check for the hotkey + if ( lookup_key_code(keycode, shift, true) == hotcode_dg && shift == 0 ) + return display_graph(&vu); + if ( lookup_key_code(keycode, shift, true) == hotcode_dg && shift == 0 ) + return display_objects(&vu); + if ( lookup_key_code(keycode, shift, true) == hotcode_rt && shift == 0 ) + return reconstruct_type(&vu); + } + break; + case hxe_double_click: + { + vdui_t &vu = *va_arg(va, vdui_t *); + decompile_func(vu); + } + break; + default: + break; + } + return 0; +} + +//-------------------------------------------------------------------------- +// Initialize the plugin. +int idaapi init(void) +{ + if ( !init_hexrays_plugin() ) + return PLUGIN_SKIP; // no decompiler + install_hexrays_callback(callback, NULL); + const char *hxver = get_hexrays_version(); + msg("Hex-rays version %s has been detected, %s ready to use\n", hxver, PLUGIN.wanted_name); + inited = true; + hotcode_dg = get_key_code(hotkey_dg); // convert the hotkey to binary form + hotcode_rt = get_key_code(hotkey_rt); // convert the hotkey to binary form + + return PLUGIN_KEEP; +} + +//-------------------------------------------------------------------------- +void idaapi term(void) +{ + if ( inited ) + { + remove_hexrays_callback(callback, NULL); + term_hexrays_plugin(); + } +} + +//-------------------------------------------------------------------------- +void idaapi run(int) +{ + // This function won't be called because our plugin is invisible (no menu + // item in the Edit, Plugins menu) because of PLUGIN_HIDE +} + +//-------------------------------------------------------------------------- +static char comment[] = "HexRaysCodeXplorer plugin"; + +//-------------------------------------------------------------------------- +// +// PLUGIN DESCRIPTION BLOCK +// +//-------------------------------------------------------------------------- +plugin_t PLUGIN = +{ + IDP_INTERFACE_VERSION, + PLUGIN_HIDE, // plugin flags + init, // initialize + term, // terminate. this pointer may be NULL. + run, // invoke plugin + comment, // long comment about the plugin + // it could appear in the status line or as a hint + "", // multiline help about the plugin + "HexRaysCodeXplorer", // the preferred short name of the plugin + "" // the preferred hotkey to run the plugin +}; diff --git a/sources/HexRaysCodeXplorer/Common.h b/sources/HexRaysCodeXplorer/Common.h new file mode 100644 index 0000000..ab95dcf --- /dev/null +++ b/sources/HexRaysCodeXplorer/Common.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +#pragma warning (disable: 4996 4800 ) + +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/GraphBuilder..cpp b/sources/HexRaysCodeXplorer/GraphBuilder..cpp new file mode 100644 index 0000000..8134b6b --- /dev/null +++ b/sources/HexRaysCodeXplorer/GraphBuilder..cpp @@ -0,0 +1,253 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + . +*/ + + +#pragma warning(disable: 4800 4018) + +#include + +#include +#include + +#include + +#include "GraphBuilder.h" + +bool callgraph_t::visited(citem_t *i, int *nid) +{ + ea_int_map_t::const_iterator it = ea2node.find(i); + if ( it != ea2node.end() ) + { + if ( nid != NULL ) + *nid = it->second; + return true; + } + return false; +} + + +void callgraph_t::create_edge(int id1, int id2) +{ + edges.push_back(edge_t(id1, id2)); +} + +char * callgraph_t::get_node_label(int n, char *buf, int bufsize) const +{ + int_ea_map_t::const_iterator it = node2ea.find(n); + + if ( it != node2ea.end() ) + { + const citem_t *item = it->second; + + char *ptr = buf; + char *endp = buf + bufsize; + + // Each node will have the element type at the first line + APPEND(ptr, endp, get_ctype_name(item->op)); + const cexpr_t *e = (const cexpr_t *)item; + const cinsn_t *i = (const cinsn_t *)item; + + // For some item types, display additional information + switch ( item->op ) + { + case cot_ptr : // *x + case cot_memptr : // x->m + // Display access size for pointers + ptr += qsnprintf(ptr, endp-ptr, ".%d", e->ptrsize); + if ( item->op == cot_ptr ) + break; + case cot_memref : // x.m + // Display member offset for structure fields + ptr += qsnprintf(ptr, endp-ptr, " (m=%d)", e->m); + break; + case cot_obj : // v + case cot_var : // l + // Display object size for local variables and global data + ptr += qsnprintf(ptr, endp-ptr, ".%d", e->refwidth); + case cot_num : // n + case cot_helper : // arbitrary name + case cot_str : // string constant + // Display helper names and number values + APPCHAR(ptr, endp, ' '); + e->print1(ptr, endp-ptr, NULL); + tag_remove(ptr, ptr, 0); + ptr = tail(ptr); + break; + case cit_goto: + // Display target label number for gotos + ptr += qsnprintf(ptr, endp-ptr, " LABEL_%d", i->cgoto->label_num); + break; + case cit_asm: + // Display instruction block address and size for asm-statements + ptr += qsnprintf(ptr, endp-ptr, " %a.%"FMT_Z, *i->casm->begin(), i->casm->size()); + break; + default: + break; + } + + // The second line of the node contains the item address + ptr += qsnprintf(ptr, endp-ptr, "\nea: %a", item->ea); + if ( item->is_expr() && !e->type.empty() ) + { + // For typed expressions, the third line will have + // the expression type in human readable form + APPCHAR(ptr, endp, '\n'); + if ( print_type_to_one_line(ptr, endp-ptr, idati, e->type.u_str()) != T_NORMAL ) + { // could not print the type? + APPCHAR(ptr, endp, '?'); + APPZERO(ptr, endp); + } + + if(e->type.is_ptr()) + { + typestring ptr_rem = remove_pointer(e->type); + if(ptr_rem.is_struct()) + { + qstring typenm; + + print_type_to_qstring(&typenm, "prefix ", 0,0, PRTYPE_MULTI | PRTYPE_TYPE | PRTYPE_SEMI, idati, ptr_rem.u_str()); + + // print_type_to_one_line(ptr, endp-ptr, idati, ptr_rem.u_str()); + } + } + } + } + + return buf; +} + +callgraph_t::nodeinfo_t *callgraph_t::get_info(int nid) +{ + nodeinfo_t *ret = NULL; + + do + { + // returned cached name + int_funcinfo_map_t::iterator it = cached_funcs.find(nid); + if ( it != cached_funcs.end() ) + { + ret = &it->second; + break; + } + + // node does not exist? + int_ea_map_t::const_iterator it_ea = node2ea.find(nid); + if ( it_ea == node2ea.end() ) + break; + + citem_t *pfn = it_ea->second; + if ( pfn == NULL ) + break; + + nodeinfo_t fi; + + // get name + char buf[MAXSTR]; + if(get_node_label(nid, buf, MAXSTR)) + fi.name = buf; + else + fi.name = "?"; + + // get color + if(pfn == highlighted) + fi.color = 2000; + else + fi.color = 1;//bgcolors.prolog_color;//calc_bg_color(pfn->startEA); + + //fi.ea = pfn->startEA; + fi.ea = 0; + + it = cached_funcs.insert(cached_funcs.end(), std::make_pair(nid, fi)); + ret = &it->second; + } while ( false ); + + return ret; +} + +//-------------------------------------------------------------------------- + +int callgraph_t::add(citem_t *i) +{ + // check if we are trying to add existing node + ea_int_map_t::const_iterator it = ea2node.find(i); + if ( it != ea2node.end() ) + return it->second; + + ea2node[i] = node_count; + node2ea[node_count] = i; + + int ret_val = node_count; + node_count ++; + return ret_val; +} + +//-------------------------------------------------------------------------- +callgraph_t::callgraph_t() : node_count(0) +{ + cur_text[0] = '\0'; +} + +//-------------------------------------------------------------------------- +void callgraph_t::clear_edges() +{ + edges.clear(); +} + +//-------------------------------------------------------------------------- +graph_info_t::graphinfo_list_t graph_info_t::instances; + +//-------------------------------------------------------------------------- +graph_info_t::graph_info_t() +{ + form = NULL; + gv = NULL; +} + +//-------------------------------------------------------------------------- +graph_info_t * graph_info_t::create(ea_t func_ea, citem_t *highlighted) +{ + graph_info_t *r; + + func_t *pfn = get_func(func_ea); + if ( pfn == NULL ) + return NULL; + + r = new graph_info_t(); + get_title(func_ea, &r->title); + r->func_ea = pfn->startEA; + r->fg.highlighted = highlighted; + instances.push_back(r); + + return r; +} + +//-------------------------------------------------------------------------- +bool graph_info_t::get_title(ea_t func_ea, qstring *out) +{ + // we should succeed in getting the name + char func_name[MAXSTR]; + if ( get_func_name(func_ea, func_name, sizeof(func_name)) == NULL ) + return false; + out->sprnt("Call graph of: %s", func_name); + return true; +} \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/GraphBuilder.cpp b/sources/HexRaysCodeXplorer/GraphBuilder.cpp new file mode 100644 index 0000000..9368a0f --- /dev/null +++ b/sources/HexRaysCodeXplorer/GraphBuilder.cpp @@ -0,0 +1,271 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#include "Common.h" +#include "GraphBuilder.h" + +#include +#include +#include + + +bool callgraph_t::visited(citem_t *i, int *nid) +{ + ea_int_map_t::const_iterator it = ea2node.find(i); + if ( it != ea2node.end() ) + { + if ( nid != NULL ) + *nid = it->second; + return true; + } + return false; +} + + +void callgraph_t::create_edge(int id1, int id2) +{ + edges.push_back(edge_t(id1, id2)); +} + +char * callgraph_t::get_node_label(int n, char *buf, int bufsize) const +{ + int_ea_map_t::const_iterator it = node2ea.find(n); + + if ( it != node2ea.end() ) + { + const citem_t *item = it->second; + + char *ptr = buf; + char *endp = buf + bufsize; + + // Each node will have the element type at the first line + APPEND(ptr, endp, get_ctype_name(item->op)); + const cexpr_t *e = (const cexpr_t *)item; + const cinsn_t *i = (const cinsn_t *)item; + + // For some item types, display additional information + switch ( item->op ) + { + case cot_ptr : // *x + case cot_memptr : // x->m + // Display access size for pointers + ptr += qsnprintf(ptr, endp-ptr, ".%d", e->ptrsize); + if ( item->op == cot_ptr ) + break; + case cot_memref : // x.m + // Display member offset for structure fields + ptr += qsnprintf(ptr, endp-ptr, " (m=%d)", e->m); + break; + case cot_obj : // v + case cot_var : // l + // Display object size for local variables and global data + ptr += qsnprintf(ptr, endp-ptr, ".%d", e->refwidth); + case cot_num : // n + case cot_helper : // arbitrary name + case cot_str : // string constant + // Display helper names and number values + APPCHAR(ptr, endp, ' '); + e->print1(ptr, endp-ptr, NULL); + tag_remove(ptr, ptr, 0); + ptr = tail(ptr); + break; + case cit_goto: + // Display target label number for gotos + ptr += qsnprintf(ptr, endp-ptr, " LABEL_%d", i->cgoto->label_num); + break; + case cit_asm: + // Display instruction block address and size for asm-statements + ptr += qsnprintf(ptr, endp-ptr, " %a.%"FMT_Z, *i->casm->begin(), i->casm->size()); + break; + default: + break; + } + + // The second line of the node contains the item address + ptr += qsnprintf(ptr, endp-ptr, "\nea: %a", item->ea); + if ( item->is_expr() && !e->type.empty() ) + { + // For typed expressions, the third line will have + // the expression type in human readable form + APPCHAR(ptr, endp, '\n'); + if ( print_type_to_one_line(ptr, endp-ptr, idati, e->type.u_str()) != T_NORMAL ) + { // could not print the type? + APPCHAR(ptr, endp, '?'); + APPZERO(ptr, endp); + } + + if(e->type.is_ptr()) + { + typestring ptr_rem = remove_pointer(e->type); + if(ptr_rem.is_struct()) + { + qstring typenm; + + print_type_to_qstring(&typenm, "prefix ", 0,0, PRTYPE_MULTI | PRTYPE_TYPE | PRTYPE_SEMI, idati, ptr_rem.u_str()); + } + } + } + } + + return buf; +} + +callgraph_t::nodeinfo_t *callgraph_t::get_info(int nid) +{ + nodeinfo_t *ret = NULL; + + do + { + // returned cached name + int_funcinfo_map_t::iterator it = cached_funcs.find(nid); + if ( it != cached_funcs.end() ) + { + ret = &it->second; + break; + } + + // node does not exist? + int_ea_map_t::const_iterator it_ea = node2ea.find(nid); + if ( it_ea == node2ea.end() ) + break; + + citem_t *pfn = it_ea->second; + if ( pfn == NULL ) + break; + + nodeinfo_t fi; + + // get name + char buf[MAXSTR]; + if(get_node_label(nid, buf, MAXSTR)) + fi.name = buf; + else + fi.name = "?"; + + // get color + if(pfn == highlighted) + fi.color = 2000; + else + fi.color = 1;//bgcolors.prolog_color;//calc_bg_color(pfn->startEA); + + //fi.ea = pfn->startEA; + fi.ea = 0; + + it = cached_funcs.insert(cached_funcs.end(), std::make_pair(nid, fi)); + ret = &it->second; + } while ( false ); + + return ret; +} + +//-------------------------------------------------------------------------- + +int callgraph_t::add(citem_t *i) +{ + // check if we are trying to add existing node + ea_int_map_t::const_iterator it = ea2node.find(i); + if ( it != ea2node.end() ) + return it->second; + + ea2node[i] = node_count; + node2ea[node_count] = i; + + int ret_val = node_count; + node_count ++; + return ret_val; +} + +//-------------------------------------------------------------------------- +callgraph_t::callgraph_t() : node_count(0) +{ + cur_text[0] = '\0'; +} + +//-------------------------------------------------------------------------- +void callgraph_t::clear_edges() +{ + edges.clear(); +} + +//-------------------------------------------------------------------------- +graph_info_t::graphinfo_list_t graph_info_t::instances; + +//-------------------------------------------------------------------------- +graph_info_t::graph_info_t() +{ + form = NULL; + gv = NULL; +} + +//-------------------------------------------------------------------------- +graph_info_t * graph_info_t::create(ea_t func_ea, citem_t *highlighted) +{ + graph_info_t *r; + + func_t *pfn = get_func(func_ea); + if ( pfn == NULL ) + return NULL; + + r = new graph_info_t(); + r->func_ea = pfn->startEA; + r->fg.highlighted = highlighted; + + size_t num_inst = 0; + for(graphinfo_list_t::iterator it = instances.begin() ; it != instances.end() ; it ++) + { + if(((*(it))->func_ea == func_ea) && (num_inst < (*(it))->func_instance_no)) + num_inst = (*(it))->func_instance_no; + } + + r->func_instance_no = ++ num_inst; + get_title(func_ea, num_inst, &r->title); + + instances.push_back(r); + + return r; +} + +//-------------------------------------------------------------------------- +bool graph_info_t::get_title(ea_t func_ea, size_t num_inst, qstring *out) +{ + // we should succeed in getting the name + char func_name[MAXSTR]; + if ( get_func_name(func_ea, func_name, sizeof(func_name)) == NULL ) + return false; + + out->sprnt("Call graph of: %s %d", func_name, num_inst); + + return true; +} + +void graph_info_t::destroy(graph_info_t *gi) +{ + for(graphinfo_list_t::iterator it = instances.begin() ; it != instances.end() ; it ++) + { + if((*(it)) == gi) + { + instances.erase(it); + break; + } + } +} \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/GraphBuilder.h b/sources/HexRaysCodeXplorer/GraphBuilder.h new file mode 100644 index 0000000..cd1c5d8 --- /dev/null +++ b/sources/HexRaysCodeXplorer/GraphBuilder.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +// function call graph creator class +class callgraph_t +{ + // total number of the nodes in the graph + int node_count; + + // node id to func addr and reverse lookup + typedef std::map ea_int_map_t; + typedef std::map int_ea_map_t; + ea_int_map_t ea2node; + int_ea_map_t node2ea; + + // current node search ptr + int cur_node; + char cur_text[MAXSTR]; + + bool visited(citem_t *i, int *nid); + +public: + + citem_t *highlighted; + + int add(citem_t *i); + // edge structure + struct edge_t + { + int id1; + int id2; + edge_t(int i1, int i2): id1(i1), id2(i2) { } + edge_t(): id1(0), id2(0) { } + }; + + typedef qlist edges_t; + + // edge manipulation + typedef edges_t::iterator edge_iterator; + void create_edge(int id1, int id2); + + edge_iterator begin_edges() { return edges.begin(); } + edge_iterator end_edges() { return edges.end(); } + + void clear_edges(); + + callgraph_t(); + + const int count() const { return node_count; } + + // node / func info + struct nodeinfo_t + { + qstring name; + bgcolor_t color; + ea_t ea; + }; + + typedef std::map int_funcinfo_map_t; + int_funcinfo_map_t cached_funcs; + nodeinfo_t *get_info(int nid); + + +// int walk_func(func_t *func); +private: + edges_t edges; + + char * get_node_label(int n, char *buf, int bufsize) const; +}; + + +// per function call graph context +class graph_info_t +{ +// Actual context variables +public: + callgraph_t fg; // associated graph maker + graph_viewer_t *gv; // associated graph_view + TForm *form; // associated TForm + vdui_t *vu; + + + ea_t func_ea; // function ea in question + qstring title; // the title + + size_t func_instance_no; +// Instance management +private: + typedef qlist graphinfo_list_t; + typedef graphinfo_list_t::iterator iterator; + + // Remove instance upon deletion of the objects + static graphinfo_list_t instances; + + + graph_info_t(); +public: + static graph_info_t *create(ea_t func_ea, citem_t *it); + static void destroy(graph_info_t *gi); + static bool get_title(ea_t func_ea, size_t num_inst, qstring *out); +}; \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.cpp b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.cpp new file mode 100644 index 0000000..4374666 --- /dev/null +++ b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.cpp @@ -0,0 +1,297 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + . +*/ + + +#include "HexRaysCodeXplorer.h" + +itemrefs_t items; + + // Display a graph node. Feel free to modify this function to fine tune the node display. + char *idaapi get_node_label(int n, char *buf, int bufsize) + { + char *ptr = buf; + char *endp = buf + bufsize; + // Get the corresponding ctree item + const citem_t *item = items[n]; + // Each node will have the element type at the first line + APPEND(ptr, endp, get_ctype_name(item->op)); + const cexpr_t *e = (const cexpr_t *)item; + const cinsn_t *i = (const cinsn_t *)item; + // For some item types, display additional information + switch ( item->op ) + { + case cot_ptr : // *x + case cot_memptr : // x->m + // Display access size for pointers + ptr += qsnprintf(ptr, endp-ptr, ".%d", e->ptrsize); + if ( item->op == cot_ptr ) + break; + case cot_memref : // x.m + // Display member offset for structure fields + ptr += qsnprintf(ptr, endp-ptr, " (m=%d)", e->m); + break; + case cot_obj : // v + case cot_var : // l + // Display object size for local variables and global data + ptr += qsnprintf(ptr, endp-ptr, ".%d", e->refwidth); + case cot_num : // n + case cot_helper : // arbitrary name + case cot_str : // string constant + // Display helper names and number values + APPCHAR(ptr, endp, ' '); + e->print1(ptr, endp-ptr, NULL); + tag_remove(ptr, ptr, 0); + ptr = tail(ptr); + break; + case cit_goto: + // Display target label number for gotos + ptr += qsnprintf(ptr, endp-ptr, " LABEL_%d", i->cgoto->label_num); + break; + case cit_asm: + // Display instruction block address and size for asm-statements + ptr += qsnprintf(ptr, endp-ptr, " %a.%"FMT_Z, *i->casm->begin(), i->casm->size()); + break; + default: + break; + } + // The second line of the node contains the item address + ptr += qsnprintf(ptr, endp-ptr, "\nea: %a", item->ea); + if ( item->is_expr() && !e->type.empty() ) + { + // For typed expressions, the third line will have + // the expression type in human readable form + APPCHAR(ptr, endp, '\n'); + if ( print_type_to_one_line(ptr, endp-ptr, idati, e->type.u_str()) != T_NORMAL ) + { // could not print the type? + APPCHAR(ptr, endp, '?'); + APPZERO(ptr, endp); + } + + if(e->type.is_ptr()) + { + typestring ptr_rem = remove_pointer(e->type); + if(ptr_rem.is_struct()) + { + qstring typenm; + + print_type_to_qstring(&typenm, "prefix ", 0,0, PRTYPE_MULTI | PRTYPE_TYPE | PRTYPE_SEMI, idati, ptr_rem.u_str()); + +// print_type_to_one_line(ptr, endp-ptr, idati, ptr_rem.u_str()); + } + } + } + return buf; + } + + + // Display a graph edge. + bool idaapi print_edge(FILE *fp, int i, int j) const + { + qfprintf(fp, "edge: { sourcename: \"%d\" targetname: \"%d\" ", i, j); + const char *label = NULL; + const citem_t *a = items[i]; + const citem_t *b = items[j]; + if ( a->is_expr() ) // For expressions, add labels to the edges + { + cexpr_t *e = (cexpr_t *)a; + if ( e->x == b ) label = "x"; + if ( e->y == b ) label = "y"; + if ( e->z == b ) label = "z"; + } + if ( label != NULL ) + qfprintf(fp, "label: \"%s\" ", label); + qfprintf(fp, "}\n"); + return true; + } + // Determine the node color. Feel free to change it. + bgcolor_t idaapi get_node_color(int n) const + { + const citem_t *item = items[n]; + if ( item == highlight ) + return CL_GREEN; // Highlighted item + if ( item->is_expr() ) + { + char buf[MAXSTR]; + const cexpr_t *e = (const cexpr_t *)item; + if ( print_type_to_one_line(buf, sizeof(buf), idati, e->type.u_str()) != T_NORMAL ) + return CL_YELLOWGREEN; // Problematic type + } + + if(item->op == cot_call) + return CL_RED; + + return DEFCOLOR; + } + // Print the node color. + void idaapi print_node_attributes(FILE *fp, int n) const + { + bgcolor_t c = get_node_color(n); + if ( c != DEFCOLOR ) + qfprintf(fp, " color: %s", get_color_name(c)); + } +}; + +//-------------------------------------------------------------------------- +// Helper class to build graph from ctree. +struct graph_builder_t : public ctree_parentee_t +{ + cfunc_graph_t &cg; // Resulting graph + std::map reverse; // Reverse mapping for tests and adding edges + + graph_builder_t(cfunc_graph_t &_cg) : cg(_cg) {} + int add_node(citem_t *i); + int process(citem_t *i); + // We treat expressions and statements the same way: add them to the graph + int idaapi visit_insn(cinsn_t *i) { return process(i); } + int idaapi visit_expr(cexpr_t *e) { return process(e); } +}; + +// Add a new node to the graph +int graph_builder_t::add_node(citem_t *i) +{ + // Check if the item has already been encountered during the traversal + if ( reverse.find(i) != reverse.end() ) + { + warning("bad ctree - duplicate nodes!"); + return -1; + } + // Add a node to the graph + int n = cg.add_node(); + // Remember the pointer to the item, we will need it to generate GDL + // (in print_node_label) + if ( n <= cg.items.size() ) + cg.items.push_back(i); + cg.items[n] = i; + // Also remember the reverse mapping (citem_t* -> n) + reverse[i] = n; + return n; +} + +// Process a ctree item +int graph_builder_t::process(citem_t *item) +{ + // Add a node for citem + int n = add_node(item); + if ( n == -1 ) + return -1; // error + + if ( parents.size() > 1 ) // The current item has a parent? + { + int p = reverse[parents.back()]; // Parent node number + cg.add_edge(p, n); // Add edge from the parent to the current item + } + return 0; +} + +//-------------------------------------------------------------------------- +// Build and display graph for the ctree +static bool idaapi display_graph(void *ud) +{ + vdui_t &vu = *(vdui_t *)ud; + // Determine the ctree item to highlight + vu.get_current_item(USE_KEYBOARD); + citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; + + cfunc_graph_t cg(highlight); // Graph to display + graph_builder_t gb(cg); // Graph builder helper class + // Build the graph by traversing the ctree + gb.apply_to(&vu.cfunc->body, NULL); + + // Our graph object 'cg' is ready. Now display it by converting it to GDL + // and calling wingraph32 + char fname[QMAXPATH]; + qtmpnam(fname, sizeof(fname)); // Generate temporary file name + gen_gdl(&cg, fname); // Generate GDL file from 'cg' graph + display_gdl(fname); // Display the GDL file + return true; // Success! +} + +func_t * get_func_by_name(const char *func_name) +{ + func_t * result_func = NULL; + size_t func_total = get_func_qty(); + if(func_total > 0) + { + char tmp[1024]; + for (int i = 0 ; i < func_total - 1 ; i ++) + { + func_t * func = getn_func(i); + if(func != NULL) + { + memset(tmp, 0x00, sizeof(tmp)); + char *func_n = get_func_name(func->startEA, tmp, sizeof(tmp)); + if(func_n != NULL) + { + if(!strcmp(func_name, func_n)) + { + result_func = func; + break; + } + } + } + } + } + return result_func; +} + +static bool idaapi decompile_func(vdui_t &vu) +{ + // Determine the ctree item to highlight + vu.get_current_item(USE_KEYBOARD); + citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; + + if(highlight != NULL) + { + if(highlight->is_expr()) + //if(highlight->op == cot_call) + { + cexpr_t *e = (cexpr_t *)highlight; + char tmp[512]; + memset(tmp, 0x00, sizeof(tmp)); + e->print1(tmp, sizeof(tmp), NULL); + tag_remove(tmp, tmp, sizeof(tmp)); + + char *proc_name = tmp + strlen(tmp); + + + while((proc_name > tmp) && (*(proc_name - 1) != '>')) + proc_name --; + + msg("Function %s is choosen\n", proc_name); + + func_t * func = get_func_by_name(proc_name); + if(func != NULL) + { + vdui_t * decompiled_window = open_pseudocode(func->startEA, -1); + /* + hexrays_failure_t error; + cfuncptr_t decompiled = decompile(func, &error); + if(decompiled != NULL) + switch_to(decompiled); + */ + } + } + } + + return true; // Success! +} \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.h b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.h new file mode 100644 index 0000000..9765a11 --- /dev/null +++ b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.h @@ -0,0 +1,150 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + . +*/ + + +#include +#include +#include + +// Hex-Rays API pointer +hexdsp_t *hexdsp = NULL; + +static bool inited = false; + +// Hotkey for the new command +static const char hotkey[] = "G"; +static ushort hotcode; + +//------------------------------------------------------------------------- +// red green blue +#define CL_WHITE ((255)+ (255<<8)+ (255<<16)) // 0 +#define CL_BLUE ((0 )+ (0 <<8)+ (255<<16)) // 1 +#define CL_RED ((255)+ (0 <<8)+ (0 <<16)) // 2 +#define CL_GREEN ((0 )+ (255<<8)+ (0 <<16)) // 3 +#define CL_YELLOW ((255)+ (255<<8)+ (0 <<16)) // 4 +#define CL_MAGENTA ((255)+ (0 <<8)+ (255<<16)) // 5 +#define CL_CYAN ((0 )+ (255<<8)+ (255<<16)) // 6 +#define CL_DARKGREY ((85 )+ (85 <<8)+ (85 <<16)) // 7 +#define CL_DARKBLUE ((0 )+ (0 <<8)+ (128<<16)) // 8 +#define CL_DARKRED ((128)+ (0 <<8)+ (0 <<16)) // 9 +#define CL_DARKGREEN ((0 )+ (128<<8)+ (0 <<16)) // 10 +#define CL_DARKYELLOW ((128)+ (128<<8)+ (0 <<16)) // 11 +#define CL_DARKMAGENTA ((128)+ (0 <<8)+ (128<<16)) // 12 +#define CL_DARKCYAN ((0 )+ (128<<8)+ (128<<16)) // 13 +#define CL_GOLD ((255)+ (215<<8)+ (0 <<16)) // 14 +#define CL_LIGHTGREY ((170)+ (170<<8)+ (170<<16)) // 15 +#define CL_LIGHTBLUE ((128)+ (128<<8)+ (255<<16)) // 16 +#define CL_LIGHTRED ((255)+ (128<<8)+ (128<<16)) // 17 +#define CL_LIGHTGREEN ((128)+ (255<<8)+ (128<<16)) // 18 +#define CL_LIGHTYELLOW ((255)+ (255<<8)+ (128<<16)) // 19 +#define CL_LIGHTMAGENTA ((255)+ (128<<8)+ (255<<16)) // 20 +#define CL_LIGHTCYAN ((128)+ (255<<8)+ (255<<16)) // 21 +#define CL_LILAC ((238)+ (130<<8)+ (238<<16)) // 22 +#define CL_TURQUOISE ((64 )+ (224<<8)+ (208<<16)) // 23 +#define CL_AQUAMARINE ((127)+ (255<<8)+ (212<<16)) // 24 +#define CL_KHAKI ((240)+ (230<<8)+ (140<<16)) // 25 +#define CL_PURPLE ((160)+ (32 <<8)+ (240<<16)) // 26 +#define CL_YELLOWGREEN ((154)+ (205<<8)+ (50 <<16)) // 27 +#define CL_PINK ((255)+ (192<<8)+ (203<<16)) // 28 +#define CL_ORANGE ((255)+ (165<<8)+ (0 <<16)) // 29 +#define CL_ORCHID ((218)+ (112<<8)+ (214<<16)) // 30 +#define CL_BLACK ((0 )+ (0 <<8)+ (0 <<16)) // 31 + +//------------------------------------------------------------------------- +// Convert internal background color code into textual form for GDL +static const char *get_color_name(bgcolor_t c) +{ + switch ( c ) + { + case CL_WHITE : return "white"; + case CL_BLUE : return "blue"; + case CL_RED : return "red"; + case CL_GREEN : return "green"; + case CL_YELLOW : return "yellow"; + case CL_MAGENTA : return "magenta"; + case CL_CYAN : return "cyan"; + case CL_DARKGREY : return "darkgrey"; + case CL_DARKBLUE : return "darkblue"; + case CL_DARKRED : return "darkred"; + case CL_DARKGREEN : return "darkgreen"; + case CL_DARKYELLOW : return "darkyellow"; + case CL_DARKMAGENTA : return "darkmagenta"; + case CL_DARKCYAN : return "darkcyan"; + case CL_GOLD : return "gold"; + case CL_LIGHTGREY : return "lightgrey"; + case CL_LIGHTBLUE : return "lightblue"; + case CL_LIGHTRED : return "lightred"; + case CL_LIGHTGREEN : return "lightgreen"; + case CL_LIGHTYELLOW : return "lightyellow"; + case CL_LIGHTMAGENTA: return "lightmagenta"; + case CL_LIGHTCYAN : return "lightcyan"; + case CL_LILAC : return "lilac"; + case CL_TURQUOISE : return "turquoise"; + case CL_AQUAMARINE : return "aquamarine"; + case CL_KHAKI : return "khaki"; + case CL_PURPLE : return "purple"; + case CL_YELLOWGREEN : return "yellowgreen"; + case CL_PINK : return "pink"; + case CL_ORANGE : return "orange"; + case CL_ORCHID : return "orchid"; + case CL_BLACK : return "black"; + } + return "?"; +} + +//-------------------------------------------------------------------------- +// Since we can not directly display cfunc_t as a graph, we build a graph +// object which will be saved as a GDL file and displayed with wingraph32. +class cfunc_graph_t : public gdl_graph_t +{ + typedef qvector itemrefs_t; + itemrefs_t items; + const citem_t *highlight; // item to highlight + friend struct graph_builder_t; + array_of_intseq_t succs; + array_of_intseq_t preds; + int idaapi nsucc(int b) const { return size() ? succs[b].size() : 0; } + int idaapi npred(int b) const { return size() ? preds[b].size() : 0; } + int idaapi succ(int b, int i) const { return succs[b][i]; } + int idaapi pred(int b, int i) const { return preds[b][i]; } +public: + cfunc_graph_t(const citem_t *_highlight) : highlight(_highlight) {} + int idaapi size(void) const { return preds.size(); } + int add_node(void) + { + int n = size(); + preds.resize(n+1); + succs.resize(n+1); + return n; + } + void add_edge(int x, int y) + { + preds[y].push_back(x); + succs[x].push_back(y); + } +}; + + +static bool idaapi display_graph(void *ud); +func_t* get_func_by_name(const char *func_name); +static bool idaapi decompile_func(vdui_t &vu); diff --git a/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj new file mode 100644 index 0000000..706057d --- /dev/null +++ b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj @@ -0,0 +1,107 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {F7E6B557-41F3-444A-BCA4-3527547DD665} + Win32Proj + HexRaysCodeXplorer + HexRaysCodeXplorer + + + + DynamicLibrary + true + MultiByte + v100 + + + DynamicLibrary + false + true + MultiByte + v100 + + + + + + + + + + + + + true + build makefile + .plw + + + false + .plw + + + + + + Level3 + Disabled + __NT__;__IDP__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(IDADIR)\idasdk64\include;$(IDADIR)\plugins\hexrays_sdk\include + MultiThreadedDebug + + + Console + true + ida.lib + /EXPORT:PLUGIN %(AdditionalOptions) + $(IDADIR)\idasdk64\lib\x86_win_vc_32 + + + + + Level3 + + + MaxSpeed + true + true + __NT__;__IDP__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(IDADIR)\idasdk64\include;$(IDADIR)\plugins\hexrays_sdk\include + MultiThreaded + + + Console + true + true + true + ida.lib + /EXPORT:PLUGIN %(AdditionalOptions) + $(IDADIR)\idasdk64\lib\x86_win_vc_32 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj.filters b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj.filters new file mode 100644 index 0000000..f15c0d1 --- /dev/null +++ b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj.user b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj.user new file mode 100644 index 0000000..f80fefa --- /dev/null +++ b/sources/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj.user @@ -0,0 +1,11 @@ + + + + $(IDADIR)\idaq.exe + WindowsLocalDebugger + + + $(IDADIR)\idaq.exe + WindowsLocalDebugger + + \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/IdaGraphBuilder.cpp b/sources/HexRaysCodeXplorer/IdaGraphBuilder.cpp new file mode 100644 index 0000000..d45750d --- /dev/null +++ b/sources/HexRaysCodeXplorer/IdaGraphBuilder.cpp @@ -0,0 +1,294 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + . +*/ + + +#include "IdaGraphBuilder.h" +#include "HexRaysCodeXplorer.h" + +#include + + + +//typedef std::map graph_nodes; + +typedef std::map basic_blocks_t; + +static std::vector graph_text; +static basic_blocks_t bbs; + + +static bool gather_basic_blocks(ea_t ea1, ea_t ea2) +{ + show_wait_box("Finding basic blocks"); + ea_t start = BADADDR; + bool ok = true; + int cnt = 0; + while ( ea1 != ea2 ) + { + if ( wasBreak() ) + { + ok = false; + break; + } + if ( start == BADADDR ) + { + start = ea1; + ea1 = nextthat(ea1, ea2, f_isCode, NULL); + if ( ea1 >= ea2 ) + break; + //start = ea1; + } + while ( ea1 < ea2 ) + { + if ( !ua_ana0(ea1) ) + break; + ea1 = get_item_end(ea1); + if ( is_basic_block_end(false) ) + break; + } + if ( ea1 != start ) + bbs[start] = ea1 - start; // remember the bb start and size + if ( !isCode(get_flags_novalue(ea1)) ) + start = BADADDR; + else + start = ea1; + } + hide_wait_box(); + return ok; +} + + +//-------------------------------------------------------------------------- +// wrapper for gather_basic_blocks() +static void update_basic_blocks(void) +{ + bbs.clear(); + func_t *f = NULL; + + f = get_func(get_screen_ea()); + if( f != NULL ) + { + if( gather_basic_blocks( f->startEA, f->endEA ) ) + { + //msg("List of basic blocks:\n"); + for ( basic_blocks_t::iterator p=bbs.begin(); p != bbs.end(); ++p ) + { + size_t i = p->first;// - base; + //msg("%08X: (end: %08X)\n",i,i+p->second); + } + } + + } + +} + + +//-------------------------------------------------------------------------- +// return number of instructions within two addresses +static size_t get_num_insns(ea_t start, ea_t end) +{ + ea_t cur = start; + size_t insns = 0; + + while( cur != BADADDR ) + { + if(isCode(getFlags(cur))) + insns++; + start = cur; + cur=next_head( start, end ); + } + + return insns; +} + +//-------------------------------------------------------------------------- +static int BuildGraph(void *, int code, va_list va) +{ + int result = 0; + switch ( code ) + { + + case grcode_user_refresh: // refresh user-defined graph nodes and edges + // in: mutable_graph_t *g + // out: success + { + mutable_graph_t *g = va_arg(va, mutable_graph_t *); + msg("%x: refresh\n", g); + + if ( g->empty() ) + g->resize( (int)(bbs.size()) ); + + int j=0; + for ( basic_blocks_t::iterator p=bbs.begin(); p != bbs.end(); ++p ) + { + //size_t i = p->first;// - base; + //msg("%08X: (end: %08X)\n",i,i+p->second); + xrefblk_t xb; + for ( bool ok=xb.first_from(prevthat(p->first+p->second, 0, f_isCode, NULL), XREF_ALL); ok; ok=xb.next_from() ) + { + //xb.to - contains the referenced address + int k=0; + for ( basic_blocks_t::iterator p2=bbs.begin(); p2 != bbs.end(); ++p2 ) + { + if( xb.to == p2->first ) + { + g->add_edge(j, k, NULL); + msg("%08x: -> %08X\n", prevthat(p->first+p->second, 0, f_isCode, NULL), xb.to); + } + k++; + } + } + j++; + } + result = true; + } + break; + + case grcode_user_gentext: // generate text for user-defined graph nodes + // in: mutable_graph_t *g + // out: must return 0 + { + mutable_graph_t *g = va_arg(va, mutable_graph_t *); + msg("%x: generate text for graph nodes\n", g); + graph_text.resize(g->size()); + + for ( node_iterator p=g->begin(); p != g->end(); ++p ) + { + int n = *p; + char buf[MAXSTR]; + + qsnprintf(buf,sizeof(buf),"Node %8d\n",n); + graph_text[n] = buf; + + int j=0; + for ( basic_blocks_t::iterator bbi=bbs.begin(); bbi != bbs.end(); ++bbi ) + { + if(n==j) + { + qsnprintf(buf, sizeof(buf), "StartEA %08X\n" + "EndEA %08X\n", + bbi->first, + bbi->first+bbi->second); + graph_text[n] += buf; + qsnprintf(buf,sizeof(buf),"Instr %8d\n",get_num_insns(bbi->first,bbi->first+bbi->second)); + graph_text[n] += buf; + break; + } + j++; + } + + qsnprintf(buf, sizeof(buf),"Indeg %8d\n" + "Outdeg %8d\n", + g->npred(n), + g->nsucc(n) + ); + + + graph_text[n] += buf; + + } + result = true; + } + break; + + case grcode_user_text: // retrieve text for user-defined graph node + // in: mutable_graph_t *g + // int node + // const char **result + // bgcolor_t *bg_color (maybe NULL) + // out: must return 0, result must be filled + // NB: do not use anything calling GDI! + { + mutable_graph_t *g = va_arg(va, mutable_graph_t *); + int node = va_argi(va, int); + const char **text = va_arg(va, const char **); + bgcolor_t *bgcolor = va_arg(va, bgcolor_t *); + + int succ = g->nsucc(node); + int pred = g->npred(node); + + *text = graph_text[node].c_str(); + + if ( bgcolor != NULL ) + { + // same indegree as outdegree and != 0 ? + if(pred == succ && pred != 0) + *bgcolor = RGB(220, 220, 220); + + // a few edges only + else if( succ <= 2 && pred <= 2 ) + { + if( succ == 0 || pred == 0 ) + { + // nodes with no edges at all + if(pred == succ) + *bgcolor = RGB(255, 50, 50); + // nodes with either in- or outdegree edges only + else + *bgcolor = RGB(0, 130, 255); + } + // "normal" node, default color + else + *bgcolor = DEFCOLOR; + } + // in- or outdegree > 2 + else + *bgcolor = RGB( 255, 255, 0 ); + } + + result = true; + qnotused(g); + } + break; + + + case grcode_dblclicked: // a graph node has been double clicked + // in: graph_viewer_t *gv + // selection_item_t *current_item + // out: 0-ok, 1-ignore click + { + graph_viewer_t *v = va_arg(va, graph_viewer_t *); + selection_item_t *s = va_arg(va, selection_item_t *); + + if ( s->is_node ) + { + int j=0; + + for ( basic_blocks_t::iterator bbi=bbs.begin(); bbi != bbs.end(); ++bbi ) + { + if(s->node==j) + { + //jump to dblclicked node in disassembly/IDA graph view + jumpto(bbi->first,-1); + break; + } + j++; + } + } + + } + break; + + } + return result; +} \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/IdaGraphBuilder.h b/sources/HexRaysCodeXplorer/IdaGraphBuilder.h new file mode 100644 index 0000000..da9542a --- /dev/null +++ b/sources/HexRaysCodeXplorer/IdaGraphBuilder.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + . +*/ + + +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/ObjectExplorer.cpp b/sources/HexRaysCodeXplorer/ObjectExplorer.cpp new file mode 100644 index 0000000..f36d1ce --- /dev/null +++ b/sources/HexRaysCodeXplorer/ObjectExplorer.cpp @@ -0,0 +1,252 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#include "Common.h" +#include "ObjectExplorer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + + +LPCTSTR get_text_disasm(ea_t ea) +{ + static char disasm_buff[MAXSTR]; + disasm_buff[0] = disasm_buff[MAXSTR - 1] = 0; + + if(generate_disasm_line(ea, disasm_buff, (sizeof(disasm_buff) - 1))) + tag_remove(disasm_buff, disasm_buff, (sizeof(disasm_buff) - 1)); + + return(disasm_buff); +} + + +BOOL get_vtbl_info(ea_t ea_address, tVTBL_info &vtbl_info) +{ + flags_t flags = getFlags(ea_address); + if(!(hasRef(flags) || has_any_name(flags) && (isDwrd(flags) || isUnknown(flags)))) + return(FALSE); + else + { + BOOL is_move_xref = FALSE; + ea_t ea_code_ref = get_first_dref_to(ea_address); + if(ea_code_ref && (ea_code_ref != BADADDR)) + { + do + { + if(isCode(getFlags(ea_code_ref))) + { + LPCTSTR disasm_line = get_text_disasm(ea_code_ref); + if((*((PUINT) disasm_line) == 0x20766F6D /*"mov "*/) && (strstr(disasm_line+4, " offset ") != NULL)) + { + is_move_xref = TRUE; + break; + } + } + + ea_code_ref = get_next_dref_to(ea_address, ea_code_ref); + + } while(ea_code_ref && (ea_code_ref != BADADDR)); + } + if(!is_move_xref) + return(FALSE); + + ZeroMemory(&vtbl_info, sizeof(tVTBL_info)); + + get_name(BADADDR, ea_address, vtbl_info.name_size, (MAXSTR - 1)); + + ea_t ea_start = vtbl_info.ea_begin = ea_address; + while(TRUE) + { + flags_t index_flags = getFlags(ea_address); + if(!(hasValue(index_flags) && (isDwrd(index_flags) || isUnknown(index_flags)))) + break; + + ea_t ea_index_value = get_32bit(ea_address); + if(!(ea_index_value && (ea_index_value != BADADDR))) + break; + + if(ea_address != ea_start) + if(hasRef(index_flags)) + break; + + flags_t value_flags = getFlags(ea_index_value); + if(!isCode(value_flags)) + { + break; + } + else + if(isUnknown(index_flags)) + { + doDwrd(ea_address, sizeof(DWORD)); + } + + ea_address += sizeof(UINT); + }; + + if((vtbl_info.methods = ((ea_address - ea_start) / sizeof(UINT))) > 0) + { + vtbl_info.ea_end = ea_address; + return(TRUE); + } + else + { + return(FALSE); + } + } +} + + +qvector vtbl_list; +static BOOL process_vtbl(ea_t &ea_rdata) +{ + tVTBL_info vftable_info_t; + if(get_vtbl_info(ea_rdata, vftable_info_t)) + { + ea_rdata = vftable_info_t.ea_end; + ea_t eaAssumedCOL; + verify_32_t((vftable_info_t.ea_begin - 4), eaAssumedCOL); + + if(vftable_info_t.methods > 1) + { + if(has_user_name(getFlags(vftable_info_t.ea_begin))) + { + char szName[MAXSTR] = {0}; + get_short_name(BADADDR, vftable_info_t.ea_begin, szName, (MAXSTR - 1)); + + qstring vtbl_info; + vtbl_info.cat_sprnt("0x%x - 0x%x: \t %s \t method count: %u", vftable_info_t.ea_begin, vftable_info_t.ea_end, vftable_info_t.name_size, vftable_info_t.methods); + vtbl_list.push_back(vtbl_info); + + return(TRUE); + } + } + + return(FALSE); + } + + ea_rdata += sizeof(UINT); + return(FALSE); +} + + +void search_vtbl() +{ + segment_t *rdata_seg = get_segm_by_name(".rdata"); + ea_t ea_rdata = rdata_seg->startEA; + while(ea_rdata <= rdata_seg->endEA) + { + process_vtbl(ea_rdata); + }; +} + + + +//--------------------------------------------------------------------------- +// IDA Custom View Window Initialization +//--------------------------------------------------------------------------- +static bool idaapi ct_keyboard(TCustomControl * /*v*/, int key, int shift, void *ud) +{ + if ( shift == 0 ) + { + object_explorer_info_t *si = (object_explorer_info_t *)ud; + switch ( key ) + { + case IK_ESCAPE: + close_tform(si->form, FORM_SAVE | FORM_CLOSE_LATER); + return true; + } + } + return false; +} + + +static bool idaapi lines_linenum( + TCustomControl * /*cv*/, + const place_t *p, + uval_t *num, + void * /*ud*/) +{ + *num = p->touval(NULL) + 1; + return true; +} + + +int idaapi ui_callback(void *ud, int code, va_list va) +{ + object_explorer_info_t *si = (object_explorer_info_t *)ud; + switch ( code ) + { + case ui_tform_invisible: + { + TForm *f = va_arg(va, TForm *); + if ( f == si->form ) + { + delete si; + unhook_from_notification_point(HT_UI, ui_callback, NULL); + } + } + break; + } + return 0; +} + + +void custom_form_init() +{ + HWND hwnd = NULL; + TForm *form = create_tform("Object Explorer", &hwnd); + if ( hwnd == NULL ) + { + warning("Object Explorer window already open. Switching to it."); + form = find_tform("Object Explorer"); + if ( form != NULL ) + switchto_tform(form, true); + return; + } + + object_explorer_info_t *si = new object_explorer_info_t(form); + + qvector ::iterator vtbl_iter; + for ( vtbl_iter = vtbl_list.begin(); vtbl_iter != vtbl_list.end(); vtbl_iter++ ) + si->sv.push_back(simpleline_t(*vtbl_iter)); + + simpleline_place_t s1; + simpleline_place_t s2(si->sv.size()-1); + si->cv = create_custom_viewer("", NULL, &s1, &s2, &s1, 0, &si->sv); + si->codeview = create_code_viewer(form, si->cv, CDVF_NOLINES); + set_code_viewer_lines_icon_margin(si->codeview, 2); + hook_to_notification_point(HT_UI, ui_callback, si); + open_tform(form, FORM_TAB|FORM_MENU|FORM_RESTORE); +} \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/ObjectExplorer.h b/sources/HexRaysCodeXplorer/ObjectExplorer.h new file mode 100644 index 0000000..e5c970b --- /dev/null +++ b/sources/HexRaysCodeXplorer/ObjectExplorer.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +#include "ida.hpp" +#include "netnode.hpp" +#include + +#include + + + +struct object_explorer_info_t +{ + TForm *form; + TCustomControl *cv; + TCustomControl *codeview; + strvec_t sv; + object_explorer_info_t(TForm *f) : form(f), cv(NULL) {} +}; + +void custom_form_init(); + + +struct tVTBL_info +{ + ea_t ea_begin; + ea_t ea_end; + UINT methods; + char name_size[MAXSTR]; +}; + + +extern qvector vtbl_list; +extern qvector ::iterator vtbl_iter; + + +BOOL get_vtbl_info(ea_t eaAddress, tVTBL_info &rtInfo); +inline BOOL is_valid_name(LPCSTR pszName){ return(*((PDWORD) pszName) == 0x375F3F3F /*"??_7"*/); } +void parse_vft_members(LPCTSTR lpszName, ea_t eaStart, ea_t eaEnd); + +void search_vtbl(); + + +template BOOL verify_32_t(ea_t ea_ptr, T &rvalue) +{ + if(getFlags(ea_ptr)) + { + rvalue = (T) get_32bit(ea_ptr); + return(TRUE); + } + + return(FALSE); +} \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/ObjectType.cpp b/sources/HexRaysCodeXplorer/ObjectType.cpp new file mode 100644 index 0000000..46a92b7 --- /dev/null +++ b/sources/HexRaysCodeXplorer/ObjectType.cpp @@ -0,0 +1,413 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + . +*/ + +#include "Common.h" +#include "ObjectType.h" + +struct type_builder_t : public ctree_parentee_t +{ + cexpr_t *highl_expr; + + char highl_expr_name[MAXSTR]; + + struct struct_filed + { + int offset; + int size; + }; + + std::vector structure; + + + int idaapi visit_expr(cexpr_t *e); + + char * get_structure(char * name, char * buffer, int buffer_size); + + int get_structure_size(); + + bool idaapi check_memptr(struct_filed &str_fld); + + bool idaapi check_idx(struct_filed &str_fld); + + bool idaapi check_helper(citem_t *parent, int &offs, int &size); + + bool idaapi check_ptr(struct_filed &str_fld); +}; + +int get_idx_type_size(cexpr_t *idx_expr) +{ + char buff[MAXSTR]; + print_type_to_one_line(buff, MAXSTR, idati, idx_expr->type.u_str()); + + if(strstr(buff, "char")) + return 1; + else if(strstr(buff, "short")) + return 2; + else if(strstr(buff, "int")) + return 4; + + return 0; +} + +bool idaapi type_builder_t::check_helper(citem_t *parent, int &off, int &num) +{ + if(parent->op == cot_call) + { + cexpr_t *expr_2 = (cexpr_t *)parent; + if(!strcmp(get_ctype_name(expr_2->x->op), "helper")) + { + char buff[MAXSTR]; + expr_2->x->print1(buff, MAXSTR, NULL); + tag_remove(buff, buff, 0); + + if(!strcmp(buff, "LOBYTE")) + { + num = 1; + off = 0; + } + else if(!strcmp(buff, "HIBYTE") || !strcmp(buff, "BYTE3")) + { + num = 1; + off = 3; + } + else if(!strcmp(buff, "BYTE1")) + { + num = 1; + off = 1; + } + else if(!strcmp(buff, "BYTE2")) + { + num = 1; + off = 2; + } + else if(!strcmp(buff, "LOWORD")) + { + num = 2; + off = 0; + } + else if(!strcmp(buff, "HIWORD")) + { + num = 2; + off = 2; + } + else + { + return false; + } + + return true; + } + } + + return false; +} + +bool idaapi type_builder_t::check_memptr(struct_filed &str_fld) +{ + // check if it has at least two parents + if ( parents.size() > 2 ) + { + citem_t *parent_1 = parents.back(); + + // check if its parent is memptr + if(parent_1->is_expr() && (parent_1->op == cot_memptr)) + { + citem_t *parent_2 = parents[parents.size() - 2]; + citem_t *parent_3 = NULL; + + int num = 0; + int off = 0; + + // check presence of the helper block + bool bHelper = check_helper(parent_2, off, num); + if(bHelper) + parent_3 = parents[parents.size() - 3]; + else + parent_3 = parent_2; + + if(parent_2->is_expr() && (parent_2->op == cot_asg)) + { + cexpr_t *expr = (cexpr_t *)parent_1; + + if(bHelper) + { + str_fld.offset = expr->m + off; + str_fld.size = num; + } + else + { + str_fld.offset = expr->m; + str_fld.size = expr->ptrsize; + } + + return true; + } + } + } + + return false; +} + +bool idaapi type_builder_t::check_ptr(struct_filed &str_fld) +{ + // check if it has at least three parents + if ( parents.size() > 2 ) + { + citem_t *parent_1 = parents.back(); + int offset = 0; + int parent_idx = 1; + + // if its parent is addition + if(parent_1->is_expr() && (parent_1->op == cot_add)) + { + parent_idx ++; + cexpr_t *expr_2 = (cexpr_t *)parent_1; + + // get index_value + char buff[MAXSTR]; + expr_2->y->print1(buff, MAXSTR, NULL); + tag_remove(buff, buff, 0); + offset = atoi(buff); + } + + citem_t *parent_3 = parents[parents.size() - parent_idx]; + if(parent_3->is_expr() && (parent_3->op == cot_cast)) + parent_idx ++; + + citem_t *parent_4 = parents[parents.size() - parent_idx]; + if(parent_4->is_expr() && (parent_4->op == cot_ptr)) + { + parent_idx ++; + citem_t *parent_5 = parents[parents.size() - parent_idx]; + + int num_hlpr = 0; + int off_hlpr = 0; + + bool bHelper = check_helper(parent_5, off_hlpr, num_hlpr); + if(bHelper) + parent_idx ++; + + citem_t *parent_6 = parents[parents.size() - parent_idx]; + if(parent_6->is_expr() && (parent_6->op == cot_asg)) + { + cexpr_t *expr_4 = (cexpr_t *)parent_4; + + if(bHelper) + { + str_fld.offset = offset + off_hlpr; + str_fld.size = num_hlpr; + } + else + { + str_fld.offset = offset; + str_fld.size = expr_4->ptrsize; + } + + return true; + } + } + } + + return false; +} + +bool idaapi type_builder_t::check_idx(struct_filed &str_fld) +{ + // check if it has at least two parents + if ( parents.size() > 1 ) + { + citem_t *parent_1 = parents.back(); + + // if its parrent is + if(parent_1->is_expr() && (parent_1->op == cot_memptr)) + { + citem_t *parent_2 = parents[parents.size() - 2]; + if(parent_2->op == cot_idx) + { + cexpr_t *expr_2 = (cexpr_t *)parent_2; + + // get index_value + char buff[MAXSTR]; + expr_2->y->print1(buff, MAXSTR, NULL); + tag_remove(buff, buff, 0); + int num = atoi(buff); + + citem_t *parent_3 = parents[parents.size() - 3]; + if(parent_3->is_expr() && (parent_3->op == cot_asg)) + { + cexpr_t *expr_1 = (cexpr_t *)parent_1; + + str_fld.offset = expr_1->m + num; + str_fld.size = get_idx_type_size(expr_2); + + return true; + } + } + } + } + + return false; +} + +int idaapi type_builder_t::visit_expr(cexpr_t *e) +{ + // check if the expression being visited is variable + if(e->op == cot_var) + { + // get the variable name + char expr_name[MAXSTR]; + e->print1(expr_name, MAXSTR, NULL); + tag_remove(expr_name, expr_name, 0); + + // check for the target variable + if(!strcmp(expr_name, highl_expr_name)) + { + struct_filed str_fld; + + if(check_memptr(str_fld)) + structure.push_back(str_fld); + else if(check_idx(str_fld)) + structure.push_back(str_fld); + else if(check_ptr(str_fld)) + structure.push_back(str_fld); + + } + } + + return 0; +} + +int type_builder_t::get_structure_size() +{ + int highest_offset = 0; + int reference_size = 0; + + + for(std::vector::iterator i = structure.begin(); i != structure.end() ; i ++) + { + if(highest_offset < i ->offset) + { + highest_offset = i ->offset; + reference_size = i->size; + } + } + + return highest_offset + reference_size; +} + +char * get_type_nm(int sz) +{ + switch(sz) + { + case 1: + return "char"; + case 2: + return "short"; + case 4: + return "int"; + } + + return "unk"; +} + +void sort_fields(std::vector &un) +{ + for(unsigned int i = 0 ; i < un.size() ; i ++) + for(unsigned int j = 0 ; j < un.size() - i - 1 ; j ++) + { + if(un[j].offset > un[j + 1].offset) + { + type_builder_t::struct_filed tmp = un[j]; + un[j] = un[j + 1]; + un[j + 1] = tmp; + } + } +} + +char * type_builder_t::get_structure(char * name, char * bufferr, int buffer_size) +{ + sort_fields(structure); + char *buffer = bufferr; + int offs = 0; + + buffer += sprintf_s(buffer, buffer_size - (int)(buffer - bufferr), "struct %s {\r\n", name); + for(unsigned int i = 0 ; i < structure.size() ; i ++) + { + if(structure[i].offset > offs) + { + buffer += sprintf_s(buffer, buffer_size - (int)(buffer - bufferr), "\tchar\tfiller_%d[%d];\r\n", i, structure[i].offset - offs); + offs = structure[i].offset; + } + + if(structure[i].offset == offs) + { + buffer += sprintf_s(buffer, buffer_size - (int)(buffer - bufferr), "\t%s\tfield_%d;\r\n", get_type_nm(structure[i].size), i); + offs += structure[i].size; + } + } + + buffer += sprintf_s(buffer, buffer_size - (int)(buffer - bufferr), "}"); + + return NULL; +} + + +bool idaapi reconstruct_type(void *ud) +{ + vdui_t &vu = *(vdui_t *)ud; + + // Determine the ctree item to highlight + vu.get_current_item(USE_KEYBOARD); + citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; + + // highlight == NULL might happen if one chooses variable at local variables declaration statement + if(highlight != NULL) + { + // the chosen item must be an expression and of 'variable' type + if(highlight->is_expr() && (highlight->op == cot_var)) + { + cexpr_t *highl_expr = (cexpr_t *)highlight; + + // initialize type rebuilder + type_builder_t type_bldr; + type_bldr.highl_expr = highl_expr; + + highl_expr->print1(type_bldr.highl_expr_name, MAXSTR, NULL); + tag_remove(type_bldr.highl_expr_name, type_bldr.highl_expr_name, 0); + + // traverse the ctree structure + type_bldr.apply_to(&vu.cfunc->body, NULL); + + // get the structure description + char buffr[MAXSTR*10]; + type_bldr.get_structure("STRUCTURE_TYPE", buffr, sizeof(buffr)); + msg("%s", buffr); + } + } + else + { + msg("Invalid item is choosen"); + } + + return true; +} \ No newline at end of file diff --git a/sources/HexRaysCodeXplorer/ObjectType.h b/sources/HexRaysCodeXplorer/ObjectType.h new file mode 100644 index 0000000..8cd946f --- /dev/null +++ b/sources/HexRaysCodeXplorer/ObjectType.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2013 + REhints + All rights reserved. + + ============================================================================ + + This file is part of HexRaysCodeXplorer + + HexRaysCodeXplorer is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; + +typedef std::basic_string TSTRING; +typedef std::basic_string WSTRING; +typedef std::basic_string ASTRING; +typedef std::vector BUFFER; + +#ifdef _UNICODE +#define tcout std::wcout +#else +#define tcout std::cout +#endif + + +bool idaapi reconstruct_type(void *ud); \ No newline at end of file