控制DLL中代码的可能方法

时间:2015-05-18 16:26:25

标签: c++ c dll argument-passing dll-injection

我正在研究我的大学项目并遇到问题。 我的任务是编写一个程序和.dll来拦截来自WinAPI的调用。 例如,我启动我的程序,它应该使用SetWindowsHookEx通过PID将.dll注入任何进程。我成功地为函数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部分运行任务,因此它不会与我们的程序相关联,因此我们可以'通过我们的论点。

也许解决方案是创建一个临时文件并为其编写参数然后从.dll中读取它,但我希望你能帮助我找到更优雅的解决方案。我将不胜感激。

1 个答案:

答案 0 :(得分:2)

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

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问题的参考,拦截流程与流程之间的通信存在常见问题。

我认为最佳解决方案是使用Pipes作为进程间通信机制,这是最简单,最优雅的解决方案。

我的建议是你应该从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