[C#] Easy Hook Library

简介

.NET似乎都没有比较好用的Hook类库,那就只好自己来做一个。


设计概念

原先我只是想将Hook的API做一些简单的封装,将其封装成一个Hook类,做一做发现其实Hook其实也不多,那乾脆先用enum将所有的hook type(参考:http://msdn.microsoft.com/en-us/library/ms644959%28v=vs.85%29.aspx)一并声明好了

因此我利用Dictionary数据结构,Key为自定的HookType,Value为自行封装的Hook类,并用一个HookManager来管理Dictionary,对Hook做Register跟Unregister的动作。

同时在register时提供自定义的delegate,以实践自定义的hookproc。


public enum HookType
{
    WH_MSGFILTER = -1,
    WH_JOURNALRECORD = 0,
    WH_JOURNALPLAYBACK = 1,
    WH_KEYBOARD = 2,
    WH_GETMESSAGE = 3,
    WH_CALLWNDPROC = 4,
    WH_CBT = 5,
    WH_SYSMSGFILTER = 6,
    WH_MOUSE = 7,
    WH_DEBUG = 9,
    WH_SHELL = 10,
    WH_FOREGROUNDIDLE = 11,
    WH_CALLWNDPROCRET = 12,
    WH_KEYBOARD_LL = 13,
    WH_MOUSE_LL = 14
}

关于HookType中的WH_XXXX数值,请参照WinUser.h中的声明。


class _HookProc
{
    #region "Declare API for Hook"
    [DllImport("user32.dll", CharSet = CharSet.Auto,
    CallingConvention = CallingConvention.StdCall)]
    static extern int SetWindowsHookEx(int idHook, _HookProcHandler lpfn,
    IntPtr hInstance, int threadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto,
    CallingConvention = CallingConvention.StdCall)]
    static extern bool UnhookWindowsHookEx(int idHook);

    [DllImport("user32.dll", CharSet = CharSet.Auto,
    CallingConvention = CallingConvention.StdCall)]
    static extern int CallNextHookEx(int idHook, int nCode,
    IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll")]
    static extern int GetCurrentThreadId();
    #endregion

    #region "Hook Proc"
    int MyHookProc(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (m_CustomHookProc != null)
            m_CustomHookProc(nCode, wParam, lParam);
        return CallNextHookEx(m_HookHandle, nCode, wParam, lParam);
    }
    #endregion

    CustomHookProc.HookProcHandler m_CustomHookProc;
    delegate int _HookProcHandler(int nCode, IntPtr wParam, IntPtr lParam);
    _HookProcHandler m_KbdHookProc;
    int m_HookHandle = 0;

    public _HookProc(HookType a_eHookType, CustomHookProc.HookProcHandler a_pHookProc)
    {
        m_CustomHookProc = a_pHookProc;
        m_KbdHookProc = new _HookProcHandler(MyHookProc);
        m_HookHandle = SetWindowsHookEx((int)a_eHookType, m_KbdHookProc, IntPtr.Zero, GetCurrentThreadId());
        if (m_HookHandle == 0)
        {
            throw new Exception(string.Format("Hook {0} to {1} Error:{2}", a_eHookType.ToString(), a_pHookProc.ToString(), Marshal.GetLastWin32Error()));
        }
    }
    ~_HookProc()
    {
        UnhookWindowsHookEx(m_HookHandle);
        Debug.WriteLine(Marshal.GetLastWin32Error());
        m_HookHandle = 0;
    }
}

public class CustomHookProc
{
    private CustomHookProc(){}
    public delegate void HookProcHandler(int nCode, IntPtr wParam, IntPtr lParam);
}


前面的几个API的声明,是在.NET中呼叫Win32 API的方法(参考:http://msdn.microsoft.com/en-us/library/aa984739%28v=VS.71%29.aspx)。

重点是在MyHookProc,SetWindowsHookEx会将Hook指到这个函数,同时在这个函数执行时,会将Hook到的讯息丢到外部的CustomHookProc.HookProcHandler Delegate。


public class HookManager
{
    private HookManager(){}

    static readonly HookManager m_instance = new HookManager();
    Dictionary<HookType, _HookProc> m_hooks = new Dictionary<HookType, _HookProc>();

    public static HookManager Instance
    {
        get { return m_instance; }
    }

    public void RegisterHook(HookType a_eHookType, CustomHookProc.HookProcHandler a_pHookProc)
    {
        if(!m_hooks.ContainsKey(a_eHookType))
        {
            m_hooks.Add(a_eHookType, new _HookProc(a_eHookType, a_pHookProc));
        }
        else
        {
            throw new Exception(string.Format("{0} already exist!", a_eHookType.ToString()));
        }
    }
    public void Unregister(HookType a_eHookType)
    {
        m_hooks.Remove(a_eHookType);
    }
}

HookManager类是一个单例类,它负责维护所有的Hook。


private void Form1_Load(object sender, EventArgs e)
{
    HookManager.Instance.RegisterHook(HookType.WH_KEYBOARD, new CustomHookProc.HookProcHandler(KeyboardHookProc));
    HookManager.Instance.RegisterHook(HookType.WH_MOUSE, new CustomHookProc.HookProcHandler(MouseHookProc));
}
void KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
    KeyStateInfo ctrlKey = KeyboardInfo.GetKeyState(Keys.ControlKey);
    KeyStateInfo altKey = KeyboardInfo.GetKeyState(Keys.Alt);
    KeyStateInfo shiftKey = KeyboardInfo.GetKeyState(Keys.ShiftKey);
    KeyStateInfo f8Key = KeyboardInfo.GetKeyState(Keys.F8);

    if (ctrlKey.IsPressed)
    {
        Console.WriteLine("Ctrl Pressed!");
    }
    if (altKey.IsPressed)
    {
        Console.WriteLine("Alt Pressed!");
    }
    if (shiftKey.IsPressed)
    {
        Console.WriteLine("Shift Pressed!");
    }
    if (f8Key.IsPressed)
    {
        Console.WriteLine("F8 Pressed!");
    }
}

void MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
    MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

    if (nCode >= 0)
    {
        String strCaption = "x = " +
        MyMouseHookStruct.pt.x.ToString("d") +
        "  y = " +
        MyMouseHookStruct.pt.y.ToString("d");
        Form tempForm = Form.ActiveForm;

        tempForm.Text = strCaption;
    }
}

封装完毕后,使用起来就非常简单

HookManager.Instance.RegisterHook(HookType.WH_KEYBOARD, new CustomHookProc.HookProcHandler(KeyboardHookProc));
HookManager.Instance.RegisterHook(HookType.WH_MOUSE, new CustomHookProc.HookProcHandler(MouseHookProc));

像这样使用,而且在HookProc中也不需要去管return CallNextHookEx(m_HookHandle, nCode, wParam, lParam);

只需针对自己所要处理的Hook处理即可。


参考连结

http://msdn.microsoft.com/zh-cn/magazine/cc188966(en-us).aspx


范例档下载

目前最好的EasyHook的完整Demo程序,包括了Hook.dll动态库和Inject.exe注入程序。 Hook.dll动态库封装了一套稳定的下钩子的机制,以后对函数下钩子,只需要填下数组表格就能实现了,极大的方便了今后的使用。 Inject.exe是用MFC写的界面程序,只需要在界面上输入进程ID就能正确的HOOK上相应的进程,操作起来非常的简便。 这个Demo的代码风格也非常的好,用VS2010成功稳定编译通过,非常值得下载使用。 部分代码片段摘录如下: //【Inject.exe注入程序的代码片段】 void CInjectHelperDlg::OnBnClickedButtonInjectDllProcessId() { ////////////////////////////////////////////////////////////////////////// //【得到进程ID值】 UINT nProcessID = 0; if (!GetProcessID(nProcessID)) { TRACE(_T("%s GetProcessID 失败"), __FUNCTION__); return; } ////////////////////////////////////////////////////////////////////////// //【得到DLL完整路径】 CString strPathDLL; if (!GetDllFilePath(strPathDLL)) { TRACE(_T("%s GetDllFilePath 失败"), __FUNCTION__); return; } ////////////////////////////////////////////////////////////////////////// //【注入DLL】 NTSTATUS ntStatus = RhInjectLibrary(nProcessID, 0, EASYHOOK_INJECT_DEFAULT, strPathDLL.GetBuffer(0), NULL, NULL, 0); if (!ShowStatusInfo(ntStatus)) { TRACE(_T("%s ShowStatusInfo 失败"), __FUNCTION__); return; } } //【Hook.dll动态库的代码片段】 extern "C" __declspec(dllexport) void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* InRemoteInfo) { if (!DylibMain()) { TRACE(_T("%s DylibMain 失败"), __FUNCTION__); return; } } FUNCTIONOLDNEW_FRMOSYMBOL array_stFUNCTIONOLDNEW_FRMOSYMBOL[]= { {_T("kernel32"), "CreateFileW", (void*)CreateFileW_new}, {_T("kernel32"), "CreateFileA", (void*)CreateFileA_new}, {_T("kernel32"), "ReadFile", (void*)ReadFile_new} }; BOOL HookFunctionArrayBySymbol() { /////////////////////////////////////////////////////////////// int nPos = 0; do { /////////////////////////////// FUNCTIONOLDNEW_FRMOSYMBOL* stFunctionOldNew = &g_stFUNCTIONOLDNEW_FRMOSYMBOL[nPos]; if (NULL == stFunctionOldNew->strModuleName) { break; } /////////////////////////////// if (!HookFunctionBySymbol(stFunctionOldNew->strModuleName, stFunctionOldNew->strNameFunction, stFunctionOldNew->pFunction_New)) { TRACE(_T("%s HookFunctionBySymbol 失败"), __FUNCTION__); return FALSE; } } while(++nPos); /////////////////////////////////////////////////////////////// return TRUE; } HANDLE WINAPI CreateFileW_new( PWCHAR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) { TRACE(_T("CreateFileW_new. lpFileName = %s"), lpFileName); return CreateFileW( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值