在注入另一个进程时控制 dllmain() 调用的顺序

Controlling the order of dllmain() calls while being injected to another process

有没有办法以某种方式控制 DLL 的加载顺序?这主要与存在于 DllMain() 函数中时必须遵守的限制有关。

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
    {
        SHGetKnownFolderPath()
    }
    case DLL_PROCESS_DETACH:
    {
        DllMainProcessDetach(hinstDLL, lpReserved);
        return TRUE;
    }
    default:
        break;
    }

    return TRUE;
}

在那个特定的代码中,我使用 SHGetKnownFolderPath() 来检索某个目录,执行 SHGetKnownFolderPath 后,我得到以下调用堆栈:

反汇编堆栈代码后,我意识到有问题的调用是 Ole32 的 CoTaskMemAlloc() 函数。

所以我再次设置了另一个调试会话,只在 DllMain() 中调用了 1 个函数:CoTaskMemAlloc() 并反汇编了代码:

保存g_pMalloc地址的EAX寄存器为空,似乎没有被dllcrt初始化。

我认为您不能安全地调用 DllMain 中的 shell 函数。由于在 Windows.

中完成进程初始化的方式,有一长串你不能做的事情

你永远不应该在 DllMain:

中执行 following tasks
  • 调用 LoadLibraryLoadLibraryEx(直接或间接)。 这可能会导致死锁或崩溃。

  • 调用 GetStringTypeAGetStringTypeExGetStringTypeW(要么 直接或间接)。这可能会导致死锁或崩溃。

  • 与其他线程同步。这可能会导致死锁。获得一个 由正在等待的代码拥有的同步对象 获取加载程序锁。这可能会导致死锁。
  • 使用 CoInitializeEx 初始化 COM 线程。在某些情况下 条件下,此函数可以调用 LoadLibraryEx
  • 调用注册表函数。这些功能是在 Advapi32.dll。如果 Advapi32.dll 在您的 DLL 之前未初始化,则 DLL 可以访问未初始化的内存并导致进程崩溃。
  • 呼叫CreateProcess。创建进程可以加载另一个 DLL。
  • 呼叫ExitThread。在 DLL 分离期间退出线程会导致 加载程序锁再次获取,导致死锁或崩溃。
  • 呼叫CreateThread。如果你不这样做,创建一个线程可以工作 与其他线程同步,但有风险。
  • 创建命名管道或其他命名对象(仅限 Windows 2000)。在 Windows 2000,命名对象由终端服务提供 动态链接库。如果此 DLL 未初始化,则对该 DLL 的调用可能会导致 进程崩溃。
  • 使用来自动态C 运行-Time (CRT) 的内存管理功能。 如果未初始化 CRT DLL,调用这些函数可能会导致 崩溃的过程。
  • 调用 User32.dll 或 Gdi32.dll 中的函数。部分功能加载 另一个可能未初始化的 DLL。
  • 使用托管代码。

以下任务可以在 DllMain 内安全执行:

  • 在编译时初始化静态数据结构和成员。
  • 创建并初始化同步对象。
  • 分配内存并初始化动态数据结构(避免 上面列出的功能。)
  • 设置线程本地存储 (TLS)。
  • 打开、读取和写入文件。
  • 调用Kernel32.dll中的函数(列出的函数除外 多于)。
  • 将全局指针设置为NULL,推迟初始化 动态成员。在 Microsoft Windows Vista™ 中,您可以使用 一次性初始化函数,以确保代码块是 在多线程环境中只执行一次。