[Window Device Driver] 1. 환경구성 및 기초

[Window Device Driver] 1. 환경구성 및 기초

윈도우 커널 구조

Ring 0 - Kernel

Ring 1 - Device Driver

Ring 2 - Device Driver

Ring 3 - Applications

RING 0~2까지가 Kernel-Mode , RING3는 User-Mode로 동작.

응용 프로그램 (Apllication)이 하드웨어 장치에 접근하기 위해서는 드라이버가 필요함.

커널모드는 기본적으로 사용자가 접근 불가능. 현재 윈도우 커널모드에서 RING 1과 2는 사용하지 않고 RING0 만을 사용한다.

대부분의 응용 프로그램들이 RING3에서 유저모드로 동작함.

NT 서비스 프로그램 : 윈도우 계정 로그온/로그아웃에 무관하게 항시 동작하게 만드는 프로그램 형태. 디바이스 드라이버는 NT 서비스 형태로 시스템에서 동작하여 항시 상주하거나 언제건 메모리에서 제거할 수 있다.

낮은 레벨의 RING 단계 프로그램은 보다 상위단계 RING 프로그램에 간섭과 접근이 불가능함.

허나 특정 조건에서 상위권한 RING에 접근을 허용할수도 있음.

환경 구축

윈도우 10 기준, windows10 SDK, Visual studio 2019, WDK 10 , 디버깅을 위한 dbgview 설치가 필요함. 현재는 윈 11이 나온 상태이기 때문에 MSDN에서는 11 기준으로 소개하므로, 별개 링크에서 구성요소를 준비한다.

윈도우는 하위호환성 ( win7에서 제작 → win10에서 실행) 은 지키지만 상위호환성(win10에서 제작 → win7에서 실행) 은 지켜지지 않으므로 되도록 구버전 프로그램을 이용해 구축하자.

wdk 설치 후 자동으로 VS2019용 확장프로그램까지 설치가 진행된다.

프로젝트 생성 및 드라이버 프로젝트 기본 구성

Visual Studio에서 프로젝트 새로 생성 - WDM Driver로 진행한다.

cpp 소스파일 생성후 코드를 작성한다.

우선 헤더파일을 include 해야하는데, 두가지 종류가 있다.

ntddk.h : NT Legacy Style 드라이버 디바이스 스택을 사용하지 않아 장치와 통신하지 않는, 커널레벨에서 코드 동작을 위해 만드는 드라이버. 어느 디렉토리에 있더라도 실행이 가능하다.

wdm.h : WDM style 드라이버 디바이스 스택을 사용하며 장치와 통신한다. Windows\System32\Drivers 디렉토리에 존재해야 한다.

*디바이스 스택?

하나의 하드웨어 디바이스 관리를 위해서는 해당 하드웨어를 관리하기 위해 여러개의 드라이버가 필요함

각 드라이버는 디바이스 관리를 위하여 각 디바이스에 자신(드라이버)의 디바이스 오브젝트를 생성한다.

하나의 디바이스 내에 여러 드라이버들이 만든 디바이스 오브젝트가 스택처럼 만들어지게 되는데, 이것이 디바이스 스택이다.

window에 연결된 장치들을 Device Tree 로 표기하고, 트리에 표현되는 각 장치들을 Device Node 라고 한다.

로 표기하고, 트리에 표현되는 각 장치들을 라고 한다. 디바이스 노드 내에 구성되는 Device Object 들이 모여 Device Stack이 된다.

나중에 별도로 정리한 문서 만들 필요 있어보임.

헤더파일 include 후 Driver Entry를 작성해준다.

일반적인 C 언어 파일의 main함수,DLL 파일로 치면 dllmain.cpp 에 있는 APIENTRY DLLMain 함수와 동일하게 가장 먼저 실행되는 함수이다.

#include extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "Hello World!

"); return STATUS_UNSUCCESSFUL; }

extern C는 컴파일 시 네임 맹글링을 C언어 방식으로 사용하겠다는 의미로, C++방식 네임 맹글링이 이뤄질 시 외부 프로그램에서 이 모듈을 참조할 수 없기 때문에 타 모듈과의 호환성을 위해 C 네임 맹글링을 이용하게 된다.

위와같이 코드 작성 후 빌드를 해야하는데, 하위호환성 옵션을 먼저 해야한다.

프로젝트 속성 - Driver Settings에 들어가보면 Target OS, 즉 목표로 하는 OS 버전을 선택할 수 있는데, 윈도우의 경우 상위호환성이 지켜지지 않기 때문에 윈7 기준으로 빌드해야 그 하위 OS들에서 실행할 수 있다.

NT legacy style은 드라이버 설치를 지원하지 않기 때문에 설치파일인 .inf 파일은 솔루션 목록에서 삭제해줘야한다.

빌드시 "이 프로젝트에는 스펙터 완화된 라이브러리가 필요합니다 " 라는 에러가 발생한다면, 속성 → C/C++ → CodeGeneration(코드 생성) → Spectre Mitigration(스펙터 완화) 를 Disable 해야한다.

( https://docs.microsoft.com/ko-kr/visualstudio/msbuild/errors/msb8040?view=vs-2019)

또한 미 사용 파라미터는 오류로 처리되기 때문에 예외처리가 필요하다.

#include extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { //미 사용 파라미터를 에러처리 하지 않으면 오류 발생 UNREFERENCED_PARAMETER(DriverObject); UNREFERENCED_PARAMETER(RegistryPath); //디버그 메시지 출력 DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "Hello World!

"); return STATUS_UNSUCCESSFUL; }

드라이버 서비스 등록 및 실행

빌드가 왼료되면 드라이버를 서비스에 등록해서 실행해봐야한다.

sc.exe [] command [] option

윈도우에서 지원하는 sc를 이용해 드라이버를 서비스에 등록하고 실행해보자.

create : 서비스 생성

query : 서비스 상태 확인

start : 서비스 실행

stop : 서비스 중단

delete : 서비스 제거

리눅스의 systemctl이나 service와 비슷한 역할을 수행한다고 생각해도 될듯 .

아래 명령을 관리자권한 cmd에서 실행해주자.

sc create driver1 binpath="C:\Users\synod2\source\repos\MyDriver1\Debug\MyDriver1.sys" displayname=driver1 start=demand type=kernel

binpath : 바이너리 위치

displayname : 사용자에게 보여질 이름

start : 구동 방법

type : 드라이버 서비스 유형

SC 옵션 관련해서 나중에 일괄정리 필요할듯

서비스 생성이 완료되면 디버거를 켜두고 실행까지 진행

디버그 로그 분석 도구 Debugview ++

유저모드와 커널모드 디버깅 로그를 볼 수 있는 프로그램인 debugview의 개량판인 debugview++을 이용해서 로그를 찍어보자.

https://github.com/CobaltFusion/DebugViewPP

디버그뷰를 관리자권한으로 실행 후, cmd에서 아까 등록한 드라이버를 실행해본다.

위 에러는 시스템 아키텍쳐가 맞지 않으면 발생할 수 있는 에러다.

혹은 64비트 빌드시 이런 에러가 날수도 있다.

이는 64비트 윈도우10 환경이기 때문. 빌드된 드라이버가 32비트건 64비트건 서명이 되어있지 않으면 차단되는걸로 보인다.

윈도우에서 서명되지 않은 드라이버를 설치할 수 있도록 설정 변경이 필요하다.

bcdedit.exe -set loadoptions DISABLE_INTEGRITY_CHECKS bcdedit.exe -set TESTSIGNING ON

혹은

bcdedit /set nointegritychecks on bcdedit /set testsigning on

cmd에서 위 명령어 실행 후 재부팅 진행

이걸로도 안되면 고급 시작옵션을 통해 설정해야한다.

고급 시작옵션 - 문제해결 - 고급옵션 - 시작 설정 선택하여 재부팅하면

이렇게 선택하는 창이 나오는데, F7을 입력하여 드라이버 서명 적용 안함 을 선택한다.

우하단에 저런 메시지가 뜨면 TESTSIGNING이 적용된거다.

허나 계속 오류가 발생하고, DBGview에도 디버그 메시지가 나오지 않더라.

실패 원인 분석

확인해보니 각기 다른 원인이 있었다.

STATUS_UNSUCCESSFUL 을 반환시에 저렇게 실패 메시지가 나온다 디버그 메시지가 나오지 않는건 win7 이상부터는 dbgprint가 그냥은 나오지 않기때문

몇가지 방법을 시도해볼건데

디버그 메시지가 나오게끔 수정 + 환경 구성 1이 안된다면 STATUS_UNSUCCESSFUL을 반환하지 않게 수정

dbgview 대신 어차피 VM에 올라가있으니 그냥 커널 디버거를 붙여버리는걸로

https://github.com/4d61726b/VirtualKD-Redux

재시도

아래 순서로 다시 시작해봐야겠다.

개발환경에서 장치 드라이버 빌드 VM으로 옮겨서 실행, 유저모드 우회 체크 VirtualKD 걸고 디버깅

그 전에 먼저, 드라이버 로드하는 프로그램을 사용하는 대신 로더도 직접 빌드해서 사용해보자.

참고 문서

https://docs.microsoft.com/ko-kr/windows-hardware/drivers/download-the-wdk - WDK 다운로드 MSDN페이지 (win11)

https://developer.microsoft.com/ko-kr/windows/downloads/windows-10-sdk/- MSDN 페이지(구버전 윈도우)

https://nroses-taek.tistory.com/276 - 윈도우 디바이스 드라이버 제작

https://richong.tistory.com/268 - 디바이스 스택

https://docs.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/device-nodes-and-device-stacks -디바이스 스택 + 디바이스 노드

https://richong.tistory.com/89 - 디바이스 오브젝트 , 디바이스 노드

https://jungmonster.tistory.com/17 - 디바이스 스택

https://oasess.tistory.com/12 -윈도우7 이상에서 디버그 메시지 출력

https://hack.kr/87 드라이버 로더 만들기

from http://my-repo.tistory.com/99 by ccl(A) rewrite - 2021-11-18 01:01:07