经过多次测试,一个笨拙的驱动程序和应用程序通信的实例终于完成了!我不会用 minifilter,所以就用了 named pipe 来解决。
代码如下:
// --- MessageThread.h
#include "wdm.h"
void MessageWorkerEntry(IN PVOID);
// --- MessageThread.cpp
#include "MessageThread.h"
#include "KernelPipe.h"
extern KEVENT keMsg;
void MessageWorkerEntry(IN PVOID pvContext)
{
HANDLE hPipe = NULL;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
PWCHAR pwszPipeName = L"\\??\\pipe\\HelloPipe";
UNICODE_STRING uniPipeName={0};
OBJECT_ATTRIBUTES ObjAttr={0};
IO_STATUS_BLOCK IoStatus={0};
KdPrint(("In MessageWorkerEntry."));
RtlInitUnicodeString(&uniPipeName,pwszPipeName);
InitializeObjectAttributes(&ObjAttr,&uniPipeName,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);
KdPrint(("Pipe name: %wZ", uniPipeName));
ns = ZwCreateFile(
&hPipe, // File handle
FILE_WRITE_DATA | SYNCHRONIZE, // Desired access
&ObjAttr, // Attributes
&IoStatus, // IO Status Block
NULL, // Allocation size
0, // File attributes
FILE_SHARE_READ | FILE_SHARE_WRITE, //File share
FILE_OPEN, // Create disposition (must exist)
//FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,// Create options
FILE_SYNCHRONOUS_IO_NONALERT,
NULL, // EA buffer
0 ); // EA size
KdPrint(("Open status: 0x%x", ns));
KdPrint(("Pipe handle: %p", hPipe));
if (NT_SUCCESS(ns))
{
ns = ZwSetNamedPipeState(hPipe, FILE_PIPE_MESSAGE_TYPE | FILE_PIPE_MESSAGE_MODE);
KdPrint(("ZwSetNamedPipeState status: 0x%x", ns));
}
IO_STATUS_BLOCK isb;
LARGE_INTEGER li;
ns = STATUS_UNSUCCESSFUL;
li.HighPart = -1;
li.LowPart = FILE_WRITE_TO_END_OF_FILE;
int i = 0;
char ch[] = "This is some sort of test message.";
for ( i=0; i<10; i++ )
{
ns = ZwWriteFile(hPipe, NULL, NULL, NULL, &isb, ch, (ULONG)strlen(ch), NULL, NULL);
KdPrint(("ZwWriteFile status: 0x%x", ns));
}
KeSetEvent(&keMsg, 0, 0);
ZwClose(hPipe);
PsTerminateSystemThread(STATUS_SUCCESS);
}
// --- KernelPipe.h
#include "wdm.h"
#include "basetsd.h"
#include "ntdef.h"
//#include "ntifs.h"
#define FILE_PIPE_MESSAGE_MODE 0x00000001
#define FILE_PIPE_MESSAGE_TYPE 0x00000001
#define FILE_PIPE_QUEUE_OPERATION 0x00000000
#define FSCTL_PIPE_ASSIGN_EVENT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_DISCONNECT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_PEEK CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_DATA)
#define FSCTL_PIPE_QUERY_EVENT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_TRANSCEIVE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
#define FSCTL_PIPE_WAIT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_IMPERSONATE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_SET_CLIENT_PROCESS CTL_CODE(FILE_DEVICE_NAMED_PIPE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_QUERY_CLIENT_PROCESS CTL_CODE(FILE_DEVICE_NAMED_PIPE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_GET_PIPE_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_SET_PIPE_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 11, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_SET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_GET_HANDLE_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 14, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_SET_HANDLE_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_PIPE_FLUSH CTL_CODE(FILE_DEVICE_NAMED_PIPE, 16, METHOD_BUFFERED, FILE_WRITE_DATA)
#pragma comment(lib,"ntifs.lib")
extern "C"
__drv_maxIRQL(PASSIVE_LEVEL)
NTSYSAPI
NTSTATUS
NTAPI
ZwFsControlFile(
__in HANDLE FileHandle,
__in_opt HANDLE Event,
__in_opt PIO_APC_ROUTINE ApcRoutine,
__in_opt PVOID ApcContext,
__out PIO_STATUS_BLOCK IoStatusBlock,
__in ULONG FsControlCode,
__in_bcount_opt(InputBufferLength) PVOID InputBuffer,
__in ULONG InputBufferLength,
__out_bcount_opt(OutputBufferLength) PVOID OutputBuffer,
__in ULONG OutputBufferLength
);
/*
extern "C"
__kernel_entry NTSYSCALLAPI
NTSTATUS
NTAPI
NtWriteFile (
__in HANDLE FileHandle,
__in_opt HANDLE Event,
__in_opt PIO_APC_ROUTINE ApcRoutine,
__in_opt PVOID ApcContext,
__out PIO_STATUS_BLOCK IoStatusBlock,
__in_bcount(Length) PVOID Buffer,
__in ULONG Length,
__in_opt PLARGE_INTEGER ByteOffset,
__in_opt PULONG Key
);
*/
#pragma pack(push,1)
/*
typedef unsigned long ULONG, ULONG32;
typedef unsigned short USHORT;
typedef unsigned char UINT8;
*/
typedef struct _WAIT_PIPE_PARAM
{
__int64 liTimeOutvalue;
ULONG ulPipeNameLen;
USHORT bUsTimeoutValue;
} WAIT_PIPE_PARAM,*PWAIT_PIPE_PARAM;
typedef struct _NAMED_PIPE_CREATE_PARAMETERS
{
ULONG32 NamedPipeType;
ULONG32 ReadMode;
ULONG32 CompletionMode;
ULONG32 MaximumInstances;
ULONG32 InboundQuota;
ULONG32 OutboundQuota;
LARGE_INTEGER DefaultTimeout;
UINT8 TimeoutSpecified;
UINT8 _PADDING0_[0x7];
} NAMED_PIPE_CREATE_PARAMETERS, *PNAMED_PIPE_CREATE_PARAMETERS;
#pragma pack(pop)
#define WAIT_FORVER (0x8000000000000000)
#define PIPE_ACCESS_DUPLEX (3)
NTSTATUS ZwCreateNamedPipeFile (
OUT PHANDLE phPipeHandle,
IN ULONG ulDesiredAccess,
IN POBJECT_ATTRIBUTES pObjAttr,
OUT PIO_STATUS_BLOCK pIoStatus,
IN ULONG ulShareAccess,
IN ULONG ulCreateDisposition,
IN ULONG ulCreateOptions,
IN BOOLEAN bIsMsgType,
IN BOOLEAN bIsMsgMode,
IN BOOLEAN bIsNonBlocking,
IN ULONG ulMaximumInstances,
IN ULONG ulInBufSize,
IN ULONG ulOutBufSize,
IN PLARGE_INTEGER pliDefaultTimeout OPTIONAL );
NTSTATUS __stdcall ZwCreateNamedPipe(PWCHAR pwszPipeName,
ULONG ulMaxInBufSize,
ULONG ulMaxOutBufSize,
ULONG ulMaxClientCount,
PLARGE_INTEGER liTimeOut,
PHANDLE phPipe);
NTSTATUS __stdcall ZwConnectNamedPipe(HANDLE hPipe);
NTSTATUS __stdcall ZwDisconnectNamedPipe(HANDLE hPipe);
NTSTATUS __stdcall ZwSetNamedPipeState(HANDLE hPipe,ULONG ulMode);
NTSTATUS __stdcall ZwWaitNamedPipe(PUNICODE_STRING puniPipeName,LARGE_INTEGER liTimeOut);
// --- KernelPipe.cpp
#include "KernelPipe.h"
NTSTATUS ZwCreateNamedPipeFile (
OUT PHANDLE phPipeHandle,
IN ULONG ulDesiredAccess,
IN POBJECT_ATTRIBUTES pObjAttr,
OUT PIO_STATUS_BLOCK pIoStatus,
IN ULONG ulShareAccess,
IN ULONG ulCreateDisposition,
IN ULONG ulCreateOptions,
IN BOOLEAN bIsMsgType,
IN BOOLEAN bIsMsgMode,
IN BOOLEAN bIsNonBlocking,
IN ULONG ulMaximumInstances,
IN ULONG ulInBufSize,
IN ULONG ulOutBufSize,
IN PLARGE_INTEGER pliDefaultTimeout OPTIONAL )
{
NAMED_PIPE_CREATE_PARAMETERS NamedPipeParms={0};
NTSTATUS NtStatus={0};
__try
{
if ( pliDefaultTimeout )
{
NamedPipeParms.TimeoutSpecified = TRUE;
NamedPipeParms.DefaultTimeout.QuadPart = pliDefaultTimeout->QuadPart;
}
else
{
NamedPipeParms.TimeoutSpecified = FALSE;
}
NamedPipeParms.NamedPipeType = bIsMsgType;
NamedPipeParms.ReadMode = bIsMsgMode;
NamedPipeParms.CompletionMode = bIsNonBlocking;
NamedPipeParms.MaximumInstances = ulMaximumInstances;
NamedPipeParms.InboundQuota = ulInBufSize;
NamedPipeParms.OutboundQuota = ulOutBufSize;
NtStatus = IoCreateFile(
phPipeHandle,
ulDesiredAccess,
pObjAttr,
pIoStatus,
NULL,
0,
ulShareAccess,
ulCreateDisposition,
ulCreateOptions,
NULL,
0,
CreateFileTypeNamedPipe,
&NamedPipeParms,
0
);
return NtStatus;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
KdPrint (("ZwCreateNamedPipeFile: Exception occured.\n"));
return GetExceptionCode();
}
}
NTSTATUS __stdcall ZwCreateNamedPipe(PWCHAR pwszPipeName,
ULONG ulMaxInBufSize,
ULONG ulMaxOutBufSize,
ULONG ulMaxClientCount,
PLARGE_INTEGER pliTimeOut,
PHANDLE phPipe)
{
NTSTATUS NtStatus=STATUS_SUCCESS;
HANDLE hPipe=NULL;
UNICODE_STRING uniPipeName={0};
//ANSI_STRING ansiPipeName = {0};
OBJECT_ATTRIBUTES ObjAttr={0};
IO_STATUS_BLOCK IoStatus={0};
RtlInitUnicodeString(&uniPipeName,pwszPipeName);
InitializeObjectAttributes(&ObjAttr,&uniPipeName,OBJ_CASE_INSENSITIVE,NULL,NULL);
//RtlInitAnsiString(&ansiPipeName, pszPipeName);
//InitializeObjectAttributes(&ObjAttr,(ULONG)&ansiPipeName,OBJ_CASE_INSENSITIVE,NULL,NULL);
KdPrint(("Name in ZwCreateNamedPipe: %wZ", &uniPipeName));
NtStatus=ZwCreateNamedPipeFile(&hPipe,
FILE_ANY_ACCESS,
&ObjAttr,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
PIPE_ACCESS_DUPLEX,
FILE_PIPE_MESSAGE_TYPE,
FILE_PIPE_MESSAGE_MODE,
FILE_PIPE_QUEUE_OPERATION,//blocking mode
ulMaxClientCount,
ulMaxInBufSize,
ulMaxOutBufSize,
pliTimeOut);
if (NT_SUCCESS(NtStatus))
{
*phPipe=hPipe;
}
else
{
*phPipe=NULL;
}
return NtStatus;
}
NTSTATUS __stdcall ZwConnectNamedPipe(HANDLE hPipe)
{
NTSTATUS NtStatus=STATUS_SUCCESS;
IO_STATUS_BLOCK IoStatus={0};
NtStatus=ZwFsControlFile(hPipe,NULL,NULL,NULL,&IoStatus,FSCTL_PIPE_LISTEN,NULL,0,NULL,0);
return NtStatus;
}
NTSTATUS __stdcall ZwDisconnectNamedPipe(HANDLE hPipe)
{
NTSTATUS NtStatus=STATUS_SUCCESS;
IO_STATUS_BLOCK IoStatus={0};
NtStatus=ZwFsControlFile(hPipe,NULL,NULL,NULL,&IoStatus,FSCTL_PIPE_DISCONNECT,NULL,0,NULL,0);
return NtStatus;
}
NTSTATUS __stdcall ZwSetNamedPipeState(HANDLE hPipe,ULONG ulMode)
{
NTSTATUS NtStatus=STATUS_UNSUCCESSFUL;
ULONG aBuf[2]={0};
IO_STATUS_BLOCK IoStatus={0};
do
{
if ((0xFFFFFFFC & ulMode)==0)
{
break;
}
aBuf[0]=((ulMode>>1) & 1);
aBuf[1]=(ulMode & 1);
NtStatus=ZwSetInformationFile(hPipe, &IoStatus, aBuf, sizeof(aBuf), FilePipeInformation);
} while (FALSE);
return NtStatus;
}
NTSTATUS __stdcall ZwWaitNamedPipe(PUNICODE_STRING puniPipeName,LARGE_INTEGER liTimeOut)
{
NTSTATUS NtStatus=STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK IoStatus={0};
HANDLE hParent=NULL;
OBJECT_ATTRIBUTES Oa={0};
WCHAR aTmpBuf[512]={0};
PWAIT_PIPE_PARAM pWaitPipeParam=(PWAIT_PIPE_PARAM)aTmpBuf;
INT iShortNameOffset=wcslen(L"\\\\.\\pipe\\")*sizeof(WCHAR);
UNICODE_STRING uniPipeParentName={0};
do
{
if (!puniPipeName || puniPipeName->Length<iShortNameOffset)
{
NtStatus=STATUS_OBJECT_NAME_NOT_FOUND;
break;
}
RtlInitUnicodeString(&uniPipeParentName,L"\\DosDevices\\pipe\\");
InitializeObjectAttributes(&Oa,&uniPipeParentName,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
NtStatus=ZwOpenFile(&hParent,0x100080,&Oa,&IoStatus,FILE_SHARE_WRITE | FILE_SHARE_READ,32);
if (!NT_SUCCESS(NtStatus))
{
break;
}
pWaitPipeParam->liTimeOutvalue=liTimeOut.QuadPart;
pWaitPipeParam->bUsTimeoutValue=TRUE;
*((USHORT*)(&pWaitPipeParam->ulPipeNameLen))=puniPipeName->Length-iShortNameOffset;
RtlCopyMemory((PVOID)((ULONG_PTR)pWaitPipeParam+sizeof(WAIT_PIPE_PARAM)),&puniPipeName->Buffer[iShortNameOffset/sizeof(WCHAR)],pWaitPipeParam->ulPipeNameLen);
NtStatus=ZwFsControlFile(hParent,NULL,NULL,NULL,&IoStatus,FSCTL_PIPE_WAIT,&pWaitPipeParam,14+pWaitPipeParam->ulPipeNameLen,NULL,0);
} while (FALSE);
if (hParent)
{
ZwClose(hParent);
}
return NtStatus;
}
就可以了。
要点:
- 打开命名管道的时候要在
ObjAttr
中使用 OBJ_KERNEL_HANDLE
,使其附加在系统进程([System])里。
ZwCreateFile
和 ZwWriteFile
必须处于同一个线程中。(我之前尝试用 PsCreateSystemThread
的 lpContext
来传递 hPipe
,结果 ZwWriteFile
返回 STATUS_INVALID_HANDLE
(此时的 hPipe
为2位~4位16进制码)。
服务器端代码如下(我保证只会有一个线程调用 ZwWriteFile
,所以我没考虑同步的问题):
#include "SnoopyTester.h"
int main()
{
HANDLE hPipe = NULL;
BOOL fRead = FALSE;
DWORD i = 0;
DWORD dwBytesRead = 0;
char buffer[100] = {0};
hPipe = CreateNamedPipe("\\\\.\\pipe\\HelloPipe", PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT, 2, 100, 100, (DWORD)-1, NULL);
if ((hPipe) && (hPipe != INVALID_HANDLE_VALUE))
{
for ( i = 0; i <= MAXDWORD; i++ )
{
fRead = ReadFile(hPipe, buffer, 100, &dwBytesRead, NULL);
if (fRead || dwBytesRead)
{
printf("Message received: %s\n", buffer);
memset(buffer, 0, 100);
}
}
printf("Application ends.\n");
getchar();
return 0;
}
else
{
printf("Cannot create named pipe \\\\.\\pipe\\HelloPipe\n");
getchar();
return 0;
}
}
其中 SnoopyTester.h 包含了 stdio.h 和 windows.h。
运行结果如下: