基于WFP的windows驱动对TCP数据的抓取,修改以及注意事项

您所在的位置:网站首页 显示器DP12有没有必要用14 基于WFP的windows驱动对TCP数据的抓取,修改以及注意事项

基于WFP的windows驱动对TCP数据的抓取,修改以及注意事项

2023-12-25 04:17| 来源: 网络整理| 查看: 265

基于WFP的windows驱动对TCP数据的抓取及修改 前言目的主要问题步骤一. WFP过滤TCP报文WFP过滤层 二. 追加OPTIONS数据TCP/IP数据报文格式如何追加TCP头部报文 修改报文后的注意虚拟机里通过虚拟网卡的报文checksum异常cksum计算优先级关于wireshark抓到数据显示checksum offload错误的问题cksum计算错误问题解决方案 总结

前言

最近开始搞windows网络驱动,需要修改TCP头部报文,遇到了一些问题,主要是追加options以及checksum校验和的问题.现在网上类似的资料不多,需要啃官方文档.如果你也在做类似的事,遇到类似的问题,希望可以帮到你节省时间.干货比较多,请耐心阅读.

目的

需要对TCP报文的头部信息进行修改

主要问题 TCP报文中的options数据的增加;增加后对TCP层和IP层报文长度的修改;对修改后的报文计算checksum报文发出去后发现checksum不对,用wireshark/tcpdump抓包后checksum offload 步骤 一. WFP过滤TCP报文

如何使用WFP就不多说了,前辈们都写的很好,可以参考 这里 另外这里首先需要知道数据的封包流程,可以参考下图,结合WFP的过滤层理解起来比较容易.比如在进入WFP的IP层后用户数据就已经加上了IP首部信息了. 在这里插入图片描述

WFP过滤层

这里可以参考雨中风华的博客一和二 也可以看微软官方文档

client: bind: FWPM_LAYER_ALE_BIND_REDIRECT_V4 这个支持win7以上系统,(不管有没有显式调用bind函数,绑定操作都会发生) bind: FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4 connect: FWPM_LAYER_ALE_CONNECT_REDIRECT_V4 , win7以上系统 connect: FWPM_LAYER_ALE_AUTH_CONNECT_V4 接着发送SYN数据包, SYN: FWPM_LAYER_OUTBOUND_TRANSPORT_V4 , SYN进入到传输层 SYN: FWPM_LAYER_OUTBOUND_IPPACKET_V4, SYN进入到IP层 接收到 SYN_ACK数据包, SYN-ACK: FWPM_LAYER_INBOUND_IPPACKET_V4, 首先进入IP层 SYN-ACK: FWPM_LAYER_INBOUND_TRANSPORT_V4 ,进入到传输层 FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4,到达ALE层,内核建立起连接,同时回复ACK包给服务端。 ACK: FWPM_LAYER_OUTBOUND_TRANSPORT_V4, 回复的ACK包进入传输层 ACK: FWPM_LAYER_OUTBOUND_IPPACKET_V4, 回复的包进入IP层

以上就是客户端在建立连接时候,WFP能挂载的所有挂载点和流程。 以下是服务端端:

server: bind: FWPM_LAYER_ALE_BIND_REDIRECT_V4 这个支持win7以上系统 bind: FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4 listen: FWPM_LAYER_ALE_AUTH_LISTEN_V4, listen函数认证 接下来就是accept开始接收客户端的请求,首先接收到的是SYN数据包, SYN: FWPM_LAYER_INBOUND_IPPACKET_V4, SYN包首先进入IP层 SYN: FWPM_LAYER_INBOUND_TRANSPORT_V4 , SYN包进入传输层 SYN: FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, SYN进入ALE层,确认建立连接,同时给客户端回复SYN-ACK数据包。 SYN-ACK: FWPM_LAYER_OUTBOUND_TRANSPORT_V4,回复的SYN-ACK数据包进入传输层 SYN-ACK: FWPM_LAYER_OUTBOUND_IPPACKET_V4, 回复的SYN-ACK数据包进入IP层 然后就开始接收客户端发来的最后一个ACK数据包, ACK: FWPM_LAYER_INBOUND_IPPACKET_V4, ACK包首先进入IP层 ACK: FWPM_LAYER_INBOUND_TRANSPORT_V4 , ACK进入传输层 FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4, ACK进入ALE层,这个时候就已经建立起了连接, accept函数返回,接收到了新的客户端连接的socket。

以上是服务端和客户端建立三次握手连接的流程。 当客户端连接服务端一个不在侦听的端口的情况下:下边是服务端的流程 SYN: FWPM_LAYER_INBOUND_IPPACKET_V, 进入IP层 SYN: FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD, 进入传输层,但是这个是时候,是进入WFP传输层的丢弃过滤点 , 同时给客户端回复RST数据包。 RST: FWPM_LAYER_OUTBOUND_TRANSPORT_V4, RST: FWPM_LAYER_OUTBOUND_IPPACKET_V4 接下来就是client和server端的数据传输: send(发送数据包): data:FWPM_LAYER_STREAM_V4, 发送数据到 Stream DATA层 TCP: FWPM_LAYER_OUTBOUND_TRANSPORT_V4, 到达传输层 IP: FWPM_LAYER_OUTBOUND_IPPACKET_V4, 达到IP层。 recv(接收数据包): 把上边的过程反过来。 服务端还要处理一种情况,就是当最初的连接授权发生变化的时候, 数据包还会进入到 FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, 认证正确 FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD, 没通过认证。

至于这个连接授权发生变化的情况,请看如下链接,这里就不再继续, https://msdn.microsoft.com/en-us/library/windows/desktop/bb613462(v=vs.85).aspx

同样,UDP的WFP流程请看如下链接,这里也不再继续。 https://msdn.microsoft.com/en-us/library/bb451831(v=vs.85).aspx

二. 追加OPTIONS数据 TCP/IP数据报文格式

准备工作都已完成,现在可以获取到TCP报文了,那么接下来我们看看TCP报文的格式,方便稍后进行修改和追加包括删除.网上这方面的资料比较多,但是想要了解清楚的话我们需要了解TCP首部的报文格式,可以看下图,也可以用wireshark抓包看真实数据: 首先看IP报头: 在这里插入图片描述 抓包对照着看会更清晰

在这里插入图片描述 注意: 这里的Header Length是20字节,这是ip报头长度.还有一个Total Length长度是72字节在这里插入图片描述再来看一下TCP报头在这里插入图片描述 注意 : 这里的Header Length是52字节 在这里插入图片描述 现在数据格式大家都清楚了,可以看到头部都是固定的20字节,加上options选项(可变).那么下面我们来看看怎么去修改增加删除.因为修改的话比较简单,这里主要讲一下如何追加tcp中的options,因为增加数据后长度会变,另外需要重新计算checksum.

如何追加TCP头部报文

要对TCP报头数据操作首先要理解数据流是怎么存储在NET_BUFFER中的.这个可以参阅微软官方文档,NET_BUFFER另外要重点看下下面的图: NET_BUFFER结构如下:

typedef struct _NET_BUFFER { union { struct { NET_BUFFER *Next; MDL *CurrentMdl; ULONG CurrentMdlOffset; union { ULONG DataLength; SIZE_T stDataLength; }; MDL *MdlChain; ULONG DataOffset; }; SLIST_HEADER Link; NET_BUFFER_HEADER NetBufferHeader; }; USHORT ChecksumBias; USHORT Reserved; NDIS_HANDLE NdisPoolHandle; PVOID NdisReserved[2]; PVOID ProtocolReserved[6]; PVOID MiniportReserved[4]; PHYSICAL_ADDRESS DataPhysicalAddress; union { NET_BUFFER_SHARED_MEMORY *SharedMemoryInfo; SCATTER_GATHER_LIST *ScatterGatherList; }; } NET_BUFFER, *PNET_BUFFER;

其中DataLength是报文长度,想要追加的话肯定要修改这个长度,但是直接修改这个数据会导致蓝屏,因为这块内存数据不是直接修改的,如果修改不了,那么在options中增加的数据将毫无意义.那么怎么修改呢?我们还需要连接一下NET_BUFFER中的回退和前进操作: 在这里插入图片描述

NDIS 提供后退和前进功能来操作NET_BUFFER结构。撤退操作使当前驱动程序可以使用更多已用数据空间。提前操作释放使用的数据空间。 在发送操作期间或驱动程序将接收到的数据返回给底层驱动程序时,需要进行撤消操作。例如,在发送操作期间,驱动程序可以调用NdisRetreatNetBufferDataStart函数为头数据腾出空间。 当发送操作完成或驱动程序从底层驱动程序接收数据时,需要高级操作。例如,在接收操作期间,驱动程序可以调用NdisAdvanceNetBufferDataStart函数来跳过较低级别驱动程序使用的标头数据。在这种情况下,头数据保留在缓冲区中未使用的数据空间中。

这是官方说法,那么讲的是什么意思呢?我的理解是这样的:Total空间是固定的,想要在used Data space中增加数据,只能缩小不用的数据空间,不能直接在使用空间的最后增加数据.那么想要缩小未使用的空间,就需要用到后退操作即NdisRetreatNetBufferDataStart.

空间释放出来之后改怎么去增加数据呢? 如果你是在TCP层FWPM_LAYER_INBOUND_TRANSPORT_V4 获取的包,那么此时数据内容是这样的

在这里插入图片描述

想要在TCP首部末尾插入options,首先要将数据空间扩大,比如要增加4字节. 那么我们想: 在这里插入图片描述

但是释放空间后是这样的 在这里插入图片描述 所以我们需要把原部首前移4字节,然后再增加最后的数据即可.

修改报文后的注意

注意事项我在前文已经给出提示: 1.有2个地方的长度需要修改

IP首部中的Total LengthTCP首部中的Header Length

2.checksum需要重新计算 cksum的计算目前大部分都通过网卡计算,因为这样的话会节省cpu的资源,所以这里你不处理也没关系.但是如果你的电脑被其他软件修改过配置,可能会导致cksum在TCP/IP中计算,所以这里还是计算一下确保没问题. 那么如何计算,网上有很多通用方法,其实原理也很简单,注意计算前先把原先的cksum置为0.

虚拟机里通过虚拟网卡的报文checksum异常

通过wireshark抓包的时候看到数据其实已经修改了,但是cksum异常 在这里插入图片描述 wireshark给出提示,cksum应该是0x960b,但是这里却是0x5a32.其实我计算出来的也是0x960b,但是为什么这里的cksum却不对?

cksum计算优先级

想解决上面的问题,我们需要了解cksum计算的优先级. 我们说了,cksum很多都是在网卡计算的,而wireshark是在数据到达网卡前抓到的数据,因此cksum肯定不对,但是报文出去的时候经过网卡计算正确,到达另一端的时候你可以试试抓包看看cksum是正确的. 但是对于有的电脑可能软件对网卡进行设置了,不让网卡计算或者网卡根本不支持计算,那么这样的话出去的报文cksum肯定不对. 下面我们来确认是否是网卡计算cksum的几种方式: 1.查看网卡属性

在这里插入图片描述 在这里插入图片描述 Rx和Tx都开,说明在网卡计算. 可以把开关关闭. 2.看注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters 其中有没有DisableTaskOffload参数,没有的话默认是0.即由网卡计算.设置为1表示不卸载到网卡.

关于wireshark抓到数据显示checksum offload错误的问题

可能是因为vmware虚拟机的虚拟网卡的问题,导致计算有问题,我在另一端抓包cksum总是不对. 所以对于我们修改过的数据,可以在代码中设置,针对这一条流不卸载到网卡.

cksum计算错误问题解决方案

因为需要解决虚拟机被我们修改后出来的报文cksum异常问题 1.直接修改网卡属性,设置校验和的开关关闭即可,这个开关可以在注册表中设置,感兴趣的可以去官网看看,但是不同操作系统位置不通.另外修改后重启网卡才生效.此方案可通过代码自动化,但是影响范围广,整个电脑. 2.修改注册表的DisableTaskOffload字段,修改后需要重启电脑,此方案也可自动化,但是影响范围广,整个电脑. 3.针对我们修改的数据,仅设置此条数据不卸载到网卡.此方案目前来说最优.那么如何实现? 大家先看看这个: NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO的结构

typedef struct _NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO { union { struct { ULONG IsIPv4 : 1; ULONG IsIPv6 : 1; ULONG TcpChecksum : 1; ULONG UdpChecksum : 1; ULONG IpHeaderChecksum : 1; ULONG Reserved : 11; ULONG TcpHeaderOffset : 10; } Transmit; struct { ULONG TcpChecksumFailed : 1; ULONG UdpChecksumFailed : 1; ULONG IpChecksumFailed : 1; ULONG TcpChecksumSucceeded : 1; ULONG UdpChecksumSucceeded : 1; ULONG IpChecksumSucceeded : 1; ULONG Loopback : 1; ULONG TcpChecksumValueInvalid : 1; ULONG IpChecksumValueInvalid : 1; } Receive; PVOID Value; }; } NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO, *PNDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO;

Transmit 包含以下成员的结构: Transmit.IsIPv4 由 TCP/IP 传输设置以指示发送数据包包含 IPv4 地址。 Transmit.IsIPv6 由 TCP/IP 传输设置以指示发送数据包包含 IPv6 地址。 Transmit.TcpChecksum 由 TCP/IP 传输设置以指示 NIC 应计算数据包的 TCP 校验和。 Transmit.UdpChecksum 由 TCP/IP 传输设置以指示 NIC 应计算数据包的 UDP 校验和。 Transmit.IpHeaderChecksum 由 TCP/IP 传输设置以指示 NIC 应计算数据包中第一个 IP 标头的 IP 校验和。如果数据包同时包含隧道 IP 标头和传输 IP 标头,则 NIC 应计算两个 IP 标头的校验和。 Transmit.Reserved 为 NDIS 保留。 Transmit.TcpHeaderOffset TCP 数据包的 TCP 标头距数据包开头的偏移量(以字节为单位)。微型端口驱动程序可以使用TcpHeaderOffset来确定 TCP 标头的位置,这样它们就不需要解析 MAC 和 IP 标头。 Value 一个PVOID版本的校验和信息。微型端口驱动程序可以使用此成员访问原始信息而不是特定字段

NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO详情查看官方文档 设置数据流中的TCPChecksum为0,即表示此条流不卸载到网卡计算cksum.

总结

这篇内容较多,文章写的比较急,很多内容没有完善,很多细节没有讲清楚,如果看的人多后面会抽空完善,或者拆成几个部分详细记录,方便后来的人. 这方面的知识和技术很多,大家一起加油,有什么问题欢迎留言和私信.



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3