- Série AT89xx complète : craquage de microcontrôleur : AT89C51 AT89C52 AT89S52 AT89S53 AT89S54 AT89S58 AT89S64 AT89C1051 AT89C2051 AT89C4051 AT89C55 AT89C55WD AT89C5131A AT89C51WD AT89C51ED2 AT89C51CC01 AT89S51 AT89C51CC02 AT89C51CC03 AT89C51RB2 AT89C51RC AT89C51RD2 AT89C51RD-CM AT89C51RC2 AT89C51ID2 AT87C5101 AT89C1051U AT89C2051X2 AT89C5130AM AT89C5130A AT89C5131AL AT89C5131AM AT89C51AC3 AT89C5132 AT89C51AC2 AT89C51CC03C AT89C51SND1C AT89C51CC03U AT89C51IC2 AT89C51RE2 AT89C51SND2 AT89LP2051 AT89LP2052 AT89LP213 AT89LP214 AT89LP216 AT89LP4051 AT89LP4052 AT89LP828 AT89LP428 AT89LS51 AT89LS52 AT89LV51 AT89LS53 AT89LS8252 AT89LV52 AT89LV55 AT89S2051 AT89S4051 AT89S8252 AT89S8253 ...
- Série AT90xx complète : craquage de microcontrôleur : AT90S1200 AT90S2323 AT90S2343 AT90S2331 AT90S4433 AT90S8515 AT90S8535 AT90S4414 AT90S4434 AT90S2313 90S1200 90S2323 90S2343 90S2331 90S4433 90S8515 90S8535 90S4414 90S4434 90S2313 ...
- Série AT90CAN/PWM/USB/xx complète : lecture de microcontrôleur : AT90CAN32 AT90CAN64 AT90CAN128 AT90PWM2 AT90PWM216 AT90PWM2B AT90PWM3 AT90PWM316 AT90PWM3B AT90USB1286 AT90USB1287 AT90USB162 AT90USB646 AT90USB647 AT90USB82 ...
-
- Série AT91SAMxx complète : craquage de firmware MCU : AT91SAM9XE512 AT91SAM9XE256 AT91SAM9XE128 AT91SAM7S64B AT91SAM7S32B AT91SAM7SE512 AT91SAM7SE256 AT91SAM7SE32 AT91SAM7XC512 AT91SAM7XC256 AT91SAM7XC128 AT91SAM7X512 AT91SAM7X256 AT91SAM7X128 AT91SAM7S161 AT91SAM7S512 AT91SAM7S256 AT91SAM7S128 AT91SAM7S64 AT91SAM7S321 ...
- Série ATTinyxx complète : craquage de firmware MCU : ATtiny4 ATtiny5 ATtiny10 ATtiny11 ATtiny12 ATtiny13 ATtiny15 ATtiny20 ATtiny22 ATtiny24 ATtiny25 ATtiny26 ATtiny261 ATtiny28 ATtiny2313 ATtiny40 ATtiny4313 ATtiny43 ATtiny44 ATtiny45 ATtiny461 ATtiny48 ATtiny84 ATtiny85 ATtiny861 ATtiny87 ATtiny88 ATtiny4A ATtiny5A ATtiny10A ATtiny11A ATtiny12A ATtiny13A ATtiny15A ATtiny20A ATtiny22A ATtiny24A ATtiny25A ATtiny26A ATtiny261A ATtiny28A ATtiny2313A ATtiny40A ATtiny4313A ATtiny43A ATtiny44A ATtiny45A ATtiny461A ATtiny48A ATtiny84A ATtiny85A ATtiny861A ATtiny87A ATtiny88A ATtiny4V ATtiny5V ATtiny10V ATtiny11V ATtiny12V ATtiny13V ATtiny15V ATtiny20V ATtiny22V ATtiny24V ATtiny25V ATtiny26V ATtiny261V ATtiny28V ATtiny2313V ATtiny40V ATtiny4313V ATtiny43V ATtiny44V ATtiny45V ATtiny461V ATtiny48V ATtiny84V ATtiny85V ATtiny861V ATtiny87V ATtiny88V ...
- Série ATMegaxx complète : craquage de microcontrôleur : ATmega16 ATmega162 ATmega164 ATmega165 ATmega168 ATmega169 ATmega128 ATmega1280 ATmega1281 ATmega2560 ATmega2561 ATmega328 ATmega48 ATmega32 ATmega324 ATmega325 ATmega3250 ATmega329 ATmega3290 ATmega64 ATmega640 ATmega645 ATmega6450 ATmega649 ATmega6490 ATmega8 ATmega88 ATmega8515 ATmega8535 ATmega16L ATmega162L ATmega164L ATmega165L ATmega168L ATmega169L ATmega128L ATmega1280L ATmega1281L ATmega2560L ATmega2561L ATmega328L ATmega48L ATmega32L ATmega324L ATmega325L ATmega3250L ATmega329L ATmega3290L ATmega64L ATmega640L ATmega645L ATmega6450L ATmega649L ATmega6490L ATmega8L ATmega88L ATmega8515L ATmega8535L ATmega16P ATmega162P ATmega164P ATmega165P ATmega168P ATmega169P ATmega128P ATmega1280P ATmega1281P ATmega2560P ATmega2561P ATmega328P ATmega48P ATmega32P ATmega324P ATmega325P ATmega3250P ATmega329P ATmega3290P ATmega64P ATmega640P ATmega645P ATmega6450P ATmega649P ATmega6490P ATmega8P ATmega88P ATmega16A ATmega162A ATmega164A ATmega165A ATmega168A ATmega169A ATmega128A ATmega1280A ATmega1281A ATmega2560A ATmega2561A ATmega328A ATmega48A ATmega32A ATmega324A ATmega325A ATmega3250A ATmega329A ATmega3290A ATmega64A ATmega640A ATmega645A ATmega6450A ATmega649A ATmega6490A ATmega8A ATmega88A ATmega8515A ATmega8535A ...
- Série ATFxx : craquage de microcontrôleur : ATF16V8B ATF16V8BL ATF16V8BQ ATF16V8BQL ATF16LV8C ATF16LV8CEXT ATF16V8C ATF16V8CEXT ATF16V8CZ ATF20V8B ATF20V8BL ATF20V8BQ ATF20V8BQL ATF22LV10C ATF22LV10CEXT ATF22LV10CUES ATF22LV10CZ ATF22LV10CQZ ATV22V10 ATF22V10B ATF22V10BQ ATF22V10BL ATF22V10BQL ATF22V10C ATF22V10CEXT ATF22V10CUES ATF22V10CZ ATF22V10CQZ ATF22V10CZUES ATF22V10CQZUES ATF1500A ATF1500ABV ATF1500ABVL ATF1500 ATF1500L ATF1502AS ATF1502ASL ATF1502ASV ATF1502ASVL ATF1504AS ATF1504ASVL ATF1508 ATF1508AS ATF1508ASV ATF2500C ATF2500CL ATF2500CQ ATF2500CQL ATF750C ATF750CEXT ATF750CL ATF750LVC ATF750LVCCEXT ATF750LVCEXT ATF750LVCL ATV2500 ATV2500H ATV2500L ATV2500B ATV2500BL ATV2500BQL ATV5000 ATV5000L ATV750 ATV750B ATV750BL ATV750L ...
- Série AT88scxx/90scxx : craquage de microcontrôleur : AT88SC0104 AT88SC0104C AT88SC0204 AT88SC0204C AT88SC0404 AT88SC0404C AT88SC0808 AT88SC0808C AT88SC1003 AT88SC101 AT88SC102 AT88SC1281 AT88SC12816C AT88SC150 AT88SC153 ...
La fonction de démarrage met VDD à un niveau haut, attend, puis définit SDA en fonction du bit d'adresse ainsi que SCK. Attend, abaisse SCK, attend encore, puis définit SDA en fonction de l'adresse. Cela se répète 2 fois de plus, sauf qu'à la 4ème fois, SDA est mis à un niveau bas car nous voulons lire les données dans les EEPROM, pas écrire.
void epsnCartStart(unsigned char addr, unsigned char write){
char i = 0; // Utilisé pour le comptage
char tmp = 0; // Variable de stockage temporaire
_ecVDDLat = 1; // Met VDD à l'état haut
DelayMS(1); // Attend que les EEPROM soient prêtes
_ecRSTLat = 1; // Active les EEPROM pour la communication
tmp = addr; // Copie l'adresse dans la variable temporaire
if(write){ // Si nous voulons écrire
temp |= 0x08; // Met le 4ème bit à 1 ('|' signifie OU)
}
while(i<4){
_ecSDALat = (tmp&0x01); // Met SDA à un niveau haut ou bas selon le LSB
wait(); // Attend environ 50 µs
_ecSCKLat = 1; // Met l'horloge à l'état haut
wait(); // Attend encore 50 µs
_ecSCKLat = 0; // Met l'horloge à l'état bas
wait(); // Attend encore 50 µs
tmp>>=1; // Décale tous les bits de tmp d'un cran vers la droite
i++; // Incrémente le compteur de un
}
}
La fonction suivante à implémenter est stop :
void epsnCartStop(){
_ecRSTLat = 0; // Met RST à l'état bas
DelayMS(1); // Attend un peu
_ecVDDLat = 0; // Éteint les EEPROM
}
Et enfin la fonction de lecture :
unsigned char epsnCartRead(){
char i=0;
char temp = 0x00;
while(i<8){
temp>>=1; // Décale la variable temporaire d'un cran vers la droite
_ecSCKLat = 1; // Met SCK à l'état haut
wait(); // Attend environ 50 µs
if(_ecSDA){ // Si SDA est à l'état haut
temp |= 0x80; // Alors met le bit 7 à 1
}
_ecSCKLat = 0; // Remet SCK à l'état bas
wait(); // Attend encore 50 µs
i++; // Incrémente le compteur de 1
}
return temp; // Retourne ce qui a été lu
}
Nous avons maintenant les fonctions de base nécessaires pour lire les données des cartouches d'encre. Configurons notre microcontrôleur et affichons les résultats.

Démarrez votre IDE, dans mon cas c'est MPLab, créez un nouveau projet pour votre puce et créez un programme "Hello World" basique pour vous assurer que votre puce fonctionne.
Remarque : Mon programme "Hello World" envoie "Hello World!\r\n" en série vers mon ordinateur à 38400 bps.
#include <p18f2550.h> // Fichier include spécifique à cette puce
#include <usart.h> // Fonctions USART
#include <stdio.h> // printf(format,...), sprintf(string, format, ...), etc.
#include "delay.h"
void main(){
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
TRISA = 0x00;
TRISB = 0x00;
TRISC = 0x00;
ADCON1 = 0x0F; // C'est un vrai fauteur de troubles, n'oubliez jamais de repasser les broches analogiques en numériques ! :P
TRISCbits.TRISC7 = 1; // Transforme la broche RX en entrée (consultez votre fiche technique pour votre puce)
OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ADDEN_OFF & USART_BRGH_HIGH & USART_CONT_RX & USART_EIGHT_BIT & USART_ASYNCH_MODE,78);
while(1){
putrsUSART("Hello World!\r\n"); // Envoie un message via Serial
LATAbits.LATA0 = ~LATAbits.LATA0; // Fait clignoter une LED en la basculant
DelayMS(500); // Une fonction de délai que j'ai créée
}
}
Ceci a été configuré avec une alimentation 3,3 V car les cartouches d'encre fonctionnent en 3,3 Volts.
Pourquoi un programme "Hello World" ? Eh bien, à chaque fois que je configure un nouveau projet sur une plaque d'essai, je veux toujours m'assurer que les bits de configuration sont corrects et que je ne reçois pas de données inintelligibles dans le terminal.
Je pense que c'est une bonne pratique et tout le monde devrait le faire ! :P
Si votre puce fait quelque chose de simple comme la mienne, super !! Passons à l'étape suivante.
Implémentation de notre bibliothèque
Nous voulons maintenant inclure la bibliothèque que nous avons créée pour interfacer le microcontrôleur avec la cartouche d'encre.
En haut du fichier, ajoutez :
#include "epsnCart.h" // le nom du fichier d'en-tête que nous avons créé précédemment
Comme ce microcontrôleur se fait passer pour l'hôte, il contrôle les signaux SCK, SDA et RST. Assurez-vous donc qu'ils sont en sortie, ajoutez ceci avec les autres registres TRIS dans main() :
epsnCartInit();
Le morceau de code suivant est ce que j'ai utilisé à l'intérieur de while(1) {
Il demande une adresse à partir de 0x00 puis l'incrémente de un après 32 octets lus :
void main(){
char addr = 0, i = 0;
char string[40];
...
epsnCartInit(); // Initialise les broches utilisées
while(1){ // Boucle infinie !
sprintf(string, "Lecture de la cartouche avec l'adresse : 0x%02X\r\n",addr);
putsUSART(string); // Affiche un message comme : Lecture de la cartouche avec l'adresse : 0x03
epsnCartStart(addr,0); // Démarre en envoyant l'adresse en mode lecture
i = 0;
while(i<32){ // Boucle tant que i est inférieur à 32
sprintf(string,"0x%02X,",epsnCartRead());
putsUSART(string);
i++;
}
epsnCartStop(); // Met RST à l'état bas
putrsUSART("\r\n");
addr++
if(addr>7){
addr = 0;
}
DelayMS(500);
}
}
Vous vous demandez probablement à propos de la ligne "sprintf(string,"0x%02X,",epsnCartRead());" et vous dites "Hein ?"
sprintf est une fonction de formatage de chaîne, un peu comme printf, sauf qu'elle enregistre la chaîne formatée dans la variable string.
"0x%02X," retournera une chaîne avec une valeur hexadécimale lisible, par exemple : 0xFE, et epsnCartRead() retourne une valeur qui a été lue depuis la cartouche d'encre.
Ceci a été configuré avec une alimentation 3,3 V car les cartouches d'encre fonctionnent en 3,3 Volts.
J'ai programmé ceci dans mon microcontrôleur, j'ai déconnecté la tête d'impression de l'imprimante pour éviter les interférences.
J'ai ensuite branché les 3 cartouches d'encre que j'avais et j'ai mis le tout sous tension.
Remarque : À ce stade, si vous exécutez ce code pour la première fois, je m'attends à ce que vous ayez des problèmes. Comme moi, j'ai passé en revue le code des dizaines de fois, en le modifiant ici et là pour le faire fonctionner. Il est normal que cela ne fonctionne pas du premier coup pour vous. C'est une excellente expérience d'apprentissage que de comprendre ce qui n'a pas fonctionné ! :P


Ouf, après tout ce travail acharné, ça vit !!!
Voici ce que j'ai obtenu sur mon terminal
Addr: 0x01
57,07,02,F2,00,00,00,00,00,50,98,6A,EB,D3,54,A3,39,50,14,15,31,93,E4,B4,24,96,57,04,35,F5,E4,14,
Addr: 0x02
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
Addr: 0x03
03,00,02,F2,00,00,00,00,00,50,C8,1C,2A,A5,82,00,3B,50,16,17,31,93,E4,B4,24,96,57,04,35,F5,E4,34,
Addr: 0x04
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
Addr: 0x05
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
Addr: 0x06
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
Addr: 0x07
03,00,02,F2,00,00,00,00,00,50,30,9F,74,81,D1,40,3B,50,1A,1B,31,93,E4,B4,24,96,57,04,35,F5,E4,74,
Maintenant, voyez ici comment seules les adresses impaires ont retourné des données, sauf 0x05 ?
C'est parce que 0x05 est l'adresse de la cartouche d'encre magenta, que je n'ai malheureusement pas :(
Routines de code d'émulation
Maintenant, la partie amusante !
J'ai besoin que l'imprimante pense qu'il y a quatre cartouches d'encre installées. Pour ce faire, nous devons d'abord implémenter quelques fonctions d'émulation. Encore une fois, à partir de connaissances antérieures, je les ai prédéfinies dans l'en-tête :
• #define epsnCartReady() (_ecRST)
• extern unsigned char espnCartGetAddr(void);
• extern void epsnCartOut(unsigned char data);
• extern unsigned char epsnCartIn(unsigned char data);
epsnCartReady est une macro utilisée pour vérifier si l'imprimante a RST à l'état haut.
epsnCartGetAddr retourne l'adresse demandée par la tête d'impression.
epsnCartOut est utilisé pour envoyer des données au contrôleur hôte.
epsnCartIn est utilisé pour recevoir des données de l'hôte lorsqu'il écrit.
Donc, cette fois, au lieu de contrôler SCK pour qu'il passe à l'état haut ou bas, nous devons attendre qu'il passe à l'état haut ou bas, mais si la réinitialisation passe à l'état bas, alors arrêtez tout et revenez :
unsigned char espnCartGetAddr(void){
char i=0;
char temp = 0x00;
while((i<4) && _ecRST){ // Boucle tant que i < 4 et RST est à l'état haut
temp>>=1; // Décale Temp d'un cran vers la droite
while((!_ecSCK) && (_ecRST)); // Attend que l'horloge passe à l'état haut
if(_ecSDA){// seulement si SDA est à l'état haut
temp |= 0x08; // alors met le 4ème bit à 1
}
while((_ecSCK) && (_ecRST));// attend que l'horloge passe à l'état bas
i++; // incrémente le compteur
}
if(_ecRST == 0){
return 0xFF;//si RST est passé à l'état bas, cela signifie que l'hôte a coupé le signal
}
return temp; //retourne l'adresse et le bit de lecture/écriture
}
Et la fonction Out :
void epsnCartOut(unsigned char data){
char i = 0;
char temp = data;
_ecSDATRIS = 0; // définit SDA en sortie
_ecSDALat = 0; // met SDA à l'état bas
while((i<8) && _ecRST){ // Boucle tant que i < 8 et RST est à l'état haut
while(!_ecSCK && _ecRST); // Attend que SCK passe à l'état haut
_ecSDALat = temp&0x01; // Met SDA à l'état haut ou bas selon le premier bit
while(_ecSCK && _ecRST); // Attend que SCK passe à l'état bas
temp>>=1; // Décale les données d'un cran vers la droite
i++; // incrémente le compteur de un
}
_ecSDATRIS = 1; // Remet SDA en entrée
_ecSDA = 1; // Pas sûr que ce soit nécessaire
}
Et enfin la fonction In :
unsigned char epsnCartIn(void){
unsigned char i=0;
char temp = 0x00;
while((i<8) && _ecRST){ // Boucle tant que i < 8 et RST est à l'état haut
temp>>=1; // Décale Temp d'un cran vers la droite
while(!_ecSCK && _ecRST); // Attend que SCK passe à l'état haut
if(_ecSDA){ // seulement si SDA est à l'état haut
temp |= 0x80; // Met le 8ème bit à 1
}
while(_ecSCK && _ecRST);// Attend que SCK passe à l'état bas
i++; // Incrémente le compteur de un
}
return temp; // retourne ce qui a été reçu
}
Ce qui se passe maintenant, c'est que nous devons configurer notre microcontrôleur pour qu'il contienne les données que nous avons extraites. Ensuite, permettre à l'hôte de l'imprimante de lire et d'écrire dessus.
Le problème avec cela est que je ne veux pas que mes fausses cartouches d'encre soient jamais épuisées. Pour ce faire, nous avons un dump fixe que le microcontrôleur chargera dans la RAM à chaque démarrage. Cela permettra à l'imprimante non seulement de lire, mais aussi d'écrire dessus. Lorsque le microcontrôleur est éteint puis rallumé, les données précédentes sont restaurées. (Double bonus)
Stockage des tableaux de données dans le microcontrôleur, placez ceci quelque part sous l'inclusion, mais avant void main()
Remarque : Cela peut varier selon les différentes familles de microcontrôleurs, mais cela fonctionne bien avec mon PIC18F
ram unsigned char black[32] = {0x10,0x00,0x02,0xF2,0x00,0x00,0x00,0x00,0x00,0x50,0x90,0x6A,0x17,0xE3,0x54,0xA3,
0x39,0x50,0x14,0x15,0x31,0x93,0xE4,0xB4,0x24,0x96,0x57,0x04,0x35,0xF5,0xE4,0x14};
ram unsigned char cyan[32] = {0x4C,0x04,0x01,0xF2,0x00,0x00,0x00,0x00,0x00,0x50,0x90,0x5A,0x19,0xF0,0x94,0x03,
0x3B,0x50,0x16,0x17,0x31,0x93,0xE4,0xB4,0x24,0x96,0x57,0x04,0x35,0xF5,0xE4,0x34};
ram unsigned char yellow[32] = {0x4A,0x04,0x01,0xF2,0x00,0x00,0x00,0x00,0x00,0x50,0x90,0x6A,0x8B,0xC9,0xA4,0x41,
0x3B,0x50,0x1A,0x1B,0x31,0x93,0xE4,0xB4,0x24,0x96,0x57,0x04,0x35,0xF5,0xE4,0x74};
Remarque : Vous avez remarqué que je n'ai pas de magenta ? C'est parce que c'est la cartouche d'encre que je n'ai pas.
L'étape suivante consiste à écrire une routine qui vérifie quelle cartouche d'encre est demandée et permet à l'hôte de lire et d'écrire dessus.
Voici comment je l'ai fait :
void main(){
unsigned char* inkPtr;
char addr = 0x00;
...
While(1){
epsnCartStartListen();
while(epsnCartReady()==1); // Attend que le signal Ready repasse à l'état bas
while(epsnCartReady()==0);
addr = espnCartGetAddr();
if(addr&0x7 == 0x01){ // si les 3 premiers bits sont égaux à 0x01
inkPtr = &black[0]; // Pointe vers les données noires
}else if(addr&0x7 == 0x03){ // si les 3 premiers bits sont égaux à 0x03
inkPtr = &cyan[0]; // Pointe vers les données cyan
}else if(addr[i]&0x7 == 0x05){
inkPtr = &cyan[0]; // Ceci est censé être le magenta, mais je ne l'ai pas
}else if(addr[i]&0x7 == 0x07){
inkPtr = &yellow[0];
}else{
continue: // Retourne au début de la boucle principale car nous ne connaissons pas cette adresse
}
if(addr&0x08){//Mode Écriture – Vérifie si l'hôte veut écrire
while(epsnCartReady()){//continue de boucler jusqu'à ce que RST passe à l'état bas
*inkPtr = epsnCartIn();
// Les données pointées par le pointeur
// sont écrasées par les nouvelles données
inkPtr++; // Incrémente le pointeur
}
}else{//Mode Lecture
while(epsnCartReady()){
epsnCartOut(*inkPtr);
// Sort les données pointées par le pointeur
inkPtr++; // Incrémente le pointeur
}
}
}
}
Succès !
Après avoir programmé ce nouveau code et allumé mon imprimante, l'imprimante a accepté 4 cartouches imaginaires grâce à mon microcontrôleur. Je suis également assez surpris qu'il ait accepté les données de la cartouche cyan pour le magenta aussi !
Ce projet est un excellent exemple de la façon dont la rétro-ingénierie peut libérer le potentiel d'un matériel propriétaire. En comprenant le protocole de communication, j'ai effectué une extraction de firmware des contenus EEPROM, bien que les données soient petites. Dans un système plus complexe, il serait nécessaire de dumper la mémoire flash d'un microcontrôleur pour analyser son code. L'EEPROM de ces cartouches agit comme un petit stockage sécurisé, mais sans aucun bit de verrouillage ni chiffrement, il est trivial de lire les données. Certaines cartouches d'imprimante modernes incluent un mécanisme de verrouillage qui empêche la réutilisation, mais ici la seule protection était le protocole obscur. Cette obscurité n'est pas de la sécurité, comme je l'ai prouvé en émulant avec succès la cartouche manquante. La capacité de dupliquer l'identité de la cartouche permettrait des recharges infinies, ce qui est exactement ce que les fabricants d'imprimantes essaient d'empêcher. Ils utilisent souvent des fusibles ou des bits programmables une fois pour marquer une cartouche comme vide, mais cette EEPROM est entièrement réinscriptible. Mon microcontrôleur agit maintenant comme un homme du milieu, interceptant les requêtes de lecture et servant les données stockées. C'est essentiellement une forme simple de récupération de firmware pour l'imprimante, car j'ai restauré la pleine fonctionnalité sans la pièce d'origine. Le code que j'ai écrit est petit mais efficace, et il pourrait être adapté à d'autres dispositifs avec des EEPROM série similaires. Je me suis souvent demandé si les fabricants d'imprimantes laissent intentionnellement ces vulnérabilités pour permettre les cartouches tierces. Quoi qu'il en soit, ce projet m'a beaucoup appris sur les protocoles matériels et les systèmes embarqués. Le MCU que j'ai utilisé, un PIC18F, était plus que capable de gérer les exigences de timing. En fait, j'aurais pu utiliser un microcontrôleur plus petit, mais le PIC m'a donné beaucoup de place pour de futures extensions. L'ensemble fonctionne en 3,3 V, ce qui correspond à la tension interne de la cartouche. Un défi était de s'assurer que la ligne SDA était correctement pilotée dans les deux sens, car l'imprimante et mon MCU alternent le contrôle. J'ai dû gérer soigneusement les registres TRIS pour éviter les conflits de bus. C'est un problème courant dans tout système multi-maîtres, mais ici c'est un seul hôte et un esclave émulé. Les diagrammes de timing du brevet ont été inestimables ; ils m'ont donné les relations exactes des fronts d'horloge. Sans cela, j'aurais passé des jours à deviner. Cette expérience souligne l'importance de la documentation, même si elle est cachée dans les brevets. J'ai aussi appris que parfois la solution la plus simple est la meilleure : stocker le dump dans la RAM et le rafraîchir à la mise sous tension. Cela garantit que les niveaux d'encre ne diminuent jamais, ce qui est un bonus sympa. Cependant, pour un produit réel, je devrais envisager l'usure et la protection contre les pertes de puissance. Mais pour un projet amateur, c'est parfait. Je suis maintenant confiant que je peux aborder des tâches de rétro-ingénierie plus complexes à l'avenir. La prochaine étape pourrait impliquer l'écoute de la communication entre l'imprimante et les pilotes du moteur de la tête d'impression. Cela me permettrait de contrôler précisément le mouvement XY pour ma conversion en imprimante 3D. Mais c'est une histoire pour un autre instructable. Pour l'instant, je suis ravi que mon émulation fonctionne parfaitement. J'ai même testé avec plusieurs cycles d'alimentation et elle conserve les données à chaque fois. Le tableau RAM est réinitialisé avec les valeurs codées en dur à chaque démarrage, donc la cartouche apparaît toujours comme neuve. L'imprimante ne se plaint jamais des cartouches contrefaites car les données sont une copie parfaite d'une cartouche authentique. C'est essentiellement une duplication de l'identité de la cartouche d'origine. Dans un cadre commercial, une telle technique pourrait être utilisée pour un clonage non autorisé, mais ici c'est pour un réemploi légitime. Je fais attention à ne l'utiliser que pour mes propres projets. Les connaissances acquises grâce à cet exercice sont applicables à de nombreux autres appareils électroniques grand public qui utilisent des mémoires série simples. De nombreux appareils ont des EEPROM similaires qui stockent des données d'étalonnage ou des numéros de série. En les lisant, vous pouvez sauvegarder et restaurer des informations critiques. C'est une forme d'extraction de firmware en soi, même si le firmware n'est que des données de configuration. J'ai vu des projets où les gens décryptent le firmware d'un compteur intelligent en utilisant des méthodes similaires. Mais cela implique une cryptographie beaucoup plus complexe et souvent un bit de verrouillage pour empêcher la lecture. Ici, il n'y a pas de tel verrou, donc c'est grand ouvert. Certains pourraient dire que c'est une faille de sécurité, mais pour moi c'est une opportunité. J'ai déjà commencé à planifier une version qui utilise un ATtiny plus petit pour économiser de l'espace. La taille du code est minuscule, donc cela pourrait tenir dans un boîtier 8 broches. Je pourrais même ajouter une fonctionnalité pour simuler différents types de cartouches via un commutateur DIP. Ce serait pratique pour tester diverses encres. Les possibilités sont infinies. J'envisage également de partager mon code sur GitHub pour que d'autres puissent l'adapter. Cette approche open-source encourage la collaboration et l'innovation. De nombreux hackers ont déjà fait des choses similaires avec d'autres marques d'imprimantes. La communauté est très active dans la rétro-ingénierie des consommables pour réduire les déchets et économiser de l'argent. C'est gagnant-gagnant pour l'environnement et l'utilisateur. J'espère que mon instructable incitera d'autres à regarder sous le capot de leurs propres appareils. Avec un analyseur logique et un peu de patience, vous pouvez découvrir des protocoles cachés. La clé est de commencer petit, comme je l'ai fait avec cette simple EEPROM. Une fois que vous maîtrisez les bases, vous pouvez passer à des cibles plus difficiles. J'attends avec impatience le jour où je pourrai imprimer en 3D avec mon imprimante convertie. Ce n'est que la première étape. La prochaine grande étape est d'interfacer les pilotes de la tête d'impression et de construire le cadre mécanique. Mais c'est un projet pour une autre saison. Pour l'instant, je savoure cette victoire. C'est une preuve tangible que la rétro-ingénierie n'est pas réservée aux pirates ; c'est une compétence précieuse pour tout ingénieur. En comprenant comment les choses fonctionnent au niveau le plus bas, vous pouvez vraiment les faire vôtres. C'est l'esprit du "making" et du bricolage. Alors allez-y, prenez une vieille imprimante et commencez à sonder. Vous serez surpris de ce que vous pouvez accomplir. Et rappelez-vous, documentez toujours vos découvertes pour que d'autres puissent apprendre de votre parcours. C'est ainsi que notre communauté grandit et évolue. Sur ce, je vais conclure cette section. Profitez du reste de l'instructable et bon bricolage !