使用C++对物理网卡/虚拟网卡进行识别(包含内外网筛选)
简介
在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;
}
使用C++对物理网卡/虚拟网卡进行识别(包含内外网筛选)的更多相关文章
- 删除Windows中隐藏的物理网卡和网络虚拟化失败后的虚拟网卡
Windows环境下,在更换硬件服务器主板和网卡等硬件.恢复操作系统或者网络虚拟化失败后,可能会出现网卡方面的问题.例如,设备管理器中多了不应该存在的网卡:因命名冲突无法重命名当前网络连接:IP地址冲 ...
- C#如何获取物理网卡,虚拟网卡,以及无线网卡
就不废话了,直接上代码 /// <summary></summary> /// 显示本机各网卡的详细信息 /// <summary></summary> ...
- Linux下双物理网卡设置成虚拟网卡
为了提供网络的高可用我们须要将多块网卡绑定设置成一块虚拟的网卡对外提供服务,这样能够防止一块网卡损坏或者防止网线连接故障造成的连接中断. 以下我们使用eth0与eth1来虚拟成为bond0为例:--- ...
- 关闭Windows 系统当前连接的Wifi以及判断物理\虚拟网卡,有线\无线网卡
1.关闭wifi ,调用Api [DllImport("Wlanapi.dll", SetLastError = true)] public static extern uint ...
- java 判断虚拟网卡物理网卡
读取注册表方式,jregistrykey.jar与jregistrykey.dll.通过“characteristics”值确定虚拟网卡还是物理网卡.该值在注册表的位置HKEY_LOCAL_MACHI ...
- MAC地址获取,有线网卡与无线网卡、物理网卡与虚拟网卡的区分
获取当前活跃状态的网卡MAC地址.物理地址 Wmic命令:Win32_NetworkAdapter和Win32_NetworkAdapterConfiguration. 其中cmd命令行执行: 1. ...
- CentOS设置虚拟网卡做NAT方式和Bridge方式桥接
CentOS设置虚拟网卡做NAT方式和Bridge方式桥接 http://www.centoscn.com/CentOS/config/2015/0225/4736.html 摘要:KVM虚拟机网络配 ...
- 通过桥接虚拟网卡使VMWare和宿主机实现双向通讯
0.为什么选择虚拟网卡和桥接模式 首先虚拟机网络设置为NAT,虚拟机实现上网是很方便的,但是宿主机访问虚拟机就比较麻烦了(需要单独配置端口转发),桥接就能很好的解决这个问题,桥接模式会把虚拟机当做宿主 ...
- Linux下使用虚拟网卡的ingress流控(入口流控)
Linux内核实现了数据包的队列机制,配合多种不同的排队策略,可以实现完美的流量控制和流量整形(以下统称流控).流控可以在两个地方实现,分别为egress和ingress,egress是在数据包发出前 ...
随机推荐
- jxa快速入门,Javascript已加入AppleScript全家桶
因为工作环境基本是以跨平台为主,所以纯mac本地化的AppleScript一直关注是不够的,前几天找资料发现AppleScript也在迅速的进步着,目前已经对Javascript做了比较好的支持--- ...
- dotnet core 开发无缝兼容Http和Websocket协议的接口服务
在应用接口开发中往往要针对不同协义开发相应的代理服务,但对于Websocket和http这两种协议来说就有些不同,从实现上来看Websocket可以说是Http的升级子协议, 两者在协议处理上基本一致 ...
- SpringBoot入门教程(六)SpringBoot2.0统一处理404,500等http错误跳转页
在做web项目的时候,大家对404.500等http状态码肯定并不陌生.然而无论是哪种"非正常"状态码,都不是我们想遇到的.尤其像一些500这种服务器内部错误,不愿意展示给用户的, ...
- JavaScript面向对象--封装
一.封装的概念 面向对象的类包括两大成员,一种是暴露给外部的接口,另一种是只在类内部才能访问的私有属性.在这个类被实例化成对象后,用户只能通过操作给定的接口来访问该类内部的私有属性,这就被称为面向对象 ...
- 【java 多线程】多线程并发同步问题及解决方法
一.线程并发同步概念 线程同步其核心就在于一个“同”.所谓“同”就是协同.协助.配合,“同步”就是协同步调昨,也就是按照预定的先后顺序进行运行,即“你先,我等, 你做完,我再做”. 线程同步,就是当线 ...
- REST API设计指导——译自Microsoft REST API Guidelines(二)
由于文章内容较长,只能拆开发布.翻译的不对之处,请多多指教. 另外:最近团队在做一些技术何架构的研究,视频教程只能争取周末多录制一点,同时预计在下周我们会展开一次直播活动,内容围绕容器技术这块. 所有 ...
- Spring Boot 系列总目录
一.Spring Boot 系列诞生原因 上学那会主要学的是 Java 和 .Net 两种语言,当时对于语言分类这事儿没什么概念,恰好在2009年毕业那会阴差阳错的先找到了 .Net 的工作,此后就开 ...
- Jenkins结合.net平台之Web项目编译
前面我们讲解了如何使用msbuild.exe编译一个.net程序.示例中我们讲解的是编译控制台项目,但是我们知道web项目不仅需要编译类的嵌入的资源文件,还要拷贝诸如css,html,js,图片等资源 ...
- [Linux] 搭建rsync服务端
rsync是unix/linux下同步文件的一个高效算法,它能同步更新两处计算机的文件与目录,并适当利用查找文件中的不同块以减少数据传输. Linux守护进程的运行方式:1.独立运行(stand-al ...
- Java Calendar类的使用总结
在实际项目当中,我们经常会涉及到对时间的处理,例如登陆网站,我们会看到网站首页显示XXX,欢迎您!今天是XXXX年....某些网站会记录下用户登陆的时间,比如银行的一些网站,对于这些经常需要处理的问题 ...