├── .gitignore ├── README.md ├── bin ├── Hex-Rays Plugin contest │ ├── 2013 │ │ ├── HexRaysCodeXplorer v1.0.pdf │ │ └── HexRaysCodeXplorer.plw │ └── 2015 │ │ ├── Linux │ │ └── HexRaysCodeXplorer.plx │ │ ├── Mac │ │ ├── HexRaysCodeXplorer.pmc │ │ └── HexRaysCodeXplorer.pmc64 │ │ └── Win │ │ ├── HexRaysCodeXplorer.p64 │ │ └── HexRaysCodeXplorer.plw ├── v1.1 [ZeroNights Edition] │ └── win │ │ └── HexRaysCodeXplorer.plw ├── v1.2 │ └── win │ │ └── HexRaysCodeXplorer.plw ├── v1.5 [H2HC Edition] │ └── win │ │ └── HexRaysCodeXplorer.plw ├── v1.6 │ ├── HexRaysCodeXplorer.p64 │ └── HexRaysCodeXplorer.plw ├── v1.7 [NSEC15 Edition] │ ├── HexRaysCodeXplorer.p64 │ └── HexRaysCodeXplorer.plw └── v2.0 [BlackHat Edition] │ ├── IDA 6.95 │ ├── Linux │ │ ├── HexRaysCodeXplorer.plx │ │ └── HexRaysCodeXplorer.plx64 │ └── Win │ │ ├── HexRaysCodeXplorer.p64 │ │ └── HexRaysCodeXplorer.plw │ ├── IDA v6.8 │ ├── Linux │ │ └── HexRaysCodeXplorer.plx │ ├── Mac │ │ ├── HexRaysCodeXplorer.pmc │ │ └── HexRaysCodeXplorer.pmc64 │ └── Win │ │ ├── HexRaysCodeXplorer.p64 │ │ └── HexRaysCodeXplorer.plw │ └── IDA v6.9 │ └── Win │ ├── HexRaysCodeXplorer.p64 │ └── HexRaysCodeXplorer.plw ├── 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 └── m1.png └── src ├── HexRaysCodeXplorer.sln ├── HexRaysCodeXplorer.xcodeproj └── project.pbxproj ├── HexRaysCodeXplorer ├── CMakeLists.txt ├── CodeXplorer.cpp ├── Common.h ├── Compat.cpp ├── Compat.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 ├── IObjectFormatParser.cpp ├── IObjectFormatParser.h ├── Linux.h ├── MSVCObjectFormatParser.cpp ├── MSVCObjectFormatParser.h ├── Makefile.osx ├── MicrocodeExtractor.cpp ├── MicrocodeExtractor.h ├── ObjectExplorer.cpp ├── ObjectExplorer.h ├── PropertySheet.props ├── ReconstructableType.cpp ├── ReconstructableType.h ├── TypeExtractor.cpp ├── TypeExtractor.h ├── TypeReconstructor.cpp ├── TypeReconstructor.h ├── Utility.cpp ├── Utility.h ├── gcc_rtti_til.h ├── makefile.lnx ├── makefile.mac ├── makefile7.mac ├── reconstructed_place_t.cpp └── reconstructed_place_t.h └── cmake └── FindIdaSdk.cmake /.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 | 19 | # CMake 20 | build/ 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
  2 |  _   _          ______                _____           _     __   __      _                     
  3 | | | | |         | ___ \              /  __ \         | |    \ \ / /     | |                    
  4 | | |_| | _____  _| |_/ /__ _ _   _ ___| /  \/ ___   __| | ___ \ V / _ __ | | ___  _ __ ___ _ __ 
  5 | |  _  |/ _ \ \/ /    // _` | | | / __| |    / _ \ / _` |/ _ \/   \| '_ \| |/ _ \| '__/ _ \ '__|
  6 | | | | |  __/>  <| |\ \ (_| | |_| \__ \ \__/\ (_) | (_| |  __/ /^\ \ |_) | | (_) | | |  __/ |   
  7 | \_| |_/\___/_/\_\_| \_\__,_|\__, |___/\____/\___/ \__,_|\___\/   \/ .__/|_|\___/|_|  \___|_|   
  8 |                              __/ |                                | |                          
  9 |                             |___/                                 |_|
10 | ============================================================================ 11 | 12 | [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) 13 | [![Code Climate](https://codeclimate.com/github/REhints/HexRaysCodeXplorer/badges/gpa.svg)](https://codeclimate.com/github/REhints/HexRaysCodeXplorer) 14 | [![Issue Count](https://codeclimate.com/github/REhints/HexRaysCodeXplorer/badges/issue_count.svg)](https://codeclimate.com/github/REhints/HexRaysCodeXplorer) 15 | 16 | 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: 17 | 18 | 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: 19 | 20 | __Contributors__: 21 | 22 | Alex Matrosov ([@matrosov](https://github.com/matrosov)) 23 | 24 | Eugene Rodionov ([@rodionov](https://github.com/rodionov)) 25 | 26 | Rodrigo Branco ([@rrbranco](https://github.com/rrbranco)) 27 | 28 | Gabriel Barbosa ([@gabrielnb](https://github.com/gabrielnb)) 29 | 30 | __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. 31 | 32 | __Why not IdaPython:__ all code developed on C/C++ because it's more stable way to support complex plugin for Hex-Rays Decompiler. 33 | 34 | __Supported Platforms:__ x86/x64 for Win, Linux and Mac. 35 | 36 | __HexRaysCodeXplorer__ - Hex-Rays Decompiler plugin for easier code navigation. Right-click context menu in the Pseudocode window shows CodeXplorer plugin commands: 37 | 38 | ![1](img/1.jpg) 39 | 40 | :gem: __Here are the main features of the CodeXplorer plugin:__ :gem: 41 | 42 | * ***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: 43 | 44 | ![2](img/2.png) 45 | 46 | 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)”. 47 | 48 | Also CodeXplorer plugin supports auto REconstruction type into IDA local types storage. 49 | 50 | ![6](img/6.png) 51 | 52 | * ***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`. 53 | 54 | ![12](img/12.png) 55 | 56 | * ***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: 57 | 58 | ![3](img/3.png) 59 | 60 | * ***Ctree Item View*** – show ctree representation for highlighted element: 61 | 62 | ![16](img/16.PNG) 63 | 64 | * ***Extract Ctrees to File*** – dump calculate SHA1 hash and dump all ctrees to file. 65 | 66 | ![14](img/14.PNG) 67 | 68 | * ***Extract Types to File*** – dump all types information (include reconstructed types) into file. 69 | 70 | * ***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: 71 | 72 | ![4](img/4.png) 73 | 74 | * ***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. 75 | 76 | ![8](img/8.png) 77 | 78 | * ***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: 79 | 80 | ![5](img/5.png) 81 | 82 | __Object Explorer supports following features:__ 83 | * Auto structures generation for VTBL into IDA local types 84 | 85 | * Navigation in virtual table list and jump to VTBL address into "IDA View" window by click 86 | 87 | * Show hints for current position in virtual table list 88 | 89 | * Shows cross-references list by click into menu on "Show XREFS to VTBL" 90 | 91 | ![11](img/11.png) 92 | 93 | * Support auto parsing RTTI objects: 94 | 95 | ![13](img/13.png) 96 | 97 | __The Batch mode contains following features:__ 98 | 99 | * 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. 100 | 101 | ``` 102 | Example (dump types and ctrees for functions with name prefix "crypto_"): 103 | idaq.exe -OHexRaysCodeXplorer:dump_types:dump_ctrees:CRYPTOcrypto_path_to_idb 104 | ``` 105 | 106 | __Compiling__: 107 | 108 | ***Windows***: 109 | * Open the solution in Visual Studio 110 | * 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) 111 | * Build `Release | x64` and `Release x64 | x64` configurations 112 | 113 | ***Linux***: 114 | * cd src/HexRaysCodeXplorer/ 115 | * IDA_DIR= IDA_SDK= EA64=0 make -f makefile.lnx 116 | * IDA_DIR= IDA_SDK= EA64=0 make -f makefile.lnx install 117 | 118 | ***Mac***: 119 | * cd src/HexRaysCodeXplorer/ 120 | * IDA_DIR= IDA_SDK= make -f makefile.mac 121 | * The Mac makefile might need some hand editing, pull requests welcome! 122 | * IDA 7.0 `.pmc` file extension should be `.dylib` 123 | * 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` 124 | * Or open project in Xcode `HexRaysCodeXplorer.xcodeproj` 125 | 126 | ***With CMake***: 127 | * cd src/HexRaysCodeXplorer/ 128 | * mkdir build && cd build 129 | * cmake .. -DIdaSdk_ROOT_DIR= -DHexRaysSdk_ROOT_DIR= 130 | * cmake --build . --config Release 131 | 132 | ============================================================================ 133 | 134 | __Conference talks about CodeXplorer plugin:__ 135 | * **2015** 136 | * "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) 137 | * "Object Oriented Code RE with HexraysCodeXplorer", NSEC [[slides]](https://github.com/REhints/Publications/raw/master/Conferences/Nsec'2015/nsec_2015.pdf) 138 | * **2014** 139 | * "HexRaysCodeXplorer: object oriented RE for fun and profit", H2HC [[slides]](https://github.com/REhints/Publications/blob/master/Conferences/ZeroNights'2013/ZN_2013_pdf.pdf) 140 | * **2013** 141 | * "HexRaysCodeXplorer: make object-oriented RE easier", ZeroNights [[slides]](https://github.com/REhints/Publications/blob/master/Conferences/ZeroNights'2013/ZN_2013_pdf.pdf) 142 | * "Reconstructing Gapz: Position-Independent Code Analysis Problem", REcon [[slides]](https://github.com/REhints/Publications/blob/master/Conferences/RECON'2013/RECON_2013.pdf) 143 | -------------------------------------------------------------------------------- /bin/Hex-Rays Plugin contest/2013/HexRaysCodeXplorer v1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/Hex-Rays Plugin contest/2013/HexRaysCodeXplorer v1.0.pdf -------------------------------------------------------------------------------- /bin/Hex-Rays Plugin contest/2013/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/Hex-Rays Plugin contest/2013/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/Hex-Rays Plugin contest/2015/Linux/HexRaysCodeXplorer.plx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/Hex-Rays Plugin contest/2015/Linux/HexRaysCodeXplorer.plx -------------------------------------------------------------------------------- /bin/Hex-Rays Plugin contest/2015/Mac/HexRaysCodeXplorer.pmc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/Hex-Rays Plugin contest/2015/Mac/HexRaysCodeXplorer.pmc -------------------------------------------------------------------------------- /bin/Hex-Rays Plugin contest/2015/Mac/HexRaysCodeXplorer.pmc64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/Hex-Rays Plugin contest/2015/Mac/HexRaysCodeXplorer.pmc64 -------------------------------------------------------------------------------- /bin/Hex-Rays Plugin contest/2015/Win/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/Hex-Rays Plugin contest/2015/Win/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /bin/Hex-Rays Plugin contest/2015/Win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/Hex-Rays Plugin contest/2015/Win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/v1.1 [ZeroNights Edition]/win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v1.1 [ZeroNights Edition]/win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/v1.2/win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v1.2/win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/v1.5 [H2HC Edition]/win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v1.5 [H2HC Edition]/win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/v1.6/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v1.6/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /bin/v1.6/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v1.6/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/v1.7 [NSEC15 Edition]/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v1.7 [NSEC15 Edition]/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /bin/v1.7 [NSEC15 Edition]/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v1.7 [NSEC15 Edition]/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA 6.95/Linux/HexRaysCodeXplorer.plx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA 6.95/Linux/HexRaysCodeXplorer.plx -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA 6.95/Linux/HexRaysCodeXplorer.plx64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA 6.95/Linux/HexRaysCodeXplorer.plx64 -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA 6.95/Win/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA 6.95/Win/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA 6.95/Win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA 6.95/Win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA v6.8/Linux/HexRaysCodeXplorer.plx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA v6.8/Linux/HexRaysCodeXplorer.plx -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA v6.8/Mac/HexRaysCodeXplorer.pmc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA v6.8/Mac/HexRaysCodeXplorer.pmc -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA v6.8/Mac/HexRaysCodeXplorer.pmc64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA v6.8/Mac/HexRaysCodeXplorer.pmc64 -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA v6.8/Win/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA v6.8/Win/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA v6.8/Win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA v6.8/Win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA v6.9/Win/HexRaysCodeXplorer.p64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA v6.9/Win/HexRaysCodeXplorer.p64 -------------------------------------------------------------------------------- /bin/v2.0 [BlackHat Edition]/IDA v6.9/Win/HexRaysCodeXplorer.plw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/bin/v2.0 [BlackHat Edition]/IDA v6.9/Win/HexRaysCodeXplorer.plw -------------------------------------------------------------------------------- /img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/1.jpg -------------------------------------------------------------------------------- /img/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/11.png -------------------------------------------------------------------------------- /img/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/12.png -------------------------------------------------------------------------------- /img/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/13.png -------------------------------------------------------------------------------- /img/14.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/14.PNG -------------------------------------------------------------------------------- /img/16.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/16.PNG -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/3.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/4.png -------------------------------------------------------------------------------- /img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/5.png -------------------------------------------------------------------------------- /img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/6.png -------------------------------------------------------------------------------- /img/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/7.png -------------------------------------------------------------------------------- /img/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/8.png -------------------------------------------------------------------------------- /img/m1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/REhints/HexRaysCodeXplorer/0fd0f61dce2ba388a654762c8742d4cb25fae91e/img/m1.png -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29806.167 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HexRaysCodeXplorer", "HexRaysCodeXplorer\HexRaysCodeXplorer.vcxproj", "{F7E6B557-41F3-444A-BCA4-3527547DD665}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug x64|Win32 = Debug x64|Win32 11 | Debug x64|x64 = Debug x64|x64 12 | Debug|Win32 = Debug|Win32 13 | Debug|x64 = Debug|x64 14 | Release x64|Win32 = Release x64|Win32 15 | Release x64|x64 = Release x64|x64 16 | Release|Win32 = Release|Win32 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|Win32.ActiveCfg = Debug x64|x64 21 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|x64.ActiveCfg = Debug x64|x64 22 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug x64|x64.Build.0 = Debug x64|x64 23 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|Win32.ActiveCfg = Debug|x64 24 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|x64.ActiveCfg = Debug|x64 25 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Debug|x64.Build.0 = Debug|x64 26 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|Win32.ActiveCfg = Release x64|x64 27 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|x64.ActiveCfg = Release x64|x64 28 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release x64|x64.Build.0 = Release x64|x64 29 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|Win32.ActiveCfg = Release|x64 30 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|x64.ActiveCfg = Release|x64 31 | {F7E6B557-41F3-444A-BCA4-3527547DD665}.Release|x64.Build.0 = Release|x64 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | GlobalSection(ExtensibilityGlobals) = postSolution 37 | SolutionGuid = {8C949C23-C6D6-418A-9214-CD10668201BC} 38 | VisualSVNWorkingCopyRoot = . 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7) 2 | 3 | project(HexRaysCodeXplorer CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 8 | 9 | if(APPLE) 10 | set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fPIC -arch x86_64") 11 | else() 12 | set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fPIC") 13 | endif() 14 | 15 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake) 16 | 17 | find_package(IdaSdk REQUIRED) 18 | 19 | set(HexRaysSdk_INCLUDE_DIRS ${HexRaysSdk_ROOT_DIR}/include) 20 | 21 | include_directories(${HexRaysSdk_INCLUDE_DIRS}) 22 | include_directories(${PROJECT_SOURCE_DIR}) 23 | 24 | set(src 25 | "CodeXplorer.cpp" 26 | "Common.h" 27 | "Compat.cpp" 28 | "Compat.h" 29 | "CtreeExtractor.cpp" 30 | "CtreeExtractor.h" 31 | "CtreeGraphBuilder.cpp" 32 | "CtreeGraphBuilder.h" 33 | "Debug.cpp" 34 | "Debug.h" 35 | "GCCObjectFormatParser.cpp" 36 | "GCCObjectFormatParser.h" 37 | "GCCTypeInfo.cpp" 38 | "GCCTypeInfo.h" 39 | "GCCVtableInfo.cpp" 40 | "GCCVtableInfo.h" 41 | "IObjectFormatParser.cpp" 42 | "IObjectFormatParser.h" 43 | "Linux.h" 44 | "MSVCObjectFormatParser.cpp" 45 | "MSVCObjectFormatParser.h" 46 | "MicrocodeExtractor.cpp" 47 | "MicrocodeExtractor.h" 48 | "ObjectExplorer.cpp" 49 | "ObjectExplorer.h" 50 | "ReconstructableType.cpp" 51 | "ReconstructableType.h" 52 | "TypeExtractor.cpp" 53 | "TypeExtractor.h" 54 | "TypeReconstructor.cpp" 55 | "TypeReconstructor.h" 56 | "Utility.cpp" 57 | "Utility.h" 58 | "gcc_rtti_til.h" 59 | "reconstructed_place_t.cpp" 60 | "reconstructed_place_t.h") 61 | 62 | add_ida_plugin(HexRaysCodeXplorer ${PROJECT_SOURCE_DIR}/CodeXplorer.cpp) 63 | 64 | set_ida_target_properties(HexRaysCodeXplorer PROPERTIES CXX_STANDARD 17) 65 | ida_target_include_directories(HexRaysCodeXplorer PRIVATE 66 | ${IdaSdk_INCLUDE_DIRS}) 67 | 68 | add_ida_library(HexRaysCodeXplorerLib ${src}) 69 | ida_target_link_libraries(HexRaysCodeXplorer HexRaysCodeXplorerLib) 70 | -------------------------------------------------------------------------------- /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 | #ifdef __MAKEDLL__ 32 | # define DLLEXPORT __declspec(dllexport) 33 | #else 34 | # define DLLEXPORT __declspec(dllimport) 35 | #endif 36 | #else 37 | #define DLLEXPORT 38 | #endif 39 | 40 | 41 | 42 | 43 | #if !defined (__LINUX__) && !defined (__MAC__) 44 | #pragma warning (disable: 4996 4800 ) 45 | #else 46 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 47 | #endif 48 | 49 | #if !defined (__LINUX__) && !defined (__MAC__) 50 | #include 51 | #include 52 | #else 53 | #include "Linux.h" 54 | #endif 55 | 56 | #ifdef __NT__ 57 | #pragma warning(push) 58 | #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 59 | #endif // __NT__ 60 | #ifndef USE_DANGEROUS_FUNCTIONS 61 | #define USE_DANGEROUS_FUNCTIONS 62 | #endif 63 | #ifdef __clang__ 64 | #pragma clang diagnostic push 65 | #pragma clang diagnostic ignored "-Wsign-compare" 66 | #pragma clang diagnostic ignored "-Wvarargs" 67 | #pragma clang diagnostic ignored "-Wlogical-op-parentheses" 68 | #pragma clang diagnostic ignored "-Wunused-private-field" 69 | #endif 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | 92 | 93 | #ifdef __NT__ 94 | #pragma warning(pop) 95 | #endif // __NT__ 96 | #ifdef __clang__ 97 | #pragma clang diagnostic pop 98 | #endif 99 | 100 | #if IDA_SDK_VERSION < 800 101 | #define EA_SIZE sizeof(ea_t) 102 | #else 103 | #define EA_SIZE EAH.ea_size 104 | #endif 105 | 106 | template 107 | struct print1_accepts_qstring 108 | { 109 | template struct yay_sfinae {}; 110 | template static char test(yay_sfinae*); 111 | template static int test(...); 112 | static const bool value = sizeof(test(0)) == sizeof(char); 113 | }; 114 | 115 | // For IDA7.1 and newer 116 | template 117 | void print1wrapper(std::true_type, const T *e, qstring *qbuf, const cfunc_t *func) { 118 | e->print1(qbuf, func); 119 | }; 120 | 121 | // For older SDKs 122 | template 123 | void print1wrapper(std::false_type, const T *e, qstring *qbuf, const cfunc_t *func) { 124 | char lbuf[MAXSTR]; 125 | const size_t len = e->print1(lbuf, sizeof(lbuf) - 1, func); 126 | qstring temp(lbuf, len); 127 | qbuf->swap(temp); 128 | }; 129 | 130 | template 131 | void print1wrapper(const T *e, qstring *qbuf, const cfunc_t *func) { 132 | return print1wrapper( 133 | std::integral_constant::value>(), 134 | e, qbuf, func); 135 | } 136 | 137 | 138 | 139 | #include 140 | #include 141 | #include 142 | 143 | #include 144 | #include 145 | #include 146 | #include 147 | #include 148 | #include 149 | #include 150 | #include 151 | 152 | #endif 153 | 154 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/Compat.cpp: -------------------------------------------------------------------------------- 1 | #include "Compat.h" 2 | #include 3 | #include 4 | 5 | namespace Compat 6 | { 7 | tid_t add_struc(uval_t idx, const char* name, bool is_union) 8 | { 9 | udt_type_data_t udt; 10 | udt.is_union = is_union; 11 | 12 | tinfo_t tif; 13 | tif.create_udt(udt); 14 | tif.set_named_type(nullptr, name); 15 | return tif.get_tid(); 16 | } 17 | 18 | struc_error_t add_struc_member(tid_t sid, const char* fieldname, ea_t offset, flags64_t flag, 19 | const opinfo_t* mt, asize_t nbytes) 20 | { 21 | qstring name_user; 22 | if (fieldname) 23 | qstr2user(&name_user, fieldname); 24 | 25 | idc_value_t result; 26 | idc_value_t args[6] = { sid, name_user, offset, flag, mt ? mt->tid : BADADDR, nbytes }; 27 | call_idc_func(&result, "add_struc_member", args, 6); 28 | return static_cast(result.num); 29 | } 30 | 31 | int get_member_flag(tid_t sid, asize_t offset) 32 | { 33 | idc_value_t result; 34 | idc_value_t args[2] = { sid, offset }; 35 | call_idc_func(&result, "get_member_flag", args, 2); 36 | return result.num; 37 | } 38 | 39 | tid_t get_member_id(tid_t sid, asize_t offset) 40 | { 41 | tinfo_t tif; 42 | if (tif.get_type_by_tid(sid) && tif.is_udt()) 43 | { 44 | udm_t udm; 45 | udm.offset = offset; 46 | 47 | int idx = tif.find_udm(&udm, STRMEM_AUTO); 48 | if (idx != -1) 49 | return tif.get_udm_tid(idx); 50 | } 51 | 52 | return BADADDR; 53 | } 54 | 55 | qstring get_member_name(tid_t sid, asize_t offset) 56 | { 57 | tinfo_t tif; 58 | if (tif.get_type_by_tid(sid) && tif.is_udt()) 59 | { 60 | udm_t udm; 61 | udm.offset = offset; 62 | 63 | int idx = tif.find_udm(&udm, STRMEM_AUTO); 64 | if (idx != -1) 65 | return udm.name; 66 | } 67 | 68 | return qstring(); 69 | } 70 | 71 | asize_t get_member_size(tid_t sid, asize_t offset) 72 | { 73 | tinfo_t tif; 74 | if (tif.get_type_by_tid(sid) && tif.is_udt()) 75 | { 76 | udm_t udm; 77 | udm.offset = offset; 78 | 79 | int idx = tif.find_udm(&udm, STRMEM_AUTO); 80 | if (idx != -1) 81 | return udm.size / 8; 82 | } 83 | 84 | return BADADDR; 85 | } 86 | 87 | bool get_member_tinfo(tinfo_t* tif, tid_t sid, asize_t offset) 88 | { 89 | tinfo_t tif_local; 90 | if (tif_local.get_type_by_tid(sid) && tif_local.is_udt()) 91 | { 92 | udm_t udm; 93 | udm.offset = offset; 94 | 95 | int idx = tif_local.find_udm(&udm, STRMEM_AUTO); 96 | if (idx != -1) 97 | *tif = udm.type; 98 | } 99 | 100 | return false; 101 | } 102 | 103 | ea_t get_struc_first_offset(tid_t id) 104 | { 105 | idc_value_t result; 106 | idc_value_t args[1] = { id }; 107 | call_idc_func(&result, "get_first_member", args, 1); 108 | return result.num; 109 | } 110 | 111 | tid_t get_struc_id(const char* name) 112 | { 113 | tid_t tid = get_named_type_tid(name); 114 | tinfo_t tif; 115 | return tid != BADADDR && tif.get_type_by_tid(tid) && tif.is_udt() ? tid : BADADDR; 116 | } 117 | 118 | qstring get_struc_name(tid_t id) 119 | { 120 | qstring name; 121 | get_tid_name(&name, id); 122 | return name; 123 | } 124 | 125 | ea_t get_struc_next_offset(tid_t id, ea_t offset) 126 | { 127 | idc_value_t result; 128 | idc_value_t args[2] = { id, offset }; 129 | call_idc_func(&result, "get_next_offset", args, 2); 130 | return result.num; 131 | } 132 | 133 | bool set_member_name(tid_t sid, ea_t offset, const char* name) 134 | { 135 | tinfo_t tif; 136 | if (tif.get_type_by_tid(sid) && tif.is_udt()) 137 | { 138 | udm_t udm; 139 | udm.offset = offset; 140 | 141 | int idx = tif.find_udm(&udm, STRMEM_AUTO); 142 | if (idx != -1) 143 | return tif.rename_udm(idx, name) == TERR_OK; 144 | } 145 | 146 | return false; 147 | } 148 | 149 | bool set_member_tinfo(tid_t sid, uval_t memoff, const tinfo_t& tif, int flags) 150 | { 151 | idc_value_t result; 152 | idc_value_t args[5] { sid, memoff, flags, tif.get_tid(), tif.get_size() }; 153 | call_idc_func(&result, "set_member_type", args, 5); 154 | return result.num != 0; 155 | } 156 | 157 | bool set_struc_cmt(tid_t id, const char* cmt, bool repeatable) 158 | { 159 | tinfo_t tif; 160 | return tif.get_type_by_tid(id) && tif.set_type_cmt(cmt, !repeatable) == TERR_OK; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/Compat.h: -------------------------------------------------------------------------------- 1 | // compatibility functions needed for IDA 9.0 support. mostly ported from IDAPython's idc module 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | /// Return values for add_struc_member() 8 | enum struc_error_t 9 | { 10 | STRUC_ERROR_MEMBER_OK = 0, ///< success 11 | STRUC_ERROR_MEMBER_NAME = -1, ///< already has member with this name (bad name) 12 | STRUC_ERROR_MEMBER_OFFSET = -2, ///< already has member at this offset 13 | STRUC_ERROR_MEMBER_SIZE = -3, ///< bad number of bytes or bad sizeof(type) 14 | STRUC_ERROR_MEMBER_TINFO = -4, ///< bad typeid parameter 15 | STRUC_ERROR_MEMBER_STRUCT = -5, ///< bad struct id (the 1st argument) 16 | STRUC_ERROR_MEMBER_UNIVAR = -6, ///< unions can't have variable sized members 17 | STRUC_ERROR_MEMBER_VARLAST = -7, ///< variable sized member should be the last member in the structure 18 | STRUC_ERROR_MEMBER_NESTED = -8, ///< recursive structure nesting is forbidden 19 | }; 20 | 21 | namespace Compat 22 | { 23 | tid_t add_struc(uval_t idx, const char* name, bool is_union = false); 24 | struc_error_t add_struc_member(tid_t sid, const char* fieldname, ea_t offset, flags64_t flag, 25 | const opinfo_t* mt, asize_t nbytes); 26 | int get_member_flag(tid_t sid, asize_t offset); 27 | tid_t get_member_id(tid_t sid, asize_t offset); 28 | qstring get_member_name(tid_t sid, asize_t offset); 29 | asize_t get_member_size(tid_t sid, asize_t offset); 30 | bool get_member_tinfo(tinfo_t* tif, tid_t sid, asize_t offset); 31 | ea_t get_struc_first_offset(tid_t id); 32 | tid_t get_struc_id(const char* name); 33 | qstring get_struc_name(tid_t id); 34 | ea_t get_struc_next_offset(tid_t id, ea_t offset); 35 | bool set_member_name(tid_t sid, ea_t offset, const char* name); 36 | bool set_member_tinfo(tid_t sid, uval_t memoff, const tinfo_t& tif, int flags); 37 | bool set_struc_cmt(tid_t id, const char* cmt, bool repeatable); 38 | 39 | /// \defgroup SET_MEMTI_ Set member tinfo flags 40 | /// Passed as 'flags' parameter to set_member_tinfo() 41 | //@{ 42 | #define SET_MEMTI_MAY_DESTROY 0x0001 ///< may destroy other members 43 | #define SET_MEMTI_COMPATIBLE 0x0002 ///< new type must be compatible with the old 44 | #define SET_MEMTI_FUNCARG 0x0004 ///< mptr is function argument (cannot create arrays) 45 | #define SET_MEMTI_BYTIL 0x0008 ///< new type was created by the type subsystem 46 | #define SET_MEMTI_USERTI 0x0010 ///< user-specified type 47 | //@} 48 | } 49 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/CtreeExtractor.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2020 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 | 46 | bool idaapi ctree_dumper_t::filter_citem(citem_t *item) { 47 | if (item->is_expr()) { 48 | auto expr = static_cast(item); 49 | 50 | if (item->op == cot_cast) 51 | return true; 52 | else if (item->op == cot_helper) 53 | return true; 54 | else if ((item->op >= cot_postinc) && (item->op <= cot_predec)) 55 | return true; 56 | else if ((item->op >= cot_idx) && ((item->op <= cot_last))) 57 | return true; 58 | } else { 59 | if (item->op == cit_expr) 60 | return true; 61 | } 62 | 63 | return false; 64 | } 65 | 66 | void ctree_dumper_t::process_for_hash(citem_t *item) 67 | { 68 | if (!filter_citem(item)) { 69 | const char* ctype_name = get_ctype_name(item->op); 70 | ctree_for_hash.cat_sprnt("%s:", ctype_name); 71 | } 72 | } 73 | 74 | // Process a ctree item 75 | int ctree_dumper_t::process(citem_t *item) 76 | { 77 | size_t parent_count = parents.size(); 78 | if (parent_count > 1) { 79 | ctree_dump += "("; 80 | } 81 | 82 | qstring buf; 83 | parse_ctree_item(item, buf); 84 | ctree_dump += buf; 85 | 86 | process_for_hash(item); 87 | return 0; 88 | } 89 | 90 | int ctree_dumper_t::process_leave(citem_t *item) 91 | { 92 | size_t parent_count = parents.size(); 93 | if (parent_count > 1) { 94 | ctree_dump += ")"; 95 | } 96 | return 0; 97 | } 98 | 99 | void ctree_dumper_t::parse_ctree_item(citem_t *item, qstring& rv) const 100 | { 101 | rv.clear(); 102 | // Each node will have the element type at the first line 103 | if (const auto v = get_ctype_name(item->op)) 104 | rv = v; 105 | 106 | const auto e = static_cast(item); 107 | const auto i = static_cast(item); 108 | 109 | // For some item types, display additional information 110 | qstring func_name; 111 | qstring s; 112 | switch (item->op) 113 | { 114 | case cot_call: 115 | if (e->x->op == cot_obj) { 116 | if (get_func_name(&func_name, e->x->obj_ea) == 0) 117 | rv.cat_sprnt(" sub_%a", e->x->obj_ea); 118 | else 119 | rv.cat_sprnt(" %s", func_name.c_str()); 120 | } 121 | break; 122 | case cot_ptr: // *x 123 | case cot_memptr: // x->m 124 | // Display access size for pointers 125 | rv.cat_sprnt(".%d", e->ptrsize); 126 | if (item->op == cot_ptr) 127 | break; 128 | case cot_memref: // x.m 129 | // Display member offset for structure fields 130 | rv.cat_sprnt(" (m=%d)", e->m); 131 | break; 132 | case cot_obj: // v 133 | case cot_var: // l 134 | // Display object size for local variables and global data 135 | rv.cat_sprnt(".%d", e->refwidth); 136 | case cot_num: // n 137 | case cot_helper: // arbitrary name 138 | case cot_str: // string constant 139 | // Display helper names and number values 140 | rv.append(' '); 141 | { 142 | qstring qbuf; 143 | print1wrapper(e, &qbuf, nullptr); 144 | tag_remove(&qbuf); 145 | rv += qbuf; 146 | } 147 | break; 148 | case cit_goto: 149 | // Display target label number for gotos 150 | rv.cat_sprnt(" LABEL_%d", i->cgoto->label_num); 151 | break; 152 | case cit_asm: 153 | // Display instruction block address and size for asm-statements 154 | rv.cat_sprnt(" %a.%" FMT_Z, *i->casm->begin(), i->casm->size()); 155 | break; 156 | default: 157 | break; 158 | } 159 | 160 | // The second line of the node contains the item address 161 | rv.cat_sprnt(";ea->%a", item->ea); 162 | 163 | if ( item->is_expr() && !e->type.empty() ) 164 | { 165 | // For typed expressions, the third line will have 166 | // the expression type in human readable form 167 | rv.append(';'); 168 | qstring out; 169 | if (e->type.print(&out)) 170 | { 171 | rv += out; 172 | } 173 | else 174 | { // could not print the type? 175 | rv.append('?'); 176 | } 177 | 178 | if(e->type.is_ptr()) 179 | { 180 | const auto ptr_rem = ::remove_pointer(e->type); 181 | if(ptr_rem.is_struct()) 182 | { 183 | qstring typenm; 184 | ptr_rem.print(&typenm, "prefix ", 0, 0, PRTYPE_MULTI | PRTYPE_TYPE | PRTYPE_SEMI); 185 | } 186 | } 187 | } 188 | 189 | } 190 | 191 | struct ctree_dump_line { 192 | qvector referres; 193 | qstring ctree_for_hash; 194 | qstring ctree_dump; 195 | qstring func_name; 196 | int func_depth{}; 197 | ea_t func_start{}; 198 | ea_t func_end{}; 199 | bool heuristic_flag{}; 200 | }; 201 | 202 | struct ctree_dump_line_impl : ctree_dump_line 203 | { 204 | }; 205 | 206 | 207 | int create_open_file(const char* file_name) { 208 | auto file_id = qopen(file_name, O_BINARY | O_TRUNC | O_CREAT); 209 | if (file_id == BADADDR) 210 | file_id = qcreate(file_name, 511); 211 | 212 | return file_id; 213 | } 214 | 215 | int get_hash_of_string(const qstring &string_to_hash, qstring &hash) { 216 | SHA1Context sha; 217 | uint8_t message_digest[SHA1HashSize]; 218 | 219 | auto err = SHA1Reset(&sha); 220 | if (err == shaSuccess) { 221 | err = SHA1Input(&sha, (uint8_t *)string_to_hash.c_str(), static_cast(string_to_hash.length())); 222 | if (err == shaSuccess) { 223 | err = SHA1Result(&sha, message_digest); 224 | if (err == shaSuccess) { 225 | char digest_hex[SHA1HashSize * 2 + 1]; 226 | memset(digest_hex, 0x00, sizeof(digest_hex)); 227 | SHA1MessageDigestToString(message_digest, digest_hex); 228 | 229 | hash = digest_hex; 230 | } 231 | } 232 | } 233 | 234 | return err; 235 | } 236 | 237 | void dump_ctrees_in_file(std::map &data_to_dump, const qstring &crypto_prefix) { 238 | const auto file_id = create_open_file("ctrees.txt"); 239 | if (file_id == -1) 240 | { 241 | logmsg(ERROR, "Failed to open file for dumping ctress\r\n"); 242 | return; 243 | } 244 | 245 | size_t crypt_prefix_len = crypto_prefix.length(); 246 | 247 | for (auto ctrees_iter = data_to_dump.begin(); ctrees_iter != data_to_dump.end(); ++ctrees_iter) { 248 | const auto& cdl = ctrees_iter->second; 249 | 250 | qstring sha_hash; 251 | auto err = get_hash_of_string(cdl.ctree_for_hash, sha_hash); 252 | if (err != shaSuccess) { 253 | logmsg(ERROR, "Error in computing SHA1 hash\r\n"); 254 | continue; 255 | } 256 | 257 | auto dump_line = sha_hash + ";"; 258 | err = get_hash_of_string(cdl.ctree_dump, sha_hash); 259 | if (err != shaSuccess) { 260 | logmsg(ERROR, "Error in computing SHA1 hash\r\n"); 261 | continue; 262 | } 263 | dump_line += sha_hash + ";"; 264 | dump_line += cdl.ctree_dump; 265 | dump_line.cat_sprnt(";%d", cdl.func_depth); 266 | dump_line.cat_sprnt(";%08X", cdl.func_start); 267 | dump_line.cat_sprnt(";%08X", cdl.func_end); 268 | if ((cdl.func_name.length() > crypt_prefix_len) && (crypt_prefix_len > 0) && (cdl.func_name.find(crypto_prefix) == 0)) 269 | dump_line.cat_sprnt(";E"); 270 | else 271 | dump_line.cat_sprnt(";N"); 272 | 273 | if ((cdl.heuristic_flag)) 274 | dump_line.cat_sprnt(";H"); 275 | else 276 | dump_line.cat_sprnt(";N"); 277 | 278 | dump_line += "\n"; 279 | 280 | qwrite(file_id, dump_line.c_str(), dump_line.length()); 281 | } 282 | 283 | qclose(file_id); 284 | } 285 | 286 | 287 | inline bool func_name_has_prefix(const qstring &prefix, const ea_t start_ea) { 288 | if (prefix.length() <= 0) 289 | return false; 290 | 291 | qstring func_name; 292 | if (get_func_name(&func_name, start_ea) <= 0) 293 | return false; 294 | 295 | if (func_name.empty()) 296 | return false; 297 | 298 | return func_name.find(prefix.c_str(), 0) == 0; 299 | } 300 | 301 | bool idaapi dump_funcs_ctree(void *ud, const qstring &crypto_prefix) 302 | { 303 | logmsg(DEBUG, "dump_funcs_ctree entered\n"); 304 | 305 | std::map data_to_dump; 306 | 307 | size_t count = 0, heur_count = 0, crypto_count = 0; 308 | size_t total_func_qty = get_func_qty(); 309 | for (size_t i = 0 ; i < total_func_qty ; i ++) { 310 | auto heuristic_flag = false; 311 | 312 | func_t *function = getn_func(i); 313 | if (function != nullptr) { 314 | bool crypto_flag = func_name_has_prefix(crypto_prefix, function->start_ea); 315 | 316 | // skip libs that are not marked as crypto 317 | if ( ((function->flags & FUNC_LIB) != 0) && !crypto_flag ) 318 | continue; 319 | 320 | // From this point on, we have a function outside of lib or a crypto one 321 | 322 | // Ignore functions less than MIN_FUNC_SIZE_DUMP bytes 323 | if ( ((function->end_ea - function->start_ea) < MIN_FUNC_SIZE_DUMP) && !crypto_flag ) 324 | continue; 325 | 326 | // If function is bigger than MIN_HEURISTIC_FUNC_SIZE_DUMP, mark as being triggered by the heuristic 327 | if (function->end_ea - function->start_ea > MIN_HEURISTIC_FUNC_SIZE_DUMP) 328 | heuristic_flag = true; 329 | 330 | // dump up to N_CRYPTO_FUNCS_TO_DUMP crypto functions 331 | // dump up to N_HEUR_FUNCS_TO_DUMP heuristic functions 332 | // at least N_FUNCS_TO_DUMP functions will be dumped 333 | if ((count < N_FUNCS_TO_DUMP) || (crypto_flag && (crypto_count < N_CRYPTO_FUNCS_TO_DUMP)) || (heuristic_flag && (heur_count < N_HEUR_FUNCS_TO_DUMP))) { 334 | hexrays_failure_t hf; 335 | cfuncptr_t cfunc = decompile(function, &hf); 336 | 337 | logmsg(DEBUG, "\nafter decompile()\n"); 338 | if (cfunc != nullptr) { 339 | ctree_dumper_t ctree_dumper; 340 | ctree_dumper.apply_to(&cfunc->body, nullptr); 341 | 342 | ctree_dump_line func_dump; 343 | func_dump.ctree_dump = ctree_dumper.ctree_dump; 344 | func_dump.ctree_for_hash = ctree_dumper.ctree_for_hash; 345 | 346 | func_dump.func_depth = -1; 347 | 348 | func_dump.func_start = function->start_ea; 349 | func_dump.func_end = function->end_ea; 350 | 351 | qstring func_name; 352 | if (get_func_name(&func_name, function->start_ea) != 0) { 353 | if (func_name.length() > 0) { 354 | func_dump.func_name = func_name; 355 | } 356 | } 357 | 358 | func_parent_iterator_t fpi(function); 359 | for (ea_t addr = get_first_cref_to(function->start_ea); addr != BADADDR; addr = get_next_cref_to(function->start_ea, addr)) { 360 | func_t *referer = get_func(addr); 361 | if (referer != nullptr) { 362 | func_dump.referres.push_back(referer->start_ea); 363 | } 364 | } 365 | 366 | func_dump.heuristic_flag = heuristic_flag; // 0 or 1 depending on code above 367 | if (heuristic_flag) 368 | heur_count++; 369 | 370 | if (crypto_flag) 371 | crypto_count++; 372 | 373 | count++; 374 | 375 | data_to_dump[function->start_ea] = func_dump; 376 | } 377 | } 378 | } 379 | } 380 | 381 | dump_ctrees_in_file(data_to_dump, crypto_prefix); 382 | 383 | return true; 384 | } 385 | 386 | bool idaapi extract_all_ctrees(void *ud) 387 | { 388 | // default prefix to display in the dialog 389 | static const qstring kDefaultPrefix = "crypto_"; 390 | 391 | va_list va; 392 | va_end(va); 393 | 394 | auto crypto_prefix = kDefaultPrefix; 395 | if (!ask_str(&crypto_prefix, 0, "Enter prefix of crypto function names", va)) 396 | return false; 397 | 398 | if(!crypto_prefix.empty()) { 399 | dump_funcs_ctree(nullptr, crypto_prefix); 400 | } else { 401 | warning("Incorrect prefix!!"); 402 | } 403 | 404 | return true; 405 | } 406 | 407 | 408 | // Ctree Item Form Init 409 | struct func_ctree_info_t 410 | { 411 | TWidget *widget; 412 | TWidget *cv; 413 | TWidget *codeview; 414 | strvec_t sv; 415 | explicit func_ctree_info_t(TWidget *f) : widget(f), cv(nullptr), codeview(nullptr){} 416 | }; 417 | 418 | 419 | bool idaapi show_citem_custom_view(void *ud, const qstring& ctree_item, const qstring& item_name) 420 | { 421 | qstring form_name = "Ctree Item View: "; 422 | form_name.append(item_name); 423 | const auto widget = create_empty_widget(form_name.c_str()); 424 | auto si = new func_ctree_info_t(widget); 425 | 426 | istringstream s_citem_str(ctree_item.c_str()); 427 | string tmp_str; 428 | while (getline(s_citem_str, tmp_str, ';')) 429 | { 430 | qstring tmp_qstr = tmp_str.c_str(); 431 | si->sv.push_back(simpleline_t(tmp_qstr)); 432 | } 433 | 434 | simpleline_place_t s1; 435 | simpleline_place_t s2(static_cast(ctree_item.size())); 436 | si->cv = create_custom_viewer("", &s1, &s2, &s1, nullptr, &si->sv, nullptr, nullptr, widget); 437 | si->codeview = create_code_viewer(si->cv, CDVF_NOLINES, widget); 438 | set_custom_viewer_handlers(si->cv, nullptr, si); 439 | display_widget(widget, WOPN_RESTORE); 440 | 441 | return false; 442 | } 443 | 444 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/CtreeExtractor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2020 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 final : 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) override { return process(i); } 42 | int idaapi visit_expr(cexpr_t *e) override { 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) override { return process_leave(i); } 45 | int idaapi leave_expr(cexpr_t *e) override { return process_leave(e); } 46 | static 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-2020 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 | const ea_int_map_t::const_iterator it = ea2node_.find(i); 39 | if (it != ea2node_.end()) 40 | { 41 | if (nid != nullptr) 42 | *nid = it->second; 43 | return true; 44 | } 45 | return false; 46 | } 47 | 48 | 49 | void callgraph_t::create_edge(const int id1, const 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 | const auto 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 | const auto ctype_name = get_ctype_name(item->op); 66 | if (ctype_name) 67 | rv = ctype_name; 68 | 69 | const auto e = static_cast(item); 70 | const auto i = static_cast(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 | const auto 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 = nullptr; 156 | 157 | do 158 | { 159 | // returned cached name 160 | auto 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 | const int_ea_map_t::const_iterator it_ea = node2ea_.find(nid); 169 | if (it_ea == node2ea_.end()) 170 | break; 171 | 172 | const auto pfn = it_ea->second; 173 | if (!pfn) 174 | break; 175 | 176 | nodeinfo_t fi; 177 | 178 | // get name 179 | qstring node_label; 180 | get_node_label(nid, node_label); 181 | if (!node_label.empty()) 182 | fi.name = node_label; 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 | const auto 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(const ea_t func_ea, citem_t *highlighted) 258 | { 259 | const auto pfn = get_func(func_ea); 260 | if (!pfn) 261 | return nullptr; 262 | 263 | auto 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(const 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(auto 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-2020 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(const int i1, const 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 | /* Copyright (c) 2013-2020 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 | 27 | 28 | #include "GCCObjectFormatParser.h" 29 | #include "Common.h" 30 | #include "entry.hpp" 31 | #include "Debug.h" 32 | #include "demangle.hpp" 33 | #include "name.hpp" 34 | #include "offset.hpp" 35 | #include "nalt.hpp" 36 | #include "bytes.hpp" 37 | #include "Utility.h" 38 | #include "stddef.h" 39 | #include "GCCVtableInfo.h" 40 | #include "GCCTypeInfo.h" 41 | #include "Debug.h" 42 | #include "ReconstructableType.h" 43 | #include 44 | 45 | #define vmi_class_type_info_name "_ZTVN10__cxxabiv121__vmi_class_type_infoE" 46 | #define class_type_info_name "_ZTVN10__cxxabiv117__class_type_infoE" 47 | #define si_class_type_info_name "_ZTVN10__cxxabiv120__si_class_type_infoE" 48 | 49 | std::unordered_mapg_KnownVtables; 50 | std::unordered_mapg_KnownTypes; 51 | std::unordered_mapg_KnownVtableNames; 52 | std::unordered_mapg_KnownTypeNames; 53 | 54 | ea_t class_type_info_vtbl = -1; 55 | ea_t si_class_type_info_vtbl = -1; 56 | ea_t vmi_class_type_info_vtbl = -1; 57 | 58 | static void buildReconstructableTypes(); 59 | 60 | GCCObjectFormatParser::GCCObjectFormatParser() 61 | { 62 | } 63 | 64 | GCCObjectFormatParser::~GCCObjectFormatParser() 65 | { 66 | } 67 | 68 | 69 | static int import_enum_cb(ea_t ea, const char *name, uval_t ord, void *param) { 70 | if (name == 0) 71 | return 1; 72 | ea += sizeof(GCC_RTTI::__vtable_info); // BUG From IDA. Hello funny imports. 73 | if (class_type_info_vtbl == BADADDR && !memcmp(class_type_info_name, name, sizeof(class_type_info_name) - 1)) 74 | { 75 | class_type_info_vtbl = ea; 76 | set_name(class_type_info_vtbl, "__cxxabiv1::__class_type_info::vtable", SN_NOWARN); 77 | } 78 | 79 | if (si_class_type_info_vtbl == BADADDR && !memcmp(si_class_type_info_name, name, sizeof(si_class_type_info_name) - 1)) 80 | { 81 | si_class_type_info_vtbl = ea; 82 | set_name(si_class_type_info_vtbl, "__cxxabiv1::__si_class_type_info::vtable", SN_NOWARN); 83 | } 84 | 85 | if (vmi_class_type_info_vtbl == BADADDR && !memcmp(vmi_class_type_info_name, name, sizeof(vmi_class_type_info_name) - 1)) 86 | { 87 | vmi_class_type_info_vtbl = ea; 88 | set_name(vmi_class_type_info_vtbl, "__cxxabiv1::__vmi_class_type_info::vtable", SN_NOWARN); 89 | } 90 | 91 | return 1; 92 | } 93 | 94 | static int __get_ea_of_name(size_t index, ea_t *value) { 95 | ea_t ea = get_nlist_ea(index); 96 | if (ea == BADADDR) 97 | return -1; 98 | *value = ea; 99 | return 0; 100 | } 101 | 102 | static int find_vtbls_by_names(bool force) { 103 | size_t cnt = get_nlist_size(); 104 | unsigned int found_vtbls = 0; 105 | ea_t ea; 106 | 107 | if (force) 108 | class_type_info_vtbl = si_class_type_info_vtbl = vmi_class_type_info_vtbl = BADADDR; 109 | else { 110 | if (class_type_info_vtbl != BADADDR) 111 | ++found_vtbls; 112 | if (si_class_type_info_vtbl != BADADDR) 113 | ++found_vtbls; 114 | if (vmi_class_type_info_vtbl != BADADDR) 115 | ++found_vtbls; 116 | } 117 | for (size_t i = 0; i < cnt && found_vtbls < 3; ++i) { 118 | const char *name = get_nlist_name(i); 119 | if (name && memcmp(name, "_ZTVN10__cxxabiv", sizeof("_ZTVN10__cxxabiv")-1) == 0) { 120 | if (class_type_info_vtbl == BADADDR) 121 | if (memcmp(name, class_type_info_name, sizeof(class_type_info_name)-1) == 0) 122 | if (!__get_ea_of_name(i, &ea)) 123 | { 124 | ea += sizeof(GCC_RTTI::__vtable_info); 125 | class_type_info_vtbl = ea; 126 | ++found_vtbls; 127 | continue; 128 | } 129 | if (si_class_type_info_vtbl == BADADDR) 130 | if (memcmp(name, si_class_type_info_name, sizeof(si_class_type_info_name)-1) == 0) 131 | if (!__get_ea_of_name(i, &ea)) 132 | { 133 | ea += sizeof(GCC_RTTI::__vtable_info); 134 | si_class_type_info_vtbl = ea; 135 | ++found_vtbls; 136 | continue; 137 | } 138 | if (vmi_class_type_info_vtbl == BADADDR) 139 | if (memcmp(name, vmi_class_type_info_name, sizeof(vmi_class_type_info_name)-1) == 0) 140 | if (!__get_ea_of_name(i, &ea)) 141 | { 142 | ea += sizeof(GCC_RTTI::__vtable_info); 143 | vmi_class_type_info_vtbl = ea; 144 | ++found_vtbls; 145 | continue; 146 | } 147 | } 148 | } 149 | return 0; 150 | } 151 | 152 | int GCCObjectFormatParser::collect_info_vtbls(bool force) { 153 | size_t count = get_entry_qty(); 154 | qstring buffer; 155 | 156 | /* We already know some values, so lets omit the search. */ 157 | if (!force && (class_type_info_vtbl != -1 || 158 | si_class_type_info_vtbl != -1 || 159 | vmi_class_type_info_vtbl != -1)) 160 | return 0; 161 | 162 | if (force) { 163 | class_type_info_vtbl = si_class_type_info_vtbl = vmi_class_type_info_vtbl = BADADDR; 164 | } 165 | for (int i = 0; i < count; ++i) { 166 | uval_t ordinal = get_entry_ordinal(i); 167 | get_entry_name(&buffer, ordinal); 168 | ea_t ea = get_entry(ordinal); 169 | ea += sizeof(GCC_RTTI::__vtable_info); 170 | 171 | if (class_type_info_vtbl == BADADDR && !memcmp(class_type_info_name, buffer.c_str(), sizeof(class_type_info_name) - 1)) 172 | { 173 | class_type_info_vtbl = ea; 174 | set_name(ea, "__cxxabiv1::__class_type_info::vtable", SN_NOWARN); 175 | } 176 | 177 | if (si_class_type_info_vtbl == BADADDR && !memcmp(si_class_type_info_name, buffer.c_str(), sizeof(si_class_type_info_name) - 1)) 178 | { 179 | si_class_type_info_vtbl = ea; 180 | set_name(ea, "__cxxabiv1::__si_class_type_info::vtable", SN_NOWARN); 181 | } 182 | 183 | if (vmi_class_type_info_vtbl == BADADDR && !memcmp(vmi_class_type_info_name, buffer.c_str(), sizeof(vmi_class_type_info_name) - 1)) 184 | { 185 | vmi_class_type_info_vtbl = ea; 186 | set_name(ea, "__cxxabiv1::__vmi_class_type_info::vtable", SN_NOWARN); 187 | } 188 | } 189 | 190 | count = get_import_module_qty(); 191 | for (uint index = 0; index < count; ++index) 192 | enum_import_names(index, &import_enum_cb, this); 193 | 194 | find_vtbls_by_names(false); 195 | 196 | 197 | if (class_type_info_vtbl == -1 && 198 | si_class_type_info_vtbl == -1 && 199 | vmi_class_type_info_vtbl == -1) 200 | return -1; 201 | return 0; 202 | } 203 | 204 | void GCCObjectFormatParser::get_rtti_info() 205 | { 206 | collect_info_vtbls(); 207 | if (class_type_info_vtbl == -1 && 208 | si_class_type_info_vtbl == -1 && 209 | vmi_class_type_info_vtbl == -1) 210 | return; 211 | // if no any rtti vtables, we cant read it. 212 | // now we can scan segments for vtables. 213 | int segCount = get_segm_qty(); 214 | for (int i = 0; i < segCount; i++) 215 | { 216 | if (segment_t *seg = getnseg(i)) 217 | { 218 | if (seg->type == SEG_DATA) 219 | { 220 | scanSeg4Vftables(seg); 221 | } 222 | } 223 | } 224 | 225 | buildReconstructableTypes(); 226 | } 227 | 228 | void GCCObjectFormatParser::scanSeg4Vftables(segment_t *seg) 229 | { 230 | size_t size = (std::max)(sizeof(GCC_RTTI::__vtable_info), sizeof(GCC_RTTI::type_info)); 231 | unsigned char buffer[(std::max)(sizeof(GCC_RTTI::__vtable_info), sizeof(GCC_RTTI::type_info))]; 232 | 233 | ea_t startEA = ((seg->start_ea + EA_SIZE) & ~((ea_t)(EA_SIZE - 1))); 234 | ea_t endEA = (seg->end_ea - EA_SIZE); 235 | ea_t ea = startEA; 236 | while (ea < endEA) 237 | { 238 | if (g_KnownTypes.count(ea)) { 239 | ea += g_KnownTypes[ea]->size; 240 | continue; 241 | } 242 | 243 | if (g_KnownVtables.count(ea)) { 244 | ea = g_KnownVtables[ea]->ea_end; 245 | continue; 246 | } 247 | if (!get_bytes(buffer, size, ea)) { 248 | ea += EA_SIZE; 249 | continue; 250 | } 251 | 252 | GCC_RTTI::type_info *ti = (GCC_RTTI::type_info *)buffer; 253 | GCC_RTTI::__vtable_info *vt = (GCC_RTTI::__vtable_info *)buffer; 254 | // do some sanity checks if it looks like a Virtual Table 255 | if (vt->ptrdiff == 0) { 256 | GCCTypeInfo *type = GCCTypeInfo::parseTypeInfo(vt->type_info); 257 | if (type != 0) { 258 | GCCVtableInfo * info = GCCVtableInfo::parseVtableInfo(ea); 259 | if (info) 260 | { 261 | VTBL_info_t vtbl_info; 262 | vtbl_info.ea_begin = info->ea_start + sizeof(GCC_RTTI::__vtable_info); 263 | vtbl_info.ea_end = info->ea_end; 264 | vtbl_info.vtbl_name = info->typeName.c_str(); 265 | vtbl_info.methods = info->vtables[0].methodsCount; 266 | rtti_vftables[ea + sizeof(GCC_RTTI::__vtable_info)] = vtbl_info; 267 | ea = info->ea_end; 268 | continue; 269 | } 270 | 271 | } 272 | } 273 | 274 | GCCTypeInfo *typeInfo = GCCTypeInfo::parseTypeInfo(ea); 275 | if (typeInfo) 276 | ea += typeInfo->size; 277 | else 278 | ea += EA_SIZE; 279 | } 280 | return; 281 | } 282 | 283 | void GCCObjectFormatParser::clear_info() 284 | { 285 | g_KnownVtables.clear(); 286 | g_KnownVtableNames.clear(); 287 | g_KnownTypes.clear(); 288 | g_KnownTypeNames.clear(); 289 | assert(false); // reasonable question what to do with ReconstructableTypes. 290 | } 291 | 292 | void buildReconstructableTypesRecursive(GCCTypeInfo *type, std::set &visitedTypes) { 293 | if (visitedTypes.count(type)) 294 | return; 295 | // Handle parents first 296 | if (type->parentsCount) 297 | { 298 | for (unsigned long i = 0; i < type->parentsCount; ++i) { 299 | GCCParentType * parent = type->parentsTypes[i]; 300 | buildReconstructableTypesRecursive(parent->info, visitedTypes); 301 | } 302 | } 303 | 304 | ReconstructableType *reType; 305 | if (g_ReconstractedTypes.count(type->typeName)) { 306 | reType = g_ReconstractedTypes[type->typeName]; 307 | return; 308 | } 309 | else { 310 | reType = ReconstructableType::getReconstructableType(type->typeName); 311 | reType->SyncTypeInfo(); 312 | } 313 | 314 | if (type->vtable) // type has vtable; 315 | { 316 | GCCVtableInfo *vtblInfo = type->vtable; 317 | std::string vtbl_class_name = type->typeName + VTBL_CLSNAME_POSTFIX; 318 | if (g_ReconstractedTypes.count(vtbl_class_name)) { 319 | assert(false); // one more assert for the future 320 | } 321 | char buffer[256]; 322 | 323 | for (unsigned int i = 0; i < vtblInfo->vtablesCount; ++i) { 324 | unsigned int offset = (unsigned int)(-(signed int)vtblInfo->vtables[i].ptrDiff); 325 | std::string parentName = vtblInfo->vtables[i].name.c_str(); 326 | std::string vtblName = vtbl_class_name; 327 | if (i != 0) { 328 | snprintf(buffer, sizeof(buffer), "%s_%x_of_%s", vtbl_class_name.c_str(), offset, parentName.c_str()); 329 | vtblName = buffer; 330 | } 331 | ReconstructableType * reVtbl = ReconstructableTypeVtable::get_reconstructable_type_vtable(vtblName, vtblInfo->ea_start); 332 | if (i != 0) { 333 | ReconstructableType *parent; 334 | if (g_ReconstractedTypes.count(type->parentsTypes[i]->info->typeName)) 335 | { 336 | parent = g_ReconstractedTypes[type->parentsTypes[i]->info->typeName]; 337 | std::map pmembers = parent->getOwnMembers(); 338 | if (parent->getSize() < sizeof(uval_t)) { 339 | ReconstructableType *parentVtbl = ReconstructableType::getReconstructableType(parent->name + VTBL_CLSNAME_POSTFIX); 340 | if (parentVtbl->getSize() < vtblInfo->vtables[i].methodsCount) { 341 | for (unsigned int methodIndx = parentVtbl->getSize(); methodIndx < vtblInfo->vtables[i].methodsCount; ++methodIndx) 342 | { 343 | ReconstructableMember *pmethod = new ReconstructableMember(); 344 | pmethod->name = "purecall"; 345 | pmethod->name += std::to_string(methodIndx); 346 | pmethod->offset = methodIndx * sizeof(uval_t); 347 | tinfo_t info = dummy_ptrtype(sizeof(uval_t), 0); 348 | pmethod->memberType = new MemberTypeIDATypeInfoGate(info); 349 | parentVtbl->AddMember(pmethod); 350 | } 351 | } 352 | ReconstructableMember *pmember = new ReconstructableMember(); 353 | pmember->name = "vtable"; 354 | pmember->offset = 0; 355 | pmember->memberType = new MemberTypePointer(parentVtbl->name); 356 | parent->AddMember(pmember); 357 | } 358 | } 359 | } 360 | 361 | 362 | for (unsigned int j = 0; j < vtblInfo->vtables[i].methodsCount; ++j) { 363 | ReconstructableMember *member = new ReconstructableMember(); 364 | member->offset = sizeof(uval_t)*j; 365 | ea_t funcPtr = getEa(vtblInfo->vtables[i].ea + sizeof(uval_t)*j + sizeof(GCC_RTTI::__vtable_info)); 366 | if (funcPtr == 0) { 367 | member->name = "purecall"; 368 | member->name += std::to_string(j); 369 | } 370 | 371 | else { 372 | if (PH.id == PLFM_ARM) 373 | funcPtr &= (ea_t)-2; 374 | qstring method_name; 375 | get_ea_name(&method_name, funcPtr); 376 | if (method_name.find("sub_", 0) == 0 || method_name.length() == 0) { 377 | // we can rename it. 378 | qstring newName; 379 | newName.sprnt("%s::refunc_%x", type->typeName.c_str(), funcPtr); 380 | if (set_name(funcPtr, newName.c_str(), SN_NOWARN)) { 381 | method_name = newName; 382 | } 383 | } 384 | if (method_name.length() == 0) 385 | method_name.sprnt("___refunc_%x", funcPtr); 386 | member->name = method_name.c_str(); 387 | } 388 | 389 | tinfo_t info = dummy_ptrtype(sizeof(uval_t), 0); 390 | member->memberType = new MemberTypeIDATypeInfoGate(info); 391 | reVtbl->AddMember(member); 392 | } 393 | if (i == 0) { 394 | // add vtable info 395 | ReconstructableMember *member = new ReconstructableMember(); 396 | member->name = "vtable"; 397 | member->offset = 0; 398 | member->memberType = new MemberTypePointer(vtbl_class_name); 399 | reType->AddMember(member); 400 | } 401 | if (i < type->parentsCount && g_ReconstractedTypes.count(type->parentsTypes[i]->info->typeName + VTBL_CLSNAME_POSTFIX)) { 402 | 403 | ReconstructableType *parentVtbl = g_ReconstractedTypes[type->parentsTypes[i]->info->typeName + VTBL_CLSNAME_POSTFIX]; 404 | 405 | ReconstructableMember *dmember = new ReconstructableMember(); 406 | dmember->name = parentVtbl->name; 407 | dmember->offset = 0; 408 | dmember->memberType = new ReconstructedMemberReType(parentVtbl); 409 | reVtbl->AddDerivedMember(dmember); 410 | } 411 | reVtbl->SyncTypeInfo(); 412 | // we have vtable, we have it as structure, lets apply its name and type to IDB 413 | if (i == 0) { 414 | std::string idb_name = type->typeName + "::_vftable"; 415 | ea_t ea = vtblInfo->vtables[0].ea + 2 * sizeof(uval_t); 416 | setUnknown(ea, vtblInfo->vtables[0].methodsCount * sizeof(uval_t)); 417 | MakeName(ea, idb_name.c_str()); 418 | tinfo_t tinfo; 419 | if (tinfo.get_named_type(get_idati(), reVtbl->name.c_str())) { 420 | apply_tinfo(ea, tinfo, TINFO_DEFINITE); 421 | } 422 | } 423 | } 424 | } 425 | for (unsigned int i = 0; i < type->parentsCount; ++i) { 426 | assert(g_ReconstractedTypes.count(type->parentsTypes[i]->info->typeName)); 427 | ReconstructableType *parent = g_ReconstractedTypes[type->parentsTypes[i]->info->typeName]; 428 | type->parentsTypes[i]; 429 | ReconstructableMember* member = new ReconstructableMember(); 430 | member->offset = type->parentsTypes[i]->offset; 431 | member->name = type->parentsTypes[i]->info->typeName; 432 | member->memberType = new ReconstructedMemberReType(parent); 433 | reType->AddDerivedMember(member); 434 | } 435 | visitedTypes.emplace(type); 436 | } 437 | 438 | 439 | void fixupRecounstructableTypesId() { 440 | unsigned long id = 0; 441 | for (auto iterator = g_ReconstractedTypes.begin(); iterator != g_ReconstractedTypes.end(); iterator++, id++) 442 | { 443 | iterator->second->id = id; 444 | } 445 | } 446 | 447 | static void buildReconstructableTypes() { 448 | std::set visitedTypes; 449 | SyncTypeInfoMethod curMethod = syncTypeInfoMethod; 450 | syncTypeInfoMethod = SyncTypeInfo_Names; 451 | std::unordered_map::iterator typesIterator; 452 | for (typesIterator = g_KnownTypes.begin(); typesIterator != g_KnownTypes.end(); ++typesIterator) { 453 | GCCTypeInfo *curType = typesIterator->second; 454 | if (visitedTypes.count(curType)) 455 | continue; // already parsed 456 | buildReconstructableTypesRecursive(curType, visitedTypes); 457 | } 458 | fixupRecounstructableTypesId(); 459 | syncTypeInfoMethod = curMethod; 460 | for (auto typeIt = g_ReconstractedTypes.begin(); typeIt != g_ReconstractedTypes.end(); ++typeIt) { 461 | typeIt->second->SyncTypeInfo(); 462 | } 463 | 464 | return; 465 | } 466 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCObjectFormatParser.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2020 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 | 27 | #pragma once 28 | #include "Common.h" 29 | #include "IObjectFormatParser.h" 30 | #include "ObjectExplorer.h" 31 | 32 | 33 | namespace GCC_RTTI { 34 | #pragma pack(push, 1) 35 | 36 | struct __vtable_info { 37 | sval_t ptrdiff; 38 | ea_t type_info; 39 | }; 40 | 41 | 42 | struct __class_type_info; 43 | 44 | struct type_info { 45 | ea_t __type_info_vtable; 46 | ea_t __type_info_name; 47 | }; 48 | 49 | struct __pbase_type_info : public type_info { 50 | int quals; 51 | ea_t *type; 52 | 53 | enum quals_masks { 54 | const_mask = 0x1, 55 | volatile_mask = 0x2, 56 | restrict_mask = 0x4, 57 | incomplete_mask = 0x8, 58 | incomplete_class_mask = 0x10 59 | }; 60 | 61 | }; 62 | 63 | struct __pointer_type_info 64 | : public __pbase_type_info { 65 | const __class_type_info *klass; 66 | }; 67 | 68 | enum vmi_masks { 69 | virtual_mask = 0x1, 70 | public_mask = 0x2, 71 | hwm_bit = 2, 72 | offset_shift = 8 /* bits to shift offset by */ 73 | }; 74 | 75 | struct __base_class_info { 76 | ea_t base; 77 | uval_t vmi_offset_flags; 78 | 79 | }; 80 | 81 | 82 | struct __class_type_info 83 | : public type_info 84 | { 85 | enum __sub_kind 86 | { 87 | __unknown = 0, /* we have no idea */ 88 | __not_contained, /* not contained within us (in some */ 89 | /* circumstances this might mean not contained */ 90 | /* publicly) */ 91 | __contained_ambig, /* contained ambiguously */ 92 | 93 | __contained_virtual_mask = virtual_mask, /* via a virtual path */ 94 | __contained_public_mask = public_mask, /* via a public path */ 95 | __contained_mask = 1 << hwm_bit, /* contained within us */ 96 | 97 | __contained_private = __contained_mask, 98 | __contained_public = __contained_mask | __contained_public_mask 99 | }; 100 | 101 | 102 | }; 103 | 104 | struct __si_class_type_info 105 | : public __class_type_info 106 | { 107 | ea_t base; 108 | }; 109 | 110 | struct __vmi_class_type_info : public __class_type_info 111 | { 112 | int vmi_flags; 113 | int vmi_base_count; 114 | struct __base_class_info vmi_bases[1]; 115 | 116 | enum vmi_flags_masks { 117 | non_diamond_repeat_mask = 0x1, /* distinct instance of repeated base */ 118 | diamond_shaped_mask = 0x2, /* diamond shaped multiple inheritance */ 119 | non_public_base_mask = 0x4, /* has non-public direct or indirect base */ 120 | public_base_mask = 0x8, /* has public base (direct) */ 121 | 122 | __flags_unknown_mask = 0x10 123 | }; 124 | 125 | }; 126 | 127 | struct __user_type_info : public type_info 128 | { 129 | enum sub_kind 130 | { 131 | unknown = 0, // we have no idea 132 | not_contained, // not contained within us (in some 133 | // circumstances this might mean not contained 134 | // publicly) 135 | contained_ambig, // contained ambiguously 136 | contained_mask = 4, // contained within us 137 | contained_virtual_mask = 1, // via a virtual path 138 | contained_public_mask = 2, // via a public path 139 | contained_private = contained_mask, 140 | contained_public = contained_mask | contained_public_mask 141 | }; 142 | 143 | }; 144 | 145 | 146 | 147 | #pragma pack(pop) 148 | }; 149 | 150 | class GCCObjectFormatParser : 151 | public IObjectFormatParser 152 | { 153 | 154 | public: 155 | GCCObjectFormatParser(); 156 | 157 | virtual ~GCCObjectFormatParser(); 158 | /* Collect rtti info from a binary. 159 | */ 160 | virtual void get_rtti_info(); 161 | /* clear collected rtti info. 162 | */ 163 | virtual void clear_info(); 164 | /* Collect class_type_info_name, si_class_type_info_name, 165 | and vmi_class_type_info_name vtbls info from a binary. 166 | @param force when set will try to redifine already existant 167 | addresses of vtabls. 168 | @return zero if success. 169 | */ 170 | int collect_info_vtbls(bool force=false); 171 | 172 | 173 | void scanSeg4Vftables(segment_t *seg); 174 | }; 175 | 176 | class GCCVtableInfo; 177 | class GCCTypeInfo; 178 | 179 | extern std::unordered_mapg_KnownVtables; 180 | extern std::unordered_mapg_KnownTypes; 181 | extern std::unordered_mapg_KnownVtableNames; 182 | extern std::unordered_mapg_KnownTypeNames; 183 | 184 | extern DLLEXPORT ea_t class_type_info_vtbl; 185 | extern DLLEXPORT ea_t si_class_type_info_vtbl; 186 | extern DLLEXPORT ea_t vmi_class_type_info_vtbl; 187 | 188 | extern std::unordered_map rtti_vftables; 189 | 190 | 191 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCTypeInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "GCCTypeInfo.h" 2 | #include "GCCObjectFormatParser.h" 3 | #include "ReconstructableType.h" 4 | #include "offset.hpp" 5 | #include "Utility.h" 6 | #include "Debug.h" 7 | #include "typeinf.hpp" 8 | #if __clang__ 9 | // Ignore "offset of on non-standard-layout type" warning 10 | #pragma clang diagnostic ignored "-Winvalid-offsetof" 11 | #endif 12 | 13 | 14 | GCCTypeInfo::GCCTypeInfo() 15 | : ea(BADADDR) 16 | , typeinfo_vtbl(BADADDR) 17 | , parentsCount(0) 18 | , parentsTypes(nullptr), 19 | vtable(0) 20 | { 21 | } 22 | 23 | 24 | GCCTypeInfo::~GCCTypeInfo() 25 | { 26 | if (parentsTypes) 27 | delete[] parentsTypes; 28 | } 29 | 30 | 31 | GCCTypeInfo *GCCTypeInfo::parseTypeInfo(ea_t ea) 32 | { 33 | if (g_KnownTypes.count(ea)) 34 | return g_KnownTypes[ea]; 35 | 36 | GCC_RTTI::type_info tmp; 37 | if (!get_bytes(&tmp, sizeof(GCC_RTTI::type_info), ea)) 38 | return 0; 39 | 40 | ea_t name_ea = tmp.__type_info_name; 41 | 42 | size_t length = get_max_strlit_length(name_ea, STRTYPE_C, ALOPT_IGNHEADS); 43 | qstring buffer; 44 | 45 | if (!get_strlit_contents(&buffer, name_ea, length, STRTYPE_C)) { 46 | return 0; 47 | } 48 | qstring name(buffer); 49 | std::string demangled_name; 50 | qstring demangled_name_qstring; 51 | name = qstring("_ZTS") + name; 52 | int32 res = demangle_name(&demangled_name_qstring, name.c_str(), 0); 53 | demangled_name = demangled_name_qstring.c_str(); 54 | if (res != (MT_GCC3 | M_AUTOCRT | MT_RTTI)) 55 | { 56 | return 0; 57 | } 58 | 59 | demangled_name = demangled_name.substr(19); 60 | 61 | if (tmp.__type_info_vtable != class_type_info_vtbl && 62 | tmp.__type_info_vtable != si_class_type_info_vtbl && 63 | tmp.__type_info_vtable != vmi_class_type_info_vtbl) 64 | return 0; 65 | 66 | 67 | GCCTypeInfo * result = new GCCTypeInfo(); 68 | result->ea = ea; 69 | result->size = sizeof(GCC_RTTI::type_info); 70 | result->typeName = demangled_name; 71 | result->typeinfo_vtbl = tmp.__type_info_vtable; 72 | 73 | 74 | setUnknown(ea , sizeof(GCC_RTTI::type_info)); 75 | MakeName(ea, demangled_name_qstring, "RTTI_", ""); 76 | 77 | if (tmp.__type_info_vtable == class_type_info_vtbl) 78 | { 79 | 80 | tinfo_t tinfo; 81 | if (tinfo.get_named_type(get_idati(), "GCC_RTTI::type_info")) { 82 | apply_tinfo(ea, tinfo, TINFO_DEFINITE); 83 | } 84 | g_KnownTypes[ea] = result; 85 | return result; 86 | } 87 | 88 | 89 | if (tmp.__type_info_vtable == si_class_type_info_vtbl) { 90 | GCC_RTTI::__si_class_type_info si_class; 91 | if (!get_bytes(&si_class, sizeof(GCC_RTTI::__si_class_type_info), ea)) 92 | { 93 | delete result; 94 | return 0; 95 | } 96 | GCCTypeInfo *base = parseTypeInfo(si_class.base); 97 | if (base == 0) 98 | { 99 | delete result; 100 | return 0; 101 | } 102 | 103 | 104 | //assert(g_ReconstractedTypes.count(base->typeName)); 105 | //ReconstructableType *baseReType = g_ReconstractedTypes[base->typeName]; 106 | //baseReType->AddSubType(reType); 107 | //reType->SetParent(baseReType, 0); 108 | 109 | 110 | setUnknown(ea + ea_t(offsetof(GCC_RTTI::__si_class_type_info, base)), sizeof(GCC_RTTI::__si_class_type_info)); 111 | tinfo_t tinfo; 112 | if (tinfo.get_named_type(get_idati(), "GCC_RTTI::__si_class_type_info")) { 113 | apply_tinfo(ea, tinfo, TINFO_DEFINITE); 114 | } 115 | result->parentsCount = 1; 116 | result->parentsTypes = new GCCParentType*[1]; 117 | result->parentsTypes[0] = new GCCParentType(); 118 | result->parentsTypes[0]->ea = base->ea; 119 | result->parentsTypes[0]->info = base; 120 | result->parentsTypes[0]->flags = 0; 121 | result->parentsTypes[0]->offset = 0; 122 | g_KnownTypes[ea] = result; 123 | result->size = sizeof(GCC_RTTI::__si_class_type_info); 124 | return result; 125 | } 126 | 127 | GCC_RTTI::__vmi_class_type_info vmi_class; 128 | if (!get_bytes(&vmi_class, sizeof(GCC_RTTI::__vmi_class_type_info), ea)) 129 | return 0; 130 | 131 | // vmi_class.vmi_flags; // WTF?? 132 | 133 | result->parentsCount = vmi_class.vmi_base_count; 134 | result->parentsTypes = new GCCParentType*[result->parentsCount]; 135 | ea_t addr = ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_bases)); 136 | 137 | setUnknown(ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_flags)), EA_SIZE); 138 | create_dword(ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_flags)), EA_SIZE); 139 | 140 | setUnknown(ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_base_count)), sizeof(int)); 141 | create_dword(ea + ea_t(offsetof(GCC_RTTI::__vmi_class_type_info, vmi_base_count)), sizeof(int)); 142 | 143 | GCC_RTTI::__base_class_info baseInfo; 144 | for (int i = 0; i < vmi_class.vmi_base_count; ++i, addr += sizeof(baseInfo)) 145 | { 146 | if (!get_bytes(&baseInfo, sizeof(baseInfo), addr)) 147 | { 148 | delete result; 149 | return 0; 150 | } 151 | 152 | GCCTypeInfo *base = parseTypeInfo(baseInfo.base); 153 | if (base == 0) 154 | { 155 | delete result; 156 | return 0; 157 | } 158 | 159 | //assert(g_ReconstractedTypes.count(base->typeName)); 160 | //ReconstructableType *baseReType = g_ReconstractedTypes[base->typeName]; 161 | //baseReType->AddSubType(reType); 162 | //reType->SetParent(baseReType, baseInfo.vmi_offset_flags >> GCC_RTTI::offset_shift); 163 | 164 | setUnknown(addr + ea_t(offsetof(GCC_RTTI::__base_class_info, base)), EA_SIZE); 165 | op_plain_offset(addr + offsetof(GCC_RTTI::__base_class_info, base), 0, addr); 166 | 167 | setUnknown(addr + ea_t(offsetof(GCC_RTTI::__base_class_info, vmi_offset_flags)), EA_SIZE); 168 | create_dword(addr + ea_t(offsetof(GCC_RTTI::__base_class_info, vmi_offset_flags)), sizeof(int)); 169 | result->parentsTypes[i] = new GCCParentType(); 170 | result->parentsTypes[i]->ea = base->ea; 171 | result->parentsTypes[i]->ea = base->ea; 172 | result->parentsTypes[i]->info = base; 173 | result->parentsTypes[i]->flags = static_cast(baseInfo.vmi_offset_flags); 174 | 175 | result->parentsTypes[i]->offset = baseInfo.vmi_offset_flags >> GCC_RTTI::offset_shift; 176 | 177 | qstring flags; 178 | if (baseInfo.vmi_offset_flags & GCC_RTTI::virtual_mask) 179 | flags += " virtual_mask "; 180 | if (baseInfo.vmi_offset_flags & GCC_RTTI::public_mask) 181 | flags += " public_mask "; 182 | if (baseInfo.vmi_offset_flags >> GCC_RTTI::offset_shift) 183 | flags += " offset_shift "; 184 | set_cmt(addr + ea_t(offsetof(GCC_RTTI::__base_class_info, vmi_offset_flags)), flags.c_str(), false); 185 | } 186 | result->size = sizeof(GCC_RTTI::__vmi_class_type_info) + (vmi_class.vmi_base_count - 1)*sizeof(GCC_RTTI::__base_class_info); 187 | g_KnownTypes[ea] = result; 188 | return result; 189 | } 190 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCTypeInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Common.h" 3 | 4 | class GCCTypeInfo; 5 | class GCCVtableInfo; 6 | 7 | class GCCParentType { 8 | public: 9 | ea_t ea = BADADDR; 10 | GCCTypeInfo *info = nullptr; 11 | unsigned long offset; 12 | unsigned int flags = 0; 13 | }; 14 | 15 | class GCCTypeInfo 16 | { 17 | public: 18 | GCCTypeInfo(); 19 | ~GCCTypeInfo(); 20 | 21 | ea_t ea; 22 | size_t size; 23 | std::string typeName; 24 | ea_t typeinfo_vtbl; // vtable of std::typeinfo. 25 | unsigned int parentsCount; 26 | GCCParentType **parentsTypes; 27 | GCCVtableInfo *vtable; 28 | static GCCTypeInfo *parseTypeInfo(ea_t ea); 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/GCCVtableInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "GCCVtableInfo.h" 2 | #include "GCCObjectFormatParser.h" 3 | #include "GCCTypeInfo.h" 4 | #include "Utility.h" 5 | #include "ObjectExplorer.h" 6 | #include "ReconstructableType.h" 7 | 8 | 9 | GCCVtableInfo::GCCVtableInfo() 10 | : ea_start(BADADDR) 11 | , vtablesCount(0) 12 | , vtables(nullptr) 13 | , ea_end(BADADDR) 14 | { 15 | } 16 | 17 | GCCVtableInfo::~GCCVtableInfo() 18 | { 19 | if (vtables) 20 | delete[]vtables; 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 += EA_SIZE; 44 | } 45 | // Now lets remove ending zeroes. 46 | while (methodsCount) { 47 | addr -= EA_SIZE; 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 + sizeof(GCC_RTTI::__vtable_info); 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->typeInfo = type; 86 | result->typeName = type->typeName; 87 | type->vtable = result; 88 | 89 | 90 | addr += methodsCount * EA_SIZE; 91 | // tid_t vtbl_stru = create_vtbl_struct1(result->ea_start + sizeof(GCC_RTTI::__vtable_info), result->ea_start + sizeof(GCC_RTTI::__vtable_info) + methodsCount * EA_SIZE, type->typeName); 92 | 93 | std::string vtbl_name = type->typeName + VTBL_CLSNAME_POSTFIX; 94 | 95 | if (!type->parentsCount) 96 | result->vtablesCount = 1; 97 | else 98 | result->vtablesCount = type->parentsCount; 99 | result->vtables = new GCCVtable[result->vtablesCount](); 100 | 101 | result->vtables[0].ea = ea; 102 | result->vtables[0].methodsCount = methodsCount; 103 | result->vtables[0].ptrDiff = 0; 104 | result->vtables[0].name = result->typeName; // +VTBL_CLSNAME_POSTFIX; 105 | if (type->parentsCount > 1) { 106 | for (unsigned i = 1; i < type->parentsCount; ++i) 107 | { 108 | if (!GCCVtableInfo::parseVtableInnerInfo(addr, &result->vtables[i])) 109 | { 110 | type->vtable = 0; 111 | delete result; 112 | return nullptr; 113 | } 114 | addr += sizeof(GCC_RTTI::__vtable_info); 115 | addr += result->vtables[i].methodsCount * EA_SIZE; 116 | } 117 | } 118 | 119 | result->ea_end = addr; 120 | g_KnownVtables[ea] = result; 121 | g_KnownVtableNames[result->typeName + VTBL_CLSNAME_POSTFIX] = result; 122 | 123 | setUnknown(ea, sizeof(GCC_RTTI::__vtable_info) + sizeof(ea)*(methodsCount - 1)); 124 | MakeName(ea, qstring(type->typeName.c_str()), "RTTI_", VTBL_NAME_POSTFIX); 125 | //struc_t* new_struc = get_struc(vtbl_stru); 126 | //if (!new_struc) 127 | // return result; 128 | 129 | //tinfo_t tinfo; 130 | //if (tinfo.get_numbered_type(get_idati(), new_struc->ordinal)) { 131 | // apply_tinfo(ea, tinfo, TINFO_DEFINITE); 132 | //} 133 | 134 | return result; 135 | } 136 | 137 | bool GCCVtableInfo::parseVtableInnerInfo(ea_t ea, GCCVtable *vtbl) 138 | { 139 | GCC_RTTI::__vtable_info vtable; 140 | if (!get_bytes(&vtable, sizeof(GCC_RTTI::__vtable_info), ea)) 141 | return false; 142 | 143 | if (vtable.ptrdiff >= 0) 144 | return false; 145 | 146 | GCCTypeInfo *type = GCCTypeInfo::parseTypeInfo(vtable.type_info); 147 | if (!type) 148 | return false; 149 | 150 | unsigned int methodsCount = 0; 151 | 152 | ea_t addr = ea + sizeof(GCC_RTTI::__vtable_info); 153 | methodsCount = findMethodsCount(addr); 154 | 155 | if (methodsCount == 0) 156 | return false; // Doesn't look like vtable. 157 | 158 | vtbl->ea = ea; 159 | vtbl->methodsCount = methodsCount; 160 | vtbl->ptrDiff = static_cast(vtable.ptrdiff); 161 | for (unsigned int i = 0; i < type->parentsCount; ++i) { 162 | if ((type->parentsTypes[i]->offset) == (-vtbl->ptrDiff)) 163 | { 164 | vtbl->name = /*type->typeName + "::vtable_of_" + */ type->parentsTypes[i]->info->typeName; 165 | return true; 166 | } 167 | } 168 | vtbl->name = type->typeName + "::vtable_of_UNKNOWN"; 169 | return true; 170 | } 171 | 172 | -------------------------------------------------------------------------------- /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 | std::string name; // name of parent type 14 | 15 | tid_t get_tid(); 16 | }; 17 | 18 | class GCCVtableInfo 19 | { 20 | public: 21 | GCCVtableInfo(); 22 | ~GCCVtableInfo(); 23 | 24 | ea_t ea_start; 25 | //ea_t vtbl_start; 26 | std::string typeName; 27 | GCCTypeInfo *typeInfo; 28 | unsigned int vtablesCount; 29 | GCCVtable *vtables; 30 | ea_t ea_end; 31 | 32 | static GCCVtableInfo *parseVtableInfo(ea_t ea); 33 | static bool parseVtableInnerInfo(ea_t ea, GCCVtable *vtbl); 34 | }; 35 | 36 | extern std::unordered_mapg_KnownVtableNames; 37 | -------------------------------------------------------------------------------- /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 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | MultiByte 33 | v142 34 | 35 | 36 | DynamicLibrary 37 | true 38 | MultiByte 39 | v142 40 | 41 | 42 | DynamicLibrary 43 | false 44 | MultiByte 45 | v142 46 | 47 | 48 | DynamicLibrary 49 | false 50 | MultiByte 51 | v142 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 | $(LibraryPath) 78 | $(IncludePath) 79 | $(IDADIR)\plugins\ 80 | 81 | 82 | true 83 | build makefile 84 | .dll 85 | $(IncludePath) 86 | $(LibraryPath) 87 | $(ProjectName)64 88 | $(IDADIR)\plugins\ 89 | 90 | 91 | false 92 | .dll 93 | $(IncludePath) 94 | $(LibraryPath) 95 | $(IDADIR)\plugins\ 96 | 97 | 98 | false 99 | .dll 100 | $(ProjectName)64 101 | $(IDADIR)\plugins\ 102 | $(IncludePath) 103 | $(LibraryPath) 104 | 105 | 106 | 107 | 108 | 109 | Level3 110 | Disabled 111 | __MAKEDLL__;__NT__;__IDP__;__X64__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 112 | $(IDASDK)\include;$(IDADIR)\plugins\hexrays_sdk\include 113 | MultiThreadedDebug 114 | 115 | 116 | Console 117 | true 118 | ida.lib;user32.lib;%(AdditionalDependencies) 119 | /EXPORT:PLUGIN %(AdditionalOptions) 120 | $(IDASDK)\lib\x64_win_vc_32;$(IDASDK)\lib\x64_win_vc_32_pro 121 | 122 | 123 | 124 | 125 | 126 | 127 | Level3 128 | Disabled 129 | __MAKEDLL__;__NT__;__IDP__;__EA64__;__X64__;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 130 | $(IDASDK)\include;$(IDADIR)\plugins\hexrays_sdk\include 131 | MultiThreadedDebugDLL 132 | 133 | 134 | Console 135 | true 136 | ida.lib;user32.lib;%(AdditionalDependencies) 137 | /EXPORT:PLUGIN %(AdditionalOptions) 138 | $(IDASDK)\lib\x64_win_vc_64;$(IDASDK)\lib\x64_win_vc_64_pro 139 | 140 | 141 | 142 | 143 | Level3 144 | 145 | 146 | Disabled 147 | true 148 | true 149 | __MAKEDLL__;__NT__;__IDP__;__X64__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 150 | $(IDASDK)\include;$(IDADIR)\plugins\hexrays_sdk\include 151 | MultiThreaded 152 | false 153 | 154 | 155 | Console 156 | true 157 | true 158 | true 159 | ida.lib;user32.lib;%(AdditionalDependencies) 160 | /EXPORT:PLUGIN %(AdditionalOptions) 161 | $(IDASDK)\lib\x64_win_vc_32;$(IDASDK)\lib\x64_win_vc_32_pro 162 | 163 | 164 | 165 | 166 | Level3 167 | 168 | 169 | Disabled 170 | true 171 | true 172 | __MAKEDLL__;__NT__;__IDP__;__EA64__;__X64__;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 173 | $(IDASDK)\include;$(IDADIR)\plugins\hexrays_sdk\include 174 | MultiThreaded 175 | false 176 | 177 | 178 | Console 179 | true 180 | true 181 | true 182 | ida.lib;user32.lib;%(AdditionalDependencies) 183 | /EXPORT:PLUGIN %(AdditionalOptions) 184 | $(IDASDK)\lib\x64_win_vc_64;$(IDASDK)\lib\x64_win_vc_64_pro 185 | 186 | 187 | 188 | 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 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/IObjectFormatParser.cpp: -------------------------------------------------------------------------------- 1 | #include "IObjectFormatParser.h" 2 | 3 | 4 | 5 | IObjectFormatParser::~IObjectFormatParser() 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/IObjectFormatParser.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2020 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 | #pragma once 27 | class IObjectFormatParser 28 | { 29 | public: 30 | virtual ~IObjectFormatParser(); 31 | 32 | virtual void get_rtti_info() = 0; 33 | virtual void clear_info() = 0; 34 | }; 35 | 36 | extern IObjectFormatParser *object_format_parser; 37 | 38 | extern bool init_object_format_parser(); 39 | -------------------------------------------------------------------------------- /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 | UINT typeDescriptor; // 00 Type descriptor of the class 95 | UINT numContainedBases; // 04 Number of nested classes following in the Base Class Array 96 | PMD pmd; // 08 Pointer-to-member displacement info 97 | UINT attributes; // 14 Flags 98 | // 18 When attributes & BCD_HASPCHD 99 | //_RTTIClassHierarchyDescriptor *classDescriptor; *X64 int32 offset 100 | 101 | static bool isValid(ea_t bcd, ea_t colBase64 = 0); 102 | 103 | }; 104 | 105 | // "Class Hierarchy Descriptor" describes the inheritance hierarchy of a class; shared by all COLs for the class 106 | // attributes flags 107 | const UINT CHD_MULTINH = 0x01; // Multiple inheritance 108 | const UINT CHD_VIRTINH = 0x02; // Virtual inheritance 109 | const UINT CHD_AMBIGUOUS = 0x04; // Ambiguous inheritance 110 | 111 | struct _RTTIClassHierarchyDescriptor 112 | { 113 | UINT signature; // 00 Zero until loaded 114 | UINT attributes; // 04 Flags 115 | UINT numBaseClasses; // 08 Number of classes in the following 'baseClassArray' 116 | UINT baseClassArray; // 0C _RTTIBaseClassArray* 117 | 118 | static bool isValid(ea_t chd, ea_t colBase64 = 0); 119 | }; 120 | 121 | // "Complete Object Locator" location of the complete object from a specific vftable pointer 122 | struct _RTTICompleteObjectLocator 123 | { 124 | UINT signature; // 00 32bit zero, 64bit one, until loaded 125 | UINT offset; // 04 Offset of this vftable in the complete class 126 | UINT cdOffset; // 08 Constructor displacement offset 127 | 128 | UINT typeDescriptor; // 0C (type_info *) of the complete class 129 | UINT classDescriptor; // 10 (_RTTIClassHierarchyDescriptor *) Describes inheritance hierarchy 130 | UINT objectBase; // 14 Object base offset (base = ptr col - objectBase) 131 | 132 | static bool isValid(ea_t col); 133 | static bool isValid2(ea_t col); 134 | }; 135 | #pragma pack(pop) 136 | 137 | const WORD IS_TOP_LEVEL = 0x8000; 138 | 139 | void freeWorkingData(); 140 | 141 | bool processVftable(ea_t vft, ea_t col, vftable::vtinfo &vi); 142 | } 143 | 144 | 145 | extern void fixEa(ea_t ea); 146 | extern void fixDword(ea_t eaAddress); 147 | extern void fixFunction(ea_t eaFunc); 148 | extern void idaapi setUnknown(ea_t ea, asize_t size); 149 | extern bool getVerifyEa(ea_t ea, ea_t &rValue); 150 | extern BOOL hasAnteriorComment(ea_t ea); 151 | extern void killAnteriorComments(ea_t ea); 152 | 153 | extern bool getPlainTypeName(const qstring& mangled, qstring& outStr); 154 | 155 | extern BOOL optionOverwriteComments, optionPlaceStructs; 156 | 157 | class MSVCObjectFormatParser : 158 | public IObjectFormatParser 159 | { 160 | public: 161 | virtual ~MSVCObjectFormatParser(); 162 | 163 | virtual void get_rtti_info(); 164 | virtual void clear_info(); 165 | }; 166 | 167 | -------------------------------------------------------------------------------- /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)CtreeExtractor.cpp \ 11 | $(SRCDIR)CtreeGraphBuilder.cpp \ 12 | $(SRCDIR)Debug.cpp \ 13 | $(SRCDIR)GCCObjectFormatParser.cpp \ 14 | $(SRCDIR)GCCTypeInfo.cpp \ 15 | $(SRCDIR)GCCVtableInfo.cpp \ 16 | $(SRCDIR)IObjectFormatParser.cpp \ 17 | $(SRCDIR)MSVCObjectFormatParser.cpp \ 18 | $(SRCDIR)ObjectExplorer.cpp \ 19 | $(SRCDIR)ReconstructableType.cpp \ 20 | $(SRCDIR)reconstructed_place_t.cpp \ 21 | $(SRCDIR)TypeExtractor.cpp \ 22 | $(SRCDIR)TypeReconstructor.cpp \ 23 | $(SRCDIR)MicrocodeExtractor.cpp \ 24 | $(SRCDIR)Utility.cpp 25 | 26 | #SRC = $(wildcard src/*.cpp) 27 | #OBJS=$(subst .cpp,.o,$(SRC)) 28 | 29 | all: check-env HexRaysCodeXplorer.pmc HexRaysCodeXplorer.pmc64 30 | 31 | HexRaysCodeXplorer.pmc: $(SRC) 32 | $(CXX) $(LDFLAGS) $(SRC) $(CXXFLAGS) -L. -L$(IDA_DIR) $(INCLUDES) -D__MAC__=1 $(LIBS) -lida -o HexRaysCodeXplorer.pmc 33 | 34 | HexRaysCodeXplorer.pmc64: $(SRC) 35 | $(CXX) $(LDFLAGS) $(SRC) $(CXXFLAGS) -L. -L$(IDA_DIR) $(INCLUDES) -D__MAC__=1 -D__EA64__=1 $(LIBS) -lida64 -o HexRaysCodeXplorer.pmc64 36 | 37 | clean: 38 | rm -f HexRaysCodeXplorer.pmc HexRaysCodeXplorer.pmc64 39 | 40 | install: 41 | cp -f HexRaysCodeXplorer.pmc $(IDA_DIR)/plugins/ 42 | cp -f HexRaysCodeXplorer.pmc64 $(IDA_DIR)/plugins/ 43 | 44 | check-env: 45 | ifndef IDA_SDK 46 | $(error IDA_SDK is undefined) 47 | endif 48 | ifndef IDA_DIR 49 | $(error IDA_DIR is undefined) 50 | endif 51 | ln -f -s $(IDA_SDK)/lib/x86_mac_gcc_32/pro.a libpro.a 52 | 53 | .PHONY: check-env 54 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/MicrocodeExtractor.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2020 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 | // This code mostly adopted from https://github.com/RolfRolles/HexRaysDeob 27 | // All kudos going to Rolf https://www.hexblog.com/?p=1248 28 | 29 | #include 30 | #include 31 | #include "Common.h" 32 | #include "MicrocodeExtractor.h" 33 | 34 | 35 | 36 | typedef std::shared_ptr shared_mbl_array_t; 37 | 38 | struct mblock_virtual_dumper_t : public vd_printer_t 39 | { 40 | virtual ~mblock_virtual_dumper_t(); 41 | int nline; 42 | int serial; 43 | mblock_virtual_dumper_t();; 44 | virtual void add_line(qstring& qs); 45 | AS_PRINTF(3, 4) virtual int print(const int indent, const char* format, ...) override; 46 | }; 47 | 48 | struct mblock_virtual_dumper_t_impl final : mblock_virtual_dumper_t 49 | { 50 | }; 51 | 52 | 53 | mblock_virtual_dumper_t::mblock_virtual_dumper_t(): nline(0), serial(0) 54 | { 55 | } 56 | 57 | int mblock_virtual_dumper_t::print(const int indent, const char* format, ...) 58 | { 59 | qstring buf; 60 | if (indent > 0) 61 | buf.fill(0, ' ', indent); 62 | va_list va; 63 | va_start(va, format); 64 | buf.cat_vsprnt(format, va); 65 | va_end(va); 66 | 67 | static const char pfx_on[] = {COLOR_ON, COLOR_PREFIX}; 68 | static const char pfx_off[] = {COLOR_OFF, COLOR_PREFIX}; 69 | buf.replace(pfx_on, ""); 70 | buf.replace(pfx_off, ""); 71 | 72 | add_line(buf); 73 | return buf.length(); 74 | } 75 | 76 | void mblock_virtual_dumper_t::add_line(qstring& qs) 77 | { 78 | } 79 | 80 | 81 | mblock_virtual_dumper_t::~mblock_virtual_dumper_t() 82 | = default; 83 | 84 | struct mblock_qstring_dumper_t final : public mblock_virtual_dumper_t 85 | { 86 | qstring q_str; 87 | mblock_qstring_dumper_t() : mblock_virtual_dumper_t() {}; 88 | 89 | void add_line(qstring& qs) override 90 | { 91 | q_str.append(qs); 92 | } 93 | }; 94 | 95 | struct mblock_dumper_t final : public mblock_virtual_dumper_t 96 | { 97 | strvec_t lines; 98 | mblock_dumper_t() : mblock_virtual_dumper_t() {}; 99 | 100 | void add_line(qstring& qs) override 101 | { 102 | lines.push_back(simpleline_t(qs)); 103 | } 104 | }; 105 | 106 | struct sample_info_t 107 | { 108 | TWidget* cv; 109 | mblock_dumper_t md; 110 | shared_mbl_array_t mba; 111 | mba_maturity_t mat; 112 | sample_info_t() : cv(nullptr), mba(nullptr), mat(){} 113 | }; 114 | 115 | 116 | class microcode_instruction_graph 117 | { 118 | public: 119 | qstring tmp; // temporary buffer for grcode_user_text 120 | qstrvec_t m_short_text; 121 | qstrvec_t m_block_text; 122 | intvec_t m_edge_colors; 123 | edgevec_t m_edges; 124 | int m_num_blocks{}; 125 | 126 | void clear(); 127 | 128 | void build(minsn_t* top); 129 | 130 | protected: 131 | void add_edge(int i_src, int i_dest, int i_pos); 132 | 133 | int get_incr_block_num(); 134 | 135 | int insert(minsn_t* ins, int i_parent); 136 | 137 | int insert(mop_t& op, int i_parent, int i_pos); 138 | }; 139 | 140 | class microcode_instruction_graph_impl : public microcode_instruction_graph 141 | { 142 | public: 143 | }; 144 | 145 | class microcode_instruction_graph_container; 146 | 147 | static ssize_t idaapi migr_callback(void* ud, int code, va_list va); 148 | 149 | class microcode_instruction_graph_container 150 | { 151 | protected: 152 | TWidget* m_tw_; 153 | graph_viewer_t* m_gv_; 154 | qstring m_title_; 155 | qstring m_gv_name_; 156 | 157 | public: 158 | microcode_instruction_graph m_mg; 159 | microcode_instruction_graph_container() : m_tw_(nullptr), m_gv_(nullptr) {}; 160 | 161 | bool display(minsn_t* top, sample_info_t* si, const int n_block, const int n_serial) 162 | { 163 | const auto mba = *si->mba; 164 | m_mg.build(top); 165 | 166 | m_title_.cat_sprnt("Microinstruction Graph - %a[%s]/%d:%d", mba->entry_ea, micro_maturity_to_string(si->mat), n_block, n_serial); 167 | m_tw_ = create_empty_widget(m_title_.c_str()); 168 | netnode id; 169 | id.create(); 170 | 171 | m_gv_name_.cat_sprnt("microins_%a_%s_%d_%d", mba->entry_ea, micro_maturity_to_string(si->mat), n_block, n_serial); 172 | m_gv_ = create_graph_viewer(m_gv_name_.c_str(), id, migr_callback, this, 0, m_tw_); 173 | activate_widget(m_tw_, true); 174 | viewer_fit_window(m_gv_); 175 | return true; 176 | } 177 | }; 178 | 179 | void microcode_instruction_graph::clear() 180 | { 181 | m_short_text.clear(); 182 | m_block_text.clear(); 183 | m_edge_colors.clear(); 184 | m_edges.clear(); 185 | m_num_blocks = 0; 186 | } 187 | 188 | void microcode_instruction_graph::build(minsn_t* top) 189 | { 190 | clear(); 191 | insert(top, -1); 192 | } 193 | 194 | void microcode_instruction_graph::add_edge(const int i_src, const int i_dest, const int i_pos) 195 | { 196 | if (i_src < 0 || i_dest < 0) 197 | return; 198 | 199 | m_edges.push_back(edge_t(i_src, i_dest)); 200 | m_edge_colors.push_back(i_pos); 201 | } 202 | 203 | int microcode_instruction_graph::get_incr_block_num() 204 | { 205 | return m_num_blocks++; 206 | } 207 | 208 | int microcode_instruction_graph::insert(minsn_t* ins, int i_parent) 209 | { 210 | char l_buf[MAXSTR]; 211 | mcode_t_to_string(ins, l_buf, sizeof(l_buf)); 212 | m_short_text.push_back(l_buf); 213 | 214 | qstring q_str; 215 | ins->print(&q_str); 216 | m_block_text.push_back(q_str); 217 | 218 | const auto i_this_block = get_incr_block_num(); 219 | 220 | insert(ins->l, i_this_block, 0); 221 | insert(ins->r, i_this_block, 1); 222 | insert(ins->d, i_this_block, 2); 223 | 224 | return i_this_block; 225 | } 226 | 227 | int microcode_instruction_graph::insert(mop_t& op, const int i_parent, const int i_pos) 228 | { 229 | if (op.t == mop_z) 230 | return -1; 231 | 232 | m_short_text.push_back(mopt_t_to_string(op.t)); 233 | 234 | qstring q_str; 235 | op.print(&q_str); 236 | m_block_text.push_back(q_str); 237 | 238 | const auto i_this_block = get_incr_block_num(); 239 | add_edge(i_parent, i_this_block, i_pos); 240 | 241 | switch (op.t) 242 | { 243 | case mop_d: // result of another instruction 244 | { 245 | const auto i_dest_block = insert(op.d, i_this_block); 246 | add_edge(i_this_block, i_dest_block, 0); 247 | break; 248 | } 249 | case mop_f: // list of arguments 250 | for (auto i = 0; i < op.f->args.size(); ++i) 251 | insert(op.f->args[i], i_this_block, i); 252 | break; 253 | case mop_p: // operand pair 254 | { 255 | insert(op.pair->lop, i_this_block, 0); 256 | insert(op.pair->hop, i_this_block, 1); 257 | break; 258 | } 259 | case mop_a: // result of another instruction 260 | { 261 | insert(*op.a, i_this_block, 0); 262 | break; 263 | } 264 | default: ; 265 | } 266 | return i_this_block; 267 | } 268 | 269 | static ssize_t idaapi migr_callback(void* ud, const int code, va_list va) 270 | { 271 | auto gcont = static_cast(ud); 272 | auto microg = &gcont->m_mg; 273 | auto result = false; 274 | 275 | switch (code) 276 | { 277 | #if IDA_SDK_VERSION < 760 278 | case grcode_user_gentext: 279 | result = true; 280 | break; 281 | #endif 282 | 283 | // refresh user-defined graph nodes and edges 284 | case grcode_user_refresh: 285 | // in: mutable_graph_t *g 286 | // out: success 287 | { 288 | auto mg = va_arg(va, interactive_graph_t*); 289 | 290 | // we have to resize 291 | mg->resize(microg->m_num_blocks); 292 | 293 | for (auto& it : microg->m_edges) 294 | mg->add_edge(it.src, it.dst, nullptr); 295 | 296 | result = true; 297 | } 298 | break; 299 | 300 | // retrieve text for user-defined graph node 301 | case grcode_user_text: 302 | //mutable_graph_t *g 303 | // int node 304 | // const char **result 305 | // bgcolor_t *bg_color (maybe NULL) 306 | // out: must return 0, result must be filled 307 | // NB: do not use anything calling GDI! 308 | { 309 | va_arg(va, interactive_graph_t*); 310 | const auto node = va_arg(va, int); 311 | const auto text = va_arg(va, const char**); 312 | 313 | microg->tmp = microg->m_short_text[node]; 314 | microg->tmp.append('\n'); 315 | microg->tmp.append(microg->m_block_text[node]); 316 | *text = microg->tmp.begin(); 317 | result = true; 318 | } 319 | break; 320 | default: ; 321 | } 322 | return static_cast(result); 323 | } 324 | 325 | static ssize_t idaapi mgr_callback(void* ud, int code, va_list va); 326 | 327 | class microcode_graph_container 328 | { 329 | public: 330 | shared_mbl_array_t m_mba; 331 | mblock_qstring_dumper_t m_mqd; 332 | qstring m_title; 333 | qstring m_gv_name; 334 | qstring tmp; 335 | shared_mbl_array_t mba; 336 | explicit microcode_graph_container(shared_mbl_array_t mba) : m_mba(std::move(mba)), mba(std::move(mba)) {}; 337 | bool display(sample_info_t* si) 338 | { 339 | const auto mba = *si->mba; 340 | m_title.cat_sprnt("Microcode Graph - %a[%s]", mba->entry_ea, micro_maturity_to_string(si->mat)); 341 | 342 | const auto tw = create_empty_widget(m_title.c_str()); 343 | netnode id; 344 | id.create(); 345 | 346 | m_gv_name.cat_sprnt("microblkgraph_%a_%s", mba->entry_ea, micro_maturity_to_string(si->mat)); 347 | const auto gv = create_graph_viewer(m_gv_name.c_str(), id, mgr_callback, this, 0, tw); 348 | activate_widget(tw, true); 349 | viewer_fit_window(gv); 350 | return true; 351 | } 352 | 353 | }; 354 | 355 | static ssize_t idaapi mgr_callback(void* ud, const int code, va_list va) 356 | { 357 | auto gcont = static_cast(ud); 358 | auto mba = *gcont->m_mba; 359 | auto result = false; 360 | 361 | switch (code) 362 | { 363 | #if IDA_SDK_VERSION < 760 364 | case grcode_user_gentext: 365 | result = true; 366 | break; 367 | #endif 368 | 369 | // refresh user-defined graph nodes and edges 370 | case grcode_user_refresh: 371 | // in: mutable_graph_t *g 372 | // out: success 373 | { 374 | interactive_graph_t* mg = va_arg(va, interactive_graph_t*); 375 | 376 | // we have to resize 377 | mg->resize(mba->qty); 378 | 379 | for (auto i = 0; i < mba->qty; ++i) 380 | for (auto dst : mba->get_mblock(i)->succset) 381 | mg->add_edge(i, dst, nullptr); 382 | 383 | result = true; 384 | } 385 | break; 386 | 387 | // retrieve text for user-defined graph node 388 | case grcode_user_text: 389 | //mutable_graph_t *g 390 | // int node 391 | // const char **result 392 | // bgcolor_t *bg_color (maybe NULL) 393 | // out: must return 0, result must be filled 394 | // NB: do not use anything calling GDI! 395 | { 396 | va_arg(va, interactive_graph_t*); 397 | const auto node = va_arg(va, int); 398 | const auto text = va_arg(va, const char**); 399 | 400 | gcont->m_mqd.q_str.clear(); 401 | mba->get_mblock(node)->print(gcont->m_mqd); 402 | *text = gcont->m_mqd.q_str.begin(); 403 | result = true; 404 | } 405 | break; 406 | default: ; 407 | } 408 | return static_cast(result); 409 | } 410 | 411 | static bool idaapi ct_keyboard(TWidget* /*v*/, const int key, const int shift, void* ud) 412 | { 413 | if (shift == 0) 414 | { 415 | auto* si = static_cast(ud); 416 | switch (key) 417 | { 418 | case 'G': 419 | { 420 | auto mgc = new microcode_graph_container(si->mba); 421 | return mgc->display(si); 422 | } 423 | 424 | 425 | // User wants to show a graph of the current instruction 426 | case 'I': 427 | { 428 | qstring buf; 429 | tag_remove(&buf, get_custom_viewer_curline(si->cv, false)); 430 | const auto p_line = buf.c_str(); 431 | const auto p_dot = strchr(p_line, '.'); 432 | if (p_dot == nullptr) 433 | { 434 | warning( 435 | "Couldn't find the block number on the current line; was the block empty?\n" 436 | "If it was not empty, and you don't see [int].[int] at the beginning of the lines\n" 437 | "please run the plugin again to generate a new microcode listing.\n" 438 | "That should fix it."); 439 | return true; // reacted to the keypress 440 | } 441 | const auto n_block = atoi(p_line); 442 | const auto n_serial = atoi(p_dot + 1); 443 | auto mba = *si->mba; 444 | 445 | if (n_block > mba->qty) 446 | { 447 | warning("Plugin error: line prefix was %d:%d, but block only has %d basic blocks.", n_block, n_serial, mba->qty); 448 | return true; 449 | } 450 | 451 | const auto blk = mba->get_mblock(n_block); 452 | auto minsn = blk->head; 453 | int i; 454 | for (i = 0; i < n_serial; ++i) 455 | { 456 | minsn = minsn->next; 457 | if (minsn == nullptr) 458 | break; 459 | } 460 | 461 | if (minsn == nullptr) 462 | { 463 | if (i == 0) 464 | warning( 465 | "Couldn't get first minsn_t from %d:%d; was the block empty?\n" 466 | "If it was not empty, and you don't see [int].[int] at the beginning of the lines\n" 467 | "please run the plugin again to generate a new microcode listing.\n" 468 | "That should fix it.", n_block, n_serial); 469 | else 470 | warning("Couldn't get first minsn_t from %d:%d; last valid instruction was %d", n_block, n_serial, i - 1); 471 | return true; 472 | } 473 | 474 | char repr[MAXSTR]; 475 | mcode_t_to_string(minsn, repr, sizeof(repr)); 476 | auto mcg = new microcode_instruction_graph_container; 477 | return mcg->display(minsn, si, n_block, n_serial); 478 | } 479 | case IK_ESCAPE: 480 | close_widget(si->cv, WCLS_SAVE | WCLS_CLOSE_LATER); 481 | return true; 482 | default: ; 483 | } 484 | } 485 | return false; 486 | } 487 | 488 | static const custom_viewer_handlers_t handlers( 489 | ct_keyboard, 490 | nullptr, // popup 491 | nullptr, // mouse_moved 492 | nullptr, // click 493 | nullptr, // dblclick 494 | nullptr, 495 | nullptr, // close 496 | nullptr, // help 497 | nullptr);// adjust_place 498 | 499 | ssize_t idaapi ui_callback(void* ud, const int code, va_list va) 500 | { 501 | const auto si = static_cast(ud); 502 | switch (code) 503 | { 504 | case ui_widget_invisible: 505 | { 506 | const auto f = va_arg(va, TWidget*); 507 | if (f == si->cv) 508 | { 509 | delete si; 510 | unhook_from_notification_point(HT_UI, ui_callback); 511 | } 512 | } 513 | break; 514 | default: ; 515 | } 516 | return 0; 517 | } 518 | 519 | const char* mat_levels[] = 520 | { 521 | "MMAT_GENERATED", 522 | "MMAT_PREOPTIMIZED", 523 | "MMAT_LOCOPT", 524 | "MMAT_CALLS", 525 | "MMAT_GLBOPT1", 526 | "MMAT_GLBOPT2", 527 | "MMAT_GLBOPT3", 528 | "MMAT_LVARS" 529 | }; 530 | 531 | mba_maturity_t ask_desired_maturity() 532 | { 533 | const char dlg_text[] = 534 | "Select maturity level\n" 535 | "\n"; 536 | 537 | qstrvec_t opts; 538 | for (auto& mat_level : mat_levels) 539 | opts.push_back(mat_level); 540 | 541 | auto sel = 0; 542 | const auto ret = ask_form(dlg_text, &opts, &sel); 543 | 544 | if (ret > 0) 545 | return static_cast(static_cast(MMAT_GENERATED) + sel); 546 | return MMAT_ZERO; 547 | } 548 | 549 | void show_microcode_explorer() 550 | { 551 | const auto pfn = get_func(get_screen_ea()); 552 | if (pfn == nullptr) 553 | { 554 | warning("Please position the cursor within a function"); 555 | return; 556 | } 557 | 558 | const auto mmat = ask_desired_maturity(); 559 | if (mmat == MMAT_ZERO) 560 | return; 561 | 562 | hexrays_failure_t hf; 563 | auto mba = gen_microcode(pfn, &hf, nullptr, 0, mmat); 564 | if (mba == nullptr) 565 | { 566 | warning("#error \"%a: %s", hf.errea, hf.desc().c_str()); 567 | return; 568 | } 569 | 570 | auto si = new sample_info_t; 571 | si->mba = std::make_shared(mba); 572 | si->mat = mmat; 573 | // Dump the microcode to the output window 574 | mba->print(si->md); 575 | 576 | simpleline_place_t s1; 577 | simpleline_place_t s2(si->md.lines.size() - 1); 578 | 579 | qstring title; 580 | title.cat_sprnt("Microcode Explorer - %a - %s", pfn->start_ea, micro_maturity_to_string(mmat)); 581 | 582 | si->cv = create_custom_viewer( 583 | title.c_str(), // title 584 | &s1, // minplace 585 | &s2, // maxplace 586 | &s1, // curplace 587 | nullptr, // renderer_info_t *rinfo 588 | &si->md.lines, // ud 589 | &handlers, // cvhandlers 590 | si, // cvhandlers_ud 591 | nullptr); // parent 592 | 593 | hook_to_notification_point(HT_UI, ui_callback, si); 594 | display_widget(si->cv, WOPN_DP_TAB | WOPN_RESTORE); 595 | } 596 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/MicrocodeExtractor.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2020 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 | // This code mostly adopted from https://github.com/RolfRolles/HexRaysDeob 27 | // All kudos going to Rolf https://www.hexblog.com/?p=1248 28 | 29 | 30 | #pragma once 31 | 32 | 33 | void show_microcode_explorer(); 34 | mba_maturity_t ask_desired_maturity(); 35 | 36 | // Produce a string for an operand type 37 | inline const char* mopt_t_to_string(const mopt_t t) 38 | { 39 | switch (t) 40 | { 41 | case mop_z: return "mop_z"; 42 | case mop_r: return "mop_r"; 43 | case mop_n: return "mop_n"; 44 | case mop_str: return "mop_str"; 45 | case mop_d: return "mop_d"; 46 | case mop_S: return "mop_S"; 47 | case mop_v: return "mop_v"; 48 | case mop_b: return "mop_b"; 49 | case mop_f: return "mop_f"; 50 | case mop_l: return "mop_l"; 51 | case mop_a: return "mop_a"; 52 | case mop_h: return "mop_h"; 53 | case mop_c: return "mop_c"; 54 | case mop_fn: return "mop_fn"; 55 | case mop_p: return "mop_p"; 56 | case mop_sc: return "mop_sc"; 57 | default: ; 58 | }; 59 | return "???"; 60 | } 61 | 62 | // Produce a brief representation of a microinstruction, including the types 63 | // of its operands. 64 | inline void mcode_t_to_string(minsn_t* o, char* out_buf, size_t n) 65 | { 66 | switch (o->opcode) 67 | { 68 | case m_nop: snprintf(out_buf, n, "m_nop"); break; 69 | case m_stx: snprintf(out_buf, n, "m_stx(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 70 | case m_ldx: snprintf(out_buf, n, "m_ldx(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 71 | case m_ldc: snprintf(out_buf, n, "m_ldc(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 72 | case m_mov: snprintf(out_buf, n, "m_mov(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 73 | case m_neg: snprintf(out_buf, n, "m_neg(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 74 | case m_lnot: snprintf(out_buf, n, "m_lnot(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 75 | case m_bnot: snprintf(out_buf, n, "m_bnot(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 76 | case m_xds: snprintf(out_buf, n, "m_xds(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 77 | case m_xdu: snprintf(out_buf, n, "m_xdu(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 78 | case m_low: snprintf(out_buf, n, "m_low(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 79 | case m_high: snprintf(out_buf, n, "m_high(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 80 | case m_add: snprintf(out_buf, n, "m_add(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 81 | case m_sub: snprintf(out_buf, n, "m_sub(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 82 | case m_mul: snprintf(out_buf, n, "m_mul(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 83 | case m_udiv: snprintf(out_buf, n, "m_udiv(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 84 | case m_sdiv: snprintf(out_buf, n, "m_sdiv(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 85 | case m_umod: snprintf(out_buf, n, "m_umod(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 86 | case m_smod: snprintf(out_buf, n, "m_smod(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 87 | case m_or: snprintf(out_buf, n, "m_or(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 88 | case m_and: snprintf(out_buf, n, "m_and(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 89 | case m_xor: snprintf(out_buf, n, "m_xor(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 90 | case m_shl: snprintf(out_buf, n, "m_shl(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 91 | case m_shr: snprintf(out_buf, n, "m_shr(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 92 | case m_sar: snprintf(out_buf, n, "m_sar(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 93 | case m_cfadd: snprintf(out_buf, n, "m_cfadd(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 94 | case m_ofadd: snprintf(out_buf, n, "m_ofadd(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 95 | case m_cfshl: snprintf(out_buf, n, "m_cfshl(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 96 | case m_cfshr: snprintf(out_buf, n, "m_cfshr(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 97 | case m_sets: snprintf(out_buf, n, "m_sets(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 98 | case m_seto: snprintf(out_buf, n, "m_seto(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 99 | case m_setp: snprintf(out_buf, n, "m_setp(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 100 | case m_setnz: snprintf(out_buf, n, "m_setnz(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 101 | case m_setz: snprintf(out_buf, n, "m_setz(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 102 | case m_setae: snprintf(out_buf, n, "m_setae(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 103 | case m_setb: snprintf(out_buf, n, "m_setb(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 104 | case m_seta: snprintf(out_buf, n, "m_seta(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 105 | case m_setbe: snprintf(out_buf, n, "m_setbe(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 106 | case m_setg: snprintf(out_buf, n, "m_setg(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 107 | case m_setge: snprintf(out_buf, n, "m_setge(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 108 | case m_setl: snprintf(out_buf, n, "m_setl(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 109 | case m_setle: snprintf(out_buf, n, "m_setle(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 110 | case m_jcnd: snprintf(out_buf, n, "m_jcnd(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 111 | case m_jnz: snprintf(out_buf, n, "m_jnz(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 112 | case m_jz: snprintf(out_buf, n, "m_jz(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 113 | case m_jae: snprintf(out_buf, n, "m_jae(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 114 | case m_jb: snprintf(out_buf, n, "m_jb(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 115 | case m_ja: snprintf(out_buf, n, "m_ja(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 116 | case m_jbe: snprintf(out_buf, n, "m_jbe(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 117 | case m_jg: snprintf(out_buf, n, "m_jg(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 118 | case m_jge: snprintf(out_buf, n, "m_jge(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 119 | case m_jl: snprintf(out_buf, n, "m_jl(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 120 | case m_jle: snprintf(out_buf, n, "m_jle(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 121 | case m_jtbl: snprintf(out_buf, n, "m_jtbl(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t)); break; 122 | case m_ijmp: snprintf(out_buf, n, "m_ijmp(%s,%s)", mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 123 | case m_goto: snprintf(out_buf, n, "m_goto(%s)", mopt_t_to_string(o->l.t)); break; 124 | case m_call: snprintf(out_buf, n, "m_call(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 125 | case m_icall: snprintf(out_buf, n, "m_icall(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 126 | case m_ret: snprintf(out_buf, n, "m_ret"); break; 127 | case m_push: snprintf(out_buf, n, "m_push(%s)", mopt_t_to_string(o->l.t)); break; 128 | case m_pop: snprintf(out_buf, n, "m_pop(%s)", mopt_t_to_string(o->d.t)); break; 129 | case m_und: snprintf(out_buf, n, "m_und(%s)", mopt_t_to_string(o->d.t)); break; 130 | case m_ext: snprintf(out_buf, n, "m_ext(???)"); break; 131 | case m_f2i: snprintf(out_buf, n, "m_f2i(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 132 | case m_f2u: snprintf(out_buf, n, "m_f2u(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 133 | case m_i2f: snprintf(out_buf, n, "m_i2f(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 134 | case m_u2f: snprintf(out_buf, n, "m_u2f(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 135 | case m_f2f: snprintf(out_buf, n, "m_f2f(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 136 | case m_fneg: snprintf(out_buf, n, "m_fneg(%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->d.t)); break; 137 | case m_fadd: snprintf(out_buf, n, "m_fadd(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 138 | case m_fsub: snprintf(out_buf, n, "m_fsub(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 139 | case m_fmul: snprintf(out_buf, n, "m_fmul(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 140 | case m_fdiv: snprintf(out_buf, n, "m_fdiv(%s,%s,%s)", mopt_t_to_string(o->l.t), mopt_t_to_string(o->r.t), mopt_t_to_string(o->d.t)); break; 141 | } 142 | } 143 | 144 | // Produce a string describing the microcode maturity level. 145 | inline const char* micro_maturity_to_string(const mba_maturity_t mmt) 146 | { 147 | switch (mmt) 148 | { 149 | case MMAT_ZERO: return "MMAT_ZERO"; 150 | case MMAT_GENERATED: return "MMAT_GENERATED"; 151 | case MMAT_PREOPTIMIZED: return "MMAT_PREOPTIMIZED"; 152 | case MMAT_LOCOPT: return "MMAT_LOCOPT"; 153 | case MMAT_CALLS: return "MMAT_CALLS"; 154 | case MMAT_GLBOPT1: return "MMAT_GLBOPT1"; 155 | case MMAT_GLBOPT2: return "MMAT_GLBOPT2"; 156 | case MMAT_GLBOPT3: return "MMAT_GLBOPT3"; 157 | case MMAT_LVARS: return "MMAT_LVARS"; 158 | default: return "???"; 159 | } 160 | } 161 | 162 | // Copied from http://www.hexblog.com/?p=1198 163 | // I did add code for the mop_d case; it used to return false 164 | 165 | //-------------------------------------------------------------------------- 166 | // compare operands but ignore the sizes 167 | inline bool equal_mops_ignore_size(const mop_t& lo, const mop_t& ro) 168 | { 169 | if (lo.t != ro.t) 170 | return false; 171 | 172 | switch (lo.t) 173 | { 174 | case mop_z: // none 175 | return true; 176 | case mop_fn: // floating point 177 | return *ro.fpc == *lo.fpc; 178 | case mop_n: // immediate 179 | { 180 | const auto minsize = qmin(lo.size, ro.size); 181 | const auto v1 = extend_sign(ro.nnn->value, minsize, false); 182 | const auto v2 = extend_sign(lo.nnn->value, minsize, false); 183 | return v1 == v2; 184 | } 185 | case mop_S: // stack variable 186 | return *ro.s == *lo.s; 187 | case mop_v: // global variable 188 | return ro.g == lo.g; 189 | case mop_d: // result of another instruction 190 | // I added this 191 | return ro.d->equal_insns(*lo.d, EQ_IGNSIZE | EQ_IGNCODE); 192 | case mop_b: // micro basic block (mblock_t) 193 | return ro.b == lo.b; 194 | case mop_r: // register 195 | return ro.r == lo.r; 196 | case mop_f: 197 | break; // not implemented 198 | case mop_l: 199 | return *ro.l == *lo.l; 200 | case mop_a: 201 | return lo.a->insize == ro.a->insize 202 | && lo.a->outsize == ro.a->outsize 203 | && equal_mops_ignore_size(*lo.a, *ro.a); 204 | case mop_h: 205 | return streq(ro.helper, lo.helper); 206 | case mop_str: 207 | return streq(ro.cstr, lo.cstr); 208 | case mop_c: 209 | return *ro.c == *lo.c; 210 | case mop_p: 211 | return equal_mops_ignore_size(lo.pair->lop, ro.pair->lop) 212 | && equal_mops_ignore_size(lo.pair->hop, ro.pair->hop); 213 | case mop_sc: // not implemented 214 | break; 215 | } 216 | return false; 217 | } 218 | -------------------------------------------------------------------------------- /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 | explicit 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 b_force = 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/ReconstructableType.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 | 26 | #ifndef __H_RECONSTRUCTABLETYPE__ 27 | #define __H_RECONSTRUCTABLETYPE__ 28 | 29 | #pragma once 30 | #include "Common.h" 31 | 32 | extern int g_replace_id; 33 | 34 | enum MemberTypeKind { 35 | MemberType_Unknown = 0, 36 | MemberType_Reconsrtucted, 37 | MemberType_Pointer, 38 | MemberType_IDAGate 39 | }; 40 | 41 | enum SyncTypeInfoMethod { 42 | SyncTypeInfo_Names = 0, 43 | SyncTypeInfo_Full 44 | }; 45 | extern DLLEXPORT SyncTypeInfoMethod syncTypeInfoMethod; 46 | 47 | class ReconstructableType; 48 | class ReconstructableMember; 49 | class ReconstructedMemberType; 50 | 51 | class DLLEXPORT ReconstructedMemberType { 52 | MemberTypeKind kind; 53 | public: 54 | ReconstructedMemberType(MemberTypeKind k); 55 | ReconstructedMemberType(const ReconstructedMemberType &other); 56 | MemberTypeKind getKind(); 57 | 58 | virtual ~ReconstructedMemberType(); 59 | 60 | virtual unsigned long getSize() = 0; 61 | virtual std::string getTypeString() = 0; 62 | 63 | //virtual flags_t get_idaapi_flags() = 0; 64 | virtual void get_idaapi_tinfo(tinfo_t * out) = 0; 65 | 66 | virtual ReconstructedMemberType * clone() = 0; 67 | }; 68 | 69 | class DLLEXPORT ReconstructedMemberReType : public ReconstructedMemberType { 70 | public: 71 | ReconstructableType * reType; 72 | 73 | ReconstructedMemberReType(ReconstructableType *type); 74 | ReconstructedMemberReType(const ReconstructedMemberReType &other); 75 | 76 | virtual ~ReconstructedMemberReType(); 77 | virtual unsigned long getSize(); 78 | virtual std::string getTypeString(); 79 | //virtual flags_t get_idaapi_flags(); 80 | virtual void get_idaapi_tinfo(tinfo_t * out); 81 | virtual ReconstructedMemberType * clone(); 82 | }; 83 | 84 | 85 | class DLLEXPORT MemberTypeIDAFlagsTGate : public ReconstructedMemberType { 86 | 87 | flags_t flags; 88 | opinfo_t info; 89 | 90 | MemberTypeIDAFlagsTGate(flags_t f, opinfo_t i); 91 | MemberTypeIDAFlagsTGate(const MemberTypeIDAFlagsTGate &other); 92 | virtual ~MemberTypeIDAFlagsTGate(); 93 | 94 | virtual unsigned long getSize(); 95 | virtual std::string getTypeString(); 96 | //virtual flags_t get_idaapi_flags(); 97 | virtual void get_idaapi_tinfo(tinfo_t * out); 98 | virtual ReconstructedMemberType * clone(); 99 | 100 | }; 101 | 102 | class DLLEXPORT MemberTypeIDATypeInfoGate : public ReconstructedMemberType { 103 | 104 | public: 105 | tinfo_t info; 106 | MemberTypeIDATypeInfoGate(tinfo_t t); 107 | MemberTypeIDATypeInfoGate(const MemberTypeIDATypeInfoGate &other); 108 | virtual ~MemberTypeIDATypeInfoGate(); 109 | 110 | virtual unsigned long getSize(); 111 | virtual std::string getTypeString(); 112 | //virtual flags_t get_idaapi_flags(); 113 | virtual void get_idaapi_tinfo(tinfo_t * out); 114 | virtual ReconstructedMemberType * clone(); 115 | }; 116 | 117 | class DLLEXPORT MemberTypePointer : public ReconstructedMemberType { 118 | public : 119 | std::string pointedType; 120 | MemberTypePointer(std::string t); 121 | MemberTypePointer(const MemberTypePointer &other); 122 | virtual ~MemberTypePointer(); 123 | virtual unsigned long getSize(); 124 | virtual std::string getTypeString(); 125 | //virtual flags_t get_idaapi_flags(); 126 | virtual void get_idaapi_tinfo(tinfo_t * out); 127 | virtual ReconstructedMemberType * clone(); 128 | }; 129 | 130 | class DLLEXPORT ReconstructableMember 131 | { 132 | public: 133 | unsigned long offset; 134 | std::string name; 135 | ReconstructedMemberType *memberType; 136 | unsigned long getSize() { return memberType->getSize(); } 137 | ReconstructableMember(); 138 | ReconstructableMember(const ReconstructableMember &other); 139 | ~ReconstructableMember(); 140 | }; 141 | 142 | class DLLEXPORT ReconstructableType 143 | { 144 | 145 | /* members as it is - free from any container */ 146 | std::map ownMembers; 147 | /* members which were grouped to some type */ 148 | std::map derivedMembers; 149 | /* inherited types */ 150 | std::set childrenTypes; 151 | std::set parentTypes; 152 | protected: 153 | 154 | ReconstructableType(const std::string &Name); 155 | 156 | public: 157 | unsigned long id; 158 | std::string name; 159 | unsigned int typeId; 160 | unsigned long maxSize; 161 | 162 | virtual ~ReconstructableType(); 163 | 164 | 165 | virtual bool SetMemberName(unsigned long offset, const char * newName); 166 | virtual bool SetMemberNameUpcast(unsigned long offset, ReconstructableType *base, const char * newName); 167 | 168 | 169 | virtual bool SetMemberType(unsigned long offset, ReconstructedMemberType* newType); 170 | virtual bool SetMemberTypeUpcast(unsigned long offset, ReconstructableType *base, ReconstructedMemberType* newType); 171 | 172 | virtual bool AddMember(ReconstructableMember* member); 173 | virtual bool AddMemberUpcast(ReconstructableMember* member, ReconstructableType *base); 174 | virtual bool AddDerivedMember(ReconstructableMember* member); 175 | 176 | unsigned getSize(); 177 | ReconstructableMember* findMemberByOffset(unsigned long offset, bool isDerived); 178 | 179 | 180 | void CopyMembersToOther(ReconstructableType *other, unsigned long offset, std::string &namePrefix); 181 | void UndefMembers(unsigned long startOffset, unsigned long size, bool ownMember); 182 | void AddSubType(ReconstructableType *subType); 183 | 184 | virtual void SyncTypeInfo(); 185 | 186 | const std::set & getParents(); 187 | const std::set & getChildren(); 188 | 189 | const std::map & getDerivedMembers(); 190 | const std::map & getOwnMembers(); 191 | 192 | void SetMaxSize(unsigned long newSize); 193 | 194 | static ReconstructableType * getReconstructableType(const std::string &Name); 195 | 196 | }; 197 | 198 | class DLLEXPORT ReconstructableTypeVtable : public ReconstructableType { 199 | 200 | protected: 201 | ReconstructableTypeVtable(std::string Name, ea_t addr) : ReconstructableType(Name), vtable_address(addr) {}; 202 | 203 | public: 204 | ea_t vtable_address; 205 | 206 | virtual ~ReconstructableTypeVtable(); 207 | 208 | virtual bool SetMemberName(unsigned long offset, const char * newName); 209 | virtual bool SetMemberType(unsigned long offset, ReconstructedMemberType* new_type); 210 | virtual bool AddMember(ReconstructableMember* member); 211 | ea_t to_ea(unsigned long offset) const; 212 | 213 | static ReconstructableTypeVtable * get_reconstructable_type_vtable(const std::string &Name, ea_t addr); 214 | }; 215 | 216 | DLLEXPORT void re_types_form_init(); 217 | DLLEXPORT void re_types_form_fini(); 218 | 219 | extern DLLEXPORT std::map g_ReconstractedTypes; 220 | extern DLLEXPORT ea_t class_type_info_vtbl; 221 | extern DLLEXPORT ea_t si_class_type_info_vtbl; 222 | extern DLLEXPORT ea_t vmi_class_type_info_vtbl; 223 | 224 | #endif 225 | -------------------------------------------------------------------------------- /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 "Compat.h" 28 | #include "TypeReconstructor.h" 29 | #include "TypeExtractor.h" 30 | #include "CtreeExtractor.h" 31 | 32 | #include "Debug.h" 33 | #include "Utility.h" 34 | 35 | #if defined (__LINUX__) || defined (__MAC__) 36 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 37 | #endif 38 | 39 | #define STRUCT_DUMP_MIN_MEMBER_COUNT 4 40 | 41 | extern qvector vtbl_t_list; 42 | extern std::unordered_map rtti_vftables; 43 | 44 | struct obj_fint_t : public ctree_parentee_t 45 | { 46 | qstring vtbl_name; 47 | qstring var_name; 48 | bool bFound; 49 | 50 | int idaapi visit_expr(cexpr_t *e); 51 | 52 | obj_fint_t() 53 | : bFound(false) 54 | {} 55 | }; 56 | 57 | 58 | int idaapi obj_fint_t::visit_expr(cexpr_t *e) 59 | { 60 | // check if the expression being visited is variable 61 | if (e->op != cot_obj) 62 | return 0; 63 | 64 | // get the variable name 65 | qstring s; 66 | print1wrapper(e, &s, NULL); 67 | tag_remove(&s); 68 | 69 | // check for the target variable 70 | if (s != vtbl_name) 71 | return 0; 72 | 73 | size_t max_parents = 3; 74 | if (parents.size() < max_parents) { 75 | max_parents = parents.size(); 76 | } 77 | 78 | for (size_t i = 1; i <= max_parents; i++) { 79 | citem_t *parent = parents.back(); 80 | if (parent->is_expr() && parent->op == cot_asg) { 81 | cexpr_t * target_expr = (cexpr_t *)parent; 82 | 83 | while (target_expr->x != NULL && target_expr->op != cot_var && target_expr->op != cot_obj) 84 | target_expr = target_expr->x; 85 | 86 | if (target_expr->op == cot_var) { 87 | s.clear(); 88 | print1wrapper(target_expr, &s, NULL); 89 | tag_remove(&s); 90 | 91 | var_name = s; 92 | bFound = true; 93 | break; 94 | } 95 | } 96 | } 97 | 98 | return 0; 99 | } 100 | 101 | void idaapi reset_pointer_type(cfuncptr_t cfunc, const qstring &var_name) { 102 | lvars_t * locals = cfunc->get_lvars(); 103 | if (locals == NULL) 104 | return; 105 | 106 | qvector::iterator locals_iter; 107 | 108 | for (locals_iter = locals->begin(); locals_iter != locals->end(); locals_iter++) { 109 | if (var_name != locals_iter->name) 110 | continue; 111 | 112 | tinfo_t int_type = tinfo_t(BT_INT32); 113 | locals_iter->set_final_lvar_type(int_type); 114 | locals_iter->set_user_type(); 115 | cfunc->build_c_tree(); 116 | break; 117 | } 118 | } 119 | 120 | bool idaapi find_var(void *ud) 121 | { 122 | vdui_t &vu = *(vdui_t *)ud; 123 | 124 | // Determine the ctree item to highlight 125 | vu.get_current_item(USE_KEYBOARD); 126 | citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL; 127 | 128 | // highlight == NULL might happen if one chooses variable at local variables declaration statement 129 | if (!highlight) 130 | { 131 | logmsg(DEBUG, "Invalid item is choosen"); 132 | return false; 133 | } 134 | 135 | // the chosen item must be an expression and of 'variable' type 136 | if (highlight->is_expr() && (highlight->op == cot_obj)) 137 | { 138 | cexpr_t *highl_expr = (cexpr_t *)highlight; 139 | 140 | qstring s; 141 | print1wrapper(highlight, &s, NULL); 142 | tag_remove(&s); 143 | 144 | // initialize type rebuilder 145 | obj_fint_t obj_find; 146 | obj_find.vtbl_name = s; 147 | 148 | // traverse the ctree structure 149 | obj_find.apply_to(&vu.cfunc->body, NULL); 150 | 151 | if (obj_find.bFound) { 152 | logmsg(DEBUG, (obj_find.var_name + "\n").c_str()); 153 | reset_pointer_type(vu.cfunc, obj_find.var_name); 154 | 155 | vu.refresh_ctext(); 156 | } else { 157 | warning("Failed to find variable...\n"); 158 | logmsg(DEBUG, "Failed to find variable...\n"); 159 | } 160 | } 161 | 162 | return true; 163 | } 164 | 165 | bool idaapi find_var(cfuncptr_t cfunc, const qstring& vtbl_name, qstring &var_name) 166 | { 167 | var_name.clear(); 168 | 169 | obj_fint_t obj_find; 170 | obj_find.vtbl_name = vtbl_name; 171 | 172 | if (obj_find.vtbl_name.find("const ") == 0) 173 | obj_find.vtbl_name.remove(0, 6); 174 | 175 | // traverse the ctree structure 176 | obj_find.apply_to(&cfunc->body, NULL); 177 | 178 | if (!obj_find.bFound) { 179 | logmsg(DEBUG, "Failed to find variable...\n"); 180 | return false; 181 | } 182 | 183 | var_name = obj_find.var_name; 184 | reset_pointer_type(cfunc, var_name); 185 | return true; 186 | } 187 | 188 | tid_t idaapi merge_types(const qvector& types_to_merge, const qstring& type_name) { 189 | tid_t struct_type_id = BADADDR; 190 | 191 | if (types_to_merge.empty()) 192 | return struct_type_id; 193 | 194 | std::set offsets; 195 | 196 | struct_type_id = Compat::add_struc(BADADDR, type_name.c_str()); 197 | if (struct_type_id == BADADDR) 198 | return struct_type_id; 199 | 200 | for (auto types_iter = types_to_merge.begin(), end = types_to_merge.end(); types_iter != end; ++types_iter) { 201 | tid_t struc_id = Compat::get_struc_id(types_iter->c_str()); 202 | if (struc_id == BADADDR) 203 | continue; 204 | 205 | // enumerate members 206 | for (ea_t offset = Compat::get_struc_first_offset(struc_id); offset != BADADDR; 207 | offset = Compat::get_struc_next_offset(struc_id, offset)) { 208 | tid_t mem_id = Compat::get_member_id(struc_id, offset); 209 | if (mem_id == BADADDR || offsets.count(offset) > 0) 210 | continue; 211 | 212 | qstring member_name = Compat::get_member_name(struc_id, offset); 213 | asize_t member_size = Compat::get_member_size(struc_id, offset); 214 | 215 | if (member_name.find("vftbl_", 0) != -1) { 216 | tinfo_t tif; 217 | if (Compat::get_member_tinfo(&tif, struc_id, offset)) { 218 | struc_error_t result = Compat::add_struc_member(struc_id, member_name.c_str(), offset, dword_flag(), nullptr, member_size); 219 | if (result == STRUC_ERROR_MEMBER_OK) 220 | Compat::set_member_tinfo(struc_id, offset, tif, SET_MEMTI_COMPATIBLE); 221 | } 222 | } else { 223 | int flag = Compat::get_member_flag(struc_id, offset); 224 | Compat::add_struc_member(struc_id, member_name.c_str(), offset, flag, NULL, member_size); 225 | } 226 | 227 | offsets.insert(offset); 228 | } 229 | } 230 | 231 | return struct_type_id; 232 | } 233 | 234 | void get_struct_key(tid_t struc_id, const VTBL_info_t& vtbl_info, qstring &file_entry_key, bool &filtered, const std::unordered_map& vtbl_map) { 235 | qstring sub_key; 236 | qstring vtables_sub_key; 237 | int vftbales_num = 0; 238 | int members_count = 0; 239 | for (ea_t offset = Compat::get_struc_first_offset(struc_id); offset != BADADDR; 240 | offset = Compat::get_struc_next_offset(struc_id, offset)) { 241 | tid_t mem_id = Compat::get_member_id(struc_id, offset); 242 | if (mem_id == BADADDR) 243 | continue; 244 | 245 | qstring member_name = Compat::get_member_name(struc_id, offset); 246 | asize_t member_size = Compat::get_member_size(struc_id, offset); 247 | 248 | if (member_name.find("vftbl_", 0) != -1) { 249 | ea_t vtable_addr = 0; 250 | int i; 251 | if (qsscanf(member_name.c_str(), "vftbl_%d_%" FMT_EA "x", &i, &vtable_addr) > 0) { 252 | if (vtbl_map.count(vtable_addr) != 0) { 253 | vtables_sub_key.cat_sprnt("_%d", vtbl_map.at(vtable_addr).methods); 254 | } 255 | } 256 | vftbales_num++; 257 | } 258 | 259 | sub_key.cat_sprnt("_%d", member_size); 260 | 261 | members_count ++; 262 | } 263 | file_entry_key.sprnt("t_%d_%d", vtbl_info.methods, vftbales_num); 264 | file_entry_key += vtables_sub_key; 265 | file_entry_key += sub_key; 266 | 267 | if (members_count < STRUCT_DUMP_MIN_MEMBER_COUNT) 268 | filtered = true; 269 | } 270 | 271 | void idaapi dump_type_info(int file_id, const VTBL_info_t& vtbl_info, const qstring& type_name, const std::unordered_map& vtbl_map) { 272 | tid_t struc_id = Compat::get_struc_id(type_name.c_str()); 273 | if (struc_id == BADADDR) 274 | return; 275 | 276 | qstring file_entry_key; 277 | qstring key_hash; 278 | bool filtered = false; 279 | 280 | get_struct_key(struc_id, vtbl_info, file_entry_key, filtered, vtbl_map); 281 | get_hash_of_string(file_entry_key, key_hash); 282 | 283 | if (filtered) 284 | return; 285 | 286 | qstring file_entry_val; 287 | tinfo_t new_type = create_typedef(type_name.c_str()); 288 | 289 | if (new_type.is_correct() && new_type.print(&file_entry_val, NULL, PRTYPE_DEF | PRTYPE_1LINE)) { 290 | qstring line; 291 | 292 | line = key_hash + ";" + file_entry_key + ";"; 293 | line.cat_sprnt("%a;", vtbl_info.ea_begin); 294 | line += file_entry_val + ";"; 295 | 296 | if (rtti_vftables.count(vtbl_info.ea_begin) != 0) { 297 | VTBL_info_t vi = rtti_vftables[vtbl_info.ea_begin]; 298 | line += vi.vtbl_name; 299 | } 300 | line.rtrim(); 301 | line += "\r\n"; 302 | qwrite(file_id, line.c_str(), line.length()); 303 | } 304 | } 305 | 306 | bool idaapi check_subtype(VTBL_info_t vtbl_info, qstring subtype_name) { 307 | qstring search_str; 308 | search_str.sprnt("_%a", vtbl_info.ea_begin); 309 | 310 | tid_t struc_id = Compat::get_struc_id(subtype_name.c_str()); 311 | if (struc_id == BADADDR) 312 | return false; 313 | 314 | // enumerate members 315 | for (ea_t offset = Compat::get_struc_first_offset(struc_id); offset != BADADDR; 316 | offset = Compat::get_struc_next_offset(struc_id, offset)) { 317 | tid_t mem_id = Compat::get_member_id(struc_id, offset); 318 | if (mem_id == BADADDR) 319 | continue; 320 | 321 | qstring member_name = Compat::get_member_name(struc_id, offset); 322 | if (member_name.find(search_str, 0) != member_name.npos) 323 | return true; 324 | } 325 | 326 | return false; 327 | } 328 | 329 | bool idaapi extract_all_types(void *ud) 330 | { 331 | logmsg(DEBUG, "extract_types()\n"); 332 | 333 | // find vtables in the binary 334 | search_objects(false); 335 | 336 | qvector ::iterator vtbl_iter; 337 | 338 | std::unordered_map vtbl_map; 339 | for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) 340 | vtbl_map[(*vtbl_iter).ea_begin] = (*vtbl_iter); 341 | 342 | int file_id = create_open_file("types.txt"); 343 | if (file_id == -1) 344 | { 345 | logmsg(ERROR, "Failed to open file for dumping types.txt\r\n"); 346 | return false; 347 | } 348 | 349 | int struct_no = 0; 350 | 351 | for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) { 352 | qstring info_msg; 353 | info_msg.cat_sprnt("Processing vtable %s\n", (*vtbl_iter).vtbl_name.c_str()); 354 | logmsg(DEBUG, info_msg.c_str()); 355 | 356 | qstring type_name; 357 | type_name.sprnt("struc_2_%d", struct_no); 358 | 359 | ea_t cur_vt_ea = (*vtbl_iter).ea_begin; 360 | int struct_subno = 0; 361 | 362 | qvector types_to_merge; 363 | for (ea_t addr = get_first_dref_to(cur_vt_ea); addr != BADADDR; addr = get_next_dref_to(cur_vt_ea, addr)) { 364 | qstring name; 365 | if (get_func_name(&name, addr) <= 0) 366 | continue; 367 | 368 | qstring info_msg1; 369 | info_msg1.cat_sprnt("\t%s\n", name.c_str()); 370 | logmsg(DEBUG, info_msg1.c_str()); 371 | 372 | func_t *pfn = get_func(addr); 373 | if (!pfn) 374 | continue; 375 | 376 | hexrays_failure_t hf; 377 | cfuncptr_t cfunc = decompile(pfn, &hf); 378 | if (cfunc != NULL) { 379 | qstring var_name; 380 | info_msg.clear(); 381 | 382 | if (find_var(cfunc, (*vtbl_iter).vtbl_name, var_name)) { 383 | info_msg.cat_sprnt(" : %s\n", var_name.c_str()); 384 | logmsg(DEBUG, info_msg.c_str()); 385 | 386 | qstring sub_type_name = type_name; 387 | sub_type_name.cat_sprnt("_%d", struct_subno); 388 | struct_subno++; 389 | 390 | if (reconstruct_type(cfunc, var_name, sub_type_name)) { 391 | if (check_subtype((*vtbl_iter), sub_type_name)) { 392 | types_to_merge.push_back(sub_type_name); 393 | } 394 | } 395 | } 396 | else { 397 | info_msg.cat_sprnt(" : none\n"); 398 | logmsg(DEBUG, info_msg.c_str()); 399 | } 400 | } 401 | } 402 | 403 | struct_no++; 404 | 405 | merge_types(types_to_merge, type_name); 406 | dump_type_info(file_id, (*vtbl_iter), type_name, vtbl_map); 407 | } 408 | 409 | qclose(file_id); 410 | return true; 411 | } 412 | -------------------------------------------------------------------------------- /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.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 | struct reconstruct_type_params_t 52 | { 53 | ea_t func_ea; 54 | char var_name[100]; 55 | char type_name[100]; 56 | }; 57 | 58 | bool idaapi reconstruct_type(const reconstruct_type_params_t & params); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /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 | display_widget(widget, WOPN_RESTORE); 58 | 59 | return false; 60 | } 61 | 62 | void split_qstring(const qstring &options, const qstring &splitter, qvector &result) { 63 | size_t start_pos = 0; 64 | 65 | do { 66 | size_t npos = options.find(splitter, start_pos); 67 | if (npos != -1) { 68 | if (npos != start_pos) { 69 | result.push_back(options.substr(start_pos, npos)); 70 | } 71 | start_pos = npos + splitter.length(); 72 | } 73 | else { 74 | qstring token = options.substr(start_pos); 75 | if (token.length() != 0) 76 | result.push_back(token); 77 | break; 78 | } 79 | } while (start_pos < options.length()); 80 | } 81 | 82 | 83 | // SHA1 implementation 84 | #define SHA1CircularShift(bits,word)(((word) << (bits)) | ((word) >> (32-(bits)))) 85 | 86 | void SHA1PadMessage(SHA1Context *); 87 | void SHA1ProcessMessageBlock(SHA1Context *); 88 | 89 | int SHA1Reset(SHA1Context *context) 90 | { 91 | if (!context) 92 | return shaNull; 93 | 94 | context->Length_Low = 0; 95 | context->Length_High = 0; 96 | context->Message_Block_Index = 0; 97 | context->Intermediate_Hash[0] = 0x67452301; 98 | context->Intermediate_Hash[1] = 0xEFCDAB89; 99 | context->Intermediate_Hash[2] = 0x98BADCFE; 100 | context->Intermediate_Hash[3] = 0x10325476; 101 | context->Intermediate_Hash[4] = 0xC3D2E1F0; 102 | context->Computed = 0; 103 | context->Corrupted = 0; 104 | return shaSuccess; 105 | } 106 | 107 | int SHA1Result(SHA1Context *context, uint8_t Message_Digest[SHA1HashSize]) 108 | { 109 | int i; 110 | if (!context || !Message_Digest) 111 | return shaNull; 112 | 113 | if (context->Corrupted) 114 | return context->Corrupted; 115 | 116 | if (!context->Computed) 117 | { 118 | SHA1PadMessage(context); 119 | for (i = 0; i<64; ++i) 120 | context->Message_Block[i] = 0; 121 | 122 | context->Length_Low = 0; /* and clear length */ 123 | context->Length_High = 0; 124 | context->Computed = 1; 125 | } 126 | for (i = 0; i < SHA1HashSize; ++i) 127 | Message_Digest[i] = context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03)); 128 | 129 | return shaSuccess; 130 | } 131 | 132 | int SHA1Input(SHA1Context *context, const uint8_t *message_array, unsigned int length) 133 | { 134 | if (!length) 135 | { 136 | return shaSuccess; 137 | } 138 | if (!context || !message_array) 139 | { 140 | return shaNull; 141 | } 142 | if (context->Computed) 143 | { 144 | context->Corrupted = shaStateError; 145 | return shaStateError; 146 | } 147 | if (context->Corrupted) 148 | { 149 | return context->Corrupted; 150 | } 151 | while (length-- && !context->Corrupted) 152 | { 153 | context->Message_Block[context->Message_Block_Index++] = 154 | (*message_array & 0xFF); 155 | context->Length_Low += 8; 156 | if (context->Length_Low == 0) 157 | { 158 | context->Length_High++; 159 | if (context->Length_High == 0) 160 | context->Corrupted = 1; 161 | } 162 | if (context->Message_Block_Index == 64) 163 | SHA1ProcessMessageBlock(context); 164 | message_array++; 165 | } 166 | return shaSuccess; 167 | } 168 | 169 | void SHA1ProcessMessageBlock(SHA1Context *context) 170 | { 171 | const uint32_t K[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6}; 172 | int t; // Loop counter 173 | uint32_t temp; // Temporary word value 174 | uint32_t W[80]; // Word sequence 175 | uint32_t A, B, C, D, E; // Word buffers 176 | // Initialize the first 16 words in the array W 177 | for (t = 0; t < 16; t++) 178 | { 179 | W[t] = context->Message_Block[t * 4] << 24; 180 | W[t] |= context->Message_Block[t * 4 + 1] << 16; 181 | W[t] |= context->Message_Block[t * 4 + 2] << 8; 182 | W[t] |= context->Message_Block[t * 4 + 3]; 183 | } 184 | 185 | for (t = 16; t < 80; t++) 186 | W[t] = SHA1CircularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); 187 | 188 | A = context->Intermediate_Hash[0]; 189 | B = context->Intermediate_Hash[1]; 190 | C = context->Intermediate_Hash[2]; 191 | D = context->Intermediate_Hash[3]; 192 | E = context->Intermediate_Hash[4]; 193 | 194 | for (t = 0; t < 20; t++) 195 | { 196 | temp = SHA1CircularShift(5, A) + 197 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 198 | E = D; 199 | D = C; 200 | C = SHA1CircularShift(30, B); 201 | B = A; 202 | A = temp; 203 | } 204 | 205 | for (t = 20; t < 40; t++) 206 | { 207 | temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; 208 | E = D; 209 | D = C; 210 | C = SHA1CircularShift(30, B); 211 | B = A; 212 | A = temp; 213 | } 214 | 215 | for (t = 40; t < 60; t++) 216 | { 217 | temp = SHA1CircularShift(5, A) + 218 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 219 | E = D; 220 | D = C; 221 | C = SHA1CircularShift(30, B); 222 | B = A; 223 | A = temp; 224 | } 225 | 226 | for (t = 60; t < 80; t++) 227 | { 228 | temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; 229 | E = D; 230 | D = C; 231 | C = SHA1CircularShift(30, B); 232 | B = A; 233 | A = temp; 234 | } 235 | 236 | context->Intermediate_Hash[0] += A; 237 | context->Intermediate_Hash[1] += B; 238 | context->Intermediate_Hash[2] += C; 239 | context->Intermediate_Hash[3] += D; 240 | context->Intermediate_Hash[4] += E; 241 | context->Message_Block_Index = 0; 242 | } 243 | 244 | void SHA1PadMessage(SHA1Context *context) 245 | { 246 | 247 | if (context->Message_Block_Index > 55) 248 | { 249 | context->Message_Block[context->Message_Block_Index++] = 0x80; 250 | while (context->Message_Block_Index < 64) 251 | context->Message_Block[context->Message_Block_Index++] = 0; 252 | 253 | SHA1ProcessMessageBlock(context); 254 | while (context->Message_Block_Index < 56) 255 | context->Message_Block[context->Message_Block_Index++] = 0; 256 | } 257 | else 258 | { 259 | context->Message_Block[context->Message_Block_Index++] = 0x80; 260 | while (context->Message_Block_Index < 56) 261 | context->Message_Block[context->Message_Block_Index++] = 0; 262 | } 263 | 264 | context->Message_Block[56] = context->Length_High >> 24; 265 | context->Message_Block[57] = context->Length_High >> 16; 266 | context->Message_Block[58] = context->Length_High >> 8; 267 | context->Message_Block[59] = context->Length_High; 268 | context->Message_Block[60] = context->Length_Low >> 24; 269 | context->Message_Block[61] = context->Length_Low >> 16; 270 | context->Message_Block[62] = context->Length_Low >> 8; 271 | context->Message_Block[63] = context->Length_Low; 272 | SHA1ProcessMessageBlock(context); 273 | } 274 | 275 | char int_to_hex(uint8_t integ) { 276 | if (integ < 10) 277 | return '0' + integ; 278 | else 279 | return 'a' + (integ - 10); 280 | } 281 | 282 | void SHA1MessageDigestToString(uint8_t Message_Digest[SHA1HashSize], char outbuffer[SHA1HashSize * 2]) { 283 | for (int i = 0; i < SHA1HashSize; i++) { 284 | outbuffer[i * 2] = int_to_hex(Message_Digest[i] >> 4); 285 | outbuffer[i * 2 + 1] = int_to_hex(Message_Digest[i] & 0xF); 286 | } 287 | } 288 | 289 | void idaapi setUnknown(ea_t ea, asize_t size) 290 | { 291 | // TODO: Does the overrun problem still exist? 292 | //do_unknown_range(ea, (size_t)size, DOUNK_SIMPLE); 293 | while (size > 0) 294 | { 295 | asize_t isize = get_item_size(ea); 296 | if (isize > size) 297 | break; 298 | 299 | del_items(ea); 300 | ea += (ea_t)isize; 301 | size -= isize; 302 | }; 303 | } 304 | 305 | 306 | void MakeName(ea_t ea, const qstring& name, const qstring& prefix, const qstring& postfix) 307 | { 308 | qstring g_name(prefix); 309 | g_name += name; 310 | g_name += postfix; 311 | 312 | g_name.replace(" ", "_"); 313 | g_name.replace("*", "_"); 314 | g_name.replace(",", "_"); 315 | g_name.replace("<", "_lt"); 316 | g_name.replace(">", "_ge"); 317 | set_name(ea, g_name.c_str(), SN_NOWARN); 318 | } 319 | 320 | bool MakeArray(ea_t ea, size_t nitems) 321 | { 322 | asize_t itemsize = 0; 323 | tid_t tid = BADADDR; 324 | flags_t flags = get_flags(ea); 325 | if (is_code(flags) || is_tail(flags) || is_align(flags)) 326 | return false; 327 | 328 | if (is_unknown(flags)) 329 | flags = 0; 330 | 331 | if (is_struct(flags)) 332 | { 333 | opinfo_t ti; 334 | if (!get_opinfo(&ti, ea, 0, flags)) 335 | return false; 336 | itemsize = get_data_elsize(ea, flags, &ti); 337 | tid = ti.tid; 338 | } 339 | else 340 | { 341 | itemsize = get_item_size(ea); 342 | } 343 | 344 | return create_data(ea, flags, static_cast(itemsize * nitems), tid); 345 | } 346 | -------------------------------------------------------------------------------- /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 | #define VTBL_NAME_POSTFIX "::vftable" 32 | #define VTBL_CLSNAME_POSTFIX "::vtable" 33 | 34 | // Simple CustomView Form Init 35 | struct string_view_form_info_t 36 | { 37 | TWidget *widget; 38 | TWidget *cv; 39 | TWidget *codeview; 40 | strvec_t sv; 41 | string_view_form_info_t(TWidget *f) : widget(f), cv(nullptr), codeview(nullptr) {} 42 | }; 43 | 44 | bool idaapi show_string_in_custom_view(void *ud, const qstring& title, const qstring& str); 45 | 46 | 47 | // Size of string with out terminator 48 | //#define SIZESTR(x) (sizeof(x) - 1) 49 | 50 | #ifndef _countof 51 | # define _countof(x) (sizeof((x)) / sizeof((x)[0])) 52 | #endif // _countof 53 | 54 | 55 | typedef qlist eaList; 56 | typedef std::set eaSet; 57 | typedef std::map eaRefMap; 58 | struct earef 59 | { 60 | ea_t ea; 61 | UINT refs; 62 | }; 63 | 64 | 65 | // 66 | // #pragma message(__LOC__ "important part to be changed") 67 | // #pragma message(__LOC2__ "error C9901: wish that error would exist") 68 | 69 | // Get IDA 32 bit value with verification 70 | template bool getVerify32_t(ea_t eaPtr, T &rValue) 71 | { 72 | // Location valid? 73 | if (is_loaded(eaPtr)) 74 | { 75 | // Get 32bit value 76 | rValue = (T) get_32bit(eaPtr); 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | 84 | #define MSVC_COMPILER_ABBR "vc" 85 | #define GCC_COMPILER_ABBR "gcc" 86 | 87 | // Check compiler 88 | bool compilerIs(const char *name); 89 | 90 | inline bool createEa(ea_t ea, asize_t length, bool force = false) 91 | { 92 | return inf_is_64bit() ? create_qword(ea, length, force) : create_dword(ea, length, force); 93 | } 94 | 95 | // Get address/pointer value 96 | inline ea_t getEa(ea_t ea) 97 | { 98 | return inf_is_64bit() ? (ea_t)get_64bit(ea) : (ea_t)get_32bit(ea); 99 | } 100 | 101 | // Returns TRUE if ea_t sized value flags 102 | inline bool isEa(flags_t f) 103 | { 104 | return inf_is_64bit() ? is_qword(f) : is_dword(f); 105 | } 106 | 107 | #ifndef _SHA_enum_ 108 | #define _SHA_enum_ 109 | enum 110 | { 111 | shaSuccess = 0, 112 | shaNull, // Null pointer parameter 113 | shaInputTooLong, // input data too long 114 | shaStateError // called Input after Result 115 | }; 116 | #endif 117 | #define SHA1HashSize 20 118 | 119 | typedef struct SHA1Context 120 | { 121 | uint32_t Intermediate_Hash[SHA1HashSize / 4]; // Message Digest 122 | uint32_t Length_Low; // Message length in bits 123 | uint32_t Length_High; // Message length in bits 124 | // Index into message block array 125 | int_least16_t Message_Block_Index; 126 | uint8_t Message_Block[64]; // 512-bit message blocks 127 | int Computed; // Is the digest computed? 128 | int Corrupted; // Is the message digest corrupted? 129 | } SHA1Context; 130 | 131 | int SHA1Reset(SHA1Context *); 132 | int SHA1Input(SHA1Context *, const uint8_t *, unsigned int); 133 | int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1HashSize]); 134 | void SHA1MessageDigestToString(uint8_t Message_Digest[SHA1HashSize], char outbuffer[SHA1HashSize * 2]); 135 | 136 | void split_qstring(const qstring &options, const qstring &splitter, qvector &result); 137 | 138 | void idaapi setUnknown(ea_t ea, asize_t size); 139 | void MakeName(ea_t ea, const qstring& name, const qstring& prefix = "", const qstring& postfix = ""); 140 | bool MakeArray(ea_t ea, size_t nitems); 141 | 142 | inline bool ends_with(std::string const & value, std::string const & ending) 143 | { 144 | if (ending.size() > value.size()) return false; 145 | return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); 146 | } 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/gcc_rtti_til.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct GCC_RTTI::__vtable_info { 4 | size_t ptrdiff; 5 | void* type_info; 6 | }; 7 | struct GCC_RTTI::__class_type_info; 8 | struct GCC_RTTI::type_info { 9 | GCC_RTTI::__vtable_info* __type_info_vtable; 10 | char * __type_info_name; 11 | }; 12 | struct GCC_RTTI::__pbase_type_info : public GCC_RTTI::type_info { 13 | int quals; 14 | void *type; 15 | enum quals_masks { 16 | const_mask = 0x1, 17 | volatile_mask = 0x2, 18 | restrict_mask = 0x4, 19 | incomplete_mask = 0x8, 20 | incomplete_class_mask = 0x10 21 | }; 22 | }; 23 | struct GCC_RTTI::__pointer_type_info 24 | : public GCC_RTTI::__pbase_type_info { 25 | const GCC_RTTI::__class_type_info *klass; 26 | }; 27 | struct GCC_RTTI::__base_class_info { 28 | void * base; 29 | size_t vmi_offset_flags; 30 | enum vmi_masks { 31 | virtual_mask = 0x1, 32 | public_mask = 0x2, 33 | hwm_bit = 2, 34 | offset_shift = 8 35 | }; 36 | }; 37 | struct GCC_RTTI::__class_type_info 38 | : public GCC_RTTI::type_info 39 | { 40 | enum __sub_kind 41 | { 42 | __unknown = 0, 43 | __not_contained, 44 | __contained_ambig, 45 | __contained_virtual_mask = 0x1, 46 | __contained_public_mask = 0x2, 47 | __contained_mask = 1 << 2, 48 | __contained_private = __contained_mask, 49 | __contained_public = __contained_mask | __contained_public_mask 50 | }; 51 | }; 52 | struct GCC_RTTI::__si_class_type_info 53 | : public GCC_RTTI::__class_type_info 54 | { 55 | void * base; 56 | }; 57 | struct GCC_RTTI::__vmi_class_type_info : public GCC_RTTI::__class_type_info 58 | { 59 | int vmi_flags; 60 | int vmi_base_count; 61 | struct GCC_RTTI::__base_class_info vmi_bases[1]; 62 | 63 | enum vmi_flags_masks { 64 | non_diamond_repeat_mask = 0x1, 65 | diamond_shaped_mask = 0x2, 66 | non_public_base_mask = 0x4, 67 | public_base_mask = 0x8, 68 | __flags_unknown_mask = 0x10 69 | }; 70 | }; 71 | struct GCC_RTTI::__user_type_info : public GCC_RTTI::type_info 72 | { 73 | enum sub_kind 74 | { 75 | unknown = 0, 76 | not_contained, 77 | contained_ambig, 78 | contained_mask = 4, 79 | contained_virtual_mask = 1, 80 | contained_public_mask = 2, 81 | contained_private = contained_mask, 82 | contained_public = contained_mask | contained_public_mask 83 | }; 84 | 85 | }; 86 | 87 | struct GCC_RTTI::virtual_destruct_vtable_info { 88 | struct GCC_RTTI::__vtable_info info; 89 | void (*scalar_destruct)(void *); 90 | void (*vector_destruct)(void *); 91 | }; -------------------------------------------------------------------------------- /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)CtreeExtractor.cpp \ 16 | $(SRCDIR)CtreeGraphBuilder.cpp \ 17 | $(SRCDIR)Debug.cpp \ 18 | $(SRCDIR)GCCObjectFormatParser.cpp \ 19 | $(SRCDIR)GCCTypeInfo.cpp \ 20 | $(SRCDIR)GCCVtableInfo.cpp \ 21 | $(SRCDIR)IObjectFormatParser.cpp \ 22 | $(SRCDIR)MSVCObjectFormatParser.cpp \ 23 | $(SRCDIR)ObjectExplorer.cpp \ 24 | $(SRCDIR)ReconstructableType.cpp \ 25 | $(SRCDIR)reconstructed_place_t.cpp \ 26 | $(SRCDIR)TypeExtractor.cpp \ 27 | $(SRCDIR)TypeReconstructor.cpp \ 28 | $(SRCDIR)MicrocodeExtractor.cpp \ 29 | $(SRCDIR)Utility.cpp 30 | 31 | OBJS=$(subst .cpp,.o,$(SRC)) 32 | 33 | CFLAGS=-m64 -fPIC -D__LINUX__ -D__PLUGIN__ -std=c++11 -D__X64__ -D_GLIBCXX_USE_CXX11_ABI=0 34 | LIBS=-lc -lpthread -ldl 35 | 36 | ifeq ($(EA64),1) 37 | CFLAGS+=-D__EA64__ 38 | LIBS+=-lida64 39 | EXT=so 40 | SUFFIX=64 41 | else 42 | EXT=so 43 | LIBS+=-lida 44 | SUFFIX= 45 | endif 46 | 47 | all: check-env clean HexRaysCodeXplorer$(SUFFIX).$(EXT) 48 | 49 | HexRaysCodeXplorer$(SUFFIX).$(EXT): $(OBJS) 50 | $(CC) $(LDFLAGS) $(LIBDIR) -o HexRaysCodeXplorer$(SUFFIX).$(EXT) $(OBJS) $(LIBS) 51 | 52 | %.o: %.cpp 53 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ 54 | 55 | clean: 56 | rm -f $(OBJS) HexRaysCodeXplorer$(SUFFIX).$(EXT) 57 | 58 | install: 59 | cp -f HexRaysCodeXplorer$(SUFFIX).$(EXT) $(IDA_DIR)/plugins 60 | 61 | check-env: 62 | ifndef IDA_SDK 63 | $(error IDA_SDK is undefined) 64 | endif 65 | ifndef IDA_DIR 66 | $(error IDA_DIR is undefined) 67 | endif 68 | ifndef EA64 69 | $(error specify EA64=0 for 32 bit build or EA64=1 for 64 bit build) 70 | endif 71 | .PHONY: check-env 72 | -------------------------------------------------------------------------------- /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 | 34 | SRC=$(SRCDIR)CodeXplorer.cpp \ 35 | $(SRCDIR)CtreeExtractor.cpp \ 36 | $(SRCDIR)CtreeGraphBuilder.cpp \ 37 | $(SRCDIR)Debug.cpp \ 38 | $(SRCDIR)GCCObjectFormatParser.cpp \ 39 | $(SRCDIR)GCCTypeInfo.cpp \ 40 | $(SRCDIR)GCCVtableInfo.cpp \ 41 | $(SRCDIR)IObjectFormatParser.cpp \ 42 | $(SRCDIR)MSVCObjectFormatParser.cpp \ 43 | $(SRCDIR)ObjectExplorer.cpp \ 44 | $(SRCDIR)ReconstructableType.cpp \ 45 | $(SRCDIR)reconstructed_place_t.cpp \ 46 | $(SRCDIR)TypeExtractor.cpp \ 47 | $(SRCDIR)TypeReconstructor.cpp \ 48 | $(SRCDIR)Utility.cpp 49 | 50 | OBJS=$(subst .cpp,.o,$(SRC)) 51 | EXECUTABLE=HexRaysCodeXplorer 52 | INCLUDES=-I$(IDA_SDK)/include -I$(HEXRAYS_SDK)/include 53 | 54 | # only used on command line anyway 55 | #DEFINE=__X64__ -D__LINUX__ 56 | #DEFINE=__EA64__ -D__LINUX__ 57 | 58 | all: check-env HexRaysCodeXplorer.$(EXT) 59 | 60 | HexRaysCodeXplorer.$(EXT): $(OBJS) 61 | #ln -f -s $(IDA_SDK)/lib/x64_linux_gcc_64/pro.a libpro.a 62 | ln -f -s $(IDA_SDK)/lib/x86_mac_gcc_32/pro.a libpro.a 63 | $(CC) $(LDFLAGS) $(LIBDIR) -o HexRaysCodeXplorer.$(EXT) $(OBJS) $(LIBS) 64 | 65 | %.o: %.cpp 66 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ 67 | 68 | clean: 69 | rm -f $(OBJS) HexRaysCodeXplorer.$(EXT) 70 | 71 | install: 72 | cp -f HexRaysCodeXplorer.$(EXT) $(IDA_DIR)/plugins 73 | 74 | check-env: 75 | ifndef IDA_SDK 76 | $(error IDA_SDK is undefined) 77 | endif 78 | ifndef IDA_DIR 79 | $(error IDA_DIR is undefined) 80 | endif 81 | 82 | .PHONY: check-env 83 | -------------------------------------------------------------------------------- /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 -lc++ -liconv 6 | INCLUDES=-I$(IDA_SDK)/include -I$(IDA_DIR)/plugins/hexrays_sdk/include 7 | 8 | SRCDIR=./ 9 | SRC=$(SRCDIR)CodeXplorer.cpp \ 10 | $(SRCDIR)CtreeExtractor.cpp \ 11 | $(SRCDIR)CtreeGraphBuilder.cpp \ 12 | $(SRCDIR)Debug.cpp \ 13 | $(SRCDIR)GCCObjectFormatParser.cpp \ 14 | $(SRCDIR)GCCTypeInfo.cpp \ 15 | $(SRCDIR)GCCVtableInfo.cpp \ 16 | $(SRCDIR)IObjectFormatParser.cpp \ 17 | $(SRCDIR)MSVCObjectFormatParser.cpp \ 18 | $(SRCDIR)ObjectExplorer.cpp \ 19 | $(SRCDIR)ReconstructableType.cpp \ 20 | $(SRCDIR)reconstructed_place_t.cpp \ 21 | $(SRCDIR)TypeExtractor.cpp \ 22 | $(SRCDIR)TypeReconstructor.cpp \ 23 | $(SRCDIR)MicrocodeExtractor.cpp \ 24 | $(SRCDIR)Utility.cpp 25 | 26 | #SRC = $(wildcard src/*.cpp) 27 | #OBJS=$(subst .cpp,.o,$(SRC)) 28 | 29 | all: check-env HexRaysCodeXplorer.dylib HexRaysCodeXplorer64.dylib 30 | 31 | HexRaysCodeXplorer.dylib: $(SRC) 32 | $(CXX) $(LDFLAGS) $(SRC) $(CXXFLAGS) -L. -L$(IDA_DIR) $(INCLUDES) -D__MAC__=1 $(LIBS) -lida -o HexRaysCodeXplorer.dylib 33 | 34 | HexRaysCodeXplorer64.dylib: $(SRC) 35 | $(CXX) $(LDFLAGS) $(SRC) $(CXXFLAGS) -L. -L$(IDA_DIR) $(INCLUDES) -D__MAC__=1 -D__EA64__=1 $(LIBS) -lida64 -o HexRaysCodeXplorer64.dylib 36 | 37 | clean: 38 | rm -f HexRaysCodeXplorer.dylib HexRaysCodeXplorer64.dylib 39 | 40 | install: 41 | cp -f HexRaysCodeXplorer.dylib $(IDA_DIR)/plugins/ 42 | cp -f HexRaysCodeXplorer64.dylib $(IDA_DIR)/plugins/ 43 | 44 | check-env: 45 | ifndef IDA_SDK 46 | $(error IDA_SDK is undefined) 47 | endif 48 | ifndef IDA_DIR 49 | $(error IDA_DIR is undefined) 50 | endif 51 | # pwd && cp -f $(IDA_SDK)/lib/x64_mac_clang_64/pro.a libpro.a 52 | 53 | .PHONY: check-env -------------------------------------------------------------------------------- /src/HexRaysCodeXplorer/reconstructed_place_t.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Common.h" 3 | 4 | 5 | enum reconstructed_place_pos_t { 6 | REPLACE_SPLIT = 0, 7 | REPLACE_BLANK, 8 | REPLACE_CLASSNAME_TOP, 9 | REPLACE_PARENTS, 10 | REPLACE_CHILDREN, 11 | REPLACE_MEMBERS, 12 | REPLACE_BLANK_BOT, 13 | REPLACE_CLASSNAME_BOT 14 | }; 15 | 16 | 17 | class ReconstructableType; 18 | 19 | class reconstructed_place_t : public place_t { 20 | 21 | public: 22 | std::string typeName; ///< rectype name 23 | uval_t index; 24 | reconstructed_place_pos_t position; 25 | bool atOwnMembers; 26 | uval_t own_offset; 27 | reconstructed_place_t(); 28 | reconstructed_place_t(std::string n); 29 | reconstructed_place_t(const reconstructed_place_t &other); 30 | 31 | virtual void idaapi print(qstring * out_buf, void * ud) const override; 32 | virtual uval_t idaapi touval(void * ud) const override; 33 | virtual place_t *idaapi clone(void) const override; 34 | virtual void idaapi copyfrom(const place_t * from) override; 35 | virtual place_t *idaapi makeplace(void * ud, uval_t x, int lnnum) const override; 36 | virtual int idaapi compare(const place_t * t2) const override; 37 | virtual void idaapi adjust(void * ud) override; 38 | virtual bool idaapi prev(void * ud) override; 39 | virtual bool idaapi next(void * ud) override; 40 | virtual bool idaapi beginning(void * ud) const override; 41 | virtual bool idaapi ending(void * ud) const override; 42 | virtual int idaapi generate(qstrvec_t * out, int * out_deflnnum, color_t * out_pfx_color, bgcolor_t * out_bgcolor, void * ud, int maxsize) const override; 43 | virtual void idaapi serialize(bytevec_t * out) const override; 44 | virtual bool idaapi deserialize(const uchar ** pptr, const uchar * end) override; 45 | virtual int idaapi id() const override; 46 | virtual const char *idaapi name() const override; 47 | virtual ea_t idaapi toea() const; 48 | 49 | ReconstructableType *getReType(); 50 | bool isDerived(); 51 | bool isOwnMember(); 52 | 53 | }; 54 | -------------------------------------------------------------------------------- /src/cmake/FindIdaSdk.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2011-2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | # use this file except in compliance with the License. You may obtain a copy of 5 | # the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations under 13 | # the License. 14 | 15 | # FindIdaSdk 16 | # ---------- 17 | # 18 | # Locates and configures the IDA Pro SDK. Supports version 7.0 or higher. 19 | # 20 | # Use this module by invoking find_package with the form: 21 | # 22 | # find_package(IdaSdk [REQUIRED] # Fail with an error if IDA SDK is not found ) 23 | # 24 | # Defines the following variables: 25 | # 26 | # IdaSdk_INCLUDE_DIRS - Include directories for the IDA Pro SDK. IdaSdk_PLATFORM 27 | # - IDA SDK platform, one of __LINUX__, __NT__ or __MAC__. 28 | # 29 | # This module reads hints about search locations from variables: 30 | # 31 | # IdaSdk_ROOT_DIR - Preferred installation prefix 32 | # 33 | # Example (this assumes Windows): 34 | # 35 | # find_package(IdaSdk REQUIRED) 36 | # 37 | # # Builds targets plugin.dll and plugin64.dll add_ida_plugin(plugin 38 | # myplugin.cc) # Builds target plugin64.dll add_ida_plugin(plugin NOEA32 39 | # myplugin.cc) # Builds target plugin.dll add_ida_plugin(plugin NOEA64 40 | # myplugin.cc) 41 | # 42 | # Builds targets ldr.dll and ldr64.dll add_ida_loader(ldr myloader.cc) 43 | # 44 | # For platform-agnostic build files, the variables _so, and _so64 are available 45 | # (and map to .dll, .so, .dylib as necessary): 46 | # 47 | # add_ida_plugin(plugin myplugin.cc) target_link_libraries(plugin${_so} ssl) 48 | # target_link_libraries(plugin${_so64} ssl) 49 | # 50 | # To avoid the duplication above, these functions, which mimic the built-in 51 | # ones, are also defined: 52 | # 53 | # add_ida_library( NOEA64|NOEA64 ...) <=> add_libary() 54 | # ida_target_link_libraries(...) <=> target_link_libraries() 55 | # ida_target_include_directories(...) <=> target_include_directories() 56 | # set_ida_target_properties(...) <=> set_target_properties() 57 | # ida_install(...) <=> install() 58 | 59 | include(CMakeParseArguments) 60 | include(FindPackageHandleStandardArgs) 61 | 62 | find_path( 63 | IdaSdk_DIR 64 | NAMES include/pro.h 65 | HINTS ${IdaSdk_ROOT_DIR} ENV IDASDK_ROOT 66 | PATHS ${CMAKE_CURRENT_LIST_DIR}/../third_party/idasdk 67 | PATH_SUFFIXES idasdk 68 | DOC "Location of the IDA SDK" 69 | NO_DEFAULT_PATH) 70 | set(IdaSdk_INCLUDE_DIRS ${IdaSdk_DIR}/include) 71 | 72 | find_package_handle_standard_args( 73 | IdaSdk 74 | FOUND_VAR IdaSdk_FOUND 75 | REQUIRED_VARS IdaSdk_DIR IdaSdk_INCLUDE_DIRS 76 | FAIL_MESSAGE "IDA SDK not found, try setting IdaSdk_ROOT_DIR") 77 | 78 | # Define some platform specific variables for later use. 79 | set(_so ${CMAKE_SHARED_LIBRARY_SUFFIX}) 80 | set(_so64 64${CMAKE_SHARED_LIBRARY_SUFFIX}) # An additional "64" 81 | # _plx, _plx64, _llx, _llx64 are kept to stay compatible with older 82 | # CMakeLists.txt files. 83 | set(_plx ${CMAKE_SHARED_LIBRARY_SUFFIX}) 84 | set(_plx64 64${CMAKE_SHARED_LIBRARY_SUFFIX}) # An additional "64" 85 | set(_llx ${CMAKE_SHARED_LIBRARY_SUFFIX}) 86 | set(_llx64 64${CMAKE_SHARED_LIBRARY_SUFFIX}) # An additional "64" 87 | if(APPLE) 88 | set(IdaSdk_PLATFORM __MAC__) 89 | elseif(UNIX) 90 | set(IdaSdk_PLATFORM __LINUX__) 91 | elseif(WIN32) 92 | set(IdaSdk_PLATFORM __NT__) 93 | else() 94 | message(FATAL_ERROR "Unsupported system type: ${CMAKE_SYSTEM_NAME}") 95 | endif() 96 | 97 | function(_ida_common_target_settings t ea64) 98 | if(ea64) # Support for 64-bit addresses. 99 | target_compile_definitions(${t} PUBLIC __EA64__) 100 | endif() 101 | # Add the necessary __IDP__ define and allow to use "dangerous" and standard 102 | # file functions. 103 | target_compile_definitions( 104 | ${t} PUBLIC ${IdaSdk_PLATFORM} __X64__ __IDP__ USE_DANGEROUS_FUNCTIONS 105 | USE_STANDARD_FILE_FUNCTIONS) 106 | target_include_directories(${t} PUBLIC ${IdaSdk_INCLUDE_DIRS}) 107 | endfunction() 108 | 109 | function(_ida_win_link_library) 110 | if(ea64) 111 | set(target_bits 64) 112 | else() 113 | set(target_bits 32) 114 | endif() 115 | 116 | if(EXISTS ${IdaSdk_DIR}/lib/x64_win_vc_${target_bits}_pro) 117 | set(ida_lib_dir ${IdaSdk_DIR}/lib/x64_win_vc_${target_bits}_pro) 118 | elseif(EXISTS ${IdaSdk_DIR}/lib/x64_win_vc_${target_bits}) 119 | set(ida_lib_dir ${IdaSdk_DIR}/lib/x64_win_vc_${target_bits}) 120 | else() 121 | message(FATAL_ERROR "IDA SDK lib directory not found") 122 | endif() 123 | 124 | target_link_libraries(${t} ${ida_lib_dir}/ida.lib) 125 | endfunction() 126 | 127 | function(_ida_plugin name ea64 link_script) # ARGN contains sources 128 | if(ea64) 129 | set(t ${name}${_so64}) 130 | else() 131 | set(t ${name}${_so}) 132 | endif() 133 | 134 | # Define a module with the specified sources. 135 | add_library(${t} MODULE ${ARGN}) 136 | _ida_common_target_settings(${t} ${ea64}) 137 | 138 | set_target_properties(${t} PROPERTIES PREFIX "" SUFFIX "") 139 | if(UNIX) 140 | target_compile_options(${t} PUBLIC ${_ida_compile_options}) 141 | if(APPLE) 142 | target_link_libraries(${t} ${_ida_compile_options} -Wl,-flat_namespace 143 | -Wl,-undefined,warning -Wl,-exported_symbol,_PLUGIN) 144 | else() 145 | # Always use the linker script needed for IDA. 146 | target_link_libraries(${t} ${_ida_compile_options} -Wl,--version-script 147 | ${IdaSdk_DIR}/${link_script}) 148 | endif() 149 | 150 | # For qrefcnt_obj_t in ida.hpp 151 | # TODO(cblichmann): This belongs in an interface library instead. 152 | target_compile_options(${t} PUBLIC -Wno-non-virtual-dtor -Wno-varargs) 153 | elseif(WIN32) 154 | _ida_win_link_library() 155 | endif() 156 | endfunction() 157 | 158 | function(_ida_loader name ea64 link_script) 159 | if(ea64) 160 | set(t ${name}${_so64}) 161 | else() 162 | set(t ${name}${_so}) 163 | endif() 164 | 165 | # Define a module with the specified sources. 166 | add_library(${t} MODULE ${ARGN}) 167 | _ida_common_target_settings(${t} ${ea64}) 168 | 169 | set_target_properties(${t} PROPERTIES PREFIX "" SUFFIX "") 170 | if(UNIX) 171 | target_compile_options(${t} PUBLIC ${_ida_compile_options}) 172 | if(APPLE) 173 | target_link_libraries(${t} ${_ida_compile_options} -Wl,-flat_namespace 174 | -Wl,-undefined,warning -Wl,-exported_symbol,_LDSC) 175 | else() 176 | # Always use the linker script needed for IDA. 177 | target_link_libraries(${t} ${_ida_compile_options} -Wl,--version-script 178 | ${IdaSdk_DIR}/${link_script}) 179 | endif() 180 | 181 | # For qrefcnt_obj_t in ida.hpp 182 | # TODO(cblichmann): This belongs in an interface library instead. 183 | target_compile_options(${t} PUBLIC -Wno-non-virtual-dtor -Wno-varargs) 184 | elseif(WIN32) 185 | _ida_win_link_library() 186 | target_link_options(${t} PUBLIC "/EXPORT:LDSC") 187 | endif() 188 | endfunction() 189 | 190 | macro(_ida_check_bitness) 191 | if(opt_NOEA32 AND opt_NOEA64) 192 | message(FATAL_ERROR "NOEA32 and NOEA64 cannot be used at the same time") 193 | endif() 194 | endmacro() 195 | 196 | function(_ida_library name ea64) 197 | if(ea64) 198 | set(t ${name}_ea64) 199 | else() 200 | set(t ${name}_ea32) 201 | endif() 202 | 203 | # Define the actual library. 204 | add_library(${t} ${ARGN}) 205 | _ida_common_target_settings(${t} ${ea64}) 206 | endfunction() 207 | 208 | function(add_ida_library name) 209 | cmake_parse_arguments(PARSE_ARGV 1 opt "NOEA32;NOEA64" "" "") 210 | _ida_check_bitness(opt_NOEA32 opt_NOEA64) 211 | 212 | if(NOT DEFINED (opt_NOEA32)) 213 | _ida_library(${name} FALSE ${opt_UNPARSED_ARGUMENTS}) 214 | endif() 215 | if(NOT DEFINED (opt_NOEA64)) 216 | _ida_library(${name} TRUE ${opt_UNPARSED_ARGUMENTS}) 217 | endif() 218 | endfunction() 219 | 220 | function(add_ida_plugin name) 221 | cmake_parse_arguments(PARSE_ARGV 1 opt "NOEA32;NOEA64" "" "") 222 | _ida_check_bitness(opt_NOEA32 opt_NOEA64) 223 | 224 | if(NOT opt_NOEA32) 225 | _ida_plugin(${name} FALSE plugins/exports.def ${opt_UNPARSED_ARGUMENTS}) 226 | endif() 227 | if(NOT opt_NOEA64) 228 | _ida_plugin(${name} TRUE plugins/exports.def ${opt_UNPARSED_ARGUMENTS}) 229 | endif() 230 | endfunction() 231 | 232 | function(add_ida_loader name) 233 | cmake_parse_arguments(PARSE_ARGV 1 opt "NOEA32;NOEA64" "" "") 234 | _ida_check_bitness(opt_NOEA32 opt_NOEA64) 235 | 236 | if(NOT opt_NOEA32) 237 | _ida_loader(${name} FALSE ldr/exports.def ${opt_UNPARSED_ARGUMENTS}) 238 | endif() 239 | if(NOT opt_NOEA64) 240 | _ida_loader(${name} TRUE ldr/exports.def ${opt_UNPARSED_ARGUMENTS}) 241 | endif() 242 | endfunction() 243 | 244 | function(ida_target_link_libraries name) 245 | foreach(item IN LISTS ARGN) 246 | if(TARGET ${item}_ea32 OR TARGET ${item}_ea64) 247 | if(TARGET ${item}_ea32) 248 | list(APPEND args32 ${item}_ea32) 249 | endif() 250 | if(TARGET ${item}_ea64) 251 | list(APPEND args64 ${item}_ea64) 252 | endif() 253 | else() 254 | list(APPEND args ${item}) 255 | endif() 256 | endforeach() 257 | foreach(target ${name}${_so} ${name}_ea32) 258 | if(TARGET ${target}) 259 | target_link_libraries(${target} ${args32} ${args}) 260 | set(added TRUE) 261 | endif() 262 | endforeach() 263 | foreach(target ${name}${_so64} ${name}_ea64) 264 | if(TARGET ${target}) 265 | target_link_libraries(${target} ${args64} ${args}) 266 | set(added TRUE) 267 | endif() 268 | endforeach() 269 | if(NOT added) 270 | message(FATAL_ERROR "No such target: ${name}") 271 | endif() 272 | endfunction() 273 | 274 | function(ida_target_include_directories name) 275 | foreach(target ${name}${_so} ${name}${_so64} ${name}_ea32 ${name}_ea64) 276 | if(TARGET ${target}) 277 | target_include_directories(${target} ${ARGN}) 278 | set(added TRUE) 279 | endif() 280 | endforeach() 281 | if(NOT added) 282 | message(FATAL_ERROR "No such target: ${name}") 283 | endif() 284 | endfunction() 285 | 286 | function(set_ida_target_properties name) 287 | foreach(target ${name}${_so} ${name}${_so64} ${name}_ea32 ${name}_ea64) 288 | if(TARGET ${target}) 289 | set_target_properties(${target} ${ARGN}) 290 | set(added TRUE) 291 | endif() 292 | endforeach() 293 | if(NOT added) 294 | message(FATAL_ERROR "No such target: ${name}") 295 | endif() 296 | endfunction() 297 | 298 | function(ida_install) 299 | foreach(item IN LISTS ARGN) 300 | if(TARGET ${item}${_so} OR TARGET ${item}${_so64}) 301 | if(TARGET ${item}${_so}) 302 | list(APPEND args ${item}${_so}) 303 | endif() 304 | if(TARGET ${item}${_so64}) 305 | list(APPEND args ${item}${_so64}) 306 | endif() 307 | else() 308 | list(APPEND args ${item}) 309 | endif() 310 | endforeach() 311 | install(${args}) 312 | endfunction() 313 | --------------------------------------------------------------------------------