使用C++對物理網卡/虛擬網卡進行識別(包含內外網篩選)

来源:https://www.cnblogs.com/PeterZ1997/archive/2018/08/24/9531551.html
-Advertisement-
Play Games

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

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 日誌作為快速定位程式問題的主要手段,日誌幾乎是所有程式都必須擁有的一部分,下麵我們就看下怎麼使用log4net.dll文件: 1.下載log4net.dll文件 2.創建自己的項目 3.在自己項目下的引用log4net.dll文件 4.在app.config配置文件里添加配置信息,下麵貼出配置信息, ...
  • 是因為webApi Views文件夾下缺乏web.config文件,從mvc項目相同目錄拷貝一個web.Config文件放入 刪除多餘的namespaces 即可 web.config配置如下: ...
  • ASP.NET Core的實時庫: SignalR簡介及使用 ...
  • asp.net core 2.1 部署IIS(win10/win7) 概述 與ASP.NET時代不同,ASP.NET Core不再是由IIS工作進程(w3wp.exe)托管,而是使用自托管Web伺服器(Kestrel)運行,IIS則是作為反向代理的角色轉發請求到Kestrel不同埠的ASP.NET ...
  • 今天在Vmware上安裝了CentOS6.5系統,下午首先把書上的安裝過程看了一遍,實際進行操作時有些步驟不一樣,經過查資料成功安裝,說一下收穫。選擇自定義安裝虛擬機,首先創建空白虛擬機,稍後編輯虛擬機,選擇DVD,添加鏡像。將磁碟以單文件形式使用,選擇亞洲上海時區,註意取消使用UTC。選擇Linu ...
  • 一 zabbix 的安裝部署 二監控 apache服務的配置 首先在本機下載模板:https://github.com/rdvn/zabbix-templates/archive/m aster.zip 該 zip 包有 apache、memcache、redis、varnish 模板,我們解壓後使 ...
  •     在Linux系統中,僅僅是關機和重啟相關的命令就至少有5個, shutdown、 halt、poweroff、reboot、init 。各個命令作用如下所示: | 命令 | 說明 | | | | | shutdown | 可用於關機、重啟。支持定時和通知 | | halt ...
  • Linux系統中,進程之間有一個明顯的繼承關係,所有進程都是 PID 為1的 init 進程的後代。內核在系統啟動的最後階段啟動 init 進程。該進程讀取系統的初始化腳本(initscript)並執行其他的相關程式,最終完成系統啟動的整個過程。 系統中每個進程必有一個父進程,相應的,每個進程也可以 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...