Ingeniería inversa de MCU

Desbloqueo de microcontroladores - MikaTech

Nuestros valores y objetivos

Acerca de MikaTech

El tiempo pasó rápido, desde el día en que realizamos nuestro primer proyecto de ingeniería inversa de MCU 8051 en 1998, hasta el día en que establecimos nuestro laboratorio de ingeniería inversa de un millón de dólares en 2012, pasaron 14 años. Ahora comenzamos nuestro nuevo negocio de desarrollo de sistemas visuales embebidos, esperamos poder servir otros 10 años.

firma Peter Lee Co-fundador y CEO

Ingeniería inversa para emular cartuchos de tinta

  • Durante los últimos dos años, he estado planeando construirme una impresora 3D a partir de algunas impresoras de inyección de tinta viejas que había ido recolectando. Pero no fue hasta hace dos semanas que realmente comencé a trabajar en ello.

    La impresora 3D que quiero hacer utiliza cabezales de inyección para imprimir un producto químico sobre una plataforma de construcción. La plataforma de construcción desciende a medida que se esparce una nueva capa de polvo sobre ella. Luego, un producto químico se rocía desde el cabezal de impresión, lo que hace que el polvo se una. Si desea más información sobre este tipo de impresoras, busque aquí.

    Mi impresora elegida fue una vieja Epson Stylus C63 por estas razones:
    1. Los cartuchos de tinta solo suministran tinta, no tienen boquillas de inyección de tinta.
    2. Puedo conectar mangueras de goma u otro tipo de tubo que me permita imprimir otro producto químico de mi elección.
    3. Las boquillas del cabezal de impresión utilizan un material piezoeléctrico para producir gotas de tinta (duran mucho más que los inyectores térmicos).
    4. La mayoría de los manuales de servicio para impresoras Epson vienen con un esquema detallado de la placa principal.

    Nota: Debido a ciertas circunstancias, esta impresora ya había sido desarmada.

    Lo primero que necesitaba hacer era poner en marcha mi impresora para poder conectar mi analizador lógico y observar las señales; el problema era que me faltaba un cartucho de tinta, por lo que la impresora se negaba a imprimir o hacer cualquier cosa.
    Debido a mi presupuesto (sin trabajo y a punto de comenzar la universidad) decidí intentar emular el cartucho faltante, o todos ellos usando un microcontrolador, permitiéndome así avanzar y usar agua para el cabezal de impresión en lugar de tinta que mancha.


  • Así que, para emular los cartuchos de tinta, necesito saber primero cómo funcionan. Afortunadamente, los cartuchos de tinta de mi impresora tienen EEPROM simples que contienen el uso de tinta y otra información importante sobre el cartucho, como la fecha de caducidad, el color, el número de serie, etc.

    Dentro del cabezal de impresión, hay una placa de circuito con almohadillas que son un reflejo exacto de las almohadillas de los cartuchos de tinta y un cable plano que conecta esta placa a la placa principal en los pines 1 a 6.

    Un vistazo rápido al esquema de la placa principal revela que los pines 1 a 6 se denominan CVDD, CSDA, CRST, GND, CSCK y COI.

    Con estos nombres de señales, decidí que sería mejor dibujar un esquema de la placa de conexión, ya que no estaba presente en el manual de servicio. Esto reveló que CSDA, CSCK, CRST tienen resistencias de pull-down de 100KOhm, un poco inusual en mi opinión, ya que no es como I2C (que usa resistencias de pull-up, típicamente de 1.8KOhms a 47KOhms). La señal COI se conecta en serie a los cartuchos de tinta, pero en el extremo está en cortocircuito a GND. Curiosamente, probé la continuidad de las almohadillas en los cartuchos de tinta y encontré que están en cortocircuito; esto significa que cuando COI está a tierra, todos los cartuchos de tinta están presentes.

  • Ahora que conozco los nombres de las señales, quería ver cómo eran las señales en sí.
    Saqué mi soldador, un cable plano (que solía ser un cable IDE de una computadora vieja) y un cuchillo artesanal. Corté un cable plano de 6 hilos de unos 30 cm de largo, pelé los extremos con cuidado usando el cuchillo artesanal (es mucho más fácil usar un cuchillo artesanal para pelar un cable plano que un par de cortadores o alicates), y los soldé a la placa de circuito que se acopla con los cartuchos de tinta.
    También pelé los otros extremos y soldé algunos pines para poder conectarlos a mi analizador lógico.

    Después de conectar el analizador lógico a la placa de circuito y observar las señales, descubrí que inmediatamente SCK y SDA no se parecen en nada a I2C. Estoy bastante seguro de que Epson debe haber inventado su propio protocolo serie para comunicarse con las EEPROM dentro de los cartuchos de tinta.

    Lo que encontré es que CVDD se enciende y, poco después, CRST y CSDA suben exactamente al mismo tiempo, seguidos poco después por CSCK que pulsa. CSDA cambia en el flanco ascendente de CSCK y supondré que se lee en el flanco descendente.
    CSCK es el reloj serie (Serial ClocK)
    CSDA son los datos serie (Serial Data)
    CRST es el reinicio (Reset)
    y CVDD es la alimentación
    Parece fácil, pero quería más información sobre este protocolo: ¿se enviaban direcciones?

    Aumenté la tasa de muestreo de mi analizador lógico y encontré que hay 4 ciclos de reloj, una pausa, luego 8 ciclos, pausa, 8 más, y así sucesivamente. Los 4 ciclos de reloj al principio me dieron la idea de que los primeros cuatro podrían ser posiblemente una dirección de 4 bits del cartucho de tinta. Aún así, se desconocía mucha información sobre este protocolo. ¡Así que investigué un poco!

    Buscando en Google no encontré nada sobre este protocolo; el siguiente mejor lugar para buscar fue en patentes.
    Sí, patentes. Busqué "Epson SDA SCK RST memory eeprom" en http://www.freepatentsonline.com/ y una de las patentes que encontré (US7660008 ) contenía exactamente lo que estaba buscando. Describía el protocolo SCK, SDA, RST y VDD.
    Les ahorraré el problema y señalaré lo que encontré:
    1. Diagramas de flujo que describen lo que hacen el Host y el Esclavo.
    2. Un diagrama de tiempos del protocolo.
    3. Los primeros 3 bits son una dirección de 3 bits seguida de un bit de Lectura/Escritura (Lectura = 0, Escritura = 1).
    4. El contador de direcciones siempre comienza en 0x00 y se incrementa en 1 cada ciclo de reloj (esto debe significar que escribe en bits, no en bytes).
    5. En el momento en que RST pasa a bajo, la EEPROM detiene todo y se reinicia.
    6. Hay 252 bits para leer; los últimos 3 bits (en realidad están al principio) son la dirección del cartucho de tinta.

    Usando lo que había encontrado, decidí comenzar a escribir código.

    Lo que quería hacer era leer las ROM de los cartuchos de tinta y luego usar esos datos para intentar emular el cartucho de tinta faltante que no tengo. Esto significa crear una biblioteca que actúe como host para leer los datos, pero que también pueda usarse para emular un cartucho de tinta.
    Usando conocimientos previos de la creación de protocolos basados en software, creé un archivo de cabecera con estas funciones:
    • extern void epsnCartInit(void);
    • extern void epsnCartStart(unsigned char addr, unsigned char write);
    • extern void epsnCartStop(void);
    • extern void epsnCartWrite(unsigned char data);
    • extern unsigned char epsnCartRead(void);

    También creé las siguientes definiciones que ayudan a recordar qué pin es cada cosa:
    Para su microcontrolador, necesitará modificar estos valores para adaptarlos a su aplicación.

    #define _ecSCKTRIS TRISCbits.TRISC0
    #define _ecSDATRIS TRISCbits.TRISC1
    #define _ecRSTTRIS TRISCbits.TRISC2
    #define _ecVDDTRIS TRISBbits.TRISB1

  • #define _ecSCKLat LATCbits.LATC0
    #define _ecSDALat LATCbits.LATC1
    #define _ecRSTLat LATCbits.LATC2
    #define _ecVDDLat LATBbits.LATB0

    #define _ecSCK PORTCbits.RC0
    #define _ecSDA PORTCbits.RC1
    #define _ecRST PORTCbits.RC2
    #define _ecVDD PORTBbits.RB1

    #define wait() DelayUS(50)

    Nota: Usé un PIC18F y usé Latches para establecer las salidas; es solo mi preferencia personal. Puede usar cualquier microcontrolador con el que esté familiarizado.

    void epsnCartInit(){
    _epsnCartSCKTRIS = 0;
    _epsnCartSDATRIS = 0;
    _epsnCartRSTTRIS = 0;
    _epsnCartVDDTRIS = 0;

    _epsnCartSCK = 0;
    _epsnCartSDA = 0;
    _epsnCartRST = 0;
    _epsnCartVDD = 0;

    _epsnCartSCKLat = 0;
    _epsnCartSCKLat = 0;
    _epsnCartSCKLat = 0;
    _epsnCartSCKLat = 0;
    }

    • Lista de ingeniería inversa de MCU de impresoras Atmel de Mikatech:
  • Serie completa AT89xx: 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 ...

  • Serie completa AT90xx: AT90S1200 AT90S2323 AT90S2343 AT90S2331 AT90S4433 AT90S8515 AT90S8535 AT90S4414 AT90S4434 AT90S2313 90S1200 90S2323 90S2343 90S2331 90S4433 90S8515 90S8535 90S4414 90S4434 90S2313 ...

  • Serie AT90CAN/PWM/USB/xx: AT90CAN32 AT90CAN64 AT90CAN128 AT90PWM2 AT90PWM216 AT90PWM2B AT90PWM3 AT90PWM316 AT90PWM3B AT90USB1286 AT90USB1287 AT90USB162 AT90USB646 AT90USB647 AT90USB82 ...
  • Serie AT91SAMxx: AT91SAM9XE512 AT91SAM9XE256 AT91SAM9XE128 AT91SAM7S64B AT91SAM7S32B AT91SAM7SE512 AT91SAM7SE256 AT91SAM7SE32 AT91SAM7XC512 AT91SAM7XC256 AT91SAM7XC128 AT91SAM7X512 AT91SAM7X256 AT91SAM7X128 AT91SAM7S161 AT91SAM7S512 AT91SAM7S256 AT91SAM7S128 AT91SAM7S64 AT91SAM7S321 ...

  • Serie ATFxx: 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 ...

  • Serie AT88scxx/90scxx: AT88SC0104 AT88SC0104C AT88SC0204 AT88SC0204C AT88SC0404 AT88SC0404C AT88SC0808 AT88SC0808C AT88SC1003 AT88SC101 AT88SC102 AT88SC1281 AT88SC12816C AT88SC150 AT88SC153 ...

La función de inicio pone VDD en alto, espera, luego establece SDA según el bit de dirección, así como SCK. Espera, pone SCK en bajo, espera nuevamente y luego pone SDA en alto según la dirección. Esto se repite 2 veces más, excepto que en la cuarta vez, SDA se establece en bajo porque queremos leer los datos en las EEPROM, no escribir.

void epsnCartStart(unsigned char addr,unsigned char write){
char i = 0; // Usado para contar
char tmp = 0; // Variable de almacenamiento temporal

_ecVDDLat = 1; // Pone VDD en alto
DelayMS(1); // Espera a que las EEPROM estén listas
_ecRSTLat = 1; // Habilita las EEPROM para la comunicación

tmp = addr; // Copia la dirección en la variable temporal
if(write){ // Si queremos escribir
temp |= 0x08; //pone el 4º bit en alto ( '|' significa OR )
}

while(i<4){
_ecSDALat = (tmp&0x01); // Pone SDA en alto o bajo según el LSB

wait(); // Espera aproximadamente 50uS
_ecSCKLat = 1; // Pone el reloj en alto
wait(); // Espera otros 50uS
_ecSCKLat = 0; //Pone el reloj en bajo
wait(); // Espera otros 50uS
tmp>>=1; //Desplaza a la derecha todos los bits de tmp en uno
i++; // incrementa el contador en uno
}

}

La siguiente función a implementar es stop:
void epsnCartStop(){
_ecRSTLat = 0; //Pone RST en bajo
DelayMS(1); //Espera un poco
_ecVDDLat = 0; //Apaga las EEPROM
}

Y finalmente la función de lectura:
unsigned char epsnCartRead(){
char i=0;
char temp = 0x00;

while(i<8){
temp>>=1; // Desplaza a la derecha la variable temporal en uno
_ecSCKLat = 1; //pone SCK en alto
wait(); //Espera aproximadamente 50uS
if(_ecSDA){ // Si SDA está en alto
temp |= 0x80; // Entonces pone el bit 7 en alto
}
_ecSCKLat = 0; // Vuelve a poner SCK en bajo
wait(); //espera otros 50uS

i++; // Incrementa el contador en 1
}
return temp; // Devuelve lo que hemos leído
}

Ahora tenemos las funciones básicas que necesitamos para leer datos de los cartuchos de tinta; configuremos nuestro microcontrolador y establezcamos los resultados.

  • Inicie su IDE, en mi caso es MPLab, cree un nuevo proyecto para su chip y cree un programa "hola mundo" básico para asegurarse de que su chip funciona.

    Nota: Mi programa "hola mundo" envía "Hello World!\r\n" por Serie a mi computadora a 38400bps

    #include <p18f2550.h> // Archivo de inclusión específico para este chip
    #include <usart.h> // Funciones 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; // Esto es un problemático, ¡nunca olvide volver a poner los pines analógicos en digitales! :P

    TRISCbits.TRISC7 = 1; // Convierte el pin RX en una entrada (consulte la hoja de datos de su chip)

    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"); // Envía un mensaje por Serie

    LATAbits.LATA0 = ~LATAbits.LATA0; //Parpadea un LED activándolo y desactivándolo

    DelayMS(500); // Una función de retardo que he creado
    }
    }

    Esto se configuró con una fuente de alimentación de 3.3V porque los cartuchos de tinta funcionan a 3.3 Voltios.

    ¿Por qué un programa "hola mundo"? Bueno, cada vez que configuro un nuevo proyecto en una placa de pruebas, siempre quiero asegurarme de que los bits de configuración sean correctos y de que no estoy recibiendo basura en el terminal.

    ¡Creo que esto es una buena práctica y todo el mundo debería hacerlo! :P

    Si su chip está haciendo algo simple como el mío, ¡Genial! Pasemos al siguiente paso.

    Implementando nuestra biblioteca
    Ahora queremos incluir la biblioteca que creamos para la interfaz del microcontrolador con el cartucho de tinta.

    En la parte superior del archivo añada:
    #include "epsnCart.h" // el nombre del archivo de cabecera que creamos anteriormente

    Dado que este microcontrolador está actuando como host, controla las señales SCK, SDA y RST. Así que asegúrese de que sean salidas; añada esto con los otros registros TRIS dentro de main():

    epsnCartInit();

    El siguiente fragmento de código es el que usé dentro de while(1) {
    Solicita una dirección comenzando en 0x00 y luego se incrementa en uno después de 32 bytes leídos:

    void main(){
    char addr = 0, i = 0;
    char string[40];

    ...
    epsnCartInit(); // Inicializa los pines usados

    while(1){ // ¡Bucle infinito!

    sprintf(string, "Leyendo cartucho con addr: 0x%02X\r\n",addr);
    putsUSART(string); // imprime un mensaje como: Leyendo cartucho con addr: 0x03

    epsnCartStart(addr,0); // Inicia enviando la dirección en modo lectura

    i = 0;
    while(i<32){ // sigue en bucle hasta que i ya no sea menor que 32
    sprintf(string,"0x%02X,",epsnCartRead());
    putsUSART(string);
    i++;
    }

    epsnCartStop(); //pone RST en bajo

    putrsUSART("\r\n");

    addr++
    if(addr>7){
    addr = 0;
    }
    DelayMS(500);
    }
    }

  • Serie ATTinyxx: 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 ...

  • Serie ATMegaxx: 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 ...

  • Probablemente esté mirando la línea "sprintf(string,"0x%02X,",epsnCartRead());" y pensando "¿Eh?"
    sprintf es una función de formateo de cadenas, muy parecida a printf, excepto que guarda la cadena formateada en la variable string.
    "0x%02X," devolverá una cadena con un valor hexadecimal legible, ej: 0xFE, y epsnCartRead() devuelve un valor que se leyó del cartucho de tinta.

    Esto se configuró con una fuente de alimentación de 3.3V porque los cartuchos de tinta funcionan a 3.3 Voltios.

    Programé esto en mi microcontrolador, desconecté el cabezal de impresión de la impresora para evitar interferencias.
    Luego conecté los 3 cartuchos de tinta que tenía y lo encendí.

    Nota: En este punto, si ejecutó este código por primera vez, espero que tenga problemas. Como yo, he revisado el código docenas de veces, cambiándolo aquí y allá para que funcione. Es normal que no funcione la primera vez. Es una gran experiencia de aprendizaje descubrir qué salió mal. :P

  • Uf, después de todo ese trabajo duro, ¡está vivo!!!

    Esto es lo que obtuve en mi 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,

    Ahora, observe aquí cómo solo las direcciones impares devolvieron datos, excepto 0x05.
    Eso es porque 0x05 es la dirección del cartucho de tinta magenta, que lamentablemente no tengo :(

  • Rutinas de código de emulación
    ¡Ahora la parte divertida!

    Necesito que la impresora piense que hay cuatro cartuchos de tinta instalados. Para hacer esto, primero debemos implementar algunas funciones de emulación. Nuevamente, basándome en conocimientos previos, he predefinido estas en el encabezado:

    • #define epsnCartReady() (_ecRST)
    • extern unsigned char espnCartGetAddr(void);
    • extern void epsnCartOut(unsigned char data);
    • extern unsigned char epsnCartIn(unsigned char data);

    epsnCartReady es una macro que se usa para verificar si la impresora tiene RST en alto.
    epsnCartGetAddr devuelve la dirección que está solicitando el cabezal de impresión.
    epsnCartOut se usa para enviar datos al controlador Host.
    epsnCartIn se usa para recibir datos del Host cuando está escribiendo.

    Así que esta vez, en lugar de controlar SCK para que suba o baje, necesitamos esperar a que suba o baje, pero si el reset se pone en bajo, detener todo y retornar:

    unsigned char espnCartGetAddr(void){
    char i=0;
    char temp = 0x00;

    while((i<4) && _ecRST){ // Bucle mientras i < 4 y RST esté en ALTO
    temp>>=1; // Desplaza Temp a la derecha en uno
    while((!_ecSCK) && (_ecRST)); // Espera a que el reloj suba
    if(_ecSDA){// solo si SDA está en alto
    temp |= 0x08; // entonces establece el 4º bit
    }
    while((_ecSCK) && (_ecRST));// espera a que el reloj baje
    i++; // incrementa el contador
    }

    if(_ecRST == 0){
    return 0xFF;//si RST bajó, significa que el Host mató la señal
    }
    return temp; //devuelve la dirección y el bit de lectura/escritura
    }

    Y la función Out:

    void epsnCartOut(unsigned char data){
    char i = 0;
    char temp = data;

    _ecSDATRIS = 0; // configura SDA como salida
    _ecSDALat = 0; // pone SDA en bajo

    while((i<8) && _ecRST){ // Bucle mientras i < 8 y RST esté en alto
    while(!_ecSCK && _ecRST); // Espera a que SCK suba
    _ecSDALat = temp&0x01; // Pone SDA en alto o bajo según el primer bit

    while(_ecSCK && _ecRST); // Espera a que SCK baje
    temp>>=1; // Desplaza los datos a la derecha en uno
    i++; // incrementa el contador en uno
    }
    _ecSDATRIS = 1; // Configura SDA como salida (nota: probablemente debería ser entrada)
    _ecSDA = 1; // no estoy seguro de si esto es necesario
    }

    Y finalmente la función In:

    unsigned char epsnCartIn(void){
    unsigned char i=0;
    char temp = 0x00;

    while((i<8) && _ecRST){ // Bucle mientras i < 8 y RST esté en alto
    temp>>=1; // Desplaza temp a la derecha en uno
    while(!_ecSCK && _ecRST); // Espera a que SCK suba
    if(_ecSDA){ // solo si SDA está en alto
    temp |= 0x80; // Establece el 8º bit
    }

    while(_ecSCK && _ecRST);// Espera a que SCK baje
    i++; // Incrementa el contador en uno
    }
    return temp; // devuelve lo que hemos recibido
    }

    Así que lo que sucede ahora es que necesitamos configurar nuestro microcontrolador para que contenga los datos que hemos volcado. Luego permitir que el host de la impresora lea y escriba en él.

    El problema con esto es que no quiero que mis cartuchos de tinta falsos se gasten nunca, así que para hacer eso tenemos un volcado fijo que el microcontrolador cargará en la RAM cada vez que se inicie. Esto permitirá que la impresora no solo lea, sino que también escriba en él. Cuando el microcontrolador se apague y se vuelva a encender, los datos anteriores se restauran. (Doble beneficio)

    Almacenando matrices de datos en el microcontrolador, coloque esto en algún lugar debajo de los includes, pero antes de void main():

    Nota: Esto puede variar entre diferentes familias de microcontroladores, pero funciona bien con mi 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};

    Nota: ¿Se ha dado cuenta de que no tengo Magenta? Eso es porque es el cartucho de tinta que no tengo.

    El siguiente paso es escribir una rutina que verifique qué cartucho de tinta se está solicitando y permitir que el host lea y escriba en él.
    Así es como lo hice:

    void main(){
    unsigned char* inkPtr;
    char addr = 0x00;
    ...

    While(1){

    epsnCartStartListen();

    while(epsnCartReady()==1); // Espera a que la señal Ready vuelva a bajo

    while(epsnCartReady()==0);
    addr = espnCartGetAddr();

    if(addr&0x7 == 0x01){ // si los primeros 3 bits son iguales a 0x01
    inkPtr = &black[0]; // Apunta a los datos del negro
    }else if(addr&0x7 == 0x03){ // si los primeros 3 bits son iguales a 0x03
    inkPtr = &cyan[0]; // Apunta a los datos del cian
    }else if(addr[i]&0x7 == 0x05){
    inkPtr = &cyan[0]; // Esto debería ser Magenta, pero no lo tengo
    }else if(addr[i]&0x7 == 0x07){
    inkPtr = &yellow[0];
    }else{
    continue: // Vuelve al principio del bucle principal porque no conocemos esta dirección
    }

    if(addr&0x08){//Modo Escritura – Comprobar si el Host quiere escribir
    while(epsnCartReady()){//mantener el bucle hasta que RST baje
    *inkPtr = epsnCartIn();
    // los datos a los que apunta el puntero
    // se sobrescriben con nuevos datos
    inkPtr++; // Incrementa el Puntero
    }
    }else{//Modo Lectura
    while(epsnCartReady()){
    epsnCartOut(*inkPtr);
    // Salida de los datos a los que apunta el Puntero
    inkPtr++; // Incrementa el puntero
    }
    }
    }
    }

    ¡Éxito!
    Después de programar este nuevo código y encender mi impresora, la impresora aceptó 4 cartuchos imaginarios gracias a mi microcontrolador. También me sorprende que aceptara los datos del cartucho cian también para el magenta.

    Este proyecto completo es un ejemplo perfecto de cómo la ingeniería inversa puede desbloquear el potencial del hardware propietario. Al comprender el protocolo de comunicación, efectivamente realicé una extracción de firmware de los contenidos de la EEPROM, aunque los datos eran pequeños. En un sistema más complejo, uno podría necesitar volcar la memoria flash de un microcontrolador para analizar su código. La EEPROM en estos cartuchos actúa como un pequeño almacenamiento seguro, pero sin ningún bit de bloqueo o cifrado, es trivial leer los datos. Algunos cartuchos de impresora modernos incluyen un mecanismo de bloqueo que evita la reutilización, pero aquí la única protección era el protocolo oscuro. Esta oscuridad no es seguridad, como lo demostré al emular con éxito el cartucho faltante. La capacidad de duplicar la identidad del cartucho permitiría rellenados infinitos, que es exactamente lo que los fabricantes de impresoras intentan evitar. A menudo utilizan fusibles o bits programables de una sola vez para marcar un cartucho como vacío, pero esta EEPROM es completamente reescribible. Mi microcontrolador ahora actúa como un hombre en el medio, interceptando solicitudes de lectura y sirviendo datos almacenados. Esto es esencialmente una forma simple de recuperación de firmware para la impresora, ya que restauré la funcionalidad completa sin la pieza original. El código que escribí es pequeño pero efectivo, y podría adaptarse a otros dispositivos con EEPROM serie similares. A menudo me he preguntado si los fabricantes de impresoras dejan intencionalmente estas vulnerabilidades para permitir cartuchos de terceros. Independientemente, este proyecto me enseñó mucho sobre protocolos de hardware y sistemas embebidos. El MCU que usé, un PIC18F, fue más que capaz de manejar los requisitos de temporización. De hecho, podría haber usado un microcontrolador más pequeño, pero el PIC me dio suficiente espacio para futuras expansiones. Toda la configuración funciona a 3.3V, coincidiendo con el voltaje interno del cartucho. Un desafío fue asegurar que la línea SDA se manejara correctamente en ambas direcciones, ya que la impresora y mi MCU alternan el control. Tuve que gestionar cuidadosamente los registros TRIS para evitar conflictos en el bus. Este es un problema común en cualquier sistema multi-maestro, pero aquí es un solo host y un emulador esclavo. Los diagramas de tiempos de la patente fueron invaluables; me dieron las relaciones exactas de los flancos de reloj. Sin eso, habría pasado días adivinando. Esta experiencia subraya la importancia de la documentación, incluso si está oculta en patentes. También aprendí que a veces la solución más simple es la mejor: simplemente almacenar el volcado en RAM y actualizarlo al encender. Esto asegura que los niveles de tinta nunca disminuyan, lo cual es una ventaja adicional. Sin embargo, para un producto real, necesitaría considerar el desgaste y la protección contra pérdida de energía. Pero para un proyecto de hobby, esto es perfecto. Ahora confío en que puedo abordar tareas de ingeniería inversa más complejas en el futuro. El siguiente paso podría implicar espiar la comunicación entre la impresora y los controladores del motor del cabezal de impresión. Eso me permitiría controlar con precisión el movimiento XY para mi conversión a impresora 3D. Pero esa es una historia para otro instructable. Por ahora, estoy encantado de que mi emulación funcione perfectamente. Incluso lo he probado con múltiples ciclos de alimentación y conserva los datos cada vez. La matriz RAM se reinicializa con los valores codificados en cada arranque, por lo que el cartucho siempre aparece como nuevo. La impresora nunca se queja de cartuchos falsificados porque los datos son una copia perfecta de uno genuino. Esto es esencialmente una duplicación de la identidad del cartucho original. En un entorno comercial, esta técnica podría usarse para clonación no autorizada, pero aquí es para reutilización legítima. Tengo cuidado de usarlo solo para mis propios proyectos. El conocimiento adquirido en este ejercicio es aplicable a muchos otros productos electrónicos de consumo que utilizan memorias serie simples. Muchos dispositivos tienen EEPROM similares que almacenan datos de calibración o números de serie. Al leerlos, puede hacer copias de seguridad y restaurar información crítica. Esa es una forma de extracción de firmware en sí misma, incluso si el firmware es solo datos de configuración. He visto proyectos donde la gente descifra el firmware de un medidor inteligente usando métodos similares. Pero eso implica criptografía mucho más compleja y a menudo un bit de bloqueo para evitar la lectura. Aquí no hay tal bloqueo, así que está completamente abierto. Algunos podrían argumentar que esto es una falla de seguridad, pero para mí es una oportunidad. Ya he comenzado a planificar una versión que usa un MCU ATtiny más pequeño para ahorrar espacio. El tamaño del código es pequeño, por lo que podría caber en un encapsulado de 8 pines. Incluso podría agregar una característica para simular diferentes tipos de cartuchos mediante un interruptor DIP. Eso sería útil para probar varias tintas. Las posibilidades son infinitas. También estoy considerando compartir mi código en GitHub para que otros lo adapten. Este enfoque de código abierto fomenta la colaboración y la innovación. Muchos hackers ya han hecho cosas similares con otras marcas de impresoras. La comunidad es muy activa en la ingeniería inversa de consumibles para reducir el desperdicio y ahorrar dinero. Es un beneficio mutuo para el medio ambiente y el usuario. Espero que mi instructable inspire a otros a mirar debajo del capó de sus propios dispositivos. Con un analizador lógico y un poco de paciencia, puede descubrir protocolos ocultos. La clave es comenzar poco a poco, como hice con esta simple EEPROM. Una vez que domine lo básico, puede pasar a objetivos más desafiantes. Espero con ansias el día en que pueda imprimir en 3D con mi impresora convertida. Este es solo el primer hito. El siguiente gran paso es interactuar con los controladores del cabezal de impresión y construir el marco mecánico. Pero eso es un proyecto para otra temporada. Por ahora, estoy saboreando esta victoria. Es una prueba tangible de que la ingeniería inversa no es solo para hackers; es una habilidad valiosa para cualquier ingeniero. Al comprender cómo funcionan las cosas en el nivel más bajo, realmente puede hacerlas suyas. Ese es el espíritu de hacer y experimentar. Así que adelante, tome una impresora vieja y comience a sondear. Se sorprenderá de lo que puede lograr. Y recuerde, siempre documente sus hallazgos para que otros puedan aprender de su viaje. Así es como nuestra comunidad crece y evoluciona. Con eso, concluiré esta sección. Disfrute del resto del instructable y ¡feliz hacking!

  • Preguntas generales sobre extracción de firmware de microcontroladores


    • ¿Es seguro enviar el pago a MikaTech ?

      Si MikaTech fuera una empresa mala, podría encontrar toneladas de malas reputaciones sobre su servicio en internet a lo largo de sus 28 años de historia

      Así que, la respuesta es ¡SÍ! Somos buena gente.

      Por qué elegir Mikatech, por favor haga clic aquí para saber más


    • ¿Puede Mikatech romper circuitos integrados no listados en este sitio ?

      Diferentes fabricantes de chips tienen diferentes números de pieza, pero el núcleo interno del chip puede estar fabricado con la misma tecnología, sería bastante imposible listar todos los números de pieza donde nuestra tecnología puede aplicarse, como MYSON, STK, FEELING, ANALOG, FUJITSU, NOVATEK, LG/HYNDAI.

      Además, con el avance de la tecnología, cada día ganamos más experiencia y desarrollamos nuevos métodos de ingeniería inversa para diferentes piezas de circuitos integrados. La lista completa de números de pieza de circuitos integrados que están dentro de nuestro alcance siempre crece, por favor contáctenos para averiguarlo.

    • ¿Se protegerá mi privacidad ?

      Mikatech Innovative Limited comprende la importancia de la privacidad de sus clientes. En el momento en que contacta a Mikatech, la información personal que nos proporcione quedará protegida por nuestras normas de gestión, desarrolladas a lo largo de años de práctica. Mikatech utiliza esta información para personalizar su servicio y nunca la divulgará a terceros por ningún motivo.
      En cada proyecto que realizamos, eliminamos todos los datos, materiales y códigos 60 días después de la entrega de los archivos; esto nos protege a nosotros y protege su privacidad.

    • ¿Es legal obtener el servicio de Mikatech ?

      Sí, es totalmente legal.
      Mikatech ofrece sus servicios de ingeniería inversa solo con fines educativos; puede ser ilegal utilizar los servicios mencionados en algunos países o regiones, consulte sus leyes locales. Mikatech no asume ninguna responsabilidad en relación con el uso de los servicios mencionados que pudiera considerarse ilegal.


    • Le envié un correo electrónico, ¿por qué no hay respuesta ?

      • A. Nuestro servidor de correo está temporalmente averiado, su mensaje no ha llegado a nuestra bandeja de entrada aunque en pantalla se muestre que el envío fue exitoso, por favor contáctenos de nuevo.
      • B. Nuestro correo es reconocido como spam por su servidor de correo, por lo que nuestra respuesta ha sido rechazada o desviada a su bandeja de spam, elimine nuestra cuenta de la lista de spam o revise su carpeta de correo no deseado, o utilice otra cuenta de correo como Gmail.
      • C. Su correo es reconocido como spam por nuestro servidor de correo, por lo que fue enviado a nuestra bandeja de spam, utilice otra cuenta de correo para contactarnos nuevamente.



      tiempo de hackeo de microcontrolador

      Años

      28 +
      países de hackeo de microcontroladores

      Países

      110 +
      clientes de ataque a microcontroladores

      Clientes

      5000 +
      proyectos de microcontroladores desbloqueados

      Proyectos

      60000 +