Keyboard Hooking under Win32
--------------------------------------------------------------------------------
김영대님 홈에서 가져옴 (cozy@hanmail.net)
거기서 원래 출처를 밝히지 않았으므로 원출처에 대해서는 모름
김태훈 번역
다음 예제는 Win32에서 System wide windows hook(역자주:하나의 Application에 국한 되지 않고 시스템 상의 모든 프로세스에 영향을 미침)을 만들어 내는 것을 보여준다. 이 예제는 system hook dll과 example application 모두 제공한다. (역자주:System wide windows hook을 작성하기 위해서는 Hook Callback 함수가 DLL에 들어 있어야 한다) 또한 우리가 만들어 낼 Hook 함수는 진보된 코딩 기술, 즉, memory mapped files을 사용해서 프로세스 경계를 넘나드는 전역 메모리 공유하기, Key Hook 함수에서 메시지를 발생시킨 Application으로 메시지 돌려 보내기, 그리고 DLL을 실행중에 동적으로 Loading하기 같은 것을 보여준다.
우리가 만들어낼 이 키보드 훅 예제는 사용자가 키보드를 통해 넣는 Keystroke 수를 매겨서 유지한다. 나아가서 우리는 Enter Key를 Trap(사로잡기)하고, Enter Key를 누른 각 시점에 키보드 훅을 시작한 Application으로 메시지를 전달하는 것을 보여 줄 것이다. 그리고나서 우리는 현재 Application을 통해 키를 임대하지 않고, 왼쪽 화살표 키를 Trap하는 것을 보여줄 것이다. 그보다는 우리는 오른쪽 화살표키로 그것을 대체할 것이다. (노트: 의심이 적은 사용자에게는 많은 혼동을 야기할것이다.)
윈도우 시스템에 훅을 더하는 것은 SetWindowsHookEx()라는 Windows API를 호출하는 것과 당신이 설치하는 훅 함수의 주소를 당신이 설치하기를 원하는 타입에 전달하는 것을 포함한다. System wide hook functions은, 시스템 상의 각 프로세스에 mapping 되어져야(역자주:가상 주소와 연관되어 있음) 하므로, dynamic link library에 속해야 함이 요구되어진다. SetWindowsHookEx() 함수는 당신의 훅 함수를, 당신이 설치한 훅의 핸들(또는 ID)을 반환하는, Windows "hook chain"에 더한다. 당신은 이 핸들을 윈도우에 있는 당신의 훅을 확인하거나 키보드 트랩핑이 끝났을때 당신의 훅을 제거하는데 사용할 것이다.
윈도우즈 "hook chain"은 윈도우가 이미 설치된 모든 훅들의 track을 유지하는데 사용하는 연결 리스트이다. 임의로 주어진 시간에 설치되어지는 다중(multiple) 훅이 허락된다. 가끔 윈도우즈는 당신의 훅 함수에게 모든 훅에게 작동할 기회를 허락하는 그 체인내에 있는 다음 훅을 호출하기위해 물을 것이다. 우리가 체인상의 다음 훅을 호출할때 우리는 우리의 훅 함수 핸들을 다음 훅으로 전달함에 의해 우리 자신을 확인하는 것이 필요할 것이다.
윈도우즈 훅을 만드는 것은 win32 하에서 특별한 다룸이 필요하다. DLL이 keystrokes를 받는 모든 Application의 프로세스 공간으로 mapping되어야하기 때문이다. 이것은 이슈가 아니다. 그러나 keyhook procedure 내부에서 운영될때, 전역변수(당신의 훅 핸들 같은 것)는 그 DLL이 다른 프로세스 공간으로 mapping되어 있을동안 보존되어 있어야 한다. 윈16에서, 이것은 하나의 프로그램이 되지는 않는다. DLL들은 모든 프로세스 mapping에 공유된 단일 Data segment를 가지고 있기때문이다. 윈32에서는, DLL의 각 mapping은 소유권을 가진 Data segment를 받는다. 이것은 그것이 keyboard hook을 담고 있는 DLL이 keystroke를 받는 각 프로세스에 mapping되어 있음을 의미한다. 그것은 새로운 Data segment와 그것과 함께 초기화 되지 않은 새 변수를 를 받는다. 이것이 문제이다. 전역 변수(당신의 훅 핸들같은 것)는 process mapping들 사이에서 보존되어야만 한다. 이 문제를 해결하기 위해 우리는 system paging file로부터 map variable들을 기억하기 위한 Win32의 능력의 유리한 점을 가질 것이다.
각 시점에 우리의 DLL은 한 프로세스에 mapping될 것이다. 우리의 DLL안에 있는 DllMain() 함수는 호출에 대한 이유는 지시하는 파라미터 Flag과 함께 윈도우에 의해 호출될 것이다. 우리가 DLL_PROCESS_ATTACH flag(다른 프로세스로 mapping된 것을 얻고 있는 나의 DLL을 지시한다)를 받았을때, 우리는 system paging file을 mapping하는 파일을 만들 것이고, 우리의 메모리에 mapping된 변수들에 대한 포인터를 얻을 것이다. 우리가 DLL_PROCESS_DETACH flag(프로세스로부터 un-mapping되는 것을 얻고 있는 나의 DLL을 지시한다.)를 받았을때, 우리는 system paging file을 mapping한 우리의 파일을 해제할 것이다. 우리가 트랙에 유지하기를 필요로 하는(그리고 keyboard hook을 Load한 Application과 DLL 모두로부터 접근할 수 있는) 그 변수들은 THookRec을 호출한 기록 구조체에 할당될 것이다. THookRec 구조체는 다음과 같다.
TheHookHandle : 원문 참조
TheAppWinHandle : 원문 참조
TheCtrlWinHandle : 원문 참조
TheKeyCount : 원문 참조
DLL은 다음 함수들을 담고 있다. - 내용은 원문 참조
MapFileMemory
UnMapFileMemory
GetHookRecPointer
KeyBoardProc
StartKeyBoardHook
StopKeyBoardHook
DllEntryPoint
Delphi Hook DLL 예제:
원문 참조
Application notes:
우리가 만들어 낸 테스트 Application은 keyboard hook을 담고 있는 DLL을 Loading하는 것과 설치하는 것, 총 keystroke 수와 (실시간에) enter key사 몇번 눌러졌는가를 보여(Display)주는 것 그리고 keyboard hook과 DLL을 uninstall하는 것을 보여(demonstrates)준다.
application code는 두개의 label과 버튼, timer component를 가진 Form을 정의하므로서 시작한다. 한번 우리는 우리의 hook 한수를 설치한다. 우리는 timer를 시작할 것이다. 그리고 every timer event에 기반해서 우리는 label1에서 총 keystroke 수(Hook이 설정된 이후 사용자에 의해 들어온)를 보여 줄 것이다. 또한 그 훅은 버튼의 OnKeyDown event를 Enter Key가 눌러진 시점에서 점화시킬 것이다. 그리고 그것은 우리에게 Enter Key가 몇번 눌러졌는가를 label2의 captiom에 보여줄 수 있는 기회를 준다.
Form이 정의된후, 우리는 hook DLL에서 정의된 바와 같은 방식으로 THookRec 구조체를 정의한다. 우리가 사용할 것인 다른 변수들은 다음을 포함한다. hook sll을 Loading하기 위해 사용되는 handle 변수, GetHookRecPointer(), StartKeyBoardHook(), and StopKeyBoardHook()를 호출하는데 사용하기위한 세개의 함수 포인터 변수. 마지막으로 우리는 그 memory mapped 변수에 접근하는데 사용하는 THookRec 구조체에 대한 포인터, enter key가 몇번 눌러졌는가에 대한 트랙을 유지하는 변수, DLL Loading의 성공을 지시하는데 사용하는 변수, 그 함수들을 얻는데 사용하는 변수 그리고 그 hook을 설정하는데 사용하는 변수를 정의한다.
Application logic은 다음처럼 행해진다.
원문 참조
댓글 없음:
댓글 쓰기