Windows
钩子 - Windows hook
编程技术的钩子就是在等待捕获系统中的某个消息或者动作
应用程序可以通过设置Hook对某个进程或窗口进行监视,即:对特定事件“挂钩”;一旦预定义特定事件发生,Windows操作系统即会向钩子hook发送通知消息,这时,应用程序可进行响应。
钩子类型
1 2 3 4 5 6 7 8 9 10 11 12 13
| WH_CALLWNDPROC :系统将消息发送到指定窗口之前的“钩子” WH_CALLWNDPROCRET Hooks :消息已经在窗口中处理的“钩子” WH_CBT Hook :基于计算机培训的“钩子” WH_DEBUG Hook :差错“钩子” WH_FOREGROUNDIDLE Hook :前台空闲窗口“钩子” WH_GETMESSAGE Hook :接收消息投递的“钩子” WH_JOURNALPLAYBACK Hook :回放以前通过WH_JOURNALRECORD“钩子”记录的输入消息 WH_JOURNALRECORD Hook :输入消息记录“钩子” WH_KEYBOARD Hook :键盘消息“钩子” WH_MOUSE Hook :鼠标消息“钩子” WH_MSGFILTER :对话框、消息框、菜单或滚动条输入消息“钩子” WH_SYSMSGFILTER Hooks :系统消息“钩子” WH_SHELL Hook :外壳“钩子”
|
局部钩子:在自身进程中创建一个Hook,可以用来捕获自身进程中的消息
全局钩子:可以捕获操作系统下所有的指定的消息,需要借助于DLL来实现
全局钩子必须要使用DLL,DLL存放了钩子函数的代码。 在操作系统中安装了全局钩子后,只要进程收到可以发出钩子的消息后,全局钩子的DLL文件会被操作系统自动或强行地加载到该进程中。
局部钩子:
安装钩子:
参数 idHook:指示欲被安装的挂钩处理过程之类型
参数 lpfn:指向相应的挂钩处理过程
参数 hMod:指示了一个动态链接的句柄,该动态连接库包含了参数lpfn 所指向的挂钩处理过程
参数 dwThreadId:指示了一个线程标识符,挂钩处理过程与线程相关
与 SetWindowsHookEx
函数一起使用的应用程序定义或库定义的回调函数
参数1:挂钩过程用于确定如何处理消息的代码。
参数2:生成 击键 消息的密钥的虚拟密钥代码。
参数3:重复计数、扫描代码、扩展键标志、上下文代码、以前的键状态标志和转换状态标志。
创建一个进程:
HookTestDlg.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| HHOOK g_hHook; LRESULT CALLBACK MyKeyboardProc( int code, WPARAM wParam, LPARAM lParam ) { if (code < 0) { return CallNextHookEx(g_hHook, code, wParam, lParam); } CString strFmt; strFmt.Format("HT:%c", wParam); OutputDebugString(strFmt); return CallNextHookEx(g_hHook, code, wParam, lParam); }
void CHookTestDlg::OnBnClickedButton1() { g_hHook = SetWindowsHookEx( WH_KEYBOARD, MyKeyboardProc, NULL, GetCurrentThreadId() ); if (g_hHook == NULL) { AfxMessageBox("局部钩子安装失败"); }
}
|
HookTestDlg.h:
1 2 3 4 5
| protected: HICON m_hIcon; HHOOK m_hHook;
|
局部卸载:
参数 hhk:要移除的钩子的句柄,SetWindowsHookExA
的返回值
1 2 3 4 5
| void CHookTestDlg::OnBnClickedButton2() { UnhookWindowsHookEx(g_hHook); }
|
安装全局钩子和卸载:
添加Dll
dllmain.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include "pch.h"
HHOOK g_hHook; LRESULT CALLBACK MyKeyboardProc( int code, WPARAM wParam, LPARAM lParam ) { if (code < 0) { return CallNextHookEx(g_hHook, code, wParam, lParam); } char szBuff[MAXBYTE]; wsprintf(szBuff, "HT:%c", wParam); OutputDebugString(szBuff); return CallNextHookEx(g_hHook, code, wParam, lParam); }
__declspec(dllexport) BOOL InstallHook() { g_hHook = SetWindowsHookEx( WH_KEYBOARD, MyKeyboardProc, GetModuleHandle("HookDll"), 0 ); return g_hHook != NULL; }
__declspec(dllexport) VOID UnInstallHook() { UnhookWindowsHookEx(g_hHook); }
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
|
HookTestDlg.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| __declspec(dllimport) BOOL InstallHook(); __declspec(dllimport) VOID UnInstallHook(); #pragma comment(lib,"./x64/Debug/HookDll.lib")
void CHookTestDlg::OnBnClickedButton3() { if (!InstallHook()) { AfxMessageBox("安装全局钩子失败"); } } void CHookTestDlg::OnBnClickedButton4() { UnInstallHook(); }
|
服务 - Service
打开服务管理器:
SC :用来与服务控制管理器和服务进行通信的命令行程序
创建一个MFC的进程:
OpenSCManager
与指定计算机上的服务控制管理器建立连接,并打开指定的服务控制管理器数据库
参数 lpMachineName:目标计算机的名称。
参数lpDatabaseName:服务控制管理器数据库的名称。
参数dwDesiredAccess:对服务控制管理器的访问。
创建服务:
创建服务对象并将其添加到指定的服务控制管理器数据库
参数hSCManager:服务控制管理器数据库的句柄
参数lpServiceName:要安装的服务的名称
参数lpDisplayName:用户界面程序用于标识服务的显示名称
参数 dwDesiredAccess:对服务的访问权限
参数dwServiceType:服务类型
参数dwStartType:服务启动选项
参数dwErrorControl:错误的严重性,以及此服务无法启动时采取的操作
参数lpBinaryPathName:服务二进制文件的完全限定路径
参数 lpLoadOrderGroup:此服务所属的加载排序组的名称
参数lpdwTagId:指向变量的指针,该变量接收在 lpLoadOrderGroup 参数中指定的组中唯一的标记值
参数lpDependencies:指向以 null 分隔的服务名称或加载排序组的双 null 终止数组的指针,系统必须在此服务之前启动这些名称
参数lpServiceStartName:运行服务的帐户的名称
参数lpPassword:lpServiceStartName 参数指定的帐户名的密码
创建一个控制台程序来写服务器:
1 2 3 4 5 6 7 8 9
|
#include <windows.h>
int main() { OutputDebugString( "Hello World!"); }
|
复制exe的路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
#include "pch.h" #include "framework.h" #include "SCP.h" #include "SCPDlg.h" #include "afxdialogex.h" #include<Windows.h>
#ifdef _DEBUG #define new DEBUG_NEW #endif
class CAboutDlg : public CDialogEx { public: CAboutDlg();
#ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif
protected: virtual void DoDataExchange(CDataExchange* pDX);
protected: DECLARE_MESSAGE_MAP() };
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { }
void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); }
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP()
CSCPDlg::CSCPDlg(CWnd* pParent ) : CDialogEx(IDD_SCP_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }
void CSCPDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); }
BEGIN_MESSAGE_MAP(CSCPDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CSCPDlg::OnBnClickedButton1) END_MESSAGE_MAP()
BOOL CSCPDlg::OnInitDialog() { CDialogEx::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } }
SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE);
return TRUE; }
void CSCPDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } }
void CSCPDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this);
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } }
HCURSOR CSCPDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); }
#include<winsvc.h> void CSCPDlg::OnBnClickedButton1() { SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCM == NULL) { AfxMessageBox("打开SCM失败"); return; } SC_HANDLE hService = CreateService( hSCM, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "C:\\vs\\Windows14\\MyService\\x64\\Release\\MyService.exe", NULL, NULL, NULL, NULL, NULL ); if (hService == NULL) { AfxMessageBox("创建服务失败"); return; } CloseServiceHandle(hService); CloseServiceHandle(hSCM); AfxMessageBox("创建服务成功"); }
|
运行结果:
如果服务已存在的话 就无法创建
但是启动服务是没有相应的
1:初始化所有的全局变量
2:注册Handler函数来处理对该服务的控制请求
3:执行初始化
4:初始化结束之后,调用SetServiceStatus将服务状态设置为SERVICE_RUNNING并指定服务准备接受的状态码
5:执行具体的任务,如果没有要执行的具体事务,将控制权返回给调用方
MyService.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
#include <windows.h>
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv ) { OutputDebugString("MSVC: ServiceMain Begin"); } int main() { OutputDebugString( "MSVC: Hello World!"); }
|
启动服务没有调用servicemain
调用servicemain
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
#include <windows.h>
char g_szServiceName[MAXBYTE] = { "myservice" }; VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv ) { OutputDebugString("MSVC: ServiceMain Begin"); } int main() { SERVICE_TABLE_ENTRY ste[] = { {g_szServiceName,ServiceMain}, {NULL,NULL} };
if (StartServiceCtrlDispatcher(ste)) { OutputDebugString("MSVC: StartServiceCtrlDispatcher sucess"); } else OutputDebugString("MSVC: StartServiceCtrlDispatcher failed"); }
|
设置服务运行的状态:
参数1:当前服务的状态信息结构的句柄
参数2:指向SERVICE_STATUS 结构的指针包含调用服务的最新状态信息
句柄获取:
参数1:由调用线程运行的服务的名称
参数2:指向要注册的处理程序函数的指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
#include <windows.h> char g_szServiceName[MAXBYTE] = { "myservice" }; SERVICE_STATUS_HANDLE g_hStatus = NULL; VOID WINAPI MyHandler(DWORD fdwControl) { SERVICE_STATUS ss = {}; ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ss.dwCurrentState = SERVICE_RUNNING; ss.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_STOP; switch (fdwControl) { case SERVICE_CONTROL_CONTINUE: OutputDebugString("MSVC: SERVICE_CONTROL_CONTINUE"); break; case SERVICE_CONTROL_PAUSE: OutputDebugString("MSVC: SERVICE_CONTROL_PAUSE"); ss.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_STOP: OutputDebugString("MSVC: SERVICE_CONTROL_STOP"); ss.dwCurrentState = SERVICE_STOPPED; default: break; } if (SetServiceStatus(g_hStatus, &ss)) { OutputDebugString("MSVC: SetServiceStatus success"); } else { OutputDebugString("MSVC: SetServiceStatus failed"); } } VOID WINAPI ServiceMain( DWORD dwArgc, LPTSTR* lpszArgv ) { OutputDebugString("MSVC: ServiceMain Begin"); g_hStatus = RegisterServiceCtrlHandler(g_szServiceName, MyHandler); if (g_hStatus == NULL) { OutputDebugString("MSVC: RegisterServiceCtrlHandler failed"); return; } SERVICE_STATUS ss = {}; ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ss.dwCurrentState = SERVICE_RUNNING; ss.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_STOP; if (SetServiceStatus(g_hStatus, &ss)) { OutputDebugString("MSVC: SetServiceStatus success"); } else { OutputDebugString("MSVC: SetServiceStatus failed"); } } int main() { OutputDebugString("MSVC: Hello World!"); SERVICE_TABLE_ENTRY ste[] = { {g_szServiceName, ServiceMain}, {NULL, NULL} }; if (StartServiceCtrlDispatcher(ste)) { OutputDebugString("MSVC: StartServiceCtrlDispatcher success"); } else { OutputDebugString("MSVC: StartServiceCtrlDispatcher failed"); } }
|
启动服务:
停止服务:
恢复服务:
删除服务:
1
| sc delete myservice(要删除的服务名称)
|