Bagikan melalui


Tutorial: Menulis driver Windows "Hello World" (Kernel-Mode Driver Framework)

Artikel ini menjelaskan cara menulis driver Universal Windows kecil menggunakan Kernel-Mode Driver Framework (KMDF) lalu menyebarkan dan menginstal driver Anda di komputer terpisah.

Prasyarat

  • Ikuti langkah-langkah untuk menginstal Windows Driver Kit (WDK). Alat Penelusuran Kesalahan untuk Windows disertakan saat Anda menginstal WDK.

  • Instal Visual Studio 2022. Saat Anda menginstal Visual Studio 2022, pilih Pengembangan desktop dengan beban kerja C++, lalu di bawah Komponen Individual tambahkan:

    • MSVC v143 - VS 2022 C++ ARM64/ARM64EC Spectre-mitigated libs (Terbaru)
    • MSVC v143 - VS 2022 C++ x64/x86 pustaka yang sudah dimitigasi Spectre (Terbaru)
    • C++ ATL untuk alat build v143 terbaru dengan Spectre Mitigations (ARM64/ARM64EC)
    • C++ ATL untuk perangkat pembangunan v143 terbaru dengan mitigasi Spectre (x86 & x64)
    • C++ MFC untuk perangkat pembangunan terbaru v143 dengan mitigasi Spectre (ARM64/ARM64EC)
    • C++ MFC untuk alat build v143 terbaru yang menyertakan Mitigasi Spectre (x86 & x64)
    • Windows Driver Kit

Membuat dan mengembangkan driver

  1. Buka Microsoft Visual Studio. Pada menu File, pilih Baru > Proyek.

  2. Dalam kotak dialog Buat proyek baru, pilih C++ di menu dropdown kiri, pilih Windows di menu dropdown tengah, dan pilih Driver di menu dropdown kanan.

  3. Pilih Kernel Mode Driver, Kosong (KMDF) dari daftar jenis proyek. Pilih Berikutnya.

    Cuplikan layar kotak dialog proyek baru Visual Studio dengan opsi driver mode kernel dipilih.

    Petunjuk

    Jika Anda tidak dapat menemukan templat proyek driver di Visual Studio, ekstensi WDK Visual Studio tidak diinstal dengan benar. Untuk mengatasi masalah ini, luncurkan Penginstal Visual Studio, pilih Ubah, tambahkan Windows Driver Kits di tab Komponen Individual, dan pilih Ubah.

  4. Dalam kotak dialog Mengonfigurasi proyek baru Anda, masukkan "KmdfHelloWorld" di bidang Nama proyek.

    Nota

    Saat membuat driver KMDF atau UMDF baru, Anda harus memilih nama driver yang memiliki 32 karakter atau kurang. Batas panjang ini didefinisikan dalam wdfglobals.h.

  5. Di bidang Lokasi, masukkan direktori tempat Anda ingin membuat proyek baru.

  6. Periksa solusi dan proyek ditempatkan di direktori yang sama dan pilih Buat.

    Cuplikan layar kotak dialog

    Visual Studio membuat satu proyek dan solusi. Anda dapat melihatnya di jendela Penjelajah Solusi. (Jika jendela Penjelajah Solusi tidak terlihat, pilih Penjelajah Solusi dari menu Tampilan.) Solusinya memiliki proyek driver bernama KmdfHelloWorld.

    Cuplikan layar jendela penjelajah solusi Visual Studio yang menampilkan solusi dan proyek driver kosong bernama KmdfHelloWorld.

  7. Di jendela Penjelajah Solusi, pilih kanan solusi 'KmdfHelloWorld' (1 dari 1 proyek) dan pilih Configuration Manager. Pilih konfigurasi dan platform untuk proyek driver. Misalnya, pilih Debug dan x64.

  8. Di jendela Penjelajah Solusi, pilih kanan proyek KmdfHelloWorld, pilih Tambahkan, lalu pilih Item Baru.

  9. Dalam kotak dialog Tambahkan Item Baru, masukkan "Driver.c".

    Nota

    Ekstensi nama file .c, bukan .cpp.

    Pilih Tambahkan. File Driver.c ditambahkan di bawah File Sumber, seperti yang ditunjukkan di sini.

    Cuplikan layar jendela penjelajah solusi Visual Studio yang menampilkan file driver.c yang ditambahkan ke proyek driver.

Menulis kode driver pertama Anda

Sekarang setelah Anda membuat proyek Hello World kosong dan menambahkan file sumber Driver.c, Anda menulis kode paling mendasar yang diperlukan agar driver berjalan dengan menerapkan dua fungsi panggilan balik peristiwa dasar.

  1. Di Driver.c, mulailah dengan menyertakan header ini:

    #include <ntddk.h>
    #include <wdf.h>
    

    Petunjuk

    Jika Anda tidak dapat menambahkan Ntddk.h, buka Konfigurasi -> C/C++ -> Umum -> Direktori Sertakan Tambahan dan tambahkan C:\Program Files (x86)\Windows Kits\10\Include\<build#>\km, ganti <build#> dengan direktori yang sesuai dalam penginstalan WDK Anda.

    Ntddk.h berisi definisi kernel Windows inti untuk semua driver, sementara Wdf.h berisi definisi untuk driver berdasarkan Windows Driver Framework (WDF).

  2. Selanjutnya, berikan deklarasi untuk dua panggilan balik:

    DRIVER_INITIALIZE DriverEntry;
    EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;
    
  3. Gunakan kode berikut untuk menulis DriverEntryAnda :

    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 adalah titik masuk untuk semua driver, seperti halnya Main() untuk banyak program di mode pengguna. Tugas DriverEntry adalah memulai struktur dan sumber daya yang berlaku untuk seluruh driver. Dalam contoh ini, Anda mencetak "Hello World" untuk DriverEntry, mengonfigurasi objek driver untuk mendaftarkan titik masuk callback EvtDeviceAdd, kemudian membuat objek driver dan mengembalikan.

    Objek driver bertindak sebagai objek induk untuk semua objek kerangka kerja lain yang mungkin Anda buat di driver Anda, yang mencakup objek perangkat, antrean I/O, timer, spinlock, dan banyak lagi. Untuk informasi selengkapnya tentang objek kerangka kerja, lihat Pengenalan Objek Kerangka Kerja.

    Petunjuk

    Untuk DriverEntry, kami sangat menyarankan untuk menyimpan nama sebagai "DriverEntry" untuk membantu analisis kode dan penelusuran kesalahan.

  4. Selanjutnya, gunakan kode berikut untuk menulis KmdfHelloWorldEvtDeviceAdd:

    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 dipanggil oleh sistem ketika mendeteksi bahwa perangkat Anda tiba. Tugasnya adalah menginisialisasi struktur dan sumber daya untuk perangkat tersebut. Dalam contoh ini, Anda mencetak pesan "Halo Dunia" untuk EvtDeviceAdd, membuat objek perangkat, dan mengembalikan. Dalam driver lain yang Anda tulis, Anda dapat membuat antrean I/O untuk perangkat keras Anda, menyiapkan konteks perangkat , ruang penyimpanan untuk informasi khusus perangkat, atau melakukan tugas lain yang diperlukan untuk menyiapkan perangkat Anda.

    Petunjuk

    Untuk penambahan panggilan balik perangkat, perhatikan cara Anda menamainya dengan nama driver Anda sebagai awalan (KmdfHelloWorldEvtDeviceAdd). Umumnya, sebaiknya beri nama fungsi driver Anda dengan cara ini untuk membedakannya dari fungsi driver lain. DriverEntry adalah satu-satunya yang harus Anda beri nama persis seperti itu.

  5. Driver.c lengkap Anda sekarang terlihat seperti ini:

    #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;
    }
    
  6. Simpan Driver.c.

Contoh ini menggambarkan konsep mendasar driver: mereka adalah "kumpulan panggilan balik" yang, setelah diinisialisasi, berdiam diri dan menunggu sistem memanggilnya ketika sistem membutuhkannya. Panggilan sistem bisa menjadi peristiwa kedatangan perangkat baru, permintaan I/O dari aplikasi mode pengguna, peristiwa pematian daya sistem, permintaan dari driver lain, atau peristiwa penghapusan mendadak saat pengguna mencabut perangkat secara tak terduga. Untungnya, untuk mengucapkan "Halo Dunia", Anda hanya perlu memikirkan pembuatan driver dan perangkat.

Selanjutnya, Anda mengembangkan driver Anda.

Membangun penggerak

  1. Di jendela Penjelajah Solusi, pilih kanan solusi 'KmdfHelloWorld' (1 dari 1 proyek) dan pilih Configuration Manager. Pilih konfigurasi dan platform untuk proyek driver. Untuk latihan ini, pilih Debug dan x64.

  2. Di jendela Penjelajah Solusi, pilih kanan KmdfHelloWorld dan pilih properti . Di Pelacakan Wpp > Semua Opsi, atur Jalankan pelacakan Wpp ke Tidak. Pilih Terapkan lalu OK.

  3. Untuk membangun driver Anda, pilih Build Solution dari menu Build. Visual Studio memperlihatkan kemajuan build di jendela Output. (Jika jendela Output tidak terlihat, pilih Output dari menu Tampilan.) Saat Anda memverifikasi bahwa solusi berhasil dibuat, Anda dapat menutup Visual Studio.

  4. Untuk melihat driver bawaan, di File Explorer, buka folder KmdfHelloWorld Anda, lalu ke x64\Debug\KmdfHelloWorld. Folder ini mencakup:

    • KmdfHelloWorld.sys -- berkas penggerak mode kernel
    • KmdfHelloWorld.inf -- file informasi yang digunakan Windows saat Anda menginstal driver
    • KmdfHelloWorld.cat -- file katalog yang digunakan alat penginstal untuk memverifikasi tanda tangan pengujian driver

Petunjuk

Jika Anda melihat DriverVer set to a date in the future saat membangun driver, ubah pengaturan proyek driver Anda sehingga Inf2Cat mengatur /uselocaltime. Untuk melakukannya, gunakan Configuration Properties->Inf2Cat->General->Gunakan Local Time. Sekarang Stampinf dan Inf2Cat menggunakan waktu lokal.

Menyebarkan pengandar

Biasanya ketika Anda menguji dan men-debug driver, debugger dan driver berjalan pada komputer terpisah. Komputer yang menjalankan debugger disebut komputer host , dan komputer yang menjalankan driver disebut komputer target . Komputer target juga disebut komputer uji .

Sejauh ini Anda menggunakan Visual Studio untuk membangun driver di komputer host. Sekarang Anda perlu mengonfigurasi komputer target.

  1. Ikuti instruksi di Menyediakan komputer untuk penyebaran dan pengujian driver (WDK 10).

    Petunjuk

    Saat Anda mengikuti langkah-langkah untuk memprovisikan komputer target secara otomatis menggunakan kabel jaringan, perhatikan port dan kunci. Anda akan menggunakannya nanti di langkah debugging. Dalam contoh ini, Anda menggunakan 50000 sebagai port dan 1.2.3.4 sebagai kunci.

    Dalam skenario debugging driver yang sebenarnya, sebaiknya gunakan kunci yang dihasilkan oleh KDNET. Untuk informasi selengkapnya tentang cara menggunakan KDNET untuk menghasilkan kunci acak, lihat topik Driver Debug - Step by Step Lab (Mode Kernel Sysvad).

  2. Di komputer host, buka solusi Anda di Visual Studio. Anda dapat mengklik dua kali file solusi, KmdfHelloWorld.sln, di folder KmdfHelloWorld Anda.

  3. Di jendela Penjelajah Solusi, klik kanan proyek KmdfHelloWorld, dan pilih properti .

  4. Pergi ke >.

  5. Untuk Nama Perangkat Target, pilih nama komputer yang Anda konfigurasi untuk pengujian dan debugging. Dalam latihan ini, kita menggunakan komputer bernama MyTestComputer.

  6. Untuk memastikan bahwa Anda menguji versi terbaru driver, periksa Hapus versi driver sebelumnya sebelum penyebaran.

  7. Pilih Pembaruan Driver ID Perangkat Keras , dan masukkan ID perangkat keras untuk driver Anda. Untuk latihan ini, ID perangkat keras adalah Root\KmdfHelloWorld. Pilih OK.

    Nota

    Dalam latihan ini, ID perangkat keras tidak mengidentifikasi perangkat keras yang sebenarnya. Ini mengidentifikasi perangkat imajiner yang ditempatkan di pohon perangkat sebagai anak dari simpul akar. Untuk perangkat keras sebenarnya, jangan pilih Pembaruan Driver ID Perangkat Keras; sebagai alternatif, pilih Instal dan Verifikasi. Anda melihat ID perangkat keras dalam file informasi driver (INF) Anda. Di jendela Penjelajah Solusi, buka KmdfHelloWorld > Driver Files, dan klik dua kali KmdfHelloWorld.inf. ID perangkat keras terletak di bawah [Standard.NT$ARCH$].

    [Standard.NT$ARCH$]
    %KmdfHelloWorld.DeviceDesc%=KmdfHelloWorld_Device, Root\KmdfHelloWorld
    
  8. Pada menu Build, pilih Deploy Solution. Visual Studio secara otomatis menyalin file yang diperlukan untuk menginstal dan menjalankan driver ke komputer target. Penyebaran mungkin memakan waktu satu atau dua menit.

    Ketika Anda menyebarkan driver, file driver disalin ke folder %Systemdrive%\drivertest\drivers pada komputer pengujian. Jika terjadi kesalahan selama penyebaran, Anda dapat memeriksa untuk melihat apakah file disalin ke komputer pengujian. Verifikasi bahwa file .inf, .cat, sertifikasi pengujian, dan .sys, dan file lain yang diperlukan, ada di folder %systemdrive%\drivertest\drivers.

    Untuk informasi selengkapnya tentang menyebarkan driver, lihat Menyebarkan Driver ke Komputer Uji.

Pasang driver

Setelah driver Hello World Anda disebarkan ke komputer target, sekarang Anda menginstal driver tersebut. Ketika sebelumnya Anda memprovisikan komputer target dengan Visual Studio menggunakan opsi otomatis, Visual Studio menyiapkan komputer target untuk menjalankan driver yang ditandatangani untuk pengujian sebagai bagian dari proses provisi. Sekarang Anda hanya perlu menginstal driver menggunakan alat DevCon.

  1. Di komputer host, navigasikan ke folder Alat di penginstalan WDK Anda dan temukan alat DevCon. Misalnya, lihat di folder berikut:

    C:\Program Files (x86)\Windows Kits\10\Tools\<version number>\x64\devcon.exe

    Salin alat DevCon ke komputer jarak jauh Anda.

  2. Pada komputer target, instal driver dengan menavigasi ke folder yang berisi file driver, lalu jalankan alat DevCon.

    1. Berikut adalah sintaks umum untuk alat devcon yang akan Anda gunakan untuk menginstal driver:

      devcon install <pasang file INF><ID perangkat keras>

      File INF yang diperlukan untuk menginstal driver ini adalah KmdfHelloWorld.inf. File INF berisi ID perangkat keras untuk menginstal biner driver, KmdfHelloWorld.sys. Ingat bahwa ID perangkat keras, yang terdapat di file INF, adalah Root\KmdfHelloWorld.

    2. Buka jendela Prompt Perintah sebagai Administrator. Navigasi ke folder Anda yang berisi file .sys driver bawaan dan masukkan perintah ini:

      devcon install kmdfhelloworld.inf root\kmdfhelloworld

      Jika Anda mendapatkan pesan kesalahan tentang devcon tidak dikenali, coba tambahkan jalur ke alat devcon. Misalnya, jika Anda menyalinnya ke folder di komputer target yang disebut C:\Tools, maka coba gunakan perintah berikut:

      c:\tools\devcon install kmdfhelloworld.inf root\kmdfhelloworld

      Kotak dialog muncul menunjukkan bahwa driver pengujian adalah driver yang belum ditandatangani. Pilih Tetap instal driver ini untuk melanjutkan.

      Cuplikan layar peringatan keamanan yang ditampilkan selama proses penginstalan driver.

Melakukan debug pada driver

Sekarang setelah Anda menginstal driver KmdfHelloWorld pada komputer target, Anda menghubungkan debugger secara jarak jauh dari komputer host.

  1. Di komputer host, buka jendela Prompt Perintah sebagai Administrator. Ubah ke direktori WinDbg.exe. Anda menggunakan x64version WinDbg.exe dari Windows Driver Kit (WDK) yang diinstal sebagai bagian dari penginstalan kit Windows. Berikut adalah jalur default ke WinDbg.exe:

    C:\Program Files (x86)\Windows Kits\10\Debuggers\x64

  2. Luncurkan WinDbg untuk menyambungkan ke sesi debug kernel pada komputer target dengan menggunakan perintah berikut. Nilai untuk port dan kunci harus sama dengan yang Anda gunakan untuk menyediakan komputer target. Anda menggunakan 50000 untuk port dan 1.2.3.4 untuk kunci, nilai yang Anda gunakan pada langkah penerapan. Bendera k menunjukkan bahwa ini adalah sesi debug kernel.

    WinDbg -k net:port=50000,key=1.2.3.4

  3. Pada menu Debug, pilih Break. Debugger pada komputer host menerobos ke komputer target. Di jendela Perintah Debugger, Anda dapat melihat prompt perintah debugging kernel: kd>.

  4. Pada titik ini, Anda dapat bereksperimen dengan debugger dengan memasukkan perintah di prompt> kd. Misalnya, Anda dapat mencoba perintah ini:

  5. Untuk membiarkan komputer target berjalan lagi, pilih Go dari menu Debug atau tekan "g," lalu tekan "enter."

  6. Untuk menghentikan sesi debugging, pilih Detach Debugger dari menu Debug.

    Penting

    Pastikan Anda menggunakan perintah "go" untuk membiarkan komputer target berjalan lagi sebelum keluar dari debugger, atau komputer target akan tetap tidak responsif terhadap input mouse dan keyboard Anda karena masih berbicara dengan debugger.

Untuk panduan langkah demi langkah terperinci dari proses debugging driver, lihat Debug Universal Driver - Step by Step Lab (Echo Kernel-Mode).

Untuk informasi selengkapnya tentang penelusuran kesalahan jarak jauh, lihat Penelusuran Kesalahan Jarak Jauh Menggunakan WinDbg.