使用LoadLibrary后DllMain未被调用

12

我是一个C++初学者(3-4个月),正在尝试学习Windows Hooking。我遇到了一个关于DLL注入的错误,过了一会儿后我意识到我的DllMain没有被调用!我查看了StackOverflow上几乎所有的帖子,但仍然无法解决我的问题。我通过将一个变量初始化为5,在DllMain中将其更改为1,并在一个函数中输出该变量来发现这一问题。变量从未发生过变化。以下是代码:

int i = 5;

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved  )
{
    i=1;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        hDll  = (HINSTANCE) hModule;

        break;

    case DLL_THREAD_ATTACH:  break;
    case DLL_THREAD_DETACH:  break;
    case DLL_PROCESS_DETACH:  break;

    }

    return TRUE;
}

bool InstallHook(){
    cout << "INSTALLING HOOK... " << endl;
    cout << i << endl;
    hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) CBTProc, hDll, 0);
    return hHook != NULL;
}

这里是我加载DLL的代码...

typedef bool (*InstallHook)();
typedef void (*UninstallHook)();
InstallHook ih;
UninstallHook uh;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            uh();
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    // Bunch of code to initialize a simple window until this: 
    HINSTANCE hDll = LoadLibrary("e:\\projects\\DLL\\ToInject.dll");
    ih = (InstallHook)GetProcAddress(hDll, "InstallHook");
    uh = (UninstallHook)GetProcAddress(hDll, "UninstallHook");
    if (!ih()){
        cout << "SUCCESS" << endl;
    }else{
        cout << "FAILED" << endl;
    }
    // other stuff to create a window
    return Msg.wParam;
}

输出:

INSTALLING HOOK... 
5 // We can see here that the DLL never changed the value of i to 1.
SUCCESS
UNINSTALL HOOK...

2
为 DLL 项目记录链接器命令行。 - Hans Passant
请注意,DllMain 的第一个参数应该是 HINSTANCE 而不是 HANDLE,但由于它们都是 typedef void *,我不认为这可能会导致您的问题。DllMain 是否已被导出? - Harry Johnston
3个回答

9

按照以下步骤创建一个可工作的示例(针对 Visual Studio):

  • 创建一个新的控制台应用程序;
  • 检查 DLL;
  • 将以下内容放入 dllmain.cpp:

dllmain.cpp

// dllmain.cpp : Defines the entry point for the DLL application.

#include "stdafx.h"
#include <string>

std::string test = "not Loaded"; 

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    test = "loaded"; //You also change on this location the value of a variable
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        MessageBoxA(NULL,"test","test",NULL);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

extern "C" __declspec (dllexport) bool example()
{
    MessageBoxA(NULL,test.c_str(),"test",NULL);
    return true;
}
  • 编译代码,确保它在发布模式下;
  • 创建一个新的控制台应用程序;
  • 检查空项目;
  • 创建一个名为main.cpp的新文件;
  • 将以下内容复制到文件中:

Main.cpp

#include <windows.h>

typedef bool (*testFunction)();

testFunction dllFunction;

int main()
{

    HINSTANCE hDll = LoadLibraryA("example.dll");
    if(hDll)
    {
        dllFunction = (testFunction)GetProcAddress(hDll, "example");
        dllFunction();
    }

    return 0;
}
  • 构建项目,确保其处于发布模式;
  • 从控制台应用程序的发布文件夹中复制您创建的DLL;
  • 运行程序。

这里可以正常工作。我收到了一个带有“test”和一次带有“loaded”的 MessageBox。您可以将此代码与您的代码进行比较。希望您能找到问题所在。


谢谢您的回答。但是,那不幸地并没有解决我的问题。正如我们在我的第一篇帖子中所看到的,我没有问题访问我的函数InstallHook和UninstallHook。问题是我无法访问DllMain。根据msdn的说法:“如果指定的模块是尚未为调用进程加载的DLL,则系统将使用DLL_PROCESS_ATTACH值调用DLL的DllMain函数。”这对我不起作用:'(链接:link - Michael Villeneuve
奇怪,我的DLL主函数被调用了。我更新了答案,这样你就可以看到我的DllMain。 - Laurence

4
extern "C" BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved  )

如果您正在使用C++编译它,则必须在DllMain函数前面添加"extern"C" "。

2

Santi!!! 这是一段好老的代码,每当我对钩子有疑问时,我仍然会参考它 :) - Tony Thomas
谢谢,我会查看这个项目。我使用WinMain的原因是我想在窗口打开时测试我的钩子,因为我在另一个StackOverflow问题中读到有时你可能很难从控制台应用程序调试DllMain。但在此之前,所有内容都在我的主函数中,但结果是相同的。 - Michael Villeneuve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接