在笔者上一篇文章《驱动开发:内核枚举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回调的更多相关文章

  1. 《Windows内核安全与驱动开发》 4.4 线程与事件

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 4.4 线程与事件 一.开辟一个线程,参数为(打印内容+打印次数),利用线程 ...

  2. X64驱动:内核操作进线程/模块

    注意:下面的所有案例必须使用.C结尾的文件,且必须在链接选项中加入 /INTEGRITYCHECK 选项,否则编译根本无法通过(整合修正,Win10可编译,须在测试模式下进行),内核代码相对固定,如果 ...

  3. Windows驱动开发-内核常用内存函数

    搞内存常用函数 C语言 内核 malloc ExAllocatePool memset RtlFillMemory memcpy RtlMoveMemory free ExFreePool

  4. 用Visual studio2012在Windows8上开发内核驱动监视线程创建

    在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破.在Windows 95中,至少应用程序I/O操作是不受限制的,而在Win ...

  5. 驱动开发:内核监视LoadImage映像回调

    在笔者上一篇文章<驱动开发:内核注册并监控对象回调>介绍了如何运用ObRegisterCallbacks注册进程与线程回调,并通过该回调实现了拦截指定进行运行的效果,本章LyShark将带 ...

  6. 驱动开发:内核监控FileObject文件回调

    本篇文章与上一篇文章<驱动开发:内核注册并监控对象回调>所使用的方式是一样的都是使用ObRegisterCallbacks注册回调事件,只不过上一篇博文中LyShark将回调结构体OB_O ...

  7. 驱动开发:内核枚举LoadImage映像回调

    在笔者之前的文章<驱动开发:内核特征码搜索函数封装>中我们封装实现了特征码定位功能,本章将继续使用该功能,本次我们需要枚举内核LoadImage映像回调,在Win64环境下我们可以设置一个 ...

  8. 驱动开发:内核枚举Registry注册表回调

    在笔者上一篇文章<驱动开发:内核枚举LoadImage映像回调>中LyShark教大家实现了枚举系统回调中的LoadImage通知消息,本章将实现对Registry注册表通知消息的枚举,与 ...

  9. 驱动开发:内核监控Register注册表回调

    在笔者前一篇文章<驱动开发:内核枚举Registry注册表回调>中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监 ...

随机推荐

  1. mybatis 05: mybatis中的动态代理

    mybatis中动态代理存在的意义 图示 图示分析 分层说明:界面层为第一层,业务逻辑层(接口层 + 实现层)为第二层,数据访问层(接口层 + 实现层)为第三层 业务逻辑层和数据访问层:分别分两层来开 ...

  2. 数据结构与算法【Java】03---栈

    前言 数据 data 结构(structure)是一门 研究组织数据方式的学科,有了编程语言也就有了数据结构.学好数据结构才可以编写出更加漂亮,更加有效率的代码. 要学习好数据结构就要多多考虑如何将生 ...

  3. Spring源码 05 IOC 注解方式

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  4. 大数据Hadoop入门教程 | (一)概论

    数据是什么 数据是指对客观事件进行记录并可以鉴别的符号,是对客观事物的性质.状态以及相互关系等进行记载的物理符号或这些物理符号的组合,它是可识别的.抽象的符号. 它不仅指狭义上的数字,还可以是具有一定 ...

  5. 【java】学习路线5-public和private、构造方法、this关键字、封装对象、static关键字、main方法结构解析

    //一个教务管理系统//知识点清单/*public & private 的区别一个是公开的,一个是私有的,作用域不一样,访问的权限不一样咯如果是用private修饰,则调用者只可以是在当前的作 ...

  6. 至少要几个砝码,可以称出 1g ~ 40g 重量

    请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...

  7. C语言:多功能计算器

    好家伙,这个东西有点折磨 这是一个多功能计算器 #include<stdio.h> #include<math.h> #include<windows.h> voi ...

  8. KingbaseES行转列(PIVOT)

    如果以交叉表格式显示,则商业智能查询返回的数据通常是最有用的.SELECT语句的pivot_.数据透视是数据仓库中的一项关键技术.在其中,您可以将多行输入转换为数据仓库中较少且通常较宽的行.进行数据透 ...

  9. KingbaseES V8R6集群外部备份案例

    案例说明: 本案例采用sys_backup.sh执行物理备份,备份使用如下逻辑架构:集群采用CentOS 7系统,repo采用kylin V10 Server. 一主一备+外部备份 此场景为主备双机常 ...

  10. 通过VS下载的NuGet包,如何修改其下载存放路径?

    一.了解NuGet包的默认存放路径 我们通过NuGet包管理器下载的引用包,默认是存放在C盘的,存储路径一般是: C:\Users\{系统用户名}\.nuget\packages 我们都知道,C盘的存 ...