Unloading a nested DLL

I have a DLL that I am inserting into other processes using SetWindowsHookEx. Inside the DLL, I increment the module reference count by invoking GetModuleHandleExso that I can control when the module is unloaded.

At this point, the module reference count should be “2” of both of these API calls. When the calling process shuts down, it calls UnhookWindowsHookEx, reducing the number of links to 1. There is a thread in the DLL that waits for several things, one of which is a handle to the process that is called SetWindowsHookEx. When the process leaves, the DLL does some cleanup, terminates all threads, cleans up memory and processes, and then calls FreeLibraryAndExitThread. This decreases the counter, and the DLL is unloaded.

Here is my problem. There are several processes, especially without a user interface, where the DLL is never unloaded. I'm pretty sure that I cleaned everything. And I know that none of my threads work.

First of all, if you have troubleshooting tips to help uncover the cause, this will be helpful. Otherwise, I thought about using some kind of API, such as NtQueryInformationProcessto get the module address and confirm that the number of module handlers is actually zero, then call CreateRemoteThreadto call LdrUnloadDllit to unload the module address from the inside to process. What are your thoughts on this approach? Does anyone have some sample code? I am having difficulty figuring out how to get the module counter.

+4
2

. , , , .

, . , . , , UnhookWindowsHookEx, . ( , , MSDN , UnhookWindowsHookEx.)

WM_NULL , UnhookWindowsHookEx, , DLL . DLL , DLL, , FreeLibraryAndExitThread.

. , , DLL , . , , DLL, . , DLL , PostThreadMessage, WM_NULL . , DLL FreeLibraryAndExitThread. , DLL , .

+2

.. .. . "" .

():

enter image description here

"" .

#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 , "un-link/hide" (, ). "/" . "" . , " " .

--, "" API, .

+6

All Articles