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,一经查实,立即删除!

相关文章

XML处理相关——学习一些处理脚本(1)——(待完善)

python脚本 import osfrom Bio.Blast import NCBIXMLimport FetchUtil #https://github.com/NiallScott/FetchUtils import randomif not os.path.exists(XML):os.mkdir(XML) if not os.path.exists(dicts):os.mkdir(dicts)def bestrecipblast(org, seed, thresh5, queueNone)…

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

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

数据库相关算法题 V1

超过经理收入的员工 超过经理收入的员工显然是要将同一张表&#xff0c;作为经理和员工表连接。这里存在两种方法&#xff0c;一种是采用WHERE SELECTa.Name AS Employee FROMEmployee AS a,Employee AS b WHEREa.ManagerId b.IdAND a.Salary > b.Salary另一种是使用JOIN…

【BUG】SpringBoot项目Long类型数据返回前端精度丢失问题

问题描述 后端再给前端返回数据&#xff0c;使用Long类型的时候存在精度丢失问题。 原因分析&#xff1a; 分布式项目中广泛使用雪花算法生成ID作为数据库表的主键&#xff0c;Long类型的雪花ID有19位&#xff0c;而前端接收Long类型用的是number类型&#xff0c;但是number…

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;它是有一个文件实体对象存在的。…

对系统的 Go 版本进行升级

方法一 直接升级系统的 Go 版本 注意以下操作仅适用于&#xff1a;amd64 架构的 Centos 系统。如果需要适配其他架构&#xff0c;需要自行编写代码实现。 手动执行&#xff1a; # 显示当前版本 go version # 查看环境变量 cat /etc/profile # 进入 go 的安装目录&#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…

UE小计:Unreal Engine 中 Actor 数据的 JSON 序列化

Unreal Engine 中 Actor 数据的 JSON 序列化 在游戏开发过程中&#xff0c;经常需要将游戏世界中的实体&#xff08;Actors&#xff09;信息导出到其他格式以便于分析、存储或交互。在Unreal Engine中&#xff0c;我们可以通过序列化这些实体的数据为JSON格式来实现这一目的。…

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

一、门电路概述 门电路&#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…

RPC之GRPC:什么是GRPC、GRPC的优缺点、GRPC使用场景

简介 gRPC是一个现代的开源高性能远程过程调用(RPC)框架&#xff0c;可以在任何环境中运行。它可以高效地连接数据中心内和跨数据中心的服务&#xff0c;支持负载平衡、跟踪、运行状况检查和身份验证。它也适用于分布式计算的最后一英里&#xff0c;将设备、移动应用程序和浏览…

linux特殊权限_suid_chattr_umask

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

软件使用-stm32入门

这节主要是介绍大家使用两个软件。这两个软件也是比较常用的&#xff0c;里面也有很多有意思的功能&#xff0c;可以给大家介绍一下。 1. FlyMcu 软件 这个软件可以通过串口给 STM32 下载程序&#xff0c;如果你没有 STLINK&#xff0c;就可以用这个软件通过串口下载程序。 …

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

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

差分数组相关知识点以及刷题

差分数组 差分数组是什么&#xff1f; **举例&#xff1a;**对于数组考虑数组 a[1,3,3,5,8]&#xff0c;对其中的相邻元素两两作差&#xff08;右边减左边&#xff09;&#xff0c;得到数组 [2,0,2,3]。然后在开头补上 a[0]&#xff0c;得到差分数组&#xff1a; ​ d[1,2,0…