6.5 Windows驱动开发:内核枚举PspCidTable句柄表

简介: 在 Windows 操作系统内核中,PspCidTable 通常是与进程(Process)管理相关的数据结构之一。它与进程的标识和管理有关,每个进程都有一个唯一的标识符,称为进程 ID(PID)。与之相关的是客户端 ID,它是一个结构,其中包含唯一标识进程的信息。这样的标识符在进程管理、线程管理和内核对象的创建等方面都起到关键作用。

在 Windows 操作系统内核中,PspCidTable 通常是与进程(Process)管理相关的数据结构之一。它与进程的标识和管理有关,每个进程都有一个唯一的标识符,称为进程 ID(PID)。与之相关的是客户端 ID,它是一个结构,其中包含唯一标识进程的信息。这样的标识符在进程管理、线程管理和内核对象的创建等方面都起到关键作用。

PspCidTable 可用于快速查找和管理进程信息,以便在系统中追踪、查询和操作进程。该表格可能包含有关每个进程的关键信息,例如 PID、客户端 ID、进程状态等。

在上一篇文章《内核枚举DpcTimer定时器》中我们通过枚举特征码的方式找到了DPC定时器基址并输出了内核中存在的定时器列表,本章将学习如何通过特征码定位的方式寻找Windows 10系统下面的PspCidTable内核句柄表地址。

首先引入一段基础概念;

  • 1.在windows下所有的资源都是用对象的方式进行管理的(文件、进程、设备等都是对象),当要访问一个对象时,如打开一个文件,系统就会创建一个对象句柄,通过这个句柄可以对这个文件进行各种操作。
  • 2.句柄和对象的联系是通过句柄表来进行的,准确来说一个句柄就是它所对应的对象在句柄表中的索引。
  • 3.通过句柄可以在句柄表中找到对象的指针,通过指针就可以对,对象进行操作。

PspCidTable 就是这样的一种表(内核句柄表),表的内部存放的是进程EPROCESS线程ETHREAD的内核对象,并通过进程PID线程TID进行索引,ID号以4递增,内核句柄表不属于任何进程,也不连接在系统的句柄表上,通过它可以返回系统的任何对象。

内核句柄表与普通句柄表完全一样,但它与每个进程私有的句柄表有以下不同;

  • 1.PspCidTable 中存放的对象是系统中所有的进程线程对象,其索引就是PIDTID
  • 2.PspCidTable 中存放的直接是对象体EPROCESS和ETHREAD,而每个进程私有的句柄表则存放的是对象头OBJECT_HEADER
  • 3.PspCidTable 是一个独立的句柄表,而每个进程私有的句柄表以一个双链连接起来。
  • 4.PspCidTable 访问对象时要掩掉低三位,每个进程私有的句柄表是双链连接起来的。

那么在Windows10系统中该如何枚举句柄表;

  • 1.首先找到PsLookupProcessByProcessId函数地址,该函数是被导出的可以动态拿到。
  • 2.其次在PsLookupProcessByProcessId地址中搜索PspReferenceCidTableEntry函数。
  • 3.最后在PspReferenceCidTableEntry地址中找到PspCidTable函数。

首先第一步先要得到PspCidTable函数内存地址,输入dp PspCidTable即可得到,如果在程序中则是调用MmGetSystemRoutineAddress取到。

PspCidTable是一个HANDLE_TALBE结构,当新建一个进程时,对应的会在PspCidTable存在一个该进程和线程对应的HANDLE_TABLE_ENTRY项。在windows10中依然采用动态扩展的方法,当句柄数少的时候就采用下层表,多的时候才启用中层表或上层表。

接着我们解析ffffdc88-79605dc0这个内存地址,执行dt _HANDLE_TABLE 0xffffdc8879605dc0得到规范化结构体。

内核句柄表分为三层如下;

  • 下层表:是一个HANDLE_TABLE_ENTRY项的索引,整个表共有256个元素,每个元素是一个8个字节长的HANDLE_TABLE_ENTRY项及索引,HANDLE_TABLE_ENTRY项中保存着指向对象的指针,下层表可以看成是进程和线程的稠密索引。
  • 中层表:共有256个元素,每个元素是4个字节长的指向下层表的入口指针及索引,中层表可以看成是进程和线程的稀疏索引。
  • 上层表:共有256个元素,每个元素是4个字节长的指向中层表的入口指针及索引,上层表可以看成是中层表的稀疏索引。

总结起来一个句柄表有一个上层表,一个上层表最多可以有256个中层表的入口指针,每个中层表最多可以有256个下层表的入口指针,每个下层表最多可以有256个进程和线程对象的指针。PspCidTable表可以看成是HANDLE_TBALE_ENTRY项的多级索引。

如上图所示TableCode是指向句柄表的指针,低二位(二进制)记录句柄表的等级:0(00)表示一级表,1(01)表示二级表,2(10)表示三级表。这里的 0xffffdc88-7d09b001 就说名它是一个二级表。

一级表里存放的就是进程和线程对象(加密过的,需要一些计算来解密),二级表里存放的是指向某个一级表的指针,同理三级表存放的是指向二级表的指针。

x64 系统中,每张表的大小是 0x1000(4096),一级表中存放的是 _handle_table_entry 结构(大小 = 16),二级表和三级表存放的是指针(大小 = 8)

我们对 0xffffdc88-7d09b001 抹去低二位,输入dp 0xffffdc887d09b000 输出的结果就是一张二级表,里面存储的就是一级表指针。

继续查看第一张一级表,输入dp 0xffffdc887962a000命令,我们知道一级句柄表是根据进程或线程ID来索引的,且以4累加,所以第一行对应id = 0,第二行对应id = 4。根据尝试,PID = 4的进程是System

所以此处的第二行0xb281de28-3300ffa7就是加密后的System进程的EPROCESS结构,对于Win10系统来说解密算法(value >> 0x10) & 0xfffffffffffffff0是这样的,我们通过代码计算出来。

#include <Windows.h>
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
   
   
    std::cout << "hello lyshark" << std::endl;

    ULONG64 ul_recode = 0xb281de283300ffa7;

    ULONG64 ul_decode = (LONG64)ul_recode >> 0x10;
    ul_decode &= 0xfffffffffffffff0;

    std::cout << "解密后地址: " << std::hex << ul_decode << std::endl;
    getchar();

    return 0;
}

运行程序得到如下输出,即可知道System系统进程解密后的EPROCESS结构地址是0xffffb281de283300

回到WinDBG调试器,输入命令dt _EPROCESS 0xffffb281de283300解析以下这个结构,输出结果是System进程。

理论知识总结已经结束了,接下来就是如何实现枚举进程线程了,枚举流程如下:

  • 1.首先找到PspCidTable的地址。
  • 2.然后找到HANDLE_TBALE的地址。
  • 3.根据TableCode来判断层次结构。
  • 4.遍历层次结构来获取对象地址。
  • 5.判断对象类型是否为进程对象。
  • 6.判断进程是否有效。

这里先来实现获取PspCidTable函数的动态地址,代码如下。

#include <ntifs.h>
#include <windef.h>

// 获取 PspCidTable
BOOLEAN get_PspCidTable(ULONG64* tableAddr)
{
   
   
    // 获取 PsLookupProcessByProcessId 地址
    UNICODE_STRING uc_funcName;
    RtlInitUnicodeString(&uc_funcName, L"PsLookupProcessByProcessId");
    ULONG64 ul_funcAddr = MmGetSystemRoutineAddress(&uc_funcName);
    if (ul_funcAddr == NULL)
    {
   
   
        return FALSE;
    }
    DbgPrint("PsLookupProcessByProcessId addr = %p \n", ul_funcAddr);

    // 前 40 字节有 call(PspReferenceCidTableEntry)
    /*
    0: kd> uf PsLookupProcessByProcessId
        nt!PsLookupProcessByProcessId:
        fffff802`0841cfe0 48895c2418      mov     qword ptr [rsp+18h],rbx
        fffff802`0841cfe5 56              push    rsi
        fffff802`0841cfe6 4883ec20        sub     rsp,20h
        fffff802`0841cfea 48897c2438      mov     qword ptr [rsp+38h],rdi
        fffff802`0841cfef 488bf2          mov     rsi,rdx
        fffff802`0841cff2 65488b3c2588010000 mov   rdi,qword ptr gs:[188h]
        fffff802`0841cffb 66ff8fe6010000  dec     word ptr [rdi+1E6h]
        fffff802`0841d002 b203            mov     dl,3
        fffff802`0841d004 e887000000      call    nt!PspReferenceCidTableEntry (fffff802`0841d090)
        fffff802`0841d009 488bd8          mov     rbx,rax
        fffff802`0841d00c 4885c0          test    rax,rax
        fffff802`0841d00f 7435            je      nt!PsLookupProcessByProcessId+0x66 (fffff802`0841d046)  Branch
    */
    ULONG64 ul_entry = 0;
    for (INT i = 0; i < 100; i++)
    {
   
   
        // fffff802`0841d004 e8 87 00 00 00      call    nt!PspReferenceCidTableEntry (fffff802`0841d090)
        if (*(PUCHAR)(ul_funcAddr + i) == 0xe8)
        {
   
   
            ul_entry = ul_funcAddr + i;
            break;
        }
    }

    if (ul_entry != 0)
    {
   
   
        // 解析 call 地址
        INT i_callCode = *(INT*)(ul_entry + 1);
        DbgPrint("i_callCode = %p \n", i_callCode);
        ULONG64 ul_callJmp = ul_entry + i_callCode + 5;
        DbgPrint("ul_callJmp = %p \n", ul_callJmp);

        // 来到 call(PspReferenceCidTableEntry) 内找 PspCidTable
        /*
        0: kd> uf PspReferenceCidTableEntry
            nt!PspReferenceCidTableEntry+0x115:
            fffff802`0841d1a5 488b0d8473f5ff  mov     rcx,qword ptr [nt!PspCidTable (fffff802`08374530)]
            fffff802`0841d1ac b801000000      mov     eax,1
            fffff802`0841d1b1 f0480fc107      lock xadd qword ptr [rdi],rax
            fffff802`0841d1b6 4883c130        add     rcx,30h
            fffff802`0841d1ba f0830c2400      lock or dword ptr [rsp],0
            fffff802`0841d1bf 48833900        cmp     qword ptr [rcx],0
            fffff802`0841d1c3 0f843fffffff    je      nt!PspReferenceCidTableEntry+0x78 (fffff802`0841d108)  Branch
        */
        for (INT i = 0; i < 0x120; i++)
        {
   
   
            // fffff802`0841d1a5 48 8b 0d 84 73 f5 ff  mov     rcx,qword ptr [nt!PspCidTable (fffff802`08374530)]
            if (*(PUCHAR)(ul_callJmp + i) == 0x48 && *(PUCHAR)(ul_callJmp + i + 1) == 0x8b && *(PUCHAR)(ul_callJmp + i + 2) == 0x0d)
            {
   
   
                // 解析 mov 地址
                INT i_movCode = *(INT*)(ul_callJmp + i + 3);
                DbgPrint("i_movCode = %p \n", i_movCode);
                ULONG64 ul_movJmp = ul_callJmp + i + i_movCode + 7;
                DbgPrint("ul_movJmp = %p \n", ul_movJmp);

                // 得到 PspCidTable
                *tableAddr = ul_movJmp;
                return TRUE;
            }
        }
    }
    return FALSE;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
   
   
    DbgPrint(("Uninstall Driver Is OK \n"));
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
   
   
    DbgPrint(("hello lyshark \n"));

    ULONG64 tableAddr = 0;

    get_PspCidTable(&tableAddr);

    DbgPrint("PspCidTable Address = %p \n", tableAddr);

    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

运行后即可得到动态地址,我们可以验证一下是否一致:

继续增加对与三级表的动态解析代码,最终代码如下所示:

#include <ntifs.h>
#include <windef.h>

// 获取 PspCidTable
BOOLEAN get_PspCidTable(ULONG64* tableAddr)
{
   
   
    // 获取 PsLookupProcessByProcessId 地址
    UNICODE_STRING uc_funcName;
    RtlInitUnicodeString(&uc_funcName, L"PsLookupProcessByProcessId");
    ULONG64 ul_funcAddr = MmGetSystemRoutineAddress(&uc_funcName);
    if (ul_funcAddr == NULL)
    {
   
   
        return FALSE;
    }
    DbgPrint("PsLookupProcessByProcessId addr = %p \n", ul_funcAddr);

    // 前 40 字节有 call(PspReferenceCidTableEntry)
    /*
    0: kd> uf PsLookupProcessByProcessId
        nt!PsLookupProcessByProcessId:
        fffff802`0841cfe0 48895c2418      mov     qword ptr [rsp+18h],rbx
        fffff802`0841cfe5 56              push    rsi
        fffff802`0841cfe6 4883ec20        sub     rsp,20h
        fffff802`0841cfea 48897c2438      mov     qword ptr [rsp+38h],rdi
        fffff802`0841cfef 488bf2          mov     rsi,rdx
        fffff802`0841cff2 65488b3c2588010000 mov   rdi,qword ptr gs:[188h]
        fffff802`0841cffb 66ff8fe6010000  dec     word ptr [rdi+1E6h]
        fffff802`0841d002 b203            mov     dl,3
        fffff802`0841d004 e887000000      call    nt!PspReferenceCidTableEntry (fffff802`0841d090)
        fffff802`0841d009 488bd8          mov     rbx,rax
        fffff802`0841d00c 4885c0          test    rax,rax
        fffff802`0841d00f 7435            je      nt!PsLookupProcessByProcessId+0x66 (fffff802`0841d046)  Branch
    */
    ULONG64 ul_entry = 0;
    for (INT i = 0; i < 100; i++)
    {
   
   
        // fffff802`0841d004 e8 87 00 00 00      call    nt!PspReferenceCidTableEntry (fffff802`0841d090)
        if (*(PUCHAR)(ul_funcAddr + i) == 0xe8)
        {
   
   
            ul_entry = ul_funcAddr + i;
            break;
        }
    }

    if (ul_entry != 0)
    {
   
   
        // 解析 call 地址
        INT i_callCode = *(INT*)(ul_entry + 1);
        DbgPrint("i_callCode = %p \n", i_callCode);
        ULONG64 ul_callJmp = ul_entry + i_callCode + 5;
        DbgPrint("ul_callJmp = %p \n", ul_callJmp);

        // 来到 call(PspReferenceCidTableEntry) 内找 PspCidTable
        /*
        0: kd> uf PspReferenceCidTableEntry
            nt!PspReferenceCidTableEntry+0x115:
            fffff802`0841d1a5 488b0d8473f5ff  mov     rcx,qword ptr [nt!PspCidTable (fffff802`08374530)]
            fffff802`0841d1ac b801000000      mov     eax,1
            fffff802`0841d1b1 f0480fc107      lock xadd qword ptr [rdi],rax
            fffff802`0841d1b6 4883c130        add     rcx,30h
            fffff802`0841d1ba f0830c2400      lock or dword ptr [rsp],0
            fffff802`0841d1bf 48833900        cmp     qword ptr [rcx],0
            fffff802`0841d1c3 0f843fffffff    je      nt!PspReferenceCidTableEntry+0x78 (fffff802`0841d108)  Branch
        */
        for (INT i = 0; i < 0x120; i++)
        {
   
   
            // fffff802`0841d1a5 48 8b 0d 84 73 f5 ff  mov     rcx,qword ptr [nt!PspCidTable (fffff802`08374530)]
            if (*(PUCHAR)(ul_callJmp + i) == 0x48 && *(PUCHAR)(ul_callJmp + i + 1) == 0x8b && *(PUCHAR)(ul_callJmp + i + 2) == 0x0d)
            {
   
   
                // 解析 mov 地址
                INT i_movCode = *(INT*)(ul_callJmp + i + 3);
                DbgPrint("i_movCode = %p \n", i_movCode);
                ULONG64 ul_movJmp = ul_callJmp + i + i_movCode + 7;
                DbgPrint("ul_movJmp = %p \n", ul_movJmp);

                // 得到 PspCidTable
                *tableAddr = ul_movJmp;
                return TRUE;
            }
        }
    }
    return FALSE;
}

/* 解析一级表
BaseAddr:一级表的基地址
index1:第几个一级表
index2:第几个二级表
*/
VOID parse_table_1(ULONG64 BaseAddr, INT index1, INT index2)
{
   
   
    // 遍历一级表(每个表项大小 16 ),表大小 4k,所以遍历 4096/16 = 526 次
    PEPROCESS p_eprocess = NULL;
    PETHREAD p_ethread = NULL;
    INT i_id = 0;
    for (INT i = 0; i < 256; i++)
    {
   
   
        if (!MmIsAddressValid((PVOID64)(BaseAddr + i * 16)))
        {
   
   
            DbgPrint("非法地址= %p \n", BaseAddr + i * 16);
            continue;
        }

        ULONG64 ul_recode = *(PULONG64)(BaseAddr + i * 16);

        // 解密
        ULONG64 ul_decode = (LONG64)ul_recode >> 0x10;
        ul_decode &= 0xfffffffffffffff0;

        // 判断是进程还是线程
        i_id = i * 4 + 1024 * index1 + 512 * index2 * 1024;
        if (PsLookupProcessByProcessId(i_id, &p_eprocess) == STATUS_SUCCESS)
        {
   
   
            DbgPrint("进程PID: %d | ID: %d | 内存地址: %p | 对象: %p \n", i_id, i, BaseAddr + i * 0x10, ul_decode);
        }
        else if (PsLookupThreadByThreadId(i_id, &p_ethread) == STATUS_SUCCESS)
        {
   
   
            DbgPrint("线程TID: %d | ID: %d | 内存地址: %p | 对象: %p \n", i_id, i, BaseAddr + i * 0x10, ul_decode);
        }
    }
}

/* 解析二级表
BaseAddr:二级表基地址
index2:第几个二级表
*/
VOID parse_table_2(ULONG64 BaseAddr, INT index2)
{
   
   
    // 遍历二级表(每个表项大小 8),表大小 4k,所以遍历 4096/8 = 512 次
    ULONG64 ul_baseAddr_1 = 0;
    for (INT i = 0; i < 512; i++)
    {
   
   
        if (!MmIsAddressValid((PVOID64)(BaseAddr + i * 8)))
        {
   
   
            DbgPrint("非法二级表指针(1):%p \n", BaseAddr + i * 8);
            continue;
        }
        if (!MmIsAddressValid((PVOID64)*(PULONG64)(BaseAddr + i * 8)))
        {
   
   
            DbgPrint("非法二级表指针(2):%p \n", BaseAddr + i * 8);
            continue;
        }
        ul_baseAddr_1 = *(PULONG64)(BaseAddr + i * 8);
        parse_table_1(ul_baseAddr_1, i, index2);
    }
}

/* 解析三级表
BaseAddr:三级表基地址
*/
VOID parse_table_3(ULONG64 BaseAddr)
{
   
   
    // 遍历三级表(每个表项大小 8),表大小 4k,所以遍历 4096/8 = 512 次
    ULONG64 ul_baseAddr_2 = 0;
    for (INT i = 0; i < 512; i++)
    {
   
   
        if (!MmIsAddressValid((PVOID64)(BaseAddr + i * 8)))
        {
   
   
            continue;
        }
        if (!MmIsAddressValid((PVOID64)* (PULONG64)(BaseAddr + i * 8)))
        {
   
   
            continue;
        }
        ul_baseAddr_2 = *(PULONG64)(BaseAddr + i * 8);
        parse_table_2(ul_baseAddr_2, i);
    }
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
   
   
    DbgPrint(("Uninstall Driver Is OK \n"));
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
   
   
    DbgPrint(("hello lyshark \n"));

    ULONG64 tableAddr = 0;

    get_PspCidTable(&tableAddr);

    DbgPrint("PspCidTable Address = %p \n", tableAddr);

    // 获取 _HANDLE_TABLE 的 TableCode
    ULONG64 ul_tableCode = *(PULONG64)(((ULONG64)*(PULONG64)tableAddr) + 8);
    DbgPrint("ul_tableCode = %p \n", ul_tableCode);

    // 取低 2位(二级制11 = 3)
    INT i_low2 = ul_tableCode & 3;
    DbgPrint("i_low2 = %X \n", i_low2);

    // 一级表
    if (i_low2 == 0)
    {
   
   
        // TableCode 低 2位抹零(二级制11 = 3)
        parse_table_1(ul_tableCode & (~3), 0, 0);
    }
    // 二级表
    else if (i_low2 == 1)
    {
   
   
        // TableCode 低 2位抹零(二级制11 = 3)
        parse_table_2(ul_tableCode & (~3), 0);
    }
    // 三级表
    else if (i_low2 == 2)
    {
   
   
        // TableCode 低 2位抹零(二级制11 = 3)
        parse_table_3(ul_tableCode & (~3));
    }
    else
    {
   
   
        DbgPrint("LyShark提示: 错误,非法! ");
        return FALSE;
    }

    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

运行如上完整代码,我们可以在WinDBG中捕捉到枚举到的进程信息:

线程信息在进程信息的下面,枚举效果如下:

至此文章就结束了,这里多说一句,实际上ZwQuerySystemInformation枚举系统句柄时就是走的这条双链,枚举系统进程如果使用的是这个API函数,那么不出意外它也是在这些内核表中做的解析。

相关文章
|
2月前
|
监控 安全 API
5.9 Windows驱动开发:内核InlineHook挂钩技术
在上一章`《内核LDE64引擎计算汇编长度》`中,`LyShark`教大家如何通过`LDE64`引擎实现计算反汇编指令长度,本章将在此基础之上实现内联函数挂钩,内核中的`InlineHook`函数挂钩其实与应用层一致,都是使用`劫持执行流`并跳转到我们自己的函数上来做处理,唯一的不同的是内核`Hook`只针对`内核API`函数,但由于其身处在`最底层`所以一旦被挂钩其整个应用层都将会受到影响,这就直接决定了在内核层挂钩的效果是应用层无法比拟的,对于安全从业者来说学会使用内核挂钩也是很重要。
5.9 Windows驱动开发:内核InlineHook挂钩技术
|
2月前
|
监控 API C++
8.4 Windows驱动开发:文件微过滤驱动入门
MiniFilter 微过滤驱动是相对于`SFilter`传统过滤驱动而言的,传统文件过滤驱动相对来说较为复杂,且接口不清晰并不符合快速开发的需求,为了解决复杂的开发问题,微过滤驱动就此诞生,微过滤驱动在编写时更简单,多数`IRP`操作都由过滤管理器`(FilterManager或Fltmgr)`所接管,因为有了兼容层,所以在开发中不需要考虑底层`IRP`如何派发,更无需要考虑兼容性问题,用户只需要编写对应的回调函数处理请求即可,这极大的提高了文件过滤驱动的开发效率。
|
2月前
|
监控 Windows
7.4 Windows驱动开发:内核运用LoadImage屏蔽驱动
在笔者上一篇文章`《内核监视LoadImage映像回调》`中`LyShark`简单介绍了如何通过`PsSetLoadImageNotifyRoutine`函数注册回调来`监视驱动`模块的加载,注意我这里用的是`监视`而不是`监控`之所以是监视而不是监控那是因为`PsSetLoadImageNotifyRoutine`无法实现参数控制,而如果我们想要控制特定驱动的加载则需要自己做一些事情来实现,如下`LyShark`将解密如何实现屏蔽特定驱动的加载。
7.4 Windows驱动开发:内核运用LoadImage屏蔽驱动
|
2月前
|
监控 安全 API
7.3 Windows驱动开发:内核监视LoadImage映像回调
在笔者上一篇文章`《内核注册并监控对象回调》`介绍了如何运用`ObRegisterCallbacks`注册`进程与线程`回调,并通过该回调实现了`拦截`指定进行运行的效果,本章`LyShark`将带大家继续探索一个新的回调注册函数,`PsSetLoadImageNotifyRoutine`常用于注册`LoadImage`映像监视,当有模块被系统加载时则可以第一时间获取到加载模块信息,需要注意的是该回调函数内无法进行拦截,如需要拦截则需写入返回指令这部分内容将在下一章进行讲解,本章将主要实现对模块的监视功能。
7.3 Windows驱动开发:内核监视LoadImage映像回调
|
2月前
|
监控 安全 API
7.2 Windows驱动开发:内核注册并监控对象回调
在笔者上一篇文章`《内核枚举进程与线程ObCall回调》`简单介绍了如何枚举系统中已经存在的`进程与线程`回调,本章`LyShark`将通过对象回调实现对进程线程的`句柄`监控,在内核中提供了`ObRegisterCallbacks`回调,使用这个内核`回调`函数,可注册一个`对象`回调,不过目前该函数`只能`监控进程与线程句柄操作,通过监控进程或线程句柄,可实现保护指定进程线程不被终止的目的。
7.2 Windows驱动开发:内核注册并监控对象回调
|
2月前
|
监控 安全 API
7.6 Windows驱动开发:内核监控FileObject文件回调
本篇文章与上一篇文章`《内核注册并监控对象回调》`所使用的方式是一样的都是使用`ObRegisterCallbacks`注册回调事件,只不过上一篇博文中`LyShark`将回调结构体`OB_OPERATION_REGISTRATION`中的`ObjectType`填充为了`PsProcessType`和`PsThreadType`格式从而实现监控进程与线程,本章我们需要将该结构填充为`IoFileObjectType`以此来实现对文件的监控,文件过滤驱动不仅仅可以用来监控文件的打开,还可以用它实现对文件的保护,一旦驱动加载则文件是不可被删除和改动的。
7.6 Windows驱动开发:内核监控FileObject文件回调
|
2月前
|
监控 安全 API
6.9 Windows驱动开发:内核枚举进线程ObCall回调
在笔者上一篇文章`《内核枚举Registry注册表回调》`中我们通过特征码定位实现了对注册表回调的枚举,本篇文章`LyShark`将教大家如何枚举系统中的`ProcessObCall`进程回调以及`ThreadObCall`线程回调,之所以放在一起来讲解是因为这两中回调在枚举是都需要使用通用结构体`_OB_CALLBACK`以及`_OBJECT_TYPE`所以放在一起来讲解最好不过。
6.9 Windows驱动开发:内核枚举进线程ObCall回调
|
Windows
24、Windows派遣函数(2)-Windows驱动开发详解笔记,直接读写方式
  1、直接读写方式 操作系统将用户模式下的缓冲区锁住,然后操作系统将这段缓冲区在内核模式地址再映射一遍。这样,用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理地址。 操作系统将用户模式的地址锁定后,用内存描述符MDL记录这段内存。
999 0
|
Windows
23、Windows派遣函数(1)-Windows驱动开发详解笔记,IRP
驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的。用户模式下所有对驱动程序的I/O请求,全部由操作系统转化为一个叫做IRP的数据结构,不同的IRP数据会被“派遣”到不同的派遣函数(Dispatch Function)中。
799 0
|
16天前
|
文件存储 Windows
Windows server 2012 服务器挂载NAS盘
Windows server 2012 服务器挂载NAS盘

相关产品

  • 云迁移中心