Reversing/Kernel

[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 <ntddk.h>

extern "C" NTSTATUS DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath) {
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "Hello World!\n");
    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 <ntddk.h>

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!\n");
    return STATUS_UNSUCCESSFUL;
}

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

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

sc.exe [<servername>] command [<servicename>] 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

 

GitHub - CobaltFusion/DebugViewPP: DebugView++, collects, views, filters your application logs, and highlights information that

DebugView++, collects, views, filters your application logs, and highlights information that is important to you! - GitHub - CobaltFusion/DebugViewPP: DebugView++, collects, views, filters your app...

github.com

디버그뷰를 관리자권한으로 실행 후, 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에도 디버그 메시지가 나오지 않더라.


실패 원인 분석

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

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

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

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

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

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

 

GitHub - 4d61726b/VirtualKD-Redux: VirtualKD-Redux - A revival and modernization of VirtualKD

VirtualKD-Redux - A revival and modernization of VirtualKD - GitHub - 4d61726b/VirtualKD-Redux: VirtualKD-Redux - A revival and modernization of VirtualKD

github.com


재시도

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

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

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


참고 문서

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

 

Download the Windows Driver Kit (WDK) - Windows drivers

Download instructions for the latest released version of the Windows Driver Kit (WDK)

docs.microsoft.com

 

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

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

 

윈도우 디바이스 드라이버 기초(1)

디바이스 인식 후 드라이버 생기는 순서 1) 버스 드라이버 2) 기능 드라이버 3) 필터 드라이버 3가지가 연속되어 디바이스 스택을 만들고 응용프로그램과 연결한다. 후에 명령을 필터 드라이버로

nroses-taek.tistory.com

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

 

[Device Stack] 디바이스 스택

디바이스 스택 하나의 디바이스(하드웨어)를 관리하기 위해서는  디바이스를 관리하는 여러개의 드라이버가 필요하다. 그리고 각 드라이버들은 해당 디바이스의 관리를 위해서 각 디바이스에

richong.tistory.com

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

 

Device nodes and device stacks - Windows drivers

In Windows, devices are represented by device nodes in the Plug and Play (PnP) device tree.

docs.microsoft.com

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

 

장치 노드[Device node], 장치 개체[Device Object] 개념

Device Driver 관련 문서를 읽다 보면 장치 노드, 장치 스택 등 필요한 용어들의 정리가 필요하다. 물론 처음 공부할 때 이해보다는 부딪처보는 스타일이여서 막 코딩해보고 파란 화면을 보면서 했

richong.tistory.com

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

 

[Windows/WDM] 드라이버 스택 코드 이해

※제가 공부하면서 정리용으로 쓰는것이기 때문이 틀릴 가능성이 다분히 있습니다. 혹시 잘못된점이 있다면 댓글로 알려주세요 (아마 잘못된 부분이 많을 것으로 예상 됩니다.) 드라이버 스택

jungmonster.tistory.com

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

 

Windows VISTA, Windows 7 이상 버전에서 Debug (DebugView, WinDbg) 메세지 출력

[ 문제 ] Windows VISTA 이상 버전의 윈도우즈에서는 기본적으로 DbgPrint 와 KdPrint를 이용하여 출력하는 디버그 메세지가 출력되지 않는다. [ 원인 ] Windows VISTA에서는 DbgPrint 및 KdPrint가 각각 DbgPrint..

oasess.tistory.com

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

 

[ROOTKIT #6] 간단한 드라이버 로더

>잘안보이는 스샷은 클릭하셔서 확대해서 보시면 됩니다!< 지난 시간에는 드라이버를 로딩하기 위해 INSTDRV.exe 유틸을 사용했으나 이번에는 자신이 직접 로딩하는 간단한 드라이버 로딩 프로그

hack.kr