【Windows】在任务管理器中隐藏进程

news2024/11/19 14:36:40

在此前的一篇,我们已经介绍过了注入Dll 阻止任务管理器结束进程 -- Win 10/11。本篇利用 hook  NtQuerySystemInformation 并进行断链的方法实现进程隐身,实测支持 taskmgr.exe 的任意多进程隐身。

任务管理器

代码:

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <detours/detours.h>
#include <winternl.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <shared_mutex>

#pragma comment(lib, "detours.lib")
#pragma comment(lib, "user32.lib")

typedef struct _VM_COUNTERS
{
    SIZE_T        PeakVirtualSize;
    SIZE_T        VirtualSize;
    ULONG         PageFaultCount;
    SIZE_T        PeakWorkingSetSize;
    SIZE_T        WorkingSetSize;
    SIZE_T        QuotaPeakPagedPoolUsage;
    SIZE_T        QuotaPagedPoolUsage;
    SIZE_T        QuotaPeakNonPagedPoolUsage;
    SIZE_T        QuotaNonPagedPoolUsage;
    SIZE_T        PagefileUsage;
    SIZE_T        PeakPagefileUsage;
} VM_COUNTERS;

// 线程信息结构体
typedef struct _MY_SYSTEM_THREAD_INFORMATION
{
    LARGE_INTEGER   KernelTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   CreateTime;
    ULONG           WaitTime;
    PVOID           StartAddress;
    CLIENT_ID       ClientId;
    KPRIORITY       Priority;
    KPRIORITY       BasePriority;
    ULONG           ContextSwitchCount;
    LONG            State;// 状态,是THREAD_STATE枚举类型中的一个值
    LONG            WaitReason;//等待原因, KWAIT_REASON中的一个值
} MY_SYSTEM_THREAD_INFORMATION, * PMY_SYSTEM_THREAD_INFORMATION;


typedef struct _MY_UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} MY_UNICODE_STRING, * PMY_UNICODE_STRING;


typedef struct _MY_SYSTEM_PROCESS_INFORMATION
{
    ULONG            NextEntryOffset; // 指向下一个结构体的指针
    ULONG            ThreadCount; // 本进程的总线程数
    ULONG            Reserved1[6]; // 保留
    LARGE_INTEGER    CreateTime; // 进程的创建时间
    LARGE_INTEGER    UserTime; // 在用户层的使用时间
    LARGE_INTEGER    KernelTime; // 在内核层的使用时间
    MY_UNICODE_STRING   ImageName; // 进程名
    KPRIORITY        BasePriority; // 
    ULONG            ProcessId; // 进程ID
    ULONG            InheritedFromProcessId;
    ULONG            HandleCount; // 进程的句柄总数
    ULONG            Reserved2[2]; // 保留
    VM_COUNTERS      VmCounters;
    IO_COUNTERS      IoCounters;
    SYSTEM_THREAD_INFORMATION Threads[5]; // 子线程信息数组
}MY_SYSTEM_PROCESS_INFORMATION, * PMY_SYSTEM_PROCESS_INFORMATION;


// 定义一个指针函数类型
typedef NTSTATUS(WINAPI* __NtQuerySystemInformation)(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
    );

// 定义一个存放原函数的指针
PVOID fpNtQuerySystemInformation = NULL;
// 读写锁
std::shared_mutex ppNameListMutex;
// 受保护进程名列表
std::vector<std::wstring> ppNameList;

// 声明函数
extern "C" {
    __declspec(dllexport)
        void StartHookingFunction();
    __declspec(dllexport) 
        void UnmappHookedFunction();
    __declspec(dllexport) 
        bool SetProtectedProcessListFromBuffer(const wchar_t* buffer, size_t length);
}

NTSTATUS WINAPI HookedNtQuerySystemInformation(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);


void OpenDebugConsole()
{
    AllocConsole();
    FILE* fDummy;
    freopen_s(&fDummy, "CONOUT$", "w", stdout);
    freopen_s(&fDummy, "CONOUT$", "w", stderr);
    freopen_s(&fDummy, "CONIN$", "r", stdin);

    std::wcout << L"Debug console opened.\n";
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved)
{
    // 禁用 DLL 模块的通知
    DisableThreadLibraryCalls(hModule);

    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        OpenDebugConsole();  // 打开控制台进行调试
        std::wcout << L"DLL injected, setting up hooks.\n";

        // 设置受保护进程列表,此函数也可以从远程进程注入线程来调用
        const WCHAR ppName[] = L"cmd.exe;conhost.exe";
        if (SetProtectedProcessListFromBuffer(ppName, wcslen(ppName) + 1))
        {
            std::wcout << L"Protected process list set successfully.\n";
        }
        else
        {
            std::wcout << L"Failed to set protected process list.\n";
        }

        // 启用 HOOK
        StartHookingFunction();
        std::wcout << L"Hooking started.\n";
    }
    break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        UnmappHookedFunction();
        std::wcout << L"Hooking detached.\n";
        break;
    }
    return TRUE;
}

extern "C"
__declspec(dllexport)
void StartHookingFunction()
{
    //开始事务
    DetourTransactionBegin();
    //更新线程信息  
    DetourUpdateThread(GetCurrentThread());

    fpNtQuerySystemInformation =
        DetourFindFunction(
            "ntdll.dll",
            "NtQuerySystemInformation");
    
    //将拦截的函数附加到原函数的地址上,这里可以拦截多个函数。
    DetourAttach(&(PVOID&)fpNtQuerySystemInformation,
        HookedNtQuerySystemInformation);
    
    //结束事务
    DetourTransactionCommit();
}

extern "C"
__declspec(dllexport)
void UnmappHookedFunction()
{
    //开始事务
    DetourTransactionBegin();
    //更新线程信息 
    DetourUpdateThread(GetCurrentThread());

    //将拦截的函数从原函数的地址上解除,这里可以解除多个函数。
    DetourDetach(&(PVOID&)fpNtQuerySystemInformation,
        HookedNtQuerySystemInformation);
    
    //结束事务
    DetourTransactionCommit();
}

// 从缓冲区解析多个进程名的函数
extern "C"
__declspec(dllexport)
bool SetProtectedProcessListFromBuffer(const wchar_t* buffer, size_t length) {
    if (buffer == nullptr || length == 0) {
        return false;  // 返回错误状态
    }

    std::unique_lock lock(ppNameListMutex);  // 写锁
    ppNameList.clear();  // 清空原列表

    std::wstring tempName;
    for (size_t i = 0; i < length; ++i) {
        if (buffer[i] == L';' || i == length - 1) {
            // 遇到分号或者到达缓冲区末尾,表示一个进程名结束
            if (i == length - 1 && buffer[i] != L';' && buffer[i] != L'\0') {
                tempName += buffer[i];  // 处理最后一个字符不是分号的情况
            }

            if (!tempName.empty()) {
                std::wcout << L"Parsed process name: " << tempName << L"\n";  // 输出调试信息
                std::wcout << L"Length: " << tempName.size() << L"\n";
                ppNameList.push_back(tempName);  // 将进程名存入列表
                tempName.clear();  // 清空临时字符串以解析下一个进程名
            }
        }
        else {
            // 继续读取进程名字符
            tempName += buffer[i];
        }
    }

    std::wcout << L"Total protected processes: " << ppNameList.size() << L"\n";  // 输出调试信息

    return !ppNameList.empty();  // 返回成功标志,如果解析后列表为空则返回false
}

// 检查进程是否在受保护列表中的函数(带读锁)
static bool IsProcessProtected(const std::wstring& processName) {
    std::vector<std::wstring> localPpNameList;
    {
        std::shared_lock lock(ppNameListMutex);
        localPpNameList = ppNameList;  // 将受保护列表复制到局部变量
    }

    // 在局部变量中进行比较
    return std::find(localPpNameList.begin(), localPpNameList.end(), processName) != localPpNameList.end();
}

static bool IsHandleValidate(const LPVOID lpAddress)
{
    MEMORY_BASIC_INFORMATION Buffer{};

    VirtualQuery(lpAddress, &Buffer, 0x30u);

    //std::wcout << L"HandleValidate Buffer.Protect: " << Buffer.Protect << L"\n";
    return Buffer.State == MEM_COMMIT && Buffer.Protect != PAGE_NOACCESS;
}

static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
    DWORD processId;
    GetWindowThreadProcessId(hwnd, &processId);

    // 检查窗口是否属于当前进程
    if (processId == GetCurrentProcessId()) {
        // 检索指向窗口句柄向量的指针
        std::vector<HWND>* pWindowHandles = reinterpret_cast<std::vector<HWND>*>(lParam);

        // 检查指针是否有效
        if (pWindowHandles && IsHandleValidate(pWindowHandles)) {
            pWindowHandles->push_back(hwnd);
        }
        else {
            // (可选)记录错误或处理无效指针情况
            std::cerr << "Invalid pointer passed to EnumWindowsProc." << std::endl;
        }
    }
    return TRUE; // 继续枚举
}

static void FlushProcessWindows() {
    std::vector<HWND> windowHandles;

    // 枚举所有顶级窗口,通过lParam将指针传递给EnumWindowsProc
    EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&windowHandles));

    // 向每一个窗口发送 F5 来刷新窗口
    for (HWND hwnd : windowHandles) {
        // 模拟 F5
        PostMessage(hwnd, WM_KEYDOWN, VK_F5, 0);
        Sleep(10);
        PostMessage(hwnd, WM_KEYUP, VK_F5, 0);
    }
}

// NtQuerySystemInformation的Hook函数,用于隐藏受保护的进程
NTSTATUS WINAPI HookedNtQuerySystemInformation(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
) {
    //std::wcout << L"NtQuerySystemInformation hook called.\n";
    static bool isNotFirstHook;
    const size_t nodeSize = sizeof(MY_SYSTEM_PROCESS_INFORMATION);

    // 先调用原始的 NtQuerySystemInformation
    NTSTATUS status = ((__NtQuerySystemInformation)fpNtQuerySystemInformation)(
        SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);

    //std::wcout << L"Original NtQuerySystemInformation returned: " << status << L"\n";

    // 只处理 SystemProcessInformation 类型的信息
    if (SystemInformationClass == SystemProcessInformation && NT_SUCCESS(status)) {
        //std::wcout << L"Processing SystemProcessInformation.\n";

        PMY_SYSTEM_PROCESS_INFORMATION pCurrentNode = (PMY_SYSTEM_PROCESS_INFORMATION)SystemInformation;
        PMY_SYSTEM_PROCESS_INFORMATION pPreviousNode = nullptr;
        bool isFirstNode = true;

        while (pCurrentNode != nullptr && IsHandleValidate(pCurrentNode)) {

            if (pCurrentNode->NextEntryOffset == 0) {  // 到达末尾
                break;
            }

            if (pCurrentNode->ImageName.Buffer == nullptr || pCurrentNode->ImageName.Length == 0) {
                // 跳过无效的进程名
                //std::wcout << L"Skipping invalid process name.\n";
                pCurrentNode = (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pCurrentNode + pCurrentNode->NextEntryOffset);
                continue;
            }

            // 获取当前进程名
            std::wstring processName(pCurrentNode->ImageName.Buffer, pCurrentNode->ImageName.Length / sizeof(WCHAR));
            //std::wcout << L"Processing process: " << processName << L"\n";

            // 检查该进程名是否在受保护列表中
            if (IsProcessProtected(processName)) {
                std::wcout << L"Process is protected: " << processName << L"\n";

                // 如果在受保护列表中,则将该进程从链表中移除
                if (pPreviousNode) {
                    pPreviousNode->NextEntryOffset += pCurrentNode->NextEntryOffset;
                    std::wcout << L"Process removed from list: " << processName << L"\n";
                }
                else if (isFirstNode) {  // 第一个节点是受保护进程,
                                         // 替换为下一个节点的数据
                    if (pCurrentNode->NextEntryOffset == 0) {
                        // 如果没有下一个节点,表示列表中只有一个受保护
                        // 将进程信息列表清空
                        memset(pCurrentNode, 0, SystemInformationLength);
                        std::wcout << L"Only one protected process, clearing list.\n";
                        break;
                    }
                    else {
                        
                        PMY_SYSTEM_PROCESS_INFORMATION pNextNode =
                            (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pCurrentNode + pCurrentNode->NextEntryOffset);

                        if(!IsHandleValidate(pNextNode)) {
                            std::wcout << L"HandleValidate failed.\n";
                            break;
                        }
                        // 将下一个节点的数据拷贝到当前节点
                        memcpy(pCurrentNode, pNextNode, sizeof(MY_SYSTEM_PROCESS_INFORMATION));
                        pCurrentNode->NextEntryOffset = pNextNode->NextEntryOffset;
                        std::wcout << L"First process was protected, replaced with next process.\n";
                        
                        continue;  // 保持 pPreviousNode 不变,重新检查当前节点
                    }
                }
            }
            else {
                // 如果没有被保护,移动到下一个节点
                pPreviousNode = pCurrentNode;
            }

            // 如果下一个节点超出缓冲区范围,停止处理
            if (((PUCHAR)pCurrentNode + pCurrentNode->NextEntryOffset + nodeSize) >
                (PUCHAR)SystemInformation + SystemInformationLength) {
                std::wcout << L"Reached end of buffer.\n";
                break;
            }

            // 继续下一个进程信息节点
            pCurrentNode = (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pCurrentNode + pCurrentNode->NextEntryOffset);
        }
    }

    // 只在第一次调用 hook 函数后强制刷新窗口
    if (!isNotFirstHook) {
        isNotFirstHook = true;
        FlushProcessWindows();
    }

    return status;
}

可以删除 dllmain 里面的hook 函数以及所有输出字符串。从外部进程通过注入远程线程的方式来实现动态调整隐身策略。主要利用下面三个函数:

导出函数

执行效果:

隐身效果(调试输出模式)

本文出处链接:[https://blog.csdn.net/qq_59075481/article/details/142676712]。

本文发布于:2024.10.02。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2183778.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MongoDB微服务部署

一、安装MongoDB 1.在linux中拉去MongoDB镜像文件 docker pull mongo:4.4.18 2. 2.创建数据挂载目录 linux命令创建 命令创建目录: mkdir -p /usr/local/docker/mongodb/data 可以在sshclient工具查看是否创建成功。 进入moogodb目录&#xff0c;给data赋予权限777 cd …

2024-09-04 深入JavaScript高级语法十五——浏览器原理-V8引擎-js执行原理

目录 1、浏览器的工作原理1.1、认识浏览器内核1.2、浏览器渲染过程 2、JS引擎2.1、认识 JavaScript 引擎2.2、浏览器内核和JS引擎的关系2.3、V8引擎的原理2.4、V8引擎的架构2.5、V8执行的细节 3、全局代码的执行过程3.1、初始化全局对象3.2、执行上下文栈&#xff08;调用栈&am…

World of Warcraft [CLASSIC][80][Grandel] Call to Arms: Victory in Wintergrasp

Wintergrasp 冬拥湖 120 VS 120 Victory in Wintergrasp - Quest - 魔兽世界怀旧服WLK3.35数据库_巫妖王之怒80级魔兽数据库_wlk数据库

逆向-下字符串查找的条件断点

为了跟踪console程序在访问某个文件时失败的问题&#xff0c;在内核中下了断点&#xff0c;但是内核中文件部分调用太频繁了&#xff0c;无法等到自己的文件。所以最好还是根据条件来下断点。 程序如下 想要在FileName是指定文件时停下来&#xff0c;例如FileName是c:\temp\f…

「轻盈」之旅:OOM故障重现与解决

前期准备 本项目均采用 VisualVM 2.1.10 进行dump文件的分析。JDK1.8及之前所在目录的bin目录下有自带的VisualVM&#xff0c;JDK1.8以后需要自行手动安装下载。 下载地址&#xff1a;https://visualvm.github.io/download.html IDEA插件配置&#xff1a;在Plugins里搜索visual…

2-109 基于matlab-GUI的BP神经网络

基于matlab-GUI的BP神经网络&#xff0c;10种不同分布的数据样本&#xff0c;9种不同的激活函数&#xff0c;可更改升级网络结构参数&#xff0c;对比各种方法参数下的训练测试效果&#xff0c;实时显示预测过程。程序已调通&#xff0c;可直接运行。 下载源程序请点链接&…

【简介Sentinel-1】

Sentinel-1是欧洲航天局哥白尼计划&#xff08;GMES&#xff09;中的地球观测卫星&#xff0c;由Sentinel-1A和Sentinel-1B两颗卫星组成。以下是对Sentinel-1的详细介绍&#xff1a; 一、基本信息 卫星名称&#xff1a;Sentinel-1 所属计划&#xff1a;欧洲航天局哥白尼计划…

【CSS】兼容处理

兼容前缀兼容查询 由于不同浏览器对CSS标准的支持程度不同&#xff0c;可能会导致在不同浏览器中出现样式差异。为了解决这个问题&#xff0c;需要采取一些措施来提高CSS的兼容性 兼容前缀 兼容前缀针对的浏览器-webkit-WebKit 内核浏览器&#xff0c;如&#xff1a;Safari 、…

.NET Core 集成 MiniProfiler性能分析工具

前言&#xff1a; 在日常开发中&#xff0c;应用程序的性能是我们需要关注的一个重点问题。当然我们有很多工具来分析程序性能&#xff1a;如&#xff1a;Zipkin等&#xff1b;但这些过于复杂&#xff0c;需要单独搭建。 MiniProfiler就是一款简单&#xff0c;但功能强大的应用…

进击J9:Inception v3算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、实验目的&#xff1a; 了解并学习InceptionV3相对于InceptionV1改进了哪些地方&#xff08;重点&#xff09;使用Inception v3完成天气识别案例 二、实验环…

Android 12.0 关于定制自适应AdaptiveIconDrawable类型的动态时钟图标的功能实现系列一

1.前言 在12.0的系统rom定制化开发中,在关于定制动态时钟图标中,原系统是不支持动态时钟图标的功能,所以就需要从新 定制动态时钟图标关于自适应AdaptiveIconDrawable类型的样式,就是可以支持当改变系统图标样式变化时,动态时钟 图标的背景图形也跟着改变,所以接下来就来…

OpenFeign微服务部署

一.开启nacos 和redis 1.查看nacos和redis是否启动 docker ps2.查看是否安装nacos和redis docker ps -a3.启动nacos和redis docker start nacos docker start redis-6379 docker ps 二.使用SpringSession共享例子 这里的两个例子在我的一个博客有创建过程&#xff0c…

通信工程学习:什么是LTE长期演进

LTE:长期演进 LTE(Long Term Evolution,长期演进)是由3GPP(The 3rd Generation Partnership Project,第三代合作伙伴计划)组织制定的UMTS(Universal Mobile Telecommunications System,通用移动通信系统)技术标准的长期演进。以下是对LTE的详细解释: 一、定…

音乐制作软件FL Studio 24.1.1.4285 中文完整版新功能介绍及如何安装激活FL Studio 24

FL Studio 24.1.1.4285 中文完整版又被国内网友称之为水果音乐制作软件24&#xff0c;是Image-Line公司成立26周年而发布的一个版本&#xff0c;是目前互联网上最优秀的完整的软件音乐制作环境或数字音频工作站&#xff0c;包含了编排&#xff0c;录制&#xff0c;编辑&#xf…

笔墨歌盛世 丹青绘匠心,艺术赋能“百千万工程”

9月30日上午&#xff0c;乡村有“艺”思——2024 年三乡镇乡村文化艺术周启动仪式暨“崛起的力量”余镇河深中通道主题美术作品展开幕仪式在中山市三乡镇古鹤村成荣美术馆举行。 中山市文联党组成员、专职副主席卢曙光&#xff0c;三乡镇党委委员艾立强&#xff0c;中山市文化馆…

leetcode每日一题day21(24.10.1)——最低票价

看到题目&#xff0c;最低消费又有各种的方案&#xff0c;与结合往期每日一题很就没出动态规划&#xff0c;就感觉这题很像动态规划。 思路:对于第X天&#xff0c;买票有三种方案&#xff0c;即从&#xff0c;X-1天买一天的票&#xff0c;X-7买7天的票&#xff0c;X-30买三十天…

iSTFT 完美重构的条件详解

目录 引言1. 短时傅里叶变换&#xff08;STFT&#xff09;与逆变换&#xff08;iSTFT&#xff09;概述2. 完美重构的条件3. 数学推导4. 实现要点5. 示例代码6. 总结 引言 在数字信号处理领域&#xff0c;短时傅里叶变换&#xff08;Short-Time Fourier Transform&#xff0c;简…

Java Web开发详解:从入门到实践

目录 引言 Java Web开发的优势 Java Web开发核心概念 Servlet和JSP Servlet JSP&#xff08;JavaServer Pages&#xff09; MVC架构 JDBC和数据库访问 JDBC概述 数据库连接示例 常用的Java Web框架 Spring MVC Hibernate MyBatis 对比常用框架 Java Web开发流程…

YOLOv5改进系列(1)——添加CBAM注意力机制

一、如何理解注意力机制 假设你正在阅读一本书&#xff0c;同时有人在你旁边说话。当你听到某些关键字时&#xff0c;比如“你的名字”或者“你感兴趣的话题”&#xff0c;你会自动把注意力从书上转移到他们的谈话上&#xff0c;尽管你并没有完全忽略书本的内容。这就是注意力机…

docker零基础入门教程

注意 本系列文章已升级、转移至我的自建站点中&#xff0c;本章原文为&#xff1a;Docker入门 目录 注意1.前言2.docker安装3.docker基本使用4.打包docker镜像5.docker进阶 1.前言 如果你长期写C/C代码&#xff0c;那你应该很容易发现C/C开源项目存在的一个严重问题&#xff…