驱动开发:内核枚举进程与线程ObCall回调
在笔者上一篇文章《驱动开发:内核枚举Registry注册表回调》中我们通过特征码定位实现了对注册表回调的枚举,本篇文章LyShark将教大家如何枚举系统中的ProcessObCall进程回调以及ThreadObCall线程回调,之所以放在一起来讲解是因为这两中回调在枚举是都需要使用通用结构体_OB_CALLBACK以及_OBJECT_TYPE所以放在一起来讲解最好不过。
我们来看一款闭源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并循环输出即可。
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#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.com \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.com] 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即可,修改后的代码如下。
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#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.com \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;
}
运行这段驱动程序,即可得到线程句柄回调:

驱动开发:内核枚举进程与线程ObCall回调的更多相关文章
- 《Windows内核安全与驱动开发》 4.4 线程与事件
<Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 4.4 线程与事件 一.开辟一个线程,参数为(打印内容+打印次数),利用线程 ...
- X64驱动:内核操作进线程/模块
注意:下面的所有案例必须使用.C结尾的文件,且必须在链接选项中加入 /INTEGRITYCHECK 选项,否则编译根本无法通过(整合修正,Win10可编译,须在测试模式下进行),内核代码相对固定,如果 ...
- Windows驱动开发-内核常用内存函数
搞内存常用函数 C语言 内核 malloc ExAllocatePool memset RtlFillMemory memcpy RtlMoveMemory free ExFreePool
- 用Visual studio2012在Windows8上开发内核驱动监视线程创建
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破.在Windows 95中,至少应用程序I/O操作是不受限制的,而在Win ...
- 驱动开发:内核监视LoadImage映像回调
在笔者上一篇文章<驱动开发:内核注册并监控对象回调>介绍了如何运用ObRegisterCallbacks注册进程与线程回调,并通过该回调实现了拦截指定进行运行的效果,本章LyShark将带 ...
- 驱动开发:内核监控FileObject文件回调
本篇文章与上一篇文章<驱动开发:内核注册并监控对象回调>所使用的方式是一样的都是使用ObRegisterCallbacks注册回调事件,只不过上一篇博文中LyShark将回调结构体OB_O ...
- 驱动开发:内核枚举LoadImage映像回调
在笔者之前的文章<驱动开发:内核特征码搜索函数封装>中我们封装实现了特征码定位功能,本章将继续使用该功能,本次我们需要枚举内核LoadImage映像回调,在Win64环境下我们可以设置一个 ...
- 驱动开发:内核枚举Registry注册表回调
在笔者上一篇文章<驱动开发:内核枚举LoadImage映像回调>中LyShark教大家实现了枚举系统回调中的LoadImage通知消息,本章将实现对Registry注册表通知消息的枚举,与 ...
- 驱动开发:内核监控Register注册表回调
在笔者前一篇文章<驱动开发:内核枚举Registry注册表回调>中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监 ...
随机推荐
- mui 登录之后tab切换页面会失灵
我的app做完刚进去的时候底部导航栏的tab切换是正常的,但是退出之后重新登录,我在首页用reload进行了刷新,之后就引发了一些问题,tab切换有时候会失灵,登录转态的改变不成功.原来是reload ...
- One---python的六种数据类型及数据转换
python的六种数据类型 python中数据类型分为不可变数据类型和可变数据类型 可变数据类型 可变数据类型包括:List(列表).Dictionary(字典).Set(集合) 不可变数据类型 不可 ...
- Docker 07 部署Tomcat
参考源 https://www.bilibili.com/video/BV1og4y1q7M4?spm_id_from=333.999.0.0 https://www.bilibili.com/vid ...
- java学习第二天面向对象.day07
变量的生命周期 成员变量:存储在堆内存中,随着对象的销毁而销毁 局部变量:存储在栈内存中,随着所定义方法的调用结束而销毁 局部变量存储在方法中,每次调用方法都会在栈空间开辟一块内存空间--栈帧,方法调 ...
- Vue3 发生错误:setup function returned a promise
当你组件中有 Promise 对象时,即 Axios.Ajax 这类的请求,然后把数据渲染到模板中就会报如下图的错误: 在这个异步组件外包裹一个 <Suspense> 组件.比如 App. ...
- Excel 快速填充功能介绍以及注意事项
快速填充 快速填充可以让我们以某种格式来填充单元格. 用"姓氏+职位"格式来快速地填充下面表格中第三列.在第一个单元格内输入"李书记",选中需要被填充的其他单元 ...
- java数组---概念
1.数组的定义 数组是相同类型数据的有序集合.数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成.其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们. 2.数组的建 ...
- MAC上PKG打包
pkg是Mac平台上非常常见的一种安装包格式,如果你想要快速将软件制作为pkg文件,就千万不要错过Packages Mac版,Packages Mac版是Mac平台上能够快速为您生成pkg程序包的一款 ...
- luogu P1488 肥猫的游戏
肥猫的游戏 P1488 肥猫的游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 野猫与胖子,合起来简称肥猫,是一个班的同学,他们也都是数学高手,所以经常在一起讨论数学问 ...
- uniapp小程序新版授权登录
1.授权按钮: <view> <button class='login-btn' type='primary' @click="bindGetUserInfo"& ...