USB-Tastaturzustände auslesen: Ein Low-Level Linux-Abenteuer

Den Zustand aller Tasten auf einer USB-Tastatur auslesen: Ein Low-Level-Linux-Abenteuer
Haben Sie sich jemals gefragt, was unter der Haube passiert, wenn Sie eine Taste auf Ihrer USB-Tastatur drücken? Was wäre, wenn Sie einen Blick auf die Rohdaten werfen könnten, die von der Tastatur an Ihren Computer gesendet werden? In diesem Blogbeitrag tauchen wir tief in die Welt der USB-HID-Protokolle (Human Interface Device) ein und schreiben ein Low-Level-Linux-Programm, um den aktuellen Zustand aller Tasten auf einer USB-Tastatur auszulesen. Keine High-Level-Abstraktionen – nur direkter, ungefilterter Zugriff auf die Hardware.
Das Problem: Den Tastaturzustand ohne Ereignisse auslesen
Wenn Sie eine Taste auf Ihrer Tastatur drücken, verarbeitet das Betriebssystem dies als Ereignis. Diese Ereignisse sind für die meisten Anwendungen praktisch, aber was, wenn Sie den aktuellen Zustand aller Tasten wissen möchten – nicht nur derjenigen, die Ereignisse ausgelöst haben? Zum Beispiel:
- Welche Tasten sind gerade gedrückt?
- Was ist der Zustand der Modifikatortasten (Shift, Strg, Alt)?
- Wie sieht es mit den LED-Zuständen aus (Feststelltaste, Num-Taste, Rollen-Taste)?
Dies ist eine häufige Herausforderung für:
- Sicherheitsforscher, die Tastatureingaben analysieren.
- Embedded-Entwickler, die USB-Geräte debuggen.
- Neugierige Hacker, die verstehen möchten, wie USB-Tastaturen funktionieren.
Aber es gibt einen Haken: Wenn eine Taste gedrückt wurde, während das System ausgeschaltet war, generiert der Linux-Kernel kein Ereignis, es sei denn, eine andere Taste wird gedrückt. Das bedeutet, dass Sie sich nicht auf das Eingabesubsystem des Kernels verlassen können, um Tasten zu erkennen, die vor dem Systemstart gedrückt wurden. Um dies zu lösen, müssen wir das High-Level-Eingabesubsystem umgehen und direkt mit der USB-Tastatur auf der niedrigsten möglichen Ebene interagieren.
Die Lösung: Verwendung von `libusb` zur Abfrage der Tastatur
Wir verwenden die libusb
-Bibliothek, um direkt mit der USB-Tastatur zu interagieren. Hier ist, was wir tun werden:
- Alle USB-Geräte auflisten, um Tastaturen zu finden.
- HID-Schnittstellen auf diesen Geräten identifizieren.
- Eine
HID GET_REPORT
-Anfrage senden, um den aktuellen Eingabebericht (Tastenzustände) abzurufen. - Den Eingabebericht decodieren, um festzustellen, welche Tasten gedrückt sind.
Der Code: Den Tastenzustand auslesen
Unten finden Sie das C-Programm, das die ganze Arbeit erledigt. Es verwendet libusb
, um mit USB-Geräten zu interagieren und den Eingabebericht für alle angeschlossenen Tastaturen abzurufen.
#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
// HID GET_REPORT-Anfrage
#define HID_GET_REPORT 0x01
#define HID_REPORT_TYPE_INPUT 0x01
// Funktion, um zu überprüfen, ob ein Gerät eine HID-Tastatur ist
int is_hid_keyboard(libusb_device *device) {
struct libusb_device_descriptor desc;
int ret = libusb_get_device_descriptor(device, &desc);
if (ret < 0) {
fprintf(stderr, "Fehler beim Abrufen des Geräte-Deskriptors\n");
return 0;
}
// Überprüfen, ob das Gerät ein HID-Gerät ist
if (desc.bDeviceClass == LIBUSB_CLASS_PER_INTERFACE) {
struct libusb_config_descriptor *config;
ret = libusb_get_config_descriptor(device, 0, &config);
if (ret < 0) {
fprintf(stderr, "Fehler beim Abrufen des Konfigurations-Deskriptors\n");
return 0;
}
for (int i = 0; i < config->bNumInterfaces; i++) {
const struct libusb_interface *interface = &config->interface[i];
for (int j = 0; j < interface->num_altsetting; j++) {
const struct libusb_interface_descriptor *iface_desc = &interface->altsetting[j];
if (iface_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
libusb_free_config_descriptor(config);
return 1; // Dies ist ein HID-Gerät
}
}
}
libusb_free_config_descriptor(config);
}
return 0; // Kein HID-Gerät
}
// Funktion, um den Eingabebericht von einer HID-Tastatur abzurufen
void get_input_report(libusb_device_handle *handle) {
unsigned char input_report[8]; // Die meisten Tastaturen verwenden 8-Byte-Eingabeberichte
int ret = libusb_control_transfer(
handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
HID_GET_REPORT,
(HID_REPORT_TYPE_INPUT << 8) | 0x00, // Berichtstyp (Eingabe) und Berichts-ID (0)
0, // Schnittstelle
input_report,
sizeof(input_report),
1000 // Timeout in Millisekunden
);
if (ret < 0) {
fprintf(stderr, "Fehler beim Abrufen des Eingabeberichts: %s\n", libusb_error_name(ret));
} else {
printf("Eingabebericht:\n");
for (int i = 0; i < ret; i++) {
printf("%02x ", input_report[i]);
}
printf("\n");
}
}
int main() {
libusb_device **devices;
ssize_t count;
int ret;
// libusb initialisieren
ret = libusb_init(NULL);
if (ret < 0) {
fprintf(stderr, "Fehler beim Initialisieren von libusb: %s\n", libusb_error_name(ret));
return 1;
}
// Liste der USB-Geräte abrufen
count = libusb_get_device_list(NULL, &devices);
if (count < 0) {
fprintf(stderr, "Fehler beim Abrufen der Geräteliste: %s\n", libusb_error_name((int)count));
libusb_exit(NULL);
return 1;
}
// Alle Geräte durchlaufen
for (ssize_t i = 0; i < count; i++) {
libusb_device *device = devices[i];
// Überprüfen, ob das Gerät eine HID-Tastatur ist
if (is_hid_keyboard(device)) {
struct libusb_device_descriptor desc;
ret = libusb_get_device_descriptor(device, &desc);
if (ret < 0) {
fprintf(stderr, "Fehler beim Abrufen des Geräte-Deskriptors\n");
continue;
}
printf("HID-Tastatur gefunden: %04x:%04x\n", desc.idVendor, desc.idProduct);
// Gerät öffnen
libusb_device_handle *handle;
ret = libusb_open(device, &handle);
if (ret < 0) {
fprintf(stderr, "Fehler beim Öffnen des Geräts: %s\n", libusb_error_name(ret));
continue;
}
// Kernel-Treiber abkoppeln (falls angeschlossen)
if (libusb_kernel_driver_active(handle, 0) == 1) {
ret = libusb_detach_kernel_driver(handle, 0);
if (ret < 0) {
fprintf(stderr, "Fehler beim Abkoppeln des Kernel-Treibers: %s\n", libusb_error_name(ret));
libusb_close(handle);
continue;
}
}
// Schnittstelle beanspruchen
ret = libusb_claim_interface(handle, 0);
if (ret < 0) {
fprintf(stderr, "Fehler beim Beanspruchen der Schnittstelle: %s\n", libusb_error_name(ret));
libusb_close(handle);
continue;
}
// Eingabebericht abrufen
get_input_report(handle);
// Schnittstelle freigeben
libusb_release_interface(handle, 0);
// Kernel-Treiber wieder ankoppeln (falls abgekoppelt)
libusb_attach_kernel_driver(handle, 0);
// Gerät schließen
libusb_close(handle);
}
}
// Geräteliste freigeben
libusb_free_device_list(devices, 1);
// libusb aufräumen
libusb_exit(NULL);
return 0;
}
Wie es funktioniert
-
Geräte-Enumeration:
- Das Programm listet alle USB-Geräte auf und identifiziert HID-Tastaturen, indem es deren Schnittstellenklasse überprüft.
-
Öffnen des Geräts:
- Für jede HID-Tastatur öffnet das Programm das Gerät und koppelt den Kernel-Treiber ab (falls notwendig).
-
Beanspruchen der Schnittstelle:
- Das Programm beansprucht die HID-Schnittstelle, um direkt mit dem Gerät zu kommunizieren.
-
Senden der `HID GET_REPORT`-Anfrage:
- Das Programm sendet eine `GET_REPORT`-Anfrage, um den Eingabebericht abzurufen, der den aktuellen Zustand aller Tasten enthält.
-
Decodieren des Eingabeberichts:
- Der Eingabebericht wird im Hexadezimalformat ausgegeben. Jedes Byte entspricht einer bestimmten Taste oder einem Modifikator.
Das Programm ausführen
- Installieren Sie
libusb
:
sudo apt install libusb-1.0-0-dev
- Kompilieren Sie das Programm:
gcc -o dump_keys dump_keys.c -lusb-1.0
- Führen Sie das Programm mit Root-Rechten aus:
sudo ./dump_keys
Beispielausgabe
Für eine Tastatur, bei der die F9-Taste gedrückt ist, könnte die Ausgabe so aussehen:
HID-Tastatur gefunden: 046d:c31c
Eingabebericht:
00 00 42 00 00 00 00 00
Das bedeutet:
- Keine Modifikatortasten sind gedrückt (`00`).
- Die F9-Taste ist gedrückt (`42`).
- Keine anderen Tasten sind gedrückt (`00 00 00 00 00`).
Warum das wichtig ist
Dieser Low-Level-Ansatz gibt Ihnen die vollständige Kontrolle über die USB-Tastatur und ermöglicht es Ihnen:
- USB-Geräte zu debuggen.
- Tastatureingaben für Sicherheitsforschung zu analysieren.
- Benutzerdefinierte Tastatur-Firmware oder Treiber zu erstellen.
Nächste Schritte
- Experimentieren Sie mit verschiedenen Tastaturen und beobachten Sie deren Eingabeberichte.
- Erweitern Sie das Programm, um LED-Zustände zu decodieren oder mehrere Tastaturen gleichzeitig zu handhaben.
- Tauchen Sie tiefer in die USB-HID-Spezifikation ein, um komplexere Geräte zu verstehen.
Viel Spaß beim Hacken! Lassen Sie uns wissen, wenn Sie Fragen haben oder weitere Hilfe benötigen. 🚀