一 简介

在使用wireshark时,最烦恼的事莫过于在海量的数据包筛选出所需要的内容。特别我们需要分析一个特定的程序的协议时,这时候如果有一个可以把进程名作为过滤器就完美了。在上网查阅资料时发现有一个实现,不过版本比较古老,是2012年十一月的,原文在这里:

Wireshark · Wireshark-dev: Re: [Wireshark-dev] [PATCH] Filter by local process name

我参照它的代码在最近的版本中实现了一下,发现确实可用。

我在这个版本的基础上修改:

Revision: 0b8acdaf689b6a4bd3d6fc7c14ac20f172831a3e
Author: Oscar Gonzalez de Dios <oscar.gonzalezdedios@telefonica.com>
Date: 2021/7/28 22:38:58
Message:
Fixed trailing whitespaces

----
Modified: epan/dissectors/packet-pcep.c

二 获取IP包对应的进程

首先要把进程和端口号关联在一起,每个连接使用的端口都是唯一的,在windows下可以使用netstat命令查询每个连接对应的源地址、目标地址、端口和进程PID。这里是通过process_info.h和process_info.c实现。

process_info.h

/* process_info.h* Process information (pid, process name)** $Id$** Wireshark - Network traffic analyzer* By Bogdan Harjoc <harjoc@gmail.com>* Copyright 1998 Gerald Combs** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version 2* of the License, or (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.*/#ifndef __PROCESS_INFO_H__
#define __PROCESS_INFO_H__#include <epan/packet.h>/** returns the name of the process based on the src:port - dst:port data from tvb */
const char *process_info_lookup(tvbuff_t *tvb);#endif /* process_info.h */

process_info.c

/* process_info.c* Process information (pid, process name)** $Id$** Wireshark - Network traffic analyzer* By Bogdan Harjoc <harjoc@gmail.com>* Copyright 1998 Gerald Combs** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version 2* of the License, or (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.*/#ifdef _WIN32#include "config.h"#include <glib.h>
#include <stdio.h>
#include <stdlib.h>#include <windows.h>
#include <winsock.h>
#include <Iphlpapi.h>
#include <Psapi.h>#include "process_info.h"#include <epan/ipproto.h>typedef struct netstat {struct netstat* next;guint loc_ip;guint rem_ip;guint16 loc_port;guint16 rem_port;guint16 proto;guint pid;
} netstat_t;typedef struct procinfo {struct procinfo* next;guint pid;char name[1];
} procinfo_t;#define HASH_SIZE 971static procinfo_t* process_hash[HASH_SIZE] = { 0 };
static netstat_t* addr_hash[HASH_SIZE] = { 0 };
static netstat_t* pair_hash[HASH_SIZE] = { 0 };/*** 先查询PID是否已经在哈希表process_hash中,如果已存在则直接返回。* 否则通过ID打开进程,查询它的进程名,并存放到哈希表内。*/
static procinfo_t* lookup_pid(guint pid)
{procinfo_t* e;HANDLE hproc;static wchar_t process_name[MAX_PATH] = { 0 };guint len;// 在哈希表内查询,注意循环的作用是查询具有相同哈希值的所有procinfo_t结构for (e = process_hash[pid % HASH_SIZE]; e; e = e->next)if (e->pid == pid)return e;// 可能这里需要提权?hproc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);if (!hproc)return NULL;len = GetProcessImageFileName(hproc, process_name, MAX_PATH);CloseHandle(hproc);if (len == 0)return NULL;e = g_malloc(offsetof(procinfo_t, name) + (len + 1));if (!e)return NULL;/* must convert properly using WideCharToMultiByte here */_snprintf(e->name, len + 1, "%.*S", len, process_name);e->name[len] = 0;e->pid = pid;e->next = process_hash[pid % HASH_SIZE];process_hash[pid % HASH_SIZE] = e;return e;
}static guint lookup_addrs(guint16 proto, guint src_ip, guint16 src_port, guint dst_ip, guint16 dst_port)
{guint h_local = src_ip + src_port;guint h_remote = dst_ip + dst_port;guint h_pair = h_local + h_remote;netstat_t* e;/* src:dst matches src -> dst  or  dst -> src (established/connecting/closed/...) */for (e = pair_hash[h_pair % HASH_SIZE]; e; e = e->next)if ((e->loc_ip == src_ip && e->rem_ip == dst_ip && e->loc_port == src_port && e->rem_port == dst_port) ||(e->loc_ip == dst_ip && e->rem_ip == src_ip && e->loc_port == dst_port && e->rem_port == src_port))if (e->proto == proto)return e->pid;/* src matches src -> 0.0.0.0:0 (listening) */for (e = addr_hash[h_local % HASH_SIZE]; e; e = e->next)if (e->loc_ip == src_ip && e->loc_port == src_port && e->rem_ip == 0 && e->rem_port == 0)if (e->proto == proto)return e->pid;/* dst matches dst -> 0.0.0.0:0 (listening) */for (e = addr_hash[h_remote % HASH_SIZE]; e; e = e->next)if (e->loc_ip == dst_ip && e->loc_port == dst_port && e->rem_ip == 0 && e->rem_port == 0)if (e->proto == proto)return e->pid;/* src matches src -> something  or  something -> src (netstat and winpcap see different IP addrs) */for (e = addr_hash[h_local % HASH_SIZE]; e; e = e->next)if ((e->loc_ip == src_ip && e->loc_port == src_port && e->rem_port == dst_port) ||(e->rem_ip == src_ip && e->rem_port == src_port && e->loc_port == dst_port))if (e->proto == proto)return e->pid;/* dst matches dst -> something  or  something -> dst (netstat and winpcap see different IP addrs) */for (e = addr_hash[h_remote % HASH_SIZE]; e; e = e->next)if ((e->loc_ip == dst_ip && e->loc_port == dst_port && e->rem_port == src_port) ||(e->rem_ip == dst_ip && e->rem_port == dst_port && e->loc_port == src_port))if (e->proto == proto)return e->pid;return 0;
}static void netstat_update()
{guint buf_size = 0;guint h;char* buf = NULL;//netstat_t* e = NULL;int ret;unsigned i;MIB_TCPTABLE_OWNER_PID* mibTable;/*** 清除addr_hash和pair_hash两个哈希表的值。*/for (h = 0; h < HASH_SIZE; h++) {while (addr_hash[h]) {netstat_t* head = addr_hash[h];addr_hash[h] = addr_hash[h]->next;g_free(head);}while (pair_hash[h]) {netstat_t* head = pair_hash[h];pair_hash[h] = pair_hash[h]->next;g_free(head);}}/* 执行netstat */ret = GetExtendedTcpTable(NULL, &buf_size, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);if (ret == ERROR_INSUFFICIENT_BUFFER) {buf = g_malloc(buf_size);if (!buf) return;ret = GetExtendedTcpTable(buf, &buf_size, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);}if (ret != NO_ERROR) {g_free(buf);return;}mibTable = (MIB_TCPTABLE_OWNER_PID*)buf;for (i = 0; i < mibTable->dwNumEntries; i++) {guint src_ip = _byteswap_ulong(mibTable->table[i].dwLocalAddr);guint dst_ip = _byteswap_ulong(mibTable->table[i].dwRemoteAddr);guint src_port = _byteswap_ushort((unsigned short)mibTable->table[i].dwLocalPort);guint dst_port = _byteswap_ushort((unsigned short)mibTable->table[i].dwRemotePort);guint pid = mibTable->table[i].dwOwningPid;guint h_local = src_ip + src_port;guint h_remote = dst_ip + dst_port;guint h_pair = h_local + h_remote;netstat_t* e;/* 添加以下项目到哈希表中:- src->dst and dst->src to pair_hash[src:dst]  -- note that hash(src:dst) == hash(dst:src)- src->dst and dst->src to addr_hash[src]- src->dst and dst->src to addr_hash[dst]dst:src is also added in order to find packets coming in both directionsnetstat_t带有next指针,用它可以将相同哈希值的元素串在一起。*///// 要假设数据包为出去的包// netstat_t.local ip = IP包的source ip// netstat_t.remote ip = IP包的destination ip// 同时,让addr_hash[src_ip + src_port] = addr_hash[dst_ip + dst_port]//e = g_malloc(sizeof(netstat_t));if (!e)break;e->loc_ip = src_ip;e->rem_ip = dst_ip;e->loc_port = src_port;e->rem_port = dst_port;e->proto = IP_PROTO_TCP;e->pid = pid;e->next = addr_hash[h_local % HASH_SIZE];addr_hash[h_local % HASH_SIZE] = e;e = g_malloc(sizeof(netstat_t));if (!e)break;e->loc_ip = src_ip;e->rem_ip = dst_ip;e->loc_port = src_port;e->rem_port = dst_port;e->proto = IP_PROTO_TCP;e->pid = pid;e->next = addr_hash[h_remote % HASH_SIZE];addr_hash[h_remote % HASH_SIZE] = e;//// 要假设数据包是回来的包// netstat_t.local ip = IP数据包.destination IP.// netstat_t.remote ip = IP数据包.source IP// 同时,让addr_hash[src_ip + src_port] = addr_hash[dst_ip + dst_port]//e = g_malloc(sizeof(netstat_t));if (!e)break;e->loc_ip = dst_ip;e->rem_ip = src_ip;e->loc_port = dst_port;e->rem_port = src_port;e->proto = IP_PROTO_TCP;e->pid = pid;e->next = addr_hash[h_local % HASH_SIZE];addr_hash[h_local % HASH_SIZE] = e;e = g_malloc(sizeof(netstat_t));if (!e)break;e->loc_ip = dst_ip;e->rem_ip = src_ip;e->loc_port = dst_port;e->rem_port = src_port;e->proto = IP_PROTO_TCP;e->pid = pid;e->next = addr_hash[h_remote % HASH_SIZE];addr_hash[h_remote % HASH_SIZE] = e;//// pair_hash[src_ip + src_port + dst_ip + dst_port] = e;//// 假设是出去方向,netstat_t.local ip = IP包的source ip。e = g_malloc(sizeof(netstat_t));if (!e)break;e->loc_ip = src_ip; e->rem_ip = dst_ip;e->loc_port = src_port;e->rem_port = dst_port;e->proto = IP_PROTO_TCP;e->pid = pid;e->next = pair_hash[h_pair % HASH_SIZE];pair_hash[h_pair % HASH_SIZE] = e;// 假设是回来方向,netstat_t.local ip = IP数据包.destination IP.。e = g_malloc(sizeof(netstat_t));if (!e)break;e->loc_ip = dst_ip;e->rem_ip = src_ip;e->loc_port = dst_port;e->rem_port = src_port;e->proto = IP_PROTO_TCP;e->pid = pid;e->next = pair_hash[h_pair % HASH_SIZE];pair_hash[h_pair % HASH_SIZE] = e;}g_free(buf);
}const char* process_info_lookup(tvbuff_t* tvb)
{static char buf[64];guint ip_vhl = tvb_get_guint8(tvb, 0);//guint ip_len = tvb_get_ntohs(tvb, 2);guint8 ip_proto = tvb_get_guint8(tvb, 9);guint proto_ofs;guint src_ip = tvb_get_ntohl(tvb, 12);guint dst_ip = tvb_get_ntohl(tvb, 16);guint16 src_port;guint16 dst_port;guint pid;procinfo_t* info;if (ip_vhl >> 4 != 4)return NULL;if (ip_proto != IP_PROTO_TCP /* && ip_proto != IP_PROTO_UDP */)return NULL;proto_ofs = (ip_vhl & 0xf) * 4;src_port = tvb_get_ntohs(tvb, proto_ofs + 0);dst_port = tvb_get_ntohs(tvb, proto_ofs + 2);pid = lookup_addrs(ip_proto, src_ip, src_port, dst_ip, dst_port);if (!pid) {netstat_update();pid = lookup_addrs(ip_proto, src_ip, src_port, dst_ip, dst_port);if (!pid)return NULL;}info = lookup_pid(pid);if (!info)return NULL;return info->name;
}#else /* _WIN32 */const char* process_info_lookup(tvbuff_t* tvb) { return NULL; }#endif /* _WIN32 */

代码非常简短,实现思路也非常简单,使用GetExtendedTcpTable实现类似netstat命令的效果,获取当前所有连接的源IP、源端口、目标IP、目标端口、PID等,然后使用几种IP加端口的不同方法做哈希放到几个哈希表中。当有个IP包要解析的时候程序就去这个哈希表里匹配,匹配到就返回PID对应的进程名字,要是匹配到就再执行一次GetExtendedTcpTable刷新整个哈希表并再其中查询。

三 在协议树里添加进程名

在协议树中添加的未知是IP报文协议部分,在原有的数据解析完成后在协议树的尾部添加一个新节点"Process Info: "。这个修改在packet-ip.c文件中做,具体由这个add_process_info函数实现:

static void
add_process_info(proto_tree * tree, tvbuff_t * tvb, gint offset){proto_item* process_info_item;proto_tree* process_info_tree;proto_item* item;const char* process_name;process_name = process_info_lookup(tvb);if (!process_name)return;process_info_item = proto_tree_add_text_internal(tree, tvb, offset + IPH_SRC, 4, "Process Info: ");PROTO_ITEM_SET_GENERATED(process_info_item);process_info_tree = proto_item_add_subtree(process_info_item, ett_ip_process_info);item = proto_tree_add_string(process_info_tree, hf_ip_process, tvb, offset, 4, process_name);PROTO_ITEM_SET_GENERATED(item);
}

也比较简单,首先是查IP包有没有对应的进程,没有就不管。

否则就往树中添加一个节点"Process Info: ",然后在它下面在创建一个字符串子节点,最后把进程名赋予它。

调用这个函数的地方是dissect_ip_v4这个解析IPv4数据包的地方,在此函数靠近尾部的地方调用即可。

最终的结果类似这样:

右键,选”在过滤器中应用“,在顶部的过滤器中展示的内容是:

ip.process == "\\Device\\HarddiskVolume8\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"

这样就可以根据进程路径过滤了。

四 其他

完整的修改在这里可以找到:

TurtleRock: 测试用。 - Gitee.com

或者这里:

https://download.csdn.net/download/lanzheng_1113/34964722

链接时会提示缺少符号,添加iphlpapi.lib到链接器就可以了。

程序目前由几个大缺陷和BUG:

  • 只支持TCP协议,UDP协议不支持。
  • 有些IP包解析后没有Process Info:字段。
  • 偶发crash,似乎和内存释放有关(暂不确定是不是因为此文中的修改导致,暂时没有空排查)

这几个问题等有空了再好好研究。

在Wireshark中按进程过滤相关推荐

  1. 在Wireshark中过滤UDS和OBD诊断ISO13400(DoIP)数据

    目录 0 WireShark简介 1如何在WireShark中添加诊断数据的"源地址"和"目标地址"列信息 2过滤诊断数据 3 解析以太网诊断DoIP数据 4 ...

  2. Linux内核中的进程等待与其实现解析

    一.进程等待的概述 进程通过 fork 产生子进程,进程也会死亡,进程退出的时候将会进行内核清理,释放所有进程的资源,资源包括:内存资源,文件资源,信号量资源,共享内存资源,或者引用计数减一,或者彻底 ...

  3. Linux 中的进程管理

    ### 1.进程定义 ### #进程的定义: 程序是静态的代码文件 进程是指程序运行时的形态 进程是程序的一个副本 进程是有生命周期的(准备期,运行期,终止期) #进程&线程 进程是资源调用的 ...

  4. wireshark windows版数据过滤插件安装及使用

    1.下载wireshark和数据过滤插件以及本文中所涉及的全部下载资源:http://download.csdn.net/detail/hjx_1000/6442019 2.数据过滤插件的安装方法: ...

  5. Linux中的进程管理

    Linux中的进程管理 Linux中的进程管理 Linux中的进程管理 1.进程 进程的定义 进程和线程 进程状态 2.进程查看命令 ps pgrep pidof top 3.进程优先级 4.进程前后 ...

  6. 【Linux操作系统基础】第六章 Linux中的进程管理

    一.进程及其状态 程序是静态的代码文件,没有生命周期.进程是指程序运行时的形态,是程序的一个副本,进程有生命周期(准备期,运行期,终止期) 进程是资源调用的最小单位,系统中的资源在同一时间只能被同一个 ...

  7. 16.WireShark学习-在WireShark中添加新协议

    16. 在Wireshark中添加新协议 WireShark编程基础 使用Lua开发简单扩展功能 使用WireShark开发新的协议解析器 测试新协议 WireShark支持Lua语言编写的脚本 16 ...

  8. 搞它!!!Linux系统中查看进程和计划任务管理

    文章目录 首先我们了解一下程序和进程的关系: 一.查看进程 1.查看静态的进程统计信息(ps) 2.查看静态的进程统计信息(top) 3.pgrep命令(查询进程信息) 4.pstree命令(查看进程 ...

  9. Wireshark图解教程和过滤方法(简介、抓包、过滤器)

    Wireshark是世界上最流行的网络分析工具.这个强大的工具可以捕捉网络中的数据,并为用户提供关于网络和上层协议的各种信息.与很多其他网络工具一样,Wireshark也使用pcap network ...

最新文章

  1. ​OpenVAS漏洞扫描基础教程之创建用户组与创建角色
  2. Ubuntu 将应用程序 固定到快快速启动栏(以Sublime为例)
  3. 安卓勒索软件进一步扩散
  4. JSP中include指令的乱码问题
  5. shell 中的return
  6. 谷歌浏览器怎么重发请求_chrome 浏览器的预提取资源机制导致的一个请求发送两次的问题以及ClientAbortException异常...
  7. 编译原理预测分析法c语言,编译原理预测分析法C语言的实验报告.doc
  8. Java客户端操作elasticsearch--创建索引(集群模式下)
  9. 电气期刊论文实现:热电联产经济调度【有代码】
  10. 基于Hexo搭建博客
  11. erlang OTP中的四大behaviour fsm的例子
  12. **【POJ - 2389】 Bull Math (高精度乘法)
  13. 福建省计算机c语言成绩查询时间,计算机C语言等级考试模拟题(福建省).doc
  14. 计算机电缆的最小弯曲半径,电缆最小弯曲半径-知道电缆长度直径弯曲半径,怎么计算出电缆盘大小-电工基础 - 电工屋...
  15. 开环控制系统与闭环控制系统
  16. js框架jquery实现的幸运大转盘抽奖程序代码,兼容多种浏览器(Internet Explorer 6.0+ 、Firefox 2.0 、Safari 3 、Opera 9 、Chrome)
  17. R语言随机森林模型回归randomForest
  18. 三星note20u计算机功能,三星Note20Ultra隐藏功能有哪些-有哪些使用技巧
  19. 微信小程序---霍兰德职业兴趣测试、心里测评、性格测评
  20. mybatis源码(一)

热门文章

  1. 【原创题】皮卡丘的兄弟姐妹
  2. MySQL中DELETE操作磁盘空间不会减少的原因
  3. python中的reshape是什么意思_python中reshape的用法(深度学习入门程序)
  4. 《中华百寺》专题片开机 江苏13古刹入选百大名寺
  5. anaconda调用TensorFlow出现dtypes.py:526: FutureWarning: Passing (type, 1) or ‘1type‘ as a synonym of typ
  6. python bp神经网络 异或_两层神经网络输出异或
  7. Revit API:Element 继承体系
  8. 第14周—项目1(3)二叉排序树
  9. 智能家居个人服务器代码大全,智能家居控制系统代码简介—了解一下智能家居控制系统代码...
  10. 备战金九银十,腾讯T4梳理2022年最全999道Java岗必备面试题答案