我有一个使用 SetWindowsHookEx 注入(inject)其他进程的 DLL。在 DLL 中,我通过调用 GetModuleHandleEx 来增加模块的引用计数器,这样我就可以控制何时卸载模块。

此时,来自这两个 API 调用的模块引用计数“应该”为 2。当调用进程关闭时,它调用 UnhookWindowsHookEx ,将引用计数递减到 1。DLL 有一个线程等待一些事情,其中​​之一是调用 SetWindowsHookEx 的进程的句柄。当进程消失时,DLL 会进行一些清理、终止所有线程、清理内存和处理,然后调用 FreeLibraryAndExitThread 。这会减少计数器并卸载 DLL。

这是我的问题。有一些进程,尤其是那些没有 UI 的进程,其中 DLL 永远不会被卸载。我非常有信心我已经清理了一切。我知道我的线程都没有运行。

首先,如果您有任何故障排除提示来帮助找出原因,那将会很有帮助。否则,我正在考虑使用诸如 NtQueryInformationProcess 之类的 API 来获取模块地址并确认模块句柄计数实际上为零,然后调用 CreateRemoteThread 注入(inject)对 LdrUnloadDll 的调用以从进程内卸载模块地址。你对这种方法有什么想法?有人有任何示例代码吗?我很难找到如何获取模块句柄计数。

最佳答案

好的.. 开始.. 有很多方法可以从进程中获取模块信息。无证方式和“有证”方式。

结果(记录):

这是“记录”的方式..

#include <windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <sstream>


int strcompare(const char* One, const char* Two, bool CaseSensitive)
{
    #if defined _WIN32 || defined _WIN64
    return CaseSensitive ? strcmp(One, Two) : _stricmp(One, Two);
    #else
    return CaseSensitive ? strcmp(One, Two) : strcasecmp(One, Two);
    #endif
}

PROCESSENTRY32 GetProcessInfo(const char* ProcessName)
{
    void* hSnap = nullptr;
    PROCESSENTRY32 Proc32 = {0};

    if ((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE)
        return Proc32;

    Proc32.dwSize = sizeof(PROCESSENTRY32);
    while (Process32Next(hSnap, &Proc32))
    {
        if (!strcompare(ProcessName, Proc32.szExeFile, false))
        {
            CloseHandle(hSnap);
            return Proc32;
        }
    }
    CloseHandle(hSnap);
    Proc32 = { 0 };
    return Proc32;
}

MODULEENTRY32 GetModuleInfo(std::uint32_t ProcessID, const char* ModuleName)
{
    void* hSnap = nullptr;
    MODULEENTRY32 Mod32 = {0};

    if ((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID)) == INVALID_HANDLE_VALUE)
        return Mod32;

    Mod32.dwSize = sizeof(MODULEENTRY32);
    while (Module32Next(hSnap, &Mod32))
    {
        if (!strcompare(ModuleName, Mod32.szModule, false))
        {
            CloseHandle(hSnap);
            return Mod32;
        }
    }

    CloseHandle(hSnap);
    Mod32 = {0};
    return Mod32;
}

std::string ModuleInfoToString(MODULEENTRY32 Mod32)
{
    auto to_hex_string = [](std::size_t val, std::ios_base &(*f)(std::ios_base&)) -> std::string
    {
        std::stringstream oss;
        oss << std::hex << std::uppercase << val;
        return oss.str();
    };

    std::string str;
    str.append("  =======================================================\r\n");
    str.append("  Module Name:             ").append(Mod32.szModule).append("\r\n");
    str.append("  =======================================================\r\n\r\n");
    str.append("  Module Path:             ").append(Mod32.szExePath).append("\r\n");
    str.append("  Process ID:              ").append(std::to_string(Mod32.th32ProcessID).c_str()).append("\r\n");
    str.append("  Load Count (Global):     ").append(std::to_string(static_cast<int>(Mod32.GlblcntUsage != 0xFFFF ? Mod32.GlblcntUsage : -1)).c_str()).append("\r\n");
    str.append("  Load Count (Process):    ").append(std::to_string(static_cast<int>(Mod32.ProccntUsage != 0xFFFF ? Mod32.ProccntUsage : -1)).c_str()).append("\r\n");
    str.append("  Base Address:            0x").append(to_hex_string(reinterpret_cast<std::size_t>(Mod32.modBaseAddr), std::hex).c_str()).append("\r\n");
    str.append("  Base Size:               0x").append(to_hex_string(Mod32.modBaseSize, std::hex).c_str()).append("\r\n\r\n");
    str.append("  =======================================================\r\n");
    return str;
}

int main()
{
    PROCESSENTRY32 ProcessInfo = GetProcessInfo("notepad.exe");
    MODULEENTRY32 ME = GetModuleInfo(ProcessInfo.th32ProcessID, "uxtheme.dll");
    std::cout<<ModuleInfoToString(ME);
}

未记录的 API 的问题是我从来没有弄清楚为什么动态模块的负载计数总是“6”而静态模块的负载计数总是“-1”..因此,我不会发布它..

如果您只想要加载计数,最好不要使用未记录的 API。未记录的 API 的唯一优点是您可以使用它来“取消链接/隐藏”进程中的模块(就像病毒一样)。它会“取消链接/隐藏”它......而不是“卸载”它。这意味着您可以随时将其“重新链接”回流程的模块列表。

由于您只需要模块引用计数,因此我只包含了“文档化”的 API,它正是这样做的。

关于c++ - 卸载注入(inject)的 DLL,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25577117/

10-11 00:50