消息钩子学习工程

  • 前奏
近来一直在自学Windows Hook相关的知识,已经尝试多种注入方式。尤其对消息钩子方式很感兴趣,因为看到Spy++能够截获系统中绝大多数应用的消息流,就很想知道它的工作原理,打算制作属于自己的Spy++。
  • 消息钩子简介:
消息钩子简言之就是Windows处理消息的一个平台,用户可以在此平台获取或过滤所需应用的消息(例如某鼠标位置,键盘击下等),这些被监控的消息都会在目标窗口处理函数之前被截获。系统在拿到消息后会问你:这是不是你想要的消息?如果是,则恭喜你,你可以在回调函数里做相应操作了。
  • 消息钩子函数背景
消息钩子主要由三部分组成:
  1. 钩子安装函数
  2. 钩子回调函数
  3. 钩子卸载函数
  • 钩子安装函数原型:
HHOOK WINAPI SetWindowsHookEx(_In_  int idHook,_In_  HOOKPROC lpfn,_In_  HINSTANCE hMod,_In_  DWORD dwThreadId
);
SetWindowsHookEx
x
1
HHOOK WINAPI SetWindowsHookEx(
2
  _In_  int idHook,
3
  _In_  HOOKPROC lpfn,
4
  _In_  HINSTANCE hMod,
5
  _In_  DWORD dwThreadId
6
);
参数1-idHook:这个函数代表了你要安装钩子的种类,比如键盘钩子,鼠标钩子,窗体钩子等等。以下我列了一张表,结合MSDN供大家参考。
钩子类型释义
WH_CALLWNDPROC(4)
此类型的钩子,可以让你监控发送到窗口过程的消息。
WH_CALLWNDPROCRET(12)
此类型的钩子,可以让你监控到已被目标窗体处理的消息。
WH_CBT(5)
此类型的钩子十分繁杂,可监控的消息很多。例如窗口创立,销毁,最大最小化,移动等。
WH_DEBUG(9)
此类型钩子,可以决定能否让系统调用与其他Hook关联的子程序。说白了,这就是个调试钩子,可以用来调试其他安装好的钩子。
WH_FOREGROUNDIDLE(11)
此类型钩子,可以在前台线程空闲时执行低优先级的任务,当然了,线程空闲是由系统决定的。
WH_GETMESSAGE(3)
此类型的钩子,可以截获消息队列中的所有消息。例如GetMessage,PeekMessage函数的返回消息。
WH_JOURNALPLAYBACK
(1)
此类型的钩子,可以插入消息到消息队列。除此,这个钩子可以记录下来连续的鼠标及键盘事件,以用来回放。
WH_JOURNALRECORD(0)
此类型的钩子,用以监视发往系统队列的输入事件,这是个全局钩子,不可用于线程。
WH_KEYBOARD
(2)
此类型的钩子,顾名思义,用于监视键盘击下,弹起消息。通过GetMessage,PeekMessage函数返回。(请注意,根据我的实验结果,这个钩子仅对本程序有效)
WH_KEYBOARD_LL(13)
此类型的钩子,是底层设备钩子,除具备WH_KEYBOARD的功能,可以记录所有的键盘输入,包括热键。
WH_MOUSE(7)
此类型的钩子,顾名思义,用于监视输入到消息队列的鼠标消息。通过GetMessage,PeekMessage函数返回。(只能获得钩子所在模块的消息)
WH_MOUSE_LL(14)
此类型的钩子,是底层设备钩子,除具备WH_KEYBOARD的功能,可以记录系统中所有的鼠标消息。
WH_MSGFILTER(-1)
此类型的钩子,可监视由对话框、消息框、菜单条、或滚动条中的输入事件引发的消息。
WH_SHELL(10)
此类型的钩子,可以监视各种Shell事件信息,例如应用程序的启动,关闭等等。
WH_SYSMSGFILTER(6)
此类型的钩子,是强化版的WH_MSGFILTER,可以监视系统中所有应用程序的此类消息。
参数2-HOOKPROC lpfn:此参数是钩子回调函数的地址,对应上述不同种类的钩子类型,其钩子回调函数原型基本是一致的。请见下(需要注意的是,wParam和lParam针对不同类型的钩子,传递参数所代表意义不同,因种类繁多,请各位查阅MSDN):
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam
)
{// process event...return CallNextHookEx(NULL, nCode, wParam, lParam);
}
12
1
LRESULT CALLBACK HookProc(
2
  int nCode, 
3
  WPARAM wParam, 
4
  LPARAM lParam
5
)
6
{
7
   // process event
8
   ...
9
10
   return CallNextHookEx(NULL, nCode, wParam, lParam);
11
}
nCode:int,此参数指示Hook例程是否需要处理消息,如果nCode为HC_ACTION,则需要处理;如果小于0,不予处理,须调用CallNextHookEx函数返回。
wParam与lParam:针对不同类型的钩子,代表的意义不同,但总体是针对当前类型钩子的消息。后面以例子做出验证。
参数3-HINSTANCE hMod:包含Hook例程的Dll所在模块基址。
参数4-DWORD dwThreadId:所要注入程序的主线程ID。如果此项填0,则代表钩子为系统钩子,基本所有在运行的进程都会被注入。如果此项指定线程ID,则是有针对性的线程钩子。
返回值:HHOOK类型的句柄。
  • 钩子回调函数
请见上。
  • 钩子卸载函数
BOOL WINAPI UnhookWindowsHookEx(_In_  HHOOK hhk
);
1
BOOL WINAPI UnhookWindowsHookEx(
2
  _In_  HHOOK hhk
3
);
参数:SetWindowsHookEx的返回值。
  • 键盘消息钩子及CBT钩子程序代码
首先我们要明确下,钩子从安装到回显的流程
  1. 编写Dll,在Dll中实现我们所需要的钩子回调函数及安装函数。
  2. Dll中除了要编写与钩子相关的处理函数,也要编写与显示程序通信的模块,以便验证钩子消息的正确性。
  3. Dll需要导出钩子启动函数与卸载函数。
  4. 回显程序处理已安装钩子发送的信息。
至此,框架已经明了,我们分步拆解完成这个小项目。(整体代码请见附件,VS2013编译)
  • 结构体及枚举的定义
typedef struct COMMPACK
{int nType;//Hook类型WPARAM wParam;//参数1LPARAM lParam;//参数2TCHAR szMsg[16];//额外的字符串信息,取决于具体钩子
} COMMPACK, *PCOMMPACK;//与回显程序通讯的包结构typedef struct HOOKSTC
{int nType;//Hook类型HOOKPROC hkproc;//Hook回调HHOOK hhook;//Hook句柄
} HOOKSTC, *PHOOKSTC;HOOKSTC m_Array4Hooks[NHOOKNUMS] = { 0 };//创建多钩子类型的结构体数组enum { M_CALLWNDPROC, M_CBT, M_DEBUG, M_GETMESSAGE, M_KEYBOARD, M_MOUSE, M_MSGFILTER };//钩子类型枚举enum { IDHCBT_ACTIVATE, IDHCBT_CLICKSKIPPED, IDHCBT_CREATEWND, IDHCBT_DESTROYWND, IDHCBT_KEYSKIPPED,IDHCBT_MINMAX, IDHCBT_MOVESIZE, IDHCBT_QS, IDHCBT_SETFOCUS, IDHCBT_SYSCOMMAND, IDUnknown
};//CBT钩子的消息群
22
1
typedef struct COMMPACK
2
{
3
    int nType;//Hook类型
4
    WPARAM wParam;//参数1
5
    LPARAM lParam;//参数2
6
    TCHAR szMsg[16];//额外的字符串信息,取决于具体钩子
7
} COMMPACK, *PCOMMPACK;//与回显程序通讯的包结构
8
9
typedef struct HOOKSTC
10
{
11
    int nType;//Hook类型
12
    HOOKPROC hkproc;//Hook回调
13
    HHOOK hhook;//Hook句柄
14
} HOOKSTC, *PHOOKSTC;
15
16
HOOKSTC m_Array4Hooks[NHOOKNUMS] = { 0 };//创建多钩子类型的结构体数组
17
18
enum { M_CALLWNDPROC, M_CBT, M_DEBUG, M_GETMESSAGE, M_KEYBOARD, M_MOUSE, M_MSGFILTER };//钩子类型枚举
19
20
enum { IDHCBT_ACTIVATE, IDHCBT_CLICKSKIPPED, IDHCBT_CREATEWND, IDHCBT_DESTROYWND, IDHCBT_KEYSKIPPED,
21
    IDHCBT_MINMAX, IDHCBT_MOVESIZE, IDHCBT_QS, IDHCBT_SETFOCUS, IDHCBT_SYSCOMMAND, IDUnknown
22
};//CBT钩子的消息群

  • CBT钩子的回调函数
LRESULT WINAPI m_CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{if (nCode < 0)return CallNextHookEx(m_Array4Hooks[M_CBT].hhook, nCode, wParam, lParam);CHAR szCode[16] = { 0 };PCOMMPACK pCP = new COMMPACK;pCP->nType = M_CBT;switch (nCode){case HCBT_ACTIVATE://系统要激活一个窗口pCP->lParam = (LPARAM)IDHCBT_ACTIVATE;pCP->wParam = IDHCBT_ACTIVATE;break;case HCBT_CLICKSKIPPED://系统已经从系统消息队列中删除了一个鼠标消息pCP->lParam = (LPARAM)IDHCBT_CLICKSKIPPED;pCP->wParam = IDHCBT_CLICKSKIPPED;break;case HCBT_CREATEWND://一个窗口将要被创建pCP->lParam = (LPARAM)IDHCBT_CREATEWND;pCP->wParam = IDHCBT_CREATEWND;break;case HCBT_DESTROYWND://一个窗口将要被销毁pCP->lParam = (LPARAM)IDHCBT_DESTROYWND;pCP->wParam = IDHCBT_DESTROYWND;break;case HCBT_KEYSKIPPED://系统已从系统消息队列中删除了一个键盘消息pCP->lParam = (LPARAM)IDHCBT_KEYSKIPPED;pCP->wParam = IDHCBT_KEYSKIPPED;break;case HCBT_MINMAX://一个窗口将被最小化或最大化pCP->lParam = (LPARAM)IDHCBT_MINMAX;pCP->wParam = IDHCBT_MINMAX;break;case HCBT_MOVESIZE://一个窗口将被移动或改变尺寸pCP->lParam = (LPARAM)IDHCBT_MOVESIZE;pCP->wParam = IDHCBT_MOVESIZE;break;case HCBT_QS://系统已从系统消息队列中取到一个WM_QUEUESYNC 消息pCP->lParam = (LPARAM)IDHCBT_QS;pCP->wParam = IDHCBT_QS;break;case HCBT_SETFOCUS://一个窗口将要获得键盘焦点pCP->lParam = (LPARAM)IDHCBT_SETFOCUS;pCP->wParam = IDHCBT_SETFOCUS;break;case HCBT_SYSCOMMAND://一个系统命令将被执行pCP->lParam = (LPARAM)IDHCBT_SYSCOMMAND;pCP->wParam = IDHCBT_SYSCOMMAND;break;default://其他pCP->lParam = (LPARAM)IDUnknown;pCP->wParam = IDUnknown;break;}m_Com(pCP);//与回显程序通信delete pCP;return CallNextHookEx(m_Array4Hooks[M_CBT].hhook, nCode, wParam, lParam);
}
56
1
57
1
LRESULT WINAPI m_CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
2
{
3
    if (nCode < 0)return CallNextHookEx(m_Array4Hooks[M_CBT].hhook, nCode, wParam, lParam);
4
    CHAR szCode[16] = { 0 };
5
    PCOMMPACK pCP = new COMMPACK;
6
    pCP->nType = M_CBT;
7
    switch (nCode)
8
    {
9
    case HCBT_ACTIVATE://系统要激活一个窗口
10
        pCP->lParam = (LPARAM)IDHCBT_ACTIVATE;
11
        pCP->wParam = IDHCBT_ACTIVATE;
12
        break;
13
    case HCBT_CLICKSKIPPED://系统已经从系统消息队列中删除了一个鼠标消息
14
        pCP->lParam = (LPARAM)IDHCBT_CLICKSKIPPED;
15
        pCP->wParam = IDHCBT_CLICKSKIPPED;
16
        break;
17
    case HCBT_CREATEWND://一个窗口将要被创建
18
        pCP->lParam = (LPARAM)IDHCBT_CREATEWND;
19
        pCP->wParam = IDHCBT_CREATEWND;
20
        break;
21
    case HCBT_DESTROYWND://一个窗口将要被销毁
22
        pCP->lParam = (LPARAM)IDHCBT_DESTROYWND;
23
        pCP->wParam = IDHCBT_DESTROYWND;
24
        break;
25
    case HCBT_KEYSKIPPED://系统已从系统消息队列中删除了一个键盘消息
26
        pCP->lParam = (LPARAM)IDHCBT_KEYSKIPPED;
27
        pCP->wParam = IDHCBT_KEYSKIPPED;
28
        break;
29
    case HCBT_MINMAX://一个窗口将被最小化或最大化
30
        pCP->lParam = (LPARAM)IDHCBT_MINMAX;
31
        pCP->wParam = IDHCBT_MINMAX;
32
        break;
33
    case HCBT_MOVESIZE://一个窗口将被移动或改变尺寸
34
        pCP->lParam = (LPARAM)IDHCBT_MOVESIZE;
35
        pCP->wParam = IDHCBT_MOVESIZE;
36
        break;
37
    case HCBT_QS://系统已从系统消息队列中取到一个WM_QUEUESYNC 消息
38
        pCP->lParam = (LPARAM)IDHCBT_QS;
39
        pCP->wParam = IDHCBT_QS;
40
        break;
41
    case HCBT_SETFOCUS://一个窗口将要获得键盘焦点
42
        pCP->lParam = (LPARAM)IDHCBT_SETFOCUS;
43
        pCP->wParam = IDHCBT_SETFOCUS;
44
        break;
45
    case HCBT_SYSCOMMAND://一个系统命令将被执行
46
        pCP->lParam = (LPARAM)IDHCBT_SYSCOMMAND;
47
        pCP->wParam = IDHCBT_SYSCOMMAND;
48
        break;
49
    default://其他
50
        pCP->lParam = (LPARAM)IDUnknown;
51
        pCP->wParam = IDUnknown;
52
        break;
53
    }
54
    m_Com(pCP);//与回显程序通信
55
    delete pCP;
56
    return CallNextHookEx(m_Array4Hooks[M_CBT].hhook, nCode, wParam, lParam);
57
}

  • 键盘钩子的回调函数
LRESULT WINAPI m_KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{if ((nCode < 0 || !((DWORD)lParam & 0x40000000)))return CallNextHookEx(m_Array4Hooks[M_KEYBOARD].hhook, nCode, wParam, lParam);PCOMMPACK pCP = new COMMPACK;pCP->lParam = lParam;pCP->wParam = wParam;//这个值就是按键的VirtualKeypCP->nType = M_KEYBOARD;m_Com(pCP);//与回显程序通讯delete pCP;return CallNextHookEx(m_Array4Hooks[M_KEYBOARD].hhook, nCode, wParam, lParam);
}
11
1
LRESULT WINAPI m_KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
2
{
3
    if ((nCode < 0 || !((DWORD)lParam & 0x40000000)))return CallNextHookEx(m_Array4Hooks[M_KEYBOARD].hhook, nCode, wParam, lParam);
4
    PCOMMPACK pCP = new COMMPACK;
5
    pCP->lParam = lParam;
6
    pCP->wParam = wParam;//这个值就是按键的VirtualKey
7
    pCP->nType = M_KEYBOARD;
8
    m_Com(pCP);//与回显程序通讯
9
    delete pCP;
10
    return CallNextHookEx(m_Array4Hooks[M_KEYBOARD].hhook, nCode, wParam, lParam);
11
}

  • 与回显程序通讯的函数
void m_Com(PCOMMPACK& pCP, int addi)
{hTarget = ::FindWindow(NULL, L"HookApp");//寻找回显程序窗口标题COPYDATASTRUCT stcCDS;//采用WM_COPYDATA消息方式进程间通讯stcCDS.cbData = sizeof(COMMPACK);stcCDS.dwData = addi;stcCDS.lpData = pCP;//打包消息结构体::SendMessage(hTarget, WM_COPYDATA, 0, (LPARAM)&stcCDS);
}
1
void m_Com(PCOMMPACK& pCP, int addi)
2
{
3
    hTarget = ::FindWindow(NULL, L"HookApp");//寻找回显程序窗口标题
4
    COPYDATASTRUCT stcCDS;//采用WM_COPYDATA消息方式进程间通讯
5
    stcCDS.cbData = sizeof(COMMPACK);
6
    stcCDS.dwData = addi;
7
    stcCDS.lpData = pCP;//打包消息结构体
8
    ::SendMessage(hTarget, WM_COPYDATA, 0, (LPARAM)&stcCDS);
9
}

  • 钩子初始化函数
void InitHooks()
{hTarget = ::FindWindow(NULL, L"HookApp");m_Array4Hooks[M_CALLWNDPROC].hkproc = m_CallWndProc;m_Array4Hooks[M_CALLWNDPROC].nType = WH_CALLWNDPROC;m_Array4Hooks[M_CBT].hkproc = m_CBTProc;m_Array4Hooks[M_CBT].nType = WH_CBT;//m_Array4Hooks[M_DEBUG]->hkproc = m_DebugProc;//m_Array4Hooks[M_DEBUG]->nType = WH_DEBUG;//m_Array4Hooks[M_GETMESSAGE]->hkproc = m_GetMsgProc;//m_Array4Hooks[M_GETMESSAGE]->nType = WH_GETMESSAGE;m_Array4Hooks[M_KEYBOARD].hkproc = m_KeyboardProc;m_Array4Hooks[M_KEYBOARD].nType = WH_KEYBOARD;m_Array4Hooks[M_MOUSE].hkproc = m_MouseProc;m_Array4Hooks[M_MOUSE].nType = WH_MOUSE;//m_Array4Hooks[M_MSGFILTER]->hkproc = m_MessageFilterProc;//m_Array4Hooks[M_MSGFILTER]->nType = WH_MSGFILTER;for (int i = 0; i < NHOOKNUMS; ++i){m_Array4Hooks[i].hhook = 0;}
}
x
1
void InitHooks()
2
{
3
    hTarget = ::FindWindow(NULL, L"HookApp");
4
    m_Array4Hooks[M_CALLWNDPROC].hkproc = m_CallWndProc;
5
    m_Array4Hooks[M_CALLWNDPROC].nType = WH_CALLWNDPROC;
6
    m_Array4Hooks[M_CBT].hkproc = m_CBTProc;
7
    m_Array4Hooks[M_CBT].nType = WH_CBT;
8
    //m_Array4Hooks[M_DEBUG]->hkproc = m_DebugProc;
9
    //m_Array4Hooks[M_DEBUG]->nType = WH_DEBUG;
10
    //m_Array4Hooks[M_GETMESSAGE]->hkproc = m_GetMsgProc;
11
    //m_Array4Hooks[M_GETMESSAGE]->nType = WH_GETMESSAGE;
12
    m_Array4Hooks[M_KEYBOARD].hkproc = m_KeyboardProc;
13
    m_Array4Hooks[M_KEYBOARD].nType = WH_KEYBOARD;
14
    m_Array4Hooks[M_MOUSE].hkproc = m_MouseProc;
15
    m_Array4Hooks[M_MOUSE].nType = WH_MOUSE;
16
    //m_Array4Hooks[M_MSGFILTER]->hkproc = m_MessageFilterProc;
17
    //m_Array4Hooks[M_MSGFILTER]->nType = WH_MSGFILTER;
18
    for (int i = 0; i < NHOOKNUMS; ++i)
19
    {
20
        m_Array4Hooks[i].hhook = 0;
21
    }
22
}

  • 钩子安装及卸载函数
void InstallHook(DWORD dwProcessID)
{g_dwThreadID = GetThreadInfo(dwProcessID);//由注入器传入指定注入进程ID,遍历获得主线程IDInitHooks();//初始化钩子for (int i = 0; i < NHOOKNUMS; ++i){if (m_Array4Hooks[i].hkproc == NULL)continue;m_Array4Hooks[i].hhook = SetWindowsHookEx(m_Array4Hooks[i].nType, m_Array4Hooks[i].hkproc, g_Module, g_dwThreadID);}
}void UnInstallHook()
{for (int i = 0; i < NHOOKNUMS; ++i){UnhookWindowsHookEx(m_Array4Hooks[i].hhook);}
}
12
1
void InstallHook(DWORD dwProcessID)
2
{
3
    g_dwThreadID = GetThreadInfo(dwProcessID);//由注入器传入指定注入进程ID,遍历获得主线程ID
4
5
    InitHooks();//初始化钩子
6
7
    for (int i = 0; i < NHOOKNUMS; ++i)
8
    {
9
        if (m_Array4Hooks[i].hkproc == NULL)continue;
10
        m_Array4Hooks[i].hhook = SetWindowsHookEx(m_Array4Hooks[i].nType, m_Array4Hooks[i].hkproc, g_Module, g_dwThreadID);
11
    }
12
}
13
14
void UnInstallHook()
15
{
16
    for (int i = 0; i < NHOOKNUMS; ++i)
17
    {
18
        UnhookWindowsHookEx(m_Array4Hooks[i].hhook);
19
    }
20
}

  • 线程遍历函数
DWORD GetThreadInfo(DWORD dwProcessID)
{HANDLE hSnThread = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);if (hSnThread == INVALID_HANDLE_VALUE) {return 0;}// 开始遍历线程THREADENTRY32 threadEntry = { sizeof(THREADENTRY32) };// 获取快照中的第一个线程的信息Thread32First(hSnThread, &threadEntry);DWORD dwSuspendCount = 0;do {// 判断遍历到的线程是否属于这个进程的.if (threadEntry.th32OwnerProcessID == dwProcessID) {return threadEntry.th32ThreadID;}// 获取快照中的下一个线程信息} while (Thread32Next(hSnThread, &threadEntry));return 1;
}
25
1
DWORD GetThreadInfo(DWORD dwProcessID)
2
{
3
    HANDLE hSnThread = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
4
    if (hSnThread == INVALID_HANDLE_VALUE) {
5
        return 0;
6
    }
7
8
    // 开始遍历线程
9
    THREADENTRY32 threadEntry = { sizeof(THREADENTRY32) };
10
11
    // 获取快照中的第一个线程的信息
12
    Thread32First(hSnThread, &threadEntry);
13
14
    DWORD dwSuspendCount = 0;
15
    do {
16
17
        // 判断遍历到的线程是否属于这个进程的.
18
        if (threadEntry.th32OwnerProcessID == dwProcessID) {
19
            return threadEntry.th32ThreadID;
20
        }
21
        // 获取快照中的下一个线程信息
22
    } while (Thread32Next(hSnThread, &threadEntry));
23
    return 1;
24
}

  • 函数导出
EXTERN_C _declspec(dllexport) void InstallHook(DWORD dwProcessID);
EXTERN_C _declspec(dllexport) void UnInstallHook();
1
EXTERN_C _declspec(dllexport) void InstallHook(DWORD dwProcessID);
2
EXTERN_C _declspec(dllexport) void UnInstallHook();

至此DLL部分结束,开始回显程序的消息处理
BOOL CHookAppDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{// TODO:  在此添加消息处理程序代码和/或调用默认值static int nIndex = 0;PCOMMPACK pCP = new COMMPACK;pCP = (PCOMMPACK)pCopyDataStruct->lpData;switch (pCP->nType)//根据消息的类型进行定义{case M_CALLWNDPROC:{}break;case M_CBT:{static int nIndex = 0;CString strCallWndProc;switch (pCP->wParam){case IDHCBT_ACTIVATE:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_ACTIVATE", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_CLICKSKIPPED:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_CLICKSKIPPED", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_CREATEWND:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_CLICKSKIPPED", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_DESTROYWND:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_DESTROYWND", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_KEYSKIPPED:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_KEYSKIPPED", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_MINMAX:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_MINMAX", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_MOVESIZE:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_MOVESIZE", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_QS:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_QS", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_SETFOCUS:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_SETFOCUS", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDHCBT_SYSCOMMAND:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_SYSCOMMAND", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case IDUnknown:{strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"Unknown", pCP->wParam);strCallWndProc += L"\r\n";m_StrCBT += strCallWndProc;UpdateData(FALSE);++nIndex;}break;default:break;}}break;case M_DEBUG:{}break;case M_GETMESSAGE:{}break;case M_KEYBOARD:{static int nIndex = 0;CString strCallWndProc;strCallWndProc.Format(L"KEYBOARD [%d] - VK: %c  ", nIndex, char(pCP->wParam));strCallWndProc += L"\r\n";m_StrKeyBoard += strCallWndProc;UpdateData(FALSE);++nIndex;}break;case M_MOUSE:{}break;case M_MSGFILTER:{}break;default:break;}return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}
x
1
BOOL CHookAppDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
2
{
3
    // TODO:  在此添加消息处理程序代码和/或调用默认值
4
    static int nIndex = 0;
5
    PCOMMPACK pCP = new COMMPACK;
6
    pCP = (PCOMMPACK)pCopyDataStruct->lpData;
7
8
    switch (pCP->nType)//根据消息的类型进行定义
9
    {
10
    case M_CALLWNDPROC:
11
    {
12
13
    }break;
14
15
    case M_CBT:
16
    {
17
        static int nIndex = 0;
18
        CString strCallWndProc;
19
        switch (pCP->wParam)
20
        {
21
        case IDHCBT_ACTIVATE:
22
        {
23
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_ACTIVATE", pCP->wParam);
24
            strCallWndProc += L"\r\n";
25
            m_StrCBT += strCallWndProc;
26
            UpdateData(FALSE);
27
            ++nIndex;
28
        }break;
29
        case IDHCBT_CLICKSKIPPED:
30
        {
31
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_CLICKSKIPPED", pCP->wParam);
32
            strCallWndProc += L"\r\n";
33
            m_StrCBT += strCallWndProc;
34
            UpdateData(FALSE);
35
            ++nIndex;
36
        }break;
37
        case IDHCBT_CREATEWND:
38
        {
39
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_CLICKSKIPPED", pCP->wParam);
40
            strCallWndProc += L"\r\n";
41
            m_StrCBT += strCallWndProc;
42
            UpdateData(FALSE);
43
            ++nIndex;
44
        }break;
45
        case IDHCBT_DESTROYWND:
46
        {
47
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_DESTROYWND", pCP->wParam);
48
            strCallWndProc += L"\r\n";
49
            m_StrCBT += strCallWndProc;
50
            UpdateData(FALSE);
51
            ++nIndex;
52
        }break;
53
        case IDHCBT_KEYSKIPPED:
54
        {
55
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_KEYSKIPPED", pCP->wParam);
56
            strCallWndProc += L"\r\n";
57
            m_StrCBT += strCallWndProc;
58
            UpdateData(FALSE);
59
            ++nIndex;
60
        }break;
61
        case IDHCBT_MINMAX:
62
        {
63
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_MINMAX", pCP->wParam);
64
            strCallWndProc += L"\r\n";
65
            m_StrCBT += strCallWndProc;
66
            UpdateData(FALSE);
67
            ++nIndex;
68
        }break;
69
        case IDHCBT_MOVESIZE:
70
        {
71
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_MOVESIZE", pCP->wParam);
72
            strCallWndProc += L"\r\n";
73
            m_StrCBT += strCallWndProc;
74
            UpdateData(FALSE);
75
            ++nIndex;
76
        }break;
77
        case IDHCBT_QS:
78
        {
79
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_QS", pCP->wParam);
80
            strCallWndProc += L"\r\n";
81
            m_StrCBT += strCallWndProc;
82
            UpdateData(FALSE);
83
            ++nIndex;
84
        }break;
85
        case IDHCBT_SETFOCUS:
86
        {
87
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_SETFOCUS", pCP->wParam);
88
            strCallWndProc += L"\r\n";
89
            m_StrCBT += strCallWndProc;
90
            UpdateData(FALSE);
91
            ++nIndex;
92
        }break;
93
        case IDHCBT_SYSCOMMAND:
94
        {
95
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"HCBT_SYSCOMMAND", pCP->wParam);
96
            strCallWndProc += L"\r\n";
97
            m_StrCBT += strCallWndProc;
98
            UpdateData(FALSE);
99
            ++nIndex;
100
        }break;
101
        case IDUnknown:
102
        {
103
            strCallWndProc.Format(L"CBT [%d] - nCode: %s, tsk: %ld  ", nIndex, L"Unknown", pCP->wParam);
104
            strCallWndProc += L"\r\n";
105
            m_StrCBT += strCallWndProc;
106
            UpdateData(FALSE);
107
            ++nIndex;
108
        }break;
109
        default:
110
            break;
111
        }
112
    }break;
113
    case M_DEBUG:
114
    {
115
116
    }break;
117
    case M_GETMESSAGE:
118
    {
119
120
    }break;
121
    case M_KEYBOARD:
122
    {
123
        static int nIndex = 0;
124
        CString strCallWndProc;
125
        strCallWndProc.Format(L"KEYBOARD [%d] - VK: %c  ", nIndex, char(pCP->wParam));
126
        strCallWndProc += L"\r\n";
127
        m_StrKeyBoard += strCallWndProc;
128
        UpdateData(FALSE);
129
        ++nIndex;
130
        
131
    }break;
132
    case M_MOUSE:
133
    {
134
        
135
    }break;
136
    case M_MSGFILTER:
137
    {
138
139
    }break;
140
141
    default:
142
        break;
143
    }
144
145
    return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
146
}
147

注入器部分代码:
BOOL _Inject_::m_WindowsHook(PWCHAR pszDllName, LPCSTR pszDllProc, DWORD dwPID)
{typedef void* (*HookOnProto)(DWORD);//声明导出函数原型HookOnProto HookOn;hInstDll = LoadLibrary(pszDllName);if (hInstDll == NULL)return FALSE;HookOn = (HookOnProto)GetProcAddress(hInstDll, pszDllProc);//从指定Dll导出所需函数if (HookOn == NULL)return FALSE;HookOn(dwPID);//钩子安装return TRUE;
}BOOL _Inject_::m_UnWinHook(PWCHAR pszDllName, LPCSTR pszDllProc)
{typedef void* (*HookOffProto)(void);HookOffProto HookOff;HookOff = (HookOffProto)GetProcAddress(hInstDll, pszDllProc);if (HookOff == NULL)return FALSE;HookOff();
}
24
1
BOOL _Inject_::m_WindowsHook(PWCHAR pszDllName, LPCSTR pszDllProc, DWORD dwPID)
2
{
3
    typedef void* (*HookOnProto)(DWORD);//声明导出函数原型
4
    HookOnProto HookOn;
5
    hInstDll = LoadLibrary(pszDllName);
6
    if (hInstDll == NULL)return FALSE;
7
8
    HookOn = (HookOnProto)GetProcAddress(hInstDll, pszDllProc);//从指定Dll导出所需函数
9
    if (HookOn == NULL)return FALSE;
10
11
    HookOn(dwPID);//钩子安装
12
13
    return TRUE;
14
}
15
16
BOOL _Inject_::m_UnWinHook(PWCHAR pszDllName, LPCSTR pszDllProc)
17
{
18
    typedef void* (*HookOffProto)(void);
19
    HookOffProto HookOff;
20
21
    HookOff = (HookOffProto)GetProcAddress(hInstDll, pszDllProc);
22
    if (HookOff == NULL)return FALSE;
23
    HookOff();
24
}

效果演示:(以注入notepad++为例)
安装消息钩子前
1280023-20171115170543515-1703250893.png

安装消息钩子后
1280023-20171115170544656-1654771803.png

由于钩子种类繁多,我暂时没有全部实现,有兴趣的各位可以在我的基础上试试其他的,代码写的不好,让各位见笑了,如有错误,也恳请各位指正。


来自为知笔记(Wiz)


转载于:https://www.cnblogs.com/B166ER/p/7839870.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354574.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Angular] 笔记 8:list/detail 页面以及@Input

1. list 页面 list/detail 是重要的 UI 设计模式。 vscode terminal 运行如下命令生成 detail 组件&#xff1a; PS D:\Angular\my-app> ng generate component pokemon-base/pokemon-detail --modulepokemon-base/pokemon-base.module.ts CREATE src/app/pokemon-base/p…

javaone_JavaOne 2012 – 2400小时! 一些建议

javaone您可能已经看到JavaOne 2012 Content Catalog在线。 计划委员会经过数周的紧张工作&#xff0c;对每个提案进行了分类&#xff0c;审查&#xff0c;评分和讨论&#xff0c;我们终于设法为您设置了&#xff08;希望如此&#xff09;有趣的组合。 整整105天或2400小时&…

推荐几个最近Star过的Github仓库

平时逛Github的时候&#xff0c;总是顺手对一些自己认为好的仓库给个 Star&#xff0c;一是对作者的鼓励&#xff0c;二来推荐给关注自己的人&#xff08;首页动态可见&#xff09;。 下面列举了一些我平时 Star 过的仓库&#xff0c;顺便也推荐给我的读者。 Front-End Checkli…

使用Gatling + Gradle + Jenkins Pipeline为您的JAX-RS(和JavaEE)应用程序进行连续压力测试...

在这篇文章中&#xff0c;我将解释如何使用Gatling项目为您的JAX-RS Java EE端点编写压力测试&#xff0c;以及如何将它们与Gradle和Jenkins Pipeline集成&#xff0c;因此&#xff0c;除了进行简单的压力测试外&#xff0c;您还可以使用以下方法&#xff1a; 连续的压力测试&a…

使用 VuePress 搭建一个自己的知识文档

最近准备对前端知识做一个梳理&#xff0c;将自己的平时遇到的问题和解决方案形成一个知识文档。本文记录了搭建 VuePress 的主要过程&#xff0c;同时也提供了部分自定义的配置&#xff0c;示例地址&#xff1a;http://doc.i-fanr.com 环境搭建 VuePress 有着比较完善的中文文…

金三银四跳槽面试季,我整理前端知识做了个网站

每年的金三银四&#xff0c;都将迎来求职面试的一个高峰期&#xff0c;为什么会有那么多的求职需求&#xff1f;多是因为以下几个来源&#xff1a;已拿 offer 等年终奖的&#xff1a;年前已经找到机会&#xff0c;领了年终奖辞职要到新公司报到的临时起意要辞及裸辞的&#xff…

hadoop的Map阶段的四大步骤

深入理解map的几个阶段是怎样执行的。转载于:https://www.cnblogs.com/xubiao/p/7846080.html

小程序 Typescript 最佳实践

小程序结合TypeScript开发&#xff0c;如果用第三方框架&#xff0c;首选Taro已完美支持。但是如果你选择原生开发&#xff0c;那么下面的这份实践可能会帮到你。小程序 Typescript 最佳实践使用 gulp 构建&#xff08;支持 typescript 和 less/sass/scss&#xff09;使用 type…

这款电脑升降桌美到我了

一直在寻觅一款集颜值与功能于一体的电脑升降桌&#xff0c;这款乐歌 E5 电动桌终于成功地满足了我的需求。有黑白两款颜色可选&#xff0c;但其中白色钢化玻璃版常适合用来作为白色系桌面的基础——四周圆角设计&#xff0c;再加上碳素钢的桌体框架&#xff0c;整体非常有质感…

分享一个引起极度舒适的工作桌面

干净整洁的桌面或许不能带给你工作效率的提升&#xff0c;但一定会给你带来愉悦的心情。长期码字一定需要一个升降桌&#xff0c;可自由地调节高度&#xff0c;以保证舒适的坐姿和灵活的视角。另外坐久了&#xff0c;累了还能站立工作一会儿。有了外显之后&#xff0c;如果不需…

canvas绘制多边形

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>canvas绘制多边形</title> </head> <body> <canvas id"canvas" style"border: 1px solid darkcyan;" width…

ehcache rmi_EhCache复制:RMI与JGroups

ehcache rmi最近&#xff0c;我正在研究一种需要复制缓存的产品。 缓存提供程序已经确定-EhCache&#xff0c;剩下的就是有关传输的问题。 哪一个是最佳选择&#xff1f; 这里的最佳选择是指性能更好的选择。 仅在两个可用传输之间进行了性能评估-JGroups和RMI&#xff0c;对其…

Element Table 可以实现哪些常见的有用的功能

最近项目中频繁使用 table 功能&#xff0c;因为 UI 框架使用的又是 Element UI&#xff0c;于是总结下在 Element 下 el-table 组件使用技巧。1.行背景色table 组件提供了 row-style 属性&#xff0c;说明&#xff1a;行的 style 的回调方法&#xff0c;也可以使用一个固定的 …

如果在这样的环境中写代码,会不会很高效

桌面环境分享系列又来了。我会把平时看到的好的桌面布置分享给大家&#xff0c;帮助大家在桌面整理和打造方面提供一些新的想法和创意。如何评价一个开发桌面的好坏&#xff0c;首先一定要清爽整洁&#xff0c;该有的家伙事儿一定要有。不是要看上去要有多高大上&#xff0c;重…

Vue 页面如何监听用户预览时间

最近的业务中涉及到这样一个需求&#xff0c;在线培训的系统需要知道用户对某个在线预览的页面追踪用户的预览时长。初步我们首先想到借助 Vue 页面的生命周期函数 mounted 和 destroyed&#xff0c;分别在其中加入开始计时和清除计时的逻辑&#xff0c;通过后台的接口上报对应…

一个追求高效的学习者手机里装有哪些APP?(转)

转载&#xff1a;http://www.jianshu.com/p/f568c8d8b6bb 1、录音软件-Recordium 参加活动&#xff0c;如果不想错过活动现场的经常片段&#xff0c;速记又来不及&#xff0c;那就选择录音吧。小六之前都使用录音笔&#xff0c;但是自从有了这个APP之后&#xff0c;在开会&…

spring social_Spring Social入门

spring social像我一样&#xff0c;无论是添加简单的Facebook“赞”按钮&#xff0c;一大堆“共享”按钮还是显示时间轴信息&#xff0c;您都不会注意到当前对应用程序“社交化”的热衷。 每个人都在做这件事&#xff0c;包括Spring的家伙&#xff0c;事实上&#xff0c;他们提…

Vue 页面如何利用生命周期函数监听用户预览时长

最近的业务中涉及到这样一个需求&#xff0c;在线培训的系统需要知道用户对某个在线预览的页面追踪用户的预览时长。初步我们首先想到借助 Vue 页面的生命周期函数 mounted 和 destroyed&#xff0c;分别在其中加入开始计时和清除计时的逻辑&#xff0c;通过后台的接口上报对应…

项目中的富文本编辑器该如何选择?

项目中经常需要用到富文本编辑器的时候&#xff0c;而常见的富文本编辑器都有哪些&#xff1f;该如何选择&#xff1f; 先看看市面上都有哪些可用的富文本编辑器&#xff1a; TinyMCE&#xff08;插件式的&#xff0c;支持 Vue&#xff0c;React&#xff0c;Angular 框架&…

根据自己的博客数据统计国内IT人群

装上百度统计有一段时间了&#xff0c;今天突然找出报表看看&#xff0c;发现一个很有意思的事情。访问来源TOP5依次是&#xff1a;北京&#xff0c;上海&#xff0c;深圳&#xff0c;杭州&#xff0c;广州 虽然大部分文章都是当时特别白的时候记录下来的遇到过的问题&#xff…