在Wireshark中按进程/PID过滤

155

有没有一种方法可以使用Wireshark根据特定的进程ID过滤或跟踪TCP/SSL流?


12
截至目前,Wireshark仍不支持此功能;但是,您可以在错误编号1184中跟踪其进展(如果有的话)。 - Christopher Maynard
1
那个问题有任何更新状态吗? - Ângelo Polotto
2
对于仍然希望拥有此功能的任何人,该问题已迁移到GitLab 此处 - gcode
13个回答

99

如果你正在寻找一种替代方法,而且你使用的是Windows环境,那么微软的网络监视器3.3是一个不错的选择。它有进程名称列。你可以很容易地将其添加到筛选器中,并使用上下文菜单应用筛选器。像往常一样,它的GUI非常直观...


13
Microsoft Network Monitor 3.4 可在 http://www.microsoft.com/en-us/download/details.aspx?id=4865 下载。 - g t
48
还有一个名为Microsoft Message Analyzer的工具,基本上就是微软版的Wireshark(我所知道的,它也是Network Monitor的后继者),但更好地集成了一些功能。在“列选择器”中,“Etw”→“EtwProviderMsg”下有一个“PID”列。它的效果很好! - Cameron
6
准确的路径是 EtwProviderMsg -> EventRecord -> Header -> ProcessId。 - r590
13
微软消息分析器已于2019年11月25日退役。他们建议改用Wireshark。 - angularsen
9
想下载微软消息分析器的人可以点击以下链接获取下载地址:https://web.archive.org/web/20191104120802/https://download.microsoft.com/download/2/8/3/283DE38A-5164-49DB-9883-9D1CC432174D/MessageAnalyzer.msi <-- 32位系统用;https://web.archive.org/web/20191104120853/https://download.microsoft.com/download/2/8/3/283DE38A-5164-49DB-9883-9D1CC432174D/MessageAnalyzer64.msi <-- 64位系统用。 - sam1370
显示剩余6条评论

64

我不明白如何做到。通常情况下,进程ID(PID)并不会传输到网络上,而且Wireshark允许您查看在网络上正在通信的所有设备 - 这可能包括所有的设备。不管怎样,在不同的设备上,进程ID并不是唯一的。


7
好观点,这也是我想的。在关闭之前,让我等一天,以防有Wireshark高手能够完成这个任务。 - Ryan Fernandes
60
Wireshark知道正在使用的端口,操作系统知道使用该端口的进程的PID。通过代码更改,Wireshark应该可以将端口映射到PID。但在某些情况下可能会出现问题,例如当操作系统在Wireshark查询端口的PID之前将端口重新分配给另一个应用程序时。因此,这不是百分之百可靠和无故障的,但如果用户知道这些限制,它仍然是一个有用的功能。 - Dojo
我认为只需在Wireshark中添加一个模块,用于监听端口的打开/关闭,并将PID映射到端口。将其与主进程同步,您就可以得到完美的端口到进程映射器。但是,从问题评论中阅读错误,该模块创建起来并不简单。 - Vesper
1
我记得第一次下载Wireshark时,它显示了进程树,你可以选择一个进程进行监视。不知道这个选项什么时候消失了,但它曾经存在过。 - Tomáš Zato

16

您可以将Wireshark中的端口号与例如netstat的端口号进行匹配,这将告诉您正在监听该端口的进程的PID。


14
这可能行不通...该程序会打开并关闭很多本地和远程端口。 - Ryan Fernandes

11

使用 Microsoft Message Analyzer v1.4。

从字段选择器中导航到 ProcessId。

Etw
-> EtwProviderMsg
--> EventRecord
---> Header
----> ProcessId

右键点击并选择 添加为列


1
谢谢你指引我找到这个,正是我需要的。顺便说一下,“ProcMon”顶级组似乎包含相同的ProcessId,以及其他信息,如进程名称、ParentId等。 - Tobias J
1
MMA已死。 MMA已死。 - huang

9

在这种情况下,使用{{link1:strace}}更加合适。

strace -f -e trace=network -s 10000 -p <PID>;

选项:

  • -f 以跟踪所有派生进程的方式进行追踪,
  • -e trace=network 仅过滤网络系统调用,
  • -s 显示字符串长度最多为10000个字符。

您还可以跟踪特定的调用,如发送、接收和读取操作:

strace -f -e trace=send,recv,read -s 10000 -p <PID>;

8
如果您想要跟踪一个尚未启动的应用程序,那么这是完全可能的:
  1. 安装Docker(参见https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
  2. 打开终端并运行一个微小的容器:docker run -t -i ubuntu /bin/bash(将“ubuntu”更改为您喜欢的发行版,这不必与您真实系统中的相同)
  3. 使用与在真实系统中安装它相同的方式在容器中安装您的应用程序。
  4. 在您的真实系统中启动Wireshark,转到捕获>选项。在打开的窗口中,您将看到所有接口。而不是选择任何wlan0eth0等,请选择新的虚拟接口docker0
  5. 开始捕获
  6. 在容器中启动您的应用程序

您可能对在容器中运行软件有些疑虑,因此以下是您可能想要问的问题的答案:

  • 我的应用程序能在容器中运行吗?几乎肯定可以,但您可能需要学习一些关于docker的知识才能使其正常工作。
  • 我的应用程序不会变慢吗?可以忽略不计。如果您的程序是运行重型计算一周,那么现在可能需要一周零3秒。
  • 如果我的软件或其他东西在容器中出现问题怎么办?这就是容器的好处。无论其中运行什么,都只会破坏当前容器,而不会影响整个系统。

4

这个机制在Wireshark中实现,可以将Wireshark的端口号与netstat中的端口号进行匹配,从而确定监听该端口的进程的PID。正如消息所指出的那样,这种方法存在一定的局限性。 - user862787
请问如何应用PID滤波器? - Ahmed Suror
请问如何应用PID滤波器? - undefined

3
这是一个重要的技能,可以用于监控某些进程尝试连接的位置,在Linux上似乎没有便捷的方法来实现这一点。然而,有几种解决方法是可行的,因此我认为值得一提。
有一个名为nonet的程序,允许在没有Internet访问权限的情况下运行程序(我在系统上设置了大多数程序启动器)。它使用setguid在组nonet中运行进程,并设置iptables规则以拒绝来自该组的所有连接。
更新:现在我使用更简单的系统,您可以使用ferm轻松获得可读的iptables配置,并使用程序sg以特定组运行程序。Iptables还允许您重新路由流量,因此您甚至可以将其路由到单独的接口或本地代理上的端口,从而允许您在wireshark中进行过滤或直接从iptables LOG数据包,如果您不想在检查流量时禁用所有Internet。

将其适应于在组中运行程序并使用iptables切断所有其他流量以执行生命周期并且然后只能从此进程捕获流量并不是很复杂。

如果我有时间写它,我会在这里发布链接。

另外,您始终可以在虚拟机中运行进程并嗅探正确的接口以隔离它所做的连接,但那将是相当低劣的解决方案...


2
我有一个PowerShell脚本,可能对这种情况有帮助,我把它放在这里并做了一点美化。 我在Windows 10上使用PowerShell版本5.2和7.2进行了测试,但目前无法在其他操作系统上进行测试。 其作用: 它构建了一个Wireshark过滤器,其中包含进程在网络统计中使用的IP和端口。您可以先查看最后两张图片以更好地理解它。 详细信息如下: 获取TCP(侦听器和连接)和UDP(侦听器)的网络统计信息,多次执行直到您想继续为止。您需要等待直到完成进程测试。当您选择继续时,它会显示当前进程及其进程ID,您必须从中选择一个或多个进程。进程是您可以应用的第一个过滤器 - OP想要的情况应该只有一个进程。然后,您必须选择您的过滤器中可能需要的连接/端口 - 通常在此处选择全部。之后,您必须选择另一种类型的过滤器,这也定义了Wireshark过滤器的外观。过滤器将显示并自动复制到剪贴板。
根据您的选择和您的进程,过滤器可能变得很长。 其不足之处: 它无法监视您的进程及其网络活动。它只是多次获取数据。在获取命令之间,您可能会错过一些连接。它也无法查看任何UDP数据包,因此无法获得有关UDP远程部分的任何信息。但它将获取本地UDP侦听端口。 其他限制如下: 0.0.0.0上的本地侦听将转换为您的本地IP地址。由于我目前没有进行本地连接监视,因此跳过在127.0.0.1上的侦听。
以下是代码:
"Attention: This script can NOT make a filter for a process, but it can build it regarding some local to remote connections (TCP) and vice versa,  and ports (UDP)."
"It works good for some cases, but not for all."
"In general it is designed to filter as less as possible."
"You may still see packets from some other processes depending on your selection"
""
"Press return to continue"
Read-Host | Out-Null

# Load Functions
function Out-WireSharkSyntax($data) {
    $data = $data -replace "\)|\(| eq | or | and |==|!|{|}| not | in ",';$0;' -split ";"
    foreach ($Line in $data) {
        $color = switch ($Line) {
            "(" {"blue"}
            ")" {"blue"}
            "!" {"cyan"}
            " eq " {"yellow"}
            " or " {"cyan"}
            " and " {"cyan"}
            " not " {"cyan"}
            " in " {"cyan"}
            "==" {"yellow"}
            "||" {"yellow"}
            "{" {"darkred"}
            "}" {"darkred"}
            Default {"green"}
        }
    Write-Host -ForegroundColor $color -NoNewline -BackgroundColor Black $line}
}


$count=0
$sleepTimer=500 #in milliseconds to restart the query for used TCP ports and listening UDP ports
$QuitKey=81 #Character code for 'q' key.

$CurrentDateTime = Get-Date
#$LocalIPv4address = @(Get-NetIPAddress -AddressFamily IPv4 -InterfaceIndex $(Get-NetConnectionProfile | Select-Object -ExpandProperty InterfaceIndex) | Select-Object -ExpandProperty IPAddress)
$LocalIPv4address = (Get-NetIPAddress -AddressFamily IPv4 -AddressState Preferred -PrefixOrigin manual,dhcp).IPAddress
if ($LocalIPv4address.count -ne 1) {
    "Could not detect exact one IPAddress. Enter the IPAddress to be used:`r`nYour local dectected addresses were:$($LocalIPv4address -join " OR ")"
    $LocalIPv4address = Read-Host
}

"Retrieving network network statistics every $sleepTimer milliseconds..."
"(very short connections may not be captured with this script because of this!)"

$TcpAndUdpProperties = @{Name="NetStatEntryAsString";Expression={$_.LocalAddress + "--" + $_.LocalPort + "--" + $_.RemoteAddress + "--" + $_.RemotePort + "--" + $_.cimclass.cimclassname}},`
"LocalAddress","LocalPort","OwningProcess","RemoteAddress","RemotePort","CreationTime"
# Properties for both equal to get equal list header in all cases
$TcpAndUdpNetworkStatistic = @()

Write-Host "Press 'q' to stop collecting network statistics and to continue with the script."
Write-Host "Wireshark should now capture and you start what ever you would like to monitor now."

while($true)
{
    if($host.UI.RawUI.KeyAvailable) {
        $key = $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyUp")
        if($key.VirtualKeyCode -eq $QuitKey) {
            #For Key Combination: eg., press 'LeftCtrl + q' to quit.
            #Use condition: (($key.VirtualKeyCode -eq $Qkey) -and ($key.ControlKeyState -match "LeftCtrlPressed"))
            Write-Host ("`r`n'q' is pressed! going on with the script now.")
            break
        }
    }
    # Temporary convertion to JSON ensures that not too much irrelevant data being bound to the new variable
    $TcpAndUdpNetworkStatistic += `
    (Get-NetTCPConnection | select -Property $($TcpAndUdpProperties + @{Name="Protocol";Expression={"TCP"}}) | ConvertTo-Json | ConvertFrom-Json) + `
    (Get-NetUDPEndpoint   | select -Property $($TcpAndUdpProperties + @{Name="Protocol";Expression={"UDP"}}) | ConvertTo-Json | ConvertFrom-Json)
    # exclude IPv6 as it is not handled in this script, remove 127.0.0.1 connections and remove duplicates
    $TcpAndUdpNetworkStatistic = $TcpAndUdpNetworkStatistic | where {$_.LocalAddress -notmatch ":" -and $_.LocalAddress -notlike "127.*"} | ConvertTo-Csv -NoTypeInformation | Sort-Object -Unique -Descending |ConvertFrom-Csv | sort Protocol,LocalAddress,LocalPort
    $TcpAndUdpNetworkStatistic | where {$_.localaddress -eq "0.0.0.0"} | foreach {$_.localaddress = $LocalIPv4Address}
    
    $count++
    Write-Host ("`rChecked network statistics {0} time{1}. Collected {2} netstat entries" -f $count,$(("s"," ")[($count -eq "1")]),$TcpAndUdpNetworkStatistic.Count) -NoNewline
    
    Start-Sleep -m $sleepTimer
}
    $TcpAndUdpNetworkStatistic | where {$_.localaddress -eq "0.0.0.0"} | foreach {$_.localaddress = $LocalIPv4Address}



$ProcessIDToNetworkstatistic = $TcpAndUdpNetworkStatistic | Group-Object OwningProcess -AsHashTable -AsString
"Getting processlist..."
$processselection = "Id", "Name", @{Name="MainModuleName";Expression={$_.MainModule.ModuleName}}, "Company",
"Path", "Product", "Description", "FileVersion", "ProductVersion", "SessionID", "CPU", "Threads", "StartTime"
$GetNetListedProcesses = Get-Process | Where {$ProcessIDToNetworkstatistic.GetEnumerator().name -contains $_.ID} | Select -Property $processselection

"Output processlist to gridview... Read the gridview title and make selection there..."
$ProcessIDs = ($GetNetListedProcesses |Select @{Name="Port/Session Count";Expression={$ProcessIDToNetworkstatistic["$($_.id)"].count}},* | `
Out-GridView -Title "Select process to view network statistics related to process id" -Passthru).ID

"Output related network statistics to gridview... Read the gridview title and make selection there..."
$TcpAndUdpNetworkStatisticFilteredByProcessID = $TcpAndUdpNetworkStatistic | Where {$ProcessIDs -contains $_.OwningProcess} | `
Out-Gridview -Title "Select lines that contain data you may like to have in your Wireshark filter" -Passthru


# for statistic and later processing
$UDPLocalPorts = ($TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "UDP"}).LocalPort | foreach {[int]$_} | Sort-Object -Unique
$TCPConnections = $TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "TCP"}
$TCPLocalPorts = @(foreach ($Connection in $TCPConnections) { [int]$Connection.LocalPort }) | Sort-Object -unique
$TCPRemotePorts = @(foreach ($Connection in $TCPConnections) { [int]$Connection.RemotePort })| Sort-Object -unique | where {$_ -ne 0}
$UDPLocalEndpoints = $TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "UDP"}
$UDPLocalPorts = @(foreach ($Endpoint in $UDPLocalEndpoints) { [int]$Endpoint.LocalPort }) | Sort-Object -unique


$FilterOptionsDialog = "
You can choose between the following filters
[all] for UDP + TCP filter - including remote address where possible ( filterable: $(($TcpAndUdpNetworkStatisticFilteredByProcessID).count) )
[tall] for TCP with listening ports and connections including remote ports and addresses ( filterable: $(($TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "TCP"}).count) )
[tcon] for TCP without listening ports - only connections including remote ports and addresses ( filterable: $(($TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "TCP" -and [int]$_.RemotePort -eq 0}).count) )
[u] for UDP portfilter - only local listening port - no `"connections`" ( filterable: $(($TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "UDP"}).count) ) 
[p] for portfilter only by ports ( filterable: $($TCPLocalPorts.count) local TCP / $($TCPRemotePorts.count) remote TCP / $($UDPLocalPorts.count) UDP )
[ptl] for portfilter only by local TCP ports (no UDP) ( filterable: $($TCPLocalPorts.count) local TCP / $($TCPRemotePorts.count) remote TCP )
[pt] for portfilter only by TCP ports (remote port ignored and no UDP) ( filterable: $($TCPLocalPorts.count) local TCP )
[pu] for portfilter only by UDP ports (only listening ports - no information about used ports) ( filterable: $($UDPLocalPorts.count) )
Type your selection and press return"
$WiresharkFilter = ""
do {
    $tmp = read-host $FilterOptionsDialog
} while ("all","u","tcon","tall","p","pt","ptl","pu" -notcontains $tmp)
switch ($tmp)
{
    
    "all" {
        # TCP connections with local and remote IP filter - both ports included - udp only listening are included
        $ConnectionFilterResolved = "("
        $ConnectionFilterResolved += $(foreach ($connection in $TcpAndUdpNetworkStatisticFilteredByProcessID) {
            if ([int]$connection.remoteport -eq 0) {
                $ConnectionFilter = "(ip.addr eq {0} and {2}.port eq {1})"
                $ConnectionFilter -f $connection.LocalAddress,$connection.LocalPort,$connection.Protocol.ToLower()
                } else {
                $ConnectionFilter = "(ip.addr eq {0} and ip.addr eq {1}) and (tcp.port eq {2} and tcp.port eq {3})"
                $ConnectionFilter -f $connection.LocalAddress,$connection.RemoteAddress, $connection.LocalPort, $connection.RemotePort
            }
        }) -join ") or ("
        $ConnectionFilterResolved += ")"
        $WiresharkFilter += $ConnectionFilterResolved
    }
    
    "u" {
        # udp.port only - without remote IP filter
        #Building the filter variable
        $FilteredPortlist = $TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "UDP"} | foreach { "udp.port eq $($_.LocalPort)"} | sort | get-unique
        if ($FilteredPortlist) {
            $WiresharkFilter += "(" +
            ($FilteredPortlist -join ") or (") +
            ")"
        }
    }
    
    
    "tall" {#tall
        # TCP connections with local and remote IP filter - both ports included - only listening are included without remote data)
        $tcpStatsFilterResolved = "("
        $tcpStatsFilterResolved += $(foreach ($connection in ($TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "TCP"} )) {
            if ([int]$connection.remoteport -eq 0) {
                $TcpFilter = "(ip.addr eq {0} and tcp.port eq {1})" 
                $TcpFilter -f $connection.LocalAddress,$connection.LocalPort
                } else {
                $TcpFilter = "(ip.addr eq {0} and ip.addr eq {1}) and (tcp.port eq {2} and tcp.port eq {3})"
                $TcpFilter -f $connection.LocalAddress,$connection.RemoteAddress, $connection.LocalPort, $connection.RemotePort
            }
        }) -join ") or ("
        $tcpStatsFilterResolved += ")"
        $WiresharkFilter += $tcpStatsFilterResolved
    }
    
    "tcon" {
        # TCP connections only - listening only ports are not included)
        $tcpStatsFilterResolved = "("
        $tcpStatsFilterResolved += $(foreach ($connection in ($TcpAndUdpNetworkStatisticFilteredByProcessID | where {$_.Protocol -eq "TCP" -and [int]$_.RemotePort -eq 0} )) {
            $TcpFilter = "(ip.addr eq {0} and ip.addr eq {1}) and (tcp.port eq {2} and tcp.port eq {3})"
            $TcpFilter -f $connection.LocalAddress,$connection.RemoteAddress, $connection.LocalPort, $connection.RemotePort
        }) -join ") or ("
        $tcpStatsFilterResolved += ")"
        $WiresharkFilter = $tcpStatsFilterResolved
    }
    
    "p" {
        # Ports only - remote and local
        $TCPWiresharkFilter = "tcp.port in {" + ( ($TCPLocalPorts + $TCPRemotePorts | Sort-Object -unique ) -join ", " ) + "}"

        $UDPWiresharkFilter = "udp.port in {" + ( $UDPLocalPorts -join ", " ) + "}"
        $Or = ( ""," or " )[$TCPConnections.count -gt 0 -and $UDPLocalEndpoints.count -gt 0]
        $WiresharkFilter = "$TCPWiresharkFilter$Or$UDPWiresharkFilter"
    }
    
    "ptl" {
        # Local tcp ports only - remote are excluded
        $WiresharkFilter = "tcp.port in {" + ( $TCPLocalPorts -join ", " ) + "}"
    }
    
    "pt" {
        # tcp ports only - remote and local ports
        $WiresharkFilter = "tcp.port in {" + ( ($TCPLocalPorts + $TCPRemotePorts | Sort-Object -unique ) -join ", " ) + "}"

    }
    
    "pu" {
        # udp ports only - no remote anyway
        $WiresharkFilter = "udp.port in {" + ( $UDPLocalPorts -join ", " ) + "}"
    }
    
    
}
if ($WiresharkFilter.toString().length -gt 5) {
    # Output to clipboard
    $WiresharkFilter | Set-Clipboard
    "The following filter should be in your clipboard already"
    ""
    ""
    Out-WireSharkSyntax $WiresharkFilter
    ""
    ""
    "Attention: All filtering is done on network statistic data arrount that time `"$CurrentDateTime`" and the additional $(1 - $count) checks that were done."
    "`tThis filter is not perfect, but it works for some cases or is a good template to be customized afterwards."
    } else {
    "Everything was filtered out by your selections - I got no data to create a filter"
}
""
"Press return to end script"
Read-Host | Out-Null

这是可能的效果: 主要步骤 结果 另一种可能的结果: 结果_pt 您可以根据自己的需求优化代码,但对我来说已经足够了。如果有人已经为Wireshark找到更好/内置的解决方案,请分享您的信息。

0
2023年我发现的最佳Windows选项是使用WinShark,它并不是很出名。

https://github.com/airbus-cert/Winshark

它使用ETW来捕获与每个数据包相关的PID,你只需要使用类似于winshark.header.ProcessId == 1234这样的语句。

enter image description here

安装它也非常简单,这在他们的 GitHub 上有详细说明。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接