From YYpBD's MediaWiki
민성기도 하는 훅킹 1.
이 글은 Kent Reisdorph가 Delphi Developer's Journal에 기고한 글을
아주 많이 참조하여 작성한 것입니다.
안녕하세요… 민성기 입니다. 이번에 화면 키보드를 만들면서 몸에
익히게 된 훅킹에 대한 정보를 함께 나누어 보죠~ 훅~ 훅훅훅훅~~
(웃음소리 입니다~) 저역시 배우는데 깝깝했던 만큼, 가능하면 쉽게
설명하도록 노력하겠습니다. 편의상 존칭은 생략합니다.
*** 훅킹이란 무엇인가~
누구나 한번쯤, 델파이에 포함되어 있는 스파이 프로그램인 '윈 사
이트'를 사용해 본 적이 있을 것이다. 이 스파이 프로그램들 처럼, 때
때로 윈도우 시스템에서 어떤 일이 일어나고 있는지 알고 싶을 때가
있다. 어떤 어플리케이션이 시작될 때나 끝날 때, 또는 사용자가 쳐대
는마우스의 움직임이나 키보드의 내용 등등… 훅킹이란 윈도우를 괴롭
히거나 다른 어플리케이션의 동작을 훔쳐보기 좋아하는 변태적인 프로
그래머들을 위해서 윈도우가 마련해 놓은 꽤나 합법적인 통로이다.
이름에서 일 수 있듯이 '훅'은 피터팬에 나오는 '후크선장'이 오른
손에 달고 다니던 엽기적인 갈구리~ 바로 그것이다. 따라서 훅킹은 순
우리말로 하면 '갈구리질' 쯤이 된다. 이 갈구리를 터억~ 하니 메시
지가 날아다니는 통로에 찍어놓고 지나가는 메시지를 협박하고 갈취해
서 원하는 목적을 이루는 것~ 이것이 훅킹의 모든 것이다. 어떤가~ 듣
는 순간, 찌리리~ '필'이 오지 않는가~???
㈜ 물론 표준말은 '갈고리' 입니다만… 왠지 어감이 약해서~ 이 강좌
에서는 '갈구리'를 쓰겠습니다. 쿄호홋~
*** 훅킹의 종류~
갈구리를 찍어두는 위치에 따라 훅은 크게 두가지로 나뉜다. 한 쓰
레드만을 집중적으로 괴롭히는 훅킹을 '쓰레드 훅킹', 통 크게 시스템
전체를 상대로 맞짱을 뜨는 훅킹을 '시스템 훅킹'이라고 한다. 괴롭히
고 싶은 메시지에 따라 갈구리 또한 취사선택 해야 하는데… 이는 머
리엔 십자, 배엔 일자 드라이버를 사용해야 하는 일반적인 게임의 법
칙과 같다. 즉 윈도우에 관련된 메시지를 상대하기 위해서는 WH_CALLW
NDPROC를, 키보드 메시지와 대적하기 위해서는 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 (대상 : 시스템 만.)
모든 어플리케이션이 만들어낸 메뉴, 다이얼로그 박스, 스크롤 박스
같은 놈에서 발생하는 메시지를 전문적으로 괴롭힐 수 있는 갈구리.
갈구리질을 잘 하기 위해서는 손에 딱 맞는 갈구리가 필요하다.
위의 취급 설명서가 때와 장소에 따라 적절히~ 갈구리를 선택할 수 있
는 지혜에 도움이 되었으면 한다.
********************
민성기도 하는 훅킹 2.
*** 윈도우의 훅 함수들~
갈구리질을 위해 준비된 윈도우의 API는 세가지 이다. 갈구리를 찍는
녀석인 SetWindowsHookEx, 다 쓴 갈구리를 정리하는
UnHookWindowsHookEx, 마지막으로 단물 다 뽑아먹은 메시지를 기다리
고 있는 다음 갈구리에게 넘겨주는 CallNextHookEx가 그것이다. 이
CallNextHookEx를 호출해야 하는 이유는 간단하다. 이미 알고 있겠지
만, 윈도우는 나 혼자만 쓰는 것이 아니기 때문이다. 충분히 메시지를
괴롭혔다고 해도, 아직 뒤에는 이 메시지를 노리는 수많은 갈구리들이
있다는 것을 잊지 말자.
** SetWindowsHookEx~
위에서도 설명 했지만, 이 함수는 메시지 통로에 갈구리를 찍기 위해
사용되는 녀석이다. 생긴 모양을 보자.
function SetWindowsHookEx(
idHook: Integer;
lpfn: TFNHookProc;
hmod: HINST;
dwThreadId: DWORD): HHOOK; stdcall;
아~ 정말 흉악하게 생겼다~. 첫번째 인자는 사용할 갈구리의 종류를
의미한다. (취급 설명서를 보자.) 두번째 인자는 원하는 메시지가
왔을 때 호출될 '훅 프로시저'이다. 훅 프로시저에 대해서는 잠시
후에 살펴보자. 세번째 파라미터는 훅 프로시저가 정의된 DLL이나 EXE
의 인스탄스이고 마지막 인자는 괴롭힐 쓰레드의 아이디이다. 시스템
전체를 상대로 갈구리질을 하기 위해서는 이 마지막 인자에 0을, 특정
쓰레드를 괴롭히고 싶으면 원하는 쓰레드의 아이디를 넣어주면 된다.
갈구리가 정확히 찍히면, 이 함수는 훅의 핸들을 넘겨주게 된다. 실패
하면 리턴값은 0이다. 이 훅의 핸들은 뒤에 갈구리를 해체할 때나
다음 갈구리를 호출할 때 사용되니 잘 보관해야 한다.
다음 예제는 현재 프로세스에 키보드 훅을 걸어주는 예제이다.
var
HKbHook : 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;
begin
Result := 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의 파일 스트림을 이용해 하드 디스크에 훅의 핸들
을 저장하는 방법을 사용하도록 하겠다.
****************
민성기도 하는 훅킹 3.
*** 실전~
자, 드디어 기다리고 기다리던 시간이다. 이제 직접 갈구리를 휘둘
러 볼 때가 왔다. 이 강좌에서는 WH_KEYBOARD와 WH_SHELL이라는 두 개
의 갈구리를 이용해 키보드의 동작과 노트패드의 실행을 마음껏 괴롭
혀 볼 것이다.
위에서도 설명 했지만 시스템 전체를 상대로 맞짱을 뜨기 위해서는
훅 프로시저가 DLL내에 있어야 한다. 혹시 DLL을 만들줄 모르는 사람
이 있다면 이 계시판에 DLL사용에 대한 다른 강좌를 읽고 빠른 시간내
에 자신의 것으로 만들자.
(아~ 이 얼마나 훌륭한 떠넘기기 인가~ ^^;)
델파이의 'New' 메뉴를 선택해 'DLL' 프로젝트를 하나 시작하고, 프
로젝트 이름을 'HookDLL.DPR'로 저장하자. 갈구리질용 함수를 사용하
기 위해서는 먼저 Uses문에 Windows와 Messages를 포함시켜야 한다.
uses
SysUtils,
Classes,
Windows,
Messages;
키보드와 셀의 훅 핸들을 저장할 두개의 전역변수를 만들어 두자.
var
HKbHook : HHOOK;
HShellHook : HHOOK;
앞에서 말했듯이, 이 전역변수들은 DLL 내의 훅 프로시저가 호출될
때마다 다른 어플리케이션의 영역에 있기 때문에 어떤값을 가지고 있
을지는 아무도 모른다. (물론, 일반적으로는 0일 것이다.) 따라서 각
어플리케이션과 무관한 영역에 이 값을 저장하고 불러와야 한다. 여기
서는 그 영역을 하드디스크 내의 'C:\Hook.dat'파일로 하자. 이제 이
파일에 파일에 훅 데이터를 읽고 써주는 프로시저, ReadData와
WriteData를 만들자.
Const
HookDataFile = 'c:\Hook.Dat';
procedure ReadData;
var
F : TFileStream;
begin
F := TFileStream.Create(HookDataFile, fmOpenRead);
try
F.Read(HKbHook, sizeof(HKbHook));
F.Read(HShellHook, sizeof(HShellHook));
finally
F.Free;
end;
end;
procedure WriteData;
var
F : TFileStream;
begin
F := TFileStream.Create(HookDataFile, fmCreate);
try
F.Write(HKbHook, sizeof(HKbHook));
F.Write(HShellHook, sizeof(HShellHook));
finally
F.Free;
end;
end;
각 어플리케이션에서 이 DLL이 호출될 때, 일반적으로 위의 전역변
수 값은 0이다. 그러나 누가 알겠는가~?? 불의의 사고로 인해 0이 아
닌 쓰레기값이 들어갈 수도 있다. 영화에서도 보면 그렇다. 다 죽은줄
알았던 주인공이 '끄응~'하고 살아나 영화 끝날때까지 악당을 괴롭힌
다. 이 악당~ 자기가 게을러서 그렇게 된 것이므로 어디가서 하소연도
하지 못한다.
따라서 우리 역시 불쌍한 악당꼴이 되지 않기 위해서는 언제나 '확
인사살'을 확실히 해야 한다. 초기에 두개의 훅핸들 전역변수를 0으로
해 주자.
begin
HKbHook := 0;
HShellHook := 0;
end.
이제 키보드 동작에 대한 갈구리질을 정의하자. 키보드를 먹통으로
만들어, 키보드 위에 라면남비를 올려놓고 라면을 먹는 것이 이 갈구
리질의 목적이다.
{ 갈구리질 프로시저 }
function MyKBHook(Code : Integer; wParam : WPARAM; lParam : LPARA
M)
: LongInt; stdcall;
begin
{ 파일에 저장된 훅핸들을 읽어온다. }
if HKbHook = 0 then
ReadData;
{ Code값이 0보다 크거나 같을때만 }
{ 갈구리질을 하는 것이 요령. }
if Code >= 0 then
begin
{ 키보드를 몽땅 안눌리게 하자. }
{ 다음 훅체인이 불리지 않도록 하면 끝~! }
Result := Integer(True);
Exit;
end;
Result := CallNextHookEx(HKbHook, Code, wParam, lParam);
end;
{ 키보드 갈구리 찍기 }
function HookKB : Boolean;
begin
HKbHook := SetWindowsHookEx(
WH_KEYBOARD, MyKBHook, HInstance, 0);
Result := Boolean(HKbHook);
{ 파일에 훅핸들 쓰기 }
WriteData;
end;
{ 키보드 갈구리 뽑기 }
function UnHookKB : Boolean;
begin
{ 파일에 저장된 훅핸들을 읽어온다. }
if HKbHook = 0 then
ReadData;
Result := UnhookWindowsHookEx(HKbHook);
end;
갈구리를 찍고 뽑는 방법, 그리고 갈구리를 휘두르는 방법에 대한
개념이 어렵지 않게 이해 되었을 것이다. 이번엔 마찬가지 방법으로
'메모장'의 실행을 모니터하는 갈구리를 하나 더 만들어 보자.
{ 셀 갈구리질 }
function MyShellHook(Code : Integer; wParam : WPARAM; lParam : LP
ARAM)
: LongInt; stdcall;
var
Buff : array [0..255] of Char;
s : String;
begin
{ 파일에 저장된 훅핸들을 읽어온다. }
if HShellHook = 0 then
ReadData;
{ 윈도우의 생성과 소멸만 괴롭힌다. 자세한 내용은
도움말을 참조할 것. }
if (code = HSHELL_WINDOWCREATED) or
(code = HSHELL_WINDOWDESTROYED) then
begin
{ 윈도우의 클래스명을 읽어온다. Code값이 위의 두개의 값일
경우, wParam은 윈도우의 핸들값이 된다. }
GetClassName(wParam, Buff, SizeOf(Buff));
{ 클래스명이 노트패드라면 메시지박스 보여주기. }
if Buff = 'Notepad' then
begin
if (code = HSHELL_WINDOWCREATED) then
S := '메모장이 실행되는구만요~!'
else
S := '메모장이 끝났구만요~!';
MessageBox(0,PChar(S),'Hook Message',0);
end;
end;
{ 다음 훅체인 호출 }
Result := CallNextHookEx(HShellHook, Code, wParam, lParam);
end;
{ 셀 갈구리 찍기 }
function HookSHELL : Boolean;
begin
HShellHook := SetWindowsHookEx(
WH_SHELL, MyShellHook, HInstance, 0);
Result := Boolean(HShellHook);
{ 파일에 훅핸들 쓰기 }
WriteData;
end;
{ 셀 갈구리 뽑기 }
function UnHookSHELL : Boolean;
begin
{ 파일에 저장된 훅핸들을 읽어온다. }
if HShellHook = 0 then
ReadData;
Result := UnhookWindowsHookEx(HShellHook);
end;
이제, 갈구리를 찍고 뽑는 함수들을 외부에서 사용할 수 있도록
Exports 구문에 추가해 주자.
Exports
HookKB,
HookSHELL,
UnHookKB,
UnHookSHELL;
이것으로 훅용 DLL이 완성되었다. 컴파일 하면 'Hookdll.DLL' 파일
이 생길 것이다.
이제 이 DLL을 사용해 갈구리를 찍고 해제하는 간단한 프로그램을
만들어 보자. 새로운 어플리케이션을 시작하고 Hookdll.DLL'내의 함수
들을 다음과 같이 임포트 한다.
function HookKB : Boolean; external 'HookDll.dll';
function UnHookKB : Boolean; external 'HookDll.dll';
function HookSHELL : Boolean; external 'HookDll.dll';
function UnHookSHELL : Boolean; external 'HookDll.dll';
버튼을 네 개 올려놓고 이름을 각각 HookKBBtn, HookShellBtn,
UnHookKBBtn, UnHookShellBtn 이라고 짓자. 앞의 두 버튼의 Enabled
속성을 꺼주고 각 버튼들의 OnClick이벤트 프로시저를 다음과 같이 작
성해 준다.
procedure TForm1.HookKBBtnClick(Sender: TObject);
begin
if HookKB then
begin
HookKBBtn.Enabled := false;
UnHookKBBtn.Enabled := True;
end;
end;
procedure TForm1.HookShellBtnClick(Sender: TObject);
begin
if HookShell then
begin
HookShellBtn.Enabled := false;
UnHookShellBtn.Enabled := True;
end;
end;
procedure TForm1.UnHookKBBtnClick(Sender: TObject);
begin
if UnHookKB then
begin
HookKBBtn.Enabled := True;
UnHookKBBtn.Enabled := False;
end;
end;
procedure TForm1.UnHookShellBtnClick(Sender: TObject);
begin
if UnHookShell then
begin
HookShellBtn.Enabled := True;
UnHookShellBtn.Enabled := False;
end;
end;
이제 컴파일 후 실행해 보자. 키보드 훅을 동작시키면 키보드 위에
라면냄비를 올려놓고 먹을 수 있다. 셀 훅을 동작시킨다면 '메모장'이
실행되고 끝날 때마다 메시지박스가 나타날 것이다. 눈치 빠른 사람은
키보드 훅으로 키보드 전체를 먹통으로 만들어도 Alt-Tab 이나
Ctrl-Alt-Del 같은 키조합이 막히지 않는다는 것을 발견했을 것이다.
윈도우는 이러한 시스템 키조합을 갈구리질로부터 보호하고 있기 때
문인데, 이것조차 막아버리기 희망하는 엽기적 프로그래머는 자료실에
하영재님이 올리신 종료막기 컴포넌트를 참고하도록 하자.
*** 맺으며~
메모장의 실행을 모니터하고 키보드를 먹통으로 만드는 간단한 갈구
리 프로그램을 만들어 보았다. 갈구리를 쓴다는 것은 것은 메시지 흐
름을 손에 쥐는 것이다. 이제 조금이라도 껄떡대는 메시지가 눈에 띈
다면 잡아서 족치고 볼 것이다. 수 틀리면 위의 키보드 훅처럼 전달하
지 않고 삽으로 묻어버리는 일도 종종 발생할 것이다.
그러니 부디 머리도 자주 감고 발도 자주 닦아 개인 위생 및 정신건
강을 바로잡고 맨정신으로 다가오는 21세기를 준비해야 겠다.
이상 강좌 끝~~!!