卸载注入的 DLL

2023-12-05

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

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

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

首先,如果您有任何故障排除提示可以帮助找出原因,那将会很有帮助。否则,我正在考虑使用一些 API,比如NtQueryInformationProcess获取模块地址并确认模块句柄计数实际上为零,然后调用CreateRemoteThread注入一个调用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,它正是执行此操作的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

卸载注入的 DLL 的相关文章

随机推荐

  • 如何对列表重新排序? [关闭]

    Closed 这个问题需要调试细节 目前不接受答案 给定一个任意大小的数组n 我想根据数组的离散索引重新组织数组的元素 Python 示例 Unique array of size n a b c d e
  • 对 Tkinter bind_class 感到困惑

    我定义了 GCanvas Canvas 的扩展 我的目的是在类级别绑定到 GCanvas 它不起作用 我还尝试绑定到 tk Canvas 但它也不起作用 绑定到root或 GCanvas 实例工作正常 这两种选择对我来说都没有用 但我只是尝
  • PowerShell:将 HTML 表提取为 CSV

    我正在尝试将 HTML 表提取到 CSV 文件 我对 PowerShell 了解不多 但在网上我找到了一些示例 但我总是收到相同的错误消息 您不能对空值表达式调用方法 行数 8 字符 1 table oHTML ParsedHtml bod
  • 使用重写规则从 url 中删除 .php

    我想重写 nginx 中的 url 以便 php扩展名可以省略 这就是我所拥有的 但这对我不起作用 有人知道如何做到这一点吗 Thanks server listen 80 server name example com return 30
  • 根据 3 个变量的颜色 - 麦克斯韦三角形

    我有一个由三个变量 u v w 组成的模型 它们随时间和空间而变化 我对这三个变量的比率特别感兴趣 但我宁愿只使用一张图 而不是显示三张图 每张图对应一个变量 我的想法是使用麦克斯韦三角形 颜色三角形 参见http homepages ab
  • ASP.NET Intranet 站点要求提供凭据 - Windows 身份验证

    我在 ASP Net 中创建了我的第一个网站 并且正在尝试在我们工作的 Intranet 上启动并运行它 我现在几乎已经完成了所有事情 但我遇到了障碍 我需要使用 Windows 身份验证 我的团队的要求 因此我完成了设置网站的过程 我已配
  • 对同一对象调用两次 MustHaveHappened 失败

    给定以下被测类 以及关联的 DTO 类和接口 public class Foo private readonly IBar bar public Foo IBar bar bar bar public void DoStuff var dt
  • 如何在项目中包含多个log4j2.xml文件?

    我的项目由多个模块组成 每个模块都可以独立运行并有单独的log4j2 xml 假设 Project X 由三个模块组成 模块 A 有 log4j2 xml 包含 Loggers 和 Appenders 模块 B 有 log4j2 xml 模
  • .vimrc 来源不正确

    我的 vimrc 中有以下几行 colorscheme solarized 这显然设置了日晒配色方案 我实际的 vimrc 肯定比这个长 并且我还指定了更多 Solarized 选项 但是 我面临的问题可以使用这个最小的 vimrc 文件来
  • Linux中DMA如何处理memcpy

    我在程序中使用 memcpy 不幸的是 当我增加变量数量时 CPU 使用率会增加 就好像 memcpy 是通过使用 for 循环迭代来运行的 linux 中也有快速的 memcpy 函数吗 我应该使用补丁并编译内核吗 在某些架构中 CPU
  • Bootstrap 突然不适用于我的 React JS 项目

    突然 引导程序停止了我的项目的工作 我不知道为什么 这是我们的 package json name blankets version 0 1 0 private true dependencies amazon cognito identi
  • 数据卡和U盘或U盘的区别

    我有一张沃达丰数据卡 可以插入 USB 端口 我有 XP 和 Vista 操作系统 并且我正在使用WM DEVICECHANGEWindows 事件 了解 USB 插入和拔出 它对我来说工作得很好 但我无法区分数据卡插入和笔驱动器插入 是否
  • 为了迭代数组,我们应该使用 size_t 还是 ptrdiff_t?

    In this 安德烈 卡尔波夫 Andrey Karpov 的博客文章标题为 About size t and ptrdiff t 他举了一个例子 for ptrdiff t i 0 i lt n i a i 0 不过不知道对不对 好像应
  • 如何在 F# 中将字典“转换”为序列?

    如何将字典 转换 为序列以便可以按键值排序 let results new Dictionary results Add George 10 results Add Peter 5 results Add Jimmy 9 results A
  • Django 垃圾评论

    Django 的评论框架中的反垃圾邮件系统效果如何 你用过吗 它大约可以防止多少百分比的垃圾评论 您还采取其他措施来帮助防止使用 Django 评论框架的网站上出现垃圾评论吗 有一个 Python API 可以Askimet 这就是 Wor
  • 在C中递归创建并遍历二叉树

    我想创建一个二叉树并通过前序遍历来遍历它 并且我使用递归方法 这些代码可以编译但不能正确运行 我发现它可能无法完成CreateBitree 功能可以 但不知道问题出在哪里 include
  • 在 Android 上的 React-Native 中压缩 Base64 编码图像无法识别“数据”协议

    Issue 在 React Native 0 43 应用程序中 我们使用一个组件 该组件使用 SectionList 来渲染按天排序的照片 每个部分可以包含多个图像 照片是使用反应本机图像作物选择器库并上传到后端 或者在没有可用互联网连接的
  • 核心数据 - 无法在路径加载优化模型

    当我在装有 iOS 9 beta 5 的 iPhone 6 中通过 Xcode 6 运行应用程序时 我在控制台中收到了一些打印内容 CoreData 无法在路径 var mobile Containers Bundle Applicatio
  • 从 Android 设备调用 Web 服务

    我已经使用 python Flask 框架在本地编写了一个 Web 服务 该框架运行在localhost 5000 我通过编写从我的计算机浏览器成功运行此 Web 服务http localhost 5000 toi something 现在
  • 卸载注入的 DLL

    我有一个 DLL 我使用它注入到其他进程中SetWindowsHookEx 在 DLL 内部 我通过调用来增加模块的引用计数器GetModuleHandleEx这样我就可以控制模块何时卸载 此时 这两个 API 调用的模块引用计数 应该 为