-
Notifications
You must be signed in to change notification settings - Fork 377
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
2,794 additions
and
0 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,375 @@ | ||
/* Copyright (c) 2013 | ||
REhints <info@rehints.com> | ||
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 | ||
<http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
|
||
#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<citem_t *, int> 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 | ||
}; |
Oops, something went wrong.