├── .gitattributes ├── CodeXplorer v2.0 [BH Edition] ├── bin │ ├── linux │ │ └── HexRaysCodeXplorer.plx │ └── win │ │ ├── HexRaysCodeXplorer.p64 │ │ └── HexRaysCodeXplorer.plw └── source code │ ├── HexRaysCodeXplorer.sln │ └── HexRaysCodeXplorer │ ├── CodeXplorer.cpp │ ├── Common.h │ ├── CtreeExtractor.cpp │ ├── CtreeExtractor.h │ ├── Debug.cpp │ ├── Debug.h │ ├── GraphBuilder.cpp │ ├── GraphBuilder.h │ ├── HexRaysCodeXplorer.vcxproj │ ├── HexRaysCodeXplorer.vcxproj.user │ ├── Linux.h │ ├── ObjectExplorer.cpp │ ├── ObjectExplorer.h │ ├── ObjectFormatMSVC.cpp │ ├── ObjectFormatMSVC.h │ ├── TypeExtractor.cpp │ ├── TypeExtractor.h │ ├── TypeReconstructor.cpp │ ├── TypeReconstructor.h │ ├── Utility.cpp │ ├── Utility.h │ └── makefile ├── CodeXplorer_Test ├── test_all_ctress.py ├── test_ctrees.py └── test_ctrees_batch.py ├── README.md ├── crypto_scan ├── crypto_scan.py └── idascope │ ├── __init__.py │ └── core │ ├── CryptoIdentifier.py │ ├── IdaProxy.py │ ├── __init__.py │ ├── helpers │ ├── GraphHelper.py │ ├── Misc.py │ ├── PatternManager.py │ └── __init__.py │ └── structures │ ├── AritlogBasicBlock.py │ ├── CryptoSignatureHit.py │ ├── Segment.py │ └── __init__.py ├── depth_scan ├── README.md └── depth_scan.py └── slides_BHUS_2015.pdf /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.pdf diff=astextplain 3 | *.pdf diff=astextplain -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/bin/linux/HexRaysCodeXplorer.plx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/BlackHat_2015/209ed880816cbdceca5188ed1146a9bdd46b7cde/CodeXplorer v2.0 [BH Edition]/bin/linux/HexRaysCodeXplorer.plx -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/bin/win/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/BlackHat_2015/209ed880816cbdceca5188ed1146a9bdd46b7cde/CodeXplorer v2.0 [BH Edition]/bin/win/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/bin/win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/BlackHat_2015/209ed880816cbdceca5188ed1146a9bdd46b7cde/CodeXplorer v2.0 [BH Edition]/bin/win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HexRaysCodeXplorer", "HexRaysCodeXplorer\HexRaysCodeXplorer.vcxproj", "{F7E6B557-41F3-444A-BCA4-3527547DD665}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug x64|Win32 = Debug x64|Win32 11 | Debug x64|x64 = Debug x64|x64 12 | Debug|Win32 = Debug|Win32 13 | Debug|x64 = Debug|x64 14 | Release x64|Win32 = Release x64|Win32 15 | Release x64|x64 = Release x64|x64 16 | Release|Win32 = Release|Win32 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|Win32.ActiveCfg = Debug x64|Win32 21 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|Win32.Build.0 = Debug x64|Win32 22 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|x64.ActiveCfg = Debug x64|x64 23 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|x64.Build.0 = Debug x64|x64 24 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|Win32.Build.0 = Debug|Win32 26 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|x64.ActiveCfg = Debug|x64 27 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|x64.Build.0 = Debug|x64 28 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|Win32.ActiveCfg = Release x64|Win32 29 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|Win32.Build.0 = Release x64|Win32 30 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|x64.ActiveCfg = Release x64|x64 31 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|x64.Build.0 = Release x64|x64 32 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|Win32.ActiveCfg = Release|Win32 33 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|Win32.Build.0 = Release|Win32 34 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|x64.ActiveCfg = Release|x64 35 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|x64.Build.0 = Release|x64 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | VisualSVNWorkingCopyRoot = . 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/CodeXplorer.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see 21 | . 22 | 23 | ============================================================================== 24 | */ 25 | 26 | #include "Common.h" 27 | #include "GraphBuilder.h" 28 | #include "ObjectExplorer.h" 29 | #include "TypeReconstructor.h" 30 | #include "TypeExtractor.h" 31 | #include "CtreeExtractor.h" 32 | #include "Utility.h" 33 | 34 | #include "Debug.h" 35 | 36 | extern plugin_t PLUGIN; 37 | 38 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 39 | 40 | 41 | // Hex-Rays API pointer 42 | hexdsp_t *hexdsp = NULL; 43 | 44 | static bool inited = false; 45 | 46 | // Hotkey for the new command 47 | static const char hotkey_dg[] = "T"; 48 | static int hotcode_dg; 49 | 50 | static const char hotkey_ce[] = "O"; 51 | static int hotcode_ce; 52 | 53 | static const char hotkey_rt[] = "R"; 54 | static int hotcode_rt; 55 | 56 | static const char hotkey_gd[] = "J"; 57 | static int hotcode_gd; 58 | 59 | static const char hotkey_et[] = "S"; 60 | static int hotcode_et; 61 | 62 | static const char hotkey_ec[] = "C"; 63 | static int hotcode_ec; 64 | 65 | static const char hotkey_vc[] = "V"; 66 | static int hotcode_vc; 67 | 68 | static const char * crypto_prefix_param = "CRYPTO"; 69 | 70 | 71 | 72 | //-------------------------------------------------------------------------- 73 | // Helper class to build graph from ctree. 74 | struct graph_builder_t : public ctree_parentee_t 75 | { 76 | callgraph_t &cg; 77 | std::map reverse; // Reverse mapping for tests and adding edges 78 | 79 | graph_builder_t(callgraph_t &_cg) : cg(_cg) {} 80 | 81 | // overriding functions 82 | int add_node(citem_t *i); 83 | int process(citem_t *i); 84 | 85 | // We treat expressions and statements the same way: add them to the graph 86 | int idaapi visit_insn(cinsn_t *i) { return process(i); } 87 | int idaapi visit_expr(cexpr_t *e) { return process(e); } 88 | }; 89 | 90 | // Add a new node to the graph 91 | int graph_builder_t::add_node(citem_t *i) 92 | { 93 | // Check if the item has already been encountered during the traversal 94 | if ( reverse.find(i) != reverse.end() ) 95 | { 96 | warning("bad ctree - duplicate nodes!"); 97 | logmsg(DEBUG, "bad ctree - duplicate nodes!"); 98 | return -1; 99 | } 100 | 101 | // Add a node to the graph 102 | int n = cg.add(i); 103 | 104 | // Also remember the reverse mapping (citem_t* -> n) 105 | reverse[i] = n; 106 | 107 | return n; 108 | } 109 | 110 | // Process a ctree item 111 | int graph_builder_t::process(citem_t *item) 112 | { 113 | // Add a node for citem 114 | int n = add_node(item); 115 | if ( n == -1 ) 116 | return -1; // error 117 | 118 | if ( parents.size() > 1 ) // The current item has a parent? 119 | { 120 | int p = reverse[parents.back()]; // Parent node number 121 | // cg.add_edge(p, n); // Add edge from the parent to the current item 122 | cg.create_edge(p, n); 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | #define DECLARE_GI_VAR \ 129 | graph_info_t *gi = (graph_info_t *) ud 130 | 131 | #define DECLARE_GI_VARS \ 132 | DECLARE_GI_VAR; \ 133 | callgraph_t *fg = &gi->fg 134 | 135 | //-------------------------------------------------------------------------- 136 | static int idaapi gr_callback(void *ud, int code, va_list va) 137 | { 138 | bool result = false; 139 | switch ( code ) 140 | { 141 | // refresh user-defined graph nodes and edges 142 | case grcode_user_refresh: 143 | // in: mutable_graph_t *g 144 | // out: success 145 | { 146 | DECLARE_GI_VARS; 147 | func_t *f = get_func(gi->func_ea); 148 | if (f == NULL) 149 | break; 150 | 151 | graph_builder_t gb(*fg); // Graph builder helper class 152 | gb.apply_to(&gi->vu->cfunc->body, NULL); 153 | 154 | mutable_graph_t *mg = va_arg(va, mutable_graph_t *); 155 | 156 | // we have to resize 157 | mg->resize(fg->count()); 158 | 159 | callgraph_t::edge_iterator end = fg->end_edges(); 160 | for ( callgraph_t::edge_iterator it=fg->begin_edges(); 161 | it != end; 162 | ++it ) 163 | { 164 | mg->add_edge(it->id1, it->id2, NULL); 165 | } 166 | 167 | fg->clear_edges(); 168 | result = true; 169 | } 170 | break; 171 | 172 | // retrieve text for user-defined graph node 173 | case grcode_user_text: 174 | //mutable_graph_t *g 175 | // int node 176 | // const char **result 177 | // bgcolor_t *bg_color (maybe NULL) 178 | // out: must return 0, result must be filled 179 | // NB: do not use anything calling GDI! 180 | { 181 | DECLARE_GI_VARS; 182 | va_arg(va, mutable_graph_t *); 183 | int node = va_arg(va, int); 184 | const char **text = va_arg(va, const char **); 185 | bgcolor_t *bgcolor = va_arg(va, bgcolor_t *); 186 | 187 | callgraph_t::nodeinfo_t *ni = fg->get_info(node); 188 | result = ni != NULL; 189 | if ( result ) 190 | { 191 | *text = ni->name.c_str(); 192 | if ( bgcolor != NULL ) 193 | *bgcolor = ni->color; 194 | } 195 | } 196 | break; 197 | 198 | case grcode_user_hint: 199 | { 200 | DECLARE_GI_VARS; 201 | va_arg(va, mutable_graph_t *); 202 | int mousenode = va_argi(va, int); 203 | int to = va_argi(va, int); 204 | int from = va_argi(va, int); 205 | char **hint = va_arg(va, char **); 206 | 207 | callgraph_t::nodeinfo_t *ni = fg->get_info(mousenode); 208 | result = ni != NULL; 209 | if (result && ni->ea != BADADDR) 210 | { 211 | qstring s = get_text_disasm(ni->ea); 212 | *hint = qstrdup(s.c_str()); 213 | } 214 | } 215 | break; 216 | 217 | case grcode_dblclicked: 218 | { 219 | DECLARE_GI_VARS; 220 | graph_viewer_t *v = va_arg(va, graph_viewer_t *); 221 | selection_item_t *s = va_arg(va, selection_item_t *); 222 | 223 | callgraph_t::nodeinfo_t *ni = fg->get_info(s->node); 224 | result = ni != NULL; 225 | if (result && s->is_node && ni->ea != BADADDR) 226 | jumpto(ni->ea); 227 | } 228 | break; 229 | 230 | } 231 | return (int)result; 232 | } 233 | 234 | 235 | // Display ctree graph for current decompiled function 236 | static bool idaapi display_graph(void *ud) 237 | { 238 | vdui_t &vu = *(vdui_t *)ud; 239 | 240 | // Determine the ctree item to highlight 241 | vu.get_current_item(USE_KEYBOARD); 242 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 243 | graph_info_t *gi = graph_info_t::create(vu.cfunc->entry_ea, highlight); 244 | 245 | netnode id; 246 | id.create(); 247 | 248 | qstring title = gi->title; 249 | 250 | HWND hwnd = NULL; 251 | TForm *form = create_tform(title.c_str(), &hwnd); 252 | if (hwnd == NULL) 253 | { 254 | warning("Ctree Graph window already open. Switching to it."); 255 | logmsg(DEBUG, "Ctree Graph window already open. Switching to it."); 256 | form = find_tform(title.c_str()); 257 | if (form != NULL) 258 | switchto_tform(form, true); 259 | return true; 260 | } 261 | 262 | if (hwnd != NULL) 263 | { 264 | gi->vu = (vdui_t *)ud; 265 | gi->form = form; 266 | gi->gv = create_graph_viewer(form, id, gr_callback, gi, 0); 267 | open_tform(form, FORM_TAB | FORM_MENU | FORM_QWIDGET); 268 | 269 | viewer_fit_window(gi->gv); 270 | } 271 | 272 | return true; 273 | } 274 | 275 | 276 | // Get pointer to func_t by routine name 277 | func_t * get_func_by_name(const char *func_name) 278 | { 279 | func_t * result_func = NULL; 280 | size_t func_total = get_func_qty(); 281 | if(func_total > 0) 282 | { 283 | char tmp[1024]; 284 | for (unsigned int i = 0 ; i < func_total - 1 ; i ++) 285 | { 286 | func_t * func = getn_func(i); 287 | if(func != NULL) 288 | { 289 | memset(tmp, 0x00, sizeof(tmp)); 290 | char *func_n = get_func_name(func->startEA, tmp, sizeof(tmp)); 291 | if(func_n != NULL) 292 | { 293 | if(!strcmp(func_name, func_n)) 294 | { 295 | result_func = func; 296 | break; 297 | } 298 | } 299 | } 300 | } 301 | } 302 | return result_func; 303 | } 304 | 305 | 306 | static char* get_expr_name(citem_t *citem) 307 | { 308 | static char citem_name[1024]; 309 | memset(citem_name, 0x00, sizeof(citem_name)); 310 | if (citem->is_expr()) 311 | { 312 | cexpr_t *e = (cexpr_t *)citem; 313 | 314 | // retrieve the name of the routine 315 | e->print1(citem_name, sizeof(citem_name), NULL); 316 | tag_remove(citem_name, citem_name, sizeof(citem_name)); 317 | 318 | return citem_name; 319 | } 320 | return citem_name; 321 | } 322 | 323 | 324 | static bool idaapi decompile_func(vdui_t &vu) 325 | { 326 | // Determine the ctree item to highlight 327 | vu.get_current_item(USE_KEYBOARD); 328 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 329 | 330 | if(highlight != NULL) 331 | { 332 | // if it is an expression 333 | if(highlight->is_expr()) 334 | { 335 | cexpr_t *e = (cexpr_t *)highlight; 336 | 337 | char *citem_name = get_expr_name(highlight); 338 | char *proc_name = citem_name + strlen(citem_name); 339 | 340 | while((proc_name > citem_name) && (*(proc_name - 1) != '>')) 341 | proc_name --; 342 | 343 | if (proc_name != citem_name) { 344 | func_t * func = get_func_by_name(proc_name); 345 | if(func != NULL) 346 | { 347 | vdui_t * decompiled_window = open_pseudocode(func->startEA, -1); 348 | } 349 | } 350 | } 351 | } 352 | 353 | return true; 354 | } 355 | 356 | 357 | // show disassembly line for ctree->item 358 | static bool idaapi decompiled_line_to_disasm(void *ud) 359 | { 360 | vdui_t &vu = *(vdui_t *)ud; 361 | vu.ctree_to_disasm(); 362 | 363 | vu.get_current_item(USE_KEYBOARD); 364 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 365 | 366 | return true; 367 | } 368 | 369 | 370 | // extract ctree to custom view 371 | static bool idaapi current_citem_to_custom_view(void *ud) 372 | { 373 | vdui_t &vu = *(vdui_t *)ud; 374 | vu.get_current_item(USE_KEYBOARD); 375 | citem_t *highlight_item = vu.item.is_citem() ? vu.item.e : NULL; 376 | ctree_dumper_t ctree_dump; 377 | 378 | if (highlight_item != NULL) 379 | { 380 | char ctree_item[MAXSTR]; 381 | ctree_dump.parse_ctree_item(highlight_item, ctree_item, MAXSTR); 382 | 383 | if (highlight_item->is_expr()) 384 | { 385 | cexpr_t *e = (cexpr_t *)highlight_item; 386 | qstring item_name = get_expr_name(highlight_item); 387 | show_citem_custom_view(&vu, ctree_item, item_name); 388 | } 389 | } 390 | return true; 391 | } 392 | 393 | 394 | // display Object Explorer 395 | static bool idaapi display_objects(void *ud) 396 | { 397 | vdui_t &vu = *(vdui_t *)ud; 398 | search_objects(); 399 | object_explorer_form_init(); 400 | 401 | return true; 402 | } 403 | 404 | 405 | //-------------------------------------------------------------------------- 406 | // This callback handles various hexrays events. 407 | static int idaapi callback(void *, hexrays_event_t event, va_list va) 408 | { 409 | switch ( event ) 410 | { 411 | case hxe_right_click: 412 | { 413 | vdui_t &vu = *va_arg(va, vdui_t *); 414 | // add new command to the popup menu 415 | add_custom_viewer_popup_item(vu.ct, "Display Ctree Graph", hotkey_dg, display_graph, &vu); 416 | add_custom_viewer_popup_item(vu.ct, "Object Explorer", hotkey_ce, display_objects, &vu); 417 | add_custom_viewer_popup_item(vu.ct, "REconstruct Type", hotkey_rt, reconstruct_type, &vu); 418 | add_custom_viewer_popup_item(vu.ct, "Extract Types to File", hotkey_et, extract_all_types, &vu); 419 | add_custom_viewer_popup_item(vu.ct, "Extract Ctrees to File", hotkey_ec, extract_all_ctrees, &vu); 420 | add_custom_viewer_popup_item(vu.ct, "Ctree Item View", hotkey_vc, current_citem_to_custom_view, &vu); 421 | add_custom_viewer_popup_item(vu.ct, "Jump to Disasm", hotkey_gd, decompiled_line_to_disasm, &vu); 422 | } 423 | break; 424 | 425 | case hxe_keyboard: 426 | { 427 | vdui_t &vu = *va_arg(va, vdui_t *); 428 | int keycode = va_arg(va, int); 429 | // check for the hotkey 430 | if (keycode == hotcode_dg) 431 | return display_graph(&vu); 432 | if (keycode == hotcode_ce) 433 | return display_objects(&vu); 434 | if (keycode == hotcode_rt) 435 | return reconstruct_type(&vu); 436 | if (keycode == hotcode_et) 437 | return extract_all_types(&vu); 438 | if (keycode == hotcode_ec) 439 | return extract_all_ctrees(&vu); 440 | if (keycode == hotcode_vc) 441 | return current_citem_to_custom_view(&vu); 442 | if (keycode == hotcode_gd) 443 | return decompiled_line_to_disasm(&vu); 444 | } 445 | break; 446 | 447 | case hxe_double_click: 448 | { 449 | vdui_t &vu = *va_arg(va, vdui_t *); 450 | decompile_func(vu); 451 | } 452 | break; 453 | default: 454 | break; 455 | } 456 | return 0; 457 | } 458 | 459 | void parse_plugin_options(qstring &options, bool &dump_types, bool &dump_ctrees, qstring &crypto_prefix) { 460 | qvector params; 461 | qstring splitter = ":"; 462 | split_qstring(options, splitter, params); 463 | 464 | dump_types = false; 465 | dump_ctrees = false; 466 | crypto_prefix = ""; 467 | 468 | for (qvector::iterator param_iter = params.begin() ; param_iter != params.end() ; param_iter ++) { 469 | if ((*param_iter) == "dump_types") { 470 | dump_types = true; 471 | } else if ((*param_iter) == "dump_ctrees") { 472 | dump_ctrees = true; 473 | } else if (((*param_iter).length() > strlen(crypto_prefix_param)) && ((*param_iter).find(crypto_prefix_param) == 0)) { 474 | crypto_prefix = (*param_iter).substr(strlen(crypto_prefix_param)); 475 | } else { 476 | qstring message = "Invalid argument: "; 477 | message += (*param_iter) + "\n"; 478 | logmsg(INFO, message.c_str()); 479 | } 480 | } 481 | } 482 | 483 | //-------------------------------------------------------------------------- 484 | // Initialize the plugin. 485 | int idaapi init(void) 486 | { 487 | logmsg(INFO, "\nHexRaysCodeXplorer plugin by @REhints loaded.\n\n\n"); 488 | 489 | if ( !init_hexrays_plugin() ) 490 | return PLUGIN_SKIP; // no decompiler 491 | bool dump_types = false, 492 | dump_ctrees = false; 493 | qstring crypto_prefix; 494 | 495 | qstring options = get_plugin_options(PLUGIN.wanted_name); 496 | parse_plugin_options(options, dump_types, dump_ctrees, crypto_prefix); 497 | 498 | install_hexrays_callback(callback, NULL); 499 | const char *hxver = get_hexrays_version(); 500 | logmsg(INFO, "Hex-rays version %s has been detected, %s ready to use\n", hxver, PLUGIN.wanted_name); 501 | inited = true; 502 | hotcode_dg = 84; // T 503 | hotcode_ce = 79; // O 504 | hotcode_rt = 82; // R 505 | hotcode_gd = 74; // J 506 | hotcode_et = 83; // S 507 | hotcode_ec = 67; // C 508 | hotcode_vc = 86; // V 509 | 510 | static const char hotkey_vc[] = "V"; 511 | static int hotcode_vc; 512 | 513 | if (dump_ctrees || dump_types) { 514 | autoWait(); 515 | 516 | if (dump_types) { 517 | qstring options_msg = "Dumping types\n"; 518 | logmsg(DEBUG, options_msg.c_str()); 519 | extract_all_types(NULL); 520 | 521 | int file_id = qcreate("codexplorer_types_done", 511); 522 | if (file_id != -1) 523 | qclose(file_id); 524 | } 525 | 526 | if (dump_ctrees) { 527 | logmsg(DEBUG, "Dumping ctrees\n"); 528 | dump_funcs_ctree(NULL, crypto_prefix); 529 | 530 | int file_id = qcreate("codexplorer_ctrees_done", 511); 531 | if (file_id != -1) 532 | qclose(file_id); 533 | } 534 | 535 | logmsg(INFO, "\nHexRaysCodeXplorer plugin by @REhints exiting...\n\n\n"); 536 | //qexit(0); 537 | } 538 | 539 | return PLUGIN_KEEP; 540 | } 541 | 542 | //-------------------------------------------------------------------------- 543 | void idaapi term(void) 544 | { 545 | if ( inited ) 546 | { 547 | logmsg(INFO, "\nHexRaysCodeXplorer plugin by @REhints terminated.\n\n\n"); 548 | remove_hexrays_callback(callback, NULL); 549 | term_hexrays_plugin(); 550 | } 551 | } 552 | 553 | //-------------------------------------------------------------------------- 554 | void idaapi run(int) 555 | { 556 | // This function won't be called because our plugin is invisible (no menu 557 | // item in the Edit, Plugins menu) because of PLUGIN_HIDE 558 | } 559 | 560 | //-------------------------------------------------------------------------- 561 | static char comment[] = "HexRaysCodeXplorer plugin by @REhints"; 562 | 563 | //-------------------------------------------------------------------------- 564 | // 565 | // PLUGIN DESCRIPTION BLOCK 566 | // 567 | //-------------------------------------------------------------------------- 568 | plugin_t PLUGIN = 569 | { 570 | IDP_INTERFACE_VERSION, 571 | PLUGIN_HIDE, // plugin flags 572 | init, // initialize 573 | term, // terminate. this pointer may be NULL. 574 | run, // invoke plugin 575 | comment, // long comment about the plugin 576 | // it could appear in the status line or as a hint 577 | "", // multiline help about the plugin 578 | "HexRaysCodeXplorer by @REhints", // the preferred short name of the plugin (PLUGIN.wanted_name) 579 | "" // the preferred hotkey to run the plugin 580 | }; 581 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/Common.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #ifndef __H_COMMON__ 26 | #define __H_COMMON__ 27 | 28 | #pragma once 29 | 30 | #ifndef __LINUX__ 31 | #pragma warning (disable: 4996 4800 ) 32 | #else 33 | #pragma GCC diagnostic ignored "-fpermissive" 34 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 35 | #endif 36 | 37 | #ifndef __LINUX__ 38 | #include 39 | #include 40 | #else 41 | #include "Linux.h" 42 | #endif 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | #include 64 | #include 65 | #include 66 | 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | 76 | #endif 77 | 78 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/CtreeExtractor.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see 21 | . 22 | 23 | ============================================================================== 24 | */ 25 | 26 | #include "Common.h" 27 | #include "TypeReconstructor.h" 28 | #include "CtreeExtractor.h" 29 | #include "Utility.h" 30 | #include "Debug.h" 31 | 32 | #ifdef __LINUX__ 33 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 34 | #endif 35 | 36 | #define MIN_HEURISTIC_FUNC_SIZE_DUMP 0x160 37 | #define MIN_FUNC_SIZE_DUMP 0x60 38 | 39 | #define N_FUNCS_TO_DUMP 40 40 | #define N_HEUR_FUNCS_TO_DUMP 60 41 | #define N_CRYPTO_FUNCS_TO_DUMP 30 42 | 43 | #define MAX_FUNC_DEPTH 100 44 | 45 | bool idaapi ctree_dumper_t::filter_citem(citem_t *item) { 46 | if (item->is_expr()) { 47 | cexpr_t * expr = (cexpr_t *)item; 48 | 49 | if (item->op == cot_cast) 50 | return true; 51 | else if (item->op == cot_helper) 52 | return true; 53 | else if ((item->op >= cot_postinc) && (item->op <= cot_predec)) 54 | return true; 55 | else if ((item->op >= cot_idx) && ((item->op <= cot_last))) 56 | return true; 57 | } else { 58 | if (item->op == cit_expr) 59 | return true; 60 | } 61 | 62 | return false; 63 | } 64 | 65 | void ctree_dumper_t::process_for_hash(citem_t *item) 66 | { 67 | if (!filter_citem(item)) { 68 | const char* ctype_name = get_ctype_name(item->op); 69 | ctree_for_hash.cat_sprnt("%s:", ctype_name); 70 | } 71 | } 72 | 73 | // Process a ctree item 74 | int ctree_dumper_t::process(citem_t *item) 75 | { 76 | int parent_count = parents.size(); 77 | if (parent_count > 1) { 78 | ctree_dump += "("; 79 | } 80 | 81 | char buf[MAXSTR]; 82 | parse_ctree_item(item, buf, MAXSTR); 83 | ctree_dump.cat_sprnt("%s", buf); 84 | 85 | process_for_hash(item); 86 | return 0; 87 | } 88 | 89 | int ctree_dumper_t::process_leave(citem_t *item) 90 | { 91 | int parent_count = parents.size(); 92 | if (parent_count > 1) { 93 | ctree_dump += ")"; 94 | } 95 | return 0; 96 | } 97 | 98 | char * ctree_dumper_t::parse_ctree_item(citem_t *item, char *buf, int bufsize) const 99 | { 100 | char *ptr = buf; 101 | char *endp = buf + bufsize; 102 | 103 | // Each node will have the element type at the first line 104 | APPEND(ptr, endp, get_ctype_name(item->op)); 105 | const cexpr_t *e = (const cexpr_t *)item; 106 | const cinsn_t *i = (const cinsn_t *)item; 107 | 108 | // For some item types, display additional information 109 | switch (item->op) 110 | { 111 | case cot_call: 112 | char buf[MAXSTR]; 113 | if (e->x->op == cot_obj) { 114 | if (get_func_name(e->x->obj_ea, buf, sizeof(buf)) == NULL) 115 | ptr += qsnprintf(ptr, endp - ptr, " sub_%a", e->x->obj_ea); 116 | else 117 | ptr += qsnprintf(ptr, endp - ptr, " %s", buf); 118 | } 119 | break; 120 | case cot_ptr: // *x 121 | case cot_memptr: // x->m 122 | // Display access size for pointers 123 | ptr += qsnprintf(ptr, endp - ptr, ".%d", e->ptrsize); 124 | if (item->op == cot_ptr) 125 | break; 126 | case cot_memref: // x.m 127 | // Display member offset for structure fields 128 | ptr += qsnprintf(ptr, endp - ptr, " (m=%d)", e->m); 129 | break; 130 | case cot_obj: // v 131 | case cot_var: // l 132 | // Display object size for local variables and global data 133 | ptr += qsnprintf(ptr, endp - ptr, ".%d", e->refwidth); 134 | case cot_num: // n 135 | case cot_helper: // arbitrary name 136 | case cot_str: // string constant 137 | // Display helper names and number values 138 | APPCHAR(ptr, endp, ' '); 139 | e->print1(ptr, endp - ptr, NULL); 140 | tag_remove(ptr, ptr, 0); 141 | ptr = tail(ptr); 142 | break; 143 | case cit_goto: 144 | // Display target label number for gotos 145 | ptr += qsnprintf(ptr, endp - ptr, " LABEL_%d", i->cgoto->label_num); 146 | break; 147 | case cit_asm: 148 | // Display instruction block address and size for asm-statements 149 | ptr += qsnprintf(ptr, endp - ptr, " %a.%" FMT_Z, *i->casm->begin(), i->casm->size()); 150 | break; 151 | default: 152 | break; 153 | } 154 | 155 | // The second line of the node contains the item address 156 | ptr += qsnprintf(ptr, endp - ptr, ";ea->%a", item->ea); 157 | 158 | if ( item->is_expr() && !e->type.empty() ) 159 | { 160 | // For typed expressions, the third line will have 161 | // the expression type in human readable form 162 | APPCHAR(ptr, endp, ';'); 163 | qstring out; 164 | if (e->type.print(&out)) 165 | { 166 | APPEND(ptr, endp, out.c_str()); 167 | } 168 | else 169 | { // could not print the type? 170 | APPCHAR(ptr, endp, '?'); 171 | APPZERO(ptr, endp); 172 | } 173 | 174 | if(e->type.is_ptr()) 175 | { 176 | tinfo_t ptr_rem = ::remove_pointer(e->type); 177 | if(ptr_rem.is_struct()) 178 | { 179 | qstring typenm; 180 | ptr_rem.print(&typenm, "prefix ", 0, 0, PRTYPE_MULTI | PRTYPE_TYPE | PRTYPE_SEMI); 181 | } 182 | } 183 | } 184 | 185 | return buf; 186 | } 187 | 188 | struct ctree_dump_line { 189 | qvector referres; 190 | qstring ctree_for_hash; 191 | qstring ctree_dump; 192 | qstring func_name; 193 | int func_depth; 194 | ea_t func_start; 195 | ea_t func_end; 196 | bool heuristic_flag; 197 | }; 198 | 199 | 200 | int create_open_file(const char* file_name) { 201 | int file_id = qopen(file_name, O_BINARY | O_TRUNC | O_CREAT); 202 | if (file_id == BADADDR) 203 | file_id = qcreate(file_name, 511); 204 | 205 | return file_id; 206 | } 207 | 208 | int get_hash_of_string(qstring &string_to_hash, qstring &hash) { 209 | SHA1Context sha; 210 | uint8_t Message_Digest[SHA1HashSize]; 211 | int err; 212 | 213 | err = SHA1Reset(&sha); 214 | if (err == shaSuccess) { 215 | err = SHA1Input(&sha, (uint8_t *)string_to_hash.c_str(), string_to_hash.length()); 216 | if (err == shaSuccess) { 217 | err = err = SHA1Result(&sha, Message_Digest); 218 | if (err == shaSuccess) { 219 | char digest_hex[SHA1HashSize * 2 + 1]; 220 | memset(digest_hex, 0x00, sizeof(digest_hex)); 221 | SHA1MessageDigestToString(Message_Digest, digest_hex); 222 | 223 | hash = digest_hex; 224 | } 225 | } 226 | } 227 | 228 | return err; 229 | } 230 | 231 | void dump_ctrees_in_file(std::map &data_to_dump, qstring &crypto_prefix) { 232 | int file_id = create_open_file("ctrees.txt"); 233 | if (file_id != -1) { 234 | 235 | size_t crypt_prefix_len = crypto_prefix.length(); 236 | 237 | for (std::map::iterator ctrees_iter = data_to_dump.begin(); ctrees_iter != data_to_dump.end() ; ctrees_iter ++) { 238 | qstring sha_hash; 239 | int err = get_hash_of_string((*ctrees_iter).second.ctree_for_hash, sha_hash); 240 | if (err == shaSuccess) { 241 | qstring dump_line = sha_hash + ";"; 242 | err = get_hash_of_string((*ctrees_iter).second.ctree_dump, sha_hash); 243 | if (err == shaSuccess) { 244 | dump_line += sha_hash + ";"; 245 | dump_line += (*ctrees_iter).second.ctree_dump; 246 | dump_line.cat_sprnt(";%d", (*ctrees_iter).second.func_depth); 247 | dump_line.cat_sprnt(";%08X", (*ctrees_iter).second.func_start); 248 | dump_line.cat_sprnt(";%08X", (*ctrees_iter).second.func_end); 249 | if (((*ctrees_iter).second.func_name.length() > crypt_prefix_len) && (crypt_prefix_len > 0) && ((*ctrees_iter).second.func_name.find(crypto_prefix) == 0)) 250 | dump_line.cat_sprnt(";E", (*ctrees_iter).second.func_end); 251 | else 252 | dump_line.cat_sprnt(";N", (*ctrees_iter).second.func_end); 253 | 254 | if (((*ctrees_iter).second.heuristic_flag)) 255 | dump_line.cat_sprnt(";H", (*ctrees_iter).second.func_end); 256 | else 257 | dump_line.cat_sprnt(";N", (*ctrees_iter).second.func_end); 258 | 259 | dump_line += "\n"; 260 | } 261 | 262 | qwrite(file_id, dump_line.c_str(), dump_line.length()); 263 | 264 | } 265 | if (err != shaSuccess) { 266 | logmsg(ERROR, "Error in computing SHA1 hash\r\n"); 267 | } 268 | } 269 | 270 | qclose(file_id); 271 | } else { 272 | logmsg(ERROR, "Failed to open file for dumping ctress\r\n"); 273 | } 274 | } 275 | 276 | 277 | inline bool func_name_has_prefix(qstring &prefix, ea_t startEA) { 278 | qstring func_name; 279 | 280 | if (prefix.length() <= 0) 281 | return false; 282 | 283 | if (get_func_name2(&func_name, startEA) == 0) 284 | return false; 285 | 286 | if (func_name.length() <= 0) 287 | return false; 288 | 289 | if (func_name.find(prefix.c_str(), 0) == -1) 290 | return false; 291 | 292 | return true; 293 | } 294 | 295 | bool idaapi dump_funcs_ctree(void *ud, qstring &crypto_prefix) 296 | { 297 | logmsg(DEBUG, "dump_funcs_ctree entered\n"); 298 | 299 | std::map data_to_dump; 300 | 301 | // enumerate through all the functions in the idb file 302 | bool heuristic_flag; 303 | size_t count = 0, heur_count = 0, crypto_count = 0; 304 | size_t total_func_qty = get_func_qty(); 305 | for (size_t i = 0 ; i < total_func_qty ; i ++) { 306 | heuristic_flag = 0; 307 | 308 | func_t *function = getn_func(i); 309 | if (function != NULL) { 310 | bool crypto_flag = func_name_has_prefix(crypto_prefix, function->startEA); 311 | 312 | // skip libs that are not marked as crypto 313 | if ( ((function->flags & FUNC_LIB) != 0) && !crypto_flag ) 314 | continue; 315 | 316 | // From this point on, we have a function outside of lib or a crypto one 317 | 318 | // Ignore functions less than MIN_FUNC_SIZE_DUMP bytes 319 | if ( ((function->endEA - function->startEA) < MIN_FUNC_SIZE_DUMP) && !crypto_flag ) 320 | continue; 321 | 322 | // If function is bigger than MIN_HEURISTIC_FUNC_SIZE_DUMP, mark as being triggered by the heuristic 323 | if (function->endEA - function->startEA > MIN_HEURISTIC_FUNC_SIZE_DUMP) 324 | heuristic_flag = 1; 325 | 326 | // dump up to N_CRYPTO_FUNCS_TO_DUMP crypto functions 327 | // dump up to N_HEUR_FUNCS_TO_DUMP heuristic functions 328 | // at least N_FUNCS_TO_DUMP functions will be dumped 329 | if ((count < N_FUNCS_TO_DUMP) || (crypto_flag && (crypto_count < N_CRYPTO_FUNCS_TO_DUMP)) || (heuristic_flag && (heur_count < N_HEUR_FUNCS_TO_DUMP))) { 330 | hexrays_failure_t hf; 331 | cfuncptr_t cfunc = decompile(function, &hf); 332 | 333 | logmsg(DEBUG, "\nafter decompile()\n"); 334 | if (cfunc != NULL) { 335 | ctree_dumper_t ctree_dumper; 336 | ctree_dumper.apply_to(&cfunc->body, NULL); 337 | 338 | ctree_dump_line func_dump; 339 | func_dump.ctree_dump = ctree_dumper.ctree_dump; 340 | func_dump.ctree_for_hash = ctree_dumper.ctree_for_hash; 341 | 342 | func_dump.func_depth = -1; 343 | 344 | func_dump.func_start = function->startEA; 345 | func_dump.func_end = function->endEA; 346 | 347 | qstring func_name; 348 | if (get_func_name2(&func_name, function->startEA) != 0) { 349 | if (func_name.length() > 0) { 350 | func_dump.func_name = func_name; 351 | } 352 | } 353 | 354 | func_parent_iterator_t fpi(function); 355 | for (ea_t addr = get_first_cref_to(function->startEA); addr != BADADDR; addr = get_next_cref_to(function->startEA, addr)) { 356 | func_t *referer = get_func(addr); 357 | if (referer != NULL) { 358 | func_dump.referres.push_back(referer->startEA); 359 | } 360 | } 361 | 362 | func_dump.heuristic_flag = heuristic_flag; // 0 or 1 depending on code above 363 | if (heuristic_flag) 364 | heur_count++; 365 | 366 | if (crypto_flag) 367 | crypto_count++; 368 | 369 | count++; 370 | 371 | data_to_dump[function->startEA] = func_dump; 372 | } 373 | } 374 | } 375 | } 376 | 377 | dump_ctrees_in_file(data_to_dump, crypto_prefix); 378 | 379 | return true; 380 | } 381 | 382 | bool idaapi extract_all_ctrees(void *ud) 383 | { 384 | // in this case don't mark dumped functions as crypto 385 | qstring crypto_prefix = "none_crypto_prefix"; 386 | dump_funcs_ctree(NULL, crypto_prefix); 387 | 388 | return true; 389 | } 390 | 391 | 392 | // Ctree Item Form Init 393 | struct func_ctree_info_t 394 | { 395 | TForm *form; 396 | TCustomControl *cv; 397 | TCustomControl *codeview; 398 | strvec_t sv; 399 | func_ctree_info_t(TForm *f) : form(f), cv(NULL) {} 400 | }; 401 | 402 | 403 | bool idaapi show_citem_custom_view(void *ud, qstring ctree_item, qstring item_name) 404 | { 405 | HWND hwnd = NULL; 406 | qstring form_name = "Ctree Item View: "; 407 | form_name.append(item_name); 408 | TForm *form = create_tform(form_name.c_str(), &hwnd); 409 | func_ctree_info_t *si = new func_ctree_info_t(form); 410 | 411 | istringstream s_citem_str(ctree_item.c_str()); 412 | string tmp_str; 413 | while (getline(s_citem_str, tmp_str, ';')) 414 | { 415 | qstring tmp_qstr = tmp_str.c_str(); 416 | si->sv.push_back(simpleline_t(tmp_qstr)); 417 | } 418 | 419 | simpleline_place_t s1; 420 | simpleline_place_t s2(ctree_item.size()); 421 | si->cv = create_custom_viewer("Ctree Item View: ", NULL, &s1, &s2, &s1, 0, &si->sv); 422 | si->codeview = create_code_viewer(form, si->cv, CDVF_NOLINES); 423 | set_custom_viewer_handlers(si->cv, NULL, NULL, NULL, NULL, NULL, NULL, si); 424 | open_tform(form, FORM_ONTOP | FORM_RESTORE); 425 | 426 | return false; 427 | } 428 | 429 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/CtreeExtractor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #ifndef __H_FUNCCTREEDUMPER__ 26 | #define __H_FUNCCTREEDUMPER__ 27 | 28 | #pragma once 29 | 30 | // Helper class to get ctree 31 | struct ctree_dumper_t : public ctree_parentee_t 32 | { 33 | ctree_dumper_t() : ctree_parentee_t(true) {} 34 | qstring ctree_dump; 35 | qstring ctree_for_hash; 36 | 37 | int process(citem_t *i); 38 | int process_leave(citem_t *i); 39 | void process_for_hash(citem_t *i); 40 | // We treat expressions and statements the same way: add them to the graph 41 | int idaapi visit_insn(cinsn_t *i) { return process(i); } 42 | int idaapi visit_expr(cexpr_t *e) { return process(e); } 43 | // We treat expressions and statements the same way: add them to the graph 44 | int idaapi leave_insn(cinsn_t *i) { return process_leave(i); } 45 | int idaapi leave_expr(cexpr_t *e) { return process_leave(e); } 46 | bool idaapi filter_citem(citem_t *item); 47 | char * parse_ctree_item(citem_t *item, char *buf, int bufsize) const; 48 | }; 49 | 50 | 51 | bool idaapi show_citem_custom_view(void *ud, qstring ctree_item, qstring item_name); 52 | bool idaapi dump_funcs_ctree(void *ud, qstring &crypto_prefix); 53 | bool idaapi extract_all_ctrees(void *ud); 54 | int create_open_file(const char* file_name); 55 | int get_hash_of_string(qstring &string_to_hash, qstring &hash); 56 | 57 | 58 | #endif -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/Debug.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see 21 | . 22 | 23 | ============================================================================== 24 | */ 25 | 26 | #include "Common.h" 27 | #include "Debug.h" 28 | 29 | #define OUTPUT_FILE "codexplorer_output.txt" 30 | #define ERROR_FILE "codexplorer_error.txt" 31 | 32 | #ifdef __LINUX__ 33 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 34 | #endif 35 | 36 | static void print_to_output_file(const char *output_msg) { 37 | int file_id = qopen(OUTPUT_FILE, O_WRONLY | O_APPEND); 38 | if (file_id == BADADDR) 39 | file_id = qcreate(OUTPUT_FILE, 511); 40 | 41 | if (file_id == -1) { 42 | msg("FATAL: print_to_output_file failed!\n"); 43 | return; 44 | } 45 | 46 | qwrite(file_id, output_msg, strlen(output_msg)); 47 | 48 | qclose(file_id); 49 | } 50 | 51 | static void print_to_error_file(const char *error_msg) { 52 | int file_id = qopen(ERROR_FILE, O_WRONLY | O_APPEND); 53 | if (file_id == BADADDR) 54 | file_id = qcreate(ERROR_FILE, 511); 55 | 56 | if (file_id == -1) { 57 | msg("FATAL: print_to_error_file failed!\n"); 58 | return; 59 | } 60 | 61 | qwrite(file_id, error_msg, strlen(error_msg)); 62 | 63 | qclose(file_id); 64 | } 65 | 66 | void logmsg(unsigned int level, const char *fmt, ...) 67 | { 68 | va_list arglist; 69 | 70 | if (level > CURRENT_DEBUG_LEVEL) 71 | return; 72 | 73 | va_start(arglist, fmt); 74 | 75 | switch (level) { 76 | case OUTPUT: 77 | print_to_output_file(fmt); 78 | break; 79 | case ERROR: 80 | print_to_error_file(fmt); 81 | break; 82 | default: 83 | msg(fmt, arglist); 84 | break; 85 | } 86 | 87 | va_end(arglist); 88 | } -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/Debug.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | void logmsg(unsigned int level, const char *fmt, ...); 26 | 27 | #ifndef __H_DEBUG__ 28 | #define __H_DEBUG__ 29 | #ifdef ERROR 30 | #undef ERROR 31 | #endif 32 | 33 | enum DEBUG_LEVELS { 34 | OUTPUT, // output printed to output file 35 | ERROR, // error printed to error file 36 | INFO, // print to IDA 37 | INTERACTIVE, // show on IDA interface 38 | DEBUG // print to IDA 39 | }; 40 | 41 | #define CURRENT_DEBUG_LEVEL ERROR 42 | 43 | #endif -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/GraphBuilder.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | 26 | #include "Common.h" 27 | #include "GraphBuilder.h" 28 | #include "ObjectExplorer.h" 29 | 30 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 31 | 32 | 33 | bool callgraph_t::visited(citem_t *i, int *nid) 34 | { 35 | ea_int_map_t::const_iterator it = ea2node.find(i); 36 | if ( it != ea2node.end() ) 37 | { 38 | if ( nid != NULL ) 39 | *nid = it->second; 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | 46 | void callgraph_t::create_edge(int id1, int id2) 47 | { 48 | edges.push_back(edge_t(id1, id2)); 49 | } 50 | 51 | 52 | char * callgraph_t::get_node_label(int n, char *buf, int bufsize) const 53 | { 54 | int_ea_map_t::const_iterator it = node2ea.find(n); 55 | 56 | if ( it != node2ea.end() ) 57 | { 58 | const citem_t *item = it->second; 59 | 60 | char *ptr = buf; 61 | char *endp = buf + bufsize; 62 | 63 | // Each node will have the element type at the first line 64 | APPEND(ptr, endp, get_ctype_name(item->op)); 65 | const cexpr_t *e = (const cexpr_t *)item; 66 | const cinsn_t *i = (const cinsn_t *)item; 67 | 68 | // For some item types, display additional information 69 | switch (item->op) 70 | { 71 | case cot_call: 72 | char buf[MAXSTR]; 73 | if (get_func_name(e->x->obj_ea, buf, sizeof(buf)) == NULL) 74 | ptr += qsnprintf(ptr, endp - ptr, " sub_%a", e->x->obj_ea); 75 | ptr += qsnprintf(ptr, endp - ptr, " %s", buf); 76 | break; 77 | case cot_ptr: // *x 78 | case cot_memptr: // x->m 79 | // Display access size for pointers 80 | ptr += qsnprintf(ptr, endp - ptr, ".%d", e->ptrsize); 81 | if (item->op == cot_ptr) 82 | break; 83 | case cot_memref: // x.m 84 | // Display member offset for structure fields 85 | ptr += qsnprintf(ptr, endp - ptr, " (m=%d)", e->m); 86 | break; 87 | case cot_obj: // v 88 | 89 | case cot_var: // l 90 | // Display object size for local variables and global data 91 | ptr += qsnprintf(ptr, endp - ptr, ".%d", e->refwidth); 92 | case cot_num: // n 93 | case cot_helper: // arbitrary name 94 | case cot_str: // string constant 95 | // Display helper names and number values 96 | APPCHAR(ptr, endp, ' '); 97 | e->print1(ptr, endp - ptr, NULL); 98 | tag_remove(ptr, ptr, 0); 99 | ptr = tail(ptr); 100 | break; 101 | case cit_goto: 102 | // Display target label number for gotos 103 | ptr += qsnprintf(ptr, endp - ptr, " LABEL_%d", i->cgoto->label_num); 104 | break; 105 | case cit_asm: 106 | // Display instruction block address and size for asm-statements 107 | ptr += qsnprintf(ptr, endp - ptr, " %a.%" FMT_Z, *i->casm->begin(), i->casm->size()); 108 | break; 109 | default: 110 | break; 111 | } 112 | 113 | ptr += qsnprintf(ptr, endp-ptr, "\nea: %a", item->ea); 114 | 115 | if ( item->is_expr() && !e->type.empty() ) 116 | { 117 | // For typed expressions, the third line will have 118 | // the expression type in human readable form 119 | APPCHAR(ptr, endp, '\n'); 120 | qstring out; 121 | if (e->type.print(&out)) 122 | { 123 | APPEND(ptr, endp, out.c_str()); 124 | } 125 | else 126 | { // could not print the type? 127 | APPCHAR(ptr, endp, '?'); 128 | APPZERO(ptr, endp); 129 | } 130 | 131 | if(e->type.is_ptr()) 132 | { 133 | tinfo_t ptr_rem = remove_pointer(e->type); 134 | if(ptr_rem.is_struct()) 135 | { 136 | qstring typenm; 137 | ptr_rem.print(&typenm, "prefix ", 0, 0, PRTYPE_MULTI | PRTYPE_TYPE | PRTYPE_SEMI); 138 | } 139 | } 140 | } 141 | } 142 | 143 | return buf; 144 | } 145 | 146 | 147 | callgraph_t::nodeinfo_t *callgraph_t::get_info(int nid) 148 | { 149 | nodeinfo_t *ret = NULL; 150 | 151 | do 152 | { 153 | // returned cached name 154 | int_funcinfo_map_t::iterator it = cached_funcs.find(nid); 155 | if ( it != cached_funcs.end() ) 156 | { 157 | ret = &it->second; 158 | break; 159 | } 160 | 161 | // node does not exist? 162 | int_ea_map_t::const_iterator it_ea = node2ea.find(nid); 163 | if ( it_ea == node2ea.end() ) 164 | break; 165 | 166 | citem_t *pfn = it_ea->second; 167 | if ( pfn == NULL ) 168 | break; 169 | 170 | nodeinfo_t fi; 171 | 172 | // get name 173 | char buf[MAXSTR]; 174 | if(get_node_label(nid, buf, MAXSTR)) 175 | fi.name = buf; 176 | else 177 | fi.name = "?unknown"; 178 | 179 | // get color 180 | if(pfn == highlighted) // highlight element with current cursor position 181 | fi.color = 2000; 182 | else 183 | fi.color = 1; 184 | 185 | #define CL_DARKBLUE ((0 )+ (0 <<8)+ (128<<16)) 186 | if (pfn->op == cit_expr) 187 | fi.color = CL_DARKBLUE; 188 | #define CL_BLUE ((0 )+ (0 <<8)+ (255<<16)) 189 | if (pfn->op == cit_block) 190 | fi.color = CL_BLUE; 191 | 192 | 193 | fi.ea = pfn->ea; 194 | 195 | it = cached_funcs.insert(cached_funcs.end(), std::make_pair(nid, fi)); 196 | ret = &it->second; 197 | } while ( false ); 198 | 199 | return ret; 200 | } 201 | 202 | 203 | //-------------------------------------------------------------------------- 204 | int callgraph_t::add(citem_t *i) 205 | { 206 | // check if we are trying to add existing node 207 | ea_int_map_t::const_iterator it = ea2node.find(i); 208 | if ( it != ea2node.end() ) 209 | return it->second; 210 | 211 | ea2node[i] = node_count; 212 | node2ea[node_count] = i; 213 | 214 | int ret_val = node_count; 215 | node_count ++; 216 | return ret_val; 217 | } 218 | 219 | 220 | //-------------------------------------------------------------------------- 221 | callgraph_t::callgraph_t() : node_count(0) 222 | { 223 | cur_text[0] = '\0'; 224 | } 225 | 226 | 227 | //-------------------------------------------------------------------------- 228 | void callgraph_t::clear_edges() 229 | { 230 | edges.clear(); 231 | } 232 | 233 | //-------------------------------------------------------------------------- 234 | graph_info_t::graphinfo_list_t graph_info_t::instances; 235 | 236 | //-------------------------------------------------------------------------- 237 | graph_info_t::graph_info_t() 238 | { 239 | form = NULL; 240 | gv = NULL; 241 | } 242 | 243 | 244 | //-------------------------------------------------------------------------- 245 | // Create graph for current decompiled function 246 | graph_info_t * graph_info_t::create(ea_t func_ea, citem_t *highlighted) 247 | { 248 | graph_info_t *r; 249 | 250 | func_t *pfn = get_func(func_ea); 251 | if ( pfn == NULL ) 252 | return NULL; 253 | 254 | r = new graph_info_t(); 255 | r->func_ea = pfn->startEA; 256 | r->fg.highlighted = highlighted; 257 | 258 | size_t num_inst = 0; 259 | for(graphinfo_list_t::iterator it = instances.begin() ; it != instances.end() ; it ++) 260 | { 261 | if(((*(it))->func_ea == func_ea) && (num_inst < (*(it))->func_instance_no)) 262 | num_inst = (*(it))->func_instance_no; 263 | } 264 | 265 | r->func_instance_no = ++ num_inst; 266 | get_title(func_ea, num_inst, &r->title); 267 | 268 | instances.push_back(r); 269 | 270 | return r; 271 | } 272 | 273 | 274 | //-------------------------------------------------------------------------- 275 | bool graph_info_t::get_title(ea_t func_ea, size_t num_inst, qstring *out) 276 | { 277 | // we should succeed in getting the name 278 | char func_name[MAXSTR]; 279 | if ( get_func_name(func_ea, func_name, sizeof(func_name)) == NULL ) 280 | return false; 281 | 282 | out->sprnt("Ctree Graph View: %s %d", func_name, num_inst); 283 | 284 | return true; 285 | } 286 | 287 | 288 | void graph_info_t::destroy(graph_info_t *gi) 289 | { 290 | for(graphinfo_list_t::iterator it = instances.begin() ; it != instances.end() ; it ++) 291 | { 292 | if((*(it)) == gi) 293 | { 294 | instances.erase(it); 295 | break; 296 | } 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/GraphBuilder.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #ifndef __H_GRAPHBUILDER__ 26 | #define __H_GRAPHBUILDER__ 27 | 28 | #pragma once 29 | 30 | #include "Common.h" 31 | 32 | // function call graph creator class 33 | class callgraph_t 34 | { 35 | // total number of the nodes in the graph 36 | int node_count; 37 | 38 | // node id to func addr and reverse lookup 39 | typedef std::map ea_int_map_t; 40 | typedef std::map int_ea_map_t; 41 | ea_int_map_t ea2node; 42 | int_ea_map_t node2ea; 43 | 44 | // current node search ptr 45 | int cur_node; 46 | char cur_text[MAXSTR]; 47 | 48 | bool visited(citem_t *i, int *nid); 49 | 50 | public: 51 | 52 | citem_t *highlighted; 53 | 54 | int add(citem_t *i); 55 | // edge structure 56 | struct edge_t 57 | { 58 | int id1; 59 | int id2; 60 | edge_t(int i1, int i2): id1(i1), id2(i2) { } 61 | edge_t(): id1(0), id2(0) { } 62 | }; 63 | 64 | typedef qlist edges_t; 65 | 66 | // edge manipulation 67 | typedef edges_t::iterator edge_iterator; 68 | void create_edge(int id1, int id2); 69 | 70 | edge_iterator begin_edges() { return edges.begin(); } 71 | edge_iterator end_edges() { return edges.end(); } 72 | 73 | void clear_edges(); 74 | 75 | callgraph_t(); 76 | 77 | const int count() const { return node_count; } 78 | 79 | // node / func info 80 | struct nodeinfo_t 81 | { 82 | qstring name; 83 | bgcolor_t color; 84 | ea_t ea; 85 | }; 86 | 87 | typedef std::map int_funcinfo_map_t; 88 | int_funcinfo_map_t cached_funcs; 89 | nodeinfo_t *get_info(int nid); 90 | 91 | 92 | // int walk_func(func_t *func); 93 | private: 94 | edges_t edges; 95 | 96 | char * get_node_label(int n, char *buf, int bufsize) const; 97 | }; 98 | 99 | 100 | // per function call graph context 101 | class graph_info_t 102 | { 103 | // Actual context variables 104 | public: 105 | callgraph_t fg; // associated graph maker 106 | graph_viewer_t *gv; // associated graph_view 107 | TForm *form; // associated TForm 108 | vdui_t *vu; 109 | 110 | 111 | ea_t func_ea; // function ea in question 112 | qstring title; // the title 113 | 114 | size_t func_instance_no; 115 | // Instance management 116 | private: 117 | typedef qlist graphinfo_list_t; 118 | typedef graphinfo_list_t::iterator iterator; 119 | 120 | // Remove instance upon deletion of the objects 121 | static graphinfo_list_t instances; 122 | 123 | 124 | graph_info_t(); 125 | public: 126 | static graph_info_t *create(ea_t func_ea, citem_t *it); 127 | static void destroy(graph_info_t *gi); 128 | static bool get_title(ea_t func_ea, size_t num_inst, qstring *out); 129 | }; 130 | 131 | #endif -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug x64 6 | Win32 7 | 8 | 9 | Debug x64 10 | x64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Debug 18 | x64 19 | 20 | 21 | Release x64 22 | Win32 23 | 24 | 25 | Release x64 26 | x64 27 | 28 | 29 | Release 30 | Win32 31 | 32 | 33 | Release 34 | x64 35 | 36 | 37 | 38 | {F7E6B557-41F3-444A-BCA4-3527547DD665} 39 | Win32Proj 40 | HexRaysCodeXplorer 41 | HexRaysCodeXplorer 42 | 8.1 43 | 44 | 45 | 46 | DynamicLibrary 47 | true 48 | MultiByte 49 | v140 50 | 51 | 52 | DynamicLibrary 53 | true 54 | MultiByte 55 | v140 56 | 57 | 58 | DynamicLibrary 59 | true 60 | MultiByte 61 | v140 62 | 63 | 64 | DynamicLibrary 65 | true 66 | MultiByte 67 | v140 68 | 69 | 70 | DynamicLibrary 71 | false 72 | true 73 | MultiByte 74 | v140 75 | 76 | 77 | DynamicLibrary 78 | false 79 | true 80 | MultiByte 81 | v140 82 | 83 | 84 | DynamicLibrary 85 | false 86 | true 87 | MultiByte 88 | v140 89 | 90 | 91 | DynamicLibrary 92 | false 93 | true 94 | MultiByte 95 | v140 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | true 127 | build makefile 128 | .plw 129 | 130 | 131 | true 132 | build makefile 133 | .plw 134 | 135 | 136 | true 137 | build makefile 138 | .p64 139 | 140 | 141 | true 142 | build makefile 143 | .p64 144 | 145 | 146 | false 147 | .plw 148 | 149 | 150 | false 151 | .plw 152 | 153 | 154 | false 155 | .p64 156 | 157 | 158 | false 159 | .p64 160 | 161 | 162 | 163 | 164 | 165 | Level3 166 | Disabled 167 | __NT__;__IDP__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 168 | $(IDADIR)\plugins\SDK\idasdk\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include 169 | MultiThreadedDebug 170 | 171 | 172 | Console 173 | true 174 | ida.lib 175 | /EXPORT:PLUGIN %(AdditionalOptions) 176 | $(IDADIR)\plugins\SDK\idasdk\lib\x86_win_vc_32 177 | 178 | 179 | 180 | 181 | 182 | 183 | Level3 184 | Disabled 185 | __NT__;__IDP__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 186 | $(IDADIR)\plugins\SDK\idasdk\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include 187 | MultiThreadedDebug 188 | 189 | 190 | Console 191 | true 192 | ida.lib 193 | /EXPORT:PLUGIN %(AdditionalOptions) 194 | $(IDADIR)\plugins\SDK\idasdk\lib\x86_win_vc_32 195 | 196 | 197 | 198 | 199 | 200 | 201 | Level3 202 | Disabled 203 | __NT__;__IDP__;__EA64__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 204 | $(IDADIR)\plugins\SDK\idasdk\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include 205 | MultiThreadedDebug 206 | 207 | 208 | Console 209 | true 210 | ida.lib 211 | /EXPORT:PLUGIN %(AdditionalOptions) 212 | $(IDADIR)\plugins\SDK\idasdk\lib\x86_win_vc_64 213 | 214 | 215 | 216 | 217 | 218 | 219 | Level3 220 | Disabled 221 | __NT__;__IDP__;__EA64__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 222 | $(IDADIR)\plugins\SDK\idasdk\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include\ 223 | MultiThreadedDebug 224 | 225 | 226 | Console 227 | true 228 | ida.lib 229 | /EXPORT:PLUGIN %(AdditionalOptions) 230 | $(IDADIR)\plugins\SDK\idasdk\lib\x86_win_vc_64 231 | 232 | 233 | 234 | 235 | Level3 236 | 237 | 238 | MaxSpeed 239 | true 240 | true 241 | __NT__;__IDP__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 242 | $(IDADIR)\plugins\SDK\idasdk\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include 243 | MultiThreaded 244 | 245 | 246 | Console 247 | true 248 | true 249 | true 250 | ida.lib 251 | /EXPORT:PLUGIN %(AdditionalOptions) 252 | $(IDADIR)\plugins\SDK\idasdk\lib\x86_win_vc_32 253 | 254 | 255 | 256 | 257 | Level3 258 | 259 | 260 | MaxSpeed 261 | true 262 | true 263 | __NT__;__IDP__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 264 | $(IDADIR)\plugins\SDK\idasdk\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include 265 | MultiThreaded 266 | 267 | 268 | Console 269 | true 270 | true 271 | true 272 | ida.lib 273 | /EXPORT:PLUGIN %(AdditionalOptions) 274 | $(IDADIR)\plugins\SDK\idasdk\lib\x86_win_vc_32 275 | 276 | 277 | 278 | 279 | Level3 280 | 281 | 282 | MaxSpeed 283 | true 284 | true 285 | __NT__;__IDP__;__EA64__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 286 | $(IDADIR)\plugins\SDK\idasdk\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include 287 | MultiThreaded 288 | 289 | 290 | Console 291 | true 292 | true 293 | true 294 | ida.lib 295 | /EXPORT:PLUGIN %(AdditionalOptions) 296 | $(IDADIR)\plugins\SDK\idasdk\lib\x86_win_vc_64 297 | 298 | 299 | 300 | 301 | Level3 302 | 303 | 304 | MaxSpeed 305 | true 306 | true 307 | __NT__;__IDP__;__EA64__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 308 | $(IDADIR)\plugins\SDK\idasdk\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include 309 | MultiThreaded 310 | 311 | 312 | Console 313 | true 314 | true 315 | true 316 | ida.lib 317 | /EXPORT:PLUGIN %(AdditionalOptions) 318 | $(IDADIR)\plugins\SDK\idasdk\lib\x86_win_vc_64 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(IDADIR)\idaq.exe 5 | WindowsLocalDebugger 6 | 7 | 8 | 9 | 10 | $(IDADIR)\idaq.exe 11 | WindowsLocalDebugger 12 | 13 | 14 | 15 | $(IDADIR)\idaq64.exe 16 | WindowsLocalDebugger 17 | 18 | 19 | $(IDADIR)\idaq64.exe 20 | WindowsLocalDebugger 21 | 22 | 23 | $(IDADIR)\idaq.exe 24 | WindowsLocalDebugger 25 | 26 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/Linux.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #pragma once 26 | 27 | #ifdef __LINUX__ 28 | 29 | #pragma GCC diagnostic ignored "-fpermissive" 30 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 31 | 32 | #include 33 | #define UINT uint32_t 34 | #define PUINT uint32_t * 35 | #define CHAR int8_t 36 | #define UCHAR uint8_t 37 | #define TCHAR uint8_t 38 | #define WCHAR wchar_t 39 | #define BOOL bool 40 | #define TRUE true 41 | #define FALSE false 42 | #define LPCSTR char *const 43 | #define LPCTSTR char *const 44 | #define LPSTR char * 45 | #define WORD uint16_t 46 | #define DWORD uint32_t 47 | #define PDWORD DWORD* 48 | #define PVOID void* 49 | #define PINT int* 50 | #define UINT64 uint64_t 51 | 52 | #define ZeroMemory(dst, length) memset(dst, 0, length) 53 | 54 | /* Those are header annotations in Visual Studio and can be safely ignored */ 55 | #define IN 56 | #define OUT 57 | #define __bcount(element) 58 | 59 | /* Ugly but ... */ 60 | #define sprintf_s snprintf 61 | #define _snprintf snprintf 62 | #endif -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/ObjectExplorer.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | 26 | #include "Common.h" 27 | #include "ObjectExplorer.h" 28 | #include "ObjectFormatMSVC.h" 29 | #include "Utility.h" 30 | 31 | #include "Debug.h" 32 | 33 | #ifndef __LINUX__ 34 | #include 35 | #else 36 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 37 | #endif 38 | 39 | qvector vtbl_t_list; // list of vtables found in the binary 40 | qvector vtbl_list; // list of string for ObjectExplrer vtables view 41 | 42 | extern std::map rtti_vftables; 43 | 44 | void free_vtable_lists() { 45 | vtbl_t_list.clear(); 46 | vtbl_list.clear(); 47 | } 48 | 49 | 50 | //--------------------------------------------------------------------------- 51 | // VTBL code parsing 52 | //--------------------------------------------------------------------------- 53 | 54 | const char * get_text_disasm(ea_t ea) { 55 | static char disasm_buff[MAXSTR]; 56 | disasm_buff[0] = disasm_buff[MAXSTR - 1] = 0; 57 | 58 | if(generate_disasm_line(ea, disasm_buff, (sizeof(disasm_buff) - 1))) 59 | tag_remove(disasm_buff, disasm_buff, (sizeof(disasm_buff) - 1)); 60 | 61 | return disasm_buff; 62 | } 63 | 64 | static bool check_vtable_load_instruction(ea_t ea_code) { 65 | bool is_move_xref = false; 66 | const char *disasm_line = get_text_disasm(ea_code); 67 | if((strncmp(disasm_line, "mov ", 4) == 0) && (qstrstr(disasm_line + 4, " offset ") != NULL)) { 68 | is_move_xref = true; 69 | } else if ((strncmp(disasm_line, "lea", 3) == 0)) { 70 | is_move_xref = true; 71 | } 72 | 73 | return is_move_xref; 74 | } 75 | 76 | //--------------------------------------------------------------------------- 77 | // Try to find vtable at the specified address 78 | //--------------------------------------------------------------------------- 79 | static bool get_vtbl_info(ea_t ea_address, VTBL_info_t &vtbl_info) 80 | { 81 | flags_t flags = get_flags_novalue(ea_address); 82 | if (hasRef(flags) && has_any_name(flags) && (isEa(flags) || isUnknown(flags))) { 83 | bool is_move_xref = false; 84 | 85 | ea_t ea_code_ref = get_first_dref_to(ea_address); 86 | if(ea_code_ref && (ea_code_ref != BADADDR)) { 87 | do { 88 | if(isCode(get_flags_novalue(ea_code_ref)) && check_vtable_load_instruction(ea_code_ref)) { 89 | is_move_xref = true; 90 | break; 91 | } 92 | 93 | ea_code_ref = get_next_dref_to(ea_address, ea_code_ref); 94 | 95 | } while(ea_code_ref && (ea_code_ref != BADADDR)); 96 | } 97 | 98 | if(is_move_xref) { 99 | ZeroMemory(&vtbl_info, sizeof(VTBL_info_t)); 100 | 101 | get_ea_name(&vtbl_info.vtbl_name, ea_address); 102 | 103 | ea_t ea_start = vtbl_info.ea_begin = ea_address; 104 | 105 | while(true) { 106 | flags_t index_flags = get_flags_novalue(ea_address); 107 | if(!(isEa(index_flags) || isUnknown(index_flags))) 108 | break; 109 | 110 | ea_t ea_index_value = getEa(ea_address); 111 | if(!(ea_index_value && (ea_index_value != BADADDR))) 112 | break; 113 | 114 | if(ea_address != ea_start) 115 | if(hasRef(index_flags)) 116 | break; 117 | 118 | flags_t value_flags = get_flags_novalue(ea_index_value); 119 | if(!isCode(value_flags)) { 120 | break; 121 | } else { 122 | if(isUnknown(index_flags)) { 123 | #ifndef __EA64__ 124 | doDwrd(ea_address, sizeof(ea_t)); 125 | #else 126 | doQwrd(ea_address, sizeof(ea_t)); 127 | #endif 128 | } 129 | } 130 | 131 | ea_address += sizeof(ea_t); 132 | }; 133 | 134 | if((vtbl_info.methods = ((ea_address - ea_start) / sizeof(ea_t))) > 0) { 135 | vtbl_info.ea_end = ea_address; 136 | return true; 137 | } 138 | } 139 | } 140 | 141 | return false; 142 | } 143 | 144 | //--------------------------------------------------------------------------- 145 | // Try to find and parse vtable at the specified address 146 | //--------------------------------------------------------------------------- 147 | static void process_vtbl(ea_t &ea_sect) 148 | { 149 | VTBL_info_t vftable_info_t; 150 | // try to parse vtable at this address 151 | if(get_vtbl_info(ea_sect, vftable_info_t)) 152 | { 153 | ea_sect = vftable_info_t.ea_end; 154 | 155 | if(vftable_info_t.methods > 1) { 156 | // check if we have already processed this table 157 | if (rtti_vftables.count(vftable_info_t.ea_begin) == 0) { 158 | vftable_info_t.vtbl_name = get_short_name(vftable_info_t.ea_begin); 159 | 160 | qstring vtbl_info_str; 161 | #ifndef __EA64__ 162 | vtbl_info_str.cat_sprnt(" 0x%0x - 0x%0x: %s methods count: %d", vftable_info_t.ea_begin, vftable_info_t.ea_end, vftable_info_t.vtbl_name.c_str(), vftable_info_t.methods); 163 | #else 164 | vtbl_info_str.cat_sprnt(" 0x%016llx - 0x%016llx: %s methods count: %d", vftable_info_t.ea_begin, vftable_info_t.ea_end, vftable_info_t.vtbl_name.c_str(), vftable_info_t.methods); 165 | #endif // !#ifndef __EA64__ 166 | 167 | 168 | 169 | vtbl_list.push_back(vtbl_info_str); 170 | vtbl_t_list.push_back(vftable_info_t); 171 | } 172 | 173 | ea_sect = vftable_info_t.ea_end; 174 | return; 175 | } 176 | } 177 | 178 | // nothing found: increment ea_sect by size of the pointer to continue search at the next location 179 | ea_sect += sizeof(ea_t); 180 | return; 181 | } 182 | 183 | //--------------------------------------------------------------------------- 184 | // Get vtable structure from the list by address 185 | //--------------------------------------------------------------------------- 186 | bool get_vbtbl_by_ea(ea_t vtbl_addr, VTBL_info_t &vtbl) { 187 | bool result = false; 188 | 189 | search_objects(false); 190 | 191 | qvector ::iterator vtbl_iter; 192 | for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) { 193 | if ((*vtbl_iter).ea_begin == vtbl_addr) { 194 | vtbl = *vtbl_iter; 195 | result = true; 196 | break; 197 | } 198 | } 199 | 200 | return result; 201 | } 202 | 203 | //--------------------------------------------------------------------------- 204 | // Create a structurte in IDA local types which represents vtable 205 | //--------------------------------------------------------------------------- 206 | tid_t create_vtbl_struct(ea_t vtbl_addr, ea_t vtbl_addr_end, char* vtbl_name, uval_t idx, unsigned int* vtbl_len) 207 | { 208 | qstring struc_name = vtbl_name; 209 | tid_t id = add_struc(BADADDR, struc_name.c_str()); 210 | 211 | if (id == BADADDR) { 212 | struc_name.clear(); 213 | struc_name = askstr(HIST_IDENT, NULL, "Default name %s not correct. Enter other structure name: ", struc_name.c_str()); 214 | id = add_struc(BADADDR, struc_name.c_str()); 215 | set_struc_cmt(id, vtbl_name, true); 216 | } 217 | 218 | struc_t* new_struc = get_struc(id); 219 | if (!new_struc) 220 | return BADNODE; 221 | 222 | ea_t ea = vtbl_addr; 223 | int offset = 0; 224 | 225 | while (ea < vtbl_addr_end) { 226 | offset = ea - vtbl_addr; 227 | qstring method_name; 228 | ea_t method_ea = getEa(ea); 229 | 230 | if (method_ea == 0) break; 231 | if (!isEnabled(method_ea)) break; 232 | 233 | flags_t method_flags = getFlags(method_ea); 234 | char* struc_member_name = NULL; 235 | if (isFunc(method_flags)) { 236 | method_name = get_short_name(method_ea); 237 | if (method_name.length() != 0) 238 | struc_member_name = (char*)method_name.c_str(); 239 | } 240 | #ifndef __EA64__ 241 | add_struc_member(new_struc, NULL, offset, dwrdflag(), NULL, sizeof(ea_t)); 242 | #else 243 | add_struc_member(new_struc, NULL, offset, qwrdflag(), NULL, sizeof(ea_t)); 244 | #endif 245 | if (struc_member_name) { 246 | if (!set_member_name(new_struc, offset, struc_member_name)) { 247 | get_ea_name(&method_name, method_ea); 248 | set_member_name(new_struc, offset, struc_member_name); 249 | } 250 | } 251 | 252 | ea = ea + sizeof(ea_t); 253 | flags_t ea_flags = getFlags(ea); 254 | 255 | if (has_any_name(ea_flags)) break; 256 | } 257 | 258 | return id; 259 | } 260 | 261 | 262 | void find_vtables_rtti() 263 | { 264 | logmsg(DEBUG, "\nprocess_rtti()\n"); 265 | 266 | // get rtti_vftables map using rtti data 267 | getRttiData(); 268 | 269 | // store this inormation in the lists 270 | for (std::map::iterator it = rtti_vftables.begin(); it != rtti_vftables.end() ; it ++ ) { 271 | VTBL_info_t vftable_info_t; 272 | vftable_info_t.ea_begin = it->second.start; 273 | vftable_info_t.ea_end = it->second.end; 274 | vftable_info_t.methods = it->second.methodCount; 275 | vftable_info_t.vtbl_name = it->second.type_info; 276 | 277 | qstring vtbl_info_str; 278 | vtbl_info_str.cat_sprnt(" 0x%x - 0x%x: %s methods count: %d", vftable_info_t.ea_begin, vftable_info_t.ea_end, vftable_info_t.vtbl_name.c_str(), vftable_info_t.methods); 279 | 280 | vtbl_list.push_back(vtbl_info_str); 281 | vtbl_t_list.push_back(vftable_info_t); 282 | } 283 | } 284 | 285 | 286 | //--------------------------------------------------------------------------- 287 | // Find vtables in the binary 288 | //--------------------------------------------------------------------------- 289 | void find_vtables() 290 | { 291 | // set of the processed segments 292 | std::set segSet; 293 | 294 | // start with .rdata section 295 | logmsg(DEBUG, "search_objects() - going for .rdata"); 296 | if (segment_t *seg = get_segm_by_name(".rdata")) { 297 | logmsg(DEBUG, "search_objects() - .rdata exist"); 298 | 299 | segSet.insert(seg); 300 | 301 | ea_t ea_text = seg->startEA; 302 | while (ea_text <= seg->endEA) 303 | process_vtbl(ea_text); 304 | 305 | } else { 306 | logmsg(DEBUG, "search_objects() - .rdata does not exist"); 307 | } 308 | 309 | // look also at .data section 310 | logmsg(DEBUG, "search_objects() - going for .data"); 311 | int segCount = get_segm_qty(); 312 | { 313 | for (int i = 0; i < segCount; i++) { 314 | if (segment_t *seg = getnseg(i)) 315 | { 316 | if (seg->type == SEG_DATA) 317 | { 318 | if (segSet.find(seg) == segSet.end()) 319 | { 320 | char name[8]; 321 | if (get_true_segm_name(seg, name, SIZESTR(name)) == SIZESTR(".data")) 322 | { 323 | if (strcmp(name, ".data") == 0) 324 | { 325 | logmsg(DEBUG, "search_objects() - .data exist"); 326 | segSet.insert(seg); 327 | ea_t ea_text = seg->startEA; 328 | while (ea_text <= seg->endEA) 329 | process_vtbl(ea_text); 330 | } 331 | } 332 | } 333 | } 334 | } 335 | } 336 | 337 | 338 | // If still none found, try any remaining data type segments 339 | if (vtbl_t_list.empty()) 340 | { 341 | logmsg(DEBUG, "search_objects() - going for other data sections"); 342 | for (int i = 0; i < segCount; i++) 343 | { 344 | if (segment_t *seg = getnseg(i)) 345 | { 346 | if (seg->type == SEG_DATA) 347 | { 348 | if (segSet.find(seg) == segSet.end()) 349 | { 350 | segSet.insert(seg); 351 | ea_t ea_text = seg->startEA; 352 | while (ea_text <= seg->endEA) 353 | process_vtbl(ea_text); 354 | } 355 | } 356 | } 357 | } 358 | } 359 | } 360 | } 361 | 362 | 363 | //--------------------------------------------------------------------------- 364 | // Handle VTBL & RTTI 365 | //--------------------------------------------------------------------------- 366 | 367 | bool bScaned = false; 368 | 369 | void search_objects(bool bForce) 370 | { 371 | if (!bScaned || bForce) { 372 | logmsg(DEBUG, "search_objects()"); 373 | 374 | // free previously found objects 375 | free_vtable_lists(); 376 | 377 | // first search vtables using rtti information 378 | find_vtables_rtti(); 379 | 380 | // find all the other vtables 381 | find_vtables(); 382 | 383 | bScaned = true; 384 | } 385 | } 386 | 387 | 388 | //--------------------------------------------------------------------------- 389 | // IDA Custom View Window Initialization 390 | //--------------------------------------------------------------------------- 391 | 392 | static int current_line_pos = 0; 393 | 394 | static bool idaapi make_vtbl_struct_cb(void *ud) 395 | { 396 | VTBL_info_t vtbl_t = vtbl_t_list[current_line_pos]; 397 | tid_t id = add_struc(BADADDR, vtbl_t.vtbl_name.c_str()); 398 | 399 | create_vtbl_struct(vtbl_t.ea_begin, vtbl_t.ea_end, (char*)vtbl_t.vtbl_name.c_str(), id); 400 | 401 | return true; 402 | } 403 | 404 | 405 | 406 | // Popup window with VTBL XREFS 407 | qvector xref_list; 408 | qvector xref_addr; 409 | static void get_xrefs_to_vtbl() 410 | { 411 | ea_t cur_vt_ea = vtbl_t_list[current_line_pos].ea_begin; 412 | for (ea_t addr = get_first_dref_to(cur_vt_ea); addr != BADADDR; addr = get_next_dref_to(cur_vt_ea, addr)) 413 | { 414 | qstring name; 415 | get_func_name2(&name, addr); 416 | 417 | xref_addr.push_back(addr); 418 | 419 | qstring tmp; 420 | tmp.cat_sprnt(" 0x%x: %s", addr, name.c_str()); 421 | xref_list.push_back(tmp); 422 | } 423 | } 424 | 425 | 426 | static bool idaapi ct_vtbl_xrefs_window_click(TCustomControl *v, int shift, void *ud) 427 | { 428 | int x, y; 429 | place_t *place = get_custom_viewer_place(v, true, &x, &y); 430 | simpleline_place_t *spl = (simpleline_place_t *)place; 431 | int line_num = spl->n; 432 | 433 | ea_t cur_xref_ea = xref_addr[line_num]; 434 | jumpto(cur_xref_ea); 435 | 436 | return true; 437 | } 438 | 439 | 440 | static bool idaapi show_vtbl_xrefs_window_cb(void *ud) 441 | { 442 | get_xrefs_to_vtbl(); 443 | if (!xref_list.empty()) 444 | { 445 | HWND hwnd = NULL; 446 | TForm *form = create_tform(vtbl_t_list[current_line_pos].vtbl_name.c_str(), &hwnd); 447 | 448 | object_explorer_info_t *si = new object_explorer_info_t(form); 449 | 450 | qvector ::iterator xref_iter; 451 | for (xref_iter = xref_list.begin(); xref_iter != xref_list.end(); xref_iter++) 452 | si->sv.push_back(simpleline_t(*xref_iter)); 453 | 454 | simpleline_place_t s1; 455 | simpleline_place_t s2(si->sv.size() - 1); 456 | si->cv = create_custom_viewer("", NULL, &s1, &s2, &s1, 0, &si->sv); 457 | si->codeview = create_code_viewer(form, si->cv, CDVF_STATUSBAR); 458 | set_custom_viewer_handlers(si->cv, NULL, NULL, NULL, ct_vtbl_xrefs_window_click, NULL, NULL, si); 459 | open_tform(form, FORM_ONTOP | FORM_RESTORE); 460 | 461 | return true; 462 | } 463 | 464 | warning("ObjectExplorer not found any xrefs here ..."); 465 | logmsg(DEBUG, "ObjectExplorer not found any xrefs here ..."); 466 | 467 | return false; 468 | } 469 | 470 | 471 | ////////////////////////////////////////////////////////////////////////// 472 | 473 | 474 | static void idaapi ct_object_explorer_popup(TCustomControl *v, void *ud) 475 | { 476 | set_custom_viewer_popup_menu(v, NULL); 477 | add_custom_viewer_popup_item(v, "Make VTBL_Srtruct", "S", make_vtbl_struct_cb, ud); 478 | add_custom_viewer_popup_item(v, "Show all XREFS to VTBL", "X", show_vtbl_xrefs_window_cb, ud); 479 | 480 | } 481 | 482 | 483 | static bool idaapi ct_object_explorer_keyboard(TCustomControl * /*v*/, int key, int shift, void *ud) 484 | { 485 | if (shift == 0) 486 | { 487 | object_explorer_info_t *si = (object_explorer_info_t *)ud; 488 | switch (key) 489 | { 490 | case IK_ESCAPE: 491 | close_tform(si->form, FORM_SAVE | FORM_CLOSE_LATER); 492 | return true; 493 | 494 | case 83: // S 495 | make_vtbl_struct_cb(ud); 496 | return true; 497 | 498 | case 88: // X 499 | show_vtbl_xrefs_window_cb(ud); 500 | return true; 501 | } 502 | } 503 | return false; 504 | } 505 | 506 | 507 | static bool idaapi ct_object_explorer_click(TCustomControl *v, int shift, void *ud) 508 | { 509 | int x, y; 510 | place_t *place = get_custom_viewer_place(v, true, &x, &y); 511 | simpleline_place_t *spl = (simpleline_place_t *)place; 512 | int line_num = spl->n; 513 | 514 | ea_t cur_vt_ea = vtbl_t_list[line_num].ea_begin; 515 | jumpto(cur_vt_ea); 516 | 517 | return true; 518 | } 519 | 520 | 521 | static char* get_vtbl_hint(int line_num) 522 | { 523 | current_line_pos = line_num; 524 | char tag_lines [4096]; 525 | ZeroMemory(tag_lines, sizeof(tag_lines)); 526 | 527 | if (isEnabled(vtbl_t_list[line_num].ea_begin)) 528 | { 529 | int flags = calc_default_idaplace_flags(); 530 | linearray_t ln(&flags); 531 | idaplace_t pl; 532 | pl.ea = vtbl_t_list[line_num].ea_begin; 533 | pl.lnnum = 0; 534 | ln.set_place(&pl); 535 | 536 | int used = 0; 537 | int n = ln.get_linecnt(); 538 | for ( int i=0; i < n; i++ ) 539 | { 540 | char buf[MAXSTR]; 541 | char *line = ln.down(); 542 | tag_remove(line, buf, sizeof(buf)); 543 | used += sprintf_s(tag_lines + used, sizeof(tag_lines) - used, "%s\n", buf); 544 | } 545 | 546 | } 547 | 548 | return qstrdup(tag_lines); 549 | } 550 | 551 | 552 | int idaapi ui_object_explorer_callback(void *ud, int code, va_list va) 553 | { 554 | object_explorer_info_t *si = (object_explorer_info_t *)ud; 555 | switch (code) 556 | { 557 | case ui_get_custom_viewer_hint: 558 | { 559 | TCustomControl *viewer = va_arg(va, TCustomControl *); 560 | place_t *place = va_arg(va, place_t *); 561 | int *important_lines = va_arg(va, int *); 562 | qstring &hint = *va_arg(va, qstring *); 563 | 564 | if ( si->cv == viewer ) 565 | { 566 | if ( place == NULL ) 567 | return 0; 568 | 569 | simpleline_place_t *spl = (simpleline_place_t *)place; 570 | hint = get_vtbl_hint (spl->n); 571 | *important_lines = 10; 572 | return 1; 573 | } 574 | break; 575 | } 576 | case ui_tform_invisible: 577 | { 578 | TForm *f = va_arg(va, TForm *); 579 | if ( f == si->form ) 580 | { 581 | delete si; 582 | unhook_from_notification_point(HT_UI, ui_object_explorer_callback, NULL); 583 | } 584 | } 585 | break; 586 | } 587 | return 0; 588 | } 589 | 590 | 591 | void object_explorer_form_init() 592 | { 593 | if (!vtbl_list.empty() && !vtbl_t_list.empty()) 594 | { 595 | HWND hwnd = NULL; 596 | TForm *form = create_tform("Object Explorer", &hwnd); 597 | if (hwnd == NULL) 598 | { 599 | warning("Object Explorer window already open. Switching to it."); 600 | logmsg(DEBUG, "Object Explorer window already open. Switching to it."); 601 | form = find_tform("Object Explorer"); 602 | if (form != NULL) 603 | switchto_tform(form, true); 604 | return; 605 | } 606 | 607 | object_explorer_info_t *si = new object_explorer_info_t(form); 608 | 609 | qvector ::iterator vtbl_iter; 610 | for (vtbl_iter = vtbl_list.begin(); vtbl_iter != vtbl_list.end(); vtbl_iter++) 611 | si->sv.push_back(simpleline_t(*vtbl_iter)); 612 | 613 | simpleline_place_t s1; 614 | simpleline_place_t s2(si->sv.size() - 1); 615 | si->cv = create_custom_viewer("", NULL, &s1, &s2, &s1, 0, &si->sv); 616 | si->codeview = create_code_viewer(form, si->cv, CDVF_STATUSBAR); 617 | set_custom_viewer_handlers(si->cv, ct_object_explorer_keyboard, ct_object_explorer_popup, NULL, ct_object_explorer_click, NULL, NULL, si); 618 | hook_to_notification_point(HT_UI, ui_object_explorer_callback, si); 619 | open_tform(form, FORM_TAB | FORM_MENU | FORM_RESTORE); 620 | } 621 | else { 622 | warning("ObjectExplorer not found any virtual tables here ..."); 623 | logmsg(DEBUG, "ObjectExplorer not found any virtual tables here ..."); 624 | } 625 | } 626 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/ObjectExplorer.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #ifndef __H_OBJECTEXPLORER__ 26 | #define __H_OBJECTEXPLORER__ 27 | 28 | 29 | // Object Explorer From Init 30 | struct object_explorer_info_t 31 | { 32 | TForm *form; 33 | TCustomControl *cv; 34 | TCustomControl *codeview; 35 | strvec_t sv; 36 | object_explorer_info_t(TForm *f) : form(f), cv(NULL) {} 37 | }; 38 | 39 | void object_explorer_form_init(); 40 | 41 | 42 | // VTBL 43 | struct VTBL_info_t 44 | { 45 | qstring vtbl_name; 46 | ea_t ea_begin; 47 | ea_t ea_end; 48 | UINT methods; 49 | 50 | }; 51 | 52 | 53 | extern qvector vtbl_list; 54 | extern qvector ::iterator vtbl_iter; 55 | 56 | 57 | 58 | inline BOOL is_valid_name(LPCSTR name){ return(*((PDWORD) name) == 0x375F3F3F /*"??_7"*/); } 59 | void parse_vft_members(LPCTSTR name, ea_t ea_start, ea_t ea_end); 60 | 61 | void search_objects(bool bForce = true); 62 | 63 | 64 | template BOOL verify_32_t(ea_t ea_ptr, T &rvalue) 65 | { 66 | if(getFlags(ea_ptr)) 67 | { 68 | rvalue = (T) get_32bit(ea_ptr); 69 | return(TRUE); 70 | } 71 | 72 | return(FALSE); 73 | } 74 | 75 | 76 | // RTTI 77 | struct RTTI_info_t 78 | { 79 | PVOID vftable; 80 | PVOID m_data; 81 | char m_d_name[MAXSTR]; // mangled name (prefix: .?AV=classes, .?AU=structs) 82 | }; 83 | 84 | static BOOL is_valid_rtti(RTTI_info_t *pIDA); 85 | static LPSTR get_name(IN RTTI_info_t *pIDA, OUT LPSTR pszBufer, int iSize); 86 | 87 | // returns TRUE if mangled name is a unknown type name 88 | static inline BOOL is_type_name(LPCSTR pszName){ return((*((PUINT)pszName) & 0xFFFFFF) == 0x413F2E /*".?A"*/); } 89 | 90 | 91 | struct PMD 92 | { 93 | int mdisp; // member 94 | int pdisp; // vftable 95 | int vdisp; // place inside vftable 96 | }; 97 | 98 | 99 | struct RTTIBaseClassDescriptor 100 | { 101 | RTTI_info_t *pTypeDescriptor; // type descriptor of the class 102 | UINT numContainedBases; // number of nested classes 103 | PMD pmd; // pointer-to-member displacement info 104 | UINT attributes; // flags (usually 0) 105 | }; 106 | 107 | 108 | struct RTTIClassHierarchyDescriptor 109 | { 110 | UINT signature; // always zero? 111 | UINT attributes; // bit 0 set = multiple inheritance, bit 1 set = virtual inheritance 112 | UINT numBaseClasses; // number of classes in pBaseClassArray 113 | RTTIBaseClassDescriptor **pBaseClassArray; 114 | }; 115 | 116 | const UINT CHDF_MULTIPLE = (1 << 0); 117 | const UINT CHDF_VIRTUAL = (1 << 1); 118 | 119 | 120 | struct RTTICompleteObjectLocator 121 | { 122 | UINT signature; // always zero ? 123 | UINT offset; // offset of this vftable in the complete class 124 | UINT cdOffset; // constructor displacement offset 125 | RTTI_info_t *pTypeDescriptor; // TypeDescriptor of the complete class 126 | RTTIClassHierarchyDescriptor *pClassDescriptor; // 10 Describes inheritance hierarchy 127 | }; 128 | 129 | ea_t find_RTTI(ea_t start_ea, ea_t end_ea); 130 | char* get_demangle_name(ea_t class_addr); 131 | void process_rtti(); 132 | 133 | const char * get_text_disasm(ea_t ea); 134 | 135 | bool get_vbtbl_by_ea(ea_t vtbl_addr, VTBL_info_t &vtbl); 136 | 137 | tid_t create_vtbl_struct(ea_t vtbl_addr, ea_t vtbl_addr_end, char* vtbl_name, uval_t idx, unsigned int* vtbl_len = NULL); 138 | 139 | #endif -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/ObjectFormatMSVC.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #pragma once 26 | #include "Common.h" 27 | 28 | 29 | ////////////////////////////////////////////////////////////////////////// 30 | // 31 | // Based on some impressions and code from ClassInformer plugin 32 | // http://sourceforge.net/projects/classinformer/ 33 | // 34 | ////////////////////////////////////////////////////////////////////////// 35 | 36 | 37 | namespace vftable 38 | { 39 | // vftable info container 40 | struct vtinfo 41 | { 42 | ea_t start, end; 43 | int methodCount; 44 | qstring type_info; 45 | }; 46 | 47 | bool getTableInfo(ea_t ea, vtinfo &info); 48 | 49 | // Returns TRUE if mangled name indicates a vftable 50 | inline bool isValid(LPCSTR name) { return(*((PDWORD)name) == 0x375F3F3F /*"??_7"*/); } 51 | } 52 | 53 | 54 | namespace RTTI 55 | { 56 | #pragma pack(push, 1) 57 | 58 | // std::type_info class representation 59 | struct type_info 60 | { 61 | ea_t vfptr; // type_info class vftable 62 | ea_t _M_data; // NULL until loaded at runtime 63 | char _M_d_name[1]; // Mangled name (prefix: .?AV=classes, .?AU=structs) 64 | 65 | static bool isValid(ea_t typeInfo); 66 | static bool isTypeName(ea_t name); 67 | static int getName(ea_t typeInfo, OUT LPSTR bufffer, int bufferSize); 68 | 69 | }; 70 | const UINT MIN_TYPE_INFO_SIZE = (offsetof(type_info, _M_d_name) + sizeof(".?AVx")); 71 | typedef type_info _TypeDescriptor; 72 | typedef type_info _RTTITypeDescriptor; 73 | 74 | // Base class "Pointer to Member Data" 75 | struct PMD 76 | { 77 | int mdisp; // 00 Member displacement 78 | int pdisp; // 04 Vftable displacement 79 | int vdisp; // 08 Displacement inside vftable 80 | }; 81 | 82 | // Describes all base classes together with information to derived class access dynamically 83 | // attributes flags 84 | const UINT BCD_NOTVISIBLE = 0x01; 85 | const UINT BCD_AMBIGUOUS = 0x02; 86 | const UINT BCD_PRIVORPROTINCOMPOBJ = 0x04; 87 | const UINT BCD_PRIVORPROTBASE = 0x08; 88 | const UINT BCD_VBOFCONTOBJ = 0x10; 89 | const UINT BCD_NONPOLYMORPHIC = 0x20; 90 | const UINT BCD_HASPCHD = 0x40; 91 | 92 | struct _RTTIBaseClassDescriptor 93 | { 94 | #ifndef __EA64__ 95 | ea_t typeDescriptor; // 00 Type descriptor of the class 96 | #else 97 | UINT typeDescriptor; // 00 Type descriptor of the class *X64 int32 offset 98 | #endif 99 | UINT numContainedBases; // 04 Number of nested classes following in the Base Class Array 100 | PMD pmd; // 08 Pointer-to-member displacement info 101 | UINT attributes; // 14 Flags 102 | // 18 When attributes & BCD_HASPCHD 103 | //_RTTIClassHierarchyDescriptor *classDescriptor; *X64 int32 offset 104 | 105 | static bool isValid(ea_t bcd, ea_t colBase64 = NULL); 106 | 107 | }; 108 | 109 | // "Class Hierarchy Descriptor" describes the inheritance hierarchy of a class; shared by all COLs for the class 110 | // attributes flags 111 | const UINT CHD_MULTINH = 0x01; // Multiple inheritance 112 | const UINT CHD_VIRTINH = 0x02; // Virtual inheritance 113 | const UINT CHD_AMBIGUOUS = 0x04; // Ambiguous inheritance 114 | 115 | struct _RTTIClassHierarchyDescriptor 116 | { 117 | UINT signature; // 00 Zero until loaded 118 | UINT attributes; // 04 Flags 119 | UINT numBaseClasses; // 08 Number of classes in the following 'baseClassArray' 120 | #ifndef __EA64__ 121 | ea_t baseClassArray; // 0C _RTTIBaseClassArray* 122 | #else 123 | UINT baseClassArray; // 0C *X64 int32 offset to _RTTIBaseClassArray* 124 | #endif 125 | 126 | static bool isValid(ea_t chd, ea_t colBase64 = NULL); 127 | 128 | }; 129 | 130 | // "Complete Object Locator" location of the complete object from a specific vftable pointer 131 | struct _RTTICompleteObjectLocator 132 | { 133 | UINT signature; // 00 32bit zero, 64bit one, until loaded 134 | UINT offset; // 04 Offset of this vftable in the complete class 135 | UINT cdOffset; // 08 Constructor displacement offset 136 | 137 | #ifndef __EA64__ 138 | ea_t typeDescriptor; // 0C (type_info *) of the complete class 139 | ea_t classDescriptor; // 10 (_RTTIClassHierarchyDescriptor *) Describes inheritance hierarchy 140 | #else 141 | UINT typeDescriptor; // 0C (type_info *) of the complete class *X64 int32 offset 142 | UINT classDescriptor; // 10 (_RTTIClassHierarchyDescriptor *) Describes inheritance hierarchy *X64 int32 offset 143 | UINT objectBase; // 14 Object base offset (base = ptr col - objectBase) 144 | #endif 145 | 146 | 147 | static BOOL isValid(ea_t col); 148 | static BOOL isValid2(ea_t col); 149 | 150 | }; 151 | #pragma pack(pop) 152 | 153 | const WORD IS_TOP_LEVEL = 0x8000; 154 | 155 | void freeWorkingData(); 156 | 157 | BOOL processVftable(ea_t vft, ea_t col, vftable::vtinfo &vi); 158 | } 159 | 160 | 161 | extern void fixEa(ea_t ea); 162 | extern void fixDword(ea_t eaAddress); 163 | extern void fixFunction(ea_t eaFunc); 164 | extern void idaapi setUnknown(ea_t ea, int size); 165 | extern bool getVerifyEa(ea_t ea, ea_t &rValue); 166 | extern BOOL hasAnteriorComment(ea_t ea); 167 | extern void killAnteriorComments(ea_t ea); 168 | 169 | extern BOOL getPlainTypeName(IN LPCSTR mangled, LPSTR outStr); 170 | 171 | extern BOOL optionOverwriteComments, optionPlaceStructs; 172 | 173 | void idaapi getRttiData(); 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/TypeExtractor.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see 21 | . 22 | 23 | ============================================================================== 24 | */ 25 | 26 | #include "Common.h" 27 | #include "TypeReconstructor.h" 28 | #include "TypeExtractor.h" 29 | #include "CtreeExtractor.h" 30 | #include "ObjectFormatMSVC.h" 31 | 32 | #include "Debug.h" 33 | 34 | #ifdef __LINUX__ 35 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 36 | #endif 37 | 38 | #define STRUCT_DUMP_MIN_MEMBER_COUNT 4 39 | 40 | extern qvector vtbl_t_list; 41 | extern std::map rtti_vftables; 42 | 43 | struct obj_fint_t : public ctree_parentee_t 44 | { 45 | std::string vtbl_name; 46 | 47 | std::string var_name; 48 | 49 | bool bFound; 50 | 51 | int idaapi visit_expr(cexpr_t *e); 52 | 53 | obj_fint_t() : bFound(false) {} 54 | }; 55 | 56 | 57 | int idaapi obj_fint_t::visit_expr(cexpr_t *e) 58 | { 59 | // check if the expression being visited is variable 60 | if(e->op == cot_obj) { 61 | // get the variable name 62 | char expr_name[MAXSTR]; 63 | e->print1(expr_name, MAXSTR, NULL); 64 | tag_remove(expr_name, expr_name, 0); 65 | 66 | // check for the target variable 67 | if(!strcmp(expr_name, vtbl_name.c_str())) { 68 | size_t max_parents = 3; 69 | if ( parents.size() < max_parents ) { 70 | max_parents = parents.size(); 71 | } 72 | 73 | for (size_t i = 1 ; i <= max_parents ; i ++) { 74 | citem_t *parent = parents[parents.size() - i]; 75 | if(parent->is_expr() && (parent->op == cot_asg)) { 76 | cexpr_t * target_expr = (cexpr_t *)parent; 77 | while ((target_expr->x != NULL) && (target_expr->op != cot_var) && (target_expr->op != cot_obj)) 78 | target_expr = target_expr->x; 79 | 80 | if (target_expr->op == cot_var) { 81 | target_expr->print1(expr_name, MAXSTR, NULL); 82 | tag_remove(expr_name, expr_name, 0); 83 | var_name = expr_name; 84 | 85 | bFound = true; 86 | 87 | break; 88 | } 89 | } 90 | } 91 | } 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | void idaapi reset_pointer_type(cfuncptr_t cfunc, qstring &var_name) { 98 | lvars_t * locals = cfunc->get_lvars(); 99 | if (locals != NULL) { 100 | qvector::iterator locals_iter; 101 | 102 | for (locals_iter = locals->begin(); locals_iter != locals->end(); locals_iter++) { 103 | if (!strcmp(var_name.c_str(), (*locals_iter).name.c_str())) { 104 | tinfo_t int_type = tinfo_t(BT_INT32); 105 | (*locals_iter).set_final_lvar_type(int_type); 106 | (*locals_iter).set_user_type(); 107 | cfunc->build_c_tree(); 108 | break; 109 | } 110 | } 111 | } 112 | } 113 | 114 | bool idaapi find_var(void *ud) 115 | { 116 | vdui_t &vu = *(vdui_t *)ud; 117 | 118 | // Determine the ctree item to highlight 119 | vu.get_current_item(USE_KEYBOARD); 120 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 121 | 122 | // highlight == NULL might happen if one chooses variable at local variables declaration statement 123 | if(highlight != NULL) 124 | { 125 | // the chosen item must be an expression and of 'variable' type 126 | if(highlight->is_expr() && (highlight->op == cot_obj)) 127 | { 128 | cexpr_t *highl_expr = (cexpr_t *)highlight; 129 | 130 | char expr_name[MAXSTR]; 131 | highlight->print1(expr_name, MAXSTR, NULL); 132 | tag_remove(expr_name, expr_name, 0); 133 | 134 | // initialize type rebuilder 135 | obj_fint_t obj_find; 136 | obj_find.vtbl_name = expr_name; 137 | 138 | 139 | // traverse the ctree structure 140 | obj_find.apply_to(&vu.cfunc->body, NULL); 141 | 142 | if (obj_find.bFound) { 143 | logmsg(DEBUG, obj_find.var_name.c_str()); 144 | // Using this horrible code to remove warnings on GCC 4.9.2. Fix this later. 145 | qstring temp_var2=qstring(obj_find.var_name.c_str()); 146 | qstring &temp_var= temp_var2; 147 | reset_pointer_type(vu.cfunc, temp_var); 148 | 149 | 150 | vu.refresh_ctext(); 151 | } else { 152 | warning("Failed to find variable..."); 153 | logmsg(DEBUG, "Failed to find variable..."); 154 | } 155 | } 156 | } 157 | else 158 | { 159 | logmsg(DEBUG, "Invalid item is choosen"); 160 | } 161 | 162 | return true; 163 | } 164 | 165 | bool idaapi find_var(cfuncptr_t cfunc, qstring vtbl_name, qstring &var_name) 166 | { 167 | obj_fint_t obj_find; 168 | int offs = 0; 169 | if (!strncmp(vtbl_name.c_str(), "const ", 6)) 170 | offs = 6; 171 | obj_find.vtbl_name = vtbl_name.c_str() + offs; 172 | bool bResult = false; 173 | 174 | 175 | // traverse the ctree structure 176 | obj_find.apply_to(&cfunc->body, NULL); 177 | 178 | if (obj_find.bFound) { 179 | var_name = obj_find.var_name.c_str(); 180 | reset_pointer_type(cfunc, var_name); 181 | bResult = true; 182 | } else { 183 | logmsg(DEBUG, "Failed to find variable..."); 184 | } 185 | 186 | return bResult; 187 | } 188 | 189 | tid_t idaapi merge_types(qvector types_to_merge, qstring type_name) { 190 | tid_t struct_type_id = BADADDR; 191 | 192 | std::set offsets; 193 | 194 | if (types_to_merge.size() != 0) { 195 | struct_type_id = add_struc(BADADDR, type_name.c_str()); 196 | if (struct_type_id != 0 || struct_type_id != BADADDR) 197 | { 198 | struc_t * struc = get_struc(struct_type_id); 199 | if(struc != NULL) { 200 | qvector::iterator types_iter; 201 | for (types_iter = types_to_merge.begin(); types_iter != types_to_merge.end(); types_iter ++) { 202 | 203 | tid_t type_id = get_struc_id((*types_iter).c_str()); 204 | if (type_id != BADADDR) { 205 | struc_t * struc_type = get_struc(type_id); 206 | if(struc_type != NULL) { 207 | // enumerate members 208 | for ( ea_t offset = get_struc_first_offset(struc_type) ; offset != BADADDR ; offset = get_struc_next_offset(struc_type, offset)) { 209 | member_t * member_info = get_member(struc_type, offset); 210 | if (member_info != NULL) { 211 | if (offsets.count(member_info->soff) == 0) { 212 | qstring member_name = get_member_name2(member_info->id); 213 | asize_t member_size = get_member_size(member_info); 214 | 215 | if (member_name.find("vftbl_", 0) != -1) { 216 | tinfo_t tif; 217 | if (get_member_tinfo2(member_info, &tif)) { 218 | add_struc_member(struc, member_name.c_str(), member_info->soff, dwrdflag(), NULL, member_size); 219 | member_t * membr = get_member(struc, member_info->soff); 220 | if (membr != NULL) { 221 | set_member_tinfo2(struc, membr, 0, tif, SET_MEMTI_COMPATIBLE); 222 | } 223 | } 224 | } else { 225 | add_struc_member(struc, member_name.c_str(), member_info->soff, member_info->flag, NULL, member_size); 226 | } 227 | 228 | offsets.insert(member_info->soff); 229 | } 230 | } 231 | } 232 | } 233 | } 234 | } 235 | } 236 | } 237 | } 238 | 239 | return struct_type_id; 240 | } 241 | 242 | void get_struct_key(struc_t * struc_type, VTBL_info_t vtbl_info, qstring &file_entry_key, bool &filtered, std::map vtbl_map) { 243 | qstring sub_key; 244 | qstring vtables_sub_key; 245 | int vftbales_num = 0; 246 | int members_count = 0; 247 | for ( ea_t offset = get_struc_first_offset(struc_type) ; offset != BADADDR ; offset = get_struc_next_offset(struc_type, offset)) { 248 | member_t * member_info = get_member(struc_type, offset); 249 | if (member_info != NULL) { 250 | qstring member_name = get_member_name2(member_info->id); 251 | asize_t member_size = get_member_size(member_info); 252 | 253 | if (member_name.find("vftbl_", 0) != -1) { 254 | 255 | ea_t vtable_addr = 0; 256 | int i; 257 | 258 | if (qsscanf(member_name.c_str(), "vftbl_%d_%p", &i, &vtable_addr) > 0) { 259 | if (vtbl_map.count(vtable_addr) != 0) { 260 | vtables_sub_key.cat_sprnt("_%d", vtbl_map[vtable_addr].methods); 261 | } 262 | } 263 | 264 | vftbales_num ++; 265 | } 266 | 267 | sub_key.cat_sprnt("_%d", member_size); 268 | 269 | members_count ++; 270 | } 271 | } 272 | file_entry_key.sprnt("t_%d_%d", vtbl_info.methods, vftbales_num); 273 | file_entry_key += vtables_sub_key; 274 | file_entry_key += sub_key; 275 | 276 | if (members_count < STRUCT_DUMP_MIN_MEMBER_COUNT) 277 | filtered = true; 278 | } 279 | 280 | void idaapi dump_type_info(int file_id, VTBL_info_t vtbl_info, qstring type_name, std::map vtbl_map) { 281 | tid_t type_id = get_struc_id(type_name.c_str()); 282 | if (type_id != BADADDR) { 283 | struc_t * struc_type = get_struc(type_id); 284 | if(struc_type != NULL) { 285 | qstring file_entry_key; 286 | qstring key_hash; 287 | bool filtered = false; 288 | 289 | get_struct_key(struc_type, vtbl_info, file_entry_key, filtered, vtbl_map); 290 | get_hash_of_string(file_entry_key, key_hash); 291 | 292 | if (!filtered) { 293 | qstring file_entry_val; 294 | tinfo_t new_type = create_typedef(type_name.c_str()); 295 | if(new_type.is_correct()) { 296 | if (new_type.print(&file_entry_val, NULL, PRTYPE_DEF | PRTYPE_1LINE)) { 297 | qstring line; 298 | 299 | line = key_hash + ";" + file_entry_key + ";"; 300 | line.cat_sprnt("%p;", vtbl_info.ea_begin); 301 | line += file_entry_val + ";"; 302 | 303 | if (rtti_vftables.count(vtbl_info.ea_begin) != 0) { 304 | vftable::vtinfo vi = rtti_vftables[vtbl_info.ea_begin]; 305 | line += vi.type_info; 306 | } 307 | line.rtrim(); 308 | line += "\r\n"; 309 | qwrite(file_id, line.c_str(), line.length()); 310 | } 311 | } 312 | } 313 | } 314 | } 315 | } 316 | 317 | bool idaapi check_subtype(VTBL_info_t vtbl_info, qstring subtype_name) { 318 | bool bResult = false; 319 | qstring search_str; 320 | search_str.sprnt("_%p", vtbl_info.ea_begin); 321 | 322 | tid_t type_id = get_struc_id(subtype_name.c_str()); 323 | if (type_id != BADADDR) { 324 | struc_t * struc_type = get_struc(type_id); 325 | if(struc_type != NULL) { 326 | // enumerate members 327 | for ( ea_t offset = get_struc_first_offset(struc_type) ; offset != BADADDR ; offset = get_struc_next_offset(struc_type, offset)) { 328 | member_t * member_info = get_member(struc_type, offset); 329 | if (member_info != NULL) { 330 | qstring member_name = get_member_name2(member_info->id); 331 | if (member_name.find(search_str, 0) != -1) { 332 | bResult = true; 333 | break; 334 | } 335 | } 336 | } 337 | } 338 | } 339 | 340 | return bResult; 341 | } 342 | 343 | bool idaapi extract_all_types(void *ud) 344 | { 345 | logmsg(DEBUG, "extract_types()"); 346 | 347 | // find vtables in the binary 348 | search_objects(false); 349 | 350 | qvector ::iterator vtbl_iter; 351 | 352 | std::map vtbl_map; 353 | for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) 354 | vtbl_map[(*vtbl_iter).ea_begin] = (*vtbl_iter); 355 | 356 | int file_id = create_open_file("types.txt"); 357 | if (file_id != BADADDR) { 358 | int struct_no = 0; 359 | 360 | for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) { 361 | qstring info_msg; 362 | info_msg.cat_sprnt("Processing vtable %s\n", (*vtbl_iter).vtbl_name.c_str()); 363 | logmsg(DEBUG, info_msg.c_str()); 364 | 365 | qstring type_name; 366 | type_name.sprnt("struc_2_%d", struct_no); 367 | 368 | ea_t cur_vt_ea = (*vtbl_iter).ea_begin; 369 | int struct_subno = 0; 370 | 371 | qvector types_to_merge; 372 | for (ea_t addr = get_first_dref_to(cur_vt_ea); addr != BADADDR; addr = get_next_dref_to(cur_vt_ea, addr)) { 373 | qstring name; 374 | get_func_name2(&name, addr); 375 | 376 | 377 | 378 | qstring info_msg1; 379 | info_msg1.cat_sprnt("\t%s", name.c_str()); 380 | logmsg(DEBUG, info_msg1.c_str()); 381 | 382 | func_t *pfn = get_func(addr); 383 | if ( pfn != NULL ) { 384 | hexrays_failure_t hf; 385 | cfuncptr_t cfunc = decompile(pfn, &hf); 386 | if ( cfunc != NULL ) { 387 | qstring var_name; 388 | info_msg.clear(); 389 | 390 | if (find_var(cfunc, (*vtbl_iter).vtbl_name, var_name)) { 391 | info_msg.cat_sprnt(" : %s\n", var_name.c_str()); 392 | logmsg(DEBUG, info_msg.c_str()); 393 | 394 | qstring sub_type_name = type_name; 395 | sub_type_name.cat_sprnt("_%d", struct_subno); 396 | struct_subno ++; 397 | 398 | if (reconstruct_type(cfunc, var_name, sub_type_name)) { 399 | if (check_subtype((*vtbl_iter), sub_type_name)) { 400 | types_to_merge.push_back(sub_type_name); 401 | } 402 | } 403 | } else { 404 | info_msg.cat_sprnt(" : none\n", var_name.c_str()); 405 | logmsg(DEBUG, info_msg.c_str()); 406 | } 407 | } 408 | } 409 | } 410 | 411 | struct_no ++; 412 | 413 | merge_types(types_to_merge, type_name); 414 | dump_type_info(file_id, (*vtbl_iter), type_name, vtbl_map); 415 | } 416 | 417 | qclose(file_id); 418 | } 419 | 420 | return true; 421 | } 422 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/TypeExtractor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #ifndef __H_TYPEEXTRACTOR__ 26 | #define __H_TYPEEXTRACTOR__ 27 | 28 | #pragma once 29 | 30 | #include "ObjectExplorer.h" 31 | 32 | bool idaapi extract_all_types(void *ud); 33 | 34 | bool idaapi find_var(void *ud); 35 | bool idaapi find_var(cfuncptr_t cfunc, qstring vtbl_name, qstring &var_name); 36 | 37 | tid_t idaapi merge_types(qvector types_to_merge, qstring type_name); 38 | 39 | void idaapi dump_type_info(int file_id, VTBL_info_t vtbl_info, qstring type_name); 40 | 41 | #endif -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/TypeReconstructor.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see 21 | . 22 | 23 | ============================================================================== 24 | */ 25 | 26 | #include "Common.h" 27 | #include "TypeReconstructor.h" 28 | 29 | #include "Debug.h" 30 | 31 | #ifndef __LINUX__ 32 | #include 33 | #else 34 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 35 | #endif 36 | 37 | /* 38 | Representation of the reconstructed type 39 | */ 40 | struct type_reference { 41 | tinfo_t type; 42 | 43 | // offset of the referenced field by the helper, if any 44 | int hlpr_off; 45 | 46 | // size of the referenced field by the helper, if any 47 | int hlpr_size; 48 | 49 | // offset of the field after all checks 50 | int final_off; 51 | 52 | // size of the field after all checks 53 | int final_size; 54 | 55 | void idaapi init(cexpr_t *e); 56 | 57 | void idaapi update_hlpr(int off, int num); 58 | 59 | void idaapi update_type(cexpr_t *e); 60 | 61 | int idaapi update_offset(int offset); 62 | 63 | int idaapi update_size(int offset); 64 | 65 | int idaapi get_type_increment_val(); 66 | 67 | int idaapi get_offset(); 68 | 69 | int idaapi get_size(); 70 | }; 71 | 72 | void idaapi type_reference::init(cexpr_t *e) { 73 | type = e->type; 74 | hlpr_off = 0; 75 | final_off = 0; 76 | 77 | hlpr_size = 0; 78 | final_size = 0; 79 | } 80 | 81 | void idaapi type_reference::update_type(cexpr_t *e) { 82 | type = e->type; 83 | } 84 | 85 | int idaapi type_reference::get_type_increment_val() { 86 | if (type.is_ptr()) { 87 | ptr_type_data_t ptr_deets; 88 | if(type.get_ptr_details(&ptr_deets)) { 89 | return ptr_deets.obj_type.get_size(); 90 | } 91 | } else if (type.is_array()) { 92 | return 1; 93 | } 94 | 95 | return 1; 96 | } 97 | 98 | int idaapi type_reference::update_offset(int offset) { 99 | int update_factor = get_type_increment_val(); 100 | final_off += update_factor * offset; 101 | 102 | return final_off; 103 | } 104 | 105 | int idaapi type_reference::update_size(int size) { 106 | final_size = size; 107 | return final_size; 108 | } 109 | 110 | int idaapi type_reference::get_offset() 111 | { 112 | return final_off + hlpr_off; 113 | } 114 | 115 | int idaapi type_reference::get_size() 116 | { 117 | if(hlpr_size != 0) 118 | return hlpr_size; 119 | else 120 | return final_size; 121 | } 122 | 123 | void idaapi type_reference::update_hlpr(int off, int num) 124 | { 125 | hlpr_off = off; 126 | hlpr_size = num; 127 | } 128 | 129 | struct type_builder_t : public ctree_parentee_t 130 | { 131 | std::vector expression_to_match; 132 | 133 | struct struct_filed 134 | { 135 | int offset; 136 | int size; 137 | ea_t vftbl; 138 | }; 139 | 140 | // std::vector structure; 141 | 142 | std::map structure; 143 | 144 | int idaapi visit_expr(cexpr_t *e); 145 | 146 | char * get_structure(char * name, char * buffer, int buffer_size); 147 | 148 | tid_t get_structure(const char * name=NULL); 149 | 150 | bool get_structure(std::map &struc); 151 | 152 | int get_structure_size(); 153 | 154 | bool match_expression(char *expr_name); 155 | 156 | bool idaapi check_memptr(struct_filed &str_fld); 157 | 158 | bool idaapi check_idx(struct_filed &str_fld); 159 | 160 | bool idaapi check_helper(citem_t *parent, int &offs, int &size); 161 | 162 | bool idaapi check_ptr(cexpr_t *e, struct_filed &str_fld); 163 | 164 | ea_t idaapi get_vftbl(cexpr_t *e); 165 | }; 166 | 167 | int get_idx_type_size(cexpr_t *idx_expr) 168 | { 169 | qstring buf; 170 | idx_expr->type.print(&buf); 171 | 172 | if(strstr(buf.c_str(), "char")) 173 | return 1; 174 | else if(strstr(buf.c_str(), "short")) 175 | return 2; 176 | else if(strstr(buf.c_str(), "int")) 177 | return 4; 178 | 179 | return 0; 180 | } 181 | 182 | bool idaapi type_builder_t::check_helper(citem_t *parent, int &off, int &num) 183 | { 184 | if(parent->op == cot_call) 185 | { 186 | cexpr_t *expr_2 = (cexpr_t *)parent; 187 | if(!strcmp(get_ctype_name(expr_2->x->op), "helper")) 188 | { 189 | char buff[MAXSTR]; 190 | expr_2->x->print1(buff, MAXSTR, NULL); 191 | tag_remove(buff, buff, 0); 192 | 193 | if(!strcmp(buff, "LOBYTE")) 194 | { 195 | num = 1; 196 | off = 0; 197 | } 198 | else if(!strcmp(buff, "HIBYTE") || !strcmp(buff, "BYTE3")) 199 | { 200 | num = 1; 201 | off = 3; 202 | } 203 | else if(!strcmp(buff, "BYTE1")) 204 | { 205 | num = 1; 206 | off = 1; 207 | } 208 | else if(!strcmp(buff, "BYTE2")) 209 | { 210 | num = 1; 211 | off = 2; 212 | } 213 | else if(!strcmp(buff, "LOWORD")) 214 | { 215 | num = 2; 216 | off = 0; 217 | } 218 | else if(!strcmp(buff, "HIWORD")) 219 | { 220 | num = 2; 221 | off = 2; 222 | } 223 | else 224 | { 225 | return false; 226 | } 227 | 228 | return true; 229 | } 230 | } 231 | 232 | return false; 233 | } 234 | 235 | bool idaapi type_builder_t::check_memptr(struct_filed &str_fld) 236 | { 237 | // check if it has at least two parents 238 | if ( parents.size() > 2 ) 239 | { 240 | citem_t *parent_1 = parents.back(); 241 | 242 | // check if its parent is memptr 243 | if(parent_1->is_expr() && (parent_1->op == cot_memptr)) 244 | { 245 | citem_t *parent_2 = parents[parents.size() - 2]; 246 | citem_t *parent_3 = NULL; 247 | 248 | int num = 0; 249 | int off = 0; 250 | 251 | // check presence of the helper block 252 | bool bHelper = check_helper(parent_2, off, num); 253 | if(bHelper) 254 | parent_3 = parents[parents.size() - 3]; 255 | else 256 | parent_3 = parent_2; 257 | 258 | if(parent_2->is_expr() && (parent_2->op == cot_asg)) 259 | { 260 | cexpr_t *expr = (cexpr_t *)parent_1; 261 | 262 | if(bHelper) 263 | { 264 | str_fld.offset = expr->m + off; 265 | str_fld.size = num; 266 | } 267 | else 268 | { 269 | str_fld.offset = expr->m; 270 | str_fld.size = expr->ptrsize; 271 | } 272 | 273 | return true; 274 | } 275 | } 276 | } 277 | 278 | return false; 279 | } 280 | 281 | ea_t idaapi type_builder_t::get_vftbl(cexpr_t *e) { 282 | ea_t vftbl = BADADDR; 283 | 284 | if (e->is_expr()) { 285 | if ((e->op == cot_cast) && (e->x != NULL)) 286 | e = e->x; 287 | 288 | if ((e->op == cot_ref) && (e->x != NULL)) 289 | e = e->x; 290 | 291 | if (e->op == cot_obj) { 292 | vftbl = e->obj_ea; 293 | } 294 | } 295 | 296 | return vftbl; 297 | } 298 | 299 | bool idaapi type_builder_t::check_ptr(cexpr_t *e, struct_filed &str_fld) 300 | { 301 | str_fld.offset = 0; 302 | str_fld.size = 0; 303 | str_fld.vftbl = BADADDR; 304 | 305 | type_reference referInfo; 306 | referInfo.init(e); 307 | 308 | qstring dbg_info; 309 | 310 | bool done = false; 311 | 312 | int par_size = parents.size(); 313 | // check if it has at least three parents 314 | if ( par_size > 2 ) 315 | { 316 | int offset = 0; 317 | int parent_idx = 1; 318 | 319 | int num = 0; 320 | int off = 0; 321 | 322 | for (size_t i = 0 ; i < parents.size() - 1 ; i ++) { 323 | citem_t *parent_i = parents[parents.size() - i - 1]; 324 | 325 | // if its parent is addition 326 | if(parent_i->is_expr() && (parent_i->op == cot_add)) 327 | { 328 | cexpr_t *expr_2 = (cexpr_t *)parent_i; 329 | 330 | // get index_value 331 | char buff[MAXSTR]; 332 | expr_2->y->print1(buff, MAXSTR, NULL); 333 | tag_remove(buff, buff, 0); 334 | 335 | int base = 10; 336 | if (strncmp(buff, "0x", 2) == 0) 337 | base = 16; 338 | 339 | offset = strtol(buff, NULL, base); 340 | 341 | referInfo.update_offset(offset); 342 | } else if(parent_i->is_expr() && (parent_i->op == cot_cast)) { 343 | referInfo.update_type((cexpr_t *)parent_i); 344 | } else if(parent_i->is_expr() && check_helper((cexpr_t *)parent_i, off, num)) { 345 | referInfo.update_hlpr(off, num); 346 | } else if(parent_i->is_expr() && (parent_i->op == cot_ptr)) { 347 | referInfo.update_size(((cexpr_t *)parent_i)->ptrsize); 348 | citem_t *parent_ii = parents[parents.size() - i - 2]; 349 | if ((parent_ii->is_expr()) && (((cexpr_t *)parent_ii)->op == cot_asg) && (((cexpr_t *)parent_ii)->x == parent_i)) { 350 | ea_t vftbl = get_vftbl(((cexpr_t *)parent_ii)->y); 351 | if (vftbl != BADADDR) 352 | str_fld.vftbl = vftbl; 353 | } 354 | done = true; 355 | break; 356 | } else if(parent_i->is_expr() && (parent_i->op == cot_memptr)) { 357 | referInfo.update_offset(((cexpr_t *)parent_i)->m); 358 | referInfo.update_size(((cexpr_t *)parent_i)->ptrsize); 359 | done = true; 360 | break; 361 | } else if(parent_i->is_expr() && (parent_i->op == cot_asg)) { 362 | if (((cexpr_t *)parent_i)->y == e) { //parents[parents.size() - i]) { 363 | char expr_name[MAXSTR]; 364 | ((cexpr_t *)parent_i)->x->print1(expr_name, MAXSTR, NULL); 365 | tag_remove(expr_name, expr_name, 0); 366 | 367 | char comment[258]; 368 | memset(comment, 0x00, sizeof(comment)); 369 | sprintf_s(comment, sizeof(comment), "monitoring %s\r\n", expr_name); 370 | 371 | logmsg(DEBUG, comment); 372 | 373 | expression_to_match.push_back(expr_name); 374 | 375 | 376 | } else { 377 | get_vftbl(((cexpr_t *)parent_i)->y); 378 | } 379 | done = true; 380 | break; 381 | } else if(parent_i->is_expr() && (parent_i->op == cot_call)) { 382 | done = true; 383 | break; 384 | } 385 | } 386 | } 387 | 388 | if(done) { 389 | str_fld.offset = referInfo.get_offset(); 390 | str_fld.size = referInfo.get_size(); 391 | if (str_fld.size == 0) { 392 | str_fld.size = 4; 393 | } 394 | 395 | if (str_fld.vftbl != BADADDR) { 396 | char tmp[1024]; 397 | memset(tmp, 0x00, sizeof(tmp)); 398 | sprintf_s(tmp, sizeof(tmp), "vftbl reference detected at offset 0x%X, ea=0x%08X\r\n", str_fld.offset, str_fld.vftbl); 399 | 400 | logmsg(DEBUG, tmp); 401 | } 402 | } 403 | 404 | return done; 405 | } 406 | 407 | bool idaapi type_builder_t::check_idx(struct_filed &str_fld) 408 | { 409 | // check if it has at least two parents 410 | if ( parents.size() > 1 ) 411 | { 412 | citem_t *parent_1 = parents.back(); 413 | 414 | // if its parrent is 415 | if(parent_1->is_expr() && (parent_1->op == cot_memptr)) 416 | { 417 | citem_t *parent_2 = parents[parents.size() - 2]; 418 | if(parent_2->op == cot_idx) 419 | { 420 | cexpr_t *expr_2 = (cexpr_t *)parent_2; 421 | 422 | // get index_value 423 | char buff[MAXSTR]; 424 | expr_2->y->print1(buff, MAXSTR, NULL); 425 | tag_remove(buff, buff, 0); 426 | int num = atoi(buff); 427 | 428 | citem_t *parent_3 = parents[parents.size() - 3]; 429 | if(parent_3->is_expr() && (parent_3->op == cot_asg)) 430 | { 431 | cexpr_t *expr_1 = (cexpr_t *)parent_1; 432 | 433 | str_fld.offset = expr_1->m + num; 434 | str_fld.size = get_idx_type_size(expr_2); 435 | 436 | return true; 437 | } 438 | } 439 | } 440 | } 441 | 442 | return false; 443 | } 444 | 445 | bool type_builder_t::match_expression(char *expr_name) { 446 | for (std::vector::iterator it = expression_to_match.begin(); it != expression_to_match.end(); ++it) { 447 | if ((*it).compare(expr_name) == 0) 448 | return true; 449 | } 450 | 451 | return false; 452 | } 453 | 454 | int idaapi type_builder_t::visit_expr(cexpr_t *e) 455 | { 456 | // check if the expression being visited is variable 457 | if(e->op == cot_var) 458 | { 459 | // get the variable name 460 | char expr_name[MAXSTR]; 461 | e->print1(expr_name, MAXSTR, NULL); 462 | tag_remove(expr_name, expr_name, 0); 463 | 464 | // check for the target variable 465 | if(match_expression(expr_name)) 466 | { 467 | struct_filed str_fld; 468 | 469 | if(check_ptr(e, str_fld)) { 470 | std::pair::iterator,bool> ret; 471 | ret = structure.insert(std::pair(str_fld.offset, str_fld)); 472 | if ((ret.second == false) && (str_fld.vftbl != BADADDR)) { 473 | structure[str_fld.offset] = str_fld; 474 | } 475 | } 476 | } 477 | } 478 | 479 | return 0; 480 | } 481 | 482 | int type_builder_t::get_structure_size() 483 | { 484 | int highest_offset = 0; 485 | int reference_size = 0; 486 | 487 | 488 | for(std::map::iterator i = structure.begin(); i != structure.end() ; i ++) 489 | { 490 | if(highest_offset < i->second.offset) 491 | { 492 | highest_offset = i ->second.offset; 493 | reference_size = i->second.size; 494 | } 495 | } 496 | 497 | return highest_offset + reference_size; 498 | } 499 | 500 | tid_t type_builder_t::get_structure(const char * name) 501 | { 502 | tid_t struct_type_id = add_struc(BADADDR, name); 503 | if (struct_type_id != 0 || struct_type_id != -1) 504 | { 505 | struc_t * struc = get_struc(struct_type_id); 506 | if(struc != NULL) 507 | { 508 | opinfo_t opinfo; 509 | opinfo.tid = struct_type_id; 510 | 511 | int j = 0; 512 | 513 | for(std::map::iterator i = structure.begin(); i != structure.end() ; i ++) 514 | { 515 | VTBL_info_t vtbl; 516 | 517 | flags_t member_flgs = 0; 518 | if(i->second.size == 1) 519 | member_flgs = byteflag(); 520 | else if (i->second.size == 2) 521 | member_flgs = wordflag(); 522 | else if (i->second.size == 4) 523 | member_flgs = dwrdflag(); 524 | else if (i->second.size == 8) 525 | member_flgs = qwrdflag(); 526 | 527 | char field_name[258]; 528 | memset(field_name, 0x00, sizeof(field_name)); 529 | 530 | if((i->second.vftbl != BADADDR) && get_vbtbl_by_ea(i->second.vftbl, vtbl)) { 531 | qstring vftbl_name = name; 532 | vftbl_name.cat_sprnt("_VTABLE_%d_%p", i->second.offset, i->second.vftbl); 533 | 534 | tid_t vtbl_str_id = create_vtbl_struct(vtbl.ea_begin, vtbl.ea_end, (char *)vftbl_name.c_str(), 0); 535 | if (vtbl_str_id != BADADDR) { 536 | sprintf_s(field_name, sizeof(field_name), "vftbl_%d_%p", j, i->second.vftbl); 537 | int iRet = add_struc_member(struc, field_name, i->second.offset, member_flgs, NULL, i->second.size); 538 | 539 | member_t * membr = get_member_by_name(struc, field_name); 540 | if (membr != NULL) { 541 | tinfo_t new_type = create_typedef((char *)vftbl_name.c_str()); 542 | if(new_type.is_correct()) { 543 | smt_code_t dd = set_member_tinfo2(struc, membr, 0, make_pointer(new_type), SET_MEMTI_COMPATIBLE); 544 | } 545 | } 546 | } 547 | } else { 548 | sprintf_s(field_name, sizeof(field_name), "field_%d", i->second.offset); 549 | int iRet = add_struc_member(struc, field_name, i->second.offset, member_flgs, NULL, i->second.size); 550 | } 551 | 552 | 553 | 554 | j ++; 555 | } 556 | } 557 | } 558 | return struct_type_id; 559 | } 560 | 561 | bool type_builder_t::get_structure(std::map &struc) 562 | { 563 | bool bResult = false; 564 | 565 | if (structure.size() != 0) { 566 | for(std::map::iterator i = structure.begin(); i != structure.end() ; i ++) { 567 | struc[i->first] = i->second; 568 | } 569 | 570 | bResult = true; 571 | } 572 | 573 | return bResult; 574 | } 575 | 576 | bool idaapi reconstruct_type(void *ud) 577 | { 578 | vdui_t &vu = *(vdui_t *)ud; 579 | 580 | // Determine the ctree item to highlight 581 | vu.get_current_item(USE_KEYBOARD); 582 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 583 | 584 | // highlight == NULL might happen if one chooses variable at local variables declaration statement 585 | if(highlight != NULL) 586 | { 587 | // the chosen item must be an expression and of 'variable' type 588 | if(highlight->is_expr() && (highlight->op == cot_var)) 589 | { 590 | cexpr_t *highl_expr = (cexpr_t *)highlight; 591 | 592 | // initialize type rebuilder 593 | type_builder_t type_bldr; 594 | 595 | 596 | char highl_expr_name[MAXSTR]; 597 | 598 | highl_expr->print1(highl_expr_name, MAXSTR, NULL); 599 | tag_remove(highl_expr_name, highl_expr_name, 0); 600 | 601 | type_bldr.expression_to_match.push_back(highl_expr_name); 602 | 603 | // traverse the ctree structure 604 | type_bldr.apply_to(&vu.cfunc->body, NULL); 605 | 606 | if (type_bldr.structure.size() != 0) { 607 | qstring struct_name = "struct_name"; 608 | 609 | va_list va; 610 | va_end(va); 611 | 612 | char * type_name = vaskstr(0, struct_name.c_str(), "Enter type name", va); 613 | if(type_name != NULL) { 614 | tid_t struct_type_id = type_bldr.get_structure(type_name); 615 | 616 | if(struct_type_id != 0 || struct_type_id != -1) { 617 | 618 | 619 | tinfo_t new_type = create_typedef(type_name); 620 | if(new_type.is_correct()) { 621 | qstring type_str; 622 | qstring pref = "New type created:\r\n"; 623 | if (new_type.print(&type_str, NULL, PRTYPE_DEF | PRTYPE_MULTI)) 624 | logmsg(DEBUG, (pref + type_str).c_str()); 625 | lvar_t * lvar = vu.item.get_lvar(); 626 | 627 | vu.set_lvar_type(lvar, make_pointer(new_type)); 628 | vu.refresh_ctext(); 629 | } 630 | } 631 | } 632 | } else { 633 | warning("Failed to reconstruct type, no field references have been found..."); 634 | logmsg(DEBUG, "Failed to reconstruct type, no field references have been found..."); 635 | } 636 | } 637 | } 638 | else 639 | { 640 | logmsg(DEBUG, "Invalid item is choosen"); 641 | } 642 | 643 | return true; 644 | } 645 | 646 | bool idaapi reconstruct_type(cfuncptr_t cfunc, qstring var_name, qstring type_name) 647 | { 648 | bool bResult = false; 649 | // initialize type rebuilder 650 | type_builder_t type_bldr; 651 | type_bldr.expression_to_match.push_back(var_name.c_str()); 652 | 653 | // traverse the ctree structure 654 | type_bldr.apply_to(&cfunc->body, NULL); 655 | 656 | if (type_bldr.structure.size() != 0) { 657 | tid_t struct_type_id = type_bldr.get_structure(type_name.c_str()); 658 | 659 | if(struct_type_id != 0 || struct_type_id != -1) { 660 | tinfo_t new_type = create_typedef(type_name.c_str()); 661 | if(new_type.is_correct()) { 662 | qstring pref = "New type created: "; 663 | qstring type_str = type_name.c_str(); 664 | type_str += "\n"; 665 | // if (new_type.print(&type_str, NULL, PRTYPE_DEF | PRTYPE_MULTI)) 666 | logmsg(DEBUG, (pref + type_str).c_str()); 667 | 668 | bResult = true; 669 | } 670 | } 671 | } else { 672 | warning("Failed to reconstruct type, no field references have been found..."); 673 | logmsg(DEBUG, "Failed to reconstruct type, no field references have been found..."); 674 | } 675 | 676 | return bResult; 677 | } 678 | 679 | 680 | 681 | 682 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/TypeReconstructor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #ifndef __H_OBJECTTYPE__ 26 | #define __H_OBJECTTYPE__ 27 | 28 | #pragma once 29 | 30 | #include "Common.h" 31 | #include "ObjectExplorer.h" 32 | 33 | 34 | using namespace std; 35 | /* 36 | typedef std::basic_string TSTRING; 37 | typedef std::basic_string WSTRING; 38 | typedef std::basic_string ASTRING; 39 | typedef std::vector BUFFER; 40 | */ 41 | #ifdef _UNICODE 42 | #define tcout std::wcout 43 | #else 44 | #define tcout std::cout 45 | #endif 46 | 47 | 48 | bool idaapi reconstruct_type(void *ud); 49 | bool idaapi reconstruct_type(cfuncptr_t cfunc, qstring var_name, qstring type_name); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/Utility.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see 21 | . 22 | 23 | ============================================================================== 24 | */ 25 | 26 | #include "Common.h" 27 | #include "Utility.h" 28 | 29 | #include "Debug.h" 30 | 31 | #ifdef __LINUX__ 32 | #include "Linux.h" 33 | #endif 34 | 35 | void split_qstring(qstring &options, qstring &splitter, qvector &result) { 36 | size_t start_pos = 0; 37 | 38 | do { 39 | size_t npos = options.find(splitter, start_pos); 40 | if (npos != -1) { 41 | if (npos != start_pos) { 42 | result.push_back(options.substr(start_pos, npos)); 43 | } 44 | start_pos = npos + splitter.length(); 45 | } 46 | else { 47 | qstring token = options.substr(start_pos); 48 | if (token.length() != 0) 49 | result.push_back(token); 50 | break; 51 | } 52 | } while (start_pos < options.length()); 53 | } 54 | 55 | 56 | // SHA1 implementation 57 | #define SHA1CircularShift(bits,word)(((word) << (bits)) | ((word) >> (32-(bits)))) 58 | 59 | void SHA1PadMessage(SHA1Context *); 60 | void SHA1ProcessMessageBlock(SHA1Context *); 61 | 62 | int SHA1Reset(SHA1Context *context) 63 | { 64 | if (!context) 65 | return shaNull; 66 | 67 | context->Length_Low = 0; 68 | context->Length_High = 0; 69 | context->Message_Block_Index = 0; 70 | context->Intermediate_Hash[0] = 0x67452301; 71 | context->Intermediate_Hash[1] = 0xEFCDAB89; 72 | context->Intermediate_Hash[2] = 0x98BADCFE; 73 | context->Intermediate_Hash[3] = 0x10325476; 74 | context->Intermediate_Hash[4] = 0xC3D2E1F0; 75 | context->Computed = 0; 76 | context->Corrupted = 0; 77 | return shaSuccess; 78 | } 79 | 80 | int SHA1Result(SHA1Context *context, uint8_t Message_Digest[SHA1HashSize]) 81 | { 82 | int i; 83 | if (!context || !Message_Digest) 84 | return shaNull; 85 | 86 | if (context->Corrupted) 87 | return context->Corrupted; 88 | 89 | if (!context->Computed) 90 | { 91 | SHA1PadMessage(context); 92 | for (i = 0; i<64; ++i) 93 | context->Message_Block[i] = 0; 94 | 95 | context->Length_Low = 0; /* and clear length */ 96 | context->Length_High = 0; 97 | context->Computed = 1; 98 | } 99 | for (i = 0; i < SHA1HashSize; ++i) 100 | Message_Digest[i] = context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03)); 101 | 102 | return shaSuccess; 103 | } 104 | 105 | int SHA1Input(SHA1Context *context, const uint8_t *message_array, unsigned length) 106 | { 107 | if (!length) 108 | { 109 | return shaSuccess; 110 | } 111 | if (!context || !message_array) 112 | { 113 | return shaNull; 114 | } 115 | if (context->Computed) 116 | { 117 | context->Corrupted = shaStateError; 118 | return shaStateError; 119 | } 120 | if (context->Corrupted) 121 | { 122 | return context->Corrupted; 123 | } 124 | while (length-- && !context->Corrupted) 125 | { 126 | context->Message_Block[context->Message_Block_Index++] = 127 | (*message_array & 0xFF); 128 | context->Length_Low += 8; 129 | if (context->Length_Low == 0) 130 | { 131 | context->Length_High++; 132 | if (context->Length_High == 0) 133 | context->Corrupted = 1; 134 | } 135 | if (context->Message_Block_Index == 64) 136 | SHA1ProcessMessageBlock(context); 137 | message_array++; 138 | } 139 | return shaSuccess; 140 | } 141 | 142 | void SHA1ProcessMessageBlock(SHA1Context *context) 143 | { 144 | const uint32_t K[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6}; 145 | int t; // Loop counter 146 | uint32_t temp; // Temporary word value 147 | uint32_t W[80]; // Word sequence 148 | uint32_t A, B, C, D, E; // Word buffers 149 | // Initialize the first 16 words in the array W 150 | for (t = 0; t < 16; t++) 151 | { 152 | W[t] = context->Message_Block[t * 4] << 24; 153 | W[t] |= context->Message_Block[t * 4 + 1] << 16; 154 | W[t] |= context->Message_Block[t * 4 + 2] << 8; 155 | W[t] |= context->Message_Block[t * 4 + 3]; 156 | } 157 | 158 | for (t = 16; t < 80; t++) 159 | W[t] = SHA1CircularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); 160 | 161 | A = context->Intermediate_Hash[0]; 162 | B = context->Intermediate_Hash[1]; 163 | C = context->Intermediate_Hash[2]; 164 | D = context->Intermediate_Hash[3]; 165 | E = context->Intermediate_Hash[4]; 166 | 167 | for (t = 0; t < 20; t++) 168 | { 169 | temp = SHA1CircularShift(5, A) + 170 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 171 | E = D; 172 | D = C; 173 | C = SHA1CircularShift(30, B); 174 | B = A; 175 | A = temp; 176 | } 177 | 178 | for (t = 20; t < 40; t++) 179 | { 180 | temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; 181 | E = D; 182 | D = C; 183 | C = SHA1CircularShift(30, B); 184 | B = A; 185 | A = temp; 186 | } 187 | 188 | for (t = 40; t < 60; t++) 189 | { 190 | temp = SHA1CircularShift(5, A) + 191 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 192 | E = D; 193 | D = C; 194 | C = SHA1CircularShift(30, B); 195 | B = A; 196 | A = temp; 197 | } 198 | 199 | for (t = 60; t < 80; t++) 200 | { 201 | temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; 202 | E = D; 203 | D = C; 204 | C = SHA1CircularShift(30, B); 205 | B = A; 206 | A = temp; 207 | } 208 | 209 | context->Intermediate_Hash[0] += A; 210 | context->Intermediate_Hash[1] += B; 211 | context->Intermediate_Hash[2] += C; 212 | context->Intermediate_Hash[3] += D; 213 | context->Intermediate_Hash[4] += E; 214 | context->Message_Block_Index = 0; 215 | } 216 | 217 | void SHA1PadMessage(SHA1Context *context) 218 | { 219 | 220 | if (context->Message_Block_Index > 55) 221 | { 222 | context->Message_Block[context->Message_Block_Index++] = 0x80; 223 | while (context->Message_Block_Index < 64) 224 | context->Message_Block[context->Message_Block_Index++] = 0; 225 | 226 | SHA1ProcessMessageBlock(context); 227 | while (context->Message_Block_Index < 56) 228 | context->Message_Block[context->Message_Block_Index++] = 0; 229 | } 230 | else 231 | { 232 | context->Message_Block[context->Message_Block_Index++] = 0x80; 233 | while (context->Message_Block_Index < 56) 234 | context->Message_Block[context->Message_Block_Index++] = 0; 235 | } 236 | 237 | context->Message_Block[56] = context->Length_High >> 24; 238 | context->Message_Block[57] = context->Length_High >> 16; 239 | context->Message_Block[58] = context->Length_High >> 8; 240 | context->Message_Block[59] = context->Length_High; 241 | context->Message_Block[60] = context->Length_Low >> 24; 242 | context->Message_Block[61] = context->Length_Low >> 16; 243 | context->Message_Block[62] = context->Length_Low >> 8; 244 | context->Message_Block[63] = context->Length_Low; 245 | SHA1ProcessMessageBlock(context); 246 | } 247 | 248 | char int_to_hex(uint8_t integ) { 249 | if (integ < 10) 250 | return '0' + integ; 251 | else 252 | return 'a' + (integ - 10); 253 | } 254 | 255 | void SHA1MessageDigestToString(uint8_t Message_Digest[SHA1HashSize], char outbuffer[SHA1HashSize * 2]) { 256 | for (int i = 0; i < SHA1HashSize; i++) { 257 | outbuffer[i * 2] = int_to_hex(Message_Digest[i] >> 4); 258 | outbuffer[i * 2 + 1] = int_to_hex(Message_Digest[i] & 0xF); 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/Utility.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2015 2 | REhints 3 | All rights reserved. 4 | 5 | ============================================================================== 6 | 7 | This file is part of HexRaysCodeXplorer 8 | 9 | HexRaysCodeXplorer is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | ============================================================================== 23 | */ 24 | 25 | #ifndef __H_UTILITY__ 26 | #define __H_UTILITY__ 27 | 28 | #pragma once 29 | 30 | #include "Common.h" 31 | 32 | 33 | // Size of string with out terminator 34 | #define SIZESTR(x) (sizeof(x) - 1) 35 | 36 | 37 | typedef qlist eaList; 38 | typedef std::set eaSet; 39 | typedef std::map eaRefMap; 40 | struct earef 41 | { 42 | ea_t ea; 43 | UINT refs; 44 | }; 45 | 46 | 47 | // 48 | // #pragma message(__LOC__ "important part to be changed") 49 | // #pragma message(__LOC2__ "error C9901: wish that error would exist") 50 | 51 | // Get IDA 32 bit value with verification 52 | template bool getVerify32_t(ea_t eaPtr, T &rValue) 53 | { 54 | // Location valid? 55 | if (isLoaded(eaPtr)) 56 | { 57 | // Get 32bit value 58 | rValue = (T) get_32bit(eaPtr); 59 | return true; 60 | } 61 | 62 | return false; 63 | } 64 | 65 | // Get address/pointer value 66 | inline ea_t getEa(ea_t ea) 67 | { 68 | #ifndef __EA64__ 69 | return((ea_t) get_32bit(ea)); 70 | #else 71 | return((ea_t) get_64bit(ea)); 72 | #endif 73 | } 74 | 75 | 76 | // Returns TRUE if ea_t sized value flags 77 | inline BOOL isEa(flags_t f) 78 | { 79 | #ifndef __EA64__ 80 | return(isDwrd(f)); 81 | #else 82 | return(isQwrd(f)); 83 | #endif 84 | } 85 | 86 | #ifndef _SHA_enum_ 87 | #define _SHA_enum_ 88 | enum 89 | { 90 | shaSuccess = 0, 91 | shaNull, // Null pointer parameter 92 | shaInputTooLong, // input data too long 93 | shaStateError // called Input after Result 94 | }; 95 | #endif 96 | #define SHA1HashSize 20 97 | 98 | typedef struct SHA1Context 99 | { 100 | uint32_t Intermediate_Hash[SHA1HashSize / 4]; // Message Digest 101 | uint32_t Length_Low; // Message length in bits 102 | uint32_t Length_High; // Message length in bits 103 | // Index into message block array 104 | int_least16_t Message_Block_Index; 105 | uint8_t Message_Block[64]; // 512-bit message blocks 106 | int Computed; // Is the digest computed? 107 | int Corrupted; // Is the message digest corrupted? 108 | } SHA1Context; 109 | 110 | int SHA1Reset(SHA1Context *); 111 | int SHA1Input(SHA1Context *, const uint8_t *, unsigned int); 112 | int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1HashSize]); 113 | void SHA1MessageDigestToString(uint8_t Message_Digest[SHA1HashSize], char outbuffer[SHA1HashSize * 2]); 114 | 115 | void split_qstring(qstring &options, qstring &splitter, qvector &result); 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /CodeXplorer v2.0 [BH Edition]/source code/HexRaysCodeXplorer/makefile: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | LD=ld 3 | 4 | #CFLAGS=-D__LINUX__ -DUSE_DANGEROUS_FUNCTIONS -D__PLUGIN__ -D__X64__ 5 | #CFLAGS=-m32 -fPIC -D__LINUX__ -DUSE_DANGEROUS_FUNCTIONS -D__PLUGIN__ -D__EA64__ 6 | 7 | CFLAGS=-m32 -fPIC -D__LINUX__ -DUSE_DANGEROUS_FUNCTIONS -D__PLUGIN__ 8 | LDFLAGS=-shared -m32 9 | 10 | # TODO: add conditional compilation over -lida or -lida64 based on the X64 11 | #LIBS= -lida64 -lpro -lc -lpthread -ldl 12 | LIBS= -lida -lpro -lc -lpthread -ldl 13 | 14 | LIBDIR=-L./ -L$(IDA_DIR) -L/usr/lib/i386-linux-gnu/ 15 | SRCDIR=./ 16 | HEXRAYS_SDK=$(IDA_DIR)/plugins/hexrays_sdk 17 | SRC=$(SRCDIR)CodeXplorer.cpp \ 18 | $(SRCDIR)GraphBuilder.cpp \ 19 | $(SRCDIR)ObjectExplorer.cpp \ 20 | $(SRCDIR)TypeReconstructor.cpp \ 21 | $(SRCDIR)CtreeExtractor.cpp \ 22 | $(SRCDIR)TypeExtractor.cpp \ 23 | $(SRCDIR)Utility.cpp \ 24 | $(SRCDIR)ObjectFormatMSVC.cpp \ 25 | $(SRCDIR)Debug.cpp 26 | OBJS=$(subst .cpp,.o,$(SRC)) 27 | EXECUTABLE=HexRaysCodeXplorer 28 | INCLUDES=-I$(IDA_SDK)/include -I$(HEXRAYS_SDK)/include 29 | 30 | # only used on command line anyway 31 | #DEFINE=__X64__ -D__LINUX__ 32 | #DEFINE=__EA64__ -D__LINUX__ 33 | 34 | all: HexRaysCodeExplorer.plx 35 | 36 | HexRaysCodeExplorer.plx: $(OBJS) 37 | #ln -f -s $(IDA_SDK)/lib/x64_linux_gcc_64/pro.a libpro.a 38 | ln -f -s $(IDA_SDK)/lib/x86_linux_gcc_32/pro.a libpro.a 39 | $(CC) $(LDFLAGS) $(LIBDIR) -o HexRaysCodeExplorer.plx $(OBJS) $(LIBS) 40 | 41 | %.o: %.cpp 42 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ 43 | 44 | clean: 45 | rm -f $(OBJS) HexRaysCodeExplorer.plx 46 | 47 | install: 48 | cp -f HexRaysCodeExplorer.plx $(IDA_DIR)/plugins 49 | -------------------------------------------------------------------------------- /CodeXplorer_Test/test_all_ctress.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import subprocess 4 | 5 | def run_ida(path_to_file): 6 | if os.path.isfile(path_to_file + ".idb"): 7 | os.remove(path_to_file + ".idb") 8 | print "Starting ida on %s \r\n" % path_to_file 9 | subprocess.call(["C:\Program Files (x86)\IDA 6.8\idaq.exe", "-A", "-OHexRaysCodeXplorer:dump_ctrees:dump_types", path_to_file]) 10 | print "Finishing ida\r\n" 11 | os.remove(path_to_file + ".idb") 12 | 13 | 14 | def copy_ctrees_file(dirpath, file_hash, suff): 15 | copy_output_file(dirpath, "ctrees", file_hash, suff) 16 | 17 | def copy_types_file(dirpath, file_hash, suff): 18 | copy_output_file(dirpath, "types", file_hash, suff) 19 | 20 | def copy_output_file(dirpath, file_type, file_hash, suff): 21 | path_to_file_old = os.path.join(dirpath, file_type + ".txt") 22 | path_to_file_new = os.path.join(dirpath, file_type + "_" + file_hash + "_" + suff + ".txt") 23 | if os.path.isfile(path_to_file_old): 24 | os.rename(path_to_file_old, path_to_file_new) 25 | else: 26 | print "no " + file_type + ".txt file\r\n" 27 | 28 | 29 | 30 | def main(sample_dir, out_file): 31 | f = [] 32 | 33 | packed = {} 34 | 35 | for (dirpath, dirnames, filenames) in os.walk(sample_dir): 36 | for file_name in filenames: 37 | if not file_name.endswith(".idb"): 38 | run_ida(os.path.join(dirpath, file_name)) 39 | copy_ctrees_file(dirpath, file_name, "1") 40 | copy_types_file(dirpath, file_name, "1") 41 | 42 | run_ida(os.path.join(dirpath, file_name)) 43 | copy_ctrees_file(dirpath, file_name, "2") 44 | copy_types_file(dirpath, file_name, "2") 45 | # break 46 | # else: 47 | # os.remove(os.path.join(dirpath, file_name)) 48 | 49 | 50 | 51 | if __name__=='__main__': 52 | if len(sys.argv) < 2: 53 | print('Usage: sample_dir outfile'.format(sys.argv[0])) 54 | else: 55 | main(sys.argv[1], sys.argv[2]) -------------------------------------------------------------------------------- /CodeXplorer_Test/test_ctrees.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | 5 | def load_ctrees_file(file_path): 6 | result = [] 7 | 8 | with open(file_path) as f: 9 | lines = f.readlines() 10 | 11 | for ctree_line in lines: 12 | result.append(ctree_line.strip().split(";")) 13 | 14 | return result 15 | 16 | 17 | def compare_ctrees(ctrees_1, ctrees_2): 18 | hashes_normalized = {} 19 | hashes_not_normalized = {} 20 | 21 | for ctree_tuple in ctrees_1: 22 | if hashes_normalized.get(ctree_tuple[0]) is not None: 23 | hashes_normalized[ctree_tuple[0]] += 1 24 | else: 25 | hashes_normalized[ctree_tuple[0]] = 1 26 | 27 | if hashes_not_normalized.get(ctree_tuple[1]) is not None: 28 | hashes_not_normalized[ctree_tuple[1]] += 1 29 | else: 30 | hashes_not_normalized[ctree_tuple[1]] = 1 31 | 32 | for ctree_tuple in ctrees_2: 33 | if hashes_normalized.get(ctree_tuple[0]) is not None: 34 | hashes_normalized[ctree_tuple[0]] -= 1 35 | else: 36 | hashes_normalized[ctree_tuple[0]] = -1 37 | 38 | if hashes_not_normalized.get(ctree_tuple[1]) is not None: 39 | hashes_not_normalized[ctree_tuple[1]] -= 1 40 | else: 41 | hashes_not_normalized[ctree_tuple[1]] = -1 42 | 43 | return (hashes_normalized, hashes_not_normalized) 44 | 45 | def check_hashes(hashes): 46 | for hash_key in hashes.keys(): 47 | if hashes[hash_key] > 0: 48 | print "Missing 2 hash " + hash_key, str(hashes[hash_key]) + "\r\n" 49 | elif hashes[hash_key] < 0: 50 | print "Missing 1 hash " + hash_key, str(hashes[hash_key]) + "\r\n" 51 | # elif hashes[hash_key] != 1: 52 | # print "Incorrect hash " + hash_key, str(hashes[hash_key]) + "\r\n" 53 | 54 | 55 | 56 | if __name__=='__main__': 57 | if len(sys.argv) < 3: 58 | print('Usage: sample_dir outfile'.format(sys.argv[0])) 59 | else: 60 | ctrees_1 = load_ctrees_file(sys.argv[1]) 61 | ctrees_2 = load_ctrees_file(sys.argv[2]) 62 | 63 | hashes_normalized, hashes_not_normalized = compare_ctrees(ctrees_1, ctrees_2) 64 | 65 | print "Checking normalized hashes\r\n" 66 | check_hashes(hashes_normalized) 67 | 68 | print "Checking not normalized hashes\r\n" 69 | check_hashes(hashes_not_normalized) -------------------------------------------------------------------------------- /CodeXplorer_Test/test_ctrees_batch.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import operator 4 | 5 | hash_stats = {} 6 | 7 | def load_ctrees_file(file_path): 8 | result = [] 9 | 10 | with open(file_path) as f: 11 | lines = f.readlines() 12 | 13 | for ctree_line in lines: 14 | result.append(ctree_line.strip().split(";")) 15 | 16 | return result 17 | 18 | def compare_ctrees(ctrees_1, ctrees_2): 19 | hashes_normalized = {} 20 | hashes_not_normalized = {} 21 | 22 | for ctree_tuple in ctrees_1: 23 | if hashes_normalized.get(ctree_tuple[0]) is not None: 24 | hashes_normalized[ctree_tuple[0]] += 1 25 | else: 26 | hashes_normalized[ctree_tuple[0]] = 1 27 | 28 | if hashes_not_normalized.get(ctree_tuple[1]) is not None: 29 | hashes_not_normalized[ctree_tuple[1]] += 1 30 | else: 31 | hashes_not_normalized[ctree_tuple[1]] = 1 32 | 33 | for ctree_tuple in ctrees_2: 34 | if hashes_normalized.get(ctree_tuple[0]) is not None: 35 | hashes_normalized[ctree_tuple[0]] -= 1 36 | else: 37 | hashes_normalized[ctree_tuple[0]] = -1 38 | 39 | if hashes_not_normalized.get(ctree_tuple[1]) is not None: 40 | hashes_not_normalized[ctree_tuple[1]] -= 1 41 | else: 42 | hashes_not_normalized[ctree_tuple[1]] = -1 43 | 44 | return (hashes_normalized, hashes_not_normalized) 45 | 46 | def check_hashes(hashes): 47 | for hash_key in hashes.keys(): 48 | if hashes[hash_key] > 0: 49 | print "Missing 2 hash " + hash_key, str(hashes[hash_key]) + "\r\n" 50 | elif hashes[hash_key] < 0: 51 | print "Missing 1 hash " + hash_key, str(hashes[hash_key]) + "\r\n" 52 | 53 | 54 | def process_hash(dirpath, file_hash): 55 | file_1 = os.path.join(dirpath, "ctrees_" + file_hash + "_1.txt") 56 | file_2 = os.path.join(dirpath, "ctrees_" + file_hash + "_2.txt") 57 | 58 | ctrees_1 = load_ctrees_file(file_1) 59 | ctrees_2 = load_ctrees_file(file_2) 60 | 61 | hashes_normalized, hashes_not_normalized = compare_ctrees(ctrees_1, ctrees_2) 62 | 63 | for hash_val in hashes_normalized.keys(): 64 | if hash_stats.get(hash_val) is None: 65 | hash_stats[hash_val] = [1, [file_hash]] 66 | else: 67 | hash_stats[hash_val][0] += 1 68 | hash_stats[hash_val][1].append(file_hash) 69 | 70 | print "Checking normalized hashes\r\n" 71 | check_hashes(hashes_normalized) 72 | 73 | print "Checking not normalized hashes\r\n" 74 | check_hashes(hashes_not_normalized) 75 | 76 | def main(sample_dir, out_file): 77 | test_hashes = set() 78 | 79 | for (dirpath, dirnames, filenames) in os.walk(sample_dir): 80 | for file_name in filenames: 81 | if file_name.startswith("ctrees_"): 82 | file_hash = file_name.split("_")[1] 83 | if file_hash not in test_hashes: 84 | process_hash(dirpath, file_hash) 85 | test_hashes.add(file_hash) 86 | 87 | print sorted(hash_stats.items(), key=operator.itemgetter(1))[10:] 88 | 89 | if __name__=='__main__': 90 | if len(sys.argv) < 2: 91 | print('Usage: sample_dir outfile'.format(sys.argv[0])) 92 | else: 93 | main(sys.argv[1], sys.argv[2]) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ###DISTRIBUTING THE RECONSTRUCTION OF HIGH-LEVEL INTERMEDIATE REPRESENTATION FOR LARGE SCALE MALWARE ANALYSIS 2 | 3 | Malware is acknowledged as an important threat and the number of new samples grows at an absurd pace. Additionally, targeted and so called advanced malware became the rule, not the exception. Analysts and companies use different degrees of automation to be able to handle the challenge, but there is always a gap. Reverse engineering is an even harder task due to the increased amount of work and the stricter time-frame to accomplish it. This has a direct impact on the investigative process and thus makes prevention of future threats more challenging. 4 | 5 | In this work, the authors discuss distributed reverse engineering techniques, using intermediate representation (thanks Hex-Rays team for support us in this research) in a clustered environment. The results presented demonstrate different uses for this kind of approach, for example to find algorithmic commonalities between malware families. 6 | 7 | A higher level abstraction of the malware code is constructed from the abstract syntax tree (ctree) provided by Hex-Rays Decompiler. That abstraction facilitates the extraction of characteristics such as domain generation algorithms (DGA), custom encryption and specific parsers for configuration data. In order to reduce the number of false positives in some C++ metadata identification, such as virtual function tables and RTTI, the authors created the object-oriented artifacts directly from the analyzed malware. 8 | 9 | The extracted characteristics of 2 million malware samples are analyzed and the presented results provide a rich dataset to improve malware analysis efforts and threat intelligence initiatives. With that dataset, other researchers will be able to extract a ctree from new samples and compare to the millions we performed. 10 | 11 | As an additional contribution, the gathered representation together with all the raw information from the samples will be available to other researchers after the presentation; together with additional ideas for future development. The developed Hex-Rays Decompiler plugin and analysis/automation tools used to extract the characteristics will also be made available to the audience on Github. -------------------------------------------------------------------------------- /crypto_scan/crypto_scan.py: -------------------------------------------------------------------------------- 1 | # Based on https://bitbucket.org/daniel_plohmann/simplifire.idascope 2 | 3 | from idascope.core.CryptoIdentifier import CryptoIdentifier 4 | from idascope.core.IdaProxy import IdaProxy 5 | 6 | ida_proxy = IdaProxy() 7 | 8 | 9 | def main(): 10 | ida_proxy.Wait() 11 | 12 | ci = CryptoIdentifier() 13 | 14 | # Crypto patterns 15 | 16 | ci.scanCryptoPatterns() 17 | signature_hits = ci.getSignatureHits() 18 | 19 | fdump = open("crypto_sig_scan.txt", "w") 20 | for signature in signature_hits: 21 | fdump.write("%s\n" % signature) 22 | 23 | for hit in signature_hits[signature]: 24 | f_name = ida_proxy.GetFunctionName(hit.start_address) 25 | f_address = ida_proxy.LocByName(f_name) 26 | new_f_name = "crypto_" + f_name 27 | 28 | if (f_address != ida_proxy.BAD_ADDR) and (not f_name.startswith("crypto_")): 29 | ida_proxy.MakeNameEx(f_address, new_f_name, SN_NOWARN) 30 | fdump.write("0x%x %s\n" % (f_address, new_f_name)) 31 | else: 32 | fdump.write("0x%x\n" % hit.start_address) 33 | 34 | for xref in hit.code_refs_to: 35 | xref_name = ida_proxy.GetFunctionName(xref[0]) 36 | xref_address = ida_proxy.LocByName(xref_name) 37 | if (xref_address != ida_proxy.BAD_ADDR) and (xref[1] == True) and (not xref_name.startswith("crypto_")): 38 | new_x_name = "crypto_ref_" + xref_name 39 | ida_proxy.MakeNameEx(xref[0], new_x_name, SN_NOWARN) 40 | fdump.write(" 0x%x %s\n" % (xref[0], new_x_name)) 41 | fdump.write("\n") 42 | fdump.close() 43 | 44 | with open("crypto_patterns_done", "w"): 45 | pass 46 | 47 | # Custom crypto 48 | 49 | ci.scanAritlog() 50 | heur_hits = ci.getAritlogBlocks(0.4, 1.0, 8, 100, 0, 1, True, True, True) 51 | 52 | tmp_dict = {} 53 | fdump = open("crypto_heur_scan.txt", "w") 54 | for hit in heur_hits: 55 | f_name = ida_proxy.GetFunctionName(hit.start_ea) 56 | f_address = ida_proxy.LocByName(f_name) 57 | if f_address not in tmp_dict.keys(): 58 | tmp_dict[f_address] = {"function_address": f_address, "num_blocks": 1, \ 59 | "num_log_arith_instructions": hit.num_log_arit_instructions} 60 | 61 | if (f_address != ida_proxy.BAD_ADDR) and (not f_name.startswith("crypto_")): 62 | new_f_name = "crypto_x_" + f_name 63 | ida_proxy.MakeNameEx(f_address, new_f_name, SN_NOWARN) 64 | 65 | checked_name = ida_proxy.GetFunctionName(f_address) 66 | fdump.write("0x%x %s\nnum_arith_instr: %d; arith_rate: %2.2f;\n" % (hit.start_ea, checked_name, \ 67 | tmp_dict[f_address]["num_log_arith_instructions"], (100.0 * hit.getAritlogRating(True)))) 68 | fdump.write("\n") 69 | else: 70 | tmp_dict[f_address]["num_blocks"] += 1 71 | tmp_dict[f_address]["num_log_arith_instructions"] += hit.num_log_arit_instructions 72 | fdump.close() 73 | 74 | with open("crypto_custom_done", "w"): 75 | pass 76 | 77 | if __name__ == '__main__': 78 | main() 79 | -------------------------------------------------------------------------------- /crypto_scan/idascope/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/BlackHat_2015/209ed880816cbdceca5188ed1146a9bdd46b7cde/crypto_scan/idascope/__init__.py -------------------------------------------------------------------------------- /crypto_scan/idascope/core/CryptoIdentifier.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ######################################################################## 3 | # Copyright (c) 2012 4 | # Daniel Plohmann gmailcom> 5 | # Alexander Hanel gmailcom> 6 | # All rights reserved. 7 | ######################################################################## 8 | # 9 | # This file is part of IDAscope 10 | # 11 | # IDAscope is free software: you can redistribute it and/or modify it 12 | # under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, but 17 | # WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | # General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see 23 | # . 24 | # 25 | ######################################################################## 26 | # Credits: 27 | # - Scanning algorithm for certificates is based on work by 28 | # kyprizel's dump_certs.py 29 | # (http://www.kyprizel.net/work/ida/getkeys.py) 30 | # which is in turn based on work by Tobias Klein 31 | # (http://www.trapkit.de/research/sslkeyfinder/) 32 | ######################################################################## 33 | 34 | import time 35 | import re 36 | 37 | from IdaProxy import IdaProxy 38 | from helpers.PatternManager import PatternManager 39 | from helpers.GraphHelper import GraphHelper 40 | import helpers.Misc 41 | 42 | from idascope.core.structures.Segment import Segment 43 | from idascope.core.structures.CryptoSignatureHit import CryptoSignatureHit 44 | from idascope.core.structures.AritlogBasicBlock import AritlogBasicBlock 45 | 46 | 47 | class CryptoIdentifier(): 48 | """ 49 | This class contains the logic to perform Crypto identification. 50 | Two techniques are currently supported: 51 | 1. A heuristic approach that identifies functions and basic blocks 52 | based on the ratio of arithmetic/logic instructions to all instructions 53 | 2. A signature-based approach, using the signatures defined in PatternManager 54 | """ 55 | 56 | def __init__(self): 57 | self.name = "CryptoIdentifier" 58 | print ("[*] loading CryptoIdentifier") 59 | self.time = time 60 | self.re = re 61 | self.GraphHelper = GraphHelper 62 | self.CryptoSignatureHit = CryptoSignatureHit 63 | self.AritlogBasicBlock = AritlogBasicBlock 64 | self.Segment = Segment 65 | self.pm = PatternManager() 66 | self.low_rating_threshold = 0.4 67 | self.high_rating_threshold = 1.0 68 | self.low_instruction_threshold = 8 69 | self.high_instruction_threshold = 100 70 | # if the threshold is set to this value, it is automatically expanded to infinite. 71 | self.max_instruction_threshold = 100 72 | self.low_call_threshold = 0 73 | self.high_call_threshold = 1 74 | # if the threshold is set to this value, it is automatically expanded to infinite. 75 | self.max_call_threshold = 10 76 | # if at least this fraction of a signature's length' has been identified 77 | # consecutively, the location is marked as a signature hit. 78 | self.match_filter_factor = 0.5 79 | self.aritlog_blocks = [] 80 | self.signature_hits = [] 81 | self.ida_proxy = IdaProxy() 82 | return 83 | 84 | def scan(self): 85 | """ 86 | Scan the whole IDB with all available techniques. 87 | """ 88 | self.scanAritlog() 89 | self.scanCryptoPatterns() 90 | 91 | ################################################################################ 92 | # Aritlog scanning 93 | ################################################################################ 94 | 95 | def scanAritlog(self): 96 | """ 97 | scan with the arithmetic/logic heuristic 98 | @return: a list of AritLogBasicBlock data objects that fulfill the parameters as specified 99 | """ 100 | print ("[*] CryptoIdentifier: Starting aritlog heuristic analysis.") 101 | self.aritlog_blocks = [] 102 | time_before = self.time.time() 103 | for function_ea in self.ida_proxy.Functions(): 104 | function_chart = self.ida_proxy.FlowChart(self.ida_proxy.get_func(function_ea)) 105 | calls_in_function = 0 106 | function_blocks = [] 107 | function_dgraph = {} 108 | blocks_in_loops = set() 109 | for current_block in function_chart: 110 | block = self.AritlogBasicBlock(current_block.startEA, current_block.endEA) 111 | for instruction in self.ida_proxy.Heads(block.start_ea, block.end_ea): 112 | if self.ida_proxy.isCode(self.ida_proxy.GetFlags(instruction)): 113 | mnemonic = self.ida_proxy.GetMnem(instruction) 114 | has_identical_operands = self.ida_proxy.GetOperandValue(instruction, 0) == \ 115 | self.ida_proxy.GetOperandValue(instruction, 1) 116 | block.updateInstructionCount(mnemonic, has_identical_operands) 117 | if mnemonic == "call": 118 | calls_in_function += 1 119 | function_blocks.append(block) 120 | # prepare graph for Tarjan's algorithm 121 | succeeding_blocks = [succ.startEA for succ in current_block.succs()] 122 | function_dgraph[current_block.startEA] = succeeding_blocks 123 | # add trivial loops 124 | if current_block.startEA in succeeding_blocks: 125 | block.is_contained_in_trivial_loop = True 126 | blocks_in_loops.update([current_block.startEA]) 127 | # perform Tarjan's algorithm to identify strongly connected components (= loops) in the function graph 128 | graph_helper = self.GraphHelper() 129 | strongly_connected = graph_helper.calculateStronglyConnectedComponents(function_dgraph) 130 | non_trivial_loops = [component for component in strongly_connected if len(component) > 1] 131 | for component in non_trivial_loops: 132 | for block in component: 133 | blocks_in_loops.update([block]) 134 | for block in function_blocks: 135 | if block.start_ea in blocks_in_loops: 136 | block.is_contained_in_loop = True 137 | block.num_calls_in_function = calls_in_function 138 | self.aritlog_blocks.extend(function_blocks) 139 | print ("[*] Heuristics analysis took %3.2f seconds." % (self.time.time() - time_before)) 140 | 141 | return self.getAritlogBlocks(self.low_rating_threshold, self.high_rating_threshold, 142 | self.low_instruction_threshold, self.high_instruction_threshold, 143 | self.low_call_threshold, self.high_call_threshold, 144 | False, False, False) 145 | 146 | def _updateThresholds(self, min_rating, max_rating, min_instr, max_instr, min_call, max_call): 147 | """ 148 | update all six threshold bounds 149 | @param min_rating: the minimum arit/log ratio a basic block must have 150 | @type min_rating: float 151 | @param max_rating: the maximum arit/log ratio a basic block can have 152 | @type max_rating: float 153 | @param min_instr: the minimum number of instructions a basic block must have 154 | @type min_instr: int 155 | @param max_instr: the minimum number of instructions a basic block can have 156 | @type max_instr: int 157 | @param min_call: the minimum number of calls a basic block must have 158 | @type min_call: int 159 | @param max_call: the minimum number of calls a basic block can have 160 | @type max_call: int 161 | """ 162 | self.low_rating_threshold = max(0.0, min_rating) 163 | self.high_rating_threshold = min(1.0, max_rating) 164 | self.low_instruction_threshold = max(0, min_instr) 165 | if max_instr >= self.max_instruction_threshold: 166 | # we cap the value here and safely assume there is no block with more than 1000000 instructions 167 | self.high_instruction_threshold = 1000000 168 | else: 169 | self.high_instruction_threshold = max_instr 170 | self.low_call_threshold = max(0, min_call) 171 | if max_call >= self.max_call_threshold: 172 | # we cap the value here and safely assume there is no block with more than 1000000 instructions 173 | self.high_call_threshold = 1000000 174 | else: 175 | self.high_call_threshold = max_call 176 | 177 | def getAritlogBlocks(self, min_rating, max_rating, min_instr, max_instr, min_api, max_api, is_nonzero, \ 178 | is_looped, is_trivially_looped): 179 | """ 180 | get all blocks that are within the limits specified by the heuristic parameters. 181 | parameters are the same as in function "_updateThresholds" except 182 | param is_nonzero: defines whether zeroing instructions (like xor eax, eax) shall be counted or not. 183 | type is_nonzero: boolean 184 | param is_looped: defines whether only basic blocks in loops shall be selected 185 | type is_looped: boolean 186 | @return: a list of AritlogBasicBlock data objects, according to the parameters 187 | """ 188 | self._updateThresholds(min_rating, max_rating, min_instr, max_instr, min_api, max_api) 189 | return [block for block in self.aritlog_blocks if 190 | (self.high_rating_threshold >= block.getAritlogRating(is_nonzero) >= self.low_rating_threshold) and 191 | (self.high_instruction_threshold >= block.num_instructions >= self.low_instruction_threshold) and 192 | (self.high_call_threshold >= block.num_calls_in_function >= self.low_call_threshold) and 193 | (not is_looped or block.is_contained_in_loop) and 194 | (not is_trivially_looped or block.is_contained_in_trivial_loop)] 195 | 196 | def getUnfilteredBlockCount(self): 197 | """ 198 | returns the number of basic blocks that have been analyzed. 199 | @return: (int) number of basic blocks 200 | """ 201 | return len(self.aritlog_blocks) 202 | 203 | ################################################################################ 204 | # Signature scanning 205 | ################################################################################ 206 | 207 | def getSegmentData(self): 208 | """ 209 | returns the raw bytes of the segments as stored by IDA 210 | @return: a list of Segment data objects. 211 | """ 212 | segments = [] 213 | for segment_ea in self.ida_proxy.Segments(): 214 | try: 215 | segment = self.Segment() 216 | segment.start_ea = segment_ea 217 | segment.end_ea = self.ida_proxy.SegEnd(segment_ea) 218 | segment.name = self.ida_proxy.SegName(segment_ea) 219 | buf = "" 220 | for ea in helpers.Misc.lrange(segment_ea, self.ida_proxy.SegEnd(segment_ea)): 221 | buf += chr(self.ida_proxy.get_byte(ea)) 222 | segment.data = buf 223 | segments.append(segment) 224 | except: 225 | print ("[!] Tried to access invalid segment data. An error has occurred while address conversion") 226 | return segments 227 | 228 | def scanCryptoPatterns(self, pattern_size=32): 229 | crypt_results = [] 230 | print ("[*] CryptoIdentifier: Starting crypto signature scanning.") 231 | time_before_matching = self.time.time() 232 | segments = self.getSegmentData() 233 | keywords = self.pm.getTokenizedSignatures(pattern_size) 234 | for keyword in keywords.keys(): 235 | for segment in segments: 236 | crypt_results.extend([self.CryptoSignatureHit(segment.start_ea + match.start(), keywords[keyword], keyword) for match in self.re.finditer(self.re.escape(keyword), segment.data)]) 237 | variable_matches = self.scanVariablePatterns() 238 | crypt_results.extend(variable_matches) 239 | print ("[*] Full matching took %3.2f seconds and resulted in %d hits." % (self.time.time() - time_before_matching, len(crypt_results))) 240 | self.signature_hits = crypt_results 241 | return crypt_results 242 | 243 | def scanVariablePatterns(self): 244 | # the scanning code is roughly based on kyprizel's signature scan, see credtis above for more information 245 | crypt_results = [] 246 | variable_signatures = self.pm.getVariableSignatures() 247 | for var_sig in variable_signatures.keys(): 248 | current_seg = self.ida_proxy.FirstSeg() 249 | seg_end = self.ida_proxy.SegEnd(current_seg) 250 | while current_seg != self.ida_proxy.BAD_ADDR: 251 | signature_hit = self.ida_proxy.find_binary(current_seg, seg_end, variable_signatures[var_sig], 16, 1) 252 | if signature_hit != self.ida_proxy.BAD_ADDR: 253 | crypt_results.append(self.CryptoSignatureHit(signature_hit, [var_sig], variable_signatures[var_sig])) 254 | current_seg = signature_hit + variable_signatures[var_sig].count(" ") + 1 255 | else: 256 | current_seg = self.ida_proxy.NextSeg(seg_end) 257 | if not current_seg == self.ida_proxy.BAD_ADDR: 258 | seg_end = self.ida_proxy.SegEnd(current_seg) 259 | return crypt_results 260 | 261 | def getSignatureLength(self, signature_name): 262 | """ 263 | returns the length for a signature, identified by its name 264 | @param signature_name: name for a signature, e.g. "ADLER 32" 265 | @type signature_name: str 266 | @return: (int) length of the signature. 267 | """ 268 | for item in self.pm.signatures.items(): 269 | if item[1] == signature_name: 270 | return len(item[0]) 271 | return 0 272 | 273 | def getSignatureHits(self): 274 | """ 275 | Get all signature hits that have a length of at least match_filter_factor percent 276 | of the signature they triggered. 277 | Hits are grouped by signature names. 278 | @return: a dictionary with key/value entries of the following form: ("signature name", [CryptoSignatureHit]) 279 | """ 280 | sorted_hits = sorted(self.signature_hits) 281 | unified_hits = [] 282 | 283 | previous_signature_names = [] 284 | for hit in sorted_hits: 285 | hit_intersection = [element for element in hit.signature_names if element in previous_signature_names] 286 | if len(hit_intersection) == 0: 287 | previous_signature_names = hit.signature_names 288 | unified_hits.append(self.CryptoSignatureHit(hit.start_address, hit.signature_names, \ 289 | hit.matched_signature)) 290 | else: 291 | previous_signature_names = hit_intersection 292 | previous_hit = unified_hits[-1] 293 | if hit.start_address == previous_hit.start_address + len(previous_hit.matched_signature): 294 | previous_hit.matched_signature += hit.matched_signature 295 | previous_hit.signature_names = hit_intersection 296 | else: 297 | unified_hits.append(self.CryptoSignatureHit(hit.start_address, hit.signature_names, \ 298 | hit.matched_signature)) 299 | 300 | filtered_hits = [] 301 | for hit in unified_hits: 302 | if len(hit.matched_signature) >= max([self.match_filter_factor * self.getSignatureLength(name) for name in hit.signature_names]): 303 | hit.code_refs_to = self.getXrefsToAddress(hit.start_address) 304 | filtered_hits.append(hit) 305 | 306 | grouped_hits = {} 307 | for hit in filtered_hits: 308 | for name in hit.signature_names: 309 | if name not in grouped_hits: 310 | grouped_hits[name] = [hit] 311 | else: 312 | grouped_hits[name].append(hit) 313 | 314 | return grouped_hits 315 | 316 | def getXrefsToAddress(self, address): 317 | """ 318 | get all references to a certain address. 319 | These are no xrefs in IDA sense but references to the crypto signatures. 320 | If the signature points to an instruction, e.g. if a constant is moved to a register, the return is flagged as 321 | "True", meaning it is an in-code reference. 322 | @param address: an arbitrary address 323 | @type address: int 324 | @return: a list of tuples (int, boolean) 325 | """ 326 | xrefs = [] 327 | head_to_address = self.ida_proxy.PrevHead(address, address - 14) 328 | if head_to_address != 0xFFFFFFFF: 329 | flags = self.ida_proxy.GetFlags(head_to_address) 330 | if self.ida_proxy.isCode(flags): 331 | xrefs.append((head_to_address, True)) 332 | for x in self.ida_proxy.XrefsTo(address): 333 | flags = self.ida_proxy.GetFlags(x.frm) 334 | if self.ida_proxy.isCode(flags): 335 | xrefs.append((x.frm, False)) 336 | return xrefs 337 | -------------------------------------------------------------------------------- /crypto_scan/idascope/core/IdaProxy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ######################################################################## 3 | # Copyright (c) 2012 4 | # Daniel Plohmann gmailcom> 5 | # Alexander Hanel gmailcom> 6 | # All rights reserved. 7 | ######################################################################## 8 | # 9 | # This file is part of IDAscope 10 | # 11 | # IDAscope is free software: you can redistribute it and/or modify it 12 | # under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, but 17 | # WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | # General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see 23 | # . 24 | # 25 | ######################################################################## 26 | 27 | import idaapi 28 | import idautils 29 | import idc 30 | 31 | 32 | class IdaProxy(): 33 | """ 34 | This class serves as a generic proxy to the IDA Pro Python API. This is neccessary because while running the 35 | plugin, dynamic references to the loaded Python modules get lost when inside functions called by Qt. 36 | As a side effect, we can also do central error handling in this proxy class. 37 | """ 38 | 39 | def __init__(self): 40 | self.idc = idc 41 | self.idaapi = idaapi 42 | self.idautils = idautils 43 | # debug output 44 | self.verbose = False 45 | # constants 46 | self.BAD_ADDR = idaapi.BADADDR 47 | self.CIC_ITEM = self.idc.CIC_ITEM 48 | self.FF_LABL = self.idc.FF_LABL 49 | self.FL_CN = self.idc.fl_CN 50 | self.FL_CN = self.idc.fl_CN 51 | self.FUNC_LIB = self.idaapi.FUNC_LIB 52 | self.FUNCATTR_END = self.idc.FUNCATTR_END 53 | self.INF_SHORT_DN = self.idc.INF_SHORT_DN 54 | self.SN_NOWARN = self.idc.SN_NOWARN 55 | self.SN_NOCHECK = self.idc.SN_NOCHECK 56 | self.SA_REL_BYTE = self.idc.saRelByte 57 | self.SA_REL_PARA = self.idc.saRelPara 58 | self.SC_PRIV = self.idc.scPriv 59 | self.SC_PUB = self.idc.scPub 60 | self.SEGMOD_KILL = self.idaapi.SEGMOD_KILL 61 | self.SEARCH_DOWN = 1 62 | self.MFF_FAST = self.idaapi.MFF_FAST 63 | self.ASCSTR_C = self.idc.ASCSTR_C 64 | self.FUNCATTR_START = self.idc.FUNCATTR_START 65 | 66 | ############################################################################### 67 | # From idc.py 68 | ############################################################################### 69 | 70 | def AddHotkey(self, hotkey, function): 71 | return self.idc.AddHotkey(hotkey, function) 72 | 73 | def AddSeg(self, start_ea, end_ea, base, use32, align, comb): 74 | return self.idc.AddSeg(start_ea, end_ea, base, use32, align, comb) 75 | 76 | def Byte(self, byte): 77 | return self.idc.Byte(byte) 78 | 79 | def Comment(self, addr): 80 | return self.idc.Comment(addr) 81 | 82 | def DelSeg(self, address, flags): 83 | return self.idc.DelSeg(address, flags) 84 | 85 | def Demangle(self, name, disable_mask): 86 | return self.idc.Demangle(name, disable_mask) 87 | 88 | def Dword(self, addr): 89 | return self.idc.Dword(addr) 90 | 91 | def FirstSeg(self): 92 | return self.idc.FirstSeg() 93 | 94 | def get_byte(self, address): 95 | return self.idaapi.get_byte(address) 96 | 97 | def GetCommentEx(self, ea, repeatable): 98 | return self.idaapi.GetCommentEx(ea, repeatable) 99 | 100 | def GetDisasm(self, address): 101 | return self.idc.GetDisasm(address) 102 | 103 | def GetFlags(self, address): 104 | return self.idc.GetFlags(address) 105 | 106 | def GetFunctionAttr(self, ea, attr): 107 | return self.idc.GetFunctionAttr(ea, attr) 108 | 109 | def GetFunctionCmt(self, ea, repeatable): 110 | return self.idc.GetFunctionCmt(ea, repeatable) 111 | 112 | def GetFunctionFlags(self, address): 113 | return self.idc.GetFunctionFlags(address) 114 | 115 | def GetFunctionName(self, address): 116 | return self.idc.GetFunctionName(address) 117 | 118 | def GetFrame(self, ea): 119 | return self.idc.GetFrame(ea) 120 | 121 | def GetLongPrm(self, offset): 122 | return self.idc.GetLongPrm(offset) 123 | 124 | def GetLastMember(self, sid): 125 | return self.idc.GetLastMember(sid) 126 | 127 | def GetMnem(self, address): 128 | return self.idc.GetMnem(address) 129 | 130 | def GetMemberComment(self, sid, member_offset, repeatable): 131 | return self.idc.GetMemberComment(sid, member_offset, repeatable) 132 | 133 | def GetMemberFlag(self, sid, member_offset): 134 | return self.idc.GetMemberFlag(sid, member_offset) 135 | 136 | def GetMemberName(self, sid, member_offset): 137 | return self.idc.GetMemberName(sid, member_offset) 138 | 139 | def GetMemberSize(self, sid, member_offset): 140 | return self.idc.GetMemberSize(sid, member_offset) 141 | 142 | def GetMemberOffset(self, sid, member_name): 143 | return self.idc.GetMemberOffset(sid, member_name) 144 | 145 | def GetOpType(self, address, index): 146 | return self.idc.GetOpType(address, index) 147 | 148 | def GetOperandValue(self, address, index): 149 | return self.idc.GetOperandValue(address, index) 150 | 151 | def GetString(self, address): 152 | return self.idc.GetString(address) 153 | 154 | def GetType(self, address): 155 | type_at_address = self.idc.GetType(address) 156 | if type_at_address is not None: 157 | return type_at_address 158 | else: 159 | if self.verbose: 160 | print ("[!] IdaProxy.FlowChart: No type information for 0x%x available, returning \"\".") % address 161 | return "" 162 | 163 | def isCode(self, flags): 164 | return self.idc.isCode(flags) 165 | 166 | def Wait(self): 167 | return self.idc.Wait() 168 | 169 | def Exit(self, code): 170 | return self.idc.Exit(code) 171 | 172 | def Jump(self, address): 173 | return self.idc.Jump(address) 174 | 175 | def LocByName(self, name): 176 | return self.idc.LocByName(name) 177 | 178 | def MakeFunction(self, instruction): 179 | return self.idc.MakeFunction(instruction) 180 | 181 | def MakeNameEx(self, address, name, warning_level): 182 | return self.idc.MakeNameEx(address, name, warning_level) 183 | 184 | def MakeRptCmt(self, ea, comment): 185 | return self.idc.MakeRptCmt(ea, comment) 186 | 187 | def Name(self, address): 188 | return self.idc.Name(address) 189 | 190 | def NextSeg(self, address): 191 | return self.idc.NextSeg(address) 192 | 193 | def PatchByte(self, address, byte): 194 | self.idc.PatchByte(address, byte) 195 | 196 | def PrevHead(self, ea, minea=0): 197 | return self.idc.PrevHead(ea, minea) 198 | 199 | def NextHead(self, ea, minea=0): 200 | return self.idc.NextHead(ea, minea) 201 | 202 | def RptCmt(self, ea): 203 | return self.idc.RptCmt(ea) 204 | 205 | def SegEnd(self, address): 206 | return self.idc.SegEnd(address) 207 | 208 | def SegName(self, address): 209 | return self.idc.SegName(address) 210 | 211 | def SegRename(self, address, name): 212 | return self.idc.SegRename(address, name) 213 | 214 | def SegStart(self, address): 215 | return self.idc.SegStart(address) 216 | 217 | def SetColor(self, address, location_type, color): 218 | return self.idc.SetColor(address, location_type, color) 219 | 220 | def GetOpnd(self, ea, n): 221 | return self.idc.GetOpnd(ea, n) 222 | 223 | ############################################################################### 224 | # From idaapi.py 225 | ############################################################################### 226 | 227 | def CompileLine(self, line): 228 | return self.idaapi.CompileLine(line) 229 | 230 | def find_not_func(self, *args): 231 | return self.idaapi.find_not_func(*args) 232 | 233 | def find_binary(self, *args): 234 | return self.idaapi.find_binary(*args) 235 | 236 | def FlowChart(self, function_address): 237 | function_chart = [] 238 | try: 239 | function_chart = self.idaapi.FlowChart(function_address) 240 | except: 241 | if self.verbose: 242 | if function_address is not None: 243 | print ("[!] Trying to resolve an API address in non-function code at location: 0x%x, continuing " \ 244 | + "analysis...") % function_address 245 | else: 246 | print ("[!] IdaProxy.FlowChart: Tried to create a FlowChart on None object, skipping function.") 247 | return function_chart 248 | 249 | def get_func(self, function_address): 250 | return self.idaapi.get_func(function_address) 251 | 252 | def get_highlighted_identifier(self): 253 | return self.idaapi.get_highlighted_identifier() 254 | 255 | def isASCII(self, flags): 256 | return self.idaapi.isASCII(flags) 257 | 258 | def minEA(self): 259 | return self.idaapi.cvar.inf.minEA 260 | 261 | def refresh_idaview_anyway(self): 262 | return self.idaapi.refresh_idaview_anyway() 263 | 264 | def get_import_module_qty(self): 265 | return self.idaapi.get_import_module_qty() 266 | 267 | def get_import_module_name(self, mod_index): 268 | return self.idaapi.get_import_module_name(mod_index) 269 | 270 | def enum_import_names(self, mod_index, py_cb): 271 | return self.idaapi.enum_import_names(mod_index, py_cb) 272 | 273 | ############################################################################### 274 | # From idautils.py 275 | ############################################################################### 276 | 277 | def CodeRefsFrom(self, source, flow): 278 | return self.idautils.CodeRefsFrom(source, flow) 279 | 280 | def CodeRefsTo(self, destination, flow): 281 | return self.idautils.CodeRefsTo(destination, flow) 282 | 283 | def DataRefsFrom(self, source): 284 | return self.idautils.DataRefsFrom(source) 285 | 286 | def DataRefsTo(self, destination): 287 | return self.idautils.DataRefsTo(destination) 288 | 289 | def execute_sync(self, *args): 290 | return self.idaapi.execute_sync(*args) 291 | 292 | def FuncItems(self, function_address): 293 | return self.idautils.FuncItems(function_address) 294 | 295 | def Functions(self, start_address=None, end_address=None): 296 | return self.idautils.Functions(start_address, end_address) 297 | 298 | def Heads(self, start_address=None, end_address=None): 299 | return self.idautils.Heads(start_address, end_address) 300 | 301 | def Names(self): 302 | return self.idautils.Names() 303 | 304 | def Segments(self): 305 | return self.idautils.Segments() 306 | 307 | def XrefsTo(self, ea, flag=0): 308 | return self.idautils.XrefsTo(ea, flag) 309 | -------------------------------------------------------------------------------- /crypto_scan/idascope/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/BlackHat_2015/209ed880816cbdceca5188ed1146a9bdd46b7cde/crypto_scan/idascope/core/__init__.py -------------------------------------------------------------------------------- /crypto_scan/idascope/core/helpers/GraphHelper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from idascope.core.IdaProxy import IdaProxy 4 | 5 | 6 | class GraphHelper(): 7 | 8 | def __init__(self): 9 | self.ida_proxy = IdaProxy() 10 | 11 | def handleGraphRecursions(self, graph): 12 | """ 13 | Analyze an arbitrary graph structure for strongly connected components. If such are found, break the 14 | loops and return the graph with an additional key "recursions" that can be used to indicate that these 15 | loops have been broken. 16 | @param graph: a dictionary describing a directed graph, with keys as nodes and values as successors. 17 | @type graph: (dict) 18 | @return: (dict) the modified graph with an additional key "recursions", indicating the broken recursions. 19 | """ 20 | strongly_connected = self.calculateStronglyConnectedComponents(graph["nodes"]) 21 | non_trivial_loops = [component for component in strongly_connected if len(component) > 1] 22 | if len(non_trivial_loops) > 0: 23 | print "here are loops: 0x%x >> %s" % \ 24 | (graph["root"], ", ".join(["0x%x" % addr for addr in non_trivial_loops[0]])) 25 | self.renderGraph(graph) 26 | 27 | def renderGraph(self, graph): 28 | for function_addr in graph["nodes"].keys(): 29 | refs = graph["nodes"][function_addr] 30 | print "0x%x (%s)" % (function_addr, self.ida_proxy.GetFunctionName(function_addr)) 31 | for ref in refs: 32 | print " > 0x%x (%s)" % (ref, self.ida_proxy.GetFunctionName(ref)) 33 | 34 | def calcAvgOutDegree(self, graph): 35 | out_refs = 0 36 | for function_addr in graph["nodes"].keys(): 37 | out_refs += len(graph["nodes"][function_addr]) 38 | print "0x%x -> %2.2f edges per node" % (graph["root"], 1.0 * out_refs / len(graph["nodes"].keys())) 39 | 40 | def calculateStronglyConnectedComponents(self, graph): 41 | """ 42 | Tarjan's Algorithm (named for its discoverer, Robert Tarjan) is a graph theory algorithm 43 | for finding the strongly connected components of a graph. 44 | This can be used to find loops. 45 | Based on: http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm 46 | 47 | Implementation by Dries Verdegem: 48 | http://www.logarithmic.net/pfh-files/blog/01208083168/tarjan.py 49 | Taken from Dr. Paul Harrison Blog: 50 | http://www.logarithmic.net/pfh/blog/01208083168 51 | 52 | @param graph: a dictionary describing a directed graph, with keys as nodes and values as successors. 53 | @type graph: (dict) 54 | @return: (a list of tuples) describing the SCCs 55 | """ 56 | 57 | index_counter = [0] 58 | stack = [] 59 | lowlinks = {} 60 | index = {} 61 | result = [] 62 | 63 | def calculateSccForNode(node): 64 | # set the depth index for this node to the smallest unused index 65 | index[node] = index_counter[0] 66 | lowlinks[node] = index_counter[0] 67 | index_counter[0] += 1 68 | stack.append(node) 69 | # Consider successors of `node` 70 | try: 71 | successors = graph[node] 72 | except: 73 | successors = [] 74 | for successor in successors: 75 | if successor not in lowlinks: 76 | # Successor has not yet been visited; recurse on it 77 | calculateSccForNode(successor) 78 | lowlinks[node] = min(lowlinks[node], lowlinks[successor]) 79 | elif successor in stack: 80 | # the successor is in the stack and hence in the current strongly connected component (SCC) 81 | lowlinks[node] = min(lowlinks[node], index[successor]) 82 | # If `node` is a root node, pop the stack and generate an SCC 83 | if lowlinks[node] == index[node]: 84 | connected_component = [] 85 | while True: 86 | successor = stack.pop() 87 | connected_component.append(successor) 88 | if successor == node: 89 | break 90 | component = tuple(connected_component) 91 | # storing the result 92 | result.append(component) 93 | for node in graph: 94 | if node not in lowlinks: 95 | calculateSccForNode(node) 96 | return result 97 | -------------------------------------------------------------------------------- /crypto_scan/idascope/core/helpers/Misc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ######################################################################## 3 | # Copyright (c) 2012 4 | # Daniel Plohmann gmailcom> 5 | # Alexander Hanel gmailcom> 6 | # All rights reserved. 7 | ######################################################################## 8 | # 9 | # Collection of possibly unrelated, 10 | # miscellaneous functions that are useful. 11 | # 12 | ######################################################################## 13 | # 14 | # This file is part of IDAscope 15 | # 16 | # IDAscope is free software: you can redistribute it and/or modify it 17 | # under the terms of the GNU General Public License as published by 18 | # the Free Software Foundation, either version 3 of the License, or 19 | # (at your option) any later version. 20 | # 21 | # This program is distributed in the hope that it will be useful, but 22 | # WITHOUT ANY WARRANTY; without even the implied warranty of 23 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 | # General Public License for more details. 25 | # 26 | # You should have received a copy of the GNU General Public License 27 | # along with this program. If not, see 28 | # . 29 | # 30 | ######################################################################## 31 | 32 | import operator 33 | 34 | 35 | def lrange(num1, num2=None, step=1): 36 | """ 37 | Allows iteration over arbitrary numbers instead of dword long numbers. 38 | Credits go to: 39 | http://stackoverflow.com/questions/2187135/range-and-xrange-for-13-digit-numbers-in-python 40 | http://stackoverflow.com/users/263162/ricardo-cardenes 41 | """ 42 | op = operator.__lt__ 43 | 44 | if num2 is None: 45 | num1, num2 = 0, num1 46 | if num2 < num1: 47 | if step > 0: 48 | num1 = num2 49 | op = operator.__gt__ 50 | elif step < 0: 51 | num1 = num2 52 | 53 | while op(num1, num2): 54 | yield num1 55 | num1 += step 56 | 57 | 58 | def cleanCountingSuffix(name): 59 | """ 60 | IDA does not support multiple identical names, thus often a suffix like _0, _1 is used to signal identity. 61 | This function will check a name for presence of such a suffix and remove to allow easier post-processing. 62 | """ 63 | if "_w" in name: 64 | try: 65 | int(name[2 + name.rindex("_w"):]) 66 | return name[:name.rindex("_w")] 67 | except: 68 | return name 69 | if "_" in name: 70 | try: 71 | int(name[1 + name.rindex("_"):]) 72 | return name[:name.rindex("_")] 73 | except: 74 | return name 75 | return name 76 | -------------------------------------------------------------------------------- /crypto_scan/idascope/core/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/BlackHat_2015/209ed880816cbdceca5188ed1146a9bdd46b7cde/crypto_scan/idascope/core/helpers/__init__.py -------------------------------------------------------------------------------- /crypto_scan/idascope/core/structures/AritlogBasicBlock.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ######################################################################## 3 | # Copyright (c) 2012 4 | # Daniel Plohmann gmailcom> 5 | # Alexander Hanel gmailcom> 6 | # All rights reserved. 7 | ######################################################################## 8 | # 9 | # This file is part of IDAscope 10 | # 11 | # IDAscope is free software: you can redistribute it and/or modify it 12 | # under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, but 17 | # WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | # General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see 23 | # . 24 | # 25 | ######################################################################## 26 | 27 | 28 | class AritlogBasicBlock(): 29 | """ 30 | This class is an information container for the arithmetic / logic heuristic of the 31 | crypto identifier 32 | """ 33 | 34 | def __init__(self, start_ea, end_ea): 35 | self.arith_log_instructions = [ 36 | "aaa", 37 | "aad", 38 | "aam", 39 | "aas", 40 | "adc", 41 | "add", 42 | "and", 43 | "daa", 44 | "cdq" 45 | "das", 46 | "dec", 47 | "div", 48 | "imul", 49 | "inc", 50 | "neg", 51 | "not", 52 | "or", 53 | "rcl", 54 | "rcr", 55 | "rol", 56 | "ror", 57 | "sal", 58 | "salc", 59 | "sar", 60 | "sbb", 61 | "shl", 62 | "shld", 63 | "shr", 64 | "shrd", 65 | "sub", 66 | "test", 67 | "xadd", 68 | "xor", 69 | ] 70 | self.self_nullifying_instructions = ["xor", "sbb", "sub"] 71 | self.start_ea = start_ea 72 | self.end_ea = end_ea 73 | self.is_contained_in_loop = False 74 | self.is_contained_in_trivial_loop = False 75 | self.num_instructions = 0 76 | self.num_log_arit_instructions = 0 77 | self.num_zeroing_instructions = 0 78 | self.num_calls_in_function = 0 79 | self.aritlog_rating = -1 80 | self.nonzeroing_aritlog_rating = -1 81 | 82 | def getAritlogRating(self, is_nonzeroing_rating=False): 83 | """ 84 | Calculates and returns the rating for this basic block 85 | @param is_nonzeroing_rating: determines whether zeroing instructions like xor eax, eax 86 | shall be taken into account or not. 87 | @type: is_nonzeroing_rating: boolean 88 | @return: the rating for this basic block 89 | """ 90 | try: 91 | if is_nonzeroing_rating: 92 | self.nonzeroing_aritlog_rating = 1.0 * (self.num_log_arit_instructions - \ 93 | self.num_zeroing_instructions) / self.num_instructions 94 | return self.nonzeroing_aritlog_rating 95 | else: 96 | self.aritlog_rating = 1.0 * self.num_log_arit_instructions / self.num_instructions 97 | return self.aritlog_rating 98 | except ZeroDivisionError: 99 | return 0 100 | 101 | def updateInstructionCount(self, instruction, has_identical_operands): 102 | """ 103 | Update the instruction count for this basic block. 104 | @param instruction: The mnemonic for a instruction of this block, as returned by IDA's I{GetMnem()}' 105 | @type: instruction: str 106 | @param has_identical_operands: determines if this instruction has two identical operands. Important for 107 | deciding whether the instruction zeroes a register or not 108 | @type: has_identical_operands: boolean 109 | """ 110 | if instruction in self.arith_log_instructions: 111 | self.num_log_arit_instructions += 1 112 | if instruction in self.self_nullifying_instructions and has_identical_operands: 113 | self.num_zeroing_instructions += 1 114 | self.num_instructions += 1 115 | 116 | def __str__(self): 117 | """ 118 | Convenience function. 119 | @return: a nice string representation for this object 120 | """ 121 | return "0x%x - 0x%x (%d), aritlog: %02.2f%% (%02.2f%%) [%s]" % (self.start_ea, self.end_ea, \ 122 | self.num_instructions, self.aritlog_rating * 100.0, self.nonzeroing_aritlog_rating * 100.0, 123 | self.is_contained_in_loop and "loop" or "no loop") 124 | 125 | def __lt__(self, other): 126 | """ 127 | Convenience function for ordering. 128 | @param other: another I{AritLogBasicBlock} 129 | @type other: I{AritLogBasicBlock} 130 | @return: less if rating is less than of the other 131 | """ 132 | return self.aritlog_rating() < other.aritlog_rating() 133 | -------------------------------------------------------------------------------- /crypto_scan/idascope/core/structures/CryptoSignatureHit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ######################################################################## 3 | # Copyright (c) 2012 4 | # Daniel Plohmann gmailcom> 5 | # Alexander Hanel gmailcom> 6 | # All rights reserved. 7 | ######################################################################## 8 | # 9 | # This file is part of IDAscope 10 | # 11 | # IDAscope is free software: you can redistribute it and/or modify it 12 | # under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, but 17 | # WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | # General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see 23 | # . 24 | # 25 | ######################################################################## 26 | 27 | 28 | class CryptoSignatureHit(): 29 | """ 30 | This class is an information container for a signature match as generated by I{CryptoIdentifier}. 31 | """ 32 | 33 | def __init__(self, start_address, names, match): 34 | self.start_address = start_address 35 | self.signature_names = names 36 | self.matched_signature = match 37 | # code refs are tuples (int, boolean) 38 | # int designates the src of the ref 39 | # boolean designates if it is an in-code reference, e.g. within a mov/push instruction or similar 40 | self.code_refs_to = [] 41 | 42 | def getSignatureNames(self): 43 | return ", ".join(self.signature_names) 44 | 45 | def __str__(self): 46 | """ 47 | Convenience function. 48 | @return: a nice string representation for this object 49 | """ 50 | return "0x%x (%d): %s" % (self.start_address, len(self.matched_signature), self.getSignatureNames()) 51 | 52 | def __lt__(self, other): 53 | """ 54 | Convenience function for ordering. 55 | @param other: another I{CryptoSignatureHit} 56 | @type other: I{CryptoSignatureHit} 57 | @return: less if start addres is less than of the other 58 | """ 59 | return self.start_address < other.start_address 60 | -------------------------------------------------------------------------------- /crypto_scan/idascope/core/structures/Segment.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ######################################################################## 3 | # Copyright (c) 2012 4 | # Daniel Plohmann gmailcom> 5 | # Alexander Hanel gmailcom> 6 | # All rights reserved. 7 | ######################################################################## 8 | # 9 | # This file is part of IDAscope 10 | # 11 | # IDAscope is free software: you can redistribute it and/or modify it 12 | # under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, but 17 | # WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | # General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see 23 | # . 24 | # 25 | ######################################################################## 26 | 27 | 28 | class Segment(): 29 | """ 30 | This class is an information container for a segment. 31 | """ 32 | 33 | def __init__(self): 34 | self.start_ea = 0 35 | self.end_ea = 0 36 | self.name = 0 37 | self.data = "" 38 | 39 | def __str__(self): 40 | """ 41 | Convenience function. 42 | @return: a nice string representation for this object 43 | """ 44 | return "% 8s (0x%x - 0x%x / % 7d bytes)" % (self.name, self.start_ea, self.end_ea, len(self.data)) 45 | -------------------------------------------------------------------------------- /crypto_scan/idascope/core/structures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/BlackHat_2015/209ed880816cbdceca5188ed1146a9bdd46b7cde/crypto_scan/idascope/core/structures/__init__.py -------------------------------------------------------------------------------- /depth_scan/README.md: -------------------------------------------------------------------------------- 1 | To use on IDA: 2 | import depth_scan 3 | depth_scan.DepthScan(target_function_name) 4 | 5 | 6 | Format of the output line: 7 | See any return line at DepthScan.calculate_depth(). In depths.txt file, the values are separated by #. 8 | Example of line: 9 | value1#value2#value3 10 | 11 | In case of error, the character 'x' is written to the output line. -------------------------------------------------------------------------------- /depth_scan/depth_scan.py: -------------------------------------------------------------------------------- 1 | # Based on https://code.google.com/p/idapathfinder/ 2 | 3 | import idc 4 | import idautils 5 | 6 | class DepthScan(object): 7 | 8 | def __init__(self, destination): 9 | # Get EntryPoint name 10 | try: 11 | epAddr = idc.BeginEA() 12 | self.epName = idc.GetFunctionName(epAddr) 13 | except: 14 | self.epName = "" 15 | 16 | # Get result 17 | retval = None 18 | try: 19 | retval = self.calculate_depth(destination, True) 20 | except: 21 | retval = None 22 | 23 | # Write the results to a file 24 | with open("depth.txt", "a") as fp: 25 | if retval == None: 26 | fp.write("x\n") 27 | else: 28 | fp.write("%d#%d#%d#%d#%d#%d#%d#%d#%d#%s#%d\n" % retval) 29 | 30 | def __enter__(self): 31 | return self 32 | 33 | def __exit__(self, t, v, traceback): 34 | return 35 | 36 | def calculate_depth(self, name, only_code): 37 | MAX_NODES = 100 38 | 39 | depth = -1 40 | nodes_counter = 0 41 | epFound = 0 42 | nParents = -1 43 | nParentsCode = -1 44 | first_root_depth = -1 45 | last_root_depth = -1 46 | first_data_depth = -1 47 | max_nodes_limit_reached = 0 48 | first_blank_depth = -1 49 | target_function_name = None 50 | 51 | visited_nodes = [] 52 | names = [] 53 | 54 | new_names_len = None 55 | 56 | # Since we only analyze named addresses/xrefs, exit now if the target function is not named 57 | if not name: 58 | print " Name is None or an empty string: #%s#" % str(name) 59 | return None 60 | 61 | target_function_name = name 62 | 63 | # Some initializations 64 | visited_nodes.append(name) 65 | names.append(name) 66 | 67 | # Get number of parents of the target function 68 | try: 69 | nParents = len([x for x in idautils.XrefsTo(idc.LocByName(name)) if x.type != 21]) 70 | except: 71 | nParents = -1 72 | 73 | # Get number of code-only parents of the target function 74 | try: 75 | nParentsCode = len([x for x in idautils.XrefsTo(idc.LocByName(name)) if x.type != 21 and x.iscode == 1]) 76 | except: 77 | nParentsCode = -1 78 | 79 | while names: 80 | new_names = [] 81 | depth += 1 82 | 83 | #print "names: %s" % str(names) 84 | for name in names: 85 | # Finish the analysis if we reached the limit. Increment nodes_counter 86 | if nodes_counter >= MAX_NODES: 87 | max_nodes_limit_reached = 1 88 | print " Max nodes limit reached: %d depth = %d" % (nodes_counter, depth) 89 | return (depth, epFound, first_root_depth, last_root_depth, first_data_depth, first_blank_depth, nParents, nParentsCode, max_nodes_limit_reached, target_function_name, nodes_counter) 90 | nodes_counter += 1 91 | 92 | # If we reached the entrypoint, then we are done 93 | if name == self.epName: 94 | epFound = 1 95 | print " Entry point found. depth %d" % depth 96 | return (depth, epFound, first_root_depth, last_root_depth, first_data_depth, first_blank_depth, nParents, nParentsCode, max_nodes_limit_reached, target_function_name, nodes_counter) 97 | 98 | is_root = True 99 | for reference in [x for x in idautils.XrefsTo(idc.LocByName(name)) if x.type != 21]: 100 | reference_name = idc.GetFunctionName(reference.frm) 101 | 102 | # We are only interested in named addresses/xrefs 103 | if not reference_name: 104 | if first_blank_depth == -1: 105 | print "Found first blank name at depth %d" % depth 106 | first_blank_depth = depth 107 | continue 108 | 109 | #print " reference: %s" % reference_name 110 | 111 | is_root = False 112 | 113 | # Get depth of the first node with a data node as a parent 114 | if first_data_depth == -1 and reference.iscode != 1: 115 | print " Found first data at depth %d" % depth 116 | first_data_depth = depth 117 | 118 | # If only_code is True, then we will only analyze code xrefs 119 | if only_code and reference.iscode != 1: 120 | continue 121 | 122 | if reference_name not in visited_nodes: 123 | visited_nodes.append(reference_name) 124 | new_names.append(reference_name) 125 | 126 | if is_root: 127 | print " Found a root node at depth %d" % depth 128 | 129 | if first_root_depth == -1: 130 | print " Found first root at depth %d" % depth 131 | first_root_depth = depth 132 | 133 | last_root_depth = depth 134 | 135 | names = new_names 136 | 137 | print "Function end depth %d" % depth 138 | return (depth, epFound, first_root_depth, last_root_depth, first_data_depth, first_blank_depth, nParents, nParentsCode, max_nodes_limit_reached, target_function_name, nodes_counter) 139 | 140 | -------------------------------------------------------------------------------- /slides_BHUS_2015.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/BlackHat_2015/209ed880816cbdceca5188ed1146a9bdd46b7cde/slides_BHUS_2015.pdf --------------------------------------------------------------------------------