본 포스팅을 따라하시면 손쉽게 VS2010에서 64비트 WDK를 개발하실 수 있습니다.

시스템 변수를 추가하는데 1,2,3 순서대로 클릭한 후 그림과 같이 새 시스템 변수를 입력합니다. (자신의 경로명에 맞게)

지금부터 프로젝트를 생성하여 빌드를 할건데 귀찮으신 분은 아래 프로젝트 파일로 테스트 해 보시길 바랍니다. 

sample 프로젝트 다운로드  

sample.zip

 

Visual Studio 2010을 실행하여 메이크파일 프로젝트를 생성합니다.

 

빌드 명령줄을 화면과 같이 입력합니다.

 

속성 페이지에서 포함 디렉토리에 그림과 같은 경로를 추가합니다. (자신의 경로에 맞게)

라이브러리 디렉토리도 추가해야 하는데 c:\WinDDK\7600.16385.1\lib\win7\i386 한 줄 추가합니다.

이제 빌드를 위해 필수 3가지 파일을 준비합니다.

ddkbuild.cmd

MAKEFILE

SOURCES

 

파일들을 자신의 프로젝트의 sample.vcxproj가 있는 디렉토리에 복사 후 SOURCES 파일을 열어 TARGETNAME과 SOURCES를 자신의 환경에 맞게 설정합니다.

빌드가 잘 되는지 테스트 합니다.

이제 asm을 추가할 차례입니다.

프로젝트 디렉토리에 AMD64 디렉토리를 생성합니다.

(필자의 경로 : D:\source\sample\sample\amd64)

SOURCES 파일에 아래 한 줄을 추가합니다.

AMD64_SOURCES=func.asm

프로젝트에서 func.asm을 생성 후 다음과 같이 입력합니다.

작성한 asm을 C에서 연동해봅니다.

빌드가 잘 되는지 테스트 합니다. 

 

이제 실제 머신에서 잘 동작하는지 테스트합니다.

드라이버 서명

원칙적으로는 64비트에서는 서명되지 않은 드라이버를 서비스에 등록할 수 없습니다.

하지만 OSR Loader + Driver Signature Enforcement Overrider (이하 DSEO) 툴 조합으로 이를 해결할 수 있습니다.

OSR Loader (AMD64 용) 다운로드OSRLOADER.exe

DSEO 다운로드dseo13b.exe

DSEO의 Sign a System File을 이용하여 sys를 서명합니다.

서명한 파일을 OSRLOADER로 실행하면 됩니다.

(만약 동작하지 않는다면 DSEO에서 Enable Test Mode로 설정하시기 바랍니다.)

 VC++에서는 문자열을 다룰 때 char나 wchar_t 로 선언합니다.

그러나 드라이버 개발을 하다보면 STRING이나 UNICODE_STRING 로 선언된 것을 많이 볼 수 있는데요.

특이하게도 문자열을 구조체로 표현합니다.

각각 길이, 최대 길이(NULL을 포함하는), 문자열 포인터를 표현합니다.

DbgPrint에서 구조체를 직접 출력할 수 있는 특이점이 있습니다. 아래 %wZ 출력을 확인해 주세요.

문자열의 초기화는 RtlInitUnicodeString()를 사용하며, 아래와 같이 PSEUDO 코드를 작성할 수 있습니다.

UnicodeString->Buffer = 초기화 문자열;

UnicodeString->Length = wcslen(초기화 문자열) ;
UnicodeString->MaximumLength = UnicodeString->Length + sizeof(UNICODE_NULL) ;

아래 코드는 동적으로 할당 및 해제 하는 방법입니다. Buffer만 동적으로 할당하니 결국 malloc()과 같다고 볼 수 있습니다.

이번에는 메모리 동적 할당에 대해 알아보겠습니다.

Ring3에서는 동적으로 메모리를 할당할 때 malloc이나 HeapAlloc 같은 함수를 사용해보셨을겁니다.

그러나 드라이버에서는 이 함수를 사용할 수 없습니다.

그럼 어떻게 동적 메모리를 생성할 수 있을까요?

커널엔 메모리 풀이라는 것이 있는데 이것이 커널모드 힙입니다.

커널에서 힙을 할당하기 위해선 ExAllocatePool 이라는 함수를 사용합니다.

주목해볼만한건 인자로 NonPagedPool을 주었는데요. 인자 값으로 아래 두가지가 있습니다.

NonPagedPool : 항상 메모리에 존재

PagedPool : 페이지 아웃 혹은 인이 될 수 있음

페이지 아웃이 되면 공포의 BSoD가 뜨겠죠? 그것을 방지하기 위해서 NonPagedPool을 인자로 주어야 합니다.

 

잘 뜹니다~

주의하실 점은 동적 메모리를 반드시 해제해 주어야 합니다. 안그러면 커널 메모리에서 둥둥 떠다닙니다~

저는 WDK를 처음 접하고 코딩을 했을때, Ring3 어플리케이션에서 쓰이는 printf, malloc 같은 함수들을 사용하지 못해서 적잖이 당황한 기억이 있습니다.

그래서 WDK관련 책들을 샀는데, 입문자가 보기엔 너무 생소하고 난해한 용어들이 많아 바로 책을 덮어버렸습니다.

책을 덮고.. 독자적으로 여러 소스들을 분석하여 얻은 결론 하나, 내부 동작 원리에 대해 잘 몰라도 개발할 수 있다는 것입니다.

물론 심도있는 개발을 위해 전부 필요한 내용이지만, 일단 진입장벽부터 넘어야 하지 않겠습니까?

우선 들어가기 전에 이 글을 읽는 대상은..

1. Ring3 에서 c/c++ 기반 시스템 프로그래밍 개발 가능한 분

2. 윈도우즈 동작 메커니즘에 대해 어느정도 이해하고 계신 분

3. 위의 두가지 조건에 충족하며 드라이버 제작을 처음으로 해보시려는 분

따라서 아주 기초적이고 구구절절한 내용은 생략합니다.

그럼, 아주 심플한 제작부터 시작해보겠습니다.

드라이버 제작에 앞서 필수적인 파일 2가지가 있습니다. 아래 두가지 파일을 작성 후 프로젝트 폴더에 저장하면 됩니다.

MAKEFILE

!INCLUDE $(NTMAKEENV)\makefile.def

SOURCES

TARGETNAME=simple
TARGETPATH=.\sys
TARGETTYPE=DRIVER
SOURCES=simple.c

그 다음, simple.c를 작성합니다.

 

정말로 이렇게 심플한 코드가 실행이 될까요? 책에선 드라이버 스택이 어쩌고 저쩌고.. 익스텐션이 어쩌고저쩌고..

뭐 일단, 빌드를 해 봅니다.

 

 

빌드된 sys는 \sys\i386 경로에 있을 것 입니다. (xp로 빌드한 경우) 그럼 이 드라이버를 커널에 올려 봅시다.

드라이버를 상주시키는 파일은 구글에서 instdrv로 검색하시면 나옵니다. 로깅 뷰어는 DebugView를 사용하면 됩니다.

 

 

짜잔~ 실행이 되었군요. VC++ 로 작성하였던 내용과 별반 다르지 않군요.

이제부터 이 내용을 뼈대삼아 살을 붙여나갈 예정입니다.

 

+ Recent posts