2008-09-28

마우스 우클릭 제한해제

javascript:function r(d)ll;d.ondragstart=null;d.onkeydown=null;d.onmousedown=null; d.body.oncontextmenu=null;d.body.onselectstart=null;d.body.ondragstart=null;d.body.onkeydown=null; d.body.onmousedown=null;};function unify(w){r(w.document);if(w.frames.length>0){for(var i=0;i< w.frames.length;i++){try{unify(w.frames[i].window);}catch(e){}};};};unify(self);alert("우클릭금지해제완료");

윈도우즈 디바이스 드라이버 개발 방법

driver online 에서 퍼왔어용~
윈도우즈 디바이스 드라이버 개발 방법

디바이스 드라이버 개발을 처음 시작하시는 분들이 가장 많이 하시는 질문은 “ 디바이스 드라이버를 개발하려면 무엇을 어떻게 공부해야 하나요 ? 라는 것이다 .

일반 애플리케이션 프로그램 개발을 시작하는 경우에는 자료도 많고 , 주변에 개발자들도 많아서 공부 방법이나 자료들을 쉽게 접할 수 있는데 , 디바이스 드라이버 분야는 개발자들이 많은 분야도 아니고 , 자료도 쉽게 찾을 수도 없다 보니 입문자들에게는 어디서부터 어떻게 시작해야 할지 막막해 한다 . 간혹, 디바이스 드라이버에 열정이 있으신 분들중에는 홀로 무수한 나날을 디버깅과 테스트를 통해 개발의 고수가 되는 경우도 있다.

하지만 , 일반 개발자들은 아직도 디바이스 드라이버 개발을 위해 어떻게 준비를 해야 할지 어려워하는게 현실이다. 그래서 이런 컬럼 에서는 필자가 그 동안 경험하고 느낀 것을 토대로 초보자들도 쉽게 접근할 수 있는 개발 방법들을 소개하려고 한다 .

우선 , 디바이스 드라이버 개발 방법의 내용을 언급하기 전에 여러분이 한 가지 알아두어야 할 사항이 있다 . 이전 1 부 컬럼 에서도 언급했듯이 디바이스 드라이버와 운영체제는 서로 밀접한 관계를 맺고 있다 . 그래서 이번 컬럼에서 다루는 윈도우 디바이스 드라이버 개발 방법이 다른 운영체제들에도 동일하게 적용되지 않을 수도 있다는 것을 참고해서 글의 내용을 이해했으면 한다 .

1. 무엇을 공부해야 하나 ?
응용프로그램 , 웹 프로그래밍 , 게임 등의 프로그램들처럼 디바이스 드라이버도 소프트웨어의 한 종류로 볼 수 있다 . 그래서 일반적인 대학교의 컴퓨터 학과들에서 배우는 알고리즘 , 운영체제 , 프로그래밍 언어 , 자료구조 , 컴파일러 등등의 다양한 지식들을 기본적으로 알고 있는 것은 디바이스 드라이버를 공부하는데 하는데 많은 도움이 된다 .

하지만 , 이런 기본적인 내용들 이외에 디바이스 드라이버를 개발하기 위해서 좀 더 알아야 할 지식들이 있다 . 그 내용들에 대해서 간략히 살펴보도록 하자 .

운영체제 아키텍처 : 다른 프로그램들도 마찬가지겠지만 , 프로그램이 동작하는 기반이 되는 운영체제를 이해하지 않고서는 제대로 된 프로그램을 개발 할 수가 없다 . 그 중에서도 디바이스 드라이버는 운영체제의 커널에서 동작 하므로, 운영체제 구조 및 개념들 ( 메모리 관리 , 스케줄링 , I/O 요청의 흐름 , 동기화 등등 ) 을 제대로 이해해야 개발하는데 문제가 없게 있게 된다 . 하지만 , 윈도우는 리눅스와 같은 Open Source 운영체제가 아니고, 내부 구조가 블랙박스처럼 베일에 싸여 있다보니, O/S 내부 내용을 공부 하려해도 항상 정확한 자료들을 가지고 아니어서 이해하는데 많은 어려움이 있다. 그래서, 이런 경우엔 직접 디버깅을 통해 알아내야 하는데, 이런 부분은 윈도우 운영체제를 이해하는데 어렵게 하는 부분이 되고 있다.

Windows Shared Source programs

( http://www.microsoft.com/resources/sharedsource/Licensing/default.mspx )

Microsoft 에서는 윈도우 소스코드를 공유하는 “ Windows Shared Source programs 제도를 운영하고 있다 . 이 프로그램에 참여방법은 여러 가지 방법이 있는데, 그 중에 Microsoft MVP 자격으로 참여해 볼 수 있는 형태가 있다. 관심 있는 분들은 MVP 에 도전해 보길 바란다.

컴퓨터 구조 및 CPU 아키텍처 : 운영체제 아키텍처를 이해하기 위해서는 먼저 컴퓨터 구조나 CPU 아키텍처의 이해가 필요하다 . 즉 , 넓은 의미로 운영체제도 CPU 및 컴퓨터 구조 기반 위에서 작동하는 프로그램이기 때문에 CPU 및 컴퓨터의 구조를 이해하는 것은 기본 중에 기본이다 . 그래서 기본적인 CPU 동작원리라던지 컴퓨터의 내부 구조에 대한 지식은 운영체제 및 드라이버를 이해하는데 필요하다.

C/C++ 언어 : 많이 질문하시는 내용 중에 “ 디바이스 드라이버는 어떤 언어로 개발하나요 ? ” 가 있다 . 윈도우 디바이스 드라이버 개발 시에는 C/C++ 언어 정도를 이해한다면 개발하는데 무리는 없다 . 그리고 , 가끔 디버깅 (Debugging) 이나 리버스 엔지니어링 (Reverse Engineering) 이 필요한 경우에 어셈블리 언어 (Assembly) 의 지식이 필요하다. 그렇다고 어셈블리 언어를 완벽한 이해해야 하는것은 아니다. 대신 남의 코드를 디버깅하는 경우 소스 코드가 어셈블리 코드로 보여 내용을 보고 분석할 줄 알아야 하는데 이때 간단히 코드를 보고 이해할 수 있을 정도의 지식이면 된다.

API 프로그래밍 : 디바이스 드라이버는 누군가의 요청에 의해 기능을 하게 된다 . 사용자가 GUI 를 가진 애플리케이션을 통해 I/O 요청을 하면 디바이스 드라이버가 해당 작업을 하게 되고 , 결과는 다시 애플리케이션에게 전달되는 구조를 가진다. 이처럼 디바이스 드라이버는 애플리케이션과 항상 상호작용을 한다.
그래서, API 프로그래밍을 공부할때는 단순 API 사용법의 내용이 아닌 디바이스 드라이버와 애플리케이션 사이의 통신 및 전체 I/O 구조에 대한 내용을 중심으로 공부하길 바라며 이 부분은 추후에 드라이버를 공부하는데도 많은 도움이 된다.

H/W 지식 : 디바이스 드라이버는 소프트웨어와 하드웨어 사이에 중간의 다리역할을 하는 프로그램이라 볼 수 있다 . 이러다 보니 디바이스 드라이버를 작성하기 위해서는 소프트웨어 지식 뿐만 아니라 , 하드웨어적인 지식도 필요로 하게 된다. 그렇다고 H/W 스펙의 전기적인 내용이나 물리적인 회로등의 이해를 요구하는 것은 아니다. 대신. 기본적인 H/W 스펙 문서에 나와있는 용어라던지 통신 프로토콜등에 대해 먼저 이해하기 바라며, 드라이버에서 사용되는 H/W 관련 개념들도 같이 공부하길 바란다.

디바이스 드라이버 모델 : 윈도우에서는 디바이스 드라이버를 어떤 방식으로 개발하라는 드라이버 모델들을 제시하고 있으며, 이 모델들을 이용해 드라이버를 좀 더 쉽게 개발할 수 있게 해준다. 현재 윈도우에서 제공하는 드라이버 모델은 10 가지 이상의 방법들을 제시하고 있고 , 개발하려는 장치 및 드라이버 종류에 따라 추천하는 드라이버 모델들이 존재하고 있다 . 하지만 , 이런 다양한 드라이버 모델은 개발자들이 드라이버 종류에 따라 각각 새로운 모델들을 익히기 위해 시간과 노력을 배로 들게 하는 단점이 있다 . 그래서 Microsoft 에서는 이런 어려움을 해결하기 위해 새로운 드라이버 모델을 계속 발전시키고 , 통합하는 과정을 진행하고 있다 .

아래 표는 현재까지의 윈도우 운영체제의 종류에 따른 지원하는 드라이버 모델이다 .

Windows 종류

Driver Model

Windows 95/98/ME

VxD, WDM ( Windows 98/ME 에 해당 )

Windows NT

NT Kernel Mode Driver

Windows 2000/XP/2003/VISTA

NT Kernel Mode Driver, WDM, WDF


아래 표는 Microsoft 에서 디바이스 및 드라이버 종류에 따라 권장하는 드라이버 모델에 대한 설명이다 . ( http://www.microsoft.com/whdc/driver/foundation/DrvRoadmap.mspx# )

Device/Driver Class

Recommended Driver Model

1394 device

Depends on device class : KMDF or WDM

Auxiliary display (SideShow)

Windows Portable Devices (WPD),
which is UMDF-based

Bluetooth L2CAP

Depends on device class : KMDF or device-class-specific model such as AVStream

Bluetooth Radio Frequency Communication (RFCOMM)

UMDF

Cell phone, PDA, portable media player

WPD, which is UMDF-baased

Digital camera

Depends on device characterisitics :
Media Transfer Protocol (MTP)/UMDF or WIA

Display adapter

Windows Display Driver Model

File system filter

FS mini-filter

Generic filter driver

KMDF

Human input device (HID)

UMDF (except for mouse and keyboard) or KMDF

Keyboard/Mouse filter

KMDF

Modem, cable modem

KMDF, WDM, or NDIS-WDM

Network Transport Driver Interface (TDI) client

KMDF

Network-connected device

UMDF

Other

Depends on device class and characteristics : UMSF, KMDF, or WDM

Printer

UniDrv, PScript, XPS

Scanner

WIA

Secure digital (SD)

Depends on device class : KMDF or WDM

Serial and parallel devices (legacy)

UMDF or KMDF

Smart card device

WDM

USB device

Depends on device class : UMDF, KMDF, or WDM

Video capture

AVStream



Port/Adapter Class

Recommended Driver Model

Audio adapter

AVStream, PortCls

HID miniport

Microsoft-supplied or KMDF

Network adapter

NDIS-WDM

Network adapter (USB)

NDIS-KMDF

PC card

Microsoft-supplied or KMDF

PCI

Microsoft-supplied or KMDF

Serial, parallel port

Microsoft-supplied or KMDF

Storage adapter (SCSI and ATA)

Scsiport, Storport, ATA port

USB adapter

Microsoft-supplied or KMDF



VxD ( Virtual Device Driver ) : Windows 95/88/ME 에서 사용되는 드라이버 모델로 디바이스 드라이버를 가상화시킨다는 개념을 적용해 드라이버를 만든다 . 확장자는 vxd 로 만들어진다 .

NT Kernel Mode Driver : Windows NT 용 드라이버를 만들기 위한 드라이버 모델로 드라이버 개발을

WDM ( Windows Driver Model ) : 윈도우 디바이스 드라이버를 어떻게 만들어야 한다는 하나의 스펙이라고 볼 수 있다 . 하나의 드라이버 바이너리 파일을 가지고 다양한 윈도우 에서 사용 할 수 있는 드라이버를 만들기 위한 목적으로 만들어졌으며 , 현재 Windows 98/ME/2000/XP/2003/Vista 에서 사용할 수 있다 . 기본적인 개념은 NT Kernel Mode Driver 구조를 바탕으로 만들어 졌으며 , PnP, Power 관리 , WMI 등을 지원한다 .

WDF ( Windows Driver Foundation ) : Windows Vista 가 출시되면서 만들어진 드라이버모델로 WDM 모델에서 발전된 형태이다 . 윈도우 API 프로그래밍을 WDM 에 비유하면 , MFC 는 WDF 해당한다고 볼 수 있다 . WDF 는 크게 두 가지 종류로 나뉘는데 , KMDF ( Kernel-Mode Driver Framework ) 와 UMDF ( User-Mode Driver Framework ) 가 그에 해당된다 .

NDIS ( Network Driver Interface Specification ) : 윈도우에서 네트워크 관련 드라이버를 개발할 때 사용되는 드라이버 모델로 네트워크 드라이버를 좀 더 모듈화 시켜서 쉽게 만들 수 있는 방법을 제공해준다 .

그럼, 현 시점에서는 이렇게 "다양한 드라이버 모델중에 어떤 모델을 공부해야 하나?" 생각이 들것이다.
필자 생각에는 먼저 WDM 드라이버 모델을 공부하라고 말하고 싶다. 이유는 여러분들이 처음 애플리케이션 만들때를 생각해 보면, 처음엔 쉽게 개발을 하기 위해 라이브러리들이 많이 지원되는 MFC 나 비주얼 베이직, 델파이 등을 이용해 프로그램들을 만들었을 것이다. 하지만 이것의 내부 구조 및 원리들을 이해하기 위해서는 API 를 다시 공부 했어야 했다. 이것은 기본적인 원리를 이해하지 못하고는 발전된 개념들을 이해하기 어렵기 때문이다. 그래서 드라이버 모델에서도 API 와 같은 WDM 를 우선적으로 공부하면 드라이버의 기본적인 개념이나 구조를 이해하는데 많은 도움이 될 것이기 때문이다. 그리고나서, 필요에 따라 WDF 를 공부한다던지, 해당 Device Class에 따른 드라이버 모델들을 공부하는 방법을 권한다.

2. 어떻게 공부해야 하나 ?

프로그래밍을 배울 때 듣는 속담 중 하나가 “ 백문이 불여일견 , 백견이 불여일타 “ 라고 했다 . 그 만큼 실제 책으로 공부하고 눈으로 보는 것 보다는 직접 코딩을 하면서 프로그램을 작성하는 것이 백배 더 효과적이라고 한다 .

디바이스 드라이버도 이런 공부 방법대로 많이 만들어보는 것이 제일 중요하다고 생각한다 . 필자도 처음에는 디바이스 드라이버를 책으로만 볼 때는 무슨 내용들을 말고 있는지 , 어떻게 드라이버가 작동 되는지 이해가 잘 되지 않았지만 , 이것저것 개발을 하면서 조금씩 이해를 한 경험이 있다 .

그러나 , 처음 드라이버를 만들려고 해도 뭔가 이론적인 바탕이 있어야 하는데 이런 부분은 혼자 공부하기에는 어려운 부분이 많다 . 그래서 여러 명이서 스터디 그룹을 만들어 같이 공부하면서 서로 공부한 것들을 공유하는 방법을 생각해 볼 수 있을 것이다 . 그리고 , 개발자 저변은 넓지 않은 분야이다 보니 자료들을 찾아보는데도 한계가 있다 . 그렇기 때문에 다양한 세미나 및 개발자 모임 등에는 적극적으로 참여해서 정보를 얻어야 한다 . 그 다음에는 관심 있는 프로그램이나 분야 중에 디바이스 드라이버가 사용되는 것을 선정해 직접 만들어보면서 실제 이론 내용을 적용해 보는 형태로 공부를 하면 많은 도움이 될 것이다 .

그럼 , 여러분들이 개발하기 전에 몇 가지 고려해야 할 사항들을 소개하겠다 .

• 지원할 운영체제 : 제일 먼저 어떤 운영체제를 지원 할지를 결정해야 한다 . 그래야 지원하는 운영체제에 따른 H/W 지원 유무및 드라이버 모델이 정해지고 , 경우에 따라서는 디바이스 드라이버를 운영체제에서 기본적으로 지원하고 있어서 디바이스 드라이버 개발을 별도로 하지 않아도 되는 경우들이 있다 . 그렇기 때문에 우선 지원할 운영체제를 무엇으로 할지 선택해야 한다 .

• Device 및 Driver Class : 개발하려는 디바이스 드라이버가 지원하는 장치 종류 및 드라이버가 어떤 종류인지 선택 해야 한다 . 다시 설명하면 , 장치관리자에 올라가는 장치 목록에 어떤 장치로 보이게 할 것인지를 선택해야 한다는 말이다 . 어떤 장치 종류이냐에 따라 앞에서도 언급한 드라이버 모델이 결정되어서 개발 방향이 결정이 되기 때문에 이 부분도 중요하게 결정되어야 한다 .

• Windows Logo 인증 : 여러분들은 장치를 구매했을 때 박스나 PC 에 Windows Logo 스티커가 있는 걸 보거나 , 드라이버 설치시에 경고창이 나타나는 것을 본 경험이 있을 것이다 . 이 Logo 의 의미는 Microsoft 는 Windows 운영체제에서 하드웨어와 소프트웨어가 안정적으로 동작할 수 있도록 하드웨어와 소프트웨어의 완벽한 호환성에 관한 명확한 기준을 제공하고 있으며 , Microsoft 의 WHQL 에서는 제시한 기준에 적합한지를 시험해서 기준에 적합하면 Windows Logo 인증 마크를 사용할 수 있는 권한을 부여하는 제도 이다 . 이런 인증 제도는 비즈니스적인 측면과 관련된 부분이긴 하지만 , 여러분의 H/W 및 디바이스 드라이버 품질을 검증해 보길 원한다면 한번 인증을 진행해 보는 것도 좋은 방법이 될 거라 본다 . 대신 별도의 인증 비용이 들어가니 이점은 참고하기 바란다 .
( http://www.microsoft.com/whdc/winlogo/default.mspx )

디바이스 드라이버를 개발하기 위해 필요한 지식 및 방법에 대한 내용을 필자의 경험을 토대로 간략히 살펴봤다 . 공부에는 왕도가 없다라는 말이 있다 . 디바이스 드라이버를 공부하는 것도 특별한 비법이 있거나 빨리 실력이 느는 방법이 따로 있는것은 아니다. 특히나 드라이버나 시스템 프로그래밍쪽은 다른 분야보다 공부한 만큼 바로 바로 결과가 나오지 않아 쉽게 포기를 하기도 하는 분야다. 이럴수록 여러분들은 차근차근 기본기부터 다진다는 생각으로 공부을 했으면 한다.
끝으로, 한 가지 더 부탁을 하자면, 인내와 끈기를 가지고 문제 해결를 끝까지 해결하려는 자세를 가졌으면 한다. 디바이스 드라이버를 개발하면서 느낀것은 쉽게 해결되는 문제가 없다는 것이다. 운영체제와 애플리케이션 , H/W 등의 다양한 구성 요소들 사이에서 동작을 하다 보니, 문제점을 파악하고 디버깅하고 테스트하는 과정은 정말 어려움 고난의 과정이다. 그래서 처음 생각과 달리 디버깅이나 테스트에서 많이들 힘들어하고 어려워한다. 하지만, 이런 과정은 여러분들이 고수로 가게 해주는 밑바탕이 될 것이며, 드라이버 개발을 재미를 느끼게 해주는 기폭제가 될것이라 본다.

그럼, 이제 디바이스 드라이버 개발을 어렵게 느끼지 말고 바로 지금 공부를 시작해보자.

출처: http://blog.naver.com/handssjh/140044732953

2008-09-01

민성기님의 후킹 강좌(Delphi)

안녕하세요… 민성기 입니다.
화면 키보드를 만들면서 몸에 익힌 훅킹기법~ 남용하면 독이 되지만 잘 만 쓰면 정말 좋은 영약이 되는 것은 세상 다른 이치와 마찬가지겠죠…?? 훅~ 훅훅훅훅~~ (웃음소리 입니다~) 저역시 배우는데 깝깝했던 만큼, 가능하면 쉽게 설명하도록 노력하겠습니다.편의상 존칭은 생략합니다.
이 강좌는 다음과 같은 순서로 진행할 것입니다.
- 훅킹이란 무엇인가- 훅킹의 종류- 훅킹에 사용되는 함수 설명- 훅 프로시저- 훅 프로시저의 위치. 왜 시스템 훅킹은 DLL이어야 하는가.- 실전
{이 글은 Kent Reisdorph가 Delphi Developer's Journal에 기고한 글을 아주 많이 참조하여 작성한 것입니다.}
*** 훅킹이란 무엇인가~누구나 한번쯤, 델파이에 포함되어 있는 스파이 프로그램인 ‘윈 사이트’를 사용해 본 적이 있을 것이다. 이 스파이 프로그램들 처럼, 때때로 윈도우 시스템에서 어떤 일이 일어나고 있는지 알고 싶을 때가 있다. 어떤 어플리케이션이 시작될 때나 끝날 때, 또는 사용자가 쳐대는 마우스의 움직임이나 키보드의 내용 등등… 훅킹이란 윈도우를 괴롭히거나 다른 어플리케이션의 동작을 훔쳐보기 좋아하는 변태적인 프로그래머들을 위해서 윈도우가 마련해 놓은 꽤나 합법적인 통로이다.
이름에서 일 수 있듯이 ‘훅’은 피터팬에 나오는 ‘후크선장’이 오른손에 달고 다니던 엽기적인 갈구리~ 바로 그것이다. 따라서 훅킹은 순 우리말로 하면 ‘갈구리질’ 쯤이 된다. 이 갈구리를 터억~ 하니 메시지가 날아다니는 통로에 찍어놓고 지나가는 메시지를 협박하고 갈취해서 원하는 목적을 이루는 것~ 이것이 훅킹의 모든 것이다. 어떤가~ 듣는 순간, 찌리리~ ‘필’이 오지 않는가~??? ㈜ 물론 표준말은 ‘갈고리’ 입니다만… 왠지 어감이 약해서~ 이 강좌에서는 ‘갈구리’를 쓰겠습니다. 쿄호홋~

*** 훅킹의 종류~갈구리를 찍어두는 위치에 따라 훅은 크게 두가지로 나뉜다. 한 쓰레드만을 집중적으로 괴롭히는 훅킹을 ‘쓰레드 훅킹’, 통 크게 시스템 전체를 상대로 맞짱을 뜨는 훅킹을 ‘시스템 훅킹’이라고 한다. 괴롭히고 싶은 메시지에 따라 갈구리 또한 취사선택 해야 하는데… 이는 머리엔 십자, 배엔 일자 드라이버를 사용해야 하는 일반적인 게임의 법칙과 같다. 즉 윈도우에 관련된 메시지를 상대하기 위해서는 WH_CALLWNDPROC를, 키보드 메시지와 대적하기 위해서는 WH_KEYBOARD라는 갈구리를 사용해야 한다는 말이다. 또한 때와 장소를 잘 가려서 적절한 갈구리를 사용해야 하는데… WH_SYSMSGFILTER같은 무식한 갈구리를 보잘것없는 쓰레드를 상대로 휘두르려 한다면… 큰 형님인 윈도우가 공포의 퍼런화면을 보여주며 ‘고만 밥숟갈 놓지~’ 라며 협박을 하기 때문이다. 자, 이제 우리가 고를 수 있는 갈구리와 타격대상등을 적어둔 취급 설명서를 살펴보자.
**갈구리 취급 설명서* WH_CALLWNDPROC (대상 : 쓰레드 또는 시스템.)윈도우 관련 메시지들이 처리되기 전에 실컷 괴롭힐 수 있는 있는 갈구리.
* WH_CALLWNDPROCRET (대상 : 쓰레드 또는 시스템.)윈도우 관련 메시지들을 처리된 후 실컷 괴롭힐 수 있는 있는 갈구리.
* WH_CBT (대상 : 쓰레드 또는 시스템.)CBT어플리케이션에 대해 사용할 수 있는 놈이라고 하는데…쓰는놈도 잘 모름.
* WH_DEBUG (대상 : 쓰레드 또는 시스템.)다른 갈구리 사용을 디버그할 수 있는 갈구리
* WH_FOREGROUNDIDLE (대상 : 쓰레드 또는 시스템.)어플리케이션의 맨 앞의 윈도우가 아이들 상태일 때 맘껏 때릴 수 있는 갈구리.
* WH_GETMESSAGE (대상 : 쓰레드 또는 시스템.)메시지 큐로 들어오는 메시지들을 괴롭히는 갈구리.
* WH_JOURNALPLAYBACK (대상 : 시스템 만.)저널 레코드 훅에 의해 저장된 키보드나 마우스 이벤트를 재생시킬 수 있는 갈구리. 일반적으로 이 갈구리를 휘두르는 동안은 키보드나 마우스 사용이 정지된다.
* WH_JOURNALRECORD (대상 : 시스템 만.)모든 키보드와 마우스 동작을 괴롭히는 갈구리. 매크로 같은 녀석을 만들 때 아주 유용하다.
* WH_KEYBOARD (대상 : 쓰레드 또는 시스템.)WM_KEYDOWN, WM_KEYUP 메시지 전문 사냥꾼.
* WH_MOUSE (대상 : 쓰레드 또는 시스템.)마우스 메시지 전문 사냥꾼.
* WH_MOUSE_LL (대상 : 쓰레드 또는 시스템.)NT에서만 사용되는 저수준 마우스 갈구리.
* WH_MSGFILTER (대상 : 쓰레드 또는 시스템.)특정 어플리케이션에서 만들어낸 메뉴, 다이얼로그 박스, 스크롤 박스 같은 놈에서 발생하는 메시지를 전문적으로 괴롭힐 수 있는 갈구리.
* WH_SHELL (대상 : 쓰레드 또는 시스템.)윈도우 셀에 관계된 메시지를 전문으로 하는 갈구리.
* WH_SYSMSGFILTER (대상 : 시스템 만.)모든 어플리케이션이 만들어낸 메뉴, 다이얼로그 박스, 스크롤 박스 같은 놈에서 발생하는 메시지를 전문적으로 괴롭힐 수 있는 갈구리.
갈구리질을 잘 하기 위해서는 손에 딱 맞는 갈구리가 필요하다. 위의 취급 설명서가 때와 장소에 따라 적절히~ 갈구리를 선택할 수 있는 지혜에 도움이 되었으면 한다.
*** 윈도우의 훅 함수들~갈구리질을 위해 준비된 윈도우의 API는 세가지 이다. 갈구리를 찍는 녀석인 SetWindowsHookEx, 다 쓴 갈구리를 정리하는 UnHookWindowsHookEx, 마지막으로 단물 다 뽑아먹은 메시지를 기다리고 있는 다음 갈구리에게 넘겨주는 CallNextHookEx가 그것이다. 이 CallNextHookEx를 호출해야 하는 이유는 간단하다. 이미 알고 있겠지만, 윈도우는 나 혼자만 쓰는 것이 아니기 때문이다. 충분히 메시지를 괴롭혔다고 해도, 아직 뒤에는 이 메시지를 노리는 수많은 갈구리들이 있다는 것을 잊지 말자.
** SetWindowsHookEx~위에서도 설명 했지만, 이 함수는 메시지 통로에 갈구리를 찍기 위해 사용되는 녀석이다. 생긴 모양을 보자.
function SetWindowsHookEx( idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD): HHOOK; stdcall;
아~ 정말 흉악하게 생겼다~.
첫번째 인자는 사용할 갈구리의 종류를 의미한다. (취급 설명서를 보자.)두번째 인자는 원하는 메시지가 왔을 때 호출될 ‘훅 프로시저’이다. 훅 프로시저에 대해서는 잠시 후에 살펴보자.세번째 인자는 훅 프로시저가 정의된 DLL이나 EXE의 인스탄스이고 마지막 인자는 괴롭힐 쓰레드의 아이디이다. 시스템 전체를 상대로 갈구리질을 하기 위해서는 이 마지막 인자에 0을, 특정 쓰레드를 괴롭히고 싶으면 원하는 쓰레드의 아이디를 넣어주면 된다. 갈구리가 정확히 찍히면, 이 함수는 훅의 핸들을 넘겨주게 된다. 실패하면 리턴값은 0이다. 이 훅의 핸들은 뒤에 갈구리를 해체할 때나 다음 갈구리를 호출할 때 사용되니 잘 보관해야 한다. 다음 예제는 현재 프로세스에 키보드 훅을 걸어주는 예제이다.
varHKbHook : HHOOK;
...
HKbHook := SetWindowsHookEx(WH_KEYBOARD, MyKBHook, HInstance, GetCurrentThreadId);
갈구리가 괴롭힐 쓰레드의 ID를 얻기 위해 GetCurrentThreadid를 사용했으며 결과값을 HKbHook에 저장해 둔 것에 유의하자.
** UnhookWindowsHookEx~갈구리를 제거하기 위해 사용하는 함수이다. 무사히 뽑히면 True값을, 그렇지 않으면 flase를 리턴한다. 대부분의 경우 갈구리를 뽑을 때 발생하는 에러는, 인자로 넘겨준 훅핸들이 이 함수의 맘에 들지 않을 때 발생한다.
Res := UnhookWindowsHookEx(HKbHook);
예제에서 보듯, 별다른 것이 없는 함수이다. 그저 정확한 훅 핸들을 넘겨주기 위해 훅 핸들 보관에 신경써야 한다는 것을 잊지 말자.
** CallNextHookEx~위에서도 잠깐 언급했지만, 우리가 괴롭히려는 메시지에 한이 맺힌 갈구리는 우리만 있는 것이 아니다. 따라서 적당히 손 본 메시지는 다음 갈구리들에게 넘겨주어야 한다. CallNextHookEx는 다음 갈구리에 메시지를 넘겨주기 위해 사용하는 함수이다. 여러 개의 훅이 ‘체인’으로 연결되어 있다고 이해하면 빠를 것이다.(갈구리에 체인까지~ 랄랄라~~) 실제로 우리가 설치한 훅은 윈도우가 다루는 훅 체인의 하나로서 동작하게 된다. 이 함수의 사용 예는 조금 뒤에 훅 프로시저에서 살펴보도록 하자.
*** 훅 프로시저~갈구리질의 가장 중요한 요소, 아니 갈구리질 그 자체를 뜻하는 녀석이다. (프로시저라고 불리지만, 이건 윈도우가 그렇게 부르기 때문이고~ 파스칼의 입장에서 볼 때는 함수 입니다.) 이 훅 프로시저는 우리가 설정한 훅이 발생할 때, 즉 괴롭히고자 하는 메시지가 발생할 때 호출된다. 키보드 훅을 예로 들면, 사용자가 키보드를 누르거나 뗄 때 실행된다. 윈도우는 갈구리의 형식에 따른 훅 프로시저를 정의해 놓았고, 위에서 언급한 키보드의 경우를 예로 들면 다음과 같다.
function MyKBHook(Code: Integer; wParam: WPARAM; lParam: LPARAM) : LongInt; stdcall;
실은, 나머지 갈구리질 함수 역시 모두 똑같이 생겼다. 다만 갈구리의 형식에 따라 넘어오는 wParam과 lParam이 달라질 뿐이다. 예를 들어, 현재 찍어놓은 갈구리가 WH_CALLWNDPROC 라면 wParam은 발생한 메시지를, lParam에는 메시지가 발생한 핸들 등 기타정보를 담은 구조체에 대한 포인터가 넘어온다. WH_KEYBOARD의 경우는 wParam에 가상 키값이, lParam에 키보드의 상태 등 기타 정보가 넘어오게 된다. 갈구리의 형식에 따른 훅 프로시저에 대해서는 SetWindowsHookEx()에 대한 Win32 API 도움말을 살펴보기 바란다. 이 훅프로시저를 작성할 때는 신경을 많이 써야 한다. 마우스 훅을 예로 들어보자. 설치해 놓은 마우스 훅 프로시저는 마우스 메시지가 발생할 때, 즉 마우스를 움직이기만 하면 호출된다. 만약 머리 터지도록 복잡한 계산을 훅 프로시저 내부에서 한다면… 또는 가뜩이나 느린 화면 그리기 같은 녀석을 여기서 처리 한다면… 뭐 윈도우가 괴롭다 괴롭다 못해 뻗어버릴 지도 모른다. 따라서 적당히~ 괴롭혀야 한다는 말씀~~ ^^; 훅 프로시저에서 메시지를 적당히 타작 했으면, CallNextHookEx()를 통해 다음 갈구리를 불러줘야 한다. 그렇게 하지 않으면 위에서 언급했던 훅체인은 깨져버리고, 메시지는 도망가 버리고 만다. 다음은 아무일도 하지 않는 훅 프로시저의 예이다.
function MyKBHook(Code: Integer; wParam: WPARAM; lParam: LPARAM) : LongInt; stdcall;beginResult := CallNextHookEx( HKbHook, Code, wParam, lParam);end;
CallNextHookEx의 첫번째 인자는 훅의 핸들이다. 나머지 인자들은 훅 프로시저로 넘어온 Code와 wParam, lParam을 채워준다. 또한 이 함수의 결과값을 훅 프로시저의 결과값으로 사용한 것에 주의하자.필자처럼 책상이 좁은 사람들은, 맘 먹고 책 한번 읽으려 해도 키보드가 걸리적 거려 힘이 든다. 이 경우, 시스템 전체에 키보드 훅을 걸어놓고 훅 프로시저에서 CallNextHookEx를 호출하지 않으면 키보드가 동작하지 않게 된다. 키보드에 락을 걸어두는 간단한 유틸리티를 만드는 것도 가능할 것이다.
*** 훅 프로시저의 위치. 왜 시스템 훅킹은 DLL이어야 하는가.~위에서 잠깐 언급 했지만, 훅을 설치할 때, 시스템 전체의 메시지를 괴롭히려면 SetWindowsHookEx의 마지막 인자에 0을, 특정 쓰레드만을 괴롭히려면 괴롭히고자 하는 쓰레드의 ID를 넣어준다.
<쓰레드 훅을 설치하는 예>HKbHook := SetWindowsHookEx( WH_KEYBOARD, MyKBHook, HInstance, GetCurrentThreadId);
<시스템 훅을 설치하는 예>HKbHook := SetWindowsHookEx( WH_KEYBOARD, MyKBHook, HInstance, 0);
쓰레드 훅에서의 훅 프로시저 위치는 별 문제가 되지 않는다. 훅의 핸들 등의 변수가 같은 어플리케이션 영역에 존재하기 때문이다. 그러나 시스템 훅에서는 이것이 큰 문제가 된다. 최초에 훅을 설치할 때는 상관 없지만, (실제로 설치는 된다.) 설치한 훅이 동작하려 할 때 훅 프로시저가 특정 어플리케이션의 영역에 있다면, 메시지가 발생한 어플리케이션에서 이 프로시저에 접근할 방법이 없기 때문이다. 때문에 시스템 훅에서는 훅 프로시저를 DLL에 집어 넣어야 한다. 고민해야 할 문제가 한가지 더 있다. DLL내에 전역변수를 선언해 갈구리를 찍을 때 훅의 핸들을 저장해 두고 훅 프로시저의 CallNextHookEx에서 사용한다고 하자. 이 경우 전역변수에는 어떤 값이 들어가 있을까…?? 최초에 SetWindowsHookEx에서 제아무리 기가막히게 훅의 핸들을 얻어다 넣어주었다 하더라도 각 어플리케이션에서 훅 프로시저가 실행될 때 읽어오게 되는 전역변수의 값은 언제나 0이다. 32비트에서는 각 어플리케이션에서 DLL이 호출될 때, 코드만 공유할 뿐이고 데이터는 각각 다른 프로세스 안에서 ‘보호’되고 있기 때문이다. 따라서 어플리케이션마다 따로 호출될 훅 프로시저에서 정확한 훅의 핸들값을 참조할 수 있도록 데이터 교환 방법에 대해 고민해야 한다.
이경우에 가장 좋은 해결방법은 ‘메모리 맵드 파일 아이오’를 이용하는 것이다. 공유할 파일 맵을 설정해 놓고 훅의 핸들이나 기타 필요한 정보들을 보관하는 것이다. 그러나, 이 개념까지 여기서 설명하기에는 조금 벅찬 듯 싶다. 메모리 맵드 파일 아이오에 대해서는 이 갈구리질 강좌가 끝난 후에 다시한번 고민해 보는 기회를 갖도록 하고, 일단 여기서는 임시적으로 VCL의 파일 스트림을 이용해 하드 디스크에 훅의 핸들을 저장하는 방법을 사용하도록 하겠다.