Hooks are just
- Tutorial
Hooks are a technology for intercepting function calls in other people's processes. Hooks, like any sufficiently powerful technology, can be used both for good purposes (sniffers, audio / video grabbers, expanding the functionality of private software, logging, bug fixing) and with malicious intent (trojans, crack, keyloggers). About hooks more than once wrote both on Habr and not on Habr. But here’s the trouble - for some reason, every article about hooks starts from the second paragraph about the “virtual function table”, “memory architecture” and offers to study huge blocks of assembler code. It is known that each formula in the text reduces the number of readers by half, and such things are completely fourfold. Therefore, we need an article that tells about hooks simply. Under kat there is no assembler, no complicated terms and literally two dozen lines of very simple C ++ code. If you have long wanted to learn hooks, but did not know where to start, start with this article.
Real challenge
For a better understanding of what we are doing, we will set ourselves some real task. For example, let's make the Firefox browser write “Hello, Habr!” In its header when entering the Habr instead of what is written there now (and now it’s "*** / Habrahabr - Mozilla Firefox" , where *** - changes depending on the section). Yes, I know that this can be done by editing the sources of Firefox, browser plug-ins, user scripts and a dozen more ways. But we will do it with hooks for educational purposes.
Just a little theory
When you launch any application, the operating system creates its process. Roughly speaking, the exe file is copied to memory, then it is determined which libraries (dll files) it needs to work (this information is recorded at the beginning of each exe file), these libraries are searched for (in the program folder and in system folders) and loaded into the process memory. Then it is determined exactly what library functions the program uses and where they are located (in which library and where exactly in this library). A plate is built of the form “SomeFunction1 () function - SomeLibrary1.dll library -% function_address_SomeFunction1 ()%”. When the program needs to call this function, it will find the necessary library in its memory, count the desired address and transfer control there.
The essence of hooking is to make the program believe that the function it needs is in another place.
This is done in this way - we write our library SomeLibrary2.dll, in which our function SomeFunction2 () will be located. Next, we load this library into the memory of another process (in Windows there is a special function for this) and change the very label that I wrote about above so that it now contains the entry “SomeFunction1 () function - SomeLibrary2.dll library - % address_of our_function_SomeFunction2 ()% ". In order to understand how to manually do everything described in this paragraph, you need to know pretty well everything - how the memory is arranged in Windows, how functions are called, how arguments are passed to them, etc. It's complicated. Well, actually not really, you can just do without it. If you need it, read some advanced article (or at least one of those that are indicated at the beginning).
A few words about Microsoft Detours
Easy to learn and use
very effectively
Good documentation
contains many examples in the source code
developed for Microsoft - good "friends" with OS
Free for research purposes and non-commercial projects
do not require knowledge of assembler
Closed
worth decent money for commercial use or x64 architecture
Overall, I would I advised you to start learning hooks with Detours - if this is just your one-time entertainment, then this is quite enough, you will succeed quickly and you will like it. If you need hooks in a serious project, you can easily switch to free and open (but slightly more complex) libraries like mhook, buy Detours or write your bike (for the last two decisions you need very good reasons).
About where to get and how to assemble Detours I wrote here .
Tricky plan
- Understand what function to set the hook on.
- Create your own library with a function that will replace the original one and do the things we need.
- Set a hook (load the library into the memory of the desired process and rearrange the pointer to the function we need).
- PROFIT!
Where to put the hook
MSDN very clearly hints to us that the window title can be set with the SendMessage function - in this case , WM_SETTEXT should be passed as the second parameter , and the text itself should be the last. But there may be nuances:
- Instead of SendMessage, PostMessage or something else can be used.
- SendMessage may not be a function at all, but a macro referencing another function (we will see later that it is)
- Firefox, like some cross-platform applications, may not use the Windows functions at all to draw standard window elements, instead using some kind of cross-platform GUI elements (fortunately, this is not so - but all of a sudden!)
So you need to check everything thoroughly. The wonderful free API Monitor program will help us.. It allows you to join a specific process and spy on which functions it calls and with which parameters. You may have already guessed - she does this too with the help of hooks. So, launch Firefox and the Monitor API. First of all, you need to specify a filter in API Monitor - which particular group of functions we want to monitor. If we choose everything at all - the program under study will work very slowly (or maybe even freeze), we will choose too few - we will miss the necessary one. Therefore, you will have to think and choose only the group where the functions for working with elements of the Windows GUI can potentially be found. Let's select the Graphics and Windows Application UI Development groups and double-click on our Firefox in the Running Processes panel. From this moment, the API Monitor in the panel on the right will show the calls of all API functions and their parameters.
Go to Firefox, open the Habr, wait for the header to change to the desired one, and return to Api Monitor to stop monitoring. Most likely, you will be surprised at the number of functions called up - there can be hundreds of thousands of them in just a few seconds of monitoring. But we still do not follow everything. Yes, yes, it all really happens inside the innocuous opening of just one site in a browser! And you still complain that this couple of seconds is too long. :)
To find the function we need will help the search on the tab with the monitoring results. We drive “WM_SETTEXT” into the search and make sure that there are indeed calls to the SendMessageW function with this parameter - with high probability this is the setting of the window title. Pay attention to the “W” at the end of the function name - it means that its unicode version is used. To set hooks, it is important to know the exact name of the function to be replaced, and now we know it.
We make our library
1. Launch Visual Studio.
2. Create a new project: File-> New-> Project. Type Visual C ++ -> Win32 -> Win32 Project. In the dialog for creating a project, specify the type "Dll".
3. Open the dllmain.cpp file and write the following code there:
#include
#include "C:\Program Files\Microsoft Research\Detours Express 3.0\src\detours.h"
LRESULT (WINAPI * TrueSendMessageW)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) = SendMessageW;
__declspec(dllexport) LRESULT WINAPI MySendMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_SETTEXT && wcsstr((LPCTSTR)lParam, L"/ Хабрахабр - Mozilla Firefox") != NULL)
return TrueSendMessageW(hWnd, Msg, wParam, (LPARAM)L"Привет, Хабр!");
return TrueSendMessageW(hWnd, Msg, wParam, lParam);
}
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)TrueSendMessageW, MySendMessageW);
DetourTransactionCommit();
}
else if (dwReason == DLL_PROCESS_DETACH)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)TrueSendMessageW, MySendMessageW);
DetourTransactionCommit();
}
return TRUE;
}
4. Open the project properties and on the linker settings tab add the value “C: \ Program Files \ Microsoft Research \ Detours Express 3.0 \ lib.X86 \ detours.lib” to the Additional Dependencies field. Attention, your path may be different - depending on where you installed the Detours library.
5. We compile the project: Build -> Build Solution. At the output we get dll-ku (let it be called hooktest.dll)
Let's analyze the source. At the beginning, we include the Windows header files (to use the SendMessageW function) and Detours (to be able to set / remove hooks).
In the seemingly complicated line # 3, we just save the real pointer to the SendMessageW function in the TrueSendMessageW variable. We need this for two purposes:
- To call the real function SendMessageW from our "fake".
- To restore a pointer to a real function at the moment when we want to remove the hook.
Next comes our fake MySendMessageW function. She is extremely simple. If the message WM_SETTEXT came across and in its text there is a mention of Habr - replace it with your own. Otherwise, we work as a transparent proxy. Pay attention to the __declspec (dllexport) prefix - it is needed so that other processes can use this function.
The DllMain function is called by the operating system in certain cases - for example, at the moments of the library’s attachment / detachment to the process. Here, too, everything is simple. At the time of the attachment, we need to set hooks, at the time of the detach - remove. The Detour library requires you to do this with transactions, and it makes sense - imagine what will happen if several people want to put hooks in one process at once. The most important thing in this code is the line
DetourAttach(&(PVOID&)TrueSendMessageW, MySendMessageW);
It is she who makes the process "believe" that now instead of the real function SendMessageW you need to call our MySendMessageW. For the sake of this line, everything was started. If anyone is interested, I once wrote an analogue of this function manually. Given all the possible combinations of function types and architectures, it took me several weeks. You just saved them - congratulations.
Set the hook
Microsoft Detours offers various options for installing hooks - we will use the simplest one. The set of examples that come with the library includes the program withdll.exe - it takes as parameters the path to the application and the library that needs to be loaded into the memory of this application after it is launched. We start it all like this:
withdll.exe -d:hooktest.dll "C:\Program Files\Mozilla Firefox\firefox.exe"
PROFIT!
We open Habr:
Hurray, it works!
Success in learning hooks.