├── .gitignore ├── CS.py ├── KC.py ├── KM.py ├── KM_kernel.py ├── LICENSE ├── README.md ├── dwarf4_fix.py ├── extra_refs.py ├── fix_extMethod.py ├── fix_methodForIndex.py ├── jsymbols.py ├── load_sigatnures.py ├── load_structs.py ├── namespace.py ├── propagate.py ├── screenshots ├── image1.png ├── image10.png ├── image11.png ├── image12.png ├── image2.png ├── image3.png ├── image4.png ├── image5.png ├── image6.png ├── image7.png ├── image8.png └── image9.png ├── signatures ├── IOBufferMemoryDescriptor.h ├── IOCommandGate.h ├── IODataQueue.h ├── IOEventSource.h ├── IOMemoryDescriptor.h ├── IOMemoryMap.h ├── IORegistryEntry.h ├── IOService.h ├── IOSharedDataQueue.h ├── IOUserClient.h ├── IOWorkLoop.h ├── OSArray.h ├── OSCollection.h ├── OSCollectionIterator.h ├── OSData.h ├── OSDictionary.h ├── OSMetaClassBase.h ├── OSNumber.h ├── OSObject.h ├── OSSerialize.h ├── OSSet.h ├── OSString.h ├── OSSymbol.h └── kernel.h └── utils ├── __init__.py ├── custom_kc.py ├── helpers.py ├── iometa.py ├── ios_kc.py ├── kext.py ├── methods.py └── references.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | .DS_Store 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | pip-wheel-metadata/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | -------------------------------------------------------------------------------- /CS.py: -------------------------------------------------------------------------------- 1 | # Create a custom class 2 | #@category iOS.kernel 3 | 4 | from utils.helpers import * 5 | from utils.custom_kc import * 6 | 7 | if __name__ == "__main__": 8 | default = "/tmp/kernel.txt" 9 | ff = askString("iometa symbol file","Symbol file: ",default) 10 | iom = ParseIOMeta(ff) 11 | Obj = iom.getObjects() 12 | 13 | kc = Custom(Obj) 14 | 15 | #kc.process_class(["IOSurface"]) 16 | 17 | kc.process_all_classes() 18 | kc.explore_pac() 19 | -------------------------------------------------------------------------------- /KC.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #@category iOS.kernel 3 | #@toolbar logos/kc.png 4 | #@keybinding Meta Shift K 5 | 6 | from utils.helpers import * 7 | from utils.ios_kc import * 8 | from utils.iometa import ParseIOMeta 9 | 10 | def fix_map(): 11 | prog = currentProgram 12 | memory = prog.getMemory() 13 | blocks = memory.getBlocks() 14 | for b in blocks: 15 | if "__got" in b.getName(): 16 | b.setWrite(False) 17 | 18 | def loadAll(): 19 | default = "/tmp/kernel.txt" 20 | ff = askString("iometa symbol file","Symbol file: ",default) 21 | 22 | iom = ParseIOMeta(ff) 23 | Obj = iom.getObjects() 24 | kc = kernelCache(Obj) 25 | 26 | #kc.clear_class_structures() 27 | 28 | kc.process_all_classes() 29 | 30 | #kc.process_class("IOUserClient") 31 | 32 | #kc.process_classes_for_bundle("com.apple.iokit.IOSurface") 33 | 34 | #kc.explore_pac() 35 | 36 | if __name__ == "__main__": 37 | #DeclareDataTypes() 38 | prepare() 39 | #fix_map() 40 | loadAll() 41 | -------------------------------------------------------------------------------- /KM.py: -------------------------------------------------------------------------------- 1 | # symbolication macOS kernel + kexts 2 | #@category iOS.kernel 3 | #@toolbar logos/km.png 4 | #@keybinding Meta Shift M 5 | 6 | from utils.helpers import * 7 | from utils.kext import * 8 | 9 | def main(): 10 | default = "/tmp/kernel.txt" 11 | ff = askString("iometa symbol file","Symbol file: ",default) 12 | iom = ParseIOMeta(ff) 13 | Obj = iom.getObjects() 14 | #del Obj['OSKext'] 15 | 16 | kc = Kext(Obj,shared_p="macOS_12.1") 17 | kc.depac() 18 | kc.process_kernel_kext() 19 | 20 | kc.explore_pac() 21 | 22 | if __name__ == "__main__": 23 | print("[+] Symbolicating Kext") 24 | main() 25 | -------------------------------------------------------------------------------- /KM_kernel.py: -------------------------------------------------------------------------------- 1 | # symbolication macOS kernel + kexts 2 | #@category iOS.kernel 3 | #@toolbar logos/km.png 4 | #@keybinding Meta Shift M 5 | 6 | from utils.helpers import * 7 | from utils.kext import * 8 | 9 | def main(): 10 | default = "/tmp/kernel.txt" 11 | ff = askString("iometa symbol file","Symbol file: ",default) 12 | iom = ParseIOMeta(ff) 13 | Obj = iom.getObjects() 14 | 15 | kc = Kext(Obj,shared_p="macOS_12.1") 16 | 17 | kc.process_kernel_kext() 18 | 19 | if __name__ == "__main__": 20 | print("Parsing 1 ... ") 21 | main() 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ghidra_kernelcache: a Ghidra iOS kernelcache framework for reverse engineering 2 | 3 | This framework is the end product of my experience in Kernelcache reverse engineering , I usually look for vulnerabilities by manually auditing the kernel and its extensions and have automated most of the things that I really wanted to see in Ghidra to speed up the process of reversing, and this has proven to be effective and saves a lot of time. 4 | The framework works on iOS 12/13/14/15 and on macOS 11/12 (both kernelcache and single KEXT) and has been made to the public with the intention to help people to start researching on iOS kernel without the struggle of preparing their own environment. 5 | As I believe, this framework (including the toolset it provides and with some basic knowledge of IOKit) is sufficient to start hacking into the Kernelcache. 6 | 7 | The framework is entirely written in Python, and can be extended to build other tools, it provides some basic APIs which you can use in almost any project and save time from reading the verbose manual, you're welcome to read the core functionalities in **[utils/](https://github.com/0x36/ghidra_kernelcache/tree/master/utils)** directory. 8 | 9 | Ghidra is good when it comes to analyzing Kernelcaches, but like other RE tools, it requires some manual work, `ghidra_kernelcache` provides a good entry point to fix things up at the start and even while doing reverse engineering, hence providing a good-looking decompiler output. 10 | 11 | There is a similar project made by [@_bazad](https://twitter.com/_bazad) in IDAPro called [ida_kernelcache](https://github.com/bazad/ida_kernelcache) which provides a good entry point for researchers wanting to work with the kernel image in IDA, my framework looks a bit similar to Brandon's work, and goes beyond by providing much more features to make the process of working with the kernelcache less painful. 12 | 13 | ## Features : 14 | - *OS kernelcache symbolication. 15 | - C++ class hierarchy reconstruction and virtual tables. 16 | - Virtual method call references. 17 | - Auto fixing external method's dispatch table for both `::externalMethod()` and `::getTargetAndMethodForIndex()`. 18 | - Applying namespaces to class methods. 19 | - Symbol name and type propagation over a function arguments. 20 | - Applying function signatures for known kernel functions. 21 | - Import old structures and classes from old project to a new project. 22 | 23 | These features are made as a separated tools which can be executed either by key shortcuts or by clicking on their icons in the toolbar. 24 | 25 | ## Installation 26 | Clone the repository : 27 | 28 | ```sh 29 | git clone https://github.com/0x36/ghidra_kernelcache.git 30 | ``` 31 | 32 | **Important note**: The project has been tested on Ghidra 10.1_PUBLIC and 10.2_DEV and it is not backward compatible. 33 | 34 | Go to *`Windows → Script Manager`,* click on *`script Directory` ,* then add *`ghidra_kernelcache`* to the directory path list. 35 | Go to *`Windows → Script Manager`,* in *scripts* listing, go to *`iOS→kernel`* category and check the plugins seen there, they will appear in GHIDRA Toolbar . 36 | 37 | in [logos/](https://github.com/0x36/ghidra_kernelcache/tree/master/logos) directory, you can put you own logos for each tool. 38 | 39 | ## iOS kernelcache symbolication 40 | 41 | `ghidra_kernelcache` requires at the first stage [iometa](https://github.com/Siguza/iometa/) (made by [@s1guza](https://twitter.com/s1guza)), a powerful tool providing C++ class information in the kernel binary, the great thing is that it works as a standalone binary, so the output can be imported to your favorite RE framework by just parsing it. My framework takes iometa's output and parses it to symbolicate and fix virtual tables. 42 | 43 | ### Usage 44 | After decompressing the kernel, run the following commands : 45 | 46 | ```sh 47 | $ iometa -n -A /tmp/kernel A10-legacy.txt > /tmp/kernel.txt 48 | # if you want also to symbolicate using jtool2 49 | $ jtool2 --analyze /tmp/kernel 50 | 51 | ``` 52 | 53 | Load the kernelcache in Ghidra, ***DO NOT USE BATCH import*** , load it as Mach-O image. 54 | After the Kernelcache being loaded and auto-analyzed, click on the icon shown in the toolbar or just press **Meta-Shift-K**, then put the full path of iometa output which is `/tmp/kernel.txt` in our case. 55 | 56 | if you want to use `jtool2` symbols, you can use `jsymbol.py` located `iOS→kernel` category as well. 57 | 58 | ### iOS kernelcache API 59 | Full API examples are in [`ghidra_kernelcache/kc.py`](https://github.com/0x36/ghidra_kernelcache/blob/master/KC.py) 60 | 61 | → Here are some examples of manipulating class objects : 62 | ```py 63 | from utils.helpers import * 64 | from utils.class import * 65 | from utils.iometa import ParseIOMeta 66 | 67 | ff = "/Users/mg/ghidra_ios/kernel.txt" 68 | iom = ParseIOMeta(ff) 69 | Obj = iom.getObjects() 70 | kc = kernelCache(Obj) 71 | 72 | 73 | # symbolicate the kernel 74 | kc.process_all_classes() 75 | 76 | # symbolicate the classes under com.apple.iokit.IOSurface bundle 77 | kc.process_classes_for_bundle("com.apple.iokit.IOSurface") 78 | 79 | # symbolicate the classes under __kernel__ bundle 80 | kc.process_classes_for_bundle("__kernel__") 81 | 82 | # Process one class (including its parents) 83 | kc.process_class("IOGraphicsAccelerator2") 84 | 85 | # Clears the content of the class structures (vtables are excluded) 86 | kc.clear_class_structures() 87 | 88 | # Overwrite the old vtable structure definition and resymbolicate it again 89 | kc.update_classes_vtable() 90 | 91 | # Reconstructing function call trees by enumerating all pac references and find their corresponding virtual method call 92 | kc.explore_pac() 93 | ``` 94 | 95 | As you can see, you can fully or partially symbolicate the kernelcache, if partial symbolication was chosen, `ghidra_kernelcache` will automatically construct all class dependencies before proceeding. 96 | If you run the script against the whole kernelcache (full symbolication), `ghidra_kernelcache` will take several minutes to analyze the kernel image. 97 | 98 | One finished, Ghidra will provide the following : 99 | 100 | → A new category has been added in Bookmark Filter called "iOS": 101 | 102 | image1 103 | 104 | 105 | → IOKit class virtual tables are added to 'iOS' Bookmark for better and faster virtual table lookup, you can just look for a kext or a class by providing letters, words or kext bundle in the search bar. 106 | 107 | image2 108 | 109 | 110 | → Fixing the virtual table : disassembles/compiles unknown code, fixes namespaces, re-symbolicates the class methods and applies function definition to each method: 111 | 112 | image3 113 | 114 | → Creation of class namespaces and put each method to its own corresponding namespace: 115 | 116 | image4 117 | 118 | → Creating class structure with the respect of class hierarchy : 119 | 120 | image5 121 | 122 | → Creating class vtables, and each method has its own method definition for better decompilation output: 123 | 124 | image6 125 | 126 | Full implementation can be found in [`utils/class.py.`](https://github.com/0x36/ghidra_kernelcache/blob/master/utils/class.py) 127 | 128 | Here are some screenshots of before/after symbolicating using `ghidra_kernelcache` : 129 | 130 | image7 131 | 132 | image8 133 | 134 | 135 | 136 | 137 | ## macOS Kext symbolication 138 | --- 139 | `ghidra_kernelcache` macOS support is for both kernelcache and single KEXT symbolication for ARM64e and x86_64 architectures. 140 | **IMPORTANT:** At the time of writing Ghidra is unable to parse the whole macOS kernelcache, but it's possible to load it in IDA for initial analysis then import the database (idb to xml) to Ghidra later, but this is out of scope. If you manage to do so, `ghidra_kernelcache` will take care of the rest. 141 | 142 | There are some few steps which have to be taken before symbolicating any macOS Kernel Extension, as `ghidra_kernelcache`'s main aim is to reconstruct the class hierarchy and to manage all class structures into a single database, a kernel extension does not fulfill those requirements, which means that the symbolication of a single KEXT does require a symbolication of the kernel and perhaps other Kernel Extensions that depends on, hence some extra work needs to be done here. 143 | `ghidra_kernelcache` now provides a powerful way to symbolicate Kernel Extensions including the kernel by managing and sharing class structures and virtual method definitions via Ghidra's powerful *DataType Project Archive* 144 | 145 | ### Steps to symbolicate a Kernel Extension 146 | - Create a new folder in your Ghidra project, then load ` /System/Library/Kernels/kernel.release.XXXXX` into that folder and let Ghidra analyzes it. 147 | - Create a new *Project Archive* : Go to `DataType Provider` → Click on the arrow in the top right of the window → `New Project Archive` → Place it inside the newly created Folder → Name it to something (i.e macOS_12.1). 148 | - Now symbolicate the kernel using `ghidra_kernelcache`, the process is quite similar to iOS *kernelcache* symbolication. 149 | 150 | ```bash 151 | $ iometa -n -A /System/Library/Kernels/kernel.release.t8101 > /tmp/kernel.txt 152 | ``` 153 | - In python console, or you can find the full script implementation in `KM.py` script : 154 | ```py 155 | >>> from utils.helpers import * 156 | >>> from utils.kext import * 157 | >>> iom = ParseIOMeta("/tmp/kernel.txt") 158 | >>> Obj = iom.getObjects() 159 | >>> kc = Kext(Obj,shared_p="macOS_12.1") 160 | >>> kc.process_kernel_kext() 161 | 162 | ``` 163 | - Once finished, a database association has been created between kernel's archive and `macOS_12.1` archive. Now, right click on the `kernel.release.t8001` → `Commit DataTypes To` → `macOS_12.1`. 164 | - Then `Right Click` →`Select All` → `Commit`. 165 | - Save the project archive : `Right click` → `Save Archive`. 166 | We've just created a project archive which can be shared across all Kernel Extensions. 167 | Let's take an example of `IOSurface` Kext for Apple Silicon : 168 | ```bash 169 | $ lipo /System/Library/Extensions/IOSurface.kext/Contents/MacOS/IOSurface -thin arm64e -output /tmp/iosurface.arm64e 170 | $ iometa -n -A /tmp/iosurface.arm64e > /tmp/iosurface.txt 171 | ``` 172 | 173 | - Load the Kext into the same folder path where the kernel database and the project archive are located and let Ghidra finishes the analysis 174 | - Load the project archive we've created earlier `macOS_12.1` : go to `Data Type Manager` → `Open Project Archive` , then select the `macOS_12.1` 175 | - Run the following methods, full script can be found in `KM.py`: 176 | ```python 177 | from utils.helpers import * 178 | from utils.kext import * 179 | 180 | kc = Kext(Obj,shared_p="macOS_12.1") 181 | 182 | # This method fixes LC_DYLD_CHAINED_FIXUPS for M1 Kernel extension 183 | kc.depac() 184 | 185 | # This method reconstructs class hierarchy and builds virtual table for each class 186 | kc.process_kernel_kext() 187 | 188 | ``` 189 | 190 | **Important Note** : sometimes `kc.process_kernel_kext()` fails because Ghidra was not able to demangle some C++ symbols. To fix this, go to the script manager and run `DemangleAllScript.java` script then restart `kc.process_kernel_kext()` again. 191 | 192 | ### Custom classes 193 | There are some cases where some C++ classes where `ghidra_kernelcache` and `iometa` cannot symbolicate, so a new feature has been added to handle this. 194 | `Custom()` class reconstruction iterates through all the `::vtable` symbols and checks wether the class is already defined or not, if not, it automatically creates a class structure, function definitions for each identified class method, a namespace and a virtual table for each class. 195 | 196 | Custom class creation is supported on macOS only at the moment. 197 | 198 | ```bash 199 | $ iometa -n -A /System/Library/Kernels/kernel.release.t8101 > /tmp/kernel.txt 200 | $ iometa -n -A >> /tmp/kernel.txt 201 | ``` 202 | 203 | ```py 204 | 205 | from utils.helpers import * 206 | from utils.custom_kc import * 207 | 208 | if __name__ == "__main__": 209 | default = "/tmp/kernel.txt" 210 | ff = askString("iometa symbol file","Symbol file: ",default) 211 | iom = ParseIOMeta(ff) 212 | Obj = iom.getObjects() 213 | 214 | kc = Custom(Obj) 215 | 216 | kc.process_all_classes() 217 | kc.explore_pac() 218 | 219 | 220 | ``` 221 | 222 | ## Miscellaneous scripts 223 | --- 224 | ### Importing KDK's Dwarf4 225 | Ghidra somehow fails to load the corresponding `.dsym` directory, I made a small script to fix this. It can be found [here](https://github.com/0x36/ghidra_kernelcache/blob/master/dwarf4_fix.py). 226 | **Usage** : load the kernel from your KDK path, let Ghidra finishes the analysis, then run `dwarf_fix.py`, it will load the symbols and the process may take several minutes. 227 | image12 228 | 229 | ### Resolving virtual method calls references 230 | `ghidra_kernelcache` provides two ways to resolve virtual calls by `kernelCache.explore_pac` or `fix_extra_refs` 231 | 232 | **kernelCache.explore_pac()** 233 | If you're working on arm64e binary, `ghidra_kernelcache` can recognize virtual method calls by looking for the `Pointer Authentication Code` value. The process is straightforward and unlike `fix_extra_refs()`, `kernelCache.explore_pac` does not rely on the `Pcode` or `varnode` identification, it just iterates through all the instructions in the program, searches for `MOVK` instructions, fetches the second operand and looks for its corresponding value in the database. 234 | Usage : 235 | Create a *KernelCache* instance via **kernelCache** , **Kext** or **Custom**, then call `explore_pac()` method. 236 | ```py 237 | from utils.helpers import * 238 | from utils.kext import * 239 | 240 | if __name__ == "__main__": 241 | default = "/tmp/kernel.txt" 242 | ff = askString("iometa symbol file","Symbol file: ",default) 243 | iom = ParseIOMeta(ff) 244 | Obj = iom.getObjects() 245 | 246 | kc = Kext(Obj) 247 | 248 | kc.explore_pac() 249 | 250 | ``` 251 | 252 | **fix_extra_refs()** 253 | This function is based on a basic data flow analysis to find all virtual call methods and to resolve their implementations automatically, it works across all architectures and has the ability to recognize the source data type from the decompiler output and resolve all the virtual call references inside the function, so the user is able to jump forward/backward directly to/from the implementation without manually looking for it. 254 | The most useful feature provided by `fix_extra_refs` is that it keeps the references synchronized on each execution. For example, you changed a variable data type to a class data type, `fix_extra_refs` will automatically recognize the change, and will recursively go through all call sites to resolve their references, and it will stop only when the call site queue became empty. 255 | 256 | There are some other features provided by `fix_extra_refs` such as: 257 | - It auto-detects `_ptmf2ptf()` calls and resolves their call method for both offsets and full function address 258 | - It identifies the namespace of an unresolved function name (functions which start with FUN_ ), and resolve it by putting the target function into its own namespace (e.g adding **this** pointer of the corresponding class). 259 | 260 | You can find the implementation in **utils/references.py,** `fix_extra_refs` parses the [pcode](https://ghidra.re/ghidra_docs/api/ghidra/program/model/pcode/package-summary.html) operations and looks for `CALLIND` and `CALL` opcodes, then gets all involved [varnodes](https://ghidra.re/ghidra_docs/api/ghidra/program/model/pcode/Varnode.html) in the operation, once a Varnode definition was identified, it retrieves its [HighVariable](https://ghidra.re/ghidra_docs/api/ghidra/program/model/pcode/HighVariable.html) to identify the class object type, if the type is unknown (i.e does not appear to be a class structure) it just ignores it, otherwise it will take the class name, looks up its virtual call table, using the offset provided by the Varnode, it can fetch the right virtual method call and puts a reference on the call instruction. 261 | 262 | ```py 263 | fix_extra_refs(toAddr(address)) 264 | ``` 265 | Here is an output example of using `fix_extra_refs` : 266 | 267 | image9 268 | 269 | Note that it has successfully resolved **IOService::isOpen()**, **OSArray:getNextIndexOfObject()** and **IOStream::removeBuffer()** virtual calls without any manual modification. 270 | 271 | Next, `fix_extra_refs` will decompile **IOStream::removeBuffer()**, gets all HighVariables of this method, then it resolves their references like the previous method ... and so on. 272 | image10 273 | 274 | ### Auto fixing external method tables 275 | 276 | I believe that every researcher has some script to deal with this part, as it is the main attack surface of IOKit, doing it manually is a burden, and it must be automated in a way the researcher wants to dig into multiple external method tables. 277 | There are two scripts provided by the`ghidra_kernelcache` : **fix_methodForIndex.py** and **fix_extMethod.py.** You can enable them like the other scripts as shown above. 278 | 279 | ***Usage***: Put the cursor at the start of the external dispatch table, run the script: provide the target, and the number of selectors. 280 | Example for `IOStreamUserClient::getTargetAndMethodForIndex()` : 281 | 282 | image11 283 | 284 | 285 | ### namespace.py : fix method namespaces … 286 | This is a useful script to populate the class type to all encountered methods, and it's a dependency for `extra_refs.py` script in order to recursively explore the callee functions and to resolve their references. 287 | 288 | ***Usage***: Put the cursor in the decompiler output of the wanted function, run the script from the toolbar or press **Meta-Shift-N** . 289 | 290 | ### Symbol name and type propagation 291 | `ghidra_kernelcache` provides type propagation support for basic Pcode operations, but it will likely fails for some variables that using complex casting . 292 | If someone wants to help, or wants to start working with low level stuff in Ghidra, this is the opportunity to do so. 293 | Implementation can be found in [ghidra_kernelcache/propagate.py](https://github.com/0x36/ghidra_kernelcache/blob/master/propagate.py) 294 | 295 | ### Loading function signatures 296 | 297 | Parsing C++ header files in Ghidra is not possible, and having kernel function signatures in kernelcache can improve many things in the decompiler output. 298 | For example, let's say we have added `virtual IOMemoryMap * map(IOOptionBits options = 0 );`, Ghidra will automatically re-type the return value into `IOMemoryMap` pointer automatically for both function definition and function signatures. 299 | You can add any C++ symbol into **signatures/** directory with the respect of the syntax and you can find defined function signatures in this directory. 300 | 301 | ```c++ 302 | // Defining an instance class method 303 | IOMemoryDescriptor * withPersistentMemoryDescriptor(IOMemoryDescriptor *originalMD); 304 | 305 | // Defining a virtual method, it must start with "virtual" keyword 306 | virtual IOMemoryMap * createMappingInTask(task_t intoTask, mach_vm_address_t atAddress, IOOptionBits options, mach_vm_size_t offset = 0, mach_vm_size_t length = 0); 307 | 308 | // Defining a structure 309 | struct task_t; 310 | 311 | // typedef'ing a type 312 | typedef typedef uint IOOptionBits; 313 | 314 | // Lines begining with '//' are ignored 315 | 316 | ``` 317 | 318 | ***Usage***: After symbolicating the kernel, it is highly recommended to run the script `load_sigatnures.py` to load all available function signatures. As most of the previous tools, run this script by adding it in the toolbar or from the Plugin manager or just press **Meta-Shift-S** . 319 | 320 | ### Loading old structures: 321 | 322 | This script is straight-froward, it imports all structures, classes, typedefs, and function definitions and everything with `SourceType.USER_DEFINED` from an old project to a new one. 323 | 324 | ***Usage***: Open the old and the new Ghidra projects on the same tool, go to [`load_structs.py`](https://github.com/0x36/ghidra_kernelcache/blob/master/load_structs.py) script, put the old program name to **src_prog_string** variable, and the new one to **dst_prog_string** variable, then run the script. 325 | 326 | ## Contribute 327 | If you see the project interesting and want to contribute, just do a PR and I will review it, meanwhile, I would like to see some contribution in the following areas: 328 | * [ghidra_kernelcache/signatures/kernel.txt](https://github.com/0x36/ghidra_kernelcache/tree/master/signatures): keep importing XNU kernel functions, it is so simple just copy/paste the function definition. 329 | * [ghidra_kernelcache/propagate.py](https://github.com/0x36/ghidra_kernelcache/blob/master/propagate.py) : support un-handled opcodes for better symbol propagation. 330 | 331 | ## Credit 332 | I would like to thank [@s1guza](https://twitter.com/s1guza) for his awesome [iometa](https://github.com/Siguza/iometa.git) which ghidra_kernelcache depends on. 333 | -------------------------------------------------------------------------------- /dwarf4_fix.py: -------------------------------------------------------------------------------- 1 | #@category iOS.kernel 2 | 3 | from ghidra.program.model.listing import CodeUnit 4 | from ghidra.app.util.bin.format.dwarf4.next import DWARFImportOptions,DWARFProgram,DWARFParser 5 | from ghidra.program.model.data import BuiltInDataTypeManager 6 | from ghidra.app.util.bin.format.dwarf4.next.sectionprovider import DSymSectionProvider 7 | from java.io import File 8 | 9 | 10 | if __name__=='__main__': 11 | if (DWARFProgram.isDWARF(currentProgram) == False): 12 | popup("Unable to find DWARF information, aborting") 13 | exit(1) 14 | 15 | importOptions = DWARFImportOptions() 16 | importOptions.setPreloadAllDIEs(True) 17 | importOptions.setImportLimitDIECount(0x1000000); 18 | 19 | dwarfProg = DWARFProgram(currentProgram, importOptions, monitor) 20 | dtms = BuiltInDataTypeManager.getDataTypeManager() 21 | dp = DWARFParser(dwarfProg, dtms, monitor); 22 | importSummary = dp.parse() 23 | importSummary.logSummaryResults(); 24 | print("[+] We're done") 25 | -------------------------------------------------------------------------------- /extra_refs.py: -------------------------------------------------------------------------------- 1 | # Fix a method's vtable calls + reference making 2 | 3 | #@author simo 4 | #@category iOS.kernel 5 | #@keybinding R 6 | #@toolbar logos/refs.png 7 | #@description Resolve references for better CFG 8 | # -*- coding: utf-8 -*- 9 | 10 | """ 11 | script which does the following: 12 | - adds references to virtual method calls 13 | - Identifies methods belong to a specific namespace 14 | - Handles multi value vtable reference (multi-nodes) 15 | """ 16 | 17 | from utils.references import * 18 | 19 | if __name__ == "__main__": 20 | fix_extra_refs(currentAddress) 21 | -------------------------------------------------------------------------------- /fix_extMethod.py: -------------------------------------------------------------------------------- 1 | # Fix IOExternalMethodDispatch for externalMethod() 2 | #@author simo 3 | #@category iOS.kernel 4 | #@keybinding Meta Shift B 5 | #@menupath 6 | #@toolbar logos/ext.png 7 | #@description test 8 | 9 | # -*- coding: utf-8 -*- 10 | 11 | from utils.helpers import * 12 | from utils.methods import * 13 | import json 14 | 15 | logger = None 16 | 17 | def fix_extMethod(class_struct ,func): 18 | dtm = currentProgram.getDataTypeManager() 19 | IOArgs_dt = find_struct("IOExternalMethodArguments") 20 | assert(IOArgs_dt != None) 21 | 22 | 23 | this = ParameterImpl("this",PointerDataType(class_struct),currentProgram) 24 | reference = ParameterImpl("reference",PointerDataType(VoidDataType()),currentProgram) 25 | IOArgs = ParameterImpl("args",PointerDataType(IOArgs_dt),currentProgram) 26 | 27 | params = [this,reference,IOArgs] 28 | 29 | func.replaceParameters(FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, 30 | True, 31 | SourceType.USER_DEFINED, 32 | params) 33 | 34 | IOExternalMethodDispatch_size = 24 35 | 36 | external_methods = {} 37 | def fix_externalMethods(target,selectors,sMethods): 38 | 39 | logger.info("target=%s selectors=%d ,sMethod=%s" %(target,selectors, sMethods)) 40 | _sMethods = sMethods 41 | className = target 42 | symbolTable = currentProgram.getSymbolTable() 43 | listing = currentProgram.getListing() 44 | 45 | namespace = symbolTable.getNamespace(className,None) 46 | 47 | if namespace == None: 48 | popup("[-] %s class not found " %(className)) 49 | exit(-1) 50 | class_struct = find_struct(className) 51 | 52 | em_infos = {} 53 | for sel in range(selectors): 54 | #off = sel * 24 55 | function_off = int(sMethods,16) 56 | checkScalarInputCount_off = function_off + 8 57 | checkStructureInputSize_off = checkScalarInputCount_off + 4 58 | checkScalarOutputCount_off = checkStructureInputSize_off + 4 59 | checkStructureOutputSize_off = checkScalarOutputCount_off +4 60 | 61 | smAddr = toAddr(sMethods) 62 | 63 | function_ptr = toAddr(hex(function_off).replace("L","")) 64 | function_end = toAddr(hex(function_off+25).replace("L","")) 65 | 66 | scalarInput_addr = toAddr(hex(checkScalarInputCount_off).replace("L","")) 67 | structureInput_addr = toAddr(hex(checkStructureInputSize_off).replace("L","")) 68 | scalarOutput_addr = toAddr(hex(checkScalarOutputCount_off).replace("L","")) 69 | structureOutput_addr = toAddr(hex(checkStructureOutputSize_off).replace("L","")) 70 | 71 | listing.clearCodeUnits(function_ptr,function_end,False) 72 | 73 | func = makeFunction(function_ptr) 74 | func_addr = getDataAt(function_ptr).getValue() 75 | 76 | func = getFunctionAt(func_addr) 77 | if func != None: 78 | symName = "extMethod_%d" %(sel) 79 | fix_namespace(className,func,symName) 80 | fix_extMethod(class_struct,func) 81 | 82 | setEOLComment(function_ptr,"sel %d" %(sel)) 83 | makeUint(scalarInput_addr,"scalarInput") 84 | makeUint(structureInput_addr,"structureInput") 85 | makeUint(scalarOutput_addr,"scalarOutput") 86 | makeUint(structureOutput_addr,"structureInput") 87 | 88 | sMethods = hex(int(sMethods,16) + 24).replace("L","") 89 | 90 | scalarInputCnt = getDataAt(scalarInput_addr).getValue() 91 | structureInputCnt = getDataAt(structureInput_addr).getValue() 92 | scalarOutputCnt = getDataAt(scalarOutput_addr).getValue() 93 | structureOutputCnt = getDataAt(structureOutput_addr).getValue() 94 | 95 | if func == None: 96 | continue 97 | 98 | function_name = func.getName(False) 99 | call_info = { 100 | "selector" : sel, 101 | "scalarInputCnt" : scalarInputCnt.getValue(), 102 | "structInputCnt" : structureInputCnt.getValue(), 103 | "scalarOutputCnt" : scalarOutputCnt.getValue(), 104 | "structOutputCnt" : structureOutputCnt.getValue(), 105 | "async" : False, 106 | "address": func_addr.toString() 107 | } 108 | 109 | if function_name in em_infos: 110 | function_name = function_name + str(sel) 111 | em_infos[function_name] = call_info 112 | 113 | external_methods['externalMethods'] = em_infos # externalMethods 114 | external_methods['target'] = className # userclient 115 | external_methods['user_client_type'] = 0 # connection type (-1 means undefiend) 116 | external_methods['sMethods'] = _sMethods 117 | out_file = "/tmp/%s.json"%(className) 118 | with open(out_file, 'w') as json_file: 119 | json.dump(external_methods, json_file,indent=4, sort_keys=True) 120 | logger.info("%s file created" %(out_file)) 121 | 122 | if __name__ == "__main__": 123 | sMethods = currentAddress 124 | if sMethods == None : 125 | popup("Select a The first External Method address") 126 | exit(-1) 127 | 128 | logger = setup_logging("external_method") 129 | addr_str = sMethods.toString() 130 | target = askString("Namespace","Target name: ") # how to track the history of strings ? 131 | selectors = askInt("sMethod " + addr_str,"Selector count: ") 132 | 133 | fix_externalMethods(target,selectors,addr_str) 134 | -------------------------------------------------------------------------------- /fix_methodForIndex.py: -------------------------------------------------------------------------------- 1 | # Fix IOExternalMethod for getTargetAndMethodForIndex 2 | #@author simo 3 | #@category iOS.kernel 4 | #@keybinding Meta Shift B 5 | #@menupath 6 | #@toolbar logos/in.png 7 | #@description test 8 | 9 | # -*- coding: utf-8 -*- 10 | 11 | from utils.helpers import * 12 | from utils.methods import * 13 | 14 | import json 15 | 16 | def handle_kIOUCScalarIScalarO(func,count0,count1): 17 | logger.debug("kIOUCScalarIScalar func=%s, count0=%d, count1=%d" %(func.getName(),count0,count1)) 18 | tool = state.getTool() 19 | service = tool.getService(DataTypeManagerService) 20 | 21 | o = 0 22 | signature = "" 23 | if count0 == 0: 24 | if count1 != 0: 25 | signature = "%s %s(" 26 | for i in range(0,count1): 27 | signature += "uint32_t *scalarOut%d, " %(i) 28 | 29 | signature = signature[:-2] 30 | signature+= ")" 31 | else: 32 | signature = "%s %s(void)" 33 | else: 34 | signature = "%s %s(" 35 | for i in range(0,count0): 36 | if i < count0: 37 | signature += "uint32_t scalar%d, " %(i) 38 | 39 | signature = signature[:-2] 40 | 41 | signature+= ")" 42 | 43 | name = func.getName() 44 | ret = func.getReturnType() 45 | signature = signature %(ret.toString(),name) 46 | 47 | fdef = parseSignature(service,currentProgram,signature) 48 | return fdef 49 | 50 | def handle_kIOUCStructIStructO(func,count0,count1): 51 | # if count0 and count 1 are set (input,output,inputCnt,outputCnt) 52 | # else (input,inputCnt) 53 | logger.debug("kIOUCStructIStructO func=%s, count0=%d, count1=%d" %(func.getName(),count0,count1)) 54 | tool = state.getTool() 55 | service = tool.getService(DataTypeManagerService) 56 | 57 | signature = "" 58 | if count1 != 0 : 59 | if count0 != 0: 60 | signature = "%s %s(char *input,char *output,uint64_t inputCnt,uint64_t *outputCnt)" 61 | else: 62 | signature = "%s %s(char *output,uint64_t *outputCnt)" 63 | 64 | else: 65 | signature = "%s %s(char *input,uint64_t inputCnt)" 66 | 67 | name = func.getName() 68 | ret = func.getReturnType() 69 | signature = signature %(ret.toString(),name) 70 | 71 | #print signature 72 | fdef = parseSignature(service,currentProgram,signature) 73 | return fdef 74 | 75 | 76 | def handle_kIOUCScalarIStructO(func,count0,count1): 77 | logger.debug("kIOUCScalarIStructO func=%s, count0=%d, count1=%d" %(func.getName(),count0,count1)) 78 | tool = state.getTool() 79 | service = tool.getService(DataTypeManagerService) 80 | 81 | signature = "" 82 | 83 | if count0 == 0: 84 | if count1 != 0: 85 | signature = "%s %s(char *output,uint32_t *outputCnt)" 86 | else: 87 | signature = "%s %s(void)" 88 | else: 89 | signature = "%s %s(" 90 | for i in range(count0): 91 | signature+= "uint32_t scalar%d, " %(i) 92 | 93 | signature+="char *output,uint32_t *outputCnt)" 94 | 95 | name = func.getName() 96 | ret = func.getReturnType() 97 | signature = signature %(ret.toString(),name) 98 | fdef = parseSignature(service,currentProgram,signature) 99 | return fdef 100 | 101 | 102 | def handle_kIOUCScalarIStructI(func,count0,count1): 103 | logger.debug("kIOUCScalarIStructI func=%s, count0=%d, count1=%d" %(func.getName(),count0,count1)) 104 | tool = state.getTool() 105 | service = tool.getService(DataTypeManagerService) 106 | 107 | signature = "" 108 | 109 | if count0 == 0: 110 | if count1 != 0: 111 | signature = "%s %s(char *input,uint32_t inputCnt)" 112 | else: 113 | signature = "%s %s(void)" 114 | else: 115 | signature = "%s %s(" 116 | for i in range(count0): 117 | signature+= "uint32_t scalar%d, " %(i) 118 | 119 | signature+="char *input,uint32_t inputCnt)" 120 | 121 | name = func.getName() 122 | ret = func.getReturnType() 123 | signature = signature %(ret.toString(),name) 124 | fdef = parseSignature(service,currentProgram,signature) 125 | 126 | return fdef 127 | 128 | 129 | def fix_getTargetAndMethodForIndex(target,selectors,sMethods): 130 | logger.info("target=%s selectors=%d ,sMethod=%s" %(target,selectors, sMethods)) 131 | manager = currentProgram.getSymbolTable() 132 | symbolTable = currentProgram.getSymbolTable() 133 | listing = currentProgram.getListing() 134 | refMgr = currentProgram.getReferenceManager() 135 | kIOUCTypeMask = 0x0000000f 136 | kIOUCScalarIScalarO = 0 137 | kIOUCScalarIStructO = 2 138 | kIOUCStructIStructO = 3 139 | kIOUCScalarIStructI = 4 140 | kIOUCForegroundOnly = 0x00000010 141 | kIOUCVariableStructureSize = 0xffffffff 142 | 143 | d = { 144 | kIOUCScalarIScalarO : "kIOUCScalarIScalarO", 145 | kIOUCScalarIStructO : "kIOUCScalarIStructO", 146 | kIOUCStructIStructO : "kIOUCStructIStructO", 147 | kIOUCScalarIStructI : "kIOUCScalarIStructI" 148 | } 149 | 150 | namespace = symbolTable.getNamespace(target,None) 151 | addr = toAddr(sMethods) 152 | assert(namespace != None) 153 | for sel in range(selectors): 154 | object_ptr = addr 155 | func_ptr = addr.add(8) 156 | off_ptr = addr.add(16) 157 | flags_ptr = addr.add(24) 158 | count0_ptr = addr.add(32) 159 | count1_ptr = addr.add(40) 160 | 161 | listing.clearCodeUnits(addr,addr.add(48),False,monitor) 162 | addr = addr.add(48) 163 | makeULongLong(object_ptr,"object") 164 | makeULongLong(flags_ptr,"function") 165 | makeULongLong(off_ptr,"is offset") 166 | makeULongLong(count0_ptr,"count0") 167 | makeULongLong(count1_ptr,"count1") 168 | 169 | 170 | setEOLComment(object_ptr,"sel %d" %(sel)) 171 | isOffset = getDataAt(off_ptr).getValue().getValue() 172 | 173 | if isOffset == 0: 174 | func = makeFunction(func_ptr) 175 | func_addr = getDataAt(func_ptr).getValue() 176 | func = getFunctionAt(func_addr) 177 | 178 | else: 179 | # function referenced as offset 180 | listing.clearCodeUnits(func_ptr,func_ptr,False,monitor) 181 | makeULongLong(func_ptr,"object") 182 | logger.debug("Function is Offset") 183 | off = getDataAt(func_ptr).getValue().getValue() 184 | 185 | ns = namespace.getName() +"_vtable" 186 | 187 | symbol = manager.getSymbol(ns,None) 188 | assert(symbol != None) 189 | ptr = symbol.getAddress().add(off) 190 | ref_addr = getDataAt(ptr).getValue() 191 | 192 | func = getFunctionAt(ref_addr) 193 | 194 | ref = refMgr.addMemoryReference(func_ptr, ref_addr, 195 | RefType.COMPUTED_CALL, SourceType.DEFAULT, 0) 196 | setEOLComment(func_ptr,"offset=0x%x" %(off)) 197 | 198 | flags = getDataAt(flags_ptr).getValue() 199 | count0 = getDataAt(count0_ptr).getValue().getValue() 200 | count1 = getDataAt(count1_ptr).getValue().getValue() 201 | 202 | if func == None: 203 | continue 204 | flags = flags.getValue() & kIOUCTypeMask 205 | 206 | if flags == kIOUCScalarIScalarO: 207 | fdef = handle_kIOUCScalarIScalarO(func,count0,count1) 208 | elif flags == kIOUCScalarIStructO: 209 | fdef = handle_kIOUCScalarIStructO(func,count0,count1) 210 | elif flags == kIOUCStructIStructO: 211 | fdef = handle_kIOUCStructIStructO(func,count0,count1) 212 | elif flags == kIOUCScalarIStructI: 213 | fdef = handle_kIOUCScalarIStructI(func,count0,count1) 214 | else: 215 | raise Exception("Unknown flag %d" %(flags)) 216 | 217 | setEOLComment(flags_ptr,d[flags]) 218 | if "FUN_" in func.getName() or "FN_" in func.getName(): 219 | func.setName("extMethod_%d" %(sel),SourceType.USER_DEFINED) 220 | 221 | func.setParentNamespace(namespace) 222 | cmd = ApplyFunctionSignatureCmd(func.getEntryPoint(),fdef,SourceType.USER_DEFINED) 223 | cmd.applyTo(func.getProgram()) 224 | func.setCallingConvention("__thiscall") 225 | 226 | if __name__ == "__main__": 227 | sMethods = currentAddress 228 | if sMethods == None : 229 | popup("Select a The first External Method address") 230 | exit(-1) 231 | 232 | logger = setup_logging("getTargetAndMethodForIndex") 233 | 234 | addr_str = sMethods.toString() 235 | target = askString("Namespace","Target name: ") # how to track the history of strings ? 236 | selectors = askInt("sMethod " + addr_str,"Selector count: ") 237 | fix_getTargetAndMethodForIndex(target,selectors,addr_str) 238 | 239 | pass 240 | -------------------------------------------------------------------------------- /jsymbols.py: -------------------------------------------------------------------------------- 1 | # Symbolicate the kernelcache from jtool2 2 | #@author simo 3 | #@category iOS.kernel 4 | from utils.methods import * 5 | 6 | if __name__ == "__main__": 7 | 8 | default_file = "test" 9 | fname = askString("Kernelcache symbol file","Symbol file: ",default_file) 10 | f = open(fname,"rb+") 11 | buf = f.read().split('\n') 12 | i = 0 13 | for line in buf: 14 | if len(line) == 0: 15 | continue 16 | addr , symbol , empty = line.split("|") 17 | if len(symbol) == 0: 18 | continue 19 | 20 | if "func_" in symbol: 21 | continue 22 | print addr,symbol 23 | symbol = symbol.strip()#.replace(" ","_") 24 | symbolicate(addr,symbol) 25 | i+= 1 26 | -------------------------------------------------------------------------------- /load_sigatnures.py: -------------------------------------------------------------------------------- 1 | #@category iOS.kernel 2 | #@toolbar logos/sign.png 3 | #@keybinding Meta Shift S 4 | 5 | from utils.helpers import * 6 | from utils.methods import * 7 | import glob 8 | 9 | dtm = void = this = manager = None 10 | 11 | def getHeaderFiles(): 12 | return glob.glob("/Users/mg/ghidra_kernelcache/signatures/*") 13 | 14 | def load_signatures_from_file(filename): 15 | funcs = open(filename,"r").read().strip().split('\n') 16 | tool = state.getTool() 17 | service = tool.getService(DataTypeManagerService) 18 | dtm = currentProgram.getDataTypeManager() 19 | funcDefs = [] 20 | text = "" 21 | 22 | for func in funcs: 23 | vtable = False 24 | if len(func) == 0: 25 | continue 26 | elif func[0:2] == "//": 27 | continue 28 | elif func[0:8] == "virtual ": 29 | vtable = True 30 | text = func[8:] 31 | 32 | elif func[0:7] == "struct ": 33 | structName = func.split(" ")[1].replace(";","") 34 | structDt = find_struct(structName) 35 | if structDt != None: 36 | continue 37 | structDt = StructureDataType(structName,0) 38 | currentProgram.getDataTypeManager().addDataType(structDt,None) 39 | currentProgram.getDataTypeManager().addDataType(PointerDataType(structDt),None) 40 | continue 41 | elif func[0:8] == "typedef ": 42 | kw, old, new = func.split(" ") 43 | addTypeDef(new[:-1],old) 44 | continue 45 | 46 | else: 47 | text = func 48 | 49 | try: 50 | funcDef = parseSignature(service,currentProgram,text,True) 51 | except ghidra.app.util.cparser.C.ParseException as e: 52 | print e 53 | raise Exception("Failed to parse the signature") 54 | 55 | if vtable == True: 56 | funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall) 57 | 58 | funcDefs.append(funcDef) 59 | 60 | return funcDefs 61 | 62 | # this fixes directly the function signature of a given function 63 | def fix_function_signatures(namespace,fdefs): 64 | tool = state.getTool() 65 | service = tool.getService(DataTypeManagerService) 66 | manager = currentProgram.getSymbolTable() 67 | for fdef in fdefs: 68 | symbol = fdef.getName() 69 | if namespace == "kernel": 70 | symbols = manager.getSymbols(symbol) 71 | for s in symbols: 72 | defineSymbol(s,fdef) 73 | 74 | ns = manager.getNamespace(namespace,None) 75 | symbols = manager.getSymbols(symbol,ns) 76 | if len(symbols) == 0 or ns == None: 77 | continue 78 | if symbols == None: 79 | continue 80 | if len(symbols) == 1: 81 | defineSymbol(symbols[0],fdef) 82 | continue 83 | 84 | #TODO : handle multi symbols below 85 | # a very bad workaround, but it's sufficient 86 | for sym in symbols: 87 | addr = sym.getAddress() 88 | 89 | plate = getPlateComment(addr) 90 | if plate == None: 91 | continue 92 | 93 | plate = plate.replace("const","") 94 | retType = fdef.getReturnType() 95 | try: 96 | df = parseSignature(service,currentProgram,plate,True) 97 | except ghidra.app.util.cparser.C.ParseException as e: 98 | print e 99 | exit(0) 100 | 101 | if df == None: 102 | plate = retType.toString()+ " " + plate 103 | try: 104 | df = parseSignature(service,currentProgram,plate,True) 105 | except ghidra.app.util.cparser.C.ParseException as e: 106 | print e 107 | exit(0) 108 | 109 | if df == None: 110 | continue 111 | 112 | defineSymbol(sym,df) 113 | 114 | def fix_method_definitions(namespace,fdefs): 115 | if namespace == "kernel": 116 | for fdef in fdefs: 117 | name = fdef.getName() 118 | symbols = manager.getSymbols(name) 119 | for symbol in symbols: 120 | full_name = symbol.getName(True) 121 | dt = find_funcdef(full_name) 122 | if dt == None: 123 | continue 124 | dt.setReturnType(fdef.getReturnType()) 125 | args = fdef.getArguments() 126 | args.insert(0,this) 127 | dt.setArguments(args) 128 | 129 | return 130 | 131 | for fdef in fdefs: 132 | name = fdef.getName() 133 | full_name = namespace + '::'+ name 134 | dt = find_funcdef(full_name) 135 | if dt == None: 136 | continue 137 | 138 | dt.setReturnType(fdef.getReturnType()) 139 | args = fdef.getArguments() 140 | args.insert(0,this) 141 | dt.setArguments(args) 142 | 143 | if __name__ == "__main__": 144 | DeclareDataTypes() 145 | dtm = currentProgram.getDataTypeManager() 146 | void = currentProgram.getDataTypeManager().findDataType("/void") 147 | this = ParameterDefinitionImpl("this",PointerDataType(void),"") 148 | manager = currentProgram.getSymbolTable() 149 | 150 | files = getHeaderFiles() 151 | for file in files: 152 | print ("[+] Processing %s" %(file)) 153 | namespace = file.split(".h")[0].split("/")[-1] 154 | fdefs= load_signatures_from_file(file) 155 | fix_function_signatures(namespace,fdefs) 156 | fix_method_definitions(namespace,fdefs) 157 | -------------------------------------------------------------------------------- /load_structs.py: -------------------------------------------------------------------------------- 1 | #import structures and typedefs from old kernelcache to a new one 2 | #@author simo 3 | #@category iOS.kernel 4 | #@toolbar logos/load_structs.png 5 | #@keybinding Meta Shift L 6 | #@menupath 7 | 8 | from ghidra.app.services import DataTypeManagerService 9 | from ghidra.program.model.data import StructureDataType,PointerDataType 10 | from ghidra.app.services import ProgramManager 11 | 12 | """ 13 | - Get all structures from source program and copy them into destination program 14 | - It avoids taking "_vtable" structures because fix_kernelcache will handle it 15 | - If struct is already there, just skip it 16 | """ 17 | 18 | 19 | src_prog_string = "" 20 | dst_prog_string = "" 21 | 22 | def isThere(name,programDT): 23 | 24 | if "MetaClass" in name: 25 | return True 26 | 27 | if "_vtable" in name: 28 | return True 29 | 30 | dataType = programDT.getDataType(name) 31 | 32 | if dataType : 33 | return True 34 | 35 | return False 36 | 37 | if __name__ == "__main__": 38 | tool = state.getTool() 39 | service = tool.getService(DataTypeManagerService) 40 | dataTypeManagers = service.getDataTypeManagers(); 41 | 42 | programManager = state.getTool().getService(ProgramManager) 43 | progs =programManager.getAllOpenPrograms() 44 | if len(progs) < 2 : 45 | popup ("You must open at least two programs") 46 | exit(1) 47 | 48 | src = dst = None 49 | for prog in progs: 50 | if src_prog_string == prog.getName(): 51 | src = prog 52 | elif dst_prog_string == prog.getName(): 53 | dst = prog 54 | 55 | if src == None or dst == None: 56 | popup("Could not get src/dst program") 57 | exit(0) 58 | 59 | print src,dst 60 | 61 | src_dtm = src.getDataTypeManager() 62 | dst_dtm = dst.getDataTypeManager() 63 | 64 | structs = src_dtm.getAllStructures() 65 | 66 | for s in structs: 67 | name = s.getName() 68 | res = isThere('/'+name,dst_dtm) 69 | if res == True: 70 | continue 71 | 72 | res = isThere('/Demangler/'+name,dst_dtm) 73 | if res == True: 74 | continue 75 | 76 | struct = StructureDataType(name,0) 77 | dst_dtm.addDataType(struct,None) 78 | dst_dtm.addDataType(PointerDataType(struct),None) 79 | -------------------------------------------------------------------------------- /namespace.py: -------------------------------------------------------------------------------- 1 | #@author simo 2 | #@category iOS.kernel 3 | #@keybinding Meta Shift N 4 | # -*- coding: utf-8 -*- 5 | 6 | from utils.helpers import * 7 | from utils.methods import * 8 | 9 | if __name__ == "__main__": 10 | 11 | targetFunction = getSymbolAt(currentAddress) 12 | 13 | if targetFunction == None : 14 | targetFunction = askString("You didn't select a method", "Method name:") 15 | exit(-1) 16 | 17 | # how to track the history of strings ? 18 | className = askString("Fix Namespace","namespace of "+ targetFunction.toString()) 19 | symbolTable = currentProgram.getSymbolTable() 20 | 21 | namespace = symbolTable.getNamespace(className,None) 22 | if namespace == None: 23 | popup("%s class not found" %(className)) 24 | exit(-1) 25 | 26 | fix_namespace(className,getFunctionAt(targetFunction.getAddress())) 27 | print "Done" 28 | -------------------------------------------------------------------------------- /propagate.py: -------------------------------------------------------------------------------- 1 | # Propagate variable symbol + type over a function 2 | #@author simo 3 | #@category iOS.kernel 4 | #@keybinding Alt X 5 | #@menupath 6 | #@toolbar logos/sdsdlogo.png 7 | #@description propagate the new symbol name/type across function arguments 8 | # -*- coding: utf-8 -*- 9 | 10 | # interesting link : https://github.com/NationalSecurityAgency/ghidra/issues/2236#issuecomment-685204563 11 | from utils.helpers import * 12 | from ghidra.app.decompiler.component import DecompilerUtils 13 | from ghidra.app.decompiler import ClangVariableToken,ClangFieldToken 14 | from ghidra.program.database.data import StructureDB 15 | #from ghidra.app.decompiler import ClangToken as clang 16 | """ 17 | ClangOpToken: ex return, if , else ..etc 18 | ClangSyntaxToken : {} () 19 | ClangFuncNameToken : a function call 20 | """ 21 | 22 | datatypes = {} 23 | 24 | def setup_datatypes(): 25 | global datatypes 26 | dtm = currentProgram.getDataTypeManager() 27 | uchar = dtm.getDataType("/uchar") 28 | ushort = dtm.getDataType("/ushort") 29 | uint = dtm.getDataType("/uint") 30 | ulonglong = dtm.getDataType("/ulonglong") 31 | 32 | datatypes[1] = uchar 33 | datatypes[2] = ushort 34 | datatypes[4] = uint 35 | datatypes[8] = ulonglong 36 | assert (uchar and ushort and uint and ulonglong) 37 | #exit(0) 38 | structure = None 39 | 40 | 41 | def validate_token_store(token): 42 | """ 43 | Checks the source target token 44 | Support : STORE , (LOAD later) 45 | """ 46 | # the token must be a variable and has an operation code 47 | if token.isVariableRef() == False or token.getPcodeOp() == None: 48 | return False 49 | 50 | op = token.getPcodeOp() 51 | if op.getOpcode() != PcodeOp.STORE: 52 | return False 53 | return True 54 | 55 | def get_struct_fild(struct,fields): 56 | pass 57 | 58 | # returns (datatype,size) of the variable token 59 | def handle_source_token(token): 60 | op = token.getPcodeOp() 61 | if (op.getOpcode() == PcodeOp.STORE): 62 | inputs = op.getInputs() 63 | dst,src = inputs[1], inputs[2] 64 | #print op 65 | 66 | if src.isConstant(): 67 | size = src.getSize() 68 | dt = None 69 | elif src.isRegister() or src.isUnique(): 70 | size = src.getSize() 71 | high = src.getHigh() 72 | 73 | if (isinstance(high,ghidra.program.model.pcode.HighOther) == True): 74 | high = None 75 | return (None,size) 76 | dt = high.getDataType() 77 | 78 | # elif src.isUnique(): 79 | # print "UNIQ" 80 | # size = src.getSize() 81 | # high = src.getHigh() 82 | # print size,high 83 | # raise Exception 84 | else: 85 | print("hndle_source_token(): varnode type not supported [IGNORE] ") 86 | return (None,src.getSize()) 87 | 88 | return (dt,size) 89 | 90 | #returns the target variable to be modified 91 | def handle_dest_vartoken(line,src_dt,src_size): 92 | var = None 93 | fields = [] 94 | for tok in line.getAllTokens(): 95 | if tok.toString() == "=": 96 | break 97 | 98 | if(isinstance(tok,ClangVariableToken) == True): 99 | if var != None: 100 | continue 101 | sym = tok.getHighVariable().getSymbol() 102 | if sym: var = tok 103 | 104 | elif(isinstance(tok,ClangFieldToken) == True): 105 | fields.append(tok) 106 | # now we have "this [IOBluetoothDeviceUserClient, field_0x10]" 107 | #if isinstance(this) 108 | var_dt = var.getHighVariable().getSymbol().getDataType() 109 | path = var_dt.getDataTypePath() 110 | mgr = var_dt.getDataTypeManager() 111 | n = var_dt.getName().replace("*","").strip() 112 | st = find_struct(n) 113 | if (st == None): 114 | raise Exception("Could not find %s structure"% n) 115 | #var_name = 116 | # fields tokens are taken recursively : dt->field1.field2. .. .fieldN 117 | if (isinstance(st,StructureDB) == False): 118 | return None 119 | 120 | cps = st.getComponents() 121 | struct = st 122 | if cps == None: 123 | return None 124 | for field in fields: 125 | cps = struct.getComponents() 126 | if cps == None: 127 | break 128 | fld_name = field.toString() 129 | # if we hit "field_name", it does mean the field member is still undefined 130 | # and we reach the end of the structure parsing 131 | if "field_" in fld_name: 132 | try: 133 | f,idx = fld_name.split("_") 134 | except ValueError: 135 | f,idx,_ = fld_name.split("_") 136 | target = struct.getDataTypeAt(int(idx,16)) 137 | fld_name = f + "_" + str(idx) 138 | try: 139 | if src_dt: dt = src_dt 140 | else: dt = datatypes[src_size] 141 | struct.replaceAtOffset(int(idx,16),dt,src_size,fld_name+"_","") 142 | 143 | # sometimes the variable is not aligned and is conflicting with other struct member 144 | # must be handled manually 145 | except java.lang.IllegalArgumentException as e: 146 | print (e) 147 | break 148 | 149 | for cp in cps: 150 | if cp.getFieldName() == fld_name: 151 | if(isinstance(cp.getDataType(),StructureDB)): 152 | struct = cp.getDataType() 153 | break 154 | 155 | # token: is the source target token 156 | def handle_line_store(line,token): 157 | global structure 158 | src_dt, src_sz = handle_source_token(token) 159 | handle_dest_vartoken(line,src_dt,src_sz) 160 | """ 161 | op = token.getPcodeOp() 162 | assert(op.getOpcode() == PcodeOp.STORE) 163 | inputs = op.getInputs() 164 | dst,src = inputs[1], inputs[2] 165 | 166 | if src.isConstant() == False: 167 | sym = src.getHigh().getSymbol() 168 | if (sym == None): 169 | return 170 | dt = sym.getDataType() 171 | print dt.getLength() 172 | print("Unable to handle no constant values") 173 | exit(0) 174 | return 175 | """ 176 | return 177 | 178 | # now get variableRef 179 | var = None 180 | var_name = None 181 | fields = [] 182 | f_done = True 183 | 184 | for t in line.getAllTokens(): 185 | #print t,type(t) 186 | if(isinstance(t,ClangVariableToken) == True): 187 | if var != None: 188 | continue 189 | sym = t.getHighVariable().getSymbol() 190 | if sym: var = t 191 | 192 | elif(isinstance(t,ClangFieldToken) == True): 193 | fields.append(t) 194 | 195 | if t == token: 196 | print "We are done" 197 | break 198 | 199 | var_dt = var.getHighVariable().getSymbol().getDataType() 200 | path = var_dt.getDataTypePath() 201 | mgr = var_dt.getDataTypeManager() 202 | n = var_dt.getName().replace("*","").strip() 203 | st = find_struct(n) 204 | if (st == None): 205 | raise Exception("Could not find %s structure"% n) 206 | 207 | # fields tokens are taken recursively : dt->field1.field2...fieldn 208 | cps = st.getComponents() 209 | struct = st 210 | if cps == None: 211 | return 212 | for field in fields: 213 | cps = struct.getComponents() 214 | if cps == None: 215 | break 216 | fld_name = field.toString() 217 | # if we hit "field_name", it does mean the field member is still undefined 218 | # and we reach the end of the structure parsing 219 | if "field_" in fld_name: 220 | f,idx = fld_name.split("_") 221 | #print f,idx 222 | target = struct.getDataTypeAt(int(idx,16)) 223 | #target.setFieldName("f_"+idx) 224 | try: 225 | struct.replaceAtOffset(int(idx,16),datatypes[target_size],target_size,"f_"+idx,"") 226 | except java.lang.IllegalArgumentException as e: 227 | print (e) 228 | break 229 | for cp in cps: 230 | if cp.getFieldName() == fld_name: 231 | if(isinstance(cp.getDataType(),StructureDB)): 232 | struct = cp.getDataType() 233 | break 234 | 235 | def debug_line(lines,linum): 236 | for line in lines: 237 | if line.getLineNumber() != linum: 238 | continue 239 | 240 | print (line) 241 | tokens = line.getAllTokens() 242 | for token in tokens: 243 | print token, type(token),"opcode :", token.getPcodeOp() 244 | 245 | 246 | 247 | def handle_line(line): 248 | tokens = line.getAllTokens() 249 | for token in tokens: 250 | if validate_token_store(token) == True: 251 | handle_line_store(line,token) 252 | pass 253 | else: # handle other opcodes here 254 | pass 255 | 256 | def do_assign(addr): 257 | entry = addr 258 | setup_datatypes() 259 | print(entry) 260 | func = getFunctionContaining(entry) 261 | assert(func != None) 262 | print func 263 | decompInterface = DecompInterface() 264 | decompInterface.openProgram(currentProgram) 265 | decompiled = decompInterface.decompileFunction(func, 120, monitor) 266 | 267 | lines = DecompilerUtils.toLines(decompiled.getCCodeMarkup()) 268 | 269 | for line in lines: 270 | handle_line(line) 271 | 272 | decompInterface.dispose() 273 | print("Done") 274 | 275 | if __name__ == "__main__": 276 | listing = currentProgram.getListing() 277 | do_assign(currentAddress) 278 | -------------------------------------------------------------------------------- /screenshots/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image1.png -------------------------------------------------------------------------------- /screenshots/image10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image10.png -------------------------------------------------------------------------------- /screenshots/image11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image11.png -------------------------------------------------------------------------------- /screenshots/image12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image12.png -------------------------------------------------------------------------------- /screenshots/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image2.png -------------------------------------------------------------------------------- /screenshots/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image3.png -------------------------------------------------------------------------------- /screenshots/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image4.png -------------------------------------------------------------------------------- /screenshots/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image5.png -------------------------------------------------------------------------------- /screenshots/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image6.png -------------------------------------------------------------------------------- /screenshots/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image7.png -------------------------------------------------------------------------------- /screenshots/image8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image8.png -------------------------------------------------------------------------------- /screenshots/image9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/screenshots/image9.png -------------------------------------------------------------------------------- /signatures/IOBufferMemoryDescriptor.h: -------------------------------------------------------------------------------- 1 | IOBufferMemoryDescriptor * inTaskWithOptions(task_t inTask, IOOptionBits options, vm_size_t capacity, vm_offset_t alignment, uint32_t kernTag, uint32_t userTag); 2 | IOBufferMemoryDescriptor * inTaskWithOptions(task_t inTask, IOOptionBits options, vm_size_t capacity, vm_offset_t alignment); 3 | IOBufferMemoryDescriptor * inTaskWithPhysicalMask(task_t inTask, IOOptionBits options, mach_vm_size_t capacity, mach_vm_address_t physicalMask); 4 | IOBufferMemoryDescriptor * withBytes(const void *bytes, vm_size_t withLength, IODirection withDirection, bool withContiguousMemory); 5 | IOBufferMemoryDescriptor * withCapacity(vm_size_t capacity, IODirection withDirection, bool withContiguousMemory); 6 | IOBufferMemoryDescriptor * withCopy(task_t inTask, IOOptionBits options, vm_map_t sourceMap, mach_vm_address_t source, mach_vm_size_t size); 7 | IOBufferMemoryDescriptor * withOptions(IOOptionBits options, vm_size_t capacity, vm_offset_t alignment); 8 | virtual void setLength(vm_size_t length); 9 | virtual void setDirection(IODirection direction); 10 | virtual bool initWithPhysicalMask(task_t inTask, IOOptionBits options, mach_vm_size_t capacity, mach_vm_address_t alignment, mach_vm_address_t physicalMask); 11 | virtual vm_size_t getCapacity(void); 12 | virtual void * getBytesNoCopy(vm_size_t start, vm_size_t withLength); 13 | virtual void * getBytesNoCopy(void); 14 | virtual bool appendBytes(const void *bytes, vm_size_t withLength); 15 | kern_return_t SetLength(uint64_t length, void * supermethod); 16 | kern_return_t GetAddressRange(IOAddressSegment *range); 17 | -------------------------------------------------------------------------------- /signatures/IOCommandGate.h: -------------------------------------------------------------------------------- 1 | IOCommandGate * commandGate(void *owner, void *action); 2 | virtual void setWorkLoop(IOWorkLoop *inWorkLoop); 3 | virtual IOReturn runCommand(void *arg0, void *arg1, void *arg2, void *arg3); 4 | virtual IOReturn runAction(void *action, void *arg0, void *arg1, void *arg2, void *arg3); 5 | virtual void commandWakeup(void *event, bool oneThread); 6 | //virtual IOReturn commandSleep(void *event, AbsoluteTime deadline, UInt32 interruptible); 7 | //virtual IOReturn commandSleep(void *event, UInt32 interruptible); 8 | virtual IOReturn attemptCommand(void *arg0, void *arg1, void *arg2, void *arg3); 9 | -------------------------------------------------------------------------------- /signatures/IODataQueue.h: -------------------------------------------------------------------------------- 1 | IODataQueue * withEntries(UInt32 numEntries, UInt32 entrySize); 2 | IODataQueue * withCapacity(UInt32 size); 3 | virtual void setNotificationPort(ipc_port *port); 4 | virtual void sendDataAvailableNotification(void); 5 | virtual bool initWithEntries(UInt32 numEntries, UInt32 entrySize); 6 | virtual bool initWithCapacity(UInt32 size); 7 | virtual IOMemoryDescriptor * getMemoryDescriptor(void); 8 | virtual bool enqueue(void *data, UInt32 dataSize); 9 | -------------------------------------------------------------------------------- /signatures/IOEventSource.h: -------------------------------------------------------------------------------- 1 | virtual const OSMetaClass * getMetaClass(); 2 | virtual bool init(); 3 | virtual void free(); 4 | virtual bool init_1(OSObject *owner, void *action); 5 | virtual bool checkForWork(); 6 | virtual void setWorkLoop(IOWorkLoop *workLoop); 7 | virtual void setNext(IOEventSource *next); 8 | virtual IOEventSource *getNext() 9 | virtual void * getAction(); 10 | virtual void enable(); 11 | virtual void disable(); 12 | virtual bool isEnabled(); 13 | virtual IOWorkLoop *getWorkLoop(); 14 | virtual bool onThread(); 15 | 16 | -------------------------------------------------------------------------------- /signatures/IOMemoryDescriptor.h: -------------------------------------------------------------------------------- 1 | //https://developer.apple.com/documentation/kernel/iomemorydescriptor?language=objc 2 | IOMemoryDescriptor * withPhysicalAddress(IOPhysicalAddress address, IOByteCount withLength, IODirection withDirection); 3 | //IOMemoryDescriptor *(mach_vm_address_t address, mach_vm_size_t length, IOOptionBits options, task_t task); 4 | IOMemoryDescriptor * withOptions(void *buffers, UInt32 count, UInt32 offset, task_t task, IOOptionBits options, IOMapper *mapper); 5 | IOMemoryDescriptor * withAddressRanges(IOAddressRange *ranges, UInt32 rangeCount, IOOptionBits options, task_t task); 6 | IOMemoryDescriptor * withAddressRange(void *address, mach_vm_size_t withLength, IOOptionBits options, task * task); 7 | IOMemoryDescriptor * withPersistentMemoryDescriptor(IOMemoryDescriptor *originalMD); 8 | virtual IOReturn complete(IODirection forDirection); 9 | virtual IOMemoryMap * createMappingInTask(task_t intoTask, mach_vm_address_t atAddress, IOOptionBits options, mach_vm_size_t offset = 0, mach_vm_size_t length = 0); 10 | virtual IODirection getDirection(); 11 | virtual IOByteCount getLength(); 12 | virtual IOReturn getPageCounts(IOByteCount *residentPageCount, IOByteCount *dirtyPageCount); 13 | virtual IOPhysicalAddress getPhysicalAddress(); 14 | virtual bool initWithOptions(void *buffers,UInt32 count, UInt32 offset, task_t task, IOOptionBits options, IOMapper *mapper = 0); 15 | virtual IOMemoryMap * map(IOOptionBits options = 0 ); 16 | virtual IOReturn performOperation( IOOptionBits options, IOByteCount offset, IOByteCount length ); 17 | virtual IOReturn prepare(IODirection forDirection = 0); 18 | virtual IOByteCount readBytes(IOByteCount offset, void *bytes, IOByteCount withLength); 19 | virtual IOMemoryMap * setMapping( task_t task, IOVirtualAddress mapAddress, IOOptionBits options = 0 ); 20 | virtual IOByteCount writeBytes( IOByteCount offset, void * bytes, IOByteCount withLength); 21 | virtual void addMapping(IOMemoryMap *mapping); 22 | virtual IOReturn doMap(vm_map_t addressMap, IOVirtualAddress *atAddress, IOOptionBits options, IOByteCount sourceOffset, IOByteCount length); 23 | virtual IOReturn doUnmap(vm_map_t addressMap, IOVirtualAddress logical, IOByteCount length); 24 | virtual uint64_t getPhysicalSegment( IOByteCount offset, IOByteCount *length, IOOptionBits options = 0 ); 25 | virtual const OSMetaClass * getMetaClass(); 26 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 27 | virtual kern_return_t Dispatch(const IORPC rpc); 28 | virtual void free(); 29 | virtual IOReturn setPurgeable( IOOptionBits newState,IOOptionBits * oldState ); 30 | virtual uint64_t getPreparationID( void ); 31 | virtual void setTag( IOOptionBits tag ); 32 | virtual IOOptionBits getTag( void ); 33 | virtual IOReturn redirect( task_t safeTask, bool redirect ); 34 | virtual IOMemoryMap * makeMapping(IOMemoryDescriptor * owner,task_t intoTask,IOVirtualAddress atAddress,IOOptionBits options,IOByteCount offset,IOByteCount length ); 35 | virtual void removeMapping(IOMemoryMap * mapping ); 36 | typedef undefined4 DMACommandOps; 37 | virtual IOReturn dmaCommandOperation(DMACommandOps op, void *vData, int dataSize); 38 | -------------------------------------------------------------------------------- /signatures/IOMemoryMap.h: -------------------------------------------------------------------------------- 1 | virtual uint64_t getAddress(); 2 | virtual task_t getAddressTask(); 3 | virtual IOByteCount getLength(); 4 | virtual IOOptionBits getMapOptions(); 5 | virtual IOMemoryDescriptor * getMemoryDescriptor(); 6 | virtual IOPhysicalAddress getPhysicalAddress(); 7 | virtual uint64_t getPhysicalSegment( IOByteCount offset, IOByteCount *length, IOOptionBits options = 0); 8 | virtual IOVirtualAddress getVirtualAddress(); 9 | virtual IOReturn redirect( IOMemoryDescriptor *newBackingMemory, IOOptionBits options, IOByteCount offset = 0); 10 | virtual IOReturn unmap(); 11 | virtual IOReturn wireRange(uint32_t options, mach_vm_size_t offset, mach_vm_size_t length); 12 | -------------------------------------------------------------------------------- /signatures/IORegistryEntry.h: -------------------------------------------------------------------------------- 1 | virtual const OSMetaClass * getMetaClass(); 2 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 3 | virtual bool init_1( OSDictionary * dictionary ); 4 | virtual void setPropertyTable( OSDictionary * dict ); 5 | virtual bool setProperty(const OSSymbol * aKey,OSObject * anObject); 6 | virtual bool setProperty_1(const OSString * aKey, OSObject * anObject); 7 | virtual bool setProperty_2(const char * aKey, OSObject * anObject); 8 | virtual bool setProperty_3(const char * aKey, const char * aString); 9 | virtual bool setProperty_4(const char * aKey, bool aBoolean); 10 | virtual bool setProperty_5( const char * aKey,unsigned long long aValue,unsigned int aNumberOfBits); 11 | virtual bool setProperty_6( const char * aKey,void * bytes,unsigned int length); 12 | virtual void removeProperty( const OSSymbol * aKey); 13 | virtual void removeProperty_1( const OSString * aKey); 14 | virtual void removeProperty_2( const char * aKey); 15 | virtual OSObject * getProperty( const OSSymbol * aKey); 16 | virtual OSObject * getProperty_1( const OSString * aKey); 17 | virtual OSObject * getProperty_2( const char * aKey); 18 | virtual OSObject * getProperty_3( const OSSymbol * aKey,const IORegistryPlane * plane,IOOptionBits options); 19 | virtual OSObject * getProperty_4( const OSString *aKey,const IORegistryPlane * plane,IOOptionBits options); 20 | virtual OSObject * getProperty_5( const char *aKey,const IORegistryPlane * plane,IOOptionBits options); 21 | virtual OSObject * copyProperty_2( const OSSymbol * aKey,const IORegistryPlane * plane ); 22 | virtual OSObject * copyProperty_1( const OSString * aKey,const IORegistryPlane * plane ); 23 | virtual OSObject * copyProperty( const char * aKey,const IORegistryPlane * plane ); 24 | virtual OSObject * copyProperty_3( const OSSymbol * aKey); 25 | virtual OSObject * copyProperty_4( const OSString * aKey); 26 | virtual OSObject * copyProperty_5( const char * aKey); 27 | virtual OSDictionary * dictionaryWithProperties( void ); 28 | virtual bool serializeProperties( OSSerialize * serialize ); 29 | virtual IOReturn setProperties( OSObject * properties ); 30 | virtual OSIterator * getParentIterator( const IORegistryPlane * plane ); 31 | virtual void applyToParents( void * applier,void * context,const IORegistryPlane * plane ); 32 | virtual IORegistryEntry * getParentEntry( const IORegistryPlane * plane ); 33 | virtual OSIterator * getChildIterator( const IORegistryPlane * plane ); 34 | virtual void applyToChildren( void * applier,void * context,const IORegistryPlane * plane ); 35 | virtual IORegistryEntry * getChildEntry( const IORegistryPlane * plane ); 36 | virtual bool isChild( IORegistryEntry * child,const IORegistryPlane * plane,bool onlyChild ); 37 | virtual bool isParent( IORegistryEntry * parent,const IORegistryPlane * plane,bool onlyParent); 38 | virtual bool inPlane( const IORegistryPlane * plane); 39 | virtual unsigned int getDepth( const IORegistryPlane * plane ); 40 | virtual bool attachToParent( IORegistryEntry * parent,const IORegistryPlane * plane ); 41 | virtual void detachFromParent( IORegistryEntry * parent,const IORegistryPlane * plane ); 42 | virtual bool attachToChild( IORegistryEntry * child,const IORegistryPlane * plane ); 43 | virtual void detachFromChild( IORegistryEntry * child,const IORegistryPlane * plane ); 44 | virtual void detachAbove( const IORegistryPlane * plane ); 45 | virtual void detachAll( const IORegistryPlane * plane ); 46 | virtual const char * getName( const IORegistryPlane * plane ); 47 | virtual const OSSymbol * copyName(const IORegistryPlane * plane); 48 | virtual bool compareNames( OSObject * name, OSString ** matched ); 49 | virtual bool compareName( OSString * name, OSString ** matched); 50 | virtual void setName( const OSSymbol * name,const IORegistryPlane * plane); 51 | virtual void setName_1( const char * name,const IORegistryPlane * plane); 52 | virtual const char * getLocation( const IORegistryPlane * plane); 53 | virtual const OSSymbol * copyLocation(const IORegistryPlane * plane); 54 | virtual void setLocation( const OSSymbol * location,const IORegistryPlane * plane ); 55 | virtual void setLocation_1( const char * location,const IORegistryPlane * plane); 56 | virtual bool getPath( char * path, int * length,const IORegistryPlane * plane); 57 | virtual bool getPathComponent( char * path, int * length,const IORegistryPlane * plane ); 58 | virtual IORegistryEntry * childFromPath( const char * path,const IORegistryPlane * plane,char * residualPath,int * residualLength ); 59 | virtual bool init_2( IORegistryEntry * from,const IORegistryPlane * inPlane ); 60 | virtual IORegistryEntry * copyParentEntry( const IORegistryPlane * plane ); 61 | virtual IORegistryEntry * copyChildEntry( const IORegistryPlane * plane ); 62 | virtual IOReturn runPropertyAction(void * action, OSObject *target,void *arg0 , void *arg1,void *arg2 , void *arg3); 63 | virtual void free(); -------------------------------------------------------------------------------- /signatures/IOService.h: -------------------------------------------------------------------------------- 1 | virtual const OSMetaClass * getMetaClass(); 2 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 3 | virtual kern_return_t Dispatch(const IORPC rpc); 4 | virtual bool init(); 5 | virtual void free(); 6 | virtual bool serializeProperties( OSSerialize * s ); 7 | virtual bool requestTerminate( IOService * provider, IOOptionBits options ); 8 | virtual bool willTerminate( IOService * provider, IOOptionBits options ); 9 | virtual bool didTerminate( IOService * provider, IOOptionBits options, bool * defer ); 10 | virtual SInt32 nextIdleTimeout(AbsoluteTime currentTime,AbsoluteTime lastActivity, unsigned int powerState); 11 | virtual void systemWillShutdown( IOOptionBits specifier ); 12 | virtual IOService * copyClientWithCategory( const OSSymbol * category ); 13 | typedef void IOReportChannelList; 14 | virtual IOReturn configureReport(IOReportChannelList *channels,void *action,void * result,void *destination); 15 | virtual IOReturn updateReport(IOReportChannelList*channels,void * action,void *result,void *destination); 16 | virtual IOOptionBits getState( void ); 17 | virtual void registerService( IOOptionBits options); 18 | virtual bool start( IOService * provider ); 19 | virtual void stop( IOService * provider ); 20 | virtual bool open( IOService * forClient,IOOptionBits options,void * arg ); 21 | virtual void close( IOService * forClient,IOOptionBits options); 22 | virtual bool isOpen( const IOService * forClient); 23 | virtual bool handleOpen(IOService * forClient,IOOptionBits options,void * arg ); 24 | virtual void handleClose(IOService * forClient,IOOptionBits options ); 25 | virtual bool handleIsOpen( const IOService * forClient ); 26 | virtual bool terminate( IOOptionBits options); 27 | virtual bool finalize( IOOptionBits options ); 28 | virtual bool init_1( OSDictionary * dictionary ); 29 | virtual bool init_2( IORegistryEntry * from,const IORegistryPlane * inPlane ); 30 | virtual void free( void ); 31 | virtual bool lockForArbitration( bool isSuccessRequired); 32 | virtual void unlockForArbitration( void ); 33 | virtual bool terminateClient( IOService * client, IOOptionBits options ); 34 | virtual UInt32 getBusyState( void ); 35 | virtual void adjustBusy( SInt32 delta ); 36 | virtual bool matchPropertyTable( OSDictionary * table,SInt32 * score ); 37 | virtual bool matchPropertyTable_1( OSDictionary * table ); 38 | virtual IOService * matchLocation( IOService * client ); 39 | virtual bool addNeededResource( const char * key ); 40 | virtual bool compareProperty( OSDictionary * matching,const char * key ); 41 | virtual bool compareProperty_1( OSDictionary * matching,const OSString * key ); 42 | virtual bool compareProperties( OSDictionary * matching,OSCollection * keys ); 43 | virtual bool attach( IOService * provider ); 44 | virtual void detach( IOService * provider ); 45 | virtual IOService * getProvider( void ); 46 | virtual IOWorkLoop * getWorkLoop(); 47 | virtual OSIterator * getProviderIterator( void ); 48 | virtual OSIterator * getOpenProviderIterator( void ); 49 | virtual IOService * getClient( void ); 50 | virtual OSIterator * getClientIterator( void ); 51 | virtual OSIterator * getOpenClientIterator( void ); 52 | virtual IOReturn callPlatformFunction( const OSSymbol * functionName,bool waitForFunction,void *param1, void *param2,void *param3, void *param4 ); 53 | virtual IOReturn callPlatformFunction_1( const char * functionName,bool waitForFunction,void *param1, void *param2,void *param3, void *param4 ); 54 | virtual IOReturn getResources( void ); 55 | typedef uint IOItemCount; 56 | virtual IOItemCount getDeviceMemoryCount( void ); 57 | //typedef char IODeviceMemory; 58 | virtual IODeviceMemory * getDeviceMemoryWithIndex( unsigned int index ); 59 | virtual IOMemoryMap * mapDeviceMemoryWithIndex( unsigned int index,IOOptionBits options ); 60 | virtual OSArray * getDeviceMemory( void ); 61 | virtual void setDeviceMemory( OSArray * array ); 62 | virtual IOReturn registerInterrupt(int source, OSObject *target,void * handler,void *refCon); 63 | virtual IOReturn unregisterInterrupt(int source); 64 | virtual IOReturn getInterruptType(int source, int *interruptType); 65 | virtual IOReturn enableInterrupt(int source); 66 | virtual IOReturn disableInterrupt(int source); 67 | virtual IOReturn causeInterrupt(int source); 68 | virtual IOReturn requestProbe( IOOptionBits options ); 69 | virtual IOReturn message( UInt32 type, IOService * provider,void * argument); 70 | virtual IOReturn messageClient( UInt32 messageType, OSObject * client,void * messageArgument , vm_size_t argSize ); 71 | virtual IOReturn messageClients( UInt32 type,void * argument, vm_size_t argSize); 72 | virtual IONotifier * registerInterest( const OSSymbol * typeOfInterest,void * handler,void * target, void * ref); 73 | virtual void applyToProviders( void * applier,void * context ); 74 | virtual void applyToClients( void * applier,void * context ); 75 | virtual void applyToInterested( const OSSymbol * typeOfInterest, void * applier,void * context ); 76 | virtual IOReturn acknowledgeNotification( void *notification,IOOptionBits response ); 77 | virtual IOReturn newUserClient( task_t owningTask, void * securityID,UInt32 type, OSDictionary * properties,IOUserClient ** handler ); 78 | virtual IOReturn newUserClient_1( task_t owningTask, void * securityID,UInt32 type,IOUserClient ** handler ); 79 | virtual const char * stringFromReturn( IOReturn rtn ); 80 | virtual int errnoFromReturn( IOReturn rtn ); 81 | virtual bool serializeProperties( OSSerialize * s ); 82 | virtual void PMinit( void ); 83 | virtual void PMstop( void ); 84 | virtual void joinPMtree( IOService * driver ); 85 | //typedef char IOPMPowerState; 86 | typedef int IOPMPowerFlags; 87 | virtual IOReturn registerPowerDriver(IOService * controllingDriver,IOPMPowerState * powerStates,unsigned long numberOfStates ); 88 | virtual IOReturn requestPowerDomainState(IOPMPowerFlags desiredState,IOPowerConnection * whichChild,unsigned long specificationFlags ); 89 | virtual bool activityTickle(unsigned long type,unsigned long stateNumber); 90 | virtual IOReturn setAggressiveness(unsigned long type,unsigned long newLevel ); 91 | virtual IOReturn getAggressiveness(unsigned long type,unsigned long * currentLevel ); 92 | virtual IOReturn addPowerChild( IOService * theChild ); 93 | virtual IOReturn removePowerChild( IOPowerConnection * theChild ); 94 | virtual IOReturn setIdleTimerPeriod( unsigned long period ); 95 | virtual IOReturn setPowerState(unsigned long powerStateOrdinal,IOService * whatDevice ); 96 | virtual unsigned long maxCapabilityForDomainState( IOPMPowerFlags domainState ); 97 | virtual unsigned long initialPowerStateForDomainState( IOPMPowerFlags domainState ); 98 | virtual unsigned long powerStateForDomainState( IOPMPowerFlags domainState ); 99 | virtual IOReturn powerStateWillChangeTo(IOPMPowerFlags capabilities,unsigned long stateNumber,IOService * whatDevice ); 100 | virtual IOReturn powerStateDidChangeTo(IOPMPowerFlags capabilities,unsigned long stateNumber,IOService * whatDevice ); 101 | virtual bool askChangeDown( unsigned long ); 102 | virtual bool tellChangeDown( unsigned long ); 103 | virtual void tellNoChangeDown( unsigned long ); 104 | virtual void tellChangeUp( unsigned long ); 105 | virtual IOReturn allowPowerChange( unsigned long refcon ); 106 | virtual IOReturn cancelPowerChange( unsigned long refcon ); 107 | virtual void powerChangeDone( unsigned long stateNumber ); 108 | IOService * probe( IOService *provider,SInt32 *score ); 109 | -------------------------------------------------------------------------------- /signatures/IOSharedDataQueue.h: -------------------------------------------------------------------------------- 1 | IOSharedDataQueue * withEntries(UInt32 numEntries, UInt32 entrySize); 2 | IOSharedDataQueue * withCapacity(UInt32 size); 3 | virtual bool setQueueSize(UInt32 size); 4 | virtual void * peek(void); 5 | virtual bool initWithCapacity(UInt32 size); 6 | virtual UInt32 getQueueSize(void); 7 | virtual IOMemoryDescriptor * getMemoryDescriptor(void); 8 | virtual bool enqueue(void *data, UInt32 dataSize); 9 | virtual bool dequeue(void *data, UInt32 *dataSize); 10 | -------------------------------------------------------------------------------- /signatures/IOUserClient.h: -------------------------------------------------------------------------------- 1 | IOReturn releaseAsyncReference64(uint64_t * reference); 2 | void setAsyncReference64(uint64_t * asyncRef, ipc_port * wakePort, mach_vm_address_t callback, uint64_t * refcon, task_t task); 3 | IOReturn releaseNotificationPort( ipc_port * ipc_port); 4 | IOMemoryMap * removeMappingForDescriptor( IOMemoryDescriptor *memory); 5 | IOReturn sendAsyncResult64WithOptions(uint64_t * reference, IOReturn result, uint64_t *args, UInt32 numArgs, IOOptionBits options); 6 | OSObject * copyClientEntitlement(task_t task, const char *entitlement); 7 | virtual kern_return_t Dispatch(const IORPC rpc); 8 | virtual bool init(); 9 | virtual void free(); 10 | virtual const OSMetaClass * getMetaClass(); 11 | virtual bool init_1( OSDictionary * dictionary ); 12 | virtual bool initWithTask(task_t owningTask, void * securityToken, UInt32 type,OSDictionary * properties); 13 | virtual bool initWithTask_1(task_t owningTask, void * securityToken, UInt32 type); 14 | virtual IOReturn clientClose( void ); 15 | virtual IOReturn clientDied( void ); 16 | virtual IOService * getService( void ); 17 | virtual IOReturn registerNotificationPort_1(ipc_port * port, UInt32 type, UInt32 refCon ); 18 | virtual IOReturn getNotificationSemaphore( UInt32 notification_type,void * semaphore ); 19 | virtual IOReturn connectClient( IOUserClient * client ); 20 | virtual IOReturn clientMemoryForType( UInt32 type,IOOptionBits * options,IOMemoryDescriptor ** memory ); 21 | virtual IOReturn exportObjectToClient(task_t task, OSObject *obj, void *clientObj); 22 | virtual IOExternalMethod * getExternalMethodForIndex( UInt32 index ); 23 | virtual IOExternalAsyncMethod * getExternalAsyncMethodForIndex( UInt32 index ); 24 | virtual IOExternalMethod * getTargetAndMethodForIndex( IOService ** targetP, UInt32 index ); 25 | virtual IOExternalAsyncMethod * getAsyncTargetAndMethodForIndex( IOService ** targetP, UInt32 index ); 26 | virtual IOExternalTrap * getExternalTrapForIndex( UInt32 index ); 27 | virtual IOExternalTrap * getTargetAndTrapForIndex( IOService **targetP, UInt32 index ); 28 | virtual IOReturn externalMethod(uint32_t selector, IOExternalMethodArguments *arguments,IOExternalMethodDispatch *dispatch,OSObject *target, void *reference); 29 | virtual IOReturn registerNotificationPort(ipc_port * port, UInt32 type, uint64_t refCon); -------------------------------------------------------------------------------- /signatures/IOWorkLoop.h: -------------------------------------------------------------------------------- 1 | IOWorkLoop * workLoopWithOptions(IOOptionBits options); 2 | IOWorkLoop * workLoop(void); 3 | void threadMainContinuation(IOWorkLoop *self); 4 | virtual IOReturn addEventSource(IOEventSource *newEvent); 5 | virtual void closeGate(void); 6 | virtual void disableAllEventSources(void); 7 | virtual void disableAllInterrupts(void); 8 | virtual void enableAllEventSources(void); 9 | virtual void enableAllInterrupts(void); 10 | virtual bool eventSourcePerformsWork(IOEventSource *inEventSource); 11 | virtual bool inGate(void); 12 | virtual bool init(void); 13 | virtual bool onThread(void); 14 | virtual void openGate(void); 15 | virtual IOReturn removeEventSource(IOEventSource *toRemove); 16 | virtual IOReturn runAction(void *action, void *target, void *arg0, void *arg1, void *arg2, void *arg3); 17 | virtual IOReturn runActionBlock(void * action); 18 | virtual bool runEventSources(void); 19 | virtual void setMaximumLockTime(uint64_t interval, uint32_t options); 20 | virtual void signalWorkAvailable(void); 21 | virtual int sleepGate(void *event, UInt32 interuptibleType); 22 | virtual int sleepGate(void *event, AbsoluteTime deadline, UInt32 interuptibleType); 23 | virtual void threadMain(void); 24 | virtual bool tryCloseGate(void); 25 | virtual void wakeupGate(void *event, bool oneThread); 26 | virtual const OSMetaClass * getMetaClass(); -------------------------------------------------------------------------------- /signatures/OSArray.h: -------------------------------------------------------------------------------- 1 | OSArray * withArray(OSArray *array, uint32_t capacity); 2 | OSArray * withCapacity(uint32_t capacity); 3 | OSArray * withObjects( OSObject **values, uint32_t count, uint32_t capacity); 4 | virtual unsigned int getCapacity(); 5 | virtual unsigned int getCount(); 6 | virtual unsigned int getNextIndexOfObject(void *anObject, unsigned intindex); 7 | virtual OSObject * getObject( unsigned intindex); 8 | virtual bool initWithArray(OSArray *anArray, unsigned int capacity = 0); 9 | virtual bool initWithCapacity( unsigned intcapacity); 10 | virtual bool initWithObjects(OSObject **objects, unsigned int count, unsigned int capacity = 0); 11 | virtual bool isEqualTo(void *anArray); 12 | virtual bool merge(OSArray *otherArray); 13 | virtual void removeObject( unsigned intindex); 14 | virtual void replaceObject( unsigned intindex, void *anObject); 15 | virtual bool serialize( OSSerialize *serializer); 16 | virtual unsigned int setCapacityIncrement( unsigned increment); 17 | virtual bool init(); 18 | virtual void free(); 19 | virtual unsigned int iteratorSize(); 20 | virtual bool initIterator(void * iterator); 21 | virtual bool getNextObjectForIterator(void * iterator, OSObject ** ret); 22 | virtual unsigned int getCapacityIncrement(); 23 | virtual unsigned int setCapacityIncrement(unsigned increment); 24 | void flushCollection(); 25 | virtual unsigned setOptions(unsigned options,unsigned mask,void * context); 26 | OSCollection * copyCollection(OSDictionary * cycleDict); 27 | virtual bool setObject(void *anObject); 28 | virtual bool setObject_1(unsigned int index,const OSMetaClassBase * anObject); 29 | virtual bool isEqualTo_1(const OSArray * anArray); 30 | OSObject * getLastObject(); 31 | virtual const OSMetaClass * getMetaClass(); 32 | virtual unsigned int ensureCapacity(unsigned int newCapacity); 33 | 34 | 35 | -------------------------------------------------------------------------------- /signatures/OSCollection.h: -------------------------------------------------------------------------------- 1 | virtual unsigned int iteratorSize(); 2 | virtual bool initIterator(void * iterationContext); 3 | virtual bool getNextObjectForIterator(void * iterationContext,OSObject ** nextObject); 4 | virtual bool init(); 5 | virtual unsigned int getCount(); 6 | virtual unsigned int getCapacity(); 7 | virtual unsigned int getCapacityIncrement(); 8 | virtual unsigned int setCapacityIncrement(unsigned increment); 9 | virtual unsigned int ensureCapacity(unsigned int newCapacity); 10 | virtual void flushCollection(); 11 | virtual unsigned setOptions(unsigned options,unsigned mask,void * context); 12 | OSCollection * copyCollection(OSDictionary * cycleDict); 13 | virtual const OSMetaClass * getMetaClass(); 14 | virtual bool isEqualTo(OSMetaClassBase *col); 15 | -------------------------------------------------------------------------------- /signatures/OSCollectionIterator.h: -------------------------------------------------------------------------------- 1 | OSCollectionIterator withCollection(void *inColl); 2 | virtual bool initWithCollection(OSCollection *inColl); 3 | virtual void * getNextObject(void); 4 | -------------------------------------------------------------------------------- /signatures/OSData.h: -------------------------------------------------------------------------------- 1 | OSData * withData(OSData *inData, unsigned int start, unsigned int numBytes); 2 | OSData * withData(OSData *inData); 3 | OSData * withCapacity(unsigned int capacity); 4 | OSData * withBytesNoCopy(void *bytes, unsigned int numBytes); 5 | OSData * withBytes(void *bytes, unsigned int numBytes); 6 | virtual bool initWithBytes(void *bytes, unsigned int numBytes); 7 | virtual unsigned int getLength(void); 8 | virtual unsigned int getCapacityIncrement(void); 9 | virtual unsigned int getCapacity(void); 10 | virtual unsigned int ensureCapacity(unsigned int newCapacity); 11 | virtual bool initWithBytesNoCopy(void *bytes, unsigned int numBytes); 12 | virtual bool initWithCapacity(unsigned int capacity); 13 | virtual bool serialize(OSSerialize *serializer); 14 | virtual void free(); 15 | virtual const OSMetaClass * getMetaClass(); 16 | virtual bool initWithData(const OSData * inData); 17 | bool initWithData_1(const OSData *inData,unsigned int start, unsigned int inLength); 18 | virtual unsigned int getLength(); 19 | virtual unsigned int getCapacity(); 20 | virtual unsigned int getCapacityIncrement(); 21 | virtual unsigned int setCapacityIncrement(unsigned increment); 22 | virtual bool appendByte(unsigned char byte, unsigned int numBytes); 23 | virtual bool appendBytes(void *bytes, unsigned int numBytes); 24 | virtual bool appendBytes_1(const OSData * aDataObj); 25 | virtual const void * getBytesNoCopy() 26 | virtual void * getBytesNoCopy_1(unsigned int start, unsigned int numBytes); 27 | virtual bool isEqualTo_1(const OSData * aDataObj); 28 | virtual bool isEqualTo_2(const void * bytes,unsigned int numBytes); 29 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 30 | virtual bool isEqualTo_3(const OSString * aString); 31 | //typedef void (*DeallocFunction)(void * ptr, unsigned int length); 32 | virtual void setDeallocFunction(void * func); 33 | 34 | -------------------------------------------------------------------------------- /signatures/OSDictionary.h: -------------------------------------------------------------------------------- 1 | OSDictionary * withObjects(void **objects,OSString **keys, unsigned int count, unsigned int capacity); 2 | OSDictionary * withCapacity(uint32_t capacity); 3 | OSDictionary * withDictionary(OSDictionary *dict, unsigned int capacity); 4 | virtual bool serialize(OSSerialize *serializer); 5 | virtual bool initWithObjects(OSObject **objects,OSString **keys, unsigned int count, unsigned int capacity = 0); 6 | virtual const OSMetaClass * getMetaClass(); 7 | virtual bool isEqualTo_2(const OSDictionary * aDictionary); 8 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 9 | virtual bool isEqualTo_1(const OSDictionary * aDictionary,const OSCollection * keys); 10 | virtual unsigned setOptions(unsigned options,unsigned mask,void * context); 11 | OSCollection * copyCollection(OSDictionary * cycleDict); 12 | virtual void flushCollection(); 13 | virtual unsigned int ensureCapacity(unsigned int newCapacity); 14 | virtual unsigned int setCapacityIncrement(unsigned increment); 15 | virtual unsigned int getCapacityIncrement(); 16 | virtual unsigned int getCapacity(); 17 | virtual unsigned int getCount(); 18 | virtual void free(); 19 | virtual bool initWithDictionary(const OSDictionary * dict,unsigned int capacity); 20 | virtual bool initWithObjects(void **objects, OSSymbol **keys, unsigned int count, unsigned int capacity); 21 | virtual bool initWithObjects_1(void **objects, OSString **keys, unsigned int count, unsigned int capacity); 22 | virtual unsigned int iteratorSize(); 23 | virtual bool initIterator(void * iterator); 24 | virtual bool getNextObjectForIterator(void * iterator, OSObject ** ret); 25 | virtual bool setObject(const OSSymbol * aKey,const OSMetaClassBase * anObject); 26 | virtual bool setObject_1(OSString *aKey, void *anObject); 27 | virtual bool setObject_2(OSSymbol *aKey, void *anObject); 28 | virtual void removeObject(const OSSymbol *aKey) 29 | virtual void removeObject_1(const OSString *aKey); 30 | virtual void removeObject_2(const char *aKey); 31 | virtual bool merge(const OSDictionary * aDictionary); 32 | virtual OSObject * getObject(const OSSymbol * aKey); 33 | virtual OSObject * getObject_1(const OSString * aKey); 34 | virtual OSObject * getObject_2(const char * aKey); 35 | virtual bool initWithCapacity(unsigned int capacity); -------------------------------------------------------------------------------- /signatures/OSMetaClassBase.h: -------------------------------------------------------------------------------- 1 | virtual void release(int freeWhen); 2 | virtual void taggedRelease(const void * tag, const int freeWhen); 3 | virtual bool init(); 4 | virtual void free(); 5 | virtual int getRetainCount(); 6 | virtual void retain(); 7 | virtual void release_1(); 8 | virtual void taggedRetain(const void * tag); 9 | virtual void taggedRelease_1(const void * tag); 10 | virtual bool serialize(OSSerialize * serializer); 11 | virtual kern_return_t Dispatch(const IORPC rpc); 12 | virtual const OSMetaClass * getMetaClass(); 13 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 14 | -------------------------------------------------------------------------------- /signatures/OSNumber.h: -------------------------------------------------------------------------------- 1 | OSNumber * withNumber(unsigned long long value, unsigned int numberOfBits); 2 | OSNumber * withNumber(char *valueString, unsigned int numberOfBits); 3 | virtual uint16_t unsigned16BitValue(void); 4 | virtual uint32_t unsigned32BitValue(void); 5 | virtual uint64_t unsigned64BitValue(void); 6 | virtual uint8_t unsigned8BitValue(void); 7 | virtual void setValue(unsigned long long value); 8 | virtual bool serialize(OSSerialize *serializer); 9 | virtual unsigned int numberOfBytes(void); 10 | virtual unsigned int numberOfBits(void); 11 | virtual void addValue(long long value); 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /signatures/OSObject.h: -------------------------------------------------------------------------------- 1 | virtual void release(int freeWhen); 2 | virtual void taggedRelease(const void * tag, const int freeWhen); 3 | virtual bool init(); 4 | virtual void free(); 5 | virtual int getRetainCount(); 6 | virtual void retain(); 7 | virtual void release_1(); 8 | virtual void taggedRetain(const void * tag); 9 | virtual void taggedRelease_1(const void * tag); 10 | virtual bool serialize(OSSerialize * serializer); 11 | virtual kern_return_t Dispatch(const IORPC rpc); 12 | virtual const OSMetaClass * getMetaClass(); 13 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 14 | 15 | -------------------------------------------------------------------------------- /signatures/OSSerialize.h: -------------------------------------------------------------------------------- 1 | OSSerialize * binaryWithCapacity(unsigned int inCapacity, void * editor, void *reference); 2 | OSSerialize * withCapacity(unsigned int capacity); 3 | virtual char * text(void); 4 | virtual bool initWithCapacity(unsigned int inCapacity); 5 | virtual void endBinaryCollection(uint32_t startCollection); 6 | virtual void clearText(void); 7 | virtual bool binarySerializeInternal(void *o); 8 | virtual bool addString(char *cString); 9 | virtual bool addBinaryObject(void *o, uint32_t key, void *_bits, size_t size, uint32_t *startCollection); 10 | virtual bool addBinary(void *data, size_t size); 11 | virtual bool previouslySerialized(const OSMetaClassBase *o); 12 | virtual bool addXMLStartTag(const OSMetaClassBase * object,const char * tagString); 13 | virtual bool addXMLEndTag(const char * tagString); 14 | virtual bool addChar(const char aChar); 15 | virtual bool addString(const char * cString); 16 | virtual bool initWithCapacity(unsigned int inCapacity); 17 | virtual unsigned int getLength(); 18 | virtual unsigned int getCapacity(); 19 | virtual unsigned int getCapacityIncrement() ; 20 | virtual unsigned int setCapacityIncrement(unsigned increment); 21 | virtual unsigned int ensureCapacity(unsigned int newCapacity); 22 | virtual void free(); 23 | virtual const OSMetaClass * getMetaClass(); 24 | virtual bool isEqualTo(const OSMetaClassBase * anObject); -------------------------------------------------------------------------------- /signatures/OSSet.h: -------------------------------------------------------------------------------- 1 | OSSet * withArray(OSArray *array, unsigned int capacity); 2 | OSSet * withCapacity(unsigned int capacity); 3 | OSSet * withObjects(OSObject **objects, unsigned int count, unsigned int capacity);; 4 | OSSet * withSet(OSSet *set, unsigned int capacity); 5 | virtual bool setObject(void *anObject); 6 | virtual bool initWithSet(OSSet *set, unsigned int capacity); 7 | virtual bool initWithObjects(OSObject **objects, unsigned int count, unsigned int capacity); 8 | virtual bool initWithCapacity(unsigned int capacity); 9 | virtual bool initWithArray(OSArray *array, unsigned int capacity); 10 | virtual unsigned int ensureCapacity(unsigned int newCapacity); 11 | virtual void flushCollection(void); 12 | virtual unsigned int iteratorSize(); 13 | virtual bool initIterator(void * iterator); 14 | virtual bool getNextObjectForIterator(void * iterator, OSObject ** ret); 15 | virtual void free(); 16 | virtual unsigned int getCapacity(); 17 | virtual unsigned int getCount(); 18 | virtual unsigned int getCapacityIncrement(); 19 | virtual unsigned int setCapacityIncrement(unsigned increment); 20 | OSCollection * copyCollection(OSDictionary * cycleDict); 21 | virtual unsigned setOptions(unsigned options,unsigned mask,void * context); 22 | virtual unsigned int ensureCapacity(unsigned int newCapacity); 23 | virtual bool merge(const OSArray * array); 24 | virtual bool merge_1(const OSSet * set); 25 | virtual void removeObject(const OSMetaClassBase * anObject); 26 | virtual bool containsObject(const OSMetaClassBase * anObject); 27 | virtual bool member(const OSMetaClassBase * anObject); 28 | virtual OSObject * getAnyObject(); 29 | virtual bool isEqualTo_1(const OSSet * aSet); 30 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 31 | virtual bool serialize(OSSerialize * serializer); 32 | virtual const OSMetaClass * getMetaClass(); 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /signatures/OSString.h: -------------------------------------------------------------------------------- 1 | OSString * withCString(char *cString); 2 | OSString * withCStringNoCopy(char *cString); 3 | OSString * withString(OSString *aString); 4 | virtual bool initWithString( OSString *aString); 5 | virtual bool initWithCStringNoCopy( char *cString); 6 | virtual bool initWithCString( char *cString); 7 | virtual unsigned int getLength(void); 8 | virtual char * getCStringNoCopy(void); 9 | virtual bool serialize( OSSerialize *serializer); 10 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 11 | virtual void free(); 12 | virtual unsigned int getLength(void); 13 | virtual bool isEqualTo_1(const OSString * aString); 14 | virtual bool isEqualTo_2(const char * cString); 15 | virtual bool isEqualTo(const OSData * aDataObject); 16 | virtual char getChar(unsigned int index); 17 | virtual bool setChar(char aChar, unsigned int index); 18 | -------------------------------------------------------------------------------- /signatures/OSSymbol.h: -------------------------------------------------------------------------------- 1 | OSSymbol * withString(OSString *aString); 2 | OSSymbol * withCStringNoCopy(char *cString); 3 | OSSymbol * withCString(char *cString); 4 | OSSymbol * existingSymbolForString(OSString *aString); 5 | OSSymbol * existingSymbolForCString(char *aCString); 6 | virtual bool initWithCString( char *cString); 7 | virtual bool initWithCStringNoCopy(char *cString); 8 | virtual bool initWithString(OSString *aString); 9 | virtual bool isEqualTo(const OSMetaClassBase * anObject); 10 | virtual void free(); 11 | virtual unsigned int getLength(void); 12 | virtual bool isEqualTo_1(const OSString * aString); 13 | virtual bool isEqualTo_2(const char * cString); 14 | virtual bool isEqualTo_4(const OSSymbol * aSymbol); 15 | virtual char getChar(unsigned int index); 16 | virtual bool setChar(char aChar, unsigned int index); 17 | virtual void taggedRelease_1(const void * tag,const int freeWhen); 18 | virtual void taggedRelease(const void * tag); 19 | virtual const OSMetaClass * getMetaClass(); 20 | 21 | -------------------------------------------------------------------------------- /signatures/kernel.h: -------------------------------------------------------------------------------- 1 | typedef u64 vm_size_t; 2 | int _memcmp(const void *s1, const void *s2, size_t ssize); 3 | void * _memcpy(void *dst, void *src, size_t ssize); 4 | void * _memmove(void *dst, void *src, size_t ssize); 5 | //void * ___memcpy_chk(void *dst, void *src, size_t ssize,size_t max); 6 | void _IOFreeAligned(void *address, vm_size_t size); 7 | void _IOFree(void *address, vm_size_t size); 8 | void * _IOLockAlloc(void); 9 | void _IOLockFree(void *lock); 10 | void _IOLockLock(void *locks); 11 | void _bzero(void *, size_t); 12 | void * _IOMallocAligned(vm_size_t size, vm_offset_t alignment); 13 | void * _IOMalloc(vm_size_t size); 14 | void * _IOMallocZero(vm_size_t size); 15 | void * _IOMallocData(vm_size_t size); 16 | void _IORecursiveLockUnlock(void *lock); 17 | void _IOLockUnlock(void *lock); 18 | void _IORecursiveLockLock(void *lock); 19 | void _IORWLockRead(void *lock); 20 | void _IORWLockWrite(void *lock); 21 | void _IORWLockUnlock(void *lock); 22 | void * _IOSimpleLockAlloc(void); 23 | void _IOSimpleLockDestroy(void *lock); 24 | void _IOSimpleLockFree(void *lock); 25 | void _IOSimpleLockLock(void *lock); 26 | void _IOSimpleLockInit(void *lock); 27 | void * _IOSimpleLockGetMachLock(void *lock); 28 | uint _IOSimpleLockLockDisableInterrupt(void *lock); 29 | bool _IOSimpleLockTryLock(void *lock); 30 | virtual IOWorkLoop * getWorkLoop(); 31 | virtual IOReturn externalMethod(uint32_t selector, IOExternalMethodArguments *arguments, IOExternalMethodDispatch *dispatch, OSObject *target, void *reference); 32 | virtual IOReturn registerNotificationPort(ipc_port *port, UInt32 type, uint64_t * refCon); 33 | virtual IOReturn clientMemoryForType(UInt32 type, IOOptionBits *options, IOMemoryDescriptor **memory); 34 | virtual IOReturn setProperties(OSDictionary *properties ); 35 | //virtual IOExternalMethod * getTargetAndMethodForIndex(IOService **targetP, UInt32 index) 36 | void * _ptmf2ptf(void *this,void *self, void *func); 37 | int _IORecursiveLockSleep(void *_lock, void *event, UInt32 interType); 38 | void IORecursiveLockWakeup(void *_lock, void *event, bool oneThread); 39 | void * kalloc_canblock (vm_size_t * size, boolean_t canblock, void * site); 40 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0x36/ghidra_kernelcache/b0961b3cdfb96e8b86c89d73fdedf84affc01c77/utils/__init__.py -------------------------------------------------------------------------------- /utils/custom_kc.py: -------------------------------------------------------------------------------- 1 | from helpers import * 2 | from __main__ import * 3 | import logging 4 | from utils.ios_kc import * 5 | from utils.iometa import ParseIOMeta 6 | from kext import * 7 | from iometa import ParseIOMeta 8 | 9 | def create_class_structures(vtab): 10 | pass 11 | 12 | class Custom(kernelCache): 13 | def __init__(self,objects,isKernel=False): 14 | print "Custom Kernel Creation" 15 | kernelCache.__init__(self,objects,macOS=True) 16 | self.sym_project = "macOS11.2.3" 17 | mn,mx = currentProgram.getMinAddress(),currentProgram.getMaxAddress() 18 | self.addrRange = AddressRangeImpl(mn,mx) 19 | self.ns = {} 20 | f = File( currentProgram.getExecutablePath()) 21 | if f.exists() == False: 22 | f = askFile("Could not find the executable path","give a path:") 23 | self.read64 = lambda off: struct.unpack("> 32) & 0xffff 82 | meth_info = self._collect_method_info(cname,addr,None,tag,off) 83 | if meth_info == None: 84 | break 85 | setEOLComment(addr,hex(off)) 86 | methods.append(meth_info) 87 | off+=8 88 | addr = addr.add(8) 89 | 90 | if external == False: 91 | self.vtables[cname].append(methods) 92 | 93 | def _collect_method_info(self,className,addr_ptr,methAddr,tag,offset): 94 | meth = {} 95 | meth["off"] = offset 96 | meth["pac"] = tag 97 | print className,addr_ptr,methAddr 98 | if methAddr == None: 99 | methAddr = getDataAt(addr_ptr) 100 | if methAddr == None: 101 | return None 102 | methAddr = methAddr.getValue() 103 | assert methAddr != None 104 | meth["methodAddr"] = int(methAddr.toString(),16) 105 | 106 | 107 | func = getFunctionAt(methAddr) 108 | signature = None 109 | funcName = None 110 | if func == None : 111 | fixLabel(methAddr) 112 | func = getFunctionAt(methAddr) 113 | if func == None: 114 | return None 115 | 116 | funcName = func.getName(True) 117 | sig = func.getSignature(True) 118 | sg = FunctionDefinitionDataType(sig) 119 | sg.setName(funcName) 120 | signature = sg.getPrototypeString(False) 121 | signature = signature[signature.find(" ")+1:] 122 | if "___cxa_pure_virtual" in signature: 123 | signature = "%s::virtual_method(void)" %(className) 124 | funcName = "%s::virtual_method" 125 | 126 | curr_ns = None 127 | mthod_ns = None 128 | 129 | if self.ns.has_key(className) == True: 130 | curr_ns = self.ns[className] 131 | else: 132 | curr_ns = self.symbolTable.getNamespace(className,None) 133 | self.ns[className] = curr_ns 134 | if curr_ns == None: 135 | curr_ns = self.create_namespace_custom(className) 136 | self.ns[className] = curr_ns 137 | 138 | assert curr_ns != None 139 | try: 140 | x = len(signature.split("::")) 141 | fns = signature.split("::")[x-2:x-1][0] 142 | except: 143 | return None 144 | 145 | if self.ns.has_key(fns) == True: 146 | meth_ns = self.ns[fns] 147 | else: 148 | meth_ns = self.symbolTable.getNamespace(fns,None) 149 | self.ns[fns] = meth_ns 150 | 151 | meth["signature"] = signature 152 | meth["name"] = funcName 153 | if meth_ns == None: 154 | meth["overriden"] = False 155 | return meth 156 | 157 | if curr_ns.toString() == meth_ns.toString(): 158 | meth["overriden"] = True 159 | else : 160 | meth["overriden"] = False 161 | 162 | return meth 163 | 164 | def create_namespace_custom(self,name): 165 | new = self.symbolTable.createNameSpace(None,name,SourceType.USER_DEFINED) 166 | return new 167 | 168 | def prepare_iometa(self): 169 | names = self.vtables.keys() 170 | for name in names: 171 | print name, self.vtables[name] 172 | -------------------------------------------------------------------------------- /utils/helpers.py: -------------------------------------------------------------------------------- 1 | from ghidra.app.services import DataTypeManagerService 2 | from ghidra.program.model.symbol import SourceType,SymbolTable,Namespace,RefType 3 | from ghidra.app.services import BlockModelService 4 | from ghidra.app.cmd.function import ApplyFunctionSignatureCmd 5 | from ghidra.app.decompiler import DecompileOptions,DecompInterface 6 | from ghidra.app.util.cparser.C.CParserUtils import parseSignature,handleParseProblem 7 | from ghidra.program.model.listing import Program, Parameter, ParameterImpl 8 | from ghidra.program.model.data import FunctionDefinition,GenericCallingConvention, \ 9 | ParameterDefinitionImpl 10 | from ghidra.program.model.data import IntegerDataType, StructureDataType, UnsignedLongLongDataType, \ 11 | PointerDataType,FunctionDefinitionDataType,TypedefDataType,VoidDataType 12 | from ghidra.framework.plugintool.util import OptionsService 13 | from ghidra.program.model.listing.Function import FunctionUpdateType 14 | from ghidra.program.model.pcode import PcodeOp,HighFunctionDBUtil 15 | #from ghidra.program.database.function import FunctionManager 16 | from ghidra.app.cmd.function import CreateFunctionCmd 17 | from generic.continues import RethrowContinuesFactory 18 | from ghidra.app.script import GhidraScript 19 | from ghidra.app.util.bin import ByteProvider 20 | from ghidra.app.util.bin import RandomAccessByteProvider 21 | from ghidra.app.util.bin import BinaryReader 22 | from ghidra.app.util.bin.format.macho import MachHeader 23 | from ghidra.app.util.bin.format.macho import Section 24 | from ghidra.app.util.bin.format.macho import commands 25 | from ghidra.program.model.address import Address 26 | from ghidra.program.model.address import AddressRangeImpl 27 | 28 | from java.io import File 29 | from java.io import ByteArrayInputStream; 30 | import struct 31 | 32 | import os,logging 33 | from __main__ import * 34 | 35 | def handle_tagged_pointer(ptr_addr,raw_ptr,className=None): 36 | func = getFunctionContaining(raw_ptr) 37 | if func == None: 38 | print("function is None at 0x%s 0x%s" %(ptr_addr,raw_ptr)) 39 | func = createFunction(raw_ptr,className) 40 | 41 | currentProgram.getReferenceManager().removeAllReferencesFrom(ptr_addr) 42 | ref = currentProgram.getReferenceManager().addMemoryReference(ptr_addr,func.getEntryPoint(), 43 | RefType.COMPUTED_CALL,SourceType.USER_DEFINED,0) 44 | currentProgram.getReferenceManager().setPrimary(ref,True) 45 | 46 | return func 47 | 48 | def get_datatype_manager_by_name(name): 49 | tool = state.getTool() 50 | service = tool.getService(DataTypeManagerService) 51 | dataTypeManagers = service.getDataTypeManagers(); 52 | 53 | for manager in dataTypeManagers: 54 | if manager.name == name: 55 | return manager 56 | 57 | return None 58 | 59 | def get_shared_dt_mgr(name): 60 | tool = state.getTool() 61 | service = tool.getService(DataTypeManagerService) 62 | dataTypeManagers = service.getDataTypeManagers(); 63 | 64 | for manager in dataTypeManagers: 65 | if manager.name == name: 66 | return manager 67 | 68 | return None 69 | 70 | def get_decompiler(): 71 | ifc = DecompInterface() 72 | DecOptions = DecompileOptions() 73 | service = state.getTool().getService(OptionsService) 74 | 75 | opt = service.getOptions("Decompiler") 76 | DecOptions.grabFromToolAndProgram(None, opt, currentProgram) 77 | ifc.setOptions(DecOptions) 78 | 79 | ifc.toggleCCode(True) 80 | ifc.toggleSyntaxTree(True) 81 | ifc.setSimplificationStyle("decompile") 82 | 83 | ifc.openProgram(currentProgram) 84 | return ifc 85 | 86 | def decompile_func(ifc,func): 87 | res = ifc.decompileFunction(func,ifc.options.defaultTimeout,monitor) 88 | if not res.decompileCompleted(): 89 | print res.getErrorMessage() 90 | raise Exception("Decompilation is not completed") 91 | 92 | hfunc = res.getHighFunction() 93 | if hfunc == None: 94 | raise Exception("Cannot get HighFunction") 95 | return hfunc 96 | 97 | def debug_clangLine(lines,linum): 98 | for line in lines: 99 | if line.getLineNumber() != linum: 100 | continue 101 | 102 | print (line) 103 | tokens = line.getAllTokens() 104 | for token in tokens: 105 | print token, type(token),"opcode :", token.getPcodeOp() 106 | 107 | def addTypeDef(name,nametype): 108 | isPtr = False 109 | dtm = currentProgram.getDataTypeManager() 110 | if "*" in nametype: 111 | nametype = nametype.replace("*","") 112 | isPtr = True 113 | 114 | aType = find_dt(nametype) 115 | if aType == None: 116 | return 117 | category = aType.getCategoryPath() 118 | if isPtr: 119 | newtype = TypedefDataType(category,name,PointerDataType(aType),dtm) 120 | else: 121 | newtype = TypedefDataType(category,name,aType,dtm) 122 | 123 | dtm.addDataType(newtype,None) 124 | 125 | def DeclareDataTypes(): 126 | addTypeDef("IOOptionBits","uint") 127 | addTypeDef("UInt32","uint") 128 | addTypeDef("IOReturn","uint") 129 | addTypeDef("IODirection","ulonglong") 130 | addTypeDef("IOVirtualAddress","ulonglong") 131 | addTypeDef("IOByteCount","ulonglong") 132 | #addTypeDef("task","pointer64") 133 | addTypeDef("task","void") 134 | addTypeDef("OSMetaClassBase","ulonglong") 135 | addTypeDef("DestinationOrSource","uint") 136 | addTypeDef("socVersion","uint") 137 | addTypeDef("tUSBHostPortType","uint") 138 | addTypeDef("IOHIDReportType","uint") 139 | addTypeDef("IOReportChannelType","uint") 140 | addTypeDef("tUSBLinkState","uint") 141 | addTypeDef("IO80211LinkState","uint") 142 | addTypeDef("IOMbufServiceClass","ulonglong") 143 | addTypeDef("ChromaOrLuma","uint") 144 | addTypeDef("VerticalOrHorizontal","uint") 145 | addTypeDef("CCTimestamp","uint") 146 | addTypeDef("IORPC","uint") 147 | addTypeDef("IOPhysicalAddress","ulonglong") 148 | addTypeDef("IOAddressSegment","ulonglong") 149 | addTypeDef("IOAddressRange","ulonglong") 150 | addTypeDef("IOByteCount","ulonglong") 151 | addTypeDef("AbsoluteTime","ulonglong") 152 | addTypeDef("IOLock","ulonglong") 153 | addTypeDef("size_t","ulonglong") 154 | addTypeDef("u64","ulonglong") 155 | addTypeDef("ipc_port","ulonglong") 156 | addTypeDef("IOExternalMethodDispatch","void") 157 | addTypeDef("u32","uint") 158 | addTypeDef("IOReturn","uint") 159 | 160 | def get_symbols_of(name): 161 | mgr = currentProgram.getSymbolTable() 162 | return mgr.getSymbols(name) 163 | 164 | # Better Load Them from old projects 165 | def defineIOExternalMethodArguments(): 166 | 167 | dtm = currentProgram.getDataTypeManager() 168 | dt = find_struct("IOExternalMethodArguments") 169 | IOMemoryDescriptor = find_struct("IOMemoryDescriptor") 170 | if IOMemoryDescriptor == None: 171 | IOMemoryDescriptor = dtm.getDataType("/ulonglong") 172 | 173 | new = None 174 | if dt == None: 175 | dt = StructureDataType("IOExternalMethodArguments",0) 176 | new = dt 177 | """ 178 | elif dt.getLength() > 1: 179 | yes = askYesNo("IOExternalMethodArguments", 180 | "[-] Looks like IOExternalMethodArguments is already defined, continue ?") 181 | if yes == False: 182 | exit() 183 | """ 184 | uint = dtm.getDataType("/uint") 185 | ulonglong= dtm.getDataType("/ulonglong") 186 | 187 | st = dt 188 | st.add(uint,"version","") 189 | st.add(uint,"selector","") 190 | 191 | st.add(ulonglong,"asyncWakePort","") 192 | st.add(PointerDataType(uint),"asyncReference","") 193 | st.add(uint,"asyncReferenceCount","") 194 | 195 | st.add(PointerDataType(ulonglong),"scalarInput","") 196 | st.add(uint,"scalarInputCount","") 197 | st.add(PointerDataType(ulonglong),"structureInput","") 198 | st.add(uint,"structureInputSize","") 199 | 200 | st.add(PointerDataType(IOMemoryDescriptor),"StructureInputDescriptor","") 201 | 202 | st.add(PointerDataType(ulonglong),"scalarOutput","") 203 | st.add(uint,"scalarOutputCount","") 204 | 205 | st.add(PointerDataType(ulonglong),"structureOutput","") 206 | st.add(uint,"structureOutputSize","") 207 | 208 | st.add(PointerDataType(IOMemoryDescriptor),"structureOutputDescriptor","") 209 | st.add(uint,"structureOutputDescriptorSize","") 210 | 211 | st.add(uint,"__reservedA","") 212 | st.add(PointerDataType(ulonglong),"structureVariableOutputData","") 213 | #st.setInternallyAligned(True) 214 | if new : 215 | dtm.addDataType(new,None) 216 | dtm.addDataType(PointerDataType(new),None) 217 | 218 | def defineIOExternalTrap(): 219 | dtm = currentProgram.getDataTypeManager() 220 | dt = dtm.findDataType(currentProgram.getName()+ "/"+"IOExternalTrap") 221 | 222 | 223 | uint = dtm.getDataType("/uint") 224 | IOService = dtm.getDataType("/IOService") 225 | IOTrap_def = "IOService::IOTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)" 226 | 227 | fdef = FunctionDefinitionDataType(IOTrap_def) 228 | fdef.setReturnType(uint) 229 | fdef.setGenericCallingConvention(GenericCallingConvention.thiscall) 230 | 231 | st = StructureDataType("IOExternalTrap", 0) 232 | #st.setToMachineAlignment() 233 | st.setExplicitPackingValue(8) 234 | st.setExplicitPackingValue(8) 235 | st.add(PointerDataType(IOService),"object","") 236 | st.add(PointerDataType(fdef),"func","") 237 | 238 | dtm.addDataType(PointerDataType(st),None) 239 | 240 | def defineIOExternalMethod(): 241 | dtm = currentProgram.getDataTypeManager() 242 | dt = dtm.findDataType(currentProgram.getName()+ "/"+"IOExternalMethod") 243 | 244 | IOService = dtm.getDataType("/IOService") 245 | IOMethod_def = "uint IOService::IOMethod(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)" 246 | uint = dtm.getDataType("/uint") 247 | ulonglong= dtm.getDataType("/ulonglong") 248 | 249 | fdef = parseCSignature(IOMethod_def) 250 | st = StructureDataType("IOExternalMethod", 0) 251 | 252 | # st.setToMachineAlignment() 253 | st.setExplicitPackingValue(8) 254 | st.add(PointerDataType(IOService),"object","") 255 | st.add(PointerDataType(fdef),"func","") 256 | st.add(uint,"flags","") 257 | st.add(ulonglong,"count0","") 258 | st.add(ulonglong,"count1","") 259 | 260 | dtm.addDataType(PointerDataType(st),None) 261 | 262 | def defineIOExternalAsyncMethod(): 263 | dtm = currentProgram.getDataTypeManager() 264 | dt = dtm.findDataType(currentProgram.getName()+ "/"+"IOExternalAsyncMethod") 265 | 266 | IOService = dtm.getDataType("/IOService") 267 | IOAsyncMethod_def = "uint IOService::IOAsyncMethod(uint asyncRef[8], void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)" 268 | 269 | uint = dtm.getDataType("/uint") 270 | ulonglong= dtm.getDataType("/ulonglong") 271 | fdef = parseCSignature(IOAsyncMethod_def) 272 | st = StructureDataType("IOExternalAsyncMethod", 0) 273 | 274 | st.setExplicitPackingValue(8) 275 | st.add(PointerDataType(IOService),"object","") 276 | st.add(PointerDataType(fdef),"func","") 277 | st.add(uint,"flags","") 278 | st.add(ulonglong,"count0","") 279 | st.add(ulonglong,"count1","") 280 | 281 | dtm.addDataType(PointerDataType(st),None) 282 | 283 | def fixLabel(data): 284 | name = getSymbolAt(data).getName() 285 | labelAddress = getSymbolAt(data).getAddress() 286 | # ghidra refers to some functions as data, I've seen only one case 287 | labelName = name.replace("LAB_","FUN_") 288 | if disassemble(labelAddress) == False: 289 | popup("This Label "+ labelAddress + "cannot be disassembled !") 290 | return -1 291 | ret = createFunction(labelAddress,labelName) 292 | func = getFunctionAt(labelAddress) 293 | if func == None: 294 | # Calling CreateFunction twice will force function creation 295 | # Don't ask me,ask NSA 296 | ret = createFunction(labelAddress,labelName) 297 | 298 | func = getFunctionAt(labelAddress) 299 | if(func == None): 300 | listing = currentProgram.getListing() 301 | blockModelService = state.getTool().getService(BlockModelService) 302 | cbm = blockModelService.getActiveSubroutineModel() 303 | cbIter = cbm.getCodeBlocksContaining(labelAddress, monitor) 304 | l = labelAddress 305 | currentProgram.getListing().clearCodeUnits(l,l.add(8),True) 306 | createFunction(labelAddress,"FUN_"+name) 307 | 308 | func = getFunctionAt(labelAddress) 309 | if(func == None): 310 | return 311 | func.setCustomVariableStorage(False) 312 | df = FunctionDefinitionDataType(func,False) 313 | 314 | # TODO : remove the below line , no need to change calling convention 315 | #df.setGenericCallingConvention(GenericCallingConvention.thiscall) 316 | df.setReturnType(func.getReturnType()) 317 | 318 | #df = FunctionDefinitionDataType(func,False) 319 | """ 320 | func.replaceParameters(FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS,#CUSTOM_STORAGE, 321 | True, 322 | SourceType.USER_DEFINED, 323 | params) 324 | """ 325 | x = ApplyFunctionSignatureCmd(func.getEntryPoint(),df,SourceType.USER_DEFINED) 326 | x.applyTo(func.getProgram()) 327 | return func 328 | 329 | def defineLabel(symtab,namespace,addr,methodName): 330 | sym = getSymbolAt(addr) 331 | if sym == None: 332 | return 333 | src = sym.getSource() 334 | #The method assumes it's already defined a function 335 | if "FUN_" not in sym.getName(): 336 | return 337 | symtab.createLabel(addr,methodName,namespace,SourceType.ANALYSIS) 338 | 339 | def makePTR(addr): 340 | PTR = currentProgram.getDataTypeManager().getDataType("/pointer") 341 | currentProgram.getListing().createData(addr, PTR) 342 | 343 | def makeUint(addr,comment): 344 | uint_dt = currentProgram.getDataTypeManager().getDataType("/uint") 345 | currentProgram.getListing().createData(addr, uint_dt) 346 | #setEOLComment(addr,comment) 347 | 348 | def makeULongLong(addr,comment= None): 349 | #addr = toAddr(addr) 350 | #uint_dt = currentProgram.getDataTypeManager().getDataType("/ulonglong") 351 | uint_dt = currentProgram.getDataTypeManager().getDataType("/qword") 352 | currentProgram.getListing().createData(addr, uint_dt) 353 | 354 | 355 | def prepareClassName(className,classSize): 356 | locs = ["/","/Demangler/"] 357 | for location in locs: 358 | res = findDataTypeByName(location+className) 359 | if res: 360 | return 361 | 362 | class_struct = StructureDataType(className,0) 363 | currentProgram.getDataTypeManager().addDataType(class_struct,None) 364 | 365 | 366 | def parseCSignature(text): 367 | tool = state.getTool() 368 | service = tool.getService(DataTypeManagerService) 369 | dtm = currentProgram.getDataTypeManager() 370 | df = None 371 | 372 | try: 373 | df =parseSignature(service,currentProgram,text,False) 374 | except ghidra.app.util.cparser.C.ParseException as e: 375 | # Loosy workaround , i will get back to it later 376 | off = text.find("(") 377 | logger.warnign("[!] Please fix the definition of %s" % (text)) 378 | text = text[:off]+"()" 379 | 380 | df = parseSignature(service,currentProgram,text,True) 381 | 382 | 383 | if df == None: 384 | return None 385 | df.setGenericCallingConvention(GenericCallingConvention.thiscall) 386 | 387 | #dtm.addDataType(PointerDataType(df),None) 388 | return df 389 | 390 | def findDataTypeByName(name): 391 | tool = state.getTool() 392 | service = tool.getService(DataTypeManagerService) 393 | dataTypeManagers = service.getDataTypeManagers(); 394 | 395 | for manager in dataTypeManagers: 396 | dataType = manager.getDataType(name) 397 | if dataType : 398 | return dataType 399 | 400 | return None 401 | 402 | def find_struct(name): 403 | return find_dt(name) 404 | 405 | def find_dt(name): 406 | locs = ["/","/Demangler/"] 407 | for location in locs: 408 | dt = findDataTypeByName(location+name) 409 | if dt: 410 | return dt 411 | 412 | return None 413 | 414 | def find_funcdef(name): 415 | dt = findDataTypeByName("/functions/"+name) 416 | if dt : return dt 417 | return findDataTypeByName("/"+name) 418 | 419 | 420 | # Defines some mandatory class structures for the kernelcache 421 | def prepare(): 422 | DeclareDataTypes() 423 | defineIOExternalMethodArguments() 424 | defineIOExternalTrap() 425 | defineIOExternalMethod() 426 | defineIOExternalAsyncMethod() 427 | #currentProgram.getDataTypeManager().endTransaction(tid) 428 | 429 | def setup_logging(name,level=logging.DEBUG): 430 | #symbolTable = currentProgram.getSymbolTable() 431 | #logging.basicConfig(filename='/tmp/debug.log',level=level) 432 | 433 | log = logging.getLogger(name) 434 | log.setLevel(level) 435 | 436 | ch = logging.StreamHandler() 437 | ch.setLevel(level) 438 | #formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s: %(message)s') 439 | formatter = logging.Formatter('%(levelname)s: %(message)s') 440 | ch.setFormatter(formatter) 441 | 442 | log.addHandler(ch) 443 | 444 | return log 445 | -------------------------------------------------------------------------------- /utils/iometa.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | 4 | class ParseIOMeta(object): 5 | def __init__(self,filename): 6 | self.filename = filename 7 | self.data = [] 8 | self.cursor = 0 9 | self.thisObject = "" # current Object Name 10 | self.thisMethodsTable = [] # Hold a list of MethodInfo dictionary 11 | # Holds full information {"thisObject" : ..... } 12 | self.Objects = {} 13 | 14 | self.parseObjects() 15 | 16 | def _getObjectHead(self): 17 | for line in self.data: 18 | if "vtab=" in line: # means a new object to be parsed 19 | # save self.thisMethodsTable to the previous object 20 | if len(self.thisMethodsTable) != 0: 21 | self.Objects[self.thisObject].append(self.thisMethodsTable) # Takes index 1 22 | self.thisMethodsTable = [] 23 | self.thisObject = "" 24 | 25 | self._parseVtableInfo() 26 | self.cursor += 1 27 | continue 28 | 29 | self._parseMethod() 30 | self.cursor += 1 31 | 32 | # the last one must be added as well 33 | if len(self.thisMethodsTable) != 0: 34 | self.Objects[self.thisObject].append(self.thisMethodsTable) # Takes index 1 35 | self.thisMethodsTable = [] 36 | self.thisObject = "" 37 | 38 | def _printMethod(self,methodDict,overridenOnly=False): 39 | fmt = "0x%x func=0x%lx overrides=0x%lx pac=0x%x %s" 40 | m = methodDict 41 | if overridenOnly == True and m['methodAddr'] != m['overrides']: 42 | print( "OVERRIDEN: ", fmt %(m['off'],m['methodAddr'],m['overrides'],m['pac'],m['name'])) 43 | elif overridenOnly == False: 44 | print(fmt %(m['off'],m['methodAddr'],m['overrides'],m['pac'],m['name'])) 45 | 46 | def printAll(self,overriden=False): 47 | for className,infos in self.Objects.items(): 48 | if len(infos) != 2: 49 | continue 50 | classInfo,methodsInfo = infos[0],infos[1] 51 | classInfo,methodsInfo = infos[0],infos[1] 52 | for methodInfo in methodsInfo: 53 | self._printMethod(methodInfo,overriden) 54 | 55 | def _resolveSymbolName(self,stringName): 56 | name = stringName 57 | if "(" in name: 58 | name = name.split("(")[0] 59 | return name 60 | 61 | 62 | def _parseMethod(self): 63 | line = self.data[self.cursor] 64 | if len(line) == 0: 65 | return 66 | pattern = ".*(\S+)\W+func=(\S+)\W+overrides=(\S+)\W+pac=(\S+)\W+(\S+\(.*\))" 67 | match = re.search(pattern,line) 68 | 69 | idx = line.find("pac=") 70 | idx+= line[idx:].find(" ") 71 | signature = line[idx+1:] 72 | if match == None or len(match.groups()) < 5: 73 | raise Exception("Failed to parse RE") 74 | 75 | off = int(match.group(1),16) 76 | methodAddr = int(match.group(2),16) 77 | overrides = int(match.group(3),16) 78 | pac = int(match.group(4),16) 79 | signature = match.group(5) 80 | 81 | methodName = self._resolveSymbolName(signature) # to be fixed later 82 | 83 | thisMethodDict = { 84 | "name": methodName, 85 | "off" : off, 86 | "methodAddr": methodAddr, 87 | "overriden" : methodAddr != overrides, 88 | "overrides" : overrides, 89 | "pac" : pac, 90 | "signature" : signature 91 | } 92 | 93 | self.thisMethodsTable.append(thisMethodDict) 94 | 95 | def getObjectInfoByName(self,className): 96 | classesIter = self.Objects.keys() 97 | if className not in classesIter: 98 | return 99 | 100 | return self.Objects[className] 101 | 102 | 103 | def printOverridenMethodsByClassName(self,className): 104 | 105 | infos = self.getObjectInfoByName(className) 106 | if len(infos) != 2: 107 | return 108 | 109 | classInfo,methodsInfo = infos[0],infos[1] 110 | for method in methodsInfo: 111 | self._printMethod(method,overridenOnly=True) 112 | 113 | 114 | def printOverridenMethodsByBundle(self,bundle): 115 | classes = [] 116 | for name,infos in self.Objects.items(): 117 | classInfo = infos[0] 118 | if bundle in classInfo['bundle']: 119 | classes.append(name) 120 | 121 | if len(classes) == 0: 122 | print( "[-] %s is invalid" %(bundle)) 123 | return 124 | 125 | for className in classes: 126 | self.printOverridenMethodsByClassName(className) 127 | 128 | 129 | def _parseVtableInfo(self): 130 | c = self.cursor 131 | line = self.data[c] 132 | 133 | pattern = "^vtab=(\S+)\W+size=(\S+)\W+meta=(\S+)\W+parent=(\S+)\W+metavtab=(\S+)\W+(\S+)\W+\((\S+)\)$" 134 | match = re.search(pattern, line) 135 | if match == None or len(match.groups()) != 7 : 136 | raise Exception ("Failed to parse vtable infos") 137 | 138 | try: 139 | vtab = int(match.group(1),16) 140 | except: 141 | #print("[-] Please go and remove '%s' line from iometa output and repeat " 142 | # %(match.group(1))) 143 | return 144 | size = int(match.group(2),16) 145 | meta = int(match.group(3),16) 146 | parent =int(match.group(4),16) 147 | metavtab = int(match.group(5),16) 148 | className = match.group(6) 149 | bundle = match.group(7) 150 | self.thisObject = className 151 | 152 | objectInfoDict = { 153 | "className": self.thisObject, 154 | "vtab" : vtab, 155 | "size" : size, 156 | "meta" : meta, 157 | "parent": parent, 158 | "metavtab" : metavtab, 159 | "bundle" : bundle 160 | } 161 | self.Objects[self.thisObject] = [objectInfoDict] 162 | 163 | def parseObjects(self): 164 | self.f = open(self.filename) 165 | self.data = self.f.read().split("\n") 166 | self._getObjectHead() 167 | 168 | def getObjects(self): 169 | return self.Objects 170 | 171 | def saveObject(self,name): 172 | print( "[+] Save symbol database in %s" %(name)) 173 | handle = open('%s' %(name), 'wb') 174 | pickle.dump(self.Objects, handle, protocol=pickle.HIGHEST_PROTOCOL) 175 | 176 | if __name__ == "__main__": 177 | 178 | if len(sys.argv) != 3: 179 | print( "%s " %(sys.argv[0])) 180 | sys.exit(-1) 181 | 182 | fIn = sys.argv[1] 183 | fOut = sys.argv[2] 184 | 185 | v = ParseIOMeta(fIn) 186 | v.saveObject(fOut) 187 | v = ParseIOMeta("kernel_iphoneX_12.1.2_16C104.syms") 188 | v.saveObject('kernel_iphoneX_12.1.2_16C104') 189 | 190 | """ 191 | v.printOverridenMethodsByClassName("IOStream") 192 | v.printOverridenMethodsByBundle("__kernel__") 193 | v.printAll(True) 194 | print v.Objects 195 | 196 | 197 | 198 | 199 | v = ParseIOMeta("/Users/mg/ghidra_ios/test.syms") 200 | """ 201 | -------------------------------------------------------------------------------- /utils/ios_kc.py: -------------------------------------------------------------------------------- 1 | from helpers import * 2 | from __main__ import * 3 | from methods import * 4 | 5 | from ghidra.program.model.data import DataTypeConflictHandler 6 | 7 | class kernelCache(object): 8 | def __init__(self,objects,macOS=False): 9 | self.objects = objects 10 | self.macOS = macOS 11 | if self.macOS == False: 12 | del self.objects["OSKext"] 13 | self.log = setup_logging("kernelcache") 14 | self.symbolTable = currentProgram.getSymbolTable() 15 | self.listing = currentProgram.getListing() 16 | self.refMgr = currentProgram.getReferenceManager() 17 | 18 | OSMetaClassBase = find_struct("OSMetaClassBase") 19 | if OSMetaClassBase == None: 20 | OSMetaClassBase = StructureDataType("OSMetaClassBase",0) 21 | namespace = self.symbolTable.getNamespace("OSMetaClassBase",None) 22 | 23 | if namespace == None: 24 | namespace = self.symbolTable.createClass(None,"OSMetaClassBase",SourceType.USER_DEFINED) 25 | 26 | mn,mx = currentProgram.getMinAddress(),currentProgram.getMaxAddress() 27 | self.memRange = AddressRangeImpl(mn,mx) 28 | 29 | def process_classes_for_bundle(self,bundle_str): 30 | names = self.get_classes_by_bundle(bundle_str) 31 | for name in names: 32 | self._process_class(name) 33 | 34 | for name in names: 35 | kernelCacheClass(self.objects[name],False,self.macOS) 36 | 37 | 38 | def process_classes(self,names): 39 | for name in names: 40 | self._process_class(name) 41 | for name in names: 42 | kernelCacheClass(self.objects[name],False,self.macOS) 43 | 44 | # Construct every class found in objects 45 | def process_all_classes(self): 46 | names = self.objects.keys() 47 | for name in names: 48 | self._process_class(name) 49 | for name in names: 50 | kernelCacheClass(self.objects[name],False,self.macOS) 51 | 52 | def process_class(self,className): 53 | self._process_class(className,True) 54 | 55 | def _process_class(self,className,single=False): 56 | classInfo = self.objects[className][0] 57 | parent = self.create_parent_class(classInfo) 58 | ret = self.create_class_structures(classInfo,parent) 59 | # if the structures already defined, return 60 | if ret == None: 61 | return 62 | if parent == None: 63 | # Needs to be tested 64 | #kernelCacheClass(self.objects[className]) 65 | return 66 | 67 | pclassName,pclassSize = parent['className'], parent['size'] 68 | pclassMembers = find_struct(pclassName+"_members") 69 | classMembers = find_struct(className+"_members") 70 | 71 | class_struct = find_struct(className) 72 | pclass_struct = find_struct(pclassName) 73 | 74 | if pclassMembers == None or classMembers == None: 75 | msg = "Fatal: Could not get %s_members or %s_members" %(className,pclassName) 76 | raise Exception(msg) 77 | 78 | pnamespace = self.symbolTable.getNamespace(pclassName,None) 79 | namespace = self.symbolTable.getNamespace(className,None) 80 | if namespace == None or pnamespace == None: 81 | raise Exception("%s's Namespace not found " %(pnamespace)) 82 | 83 | # namespace.setParentNamespace(pnamespace) 84 | # some classes are there but without vtable 85 | if len(self.objects[className]) != 2: 86 | return 87 | if single == True: 88 | kernelCacheClass(self.objects[className],False,self.macOS) 89 | 90 | def update_class(self,name,obj): 91 | # tbd 92 | pass 93 | 94 | 95 | def remove_classes(self): 96 | names = self.objects.keys() 97 | for name in names: 98 | struc = find_struct(name) 99 | if struc == None: 100 | return 101 | 102 | struc.deleteAll() # clear all old vtable fields 103 | 104 | def update_classes_vtable(self): 105 | names = self.objects.keys() 106 | for name in names: 107 | vtable = find_struct(name+"_vtable") 108 | if vtable == None: 109 | return 110 | 111 | vtable.deleteAll() # clear all old vtable fields 112 | kernelCacheClass(self.objects[name],True,self.macOS) 113 | 114 | # Clears the content of the class structures (vtables are excluded) 115 | def clear_class_structures(self): 116 | names = self.objects.keys() 117 | for name in names: 118 | class_member = find_struct(name+"_members") 119 | class_struct = find_struct(name) 120 | 121 | if class_member: 122 | class_member.deleteAll() 123 | if class_struct: 124 | class_struct.deleteAll() 125 | 126 | def get_classes_by_bundle(self,bundle): 127 | l = [] 128 | names = self.objects.keys() 129 | for name in names: 130 | if self.objects[name][0]["bundle"] == bundle: 131 | l.append(name) 132 | return l 133 | 134 | def fix_kernelcache(self): 135 | names = self.objects.keys() 136 | for name in names: 137 | if len(self.objects[name]) < 2: 138 | return 139 | kernelCacheClass(self.objects[name],self.macOS) 140 | 141 | 142 | def get_class_parent(self,classInfo): 143 | parent = classInfo["parent"] 144 | name = classInfo["className"] 145 | cs = self.objects.keys() 146 | for c in cs: 147 | obj = self.objects[c] 148 | if obj[0]['meta'] == parent: 149 | return obj[0] 150 | return None 151 | 152 | def create_parent_class(self,classInfo): 153 | namespace = self.symbolTable.getNamespace(classInfo['className'],None) 154 | if namespace == None: 155 | namespace = self.symbolTable.createClass(None,classInfo['className'],SourceType.USER_DEFINED) 156 | parent = self.get_class_parent(classInfo) 157 | if parent == None: 158 | return None 159 | 160 | self._process_class(parent['className']) 161 | #self.create_class_structures(parent,None) 162 | return parent 163 | 164 | def create_class_structures(self,classInfo,classInfoParent): 165 | className,classSize = classInfo['className'], classInfo['size'] 166 | class_struct = None 167 | class_members = None 168 | 169 | find_cs = find_struct(className) 170 | find_cm = find_struct(className + "_members") 171 | find_vt = find_struct(className + "_vtable") 172 | 173 | pclass_struct = None 174 | if classInfoParent != None: 175 | pclassName, pclassSize = classInfoParent["className"] , classInfoParent["size"] 176 | pclass_struct = find_struct(pclassName) 177 | if find_cm and find_cs and find_vt: 178 | #print "[!] %s class structures already defined" %(className) 179 | return None 180 | 181 | sz = 0 182 | if find_cm == None and find_vt == None: 183 | class_vtable = StructureDataType(className+"_vtable",0) 184 | if pclass_struct == None: 185 | class_members = StructureDataType(className+"_members",classSize - 8) 186 | else: 187 | sz = classSize - pclass_struct.length 188 | if( sz < 0): 189 | self.log.error("Could not have negative size %d of %s parent=%s" 190 | %(sz,className,pclassName)) 191 | sz = classSize + pclass_struct.length 192 | 193 | class_members = StructureDataType(className+"_members",sz) 194 | 195 | elif find_vt == None and find_cm != None: 196 | class_vtable = StructureDataType(className+"_vtable",0) 197 | class_members = find_cm 198 | 199 | elif find_vt != None and find_cm == None: 200 | print "BAD ",className 201 | assert(1==0) 202 | 203 | else: 204 | 205 | class_members = find_cm 206 | class_vtable = find_vt 207 | 208 | if find_cs == None: 209 | class_struct = StructureDataType(className,0) 210 | else: 211 | class_struct = find_cs 212 | 213 | #class_struct.setPackingValue(8) 214 | class_struct.setExplicitPackingValue(8) 215 | class_struct.add(PointerDataType(class_vtable),0,"vtable","") 216 | if pclass_struct == None: 217 | class_struct.insertAtOffset(8,class_members,classSize - 8,"m_"+className+"","") 218 | 219 | else: 220 | comps = pclass_struct.getComponents() 221 | num = pclass_struct.getNumComponents() 222 | s = 8 223 | for i in range(1,num): 224 | c = pclass_struct.getComponent(i) 225 | cdt = c.getDataType() 226 | cn = c.getFieldName() 227 | cz = c.getLength() 228 | class_struct.insertAtOffset(s,cdt,cz,cn,"") 229 | s += cz 230 | 231 | # we cannot pass 0 size structure 232 | if sz != 0: 233 | class_struct.insertAtOffset(s,class_members,0,"m_"+className+"","") 234 | #class_struct.insertAtOffset(s,class_members,0,className+"","") 235 | 236 | if find_cm == None: 237 | currentProgram.getDataTypeManager().addDataType(class_members,None) 238 | currentProgram.getDataTypeManager().addDataType(class_vtable,None) 239 | 240 | if find_cs == None: 241 | currentProgram.getDataTypeManager().addDataType(class_struct,None) 242 | return class_struct 243 | 244 | def _pac_prepare_methods(self): 245 | print("[+] Sorting PACs ... ") 246 | self.pac_dict = {} 247 | obj = self.objects 248 | get_methods = lambda key,obj: obj[key][1] 249 | 250 | for k in obj.keys(): 251 | if len(obj[k]) < 2: 252 | continue 253 | l = get_methods(k,obj) 254 | for method in l: 255 | pac = method['pac'] 256 | if self.pac_dict.has_key(pac) == True: 257 | if self.has_method(method['signature'],pac) == True: 258 | continue 259 | 260 | self.pac_dict[pac].append(method) 261 | else: 262 | self.pac_dict[pac] = [method] 263 | 264 | 265 | def has_method(self,signature,pac): 266 | for mm in self.pac_dict[pac]: 267 | if signature == mm['signature']: 268 | return True 269 | 270 | return False 271 | 272 | def _find_movk_instr(self): 273 | print("[+] Searching for MOVK instructions") 274 | instrs = self.listing.getInstructions(currentProgram.getImageBase(),True) 275 | 276 | movks = [] 277 | for ins in instrs: 278 | if ins.getMnemonicString() != "movk": 279 | continue 280 | ins_addr = ins.getAddress() 281 | pac_val = ins.getOpObjects(1)[0] 282 | pac_val = int(pac_val.getValue()) 283 | if self.pac_dict.has_key(pac_val) == False: 284 | continue 285 | movks.append((ins,pac_val)) 286 | self.movks = movks 287 | return self.movks 288 | 289 | def add_mem_ref(self,ins,pac): 290 | ll = self.pac_dict[pac] 291 | # Filter out the unecessary calls 292 | if len(ll) > 50: 293 | return 294 | 295 | self.refMgr.removeAllReferencesFrom(ins.getAddress()) 296 | 297 | for meth in ll: 298 | methAddr = meth['methodAddr'] 299 | # This means the address is exteranal 300 | if methAddr == 0 or self.memRange.contains(toAddr(hex(methAddr).replace("L",""))) == False: 301 | m = meth["name"] 302 | if ("::" in m) == False: 303 | return 304 | ns,name = m.split("::") 305 | syms = currentProgram.getSymbolTable().getSymbols(name) 306 | for s in syms: 307 | fname = s.getName(True) 308 | if fname != m: 309 | continue 310 | methAddr = int(s.getAddress().toString(),16) 311 | methAddr = hex(methAddr).replace("L","") 312 | 313 | print "[+] Found a reference for 0x%s with pac=0x%x,%s" %(ins.getAddress().toString(),pac,methAddr) 314 | self.refMgr.addMemoryReference(ins.getAddress(), 315 | toAddr(methAddr), 316 | RefType.COMPUTED_CALL, 317 | SourceType.USER_DEFINED, 0) 318 | return 319 | 320 | methAddr = hex(methAddr).replace("L","") 321 | 322 | print "[+] Found a reference for 0x%s with pac=0x%x,%s" \ 323 | %(ins.getAddress().toString(),pac,methAddr) 324 | self.refMgr.addMemoryReference(ins.getAddress(),toAddr(methAddr),RefType.COMPUTED_CALL, SourceType.USER_DEFINED, 0) 325 | 326 | def _resolve_refs(self): 327 | print("[+] Resolving PAC references ...") 328 | for t in self.movks: 329 | # Look for blraa/braa instructions 330 | ins,pac = t 331 | for i in range(100): 332 | ins = ins.getNext() 333 | if ins == None: 334 | break 335 | if ins.getMnemonicString() != "blraa" and ins.getMnemonicString() != "braa": 336 | continue 337 | self.add_mem_ref(ins,pac) 338 | break 339 | 340 | 341 | def explore_pac(self): 342 | self._pac_prepare_methods() 343 | movks = self._find_movk_instr() 344 | self._resolve_refs() 345 | 346 | 347 | fdefs = {} 348 | class kernelCacheClass(object): 349 | def __init__(self,infos,update=False,macOS=False): 350 | if len(infos) < 2: 351 | return 352 | self.macOS = macOS 353 | classInfo , methodsInfo = infos 354 | addr = classInfo['vtab'] 355 | name = classInfo['className'] 356 | size = classInfo['size'] 357 | bundle = classInfo['bundle']#[:-1] 358 | print "[+] Processing %s class with vtab=0x%lx" %(name,addr) 359 | 360 | self.start = addr 361 | self.className = name 362 | self.classSize = size 363 | self.classBundle = bundle 364 | self.methodsInfo = methodsInfo 365 | self.SymVtable = toAddr(hex(addr).replace("L","")) 366 | self.update = update 367 | self.class_struct = None 368 | self.vtable_struct = None 369 | self.refMgr = currentProgram.getReferenceManager() 370 | 371 | self.end = 0 # tbd 372 | self.dtm = currentProgram.getDataTypeManager() 373 | self.listing = currentProgram.getListing() 374 | self.symbolTable = currentProgram.getSymbolTable() 375 | self.bookmark = currentProgram.getBookmarkManager() 376 | self.tool = state.getTool() 377 | self.service = self.tool.getService(DataTypeManagerService) 378 | self.namespace = None 379 | # fast namesapce lookups 380 | self.namespaces = {} 381 | self.currentProgram = currentProgram 382 | self.decompiler = None #get_decompiler() 383 | self.log = setup_logging("kernelcache") 384 | self.pointer = self.dtm.getDataType("/pointer64") 385 | if self.pointer == None: 386 | self.pointer = self.dtm.getDataType("/pointer") 387 | self.void = self.dtm.findDataType("/void") 388 | 389 | self.renameTable() 390 | self.fixMethoTable() 391 | self.defineObjects() 392 | if self.decompiler != None: 393 | self.decompiler.dispose() 394 | 395 | def renameTable(self): 396 | """ 397 | Assign a name of 'object_vtable' label to the virtual table 398 | """ 399 | self.setBookmark() 400 | sym = getSymbolAt(self.SymVtable) 401 | if sym == None: 402 | createLabel(self.SymVtable,self.className+"_vtable",False) 403 | return 0 404 | 405 | sym.setName(self.className+"_vtable",SourceType.USER_DEFINED) 406 | return 0 407 | 408 | def fixMethoTable(self): 409 | """ 410 | Fix Method table by making each entry as a pointer 411 | Get the start/end of the vtable 412 | """ 413 | add = self.start 414 | self.end = self.start 415 | i = 0 416 | off = 0 417 | while True: 418 | Addr = toAddr(hex(add).replace("L","")) 419 | data = self._fixAndGetData(Addr) 420 | value = data.getValue() 421 | # if the pointer is NULL, we may have reached the end of the vtable 422 | v = int(value.toString(),16) & 0xfffffffffff00000 423 | if v == 0 or v == 0xfffffffffff00000 : 424 | self.end = add 425 | break 426 | 427 | setEOLComment(Addr,"0x%x"%(off)) 428 | function = getFunctionAt(value) 429 | if function == None: 430 | if self.macOS == True: 431 | pass 432 | else: 433 | fixLabel(value) 434 | 435 | off+=8 436 | add+=8 437 | 438 | # define the class and the virtual table objects 439 | def defineObjects(self): 440 | self._getClassName() 441 | self._getClassNamespace() 442 | self._getVtableStruct() 443 | self._defineVtable() 444 | 445 | def _getVtableStruct(self): 446 | self.classNameVtable = self.className + "_vtable" 447 | self.vtable_struct = find_struct(self.classNameVtable) 448 | 449 | assert(self.vtable_struct != None) 450 | 451 | return self.vtable_struct 452 | 453 | def _defineVtable(self): 454 | 455 | constructor = self.methodsInfo[0] 456 | try: 457 | className,methName = constructor['name'].split("::") 458 | except: 459 | className,methName,_ = constructor['name'].split("::") 460 | 461 | self.methodsInfo[0]["name"] = className + "::constructor_" + className 462 | self.methodsInfo[1]["name"] = className + "::destructor_" + className 463 | self.methodsInfo[0]["signature"] = className + "::cst_" + className +"()" 464 | self.methodsInfo[1]["signature"] = className + "::dst_" + className +"()" 465 | i = 1 466 | meths = {} 467 | for method in self.methodsInfo: 468 | if len(method['name']) == 0: 469 | continue 470 | methName = method['name'].split("::")[1] 471 | methAddr = toAddr(hex(method['methodAddr'])[:-1]) 472 | 473 | # working with C++ function overload 474 | if meths.has_key(methName) == True: 475 | meths[methName] += 1 476 | old = methName 477 | methName = methName + "_%d" %(meths[methName]) 478 | method['name'] = method['name'].replace(old,methName) 479 | method['signature'] = method['signature'].replace(old,methName) 480 | else: 481 | meths[methName] = 0 482 | 483 | # Ghidra doesnt like const keyword 484 | funcDef = self.prepareSignature(method) 485 | assert(funcDef) 486 | name = funcDef.getDisplayName() 487 | ret = self.vtable_struct.add(PointerDataType(funcDef), methName, "") 488 | 489 | def setCustomFunctionDefinition(self,name,addr,namespace,text): 490 | if addr.toString() == "ffffffffffffffff": 491 | funcDef = FunctionDefinitionDataType(namespace.getName()+"::"+name) 492 | return funcDef 493 | 494 | func = getFunctionAt(addr) 495 | if func == None: 496 | func = fixLabel(addr) 497 | 498 | if func == None: 499 | msg = "Unable to get function at %s, please undo, then manually create that function (type 'f'), save, then launch ghidra_kernelcache again" %(addr) 500 | raise Exception(msg ) 501 | #return None 502 | 503 | func.setName(name,SourceType.USER_DEFINED) 504 | if namespace != None: 505 | func.setParentNamespace(namespace) 506 | func.setCustomVariableStorage(False) 507 | 508 | count = func.getParameterCount() 509 | if count == 0: 510 | if self.decompiler == None: 511 | self.decompiler = get_decompiler() 512 | try: 513 | hfunc = decompile_func(self.decompiler,func) 514 | HighFunctionDBUtil.commitParamsToDatabase(hfunc,True,SourceType.USER_DEFINED) 515 | except: 516 | pass 517 | 518 | if func.getParameterCount() != 0: 519 | func.removeParameter(0) 520 | 521 | #func.setCustomVariableStorage(False) 522 | func.setCallingConvention("__thiscall") 523 | funcName = func.getName(True) 524 | funcDef = FunctionDefinitionDataType(func,True) 525 | funcDef.setName(funcName) 526 | return funcDef 527 | 528 | # Make the content of addr as a pointer 529 | def _makePTR(self,addr): 530 | try: 531 | self.listing.createData(addr, self.pointer) 532 | except: 533 | self.listing.clearCodeUnits(addr,addr.add(8),False) 534 | self.listing.createData(addr, self.pointer) 535 | 536 | 537 | def _fixAndGetData(self,Addr): 538 | data =getDataAt(Addr) 539 | # GHIDRA somehow fails to identify some methods 540 | if data == None or data.pointer == False: 541 | self._makePTR(Addr) 542 | data = getDataAt(Addr) 543 | return data 544 | 545 | # returns a class (create it if not found) 546 | def _getClassNamespace(self): 547 | self.namespace = self.symbolTable.getNamespace(self.className,None) 548 | assert(self.namespace != None) 549 | return self.namespace 550 | 551 | def _getClassName(self): 552 | if self.class_struct: 553 | return self.class_struct 554 | self.class_struct = find_struct(self.className) 555 | assert(self.class_struct != None) 556 | 557 | return self.class_struct 558 | 559 | def setBookmark(self): 560 | bookmarks = self.bookmark.getBookmarks(self.SymVtable,"iOS") 561 | for bookmark in bookmarks: 562 | self.bookmark.removeBookmark(bookmark) 563 | self.bookmark.setBookmark(self.SymVtable,"iOS",None,self.classBundle) 564 | 565 | def prepareSignature(self,method): 566 | return self.parseCSignature(method) 567 | 568 | # Returns a function definition for the current method 569 | # Or Creates a new one if not found 570 | def parseCSignature(self,method): 571 | 572 | #text = "undefined4 "+ method["signature"] #.split("::")[1] 573 | #text = text.replace("const","") 574 | 575 | full_name = method['name'] 576 | nn = full_name.split("::") 577 | if len(nn) == 2: 578 | methNS,methName = nn[0] , nn[1] 579 | elif len(nn) == 3: 580 | methNS,methName = nn[0] , nn[1]+"::" +nn[2] 581 | 582 | methAddr = toAddr(hex(method['methodAddr'])[:-1]) 583 | func = None 584 | if methAddr != None: 585 | func = getFunctionAt(methAddr) 586 | 587 | if func == None: 588 | text = "undefined4 "+ method["signature"] #.split("::")[1] 589 | text = text.replace("const","") 590 | else: 591 | rett = func.getReturnType().getName() 592 | text = rett +" "+ method["signature"] #.split("::")[1] 593 | text = text.replace("const","") 594 | 595 | if method['overriden'] == True: 596 | namespace = self.namespace 597 | else: 598 | if self.namespaces.has_key(methNS): 599 | namespace = self.namespaces[methNS] 600 | else: 601 | namespace = self.symbolTable.getNamespace(methNS,None) 602 | self.namespaces[methNS] = namespace 603 | 604 | assert(namespace != None) 605 | new = False 606 | if self.isUnknownMethod(methName) == False: 607 | try: 608 | df = None 609 | if fdefs.has_key(full_name) == True: 610 | df = fdefs[full_name] 611 | return df 612 | 613 | df = parseSignature(self.service,self.currentProgram,text,False) 614 | new = True 615 | 616 | assert(df != None) 617 | if self.macOS == True and methAddr == None: 618 | name = method['name'] 619 | fdd = find_funcdef(name) 620 | assert(fdd != None) 621 | return fdd 622 | 623 | func = getFunctionAt(methAddr) 624 | # pure virtual method 625 | if func == None: 626 | return df 627 | src = func.getSymbol().getSource() 628 | 629 | # BROKEN: more testing on this condition 630 | #if src == SourceType.USER_DEFINED and self.update == False: 631 | # #raise Exception(func) 632 | # return df 633 | 634 | df.setGenericCallingConvention(GenericCallingConvention.thiscall) 635 | df.setReturnType(func.getReturnType()) 636 | 637 | func.setCustomVariableStorage(False) 638 | func.setParentNamespace(namespace) 639 | 640 | cmd = ApplyFunctionSignatureCmd(func.getEntryPoint(),df,SourceType.USER_DEFINED) 641 | cmd.applyTo(func.getProgram()) 642 | func.setName(methName,SourceType.USER_DEFINED) 643 | except ghidra.app.util.cparser.C.ParseException as e: 644 | # Ghidra is unable to parse this signature 645 | # Put the original definition above, so the user will manually handle it 646 | setPlateComment(methAddr,text) 647 | df = self.setCustomFunctionDefinition(methName,methAddr,namespace,text) 648 | else: 649 | if fdefs.has_key(full_name) == True: 650 | df = fdefs[full_name] 651 | return df 652 | 653 | df = self.setCustomFunctionDefinition(methName,methAddr,namespace,text) 654 | new = True 655 | 656 | #insert 'this' pointer at the begining of the parameters 657 | args = df.getArguments() 658 | this = ParameterDefinitionImpl("this",PointerDataType(self.void),"") 659 | args.insert(0,this) 660 | df.setArguments(args) 661 | func = getFunctionAt(methAddr) 662 | if func != None: 663 | df.setReturnType(func.getReturnType()) 664 | # Needs to be tested 665 | if self.update == True: 666 | raise Exception("Broken : Please don't enable it") 667 | else: 668 | df = self.dtm.addDataType(df,None) 669 | fdefs[full_name] = df 670 | plate = getPlateComment(methAddr) 671 | if plate == None: 672 | setPlateComment(methAddr,text) 673 | 674 | return df 675 | 676 | def isUnknownMethod(self,method_name): 677 | if "fn_0x" in method_name: 678 | return True 679 | 680 | return False 681 | 682 | -------------------------------------------------------------------------------- /utils/kext.py: -------------------------------------------------------------------------------- 1 | from helpers import * 2 | from __main__ import * 3 | import logging 4 | from iometa import ParseIOMeta 5 | 6 | from ghidra.program.model.data import DataTypeConflictHandler 7 | from ios_kc import * 8 | 9 | 10 | 11 | MH_EXECUTE = 0x00000002 12 | MH_KEXT_BUNDLE = 0x0000000b 13 | LC_DYLD_CHAINED_FIXUPS = 0x80000034 14 | 15 | class Kext(kernelCache): 16 | def __init__(self,objects,isKernel=False,shared_p = "macOS11.2.3"): 17 | kernelCache.__init__(self,objects,macOS=True) 18 | self.macOS = True 19 | self.sym_project = shared_p 20 | self.filetype = None 21 | self.dtm = currentProgram.getDataTypeManager() 22 | self.mem = currentProgram.getMemory() 23 | self.obj = {} 24 | self.listing = currentProgram.getListing() 25 | self.symbolTable = currentProgram.getSymbolTable() 26 | self.ifc = get_decompiler() 27 | self.ns = {} 28 | self.shm_dt = None 29 | mn,mx = currentProgram.getMinAddress(),currentProgram.getMaxAddress() 30 | self.addrRange = AddressRangeImpl(mn,mx) 31 | 32 | self.class_methods ={} 33 | self.vtables = {} 34 | self._collect_vtables() 35 | f = File( currentProgram.getExecutablePath()) 36 | if f.exists() == False: 37 | f = askFile("Could not find the executable path","give a path:") 38 | 39 | assert f.exists() == True 40 | self.read64 = lambda off: struct.unpack("> 32) & 0xffff 155 | b = struct.pack("> 51) & 2047 229 | bind = (content >> 62) & 1 230 | tag = (content >> 32) & 0xffff 231 | if bind == 1: 232 | name_off = self.read32(import_off + offset * 4) 233 | name_off = (name_off >> 9) 234 | symbol = self.br.readAsciiString(syms_off + name_off ) 235 | 236 | symbolTable = currentProgram.getSymbolTable() 237 | ns = symbolTable.getNamespace("Global",None) 238 | #sm = symbolTable.getSymbol(symbol,ns) 239 | sm = getSymbol(symbol,ns) 240 | if sm != None: 241 | sym_addr = sm.getAddress().toString()#,hex(offset) 242 | b = struct.pack(" 0: 88 | params[0] = newParm 89 | else: 90 | # a small workaround is by giving the user the choice to manually add 91 | # the parameters 92 | #print "FUNCTION ", func , "params" , len(params) 93 | #paramsCount = askInt("I couldn't get the params","Put parameter count:") 94 | #print paramsCount 95 | paramsCount = len(params) 96 | ulong_dt = currentProgram.getDataTypeManager().findDataType("/ulong") 97 | params = [newParm] 98 | # Already consumed one 99 | for i in range(paramsCount - 1): 100 | param = ParameterImpl("arg_" + str(i+0),ulong_dt,currentProgram) 101 | params.append(param) 102 | pass 103 | 104 | func.replaceParameters(FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, 105 | True, 106 | SourceType.ANALYSIS, 107 | params) 108 | 109 | #except Exception as e: 110 | # print "[-] Function is invalid" ,e 111 | # raise Exception(e) 112 | 113 | def fix_method(addr,class_name): 114 | dtm = currentProgram.getDataTypeManager() 115 | class_struct = find_struct(class_name) 116 | if class_struct == None: 117 | popup( "Class struct %s not found" %(class_name)) 118 | return 119 | 120 | func = getFunctionAt(addr) 121 | 122 | _fix_method(func,class_struct) 123 | 124 | func.setCallingConvention("__thiscall") 125 | 126 | def fix_func_namespace(className,FuncName): 127 | if "FUN_" in FuncName: 128 | dlm = "FUN_" 129 | elif "FN_" in FuncName: 130 | dlm = "FN_" 131 | #funcs.pop() 132 | f = FuncName.split(dlm)[1] 133 | define_label_with_namespace(f,className) 134 | fix_method(f,className) 135 | 136 | def fix_method_definitions(namespace,fdefs): 137 | if namespace == "kernel": 138 | for fdef in fdefs: 139 | name = fdef.getName() 140 | symbols = manager.getSymbols(name) 141 | for symbol in symbols: 142 | full_name = symbol.getName(True) 143 | dt = find_funcdef(full_name) #dtm.getDataType("/functions/"+full_name) 144 | if dt == None: 145 | continue 146 | dt.setReturnType(fdef.getReturnType()) 147 | args = fdef.getArguments() 148 | args.insert(0,this) 149 | dt.setArguments(args) 150 | 151 | return 152 | 153 | for fdef in fdefs: 154 | name = fdef.getName() 155 | full_name = namespace + '::'+ name 156 | dt = find_funcdef(full_name) 157 | # probably it's not a virtual function, alright 158 | if dt == None: 159 | continue 160 | dt.setReturnType(fdef.getReturnType()) 161 | args = fdef.getArguments() 162 | args.insert(0,this) 163 | dt.setArguments(args) 164 | 165 | def makeFunction(function_ptr): 166 | function = getDataAt(function_ptr) 167 | if function == None : 168 | currentProgram.getListing().clearCodeUnits(function_ptr,function_ptr,False) 169 | PTR = currentProgram.getDataTypeManager().getDataType("/pointer") 170 | if PTR == None: 171 | addTypeDef("pointer","pointer64") 172 | PTR = currentProgram.getDataTypeManager().getDataType("/pointer") 173 | 174 | currentProgram.getListing().createData(function_ptr, PTR) 175 | 176 | # label address value 177 | label = getDataAt(function_ptr).getValue() 178 | if label.getOffset() == 0: 179 | return 180 | 181 | func = getFunctionAt(label) 182 | 183 | if func == None: 184 | # the function is not defined as a function" 185 | if fixLabel(label) == -1: 186 | return 187 | return func 188 | 189 | def fix_namespace(className,function,func_name=None): 190 | function_string = function.getName(True) 191 | if "FUN_" in function_string: 192 | dlm = "FUN_" 193 | elif "FN_" in function_string: 194 | dlm = "FN_" 195 | #funcs.pop() 196 | elif "extMethod" in function_string: 197 | dlm = "extMethod" 198 | 199 | #f = function_string.split(dlm)[1] 200 | 201 | func_addr = function.getEntryPoint() 202 | define_label_with_namespace(func_addr,className,func_name) 203 | fix_method(func_addr,className) 204 | 205 | 206 | def getHeaderFiles(): 207 | return glob.glob("/Users/mg/ghidra_ios/signatures/*") 208 | 209 | def load_signatures_from_file(filename): 210 | funcs = open(filename,"r").read().strip().split('\n') 211 | tool = state.getTool() 212 | service = tool.getService(DataTypeManagerService) 213 | dtm = currentProgram.getDataTypeManager() 214 | funcDefs = [] 215 | 216 | for func in funcs: 217 | vtable = False 218 | if len(func) == 0: 219 | continue 220 | if func[0] == "#": 221 | continue 222 | if func[0] == "-": 223 | vtable = True 224 | 225 | text = func[1:] 226 | funcDef = parseSignature(service,currentProgram,text) 227 | if vtable == True: 228 | funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall) 229 | 230 | funcDefs.append(funcDef) 231 | 232 | return funcDefs 233 | 234 | # this fixes directly the function signature of a given function 235 | def fix_function_signatures(namespace,fdefs): 236 | manager = currentProgram.getSymbolTable() 237 | for fdef in fdefs: 238 | symbol = fdef.getName() 239 | if namespace == "kernel": 240 | symbols = manager.getSymbols(symbol) 241 | for s in symbols: 242 | defineSymbol(s,fdef) 243 | #continue 244 | 245 | ns = manager.getNamespace(namespace,None) 246 | # get symbol only for that namespace 247 | symbols = manager.getSymbols(symbol,ns) 248 | if len(symbols) == 0 or ns == None: 249 | #print(" [-] Symbol/Namespace not found for %s "% (fdef.getName()) , ns) 250 | continue 251 | if symbols == None: 252 | continue 253 | if len(symbols) == 1: 254 | defineSymbol(symbols[0],fdef) 255 | continue 256 | 257 | #TODO : handle multi symbols below 258 | print("[!] Multiple symbols found for %s"%(symbol)) 259 | #print fdef,symbols 260 | #raise Exception 261 | 262 | def load_signatures(): 263 | DeclareDataTypes() 264 | dtm = currentProgram.getDataTypeManager() 265 | void = currentProgram.getDataTypeManager().findDataType("/void") 266 | this = ParameterDefinitionImpl("this",PointerDataType(void),"") 267 | manager = currentProgram.getSymbolTable() 268 | 269 | files = getHeaderFiles() 270 | #files = ["/Users/mg/gh_projects/signatures/kernel.h"] 271 | for file in files: 272 | print ("[+] Processing %s" %(file)) 273 | namespace = file.split(".h")[0].split("/")[-1] 274 | fdefs= load_signatures_from_file(file) 275 | fix_function_signature(namespace,fdefs) 276 | fix_method_definition(namespace,fdefs) 277 | -------------------------------------------------------------------------------- /utils/references.py: -------------------------------------------------------------------------------- 1 | from helpers import * 2 | from methods import * 3 | from references import * 4 | 5 | funcs = [] 6 | logger = [] 7 | 8 | black_list_ns = ["OSObject","OSArray","OSDictionary","OSData","OSString", 9 | "OSBoolean","OSCollection","OSCollectionIterator", 10 | "OSIterator","OSNumber","OSOrderedSet","OSSerialize", 11 | "OSSerializer","OSSet","OSSymbol","OSAction","OSUserMetaClass"] 12 | 13 | def append_to_functions(func): 14 | if func in funcs: 15 | return 16 | ns = func.getSymbol().getParentNamespace() 17 | if ns.getName() not in black_list_ns: 18 | funcs.append(func) 19 | 20 | # get the DataType of the the first argument 21 | def process_this(this): 22 | if this.isRegister(): 23 | dt = this.getHigh().getDataType() 24 | return dt.getName().replace("*","").strip() 25 | 26 | thisdef = this.getDef() 27 | if thisdef == None: 28 | return None 29 | 30 | if thisdef.opcode == PcodeOp.CAST: 31 | var = thisdef.getInput(0) 32 | if var.isRegister(): 33 | dt = var.getHigh().getDataType() 34 | return dt.getName().replace("*","").strip() 35 | else: 36 | pass 37 | 38 | return None 39 | 40 | def fix_hfunc_namespaces(hfunc): 41 | symbolTable = currentProgram.getSymbolTable() 42 | global funcs 43 | for op in hfunc.pcodeOps: 44 | addr = op.getSeqnum().getTarget() 45 | if op.opcode == PcodeOp.CALL: 46 | numParams = op.getNumInputs() 47 | # avoiding functions with no arguments 48 | if numParams < 2: 49 | continue 50 | caller = op.getInput(0) 51 | targetFunc = getSymbolAt(toAddr(caller.getOffset())) 52 | targetFuncName = targetFunc.getName() 53 | if "FUN_" not in targetFuncName and "FN_" not in targetFuncName : 54 | continue 55 | 56 | this = op.getInput(1) 57 | className = process_this(this) 58 | if className == None: 59 | continue 60 | namespace = symbolTable.getNamespace(className,None) 61 | if namespace == None: 62 | logger.debug("[-] I couldn't get the namespace of '%s' 0x%s" %(className,addr)) 63 | continue 64 | logger.debug("[+] Namespace : Function %s with namespace %s " %(targetFuncName,className)) 65 | 66 | func = getFunctionContaining(targetFunc.getAddress()) 67 | if func not in funcs : 68 | append_to_functions(func) 69 | fix_namespace(className,func) 70 | 71 | def process_vn_for_refs(cdef,depth=0): 72 | 73 | logger.debug("depth=%d, def : %s",depth,cdef.toString()) 74 | 75 | if cdef.opcode == PcodeOp.LOAD: 76 | varnode = cdef.getInput(1) 77 | if varnode.isUnique() == False: 78 | logger.error("This may produce undesirable output, unhandled case ") 79 | raise Exception 80 | 81 | uniqueDef = varnode.getDef() 82 | return process_vn_for_refs(uniqueDef,depth+1) 83 | 84 | elif cdef.opcode == PcodeOp.PTRSUB: 85 | reg , const = cdef.getInputs() 86 | vtable = reg.getHigh().getDataType() 87 | offset = const.getOffset() 88 | return (vtable,offset) 89 | 90 | elif cdef.opcode == PcodeOp.CAST: 91 | varnode = cdef.getInput(0) 92 | if varnode.isUnique() == False: 93 | if varnode.isRegister() == True: 94 | rdef = varnode.getDef() 95 | return process_vn_for_refs(rdef,depth+1) 96 | else: 97 | logger.warning("This may produce undesirable output, unhandled case ") 98 | return None 99 | 100 | uniqueDef = varnode.getDef() 101 | return process_vn_for_refs(uniqueDef,depth+1) 102 | 103 | elif cdef.opcode == PcodeOp.INT_ADD: 104 | reg,const = cdef.getInputs() 105 | 106 | vtable = reg.getHigh().getDataType() 107 | offset = const.getOffset() 108 | return (vtable,offset) 109 | 110 | elif cdef.opcode == PcodeOp.MULTIEQUAL: 111 | varnodes = cdef.getInputs() 112 | ls = [] 113 | for vn in varnodes : 114 | vnDef = vn.getDef() 115 | x,y = process_vn_for_refs(vnDef,depth+1) 116 | ls.append((x,y)) 117 | 118 | return ls 119 | 120 | elif cdef.opcode == PcodeOp.PTRADD: 121 | varnodes = cdef.getInputs() 122 | 123 | # The inputs may take different looks 124 | vtable = varnodes[0].getHigh().getDataType() 125 | b = varnodes[1].getOffset() 126 | c = varnodes[2].getOffset() 127 | 128 | return (vtable,b * c) 129 | else: 130 | logger.fatal("Unhandled opcode ") 131 | raise Exception(cdef.opcode) 132 | 133 | def process_ptmf2ptf(callerDef): 134 | global funcs 135 | op = callerDef 136 | logger.debug("op %s",op.toString()) 137 | inputs = op.getInputs() 138 | if len(inputs) < 2: 139 | logger.error("Bogus _ptmf2ptf implementation ") 140 | raise Exception 141 | 142 | target_ns = inputs[1] 143 | target_off = inputs[2] 144 | 145 | ns = target_ns.getHigh().getDataType() 146 | vtable_symbol = ns.getName().replace("*","").strip()+"_vtable" 147 | 148 | if target_off.isConstant(): 149 | offset = target_off.getOffset() 150 | 151 | if len(inputs) == 4: 152 | m = inputs[3].getOffset() 153 | offset = offset * m 154 | 155 | addr = callerDef.getSeqnum().getTarget() 156 | memory_add_reference(addr,vtable_symbol,offset,True) 157 | 158 | 159 | elif target_off.isUnique(): 160 | udef = target_off.getDef() 161 | addr = callerDef.getSeqnum().getTarget() 162 | 163 | if udef.opcode == PcodeOp.PTRSUB : 164 | input = udef.getInput(1) 165 | offset = input.getOffset() 166 | memory_add_reference(addr,vtable_symbol,offset,True) 167 | # check if the offset is a function 168 | func = getFunctionAt(toAddr(offset)) 169 | sym = getSymbolAt(toAddr(offset)) 170 | 171 | # if offset is just a a vtable offset, skip 172 | if func == None and "LAB_" not in sym.getName(): 173 | return 174 | else: 175 | if "LAB_" in sym.getName(): 176 | fn = sym.getName().replace("LAB","FUN") 177 | createFunction(toAddr(offset),fn) 178 | func = getFunctionAt(toAddr(offset)) 179 | if func == None: 180 | logger.warning("Something wrong with %s" %(toAddr(offset).toString())) 181 | return 182 | 183 | 184 | string = ns.getDataType().getName() 185 | fix_namespace(string,func) 186 | append_to_functions(func) 187 | 188 | pass 189 | 190 | else: 191 | pass 192 | 193 | else: 194 | logger.warning("UNKNOWN operation ") 195 | raise Exception(target_off) 196 | 197 | 198 | def fix_refs(hfunc): 199 | func = hfunc.getFunction() 200 | #logger.debug("Fixing references at %s" % (func.getName())) 201 | 202 | for op in hfunc.pcodeOps: 203 | addr = op.getSeqnum().getTarget() 204 | logging.debug("addr: 0x%s, opcode : %s" ,addr.toString(), op.toString()) 205 | if op.opcode == PcodeOp.CALLIND: 206 | logger.debug("addr: 0x%s, opcode : %s" ,addr.toString(), op.toString()) 207 | caller = op.getInput(0) 208 | callerDef = caller.getDef() 209 | if callerDef == None: 210 | print "FIXMEE : CallerDef is Nil" 211 | logger.error("Could not get callerDef") 212 | raise Exception 213 | 214 | # take the caller definition and get (vtable,offset) 215 | logger.debug("Caller Definition opcode : %s" ,callerDef.toString()) 216 | info = process_vn_for_refs(callerDef) 217 | 218 | if info == None: 219 | logger.error("None : %s , %s" ,addr.toString(),op.toString()) 220 | continue 221 | # MULTI EQUAL operation 222 | if isinstance(info,list) == True: 223 | for i in info: 224 | process_reference(addr,i) 225 | continue 226 | process_reference(addr,info) 227 | 228 | 229 | if op.opcode == PcodeOp.CALL: 230 | caller = op.getInput(0) 231 | if caller.isAddress() == False: 232 | continue 233 | name = getSymbolAt(caller.getAddress()) 234 | if name == None : 235 | continue 236 | 237 | if name.getName() == "_ptmf2ptf": 238 | process_ptmf2ptf(op) 239 | 240 | def memory_add_reference(addr,vtable_symbol,off,primary=False): 241 | manager = currentProgram.getSymbolTable() 242 | symbol = manager.getSymbol(vtable_symbol,None) 243 | 244 | if symbol == None: 245 | print "[-] '%s' symbol not found" % (vtable_symbol) 246 | return 247 | 248 | new = symbol.getAddress().add(off) 249 | func = getDataAt(new) 250 | if func == None: 251 | return 252 | 253 | funcAddr = func.getValue() 254 | tfunc = getFunctionAt(funcAddr) 255 | append_to_functions(tfunc) 256 | 257 | refMgr = currentProgram.getReferenceManager() 258 | ref = refMgr.addMemoryReference(addr, funcAddr, RefType.COMPUTED_CALL, SourceType.DEFAULT, 0) 259 | if primary == True: 260 | refMgr.setPrimary(ref,True) 261 | 262 | def process_reference(addr,info): 263 | global funcs 264 | dt, off = info 265 | vtable_symbol = dt.getName().replace("*","").strip() 266 | manager = currentProgram.getSymbolTable() 267 | # TODO : sanity checks against vtable_symbols (ie : undefined/longlong ..etc) 268 | if "_vtable" not in vtable_symbol: 269 | logger.debug("'%s' Looks like not a valid symbol at %s" %(vtable_symbol,addr.toString())) 270 | return 271 | 272 | memory_add_reference(addr,vtable_symbol,off) 273 | 274 | 275 | def fix_extra_refs(entry_addr): 276 | global funcs 277 | global logger 278 | logger = setup_logging("extra_ref") 279 | black_list_funcs = ["IOCommandGate::runAction"] 280 | 281 | ifc = get_decompiler() 282 | func = getFunctionContaining(entry_addr) 283 | # we start from the selected function 284 | if func == None: 285 | popup("Could not get function at %s" %(entry_addr.toString())) 286 | return 287 | 288 | funcs.append(func) 289 | for func in funcs: 290 | if func in black_list_funcs: 291 | continue 292 | if "OSObject" in func.getName(True): 293 | continue 294 | 295 | logger.info("Fixing %s at 0x%s" %(func,func.getEntryPoint().toString())) 296 | hfunc = decompile_func(ifc,func) 297 | #HighFunctionDBUtil.commitParamsToDatabase(hfunc,True,SourceType.USER_DEFINED) 298 | # this is useful for changing method namespace on the fly 299 | func.setCustomVariableStorage(True) 300 | fix_hfunc_namespaces(hfunc) 301 | fix_refs(hfunc) 302 | 303 | funcs = [] 304 | --------------------------------------------------------------------------------