This is the hard way of doing it: if your app is supposed to be running as Administrator on a pre-Vista Windows, you could get the address of the API via ::GetProcAddress()
, give yourself privileges to write to its memory page, and overwrite the beginning of the API's code with a "jmp
" assembly instruction jumping into the address of your override function. Make sure your overwrite function takes the same arguments and is declared as __cdecl
.
Expanded answer follows.
The "standard" technique for API hooking involves the following steps:
1: Inject your DLL into the target process
This is usually accomplished by first allocating memory in the target process for a string containing the name/path of your DLL (e.g. "MyHook.dll"), and then creating a remote thread in the target process whose entry point is kernel32::LoadLibraryA()
passing the name of your DLL as argument. This page has an implementation of this technique. You'll have to wrestle a bit with privileges, but it's guaranteed to work 100% on Windows XP and earlier OSes. I'm not sure about Vista and post-Vista, Address Space Layout Randomization might make this tricky.
2. Hook the API
Once your DLL is loaded into the target process, its DllMain()
will be executed automatically, giving you a chance to run anything you want in the target process. From within your DllMain
, use ::LoadLibraryA()
to get the HMODULE
of the library containing the API you want to hook (e.g. "user32.dll") and pass it to ::GetProcAddress()
together with the name of the API you want to hook (e.g. "MessageBeep") to get the address of the API itself. Eventaully give yourself privileges to write to that address' page, and overwrite the beginning of the API with a jmp
instruction jumping into your detour (i.e. into your "version" of the API to hook). Note that your detour needs to have the same signature and calling convention (usually _cdecl
) as the API you want to hook, or else monsters will be awakened.
As described here, this technique is somewhat destructive: you can't call back into the original API from the detour, as the original API has been modified to jump into yours and you'll end up with a very tight and nice infinite loop. There are many different techniques that would allow you to preserve and/or call back into the original API, one of which is hooking the ...A()
versions of the API and then calling into the ...W()
versions (most if not all of the ...A()
Windows API's convert ASCII strings into UNICODE strings and end up calling into their ...W()
counterparts).