In-depth analysis of hooks and Dynamic Link Libraries

Source: Internet
Author: User

In-depth analysis of hooks and Dynamic Link Libraries
Ashao1981)

Download source code-22 KB

This article attempts to clarify many controversies over how to use and create hooks.

Note: If you only use hooks in your own processes, the following issues will not occur, only when you use system hooks.

The key issue lies in the address space. Any object (including variables) created by the code in the DLL function is owned by the thread or process that calls it. When a process loads a 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, also, copy the global data of the DLL to the process space. That is to say, the global data of the same DLL owned by each process is private. The DLL becomes a part of the process and runs as the process and uses the stack of the process. This means that the data will be reinitialized. Typically, they will be zero.

Someone suggested the address for storing data on the DLL. This is impossible. Someone opposed it? Well, this is not impossible, but it is impossible for any purpose. Even if you create a shared memory variable visible to all DLL instances, this variable has practical significance only in the process where it is stored. For all other processes, this is just a string of bits. If you try to use it as an address, this address is useless for the process blocked by the event, and even causes the program to crash.

This concept of separate address space is hard to grasp. Let me use an image to describe it.

Here we have three processes. Your process is displayed on the left. Dll contains code, data, and a shared data segment. Now, when the hook DLL executes an event interception on process A, the system automatically maps the DLL address to the private space of the process, that is, the virtual address space of the process, also, copy the global data of the DLL to the process space. Coincidentally, they will be migrated to the same virtual address as process. Process A has its own private copy data segment. In this case, process a sees either its own private data segment in "data, it is either unable to affect other processes (or affected by other processes !). The trouble here is that the shared data segment is displayed in red .) The same memory page is indicated in process a and process. Note, coincidentally, these memory pages appear on the same virtual address. If you debug your process and process a at the same time, and pay attention to the & something in the common data segment, and look at the same & something in process A, you will see the same data, even in the same address. If you use the debugger to change the value of & something, you may see that the program has changed the value of & something. You can go to another process and check it to see the new value that appears there.

Let's take a look at what will happen in process B. When the event is hooked in process B, the DLL is mapped. The code is moved to another address in process B. If you debug B in the process and pay attention to & something in the common areas, you will find that the & Something address is different, but the content of & something will be the same; the changes made to & Something content in your process or process A can be seen immediately in process B, even if process B is in another bucket, the attacker is fined #? I> This is in the same physical memory location ). When I mention coincidence, "coincidence" refers to being planned. Windows always tries to map DLL to the same virtual address, but it rarely works.

This means that if you store a pointer to the callback function in the DLL, but it may point to another address when running process a or process B. This also means that you cannot use MFC In the DLL -- it cannot be an extended mfc dll or mfc dll, because these DLL (Dynamic Link Library) will call the MFC function.

So where are the MFC functions? They are in your address space, not in the address space of 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 you ignore the entire C Runtime Library. Only use APIs. Use lstrcpy instead of strcpy or tcscpy, and use lstrcmp instead of strcmp or tcscmp.

How can I make your DLL communicate with its controlling server?

A solution uses the: postmessage or: sendmessage function. (I mentioned the call of the original API, not the call of MFC !) Whenever possible: postmessage is used, it is preferred to use: sendmessage. Otherwise, if your process stops unfortunately, because everyone is blocked in a: sendmessage that will never be returned, other processes will also stop, and then the entire system will stop.

You can also consider using information queues in the shared memory area, but that question is out of the scope of this article.

In: sendmessage or: postmessage, you cannot return a pointer (We will ignore the problem of returning a relative pointer into the shared memory area; that is beyond the scope of this article ). this is because the address indicated by any pointer you can use is either in the DLL or in the hooked process. (Process a or process B) Therefore, this pointer is completely useless in your process. You can only transmit the information in wparam or lparam to the address space.

I strongly recommend that you use the registered window message for this purpose. You can send messages to the message_map window and use the on_registered_message macro command here.

Now the key is to get the hwnd (handle) of the window ). Fortunately, this is easy.

The first thing you must do is create a common data segment. So we use the # pragma data_seg declaration. Use a memorable data segment name (it must be no longer than 8 characters ). I want to emphasize that the name is arbitrary. Here I use my own name. I found that if I use a name like. share or. SHR or. shrdata, others will think that the name has a special meaning. However, 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. variables declared in this range will be assigned to this data segment after initialization, assuming they are initialized. if not initialized, the variable is assigned to the default data segment, and # pragma does not work.

It seems that this will prevent you from using some C ++ objects in the common data segments, Because You Cannot initialize user-defined objects in C ++. This seems to be a fundamental limitation.

# Pragma comment Add the command line switch on the connector to the link step. You can enter the VC ++ project | set and change the connector command line.

You can reserve a window handle for a certain mechanism, for example

Void setwindow (hwnd W) {hwnd = W ;}

But more often it is as follows.

Sample: A mouse hook
Header file (myhook. h)

The setmyhook function and clearmyhook must be declared here. This is detailed in my other article. "The ultimate DLL header file ."

# Define uwm_mousehook_msg/
_ T ("umw_mousehook -"/
"{B30856F0-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;
Uint hwm_mousehook;
Hhook hook;

// Forward Declaration
Static lresult callback msghook (INT ncode, wparam, 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 was an error (never returned)
* Effect:
* Initializes the DLL.
**************************************** ************************/

Bool dllmain (hinstance hinst, DWORD reason, lpvoid reserved)
{
Switch (reason)
{/* Reason */
//************************************** ********
// Process_attach
//************************************** ********
Case dll_process_attach:
// Save the instance 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 unhooked the hook, unhook it as we unload
If (hwndserver! = NULL)
Clearmyhook (hwndserver );
Return true;
}/* Reason */
/*************************************** *************************
* Setmyhook
* Inputs:
* Hwnd: Window whose hook is to be set
* Result: bool
* True if the hook is properly set
* False if there was 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
* Server window.
**************************************** ************************/

_ Declspec (dllexport) bool winapi setmyhook (hwnd)
{
If (hwndserver! = NULL)
Return false;
Hook = setwindowshookex (
Wh_getmessage,
(Hookproc) msghook,
Hinstance,
0 );
If (Hook! = NULL)
{/* Success */
Hwndserver = hwnd;
Return true;
}/* Success */
Return false;
} // Setmyhook

/*************************************** *************************
* Clearmyhook
* Inputs:
* Hwnd: Window whose hook is to be cleared
* Result: bool
* True if the hook is properly unhooked
* False if you gave the wrong parameter
* Effect:
* Removes the hook that has been set.
**************************************** ************************/
_ Declspec (dllexport) bool clearmyhook (hwnd)
{
If (hwnd! = Hwndserver)
Return false;
Bool unhooked = unhookwindowshookex (Hook );
If (unhooked)
Hwndserver = NULL;
Return unhooked;
}
/*************************************** *************************
* Msghook
* Inputs:
* Int ncode: code value
* Wparam: Parameter
* Lparam: Parameter
* Result: lresult
*
* Effect:
* If the message is a mouse-move message, posts it back
* 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, lparam)
{
// If the value of ncode is <0, just pass it on and return 0
// This is required by the specification of hook handlers
If (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, we want to have y the parent that it has
// Occurred. Note the use of postmessage instead of sendmessage
If (MSG-> message = wm_mousemove |
MSG-> message = wm_ncmousemove)
Postmessage (hwndserver,
Uwm_mousemove,
0, 0 );

// Pass the message on to the next hook
Return callnexthookex (Hook, ncode,
Wparam, lparam );
} // Msghook
The server application
In the header file, add the following to the protected segment of the class:

Afx_msg lresult onmymousemove (wparam, lparam );
In the application file, add the following code to the front of the file.

Uint uwm_mousemove =: registerwindowmessage (uwm_mousemove_msg );
Add the following code in message_map:

// {Afx_msg comments:

On_registered_message (uwm_mousemove, onmymousemove)
In your application file, add the following function:

Lresult cmyclass: onmymousemove (wparam, lparam)
{
//... Do stuff here
Return 0;
}

The above is a small program I wrote. Since I spent N + 1st time on hook, I just gave it a good user interface. The cat stared at the mouse in the window. Be careful! When the mouse is close enough to the cat and it will catch the mouse!

You can download this project and create it. The real key is the DLL sub-project; other projects are just a foil. There are several other technologies used in this example, including various image technologies, clipcursor and setcapture usage, area selection, screen update, and so on ., Therefore, in addition to displaying the use of hook functions, it also has some value for beginners to master window style design programming.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.