├── .gitignore ├── LICENSE ├── README.md ├── bin ├── .gitkeep ├── ida_ver_6.6.141224 │ ├── gcc_rtti.p64 │ └── gcc_rtti.plw ├── ida_ver_6.8.150423 │ ├── gcc_rtti.p64 │ └── gcc_rtti.plw └── ida_ver_7.0.170914 │ ├── gcc_rtti.dll │ ├── gcc_rtti64.dll │ └── x86 │ └── gcc_rtti.dll └── src ├── gcc_rtti ├── gcc_rtti.cxx ├── gcc_rtti.hxx ├── gcc_rtti.vcxproj ├── gcc_rtti.vcxproj.filters ├── gcc_rtti.vcxproj.user ├── graph.cxx ├── graph.hxx ├── plugin.cxx ├── stdinc.cxx ├── stdinc.hxx ├── utils.cxx ├── utils.hxx ├── x64_copy_bin_files_32.bat ├── x64_copy_bin_files_64.bat └── x86_copy_bin_files_32.bat ├── ida_gcc_rtti.sln └── libs └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | bin/ 35 | obj/ 36 | src/libs/idasdk -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IDA GCC RTTI 2 | 3 | ##### This is Class informer plugin for Interactive Disassembler (IDA) which parses GCC RTTI 4 | 5 | ### Features 6 | * Completely written in C++14 (Native) 7 | * Supported at least by IDA (Windows only) versions: `6.6`, `6.8`, `7.0` 8 | * Optimized and fast parsing methods (handling 5500 classes in about 30 seconds - including names making, etc.) 9 | * Exporting classes to `.dot` format (graph) 10 | * Supported platforms & binaries: x86, x64 11 | * Extra settings to make auxiliary vtable names & exclude prefixed names from graph 12 | * Handling anonymous names 13 | 14 | ### Installation 15 | Download compiled plugin in proper version, i.e. (`bin/ida_ver_x_x.xxxxxx/gcc_rtti.plw` and `*.p64` or `.dll`), then put `.plw` and `.p64` or `.dll` files in `/plugins` directory in IDA. 16 | 17 | ### Usage 18 | Load your binary to IDA, wait for the end of analysis, and if plugin was loaded successfully you should have `Class Informer - GCC RTTI` in `Edit` -> `Plugins` toolbar. 19 | 20 | ### Graphs 21 | It is a little problem to deal with for example 5000 classes in one graph. I have not found any software, which could render it properly, so I think the best approach, which I was using is to use Graphviz (https://www.graphviz.org) tools to convert `.dot` format to `.svg`. Then you can load .svg file into Google Chrome or any web browser, which certainly will handle it well (do not forget to disable all plugins in web browser which try to help with manipulating svg file, however they seem to be working very slowly with that amount of data). 22 | 23 | You can easily convert `.dot` format to `.svg` using following command: 24 | 25 | ``bin\dot.exe -Tsvg classes.dot -o classes.svg`` 26 | 27 | Also do not forget to use ignored prefixes feature, since you rather do not need libraries classes in graph (it makes only a mess). 28 | 29 | ### Compilation 30 | ##### Requirements: 31 | * Visual Studio 2015/2017 32 | * IDA SDK (`idasdk`) - supported versions: 6.6 (`ida_older_than_70` branch), 6.8 (`ida_older_than_70` branch), 7.0 (`master` branch), and probably also older/newer versions 33 | 34 | ##### Building: 35 | 1. Put `idasdk` into `/src/libs/`, so there will be `/src/libs/idasdk/include/` and `/src/libs/idasdk/lib/` 36 | 2. Open `src/ida_gcc_rtti.sln` in Visual Studio 37 | 3. Set proper Solution Configuration (`Release`), and proper Solution Platform (`IDA32` or `IDA64` - depends on what you need) 38 | 4. Build solution. 39 | 5. If plugin was successfully build, then binaries should be available in `/bin/win32/` and `/bin/win64/` 40 | 41 | ##### Building on different platforms (Linux, MacOS), using another compilers (clang, gcc) 42 | Feel free to adjust code and linking to make it possible. I do not need it, so I am certainly not going to do it. 43 | 44 | ### Original GCC RTTI parsing scripts 45 | I wrote this plugin basing on already existing python scripts, which also handle parsing RTTI. However they perform parsing tasks very very slow, they seem to be not optimized well, that is why handling few thousand classes in some binary might take even few days. If you do not have time like me to wait few days, then use this plugin to make it a lot faster. Also I added some extra stuff to it and it has few fixes comparing to original scripts. 46 | 47 | Original scripts I was basing on: 48 | * http://www.hexblog.com/?p=704 - By Igor Skochinsky 49 | * https://github.com/nccgroup/PythonClassInformer - By NCC Group 50 | 51 | ### License 52 | This software is released under three-clause BSD License. 53 | 54 | Copyright © 2018, Michał Wójtowicz a.k.a. mwl4 55 | -------------------------------------------------------------------------------- /bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/bin/.gitkeep -------------------------------------------------------------------------------- /bin/ida_ver_6.6.141224/gcc_rtti.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/bin/ida_ver_6.6.141224/gcc_rtti.p64 -------------------------------------------------------------------------------- /bin/ida_ver_6.6.141224/gcc_rtti.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/bin/ida_ver_6.6.141224/gcc_rtti.plw -------------------------------------------------------------------------------- /bin/ida_ver_6.8.150423/gcc_rtti.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/bin/ida_ver_6.8.150423/gcc_rtti.p64 -------------------------------------------------------------------------------- /bin/ida_ver_6.8.150423/gcc_rtti.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/bin/ida_ver_6.8.150423/gcc_rtti.plw -------------------------------------------------------------------------------- /bin/ida_ver_7.0.170914/gcc_rtti.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/bin/ida_ver_7.0.170914/gcc_rtti.dll -------------------------------------------------------------------------------- /bin/ida_ver_7.0.170914/gcc_rtti64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/bin/ida_ver_7.0.170914/gcc_rtti64.dll -------------------------------------------------------------------------------- /bin/ida_ver_7.0.170914/x86/gcc_rtti.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/bin/ida_ver_7.0.170914/x86/gcc_rtti.dll -------------------------------------------------------------------------------- /src/gcc_rtti/gcc_rtti.cxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #include 14 | 15 | #include "gcc_rtti.hxx" 16 | 17 | #include "graph.hxx" 18 | 19 | const string gcc_rtti_t::ti_names[gcc_rtti_t::TI_COUNT] = { 20 | "St9type_info", 21 | "N10__cxxabiv117__class_type_infoE", 22 | "N10__cxxabiv120__si_class_type_infoE", 23 | "N10__cxxabiv121__vmi_class_type_infoE", 24 | }; 25 | 26 | gcc_rtti_t::gcc_rtti_t() 27 | : m_current_class_id(0) 28 | { 29 | } 30 | 31 | gcc_rtti_t::~gcc_rtti_t() 32 | { 33 | } 34 | 35 | bool gcc_rtti_t::init() 36 | { 37 | return true; 38 | } 39 | 40 | void gcc_rtti_t::destroy() 41 | { 42 | m_segments_data.clear(); 43 | m_strings.clear(); 44 | m_graph.reset(); 45 | } 46 | 47 | void gcc_rtti_t::run() 48 | { 49 | // turn on GCC3 demangling 50 | inf.demnames |= DEMNAM_GCC3; 51 | 52 | // initialize strings list 53 | m_strings = utils::get_strings(); 54 | if (m_strings.empty()) 55 | { 56 | warning("Strings list is empty, generate strings list firstly."); 57 | return; 58 | } 59 | 60 | m_classes.clear(); 61 | m_current_class_id = 0; 62 | 63 | initialize_segments_data(); 64 | 65 | // there is no way to get stdout/in from IDA application, 66 | // so we must create system console and use cstdlib stdout/in instead 67 | // that means also using standard printf (not qprintf) 68 | utils::operating_system_t::create_console(); 69 | 70 | printf("Looking for standard type info classes\n"); 71 | find_type_info(TI_TINFO); 72 | find_type_info(TI_CTINFO); 73 | find_type_info(TI_SICTINFO); 74 | find_type_info(TI_VMICTINFO); 75 | 76 | printf("Looking for simple classes\n"); 77 | handle_classes(TI_CTINFO, &gcc_rtti_t::format_type_info); 78 | 79 | printf("Looking for single-inheritance classes\n"); 80 | handle_classes(TI_SICTINFO, &gcc_rtti_t::format_si_type_info); 81 | 82 | printf("Looking for multiple-inheritance classes\n"); 83 | handle_classes(TI_VMICTINFO, &gcc_rtti_t::format_vmi_type_info); 84 | 85 | info("Success, found %u classes.", static_cast(m_classes.size())); 86 | 87 | // destroy console which was created 88 | utils::operating_system_t::destroy_console(); 89 | 90 | // create graph 91 | m_graph = std::make_unique(); 92 | m_graph->run(); 93 | } 94 | 95 | void gcc_rtti_t::initialize_segments_data() 96 | { 97 | m_segments_data.clear(); 98 | 99 | for (int segment_id = 0; segment_id < get_segm_qty(); ++segment_id) 100 | { 101 | segment_t *const segment = getnseg(segment_id); 102 | if (!segment) 103 | { 104 | continue; 105 | } 106 | 107 | qstring segment_name; 108 | get_segm_name(&segment_name, segment); 109 | 110 | qstring segment_class; 111 | get_segm_class(&segment_class, segment); 112 | 113 | if (segment_class != "DATA" && segment_class != "CONST") 114 | { 115 | continue; 116 | } 117 | 118 | segment_data_t segcode; 119 | segcode.m_start_ea = segment->start_ea; 120 | segcode.m_end_ea = segment->end_ea; 121 | 122 | if (segment->start_ea == BADADDR || segment->end_ea == BADADDR) 123 | { 124 | warning("Code begins/end in inproper place, begin = " ADDR_FORMAT "; end = " ADDR_FORMAT, segment->start_ea, segment->end_ea); 125 | continue; 126 | } 127 | 128 | if ((segment->end_ea - segment->start_ea) > 100 * 1024 * 1024) // 100 MB limit 129 | { 130 | warning 131 | ( 132 | "Segment (%s) data size exceeds limit of 100 MB (%u MB) [ " ADDR_FORMAT " - " ADDR_FORMAT " ]", 133 | segment_name.c_str(), 134 | static_cast((segment->end_ea - segment->start_ea) / 1024 / 1024), 135 | segcode.m_start_ea, segcode.m_end_ea 136 | ); 137 | continue; 138 | } 139 | 140 | segcode.m_data.resize(static_cast(segcode.m_end_ea - segcode.m_start_ea)); 141 | if (!get_bytes(&segcode.m_data[0], segcode.m_data.size(), segcode.m_start_ea, GMB_READALL)) 142 | { 143 | warning("get_bytes() returned failure, expect problems.. [" ADDR_FORMAT " - " ADDR_FORMAT "]", segcode.m_start_ea, segcode.m_end_ea); 144 | } 145 | 146 | m_segments_data.push_back(segcode); 147 | } 148 | } 149 | 150 | ea_t gcc_rtti_t::find_string(const string s) const 151 | { 152 | for (const utils::string_data_t &str : m_strings) 153 | { 154 | if (str.m_data == s) 155 | { 156 | return str.m_address; 157 | } 158 | } 159 | return BADADDR; 160 | } 161 | 162 | void gcc_rtti_t::find_type_info(const ti_types_t idx) 163 | { 164 | const ea_t address = find_string(ti_names[idx]); 165 | if (address == BADADDR) 166 | { 167 | return; 168 | } 169 | 170 | utils::xreferences_t xrefs = utils::xref_or_find(address); 171 | if (xrefs.empty()) 172 | { 173 | return; 174 | } 175 | 176 | const ea_t ti_start = xrefs[0].m_address - sizeof(ea_t); 177 | if (utils::is_bad_addr(ti_start)) 178 | { 179 | return; 180 | } 181 | 182 | printf("found %d at " ADDR_FORMAT "\n", static_cast(idx), ti_start); 183 | const ea_t ea = format_type_info(ti_start); 184 | if (idx >= TI_CTINFO) 185 | { 186 | format_struct(ea, "p"); 187 | } 188 | } 189 | 190 | void gcc_rtti_t::handle_classes(ti_types_t idx, ea_t(gcc_rtti_t::*const formatter)(const ea_t address)) 191 | { 192 | sstring_t name = vtname(ti_names[idx]); 193 | 194 | // try single underscore first 195 | ea_t address = get_name_ea(BADADDR, &name[1]); 196 | if (address != BADADDR) 197 | { 198 | name = &name[1]; 199 | } 200 | else 201 | { 202 | address = get_name_ea(BADADDR, &name[0]); 203 | } 204 | 205 | if (address == BADADDR) 206 | { 207 | printf("Could not find vtable for %s\n", ti_names[idx]); 208 | return; 209 | } 210 | 211 | idx = TI_TINFO; 212 | utils::xreferences_t xrefs; 213 | xrefs.reserve(100); // just for optimization 214 | map_t handled; 215 | 216 | while (address != BADADDR) 217 | { 218 | xrefs.clear(); 219 | 220 | printf("Looking for refs to vtable " ADDR_FORMAT "\n", address); 221 | 222 | if (is_spec_ea(address)) 223 | { 224 | xrefs = utils::xref_or_find(address, true); 225 | } 226 | 227 | address += sizeof(ea_t) * 2; // We are looking for +8(32)/+16(64) offset to type vtable 228 | 229 | for (const segment_data_t &segment_data : m_segments_data) 230 | { 231 | for (size_t current = 0; current < segment_data.m_data.size() - sizeof(ea_t); current += sizeof(ea_t)) 232 | { 233 | if (*reinterpret_cast(&segment_data.m_data[current]) != address 234 | || is_code(get_flags(segment_data.m_start_ea + current))) 235 | { 236 | continue; 237 | } 238 | 239 | const ea_t next_ea = *reinterpret_cast(&segment_data.m_data[current + sizeof(ea_t)]); 240 | 241 | if (is_code(get_flags(next_ea))) 242 | { 243 | continue; 244 | } 245 | 246 | sstring_t mangled_name = utils::get_string(next_ea); 247 | if (mangled_name[0] == '\0' || mangled_name[0] == -1) { continue; } 248 | if (mangled_name[0] == '*') { mangled_name = &mangled_name[1]; } 249 | if (detect_compiler_using_demangler((sstring_t("_ZTV") + mangled_name).c_str()) <= 0) 250 | { 251 | continue; 252 | } 253 | 254 | xrefs.push_back(utils::xreference_t(segment_data.m_start_ea + current, false)); 255 | } 256 | } 257 | 258 | for (const utils::xreference_t &xref : xrefs) 259 | { 260 | if (utils::is_bad_addr(xref.m_address) || handled.find(xref.m_address) != handled.end()) 261 | { 262 | continue; 263 | } 264 | 265 | printf("found %s at " ADDR_FORMAT "\n", name.c_str(), xref.m_address); 266 | (this->*formatter)(xref.m_address); 267 | handled[xref.m_address] = true; 268 | } 269 | 270 | sstring_t name2; name2.sprnt("%s_%d", name.c_str(), static_cast(idx)); 271 | address = get_name_ea(BADADDR, name2.c_str()); 272 | idx = static_cast(static_cast(idx) + 1); 273 | } 274 | } 275 | 276 | ea_t gcc_rtti_t::format_type_info(const ea_t address) 277 | { 278 | // dd `vtable for'std::type_info+8 279 | // dd `typeinfo name for'std::type_info 280 | 281 | const ea_t tis = utils::get_ea(address + sizeof(ea_t)); 282 | if (utils::is_bad_addr(tis)) 283 | { 284 | return BADADDR; 285 | } 286 | 287 | const sstring_t name = utils::get_string(tis); 288 | 289 | if (name.empty()) 290 | { 291 | return BADADDR; 292 | } 293 | 294 | /* skip '*' character in case of type defined in function */ 295 | const sstring_t proper_name = (name[0] == '*' ? name.c_str() + 1 : name.c_str()); 296 | 297 | // looks good, let's do it 298 | const ea_t address2 = format_struct(address, "vp"); 299 | set_name(tis, (sstring_t("__ZTS") + proper_name).c_str(), SN_NOWARN); 300 | set_name(address, (sstring_t("__ZTI") + proper_name).c_str(), SN_NOWARN); 301 | 302 | qstring demangled_name; 303 | if(demangle_name(&demangled_name, (sstring_t("_Z") + proper_name).c_str(), 0) >= 0) 304 | { 305 | get_class(address)->m_name = demangled_name; 306 | } 307 | else 308 | { 309 | get_class(address)->m_name = name; 310 | } 311 | 312 | ea_t vtb = BADADDR; 313 | 314 | // find our vtable 315 | // 0 followed by ea 316 | for (const segment_data_t &segment_data : m_segments_data) 317 | { 318 | for (size_t current = sizeof(ea_t); current < segment_data.m_data.size(); current += sizeof(ea_t)) 319 | { 320 | if (*reinterpret_cast(&segment_data.m_data[current - sizeof(ea_t)]) != 0 // following 0 321 | || *reinterpret_cast(&segment_data.m_data[current]) != address) 322 | { 323 | continue; 324 | } 325 | 326 | vtb = segment_data.m_start_ea + current; 327 | } 328 | } 329 | 330 | if (!utils::is_bad_addr(vtb)) 331 | { 332 | printf("vtable for %s at " ADDR_FORMAT "\n", proper_name.c_str(), vtb); 333 | format_struct(vtb, "pp"); 334 | set_name(vtb, (sstring_t("__ZTV") + proper_name).c_str(), SN_NOWARN); 335 | } 336 | else 337 | { 338 | return BADADDR; 339 | } 340 | 341 | return address2; 342 | } 343 | 344 | ea_t gcc_rtti_t::format_si_type_info(const ea_t address) 345 | { 346 | // dd `vtable for'__cxxabiv1::__si_class_type_info+8 347 | // dd `typeinfo name for'MyClass 348 | // dd `typeinfo for'BaseClass 349 | 350 | const ea_t addr = format_type_info(address); 351 | const ea_t pbase = utils::get_ea(addr); 352 | get_class(address)->add_base(class_t::base_t(get_class(pbase))); 353 | return format_struct(addr, "p"); 354 | } 355 | 356 | ea_t gcc_rtti_t::format_vmi_type_info(const ea_t address) 357 | { 358 | // dd `vtable for'__cxxabiv1::__si_class_type_info+8 359 | // dd `typeinfo name for'MyClass 360 | // dd flags 361 | // dd base_count 362 | // (base_type, offset_flags) x base_count 363 | 364 | ea_t addr = format_type_info(address); 365 | if (addr == BADADDR) 366 | { 367 | return address; 368 | } 369 | 370 | addr = format_struct(addr, "ii"); 371 | 372 | const uint32_t base_count = get_32bit(addr - sizeof(uint32_t)); 373 | if (base_count > 100) 374 | { 375 | printf(ADDR_FORMAT ": over 100 base classes (%u)(" ADDR_FORMAT ")?!\n", address, base_count, static_cast(addr - sizeof(uint32_t))); 376 | return BADADDR; 377 | } 378 | 379 | for (uint32_t i = 0; i < base_count; ++i) 380 | { 381 | const ea_t base_ti = utils::get_ea(addr); 382 | const ea_t flags_off = utils::get_ea(addr + sizeof(ea_t)); 383 | const ea_t off = utils::sig_next(flags_off >> 8, 24); 384 | 385 | get_class(address)->add_base(class_t::base_t(get_class(base_ti), static_cast(off), static_cast(flags_off & 0xff))); 386 | 387 | addr = format_struct(addr, "pl"); 388 | } 389 | 390 | return addr; 391 | } 392 | 393 | /** 394 | * p pointer 395 | * v vtable pointer (delta ptrsize * 2) 396 | * i integer (32-bit) 397 | * l integer (32 or 64-bit) 398 | */ 399 | ea_t gcc_rtti_t::format_struct(ea_t address, const string fmt) 400 | { 401 | for (const char *cp = fmt; *cp; ++cp) 402 | { 403 | const char f = *cp; 404 | if (f == 'p' || f == 'v') 405 | { 406 | size_t delta = 0; 407 | if (f == 'v') 408 | { 409 | delta = sizeof(ea_t) * 2; 410 | } 411 | utils::force_ptr(address, delta); 412 | address += sizeof(ea_t); 413 | } 414 | else if (f == 'i') 415 | { 416 | 417 | create_dword(address, sizeof(int)); 418 | address += sizeof(int); 419 | } 420 | else if (f == 'l') 421 | { 422 | #ifdef __EA64__ 423 | create_qword(address, sizeof(ea_t)); 424 | #else 425 | create_dword(address, sizeof(ea_t)); 426 | #endif 427 | address += sizeof(ea_t); 428 | } 429 | } 430 | return address; 431 | } 432 | 433 | sstring_t gcc_rtti_t::vtname(const sstring_t &name) const 434 | { 435 | return sstring_t("__ZTV") + name; 436 | } 437 | 438 | auto gcc_rtti_t::get_class(const ea_t address) -> class_t * 439 | { 440 | unique_ptr_t &class_ptr = m_classes[address]; 441 | if (!class_ptr) 442 | { 443 | class_ptr = std::make_unique(); 444 | class_ptr->m_id = m_current_class_id++; 445 | } 446 | return class_ptr.get(); 447 | } 448 | 449 | auto gcc_rtti_t::get_classes() const -> const classes_t & 450 | { 451 | return m_classes; 452 | } 453 | 454 | gcc_rtti_t *gcc_rtti_t::s_instance = nullptr; 455 | 456 | gcc_rtti_t *gcc_rtti_t::instance() 457 | { 458 | return s_instance; 459 | } 460 | 461 | int idaapi gcc_rtti_t::init_s(void) 462 | { 463 | if (s_instance) 464 | { 465 | s_instance->destroy(); 466 | delete s_instance; 467 | } 468 | 469 | s_instance = new gcc_rtti_t; 470 | if (s_instance->init()) 471 | { 472 | return PLUGIN_KEEP; 473 | } 474 | else 475 | { 476 | return PLUGIN_SKIP; 477 | } 478 | } 479 | 480 | bool idaapi gcc_rtti_t::run_s(size_t arg) 481 | { 482 | if (s_instance) 483 | { 484 | s_instance->run(); 485 | } 486 | return true; 487 | } 488 | 489 | void idaapi gcc_rtti_t::term_s() 490 | { 491 | if (s_instance) 492 | { 493 | s_instance->destroy(); 494 | delete s_instance; 495 | s_instance = nullptr; 496 | } 497 | } 498 | 499 | /* eof */ 500 | -------------------------------------------------------------------------------- /src/gcc_rtti/gcc_rtti.hxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | /* forward declarations */ 18 | class graph_t; 19 | 20 | class gcc_rtti_t 21 | { 22 | public: 23 | gcc_rtti_t(); 24 | gcc_rtti_t(gcc_rtti_t const&) = delete; 25 | gcc_rtti_t(gcc_rtti_t &&) = delete; 26 | ~gcc_rtti_t(); 27 | 28 | gcc_rtti_t &operator=(gcc_rtti_t const&) = delete; 29 | gcc_rtti_t &operator=(gcc_rtti_t &&) = delete; 30 | 31 | bool init(); 32 | void destroy(); 33 | void run(); 34 | 35 | static gcc_rtti_t *instance(); 36 | 37 | public: 38 | static int idaapi init_s(void); 39 | static bool idaapi run_s(size_t arg); 40 | static void idaapi term_s(); 41 | 42 | private: 43 | static gcc_rtti_t *s_instance; 44 | 45 | public: 46 | class class_t; 47 | using classes_t = map_t>; 48 | 49 | class segment_data_t; 50 | using segments_data_t = array_dyn_t; 51 | 52 | private: 53 | enum ti_types_t 54 | { 55 | TI_TINFO = 0, 56 | TI_CTINFO, 57 | TI_SICTINFO, 58 | TI_VMICTINFO, 59 | TI_COUNT /* always at end */ 60 | }; 61 | static const string ti_names[gcc_rtti_t::TI_COUNT]; 62 | 63 | void initialize_segments_data(); 64 | 65 | ea_t find_string(const string s) const; 66 | void find_type_info(const ti_types_t idx); 67 | void handle_classes(ti_types_t idx, ea_t(gcc_rtti_t::*const formatter)(const ea_t address)); 68 | 69 | ea_t format_type_info(const ea_t address); 70 | ea_t format_si_type_info(const ea_t address); 71 | ea_t format_vmi_type_info(const ea_t address); 72 | 73 | ea_t format_struct(ea_t address, const string fmt); 74 | 75 | sstring_t vtname(const sstring_t &name) const; 76 | 77 | class_t *get_class(const ea_t address); 78 | 79 | public: 80 | const classes_t &get_classes() const; 81 | 82 | private: 83 | utils::strings_data_t m_strings; 84 | segments_data_t m_segments_data; 85 | classes_t m_classes; 86 | unique_ptr_t m_graph; 87 | unsigned int m_current_class_id; 88 | }; 89 | 90 | class gcc_rtti_t::class_t 91 | { 92 | public: 93 | class base_t 94 | { 95 | public: 96 | base_t(class_t *const class_ptr) 97 | : m_class(class_ptr) 98 | , m_offset(0) 99 | , m_flags(0) 100 | { 101 | } 102 | 103 | base_t(class_t *const class_ptr, uint offset, uint flags) 104 | : m_class(class_ptr) 105 | , m_offset(offset) 106 | , m_flags(flags) 107 | { 108 | } 109 | 110 | public: 111 | class_t *m_class; 112 | uint m_offset; 113 | uint m_flags; 114 | }; 115 | 116 | public: 117 | void add_base(const base_t &base) 118 | { 119 | m_bases.push_back(base); 120 | } 121 | 122 | public: 123 | sstring_t m_name; 124 | array_dyn_t m_bases; 125 | unsigned int m_id; 126 | bool m_shown = false; 127 | }; 128 | 129 | class gcc_rtti_t::segment_data_t 130 | { 131 | public: 132 | array_dyn_t m_data; 133 | ea_t m_start_ea = BADADDR; 134 | ea_t m_end_ea = BADADDR; 135 | }; 136 | 137 | /* eof */ -------------------------------------------------------------------------------- /src/gcc_rtti/gcc_rtti.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 32 6 | Win32 7 | 8 | 9 | Debug 32 10 | x64 11 | 12 | 13 | Debug 64 14 | Win32 15 | 16 | 17 | Debug 64 18 | x64 19 | 20 | 21 | Release 32 22 | Win32 23 | 24 | 25 | Release 32 26 | x64 27 | 28 | 29 | Release 64 30 | Win32 31 | 32 | 33 | Release 64 34 | x64 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Create 49 | Create 50 | Create 51 | Create 52 | Create 53 | Create 54 | Create 55 | Create 56 | 57 | 58 | 59 | 60 | {1C76E780-917D-45FF-852B-F007D47D4972} 61 | Win32Proj 62 | gcc_rtti 63 | 7.0 64 | gcc_rtti 65 | 66 | 67 | 68 | DynamicLibrary 69 | true 70 | v141_xp 71 | NotSet 72 | 73 | 74 | DynamicLibrary 75 | true 76 | v141_xp 77 | NotSet 78 | 79 | 80 | DynamicLibrary 81 | true 82 | v141_xp 83 | NotSet 84 | 85 | 86 | DynamicLibrary 87 | true 88 | v141_xp 89 | NotSet 90 | 91 | 92 | DynamicLibrary 93 | false 94 | v141_xp 95 | true 96 | NotSet 97 | 98 | 99 | DynamicLibrary 100 | false 101 | v141_xp 102 | true 103 | NotSet 104 | 105 | 106 | DynamicLibrary 107 | false 108 | v141_xp 109 | true 110 | NotSet 111 | 112 | 113 | DynamicLibrary 114 | false 115 | v141_xp 116 | true 117 | NotSet 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | ..\..\bin\win32\ 151 | ..\..\obj\win32\gcc_rtti\ 152 | gcc_rtti 153 | .dll 154 | 155 | 156 | ..\..\bin\win32\ 157 | ..\..\obj\win32\gcc_rtti\ 158 | gcc_rtti 159 | .dll 160 | 161 | 162 | gcc_rtti64 163 | .dll 164 | ..\..\bin\win64\ 165 | ..\..\obj\win64\gcc_rtti\ 166 | 167 | 168 | gcc_rtti 169 | .dll 170 | ..\..\bin\win64\ 171 | ..\..\obj\win64\gcc_rtti\ 172 | 173 | 174 | ..\..\bin\win32\ 175 | ..\..\obj\win32\gcc_rtti_d\ 176 | gcc_rtti_d 177 | .dll 178 | 179 | 180 | ..\..\bin\win32\ 181 | ..\..\obj\win32\gcc_rtti_d\ 182 | gcc_rtti_d 183 | .dll 184 | 185 | 186 | gcc_rtti_d64 187 | .dll 188 | ..\..\bin\win64\ 189 | ..\..\obj\win64\gcc_rtti_d\ 190 | 191 | 192 | gcc_rtti_d 193 | .dll 194 | ..\..\bin\win64\ 195 | ..\..\obj\win64\gcc_rtti_d\ 196 | 197 | 198 | 199 | Use 200 | Level3 201 | Disabled 202 | WIN32;_DEBUG;_WINDOWS;_USRDLL;__NT__;__IDP__;__VC__;%(PreprocessorDefinitions) 203 | true 204 | .\;.\..\libs\idasdk\include\;%(AdditionalIncludeDirectories) 205 | 4267;4996;%(DisableSpecificWarnings) 206 | MultiThreadedDebug 207 | stdinc.hxx 208 | 209 | 210 | Windows 211 | /EXPORT:PLUGIN %(AdditionalOptions) 212 | 213 | 214 | 215 | 216 | 217 | Use 218 | Level3 219 | Disabled 220 | WIN32;_DEBUG;_WINDOWS;_USRDLL;__NT__;__IDP__;__VC__;%(PreprocessorDefinitions) 221 | true 222 | .\;.\..\libs\idasdk\include\;%(AdditionalIncludeDirectories) 223 | 4267;4996;%(DisableSpecificWarnings) 224 | MultiThreadedDebug 225 | stdinc.hxx 226 | 227 | 228 | Windows 229 | .\..\libs\idasdk\lib\x86_win_vc_32\;%(AdditionalLibraryDirectories) 230 | ida.lib;%(AdditionalDependencies) 231 | /EXPORT:PLUGIN %(AdditionalOptions) 232 | 233 | 234 | 235 | 236 | 237 | Use 238 | Level3 239 | Disabled 240 | WIN32;_DEBUG;_WINDOWS;_USRDLL;__NT__;__IDP__;__VC__;__EA64__;__X64__;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) 241 | true 242 | .\;.\..\libs\idasdk\include\;%(AdditionalIncludeDirectories) 243 | 4267;4996;%(DisableSpecificWarnings) 244 | MultiThreadedDebug 245 | stdinc.hxx 246 | 247 | 248 | Windows 249 | .\..\libs\idasdk\lib\x64_win_vc_64\;%(AdditionalLibraryDirectories) 250 | ida.lib;%(AdditionalDependencies) 251 | /EXPORT:PLUGIN %(AdditionalOptions) 252 | 253 | 254 | 255 | 256 | 257 | Use 258 | Level3 259 | Disabled 260 | WIN32;_DEBUG;_WINDOWS;_USRDLL;__NT__;__IDP__;__VC__;__X64__;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) 261 | true 262 | .\;.\..\libs\idasdk\include\;%(AdditionalIncludeDirectories) 263 | 4267;4996;%(DisableSpecificWarnings) 264 | MultiThreadedDebug 265 | stdinc.hxx 266 | 267 | 268 | Windows 269 | .\..\libs\idasdk\lib\x64_win_vc_32\;%(AdditionalLibraryDirectories) 270 | ida.lib;%(AdditionalDependencies) 271 | /EXPORT:PLUGIN %(AdditionalOptions) 272 | 273 | 274 | 275 | 276 | 277 | Level3 278 | Use 279 | MaxSpeed 280 | true 281 | true 282 | WIN32;NDEBUG;_WINDOWS;_USRDLL;__NT__;__IDP__;__VC__;%(PreprocessorDefinitions) 283 | true 284 | .\;.\..\libs\idasdk\include\;%(AdditionalIncludeDirectories) 285 | MultiThreaded 286 | 4267;4996;%(DisableSpecificWarnings) 287 | stdinc.hxx 288 | 289 | 290 | Windows 291 | true 292 | true 293 | /EXPORT:PLUGIN %(AdditionalOptions) 294 | 295 | 296 | 297 | 298 | 299 | Level3 300 | Use 301 | MaxSpeed 302 | true 303 | true 304 | WIN32;NDEBUG;_WINDOWS;_USRDLL;__NT__;__IDP__;__VC__;%(PreprocessorDefinitions) 305 | true 306 | .\;.\..\libs\idasdk\include\;%(AdditionalIncludeDirectories) 307 | MultiThreaded 308 | 4267;4996;%(DisableSpecificWarnings) 309 | stdinc.hxx 310 | 311 | 312 | Windows 313 | true 314 | true 315 | .\..\libs\idasdk\lib\x86_win_vc_32\;%(AdditionalLibraryDirectories) 316 | ida.lib;%(AdditionalDependencies) 317 | /EXPORT:PLUGIN %(AdditionalOptions) 318 | 319 | 320 | x86_copy_bin_files_32.bat 321 | 322 | 323 | 324 | 325 | Level3 326 | Use 327 | MaxSpeed 328 | true 329 | true 330 | WIN32;NDEBUG;_WINDOWS;_USRDLL;__NT__;__IDP__;__VC__;__EA64__;__X64__;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) 331 | true 332 | .\;.\..\libs\idasdk\include\;%(AdditionalIncludeDirectories) 333 | MultiThreaded 334 | 4267;4996;%(DisableSpecificWarnings) 335 | stdinc.hxx 336 | 337 | 338 | Windows 339 | true 340 | true 341 | .\..\libs\idasdk\lib\x64_win_vc_64\;%(AdditionalLibraryDirectories) 342 | ida.lib;%(AdditionalDependencies) 343 | /EXPORT:PLUGIN %(AdditionalOptions) 344 | 345 | 346 | x64_copy_bin_files_64.bat 347 | 348 | 349 | 350 | 351 | Level3 352 | Use 353 | MaxSpeed 354 | true 355 | true 356 | WIN32;NDEBUG;_WINDOWS;_USRDLL;__NT__;__IDP__;__VC__;__X64__;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) 357 | true 358 | .\;.\..\libs\idasdk\include\;%(AdditionalIncludeDirectories) 359 | MultiThreaded 360 | 4267;4996;%(DisableSpecificWarnings) 361 | stdinc.hxx 362 | 363 | 364 | Windows 365 | true 366 | true 367 | .\..\libs\idasdk\lib\x64_win_vc_32\;%(AdditionalLibraryDirectories) 368 | ida.lib;%(AdditionalDependencies) 369 | /EXPORT:PLUGIN %(AdditionalOptions) 370 | 371 | 372 | x64_copy_bin_files_32.bat 373 | 374 | 375 | 376 | 377 | 378 | -------------------------------------------------------------------------------- /src/gcc_rtti/gcc_rtti.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/gcc_rtti/gcc_rtti.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/gcc_rtti/graph.cxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #include 14 | 15 | #include "graph.hxx" 16 | 17 | void graph_t::run() 18 | { 19 | const string question = "Do you want to generate graph?\n"; 20 | const int answer = ask_buttons("Yes", "No", "Cancel", ASKBTN_YES, question); 21 | 22 | if (answer != ASKBTN_YES) 23 | { 24 | return; 25 | } 26 | 27 | if (!fill_ignored_prefixes()) 28 | { 29 | return; 30 | } 31 | 32 | process_ignored_prefixes(); 33 | 34 | const string filepath = ask_file(true, "", "*.dot", "Choose file to which save the graph..."); 35 | 36 | if (!filepath) 37 | { 38 | return; 39 | } 40 | 41 | save_to_file(filepath); 42 | } 43 | 44 | bool graph_t::fill_ignored_prefixes() 45 | { 46 | const string default_value = "std\ntype_info"; 47 | const string question = "List of ignored prefixes:"; 48 | 49 | qstring ignore_namespaces_buffer; 50 | if (!ask_text(&ignore_namespaces_buffer, 2048, default_value, question)) 51 | { 52 | return false; 53 | } 54 | 55 | sstring_t current; 56 | for (const char *c = ignore_namespaces_buffer.c_str(); *c; ++c) 57 | { 58 | if (*c == '\n' || *(c + 1) == '\0') 59 | { 60 | if (*c != '\n' && *(c + 1) == '\0') 61 | { 62 | current.append(*c); 63 | } 64 | if (!current.empty()) 65 | { 66 | m_ignored_prefixes.push_back(current); 67 | current.clear(); 68 | } 69 | } 70 | else 71 | { 72 | current.append(*c); 73 | } 74 | } 75 | 76 | return true; 77 | } 78 | 79 | void graph_t::process_ignored_prefixes() 80 | { 81 | using class_t = gcc_rtti_t::class_t; 82 | 83 | const gcc_rtti_t::classes_t &classes = gcc_rtti_t::instance()->get_classes(); 84 | 85 | for (const std::pair> &class_pair : classes) 86 | { 87 | if (!class_pair.second) 88 | { 89 | continue; 90 | } 91 | 92 | bool is_ignored = false; 93 | for (const sstring_t &ignored : m_ignored_prefixes) 94 | { 95 | if (class_pair.second->m_name.length() < ignored.length()) 96 | { 97 | continue; 98 | } 99 | 100 | if (memcmp(class_pair.second->m_name.c_str(), ignored.c_str(), ignored.length()) == 0) 101 | { 102 | is_ignored = true; 103 | } 104 | } 105 | 106 | if (is_ignored && !class_pair.second->m_shown) 107 | { 108 | continue; 109 | } 110 | 111 | class_pair.second->m_shown = true; 112 | make_class_bases_visible(class_pair.second.get()); 113 | } 114 | } 115 | 116 | void graph_t::make_class_bases_visible(gcc_rtti_t::class_t *const c) 117 | { 118 | for (const gcc_rtti_t::class_t::base_t &base : c->m_bases) 119 | { 120 | if (!base.m_class) 121 | { 122 | continue; 123 | } 124 | 125 | base.m_class->m_shown = true; 126 | make_class_bases_visible(base.m_class); 127 | } 128 | } 129 | 130 | bool graph_t::save_to_file(const string filepath) 131 | { 132 | FILE *const file = qfopen(filepath, "wb"); 133 | if (!file) 134 | { 135 | warning("Unable to open file for write!"); 136 | return false; 137 | } 138 | 139 | qfprintf(file, "digraph G {\n"); 140 | qfprintf(file, "graph [overlap=scale]; node [fontname=Courier]; rankdir=\"LR\";\n\n"); 141 | 142 | const auto &classes = gcc_rtti_t::instance()->get_classes(); 143 | 144 | for (const auto &class_pair : classes) 145 | { 146 | if (!class_pair.second || !class_pair.second->m_shown) 147 | { 148 | continue; 149 | } 150 | 151 | qfprintf(file, " a%u [shape=box, label = \"%s\", color=\"blue\", tooltip=\"" ADDR_FORMAT "\"]\n", 152 | class_pair.second->m_id, class_pair.second->m_name.c_str(), class_pair.first); 153 | } 154 | 155 | for (const auto &class_pair : classes) 156 | { 157 | if (!class_pair.second || !class_pair.second->m_shown) 158 | { 159 | continue; 160 | } 161 | 162 | for (const auto &base : class_pair.second->m_bases) 163 | { 164 | if (!base.m_class) 165 | { 166 | continue; 167 | } 168 | 169 | qfprintf(file, " a%u -> a%u [style = bold]\n", class_pair.second->m_id, base.m_class->m_id); 170 | } 171 | } 172 | 173 | qfprintf(file, "}"); 174 | qflush(file); 175 | qfclose(file); 176 | return true; 177 | } 178 | 179 | /* eof */ 180 | -------------------------------------------------------------------------------- /src/gcc_rtti/graph.hxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #pragma once 14 | 15 | #include "gcc_rtti.hxx" 16 | 17 | class graph_t 18 | { 19 | public: 20 | void run(); 21 | 22 | private: 23 | bool fill_ignored_prefixes(); 24 | void process_ignored_prefixes(); 25 | void make_class_bases_visible(gcc_rtti_t::class_t *const c); 26 | bool save_to_file(const string filepath); 27 | 28 | private: 29 | array_dyn_t m_ignored_prefixes; 30 | }; 31 | 32 | /* eof */ 33 | -------------------------------------------------------------------------------- /src/gcc_rtti/plugin.cxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #include 14 | 15 | #include 16 | 17 | plugin_t PLUGIN = 18 | { 19 | IDP_INTERFACE_VERSION, // version 20 | NULL, // flags 21 | &gcc_rtti_t::init_s, // initialize 22 | &gcc_rtti_t::term_s, // destroy 23 | &gcc_rtti_t::run_s, // invoke plugin 24 | "Class informer - GCC RTTI", // comment 25 | "Class informer - GCC RTTI", // help 26 | "Class informer - GCC RTTI", // wanted name 27 | NULL, // wanted hotkey 28 | }; 29 | 30 | /* eof */ 31 | -------------------------------------------------------------------------------- /src/gcc_rtti/stdinc.cxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #include 14 | 15 | /* eof */ 16 | -------------------------------------------------------------------------------- /src/gcc_rtti/stdinc.hxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #pragma once 14 | 15 | /* C headers */ 16 | #include // for printf 17 | 18 | /* C++ headers */ 19 | #include // for std::remove_if 20 | #include // for std::map<> 21 | #include // for std::unique_ptr<> 22 | 23 | #define USE_STANDARD_FILE_FUNCTIONS // allow using stdin, stdout, etc. 24 | 25 | /* idaapi headers */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | /* aliases of types */ 44 | template < typename T > 45 | using array_dyn_t = qvector; // may use also std::vector instead which allows for move operations for instance 46 | 47 | template < typename Tkey, typename Tvalue > 48 | using map_t = std::map; // there is no idaapi equivalent, so use std::map<> instead 49 | 50 | using string = const char *; // simple c-string 51 | using sstring_t = qstring; // sstring stands for smart string 52 | 53 | template < typename T > 54 | using unique_ptr_t = std::unique_ptr; 55 | 56 | /* eof */ 57 | -------------------------------------------------------------------------------- /src/gcc_rtti/utils.cxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #include 14 | 15 | #include "utils.hxx" 16 | 17 | #ifdef _WIN32 18 | #include // for AllocConsole, FreeConsole 19 | #endif 20 | 21 | namespace utils 22 | { 23 | sstring_t get_segment_name(ea_t address) 24 | { 25 | if (segment_t *const seg = getseg(address)) 26 | { 27 | qstring segname; 28 | get_visible_segm_name(&segname, seg); 29 | return segname; 30 | } 31 | return sstring_t(); 32 | } 33 | 34 | xreferences_t get_xrefs(ea_t ea, int flags) 35 | { 36 | xreferences_t result; 37 | xrefblk_t xb; 38 | for (bool xb_ok = xb.first_to(ea, flags); xb_ok; xb_ok = xb.next_to()) 39 | { 40 | if (get_segment_name(xb.from) != "_pdata") 41 | { 42 | result.push_back(xreference_t(xb.from, xb.iscode ? true : false)); 43 | } 44 | } 45 | return result; 46 | } 47 | 48 | xreferences_t xref_or_find(const ea_t address, const bool allow_many/*= false*/) 49 | { 50 | xreferences_t found; 51 | 52 | const ea_t min_ea = get_first_seg()->start_ea; 53 | const ea_t max_ea = get_last_seg()->end_ea; 54 | 55 | for (ea_t start_address = min_ea, current = 0;; start_address = current + sizeof(ea_t)) 56 | { 57 | const ea_t mask = ALL_BYTES_EA_MASK; 58 | current = bin_search 59 | ( 60 | start_address, max_ea, 61 | reinterpret_cast(&address), 62 | reinterpret_cast(&mask), 63 | sizeof(ea_t), 64 | BIN_SEARCH_FORWARD, BIN_SEARCH_CASE 65 | ); 66 | if (current != BADADDR) 67 | { 68 | if (get_segment_name(current) != "LOAD") 69 | { 70 | found.push_back(xreference_t(current, is_code(get_flags(current)))); 71 | } 72 | } 73 | else 74 | { 75 | break; 76 | } 77 | } 78 | 79 | if (found.empty()) 80 | { 81 | found = get_xrefs(address, XREF_DATA); 82 | } 83 | 84 | if (found.size() > 1 && !allow_many) 85 | { 86 | msg("Too many xrefs to " ADDR_FORMAT, address); 87 | return xreferences_t(); 88 | } 89 | 90 | found.erase(std::remove_if( 91 | found.begin(), found.end(), 92 | [](const xreference_t &ref) 93 | { 94 | return ref.m_code; 95 | } 96 | ), found.end()); 97 | 98 | return found; 99 | } 100 | 101 | strings_data_t get_strings() 102 | { 103 | strings_data_t result; 104 | string_info_t info; 105 | size_t n = get_strlist_qty(); 106 | for (size_t i = 0; i < n; ++i) 107 | { 108 | get_strlist_item(&info, i); 109 | size_t buffer_size = info.length + 1; 110 | char *buffer = new char[buffer_size]; 111 | get_bytes(buffer, info.length, info.ea, GMB_READALL); 112 | buffer[info.length] = '\0'; 113 | result.push_back(string_data_t(info.ea, buffer)); 114 | delete[] buffer; 115 | } 116 | return result; 117 | } 118 | 119 | sstring_t get_string(const ea_t address) 120 | { 121 | if (is_bad_addr(address)) 122 | { 123 | return sstring_t(); 124 | } 125 | 126 | sstring_t result; 127 | for (uchar c = 0; (c = get_byte(address + result.length()));) 128 | { 129 | if (result.length() < 1000) // limit reached 130 | { 131 | result.append(static_cast(c)); 132 | } 133 | else break; 134 | } 135 | return result; 136 | } 137 | 138 | sstring_t ea_to_bytes(const ea_t address) 139 | { 140 | sstring_t result; 141 | for (int i = 0; i < sizeof(address); ++i) 142 | { 143 | result.cat_sprnt("%02X", ((address >> (i * 8)) & 0xff)); 144 | if (i + 1 != sizeof(address)) { result += ' '; } 145 | } 146 | return result; 147 | } 148 | 149 | ea_t get_ea(const ea_t address) 150 | { 151 | #ifdef __EA64__ 152 | return get_64bit(address); 153 | #else 154 | return get_32bit(address); 155 | #endif 156 | } 157 | 158 | void force_ptr(const ea_t address, size_t delta/* = 0 */) 159 | { 160 | #ifdef __EA64__ 161 | create_qword(address, 8); 162 | #else 163 | create_dword(address, 4); 164 | #endif 165 | 166 | if (is_off0(get_flags(address))) 167 | { 168 | return; // don't touch fixups 169 | } 170 | 171 | const ea_t pv = get_ea(address); 172 | if (pv != 0 && pv != BADADDR) 173 | { 174 | // apply offset again 175 | if (is_spec_ea(pv)) 176 | { 177 | delta = 0; 178 | } 179 | 180 | insn_t instruction; 181 | create_insn(address, &instruction); 182 | op_stroff(instruction, 0, nullptr, 0, delta); 183 | } 184 | } 185 | 186 | ea_t sig_next(ea_t x, ea_t b) 187 | { 188 | #ifdef __EA64__ 189 | const ea_t m = 1ULL << (b - 1); 190 | x = x & ((1ULL << b) - 1); 191 | return (x ^ m) - m; 192 | #else 193 | const ea_t m = 1 << (b - 1); 194 | x = x & ((1 << b) - 1); 195 | return (x ^ m) - m; 196 | #endif 197 | } 198 | 199 | void operating_system_t::create_console() 200 | { 201 | #ifdef _WIN32 202 | AllocConsole(); 203 | s_fstdout = freopen("CONOUT$", "w", stdout); 204 | s_fstdin = freopen("CONIN$", "r", stdin); 205 | #else 206 | // TODO: Write implementation which opens console in linux application 207 | #endif 208 | } 209 | 210 | void operating_system_t::destroy_console() 211 | { 212 | #ifdef _WIN32 213 | fclose(s_fstdin); 214 | fclose(s_fstdout); 215 | FreeConsole(); 216 | #else 217 | // TODO: Write implementation which frees console in linux application 218 | #endif 219 | } 220 | 221 | FILE *operating_system_t::s_fstdout = nullptr; 222 | FILE *operating_system_t::s_fstdin = nullptr; 223 | } // namespace utils 224 | 225 | /* eof */ 226 | -------------------------------------------------------------------------------- /src/gcc_rtti/utils.hxx: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************************** 2 | * 3 | * Class informer, plugin for Interactive Disassembler (IDA) 4 | * 5 | * Rewritten to C++14, modified and optimized GCC RTTI parsing code originally written by: 6 | * ^ Igor Skochinsky, see http://www.hexblog.com/?p=704 for the original version of this code 7 | * ^ NCC Group, see https://github.com/nccgroup/PythonClassInformer for the modified version of the code above 8 | * 9 | * This code has been written by Michał Wójtowicz a.k.a mwl4, 02/2018 10 | * 11 | ***************************************************************************************************************/ 12 | 13 | #pragma once 14 | 15 | namespace utils 16 | { 17 | class string_data_t 18 | { 19 | public: 20 | string_data_t(const sstring_t &data) 21 | : m_address(BADADDR), m_data(data) 22 | { 23 | } 24 | 25 | string_data_t(const ea_t &address, const sstring_t &data) 26 | : m_address(address), m_data(data) 27 | { 28 | } 29 | 30 | inline bool operator==(const string_data_t &rhs) const 31 | { 32 | return m_data == rhs.m_data; 33 | } 34 | 35 | public: 36 | ea_t m_address; 37 | sstring_t m_data; 38 | }; 39 | 40 | using strings_data_t = array_dyn_t; 41 | strings_data_t get_strings(); 42 | 43 | sstring_t get_string(const ea_t address); 44 | 45 | class xreference_t 46 | { 47 | public: 48 | xreference_t() 49 | : m_address(0), m_code(false) 50 | { 51 | } 52 | 53 | xreference_t(ea_t address, bool code) 54 | : m_address(address), m_code(code) 55 | { 56 | } 57 | 58 | public: 59 | ea_t m_address; 60 | bool m_code; 61 | }; 62 | 63 | using xreferences_t = array_dyn_t; 64 | xreferences_t get_xrefs(ea_t ea, int flags /* XREF_ALL | XREF_FAR | XREF_DATA */); 65 | 66 | xreferences_t xref_or_find(const ea_t address, const bool allow_many = false); 67 | 68 | ea_t get_ea(const ea_t address); 69 | 70 | void force_ptr(const ea_t address, size_t delta = 0); 71 | 72 | static inline bool is_bad_addr(const ea_t address) 73 | { 74 | return address == 0 || address == BADADDR /*|| is_spec_ea(address) || !is_loaded(address)*/; 75 | } 76 | 77 | sstring_t ea_to_bytes(const ea_t address); 78 | 79 | /* sign extend b low bits in x */ 80 | /* from "Bit Twiddling Hacks" */ 81 | ea_t sig_next(ea_t x, ea_t b); 82 | 83 | #ifdef __EA64__ 84 | # define ADDR_FORMAT "0x%016llX" 85 | #else 86 | # define ADDR_FORMAT "0x%08X" 87 | #endif 88 | 89 | #ifdef __EA64__ 90 | const ea_t ALL_BYTES_EA_MASK = 0x0101010101010101; 91 | #else 92 | const ea_t ALL_BYTES_EA_MASK = 0x01010101; 93 | #endif 94 | 95 | class operating_system_t 96 | { 97 | public: 98 | static void create_console(); 99 | static void destroy_console(); 100 | 101 | private: 102 | static FILE *s_fstdout; 103 | static FILE *s_fstdin; 104 | }; 105 | } // namespace utils 106 | 107 | /* eof */ 108 | -------------------------------------------------------------------------------- /src/gcc_rtti/x64_copy_bin_files_32.bat: -------------------------------------------------------------------------------- 1 | rem Use this script to copy binary files to /plugins directory in IDA 2 | copy "..\..\bin\win64\gcc_rtti.dll" "..\..\" -------------------------------------------------------------------------------- /src/gcc_rtti/x64_copy_bin_files_64.bat: -------------------------------------------------------------------------------- 1 | rem Use this script to copy binary files to /plugins directory in IDA 2 | copy "..\..\bin\win64\gcc_rtti64.dll" "..\..\" -------------------------------------------------------------------------------- /src/gcc_rtti/x86_copy_bin_files_32.bat: -------------------------------------------------------------------------------- 1 | rem Use this script to copy binary files to /plugins directory in IDA 2 | copy "..\..\bin\win32\gcc_rtti.dll" "..\..\" -------------------------------------------------------------------------------- /src/ida_gcc_rtti.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2024 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gcc_rtti", "gcc_rtti\gcc_rtti.vcxproj", "{1C76E780-917D-45FF-852B-F007D47D4972}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug 32|x64 = Debug 32|x64 11 | Debug 32|x86 = Debug 32|x86 12 | Debug 64|x64 = Debug 64|x64 13 | Debug 64|x86 = Debug 64|x86 14 | Release 32|x64 = Release 32|x64 15 | Release 32|x86 = Release 32|x86 16 | Release 64|x64 = Release 64|x64 17 | Release 64|x86 = Release 64|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {1C76E780-917D-45FF-852B-F007D47D4972}.Debug 32|x64.ActiveCfg = Debug 32|x64 21 | {1C76E780-917D-45FF-852B-F007D47D4972}.Debug 32|x64.Build.0 = Debug 32|x64 22 | {1C76E780-917D-45FF-852B-F007D47D4972}.Debug 32|x86.ActiveCfg = Debug 32|Win32 23 | {1C76E780-917D-45FF-852B-F007D47D4972}.Debug 32|x86.Build.0 = Debug 32|Win32 24 | {1C76E780-917D-45FF-852B-F007D47D4972}.Debug 64|x64.ActiveCfg = Debug 64|x64 25 | {1C76E780-917D-45FF-852B-F007D47D4972}.Debug 64|x64.Build.0 = Debug 64|x64 26 | {1C76E780-917D-45FF-852B-F007D47D4972}.Debug 64|x86.ActiveCfg = Debug 64|Win32 27 | {1C76E780-917D-45FF-852B-F007D47D4972}.Debug 64|x86.Build.0 = Debug 64|Win32 28 | {1C76E780-917D-45FF-852B-F007D47D4972}.Release 32|x64.ActiveCfg = Release 32|x64 29 | {1C76E780-917D-45FF-852B-F007D47D4972}.Release 32|x64.Build.0 = Release 32|x64 30 | {1C76E780-917D-45FF-852B-F007D47D4972}.Release 32|x86.ActiveCfg = Release 32|Win32 31 | {1C76E780-917D-45FF-852B-F007D47D4972}.Release 32|x86.Build.0 = Release 32|Win32 32 | {1C76E780-917D-45FF-852B-F007D47D4972}.Release 64|x64.ActiveCfg = Release 64|x64 33 | {1C76E780-917D-45FF-852B-F007D47D4972}.Release 64|x64.Build.0 = Release 64|x64 34 | {1C76E780-917D-45FF-852B-F007D47D4972}.Release 64|x86.ActiveCfg = Release 64|Win32 35 | {1C76E780-917D-45FF-852B-F007D47D4972}.Release 64|x86.Build.0 = Release 64|Win32 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {673B68F5-55B1-40D3-B215-3B6C6033F4EF} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /src/libs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwl4/ida_gcc_rtti/098d2dea0c7b9ac5f6333106eef5ea558bd54b1f/src/libs/.gitkeep --------------------------------------------------------------------------------