
Hooks are a technology for intercepting function calls in foreign processes. Hooks, like any sufficiently powerful technology, can be used both for good purposes (sniffers, audio / video grabbers, extensions to the functionality of proprietary software, logging, bugfixing) and with malicious intent (Trojans, cracks, keyloggers). About hukah more than once wrote
on Habré and
not on Habré . But here's the trouble - for some reason, every article about hooks literally from the second paragraph begins to talk about the “virtual functions table”, the “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 - and so does four times. Therefore, we need an article that tells about the hooks easy. Under the cut 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. Let's, for example, make Firefox browser enter Habr when entering
Habr! In its header instead of what is written there now (and now there will be
"*** / Habrahabr - Mozilla Firefox" , where *** - varies depending on the section). Yes, I know that this can be done by editing the source Firefox, browser plugins, user scripts and a dozen more ways. But we will make it a hook for educational purposes.
Just a bit of theory
When you run any application, the operating system creates its process. Roughly speaking, the exe-file is copied into 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 (in the program folder and in the system folders) and loaded into process memory. Then it is determined exactly what functions of libraries the program uses and where they are located (in which library and where exactly in this library). A label is constructed of the form "SomeFunction1 () function - SomeLibrary1.dll library -% address_of_function_SomeFunction1 ()%". When the program needs to call this function, it will find the necessary library in its memory, count the necessary address and transfer control there.
')

The essence of hooking is to make the program believe that the function it needs is in a different place.

It is done this way - we are writing our own library SomeLibrary2.dll, which will contain our function SomeFunction2 (). Next, we load this library into the memory of someone else's process (in Windows there is a special function for this) and change the very label that I wrote about a little higher, so that it now contains the entry “SomeFunction1 () function - SomeLibrary2.dll library - % address_of_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 organized in Windows, how functions are called, how arguments are passed to them, etc. It's complicated. Well, in fact, not really, you can just do without it. If you need it, read some advanced article (or at least one of those listed at the beginning). We will go the other way - we use the ready-made Microsoft Detours library, which will do all the dirty work for us.
A few words about Microsoft Detours

Easy to learn and use.

Highly effective

Good documentation

Contains many examples in source

Developed by Microsoft - not bad "friends" with the OS

Free for research purposes and non-profit projects.

Does not require assembly knowledge

Is closed

Worth decent money for commercial use or x64 architecture
In general, I would advise starting the study of 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 complicated) libraries like
mhook , buy Detours or write your bike (for the last two decisions, you need very good reasons).
I wrote about how to get and how to collect Detours
here .
Tricky plan
- Understand what function to put the hook.
- Make your library with a function that will replace the original one and do the things we need.
- Install the 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 quite clearly hints to us that the window title can be set using the
SendMessage function — with the second parameter being the
WM_SETTEXT , and the text itself being passed as the second parameter. But there may be nuances:
- PostMessage or something else can be used instead of SendMessage.
- SendMessage may not be a function at all, but a macro referring to another function (later we will see that this is the case)
- Firefox, like some cross-platform applications, may not use Windows functions at all to draw standard window elements, using some native cross-platform GUI elements instead (fortunately, this is not true - but all of a sudden!)
So you need to check everything carefully. We will be helped by a wonderful free
API Monitor program. It allows you to join a specific process and see which functions it calls and with which parameters. You may have already guessed it - she does this with the help of hooks too. So run Firefox and API Monitor. First of all, in the Monitor API you need to specify a filter - which 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), choose too little - we will miss the right one. Therefore, you will have to think and choose only the group where the functions for working with Windows GUI elements are potentially located. Let's select the Graphics and Windows Application UI Development groups and in the Running Processes panel, double-click on our Firefox. From now on, the API Monitor in the panel on the right will show calls to all API functions and their parameters.
Go to Firefox, open Habr, wait for the title 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 - they can be hundreds of thousands in just a few seconds of monitoring. And we are still not watching everything. Yes, yes, this all really happens inside the innocuous opening of just one site in the browser! And you still complain that this couple of seconds is too long. :)

Find the function we need will help search the tab with the results of monitoring. We drive “WM_SETTEXT” into the search and make sure that there are really 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 install hooks, it is important to know the exact name of the function being replaced, and now we know it.
We make our library
1. Run Visual Studio.
2. Create a new project: File-> New-> Project. Type Visual C ++ -> Win32 -> Win32 Project. In the project creation dialog, specify the type “Dll”.
3. Open the dllmain.cpp file and write the following code there:
#include <windows.h> #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. Compile the project: Build -> Build Solution. At the output we get dll-ku (let it be called hooktest.dll)
Let's analyze the source. In 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 difficult row number 3, we just save the real pointer to the SendMessageW function in the TrueSendMessageW variable. We need this for two purposes:
- To call this function SendMessageW from our "fake".
- To restore the pointer to the real function at the moment when we want to remove the hook.
Next is our fake MySendMessageW function. It is extremely simple. If the WM_SETTEXT message is caught and there is a mention of Habr in its text, we replace it with our own. Otherwise, we work as a transparent proxy. Pay attention to the prefix
__declspec (dllexport) - 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 attaching the library to the process. Here, too, everything is simple. At the time of the attachment, we need to install the hooks, at the time of detailing - remove. The Detour library requires you to do this with transactions, and this makes sense - imagine what happens if several people want to put the hooks in one process at a time. The most important thing about this code is the string.
DetourAttach(&(PVOID&)TrueSendMessageW, MySendMessageW);
It is this process that makes the process “believe” that now instead of the real SendMessageW function, you need to call our MySendMessageW. For the sake of this line, everything was started. If anyone is interested, once I wrote an analogue of this function manually. With all the possible combinations of function types and architectures, it took me several weeks. You've just saved them - congratulations.
Set the hook
Microsoft Detours offers various options for installing hooks - we use the simplest. In the set of examples that come with the library, there is a withdll.exe program - 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 up 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.