This commit is contained in:
Karmaz95
2024-03-15 22:22:41 +01:00
parent dceee00b32
commit a0355a6f29
14 changed files with 1748 additions and 109026 deletions
+4 -1
View File
@@ -303,4 +303,7 @@ Each Snake class will be a child of the previous one and infinitely "eat itself"
* Make testing branch and implement tests, before pushing new updates.
* Create `RottenApple.app` in another repository and use it for testing.
* Add Dyld Closure chapter to Snake&Apple V - Dyld
* Move `dumpPrelink_info` and `dumpPrelink_text` to Snake & Apple chapter about Kernel Extensions when ready.
* Move `kext_prelinkinfo`, `dumpPrelink_info` and `dumpPrelink_text` to Snake & Apple chapter about Kernel Extensions when ready.
* Add kernelcache parser.
* Add `LC_FILESET_ENTRY` method to `dumpKernelExtension`.
* Consider moving methods like `removeNullBytesAlignment`, `calcTwoComplement64` etc. to `Utils` class.
@@ -0,0 +1,215 @@
void _initializeAppleMobileFileIntegrity(void)
{
bool bVar1;
int iVar2;
int iVar3;
undefined8 uVar4;
ulong uVar5;
long *plVar6;
long lVar7;
uint local_d4;
ulong local_d0;
undefined8 uStack_c8;
undefined8 uStack_c0;
undefined8 uStack_b8;
undefined8 local_b0;
undefined8 uStack_a8;
undefined8 uStack_a0;
undefined8 local_98;
undefined8 local_90;
undefined8 uStack_88;
undefined8 uStack_80;
undefined8 uStack_78;
undefined8 local_70;
undefined8 uStack_68;
undefined8 uStack_60;
undefined8 uStack_58;
undefined8 local_50;
undefined8 uStack_48;
undefined8 local_38;
local_38 = *(undefined8 *)PTR_DAT_fffffe0007e6ba68;
uVar4 = func_0xfffffe0008c3cf30();
func_0xfffffe00085a8e38();
uVar5 = func_0xfffffe0008bbcd34(0,uVar4,&_driverLock);
if ((uVar5 & 1) == 0) {
return;
}
_AMFILockGroup = func_0xfffffe00085a8478("AMFI",0);
initLibraryConstraints();
_overrideUnrestrictedDebugging = 0;
func_0xfffffe0008aa1474(&_sysctl__hw_features_allows_security_research);
_allows_security_research = 0;
uStack_48 = 0;
local_50 = 0;
uStack_68 = 0;
local_70 = 0;
uStack_58 = 0;
uStack_60 = 0;
uStack_88 = 0;
local_90 = 0;
uStack_78 = 0;
uStack_80 = 0;
uStack_a8 = 0;
local_b0 = 0;
local_98 = 0;
uStack_a0 = 0;
uStack_c8 = 0;
local_d0 = 0;
uStack_b8 = 0;
uStack_c0 = 0;
uVar4 = func_0xfffffe0009915f8c();
iVar2 = func_0xfffffe0009910330(uVar4,&local_d0);
if (iVar2 != 0) {
func_0xfffffe0008da4510("\"AMFI: No chip from IMG4? errno: %d\" @%s:%d");
return;
}
if ((uStack_a0._5_1_ != '\0') || ((int)local_98 == 1)) {
_allows_security_research = 1;
}
local_d4 = 0;
iVar2 = func_0xfffffe0008d70830("amfi_allow_research",&local_d4,4);
if ((iVar2 != 0) && (local_d4 != 0)) {
func_0xfffffe0008c3c908("AMFI: Allowing research due to amfi_allow_research boot arg");
_allows_security_research = 1;
}
local_d0 = local_d0 & 0xffffffff00000000;
iVar2 = func_0xfffffe0008a49ecc(8);
if (iVar2 == 0) {
local_d4 = 0;
func_0xfffffe0008d70830("amfi",&local_d4,4);
iVar2 = func_0xfffffe0008d70830("amfi_unrestrict_task_for_pid",&local_d0,4);
if (((iVar2 != 0) && ((int)local_d0 != 0)) || ((local_d4 & 1) != 0)) {
func_0xfffffe0008c3c908("%s: unrestricted task_for_pid enabled by boot-arg\n");
_overrideUnrestrictedDebugging = 1;
_BootedDevice = 1;
}
iVar2 = func_0xfffffe0008d70830("amfi_dev_mode_policy",&local_d0,4);
if ((iVar2 != 0) && ((int)local_d0 != 0)) {
func_0xfffffe0008c3c908("%s: developer mode internal policy disabled by boot-arg\n");
DAT_fffffe0007e74790 = 1;
}
iVar2 = func_0xfffffe0008d70830("amfi_allow_any_signature",&local_d0,4);
if (((iVar2 != 0) && ((int)local_d0 != 0)) || (((byte)local_d4 >> 1 & 1) != 0)) {
func_0xfffffe0008c3c908("%s: signature enforcement disabled by boot-arg\n");
/* WARNING: Read-only address (ram,0xfffffe0007e7478b) is written */
_DAT_fffffe0007e7478a = CONCAT11(DAT_fffffe0007e7478b,1);
}
iVar2 = func_0xfffffe0008d70830("amfi_get_out_of_my_way",&local_d0,4);
if (((iVar2 != 0) && ((int)local_d0 != 0)) || ((local_d4 >> 7 & 1) != 0)) {
func_0xfffffe0008c3c908("%s: signature enforcement disabled by boot-arg\n");
_DAT_fffffe0007e7478a = 0x101;
}
if ((local_d4 >> 2 & 1) != 0) {
func_0xfffffe0008c3c908
("%s: library validation will not mark external binaries as platform\n");
DAT_fffffe0007e7478f = 1;
}
iVar2 = func_0xfffffe0008d70830("amfi_unrestricted_local_signing",&local_d0,4);
if ((iVar2 != 0) && ((int)local_d0 != 0)) {
func_0xfffffe0008c3c908("%s: unrestricted AMFI local signing enabled by boot-arg\n");
DAT_fffffe0007e7478c = 1;
}
}
iVar2 = func_0xfffffe0008d70830("amfi_ready_to_roll",&local_d0,4);
if ((iVar2 != 0) && ((int)local_d0 != 0)) {
func_0xfffffe0008c3c908("%s: practice a key roll\n");
_readyToRoll = 1;
}
iVar2 = func_0xfffffe0008d70830("cs_enforcement_disable",&local_d0,4);
bVar1 = (int)local_d0 != 0;
if (iVar2 != 0 && bVar1) {
func_0xfffffe0008c3c908("%s: cs_enforcement disabled by boot-arg\n");
iVar3 = func_0xfffffe0008a49ecc(8);
if (iVar3 != 0) goto LAB_fffffe0009ac1ba8;
}
DAT_fffffe0007e7478e = iVar2 != 0 && bVar1;
InitializeDenylist();
_initializeCoreEntitlementsSupport(1);
precookExemptionProfile();
numJitHashCacheEntries = 0;
jitHashCache = 0;
jitHashCacheLock = func_0xfffffe0008c3cf30();
dyldSimCacheLock = func_0xfffffe0008c3cf30();
supplementalSigningInit();
_swiftPlaygroundsJIT = '\x01';
plVar6 = (long *)func_0xfffffe0008c45154("/",*(undefined8 *)PTR_DAT_fffffe0007e6bb00,0,0,0);
if (plVar6 == (long *)0x0) {
_initializeAppleMobileFileIntegrity();
LAB_fffffe0009ac1ba0:
_initializeAppleMobileFileIntegrity();
}
else {
uVar4 = (**(code **)(*plVar6 + 0x2d8))(plVar6,"model");
plVar6 = (long *)func_0xfffffe0008bbdca0(uVar4,*(undefined8 *)PTR_DAT_fffffe0007e6ba08);
if (plVar6 == (long *)0x0) goto LAB_fffffe0009ac1ba0;
uVar4 = (**(code **)(*plVar6 + 0x198))();
func_0xfffffe0008c3c908("AMFI: queried model name from device tree: %s\n");
lVar7 = func_0xfffffe00086ac444(uVar4,"iPhone",6);
if (lVar7 == 0) {
if (_swiftPlaygroundsJIT == '\0') goto LAB_fffffe0009ac17f4;
}
else {
func_0xfffffe0008c3c908("AMFI: disabling Swift Playgrounds JIT services on iPhone devices\n");
_swiftPlaygroundsJIT = '\0';
LAB_fffffe0009ac17f4:
func_0xfffffe0008ab4fe8(0x10000000);
func_0xfffffe0008ab4fe8(0x20000000);
}
_unrestrictedCDHashLock = func_0xfffffe0008c3cf30();
initTrustCacheAccess();
DAT_fffffe0007e747d0 = _cred_check_label_update_execve;
DAT_fffffe0007e747f8 = _cred_label_associate;
DAT_fffffe0007e74808 = _cred_label_destroy;
DAT_fffffe0007e74820 = _cred_label_init;
DAT_fffffe0007e74830 = _cred_label_update_execve;
DAT_fffffe0007e74b58 = _proc_check_inherit_ipc_ports;
DAT_fffffe0007e75120 = _vnode_check_signature;
DAT_fffffe0007e749a0 = _file_check_library_validation;
DAT_fffffe0007e74b40 = _policy_initbsd;
DAT_fffffe0007e74b48 = _policy_syscall;
DAT_fffffe0007e74ab8 = _task_id_token_get_task;
DAT_fffffe0007e747f0 = _cred_label_associate_kernel;
DAT_fffffe0007e748f8 = _proc_check_launch_constraints;
DAT_fffffe0007e74ba0 = amfi_exc_action_check_exception_send;
DAT_fffffe0007e74ba8 = amfi_exc_action_label_associate;
DAT_fffffe0007e74bb0 = amfi_exc_action_label_populate;
DAT_fffffe0007e74bb8 = amfi_exc_action_label_destroy;
DAT_fffffe0007e74bc0 = amfi_exc_action_label_init;
DAT_fffffe0007e74bc8 = amfi_exc_action_label_update;
DAT_fffffe0007e74d88 = macos_task_get_movable_control_port;
DAT_fffffe0007e75178 = hsp_proc_check_map_anon;
DAT_fffffe0007e74aa8 = macos_task_policy;
DAT_fffffe0007e74ab0 = macos_task_policy;
DAT_fffffe0007e74c88 = macos_task_control_policy;
DAT_fffffe0007e75138 = macos_proc_check_run_cs_invalid;
DAT_fffffe0007e75040 = hook_vnode_check_setextattr;
DAT_fffffe0007e74fc0 = hook_vnode_check_getextattr;
DAT_fffffe0007e748c0 = _file_check_mmap;
DAT_fffffe0007e751c0 = _vnode_notify_open;
DAT_fffffe0007e74cf8 = core_dump_policy;
DAT_fffffe0007e75158 = supplementalVnodeCheckSignature;
mac_policy = "AMFI";
DAT_fffffe0007e75220 = "Apple Mobile File Integrity";
DAT_fffffe0007e75228 = &_initializeAppleMobileFileIntegrity()::labelnamespaces;
DAT_fffffe0007e75230 = 1;
DAT_fffffe0007e75238 = &mac_ops;
DAT_fffffe0007e75240 = 0;
DAT_fffffe0007e75248 = &_amfi_mac_slot;
DAT_fffffe0007e75250 = 0;
iVar2 = func_0xfffffe0008d75b64(&mac_policy,&amfiPolicyHandle,0);
if (iVar2 == 0) {
configurationSettingsInit();
hardeningInit();
/* WARNING: Bad instruction - Truncating control flow here */
halt_baddata();
}
}
_initializeAppleMobileFileIntegrity();
LAB_fffffe0009ac1ba8:
_initializeAppleMobileFileIntegrity();
func_0xfffffe0008c3c908("%s\n");
func_0xfffffe0008da4510("\"Cannot unload AMFI - policy is not dynamic\\n\" @%s:%d");
return;
}
@@ -0,0 +1,134 @@
// Initialization function for Apple's Mobile File Integrity (AMFI) system
initializeAppleMobileFileIntegrity() {
// Allocating and locking mutex for thread safety
lock = IOLockAlloc();
lck_mtx_lock(lock);
// Checking if driver lock is not already set
if (OSCompareAndSwapPtr(0, lock, &driverLock))
// Initializing AMFI lock group
AMFILockGroup = lck_grp_alloc_init("AMFI", 0);
// Initializing library constraints
initLibraryConstraints();
// Registering system control variable
sysctl_register_oid(&sysctl__hw_features_allows_security_research);
// Selecting personalized chip(pointer to img4_chip_t)
chip = img4_chip_select_personalized_ap();
// Instantiating chip and checking for errors
chip_error = img4_chip_instantiate(chip);
if (chip_error)
panic("AMFI: No chip from IMG4? errno" + chip_error);
// Checking chip properties to enable security research (Apple Security Research Device Program - https://security.apple.com/research-device/?)
if (allow_security_reserach(chip))
allows_security_research = 1;
// Checking for boot-arg, e.g.:
// sudo nvram boot-args="amfi_get_out_of_my_way=1"
if (PE_parse_boot_argn("amfi_allow_research"))
IOLog("AMFI: Allowing research due to amfi_allow_research boot-arg");
allows_security_research = 1;
// Without this boor-arg, the entitlements get-task-allow and task_for_pid-allow are required to use task_for_pid if binary is signed
if (PE_parse_boot_argn("amfi_unrestrict_task_for_pid"))
IOLog("unrestricted task_for_pid enabled by boot-arg");
unrestricted_debugging = 1;
boot_device = 1;
if (PE_parse_boot_argn("amfi_dev_mode_policy"))
IOLog("developer mode internal policy disabled by boot-arg");
dev_mode = 1
if (PE_parse_boot_argn("amfi_allow_any_signature" | "amfi_get_out_of_my_way"))
IOLog("signature enforcement disabled by boot-arg");
IOLog("library validation will not mark external binaries as platform"); // NOT SURE
if (PE_parse_boot_argn("amfi_unrestricted_local_signing"))
IOLog("unrestricted AMFI local signing enabled by boot-arg");
if (PE_parse_boot_argn("amfi_ready_to_roll"))
IOLog("practice a key roll");
readyToRoll = true;
// Disabling code signing enforcement based on the boot-arg
if (PE_parse_boot_argn("cs_enforcement_disable"))
IOLog("cs_enforcement disabled by boot-arg")
// Finalizing initialization
InitializeDenylist();
_initializeCoreEntitlementsSupport(1); // Initialize support for entitlements and AMFI trust cache interface
// Initialize UDID enforcement the exemption profile (define components allowed to execute despite AMFI
precookExemptionProfile();
jitHashCacheLock = IOLockAlloc()
dyldSimCacheLock = IOLockAlloc()
supplementalSigningInit(); // Another lock
// Access device tree to get model name
model_name = IORegistryEntry::fromPath("/")
model_name = OSMetaClassBase::safeMetaCast(OSData::gMetaClass)
IOLog("AMFI: queried model name from device tree:" + model_name);
// Check if the model is iPhone
// If true disable Swift Playgrounds JIT services && some CS features
if (model_name == 'iPhone')
IOLog("AMFI: disabling Swift Playgrounds JIT services on iPhone devices");
_swiftPlaygroundsJIT == 0
disable_code_signing_feature(0x10000000);
disable_code_signing_feature(0x20000000);
// For not iPhones - initialize function pointers to AMFI handlers for various security checks
if (_swiftPlaygroundsJIT)
pointers_list = {
_cred_check_label_update_execve
_cred_label_associate
_cred_label_destroy
_cred_label_init
_cred_label_update_execve
_proc_check_inherit_ipc_ports
_vnode_check_signature // Check Code Signature handler
_file_check_library_validation // Check validation of a library file
_policy_initbsd // Final call from BSD for finalizing initialization of MACF ?
_policy_syscall // MACF policy syscall handler
_task_id_token_get_task
_cred_label_associate_kernel
_proc_check_launch_constraints // Check launch constraints for a process
amfi_exc_action_check_exception_send
amfi_exc_action_label_associate
amfi_exc_action_label_populate
amfi_exc_action_label_destroy
amfi_exc_action_label_init
amfi_exc_action_label_update
macos_task_get_movable_control_port
hsp_proc_check_map_anon
macos_task_policy
macos_task_control_policy
macos_proc_check_run_cs_invalid
hook_vnode_check_setextattr
hook_vnode_check_getextattr
_file_check_mmap
_vnode_notify_open
core_dump_policy
}
// Register MAC policy
mac_policy_register("AMFI", amfiPolicyHandle, 0)
// Set security policies and constraints for AMFI
configurationSettingsInit();
// Initialize a lock for exception list
hardeningInit()
// Unlocking driver lock
lck_mtx_unlock(driverLock);
// Unlocking mutex and freeing memory
lck_mtx_unlock(lock);
IOLockFree(lock);
lck_mtx_lock(driverLock);
}
+24
View File
@@ -0,0 +1,24 @@
-restore
BATS_TESTPLAN_ID
amfi
amfi_allow_3p_launch_constraints
amfi_allow_any_signature
amfi_allow_non_platform
amfi_allow_only_tc
amfi_allow_only_tc_override
amfi_allow_research
amfi_block_unsigned_code
amfi_dev_mode_policy
amfi_enforce_cc_types
amfi_enforce_launch_constraints
amfi_enforce_tcc_hardening
amfi_force_cs_kill
amfi_get_out_of_my_way
amfi_hsp_disable
amfi_hsp_logging
amfi_no_aot_tc
amfi_prevent_old_entitled_platform_binaries
amfi_ready_to_roll
amfi_unrestrict_task_for_pid
amfi_unrestricted_local_signing
cs_enforcement_disable
+30
View File
@@ -0,0 +1,30 @@
__ZN24AppleMobileFileIntegrity15copyEntitlementEP4procPKc
__ZN24AppleMobileFileIntegrity15copyEntitlementEP5ucredPKc
__ZN24AppleMobileFileIntegrity15getEntitlementsEP5ucred
__ZN24AppleMobileFileIntegrity16copyEntitlementsEP4proc
__ZN24AppleMobileFileIntegrity16copyEntitlementsEP5ucred
__ZN24AppleMobileFileIntegrity18copyEntitlementKeyEP4procP17__opaque_amfi_key
__ZN24AppleMobileFileIntegrity18copyEntitlementKeyEP5ucredP17__opaque_amfi_key
__ZN24AppleMobileFileIntegrity18isHardeningEnabledEv
__ZN24AppleMobileFileIntegrity19AMFIGetQueryContextEP4procPP14CEQueryContext
__ZN24AppleMobileFileIntegrity19AMFIGetQueryContextEP5ucredPP14CEQueryContext
__ZN24AppleMobileFileIntegrity21AMFIEntitlementGetKeyEPKc
__ZN24AppleMobileFileIntegrity21copySigningIdentifierEP5ucred
__ZN24AppleMobileFileIntegrity22AMFIEntitlementGetBoolEP4procPKcPb
__ZN24AppleMobileFileIntegrity22AMFIEntitlementGetBoolEP5ucredPKcPb
__ZN24AppleMobileFileIntegrity22AMFIEntitlementPresentEP4procPKcPb
__ZN24AppleMobileFileIntegrity22AMFIEntitlementPresentEP5ucredPKcPb
__ZN24AppleMobileFileIntegrity25AMFIEntitlementReleaseKeyEP17__opaque_amfi_key
__ZN24AppleMobileFileIntegrity26AMFIEntitlementGetConstKeyEPKc
__ZN24AppleMobileFileIntegrity27AMFIEntitlementKeyIsPresentEP4procP17__opaque_amfi_keyPb
__ZN24AppleMobileFileIntegrity27AMFIEntitlementKeyIsPresentEP5ucredP17__opaque_amfi_keyPb
__ZN24AppleMobileFileIntegrity28AMFIEntitlementKeyIsBoolTrueEP4procP17__opaque_amfi_keyPb
__ZN24AppleMobileFileIntegrity28AMFIEntitlementKeyIsBoolTrueEP5ucredP17__opaque_amfi_keyPb
__ZN24AppleMobileFileIntegrity29isCodeDirectoryHashInJitCacheEP4procPKh
__ZN24AppleMobileFileIntegrity9metaClassE
_amfi_register_mac_policy
_kmod_info
InitFunc_1
InitFunc_2
InitFunc_3
InitFunc_4
+652
View File
@@ -0,0 +1,652 @@
_Assert
_CTEvaluateAMFICodeSignatureCMS
_CTEvaluateAMFICodeSignatureCMSPubKey
_CTEvaluateProvisioningProfile
_IOCurrentTaskHasEntitlement
_IOFreeData
_IOFreeTypeImpl
_IOFreeTypeVarImpl
_IOLockAlloc
_IOLockFree
_IOLockLock
_IOLockUnlock
_IOLog
_IOLogv
_IOMallocData
_IOMallocTypeImpl
_IOMallocTypeVarImpl
_IOMallocZeroData
_IORWLockAlloc
_IORWLockRead
_IORWLockUnlock
_IORWLockWrite
_NDR_record
_OSCompareAndSwapPtr
_OSIncrementAtomic
_OSObject_typed_operator_delete
_OSObject_typed_operator_new
_PAGE_SHIFT_CONST
_PE_parse_boot_argn
_SecureDTGetProperty
_SecureDTLookupEntry
_VNOP_IOCTL
__Block_object_assign
__Block_object_dispose
__NSConcreteStackBlock
__Z16OSUnserializeXMLPKcmPP8OSString
__ZN11OSMetaClass21_RESERVEDOSMetaClass0Ev
__ZN11OSMetaClass21_RESERVEDOSMetaClass1Ev
__ZN11OSMetaClass21_RESERVEDOSMetaClass2Ev
__ZN11OSMetaClass21_RESERVEDOSMetaClass3Ev
__ZN11OSMetaClass21_RESERVEDOSMetaClass4Ev
__ZN11OSMetaClass21_RESERVEDOSMetaClass5Ev
__ZN11OSMetaClass21_RESERVEDOSMetaClass6Ev
__ZN11OSMetaClass21_RESERVEDOSMetaClass7Ev
__ZN11OSMetaClassC2EPKcPKS_j
__ZN11OSMetaClassC2EPKcPKS_jPP4zoneS1_19zone_create_flags_t
__ZN11OSMetaClassD2Ev
__ZN12IOUserClient10clientDiedEv
__ZN12IOUserClient10gMetaClassE
__ZN12IOUserClient10getServiceEv
__ZN12IOUserClient12initWithTaskEP4taskPvj
__ZN12IOUserClient13connectClientEPS_
__ZN12IOUserClient18clientHasPrivilegeEPvPKc
__ZN12IOUserClient19clientMemoryForTypeEjPjPP18IOMemoryDescriptor
__ZN12IOUserClient20exportObjectToClientEP4taskP8OSObjectPS3_
__ZN12IOUserClient22_RESERVEDIOUserClient0Ev
__ZN12IOUserClient22_RESERVEDIOUserClient1Ev
__ZN12IOUserClient22_RESERVEDIOUserClient2Ev
__ZN12IOUserClient22_RESERVEDIOUserClient3Ev
__ZN12IOUserClient22_RESERVEDIOUserClient4Ev
__ZN12IOUserClient22_RESERVEDIOUserClient5Ev
__ZN12IOUserClient22_RESERVEDIOUserClient6Ev
__ZN12IOUserClient22_RESERVEDIOUserClient7Ev
__ZN12IOUserClient22_RESERVEDIOUserClient8Ev
__ZN12IOUserClient22_RESERVEDIOUserClient9Ev
__ZN12IOUserClient23_RESERVEDIOUserClient10Ev
__ZN12IOUserClient23_RESERVEDIOUserClient11Ev
__ZN12IOUserClient23_RESERVEDIOUserClient12Ev
__ZN12IOUserClient23_RESERVEDIOUserClient13Ev
__ZN12IOUserClient23_RESERVEDIOUserClient14Ev
__ZN12IOUserClient23_RESERVEDIOUserClient15Ev
__ZN12IOUserClient23getExternalTrapForIndexEj
__ZN12IOUserClient24getNotificationSemaphoreEjPP9semaphore
__ZN12IOUserClient24getTargetAndTrapForIndexEPP9IOServicej
__ZN12IOUserClient24registerNotificationPortEP8ipc_portjj
__ZN12IOUserClient24registerNotificationPortEP8ipc_portjy
__ZN12IOUserClient25getExternalMethodForIndexEj
__ZN12IOUserClient26getTargetAndMethodForIndexEPP9IOServicej
__ZN12IOUserClient30getExternalAsyncMethodForIndexEj
__ZN12IOUserClient31getAsyncTargetAndMethodForIndexEPP9IOServicej
__ZN12IOUserClient4freeEv
__ZN12IOUserClient4initEP12OSDictionary
__ZN12IOUserClient4initEv
__ZN12IOUserClient8DispatchE5IORPC
__ZN12IOUserClientC2EPK11OSMetaClass
__ZN12IOUserClientD2Ev
__ZN12OSDictionary12withCapacityEj
__ZN12OSDictionary9metaClassE
__ZN12OSDictionary9setObjectEPKcRK11OSSharedPtrIK15OSMetaClassBaseE
__ZN12OSDictionary9setObjectERK11OSSharedPtrIK8OSSymbolERKS0_IK15OSMetaClassBaseE
__ZN15IORegistryEntry11detachAboveEPK15IORegistryPlane
__ZN15IORegistryEntry11setLocationEPK8OSSymbolPK15IORegistryPlane
__ZN15IORegistryEntry11setLocationEPKcPK15IORegistryPlane
__ZN15IORegistryEntry11setPropertyEPK8OSStringP8OSObject
__ZN15IORegistryEntry11setPropertyEPK8OSSymbolP8OSObject
__ZN15IORegistryEntry11setPropertyEPKcP8OSObject
__ZN15IORegistryEntry11setPropertyEPKcPvj
__ZN15IORegistryEntry11setPropertyEPKcS1_
__ZN15IORegistryEntry11setPropertyEPKcb
__ZN15IORegistryEntry11setPropertyEPKcyj
__ZN15IORegistryEntry13attachToChildEPS_PK15IORegistryPlane
__ZN15IORegistryEntry13childFromPathEPKcPK15IORegistryPlanePcPi
__ZN15IORegistryEntry13setPropertiesEP8OSObject
__ZN15IORegistryEntry14attachToParentEPS_PK15IORegistryPlane
__ZN15IORegistryEntry14removePropertyEPK8OSString
__ZN15IORegistryEntry14removePropertyEPK8OSSymbol
__ZN15IORegistryEntry14removePropertyEPKc
__ZN15IORegistryEntry15detachFromChildEPS_PK15IORegistryPlane
__ZN15IORegistryEntry16detachFromParentEPS_PK15IORegistryPlane
__ZN15IORegistryEntry16setPropertyTableEP12OSDictionary
__ZN15IORegistryEntry17runPropertyActionEPFiP8OSObjectPvS2_S2_S2_ES1_S2_S2_S2_S2_
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry0Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry1Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry2Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry3Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry4Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry5Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry6Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry7Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry8Ev
__ZN15IORegistryEntry25_RESERVEDIORegistryEntry9Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry10Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry11Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry12Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry13Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry14Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry15Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry16Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry17Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry18Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry19Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry20Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry21Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry22Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry23Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry24Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry25Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry26Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry27Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry28Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry29Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry30Ev
__ZN15IORegistryEntry26_RESERVEDIORegistryEntry31Ev
__ZN15IORegistryEntry7setNameEPK8OSSymbolPK15IORegistryPlane
__ZN15IORegistryEntry7setNameEPKcPK15IORegistryPlane
__ZN15IORegistryEntry8fromPathEPKcPK15IORegistryPlanePcPiPS_
__ZN15IORegistryEntry9detachAllEPK15IORegistryPlane
__ZN15OSMetaClassBase12safeMetaCastEPKS_PK11OSMetaClass
__ZN15OSMetaClassBase25_RESERVEDOSMetaClassBase0Ev
__ZN15OSMetaClassBase25_RESERVEDOSMetaClassBase1Ev
__ZN15OSMetaClassBase25_RESERVEDOSMetaClassBase2Ev
__ZN15OSMetaClassBase25_RESERVEDOSMetaClassBase3Ev
__ZN15OSMetaClassBase25_RESERVEDOSMetaClassBase4Ev
__ZN15OSMetaClassBase25_RESERVEDOSMetaClassBase5Ev
__ZN15OSMetaClassBase25_RESERVEDOSMetaClassBase6Ev
__ZN15OSMetaClassBase25_RESERVEDOSMetaClassBase7Ev
__ZN15OSMetaClassBase8DispatchE5IORPC
__ZN16CoreAnalyticsHub22analyticsSendEventLazyEP8OSStringP8OSObject
__ZN16CoreAnalyticsHub9metaClassE
__ZN18IOMemoryDescriptor11withAddressEPvyj
__ZN20OSCollectionIterator14withCollectionEPK12OSCollection
__ZN6OSData9metaClassE
__ZN6OSData9withBytesEPKvj
__ZN7OSArray12withCapacityEj
__ZN7OSArray9metaClassE
__ZN7OSArray9setObjectERK11OSSharedPtrIK15OSMetaClassBaseE
__ZN8OSNumber10withNumberEyj
__ZN8OSNumber9metaClassE
__ZN8OSObject10gMetaClassE
__ZN8OSObject18_RESERVEDOSObject0Ev
__ZN8OSObject18_RESERVEDOSObject1Ev
__ZN8OSObject18_RESERVEDOSObject2Ev
__ZN8OSObject18_RESERVEDOSObject3Ev
__ZN8OSObject18_RESERVEDOSObject4Ev
__ZN8OSObject18_RESERVEDOSObject5Ev
__ZN8OSObject18_RESERVEDOSObject6Ev
__ZN8OSObject18_RESERVEDOSObject7Ev
__ZN8OSObject18_RESERVEDOSObject8Ev
__ZN8OSObject18_RESERVEDOSObject9Ev
__ZN8OSObject19_RESERVEDOSObject10Ev
__ZN8OSObject19_RESERVEDOSObject11Ev
__ZN8OSObject19_RESERVEDOSObject12Ev
__ZN8OSObject19_RESERVEDOSObject13Ev
__ZN8OSObject19_RESERVEDOSObject14Ev
__ZN8OSObject19_RESERVEDOSObject15Ev
__ZN8OSObject4initEv
__ZN8OSObject8DispatchE5IORPC
__ZN8OSObjectC2EPK11OSMetaClass
__ZN8OSObjectD2Ev
__ZN8OSObjectdlEPvm
__ZN8OSObjectnwEm
__ZN8OSString11withCStringEPKc
__ZN8OSString11withCStringEPKcm
__ZN8OSString17withCStringNoCopyEPKc
__ZN8OSString9metaClassE
__ZN8OSSymbol10withStringEPK8OSString
__ZN8OSSymbol11withCStringEPKc
__ZN8OSSymbol17withCStringNoCopyEPKc
__ZN8OSSymbol9metaClassE
__ZN9IODTNVRAM9metaClassE
__ZN9IOService10adjustBusyEi
__ZN9IOService10gMetaClassE
__ZN9IOService10handleOpenEPS_jPv
__ZN9IOService10joinPMtreeEPS_
__ZN9IOService11getPlatformEv
__ZN9IOService11handleCloseEPS_j
__ZN9IOService12didTerminateEPS_jPb
__ZN9IOService12getBusyStateEv
__ZN9IOService12getResourcesEv
__ZN9IOService12requestProbeEj
__ZN9IOService12tellChangeUpEm
__ZN9IOService12updateReportEP19IOReportChannelListjPvS2_
__ZN9IOService13addPowerChildEPS_
__ZN9IOService13askChangeDownEm
__ZN9IOService13matchLocationEPS_
__ZN9IOService13messageClientEjP8OSObjectPvm
__ZN9IOService13newUserClientEP4taskPvjP12OSDictionaryPP12IOUserClient
__ZN9IOService13newUserClientEP4taskPvjPP12IOUserClient
__ZN9IOService13setPowerStateEmPS_
__ZN9IOService13willTerminateEPS_j
__ZN9IOService14activityTickleEmm
__ZN9IOService14applyToClientsEPFvPS_PvES1_
__ZN9IOService14causeInterruptEi
__ZN9IOService14messageClientsEjPvm
__ZN9IOService14tellChangeDownEm
__ZN9IOService14waitForServiceEP12OSDictionaryP13mach_timespec
__ZN9IOService15comparePropertyEP12OSDictionaryPK8OSString
__ZN9IOService15comparePropertyEP12OSDictionaryPKc
__ZN9IOService15configureReportEP19IOReportChannelListjPvS2_
__ZN9IOService15enableInterruptEi
__ZN9IOService15errnoFromReturnEi
__ZN9IOService15getDeviceMemoryEv
__ZN9IOService15nextIdleTimeoutEyyj
__ZN9IOService15powerChangeDoneEm
__ZN9IOService15registerServiceEj
__ZN9IOService15serviceMatchingEPKcP12OSDictionary
__ZN9IOService15setDeviceMemoryEP7OSArray
__ZN9IOService15terminateClientEPS_j
__ZN9IOService16allowPowerChangeEm
__ZN9IOService16applyToProvidersEPFvPS_PvES1_
__ZN9IOService16disableInterruptEi
__ZN9IOService16getInterruptTypeEiPi
__ZN9IOService16registerInterestEPK8OSSymbolPFiPvS3_jPS_S3_mES3_S3_
__ZN9IOService16removePowerChildEP17IOPowerConnection
__ZN9IOService16requestTerminateEPS_j
__ZN9IOService16stringFromReturnEi
__ZN9IOService16tellNoChangeDownEm
__ZN9IOService17addNeededResourceEPKc
__ZN9IOService17applyToInterestedEPK8OSSymbolPFvP8OSObjectPvES5_
__ZN9IOService17cancelPowerChangeEm
__ZN9IOService17comparePropertiesEP12OSDictionaryP12OSCollection
__ZN9IOService17getAggressivenessEmPm
__ZN9IOService17registerInterruptEiP8OSObjectPFvS1_PvPS_iES2_
__ZN9IOService17setAggressivenessEmm
__ZN9IOService18lockForArbitrationEb
__ZN9IOService18matchPropertyTableEP12OSDictionary
__ZN9IOService18matchPropertyTableEP12OSDictionaryPi
__ZN9IOService18setIdleTimerPeriodEm
__ZN9IOService18systemWillShutdownEj
__ZN9IOService19_RESERVEDIOService0Ev
__ZN9IOService19_RESERVEDIOService1Ev
__ZN9IOService19_RESERVEDIOService2Ev
__ZN9IOService19_RESERVEDIOService3Ev
__ZN9IOService19_RESERVEDIOService4Ev
__ZN9IOService19_RESERVEDIOService5Ev
__ZN9IOService19_RESERVEDIOService6Ev
__ZN9IOService19_RESERVEDIOService7Ev
__ZN9IOService19_RESERVEDIOService8Ev
__ZN9IOService19_RESERVEDIOService9Ev
__ZN9IOService19registerPowerDriverEPS_P14IOPMPowerStatem
__ZN9IOService19unregisterInterruptEi
__ZN9IOService20_RESERVEDIOService10Ev
__ZN9IOService20_RESERVEDIOService11Ev
__ZN9IOService20_RESERVEDIOService12Ev
__ZN9IOService20_RESERVEDIOService13Ev
__ZN9IOService20_RESERVEDIOService14Ev
__ZN9IOService20_RESERVEDIOService15Ev
__ZN9IOService20_RESERVEDIOService16Ev
__ZN9IOService20_RESERVEDIOService17Ev
__ZN9IOService20_RESERVEDIOService18Ev
__ZN9IOService20_RESERVEDIOService19Ev
__ZN9IOService20_RESERVEDIOService20Ev
__ZN9IOService20_RESERVEDIOService21Ev
__ZN9IOService20_RESERVEDIOService22Ev
__ZN9IOService20_RESERVEDIOService23Ev
__ZN9IOService20_RESERVEDIOService24Ev
__ZN9IOService20_RESERVEDIOService25Ev
__ZN9IOService20_RESERVEDIOService26Ev
__ZN9IOService20_RESERVEDIOService27Ev
__ZN9IOService20_RESERVEDIOService28Ev
__ZN9IOService20_RESERVEDIOService29Ev
__ZN9IOService20_RESERVEDIOService30Ev
__ZN9IOService20_RESERVEDIOService31Ev
__ZN9IOService20_RESERVEDIOService32Ev
__ZN9IOService20_RESERVEDIOService33Ev
__ZN9IOService20_RESERVEDIOService34Ev
__ZN9IOService20_RESERVEDIOService35Ev
__ZN9IOService20_RESERVEDIOService36Ev
__ZN9IOService20_RESERVEDIOService37Ev
__ZN9IOService20_RESERVEDIOService38Ev
__ZN9IOService20_RESERVEDIOService39Ev
__ZN9IOService20_RESERVEDIOService40Ev
__ZN9IOService20_RESERVEDIOService41Ev
__ZN9IOService20_RESERVEDIOService42Ev
__ZN9IOService20_RESERVEDIOService43Ev
__ZN9IOService20_RESERVEDIOService44Ev
__ZN9IOService20_RESERVEDIOService45Ev
__ZN9IOService20_RESERVEDIOService46Ev
__ZN9IOService20_RESERVEDIOService47Ev
__ZN9IOService20callPlatformFunctionEPK8OSSymbolbPvS3_S3_S3_
__ZN9IOService20callPlatformFunctionEPKcbPvS2_S2_S2_
__ZN9IOService20getDeviceMemoryCountEv
__ZN9IOService20unlockForArbitrationEv
__ZN9IOService21powerStateDidChangeToEmmPS_
__ZN9IOService22copyClientWithCategoryEPK8OSSymbol
__ZN9IOService22powerStateWillChangeToEmmPS_
__ZN9IOService22waitForMatchingServiceEP12OSDictionaryy
__ZN9IOService23acknowledgeNotificationEPvj
__ZN9IOService23addMatchingNotificationEPK8OSSymbolP12OSDictionaryPFbPvS5_PS_P10IONotifierES5_S5_i
__ZN9IOService23requestPowerDomainStateEmP17IOPowerConnectionm
__ZN9IOService24getDeviceMemoryWithIndexEj
__ZN9IOService24mapDeviceMemoryWithIndexEjj
__ZN9IOService24powerStateForDomainStateEm
__ZN9IOService27maxCapabilityForDomainStateEm
__ZN9IOService31initialPowerStateForDomainStateEm
__ZN9IOService4freeEv
__ZN9IOService4initEP12OSDictionary
__ZN9IOService4initEP15IORegistryEntryPK15IORegistryPlane
__ZN9IOService4openEPS_jPv
__ZN9IOService4stopEPS_
__ZN9IOService5closeEPS_j
__ZN9IOService5probeEPS_Pi
__ZN9IOService6PMinitEv
__ZN9IOService6PMstopEv
__ZN9IOService6attachEPS_
__ZN9IOService6detachEPS_
__ZN9IOService7messageEjPS_Pv
__ZN9IOService8DispatchE5IORPC
__ZN9IOService8finalizeEj
__ZN9IOService9terminateEj
__ZN9IOServiceC2EPK11OSMetaClass
__ZN9IOServiceD2Ev
__ZN9OSBoolean11withBooleanEb
__ZN9OSBoolean9metaClassE
__ZNK11OSMetaClass12getClassNameEv
__ZNK11OSMetaClass12getMetaClassEv
__ZNK11OSMetaClass12taggedRetainEPKv
__ZNK11OSMetaClass13taggedReleaseEPKv
__ZNK11OSMetaClass13taggedReleaseEPKvi
__ZNK11OSMetaClass14getRetainCountEv
__ZNK11OSMetaClass19instanceConstructedEv
__ZNK11OSMetaClass6retainEv
__ZNK11OSMetaClass7releaseEi
__ZNK11OSMetaClass7releaseEv
__ZNK11OSMetaClass9serializeEP11OSSerialize
__ZNK15IORegistryEntry11compareNameEP8OSStringPS1_
__ZNK15IORegistryEntry11getLocationEPK15IORegistryPlane
__ZNK15IORegistryEntry11getPropertyEPK8OSString
__ZNK15IORegistryEntry11getPropertyEPK8OSStringPK15IORegistryPlanej
__ZNK15IORegistryEntry11getPropertyEPK8OSSymbol
__ZNK15IORegistryEntry11getPropertyEPK8OSSymbolPK15IORegistryPlanej
__ZNK15IORegistryEntry11getPropertyEPKc
__ZNK15IORegistryEntry11getPropertyEPKcPK15IORegistryPlanej
__ZNK15IORegistryEntry12compareNamesEP8OSObjectPP8OSString
__ZNK15IORegistryEntry12copyLocationEPK15IORegistryPlane
__ZNK15IORegistryEntry12copyPropertyEPK8OSString
__ZNK15IORegistryEntry12copyPropertyEPK8OSStringPK15IORegistryPlanej
__ZNK15IORegistryEntry12copyPropertyEPK8OSSymbol
__ZNK15IORegistryEntry12copyPropertyEPK8OSSymbolPK15IORegistryPlanej
__ZNK15IORegistryEntry12copyPropertyEPKc
__ZNK15IORegistryEntry12copyPropertyEPKcPK15IORegistryPlanej
__ZNK15IORegistryEntry13getChildEntryEPK15IORegistryPlane
__ZNK15IORegistryEntry14applyToParentsEPFvPS_PvES1_PK15IORegistryPlane
__ZNK15IORegistryEntry14copyChildEntryEPK15IORegistryPlane
__ZNK15IORegistryEntry14getParentEntryEPK15IORegistryPlane
__ZNK15IORegistryEntry15applyToChildrenEPFvPS_PvES1_PK15IORegistryPlane
__ZNK15IORegistryEntry15copyParentEntryEPK15IORegistryPlane
__ZNK15IORegistryEntry16getChildIteratorEPK15IORegistryPlane
__ZNK15IORegistryEntry16getPathComponentEPcPiPK15IORegistryPlane
__ZNK15IORegistryEntry17getParentIteratorEPK15IORegistryPlane
__ZNK15IORegistryEntry24dictionaryWithPropertiesEv
__ZNK15IORegistryEntry7getNameEPK15IORegistryPlane
__ZNK15IORegistryEntry7getPathEPcPiPK15IORegistryPlane
__ZNK15IORegistryEntry7inPlaneEPK15IORegistryPlane
__ZNK15IORegistryEntry7isChildEPS_PK15IORegistryPlaneb
__ZNK15IORegistryEntry8copyNameEPK15IORegistryPlane
__ZNK15IORegistryEntry8getDepthEPK15IORegistryPlane
__ZNK15IORegistryEntry8isParentEPS_PK15IORegistryPlaneb
__ZNK15OSMetaClassBase9isEqualToEPKS_
__ZNK8OSObject12taggedRetainEPKv
__ZNK8OSObject13taggedReleaseEPKv
__ZNK8OSObject13taggedReleaseEPKvi
__ZNK8OSObject14getRetainCountEv
__ZNK8OSObject6retainEv
__ZNK8OSObject7releaseEi
__ZNK8OSObject7releaseEv
__ZNK8OSObject9serializeEP11OSSerialize
__ZNK9IOService11getProviderEv
__ZNK9IOService11getWorkLoopEv
__ZNK9IOService12handleIsOpenEPKS_
__ZNK9IOService17getClientIteratorEv
__ZNK9IOService19getProviderIteratorEv
__ZNK9IOService19serializePropertiesEP11OSSerialize
__ZNK9IOService21getOpenClientIteratorEv
__ZNK9IOService23getOpenProviderIteratorEv
__ZNK9IOService6isOpenEPKS_
__ZNK9IOService8getStateEv
__ZNK9IOService9getClientEv
__ZTV12IOUserClient
__ZTV8OSObject
__ZTV9IOService
__ZdlPv
___cxa_pure_virtual
___memcpy_chk
___stack_chk_fail
___stack_chk_guard
___strlcpy_chk
__img4_chip_ap_software_ff00
__img4_chip_ap_software_ff01
__img4_chip_ap_software_ff06
__img4_chip_ap_supplemental
__img4_chip_cryptex1_asset
__img4_chip_cryptex1_boot_reduced
__img4_chip_cryptex1_generic
__img4_chip_cryptex1_generic_supplemental
__img4_nonce_domain_cryptex
__img4_nonce_domain_ddi
__img4_nonce_domain_ephemeral_cryptex
__img4_nonce_domain_pdi
__img4_nonce_domain_trust_cache
__os_log_default
__os_log_internal
_amfi_interface_register
_bcmp
_bzero
_ccder_blob_decode_len
_ccder_blob_decode_range
_ccder_blob_decode_sequence_tl
_ccder_blob_decode_tag
_ccder_blob_decode_tl
_ccder_decode_rsa_pub_n
_ccder_decode_tag
_ccder_decode_tl
_ccder_decode_uint64
_ccder_encode_tl
_ccder_sizeof_len
_ccder_sizeof_tag
_ccdigest
_ccdigest_init
_ccdigest_update
_ccec_cp_256
_ccec_import_pub
_ccec_verify
_ccrsa_import_pub
_ccrsa_verify_pkcs1v15
_ccsha1_di
_ccsha224_di
_ccsha256_di
_ccsha384_di
_ccsha512_di
_cczp_bitlen
_check_trust_cache_runtime_for_uuid
_code_signing_configuration
_copyin
_copyout
_copyoutstr
_cs_blob_reset_cache
_cs_debug
_cs_debug_fail_on_unsigned_code
_cs_debug_unsigned_exec_failures
_cs_debug_unsigned_mmap_failures
_cs_entitlement_flags
_cs_identity_get
_cs_process_enforcement
_cs_require_lv
_cs_restricted
_cs_system_require_lv
_cs_valid
_cs_vm_supports_4k_translations
_csblob_find_blob_bytes
_csblob_get_addr
_csblob_get_base_offset
_csblob_get_cdhash
_csblob_get_code_directory
_csblob_get_der_entitlements
_csblob_get_entitlements
_csblob_get_flags
_csblob_get_hashtype
_csblob_get_identity
_csblob_get_platform_binary
_csblob_get_signer_type
_csblob_get_size
_csblob_get_teamid
_csblob_get_validation_category
_csblob_os_entitlements_copy
_csblob_os_entitlements_get
_csblob_os_entitlements_set
_csblob_register_profile_uuid
_csblob_set_validation_category
_csfg_get_csblob
_csfg_get_supplement_cdhash
_csfg_get_supplement_csblob
_csfg_get_supplement_linkage_cdhash
_csfg_get_supplement_teamid
_csfg_get_teamid
_csm_resolve_os_entitlements_from_proc
_csproc_check_invalid_allowed
_csproc_disable_enforcement
_csproc_forced_lv
_csproc_get_blob
_csproc_get_platform_binary
_csproc_get_teamid
_csproc_hardened_runtime
_csproc_mark_invalid_allowed
_csr_check
_csvnode_get_blob
_csvnode_invalidate_flags
_current_proc
_developer_mode_state
_disable_code_signing_feature
_enable_developer_mode
_fg_get_vnode
_gIODTPlane
_gIOPublishNotification
_garbage_collect_provisioning_profiles
_get_local_signing_public_key
_host_get_special_port
_host_priv_self
_img4_chip_instantiate
_img4_chip_select_categorized_ap
_img4_chip_select_cryptex1_boot
_img4_chip_select_cryptex1_preboot
_img4_chip_select_personalized_ap
_img4_firmware_attach_manifest
_img4_firmware_destroy
_img4_firmware_execute
_img4_firmware_init
_img4_firmware_init_from_buff
_img4_image_get_bytes
_img4_nonce_domain_copy_nonce
_ipc_kernel_map
_kalloc_data
_kalloc_type_impl
_kalloc_type_var_impl
_kauth_cred_issuser
_kauth_cred_proc_ref
_kauth_cred_unref
_kern_os_zfree
_kernel_map
_kernproc
_kfree_data
_kfree_type_impl
_kfree_type_var_impl
_kmem_alloc_kobject
_kmem_free
_launch_constraint_data_get_launch_type
_lck_grp_alloc_init
_lck_rw_destroy
_lck_rw_init
_lck_rw_lock_exclusive
_lck_rw_lock_shared
_lck_rw_unlock_exclusive
_lck_rw_unlock_shared
_load_trust_cache
_load_trust_cache_with_type
_mac_file_getxattr
_mac_label_get
_mac_label_set
_mac_policy_register
_mac_vnop_getxattr
_mach_msg_destroy_from_kernel_proper
_mach_msg_rpc_from_kernel_proper
_match_compilation_service_cdhash
_memchr
_memcmp
_memcpy
_memmove
_memset
_memset_s
_mig_dealloc_reply_port
_mig_get_reply_port
_mig_put_reply_port
_mig_strncpy
external
_os_log_create
_panic
_printf
_proc_chrooted
_proc_find
_proc_find_ident
_proc_getexecutablevnode
_proc_is_translated
_proc_isinitproc
_proc_issetugid
_proc_name
_proc_pid
_proc_pidversion
_proc_platform
_proc_rele
_proc_self
_proc_selfpid
_proc_selfppid
_proc_suser
_ptrauth_utils_auth_blob_generic
_ptrauth_utils_sign_blob_generic
_query_trust_cache
_scnprintf
_set_compilation_service_cdhash
_set_local_signing_public_key
_snprintf
_strcmp
_strlen
_strncmp
_strnlen
_strnstr
_sysctl__hw_features_children
_sysctl__security_mac_children
_sysctl_handle_int
_sysctl_register_oid
_sysctlbyname
_thread_call_allocate_with_options
_thread_call_enter1
_thread_call_free
_unrestrict_local_signing_cdhash
_vfs_context_create
_vfs_context_proc
_vfs_context_rele
_vfs_context_ucred
_vfs_flags
_vm_allocate
_vm_deallocate
_vm_map_copyin
_vm_map_copyout
_vm_map_page_mask
_vm_map_unwire
_vm_map_wire
_vn_getpath
_vn_rdwr
_vnode_close
_vnode_getattr
_vnode_isdir
_vnode_isreg
_vnode_mount
_vnode_open
_vnode_put
_vsnprintf
_zalloc_flags
_zalloc_ro
_zalloc_ro_mut
_zfree_ro
_zone_create_ro
_zone_require_ro
+524 -21
View File
@@ -10,6 +10,7 @@ import plistlib
import json
import sys
import treelib
import ctypes
### --- I. MACH-O --- ###
class MachOProcessor:
@@ -53,19 +54,34 @@ class MachOProcessor:
if args.load_commands: # Print binary load commands
load_commands_list = snake_instance.getLoadCommands()
print("Load Commands:", " ".join(load_command.command.name for load_command in load_commands_list))
if args.has_cmd: # Check if LC exist
snake_instance.printHasLoadCommand(args.has_cmd)
if args.segments: # Print binary segments in human friendly form
for segment in snake_instance.getSegments():
print(segment)
if args.has_segment: # Check if binary has given __SEGMENT
snake_instance.printHasSegment(args.has_segment)
if args.sections: # Print binary sections in human friendly form
for section in snake_instance.getSections():
print(section)
if args.has_section: # Check if binary has given __SEGMENT,__section
snake_instance.printHasSection(args.has_section)
if args.symbols: # Print symbols
for symbol in snake_instance.getSymbols():
print(f"0x{symbol.value:016X} {symbol.name}")
if args.imports: # Print imported symbols
snake_instance.printImports()
if args.exports: # Print exported symbols
snake_instance.printExports()
if args.imported_symbols:
snake_instance.printImportedSymbols()
@@ -130,6 +146,12 @@ class MachOProcessor:
print('\n<=== ENTRYPOINT ===>')
snake_instance.printMain()
if args.dump_data: # Dump {size} bytes starting from {offset} to a given {filename}.
snake_instance.dumpDataArgParser(args.dump_data)
if args.calc_offset: # Calculate the real address of the Virtual Memory in the file.
snake_instance.printCalcRealAddressFromVM(args.calc_offset)
class SnakeI:
def __init__(self, binaries, file_path):
'''
@@ -158,6 +180,19 @@ class SnakeI:
0x8: 'SG_PROTECTED_VERSION_1',
0x10: 'SG_READ_ONLY',
}
self.symbol_types = {
'N_STAB': 0xE0, # DEBUG SYMBOL
'N_PEXT': 0x10, # PRIVATE EXTERNAL SYMBOL
'N_TYPE': 0x0E, # CHECK N_TYPES
'N_EXT' : 0x01, # EXTERNAL SYMBOL
'N_TYPES': {
'N_UNDF': 0x00, # UNDEFINED
'N_ABS': 0x02, # ABSOLUTE
'N_SECT': 0x0E, # DEFINED IN SECTION
'N_PBUD': 0x0C, # PREBOUND UNDEFINED (in dylib)
'N_INDR': 0x0A, # INDIRECT
}
}
def mapProtection(self, numeric_protection):
'''Maps numeric protection to its string representation.'''
@@ -207,6 +242,15 @@ class SnakeI:
'''https://lief-project.github.io/doc/stable/api/python/macho.html#loadcommand'''
return self.binary.commands
def getSegment(self, segment_name):
''' Return segment object for the given {segment_name} __SEGMENT. '''
segment_name = segment_name.lower()
for segment in self.binary.segments:
if (segment.name).lower() == segment_name:
return segment
return None
def getSegments(self):
'''Extract segmenents from binary and return a human readable string: https://lief-project.github.io/doc/stable/api/python/macho.html#lief.MachO.SegmentCommand'''
segment_info = []
@@ -225,6 +269,18 @@ class SnakeI:
segment_info.append(f'{name.ljust(16)}{init_prot}/{max_prot.ljust(8)} VM: {va_start}-{va_end.ljust(24)} FILE: {file_start}-{file_end}')
return segment_info
def hasSegment(self, segment_name):
''' Check if binary has given segment {segment_name}. '''
for segment in self.binary.segments:
if segment.name == segment_name:
return True
return False
def printHasSegment(self, segment_name):
''' Printing function for --has_segment. '''
if self.hasSegment(segment_name):
print(f'{self.file_path} has {segment_name}')
def calcSectionRange(self, section):
'''
The function calculates a section's start and end offset by adding the FAT slide in case of fat binary.
@@ -248,6 +304,18 @@ class SnakeI:
return section_offset_start, section_offset_end
return False, False
def getSection(self, segment_section):
''' Return segment object for the given {segment_section} __SEGMENT,__section. '''
segment_section = segment_section.lower()
for section in self.binary.sections:
current_segment_section = f'{section.segment_name},{section.name}'.lower()
if current_segment_section == segment_section:
return section
return None
def getSections(self):
'''Extract sections from binary and return in human readable format: https://lief-project.github.io/doc/stable/api/python/macho.html#lief.MachO.Section'''
sections_info = []
@@ -272,6 +340,38 @@ class SnakeI:
'''Get all symbols from the binary (LC_SYMTAB, Chained Fixups, Exports Trie): https://lief-project.github.io/doc/stable/api/python/macho.html#symbol'''
return self.binary.symbols
def getImports(self):
''' Imported symbols are undefined and external. '''
imported_symbols = []
for symbol in self.getSymbols():
if (symbol.type & self.symbol_types['N_EXT']):
if (symbol.type & self.symbol_types['N_TYPE']) == self.symbol_types['N_TYPES']['N_UNDF']:
imported_symbols.append(symbol)
return(imported_symbols)
def printImports(self):
''' Printing only imported symbol names. '''
for symbol in self.getImports():
print(symbol.name)
def getExports(self):
''' Exported symbols are external but not undefined or private. '''
exported_symbols = []
for symbol in self.getSymbols():
if (symbol.type & self.symbol_types['N_EXT']):
if (symbol.type & self.symbol_types['N_TYPE']) != self.symbol_types['N_TYPES']['N_UNDF']:
exported_symbols.append(symbol)
return(exported_symbols)
def printExports(self):
''' Printing only exported symbol names. '''
for symbol in self.getExports():
print(symbol.name)
def getChainedFixups(self):
'''Return Chained Fixups information: https://lief-project.github.io/doc/latest/api/python/macho.html#chained-binding-info'''
return self.binary.dyld_chained_fixups
@@ -293,17 +393,29 @@ class SnakeI:
return uuid_string
def getMain(self):
'''Determine the entry point of an executable.'''
return self.binary.main_command
'''Determine the entry point of an executable (LC_MAIN or LC_THREAD or LC_UNIXTHREAD)'''
LC_MAIN = self.binary.main_command
if LC_MAIN:
return LC_MAIN
LC_UNIXTHREAD = self.binary.thread_command
return LC_UNIXTHREAD
def printMain(self):
'''Prints entry point and stack size if exists.'''
'''Prints entry point and stack size or Thread flavor if exists.'''
entry_point = self.getMain()
if entry_point:
print(f'Entry point: {hex(self.getMain().entrypoint)}')
print(f'Stack size: {hex(self.getMain().stack_size)}')
if entry_point and hasattr(entry_point, 'entrypoint'):
print(f'Entry point: {hex(entry_point.entrypoint)}')
print(f'Stack size: {hex(entry_point.stack_size)}')
elif entry_point and hasattr(entry_point, 'pc'):
print(f'Entry point (PC): {hex(entry_point.pc)}')
print(f'Thread flavor: {hex(entry_point.flavor)}')
else:
print(f"{self.file_path} has no entry point.")
print(f"{self.file_path} has no entry point (LC_MAIN or LC_THREAD or LC_UNIXTHREAD).")
def getStringSection(self):
'''Return strings from the __cstring (string table).'''
@@ -372,18 +484,79 @@ class SnakeI:
extracted_bytes = file.read(size)
return extracted_bytes
def saveEcryptedData(self,output_path):
def saveBytesToFile(self, data, filename):
''' Save bytes to a file. '''
with open(filename, 'wb') as file:
file.write(data)
def readBytesFromFile(self, filename):
''' Read bytes from a file. '''
with open(filename, 'rb') as file:
data = file.read()
return data
def dumpData(self, offset, size, filename):
''' Extract {size} bytes starting from {offset} to a given {filename}. '''
extracted_bytes = self.extractBytesAtOffset(offset, size)
if extracted_bytes:
self.saveBytesToFile(extracted_bytes, filename)
def dumpDataArgParser(self, args):
''' Parse comma separated values for dumpData from --dump_data 'offset,size,filename'. '''
offset, size, filename = args.split(',')
offset = offset.strip().lower()
if offset.startswith("0x"):
offset = int(offset, 16)
size = size.strip().lower()
if size.startswith("0x"):
size = int(size, 16)
filename = filename.strip()
self.dumpData(offset, size, filename)
def saveEcryptedData(self, output_path):
'''Method for saving encrypted data sector to specified file.'''
_, cryptoff, cryptsize = self.getEncryptionInfo()
self.saveBytesToFile(self.extractBytesAtOffset(cryptoff + self.fat_offset, cryptsize), output_path)
def hasSection(self, segment_section):
'''
Takes "__SEGMENT,__section" as an input.
Return True if it exists.
'''
segment_section = segment_section.lower()
for section in self.binary.sections:
current_segment_section = f'{section.segment_name},{section.name}'.lower()
if current_segment_section == segment_section:
return True
return False
def printHasSection(self, segment_section):
''' Printing function for --has_section. '''
if self.hasSection(segment_section):
print(f'{self.file_path} has {segment_section}')
def extractSection(self, segment_name, section_name):
'''
As argument takes segment name (e.g. "__PRELINK_INFO") and section name that is a part of the segment (e.g. '__text').
Return data (bytes) stored in a given section.
If section was not found, return False.
If section was not found or is empty -> return False.
'''
segment_section = f'{segment_name},{section_name}'
if not self.hasSection(segment_section): # If section was not found, break.
return False
section_offset_start, section_offset_end = self.getSectionRange(segment_name, section_name)
if section_offset_start and section_offset_end:
size = section_offset_end - section_offset_start
extracted_bytes = self.extractBytesAtOffset(section_offset_start, size)
@@ -401,6 +574,57 @@ class SnakeI:
return True
return False
def hasLoadCommand(self, load_command):
''' Check if the given Load Command exists in the binary. '''
if load_command.startswith("LC_"):
load_command = load_command[3:]
load_command = load_command.lower()
for cmd in self.load_commands:
cmd = str(cmd.command.name).lower()
if load_command == cmd:
return True
return False
def printHasLoadCommand(self, load_command):
''' Printing function for has_cmd. '''
original_user_input = load_command
if self.hasLoadCommand(load_command):
print(f'{self.file_path} has {original_user_input}')
def getVirtualMemoryStartingAddress(self):
''' Get start VM base addr of the __TEXT segment '''
vm_base = 0
if self.hasSegment('__TEXT'):
for segment in self.binary.segments:
if segment.name == '__TEXT':
vm_base = segment.virtual_address + self.fat_offset
return vm_base
def calcRealAddressFromVM(self, vm_offset):
'''
Calculate the real address of the Virtual Memory in the file.
vm_start == __TEXT segment
vm_offset == your address
real = vm_offset - vm_start
'''
# Handling strings and hexes
if type(vm_offset) is not int:
if (vm_offset.lower()).startswith("0x"):
vm_offset = int(vm_offset, 16)
else:
vm_offset = int(vm_offset)
vm_base = self.getVirtualMemoryStartingAddress()
vm_offset = vm_offset - vm_base
return vm_offset
def printCalcRealAddressFromVM(self, vm_offset):
''' Printing function for --calc_offset '''
real_offset = self.calcRealAddressFromVM(vm_offset)
real_offset_hex = hex(real_offset)
print(f'{vm_offset} : {real_offset_hex}')
### --- II. CODE SIGNING --- ###
class CodeSigningProcessor:
def __init__(self):
@@ -480,11 +704,6 @@ class SnakeII(SnakeI):
cms_signature = cs_content[offset + 8:offset + 8 + cms_len_in_int]
return cms_signature
def saveBytesToFile(self, data, filename):
'''Save bytes to a file.'''
with open(filename, 'wb') as file:
file.write(data)
def extractCertificatesFromCodeSignature(self, cert_name):
'''Extracts certificates from the CMS Signature and saves them to a file with _0, _1, _2 indexes at the end of the file names.'''
subprocess.run(["codesign", "-d", f"--extract-certificates={cert_name}_", self.file_path], capture_output=True)
@@ -1584,7 +1803,7 @@ class AMFIProcessor:
def __init__(self):
'''This class contains part of the code from the main() for the SnakeVI: AMFI.'''
pass
def process(self, args):
if args.dump_prelink_info is not None: # nargs="?", const='PRELINK_info.txt' # Dump '__PRELINK_INFO,__info' to a given file (default: 'PRELINK_info.txt')
snake_instance.dumpPrelink_info(args.dump_prelink_info)
@@ -1592,12 +1811,63 @@ class AMFIProcessor:
if args.dump_prelink_text is not None: # Dump '__PRELINK_TEXT,__text' to a given file (default: 'PRELINK_text.txt')
snake_instance.dumpPrelink_text(args.dump_prelink_text)
if args.dump_prelink_kext is not None: # Dump prelinked KEXT from decompressed Kernel Cache to a file named: prelinked_{kext_name}.bin
snake_instance.dumpKernelExtensionFromPRELINK_TEXT(args.dump_prelink_kext)
if args.kext_prelinkinfo: # Print _Prelink properties from PRELINK_INFO,__info for a give kext
snake_instance.printParsedPRELINK_INFO_plist(args.kext_prelinkinfo)
if args.kmod_info: # Print parsed kmod_info for the given kext
snake_instance.printParsedkmod_info(args.kmod_info)
if args.kext_entry: # Print kext entrypoint
snake_instance.printKextEntryPoint(args.kext_entry)
if args.kext_exit: # Print kext exitpoint
snake_instance.printKextExitPoint(args.kext_exit)
if args.amfi:
pass
snake_instance.printExports()
class SnakeVI(SnakeV):
def __init__(self, binaries, file_path):
super().__init__(binaries, file_path)
# This map is just a helper for --dump_kext so the user can specify different names for the same kext.
# For instance, amfi instead of AppleMobileFileIntegrity.kext
self.kext_map = {
'amfi' : 'applemobilefileintegrity',
'com.apple.driver.applemobilefileintegrity' : 'applemobilefileintegrity',
'applemobilefileintegrity.kext' : 'applemobilefileintegrity',
}
def loadPRELINK_INFOFromFile(self, prelink_info_filename): # Not used yet.
'''
Read PRELINK_INFO,__info section from file (with alignment).
The last line in the dumped section plist is broken, because of alignment.
This function remove it so the plistlib.loads work.
It returns loaded PLIST {prelink_info_plist}.
'''
prelink_info_plist_bytes = self.readBytesFromFile(prelink_info_filename)
prelink_as_bytes_without_last_line = self.removeNullBytesAlignment(prelink_info_plist_bytes)
prelink_info_plist = plistlib.loads(prelink_as_bytes_without_last_line)
return prelink_info_plist
def calcTwoComplement64(self, value):
''' Convert negative int to hex representation. '''
return hex((value + (1 << 64)) % (1 << 64))
def removeNullBytesAlignment(self, string_as_bytes):
'''
The last line in the PLISTs and other files dumped from memory will almost always be aligned with 0x00 bytes.
This function:
Detects lines in a given bytes {string_as_bytes}.
Removes the last line.
Returns a new {string_as_bytes}.
'''
decoded_string = string_as_bytes.decode('utf-8')
decoded_string_without_last_line = decoded_string[:decoded_string.rfind('\n')]
string_as_bytes_without_last_line = decoded_string_without_last_line.encode()
return string_as_bytes_without_last_line
def dumpPrelink_info(self, filename):
''' Dump '__PRELINK_INFO,__info' to a given file (default: 'PRELINK_info.txt') '''
@@ -1611,6 +1881,141 @@ class SnakeVI(SnakeV):
section_name = '__text'
self.dumpSection(segment_name, section_name, filename)
def extractPRELINK_INFO_plist(self):
''' Extract '__PRELINK_INFO,__info' and return it. '''
segment_name = '__PRELINK_INFO'
section_name = '__info'
extracted_bytes = self.extractSection(segment_name, section_name)
return extracted_bytes
def parsePRELINK_INFO_plist(self, kext_name):
''' Extract PLIST properties values from '__PRELINK_INFO,__info' section for the given {kext_name}:
_PrelinkBundlePath
_PrelinkExecutableLoadAddr
_PrelinkExecutableRelativePath
_PrelinkExecutableSize
_PrelinkExecutableSourceAddr
_PrelinkKmodInfo
'''
#prelink_info_plist = self.loadPRELINK_INFO(prelink_info_filename) # For loading PRELINK_INFO from file
prelink_as_bytes = self.extractPRELINK_INFO_plist()
prelink_as_bytes_without_last_line = self.removeNullBytesAlignment(prelink_as_bytes)
prelink_info_plist = plistlib.loads(prelink_as_bytes_without_last_line)
kext_name = kext_name.lower()
if kext_name in self.kext_map:
kext_name = self.kext_map[kext_name]
# Iterate over the parsed dictionary
for item in prelink_info_plist['_PrelinkInfoDictionary']:
PrelinkExecutableRelativePath = item.get('_PrelinkExecutableRelativePath', '').lower()
# Check if the '_PrelinkExecutableRelativePath' contains {kext_name} in its path
if kext_name in PrelinkExecutableRelativePath:
# Extract the desired keys and their corresponding values
bundle_path = item.get('_PrelinkBundlePath')
executable_load_addr = str(item.get('_PrelinkExecutableLoadAddr')).lower()
if executable_load_addr.startswith("0x"):
executable_load_addr = int(executable_load_addr, 16)
elif executable_load_addr.startswith("-"):
executable_load_addr = self.calcTwoComplement64(int(executable_load_addr))
executable_relative_path = item.get('_PrelinkExecutableRelativePath')
executable_size = str(item.get('_PrelinkExecutableSize')).lower()
if executable_size.startswith("0x"):
executable_size = int(executable_size, 16)
elif executable_size.startswith("-"):
executable_size = self.calcTwoComplement64(int(executable_size))
source_addr = str(item.get('_PrelinkExecutableSourceAddr')).lower()
if source_addr.startswith("0x"):
source_addr = int(source_addr, 16)
elif source_addr.startswith("-"):
source_addr = self.calcTwoComplement64(int(source_addr))
kmod_info = str(item.get('_PrelinkKmodInfo')).lower()
if kmod_info.startswith("0x"):
kmod_info = int(kmod_info, 16)
elif kmod_info.startswith("-"):
kmod_info = self.calcTwoComplement64(int(kmod_info))
return bundle_path, executable_load_addr, executable_relative_path, executable_size, source_addr, kmod_info
def printParsedPRELINK_INFO_plist(self, kext_name):
''' Print extracted properties for PRELINK_INFO Plist for a given kext. '''
bundle_path, executable_load_addr, executable_relative_path, executable_size, source_addr, kmod_info = self.parsePRELINK_INFO_plist(kext_name)
print(f'_PrelinkBundlePath: {bundle_path}')
print(f'_PrelinkExecutableLoadAddr: {executable_load_addr}')
print(f'_PrelinkExecutableRelativePath: {executable_relative_path}')
print(f'_PrelinkExecutableSize: {hex(int(executable_size))}')
print(f'_PrelinkExecutableSourceAddr: {source_addr}')
print(f'_PrelinkKmodInfo: {kmod_info}')
def dumpKernelExtensionFromPRELINK_TEXT(self, kext_name):
''' Dump prelinked KEXT {kext_name} from decompressed Kernel Cache PRELINK_TEXT segment -p {file_path} to a file named: prelinked_{kext_name}.bin '''
segment_section = '__PRELINK_TEXT,__text'
if not self.hasSection(segment_section): # If segment does not exist - break
print(f'Specified binary file does not have {segment_section} - the extension was not dumped.')
return False
_, kext_load_addr, _, kext_size, source_addr, _ = self.parsePRELINK_INFO_plist(kext_name)
kext_load_addr = int(kext_load_addr, 16)
kext_size = int(kext_size, 16)
output_path = f'prelinked_{kext_name}.bin'
kext_offset = self.calcRealAddressFromVM(kext_load_addr)
self.dumpData(kext_offset, kext_size, output_path)
def parsekmod_info(self, kext_name):
''' Parse kmod_info structure for the given {kext_name} from Kernel Cache '''
_, _, _, _, _, kmod_info_vm_addr = self.parsePRELINK_INFO_plist(kext_name)
kmod_info_in_file = self.calcRealAddressFromVM(kmod_info_vm_addr)
kmod_info_size = ctypes.sizeof(AppleStructuresManager.kmod_info)
extracted_kmod_info_bytes = self.extractBytesAtOffset(kmod_info_in_file, kmod_info_size)
# debug +
#Utils.printQuadWordsLittleEndian64(extracted_kmod_info_bytes)
# debug -
kmod_info_as_dict = AppleStructuresManager.parsekmod_info(extracted_kmod_info_bytes)
return kmod_info_as_dict
def printParsedkmod_info(self, kext_name):
''' Printing function for --kmod_info '''
kmod_info_as_dict = self.parsekmod_info(kext_name)
for k, v in kmod_info_as_dict.items():
print(f'{k.ljust(16)}: {v}')
def calcKextEntryPoint(self, kext_name):
''' Calculate the __start for the given {kext_name} Kernel Extension '''
kmod_info_as_dict = self.parsekmod_info(kext_name)
start = int(kmod_info_as_dict['start'], 16) & 0xFFFFFFFF
kernelcache_text_segment = self.getSegment('__TEXT')
kernelcache_text_segment_base = kernelcache_text_segment.virtual_address
return start + kernelcache_text_segment_base
def printKextEntryPoint(self, kext_name):
''' Printing function for --kext_entry flag. '''
kext_entrypoint = hex(self.calcKextEntryPoint(kext_name))
print(f'{kext_name} entrypoint: {kext_entrypoint}')
def calcKextExitPoint(self, kext_name):
''' Calculate the __stop for the given {kext_name} Kernel Extension '''
kmod_info_as_dict = self.parsekmod_info(kext_name)
stop = int(kmod_info_as_dict['stop'], 16) & 0xFFFFFFFF
kernelcache_text_segment = self.getSegment('__TEXT')
kernelcache_text_segment_base = kernelcache_text_segment.virtual_address
return stop + kernelcache_text_segment_base
def printKextExitPoint(self, kext_name):
''' Printing function for --kext_exit flag. '''
kext_exitpoint = hex(self.calcKextEntryPoint(kext_name))
print(f'{kext_name} exitpoint: {kext_exitpoint}')
### --- ARGUMENT PARSER --- ###
class ArgumentParser:
@@ -1635,10 +2040,15 @@ class ArgumentParser:
macho_group.add_argument('--endian', action='store_true', help="Print binary endianess")
macho_group.add_argument('--header', action='store_true', help="Print binary header")
macho_group.add_argument('--load_commands', action='store_true', help="Print binary load commands names")
macho_group.add_argument('--has_cmd', metavar='LC_MAIN', help="Check of binary has given load command")
macho_group.add_argument('--segments', action='store_true', help="Print binary segments in human-friendly form")
macho_group.add_argument('--has_segment', help="Check if binary has given '__SEGMENT'", metavar='__SEGMENT')
macho_group.add_argument('--sections', action='store_true', help="Print binary sections in human-friendly form")
macho_group.add_argument('--has_section', help="Check if binary has given '__SEGMENT,__section'", metavar='__SEGMENT,__section')
macho_group.add_argument('--symbols', action='store_true', help="Print all binary symbols")
macho_group.add_argument('--imported_symbols', action='store_true', help="Print symbols imported from external libraries")
macho_group.add_argument('--imports', action='store_true', help="Print imported symbols")
macho_group.add_argument('--exports', action='store_true', help="Print exported symbols")
macho_group.add_argument('--imported_symbols', action='store_true', help="Print symbols imported from external libraries with dylib names")
macho_group.add_argument('--chained_fixups', action='store_true', help="Print Chained Fixups information")
macho_group.add_argument('--exports_trie', action='store_true', help="Print Export Trie information")
macho_group.add_argument('--uuid', action='store_true', help="Print UUID")
@@ -1648,6 +2058,8 @@ class ArgumentParser:
macho_group.add_argument('--all_strings', action='store_true', help="Print strings from all sections")
macho_group.add_argument('--save_strings', help="Parse all sections, detect strings, and save them to a file", metavar='all_strings.txt')
macho_group.add_argument('--info', action='store_true', default=False, help="Print header, load commands, segments, sections, symbols, and strings")
macho_group.add_argument('--dump_data', help="Dump {size} bytes starting from {offset} to a given {filename} (e.g. '0x1234,0x1000,out.bin')", metavar=('offset,size,output_path'), nargs="?")
macho_group.add_argument('--calc_offset', help="Calculate the real address (file on disk) of the given Virtual Memory {vm_offset} (e.g. 0xfffffe000748f580)", metavar='vm_offset')
def addCodeSignArgs(self):
codesign_group = self.parser.add_argument_group('CODE SIGNING ARGS')
@@ -1692,7 +2104,7 @@ class ArgumentParser:
dylibs_group.add_argument('--reexport_paths', action='store_true', default=False, help="Print paths from LC_REEXPORT_DLIB")
dylibs_group.add_argument('--hijack_sec', action='store_true', default=False, help="Check if binary is protected against Dylib Hijacking")
dylibs_group.add_argument('--dylib_hijacking', metavar='(optional) cache_path' ,nargs="?", const="default", help="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")
dylibs_group.add_argument('--dylib_hijacking_a', metavar='cache_path' ,nargs="?", const="default", help="Like --dylib_hijacking, but shows only possible vectors (without protected binaries)")
dylibs_group.add_argument('--dylib_hijacking_a', metavar='cache_path', nargs="?", const="default", help="Like --dylib_hijacking, but shows only possible vectors (without protected binaries)")
dylibs_group.add_argument('--prepare_dylib', metavar='(optional) target_dylib_name', nargs="?", const='', help="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")
def addDyldArgs(self):
@@ -1707,7 +2119,12 @@ class ArgumentParser:
dyld_group = self.parser.add_argument_group('AMFI ARGS')
dyld_group.add_argument('--dump_prelink_info', metavar='(optional) out_name', nargs="?", const='PRELINK_info.txt', help='Dump "__PRELINK_INFO,__info" to a given file (default: "PRELINK_info.txt")')
dyld_group.add_argument('--dump_prelink_text', metavar='(optional) out_name', nargs="?", const='PRELINK_text.txt', help='Dump "__PRELINK_TEXT,__text" to a given file (default: "PRELINK_text.txt")')
dyld_group.add_argument('--amfi', action='store_true', default=False, help="a")
dyld_group.add_argument('--dump_prelink_kext', metavar='kext_name', nargs="?", help='Dump prelinked KEXT {kext_name} from decompressed Kernel Cache PRELINK_TEXT segment to a file named: prelinked_{kext_name}.bin')
dyld_group.add_argument('--kext_prelinkinfo', metavar='kext_name', nargs="?", help='Print _Prelink properties from PRELINK_INFO,__info for a give {kext_name}')
dyld_group.add_argument('--kmod_info', metavar='kext_name', help="Parse kmod_info structure for the given {kext_name} from Kernel Cache")
dyld_group.add_argument('--kext_entry', metavar='kext_name', help="Calculate the virtual memory address of the __start (entrpoint) for the given {kext_name} Kernel Extension")
dyld_group.add_argument('--kext_exit', metavar='kext_name', help="Calculate the virtual memory address of the __stop (exitpoint) for the given {kext_name} Kernel Extension")
dyld_group.add_argument('--amfi', help="a")
@@ -1748,6 +2165,92 @@ void myconstructor(int argc, const char **argv)
clang_command = ["clang", file_name_c, "-o", output_filename, *flag_list]
subprocess.run(clang_command, check=True)
### --- APPLE CODE --- ###
class AppleStructuresManager:
''' It stores Apple structures and their parsers. '''
class kmod_info(ctypes.Structure):
''' REF: https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/mach/kmod.h#L87 '''
_pack_ = 1 # Specify the byte order (little-endian)
_fields_ = [
("next", ctypes.c_uint64), # Simplifying the structure, it should be: struct kmod_info * next;
("info_version", ctypes.c_int32),
("id", ctypes.c_uint32),
("name", ctypes.c_char * 64),
("version", ctypes.c_char * 64),
("reference_count", ctypes.c_int32),
("reference_list", ctypes.c_uint64),
("address", ctypes.c_uint64),
("size", ctypes.c_uint64),
("hdr_size", ctypes.c_uint64),
("start", ctypes.c_uint64),
("stop", ctypes.c_uint64)
]
def parsekmod_info(data):
# Create an instance of the kmod_info structure
info = AppleStructuresManager.kmod_info()
# Cast the binary data to the structure
ctypes.memmove(ctypes.byref(info), data, ctypes.sizeof(info))
# Convert name and version to strings
name = info.name.decode('utf-8').rstrip('\x00')
version = info.version.decode('utf-8').rstrip('\x00')
# Return parsed data as a dictionary
return {
"next": info.next,
"info_version": info.info_version,
"id": hex(info.id),
"name": name,
"version": version,
"reference_count": info.reference_count,
"reference_list": hex(info.reference_list),
"address": hex(info.address),
"size": hex(info.size),
"hdr_size": hex(info.hdr_size),
"start": hex(info.start),
"stop": hex(info.stop)
}
### --- UTILS / DEBUG --- ###
class Utils:
def printQuadWordsLittleEndian64(byte_string, columns=2):
''' Print Q values from given {byte_string} in {columns} columns (default 2)
0000000000000000 FFFFFFFF00000001
6C7070612E6D6F63 7265766972642E65
'''
# Ensure the byte string length is a multiple of 8
while len(byte_string) % 8 != 0:
byte_string += b'\x00' # Add padding to make it divisible by 8
# Convert the byte string to a list of integers
byte_list = list(byte_string)
# Group the bytes into 8-byte chunks
chunks = [byte_list[i:i+8] for i in range(0, len(byte_list), 8)]
# Print the raw bytes in 64-bit little-endian order
print("Raw bytes (64-bit little-endian):")
i = 1
for chunk in chunks:
chunk_value = int.from_bytes(chunk, byteorder='little')
if i < columns:
print(f"{chunk_value:016X}", end=" ")
else:
print(f"{chunk_value:016X}", end="\n")
i = 0
i+=1
print()
def printRawHex(byte_string):
'''
Print bytes as raw hexes (without endianess).
01 00 00 00 ff ff ...
'''
hex_string = ' '.join(f'{byte:02x}' for byte in byte_string)
print(hex_string)
if __name__ == "__main__":
arg_parser = ArgumentParser()
args = arg_parser.parseArgs()
@@ -1776,4 +2279,4 @@ if __name__ == "__main__":
### --- VI. AMFI --- ###
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
amfi_processor.process(args)
-108996
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
+165 -8
View File
@@ -201,7 +201,6 @@ def run_and_get_stdout(command):
command_with_stdout = f"{command} 2>&1"
return os.popen(command_with_stdout).read().strip()
class TestSnakeI():
'''Testing I. MACH-O'''
@classmethod
@@ -315,6 +314,20 @@ class TestSnakeI():
assert expected_output in uroboros_output
def test_has_cmd(self):
'''Test the --has_cmd flag of SnakeI.'''
args_list = ['-p', 'hello_1', '--has_cmd', 'LC_MAIN']
args, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
macho_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'hello_1 has LC_MAIN'
assert expected_output in uroboros_output
def test_segments(self):
'''Test the --segments flag of SnakeI.'''
args_list = ['-p', 'hello_1', '--segments']
@@ -335,6 +348,20 @@ class TestSnakeI():
assert expected_output_3 in uroboros_output
assert expected_output_4 in uroboros_output
def test_has_segment(self):
'''Test the --has_segment flag of SnakeI.'''
args_list = ['-p', 'hello_1', '--has_segment', '__TEXT']
args, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
macho_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'hello_1 has __TEXT'
assert expected_output in uroboros_output
def test_sections(self):
'''Test the --sections flag of SnakeI.'''
args_list = ['-p', 'hello_1', '--sections']
@@ -356,7 +383,21 @@ class TestSnakeI():
assert expected_output_3 in uroboros_output
assert expected_output_4 in uroboros_output
assert expected_output_5 in uroboros_output
def test_has_section(self):
'''Test the --has_section flag of SnakeI.'''
args_list = ['-p', 'hello_1', '--has_section', '__TEXT,__text']
args, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
macho_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = 'hello_1 has __TEXT,__text'
assert expected_output in uroboros_output
def test_symbols(self):
'''Test the --symbols flag of SnakeI.'''
args_list = ['-p', 'hello_1', '--symbols']
@@ -537,6 +578,40 @@ class TestSnakeI():
assert expected_output_4 in uroboros_output
assert expected_output_5 in uroboros_output
def test_dump_data(self):
'''Test the --dump_data flag of SnakeI.'''
args_list = ['-p', 'hello_1', '--dump_data', '0x00,0x08,hello_1_header_dump.bin']
args, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
macho_processor.process(args)
executeCodeBlock(code_block)
assert os.path.exists('hello_1_header_dump.bin')
with open('hello_1_header_dump.bin', 'rb') as file:
file_output = file.read()
expected_output = b'\xcf\xfa\xed\xfe\x0c\x00\x00\x01'
assert expected_output in file_output
os.remove('hello_1_header_dump.bin')
def test_calc_offset(self):
'''Test the --calc_offset flag of SnakeI.'''
args_list = ['-p', 'hello_1', '--calc_offset', "0x0000000100003f20"]
args, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
macho_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
expected_output = "0x0000000100003f20 : 0x3f20"
assert expected_output in uroboros_output
class TestSnakeII():
'''Testing II. CODE SIGNING'''
@classmethod
@@ -1472,7 +1547,7 @@ class TestSnakeVI():
os.system("rm -rf kernelcache")
assert not os.path.exists("kernelcache")
def test_dumpPrelink_info(self):
def test_dump_prelink_info(self):
'''Test the --dump_prelink_info flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--dump_prelink_info']
args, file_path = argumentWrapper(args_list)
@@ -1483,12 +1558,13 @@ class TestSnakeVI():
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
executeCodeBlock(code_block)
assert os.path.exists('PRELINK_info.txt')
os.remove('PRELINK_info.txt')
def test_dumpPrelink_text(self):
'''Test the --dump_prelink_info flag of SnakeVI.'''
def test_dump_prelink_text(self):
'''Test the --dump_prelink_text flag of SnakeVI.'''
args_list = ['-p', self.kernelcache_path, '--dump_prelink_text']
args, file_path = argumentWrapper(args_list)
@@ -1498,6 +1574,87 @@ class TestSnakeVI():
amfi_processor = AMFIProcessor()
amfi_processor.process(args)
uroboros_output = executeCodeBlock(code_block)
executeCodeBlock(code_block)
assert os.path.exists('PRELINK_text.txt')
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, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
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, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
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, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
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, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
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, file_path = argumentWrapper(args_list)
def code_block():
macho_processor = MachOProcessor(file_path)
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