首页 > 未分类 > 监听 IP 数据包

监听 IP 数据包

利用系统的 ipfltdrv.sys 实现的过滤器钩子驱动(Filter-Hook Drivers)。

测试前请确保 SystemRoot\System32\Drivers\ipfltdrv.sys 已经加载(存在设备 \Device\IpFilterdriver)。如果没有加载的话可以用各种加载驱动的工具来加载(比如 CoderuiInstDrv.exe)。

注意在回调里面,Packet 是包括了 TCP / UDP / IGMP / ICMP 的报头的(但是不包括 IP 报头。)。

[FilterHookDriver] DriverEntry: Driver loaded. Built time: Jun 29 2012 01:37:03.
[FilterHookDriver] PacketFilterCallbackProc: Sent a packet from 10.0.0.2 to 10.0.0.1 with length 8
[FilterHookDriver] PacketFilterCallbackProc: Sent a packet from 10.0.0.2 to 10.0.0.255 with length 8
[FilterHookDriver] PacketFilterCallbackProc: Received a packet from 10.0.0.2 to 10.0.0.255 with length 209
[FilterHookDriver] PacketFilterCallbackProc: Received a packet from 10.0.0.1 to 10.0.0.2 with length 1064
[FilterHookDriver] PacketFilterCallbackProc: Sent a packet from 10.0.0.2 to 10.0.0.1 with length 8
[FilterHookDriver] PacketFilterCallbackProc: Received a packet from 10.0.0.1 to 10.0.0.2 with length 1064
[FilterHookDriver] PacketFilterCallbackProc: Sent a packet from 10.0.0.2 to 10.0.0.1 with length 8
[FilterHookDriver] PacketFilterCallbackProc: Received a packet from 10.0.0.1 to 10.0.0.2 with length 1064
[FilterHookDriver] DriverUnload: Driver unloaded.

#include <ntddk.h>
#include <ntddndis.h>
#include <pfhook.h>
#include <ntstrsafe.h>

//
// 类型定义。
//

typedef struct _IP_HEADER {
  UCHAR HeaderVersion;
  UCHAR TypeOfService;
  USHORT PacketSize;
  USHORT PacketId;

  //
  // 分片偏移也在 Flags 中。参考 IP 报头。
  //

  USHORT Flags;
  UCHAR TimeToLive;
  UCHAR Protocol;
  USHORT Checksum;
  ULONG Source;
  ULONG Destination;
} IP_HEADER, *PIP_HEADER;

typedef PacketFilterExtensionPtr PACKET_FILTER_EXTENSION_PTR;

//
// 字符串形式的 IP 地址的最大长度。
//

#define STRING_ADDRESS_LENGTH 16

//
// 输出调试信息。
//

#define PROJECT_NAME "FilterHookDriver"

#define DbgWrite(Format, ...) DbgPrint("[" PROJECT_NAME "] " __FUNCTION__ ": " Format, __VA_ARGS__)
#define DbgWriteLine(Format, ...) DbgWrite(Format "\n", __VA_ARGS__)

//
// 修改指针位置。
//

#define PointerAdd(Pointer, Increment, Type) ((Type)((ULONG_PTR)(Pointer) + (Increment)))

//
// 计算静态数组中的元素个数。
//

#define CountOf(Array) ((sizeof(Array) / sizeof((Array)[0])))

//
// 过滤器驱动的设备对象名称。
//

#define IP_FILTER_DEVICE_NAME L"\\Device\\Ipfilterdriver"

//
// 函数原型。
//

DRIVER_INITIALIZE DriverEntry;

DRIVER_UNLOAD DriverUnload;

NTSTATUS OpenFilterDeviceObject(
  __out PDEVICE_OBJECT *DeviceObject
  );

NTSTATUS RegisterFilterCallback(
  __in PACKET_FILTER_EXTENSION_PTR FilterCallbackProc
  );

//
// 函数所属区段标记。
//

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)
#pragma alloc_text(PAGE, OpenFilterDeviceObject)
#pragma alloc_text(PAGE, RegisterFilterCallback)
#endif

//
// 将 ULONG 型 IP 地址转换为 xxx.xxx.xxx.xxx 形式的 IP 地址。
//
// StringAddress 的长度至少需要为 STRING_ADDRESS_LENGTH。
//

VOID ConvertNumericAddressToString(
  __out PUCHAR StringAddress,
  __in ULONG NumericAddress
  )
{
  ULONG CurrentPosition;
  ULONG Index;

  CurrentPosition = 0;

  //
  // 将 IP 地址按字节分开,分别转换为字符串写入 StringAddress。
  //

  for (Index = 0; Index < sizeof(ULONG); Index++) {
    LPTSTR DestinationEnd;
    UCHAR Current;
    NTSTATUS Status;

    //
    // 得到这一位的数值。
    //

    Current = *PointerAdd(&NumericAddress, Index, PUCHAR);

    //
    // 转换为字符串。
    //

    ASSERT(STRING_ADDRESS_LENGTH > CurrentPosition);

    Status = RtlStringCchPrintfExA(PointerAdd(StringAddress, CurrentPosition, PCHAR), 
      STRING_ADDRESS_LENGTH - CurrentPosition, &DestinationEnd, NULL, 0, "%d",
      Current);

    ASSERT(NT_SUCCESS(Status));

    CurrentPosition = (PUCHAR)DestinationEnd - StringAddress;

    //
    // 如果不是最后一段,则增加分隔符(“.”)。
    //

    if (Index != sizeof(ULONG) - 1) {
      StringAddress[CurrentPosition++] = '.';
    }
  }

  //
  // 末尾补 0。
  //

  StringAddress[CurrentPosition++] = 0;

  ASSERT(CurrentPosition <= STRING_ADDRESS_LENGTH);

  return;
}

//
// 过滤回调。
//
// Packet、PacketSize 均不包含 IP 报头。
//
// 本应为 PacketFilterExtensionPtr 类型,为了方便处理此处稍微有点变化。
// PacketFilterExtensionPtr 的定义参考 
// http://msdn.microsoft.com/en-us/library/windows/hardware/ff562312(v=vs.85).aspx。
//

PF_FORWARD_ACTION PacketFilterCallbackProc(
  __in PIP_HEADER Header,
  __in PUCHAR Packet,
  __in ULONG PacketSize,
  __in ULONG ReceiveInterfaceIndex,
  __in ULONG SendInterfaceIndex,
  __in PVOID ReceiveLinkNextHoop,
  __in PVOID SendLinkNextHoop
  )
{
  static const CHAR *OperationDescription[] = {"Sent", "Received"};

  UCHAR Source[STRING_ADDRESS_LENGTH], Destination[STRING_ADDRESS_LENGTH];
  ULONG OperationType;

  //
  // 将 IP 地址转换为字符串形式。
  //

  ConvertNumericAddressToString(Source, Header->Source);
  ConvertNumericAddressToString(Destination, Header->Destination);

  //
  // 获取操作类型。
  //
  // 如果 ReceiveInterfaceIndex 为 INVALID_PF_IF_INDEX,则表示当前过滤的是发送操作。
  // 如果 SendInterfaceIndex 为 INVALID_PF_IF_INDEX,则表示当前过滤的是接受操作。
  //
  // ReceiveInterfaceIndex 和 SendInterfaceIndex 中有且只可能有一个是 INVALID_PF_IF_INDEX。
  //

  ASSERT(((ReceiveInterfaceIndex == INVALID_PF_IF_INDEX ^
    SendInterfaceIndex == INVALID_PF_IF_INDEX)) == TRUE);

  if (ReceiveInterfaceIndex == INVALID_PF_IF_INDEX) {
    OperationType = 0;
  } else {
    OperationType = 1;
  }

  ASSERT(OperationType < CountOf(OperationDescription));

  //
  // 输出信息。
  //

  DbgWriteLine("%s a packet from %s to %s with length %d", OperationDescription[OperationType],
    Source, Destination, PacketSize);

  //
  // 放行。
  //

  return PF_FORWARD;
}

//
// 打开 IP 过滤器驱动的设备对象。
//
// 这个函数在返回之前会引用 IP 过滤器驱动的设备对象。稍后应释放引用。
//

NTSTATUS OpenFilterDeviceObject(
  __out PDEVICE_OBJECT *DeviceObject
  )
{
  UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(IP_FILTER_DEVICE_NAME);
  PDEVICE_OBJECT LocalDeviceObject;
  PFILE_OBJECT FileObject;
  NTSTATUS Status;

  PAGED_CODE();

  //
  // 获得设备对象的指针。
  //

  Status = IoGetDeviceObjectPointer(&DeviceName, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
    &FileObject, &LocalDeviceObject);

  if (!NT_SUCCESS(Status)) {
    return Status;
  }

  //
  // IoGetDeviceObjectPointer 只会引用 FileObject (FileObject 间接引用了 DeviceObject。)
  // 此处引用 DeviceObject 并释放对 FileObject 的引用。
  //

  ObReferenceObject((PVOID)LocalDeviceObject);
  ObDereferenceObject((PVOID)FileObject);

  //
  // 返回设备对象给调用方。
  //

  *DeviceObject = LocalDeviceObject;

  return Status;
}

//
// 注册过滤回调。
//
// FilterCallbackProc 输入 NULL 则会从过滤器驱动中清除已经注册的过滤回调。
//

NTSTATUS RegisterFilterCallback(
  __in PACKET_FILTER_EXTENSION_PTR FilterCallbackProc
  )
{
  PF_SET_EXTENSION_HOOK_INFO SetExtensionHookInfo;
  PDEVICE_OBJECT FilterDeviceObject;
  IO_STATUS_BLOCK IoStatusBlock;
  KEVENT Event;
  PIRP Irp;
  NTSTATUS Status;

  PAGED_CODE();

  //
  // 打开过滤器驱动的设备对象。
  //

  Status = OpenFilterDeviceObject(&FilterDeviceObject);

  if (!NT_SUCCESS(Status)) {
    return Status;
  }

  //
  // 填充注册信息。
  //

  SetExtensionHookInfo.ExtensionPointer = FilterCallbackProc;

  //
  // 初始化用于同步操作的事件。
  //

  KeInitializeEvent(&Event, NotificationEvent, FALSE);

  //
  // 构造 IRP。
  //

  Irp = IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER, FilterDeviceObject, 
    (PVOID)&SetExtensionHookInfo, sizeof(PF_SET_EXTENSION_HOOK_INFO), NULL, 0, FALSE,
    &Event, &IoStatusBlock);

  if (!Irp) {
    ObDereferenceObject((PVOID)FilterDeviceObject);

    return STATUS_INSUFFICIENT_RESOURCES;
  }

  //
  // 注册过滤回调。
  //

  Status = IoCallDriver(FilterDeviceObject, Irp);

  if (Status == STATUS_PENDING) {
    (VOID)KeWaitForSingleObject((PVOID)&Event, Executive, KernelMode, FALSE, NULL);

    Status = IoStatusBlock.Status;
  }

  //
  // 释放资源。
  //
  // IRP 会由过滤器驱动在 IoCompleteRequest 时被系统释放。
  //

  ObDereferenceObject((PVOID)FilterDeviceObject);

  if (!NT_SUCCESS(Status)) {
    return Status;
  }

  return Status;
}

//
// 入口点。
//

NTSTATUS DriverEntry(
  __in PDRIVER_OBJECT DriverObject,
  __in PUNICODE_STRING RegistryPath
  )
{
  NTSTATUS Status;

  UNREFERENCED_PARAMETER(RegistryPath);

  DbgWriteLine("Driver loaded. Built time: %s %s.", __DATE__, __TIME__);

  //
  // 填充回调函数。
  //

  DriverObject->DriverUnload = DriverUnload;

  //
  // 注册过滤回调。
  //

  Status = RegisterFilterCallback((PACKET_FILTER_EXTENSION_PTR)PacketFilterCallbackProc);

  if (!NT_SUCCESS(Status)) {
    DbgWriteLine("We failed to register our filter hook. Unloading.");

    return Status;
  }

  return Status;
}

//
// 卸载回调。
//

VOID DriverUnload(
  __in PDRIVER_OBJECT DriverObject
  )
{
  NTSTATUS Status;

  PAGED_CODE();

  //
  // 注销过滤回调。
  //

  Status = RegisterFilterCallback(NULL);

  ASSERT(NT_SUCCESS(Status));

  DbgWriteLine("Driver unloaded.");

  return;
}

  1. 本文目前尚无任何评论.