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;                // Uint2BUCHAR ObjectTypeFlags;            // UCharULONG ObjectTypeCode;             // Uint4BULONG InvalidAttributes;          // Uint4BGENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPINGULONG ValidAccessMask;       // Uint4BULONG RetainAccess;         // Uint4BPOOL_TYPE PoolType;        // _POOL_TYPEULONG DefaultPagedPoolCharge;  // Uint4BULONG DefaultNonPagedPoolCharge; // Uint4BPVOID DumpProcedure;       // Ptr64     voidPVOID OpenProcedure;      // Ptr64     longPVOID CloseProcedure;     // Ptr64     voidPVOID DeleteProcedure;        // Ptr64     voidPVOID ParseProcedure;     // Ptr64     longPVOID SecurityProcedure;      // Ptr64     longPVOID QueryNameProcedure;     // Ptr64     longPVOID OkayToCloseProcedure;     // Ptr64     unsigned charULONG WaitObjectFlagMask;     // Uint4BUSHORT WaitObjectFlagOffset;    // Uint2BUSHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;typedef struct _OBJECT_TYPE
{LIST_ENTRY TypeList;           // _LIST_ENTRYUNICODE_STRING Name;         // _UNICODE_STRINGPVOID DefaultObject;         // Ptr64 VoidUCHAR Index;             // UCharULONG TotalNumberOfObjects;      // Uint4BULONG TotalNumberOfHandles;      // Uint4BULONG HighWaterNumberOfObjects;    // Uint4BULONG HighWaterNumberOfHandles;    // Uint4BOBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZEREX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCKULONG Key;                 // Uint4BLIST_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;                // Uint2BUCHAR ObjectTypeFlags;            // UCharULONG ObjectTypeCode;             // Uint4BULONG InvalidAttributes;          // Uint4BGENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPINGULONG ValidAccessMask;       // Uint4BULONG RetainAccess;         // Uint4BPOOL_TYPE PoolType;        // _POOL_TYPEULONG DefaultPagedPoolCharge;  // Uint4BULONG DefaultNonPagedPoolCharge; // Uint4BPVOID DumpProcedure;       // Ptr64     voidPVOID OpenProcedure;      // Ptr64     longPVOID CloseProcedure;     // Ptr64     voidPVOID DeleteProcedure;        // Ptr64     voidPVOID ParseProcedure;     // Ptr64     longPVOID SecurityProcedure;      // Ptr64     longPVOID QueryNameProcedure;     // Ptr64     longPVOID OkayToCloseProcedure;     // Ptr64     unsigned charULONG WaitObjectFlagMask;     // Uint4BUSHORT WaitObjectFlagOffset;    // Uint2BUSHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;typedef struct _OBJECT_TYPE
{LIST_ENTRY TypeList;           // _LIST_ENTRYUNICODE_STRING Name;         // _UNICODE_STRINGPVOID DefaultObject;         // Ptr64 VoidUCHAR Index;             // UCharULONG TotalNumberOfObjects;      // Uint4BULONG TotalNumberOfHandles;      // Uint4BULONG HighWaterNumberOfObjects;    // Uint4BULONG HighWaterNumberOfHandles;    // Uint4BOBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZEREX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCKULONG Key;                 // Uint4BLIST_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;                // Uint2BUCHAR ObjectTypeFlags;            // UCharULONG ObjectTypeCode;             // Uint4BULONG InvalidAttributes;          // Uint4BGENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPINGULONG ValidAccessMask;       // Uint4BULONG RetainAccess;         // Uint4BPOOL_TYPE PoolType;        // _POOL_TYPEULONG DefaultPagedPoolCharge;  // Uint4BULONG DefaultNonPagedPoolCharge; // Uint4BPVOID DumpProcedure;       // Ptr64     voidPVOID OpenProcedure;      // Ptr64     longPVOID CloseProcedure;     // Ptr64     voidPVOID DeleteProcedure;        // Ptr64     voidPVOID ParseProcedure;     // Ptr64     longPVOID SecurityProcedure;      // Ptr64     longPVOID QueryNameProcedure;     // Ptr64     longPVOID OkayToCloseProcedure;     // Ptr64     unsigned charULONG WaitObjectFlagMask;     // Uint4BUSHORT WaitObjectFlagOffset;    // Uint2BUSHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;typedef struct _OBJECT_TYPE
{LIST_ENTRY TypeList;           // _LIST_ENTRYUNICODE_STRING Name;         // _UNICODE_STRINGPVOID DefaultObject;         // Ptr64 VoidUCHAR Index;             // UCharULONG TotalNumberOfObjects;      // Uint4BULONG TotalNumberOfHandles;      // Uint4BULONG HighWaterNumberOfObjects;    // Uint4BULONG HighWaterNumberOfHandles;    // Uint4BOBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZEREX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCKULONG Key;                 // Uint4BLIST_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;
}

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

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

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

相关文章

02.PostgreSQL 查询处理期间发生了什么?

PostgreSQL 查询处理期间发生了什么&#xff1f; 文中主要内容引用自PostgreSQL指南&#xff1a;内幕探索 查询处理是PostgreSQL中最为复杂的子系统。如PostgreSQL官方文档所述&#xff0c;PostgreSQL支持SQL2011标准中的大多数特性&#xff0c;查询处理子系统能够高效地处理这…

Hdoop学习笔记(HDP)-Part.08 部署Ambari集群

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

有文件实体的后门无文件实体的后门rootkit后门

有文件实体后门和无文件实体后门&RootKit后门 什么是有文件的实体后门&#xff1a; 在传统的webshell当中&#xff0c;后门代码都是可以精确定位到某一个文件上去的&#xff0c;你可以rm删除它&#xff0c;可以鼠标右键操作它&#xff0c;它是有一个文件实体对象存在的。…

西南科技大学(数据结构A)期末自测练习三

一、填空题&#xff08;每空1分&#xff0c;共10分&#xff09; 1、为解决计算机主机与打印机之间速度不匹配的问题&#xff0c;通常设置一个打印数据缓冲区。主机将要输出的数据依次写入缓冲区&#xff0c;打印机则依次从缓冲区中取出数据&#xff0c;则该换缓冲区的逻辑结构…

【Java Web学习笔记】 2 - CSS入门

项目代码 零、 CSS引出 CSS 教程 官方教学文档 1.在没有CSS之前&#xff0c;我们想要修改HTML元素的样式需要为每个HTML元素单独定义样式属性&#xff0c;费心费力。所以CSS就出现了。 2.使用CSS将HTML页面的内容与样式分离提高web开发的工作效率&#xff08;针对前端开发&a…

一篇短文让你彻底理解什么是逻辑门电路

一、门电路概述 门电路&#xff1a;实现基本运算、复合运算的单元电路&#xff0c;如与门、与非门、或门… 注意&#xff1a;门电路中以高/低电平表示逻辑状态的1/0 正逻辑与负逻辑&#xff1a; 正逻辑&#xff1a;高电平表示1、低电平表示0 负逻辑&#xff1a;高电平表示0、低…

k8s ingress 无法找到端点

文章目录 ingress rule无法找到端点这个注解是什么意思呢&#xff1f;为何不生效呢&#xff1f;端点无法更新&#xff1f;如何确认ingressclass呢&#xff1f;修复端点无法发现的问题多个ingress controller 架构 ingress rule无法找到端点 在vnnox-cn集群创建ingress&#xf…

数据结构(三)——算法和算法分析

&#x1f600;前言 数据结构和算法是计算机科学领域中至关重要的概念。它们为解决实际问题提供了有效的方法和步骤。算法作为解决问题的方法和步骤&#xff0c;在计算机中以指令的有限序列的形式表达。本文将介绍算法的定义、描述和程序设计等方面的内容&#xff0c;帮助您深入…

【FPGA图像处理实战】- 图像基础知识

视频图像处理是FPGA主要应用方向之一&#xff0c;很多FPGA从事或准备进入这一领域&#xff0c;我们现在开始发布新的FPGA实战专栏——FPGA图像处理。 FPGA处理视频图像处理的主要优势是流水线和并行处理运算&#xff0c;特别是现在视频分辨率越来越大&#xff0c;从720p到1080…

二维A*算法

MATLAB2016b可以正常运行 function bidirectional_ASTAR clc; clear; %% 初始化界面 n 11; % field size n x n tiles 20*20的界面 %wallpercent 0.3; % this percent of field is walls 15%的界面作为阻碍物&#xff08;墙&#xff09; cmap [1 1 1; ...% 1 - whit…

linux特殊权限_suid_chattr_umask

3.3 特殊权限 如果一个文件很重要&#xff0c;需要依赖特殊权限避免其被删除。 由于特殊权限会拥有一些“特权”&#xff0c;因而用户若无特殊需要&#xff0c;不应该去打开这些权限&#xff0c;避免安全方面出现严重漏洞&#xff0c;甚至摧毁系统。3个权限是对了执行文件或目…

FPGA串口接收解帧、并逐帧发送有效数据-2

FPGA串口接收解帧、并逐帧发送有效数据 工程实现的功能&#xff1a;FPGA串口接收到串口调试助手发来的数据&#xff0c;将其数据解帧。判断到正确的帧头和帧尾之后&#xff0c;将有效数据存入rx_data中&#xff1b;另一方面发送端将有效数据逐帧发送出去。 参考&#xff1a;正…

【电路笔记】-串联和并联电阻

串联和并联电阻 文章目录 串联和并联电阻1、概述2、串联和并联电阻示例13、串联和并联电阻示例2 电阻器可以无限数量的串联和并联组合连接在一起&#xff0c;形成复杂的电阻电路。 1、概述 在之前的教程中&#xff0c;我们学习了如何将各个电阻器连接在一起以形成串联电阻器网…

linux设置权限_setfacl_getfacl

3.2 设置权限ACL&#xff08;access control list&#xff09; 假设&#xff1a;/data所有者与所属组均为root&#xff0c;在不改变所有者的前提下&#xff0c;要求用户tom对该目录有完全访问权限&#xff08;rwx&#xff09;。只能考虑&#xff1a; 方法一&#xff1a;给/dat…

超详细实现【贪吃蛇】(1)

目录 技术要点介绍 &#x1f642;Win32 API &#x1f642;控制台程序 &#x1f387;标题 &#x1f387;大小 在Windows终端上&#xff1a; 在VS上&#xff1a; &#x1f387;坐标 &#x1f642;光标 &#x1f636;‍&#x1f32b;️GetStdHandle &#x1f636;‍&am…

基于STM32 + TIM _定时器的基本机构和工作原理详解

前言 本篇博客主要学习了解定时器的基本结构和工作原理&#xff0c;掌握定时器的驱动程序和设计。本篇博客大部分是自己收集和整理&#xff0c;如有侵权请联系我删除。 本次博客板子使用的是正点原子精英版&#xff0c;芯片是STM32F103ZET6,需要资料可以我拿取。 本博客内容原…

[数据结构]红黑树的定义以及添加原则

红黑树是一种自平衡的二叉查找树&#xff0c;是一种常用的数据结构 1972年出现&#xff0c;在当时被称为平衡二叉B树。后来1978年被修改为如今的“红黑树” 它是一个特殊的二叉查找树&#xff0c;红黑树的每一个节点上都有储存位表示节点的颜色 每一个节点可以是红或者黑&#…

代码生成器——MyBatisX插件

MyBatisX插件 MyBatis-Plus为我们提供了强大的mapper和service模板&#xff0c;能够大大的提高开发效率。 但是在真正开发过程中&#xff0c;MyBatis-Plus并不能为我们解决所有问题&#xff0c;例如一些复杂的SQL&#xff0c;多表联查&#xff0c;我们就需要自己去编写代码和SQ…

密码学实验三

第一题&#xff1a; 寻找满足特定条件的 e&#xff1b; 第一步&#xff1a; 第二步&#xff1a; 由式1.7知&#xff0c;给定e,p,q&#xff0c;就可计算出相应的RSA不动点的数目。因此设计算法步骤如下&#xff1a; 枚举找出所有与φ(n)互素的e。枚举所有满足条件的e&#xff…

为XiunoBBS4.0开启redis缓存且支持密码验证

修改模块文件1 xiunoPHP/cache_redis.class.php: <?phpclass cache_redis {public $conf array();public $link NULL;public $cachepre ;public $errno 0;public $errstr ;public function __construct($conf array()) {if(!extension_loaded(Redis)) {return $thi…