Introduction

이번 시간에는 전역 후킹(Global Hooking)에 대해서 알아보도록 하겠습니다.

C/C++ 에서는 Win32 API를 이용하여 손쉽게 전역 후킹을 할 수 있습니다. 물론 .NET 에서도 Win32 API의 DLL 파일을 Import 하여 후킹이 가능합니다. 하지만 약간의 문제가 있습니다. 지역 후킹이 아닌 전역 후킹에서는 CallBack Procedure 를 DLL 파일로 만들어야 한다는 것이지요. 이런 이유로 .NET 에서는 전역 후킹이 안된다는 이야기가 많이 있습니다. 저 역시 초기에 이런 문제에 부딪혔습니다.

Microsoft 에서 전역 후킹에 대해서 찾아보니 심지어 이런 내용이 있었습니다.

물론 이 이야기가 맞습니다. .NET 에서 전역 후킹(Global Hooking)을 하려면, 이 DLL 을 C/C++ 과 같이 네이트브 코드로 만들고, 이것을 호출하는 방법 밖엔 없습니다.

하지만, 마우스와 키보드에 대한 전역 후킹은 .NET 에서 가능합니다. 다시 말하자면, 마우스와 키보드 이외에는 전역후킹이 불가능 하다는 이야기가 되겠습니다 :) 이 방식은 WH_MOUSE_LL, WH_KEYBOARD_LL 만 지원한다는 이야기입니다.

즉, WH_MOUSE 나 WH_KEYBOARD 는 지원하지 않습니다. 저 역시 예전엔 이 idHook 을 사용하고 왜 안될까 고민했던 것 같습니다.
코드는 다음과 같이 매우 간단합니다. 가독성을 위해서 partial 로 나누어 놓았습니다. 오해 없으시기 바랍니다.


Example

[Win32 API Wrapper]


internal static class Win32   
{   
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]   
    public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);      
  
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]   
    public static extern bool UnhookWindowsHookEx(int idHook);      
  
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]   
    public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);   
  
    public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);   
}




[구조체 / idHook]


public static partial class MouseHook  
{  
    [StructLayout(LayoutKind.Sequential)] 
    public class POINT  
    {  
        public int x;  
        public int y;  
    }     

    [StructLayout(LayoutKind.Sequential)]  
    public class MouseHookStruct  
    {  
        public POINT point;  
        public int hwnd;  
        public int wHitTestCode;  
        public int dwExtraInfo;  
    }  

    public const int WH_MOUSE_LL = 14;  
} 



[Start Hook]


public static partial class MouseHook  
{  
    private static int hookHandle = 0;     

    public static void StartHook() {  
        if(hookHandle != 0) { return; }  
        hookHandle = Win32.SetWindowsHookEx(WH_MOUSE_LL, CallBack, Marshal.GetHINSTANCE(  
                    Assembly.GetExecutingAssembly().GetModules()[0]), 0);  
    }  

    public static void StopHook() {  
        Win32.UnhookWindowsHookEx(hookHandle);  
    }  

    public static int CallBack(int nCode, IntPtr wParam, IntPtr lParam) {  
        MouseHookStruct mouseInput = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));  
        System.Diagnostics.Debug.WriteLine(mouseInput.pt.x + " : " + mouseInput.pt.y);  
        return Win32.CallNextHookEx(hookHandle, nCode, wParam, lParam);  
    }  
} 




Epilogue

이 포스팅을 포함하여 몇몇 포스팅을 보다가 이런 생각을 하시는 분들이 계실것 같습니다.

'어?! 이거 어디서 본 포스팅 같은데? 어디서 긁어온 것 아냐? 저작권 침해다.'

맞는 말이기도 하고 틀린 말이기도 합니다.
긁어온 것은 맞으나, 저작권 침해는 아니라는 것이죠.
왜냐면 원본글 역시 제가 작성했던 글이거든요 :)

사실 이 글은 http://witstudio.net 에서 제가 작성했던 글을 다시 옮겨온 것입니다. :)
오해 없으시기 바랍니다.