Chapter 24 WINDOWS Hook Function
In this lesson, we will learn how to use the WINDOWS hook function. The Windows hook function is very powerful, with it you can detect other processes and change the behavior of other processes.
Theory: The hook function of Windows can be considered one of the main features of Windows. With them, you can capture events you have in your own processes or other processes. With "hook", you can give Windows a callback function for handling or filtering events, which is called "hook function". When you have interested in interest, Windows will call this function. There are two types of hooks: topical and remote.
The local hook only hooks the event of your own process. Remote hooks can also hang an event that happens in other processes. There are two remote hooks:
Thread-based changes will capture events in other processes. Briefly, events that can be used to observe a particular thread in other processes will occur. The system range will capture event messages that will occur in all processes in the system. Installing the hook function will affect the performance of the system. The system hook monitors the system-wide events is particularly obvious. Because the system will call your hook function when processing all relevant events, so your system will slow down. So should be used with caution, and immediately uninstall it immediately. Also, since you can intercept the other process messages, once your hook functions have problems, you will affect other processes. Remember: Powerful features also means responsible when using.
Before using the hook function correctly, let's talk about the working principle of the hook function. When you create a hook, Windows will create a data structure in memory, which contains information about the hook, and then adds the structure to the existing hooks. The new hook will add to the old front. When an event occurs, if you installed a partial hook, the hook function in your process will be called. If it is a remote hook, the system must insert the hook function into the address space of other processes. To do this requires the hook function must be in a dynamic link library, so if you want to use the remote hook, you must put the hook The function is placed in the dynamic link library. Of course there are two exceptions: work log hooks and work logs play back hooks. The hook functions of these two hooks must be in the thread of the mounting hook. The reason is that these two hooks are used to monitor the comparative underlying hardware events. Since they are recorded and playback, all events are of course the order. So if you put the back function in the DLL, the input event is placed in several threads, so we cannot guarantee the correct order. Therefore, the solution is to put the hook function in a single thread, such as the thread of the hook.
There are 14 kinds of hooks, the following is the timing they are called:
WH_CALLWNDPROC when calling SendMessage WH_CALLWNDPROCRET When calling SendMessage returns WH_GETMESSAGE when calling GetMessage or PeekMessage WH_KEYBOARD when calling GetMessage or PeekMessage to query WM_KEYUP or WM_KEYDOWN from the message queue WH_MOUSE when calling GetMessage or PeekMessage to query mouse event from the message queue When the message is called GetMessage or PeekMessage to query the non-mouse, the keyboard message when the keyboard message is queried from the message team, the menu or scroll bar is handled when a message is handled. This hook is partial. It is designed for control objects with your own message processing. WH_SYSMSGFILTER and WH_MSGFILTER, just a system-wide WH_JournalRecord when Windows gets a message from the hard queue, WH_Journalplayback When an event is requested from the system's hardware input queue, WH_Shell When the Windows shell occurs, such as task strips need to be redrawn. Its button. WH_CBT When the computer-based training (CBT) event occurs when the wh_ForegroundIdle is used by Windows yourself, the general application rarely uses wh_debug to give the hook function. Now we know some basic theories. Now you start explaining how Install / uninstall a hook. To install a hook, you can call the SetWindowHooKex function. The prototype of this function is as follows:
SetWindowsHookex Proto HookType: DWORD, PHOOKPROC: DWORD, HINSTANCE: DWORD, ThreadId: DWORD
HookType is one of the values listed above, such as wh_mouse, wh_keyboard phookProc is the address of the hook function. If you are using a remote hook, you must put it in a DLL, otherwise put the instance handle of the Hinstance hook function in your own code. If it is a partial hook, the value is Null ThreadID is the ID number of the thread that you want to monitor after the hook function is installed. This parameter can determine whether the hook is partial or system range. If the value is null, the hook will be interpreted into a system range, then it can monitor all processes and their threads. If you specify a thread ID number in your own process, the hook is a partial hook. If the thread ID is an ID of a thread in another process, the hook is a global remote hook. There are two special circumstances: WH_JournalRecord and WH_JournalPlayback always represent partial system-wide hooks, which are partially, because they don't have to put them in a DLL. WH_SYSMSGFilter is always a remote hook within a system. In fact, it is similar to the Wh_Msgfilter hook. If you set the parameters ThreadID, they are exactly the same. If the function calls successfully, return the handle of the hook in EAX, otherwise return NULL. You must save this handle because we have to uninstall the hooks later.
To uninstall a hook, call UNHOOKWIDOKEX functions, which only one parameter is to uninstall the handle of the hook. If the call is successful, return a non-0 value in EAX, otherwise returns NULL.
Now you know how to install and uninstall a hook, then we will look at the hook function. .
As long as the message event type of the hook you install, Windows will call the hook function. For example, the hook you install is a wh_mouse type, then the hook function will be called as long as there is a mouse event. Regardless of the type of hook, the prototype of the hook function is the same regardless of your installation: HookProc Proto Ncode: DWORD, WPARAM: DWORD, LPARAM: DWORD
Ncode Specifies whether to handle this message wPARAM and LPARAM include additional messages for the message
HookProc can be seen as a placeholder of a function name. As long as the origin of the function is consistent, you can give this function to any name. As for several parameters and the specific meaning of the return value, the various types of hooks are different. for example:
WH_CallWndProc
Ncode can only be HC_Action, which represents a message sent to a window wParam if not 0, represents the message being sent LPARAM points to the pointer of CWPSTRUCT structure variable Return Value: Not used, return 0
WH_MOUSE
Ncode is hc_action or hc_noremove wparam contains an event message of the mouse LParam points to the MousehookTRUCT structure variable pointer Return Value: if not processed, return non-0 value
So you must query your Win32 API guide to get detailed definitions of the parameters of different types of hooks and their significance of their return values. There is also a problem here. Need to note: All hooks are string on one linked list, recently added hooks on the head of the linked list. When an event occurs, Windows will follow the order from the linked list to the linked list. So your hook function is responsible for transmitting the message to the hook function in the next chain. Of course, you can do this, but you'd better understand the reason why you do this. In most cases, it is best to pass the message event so that other hooks have the opportunity to obtain this news. Call the next hook function to call the function CallNexthooKex. The prototype of this function is as follows:
CallNexthookex Proto HHOOK: DWORD, NCODE: DWORD, WPARAM: DWORD, LPARAM: DWORD
HHOOK is your handle of your own hook function. The hook chain can be traversed by this handle. Ncode, WPARAM and LPARAM You just pass the incoming parameters to CallNexthookex.
Please note: For remote hooks, the hook function must be placed in the DLL, which will map from the DLL to other process space. When Windows maps DLLs to other process spaces, the data segment will not be mapped. Briefly, all processes only share the DLL code, as for the data segment, each process will have its own copy. This is a problem that is easily ignored. You may want to be sure that the values saved in the DLL can be shared between all the processes that map the DLL. Under normal circumstances, since each of the processes that map the DLL have their own data segments, in most cases, your program is working well. But the hook function is not the case. For hook functions, request DLL data segments must also be the same for all processes. This way you must set the data segment into shared, which can be implemented by the properties of the segment in the link switch. You can do this in Masm:
/ Section:
The predetermined paragraph name is .data, uninited segment name is .bss. `Join you want to write a DLL that contains the hook function, and you want to share the uninitial data segments in all processes, you have to do this:
Link /SECTION :.Bss, S / DLL / SUBSYSTEM: Windows ..........
S is a shared section representative.
Example: A total of two modules: one is the GUI section, the other is the DLL of the installation and unloading hook. ; ------------------------------------------- Main Program Code section ------------------------------------ .386 .Model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc include mousehook.inc includelib mousehook.lib includelib /masm32/lib/user32.lib includelib / masm32 / lib / kernel32.lib
WSPRINTFA Proto C: DWORD,: DWORD,: VARARG WSPRINTF TEXTEQU
.const IDD_MAINDLG EQU 101 IDC_CLASSNAME EQU 1000 IDC_Handle EQU 1001 IDC_WndProc EQU 1002 IDC_HOOK EQU 1004 IDC_EXIT EQU 1005 WM_Mousehook EQU WM_USER 6
DLGFunc Proto: DWORD,: DWORD,: DWORD,: DWORD
.DATA HOOKFLAG DD FALSE HOOKTEXT DB "& HOOK", 0 UnHooktext DB "& Unhook", 0 Template DB "% lx", 0
.DATA? HINSTANCE DD? HHOOK DD? CODE Start: Invoke GetModuleHandle, Null Mov Hinstance, Eax Invoke Dialogboxparam, Hinstance, IDD_MAINDLG, NULL, AddR Dlgfunc, Null Invoke EXIXITPROCESS, NULL
DLGFunc Proc HDLG: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD LOCAL HLIB: DWORD LOCAL BUFFER [128]: BYTE LOCAL BUFFER1 [128]: BYTE LOCAL RECT: Rect .IF UMSG == WM_Close .IF hookflag == TRUE invoke UninstallHook .endif invoke EndDialog, hDlg, NULL .elseif uMsg == WM_INITDIALOG invoke GetWindowRect, hDlg, addr rect invoke SetWindowPos, hDlg, HWND_TOPMOST, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW .elseif uMsg == WM_MOUSEHOOK invoke GetDlgItemText, hDlg, IDC_HANDLE, addr buffer1,128 invoke wsprintf, addr buffer, addr template, wParam invoke lstrcmpi, addr buffer, addr buffer1 .if eax! = 0 invoke SetDlgItemText, hDlg, IDC_HANDLE, addr buffer .endif invoke GetDlgItemText, hDlg, IDC_CLASSNAME, addr buffer1,128 invoke GetClassName, wParam, addr buffer, 128 invoke lstrcmpi, addr buffer, addr buffer1 .if eax! = 0 invoke SetDlgItemText, hDlg, IDC_ CLASSNAME, addr buffer .endif invoke GetDlgItemText, hDlg, IDC_WNDPROC, addr buffer1,128 invoke GetClassLong, wParam, GCL_WNDPROC invoke wsprintf, addr buffer, addr template, eax invoke lstrcmpi, addr buffer, addr buffer1 .if eax! = 0 invoke SetDlgItemText, hDlg, IDC_WNDPROC, addr buffer .endif .elseif uMsg == WM_COMMAND .if lParam! = 0 mov eax, wParam mov edx, eax shr edx, 16 .if dx == BN_CLICKED .if ax == IDC_EXIT invoke SendMessage, hDlg, WM_CLOSE , 0, 0 .else .IF hookflag ==
FALSE invoke InstallHook, hDlg .if eax! = NULL mov HookFlag, TRUE invoke SetDlgItemText, hDlg, IDC_HOOK, addr UnhookText .endif .else invoke UninstallHook invoke SetDlgItemText, hDlg, IDC_HOOK, addr HookText mov HookFlag, FALSE invoke SetDlgItemText, hDlg, IDC_CLASSNAME, NULL invoke SetDlgItemText, hDlg, IDC_HANDLE, NULL invoke SetDlgItemText, hDlg, IDC_WNDPROC, NULL .endif .endif .endif .endif .else mov eax, FALSE ret .endif mov eax, TRUE ret DlgFunc endpend start
; ------------------------------------------------- ---- DLL source code section ----------------------------------- .386. model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/kernel32.inc includelib /masm32/lib/kernel32.lib include /masm32/include/user32.inc includelib / masm32 / lib / User32.lib
.const WM_MouseHook Equ WM_USER 6
.DATA HINSTANCE DD 0
.DATA? HHOOK DD? HWND DD?
.code dllenTry Proc Hinst: Hinstance, Reason: DWORD, Reserved1: Dword .if realved1: dword .if realved1: dword .if realved1: dword .if realved1: dword .if realved1: dll_process_attach push hinst pop hinstance .ndif Mov EAX, TRUE RET DLLENTRY ENDP
MouseProc proc nCode: DWORD, wParam: DWORD, lParam: DWORD invoke CallNextHookEx, hHook, nCode, wParam, lParam mov edx, lParam assume edx: PTR MOUSEHOOKSTRUCT invoke WindowFromPoint, [edx] .pt.x, [edx] .pt.y invoke PostMessage, hWnd, WM_MOUSEHOOK, eax, 0 assume edx: nothing xor eax, eax ret MouseProc endpInstallHook proc hwnd: DWORD push hwnd pop hWnd invoke SetWindowsHookEx, WH_MOUSE, addr MouseProc, hInstance, NULL mov hHook, eax ret InstallHook endp
Uninstallhook Proc Invoke UnHookWindowshookex, HHOOK RET Uninstallhook Endp
End dllenTry
; -------------------------------------------- DLL Makefile file----------------------------------------------
Name = mousehook $ (name) .dll: $ (name) .Obj link /section: #bss, s / dll /def: $(Name ).def / subsystem: windows / libpath: C: / Masm / LIB $ Name) .Obj $ (name) .Obj: $ (name) .asm ML / C / COFF / CP $ (Name) .asm
Analysis: The main window of the application consists of three editing controls, which will display the address of the window class name, window handle, and window procedure where the current mouse cursor is located. There are two buttons: "hook" and "EIXT". When you press HOOK, the application will hook the event message entered by the mouse, which will turn "UnHook". When you slide the mouse button over a window, the relevant messages of the window will appear in the main window. When you press "UnHook", the application will uninstall the hook. The main window uses a dialog as its main window. It customizes a message WM_MouseHook to deliver messages between the main window and the DLL. When the main window receives the message, the WPARAM contains the handle of the window where the cursor is located. Of course this is what we do. I am doing this just for convenience. You can communicate between the main application and the DLL using your own method.
.IF hookflag == false Invoke Installhook, HDLG .IF Eax! = Null Mov Hookflag, True Invoke setdlgitemtext, HDLG, IDC_HOOK, ADDR UNHOOKTEXT .ENDIF
The app has a global variable, hookflag, which is used to monitor the status of the hook. If you install it to hook it is true, otherwise it is false. When the user presses the hook button, the application checks if the hook has been installed. If not yet, it will call the function installhook from the DLL to install it. Note We pass the handle of the main dialog to the DLL so this hook DLL can pass the WM_MouseHook message to the correct window. When the application is loaded, the hook DLL is simultaneously loaded. When the main program is loaded into the memory, the DLL is immediately loaded. The first statement of the DLL entry point function is executed before the first statement of the main program is executed. So when the master program is executed, the DLL has been initialized. We put into the following code at the mouthpiece: .IF REASON == DLL_Process_attach Push Hinst Pop Hinstance .endif
This segment code puts the DLL own instance handle to save it in a global variable. Since the entry point function is performed before all function calls, Hinstance is always valid. We put this variable in .DATA, so that every process has the value of one of its own variables. Because the mouse smell is stopped on one window, the hook DLL is mapped to the address space of the process. Add other DLLs that are added to the DLL default load, the hook DLL will be mapped to other addresses. Hinstance will be updated to other values. When the user presses the unHook and press HOOK, SETWINDOWSHOOKEX will be called again. This time, it will use the new address as an instance handle. In the example, this is wrong, the address of the DLL load is not changed. This hook will become a part, you can only hook the mouse event that happens in your window, which is hard to satisfy.
Installhook Proc HWnd: DWORD PUSH HWND POP HWND INVOKE SETWINDOWSHOKEX, WH_MOUSE, Addr Mouseproc, Hinstance, Null Mov HHOOK, EAX RET InstallHook Endp
The InstallHook function is very simple. It saves the passing window handle in hwnd to prepare. The SETWINDOWSHOKEX function is then called to install a mouse hook. The return value of this function is placed in the global variable hHOOK, and it will be used in UnHookWindowsHookex in the future. After calling SETWINDOWSHOKEX, the mouse hook starts working. Whenever a mouse event occurs, the MouseProc function will be called:
MouseProc proc nCode: DWORD, wParam: DWORD, lParam: DWORD invoke CallNextHookEx, hHook, nCode, wParam, lParam mov edx, lParam assume edx: PTR MOUSEHOOKSTRUCT invoke WindowFromPoint, [edx] .pt.x, [edx] .pt.y Invoke Postmessage, Hwnd, WM_Mousehook, EAX, 0 Assume Edx: Nothing Xor Eax, EAX RET MOUSEPROC ENDP
The hook function first calls the CallNextHooKex function to processes the mouse event by other hooks. Then, call the WindowFromPoint function to get the window handle at a given screen coordinate location. Note: We use LParam to point to Point member variables in the MousehookTRUCT structure variable as the current mouse position. Send the WM_MouseHook message to the main program when we call the PostMessage function. One thing you must remember is: Don't use the SendMessage function in the hook function, it will cause a deadlock. The definition of MouseHookstruct is as follows: MousehookStruct Struct DWORD PT POINT <> HWND DWORD? WhittestCode DWORD? DWEXTRAINFO DWORD? MousehookStruct Ends
PT is the screen position where the current mouse is located. HWnd is the handle of the window that receives the mouse message. Usually it is a window where the mouse is located, but if the window calls setCapture, the mouse input will go to this window. Because we don't have to use the member variables but use the WindowFromPoint function. WhitTestCode Specifies the HIT-TEST value, which gives more mouse position values. It specifies the part of the mouse in the window. For a full list of this value, refer to the WM_NCHITTEST message in the Win32 API guide. DWEXTRAINFO This value contains related information. General This value is set by the mouse_event function, you can call GetMessageExtrainfo to get.
When the main window receives the WM_MouseHook message, it queries the window with the window handle in the WPARAM parameter.
.elseif uMsg == WM_MOUSEHOOK invoke GetDlgItemText, hDlg, IDC_HANDLE, addr buffer1,128 invoke wsprintf, addr buffer, addr template, wParam invoke lstrcmpi, addr buffer, addr buffer1 .if eax! = 0 invoke SetDlgItemText, hDlg, IDC_HANDLE, addr buffer .endif invoke GetDlgItemText, hDlg, IDC_CLASSNAME, addr buffer1,128 invoke GetClassName, wParam, addr buffer, 128 invoke lstrcmpi, addr buffer, addr buffer1 .if eax! = 0 invoke SetDlgItemText, hDlg, IDC_CLASSNAME, addr buffer .endif invoke GetDlgItemText, hDlg, IDC_WNDPROC, addr buffer1,128 invoke GetClassLong, wParam, GCL_WNDPROC invoke wsprintf, addr buffer, addr template, eax invoke lstrcmpi, addr buffer, addr buffer1 .if eax! = 0 invoke SetDlgItemText, hDlg, IDC_WNDPROC, addr buffer .endif
In order to avoid the shake of the text, we put the text that is already in the middle of the midline and the contrast us we will display. If the same, you can ignore it. Get the class name to call getClassName, get the window process call getClasslong and passed into the GCL_WndProc flag, and then format them into text strings and put it in the relevant editing space. invoke UninstallHook invoke SetDlgItemText, hDlg, IDC_HOOK, addr HookText mov HookFlag, FALSE invoke SetDlgItemText, hDlg, IDC_CLASSNAME, NULL invoke SetDlgItemText, hDlg, IDC_HANDLE, NULL invoke SetDlgItemText, hDlg, IDC_WNDPROC, NULL
When the user presses UNHOOK, the main program is called the UninstallHook function in the DLL. This function calls the UnHookWindowsHooKex function. Then, it converts the text of the button back to "hook", and the value of hookflag is set to false and then clear the text in the edit control. The switch options for the linker are as follows:
Link /section :bss, s / dll /def: $ (Name ).def / subsystem: windows
It specifies the .bss segment as a shared segment so that all processes that map the DLL share uninitialized data segments. If you don't have to switch, the hook in your DLL can't work.