{"id":19947643,"url":"https://github.com/googleprojectzero/ktrw","last_synced_at":"2025-05-03T18:30:50.611Z","repository":{"id":43675633,"uuid":"218111983","full_name":"googleprojectzero/ktrw","owner":"googleprojectzero","description":"An iOS kernel debugger based on a KTRR bypass for A11 iPhones; works with LLDB and IDA Pro.","archived":false,"fork":false,"pushed_at":"2022-10-22T21:45:51.000Z","size":276,"stargazers_count":614,"open_issues_count":5,"forks_count":121,"subscribers_count":49,"default_branch":"master","last_synced_at":"2023-11-07T12:48:59.476Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/googleprojectzero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-28T17:58:02.000Z","updated_at":"2023-11-07T00:53:12.000Z","dependencies_parsed_at":"2023-01-20T05:16:50.595Z","dependency_job_id":null,"html_url":"https://github.com/googleprojectzero/ktrw","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googleprojectzero%2Fktrw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googleprojectzero%2Fktrw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googleprojectzero%2Fktrw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googleprojectzero%2Fktrw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/googleprojectzero","download_url":"https://codeload.github.com/googleprojectzero/ktrw/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224370245,"owners_count":17299968,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T00:36:57.795Z","updated_at":"2024-11-13T00:36:58.340Z","avatar_url":"https://github.com/googleprojectzero.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"KTRW\n===================================================================================================\n\nKTRW is an iOS kernel debugger for devices with an A11 SoC, such as the iPhone 8. It demonstrates\nhow to use debug registers present on these devices to bypass KTRR, remap the kernel as writable,\nand load a kernel extension that implements a GDB stub, allowing full-featured kernel debugging\nwith LLDB or IDA Pro over a standard Lightning to USB cable.\n\nWith the release of the [checkra1n] jailbreak and [pongoOS] pre-boot environment, it is possible to\nload KTRW as a kernel extension directly into the iOS kernelcache, so the original KTRR bypass is\nno longer used.\n\n[checkra1n]: https://checkra.in\n[pongoOS]: https://github.com/checkra1n/pongoOS\n\n\nBypassing KTRR\n---------------------------------------------------------------------------------------------------\n\nKTRR was introduced with the A10 as a means of locking down critical kernel data (including all\nexecutable code) to prevent it from being modified, even by an attacker with a kernel memory\nread/write capability. However, on A11 SoCs, the ARMv8 External Debug registers and a proprietary\nregister called DBGWRAP were left enabled. This makes it possible to subvert execution of the reset\nvector on these devices, skipping the MMU's KTRR initialization and setting a custom page table\nbase that remaps the kernel as writable. Once KTRR has been disabled, it becomes possible to\nexecute dynamically loaded kernel code, i.e., load kernel extensions.\n\nNote that even though the kernel is remapped as writable, the physical pages spanned by the AMCC\nRoRgn remain protected by the memory controller, and thus writes to these physical pages will be\ndiscarded. Bypassing KTRR on the MMU does not defeat KTRR on the AMCC, and thus the only way to\nremap the kernel as writable is to copy the kernel data in the AMCC RoRgn onto new, writable\nphysical pages. But since the AMCC is still protecting the original physical pages, and since the\nreset vector executes from a physical address inside the AMCC RoRgn, the reset vector cannot be\npersistently modified to disable KTRR automatically on reset without a more powerful capability\n(such as a bootchain vulnerability). Thus, the KTRR bypass will disappear once the core resets\nnormally (that is, without being hijacked using the debug registers from another core). This means\nthat the KTRR bypass is not persistent: it will be lost once the device sleeps.\n\n\nUsing KTRW\n---------------------------------------------------------------------------------------------------\n\nKTRW consists of four components: the `pongo_kext_loader` utility, the `kextload.pongo-module`\npongoOS module, the `ktrw_gdb_stub.ikext` kernel extension, and the `ktrw_usb_proxy` USB-to-TCP\nproxy utility. These can be built individually by ruunning `make` in each subdirectory or\ncollectively by running `make` in the top-level directory.\n\nTo use KTRW, we'll run three utilities: [checkra1n], `pongo_kext_loader`, and `ktrw_usb_proxy`.\n\nCheckra1n uses the checkm8 SecureROM exploit to establish a pre-boot environment called pongoOS\ncapable of loading arbitrary code modules and patching the kernel. Running the following command\ncauses checkra1n to listen for attached iOS devices in DFU mode and boot pongoOS:\n\n\t$ /Applications/checkra1n.app/Contents/MacOS/checkra1n -c -p\n\nBy itself pongoOS does not provide the ability to insert XNU kernel extensions into the kernelcache\non the device; in order to do this we use `pongo_kext_loader` and `kextload.pongo-module`. The\n`kextload` pongoOS module adds two new commands to the pongoOS shell: `kernelcache-symbols`, which\nallows uploading a symbol table to resolve kernel symbols, and `kextload`, which inserts an\nuploaded kernel extension into the kernelcache. The `pongo_kext_loader` utility glues everything\ntogether: it listens for attached pongoOS devices, loads `kextload.pongo-module`, inserts the\n`ktrw_gdb_stub.ikext` kernel extension into the iOS kernelcache, and boots XNU.\n\nRun the following command to have `pongo_kext_loader` load `ktrw_gdb_stub.ikext` on the iOS device\nat boot:\n\n\t$ pongo_kext_loader/pongo_kext_loader \\\n\t\tpongo_kextload/kextload.pongo-module \\\n\t\tktrw_gdb_stub/kernel_symbols \\\n\t\tktrw_gdb_stub/ktrw_gdb_stub.ikext\n\nThe final utility that needs to run is `ktrw_usb_proxy`. `ktrw_usb_proxy` is needed to communicate\nwith the kernel extension over USB and relay the data over TCP so that LLDB can connect to it. It\nwill print the data being exchanged over the connection to stdout. Run `ktrw_usb_proxy` with the\nport number LLDB will connect to:\n\n\t$ ktrw_usb_proxy/ktrw_usb_proxy 39399\n\nFinally, connect an iOS device using a USB cable and enter DFU mode. First checkra1n will boot\npongoOS, then `pongo_kext_loader` will insert the KTRW GDB stub kernel extension, and finally XNU\nwill boot. The GDB stub will start running about 30 seconds after the kernel starts booting to give\nthe system time to initialize. (This delay can be configured during build using the\n`ACTIVATION_DELAY` make variable.)\n\nOnce the GDB stub runs, it will claim one CPU core for itself and halt the remaining cores. It will\nalso hijack the Synopsys USB 2.0 OTG controller from the kernel so that it can communicate with the\nhost. As a result, the host will not see the iPhone as an iOS device and the phone (once it has\nbeen resumed) will not be able to send data over USB as normal.\n\nAt this point, you are ready to debug the device.\n\nA few common issues:\n\n* If you're having trouble entering DFU mode using a USB C cable, try using a USB A cable instead.\n* If the device immediately panics when the GDB stub starts to run, the issue may be that the USB\n  hardware is not yet powered. This is likely to be the case if the device has a passcode and the\n  \"USB Accessories\" setting is disabled to prevent USB accessories from connecting when the device\n  is locked. Either disabling the passcode, allowing USB accessories, or unlocking the device\n  before the GDB stub starts should solve the issue. Try changing `ACTIVATION_DELAY` if you need\n  more time to unlock the device.\n* Similarly, do not unplug the device while KTRW is running, as this powers down the USB hardware.\n* If LLDB does not automatically detect that the target is an iOS kernelcache, it's possible that\n  the system halted while a CPU core was in userspace. Try continuing and re-interrupting the\n  target until all CPU cores are running in kernel mode, then reattach to the target.\n* Sometimes the screen becomes unresponsive right after connecting LLDB. I have been unable to\n  identify/fix the root cause of this issue, but it seems to help if you connect with LLDB as soon\n  as the GDB stub first halts the device, then immediately continue to minimize the amount of time\n  the system is stopped during this initial halt.\n* KTRW is incompatible with on-device debugging, e.g. using Xcode or debugserver to debug a process\n  on the device.\n* The pongoOS kernel extension loading module currently has several limitations: it will only work\n  on new-style kernelcaches and only one kernel extension can be inserted into the kernelcache.\n\nThe method described here has been tested as working on iOS 13.3. Prior versions of KTRW used a\nKTRR bypass to load kernel extensions rather than relying on checkra1n; `ktrw_kext_loader`\nimplements this technique, and it should be used instead when debugging iOS 12.\n\n\nDebugging with LLDB\n---------------------------------------------------------------------------------------------------\n\nUse LLDB to connect to `ktrw_usb_proxy` and communicate with `ktrw_gdb_stub.ikext`. Here I have\nconnected to an iPhone 8 running iOS 12.1.2:\n\n\t$ lldb kernelcache.iPhone10,1.16C101\n\t(lldb) target create \"kernelcache.iPhone10,1.16C101\"\n\tCurrent executable set to 'kernelcache.iPhone10,1.16C101' (arm64).\n\t(lldb) settings set plugin.dynamic-loader.darwin-kernel.load-kexts false\n\t(lldb) gdb-remote 39399\n\tKernel UUID: 94463A80-7B38-3176-8872-0B8E344C7138\n\tLoad Address: 0xfffffff027e04000\n\tKernel slid 0x20e00000 in memory.\n\tLoaded kernel file kernelcache.iPhone10,1.16C101\n\tProcess 2 stopped\n\tTarget 0: (kernelcache.iPhone10,1.16C101) stopped.\n\t(lldb)\n\nYou can use `thread list` to list the code running on each physical CPU core. (Note that one core\nis reserved for the debugger itself, so it will not show up in the list.)\n\n\t(lldb) th l\n\tProcess 2 stopped\n\t* thread #1: tid = 0x0002, 0xfffffff027ffda18 kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol1734$$kernelcache.iPhone10,1.16C101 + 272\n\t  thread #2: tid = 0x0003, 0xfffffff027ffda18 kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol1734$$kernelcache.iPhone10,1.16C101 + 272\n\t  thread #3: tid = 0x0004, 0xfffffff027ffda18 kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol1734$$kernelcache.iPhone10,1.16C101 + 272\n\t  thread #4: tid = 0x0005, 0xfffffff027ffda18 kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol1734$$kernelcache.iPhone10,1.16C101 + 272\n\t  thread #5: tid = 0x0006, 0xfffffff027ffda18 kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol1734$$kernelcache.iPhone10,1.16C101 + 272\n\t(lldb)\n\nBecause KTRR has been disabled, it is possible to patch kernel memory:\n\n\t(lldb) x/12wx 0xfffffff027e04000\n\t0xfffffff027e04000: 0xfeedfacf 0x0100000c 0x00000000 0x00000002\n\t0xfffffff027e04010: 0x00000016 0x00001068 0x00200001 0x00000000\n\t0xfffffff027e04020: 0x00000019 0x00000188 0x45545f5f 0x00005458\n\t(lldb) mem wr -s 4 0xfffffff027e04000 0x11223344 0x55667788\n\t(lldb) x/12wx 0xfffffff027e04000\n\t0xfffffff027e04000: 0x11223344 0x55667788 0x00000000 0x00000002\n\t0xfffffff027e04010: 0x00000016 0x00001068 0x00200001 0x00000000\n\t0xfffffff027e04020: 0x00000019 0x00000188 0x45545f5f 0x00005458\n\nResume executing the kernel with `continue`. You can interrupt it at any time with `^C`:\n\n\t(lldb) c\n\tProcess 2 resuming\n\t(lldb) ^C\n\tProcess 2 stopped\n\tTarget 0: (kernelcache.iPhone10,1.16C101) stopped.\n\t(lldb)\n\nYou can set breakpoints as usual. KTRW currently only supports hardware breakpoints, but LLDB will\nautomatically detect this and set the appropriate breakpoint type:\n\n\t(lldb) b 0xfffffff0282753b4\n\tBreakpoint 1: where = kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101, address = 0xfffffff0282753b4\n\t(lldb) c\n\tProcess 2 resuming\n\tProcess 2 stopped\n\t* thread #4, stop reason = breakpoint 1.1\n\t    frame #0: 0xfffffff0282753b4 kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101\n\tkernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101:\n\t-\u003e  0xfffffff0282753b4 \u003c+0\u003e:  sub    sp, sp, #0x80             ; =0x80\n\t    0xfffffff0282753b8 \u003c+4\u003e:  stp    x28, x27, [sp, #0x20]\n\t    0xfffffff0282753bc \u003c+8\u003e:  stp    x26, x25, [sp, #0x30]\n\t    0xfffffff0282753c0 \u003c+12\u003e: stp    x24, x23, [sp, #0x40]\n\tTarget 0: (kernelcache.iPhone10,1.16C101) stopped.\n\t(lldb)\n\nSingle-stepping works as expected:\n\n\t(lldb) si\n\tProcess 2 stopped\n\t* thread #4, stop reason = instruction step into\n\t    frame #0: 0xfffffff0282753b8 kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101 + 4\n\tkernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101:\n\t-\u003e  0xfffffff0282753b8 \u003c+4\u003e:  stp    x28, x27, [sp, #0x20]\n\t    0xfffffff0282753bc \u003c+8\u003e:  stp    x26, x25, [sp, #0x30]\n\t    0xfffffff0282753c0 \u003c+12\u003e: stp    x24, x23, [sp, #0x40]\n\t    0xfffffff0282753c4 \u003c+16\u003e: stp    x22, x21, [sp, #0x50]\n\tTarget 0: (kernelcache.iPhone10,1.16C101) stopped.\n\t(lldb) si\n\tProcess 2 stopped\n\t* thread #4, stop reason = instruction step into\n\t    frame #0: 0xfffffff0282753bc kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101 + 8\n\tkernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101:\n\t-\u003e  0xfffffff0282753bc \u003c+8\u003e:  stp    x26, x25, [sp, #0x30]\n\t    0xfffffff0282753c0 \u003c+12\u003e: stp    x24, x23, [sp, #0x40]\n\t    0xfffffff0282753c4 \u003c+16\u003e: stp    x22, x21, [sp, #0x50]\n\t    0xfffffff0282753c8 \u003c+20\u003e: stp    x20, x19, [sp, #0x60]\n\tTarget 0: (kernelcache.iPhone10,1.16C101) stopped.\n\t(lldb)\n\nWatchpoints are also supported:\n\n\t(lldb) wa s e -s 8 -w read_write -- 0xfffffff027e04000\n\tWatchpoint created: Watchpoint 1: addr = 0xfffffff027e04000 size = 8 state = enabled type = rw\n\t    new value: 6153737367135073092\n\t(lldb) reg w x1 0xfffffff027e04000\n\t(lldb) c\n\tProcess 2 resuming\n\t\n\tWatchpoint 1 hit:\n\told value: 6153737367135073092\n\tnew value: 6153737367135073092\n\tProcess 2 stopped\n\t* thread #5, stop reason = watchpoint 1\n\t    frame #0: 0xfffffff028275418 kernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101 + 100\n\tkernelcache.iPhone10,1.16C101`___lldb_unnamed_symbol4960$$kernelcache.iPhone10,1.16C101:\n\t-\u003e  0xfffffff028275418 \u003c+100\u003e: and    x21, x9, x10\n\t    0xfffffff02827541c \u003c+104\u003e: add    x10, x11, x10\n\t    0xfffffff028275420 \u003c+108\u003e: add    x8, x10, w8, sxtw\n\t    0xfffffff028275424 \u003c+112\u003e: and    x26, x9, x8\n\tTarget 0: (kernelcache.iPhone10,1.16C101) stopped.\n\t(lldb) x/4i $pc-8\n\t    0xfffffff028275410: 0x9360fd29   asr    x9, x9, #32\n\t    0xfffffff028275414: 0xa9402eea   ldp    x10, x11, [x23]\n\t-\u003e  0xfffffff028275418: 0x8a0a0135   and    x21, x9, x10\n\t    0xfffffff02827541c: 0x8b0a016a   add    x10, x11, x10\n\t(lldb) reg r x23 x10 x11\n\t     x23 = 0xfffffff027e04000\n\t     x10 = 0x5566778811223344\n\t     x11 = 0x0000000200000000\n\t(lldb)\n\nLLDB limits watchpoints to 1, 2, 4, or 8 bytes in size, even though the hardware supports even\nlarger watchpoints.\n\n\nDebugging with IDA Pro\n---------------------------------------------------------------------------------------------------\n\nIt is possible to use IDA Pro 7.3 or later for iOS kernel debugging, but there are some notable\nlimitations prior to IDA Pro 7.5.\n\nOn IDA Pro 7.3 and 7.4, you will need to modify `dbg_xnu.cfg` to add support for the KTRW GDB\nstub's `target.xml` features. You can find the required changes in `misc/dbg_xnu.cfg.patch`. I also\nrecommend setting up `KDK_PATH` to point to a directory containing copies of any kernelcaches you\nwill be debugging to reduce the amount of memory IDA downloads off the device. You will also need\nto be sure to always use hardware breakpoints rather than software breakpoints, which are currently\nunsupported.\n\nKTRW should work out of the box with IDA Pro 7.5.\n\nOpen the kernelcache corresponding to the device in IDA Pro, select the remote XNU debugger, and\nconnect to the port on which `ktrw_usb_proxy` is listening. You should see IDA rebase the\nkernelcache and start downloading data off the device. This may take a long time to complete.\n\n\nAdding support for new platforms\n---------------------------------------------------------------------------------------------------\n\nKernel extensions are linked against the symbols supplied in the `ktrw_gdb_stub/kernel_symbols`\ndirectory. The files in this directory are named `\u003chardware-version\u003e_\u003cbuild-version\u003e.txt`, where\n`\u003chardware-version\u003e` is the hardware identifier (e.g. iPhone10,1) and `\u003cbuild-version\u003e` is the\niOS build version (e.g. 16C101). There must be a single file per kernelcache UUID, so more\nhardware/build version pairs may be supported than what is implied by the file name. Each file\nshould declare all supported hardware/build pairs in the header.\n\n\nBreakpoints and watchpoints\n---------------------------------------------------------------------------------------------------\n\nKTRW currently uses hardware breakpoints and watchpoints. The hardware supports 6 breakpoints and 4\nwatchpoints, which should be sufficient for most basic debugging tasks. It is possible to add\nsupport for software breakpoints.\n\n\nDynamic code generation\n---------------------------------------------------------------------------------------------------\n\nCurrently, LLDB automatically disables dynamic code generation when debugging Darwin kernels\nwithout testing whether or not the feature is supported, which breaks the ability to call kernel\nfunctions from within LLDB.\n\nAs a workaround, you can build LLDB from source and comment out the line\n`process-\u003eSetCanRunCode(false)` from `DynamicLoaderDarwinKernel.cpp`. This will allow you to run\n`call` and `expression` commands in LLDB that are evaluated in the iOS kernel.\n\n\nDebugging the reset vector\n---------------------------------------------------------------------------------------------------\n\nWhile it is possible to use the CoreSight External Debug registers to debug execution of the reset\nvector before the MMU has been enabled, this use case is not supported by KTRW. The main reason is\nthat KTRW disables core resets while the device is plugged in and active (i.e. not sleeping) anyway\nin order to make the KTRR bypass partially persistent.\n\n\nA note on security and safety\n---------------------------------------------------------------------------------------------------\n\nDo not run KTRW on your personal iPhone: only run it on a dedicated research device that you do not\nmind permanently damaging. KTRW expects the kernel task port to be exposed to unprivileged\napplications, which critically compromises the system's security. Additionally, KTRW operates by\nrunning a debugger on a single core that never sleeps, which consumes a lot of power and generates\nexcessive heat that could permanently damage the device or cause physical burns.\n\n\n---------------------------------------------------------------------------------------------------\nDeveloped and maintained by Brandon Azad of Google Project Zero, \u003cbazad@google.com\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoogleprojectzero%2Fktrw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoogleprojectzero%2Fktrw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoogleprojectzero%2Fktrw/lists"}