首页 > 未分类 > 查询网卡的物理地址

查询网卡的物理地址

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

用 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;
}

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