I'm writing a simple Dll injection and hooking program, and everything was fine when I manually declared functions to hook like this for CreateFileA:
HANDLE WINAPI Hook_CreateFileA(
LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile
)
{
...
return CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
But now I need to write a function that handles any function from kernel32.dll, for example. It means that I don't know anything about function except its name and hence an address.
I know a little bit about calling convention - function parameters are pushed in straight order (__stdcall) and then the function is called. I tried to write a __declspec(naked) function that looks like this:
PVOID __declspec(naked) HookAnyFunction()
{
/* do something */
__asm {
mov ebx, [esp]
add esp, 4
call pfnFuncAddr
sub esp, 4
mov[esp], ebx
ret
}
}
pfnFuncAddr - is an address of the original function. But it crashes an application with injected Dll. I guess my code corrupts stack or something. What am I doing wrong? Hope my explanation makes sense.
ebx
is not volatile, you cannot just write to it, you have to save/restore the original value.
Writing a generic hook function is going to be hard because the 32-bit Windows ABI has 3 calling conventions; stdcall (callee cleans the stack), cdecl (caller cleans the stack) and fastcall (first two parameters in registers but it is not used much in the public API).
If you just want to log the function calls you could probably do something like this:
push esp
push pfnFuncAddr
call mylogger ; assumed to be stdcall in this case, it can also change the jump
jmp eax
and FARPROC __stdcall mylogger(FARPROC function, SIZE_T stackaddress) { ...; return function; }
(remember that esp
has changed so you have to adjust the stack parameter by 8+4 bytes if you want to log the contents of the stack.) If you care about fastcall you also have to push the registers but there is no way for a generic logger to know if the first parameters are on the stack or in registers.