One,
Preamble is most
Windows developer, how to
Win32 system
The call of the API function interception has been a challenging topic, because this will be a comprehensive test for computer knowledge you have, especially some in today's use.
The knowledge is not commonly used in software development, which includes operating system principles, assembly language or even about machine instruction code (it is a bit horror, but this is the fact).
Currently used
WINDOWS operating system, like
Win 9X and
WIN NT / 2K provides a more robust mechanism to make the memory address space of each process are independent, that is, a valid memory address in a process is meaningless to another process. This memory protection measures greatly increase the stability of the system. However, this also makes system-level
The difficulty of the API interception work is also greatly increased.
Of course, I refer to it here is a relatively elegant interception method, and you will implement the code in memory in memory by modifying executables.
Dynamic interception of API calls; rather than using comparative violence, rewrite the machine code directly on the disk storage of executable files.
two,
API hook system general framework usually, we intercept
This process of the call of the API is called an installation
API hook (
API HOOK. One
The API hook has at least two modules: one is a hook server (
Hook Server) module, generally
EXE form; one is a hook drive (
Hook driver) module, generally
DLL form.
The server is primarily responsible for injecting the drive to the target process, making the drive in the address space of the target process, which is a key first. The driver is responsible for actual
API intercepts work in order to care
API function calls can do some work we need.
One more common
The example of the API hook is some of the high-time translation software (like Jinshan Words): screen scratches, it is mainly for some
The GDI function has intercepted and gets the strings in their input parameters and then displayed in your own window. In response to the two parts described above, we have the following two points. We need to focus on:
What kind of use
DLL injection technology
What kind of
API interception mechanism
three,
Injection technology
The address of each process in the Win32 system is independent of each other, so we cannot make effective modifications to the code of another process in a process. And you have to complete
This operation must be carried out in the work of the API hook. Therefore, we must take some unique means to make
The API hook (accurately the hook drive) can become part of the target process, with a larger possible modification of the target process data and code.
There is usually the following ways:
1. Use the registry if we prepare interception processes connected
User32.dll, that is, use
User32
API (general graphical interface apps in line with this condition), then you can simply put your hook drive
The name of the DLL is added as the value of the following registry:
HKEY_LOCAL_MACHINE / SOFTWARE / Microsoft / WindowsNT / CURRENTVERSION / Windows / Appinit_dlls value forms can be single
DLL file name, or a group
DLL file name, with a comma or space between adjacent names. All identified by this value
The DLL will be loaded when the eligible application is started. This is an operating system built-in mechanism, which is less dangerous relative to other ways, but it has some obvious shortcomings: this method is only available
NT / 2K operating system. Look at the name of the key, you should understand
In order to activate or stop the injection of the hook, you must restart
WINDOWS. This seems too inconvenient.
Can't use this method
User32 application injection
DLL, such as console applications
No matter whether it is needed, hooks
DLL will inject every one
GUI app, which will result in a decline in the performance of the entire system
2.
Establish system range
Windows hook wants to inject a process
DLL, a very common method is to build in standard
On the basis of Windows hooks.
Windows hooks are generally
DLL is implemented, this is a global
The basic requirements of the Windows hook, which is also in line with our needs. When we successfully call
After the SETWINDOWSHOKEX function, a type of message hook is installed in the system, which can be a process or all processes in the system. Once this type of message is generated in a process, the operating system will automatically put the hook.
The DLL image is in the address space of the process, so that the message callback function (in
Specified in the parameter of SETWINDOWSHOKEX, can be properly processed, here, of course, is of course not to process the message, so just put the message hook backwards in the message callback function, but we needed
The DLL has successfully injected the address space of the target process, so that follow-up work can be completed.
We know that in different processes
DLLs cannot be shared directly because they are active in different address spaces. In
Windows hook
In the DLL, there are some data, such as
Windows hook handle
Hhook, this is
Setwindowshookex function returns worth it, and as a parameter
CallNexthooKex function and
Used in the UnHookWindoShooKex function, obviously
SETWINDOWSHOKEX function process and use
The process of the CallNexthookex function is generally not the same process, so we must be able to make the handle in all address spaces, that is, its value must be in these hooks
The process hooks the process hooks is shared. In order to achieve this, we should store it in a shared data area.
in
We can use the pre-compilation instruction in VC
#pragma data_seg
Create a new segment in the DLL file, and
The properties of this paragraph are set to "in the DEF file"
", this has established a shared data segment. For use
Delphi people are not so lucky: there is no similar relatively simple method (maybe there, but I have not found). However, we can also use memory image technology to apply for the memory area that can be shared using a process, mainly using
CreateFilemapping and
MapViewOffile These two functions. This is a universal method that is suitable for all development languages, as long as it can use
Windows
API.
in
Borland
There is an instruction in the BCB
#pragma codeseg and
VC
#pragma data_seg is a bit similar, it should also play the same role, but I tried it, there is no effect, and
BCB's online help is also mentioned there, I don't know how to use it correctly. Once hook
After the DLL loads the address space that goes into the target process, it is not possible to stop working before we call UNHOOKWINDOWSHOKEX functions unless the target process is turned off.
This
There are two advantages in the DLL injection method:
This mechanism is
Win 9X / ME and
Win NT / 2K is supported, and it is expected to be supported in future versions.
hook
The DLL can be called by our initiative when it is not required.
UnHookWindowsHookex is uninstalled, which is convenient than the mechanism to use the registry, which is a fairly simple method, but it also has some obvious shortcomings:
First of all, we pay attention to it.
Windows hooks will reduce the performance of the entire system because it adds an additional time of the system in message processing.
Second, only when the target process is ready to accept some kind of message, the hook is
The DLL will be mapped to the address space of the process, and the hook can really start playing. So if we want to have a whole life cycle of some processes
The API call situation is monitored, and this method will obviously miss some
API call
3.
use
CreateremoteThread function In my opinion, this is a quite a good way, but unfortunately,
CreateRemoteThread This function can only be
Support in the Win NT / 2K system, although in
Win 9x this
The API can also be invoked by safe calls, but it does not do anything else to return an empty value. entire
The DLL injection process is very simple. We know that any process can be used
LoadLibrary is dynamically loaded
DLL. But the question is, how do we make the target process loading our hooks under our control
DLL (That is a hook drive)? Here there is one
API function
CreateRemoteThread, which can build and run a remote thread in a process.
Call the
The API needs to specify a thread function pointer as a parameter, the prototype of the thread function is as follows:
Function ThreadProc (LPPARAM: POINTER): DWORD; Let's take a look
LoadLibrary function prototype:
Function LoadLibrary (LPFileName: Pchar): hmodule; It can be seen that these two function prototypes are essentially identical (in fact, whether the return value is not the same, because we can't get the return value of the remote thread function), just The name is different, this same makes we can put it directly
LoadLibrary uses the thread function to use to load hooks in the target process
DLL.
Similar, when we need to unload hooks
DLL can also
Freelibrary is used as a thread function, shifting the hook in the target process.
DLL. Everything seems to be very simple and convenient. Call
GetProcAddress function, we can get
The address of the LoadLibrary function. due to
LoadLibrary is
The function in kernel32, and this system
The DLL mapping address is the same for each process, so
The same is true for the address of the LoadLibrary function. This will make sure we can pass the address of the function as a valid parameter to
CreateremoteThread is used.
AddrofloadLibrary: = getProcadDress (getModuleHandle ('
Kernel32.dll '
), '
LoadLibrary '
);
HREMOTETHREAD: = CreateremoteThread (HtargetProcess, NIL, 0, AddrofloadLibrary, Hookdllname, 0, NIL);
CreateRemoteThread, we need the handle of the target process as a parameter. When we use
When the OpenProcess function is to get the handle of the process, it is usually desirable to have a full access to this process, that is
Process_all_access is a logo opens a process. But for some system-level processes, it is obviously not possible, and only one empty handle (zero) can be returned. To do this, we must set itself to the privilege of the trial level, which will have the largest access rights, so that we can make some necessary operations for these system-level processes.
4.
by
Bho to inject
DLL Sometimes we want to inject
The object of the DLL is just
Internet Explorer. Fortunately,
The Windows operating system provides us with a simple archiving method (this guarantees its reliability) -
use
Browser Helper Objects
BHO). One
Bho is one
Dedicated in DLL
COM object, it mainly implements a
IObjectWithsite interface, and whenever
When I is running, it will automatically load all the interface.
COM object.
four,
Intercepting mechanism has two types in the system level of hook applications
The mechanism of API interception - the interception of the kernel and the user-level interception. The kernel hook is mainly implemented by a driver of a kernel mode. It is clear that its function should be stronger, can capture any details of the system activity, but the difficulty is also large, not within the scope of our exploration (especially for me This use
Delphi's person, has not been involved in this area, so it is impossible to discuss);
And user-level hooks are usually in ordinary
All in DLL
The API intercepted work, this is what we are now focusing on. Interception
The call of the API function, generally can have the following methods:
1.
proxy
DLL (Trojan Horse) an easy way to think is the same name
DLL replaces the original output we are ready to intercept
API
DLL. Of course agency
The DLL also outputs all functions as the original. If you think
Hundreds of functions may be output in the DLL, and we should understand that this method is not high. In addition, we have to consider
DLL version problem.
2. The method of rewriting execution code has many interception is based on the rewriting of executable code. One of them is changing
The function address used in the CALL instruction is a bit difficult, which is more prone to errors. Its basic idea is to retrieve all you have to intercept in memory.
API
Call instruction, then change the original address into the address of the function you provide.
Another method of rewriting another code is more complicated, and its main implementation step is to find the original
The address of the API function, then uses a few bytes starting with the function
JMP instructions (sometimes have to be used
INT instructions, make it
The call to the API function can turn to our own function call. This method is to involve a series of stacks and outstanding operations out of the bottom-up operation, clearly the knowledge of our assembly language and operating system. This method is similar to the infection mechanism of many viruses.
3. Intercepting another optional method as a debugger is to place a tested breakpoint in the target function, so that the process runs to the debug state. However, such some problems have also come, and more important is that the production of debugging will hang all the threads in the process. It also requires an additional debug module to process all exceptions, the entire process will run in debug state until it runs. 4. This method of rewriting the input address table is mainly due to now
Executable files used in the Windows system (including
EXE file and
Good structure of a DLL file -
PE file format (
Portable Executable file format, so it is quite robust and easy to travel. To understand how this method works, first of all you have
The PE file format has an understanding.
One
The structure of the PE file is roughly shown below:
general
The PE file is one beginning.
DOS program, when your program is not supported
When you run in Windows, it will display "
This Program Cannot Be Run in dos mode ", this warning statement, then this
The DOS file header begins to real
The PE file is content. The first is a period of saying "
Image_nt_header "data, which is much about
The message of the PE file, the end of this data is a
Data Directory's data sheet, can quickly locate some
Middle section of PE file (
Section) 's address. After this data, it is a ""
Image_section_Header "list, each of which describes information about a segment of the following sections. Next it is
The most important segment data in the PE file is stored in these segments, respectively.
In all these paragraphs, there is a known "
.idata segment (input data segment) is worthy of us to pay attention, including some input address tables (
IAT,
IMPORT Address Table) Data list. Each implicitly loaded
API
DLL has one
IAT and correspondence, one
The address of the API is also
One corresponds to IAT. When an application is loaded into the memory, for each
The API function call, the corresponding assembly instruction is generated:
JMP DWORD PTR [xxxxxxxx]
If
VC is used
_Delcspec (import), then the corresponding instructions become
Call DWORD PTR [xxxxxxx].
In any case, the above square bracket is always an address, pointing to an entry in the input address table, is a
DWORD, but it is this
DWORD is
The real address of the API function in memory. So we want to intercept one
The call of API, as long as it is simple
DWORD changed to our own function, then all about this
The API call will go to our own function, and the intercepting work will be successful. It should be noted here that the form of calling the custom function should be
The way the API calls, that is
STDCALL method, and
Delf in Delphi is
Pascal call mode, that is
Register mode, there is a big difference in the way of delivery of parameters.
In addition, the parameters of custom functions can be and originally
The API function is the same, but this is not necessary, and this will have some problems at some time, I will mention it later. So to intercept
The call of the API, first we have to get the address of the corresponding IAT. The system loads a process module into memory, actually
The PE file is almost unmounted to the address space of the process, and the module handle
HMODULE is actually the address of the module image in memory,
The address of some data items in the PE file is the offset relative to this address, so it is called a relative virtual address.
RVA,
Relative Virtual Address.
So we can
HMODULE starts, after a series of address offsets
IAT's address. But I have a simple way here, it uses an existing
API function
ImageDirectoryEntryTodata, it helps us in positioning
When IAT can take a few steps, save the offset address wrong, and go to the detour. But pure use
RVA from
HModule starts to position
The address of the IAT is actually not bother, and this is more helpful to
The structure of the PE file is understood. Above mentioned
The API function is
DBGHELP.DLL output (this is from
Win 2K has only begun, before this
ImageHLP.DLL is provided), detailed introduction to this function can be found
MSDN.
Find
After IAT, we only need to traverse it, find what we need.
API address, then use our own function address to overwrite it. A corresponding source code is given below:
Procedure redirectapicall; var importdesc: pimage_import_descriptor; firstthunk: pimage_thunk_data32; s: dword;
Begin
// Get an input to describe the first address of the structure list, each
DLL corresponds to one such structure
Importdesc: = ImageDirectoryEntryTodata (Pointer (HtargetModule), True, Image_Directory_ENTRY_IMPORT, SZ);
While Pointer (importdesc.name) <> nil do
Begin // Judgment is the required
DLL input description
IF stricomp (Pchar (Dllname), Pchar (HtargetModule ImportDesc.name) = 0 THEN BEGIN
//get
IAT's first address
Firstthunk: = pimage_thunk_data32 (HtargetModule ImportDesc.firstthunk);
While firstthunk.func <> NIL DO
Begin
if firstthunk.func = Olddressofapi Then
Begin
// Find a match
API address
......
//rewrite
API address
Break;
END;
Inc (firstthunk);
END;
END;
INC; ImportDesc
END;
END;
In the end, it is necessary to point out if we handle the hook.
DLL's exit target process, then call the function to call the function before exiting the original address, that is
The real address of the API, because once you
DLL exits, rewritten new address will point to a meaningless memory area, and then use it clearly an illegal operation.
Fives,
Replacement function writing
The front key is finished, one
The API hook is basically completed. However, there are some related things that need us to study, including how to do an alternative function.
Below is the step of doing an alternative function:
First of all, we don't lose general, we first assume that such an API function, its prototype is as follows:
Function SomeApi (Param1: Pchar; Param2: Integer): DWORD;
Then establish a function type with the same parameters and return values:
TYPE FUNCTYPE = Function (param1: pchar; param2: integer): DWORD;
Then we put
SomeApi function's address is stored
OldDress pointers. Then we can use the code for writing the function:
Function DummyFunc (param1: pchar; param2: integer): DWORD; begin ...
/ / Do some before calling
Result: = Functype (OldDress) (PARAM1, PARAM2);
// call the original
API function
......
/ / Do some of the calls after calling
END;
We will save the address of this function to
In Newaddress, then cover it with this address.
The address of the API. This time when the target process calls
When the API is actually called our own functions, we can do some operations, then call the original
The API function, the result is like anything. Of course, we can also change the input parameters, even shielded this
Call of API functions.
Although the above method is feasible, there is a significant shortcoming: the method of making this replacement function does not have versatility, only for a small number of functions. If only a few
The API wants to intercept, then it is only necessary to repeat it several times. But if you have a variety of
The API has to handle, their number of parameters and types, and the type of return value are different, or it is too efficient to use this method.
Indeed, the above given is just a simple and easier way to think, just a basic architecture of a replacement function. As I mentioned earlier, the replacement function is originally
The parameter type of the API function does not have to be the same. Generally, we can design a function that does not have a call parameter and has no return value, through certain skills, make it adapt to a variety of
The API function calls, but this requires you to have a certain understanding of the assembly language.
Let me talk about this in detail below.
First, let's take a look at the stack situation before being inside a function (here the function is called
STDCALL).
As can be seen from the example, the call parameters of the function are pressed into the stack in the order from the right to left (the stack is developed by the high-end to low-end), and it is also pressed into a function returned address. Before entering the function,
ESP is pointing to the return address. Therefore, we only need to
ESP 4 can get the call parameters of this function, and increase each parameter
4. In addition, when returning from the function, it is generally
The return value of the payment function is stored in EAX.
Understand the above knowledge, we can design a relatively universal replacement function, which uses it.
Delphi's inline assembly language features.
PROCEDURE DUMMYFUNC;
ASM Add ESP, 4 MOV EAX, ESP // Get the first parameter
MOV EAX, ESP 4 // Get the second parameters
......
/ / Do some processing, here to guarantee
ESP is restored after this
Call Olddress // Calling original
API function
......
/ / Do some other things
END;
Of course, this replacement function is still relatively simple, you can call some pure use
OP language write function or procedure to complete some more complex operations (if you use assembly to complete, then you can die), but you should be unified to stdcall how to call you, which makes them only Use the stack to deliver parameters, so you only need to master the changes in the stack. If you store the machine instructions corresponding to the above assembly code in a byte array, then use the address of the array as a function address, the effect is the same.
The above code is
Implementation in WIN 2K / XP & Delphi 6.0.
Six, postscript
Do one
The API hook is indeed not easy, especially for me.
Delphi people say, in order to solve a problem, often
OP,
C and assembly language information in Middle East Chase, find some unexpected things in the process of procedure, and yourself is a hand. However, I have finally made one.
The prototype of the API hook is still very happy, and the knowledge of computer systems has also mastered a lot, and it is not shallow. I just wanted to translate an article before writing this article.
Down's English information (URL is
Www.codeproject.com, the article name "
API Hook Revealed, the sample source code is used
VC is written, and there is a level of foreigners to admire foreigners, and the article is very depth, and each detail is very detailed).
However, if you turn over, I feel that I am a limited level. Although I understand it yourself, I don't know how to use Chinese to express it. So I have to think that I have used it. I can use some of them. In practice, the experience is experienced with the experience, but it has a little or not, but it is also a lot of time, and I have a lot of time (embarrassing, embarrassing!), I hope that the master should not laugh, please advise.