Index
- 개요
- 개발 및 테스트 환경
2-1. 개발 환경
2-1. 테스트 환경- 기능
- 주의 사항
- 사용법
5-1. 테스트 모드 설정
5-2. 커맨드 라인에서 사용
5-3. Visual Studio에서 사용- 구현 상세
6-1. 진입점
6-2. Loader 프로세스
6-3. Unloader 프로세스- 개발자 코멘트
전체 소스 코드는 GitHub Repository에 공개되어 있습니다.
WinKMDLoader(Windows Kernel Mode Driver Loader)는 Windows의 번거로운 커널 드라이버 로드, 언로드 및 서비스 생성, 제거 작업에 대한 자동화를 제공하는 간단한 도구입니다.
커맨드 라인으로 실행하거나, 대상 Visual Studio 커널 드라이버 프로젝트의 디버깅 설정을 통해 개발 중 F5를 눌러 대상 커널 드라이버를 즉시 로드할 수 있습니다.
프로그램을 사용자가 종료하면, 대상 커널 드라이버가 자동으로 언로드되고 서비스가 제거됩니다.

C# 10.0 .NET Framework 4.8.1 Visual Studio 2022
Windows 10 22H2 19045.3693 x64 Visual Studio 2022
커널 드라이버 서비스 생성
커널 드라이버 로드
프로그램 종료 시 커널 드라이버 자동 언로드
프로그램 종료 시 커널 드라이버 서비스 자동 제거
커널 드라이버 서비스를 제어하기 위해 관리자 권한이 필요합니다.
안전하지 않은 코드가 작성된 커널 드라이버를 무심코 로드하여 BSOD를 발생시키는 불상사가 없도록 합시다.
커널 드라이버 개발 시 코드의 모든 동작에 대한 호환성과 안정성을 검증하는 습관은 필수입니다.
대상 드라이버가 서명되어 있다면 이 과정은 건너뜁니다.
※ 서명되지 않은 드라이버를 Windows에 로드하려면, 테스트 모드가 활성화되어 있어야 합니다.
다음 커맨드 라인을 실행한 후 PC를 재부팅 하여 테스트 모드를 활성화하거나 비활성화할 수 있습니다.
bcdedit /set testsigning on
bcdedit /set testsigning off
WinKMDLoader.exe <DRIVER_FILE_PATH>
DRIVER_FILE_PATH : 대상 드라이버 파일(.sys)의 경로입니다. 상대 경로가 지정된 경우 자동으로 내부에서 절대 경로로 변환하여 사용합니다.WinKMDLoader.exe TestDriver.sys
WinKMDLoader.exe "C:\TestDriver.sys"
Visual Studio 커널 드라이버 프로젝트 속성 > 구성 속성 > 디버깅으로 이동하여 아래 값을 설정합니다.
시작할 디버거 : 로컬 Windows 디버거를 선택합니다.
명령 : WinKMDLoader.exe의 절대 경로를 입력합니다.
별도의 전역 환경변수 설정 등의 작업을 거친다면 WinKMDLoader.exe만 입력해도 작동합니다.
명령 인수 : "$(TargetPath)"를 입력합니다.대상 커널 드라이버 파일의 경로에 공백 문자가 존재하는 경우를 위해 큰따옴표를 포함하여 입력합니다.

이제 코드 편집기에서 F5(디버깅 시작)를 누르면 해당 커널 드라이버의 서비스가 생성된 후 커널 드라이버가 로드되고, 디버깅을 중지하면 해당 커널 드라이버가 언로드된 후 커널 드라이버 서비스가 제거됩니다.
WinKMDLoader는 커널 드라이버 디버깅 기능이 없습니다. 위 설정으로 Visual Studio 디버거로 사용한다고 하여도 디버깅이 수행되는 것은 아닙니다.
전체 소스 코드는 GitHub Repository에 공개되어 있습니다.
private static void Main(string[] args)
{
// ...
if (args.Length == 1)
{
LoaderEntry(args[0]);
}
else if (args.Length == 3 && args[0].Equals("-unloader", StringComparison.CurrentCultureIgnoreCase) && int.TryParse(args[1], out int loaderProcessId))
{
UnloaderEntry(loaderProcessId, args[2]);
}
// ...
}
프로그램이 실행되면 Loader 프로세스로 실행할지, Unloader 프로세스로 실행할지 파라미터로 판단합니다.
5-2. 커맨드 라인에서 사용, 5-3. Visual Studio에서 사용과 같은 방법으로 커널 드라이버 파일의 경로를 파라미터로 전달하면 Loader 프로세스로 실행됩니다.
private static void LoaderEntry(string driverFilePath)
{
// ...
CreateUnloaderProcess(driverName);
// ...
if (ExecuteBackgroundProcess("sc", $"create \"{driverName}\" type= kernel binpath= \"{driverFileAbsolutePath}\"") != 0)
{
ExitWithError("Failed to create service.");
}
Console.WriteLine("Service created successfully.");
if (ExecuteBackgroundProcess("sc", $"start \"{driverName}\"") != 0)
{
ExitWithError("Failed to start service.");
}
Console.WriteLine("Service started successfully.");
while (true)
{
Console.ReadKey(true);
}
}
private static void CreateUnloaderProcess(string driverName)
{
using Process currentProcess = Process.GetCurrentProcess();
ExecuteBackgroundProcess(Assembly.GetExecutingAssembly().Location, $"-unloader {currentProcess.Id} {driverName}", false);
}
Loader 프로세스로 실행되면, 현재 Loader 프로세스가 종료되었을 때 자동으로 대상 커널 드라이버를 언로드하고 커널 드라이버 서비스를 제거해 줄 Unloader 프로세스를 새로 생성하여 실행합니다. (CreateUnloaderProcess)
파라미터로 전달받은 드라이버 파일 경로의 검증 및 변환이 성공했다면, Windows 시스템 구성 요소인 sc.exe 파일을 통해 커널 드라이버 서비스를 생성한 후 커널 드라이버를 로드합니다.
모든 과정이 성공했다면, 사용자가 직접 프로그램을 닫을 때까지 대기합니다.
private static void UnloaderEntry(int loaderProcessId, string driverName)
{
using Process loaderProcess = Process.GetProcessById(loaderProcessId);
loaderProcess.WaitForExit();
ExecuteBackgroundProcess("sc", $"stop \"{driverName}\"");
ExecuteBackgroundProcess("sc", $"delete \"{driverName}\"");
}
Unloader 프로세스로 실행되면, 파라미터로 전달받은 부모 Loader 프로세스가 종료될 때까지 대기합니다.
해당 Loader 프로세스가 종료되면, 대상 커널 드라이버를 언로드한 후 커널 드라이버 서비스를 제거합니다.