Обратная разработка MCU

Взлом микроконтроллеров - MikaTech

Наши ценности и цели

О компании MikaTech

Время пролетело быстро: с того дня, когда мы выполнили наш первый проект по обратной разработке MCU 8051 в 1998 году, до того дня, когда мы создали нашу миллионную лабораторию обратной разработки в 2012 году, прошло 14 лет. Теперь мы начинаем наш новый бизнес по разработке встраиваемых визуальных систем, надеемся, что сможем прослужить ещё 10 лет.

подпись Peter Lee Сооснователь и генеральный директор

Обратный инжиниринг для эмуляции картриджей с чернилами

  • Последние два года я планировал построить себе 3D-принтер из старых струйных принтеров, которые собирал годами. Но только две недели назад я наконец начал над ним работать.

    3D-принтер, который я хочу сделать, использует струйные головки для нанесения химического вещества на платформу построения. Платформа опускается, когда на неё насыпается новый слой порошка. Затем химикат распыляется из печатающей головки, что вызывает связывание порошка. Если вам нужна дополнительная информация о таких принтерах, посмотрите здесь.

    Мой выбор пал на старый Epson Stylus C63 по следующим причинам:
    1. Картриджи с чернилами только подают чернила, сами не имеют сопел струйной головки.
    2. Я могу подсоединить резиновые шланги или другие трубки, которые позволят мне печатать другим химикатом по моему выбору.
    3. Сопла печатающей головки используют пьезоэлектрический материал для образования капель чернил (служат намного дольше, чем термические струйные).
    4. Большинство руководств по обслуживанию принтеров Epson содержат подробные схемы основной платы.

    Примечание. В связи с определёнными обстоятельствами этот принтер уже был разобран.

    Первое, что мне нужно было сделать, — запустить принтер, чтобы я мог подключить логический анализатор и посмотреть сигналы. Проблема была в том, что у меня отсутствовал один картридж, поэтому принтер отказывался печатать или что-либо делать.
    Из-за моего бюджета (без работы и собираюсь поступать в университет) я решил попытаться эмулировать отсутствующий картридж или все сразу с помощью одного микроконтроллера, что позволило бы мне продвинуться вперёд и использовать воду для печатающей головки вместо чернил, которые оставляют пятна.


  • Итак, чтобы эмулировать чернильные картриджи, мне нужно сначала узнать, как они работают. К счастью, картриджи в моём принтере имеют простые EEPROM, которые хранят информацию об использовании чернил и другие важные данные, такие как срок годности, цвет, серийный номер и т.д.

    Внутри печатающей головки есть плата с контактными площадками, которые являются точным зеркалом площадок на чернильных картриджах, и шлейф, который соединяет эту плату с основной платой по выводам 1–6.

    Быстрый взгляд на схему основной платы показывает, что выводы 1–6 называются CVDD, CSDA, CRST, GND, CSCK и COI.

    Имея эти имена сигналов, я решил, что лучше нарисовать схему соединительной платы, так как она отсутствовала в руководстве по обслуживанию. Это показало, что CSDA, CSCK, CRST имеют подтягивающие резисторы 100 кОм к земле, что, по моему мнению, необычно, так как это не I2C (где обычно используются подтягивающие резисторы 1,8–47 кОм к питанию). Сигнал COI последовательно соединяется с картриджами, но на конце замыкается на землю. Любопытно, я проверил непрерывность площадок на картриджах и обнаружил, что они замкнуты, это означает, что когда COI замкнут на землю, все картриджи присутствуют.

  • Теперь, когда я знаю имена сигналов, я хотел увидеть, как выглядят сами сигналы.
    Я достал паяльник, шлейф (раньше это был IDE-кабель от старого компьютера) и канцелярский нож. Я отрезал 6-жильный шлейф длиной около 30 см, аккуратно зачистил концы с помощью канцелярского ножа (это намного проще, чем использовать кусачки или плоскогубцы) и припаял их к печатной плате, которая соединяется с картриджами.
    Я также зачистил другие концы и припаял штырьки, чтобы их можно было подключить к логическому анализатору.

    После подключения логического анализатора к печатной плате и просмотра сигналов я обнаружил, что сразу же SCK, SDA совсем не похожи на I2C. Я почти уверен, что Epson должна была изобрести свой собственный последовательный протокол для общения с EEPROM внутри чернильных картриджей.

    Я обнаружил, что CVDD подаётся питание, а вскоре после этого CRST и CSDA поднимаются одновременно, а затем CSCK начинает выдавать импульсы. CSDA изменяется по переднему фронту CSCK, и я предположу, что он считывается по спадающему фронту.
    CSCK — это последовательная тактовая частота (Serial ClocK)
    CSDA — это последовательные данные (Serial Data)
    CRST — это сброс (Reset)
    а CVDD — питание
    Выглядит достаточно просто, но я хотел получить больше информации об этом протоколе: были ли там какие-либо адреса?

    Я увеличил частоту дискретизации на логическом анализаторе и обнаружил, что есть 4 тактовых цикла, пауза, затем 8 циклов, пауза, ещё 8 и так далее. 4 тактовых цикла в начале навели меня на мысль, что первые четыре бита могут быть 4-битным адресом картриджа. Тем не менее, много информации об этом протоколе было неизвестно. Поэтому я провёл небольшое исследование!

    Поиск в Google не дал результатов об этом протоколе, следующим лучшим местом для поиска были патенты.
    Да, патенты. Я искал «Epson SDA SCK RST memory eeprom» на http://www.freepatentsonline.com/ и один из патентов, который я нашёл (US7660008), содержал именно то, что я искал. В нём описывались SCK, SDA, RST и VDD протокола.
    Я избавлю вас от хлопот и укажу, что я нашёл:
    1. Блок-схемы, описывающие, что делают ведущий и ведомый.
    2. Временная диаграмма протокола.
    3. Первые 3 бита — это 3-битный адрес, за которым следует бит чтения/записи (Read = 0, Write = 1).
    4. Счётчик адреса всегда начинается с 0x00 и увеличивается на 1 за каждый такт (это означает, что запись идёт побитно, а не побайтово).
    5. Как только RST переходит в низкий уровень, EEPROM останавливает всё и сбрасывается.
    6. Всего 252 бита для чтения, последние 3 бита (на самом деле они в начале) — это адрес чернильного картриджа.

    Используя то, что я нашёл, я решил начать писать код.

    Я хотел прочитать ПЗУ из картриджей, а затем использовать эти данные для попытки эмуляции отсутствующего картриджа. Это означает создание библиотеки, которая будет действовать как ведущий для чтения данных, но также может использоваться для эмуляции чернильного картриджа.
    Используя предыдущие знания по созданию программных протоколов, я создал заголовочный файл со следующими функциями:
    • 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);

    Я также создал следующие определения, которые помогают запомнить, какой вывод за что отвечает:
    Для вашего микроконтроллера вам нужно будет изменить эти значения в соответствии с вашим приложением.

    #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)

    Примечание: Я использовал PIC18F и использовал защёлки для установки выходов, это просто моё предпочтение. Вы можете использовать любой микроконтроллер, с которым вы знакомы.

    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;
    }

    • Список обратной разработки принтерных MCU Atmel от Mikatech:
  • Полная серия 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 ...

  • Полная серия AT90xx — взлом микроконтроллеров: AT90S1200 AT90S2323 AT90S2343 AT90S2331 AT90S4433 AT90S8515 AT90S8535 AT90S4414 AT90S4434 AT90S2313 90S1200 90S2323 90S2343 90S2331 90S4433 90S8515 90S8535 90S4414 90S4434 90S2313 ...

  • Полная серия AT90CAN/PWM/USB/xx — чтение микроконтроллеров: AT90CAN32 AT90CAN64 AT90CAN128 AT90PWM2 AT90PWM216 AT90PWM2B AT90PWM3 AT90PWM316 AT90PWM3B AT90USB1286 AT90USB1287 AT90USB162 AT90USB646 AT90USB647 AT90USB82 ...
  • Полная серия AT91SAMxx — взлом прошивки микроконтроллеров: AT91SAM9XE512 AT91SAM9XE256 AT91SAM9XE128 AT91SAM7S64B AT91SAM7S32B AT91SAM7SE512 AT91SAM7SE256 AT91SAM7SE32 AT91SAM7XC512 AT91SAM7XC256 AT91SAM7XC128 AT91SAM7X512 AT91SAM7X256 AT91SAM7X128 AT91SAM7S161 AT91SAM7S512 AT91SAM7S256 AT91SAM7S128 AT91SAM7S64 AT91SAM7S321 ...

  • Серия 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 ...

  • Серия AT88scxx/90scxx — взлом микроконтроллеров: AT88SC0104 AT88SC0104C AT88SC0204 AT88SC0204C AT88SC0404 AT88SC0404C AT88SC0808 AT88SC0808C AT88SC1003 AT88SC101 AT88SC102 AT88SC1281 AT88SC12816C AT88SC150 AT88SC153 ...

Функция старта поднимает VDD, ждёт, затем устанавливает SDA в соответствии с битом адреса, а также SCK. Ждёт, опускает SCK, снова ждёт и затем поднимает SDA в соответствии с адресом. Это повторяется ещё 2 раза, за исключением того, что на 4-й раз SDA устанавливается в низкий уровень, потому что мы хотим читать данные из EEPROM, а не записывать.

void epsnCartStart(unsigned char addr,unsigned char write){
char i = 0; // Используется для счёта
char tmp = 0; // Временная переменная хранения

_ecVDDLat = 1; // Установить VDD высоко
DelayMS(1); // Подождать, пока EEPROM будут готовы
_ecRSTLat = 1; // Включить EEPROM для связи

tmp = addr; // Скопировать адрес во временную переменную
if(write){ // Если мы хотим записать
temp |= 0x08; // установить 4-й бит высоко ( '|' означает ИЛИ )
}

while(i<4){
_ecSDALat = (tmp&0x01); // Установить SDA высоко или низко в соответствии с младшим битом

wait(); // Подождать примерно 50 мкс
_ecSCKLat = 1; // Установить такт высоко
wait(); // Подождать ещё 50 мкс
_ecSCKLat = 0; // Установить такт низко
wait(); // Подождать ещё 50 мкс
tmp>>=1; // Сдвинуть все биты tmp вправо на один
i++; // Увеличить счётчик на один
}

}

Следующая функция, которую нужно реализовать, — stop:
void epsnCartStop(){
_ecRSTLat = 0; // Установить RST низко
DelayMS(1); // Подождать немного
_ecVDDLat = 0; // Выключить EEPROM
}

И, наконец, функция чтения:
unsigned char epsnCartRead(){
char i=0;
char temp = 0x00;

while(i<8){
temp>>=1; // Сдвинуть временную переменную вправо на один
_ecSCKLat = 1; // Установить SCK высоко
wait(); // Подождать примерно 50 мкс
if(_ecSDA){ // Если SDA высоко
temp |= 0x80; // Тогда установить 7-й бит высоко
}
_ecSCKLat = 0; // Снова опустить SCK
wait(); // Подождать ещё 50 мкс

i++; // Увеличить счётчик на 1
}
return temp; // Вернуть то, что мы прочитали
}

Теперь у нас есть базовые функции, необходимые для чтения данных из чернильных картриджей. Давайте настроим наш микроконтроллер и посмотрим результаты.

  • Запустите свою среду разработки, в моём случае это MPLab, создайте новый проект для вашего чипа и создайте простую программу «Hello World», чтобы убедиться, что ваш чип работает.

    Примечание: Моя программа Hello World отправляет «Hello World!\r\n» по последовательному порту на мой компьютер со скоростью 38400 бит/с.

    #include <p18f2550.h> // Файл включения для этого чипа
    #include <usart.h> // Функции USART
    #include <stdio.h> // printf(format,...), sprintf(string, format, ...), и т.д.

    #include "delay.h"

    void main(){

    PORTA = 0x00;
    PORTB = 0x00;
    PORTC = 0x00;

    TRISA = 0x00;
    TRISB = 0x00;
    TRISC = 0x00;

    ADCON1 = 0x0F; // Это доставляет много хлопот, никогда не забывайте переключать аналоговые выводы обратно в цифровые! :P

    TRISCbits.TRISC7 = 1; // Превращает вывод RX во вход (посмотрите в вашем даташите для вашего чипа)

    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"); // Отправить сообщение через Serial

    LATAbits.LATA0 = ~LATAbits.LATA0; // Мигать светодиодом, переключая его вкл/выкл

    DelayMS(500); // Функция задержки, которую я создал
    }
    }

    Это было настроено с источником питания 3,3 В, потому что чернильные картриджи работают от 3,3 вольт.

    Зачем программа Hello World? Что ж, каждый раз, когда я настраиваю новый проект на макетной плате, я всегда хочу убедиться, что биты конфигурации установлены правильно и что я не получаю мусор в терминале.

    Я думаю, это хорошая практика, и каждый должен так делать! :P

    Если ваш чип делает что-то простое, как мой, отлично! Переходим к следующему шагу.

    Реализация нашей библиотеки
    Теперь мы хотим включить библиотеку, которую мы создали для взаимодействия микроконтроллера с чернильным картриджем.

    В верхней части файла добавьте:
    #include "epsnCart.h" // имя созданного нами заголовочного файла

    Поскольку этот микроконтроллер выступает в роли ведущего, он управляет сигналами SCK, SDA и RST. Поэтому убедитесь, что они являются выходами, добавьте это вместе с другими регистрами TRIS внутри main():

    epsnCartInit();

    Следующий код я использовал внутри while(1) {
    Он запрашивает адрес, начиная с 0x00, и затем увеличивает его на 1 после 32 прочитанных байт:

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

    ...
    epsnCartInit(); // Инициализировать используемые выводы

    while(1){ // Бесконечный цикл!

    sprintf(string, "Чтение картриджа с адресом: 0x%02X\r\n",addr);
    putsUSART(string); // Выводит сообщение типа: Чтение картриджа с адресом: 0x03

    epsnCartStart(addr,0); // Запустить, отправив адрес в режиме чтения

    i = 0;
    while(i<32){ // продолжать цикл, пока i меньше 32
    sprintf(string,"0x%02X,",epsnCartRead());
    putsUSART(string);
    i++;
    }

    epsnCartStop(); // опускает RST обратно в низкий уровень

    putrsUSART("\r\n");

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

  • Полная серия 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 ...

  • Полная серия 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 ...

  • Вы, вероятно, смотрите на строку «sprintf(string,"0x%02X,",epsnCartRead());» и думаете «А?»
    sprintf — это функция форматирования строк, похожая на printf, но сохраняющая отформатированную строку в переменную string.
    "0x%02X," вернёт строку с читаемым шестнадцатеричным значением, например 0xFE, а epsnCartRead() возвращает значение, прочитанное из картриджа.

    Это было настроено с источником питания 3,3 В, потому что картриджи работают от 3,3 вольт.

    Я запрограммировал это в свой микроконтроллер, отключил печатающую головку от принтера, чтобы избежать помех.
    Затем я вставил 3 имеющихся у меня картриджа и включил его.

    Примечание: На этом этапе, если вы запускаете этот код в первый раз, я ожидаю, что у вас будут проблемы. Как и у меня, я просматривал код десятки раз, изменяя его то там, то здесь, чтобы заставить его работать. Это нормально, если у вас не получится с первого раза. Это отличный опыт обучения — выяснять, что пошло не так! :P

  • Уф, после всей этой тяжёлой работы, оно работает!!!

    Вот что я получил в своём терминале

    Адрес: 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,

    Адрес: 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,

    Адрес: 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,

    Адрес: 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,

    Адрес: 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,

    Адрес: 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,

    Адрес: 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,

    Теперь обратите внимание, что только нечётные адреса вернули данные, кроме 0x05?
    Это потому, что 0x05 — это адрес пурпурного картриджа, которого у меня, к сожалению, нет :(

  • Подпрограммы эмуляции
    Теперь самое интересное!

    Мне нужно, чтобы принтер думал, что установлены четыре чернильных картриджа фокусированный ионный пучок fib цена, для этого нам нужно сначала реализовать некоторые функции эмуляции. Опять же, на основе предыдущих знаний я предопределил их в заголовочном файле:

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

    epsnCartReady — это макрос, который используется для проверки, установлен ли RST высоко.
    epsnCartGetAddr возвращает адрес, который запрашивает печатающая головка.
    epsnCartOut используется для отправки данных ведущему контроллеру.
    epsnCartIn используется для получения данных от ведущего, когда он выполняет запись.

    Итак, на этот раз вместо управления SCK для перехода в высокое или низкое состояние нам нужно ждать его перехода в высокое или низкое состояние, но если сброс переходит в низкое состояние, то остановить всё и вернуться:

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

    while((i<4) && _ecRST){ // Цикл, пока i < 4 и RST высок
    temp>>=1; // Сдвиг Temp вправо на один
    while((!_ecSCK) && (_ecRST)); // Ждать, пока такт перейдёт в высокое состояние
    if(_ecSDA){// только если SDA высок
    temp |= 0x08; // тогда установить 4-й бит
    }
    while((_ecSCK) && (_ecRST));// ждать, пока такт перейдёт в низкое состояние
    i++; // увеличить счётчик
    }

    if(_ecRST == 0){
    return 0xFF;//если RST стал низким, значит ведущий оборвал сигнал
    }
    return temp; //вернуть адрес и бит чтения/записи
    }

    И функция вывода:

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

    _ecSDATRIS = 0; // установить SDA как выход
    _ecSDALat = 0; // установить SDA низко

    while((i<8) && _ecRST){ // Цикл, пока i < 8 и RST высок
    while(!_ecSCK && _ecRST); // Ждать, пока SCK перейдёт в высокое состояние
    _ecSDALat = temp&0x01; // Установить SDA высоко или низко в соответствии с первым битом

    while(_ecSCK && _ecRST); // Ждать, пока SCK перейдёт в низкое состояние
    temp>>=1; // Сдвинуть данные вправо на один
    i++; // Увеличить счётчик на один
    }
    _ecSDATRIS = 1; // Установить SDA как вход
    _ecSDA = 1; // не уверен, нужно ли это
    }

    И наконец функция ввода:

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

    while((i<8) && _ecRST){ // Цикл, пока i < 8 и RST высок
    temp>>=1; // Сдвиг temp вправо на один
    while(!_ecSCK && _ecRST); // Ждать, пока SCK перейдёт в высокое состояние
    if(_ecSDA){ // только если SDA высок
    temp |= 0x80; // Установить 8-й бит
    }

    while(_ecSCK && _ecRST);// Ждать, пока SCK перейдёт в низкое состояние
    i++; // Увеличить счётчик на один
    }
    return temp; // вернуть полученное
    }

    Теперь нам нужно настроить наш микроконтроллер так, чтобы он содержал данные, которые мы извлекли. Затем позволить ведущему принтера читать и записывать их.

    Проблема в том, что я не хочу, чтобы мои фальшивые картриджи когда-либо израсходовались. Для этого мы используем фиксированный дамп, который микроконтроллер будет загружать в ОЗУ при каждом запуске. Это позволит принтеру не только читать, но и записывать в него. Когда микроконтроллер выключается и снова включается, предыдущие данные восстанавливаются. (Двойной бонус)

    Хранение массивов данных в микроконтроллере. Поместите это где-нибудь после включений, но перед void main()

    Примечание: Это может отличаться для разных семейств микроконтроллеров, но отлично работает с моим 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};

    Примечание: Заметили, что у меня нет пурпурного? Это потому, что это тот картридж, которого у меня нет.

    Следующий шаг — написать подпрограмму, которая проверяет, какой картридж запрашивается, и позволяет ведущему читать и записывать в него.
    Вот как я это сделал:

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

    While(1){

    epsnCartStartListen();

    while(epsnCartReady()==1); // Ждать, пока сигнал Ready не вернётся в низкий уровень

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

    if(addr&0x7 == 0x01){ // если первые 3 бита равны 0x01
    inkPtr = &black[0]; // Указать на данные чёрного
    }else if(addr&0x7 == 0x03){ // если первые 3 бита равны 0x03
    inkPtr = &cyan[0]; // Указать на данные голубого
    }else if(addr[i]&0x7 == 0x05){
    inkPtr = &cyan[0]; // Это должно быть пурпурное, но у меня его нет
    }else if(addr[i]&0x7 == 0x07){
    inkPtr = &yellow[0];
    }else{
    continue: // Вернуться в начало основного цикла, так как адрес неизвестен
    }

    if(addr&0x08){// Режим записи – проверить, хочет ли ведущий записать
    while(epsnCartReady()){// продолжать цикл, пока RST не станет низким
    *inkPtr = epsnCartIn();
    // данные, на которые указывает указатель
    // перезаписываются новыми данными
    inkPtr++; // Увеличить указатель
    }
    }else{// Режим чтения
    while(epsnCartReady()){
    epsnCartOut(*inkPtr);
    // Вывести данные, на которые указывает указатель
    inkPtr++; // Увеличить указатель
    }
    }
    }
    }

    Успех!
    После программирования этого нового кода и включения принтера, принтер принял 4 воображаемых картриджа благодаря моему микроконтроллеру. Я также довольно удивлён, что он принял данные голубого картриджа для пурпурного!

    Весь этот проект — отличный пример того, как обратный инжиниринг может раскрыть потенциал проприетарного оборудования. Понимая протокол связи, я фактически выполнил извлечение прошивки содержимого EEPROM, хотя данные были небольшими. В более сложной системе может потребоваться извлечь флэш-память из микроконтроллера для анализа его кода. EEPROM в этих картриджах действует как крошечное защищённое хранилище, но без какого-либо бита блокировки или шифрования считывание данных тривиально. Некоторые современные картриджи имеют механизм блокировки, предотвращающий повторное использование, но здесь единственной защитой был малоизвестный протокол. Эта неясность не является безопасностью, что я и доказал, успешно эмулируя отсутствующий картридж. Возможность дублировать идентичность картриджа позволила бы бесконечную перезаправку, что именно производители принтеров пытаются предотвратить. Они часто используют предохранители или однократно программируемые биты для маркировки картриджа как пустого, но этот EEPROM полностью перезаписываем. Теперь мой микроконтроллер действует как посредник, перехватывая запросы на чтение и выдавая сохранённые данные. Это, по сути, простая форма восстановления прошивки для принтера, поскольку я восстановил полную функциональность без оригинальной детали. Написанный мной код мал, но эффективен, и его можно адаптировать для других устройств с аналогичными последовательными EEPROM. Мне часто было интересно, оставляют ли производители принтеров эти уязвимости намеренно, чтобы разрешить использование сторонних картриджей. В любом случае, этот проект научил меня многому об аппаратных протоколах и встраиваемых системах. Используемый мной MCU, PIC18F, был более чем способен справиться с требованиями синхронизации. Фактически, я мог бы использовать меньший микроконтроллер, но PIC дал мне достаточно места для будущего расширения. Вся установка работает от 3,3 В, что соответствует внутреннему напряжению картриджа. Одной из проблем было обеспечение правильного управления линией SDA в обоих направлениях, поскольку принтер и мой MCU попеременно управляют ей. Мне пришлось тщательно управлять регистрами TRIS, чтобы избежать конфликтов на шине. Это распространённая проблема в любой системе с несколькими ведущими, но здесь только одно ведущее и эмулятор ведомого. Временные диаграммы из патента были бесценны; они дали мне точные соотношения фронтов тактов. Без них я бы потратил дни на догадки. Этот опыт подчёркивает важность документации, даже если она скрыта в патентах. Я также узнал, что иногда самое простое решение работает лучше всего — просто хранить дамп в ОЗУ и обновлять его при включении питания. Это гарантирует, что уровень чернил никогда не уменьшается, что является приятным бонусом. Однако для реального продукта мне нужно было бы учитывать выравнивание износа и защиту от потери питания. Но для любительского проекта это идеально. Теперь я уверен, что смогу справиться с более сложными задачами обратного инжиниринга в будущем. Следующим шагом может быть перехват связи между принтером и драйверами двигателей печатающей головки. Это позволило бы мне точно управлять XY-перемещением для моего 3D-принтера. Но это уже история для другой инструкции. Сейчас я очень рад, что моя эмуляция работает безупречно. Я даже протестировал её с несколькими циклами включения/выключения, и данные сохраняются каждый раз. Массив ОЗУ переинициализируется с жестко заданными значениями при каждой загрузке, поэтому картридж всегда выглядит как новый. Принтер никогда не жалуется на контрафактные картриджи, потому что данные являются точной копией оригинальных. Это, по сути, дублирование идентичности оригинального картриджа. В коммерческой среде такая техника могла бы использоваться для неавторизованного клонирования, но здесь она используется для легитимного перепрофилирования. Я осторожен и использую её только для своих собственных проектов. Знания, полученные в ходе этого упражнения, применимы ко многим другим потребительским электронным устройствам, использующим простые последовательные памяти. Многие устройства имеют аналогичные EEPROM, хранящие калибровочные данные или серийные номера. Считывая их, можно создать резервную копию и восстановить критически важную информацию. Это также форма извлечения прошивки, даже если прошивка — это просто конфигурационные данные. Я видел проекты, где люди расшифровывали прошивку умных счётчиков с помощью аналогичных методов. Но там используется гораздо более сложная криптография и часто бит блокировки для предотвращения считывания. Здесь такой блокировки нет, так что всё открыто. Некоторые могут утверждать, что это недостаток безопасности, но для меня это возможность. Я уже начал планировать версию, использующую меньший ATtiny для экономии места. Размер кода крошечный, поэтому он может поместиться в 8-выводном корпусе. Возможно, я даже добавлю возможность имитации разных типов картриджей с помощью DIP-переключателя. Это было бы удобно для тестирования различных чернил. Возможности безграничны. Я также рассматриваю возможность публикации моего кода на GitHub для адаптации другими. Такой открытый подход поощряет сотрудничество и инновации. Многие хакеры уже делали подобное с другими брендами принтеров. Сообщество очень активно в обратном инжиниринге расходных материалов, чтобы уменьшить отходы и сэкономить деньги. Это беспроигрышная ситуация для окружающей среды и пользователя. Я надеюсь, что моя инструкция вдохновит других заглянуть под капот своих собственных устройств. С логическим анализатором и каплей терпения можно раскрыть скрытые протоколы. Ключ в том, чтобы начинать с малого, как я сделал с этой простой EEPROM. Освоив основы, можно переходить к более сложным целям. Я с нетерпением жду дня, когда смогу печатать на своём переделанном принтере в 3D. Это только первая веха. Следующий большой шаг — подключить драйверы печатающей головки и построить механическую раму. Но это проект для другого сезона. Сейчас я наслаждаюсь этой победой. Это реальное доказательство того, что обратный инжиниринг — это не только для хакеров; это ценный навык для любого инженера. Понимая, как вещи работают на самом низком уровне, вы можете по-настоящему сделать их своими. Это дух созидания и экспериментов. Так что вперёд, возьмите старый принтер и начните зондировать. Вы будете удивлены тому, чего можете достичь. И помните, всегда документируйте свои находки, чтобы другие могли учиться на вашем опыте. Именно так наше сообщество растёт и развивается. На этом я завершу этот раздел. Наслаждайтесь остальной частью инструкции и удачного хакерства!

  • Общие вопросы об извлечении прошивки микроконтроллеров


    • Безопасно ли отправлять оплату в MikaTech?

      Если бы MikaTech была недобросовестной компанией, вы бы нашли множество негативных отзывов о её услугах в интернете за 28-летнюю историю

      Итак, ответ — ДА! Мы хорошие люди.

      Почему выбирают Mikatech, пожалуйста, нажмите здесь, чтобы узнать


    • Может ли Mikatech взламывать микросхемы, не указанные на этом сайте?

      У разных производителей микросхем разные номера деталей, но внутреннее ядро микросхемы может быть изготовлено по одной и той же технологии, поэтому было бы совершенно невозможно перечислить все номера деталей, к которым применима наша технология, такие как MYSON, STK, FEELING, ANALOG, FUJITSU, NOVATEK, LG/HYNDAI.

      Кроме того, с развитием технологий мы каждый день получаем всё больше опыта и разрабатываем новые методы обратной разработки для различных типов интегральных схем. Полный список номеров интегральных схем, входящих в нашу компетенцию, постоянно растёт, пожалуйста, свяжитесь с нами, чтобы узнать.

    • Будет ли моя конфиденциальность защищена?

      Mikatech Innovative Limited понимает важность конфиденциальности своих клиентов. В момент обращения в Mikatech ваша личная информация попадает под защиту наших управленческих регламентов, разработанных на основе многолетней практики. Mikatech использует эту информацию для настройки своих услуг под вас и никогда не раскрывает её третьим лицам по каким-либо причинам.
      По каждому проекту мы удаляем все данные, материалы и коды через 60 дней после передачи файлов — это защищает нас и защищает вашу конфиденциальность.

    • Законно ли получать услуги от Mikatech?

      Да, это абсолютно законно.
      Mikatech предоставляет свои услуги по обратной разработке исключительно в образовательных целях. Использование вышеуказанных услуг может быть незаконным в некоторых странах или регионах, пожалуйста, проверьте местные законы. Mikatech не несёт никакой ответственности в связи с использованием вышеуказанных услуг, которое может считаться незаконным.


    • Я отправил вам письмо, почему нет ответа?

      • A. Наш почтовый сервер временно вышел из строя, ваше сообщение не было доставлено в наш почтовый ящик, даже если на экране отображается сообщение об успешной отправке, пожалуйста, свяжитесь с нами снова.
      • B. Наше письмо распознаётся вашим почтовым сервером как спам, поэтому наш ответ был отклонён вашим почтовым сервером или перенаправлен в папку со спамом. Пожалуйста, удалите наш аккаунт из списка спама или проверьте папку со спамом, либо используйте другой адрес электронной почты для связи, например Gmail.
      • C. Ваше письмо распознаётся нашим почтовым сервером как спам, поэтому оно было помещено в нашу папку со спамом. Пожалуйста, используйте другой адрес электронной почты для связи с нами.



      Услуги по взлому MCU


      время взлома микроконтроллера

      Лет

      28 +
      страны взлома микроконтроллеров

      Стран

      110 +
      клиенты по атакам на микроконтроллеры

      Клиентов

      5000 +
      разблокированные проекты микроконтроллеров

      Проектов

      60000 +