MCP2221 mit C# – aber schnell.

Nachdem die Python-Lib ganz gut funktioniert (ein paar Bugs habe ich bereits gefunden, Fixes stehen noch aus), wollte ich die Implementierung auch in C# umsetzen. Zwar gibt es von Microchip schon eine Lib, allerdings ist diese nicht Native und auch nicht open source und dadurch auf bestimmte .NET-Versionen eingeschränkt.

Um das Rad nicht neu erfinden zu müssen, wollte ich zumindest für die USB-HID-Kommunikation eine fertige Bibliothek verwenden. Bei der Suche bin ich auf HidLibrary gestoßen, die zwar nicht mehr so aktiv gepflegt wird – aber das muss nicht unbedingt viel bedeuten. Ja, auch Software kann mal fertig sein 😉

Heruntergeladen und die ersten Funktionsblöcke geschrieben. Als ersten Test habe ich i2c_detect portiert und laufen lassen. Für 127 Adressen dauert der Scan knapp über 17 Sekunden. Mit Microships MCP2221 I2C/SMBus Terminal sind es nicht ganz 11 Sekunden und mit meiner Python-Lib unter 0,7 Sekunden. Was ist da los?

Im ersten Schritt habe ich mit System.Diagnostics.Stopwatch die Schreib und Lesezeiten gemessen – jeweils braucht die Lib im Schnitt 21 ms, für jeden Probe einer Adresse sind zwei Schreib-/Lesezyklen erforderlich, kommt kein ACK für eine Adresse ist ein weiterer Zyklus für ein i2c_cancel erforderlich. Macht für einen Proben einer nicht genutzten Adresse ca. 126 ms, für 127 Adressen sind das bisschen über 16 Sekunden – kommt also hin.

Visual Studio kann Performance-Analysen und der schuldige ist schnell gefunden:

Es hängt also am HidLibrary.HidDevice::IsConnected bzw. EnumerateDevices.

Auf GitHub gibt es (Stand November 2018) auch Bugs zum Thema Performance.

Die Tickets existieren seit 2011, 2014 und 2016 – also besteht offenbar kein Interesse, das zu fixen. Ein User namens kaczart hat eine Lösung gefunden.

Um im ersten Schritt nicht zu viel zu verbasteln, habe ich einfach mal „IsConnected“ ein einstweiliges „return true;“ verpasst. Nun benötigt ein Schreibvorgang um die 3,4 ms und ein Lesevorgang knapp 2,3 ms. Unterm Strich dauert der Scan nun 2,5 Sekunden. Besser aber noch nicht gut genug.

In anderen „Projekten“ hat mir in Sachen Timing gerne mal der Debugger in die Suppe gespuckt, also mal als Release ausgeführt und Tadaa: 0,78 Sekunden. Fast so schnell wie die Python-Implementierung.

Um es nochmal genau zu wissen habe das „return true;“ aus HidDevice::IsConnected wieder entfernt und als Release ausgeführt: 14 Sekunden.

Der Hund liegt also definitiv in der Lib begraben. Workaround, Fixen, nach Alternativen suchen oder selber machen (oder einfach eine Weile abhängen lassen und etwas anderes machen)?

Mal sehen.

Was der MCP2221 sonst noch kann

Es gibt Dinge, die Zeit verschwenden, nicht richtig funktionieren und schlussendlich nicht einmal einen Sinn ergeben. Manche nennen das sogar Hobby.

Nachdem mir im Zuge der MCP-USB-Bridges keine Python-Implementierung so richtig gefallen habe, bin ich gerade dabei, selbst eine zu schreiben und mehr oder weniger ausgiebig zu testen.

GPIOs, ADC funktionieren so wie es aussieht genz gut, heute war der DAC dran.
So richtig toll ist er nicht, aber besser als nichts. Um Seine Leidensfähigkeit zu zeigen, musste ein kleines Beispiel her.

Warum nicht einfach so etwas ähnliches wie einen Hellschreiber implementieren? Nur halt extrem ranzig.

In Python geht das ordentlich schnell und einfach:

txt = "Hallo Welt!"

vals = [22,20,18,16,14,12,10,8]

meh = []
for c in txt:
    meh.extend(font[ord(c)-32])
    meh += [0]

for col in meh:
    for reps in range(4):
        curcol = col
        for y in range(8):
            if curcol & 1 == 1:
                dev.dac_setvalue(vals[y])
            else:
                dev.dac_setvalue(0)
            curcol >>= 1
            time.sleep(0.003)

Die Font liegt in als Liste vor, die alle wichtigen Zeichen ab dem Leerzeichen enthält. Vals beinhaltet die Analogwerte der jeweiligen Bits der Zeichen (in der Höhe). Der Text wird sprichwörtlich in eine Bitmap umgewandelt und einfach über den DAC rausgejagt. Damit die Zeichen etwas besser lesbar sind, werden sie 4 mal wiederholt. Die kurze Pause ist nötig, weil sich sonst der MCP verhaspelt.


Ist das nun Kunst oder kann das weg? 😉

BadUSB gone worse!?

Vor zwei Jahren präsentierte Karsten Nohl auf der Black Hat seinen Vortrag über BadUSB. Auf dem Chaos Communication Congress danach wurden, wenn ich mich richtig erinnere, USB-Sticks verteilt, deren Firmware sich einfach anpassen lässt. Von konkreten Angriffen habe ich bis jetzt von nichts gehört, trotzdem ist die „Bedrohung“ durchaus real.

USB macht seinem Namen alle Ehre – der Anschluss ist extrem universell und den Geräten sieht man nicht an, als was sie sich gegenüber dem PC anmelden. Dazu kommt, dass jedes Device nicht auf eine Funktion beschränkt ist, was grundsätzlich nichts böses ist und in manchen Fällen sogar zwingend erforderlich ist. Hier fängt aber auch das Problem an: Ein USB-Stick kann neben dem Massenspeicher auch noch ein einen Endpunkt haben, der z. B. eine Netzwerkkarte mimt. Diese kann dann den Datenverkehr belauschen und interessantes in einen unsichtbaren Bereich des Speichers ablegen. Hat der Angreifer keinen physischen Zugriff auf das Gerät, kann aber auch einfach nur der DNS umgebogen werden.

Einfacher und auf den ersten Blick weniger fatal wäre, wenn der USB-Stick auch eine Maus implementiert und den Cursor alle paar Minuten um einen Pixel verschiebt. Wären da nicht die User, die ihren PC nicht manuell sondern durch den Bildschirmschoner sperren lassen – und schon hat ein dritter zumindest Benutzerrechte. Genauso mit einer emulierten Tastatur. Wer tiefer gehen will, kann auch DMA nutzen und somit (mehr oder weniger) direkt auf den Speicher des PCs zugreifen.

Gegenmaßnahmen gab es bis jetzt keine praktikablen. Aber das USB-IF blieb nicht untätig, wie heise berichtet. Dennoch halte ich das für den falschen Weg. Wie bereits im dortigen Forum bemängelt wird, öffnet das Tür und Tor, USB bzw. Zubehör in Apple-Manier zu verdongeln – was aus Nutzersicht nur Nachteile bringt. Zudem muss wieder mal eine Crypto- und Zertifikatsinfrastruktur aufgebaut werden, die, wie wir alle gelernt haben, wahrscheinlich irgendwann geknackt wird und somit Angreifer wieder einen Vektor haben – denn ganz ehrlich: Wenn sich das Ziel sich lohnt, findet sich auch ein Weg. Ich verweise einfach mal auf die prominenten Beispiele DVD und HDCP.

Mein Vorschlag wäre deutlich pragmatischer: eine Firewall für den Host. Wird ein USB-Gerät (das erste Mal) eingesteckt, wird es zwar enumeriert aber nicht eingebunden. Der Benutzer bekommt angezeigt, welche Device-Klassen implementiert sind und wählt Zulassen oder Verweigern. Zur Unterstützung könnte das Betriebssystem auch anzeigen, ob die Funktionen plausibel wären – z. B. dass eine Maus mit RNDIS (Netzwerkinterface) dubios ist. Das schöne wäre, dass dies nicht nur für den USB-C-Type-Stecker, sondern für alle anderen USB-Versionen und komplett plattformunabhängig funktionieren könnte. Natürlich mit der Einschränkung, dass der Nutzer mit einer Meldung belämmert wird, die er unter Umständen nicht versteht. Vielleicht ist das mit den Zertifikaten doch nicht so schlecht. 😉