6.9 Windows驱动开发:内核枚举进线程ObCall回调

在笔者上一篇文章《内核枚举Registry注册表回调》中我们通过特征码定位实现了对注册表回调的枚举,本篇文章LyShark将教大家如何枚举系统中的ProcessObCall进程回调以及ThreadObCall线程回调,之所以放在一起来讲解是因为这两中回调在枚举是都需要使用通用结构体_OB_CALLBACK以及_OBJECT_TYPE所以放在一起来讲解最好不过。

进程与线程ObCall回调是Windows操作系统提供的一种机制,它允许开发者在进程或线程发生创建、销毁、访问、修改等事件时拦截并处理这些事件。进程与线程ObCall回调是通过操作系统提供的回调机制来实现的。

当操作系统创建、销毁、访问或修改进程或线程时,它会触发进程与线程ObCall回调事件,然后在回调事件中调用注册的进程与线程ObCall回调函数。开发者可以在进程与线程ObCall回调函数中执行自定义的逻辑,例如记录日志,过滤敏感数据,或者阻止某些操作。

进程与线程ObCall回调可以通过操作系统提供的回调函数PsSetCreateProcessNotifyRoutine、PsSetCreateThreadNotifyRoutine、PsSetLoadImageNotifyRoutine等来进行注册。同时,进程与线程ObCall回调函数需要遵守一定的约束条件,例如不能阻塞或挂起进程或线程的创建或访问,不能调用一些内核API函数等。

进程与线程ObCall回调在安全软件、系统监控和调试工具等领域有着广泛的应用。

我们来看一款闭源ARK工具是如何实现的:

首先我们需要定义好结构体,结构体是微软公开的,如果有其它需要请自行去微软官方去查。

typedef struct _OBJECT_TYPE_INITIALIZER
{
    USHORT Length;                // Uint2B
    UCHAR ObjectTypeFlags;            // UChar
    ULONG ObjectTypeCode;             // Uint4B
    ULONG InvalidAttributes;          // Uint4B
    GENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPING
    ULONG ValidAccessMask;       // Uint4B
    ULONG RetainAccess;         // Uint4B
    POOL_TYPE PoolType;        // _POOL_TYPE
    ULONG DefaultPagedPoolCharge;  // Uint4B
    ULONG DefaultNonPagedPoolCharge; // Uint4B
    PVOID DumpProcedure;       // Ptr64     void
    PVOID OpenProcedure;      // Ptr64     long
    PVOID CloseProcedure;     // Ptr64     void
    PVOID DeleteProcedure;        // Ptr64     void
    PVOID ParseProcedure;     // Ptr64     long
    PVOID SecurityProcedure;      // Ptr64     long
    PVOID QueryNameProcedure;     // Ptr64     long
    PVOID OkayToCloseProcedure;     // Ptr64     unsigned char
    ULONG WaitObjectFlagMask;     // Uint4B
    USHORT WaitObjectFlagOffset;    // Uint2B
    USHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _OBJECT_TYPE
{
    LIST_ENTRY TypeList;           // _LIST_ENTRY
    UNICODE_STRING Name;         // _UNICODE_STRING
    PVOID DefaultObject;         // Ptr64 Void
    UCHAR Index;             // UChar
    ULONG TotalNumberOfObjects;      // Uint4B
    ULONG TotalNumberOfHandles;      // Uint4B
    ULONG HighWaterNumberOfObjects;    // Uint4B
    ULONG HighWaterNumberOfHandles;    // Uint4B
    OBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZER
    EX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCK
    ULONG Key;                 // Uint4B
    LIST_ENTRY CallbackList;       // _LIST_ENTRY
}OBJECT_TYPE, *POBJECT_TYPE;

#pragma pack(1)
typedef struct _OB_CALLBACK
{
    LIST_ENTRY ListEntry;
    ULONGLONG Unknown;
    HANDLE ObHandle;
    PVOID ObTypeAddr;
    PVOID PreCall;
    PVOID PostCall;
}OB_CALLBACK, *POB_CALLBACK;
#pragma pack()

代码部分的实现很容易,由于进程与线程句柄的枚举很容易,直接通过(POBJECT_TYPE)(*PsProcessType))->CallbackList就可以拿到链表头结构,得到后将其解析为POB_CALLBACK并循环输出即可。

#include <ntifs.h>
#include <wdm.h>
#include <ntddk.h>

typedef struct _OBJECT_TYPE_INITIALIZER
{
    USHORT Length;                // Uint2B
    UCHAR ObjectTypeFlags;            // UChar
    ULONG ObjectTypeCode;             // Uint4B
    ULONG InvalidAttributes;          // Uint4B
    GENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPING
    ULONG ValidAccessMask;       // Uint4B
    ULONG RetainAccess;         // Uint4B
    POOL_TYPE PoolType;        // _POOL_TYPE
    ULONG DefaultPagedPoolCharge;  // Uint4B
    ULONG DefaultNonPagedPoolCharge; // Uint4B
    PVOID DumpProcedure;       // Ptr64     void
    PVOID OpenProcedure;      // Ptr64     long
    PVOID CloseProcedure;     // Ptr64     void
    PVOID DeleteProcedure;        // Ptr64     void
    PVOID ParseProcedure;     // Ptr64     long
    PVOID SecurityProcedure;      // Ptr64     long
    PVOID QueryNameProcedure;     // Ptr64     long
    PVOID OkayToCloseProcedure;     // Ptr64     unsigned char
    ULONG WaitObjectFlagMask;     // Uint4B
    USHORT WaitObjectFlagOffset;    // Uint2B
    USHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _OBJECT_TYPE
{
    LIST_ENTRY TypeList;           // _LIST_ENTRY
    UNICODE_STRING Name;         // _UNICODE_STRING
    PVOID DefaultObject;         // Ptr64 Void
    UCHAR Index;             // UChar
    ULONG TotalNumberOfObjects;      // Uint4B
    ULONG TotalNumberOfHandles;      // Uint4B
    ULONG HighWaterNumberOfObjects;    // Uint4B
    ULONG HighWaterNumberOfHandles;    // Uint4B
    OBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZER
    EX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCK
    ULONG Key;                 // Uint4B
    LIST_ENTRY CallbackList;       // _LIST_ENTRY
}OBJECT_TYPE, *POBJECT_TYPE;

#pragma pack(1)
typedef struct _OB_CALLBACK
{
    LIST_ENTRY ListEntry;
    ULONGLONG Unknown;
    HANDLE ObHandle;
    PVOID ObTypeAddr;
    PVOID PreCall;
    PVOID PostCall;
}OB_CALLBACK, *POB_CALLBACK;
#pragma pack()

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
    NTSTATUS status = STATUS_SUCCESS;

    DbgPrint("hello lyshark \n");

    POB_CALLBACK pObCallback = NULL;

    // 直接获取 CallbackList 链表
    LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsProcessType))->CallbackList;

    // 开始遍历
    pObCallback = (POB_CALLBACK)CallbackList.Flink;
    do
    {
        if (FALSE == MmIsAddressValid(pObCallback))
        {
            break;
        }
        if (NULL != pObCallback->ObHandle)
        {
            // 显示
            DbgPrint("[lyshark] ObHandle = %p | PreCall = %p | PostCall = %p \n", pObCallback->ObHandle, pObCallback->PreCall, pObCallback->PostCall);

        }
        // 获取下一链表信息
        pObCallback = (POB_CALLBACK)pObCallback->ListEntry.Flink;

    } while (CallbackList.Flink != (PLIST_ENTRY)pObCallback);
    return status;
}

运行这段驱动程序,即可得到进程句柄回调:

当然了如上是进程句柄的枚举,如果是想要输出线程句柄,则只需要替换代码中的PsProcessType((POBJECT_TYPE)(*PsThreadType))->CallbackList即可,修改后的代码如下。

#include <ntifs.h>
#include <wdm.h>
#include <ntddk.h>

typedef struct _OBJECT_TYPE_INITIALIZER
{
    USHORT Length;                // Uint2B
    UCHAR ObjectTypeFlags;            // UChar
    ULONG ObjectTypeCode;             // Uint4B
    ULONG InvalidAttributes;          // Uint4B
    GENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPING
    ULONG ValidAccessMask;       // Uint4B
    ULONG RetainAccess;         // Uint4B
    POOL_TYPE PoolType;        // _POOL_TYPE
    ULONG DefaultPagedPoolCharge;  // Uint4B
    ULONG DefaultNonPagedPoolCharge; // Uint4B
    PVOID DumpProcedure;       // Ptr64     void
    PVOID OpenProcedure;      // Ptr64     long
    PVOID CloseProcedure;     // Ptr64     void
    PVOID DeleteProcedure;        // Ptr64     void
    PVOID ParseProcedure;     // Ptr64     long
    PVOID SecurityProcedure;      // Ptr64     long
    PVOID QueryNameProcedure;     // Ptr64     long
    PVOID OkayToCloseProcedure;     // Ptr64     unsigned char
    ULONG WaitObjectFlagMask;     // Uint4B
    USHORT WaitObjectFlagOffset;    // Uint2B
    USHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _OBJECT_TYPE
{
    LIST_ENTRY TypeList;           // _LIST_ENTRY
    UNICODE_STRING Name;         // _UNICODE_STRING
    PVOID DefaultObject;         // Ptr64 Void
    UCHAR Index;             // UChar
    ULONG TotalNumberOfObjects;      // Uint4B
    ULONG TotalNumberOfHandles;      // Uint4B
    ULONG HighWaterNumberOfObjects;    // Uint4B
    ULONG HighWaterNumberOfHandles;    // Uint4B
    OBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZER
    EX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCK
    ULONG Key;                 // Uint4B
    LIST_ENTRY CallbackList;       // _LIST_ENTRY
}OBJECT_TYPE, *POBJECT_TYPE;

#pragma pack(1)
typedef struct _OB_CALLBACK
{
    LIST_ENTRY ListEntry;
    ULONGLONG Unknown;
    HANDLE ObHandle;
    PVOID ObTypeAddr;
    PVOID PreCall;
    PVOID PostCall;
}OB_CALLBACK, *POB_CALLBACK;
#pragma pack()

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
    NTSTATUS status = STATUS_SUCCESS;

    DbgPrint("hello lyshark \n");

    POB_CALLBACK pObCallback = NULL;

    // 直接获取 CallbackList 链表
    LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsThreadType))->CallbackList;

    // 开始遍历
    pObCallback = (POB_CALLBACK)CallbackList.Flink;
    do
    {
        if (FALSE == MmIsAddressValid(pObCallback))
        {
            break;
        }
        if (NULL != pObCallback->ObHandle)
        {
            // 显示
            DbgPrint("[LyShark] ObHandle = %p | PreCall = %p | PostCall = %p \n", pObCallback->ObHandle, pObCallback->PreCall, pObCallback->PostCall);
        }
        // 获取下一链表信息
        pObCallback = (POB_CALLBACK)pObCallback->ListEntry.Flink;

    } while (CallbackList.Flink != (PLIST_ENTRY)pObCallback);

    return status;
}

运行这段驱动程序,即可得到线程句柄回调:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

理解位运算的规则

关卡名 理解位运算的规则 我会了✔️ 内容 1.理解位运算的基本规则 ✔️ 2.理解移位的原理以及与乘除的关系 ✔️ 3.掌握位运算的常用技巧 ✔️ 在学习位操作之前&#xff0c;我们先明确数据在计算机中怎么表示的。我们明确原码、反码和补码的概念和表示方法&#xff0c;之…

2023年营养保健品市场销售数据分析(京东数据运营-京东数据产品):10月销额同比增长67%

如今&#xff0c;随着健康经济、颜值经济的兴起&#xff0c;越来越多的年轻人加入养生大军&#xff0c;成为营养保健品市场上的一股新力量&#xff0c;带动市场扩容。在养生年轻化、人口老龄化等多重因素的驱动下&#xff0c;营养保健品市场增长强劲。 根据鲸参谋电商数据分析平…

RocketMQ(四):重复消费、消息重试、死信消息的解决方案

RocketMQ系列文章 RocketMQ(一)&#xff1a;基本概念和环境搭建 RocketMQ(二)&#xff1a;原生API快速入门 RocketMQ(三)&#xff1a;集成SpringBoot RocketMQ(四)&#xff1a;重复消费、消息重试、死信消息的解决方案 目录 一、重复消费1、消息重复的情况2、MySql唯一索引…

Hexo | 支持书写数学公式

为了能够让 Hexo 支持书写数学公式&#xff0c;遇到了好多个坑。虽然以下方法我亲测有效&#xff0c;但并不能保证每个人都能成功。最差的情况就是 hexo s 启动失败&#xff0c;不过还可以重新 hexo init 哈哈笑不出来。 提醒&#xff1a;本文主要针对 fluid 主题&#xff0c;…

视频合并方法:掌握视频批量嵌套合并技巧,成为剪辑高手

在视频剪辑的过程中&#xff0c;我们经常需要将多个视频片段合并在一起。传统的视频合并方法往往需要大量的时间和精力&#xff0c;通过掌握批量嵌套合并技巧&#xff0c;可以更高效地完成这项任务&#xff0c;成为剪辑高手。本文讲解一种简单易学的视频合并方法&#xff0c;轻…

【爬虫】Java 爬虫组件 Jsoup

【爬虫】Java 爬虫组件 Jsoup 写在前面实现思路和步骤步骤一&#xff1a;引入 Jsoup步骤二&#xff1a;获取页面组件内容步骤三&#xff1a;分析页面构成获取需要的组件 代码案例 写在前面 爬虫是通过编程的方式&#xff0c;从网站上获取数据的一种方式。很多语言都提供的有爬…

机器学习---EM算法

1. 极大似然估计与EM算法 极大似然估计是一种常用的参数估计方法&#xff0c;它是以观测值出现的概率最大作为准则。关于极 大似然估计&#xff0c;假设现在已经取到样本值了&#xff0c;这表明取到这一样本的概率L(θ) 比较 大。我们自然不会考虑那些不能使样本出现的θ作为…

高校智慧用电管理平台

高校智慧用电管理平台是一种基于物联网、云计算、大数据等技术的智能化用电管理系统&#xff0c;旨在实现高校用电的实时监测、智能控制、数据分析和管理决策。 具体来说&#xff0c;该平台通常包括以下功能和特点&#xff1a; 实时监测&#xff1a;通过安装传感器、智能终端等…

ZeroTier外网访问实验室Linux服务器

ZeroTier外网访问实验室Linux服务器 1、在ZeroTier上创建一个自己的Network 进入ZeroTier的官网https://www.zerotier.com/注册一个账号 注册完之后登录进去&#xff0c;创建自己的Network 创建完之后来到IPv4的分配管理&#xff0c;选择主机位只有后8位的IP&#xff0c;才能…

img[src=““] img无路径情况下,页面出现边框

在开发过程中遇到一个问题就是当img标签的src为空时&#xff0c;会出现边框&#xff0c;影响美观 其实我们可以直接加上这个就可以解决了 img[src""],img:not([src]){opacity:0; }

金融系统中容易踩坑的问题

1、产品类型指的是大类还是小类 有的产品比如员工贷既是指员工贷小类&#xff0c;也是指员工贷系列的产品&#xff0c;这时候需要关注需求描述的员工贷覆盖范围是产品大类还是小类。 2、未带参数时是否有默认处理 前端传输的某个值为空时&#xff0c;后端是否需要设默认值&a…

夯实c基础

夯实c基础 区别&#xff1a; 图一的交换&#xff0c;&#xff08;交换的是地址而不是两数&#xff09;无法实现两数的交换。 题干以下程序的输出结果为&#xff08; c  &#xff09;。 void fun(int a, int b, int c){ ca*b; } void main( ){ int…

模型层(回顾补充)

1.1基本使用 orm框架---》对象关系映射 数据库中&#xff1a;一个个表 &#xff1a;user表&#xff0c;book表&#xff0c;一条条的记录 程序中&#xff1a;一个个类&#xff0c;一个个对象 以后数据库中一张表---》对应程序中一个类 以后数据库中一条记录--》对应…

ThinkPHP 2.x任意代码执行漏洞

任务一&#xff1a; 复现环境中的代码漏洞 任务二&#xff1a; 尝试利用代码执行漏洞读取服务器web目录下的文件列表。 任务一&#xff1a; 1.搭建环境&#xff1a; 2.在php环境下直接输入{${phpinfo}}测试代码片段 2.写入一句话木马&#xff0c;用antsword连接&#xff0…

C++基础 -24- 覆盖

覆盖的三个条件 -1- 基类和派生类存在同名的函数 -2- 基类的函数为虚函数 -3- 必须使用基类引用或指针指向派生类 #include "iostream"using namespace std;class base {public:base(){}virtual void show(){cout << "base show" << endl;} };…

【LeetCode】栈和队列OJ题---C语言版

栈和队列OJ题 1.括号匹配问题&#xff08;1&#xff09;题目描述&#xff1a;&#xff08;2&#xff09;思路表述&#xff1a;&#xff08;3&#xff09;代码实现&#xff1a; 2.用队列实现栈&#xff08;1&#xff09;题目描述&#xff1a;&#xff08;2&#xff09;思路表述&…

OSI七层模型与TCP/IP四层模型的区别(计算机网络)

一、OSI七层网络模型 OSI 网络模型共有 7 层&#xff0c;分别是应用层、表示层、会话层、传输层、网络层、数据链路层和物理层。 应用层&#xff0c;负责给应用程序提供统一的接口&#xff1b;表示层&#xff0c;负责把数据转换成兼容另一个系统能识别的格式&#xff1b;会话…

NX二次开发UF_MTX2_copy 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_MTX2_copy Defined in: uf_mtx.h void UF_MTX2_copy(const double mtx_src [ 4 ] , double mtx_dst [ 4 ] ) overview 概述 Copies the 2x2 matrix elements from the source m…

对外汉语教师简历(精选12篇)

以对外汉语老师招聘需求为背景&#xff0c;我们制作了1份全面、专业且具有参考价值的简历案例&#xff0c;大家可以灵活借鉴&#xff0c;希望能帮助大家在众多候选人中脱颖而出。 对外汉语教师简历下载&#xff08;在线制作&#xff09;&#xff1a;百度幻主简历或huanzhucv.c…