├── .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 5 ustar 00molt wheel 000000 000000 ./usr/ 000755 000765 000000 00000000000 13001240260 012121 5 ustar 00molt wheel 000000 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 |
--------------------------------------------------------------------------------