64비트 환경에서 메시지 훅을 해보셨다면 한번 쯤은 프로그램이 행에 걸리는 문제를 겪어 보셨을 겁니다. 안겪어 보셨을 수도 있구요. ㅋㅋ~
문제의 증상은 다음과 같습니다. 64비트 DLL을 인젝션한 경우에는 64비트 프로세스들은 잘 돌아가는데 32비트 프로세스만 가면 32비트 프로세스가 행이 걸리면서 크래시가 발생합니다. 마찬가지로 32비트 DLL을 인젝션한 경우에는 32비트 프로세스는 잘 돌아가는데 64비트 프로세스만 가면 행이 걸리죠. MSDN을 보아도 뭐 당연한 소리만 있습니다. 32비트 프로세스에는 32비트 DLL만 인젝션 할 수 있고, 64비트는 뭐 64비트만 인젝션 할 수 있다는 둥. 32비트 DLL을 64비트, 64비트 DLL을 32비트 프로세스에 인젝션 할 수 없다는 그런 이야기죠.
그렇다면 왜 도대체 저렇게 따로 따로 잘 돌아가는 것처럼 적어 놓은 것들이 제대로 돌아가지 않고 행이 걸리는 걸까요? 이유는 간단합니다. 인터센더블 타입의 훅이 문제인 겁니다. HKF_INTERSENDABLE이라는 타입의 훅들이 있습니다. WH_KEYBOARD, WH_MOUSE, WH_JOURNAL*, WH_SHELL, WH_KEYBOARD_LL, WH_MOUSE_LL 같은 놈이죠. 이 인터센더블이 뭐냐면 훅 메시지가 발생한 곳과 훅 프로시저가 처리되는 부분이 다르다는 겁니다. 제가 몇 년 전에 했던 후킹 강좌를 보시면 아시겠지만 WH_KEYBOARD_LL 같은 경우에는 전역 훅을 하더라도 굳이 DLL에 훅 프로시저를 넣을 필요 없이 실행 파일에 훅 프로시저를 작성해도 잘 동작합니다. 그 이유가 윈도우 하부 시스템에서 이 인터센더블 훅이면 다른 프로세스로 SendMessage를 해서 훅을 처리해주기 때문입니다. 대신에 훅 프로시저가 호출되는 컨텍스트는 당연히 틀리죠.
그렇다면 도대체 왜 이 인터센더블이 64비트로 가면서 문제를 일으키는 걸까요? 간단합니다. 인터센더블 처리를 제대로 해주지 않아서 그런 겁니다. 32비트 윈도우 환경에서는 WH_KEYBOARD 전역 훅을 했고, DLL에 훅 프로시저를 작성했다면 항상 같은 컨텍스트에서 해당 훅 프로시저가 호출됩니다. 이게 64비트로 가면 어떻게 되느냐? 64비트 DLL을 인젝션 했다면 32비트 프로세스들은 그 64비트 윈도우 훅 DLL을 로드할 수 없기 때문에 대신에 64비트 훅을 설치한 그 프로세스로 훅 처리를 넘겨주게 되는 겁니다. 즉, 32비트 환경과는 달리 DLL에 훅 프로시저를 두어도 필연적으로 64비트 환경에서는 인터센더블 상황이 발생하는 것이죠.
그렇다면 이제 이건 다 이해했는데 왜 행이 걸린 걸까요? 그건 간단합니다. 훅을 설치한 프로세스가 메시지 프로시저를 가지고 있지 않기 때문입니다. 윈도우 하부 시스템에서는 이 인터센더블을 구현하기 위해서 SendMessage를 사용합니다. 그런데 훅을 설치한 프로세스가 메시지 핸들러가 없다면 이 SendMessage를 받아서 처리할 수가 없겠죠. 그러니 행이 걸리는 겁니다.
자, 그러면 64비트 환경에서 제대로 인터센더블 훅을 처리하려면 어떻게 해야 할까요? 일단 행을 없애려면 훅을 설치한 스레드는 반드시 메시지 핸들러를 가지고 있어야 합니다. 더불어서 다른 프로세스에서 발생한 이벤트가 우리 쪽에서 처리되기 때문에 이에 대한 결정도 해야 합니다. 이걸 무시할지 안할지 말입니다. 무시하는 방법은 간단합니다. 호출되는 스레드 컨텍스트가 우리 메시지 핸들러 컨텍스트인지만 확인하면 되겠죠.
0 0