Пишем прошивку для старого пин-пада

Приветствую всех!
Многие из нас уже знают, что POS-terminal’ы и пин-пады обычно собираются на базе заказных чипов, даташиты на которые не найти. Но, понятное дело, так было далеко не всегда. И мне стало интересно:, а что, если попробовать найти такой древний терминал, отреверсить его схему и написать что-то под него, не имея ни SDK, ни документации?

vnlnrv9y0xbznfzotrr5ahkekuo.jpeg

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

Суть такова


Когда-то давно я уже писал пост про то, как работают пин-пады и что у них внутри.

i85jdo9dfte-e7gspdqlpyditro.jpeg

Если разобрать типичный пин-пад, выпущенный после середины двухтысячных, то, скорее всего, все микросхемы внутри будут проприетарными. А это значит, что информация о них доступна, наверное, только самим разработчикам терминалов.
Но в лучшие годы всё было совершенно иначе. А как оно было, сейчас и будем разбираться.

Обзор оборудования


5ddyl5hek7pnfucg2xo9pruqpsg.jpeg

Так получилось, что в мои руки попал пин-пад Hypercom HFT106. Девайс очень старый, начала двухтысячных годов. По виду он тоже сильно отличается от привычных нам, напоминая то ли калькулятор, то ли какой-то сервисный прибор. Слот для смарт-карт расположен в задней части, карта вставляется вертикально.

1f4wi1vzukrnt5jftesz8c2omhm.jpeg

Обратная сторона. Тут ничего интересного, только порт 6P6C.

vlucgrjvoiwh1cqzrjzmdqoqae4.jpeg

А вот и пример терминала, к которому такой девайс подключался. Это Hypercom T7PS, древний аппарат на процессоре Z80. Но про этот экземпляр поговорим как-нибудь потом.

Внутренности


Само собой, чтобы узнать, на чём он собран, девайс надо разобрать.

2cugaoxzjzgsw6cbnzql6m4u_ge.jpeg

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

efzfzaq_cyd1uzl5s9zdd5rifge.jpeg

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

h3719zlvaoazvbrougkar73rwmu.jpeg

Дисплей, обычный 1602.

dwbuc_qje86cgsahmmylzc88qhy.jpeg

pxqc-ebhnsdqg0gz93djulnoywo.jpeg

Модуль считывателя карт. В одном из разъёмов находилась SAM-карта, второй оказался пуст. Интересно, зачем он вообще, в залитом-то корпусе… На этой же плате находится концевик тампера.

exk78ox1bue8gex5o4xdsr8xjve.jpeg

SAM-карта. Обратная сторона маркировки не имела.

Что же внутри этого пин-пада?


Само собой, вопрос о том, на базе чего собрано данное устройство, так и остался открытым. Пришлось гуглить. На форуме nedoPC кто-то уже разбирал подобный терминал. Модель, правда, была другой, HFT105. После нескольких часов ковыряния эпоксидки и изучения фотографий платы было выяснено, что HFT106 является по сути более защищённым аналогом HFT105. По схемотехнике они абсолютно идентичны.

e-k2p5gdliioa0a0ea9nsnn4mpe.jpeg

Плата терминала HFT105 крупным планом.

DS5002FP


Итак, пин-пад оказался собран на базе защищённого микроконтроллера от Dallas. Штука эта весьма интересная — по сути это 8051-совместимый МК, специально разработанный для подобных применений. У этого контроллера нет пользовательского ПЗУ, вся программа загружается в SRAM.

43hxh5neddxjdcdjvky_1-m7pri.png

Вот его структурная схема. Видно, что для работы с внешней памятью все данные на шине тоже зашифрованы, а также обфусцированы (периодически МК читает из памяти случайные значения для защиты от сканирования шины логическим анализатором). Также имеется аппаратный вход тампера (Self-Destruct input), при активации которого сбрасываются ключи и векторы прерываний.

Для защиты от реверс-инжиниринга существовали доступные под заказ ещё более защищённые версии этого чипа, обладающие контуром безопасности прямо на кристалле, который защищает чип от вскрытия и исследований электронным микроскопом. В качестве алгоритма шифрования используется DES с ключом длиной в 64 бита, также по усмотрению заказчика мог быть предусмотрен проприетарный алгоритм шифрования. МК оборудован аппаратным генератором случайных чисел (если верить даташиту, принцип основан на девиациях частоты кварца и внутреннего генератора, которые измеряются контроллером), использующимся для генерации ключей.

7i2xaap6avgnsc3ubctnnwqasbi.png

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

Софт


Итак, для того, чтобы написать какую-то прошивку, необходим SDK. Стандартный набор — библиотеки, компилятор и загрузчик.

qqhtjy5d98f4yxvsdaycgs-adx0.png


SDK для столь экзотического контроллера без проблем можно найти: он имеется в составе Keil для МК MCS-51. Скачиваем Keil, открываем Device Database и устанавливаем поддержку для этого МК.

Теперь очередь заливки софта в контроллер. И тут всё весьма интересно: никакой программатор для этого не понадобится.

MTK2


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

f0nb5hzf3bcleykjng7qn61gh3u.jpeg

Если отковырять одну из резиновых ножек, то можно увидеть там вырез, где скрываются два торчащих из смолы штырька. Один из них — земля, другой — PROG. Если их замкнуть, то при подаче питания будет запущен расположенный в масочном ПЗУ загрузчик, задача которого — поместить пришедшую по UART программу в SRAM. Перемычка на эти штырьки не налезала, поэтому я просто запихал туда фольгу от обёртки жвачки.

mrlxisajtascrbppsvepjglahco.png


Теперь очередь софта для прошивки. Есть такая утилита как Dallas Microcontroller Toolkit (MTK2). Она предназначена для заливки HEX-файла с программой в целый модельный ряд МК от Dallas. Среди всех прочих есть и наш экземпляр.

Подключение


Пин-пад подключается к терминалу по интерфейсу RS-422. Внутри он реализован на базе двух трансиверов RS-485, один из которых включён всегда на приём, а другой — на передачу.

nheqzubugh3kjyj3pecvpc-m-ew.jpeg

Само собой, чтобы подключить девайс к компьютеру, необходимо спаять переходник. Схема его в моём случае вышла такая:

h-t0idh5khtvipi_s_whsnyaizo.png

Так получилось, что месяцем ранее я разобрал другой терминал — Hypercom Optimum T4220. Именно из его интерфейсного модуля и были позаимствованы все нужные компоненты — микросхема, разъём 6P6C и кабель от пин-пада. В принципе, ничто не мешает использовать два трансивера RS-485, как это реализовано в пин-паде.

Схемы девайса с форума nedoPC. Скопировал сюда на всякий случай

Первый запуск


Итак, подключаем девайс к компьютеру. В качестве преобразователя USB-UART выступила традиционно Arduino. Замыкаем контакты и подаём питание.

rzzrm7iqseuzax24735vwkjvx9q.jpeg


Теперь открываем MTK2 и пытаемся установить соединение с загрузчиком. И оно работает!
Само собой, если подать питание просто так, то ничего не будет — из-за севшей батарейки оригинальная прошивка давно утрачена.

Загрузчик


hvlh4wooartyxqolm6lzfp0zs0q.png

Если открыть список команд, то можно заметить, что среди них есть возможность прямо из загрузчика управлять портами. Для проверки попробуем завести пищалку. При помощи команды P выставляем высокий уровень на соответствующей ножке, и терминал начинает непрерывно пищать. Ну что же, схема нас не обманула, HFT106 действительно во многом близок к HFT105.

Официальный порядок загрузки прошивки такой:

  1. F. Затереть SRAM.
  2. L. Залить HEX.
  3. D. Прочитать память.
  4. V. Проверить правильность записи.
  5. C. Сверить CRC.


В ходе выполнения этих операций происходит очистка памяти, после чего ГСЧ генерирует ключ (он является неизвлекаемым и недоступен для чтения), которым шифруется прошивка. Если выполнение программы загрузчика при этом не было прервано (то есть если не была выполнена команда E или если МК не был сброшен), то возможно и чтение содержимого ОЗУ, что используется для верификации.

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

Пишем первую программу


Ну что же, время написать что-то под этот девайс. Начнём, конечно, с классического микроконтроллерного «Hello, world!» — с вывода текста на экран.
Дисплей здесь работает в восьмибитном режиме, все его линии данных подключены к порту P2. Для управляющих линий отведён P3. Итак, тестовая прога получилась вот такая:

#include                 /* special function register declarations   */
                                  /* for the intended 8051 derivative         */
#include                 /* prototype declarations for I/O functions */


#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */
char code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */
#endif                                   /* Stop Exection with Serial Intr.   */
                                         /* is enabled                        */

/*------------------------------------------------
The main C function.  Program execution starts
here after stack initialization.
------------------------------------------------*/
void delay(void) {
unsigned long n;
	for(n = 0; n < 100; n++);;
}

void lcdSend(int isCommand, unsigned char toLCD) {
	P3 &= ~(1 << 7);
    if(isCommand == 0) P3 |= (1 << 6);
	else if(isCommand == 1) P3 &= ~(1 << 6);
    delay();
	P2 = toLCD;
	P3 |= (1 << 5);
	delay();
	P3 &= ~(1 << 5);
	delay();
}
void lcdCommand(unsigned char cmd) {
    lcdSend(1, cmd);
}

void lcdChar(const char chr) {
    lcdSend(0, chr);
}

void lcdString(const char* str) {
    while(*str != '\0') {
        lcdChar(*str);
        str++;
    }
}
void main (void) {
/*------------------------------------------------
Setup the serial port for 1200 baud at 16MHz.
------------------------------------------------*/
#ifndef MONITOR51
    SCON  = 0x50;		        /* SCON: mode 1, 8-bit UART, enable rcvr      */
    TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
    TH1   = 221;                /* TH1:  reload value for 1200 baud @ 16MHz   */
    TR1   = 1;                  /* TR1:  timer 1 run                          */
    TI    = 1;                  /* TI:   set TI to send first char of UART    */
#endif

   lcdCommand(0x38);
   lcdCommand(0x01);
   lcdCommand(0x06);
   lcdCommand(0x0C);
   lcdCommand(0x80); 
   lcdString("Hello, Habr!");
	while(1);;
}



Инициализация дисплея абсолютно стандартная, подробно расписывать её не вижу смысла.
Собираем проект и в папке с ним получаем *.hex-файл с готовой прошивкой.

xer57a1reb5bcn6hu0uhyrddyy8.jpeg


Теперь открываем MTK2, выбираем в меню «Load SRAM», выбираем нашу прошивку. По окончании загрузки отправляем команду E.
И, если всё было успешно, на экране загорится примерно следующее:

axpex49rifxouxue4sqegzykn1w.jpeg


Ну что же, всё успешно.

Клавиатура


Ну, где дисплей, там и клавиатура. Схемы считывателя смарт-карт у меня нет, так что это единственная периферия, которую ещё можно запустить. И программа оказалась такой:

#include                 /* special function register declarations   */
                                  /* for the intended 8051 derivative         */
#include                 /* prototype declarations for I/O functions */

#ifdef MONITOR51                         /* Debugging with Monitor-51 needs   */
char code reserve [3] _at_ 0x23;         /* space for serial interrupt if     */
#endif                                   /* Stop Exection with Serial Intr.   */
                                         /* is enabled                        */

/*------------------------------------------------
The main C function.  Program execution starts
here after stack initialization.
------------------------------------------------*/
void delay(void) {
unsigned long n;
	for(n = 0; n < 100; n++);;
}
char s[16];
char symbols[4][4] = {{'E', '0', 'R', 'C'},
   	              {'9', '8', '7', 'B'},
		      {'6', '5', '4', 'A'},
		      {'3', '2', '1', 'Z'}};
char symbolsP0[4] =  {'L', 'K', 'J', 'I'};
void lcdSend(int isCommand, unsigned char toLCD) {
	P3 &= ~(1 << 7);
    if(isCommand == 0) P3 |= (1 << 6);
	else if(isCommand == 1) P3 &= ~(1 << 6);
    delay();
	P2 = toLCD;
	P3 |= (1 << 5);
	delay();
	P3 &= ~(1 << 5);
	delay();
}
void lcdCommand(unsigned char cmd) {
    lcdSend(1, cmd);
}

void lcdChar(const char chr) {
    lcdSend(0, chr);
}

void lcdString(const char* str) {
   while(*str != '\0') { //*str != '\0'
        lcdChar(*str);
        str++;
    }
}
void main (void) {
   int n1, i, j, k;  
   lcdCommand(0x38);
   lcdCommand(0x01);
   lcdCommand(0x06);
   lcdCommand(0x0C);
	while(1) {
		P1 = 0x0F;
		P0 |= (1 << 7);
		for(i = 4; i < 8; i++) {
		for(j = 4; j < 8; j++) P1 |= (1 << j);
		P1 &= ~(1 << i);
		for(k = 0; k < 4; k++) {
			if(((P1 >> k) & 1) == 0 ) {
				P3 &= ~(1 << 4);
				n1 = P1;
				sprintf(s, "%X", n1);
				lcdCommand(0x80); 
				lcdString("Scanc0de: ");
				lcdString(s);
				lcdCommand(0xC0);
				lcdString("Key: ");
				lcdChar(symbols[i-4][k]);
				for(j = 0; j < 30; j++)	delay();
			}
			else {
				P3 |= (1 << 4);
			}
		}
	}
		P0 &= ~(1 << 7);
		for(i = 0; i < 4; i++) {
			if(((P1 >> i) & 1) == 0 ) {
				P3 &= ~(1 << 4);
				n1 = P1;
				sprintf(s, "%X", n1);
				lcdCommand(0x80); 
				lcdString("Scanc0de: ");
				lcdString(s);
				lcdCommand(0xC0);
				lcdString("Key: ");
				lcdChar(symbolsP0[i]);
				for(j = 0; j < 30; j++)	delay();
			}
			else {
				P3 |= (1 << 4);
			}
	}
}
}


Запускаем, и вот результат:

wthb0wiev9ae17hr3isfzxava9w.jpeg

А что же насчёт банковских функций?


Увы, у меня нет никакого софта или документации на пин-пады или терминалы Hypercom. Пожалуй, по этим терминалам информации в интернете меньше всего.
Что же до платёжных функций (хранения ключей, работы с картами), то аппаратной их поддержки в микроконтроллере нет. DS5002FP был чипом общего назначения (и предназначался, к слову, не только для платёжных терминалов, но и для тех областей, где была нужна защита от реверс-инжиниринга), так что всё было реализовано средствами почившей прошивки.

n1aqzjqgct8mpclj9qtvbx2_vdo.png

Из других терминалов, работавших на базе такого чипа, мне известен Castles CIT7000, для которого я даже смог найти SDK. Увы, самой железки у меня нет.

Вот как-то так


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

Ссылки



Возможно, захочется почитать и это:
b5pjofdoxth14ro-rjsrn7sbmiy.png

© Habrahabr.ru