Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird beschrieben, wie Sie einen kleinen universellen Windows-Treiber mit Kernel-Mode Driver Framework (KMDF) schreiben und dann Ihren Treiber auf einem separaten Computer bereitstellen und installieren.
Voraussetzungen
Führen Sie die Schritte zum Installieren Windows Driver Kit (WDK)aus. Debugging-Tools für Windows sind enthalten, wenn Sie das Windows Driver Kit (WDK) installieren.
Installieren Sie Visual Studio 2022-. Wählen Sie bei der Installation von Visual Studio 2022 den Workload Desktop-Entwicklung mit C++ und fügen Sie dann unter Einzelne Komponenten hinzu:
- MSVC v143: C++-Bibliotheken mit Spectre-Entschärfungen für ARM64/ARM64EC in VS 2022 (neueste Version)
- MSVC v143 – VS 2022 C++ x64/x86 Spectre-geminderte Bibliotheken (Neueste)
- C++ ATL für die neuesten v143-Build-Tools mit Spectre Mitigations (ARM64/ARM64EC)
- C++ ATL für neueste v143-Buildtools mit Spectre-Abmilderungen (x86 & x64)
- C++ MFC für die neuesten v143-Build-Tools mit Spectre-Mitigations (ARM64/ARM64EC)
- C++ MFC für neueste v143-Buildtools mit Spectre Mitigations (x86 & x64)
- Windows Driver Kit
Erstellen und Entwickeln eines Treibers
Öffnen Sie Microsoft Visual Studio. Wählen Sie im Menü Datei Neues >Projekt.
Wählen Sie im Dialogfeld Erstellen eines neuen Projekts im linken Dropdownmenü C++- aus, wählen Sie Windows in der mittleren Dropdownliste und dann Treiber- in der rechten Dropdownliste aus.
Wählen Sie Kernel Mode Driver, Empty (KMDF) aus der Liste der Projekttypen. Wählen Sie Weiter aus.
Tipp
Wenn Sie in Visual Studio keine Treiberprojektvorlagen finden können, wurde die WDK Visual Studio-Erweiterung nicht ordnungsgemäß installiert. Um dieses Problem zu beheben, starten Sie Visual Studio Installer, wählen Sie Ändern, fügen Sie Windows Driver Kits auf der Registerkarte einzelne Komponente hinzu, und wählen Sie Ändernaus.
Geben Sie im Dialogfeld "Neues Projekt konfigurieren" "KmdfHelloWorld" in das Feld Projektname ein.
Anmerkung
Wenn Sie einen neuen KMDF- oder UMDF-Treiber erstellen, müssen Sie einen Treibernamen mit 32 Zeichen oder weniger auswählen. Dieser Längengrenzwert wird in wdfglobals.h definiert.
Geben Sie im Feld Speicherort das Verzeichnis ein, in dem Sie das neue Projekt erstellen möchten.
Markieren Sie Lösung und Projekt in dasselbe Verzeichnis legen und wählen Sie Erstellen.
Visual Studio erstellt ein Projekt und eine Projektmappe. Diese werden im Fenster Projektmappen-Explorer angezeigt. (Wenn das Fenster "Projektmappen-Explorer" nicht angezeigt wird, wählen Sie Projektmappen-Explorer aus dem Menü Ansicht aus.) Die Lösung hat ein Treiberprojekt namens KmdfHelloWorld.
Wählen Sie im Fenster Lösungs-Explorer mit der rechten Maustaste Lösung 'KmdfHelloWorld' (1 von 1 Projekt) und wählen Sie Konfiguration Manager. Wählen Sie eine Konfiguration und Plattform für das Treiberprojekt aus. Wählen Sie beispielsweise Debug- und x64-aus.
Wählen Sie im Fenster Lösungs-Explorer mit der rechten Maustaste das Projekt KmdfHelloWorld, wählen Sie Hinzufügen und dann Neues Element.
Geben Sie im Dialogfeld "Neues Element hinzufügen" "Driver.c" ein.
Anmerkung
Die Dateinamenerweiterung ist .c, nicht .cpp.
Wählen Sie aus, fügen Siehinzu. Die datei Driver.c wird wie hier gezeigt unter Quelldateienhinzugefügt.
Schreiben des ersten Treibercodes
Nachdem Sie nun Ihr leeres Hello World-Projekt erstellt und die Quelldatei "Driver.c" hinzugefügt haben, schreiben Sie den grundlegendsten Code, der für die Ausführung des Treibers erforderlich ist, indem Sie zwei grundlegende Ereignisrückruffunktionen implementieren.
Beginnen Sie in Driver.c mit den folgenden Headern:
#include <ntddk.h> #include <wdf.h>
Tipp
Wenn Sie
Ntddk.h
nicht hinzufügen können, öffnen Sie Konfiguration -> C/C++ ->Allgemein ->Zusätzliche Include-Verzeichnisse und fügenC:\Program Files (x86)\Windows Kits\10\Include\<build#>\km
hinzu, wobei Sie<build#>
durch das entsprechende Verzeichnis in Ihrer WDK-Installation ersetzen.Ntddk.h enthält kernige Windows-Kerneldefinitionen für alle Treiber, während Wdf.h- Definitionen für Treiber enthält, die auf dem Windows Driver Framework (WDF) basieren.
Stellen Sie als Nächstes Deklarationen für die beiden Rückrufe bereit:
DRIVER_INITIALIZE DriverEntry; EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;
Verwenden Sie den folgenden Code, um Ihren DriverEntryzu verfassen.
NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { // NTSTATUS variable to record success or failure NTSTATUS status = STATUS_SUCCESS; // Allocate the driver configuration object WDF_DRIVER_CONFIG config; // Print "Hello World" for DriverEntry KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n" )); // Initialize the driver configuration object to register the // entry point for the EvtDeviceAdd callback, KmdfHelloWorldEvtDeviceAdd WDF_DRIVER_CONFIG_INIT(&config, KmdfHelloWorldEvtDeviceAdd ); // Finally, create the driver object status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE ); return status; }
DriverEntry ist der Einstiegspunkt für alle Treiber, wie
Main()
für viele Benutzermodusanwendungen. Der Job von DriverEntry ist es, treiberweite Strukturen und Ressourcen zu initialisieren. In diesem Beispiel haben Sie "Hello World" für DriverEntry ausgegeben, das Treiberobjekt so konfiguriert, dass es den Einstiegspunkt Ihres EvtDeviceAdd-Callbacks registriert, dann das Treiberobjekt erstellt und zurückgegeben.Das Treiberobjekt fungiert als übergeordnetes Objekt für alle anderen Framework-Objekte, die Sie möglicherweise in Ihrem Treiber erstellen, darunter Geräteobjekte, E/A-Warteschlangen, Zeitgeber, Spinlocks und vieles mehr. Weitere Informationen zu Frameworkobjekten finden Sie unter Einführung in Framework-Objekte.
Hinweis
Für DriverEntry-, wird dringend empfohlen, den Namen als "DriverEntry" beizubehalten, um die Codeanalyse und das Debugging zu erleichtern.
Verwenden Sie als Nächstes den folgenden Code, um Ihren KmdfHelloWorldEvtDeviceAddzu erstellen:
NTSTATUS KmdfHelloWorldEvtDeviceAdd( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) { // We're not using the driver object, // so we need to mark it as unreferenced UNREFERENCED_PARAMETER(Driver); NTSTATUS status; // Allocate the device object WDFDEVICE hDevice; // Print "Hello World" KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n" )); // Create the device object status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &hDevice ); return status; }
EvtDeviceAdd wird vom System aufgerufen, wenn erkannt wird, dass Ihr Gerät eingetroffen ist. Der Auftrag besteht darin, Strukturen und Ressourcen für dieses Gerät zu initialisieren. In diesem Beispiel haben Sie eine "Hello World"-Nachricht für EvtDeviceAddausgegeben, das Geräteobjekt erstellt und zurückgegeben. In anderen Treibern, die Sie schreiben, können Sie E/A-Warteschlangen für Ihre Hardware erstellen, einen Gerätekontext Speicherplatz für gerätespezifische Informationen einrichten oder andere Aufgaben ausführen, die zum Vorbereiten Ihres Geräts erforderlich sind.
Tipp
Beachten Sie bei dem Callback für das Hinzufügen von Geräten, dass Sie ihn mit dem Namen Ihres Treibers als Präfix benannt haben (KmdfHelloWorldEvtDeviceAdd). Im Allgemeinen wird empfohlen, die Funktionen Ihres Treibers auf diese Weise zu benennen, um sie von den Funktionen anderer Treiber zu unterscheiden. DriverEntry ist der einzige, den Sie genau so benennen sollten.
Ihr vollständiger Driver.c sieht nun wie folgt aus:
#include <ntddk.h> #include <wdf.h> DRIVER_INITIALIZE DriverEntry; EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd; NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { // NTSTATUS variable to record success or failure NTSTATUS status = STATUS_SUCCESS; // Allocate the driver configuration object WDF_DRIVER_CONFIG config; // Print "Hello World" for DriverEntry KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n" )); // Initialize the driver configuration object to register the // entry point for the EvtDeviceAdd callback, KmdfHelloWorldEvtDeviceAdd WDF_DRIVER_CONFIG_INIT(&config, KmdfHelloWorldEvtDeviceAdd ); // Finally, create the driver object status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE ); return status; } NTSTATUS KmdfHelloWorldEvtDeviceAdd( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) { // We're not using the driver object, // so we need to mark it as unreferenced UNREFERENCED_PARAMETER(Driver); NTSTATUS status; // Allocate the device object WDFDEVICE hDevice; // Print "Hello World" KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n" )); // Create the device object status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &hDevice ); return status; }
Speichern Sie Driver.c.
In diesem Beispiel wird ein grundlegendes Konzept von Treibern veranschaulicht: Sie sind eine "Sammlung von Rückrufen", die nach der Initialisierung sitzen und warten, bis das System sie aufruft, wenn etwas benötigt wird. Ein Systemaufruf kann ein Ereignis sein, bei dem ein neues Gerät eintrifft, eine E/A-Anfrage von einer Anwendung im Benutzermodus, ein Ereignis beim Abschalten des Systems, eine Anfrage von einem anderen Treiber oder ein Ereignis, bei dem ein Benutzer das Gerät unerwartet aussteckt. Um "Hello World" zu sagen, mussten Sie sich glücklicherweise nur um die Erstellung von Treibern und Geräten kümmern.
Als Nächstes erstellen Sie Ihren Treiber.
Treiber erstellen
Wählen Sie im Projektmappen-Explorer-Fenster die Projektmappe "KmdfHelloWorld" (1 von 1 Projekt) mit der rechten Maustaste aus und wählen Sie den Konfigurations-Manager. Wählen Sie eine Konfiguration und Plattform für das Treiberprojekt aus. Wählen Sie für diese Übung Debug- und x64-aus.
Wählen Sie im Fenster Lösungs-Explorer mit der rechten Maustaste KmdfHelloWorld und wählen Sie Eigenschaften. Legen Sie unter Wpp Tracing >Alle Optionen Wpp Tracing ausführen auf Nein fest. Wählen Sie Übernehmen und anschließend OK aus.
Um Ihren Treiber zu erstellen, wählen Sie Lösung erstellen aus dem Menü Erstellen. Visual Studio zeigt den Fortschritt der Erstellung im Fenster Output an. (Wenn das Fenster Ausgabe nicht sichtbar ist, wählen Sie Ausgabe aus dem Menü Ansicht.) Wenn Sie überprüfen, ob die Lösung erfolgreich erstellt wurde, können Sie Visual Studio schließen.
Um den integrierten Treiber im Datei-Explorer anzuzeigen, navigieren Sie zu Ihrem KmdfHelloWorld Ordner und dann zu x64\Debug\KmdfHelloWorld. Der Ordner enthält Folgendes:
- KmdfHelloWorld.sys – die Kernelmodustreiberdatei
- KmdfHelloWorld.inf – eine Informationsdatei, die Windows beim Installieren des Treibers verwendet
- KmdfHelloWorld.cat – eine Katalogdatei, die das Installationsprogramm verwendet, um die Testsignatur des Treibers zu überprüfen
Tipp
Wenn beim Erstellen des Treibers DriverVer set to a date in the future
angezeigt wird, ändern Sie die Einstellungen des Treiberprojekts so, dass Inf2Cat /uselocaltime
festlegt. Verwenden Sie dazu Konfigurationseigenschaften ->Inf2Cat ->Allgemein ->Lokale Zeit. Jetzt verwenden sowohl Stampinf als auch Inf2Cat lokale Zeit.
Bereitstellen des Treibers
Wenn Sie einen Treiber testen und debuggen, werden der Debugger und der Treiber auf separaten Computern ausgeführt. Der Computer, auf dem der Debugger ausgeführt wird, wird als Hostcomputerbezeichnet, und der Computer, auf dem der Treiber ausgeführt wird, wird als Zielcomputerbezeichnet. Der Zielcomputer wird auch als Testcomputerbezeichnet.
Bisher haben Sie Visual Studio zum Erstellen eines Treibers auf dem Hostcomputer verwendet. Jetzt müssen Sie einen Zielcomputer konfigurieren.
Folgen Sie den Anweisungen in Bereitstellen eines Computers für die Treiberbereitstellung und -tests (WDK 10).
Tipp
Wenn Sie die Schritte ausführen, um den Zielcomputer automatisch über ein Netzwerkkabel bereitzustellen, notieren Sie sich den Anschluss und den Schlüssel. Sie verwenden sie später im Debugschritt. In diesem Beispiel verwenden Sie 50000 als Port und 1.2.3.4 als Schlüssel.
In echten Treiberdebuggingszenarien empfehlen wir die Verwendung eines von KDNET generierten Schlüssels. Weitere Informationen zur Verwendung von KDNET zum Generieren eines Zufälligen Schlüssels finden Sie im Thema Debugtreiber – Step by Step Lab (Sysvad Kernel Mode) Thema.
Öffnen Sie auf dem Host-Computer Ihre Lösung in Visual Studio. Sie können im Ordner "KmdfHelloWorld" auf die Lösungsdatei KmdfHelloWorld.sln doppelklicken.
Klicken Sie im Fenster Lösungs-Explorer mit der rechten Maustaste auf das KmdfHelloWorld-Projekt und wählen Sie Eigenschaften.
Gehen Sie zu Treiber installieren > Bereitstellung.
Wählen Sie für Zielgerätenameden Namen des Computers aus, den Sie zum Testen und Debuggen konfiguriert haben. In dieser Übung verwenden wir einen Computer namens MyTestComputer.
Um sicherzustellen, dass Sie die neueste Version des Treibers testen, überprüfen Sie Entfernen vorheriger Treiberversionen vor der Bereitstellung.
Wählen Sie Hardware-ID-Treiberupdateaus, und geben Sie die Hardware-ID für Ihren Treiber ein. Für diese Übung ist die Hardware-ID "Root\KmdfHelloWorld". Wählen Sie OKaus.
Anmerkung
In dieser Übung identifiziert die Hardware-ID keine echte Hardware. Er identifiziert ein imaginäres Gerät, das als untergeordneter Knoten des Root-Knotens einen Platz im Gerätebaum erhält. Wählen Sie für echte Hardware nicht Hardware-ID-Treiberupdateaus; Wählen Sie stattdessen Installieren undüberprüfen aus. Die Hardware-ID wird in der INF-Datei (Driver's Information) angezeigt. Gehen Sie im Fenster Lösungs-Explorer zu KmdfHelloWorld >Treiberdateien und klicken Sie doppelt auf KmdfHelloWorld.inf. Die Hardware-ID befindet sich unter [Standard.NT$ARCH$].
[Standard.NT$ARCH$] %KmdfHelloWorld.DeviceDesc%=KmdfHelloWorld_Device, Root\KmdfHelloWorld
Wählen Sie im Menü "Erstellen" die Option "Lösung bereitstellen"aus. Visual Studio kopiert automatisch die zum Installieren und Ausführen des Treibers erforderlichen Dateien auf den Zielcomputer. Die Bereitstellung kann ein oder zwei Minuten dauern.
Wenn Sie einen Treiber bereitstellen, werden die Treiberdateien auf dem Testcomputer in den Ordner %Systemdrive%\drivertest\drivers kopiert. Wenn während der Bereitstellung ein Fehler auftritt, können Sie überprüfen, ob die Dateien auf den Testcomputer kopiert werden. Vergewissern Sie sich, dass die .inf-, .cat-Dateien, das Testzertifikat, die .sys-Dateien sowie alle anderen erforderlichen Dateien im Ordner %systemdrive%\drivertest\drivers vorhanden sind.
Weitere Informationen zum Bereitstellen von Treibern finden Sie unter Bereitstellen eines Treibers auf einem Testcomputer.
Installieren des Treibers
Nachdem Ihr Hello World-Treiber auf dem Zielcomputer bereitgestellt wurde, installieren Sie nun den Treiber. Wenn Sie den Zielcomputer zuvor mit Visual Studio mithilfe der automatischen Option bereitgestellt haben, richtet Visual Studio den Zielcomputer so ein, dass er im Rahmen des Bereitstellungsprozesses Tests von signierten Treibern ausführt. Jetzt müssen Sie nur den Treiber mithilfe des DevCon-Tools installieren.
Navigieren Sie auf dem Hostcomputer zu dem Ordner "Tools" in Ihrer WDK-Installation, und suchen Sie das DevCon-Tool. Suchen Sie beispielsweise im folgenden Ordner:
C:\Program Files (x86)\Windows Kits\10\Tools\x64\devcon.exe
Kopieren Sie das DevCon-Tool auf Ihren Remotecomputer.
Installieren Sie auf dem Zielcomputer den Treiber, indem Sie zu dem Ordner navigieren, der die Treiberdateien enthält, und führen Sie dann das DevCon-Tool aus.
Dies ist die allgemeine Syntax für das Devcon-Tool, das Sie zum Installieren des Treibers verwenden:
devcon install <INF file><hardware ID>
Die FÜR die Installation dieses Treibers erforderliche INF-Datei ist KmdfHelloWorld.inf. Die INF-Datei enthält die Hardware-ID zum Installieren der Treiber-Binärdatei, KmdfHelloWorld.sys. Denken Sie daran, dass die Hardware-ID, die sich in der INF-Datei befindet, Root\KmdfHelloWorldist.
Öffnen Sie ein Eingabeaufforderungsfenster als Administrator. Navigieren Sie zu Ihrem Ordner, der den integrierten Treiber .sys Datei enthält, und geben Sie diesen Befehl ein:
devcon install kmdfhelloworld.inf root\kmdfhelloworld
Wenn Sie die Fehlermeldung erhalten, dass devcon nicht erkannt wird, versuchen Sie, den Pfad zum devcon-Tool hinzuzufügen. Wenn Sie ihn beispielsweise in einen Ordner auf dem Zielcomputer kopiert haben, der C:\Toolsheißt, versuchen Sie es mit dem folgenden Befehl:
c:\tools\devcon install kmdfhelloworld.inf root\kmdfhelloworld
Ein Dialogfeld wird angezeigt, das angibt, dass der Testtreiber ein nicht signierter Treiber ist. Wählen Sie Diesen Treiber trotzdem installieren, um fortzufahren.
Debuggen des Treibers
Nachdem Sie ihren KmdfHelloWorld-Treiber nun auf dem Zielcomputer installiert haben, fügen Sie einen Debugger remote vom Hostcomputer an.
Öffnen Sie auf dem Hostcomputer ein Eingabeaufforderungsfenster als Administrator. Wechseln Sie in das Verzeichnis WinDbg.exe. Sie verwenden die x64version von WinDbg.exe aus dem Windows Driver Kit (WDK), das als Teil der Windows Kit-Installation installiert wurde. Hier ist der Standardpfad zu WinDbg.exe:
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64
Starten Sie WinDbg, um mithilfe des folgenden Befehls eine Verbindung mit einer Kerneldebugsitzung auf dem Zielcomputer herzustellen. Der Wert für Port und Schlüssel sollte mit dem übereinstimmen, was Sie zum Bereitstellen des Zielcomputers verwendet haben. Sie verwenden 500000 für den Port und 1.2.3.4 für den Schlüssel, die Werte, die Sie während des Bereitstellungsschritts verwendet haben. Das k Flag gibt an, dass es sich um eine Kerneldebugsitzung handelt.
WinDbg -k net:port=50000,key=1.2.3.4
Wählen Sie im Menü Debug die Option Break. Der Debugger auf dem Hostcomputer greift in den Zielcomputer ein. Im Fenster Debuggerbefehl sehen Sie die Kerneldebugging-Eingabeaufforderung: kd>.
An diesem Punkt können Sie mit dem Debugger experimentieren, indem Sie Befehle an der kd> Eingabeaufforderung eingeben. Sie können beispielsweise die folgenden Befehle ausprobieren:
Um den Zielcomputer erneut auszuführen, wählen Sie Go aus dem Menü Debug, oder drücken Sie "g", dann "Enter".
Um die Debugging-Sitzung zu beenden, wählen Sie aus dem Menü Debug die Option Debugger absetzen.
Wichtig
Stellen Sie sicher, dass Sie den Befehl "go" verwenden, damit der Zielcomputer, bevor Sie den Debugger verlassen, erneut ausgeführt werden kann, sonst bleibt der Zielcomputer unempfindlich gegenüber Ihren Maus- und Tastatureingaben, da er immer noch mit dem Debugger kommuniziert.
Eine detaillierte schrittweise Vorgehensweise des Treiberdebuggingprozesses finden Sie unter Debuggen universeller Treiber – Schritt für Schritt -Übung (Echo Kernel-Mode).
Weitere Informationen zum Remotedebugging finden Sie unter Remotedebugging mit WinDbg.
Verwandte Artikel
Debuggen universeller Treiber – Schritt-für-Schritt-Labor (Echo Kernel-Mode)