Wir schreiben einen Treiber für einen Laptop, um Spaß zu haben und Gewinn zu machen, oder wie man sich auf den Kernel einlässt, selbst wenn man ein Idiot ist

Wie alles begann


Beginnen wir mit der Problemstellung. Gegeben: ein Laptop. Neuer Laptop, Spiele. Mit RGB-Hintergrundbeleuchtung. Hier ist ein Laptop wie dieser:

Bild
Bild von lenovo.com genommen

Es gibt auch ein Programm für diesen Laptop. Das Programm steuert nur diese Hintergrundbeleuchtung.

Das einzige Problem ist das Programm für Windows, aber ich möchte, dass alles in Ihrem Lieblings-Linux funktioniert. Und Glühbirnen zu leuchten, und damit flackerten schöne Farben. Ja, das ist einfach so, so dass ohne Reverse Engineering und ohne Schreiben Ihrer Treiber? Die einfache Antwort kam schnell - auf keinen Fall. Nun, lass uns einen Fahrer schreiben.

Schritt 1 - Eintauchen in den Code


Wir haben drei Stellen, an denen Sie sehen können, wie die Hintergrundbeleuchtung blinkt. In aufsteigender Reihenfolge:

1. Ein umfangreiches und umfangreiches Gaming-Programm Lenovo Nerve Center, in dem Sie die gesamte Hintergrundbeleuchtung konfigurieren können.

2. Die Kombination der Tastenkombinationen Fn + Space ist möglich. es wird von demselben Programm verarbeitet.

3. BIOS. Während der Laptop geladen wird, flackert auch die Hintergrundbeleuchtung - allerdings nur in Rot und nur für eine Sekunde.

Mit Blick auf die Zukunft muss ich sagen, dass ich alle drei ausprobieren musste, aber erst in der ersten Phase habe ich einige Fortschritte erzielt. Wir werden über sie reden.

Öffnen Sie den Programmordner:

Ordner

Wir bemerken sofort, dass es eine DLL mit einem interessanten Namen gibt - LedSettingsPlugin.dll. Ist unser ...? Lassen Sie uns in IDA Pro öffnen und einen Blick darauf werfen.

rechte hälfte

Achten Sie auf die rechte Bildschirmhälfte. Es sind noch viele Informationen von den Programmierern übrig - wir werden sie verwenden. Wir sehen, dass es aus irgendeinem Grund viele Zeilen gibt, die den Methodennamen ähnlich sind. Warum?

name-of-func

Und das sind die Namen der Methoden. Wie bequem! Sagen wir, was wir mit unseren eigenen Namen können, und schauen wir uns die Liste der Funktionen noch einmal an. Zum Benennen in der IDA können Sie den N-Hotkey verwenden oder einfach mit der rechten Maustaste auf das klicken, was wir aufrufen möchten.

setledstatusex

Wir betrachten die Funktionen ... Y720LedSetHelper :: SetLEDStatusEx. Sieht so aus, als müssten wir! Wir stellen fest, dass hier so etwas wie eine Zeichenfolge gebildet und dann an einen bestimmten CHidDevHelper :: HidRequestsByPath übergeben wird. Speziell interessiert an var_38, dessen Metamorphosen uns freundlicherweise von der IDA zur Verfügung gestellt wurden.

Var_34 ist auch für uns interessant. Es geht direkt nach var_38 - in der Assembly-Tradition werden Variablen unter RSP in umgekehrter Reihenfolge gespeichert. Var_34 ist hier nur der Name der Konstante - -34h.

Wir bekommen, dass das Programm ab var_38 Null setzt, dann sind der Stil, die Farbe, die Nummer drei und der Block der Teil der Tastatur, auf den diese Farbe angewendet wird. (Mit Blick auf die Zukunft werde ich sagen, dass hier drei der Helligkeitswert ist. Nachdem wir es handhabbar gemacht haben, bekommen wir den Treiber sogar noch cooler als das Original!)

Kommen wir zu HidRequestsByPath und finden schließlich heraus, wie es geht.

Entwicklungshelfer

Wir sehen zwei Funktionen, HidD_GetFeature und HidD_SetFeature. Beide in der Datei sind nicht nachverfolgt ... Aber sie sind in der offiziellen Microsoft-Dokumentation sehr gut nachverfolgt - hier und hier .

Sie können sich dazu beglückwünschen - wir sind dort angekommen. Dies ist der Boden, keine Notwendigkeit, tiefer zu graben. In Linux gibt es solche Funktionen - Sie müssen sie nur mit denselben Argumenten aufrufen, und alles sollte funktionieren ... ist es wahr?

Schritt 2 - Prototyp starten ...?


Nicht wirklich. Fangen wir einfach an und führen Sie lsusb aus. Also finden wir die Tastatur und senden etwas an sie.

lsusb

Integrated Technology Express, Inc. sieht hier am interessantesten aus. Wir werden das berühmte Tool / dev / hidraw verwenden. Wir finden das Richtige ... Dies geschieht durch eine einfache Suche in den Dateien / sys / class / hidraw / hidraw * / device / uevent.

versteck dich

Hier ist einer. Die Nummern sind die gleichen - das bedeutet, dass dieses Gerät versteckt ist0. Aber wir versuchen Daten zu senden und nichts passiert! Ein Unsinn. In diesem Stadium beginnen die Hände zu sinken ... Vielleicht, nicht für bloße Sterbliche, ist dies diese Rückentwicklung?

Aber lass uns weitermachen. Wir werden es versuchen. Wenn der Autor das alles verstehen würde, würde er die Suche nach unserem Fahrer vom selben Nervenzentrum umkehren ... Aber wir haben kein Gehirn. Kehren wir zu Windows zurück, es gibt eine Idee.

Es gibt so etwas in Windows - Geräte-Manager. Sie können viel tun - wir sind daran interessiert, dass Sie damit Geräte abhacken können. Einfach und kompromisslos.

Lassen Sie uns die Geräte einzeln abhacken, bis sich der Zustand der Lampen nicht mehr ändert.

Gerät deaktivieren

Dieser wurde abgeschnitten. Wenn Sie sich also die Hardware-ID ansehen, werden wir sehen, wie er heißt und womit er isst.

Unser Gerät

Wir schauen - er ist es.

dmesg

Ein Gerät, das ich seit einigen Jahren in Dmesg überflutet habe.

[Warum ist er nicht in lsusb aufgetaucht? Und überhaupt nicht USB. Es verwendet das I2C-HID-Protokoll, mit dem Sie Geräte vor den neugierigen Händen von Handwerkern verstecken können, um HID- Geräte auf dem Bus des Computers selbst zu installieren.]

Lyrischer Exkurs - lasst uns begehen


Auf der Suche nach dem richtigen Gerät habe ich meine Installation fast bis zum Kernel übernommen. Außerdem hat mir nicht wirklich gefallen, was ich vor jedem Schloss auf diesem Dmesg-Blatt gezeigt habe. Da ich hier bin, warum nicht ein kurzes Commit schreiben? Die Hände jucken trotzdem.

Was wir sehen müssen, ist, wo sich die Geräte auf I2C HID befinden und wo zu schreiben ist, welche Merkwürdigkeiten ihnen inhärent sind. Hier. Hören wir uns ohne weiteres den Fehler an - falsche Eingabelänge. Machen wir es richtig.

schlechte Eingabegröße

Fügen Sie einen neuen Quirk hinzu, nennen wir ihn I2C_HID_QUIRK_BAD_INPUT_SIZE. In Analogie zu bestehenden.

schrullig

Fügen Sie unser Gerät der Quirkut-Liste hinzu. Was wir bisher gemacht haben:

1. Suchen Sie im Internet nach "i2c hid linux kernel". Klickte auf die vierte Antwort auf DuckDuckGo.

2. Schrieb drei (!) Wörter in Englisch - BAD_INPUT_SIZE

3. BIT (4) um eins erweitert. Es stellte sich heraus, BIT (5).

4. In hid-ids.h haben wir eine Nummer hinzugefügt - die ID unseres Geräts (in der Abbildung nicht gezeigt, aber dort ist sie auch ungefähr).

Lassen Sie uns jetzt programmieren.

Wir sehen die Zeile - `ret_size = ihid-> inbuf [0] | ihid-> inbuf [1] << 8; `

Und dann beklagt es sich, dass ret_size nicht dem entspricht, was es will.

Lassen Sie, wenn die Queer beteiligt ist, das Gleiche tun, genau das Gegenteil.

if-Bedingung

Wir senden den Patch an den Newsletter, nicht zu vergessen, zu testen ... (um ehrlich zu sein, es hat nur mehr gedauert, um den Gehirn-Newsletter zu erweitern. Es ist nicht einfach.)

angewendet

Und alle.

Schritt 3 - der Fahrer!


Dann erinnerte ich mich - oh ja, du musst noch einen Fahrer schreiben. Ich habe mich entschlossen, es noch nicht dem Kernel zu überlassen (da tauchten Fragen auf, ich musste nachdenken. Wenn einer der Habrowsker mir helfen kann, schreiben Sie mir - ich freue mich!)

Öffne die Python. (Am Anfang war bash, aber ich habe es mir sehr schnell anders überlegt.) Wir werden das bekannte Tool / dev / hidraw verwenden.

/ dev / hidraw0, / dev / hidraw1 - wie funktionieren diese Dateien überhaupt? Für einfache E / A-Vorgänge können sie wie normale Dateien verwendet werden, und es wird funktionieren. Aber GetFeature und SetFeature müssen basteln mit ...

StackOverflow (oder jemand anderes, an den ich mich noch nicht erinnere) schlug vor, dass ein ioctl erforderlich ist. Dies ist eine spezielle Methode zum Arbeiten mit ungewöhnlichen Dateien wie HID-Geräten, Terminals und dergleichen.

Ioctl funktioniert so. Sie geben ihm einen offenen Dateideskriptor (wer interessiert sich dafür, was es ist, es gibt einen Link zu Wikipedia ), eine Nummer und einen Puffer - danach macht er etwas mit diesem Puffer und gibt ihn zurück. Ich werde nicht übertreiben, da hängt nur vieles von der Umsetzung ab. Lassen Sie mich Ihnen ein Beispiel geben: 0xC0114806 oder uns bereits bekanntes SetFeature. Es ist

(6 << 29) | (ord('H') << 8) | (0x06 << 0) | (0x11 << 16).

Die ersten 6 hier bedeuten, dass die Datei zum Schreiben und Lesen geöffnet ist. Warum lesen ist nicht sehr klar - aber es ist dafür geschrieben, wahrscheinlich sollte es. Ord ('H') hier - HID abgekürzt. Vielleicht bedeuten andere Dinge, abhängig von der Datei. In diesem Fall ist der HID.
0x06 - das Team selbst. Das sechste Team mit HID ist SetFeature. Der letzte Teil ist die Länge des Puffers.

Es bleibt nur ioctl mit diesen Werten aufzurufen - und die Ausgabe ist der Treiber. Er arbeitet

Nachwort


Ich hoffe es war interessant zu lesen. Vielleicht sogar nützlich. Einige wurden weggelassen oder abgekürzt - der scharfsichtige Leser wird vielleicht die Anzeige des Zustands im Fahrer herausfinden, und einige zweite SetFeature, die im Text überhaupt nicht erwähnt wurden. Die Entwicklung von Treibern und des Linux-Kernels ist eine große Sache und kann nicht vollständig mit einem Fahrrad gemeistert werden. Der Artikel handelt eher nicht davon, sondern davon, dass es überhaupt nicht schwierig ist, etwas Kleines und Angenehmes, Open Source oder für sich selbst, zu machen. Sie brauchen nur eine Woche Abends mit Tee und dem Wunsch, sich mit dem Code zu beschäftigen.

Source: https://habr.com/ru/post/de484564/


All Articles