Windows von Niklas Bartz Es geht um die Kommunikation eines Treibers mit einem User-Programm. Willkomen zum zweiten Treiber Tutorial. Diesmal werden wir die Kommunikation zwischen einem Treiber und einem Programm im User-Mode behandeln. Um mit einem anderen Programm zu kommunizieren muss ein Treiber I/O Request Packets (IRP) benutzen. Dies ist eine einfach Datenstruktur, welche Puffer mit Daten enthält. Das ganze funktioniert, wie sollte es auch anders sein unter Windows, mit Datei-Handles. Wenn also nun ein User-Programm ein String in das Datei-Handle des Treibers schreibt, dann wird vom Kernel ein IRP erzeugt, welches diesen String enthält. Um nun IRPs verarbeiten zu können muss unser Kerneltreiber eine Funktion zur verarbeitung bereitstellen. Dies funktioniert genau so wie mit der Endladeroutine. Es wird einfach der zugehörige Funktionszeiger gesetzt. Alle Hauptfunktionen sind in einem Array namens MajorFunction gespeichert. Es sind Werte definiert wodurch man die Funktionen setzten kann. -- } // u.s.w. //... Abbildung 1: Ein Kerneltreiber kann für jede Hauptfunktion eine eigene Callbackfuntkion definieren Man sollte sich im klaren seien, dass man ohne ein Request von dem User-Mode-Programm nichts vom Treiber senden kann oder habt ihr schonmal eine Nachricht von einer Datei empfangen? Also jede Kommunikation erfolgt vom User-Programm aus. Wenn man nun dafür sorgen möchte, dass der Treiber einem immer etwas senden kann, dann muss man immer genügend Request bereitstellen, bevor diese verbraucht sind. Man sendet also ein Request an den Treiber welches dieses erst verwendet, wenn er Daten zu übermitteln hat. Dann reagiert er auf das Request und sendet etwas an das Programm zurück. Um nun von einem Programm im User-Mode aus einen Treiber zu verwenden, muss dieses Programm ein Handle zum Treiber öffen. Dies geht jedoch nur, wenn der Treiber zuvor ein Gerät registriert hat. Danach kann man mit dem User-Programm das Gerät öffnen und darauf zugreifen, als sei es eine Datei. So ähnlich ist es in der Regel auch bei UNIX-Systemen. So wollen wir mal mit unserem Kerneltreiber ein Gerät registrieren: Code c: -- Dazu folgendes: Wenn man eine Event im Kernel-Mode erstellt, dann kann ma dies im User-Mode nicht modifizieren, man kann nur den Status abfragen. Allerdings möchten wir, dass unsere GUI Anwendung den Status verändern kann. Da der Treiber mit höherer Priorität als eine GUI Anwendung läuft, können wir vom Treiber aus auf alles in einer GUI Anwendung zugreifen. Somit müssen wir das Event in unserem Programm erstellen und an den Treiber weiterleiten (referenzieren). Wenn man eine neue IOCTL schreibt, welcher es möglich seien soll mit User-Mode-Software zu kommunizieren, dann muss diese IRP_MJ_DEVICE_CONTROL Requests benutzen (MSDN(27.10.2011)). Von Windows wird das CTL_CODE Makro geliefert, welches in der Wdm.h und Ntddk.h definiert ist (Def. s.unten oder hier MSDN (27.10.2011)). An dieser Stelle Zeige ich einfach einmal den ganzen Code des Treibers und der GUI Testanwendung. Der Code sollte eigentlich selbst erklärend seien, für jeden der meint er ist weit genug um Treiber zu programmieren. Das komplette Beispiel ist auch im Anhang vorhanden. Treiber: IOCTL.h // wird von dem Treiber und der GUI App verwendet Code c: