I was doing with a so called \'seh hooking\'. Actually it changes permission of region of memory and catches the exception when it gets accessed, so it can hook the function.
Short answer:
Yes the single step flag is part of the x86 achitecture and also still implemented in windows 7 via the eflags component of the processor context.
I have managed to download your project and everything works fine without modifications on Windows 8 with UAC turned off. So it should work on Windows 7, too. When starting VEH Hooking Test.exe
it displays two message boxes, after each one I get MessageBoxA
console output, so the hook worked. Maybe try starting the program as admin on Windows 7?
Long answer:
SEH
stands for structured exception handling, but what you are describing sounds more like VEH
- vectored exception handling.
VEH hooking is a hooking method that is really damn slow, so it can't really be used in performance critical hooks, like graphics hook for example where your hooks hits multiple times per second. It is usually used for one time hooks. The purpose of VEH hooking is to be really stealthy. There is no memory written in someone elses code and you don't have to use debug registers.
The following is how I would implement it using c++.
First you have to register a vectored exceptionhandler. This is a global exception handler for the process. Every thrown exception that were unhandled and would fall through to the operating system will be caught by this handler.
PVOID pExHandler = AddVectoredExceptionHandler(1, VectoredHandler);
After this you should set the memory protection of the page where your HOOK_LOCATION
(the address to hook) is in. The new protection I'm using is PAGE_EXECUTE_READ|PAGE_GUARD
. A guarded page will cause an exception on access and will remove the guard protection after that automaticly. This exception will not be handled by anyone, so it will fall through to our vectored handler. After the exception is thrown, the page is accessible again. (see Creating Guard Pages)
Memory can only be protected in pages (usually 0x1000 bytes long). This is why we can't only protect the hook location and have the massive performance overhead.
DWORD orgProt;
VirtualProtect(HOOK_LOCATION, 1, PAGE_EXECUTE_READ|PAGE_GUARD, &orgProt);
Now for our exception handler. This is how it could look like:
LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS exc)
{
if (exc->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
{
// guard page exeption occured. guard page protection is gone now
if (HOOK_LOCATION == reinterpret_cast<long*>(exc->ContextRecord->Eip)) {
// hook location was hit! call any hook callbacks here
} else {
// hook was not hit and has to be refreshed. set single-step flag
exc->ContextRecord->EFlags |= 0x100;
}
return EXCEPTION_CONTINUE_EXECUTION;
}
if (exc->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)
{
// single-step exeption occured. single-step flag is cleared now
// set guard page protection
DWORD oldProt;
VirtualProtect(HOOK_LOCATION, 1, PAGE_EXECUTE_READ|PAGE_GUARD, &oldProt);
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
If code runs into the protected memory page, it will throw the guard page violation. We check if we were at the hook location. If we are everything is fine and we can call the hook callback. If we are not at the correct location we somehow need to reprotect the code, but if we would do it now, we could not advance and always get an exception on the same location and deadlock the application. So we set the processor single step flag.
Now when recieving the single step exception, we can set the guard protection again, because we advanced by one instruction. This is how we can always have the target page protected and not miss any hook hits.
The cost is two exceptions and one page protection per instruction that gets executed in the target page. Don't try to do this with a debugger attached. It will go crazy.
For an actual implementation you may need synchronisation objects to get rid of the hook without crashing the program and better hook managing.
I really like this clever mechanism and hope some people learned a bit about it.