gpt4 book ai didi

c++ - 卸载注入(inject)的 DLL

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:18:51 24 4
gpt4 key购买 nike

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

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

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

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

最佳答案

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

结果(已记录):

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 的唯一优点是您可以使用它在进程中“取消链接/隐藏”模块(就像病毒一样)。它会“取消链接/隐藏”它......而不是“卸载”它。这意味着您可以随时将其“重新链接”回流程的模块列表。

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

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

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com