原创 编程获取网卡MAC地址

2008-4-7 13:20 7435 4 5 分类: 软件与OS
网卡的MAC地址是一个很好的标志信息,软件注册认证等等往往需要一个唯一的身份信息,这样可以防止
软件的非法使用。编程获得网卡的MAC地址是个老话题。这两天没事就写了个库实现收集系统信息的功能,
MAC地址当然是其中之一,此外,CPU的ID信息,硬盘的序列号等等。准备把这个做成dll,以后万一要用到
这些信息进行软件注册,就省的再写了。
有两种方法可以获得MAC地址(当然用delphi,asp里面的控件和支持库也可以做到,我这里只是指用c/c++来实现)
第一种用到Netbios,我写的代码是可以正常工作,但是出现一个奇怪的现象,在我办公室的机器上,只有一块
网卡,这种方法却返回两个网卡和两个MAC地址(当然这两个地址是完全相同的)。用了winpcap提供的函数
就更加古怪,它读取register下面HKLM\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318 
的所有子键值,这样通常都能读到7-8条网卡信息,但是只有两条是真正安装在我的机器上的网卡信息,而且正好
对应于Netbios方法查询到的那两条重复信息。
代码如下:
/* return 0 successful,others failed*/
SYSINFO_API UCHAR NetbiosEnumAdapter(LANA_ENUM *pLanaEnum)
{
NCB ncb;
UCHAR uRet;
LANA_ENUM tmp;
memset(&ncb,0,sizeof(ncb));
ncb.ncb_command=NCBENUM;
ncb.ncb_buffer=(unsigned char *)&tmp;
ncb.ncb_length=sizeof(tmp);
uRet=Netbios(&ncb);
if(uRet==NRC_GOODRET){
*pLanaEnum=tmp;
return 0;
}
return uRet;
}
该函数枚举所有网卡,得到LANA_ENUM信息后,可以挨个获取它们的MAC地址,获取MAC地址的代码如下:
/* Get the computer's Network Adapter's MAC address
* Argument:
* AdapterNum---the Adapter number ,possible there are more than one adapter
* LanEnum--- LANA_ENUM struct,contains the numbers for the current LAN adapters
* pAdapterStatus---the return MAC address
* return:
*  others--failed
*  0--successful, then pAdapterStatus->adapter_address contains the MAC address
*/
SYSINFO_API UCHAR NetbiosGetMacAddress(int AdapterNum, LANA_ENUM LanEnum,  PADAPTER_STATUS pAdapterStatus)
{
UCHAR uRet=0;
NCB ncb;

/* First reset the adapter*/
memset(&ncb,0,sizeof(ncb));
ncb.ncb_command=NCBRESET;
ncb.ncb_lana_num =LanEnum.lana[AdapterNum];
uRet=Netbios(&ncb);
if(uRet!=NRC_GOODRET)
return uRet;

/* send NCBASTAT command to get mac address*/

memset(&ncb,0,sizeof(ncb));
ncb.ncb_command=NCBASTAT;
ncb.ncb_lana_num=LanEnum.lana[AdapterNum];
strcpy((char*)ncb.ncb_callname,"*               ");
ncb.ncb_buffer=(unsigned char *)&Adapter;
ncb.ncb_length=sizeof(Adapter);
uRet=Netbios(&ncb);
if(uRet!=NRC_GOODRET)
return uRet;
*pAdapterStatus=Adapter.adapter;
return 0;
}

这种方法另一个恶心的缺点是,如果系统没有安装Netbios协议,则完全没用,而目前许多计算机确实没有安装
netbios协议。想了想,写出下面的方法,也没什么新意,网上早就有人讨论了这种方法:通过 发送ioctl给
ndis驱动程序获得MAC地址。
首先,枚举系统所有网卡:
SYSINFO_API int NdisEnumAdapter()
{
HKEY   RootKey, SubKey;
TCHAR SubKeyName[64],AdapterName[256];
LONG status;
int i=0,ret=0;
DWORD len;

status=RegOpenKeyEx(HKEY_LOCAL_MACHINE,WINNT_QUERY_ROOT_KEY,0,KEY_READ,&RootKey);
if(status!=ERROR_SUCCESS){
SysInfoDebug("NdisEnumAdapter-Open Root Key failed");
return 0;
}
while(RegEnumKey(RootKey,i,SubKeyName,sizeof(SubKeyName)/2)==ERROR_SUCCESS)
{
i++;
status=RegOpenKeyEx(RootKey,SubKeyName,0,KEY_READ,&SubKey);
if(status!=ERROR_SUCCESS){
SysInfoDebug("NdisEnumAdapter-Open Sub Key Failed");
continue;
}
len=sizeof(AdapterName);
status=RegQueryValueEx(SubKey,TEXT("ServiceName"),NULL,0,(PBYTE)AdapterName,&len);
if(status!=ERROR_SUCCESS){
SysInfoDebug("NdisEnumAdapter-Query ServiceName Failed");
continue;
}
lstrcpy(g_AdapterName[ret].name,TEXT("\\\\.\\"));
lstrcat(g_AdapterName[ret].name,AdapterName);
g_AdapterName[ret].index=ret;
if((++ret)>=20)
break;
}
return ret;
}
然后调用下面函数获得每个网卡的地址:
/*AdaptNum--Adapter number
* MacAddr--return Mac address
*/
SYSINFO_API BOOL NdisGetMacAddress(int AdaptNum, UCHAR *MacAddr)
{
TCHAR SymLink[256];
HANDLE hFile;
ULONG oid=OID_802_3_CURRENT_ADDRESS;
UCHAR data[6];
DWORD ByteRet;

if(AdaptNum>20||AdaptNum<1)
return FALSE;
wsprintf(SymLink,"%s",g_AdapterName[AdaptNum-1].name);
hFile=CreateFile(SymLink,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);
if(hFile!=INVALID_HANDLE_VALUE){
SysInfoDebug("NdisGetMacAddress-CreateFile Success");
if(DeviceIoControl(hFile,IOCTL_NDIS_QUERY_GLOBAL_STATS,&oid,sizeof(oid),data,
sizeof(data),&ByteRet,NULL)==0){
SysInfoDebug("Can't get MAC address");
CloseHandle(hFile);
return FALSE;
}
memcpy(MacAddr,data,sizeof(data));
       CloseHandle(hFile);
return TRUE;
}
SysInfoDebug("Open Adapter Failed");
return FALSE;
}

文章评论1条评论)

登录后参与讨论

用户178916 2008-10-6 23:45

如果真要写成DLL以后用,用IPHELPAPI应该会好点吧!
相关推荐阅读
用户1361860 2012-06-28 23:44
Nicrosystem Freescale Kinetis教程---SDHC
这是研究生翻译的SDHC的中文文档,里面很多句子不通,但我现在没时间去修改了。先放出来,应该还是会有一点作用  ...
用户1361860 2012-06-26 12:39
Nicrosystem Freescale Kinetis教程--低功耗定时器
Freescale Kinetis内部集成了一个独特的低功耗定时器,它可以在系统处于低功耗模式下,仍然以极低功耗运行,可以用于在适当时候唤醒系统进入正常工作模式  ...
用户1361860 2012-06-24 22:11
Nicrosystem Freescale Kinetis教程----RTC实时时钟
Nicrosystem的飞思卡尔kinetis教程之片上RTC  ...
用户1361860 2012-06-22 10:21
TI C2000微控制器指南
这是官方的C2000的介绍,C2000做电机控制那是业界最好的。  ...
用户1361860 2012-06-20 23:52
Nicrosystem Freescale Kinetis教程--PIT定时器教程
这是PIT定时器的教程,PIT是 Kinetis支持的另一种定时器,相对于上一讲的flextimer要简单。 今晚赶到北京,到宾馆发一篇博客  ...
用户1361860 2012-06-19 13:15
Nicrosystem Freescale Kinetis教程--Flextimer教程
Kinetis的Flextimer定时器教程 kinetis集成了众多功能各异的定时器,flextimer是其中最为复杂的一个  ...
我要评论
1
4
关闭 站长推荐上一条 /2 下一条