Object Oriented WinAPI hooks
Some time ago I was playing with a WH_GETMESSAGE message hook to
intercept any mouse and keyboard input. The hook was installed in several UI threads
controlled by different application modules. In order to install a message hook,
you issue the following code:
const HHOOK hHook = ::SetWindowsHookEx(WH_GETMESSAGE, &GetMsgProc, NULL, ::GetCurrentThreadId());
and your GetMsgProc looks like this one:
LRESULT CALLBACK GetMsgProc(int code, WPARAM wParam, LPARAM lParam)
{
// Extra work here...
return ::CallNextHookEx(NULL, code, wParam, lParam);
}
What if you need to pass control over to some object, invoke a member function?
Keep in mind that GetMsgProc is a free function (that doesn't receive
hook handle in its parameters). Therefore you can't use anything to map invocation
context to OOP world citizens. You could use a global object to overcome this issue,
but still you can't install more than one message hook with the same callback function.
So the only thing that can map to an object ... is the callback function itself. Hopefully, we are able to create that function on the fly, in memory:
struct IGetMessageHookTarget
{
virtual LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam)
{
return ::CallNextHookEx(NULL, code, wParam, lParam);
}
};
class GetMessageHook : IGetMessageHookTarget
{
static const size_t ProcSize = 18;
public:
GetMessageHook() {
BYTE getMsgProcBytes[ProcSize] =
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp,esp
0xA1, 0x00, 0x00, 0x00, 0x00, // mov eax,dword ptr ds:[this]
0xB9, 0x00, 0x00, 0x00, 0x00, // mov ecx,this
0x8B, 0x10, // mov edx,dword ptr [eax]
0x5D, // pop ebp
0xFF, 0xE2, // jmp edx
};
*reinterpret_cast<size_t *>(&getMsgProcBytes[4]) = reinterpret_cast<size_t>(this);
*reinterpret_cast<size_t *>(&getMsgProcBytes[4 + 1 + sizeof(size_t)]) = reinterpret_cast<size_t>(this);
const HANDLE hCurrentProcess = ::GetCurrentProcess();
_getMsgProcBytes = ::VirtualAllocEx(hCurrentProcess, NULL, ProcSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
CopyMemory(_getMsgProcBytes, getMsgProcBytes, sizeof(getMsgProcBytes));
::VirtualProtectEx(hCurrentProcess, _getMsgProcBytes, ProcSize, PAGE_EXECUTE, NULL);
_hHook = ::SetWindowsHookEx(WH_GETMESSAGE, reinterpret_cast<HOOKPROC>(_getMsgProcBytes), NULL, ::GetCurrentThreadId());
}
~GetMessageHook() {
::UnhookWindowsHookEx(_hHook);
::VirtualFreeEx(::GetCurrentProcess(), _getMsgProcBytes, ProcSize, MEM_RELEASE);
}
protected:
virtual LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam)
{
return ::CallNextHookEx(NULL, code, wParam, lParam);
}
private:
HHOOK _hHook;
LPVOID _getMsgProcBytes;
};
GetMessageHook constructor creates an in-memory code that passes
control over to GetMsgProc member function. Believe me - it works.
At least on x86.
2 коммент.:
Thanks for the good writeup. It actually was a enjoyment account it.
Look advanced to far brought agreeable from you! However, how could we keep in touch?
Also visit my webpage - GFI Norte
After checking out a handful of the blog articles on your site, I seriously appreciate your way of blogging.
I added it to my bookmark site list and will be checking back soon.
Please visit my website as well and let me know your opinion.
Feel free to visit my web-site iphone 5 release date uk
Отправить комментарий