간단하게 커널모드 코드를 테스트 할 수 있는 방법에 대해서 설명할까 합니다.
응용프로그램 레벨에서는 사용할 수 없는 인스트럭션 (예. mov eax, cr0 )들에 대한 테스트가 필요한 경우도 있고, 간단한 커널모드 코드 조각을 테스트해야 하는 경우도 있고, 커널모드 안티디버깅 같은거 테스트 할 때... 필요한 상황이야 많습니다.
대부분의 응용프로그램 개발자들은 커널모드 프로그램 개발에 대해서 알지 못하고, 간단한 테스트 하나 하자고, 두꺼운 책들과 씨름하기엔 너무 귀찮고, 좀 어렵죠?
좀 쉽게 할 수 있는 방법이 없을까요? (있으니까 이런 글을 쓰고 있겠죠.)
유닛테스트 프레임웤 중에
cfix 라는 녀석은 윈도우즈 커널모드 코드에 대한 유닛테스팅을 지원합니다. 예전에도 몇번인가 제 블로그에서 다뤘던거 같은데요.
cfix 를 이용해서 테스트할 커널 코드를 작성하고, 프레임웤을 이용해서 실행해보면 되는거죠. 드라이버를 실행하기 위한 서비스 등록/시작/중지/제거기능, 드라이버 구현을 위한 기본 코드따위는 프레임웤이 알아서 다 해줍니다.
우린 그냥 프레임웤에 테스트할 코드만 넣어주면 땡입니다. 아싸~
우선
여기에서 cfix 프레임웤을 받아서 설치합니다.
홈페이지에 보면 Visual Assert 와 cfix 두 가지가 있는데 읽어보시면 알겠지만 visual assert 는 cfix 를 기반으로 만들어진 visual studio 용 플러그인입니다.
둘다 사용법은 같으니 아무거나 설치해도 됩니다만 나중에 visual studio 에서 유닛테스트를 사용할 때도 쓰려면 visual assert 를, 드라이버 테스트만을 위한거라면 cfix 를 설치하시면 됩니다.
설치할때 주의할 점은 설치 경로에 공백문자나 한글이 있는 경우 커널모드 유닛테스트를 사용할때 문제가 발생 할 수 있습니다. 그냥 C:\VisualAssert 에 설치하는게 가장 좋습니다.
C:\VisualAssert 아래 Doc, example 에 보면 필요한 내용은 다 있습니다. 그거 참고해서 알아서들 하세요... 라고 하고 싶... :-)
C:\VisualAssert\examples\KernelMode 에 보면 우리에게 필요한 모든게 다 있습니다.
suite.c 파일에 있는 주석들 대충 읽어보면 뭐가 뭔지 알거에요. 나중에 읽어보시고, 아래처럼 간단하게 고쳐봅시다.
#include
static void __stdcall Test1()
{
// CR4 레지스터에 접근해 볼까요?
unsigned long _cr4=0x00000000;
__asm
{
mov eax, cr4
mov _cr4, eax
}
CFIX_LOG(L"cr4 = 0x%08x", _cr4);
}
CFIX_BEGIN_FIXTURE( MyFixture )
CFIX_FIXTURE_ENTRY( Test1 )
CFIX_END_FIXTURE()
이제 드라이버 코드를 빌드해야 겠죠? 당연히 드라이버 빌드를 위해서는 DDK가 설치되어있어야 합니다. 우선 32 비트 xp 에서 테스트 할 것이므로 아래 그림처럼 WindowsXP \ x86 checked Build Environment 를 선택합니다.
당연히 디버깅을 할 상황도 생길 수 있기때문에 checked build 를 선택하는게 좋겠죠?
MakeFile, Sources 파일이 위치한 경로로 이동해서 "build -ceZ" 명령을 내려주면 됩니다.
빨간 부분으로 표시한 곳을 보면 에러가 발생했네요.
잘 읽어보면 에러를 워닝으로 간주하도록 설정이 되어있어서 워닝 -> 에러가 된 상황이죠. ( 간혹 워닝은 워닝이니까 하고, 무시하는 님들이 계신데, 워닝은 에러... 라고 생각하고, 미주알 고주알 따져서 반드시 다 없애주는 버릇을 들여줘야 합니다. 무시한 워닝 하나로 인해 정말 찾기 힘든 버그 만들어서 개고생 하는 사람들 많이 봤습니다 )
워닝 메세지를 보니 cr4 라는 레이블을 인식못한다는 군요. 이것은 DDK 에 내장된 어셈블러가 'cr4' 문자열을 레지스터 이름으로 인식하지 못하고, 일반 문자열로 인식하기 때문이겠죠.
mov eax, cr4 명령을 기계어로 넣어주거나, __readcr4( ) 함수를 이용하면 됩니다. 자세한건 인터넷 찾아보시고요. 아래 처럼 코드를 수정해 주시고, 다시 build -ceZ 명령을 해봅시다.
static void __stdcall Test1()
{
// CR4 레지스터에 접근해 볼까요?
unsigned long _cr4=0x00000000;
__asm
{
_emit 0x0f ; mov eax, cr4
_emit 0x20
_emit 0xe0
mov _cr4, eax
}
CFIX_LOG(L"cr4 = 0x%08x", _cr4);
}
아 ㅅㅂ 또 에러인데, 이번도 warning 때문에 발생한 문제네요. 그런데 워닝 메세지도 없습니다. ㅠ.ㅠ
build 명령을 내리면 현재 MakeFile 이 있는 디렉토리에 buildXXX_XXX_XXX.wrn/err/log 파일이 생성되는데 각 파일들은 워님, 에러, 로그를 담고있습니다.
wrn 파일을 열어보면 아래와 같은 내용이...
1>c:\visualassert\examples\kernelmode\cl : warning D9035 : option 'Wp64' has been deprecated and will be removed in a future release
1>c:\visualassert\examples\kernelmode\suite.c : warning C4819: The file contains a character that cannot be represented in the current code page (949). Save the file in Unicode format to prevent data loss
대충 요약해 보면 첫 번째 라인은 64 비트 호환모드 옵션(/Wp64)때문인데 아마 vs 2003 이후 컴파일러부터는 필요없는 옵션일겁니다.
두 번째는 소스 파일 인코딩이 cp949 가 아니라는 거죠. 외국에서 만든거니 코드페이지가 달라서 발생한 문제입니다.
다 귀찮으니 SOURCES 파일의 컴파일 옵션을 아래처럼 수정하고, 다시 빌드합니다.
( 64 비트 호환모드 체크 안함 / 워닝을 에러로 처리 안함 )
# MSC_WARNING_LEVEL=/W4 /WX /Wp64
MSC_WARNING_LEVEL=/W4
그대로 따라했다면 " C:\VisualAssert\examples\bin\chk\i386\kern.sys/pdb/obj/lib " 같은 파일들이 생겼을겁니다. 젠장, 이제 겨우 빌드에 성공했군요. -_-;
이제 빌드 한 커널드라이버를 실행하기 위해서 가상머신에 cfix 프레임웤을 설치해야 합니다. 사실 개발 머신에는 cfix 프레임웤을 설치할 필요는 없으나 예제 코드를 그대로 사용하려고 했던거고요.
정말 중요한건 드라이버를 실행할 PC 에 cifx 프레임웤을 설치해야 하는거죠.
가상머신에 visual studio 가 설치되어있지 않은 경우 visual assert 를 설치하려하면 오류가 나고, 설치가 중단됩니다. 당연히 visual assert 는 visual studio 플러그인이니까요. 홈페이지에서 cfix 를 다운로드 해서 설치하거나 " c:\VisualAssert\bin\i386 " 폴더 아래의 파일들을 가상머신의 적당한 경로에 복사합니다. 편한대로 하세요~
저는 가상머신의 c:\dbg 폴더 아래에 복사했고, 빌드 할 실행파일 kern.sys 도 같은 경로에 복사했습니다. c:\dbg\cfix32.exe -kern kern.sys 명령을 실행하면 아래처럼 우리가 작성했던 코드의 결과를 확인할 수 있습니다.
참~ 쉽죠~?! ^__^