The Windows system is built on the event-driven mechanism, saying that the entire system is implemented through the transfer of messages. The hook is a very important system interface in the Windows system, which can intercept and process messages that are given to other applications to complete the functionality of common applications. The hook can monitor the various event messages in the system or process, intercept messages to the target window and proceed. In this way, we can install custom hooks in the system, monitor the occurrence of specific events in the system, complete specific features, such as intercepting keyboard, mouse input, screen tether, log monitoring, etc. It can be seen that many special and useful features can be achieved by hooks. Therefore, it is necessary for advanced programmers to master the programming method of the hook.
Type of hook
One. Classified by event, there are several common types
(1) Keyboard hooks and low-level keyboard hooks can monitor various keyboard messages.
(2) Mouse hooks and low-level mouse hooks can monitor various mouse messages.
(3) The hook hook can monitor various shell event messages. Such as startup and closing the app.
(4) The log hook can record the various event messages removed from the system message queue.
(5) Window Process Hook Monitor All messages from the system message queue to the target window.
In addition, there are some of the hooks of some particular events to us, and they are not listed in one by one.
The commonly used hook type is described below:
1, WH_CallWndProc and WH_CallWndProcret Hooks
Wh_callwndproc and wh_callwndprocret hooks allow you to monitor messages sent to the window process. The system calls the WH_CallWndProc Hook subsess before sending to the receiving window process, and calls wh_callwndpro after the window is handled in the window process
Cret Hook Surprise. The Wh_CallWndProcret Hook passes the pointer to the CWPRETSTRUCT structure, and then passes to the hook subsequence. The CWPRETSTRUCT structure contains the return value from the window process from the processing message, and also includes message parameters associated with this message.
2, WH_CBT HOOK
Before the following events, the system calls the WH_CBT HOOK subtext, including:
1. Activate, build, destroy, minimize, maximize, move, change the size of window events such as sizes;
2. Complete system instructions;
3. Mobile mouse, keyboard events from the system message queue;
4. Set the input focus event;
5. Synchronize the system message queue event.
The return value of the Hook subsidiary determines whether the system allows or prevents one of these operations.
3, WH_Debug hook
The system will call the WH_Debug hook subroutine before the HOOK subtext associated with other hooks in the system call system. You can use this hook to determine if the system is allowed to call the Hook subtrace associated with other hooks.
4, WH_ForegroundIdle Hook
When the front desk thread of the application is idle, you can use the WH_ForeGroundIdle Hook to perform low priority tasks. When the front desk thread of the application is about to become an idle state, the system calls the Wh_ForegroundIdle Hook subtrace.
5, WH_GetMessage Hook
The application uses the WH_GetMessage Hook to monitor the message returned from the GetMessage or PeekMessage function. You can use the WH_GetMessage Hook to monitor mouse and keyboard input, and other messages sent to the message queue.
6, WH_Journalplayback Hook HOOK
The Wh_Journalplayback Hook enables the application to insert a message to the system message queue. You can use this hook playback through the continuous mouse and keyboard events recorded by using WH_Journalrord Hook. As long as the WH_JournalPlayback Hook has been installed, normal mouse and keyboard events are invalid. Wh_journalplayback Hook is a global HOOK, it cannot be used like thread specific HOOK. WH_JournalPlayback Hook Returns a timeout value, this value tells the system how long (milliseconds) will be taken before processing the current message from the playback hook. This makes hooks to control the playback of real-time events. WH_JournalPlayback is System-Wide Local Hooks that will not be injected to any stroke location space. (Estimated button elf use this hook) 7, WH_JournalrRecord HOOK
WH_JournalRecord hook is used to monitor and record an input event. Typically, this Hook records continuous mouse and keyboard events, and then play back by using the Wh_Journalplayback Hook. Wh_JournalRecord Hook is a global hook, which cannot be used like thread specific HOOK. WH_JournalRecord is System-Wide Local Hooks that will not be injected to any stroke location space.
8, WH_Keyboard HOOK
In the application, the Wh_keyboard hook is used to monitor the WM_KEYDOWN AND WM_KEYUP message, which is returned by GetMessage or PeekMessage Function. You can use this hook to monitor the keyboard message input to the message queue.
9, wh_keyboard_ll hook
WH_KEYBOARD_LL HOOK Monitor Enter the keyboard message in the thread message queue.
10, WH_MOUSE HOOK
WH_MOUSE Hook monitors the mouse message returned from the GetMessage or PeekMessage function. Use this Hook monitor to enter mouse messages in the message queue.
11, WH_MOUSE_LL HOOK
WH_MOUSE_LL HOOK Monitor Enter the mouse message in the thread message queue.
12, WH_MSGFILTER and WH_SYSMSGFILTER HOOKS
Wh_msgfilter and wh_sysmsgfilter hooks allow us to monitor menus, scroll bars, message boxes, dialog messages and discover users to switch the window using the Alt Tab OR Alt ESC Combination key. The WH_MSGFilter Hook can only monitor messages that are passed to the menu, scroll bar, message box, and the message that is passed to the dialog established by an application that has an Hook subtertaine. WH_SYSMSGFILTER Hook Monitor all application messages. WH_MSGFILTER and WH_SYSMSGFILTER hooks allow us to filter messages during the mode cycle, which is equivalent to filtering messages in the main message loop. WH_MSGFILTER HOOK can be called directly by calling CallMSGFilter Function. By using this function, the application can use the same code to filter messages during the mode cycle, just like the main message cycle.
13, WH_SHELL HOOK
The shell application can use the WH_SHELL HOOK to receive important notifications. When the shell application is activated and when the top window is established or destroyed, the system calls the WH_Shell Hook subsess.
WH_SHELL has a total of 5 minutes:
1. As long as there is a top-level, the Unowned window is generated, works, or destroyed;
2. When Taskbar needs to redraw a button;
3. When the system needs to display a minimize form of a program of Taskbar; 4. When the current keyboard layout status changes;
5. When the user presses Ctrl ESC to perform Task Manager (or the same level).
According to conventions, both the shell application does not receive the WH_SHELL message. Therefore, before the application is able to receive the Wh_Shell message, the application must call the SystemParametersInfo Function to register itself.
The above is a 10 common HOOK type!
two. Classified according to the range of use, mainly threaded hooks and system hooks
(1) Thread hook monitors the event message of the specified thread.
(2) System hook monitoring event messages in all threads in the system. Because the system hook affects all applications in the system, the hook function must be placed in an independent dynamic link library (DLL)
in. This is the difference between system hooks and thread hooks.
A number of places that need to be explained:
(1) If you install both the thread hook and the system hook is installed for the same event, the system will automatically call the thread hook, then call the system hook.
(2) Multiple hook processing can be installed on the same event message, which form a hook chain. The hook information should be passed to the next hook function after the current hook processing ends. Moreover, the recently installed hooks are placed in the beginning of the chain, and the earliest installed hooks are finally added, and the control is obtained first.
(3) Hooks, especially system hooks, will consume message processing time and reduce system performance. The hook is installed only when necessary, and then uninstall it after use.
Write a hook program
The steps to write hook programs are divided into three steps: define hook functions, install hooks and unload hooks.
1. Define hook functions
The hook function is a special callback function. After the specific event of hook monitors, the system will call the hook function. The form of hook functions of different events is different. The prototype of the hook function is illustrated by the mouse hook function:
LResult Callback HookProc (int Ncode, WPARAM WPARAM, LPARAM LPARAM)
Parameters WPARAM and LPARAM include information of hooked messages, such as mouse positions, status, keyboard buttons, etc. Ncode contains information about the message itself, such as whether it is removed from the message queue.
Let's implement custom features in the hook function, then call the function callnexthookex. Pass the hook information to the next hook function of the hook chain. The prototype of CallNexThookex is as follows:
LResult Callnexthookex (Hhook HHK, Int Ncode, WPARAM WPARAM, LPARAM LPARAM)
The parameter hHK is a hook handle. NCODE, WPARAM, and LPARAM are hook functions.
Of course, it can also be discarded by directly returning True, blocking the passage of the message.
2. Install hook
When the program is initialized, the call function setWindowshookex is installed. Its function prototype is:
HHOOK SETWINDOWSHOKEX (Int IDHOOK, HOOKPROC LPFN, Instance Hmod, DWORD DWTHREADID)
Parameter IDHOOK represents the hook type, which is corresponding to the hook function type. For example, wh_keyboard indicates that the keyboard hook is installed, wh_mouse is represented by a mouse hook, and the like.
LPFN is the address of the hook function.
HMOD is the handle of the instance of the hook function. For thread hooks, this parameter is null; for the system hook, this parameter is the DLL handle where the hook function is located.
DWTHREADID Specifies the thread number of the thread monitored by the hook. For global hooks, this parameter is NULL. Setwindowshookex returns the installed hook handle.
3. Uninstall
When the hook is no longer used, you must uninstall it in time. Simply call function BOOL UnHookWindowsHookex (HHOOK HHK).
It is worth noting that the location of the hook function of the thread hook and the system hook has a big difference. Thread hooks are generally within the thread of current threads or current threads, and the system hook must be placed in a separate dynamic link library, and it is troublesome.
Programming example of thread hook:
A thread-level mouse hook is implemented in accordance with the methods described above. The hook tracks the location change information of the current window mouse. And output to the window.
(1) Using MFC in VC 6.0
AppWizard (exe) Generates a single document that does not use document / viewing Mousehook. Open the childview.cpp file and join the global variable:
Hhook hhook; // mouse hook handle
CPoint Point; // Mouse location information
Cchildview * pView;
// Output window pointer for mouse hook functions
Add the following code in cchildview :: onpaint ():
CPAINTDC DC (this);
Char Str [256];
Sprintf (STR, "X =% D, Y =% D", Point.x, Point.y);
// Construct string
Dc.TextOut (0, 0, str); // Display string
(2) Define global mouse hook functions in childview.cpp files.
LResult Callback MouseProc
(int Ncode, WPARAM WPARAM, LPARAM LPARAM)
{// is a mouse mobile message
IF (wparam == wm_mousemove || WPARAM
== WM_NCMOMOVE)
{
Point = ((mousehookstruct *) lparam) -> Pt;
// Take the mouse information
PView-> invalidate (); // Window Heavy Pictures
}
Return CallNexthookex (HHOOK, NCODE, WPARAM, LPARAM);
// Pass hook information
}
(3) Install the hook in the constructor of the CChildView class.
CChildview :: cchildview ()
{
PVIEW = this; // Get the output window pointer
HHOOK = SETWINDOWSHOKEX (Wh_Mouse, MouseProc, 0, getCurrentThreadId ());
}
(4) Uninstall the hook in the destructor of the CchildView class.
CchildView :: ~ cchildview ()
{
IF (hHOOK)
UnHookWindowsHookex (HHOOK);
}
System hook programming example:
Since the system hook is used to use the DLL, first introduce the characteristics of Win32 DLL:
Win32 DLL has a great difference from Win16 DLL, which is mainly determined by the design idea of the operating system. On the one hand, in the Win16 DLL in the process entry point function and the exit point function (libmain and WEP) are respectively implemented; in the Win32 DLL, it is implemented by the same function Dllmain. Whenever, when a process or thread is loaded and uninstalling the DLL, the function is called, and its prototype is Bool WinApi Dllmain.
(Hinstance Hinstdll, DWORD FDWREASON, LPVOID LPVRESERVED);, the first parameter represents the instance handle of the DLL; the third parameter system is preserved; here is the second parameter, it has four possible values: DLL_Process_attach ( Process Load), DLL_THREAD_ATTACH (thread load), DLL_THREAD_DETACH (thread uninstall), DLL_PROCESS_DETACH (process uninstall), can discriminate the value of the passing parameter in the DLLMAIN function, and the DLL is necessary according to different parameter values Initialization or cleanup work. For example, when a process is loaded into a DLL, the system assists the second parameter of the DLL is DLL_Process_attach, where you can initialize specific data based on this parameter. On the other hand, in the Win16 environment, all applications are in the same address space; and in the Win32 environment, all applications have their own private space, each process is independent, which reduces the application. Mutual influence, but also increased programming. Everyone knows that in the Win16 environment, the global data of the DLL is the same for each process loaded; in the Win32 environment, the situation has changed, and when the process is loaded, the system automatically The DLL address is mapped to the private space of the process, and a copy of the global data of the DLL is also copied to the process space, that is, the same DLL's global data owned by each process is not necessarily the same. of. Therefore, in the Win32 environment, you must share the data in multiple processes, you must make the necessary settings. That is, the data that needs to be shared is separated, placed in a separate data segment, and set the properties of the segment to sharing. There are three forms of MFC DLL in VC6 (available and inherited in this DLL) Alternative, ie Regular StaticLinked TO MFC DLL (Static Link MFC DLL) and Regular Using The Shared MFC DLL ( Standard Dynamic Link MFC DLL) and Extension MFC DLL (Extended MFC DLL). The first DLL is characterized by adding the MFC code used when compiling to the DLL, so there is no need to exist in other MFC dynamic link class libraries when using the program, but the space for the occupied disk is relatively large; second DLL The feature is that when running, dynamically link to the MFC class library, thereby reducing the occupation of space, but relies on the MFC dynamic link class library at runtime; these two DLLs can be used only by the MFC program or by Win32 program use. The third DLL is similar to the second, as an extension of the MFC class library, can only be used by the MFC program.
Let's talk about the implementation of global sharing data in VC6
In the main file, create a new data segment with #pragma data_seg and define shared data, which is:
#pragma data_seg ("SharedData")
HWND SharedWnd = NULL; // Share Data
#pragma data_seg ()
Only one data segment does not reach the purpose of sharing data, but also tell the compiler that the properties of this segment can achieve this (the effect is the same), one method is to add the following in the .def file. Statement: Setctions SharedData Read Write Shared
Another method is to add the following statement in the project setting link option:
/ Section: SharedData, RWS
Ok, preparing knowledge has been completed, let us start writing a global hook program!
Since the global hook function must be included in the dynamic link library, this example is implemented by two programs.
1. Create hook mousehook.dll
(1) Select MFC AppWizard (DLL) to create a project mousehook;
(2) Select the type of MFC EXTENSION DLL (shared MFC Copy);
(3) Since the VC5 does not have a ready-made hook class, create a mousehook.h file in the project directory, set the hook class:
Class AFX_EXT_CLASS CMOUSEHOOK: PUBLIC COBJECT
{
PUBLIC:
Cmousehook ();
// Trimming function of hook classes
~ Cmousehook ();
// Coloring function of hook
Bool StartHook (HWND HWND);
/ / Install the hook function
Bool stophook ();
Uninstall hook function
}
(4) Add to the #include "mousehook.h" statement at the top of the mousehook.app file;
(5) Join the global shared data variable:
#pragma data_seg ("MyData")
HWND GLHPREVTARWND = NULL;
// The window handle of the last mouse
HWND GLHDISPLAYWND = NULL;
/ / Display the handle of the target window title edit box
HHOOK GLHHOK = NULL;
// Installed Mouse Hook Handle
Hinstance glhinstance = null;
// DLL instance handle
#pragma data_seg ()
(6) Define segment attributes in the DEF file:
Sections
MyData Read Write Shared
(7) Add the statement to save the DLL instance handle in the dllmain function of the main file mousehook.cpp:
Dllmain (Hinstance Hinstance, DWORD DWREASON, LPVOID LPRESERVED)
{
/ / If you use the lpreserved parameter, remove the following line.
Unreferenced_Parameter (LPRESERVED);
IF (dwreason == DLL_PROCESS_ATTACH)
{
Trace0 ("Mousehook.dll Initializing! / N");
/ / Extended DLL only initialization
IF (! AFXINITEXTENSIONMODULE (MouseHookdll, Hinstance)
Return 0;
New cdynlinklibrary (mousehookdll);
// Add DLL to dynamic MFC class libraries
GLHINSTANCE = Hinstance;
// Insert Save DLL Equity Handle
}
Else IF (dwreason == dll_process_detach)
{
TRACE0 ("Mousehook.dll Terminating! / N");
/ / Terminate this link library to call it
AfxterMextensionModule; MouseHookdll;
}
Return 1;
}
(8) Specific implementation of member functions of class cmousehook:
Cmousehook :: cmousehook ()
// class constructor
{
}
Cmousehook :: ~ cmousehook ()
// classification function
{
Stophook ();
}
Bool Cmousehook :: StartHook (HWND HWND)
/ / Install the hook and set the reception display window handle
{
Bool Bresult = false;
GLHHOOK = SETWINDOWSHOKEX (Wh_Mouse, MouseProc, Glhinstance, 0);
IF (GLHHOOK! = NULL)
BRESULT = True;
GLHDISPLAYWND = HWND;
// Set the handle of the display target window title edit box
Return BRESULT;
}
Bool cmousehook :: stophook ()
// Uninstall the hook
{
Bool Bresult = false;
IF (GLHHOOK)
{
BRESULT = UnHookWindowsHookex (Glhhook);
IF (BRESULT)
{
GLHPREVTARWND = NULL;
GLHDISPLAYWND = NULL; // Clear variable
Glhhook = NULL;
}
}
Return BRESULT;
}
(9) Realization of hook functions:
LResult WinApi MouseProc (Int Ncode, WPARAM WPARAM, LPARAM LPARAM)
{
LPMouseHookStruct Pmousehook = (MousehookStruct Far *) LPARAM;
IF (ncode> = 0)
{
HWND GLHTARGETWND = PMousehook-> hwnd;
// Take the target window handle
HWND PARENTWND = GLHTARGETWND;
While (PARENTWND! = NULL)
{
GLHTARGETWND = PARENTWND;
PARENTWND = GetParent (GLHTARGETWND);
// Take the application main window handle
}
IF (GLHTARGETWND! = GLHPREVTARWND)
{
Char szcaption [100];
GetWindowText (GLHTARGETWND, SZCAPTION, 100);
// Take the target window title
IF (Iswindow (GLHDISPLAYWND))
SendMessage (GLHDISPLAYWND, WM_SETTEXT, 0, (LPAram) (LPCTSTSTR) SZCAPTION;
GLHPREVTARWND = GLHTARGETWND;
/ / Save the target window
}
}
Return CallNexthookex (Glhhook, Ncode, WPARAM, LPARAM);
// Continue to pass the message
}
(10) Compile the project to generate mousehook.dll.
2. Create a hook executable
(1) Create a project mouse with the MFC AppWizard (EXE);
(2) Select "Dialog Application" and press "Finish" button;
(3) Editing the dialog, delete the original two buttons, add a static text box and edit box, right-click the static text box, select "Properties" in the pop-up menu, set its title as "the mouse is located Window header ";
(4) Add to Mousehook.h in mouse.h. #Include "../ mousehook / mousehook.h";
(5) Add private data member to cmousedlg.h's cmousedlg class:
Cmousehook m_hook; // Add hook class as a data member
(6) Modify cmousedlg :: OnInitdialog () function: BOOL cmousedlg :: OnInitdialog ()
{
CDIALOG :: OnInitdialog ();
Assert (IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
Assert (IDM_AboutBox <0xF000);
CMenu * psysmenu = getSystemMenu (false);
IF (psysmenu! = NULL)
{
CSTRING STRABOUTMENU;
STRABOUTMENU.LOADSTRING (IDS_ABOUTBOX);
IF (! straboutmenu.isempty ())
{
Psysmenu-> appendmenu (mf_separator);
Psysmenu-> appendmenu (mf_string, idm_aboutbox, straboutmenu);
}
}
Seticon (M_Hicon, True); // set Big icon
Seticon (M_Hicon, False); // set small icon
// Todo: Add Extra Initialization Here
CWND * PWND = getdlgitem (idc_edit1);
// Terminal pointer to acquire the edit box
M_hook.starthook (pWnd-> getsafehwnd ());
/ / Acquire the window handle of the edit box and install the hook
Return True;
// Return True UnsS you set the focus to a control
}
(7) Link the DLL library, add ../mousehook/debug/mousehook.lib to the project settings link tab;
(8) Compiling the project to generate an executable;
(9) Copy the mousehook.dll to the ../mouse/debug directory;
(10) First run several executable, then run the mouse.exe program, move the mouse in different windows, and will display the title of the application main window in the mouse in the edit box in the Mouse.exe program window.
Ok, finally finished, tired, this is the introduction knowledge of the hook function, including thread hooks and global hooks, I hope the masters will finish the ax! thank you all!
. GetCurrentThreadId ()
Refers to this hook function to monitor the own program, how can this parameter definition if I want to monitor other specific programs? For example, I want to only monitor the MIR3 program, how to define the fourth parameter? Thank you! ]