├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── misc ├── control └── template.tar └── src ├── cfj.c ├── cfj.h ├── common.c ├── common.h ├── ioclass.c ├── iokit.h ├── ioprint.c └── ioscan.c /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /bin 3 | /pkg 4 | /*.tar.xz 5 | /*.deb 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION = 1.4.0 2 | BINDIR = bin 3 | SRCDIR = src 4 | ALL = $(patsubst $(SRCDIR)/%.c,%,$(wildcard $(SRCDIR)/io*.c)) 5 | PKG = pkg 6 | XZ = iokit-utils.tar.xz 7 | DEB = net.siguza.iokit-utils_$(VERSION)_iphoneos-arm.deb 8 | C_FLAGS ?= -Wall -O3 -framework IOKit -framework CoreFoundation -framework Security $(CFLAGS) 9 | CC_FLAGS ?= -arch x86_64 -arch arm64 10 | IOS_CC ?= xcrun -sdk iphoneos clang 11 | IOS_CFLAGS ?= -arch armv7 -arch arm64 12 | CODESIGN ?= codesign 13 | 14 | 15 | .PHONY: all dist xz deb clean 16 | 17 | all: $(addprefix $(BINDIR)/macos/, $(ALL)) $(addprefix $(BINDIR)/ios/, $(ALL)) 18 | 19 | $(BINDIR)/macos/%: $(SRCDIR)/%.c $(SRCDIR)/common.c $(SRCDIR)/cfj.c | $(BINDIR)/macos 20 | $(CC) $(CC_FLAGS) $(C_FLAGS) -o $@ $^ 21 | $(CODESIGN) -s - $@ 22 | 23 | $(BINDIR)/ios/%: $(SRCDIR)/%.c $(SRCDIR)/common.c $(SRCDIR)/cfj.c | $(BINDIR)/ios 24 | $(IOS_CC) $(IOS_CFLAGS) $(C_FLAGS) -o $@ $^ 25 | $(CODESIGN) -s - $@ 26 | 27 | dist: xz deb 28 | 29 | xz: $(XZ) 30 | 31 | deb: $(DEB) 32 | 33 | $(XZ): $(addprefix $(BINDIR)/macos/, $(ALL)) $(addprefix $(BINDIR)/ios/, $(ALL)) 34 | tar -cJf $(XZ) -C $(BINDIR) macos ios 35 | 36 | $(DEB): $(PKG)/control.tar.gz $(PKG)/data.tar.lzma $(PKG)/debian-binary 37 | ( cd "$(PKG)"; ar -cr "../$(DEB)" 'debian-binary' 'control.tar.gz' 'data.tar.lzma'; ) 38 | 39 | $(PKG)/control.tar.gz: $(PKG)/control 40 | tar -czf '$(PKG)/control.tar.gz' --exclude '.DS_Store' --exclude '._*' --exclude 'control.tar.gz' --include '$(PKG)' --include '$(PKG)/control' -s '%^$(PKG)%.%' $(PKG) 41 | 42 | $(PKG)/data.tar.lzma: $(addprefix $(BINDIR)/ios/, $(ALL)) | $(PKG) 43 | tar -c --lzma -f '$(PKG)/data.tar.lzma' --exclude '.DS_Store' --exclude '._*' -s '%^bin/ios%./usr/bin%' @misc/template.tar $(BINDIR)/ios 44 | 45 | $(PKG)/debian-binary: | $(PKG) 46 | echo '2.0' > "$(PKG)/debian-binary" 47 | 48 | $(PKG)/control: misc/control | $(PKG) 49 | ( echo "Version: $(VERSION)"; cat misc/control; ) > $(PKG)/control 50 | 51 | $(BINDIR) $(BINDIR)/macos $(BINDIR)/ios $(PKG): 52 | mkdir -p $@ 53 | 54 | clean: 55 | rm -rf $(BINDIR) $(PKG) $(XZ) net.siguza.iokit-utils_*_iphoneos-arm.deb 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IOKit Utils 2 | 3 | Just some little dev tools to probe IOKit. 4 | Makefile is designed to build all-in-one binaries for both iOS and macOS. 5 | 6 | # `ioclass` 7 | 8 | Usage: 9 | 10 | ioclass [-b] [Name] 11 | 12 | Takes an IOKit class name as argument and, if `-b` is given, prints the bundle ID of the providing kext, otherwise prints its class hierarchy. 13 | 14 | ### Example 15 | 16 | bash$ ioclass RootDomainUserClient 17 | RootDomainUserClient 18 | IOUserClient 19 | IOService 20 | IORegistryEntry 21 | OSObject 22 | 23 | # `ioprint` 24 | 25 | Iterate over all entries in a registry plane and perform operations on them. 26 | 27 | Usage: 28 | 29 | ioprint [-d] [-j] [-k] [-o] [-h] [-p Plane] [-s] [Name] 30 | 31 | All arguments are optional. 32 | Class names of all considered objects as well as return values are always printed. 33 | 34 | - `Name`: Limit the performed operations to only objects that either extend a class `Name`, or whose name in the registry is `Name`. If none is given, all objects are processed. 35 | - `-d`: Print IOKit properties in XML format. 36 | - `-h`: Print a help and exit. 37 | - `-j`: Print IOKit properties in JSON format. 38 | - `-k`: Print IOKit properties in mix between JSON and hexdump. 39 | - `-o`: Print only IOKit properties and nothing else. 40 | - `-s`: Try to set properties `herpderp` on all objects. 41 | - `-p Plane`: Iterate over registry plane `Plane`. Default is `IOService`. 42 | 43 | ### Examples 44 | 45 | List all entries of the `IOService` plane: 46 | 47 | bash$ ioprint 48 | # [ excessive output omitted ] 49 | 50 | List all entries of the `IOUSB` plane: 51 | 52 | bash$ ioprint -p IOUSB 53 | IORegistryEntry(Root) 54 | IOUSBRootHubDevice(Root Hub Simulation Simulation) 55 | IOUSBDevice(Bluetooth USB Host Controller) 56 | 57 | List all `IOUserClient` instances: 58 | 59 | bash$ ioprint IOUserClient 60 | # [ excessive output omitted ] 61 | 62 | Print properties of all `IOHIDUserClient` instances: 63 | 64 | bash$ ioprint -d IOHIDUserClient 65 | IOHIDUserClient: (os/kern) successful (0x0) 66 | 67 | 68 | 69 | 70 | IOUserClientCreator 71 | pid 223, WindowServer 72 | IOUserClientCrossEndianCompatible 73 | 74 | 75 | 76 | 77 | List all properties of the registry root: 78 | 79 | bash$ ioprint -d Root 80 | # [ excessive output omitted ] 81 | 82 | Try to set properties on all `IOHIDUserClient` instances: 83 | 84 | bash$ ioprint -s IOHIDUserClient 85 | IOHIDUserClient: (os/kern) successful (0x0) 86 | 87 | (Note: The return value doesn't necessarily indicate that properties were actually set. Usually for user clients, they are not.) 88 | 89 | # `ioscan` 90 | 91 | Iterate over all entries in a registry plane and try to spawn user clients. 92 | Prints name and class of all services, whether spawning a client was successful, class of the spawned client, and whether multiple user clients have the same ID (i.e. are shared clients). 93 | 94 | Usage: 95 | 96 | ioscan [-h] [-p Plane] [-s] [Name [min [max]]] 97 | 98 | - `Name`: Limit the performed operations to only objects that either extend a class `Name`, or whose name in the registry is `Name`. If none is given, all objects are processed. 99 | - `min` and `max`: Try spawning user clients of certain types (can be given in base 8, 10 or 16). If both `min` and `max` are given, all types in that range will be tried. If only `min` is given, that one type will be tried. Defaults to `0`. 100 | - `-h`: Print a help and exit. 101 | - `-s`: Only print entries where a user client was successfully spawned. 102 | - `-p Plane`: Iterate over registry plane `Plane`. Default is `IOService`. 103 | 104 | All arguments are optional, but `min` and `max` can only be given if `Name` is given too. 105 | 106 | ### Examples 107 | 108 | Spawn a user client for every service: 109 | 110 | bash$ ioscan 111 | # [ excessive output omitted ] 112 | 113 | Spawn an AMFI user client: 114 | 115 | bash$ ioscan AppleMobileFileIntegrity 116 | Class Name Type Spawn UC One Two Equal 117 | AppleMobileFileIntegrity AppleMobileFileIntegrity 0 (os/kern) successful AppleMobileFileIntegrityUserClient 23207 23107 != 118 | 119 | Spawn an `IOGraphicsDevice` user client of type `1`: 120 | 121 | bash$ ioscan IOGraphicsDevice 1 122 | Class Name Type Spawn UC One Two Equal 123 | AppleIntelFramebuffer AppleIntelFramebuffer 1 (os/kern) successful IOFramebufferSharedUserClient 8307 8307 == 124 | AppleIntelFramebuffer AppleIntelFramebuffer 1 (os/kern) successful IOFramebufferSharedUserClient 8d07 8d07 == 125 | AppleIntelFramebuffer AppleIntelFramebuffer 1 (os/kern) successful IOFramebufferSharedUserClient 9407 9407 == 126 | 127 | ### License 128 | 129 | [MPL2](https://github.com/Siguza/iokit-utils/blob/master/LICENSE) with Exhibit B, except for [`iokit.h`](https://github.com/Siguza/iokit-utils/blob/master/src/iokit.h) which is Public Domain. 130 | -------------------------------------------------------------------------------- /misc/control: -------------------------------------------------------------------------------- 1 | Package: net.siguza.iokit-utils 2 | Name: iokit-utils 3 | Architecture: iphoneos-arm 4 | Description: IOKit probing toolkit 5 | Dev tools for probing IOKit.
6 | Free and open source. 7 | Maintainer: Siguza 8 | Author: Siguza 9 | Homepage: https://github.com/Siguza/iokit-utils 10 | Section: Development 11 | -------------------------------------------------------------------------------- /misc/template.tar: -------------------------------------------------------------------------------- 1 | ./000755 000765 000000 00000000000 13001240310 011304 5ustar00moltwheel000000 000000 ./usr/000755 000765 000000 00000000000 13001240260 012121 5ustar00moltwheel000000 000000 -------------------------------------------------------------------------------- /src/cfj.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2021 Siguza 2 | * 3 | * This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | * 7 | * This Source Code Form is "Incompatible With Secondary Licenses", as 8 | * defined by the Mozilla Public License, v. 2.0. 9 | **/ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "common.h" 16 | #include "cfj.h" 17 | 18 | static void cfj_dict_cb(const void *key, const void *val, void *context); 19 | static void cfj_arr_cb(const void *val, void *context); 20 | static void cfj_print_str(common_ctx_t *ctx, const CFStringRef str); 21 | static void cfj_print_internal(common_ctx_t *ctx, CFTypeRef obj); 22 | 23 | static void cfj_dict_cb(const void *key, const void *val, void *context) 24 | { 25 | common_ctx_t *ctx = context; 26 | if(ctx->first) 27 | { 28 | fprintf(ctx->stream, "\n"); 29 | ctx->first = false; 30 | } 31 | else 32 | { 33 | fprintf(ctx->stream, ",\n"); 34 | } 35 | fprintf(ctx->stream, "%*s", ctx->lvl * 4, ""); 36 | cfj_print_str(ctx, key); 37 | fprintf(ctx->stream, ": "); 38 | cfj_print_internal(ctx, val); 39 | } 40 | 41 | static void cfj_arr_cb(const void *val, void *context) 42 | { 43 | common_ctx_t *ctx = context; 44 | if(ctx->first) 45 | { 46 | fprintf(ctx->stream, "\n"); 47 | ctx->first = false; 48 | } 49 | else 50 | { 51 | fprintf(ctx->stream, ",\n"); 52 | } 53 | fprintf(ctx->stream, "%*s", ctx->lvl * 4, ""); 54 | cfj_print_internal(ctx, val); 55 | } 56 | 57 | static void cfj_print_str(common_ctx_t *ctx, const CFStringRef str) 58 | { 59 | fprintf(ctx->stream, "\""); 60 | char buf[0x100]; 61 | for(CFIndex i = 0, len = CFStringGetLength(str); i < len; ) 62 | { 63 | CFIndex max = len - i, 64 | out = 0; 65 | CFRange range = CFRangeMake(i, max); 66 | max = CFStringGetBytes(str, range, kCFStringEncodingUTF8, 0, false, (UInt8*)buf, sizeof(buf), &out); 67 | if(ctx->true_json) 68 | { 69 | for(size_t j = 0; j < out; ++j) 70 | { 71 | common_print_char(ctx, buf[j]); 72 | } 73 | } 74 | else 75 | { 76 | fwrite(buf, 1, out, ctx->stream); 77 | } 78 | i += max; 79 | } 80 | fprintf(ctx->stream, "\""); 81 | } 82 | 83 | static void cfj_print_internal(common_ctx_t *ctx, CFTypeRef obj) 84 | { 85 | CFTypeID type = CFGetTypeID(obj); 86 | if(type == CFBooleanGetTypeID()) 87 | { 88 | fprintf(ctx->stream, "%s", CFBooleanGetValue(obj) ? "true" : "false"); 89 | return; 90 | } 91 | else if(type == CFNumberGetTypeID()) 92 | { 93 | if(CFNumberIsFloatType(obj)) 94 | { 95 | double val = 0; 96 | if(CFNumberGetValue(obj, kCFNumberDoubleType, &val)) 97 | { 98 | fprintf(ctx->stream, "%lf", val); 99 | return; 100 | } 101 | } 102 | else 103 | { 104 | unsigned long long val = 0; 105 | if(CFNumberGetValue(obj, kCFNumberLongLongType, &val)) 106 | { 107 | fprintf(ctx->stream, ctx->true_json ? "%llu" : "0x%llx", val); 108 | return; 109 | } 110 | } 111 | } 112 | else if(type == CFStringGetTypeID()) 113 | { 114 | cfj_print_str(ctx, obj); 115 | return; 116 | } 117 | else if(type == CFDataGetTypeID()) 118 | { 119 | CFIndex size = CFDataGetLength(obj); 120 | if(ctx->true_json) 121 | { 122 | common_print_bytes(ctx, CFDataGetBytePtr(obj), size); 123 | } 124 | else if(size > 0) 125 | { 126 | int pad = (ctx->lvl + 1) * 4; 127 | fprintf(ctx->stream, "<\n%*s", pad, ""); 128 | const UInt8 *data = CFDataGetBytePtr(obj); 129 | char cs[17] = {}; 130 | int i; 131 | for(i = 0; i < size; i++) 132 | { 133 | if(i != 0 && i % 0x10 == 0) 134 | { 135 | fprintf(ctx->stream, " |%s|\n%*s", cs, pad, ""); 136 | memset(cs, 0, 17); 137 | } 138 | else if(i != 0 && i % 0x8 == 0) 139 | { 140 | fprintf(ctx->stream, " "); 141 | } 142 | fprintf(ctx->stream, "%02x ", data[i]); 143 | cs[(i % 0x10)] = (data[i] >= 0x20 && data[i] <= 0x7e) ? data[i] : '.'; 144 | } 145 | i = i % 0x10; 146 | if(i != 0) 147 | { 148 | if(i <= 0x8) 149 | { 150 | fprintf(ctx->stream, " "); 151 | } 152 | while(i++ < 0x10) 153 | { 154 | fprintf(ctx->stream, " "); 155 | } 156 | } 157 | fprintf(ctx->stream, " |%s|\n%*s>", cs, pad - 4, ""); 158 | } 159 | return; 160 | } 161 | else if(type == CFDictionaryGetTypeID()) 162 | { 163 | common_ctx_t newctx = 164 | { 165 | .true_json = ctx->true_json, 166 | .bytes_raw = ctx->bytes_raw, 167 | .first = true, 168 | .lvl = ctx->lvl + 1, 169 | .stream = ctx->stream, 170 | }; 171 | fprintf(ctx->stream, "{"); 172 | CFDictionaryApplyFunction(obj, &cfj_dict_cb, &newctx); 173 | if(!newctx.first) 174 | { 175 | fprintf(ctx->stream, "\n%*s", ctx->lvl * 4, ""); 176 | } 177 | fprintf(ctx->stream, "}"); 178 | return; 179 | } 180 | else if(type == CFArrayGetTypeID()) 181 | { 182 | common_ctx_t newctx = 183 | { 184 | .true_json = ctx->true_json, 185 | .bytes_raw = ctx->bytes_raw, 186 | .first = true, 187 | .lvl = ctx->lvl + 1, 188 | .stream = ctx->stream, 189 | }; 190 | fprintf(ctx->stream, "["); 191 | CFArrayApplyFunction(obj, CFRangeMake(0, CFArrayGetCount(obj)), &cfj_arr_cb, &newctx); 192 | if(!newctx.first) 193 | { 194 | fprintf(ctx->stream, "\n%*s", ctx->lvl * 4, ""); 195 | } 196 | fprintf(ctx->stream, "]"); 197 | return; 198 | } 199 | else 200 | { 201 | fprintf(ctx->stream, ""); 202 | return; 203 | } 204 | fprintf(ctx->stream, ""); 205 | } 206 | 207 | void cfj_print(FILE *stream, CFTypeRef obj, bool true_json, bool bytes_raw) 208 | { 209 | common_ctx_t ctx = 210 | { 211 | .true_json = true_json, 212 | .bytes_raw = bytes_raw, 213 | .first = false, 214 | .lvl = 0, 215 | .stream = stream, 216 | }; 217 | cfj_print_internal(&ctx, obj); 218 | fprintf(stream, "\n"); 219 | } 220 | -------------------------------------------------------------------------------- /src/cfj.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2019-2021 Siguza 2 | * 3 | * This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | * 7 | * This Source Code Form is "Incompatible With Secondary Licenses", as 8 | * defined by the Mozilla Public License, v. 2.0. 9 | **/ 10 | 11 | #ifndef CFJ_H 12 | #define CFJ_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | void cfj_print(FILE *stream, CFTypeRef obj, bool true_json, bool bytes_raw); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 Siguza 2 | * 3 | * This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | * 7 | * This Source Code Form is "Incompatible With Secondary Licenses", as 8 | * defined by the Mozilla Public License, v. 2.0. 9 | **/ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "common.h" 17 | 18 | extern size_t SecBase64Encode(void const *src, size_t srcSize, char *dest, size_t destLen); 19 | 20 | void common_print_bytes(common_ctx_t *ctx, const uint8_t *buf, size_t size) 21 | { 22 | if(ctx->bytes_raw) 23 | { 24 | fprintf(ctx->stream, "\""); 25 | for(size_t i = 0; i < size; ++i) 26 | { 27 | common_print_char(ctx, (char)buf[i]); 28 | } 29 | fprintf(ctx->stream, "\""); 30 | } 31 | else 32 | { 33 | size_t encoded_size = ((size + 2) / 3) * 4 + 1; 34 | char *str = malloc(encoded_size); 35 | if(!str) 36 | { 37 | fprintf(ctx->stream, ""); 38 | } 39 | else 40 | { 41 | str[encoded_size - 1] = '\0'; 42 | SecBase64Encode(buf, size, str, encoded_size); 43 | fprintf(ctx->stream, "\"%s\"", str); 44 | free(str); 45 | } 46 | } 47 | } 48 | 49 | void common_print_char(common_ctx_t *ctx, char c) 50 | { 51 | // This catches both <0x20 and >=0x80 52 | if(c < 0x20) 53 | { 54 | fprintf(ctx->stream, "\\u%04hx", (unsigned char)c); 55 | return; 56 | } 57 | switch(c) 58 | { 59 | case '\n': 60 | fputs("\\n", ctx->stream); 61 | return; 62 | case '\r': 63 | fputs("\\r", ctx->stream); 64 | return; 65 | case '\t': 66 | fputs("\\t", ctx->stream); 67 | return; 68 | case '\f': 69 | fputs("\\f", ctx->stream); 70 | return; 71 | case '\b': 72 | fputs("\\b", ctx->stream); 73 | return; 74 | case '\\': 75 | case '"': 76 | fputc('\\', ctx->stream); 77 | break; 78 | } 79 | fputc(c, ctx->stream); 80 | } 81 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2022 Siguza 2 | * 3 | * This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | * 7 | * This Source Code Form is "Incompatible With Secondary Licenses", as 8 | * defined by the Mozilla Public License, v. 2.0. 9 | **/ 10 | 11 | #ifndef COMMON_H 12 | #define COMMON_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include // printf, fprintf, stderr 18 | 19 | #define LOG(str, args...) \ 20 | do \ 21 | { \ 22 | printf(str "\n", ##args); \ 23 | } while(0) 24 | 25 | #define ERR(str, args...) \ 26 | do \ 27 | { \ 28 | fprintf(stderr, str "\n", ##args); \ 29 | } while(0) 30 | 31 | #define COLOR_RED "\x1b[1;91m" 32 | #define COLOR_GREEN "\x1b[1;92m" 33 | #define COLOR_YELLOW "\x1b[1;93m" 34 | #define COLOR_BLUE "\x1b[1;94m" 35 | #define COLOR_PURPLE "\x1b[1;95m" 36 | #define COLOR_CYAN "\x1b[1;96m" 37 | #define COLOR_RESET "\x1b[0m" 38 | 39 | typedef struct 40 | { 41 | bool true_json; 42 | bool bytes_raw; 43 | bool first; 44 | int lvl; 45 | FILE *stream; 46 | } common_ctx_t; 47 | 48 | void common_print_bytes(common_ctx_t *ctx, const uint8_t *buf, size_t size); 49 | void common_print_char(common_ctx_t *ctx, char c); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/ioclass.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2018 Siguza 2 | * 3 | * This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | * 7 | * This Source Code Form is "Incompatible With Secondary Licenses", as 8 | * defined by the Mozilla Public License, v. 2.0. 9 | **/ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "common.h" 18 | #include "iokit.h" 19 | 20 | int main(int argc, const char **argv) 21 | { 22 | bool bundle = false, 23 | extends = false; 24 | int aoff; 25 | for(aoff = 1; aoff < argc; ++aoff) 26 | { 27 | if(argv[aoff][0] != '-') 28 | { 29 | break; 30 | } 31 | if(strcmp(argv[aoff], "-b") == 0) 32 | { 33 | bundle = true; 34 | } 35 | else if(strcmp(argv[aoff], "-e") == 0) 36 | { 37 | extends = true; 38 | } 39 | else 40 | { 41 | ERR(COLOR_RED "Unrecognized argument: %s" COLOR_RESET, argv[aoff]); 42 | return -1; 43 | } 44 | } 45 | 46 | if(argc - aoff < 1) 47 | { 48 | ERR("Usage: %s [-b] [-e] ClassName", argv[0]); 49 | return -1; 50 | } 51 | 52 | CFStringRef class = CFStringCreateWithCStringNoCopy(NULL, argv[aoff], kCFStringEncodingUTF8, kCFAllocatorNull); 53 | if(extends) 54 | { 55 | io_registry_entry_t root = IORegistryGetRootEntry(kIOMasterPortDefault); 56 | CFDictionaryRef diag = IORegistryEntryCreateCFProperty(root, CFSTR("IOKitDiagnostics"), NULL, 0); 57 | CFDictionaryRef classes = CFDictionaryGetValue(diag, CFSTR("Classes")); 58 | CFIndex num = CFDictionaryGetCount(classes); 59 | CFStringRef *names = malloc(num * sizeof(CFStringRef)); 60 | CFDictionaryGetKeysAndValues(classes, (const void**)names, NULL); 61 | 62 | for(size_t i = 0; i < num; ++i) 63 | { 64 | CFStringRef actual = names[i]; 65 | CFStringRef current = actual; 66 | CFRetain(current); 67 | while(current != NULL) 68 | { 69 | if(CFEqual(current, class)) 70 | { 71 | char classStr[512]; 72 | if(!CFStringGetCString(actual, classStr, sizeof(classStr), kCFStringEncodingUTF8)) 73 | { 74 | ERR(COLOR_RED "Failed to convert class name to UTF-8." COLOR_RESET); 75 | return -1; 76 | } 77 | if(bundle) 78 | { 79 | CFStringRef bndl = IOObjectCopyBundleIdentifierForClass(actual); 80 | char bundleStr[512]; 81 | if(!CFStringGetCString(bndl, bundleStr, sizeof(bundleStr), kCFStringEncodingUTF8)) 82 | { 83 | ERR(COLOR_RED "Failed to convert bundle name to UTF-8." COLOR_RESET); 84 | return -1; 85 | } 86 | LOG("%s (%s)", classStr, bundleStr); 87 | CFRelease(bndl); 88 | } 89 | else 90 | { 91 | LOG("%s", classStr); 92 | } 93 | CFRelease(current); 94 | break; 95 | } 96 | CFStringRef super = IOObjectCopySuperclassForClass(current); 97 | CFRelease(current); 98 | current = super; 99 | } 100 | } 101 | 102 | free(names); 103 | CFRelease(diag); 104 | IOObjectRelease(root); 105 | CFRelease(class); 106 | } 107 | else if(bundle) 108 | { 109 | CFStringRef bndl = IOObjectCopyBundleIdentifierForClass(class); 110 | if(bndl) 111 | { 112 | char bundleStr[512]; 113 | if(!CFStringGetCString(bndl, bundleStr, sizeof(bundleStr), kCFStringEncodingUTF8)) 114 | { 115 | ERR(COLOR_RED "Failed to convert bundle name to UTF-8." COLOR_RESET); 116 | return -1; 117 | } 118 | LOG("%s", bundleStr); 119 | } 120 | else 121 | { 122 | LOG(COLOR_RED "Class not found" COLOR_RESET); 123 | } 124 | CFRelease(bndl); 125 | CFRelease(class); 126 | } 127 | else 128 | { 129 | for(int i = 0; class != NULL; ++i) 130 | { 131 | char classStr[512]; 132 | if(!CFStringGetCString(class, classStr, sizeof(classStr), kCFStringEncodingUTF8)) 133 | { 134 | ERR(COLOR_RED "Failed to convert class name to UTF-8." COLOR_RESET); 135 | return -1; 136 | } 137 | LOG("%*s%s", i, "", classStr); 138 | CFStringRef super = IOObjectCopySuperclassForClass(class); 139 | CFRelease(class); 140 | class = super; 141 | } 142 | } 143 | 144 | return 0; 145 | } 146 | -------------------------------------------------------------------------------- /src/iokit.h: -------------------------------------------------------------------------------- 1 | // This file is Public Domain. 2 | 3 | #ifndef IOKIT_H 4 | #define IOKIT_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | typedef char io_name_t[128]; 11 | typedef char io_string_t[512]; 12 | typedef char io_struct_inband_t[4096]; 13 | typedef mach_port_t io_object_t; 14 | typedef io_object_t io_registry_entry_t; 15 | typedef io_object_t io_service_t; 16 | typedef io_object_t io_connect_t; 17 | typedef io_object_t io_iterator_t; 18 | 19 | enum 20 | { 21 | kIOCFSerializeToBinary = 0x00000001U, 22 | }; 23 | 24 | enum 25 | { 26 | kIOClassNameOverrideNone = 0x00000001U, 27 | }; 28 | 29 | enum 30 | { 31 | kIOMapAnywhere = 0x00000001U, 32 | }; 33 | 34 | enum 35 | { 36 | kIORegistryIterateRecursively = 0x00000001U, 37 | kIORegistryIterateParents = 0x00000002U, 38 | }; 39 | 40 | enum 41 | { 42 | kOSSerializeDictionary = 0x01000000U, 43 | kOSSerializeArray = 0x02000000U, 44 | kOSSerializeSet = 0x03000000U, 45 | kOSSerializeNumber = 0x04000000U, 46 | kOSSerializeSymbol = 0x08000000U, 47 | kOSSerializeString = 0x09000000U, 48 | kOSSerializeData = 0x0a000000U, 49 | kOSSerializeBoolean = 0x0b000000U, 50 | kOSSerializeObject = 0x0c000000U, 51 | 52 | kOSSerializeTypeMask = 0x7F000000U, 53 | kOSSerializeDataMask = 0x00FFFFFFU, 54 | 55 | kOSSerializeEndCollection = 0x80000000U, 56 | 57 | kOSSerializeMagic = 0x000000d3U, 58 | }; 59 | 60 | extern const mach_port_t kIOMasterPortDefault; 61 | 62 | CF_RETURNS_RETAINED CFDataRef IOCFSerialize(CFTypeRef object, CFOptionFlags options); 63 | CFTypeRef IOCFUnserializeWithSize(const char *buf, size_t len, CFAllocatorRef allocator, CFOptionFlags options, CFStringRef *err); 64 | 65 | kern_return_t IOObjectRetain(io_object_t object); 66 | kern_return_t IOObjectRelease(io_object_t object); 67 | boolean_t IOObjectConformsTo(io_object_t object, const io_name_t name); 68 | uint32_t IOObjectGetKernelRetainCount(io_object_t object); 69 | kern_return_t IOObjectGetClass(io_object_t object, io_name_t name); 70 | kern_return_t _IOObjectGetClass(io_object_t object, uint64_t options, io_name_t name); 71 | CFStringRef IOObjectCopyClass(io_object_t object); 72 | CFStringRef _IOObjectCopyClass(io_object_t object, uint64_t options); 73 | CFStringRef IOObjectCopySuperclassForClass(CFStringRef name); 74 | CFStringRef IOObjectCopyBundleIdentifierForClass(CFStringRef name); 75 | 76 | io_registry_entry_t IORegistryGetRootEntry(mach_port_t master); 77 | io_registry_entry_t IORegistryEntryFromPath(mach_port_t master, const io_string_t path); 78 | kern_return_t IORegistryEntryGetName(io_registry_entry_t entry, io_name_t name); 79 | kern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID); 80 | kern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path); 81 | kern_return_t IORegistryEntryGetProperty(io_registry_entry_t entry, const io_name_t name, io_struct_inband_t buffer, uint32_t *size); 82 | kern_return_t IORegistryEntryCreateCFProperties(io_registry_entry_t entry, CFMutableDictionaryRef *properties, CFAllocatorRef allocator, uint32_t options); 83 | CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, uint32_t options); 84 | kern_return_t IORegistryEntrySetCFProperties(io_registry_entry_t entry, CFTypeRef properties); 85 | 86 | kern_return_t IORegistryCreateIterator(mach_port_t master, const io_name_t plane, uint32_t options, io_iterator_t *it); 87 | kern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, const io_name_t plane, uint32_t options, io_iterator_t *it); 88 | kern_return_t IORegistryEntryGetChildIterator(io_registry_entry_t entry, const io_name_t plane, io_iterator_t *it); 89 | kern_return_t IORegistryEntryGetParentIterator(io_registry_entry_t entry, const io_name_t plane, io_iterator_t *it); 90 | io_object_t IOIteratorNext(io_iterator_t it); 91 | boolean_t IOIteratorIsValid(io_iterator_t it); 92 | void IOIteratorReset(io_iterator_t it); 93 | 94 | CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED; 95 | CFMutableDictionaryRef IOServiceNameMatching(const char *name) CF_RETURNS_RETAINED; 96 | io_service_t IOServiceGetMatchingService(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT); 97 | kern_return_t IOServiceGetMatchingServices(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT, io_iterator_t *it); 98 | kern_return_t _IOServiceGetAuthorizationID(io_service_t service, uint64_t *authID); 99 | kern_return_t _IOServiceSetAuthorizationID(io_service_t service, uint64_t authID); 100 | kern_return_t IOServiceGetBusyStateAndTime(io_service_t service, uint64_t *state, uint32_t *busyState, uint64_t *busyTime); 101 | kern_return_t IOServiceOpen(io_service_t service, task_t task, uint32_t type, io_connect_t *client); 102 | kern_return_t IOServiceClose(io_connect_t client); 103 | kern_return_t IOCloseConnection(io_connect_t client); 104 | kern_return_t IOConnectAddRef(io_connect_t client); 105 | kern_return_t IOConnectRelease(io_connect_t client); 106 | kern_return_t IOConnectGetService(io_connect_t client, io_service_t *service); 107 | kern_return_t IOConnectAddClient(io_connect_t client, io_connect_t other); 108 | kern_return_t IOConnectSetNotificationPort(io_connect_t client, uint32_t type, mach_port_t port, uintptr_t ref); 109 | kern_return_t IOConnectMapMemory64(io_connect_t client, uint32_t type, task_t task, mach_vm_address_t *addr, mach_vm_size_t *size, uint32_t options); 110 | kern_return_t IOConnectUnmapMemory64(io_connect_t client, uint32_t type, task_t task, mach_vm_address_t addr); 111 | kern_return_t IOConnectSetCFProperties(io_connect_t client, CFTypeRef properties); 112 | kern_return_t IOConnectCallMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, const void *inStruct, size_t inStructCnt, uint64_t *out, uint32_t *outCnt, void *outStruct, size_t *outStructCnt); 113 | kern_return_t IOConnectCallScalarMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt); 114 | kern_return_t IOConnectCallStructMethod(io_connect_t client, uint32_t selector, const void *inStruct, size_t inStructCnt, void *outStruct, size_t *outStructCnt); 115 | kern_return_t IOConnectCallAsyncMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const uint64_t *in, uint32_t inCnt, const void *inStruct, size_t inStructCnt, uint64_t *out, uint32_t *outCnt, void *outStruct, size_t *outStructCnt); 116 | kern_return_t IOConnectCallAsyncScalarMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt); 117 | kern_return_t IOConnectCallAsyncStructMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const void *inStruct, size_t inStructCnt, void *outStruct, size_t *outStructCnt); 118 | kern_return_t IOConnectTrap6(io_connect_t client, uint32_t index, uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e, uintptr_t f); 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /src/ioprint.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2022 Siguza 2 | * 3 | * This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | * 7 | * This Source Code Form is "Incompatible With Secondary Licenses", as 8 | * defined by the Mozilla Public License, v. 2.0. 9 | **/ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "cfj.h" 19 | #include "common.h" 20 | #include "iokit.h" 21 | 22 | static bool printEntry(io_object_t o, const char *match, bool hdr, bool xml, bool cfj, bool json, bool set) 23 | { 24 | static CFDictionaryRef dict = NULL; 25 | if(set && dict == NULL) 26 | { 27 | CFStringRef key = CFSTR("herp"); 28 | CFStringRef val = CFSTR("derp"); 29 | dict = CFDictionaryCreate(NULL, (const void**)&key, (const void**)&val, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 30 | if(dict == NULL) 31 | { 32 | ERR(COLOR_RED "Failed to create dict" COLOR_RESET); 33 | return false; 34 | } 35 | } 36 | 37 | io_name_t name; 38 | kern_return_t ret = IORegistryEntryGetName(o, name); 39 | if(ret != KERN_SUCCESS) 40 | { 41 | ERR(COLOR_RED "IORegistryEntryGetName: %s" COLOR_RESET, mach_error_string(ret)); 42 | return false; 43 | } 44 | if(!match || IOObjectConformsTo(o, match) || strcmp(name, match) == 0) 45 | { 46 | io_name_t class; 47 | ret = _IOObjectGetClass(o, kIOClassNameOverrideNone, class); 48 | if(ret != KERN_SUCCESS) 49 | { 50 | ERR(COLOR_RED "class(%s): %s" COLOR_RESET, name, mach_error_string(ret)); 51 | return false; 52 | } 53 | 54 | if(set) 55 | { 56 | kern_return_t ret = IORegistryEntrySetCFProperties(o, dict); 57 | if(hdr) 58 | { 59 | LOG("%s%s(%s):%s %s%s%s", 60 | COLOR_CYAN, class, name, COLOR_RESET, 61 | ret == KERN_SUCCESS ? COLOR_GREEN : COLOR_YELLOW, mach_error_string(ret), COLOR_RESET 62 | ); 63 | } 64 | } 65 | if(xml || cfj || json) 66 | { 67 | CFMutableDictionaryRef p = NULL; 68 | kern_return_t ret = IORegistryEntryCreateCFProperties(o, &p, NULL, 0); 69 | if(hdr && !set) 70 | { 71 | LOG("%s%s(%s):%s %s%s%s", 72 | COLOR_CYAN, class, name, COLOR_RESET, 73 | ret == KERN_SUCCESS ? COLOR_GREEN : COLOR_YELLOW, mach_error_string(ret), COLOR_RESET 74 | ); 75 | } 76 | if(ret == KERN_SUCCESS) 77 | { 78 | if(xml) 79 | { 80 | CFDataRef prop = CFPropertyListCreateData(NULL, p, kCFPropertyListXMLFormat_v1_0, 0, NULL); 81 | if(prop) 82 | { 83 | LOG("%.*s", (int)CFDataGetLength(prop), CFDataGetBytePtr(prop)); 84 | CFRelease(prop); 85 | } 86 | else 87 | { 88 | CFShow(p); 89 | } 90 | } 91 | if(cfj) 92 | { 93 | cfj_print(stdout, p, false, true); 94 | } 95 | if(json) 96 | { 97 | cfj_print(stdout, p, true, false); 98 | } 99 | CFRelease(p); 100 | } 101 | } 102 | else if(hdr && !set) 103 | { 104 | LOG("%s%s(%s)%s", COLOR_CYAN, class, name, COLOR_RESET); 105 | } 106 | } 107 | return true; 108 | } 109 | 110 | static void print_help(const char *self) 111 | { 112 | fprintf(stderr, "Usage:\n" 113 | " %s [options] [name]\n" 114 | "\n" 115 | "Description:\n" 116 | " Iterate over all registry entries and optionally perform some operations.\n" 117 | " If name is given, only entries with matching class or instance name are considered.\n" 118 | "\n" 119 | "Options:\n" 120 | " -d Print IOKit properties in XML format\n" 121 | " -h Print this help and exit\n" 122 | " -j Print IOKit properties in JSON format\n" 123 | " -k Print IOKit properties in mix between JSON and hexdump\n" 124 | " -o Print only IOKit properties and nothing else\n" 125 | " -p plane Iterate over the given registry plane (default: IOService)\n" 126 | " -s Try to set the entries' properties\n" 127 | , self 128 | ); 129 | } 130 | 131 | int main(int argc, const char **argv) 132 | { 133 | bool hdr = true, 134 | xml = false, 135 | cfj = false, 136 | json = false, 137 | set = false; 138 | const char *plane = "IOService"; 139 | int aoff; 140 | for(aoff = 1; aoff < argc; ++aoff) 141 | { 142 | if(argv[aoff][0] != '-') 143 | { 144 | break; 145 | } 146 | bool opt = true; 147 | for(size_t i = 1; opt; ++i) 148 | { 149 | char c = argv[aoff][i]; 150 | if(c == '\0') 151 | { 152 | break; 153 | } 154 | switch(c) 155 | { 156 | case 'h': 157 | print_help(argv[0]); 158 | return -1; 159 | 160 | case 'd': 161 | xml = true; 162 | break; 163 | 164 | case 'j': 165 | json = true; 166 | break; 167 | 168 | case 'k': 169 | cfj = true; 170 | break; 171 | 172 | case 'o': 173 | hdr = false; 174 | break; 175 | 176 | case 's': 177 | set = true; 178 | break; 179 | 180 | case 'p': 181 | if(argv[aoff][i+1] != '\0' || ++aoff >= argc) 182 | { 183 | ERR(COLOR_RED "Missing argument to -p" COLOR_RESET); 184 | printf("\n"); 185 | print_help(argv[0]); 186 | return -1; 187 | } 188 | plane = argv[aoff]; 189 | opt = false; 190 | break; 191 | 192 | default: 193 | ERR(COLOR_RED "Unrecognized argument: %s" COLOR_RESET, argv[aoff]); 194 | printf("\n"); 195 | print_help(argv[0]); 196 | return -1; 197 | } 198 | } 199 | } 200 | 201 | const char *match = aoff < argc ? argv[aoff] : NULL; 202 | io_object_t o = IORegistryGetRootEntry(kIOMasterPortDefault); 203 | bool succ = printEntry(o, match, hdr, xml, cfj, json, set); 204 | IOObjectRelease(o); 205 | if(!succ) 206 | { 207 | return -1; 208 | } 209 | 210 | int retval = 0; 211 | io_iterator_t it = MACH_PORT_NULL; 212 | if(IORegistryCreateIterator(kIOMasterPortDefault, plane, kIORegistryIterateRecursively, &it) == KERN_SUCCESS) 213 | { 214 | while((o = IOIteratorNext(it)) != 0) 215 | { 216 | succ = printEntry(o, match, hdr, xml, cfj, json, set); 217 | IOObjectRelease(o); 218 | if(!succ) 219 | { 220 | retval = -1; 221 | break; 222 | } 223 | } 224 | IOObjectRelease(it); 225 | } 226 | return retval; 227 | } 228 | -------------------------------------------------------------------------------- /src/ioscan.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017-2021 Siguza 2 | * 3 | * This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | * 7 | * This Source Code Form is "Incompatible With Secondary Licenses", as 8 | * defined by the Mozilla Public License, v. 2.0. 9 | **/ 10 | 11 | #include // errno 12 | #include // floor, log2 13 | #include // bool, true, false 14 | #include // uint32_t, uint64_t 15 | #include // strtol, malloc 16 | #include // strerror, strlcpy 17 | 18 | #include // kern_return_t, KERN_SUCCESS 19 | #include // mach_error_string 20 | #include // mach_port_t 21 | #include // mach_host_self 22 | #include // MACH_PORT_NULL, MACH_PORT_VALID 23 | 24 | #include "common.h" 25 | #include "iokit.h" 26 | 27 | typedef struct ioscan 28 | { 29 | struct ioscan *next; 30 | io_name_t class; 31 | io_name_t ucClass; 32 | io_name_t name; 33 | uint32_t type; 34 | kern_return_t spawn; 35 | io_connect_t one; 36 | io_connect_t two; 37 | } ioscan_t; 38 | 39 | static ioscan_t** processEntry(io_object_t o, const char *plane, const char *match, uint32_t min, uint32_t max, bool only_success, ioscan_t **ptr) 40 | { 41 | io_name_t name; 42 | kern_return_t ret = IORegistryEntryGetName(o, name); 43 | if(ret != KERN_SUCCESS) 44 | { 45 | name[0] = '\0'; 46 | } 47 | if(!match || IOObjectConformsTo(o, match) || (name[0] && strcmp(name, match) == 0)) 48 | { 49 | io_name_t class; 50 | ret = _IOObjectGetClass(o, kIOClassNameOverrideNone, class); 51 | if(ret != KERN_SUCCESS) 52 | { 53 | class[0] = '\0'; 54 | } 55 | for(uint32_t i = min; i <= max; ++i) 56 | { 57 | io_connect_t one = MACH_PORT_NULL, 58 | two = MACH_PORT_NULL; 59 | ret = IOServiceOpen(o, mach_task_self(), i, &one); 60 | if(ret == KERN_SUCCESS && MACH_PORT_VALID(one)) 61 | { 62 | IOServiceOpen(o, mach_task_self(), i, &two); 63 | } 64 | 65 | if(!only_success || ret == KERN_SUCCESS) 66 | { 67 | ioscan_t *data = malloc(sizeof(ioscan_t)); 68 | if(!data) 69 | { 70 | ERR(COLOR_RED "Failed to allocate entry for %s: %s" COLOR_RESET, name, strerror(errno)); 71 | return NULL; 72 | } 73 | data->next = NULL; 74 | data->class[0] = '\0'; 75 | data->ucClass[0] = '\0'; 76 | data->name[0] = '\0'; 77 | data->type = i; 78 | data->spawn = ret; 79 | data->one = one; 80 | data->two = two; 81 | 82 | strlcpy(data->name, name, sizeof(io_name_t)); 83 | strlcpy(data->class, class, sizeof(io_name_t)); 84 | 85 | if(ret == KERN_SUCCESS && MACH_PORT_VALID(one)) 86 | { 87 | io_iterator_t it = MACH_PORT_NULL; 88 | if(IORegistryEntryGetChildIterator(o, plane, &it) == KERN_SUCCESS) 89 | { 90 | io_object_t client = MACH_PORT_NULL; 91 | while((client = IOIteratorNext(it)) != 0) 92 | { 93 | io_struct_inband_t buf; 94 | uint32_t len = sizeof(buf); 95 | ret = IORegistryEntryGetProperty(client, "IOUserClientCreator", buf, &len); 96 | if(ret == KERN_SUCCESS) 97 | { 98 | uint32_t pid; 99 | if(sscanf(buf, "pid %u,", &pid) == 1) 100 | { 101 | if(pid == getpid()) 102 | { 103 | io_name_t ucClass; 104 | ret = _IOObjectGetClass(client, kIOClassNameOverrideNone, ucClass); 105 | if(ret == KERN_SUCCESS) 106 | { 107 | strlcpy(data->ucClass, ucClass, sizeof(io_name_t)); 108 | } 109 | IOObjectRelease(client); 110 | break; 111 | } 112 | } 113 | } 114 | IOObjectRelease(client); 115 | } 116 | IOObjectRelease(it); 117 | } 118 | } 119 | 120 | *ptr = data; 121 | ptr = &data->next; 122 | } 123 | 124 | if(one) IOServiceClose(one); 125 | if(two) IOServiceClose(two); 126 | } 127 | } 128 | return ptr; 129 | } 130 | 131 | static void print_help(const char *self) 132 | { 133 | printf("Usage:\n" 134 | " %s [options] [name [min [max]]]\n" 135 | "\n" 136 | "Description:\n" 137 | " Iterate over all registry entries and try to spawn UserClients.\n" 138 | " If name is given, only entries with matching class or instance name are considered.\n" 139 | " If min and max are given, all types in between are tried.\n" 140 | " If only min is given, only that type is tried, otherwise it defaults to type 0.\n" 141 | "\n" 142 | "Options:\n" 143 | " -h Print this help and exit\n" 144 | " -p plane Iterate over the given registry plane (default: IOService)\n" 145 | " -s Print only successful spawning attempts\n" 146 | , self 147 | ); 148 | } 149 | 150 | int main(int argc, const char **argv) 151 | { 152 | bool only_success = false; 153 | const char *plane = "IOService"; 154 | int aoff; 155 | for(aoff = 1; aoff < argc; ++aoff) 156 | { 157 | if(argv[aoff][0] != '-') 158 | { 159 | break; 160 | } 161 | else if(strcmp(argv[aoff], "-h") == 0) 162 | { 163 | print_help(argv[0]); 164 | return -1; 165 | } 166 | else if(strcmp(argv[aoff], "-p") == 0) 167 | { 168 | ++aoff; 169 | if(aoff >= argc) 170 | { 171 | ERR(COLOR_RED "Missing argument to -p" COLOR_RESET); 172 | printf("\n"); 173 | print_help(argv[0]); 174 | return -1; 175 | } 176 | plane = argv[aoff]; 177 | } 178 | else if(strcmp(argv[aoff], "-s") == 0) 179 | { 180 | only_success = true; 181 | } 182 | else 183 | { 184 | ERR(COLOR_RED "Unrecognized argument: %s" COLOR_RESET, argv[aoff]); 185 | printf("\n"); 186 | print_help(argv[0]); 187 | return -1; 188 | } 189 | } 190 | 191 | const char *match = NULL; 192 | uint32_t min = 0, 193 | max = 0; 194 | if(aoff < argc) 195 | { 196 | match = argv[aoff]; 197 | ++aoff; 198 | if(aoff < argc) 199 | { 200 | min = max = (uint32_t)strtol(argv[aoff], NULL, 0); 201 | ++aoff; 202 | if(aoff < argc) 203 | { 204 | max = (uint32_t)strtol(argv[aoff], NULL, 0); 205 | ++aoff; 206 | } 207 | } 208 | } 209 | 210 | // Need to get all entries here, because spawning clients invalidates our iterator 211 | size_t num = 1024, 212 | idx = 0; 213 | io_object_t *objs = malloc(num * sizeof(io_object_t)); 214 | if(!objs) 215 | { 216 | ERR(COLOR_RED "Failed to allocate objects buffer: %s" COLOR_RESET, strerror(errno)); 217 | return -1; 218 | } 219 | 220 | objs[idx++] = IORegistryGetRootEntry(kIOMasterPortDefault); 221 | io_iterator_t it = MACH_PORT_NULL; 222 | if(IORegistryCreateIterator(kIOMasterPortDefault, plane, kIORegistryIterateRecursively, &it) == KERN_SUCCESS) 223 | { 224 | io_object_t o; 225 | while((o = IOIteratorNext(it)) != 0) 226 | { 227 | if(idx >= num) 228 | { 229 | num *= 2; 230 | objs = realloc(objs, num * sizeof(io_object_t)); 231 | if(!objs) 232 | { 233 | ERR(COLOR_RED "Failed to reallocate objects buffer: %s" COLOR_RESET, strerror(errno)); 234 | return -1; 235 | } 236 | } 237 | objs[idx++] = o; 238 | } 239 | IOObjectRelease(it); 240 | } 241 | 242 | ioscan_t *head = NULL, 243 | **ptr = &head; 244 | for(size_t i = 0; i < idx; ++i) 245 | { 246 | ptr = processEntry(objs[i], plane, match, min, max, only_success, ptr); 247 | if(!ptr) 248 | { 249 | for(; i < idx; ++i) 250 | { 251 | IOObjectRelease(objs[i]); 252 | } 253 | free(objs); 254 | objs = NULL; 255 | for(ioscan_t *node = head; node != NULL; ) 256 | { 257 | ioscan_t *next = node->next; 258 | free(node); 259 | node = next; 260 | } 261 | return -1; 262 | } 263 | IOObjectRelease(objs[i]); 264 | } 265 | free(objs); 266 | objs = NULL; 267 | 268 | int classLen = strlen("Class"), 269 | nameLen = strlen("Name"), 270 | typeLen = strlen("Type"), 271 | spawnLen = strlen("Spawn"), 272 | ucLen = strlen("UC"), 273 | oneLen = strlen("One"), 274 | twoLen = strlen("Two"), 275 | equalLen = strlen("Equal"); 276 | 277 | for(ioscan_t *node = head; node != NULL; node = node->next) 278 | { 279 | int l = strlen(node->class[0] ? node->class : "failed"); 280 | if(l > classLen) classLen = l; 281 | l = strlen(node->name); 282 | if(l == 0) 283 | { 284 | l = strlen("failed"); 285 | } 286 | if(l > nameLen) nameLen = l; 287 | l = 1 + (node->type == 0 ? 0 : (int)floor(log10(node->type))); // Decimal 288 | if(l > typeLen) typeLen = l; 289 | l = strlen(mach_error_string(node->spawn)); 290 | if(l > spawnLen) spawnLen = l; 291 | l = strlen(node->ucClass); 292 | if(l > ucLen) ucLen = l; 293 | l = 1 + (node->one == 0 ? 0 : (int)floor(log2(node->one) / 4)); // Hex 294 | if(l > oneLen) oneLen = l; 295 | l = 1 + (node->two == 0 ? 0 : (int)floor(log2(node->two) / 4)); // Hex 296 | if(l > twoLen) twoLen = l; 297 | } 298 | 299 | LOG(COLOR_CYAN "%-*s %-*s %*s %-*s %-*s %*s %*s %-*s" COLOR_RESET, 300 | classLen, "Class", 301 | nameLen, "Name", 302 | typeLen, "Type", 303 | spawnLen, "Spawn", 304 | ucLen, "UC", 305 | oneLen, "One", 306 | twoLen, "Two", 307 | equalLen, "Equal" 308 | ); 309 | for(ioscan_t *node = head; node != NULL; ) 310 | { 311 | ioscan_t *next = node->next; 312 | LOG("%s%-*s%s %s%-*s%s %s%*u%s %s%-*s%s %s%-*s%s %*x %*x %-*s", 313 | node->class[0] ? "" : COLOR_RED, classLen, node->class[0] ? node->class : "failed", node->class[0] ? "" : COLOR_RESET, 314 | node->name[0] ? "" : COLOR_RED, nameLen, node->name[0] ? node->name : "failed", node->name[0] ? "" : COLOR_RESET, 315 | COLOR_PURPLE, typeLen, node->type, COLOR_RESET, 316 | node->spawn == KERN_SUCCESS ? COLOR_GREEN : COLOR_YELLOW, spawnLen, mach_error_string(node->spawn), COLOR_RESET, 317 | COLOR_BLUE, ucLen, node->ucClass, COLOR_RESET, 318 | oneLen, node->one, 319 | twoLen, node->two, 320 | equalLen, node->two == 0 ? "" : node->one == node->two ? "==" : "!="); 321 | free(node); 322 | node = next; 323 | } 324 | 325 | return 0; 326 | } 327 | --------------------------------------------------------------------------------