├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── img ├── 1.jpg ├── 11.png ├── 12.png ├── 13.png ├── 14.PNG ├── 16.PNG ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── ida7.0_mac_target.png ├── ida7.1_mac_target.png ├── ida7.2.png └── m1.png ├── src ├── HexRaysCodeXplorer.sln ├── HexRaysCodeXplorer.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── HexRaysCodeXplorer │ ├── CodeXplorer.cpp │ ├── Common.h │ ├── CtreeExtractor.cpp │ ├── CtreeExtractor.h │ ├── CtreeGraphBuilder.cpp │ ├── CtreeGraphBuilder.h │ ├── Debug.cpp │ ├── Debug.h │ ├── GCCObjectFormatParser.cpp │ ├── GCCObjectFormatParser.h │ ├── GCCTypeInfo.cpp │ ├── GCCTypeInfo.h │ ├── GCCVtableInfo.cpp │ ├── GCCVtableInfo.h │ ├── HexRaysCodeXplorer.vcxproj │ ├── HexRaysCodeXplorer.vcxproj.user │ ├── IObjectFormatParser.cpp │ ├── IObjectFormatParser.h │ ├── Linux.h │ ├── MSVCObjectFormatParser.cpp │ ├── MSVCObjectFormatParser.h │ ├── Makefile.osx │ ├── ObjectExplorer.cpp │ ├── ObjectExplorer.h │ ├── PropertySheet.props │ ├── TypeExtractor.cpp │ ├── TypeExtractor.h │ ├── TypeReconstructor.cpp │ ├── TypeReconstructor.h │ ├── Utility.cpp │ ├── Utility.h │ ├── makefile.lnx │ ├── makefile.mac │ └── makefile7.mac └── targets ├── IDA_v6.8 ├── Linux │ └── HexRaysCodeXplorer.plx ├── Mac │ ├── HexRaysCodeXplorer.pmc │ └── HexRaysCodeXplorer.pmc64 └── Win │ ├── HexRaysCodeXplorer.p64 │ └── HexRaysCodeXplorer.plw ├── IDA_v6.9 └── Win │ ├── HexRaysCodeXplorer.p64 │ └── HexRaysCodeXplorer.plw ├── IDA_v6.95 └── Win │ ├── HexRaysCodeXplorer.p64 │ └── HexRaysCodeXplorer.plw ├── IDA_v7.0 ├── HexRaysCodeXplorer.dylib └── HexRaysCodeXplorer64.dylib ├── IDA_v7.1 ├── HexRaysCodeXplorer.dylib └── HexRaysCodeXplorer64.dylib └── IDA_v7.2 ├── HexRaysCodeXplorer.dylib └── HexRaysCodeXplorer64.dylib /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | #*.so 8 | #*.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | /src/HexRaysCodeXplorer/x64 15 | /src/.vs 16 | /src/*.db 17 | /src/*.opendb 18 | build-7.1-32/* 19 | build-7.1-64/* 20 | build 21 | build-7.2-32 22 | build-7.2-64 23 | 24 | src/HexRaysCodeXplorer.xcodeproj/project.xcworkspace/xcuserdata 25 | src/HexRaysCodeXplorer.xcodeproj/xcuserdata 26 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ida-cmake"] 2 | path = ida-cmake 3 | url = https://github.com/fjh658/ida-cmake.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(HexRaysCodeXplorer) 3 | 4 | include("ida-cmake/cmake/IDA.cmake") 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | 8 | set(sources "src/HexRaysCodeXplorer/Debug.cpp" 9 | "src/HexRaysCodeXplorer/CtreeExtractor.cpp" 10 | "src/HexRaysCodeXplorer/GCCObjectFormatParser.cpp" 11 | "src/HexRaysCodeXplorer/GCCTypeInfo.cpp" 12 | "src/HexRaysCodeXplorer/GCCVtableInfo.cpp" 13 | "src/HexRaysCodeXplorer/IObjectFormatParser.cpp" 14 | "src/HexRaysCodeXplorer/MSVCObjectFormatParser.cpp" 15 | "src/HexRaysCodeXplorer/ObjectExplorer.cpp" 16 | "src/HexRaysCodeXplorer/CodeXplorer.cpp" 17 | "src/HexRaysCodeXplorer/CtreeGraphBuilder.cpp" 18 | "src/HexRaysCodeXplorer/TypeReconstructor.cpp" 19 | "src/HexRaysCodeXplorer/TypeExtractor.cpp" 20 | "src/HexRaysCodeXplorer/Utility.cpp") 21 | 22 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") 23 | # using AppleClang 24 | set(CMAKE_C_FLAGS "-DUSE_DANGEROUS_FUNCTIONS=1 -DUSE_STANDARD_FILE_FUNCTIONS=1") 25 | set(CMAKE_CXX_FLAGS "-DUSE_DANGEROUS_FUNCTIONS=1 -DUSE_STANDARD_FILE_FUNCTIONS=1") 26 | 27 | elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 28 | # using Clang 29 | # TODO 30 | 31 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 32 | # using GCC 33 | # TODO 34 | 35 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") 36 | # using Intel C++ 37 | # TODO 38 | 39 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 40 | # using Visual Studio C++ 41 | # TODO 42 | endif() 43 | 44 | add_ida_plugin(${CMAKE_PROJECT_NAME} ${sources}) 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
  2 | _   _          ______                _____           _     __   __      _
  3 | | | | |         | ___ \              /  __ \         | |    \ \ / /     | |                    
  4 | | |_| | _____  _| |_/ /__ _ _   _ ___| /  \/ ___   __| | ___ \ V / _ __ | | ___  _ __ ___ _ __ 
  5 | |  _  |/ _ \ \/ /    // _` | | | / __| |    / _ \ / _` |/ _ \/   \| '_ \| |/ _ \| '__/ _ \ '__|
  6 | | | | |  __/>  <| |\ \ (_| | |_| \__ \ \__/\ (_) | (_| |  __/ /^\ \ |_) | | (_) | | |  __/ |   
  7 | \_| |_/\___/_/\_\_| \_\__,_|\__, |___/\____/\___/ \__,_|\___\/   \/ .__/|_|\___/|_|  \___|_|   
  8 |                              __/ |                                | |                          
  9 |                             |___/                                 |_|
10 | 11 | ## changelist: 12 | 1. #### Add support ida7.0/ida7.1/ida7.2 for macOS 13 | 14 | ![ida7.0_mac_target](./img/ida7.2.png) 15 | 16 | - build script 17 | 18 | ```shell 19 | ida-cmake/build.py -i /Users/shared/idasdk72 -t 7.2 --idaq-path "/Applications/IDA_Pro_7.2/ida.app/Contents/MacOS" 20 | ``` 21 | - Generate Xcode 22 | - 64bit 23 | ``` 24 | mkdir build-64 && cd build-64 25 | cmake -G Xcode -DIDA_SDK=/Users/shared/idasdk72 -DIDA_VERSION=720 -DIDA_BINARY_64=ON -DIDA_INSTALL_DIR=/Applications/IDA_Pro_7.2/ida.app/Contents/MacOS -DCMAKE_INSTALL_PREFIX=/Applications/IDA_Pro_7.2/ida.app/Contents/MacOS -DIDA_EA_64=TRUE .. 26 | ``` 27 | `Note: -DIDA_EA_64=TRUE` 28 | 29 | - 32bit 30 | ``` 31 | mkdir build-32 && cd build-32 32 | cmake -G Xcode -DIDA_SDK=/Users/shared/idasdk72 -DIDA_VERSION=720 -DIDA_BINARY_64=ON -DIDA_INSTALL_DIR=/Applications/IDA_Pro_7.2/ida.app/Contents/MacOS -DCMAKE_INSTALL_PREFIX=/Applications/IDA_Pro_7.2/ida.app/Contents/MacOS -DIDA_EA_64=FALSE .. 33 | ``` 34 | `Note: -DIDA_EA_64=FALSE` 35 | 36 | - compile & install 37 | ``` 38 | cmake --build . -j 4 --clean-first --target install -- VERBOSE=1 39 | ``` 40 | - Debugging the plugin in Xcode 41 | - Attach to process 42 | ​ 43 | ​ 44 | [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) 45 | [![Code Climate](https://codeclimate.com/github/REhints/HexRaysCodeXplorer/badges/gpa.svg)](https://codeclimate.com/github/REhints/HexRaysCodeXplorer) 46 | [![Issue Count](https://codeclimate.com/github/REhints/HexRaysCodeXplorer/badges/issue_count.svg)](https://codeclimate.com/github/REhints/HexRaysCodeXplorer) 47 | [![Join the chat at https://gitter.im/REhints/HexRaysCodeXplorer](https://badges.gitter.im/REhints/HexRaysCodeXplorer.svg)](https://gitter.im/REhints/HexRaysCodeXplorer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 48 | [![Codewake](https://www.codewake.com/badges/ask_question.svg)](https://www.codewake.com/p/hexrayscodexplorer) 49 | 50 | The Hex-Rays Decompiler plugin for better code navigation in RE process. CodeXplorer automates code REconstruction of C++ applications or modern malware like Stuxnet, Flame, Equation, Animal Farm ... :octocat: 51 | 52 | The CodeXplorer plugin is one of the [first publicly available](https://www.hex-rays.com/products/decompiler/manual/third_party.shtml) Hex-Rays Decompiler plugins. We keep updated this project [since summer of 2013](https://www.hex-rays.com/contests/2013/) and continue contributing new features frequently. Also most interesting feutures of CodeXplorer have been presented on numerous security conferences like: REcon, ZeroNights, H2HC, NSEC and BHUS :space_invader: 53 | 54 | __Contributors__: 55 | 56 | Alex Matrosov ([@matrosov](https://github.com/matrosov)) 57 | 58 | Eugene Rodionov ([@rodionov](https://github.com/rodionov)) 59 | 60 | Rodrigo Branco ([@rrbranco](https://github.com/rrbranco)) 61 | 62 | Gabriel Barbosa ([@gabrielnb](https://github.com/gabrielnb)) 63 | 64 | __Supported versions of Hex-Rays products:__ everytime we focus on last versions of IDA and Decompiler because trying to use new interesting features in new SDK releases. It's also mean we tested just on last versions of Hex-Rays products and not guaranteed stable work on previous ones. 65 | 66 | __Why not IdaPython:__ all code developed on C/C++ because it's more stable way to support complex plugin for Hex-Rays Decompiler. 67 | 68 | __Supported Platforms:__ x86/x64 for Win, Linux and Mac. 69 | 70 | __HexRaysCodeXplorer__ - Hex-Rays Decompiler plugin for easier code navigation. Right-click context menu in the Pseudocode window shows CodeXplorer plugin commands: 71 | 72 | ![1](img/1.jpg) 73 | 74 | :gem: __Here are the main features of the CodeXplorer plugin:__ :gem: 75 | 76 | * ***Automatic type REconstruction*** for C++ objects. To be able to reconstruct a type using HexRaysCodeXplorer one needs to select the variable holding pointer to the instance of position independed code or to an object and by right-button mouse click select from the context menu «REconstruct Type» option: 77 | 78 | ![2](img/2.png) 79 | 80 | The reconstructed structure is displayed in “Output window”. Detailed information about type Reconstruction feature is provided in the blog post “[Type REconstruction in HexRaysCodeXplorer](http://rehints.com/2013-09-02-Type-REconstruction-in-HexRaysCodeXplorer.html)”. 81 | 82 | Also CodeXplorer plugin supports auto REconstruction type into IDA local types storage. 83 | 84 | ![6](img/6.png) 85 | 86 | * ***Virtual function table identification*** - automatically identifies references to virtual function tables during type reconstruction. When a reference to a virtual function table is identified the plugin generates a corresponding C-structure. As shown below during reconstructing `struct_local_data_storage` two virtual function tables were identified and, as a result, two corresponding structures were generated: `struct_local_data_storage_VTABLE_0` and `struct_local_data_storage_VTABLE_4`. 87 | 88 | ![12](img/12.png) 89 | 90 | * ***C-tree graph visualization*** – a special tree-like structure representing a decompiled routine in citem_t terms (hexrays.hpp). Useful feature for understanding how the decompiler works. The highlighted graph node corresponds to the current cursor position in the HexRays Pseudocode window: 91 | 92 | ![3](img/3.png) 93 | 94 | * ***Ctree Item View*** – show ctree representation for highlighted element: 95 | 96 | ![16](img/16.PNG) 97 | 98 | * ***Extract Ctrees to File*** – dump calculate SHA1 hash and dump all ctrees to file. 99 | 100 | ![14](img/14.PNG) 101 | 102 | * ***Extract Types to File*** – dump all types information (include reconstructed types) into file. 103 | 104 | * ***Navigation through virtual function calls*** in HexRays Pseudocode window. After representing C++ objects by C-structures this feature make possible navigation by mouse clicking to the virtual function calls as structure fields: 105 | 106 | ![4](img/4.png) 107 | 108 | * ***Jump to Disasm*** - small feature for navigate to assembly code into "IDA View window" from current Pseudocode line position. It is help to find a place in assembly code associated with decompiled line. 109 | 110 | ![8](img/8.png) 111 | 112 | * ***Object Explorer*** – useful interface for navigation through virtual tables (VTBL) structures. Object Explorer outputs VTBL information into IDA custom view window. The output window is shown by choosing «Object Explorer» option in right-button mouse click context menu: 113 | 114 | ![5](img/5.png) 115 | 116 | __Object Explorer supports following features:__ 117 | * Auto structures generation for VTBL into IDA local types 118 | 119 | * Navigation in virtual table list and jump to VTBL address into "IDA View" window by click 120 | 121 | * Show hints for current position in virtual table list 122 | 123 | * Shows cross-references list by click into menu on "Show XREFS to VTBL" 124 | 125 | ![11](img/11.png) 126 | 127 | * Support auto parsing RTTI objects: 128 | 129 | ![13](img/13.png) 130 | 131 | __The Batch mode contains following features:__ 132 | 133 | * Batch mode - useful feature to use CodeXplorer for processing multiple files without any interaction from user. We add this feature after Black Hat research in 2015 for processing 2 millions samples. 134 | 135 | ``` 136 | Example (dump types and ctrees for functions with name prefix "crypto_"): 137 | idaq.exe -OHexRaysCodeXplorer:dump_types:dump_ctrees:CRYPTOcrypto_path_to_idb 138 | ``` 139 | 140 | __Compiling__: 141 | 142 | ***Windows:*** 143 | * Open the solution in Visual Studio 144 | * Open file `src/HexRaysCodeXplorer/PropertySheet.props` in notepad(++) and update values of `IDADIR` and `IDASDK` paths to point to IDA installation path and IDA7 SDK path accordingly. HexRays SDK should be in `$IDADIR\plugins\hexrays_sdk` (like by default) 145 | * Build `Release | x64` and `Release x64 | x64` configurations 146 | 147 | ***Linux***: 148 | * cd src/HexRaysCodeXplorer/ 149 | * IDA_DIR= IDA_SDK= EA64=0 make -f makefile.lnx 150 | * IDA_DIR= IDA_SDK= EA64=0 make -f makefile.lnx 151 | 152 | ***Mac***: 153 | * cd src/HexRaysCodeXplorer/ 154 | * IDA_DIR= IDA_SDK= make -f makefile.mac 155 | * The Mac makefile might need some hand editing, pull requests welcome! 156 | * IDA 7.0 `.pmc` file extension should be `.dylib` 157 | * bash$ `export IDA_DIR="/Applications/IDA\ Pro\ 7.0/ida.app/Contents/MacOS" && export IDA_SDK="/Applications/IDA\ Pro\ 7.0/ida.app/Contents/MacOS/idasdk" && make -f makefile7.mac` 158 | * Or open project in Xcode `HexRaysCodeXplorer.xcodeproj` 159 | 160 | ============================================================================ 161 | 162 | __Conference talks about CodeXplorer plugin:__ 163 | * **2015** 164 | * "Distributing the REconstruction of High-Level IR for Large Scale Malware Analysis", BHUS [[slides]](https://github.com/REhints/Publications/blob/master/Conferences/BH'2015/BH_2015.pdf) 165 | * "Object Oriented Code RE with HexraysCodeXplorer", NSEC [[slides]](https://github.com/REhints/Publications/raw/master/Conferences/Nsec'2015/nsec_2015.pdf) 166 | * **2014** 167 | * "HexRaysCodeXplorer: object oriented RE for fun and profit", H2HC [[slides]](https://github.com/REhints/Publications/blob/master/Conferences/ZeroNights'2013/ZN_2013_pdf.pdf) 168 | * **2013** 169 | * "HexRaysCodeXplorer: make object-oriented RE easier", ZeroNights [[slides]](https://github.com/REhints/Publications/blob/master/Conferences/ZeroNights'2013/ZN_2013_pdf.pdf) 170 | * "Reconstructing Gapz: Position-Independent Code Analysis Problem", REcon [[slides]](https://github.com/REhints/Publications/blob/master/Conferences/RECON'2013/RECON_2013.pdf) 171 | -------------------------------------------------------------------------------- /img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/1.jpg -------------------------------------------------------------------------------- /img/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/11.png -------------------------------------------------------------------------------- /img/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/12.png -------------------------------------------------------------------------------- /img/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/13.png -------------------------------------------------------------------------------- /img/14.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/14.PNG -------------------------------------------------------------------------------- /img/16.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/16.PNG -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/3.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/4.png -------------------------------------------------------------------------------- /img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/5.png -------------------------------------------------------------------------------- /img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/6.png -------------------------------------------------------------------------------- /img/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/7.png -------------------------------------------------------------------------------- /img/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/8.png -------------------------------------------------------------------------------- /img/ida7.0_mac_target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/ida7.0_mac_target.png -------------------------------------------------------------------------------- /img/ida7.1_mac_target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/ida7.1_mac_target.png -------------------------------------------------------------------------------- /img/ida7.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/ida7.2.png -------------------------------------------------------------------------------- /img/m1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/img/m1.png -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 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|x64 = Debug x64|x64 11 | Debug|x64 = Debug|x64 12 | Release x64|x64 = Release x64|x64 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|x64.ActiveCfg = Debug x64|x64 17 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|x64.Build.0 = Debug x64|x64 18 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|x64.ActiveCfg = Debug|x64 19 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|x64.Build.0 = Debug|x64 20 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|x64.ActiveCfg = Release x64|x64 21 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|x64.Build.0 = Release x64|x64 22 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|x64.ActiveCfg = Release|x64 23 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | VisualSVNWorkingCopyRoot = . 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/CodeXplorer.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2016 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 "CtreeGraphBuilder.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 | #include "IObjectFormatParser.h" 36 | #include "MSVCObjectFormatParser.h" 37 | #include "GCCObjectFormatParser.h" 38 | 39 | #include 40 | 41 | extern plugin_t PLUGIN; 42 | 43 | IObjectFormatParser *objectFormatParser = 0; 44 | #if defined (__LINUX__) || defined (__MAC__) 45 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 46 | #endif 47 | 48 | // Hex-Rays API pointer 49 | hexdsp_t *hexdsp = NULL; 50 | 51 | namespace { 52 | 53 | static bool inited = false; 54 | 55 | // Hotkey for the new command 56 | static const char hotkey_dg[] = "T"; 57 | static const char hotkey_ce[] = "O"; 58 | static const char hotkey_rt[] = "R"; 59 | static const char hotkey_gd[] = "J"; 60 | static const char hotkey_et[] = "S"; 61 | static const char hotkey_ec[] = "C"; 62 | static const char hotkey_vc[] = "V"; 63 | static const char hotkey_so[] = "Q"; // After positioning cursor at source code user can press Q to copy to clipboard string of form modulename + 0xoffset. 64 | // It can be useful while working with WinDbg. 65 | 66 | static const char hotkey_rv[] = "E"; // Automatic renaming of duplicating variables by pressing E. 67 | // All duplicating successors obtain _2, _3 ... postfixes. 68 | 69 | static const qstring kCryptoPrefixParam = "CRYPTO"; 70 | 71 | 72 | 73 | //-------------------------------------------------------------------------- 74 | // Helper class to build graph from ctree. 75 | struct graph_builder_t : public ctree_parentee_t 76 | { 77 | callgraph_t &cg; 78 | std::map reverse; // Reverse mapping for tests and adding edges 79 | 80 | graph_builder_t(callgraph_t &_cg) : cg(_cg) {} 81 | 82 | // overriding functions 83 | int add_node(citem_t *i); 84 | int process(citem_t *i); 85 | 86 | // We treat expressions and statements the same way: add them to the graph 87 | int idaapi visit_insn(cinsn_t *i) { return process(i); } 88 | int idaapi visit_expr(cexpr_t *e) { return process(e); } 89 | }; 90 | 91 | // Add a new node to the graph 92 | int graph_builder_t::add_node(citem_t *i) 93 | { 94 | // Check if the item has already been encountered during the traversal 95 | if (reverse.find(i) != reverse.end()) 96 | { 97 | warning("bad ctree - duplicate nodes!"); 98 | logmsg(DEBUG, "bad ctree - duplicate nodes!"); 99 | return -1; 100 | } 101 | 102 | // Add a node to the graph 103 | int n = cg.add(i); 104 | 105 | // Also remember the reverse mapping (citem_t* -> n) 106 | reverse[i] = n; 107 | 108 | return n; 109 | } 110 | 111 | // Process a ctree item 112 | int graph_builder_t::process(citem_t *item) 113 | { 114 | // Add a node for citem 115 | int n = add_node(item); 116 | if (n == -1) 117 | return -1; // error 118 | 119 | if (parents.size() > 1) // The current item has a parent? 120 | { 121 | int p = reverse[parents.back()]; // Parent node number 122 | // cg.add_edge(p, n); // Add edge from the parent to the current item 123 | cg.create_edge(p, n); 124 | } 125 | 126 | return 0; 127 | } 128 | 129 | typedef map to_raname_t; 130 | 131 | const qstring kRoot = "*&|"; 132 | 133 | struct ida_local renamer_t : public ctree_visitor_t 134 | { 135 | to_raname_t& to_rename_; 136 | lvars_t& lvars_; 137 | 138 | renamer_t(to_raname_t& to_rename, lvars_t& lvars) 139 | : ctree_visitor_t(CV_FAST) 140 | , to_rename_(to_rename) 141 | , lvars_(lvars) 142 | { 143 | } 144 | 145 | map valid_rvars; 146 | map postfixes; 147 | map> roots; 148 | 149 | qstring rvar_depends_on(cexpr_t* e) { 150 | qstring rvar_name = lvars_[e->y->v.idx].name; 151 | map>::iterator it; 152 | for (it = roots.begin(); it != roots.end(); ++it) 153 | { 154 | if (it->first == rvar_name) 155 | return kRoot; 156 | vector::iterator yt; 157 | for (yt = it->second.begin(); yt != it->second.end(); ++yt) 158 | { 159 | if (*yt == rvar_name) 160 | return it->first; 161 | } 162 | } 163 | return kRoot; 164 | } 165 | 166 | int idaapi visit_expr(cexpr_t *e) 167 | { 168 | char pstx_buf[8]; 169 | qstring new_name; 170 | qstring lvar_name, rvar_name, tvar_name; 171 | if (e->op == cot_asg && e->x->op == cot_var && e->y->op == cot_var) 172 | { 173 | lvar_name = lvars_[e->x->v.idx].name; 174 | rvar_name = lvars_[e->y->v.idx].name; 175 | tvar_name = rvar_depends_on(e); 176 | if (tvar_name == kRoot) 177 | { 178 | //rvar is root variable 179 | if (rvar_name != lvar_name) 180 | roots[rvar_name].push_back(lvar_name); 181 | } 182 | else 183 | { 184 | //rvar is dependant 185 | if (tvar_name != lvar_name) 186 | { 187 | rvar_name = tvar_name; 188 | roots[tvar_name].push_back(lvar_name); 189 | } 190 | } 191 | 192 | for (size_t i = 0; i < roots[lvar_name].size(); i++) 193 | { 194 | if (roots[lvar_name][i] == rvar_name) 195 | return 0; 196 | } 197 | 198 | postfixes.insert(pair(rvar_name, 2)); 199 | sprintf(pstx_buf, "%d", postfixes[rvar_name]++); 200 | new_name = rvar_name + "_" + pstx_buf; 201 | to_rename_[&lvars_[e->x->v.idx]] = new_name; 202 | roots[rvar_name].push_back(new_name); 203 | } 204 | return 0; 205 | } 206 | }; 207 | 208 | } // anonymous 209 | 210 | #define DECLARE_GI_VAR \ 211 | graph_info_t *gi = (graph_info_t *) ud 212 | 213 | #define DECLARE_GI_VARS \ 214 | DECLARE_GI_VAR; \ 215 | callgraph_t *fg = &gi->fg 216 | 217 | //-------------------------------------------------------------------------- 218 | static ssize_t idaapi gr_callback(void *ud, int code, va_list va) 219 | { 220 | bool result = false; 221 | switch (code) 222 | { 223 | // refresh user-defined graph nodes and edges 224 | case grcode_user_refresh: 225 | // in: mutable_graph_t *g 226 | // out: success 227 | { 228 | DECLARE_GI_VARS; 229 | func_t *f = get_func(gi->func_ea); 230 | if (f == NULL) 231 | break; 232 | 233 | graph_builder_t gb(*fg); // Graph builder helper class 234 | gb.apply_to(&gi->vu->cfunc->body, NULL); 235 | 236 | mutable_graph_t *mg = va_arg(va, mutable_graph_t *); 237 | 238 | // we have to resize 239 | mg->resize(fg->count()); 240 | 241 | callgraph_t::edge_iterator end = fg->end_edges(); 242 | for (callgraph_t::edge_iterator it = fg->begin_edges(); 243 | it != end; 244 | ++it) 245 | { 246 | mg->add_edge(it->id1, it->id2, NULL); 247 | } 248 | 249 | fg->clear_edges(); 250 | result = true; 251 | } 252 | break; 253 | 254 | // retrieve text for user-defined graph node 255 | case grcode_user_text: 256 | //mutable_graph_t *g 257 | // int node 258 | // const char **result 259 | // bgcolor_t *bg_color (maybe NULL) 260 | // out: must return 0, result must be filled 261 | // NB: do not use anything calling GDI! 262 | { 263 | DECLARE_GI_VARS; 264 | va_arg(va, mutable_graph_t *); 265 | int node = va_arg(va, int); 266 | const char **text = va_arg(va, const char **); 267 | bgcolor_t *bgcolor = va_arg(va, bgcolor_t *); 268 | 269 | callgraph_t::nodeinfo_t *ni = fg->get_info(node); 270 | result = ni != NULL; 271 | if (result) 272 | { 273 | *text = ni->name.c_str(); 274 | if (bgcolor != NULL) 275 | *bgcolor = ni->color; 276 | } 277 | } 278 | break; 279 | 280 | case grcode_user_hint: 281 | { 282 | DECLARE_GI_VARS; 283 | va_arg(va, mutable_graph_t *); 284 | int mousenode = va_argi(va, int); 285 | int to = va_argi(va, int); 286 | int from = va_argi(va, int); 287 | char **hint = va_arg(va, char **); 288 | 289 | callgraph_t::nodeinfo_t *ni = fg->get_info(mousenode); 290 | result = ni != NULL; 291 | if (result && ni->ea != BADADDR) 292 | { 293 | qstring s; 294 | get_text_disasm(ni->ea, s); 295 | *hint = qstrdup(s.c_str()); 296 | } 297 | } 298 | break; 299 | 300 | case grcode_dblclicked: 301 | { 302 | DECLARE_GI_VARS; 303 | graph_viewer_t *v = va_arg(va, graph_viewer_t *); 304 | selection_item_t *s = va_arg(va, selection_item_t *); 305 | if (s != NULL) { 306 | callgraph_t::nodeinfo_t *ni = fg->get_info(s->node); 307 | result = ni != NULL; 308 | if (result && s->is_node && ni->ea != BADADDR) 309 | jumpto(ni->ea); 310 | } 311 | } 312 | break; 313 | 314 | } 315 | return (int)result; 316 | } 317 | 318 | 319 | // Display ctree graph for current decompiled function 320 | static bool idaapi display_ctree_graph(void *ud) 321 | { 322 | vdui_t &vu = *(vdui_t *)ud; 323 | 324 | // Determine the ctree item to highlight 325 | vu.get_current_item(USE_KEYBOARD); 326 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 327 | graph_info_t *gi = graph_info_t::create(vu.cfunc->entry_ea, highlight); 328 | 329 | netnode id; 330 | id.create(); 331 | 332 | qstring title = gi->title; 333 | 334 | TWidget *widget = find_widget(title.c_str()); 335 | if (widget) 336 | { 337 | warning("Ctree Graph window already open. Switching to it.\n"); 338 | logmsg(DEBUG, "Ctree Graph window already open. Switching to it.\n"); 339 | activate_widget(widget, true); 340 | return true; 341 | } 342 | widget = create_empty_widget(title.c_str()); 343 | 344 | gi->vu = (vdui_t *)ud; 345 | gi->widget = widget; 346 | gi->gv = create_graph_viewer("ctree", id, gr_callback, gi, 0, widget); 347 | activate_widget(widget, true); 348 | #if (defined(IDA_SDK_VERSION) && IDA_SDK_VERSION == 720) 349 | display_widget(widget, WOPN_TAB); 350 | #else 351 | display_widget(widget, WOPN_TAB | WOPN_MENU); 352 | #endif 353 | viewer_fit_window(gi->gv); 354 | 355 | return true; 356 | } 357 | 358 | // Get pointer to func_t by routine name 359 | func_t * get_func_by_name(const char *func_name) 360 | { 361 | #if 0 362 | func_t * result_func = NULL; 363 | size_t func_total = get_func_qty(); 364 | if (func_total > 0) 365 | { 366 | char tmp[1024]; 367 | for (unsigned int i = 0; i < func_total - 1; i++) 368 | { 369 | func_t * func = getn_func(i); 370 | if (func != NULL) 371 | { 372 | memset(tmp, 0x00, sizeof(tmp)); 373 | qstring func_n; 374 | if (get_func_name(&func_n, func->start_ea) > 0) 375 | { 376 | if (!strcmp(func_name, func_n.c_str())) 377 | { 378 | result_func = func; 379 | break; 380 | } 381 | } 382 | } 383 | } 384 | } 385 | return result_func; 386 | #endif // 0 387 | return get_func(get_name_ea(BADADDR, func_name)); 388 | } 389 | 390 | 391 | static bool get_expr_name(citem_t *citem, qstring& rv) 392 | { 393 | if (!citem->is_expr()) 394 | return false; 395 | 396 | cexpr_t *e = (cexpr_t *)citem; 397 | 398 | // retrieve the name of the routine 399 | print1wrapper(e, &rv, NULL); 400 | tag_remove(&rv); 401 | 402 | return true; 403 | } 404 | 405 | 406 | static bool idaapi decompile_func(vdui_t &vu) 407 | { 408 | // Determine the ctree item to highlight 409 | vu.get_current_item(USE_KEYBOARD); 410 | citem_t* highlight = vu.item.is_citem() ? vu.item.e : NULL; 411 | if (!highlight) 412 | return false; 413 | 414 | // if it is an expression 415 | if (!highlight->is_expr()) 416 | return false; 417 | 418 | cexpr_t *e = (cexpr_t *)highlight; 419 | 420 | qstring qcitem_name; 421 | if (!get_expr_name(highlight, qcitem_name)) 422 | return false; 423 | 424 | const char* citem_name = qcitem_name.c_str(); 425 | const char *proc_name = citem_name + strlen(citem_name); 426 | 427 | while ((proc_name > citem_name) && (*(proc_name - 1) != '>')) // WTF is going here? 428 | proc_name--; 429 | 430 | if (proc_name != citem_name) 431 | { 432 | if (func_t* func = get_func_by_name(proc_name)) 433 | open_pseudocode(func->start_ea, -1); 434 | } 435 | 436 | return true; 437 | } 438 | 439 | /* 440 | * TODO: Make changes persistent 441 | */ 442 | 443 | static bool idaapi rename_simple_expr(void *ud) 444 | { 445 | vdui_t &vu = *(vdui_t *)ud; 446 | cfuncptr_t pfunc = vu.cfunc; 447 | 448 | lvars_t& lvars = *pfunc->get_lvars(); 449 | 450 | map to_rename; 451 | renamer_t zc{to_rename, lvars}; 452 | zc.apply_to(&pfunc->body, NULL); 453 | for (map::iterator it = to_rename.begin(); it != to_rename.end(); ++it) 454 | vu.rename_lvar(it->first, it->second.c_str(), 0); 455 | vu.refresh_ctext(); 456 | return true; 457 | } 458 | 459 | static bool idaapi show_offset_in_windbg_format(void *ud) { 460 | char _offset[32] = { 0 }; 461 | char module_name[256] = { 0 }; 462 | qstring result; 463 | adiff_t offset; 464 | vdui_t &vu = *(vdui_t *)ud; 465 | vu.get_current_item(USE_KEYBOARD); 466 | offset = vu.item.i->ea - get_imagebase(); 467 | 468 | if (offset < 0) 469 | { 470 | info("Locate pointer after = sign or at operand of function\n"); 471 | return false; 472 | } 473 | 474 | get_root_filename(module_name, 255); 475 | for (int i = 0; i < 255; i++) 476 | if (module_name[i] == '.') { module_name[i] = 0; break; } 477 | #ifdef __EA64__ 478 | const char *fmt = "%llx"; 479 | #else 480 | const char *fmt = "%x"; 481 | #endif 482 | sprintf(_offset, fmt, offset); 483 | result.cat_sprnt("%s+0x%s", module_name, _offset); 484 | 485 | qstring title; 486 | title.cat_sprnt("0x%X", vu.item.i->ea); 487 | show_string_in_custom_view(&vu, title, result); 488 | 489 | #if defined (__LINUX__) || defined (__MAC__) 490 | msg("%s", result.c_str()); 491 | #else 492 | OpenClipboard(0); 493 | EmptyClipboard(); 494 | HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, result.size()); 495 | 496 | if (!hg) 497 | { 498 | CloseClipboard(); 499 | msg("Can't alloc\n"); 500 | return false; 501 | } 502 | 503 | CopyMemory(GlobalLock(hg), result.c_str(), result.size()); 504 | GlobalUnlock(hg); 505 | SetClipboardData(CF_TEXT, hg); 506 | CloseClipboard(); 507 | GlobalFree(hg); 508 | #endif 509 | return true; 510 | } 511 | 512 | // show disassembly line for ctree->item 513 | bool idaapi decompiled_line_to_disasm_cb(void *ud) 514 | { 515 | vdui_t &vu = *(vdui_t *)ud; 516 | vu.ctree_to_disasm(); 517 | 518 | vu.get_current_item(USE_KEYBOARD); 519 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 520 | 521 | return true; 522 | } 523 | 524 | 525 | // extract ctree to custom view 526 | static bool idaapi show_current_citem_in_custom_view(void *ud) 527 | { 528 | vdui_t &vu = *(vdui_t *)ud; 529 | vu.get_current_item(USE_KEYBOARD); 530 | citem_t *highlight_item = vu.item.is_citem() ? vu.item.e : NULL; 531 | if (!highlight_item) 532 | return false; 533 | 534 | ctree_dumper_t ctree_dump; 535 | qstring ctree_item; 536 | ctree_dump.parse_ctree_item(highlight_item, ctree_item); 537 | 538 | if (highlight_item->is_expr()) 539 | { 540 | cexpr_t *e = (cexpr_t *)highlight_item; 541 | qstring item_name; 542 | get_expr_name(highlight_item, item_name); 543 | show_citem_custom_view(&vu, ctree_item, item_name); 544 | } 545 | return true; 546 | } 547 | 548 | bool initObjectFormatParser() 549 | { 550 | if (!objectFormatParser) 551 | { 552 | //if (isMSVC()) 553 | if (compilerIs(MSVC_COMPILER_ABBR)) 554 | objectFormatParser = new MSVCObjectFormatParser(); 555 | if (compilerIs(GCC_COMPILER_ABBR)) 556 | objectFormatParser = new GCCObjectFormatParser(); 557 | if (!objectFormatParser) 558 | { 559 | info("CodeXplorer doesn't support parsing of not MSVC VTBL's"); 560 | return false; 561 | } 562 | } 563 | return true; 564 | } 565 | 566 | // display Object Explorer 567 | static bool idaapi display_vtbl_objects(void *ud) 568 | { 569 | if (!initObjectFormatParser()) 570 | return false; 571 | 572 | search_objects(); 573 | object_explorer_form_init(); 574 | return true; 575 | } 576 | 577 | 578 | //-------------------------------------------------------------------------- 579 | // This callback handles various hexrays events. 580 | static ssize_t idaapi callback(void* ud, hexrays_event_t event, va_list va) 581 | { 582 | switch (event) 583 | { 584 | case hxe_populating_popup: 585 | { 586 | TWidget *widget = va_arg(va, TWidget *); 587 | TPopupMenu *popup = va_arg(va, TPopupMenu *); 588 | vdui_t &vu = *va_arg(va, vdui_t *); 589 | 590 | // add new command to the popup menu 591 | attach_action_to_popup(vu.ct, popup, "codexplorer::display_ctree_graph"); 592 | attach_action_to_popup(vu.ct, popup, "codexplorer::object_explorer"); 593 | attach_action_to_popup(vu.ct, popup, "codexplorer::reconstruct_type"); 594 | 595 | attach_action_to_popup(vu.ct, popup, "codexplorer::extract_types_to_file"); 596 | attach_action_to_popup(vu.ct, popup, "codexplorer::extract_ctrees_to_file"); 597 | attach_action_to_popup(vu.ct, popup, "codexplorer::ctree_item_view"); 598 | attach_action_to_popup(vu.ct, popup, "codexplorer::jump_to_disasm"); 599 | attach_action_to_popup(vu.ct, popup, "codexplorer::show_copy_item_offset"); 600 | attach_action_to_popup(vu.ct, popup, "codexplorer::rename_vars"); 601 | } 602 | break; 603 | 604 | case hxe_double_click: 605 | { 606 | vdui_t &vu = *va_arg(va, vdui_t *); 607 | decompile_func(vu); 608 | } 609 | break; 610 | default: 611 | break; 612 | } 613 | return 0; 614 | } 615 | 616 | void parse_plugin_options(qstring &options, bool &dump_types, bool &dump_ctrees, qstring &crypto_prefix) { 617 | qvector params; 618 | qstring splitter = ":"; 619 | split_qstring(options, splitter, params); 620 | 621 | dump_types = false; 622 | dump_ctrees = false; 623 | crypto_prefix = ""; 624 | 625 | for (const qstring& param : params) { 626 | if (param == "dump_types") { 627 | dump_types = true; 628 | } 629 | else if (param == "dump_ctrees") { 630 | dump_ctrees = true; 631 | } 632 | else if (param.length() > kCryptoPrefixParam.length() && param.find(kCryptoPrefixParam) == 0) { 633 | crypto_prefix = param.substr(kCryptoPrefixParam.length()); 634 | } 635 | else { 636 | qstring message = "Invalid argument: "; 637 | message += param + "\n"; 638 | logmsg(INFO, message.c_str()); 639 | } 640 | } 641 | } 642 | 643 | namespace { 644 | 645 | class MenuActionHandler : public action_handler_t 646 | { 647 | public: 648 | typedef std::function handler_t; 649 | 650 | MenuActionHandler(handler_t handler) 651 | : handler_(handler) 652 | { 653 | } 654 | virtual int idaapi activate(action_activation_ctx_t *ctx) 655 | { 656 | auto vdui = get_widget_vdui(ctx->widget); 657 | return handler_(vdui) ? TRUE : FALSE; 658 | } 659 | 660 | virtual action_state_t idaapi update(action_update_ctx_t *ctx) 661 | { 662 | return ctx->widget_type == BWN_PSEUDOCODE ? AST_ENABLE_FOR_WIDGET : AST_DISABLE_FOR_WIDGET; 663 | } 664 | 665 | private: 666 | handler_t handler_; 667 | }; 668 | 669 | static MenuActionHandler kDisplayCtreeGraphHandler{ display_ctree_graph }; 670 | static MenuActionHandler kObjectExplorerHandler{ display_vtbl_objects }; 671 | static MenuActionHandler kReconstructTypeHandler{ reconstruct_type_cb }; 672 | static MenuActionHandler kExtractAllTypesHandler{ extract_all_types }; 673 | static MenuActionHandler kExtractAllCtreesHandler{ extract_all_ctrees }; 674 | static MenuActionHandler kShowCurrentCItemInCustomView{ show_current_citem_in_custom_view }; 675 | static MenuActionHandler kJumpToDisasmHandler{ decompiled_line_to_disasm_cb }; 676 | static MenuActionHandler kShowOffsetInWindbgFormatHandler{ show_offset_in_windbg_format }; 677 | static MenuActionHandler kRenameVarsHandler{ rename_simple_expr }; 678 | 679 | static action_desc_t kActionDescs[] = { 680 | ACTION_DESC_LITERAL("codexplorer::display_ctree_graph", "Display Ctree Graph", &kDisplayCtreeGraphHandler, hotkey_dg, nullptr, -1), 681 | ACTION_DESC_LITERAL("codexplorer::object_explorer", "Object Explorer", &kObjectExplorerHandler, hotkey_ce, nullptr, -1), 682 | ACTION_DESC_LITERAL("codexplorer::reconstruct_type", "REconstruct Type", &kReconstructTypeHandler, hotkey_rt, nullptr, -1), 683 | ACTION_DESC_LITERAL("codexplorer::extract_types_to_file", "Extract Types to File", &kExtractAllTypesHandler, hotkey_et, nullptr, -1), 684 | ACTION_DESC_LITERAL("codexplorer::extract_ctrees_to_file", "Extract Ctrees to File", &kExtractAllCtreesHandler, hotkey_ec, nullptr, -1), 685 | ACTION_DESC_LITERAL("codexplorer::ctree_item_view", "Ctree Item View", &kShowCurrentCItemInCustomView, hotkey_vc, nullptr, -1), 686 | ACTION_DESC_LITERAL("codexplorer::jump_to_disasm", "Jump to Disasm", &kJumpToDisasmHandler, hotkey_gd, nullptr, -1), 687 | ACTION_DESC_LITERAL("codexplorer::show_copy_item_offset", "Show/Copy item offset", &kShowOffsetInWindbgFormatHandler, hotkey_so, nullptr, -1), 688 | ACTION_DESC_LITERAL("codexplorer::rename_vars", "Rename vars", &kRenameVarsHandler, hotkey_rv, nullptr, -1) 689 | }; 690 | 691 | } 692 | //-------------------------------------------------------------------------- 693 | // Initialize the plugin. 694 | int idaapi init(void) 695 | { 696 | logmsg(INFO, "\nHexRaysCodeXplorer plugin by @REhints loaded.\n\n\n"); 697 | 698 | if (!init_hexrays_plugin()) 699 | return PLUGIN_SKIP; // no decompiler 700 | 701 | bool dump_types = false; 702 | bool dump_ctrees = false; 703 | qstring crypto_prefix; 704 | 705 | qstring options = get_plugin_options(PLUGIN.wanted_name); 706 | parse_plugin_options(options, dump_types, dump_ctrees, crypto_prefix); 707 | 708 | for (unsigned i = 0; i < _countof(kActionDescs); ++i) 709 | register_action(kActionDescs[i]); 710 | 711 | install_hexrays_callback((hexrays_cb_t*)callback, nullptr); 712 | logmsg(INFO, "Hex-rays version %s has been detected\n", get_hexrays_version()); 713 | inited = true; 714 | 715 | if (dump_ctrees || dump_types) { 716 | auto_wait(); 717 | 718 | if (dump_types) { 719 | logmsg(DEBUG, "Dumping types\n"); 720 | extract_all_types(NULL); 721 | 722 | int file_id = qcreate("codexplorer_types_done", 511); 723 | if (file_id != -1) 724 | qclose(file_id); 725 | } 726 | 727 | if (dump_ctrees) { 728 | logmsg(DEBUG, "Dumping ctrees\n"); 729 | dump_funcs_ctree(NULL, crypto_prefix); 730 | 731 | int file_id = qcreate("codexplorer_ctrees_done", 511); 732 | if (file_id != -1) 733 | qclose(file_id); 734 | } 735 | 736 | logmsg(INFO, "\nHexRaysCodeXplorer plugin by @REhints exiting...\n\n\n"); 737 | } 738 | 739 | return PLUGIN_KEEP; 740 | } 741 | 742 | //-------------------------------------------------------------------------- 743 | void idaapi term(void) 744 | { 745 | if (inited) 746 | { 747 | logmsg(INFO, "\nHexRaysCodeXplorer plugin by @REhints terminated.\n\n\n"); 748 | remove_hexrays_callback((hexrays_cb_t*)callback, NULL); 749 | term_hexrays_plugin(); 750 | } 751 | } 752 | 753 | //-------------------------------------------------------------------------- 754 | bool idaapi run(size_t) 755 | { 756 | // This function won't be called because our plugin is invisible (no menu 757 | // item in the Edit, Plugins menu) because of PLUGIN_HIDE 758 | return true; 759 | } 760 | 761 | //-------------------------------------------------------------------------- 762 | static const char comment[] = "HexRaysCodeXplorer plugin by @REhints"; 763 | 764 | //-------------------------------------------------------------------------- 765 | // 766 | // PLUGIN DESCRIPTION BLOCK 767 | // 768 | //-------------------------------------------------------------------------- 769 | plugin_t PLUGIN = 770 | { 771 | IDP_INTERFACE_VERSION, 772 | PLUGIN_HIDE, // plugin flags 773 | init, // initialize 774 | term, // terminate. this pointer may be NULL. 775 | run, // invoke plugin 776 | comment, // long comment about the plugin 777 | // it could appear in the status line or as a hint 778 | "", // multiline help about the plugin 779 | "HexRaysCodeXplorer by @REhints", // the preferred short name of the plugin (PLUGIN.wanted_name) 780 | "" // the preferred hotkey to run the plugin 781 | }; 782 | -------------------------------------------------------------------------------- /src/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 | #if !defined (__LINUX__) && !defined (__MAC__) 31 | #pragma warning (disable: 4996 4800 ) 32 | #else 33 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 34 | #endif 35 | 36 | #if !defined (__LINUX__) && !defined (__MAC__) 37 | #include 38 | #include 39 | #else 40 | #include "Linux.h" 41 | #endif 42 | 43 | #ifdef __NT__ 44 | #pragma warning(push) 45 | #pragma warning(disable:4309 4244 4267) // disable "truncation of constant value" warning from IDA SDK, conversion from 'ssize_t' to 'int', possible loss of data 46 | #endif // __NT__ 47 | #ifndef USE_DANGEROUS_FUNCTIONS 48 | #define USE_DANGEROUS_FUNCTIONS 49 | #endif 50 | #ifdef __clang__ 51 | #pragma clang diagnostic push 52 | #pragma clang diagnostic ignored "-Wsign-compare" 53 | #pragma clang diagnostic ignored "-Wvarargs" 54 | #pragma clang diagnostic ignored "-Wlogical-op-parentheses" 55 | #pragma clang diagnostic ignored "-Wunused-private-field" 56 | #endif 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #ifdef __NT__ 76 | #pragma warning(pop) 77 | #endif // __NT__ 78 | #ifdef __clang__ 79 | #pragma clang diagnostic pop 80 | #endif 81 | 82 | template 83 | struct print1_accepts_qstring 84 | { 85 | template struct yay_sfinae {}; 86 | template static char test(yay_sfinae*); 87 | template static int test(...); 88 | static const bool value = sizeof(test(0)) == sizeof(char); 89 | }; 90 | 91 | // For IDA7.1 and newer 92 | template 93 | void print1wrapper(std::true_type, const T *e, qstring *qbuf, const cfunc_t *func) { 94 | e->print1(qbuf, func); 95 | }; 96 | 97 | // For older SDKs 98 | template 99 | void print1wrapper(std::false_type, const T *e, qstring *qbuf, const cfunc_t *func) { 100 | char lbuf[MAXSTR]; 101 | const size_t len = e->print1(lbuf, sizeof(lbuf) - 1, func); 102 | qstring temp(lbuf, len); 103 | qbuf->swap(temp); 104 | }; 105 | 106 | template 107 | void print1wrapper(const T *e, qstring *qbuf, const cfunc_t *func) { 108 | return print1wrapper( 109 | std::integral_constant::value>(), 110 | e, qbuf, func); 111 | } 112 | 113 | 114 | 115 | #include 116 | #include 117 | #include 118 | 119 | #include 120 | #include 121 | #include 122 | #include 123 | #include 124 | #include 125 | #include 126 | #include 127 | 128 | #endif 129 | 130 | -------------------------------------------------------------------------------- /src/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 | #if defined (__LINUX__) || defined (__MAC__) 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 | size_t parent_count = parents.size(); 77 | if (parent_count > 1) { 78 | ctree_dump += "("; 79 | } 80 | 81 | qstring buf; 82 | parse_ctree_item(item, buf); 83 | ctree_dump += buf; 84 | 85 | process_for_hash(item); 86 | return 0; 87 | } 88 | 89 | int ctree_dumper_t::process_leave(citem_t *item) 90 | { 91 | size_t parent_count = parents.size(); 92 | if (parent_count > 1) { 93 | ctree_dump += ")"; 94 | } 95 | return 0; 96 | } 97 | 98 | void ctree_dumper_t::parse_ctree_item(citem_t *item, qstring& rv) const 99 | { 100 | rv.clear(); 101 | // Each node will have the element type at the first line 102 | if (auto v = get_ctype_name(item->op)) 103 | rv = v; 104 | 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 | qstring func_name; 110 | qstring s; 111 | switch (item->op) 112 | { 113 | case cot_call: 114 | if (e->x->op == cot_obj) { 115 | if (get_func_name(&func_name, e->x->obj_ea) == 0) 116 | rv.cat_sprnt(" sub_%a", e->x->obj_ea); 117 | else 118 | rv.cat_sprnt(" %s", func_name.c_str()); 119 | } 120 | break; 121 | case cot_ptr: // *x 122 | case cot_memptr: // x->m 123 | // Display access size for pointers 124 | rv.cat_sprnt(".%d", e->ptrsize); 125 | if (item->op == cot_ptr) 126 | break; 127 | case cot_memref: // x.m 128 | // Display member offset for structure fields 129 | rv.cat_sprnt(" (m=%d)", e->m); 130 | break; 131 | case cot_obj: // v 132 | case cot_var: // l 133 | // Display object size for local variables and global data 134 | rv.cat_sprnt(".%d", e->refwidth); 135 | case cot_num: // n 136 | case cot_helper: // arbitrary name 137 | case cot_str: // string constant 138 | // Display helper names and number values 139 | rv.append(' '); 140 | { 141 | qstring qbuf; 142 | print1wrapper(e, &qbuf, NULL); 143 | tag_remove(&qbuf); 144 | rv += qbuf; 145 | } 146 | break; 147 | case cit_goto: 148 | // Display target label number for gotos 149 | rv.cat_sprnt(" LABEL_%d", i->cgoto->label_num); 150 | break; 151 | case cit_asm: 152 | // Display instruction block address and size for asm-statements 153 | rv.cat_sprnt(" %a.%" FMT_Z, *i->casm->begin(), i->casm->size()); 154 | break; 155 | default: 156 | break; 157 | } 158 | 159 | // The second line of the node contains the item address 160 | rv.cat_sprnt(";ea->%a", item->ea); 161 | 162 | if ( item->is_expr() && !e->type.empty() ) 163 | { 164 | // For typed expressions, the third line will have 165 | // the expression type in human readable form 166 | rv.append(';'); 167 | qstring out; 168 | if (e->type.print(&out)) 169 | { 170 | rv += out; 171 | } 172 | else 173 | { // could not print the type? 174 | rv.append('?'); 175 | } 176 | 177 | if(e->type.is_ptr()) 178 | { 179 | tinfo_t ptr_rem = ::remove_pointer(e->type); 180 | if(ptr_rem.is_struct()) 181 | { 182 | qstring typenm; 183 | ptr_rem.print(&typenm, "prefix ", 0, 0, PRTYPE_MULTI | PRTYPE_TYPE | PRTYPE_SEMI); 184 | } 185 | } 186 | } 187 | 188 | } 189 | 190 | struct ctree_dump_line { 191 | qvector referres; 192 | qstring ctree_for_hash; 193 | qstring ctree_dump; 194 | qstring func_name; 195 | int func_depth; 196 | ea_t func_start; 197 | ea_t func_end; 198 | bool heuristic_flag; 199 | }; 200 | 201 | 202 | int create_open_file(const char* file_name) { 203 | int file_id = qopen(file_name, O_BINARY | O_TRUNC | O_CREAT); 204 | if (file_id == BADADDR) 205 | file_id = qcreate(file_name, 511); 206 | 207 | return file_id; 208 | } 209 | 210 | int get_hash_of_string(const qstring &string_to_hash, qstring &hash) { 211 | SHA1Context sha; 212 | uint8_t Message_Digest[SHA1HashSize]; 213 | int err; 214 | 215 | err = SHA1Reset(&sha); 216 | if (err == shaSuccess) { 217 | err = SHA1Input(&sha, (uint8_t *)string_to_hash.c_str(), static_cast(string_to_hash.length())); 218 | if (err == shaSuccess) { 219 | err = SHA1Result(&sha, Message_Digest); 220 | if (err == shaSuccess) { 221 | char digest_hex[SHA1HashSize * 2 + 1]; 222 | memset(digest_hex, 0x00, sizeof(digest_hex)); 223 | SHA1MessageDigestToString(Message_Digest, digest_hex); 224 | 225 | hash = digest_hex; 226 | } 227 | } 228 | } 229 | 230 | return err; 231 | } 232 | 233 | void dump_ctrees_in_file(std::map &data_to_dump, const qstring &crypto_prefix) { 234 | int file_id = create_open_file("ctrees.txt"); 235 | if (file_id == -1) 236 | { 237 | logmsg(ERROR, "Failed to open file for dumping ctress\r\n"); 238 | return; 239 | } 240 | 241 | size_t crypt_prefix_len = crypto_prefix.length(); 242 | 243 | for (auto ctrees_iter = data_to_dump.begin(); ctrees_iter != data_to_dump.end(); ++ctrees_iter) { 244 | const ctree_dump_line& cdl = ctrees_iter->second; 245 | 246 | qstring sha_hash; 247 | int err = get_hash_of_string(cdl.ctree_for_hash, sha_hash); 248 | if (err != shaSuccess) { 249 | logmsg(ERROR, "Error in computing SHA1 hash\r\n"); 250 | continue; 251 | } 252 | 253 | qstring dump_line = sha_hash + ";"; 254 | err = get_hash_of_string(cdl.ctree_dump, sha_hash); 255 | if (err != shaSuccess) { 256 | logmsg(ERROR, "Error in computing SHA1 hash\r\n"); 257 | continue; 258 | } 259 | dump_line += sha_hash + ";"; 260 | dump_line += cdl.ctree_dump; 261 | dump_line.cat_sprnt(";%d", cdl.func_depth); 262 | dump_line.cat_sprnt(";%08X", cdl.func_start); 263 | dump_line.cat_sprnt(";%08X", cdl.func_end); 264 | if ((cdl.func_name.length() > crypt_prefix_len) && (crypt_prefix_len > 0) && (cdl.func_name.find(crypto_prefix) == 0)) 265 | dump_line.cat_sprnt(";E"); 266 | else 267 | dump_line.cat_sprnt(";N"); 268 | 269 | if ((cdl.heuristic_flag)) 270 | dump_line.cat_sprnt(";H"); 271 | else 272 | dump_line.cat_sprnt(";N"); 273 | 274 | dump_line += "\n"; 275 | 276 | qwrite(file_id, dump_line.c_str(), dump_line.length()); 277 | } 278 | 279 | qclose(file_id); 280 | } 281 | 282 | 283 | inline bool func_name_has_prefix(const qstring &prefix, ea_t startEA) { 284 | if (prefix.length() <= 0) 285 | return false; 286 | 287 | qstring func_name; 288 | if (get_func_name(&func_name, startEA) <= 0) 289 | return false; 290 | 291 | if (func_name.empty()) 292 | return false; 293 | 294 | return func_name.find(prefix.c_str(), 0) == 0; 295 | } 296 | 297 | bool idaapi dump_funcs_ctree(void *ud, const qstring &crypto_prefix) 298 | { 299 | logmsg(DEBUG, "dump_funcs_ctree entered\n"); 300 | 301 | std::map data_to_dump; 302 | 303 | // enumerate through all the functions in the idb file 304 | bool heuristic_flag; 305 | size_t count = 0, heur_count = 0, crypto_count = 0; 306 | size_t total_func_qty = get_func_qty(); 307 | for (size_t i = 0 ; i < total_func_qty ; i ++) { 308 | heuristic_flag = 0; 309 | 310 | func_t *function = getn_func(i); 311 | if (function != NULL) { 312 | bool crypto_flag = func_name_has_prefix(crypto_prefix, function->start_ea); 313 | 314 | // skip libs that are not marked as crypto 315 | if ( ((function->flags & FUNC_LIB) != 0) && !crypto_flag ) 316 | continue; 317 | 318 | // From this point on, we have a function outside of lib or a crypto one 319 | 320 | // Ignore functions less than MIN_FUNC_SIZE_DUMP bytes 321 | if ( ((function->end_ea - function->start_ea) < MIN_FUNC_SIZE_DUMP) && !crypto_flag ) 322 | continue; 323 | 324 | // If function is bigger than MIN_HEURISTIC_FUNC_SIZE_DUMP, mark as being triggered by the heuristic 325 | if (function->end_ea - function->start_ea > MIN_HEURISTIC_FUNC_SIZE_DUMP) 326 | heuristic_flag = 1; 327 | 328 | // dump up to N_CRYPTO_FUNCS_TO_DUMP crypto functions 329 | // dump up to N_HEUR_FUNCS_TO_DUMP heuristic functions 330 | // at least N_FUNCS_TO_DUMP functions will be dumped 331 | if ((count < N_FUNCS_TO_DUMP) || (crypto_flag && (crypto_count < N_CRYPTO_FUNCS_TO_DUMP)) || (heuristic_flag && (heur_count < N_HEUR_FUNCS_TO_DUMP))) { 332 | hexrays_failure_t hf; 333 | cfuncptr_t cfunc = decompile(function, &hf); 334 | 335 | logmsg(DEBUG, "\nafter decompile()\n"); 336 | if (cfunc != NULL) { 337 | ctree_dumper_t ctree_dumper; 338 | ctree_dumper.apply_to(&cfunc->body, NULL); 339 | 340 | ctree_dump_line func_dump; 341 | func_dump.ctree_dump = ctree_dumper.ctree_dump; 342 | func_dump.ctree_for_hash = ctree_dumper.ctree_for_hash; 343 | 344 | func_dump.func_depth = -1; 345 | 346 | func_dump.func_start = function->start_ea; 347 | func_dump.func_end = function->end_ea; 348 | 349 | qstring func_name; 350 | if (get_func_name(&func_name, function->start_ea) != 0) { 351 | if (func_name.length() > 0) { 352 | func_dump.func_name = func_name; 353 | } 354 | } 355 | 356 | func_parent_iterator_t fpi(function); 357 | for (ea_t addr = get_first_cref_to(function->start_ea); addr != BADADDR; addr = get_next_cref_to(function->start_ea, addr)) { 358 | func_t *referer = get_func(addr); 359 | if (referer != NULL) { 360 | func_dump.referres.push_back(referer->start_ea); 361 | } 362 | } 363 | 364 | func_dump.heuristic_flag = heuristic_flag; // 0 or 1 depending on code above 365 | if (heuristic_flag) 366 | heur_count++; 367 | 368 | if (crypto_flag) 369 | crypto_count++; 370 | 371 | count++; 372 | 373 | data_to_dump[function->start_ea] = func_dump; 374 | } 375 | } 376 | } 377 | } 378 | 379 | dump_ctrees_in_file(data_to_dump, crypto_prefix); 380 | 381 | return true; 382 | } 383 | 384 | bool idaapi extract_all_ctrees(void *ud) 385 | { 386 | // default prefix to display in the dialog 387 | static const qstring kDefaultPrefix = "crypto_"; 388 | 389 | va_list va; 390 | va_end(va); 391 | 392 | qstring crypto_prefix = kDefaultPrefix; 393 | if (!ask_str(&crypto_prefix, 0, "Enter prefix of crypto function names", va)) 394 | return false; 395 | 396 | if(!crypto_prefix.empty()) { 397 | dump_funcs_ctree(NULL, crypto_prefix); 398 | } else { 399 | warning("Incorrect prefix!!"); 400 | } 401 | 402 | return true; 403 | } 404 | 405 | 406 | // Ctree Item Form Init 407 | struct func_ctree_info_t 408 | { 409 | TWidget *widget; 410 | TWidget *cv; 411 | TWidget *codeview; 412 | strvec_t sv; 413 | func_ctree_info_t(TWidget *f) : widget(f), cv(nullptr), codeview(nullptr){} 414 | }; 415 | 416 | 417 | bool idaapi show_citem_custom_view(void *ud, const qstring& ctree_item, const qstring& item_name) 418 | { 419 | qstring form_name = "Ctree Item View: "; 420 | form_name.append(item_name); 421 | TWidget *widget = create_empty_widget(form_name.c_str()); 422 | func_ctree_info_t *si = new func_ctree_info_t(widget); 423 | 424 | istringstream s_citem_str(ctree_item.c_str()); 425 | string tmp_str; 426 | while (getline(s_citem_str, tmp_str, ';')) 427 | { 428 | qstring tmp_qstr = tmp_str.c_str(); 429 | si->sv.push_back(simpleline_t(tmp_qstr)); 430 | } 431 | 432 | simpleline_place_t s1; 433 | simpleline_place_t s2(static_cast(ctree_item.size())); 434 | si->cv = create_custom_viewer("", &s1, &s2, &s1, nullptr, &si->sv, nullptr, nullptr, widget); 435 | si->codeview = create_code_viewer(si->cv, CDVF_NOLINES, widget); 436 | set_custom_viewer_handlers(si->cv, NULL, si); 437 | #if (defined(IDA_SDK_VERSION) && IDA_SDK_VERSION == 720) 438 | display_widget(widget, WOPN_RESTORE); 439 | #else 440 | display_widget(widget, WOPN_ONTOP | WOPN_RESTORE); 441 | #endif 442 | 443 | return false; 444 | } 445 | 446 | -------------------------------------------------------------------------------- /src/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 | void parse_ctree_item(citem_t *item, qstring& rv) const; 48 | }; 49 | 50 | 51 | bool idaapi show_citem_custom_view(void *ud, const qstring& ctree_item, const qstring& item_name); 52 | bool idaapi dump_funcs_ctree(void *ud, const 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(const qstring &string_to_hash, qstring &hash); 56 | 57 | 58 | #endif -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/CtreeGraphBuilder.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 "CtreeGraphBuilder.h" 28 | #include "ObjectExplorer.h" 29 | #include "Utility.h" 30 | 31 | #if defined (__LINUX__) || defined (__MAC__) 32 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 33 | #endif 34 | 35 | 36 | bool callgraph_t::visited(citem_t *i, int *nid) 37 | { 38 | ea_int_map_t::const_iterator it = ea2node.find(i); 39 | if (it != ea2node.end()) 40 | { 41 | if (nid != NULL) 42 | *nid = it->second; 43 | return true; 44 | } 45 | return false; 46 | } 47 | 48 | 49 | void callgraph_t::create_edge(int id1, int id2) 50 | { 51 | edges.push_back(edge_t(id1, id2)); 52 | } 53 | 54 | 55 | void callgraph_t::get_node_label(int n, qstring& rv) const 56 | { 57 | int_ea_map_t::const_iterator it = node2ea.find(n); 58 | rv.clear(); 59 | 60 | if ( it != node2ea.end() ) 61 | { 62 | const citem_t *item = it->second; 63 | 64 | // Each node will have the element type at the first line 65 | auto ctype_name = get_ctype_name(item->op); 66 | if (ctype_name) 67 | rv = ctype_name; 68 | 69 | const cexpr_t *e = (const cexpr_t *)item; 70 | const cinsn_t *i = (const cinsn_t *)item; 71 | 72 | // For some item types, display additional information 73 | qstring func_name; 74 | qstring constant; 75 | switch (item->op) 76 | { 77 | case cot_call: 78 | if (get_func_name(&func_name, e->x->obj_ea) == 0) 79 | rv.cat_sprnt(" sub_%a", e->x->obj_ea); 80 | else 81 | rv.cat_sprnt(" %s", func_name.c_str()); 82 | break; 83 | case cot_ptr: // *x 84 | case cot_memptr: // x->m 85 | // Display access size for pointers 86 | rv.cat_sprnt(".%d", e->ptrsize); 87 | if (item->op == cot_ptr) 88 | break; 89 | case cot_memref: // x.m 90 | // Display member offset for structure fields 91 | rv.cat_sprnt(" (m=%d)", e->m); 92 | break; 93 | case cot_obj: // v 94 | 95 | case cot_var: // l 96 | // Display object size for local variables and global data 97 | rv.cat_sprnt(".%d", e->refwidth); 98 | case cot_num: // n 99 | case cot_helper: // arbitrary name 100 | case cot_str: // string constant 101 | // Display helper names and number values 102 | rv.append(' '); 103 | { 104 | qstring qbuf; 105 | print1wrapper(e, &qbuf, nullptr); 106 | tag_remove(&qbuf); 107 | rv += qbuf; 108 | } 109 | break; 110 | case cit_goto: 111 | // Display target label number for gotos 112 | rv.cat_sprnt(" LABEL_%d", i->cgoto->label_num); 113 | break; 114 | case cit_asm: 115 | // Display instruction block address and size for asm-statements 116 | rv.cat_sprnt(" %a.%" FMT_Z, *i->casm->begin(), i->casm->size()); 117 | break; 118 | default: 119 | break; 120 | } 121 | 122 | rv.cat_sprnt("\nea: %a", item->ea); 123 | 124 | if ( item->is_expr() && !e->type.empty() ) 125 | { 126 | // For typed expressions, the third line will have 127 | // the expression type in human readable form 128 | rv.append('\n'); 129 | qstring out; 130 | if (e->type.print(&out)) 131 | { 132 | rv += out; 133 | } 134 | else 135 | { // could not print the type? 136 | rv.append('?'); 137 | } 138 | 139 | if(e->type.is_ptr()) 140 | { 141 | tinfo_t ptr_rem = remove_pointer(e->type); 142 | if(ptr_rem.is_struct()) 143 | { 144 | qstring typenm; 145 | ptr_rem.print(&typenm, "prefix ", 0, 0, PRTYPE_MULTI | PRTYPE_TYPE | PRTYPE_SEMI); 146 | } 147 | } 148 | } 149 | } 150 | } 151 | 152 | 153 | callgraph_t::nodeinfo_t *callgraph_t::get_info(int nid) 154 | { 155 | nodeinfo_t *ret = NULL; 156 | 157 | do 158 | { 159 | // returned cached name 160 | int_funcinfo_map_t::iterator it = cached_funcs.find(nid); 161 | if (it != cached_funcs.end()) 162 | { 163 | ret = &it->second; 164 | break; 165 | } 166 | 167 | // node does not exist? 168 | int_ea_map_t::const_iterator it_ea = node2ea.find(nid); 169 | if (it_ea == node2ea.end()) 170 | break; 171 | 172 | citem_t *pfn = it_ea->second; 173 | if (!pfn) 174 | break; 175 | 176 | nodeinfo_t fi; 177 | 178 | // get name 179 | qstring nodeLabel; 180 | get_node_label(nid, nodeLabel); 181 | if (!nodeLabel.empty()) 182 | fi.name = nodeLabel; 183 | else 184 | fi.name = "?unknown"; 185 | 186 | // get color 187 | if(pfn == highlighted) // highlight element with current cursor position 188 | fi.color = 2000; 189 | else 190 | fi.color = 1; 191 | 192 | #define CL_DARKBLUE ((0 )+ (0 <<8)+ (128<<16)) 193 | if (pfn->op == cit_expr) 194 | fi.color = CL_DARKBLUE; 195 | #define CL_BLUE ((0 )+ (0 <<8)+ (255<<16)) 196 | if (pfn->op == cit_block) 197 | fi.color = CL_BLUE; 198 | 199 | fi.ea = pfn->ea; 200 | 201 | it = cached_funcs.insert(cached_funcs.end(), std::make_pair(nid, fi)); 202 | ret = &it->second; 203 | } while ( false ); 204 | 205 | return ret; 206 | } 207 | 208 | 209 | //-------------------------------------------------------------------------- 210 | int callgraph_t::add(citem_t *i) 211 | { 212 | // check if we are trying to add existing node 213 | ea_int_map_t::const_iterator it = ea2node.find(i); 214 | if ( it != ea2node.end() ) 215 | return it->second; 216 | 217 | ea2node[i] = node_count; 218 | node2ea[node_count] = i; 219 | 220 | int ret_val = node_count; 221 | node_count ++; 222 | return ret_val; 223 | } 224 | 225 | 226 | //-------------------------------------------------------------------------- 227 | callgraph_t::callgraph_t() 228 | : node_count(0) 229 | , highlighted(nullptr) 230 | { 231 | //cur_text[0] = '\0'; 232 | } 233 | 234 | 235 | //-------------------------------------------------------------------------- 236 | void callgraph_t::clear_edges() 237 | { 238 | edges.clear(); 239 | } 240 | 241 | //-------------------------------------------------------------------------- 242 | graph_info_t::graphinfo_list_t graph_info_t::instances; 243 | 244 | //-------------------------------------------------------------------------- 245 | graph_info_t::graph_info_t() 246 | : gv(nullptr) 247 | , widget(nullptr) 248 | , vu(nullptr) 249 | , func_ea(BADADDR) 250 | , func_instance_no(0) 251 | { 252 | } 253 | 254 | 255 | //-------------------------------------------------------------------------- 256 | // Create graph for current decompiled function 257 | graph_info_t * graph_info_t::create(ea_t func_ea, citem_t *highlighted) 258 | { 259 | func_t *pfn = get_func(func_ea); 260 | if (!pfn) 261 | return nullptr; 262 | 263 | graph_info_t *r = new graph_info_t(); 264 | r->func_ea = pfn->start_ea; 265 | r->fg.highlighted = highlighted; 266 | 267 | size_t num_inst = 0; 268 | for (const graph_info_t* gi : instances) 269 | { 270 | if (gi->func_ea == func_ea && num_inst < gi->func_instance_no) 271 | num_inst = gi->func_instance_no; 272 | } 273 | 274 | r->func_instance_no = ++num_inst; 275 | get_title(func_ea, num_inst, &r->title); 276 | 277 | instances.push_back(r); 278 | 279 | return r; 280 | } 281 | 282 | 283 | //-------------------------------------------------------------------------- 284 | bool graph_info_t::get_title(ea_t func_ea, size_t num_inst, qstring *out) 285 | { 286 | // we should succeed in getting the name 287 | qstring func_name; 288 | if ( get_func_name(&func_name, func_ea) == 0) 289 | return false; 290 | 291 | out->sprnt("Ctree Graph View: %s %d", func_name.c_str(), static_cast(num_inst)); 292 | 293 | return true; 294 | } 295 | 296 | 297 | void graph_info_t::destroy(graph_info_t *gi) 298 | { 299 | // FIXME: never called 300 | for(graphinfo_list_t::iterator it = instances.begin() ; it != instances.end() ; ++it) 301 | { 302 | if (*it == gi) 303 | { 304 | instances.erase(it); 305 | break; 306 | } 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/CtreeGraphBuilder.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 | //char cur_text[MAXSTR]; 46 | 47 | bool visited(citem_t *i, int *nid); 48 | 49 | public: 50 | 51 | citem_t *highlighted; 52 | 53 | int add(citem_t *i); 54 | // edge structure 55 | struct edge_t 56 | { 57 | int id1; 58 | int id2; 59 | edge_t(int i1, int i2): id1(i1), id2(i2) { } 60 | edge_t(): id1(0), id2(0) { } 61 | }; 62 | 63 | typedef qlist edges_t; 64 | 65 | // edge manipulation 66 | typedef edges_t::iterator edge_iterator; 67 | void create_edge(int id1, int id2); 68 | 69 | edge_iterator begin_edges() { return edges.begin(); } 70 | edge_iterator end_edges() { return edges.end(); } 71 | 72 | void clear_edges(); 73 | 74 | callgraph_t(); 75 | 76 | int count() const { return node_count; } 77 | 78 | // node / func info 79 | struct nodeinfo_t 80 | { 81 | qstring name; 82 | bgcolor_t color; 83 | ea_t ea; 84 | }; 85 | 86 | typedef std::map int_funcinfo_map_t; 87 | int_funcinfo_map_t cached_funcs; 88 | nodeinfo_t *get_info(int nid); 89 | 90 | 91 | // int walk_func(func_t *func); 92 | private: 93 | edges_t edges; 94 | 95 | void get_node_label(int n, qstring& rv) const; 96 | }; 97 | 98 | 99 | // per function call graph context 100 | class graph_info_t 101 | { 102 | // Actual context variables 103 | public: 104 | callgraph_t fg; // associated graph maker 105 | graph_viewer_t *gv; // associated graph_view 106 | TWidget *widget; // associated TForm 107 | vdui_t *vu; 108 | 109 | 110 | ea_t func_ea; // function ea in question 111 | qstring title; // the title 112 | 113 | size_t func_instance_no; 114 | // Instance management 115 | private: 116 | typedef qlist graphinfo_list_t; 117 | typedef graphinfo_list_t::iterator iterator; 118 | 119 | // Remove instance upon deletion of the objects 120 | static graphinfo_list_t instances; 121 | 122 | 123 | graph_info_t(); 124 | public: 125 | static graph_info_t *create(ea_t func_ea, citem_t *it); 126 | static void destroy(graph_info_t *gi); 127 | static bool get_title(ea_t func_ea, size_t num_inst, qstring *out); 128 | }; 129 | 130 | #endif -------------------------------------------------------------------------------- /src/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 | #if defined (__LINUX__) || defined (__MAC__) 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 == -1) 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 | qclose(file_id); 48 | } 49 | 50 | static void print_to_error_file(const char *error_msg) { 51 | int file_id = qopen(ERROR_FILE, O_WRONLY | O_APPEND); 52 | if (file_id == -1) 53 | file_id = qcreate(ERROR_FILE, 511); 54 | 55 | if (file_id == -1) { 56 | msg("FATAL: print_to_error_file failed!\n"); 57 | return; 58 | } 59 | 60 | qwrite(file_id, error_msg, strlen(error_msg)); 61 | qclose(file_id); 62 | } 63 | 64 | void logmsg(unsigned int level, const char *fmt, ...) 65 | { 66 | va_list arglist; 67 | 68 | if (level > CURRENT_DEBUG_LEVEL) 69 | return; 70 | 71 | va_start(arglist, fmt); 72 | 73 | switch (level) { 74 | case OUTPUT: 75 | print_to_output_file(fmt); 76 | break; 77 | case ERROR: 78 | print_to_error_file(fmt); 79 | break; 80 | default: 81 | vmsg(fmt, arglist); 82 | break; 83 | } 84 | 85 | va_end(arglist); 86 | } -------------------------------------------------------------------------------- /src/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 -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCObjectFormatParser.cpp: -------------------------------------------------------------------------------- 1 | #include "GCCObjectFormatParser.h" 2 | #include "Common.h" 3 | #include "entry.hpp" 4 | #include "Debug.h" 5 | #include "demangle.hpp" 6 | #include "name.hpp" 7 | #include "offset.hpp" 8 | #include "nalt.hpp" 9 | #include "bytes.hpp" 10 | #include "Utility.h" 11 | #include "stddef.h" 12 | #include "GCCVtableInfo.h" 13 | #include "GCCTypeInfo.h" 14 | 15 | 16 | #define vmi_class_type_info_name "_ZTVN10__cxxabiv121__vmi_class_type_infoE" 17 | #define class_type_info_name "_ZTVN10__cxxabiv117__class_type_infoE" 18 | #define si_class_type_info_name "_ZTVN10__cxxabiv120__si_class_type_infoE" 19 | 20 | 21 | extern std::map rtti_vftables; 22 | 23 | std::mapg_KnownVtables; 24 | std::mapg_KnownTypes; 25 | 26 | ea_t class_type_info_vtbl = -1; 27 | ea_t si_class_type_info_vtbl = -1; 28 | ea_t vmi_class_type_info_vtbl = -1; 29 | 30 | 31 | 32 | GCCObjectFormatParser::GCCObjectFormatParser() 33 | { 34 | } 35 | 36 | 37 | GCCObjectFormatParser::~GCCObjectFormatParser() 38 | { 39 | } 40 | 41 | void GCCObjectFormatParser::getRttiInfo() 42 | { 43 | qstring buffer; 44 | const size_t count = get_entry_qty(); 45 | 46 | // First collect info about __cxxabiv1:: vtables 47 | for (int i = 0; i < count; ++i) { 48 | uval_t ordinal = get_entry_ordinal(i); 49 | get_entry_name(&buffer, ordinal); 50 | ea_t ea = get_entry(ordinal); 51 | ea += offsetof(GCC_RTTI::__vtable_info, origin); 52 | 53 | if (buffer == class_type_info_name) 54 | { 55 | class_type_info_vtbl = ea; 56 | set_name(ea, "__cxxabiv1::__class_type_info::vtable", SN_NOWARN); 57 | } 58 | 59 | if (buffer == si_class_type_info_name) 60 | { 61 | si_class_type_info_vtbl = ea; 62 | set_name(ea, "__cxxabiv1::__si_class_type_info::vtable", SN_NOWARN); 63 | } 64 | 65 | if (buffer == vmi_class_type_info_name) 66 | { 67 | vmi_class_type_info_vtbl = ea; 68 | set_name(ea, "__cxxabiv1::__vmi_class_type_info::vtable", SN_NOWARN); 69 | } 70 | } 71 | // now we can scan segments for vtables. 72 | int segCount = get_segm_qty(); 73 | for (int i = 0; i < segCount; i++) 74 | { 75 | if (segment_t *seg = getnseg(i)) 76 | { 77 | if (seg->type == SEG_DATA) 78 | { 79 | scanSeg4Vftables(seg); 80 | } 81 | } 82 | } 83 | } 84 | 85 | void GCCObjectFormatParser::scanSeg4Vftables(segment_t *seg) 86 | { 87 | UINT found = 0; 88 | if (seg->size() >= sizeof(ea_t)) 89 | { 90 | ea_t startEA = ((seg->start_ea + sizeof(ea_t)) & ~((ea_t)(sizeof(ea_t) - 1))); 91 | ea_t endEA = (seg->end_ea - sizeof(ea_t)); 92 | 93 | for (ea_t ptr = startEA; ptr < endEA; ptr += sizeof(ea_t)) 94 | { 95 | // Struct of vtable is following: 96 | // 0: ptrdiff that tells "Where is the original object according to vtable. This one is 0 of -x; 97 | // 1*sizeof(ea_t): ptr to type_info 98 | // 2*sizeof(ea_t) ... : the exact functions. 99 | // So if we can parse type_info as type_info and we see functions, it should be vtable. 100 | //ea_t ea = getEa(ptr); 101 | //flags_t flags = get_flags_novalue(ea); 102 | //if (isData(flags)) 103 | //{ 104 | GCCVtableInfo * info = GCCVtableInfo::parseVtableInfo(ptr); 105 | if (info) 106 | { 107 | VTBL_info_t vtbl_info; 108 | vtbl_info.ea_begin = info->vtbl_start; 109 | vtbl_info.ea_end = info->ea_end; 110 | vtbl_info.vtbl_name = info->typeName; 111 | vtbl_info.methods = info->vtables[0].methodsCount; 112 | rtti_vftables[ptr + offsetof(GCC_RTTI::__vtable_info, origin)] = vtbl_info; 113 | ptr = info->ea_end; 114 | } 115 | else { 116 | 117 | GCCTypeInfo *typeInfo = GCCTypeInfo::parseTypeInfo(ptr); 118 | if (typeInfo) 119 | { 120 | ; 121 | } 122 | 123 | } 124 | //} 125 | } 126 | } 127 | 128 | return; 129 | } 130 | 131 | void GCCObjectFormatParser::clearInfo() 132 | { 133 | g_KnownVtables.clear(); 134 | g_KnownTypes.clear(); 135 | } -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCObjectFormatParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Common.h" 3 | #include "IObjectFormatParser.h" 4 | #include "ObjectExplorer.h" 5 | 6 | 7 | namespace GCC_RTTI { 8 | #pragma pack(push, 1) 9 | 10 | struct __vtable_info { 11 | ea_t ptrdiff; 12 | ea_t type_info; 13 | ea_t origin[1]; 14 | }; 15 | 16 | 17 | struct __class_type_info; 18 | 19 | struct type_info { 20 | ea_t __type_info_vtable; 21 | ea_t __type_info_name; 22 | }; 23 | 24 | struct __pbase_type_info : public type_info { 25 | int quals; 26 | ea_t *type; 27 | 28 | enum quals_masks { 29 | const_mask = 0x1, 30 | volatile_mask = 0x2, 31 | restrict_mask = 0x4, 32 | incomplete_mask = 0x8, 33 | incomplete_class_mask = 0x10 34 | }; 35 | 36 | }; 37 | 38 | struct __pointer_type_info 39 | : public __pbase_type_info { 40 | const __class_type_info *klass; 41 | }; 42 | 43 | struct __base_class_info { 44 | ea_t base; 45 | size_t vmi_offset_flags; 46 | enum vmi_masks { 47 | virtual_mask = 0x1, 48 | public_mask = 0x2, 49 | hwm_bit = 2, 50 | offset_shift = 8 /* bits to shift offset by */ 51 | }; 52 | }; 53 | 54 | 55 | struct __class_type_info 56 | : public type_info 57 | { 58 | enum __sub_kind 59 | { 60 | __unknown = 0, /* we have no idea */ 61 | __not_contained, /* not contained within us (in some */ 62 | /* circumstances this might mean not contained */ 63 | /* publicly) */ 64 | __contained_ambig, /* contained ambiguously */ 65 | 66 | __contained_virtual_mask = __base_class_info::virtual_mask, /* via a virtual path */ 67 | __contained_public_mask = __base_class_info::public_mask, /* via a public path */ 68 | __contained_mask = 1 << __base_class_info::hwm_bit, /* contained within us */ 69 | 70 | __contained_private = __contained_mask, 71 | __contained_public = __contained_mask | __contained_public_mask 72 | }; 73 | 74 | 75 | }; 76 | 77 | struct __si_class_type_info 78 | : public __class_type_info 79 | { 80 | ea_t base; 81 | }; 82 | 83 | struct __vmi_class_type_info : public __class_type_info 84 | { 85 | int vmi_flags; 86 | int vmi_base_count; 87 | struct __base_class_info vmi_bases[1]; 88 | 89 | enum vmi_flags_masks { 90 | non_diamond_repeat_mask = 0x1, /* distinct instance of repeated base */ 91 | diamond_shaped_mask = 0x2, /* diamond shaped multiple inheritance */ 92 | non_public_base_mask = 0x4, /* has non-public direct or indirect base */ 93 | public_base_mask = 0x8, /* has public base (direct) */ 94 | 95 | __flags_unknown_mask = 0x10 96 | }; 97 | 98 | }; 99 | 100 | struct __user_type_info : public type_info 101 | { 102 | enum sub_kind 103 | { 104 | unknown = 0, // we have no idea 105 | not_contained, // not contained within us (in some 106 | // circumstances this might mean not contained 107 | // publicly) 108 | contained_ambig, // contained ambiguously 109 | contained_mask = 4, // contained within us 110 | contained_virtual_mask = 1, // via a virtual path 111 | contained_public_mask = 2, // via a public path 112 | contained_private = contained_mask, 113 | contained_public = contained_mask | contained_public_mask 114 | }; 115 | 116 | }; 117 | 118 | 119 | 120 | #pragma pack(pop) 121 | }; 122 | 123 | class GCCObjectFormatParser : 124 | public IObjectFormatParser 125 | { 126 | 127 | public: 128 | GCCObjectFormatParser(); 129 | virtual ~GCCObjectFormatParser(); 130 | 131 | virtual void getRttiInfo(); 132 | virtual void clearInfo(); 133 | 134 | void scanSeg4Vftables(segment_t *seg); 135 | }; 136 | 137 | class GCCVtableInfo; 138 | class GCCTypeInfo; 139 | 140 | extern std::mapg_KnownVtables; 141 | extern std::mapg_KnownTypes; 142 | 143 | extern ea_t class_type_info_vtbl; 144 | extern ea_t si_class_type_info_vtbl; 145 | extern ea_t vmi_class_type_info_vtbl; 146 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCTypeInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "GCCTypeInfo.h" 2 | #include "GCCObjectFormatParser.h" 3 | #include "offset.hpp" 4 | #include "Utility.h" 5 | 6 | #if __clang__ 7 | // Ignore "offset of on non-standard-layout type" warning 8 | #pragma clang diagnostic ignored "-Winvalid-offsetof" 9 | #endif 10 | 11 | 12 | GCCTypeInfo::GCCTypeInfo() 13 | : ea(BADADDR) 14 | , vtbl(BADADDR) 15 | , parentsCount(0) 16 | , parentsTypes(nullptr) 17 | { 18 | } 19 | 20 | 21 | GCCTypeInfo::~GCCTypeInfo() 22 | { 23 | if (parentsTypes) 24 | delete[] parentsTypes; 25 | } 26 | 27 | 28 | GCCTypeInfo *GCCTypeInfo::parseTypeInfo(ea_t ea) 29 | { 30 | if (g_KnownTypes.count(ea)) 31 | return g_KnownTypes[ea]; 32 | 33 | GCC_RTTI::type_info tmp; 34 | if (!get_bytes(&tmp, sizeof(GCC_RTTI::type_info), ea)) 35 | return 0; 36 | 37 | ea_t name_ea = tmp.__type_info_name; 38 | 39 | size_t length = get_max_strlit_length(name_ea, STRTYPE_C, ALOPT_IGNHEADS); 40 | qstring buffer; 41 | 42 | if (!get_strlit_contents(&buffer, name_ea, length, STRTYPE_C)) { 43 | return 0; 44 | } 45 | qstring name(buffer); 46 | qstring demangled_name; 47 | name = qstring("_ZTS") + name; 48 | int32 res = demangle_name(&demangled_name, name.c_str(), 0); 49 | if (res != (MT_GCC3 | M_AUTOCRT | MT_RTTI)) 50 | { 51 | return 0; 52 | } 53 | 54 | demangled_name = demangled_name.substr(19); 55 | 56 | GCCTypeInfo * result = new GCCTypeInfo(); 57 | result->ea = ea; 58 | result->typeName = demangled_name; 59 | result->vtbl = tmp.__type_info_vtable; 60 | 61 | setUnknown(ea + ea_t(offsetof(GCC_RTTI::type_info, __type_info_vtable)), sizeof(ea_t)); 62 | 63 | op_plain_offset(ea + ea_t(offsetof(GCC_RTTI::type_info, __type_info_vtable)), 0, ea); 64 | setUnknown(ea + ea_t(offsetof(GCC_RTTI::type_info, __type_info_name)), sizeof(ea_t)); 65 | op_plain_offset(ea + ea_t(offsetof(GCC_RTTI::type_info, __type_info_name)), 0, ea); 66 | MakeName(ea, demangled_name, "RTTI_", ""); 67 | 68 | if (tmp.__type_info_vtable == class_type_info_vtbl) 69 | { 70 | g_KnownTypes[ea] = result; 71 | return result; 72 | } 73 | 74 | 75 | if (tmp.__type_info_vtable == si_class_type_info_vtbl) 76 | { 77 | GCC_RTTI::__si_class_type_info si_class; 78 | if (!get_bytes(&si_class, sizeof(GCC_RTTI::__si_class_type_info), ea)) 79 | { 80 | delete result; 81 | return 0; 82 | } 83 | GCCTypeInfo *base = parseTypeInfo(si_class.base); 84 | if (base == 0) 85 | { 86 | delete result; 87 | return 0; 88 | } 89 | 90 | setUnknown(ea + ea_t(offsetof(GCC_RTTI::__si_class_type_info, base)), sizeof(ea_t)); 91 | op_plain_offset(ea + ea_t(offsetof(GCC_RTTI::__si_class_type_info, base)), 0, ea); 92 | 93 | result->parentsCount = 1; 94 | result->parentsTypes = new GCCParentType*[1]; 95 | result->parentsTypes[0] = new GCCParentType(); 96 | result->parentsTypes[0]->ea = base->ea; 97 | result->parentsTypes[0]->info = base; 98 | result->parentsTypes[0]->flags = 0; 99 | g_KnownTypes[ea] = result; 100 | return result; 101 | } 102 | 103 | if (tmp.__type_info_vtable != vmi_class_type_info_vtbl) { 104 | // Unknown type, ignore it 105 | delete result; 106 | return 0; 107 | } 108 | 109 | GCC_RTTI::__vmi_class_type_info vmi_class; 110 | if (!get_bytes(&vmi_class, sizeof(GCC_RTTI::__vmi_class_type_info), ea)) 111 | return 0; 112 | 113 | // vmi_class.vmi_flags; // WTF?? 114 | 115 | result->parentsCount = vmi_class.vmi_base_count; 116 | result->parentsTypes = new GCCParentType*[result->parentsCount]; 117 | ea_t addr = ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_bases)); 118 | 119 | setUnknown(ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_flags)), sizeof(ea_t)); 120 | create_dword(ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_flags)), sizeof(ea_t)); 121 | 122 | setUnknown(ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_base_count)), sizeof(int)); 123 | create_dword(ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_base_count)), sizeof(int)); 124 | 125 | GCC_RTTI::__base_class_info baseInfo; 126 | for (int i = 0; i < vmi_class.vmi_base_count; ++i, addr += sizeof(baseInfo)) 127 | { 128 | if (!get_bytes(&baseInfo, sizeof(baseInfo), addr)) 129 | { 130 | delete result; 131 | return 0; 132 | } 133 | 134 | GCCTypeInfo *base = parseTypeInfo(baseInfo.base); 135 | if (base == 0) 136 | { 137 | delete result; 138 | return 0; 139 | } 140 | setUnknown(addr + ea_t(offsetof(GCC_RTTI::__base_class_info, base)), sizeof(ea_t)); 141 | op_plain_offset(addr + offsetof(GCC_RTTI::__base_class_info, base), 0, addr); 142 | 143 | setUnknown(addr + ea_t(offsetof(GCC_RTTI::__base_class_info, vmi_offset_flags)), sizeof(ea_t)); 144 | create_dword(addr + ea_t(offsetof(GCC_RTTI::__base_class_info, vmi_offset_flags)), sizeof(int)); 145 | result->parentsTypes[i] = new GCCParentType(); 146 | result->parentsTypes[i]->ea = base->ea; 147 | result->parentsTypes[i]->ea = base->ea; 148 | result->parentsTypes[i]->info = base; 149 | result->parentsTypes[i]->flags = static_cast(baseInfo.vmi_offset_flags); 150 | 151 | qstring flags; 152 | if (baseInfo.vmi_offset_flags & baseInfo.virtual_mask) 153 | flags += " virtual_mask "; 154 | if (baseInfo.vmi_offset_flags & baseInfo.public_mask) 155 | flags += " public_mask "; 156 | if (baseInfo.vmi_offset_flags & baseInfo.offset_shift) 157 | flags += " offset_shift "; 158 | set_cmt(addr + ea_t(offsetof(GCC_RTTI::__base_class_info, vmi_offset_flags)), flags.c_str(), false); 159 | } 160 | g_KnownTypes[ea] = result; 161 | return result; 162 | } 163 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCTypeInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Common.h" 3 | 4 | class GCCTypeInfo; 5 | 6 | class GCCParentType { 7 | public: 8 | ea_t ea = BADADDR; 9 | GCCTypeInfo *info = nullptr; 10 | unsigned int flags = 0; 11 | }; 12 | 13 | class GCCTypeInfo 14 | { 15 | public: 16 | GCCTypeInfo(); 17 | ~GCCTypeInfo(); 18 | 19 | ea_t ea; 20 | qstring typeName; 21 | ea_t vtbl; // vtable of std::typeinfo. 22 | unsigned int parentsCount; 23 | GCCParentType **parentsTypes; 24 | 25 | static GCCTypeInfo *parseTypeInfo(ea_t ea); 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCVtableInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "GCCVtableInfo.h" 2 | #include "GCCObjectFormatParser.h" 3 | #include "GCCTypeInfo.h" 4 | #include "Utility.h" 5 | 6 | 7 | 8 | GCCVtableInfo::GCCVtableInfo() 9 | : ea_start(BADADDR) 10 | , vtbl_start(BADADDR) 11 | , typeInfo(nullptr) 12 | , vtablesCount(0) 13 | , vtables(nullptr) 14 | , ea_end(BADADDR) 15 | { 16 | } 17 | 18 | 19 | GCCVtableInfo::~GCCVtableInfo() 20 | { 21 | } 22 | 23 | 24 | unsigned int findMethodsCount(ea_t addr) 25 | { 26 | ea_t func; 27 | unsigned int methodsCount = 0; 28 | while (1) { 29 | func = getEa(addr); 30 | if (func != 0) 31 | { 32 | segment_t *seg = getseg(func); 33 | if (!seg) 34 | { 35 | break; 36 | } 37 | if ((seg->perm & SEGPERM_EXEC) == 0) 38 | { 39 | break; 40 | } 41 | } 42 | ++methodsCount; 43 | addr += sizeof(ea_t); 44 | } 45 | // Now lets remove ending zeroes. 46 | while (methodsCount) { 47 | addr -= sizeof(ea_t); 48 | func = getEa(addr); 49 | if (func != 0) 50 | break; 51 | --methodsCount; 52 | } 53 | return methodsCount; 54 | } 55 | 56 | 57 | GCCVtableInfo *GCCVtableInfo::parseVtableInfo(ea_t ea) 58 | { 59 | if (g_KnownVtables.count(ea)) 60 | return g_KnownVtables[ea]; 61 | 62 | GCC_RTTI::__vtable_info vtable; 63 | ea_t addr; 64 | if (!get_bytes(&vtable, sizeof(GCC_RTTI::__vtable_info), ea)) 65 | return nullptr; 66 | 67 | // Check ptrdiff is 0 for origin vtable 68 | if (vtable.ptrdiff != 0) 69 | return nullptr; 70 | 71 | GCCTypeInfo *type = GCCTypeInfo::parseTypeInfo(vtable.type_info); 72 | if (type == 0) 73 | return nullptr; 74 | 75 | unsigned int methodsCount = 0; 76 | 77 | addr = ea + offsetof(GCC_RTTI::__vtable_info, origin); 78 | methodsCount = findMethodsCount(addr); 79 | 80 | if (methodsCount == 0) 81 | return nullptr; // Doesnt look like vtable. 82 | 83 | GCCVtableInfo *result = new GCCVtableInfo(); 84 | result->ea_start = ea; 85 | result->vtbl_start = ea + offsetof(GCC_RTTI::__vtable_info, origin); 86 | result->typeInfo = type; 87 | result->typeName = type->typeName; 88 | 89 | addr += methodsCount * sizeof(ea_t); 90 | if (type->parentsCount > 1) { 91 | result->vtablesCount = type->parentsCount; 92 | result->vtables = new GCCVtable[type->parentsCount](); 93 | for (unsigned i = 0; i < type->parentsCount; ++i) 94 | { 95 | if (!GCCVtableInfo::parseVtableInnerInfo(addr, &result->vtables[i])) 96 | { 97 | delete result; 98 | return nullptr; 99 | } 100 | addr += offsetof(GCC_RTTI::__vtable_info, origin); 101 | addr += result->vtables[i].methodsCount * sizeof(ea_t); 102 | } 103 | } 104 | else 105 | { 106 | result->vtablesCount = 1; 107 | result->vtables = new GCCVtable[1](); 108 | result->vtables[0].ea = ea; 109 | result->vtables[0].methodsCount = methodsCount; 110 | result->vtables[0].ptrDiff = 0; 111 | result->vtables[0].typeInfo = type; 112 | } 113 | result->ea_end = addr; 114 | g_KnownVtables[ea] = result; 115 | 116 | return result; 117 | } 118 | bool GCCVtableInfo::parseVtableInnerInfo(ea_t ea, GCCVtable *vtbl) 119 | { 120 | /* 121 | result->vtables[i].ea = ea; 122 | result->vtables[i].methodsCount = methodsCount; 123 | result->vtables[i].ptrDiff = 0; 124 | result->vtables[i].typeInfo = type; 125 | */ 126 | 127 | GCC_RTTI::__vtable_info vtable; 128 | if (!get_bytes(&vtable, sizeof(GCC_RTTI::__vtable_info), ea)) 129 | return false; 130 | 131 | if (vtable.ptrdiff >= 0) 132 | return false; 133 | 134 | GCCTypeInfo *type = GCCTypeInfo::parseTypeInfo(vtable.type_info); 135 | if (!type) 136 | return false; 137 | 138 | unsigned int methodsCount = 0; 139 | 140 | ea_t addr = ea + offsetof(GCC_RTTI::__vtable_info, origin); 141 | methodsCount = findMethodsCount(addr); 142 | 143 | if (methodsCount == 0) 144 | return false; // Doesn't look like vtable. 145 | 146 | vtbl->ea = ea; 147 | vtbl->methodsCount = methodsCount; 148 | vtbl->ptrDiff = static_cast(vtable.ptrdiff); 149 | vtbl->typeInfo = type; 150 | return true; 151 | } -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCVtableInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Common.h" 3 | 4 | class GCCTypeInfo; 5 | 6 | class GCCVtable 7 | { 8 | 9 | public: 10 | ea_t ea; 11 | signed long ptrDiff; 12 | unsigned int methodsCount; 13 | GCCTypeInfo *typeInfo; 14 | 15 | }; 16 | 17 | class GCCVtableInfo 18 | { 19 | public: 20 | GCCVtableInfo(); 21 | ~GCCVtableInfo(); 22 | 23 | ea_t ea_start; 24 | ea_t vtbl_start; 25 | qstring typeName; 26 | GCCTypeInfo *typeInfo; 27 | unsigned int vtablesCount; 28 | GCCVtable *vtables; 29 | ea_t ea_end; 30 | 31 | static GCCVtableInfo *parseVtableInfo(ea_t ea); 32 | static bool parseVtableInnerInfo(ea_t ea, GCCVtable *vtbl); 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug x64 6 | x64 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release x64 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {F7E6B557-41F3-444A-BCA4-3527547DD665} 23 | Win32Proj 24 | HexRaysCodeXplorer 25 | HexRaysCodeXplorer 26 | 8.1 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | MultiByte 33 | v140 34 | 35 | 36 | DynamicLibrary 37 | true 38 | MultiByte 39 | v140 40 | 41 | 42 | DynamicLibrary 43 | false 44 | MultiByte 45 | v140 46 | 47 | 48 | DynamicLibrary 49 | false 50 | MultiByte 51 | v140 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | build makefile 76 | .dll 77 | $(IDADIR)\plugins\SDK\idasdk70\lib\x64_win_vc_32;$(IDADIR)\plugins\SDK\idasdk70\lib\x64_win_qt;$(LibraryPath) 78 | $(IDADIR)\plugins\SDK\idasdk70\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include;$(IncludePath) 79 | $(IDADIR)\plugins\ 80 | 81 | 82 | true 83 | build makefile 84 | .dll 85 | $(IDADIR)\plugins\SDK\idasdk70\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include;$(IncludePath) 86 | $(IDADIR)\plugins\SDK\idasdk70\lib\x64_win_vc_64;$(IDADIR)\plugins\SDK\idasdk70\lib\x64_win_qt;$(LibraryPath) 87 | $(ProjectName)64 88 | $(IDADIR)\plugins\ 89 | 90 | 91 | false 92 | .dll 93 | $(IDADIR)\plugins\SDK\idasdk70\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include;$(IncludePath) 94 | $(IDADIR)\plugins\SDK\idasdk70\lib\x64_win_vc_32;$(IDADIR)\plugins\SDK\idasdk70\lib\x64_win_qt;$(LibraryPath) 95 | $(IDADIR)\plugins\ 96 | 97 | 98 | false 99 | .dll 100 | $(ProjectName)64 101 | $(IDADIR)\plugins\ 102 | $(IDADIR)\plugins\SDK\idasdk70\include;$(IDADIR)\plugins\SDK\hexrays_sdk\include;$(IncludePath) 103 | $(IDADIR)\plugins\SDK\idasdk70\lib\x64_win_vc_64;$(IDADIR)\plugins\SDK\idasdk70\lib\x64_win_qt;$(LibraryPath) 104 | 105 | 106 | 107 | 108 | 109 | Level3 110 | Disabled 111 | __NT__;__IDP__;__X64__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 112 | $(IDASDK)\include;$(IDADIR)\plugins\hexrays_sdk\include 113 | MultiThreadedDebug 114 | true 115 | 116 | 117 | Console 118 | true 119 | ida.lib;user32.lib;%(AdditionalDependencies) 120 | /EXPORT:PLUGIN %(AdditionalOptions) 121 | $(IDASDK)\lib\x64_win_vc_32 122 | 123 | 124 | 125 | 126 | 127 | 128 | Level3 129 | Disabled 130 | __NT__;__IDP__;__EA64__;__X64__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 131 | $(IDASDK)\include;$(IDADIR)\plugins\hexrays_sdk\include 132 | MultiThreadedDebugDLL 133 | true 134 | 135 | 136 | Console 137 | true 138 | ida.lib;user32.lib;%(AdditionalDependencies) 139 | /EXPORT:PLUGIN %(AdditionalOptions) 140 | $(IDASDK)\lib\x64_win_vc_64 141 | 142 | 143 | 144 | 145 | Level3 146 | 147 | 148 | Disabled 149 | true 150 | true 151 | __NT__;__IDP__;__X64__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 152 | $(IDASDK)\include;$(IDADIR)\plugins\hexrays_sdk\include 153 | MultiThreadedDLL 154 | false 155 | true 156 | 157 | 158 | Console 159 | true 160 | true 161 | true 162 | ida.lib;user32.lib;%(AdditionalDependencies) 163 | /EXPORT:PLUGIN %(AdditionalOptions) 164 | $(IDASDK)\lib\x64_win_vc_32 165 | 166 | 167 | 168 | 169 | Level3 170 | 171 | 172 | Disabled 173 | true 174 | true 175 | __NT__;__IDP__;__EA64__;__X64__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 176 | $(IDASDK)\include;$(IDADIR)\plugins\hexrays_sdk\include 177 | MultiThreadedDLL 178 | false 179 | true 180 | 181 | 182 | Console 183 | true 184 | true 185 | true 186 | ida.lib;user32.lib;%(AdditionalDependencies) 187 | /EXPORT:PLUGIN %(AdditionalOptions) 188 | $(IDASDK)\lib\x64_win_vc_64 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/HexRaysCodeXplorer.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(IDADIR)\idaq.exe 5 | WindowsLocalDebugger 6 | 7 | 8 | 9 | 10 | $(IDADIR)\ida.exe 11 | WindowsLocalDebugger 12 | 13 | $(IDADIR) 14 | 15 | 16 | $(IDADIR)\idaq64.exe 17 | WindowsLocalDebugger 18 | 19 | 20 | $(IDADIR)\idaq64.exe 21 | WindowsLocalDebugger 22 | 23 | 24 | $(IDADIR)\idaq.exe 25 | WindowsLocalDebugger 26 | 27 | 28 | $(IDADIR) 29 | WindowsLocalDebugger 30 | $(IDADIR)\ida64.exe 31 | 32 | 33 | $(IDADIR) 34 | WindowsLocalDebugger 35 | $(IDADIR)\ida64.exe 36 | 37 | 38 | $(IDADIR) 39 | WindowsLocalDebugger 40 | $(IDADIR)\ida.exe 41 | 42 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/IObjectFormatParser.cpp: -------------------------------------------------------------------------------- 1 | #include "IObjectFormatParser.h" 2 | 3 | 4 | 5 | IObjectFormatParser::~IObjectFormatParser() 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/IObjectFormatParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class IObjectFormatParser 3 | { 4 | public: 5 | virtual ~IObjectFormatParser(); 6 | 7 | virtual void getRttiInfo() = 0; 8 | virtual void clearInfo() = 0; 9 | }; 10 | 11 | extern IObjectFormatParser *objectFormatParser; 12 | 13 | extern bool initObjectFormatParser(); 14 | -------------------------------------------------------------------------------- /src/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 | #if defined (__LINUX__) || defined (__MAC__) 28 | 29 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 30 | 31 | #include 32 | #define UINT uint32_t 33 | #define PUINT uint32_t * 34 | #define CHAR int8_t 35 | #define UCHAR uint8_t 36 | #define TCHAR uint8_t 37 | #define WCHAR wchar_t 38 | #define BOOL bool 39 | #define TRUE true 40 | #define FALSE false 41 | #define LPCSTR const char * 42 | #define LPCTSTR const char * 43 | #define LPSTR char * 44 | #define WORD uint16_t 45 | #define DWORD uint32_t 46 | #define PDWORD DWORD* 47 | #define PVOID void* 48 | #define PINT int* 49 | #define UINT64 uint64_t 50 | 51 | #define ZeroMemory(dst, length) memset(dst, 0, length) 52 | 53 | /* Those are header annotations in Visual Studio and can be safely ignored */ 54 | #define IN 55 | #define OUT 56 | #define __bcount(element) 57 | 58 | /* Ugly but ... */ 59 | #define sprintf_s snprintf 60 | #define _snprintf snprintf 61 | #endif 62 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/MSVCObjectFormatParser.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 "IObjectFormatParser.h" 27 | #include "Common.h" 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 | asize_t 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 bool getName(ea_t typeInfo, qstring& outName); 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 = 0); 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 = 0); 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, asize_t 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(const qstring& mangled, qstring& outStr); 170 | 171 | extern BOOL optionOverwriteComments, optionPlaceStructs; 172 | 173 | class MSVCObjectFormatParser : 174 | public IObjectFormatParser 175 | { 176 | public: 177 | virtual ~MSVCObjectFormatParser(); 178 | 179 | virtual void getRttiInfo(); 180 | virtual void clearInfo(); 181 | }; 182 | 183 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/Makefile.osx: -------------------------------------------------------------------------------- 1 | CXX ?= clang++ 2 | MACSDK=$(shell xcrun --show-sdk-path --sdk macosx) 3 | CXXFLAGS=-m32 -fPIC -shared -D__PLUGIN__ -Wall -Wextra -std=c++11 -isysroot $(MACSDK) -static-libstdc++ -DUSE_DANGEROUS_FUNCTIONS=1 -DUSE_STANDARD_FILE_FUNCTIONS=1 4 | LDFLAGS=-shared -m32 5 | LIBS=-lc -lpthread -ldl -lpro 6 | INCLUDES=-I$(IDA_SDK)/include -I$(IDA_DIR)/plugins/hexrays_sdk/include 7 | 8 | SRCDIR=./ 9 | SRC=$(SRCDIR)CodeXplorer.cpp \ 10 | $(SRCDIR)CtreeGraphBuilder.cpp \ 11 | $(SRCDIR)ObjectExplorer.cpp \ 12 | $(SRCDIR)TypeReconstructor.cpp \ 13 | $(SRCDIR)CtreeExtractor.cpp \ 14 | $(SRCDIR)TypeExtractor.cpp \ 15 | $(SRCDIR)Utility.cpp \ 16 | $(SRCDIR)ObjectFormatMSVC.cpp \ 17 | $(SRCDIR)Debug.cpp 18 | #SRC = $(wildcard src/*.cpp) 19 | #OBJS=$(subst .cpp,.o,$(SRC)) 20 | 21 | all: check-env HexRaysCodeXplorer.pmc HexRaysCodeXplorer.pmc64 22 | 23 | HexRaysCodeXplorer.pmc: $(SRC) 24 | $(CXX) $(LDFLAGS) $(SRC) $(CXXFLAGS) -L. -L$(IDA_DIR) $(INCLUDES) -D__MAC__=1 $(LIBS) -lida -o HexRaysCodeXplorer.pmc 25 | 26 | HexRaysCodeXplorer.pmc64: $(SRC) 27 | $(CXX) $(LDFLAGS) $(SRC) $(CXXFLAGS) -L. -L$(IDA_DIR) $(INCLUDES) -D__MAC__=1 -D__EA64__=1 $(LIBS) -lida64 -o HexRaysCodeXplorer.pmc64 28 | 29 | clean: 30 | rm -f HexRaysCodeXplorer.pmc HexRaysCodeXplorer.pmc64 31 | 32 | install: 33 | cp -f HexRaysCodeXplorer.pmc $(IDA_DIR)/plugins/ 34 | cp -f HexRaysCodeXplorer.pmc64 $(IDA_DIR)/plugins/ 35 | 36 | check-env: 37 | ifndef IDA_SDK 38 | $(error IDA_SDK is undefined) 39 | endif 40 | ifndef IDA_DIR 41 | $(error IDA_DIR is undefined) 42 | endif 43 | ln -f -s $(IDA_SDK)/lib/x86_mac_gcc_32/pro.a libpro.a 44 | 45 | .PHONY: check-env -------------------------------------------------------------------------------- /src/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 "GCCObjectFormatParser.h" 29 | #include "Utility.h" 30 | 31 | #include "Debug.h" 32 | 33 | #include 34 | 35 | #if !defined (__LINUX__) && !defined (__MAC__) 36 | #include 37 | #else 38 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 39 | #endif 40 | 41 | extern plugin_t PLUGIN; 42 | 43 | qvector vtbl_t_list; // list of vtables found in the binary 44 | qvector vtbl_list; // list of string for ObjectExplrer vtables view 45 | 46 | std::map rtti_vftables; 47 | 48 | void free_vtable_lists() { 49 | vtbl_t_list.clear(); 50 | vtbl_list.clear(); 51 | } 52 | 53 | 54 | //--------------------------------------------------------------------------- 55 | // VTBL code parsing 56 | //--------------------------------------------------------------------------- 57 | 58 | bool get_text_disasm(ea_t ea, qstring& rv) { 59 | rv.clear(); 60 | 61 | if (!generate_disasm_line(&rv, ea)) 62 | return false; 63 | 64 | tag_remove(&rv); 65 | 66 | return true; 67 | } 68 | 69 | static bool check_vtable_load_instruction(ea_t ea_code) { 70 | 71 | qstring dism; 72 | if (!get_text_disasm(ea_code, dism)) 73 | return false; 74 | 75 | if (dism.find("mov ") == 0 && dism.find(" offset ") != dism.npos) 76 | return true; 77 | 78 | if (dism.find("lea") == 0) 79 | return true; 80 | 81 | return false; 82 | } 83 | 84 | //--------------------------------------------------------------------------- 85 | // Try to find vtable at the specified address 86 | //--------------------------------------------------------------------------- 87 | static bool get_vtbl_info(ea_t ea_address, VTBL_info_t &vtbl_info) 88 | { 89 | flags_t flags = get_flags(ea_address); 90 | if (has_xref(flags) && has_any_name(flags) && (isEa(flags) || is_unknown(flags))) { 91 | bool is_move_xref = false; 92 | 93 | ea_t ea_code_ref = get_first_dref_to(ea_address); 94 | if(ea_code_ref && ea_code_ref != BADADDR) { 95 | do { 96 | if(is_code(get_flags(ea_code_ref)) && check_vtable_load_instruction(ea_code_ref)) { 97 | is_move_xref = true; 98 | break; 99 | } 100 | 101 | ea_code_ref = get_next_dref_to(ea_address, ea_code_ref); 102 | 103 | } while(ea_code_ref && ea_code_ref != BADADDR); 104 | } 105 | 106 | if(is_move_xref) { 107 | ZeroMemory(&vtbl_info, sizeof(VTBL_info_t)); 108 | 109 | get_ea_name(&vtbl_info.vtbl_name, ea_address); 110 | 111 | ea_t ea_start = vtbl_info.ea_begin = ea_address; 112 | 113 | while(true) { 114 | flags_t index_flags = get_flags(ea_address); 115 | if(!(isEa(index_flags) || is_unknown(index_flags))) 116 | break; 117 | 118 | ea_t ea_index_value = getEa(ea_address); 119 | if(!ea_index_value || ea_index_value == BADADDR) 120 | break; 121 | 122 | if (ea_address != ea_start && has_xref(index_flags)) 123 | break; 124 | 125 | flags_t value_flags = get_flags(ea_index_value); 126 | if(!is_code(value_flags)) { 127 | break; 128 | } else { 129 | if(is_unknown(index_flags)) { 130 | #ifndef __EA64__ 131 | create_dword(ea_address, sizeof(ea_t)); 132 | #else 133 | create_qword(ea_address, sizeof(ea_t)); 134 | #endif 135 | } 136 | } 137 | 138 | ea_address += sizeof(ea_t); 139 | } 140 | 141 | if((vtbl_info.methods = ((ea_address - ea_start) / sizeof(ea_t))) > 0) { 142 | vtbl_info.ea_end = ea_address; 143 | return true; 144 | } 145 | } 146 | } 147 | 148 | return false; 149 | } 150 | 151 | //--------------------------------------------------------------------------- 152 | // Try to find and parse vtable at the specified address 153 | //--------------------------------------------------------------------------- 154 | static void process_vtbl(ea_t &ea_sect) 155 | { 156 | VTBL_info_t vftable_info_t; 157 | // try to parse vtable at this address 158 | if(get_vtbl_info(ea_sect, vftable_info_t)) 159 | { 160 | ea_sect = vftable_info_t.ea_end; 161 | 162 | if(vftable_info_t.methods > 1) { 163 | // check if we have already processed this table 164 | if (rtti_vftables.count(vftable_info_t.ea_begin) == 0) { 165 | vftable_info_t.vtbl_name = get_short_name(vftable_info_t.ea_begin); 166 | 167 | qstring vtbl_info_str; 168 | #ifndef __EA64__ 169 | 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); 170 | #else 171 | 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); 172 | #endif // !#ifndef __EA64__ 173 | 174 | vtbl_list.push_back(vtbl_info_str); 175 | vtbl_t_list.push_back(vftable_info_t); 176 | } 177 | 178 | ea_sect = vftable_info_t.ea_end; 179 | return; 180 | } 181 | } 182 | 183 | // nothing found: increment ea_sect by size of the pointer to continue search at the next location 184 | ea_sect += sizeof(ea_t); 185 | return; 186 | } 187 | 188 | //--------------------------------------------------------------------------- 189 | // Get vtable structure from the list by address 190 | //--------------------------------------------------------------------------- 191 | bool get_vbtbl_by_ea(ea_t vtbl_addr, VTBL_info_t &vtbl) { 192 | bool result = false; 193 | 194 | search_objects(false); 195 | 196 | qvector ::iterator vtbl_iter; 197 | for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) { 198 | if ((*vtbl_iter).ea_begin == vtbl_addr) { 199 | vtbl = *vtbl_iter; 200 | result = true; 201 | break; 202 | } 203 | } 204 | 205 | return result; 206 | } 207 | 208 | //--------------------------------------------------------------------------- 209 | // Create a structurte in IDA local types which represents vtable 210 | //--------------------------------------------------------------------------- 211 | tid_t create_vtbl_struct(ea_t vtbl_addr, ea_t vtbl_addr_end, const qstring& vtbl_name, uval_t idx, unsigned int* vtbl_len) 212 | { 213 | qstring struc_name = vtbl_name; 214 | struc_name += "::vtable"; 215 | tid_t id = add_struc(BADADDR, struc_name.c_str()); 216 | 217 | if (id == BADADDR) { 218 | if (!ask_str(&struc_name, HIST_IDENT, "Default name %s not correct. Enter other structure name: ", struc_name.c_str())) 219 | return BADNODE; 220 | id = add_struc(BADADDR, struc_name.c_str()); 221 | if (id == BADADDR) 222 | { 223 | msg("failed to add struct: %s\n", struc_name.c_str()); 224 | return BADNODE; 225 | } 226 | set_struc_cmt(id, vtbl_name.c_str(), true); 227 | } 228 | 229 | struc_t* new_struc = get_struc(id); 230 | if (!new_struc) 231 | return BADNODE; 232 | 233 | ea_t ea = vtbl_addr; 234 | ea_t offset = 0; 235 | 236 | while (ea < vtbl_addr_end) { 237 | offset = ea - vtbl_addr; 238 | qstring method_name; 239 | ea_t method_ea = getEa(ea); 240 | 241 | if (ph.id == PLFM_ARM) 242 | { 243 | method_ea &= (ea_t)-2; 244 | } 245 | 246 | if (method_ea == 0) 247 | { 248 | ea = ea + sizeof(ea_t); 249 | continue; 250 | } 251 | if (!is_mapped(method_ea)) 252 | break; 253 | 254 | flags_t method_flags = get_flags(method_ea); 255 | const char* struc_member_name = nullptr; 256 | if (is_func(method_flags)) { 257 | method_name = get_short_name(method_ea); 258 | 259 | if (!method_name.empty()) { 260 | 261 | size_t bp = method_name.find('(', 0); 262 | 263 | if (bp != qstring::npos) 264 | method_name = method_name.substr(0, bp); 265 | 266 | struc_member_name = method_name.c_str(); 267 | } 268 | } 269 | #ifndef __EA64__ 270 | add_struc_member(new_struc, NULL, offset, dword_flag(), NULL, sizeof(ea_t)); 271 | #else 272 | add_struc_member(new_struc, NULL, offset, qword_flag(), NULL, sizeof(ea_t)); 273 | #endif 274 | if (struc_member_name) { 275 | set_member_cmt(get_member(new_struc, offset), get_short_name(method_ea).c_str(), true); 276 | 277 | if (!set_member_name(new_struc, offset, struc_member_name)) { 278 | 279 | method_name.cat_sprnt("_%X", offset); 280 | struc_member_name = method_name.c_str(); 281 | 282 | if (!set_member_name(new_struc, offset, struc_member_name)) { 283 | get_ea_name(&method_name, method_ea); 284 | set_member_name(new_struc, offset, method_name.c_str()); 285 | } 286 | } 287 | } 288 | 289 | ea = ea + sizeof(ea_t); 290 | flags_t ea_flags = get_flags(ea); 291 | 292 | if (has_any_name(ea_flags)) 293 | break; 294 | } 295 | 296 | return id; 297 | } 298 | 299 | 300 | void find_vtables_rtti() 301 | { 302 | logmsg(DEBUG, "\nprocess_rtti()\n"); 303 | 304 | if (!objectFormatParser && !initObjectFormatParser()) 305 | return; 306 | 307 | // get rtti_vftables map using rtti data 308 | objectFormatParser->getRttiInfo(); 309 | 310 | // store this inormation in the lists 311 | for (std::map::iterator it = rtti_vftables.begin(); it != rtti_vftables.end(); it++) { 312 | VTBL_info_t vftable_info_t; 313 | vftable_info_t.ea_begin = it->second.ea_begin; 314 | vftable_info_t.ea_end = it->second.ea_end; 315 | vftable_info_t.methods = it->second.methods; 316 | vftable_info_t.vtbl_name = it->second.vtbl_name; 317 | 318 | qstring vtbl_info_str; 319 | 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); 320 | 321 | vtbl_list.push_back(vtbl_info_str); 322 | vtbl_t_list.push_back(vftable_info_t); 323 | } 324 | } 325 | 326 | 327 | //--------------------------------------------------------------------------- 328 | // Find vtables in the binary 329 | //--------------------------------------------------------------------------- 330 | void find_vtables() 331 | { 332 | // set of the processed segments 333 | std::set segSet; 334 | 335 | // start with .rdata section 336 | logmsg(DEBUG, "search_objects() - going for .rdata\n"); 337 | if (segment_t *seg = get_segm_by_name(".rdata")) { 338 | logmsg(DEBUG, "search_objects() - .rdata exist\n"); 339 | 340 | segSet.insert(seg); 341 | 342 | ea_t ea_text = seg->start_ea; 343 | while (ea_text <= seg->end_ea) 344 | process_vtbl(ea_text); 345 | 346 | } else { 347 | logmsg(DEBUG, "search_objects() - .rdata does not exist\n"); 348 | } 349 | 350 | // look also at .data section 351 | logmsg(DEBUG, "search_objects() - going for .data\n"); 352 | int segCount = get_segm_qty(); 353 | qstring segm_name; 354 | 355 | for (int i = 0; i < segCount; i++) { 356 | segment_t *seg = getnseg(i); 357 | if (!seg || seg->type != SEG_DATA) 358 | continue; 359 | 360 | if (segSet.find(seg) == segSet.end()) 361 | { 362 | if (get_segm_name(&segm_name, seg) > 0 && segm_name == ".data") 363 | { 364 | logmsg(DEBUG, "search_objects() - .data exist\n"); 365 | segSet.insert(seg); 366 | ea_t ea_text = seg->start_ea; 367 | while (ea_text <= seg->end_ea) 368 | process_vtbl(ea_text); 369 | } 370 | } 371 | } 372 | 373 | // If still none found, try any remaining data type segments 374 | if (vtbl_t_list.empty()) 375 | { 376 | logmsg(DEBUG, "search_objects() - going for other data sections\n"); 377 | for (int i = 0; i < segCount; i++) 378 | { 379 | segment_t *seg = getnseg(i); 380 | if (!seg || seg->type != SEG_DATA) 381 | continue; 382 | 383 | if (segSet.find(seg) == segSet.end()) 384 | { 385 | segSet.insert(seg); 386 | ea_t ea_text = seg->start_ea; 387 | while (ea_text <= seg->end_ea) 388 | process_vtbl(ea_text); 389 | } 390 | } 391 | } 392 | } 393 | 394 | 395 | //--------------------------------------------------------------------------- 396 | // Handle VTBL & RTTI 397 | //--------------------------------------------------------------------------- 398 | 399 | bool bScaned = false; 400 | 401 | void search_objects(bool bForce) 402 | { 403 | if (!bScaned || bForce) { 404 | logmsg(DEBUG, "search_objects()"); 405 | 406 | // free previously found objects 407 | free_vtable_lists(); 408 | 409 | // first search vtables using rtti information 410 | find_vtables_rtti(); 411 | 412 | // find all the other vtables 413 | find_vtables(); 414 | 415 | bScaned = true; 416 | } 417 | } 418 | 419 | 420 | //--------------------------------------------------------------------------- 421 | // IDA Custom View Window Initialization 422 | //--------------------------------------------------------------------------- 423 | 424 | static int current_line_pos = 0; 425 | 426 | bool idaapi make_vtbl_struct_cb() 427 | { 428 | VTBL_info_t vtbl_t = vtbl_t_list[current_line_pos]; 429 | tid_t id = add_struc(BADADDR, vtbl_t.vtbl_name.c_str()); 430 | 431 | create_vtbl_struct(vtbl_t.ea_begin, vtbl_t.ea_end, vtbl_t.vtbl_name, id); 432 | 433 | return true; 434 | } 435 | 436 | 437 | 438 | // Popup window with VTBL XREFS 439 | qvector xref_list; 440 | qvector xref_addr; 441 | static void get_xrefs_to_vtbl() 442 | { 443 | ea_t cur_vt_ea = vtbl_t_list[current_line_pos].ea_begin; 444 | for (ea_t addr = get_first_dref_to(cur_vt_ea); addr != BADADDR; addr = get_next_dref_to(cur_vt_ea, addr)) 445 | { 446 | qstring name; 447 | get_func_name(&name, addr); 448 | 449 | xref_addr.push_back(addr); 450 | 451 | qstring tmp; 452 | tmp.cat_sprnt(" 0x%x: %s", addr, name.c_str()); 453 | xref_list.push_back(tmp); 454 | } 455 | } 456 | 457 | 458 | static bool idaapi ct_vtbl_xrefs_window_dblclick(TWidget *v, int shift, void *ud) 459 | { 460 | int x, y; 461 | place_t *place = get_custom_viewer_place(v, true, &x, &y); 462 | simpleline_place_t *spl = (simpleline_place_t *)place; 463 | int line_num = spl->n; 464 | 465 | if (line_num < 0 || line_num >= static_cast(xref_addr.size())) 466 | return false; 467 | 468 | ea_t cur_xref_ea = xref_addr[line_num]; 469 | 470 | return jumpto(cur_xref_ea); 471 | } 472 | 473 | 474 | bool idaapi show_vtbl_xrefs_window_cb() 475 | { 476 | get_xrefs_to_vtbl(); 477 | 478 | if (xref_list.empty()) 479 | { 480 | warning("ObjectExplorer not found any xrefs here ...\n"); 481 | logmsg(DEBUG, "ObjectExplorer not found any xrefs here ...\n"); 482 | 483 | return false; 484 | } 485 | 486 | TWidget *widget = create_empty_widget(vtbl_t_list[current_line_pos].vtbl_name.c_str()); 487 | 488 | object_explorer_info_t *si = new object_explorer_info_t(widget); 489 | 490 | for (const qstring& xref : xref_list) 491 | si->sv.push_back(simpleline_t(xref)); 492 | 493 | simpleline_place_t s1; 494 | simpleline_place_t s2(static_cast(si->sv.size()) - 1); 495 | si->cv = create_custom_viewer("", &s1, &s2, &s1, nullptr, &si->sv, nullptr, nullptr, widget); 496 | si->codeview = create_code_viewer(si->cv, CDVF_STATUSBAR, widget); 497 | set_custom_viewer_handler(si->cv, CVH_DBLCLICK, (void *)ct_vtbl_xrefs_window_dblclick); 498 | #if (defined(IDA_SDK_VERSION) && IDA_SDK_VERSION == 720) 499 | display_widget(widget, WOPN_RESTORE); 500 | #else 501 | display_widget(widget, WOPN_ONTOP | WOPN_RESTORE); 502 | #endif 503 | 504 | return true; 505 | } 506 | 507 | 508 | ////////////////////////////////////////////////////////////////////////// 509 | 510 | 511 | static bool idaapi ct_object_explorer_keyboard(TWidget * /*v*/, int key, int shift, void *ud) 512 | { 513 | if (shift == 0) 514 | { 515 | object_explorer_info_t *si = (object_explorer_info_t *)ud; 516 | switch (key) 517 | { 518 | case IK_ESCAPE: 519 | close_widget(si->widget, WOPN_CLOSED_BY_ESC); 520 | return true; 521 | 522 | case 83: // S 523 | make_vtbl_struct_cb(); 524 | return true; 525 | 526 | case 88: // X 527 | show_vtbl_xrefs_window_cb(); 528 | return true; 529 | } 530 | } 531 | return false; 532 | } 533 | 534 | 535 | static bool idaapi ct_object_explorer_dblclick(TWidget *v, int shift, void *ud) 536 | { 537 | int x, y; 538 | place_t *place = get_custom_viewer_place(v, true, &x, &y); 539 | simpleline_place_t *spl = (simpleline_place_t *)place; 540 | int line_num = spl->n; 541 | 542 | if (line_num < 0 || line_num >= static_cast(vtbl_t_list.size())) 543 | return false; 544 | 545 | ea_t cur_vt_ea = vtbl_t_list[line_num].ea_begin; 546 | 547 | return jumpto(cur_vt_ea); 548 | } 549 | 550 | 551 | static qstring get_vtbl_hint(int line_num) 552 | { 553 | current_line_pos = line_num; 554 | qstring tag_lines; 555 | 556 | if (is_mapped(vtbl_t_list[line_num].ea_begin)) 557 | { 558 | int flags = calc_default_idaplace_flags(); 559 | linearray_t ln(&flags); 560 | 561 | idaplace_t here; 562 | here.ea = vtbl_t_list[line_num].ea_begin; 563 | here.lnnum = 0; 564 | ln.set_place(&here); 565 | 566 | int used = 0; 567 | for (int i = 0; i < ln.get_linecnt(); i++) 568 | { 569 | qstring line = *ln.down(); 570 | tag_remove(&line); 571 | 572 | tag_lines.cat_sprnt((COLSTR(SCOLOR_INV"%s\n", SCOLOR_DREF)), line.c_str()); 573 | used++; 574 | int n = qmin(ln.get_linecnt(), 20); 575 | used += n; 576 | for (int j = 0; j < n; ++j) 577 | tag_lines.cat_sprnt("%s\n", ln.down()->c_str()); 578 | } 579 | } 580 | return tag_lines; 581 | } 582 | 583 | 584 | ssize_t idaapi ui_object_explorer_callback(void *ud, int code, va_list va) 585 | { 586 | object_explorer_info_t *si = (object_explorer_info_t *)ud; 587 | switch (code) 588 | { 589 | case ui_get_custom_viewer_hint: 590 | { 591 | qstring &hint = *va_arg(va, qstring *); 592 | TWidget *viewer = va_arg(va, TWidget *); 593 | place_t *place = va_arg(va, place_t *); 594 | int *important_lines = va_arg(va, int *); 595 | 596 | if (si->cv == viewer) 597 | { 598 | if ( place == NULL ) 599 | return 0; 600 | 601 | simpleline_place_t *spl = (simpleline_place_t *)place; 602 | hint = get_vtbl_hint (spl->n); 603 | *important_lines = 20; 604 | return 1; 605 | } 606 | break; 607 | } 608 | case ui_widget_invisible: 609 | { 610 | TWidget *f = va_arg(va, TWidget *); 611 | if ( f == si->widget ) 612 | { 613 | delete si; 614 | unhook_from_notification_point(HT_UI, ui_object_explorer_callback, NULL); 615 | } 616 | } 617 | break; 618 | 619 | case ui_populating_widget_popup: 620 | { 621 | TWidget* viewer = va_arg(va, TWidget *); 622 | TPopupMenu* popup = va_arg(va, TPopupMenu *); 623 | if (si->widget == viewer || si->cv == viewer) 624 | { 625 | attach_action_to_popup(viewer, popup, "codexplorer::make_vtbl_struct"); 626 | attach_action_to_popup(viewer, popup, "codexplorer::show_vtbl_xrefs_window"); 627 | } 628 | } 629 | break; 630 | } 631 | return 0; 632 | } 633 | 634 | struct HandlerCBAction_t : public action_handler_t 635 | { 636 | typedef std::function handler_t; 637 | 638 | handler_t handler_; 639 | 640 | HandlerCBAction_t(handler_t handler) 641 | : handler_(handler) 642 | {} 643 | 644 | virtual int idaapi activate(action_activation_ctx_t* ctx) 645 | { 646 | return handler_() ? 1 : 0; 647 | } 648 | 649 | virtual action_state_t idaapi update(action_update_ctx_t*) 650 | { 651 | return AST_ENABLE_ALWAYS; 652 | } 653 | }; 654 | 655 | static HandlerCBAction_t kMakeVTBLStructActionHandler{ make_vtbl_struct_cb }; 656 | static HandlerCBAction_t kShowVTBLXrefsWindowActionHandler{ show_vtbl_xrefs_window_cb }; 657 | 658 | static const action_desc_t kMakeVTBLStrucActionDesc = ACTION_DESC_LITERAL("codexplorer::make_vtbl_struct", 659 | "Make VTBL_Struct", &kMakeVTBLStructActionHandler, "S", NULL, -1); 660 | static const action_desc_t kShowVTBLXrefsWindowActionDesc = ACTION_DESC_LITERAL("codexplorer::show_vtbl_xrefs_window", 661 | "Show all XREFS to VTBL", &kShowVTBLXrefsWindowActionHandler, "X", NULL, -1); 662 | 663 | void object_explorer_form_init() 664 | { 665 | if (vtbl_list.empty() || vtbl_t_list.empty()) 666 | { 667 | warning("ObjectExplorer not found any virtual tables here ...\n"); 668 | logmsg(DEBUG, "ObjectExplorer not found any virtual tables here ...\n"); 669 | return; 670 | } 671 | 672 | TWidget *widget = find_widget("Object Explorer"); 673 | if (widget) 674 | { 675 | warning("Object Explorer window already open. Switching to it.\n"); 676 | logmsg(DEBUG, "Object Explorer window already open. Switching to it.\n"); 677 | activate_widget(widget, true); 678 | return; 679 | } 680 | 681 | widget = create_empty_widget("Object Explorer"); 682 | static bool actionsInitialized = false; 683 | if (!actionsInitialized) 684 | { 685 | actionsInitialized = true; 686 | register_action(kMakeVTBLStrucActionDesc); 687 | register_action(kShowVTBLXrefsWindowActionDesc); 688 | } 689 | object_explorer_info_t *si = new object_explorer_info_t(widget); 690 | 691 | qvector ::iterator vtbl_iter; 692 | for (vtbl_iter = vtbl_list.begin(); vtbl_iter != vtbl_list.end(); vtbl_iter++) 693 | si->sv.push_back(simpleline_t(*vtbl_iter)); 694 | 695 | simpleline_place_t s1; 696 | simpleline_place_t s2(static_cast(si->sv.size()) - 1); 697 | si->cv = create_custom_viewer("", &s1, &s2, &s1, nullptr, &si->sv, nullptr, nullptr, widget); 698 | si->codeview = create_code_viewer(si->cv, CDVF_STATUSBAR, widget); 699 | 700 | custom_viewer_handlers_t cvh = custom_viewer_handlers_t(); 701 | cvh.keyboard = ct_object_explorer_keyboard; 702 | cvh.dblclick = ct_object_explorer_dblclick; 703 | set_custom_viewer_handlers(si->cv, &cvh, si); 704 | 705 | hook_to_notification_point(HT_UI, ui_object_explorer_callback, si); 706 | #if (defined(IDA_SDK_VERSION) && IDA_SDK_VERSION == 720) 707 | display_widget(widget, WOPN_TAB | WOPN_RESTORE); 708 | #else 709 | display_widget(widget, WOPN_TAB | WOPN_MENU | WOPN_RESTORE); 710 | #endif 711 | } 712 | -------------------------------------------------------------------------------- /src/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 Form Init 30 | struct object_explorer_info_t 31 | { 32 | TWidget *widget; 33 | TWidget *cv; 34 | TWidget *codeview; 35 | strvec_t sv; 36 | object_explorer_info_t(TWidget *f) : widget(f), cv(nullptr), codeview(nullptr) {} 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 | asize_t methods; 49 | }; 50 | 51 | 52 | extern qvector vtbl_list; 53 | extern qvector ::iterator vtbl_iter; 54 | 55 | 56 | 57 | inline BOOL is_valid_name(LPCSTR name){ return(*((PDWORD) name) == 0x375F3F3F /*"??_7"*/); } 58 | //void parse_vft_members(LPCTSTR name, ea_t ea_start, ea_t ea_end); 59 | 60 | void search_objects(bool bForce = true); 61 | 62 | 63 | template BOOL verify_32_t(ea_t ea_ptr, T &rvalue) 64 | { 65 | if (get_flags(ea_ptr)) 66 | { 67 | rvalue = (T) get_32bit(ea_ptr); 68 | return TRUE; 69 | } 70 | 71 | return FALSE; 72 | } 73 | 74 | 75 | // RTTI 76 | struct RTTI_info_t 77 | { 78 | PVOID vftable; 79 | PVOID m_data; 80 | char m_d_name[MAXSTR]; // mangled name (prefix: .?AV=classes, .?AU=structs) 81 | }; 82 | 83 | //static BOOL is_valid_rtti(RTTI_info_t *pIDA); 84 | //static LPSTR get_name(IN RTTI_info_t *pIDA, OUT LPSTR pszBufer, int iSize); 85 | 86 | // returns TRUE if mangled name is a unknown type name 87 | static inline BOOL is_type_name(LPCSTR pszName){ return((*((PUINT)pszName) & 0xFFFFFF) == 0x413F2E /*".?A"*/); } 88 | 89 | 90 | struct PMD 91 | { 92 | int mdisp; // member 93 | int pdisp; // vftable 94 | int vdisp; // place inside vftable 95 | }; 96 | 97 | 98 | struct RTTIBaseClassDescriptor 99 | { 100 | RTTI_info_t *pTypeDescriptor; // type descriptor of the class 101 | UINT numContainedBases; // number of nested classes 102 | PMD pmd; // pointer-to-member displacement info 103 | UINT attributes; // flags (usually 0) 104 | }; 105 | 106 | 107 | struct RTTIClassHierarchyDescriptor 108 | { 109 | UINT signature; // always zero? 110 | UINT attributes; // bit 0 set = multiple inheritance, bit 1 set = virtual inheritance 111 | UINT numBaseClasses; // number of classes in pBaseClassArray 112 | RTTIBaseClassDescriptor **pBaseClassArray; 113 | }; 114 | 115 | const UINT CHDF_MULTIPLE = (1 << 0); 116 | const UINT CHDF_VIRTUAL = (1 << 1); 117 | 118 | 119 | struct RTTICompleteObjectLocator 120 | { 121 | UINT signature; // always zero ? 122 | UINT offset; // offset of this vftable in the complete class 123 | UINT cdOffset; // constructor displacement offset 124 | RTTI_info_t *pTypeDescriptor; // TypeDescriptor of the complete class 125 | RTTIClassHierarchyDescriptor *pClassDescriptor; // 10 Describes inheritance hierarchy 126 | }; 127 | 128 | bool get_text_disasm(ea_t ea, qstring& rv); 129 | 130 | bool get_vbtbl_by_ea(ea_t vtbl_addr, VTBL_info_t &vtbl); 131 | 132 | tid_t create_vtbl_struct(ea_t vtbl_addr, ea_t vtbl_addr_end, const qstring& vtbl_name, uval_t idx, unsigned int* vtbl_len = NULL); 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/PropertySheet.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | m:\!re\IDA71_x64 6 | m:\!re\idasdk71 7 | 8 | 9 | 10 | 11 | 12 | $(IDADIR) 13 | true 14 | 15 | 16 | $(IDASDK) 17 | true 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/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 | 31 | #include "Debug.h" 32 | #include "Utility.h" 33 | 34 | #if defined (__LINUX__) || defined (__MAC__) 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 | qstring vtbl_name; 46 | qstring var_name; 47 | bool bFound; 48 | 49 | int idaapi visit_expr(cexpr_t *e); 50 | 51 | obj_fint_t() 52 | : bFound(false) 53 | {} 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 | return 0; 62 | 63 | // get the variable name 64 | qstring s; 65 | print1wrapper(e, &s, NULL); 66 | tag_remove(&s); 67 | 68 | // check for the target variable 69 | if (s != vtbl_name) 70 | return 0; 71 | 72 | size_t max_parents = 3; 73 | if (parents.size() < max_parents) { 74 | max_parents = parents.size(); 75 | } 76 | 77 | for (size_t i = 1; i <= max_parents; i++) { 78 | citem_t *parent = parents.back(); 79 | if (parent->is_expr() && parent->op == cot_asg) { 80 | cexpr_t * target_expr = (cexpr_t *)parent; 81 | 82 | while (target_expr->x != NULL && target_expr->op != cot_var && target_expr->op != cot_obj) 83 | target_expr = target_expr->x; 84 | 85 | if (target_expr->op == cot_var) { 86 | s.clear(); 87 | print1wrapper(target_expr, &s, NULL); 88 | tag_remove(&s); 89 | 90 | var_name = s; 91 | bFound = true; 92 | break; 93 | } 94 | } 95 | } 96 | 97 | return 0; 98 | } 99 | 100 | void idaapi reset_pointer_type(cfuncptr_t cfunc, const qstring &var_name) { 101 | lvars_t * locals = cfunc->get_lvars(); 102 | if (locals == NULL) 103 | return; 104 | 105 | qvector::iterator locals_iter; 106 | 107 | for (locals_iter = locals->begin(); locals_iter != locals->end(); locals_iter++) { 108 | if (var_name != locals_iter->name) 109 | continue; 110 | 111 | tinfo_t int_type = tinfo_t(BT_INT32); 112 | locals_iter->set_final_lvar_type(int_type); 113 | locals_iter->set_user_type(); 114 | cfunc->build_c_tree(); 115 | break; 116 | } 117 | } 118 | 119 | bool idaapi find_var(void *ud) 120 | { 121 | vdui_t &vu = *(vdui_t *)ud; 122 | 123 | // Determine the ctree item to highlight 124 | vu.get_current_item(USE_KEYBOARD); 125 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 126 | 127 | // highlight == NULL might happen if one chooses variable at local variables declaration statement 128 | if (!highlight) 129 | { 130 | logmsg(DEBUG, "Invalid item is choosen"); 131 | return false; 132 | } 133 | 134 | // the chosen item must be an expression and of 'variable' type 135 | if (highlight->is_expr() && (highlight->op == cot_obj)) 136 | { 137 | cexpr_t *highl_expr = (cexpr_t *)highlight; 138 | 139 | qstring s; 140 | print1wrapper(highlight, &s, NULL); 141 | tag_remove(&s); 142 | 143 | // initialize type rebuilder 144 | obj_fint_t obj_find; 145 | obj_find.vtbl_name = s; 146 | 147 | // traverse the ctree structure 148 | obj_find.apply_to(&vu.cfunc->body, NULL); 149 | 150 | if (obj_find.bFound) { 151 | logmsg(DEBUG, (obj_find.var_name + "\n").c_str()); 152 | reset_pointer_type(vu.cfunc, obj_find.var_name); 153 | 154 | vu.refresh_ctext(); 155 | } else { 156 | warning("Failed to find variable...\n"); 157 | logmsg(DEBUG, "Failed to find variable...\n"); 158 | } 159 | } 160 | 161 | return true; 162 | } 163 | 164 | bool idaapi find_var(cfuncptr_t cfunc, const qstring& vtbl_name, qstring &var_name) 165 | { 166 | var_name.clear(); 167 | 168 | obj_fint_t obj_find; 169 | obj_find.vtbl_name = vtbl_name; 170 | 171 | if (obj_find.vtbl_name.find("const ") == 0) 172 | obj_find.vtbl_name.remove(0, 6); 173 | 174 | // traverse the ctree structure 175 | obj_find.apply_to(&cfunc->body, NULL); 176 | 177 | if (!obj_find.bFound) { 178 | logmsg(DEBUG, "Failed to find variable...\n"); 179 | return false; 180 | } 181 | 182 | var_name = obj_find.var_name; 183 | reset_pointer_type(cfunc, var_name); 184 | return true; 185 | } 186 | 187 | tid_t idaapi merge_types(const qvector& types_to_merge, const qstring& type_name) { 188 | tid_t struct_type_id = BADADDR; 189 | 190 | if (types_to_merge.empty()) 191 | return struct_type_id; 192 | 193 | std::set offsets; 194 | 195 | struct_type_id = add_struc(BADADDR, type_name.c_str()); 196 | if (struct_type_id == BADADDR) 197 | return struct_type_id; 198 | 199 | struc_t * struc = get_struc(struct_type_id); 200 | if (!struc) 201 | return struct_type_id; 202 | 203 | for (auto types_iter = types_to_merge.begin(), end = types_to_merge.end(); types_iter != end; ++types_iter) { 204 | struc_t * struc_type = get_struc(get_struc_id(types_iter->c_str())); 205 | if (!struc_type) 206 | continue; 207 | 208 | // enumerate members 209 | for ( ea_t offset = get_struc_first_offset(struc_type) ; offset != BADADDR ; offset = get_struc_next_offset(struc_type, offset)) { 210 | member_t * member_info = get_member(struc_type, offset); 211 | if (!member_info) 212 | continue; 213 | 214 | if (offsets.count(member_info->soff) == 0) { 215 | qstring member_name = get_member_name(member_info->id); 216 | asize_t member_size = get_member_size(member_info); 217 | 218 | if (member_name.find("vftbl_", 0) != -1) { 219 | tinfo_t tif; 220 | if (get_member_tinfo(&tif, member_info)) { 221 | add_struc_member(struc, member_name.c_str(), member_info->soff, dword_flag(), NULL, member_size); 222 | if (member_t * membr = get_member(struc, member_info->soff)) { 223 | set_member_tinfo(struc, membr, 0, tif, SET_MEMTI_COMPATIBLE); 224 | } 225 | } 226 | } 227 | else { 228 | add_struc_member(struc, member_name.c_str(), member_info->soff, member_info->flag, NULL, member_size); 229 | } 230 | 231 | offsets.insert(member_info->soff); 232 | } 233 | } 234 | } 235 | 236 | return struct_type_id; 237 | } 238 | 239 | void get_struct_key(struc_t * struc_type, const VTBL_info_t& vtbl_info, qstring &file_entry_key, bool &filtered, const std::map& vtbl_map) { 240 | qstring sub_key; 241 | qstring vtables_sub_key; 242 | int vftbales_num = 0; 243 | int members_count = 0; 244 | for ( ea_t offset = get_struc_first_offset(struc_type) ; offset != BADADDR ; offset = get_struc_next_offset(struc_type, offset)) { 245 | member_t * member_info = get_member(struc_type, offset); 246 | if (member_info != NULL) { 247 | qstring member_name = get_member_name(member_info->id); 248 | asize_t member_size = get_member_size(member_info); 249 | 250 | if (member_name.find("vftbl_", 0) != -1) { 251 | 252 | ea_t vtable_addr = 0; 253 | int i; 254 | 255 | if (qsscanf(member_name.c_str(), "vftbl_%d_%" FMT_EA "x", &i, &vtable_addr) > 0) { 256 | if (vtbl_map.count(vtable_addr) != 0) { 257 | vtables_sub_key.cat_sprnt("_%d", vtbl_map.at(vtable_addr).methods); 258 | } 259 | } 260 | 261 | vftbales_num ++; 262 | } 263 | 264 | sub_key.cat_sprnt("_%d", member_size); 265 | 266 | members_count ++; 267 | } 268 | } 269 | file_entry_key.sprnt("t_%d_%d", vtbl_info.methods, vftbales_num); 270 | file_entry_key += vtables_sub_key; 271 | file_entry_key += sub_key; 272 | 273 | if (members_count < STRUCT_DUMP_MIN_MEMBER_COUNT) 274 | filtered = true; 275 | } 276 | 277 | void idaapi dump_type_info(int file_id, const VTBL_info_t& vtbl_info, const qstring& type_name, const std::map& vtbl_map) { 278 | struc_t * struc_type = get_struc(get_struc_id(type_name.c_str())); 279 | if (!struc_type) 280 | return; 281 | 282 | qstring file_entry_key; 283 | qstring key_hash; 284 | bool filtered = false; 285 | 286 | get_struct_key(struc_type, vtbl_info, file_entry_key, filtered, vtbl_map); 287 | get_hash_of_string(file_entry_key, key_hash); 288 | 289 | if (filtered) 290 | return; 291 | 292 | qstring file_entry_val; 293 | tinfo_t new_type = create_typedef(type_name.c_str()); 294 | 295 | if (new_type.is_correct() && new_type.print(&file_entry_val, NULL, PRTYPE_DEF | PRTYPE_1LINE)) { 296 | qstring line; 297 | 298 | line = key_hash + ";" + file_entry_key + ";"; 299 | line.cat_sprnt("%a;", vtbl_info.ea_begin); 300 | line += file_entry_val + ";"; 301 | 302 | if (rtti_vftables.count(vtbl_info.ea_begin) != 0) { 303 | VTBL_info_t vi = rtti_vftables[vtbl_info.ea_begin]; 304 | line += vi.vtbl_name; 305 | } 306 | line.rtrim(); 307 | line += "\r\n"; 308 | qwrite(file_id, line.c_str(), line.length()); 309 | } 310 | } 311 | 312 | bool idaapi check_subtype(VTBL_info_t vtbl_info, qstring subtype_name) { 313 | qstring search_str; 314 | search_str.sprnt("_%a", vtbl_info.ea_begin); 315 | 316 | struc_t * struc_type = get_struc(get_struc_id(subtype_name.c_str())); 317 | if (!struc_type) 318 | return false; 319 | 320 | // enumerate members 321 | for ( ea_t offset = get_struc_first_offset(struc_type) ; offset != BADADDR ; offset = get_struc_next_offset(struc_type, offset)) { 322 | member_t * member_info = get_member(struc_type, offset); 323 | if (!member_info) 324 | continue; 325 | 326 | qstring member_name = get_member_name(member_info->id); 327 | if (member_name.find(search_str, 0) != member_name.npos) 328 | return true; 329 | } 330 | 331 | return false; 332 | } 333 | 334 | bool idaapi extract_all_types(void *ud) 335 | { 336 | logmsg(DEBUG, "extract_types()\n"); 337 | 338 | // find vtables in the binary 339 | search_objects(false); 340 | 341 | qvector ::iterator vtbl_iter; 342 | 343 | std::map vtbl_map; 344 | for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) 345 | vtbl_map[(*vtbl_iter).ea_begin] = (*vtbl_iter); 346 | 347 | int file_id = create_open_file("types.txt"); 348 | if (file_id == -1) 349 | { 350 | logmsg(ERROR, "Failed to open file for dumping types.txt\r\n"); 351 | return false; 352 | } 353 | 354 | int struct_no = 0; 355 | 356 | for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) { 357 | qstring info_msg; 358 | info_msg.cat_sprnt("Processing vtable %s\n", (*vtbl_iter).vtbl_name.c_str()); 359 | logmsg(DEBUG, info_msg.c_str()); 360 | 361 | qstring type_name; 362 | type_name.sprnt("struc_2_%d", struct_no); 363 | 364 | ea_t cur_vt_ea = (*vtbl_iter).ea_begin; 365 | int struct_subno = 0; 366 | 367 | qvector types_to_merge; 368 | for (ea_t addr = get_first_dref_to(cur_vt_ea); addr != BADADDR; addr = get_next_dref_to(cur_vt_ea, addr)) { 369 | qstring name; 370 | if (get_func_name(&name, addr) <= 0) 371 | continue; 372 | 373 | qstring info_msg1; 374 | info_msg1.cat_sprnt("\t%s\n", name.c_str()); 375 | logmsg(DEBUG, info_msg1.c_str()); 376 | 377 | func_t *pfn = get_func(addr); 378 | if (!pfn) 379 | continue; 380 | 381 | hexrays_failure_t hf; 382 | cfuncptr_t cfunc = decompile(pfn, &hf); 383 | if (cfunc != NULL) { 384 | qstring var_name; 385 | info_msg.clear(); 386 | 387 | if (find_var(cfunc, (*vtbl_iter).vtbl_name, var_name)) { 388 | info_msg.cat_sprnt(" : %s\n", var_name.c_str()); 389 | logmsg(DEBUG, info_msg.c_str()); 390 | 391 | qstring sub_type_name = type_name; 392 | sub_type_name.cat_sprnt("_%d", struct_subno); 393 | struct_subno++; 394 | 395 | if (reconstruct_type(cfunc, var_name, sub_type_name)) { 396 | if (check_subtype((*vtbl_iter), sub_type_name)) { 397 | types_to_merge.push_back(sub_type_name); 398 | } 399 | } 400 | } 401 | else { 402 | info_msg.cat_sprnt(" : none\n"); 403 | logmsg(DEBUG, info_msg.c_str()); 404 | } 405 | } 406 | } 407 | 408 | struct_no++; 409 | 410 | merge_types(types_to_merge, type_name); 411 | dump_type_info(file_id, (*vtbl_iter), type_name, vtbl_map); 412 | } 413 | 414 | qclose(file_id); 415 | return true; 416 | } 417 | -------------------------------------------------------------------------------- /src/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, const qstring& vtbl_name, qstring &var_name); 36 | 37 | tid_t idaapi merge_types(const qvector& types_to_merge, const qstring& type_name); 38 | 39 | #endif -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/TypeReconstructor.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2016 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 | #include "Utility.h" 31 | 32 | #if !defined (__LINUX__) && !defined (__MAC__) 33 | #include 34 | #else 35 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 36 | #endif 37 | 38 | /* 39 | Representation of the reconstructed type 40 | */ 41 | struct type_reference { 42 | tinfo_t type; 43 | 44 | // offset of the referenced field by the helper, if any 45 | int hlpr_off; 46 | 47 | // size of the referenced field by the helper, if any 48 | int hlpr_size; 49 | 50 | // offset of the field after all checks 51 | int final_off; 52 | 53 | // size of the field after all checks 54 | int final_size; 55 | 56 | void idaapi init(cexpr_t *e); 57 | 58 | void idaapi update_hlpr(int off, int num); 59 | 60 | void idaapi update_type(cexpr_t *e); 61 | 62 | int idaapi update_offset(int offset); 63 | 64 | int idaapi update_size(int offset); 65 | 66 | int idaapi get_type_increment_val(); 67 | 68 | int idaapi get_offset(); 69 | 70 | int idaapi get_size(); 71 | }; 72 | 73 | void idaapi type_reference::init(cexpr_t *e) { 74 | type = e->type; 75 | hlpr_off = 0; 76 | final_off = 0; 77 | 78 | hlpr_size = 0; 79 | final_size = 0; 80 | } 81 | 82 | void idaapi type_reference::update_type(cexpr_t *e) { 83 | type = e->type; 84 | } 85 | 86 | int idaapi type_reference::get_type_increment_val() { 87 | if (type.is_ptr()) { 88 | ptr_type_data_t ptr_deets; 89 | if(type.get_ptr_details(&ptr_deets)) { 90 | return static_cast(ptr_deets.obj_type.get_size()); 91 | } 92 | } else if (type.is_array()) { 93 | return 1; 94 | } 95 | 96 | return 1; 97 | } 98 | 99 | int idaapi type_reference::update_offset(int offset) { 100 | int update_factor = get_type_increment_val(); 101 | final_off += update_factor * offset; 102 | 103 | return final_off; 104 | } 105 | 106 | int idaapi type_reference::update_size(int size) { 107 | final_size = size; 108 | return final_size; 109 | } 110 | 111 | int idaapi type_reference::get_offset() 112 | { 113 | return final_off + hlpr_off; 114 | } 115 | 116 | int idaapi type_reference::get_size() 117 | { 118 | if(hlpr_size != 0) 119 | return hlpr_size; 120 | 121 | return final_size; 122 | } 123 | 124 | void idaapi type_reference::update_hlpr(int off, int num) 125 | { 126 | hlpr_off = off; 127 | hlpr_size = num; 128 | } 129 | 130 | struct type_builder_t : public ctree_parentee_t 131 | { 132 | std::set expression_to_match; 133 | 134 | struct struct_filed 135 | { 136 | int offset; 137 | int size; 138 | ea_t vftbl; 139 | }; 140 | 141 | std::map structure; 142 | 143 | int idaapi visit_expr(cexpr_t *e); 144 | 145 | tid_t get_structure(const qstring& name); 146 | 147 | bool get_structure(std::map &struc); 148 | 149 | int get_structure_size(); 150 | 151 | bool match_expression(const qstring& expr_name); 152 | 153 | bool idaapi check_memptr(struct_filed &str_fld); 154 | 155 | bool idaapi check_idx(struct_filed &str_fld); 156 | 157 | bool idaapi check_helper(citem_t *parent, int &offs, int &size); 158 | 159 | bool idaapi check_ptr(cexpr_t *e, struct_filed &str_fld); 160 | 161 | ea_t idaapi get_vftbl(cexpr_t *e); 162 | }; 163 | 164 | int get_idx_type_size(cexpr_t *idx_expr) 165 | { 166 | qstring buf; 167 | idx_expr->type.print(&buf); 168 | 169 | if(strstr(buf.c_str(), "char")) 170 | return 1; 171 | else if(strstr(buf.c_str(), "short")) 172 | return 2; 173 | else if(strstr(buf.c_str(), "int")) 174 | return 4; 175 | 176 | return 0; 177 | } 178 | 179 | bool idaapi type_builder_t::check_helper(citem_t *parent, int &off, int &num) 180 | { 181 | if(parent->op == cot_call) 182 | { 183 | cexpr_t *expr_2 = (cexpr_t *)parent; 184 | if(!strcmp(get_ctype_name(expr_2->x->op), "helper")) 185 | { 186 | qstring expr; 187 | print1wrapper(expr_2->x, &expr, NULL); 188 | tag_remove(&expr); 189 | 190 | if(expr == "LOBYTE") 191 | { 192 | num = 1; 193 | off = 0; 194 | } 195 | else if(expr == "HIBYTE" || expr == "BYTE3") 196 | { 197 | num = 1; 198 | off = 3; 199 | } 200 | else if(expr == "BYTE1") 201 | { 202 | num = 1; 203 | off = 1; 204 | } 205 | else if(expr == "BYTE2") 206 | { 207 | num = 1; 208 | off = 2; 209 | } 210 | else if(expr == "LOWORD") 211 | { 212 | num = 2; 213 | off = 0; 214 | } 215 | else if(expr == "HIWORD") 216 | { 217 | num = 2; 218 | off = 2; 219 | } 220 | else 221 | { 222 | return false; 223 | } 224 | 225 | return true; 226 | } 227 | } 228 | 229 | return false; 230 | } 231 | 232 | bool idaapi type_builder_t::check_memptr(struct_filed &str_fld) 233 | { 234 | // check if it has at least two parents 235 | if ( parents.size() > 2 ) 236 | { 237 | citem_t *parent_1 = parents.back(); 238 | 239 | // check if its parent is memptr 240 | if(parent_1->is_expr() && (parent_1->op == cot_memptr)) 241 | { 242 | citem_t *parent_2 = parents[parents.size() - 2]; 243 | citem_t *parent_3 = NULL; 244 | 245 | int num = 0; 246 | int off = 0; 247 | 248 | // check presence of the helper block 249 | bool bHelper = check_helper(parent_2, off, num); 250 | if(bHelper) 251 | parent_3 = parents[parents.size() - 3]; 252 | else 253 | parent_3 = parent_2; 254 | 255 | if(parent_2->is_expr() && (parent_2->op == cot_asg)) 256 | { 257 | cexpr_t *expr = (cexpr_t *)parent_1; 258 | 259 | if(bHelper) 260 | { 261 | str_fld.offset = expr->m + off; 262 | str_fld.size = num; 263 | } 264 | else 265 | { 266 | str_fld.offset = expr->m; 267 | str_fld.size = expr->ptrsize; 268 | } 269 | 270 | return true; 271 | } 272 | } 273 | } 274 | 275 | return false; 276 | } 277 | 278 | ea_t idaapi type_builder_t::get_vftbl(cexpr_t *e) { 279 | ea_t vftbl = BADADDR; 280 | 281 | if (e->is_expr()) { 282 | if ((e->op == cot_cast) && (e->x != NULL)) 283 | e = e->x; 284 | 285 | if ((e->op == cot_ref) && (e->x != NULL)) 286 | e = e->x; 287 | 288 | if (e->op == cot_obj) { 289 | vftbl = e->obj_ea; 290 | } 291 | } 292 | 293 | return vftbl; 294 | } 295 | 296 | bool idaapi type_builder_t::check_ptr(cexpr_t *e, struct_filed &str_fld) 297 | { 298 | str_fld.offset = 0; 299 | str_fld.size = 0; 300 | str_fld.vftbl = BADADDR; 301 | 302 | type_reference referInfo; 303 | referInfo.init(e); 304 | 305 | qstring dbg_info; 306 | 307 | bool done = false; 308 | 309 | auto par_size = parents.size(); 310 | // check if it has at least three parents 311 | if ( par_size > 2 ) 312 | { 313 | int offset = 0; 314 | int parent_idx = 1; 315 | 316 | int num = 0; 317 | int off = 0; 318 | 319 | for (size_t i = 0 ; i < parents.size() - 1 ; i ++) { 320 | citem_t *parent_i = parents[parents.size() - i - 1]; 321 | 322 | // if its parent is addition 323 | if(parent_i->is_expr() && (parent_i->op == cot_add)) 324 | { 325 | cexpr_t *expr_2 = (cexpr_t *)parent_i; 326 | 327 | // get index_value 328 | qstring s; 329 | print1wrapper(expr_2->y, &s, NULL); 330 | tag_remove(&s); 331 | 332 | int base = 10; 333 | if (s.find("0x") == 0) 334 | base = 16; 335 | 336 | offset = strtol(s.c_str(), NULL, base); 337 | 338 | referInfo.update_offset(offset); 339 | } else if(parent_i->is_expr() && (parent_i->op == cot_cast)) { 340 | referInfo.update_type((cexpr_t *)parent_i); 341 | } else if(parent_i->is_expr() && check_helper((cexpr_t *)parent_i, off, num)) { 342 | referInfo.update_hlpr(off, num); 343 | } else if(parent_i->is_expr() && (parent_i->op == cot_ptr)) { 344 | referInfo.update_size(((cexpr_t *)parent_i)->ptrsize); 345 | citem_t *parent_ii = parents[parents.size() - i - 2]; 346 | if ((parent_ii->is_expr()) && (((cexpr_t *)parent_ii)->op == cot_asg) && (((cexpr_t *)parent_ii)->x == parent_i)) { 347 | ea_t vftbl = get_vftbl(((cexpr_t *)parent_ii)->y); 348 | if (vftbl != BADADDR) 349 | str_fld.vftbl = vftbl; 350 | } 351 | done = true; 352 | break; 353 | } else if(parent_i->is_expr() && (parent_i->op == cot_memptr)) { 354 | referInfo.update_offset(((cexpr_t *)parent_i)->m); 355 | referInfo.update_size(((cexpr_t *)parent_i)->ptrsize); 356 | done = true; 357 | break; 358 | } else if(parent_i->is_expr() && (parent_i->op == cot_asg)) { 359 | if (((cexpr_t *)parent_i)->y == e) { //parents[parents.size() - i]) { 360 | qstring s; 361 | print1wrapper(((cexpr_t *)parent_i)->x, &s, NULL); 362 | tag_remove(&s); 363 | 364 | char comment[258]; 365 | memset(comment, 0x00, sizeof(comment)); 366 | sprintf_s(comment, sizeof(comment), "monitoring %s\r\n", s.c_str()); 367 | 368 | logmsg(DEBUG, comment); 369 | 370 | expression_to_match.insert(s); 371 | 372 | } else { 373 | get_vftbl(((cexpr_t *)parent_i)->y); 374 | } 375 | done = true; 376 | break; 377 | } else if(parent_i->is_expr() && (parent_i->op == cot_call)) { 378 | done = true; 379 | break; 380 | } 381 | } 382 | } 383 | 384 | if(done) { 385 | str_fld.offset = referInfo.get_offset(); 386 | str_fld.size = referInfo.get_size(); 387 | if (str_fld.size == 0) { 388 | str_fld.size = 4; 389 | } 390 | 391 | if (str_fld.vftbl != BADADDR) { 392 | char tmp[1024]; 393 | memset(tmp, 0x00, sizeof(tmp)); 394 | #ifdef __EA64__ 395 | const char *fmt = "vftbl reference detected at offset 0x%X, ea=0x%08llX\r\n"; 396 | #else 397 | const char *fmt = "vftbl reference detected at offset 0x%X, ea=0x%08X\r\n"; 398 | #endif 399 | sprintf_s(tmp, sizeof(tmp), fmt, str_fld.offset, str_fld.vftbl); 400 | 401 | logmsg(DEBUG, tmp); 402 | } 403 | } 404 | 405 | return done; 406 | } 407 | 408 | bool idaapi type_builder_t::check_idx(struct_filed &str_fld) 409 | { 410 | // check if it has at least two parents 411 | if ( parents.size() > 1 ) 412 | { 413 | citem_t *parent_1 = parents.back(); 414 | 415 | // if its parrent is 416 | if(parent_1->is_expr() && (parent_1->op == cot_memptr)) 417 | { 418 | citem_t *parent_2 = parents[parents.size() - 2]; 419 | if(parent_2->op == cot_idx) 420 | { 421 | cexpr_t *expr_2 = (cexpr_t *)parent_2; 422 | 423 | // get index_value 424 | qstring s; 425 | print1wrapper(expr_2->y, &s, NULL); 426 | tag_remove(&s); 427 | int num = atoi(s.c_str()); 428 | 429 | citem_t *parent_3 = parents[parents.size() - 3]; 430 | if(parent_3->is_expr() && (parent_3->op == cot_asg)) 431 | { 432 | cexpr_t *expr_1 = (cexpr_t *)parent_1; 433 | 434 | str_fld.offset = expr_1->m + num; 435 | str_fld.size = get_idx_type_size(expr_2); 436 | 437 | return true; 438 | } 439 | } 440 | } 441 | } 442 | 443 | return false; 444 | } 445 | 446 | bool type_builder_t::match_expression(const qstring& expr_name) { 447 | return expression_to_match.find(expr_name) != expression_to_match.end(); 448 | } 449 | 450 | int idaapi type_builder_t::visit_expr(cexpr_t *e) 451 | { 452 | // check if the expression being visited is variable 453 | if (e->op == cot_var) 454 | { 455 | // get the variable name 456 | qstring s; 457 | print1wrapper(e, &s, NULL); 458 | tag_remove(&s); 459 | 460 | // check for the target variable 461 | if (match_expression(s)) 462 | { 463 | struct_filed str_fld; 464 | 465 | if(check_ptr(e, str_fld)) { 466 | auto ret = structure.insert(std::make_pair(str_fld.offset, str_fld)); 467 | if (!ret.second && str_fld.vftbl != BADADDR) { 468 | structure[str_fld.offset] = str_fld; 469 | } 470 | } 471 | } 472 | } 473 | 474 | return 0; 475 | } 476 | 477 | int type_builder_t::get_structure_size() 478 | { 479 | int highest_offset = 0; 480 | int reference_size = 0; 481 | 482 | for (std::map::iterator i = structure.begin(); i != structure.end() ; ++i) 483 | { 484 | if (highest_offset < i->second.offset) 485 | { 486 | highest_offset = i ->second.offset; 487 | reference_size = i->second.size; 488 | } 489 | } 490 | 491 | return highest_offset + reference_size; 492 | } 493 | 494 | tid_t type_builder_t::get_structure(const qstring& name) 495 | { 496 | tid_t struct_type_id = add_struc(BADADDR, name.c_str()); 497 | 498 | if (struct_type_id == BADADDR) { 499 | // the name is ill-formed or *is already used in the program* 500 | struct_type_id = get_struc_id(name.c_str()); 501 | } 502 | 503 | if (struct_type_id != BADADDR) 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 = byte_flag(); 520 | else if (i->second.size == 2) 521 | member_flgs = word_flag(); 522 | else if (i->second.size == 4) 523 | member_flgs = dword_flag(); 524 | else if (i->second.size == 8) 525 | member_flgs = qword_flag(); 526 | 527 | qstring field_name; 528 | 529 | if ((i->second.vftbl != BADADDR) && get_vbtbl_by_ea(i->second.vftbl, vtbl)) 530 | { 531 | qstring vftbl_name = name; 532 | vftbl_name.cat_sprnt("_VTABLE_%X_%p", i->second.offset, i->second.vftbl); 533 | 534 | tid_t vtbl_str_id = create_vtbl_struct(vtbl.ea_begin, vtbl.ea_end, vftbl_name, 0); 535 | if (vtbl_str_id != BADADDR) { 536 | field_name.cat_sprnt("vftbl_%d_%p", j, i->second.vftbl); 537 | const char *fncstr = field_name.c_str(); 538 | int iRet = add_struc_member(struc, fncstr, i->second.offset, member_flgs, NULL, i->second.size); 539 | 540 | member_t * membr = get_member_by_name(struc, fncstr); 541 | if (membr != NULL) { 542 | tinfo_t new_type = create_typedef(vftbl_name.c_str()); 543 | if (new_type.is_correct()) { 544 | smt_code_t dd = set_member_tinfo(struc, membr, 0, make_pointer(new_type), SET_MEMTI_COMPATIBLE); 545 | } 546 | } 547 | } 548 | } 549 | else 550 | { 551 | field_name.cat_sprnt("field_%X", i->second.offset); 552 | const char *fncstr = field_name.c_str(); 553 | int iRet = add_struc_member(struc, fncstr, i->second.offset, member_flgs, NULL, i->second.size); 554 | } 555 | j ++; 556 | } 557 | } 558 | } 559 | return struct_type_id; 560 | } 561 | 562 | bool type_builder_t::get_structure(std::map &struc) 563 | { 564 | bool bResult = false; 565 | 566 | if (structure.empty()) 567 | return false; 568 | 569 | for(auto i = structure.begin(); i != structure.end() ; ++i) 570 | struc[i->first] = i->second; 571 | 572 | return true; 573 | } 574 | 575 | bool idaapi reconstruct_type_cb(void *ud) 576 | { 577 | vdui_t &vu = *(vdui_t *)ud; 578 | 579 | // Determine the ctree item to highlight 580 | vu.get_current_item(USE_KEYBOARD); 581 | lvar_t* lvar = NULL; 582 | 583 | if (vu.item.is_citem()) { 584 | citem_t *highlight = vu.item.e; 585 | if (highlight && highlight->is_expr() && (highlight->op == cot_var)) { 586 | lvar = vu.item.get_lvar(); 587 | } 588 | } else if (vu.item.citype == VDI_LVAR) { 589 | lvar = vu.item.get_lvar(); 590 | } 591 | 592 | if (lvar != NULL) { 593 | // initialize type rebuilder 594 | type_builder_t type_bldr; 595 | type_bldr.expression_to_match.insert(lvar->name); 596 | // traverse the ctree structure 597 | type_bldr.apply_to(&vu.cfunc->body, NULL); 598 | 599 | if (!type_bldr.structure.empty() && lvar != NULL) 600 | { 601 | qstring type_name{ "struct_name" }; 602 | 603 | if (lvar->type().is_ptr()) // doesn't make sense if it's not tbh 604 | (void)lvar->type().get_pointed_object().get_type_name(&type_name); 605 | 606 | if (!ask_str(&type_name, 0, "Enter type name:")) 607 | return false; 608 | 609 | tid_t struct_type_id = BADADDR; 610 | if (!type_name.empty()) 611 | { 612 | struct_type_id = type_bldr.get_structure(type_name); 613 | } 614 | 615 | if (struct_type_id != BADADDR) 616 | { 617 | tinfo_t new_type = create_typedef(type_name.c_str()); 618 | if (new_type.is_correct()) 619 | { 620 | qstring type_str; 621 | if (new_type.print(&type_str, NULL, PRTYPE_DEF | PRTYPE_MULTI)) 622 | { 623 | msg("New type created:\r\n%s\n", type_str.c_str()); 624 | logmsg(DEBUG, "New type created:\r\n%s\n", type_str.c_str()); 625 | tinfo_t ptype = make_pointer(new_type); 626 | vu.set_lvar_type(lvar, ptype); 627 | vu.refresh_ctext(); 628 | return true; 629 | } 630 | } 631 | } 632 | 633 | warning("Invalid type name: %s", type_name.c_str()); 634 | logmsg(DEBUG, "Invalid type name: %s", type_name.c_str()); 635 | return false; 636 | } 637 | else 638 | { 639 | warning("Failed to reconstruct type, no field references have been found ...\n"); 640 | logmsg(DEBUG, "Failed to reconstruct type, no field references have been found ...\n"); 641 | return false; 642 | } 643 | } 644 | 645 | warning("Selected item is invalid...\n"); 646 | logmsg(DEBUG, "Selected item is invalid...\n"); 647 | return false; 648 | } 649 | 650 | bool idaapi reconstruct_type(cfuncptr_t cfunc, const qstring& var_name, const qstring& type_name) 651 | { 652 | bool bResult = false; 653 | // initialize type rebuilder 654 | type_builder_t type_bldr; 655 | type_bldr.expression_to_match.insert(var_name.c_str()); 656 | 657 | // traverse the ctree structure 658 | type_bldr.apply_to(&cfunc->body, NULL); 659 | 660 | if (type_bldr.structure.size() != 0) { 661 | tid_t struct_type_id = type_bldr.get_structure(type_name); 662 | 663 | if(struct_type_id != BADADDR) { 664 | tinfo_t new_type = create_typedef(type_name.c_str()); 665 | if(new_type.is_correct()) { 666 | qstring type_str = type_name; 667 | //if (new_type.print(&type_str, NULL, PRTYPE_DEF | PRTYPE_MULTI)) 668 | logmsg(DEBUG, "New type created: %s\n", type_str.c_str()); 669 | 670 | bResult = true; 671 | } 672 | } 673 | } else { 674 | warning("Failed to reconstruct type, no field references have been found...\n"); 675 | logmsg(DEBUG, "Failed to reconstruct type, no field references have been found...\n"); 676 | } 677 | 678 | return bResult; 679 | } 680 | -------------------------------------------------------------------------------- /src/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_cb(void *ud); 49 | bool idaapi reconstruct_type(cfuncptr_t cfunc, const qstring& var_name, const qstring& type_name); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/Utility.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2016 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 | #if defined (__LINUX__) || defined (__MAC__) 32 | #include "Linux.h" 33 | #endif 34 | 35 | bool compilerIs(const char *name) 36 | { 37 | comp_t vc = default_compiler(); 38 | //qstring comp = get_compiler_name(vc); //fullname 39 | qstring comp = get_compiler_abbr(vc); 40 | 41 | if (comp == name) 42 | return true; 43 | return false; 44 | } 45 | 46 | bool idaapi show_string_in_custom_view(void *ud, const qstring& title, const qstring& str) 47 | { 48 | TWidget *widget = create_empty_widget(title.c_str()); 49 | string_view_form_info_t *si = new string_view_form_info_t(widget); 50 | si->sv.push_back(simpleline_t(str)); 51 | 52 | simpleline_place_t s1; 53 | simpleline_place_t s2(static_cast(si->sv.size())); 54 | si->cv = create_custom_viewer((title + "_").c_str(), &s1, &s2, &s1, nullptr, &si->sv, nullptr, nullptr, widget); 55 | si->codeview = create_code_viewer(si->cv, CDVF_NOLINES, widget); 56 | set_custom_viewer_handlers(si->cv, nullptr, si); 57 | #if (defined(IDA_SDK_VERSION) && IDA_SDK_VERSION == 720) 58 | display_widget(widget, WOPN_RESTORE); 59 | #else 60 | display_widget(widget, WOPN_ONTOP | WOPN_RESTORE); 61 | #endif 62 | 63 | return false; 64 | } 65 | 66 | void split_qstring(const qstring &options, const qstring &splitter, qvector &result) { 67 | size_t start_pos = 0; 68 | 69 | do { 70 | size_t npos = options.find(splitter, start_pos); 71 | if (npos != -1) { 72 | if (npos != start_pos) { 73 | result.push_back(options.substr(start_pos, npos)); 74 | } 75 | start_pos = npos + splitter.length(); 76 | } 77 | else { 78 | qstring token = options.substr(start_pos); 79 | if (token.length() != 0) 80 | result.push_back(token); 81 | break; 82 | } 83 | } while (start_pos < options.length()); 84 | } 85 | 86 | 87 | // SHA1 implementation 88 | #define SHA1CircularShift(bits,word)(((word) << (bits)) | ((word) >> (32-(bits)))) 89 | 90 | void SHA1PadMessage(SHA1Context *); 91 | void SHA1ProcessMessageBlock(SHA1Context *); 92 | 93 | int SHA1Reset(SHA1Context *context) 94 | { 95 | if (!context) 96 | return shaNull; 97 | 98 | context->Length_Low = 0; 99 | context->Length_High = 0; 100 | context->Message_Block_Index = 0; 101 | context->Intermediate_Hash[0] = 0x67452301; 102 | context->Intermediate_Hash[1] = 0xEFCDAB89; 103 | context->Intermediate_Hash[2] = 0x98BADCFE; 104 | context->Intermediate_Hash[3] = 0x10325476; 105 | context->Intermediate_Hash[4] = 0xC3D2E1F0; 106 | context->Computed = 0; 107 | context->Corrupted = 0; 108 | return shaSuccess; 109 | } 110 | 111 | int SHA1Result(SHA1Context *context, uint8_t Message_Digest[SHA1HashSize]) 112 | { 113 | int i; 114 | if (!context || !Message_Digest) 115 | return shaNull; 116 | 117 | if (context->Corrupted) 118 | return context->Corrupted; 119 | 120 | if (!context->Computed) 121 | { 122 | SHA1PadMessage(context); 123 | for (i = 0; i<64; ++i) 124 | context->Message_Block[i] = 0; 125 | 126 | context->Length_Low = 0; /* and clear length */ 127 | context->Length_High = 0; 128 | context->Computed = 1; 129 | } 130 | for (i = 0; i < SHA1HashSize; ++i) 131 | Message_Digest[i] = context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03)); 132 | 133 | return shaSuccess; 134 | } 135 | 136 | int SHA1Input(SHA1Context *context, const uint8_t *message_array, unsigned int length) 137 | { 138 | if (!length) 139 | { 140 | return shaSuccess; 141 | } 142 | if (!context || !message_array) 143 | { 144 | return shaNull; 145 | } 146 | if (context->Computed) 147 | { 148 | context->Corrupted = shaStateError; 149 | return shaStateError; 150 | } 151 | if (context->Corrupted) 152 | { 153 | return context->Corrupted; 154 | } 155 | while (length-- && !context->Corrupted) 156 | { 157 | context->Message_Block[context->Message_Block_Index++] = 158 | (*message_array & 0xFF); 159 | context->Length_Low += 8; 160 | if (context->Length_Low == 0) 161 | { 162 | context->Length_High++; 163 | if (context->Length_High == 0) 164 | context->Corrupted = 1; 165 | } 166 | if (context->Message_Block_Index == 64) 167 | SHA1ProcessMessageBlock(context); 168 | message_array++; 169 | } 170 | return shaSuccess; 171 | } 172 | 173 | void SHA1ProcessMessageBlock(SHA1Context *context) 174 | { 175 | const uint32_t K[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6}; 176 | int t; // Loop counter 177 | uint32_t temp; // Temporary word value 178 | uint32_t W[80]; // Word sequence 179 | uint32_t A, B, C, D, E; // Word buffers 180 | // Initialize the first 16 words in the array W 181 | for (t = 0; t < 16; t++) 182 | { 183 | W[t] = context->Message_Block[t * 4] << 24; 184 | W[t] |= context->Message_Block[t * 4 + 1] << 16; 185 | W[t] |= context->Message_Block[t * 4 + 2] << 8; 186 | W[t] |= context->Message_Block[t * 4 + 3]; 187 | } 188 | 189 | for (t = 16; t < 80; t++) 190 | W[t] = SHA1CircularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); 191 | 192 | A = context->Intermediate_Hash[0]; 193 | B = context->Intermediate_Hash[1]; 194 | C = context->Intermediate_Hash[2]; 195 | D = context->Intermediate_Hash[3]; 196 | E = context->Intermediate_Hash[4]; 197 | 198 | for (t = 0; t < 20; t++) 199 | { 200 | temp = SHA1CircularShift(5, A) + 201 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 202 | E = D; 203 | D = C; 204 | C = SHA1CircularShift(30, B); 205 | B = A; 206 | A = temp; 207 | } 208 | 209 | for (t = 20; t < 40; t++) 210 | { 211 | temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; 212 | E = D; 213 | D = C; 214 | C = SHA1CircularShift(30, B); 215 | B = A; 216 | A = temp; 217 | } 218 | 219 | for (t = 40; t < 60; t++) 220 | { 221 | temp = SHA1CircularShift(5, A) + 222 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 223 | E = D; 224 | D = C; 225 | C = SHA1CircularShift(30, B); 226 | B = A; 227 | A = temp; 228 | } 229 | 230 | for (t = 60; t < 80; t++) 231 | { 232 | temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; 233 | E = D; 234 | D = C; 235 | C = SHA1CircularShift(30, B); 236 | B = A; 237 | A = temp; 238 | } 239 | 240 | context->Intermediate_Hash[0] += A; 241 | context->Intermediate_Hash[1] += B; 242 | context->Intermediate_Hash[2] += C; 243 | context->Intermediate_Hash[3] += D; 244 | context->Intermediate_Hash[4] += E; 245 | context->Message_Block_Index = 0; 246 | } 247 | 248 | void SHA1PadMessage(SHA1Context *context) 249 | { 250 | 251 | if (context->Message_Block_Index > 55) 252 | { 253 | context->Message_Block[context->Message_Block_Index++] = 0x80; 254 | while (context->Message_Block_Index < 64) 255 | context->Message_Block[context->Message_Block_Index++] = 0; 256 | 257 | SHA1ProcessMessageBlock(context); 258 | while (context->Message_Block_Index < 56) 259 | context->Message_Block[context->Message_Block_Index++] = 0; 260 | } 261 | else 262 | { 263 | context->Message_Block[context->Message_Block_Index++] = 0x80; 264 | while (context->Message_Block_Index < 56) 265 | context->Message_Block[context->Message_Block_Index++] = 0; 266 | } 267 | 268 | context->Message_Block[56] = context->Length_High >> 24; 269 | context->Message_Block[57] = context->Length_High >> 16; 270 | context->Message_Block[58] = context->Length_High >> 8; 271 | context->Message_Block[59] = context->Length_High; 272 | context->Message_Block[60] = context->Length_Low >> 24; 273 | context->Message_Block[61] = context->Length_Low >> 16; 274 | context->Message_Block[62] = context->Length_Low >> 8; 275 | context->Message_Block[63] = context->Length_Low; 276 | SHA1ProcessMessageBlock(context); 277 | } 278 | 279 | char int_to_hex(uint8_t integ) { 280 | if (integ < 10) 281 | return '0' + integ; 282 | else 283 | return 'a' + (integ - 10); 284 | } 285 | 286 | void SHA1MessageDigestToString(uint8_t Message_Digest[SHA1HashSize], char outbuffer[SHA1HashSize * 2]) { 287 | for (int i = 0; i < SHA1HashSize; i++) { 288 | outbuffer[i * 2] = int_to_hex(Message_Digest[i] >> 4); 289 | outbuffer[i * 2 + 1] = int_to_hex(Message_Digest[i] & 0xF); 290 | } 291 | } 292 | 293 | void idaapi setUnknown(ea_t ea, asize_t size) 294 | { 295 | // TODO: Does the overrun problem still exist? 296 | //do_unknown_range(ea, (size_t)size, DOUNK_SIMPLE); 297 | while (size > 0) 298 | { 299 | asize_t isize = get_item_size(ea); 300 | if (isize > size) 301 | break; 302 | 303 | del_items(ea); 304 | ea += (ea_t)isize; 305 | size -= isize; 306 | }; 307 | } 308 | 309 | 310 | void MakeName(ea_t ea, const qstring& name, const qstring& prefix, const qstring& postfix) 311 | { 312 | qstring g_name(prefix); 313 | g_name += name; 314 | g_name += postfix; 315 | 316 | g_name.replace(" ", "_"); 317 | g_name.replace("*", "_"); 318 | g_name.replace(",", "_"); 319 | g_name.replace("<", "_lt"); 320 | g_name.replace(">", "_ge"); 321 | set_name(ea, g_name.c_str(), SN_NOWARN); 322 | } 323 | 324 | bool MakeArray(ea_t ea, size_t nitems) 325 | { 326 | asize_t itemsize = 0; 327 | tid_t tid = BADADDR; 328 | flags_t flags = get_flags(ea); 329 | if (is_code(flags) || is_tail(flags) || is_align(flags)) 330 | return false; 331 | 332 | if (is_unknown(flags)) 333 | flags = 0; 334 | 335 | if (is_struct(flags)) 336 | { 337 | opinfo_t ti; 338 | if (!get_opinfo(&ti, ea, 0, flags)) 339 | return false; 340 | itemsize = get_data_elsize(ea, flags, &ti); 341 | tid = ti.tid; 342 | } 343 | else 344 | { 345 | itemsize = get_item_size(ea); 346 | } 347 | 348 | return create_data(ea, flags, static_cast(itemsize * nitems), tid); 349 | } 350 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/Utility.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2016 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 | // Simple CustomView Form Init 34 | struct string_view_form_info_t 35 | { 36 | TWidget *widget; 37 | TWidget *cv; 38 | TWidget *codeview; 39 | strvec_t sv; 40 | string_view_form_info_t(TWidget *f) : widget(f), cv(nullptr), codeview(nullptr) {} 41 | }; 42 | 43 | bool idaapi show_string_in_custom_view(void *ud, const qstring& title, const qstring& str); 44 | 45 | 46 | // Size of string with out terminator 47 | //#define SIZESTR(x) (sizeof(x) - 1) 48 | 49 | #ifndef _countof 50 | # define _countof(x) (sizeof((x)) / sizeof((x)[0])) 51 | #endif // _countof 52 | 53 | 54 | typedef qlist eaList; 55 | typedef std::set eaSet; 56 | typedef std::map eaRefMap; 57 | struct earef 58 | { 59 | ea_t ea; 60 | UINT refs; 61 | }; 62 | 63 | 64 | // 65 | // #pragma message(__LOC__ "important part to be changed") 66 | // #pragma message(__LOC2__ "error C9901: wish that error would exist") 67 | 68 | // Get IDA 32 bit value with verification 69 | template bool getVerify32_t(ea_t eaPtr, T &rValue) 70 | { 71 | // Location valid? 72 | if (is_loaded(eaPtr)) 73 | { 74 | // Get 32bit value 75 | rValue = (T) get_32bit(eaPtr); 76 | return true; 77 | } 78 | 79 | return false; 80 | } 81 | 82 | 83 | #define MSVC_COMPILER_ABBR "vc" 84 | #define GCC_COMPILER_ABBR "gcc" 85 | 86 | // Check compiler 87 | bool compilerIs(const char *name); 88 | 89 | 90 | // Get address/pointer value 91 | inline ea_t getEa(ea_t ea) 92 | { 93 | #ifndef __EA64__ 94 | return (ea_t)get_32bit(ea); 95 | #else // __EA64__ 96 | return (ea_t)get_64bit(ea); 97 | #endif // __EA64__ 98 | } 99 | 100 | 101 | // Returns TRUE if ea_t sized value flags 102 | inline bool isEa(flags_t f) 103 | { 104 | #ifndef __EA64__ 105 | return is_dword(f); 106 | #else // __EA64__ 107 | return is_qword(f); 108 | #endif // __EA64__ 109 | } 110 | 111 | #ifndef _SHA_enum_ 112 | #define _SHA_enum_ 113 | enum 114 | { 115 | shaSuccess = 0, 116 | shaNull, // Null pointer parameter 117 | shaInputTooLong, // input data too long 118 | shaStateError // called Input after Result 119 | }; 120 | #endif 121 | #define SHA1HashSize 20 122 | 123 | typedef struct SHA1Context 124 | { 125 | uint32_t Intermediate_Hash[SHA1HashSize / 4]; // Message Digest 126 | uint32_t Length_Low; // Message length in bits 127 | uint32_t Length_High; // Message length in bits 128 | // Index into message block array 129 | int_least16_t Message_Block_Index; 130 | uint8_t Message_Block[64]; // 512-bit message blocks 131 | int Computed; // Is the digest computed? 132 | int Corrupted; // Is the message digest corrupted? 133 | } SHA1Context; 134 | 135 | int SHA1Reset(SHA1Context *); 136 | int SHA1Input(SHA1Context *, const uint8_t *, unsigned int); 137 | int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1HashSize]); 138 | void SHA1MessageDigestToString(uint8_t Message_Digest[SHA1HashSize], char outbuffer[SHA1HashSize * 2]); 139 | 140 | void split_qstring(const qstring &options, const qstring &splitter, qvector &result); 141 | 142 | void idaapi setUnknown(ea_t ea, asize_t size); 143 | void MakeName(ea_t ea, const qstring& name, const qstring& prefix = "", const qstring& postfix = ""); 144 | bool MakeArray(ea_t ea, size_t nitems); 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/makefile.lnx: -------------------------------------------------------------------------------- 1 | # use this makefile to build HexRaysCodeXplorer for Linux 2 | 3 | CC=g++ 4 | LD=ld 5 | 6 | LDFLAGS=-shared -m64 -static-libgcc -static-libstdc++ 7 | 8 | LIBDIR=-L$(IDA_DIR) 9 | SRCDIR=./ 10 | HEXRAYS_SDK=$(IDA_DIR)/plugins/hexrays_sdk 11 | INCLUDES=-I$(IDA_SDK)/include -I$(HEXRAYS_SDK)/include 12 | __X64__=1 13 | 14 | SRC=$(SRCDIR)CodeXplorer.cpp \ 15 | $(SRCDIR)CtreeGraphBuilder.cpp \ 16 | $(SRCDIR)ObjectExplorer.cpp \ 17 | $(SRCDIR)TypeReconstructor.cpp \ 18 | $(SRCDIR)CtreeExtractor.cpp \ 19 | $(SRCDIR)TypeExtractor.cpp \ 20 | $(SRCDIR)Utility.cpp \ 21 | $(SRCDIR)MSVCObjectFormatParser.cpp \ 22 | $(SRCDIR)IObjectFormatParser.cpp \ 23 | $(SRCDIR)GCCObjectFormatParser.cpp \ 24 | $(SRCDIR)GCCVtableInfo.cpp \ 25 | $(SRCDIR)GCCTypeInfo.cpp \ 26 | $(SRCDIR)Debug.cpp 27 | 28 | OBJS=$(subst .cpp,.o,$(SRC)) 29 | 30 | CFLAGS=-m64 -fPIC -D__LINUX__ -D__PLUGIN__ -std=c++11 -D__X64__ -D_GLIBCXX_USE_CXX11_ABI=0 31 | LIBS=-lc -lpthread -ldl 32 | 33 | ifeq ($(EA64),1) 34 | CFLAGS+=-D__EA64__ 35 | LIBS+=-lida64 36 | EXT=so 37 | SUFFIX=64 38 | else 39 | EXT=so 40 | LIBS+=-lida 41 | SUFFIX= 42 | endif 43 | 44 | all: check-env clean HexRaysCodeXplorer$(SUFFIX).$(EXT) 45 | 46 | HexRaysCodeXplorer$(SUFFIX).$(EXT): $(OBJS) 47 | $(CC) $(LDFLAGS) $(LIBDIR) -o HexRaysCodeXplorer$(SUFFIX).$(EXT) $(OBJS) $(LIBS) 48 | 49 | %.o: %.cpp 50 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ 51 | 52 | clean: 53 | rm -f $(OBJS) HexRaysCodeXplorer$(SUFFIX).$(EXT) 54 | 55 | install: 56 | cp -f HexRaysCodeXplorer$(SUFFIX).$(EXT) $(IDA_DIR)/plugins 57 | 58 | check-env: 59 | ifndef IDA_SDK 60 | $(error IDA_SDK is undefined) 61 | endif 62 | ifndef IDA_DIR 63 | $(error IDA_DIR is undefined) 64 | endif 65 | ifndef EA64 66 | $(error specify EA64=0 for 32 bit build or EA64=1 for 64 bit build) 67 | endif 68 | .PHONY: check-env 69 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/makefile.mac: -------------------------------------------------------------------------------- 1 | # DO NOT USE THIS makefile FOR LINUX 2 | # USER makefile.lnx INSTEAD 3 | 4 | CC=g++ 5 | LD=ld 6 | 7 | LDFLAGS=-shared -m32 8 | 9 | ifdef __LINUX__ 10 | CFLAGS=-m32 -D__LINUX__ -D__PLUGIN__ -std=c++11 11 | EXT=plx 12 | LDFLAGS+=-static-libgcc -static-libstdc++ 13 | endif 14 | ifdef __LINUX64__ 15 | CFLAGS=-m32 -fPIC -D__LINUX__ -D__PLUGIN__ -D__EA64__ -std=c++11 16 | EXT=plx64 17 | LDFLAGS+=-static-libgcc -static-libstdc++ 18 | endif 19 | ifdef __MAC__ 20 | CFLAGS=-m32 -fPIC -D__MAC__ -D__PLUGIN__ -std=c++11 21 | EXT=pmc 22 | endif 23 | 24 | 25 | # TODO: add conditional compilation over -lida or -lida64 based on the X64 26 | 27 | #LIBS= -lida64 -lpro -lc -lpthread -ldl 28 | LIBS= -lida -lpro -lc -lpthread -ldl 29 | 30 | LIBDIR=-L./ -L$(IDA_DIR) 31 | SRCDIR=./ 32 | HEXRAYS_SDK=$(IDA_DIR)/plugins/hexrays_sdk 33 | SRC=$(SRCDIR)CodeXplorer.cpp \ 34 | $(SRCDIR)CtreeGraphBuilder.cpp \ 35 | $(SRCDIR)ObjectExplorer.cpp \ 36 | $(SRCDIR)TypeReconstructor.cpp \ 37 | $(SRCDIR)CtreeExtractor.cpp \ 38 | $(SRCDIR)TypeExtractor.cpp \ 39 | $(SRCDIR)Utility.cpp \ 40 | $(SRCDIR)ObjectFormatMSVC.cpp \ 41 | $(SRCDIR)Debug.cpp 42 | OBJS=$(subst .cpp,.o,$(SRC)) 43 | EXECUTABLE=HexRaysCodeXplorer 44 | INCLUDES=-I$(IDA_SDK)/include -I$(HEXRAYS_SDK)/include 45 | 46 | # only used on command line anyway 47 | #DEFINE=__X64__ -D__LINUX__ 48 | #DEFINE=__EA64__ -D__LINUX__ 49 | 50 | all: check-env HexRaysCodeXplorer.$(EXT) 51 | 52 | HexRaysCodeXplorer.$(EXT): $(OBJS) 53 | #ln -f -s $(IDA_SDK)/lib/x64_linux_gcc_64/pro.a libpro.a 54 | ln -f -s $(IDA_SDK)/lib/x86_mac_gcc_32/pro.a libpro.a 55 | $(CC) $(LDFLAGS) $(LIBDIR) -o HexRaysCodeXplorer.$(EXT) $(OBJS) $(LIBS) 56 | 57 | %.o: %.cpp 58 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ 59 | 60 | clean: 61 | rm -f $(OBJS) HexRaysCodeXplorer.$(EXT) 62 | 63 | install: 64 | cp -f HexRaysCodeXplorer.$(EXT) $(IDA_DIR)/plugins 65 | 66 | check-env: 67 | ifndef IDA_SDK 68 | $(error IDA_SDK is undefined) 69 | endif 70 | ifndef IDA_DIR 71 | $(error IDA_DIR is undefined) 72 | endif 73 | 74 | .PHONY: check-env 75 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/makefile7.mac: -------------------------------------------------------------------------------- 1 | CXX ?= clang++ 2 | MACSDK=$(shell xcrun --show-sdk-path --sdk macosx) 3 | CXXFLAGS=-m64 -fPIC -shared -D__PLUGIN__ -D__X64__ -Wall -Wextra -std=c++11 -isysroot $(MACSDK) -static-libstdc++ -DUSE_DANGEROUS_FUNCTIONS=1 -DUSE_STANDARD_FILE_FUNCTIONS=1 4 | LDFLAGS=-shared -m64 5 | LIBS=-lc -lpthread -ldl -lpro -lc++ 6 | INCLUDES=-I$(IDA_SDK)/include -I$(IDA_DIR)/plugins/hexrays_sdk/include 7 | 8 | SRCDIR=./ 9 | SRC=$(SRCDIR)CodeXplorer.cpp \ 10 | $(SRCDIR)CtreeGraphBuilder.cpp \ 11 | $(SRCDIR)ObjectExplorer.cpp \ 12 | $(SRCDIR)TypeReconstructor.cpp \ 13 | $(SRCDIR)CtreeExtractor.cpp \ 14 | $(SRCDIR)TypeExtractor.cpp \ 15 | $(SRCDIR)Utility.cpp \ 16 | $(SRCDIR)MSVCObjectFormatParser.cpp \ 17 | $(SRCDIR)IObjectFormatParser.cpp \ 18 | $(SRCDIR)GCCObjectFormatParser.cpp \ 19 | $(SRCDIR)GCCVtableInfo.cpp \ 20 | $(SRCDIR)GCCTypeInfo.cpp \ 21 | $(SRCDIR)Debug.cpp 22 | #SRC = $(wildcard src/*.cpp) 23 | #OBJS=$(subst .cpp,.o,$(SRC)) 24 | 25 | all: check-env HexRaysCodeXplorer.dylib HexRaysCodeXplorer64.dylib 26 | 27 | HexRaysCodeXplorer.dylib: $(SRC) 28 | $(CXX) $(LDFLAGS) $(SRC) $(CXXFLAGS) -L. -L$(IDA_DIR) $(INCLUDES) -D__MAC__=1 $(LIBS) -lida -o HexRaysCodeXplorer.dylib 29 | 30 | HexRaysCodeXplorer64.dylib: $(SRC) 31 | $(CXX) $(LDFLAGS) $(SRC) $(CXXFLAGS) -L. -L$(IDA_DIR) $(INCLUDES) -D__MAC__=1 -D__EA64__=1 $(LIBS) -lida64 -o HexRaysCodeXplorer64.dylib 32 | 33 | clean: 34 | rm -f HexRaysCodeXplorer.dylib HexRaysCodeXplorer64.dylib libpro.a 35 | 36 | install: 37 | cp -f HexRaysCodeXplorer.dylib $(IDA_DIR)/plugins/ 38 | cp -f HexRaysCodeXplorer64.dylib $(IDA_DIR)/plugins/ 39 | 40 | check-env: 41 | ifndef IDA_SDK 42 | $(error IDA_SDK is undefined) 43 | endif 44 | ifndef IDA_DIR 45 | $(error IDA_DIR is undefined) 46 | endif 47 | pwd && cp -f $(IDA_SDK)/lib/x64_mac_gcc_64/pro.a libpro.a 48 | 49 | .PHONY: check-env -------------------------------------------------------------------------------- /targets/IDA_v6.8/Linux/HexRaysCodeXplorer.plx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.8/Linux/HexRaysCodeXplorer.plx -------------------------------------------------------------------------------- /targets/IDA_v6.8/Mac/HexRaysCodeXplorer.pmc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.8/Mac/HexRaysCodeXplorer.pmc -------------------------------------------------------------------------------- /targets/IDA_v6.8/Mac/HexRaysCodeXplorer.pmc64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.8/Mac/HexRaysCodeXplorer.pmc64 -------------------------------------------------------------------------------- /targets/IDA_v6.8/Win/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.8/Win/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /targets/IDA_v6.8/Win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.8/Win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /targets/IDA_v6.9/Win/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.9/Win/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /targets/IDA_v6.9/Win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.9/Win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /targets/IDA_v6.95/Win/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.95/Win/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /targets/IDA_v6.95/Win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v6.95/Win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /targets/IDA_v7.0/HexRaysCodeXplorer.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v7.0/HexRaysCodeXplorer.dylib -------------------------------------------------------------------------------- /targets/IDA_v7.0/HexRaysCodeXplorer64.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v7.0/HexRaysCodeXplorer64.dylib -------------------------------------------------------------------------------- /targets/IDA_v7.1/HexRaysCodeXplorer.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v7.1/HexRaysCodeXplorer.dylib -------------------------------------------------------------------------------- /targets/IDA_v7.1/HexRaysCodeXplorer64.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v7.1/HexRaysCodeXplorer64.dylib -------------------------------------------------------------------------------- /targets/IDA_v7.2/HexRaysCodeXplorer.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v7.2/HexRaysCodeXplorer.dylib -------------------------------------------------------------------------------- /targets/IDA_v7.2/HexRaysCodeXplorer64.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fjh658/HexRaysCodeXplorer/7484b852f388b43f58c7c80a3aacce2c2030cb2f/targets/IDA_v7.2/HexRaysCodeXplorer64.dylib --------------------------------------------------------------------------------