From:http://blog.csdn.net/zhangting1987/article/details/2732135

网卡地址这个概念有点混淆不清。因为实际上有两个地址,mac地址和物理地址,一般说网卡地址我是指物理地址,不知道别人怎么看?物理地址指的是网卡上的存放地址的ROM里的地址,mac地址是这块卡工作的时候用的地址,一般情况下这两个地址是一样的,所以很多人都混用了,甚至不知道有区别  -_-#

网卡工作的时候,一个以太网帧60到1514(不包括crc),帧的crc是网卡自动加的,前导码是自动加的。网卡目的地址和源地址是驱动程序加的.所以实际上网卡工作的时候用什么地址作为工作地址完全是由驱动程序决定的 :)因此,我们完全可以在不改变网卡的物理地址的情况下用软件方法改变具体的网卡的工作地址.

MAC地址一般保存在注册表里,可以修改,于是就有下面连个问题:

第1,可以肆无忌弹的盗用ip,

第2,可以破一些垃圾加密软件...

很多软件是通过网卡地址加密的,这里面有两种不同。有些做的比较好的是通过物理地址加密。有些是通过工作地址加密.通过工作地址加密的像通过guidgen,netbios等方法得到的地址都是mac地址。一般都可以用该方法破解。通过物理地址加密的有点难破,但是也不是没有办法。

取得系统中网卡MAC地址的三种方法

第一种方法使用Microsoft的Netbios API。 这是一套通过Winsock提供底层网络支持的命令。使用Netbios的最大缺点是您必须在系统中安装了Netbios服务(如果您在windows网络中启用了文件共享的话,这就不是问题了)。除此此外,这种方法又快又准确。

Netbios API只包括了一个函数,就叫做Netbios。这个函数使用网络控制块(network control block)结构作为参数,这个结构告诉函数要做什么。结构的定义如下:

typedef struct _NCB {

UCHAR ncb_command;

UCHAR ncb_retcode;

UCHAR ncb_lsn;

UCHAR ncb_num;

PUCHAR ncb_buffer;

WORD ncb_length;

UCHAR ncb_callname[NCBNAMSZ];

UCHAR ncb_name[NCBNAMSZ];

UCHAR ncb_rto;

UCHAR ncb_sto;

void (CALLBACK *ncb_post) (struct _NCB *);

UCHAR ncb_lana_num;

UCHAR ncb_cmd_cplt;

#ifdef _WIN64

UCHAR ncb_reserve[18];

#else

UCHAR ncb_reserve[10];

#endif

HANDLE ncb_event;

} NCB, *PNCB;

重点在于ncb_command 成员。这个成员告诉Netbios该作什么。我们使用三个命令来探测MAC地址。他们在MSDN的定义如下:

命令描述:

NCBENUM Windows NT/2000: 列举系统中网卡的数量。使用此命令后,ncb_buffer成员指向由LANA_ENUM结构填充的缓冲区。

NCBENUM 不是标准的 NetBIOS 3.0 命令。

NCBRESET 重置网卡。网卡在接受新的NCB命令之前必须重置。

NCBASTAT 接受本地或远程接口卡的状态。使用此命令后,ncb_buffer成员指向由ADAPTER_STATUS结构填充的缓冲区,随后是NAME_BUFFER结构的数组。

下面就是取得您系统MAC地址的步骤:

1》列举所有的接口卡。

2》重置每块卡以取得它的正确信息。

3》查询接口卡,取得MAC地址并生成标准的冒号分隔格式。

下面就是实例源程序。

#include <windows.h>

#include <stdlib.h>

#include <stdio.h>

#include <iostream>

#include <string>

using namespace std;

#define bzero(thing,sz) memset(thing,0,sz)

bool GetAdapterInfo(int adapter_num, string &mac_addr)

{

// 重置网卡,以便我们可以查询

NCB Ncb;

memset(&Ncb, 0, sizeof(Ncb));

Ncb.ncb_command = NCBRESET;

Ncb.ncb_lana_num = adapter_num;

if (Netbios(&Ncb) != NRC_GOODRET) {

mac_addr = "bad (NCBRESET): ";

mac_addr += string(Ncb.ncb_retcode);

return false;

}

// 准备取得接口卡的状态块

bzero(&Ncb,sizeof(Ncb);

Ncb.ncb_command = NCBASTAT;

Ncb.ncb_lana_num = adapter_num;

strcpy((char *) Ncb.ncb_callname, "*");

struct ASTAT

{

ADAPTER_STATUS adapt;

NAME_BUFFER NameBuff[30];

} Adapter;

bzero(&Adapter,sizeof(Adapter));

Ncb.ncb_buffer = (unsigned char *)&Adapter;

Ncb.ncb_length = sizeof(Adapter);

// 取得网卡的信息,并且如果网卡正常工作的话,返回标准的冒号分隔格式。

if (Netbios(&Ncb) == 0)

{

char acMAC[18];

sprintf(acMAC, "%02X:%02X:%02X:%02X:%02X:%02X",

int (Adapter.adapt.adapter_address[0]),

int (Adapter.adapt.adapter_address[1]),

int (Adapter.adapt.adapter_address[2]),

int (Adapter.adapt.adapter_address[3]),

int (Adapter.adapt.adapter_address[4]),

int (Adapter.adapt.adapter_address[5]));

mac_addr = acMAC;

return true;

}

else

{

mac_addr = "bad (NCBASTAT): ";

mac_addr += string(Ncb.ncb_retcode);

return false;

}

}

int main()

{

// 取得网卡列表

LANA_ENUM AdapterList;

NCB Ncb;

memset(&Ncb, 0, sizeof(NCB));

Ncb.ncb_command = NCBENUM;

Ncb.ncb_buffer = (unsigned char *)&AdapterList;

Ncb.ncb_length = sizeof(AdapterList);

Netbios(&Ncb);

// 取得本地以太网卡的地址

string mac_addr;

for (int i = 0; i < AdapterList.length - 1; ++i)

{

if (GetAdapterInfo(AdapterList.lana, mac_addr))

{

cout << "Adapter " << int (AdapterList.lana) <<

"´s MAC is " << mac_addr << endl;

}

else

{

cerr << "Failed to get MAC address! Do you" << endl;

cerr << "have the NetBIOS protocol installed?" << endl;

break;

}

}

return 0;

}

第二种方法-使用COM GUID API

这种方法使用COM API创建一个GUID(全局唯一标识符)并从那里继承MAC地址。GUID通常用来标识COM组件以及系统中的其他对象。它们是由MAC地址(结合其他东西)计算得来的,表面上MAC地址就包含在其中。我说表面上是因为事实上并没有包含。

我提供这种方法更多的是为了作为反面教材。您也许用这种方法能够得到MAC地址,但有时候您只会得到随机的十六进制数值。

下面的例子十分简单,无需多讲。我们使用CoCreateGuid创建GUID,并将最后六个字节放入字符串中。它们可能是MAC地址,但并不是必然的。

#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;

}

第三种方法- 使用SNMP扩展API

我要讨论的第三种方法是使用Windows的SNMP(简单网络管理协议)扩展来取得MAC地址。在我的经验里,这个协议很简单。代码也是直勾勾的向前的。基本步骤和Netbios相同:

1》取得网卡列表

2》查询每块卡的类型和MAC地址

3》保存当前网卡

我个人对SNMP了解不多,但如我刚刚所言,代码十分清楚。

#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;

/* 载入SNMP DLL并取得实例句柄 */

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);

/* 初始化用来接收m_Query查询结果的变量列表 */

varBindList.list = varBind;

varBind[0].name = MIB_NULL;

varBind[1].name = MIB_NULL;

/* 在OID中拷贝并查找接口表中的入口数量 */

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;

/* 拷贝OID的ifType-接口类型 */

SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);

/* 拷贝OID的ifPhysAddress-物理地址 */

SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);

do

{

/* 提交查询,结果将载入 varBindList。

可以预料这个循环调用的次数和系统中的接口卡数量相等 */

ret =

m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,

&errorIndex);

if (!ret)

ret = 1;

else

/* 确认正确的返回类型 */

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)

{

/* 确认我们已经在此取得地址 */

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))

{

/* 忽略所有的拨号网络接口卡 */

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))

{

/* 忽略由其他的网络接口卡返回的NULL地址 */

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); /* 发生错误终止。 */

getch();

FreeLibrary(m_hInst);

/* 解除绑定 */

SNMP_FreeVarBind(&varBind[0]);

SNMP_FreeVarBind(&varBind[1]);

}

得到物理地址的方法对于不同的网卡是不同的,不过都是操作io端口,端口的具体地址要看具体芯片的说明书。加密软件要得到物理地址,不能用这个方法。一般来说,是在核心态用NDISREQUEST来得到的。这里提供一个应用层的方法。

要扯到NDISREQUEST,就要扯远了,还是打住吧...

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条目。

于是我们就得到了mac地址和物理地址。

--------------------------------------------------------------------------------

关于如何修改mac地址,没有太多的讲的必要,反正和注册表有关,下面帖一点如何修改网卡物理地址的东西:

可以直接从eeprom读取或修改(如:8029AS采用的是93c46芯片)

不过网卡的芯片不同,读取得方式不同。

如读取8029AS的eeprom的MAC的OFFSET 0001h;实际ADDRESS I/O+01

MAC存入在EEPROM的ADDRESS 1h,2h,3h中;

如读取8139C(L)的EEPROM(93c46)里OFFSET 0050h;实际 I/O+0x50

MAC存入在EEPROM中,ADDRESS 7h,8h,9h中;

系统实际使用的MAC放在8139chin的 register中,偏移地址是 0000h,0001h,0002h,0003h,0004h,0005h中

转载于:https://www.cnblogs.com/ourran/p/4968520.html

【转载】取得系统中网卡MAC地址的三种方法相关推荐

  1. linux系统中清空文件内容的三种方法

    1.使用vi/vim命令打开文件后,输入"%d"清空,后保存即可.但当文件内容较大时,处理较慢,命令如下: vim file_name :%d :wq 2.使用cat命令情况,命令 ...

  2. win7修改mac地址的三种方法

    Win7修改MAC地址方法有以下三种: 方法一:使用Win7MAC地址修改工具 1,只适用于windows7系统的网卡MAC地址修改.XP的可以用,但没做什么测试. 2,部分windows7下的无线网 ...

  3. Linux克隆Mac地址一样,详解Linux系统中网卡MAC地址克隆方法

    怎么临时性地改变 mac 地址? 你可以在 linux 运行的时候改变 mac 地址.需要注意的是当 mac 地址转换的那一会时间,你的网络会掉线.当电脑重启时 mac 地址又会变回原来的.下面介绍几 ...

  4. 获取MAC地址的四种方法(转)

    https://www.cnblogs.com/zlshmily/p/10058560.html zlshmily 在实际的应用系统中,我们往往会需要在程序运行时获取当前机器的网卡的MAC地址,以便作 ...

  5. 在 Linux 系统中查找 MAC 地址的方法

    参考文章: 多种方法在Linux上找到MAC地址 引言: MAC(Media Access Control)地址是网络设备(如网卡)的唯一标识符,用于在局域网中进行通信.在 Linux 系统中,有几种 ...

  6. Java 跨平台获取 MAC 地址的两种方法

    前言 有时我们因为软件授权或者其它需要获取主机唯一标识而需要获取用户主机的MAC地址,而本文则将介绍如何通过Java来实现跨平台获取MAC地址的两种方法,同时具体的代码也已上传到GitHub. 如果不 ...

  7. Linux系统中运行.sh文件的几种方法

    在Linux系统中执行.sh文件的几种方法: 1. cd到.sh文件所在的目录,然后执行./xxx.sh   [前提:该./sh文件要有可执行的权限,chmod u+x xxx.sh]  2. 在任何 ...

  8. android 取mac地址,Android手机获取Mac地址的几种方法,androidmac

    Android手机获取Mac地址的几种方法,androidmac 最常用的方法,通过WiFiManager获取: /** * 通过WiFiManager获取mac地址 * @param context ...

  9. Linux中创建Daemon进程的三种方法

    Linux中创建Daemon进程的三种方法 什么是daemon进程? Unix/Linux中的daemon进程类似于Windows中的后台服务进程,一直在后台运行运行,例如http服务进程nginx, ...

最新文章

  1. java注解的执行顺序_深入理解Spring的@Order注解和Ordered接口
  2. HDU - 1051 Wooden Sticks
  3. 谈Elasticsearch下分布式存储的数据分布
  4. 用“Web的思想”做PC客户端
  5. 《需求分析与系统设计》第三篇
  6. 文件服务器无法上传资料,该文件未上传至服务器怎么回事
  7. Python自动化办公 | 补写178份Word日报!
  8. tcpdump命令--详解
  9. 解决Mac Chrome打开HTTPS证书错误问题
  10. 利用静态内部类实现单例模式
  11. 背水一战 Windows 10 (53) - 控件(集合类): ItemsControl 的布局控件 - ItemsStackPanel, ItemsWrapGrid...
  12. Python编程之画圆
  13. Ubuntu NumPy 安装
  14. 北京大学计算机学院刘利,信息科学学院 科研动态 深化新文科计算机教学改革,实施分类分层次教学体系研讨会在京召开...
  15. Memory threshold for SAP CRM WebClient UI technical framework
  16. Espresso之RecyclerView
  17. 读取文件时内容乱码解决方法
  18. 复杂大脑网络的结构和功能
  19. 【狂神说】Docker 学习笔记【基础篇】
  20. DSP28335 GPIO模块

热门文章

  1. F5 Networks任命Adam Judd领导亚太区销售工作 将加速区域云和安全业务发展
  2. 货车运输(LCA+最大生成树)
  3. 影响淘宝宝贝排名的因素
  4. Qt creator一些常用的快捷注释语句
  5. jsp编译指令--pge
  6. Golang 中 Slice的分析与使用(含源码)
  7. LeetCode 42 Hard 收集雨水I Python
  8. 爱签电子合同入选“2022产业链供应链数字经济创新案例”
  9. 亚马逊云科技——云原生主题容器入门笔记
  10. 利用计算机打开电视盒子,创维盒子教您如何使用计算机连电视?