Dev.to AI 🤖 Ai 👁 0 📖 4 min read

Wireshark cannot filter by process on Windows. Here is what does.

On Windows, Wireshark captures below the socket layer. The packets it produces carry no process semantics — there is no field in a TCP/IP header that says "this came from WeChat.exe". So when you capture for 30 seconds a

On Windows, Wireshark captures below the socket layer. The packets it produces carry no process semantics — there is no field in a TCP/IP header that says "this came from WeChat.exe". So when you capture for 30 seconds and get 40,000 packets from 60 different connections, you are left guessing by port number which ones belong to the app you actually care about.

This is not a Wireshark bug. It is a structural property of where capture happens. Wireshark does have a _ws.process.id field, but it is populated from ETW metadata (NDIS layer), not from libpcap. If you start a capture directly in the Wireshark GUI, that field stays empty.

The workaround: pktmon

Windows 10 1809+ ships pktmon, a built-in capture tool that writes the PID into the ETL at capture time. That is the key difference — the process identity is recorded by the kernel during capture, not reconstructed afterwards.

In an administrator terminal:

pktmon start --capture --pkt-size 4096 --file-name cap.etl
:: do the thing in the target app
pktmon stop
pktmon etl2pcap cap.etl --out cap.pcapng

Then filter by PID with tshark (get the PID from Task Manager or tasklist | findstr appname):

tshark -r cap.pcapng -Y "_ws.process.id == 12345" -w filtered.pcap

filtered.pcap opens in Wireshark containing only the target process's packets. Statistics → Conversations now gives you a clean connection list instead of everything on the machine.

What this does and doesn't solve

It solves attribution: which packets belong to which process. It does not solve content. HTTPS is still ciphertext. For plaintext you need a MITM proxy (mitmproxy, Charles, Fiddler), the target has to route through it, and it has to trust your CA.

The filtering problem reappears at the proxy layer in a different form: mitmproxy records every flow through the proxy, including the browser and everything else. The trick that works is to take each flow's client source port, look it up in psutil.net_connections(), and keep only flows whose resolved PID matches the target.

Two things will bite you:

  • SSL Pinning. Plenty of clients — finance, trading, some games — hardcode the server certificate fingerprint. Installing the mitmproxy CA does nothing; the handshake fails. That needs a Frida hook on the certificate validation function, which is reverse engineering, not packet capture.
  • Proxy bypass. Desktop apps do not reliably read the system proxy. Some need HTTP_PROXY / HTTPS_PROXY set before launch; some are hardcoded to direct connections. QUIC and raw UDP bypass the proxy entirely, though L3/L4 still sees them.

The tool

I wrapped this whole flow into proc-sniffer — pktmon capture with PID filtering, plus an optional mitmproxy L7 layer that maps source port → PID so you only get plaintext for the process you asked for.

It ships as both a CLI and an MCP server, so an agent can start a capture, stop it, and export the results inside one conversation.

process name --psutil--> PID / local ports
  L3/L4: pktmon (captures with PID) --> ETL --etl2pcapng--> pcapng --filter by PID--> filtered.pcap
  L7   : mitmproxy (proxy, filter by src port -> PID) --> http_traffic.jsonl
  export: requests.json / index.md / filtered.pcap / http_traffic.jsonl
# L3/L4 + L7, capture "chrome" for 30 seconds
python proc_sniffer.py chrome 30 full

Output lands in %PROC_SNIFFER_WORKDIR%\exports\<app>\:

  • requests.json / index.md — connection list
  • filtered.pcap — only that process's packets, openable in Wireshark
  • http_traffic.jsonl — L7 plaintext, one {method,url,req_*,resp_*} per line

If Wireshark is not installed there is no tshark, so _ws.process.id filtering is unavailable. The fallback samples the target's local ports once per second during capture and filters by port. Short-lived connections can be missed.

Gotchas I hit while building it

  • PID drift. The process restarts, a child process spins up with a new PID. Matching on name/exe/cmdline is more stable than matching an exact PID.
  • Admin is mandatory. Both packet capture and reading all processes' connections require elevation.
  • etl2pcapng vs pktmon etl2pcap. The built-in converter works, but Microsoft's standalone etl2pcapng.exe produces slightly cleaner output. The tool uses whichever it finds.
  • macOS and Linux don't have this problem. lsof -i plus tcpdump, or ss -tp, gives you process names directly. The Windows detour exists because the NDIS layer does not carry process semantics.

Scope

The tool captures traffic from software running on your own machine. Use it on software you own or are authorized to analyze — for interoperability, debugging, security research, or learning. Capturing other people's traffic, or the traffic of services you have no right to inspect, may violate law and terms of service in your jurisdiction. That is not a disclaimer paragraph; it is the actual boundary of what the tool is for.

MIT licensed.

Repo: https://github.com/xiao77mwq/proc-sniffer

If you hit a case it cannot capture, open an issue with what the app is and what you were trying to see — I read them.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.