在 DLL 中控制代码的可能方法

Possible ways to control code in DLL

我正在做我的大学项目,但遇到了一个问题。 我的任务是编写一个程序和 .dll 来拦截来自 WinAPI 的调用。 例如,我启动我的程序,它应该使用 SetWindowsHookEx 将 .dll 注入到 PID 的任何进程中。我成功地为函数 CreateFile 完成了这个任务,但我需要为多个函数实现它,并允许用户通过命令行参数选择要拦截的函数。

在我的代码中,安装钩子时我定义了回调函数:

HINSTANCE hinst = LoadLibrary(L"ConsoleApplication1.dll");
HOOKPROC addr = (HOOKPROC)GetProcAddress(hinst, "meconnect");
HHOOK handle = SetWindowsHookEx(WH_KEYBOARD, addr, hinst, threadID);

但是这个启动回调函数只有三个参数CallNextHookEx(NULL, code, wParam, lParam),看来我们不能改变它们。

另一个问题是,当我们将 .dll 注入另一个进程时,我们只能 运行 来自 DLL_PROCESS_ATTACH 部分的任务,所以它不会 link 我们的程序,所以我们不能传递参数。

也许解决方案是创建一个临时文件并向其写入参数,然后从 .dll 中读取它,但我希望您能帮助我提供更优雅的解决方案。我将不胜感激任何帮助。

例如,您可以为每个挂钩使用单独的函数。

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        {
            SetWindowsHookEx(WH_CBT, CBTProc, (HINSTANCE) NULL, GetCurrentThreadId());
            SetWindowsHookEx(WH_CALLWNDPROCRET, CallWndRetProc, (HINSTANCE) NULL, GetCurrentThreadId());
            break;
        }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) 
{ 
    if (nCode < 0)
        return CallNextHookEx(___cbt_message_hookptr, nCode, wParam, lParam); 

    // your code here
    return CallNextHookEx(___cbt_message_hookptr, nCode, wParam, lParam); 
} 

LRESULT CALLBACK CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam) 
{ 
    if (nCode < 0)
        return CallNextHookEx(___callwndprocret_message_hookptr, nCode, wParam, lParam); 

    // your code here
    return CallNextHookEx(___callwndprocret_message_hookptr, nCode, wParam, lParam); 
} 

参考您的 DLL_PROCESS_ATTACH 问题,这是拦截进程与您的进程之间通信的常见问题。

我认为最好的解决方案是使用管道作为进程间通信机制,因为这是最简单和最优雅的解决方案。

我的建议是你应该从 DLL_PROCESS_ATTACH 启动另一个线程,它将通过管道从主应用程序接收命令以挂钩某些函数,它还将通过同一管道将截获的数据发送到你将在其中的主应用程序存档或显示此数据。

从截获进程通过管道发送消息的示例,假设您在另一端监听此数据:

LPTSTR lpszPipename = TEXT("\\.\pipe\payload_datapipe");
CHAR chReadBuf[1024];
DWORD cbRead = 0;
BOOL fResult;  

fResult = CallNamedPipe( 
    lpszPipename,          // pipe name 
    _Message,              // message to server 
    strlen(_Message),      // message length 
    chReadBuf,             // buffer to receive reply 
    sizeof(chReadBuf),     // size of read buffer 
    &cbRead,               // number of bytes read 
    NMPWAIT_NOWAIT);//NMPWAIT_WAIT_FOREVER); // wait;-) 

if (!fResult)
{
    return;
}

您可以在相关文档页面找到有关命名管道的更多信息。 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592%28v=vs.85%29.aspx