1.NDIS(DDK)通过驱动程序获取MAC地址

ndis规范中说明,网卡驱动程序支持ioctl_ndis_query_stats接口
参数如下:
OID_802_3_PERMANENT_ADDRESS :物理地址
OID_802_3_CURRENT_ADDRESS   :mac地址
于是我们的方法就得到了。

首先,看看注册表,找一找网卡有几块,分别是什么设备名。
具体位置和os有关,2000下在hlm\software\microsoft\windows nt\current version\networkcards。

然后createfile(devicename,...)注意,要用linkname,因此
还要加上"////.//device//".

接着
deviceiocontrol(hmac,IOCTL_NDIS_QUERY_STATS,
OID_802_3_PERMANENT_ADDRESS/OID_802_3_CURRENT_ADDRESS...)


具体的情况可以参看ddk下的
OID_802_3_CURRENT_ADDRESS条目


2.NetAPI-2得到MAC (MSDN推荐方法)

#include <windows.h>
//#include <wincon.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

typedef struct _ASTAT_
{
   ADAPTER_STATUS adapt;
   NAME_BUFFER    NameBuff [30];
}ASTAT, * PASTAT;

ASTAT Adapter;

int main (void)
{
      NCB Ncb;
      UCHAR uRetCode;
      char NetName[50];
      LANA_ENUM   lenum;
      int      i;

      memset( &Ncb, 0, sizeof(Ncb) );
      Ncb.ncb_command = NCBENUM;
      Ncb.ncb_buffer = (UCHAR *)&lenum;
      Ncb.ncb_length = sizeof(lenum);
      uRetCode = Netbios( &Ncb );
      printf( "The NCBENUM return code is: 0x%x \n", uRetCode );

      for(i=0; i < lenum.length ;i++)
       {
          memset( &Ncb, 0, sizeof(Ncb) );
          Ncb.ncb_command = NCBRESET;
          Ncb.ncb_lana_num = lenum.lana[i];

          uRetCode = Netbios( &Ncb );
          printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
                  lenum.lana, uRetCode );

          memset( &Ncb, 0, sizeof (Ncb) );
          Ncb.ncb_command = NCBASTAT;
          Ncb.ncb_lana_num = lenum.lana[i];

          strcpy( Ncb.ncb_callname,  "*               " );
          Ncb.ncb_buffer = (char *) &Adapter;
          Ncb.ncb_length = sizeof(Adapter);

          uRetCode = Netbios( &Ncb );
          printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
                  lenum.lana, uRetCode );
          if ( uRetCode == 0 )
            {
             printf( "The Ethernet Number on LANA %d is:%02x%02x%02x%02x%02x%02x\n",
                  lenum.lana,
                  Adapter.adapt.adapter_address[0],
                  Adapter.adapt.adapter_address[1],
                  Adapter.adapt.adapter_address[2],
                  Adapter.adapt.adapter_address[3],
                  Adapter.adapt.adapter_address[4],
                  Adapter.adapt.adapter_address[5] );
             }
         }

}


               
3.用COM API获取网卡MAC地址
     这种方法使用COM API创建一个GUID(全局唯一标识符)并从那里继承MAC地址。
GUID通常用来标识COM组件以及系统中的其他对象。它们是由MAC地址(结合其他东西)计算得来的,表面上MAC地址就包含在其中。
我说表面上是因为事实上并没有包含。我提供这种方法更多的是为了作为反面教材。您也许用这种方法能够得到MAC地址,但
有时候您只会得到随机的十六进制数值。下面的例子十分简单,无需多讲。我们使用CoCreateGuid创建GUID,并将最后六个字节
放入字符串中。它们可能是MAC地址,但并不是必然的。

uuid.cpp
#include <windows.h>
#include <iostream>
#include <conio.h>

using namespace std;

int main()
{
   cout << "MAC address is: ";
   
   // 向COM要求一个UUID。如果机器中有以太网卡,
   // UUID最后的六个字节(Data4的2-7字节)应该是本地以太网卡的MAC地址。
   GUID uuid;
   CoCreateGuid(&uuid);
   // Spit the address out
   char mac_addr[18];
   sprintf(mac_addr,"%02X:%02X:%02X:%02X:%02X:%02X",
   uuid.Data4[2],uuid.Data4[3],uuid.Data4[4],
   uuid.Data4[5],uuid.Data4[6],uuid.Data4[7]);
   cout << mac_addr << endl;
   getch();
   return 0;
}


4.用NetAPI来获取网卡MAC地址

首先在头文件定义中加入#include "nb30.h"

#pragma comment(lib,"netapi32.lib")
typedef struct _ASTAT_
{
  ADAPTER_STATUS adapt;
  NAME_BUFFER    NameBuff[30];
} ASTAT, * PASTAT;


就可以这样调用来获取远程网卡MAC地址了:

CString GetMacAddress(CString sNetBiosName)
{
    ASTAT Adapter;

    NCB ncb;
    UCHAR uRetCode;

    memset(&ncb, 0, sizeof(ncb));
    ncb.ncb_command = NCBRESET;
    ncb.ncb_lana_num = 0;

    uRetCode = Netbios(&ncb);

    memset(&ncb, 0, sizeof(ncb));
    ncb.ncb_command = NCBASTAT;
    ncb.ncb_lana_num = 0;

    sNetBiosName.MakeUpper();

    FillMemory(ncb.ncb_callname, NCBNAMSZ - 1, 0x20);

    strcpy((char *)ncb.ncb_callname, (LPCTSTR) sNetBiosName);

    ncb.ncb_callname[sNetBiosName.GetLength()] = 0x20;
    ncb.ncb_callname[NCBNAMSZ] = 0x0;

    ncb.ncb_buffer = (unsigned char *) &Adapter;
    ncb.ncb_length = sizeof(Adapter);

    uRetCode = Netbios(&ncb);
   
    CString sMacAddress;

    if (uRetCode == 0)
    {
        sMacAddress.Format(_T("%02x%02x%02x%02x%02x%02x"),
         Adapter.adapt.adapter_address[0],
            Adapter.adapt.adapter_address[1],
            Adapter.adapt.adapter_address[2],
            Adapter.adapt.adapter_address[3],
            Adapter.adapt.adapter_address[4],
            Adapter.adapt.adapter_address[5]);
    }
    return sMacAddress;
}

5、snmp.cpp
#include <snmp.h>
#include <conio.h>
#include <stdio.h>

typedef bool(WINAPI * pSnmpExtensionInit) (
        IN DWORD dwTimeZeroReference,
        OUT HANDLE * hPollForTrapEvent,
        OUT AsnObjectIdentifier * supportedView);

typedef bool(WINAPI * pSnmpExtensionTrap) (
        OUT AsnObjectIdentifier * enterprise,
        OUT AsnInteger * genericTrap,
        OUT AsnInteger * specificTrap,
        OUT AsnTimeticks * timeStamp,
        OUT RFC1157VarBindList * variableBindings);

typedef bool(WINAPI * pSnmpExtensionQuery) (
        IN BYTE requestType,
        IN OUT RFC1157VarBindList * variableBindings,
        OUT AsnInteger * errorStatus,
        OUT AsnInteger * errorIndex);

typedef bool(WINAPI * pSnmpExtensionInitEx) (
        OUT AsnObjectIdentifier * supportedView);

void main()
{
  HINSTANCE m_hInst;
  pSnmpExtensionInit m_Init;
  pSnmpExtensionInitEx m_InitEx;
  pSnmpExtensionQuery m_Query;
  pSnmpExtensionTrap m_Trap;
  HANDLE PollForTrapEvent;
  AsnObjectIdentifier SupportedView;
  UINT OID_ifEntryType[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 3};
  UINT OID_ifEntryNum[] = {1, 3, 6, 1, 2, 1, 2, 1};
  UINT OID_ipMACEntAddr[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 6};
  AsnObjectIdentifier MIB_ifMACEntAddr =
    { sizeof(OID_ipMACEntAddr)  sizeof(UINT), OID_ipMACEntAddr };
  AsnObjectIdentifier MIB_ifEntryType =
    {sizeof(OID_ifEntryType)  sizeof(UINT), OID_ifEntryType};
  AsnObjectIdentifier MIB_ifEntryNum =
    {sizeof(OID_ifEntryNum)  sizeof(UINT), OID_ifEntryNum};
  RFC1157VarBindList varBindList;
  RFC1157VarBind varBind[2];
  AsnInteger errorStatus;
  AsnInteger errorIndex;
  AsnObjectIdentifier MIB_NULL = {0, 0};
  int ret;
  int dtmp;
  int i = 0, j = 0;
  bool found = false;
  char TempEthernet[13];
  m_Init = NULL;
  m_InitEx = NULL;
  m_Query = NULL;
  m_Trap = NULL;

  /* Load the SNMP dll and get the addresses of the functions
     necessary */
  m_hInst = LoadLibrary("inetmib1.dll");
  if (m_hInst < (HINSTANCE) HINSTANCE_ERROR)
  {
    m_hInst = NULL;
    return;
  }
  m_Init =
    (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit");
  m_InitEx =
    (pSnmpExtensionInitEx) GetProcAddress(m_hInst,
                                          "SnmpExtensionInitEx");
  m_Query =
    (pSnmpExtensionQuery) GetProcAddress(m_hInst,
                                         "SnmpExtensionQuery");
  m_Trap =
    (pSnmpExtensionTrap) GetProcAddress(m_hInst, "SnmpExtensionTrap");
  m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);

  /* Initialize the variable list to be retrieved by m_Query */
  varBindList.list = varBind;
  varBind[0].name = MIB_NULL;
  varBind[1].name = MIB_NULL;

  /* Copy in the OID to find the number of entries in the
     Inteface table */
  varBindList.len = 1;        /* Only retrieving one item */
  SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
  ret =
    m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
            &errorIndex);
  printf("# of adapters in this system : %in",
       varBind[0].value.asnvalue.number);
  varBindList.len = 2;

  /* Copy in the OID of ifType, the type of interface */
  SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);

  /* Copy in the OID of ifPhysAddress, the address */
  SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);

  do
  {

    /* Submit the query.  Responses will be loaded into varBindList.
       We can expect this call to succeed a # of times corresponding
       to the # of adapters reported to be in the system */
    ret =
      m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
              &errorIndex);
    if (!ret)
      ret = 1;
    else
        /* Confirm that the proper type has been returned */
      ret =
          SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
                       MIB_ifEntryType.idLength); if (!ret) {
    j++;
    dtmp = varBind[0].value.asnvalue.number;
    printf("Interface #%i type : %in", j, dtmp);

    /* Type 6 describes ethernet interfaces */
    if (dtmp == 6)
    {

      /* Confirm that we have an address here */
      ret =
          SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr,
                       MIB_ifMACEntAddr.idLength);
      if ((!ret) && (varBind[1].value.asnvalue.address.stream != NULL))
      {
        if((varBind[1].value.asnvalue.address.stream[0] == 0x44)
          && (varBind[1].value.asnvalue.address.stream[1] == 0x45)
          && (varBind[1].value.asnvalue.address.stream[2] == 0x53)
          && (varBind[1].value.asnvalue.address.stream[3] == 0x54)
          && (varBind[1].value.asnvalue.address.stream[4] == 0x00))
        {
          /* Ignore all dial-up networking adapters */
          printf("Interface #%i is a DUN adaptern", j);
          continue;
        }
        if ((varBind[1].value.asnvalue.address.stream[0] == 0x00)
            && (varBind[1].value.asnvalue.address.stream[1] == 0x00)
            && (varBind[1].value.asnvalue.address.stream[2] == 0x00)
            && (varBind[1].value.asnvalue.address.stream[3] == 0x00)
            && (varBind[1].value.asnvalue.address.stream[4] == 0x00)
            && (varBind[1].value.asnvalue.address.stream[5] == 0x00))
        {
          /* Ignore NULL addresses returned by other network
             interfaces */
          printf("Interface #%i is a NULL addressn", j);
          continue;
        }
        sprintf(TempEthernet, "%02x%02x%02x%02x%02x%02x",
                varBind[1].value.asnvalue.address.stream[0],
                varBind[1].value.asnvalue.address.stream[1],
                varBind[1].value.asnvalue.address.stream[2],
                varBind[1].value.asnvalue.address.stream[3],
                varBind[1].value.asnvalue.address.stream[4],
                varBind[1].value.asnvalue.address.stream[5]);
        printf("MAC Address of interface #%i: %sn", j,
               TempEthernet);}
      }
    }
  } while (!ret);         /* Stop only on an error.  An error will occur
                             when we go exhaust the list of interfaces to
                             be examined */
  getch();

  FreeLibrary(m_hInst);
  /* Free the bindings */
  SNMP_FreeVarBind(&varBind[0]);
  SNMP_FreeVarBind(&varBind[1]);
}