logo

Einführung in die Windows-Kernelentwicklung mit Rust (Teil 1)

Einführung

Grüße, furchtloser Leser! Mach dich bereit für eine aufregende Reise in das Reich der Treiberentwicklung, ermächtigt durch die gewaltige Programmiersprache Rust!

Wenn Sie sich auf dieses aufregende Abenteuer begeben, erwarten Sie eine bevorstehende Expedition, bei der wir einen mächtigen Treiber erstellen werden, der in der Lage ist, bisher unsichtbare Prozesse darzustellen. Diesen Artikel zu überspringen wäre eine verpasste Gelegenheit, da er die Antworten auf die hier gestellten Fragen enthält.

Wenn Rust für dich Neuland ist, keine Sorge, denn ich werde dein Führer sein, selbst in die bekannten Gefilde von C++ vorstoßend. Alles, was benötigt wird, ist ein bisschen freie Zeit, Kenntnisse in C++ Programmierung und ein grundlegendes Verständnis für Kernel-Level-Zauberei.

Aber warum Rust, fragen Sie sich vielleicht? Die Antwort liegt auf der Hand: Rust vereint Stil, Innovation und unerschütterliche Stärke. Es bietet eine Leistung ähnlich wie C++, verstärkt durch undurchdringliche Sicherheitsmaßnahmen. Technologiegiganten wie Microsoft, Google, Mozilla und die Linux Foundation haben sein Potenzial erkannt. Sogar Linus Torvalds, der Verfechter von "C für immer", hat offiziell die Integration von Rust in den Linux-Kernel [1] befürwortet. Microsoft schreibt den Kern von Windows mit Rust neu [2], hat jedoch den Entwicklern noch nicht das Privileg eingeräumt, Rust innerhalb des Windows-Kernels einzusetzen. Macht nichts; wir werden selbst die Zügel in die Hand nehmen und ihre Bemühungen übertreffen.

Im Jahr 2015 wurde die erste Version der Sprache veröffentlicht, und seitdem wird sie alle 6 Wochen aktualisiert. Es gibt 3 Veröffentlichungskanäle: stabil, beta und nächtlich. (Übrigens benötigen wir die nächtliche Toolchain, um Treiber zu entwickeln). Darüber hinaus hat Rust Editionen (so etwas wie Standards in C++), nämlich Rust 2015, Rust 2018 und jetzt zum Zeitpunkt des Schreibens - Rust 2021. Deshalb hat Rust sogar den Befehl cargo fix --edition, der hilft, teilweise inkompatible Stellen für den neuen Standard zu korrigieren.

 

Abhängigkeiten

Um die Bühne für unsere Suche zu bereiten, müssen wir die notwendigen Werkzeuge sammeln und unsere Umgebung auf die bevorstehenden Herausforderungen vorbereiten. Hier ist eine Checkliste dessen, was wir benötigen:

 


Erforderliche Werkzeuge
1. Rust installieren: Zuerst sollten wir die Kraft von Rust nutzen, indem wir es von hier installieren.
2. SDK installieren: Wir benötigen das Windows SDK für unser Vorhaben. Du kannst es hier erwerben.
3. WDK installieren: Das Windows Driver Kit (WDK) ist unser vertrauter Begleiter für die Treiberentwicklung. Du kannst es hier erhalten.
4. Sysinternals installieren: Das Sysinternals Suite wird unser unschätzbares Werkzeugset sein. Hol es dir hier.

HINWEIS: Das Terminal sollte mit Administratorrechten ausgeführt werden.

 

Entwicklung

Konfiguration
Nachdem das Projekt erstellt wurde, navigiere zum hello-win-kernel Verzeichnis. Du wirst folgende Struktur vorfinden:

cargo new hello-win-kernel --lib

Nachdem das Projekt erstellt wurde, navigieren Sie zum hello-win-kernel Verzeichnis. Sie finden folgende Struktur:

# hello-win-kernel folder
srclib.rs
.gitignore
Cargo.toml

In Rust benennen wir die Datei, die den Einstiegspunkt für Anwendungen enthält, typischerweise als main.rs, während sie für Bibliotheken lib.rs ist. Die Cargo.toml Datei enthält Projekt-Abhängigkeiten und Einstellungen, während .gitignore klugerweise das Verzeichnis target ausschließt, in dem die Binärdateien gespeichert werden.
Jetzt verbessern wir unsere Projekteinstellung, indem wir die Cargo.toml Datei bearbeiten. Zuerst fügen wir einen [lib] Abschnitt hinzu, der den Pfad der Einstiegsdatei angibt und sie als "dynamische Bibliothek" ausweist.

[package]
name = "hello-win-kernel"
version = "0.1.0"
edition = "2021"

[lib]
path = "src/lib.rs"
crate-type = ["cdylib"]

Wir werden auch [profile.dev] und [profile.release] Abschnitte erstellen, um den Panic Typ als "abort" für eine bessere Fehlerbehandlung festzulegen.
Als Nächstes fügen Sie einen [build-dependencies]-Abschnitt hinzu, der das winreg-Paket für Windows-Registry-Operationen einführt:

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

[build-dependencies]
winreg = "0.50.0"

Um eine reibungslose Projektkompilierung zu gewährleisten, erstellen Sie eine rust-toolchain Datei im hello-win-kernel Verzeichnis, die die Verwendung der Nightly-Toolchain angibt und den Zugriff auf spezielle Flags ermöglicht:

rust-toolchain

nightly

Um den Treiber zu kompilieren, müssen Sie Pfade zum WDK hinzufügen. Dies kann mit einem build.rs Skript erreicht werden. Das build.rs Skript wird von cargo vor dem Bauen des Pakets ausgeführt. Es ermöglicht Ihnen, installierte Bibliotheken zu lokalisieren und deren Informationen in Cargo einzuschließen. Nachdem Sie das #[link(name = "libname")] Konstrukt in Ihrem Code verwendet haben, wird der Build-Prozess die hinzugefügten Pfade durchsuchen und Bibliotheken verlinken, ähnlich wie in C oder C++. Erstellen Sie eine build.rs Datei im hello-win-kernel Verzeichnis. Füllen Sie diese Datei mit dem Code aus, um das WDK abzurufen. Sie können Ihr Skript basierend auf dem finden in diesem GitHub Repositorium.

build.rs

// A.k.a #include  in the C++
extern crate winreg;

// Imports the need features. A.k.a using namespace std in the C++
use std::env::var;
use std::error::Error;
use std::fmt;
use std::path::{Path, PathBuf};
use winreg::enums::*;
use winreg::RegKey;

// Windows Kits registry key
const WIN_KITS_KEY: &str = r"SOFTWAREMicrosoftWindows KitsInstalled Roots";

// Custom error type
#[derive(Debug)]
struct BuildError {
    msg: String,
}

impl Error for BuildError {}

impl fmt::Display for BuildError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BuildError: {}", self.msg)
    }
}

// Get the Windows Kits directory from the registry
fn get_windows_kits_dir() -> Result {
    let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
    match hklm.open_subkey(WIN_KITS_KEY) {
        Ok(key) => match key.get_value::("KitsRoot10") {
            Ok(dir) => Ok(dir.into()),
            Err(_) => Err(BuildError {
                msg: format!("Can not get value: {}", WIN_KITS_KEY),
            }),
        },
        Err(_) => Err(BuildError {
            msg: format!("Can not open sub_key: {}", WIN_KITS_KEY),
        }),
    }
}

// Get the latest km directory from the Windows Kits directory
fn get_km_dir(windows_kits_dir: &PathBuf) -> Result {
    match Path::new(windows_kits_dir).join("lib").read_dir() {
        Ok(read_dir) => {
            match read_dir
                .filter_map(|dir| dir.ok())
                .map(|dir| dir.path())
                .filter(|dir| {
                    dir.components()
                        .last()
                        .and_then(|c| c.as_os_str().to_str())
                        .map(|c| c.starts_with("10.") && dir.join("km").is_dir())
                        .unwrap_or(false)
                })
                .max()
                .ok_or_else(|| format!("Can not find a valid km dir in `{:?}`", windows_kits_dir))
            {
                Ok(max_lib_dir) => Ok(max_lib_dir.join("km")),
                Err(msg) => Err(BuildError { msg }),
            }
        }
        Err(_) => Err(BuildError {
            msg: format!("Can not read dir: {:?}", windows_kits_dir),
        }),
    }
}

fn main() {
    let windows_kits_dir = get_windows_kits_dir().unwrap();
    let km_dir = get_km_dir(&windows_kits_dir).unwrap();
    let target = var("TARGET").unwrap();
    let arch = if target.contains("x86_64") {
        "x64"
    } else if target.contains("i686") {
        "x86"
    } else {
        panic!("Only support x64 and x86!");
    };
    let wdk_lib_dir = km_dir.join(arch);

    // link
    println!(
        "cargo:rustc-link-search=native={}",
        wdk_lib_dir.to_str().unwrap()
    );
}

Um unseren Treiber einzuführen, müssen wir zunächst eine Konfigurationsdatei erstellen. Fürchte dich nicht, denn ich werde dich auf diesem Weg zum Triumph führen.

1. Erstelle ein Verzeichnis namens .cargo in deinem aktuellen Verzeichnis – eine Welt voller Möglichkeiten.

2. Innerhalb dieses neu gefundenen Bereichs, erstelle eine Datei mit dem Namen config. Hier werden wir unsere Anweisungen eingravieren.

 

Schreibe diese Flags in die config ein, jedes ein Leuchtfeuer, das uns durch die labyrinthartigen Tiefen der Treiberkompilierung führt. Für ein tieferes Verständnis dieser Flags kannst du in den Annalen der Weisheit auf MSDN [5] nachschlagen.

.cargo/config

[build]
target = "x86_64-pc-windows-msvc"

rustflags = [
    # Pre Link Args
    "-Z", "pre-link-arg=/NOLOGO",
    "-Z", "pre-link-arg=/NXCOMPAT",
    "-Z", "pre-link-arg=/NODEFAULTLIB",
    "-Z", "pre-link-arg=/SUBSYSTEM:NATIVE",
    "-Z", "pre-link-arg=/DRIVER",
    "-Z", "pre-link-arg=/DYNAMICBASE",
    "-Z", "pre-link-arg=/INCREMENTAL:NO",
    "-Z", "pre-link-arg=/MANIFEST:NO",
    "-Z", "pre-link-arg=/PDBALTPATH:none",

    # Post Link Args
    "-C", "link-arg=/OPT:REF,ICF",
    "-C", "link-arg=/ENTRY:driver_entry",
    "-C", "link-arg=/MERGE:.edata=.rdata",
    "-C", "link-arg=/MERGE:.rustc=.data",
    "-C", "link-arg=/INTEGRITYCHECK"
]

 

Umsetzung

Puh! Hurra, wir haben es geschafft! Kannst du es glauben? Es ist Zeit, mit dem Programmieren zu beginnen. Ja, wir können mit der Entwicklung des Treibers beginnen. Genau wie C++, unterstützt Rust die Standardbibliothek im Kernel-Modus nicht aufgrund der Unterschiede zwischen User-Modus und Kernel-Modus. Daher müssen wir sie mit dem #![no_std] Attribut deaktivieren, das zu Beginn der lib.rs Datei angegeben werden sollte.

Als Nächstes müssen wir die __CxxFrameHandler3-Funktion und die _fltused-Variable deklarieren, um Verknüpfungsfehler zu beheben. Zusätzlich müssen wir unseren eigenen panic_handler implementieren, da die Standardbibliothek nicht mehr verfügbar ist, weil wir sie deaktiviert haben.

In die Zukunft blickend, lasst uns die driver_entry Funktion erstellen, die der Einstiegspunkt für den Treiber sein wird. Du kannst dieser Funktion einen anderen Namen geben, aber du musst sie im .cargo/config File spezifizieren, indem du das Feld "-C", "link-arg=/ENTRY:driver_entry" änderst, zum Beispiel auf "-C", "link-arg=/ENTRY:entry".

Da die Windows-API in C implementiert ist, müssen wir FFI (Foreign Function Interface) verwenden. Einfach ausgedrückt ist es ein Mechanismus, der es uns ermöglicht, APIs aus einer anderen Sprache aufzurufen.

Um zu beginnen, müssen wir das Verfälschen von Namen mit dem #[no_mangle]-Attribut deaktivieren und festlegen, dass die Systemaufrufkonvention (stdcall) für Funktionsaufrufe mit extern "system" verwendet wird. Zur Vereinfachung erstellen wir einige Typen. Anstatt PDRIVER_OBJECT und PUNICODE_STRING verwenden wir vorerst PVOID, da wir diese Datenstrukturen momentan nicht benötigen.

Also, fügen wir den folgenden Code zu src/lib.rs hinzu.

src/lib.rs

// Disables the standard library
#![no_std]

// A.k.a #include  in C++
mod dbg;
mod ntstatus;
mod types;

// Imports the need features. A.k.a using namespace std in the C++
use dbg::*;
use ntstatus::*;
use types::*;

// Need for fix linker error.
#[no_mangle]
pub extern "system" fn __CxxFrameHandler3(_: *mut u8, _: *mut u8, _: *mut u8, _: *mut u8) -> i32 {
    unimplemented!()
}

// Need for fix linker error. Floating point calculations aren`t allowed when running in the Windows Kernel.
#[export_name = "_fltused"]
static _FLTUSED: i32 = 0;

// Panic hanlder
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    // The purpose of the loop construct in this context is to create an infinite loop.
    // When a panic occurs, the panic function is invoked, and instead of unwinding
    // the stack or aborting the program, it enters an infinite loop.
    // This behavior is intentional to prevent the program from terminating or propagating
    // the panic further. By using an infinite loop in the panic handler, the program effectively
    // hangs or stalls at the point of panic, allowing for potential diagnostics or
    // debugging to be performed.
    loop {}
}

// The entry point of the driver, set as global (pub).
#[no_mangle]
pub extern "system" fn driver_entry(_driver: PVOID, _path: PVOID) -> NTSTATUS {
    kd_print!("Hello, world!
");
    STATUS_SUCCESS
}

Als Nächstes erstellen wir src/types.rs und fügen C-ähnliche Typen mittels Aliases hinzu (auch bekannt als typedef in C). Zusätzlich werden wir in der Datei src/ntstatus.rs Statusmeldungen wie STATUS_SUCCESS hinzufügen.

src/types.rs

// Aliases for Windows types
pub type NTSTATUS = u32;
pub type PCSTR = *const u8;
pub type PVOID = *mut core::ffi::c_void;

src/ntstatus.rs

// Imports the need features. A.k.a using namespace std in the C++
use crate::types::*;

pub const STATUS_SUCCESS: NTSTATUS = 0x00000000;

Prima, jetzt fügen wir die DbgPrint API hinzu, die zum Protokollieren von Debug-Informationen beim Entwickeln von Treibern verwendet wird. Dazu erstellen wir eine Datei namens src/dbg.rs, verknüpfen sie mit ntoskrnl und fügen die DbgPrint API hinzu. Zusätzlich, um die Arbeit komfortabler zu gestalten, erstellen wir ein kd_print Makro, da wir ständig das Zeichen \O am Ende eines Satzes hinzufügen müssen, aufgrund der spezifischen Programmierung in C (In C werden Zeichenketten mit einem \O Zeichen beendet).

Wir werden DbgPrint in einen unsafe Block einbetten, da es sich um eine API aus einer anderen Sprache handelt und Rust dafür keine Garantien bieten kann.

src/dbg.rs

// Imports the need features. A.k.a using namespace std in the C++
use crate::types::*;

// Imports the `DbgPrint` function from `ntoskrnl.exe`, and set as a global function (pub),
// that can be called from anywhere module in the crate.
#[link(name = "ntoskrnl")]
extern "C" {
	  #[allow(dead_code)]
    pub fn DbgPrint(format: PCSTR, ...) -> NTSTATUS;
}

// Macro that calls the `DbgPrint` function, and prepends the string with the name of the driver,
// and a null terminator. The `unsafe` is used because the `DbgPrint` function is written in a different language,
// and Rust cannot guarantee safety.
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! kd_print {
    ($string: expr) => {
        unsafe {
            $crate::DbgPrint(concat!("[hello_win_kernel.sys] ", $string, "�").as_ptr())
        }
    };

    ($string: expr, $($x:tt)*) => {
        unsafe {
            $crate::DbgPrint(concat!("[hello_win_kernel.sys] ", $string, "�").as_ptr(), $($x)*)
        }
    };
}

// Empty macro for release
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! kd_print {
	  ($string: expr) => {};
    ($string: expr, $($x:tt)*) => {};
}

Nun können wir erfolgreich unseren Treiber erstellen. Dies ist jedoch nicht das Ende, denn als Nächstes müssen wir den Mechanismus für die Treibersignatur und -bereitstellung implementieren.

Der untenstehende Beispiel-Treiber in C++ zeigt, dass das Schreiben eines Treibers in C oder C++ einfacher ist im Vergleich zu Rust. Aber bis es offizielle Unterstützung von Microsoft gibt, auf die alle gespannt warten (tatsächlich, bis wir die Dinge selbst in die Hand nehmen und es selbst implementieren, wie im Fall bei C++), erhalten wir die Garantien von Rust für unser Entwicklungslevel, die es uns ermöglichen, einen sichereren Treiber zu bauen, zusammen mit vollständigem Inline-ASM, Musterabgleichung und vielen anderen coolen Funktionen, die Rust bietet.

Einige Startups verwenden bereits Rust, um Treiber für virtuelle Geräte im Kontext der Cybersicherheit zu entwickeln.

Beispiel-Treiber in C++ aus dem Projekt "hello-win-kernel-cpp":

#include 

extern "C"
{
    DRIVER_INITIALIZE DriverEntry;
}


#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#endif

// The entry point of the driver
_Use_decl_annotations_
NTSTATUS DriverEntry([[maybe_unused]] PDRIVER_OBJECT DriverObject,
                     [[maybe_unused]] PUNICODE_STRING RegistryPath)
{
    DbgPrint("[hello-win-kernel-cpp.sys] Hello, World!
");
    return STATUS_SUCCESS;
}

Bereitstellung und Testen

Um unseren Treiber zu testen, müssen wir zunächst seine Erweiterung von .dll in .sys ändern und ihn mit einem Testzertifikat signieren. Um all dies zu automatisieren, verwenden wir cargo-make. Führen Sie dazu den folgenden Befehl im Terminal aus.

cargo install cargo-make

Als Nächstes werden wir eine Middleware namens WIN_SDK_TOOLS, erstellen, die möglicherweise mit den Windows SDK-Tools zusammenhängt. Für wen unterzeichnen Sie die folgenden Schritte:

1. Öffnen Sie Erweiterte Systemeinstellungen anzeigen, indem Sie danach suchen und diese Option starten.

2. Im Systemeigenschaften Fenster, wählen Sie den Erweitert-Reiter.

3. Klicken Sie auf die Schaltfläche Umgebungsvariablen.

4. Im Umgebungsvariablen Fenster, scrollen Sie nach unten zum Abschnitt Systemvariablen und klicken Sie auf den Neu Button.

5. Im Feld Variablenname geben Sie den Variablennamen als WIN_SDK_TOOLS ein.

6. Im Feld Variablenwert geben Sie den Pfad zum Ordner an, der die Windows SDK-Tools enthält.

7. Klicken Sie auf OK, um die Änderungen zu speichern.

Als Nächstes müssen wir eine makefile.toml erstellen, in der wir Bauvorschriften definieren werden.

Cargo-make ist ähnlich wie das reguläre make, aber die Regeln sind in einem etwas anderen, einfacheren Format definiert. Um genauer zu sein, erstellen wir in diesem Skript Aufgaben für das Bauen des Treibers, das Umbenennen der Erweiterung zu .sys, das Signieren des Treibers mit den Utilities makecer.exe und signtool.exe, das Deployen des Treibers (Verschieben des Treibers und des Zertifikats in einen separaten bin-Ordner) und das Reinigen des Builds.

Makefile.toml

[env.development]
TARGET_PATH = "target/x86_64-pc-windows-msvc/debug"

[env.release]
TARGET_PATH = "target/x86_64-pc-windows-msvc/release"
BUILD_FLAGS = "--release"

[tasks.build-driver]
script = [
    "cargo build %BUILD_FLAGS%"
]

[tasks.rename-driver]
dependencies = ["build-driver"]
ignore_errors = true
script = [
    "cd %TARGET_PATH%",
    "rename hello_win_kernel.dll hello_win_kernel.sys",
]

[tasks.sign-driver]
dependencies = ["build-driver", "rename-driver"]
script = [
    ""%WIN_SDK_TOOLS%\makecert.exe" -r -pe -ss PrivateCertStore -n "CN=hello_win_kernel_cert" hello_win_kernel_cert.cer",
    ""%WIN_SDK_TOOLS%\signtool.exe" sign /fd sha256 /v /s PrivateCertStore /n "hello_win_kernel_cert" /t http://timestamp.digicert.com /a %TARGET_PATH%/hello_win_kernel.sys",
]

[tasks.deploy]
dependencies = ["sign-driver"]
script = [
    "mkdir bin",
    "move hello_win_kernel_cert.cer bin\hello_win_kernel_cert.cer",
    "move %TARGET_PATH%\hello_win_kernel.sys bin\hello_win_kernel.sys"
]

[tasks.cleanup]
script = [
    "rmdir /s /q bin",
    "cargo clean",
]

Um das Projekt zu erstellen, die Erweiterung zu ändern und den Treiber zu signieren, müssen Sie den folgenden Befehl ausführen (Verwenden Sie nicht das integrierte VSCode-Terminal, da es während der Treibersignierung zu Problemen kommen kann. Ich empfehle die Verwendung des Windows-Terminals):

cargo make deploy

Um das Projekt zu bereinigen, führen Sie den folgenden Befehl aus:

cargo make cleanup

Sie können auch einzelne Schritte separat ausführen. Zum Beispiel, wenn Sie nur den Treiber signieren müssen, führen Sie folgenden Befehl aus:

cargo make sign-driver

Als nächstes können Sie mit dem Testen fortfahren. Um dies zu tun, starten Sie eine virtuelle Maschine mit Windows 10 x64 oder Windows 11, mit aktiviertem Testmodus und Debug-Modus. Falls diese Modi deaktiviert sind, müssen Sie die folgenden Befehle ausführen und das Betriebssystem neu starten:

HINWEIS: Das Terminal sollte mit Administratorrechten ausgeführt werden

# Enable Test mode
bcdedit -set TESTSIGNING ON

# Enable Debug kernel
bcdedit /debug on

Kopiere das **DebugView** Tool aus dem **sysinternals** Paket, welches du von den Microsoft Servern heruntergeladen haben solltest, auf die virtuelle Maschine. Erstelle einen Testordner auf dem Desktop und übertrage deinen Treiber und das Zertifikat von der Hostmaschine in diesen Ordner.

Dann starte **DebugView**, klicke auf **Capture** und setze ein Häkchen neben **Capture Kernel** und Enable Verbose Kernel Output. Dies ermöglicht es dir, die Kernel-Debug-Ausgabe zu sehen.

Nach diesen Manipulationen können Sie mit der Registrierung fortfahren und den Treiber starten, indem Sie die folgenden Befehle im Terminal ausführen:

HINWEIS: Das Terminal sollte mit Administratorrechten ausgeführt werden, wenn ein Treiber auf Windows registriert und gestartet wird

Um Ihren Treiber zu registrieren:

sc create hello_win_kernel binPath= "FullPathhello_win_kernel.sys" type= kernel start= demand

Startfahrer

sc start hello_win_kernel 

Ergebnis

Prima! Wenn du dich erfolgreich registriert und deinen Treiber gestartet hast, solltest du die "Hello, world!" Nachricht von deinem Treiber in DebugView sehen können.

Zusammenfassung

Das war`s! Sie haben gelernt, wie man einen eigenen Treiber mit der Programmiersprache Rust erstellt. Wie Sie sehen können, ist es möglich, einen Treiber in Rust zu schreiben, obwohl es einige Mühe erfordert. Tatsächlich wird das Ergebnis sehr beeindruckend sein, wenn Sie alles richtig einrichten. Also, ich warte auf Sie im zweiten Artikel, wo wir mit dem Schreiben eines echten Treibers fortfahren werden.

Wenn Sie weitere Fragen haben oder zukünftig weitere Unterstützung benötigen, zögern Sie nicht, sich zu melden. Viel Erfolg bei der Entwicklung Ihres Treibers!

Referenz

1. Microsoft ist damit beschäftigt, Kern-Windows-Code in dem speichersicheren Rust neu zu schreiben

    https://www.theregister.com/2023/04/27/microsoft_windows_rust/

2. Linus Torvalds: Rust wird in Linux 6.1 integriert

    https://www.zdnet.com/article/linus-torvalds-rust-will-go-into-linux-6-1/

3. Skripte erstellen

    https://doc.rust-lang.org/cargo/reference/build-scripts.html

4. Skript erstellen für Treiber

    https://github.com/memN0ps/rootkit-rs/blob/master/driver/build.rs

5. MSVC-Flags

    https://learn.microsoft.com/en-us/cpp/build/reference/linker-options?view=msvc-170