要控制流量大概是在 IoCompletion 里面返回 STATUS_MORE_PROCESSING_REQUIRED 然后投递一个 WorkItem 到某个工作线程里面去,然后在那工作线程里面多 Sleep 一会儿再 IoCompleteRequest?
[FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 280, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 280, Sent: 413 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 57 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 4, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 57 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 4, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 280, Sent: 413 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 57 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 4, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 280, Sent: 596 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 239 bytes / s Received: 70948 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 4, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 239 bytes / s Received: 8927920 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 4, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 12346060 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 8163876 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 9287056 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 3076616 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 7026796 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 9108028 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 3158352 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 5285124 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 10047148 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 11329012 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 13408224 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 13795512 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 16626816 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 4, Sent: 201 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 13855816 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 20182288 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 14285852 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 14093656 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 17039600 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 18342860 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 16822336 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 14925796 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 17185912 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 17422724 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 14773376 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 13452628 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 20832756 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 280, Sent: 17 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 2674734 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1132, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 2674734 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 1588, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 4, Sent: 0 bytes / s Received: 0 bytes / s. [FlowWatcher] DumpNetworkUsage: Process Id: 4, Sent: 0 bytes / s Received: 0 bytes / s.
// #define PROJECT_NAME "FlowWatcher" // #define NETWORK_USAGE_DUMP_INTERVAL 1000 // #define MILLISECOND_TO_KERNEL_DELAY(Millisecond) (-1LL * (Millisecond) * 1000 * 10) // #define MILLISECOND_TO_SECOND(Millisecond) ((Millisecond) / 1000) // #define ATTACHING_DEVICE_EXTENSION(DeviceObject) ((PATTACHING_DEVICE_EXTENSION)((DeviceObject)->DeviceExtension)) // #define NETWORK_USAGE_GENERIC_TABLE_NODE_TAG 'NUGT' // #define TCP_DEVICE_NAME L"\\Device\\Tcp" // #define UDP_DEVICE_NAME L"\\Device\\Udp" // #define RAWIP_DEVICE_NAME L"\\Device\\RawIp" // #define CountOf(Array) ((sizeof(Array) / sizeof((Array)[0]))) // typedef struct _NETWORK_USAGE_INFORMATION { // ULONGLONG BytesSent; // ULONGLONG BytesReceived; // typedef struct _NETWORK_USAGE_GENERIC_TABLE_NODE { // PEPROCESS Process; // NETWORK_USAGE_INFORMATION NetworkUsageInformation; // typedef struct _NETWORK_USAGE_GENERIC_TABLE { // RTL_GENERIC_TABLE Table; // KSPIN_LOCK TableLock; // typedef struct _NETWORK_USAGE_DUMPER_CONTROL_BLOCK { // PETHREAD Worker; // BOOLEAN Exit; // KEVENT SleepingEvent; // typedef struct _DEVICE_ATTACH_STATE { // PDEVICE_OBJECT AttachingDevice; // PDEVICE_OBJECT AttachedDevice; // typedef struct _ATTACHING_DEVICE_EXTENSION { // DEVICE_ATTACH_STATE AttachState; // typedef struct _DEVICE_ATTACHMENT { // UNICODE_STRING TargetDeviceName; // PDEVICE_OBJECT AttachingDevice; // #define DbgWrite(Format, ...) DbgPrint("[" PROJECT_NAME "] " __FUNCTION__ ": " Format, __VA_ARGS__) // NETWORK_USAGE_DUMPER_CONTROL_BLOCK NetworkUsageDumperControlBlock; // NETWORK_USAGE_GENERIC_TABLE NetworkUsageGenericTable; // DEVICE_ATTACHMENT DeviceAttachments[] = { // PDRIVER_OBJECT FlowWatcherDriverObject; // RTL_GENERIC_COMPARE_ROUTINE NetworkUsageGenericTableComparaRoutine; VOID InitializeNetworkUsageGenericTable( NTSTATUS AttachDevice( NTSTATUS CreateAndAttachDevice( VOID DetachDevice( VOID DeleteAndDetachDevice( NTSTATUS AttachDevices( VOID DetachDevices( NTSTATUS CreateNetworkUsageDumper( VOID TerminateNetworkUsageDumper( // #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(PAGE, DriverUnload) #endif // RTL_GENERIC_COMPARE_RESULTS NTAPI NetworkUsageGenericTableComparaRoutine( LeftNode = (PNETWORK_USAGE_GENERIC_TABLE_NODE)FirstObject; // if (LeftNode->Process < RightNode->Process) { // PVOID NTAPI NetworkUsageGenericTableAllocateRoutine( // VOID NTAPI NetworkUsageGenericTableFreeRoutine( return; // VOID InitializeNetworkUsageGenericTable( KeInitializeSpinLock(&NetworkUsageGenericTable.TableLock); // RtlInitializeGenericTable(&NetworkUsageGenericTable.Table, return; // VOID DeleteNetworkUsageGenericTableUnsafe( // for (CurrentEntry = RtlEnumerateGenericTable(&NetworkUsageGenericTable.Table, TRUE); // DeleteStatus = RtlDeleteElementGenericTable(&NetworkUsageGenericTable.Table, CurrentEntry); ASSERT(DeleteStatus == TRUE); return; // VOID DeleteNetworkUsageGenericTable( // KeAcquireInStackQueuedSpinLock(&NetworkUsageGenericTable.TableLock, // DeleteNetworkUsageGenericTableUnsafe(); // KeReleaseInStackQueuedSpinLock(&LockHandle); return; // BOOLEAN QueryProcessNetworkUsageUnsafe( TableNode.Process = Process; // EntryFound = RtlLookupElementGenericTable(&NetworkUsageGenericTable.Table, if (!EntryFound) { // *NetworkUsageInformation = ((PNETWORK_USAGE_GENERIC_TABLE_NODE)EntryFound)->NetworkUsageInformation; return TRUE; // BOOLEAN QueryProcessNetworkUsage( // KeAcquireInStackQueuedSpinLock(&NetworkUsageGenericTable.TableLock, // Status = QueryProcessNetworkUsageUnsafe(Process, NetworkUsageInformation); // KeReleaseInStackQueuedSpinLock(&LockHandle); if (Status != TRUE) { return Status; // VOID UpdateProcessNetworkUsageUnsafe( TableNode.Process = Process; // EntryFound = RtlLookupElementGenericTable(&NetworkUsageGenericTable.Table, if (EntryFound) { Status = RtlDeleteElementGenericTable(&NetworkUsageGenericTable.Table, EntryFound); ASSERT(Status == TRUE); // (VOID)RtlInsertElementGenericTable(&NetworkUsageGenericTable.Table, return; // VOID UpdateProcessNetworkUsage( // KeAcquireInStackQueuedSpinLock(&NetworkUsageGenericTable.TableLock, // UpdateProcessNetworkUsageUnsafe(Process, NetworkUsageInformation); // KeReleaseInStackQueuedSpinLock(&LockHandle); return; // VOID DumpNetworkUsage( // KeAcquireInStackQueuedSpinLock(&NetworkUsageGenericTable.TableLock, // for (CurrentEntry = RtlEnumerateGenericTable(&NetworkUsageGenericTable.Table, TRUE); TableNode = (PNETWORK_USAGE_GENERIC_TABLE_NODE)CurrentEntry; Process = TableNode->Process; // DbgWriteLine("Process Id: %4d, Sent: %10I64d bytes / s Received: %10I64d bytes / s.", // DeleteNetworkUsageGenericTableUnsafe(); // KeReleaseInStackQueuedSpinLock(&LockHandle); return; // VOID NetworkUsageDumper( PAGED_CODE(); // ControlBlock = (PNETWORK_USAGE_DUMPER_CONTROL_BLOCK)Context; while (!ControlBlock->Exit) { // DumpInterval.QuadPart = MILLISECOND_TO_KERNEL_DELAY(NETWORK_USAGE_DUMP_INTERVAL); (VOID)KeWaitForSingleObject((PVOID)&ControlBlock->SleepingEvent, Executive, KernelMode, // DumpNetworkUsage(); return; // NTSTATUS AttachDevice( // Status = IoAttachDevice(AttachingDevice, DeviceName, &DeviceAttachState->AttachedDevice); if (!NT_SUCCESS(Status)) { // DeviceAttachState->AttachingDevice = AttachingDevice; return Status; // NTSTATUS CreateAndAttachDevice( // Status = IoCreateDevice(FlowWatcherDriverObject, if (!NT_SUCCESS(Status)) { DeviceExtension = (PATTACHING_DEVICE_EXTENSION)LocalAttachingDevice->DeviceExtension; // Status = AttachDevice(&DeviceExtension->AttachState, LocalAttachingDevice, DeviceName); if (!NT_SUCCESS(Status)) { return Status; // *AttachingDevice = LocalAttachingDevice; return Status; // VOID DetachDevice( // IoDetachDevice(DeviceAttachState->AttachedDevice); return; // VOID DeleteAndDetachDevice( // DetachDevice(DeviceAttachState); // IoDeleteDevice(DeviceAttachState->AttachingDevice); return; // NTSTATUS AttachDevices( // for (DeviceIndex = 0; DeviceIndex < CountOf(DeviceAttachments); DeviceIndex++) {
ULONG DeviceIndex2;
//
// 附加到该设备上。
//
Status = CreateAndAttachDevice(&DeviceAttachments[DeviceIndex].AttachingDevice,
&DeviceAttachments[DeviceIndex].TargetDeviceName);
if (!NT_SUCCESS(Status)) {
//
// 撤销已经成功的附加操作。
//
for (DeviceIndex2 = 0; DeviceIndex2 < DeviceIndex; DeviceIndex2++) {
//
// 分离设备并删除创建的设备。
//
DeleteAndDetachDevice(&ATTACHING_DEVICE_EXTENSION(
DeviceAttachments[DeviceIndex2].AttachingDevice)->AttachState); break; return Status; // VOID DetachDevices( PAGED_CODE(); // for (DeviceIndex = 0; DeviceIndex < CountOf(DeviceAttachments); DeviceIndex++) {
//
// 分离设备并删除创建的设备。
//
DeleteAndDetachDevice(&ATTACHING_DEVICE_EXTENSION(
DeviceAttachments[DeviceIndex].AttachingDevice)->AttachState); return; // NTSTATUS CreateNetworkUsageDumper( // NetworkUsageDumperControlBlock.Exit = FALSE; // KeInitializeEvent(&NetworkUsageDumperControlBlock.SleepingEvent, NotificationEvent, FALSE); // Status = PsCreateSystemThread(&ThreadHandle, 0, NULL, 0, NULL, NetworkUsageDumper, if (!NT_SUCCESS(Status)) { // Status = ObReferenceObjectByHandle(ThreadHandle, 0, *PsThreadType, KernelMode, ZwClose(ThreadHandle); if (!NT_SUCCESS(Status)) { return Status; return Status; // VOID TerminateNetworkUsageDumper( // NetworkUsageDumperControlBlock.Exit = TRUE; // KeSetEvent(&NetworkUsageDumperControlBlock.SleepingEvent, 0, TRUE); // KeWaitForSingleObject((PVOID)NetworkUsageDumperControlBlock.Worker, Executive, KernelMode, return; // VOID AnalyzeNetworkIrp( IoStackLocation = IoGetCurrentIrpStackLocation(Irp); ASSERT(IoStackLocation->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL); Process = PsGetCurrentProcess(); if (QueryProcessNetworkUsage(Process, &NetworkUsageInformation) == FALSE) { // NetworkUsageInformation.BytesReceived = 0; if (IoStackLocation->MinorFunction == TDI_RECEIVE) { Parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&IoStackLocation->Parameters; // NetworkUsageInformation.BytesReceived += Parameters->ReceiveLength; Parameters = (PTDI_REQUEST_KERNEL_SEND)&IoStackLocation->Parameters; // NetworkUsageInformation.BytesSent += Parameters->SendLength; Parameters = (PTDI_REQUEST_KERNEL_RECEIVEDG)&IoStackLocation->Parameters; // NetworkUsageInformation.BytesReceived += Parameters->ReceiveLength; Parameters = (PTDI_REQUEST_KERNEL_SENDDG)&IoStackLocation->Parameters; // NetworkUsageInformation.BytesSent += Parameters->SendLength; // UpdateProcessNetworkUsage(Process, &NetworkUsageInformation); return; // NTSTATUS GeneralPassthroughDispath( ASSERT(ATTACHING_DEVICE_EXTENSION(DeviceObject)); LowerDeviceObject = ATTACHING_DEVICE_EXTENSION(DeviceObject)->AttachState.AttachedDevice; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); // if (IoStackLocation->MajorFunction == IRP_MJ_DEVICE_CONTROL) { // (VOID)TdiMapUserRequest(DeviceObject, Irp, IoStackLocation); // if (IoStackLocation->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) { // IoSkipCurrentIrpStackLocation(Irp); // return IoCallDriver(LowerDeviceObject, Irp); // NTSTATUS DriverEntry( FlowWatcherDriverObject = DriverObject; // DriverObject->DriverUnload = DriverUnload; for (MajorFunctionIndex = 0; MajorFunctionIndex <= IRP_MJ_MAXIMUM_FUNCTION;
MajorFunctionIndex++) {
DriverObject->MajorFunction[MajorFunctionIndex] = GeneralPassthroughDispath; // InitializeNetworkUsageGenericTable(); // Status = AttachDevices(); if (!NT_SUCCESS(Status)) { // Status = CreateNetworkUsageDumper(); if (!NT_SUCCESS(Status)) { return Status; return Status; // VOID DriverUnload( // TerminateNetworkUsageDumper(); // DetachDevices(); // DeleteNetworkUsageGenericTable(); return;#include
#include
// 驱动名称。
//
// 输出网络使用情况的间隔,单位毫秒。
//
// 由于 MILLISECOND_TO_SECOND 在将毫秒转换为秒时可能会有精度损失
// 因此此处最好是整数秒。
//
// 毫秒转换为内核下的等待时长。
//
// 内核下的等待时长为负数时表示超时间隔为相对时长,单位是纳秒。
//
// 有关于内核下的等待时长(即 KeWaitForSingleObject 的 Timeout 参数),参考
// http://msdn.microsoft.com/en-us/library/windows/hardware/ff553350(v=vs.85).aspx。
//
// 毫秒转换为秒。
//
// 此处是整除,若不是整数秒,则会有精度损失。
//
// 获取用于附加操作的设备的设备扩展。
//
// 用于记录网络使用信息的通用表的节点的缓冲池标记。
//
// TDI 的 TCP 设备名。
//
// TDI 的 UDP 设备名。
//
// TDI 的 RAW IP 设备名。
//
// 计算静态数组中的元素个数。
//
// 单进程的网络使用的统计信息。
//
// 自从上次输出统计信息后发送的字节数。
//
// 每次输出统计信息都会清空发送字节数。
//
// 自从上次输出统计信息后接受的字节数。
//
// 每次输出统计信息都会清空接受字节数。
//
} NETWORK_USAGE_INFORMATION, *PNETWORK_USAGE_INFORMATION;
// 储存在通用表中的节点。
//
// 进程的 PCB 指针。
//
// 在通用表中存放时,用于比较结构体相对大小使用的就是 Process 成员。
//
// 进程的网络使用信息。
//
} NETWORK_USAGE_GENERIC_TABLE_NODE, *PNETWORK_USAGE_GENERIC_TABLE_NODE;
// 用于统计进程网络使用信息的表。
//
// 用于记录信息的通用表。
//
// 用于同步访问的自旋锁。
//
} NETWORK_USAGE_GENERIC_TABLE, *PNETWORK_USAGE_GENERIC_TABLE;
// 输出网络使用情况的工作线程控制块。
//
// 工作线程的指针。
//
// 为 TRUE 时要求工作线程退出。
//
// 输出网络使用情况的工作线程每隔 NETWORK_USAGE_DUMP_INTERVAL 毫秒
// 输出一次。如果直接使用 KeDelayExecutionThread,那么在 DriverUnload
// 中等待工作线程退出最多会需要大约 NETWORK_USAGE_DUMP_INTERVAL
// 毫秒的时间。当 NETWORK_USAGE_DUMP_INTERVAL 增大时,DriverUnload
// 可能会需要相当长的等待时间。
//
// 考虑到 DriverUnload 是由系统的工作线程调用的,因此应当尽快返回。
// 所以此处令工作线程等待 SleepingEvent。SleepingEvent 除非在 Exit
// 为 TRUE 的时候才会置为信号态。这样,在驱动退出之前。等待 SleepingEvent
// 的结果总是会超时,这样也就实现了 KeDelayExecutionThread 的效果,
// 而 DriverUnload 中将 SleepingEvent 置为信号态,这样等待就会立即
// 结束,从而让工作线程立即退出。
//
// 如果将来 WDK 提供了类似 KeAlertThread 的例程,则可以考虑使用
// KeDelayExecutionThread + KeAlertThread 的组合。
//
// 同样,通过投递 APC 也可以唤醒工作线程,但是为了唤醒线程而投递
// APC 并非一个好的选择。
//
} NETWORK_USAGE_DUMPER_CONTROL_BLOCK, *PNETWORK_USAGE_DUMPER_CONTROL_BLOCK;
// 附加到设备的操作的状态。
//
// 用于附加操作所创建的设备。
//
// 附加到的设备。
//
// 由于我们是附加到目标设备之上,因此此设备也是紧挨我们下层的设备。
//
} DEVICE_ATTACH_STATE, *PDEVICE_ATTACH_STATE;
// 用于附加操作所创建的设备的设备扩展。
//
// 用于描述附加操作的状态。
//
} ATTACHING_DEVICE_EXTENSION, *PATTACHING_DEVICE_EXTENSION;
// 用于描述附加操作的数据结构。
//
// 要附加到的设备的设备名。
//
// 为附加操作创建的设备对象。
//
} DEVICE_ATTACHMENT, *PDEVICE_ATTACHMENT;
// 输出调试信息。
//
#define DbgWriteLine(Format, ...) DbgWrite(Format "\n", __VA_ARGS__)
// 输出网络使用情况的工作线程的控制块。
//
// 统计网络使用状况的表。
//
// 需要进行的附加驱动的操作。
//
{RTL_CONSTANT_STRING(TCP_DEVICE_NAME), 0},
{RTL_CONSTANT_STRING(UDP_DEVICE_NAME), 0},
{RTL_CONSTANT_STRING(RAWIP_DEVICE_NAME), 0}
};
// 驱动对象。
//
// 函数原型声明。
//
RTL_GENERIC_ALLOCATE_ROUTINE NetworkUsageGenericTableAllocateRoutine;
RTL_GENERIC_FREE_ROUTINE NetworkUsageGenericTableFreeRoutine;
DRIVER_DISPATCH GeneralPassthroughDispath;
DRIVER_INITIALIZE DriverEntry;
DRIVER_UNLOAD DriverUnload;
KSTART_ROUTINE NetworkUsageDumper;
VOID
);
__out PDEVICE_ATTACH_STATE DeviceAttachState,
__in PDEVICE_OBJECT AttachingDevice,
__in PUNICODE_STRING DeviceName
);
__out PDEVICE_OBJECT *AttachingDevice,
__in PUNICODE_STRING DeviceName
);
__in PDEVICE_ATTACH_STATE DeviceAttachState
);
__in PDEVICE_ATTACH_STATE DeviceAttachState
);
VOID
);
VOID
);
VOID
);
VOID
);
// 将函数关联到对应的代码段。
//
#pragma alloc_text(INIT, InitializeNetworkUsageGenericTable)
#pragma alloc_text(INIT, CreateNetworkUsageDumper)
#pragma alloc_text(INIT, AttachDevice)
#pragma alloc_text(INIT, CreateAndAttachDevice)
#pragma alloc_text(INIT, AttachDevices)
#pragma alloc_text(PAGE, TerminateNetworkUsageDumper)
#pragma alloc_text(PAGE, NetworkUsageDumper)
#pragma alloc_text(PAGE, DetachDevice)
#pragma alloc_text(PAGE, DeleteAndDetachDevice)
#pragma alloc_text(PAGE, DetachDevices)
// 用于比较两个 NETWORK_USAGE_GENERIC_TABLE_NODE 的比较函数。
//
__in PRTL_GENERIC_TABLE GenericTable,
__in PVOID FirstObject,
__in PVOID SecondObject
)
{
PNETWORK_USAGE_GENERIC_TABLE_NODE LeftNode, RightNode;
RightNode = (PNETWORK_USAGE_GENERIC_TABLE_NODE)SecondObject;
// 此处使用 NETWORK_USAGE_GENERIC_TABLE_NODE::Process 来比较结构体的大小。
//
return GenericLessThan;
} else if (LeftNode->Process > RightNode->Process) {
return GenericGreaterThan;
} else {
return GenericEqual;
}
}
// 用于分配 NETWORK_USAGE_GENERIC_TABLE_NODE 的函数。
//
__in PRTL_GENERIC_TABLE GenericTable,
__in CLONG BufferSize
)
{
return ExAllocatePoolWithTag(NonPagedPool, BufferSize, NETWORK_USAGE_GENERIC_TABLE_NODE_TAG);
}
// 用于释放 NETWORK_USAGE_GENERIC_TABLE_NODE 的函数。
//
__in PRTL_GENERIC_TABLE GenericTable,
__in PVOID Buffer
)
{
ExFreePoolWithTag(Buffer, NETWORK_USAGE_GENERIC_TABLE_NODE_TAG);
}
// 初始化统计网络使用情况的通用表。
//
VOID
)
{
//
// 初始化用于同步访问的自旋锁。
//
// 初始化用于记录信息的通用表。
//
NetworkUsageGenericTableComparaRoutine,
NetworkUsageGenericTableAllocateRoutine,
NetworkUsageGenericTableFreeRoutine,
NULL);
}
// 释放统计网络使用情况的通用表(不上锁)。
//
VOID
)
{
PVOID CurrentEntry;
// 逐个删除元素。
//
CurrentEntry;
CurrentEntry = RtlEnumerateGenericTable(&NetworkUsageGenericTable.Table, FALSE)) {
BOOLEAN DeleteStatus;
// 删除元素。
//
}
}
// 释放统计网络使用情况的通用表。
//
VOID
)
{
KLOCK_QUEUE_HANDLE LockHandle;
PVOID CurrentEntry;
// 获取自旋锁。
//
&LockHandle);
// 清空通用表。
//
// 释放自旋锁。
//
}
// 获取某进程的网络使用情况(不上锁)。
//
__in PEPROCESS Process,
__out PNETWORK_USAGE_INFORMATION NetworkUsageInformation
)
{
NETWORK_USAGE_GENERIC_TABLE_NODE TableNode;
PVOID EntryFound;
// 查询使用情况。
//
(PVOID)&TableNode);
return FALSE;
}
// 返回信息。
//
}
// 获取某进程的网络使用情况。
//
__in PEPROCESS Process,
__out PNETWORK_USAGE_INFORMATION NetworkUsageInformation
)
{
KLOCK_QUEUE_HANDLE LockHandle;
BOOLEAN Status;
// 获取自旋锁。
//
&LockHandle);
// 查询使用情况。
//
// 释放自旋锁。
//
return Status;
}
}
// 更新某进程的网络使用情况(不上锁)。
//
__in PEPROCESS Process,
__in PNETWORK_USAGE_INFORMATION NetworkUsageInformation
)
{
NETWORK_USAGE_GENERIC_TABLE_NODE TableNode;
PVOID EntryFound;
TableNode.NetworkUsageInformation = *NetworkUsageInformation;
// 删除已有节点。
//
(PVOID)&TableNode);
BOOLEAN Status;
}
// 插入新节点。
//
(PVOID)&TableNode, sizeof(NETWORK_USAGE_GENERIC_TABLE_NODE), NULL);
}
// 更新某进程的网络使用情况。
//
__in PEPROCESS Process,
__in PNETWORK_USAGE_INFORMATION NetworkUsageInformation
)
{
KLOCK_QUEUE_HANDLE LockHandle;
// 获取自旋锁。
//
&LockHandle);
// 更新网络使用情况。
//
// 释放自旋锁。
//
}
// 输出网络使用情况的统计信息。
//
VOID
)
{
KLOCK_QUEUE_HANDLE LockHandle;
PVOID CurrentEntry;
// 获取自旋锁。
//
&LockHandle);
// 遍历统计网络使用情况的通用表。
//
CurrentEntry;
CurrentEntry = RtlEnumerateGenericTable(&NetworkUsageGenericTable.Table, FALSE)) {
PNETWORK_USAGE_GENERIC_TABLE_NODE TableNode;
PEPROCESS Process;
NETWORK_USAGE_INFORMATION NetworkUsageInformation;
NetworkUsageInformation = TableNode->NetworkUsageInformation;
// 输出信息。
//
// DbgPrint 在输出 64 位整数时似乎不能识别 %lld(至少不能识别 %10lld),因此
// 此处使用 %I64d。
//
PsGetProcessId(Process),
NetworkUsageInformation.BytesSent / MILLISECOND_TO_SECOND(NETWORK_USAGE_DUMP_INTERVAL),
NetworkUsageInformation.BytesReceived / MILLISECOND_TO_SECOND(NETWORK_USAGE_DUMP_INTERVAL));
}
// 清空统计数据。
//
// 释放自旋锁。
//
}
// 用于输出当前网络使用情况的工作线程。
//
__in PVOID Context
)
{
PNETWORK_USAGE_DUMPER_CONTROL_BLOCK ControlBlock;
// 获得控制块指针。
//
LARGE_INTEGER DumpInterval;
// 每隔 NETWORK_USAGE_DUMP_INTERVAL 毫秒输出一次统计信息。
//
// 有关于 SleepingEvent 的使用,参考 NETWORK_USAGE_DUMPER_CONTROL_BLOCK
// 的定义。
//
FALSE, &DumpInterval);
// 输出统计信息。
//
}
}
// 附加到指定设备。
//
__out PDEVICE_ATTACH_STATE DeviceAttachState,
__in PDEVICE_OBJECT AttachingDevice,
__in PUNICODE_STRING DeviceName
)
{
NTSTATUS Status;
// 附加到指定设备。
//
return Status;
}
// 填充附加状态信息。
//
}
// 创建一个设备对象并将其附加到指定的设备上。
//
__out PDEVICE_OBJECT *AttachingDevice,
__in PUNICODE_STRING DeviceName
)
{
PATTACHING_DEVICE_EXTENSION DeviceExtension;
PDEVICE_OBJECT LocalAttachingDevice;
NTSTATUS Status;
// 创建用于附加操作的设备对象。
//
sizeof(ATTACHING_DEVICE_EXTENSION), NULL, FILE_DEVICE_NETWORK, 0, FALSE,
&LocalAttachingDevice);
return Status;
}
// 将设备附加到指定的设备上。
//
IoDeleteDevice(LocalAttachingDevice);
}
// 将新创建的设备对象返回给调用方。
//
}
// 从之前附加到的设备上分离。
//
__in PDEVICE_ATTACH_STATE DeviceAttachState
)
{
PAGED_CODE();
// 分离。
//
}
// 从之前附加到的设备上分离并释放为附加操作创建的设备对象。
//
__in PDEVICE_ATTACH_STATE DeviceAttachState
)
{
PAGED_CODE();
// 分离设备。
//
// 删除设备。
//
}
// 附加到各个(TCP / UDP / RAW IP) TDI 驱动的设备对象上。
//
VOID
)
{
ULONG DeviceIndex;
NTSTATUS Status;
// 附加到 TDI 的设备上。
//
}
}
}
}
// 从 TDI 的各个设备对象上分离。
//
VOID
)
{
ULONG DeviceIndex;
// 撤销附加到 TDI 的设备的操作。
//
}
}
// 创建用于输出网络使用情况的线程。
//
VOID
)
{
HANDLE ThreadHandle;
NTSTATUS Status;
// 初始化线程控制块。
//
// 用于线程休眠的事件。
//
// 创建线程。
//
(PVOID)&NetworkUsageDumperControlBlock);
return Status;
}
// 获得线程的 ETHREAD。
//
(PVOID *)&NetworkUsageDumperControlBlock.Worker, NULL);
NetworkUsageDumperControlBlock.Exit = TRUE;
KeSetEvent(&NetworkUsageDumperControlBlock.SleepingEvent, 0, FALSE);
}
}
// 结束用于输出网络使用情况的线程。
//
VOID
)
{
PAGED_CODE();
// 通知线程退出。
//
// 唤醒线程。
//
// 等待线程退出。
//
FALSE, NULL);
}
// 用于统计进程的网络使用情况。
//
// 此处只能处理 IRP_MJ_INTERNAL_DEVICE_CONTROL 类型的 IRP,对于
// IRP_MJ_DEVICE_CONTROL,需要使用 TdiMapUserRequest 将其映射为
// IRP_MJ_INTERNAL_DEVICE_CONTROL 类型的 IRP。
//
__in PIRP Irp
)
{
PEPROCESS Process;
PIO_STACK_LOCATION IoStackLocation;
NETWORK_USAGE_INFORMATION NetworkUsageInformation;
// 若查询不到当前进程的网络使用情况,则表示通用表中还没有这个进程
// 相关的表项,那么就将该进程的网络使用情况初始化成 0。
//
NetworkUsageInformation.BytesSent = 0;
}
PTDI_REQUEST_KERNEL_RECEIVE Parameters;
// 统计接受的字节数。
//
} else if (IoStackLocation->MinorFunction == TDI_SEND) {
PTDI_REQUEST_KERNEL_SEND Parameters;
// 统计发送的字节数。
//
} else if (IoStackLocation->MinorFunction == TDI_RECEIVE_DATAGRAM) {
PTDI_REQUEST_KERNEL_RECEIVEDG Parameters;
// 统计接受的字节数。
//
} else if (IoStackLocation->MinorFunction == TDI_SEND_DATAGRAM) {
PTDI_REQUEST_KERNEL_SENDDG Parameters;
// 统计发送的字节数。
//
}
// 更新进程的网络使用情况。
//
}
// 通用的传递 IRP 到下层驱动的派遣函数。
//
__in PDEVICE_OBJECT DeviceObject,
__inout PIRP Irp
)
{
PDEVICE_OBJECT LowerDeviceObject;
PIO_STACK_LOCATION IoStackLocation;
// 对于 IRP_MJ_DEVICE_CONTROL 类型请求,将其转换为 IRP_MJ_INTERNAL_DEVICE_CONTROL
// 类型后再处理。
//
// 若转换失败,则 IRP 依然是 IRP_MJ_DEVICE_CONTROL 类型,那么就不会被提交给
// AnalyzeNetworkIrp 做进一步处理。
//
// 由于稍后会再次判断 IRP 的类型,因此此处可以忽略 TdiMapUserRequest 的返回值。
//
}
// 若是 IRP_MJ_INTERNAL_DEVICE_CONTROL 类型请求,则记录进程的网络使用情况。
//
AnalyzeNetworkIrp(Irp);
}
// 跳过当前 IRP 参数栈。
//
// 下发 IRP。
//
}
// 驱动入口点。
//
__inout PDRIVER_OBJECT DriverObject,
__in PUNICODE_STRING RegistryPath
)
{
ULONG MajorFunctionIndex;
NTSTATUS Status;
// 填充回调表。
//
}
// 初始化记录进程网络使用情况的通用表。
//
// 附加到 TDI 的设备对象上。
//
return Status;
}
// 创建输出网络使用信息的线程。
//
DetachDevices();
}
}
// 驱动卸载回调。
//
__in PDRIVER_OBJECT DriverObject
)
{
PAGED_CODE();
// 结束输出网络使用情况的线程。
//
// 从 TDI 的设备对象上分离。
//
// 释放用于统计进程网络使用情况的通用表。
//
}
Update at 19:24 2012/8/21:
似乎应该在 IoAttachDevice 之前去掉 DeviceObject->Flags 中的 DO_DEVICE_INITIALIZING,同时要把 TDI 的 DeviceObject 的 Flags 复制过来。
另外用 Timer Object 要比用 Event 来的合理。
发表回复