1、创建进程、创建线程、加载模块回调
(1)创建进程回调
注册创建进程回调使用函数 PsSetCreateProcessNotifyRoutine,调用这个函数会将注册的信息保存到一个数组里面。
反汇编这个函数,会发现以下片段:
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 在该函数上可能的差异。。。得到以下信息:
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中的回调函数
系统中只允许设置一个这样的回调函数
有人跟着给出具体结构和定义:
typedef VOID (*PLEGO_NOTIFY_ROUTINE)( PKTHREAD Thread );
ULONG PsSetLegoNotifyRoutine( PLEGO_NOTIFY_ROUTINE LegoNotifyRoutine )
{
PAGED_CODE();
PspLegoNotifyRoutine = LegoNotifyRoutine;
return FIELD_OFFSET(KTHREAD,LegoData);
}
硬编码搜索到这个全局变量,查看地址是否为0即可(不知是否有误,或者加上地址有效检测?)
代码:
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。。。。
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
代码如下:
代码:
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
,查了一下,果然是。
也是一个链表头的形式,相关结构和定义:
代码:
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
结构:
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也是)元素的数组,每个都是一个链表,数据格式: 代码:
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 这个函数没有导出,我用了最烂的方法,遍历内核模块空间,根据特征码得到函数地址
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 删除。