(Win32 : WindowsProgramming-31) Hello, Driver

Posted by : at

Category : win32   WindowsProgramming


개발 도구

  • Visual Stduio
  • Windows Driver Kit
  • Windows Driver Kit “Visual Studio Extension”

  • Device, Driver의 경우 BlueScreen을 유발할 수 있기에 VM을 통해서 테스트해보도록 하자.

프로젝트생성

  • Empty WDM 생성

  • Ex1.cpp 파일생성
// ex1.cpp
#pragma warning(disable:4100)

#include <ntddk.h>

void DriverUnload(PDRIVER_OBJECT pDriver)
{
    DbgPrint("DriverUnload");
}

extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath)
{
    DbgPrint("DriverEntry : &p\n", pDriver);

    pDriver->DriverUnload = DriverUnload;

    return STATUS_SUCCESS;
}

그냥 빌드하면 에러가 발생

  • 자동 생성된 .inf 파일 제거(프로젝트에서 제거)
  • 자신의 OS에 맞게 x84, x64 선택
  • 프로젝트 메뉴 -> 속성 -> C/C++ -> 코드 생성 항목 선택 후 -> 스펙터 완화(Spectre Mitigation) 라이브러리 사용 안함 선택
  • 속성 -> Driver Settings -> Target OS Version -> 자신의 OS버전에 맞게 변경

빌드하면 ex1.sys파일이 생성된다.


Driver Install

이제 아래의 단계들이 남았다

  • 디바이스 드라이버를 시스템에 설치
  • 디바이스 드라이버 시동(Start)
  • 디바이스 드라이버 중지(Stop)
  • 디바이스 드라이버 시스템에서 제거

디바이스 드라이버를 시스템에 설치

레지스트리 컴퓨터\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services에 접근 여기에 드라이버를 설치한다. 예를 들어서

컴퓨터\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ACPI에 접근시 ACPI.sys가 어디에 설치되어있는지 알 수 있다.

이제 레지스트리를 추가해야 하는데 방법은 세 가지가 있다.

  • 직접수정(비추천, 특히 Device Driver를 추가하기에 위험)
  • 레지스트리 API이용
  • sc.exe(SystemControll.exe) 도구 사용(이 방법을 이용할 예정)

  • 관리자 권한 cmd실행
  • $ sc create Ex1 type=kernel binPath=C:\Driver\Ex1\x64\debug\Ex1.sys

여기까지하면 레지스트리에 등록을 확인 가능

디바이스 드라이버 시동(Start)

드라이버를 메모리에 올리는 과정이다.

$ sc start Ex1

단, 디지털서명이 없으면 드라이버 시동이 불가능 윈도우 부트 설정을 변경해야 한다.
관리자 모드 cmd에서

$ bcdedit /set testsigning on

재부팅 까지 해야함

디바이스 드라이버 중지(Stop)

$ sc stop Ex1

디바이스 드라이버 시스템에서 제거

$ sc delete Ex1

Device Driver 코드

// ex1.cpp
#pragma warning(disable:4100)
// (PDRIVER_OBJECT pDriver)매개변수를 사용하지 않으면 Warning이 Error로 뜨게 된다
// #pragma warning(disable:4100)을 선언해서 Warning을 제거

#include <ntddk.h>  // 디바이스 드라이버를 개발하기 위한 함수/구조체 포함

// void DriverUnload([[maybe_unused]] PDRIVER_OBJECT pDriver) // (C++17) warning 4100을 방지해 준다.
void DriverUnload(PDRIVER_OBJECT pDriver)
{
    UNREFERENCED_PARAMETER(pDriver);        // warning 4100을 방지해 준다.

    DbgPrint("DriverUnload");
    // DbgView.exe에서 출력을 확인가능
        // (참고) DbgView.exe에서 Edit -> Filter -> Exclude에 다른 Device Driver에 나오는 메시지를 제외시켜야 보기 편함.
        // (참고2) DbgView.exe에 아무런 메시지가 안뜬다면?
        // 레지스트리 \HKEY_LOCAL_MACHIINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter 에 DEFAULT(REG_DWORD)를 0xf0000000으로 추가한다

    KdPrint(("AAAA"));
    // DBG가 정의되어 있다면 DbgPrint로 변환해줌
    // (참고) 괄호를 두개 쳐야함 오타아님
}

// Driver Entry Point (main이라 생각)
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver,     
                                // OS에서 관리하는 DeviceDriver 객체 주소
                                // DeviceDriver를 생성시 마다 할당된다.
                                PUNICODE_STRING pRegPath)
                                // 레지스트리 경로
{
    DbgPrint("DriverEntry : &p\n", pDriver);

    // Unload될때 어떤 함수를 부를지 등록(반드시 해야한다.)
    pDriver->DriverUnload = DriverUnload;
    // 등록을 하지 않을경우 PC가 꺼질때 까지 Device Driver가 종료되지 않음.

    return STATUS_SUCCESS;
}

About Taehyung Kim

안녕하세요? 8년차 현업 C++ 개발자 김태형이라고 합니다. 😁 C/C++을 사랑하며 다양한 사람과의 협업을 즐깁니다. ☕ 꾸준한 자기개발을 미덕이라 생각하며 노력중이며, 제가 얻은 지식을 홈페이지에 정리 중입니다. 좀 더 상세한 제 이력서 혹은 Private 프로젝트 접근 권한을 원하신다면 메일주세요. 😎

Star
Useful Links