Hook Technology 1 _ Injection

Source: Internet
Author: User

 

 

 

 

Intercept Win32 API calls

Indows developers have always been a very challenging topic. I admit that this is also a topic I am interested in. The hook mechanism uses an underlying technology to control the execution of specific code segments. It also provides an intuitive way to easily change the operating system's behavior without involving code. This is similar to some third-party products.
Many systems use existing Windows applications through the interception technology (spying techniques. An important purpose of interception is not only to provide more advanced functions for the application, but to complete debugging.
Unlike older operating systems (such as DOS and win3.xx), existing operating systems (such as winnt/2 K and Win9x) use mature mechanisms to separate the address spaces of various processes. This architecture provides real memory protection, so no application can destroy the address space belonging to other processes, not the operating system itself. This makes it very difficult to develop system-related hooks (system-aware hooks.
I am writing this article to discuss a simple and practical hook mechanism. It provides a simple interface to intercept different API calls. It also demonstrates some tips to help you develop your own spying system ). It also provides a series of methods to intercept Win32 APIs on Windows, such as Win2k/NT and Win98/ME (9x. To simplify my description, I didn't introduce Unicode-related content. However, you only need to make minor changes to the Code to support Unicode.

Spying of applications has many advantages:
1. Monitor API functions
This helps control API calls and allows developers to track application-specific "invisible" actions during API calls. It helps developers fully understand the details of the Program (comprehensive validation of parameters) and also helps to discover potential problems. For example, sometimes it can easily monitor resource leaks caused by Memory Management APIs.
2. debugging and Reverse Engineering
In addition to common debugging methods, API hooks are also a very popular debugging method. Many developers use hooks to differentiate the execution of different components and their associations. Therefore, it is also used to obtain information about binary executable files.
3. go deep into the operating system
Developers are usually keen to gain an in-depth understanding of the operating system and play the "Debugger" role. The hook mechanism is also a powerful technique used to decode undisclosed or unknown APIs.
4. extend existing functions
You can embed custom modules into external Windows applications to enhance the functions of the original functions, this requires the use of hooks to redirect the execution sequence of the original code (allowing the system to execute user-defined code during the execution of the original code), so as to expand the functions of the existing module. For example, many third-party software products do not follow the specified security rules but only meet the specific user needs. The interception application allows developers to add their own code before or after the original API execution. This helps change the behavior of compiled code.
Functional requirements for the interception system
Before implementing any form of API Interception System, you must consider it carefully. First, you need to decide whether to develop a hook for a single program or a global hook. For example, if you only want to intercept a program, you do not need to install a global hook. However, if you want to monitor all calls to terminateprocess () and writeprocessmemory, the only way is to use a global hook. The methods used depend on the specific environment and the problems to be solved.

Brief design of API Interception Architecture
Generally, the interception system consists of at least two parts: a hook server and a driver ). The hook server is used to inject the driver into the target process at the right time. It can also manage the driver, or even obtain the driver's working condition through the injection point. This design is rough, and obviously it does not involve all possible implementation methods. However, this can already describe the API Interception framework.

 

If you need to implement a specific hook architecture, consider the following points with caution:
A. What programs should I intercept?
B. How to inject DLL or application injection technology into the target process
C. What interception mechanism is used?
We hope that you can find the answer from the following chapters.

Injection Technology
1. Registry
To inject DLL to a process loaded with user32.dll, write the DLL name to the following registry key:
HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ windows \ appinit_dlls
The preceding table key values can contain single or group DLL names separated by commas (,) or spaces. According to the msdn document [Reference 7], all DLL contained in the preceding key value will be loaded by any windows application running in the current logon session. Interestingly, in fact, the loading process of these DLL is actually part of the initial process of USER32. USER32 reads the preceding key values and calls loadlibrary () for these DLL entries (). However, this method is only applicable to programs that load user32.dll. Another limitation is that this built-in mechanism is only applicable to windows2k/NT systems. This is a safe DLL injection method, but it has the following Disadvantages:
A. You must restart Windows to activate or cancel process injection.
B. The injected DLL is mapped only to the processes loaded with user32.dll. Therefore, this method cannot be injected into the console program at least, because they do not need to import USER32 functions at all.
C. On the other hand, it is impossible for the injector to control the injection process. That is to say, the DLL is injected into all gui programs, regardless of whether the injection party has such a requirement. When you only need to intercept a small number of programs, this will be redundant. For more information, see [Reference 2] "inject DLL using Registry ".

2. Global Windows Hook
Indeed, another popular DLL injection method comes from Windows hooks. Msdn points out that this hook is a trap added to the system message processing mechanism. Applications can install hooks to monitor message streams in the system and process messages before they arrive at a specific window.
According to the underlying requirements of the system, this global hook is generally implemented in DLL. The basic principle is that the hook callback process is called in the address space of the intercepted process. Install a hook by calling setjavaswhookex () and adding appropriate parameters. Once this global hook is installed, the operating system maps the DLL to the address space of the target process. At this time, the global variables in the DLL are limited to a single process and cannot be shared by the target process. Therefore, all variables to be shared should be placed in the shared data segment. An example is shown: the hook server registers a hook and injects it into the address space of a process named "application one" and "application two.

Figure 1
  
Each time setwindowshookex () is executed, the global hook is registered once. If everything is correct, the function returns the handle of the hook. The above handle will be used when calling callnexthookex () at the end of the custom hook callback process. After setwindowshookex () is successfully called, the operating system automatically injects the DLL into the address space of all processes that meet the requirements, but not necessarily immediately. The function body used to filter wh_getmessage is as follows:
//---------------------------------------------------------------------------
// Getmsgproc
//
// Filter function for the wh_getmessage-it's just a dummy Function
//---------------------------------------------------------------------------
Lresult callback getmsgproc (
Int code, // hook code
Wparam, // removal option
Lparam // message
)
...{
// We must pass the all messages on to callnexthookex.
Return: callnexthookex (sg_hgetmsghook, code, wparam, lparam );
}
Local hooks are loaded by multiple processes that do not share the same address space. For example, the hook handle sg_hgetmsghook is obtained by the setwindowshookex () function and used as a parameter for callnexthookex (). It must be used in the address space of each process. That is to say, the value of the handle must be shared by the client process and the interception server. Therefore, the hook handle should be placed in the shared data segment.
The following example calls # pragma data_seg () to compile the pre-processing Statement (using the shared data segment ). Here, I would like to remind you that variables in the shared data segment must be initialized, otherwise they will be placed in the default data segment, and the # pragma data_seg () statement will also become invalid.
//---------------------------------------------------------------------------
// Shared by all processes Variables
//---------------------------------------------------------------------------
# Pragma data_seg (". HKT ")
Hhook sg_hgetmsghook = NULL;
Bool sg_bhookinstalled = false;
// We get this from the application who CILS setwindowshookex ()'s wrapper
Hwnd sg_hwndserver = NULL;
# Pragma data_seg ()

At the same time, you should add the sections statement to the def file of the DLL, as shown below:
Sections
. HKT read write shared
Or use
# Pragma comment (linker, "/section:. HKT, RWS ")

Once the hook DLL is loaded to the address space of the target process, if you want to uninstall the hook, there is no other way to do this except to intercept the server to call the unhook?whookex () function or the client process to exit. When the interception server calls the unhookdomainwhookex () function, the operating system will scan a list that contains all processes loaded with Hook DLL. At this time, the operation system will (according to the number of processes in the list) decrease the lock count of the hook DLL accordingly. When this count is changed to 0, the DLL will be deleted from the address space of the corresponding process.
The following lists some of the advantages of the above method.
A. This mechanism is supported by winnt/2 K and 9x operating systems, and is expected to be supported by later versions of Windows.
B. Unlike the Registry injection mechanism, you can call unhookwindowshookex () to uninstall the hook when the server no longer needs hook DLL.
Although I think windows hooks are convenient and practical, they inevitably have the following Disadvantages:
A. Windows hooks significantly reduce Windows performance because they increase the overhead required by the system to process each message.
B. It is very troublesome to debug global hooks. However, if you run more than one VC ++ instance at the same time, you will find that such debugging is easier under complicated circumstances.
C. The last problem that cannot be ignored. This hook will affect the entire system. in a specific environment (There is a bug in the hook), restart the system to restore it.

3. Use the createremotethread () function to remotely inject DLL
This is my favorite injection method. Unfortunately, only nt and 2 k systems are supported. The unique feature of this function is that it can also be executed on Windows9X, but only returns NULL without any operation.
The remote injection DLL was invented by Jeffrey ritcher and is recorded in his article [Reference 9] "load your 32-bit DLL into another process's address space using injlib.
The basic principle is simple and clever. Any process can call loadlibrary () to dynamically load the DLL. The problem is, when we lack access to the sub-threads of the target (external) process, how can we force the external process to call this function as needed? The createremotethread () function is used here. It can generate threads remotely. Here is a tip -- and look at the prototype of the thread body function. Its pointer (type: lpthread_start_routine) is passed as a parameter to createremotethread ():
DWORD winapi threadproc (lpvoid lpparameter );
The following is the prototype of loadlibrary:
Hmodule winapi loadlibrary (lpctstr lpfilename );

They all have similarities. They all use the same winapi call convention, they all accept a parameter, and the return value length is the same. The comparison above tells us that loadlibrary () can be used as the thread body so that it can be executed after being generated by a remote thread. Next, let's look at the following sample code:
Hthread =: createremotethread (
Hprocessforhooking,
Null,
0,
Pfnloadlibrary,
"C: hooktool. dll ",
0,
Null );

Call getprocaddress () to obtain the address of loadlibrary. Cleverly, kernel32.dll is always mapped to the same location of the process address space. Therefore, the loadlibrary () address is always the same in each process. This ensures that the parameters received by createremotethread () are always a valid pointer.
We use the absolute path of DLL as the real parameter of the thread body function and convert it to the lpvoid type. When a remote thread runs, it will pass the dll path to the loadlibrary function ). These are all tips for using remote threads to inject DLL.
Therefore, you need to carefully consider whether to use createremotethread () for remote injection. Createremotethread () is called every time the program is injected to access the virtual address space of the target process. It first uses OpenProcess () to open the target process and passes the process_all_access flag as the real parameter, this gives the target process the highest access permission. In this case, OpenProcess () returns NULL for some low-ID processes. This is because, despite the use of the combined process ID, the context of the injection program has insufficient permissions to access the target process. After thinking for a moment, you will immediately find that this is actually necessary. All processes that are strictly restricted to access are part of the operating system, so common processes should not access them. What happens if some bugs suddenly attempt to terminate an operating system process? In order to avoid these problems on the operating system, the application process must have sufficient privileges to call the APIs that change the operating system behavior. OpenProcess () to access operating system resources (such as smss.exe, winlogon.exe, and services.exe), you must have the debug privilege level ). This is a very powerful function that provides a way to access operating system resources, which is usually restricted. It is difficult to adjust the process privilege level. You can describe the process as follows:
A. Use the access permission required at the target privileged level to open the process token (processs token)
B. To specify the privileged level name "sedebugprivilege", you must locate its local luid ing. Each privileged level is named and can be found in winnt. H of the Platform SDK.
C. Call the adjusttokenprovileges () function to adjust the process token so that the "sedebugprivilege" Privilege takes effect.
D. Disable the process tag handle obtained through the openprocesstoken () function.
For more information on changing the privilege level, refer to [Reference 10] "using privilege ".

4. BHO plug-in Injection
Sometimes we just want to inject custom code into Inernet explorer. Fortunately, Microsoft provides a simple and documented solution for such a demand-Browser Helper Object (BHO ). BHO is implemented using com dll. Once it is correctly registered, all COM components that implement the iobjectwithsite interface will be loaded with IE whenever it is loaded.

5. Microsoft Office plug-in
Similar to the BHO plug-in, if you want to inject user-defined code into Microsoft Office applications, you only need to use the advanced mechanism provided by Microsoft to implement the Office plug-in. Many out-of-the-box codes demonstrate how to implement such plug-ins.
Interception Mechanism
Injecting DLL into external processes is a key part of intercepting the system. It provides an excellent opportunity to control external thread activity. However, this is not enough to intercept API calls.
This section will give an overview of API Interception methods in the real world, focus on the key points of each method, and reveal their respective advantages and disadvantages.
The hooks used by the root data can be divided into two types: kernel-level and user-level. To better understand these two levels, you must master the relationship between the Win32 sub-system API and the internal API (native API. The location of hooks of different levels is explained, and the relationship between modules and their dependencies on Windows 2 k systems are described.

Figure 2
  
The main difference in implementation is that the kernel-level interception engine is implemented using the kernel mode driver, while user-level hooks are generally implemented using the user mode DLL.

1. NT kernel-level hooks

In kernel mode, there are several methods to intercept NT system services. The most popular methods are described in the articles mark russinovich and Bryce Cognos [Refer to 3] "Windows NT System-call hooking. The basic idea is to monitor the Interception Mechanism of NT system calls in user mode. This technology is very powerful. It provides a flexible method to intercept user thread requests before the system kernel processes them.
You can find the best design and implementation of the above mechanism in "unreceivented Windows 2000 secrets. In this book, Sven Schreiber explains how to build a kernel-level hook framework from scratch [Refer to 5].
Another comprehensive analysis and brilliant implementation comes from Prasad Dabak's [Reference 17] "untitled ented Windows NT ". Even so, all the above interception policies are beyond the scope of this article.
2. Win32 user-level hooks
A. Window subclass
This method applies to applications with different behaviors based on the implementation of different window procedures. To complete the preceding work (execute user-defined code by changing the window), you only need to call setwindowlongptr () for the specific window (), pass gwlp_wndproc and the pointer of the User-Defined window process as the real parameter. Once the User-Defined window process is established, the user-defined window process will be called every time windows sends messages to the target window.
The disadvantage of this mechanism is that the subclass is only valid within the boundaries of a specific process (the current process) boundaries. That is to say, an application cannot create a window subclass for Windows created by other processes.
Generally, this method applies to intercept applications through plug-ins, so that you can obtain the handle of the window to replace the window process.
For example, I have previously written a simple IE Plug-in (BHO), which replaces the floating menu of IE through the window subclass.
B. Proxy DLL (DLL Trojan)
Another simple way to intercept an API is to replace the original DLL of the application with a DLL with the same name and export symbol. It is easy to implement this technology by using function forwarders. Basically, the function export section is the export section at the DLL entrance, which represents the function call relationship between this module and other DLL.
You can simply use # pragma comment to complete the above work:
# Pragma comment (linker, "/export: dosomething = dllimpl. actuallydosomething ")
If you decide to use this method, you should handle compatibility issues between the old and new versions of the library. For more information, see [Reference 13a] "Export forwarding" and [Reference 2] "function forwarders ".

C. Code Overwriting)
Many function interception methods are based on code rewriting. One method is to rewrite the code by changing the target address of the Call Command. This method is difficult to use and prone to errors. The basic idea is to intercept all the call commands in the memory and replace the original function address with the address provided by the user.
Another method of code rewriting is more complicated. Simply put, the basic idea is to first locate the original API function address, and then use the JMP command to change the first few bytes of the function body to redirect to the User-Defined API function for execution. This method requires strong skill and involves a series of recovery and interception operations for each call. It should be pointed out that if the function is in the unblocked state (unhooked mode) and the function is being called, the next call to the function will not be blocked.
The main problem with the above method is that it conflicts with the thread rules in the multi-threaded environment.
Despite this, there are still some clever solutions, which solve some problems and provide a mature method that can basically implement API Interception. If you are interested in the above issues, you can view the detours solution [Refer to 12.

D. Use the debugger to intercept API calls.
Another alternative is to insert a breakpoint in the target function. However, this method also has some disadvantages. The main problem is that when a debugging exception is thrown (debugging exceptions), the execution of all sub-threads in the current application process will be suspended. You also need a debugging thread to handle this exception. Another problem is that when the debugging process (debugger) is completed, Windows closes the debugger.
E. Intercept API calls by changing the import Address Table
This technology was initially announced by Matt pietrek and later by Jeffrey ritcher ([Refer to 2] "Implementing API Interception through the import section of the operation module ") and John Robbins ([Refer to 4] "intercept import function. This is a powerful, simple, and easy-to-implement method that meets most of the requirements for running the interception system on winnt/2 K and 9X. This technology is based on the executable file structure of windows. To understand the working process of this method, you must be familiar with the PE file structure, which is an extension of the common file object format (coff. Matt pietrek details the PE format in [Reference 6] "Deep PE format" and [Reference 13a/B] "win32pe format deep perspective. I will give an overview of the PE format, aiming to let readers understand the idea of implementing API Interception through the import table operation.
Generally, the format of a PE binary file is organized, so it has code sections and data sections ), this is consistent with the format of the executable file in the memory. The PE file format consists of several sections. Each section maintains specific data and meets the specific requirements of the operating system program loader.
Note that the. idata section contains information about the import address table. This part of information is very important for a system that modifies the IAT to intercept API calls.

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.