Hooking is Simple
Hooking is a technology for intercepting function calls in other processes. Hooking, as any other sufficiently powerful technology, can be used for both good (sniffers, audio/video grabbers, extension of the closed software functionality, logging and bug fixing) and bad deeds (Trojans, cracks, and keyloggers). Hooking has been described many times. But the trouble is that, somehow, each article on hooking starts telling in its second paragraph about the virtual functions table and memory architecture and asks to study huge junks of assembly code. Each formula in a text is known to reduce the number of readers by 50%, and such things — by 100%. That’s why there is a need in the article that will tell about hooking in a simple language. There is no assembler, no complicated terms, and only a score of a simple code in С++. If you wanted to learn hooking and didn’t know where to start, start with this article.
To better understand what we are doing, let’s set a real task. Say, let’s make Firefox write in its header Hi, Infopulse! instead of current text (now it’s Nearshore, Offshore software development Eastern Europe. IT outsourcing Ukraine. — Mozilla Firefox) when opening Infopulse site. Yes, I know that it can be done by editing the Firefox source codes, with browser plug-ins, user scripts and what not, but for the sake of learning we will hook it.
Small Bit of Theory
With an application being started, the OS creates its process. Roughly speaking, an .exe file is copied into the memory, then the libraries (.dll) required for running are determined (it’s written at the beginning of each .exe file), these libraries are searched (in the application or system folders) and uploaded into the process memory. Then it is determined which functions from the libraries are used by the application and where they are located (which library and place in it). A table like SomeFunction1() — SomeLibrary1.dll — %SomeFunction1()_address% is built. When the application wants to use the function, it finds the required library in its memory, finds the required address and passes control there.
The essence of hooking is to make the application believe that the required function is at a different address.
It’s done as follows: write your own library SomeLibrary2.dll with your own function (SomeFunction2). Then upload the library into the memory of the foreign process (Windows has a special function for it) and edit the table mentioned above so that it may contain the SomeFunction1() — SomeLibrary2.dll — %your_SomeFunction2()_address% line. To understand how to do all this manually, you should know loads of different stuff: Windows memory structure, functions naming, etc. It’s difficult but not really, you can simply do without it. If you need it, just read some advanced article. We’ll take a different route: we’ll use a ready-made library (Microsoft Detours) that will do all the dirty work for us.
Something about Microsoft Detours
- easy to learn and use
- rather efficient
- good documentation
- many examples in source codes
- developed by Microsoft: “OS-friendly”
- free for research and non-profit use
- does not require to know the assembler
- rather costly for commercial use or х64 architecture
In general, I’d recommend to start learning hooking with Detours — if it’s just for fun, then it will suffice: you will progress quickly and will like it. If hooking is needed for a serious project though, you’ll easily switch to free and open (but a bit more complicated) libraries like mhook, will buy Detours or will invent your own wheel (the last two cases require rather serious reasons).
- Understand which function to hook.
- Create your own library with the function to replace the original one and to do what is needed.
- Mount the hook (upload the library into the required process memory and index the required function).
Where to Hook
MSDN rather broadly hints that the window header can be set with the SendMessage function, at the same time the second attribute should set WM_SETTEXT, and the last should set the text itself. Yet, there are some “buts”:
- Instead of SendMessage, PostMessage or something else can be used.
- SendMessage can be anything but a function: a macros referring to some other function (later on we’ll see that this is the case).
- Firefox, like some other cross-platform application, can run without any Windows functions for creating window standard elements using instead its own cross-platform GUI (fortunately, it’s not so, but who knows!)
So, all needs to be properly checked. A marvelous free application API Monitor will come in handy. It allows peeping into a process to see the functions it calls and their attributes. You might have guessed that it’s also done with the help of hooking. So, start Firefox and API Monitor. To begin with, define filter settings in API Monitor: the group of functions to be monitored. With absolutely all functions chosen, the monitored application will run very slowly (and can completely hang up), and with too few chosen, the needed ones may be missed. That’s why, think and select only the group that may contain the functions working with GUI Windows. Let’s select Graphics and Windows Application UI Development and double click Firefox in the Running Processes toolbar. Now API Monitor will show calls to all API functions and their attributes in the right-hand panel.
Switch to Firefox, open infopulse.com, wait till the heading changes to the required one and then return to Api Monitor to stop monitoring. You will most probably be surprised at the number of functions called — they can count literally hundreds of thousands in a few seconds of monitoring, and we are not even close to monitoring all the functions. Oh yes, all this really happens when a simple web-page is opened in a browser! And you dare to complain that these few seconds last too long. :)
The required function can be found with the help of Search in the Monitoring Results tab. Enter WM_SETTEXT to find out that the SendMessageW function has really been called with this attribute — it is highly probable that this is the window heading setting function. (Note: if you need to use Unicode version, set the W at the end of the name SendMessageW). To set the hooks, the exact name of the substituted function is needed. After that change the name.
Create Your Own Library
Then goes the fake MySendMessageW function. It’s absolutely simple. In any WM_SETTEXT message containing Infopulse, the text will be replaced with our text. Otherwise, it works as a transparent proxy. Note the __declspec(dllexport) prefix, it is needed to enable other processes to be able to use this function.
The DllMain function is called by the OS in certain cases, e.g. when a library is attached to/detached from the process. All this is also simple. We need to mount hooks at the moment of attaching and dismount them when detaching. The Detour library requires it to be done in transactions, and it makes sense as you can imagine what would happen if a bunch of people wanted to hook one but the same process at the same time. The most important in this code is line
It is this line that makes the process “believe” that instead of the real SendMessageW function, our MySendMessageW function must be called. It is this function for which all this fuss was kicked up. If you ask, I once wrote a similar function manually. With all possible combinations of function types and architecture, it took me a couple of weeks. So, you have just saved them — congrats.
Setting the Hook
Microsoft Detours offers different hook setting options — we’ll use the simplest one. The samples set, complementary to the library, contains a withdll.exe application. It takes for attributes the path to the application and the library that can be uploaded into the memory of this application after it has been launched. All this is launched, say, in this way:
withdll.exe -d:hooktest.dll "C:\Program Files\Mozilla Firefox\firefox.exe"
Now we can open infopulse.com:
Hurrah! It works!
I wish you good luck in mastering hooks.