잊지 않겠습니다.

'NativeCode'에 해당되는 글 1건

  1. 2010.01.05 0008. CSWindowsHook

0008. CSWindowsHook

Sample Codes 2010. 1. 5. 16:26
Windows Hooking의 경우에는 Windows message queue에 대한 이해가 좀 필요하다.
Windows는 Windows Message Queue를 통해서 각각의 Message를 전달하고, 그 Message에 따라 각기 다른 Action을 행한다.
WM_PAINT의 경우에는 화면을 그리라는 Message가 되고, WM_MOUSE의 경우에는 Mouse의 움직임에 따라 발생되는 Windows
Message이다.

Hooking은 이런 WIndows Message Queue에 Hook을 걸어서, 원래 처리되어야지 되는 함수가 아닌, 사용자 지정 Method에서
처리하게 하는 방법이다. 이것을 이용하면 Ctrl+Alt+Del의 기능도 막아버릴 수 있으며, 마우스를 움직여서 다른 동작을 하는 것도
막는 것이 가능하다. 또한 Mouse나 Keyboard의 모든 기록들을 저장할 수 있기 때문에 Windows에서 Cracking을 하는 경우에
왕왕 사용되는 방법이다.

먼저, WIN32 함수인 SetWindowsHookEx 함수를 DllImport시켜서 가지고 온다. 필요한 Native method의 선언은 다음과 같다.

internal delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

internal class NativeMethods
{
    /// 
    /// Hooking WIN32 API
    /// dwThreadId가 0인 경우에는 전역 hook
    /// 특정 handler안에서 Hooking을 하는 경우에는 Handle 값을 넣어준다.
    /// 
    /// 
    /// Hooking을 한 이후에 받을 method의 주소값 delegate된 method를 넣어줄수 있다.
    /// 
    /// 
    /// 
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc callback, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
}

internal static class HookCodes
{
    public const int HC_ACTION = 0;
    public const int HC_GETNEXT = 1;
    public const int HC_SKIP = 2;
    public const int HC_NOREMOVE = 3;
    public const int HC_NOREM = HC_NOREMOVE;
    public const int HC_SYSMODALON = 4;
    public const int HC_SYSMODALOFF = 5;
}

internal enum HookType
{
    WH_KEYBOARD = 2,
    WH_MOUSE = 7,
    WH_KEYBOARD_LL = 13,
    WH_MOUSE_LL = 14
}

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

/// 
/// The MSLLHOOKSTRUCT structure contains information about a low-level keyboard 
/// input event. 
/// 
[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEHOOKSTRUCT
{
    public POINT pt;        // The x and y coordinates in screen coordinates
    public int hwnd;        // Handle to the window that'll receive the mouse message
    public int wHitTestCode;
    public int dwExtraInfo;
}

/// 
/// The MOUSEHOOKSTRUCT structure contains information about a mouse event passed 
/// to a WH_MOUSE hook procedure, MouseProc. 
/// 
[StructLayout(LayoutKind.Sequential)]
internal struct MSLLHOOKSTRUCT
{
    public POINT pt;        // The x and y coordinates in screen coordinates. 
    public int mouseData;   // The mouse wheel and button info.
    public int flags;
    public int time;        // Specifies the time stamp for this message. 
    public IntPtr dwExtraInfo;
}

internal enum MouseMessage
{
    WM_MOUSEMOVE = 0x0200,
    WM_LBUTTONDOWN = 0x0201,
    WM_LBUTTONUP = 0x0202,
    WM_LBUTTONDBLCLK = 0x0203,
    WM_RBUTTONDOWN = 0x0204,
    WM_RBUTTONUP = 0x0205,
    WM_RBUTTONDBLCLK = 0x0206,
    WM_MBUTTONDOWN = 0x0207,
    WM_MBUTTONUP = 0x0208,
    WM_MBUTTONDBLCLK = 0x0209,

    WM_MOUSEWHEEL = 0x020A,
    WM_MOUSEHWHEEL = 0x020E,

    WM_NCMOUSEMOVE = 0x00A0,
    WM_NCLBUTTONDOWN = 0x00A1,
    WM_NCLBUTTONUP = 0x00A2,
    WM_NCLBUTTONDBLCLK = 0x00A3,
    WM_NCRBUTTONDOWN = 0x00A4,
    WM_NCRBUTTONUP = 0x00A5,
    WM_NCRBUTTONDBLCLK = 0x00A6,
    WM_NCMBUTTONDOWN = 0x00A7,
    WM_NCMBUTTONUP = 0x00A8,
    WM_NCMBUTTONDBLCLK = 0x00A9
}

/// 
/// The structure contains information about a low-level keyboard input event. 
/// 
[StructLayout(LayoutKind.Sequential)]
internal struct KBDLLHOOKSTRUCT
{
    public int vkCode;      // Specifies a virtual-key code
    public int scanCode;    // Specifies a hardware scan code for the key
    public int flags;
    public int time;        // Specifies the time stamp for this message
    public int dwExtraInfo;
}

internal enum KeyboardMessage
{
    WM_KEYDOWN = 0x0100,
    WM_KEYUP = 0x0101,
    WM_SYSKEYDOWN = 0x0104,
    WM_SYSKEYUP = 0x0105
}

여기에서 구성된 Hooking method들은 다음과 같다.

private bool SetGlobalLLMouseHook()
{
    // Create an instance of HookProc.
    globalLLMouseHookCallback = new HookProc(this.LowLevelMouseProc);

    hGlobalLLMouseHook = NativeMethods.SetWindowsHookEx(
        HookType.WH_MOUSE_LL,  // Must be LL for the global hook
        globalLLMouseHookCallback,
        // Get the handle of the current module
        Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
        // The hook procedure is associated with all existing threads running 
        // in the same desktop as the calling thread.
        0);
    return hGlobalLLMouseHook != IntPtr.Zero;
}

public int LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
{
    if(nCode >= 0)
    {
        // Marshal the MSLLHOOKSTRUCT data from the callback lParam
        MSLLHOOKSTRUCT mouseLLHookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));

        // Get the mouse WM from the wParam parameter
        MouseMessage wmMouse = (MouseMessage)wParam;

        // Display the current mouse coordinates and the message
        String log = String.Format("X = {0} Y = {1}  ({2})\r\n", mouseLLHookStruct.pt.x, mouseLLHookStruct.pt.y, wmMouse);
        tbLog.AppendText(log);
    }

    // Pass the hook information to the next hook procedure in chain
    return NativeMethods.CallNextHookEx(hGlobalLLMouseHook, nCode, wParam, lParam);
}
Posted by Y2K
,