驱动笔记之二:一个成功的驱动程序与应用程序通信的实例(命名管道方式)

经过多次测试,一个笨拙的驱动程序和应用程序通信的实例终于完成了!我不会用 minifilter,所以就用了 named pipe 来解决。

代码如下:

1
2
3
4
5
// --- MessageThread.h

#include "wdm.h"

void MessageWorkerEntry(IN PVOID);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// --- 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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// --- 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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// --- 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;
}

就可以了。

要点:

  1. 打开命名管道的时候要在 ObjAttr 中使用 OBJ_KERNEL_HANDLE,使其附加在系统进程([System])里。
  2. ZwCreateFileZwWriteFile 必须处于同一个线程中。(我之前尝试用 PsCreateSystemThreadlpContext 来传递 hPipe,结果 ZwWriteFile 返回 STATUS_INVALID_HANDLE(此时的 hPipe 为2位~4位16进制码)。

服务器端代码如下(我保证只会有一个线程调用 ZwWriteFile,所以我没考虑同步的问题):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#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。

运行结果如下:

Sc

分享到 评论