본컬럼에대한모든저작권은 DevGuru에있습니다. 컬럼을타사이트등에기재및링크또는컬럼내용을인용시반드시출처를밝히셔야합니다. 컬럼들을 CD나기타매체로배포하고자할경우 DevGuru에동의를얻으셔야합니다. c DevGuru Corporation. All rights reserved 기타자세한질문사항들은웹게시판이나 support@devguru.co.kr 으로 문의하기바랍니다. http://www.devguru.co.kr - 1 -
written by Song Jiho(songjiho@devguru.co.kr) 1. 개요필자가 WDM 관련된강의를하면서자주접하는질문들이있다. 바로이번에소개하려고하는필터 (filter) 드라이버에관한질문이그중대표적인내용이다. 드라이버를작성하는이유나사용용도는하드웨어를직접제어해야하는필요성때문일경우도있지만이미나와있는기존드라이버들의동작내용을확인하거나기존드라이버를제어해야하는필요성때문인경우도많기때문인것같다. 필터드라이버는이럴경우가장적합한방법이될것이다. 필터드라이버의실제사용용도를먼저살펴보고예제를통해간단한필터드라이버를작성해필터드라이버를이해해보자. 필터드라이버의용도는사용자가사용하기나름이겠지만다음과같은필요에의해사용할수있다. 1-1 기존의드라이버에대한 I/O를감시 1-2 기존의드라이버에대한 I/O를수정 ( 통제 ) 1-3 제공되는드라이버와하드웨어간에문제해결 각각에대해조금더구체적인예를들어보면사용용도나필요성에대해쉽게이해가될 것이라고생각된다. 또한편의상위의세가지정도의기능을이번컬럼에서는필터링이 란단어로대체해서컬럼을진행하겠다. 1-1번과 1-2번항목의경우이번컬럼의예제로간단한골격이제공되겠지만사내의자료유출에대한보안책으로저장장치에대해서누가어떤내용을복사했는지기록을남기거나 (log), 또는인가받지않은사용자가저장장치에대해서접근할수없게하려면필터드라이버를작성해서탐색기 (exploer.exe) 와같은프로그램에서플로피와같은저장장치로어떠한내용을 I/O했는지감시하거나인가받지않은사용자의접근을제어하는방법을사용할수있다. 1-3번항목의경우 SCSI (Small Computer System Interface) 장치를예로들어볼수있다. SCSI하드웨어가한번에 4K보다적은양의데이터를전송하게설계되어있는데기존의드라이버에서는이러한내용을감안하지않고작성되어있을때필터드라이버를중간에삽입해서전송되는데이터가 4K 보가클경우드라이버가 4K단위로데이터를나눠서전송을하게수정할수있다. 또한요즘많이사용하는 USB MassStorage장치의경우 OS가제공하는드라이 http://www.devguru.co.kr - 2 -
버를사용하므로정해진방법대로밖에 I/O 를할수없으나여기에필터드라이버를삽입해 서다른저장공간에나만의데이터를저장할수도있다. 이밖에도필터드라이버를잘응용하면여러가지다양한분야로응용이가능할것이다. 그럼부디이번컬럼을통해서필터드라이버에대한개념을알아보고작성방법에관한 기본지식들을습득하기를바란다. 2. 의구조 2-1 구조 WDM 드라이버는계층화된 (layered) 드라이버구조를가지고있다. 그렇기때문에 Filter Driver도이러한 WDM의계층속에포함되게작성하는방법이일반적이다. 개념적으로 filter driver는다음의그림 2-1과같은모양을가지고있다. IRP Filter Functional Device Object Filter Physical Device Object Device Node [ 그림 2-1]Filter Driver 의 Stack 구조 http://www.devguru.co.kr - 3 -
기본적인구조 ( 파란색부분 ) 인 FDO 와 PDO 의구조에서필터링하기원하는곳에필터드라이 버가위치하게되고필터드라이버는 FDO 와 PDO 를거쳐가는모든데이터를보거나변경할 수있게된다. 상기 1 절의 3) 항에서설명한내용은그림 2-2 와같은모습을하게된다. Functional Device Object IRP Filter IRP IRP Physical Device Object Device Node [ 그림 2-2] Filter Driver 예제 2-2 필터드라이버의종류 WDM 필터드라이버는크게 Class Filter, Device Filter, Bus Filter의세가지종류로구분할수있고각각은또한설치되는위치에따라 Lower Filter와 Upper Filter 두가지로나눠질수있다. 또한 WDM 필터드라이버들은레지스트리에자신의종류와위치를기록함으로서원하는시점에원하는드라이버계층에포함 (Load) 되어질수있다. 우선종류에따라이들각각을간략히살펴보면다음과같은특징이있다. 1) Class Filter 주어진 Class에모든드라이버들이 Load 될때함께 Load되어서모든 Class의드라이버들 http://www.devguru.co.kr - 4 -
에대한필터링을할수있다. 이위치에설치된필터드라이버는단지 Class의영향을받을뿐이고하드웨어 ID나제조사심지어는 Bus Type과도무관하게설치되기원하는 Class의다른드라이버가 Load될때함께 Load 되어진다. 예를들어우리가 Mouse Class에대한 Class 필터드라이버로우리가제작한 MyMouse.sys 라는드라이버를등록한다면 USB Mouse 드라이버가 Load될때 MyMouse.sys가 load 될것이고 Serial Mouse가설치될때도 MyMouse.sys가 load되어결국모든 Mouse에대한필터링이가능해진다. 2) Device Filter Class filter와는다르게특정 device node에만설치되는필터드라이버이다. 예를들어 VID가 1234이고 PID가 5678인 USB 장치에대한필터링이필요할경우이장치에대한 Device Filter를설치해서다른장치에대한 I/O는받지않고단지원하는장치에대해서만필터링이가능하게할수있다. 3) Bus Filter 말그대로특정 BUS Driver에대해서필터링이가능한드라이버이다. 위의 2) 번항목에서는 USB 장치중특정장치만을필터링할수있지만 BUS Filter Driver를 USB BUS Filter Driver로설치하면모든 USB 장치에대한내용들을필터링할수있다. 이러한세가지종류의필터드라이버는각각마다설치되는위치에따라또다시 Upper Filter와 Lower Filter로구분되어진다. 2) 번항목의 Device Filter에서필터링하려는드라이버보다먼저 I/O 요청을받아서필터링하기원하면 Upper Filter로설치하게되고필터링하려는드라이버에서처리가끝난 I/O요청에대해서필터링하려면 LowerFilter로설치하게된다.( 단 Bus Filter Driver는 Upper Filter Driver만존재한다.) 1) LowerFilter LowerFilter driver는 PDO(Physical Driver Object) 로전달되는 I/O를가로채서살펴보거나수정하는용도로사용한다. 1-3의기능을수행하기에적당하다. 2) UpperFilter FDO(Function Device Object) 로전달되는 I/O를가로채서살펴보거나수정하는용도로사용한다. FDO로전달되는 I/O요청을수정하거나새로운 I/O요청으로변경하는데사용되기에적당하다. 이러한드라이버들은 Class Filter, Device Filter, Bus Filter 의순서로설치되게된다. 이상의내용을그림으로정리해보면다음과같다. 드라이버들의위치와순서를잘생각해 보면서다음 그림 2-3 을살펴보기바란다. http://www.devguru.co.kr - 5 -
s IRP Upper Class Filter Upper Device Filter Functional Device Object Lower Class Filter Lower Device Filter BUS Filter Physical Device Object Device Node [ 그림 2-3] Device Stack 구조 3. 작성법 3-1 기본수칙빌드하는방법은일반적인WDM드라이버빌드방법과동일하다. 코드상에서는다음과같은점들을주의해야한다. 주의 1) PnP와 Power 관련된루틴들은조심해서다뤄야한다. 주의 2) 작성되는드라이버가올라가는 Device Stack를정확히알고있어야하며 characteristics는수정하면안된다. 주의 3) 수정하려고하는기능이외의다른 IRP들은건드리면안된다. http://www.devguru.co.kr - 6 -
주의 4) 모든 dispatch routine 들에대해서처리해주어야한다. 주의 5) 정의되지않았거나처리하지않는모든 IRP 에대해서는반듯이밑으로전달 (PassDown) 해주어야한다. 3-2 DriverEntry routine 3-1 의주의점들을감안하면 ( 특별히주의 4) 항목 ) DriverEntry 루틴은 표 3-1 과같 은모습을가지게된다. ULONG i; UNICODE_STRING unintnamestring, uniwin32namestring; NTSTATUS status; PDEVICE_OBJECT filterdevobj = NULL; PAGED_CODE(); UNREFERENCED_PARAMETER(RegistryPath); DBGOUT(("DriverEntry")); /* * Route all IRPs on device objects created by this driver * to our IRP dispatch routine. */ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++){ DriverObject->MajorFunction[i] = VA_Dispatch; } DriverObject->DriverExtension->AddDevice = VA_AddDevice; DriverObject->DriverUnload = VA_DriverUnload; return STATUS_SUCCESS; [ 표 3-1] DriverEntry 3-3 AddDevice Routine AddDevice 루틴은흔히 TopOfStackObject로불리는 DeviceObject를얻어와서보관해야한다. 종종드라이버소스코드들중에하위드라이버 IoCallDriver함수를호출할때처음인자로사용하는 DeviceObject로 BUS Driver가제공하는 PDO(Physical Device http://www.devguru.co.kr - 7 -
Object) 를사용하는코드들이있다. 물론이코드들은로직상특별한일이없으면동작에무리가없는경우가대부분이지만특별히필터드라이버에서는 PDO로직접 IoCallDriver() 함수를호출해서는안된다. 그리고 AddDevice 루틴에서는하위드라이버의 Device object flag들을그대로사용해야하므로 flag들 (DO_POWER_PAGABLE,DO_BUFFERED_IO,DO_DIRECT_IO 등등 ) 과관련된코드들이일반적인 WDM 드라이버와달라진다. 코드를살펴보면다음표3-2와같다. 중요한부분은코드상에주석으로설명을대신하도록한다. filterdevobj->flags =(devext->topdevobj->flags & (DO_BUFFERED_IO DO_DIRECT_IO)); filterdevobj->flags =(devext->topdevobj->flags&(do_power_inrush DO_POWER_PAGABLE)); [ 표 3-4] IRP 처리모든 IRP들은 IoAttachDevieToDeviceStack() 함수가리턴해준 DeviceObject쪽으로 IoCallDriver() 함수를사용해서전달되어야하며우리는우리가관심을가지는 IRP에대해서만변경하거나처리방법을바꾸어야한다. 다음표 3- 에서플로피로 Read/Write되는값들에대해서몇 byte만큼 Read/Write했는지디버깅메시지를출력하는코드를소개한다. 전체코드는 www.devguru.co.kr에서자료실에있는플로피필터드라이버소스를참고해서확인해보기바란다. 4. 설치및실행방법우선제공되는예제는편의를위해 windows 2000 DDK의 src wdm general filter에있는예제를기본골격으로사용하였고대부분의주석이나코드에수정을가하지않았음을밝힌다. 이예제를참고하면서전체코드를살펴보기바란다. 또한이코드는 windows2000 advenced server 에서작성되었고다른 OS와의호환성은검토되지않았다. 4-1 설치및실행방법필터드라이버도 WDM으로작성되었으므로 WDM드라이버를설치하듯이확장자가 inf인설치파일을사용해서드라이버를설치할수있다. 물론 SetupDiGetClassDevs() 함수나 SetupDiEnumDeviceInfo(), SeupDiGetDeviceRegistryProperty(), SetupDiSetDeviceRegistryProperty() 함수등을사용해서프로그램적으로설치할수도있다. 이방법은독자들에게과제로남겨두고이번컬럼에서는수동으로드라이버를설치하는방법에관해서만다루도록하겠다. 관심이있는독자는 DDK의 src general toaster filter나 src wdm general filter 에있는소스를참조하기바란다. 또한 filter driver와어플리케이션과의통신에관한 MS의권고사항은 KB Article에있는 Article ID 262305 인문서 ( 이문서의현재링크는 http://support.microsoft.com/default.aspx?scid=kb;en-us;q262305 로되어있다.) http://www.devguru.co.kr - 8 -
를참조해서 DevGuru 에서제공되는샘플과비교해보기바란다. 테스트방법은첨부되는 Testapp.exe를실행한후 Install 버튼을누른다. 이때필터드라이버에관한서비스키와 f_filter.sys 라는파일을복사하는작업이이루어진다. 또한 f_filter.sys파일은 Testapp.exe와같은곳에있어야한다. 설치가잘되었다면레지스트를확인해보자. regedit.exe를실행해서레지스트리를살펴보면다름 [ 그림 4-1] 과 [ 그림 4-2] 와같은내용을확인할수있다. [ 그림 4-1] Service Key [ 그림 4-2] Class Key Install 후메시지에서나오는것과같이재부팅후다시 testapp.exe를실행하고 Do Not Access 버튼을클릭한후플로피에접근해보면정상적으로사용할수없음을확인할수있다. 다시 Access OK버튼을클릭하고플로피디스크에접근해보면정상적으로플로피디스크를사용할수있다. 그림 4-2를보면우리의 f_filter.sys 드라이버는 FloppyDisk드라이버의상위에설치되는 UpperFilter드라이버로동작한다는것을알수있다. Do Not Access 버튼과 Access OK 버튼을클릭할때에는어플리케이션에서는 DeviceIoControl() 함수를사용해서 f_filter.sys 드라이버쪽으로단순한컨트롤코드만을 http://www.devguru.co.kr - 9 -
넘겨주고이를받은드라이버에서는다음표 4-1과같이플래그를설정해서다음번 Read 요청에관해서아랫단드라이버로전달할지 UNSUCCESS로완료할지를결정한다. 플로피드라이버의경우많은부분을 IRP_MJ_DEVICE_CONTROL을통해서처리한다. 제공되는샘플은 IRP_MJ_DEVICE_CONTROL에관해서처리하지않기때문에 Do Not Access 버튼을클릭한후에도폴더목록등은여전히보일것이다. 하지만파일들을실행한다거나 editor등에서파일을열어볼때는파일을읽을수없다는메세지를보게될것이다. 주요처리코드는표 4-1과같다. switch (majorfunc){ case IRP_MJ_PNP: status = VA_PnP(devExt, Irp); passirpdown = FALSE; case IRP_MJ_POWER: status = VA_Power(devExt, Irp); passirpdown = FALSE; case IRP_MJ_READ: if(devext->baccess == FALSE){ status = Irp->IoStatus.Status = STATUS_UNSUCCESSFUL ; IoCompleteRequest(Irp, IO_NO_INCREMENT); passirpdown = FALSE; } case IRP_MJ_DEVICE_CONTROL: { iocontrolcode = irpsp->parameters.deviceiocontrol.iocontrolcode; if(iocontrolcode == IOCTL_ACCESS_OK){ devext->baccess = TRUE; status = Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); passirpdown = FALSE; http://www.devguru.co.kr - 10 -
} } else if(iocontrolcode == IOCTL_DO_NOT_ACCESS){ devext->baccess = FALSE; status = Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); passirpdown = FALSE; } case IRP_MJ_CREATE: case IRP_MJ_CLOSE: case IRP_MJ_SYSTEM_CONTROL: case IRP_MJ_INTERNAL_DEVICE_CONTROL: - 생략 - [ 표 4-1] 한번씩실행해보고필요한부분을수정하거나디버깅해보기바란다. 이를조금더 잘다듬고어플리케이션을확장한다면간단한플로피입출력통제시스템이될것이다. 5. 결론위에서설명한방법을통해 WDM 필터드라이버를작성할수있다. 물론여기에소개된내용들보다는수정해야할부분들이더많이있겠지만기본골격과개념에는크게변화가없으리라생각한다. 이번컬럼에서제시한방법외에도조금고전적인방법으로함수포인터를직접수정해서필터링을하는방법도있다. 필자개인적인생각으로는굳이그러한작업이필요한때가아니라면 MS에서제시하는표준방법 ( 이번컬럼에서소개한방법 ) 으로필터드라이버를작성하는것이바람직할것이다. 부디이번컬럼이필터드라이버의개념을설정하는데도움이되기를바라며또한여러분들 의드라이버를디자인할때한번쯤필터드라이버로작성이가능한지고민해볼수있는계 기가되기를희망한다. http://www.devguru.co.kr - 11 -