반응형

WH_MOUSE_LL 불편(?) 진실

 

Syntax

HHOOK WINAPI SetWindowsHookEx(

  __in  int idHook,

  __in  HOOKPROC lpfn,

  __in  HINSTANCE hMod,

  __in  DWORD dwThreadId

);

 

Mouse/Keyboard, Windows Message Hooking을 위한 기본 함수일 뿐 아니라,

Dll Injection용도로도 많이 쓰이는 SetWindowsHookEx 함수입니다.

아시는 바와 같이 두번째 인자인 idHook을 이용해 Hook Type을 설정하게 됩니다.

 

기계적으로 가져다 사용하던 터에 몇 가지 문제가 생겨 좀 자세히 훑어 보았습니다.

혹시 InstallHookProcedure가 어떤 Context에서 호출되는지 생각해 본적 있으신가요?

 

* 이번 포스트는 WH_MOUSE_LL에 대한 내용입니다.(WH_KEYBOARD_LL또한 유사할 것으로 짐작됩니다.)

 

MSDN을 보면 WH_MOUSE_LL 타입에 대해 다음과 같이 설명되어 있군요.

WH_MOUSE_LL

14

 

 

installs a hook procedure that monitors low-level mouse input events.

Low-Level 마우스 입력을 모니터링하는 프로시저를 설치한다.

 

For more information, see the LowLevelMouseProc hook procedure.

정보를 얻으려면 LowLevelMouseProc 보라는 군요.

한번 따라가 보겠습니다.

LowLevelMouseProc

제가 정리하고자 하는 내용은 바로 여기 Remarks 부분에 있군요.

Remarks

…<전략>

This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.

…<중략>

the WH_MOUSE_LL hook is not injected into another process. Instead, the context switches back to the process that installed the hook and it is called in its original context. Then the context switches back to the application that generated the event.

The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key:

HKEY_CURRENT_USER\Control Panel\Desktop

The value is in milliseconds. If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called. There is no way for the application to know whether the hook is removed.

The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key 

  

* 제가 설명하려는 부분에 대해 몇 가지만 찍어 보겠습니다.

1.     WH_MOUSE_LL 타입의 훅은 훅을 설치한 Thread와 같은 Context에서 호출된다. 이 호출은 훅이 설치된 Thread Message를 전달해서 호출된다. 이런 이유로 이 타입의 훅을 설치하는 Thread는 반드시 Message-Loop를 가져야 한다.

2.     WH_MOUSE_LL 타입의 훅은 다른 프로세스에 injection되지 않으며(당근 이 타입의 훅은 Dll인젝션에 사용할 수 없겠군요.), 대신 훅을 설치한 ContextContex-Switch한 후, 해당 Context에서 HookProcedure를 호출한다.

3.     HookProcedure는 최대한 빨리 처리되어야 하며, 특정 registry에 있는 Timeout안에 리턴하지 않으면 (win7 Or later에서는)해당 Hook을 조용히 제거해 버린다.(Hook을 설치한 어플리케이션으로 제거 사실은 통지되지 않으므로, 해당 시점부터 HookProcedure가 호출되지 않겠군요.)

 

* 마지막으로 제가 직면했던 문제사항은 아래와 같더랍니다.

1.     테스트OS(Win7)

2.     프로그램 시작시 WH_MOUSE_LL타입의 Hook을 설치함.

3.     Hook이 정상적으로 설치되었고, 특정 동작을 할떄까지 HookProcedure가 잘 ~ 호출됨.(특정 동작을 한 후라는걸 찾는것도 고생을 좀 했습니다.)

4.     HookHandle도 그대로 이고 UnHook하지도 않았건만, 특정 시점부터 HookProcedure가 호출되지 않음.

5.     물론 훅프로시저 내에서 긴 시간을 지체하는 코드는 없음.

 

* What’s the problem???

1.     HookProcedure내에서는 긴시간을 소요하는 작업이 없었지만, 훅을 installThread(Main Thread)에서 1초 이상 시간이 소요되는 작업요소가 있었는데, 해당 작업을 하고 나면 문제가 발생했습니다.

2.     OS는 Mouse이벤트 발생시 내 ApplicationMainThread Context-Switch한 후, HookProcedure를 호출하려 했으나 (Maint Thread에서 처리되는)시간이 소요되는 다른 작업으로 인해 Timeout안에 해당 함수를 호출하여 리턴받지 못함(HookProcedure가 호출되는 Context가 훅을 설치한 Context와 동일하므로, OS 입장에서는 HookProcedure내에서 소요되는 시간뿐아니라 해당 Context내에서 동작하는 다른 코드가 실행되는 시간에도 영향을 받게 된다는 결론이군요.)

3.     이로 인해 내가 설치한 Hook MSDN에 나온대로 조용히~ Remove된게 아닌가 싶습니다.

4.     메뉴를 하나 만들어서 Sleep(5000)하면, 해당 메뉴 실행 후 바로 훅이 풀려버리더군요.

5.     Hook을 설치한 Thread가 시간을 많이 잡아먹는 동작을 한다면, 별도의 훅 Install Thread를 생성하는 것도 고려해야 할 듯 합니다.(위에서 기술한것처럼 훅 설치 Thread에는 메시지 루프가 있어야 한다는 것도 잊지 마시기 바랍니다.)

 

  

*참고로 WH_MOUSE TypeHookProcedure는 마우스 메시지가 발생한 윈도우의 Thread Context에서 호출 됩니다.


반응형

+ Recent posts