4

を使用して他のプロセスに挿入するDLLがありますSetWindowsHookEx。DLL 内で、モジュールの参照カウンターを呼び出してインクリメントし、モジュールGetModuleHandleExがいつアンロードされるかを制御できるようにします。

この時点で、これらの API 呼び出しの両方からのモジュール参照カウントは「2 である必要があります」。呼び出しプロセスがシャットダウンすると、 が呼び出されUnhookWindowsHookEx、参照カウントが 1 に減ります。DLL には、いくつかのことを待機するスレッドがあり、そのうちの 1 つは、 を呼び出したプロセスのハンドルですSetWindowsHookEx。プロセスがなくなると、DLL はいくつかのクリーンアップを行い、すべてのスレッドを終了し、メモリとハンドルをクリーンアップしてから を呼び出しますFreeLibraryAndExitThread。これにより、カウンターが減少し、DLL がアンロードされます。

これが私の問題です。いくつかのプロセス、特に UI のないプロセスでは、DLL がアンロードされません。私はすべてをきれいにしたと確信しています。そして、私のスレッドがどれも実行されていないという事実を知っています。

まず、原因を突き止めるためのトラブルシューティングのヒントがあれば、それが役に立ちます。NtQueryInformationProcessそれ以外の場合は、モジュール アドレスを取得し、モジュール ハンドル数が実際にゼロであることを確認するような API を使用してから、プロセス内からモジュール アドレスをアンロードするためCreateRemoteThreadの呼び出しを挿入することを考えていました。LdrUnloadDllこのアプローチについてどう思いますか?誰かがサンプルコードを持っていますか? モジュール ハンドル数を取得する方法がわかりません。

4

2 に答える 2

6

わかりました..ここに行きます..プロセスからモジュール情報を取得する方法はたくさんあります。文書化されていない方法と「文書化された」方法。

結果 (文書化):

ここに画像の説明を入力

これが「文書化された」方法です..

#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 のみを含めました。

于 2014-08-30T01:41:59.573 に答える