logo

Windows 커널 개발에 Rust 사용 소개 (파트 1)

소개

안녕하세요, 두려움 없는 독자여러분! 강력한 Rust 프로그래밍 언어로 무장하여 드라이버 개발의 영역으로 짜릿한 여정을 준비하세요!

이 흥미진진한 모험을 시작하면서, 우리가 보이지 않는 프로세스를 렌더링할 수 있는 강력한 드라이버를 만들어 낼 예정인 탐험을 기대하십시오. 이 기사를 건너뛰는 것은 이곳에 제기된 질문들에 대한 답을 얻을 수 있는 기회를 놓치는 것이 될 것입니다.

만약 Rust가 여러분에게 낯선 영역이라면 걱정하지 마십시오. 저는 여러분의 안내자가 되어 C++의 익숙한 영역으로도 함께 탐험할 것입니다. 필요한 것은 약간의 여유 시간, C++ 프로그래밍에 대한 숙련도, 그리고 커널 레벨 마법에 대한 기본적인 이해뿐입니다.

그런데 왜 Rust일까요, 궁금하실 겁니다. 답은 명백합니다: Rust는 스타일, 혁신, 그리고 흔들림 없는 강력함을 결합합니다. C++와 유사한 성능을 제공하며, 통과할 수 없는 안전 조치로 강화되었습니다. Microsoft, Google, Mozilla, 그리고 Linux Foundation 같은 기술 거인들이 그 잠재력을 인정했습니다. 심지어 "C 영원히"를 주장하는 Linus Torvalds도 공식적으로 Rust의 Linux 커널 통합을 지지했습니다 [1]. Microsoft는 Windows의 핵심을 Rust로 재작성하고 있습니다 [2], 하지만 아직 개발자들에게 Windows 커널 내에서 Rust를 사용할 수 있는 특권을 부여하지 않았습니다. 상관없습니다; 우리 스스로 고삐를 잡고 그들의 노력을 뛰어넘을 것입니다.

2015년에 첫 번째 버전의 언어가 출시되었으며, 그 이후로 6주마다 업데이트되고 있습니다. 안정적인 버전, 베타 버전, 그리고 나이틀리 버전의 총 3개 릴리즈 채널이 있습니다. (참고로, 드라이버를 개발하기 위해서는 나이틀리 툴체인이 필요합니다). 또한, Rust에는 C++의 표준과 비슷한 에디션들이 있는데, 바로 Rust 2015, Rust 2018, 그리고 지금 작성하는 시점에서는 Rust 2021입니다. 이것이 Rust에 cargo fix --edition 명령어가 있는 이유로, 새로운 표준에 부적합한 부분을 부분적으로 수정하는 데 도움이 됩니다.

 

의존성

우리의 탐험을 위한 무대를 설정하기 위해, 필요한 도구를 모으고 앞으로 다가올 도전에 대비해 환경을 준비해야 합니다. 다음은 우리가 필요한 것들의 체크리스트입니다:

 


필요한 도구들
1. Rust 설치: 우선 Rust의 힘을 활용하기 위해 여기서 설치하세요.
2. SDK 설치: 우리의 탐험을 위해 Windows SDK가 필요합니다. 여기서 구할 수 있습니다.
3. WDK 설치: Windows Driver Kit (WDK)는 드라이버 개발에 있어 우리의 신뢰할 수 있는 동반자입니다. 여기서 얻을 수 있습니다.
4. Sysinternals 설치: Sysinternals Suite은 우리에게 꼭 필요한 도구 모음이 될 것입니다. 여기서 가져가세요.

참고: 터미널은 관리자 권한으로 실행되어야 합니다.

 

개발

설정
프로젝트를 생성한 후, hello-win-kernel 디렉토리로 이동하세요. 다음과 같은 구조를 확인할 수 있습니다:

cargo new hello-win-kernel --lib

프로젝트를 생성한 후, hello-win-kernel 디렉토리로 이동하세요. 다음과 같은 구조를 발견할 수 있습니다:

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

Rust에서는 일반적으로 애플리케이션의 진입점을 포함하는 파일을 main.rs라고 명명하며, 라이브러리의 경우에는 lib.rs라고 합니다. Cargo.toml 파일은 프로젝트 의존성과 설정을 보유하며, .gitignore는 바이너리가 저장되는 target 디렉터리를 현명하게 제외합니다.
이제, Cargo.toml 파일을 편집함으로써 프로젝트 설정을 강화합시다. 먼저, [lib] 섹션을 추가하고, 진입점 파일의 경로를 지정하며 "동적 라이브러리"로 지정합시다.

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

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

우리는 또한 [profile.dev] [profile.release] 섹션을 설정하여 panic 유형을 "abort"로 설정하여 오류 처리를 개선합니다.
다음으로, [build-dependencies] 섹션을 포함시켜 Windows 레지스트리 작업을 위한 winreg 크레이트를 소개합니다:

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

[build-dependencies]
winreg = "0.50.0"

프로젝트 컴파일을 원활하게 하기 위해, rust-toolchain 파일을 hello-win-kernel 디렉토리에 생성하고, 나이틀리 툴체인을 사용하도록 지정하여 특수 플래그에 대한 접근을 가능하게 합니다:

rust-toolchain

nightly

드라이버를 컴파일하려면 WDK에 경로를 추가해야 합니다. 이는 build.rs 스크립트를 사용하여 달성할 수 있습니다. build.rs 스크립트는 패키지를 빌드하기 전에 cargo 에 의해 실행됩니다. 이를 통해 설치된 라이브러리를 찾고 Cargo에 그 정보를 포함할 수 있습니다. 코드에서 #[link(name = "libname")] 구문을 사용한 후에는 빌드 과정이 추가된 경로를 검색하고 C 또는 C++과 유사하게 라이브러리를 링크합니다. hello-win-kernel 디렉토리에 build.rs 파일을 생성하세요. 이 파일에 WDK를 가져오는 코드를 작성하십시오. 스크립트는 이 GitHub 저장소에서 찾은 것을 기반으로 할 수 있습니다.

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()
    );
}

드라이버를 시작하려면 먼저 구성 파일을 작성해야 합니다. 걱정하지 마세요, 저는 이 승리로 가는 길을 안내해 드리겠습니다.

1. 현재 도메인에 .cargo라는 이름의 디렉터리를 생성하세요—여러 가능성의 영역입니다.

2. 이 새로 발견된 도메인 내에 config라는 이름의 파일을 만드세요. 여기에 우리의 지시사항을 새길 것입니다.

 

이 플래그들을 config 파일 안에 기입하세요. 각 플래그는 드라이버 컴파일의 복잡한 깊이를 안내하는 등대와 같습니다. 이 플래그들에 대한 더 깊은 이해를 원한다면 MSDN [5]에서 찾을 수 있는 지혜의 기록을 탐구할 수 있습니다.

.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"
]

 

구현

휴! 만세, 우리 했어요! 믿을 수 있나요? 코드 작성을 시작할 시간이에요. 네, 드라이버 개발에 뛰어들 수 있습니다. C++처럼, Rust는 사용자 모드와 커널 모드 간의 차이 때문에 커널 모드에서 표준 라이브러리를 지원하지 않습니다. 그러므로 우리는 #![no_std] 속성을 사용하여 비활성화해야 하며, 이는 lib.rs 파일의 시작 부분에서 명시되어야 합니다.

다음으로, 연결 오류를 해결하기 위해 __CxxFrameHandler3 함수와 _fltused 변수를 선언해야 합니다. 추가로, 표준 라이브러리를 사용할 수 없게 되었으므로, 우리의 커스텀 panic_handler 를 구현해야 합니다.

앞으로, driver_entry 함수를 만들어보겠습니다. 이 함수는 드라이버의 진입점이 될 것입니다. 이 함수의 이름을 다르게 지정할 수 있지만, .cargo/config 파일에서 필드 "-C", "link-arg=/ENTRY:driver_entry"를 예를 들어 "-C", "link-arg=/ENTRY:entry"로 변경하여 명시해야 합니다.

Windows API는 C로 구현되어 있기 때문에 FFI (Foreign Function Interface)를 사용해야 합니다. 간단히 말해서, 이는 다른 언어에서 API를 호출할 수 있게 해주는 메커니즘입니다.

먼저, 이름 변경을 방지하기 위해 #[no_mangle] 속성을 사용 비활성화하고 함수 호출에는 extern "system"이라고 명시하여 시스템(stdcall) 호출 규약을 사용합니다. 편의를 위해 몇 가지 유형을 만듭시다. PDRIVER_OBJECTPUNICODE_STRING 대신 현재는 해당 데이터 구조가 필요하지 않으므로 PVOID를 사용하겠습니다.

그러면 다음 코드를 src/lib.rs에 추가합시다.

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
}

다음으로, src/types.rs를 생성하고 별칭(즉, C에서의 typedef)을 이용해 C 언어 스타일의 타입들을 추가할 것입니다. 추가로, src/ntstatus.rs 파일에는 STATUS_SUCCESS와 같은 상태들을 추가할 것입니다.

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;

좋습니다, 이제 드라이버 개발 시 디버그 정보를 기록하는 데 사용되는 DbgPrint API를 추가해 보겠습니다. 이를 위해 src/dbg.rs라는 파일을 생성하고, ntoskrnl에 연결한 다음 DbgPrint API를 추가하겠습니다. 또한, 더 편리하게 작업하기 위해, C 언어 특성상 문장 끝에 \O 문자를 지속적으로 추가해야 하므로 kd_print 매크로를 생성하겠습니다( C에서는 문자열이 \O 문자로 종료됩니다).

We`ll wrap DbgPrintunsafe 블록 안에 넣을 것입니다. 왜냐하면 그것은 다른 언어에서의 API이며, Rust는 그것에 대한 보증을 제공할 수 없기 때문입니다.

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)*) => {};
}

이제 우리는 드라이버를 성공적으로 빌드할 수 있습니다. 그러나 이것이 끝은 아니며, 다음으로 드라이버 서명 및 배포 메커니즘을 구현해야 할 것입니다.

C++로 작성된 아래의 예제 드라이버는 C 또는 C++에서 드라이버를 작성하는 것이 Rust에 비해 쉽다는 것을 보여줍니다. 하지만 마이크로소프트의 공식 지원이 나올 때까지, 사실상 우리가 직접 C++의 경우처럼 문제를 해결하고 구현할 때까지 (모두가 간절히 기다리고 있습니다), 우리는 Rust의 보장을 개발 수준에서 누릴 수 있어, 더 안전한 드라이버를 구축할 수 있습니다. 이는 전체 인라인 ASM, 패턴 매칭 및 Rust가 제공하는 많은 다른 멋진 기능들을 포함합니다.

일부 스타트업들은 사이버보안의 맥락에서 가상 장치용 드라이버를 개발하기 위해 이미 Rust를 사용하고 있습니다.

"hello-win-kernel-cpp" 프로젝트에서 C++ 예제 드라이버:

#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;
}

배포 및 테스트

드라이버를 테스트하기 위해, 먼저 .dll 확장자를 .sys로 변경하고 테스트 인증서로 서명해야 합니다. 이 모든 과정을 자동화하기 위해 cargo-make를 사용할 것입니다. 이를 수행하려면 터미널에서 다음 명령어를 실행하세요.

cargo install cargo-make

다음으로, WIN_SDK_TOOLS라는 미들웨어를 만들 것입니다. 이것은 Windows SDK 도구와 관련이 있을 수 있습니다. 다음 단계를 누구를 위해 서명하시겠습니까?

1. 이 옵션을 검색하고 실행하여 View advanced system settings를 엽니다.

2. System Properties 창에서, Advanced 탭을 선택하세요.

3. Environment Variables 버튼을 클릭하세요.

4. Environment Variables창에서 아래로 스크롤하여 System variables섹션으로 이동한 다음, New 버튼을 클릭하세요.

5. Variable name 필드에 WIN_SDK_TOOLS로 변수 이름을 입력하세요.

6. Variable value 필드에 Windows SDK 도구가 포함된 폴더의 경로를 입력하세요.

7. 변경사항을 저장하려면 OK 클릭하세요.

다음으로, 빌드 규칙을 정의할 makefile.toml 을 생성해야 합니다.

Cargo-make는 일반적인 make와 유사하지만, 규칙들이 약간 다르고 더 단순한 형식으로 정의됩니다. 구체적으로, 이 스크립트에서는 드라이버를 빌드하는 작업을 생성하고, 확장자를 .sys로 변경하며, makecer.exesigntool.exe 유틸리티를 사용하여 드라이버를 서명하고, 드라이버(드라이버 및 인증서를 별도의 bin 폴더로 이동)을 배포하고, 빌드를 정리합니다.

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",
]

프로젝트를 빌드하고, 확장명을 변경하며, 드라이버에 서명하기 위해서는 다음 명령을 실행해야 합니다 (드라이버 서명 중 문제가 발생할 수 있으므로 내장된 VSCode 터미널은 사용하지 마십시오. Windows Terminal 사용을 권장합니다):

cargo make deploy

프로젝트를 정리하려면, 다음 명령어를 실행하세요:

cargo make cleanup

개별 단계도 별도로 실행할 수 있습니다. 예를 들어, 드라이버에만 서명이 필요한 경우 다음 명령을 실행하십시오:

cargo make sign-driver

다음으로, 테스트를 진행할 수 있습니다. 이를 위해 Windows 10 x64 또는 Windows 11이 설치된 가상 머신을 시작하고, 테스트 모드와 디버깅 모드를 활성화하세요. 이 모드들이 비활성화되어 있다면, 다음 명령어를 실행하고 OS를 재시작해야 합니다:

참고: 터미널은 관리자 권한으로 실행되어야 합니다

# Enable Test mode
bcdedit -set TESTSIGNING ON

# Enable Debug kernel
bcdedit /debug on

**sysinternals** 패키지에서 **DebugView** 유틸리티를 복사하여, Microsoft 서버에서 다운로드 받아야 하는 것을 가상 머신에 옮깁니다. 데스크탑에 테스트 폴더를 만들고 호스트 머신에서 드라이버와 인증서를 이 폴더로 전송하세요.

그런 다음, **DebugView**를 실행하고, **Capture**를 클릭한 다음, **Capture Kernel**Enable Verbose Kernel Output 옆에 있는 체크박스를 선택하세요. 이렇게 하면 커널 디버그 출력을 볼 수 있습니다.

이러한 조작을 마친 후, 터미널에서 다음 명령어를 실행하여 등록을 진행하고 드라이버를 시작할 수 있습니다:

참고: Windows에서 드라이버를 등록하고 시작할 때는 관리자 권한으로 터미널을 실행해야 합니다

드라이버를 등록하려면:

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

드라이버 시작

sc start hello_win_kernel 

결과

훌륭해요! 성공적으로 등록하고 드라이버를 시작했다면, DebugView에서 당신의 드라이버가 보낸 "Hello, world!" 메시지를 볼 수 있어야 합니다.

요약

바로 그거예요! 여러분은 Rust 프로그래밍 언어를 사용하여 자신의 드라이버를 구축하는 방법을 배웠습니다. 보시다시피 Rust에서 드라이버를 작성할 수는 있지만, 일정한 노력이 필요합니다. 사실, 모든 것을 올바르게 설정하면 결과는 매우 인상적일 것입니다. 그러니, 두 번째 기사에서 만나 어떻게 진짜 드라이버를 작성해 나갈지 이어가 보겠습니다.

앞으로 추가 질문이 있거나 도움이 필요하시면 언제든지 연락주세요. 드라이버 개발에 행운을 빕니다!

참조

1. Microsoft는 메모리 안전한 Rust로 핵심 Windows 코드를 다시 작성하는데 바쁩니다

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

2. 리누스 토발즈: 러스트가 리눅스 6.1에 통합될 것입니다

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

3. 빌드 스크립트

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

4. 드라이버용 스크립트 구축

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

5. MSVC 플래그

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