使用C++对物理网卡/虚拟网卡进行识别(包含内外网筛选)

时间:2024-01-21 10:22:52

简介

在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;
}