 So the next talk is called KTRW the journey to build a debuggable iPhone Well hardware debugging of an iPhone is usually not possible It's not possible of iOS devices or it wasn't possible for iOS devices and Security research of the kernel is therefore quite a challenge Well with the Apple a 10 chip Apple implemented a thing called kernel text read only regions which is called KTRR in short and Brandon asset of Google project zero he found a way to make a debuggable iPhone and tonight he's Gonna tell us how he broke this car to KTRR and how he made Debuggable iPhone out of a regular production iPhone. Please give a warm round of applause to Brandon Awesome. Thank you very much. I'm very excited to be here. Thank you for showing up to my talk and Today I'm going to take you along my journey to build a capability that I've wanted to have for a very long time a debuggable iPhone So what exactly do I mean by a debuggable iPhone? Well in order to kind of give you the context that you need to understand this I'm going to need to talk about something which isn't frequently talked about in public and that's the thing called Dev fused devices Development fused devices prototype iPhones These are all names for similar concept, which is a type of device a type of iPhone that has extra Debug capabilities built into it. So that's things like serial wire debug JTAG Basically functionality that now allows you to debug the phone at a very low level for example doing things like Single-stepping through the bootloader putting breakpoints in kernel mode and dumping registers modifying registers source of things which would be very important for Apple engineers to be able to do but which are Definitely not something Apple wants available on production iPhones distributed and mass Now in order to connect to these special type of iPhones debug capabilities. You need a Really special type of cable usually called a probe It here's an example of what's called a conzi cable It has a special lightning connector on one end Which has a special accessory ID burned into it which allows it to communicate with the debug hardware on the phone It has a controller which is the chunky part in the middle Which is able to talk the debugging protocol and it has USB port on the other end which you can connect to a laptop and On the laptop you would typically run software for example. There's this tool which you can find Online called asteris this is not software which Apple is willingly distributing. This is kind of as I understand it leaked code so it's not something which Is like you know sanctioned but There are people who are able to obtain this software and use it to operate these debug probes Here's an example of a screenshot where someone was able to use a Kong serial wire debug probe and connect it to a 32-bit dev-used iPhone and You can see register dumps. You can read and write memory do so all sorts of really low-level debugging on this iPhone Now I need to say I do not use dev views devices I don't have access to these devices. I don't want to have access to these devices to do my work That being said it would really be incredibly useful to have such a low-level and powerful debug capability So this is the motivation for my research project I wanted to find some way to build a debug capability on a regular Apple certified iPhone Some way to build my own homebrewed dev phone And there were a number of different features that I wanted present in this homebrewed dev phone I wanted the ability to patch kernel memory and in particular the ability to patch the executable code in the kernel for example modifying existing instructions or Injecting kernel shell code things like that I wanted the ability to Kind of do your standard debugger features set break points at watch points Kind of the third item that I wanted this debug phone to be capable of is I wanted it to use only You know standard off-the-shelf debuggers. I didn't want to use or to depend upon Proprietary Apple software like asteris in order to operate The next item is I wanted this homebrewed dev phone to be updateable So I wanted to find some sort of low-level vulnerability such that if I'm going to spend, you know three months trying to create this Debuggable phone and then Apple is able to patch The whatever technique was being used in the next version of iOS and now all of a sudden I no longer. I'm able to debug the latest version Certainly, this would be very useful. I can always Diff kind of the differences between subsequent versions of iOS to still get useful information from my debugger But I would really love to be able to amortize the development cost of this debugger over many iterations of the iOS operating system so keep this capability alive as long as possible In practice what this meant was I was going to be looking for perhaps a bootloader vulnerability Maybe some sort of hardware bug something which was Either difficult to patch or even if it was patched It was early enough in the boot process that it would still be possible to update the version of the iOS kernel running on the device and the Final thing is that I wanted this dev phone to use only parts that you could obtain at an Apple store So no specially fused CPUs no Special debug cables nothing of that sort Now I want to mention something really really important that happened Probably the most important thing to happen to iOS security research in several years And that is pretty much just a couple of days before I was about to open source KTRW Axiom X released a boot ROM exploit for all iPhones between the iPhone 4s and the iPhone 10 Now the boot ROM exploit is actually Strictly more powerful than the capability used in KTRW Everything that I want to do and my debug phone is totally possible to do using the boot ROM exploit alone So I want to tell you this just so that you're aware that many of the assumptions that I made Going into this project really don't hold anymore, but they did hold at the time that I started this research And I do expect that future debug capabilities and future research platforms on the iPhone will be based around the boot ROM exploit instead So with that let's talk about the main mitigation that makes kernel debugging on iPhone right now Both really hard to do and also so important And that's a mitigation called KTRR If we look back at the list of requirements that I wanted in my homebrew Dev phone The very first item on this list was I wanted the ability to patch kernel memory and in particular to patch the executable code Now normally on most systems, this isn't actually that difficult Once you have the ability to read and write kernel memory You can just modify page tables make some page and memory read write execute stuff your shellcode in there And you're basically done But on the iPhone Apple has added a mitigation called KTRW And the idea is that we have a kernel caching memory that's been you know put there by some sort of secure boot process But once it's in memory and the system is running Apple would really like a way to guarantee that the kernel cache gets locked down as much as possible and Any data in it which really does not need to be writable is never going to be modified basically keep The guarantee that once an iPhone is booted the code running in your kernel is exactly the code that was protected by and Verified by the secure boot process. So there is some data in your kernel, which does need to be writable But there's also a bunch of data which really does not need to be writable The most prominent example is the executable code. Clearly. We don't want that to be changeable But there's also a bunch of other pieces of data which are worth protecting for example You have strings maybe format strings Virtual method tables the page tables that are mapping the kernel cache itself into memory All of these additional pieces of data Apple would really like to have them be protected and not modifiable And that's what KTRR does. It's going to lock down all of this data that we want to be read-only as the defenders So as far as we know KTRR stands for kernel text read-only region So what KTRR boils down to is it's a very strong form of write X or execute protection It's available in Apple A10 CPUs and later and it provides two very strong guarantees First is that all writes to memory inside of the region protected by KTRR will fail But this basically is what provides kind of the lock down guarantee that what was put there by the secure bootchain Kind of stays that way and can't be changed But there's another part to it which is equally important and that is that all Instruction fetches from memory outside of the protected region are guaranteed to fail This is what ensures that you can't put new executable code in the kernel But the only code that you're allowed to run is the kernel zone code So in order to kind of understand how this works in a little more detail Let's look at an oversimplified diagram of how CPU works So here we have the CPU cores. This is for example an a11 CPU with six cores The little purple box in the bottom corner is the MMU We have the highest level of the cache hierarchy is the L2 cache behind that is the memory controller called AMCC and Then this is connected to DRAM. Now the kernel lives contiguously in physical memory in DRAM and this is what Apple wants to protect with KTRR So the first step in order to lock down this region happens on the MMU. So let's zoom in to a single CPU core What Apple has done as far as I understand is basically just add a couple of registers to the MMU That point to the beginning and ending address of the region to protect What this allows us to do is the CPU core can now check whether each instruction It's about to execute violates the security guarantees we want from KTRR So for example, let's say the CPU wants to issue a right to a physical address outside of the KTRR region That's fine. We can execute we can write to that memory. So this will be allowed by the MMU and the right will go through If however, we try to issue a right to an address that points to inside the KTRR region This violates the security properties of KTRR and so the MMU will recognize this It'll deny the right and it'll cause that instruction to fault Similarly, if the CPU tries to execute an instruction that is fetched from an address outside of the KTRR region MMU can recognize this and cause that instruction fetch default But so here's kind of the new picture of the CPU cores We have a bunch of new registers in the MMU that kind of have this KTRR protection built into them The next however, this isn't the complete picture that we need in order to Protect this memory see there are other Devices that are connected to your system all sorts of peripherals. This could be like a Wi-Fi chip This could be like a USB stack all sorts of thing any sort of hardware device which could Issue DMA commands to your memory controller. So in order to protect against malicious peripherals DMAing over the protected region We think that Apple has added a registers to the memory controller as well that also point to the beginning and ending address of This lockdown region such that that way anytime some peripheral tries to DMA over the secure region The memory controller sees that this DMA doesn't look valid and it'll just discard the right So this is kind of the picture that the hardware now looks like in order to support KTRR But this isn't actually the complete story either because There's one specific edge case that needs to be properly handled and that's when a CPU core goes to sleep for a little bit And then wakes up what's called resetting Anytime the a CPU core goes to sleep It's going to power down registers and in particular the MMU Registers which store the KTRR bounds are going to lose their value and be reset to zero So when the CPU wakes up from sleep We need some way to reset those registers to point to the beginning and ending bounds of the lockdown region So the reset vector is the first piece of code that gets executed when a CPU core wakes from sleep And it does so with the MMU off And what Apple has done is they've added code to the reset vector that basically just initializes those KTRR registers The beginning and ending bounds are stored in these global variables These variables by the way happen to lie inside of the locked down region, so they can't be modified And once it reads those values into general purpose registers It writes those bounds into special system registers That are used by the MMU to verify the KTRR security properties so once this code executes KTRR will be locked down on the MMU and Once again, you can no longer Execute memory that lies outside of the lockdown region So now that we have kind of a high-level understanding of how KTRR works Let's look at how it's possible to break KTRR and we'll start with a few historical examples There are two historical instances of partial KTRR bypasses up till now And the first one came out pretty soon after the KTRR mitigation was first introduced And it was discovered by Luca Tedesco who's going to be giving a talk. I think in this room tomorrow evening So what Luca found was that Apple had left an instruction in the kernel cache that They didn't mean to leave executable, but it accidentally was this was the MSR TT BR1 instruction Which sets the special TT BR1 register This register stores the physical address of the root of the page table hierarchy Which means that if you're able to modify the value of this register Then you were able to supply your own custom page table hierarchy and therefore remap virtual memory onto new physical pages So this is exactly what he did. He just chose a remapping that placed the read-only regions of kernel memory onto new physical pages that contained a copy of the original kernel data Now it's important to note that KTRR was still actually fully initialized At the point at which you were able to execute this MSR instruction so We can patch read-only data, but we can't execute new kernel code because KTRR lockdown on the MMU still did occur So what the KTRR bypass in 10.1 basically achieved was limiting what was protected by KTRR down from the whole read-only region to only the executable code But we get a whole bunch of new data in the kernel, which is now writable The second KTRR bypass That was released was more of a bypass in spirit than in practice But it's definitely a very important tool and a huge inspiration for my research so back in iOS 11.1.2 Ian beer found that the debugging functionality in the ARM specification was actually implemented in Apples processors and could be used to implement a full-featured kernel debugger So if you read the ARM architecture reference manual, you'll find that there are Documentation on a feature called self-hosted debugging Basically the architecture provides a set of debug registers, which you can access via MSR instructions And you can use these debugging registers to set breakpoints in kernel mode and also to by implementing exception handling code in your exception handler you can catch your own Breakpoint exceptions and basically had the kernel implement its own debugger for example, this might be somewhat analogous to using a KDP to debug a Mac book Now KDP has actually been removed from the iOS kernel that's distributed on production devices however, the Debugging registers that one might use to implement this are still present still fully functional And what Ian found was that he could use return-oriented programming to set the values of these registers correctly in order to implement a Rather full-featured kernel debugger He built something that works with LLDB proved quite useful And in particular it was able to by setting you know breakpoint single-stepping modify register values Execute existing instructions in the kernel in basically arbitrary order So not native like arbitrary shellcode execution, but pretty darn close So I Started this project of trying to find some sort of KTRR bypass by looking in kind of the Places that I thought would be more powerful find more Powerful KTRR bypass is more likely to lead to something that would be persistent across multiple versions via OS Where I started was looking in iBoot. I was trying to find some sort of iBoot bug in the image for parsing and verification functions. I didn't end up finding anything there Next I kind of read through several sections of the ARM architecture manual Saw some interesting things about you know, maybe you know if you have weird malformed TLB Entry if you have weird malformed page table entries. You could do something weird with the TLB That didn't really end up yielding anything useful I played around a little bit with you know, I kind of misunderstood how KTRR worked a little bit And I thought you know, maybe there's a way to Corrupt the L2 cache and then bypass KTRR that way that didn't end up really working either So I kind of you know tried a bunch of things none of them really panned out and I put This research on the back burner for a while And it was actually while I was doing something totally unrelated that I happened to generate a kernel panic Which reignited my interest So I was playing around with interrupts and I'd managed to get a CPU core stuck in an infinite loop With interrupts disabled in kernel mode And I got a panic message which said you know panic watchdog timer timeout CPU on has failed to respond So kind of the exact thing you would expect when a CPU isn't responding because it's stuck Burning CPU cycles in an infinite loop eventually system notices and panics because you know, there's some significant problem here But what really caught my attention about this panic message was something much earlier in it where it says attempting to forcibly halt CPU one Now this was really interesting to me because according to what I'd read from the arm manual there wasn't any Standard way for one CPU core to halt a second CPU like there's no MSRs that you can write to I didn't really remember any way to accomplish this So what I figured was there's probably some sort of like proprietary interface going on here where you know, maybe there's special CPU control registers which are accessible via MMIO and Somehow XNU is trying to leverage those in order to halt the CPU. So this seems like you know pretty interesting I've never seen something like this before So I decided to you know, pull up the Security engineering tools needed to figure out what was going on here So I grep through the XNU source code to try to find the string attempting to forcibly halt CPU Pretty quickly came to the function ML debug wrap halt CPU which seemed to implement this functionality It takes the index of which CPU you want to halt so on a CPU with six cores So to be the index zero through five And the actual part which halts the CPU is just right down here a couple lines lower So what this does is it reads a pointer to some volatile memory from a per CPU data structure This is memory this variable that stores the pointer to the memory is called debug wrap reg and then the actual part of the code which halts the CPU is Simply consists of the single line where it writes Some special debug halt of value to the debug wrap reg So this really strongly Supports the idea that this is some you know special mmio register and when I was looking online for trying to find references to this debug wrap thing I wasn't really getting any results. So it kind of really strongly suggested that yes This is some sort of proprietary Apple specific interface The other thing that kind of caught my attention was this reference to something called core site I remembered hearing, you know core site somewhere else before but it doesn't really didn't really know what it was Marked it as something to come back to But what really caught my attention when I was looking through this file was a function just a few lines down Called ML debug wrap halt CPU with state This does basically the same thing as the other function except in addition to halting a CPU It also reads out the values of the registers on that CPU that was just halted and the way that does this is actually quite remarkable So first off you can see that there is another reference to this core site thing It says ensure memory mapped core site registers can be written So clearly something with core site is important here. Maybe it's the block of registers that contain this functionality But the important part is this for loop right below which iterates I over the indices of your general purpose registers What this code does is first it's going to generate the numerical opcode for the instruction Which writes the value of general purpose register Xi into the special system register debug DTR So this isn't an instruction which already exists in the kernel cache It is just literally generating the numerical value of the opcode for that instruction Next it passes that opcode into ML debug wrap stuff instruction And finally it reads the value of the debug DTR register and writes the value into the output buffers Xi field So this is actually really interesting because of what it suggests is that ML debug wrap stuff instruction is somehow Executing dynamically generated instructions and this really flies in the face of the security model That KTR is designed for so KTR is meant to ensure that you know all of the instructions in your kernel cache Those are the only ones that you're allowed to execute But here there's some sort of interface which seems to be able to execute any instruction you want on a halted CPU So this is definitely really interesting Now just because there's code to do something in XNU doesn't actually mean that it necessarily works in practice So I basically just decided to test to see if this code actually runs I pulled up an old kernel exploit that I'd written and I basically just wrote an Packed together something that would call the function ML debug wrap halt CPU with state Pass it an output buffer and then dump the contents of that buffer And what I found was that the output buffer really did look like a bunch of registers So there's a bunch of stuff which was zero which you know is kind of weird But the value of CPSR Does look correct. It actually looks like a CPU running in kernel mode And the value of PC it doesn't really look like a normal kernel virtual address Those usually start with you know like ffff, but it does really look like some sort of physical address perhaps And with a little bit of digging into this I pretty quickly discovered that this is a physical address of an instruction in the reset vector Now things are really really getting interesting because what this suggests is that we've managed to halt the execution of a CPU core While it's actually running the reset vector and in particular before the MMU has been turned on now This is a really critical point in time for KTRR because before the MMU has been turned on KTRR is unable to protect the CPU from executing instructions outside of the locked-down region So of course what I really wanted to know was how do we use this capability in order to bypass KTRR? Well, it turns out that there's kind of a more fundamental question that I need to answer first Which was what exactly is this core site thing anyway? It's really hard in practice to at least for me to exploit something without kind of knowing a general sense of how something works And so I basically just searched for core site in the ARM reference manual and Came across a bunch of references to core site in connection with something called the external debug interface Now the external debug interface it turns out is pretty much just a different way of accessing the same functionality that Ian used in his self-hosted kernel debugger So the in the self-hosted debugging interface you write to these debug registers using MSR instructions The external debug interface provides kind of the very similar functionality. It's probably the same Debugging hardware under the hood that you're driving, but the interface to access these registers is via MMIO Rather than via executing MSR instructions So this means that basically the functionality that is necessary to build a kernel debugger is still there Even though the BROC gadgets that Ian used to activate it are taken away the memory mapped interface still exists and In fact, this isn't even the first time not even close to the first time that someone has tried to use debugging registers in an ARM processor in order to mount some sort of privileged attack Shin Yu Ning and Feng Wei Zhang presented an attack at Mosec 2019 where they basically were able to leverage the same debugging registers on Android phones to break the protection of the Secure world so they were able to Make one CPU core debug another CPU core make that second CPU core Execute instructions to enter the secure world at EL3 and then also make it execute instructions That would cause it to read and write memory in the secure world So just to summarize kind of the key concepts behind the external debug interface It is an on-chip debugging architecture. It provides per CPU Debug registers which are accessible via MMIO The actual interface itself how to use these registers is really extensively documented in the ARM manual It talks about, you know, what the names of all the registers are at the offsets of them Like how to program the registers in order to do things like set break points and watch points So I'm not going to go over all of that right here But what I will say is that the external debug interface is certainly more than powerful enough to do any sort of kernel debugging That we might be interested in definitely capable of setting break points and watch points single stepping execution executing arbitrary instructions poking at memory all this sort of stuff So the idea for my attack was we have these debugging registers We can do things like single stepping and we know that we can halt execution in the reset vector So I basically decided I would try to use the external debug interface to single step the reset vector And then once the reset vector is about to execute the KTR lockdown instructions Just jump over that piece of code. So KTRR never gets initialized So if we look at the reset vector, we'll just step through all of the first instructions and then once we see that we've hit this conditional branch Where we're just about to start doing the KTRR register initialization set x 17 to 0 jump over the KTRR code altogether now This is a nice idea But we don't actually have all the tools yet necessary in order to carry it out We know that we can hold a CPU and we know that we can execute arbitrary instructions on it and do things like modify the values and registers But we haven't yet found the ability to resume executing on the CPU after it's been halted So if we set a break point on the reset vector, for example, that's nice But it's not going to be of much use if we can't continue execution after that point Furthermore, there's another somewhat more subtle issue which is that we're using one CPU to hijack another CPU as it resets But CPU resets happen all the time any time a CPU core is idle for a couple of seconds It'll eventually just do a reset as it powers down and powers back up again So we're gonna have to do this KTRR hijack We're gonna need to modify the execution of the reset vector and skip the KTR initialization Every single time that a CPU core resets unless we can find some way to disable the core from resetting So I didn't know how to do either of these two things So I kind of just decided to play around with that Original proprietary register that I found earlier. So the XNU source code documents a couple of the bits I think it documents two of the bits in that register The remaining bits are undocumented. So I figured, you know, might as well set some bits clear some bits see what happens see if I learn anything interesting and I kid you not by sheer dumb luck. It happened that that register contained Exactly the pieces of functionality we needed to pull this hijack together. So bit 30 actually will clear the Hult and it'll allow the CPU to resume executing and bit 26 will keep the CPU powered up So that it doesn't subsequently reset and then we have to re-hijack the reset vector So basically the attack that we described before Works perfectly well Once we have this new functionality We just make sure that once we hit this branch we skip over the KTR register lockdown code And then these registers never get written to KTRR is never initialized on the system and kernel memory becomes executable So what this looks like is first we have KTRR enabled once we do this hijack KTRR is disabled on MMU and now any Page in kernel memory could now potentially be executed got a little bit more to go Thank you So now that we've found a way to break KTRR I want to talk about how to build an actual debugger on top of this because I found it to be a quite non-trivial challenge So there were a number of steps involved in this process and actually in many of them I encountered issues that I thought would be basically insurmountable So the first step in the process is we need to remap the kernel Because even though we've enabled the ability to execute arbitrary kernel shellcode. We don't yet have the ability to patch kernel memory Next we need to figure out some way to load a kernel extension We need to make sure that we're properly handling interrupts because we're going to be disabling or sorry We're going to be halting CPUs and once the CPU is halted it of course can't service interrupts anymore we're going to need to establish some sort of communication channel between the Kernel extension running in your iPhone and your laptop running LLDB and Finally, we need to implement a GDB stub to process the packet sent by LLDB and to drive the debugging hardware So at the point in which we bypass KTRR we Have the ability to execute arbitrary kernel shellcode But we don't yet have the ability to patch kernel memory The reason for this is that even though we've disabled KTRR on the MMUs It's still fully enabled on the memory controller so even though we can Execute code outside of the read-only region the read-only regions physical pages are still fully protected and we can't modify them persistently So this is actually kind of problematic for us We really do need to modify the page table permissions in order to make the kernel extensions memory executable and The root of the page table hierarchy lies inside of the KTRR region, which is still protected So the solution to this is to basically do exactly the same thing that Luca did in The 10.1.1 bypass which is to remap the kernel onto fresh writeable pages and set ttbr1 to point to the new page tables instead so what that looks like is initially the ttbr1 registers is going to point to the root of the page tables which lies inside the protected region What we have to do is we need to copy the kernel the pages containing the kernel We need to copy the data of that onto new writeable pages that are outside of the protected region update the page tables in kernel memory and then make ttbr1 point to the new modified page tables instead and With that we do now have the ability to patch the kernel So the next step in this process is we need the ability to load kernel extensions This actually turns out is pretty simple once we bypassed KTRR All we have to do is we need to allocate some memory to put the kernel extension in Copy in the binary Dynamically link the kernel extension against the kernel that's running because if you want to have a kernel extension Presumably you're going to want to call kernel functions at various points After that we need to modify page tables to make the kernel extension executable And finally we need to call some function in the kernel extension to begin it running And with that we're now ready to start designing a kernel debugger So what I eventually settled on was a pretty simple design I would have one core in the CPU which I called the monitor core is going to be exclusively reserved for the KTRR W debugger itself So it's no longer going to be running XNU All of the other cores in the system are going to continue to run your operating system as they do normally When you set a breakpoint or a watch point on one of the debugged cores It's going to cause that core to halt and enter debug state So the monitor core is just going to sit in a tight loop Polling all of the other cores to see when they enter debug state and when it notices this It'll send a message to LLDB over some communication channel saying hey this core halted because it hit a breakpoint and then LLDB can Take care of the rest Now when I implemented this I pretty quickly encountered weird panic messages So this is one example AOP panic no pulse on something or other And it took a little bit of effort, but what I eventually learned was this was being caused by a Processor on the device call it called the always-on processor Sending periodic interrupts to the main application processor and the interrupts that are sent by the always-on processor Need to be handled or else the AOP will panic and once the AOP panics it brings down the whole system Now some of these interrupts are actually relatively easy to disable. I reverse engineered the watchdog timer kernel extension and found the Hardware interface the set of registers needed to Disable that but there are other interrupts, which I wasn't able to narrow down. I wasn't able to disable now I'm I strongly suspect that the dev fused devices that some are able to acquire do have the ability to Disable these interrupts or other or in some way are not affected by this problem because presumably when apples engineers are Using one of these devices to debug the kernel and they halt the kernel for a few seconds It's not a great user interface if when they resume Execution the whole kernel panics because of this interrupt problem So I strongly suspect there's a way to fix this problem, but I wasn't able to find it Instead I basically implemented a big hack, which is that I started servicing interrupts from the AOP on the monitor core itself Now this introduced its own problem, which is that now execution on the monitor core can jump back into XNU and start running the IRQ handler at basically any time and that includes when Any of the debugged cores is halted holding an IRQ critical spin lock This is a huge problem because once we try to acquire that same spin lock We can't acquire it. It's already held and the only way that lock can be released Is if that debugged core is resumed which it has to be done by us so we enter this deadlock For a very long time. I thought this was pretty much an unsolvable problem for my debugger But it actually turns out there's a really really simple solution And the reason is that the XNU kernel itself has to deal with this problem See when an IRQ is delivered and some code is processing the IRQ if interrupts were enabled Then a second IRQ could be delivered and cause the IRQ handler to be re-entered In which case that same lock would be grabbed a second time. What that means is that interrupts have to be disabled while in an IRQ critical region Which means it's really easy to test for whether it's safe to halt one of the debugged cores You just check whether interrupts are enabled or not if interrupts are disabled That means that it's possibly in an IRQ critical region and you just wait a little bit of time before halting that core And after that all of my interrupt problems pretty much disappeared So now we're at the point where we have a Text running in the kernel we seem to be able to halt and resume CPU cores But we need some way for LLDB running on your laptop to communicate with the debugger running on your iPhone's kernel I considered a number of different options each with various advantages and disadvantages Serial is really really nice because it's incredibly simple to implement USB I liked because it would be really really fast Wi-Fi I kind of just threw in there in case the other two didn't work There wasn't any really compelling reason to implement a debugger over Wi-Fi What really made the decision was the disadvantages of each technique So for serial as far as I'm aware you do need special hardware in order to operate Communicate with the iPhone over serial so this basically violates the first goal one of the goals of my Homebrew Dev phone, which is that you don't need any special hardware everything can be purchased from an Apple store The other two techniques USB and Wi-Fi both suffered from the same problem Which is that I would need to write a custom driver for the hardware The reason for this is that I cannot rely in my debugger on the code that I'm debugging if I set a breakpoint and CPU core halts while it has some lock used by the Wi-Fi or the USB drivers then when my application ruin my kernel debugger tries to communicate over that mechanism using the Stack built-in to XNU it's going to try to take the same lock and deadlock same problem. We had before so Whatever communication channel we use we need to implement a custom driver for it, which is self-contained So out of USB and Wi-Fi. I basically figured that writing a USB stack was slightly less painful It was pretty easy to figure out with some googling which Hardware USB controller wasn't used in the iPhone It's a controller by synopsis called the design where high-speed USB 2.0 on the go controller What's somewhat unfortunate about this controller is that it is Proprietary the interface that it uses to communicate is not one of the standard USB interfaces Which means that you cannot use kind of your stock open source off-the-shelf drivers for it And when I tried to look at the data sheet to see how I could you know program my own driver I quickly ran into a login wall. I couldn't actually access it and I Was unable to obtain the data sheet for it So this seemed really problematic, but one thing that I could find was open source header files for this hardware now there are open source drivers for operating it But all the ones that I was able to find That operated this hardware did so in a host mode so kind of as a laptop rather than as a device you plug into it And that didn't really work for me. So that wouldn't Be that wasn't what I wanted, but I was able to use the header files which contained the register definitions Now the only place that I could think of that contained a fully self-contained implementation of the USB stack that operated the exact same hardware as used in the iPhone was the iPhones very own secure ROM so the secure ROM is the very first piece of code that runs on the Application processor when it starts up and it needs a USB stack in order to communicate With a computer over for DFU firmware upgrades So I basically took Apple's secure ROM there are dumps of it that you can find online and I put it into IDA and reverse engineered the Secure ROMs USB stack basically back to source and then re-implemented it in C And so this was a rather painful process But the end result was that I was able to make my iPhone appear to my laptop as a special TTRW USB device And with that the only step left in actually implementing a debugger is Implementing the GDB stub this is pretty easy as compared to kind of the other stuff in this project The GDB specification is open source basically just a bunch of parsing and then driving the external debug interface And once that was done. I had the ability to debug a production iPhone Over USB no special cables. No leak software involved Yeah, it was pretty cool So here I'll do a hopefully very quick demo of how to operate this debugger. So I have an iPhone which You can see here right now you're able to see the Kind of the screenshot of it on the laptop But as soon as I operate the debugger the USB stack will be taken over and you'll no longer be able to see This part of it. So What I'll do is I'll simply start the app that loads the kernel extension And so once that's running we'll lose Connectivity with advice, but we can connect to it with LLDB and Yeah, okay, so LLDB has recognized This device as an iOS device an iOS kernel cache It's discovered the load address and it's halted the kernel so we can now resume execution Now I can't show this on the display But for those of you in person you can see that the device is still responsive You can do things like load apps and yet there's still a kernel debugger attached to the device So we can do things for example, I'll set a break point on the sys to call min core All right, so we have a break point set now I have an application on the device that is simply going to call min core with very distinctive arguments It is possible to load an app onto the device over Wi-Fi even once the USB hardware has been co-opted But for this demo, I'm just going to have the app pre-installed the device I'm going to click on the application icon and it basically immediately halts CP the phone is no longer responsive because we're halted a break point We can do things like get a backtrace. We can examine registers So look at the memory point to do by register x1 and we can indeed see our arguments that were passed from user space We can do things like set watch points kind of all of your standard debugging functionality Hey So we'll set a watch point on this memory address and resume execution and we basically immediately hit the watch point and You can see the instruction that triggered this watch point loads x10 and x11 and These are indeed the values that we expect so watch points seem to function correctly We can disable the break point and the watch point and resume execution The app runs again your phone is responsive. So basically full-featured kernel debugger Cool, so thank you very much the debugger source code is available on the Google project zero github I also wrote a blog post kind of describing in more detail the process of finding the KTRR bypass This was a really really fun project and I'm really Excited to hopefully make Kernel debugging on the iPhone just a little bit easier Future versions will probably be based on the boot ROM exploit, which I'm really excited to see what comes out of that So, thank you Thank you very much So we have five minutes left for a Q&A. Please queue up on the microphones in between microphone one two three four we have some more so and Maybe you have questions from the signal angel signal angel No questions from the signal angel so microphone one please Yeah, thanks for the amazing talk at the beginning you showed us a tweet of the exploit and you said that Everything you could do is possible with this one as well and it said that it's not patchable So do you see any problems regarding security or anything using such a technique? Is it possible to run it like without I Don't know having the iPhone unlocked and is there any way to sort of abuse this which Do you mean the boot ROM bug or do you mean the debugging registers used here or both rather? Yeah, just everything all the above I Don't really know This isn't really kind of my area of expertise I can see you know some people might be able to leverage these types of vulnerabilities for you know proximal physical attacks The debugging registers that I'm using here aren't really all that useful For a remote attack because you encounter that problem or you know CPU resets and the KTR bypass gets lost And really once you have a kernel code execution You should really consider your device fully compromised anyway So I don't really think that the debug registers or security issue the boot ROM, you know, maybe for physical stuff, but It depends on your threat model. Thank you microphone for please Did you have a look into the Linux kernel for the design word to core driver because it's in drivers USB dvc too I think yeah, so this was actually really funny Basically as soon as I had finished implementing the USB stack and I'd got it working I realized that the reason I couldn't find any open-source drivers online was because I was searching for the wrong things in Google I'm just really bad at googling and the files containing the driver for operating it in Device mode were just named something different than I expected so You learn as you go Great. Thanks microphone one please Hi, great. I really enjoyed it So I have a quick comment and then a question so comment is This is the first time this is publicly revealed But the Vita was actually the trust zone was first dumped exactly the same way through the core site register So that was 2014. I thought it's pretty funny seeing this this still happening again and again my question is you said you reversed the The USB from secure on so did you find checkmate? So first about your comment definitely I Know that there are tons of people who have found similar capabilities basically nothing that I've done in this project is Original work all of it is building off of stuff which other people have done so absolutely. That's definitely the case About whether I discovered checkmate or not the first time I was looking at iBoot I basically saw the USB stack code and was like, oh my god This is so complicated. I want to avoid touching this if at all possible. So no, I completely missed that Thank you. So no more questions. Please another big round of applause for Brandon