Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Windows Kernel-仿pchunter获得系统回调列表

Windows Kernel-仿pchunter获得系统回调列表

原创
作者头像
franket
发布于 2020-05-10 05:33:23
发布于 2020-05-10 05:33:23
13.8K00
代码可运行
举报
文章被收录于专栏:技术杂记技术杂记
运行总次数:0
代码可运行

1、创建进程、创建线程、加载模块回调

(1)创建进程回调

注册创建进程回调使用函数 PsSetCreateProcessNotifyRoutine,调用这个函数会将注册的信息保存到一个数组里面。

反汇编这个函数,会发现以下片段:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
805d0c27 56			  push	esi
805d0c28 57			  push	edi
805d0c29 7464			  je	  nt!PsSetCreateProcessNotifyRoutine+0x73 (805d0c8f)
805d0c2b bf404a5680	          mov	 edi,offset nt!PspCreateProcessNotifyRoutine (80564a40)
805d0c30 57			  push	edi
 
PspCreateProcessNotifyRoutine (80564a40)即这个数组的地址,这个数组是以下结构:
ypedef struct _EX_FAST_REF
{
	union
	{
		PVOID Object;
		ULONG_PTR RefCnt:3;
		ULONG_PTR Value;
	};
} EX_FAST_REF, *PEX_FAST_REF;
 
低三位RefCnt是引用指针,Value指向一个结构,如下:
typedef struct _EX_CALLBACK_ROUTINE_BLOCK
{
	EX_RUNDOWN_REF RundownProtect;
	PEX_CALLBACK_FUNCTION Function;
	PVOID Context;
} EX_CALLBACK_ROUTINE_BLOCK, *PEX_CALLBACK_ROUTINE_BLOCK;

可以看到保存了回调函数的地址

因而采用搜索数组的方式在进行遍历即可,因为在WIN XP SP3中数组元素为8个,所以遍历的时候就按八个来的,WIN 7就不是了

(2)创建线程和加载模块一样,略过。。。

2、注册表回调

一开始真不知道哪个函数是注册注册表回调,尝试着在MSDN以cm(Xuetr回调类型里就是cmpCallBack)开头看到了CmRegisterCallback,大致看了一下,跟上面的原理一样。。不过是不是八个元素没注意,按八个处理的

3、错误检测回调

函数是:

KeRegisterBugCheckCallback

KeRegisterBugCheckReasonCallback

反汇编KeRegisterBugCheckCallback :

查看WRK ,这里没有考虑WRK与WIN XP 在该函数上可能的差异。。。得到以下信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NTKERNELAPI
BOOLEAN
KeRegisterBugCheckCallback (
	__out PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
	__in PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
	__in PVOID Buffer,
	__in ULONG Length,
	__in PUCHAR Component
	)
typedef struct _KBUGCHECK_CALLBACK_RECORD {
	LIST_ENTRY Entry;
	PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine;
	PVOID Buffer;
	ULONG Length;
	PUCHAR Component;
	ULONG_PTR Checksum;
	UCHAR State;
} KBUGCHECK_CALLBACK_RECORD, *PKBUGCHECK_CALLBACK_RECORD;
 
LIST_ENTRY KeBugCheckCallbackListHead;
LIST_ENTRY KeBugCheckReasonCallbackListHead;

结构类型就很清楚了,得到链表头,按照双向链表便利即可

4、Lego回调

刚从XUETR里面看到这个还真不知道是什么,搜索一番后,得到了MJ的一些说明:

ULONG PsSetLegoNotifyRoutine(PVOID notifyroutine)

notifyroutine为需要设置的回调函数地址

返回值是_ETHREAD->Tcb->LegoData的偏移量

调用此函数,系统会将一个未导出的全局变量_PspLegoNotifyRoutine设置为你设定的回调函数地址

当一个线程的_ETHREAD->Tcb->LegoData不为空,且_PspLegoNotifyRoutine不为空,那么当这个线程调用PspExitThread退出时,会调用PspLegoNotifyRoutine中的回调函数

系统中只允许设置一个这样的回调函数

有人跟着给出具体结构和定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef VOID (*PLEGO_NOTIFY_ROUTINE)( PKTHREAD Thread );
ULONG PsSetLegoNotifyRoutine( PLEGO_NOTIFY_ROUTINE LegoNotifyRoutine )
{
	PAGED_CODE();
	PspLegoNotifyRoutine = LegoNotifyRoutine;
	return FIELD_OFFSET(KTHREAD,LegoData);
}

硬编码搜索到这个全局变量,查看地址是否为0即可(不知是否有误,或者加上地址有效检测?)

代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nt!PsSetLegoNotifyRoutine:
805d299a 8bff			  mov	 edi,edi
805d299c 55			  push	ebp
805d299d 8bec			  mov	 ebp,esp
805d299f 8b4508		          mov	 eax,dword ptr [ebp+8]
805d29a2 a3c0d26780	          mov	 dword ptr [nt!PspLegoNotifyRoutine (8067d2c0)],eax//这里
805d29a7 b8d0000000	          mov	 eax,0D0h
805d29ac 5d			  pop	 ebp
805d29ad c20400		          ret	 4

5、关机回调

有两个函数:

IoRegisterShutdownNotification

IoRegisterLastChanceShutdownNotification

来看第一个:

相关结构和定义也是参考了WRK。。。。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
LIST_ENTRY IopNotifyShutdownQueueHead;
LIST_ENTRY IopNotifyLastChanceShutdownQueueHead;
 
typedef struct _SHUTDOWN_PACKET {
	LIST_ENTRY ListEntry;
	PDEVICE_OBJECT DeviceObject;
} SHUTDOWN_PACKET, *PSHUTDOWN_PACKET;

要得到回调函数地址,需要得到设备对象,回调函数地址即IRP_MJ_SHUTDOWN的例程地址

//#define IRP_MJ_SHUTDOWN 0x10

代码如下:

代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ULONG GetNotifyAddr(PDEVICE_OBJECT Device_Object)
{
  ULONG Addr;
  PDRIVER_OBJECT Driver_Object;
  Driver_Object=Device_Object->DriverObject;
  Addr=*(ULONG*)((ULONG)Driver_Object+0x38+0x40);
  return Addr;
}

6、注销回调

搜了N久也不知道是哪个函数,于是看了看Xuetr,只有mrxsmb.sys注册了注销回调,查看其导入表看看有没有跟注册相关的字眼,于是找到了SeRegisterLogonSessionTerminatedRoutine

,查了一下,果然是。

也是一个链表头的形式,相关结构和定义:

代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef NTSTATUS (*PSE_LOGON_SESSION_TERMINATED_ROUTINE) (
  IN PLUID LogonId
  );
typedef struct _SEP_LOGON_SESSION_TERMINATED_NOTIFICATION {
	struct _SEP_LOGON_SESSION_TERMINATED_NOTIFICATION *Next;
	PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine;
} SEP_LOGON_SESSION_TERMINATED_NOTIFICATION, *PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION;
 
NTSTATUS
SeRegisterLogonSessionTerminatedRoutine(
	IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine
	);

7、文件系统改变回调

相关的注册函数是:IoRegisterFsRegistrationChange

结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct _NOTIFICATION_PACKET
{
	LIST_ENTRY ListEntry;
	PDRIVER_OBJECT DriverObject;
	ULONG NotificationRoutine;
} NOTIFICATION_PACKET, *PNOTIFICATION_PACKET;

8、即插即用回调

(1)注册的函数应该是IoRegisterPlugPlayNotification

今天下了一份2000源代码回来,找到了IoRegisterPlugPlayNotification函数的实现部分,发现了一个链表IopDeviceClassNotifyList,用Windbg查看这个链表,得到如下信息:

|————————|

1.8067d080 -> e1dd7698 ->–^

8067d080 <- e1dd7698 <---- |________________________| |------------------------------------------------| 2.e1336d98 -> e1036468 -> e1307548 -> 8067d090 ->–^

e1307548 <- 8067d090 <- e1336d98 <- e1036468 <---- |________________________________________________| |------------------------------------------------| 4.e1000888 -> e1f58478 -> e1bc04a0 -> 8067d0a0 ->–^

e1bc04a0 <- 8067d0a0 <- e1000888 <- e1f58478 <---- |________________________________________________| |------------------------| 5.e1537858 -> 8067d0a8 ->–^

e1537858 <- 8067d0a8 <---- |________________________| |------------------------| 6.e156e7c8 -> 8067d0b0 ->–^

e156e7c8 <- 8067d0b0 <---- |________________________| |------------------------| 10.e1315d60 -> 8067d0d0 ->–^

e1315d60 <- 8067d0d0 <---- |________________________| |------------------------------------------------| 11.e1002ad8 -> e156fc48 -> e1301258 -> 8067d0d8 ->–^

e1301258 <- 8067d0d8 <- e1002ad8 <- e156fc48 <---- |________________________________________________| |------------------------------------------------------------| 12.e1023c40 -> e131ae08 -> e101ea20 -> e1f752c8 -> 8067d0e0 ->–^

e1f752c8 <- 8067d0e0 <- e1023c40 <- e131ae08 <- e101ea20 <---- |____________________________________________________________| 一共17个,正好跟Xuetr对应上 而参照2000代码,IopDeviceClassNotifyList是一个具有13个(XP也是)元素的数组,每个都是一个链表,数据格式: 代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct _SETUP_NOTIFY_DATA
 {
	LIST_ENTRY ListEntry;
	IO_NOTIFICATION_EVENT_CATEGORY EventCategory;
	PDRIVER_NOTIFICATION_CALLBACK_ROUTINE Callback;
	PVOID Context;
	PDRIVER_OBJECT DriverObject;
	USHORT RefCount;
	BOOLEAN Unregistered;
	PFAST_MUTEX Lock;
} SETUP_NOTIFY_DATA, *PSETUP_NOTIFY_DATA;

但是偏移跟实际的对不上。。。应该有所更改了

通过计算注册时提供的ClassGuid得到不同的hash值,hash值相同的串在一个链表里

但是技术太烂,WinDbg在u IoRegisterPlugPlayNotification里面没看到IopDeviceClassNotifyList数组,但是发现还有一个函数:IopInitializePlugPlayNotification 这个函数没有导出,我用了最烂的方法,遍历内核模块空间,根据特征码得到函数地址

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nt!IopInitializePlugPlayNotification:
8058a5b4 6a0d			push	0Dh
8058a5b6 b880d06780	  mov	 eax,offset nt!IopDeviceClassNotifyList (8067d080)
8058a5bb 59			  pop	 ecx
8058a5bc 894004		  mov	 dword ptr [eax+4],eax

再得到IopDeviceClassNotifyList 数组地址,遍历即可。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
暂无评论
推荐阅读
编辑精选文章
换一批
6.7 Windows驱动开发:内核枚举LoadImage映像回调
在笔者之前的文章《内核特征码搜索函数封装》中我们封装实现了特征码定位功能,本章将继续使用该功能,本次我们需要枚举内核LoadImage映像回调,在Win64环境下我们可以设置一个LoadImage映像加载通告回调,当有新驱动或者DLL被加载时,回调函数就会被调用从而执行我们自己的回调例程,映像回调也存储在数组里,枚举时从数组中读取值之后,需要进行位运算解密得到地址。
王 瑞
2023/12/02
3830
6.7 Windows驱动开发:内核枚举LoadImage映像回调
驱动开发:内核枚举Registry注册表回调
在笔者上一篇文章《驱动开发:内核枚举LoadImage映像回调》中LyShark教大家实现了枚举系统回调中的LoadImage通知消息,本章将实现对Registry注册表通知消息的枚举,与LoadImage消息不同Registry消息不需要解密只要找到CallbackListHead消息回调链表头并解析为_CM_NOTIFY_ENTRY结构即可实现枚举。
王 瑞
2022/12/28
5640
驱动开发:内核枚举Registry注册表回调
驱动开发:内核监控FileObject文件回调
本篇文章与上一篇文章《驱动开发:内核注册并监控对象回调》所使用的方式是一样的都是使用ObRegisterCallbacks注册回调事件,只不过上一篇博文中LyShark将回调结构体OB_OPERATION_REGISTRATION中的ObjectType填充为了PsProcessType和PsThreadType格式从而实现监控进程与线程,本章我们需要将该结构填充为IoFileObjectType以此来实现对文件的监控,文件过滤驱动不仅仅可以用来监控文件的打开,还可以用它实现对文件的保护,一旦驱动加载则文件是不可被删除和改动的。
王 瑞
2022/11/14
4980
驱动开发:内核监控FileObject文件回调
6.8 Windows驱动开发:内核枚举Registry注册表回调
在笔者上一篇文章《内核枚举LoadImage映像回调》中LyShark教大家实现了枚举系统回调中的LoadImage通知消息,本章将实现对Registry注册表通知消息的枚举,与LoadImage消息不同Registry消息不需要解密只要找到CallbackListHead消息回调链表头并解析为_CM_NOTIFY_ENTRY结构即可实现枚举。
王 瑞
2023/12/02
3320
6.8 Windows驱动开发:内核枚举Registry注册表回调
windows内核提权,又一突破游戏进程保护的方法
当一个进程被保护的时候 比如无法获取其进程句柄权限 (OpenProcess) 或者无法获取内存读写访问权限的时候,则可以使用此方法来进行提权。
IBinary
2023/07/24
1.9K0
windows内核提权,又一突破游戏进程保护的方法
驱动开发:内核枚举IoTimer定时器
今天继续分享内核枚举系列知识,这次我们来学习如何通过代码的方式枚举内核IoTimer定时器,内核定时器其实就是在内核中实现的时钟,该定时器的枚举非常简单,因为在IoInitializeTimer初始化部分就可以找到IopTimerQueueHead地址,该变量内存储的就是定时器的链表头部。枚举IO定时器的案例并不多见,即便有也是无法使用过时的,此教程学到肯定就是赚到了。
王 瑞
2022/11/18
5560
驱动开发:内核枚举IoTimer定时器
驱动开发:内核RIP劫持实现DLL注入
本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用CreateRemoteThread直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过劫持EIP的方式实现,其实现原理可总结为,挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,并把相关的指令机器码和数据拷贝到里面去,然后直接修改目标进程EIP使其强行跳转到我们拷贝进去的相关机器码位置,执行相关代码后,然后再次跳转回来执行原始指令集。
王 瑞
2023/10/11
1.2K0
驱动开发:内核RIP劫持实现DLL注入
7.2 Windows驱动开发:内核注册并监控对象回调
在笔者上一篇文章《内核枚举进程与线程ObCall回调》简单介绍了如何枚举系统中已经存在的进程与线程回调,本章LyShark将通过对象回调实现对进程线程的句柄监控,在内核中提供了ObRegisterCallbacks回调,使用这个内核回调函数,可注册一个对象回调,不过目前该函数只能监控进程与线程句柄操作,通过监控进程或线程句柄,可实现保护指定进程线程不被终止的目的。
王 瑞
2023/12/02
7750
7.2 Windows驱动开发:内核注册并监控对象回调
Windows Kernel-crash 回调(写入有效的二次数据)
为KbCallbackSecondaryDumpData 指定要写入二次数据,CallbackRoutine此时为BugCheckSecondaryDumpDataCallback
franket
2020/05/10
13K0
7.6 Windows驱动开发:内核监控FileObject文件回调
本篇文章与上一篇文章《内核注册并监控对象回调》所使用的方式是一样的都是使用ObRegisterCallbacks注册回调事件,只不过上一篇博文中LyShark将回调结构体OB_OPERATION_REGISTRATION中的ObjectType填充为了PsProcessType和PsThreadType格式从而实现监控进程与线程,本章我们需要将该结构填充为IoFileObjectType以此来实现对文件的监控,文件过滤驱动不仅仅可以用来监控文件的打开,还可以用它实现对文件的保护,一旦驱动加载则文件是不可被删除和改动的。
王 瑞
2023/12/02
6580
7.6 Windows驱动开发:内核监控FileObject文件回调
进程强杀
我们知道在windows操作系统里面有ring0跟ring3的概念(ring1、ring2在windows中并未使用),因为ring0的特权级别是比ring3高的,那么我们肯定不能在ring3调用windows提供的api杀死ring0特权级别的进程,那么这时候我们就需要使用的ring0的函数来强行结束一些处于ring0级别的进程。
红队蓝军
2022/03/04
2.1K0
进程强杀
4.3 Windows驱动开发:监控进程与线程对象操作
在内核中,可以使用ObRegisterCallbacks这个内核回调函数来实现监控进程和线程对象操作。通过注册一个OB_CALLBACK_REGISTRATION回调结构体,可以指定所需的回调函数和回调的监控类型。这个回调结构体包含了回调函数和监控的对象类型,还有一个Altitude字段,用于指定回调函数的优先级。优先级越高的回调函数会先被调用,如果某个回调函数返回了一个非NULL值,后续的回调函数就不会被调用。
王 瑞
2023/11/18
8860
4.3 Windows驱动开发:监控进程与线程对象操作
6.4 Windows驱动开发:内核枚举DpcTimer定时器
在操作系统内核中,DPC(Deferred Procedure Call)是一种延迟执行的过程调用机制,用于在中断服务例程(ISR)的上下文之外执行一些工作。DPC定时器是基于DPC机制的一种定时执行任务的方式。
王 瑞
2023/11/28
6690
6.4 Windows驱动开发:内核枚举DpcTimer定时器
驱动开发:内核远程线程实现DLL注入
在笔者上一篇文章《内核RIP劫持实现DLL注入》介绍了通过劫持RIP指针控制程序执行流实现插入DLL的目的,本章将继续探索全新的注入方式,通过NtCreateThreadEx这个内核函数实现注入DLL的目的,需要注意的是该函数在微软系统中未被导出使用时需要首先得到该函数的入口地址,NtCreateThreadEx函数最终会调用ZwCreateThread,本章在寻找函数的方式上有所不同,前一章通过内存定位的方法得到所需地址,本章则是通过解析导出表实现。
王 瑞
2023/06/25
5300
驱动开发:内核远程线程实现DLL注入
驱动开发:内核RIP劫持实现DLL注入
本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用CreateRemoteThread直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过劫持EIP的方式实现,其实现原理可总结为,挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,并把相关的指令机器码和数据拷贝到里面去,然后直接修改目标进程EIP使其强行跳转到我们拷贝进去的相关机器码位置,执行相关代码后,然后再次跳转回来执行原始指令集。
王 瑞
2023/06/16
1K0
驱动开发:内核RIP劫持实现DLL注入
驱动开发:对象回调监控文件访问
无论在用户层还是内核层,操作文件的流程基本一致,除了在API函数上的区别(用户层调用用户层API,内核层调用内核API)以外其他基本一致,先讲解一下文件系统执行的流程。实现文件的监控呢,比如当文件被访问时自动触发回调,看如下代码实现方式。
王 瑞
2022/12/28
2720
驱动开发:内核枚举进程与线程ObCall回调
在笔者上一篇文章《驱动开发:内核枚举Registry注册表回调》中我们通过特征码定位实现了对注册表回调的枚举,本篇文章LyShark将教大家如何枚举系统中的ProcessObCall进程回调以及ThreadObCall线程回调,之所以放在一起来讲解是因为这两中回调在枚举是都需要使用通用结构体_OB_CALLBACK以及_OBJECT_TYPE所以放在一起来讲解最好不过。
王 瑞
2022/11/14
3120
驱动开发:内核枚举进程与线程ObCall回调
驱动开发:内核注册并监控对象回调
在笔者上一篇文章《驱动开发:内核枚举进程与线程ObCall回调》简单介绍了如何枚举系统中已经存在的进程与线程回调,本章LyShark将通过对象回调实现对进程线程的句柄监控,在内核中提供了ObRegisterCallbacks回调,使用这个内核回调函数,可注册一个对象回调,不过目前该函数只能监控进程与线程句柄操作,通过监控进程或线程句柄,可实现保护指定进程线程不被终止的目的。
王 瑞
2022/11/14
6320
驱动开发:内核注册并监控对象回调
x32下PsSetLoadImageNotifyRoutine的逆向
纯属兴趣爱好.特来逆向玩玩. PsSetLoadImageNotifyRoutine 是内核中用来监控模块加载.操作系统给我们提供的回调. 我们只需要填写对应的回调函数原型即可进行加监控. 既然可以进行监控.那么我们的回调函数存储在哪.这是个问题.所以特来逆向玩玩.
IBinary
2019/08/06
9310
驱动开发:挂接SSDT内核钩子
SSDT 中文名称为系统服务描述符表,该表的作用是将Ring3应用层与Ring0内核层,两者的API函数连接起来,起到承上启下的作用,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基址、服务函数个数等,SSDT 通过修改此表的函数地址可以对常用 Windows 函数进行内核级的Hook,从而实现对一些核心的系统动作进行过滤、监控的目的,接下来将演示如何通过编写简单的驱动程序,来实现搜索 SSDT 函数的地址,并能够实现简单的内核 Hook 挂钩。
王 瑞
2022/12/20
8880
驱动开发:挂接SSDT内核钩子
相关推荐
6.7 Windows驱动开发:内核枚举LoadImage映像回调
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验