存档

2012年6月 的存档

监听 IP 数据包

2012年6月29日 没有评论

利用系统的 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;
}

Windows 8 Release Preview 有内存泄漏

2012年6月28日 没有评论

rt。
具体是谁干的不清楚。昨天Ctrl + Scroll Lock + Scroll Lock没搞出来dump(C盘也有PF,设置的也是核心转储,还是没搞到dump,不知道是不是C盘的PF太小了)。
用傲游拿flash看视频(Webkit核)的时候用procexp可以看到NonPagedPool一直在涨,一秒几十到几百K的样子。
后来用poolmon看了下,pool tag是Mdl,大概是哪个驱动有BUG吧。

查询网卡的物理地址

2012年6月21日 没有评论

包括出厂时的地址,以及管理员指定的地址(如果不存在,则与出厂地址相同)。

用 C++ 编译的话要给函数原型声明都加上 EXTERN_C(或者 extern “C”)。(或者干脆用 EXTERN_C 把所有的声明都包括起来( EXTERN_C { … }。)。)

(NDMP18 展示了当出厂 MAC 跟管理员指定的 MAC 不同时的输出。)

We're checking device \Device\NDMP1:
Its permanent physical address is: 12-34-56-78-90-12
Its current physical address is: 12-34-56-78-90-12

We're checking device \Device\NDMP2:
Its permanent physical address is: 11-22-33-44-55-66
Its current physical address is: 11-22-33-44-55-66

We're checking device \Device\NDMP3:
We failed to open that device, status = 0xC0000001

We're checking device \Device\NDMP4:
We failed to query its permanent physical address, status = 0xC000000D
We failed to query its current physical address, status = 0xC000000D

We're checking device \Device\NDMP5:
We failed to query its permanent physical address, status = 0xC000000D
We failed to query its current physical address, status = 0x80000005

We're checking device \Device\NDMP6:
Its permanent physical address is: AA-BB-CC-DD-EE-FF
Its current physical address is: AA-BB-CC-DD-EE-FF

We're checking device \Device\NDMP7:
Its permanent physical address is: AB-CD-EF-AB-CD-EF
Its current physical address is: AB-CD-EF-AB-CD-EF

We're checking device \Device\NDMP8:
Its permanent physical address is: 00-00-00-00-00-00
Its current physical address is: 00-00-00-00-00-00

We're checking device \Device\NDMP9:
We failed to open that device, status = 0xC0000001

We're checking device \Device\NDMP10:
We failed to query its permanent physical address, status = 0xC000000D
We failed to query its current physical address, status = 0x80000005

We're checking device \Device\NDMP11:
We failed to query its permanent physical address, status = 0xC000000D
We failed to query its current physical address, status = 0x80000005

We're checking device \Device\NDMP12:
We failed to query its permanent physical address, status = 0xC000000D
We failed to query its current physical address, status = 0x80000005

We're checking device \Device\NDMP13:
We failed to query its permanent physical address, status = 0xC000000D
We failed to query its current physical address, status = 0x80000005

We're checking device \Device\NDMP14:
We failed to query its permanent physical address, status = 0xC000000D
We failed to query its current physical address, status = 0x80000005

We're checking device \Device\NDMP15:
Its permanent physical address is: 12-34-56-78-9A-BC
Its current physical address is: 12-34-56-78-9A-BC

We're checking device \Device\NDMP16:
We failed to open that device, status = 0xC0000001

We're checking device \Device\NDMP17:
We failed to open that device, status = 0xC0000001

We're checking device \Device\NDMP18:
Its permanent physical address is: FE-DC-BA-AB-CD-EF
Its current physical address is: AB-CD-EF-FE-DC-BA

We're checking device \Device\NDMP19:
We failed to query its permanent physical address, status = 0xC000000D
We failed to query its current physical address, status = 0xC000000D

请按任意键继续. . .

#include <windows.h>
#include <stdio.h>

//
// 用到的宏 / 例程等的声明。
//

#define IOCTL_NDIS_QUERY_GLOBAL_STATS 0x00170002

#define OID_802_3_PERMANENT_ADDRESS 0x01010101
#define OID_802_3_CURRENT_ADDRESS 0x01010102

#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

NTSYSAPI
VOID
NTAPI
RtlInitUnicodeString(
    IN OUT PUNICODE_STRING DestinationString,
    IN PCWSTR SourceString
);

typedef struct _OBJECT_ATTRIBUTES
{
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

#define OBJ_CASE_INSENSITIVE 0x00000040L

#define InitializeObjectAttributes(p,n,a,r,s) { \
    (p)->Length = sizeof(OBJECT_ATTRIBUTES);    \
    (p)->RootDirectory = (r);                   \
    (p)->Attributes = (a);                      \
    (p)->ObjectName = (n);                      \
    (p)->SecurityDescriptor = (s);              \
    (p)->SecurityQualityOfService = NULL;       \
}

typedef struct _IO_STATUS_BLOCK
{
    union
    {
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

#define FILE_OPEN 0x00000001

NTSYSAPI
NTSTATUS
NTAPI
ZwCreateFile(
    OUT PHANDLE FileHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN PLARGE_INTEGER AllocationSize OPTIONAL,
    IN ULONG FileAttributes,
    IN ULONG ShareAccess,
    IN ULONG CreateDisposition,
    IN ULONG CreateOptions,
    IN PVOID EaBuffer OPTIONAL,
    IN ULONG EaLength
);

NTSYSAPI
NTSTATUS
NTAPI
ZwDeviceIoControlFile(
    IN HANDLE DeviceHandle,
    IN HANDLE Event OPTIONAL,
    IN PVOID UserApcRoutine OPTIONAL,
    IN PVOID UserApcContext OPTIONAL,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    IN ULONG IoControlCode,
    IN PVOID InputBuffer,
    IN ULONG InputBufferSize,
    OUT PVOID OutputBuffer,
    IN ULONG OutputBufferSize
);

NTSYSAPI
NTSTATUS
NTAPI
ZwClose(
    IN HANDLE Handle
);

//
// MAC 地址长度。(6字节)
//

#define PHYSICAL_ADDRESS_LENGTH 6

//
// 打开设备。
//

NTSTATUS ObtainDeviceHandle(
  __out PHANDLE DeviceHandle,
  __in PUNICODE_STRING DeviceName
  )
{
  OBJECT_ATTRIBUTES ObjectAttributes;
  IO_STATUS_BLOCK IoStatusBlock;
  HANDLE LocalDeviceHandle;
  NTSTATUS Status;

  //
  // 初始化 OBJECT_ATTRIBUTES。
  //

  InitializeObjectAttributes(&ObjectAttributes, DeviceName, OBJ_CASE_INSENSITIVE, 
    NULL, NULL);

  //
  // 尝试打开设备。
  //

  Status = ZwCreateFile(&LocalDeviceHandle, FILE_READ_ACCESS, &ObjectAttributes, 
    &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0);

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

  //
  // 将句柄返回给调用方。
  //

  *DeviceHandle = LocalDeviceHandle;

  return Status;
}

//
// 获取网卡信息。
//

NTSTATUS QueryNdisDeviceInformation(
  __in HANDLE DeviceHandle,
  __in ULONG ObjectIdentifier,
  __out_bcount_opt(OutputBufferSize) PVOID OutputBuffer,
  __in SIZE_T OutputBufferSize
  )
{
  IO_STATUS_BLOCK IoStatusBlock;
  NTSTATUS Status;

  //
  // 发起请求。
  //

  Status = ZwDeviceIoControlFile(DeviceHandle, NULL, NULL, NULL, &IoStatusBlock, 
    IOCTL_NDIS_QUERY_GLOBAL_STATS, (PVOID)&ObjectIdentifier, sizeof(ULONG), 
    OutputBuffer, OutputBufferSize);

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

  return Status;
}

//
// 获取网卡 MAC 地址。
//
// 网卡 MAC 地址可以是出厂时的 MAC 地址,也可以是管理员指派的 MAC 地址。
//
// 输出参数 PhysicalAddress 至少需要 PHYSICAL_ADDRESS_LENGTH 个字节大小。
//(MAC 地址占 PHYSICAL_ADDRESS_LENGTH 字节。)
//

NTSTATUS QueryNdisDevicePhysicalAddress(
  __out PUCHAR PhysicalAddress,
  __in HANDLE DeviceHandle,
  __in BOOLEAN PermanentPhysicalAddress
  )
{
  //
  // 向设备查询网卡地址。
  //

  return QueryNdisDeviceInformation(DeviceHandle, 
    (PermanentPhysicalAddress ? OID_802_3_PERMANENT_ADDRESS : OID_802_3_CURRENT_ADDRESS), 
    (PVOID)PhysicalAddress, PHYSICAL_ADDRESS_LENGTH);
}

//
// 显示网卡信息。
//

VOID DumpNdisDevicePhysicalAddress(
  __in PUNICODE_STRING DeviceName
  )
{
  HANDLE DeviceHandle;
  BOOLEAN PermanentPhysicalAddressCandidates[] = {TRUE, FALSE};
  LPCSTR PhysicalAddressDescriptions[] = {"permanent physical address", "current physical address"};
  ULONG Index;
  NTSTATUS Status;

  //
  // 打开网卡设备。
  //

  Status = ObtainDeviceHandle(&DeviceHandle, DeviceName);

  if (!NT_SUCCESS(Status)) {
    printf("We failed to open that device, status = 0x%08X\n", Status);

    return;
  }

  //
  // 对所有 PermanentPhysicalAddress 可能的取值分别查询其对应的物理地址。
  //

  for (Index = 0; Index < _countof(PermanentPhysicalAddressCandidates); Index++) {
    UCHAR PhysicalAddress[PHYSICAL_ADDRESS_LENGTH];
    ULONG AddressIndex;

    //
    // 查询物理地址。
    //

    Status = QueryNdisDevicePhysicalAddress(PhysicalAddress, DeviceHandle, 
      PermanentPhysicalAddressCandidates[Index]);

    if (!NT_SUCCESS(Status)) {
      printf("We failed to query its %s, status = 0x%08X\n", PhysicalAddressDescriptions[Index],
        Status);

      continue;
    }

    //
    // 输出物理地址。
    //

    printf("Its %s is: ", PhysicalAddressDescriptions[Index]);

    for (AddressIndex = 0; AddressIndex < _countof(PhysicalAddress); AddressIndex++) {

      if (AddressIndex) {
        printf("-");
      }

      printf("%02X", PhysicalAddress[AddressIndex]);
    }

    printf("\n");
  }

  //
  // 释放设备。
  //

  ZwClose(DeviceHandle);

  return;
}

//
// 判断设备是否存在。
//

BOOLEAN IsDeviceExists(
  __in PUNICODE_STRING DeviceName
  )
{
  HANDLE DeviceHandle;
  NTSTATUS Status;

  //
  // 尝试打开设备。
  //

  Status = ObtainDeviceHandle(&DeviceHandle, DeviceName);

  if (NT_SUCCESS(Status)) {
    ZwClose(DeviceHandle);
  }

  return Status != STATUS_OBJECT_NAME_NOT_FOUND;
}

int main() {
  const static WCHAR DeviceNameFormat[] = L"\\Device\\NDMP%d";
  const static ULONG MaximumDeviceIndex = 10000;

  WCHAR DeviceNameBuffer[sizeof(DeviceNameFormat) + 12]; // ULONG 转换为十进制不会超过 12 位。
  ULONG DeviceIndex;

  //
  // 枚举设备。
  //

  DeviceIndex = 1; 
  
  for (DeviceIndex = 1; DeviceIndex < MaximumDeviceIndex; DeviceIndex++) {
    UNICODE_STRING DeviceName;
    
    //
    // 构造设备名。
    //

    wsprintfW(DeviceNameBuffer, DeviceNameFormat, DeviceIndex);

    RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);

    if (!IsDeviceExists(&DeviceName)) {
      continue;
    }

    //
    // 查询设备的物理地址。
    //

    printf("We're checking device %ls:\n", DeviceName.Buffer);

    DumpNdisDevicePhysicalAddress(&DeviceName);

    printf("\n");
  }

  return 0;
}

使用 Native API 创建进程 (Vista+)

2012年6月8日 没有评论

Vista+ 把很多事情都挪到内核里面去了,好像是因为“受保护的进程”的原因。

#include <Windows.h>

//
// 用到的各种宏、类型、函数的声明。
//

#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL)

typedef __success(return >= 0) LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;

#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

typedef struct _STRING
{
    USHORT Length;
    USHORT MaximumLength;
    __field_bcount_part_opt(MaximumLength, Length) PCHAR Buffer;
} STRING, *PSTRING, ANSI_STRING, *PANSI_STRING, OEM_STRING, *POEM_STRING;

typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    __field_bcount_part(MaximumLength, Length) PWCH Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), s }

typedef struct _OBJECT_ATTRIBUTES
{
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

#define DOS_MAX_COMPONENT_LENGTH 255
#define DOS_MAX_PATH_LENGTH (DOS_MAX_COMPONENT_LENGTH + 5)

typedef struct _CURDIR
{
    UNICODE_STRING DosPath;
    HANDLE Handle;
} CURDIR, *PCURDIR;

#define RTL_USER_PROC_CURDIR_CLOSE 0x00000002
#define RTL_USER_PROC_CURDIR_INHERIT 0x00000003

typedef struct _RTL_DRIVE_LETTER_CURDIR
{
    USHORT Flags;
    USHORT Length;
    ULONG TimeStamp;
    STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;

#define RTL_MAX_DRIVE_LETTERS 32
#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001

typedef struct _RTL_USER_PROCESS_PARAMETERS
{
    ULONG MaximumLength;
    ULONG Length;

    ULONG Flags;
    ULONG DebugFlags;

    HANDLE ConsoleHandle;
    ULONG ConsoleFlags;
    HANDLE StandardInput;
    HANDLE StandardOutput;
    HANDLE StandardError;

    CURDIR CurrentDirectory;
    UNICODE_STRING DllPath;
    UNICODE_STRING ImagePathName;
    UNICODE_STRING CommandLine;
    PVOID Environment;

    ULONG StartingX;
    ULONG StartingY;
    ULONG CountX;
    ULONG CountY;
    ULONG CountCharsX;
    ULONG CountCharsY;
    ULONG FillAttribute;

    ULONG WindowFlags;
    ULONG ShowWindowFlags;
    UNICODE_STRING WindowTitle;
    UNICODE_STRING DesktopInfo;
    UNICODE_STRING ShellInfo;
    UNICODE_STRING RuntimeData;
    RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS];

    ULONG EnvironmentSize;
    ULONG EnvironmentVersion;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

#define RTL_USER_PROC_PARAMS_NORMALIZED 0x00000001

// begin_rev
#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff
#define PS_ATTRIBUTE_THREAD 0x00010000 // can be used with threads
#define PS_ATTRIBUTE_INPUT 0x00020000 // input only
#define PS_ATTRIBUTE_UNKNOWN 0x00040000
// end_rev

// private
typedef enum _PS_ATTRIBUTE_NUM
{
    PsAttributeParentProcess, // in HANDLE
    PsAttributeDebugPort, // in HANDLE
    PsAttributeToken, // in HANDLE
    PsAttributeClientId, // out PCLIENT_ID
    PsAttributeTebAddress, // out PTEB *
    PsAttributeImageName, // in PWSTR
    PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION
    PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE
    PsAttributePriorityClass, // in UCHAR
    PsAttributeErrorMode, // in ULONG
    PsAttributeStdHandleInfo, // 10, in PPS_STD_HANDLE_INFO
    PsAttributeHandleList, // in PHANDLE
    PsAttributeGroupAffinity, // in PGROUP_AFFINITY
    PsAttributePreferredNode, // in PUSHORT
    PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER
    PsAttributeUmsThread, // ? in PUMS_CREATE_THREAD_ATTRIBUTES
    PsAttributeMitigationOptions, // in UCHAR
    PsAttributeMax
} PS_ATTRIBUTE_NUM;

// begin_rev

#define PsAttributeValue(Number, Thread, Input, Unknown) \
    (((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \
    ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \
    ((Input) ? PS_ATTRIBUTE_INPUT : 0) | \
    ((Unknown) ? PS_ATTRIBUTE_UNKNOWN : 0))

#define PS_ATTRIBUTE_PARENT_PROCESS \
    PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_DEBUG_PORT \
    PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_TOKEN \
    PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE)
#define PS_ATTRIBUTE_CLIENT_ID \
    PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE)
#define PS_ATTRIBUTE_TEB_ADDRESS \
    PsAttributeValue(PsAttributeTebAddress, TRUE, FALSE, FALSE)
#define PS_ATTRIBUTE_IMAGE_NAME \
    PsAttributeValue(PsAttributeImageName, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_IMAGE_INFO \
    PsAttributeValue(PsAttributeImageInfo, FALSE, FALSE, FALSE)
#define PS_ATTRIBUTE_MEMORY_RESERVE \
    PsAttributeValue(PsAttributeMemoryReserve, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_PRIORITY_CLASS \
    PsAttributeValue(PsAttributePriorityClass, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_ERROR_MODE \
    PsAttributeValue(PsAttributeErrorMode, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_STD_HANDLE_INFO \
    PsAttributeValue(PsAttributeStdHandleInfo, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_HANDLE_LIST \
    PsAttributeValue(PsAttributeHandleList, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_GROUP_AFFINITY \
    PsAttributeValue(PsAttributeGroupAffinity, TRUE, TRUE, FALSE)
#define PS_ATTRIBUTE_PREFERRED_NODE \
    PsAttributeValue(PsAttributePreferredNode, FALSE, TRUE, FALSE)
#define PS_ATTRIBUTE_IDEAL_PROCESSOR \
    PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE)
#define PS_ATTRIBUTE_MITIGATION_OPTIONS \
    PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, TRUE)

// end_rev

// begin_private

typedef struct _PS_ATTRIBUTE
{
    ULONG Attribute;
    SIZE_T Size;
    union
    {
        ULONG Value;
        PVOID ValuePtr;
    };
    PSIZE_T ReturnLength;
} PS_ATTRIBUTE, *PPS_ATTRIBUTE;

typedef struct _PS_ATTRIBUTE_LIST
{
    SIZE_T TotalLength;
    PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;

typedef struct _PS_MEMORY_RESERVE
{
    PVOID ReserveAddress;
    SIZE_T ReserveSize;
} PS_MEMORY_RESERVE, *PPS_MEMORY_RESERVE;

typedef enum _PS_STD_HANDLE_STATE
{
    PsNeverDuplicate,
    PsRequestDuplicate, // duplicate standard handles specified by PseudoHandleMask, and only if StdHandleSubsystemType matches the image subsystem
    PsAlwaysDuplicate, // always duplicate standard handles
    PsMaxStdHandleStates
} PS_STD_HANDLE_STATE;

// begin_rev
#define PS_STD_INPUT_HANDLE 0x1
#define PS_STD_OUTPUT_HANDLE 0x2
#define PS_STD_ERROR_HANDLE 0x4
// end_rev

typedef struct _PS_STD_HANDLE_INFO
{
    union
    {
        ULONG Flags;
        struct
        {
            ULONG StdHandleState : 2; // PS_STD_HANDLE_STATE
            ULONG PseudoHandleMask : 3; // PS_STD_*
        };
    };
    ULONG StdHandleSubsystemType;
} PS_STD_HANDLE_INFO, *PPS_STD_HANDLE_INFO;

// windows-internals-book:"Chapter 5"
typedef enum _PS_CREATE_STATE
{
    PsCreateInitialState,
    PsCreateFailOnFileOpen,
    PsCreateFailOnSectionCreate,
    PsCreateFailExeFormat,
    PsCreateFailMachineMismatch,
    PsCreateFailExeName, // Debugger specified
    PsCreateSuccess,
    PsCreateMaximumStates
} PS_CREATE_STATE;

typedef enum _PS_IFEO_KEY_STATE
{
    PsReadIFEOAllValues,
    PsSkipIFEODebugger,
    PsSkipAllIFEO,
    PsMaxIFEOKeyStates
} PS_IFEO_KEY_STATE, *PPS_IFEO_KEY_STATE;

typedef struct _PS_CREATE_INFO
{
    SIZE_T Size;
    PS_CREATE_STATE State;
    union
    {
        // PsCreateInitialState
        struct
        {
            union
            {
                ULONG InitFlags;
                struct
                {
                    UCHAR WriteOutputOnExit : 1;
                    UCHAR DetectManifest : 1;
                    UCHAR SpareBits1 : 6;
                    UCHAR IFEOKeyState : 2; // PS_IFEO_KEY_STATE
                    UCHAR SpareBits2 : 6;
                    USHORT ProhibitedImageCharacteristics : 16;
                };
            };
            ACCESS_MASK AdditionalFileAccess;
        } InitState;

        // PsCreateFailOnSectionCreate
        struct
        {
            HANDLE FileHandle;
        } FailSection;

        // PsCreateFailExeName
        struct
        {
            HANDLE IFEOKey;
        } ExeName;

        // PsCreateSuccess
        struct
        {
            union
            {
                ULONG OutputFlags;
                struct
                {
                    UCHAR ProtectedProcess : 1;
                    UCHAR AddressSpaceOverride : 1;
                    UCHAR DevOverrideEnabled : 1; // from Image File Execution Options
                    UCHAR ManifestDetected : 1;
                    UCHAR SpareBits1 : 4;
                    UCHAR SpareBits2 : 8;
                    USHORT SpareBits3 : 16;
                };
            };
            HANDLE FileHandle;
            HANDLE SectionHandle;
            ULONGLONG UserProcessParametersNative;
            ULONG UserProcessParametersWow64;
            ULONG CurrentParameterFlags;
            ULONGLONG PebAddressNative;
            ULONG PebAddressWow64;
            ULONGLONG ManifestAddress;
            ULONG ManifestSize;
        } SuccessState;
    };
} PS_CREATE_INFO, *PPS_CREATE_INFO;

extern "C"
NTSYSCALLAPI
NTSTATUS
NTAPI
ZwCreateUserProcess(
    __out PHANDLE ProcessHandle,
    __out PHANDLE ThreadHandle,
    __in ACCESS_MASK ProcessDesiredAccess,
    __in ACCESS_MASK ThreadDesiredAccess,
    __in_opt POBJECT_ATTRIBUTES ProcessObjectAttributes,
    __in_opt POBJECT_ATTRIBUTES ThreadObjectAttributes,
    __in ULONG ProcessFlags,
    __in ULONG ThreadFlags,
    __in_opt PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
    __inout PPS_CREATE_INFO CreateInfo,
    __in_opt PPS_ATTRIBUTE_LIST AttributeList
    );;

#define IMAGE_PATH L"\\??\\C:\\Windows\\System32\\cmd.exe"

#define PointerAdd(Pointer, Increment, ResultType) ((ResultType)((ULONG_PTR)(Pointer) \
  + (ULONG_PTR)(Increment)))

#define RoundUp(Value, Alignment) (((Value) + (Alignment) - 1) / (Alignment) * (Alignment))

//
// 创建用户进程参数。
//

static NTSTATUS PsCreateProcessParameters(
  OUT PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
  IN PUNICODE_STRING ImagePath,
  IN PUNICODE_STRING CurrentDirectory,
  IN PWSTR Environment,
  IN ULONG EnvironmentSize
  )
{
  static UNICODE_STRING EmptyUnicodeString = RTL_CONSTANT_STRING(L"");
  static UNICODE_STRING DefaultDesktop = RTL_CONSTANT_STRING(L"Winsta0\\Default");

  PRTL_USER_PROCESS_PARAMETERS LocalProcessParameters;
  PUNICODE_STRING CommandLine, WindowTitle, DesktopInfo, ShellInfo, RuntimeData, DllPath;
  ULONG ProcessParametersSize;
  PWSTR CurrentString;

  CommandLine = ImagePath;
  DllPath = &EmptyUnicodeString;
  WindowTitle = &EmptyUnicodeString;
  DesktopInfo = &DefaultDesktop;
  ShellInfo = &EmptyUnicodeString;
  RuntimeData = &EmptyUnicodeString;

  //
  // 计算用户进程参数的大小。
  //

  ProcessParametersSize = sizeof(RTL_USER_PROCESS_PARAMETERS) + 
    RoundUp(ImagePath->Length + sizeof(UNICODE_NULL), sizeof(ULONG)) +
    RoundUp(CommandLine->Length + sizeof(UNICODE_NULL), sizeof(ULONG)) +
    RoundUp(DllPath->MaximumLength, sizeof(ULONG)) +
    RoundUp(WindowTitle->MaximumLength, sizeof(ULONG)) +
    RoundUp(DesktopInfo->MaximumLength, sizeof(ULONG)) +
    RoundUp(ShellInfo->MaximumLength, sizeof(ULONG)) +
    RoundUp(RuntimeData->MaximumLength, sizeof(ULONG)) +
    RoundUp(DOS_MAX_PATH_LENGTH / sizeof(CHAR) * sizeof(WCHAR), sizeof(ULONG));

  //
  // 为用户进程参数分配内存。
  //

  LocalProcessParameters = (PRTL_USER_PROCESS_PARAMETERS)malloc(ProcessParametersSize);

  if (!LocalProcessParameters) {
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  //
  // 初始化用户进程参数。
  //

  RtlZeroMemory(LocalProcessParameters, ProcessParametersSize);

  LocalProcessParameters->Length = LocalProcessParameters->MaximumLength = 
    ProcessParametersSize;
  LocalProcessParameters->Flags = RTL_USER_PROC_PARAMS_NORMALIZED;
  LocalProcessParameters->DebugFlags = 0;
  LocalProcessParameters->Environment = (PVOID)Environment;
  LocalProcessParameters->EnvironmentSize = EnvironmentSize;
  LocalProcessParameters->CurrentDirectory.Handle = 0;
  LocalProcessParameters->ConsoleFlags = 0;
  
  //
  // 复制字符串。
  //

#define PspCopyUnicodeString(BufferPointer, Destination, Source, AllocationSize) \
  (Destination)->Buffer = BufferPointer; \
  (Destination)->Length = (Source)->Length; \
  (Destination)->MaximumLength = AllocationSize; \
  RtlCopyMemory(BufferPointer, (PVOID)(Source)->Buffer, Source->Length); \
  BufferPointer = PointerAdd(BufferPointer, RoundUp( \
    AllocationSize, sizeof(ULONG)), PWSTR);

  CurrentString = (PWCHAR)(LocalProcessParameters + 1);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->ImagePathName, 
    ImagePath, ImagePath->Length + sizeof(UNICODE_NULL));

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->CommandLine, 
    CommandLine, CommandLine->Length + sizeof(UNICODE_NULL));

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->DllPath, 
    DllPath, DllPath->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->WindowTitle, 
    WindowTitle, WindowTitle->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->DesktopInfo, 
    DesktopInfo, DesktopInfo->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->ShellInfo, 
    ShellInfo, ShellInfo->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->RuntimeData, 
    RuntimeData, RuntimeData->MaximumLength);

  PspCopyUnicodeString(CurrentString, &LocalProcessParameters->CurrentDirectory.DosPath,
    CurrentDirectory, DOS_MAX_PATH_LENGTH / sizeof(CHAR) * sizeof(WCHAR));

#undef PspCopyUnicodeString

  //
  // 返回结果给调用方。
  //

  *ProcessParameters = LocalProcessParameters;

  return STATUS_SUCCESS;
}

//
// 释放用户进程参数。
//

static VOID PsFreeProcessParameters(
  IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters
  )
{
  free((PVOID)ProcessParameters);

  return;
}

//
// 创建环境变量信息。
//

static NTSTATUS PsCreateEnvironment(
  OUT PWSTR *Environment,
  OUT ULONG *EnvironmentSize
  )
{
  static PWSTR LocalEnvironment = L"\0";

  //
  // FIX: 目前只是返回一个空的环境变量信息。应改为从注册表(
  // Registry\Machine\System\CurrentControlSet\Control\Session Manager\Environment)
  // 查询。
  //
  // 环境变量信息也可以从 PEB 中获取。
  //

  *Environment = LocalEnvironment;
  *EnvironmentSize = sizeof(LocalEnvironment);

  return STATUS_SUCCESS;
}

//
// 释放环境变量信息。
//

static VOID PsFreeEnvironment(
  IN PWSTR Environment
  )
{
  //
  // 因为目前环境变量信息是一个静态变量,因此不需释放。
  //

  UNREFERENCED_PARAMETER(Environment);

  return;
}

//
// 创建进程。
//

NTSTATUS PsCreateProcess(
  OUT HANDLE *ProcessHandle,
  OUT HANDLE *ThreadHandle,
  IN PUNICODE_STRING ImagePath
  )
{
  static UNICODE_STRING CurrentDirectory = RTL_CONSTANT_STRING(L"C:\\");

  PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  PWSTR Environment;
  ULONG EnvironmentSize;
  PS_CREATE_INFO CreateInfo = {0};
  PS_ATTRIBUTE_LIST AttributeList = {0};
  NTSTATUS Status;

  //
  // 创建环境变量。
  //

  Status = PsCreateEnvironment(&Environment, &EnvironmentSize);
  
  if (!NT_SUCCESS(Status)) {
    return Status;
  }

  //
  // 创建进程参数。
  //

  Status = PsCreateProcessParameters(&ProcessParameters, ImagePath, &CurrentDirectory,
    Environment, EnvironmentSize);

  if (!NT_SUCCESS(Status)) {
    PsFreeEnvironment(Environment);

    return Status;
  }
   
  //
  // 初始化 PS_CREATE_INFO 结构体。
  //

  CreateInfo.Size = sizeof(PS_CREATE_INFO);
  CreateInfo.State = PsCreateInitialState;

  //
  // 将文件名通过 PS_ATTRIBUTE_LIST 传给 ZwCreateUserProcess。
  //

  AttributeList.TotalLength = sizeof(PS_ATTRIBUTE_LIST);
  AttributeList.Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
  AttributeList.Attributes[0].Size = ImagePath->Length;
  AttributeList.Attributes[0].ValuePtr = (PVOID)ImagePath->Buffer;

  //
  // 创建进程。
  //

  Status = ZwCreateUserProcess(ProcessHandle, ThreadHandle, MAXIMUM_ALLOWED, MAXIMUM_ALLOWED,
    NULL, NULL, 0, 0, ProcessParameters, &CreateInfo, &AttributeList);

  PsFreeProcessParameters(ProcessParameters);
  PsFreeEnvironment(Environment);

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

  return Status;
}

int main() {
  static UNICODE_STRING strImagePath = RTL_CONSTANT_STRING(IMAGE_PATH);

  HANDLE hProcess, hThread;
  NTSTATUS Status;

  Status = PsCreateProcess(&hThread, &hProcess, &strImagePath);

  if (NT_SUCCESS(Status)) {
    CloseHandle(hThread);
    CloseHandle(hProcess);
  }
   
  return 0;
}

Windows Defender 阻止修改 hosts 的解决办法

2012年6月4日 没有评论

郁闷了好几天,其实很简单的嘛~~直接把hosts加到白名单去就行了~~

话说今天发现其实在查杀记录里面选上那一项前面的选项框然后选“允许”就好了……