• [Driver] v0.1 -Windows

    Ich beschäftige mich momentan sehr stark mit dem Thema Rootkits und programmiere somit
    zwangsweise (aber mit Spass) Treiber (Rootkit15.07.2010).
    Hier möchte ich einen Einblick in die Treiber-Programmierung geben.
    Ich denke, es werden Tutorials folgen, welche auf diesem aufbauen.
    Update 24.10.2011: Windows Vista und 7


    Was wird benötigt?


    Das Device Driver Developement Kit
    Um unseren Windows-Gerätetreiber zu erstellen, brauchen wir das Driver Developement Kit (DDK). Das DDK wurde inzwischen von Microsoft durch das Windows Driver Kit (WDK) ersetzt. (Bei meinem noch hoffentlich folgenden Tutorial für Windows 7 wird dieses dann verwendet werden)

    DDK Installieren (15.07.2010)


    Die Build Umgebung

    Von dem DKK werden zwei verschiedene Build-Umgebungen zur Verfügung gestellt: zum einen die geprüfte (checked) und zum anderen die freie (free). Bei dem geprüften Buil werden die Debugging-Tests des DDKs mit in den Treiber kompilier, wodurch der Treiber wesentlich größer ist als in der freien Version. Verwenden Sie den geprüften Build für dieses Tutorial und ihre Entwicklungsarbeit. Der freie Build sollte ausschließlich zum testen eines fertigen Produkts verwendet werden.


    Welche Dateien werden benötigt?
    Der Treiberquellcode wird in C geschrieben. Für ein Projekt legen Sie ein leeres Verzeichnis an (z.B. C:\mydriver)

    Der Quellcode

    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    
    #include "ntddk.h"
     
    NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
    {
        DbgPrint("Hello World!");
        return STATUS_SUCCESS;
    }
    Das war einfach oder? Wenn dieser Code in den Kernel geladen, dann wird die Debug-Anweisung Hello World! ausgegeben.


    SOURCES
    Erstellen Sie nun eine Datei namens SOURCES unzwar in Großbuchstaben und ohne Erweiterung mit folgendem Code:
    Code :
    1
    2
    3
    4
    
    TARGETNAME = MYDRIVER
    TARGETPATH = OBJ
    TARGETTYPE = DRIVER
    SOURCES    = mydriver.c
    Die Vairiable TARGETNAME gibt den Namen des Treibers an.
    Die Variable TARGETPATH gibt an wo die Dateien paltziert werden sollen. Im Normalfall geschieht dies in dem Unterordner objchk_.../i386 des aktuellen Verzeichnisses.
    Die Variable TARGETTYPE beschreibt welche Art von Datei kompiliert werden soll.

    Mit Microsoft DDKs ist es auch mögliche "normale" ausführbare Programme zu erstellen. In diesem Fall müsste TARGETTYPE auf PROGRAM gesetzt werden. Es gibt auch noch weitere Typen wie z.B. DRIVER_LIBRARY oder DYNLINK.

    Die Variable SOURCES beschreibt eine Liste von .c-Dateien. Falls Sie mehrere Dateien benötigen schreiben Sie ein \ (Backlslash) an jedes Ende einer Zeile auf die eine weitere folgt, wie z.B.:
    Code :
    1
    2
    3
    4
    
    SOURCES = file1.c \
            = file2.c \
            = file3.c \
            = file4.c


    Es ist möglich zusätzlich die Variable INCLUDES zu verwenden, welche die Verzeichnisse der Include-Dateien angibt:
    Code :
    1
    2
    3
    
    INCLUDES = C:\ includes \
               ... \ inc \ ... \
               C:\ my_includes


    Desweiteren steht die Variable TARGETLIBS zur Verfügung. Diese wird zum Linken von Bibliotheken benötigt. Da evtl. die NDIS-Bibliothek in nachfoglenden Tutorials verwendet wird gebe ich dieses als Beispiel hier an:
    Code :
    1
    
    TARGETLIBS = $(DDK_LIB_PATH)\ndis.lib



    MAKEFILE
    Zu guter letzt benötigen wird noch ein Makefile. Also legen Sei wieder eine Datei names MAKEFILE in Großbuchstaben und ohne Erweiterung an. Hier benötigen wir nur eine Zeile:
    Code :
    1
    
    !INCLUDE $(NTMAKEENV)\makefile.def



    Endladeroutine
    Der main-Funktion eines Treiber wird immer ein theDriverObject-Armgument übergeben. Dieses zeigt auf eine Dateunstruktur von Funktionszeigern. Von diesem ist einer die Endladeroutine. Wenn wir nun also diesen Zeiger setzen, dann können wir den Treiber aus dem Speicher entladen. Ohne ein setzen diese Zeiger ist es nur möglich den Treiber in den Speicher zu laden, d.h. um den Treiber wieder aus dem Speicher zu entfernen muss der Computer neu gestartet werden.
    In der Entwicklung müssen wir jedoch den Treiber mehrmals laden und entladen um die jeweils neue Version zu testen.
    Um die Entladeroutine zu setzen müssen wir nur eine Entladefunktion erstellen und dann den Zeiger auf diese setzten:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    // unser erster Gerätetreiber
     
    #include "ntddk.h"
     
    VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
    {
        DbgPrint("OnUnload\n");
    }
     
    NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
    {
        DbgPrint("My Driver loaded!");
        // Den Zeiger in theDriverObject
        // auf die Entladefunktion setzten
        theDriverObject->DriverUnload  = OnUnload; 
        return STATUS_SUCCESS;
    }

    So nun hätten wir ein sicheres laden und entladen gewährleistet.


    Den Treiber erstellen
    So wir haben nun MAKEFILE, SOURCES und die .c-Dateien. Nun können wir unseren Treiber erstellen. Dazu benötigen wir die geprüfte Build-Umgebung des DDKs. Diese starten Sie im Startmenü unter Programme in der Gruppe Development Kits. Nun öffnet sich die Shell der Build-Umgebung. Wechseln Sie in das Verzeichnis ihres Treibers, z.B. cd c:\mydriver (der Befehl cd weist an das Verzeichnis zu wechseln). Nun geben Sie den Befehlt build ein. Im Idealfall sollten keine Fehler auftreten und Sie haben nun Ihren ersten eigenen Treiber.
    TIPP: keinen Pfad mit Leerzeichen verwenden, dies kann zu Fehlern führen.


    Treiber laden und entladen
    Zum laden und entladen unseres Treibers verwenden wir das Tool InstDrv. Dieses können Sie z.B. auf rootkit.com herunterladen

    InstDrv Herunterladen (16.07.2010)

    Mit diesem Tool können Sie ihren Treiber registrieren, starten und beenden.
    Für den echten Einsatz benötigen Sie eine bessere Methode zum laden ihres Treibers, aber in der Entwicklung ist diese Tool sehr hilfreich. Das laden eines Treiber mit Ihrem eigenen Programm wird in dem 3. Tutorial behandelt.


    Debug-Anweisungen anzeigen lassen
    Mit Debug-Aweisungen können Sie wichtige Informationen protokollieren. Oftmals ist dies einfacher als die Verwendung eines Debuggers (z.B. SoftIce oder WinDbg), mit welchem Sie alles in einzelnen Schritten durchgehen müssen.
    Um Debug-Aweisungen anzuzeigen benötigen Sie ein Toll um diese zu erfassen. Ich verwenden hierzu DebugView.

    DebugView Download (von http://technet.microsoft.com/de-de/s.../bb842059.aspx 18.07.2010)

    Code cpp:
    1
    
    DbgPrint("something or other");
    Mit Funtktion DbgPrint() können Sie unter Windows Debug-Anweisungen von Treibern ausgeben lassen.

    Der Sourcecode, Makefile, Sourcefile sowie ein kompilierte Version für ein 32bit System sind im Anhang.

    Windows Vista und 7: Folgende Änderungen sind zu beachten

    Statt dem DDK braucht man das WDK (Windows Driver Kit). Windows hat die weiterentwicklung des DDK seit Windows Vista [?!] eingestellt und entwickelt nun das WDK weiter.
    Nun der wichtigste Unterschied zur vorherigen Entwicklung ist, dass man seit Windows Vista eine treiber Signatur benötigt, damit man den Treiber laden kann.
    Ein Windows Zertifikat [wut] für Treiber kosted natürlich etwas und somit braucht man ein neues Tool um diese Schikane zu umgehen.
    Im Anhang befinden sich alle notwendigen Tools:
    - DebugView (64/32bit)
    - DriverSignatureEnforcement (umgeht die Treiber Signatur)
    - OSRLoader (statt InstDriver)

    Um nun einen Treiber zu laden started man die Anwendung DriverSignatureEnforcement, aktiviert den Testmode und started anschließen das OS neu.
    Wenn man ein Treiber mittels WDK erstellt hat muss man ihn mittels DriverSignatureEnforcement signieren und danach kann man ihn laden.

    Ich empfehle statt dem Programm InstDriver das Programm OSRLoader zum Laden und Entladen seines Treibers zu verwenden (bessere Kompatibilität ab Windows Vista) (Dieses ist auch im Anhang enthalten).

    WDK

    Das WDK is dem DDK ziemlich gleich. Es gibt vieles neue Features, ein paar veraltete Dinge werden nicht mehr unterstützt und es macht das Debuggen wesentlich leichter.
    Die Build Umgebung findet man im Startmenü unter Programme in der Gruppe Windows Driver Kits, dann WDK und die aktuelle Versionsnummer -> Build Environments -> Ziel OS
    Unterstütz werden:
    - Windows 7
    - Windows Vista und Server 2008
    - Windows XP
    - Windows Server 2003

    How to get the WDK

    Um im DebugView unter Windows 7 DbgPrint Events abzufangen muss man Capture Kernel, Enable Verbose Kernel Output und Capture Events aktivieren.
    So dies war meiner Meinung nach alles nötige um auf Windows 7 und oder 64bit Windows Systeme umzusteigen

    Der Sourcecode, Makefile, Sourcefile sowie ein kompilierte Version für Windows 7 64bit (Treiberfile nur für AMD) sind im Anhang.

    ---

    So das war es fürs erste von mir. Ich hoffe es hat euch gefallen, denn dies war mein erstes Tutorial überhaupt weltweit .
    In dem nächsten Tutorial wird dann die Kommunikation zwischen einem Treiber und einem eigenen Programm behandelt.

    Rechtschreib und Grammatikfehler dienen ausschließlich zur Überprüfung ihrer Kenntnisse im Deutschen und sind nicht unabsichtlich beim Schreiben entstanden.

    Ich bitte natürlich um ein Feedback.

    Man liest sich
    Tschöö

    Anhänge
    [Driver] v0.1 -Windows (XP).zip
    Tools.rar
    [Driver] v0.1b -Windows [7] - WDK.rar‎


    Hier geht es zum zweiten Teil:
    Tutorial 2 || Einführung in die Gerätetreiberprogrammierung unter Windows
     


     
    Kommentare 6 Kommentare
    1. Avatar von 2downtown
      2downtown -
      Interessante Anleitung. Hatte zwar erst Probleme mit 64bit w7, hab es aber dann doch hinbekommen
      Geht es noch weiter? Wenn ja bin auf die Fortsetzung gespannt.
    1. Avatar von Schattenschlag
      Schattenschlag -
      Jup kann nur sagen sehr nett und gut geschrieben ...

      hoffe auch auf einen nette kleine Fortsetzung
    1. Avatar von 3Cyb3r
      3Cyb3r -
      Es geht die Tage weiter und das Update mit W7 und 64bit ist nun auch drin
    1. Avatar von Bratkartoffel
      Bratkartoffel -
      Zwar bisher nur überflogen, sieht aber ganz gut aus. Werde es heute Abend mal ausprobieren
      Freu mich auch schon auf die angekündigten Neuerungen
    1. Avatar von Kurmis
      Kurmis -
      Bei mir sieht es so aus
      >cd C:\mydriver

      C:\mydriver>dir
      15/11/2011 10:19 37 MAKEFILE
      15/11/2011 10:30 699 mydriver.c
      15/11/2011 10:14 85 SOURCES

      Welche Datei muss gespeichert als mydriver.c ****
      Diese da : ?

      #include "ntddk.h"

      VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
      {
      DbgPrint("OnUnload\n");
      }

      NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
      {
      DbgPrint("My Driver loaded!");
      // Den Zeiger in theDriverObject
      // auf die Entladefunktion setzten
      theDriverObject->DriverUnload = OnUnload;
      return STATUS_SUCCESS;
      }

      oder diese

      #include "ntddk.h"

      NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
      {
      DbgPrint("Hello World!");
      return STATUS_SUCCESS;
      }
    1. Avatar von 3Cyb3r
      3Cyb3r -
      Also, wenn du den Treiber entladen möchtest ohne Neustart, wäre es sinnvoll die Entladeroutine zu deklarieren. Btw es funktioniert beides - jedoch rate ich dir erst einaml C? oder Programmieren / ein Grundkentniss anzueignen bevor du dir mit der Treiberprogrammiereung deinen PC zerschießt. Wenn du weißt, was VM-Ware ist, und damit arbeiten kannst, ist ein geeigneter Zeitpunkt hier weiter zu machen.