Prüfliste zur Treibersicherheit

Dieser Artikel enthält eine Sicherheitsprüfliste für Treiberentwickler, um das Risiko zu verringern, dass Treiber kompromittiert werden.

Übersicht über die Treibersicherheit

Ein Sicherheitsfehler ist jeder Fehler, der es einem Angreifer ermöglicht, einen Treiber so zu stören, dass es dazu führt, dass das System abstürzt oder unbrauchbar wird. Darüber hinaus können Sicherheitsrisiken im Treibercode es einem Angreifer ermöglichen, Zugriff auf den Kernel zu erhalten und eine Möglichkeit zu schaffen, das gesamte Betriebssystem zu gefährden. Wenn die meisten Entwickler an ihrem Treiber arbeiten, konzentriert sich ihr Fokus darauf, den Treiber ordnungsgemäß zu arbeiten, und nicht darauf, ob ein böswilliger Angreifer versucht, Sicherheitsrisiken innerhalb ihres Codes auszunutzen.

Nachdem ein Treiber freigegeben wurde, können Angreifer jedoch versuchen, Sicherheitsfehler zu untersuchen und zu identifizieren. Entwickler müssen diese Probleme während der Entwurfs- und Implementierungsphase berücksichtigen, um die Wahrscheinlichkeit solcher Sicherheitsrisiken zu minimieren. Ziel ist es, alle bekannten Sicherheitsfehler zu beseitigen, bevor der Treiber freigegeben wird.

Die Schaffung sichererer Treiber erfordert die Zusammenarbeit des Systemarchitekten (bewusst denken sie an potenzielle Bedrohungen für den Treiber), den Entwickler, der den Code implementiert (defensiv codiert allgemeine Vorgänge, die die Quelle von Exploits sein können) und das Testteam (proaktiv versuchen, Schwäche und Sicherheitsanfälligkeiten zu finden). Durch die ordnungsgemäße Koordinierung aller dieser Aktivitäten wird die Sicherheit des Fahrers erheblich verbessert.

Neben der Vermeidung der Probleme, die einem Angriff auf einen Treiber zugeordnet sind, erhöhen viele der beschriebenen Schritte, z. B. genauere Verwendung des Kernelspeichers, die Zuverlässigkeit Ihres Treibers. Dadurch werden die Supportkosten reduziert und die Kundenzufriedenheit mit Ihrem Produkt erhöht. Das Abschließen der Aufgaben in der nachstehenden Checkliste hilft ihnen, alle diese Ziele zu erreichen.

Sicherheitsprüfliste:Führen Sie die in den einzelnen Themen beschriebene Sicherheitsaufgabe aus.

empty checkbox.Bestätigen Sie, dass ein Kerneltreiber erforderlich ist.

empty checkbox.Verwenden der Treiberframeworks

empty checkbox.Steuern des Zugriffs nur auf Softwaretreiber

empty checkbox.Code des Testtreibers für produktionsbezogenes Signieren nicht

empty checkbox.Ausführen einer Bedrohungsanalyse

empty checkbox.Befolgen von Richtlinien für die sichere Codierung des Treibers

empty checkbox.Überprüfen der HVCI-Kompatibilität

empty checkbox.Befolgen von technologiespezifischen Code bewährte Methoden

empty checkbox.Durchführen einer Peercodeüberprüfung

empty checkbox.Verwalten der Treiberzugriffssteuerung

empty checkbox.Verbessern der Geräteinstallationssicherheit

empty checkbox.Ausführen der ordnungsgemäßen Veröffentlichungstreibersignatur

empty checkbox.Verwenden der Codeanalyse in Visual Studio zur Untersuchung der Treibersicherheit

empty checkbox.Verwenden der Statischen Treiberüberprüfung zum Überprüfen auf Sicherheitsrisiken

empty checkbox.Code mit BinSkim Binary Analyzer überprüfen

empty checkbox.Verwenden von Codeüberprüfungstools

empty checkbox.Überprüfen von Debuggertechniken und Erweiterungen

empty checkbox.Überprüfen von Ressourcen für sichere Codierung

Zusammenfassung der wichtigsten Erkenntnisse

Bestätigen Sie, dass ein Kerneltreiber erforderlich ist.

Sicherheitsprüflisteelement #1:Bestätigen Sie, dass ein Kerneltreiber erforderlich ist und dass ein niedrigerer Risikoansatz, z. B. Windows Dienst oder App, keine bessere Option ist.

Treiber leben im Windows Kernel und haben beim Ausführen im Kernel ein Problem, das das gesamte Betriebssystem verfügbar macht. Wenn eine andere Option verfügbar ist, ist es wahrscheinlich niedriger und hat weniger Risiken als das Erstellen eines neuen Kerneltreibers. Weitere Informationen zur Verwendung der integrierten Windows Treiber finden Sie unter "Müssen Sie einen Treiber schreiben?".

Informationen zur Verwendung von Hintergrundaufgaben finden Sie unter "Unterstützen Ihrer App mit Hintergrundaufgaben".

Informationen zur Verwendung von Windows Diensten finden Sie unter "Dienste".

Verwenden der Treiberframeworks

Sicherheitsprüflisteelement #2:Verwenden Sie die Treiberframeworks, um die Größe Ihres Codes zu verringern und die Zuverlässigkeit und Sicherheit zu erhöhen.

Verwenden Sie die Windows Driver Frameworks, um die Größe Ihres Codes zu verringern und die Zuverlässigkeit und Sicherheit zu erhöhen. Lesen Sie zunächst die Verwendung von WDF zum Entwickeln eines Treibers. Informationen zur Verwendung des Treibertreibers für den niedrigeren Benutzermodusmodus (UMDF) finden Sie unter Auswählen eines Treibermodells.

Das Schreiben eines alten Windows Driver Model (WDM)-Treibers ist zeitaufwendiger, kostspieliger und umfasst fast immer das Neustellen von Code, der in den Treiberframeworks verfügbar ist.

Der Windows Driver Framework-Quellcode ist Open Source und für GitHub verfügbar. Dies ist der gleiche Quellcode, aus dem die WDF-Laufzeitbibliothek, die in Windows 10 enthalten ist, erstellt wird. Sie können Ihren Treiber effektiver debuggen, wenn Sie die Interaktionen zwischen dem Treiber und WDF verfolgen können. Laden Sie es von https://github.com/Microsoft/Windows-Driver-Frameworks.

Steuern des Zugriffs nur auf Softwaretreiber

Sicherheitsprüfliste-Element #3:Wenn ein nur softwaregeschützter Treiber erstellt werden soll, muss zusätzliche Zugriffssteuerung implementiert werden.

Nur Software-Kerneltreiber verwenden plug-and-play (PnP) nicht, um bestimmten Hardware-IDs zugeordnet zu werden und können auf jedem PC ausgeführt werden. Ein solcher Treiber könnte für andere Zwecke als die ursprünglich beabsichtigte verwendet werden, um einen Angriffsvektor zu erstellen.

Da softwaregeschützte Kerneltreiber zusätzliche Risiken enthalten, müssen sie auf bestimmte Hardware beschränkt sein (z. B. mithilfe einer eindeutigen PnP-ID zum Erstellen eines PnP-Treibers oder durch Überprüfen der SMBIOS-Tabelle auf die Anwesenheit bestimmter Hardware).

Stellen Sie sich beispielsweise vor, OEM Fabrikam möchte einen Treiber verteilen, der ein Overclocking-Dienstprogramm für ihre Systeme ermöglicht. Wenn dieser Nur-Softwaretreiber auf einem System von einem anderen OEM ausgeführt werden soll, können Systeminstabilitäten oder Schäden auftreten. Fabrikam-Systeme sollten eine eindeutige PnP-ID enthalten, um die Erstellung eines PnP-Treibers zu ermöglichen, der auch über Windows Update aktualisiert werden kann. Wenn dies nicht möglich ist, und Fabrikam autoren einen Legacytreiber, sollte dieser Treiber eine andere Methode finden, um zu überprüfen, ob er auf einem Fabrikam-System ausgeführt wird (z. B. durch Prüfung der SMBIOS-Tabelle vor der Aktivierung von Funktionen).

Testcode für Produktionszeichen nicht ausführen

Sicherheitsprüfliste -Element #4:Nicht Produktionscode signieren Entwicklung, Tests und Herstellung von Kerneltreibercode.

Kerneltreibercode, der für Entwicklung, Tests oder Fertigung verwendet wird, kann gefährliche Funktionen enthalten, die ein Sicherheitsrisiko darstellen. Dieser gefährliche Code sollte niemals mit einem Zertifikat signiert werden, das von Windows vertrauenswürdig ist. Der richtige Mechanismus zum Ausführen des gefährlichen Treibercodes besteht darin, den sicheren UEFI-Start zu deaktivieren, den BCD "TESTSIGNING" zu aktivieren und den Entwicklungs-, Test- und Fertigungscode mithilfe eines nicht vertrauenswürdigen Zertifikats zu signieren (z. B. eine, die von makecert.exe generiert wird).

Code, der von einem vertrauenswürdigen Software Publisher Certificate (SPC) oder Windows Hardware Quality Labs (WHQL)-Signatur signiert ist, dürfen die Umgehung von Windows Codeintegritäts- und Sicherheitstechnologien nicht erleichtern. Bevor Der Code von einer vertrauenswürdigen SPC- oder WHQL-Signatur signiert wird, stellen Sie zunächst sicher, dass sie anleitungen vom Erstellen zuverlässiger Kernel-Mode Treiber erfüllt. Darüber hinaus darf der Code keine gefährlichen Verhaltensweisen enthalten, wie unten beschrieben. Weitere Informationen zur Treibersignierung finden Sie weiter unten in diesem Artikel unter Releasetreibersignatur .

Beispiele für gefährliches Verhalten sind die folgenden:

  • Stellt die Möglichkeit bereit, beliebigen Kernel, physischen oder Gerätespeicher dem Benutzermodus zuzuordnen.
  • Bietet die Möglichkeit, beliebigen Kernel, physischen oder Gerätespeicher zu lesen oder zu schreiben, einschließlich Porteingabe/Ausgabe (I/O).
  • Bereitstellen des Zugriffs auf den Speicher, der Windows Zugriffssteuerung umgeht.
  • Bietet die Möglichkeit, Hardware oder Firmware zu ändern, die der Treiber nicht für die Verwaltung konzipiert war.

Ausführen einer Bedrohungsanalyse

Sicherheitsprüflisteelement #5:Ändern Sie entweder ein vorhandenes Treiber-Bedrohungsmodell, oder erstellen Sie ein benutzerdefiniertes Bedrohungsmodell für Ihren Treiber.

Bei der Prüfung der Sicherheit besteht eine gemeinsame Methodik darin, spezifische Bedrohungsmodelle zu erstellen, die versuchen, die Arten von Angriffen zu beschreiben, die möglich sind. Diese Technik ist nützlich beim Entwerfen eines Treibers, da er den Entwickler gezwungen, die potenziellen Angriffsvektoren vor einem Treiber zu berücksichtigen. Nachdem sie potenzielle Bedrohungen identifiziert haben, kann ein Treiberentwickler dann Mittel zur Verteidigung gegen diese Bedrohungen berücksichtigen, um die Gesamtsicherheit der Treiberkomponente zu stärken.

Dieser Artikel enthält treiberspezifische Anleitungen zum Erstellen eines einfachen Bedrohungsmodells: Bedrohungsmodell für Treiber. Der Artikel enthält ein Beispiel für ein Treiber-Bedrohungsmodelldiagramm, das als Ausgangspunkt für Ihren Treiber verwendet werden kann.

Sample data flow diagram for hypothetical kernel-mode driver.

Bewährte Methoden und zugehörige Tools für security Development Lifecycle (SDL) können von IHVs und OEMs verwendet werden, um die Sicherheit ihrer Produkte zu verbessern. Weitere Informationen finden Sie unter SDL-Empfehlungen für OEMs.

Befolgen von Richtlinien für die sichere Codierung des Treibers

Sicherheitsprüflisteelement #6:Überprüfen Sie Ihren Code, und entfernen Sie bekannte Coderisiken.

Die Kernaktivität beim Erstellen sicherer Treiber besteht darin, Bereiche im Code zu identifizieren, die geändert werden müssen, um bekannte Softwarerisiken zu vermeiden. Viele dieser bekannten Softwarerisiken befassen sich mit der strikten Nachverfolgung der Verwendung von Arbeitsspeicher, um Probleme mit anderen zu vermeiden, die überschreiben oder anderweitig aus den Speicherspeicherorten bestehen, die Ihr Treiber verwendet.

Der Abschnitt "Code Validation Tools" in diesem Artikel beschreibt Softwaretools, die verwendet werden können, um bekannte Softwarerisiken zu finden.

Speicherpuffer

Verwenden der geeigneten Methode für den Zugriff auf Datenpuffer mit IOCTLs

Eine der hauptverantwortlichen Zuständigkeiten eines Windows Treibers ist das Übertragen von Daten zwischen Benutzermodusanwendungen und den Geräten eines Systems. Die drei Methoden für den Zugriff auf Datenpuffer werden in der folgenden Tabelle angezeigt.

IOCTL-Puffertyp Zusammenfassung Weitere Informationen finden Sie unter
METHOD_BUFFERED Empfohlen für die meisten Situtationen Verwenden von gepufferten E/A
METHOD_IN_DIRECT oder METHOD_OUT_DIRECT Wird in einigen Hochgeschwindigkeits-HW-I/O verwendet Verwenden von direct I/O
METHOD_NEITHER Vermeiden Sie ggf. Verwenden von weder gepufferter noch direkter E/A

Im Allgemeinen wird gepufferte I/O empfohlen, da sie die sichersten Puffermethoden bereitstellt. Aber auch beim Verwenden von gepufferten I/O gibt es Risiken, z. B. eingebettete Zeiger, die abgemildert werden müssen.

Weitere Informationen zum Arbeiten mit Puffern in IOCTLs finden Sie unter Methoden für den Zugriff auf Datenpuffer.

Fehler bei der Verwendung von IOCTL-pufferten I/O

  • Überprüfen Sie die Größe der zugehörigen IOCTL-Puffer. Weitere Informationen finden Sie unter Fehler beim Überprüfen der Größe von Puffern.

  • Initialisieren Sie die Ausgabepuffer ordnungsgemäß. Weitere Informationen finden Sie unter Fehler beim Initialisieren von Ausgabepuffern.

  • Überprüfen Sie ordnungsgemäß Puffer mit variabler Länge. Weitere Informationen finden Sie unter Fehler beim Überprüfen Variable-Length Puffer.

  • Achten Sie beim Verwenden von gepufferten I/O darauf, die richtige Länge für den OutputBuffer im Feld IO_STATUS_BLOCK Strukturinformation zurückzugeben. Geben Sie nicht nur die Länge direkt aus einer READ-Anforderung zurück. Betrachten Sie beispielsweise eine Situation, in der die zurückgegebenen Daten aus dem Benutzerbereich angeben, dass ein 4K-Puffer vorhanden ist. Wenn der Treiber tatsächlich nur 200 Bytes zurückgeben sollte, sondern nur 4K im Informationsfeld zurückgibt, ist eine Sicherheitslücke zur Offenlegung von Informationen aufgetreten. Dieses Problem tritt auf, da in früheren Versionen von Windows der Puffer, den der I/O-Manager für Puffer-I/O verwendet, nicht null ist. Daher ruft die Benutzer-App die ursprünglichen 200 Bytes von Daten plus 4K-200 Bytes von dem zurück, was im Puffer war (nicht seitenseitige Poolinhalte). Dieses Szenario kann mit allen Verwendungen von Puffer-I/O und nicht nur mit IOCTLs auftreten.

Fehler in IOCTL direct I/O

Behandeln von Puffern mit null Länge richtig. Weitere Informationen finden Sie unter "Fehler in Direct I/O".

Fehler beim Verweisen auf Benutzerbereichsadressen

TOCTOU-Sicherheitsanfälligkeiten

Es gibt eine potenzielle Zeit der Überprüfung auf die Zeit der Verwendung (TOCTOU) bei der Verwendung von direct I/O (für IOCTLs oder für Lese-/Schreibzugriff). Beachten Sie, dass der Treiber auf den Benutzerdatenpuffer zugreift, kann der Benutzer gleichzeitig darauf zugreifen.

Um dieses Risiko zu verwalten, kopieren Sie alle Parameter, die vom Benutzerdatenpuffer in den Arbeitsspeicher überprüft werden müssen, der ausschließlich über den Kernelmodus (z. B. den Stapel oder pool) zugegriffen werden muss. Sobald auf die Daten nicht von der Benutzeranwendung zugegriffen werden kann, überprüfen Sie die Daten, die übergeben wurden, und arbeiten Sie dann mit den Daten, die übergeben wurden.

Treibercode muss die richtige Verwendung des Arbeitsspeichers vornehmen.

  • Alle Treiberpoolzuweisungen müssen sich im nicht ausführbaren (NX)-Pool befinden. Die Verwendung von NX-Speicherpools ist inhärent sicherer als die Verwendung ausführbarer nicht-pager (NP)-Pools und bietet einen besseren Schutz vor Überlaufangriffen.

  • Gerätetreiber müssen verschiedene Benutzermodus- und Kernel-I/O-Anforderungen ordnungsgemäß verarbeiten.

Um Treibern die Unterstützung der HVCI-Virtualisierung zu ermöglichen, gibt es zusätzliche Speicheranforderungen. Weitere Informationen finden Sie weiter unten in diesem Artikel unter HVCI-Kompatibilität .

Ziehpunkte

Geräteobjekte

Irps

WDF und IRPs

Ein Vorteil der Verwendung von WDF ist, dass WDF-Treiber in der Regel nicht direkt auf IRPs zugreifen. Das Framework konvertiert beispielsweise die WDM-IRPs, die Lese-, Schreib- und Geräte-I/O-Steuerelementvorgänge darstellen, in Framework-Anforderungsobjekte, die KMDF/UMDF in I/O-Warteschlangen empfangen.

Wenn Sie einen WDM-Treiber schreiben, lesen Sie die folgenden Anleitungen.

Ordnungsgemäß verwalten von IRP-I/O-Puffern

Die folgenden Artikel enthalten Informationen zur Überprüfung von IRP-Eingabewerten:

DispatchReadWrite Using Buffered I/O

Fehler in gepufferter E/A

DispatchReadWrite Using Direct I/O

Fehler in Direct I/O

Sicherheitsprobleme für I/O-Kontrollcodes

Erwägen Sie, Werte zu überprüfen, die einem IRP zugeordnet sind, z. B. Pufferadressen und Längen.

Wenn Sie sich für die Verwendung von "Weder I/O" entschieden haben, beachten Sie, dass im Gegensatz zu "Lese- und Schreibzugriff" und im Gegensatz zu "Puffer-I/O" und "Direct I/O" nicht überprüft wird, dass bei Verwendung von "Weder I/O I/OTL" die Pufferzeiger und -längen vom I/O-Manager überprüft werden.

Behandeln von IRP-Abschlussvorgängen ordnungsgemäß

Ein Treiber muss niemals ein IRP mit einem Statuswert von STATUS_SUCCESS abschließen, es sei denn, er unterstützt und verarbeitet das IRP. Informationen zu den richtigen Methoden zum Behandeln von IRP-Abschlussvorgängen finden Sie unter Abschließen von IRPs.

Verwalten des ausstehenden Zustands des Treibers

Der Treiber sollte den IRP ausstehend markieren, bevor er das IRP speichert, und sollte sowohl den Aufruf von IoMarkIrpPending als auch die Zuordnung in einer interlockierten Sequenz berücksichtigen. Weitere Informationen finden Sie unter Fehler beim Überprüfen des Zustands eines Treibers und halten eingehende IRPs, wenn ein Gerät angehalten wird.

Behandeln von IRP-Abbruchvorgängen ordnungsgemäß

Abbrechen von Vorgängen kann schwierig sein, ordnungsgemäß zu codieren, da sie in der Regel asynchron ausgeführt werden. Probleme im Code, der Abbruchvorgänge behandelt, können lange nicht beachtet werden, da dieser Code in der Regel nicht häufig in einem ausgeführten System ausgeführt wird. Lesen und verstehen Sie alle informationen, die unter "Canceling IRPs" bereitgestellt werden. Achten Sie besonders auf die Synchronisierung von IRP-Abbruch und Punkten, die beim Abbrechen von IRPs berücksichtigt werden.

Eine empfohlene Möglichkeit, um die Synchronisierungsprobleme zu minimieren, die mit Abbruchvorgängen verknüpft sind, besteht darin, eine abbruchsichere IRP-Warteschlange zu implementieren.

Behandeln von IRP-Bereinigungs- und Schließenvorgängen ordnungsgemäß

Achten Sie darauf, dass Sie den Unterschied zwischen IRP_MJ_CLEANUP und IRP_MJ_CLOSE Anforderungen verstehen. Bereinigungsanforderungen werden eingetroffen, nachdem eine Anwendung alle Handle eines Dateiobjekts geschlossen hat, aber manchmal, bevor alle E/A-Anforderungen abgeschlossen wurden. Schließen Sie Anforderungen, nachdem alle E/A-Anforderungen für das Dateiobjekt abgeschlossen oder abgebrochen wurden. Weitere Informationen finden Sie in den folgenden Artikeln:

DispatchCreate-, DispatchClose- und DispatchCreateClose-Routinen

DispatchCleanup-Routinen

Fehler beim Behandeln von Bereinigungs- und Schließenvorgängen

Weitere Informationen zum korrekten Behandeln von IRPs finden Sie unter Weitere Fehler bei der Behandlung von IRPs.

Andere Sicherheitsprobleme

  • Verwenden Sie eine Sperre oder eine versperrte Sequenz, um Rennbedingungen zu verhindern. Weitere Informationen finden Sie unter "Fehler in einer Multiprozessorumgebung".

  • Stellen Sie sicher, dass Gerätetreiber verschiedene Benutzermodus- und Kernel-E/A-Anforderungen ordnungsgemäß verarbeiten.

  • Stellen Sie sicher, dass keine TDI-Filter oder LSPs vom Treiber oder zugeordneten Softwarepaketen während der Installation oder Verwendung installiert werden.

Verwenden sicherer Funktionen

Zusätzliche Coderisiken

Zusätzlich zu den möglichen Sicherheitsrisiken, die hier behandelt werden, enthält dieser Artikel zusätzliche Informationen zur Verbesserung der Sicherheit des Kernelmodustreibercode: Erstellen zuverlässiger Kernel-Mode Treiber.

Weitere Informationen zur sicheren Codierung von C und C++ finden Sie am Ende dieses Artikels unter Sichere Codierungsressourcen .

Verwalten der Treiberzugriffskontrolle

Sicherheitschecklisteelement #7:Überprüfen Sie Ihren Treiber, um sicherzustellen, dass Sie den Zugriff ordnungsgemäß steuern.

Verwalten der Treiberzugriffskontrolle – WDF

Treiber müssen funktionieren, um zu verhindern, dass Benutzer unangemessen auf die Geräte und Dateien eines Computers zugreifen. Um nicht autorisierten Zugriff auf Geräte und Dateien zu verhindern, müssen Sie Folgendes ausführen:

  • Benennen Sie Geräteobjekte nur bei Bedarf. Benannte Geräteobjekte sind im Allgemeinen nur aus älteren Gründen erforderlich, z. B. wenn Sie über eine Anwendung verfügen, die erwartet, das Gerät mithilfe eines bestimmten Namens zu öffnen oder wenn Sie ein Nicht-PNP-Gerät/Steuerungsgerät verwenden. Beachten Sie, dass WDF-Treiber ihre PnP-Geräte-FDO nicht benennen müssen, um einen symbolischen Link mithilfe von WdfDeviceCreateSymbolicLink zu erstellen.

  • Sicherer Zugriff auf Geräteobjekte und Schnittstellen.

Damit Anwendungen oder andere WDF-Treiber auf Ihren PnP-Geräte-PDO zugreifen können, sollten Sie Geräteschnittstellen verwenden. Weitere Informationen finden Sie unter Verwenden von Geräteschnittstellen. Eine Geräteschnittstelle dient als symbolische Verknüpfung zum PDO Ihres Gerätestapels.

Eine der besseren Möglichkeiten zum Steuern des Zugriffs auf das PDO besteht darin, eine SDDL-Zeichenfolge in Ihrem INF anzugeben. Wenn sich die SDDL-Zeichenfolge nicht in der INF-Datei befindet, wendet Windows einen Standardsicherheitsdeskriptor an. Weitere Informationen finden Sie unter Sichern von Geräteobjekten und SDDL für Geräteobjekte.

Weitere Informationen zum Steuern des Zugriffs finden Sie in den folgenden Artikeln:

Steuern des Gerätezugriffs in KMDF-Treibern

Namen, Sicherheitsdeskriptoren und Geräteklassen – Barrierefreiheit von Geräteobjekten... und SAFE vom Januar 2017 Der NT Insider Newsletter , der von OSR veröffentlicht wurde.

Verwalten der Treiberzugriffskontrolle – WDM

Wenn Sie mit einem WDM-Treiber arbeiten und ein benanntes Geräteobjekt verwendet haben, können Sie IoCreateDeviceSecure verwenden und eine SDDL angeben, um es zu sichern. Wenn Sie IoCreateDeviceSecure implementieren, geben Sie immer eine benutzerdefinierte Klassen-GUID für DeviceClassGuid an. Sie sollten hier keine vorhandene Klassen-GUID angeben. Dies hat das Potenzial, Sicherheitseinstellungen oder Kompatibilität für andere Geräte zu unterbrechen, die zu dieser Klasse gehören. Weitere Informationen finden Sie unter WdmlibIoCreateDeviceSecure.

Weitere Informationen finden Sie in den folgenden Artikeln:

Steuern des Gerätezugriffs

Steuern des Gerätenamespacezugriffs

Windows Sicherheitsmodell für Treiberentwickler

Sicherheitsbezeichner (SIDs) Risikohierarchie

Im folgenden Abschnitt wird die Risikohierarchie der gängigen SIDs beschrieben, die im Treibercode verwendet werden. Allgemeine Informationen zu SDDL finden Sie unter SDDL für Geräteobjekte, SID-Zeichenfolgen und SDDL-Zeichenfolgensyntax.

Es ist wichtig zu verstehen, dass, wenn niedrigere Berechtigungsanrufer auf den Kernel zugreifen dürfen, das Coderisiko erhöht wird. In diesem Zusammenfassungsdiagramm erhöht sich das Risiko, da Sie den Zugriff auf Ihre Treiberfunktionen mit niedrigeren Berechtigungen zulassen.

SY (System)
\/
BA (Built-in Administrators)
\/
LS (Local Service)
\/
BU (Built-in User)
\/
AC (Application Container)

Konfigurieren Sie nach dem allgemeinen Sicherheitsprinzip für die rechteste Berechtigung nur die mindeste Zugriffsstufe, die für die Funktion Ihres Treibers erforderlich ist.

WDM Granular IOCTL-Sicherheitssteuerung

Um die Sicherheit weiter zu verwalten, wenn IOCTLs von Benutzermodus-Anrufern gesendet werden, kann der Treibercode die IoValidateDeviceIoControlAccess-Funktion enthalten. Diese Funktion ermöglicht es einem Treiber, Zugriffsrechte zu überprüfen. Nach dem Empfang eines IOCTL kann ein Treiber IoValidateDeviceIoControlAccess aufrufen, die FILE_READ_ACCESS, FILE_WRITE_ACCESS oder beides angeben.

Die Implementierung der detaillierten IOCTL-Sicherheitssteuerung ersetzt nicht die Notwendigkeit, den Treiberzugriff mithilfe der oben beschriebenen Techniken zu verwalten.

Weitere Informationen finden Sie in den folgenden Artikeln:

Definieren von I/O-Steuerelementcodes

Überprüfen der HVCI-Kompatibilität

Sicherheitschecklisteelement #8:Überprüfen, ob Der Treiber Speicher verwendet, damit es HVCI kompatibel ist.

Speichernutzung und HVCI-Kompatibilität

HVCI verwendet Hardwaretechnologie und Virtualisierung, um die Entscheidungsfunktion Codeintegrität (CI) von den restlichen Betriebssystemen zu isolieren. Wenn Sie virtualisierungsbasierte Sicherheit verwenden, um CI zu isolieren, kann der Kernelspeicher über eine CI-Überprüfung ausführbarer werden. Das bedeutet, dass Kernelspeicherseiten nie beschreibbar und ausführbar sein können, und ausführbarer Code kann nicht direkt geändert werden.

Um den kompatiblen HVCI-Code zu implementieren, stellen Sie sicher, dass Der Treibercode folgendes ausführt:

  • Aktiviert sich standardmäßig bei NX
  • Verwendet NX-APIs/Flags für die Speicherzuweisung (NonPagedPoolNx)
  • Verwendet keine Abschnitte, die sowohl schreibbar als auch ausführbare Dateien sind
  • Versucht nicht, ausführbare Systemspeicher direkt zu ändern
  • Verwendet keinen dynamischen Code im Kernel
  • Lädt keine Datendateien als ausführbare Datei
  • Die Abschnittsausrichtung ist ein Vielfaches von 0x1000 (PAGE_SIZE). z. B. DRIVER_ALIGNMENT=0x1000

Weitere Informationen zur Verwendung des Tools und einer Liste mit inkompatiblen Speicheraufrufen finden Sie unter "Auswerten der HVCI-Treiberkompatibilität".

Weitere Informationen zu den zugehörigen Systemgrundsicherheitstests finden Sie unter Device Guard - Compliancetest und Treiberkompatibilität mit Device Guard.

Folgen von technologiespezifischen Bewährten Codemethoden

Sicherheitschecklisteelement #9:Überprüfen Sie die folgenden technologiespezifischen Anleitungen für Ihren Treiber.

Dateisysteme

Weitere Informationen zur Sicherheit des Dateisystemtreibers finden Sie in den folgenden Artikeln:

Einführung in die Sicherheit von Dateisystemen

Probleme bei der Sicherheit des Dateisystems

Sicherheitsfeatures für Dateisysteme

Koexistenz mit anderen Dateisystemfiltertreibern

NDIS - Netzwerk

Informationen zur NDIS-Treibersicherheit finden Sie unter Sicherheitsprobleme für Netzwerktreiber.

Anzeige

Informationen zur Sicherheit des Anzeigetreibers finden Sie unter <"Ausstehend">.

Drucker

Informationen zur Sicherheit des Druckertreibers finden Sie unter V4 Printer Driver Security Überlegungen.

Sicherheitsprobleme für Windows Image Acquisition (WIA)-Treiber

Informationen zu WIA-Sicherheit finden Sie unter Sicherheitsprobleme für Windows Image Acquisition (WIA)-Treiber.

Verbessern der Geräteinstallationssicherheit

Sicherheitslistenelement #10:Überprüfen des Treibers inf-Erstellung und Installationsanleitung, um sicherzustellen, dass Sie bewährte Methoden folgen.

Wenn Sie den Code erstellen, der Ihren Treiber installiert, müssen Sie sicherstellen, dass die Installation Ihres Geräts immer sicher ausgeführt wird. Eine sichere Geräteinstallation ist eine, die folgendes ausführt:

  • Beschränkt den Zugriff auf das Gerät und seine Geräteschnittstellenklassen
  • Beschränkt den Zugriff auf die Treiberdienste, die für das Gerät erstellt wurden
  • Schützt Treiberdateien vor Änderung oder Löschung
  • Beschränkt den Zugriff auf die Registrierungseinträge des Geräts
  • Beschränkt den Zugriff auf die WMI-Klassen des Geräts
  • Verwendet SetupAPI-Funktionen ordnungsgemäß

Weitere Informationen finden Sie in den folgenden Artikeln:

Erstellen sicherer Geräteinstallationen

Richtlinien für die Verwendung von SetupAPI

Verwenden von Geräteinstallationsfunktionen

Erweiterte Themen zur Geräte- und Treiberinstallation

Ausführen der Peercodeüberprüfung

Sicherheitslistenelement #11:Durchführen der Peercodeüberprüfung, um nach Problemen zu suchen, die von den anderen Tools und Prozessen nicht angezeigt werden.

Suchen Sie wissende Codeprüfer, um nach Problemen zu suchen, die Sie möglicherweise verpasst haben. Eine zweite Reihe von Augen sieht oft Probleme, die Sie möglicherweise übersehen haben.

Wenn Sie nicht über geeignete Mitarbeiter verfügen, um Den Code intern zu überprüfen, sollten Sie externe Hilfe für diesen Zweck berücksichtigen.

Ausführen der richtigen Treibersignatur

Sicherheitslistenelement #12:Verwenden Sie das Windows Partnerportal, um Ihren Treiber für die Verteilung ordnungsgemäß zu signieren.

Bevor Sie ein Treiberpaket für die Öffentlichkeit freigeben, empfehlen wir Ihnen, das Paket für die Zertifizierung zu übermitteln. Weitere Informationen finden Sie unter "Testen der Leistung und Kompatibilität", Erste Schritte mit dem Hardwareprogramm, den Hardwaredashboarddiensten und dem Signieren eines Kerneltreibers für die öffentliche Version.

Verwenden der Codeanalyse in Visual Studio zur Untersuchung der Treibersicherheit

Sicherheitslistenelement #13:Führen Sie diese Schritte aus, um das Codeanalysefeature in Visual Studio zu verwenden, um Sicherheitsrisiken im Treibercode zu überprüfen.

Verwenden Sie das Codeanalysefeature in Visual Studio, um sicherheitsrisiken in Ihrem Code zu überprüfen. Das Windows Driver Kit (WDK) installiert Regelsätze, die für die Überprüfung von Problemen im systemeigenen Treibercode konzipiert sind.

Weitere Informationen finden Sie unter Ausführen von Code Analysis für Treiber.

Weitere Informationen finden Sie unter Code Analysis für Treiberübersicht. Weitere Hintergründe zur Codeanalyse finden Sie unter Visual Studio 2013 Statischen Code Analysis ausführlicher.

Um mit der Codeanalyse vertraut zu werden, können Sie beispielsweise einen der Beispieltreiber, das empfohlene Toasterbeispiel oder das ELAM Early Launch Anti-Malware-Beispiel https://github.com/Microsoft/Windows-driver-samples/tree/master/general/toaster/toastDrv/kmdf/func/featuredhttps://github.com/Microsoft/Windows-driver-samples/tree/master/security/elamverwenden.

  1. Öffnen Sie die Treiberlösung in Visual Studio.

  2. Ändern Sie in Visual Studio für jedes Projekt in der Lösung die Projekteigenschaften, um den gewünschten Regelsatz zu verwenden. Wählen Sie z. B. Project Eigenschaften >> Code Analysis >>>> Allgemein die Option "Empfohlene Treiberregeln" aus. Verwenden Sie zusätzlich zur Verwendung der recommenced-Treiberregeln die Regelsatz "Empfohlene systemeigene Regeln ".

  3. Wählen Sie "Build >> ausführen" Code Analysis auf Lösung aus.

  4. Anzeigen von Warnungen auf der Registerkarte "Fehlerliste" des Buildausgabefensters in Visual Studio.

Wählen Sie die Beschreibung für jede Warnung aus, um den problematischen Bereich in Ihrem Code anzuzeigen.

Wählen Sie den verknüpften Warnungscode aus, um zusätzliche Informationen anzuzeigen.

Bestimmen Sie, ob Der Code geändert werden muss oder ob eine Anmerkung hinzugefügt werden muss, damit das Codeanalysemodul ordnungsgemäß der Absicht Ihres Codes folgen kann. Weitere Informationen zu Codeanmerkungen finden Sie unter Verwenden von SAL-Anmerkungen zum Reduzieren von C/C++-Codefehlern und SAL 2.0-Anmerkungen für Windows Treiber.

Allgemeine Informationen zu SAL finden Sie in diesem Artikel, der von OSR zur Verfügung steht. https://www.osr.com/blog/2015/02/23/sal-annotations-dont-hate-im-beautiful/

Verwenden der statischen Treiberüberprüfung zum Überprüfen auf Sicherheitsrisiken

Sicherheitslistenelement #14:Führen Sie diese Schritte aus, um statische Treiberüberprüfung (SDV) in Visual Studio zu verwenden, um Sicherheitsrisiken im Treibercode zu überprüfen.

Statische Treiberüberprüfung (SDV) verwendet eine Reihe von Schnittstellenregeln und ein Modell des Betriebssystems, um festzustellen, ob der Treiber mit dem Windows Betriebssystem korrekt interagiert. SDV findet Fehler im Treibercode, der auf potenzielle Fehler in Treibern verweisen könnte.

Weitere Informationen finden Sie unter Einführung der Statischen Treiberüberprüfung und statischen Treiberüberprüfung.

Beachten Sie, dass nur bestimmte Arten von Treibern von SDV unterstützt werden. Weitere Informationen zu den Treibern, die SDV überprüfen können, finden Sie unter Unterstützte Treiber. Weitere Informationen zu den SDV-Tests finden Sie auf den folgenden Seiten, die für den Treibertyp verfügbar sind, mit dem Sie arbeiten.

Um mit SDV vertraut zu werden, können Sie einen der Beispieltreiber verwenden (z. B. das empfohlene Toasterbeispiel: https://github.com/Microsoft/Windows-driver-samples/tree/master/general/toaster/toastDrv/kmdf/func/featured).

  1. Öffnen Sie die Zieltreiberlösung in Visual Studio.

  2. Ändern Sie in Visual Studio den Buildtyp in "Release". Statische Treiberüberprüfung erfordert, dass der Buildtyp freigegeben ist, nicht debuggen.

  3. Wählen Sie in Visual Studio die Option "Buildmappe erstellen>>" aus.

  4. Wählen Sie in Visual Studio die Option ">>Statische Treiberüberprüfung" aus.

  5. Wählen Sie in SDV auf der Registerkarte "Regeln" unter "Regelsätze" die Option "Standard" aus.

    Obwohl die Standardregeln viele häufige Probleme finden, sollten Sie auch die erweiterte Regel " Alle Treiberregeln " ausführen.

  6. Wählen Sie auf der Registerkarte "Haupt " von SDV die Option "Start" aus.

  7. Wenn SDV abgeschlossen ist, überprüfen Sie alle Warnungen in der Ausgabe. Die Registerkarte "Haupt " zeigt die Gesamtzahl der gefundenen Fehler an.

  8. Wählen Sie jede Warnung aus, um die SDV-Berichtsseite zu laden, und untersuchen Sie die Informationen, die der möglichen Coderisiken zugeordnet sind. Verwenden Sie den Bericht, um das Überprüfungsergebnis zu untersuchen und Pfade in Ihrem Treiber zu identifizieren, die eine SDV-Überprüfung fehlschlagen. Weitere Informationen finden Sie unter "Statischer Treiberüberprüfungsbericht".

Überprüfen des Codes mit dem BinSkim Binary Analyzer

Sicherheitslistenelement #15:Führen Sie diese Schritte aus, um BinSkim zu verwenden, um die Kompilierungs- und Buildoptionen zu überprüfen, um bekannte Sicherheitsprobleme zu minimieren.

Verwenden Sie BinSkim, um binäre Dateien zu untersuchen, um Codierungs- und Gebäudepraktiken zu identifizieren, die potenziell die binär anfällige Binärdatei rendern können.

BinSkim sucht nach:

  • Verwendung veralteter Compilertoolsätze – Binärdateien sollten mit den neuesten Compilertoolsätzen kompiliert werden, um die Verwendung der aktuellen Compilerebene und der vom Betriebssystem bereitgestellten Sicherheitsminderungen zu maximieren.
  • Unsichere Kompilierungseinstellungen – Binärdateien sollten mit den sichersten Einstellungen kompiliert werden, um betriebssystembezogene Sicherheitsminderungen zu ermöglichen, Compilerfehler und aktionenbare Warnungen zu berichten.
  • Signaturprobleme – Signierte Binärdateien sollten mit kryptografisch starken Algorithmen signiert werden.

BinSkim ist ein Open Source-Tool und generiert Ausgabedateien, die das Static Analysis Results Interchange Format (SARIF)-Format verwenden. BinSkim ersetzt das ehemalige BinScope-Tool .

Weitere Informationen zu BinSkim finden Sie im BinSkim-Benutzerhandbuch.

Führen Sie diese Schritte aus, um zu überprüfen, ob die Sicherheitskompilierungsoptionen im Code ordnungsgemäß konfiguriert sind, den Sie versenden.

  1. Laden Sie das plattformübergreifende .NET Core SDK herunter und installieren Sie sie.

  2. Bestätigen Sie, Visual Studio installiert ist. Informationen zum Herunterladen und Installieren von Visual Studio finden Sie unter "Installieren Visual Studio".

  3. Es gibt eine Reihe von Optionen zum Herunterladen von BinSkim, z. B. ein NuGet-Paket. In diesem Beispiel verwenden wir die Git-Klonoption zum Herunterladen von hier: https://github.com/microsoft/binskim und installieren Sie es auf einem 64-Bit-Windows PC.

  4. Öffnen Sie ein Visual Studio Entwickler-Eingabeaufforderungsfenster, und erstellen Sie ein Verzeichnis, zC:\binskim-master. B. .

    C:\> Md \binskim-master
    
  5. Wechseln Sie zu diesem Verzeichnis, das Sie gerade erstellt haben.

    C:\> Cd \binskim-master
    
  6. Verwenden Sie den Git-Klonbefehl, um alle erforderlichen Dateien herunterzuladen.

    C:\binskim-master> git clone --recurse-submodules https://github.com/microsoft/binskim.git
    
  7. Wechseln Sie zur neuen binskim Dirctory, die der erstellte Klonbefehl erstellt hat.

    C:\> Cd \binskim-master\binskim
    
  8. Führen Sie BuildAndTest.cmd aus, um sicherzustellen, dass der Release-Build erfolgreich ist, und dass alle Tests übergeben werden.

    C:\binskim-master\binskim> BuildAndTest.cmd
    
    Welcome to .NET Core 3.1!
    ---------------------
    SDK Version: 3.1.101
    
    ...
    
    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64\BinSkim.Sdk.dll
    1 File(s) copied
    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\linux-x64\BinSkim.Sdk.dll
    1 File(s) copied
    
    ...
    
    
  9. Der Buildprozess erstellt eine Reihe von Verzeichnissen mit den ausführbaren BinSkim-Dateien. Wechseln Sie zum Win-x64-Buildausgabeverzeichnis.

    C:\binskim-master\binskim> Cd \binskim-master\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64>
    
  10. Zeigen Sie Hilfe für die Analyseoption an.

    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim help analyze
    
    BinSkim PE/MSIL Analysis Driver 1.6.0.0
    
    --sympath                      Symbols path value, e.g., SRV*http://msdl.microsoft.com/download/symbols or Cache*d:\symbols;Srv*http://symweb. See
                                  https://docs.microsoft.com/windows-hardware/drivers/debugger/advanced-symsrv-use for syntax information. Note that BinSkim will clear the
                                  _NT_SYMBOL_PATH environment variable at runtime. Use this argument for symbol information instead.
    
    --local-symbol-directories     A set of semicolon-delimited local directory paths that will be examined when attempting to locate PDBs.
    
    -o, --output                   File path to which analysis output will be written.
    
    --verbose                      Emit verbose output. The resulting comprehensive report is designed to provide appropriate evidence for compliance scenarios.
    
    ...
    
    

Festlegen des Symbolpfads

Wenn Sie alle Code erstellen, den Sie auf demselben Computer analysieren, auf dem Sie BinSkim ausführen, müssen Sie in der Regel keinen Symbolpfad festlegen. Dies liegt daran, dass Ihre Symboldateien im lokalen Feld verfügbar sind, in dem Sie kompiliert wurden. Wenn Sie ein komplexeres Buildsystem verwenden oder Ihre Symbole an unterschiedliche Speicherorte umleiten (nicht zusammen mit der kompilierten Binärdatei), verwenden --local-symbol-directories Sie diese Speicherorte zur Symboldateisuche. Wenn Ihr Code auf eine kompilierte Binärdatei verweist, die nicht Teil Ihres Codes ist, kann der Fenster-Debugger-Sympath verwendet werden, um Symbole abzurufen, um die Sicherheit dieser Codeabhängigkeiten zu überprüfen. Wenn Sie ein Problem in diesen Abhängigkeiten finden, können Sie sie möglicherweise nicht beheben. Es kann jedoch nützlich sein, dass Sie über jedes mögliche Sicherheitsrisiko informiert werden, das Sie akzeptieren, indem Sie diese Abhängigkeiten übernehmen.

Tipp

Fügen Sie beim Hinzufügen eines Symbolpfads (der auf einen Netzwerksymbolserver verweist) einen lokalen Cachespeicherort hinzu, um einen lokalen Pfad zum Cache der Symbole anzugeben. Dies kann die Leistung von BinSkim erheblich kompromittieren. Im folgenden Beispiel wird ein lokaler Cache bei d:\Symbols angegeben. --sympath Cache*d:\symbols;Srv*http://symwebWeitere Informationen zu Sympath finden Sie unter Symbolpfad für Windows Debugger.

  1. Führen Sie den folgenden Befehl aus, um eine kompilierte Treiber-Binärdatei zu analysieren. Aktualisieren Sie den Zielpfad, um auf Ihren erfüllten Treiber .sys Datei zu verweisen.

    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim analyze "C:\Samples\KMDF_Echo_Driver\echo.sys"
    
  2. Für zusätzliche Informationen fügen Sie die ausführliche Option wie folgt hinzu.

    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim analyze "C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys" --verbose
    

    Hinweis

    Die Option --verbose erzeugt explizite Pass-/Fehlerergebnisse für jede Überprüfung. Wenn Sie keine Verbose bereitstellen, werden nur die Mängel angezeigt, die BinSkim erkennt. Die Option "-verbose" wird in der Regel aufgrund der erhöhten Größe von Protokolldateien nicht für tatsächliche Automatisierungssysteme empfohlen und da es schwieriger ist, einzelne Fehler beim Auftreten aufzuheben, da sie in die Mitte einer großen Anzahl von "Pass"-Ergebnissen eingebettet werden.

  3. Überprüfen Sie die Befehlsausgabe, um nach möglichen Problemen zu suchen. In dieser Beispielausgabe werden drei Tests angezeigt, die bestanden wurden. Weitere Informationen zu den Regeln, z. B. BA2002, stehen im BinSkim-Benutzerhandbuch zur Verfügung.

    Analyzing...
    Analyzing 'osrusbfx2.sys'...
    ...
    
    C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys\Debug\osrusbfx2.sys: pass BA2002: 'osrusbfx2.sys' does not incorporate any known vulnerable dependencies, as configured by current policy.
    C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: pass BA2005: 'osrusbfx2.sys' is not known to be an obsolete binary that is vulnerable to one or more security problems.
    C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys: pass BA2006: All linked modules of 'osrusbfx2.sys' generated by the Microsoft front-end satisfy configured policy (compiler minimum version 17.0.65501.17013).
    
  4. Diese Ausgabe zeigt, dass der Test BA3001 nicht ausgeführt wird, da das Tool angibt, dass der Treiber keine ELF-Binärdatei ist.

    ...
    C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: notapplicable BA3001: 'osrusbfx2.sys' was not evaluated for check 'EnablePositionIndependentExecutable' as the analysis is not relevant based on observed metadata: image is not an ELF binary.
    
  5. Diese Ausgabe zeigt einen Fehler für test BA2007.

    ...
    
    C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: error BA2007: 'osrusbfx2.sys' disables compiler warning(s) which are required by policy.
    A compiler warning is typically required if it has a high likelihood of flagging memory corruption, information disclosure, or double-free vulnerabilities.
    To resolve this issue, enable the indicated warning(s) by removing /Wxxxx switches (where xxxx is a warning id indicated here) from your command line, and resolve any warnings subsequently raised during compilation.
    

Um diese Warnungen in Visual Studio zu aktivieren, entfernen Sie unter C/C++ in den Eigenschaftenseiten für das Projekt die Werte, die Sie nicht in "Bestimmte Warnungen deaktivieren" ausschließen möchten.

dialog box for disable specific warnings in Visual Studio 2019.

Die Standardkompilierungsoptionen in Visual Studio für Treiberprojekte können Warnungen wie die folgenden deaktivieren. Diese Warnungen werden von BinSkim gemeldet.

C4603 – "Name": Makro ist nicht definiert oder definition ist nach der Verwendung vorkompilierter Kopfzeilen unterschiedlich.

C4627 – "beschreibung": beim Suchen nach vorkompilierten Headern übersprungen

C4986 – "Deklaration": Ausnahmespezifikation stimmt nicht mit der vorherigen Deklaration überein.

Weitere Informationen zu den Compilerwarnungen finden Sie unter Compilerwarnungen nach Compilerversion.

Verwenden zusätzlicher Codeüberprüfungstools

Sicherheitsprüflisteelement #16:Verwenden Sie diese zusätzlichen Tools, um zu überprüfen, ob Ihr Code Sicherheitsempfehlungen folgt, und um Lücken zu prüfen, die in Ihrem Entwicklungsprozess verpasst wurden.

Verwenden Sie neben Visual Studio Code Analyse, statischer Treiberüberprüfung und Binskim oben beschriebene Tools die folgenden Tools, um Lücken zu untersuchen, die in Ihrem Entwicklungsprozess verpasst wurden.

Treiberüberprüfung

Die Treiberüberprüfung ermöglicht live tests des Treibers. Die Treiberüberprüfung überwacht Windows Kernelmodustreiber und Grafiktreiber, um illegale Funktionsaufrufe oder Aktionen zu erkennen, die das System möglicherweise beschädigt haben. Die Treiberüberprüfung kann den Windows Treibern eine Vielzahl von Belastungen und Tests zuweisen, um fehlerhaftes Verhalten zu finden. Weitere Informationen finden Sie unter Driver Verifier.

Tests des Hardwarekompatibilitätsprogramms

Das Hardwarekompatibilitätsprogramm enthält sicherheitsbezogene Tests können verwendet werden, um nach Coderisiken zu suchen. Das Windows Hardwarekompatibilitätsprogramm nutzt die Tests im Windows Hardware Lab Kit (HLK). Die HLK-Gerätegrundwerte können in der Befehlszeile verwendet werden, um Treibercode zu üben und die Schwäche zu testen. Allgemeine Informationen zu den Grundlagentests des Geräts und dem Hardwarekompatibilitätsprogramm finden Sie unter Windows Hardware Lab Kit.

Die folgenden Tests sind Beispiele für Tests, die hilfreich sein können, um Treibercode auf einige Verhaltensweisen zu überprüfen, die mit Coderisiken verbunden sind:

DF – Fuzz – Zufälliger IOCTL-Test (Zuverlässigkeit)

DF – Fuzz – Test zum Öffnen von Sub (Zuverlässigkeit)

DF – Fuzz – FSCTL-Test auf Puffer mit Länge null (Zuverlässigkeit)

DF – Fuzz – Zufälliger FSCTL-Test (Zuverlässigkeit)

DF – Fuzz – Sonstiger API-Test (Zuverlässigkeit)

Sie können auch die Kernelsynchronisierungsverzögerung verwenden, die in der Treiberüberprüfung enthalten ist.

Die CHAOS-Tests (Gleichzeitige Hardware und Betriebssystem) führen verschiedene PnP-Treibertests, Gerätetreiber-Fuzztests und Systemtests gleichzeitig aus. Weitere Informationen finden Sie unter CHAOS Tests (Device Fundamentals).

Die Gerätegrunddurchdringungstests führen verschiedene Arten von Eingabeangriffen aus, die eine wichtige Komponente der Sicherheitstests sind. Angriffs- und Penetrationstests können dabei helfen, Schwachstellen in Softwareschnittstellen zu identifizieren. Weitere Informationen finden Sie unter Penetrationstests (Gerätegrundsätze).

Verwenden Sie den Device Guard - Compliance-Test zusammen mit den anderen tools, die in diesem Artikel beschrieben werden, um zu bestätigen, dass Ihr Treiber HVCI kompatibel ist.

Benutzerdefinierte und domänenspezifische Testtools

Berücksichtigen Sie die Entwicklung benutzerdefinierter domänenspezifischer Sicherheitstests. Um zusätzliche Tests zu entwickeln, sammeln Sie Eingaben aus den ursprünglichen Designern der Software sowie nicht zusammenhängende Entwicklungsressourcen, die mit der spezifischen Art des entwickelten Treibers vertraut sind, und eine oder mehrere Personen, die mit sicherheitsrelevanter Angriffsanalyse und -prävention vertraut sind.

Überprüfen von Debuggertechniken und Erweiterungen

Sicherheitsprüflisteelement #17:Überprüfen Sie diese Debuggertools, und berücksichtigen Sie deren Verwendung in Ihrem Entwicklungsdebuggingworkflow.

Die Erweiterungsformate von !acl und zeigt den Inhalt einer Zugriffssteuerungsliste (Access Control List, ACL) an. Weitere Informationen finden Sie unter Ermitteln der ACL eines Objekts und !acl.

Die Erweiterung !token zeigt eine formatierte Ansicht eines Sicherheitstokenobjekts an. Weitere Informationen finden Sie unter !token.

Die Erweiterung !tokenfields zeigt die Namen und Offsets der Felder innerhalb des Zugriffstokenobjekts (die TOKEN-Struktur) an. Weitere Informationen finden Sie unter !tokenfields.

Die !sid-Erweiterung zeigt den Sicherheitsbezeichner (SID) an der angegebenen Adresse an. Weitere Informationen finden Sie unter !sid.

Die !sd-Erweiterung zeigt den Sicherheitsdeskriptor an der angegebenen Adresse an. Weitere Informationen finden Sie unter !sd.

Überprüfen von Ressourcen für sichere Codierung

Sicherheitsprüflisteelement #18:Überprüfen Sie diese Ressourcen, um Ihr Verständnis der bewährten Methoden für die sichere Codierung zu erweitern, die für Treiberentwickler gelten.

Überprüfen Sie diese Ressourcen, um mehr über die Treibersicherheit zu erfahren

Richtlinien für sicheres Kernelmodustreiber-Codieren

Erstellen zuverlässiger Kernel-Mode Treiber

Sichere Codierung von Organisationen

Carnegie Mellon University SEI CERT

Carnegie Mellon University SEI CERT C Coding Standard: Regeln für die Entwicklung von Tresor, zuverlässigen und sicheren Systemen (2016 Edition).

CERT – Build Security In

MITRE - Schwachstellen, die vom CERT C Secure Coding Standard behandelt werden

Building Security In Maturity Model (BSIMM) - https://www.bsimm.com/

SAFECode - https://safecode.org/

OSR

OSR bietet Treiberentwicklungs- und Beratungsleistungen. Diese Artikel aus dem OSR-Newsletter heben Treibersicherheitsprobleme hervor.

Namen, Sicherheitsdeskriptoren und Geräteklassen – Barrierefreie Geräteobjekte... und SICHER

Sie haben Gotta Use Protection -- Inside Driver & Device Security

Sperren von Treibern – Eine Umfrage über Techniken

Meltdown und Spectre: Was ist mit Treibern?

Fallstudie

Von Warnung zu Treiberrisiko: Microsoft Defender ATP-Untersuchung entdeckt Berechtigungskalationsfehler

Bücher

24 tödliche Sünden der Softwaresicherheit : Programmierfehler und wie sie von Michael Howard, David LeBlanc und John Viega behoben werden

Die Kunst der Softwaresicherheitsbewertung : Identifizieren und Verhindern von Softwarerisiken, Mark Dowd, John McDonald und Justin Schuh

Schreiben von Secure Software Second Edition, Michael Howard und David LeBlanc

Art of Software Security Assessment: Identifizieren und Verhindern von Software-Schwachstellen, Mark Dowd und John McDonald

Sichere Codierung in C und C++ (SEI Series in Software Engineering) 2. Edition, Robert C. Seacord

Programmieren des Microsoft Windows Treibermodells (2. Edition), Walter Oney

Entwickeln von Treibern mit der Windows Driver Foundation (Entwicklerreferenz), Penny Orwick und Guy Smith

Training

Windows Schulungstraining für Fahrer ist von Anbietern wie folgenden verfügbar:

Sicheres Codieren von Onlineschulungen ist aus einer Vielzahl von Quellen verfügbar. Dieser Kurs ist z. B. von Kursra verfügbar:

https://www.coursera.org/learn/software-security.

SAFECode bietet auch kostenlose Schulungen:

SAFECode.org/training

Professional Zertifizierung

CERT bietet eine Secure Coding Professional Zertifizierung an.

Zusammenfassung der wichtigsten Erkenntnisse

Die Treibersicherheit ist ein komplexes Unternehmen mit vielen Elementen, aber hier sind einige wichtige Punkte zu berücksichtigen:

  • Treiber leben im Windows-Kernel, und beim Ausführen im Kernel wird das gesamte Betriebssystem verfügbar gemacht. Achten Sie daher auf die Sicherheit und das Design des Fahrers mit Berücksichtigung der Sicherheit.

  • Wenden Sie das Prinzip der geringsten Berechtigungen an:

    a. Verwenden einer strengen SDDL-Zeichenfolge zum Einschränken des Zugriffs auf den Treiber

    b. Weitere Einschränkungen einzelner IOCTL-Daten

  • Erstellen Sie ein Bedrohungsmodell, um Angriffsvektoren zu identifizieren und zu berücksichtigen, ob alles weiter eingeschränkt werden kann.

  • Achten Sie bei eingebetteten Zeigern, die vom Benutzermodus übergeben werden. Sie müssen geprüft werden, innerhalb von Versuchen darauf zugreifen, außer, und sie sind anfällig für Zeit der Überprüfungszeit (ToCToU) Probleme, es sei denn, der Wert des Puffers wird erfasst und verglichen.

  • Wenn Sie unsicher sind, verwenden Sie METHOD_BUFFERED als IOCTL-Puffermethode.

  • Verwenden Sie Codescan-Dienstprogramme, um nach bekannten Coderisiken zu suchen und identifizierte Probleme zu beheben.

  • Suchen Sie wissende Codeprüfer, um nach Problemen zu suchen, die Sie möglicherweise verpasst haben.

  • Verwenden Sie Treiberprüfer, und testen Sie Ihren Treiber mit mehreren Eingaben, einschließlich Eckenfällen.