任何挂钩功能的单一界面

时间:2017-05-14 23:23:16

标签: c++ windows hook dll-injection

我正在编写一个简单的Dll注入和挂钩程序,当我为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);
}

但是现在我需要编写一个函数来处理来自kernel32.dll的任何函数。这意味着除了名称和地址之外,我对功能一无所知。

我对调用约定有一点了解 - 函数参数按直接顺序推送(__stdcall),然后调用该函数。我试着编写一个如下所示的 __ declspec(裸)函数:

PVOID __declspec(naked) HookAnyFunction()
    {
        /* do something */

        __asm {
            mov ebx, [esp]
            add esp, 4
            call pfnFuncAddr
            sub esp, 4
            mov[esp], ebx
            ret
        }
    }

pfnFuncAddr - 是原始函数的地址。但它使用注入的Dll崩溃了一个应用程序。我猜我的代码会破坏堆栈或其他东西。我究竟做错了什么?希望我的解释是有道理的。

1 个答案:

答案 0 :(得分:3)

ebx不易变,你不能只是写它,你必须保存/恢复原始值。

编写通用挂钩函数会很困难,因为32位Windows ABI有3个调用约定; stdcall(callee清理堆栈),cdecl(调用者清理堆栈)和fastcall(寄存器中的前两个参数,但在公共API中没有使用太多)。

如果您只想记录函数调用,您可能会执行以下操作:

push esp
push pfnFuncAddr
call mylogger ; assumed to be stdcall in this case, it can also change the jump
jmp eax

FARPROC __stdcall mylogger(FARPROC function, SIZE_T stackaddress) { ...; return function; }(请记住esp已更改,因此如果要记录堆栈的内容,则必须将堆栈参数调整为8 + 4个字节。)如果您关心快速调用也必须推送寄存器,但通用记录器无法知道第一个参数是在堆栈上还是在寄存器中。