In-depth analysis of hooks and dynamic link libraries
2004-5-15 2:17:10 (Article Category: C )
Ashao1981 (translation) Download Source Code - 22 KB There are many disputes for how to use and create hooks, this article tries to clarify these issues. Note: If you just use the hook within your own process, there will be no one below, which occurs when you use the system hook. The key issue is that any objects (including variables) created by the code in the DLL function, all of which are created by it. When the process is loaded into the DLL, the operating system automatically maps the DLL address to the private space of the process, that is, the virtual address space of the process, and copying a copy of the global data of the DLL to the process space. That is to say, the same DLL of each process, is a private, DLL to become part of the process, executed by this process, using this process stack. This means that the data will be reinitialized. Typically, they will be zero. Some people suggested that the data is stored on the DLL. This is impossible. Is anyone opposed? Well, this is not impossible, but this is impossible to use it. Make you created a shared memory variable visible to all instances of the DLL, this variable is only actually meaningful in the process of storing it. For all other processes, this is just a string bit, and if you try to use it as an address, this address is completely useless or even cause the program to crash. This concept is a concept that is difficult to master. Let me use the picture to explain it.
We have three processes here. Your process is displayed on the left. There is code in the DLL, with data, and has a shared data segment. Now when the hook DLL executes an event interception of the process A, the system automatically maps the DLL address to the private space of the process, which is the virtual address space of the process, and copying a copy of the DLL global data to the process space. . Coincidentally, they will be moved to the same virtual address in process a. Process A has its own private copy data segment, then the process A sees it in "Data" or is either private, or it is impossible to affect other processes (or affected by other processes!). Here is shared Data segments (show red.) In your process and process A, the same memory page is indicated in your processes. Note, coincidentally, these memory pages appear on the same virtual address. If you debug your process and process A, and pay attention to the & sol in a common data segment, and see the same & Something in the process in the process, you will see the same data, even they are The same address. If you use the debugger to change, maybe you will see the programs change the value of & something, you can go to another process, check it, see the new value that appears there. Let's take a look at what happens in the process B. The DLL is mapped when the event is hooked in the process B. The code is moved to another address in the process in the process. If you debug in the process B, pay attention to & Something in a shared area, you will find that the address of & Something is different, but & Something content will be the same; in your process or the contents of & Something content in your process or process A Changing immediately can see in the process B, even if the process B is in another cavity, a penalty is a penalty, a penalty, ┛ #? I> This is in the same physical memory location). When I mentioned coincidence, "coincidence" refers to being planned; Windows always tries to map the DLL map into the same virtual address, it tries to do so, but it is very successful. This means that if you put a pointer to the callback function in the DLL, it may point to other addresses when you actually run the process a or process B. This also means that you will not be able to use MFC in the DLL - it cannot be an extended MFC DLL or MFC DLL because these DLLs (Dynamic Link Libraries) call MFC functions. So where is the MFC function? They are in your address space instead of the address space in the process a or process B! Because they may be written in Visual.basic, Java or other languages, you must write Straight-C DLL, and I suggest that you ignore the entire C Runtime Library., Just use the API. Use lstrcpy instead of strcpy or tcscpy, instead of strCMP or TCSCMP with lstrcmp, and so on. How to make your DLL communicate with your Controlling Server? A solution will use :: PostMessage or :: SendMessage function. (I mentioned here is the original API call, not MFC call!) Whenever possible: PostMessage, use it as much as possible to use: SendMessage. Otherwise, if your process is unfortunate, everyone is blocked in a never return :: SendMessage, other processes will stop, then the entire system stops.
You can also consider using the information queue in shared memory area, but that topic is outside this article. In: Z: SendMessage or :: PostMessage, you can't pass back a pointer (we will ignore the issue of passing a relative pointer to the shared memory area; that is also outside this article). This is because you can use Any address indicated by any pointer is either in the DLL or in the process of hook. (Process A or Process B) So in your process, this pointer is completely useless. You can only return the address space by the information in WPARAM or LPARAM. i I strongly recommends using the registered window message for this. You can send a message to the Message_Map window and use the ON_REGISTERED_MESSAGE macro here. Now the key is to get the HWnd (handle) of that window. Fortunately, this is easy. You must do the first thing to create a shared data segment. So we use the # pragma data_seg declaration. Use a good data segment name (it must be no longer than 8 characters). I want to emphasize the names anything, here I use my own name. I found that if I use a good name. SHARE or .shr or .shrdata, others will think that the name has special meaning. But I want to say NO. # Pragma Data_Seg (". Joe") Handle Hwnd = Null; # pragma DTA_SEG () # Pragma Comment (Linker, "/ Section: .joe, RWS") # Pragma declares a data segment, declared within this range The variable will be assigned to the data segment after initialization, assume that they initialize. If it is not initialized, the variable will be assigned to the default data segment, and # prgMA interacts. I look at it, this will prevent you from using some C objects in a common data segment, because you can't initialize the user-defined object in C . This seems to be an fundamental limit. # Pragma Comment Enables the connector to have command line switches to be displayed to the link step. You can enter the VC project | Settings and change the connector command line. You can book a mechanism to set a window handle, such as Void SetWindow (HWnd W) {hWnd = W;} but more often is the combination of the hook as shown below. Sample: a mouse hookheader file (myhook.h) Function setMYHOOK and ClearMyhook must be declared here. This is discussed in detail in my other article. "The Ultimate DLL Header File." # Define UWM_MouseHook_msg / _T ("UMW_MouseHook-" / "{b30856f
0-D3DD-11D4-A00B-006067718D04} ") Source file (myhook.cpp) #include" stdafx.h "#include" myhook.h "#pragma data_seg (". Joe ") hWnd hwndserver = null; #pragma data_seg () #pragma comment ( "linker, /section:.JOE,rws")HINSTANCE hInstance; UINT HWM_MOUSEHOOK; HHOOK hook; // Forward declarationstatic LRESULT CALLBACK msghook (int nCode, WPARAM wParam, LPARAM lParam); / **** *********************************************************** *********** DLLMAIN * INPUTS: * Hinstance Hinst: Instance Handle for the dll * DWord Reason: Reason For call * lpvoid reserved: ignored * result: BOOL * True if successful * false if there is an error (never returned) * Effect: * Initializes the dll. **** *********************************************************** ********* / BOOL DLLMAIN (Hinstance Hinst, DWord Reason) {switch (Reason) {/ * r * / // ********************* ****************************************** // process_attach // ****** ************************************************* Case DLL_Process_attach: // Save the insta nce handle because we need it to set the hook later hInstance = hInst; // This code initializes the hook notification message UWM_MOUSEHOOK = RegisterWindowMessage (UWM_MOUSEHOOK_MSG); return TRUE; // **************************************************** // Process_detach // ************************************************************* * Case DLL_PROCESS_DETACH: // if The Server Has Not unhat as we unload (hwndserver! = Null) clearmyhook; Return True ;
}} / * Reason * // *************************************************** ********************** SETMYHOK * INPUTS: * hWnd hwnd: Window Whose hook is to be set * result: Bool * True if the hook is properly set * false if there is an error, such as the hook already * being set * effect: * sets the hook for the specified window. * this sets a message-intercept hook (wh_getMessage) * If the setting is successful, the hwnd is set as the * Server window. ** *********************************************************** ************ / __ DECLSPEC (DLLEXPORT) BOOL WINAPI SETMYHOOK (HWND HWND) { IF (HWNDSERVER! = null) return false; hook = setWindowshookex ( wh_getimentage, (hookproc) msghook, hinstance, 0); IF (hook! = Null) {/ * access * / hwndserver = hwnd; return true; } / * success * / Return False; } // setMyhook / ************************************************************* ******************** Clearmyhook * Inputs: * hWnd hwnd: Wi NDOW whose hook is to be pas true if the hook is properly unhatless * false if you gave the wrong parameter * Effect: * Removes the hook That Has Been set. ** *********************************************************** ************ / __ DECLSPEC (DLLEXPORT) BOOL Clearmyhook (HWND HWND) {IF (hwnd! = hwndserver) Return False; Bool unhatked = unhookwindowshookex (hook); IF (unhooked) hWndServer = null; return unhat
} / ********************************************************* ***************** MSGHOOK * INPUTS: * Int ncode: code value * WPARAM WPARAM: Parameter * LParam LParam: parameter * Result: LRESULT ** Effect: * If the message is a mouse-move message, posts it back to * THE Server window with the mouse coordinates * NOTES: * This Must Be a callback function or it will not work! ******************************************************************* ****************************************** / Static Lresult Callback Msghook (int ncode, wparam wparam, lparam lparam) { // if the value of ncode is <0, Just Pass it on and return 0 // this is required by the specification of hook handlers (ncode <0) {/ * pass it on * / CallNexthooKex (Hook, Ncode, wparam, lparam); Return 0; } / * pass it on * / // read the document. Tion to Discover What WParam and LParam // Mean. for a wh_Message Hook, LParam is Specified As Being // A Pointer To a MSG Structure, So The Code Below Makes That // Structure Available lpmsg MSG = (LPMSG) LParam; // if IT IS A Mouse-Move Message, Either In The Client Area OR /// The Non-Client Area, Want To Notify The Parent That Has // Occurred. Note the user (msg-> message == wm_mousemove || msg-> message == wm_ncmousemove) POSTMESSAGE (HWNDSERVER, UWM_MOUSEMOVE, 0, 0); // Pass the Message on to the next hookreturn callnexthookex (hook, ncode, wparam, lparam );} // msghookThe Server Application In the header file, the following increases to the class: AFX_MSG LRESULT ONMYMOMOVE (WPARAM, LRESULT ONMYMOMOVE (WPARAM, LRESULT OnMYMOVE); In the Application file, add the following code to the front of the file.
UINT UWM_MOUSEMOVE = :: RegisterWindowMessage (UWM_MOUSEMOVE_MSG); in MESSAGE_MAP, increased following code // {AFX_MSG comments: ON_REGISTERED_MESSAGE (UWM_MOUSEMOVE, OnMyMouseMove) In your application file, add the following function: LRESULT CMyClass :: OnMyMouseMove (WPARAM, LPARAM) { // ... do stuff herereturn 0; } The above is a small program I wrote. Since I spent N 1st time for hooks, I simply give it a good user interface. The cat stared at the mouse within the window. Be careful! When the mouse is close to the cat and it will catch the mouse! You can download this project and build it. The real key is the DLL sub-project; others are all accompanying. Several other technologies are used in this example, including a wide variety of drawing techniques, ClipCursor and SetCapture usage, regional selection, screen updates, and more. Therefore, in addition to displaying the use of hook functions, there are also some value for primary programmers to master window style design.