{"id":2279,"date":"2024-04-08T05:02:16","date_gmt":"2024-04-07T20:02:16","guid":{"rendered":"https:\/\/h4ck.kr\/?p=2279"},"modified":"2024-04-08T05:09:06","modified_gmt":"2024-04-07T20:09:06","slug":"ktrw-%ec%bb%a4%eb%84%90-%eb%94%94%eb%b2%84%ea%b1%b0-6s-%ed%8f%ac%ed%8c%85-%ec%8b%a4%ed%8c%a8-failed-to-port-ktrw-kernel-debugger-to-iphone-6s","status":"publish","type":"post","link":"https:\/\/h4ck.kr\/?p=2279","title":{"rendered":"KTRW \ucee4\ub110 \ub514\ubc84\uac70 6s \ud3ec\ud305 \uc2e4\ud328 (Failed porting KTRW kernel debugger to iPhone 6s)"},"content":{"rendered":"\n<p><a href=\"https:\/\/github.com\/jsherman212\/ktrw\">https:\/\/github.com\/jsherman212\/ktrw<\/a><\/p>\n\n\n\n<p>\uc544\uc774\ud3f08 iOS 14\uc5d0\uc11c\ub9cc \uc791\ub3d9\ud558\ub294 \ucee4\ub110 \ub514\ubc84\uac70\ub97c 6s 14.5.1\uc5d0 \ud638\ud658\ub418\ub3c4\ub85d \uba87\uac00\uc9c0 \uc0bd\uc9c8\uc744 \ud588\uc9c0\ub9cc, \uc2e4\ud328\ud588\ub2e4.<br>I&#8217;ve just tried to make working kernel debugger which only supported A11 devices to iPhone 6s\/iOS 14.5.1, but I failed.<\/p>\n\n\n\n<p>\uc815\ud655\ud788 \ub9d0\ud558\uc790\uba74, <code>kext_insert<\/code> \ud568\uc218\uc758 __PRELINK_INFO \uc138\uadf8\uba3c\ud2b8\uc5d0 \uc788\ub294 \uc5ed\uc9c1\ub82c\ud654\ub41c kext dictionary\ub97c \ub123\ub294\ub370\uc5d0\uc11c \ub9c9\ud614\ub294\ub370,<br>Especially, got stucked to get working <code>static void kext_insert(struct kext_load_info *info)<\/code> function which insert unserialized kext dictionary.<\/p>\n\n\n\n<p>__PRELINK_INFO \uc138\uadf8\uba3c\ud2b8 \ub9c8\uc9c0\ub9c9\uc5d0 \uc544\uc774\ud3f08\uc5d0\uc11c\ub294 &lt;\/array&gt;&lt;\/dict&gt;\ub85c \ub05d\ub098\uc9c0\ub9cc, 6s\uc758 \uacbd\uc6b0 &lt;\/data&gt;&lt;\/dict&gt;\ub85c \ub05d\ub09c\ub2e4\ub294 \uc810\uc774\uc5c8\ub2e4.<br>In last part of __PRELINK_INFO segments, It ends with &lt;\/array&gt;&lt;\/dict&gt; on iPhone 8, <br>However, on 6s, it ends with &lt;\/data&gt;&lt;\/dict&gt;.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>iPhone 8 Kernel<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"585\" height=\"264\" src=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.38.34.png\" alt=\"\" class=\"wp-image-2284\" srcset=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.38.34.png 585w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.38.34-300x135.png 300w\" sizes=\"auto, (max-width: 585px) 100vw, 585px\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>iPhone 6s Kernel<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"515\" height=\"220\" src=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.39.30.png\" alt=\"\" class=\"wp-image-2285\" srcset=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.39.30.png 515w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.39.30-300x128.png 300w\" sizes=\"auto, (max-width: 515px) 100vw, 515px\" \/><\/figure>\n\n\n\n<p><br>\uc544\uc774\ud3f08 \uae30\uae30\uc5d0\ub294 0xFFFFFFF0095A437A\uc9c0\uc810\uc5d0 \uc0bd\uc785\ud558\uae30\uc5d0<br>6s\uc5d0\uc11c \ucd5c\ub300\ud55c \ube44\uc2b7\ud55c \uc9c0\uc810\uc744 \ucc3e\uc544 0xFFFFFFF007B69F25 \uc9c0\uc810\uc5d0 kext dictionary\ub97c \uc0bd\uc785\ud558\ub824\uace0 \uc2dc\ub3c4\ud558\uc600\ub2e4.<\/p>\n\n\n\n<p>Actually kext dictionary inserts in 0xFFFFFFF0095A437A on iPhone 8,<br>so finding as close a spot as possible, tried to insert dict in 0xFFFFFFF007B69F25 on iPhone 6s.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>iPhone 8 Kernel\/14.5.1<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"550\" height=\"591\" src=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/image-9.png\" alt=\"\" class=\"wp-image-2287\" srcset=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/image-9.png 550w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/image-9-279x300.png 279w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>iPhone 6s Kernel\/14.5.1<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"534\" height=\"546\" src=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.41.59.png\" alt=\"\" class=\"wp-image-2286\" srcset=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.41.59.png 534w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/\uc2a4\ud06c\ub9b0\uc0f7-2024-04-08-\uc624\uc804-4.41.59-293x300.png 293w\" sizes=\"auto, (max-width: 534px) 100vw, 534px\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>pongo_kextload\/source\/pongo_kextload.c<\/em><\/strong><\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:100%\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"dracula\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static void\nkext_insert(struct kext_load_info *info) {\n\t\/\/ Get the kernelcache's __PRELINK_INFO.__info section.\n\tstruct segment_command_64 *prelink_info_segment\n\t\t= macho_get_segment(mh_execute_header, \"__PRELINK_INFO\");\n\tstruct section_64 *prelink_info_section\n\t\t= macho_get_section(prelink_info_segment, \"__info\");\n\t\/\/ Insert the plist before the \"&lt;\/array>&lt;\/dict>\" at the end.\n\tchar *p = ptr_for_va(prelink_info_section->addr);\n\tprintf(\"prelink_info_section->addr: 0x%llx\\n\", prelink_info_section->addr - kernel_slide);\n\tprintf(\"prelink_info_section->size: 0x%llx\\n\", prelink_info_section->size);\n\tchar *begin = p;\n\tp += prelink_info_section->size;\n\twhile (p[-1] == 0) {\n\t\tp--;\n\t}\n\t\/\/while (strcmp(p, \"&lt;\/array>&lt;\/dict>\") != 0) {\n\t\/\/ 3C 2F 61 72 72 61 79 3E 3C 6B 65 79 3E 5F 50 72 65\n\t\/\/ &lt;\/array>&lt;key>_Pre\n\twhile (memcmp(p, \"\\x3C\\x2F\\x61\\x72\\x72\\x61\\x79\\x3E\\x3C\\x6B\\x65\\x79\\x3E\\x5F\\x50\\x72\\x65\", 17) != 0) {\n\t\tif (p &lt;= begin) {\n\t\t\tputs(\"Could not insert kernel extension into __PRELINK_INFO.__info\");\n\t\t\tsleep(15);\n\t\t\treturn;\n\t\t}\n\t\tp--;\n\t}\n\tputs(\"Inserting kernel extension into __PRELINK_INFO.__info\");\n\n\tputs(\"Copying last bytes\");\n\n\tsize_t info_size = strlen(prelink_info_str);\n\t\/\/ Re-insert the \"&lt;\/array>&lt;\/dict>\" at the end.\n\tchar *end = p + info_size;\n\t\/\/strcpy(end, \"&lt;\/array>&lt;\/dict>\");\n\tconst char* aaaa = \"AAAA\";\n\tmemmove(end, p, 1638503);\n\tmemmove(p, prelink_info_str, strlen(prelink_info_str));\n\t\/\/printf(\"%s\", p-14);\n\t\/\/ Patch up the info dict fields. _PrelinkKmodInfo must be unslid.\n\tchar *nnn0 = memmem(p, info_size, \"NNN0\", 4);\n\tchar *nnn1 = memmem(p, info_size, \"NNN1\", 4);\n\tchar *address = memmem(p, info_size, \"ADDRESS\", 7);\n\tchar *size = memmem(p, info_size, \"SIZE\", 4);\n\tchar *kmodinfo = memmem(p, info_size, \"KMODINFO\", 8);\n\tprintf(\"nnn0: %p, nnn1: %p, address: %p, size: %p, kmodinfo: %p\\n\", nnn0, nnn1, address, size, kmodinfo);\n\t\/\/printf(\"sa_for_ptr(info->kext): 0x%llx, info->vm_size: %zu, sa_for_ptr(info->kmod_info): 0x%llx, kext_id: %u\\n\", sa_for_ptr(info->kext), info->vm_size, sa_for_ptr(info->kmod_info), kext_id);\n\t\/\/sleep(120);\n\tformat_hex(address, 16, sa_for_ptr(info->kext));\n\tformat_hex(size, 16, info->vm_size);\n\tformat_hex(kmodinfo, 16, sa_for_ptr(info->kmod_info));\n\tformat_hex(nnn0, 4, kext_id);\n\tformat_hex(nnn1, 4, kext_id);\n\t\/\/ Adjust the __PRELINK_INFO metadata.\n\tprelink_info_section->size += info_size;\n\t\/\/ Increment the kext ID for the next kext.\n\tkext_id++;\n}<\/pre>\n<\/div>\n<\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"472\" height=\"1024\" src=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2661-min-472x1024.jpg\" alt=\"\" class=\"wp-image-2281\" srcset=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2661-min-472x1024.jpg 472w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2661-min-138x300.jpg 138w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2661-min-768x1665.jpg 768w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2661-min-709x1536.jpg 709w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2661-min-945x2048.jpg 945w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2661-min.jpg 1179w\" sizes=\"auto, (max-width: 472px) 100vw, 472px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"503\" height=\"1024\" src=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2659-min-503x1024.jpg\" alt=\"\" class=\"wp-image-2282\" srcset=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2659-min-503x1024.jpg 503w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2659-min-147x300.jpg 147w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2659-min-768x1564.jpg 768w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2659-min-754x1536.jpg 754w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2659-min-1006x2048.jpg 1006w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2659-min-scaled.jpg 1257w\" sizes=\"auto, (max-width: 503px) 100vw, 503px\" \/><\/figure>\n\n\n\n<p>\uc0bd\uc785\ub41c kext dictionary \ub0b4\uc6a9\uc744 \ud655\uc778\ud574\ubd24\uc744\ub54c, \uc81c\ub300\ub85c \ub41c \uac83 \uc0bd\uc785\ub418\uc5c8\uc9c0\ub9cc<br>When I check about inserted kext dictionary, It inserted as well, but<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"552\" height=\"1024\" src=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2660-min-552x1024.jpg\" alt=\"\" class=\"wp-image-2283\" srcset=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2660-min-552x1024.jpg 552w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2660-min-162x300.jpg 162w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2660-min-768x1425.jpg 768w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2660-min-828x1536.jpg 828w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2660-min-1104x2048.jpg 1104w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/IMG_2660-min-scaled.jpg 1380w\" sizes=\"auto, (max-width: 552px) 100vw, 552px\" \/><\/figure>\n\n\n\n<p>\ubb34\uc2a8 \uc774\uc720\uc5d0\uc120\uc9c0 \uc704\uc640 \uac19\uc774 &#8220;ml_static_protect(): 0 &lt; 0xfffffffe000000000&#8221; \ud328\ub2c9 \uba54\uc2dc\uc9c0\uac00 \ub098\ud0c0\ub09c\ub2e4.<br>due to unknown reason, It panic messages with &#8220;ml_static_protect(): 0 &lt; 0xfffffffe000000000&#8221; as above.<\/p>\n\n\n\n<p>\uc0ac\uc2e4 \uc774\ubfd0\ub9cc\uc774 \uc544\ub2c8\ub77c, \uc5ec\ub7ec\uac00\uc9c0\ub97c \uc190\ub308 \ud544\uc694\uac00 \uc788\uc5c8\ub294\ub370,<br>Not only this, but there was also needed to be fix another things,<\/p>\n\n\n\n<p>\ud328\uce58\ud30c\uc778\ub354\uac00 \uc644\uc804\ud788 \uc791\ub3d9\ud558\uc9c0\ub294 \uc54a\uc544 <br>\uc544\uc774\ud3f08 \ucee4\ub110\uacfc \ube44\uad50\ud558\uba74\uc11c footprint\ub97c \ucc3e\uc544 \uc544\ub798 6\uac00\uc9c0\uc758 6s \ucee4\ub110 \uc624\ud504\uc14b\uc744 \ucc3e\uc544\ub0bc \ud544\uc694\uac00 \uc788\uc5c8\ub2e4.<br>Since kernel patchfinder not fully works,<br>I had to find these kernel offsets and fixed with hardcoded offsets and finding footprint. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>g_paniclog_append_noflush_addr<\/li>\n\n\n\n<li>g_kernel_thread_start_addr<\/li>\n\n\n\n<li>g_thread_deallocate_addr<\/li>\n\n\n\n<li>g__enable_preemption_addr<\/li>\n\n\n\n<li>g__disable_preemption_addr<\/li>\n\n\n\n<li>g_kernel_memory_allocate_addr<\/li>\n<\/ul>\n\n\n\n<p>&#8230;..<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em><strong>pongo_kextload\/source\/pf\/14\/pf.c<\/strong><\/em><\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:100%\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"dracula\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;stdio.h>\n#include &lt;stdint.h>\n\n#include \"..\/offsets.h\"\n\n#include \"..\/..\/asm.h\"\n#include \"..\/..\/common.h\"\n\n#include \"..\/..\/third_party\/pongo.h\"\n\n\/* XXX Start original KTRW patchfinders *\/\nbool OSKext_init_patcher_14(xnu_pf_patch_t *patch, void *cacheable_stream) {\n\tconst int MAX_SEARCH = 300;\n\tuint32_t *insn = cacheable_stream;\n\t\/\/ First we need to resolve the ADRP\/ADD target at [2].\n\tvoid *target = RESOLVE_ADRP_ADD(&amp;insn[2]);\n\tif (target == NULL) {\n\t\treturn false;\n\t}\n\t\/\/ Check if the target is \"_PrelinkBundlePath\", which indicates that this function is\n\t\/\/ OSKext::initWithPrelinkedInfoDict(). Bailing here is the most common path.\n\tif (strcmp(target, \"_PrelinkBundlePath\") != 0) {\n\t\treturn false;\n\t}\n\t\/* puts(\"Patching OSKext::initWithPrelinkedInfoDict()\"); *\/\n\t\/\/ Search backwards until we get the prologue. Record the instruction that MOVs from X2.\n\tuint32_t *x2_insn = NULL;\n\tfor (int i = 0;; i--) {\n\t\tif (i &lt; -MAX_SEARCH) {\n\t\t\treturn false;\n\t\t}\n\t\t\/\/ Check for either of the following instructions, signaling we hit the prologue:\n\t\t\/\/ \tSUB  SP, SP, #0xNNN\t\t;; 0xNNN &lt; 0x400\n\t\t\/\/ \tSTP  X28, X27, [SP,#0xNNN]\t;; 0xNNN &lt; 0x100\n\t\tbool prologue = MATCH(insn[i], 0xD10003FF, 0xFFF01FFF)\n\t\t\t|| MATCH(insn[i], 0xA9006FFC, 0xFFC0FFFF);\n\t\tif (prologue) {\n\t\t\tbreak;\n\t\t}\n\t\t\/\/ Check for the instruction that saves argument X2, doCoalesedSlides:\n\t\t\/\/ \tMOV  Xn, X2\n\t\tbool mov_xn_x2 = MATCH(insn[i], 0xAA0203E0, 0xFFFFFFE0);\n\t\tif (mov_xn_x2) {\n\t\t\tx2_insn = &amp;insn[i];\n\t\t}\n\t}\n\t\/\/ Check that we found the target instruction.\n\tif (x2_insn == NULL) {\n\t\treturn false;\n\t}\n\t\/\/ Patch the instruction to zero out doCoalesedSlides:\n\t\/\/ \tMOV  Xn, XZR\n\t*x2_insn |= 0x001F0000;\n    puts(\"KTRW: Patched OSKext::initWithPrelinkedInfoDict\");\n\t\/\/ We no longer need to match this. Disabling the patch speeds up execution time, since the\n\t\/\/ pattern is pretty frequent.\n\txnu_pf_disable_patch(patch);\n\treturn true;\n}\n\n\/* XXX End original KTRW patchfinders *\/\n\n\/* confirmed working on all KTRR kernels 14.0-14.5 *\/\nbool ktrr_lockdown_patcher_14(xnu_pf_patch_t *patch, void *cacheable_stream){\n    \/* This also hits rorgn_lockdown, where the AMCC CTRR patches are,\n     * but it's easier for me to separate them since the instruction\n     * sequences are so different *\/\n    static int count = 1;\n    uint32_t *opcode_stream = cacheable_stream;\n\n    *opcode_stream = 0xd503201f;\n    opcode_stream[1] = 0xd503201f;\n    opcode_stream[3] = 0xd503201f;\n\n    if(count == 2){\n        xnu_pf_disable_patch(patch);\n        puts(\"KTRW: disabled KTRR MMU lockdown\");\n    }\n\n    count++;\n\n    return true;\n}\n\n\/* confirmed working on all KTRR kernels 14.0-14.5 *\/\nbool amcc_ctrr_lockdown_patcher_14(xnu_pf_patch_t *patch,\n        void *cacheable_stream){\n    \/* On 14.x A10+ there doesn't seem to be a specific lock for\n     * RoRgn, instead we've got these AMCC CTRR registers. We are\n     * patching three of them: lock, enable, and write-disable. See\n     * find_lock_group_data and rorgn_lockdown for more info. *\/\n    static int count = 1;\n    uint32_t *opcode_stream = cacheable_stream;\n\n    \/* str w0, [x16, x17] --> str wzr, [x16, x17] *\/\n    opcode_stream[5] = 0xb8316a1f;\n\n    if(count == 3){\n        xnu_pf_disable_patch(patch);\n        puts(\"KTRW: disabled AMCC CTRR MMU lockdown\");\n    }\n\n    count++;\n\n    return true;\n}\n\n\/* confirmed working on all kernels 13.0-14.5 *\/\nbool IOSleep_finder_14(xnu_pf_patch_t *patch, void *cacheable_stream){\n    xnu_pf_disable_patch(patch);\n\n    g_IOSleep_addr = xnu_ptr_to_va(cacheable_stream);\n\n    puts(\"KTRW: found IOSleep\");\n    printf(\"g_IOSleep_addr: 0x%llx\\n\", g_IOSleep_addr - kernel_slide);\n\n    return true;\n}\n\n\/* confirmed working on all kernels 13.0-14.5 *\/\nbool kernel_map_finder_14(xnu_pf_patch_t *patch, void *cacheable_stream){\n    xnu_pf_disable_patch(patch);\n\n    \/* If we're 13.x, we've landed inside profile_release, if we're 14.x,\n     * we've landed inside _profile_destroy. For vm_map_unwire, it'll be the\n     * branch we're currently sitting at. *\/\n    uint32_t *opcode_stream = cacheable_stream;\n\n    \/* Finally, we can find kernel_map by searching up for the first ADRP\n     * or ADR from where we initially landed *\/\n    uint32_t instr_limit = 150;\n\n    while((*opcode_stream &amp; 0x1f000000) != 0x10000000){\n        if(instr_limit-- == 0)\n            return false;\n\n        opcode_stream--;\n    }\n\n    \/* The ADRP,LDR pairs require another level of indirection for this *\/\n    if(((opcode_stream[1] >> 25) &amp; 5) == 4){\n        g_kernel_map_addr = *(uint64_t *)get_adrp_ldr_target(opcode_stream);\n        g_kernel_map_addr |= ((uint64_t)0xffff &lt;&lt; 48);\n        g_kernel_map_addr = kext_rebase_va(g_kernel_map_addr);\n    }\n    else{\n        uint64_t kernel_map_addr;\n\n        if(*opcode_stream &amp; 0x80000000)\n            kernel_map_addr = get_adrp_add_target(opcode_stream);\n        else\n            kernel_map_addr = get_adr_target(opcode_stream);\n\n        g_kernel_map_addr = xnu_ptr_to_va((void *)kernel_map_addr);\n    }\n\n    puts(\"KTRW: found kernel_map\");\n    printf(\"g_kernel_map_addr: 0x%llx\\n\", g_kernel_map_addr - kernel_slide);\n\n    return true;\n}\n\n\/* confirmed working on all kernels 13.0-14.5 *\/\nbool kernel_thread_start_thread_deallocate_finder_14(xnu_pf_patch_t *patch,\n        void *cacheable_stream){\n    \/* There's two hits for this, but they're identical, so whatever is\n     * matched first will do *\/\n    xnu_pf_disable_patch(patch);\n\n    \/\/ uint32_t *opcode_stream = cacheable_stream;\n\n    \/\/ uint32_t *kernel_thread_start = get_branch_dst_ptr(opcode_stream);\n    \/\/ uint32_t *thread_deallocate = get_branch_dst_ptr(opcode_stream + 8);\n\n    \/\/ g_kernel_thread_start_addr = xnu_ptr_to_va(kernel_thread_start);\n    \/\/ g_thread_deallocate_addr = xnu_ptr_to_va(thread_deallocate);\n\n    \/\/6s 14.5.1 offset\n    g_kernel_thread_start_addr = 0xFFFFFFF00719A308 + kernel_slide;\n    g_thread_deallocate_addr = 0xFFFFFFF007198538 + kernel_slide;\n\n    puts(\"KTRW: found kernel_thread_start\");\n    puts(\"KTRW: found thread_deallocate\");\n\n    printf(\"g_kernel_thread_start_addr: 0x%llx\\n\", g_kernel_thread_start_addr - kernel_slide);\n    printf(\"g_thread_deallocate_addr: 0x%llx\\n\", g_thread_deallocate_addr - kernel_slide);\n\n    return true;\n}\n\n\/* confirmed working on all kernels 13.0-14.5 *\/\nbool panic_finder_14(xnu_pf_patch_t *patch, void *cacheable_stream){\n    xnu_pf_disable_patch(patch);\n\n    uint32_t *opcode_stream = cacheable_stream;\n\n    \/* Look for the start of panic's prologue, trying to match\n     * sub sp, sp, n *\/\n    uint32_t instr_limit = 50;\n\n    while((*opcode_stream &amp; 0xffc003ff) != 0xd10003ff){\n        if(instr_limit-- == 0)\n            return false;\n\n        opcode_stream--;\n    }\n\n    g_panic_addr = xnu_ptr_to_va(opcode_stream);\n\n    puts(\"KTRW: found panic\");\n    printf(\"g_panic_addr: 0x%llx\\n\", g_panic_addr - kernel_slide);\n\n    return true;\n}\n\nbool const_boot_args_finder_14(xnu_pf_patch_t *patch,\n        void *cacheable_stream){\n    \/* I don't know where we landed but const_boot_args is the target\n     * of the ADRP\/ADD one instruction down *\/\n    xnu_pf_disable_patch(patch);\n\n    \/\/ uint32_t *opcode_stream = cacheable_stream;\n\n    \/\/ uint64_t const_boot_args = get_pc_rel_target(opcode_stream + 1);\n    \/\/ g_const_boot_args_addr = xnu_ptr_to_va(const_boot_args);\n\n    \/\/6s 14.5.1 offset\n    g_const_boot_args_addr = 0xFFFFFFF0070B6380 + kernel_slide;\n\n    puts(\"KTRW: found const_boot_args\");\n    printf(\"g_const_boot_args_addr: 0x%llx\\n\", g_const_boot_args_addr - kernel_slide);\n\n    return true;\n}\n\nbool _disable_enable_preemption_finder_14(xnu_pf_patch_t *patch,\n        void *cacheable_stream){\n    \/* We may have landed inside _disable_preemption. The only way\n     * we can tell is if there's a clrex #0xf less than ten instructions up,\n     * so look for that. *\/\n    \/\/ uint32_t *opcode_stream = cacheable_stream;\n    \/\/ uint32_t instr_limit = 10;\n\n    \/\/ while(*opcode_stream != 0xd5033f5f){\n    \/\/     if(instr_limit-- == 0)\n    \/\/         return false;\n\n    \/\/     opcode_stream--;\n    \/\/ }\n\n    xnu_pf_disable_patch(patch);\n\n    \/\/ instr_limit = 10;\n\n    \/* The clrex #0xf is there, go forward for the start of\n     * _disable_preemption. Looking for stp x29, x30, [sp, #-0x10]! *\/\n    \/\/ while(*opcode_stream != 0xa9bf7bfd){\n    \/\/     if(instr_limit-- == 0)\n    \/\/         return false;\n\n    \/\/     opcode_stream++;\n    \/\/ }\n\n    \/\/ g__disable_preemption_addr = xnu_ptr_to_va(opcode_stream);\n\n    \/* _enable_preemption is right under _disable_preemption, so\n     * we grab that also *\/\n    \/\/ instr_limit = 25;\n\n    \/* The clrex #0xf is there, go forward for the start of\n     * _disable_preemption. Looking for stp x29, x30, [sp, #-0x10]! *\/\n    \/\/ while(*opcode_stream != 0xa9bf7bfd){\n    \/\/     if(instr_limit-- == 0)\n    \/\/         return false;\n\n    \/\/     opcode_stream++;\n    \/\/ }\n\n    \/\/ g__enable_preemption_addr = xnu_ptr_to_va(opcode_stream);\n\n    \/\/6s 14.5.1 offset\n    g__enable_preemption_addr = 0xFFFFFFF007268C0C + kernel_slide;\n    g__disable_preemption_addr = 0xFFFFFFF007268BE4 + kernel_slide;\n\n    puts(\"KTRW: found _disable_preemption\");\n    puts(\"KTRW: found _enable_preemption\");\n\n    printf(\"g__enable_preemption_addr: 0x%llx\\n\", g__enable_preemption_addr - kernel_slide);\n    printf(\"g__disable_preemption_addr: 0x%llx\\n\", g__disable_preemption_addr - kernel_slide);\n\n    return true;\n}\n\nbool vsnprintf_finder_14(xnu_pf_patch_t *patch, void *cacheable_stream){\n    \/* We landed in vsnprintf so we need to find its prolouge. Searching\n     * for sub sp, sp, n *\/\n    xnu_pf_disable_patch(patch);\n\n    uint32_t *opcode_stream = cacheable_stream;\n    uint32_t instr_limit = 50;\n\n    while((*opcode_stream &amp; 0xffc003ff) != 0xd10003ff){\n        if(instr_limit-- == 0)\n            return false;\n\n        opcode_stream--;\n    }\n\n    g_vsnprintf_addr = xnu_ptr_to_va(opcode_stream);\n\n    puts(\"KTRW: found vsnprintf\");\n    printf(\"g_vsnprintf_addr: 0x%llx\\n\", g_vsnprintf_addr - kernel_slide);\n\n    return true;\n}\n\nbool ml_nofault_copy_finder_14(xnu_pf_patch_t *patch,\n        void *cacheable_stream){\n    \/* We landed inside ml_nofault_copy so we need to find its\n     * prologue. Searching for stp x28, x27, [sp, #-0x60]! *\/\n    xnu_pf_disable_patch(patch);\n\n    uint32_t *opcode_stream = cacheable_stream;\n    uint32_t instr_limit = 200;\n\n    while(*opcode_stream != 0xa9ba6ffc){\n        if(instr_limit-- == 0)\n            return false;\n\n        opcode_stream--;\n    }\n\n    g_ml_nofault_copy_addr = xnu_ptr_to_va(opcode_stream);\n\n    puts(\"KTRW: found ml_nofault_copy\");\n    printf(\"g_ml_nofault_copy_addr: 0x%llx\\n\", g_ml_nofault_copy_addr - kernel_slide);\n\n    return true;\n}\n\nbool kernel_memory_allocate_finder_14(xnu_pf_patch_t *patch,\n        void *cacheable_stream){\n    \/* kernel_memory_allocate is the dst of the branch three\n     * instructions down *\/\n    xnu_pf_disable_patch(patch);\n\n    \/\/ uint32_t *opcode_stream = cacheable_stream;\n    \/\/ uint32_t *kernel_memory_allocate = get_branch_dst_ptr(opcode_stream + 3);\n\n    \/\/ g_kernel_memory_allocate_addr = xnu_ptr_to_va(kernel_memory_allocate);\n\n    \/\/6s 14.5.1 offset\n    g_kernel_memory_allocate_addr = 0xFFFFFFF0071F10D0 + kernel_slide;\n\n    puts(\"KTRW: found kernel_memory_allocate\");\n    printf(\"g_kernel_memory_allocate_addr: 0x%llx\\n\", g_kernel_memory_allocate_addr - kernel_slide);\n\n    return true;\n}\n\nbool paniclog_append_noflush_finder_14(xnu_pf_patch_t *patch,\n        void *cacheable_stream){\n    \/\/ uint32_t *opcode_stream = cacheable_stream;\n\n\t\/\/ void *target = RESOLVE_ADRP_ADD(opcode_stream + 2);\n    \/\/ target = target ? target : RESOLVE_ADR(opcode_stream + 2);\n\n    \/\/ if(!target)\n    \/\/     return false;\n\n    \/\/ if(strcmp(target, \"\\nPlease go to https:\/\/panic.apple.com to report this panic\\n\"))\n    \/\/     return false;\n\n    xnu_pf_disable_patch(patch);\n\n    \/\/ uint32_t *paniclog_append_noflush = get_branch_dst_ptr(opcode_stream + 3);\n\n    \/\/ g_paniclog_append_noflush_addr = xnu_ptr_to_va(paniclog_append_noflush);\n\n    \/\/6s 14.5.1\n    g_paniclog_append_noflush_addr = 0xFFFFFFF007173C84+ kernel_slide;\n    \/\/add anyway\n    g_const_boot_args_addr = 0xFFFFFFF0070B6380 + kernel_slide;\n    g_kernel_memory_allocate_addr = 0xFFFFFFF0071F10D0 + kernel_slide;\n\n    puts(\"KTRW: found paniclog_append_noflush\");\n    printf(\"g_paniclog_append_noflush_addr: 0x%llx\\n\", g_paniclog_append_noflush_addr - kernel_slide);\n\n    return true;\n}\n\nbool OSKext_slidePrelinkedExecutable_patcher_14(xnu_pf_patch_t *patch,\n        void *cacheable_stream){\n    \/* The STR we matched zeroes vmaddr of all the segments in the\n     * KTRW kext and I don't know why, but patching it out works *\/\n    xnu_pf_disable_patch(patch);\n\n    \/\/ uint32_t *opcode_stream = cacheable_stream;\n    \/\/ opcode_stream[2] = 0xd503201f;\n\n    g_did_patch_slidePrelinkedExecutable = true;\n\n    puts(\"KTRW: patched OSKext::slidePrelinkedExecutable\");\n\n    return true;\n}\n<\/pre>\n<\/div>\n<\/div>\n\n\n\n<p>\uacb0\uad6d \uace0\uce58\ub294\ub370 \uc2dc\uac04\uc774 \ub9ce\uc774 \ub4e4\uac70\ub77c \uc0dd\uac01\ub418\uc5b4 \uadf8\ub0e5 iOS 14.4.2 \ubc84\uc804\uc758 \uc544\uc774\ud3f0 8 \uc911\uace0\ub97c \uc0ac\uae30\ub85c \ud588\ub2e4.<br>I ended up buying used iPhone 8\/iOS 14.4.2, because It takes a lot of time to fix it.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"459\" src=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/image-10-1024x459.png\" alt=\"\" class=\"wp-image-2291\" srcset=\"https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/image-10-1024x459.png 1024w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/image-10-300x135.png 300w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/image-10-768x344.png 768w, https:\/\/h4ck.kr\/wp-content\/uploads\/2024\/04\/image-10.png 1048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/github.com\/jsherman212\/ktrw \uc544\uc774\ud3f08 iOS 14\uc5d0\uc11c\ub9cc \uc791\ub3d9\ud558\ub294 \ucee4\ub110 \ub514\ubc84\uac70\ub97c 6s 14.5.1\uc5d0 \ud638\ud658\ub418\ub3c4\ub85d \uba87\uac00\uc9c0 \uc0bd\uc9c8\uc744 \ud588\uc9c0\ub9cc, \uc2e4\ud328\ud588\ub2e4.I&#8217;ve just tried to make working kernel debugger which only supported A11 devices to iPhone 6s\/iOS 14.5.1, but I failed. \uc815\ud655\ud788 \ub9d0\ud558\uc790\uba74, kext_insert \ud568\uc218\uc758 __PRELINK_INFO \uc138\uadf8\uba3c\ud2b8\uc5d0 \uc788\ub294 \uc5ed\uc9c1\ub82c\ud654\ub41c kext dictionary\ub97c \ub123\ub294\ub370\uc5d0\uc11c \ub9c9\ud614\ub294\ub370,Especially, got stucked to get working static void kext_insert(struct kext_load_info *info)&hellip;&nbsp;<a href=\"https:\/\/h4ck.kr\/?p=2279\" rel=\"bookmark\">\ub354 \ubcf4\uae30 &raquo;<span class=\"screen-reader-text\">KTRW \ucee4\ub110 \ub514\ubc84\uac70 6s \ud3ec\ud305 \uc2e4\ud328 (Failed porting KTRW kernel debugger to iPhone 6s)<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","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":"","footnotes":""},"categories":[1],"tags":[11],"class_list":["post-2279","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-ios"],"_links":{"self":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/2279","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=2279"}],"version-history":[{"count":4,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/2279\/revisions"}],"predecessor-version":[{"id":2292,"href":"https:\/\/h4ck.kr\/index.php?rest_route=\/wp\/v2\/posts\/2279\/revisions\/2292"}],"wp:attachment":[{"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2279"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2279"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/h4ck.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2279"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}