Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: xevuel
WinAPI i Windows

Tworzenie i uruchamianie sterowników w systemie Windows 7 x64

[artykuł] Artykuł opisuje, w jaki sposób można stworzyć i uruchomić swój własny sterownik w systemie Windows 7 x64 przy użyciu Windows Driver Kit w wersji 7.1.

Przygotowanie środowiska pracy

Zacznijmy od przygotowania środowiska. Będzie nam potrzebne WDK (Windows Driver Kit), w wersji 7.1, która umożliwia tworzenie sterowników pod systemy Windows XP, Vista oraz 7. Gwoli ścisłości należy wspomnieć, że najnowszą obecnie wersją jest WDK 8, która obsługuje Windows 8, ale nie zadziała już na XP.
Jest ono dostępne do pobrania stąd: WDK 7.1. Plik ISO po pobraniu należy nagrać na płytę, lub zamontować jako wirtualny napęd w systemie. Następną wymaganą czynnością jest odpalenie instalatora z tego napędu. Podczas instalacji najlepiej jest zaznaczyć wszystkie możliwe komponenty, chyba że jesteśmy pewni, że któryś z nich się nam nie przyda.

Kompilacja przykładowego sterownika

Po zainstalowaniu WDK utwórzmy folder, gdzie będą się znajdować źródła naszego sterownika, nazwijmy go MyDriver. Niech będzie to C:\MyDriver. Należy w nim umieścić pliki:
  • MyDriver.c:
    C/C++
    #include <ntddk.h>

    DRIVER_INITIALIZE DriverEntry;
    DRIVER_UNLOAD OnUnload;

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

    NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
    {
        DbgPrint( "Hello world!" );
       
        theDriverObject->DriverUnload = OnUnload;
        return STATUS_SUCCESS;
    }
  • SOURCES:
    TARGETNAME=MyDriver
    TARGETPATH=obj
    TARGETTYPE=DRIVER

    SOURCES=MyDriver.c
  • MAKEFILE:
    !INCLUDE $(NTMAKEENV)\makefile.def

Po czym możemy już skompilować sterownik. W tym celu otwieramy Menu Start, wskazujemy kolejno Windows Driver Kits -> WDK 7600.16385.1 -> Build Environments -> Windows 7 -> x64 Free Build Environment. W oknie konsoli przechodzimy do katalogu C:\MyDriver i wpisujemy build. Powinniśmy otrzymać output o mniej więcej takiej postaci:
BUILD: Compile and Link for AMD64
BUILD: Loading c:\winddk\7600.16385.1\build.dat...
BUILD: Computing Include file dependencies:
BUILD: Start time:
BUILD: Examining c:\mydriver directory for files to compile.

    c:\mydriver Invalidating OACR warning log for 'root:amd64fre'
BUILD: Saving c:\winddk\7600.16385.1\build.dat...
BUILD: Compiling and Linking c:\mydriver directory
Configuring OACR for 'root:amd64fre' - <OACR on>
Compiling - mydriver.c
Linking Executable - objfre_win7_amd64\amd64\mydriver.sys
BUILD: Finish time:
BUILD: Done

    3 files compiled - 4 Warnings
    1 executable built
Nasz sterownik pojawił się teraz w lokalizacji C:\MyDriver\objfre_win7_amd64\amd64\mydriver.sys.

Podpisanie cyfrowe sterownika

Mamy sterownik, ale próba uruchomienia go w tej chwili zakończy się najprawdopodobniej otrzymaniem kodu błędu 577 (» WinAPISystemowe kody błędów (500-999)). Dlaczego tak się dzieje? Otóż, od czasów Visty wszystkie sterowniki działające przy systemach x64 muszą być podpisane, aby można było je uruchomić. Taka mała niewygoda dla twórców rootkitów ;) Wiadomo jednak, że deweloper nie szejk katarski, pieniędzy łatwo wydawać nie chce. W związku z tym, stworzono coś, co nazywa się TESTSIGNING. Polega to na tym, że system zgodzi się na załadowanie wszystkich sterowników, które są podpisane jakimkolwiek certyfikatem, ale podpisane być muszą. Jak to włączyć? Potrzebne będą niestety uprawnienia administratora. Uruchamiamy cmd.exe, właśnie jako administrator, i wpisujemy następujące polecenie:
Bcdedit.exe -set TESTSIGNING ON


Wykonajmy teraz jeszcze jedną czynność. Teoretycznie powinna być opisana na końcu, ale żeby nie restartować komputera kilka razy, wspomniana będzie tutaj, a omówiona na końcu.
Uruchamiamy edytor rejestru i przechodzimy do klucza HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter. Jeśli nie mamy go w rejestrze, należy go stworzyć. Następnie tworzymy nową wartość typu DWORD o nazwie DEFAULT i ustawiamy jej dane na 0xffffffff lub, w dziesiątkowym, na 4294967295. Następnie restartujemy komputer.

Nasz system powinien teraz obsługiwać testowe podpisywanie. Aby sprawdzić, czy to faktycznie działa, wystarczy popatrzyć na któryś z rogów pulpitu, czy znajduje się tam informacja o systemie i kompilacji. Wg MSDN'u jest to lewy dolny róg, ale w moim systemie prawy. Wygląda na to, że ktoś był nietrzeźwy ;)

Niemniej jednak, czas na wygenerowanie naszego testowego certyfikatu. Z poziomu cmd przechodzimy do katalogu C:\WinDDK\7600.16385.1\bin\amd64 i wpisujemy polecenie:
makecert -r -pe -ss PrivateCertStore -n CN=NazwaCertyfikatu MyDriver.cer

Aby sprawdzić, czy certyfikat został prawidłowo utworzony, można odpalić certmgr.msc i po lewej stronie przejść do Certyfikaty - bieżący użytkownik -> PrivateCertStore -> Certyfikaty.

Teraz pozostaje nam podpisać sterownik. Używamy w tym celu następującego polecenia:
signtool sign /v /s PrivateCertStore /n NazwaCertyfikatu /t http://timestamp.verisign.com/scripts/timestamp.dll C:\MyDriver\objfre_win7_amd64\amd64\mydriver.sys

Możemy jeszcze zweryfikować podpisanie, poprzez wykonanie następujących poleceń (z prawami administratora):
certmgr.exe /add MyDriver.cer /s /r localMachine root
signtool verify /pa /v C:\MyDriver\objfre_win7_amd64\amd64\MyDriver.sys

Jeśli nie wystąpiły żadne błędy, sterownik został prawidłowo podpisany i jest gotowy do użycia. No właśnie, jak go uruchomić? Generalnie, istnieje kilka metod. Jedna z nich, polega na wykorzystaniu nieudokumentowanych funkcji WinAPI (np. ZwSystemSetInformation z ntdll.dll). Pojawia się tu jednak pewien problem - pamięć sterownika może zostać poddana stronicowaniu. Próba dostępu do takiej pamięci może z kolei spowodować BSoD'a. Drugą (bezpieczną, bo sterowniki nie zostaną poddane stronicowaniu) metodą, jest użycie SCM (Service Control Manager), i właśnie tej metody użyjemy. Będziemy potrzebować dodatkowego programu. Możemy napisać go sami (przykładowy kod poniżej) lub ściągnąć z internetu (np. OSRLOADER).
C/C++
#include <cstdio>
#include <windows.h>
#include <shlwapi.h>

int main( int argc, char ** argv )
{
    if( argc != 2 )
    {
        printf( "Usage: %s path_to_driver\n", argv[ 0 ] );
        return 1;
    }
   
    SC_HANDLE hSCManager;
    SC_HANDLE hService;
    SERVICE_STATUS sStatus;
   
    hSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE );
   
    if( hSCManager )
    {
        hService = CreateService( hSCManager, PathFindFileName( argv[ 1 ] ), PathFindFileName( argv[ 1 ] ),
        SERVICE_START | DELETE | SERVICE_STOP, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START,
        SERVICE_ERROR_IGNORE, argv[ 1 ], NULL, NULL, NULL, NULL, NULL );
       
        if( !hService )
        hService = OpenService( hSCManager, PathFindFileName( argv[ 1 ] ),
             SERVICE_START | DELETE | SERVICE_STOP );
       
        if( hService )
        {
            if( !StartService( hService, 0, NULL ) )
                 printf( "Some error has occured while starting service: %d\n",( int ) GetLastError() );
            else
                 printf( "Service started successfully\n" );
           
            printf( "Press Enter to stop service\n" );
            getchar();
            ControlService( hService, SERVICE_CONTROL_STOP, & sStatus );
            DeleteService( hService );
            CloseServiceHandle( hService );
        }
        else
             printf( "Some error has occured while creating service: %d\n",( int ) GetLastError() );
       
        CloseServiceHandle( hSCManager );
    }
    else
         printf( "Some error has occured while opening SCM: %d\n",( int ) GetLastError() );
   
    return 0;
}
Program należy skompilować z
-lshlwapi
, a następnie uruchomić jako administrator.

Prawdopodobnie podczas uruchamiania nie otrzymaliśmy żadnych błędów, więc sterownik powinien działać. Można się o tym przekonać na własne oczy. Tutaj dochodzimy do miejsca, gdzie trzeba wytłumaczyć cel stworzenia odpowiednich wartości w rejestrze. Otóż, poczynając od Windows Visty i Windows Server 2008, output funkcji DbgPrint jest wyłączony. Jako że w naszym przykładowym sterowniku ta funkcja jest jedyną widoczną oznaką, że wszystko działa, należy ten output włączyć. Robimy to właśnie poprzez zmodyfikowanie rejestru.

Aby podglądnąć wynik działania tej funkcji, należy pobrać program DebugView i uruchomić go (oczywiście z prawami administratora), oraz wcisnąć Ctrl+K. Następnie uruchomić sterownik za pomocą naszego programu. W okienku DebugView powinnien się pojawić napis "Hello world!", a po zakończeniu usługi "Invoked OnUnload".

Podsumowanie

Artykuł ten ma na celu przedstawić sposób uruchomienia własnych sterowników jedynie jako ciekawostkę. Wszelkie błędy, jak również różnice w instalacji na innych systemach, można zgłaszać na forum.

Źródła