iOS Diagnostics mode.
0x0. IntroductionHello and welcome to my second blog post !
Today I will talk about the iOS diags mode !
This subject may be useless or not interesting for some people, but the time I spent on it was useful for me because I understand a lot of things that I didn't understood before. =)
In this post, I will assume that you have a bit of knowledges about bootloaders and firmwares (also in reverse engineering, programming, ...) and I will talk about Apple Internal software for educational purposes only so do not expect any files from me.
I did not had enough time to do the necessary to boot up with a
RELEASEimage (knowing that I probably spent a month for writing this post due to school) so the
iBootused in this post is
However, it is actually possible to boot in diags mode from a
RELEASEimage by following this blog post (do not forget to repack the image before loading it to the device though).
Even if it is not amazing, I really hope that you will learn something new (a little bit at least... Ah and if I am wrong, please let me know). ~
0x1. DiagnosticsFrom the release of iOS 10.3, iOS contain an 'hidden' functionnality called 'Diagnostics' (with the side buttons...), and this is absolutely not what we are about to talk here ww.
Before starting, let's take a look to the iPhone boot chain which is designed to be working like this :
Just to be sure, I will remind some things :
- The iBSS is the DFU Mode LLB that setup the Hardware, check and load the
- The iBEC is the DFU Mode iBoot and just like the
iBootit "handles an access to the FileSystem (because it needs to read a special "restore" partition during upgrades)" (xerub).
A BootROM exploit is executed, a payload is sent in DFU, an other payload and its ramdisk is uploaded, the device boot then a kernel exploit is executed in the userlad to achieve an untethered jailbreak
But for booting in diags mode, the boot chain is a little bit different :
iBEChave to stay decrypted when they are loaded in the device, even with the
Note that this boot chain can only happens when a
BootROMexploit is executed (exploits like limera1n, checkm8, ...), OR when softwares like kloader are executed (the boot sequence remains the same except that the
iBSSbootloader is loaded in the
userlandand not from the BootROM).
So now let's talk about the diags mode, that is used to test the device capabilities.
These tests are basically applied on prototypes devices (
DVT) before the official release of a device.
The Diagnostics are before all a firmware that is either an IMG3 image with the '
gaid' tag and that needs to be renamed as
diag.img3before being loaded to the device (32bit), or either an IMG4 image with the '
diag' tag and that also to be renamed too as
diag.img4before being loaded to the device (64bit).
That image will, like others iOS bootloaders, open a serial connection on the baud rate
115200and can be booted (after that the
iBECare fully loaded) using one of these two
- The 'go' command : it has been used multiple times in older jailbreaks utilities such as Syringe (but just in case), this command is used to jump to the (address of the) last image loaded in memory (which here should be the
- The 'diags' command : this command will try to find in the
AppleInternal/Diags/bin') an image of type "
64 69 61 67" (
diag) then jumps to its address if the image is found (however, for some reasons this debug path is no longer working on some
By the way, here is a tiny note : unlike the '
go' command, the '
diags' one is a little bit particular.
I was curious about the real difference between these two commands so I had the idea to look at the
iBootsource code (
apps/iBoot/boot.c) and I found 3 functions related to the
int do_diagboot(int argc, struct cmd_arg *args);
do_diagboot()function is in fact the
diagscommand that we see when the '
help' command is used, and takes in count the arguments given :
- If there is an argument, the function should run like the
gocommand (except that it will check if the image can be loaded in memory with some other checks and if it fails, a
Permission Deniederror message will be printed) and should load the given image,
- Else if nothing is provided, the
do_diagboot()function will call the
boot_diagnostics()one (which is a pretty small function) : And as you can see, this function will calls an other one, which is the
boot_diagnostic_fs()function will try to boot the
diagsdirectly from the FileSystem, starting by getting the value of the environment variable '
diag-path' (which checks the '
AppleInternal/Diags/bin/' directory) that is by the way standing in the
NVRAM(the value is stored in the '
const char *diag-paths' variable) and by trying to mount the boot file system at the '
I added some comments but this screenshot should be enough detailed to understand what is happening here (this is the following part of my explaination from above) :
[NOTE]: If it fails, the '
/boot' directory is unmounted and that is where you see a message error.
So yes, this is what happening when you execute the
Additionally, I noticed some things that could be interesting to take a look to :
- First, after an
64bit) we can notice that the
addr baseof the firmware is at
0x800, then there is only some
I also used a tool called 'UEFITool' to look a little bit and here is what we can see first : At first I did not what this offset was, and if we look well, we can see that it is in fact the FileSystem
GUID Partition Table.
So after reversing the order of the selected text from above and re-opened the
hexdump, what do we see at
GUID Partition Tableoffset ! I checked a little bit too at a
32bitand I found out that the The
GUID Partition Tableis not at
I took the
GUIDfor example but if I looked a little bit more further, I am pretty sure that I could find the payload and every other commands that the
- One more thing that I noticed is that when I scrolled down, I found something called '
PreEfi.[extension]' (I found it in a string) in the
At the beginning, I did not really know what that thing was and with a bit of research I ended up surprised to find this kind of stuff :
[NOTE]: Most of the time, all of the documentation that I found about this were written by Microsoft.
So yes, after some researches, here is what I found and learned :
Firmware Volume, where the
PEIis searched for in,
PEIstands for Pre-Efi Initialization,
Portable Executablethat is refering to the fact that the format is not architecture specific, I am not surpirsed about why it is used here now (its the magic value is
DOSheader, which should owns a length of
64 bytesand its magic value is
As you can see, the Diagnostics that we were used to run normally are in fact running a software that is actually
Eficompatible ! (part of the
Then after a bit of documentation reading and minutes of thought, I assume that every available commands are in fact corresponding to an
Efi Module(like the
aes, and every other ones ...), these commands are by the way loaded in the
For finishing, when the
diagsare finally booting, some commands (available in the diags mode) are ran to checks if the device is able to run the image correctly.
It is actually quite difficult to know more about, which is very unpleasant but we have no choice except admit it anyways because there is no ways to decrypt the
diagsimage since it do not handles any
Also, while I was writting this blog post I found out that someone else made an amazing blog post about the
iBootand others bootloaders.
If you are interested, you can read this blog post (written by Jonathan Levin). ^△^
0x2. Boot TimeWell, this part is just a mini tutorial, the better part was above but this one could "maybe" help someone...
Also, I am not responsible if you ever meet a problem due to the following steps so do it at your own risks, you have been warned.
Make sure that your device is jailbroken (I am using the checkra1n jailbreak under iOS 13.5), and to get a
I will use an iPhone10,4 |
D20APto boot in diags mode (I will not write for 32bit else this blog post would be too long but if you need help or want to know more, I will try to do my best to help you though). (^0^)v
As we just saw previously, we need to be in
pwnedDFUmode (pwning the
BootROM), that's why I will use first use checkm8 and then apply the signature patches for then loading unsigned
img4images by using this (iPhone8) or this (iPhone5S) ipwndfu fork :
Before starting to load anything, I will do a simple test to see if my device (which is in
pwnedDFUmode) can really accept unsigned images by creating and sending a random single one file and sending it using the tool that I have been wrote called iBootime :
Great ! It loaded just fine which means that we can now load properly our
At the same time, I always use a serial console to see the log (in my case I use termz), so if you do it too, you should see this kind of output once the
iBEChas been loaded to the device (anyways, you will have to run the serial console for interacting with the
diags) : [NOTE]: Based on the
BUILD_TAG, it seems that this is an iOS 12.0 bootloader.
On a side note, this
iBootowns some strings that I did not saw before such as :
ASN2that apparently means '
Apple NAND Storage 2' which appears to be an SSD controller used in the
T2chips (Mac) and in iPhones,
nvmethat apparently stands for '
Non-Volatile Memory Express' which is used to access to a storage media such as an SSD (it seems logic to me as we previously talked about
ASN2) etcetera etcetera...
SMCthat apparently stands for '
System Management Controller' which is used to manage the Hardware such as the
USB, battery, ...
These softwares are also used in the Macs.
The time has come to load the diags image, but in my case, I need to pack my diags image into an
IMG4image (I will still use iBootime, that will adds a total size of
11 bytesonce that the image will be created) :
And then we should now be able to properly load it to our device !
[NOTE]: I am truly sorry because there is a weird bug that makeAnd then we can boot into Diagnostic mode by using
iBootimeunable to load a
diagimage, so I had to use irecovery to load it... I will do my best to find enough time and try to fix it !
--start -roption because it will sends the
gocommand (and as we just loaded the Diagnostic image, the last address loaded in memory would be this one).
And from there, the device should has been booted ! here is the output :
0x3. ConclusionIt was a really interesting research, I learned a very lot about bootloaders and the
I also had the chance to get some
DEVELOPEMENTimages which helped me a lot through this so may thanks to the people who gave it to me and for some tips, you all are amazing !
Also, I noticed some commands that could be potentially interesting (or not) to try, such as :
memory [--info] | [--list] | [--leak] | [--dump] (address) (length)
syscfg [init | add | print | list | type | delete] (KEY) (value1) (value2) ...
- [. . .]
(except of course the
memorycommand like :
memory --dump 0x800000000 0x1EA)
but if someone also wants to play with the
diagsand maybe bricks their device too, hit me up so I can see what the commands did to it. :p
Well that is all I wanted to say, you can tell me on my twitter if you liked this post and you can also supports me by looking at my others projects on GitHub !
Thank you for your time. ヾ(・ω・*)ノ