基于WFP的windows驱动对TCP数据的抓取及修改

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

前言

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

目的

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

主要问题

  1. TCP报文中的options数据的增加;
  2. 增加后对TCP层和IP层报文长度的修改;
  3. 对修改后的报文计算checksum
  4. 报文发出去后发现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 Length
  • TCP首部中的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.

总结

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

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

  1. ajax获取网页新闻,基于Ajax的新闻网页动态数据的抓取方法及系统

    主权项: 1.基于Ajax的新闻网页动态数据的抓取方法,其特征是,包括如下步骤:步骤(101):建立新闻网页爬取内容数据库,设置新闻网页爬取内容数据库的编码方式:获得待抓取新闻网页的新闻列表页面的UR ...

  2. 谷歌X最新开源任务驱动的类级别机器人抓取CaTGrasp!

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者丨bowen 来源丨计算机视觉life 大家好,今天给大家介绍谷歌X最新开源任务驱动的类级别机器人 ...

  3. 关于淘宝网评论数据的抓取

    关于淘宝网评论数据的抓取 第一步 如何获取商品基本信息 我们打开多张淘宝的商品网页,分析网页的URL组成,寻找其中的规律,下面给出一个例子 我们发现了一个规律就是http://item.taobao. ...

  4. 利用新浪API实现数据的抓取\微博数据爬取\微博爬虫 1

    PS:(本人长期出售超大量微博数据.旅游网站评论数据,并提供各种指定数据爬取服务,Message to YuboonaZhang@Yahoo.com.由于微博接口更新后限制增大,这个代码已经不能用来爬 ...

  5. mitmproxy + Appium实现快手数据的抓取

    mitmproxy + Appium实现快手数据的抓取 mitmproxy 1,mitmproxy介绍 mitmproxy是一个支持Http和Https的抓包程序,类似于fiddler,Charles ...

  6. C# 开发的网络数据包抓取的的实现

    利用C# 开发的网络数据包抓取的的实现 利用套接字Socket  socket=new Socket(AddressFamily.InterNetwork, SocketType.Raw, Proto ...

  7. PythonStock(37)股票系统:Python股票系统发布V2.0版本,改个名字吧,叫Python全栈股票系统2.0,可以实现数据的抓取(akshare),统计分析,数据报表展示。

    目录 前言 1,关于Python全栈股票系统V2.0 2,在CSDN上居然有人给代码打包收费下载!! 2,更新docker镜像 3,总结 前言 使用Python开发一个web股票项目. [github ...

  8. 利用新浪API实现数据的抓取\微博数据爬取\微博爬虫

    PS:(本人长期出售超大量微博数据.旅游网站评论数据,并提供各种指定数据爬取服务,Message to YuboonaZhang@Yahoo.com.由于微博接口更新后限制增大,这个代码已经不能用来爬 ...

  9. 用selenium实现对微博搜索数据的抓取

     http://computational-communication.com/post/bian-cheng-gong-ju/2014-06-25-searching-weibo-with-se ...

最新文章

  1. java epoll select_Java 非阻塞 IO 和异步 IO
  2. Java黑皮书课后题第6章:**6.34(打印日历)编程练习题3.21使用Zeller一致性原理来计算某天是星期几,使用Zeller的算法简化程序清单6-12以获得每月开始的第一天是星期几
  3. android service中显示一个dialog
  4. NAT(网络地址转换)技术与代理服务器原理
  5. Pull Request的正确打开方式(如何在GitHub上贡献开源项目)
  6. Snabbdom(虚拟dom-8-removeVnodes函数)
  7. 关于如何修改CSDN中的字体大小和颜色
  8. Ubuntu18.04报错:make[1]: *** No rule to make target armv4-mont.o, needed by build-msm8916/lk. Stop.
  9. NYOJ-915 +-字符串(贪心)
  10. Spring mvc文件下载
  11. hibernate中实体类对象的四种状态
  12. Navicat安装与破解
  13. 品达物流项目重点技术 微服务高性能实战
  14. 赫兹的单位换算_hz单位换算
  15. 经典成功创业-36法则
  16. c语言中fabs是什么意思,c语言fabs是什么意思_后端开发
  17. markdown语法补充和todo制作
  18. linux网络编程之shutdown() 与 close()函数详解
  19. webSpider----request
  20. CV 经典主干网络 (Backbone) 系列: 开篇

热门文章

  1. 曝光!中国女性的私密数据分析…
  2. 呼叫中心系统和外呼机器人的高效组合
  3. 用PowerPoint巧做特效字幕(转)
  4. leetcode回溯算法
  5. Android 辅助服务实战-游戏点击器
  6. SIM7600透传模式
  7. matlab 锁相环仿真,MATLAB锁相环仿真程序求解
  8. html怎么把图片做成抖动效果,js实现鼠标触发图片抖动效果的方法
  9. mvdbos php spider,yemtao
  10. 华为运营商级路由器配置示例 | 公网IPv6 over SRv6 TE Policy