首页
论坛
课程
招聘
[原创]内核层自己发送IRP请求操作文件全面总结(已完整调试, x86/x64各系统通用)
2020-12-8 00:30 11495

[原创]内核层自己发送IRP请求操作文件全面总结(已完整调试, x86/x64各系统通用)

2020-12-8 00:30
11495
收藏
点赞12
打赏
分享
最新回复 (46)
雪    币: 221
活跃值: 活跃值 (1183)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
章鱼C 活跃值 2020-12-21 14:50
26
0
我印象中ntfs PG是会扫的 你可以查一下
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-21 17:22
27
0
章鱼C 我印象中ntfs PG是会扫的 你可以查一下
我查了下,Patch Guard是针对内核模块: ntoskrnl.exe的,而文件系统驱动:ntfs.sys/fastfat.sys PG会忽略的。
当然也不排除以后的系统微软可能要增加对文件系统的Patch Guard
雪    币: 6597
活跃值: 活跃值 (2056)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 1 2020-12-21 17:29
28
0
低调putchar 我查了下,Patch Guard是针对内核模块: ntoskrnl.exe的,而文件系统驱动:ntfs.sys/fastfat.sys PG会忽略的。 当然也不排除以后的系统微软可能要增加对文件系统 ...
引用某个大佬的pg_context,现在的pg今非昔比了

       0   : A generic data region
       1   : Modification of a function or .pdata
       2   : A processor IDT
       3   : A processor GDT
       4   : Type 1 process list corruption
       5   : Type 2 process list corruption
       6   : Debug routine modification
       7   : Critical MSR modification
       8   : Object type
       9   : A processor IVT
       a   : Modification of a system service function
       b   : A generic session data region
       c   : Modification of a session function or .pdata
       d   : Modification of an import table
       e   : Modification of a session import table
       f   : Ps Win32 callout modification
       10  : Debug switch routine modification
       11  : IRP allocator modification
       12  : Driver call dispatcher modification
       13  : IRP completion dispatcher modification
       14  : IRP deallocator modification
       15  : A processor control register
       16  : Critical floating point control register modification
       17  : Local APIC modification
       18  : Kernel notification callout modification
       19  : Loaded module list modification
       1a  : Type 3 process list corruption
       1b  : Type 4 process list corruption
       1c  : Driver object corruption
       1d  : Executive callback object modification
       1e  : Modification of module padding
       1f  : Modification of a protected process
       20  : A generic data region
       21  : A page hash mismatch
       22  : A session page hash mismatch
       23  : Load config directory modification
       24  : Inverted function table modification
       25  : Session configuration modification
       26  : An extended processor control register
       27  : Type 1 pool corruption
       28  : Type 2 pool corruption
       29  : Type 3 pool corruption
       2a  : Type 4 pool corruption
       2b  : Modification of a function or .pdata
       2c  : Image integrity corruption
       2d  : Processor misconfiguration
       2e  : Type 5 process list corruption
       2f  : Process shadow corruption
       101 : General pool corruption
       102 : Modification of win32k.sys
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-21 19:12
29
0
hhkqqs 引用某个大佬的pg_context,现在的pg今非昔比了 “ 0 : A generic data region 1 : Modification of a ...
IRP钩子修改的是nt!_DRIVER_OBJECT驱动对象的内容,Win10的x64系统上会触发PG.
再试试inline Hook钩子。这个应该是修改的ntfs.sys里面的内容了。
雪    币: 221
活跃值: 活跃值 (1183)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
章鱼C 活跃值 2020-12-21 19:22
30
0
低调putchar IRP钩子修改的是nt!_DRIVER_OBJECT驱动对象的内容,Win10的x64系统上会触发PG. 再试试inline Hook钩子。这个应该是修改的ntfs.sys里面的内容了。
刚问了一下 的确扫 PG3还是PG4就开始了 我没记错
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-21 19:52
31
0
章鱼C 刚问了一下 的确扫 PG3还是PG4就开始了 我没记错

嗯!在WIN10 1809 x64下测试了下,可以确定:
1)替换驱动对象(nt!_DRIVER_OBJECT)的分发函数是要触发PG
2)inline hook 驱动对象的分发函数(只HOOK位于ntfs.sys地址空间的分发函数)目前正在测试。

如果实在不行,先暂时只有在32位下玩了。


挂了inline hook的虚拟机等它跑起,我先去忙别的了,过1个多钟头再来看。

最后于 2020-12-21 19:55 被低调putchar编辑 ,原因:
雪    币: 221
活跃值: 活跃值 (1183)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
章鱼C 活跃值 2020-12-21 20:51
32
0
低调putchar 章鱼C 刚问了一下 的确扫 PG3还是PG4就开始了 我没记错 嗯!在WIN10 1809 x64下测试了下,可以确定:1) ...
PG有快速测试的方法 调那个时间函数 叫什么来着我忘记了
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-21 21:07
33
0
章鱼C PG有快速测试的方法 调那个时间函数 叫什么来着我忘记了
WIN10 X64上还是不行!微软已经把ntfs.sys的PG校验加起了。
在WIN7X64 SP0,SP1上还可以试试,PG比较旧。
雪    币: 221
活跃值: 活跃值 (1183)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
章鱼C 活跃值 2020-12-21 21:30
34
0
低调putchar WIN10 X64上还是不行!微软已经把ntfs.sys的PG校验加起了。 在WIN7X64 SP0,SP1上还可以试试,PG比较旧。
win7不会扫的 正常来说
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-21 22:56
35
0
章鱼C win7不会扫的 正常来说
实际也测试了,win7 x64 PG不会扫ntfs。只能在win7及以下的系统64位hook ntfs的话,64位应用就受到限制了。
接触64位时间不长! 就算积累点经验吧!多谢提示!
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-21 23:02
36
0

这里还是顺便提供一个64位 hook ntfs的完整例子吧!不过只能在Win7 X64上跑

注: inline hook部分已改进,不用考虑线程同步, 性能和稳定性提升了

#include <ntddk.h>
//一个未公开的内核API函数,直接声明一下就可以用了
NTKERNELAPI
NTSTATUS NTAPI ObReferenceObjectByName(
	IN PUNICODE_STRING ObjectName,
	IN ULONG Attributes,
	OUT PACCESS_STATE AccessState OPTIONAL,
	IN ACCESS_MASK DesiredAccess,
	IN POBJECT_TYPE ObjectType OPTIONAL,
	IN KPROCESSOR_MODE AccessMode,
	IN PVOID ParseContext OPTIONAL,
	OUT PVOID *Object
);

extern POBJECT_TYPE *IoDriverObjectType;

//0: 表示编译inline hook, 1: 表示编译IRP hook
#define _IRP_HOOK 0

//
// 函数声明
//
NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT pDriverObject,
	IN PUNICODE_STRING punsReg
);

VOID DriverUnload(
	IN PDRIVER_OBJECT pDriverObject
);


//钩子函数
NTSTATUS HookedDispatchDirectoryControl(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
);

//中转函数(类似32位inline hook中的__declspec(naked)裸函数功能,必须保证至少容纳24字节)
//在hook时,前12字节被替换为: g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]的前12个字节节
//然后: mov rax, imm64(机器码: 48 b8 64位立即数)
//jmp rax(机器码: ff e0)
//在hook时, imm64被替换为: (ULONG_PTR)g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]+12
NTSTATUS NakedDispatchDirectoryControl(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
);

typedef NTSTATUS(NTAPI *lpfnDispatchFunc)(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
);

PDRIVER_OBJECT g_pNtfsDriver = NULL;
lpfnDispatchFunc g_sysDispatchDirectoryControl = NULL;
FAST_MUTEX g_fastMutex;
UCHAR g_oldCode[12];

//
// 指定函数所在节
//
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)

//inline hook
VOID InlineHook(VOID);

//inline unhook
VOID UnInlineHook(VOID);

//关闭写保护
VOID CloseWriteProtect(KIRQL *kSavedIrql);

//恢复写保护
VOID RestoreWriteProtect(KIRQL kSavedIrql);

//
// 函数声明
//
NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT pDriverObject,
	IN PUNICODE_STRING punsReg
)
{
	NTSTATUS ntStatus;
	UNICODE_STRING unsObjectName;

	ExInitializeFastMutex(&g_fastMutex);

	//获得ntfs驱动对象指针
	RtlInitUnicodeString(&unsObjectName,
		L"\\FileSystem\\Ntfs");
	ntStatus = ObReferenceObjectByName(&unsObjectName,
		OBJ_CASE_INSENSITIVE,
		NULL,
		FILE_READ_DATA | FILE_WRITE_DATA,
		*IoDriverObjectType,
		KernelMode,
		NULL,
		(PVOID*)&g_pNtfsDriver);

	if (NT_SUCCESS(ntStatus)) {
		DbgPrint("Succeeded to ObReferenceObjectByName[DriverEntry]!\n");
		
#if _IRP_HOOK
		//IRP Hook
		g_sysDispatchDirectoryControl = (lpfnDispatchFunc)InterlockedExchangePointer(
			(PVOID*)&g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL],
			(PVOID)HookedDispatchDirectoryControl);
#else
		//inline Hook
		InlineHook();
#endif

		ObDereferenceObject((PVOID)g_pNtfsDriver);
#if _IRP_HOOK
		pDriverObject->DriverUnload = DriverUnload;
#endif
	}else {
		DbgPrint("Failed to ObReferenceObjectByName[DriverEntry]!Status: 0x%08X\n", ntStatus);
	}

	return ntStatus;
}

VOID DriverUnload(
	IN PDRIVER_OBJECT pDriverObject
)
{
	DbgPrint("DriverUnload...\n");

	if (g_pNtfsDriver != NULL) {
#if _IRP_HOOK
	    InterlockedExchangePointer((PVOID*)&g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL],
			(PVOID)g_sysDispatchDirectoryControl);
#endif
	}

	return;
}

//钩子函数
NTSTATUS HookedDispatchDirectoryControl(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
)
{
	NTSTATUS ntStatus;

	//执行前过滤
	//... 	
#if _IRP_HOOK
	// 转去执行ntfs的派遣例程
	ntStatus = g_sysDispatchDirectoryControl(pDeviceObject,
		pIrp);
#else
	//
	// 执行中转函数(类似32位inline hook的裸函数),最终转去执行ntfs的原来的派遣例程功能(这里作了改进,不用考虑线程同步)
	//
	ntStatus = NakedDispatchDirectoryControl(pDeviceObject,
		pIrp);
#endif
	
    //执行后的过滤
	//...  

	return ntStatus;
}

//中转函数(类似32位inline hook中的__declspec(naked)裸函数功能,必须保证至少容纳24字节)
//在hook时,前12字节被替换为: g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]的前12个字节节
//然后: mov rax, imm64(机器码: 48 b8 64位立即数)
//jmp rax(机器码: ff e0)
//在hook时, imm64被替换为: (ULONG_PTR)g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]+12
NTSTATUS NakedDispatchDirectoryControl(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
)
{
	//这里随便实现一些功能(hook时函数头会被替换,以下内容不会执行),只是起到保证函数体长度不少于24字节的作用
	NTSTATUS ntStatus;
	ULONG i;
	ULONG a[24];

	DbgPrint("Before reverse: \n");
	for (i = 0; i < 24; i++) {
		a[i] = i;
		DbgPrint("%u\n",a[i]);
	}

	for (i = 0; i < 12; i++) {
		a[i] ^= a[23 - i];
		a[23 - i] ^= a[i];
		a[i] ^= a[23 - i];
	}

	DbgPrint("After reverse: \n");
	for (i = 0; i < 24; i++) {
		DbgPrint("%u\n", a[i]);
	}

	ntStatus = pIrp->IoStatus.Status;
	return ntStatus;
}

//inline hook
VOID InlineHook(VOID)
{
	//mov rax,imm64 (机器码: 48 b8 64位立即数)
	//jmp rax(机器码: ff e0)
	UCHAR ucCode[12] = { 0x48,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0 },  //imm64: 为钩子函数HookedDispatchDirectoryControl地址
		  ucCodeNaked[12] = { 0x48,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0 }; //imm64: 为ntfs派遣例程地址+12
	ULONGLONG ullAddr;
	KIRQL kSavedIrql;

	//保存ntfs派遣例程的前12字节指令集
	/*
	    WIN7 SP0
	        PAGE:00000000000B1680                 mov     [rsp+arg_0], rbx
        PAGE:00000000000B1685                 mov     [rsp+arg_8], rdx
        PAGE:00000000000B168A                 push    rsi
        PAGE:00000000000B168B                 push    rdi
	*/
	/*
	    WIN7 SP1
	        PAGE:00000000000A97E0                 mov     [rsp+arg_0], rbx
        PAGE:00000000000A97E5                 mov     [rsp+arg_8], rdx
        PAGE:00000000000A97EA                 push    rsi
        PAGE:00000000000A97EB                 push    rdi
	*/
	RtlCopyMemory(g_oldCode,
		g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL],
		12);

	//钩子派遣例程地址
	ullAddr = (ULONGLONG)HookedDispatchDirectoryControl; 
	RtlCopyMemory(&ucCode[2],
		&ullAddr,
		8);

	//ntfs派遣例程地址的12字节偏处
	ullAddr = (ULONGLONG)g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] + 12;
	RtlCopyMemory(&ucCodeNaked[2],
		&ullAddr,
		8);

	
    CloseWriteProtect(&kSavedIrql); //关闭写保护(自实现的中断请求级别提升及CR0的bit16置0)
	
	//Patch掉NakedDispatchDirectoryControl的前24字节
	//调用时, 先执行ntfs派遣例程原来的12字节指令集,然后跳转到ntfs派遣例程+12处,发挥类似裸函数的功能
	RtlCopyMemory(NakedDispatchDirectoryControl,
		g_oldCode,
		12); 
	RtlCopyMemory((PUCHAR)NakedDispatchDirectoryControl + 12,
		ucCodeNaked,
		12); 

	//修改ntfs派遣例程前12字节,以便跳转到我们的钩子函数
	RtlCopyMemory(g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL],
		ucCode,
		12);  
	
	RestoreWriteProtect(kSavedIrql); //恢复写保护(自实现的中断请求级别恢复及CR0bit16置1)

	return;
}

//inline unhook
VOID UnInlineHook(VOID)
{
	KIRQL kSavedIrql;

	CloseWriteProtect(&kSavedIrql); //关闭写保护(自实现的中断请求级别提升及CR0的bit16置0)
	RtlCopyMemory(g_pNtfsDriver->MajorFunction[IRP_MJ_DIRECTORY_CONTROL],
		g_oldCode,
		12); //恢复派遣例程前12字节
	RestoreWriteProtect(kSavedIrql); //恢复写保护 (自实现的中断请求级别恢复及CR0bit16置1)

	return;
}

//关闭写保护
VOID CloseWriteProtect(KIRQL *kSavedIrql)
{
	ULONGLONG ullCR0;
	*kSavedIrql = KeRaiseIrqlToDpcLevel();
	_disable();
	ullCR0 = __readcr0();
	ullCR0 &= 0xFFFFFFFFFFFEFFFF;
	__writecr0(ullCR0);
    return;
}

//恢复写保护
VOID RestoreWriteProtect(KIRQL kSavedIrql)
{
	ULONGLONG ullCR0;
	ullCR0 = __readcr0();
	ullCR0 |= 0x10000;
	__writecr0(ullCR0);
	_enable();
	KeLowerIrql(kSavedIrql);
	return;
}


最后于 2020-12-24 08:35 被低调putchar编辑 ,原因:
雪    币: 221
活跃值: 活跃值 (1183)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
章鱼C 活跃值 2020-12-22 07:32
37
0
低调putchar 实际也测试了,win7 x64 PG不会扫ntfs。只能在win7及以下的系统64位hook ntfs的话,64位应用就受到限制了。 接触64位时间不长! 就算积累点经验吧!多谢提示!
建议没必要花过多时间研究32位 工作中用不到 实际中也基本用不到
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-22 09:15
38
0
章鱼C 建议没必要花过多时间研究32位 工作中用不到 实际中也基本用不到
嗯!32位的用户比较少了,基本是维护原来的,现在新的地方主要用64位。
雪    币: 14
活跃值: 活跃值 (158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ZwTrojan 活跃值 2020-12-22 11:03
39
0
俺是小白,请问这些函数可以起什么作用呢
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-22 20:37
40
1
沉醉星渊 谢谢大佬,我去研究一下
我做事情喜欢有始有终!昨天临时验证PG问题,代码是都是当时现写的,有些匆忙。
趁今晚有时间作了该进,64位inline hook可以不用考虑线程同步了,只需Patch掉自己的一个中转函数即可,你注意看一下。性能和稳定性有了提升。不过: 只能在WIN7 64位下运行, WIN10上会触发PG。
好了!这个问题先告一段落了!
雪    币: 112
活跃值: 活跃值 (49)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
dragonwang 活跃值 2020-12-27 22:57
41
0
低调putchar 我做事情喜欢有始有终!昨天临时验证PG问题,代码是都是当时现写的,有些匆忙。 趁今晚有时间作了该进,64位inline hook可以不用考虑线程同步了,只需Patch掉自己的一个中转函数即可,你注意 ...
主贴的内容没有hook吧,是不是win10 64位可以通用,比方说写个ark小工具之类的可以放心用吧?
雪    币: 2658
活跃值: 活跃值 (2055)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-12-27 23:12
42
0
dragonwang 主贴的内容没有hook吧,是不是win10 64位可以通用,比方说写个ark小工具之类的可以放心用吧?

主题总结的是向文件系统卷设备自行发送IRP(x86/x64各Windows系统通用)。
评论时,有人问及NTFS:IRP HOOK/inline Hook的例子,就在回复中给了个WIN7 64位下HOOK NTFS的例子。由于涉及PG的问题,目前不能通用。

最后于 2020-12-27 23:14 被低调putchar编辑 ,原因:
雪    币: 611
活跃值: 活跃值 (737)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
绝望的皮卡丘 活跃值 2020-12-28 11:43
43
0
hhkqqs 膜拜,看原理应该跟pchunter差不多,绕过ssdt函数直接自行下发irp[em_63]
能给个Pchunter的代码吗
雪    币: 6597
活跃值: 活跃值 (2056)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 1 2020-12-29 00:26
44
0
绝望的皮卡丘 能给个Pchunter的代码吗
我又不是作者哪來的源碼
雪    币: 2389
活跃值: 活跃值 (869)
能力值: ( LV4,RANK:56 )
在线值:
发帖
回帖
粉丝
VirtualCC 活跃值 2021-7-27 00:54
45
0

当你通过IrpCreateFile指定ShareAccess时,应该仅传递FILE_SHARE_VALID_FLAGS,否则删除某些共享访问的文件时,会出现STATUS_SHARING_VIOLATION。微软官方文档解释: 

A file cannot be opened because the share access flags are incompatible.

Also, the proper way to specify "share all" is FILE_SHARE_VALID_FLAGS, not 0 (which means "share none").

以下是示例代码:

status = IrpCreateFile(&FileObject,
		&DeviceObject,
		FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,
		fileName,
		&ioStatus,
		NULL,
		FILE_ATTRIBUTE_NORMAL,
		FILE_SHARE_VALID_FLAGS,
		FILE_OPEN,
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL,
		0);


雪    币: 179
活跃值: 活跃值 (118)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
RootkitsNt 活跃值 2021-8-13 21:36
46
0
win11移植读写会蓝屏
雪    币: 186
活跃值: 活跃值 (880)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wem 活跃值 2021-11-30 18:58
47
0
great
游客
登录 | 注册 方可回帖
返回