簡介 在Socket編程的時候,我們需要實時獲取我們所需要的IP地址。例如在編寫後門的時候,我們可能需要獲得有效的外網IP或內網IP;有時候我們可能需要判斷我們獲取的是否是虛擬機網卡,這時候就需要對每一張網卡上的特征進行識別。以下筆者總結了一些常用的處理方法供大家參考。 參考資料: 1. "提取網卡 ...
簡介
在Socket編程的時候,我們需要實時獲取我們所需要的IP地址。例如在編寫後門的時候,我們可能需要獲得有效的外網IP或內網IP;有時候我們可能需要判斷我們獲取的是否是虛擬機網卡,這時候就需要對每一張網卡上的特征進行識別。以下筆者總結了一些常用的處理方法供大家參考。
參考資料:1. 提取網卡信息方法
2. 虛擬與物理網卡區分方法
C++代碼樣例
1. 頭文件(包含特征處理函數)
/////////////////////////////////////////
//
// FileName : NetInfoProc.h
// Creator : PeterZ
// Date : 2018-6-21 23:50
// Comment : 網卡信息篩選
// Editor : Visual Studio 2017
//
/////////////////////////////////////////
#pragma once
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <strsafe.h>
#include <WinSock2.h>
#include <Iphlpapi.h>
#include <cstring>
#pragma comment(lib,"Iphlpapi.lib")
using namespace std;
#define REG_ERROR -2
#define NO_PCI -1
#define IS_PCI 0
/**
* @brief 查看字元串中是否有指定特征串
* @param source 指向源字元串的指針
* @param target 指向目標字元串的指針
*/
BOOL IsInString(LPCSTR source, LPCSTR target)
{
if (source == NULL && target == NULL)
{
return false;
}
const size_t targetLength = strlen(target);
const size_t sourceLength = strlen(source);
if (sourceLength >= targetLength)
{
for (int i = 0; i < strlen(source); i++)
{
if (i + targetLength > sourceLength)
{
return false;
}
for (int j = 0; j < targetLength; j++)
{
if (*(source + i + j) != *(target + j))
{
break;
}
if (j == targetLength - 1)
{
return true;
}
}
}
}
return false;
}
/**
* @brief 獲取註冊表數據
* @param hRoot 根鍵
* @param szSubKey 子鍵
* @param szValueName 數據項名
* @param szRegInfo 數據
*/
BOOL GetRegInfo(HKEY hRoot, LPCTSTR szSubKey, LPCTSTR szValueName, LPSTR szRegInfo)
{
HKEY hKey;
DWORD dwType = REG_SZ;
DWORD dwLenData = strlen(szRegInfo);
LONG lRes = RegCreateKeyEx(hRoot, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (lRes != ERROR_SUCCESS)
{
if (lRes == 5)
{
printf("Please use Administrator Privilege !\n");
}
else
{
printf("Get Register Info Error! Error Code is ");
printf("%ld\n", lRes);
}
RegCloseKey(hKey);
RegCloseKey(hRoot);
return false;
}
RegQueryValueEx(hKey, szValueName, 0, &dwType, NULL, &dwLenData);
lRes = RegQueryValueEx(hKey, szValueName, 0, &dwType, (LPBYTE)szRegInfo, &dwLenData);
if (lRes != ERROR_SUCCESS)
{
RegCloseKey(hKey);
RegCloseKey(hRoot);
return false;
}
RegCloseKey(hKey);
RegCloseKey(hRoot);
return true;
}
/**
* @brief 驗證註冊信息是否是PCI物理網卡(需要以管理員許可權運行程式)
* @param pIpAdapterInfo 指向網卡數據的指針
*/
int IsPCINetCard(const PIP_ADAPTER_INFO pIpAdapterInfo)
{
//通過註冊表特征去除非物理網卡
CHAR szRegSubKey[255] = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
CHAR szNetCardRegInfo[255] = "\0";
StringCchCat(szRegSubKey, sizeof(szRegSubKey), pIpAdapterInfo->AdapterName);
StringCchCat(szRegSubKey, sizeof(szRegSubKey), "\\Connection");
if (!GetRegInfo(HKEY_LOCAL_MACHINE, szRegSubKey, "PnPInstanceId", szNetCardRegInfo))
{
return REG_ERROR;
}
if (strncmp(szNetCardRegInfo, "PCI", 3) == 0) return IS_PCI;
else return NO_PCI;
}
/**
* @brief 驗證是否是虛擬網卡
* @param pIpAdapterInfo 指向網卡數據的指針
*/
BOOL IsVirtualNetCard(const PIP_ADAPTER_INFO pIpAdapterInfo)
{
//去除有特征名的虛擬網卡
if (IsInString(strlwr(pIpAdapterInfo->Description), "virtual")) return true;
//去除有MAC的虛擬網卡 vmware
if (pIpAdapterInfo->Address[0] == 0x00 && pIpAdapterInfo->Address[1] == 0x05 && pIpAdapterInfo->Address[2] == 0x69) return true;
//去除有MAC的虛擬網卡 vmware
if (pIpAdapterInfo->Address[0] == 0x00 && pIpAdapterInfo->Address[1] == 0x0C && pIpAdapterInfo->Address[2] == 0x29) return true;
//去除有MAC的虛擬網卡 vmware
if (pIpAdapterInfo->Address[0] == 0x00 && pIpAdapterInfo->Address[1] == 0x50 && pIpAdapterInfo->Address[2] == 0x56) return true;
//去除有MAC的虛擬網卡 vmware
if (pIpAdapterInfo->Address[0] == 0x00 && pIpAdapterInfo->Address[1] == 0x1C && pIpAdapterInfo->Address[2] == 0x14) return true;
//去除有MAC的虛擬網卡 parallels
if (pIpAdapterInfo->Address[0] == 0x00 && pIpAdapterInfo->Address[1] == 0x1C && pIpAdapterInfo->Address[2] == 0x42) return true;
//去除有MAC的虛擬網卡 microsoft virtual pc
if (pIpAdapterInfo->Address[0] == 0x00 && pIpAdapterInfo->Address[1] == 0x03 && pIpAdapterInfo->Address[2] == 0xFF) return true;
//去除有MAC的虛擬網卡 virtual iron
if (pIpAdapterInfo->Address[0] == 0x00 && pIpAdapterInfo->Address[1] == 0x0F && pIpAdapterInfo->Address[2] == 0x4B) return true;
//去除有MAC的虛擬網卡 red hat xen , oracle vm , xen source, novell xen
if (pIpAdapterInfo->Address[0] == 0x00 && pIpAdapterInfo->Address[1] == 0x16 && pIpAdapterInfo->Address[2] == 0x3E) return true;
//去除有MAC的虛擬網卡 virtualbox
if (pIpAdapterInfo->Address[0] == 0x08 && pIpAdapterInfo->Address[1] == 0x00 && pIpAdapterInfo->Address[2] == 0x27) return true;
return false;
}
/**
* @brief 驗證是否是0.0.0.0不可用IP
* @param pIpAdapterInfo 指向網卡數據的指針
*/
BOOL IsInvalidIp(const PIP_ADAPTER_INFO pIpAdapterInfo)
{
IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
do
{
if (!strcmp(pIpAddrString->IpAddress.String, "0.0.0.0"))
{
return false;
}
if ((pIpAddrString = pIpAddrString->Next) == NULL)
{
return true;
}
} while (pIpAddrString);
return true;
}
/**
* @brief 驗證是否是內網IP
* @param pIpAdapterInfo 指向網卡數據的指針
*/
BOOL IsIntranetIP(const PIP_ADAPTER_INFO pIpAdapterInfo)
{
IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
do
{
if (strncmp(pIpAddrString->IpAddress.String, "10", 2) == 0 || (strncmp(pIpAddrString->IpAddress.String, "172.16", 6) > 0 && strncmp(pIpAddrString->IpAddress.String, "172.31", 6) < 0) || strncmp(pIpAddrString->IpAddress.String, "192.168", 7) == 0)
{
return true;
}
if ((pIpAddrString = pIpAddrString->Next) == NULL)
{
return false;
}
} while (pIpAddrString);
return true;
}
2. CPP文件(代碼應用演示)
/////////////////////////////////////////
//
// FileName : NetCardVer.cpp
// Creator : PeterZ
// Date : 2018-6-21 23:50
// Comment : 網卡信息篩選
// Editor : Visual Studio 2017
//
/////////////////////////////////////////
#include "NetInfoProc.h"
void Output1(PIP_ADAPTER_INFO pIpAdapterInfo); //結果輸出1(正常結果)
void Output2(PIP_ADAPTER_INFO pIpAdapterInfo); //結果輸出2(刪除虛擬網卡的結果)
void Output3(PIP_ADAPTER_INFO pIpAdapterInfo); //結果輸出3(去除非PCI物理網卡) >>需要以管理員許可權運行程式<<
void Output4(PIP_ADAPTER_INFO pIpAdapterInfo); //結果輸出4(篩選內網網卡)
//主函數
int main(void)
{
PIP_ADAPTER_INFO pIpAdapterInfo = (PIP_ADAPTER_INFO)malloc(sizeof(IP_ADAPTER_INFO));
unsigned long stSize = sizeof(IP_ADAPTER_INFO);
int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
if (ERROR_BUFFER_OVERFLOW == nRel/*GetAdaptersInfo參數傳遞的記憶體空間不足*/)
{
//free(pIpAdapterInfo);
pIpAdapterInfo = (PIP_ADAPTER_INFO)realloc(pIpAdapterInfo, stSize);
nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
}
if (ERROR_SUCCESS == nRel)
{
printf(">>>>>>>>> 正常結果 <<<<<<<<<<<\n\n");
Output1(pIpAdapterInfo);
printf("\n\n>>>>>>>>> 刪除虛擬網卡的結果 <<<<<<<<<\n\n");
Output2(pIpAdapterInfo);
printf("\n\n>>>>>>>>> 去除非PCI物理網卡的結果 <<<<<<<<<\n\n");
Output3(pIpAdapterInfo);
printf("\n\n>>>>>>>>> 篩選內網網卡的結果 <<<<<<<<<\n\n");
Output4(pIpAdapterInfo);
}
if (pIpAdapterInfo)
{
free(pIpAdapterInfo);
}
system("pause");
return 0;
}
//結果輸出1(正常結果)
void Output1(PIP_ADAPTER_INFO pIpAdapterInfo)
{
//可能有多網卡,因此通過迴圈去判斷
while (pIpAdapterInfo)
{
//輸出信息
cout << "網卡名稱:" << pIpAdapterInfo->AdapterName << endl;
cout << "網卡描述:" << pIpAdapterInfo->Description << endl;
cout << "網卡MAC地址:" << pIpAdapterInfo->Address;
for (UINT i = 0; i < pIpAdapterInfo->AddressLength; i++)
{
if (i == pIpAdapterInfo->AddressLength - 1)
{
printf("%02x\n", pIpAdapterInfo->Address[i]);
}
else
{
printf("%02x-", pIpAdapterInfo->Address[i]);
}
}
cout << "網卡IP地址如下:" << endl;
IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
//可能網卡有多IP,因此通過迴圈去判斷
do
{
cout << pIpAddrString->IpAddress.String << endl;
pIpAddrString = pIpAddrString->Next;
} while (pIpAddrString);
pIpAdapterInfo = pIpAdapterInfo->Next;
cout << "*****************************************************" << endl;
}
return;
}
//結果輸出2(刪除虛擬網卡的結果)
void Output2(PIP_ADAPTER_INFO pIpAdapterInfo)
{
//可能有多網卡,因此通過迴圈去判斷
while (pIpAdapterInfo)
{
//去除虛擬網卡IP
if (IsVirtualNetCard(pIpAdapterInfo))
{
pIpAdapterInfo = pIpAdapterInfo->Next;
continue;
}
//輸出信息
cout << "網卡名稱:" << pIpAdapterInfo->AdapterName << endl;
cout << "網卡描述:" << pIpAdapterInfo->Description << endl;
cout << "網卡MAC地址:" << pIpAdapterInfo->Address;
for (UINT i = 0; i < pIpAdapterInfo->AddressLength; i++)
{
if (i == pIpAdapterInfo->AddressLength - 1)
{
printf("%02x\n", pIpAdapterInfo->Address[i]);
}
else
{
printf("%02x-", pIpAdapterInfo->Address[i]);
}
}
cout << "網卡IP地址如下:" << endl;
IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
//可能網卡有多IP,因此通過迴圈去判斷
do
{
cout << pIpAddrString->IpAddress.String << endl;
pIpAddrString = pIpAddrString->Next;
} while (pIpAddrString);
pIpAdapterInfo = pIpAdapterInfo->Next;
cout << "*****************************************************" << endl;
}
return;
}
//結果輸出3(去除非PCI物理網卡)
void Output3(PIP_ADAPTER_INFO pIpAdapterInfo)
{
//可能有多網卡,因此通過迴圈去判斷
while (pIpAdapterInfo)
{
//去除非PCI物理網卡
if (IsPCINetCard(pIpAdapterInfo) != IS_PCI)
{
if (IsPCINetCard(pIpAdapterInfo) == REG_ERROR)
{
printf("1\n");
return;
}
pIpAdapterInfo = pIpAdapterInfo->Next;
continue;
}
//輸出信息
cout << "網卡名稱:" << pIpAdapterInfo->AdapterName << endl;
cout << "網卡描述:" << pIpAdapterInfo->Description << endl;
cout << "網卡MAC地址:" << pIpAdapterInfo->Address;
for (UINT i = 0; i < pIpAdapterInfo->AddressLength; i++)
{
if (i == pIpAdapterInfo->AddressLength - 1)
{
printf("%02x\n", pIpAdapterInfo->Address[i]);
}
else
{
printf("%02x-", pIpAdapterInfo->Address[i]);
}
}
cout << "網卡IP地址如下:" << endl;
IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
//可能網卡有多IP,因此通過迴圈去判斷
do
{
cout << pIpAddrString->IpAddress.String << endl;
pIpAddrString = pIpAddrString->Next;
} while (pIpAddrString);
pIpAdapterInfo = pIpAdapterInfo->Next;
cout << "*****************************************************" << endl;
}
return;
}
//結果輸出4(篩選內網網卡)
void Output4(PIP_ADAPTER_INFO pIpAdapterInfo)
{
//可能有多網卡,因此通過迴圈去判斷
while (pIpAdapterInfo)
{
//篩選內網網卡
if (!IsIntranetIP(pIpAdapterInfo))
{
pIpAdapterInfo = pIpAdapterInfo->Next;
continue;
}
//輸出信息
cout << "網卡名稱:" << pIpAdapterInfo->AdapterName << endl;
cout << "網卡描述:" << pIpAdapterInfo->Description << endl;
cout << "網卡MAC地址:" << pIpAdapterInfo->Address;
for (UINT i = 0; i < pIpAdapterInfo->AddressLength; i++)
{
if (i == pIpAdapterInfo->AddressLength - 1)
{
printf("%02x\n", pIpAdapterInfo->Address[i]);
}
else
{
printf("%02x-", pIpAdapterInfo->Address[i]);
}
}
cout << "網卡IP地址如下:" << endl;
IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
//可能網卡有多IP,因此通過迴圈去判斷
do
{
cout << pIpAddrString->IpAddress.String << endl;
pIpAddrString = pIpAddrString->Next;
} while (pIpAddrString);
pIpAdapterInfo = pIpAdapterInfo->Next;
cout << "*****************************************************" << endl;
}
return;
}