方法一:利用NetBIOS API来获取MAC
缺陷:依赖于NetBIOS协议,这个协议现在的网卡有些已经不支持了,所以有些情况下会取不到(不推荐使用这种方法)
HRESULT GetMAC(char* pszMAC, unsigned int uCount)
...{
if (!pszMAC)
return E_INVALIDARG;
if (uCount < SIZE_OF_MAC)
return E_INVALIDARG;

HRESULT hr = E_FAIL;

NCB Ncb;
UCHAR uRetCode;
LANA_ENUM lenum;
ASTAT Adapter;

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 ", uRetCode );
//for(i=0; i < lenum.length ;i++)
...{
memset( &Ncb, 0, sizeof(Ncb) );
Ncb.ncb_command = NCBRESET;
Ncb.ncb_lana_num = (unsigned char)lenum.lana;
uRetCode = Netbios( &Ncb );
printf( "The NCBRESET on LANA %d return code is: 0x%x ",
lenum.lana, uRetCode );
memset( &Ncb, 0, sizeof (Ncb) );
Ncb.ncb_command = NCBASTAT;
Ncb.ncb_lana_num = (unsigned char)lenum.lana;
strcpy( (char*)Ncb.ncb_callname, "* " );
Ncb.ncb_buffer = (unsigned char *) &Adapter;
Ncb.ncb_length = sizeof(Adapter);
uRetCode = Netbios( &Ncb );
printf( "The NCBASTAT on LANA %d return code is: 0x%x ",
lenum.lana, uRetCode );
if ( uRetCode == 0 )
...{
memset(pszMAC, 0, uCount);
sprintf(pszMAC,
"%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] );
hr = S_OK;
}
}
return hr;
}
方法二:ipconfig猥琐法取MAC地址
通过对ipconfig /all的输出进行字条串查找来得到MAC。
缺陷:不能通用各语言版本的Windows系统。我试过,因为w2k和xp下用ipconfig /all显示出来都是英文的所以可以通用,但vista不同语言就不一样了。(不推荐使用这种方法)
方法三,IP Helper API取MAC
这种方法我喜欢,其实就是用IDA分析ipconfig.exe时发现他用到一系列api叫iphlpapi,感觉应该就是用这么个东东来取网卡相关的信息。查msdn得知:
Platform SDK: IP Helper下有一个叫GetAdaptersInfo的api可以得到网卡的物理地址。
BOOL KLocalUUID::__getMacByIPHelper(char* pszMac, unsigned int uCount)
{
if (!pszMac
|| uCount <= 0)
return FALSE;
PIP_ADAPTER_INFO pAdapterInfo = NULL;
DWORD dwRetVal = 0;
pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) );
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
// Make an initial call to GetAdaptersInfo to get
// the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
{
free (pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
}
if ((dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
{
char* p = pszMac;
int nWriteLen = 0;
while (pAdapterInfo)
{
ULONG i = 0;
while(i < pAdapterInfo->AddressLength)
{
if (nWriteLen >= (uCount - 2))
break;
sprintf(p, "%02x", pAdapterInfo->Address[i]);
nWriteLen += strlen(p);
p += strlen(p);
i++;
}
pAdapterInfo = pAdapterInfo->Next;
}
}
else
{
printf("Call to GetAdaptersInfo failed./n");
}
printf("MAC : %s/n", pszMac);
free (pAdapterInfo);
return TRUE;
}
结束语:
这里代码都是源代码文件中的关键部分,需要的头文件或是一些无关紧要的宏定义我就没贴出来。
取MAC地址应该会时常用到,一次弄明白了,下次就舒服了~~
+_+
// ---------------------------------------end line by debehe---------------------------------------
缺陷:依赖于NetBIOS协议,这个协议现在的网卡有些已经不支持了,所以有些情况下会取不到(不推荐使用这种方法)
HRESULT GetMAC(char* pszMAC, unsigned int uCount)
...{
if (!pszMAC)
return E_INVALIDARG;
if (uCount < SIZE_OF_MAC)
return E_INVALIDARG;
HRESULT hr = E_FAIL;
NCB Ncb;
UCHAR uRetCode;
LANA_ENUM lenum;
ASTAT Adapter;
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 ", uRetCode );
//for(i=0; i < lenum.length ;i++)
...{
memset( &Ncb, 0, sizeof(Ncb) );
Ncb.ncb_command = NCBRESET;
Ncb.ncb_lana_num = (unsigned char)lenum.lana;
uRetCode = Netbios( &Ncb );
printf( "The NCBRESET on LANA %d return code is: 0x%x ",
lenum.lana, uRetCode );
memset( &Ncb, 0, sizeof (Ncb) );
Ncb.ncb_command = NCBASTAT;
Ncb.ncb_lana_num = (unsigned char)lenum.lana;
strcpy( (char*)Ncb.ncb_callname, "* " );
Ncb.ncb_buffer = (unsigned char *) &Adapter;
Ncb.ncb_length = sizeof(Adapter);
uRetCode = Netbios( &Ncb );
printf( "The NCBASTAT on LANA %d return code is: 0x%x ",
lenum.lana, uRetCode );
if ( uRetCode == 0 )
...{
memset(pszMAC, 0, uCount);
sprintf(pszMAC,
"%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] );
hr = S_OK;
}
}
return hr;
}方法二:ipconfig猥琐法取MAC地址
通过对ipconfig /all的输出进行字条串查找来得到MAC。
缺陷:不能通用各语言版本的Windows系统。我试过,因为w2k和xp下用ipconfig /all显示出来都是英文的所以可以通用,但vista不同语言就不一样了。(不推荐使用这种方法)
//网卡MAC地址的前导信息
const char szSearchMAC_EN[MAX_PATH] = "Physical Address. . . . . . . . . : ";
const char szSearchMAC_CN[MAX_PATH] = "物理地址. . . . . . . . . . . . . : ";
// 省略号 ... ...
BOOL __getIpconfigOutput(char* pszOutput, unsigned int uCount)
{
BOOL bRet = FALSE;
SECURITY_ATTRIBUTES sa;
HANDLE hReadPipe,hWritePipe;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
// 创建管道
bRet = CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
if(!bRet)
{
return FALSE;
}
STARTUPINFO si; // 控制命令行窗口信息
PROCESS_INFORMATION pi; // 返回进程信息
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.hStdError = hWritePipe;
si.hStdOutput = hWritePipe;
si.wShowWindow = SW_HIDE; //隐藏命令行窗口
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
// 创建获取命令行输出的进程
bRet = CreateProcess (NULL, szFetCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi );
if (bRet)
{
WaitForSingleObject (pi.hProcess, INFINITE);

unsigned long count;
memset(pszOutput, 0x00, uCount);
bRet = ReadFile(hReadPipe, pszOutput, uCount, &count, 0);
}
//关闭所有的句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hWritePipe);
CloseHandle(hReadPipe);
return bRet;
}

BOOL __analyseMACOutput(char* pszOutput, char* pszMAC, unsigned int uCount)
{
if (!pszOutput
|| !pszMAC)
return FALSE;

KString strBuffer;
strBuffer = pszOutput;
long ipos;
if (-1 != (ipos = strBuffer.find(szSearchMAC_EN)))
{
// 提取MAC地址串
strBuffer = strBuffer.substr(ipos+strlen(szSearchMAC_EN));
strBuffer = strBuffer.substr(0, MAC_STRING_LENGTH);
}
else if ( -1 != (ipos = strBuffer.find(szSearchMAC_CN)))
{
strBuffer = strBuffer.substr(ipos+strlen(szSearchMAC_CN));
strBuffer = strBuffer.substr(0, MAC_STRING_LENGTH);
}

strncpy(pszMAC, strBuffer.c_str(), strBuffer.size() > uCount ? uCount : strBuffer.size());

return TRUE;
}

HRESULT __getMAC(char* pszMAC, unsigned int uCount)
{
if (!pszMAC)
return E_INVALIDARG;
if (uCount < MAC_STRING_LENGTH)
return E_INVALIDARG;

HRESULT hr = S_OK;
char szBuffer[MAX_COMMAND_SIZE+1]; //放置命令行输出缓冲区

memset(pszMAC, 0x00, sizeof(pszMAC));
BOOL bRet = __getIpconfigOutput(szBuffer, MAX_COMMAND_SIZE);
if (!bRet)
return E_FAIL;
char szAnalysedMAC[MAX_PATH] = {0};
bRet = __analyseMACOutput(szBuffer, szAnalysedMAC, MAX_PATH);
if (!bRet)
return E_FAIL;

int j = 0;
int nLen = strlen(szAnalysedMAC);
for(int i=0; i < nLen; i++)
{
if(szAnalysedMAC[i] != '-')
{
pszMAC[j] = szAnalysedMAC[i];
j++;
}
}

return S_OK;
}
const char szSearchMAC_EN[MAX_PATH] = "Physical Address. . . . . . . . . : ";
const char szSearchMAC_CN[MAX_PATH] = "物理地址. . . . . . . . . . . . . : ";
// 省略号 ... ...
BOOL __getIpconfigOutput(char* pszOutput, unsigned int uCount)
{
BOOL bRet = FALSE;
SECURITY_ATTRIBUTES sa;
HANDLE hReadPipe,hWritePipe;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
// 创建管道
bRet = CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
if(!bRet)
{
return FALSE;
}
STARTUPINFO si; // 控制命令行窗口信息
PROCESS_INFORMATION pi; // 返回进程信息
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.hStdError = hWritePipe;
si.hStdOutput = hWritePipe;
si.wShowWindow = SW_HIDE; //隐藏命令行窗口
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
// 创建获取命令行输出的进程
bRet = CreateProcess (NULL, szFetCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi );
if (bRet)
{
WaitForSingleObject (pi.hProcess, INFINITE);
unsigned long count;
memset(pszOutput, 0x00, uCount);
bRet = ReadFile(hReadPipe, pszOutput, uCount, &count, 0);
}
//关闭所有的句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hWritePipe);
CloseHandle(hReadPipe);
return bRet;
}
BOOL __analyseMACOutput(char* pszOutput, char* pszMAC, unsigned int uCount)
{
if (!pszOutput
|| !pszMAC)
return FALSE;
KString strBuffer;
strBuffer = pszOutput;
long ipos;
if (-1 != (ipos = strBuffer.find(szSearchMAC_EN)))
{
// 提取MAC地址串
strBuffer = strBuffer.substr(ipos+strlen(szSearchMAC_EN));
strBuffer = strBuffer.substr(0, MAC_STRING_LENGTH);
}
else if ( -1 != (ipos = strBuffer.find(szSearchMAC_CN)))
{
strBuffer = strBuffer.substr(ipos+strlen(szSearchMAC_CN));
strBuffer = strBuffer.substr(0, MAC_STRING_LENGTH);
}
strncpy(pszMAC, strBuffer.c_str(), strBuffer.size() > uCount ? uCount : strBuffer.size());
return TRUE;
}
HRESULT __getMAC(char* pszMAC, unsigned int uCount)
{
if (!pszMAC)
return E_INVALIDARG;
if (uCount < MAC_STRING_LENGTH)
return E_INVALIDARG;
HRESULT hr = S_OK;
char szBuffer[MAX_COMMAND_SIZE+1]; //放置命令行输出缓冲区
memset(pszMAC, 0x00, sizeof(pszMAC));
BOOL bRet = __getIpconfigOutput(szBuffer, MAX_COMMAND_SIZE);
if (!bRet)
return E_FAIL;
char szAnalysedMAC[MAX_PATH] = {0};
bRet = __analyseMACOutput(szBuffer, szAnalysedMAC, MAX_PATH);
if (!bRet)
return E_FAIL;
int j = 0;
int nLen = strlen(szAnalysedMAC);
for(int i=0; i < nLen; i++)
{
if(szAnalysedMAC[i] != '-')
{
pszMAC[j] = szAnalysedMAC[i];
j++;
}
}
return S_OK;
}方法三,IP Helper API取MAC
这种方法我喜欢,其实就是用IDA分析ipconfig.exe时发现他用到一系列api叫iphlpapi,感觉应该就是用这么个东东来取网卡相关的信息。查msdn得知:
Platform SDK: IP Helper下有一个叫GetAdaptersInfo的api可以得到网卡的物理地址。
BOOL KLocalUUID::__getMacByIPHelper(char* pszMac, unsigned int uCount){
if (!pszMac
|| uCount <= 0)
return FALSE;
PIP_ADAPTER_INFO pAdapterInfo = NULL;
DWORD dwRetVal = 0;
pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) );
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
// Make an initial call to GetAdaptersInfo to get
// the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
{
free (pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
}
if ((dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
{
char* p = pszMac;
int nWriteLen = 0;
while (pAdapterInfo)
{
ULONG i = 0;
while(i < pAdapterInfo->AddressLength)
{
if (nWriteLen >= (uCount - 2))
break;
sprintf(p, "%02x", pAdapterInfo->Address[i]);
nWriteLen += strlen(p);
p += strlen(p);
i++;
}
pAdapterInfo = pAdapterInfo->Next;
}
}
else
{
printf("Call to GetAdaptersInfo failed./n");
}
printf("MAC : %s/n", pszMac);
free (pAdapterInfo);
return TRUE;
}
结束语:
这里代码都是源代码文件中的关键部分,需要的头文件或是一些无关紧要的宏定义我就没贴出来。
取MAC地址应该会时常用到,一次弄明白了,下次就舒服了~~
+_+
// ---------------------------------------end line by debehe---------------------------------------
本文介绍三种获取MAC地址的方法:利用NetBIOS API、通过解析ipconfig输出和使用IP Helper API。详细展示了每种方法的优缺点及实现代码。
...
9847

被折叠的 条评论
为什么被折叠?



