aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
阅读:3085回复:4

TDI心得总结

楼主#
更多 发布于:2007-04-16 14:06
  Tdi的文档很少,网上能找到的资料少得可怜。在DDK的文档上介绍得也是及其的模糊。唯一比较有用的参考文档就是楚狂人的那篇关于TDI的文档了,但也是满简单的入门介绍。其他的就只能多看代码进行理解了(看了很多以后,发现其实很多代码即使看不懂也能进行开发)。
    在这里我利用tdi_fw的程序,改造出一个tdi filter的整体过滤框架,就像IMD下的Passthru。可以在上面进行二次开发。我在其基础上进行数据包的过滤。
    下面是我进行Tdi研究的一些心得体会,供参考。

    1、Tdi可分为Tdi Filter、Tdi Client和Tdi Server。Tdi Server也就是TCPIP这些的SYS驱动。应该是没有人会自己去开发新的一套TCPIP的协议实现。Tdi Client这是一种自己来组建数据包然后依靠创建Irp进行数据发送和接收的客户驱动。当我们用这种方式进行数据包的收发时,SPI、WinpCap和Tdi Filter都是抓不到这种数据包的。能拦截到的只有万能的IMD。当时这三种不同的驱动再加上一个Tdi hook(其实就是NDIS Hook),搞得我头晕脑涨的,不知道该实现哪一个。
2、用Tdi Filter进行数据包的修改。如果是Remote IP、Remote PORT,或者是同样数据长度的数据修改,应该不是什么大问题。但是如果要改变发送数据的长度或者Local IP、Local Port。这就很麻烦很麻烦了。看网上的讨论,Tdi Filter不适用来修改数据包。我自己的体会也是这样。
    3、用Tdi Filter主要的用途可能是它能很好的掌握发送数据包和接收数据包的应用程序Pid。这只是指驱动程序层面下,应用程序层面上如SPI或者WinpCap应该也能很好的完成这个工作。我试过在IMD下进行PsGetCurrentProcessId的调用,也可以得到当前的进程信息,但是准确率可能只有90%。这一点其实很好理解,我们在驱动中调用PsGetCurrentProcessId函数时,得到的是当前进程的信息。由于IMD过于底层,当Irp传到这里的时候,进程早就随时间片切换了,也有可能是因为驱动中发送和接收的Pending问题,造成得到的进程Pid不准确。这一点在TDI上倒是没有错。
    4、还有一个Tdi Filter的net stop很容易蓝屏的问题,这一点我看确实是很难避免了,似乎这本身就是Tdi的阿喀琉斯之踝。我解决不了,网上关于这方面的讨论是根本不要是停止服务,等到系统关机重启的时候自动停止就行了。
    5、其实用Tdi Filter进行数据包的过滤也是一件很麻烦的事情,如果不是因为要得到正确的Pid的话,打死我都想不到用Tdi Filter进行数据包过滤的理由。
举过滤TCP作为例子进行说明吧。关于发送TCP数据包,这里面有包含很多的信息需要用全局列表ote_entry保存以便后面的操作查询,如TdiTransportAddress、TdiConnectionContext、TDI_ASSOCIATE_ADDRESS等。,我们应该把这些FILE_OBJECT和生成的地址对应起来。这样后续的事件(如发送和接收)发生的时候,我们才可以知道是什么地址哪个连接在进行发送接收。
而且Tdi下的发送和接收还有连接和断掉连接的方式特多, Connect有两种方式一种是直接的tdi_connect,一种是tdi_event_connect。同样的也要进行两种不同的Disconnect。TCP接收的话有tdi_receive、tdi_event_receive、tdi_event_chain_receive等。你不仅每种方式都要过滤到,还要时时更新当前的一个ote_entry全局列表,这个ote_entry全局列表包含所有当前TCP的连接信息。当新建一个连接时增加一个表项单元,断开一个连接时从列表中删除一个表项单元。发送和接收时更新表项的信息。
周维彬
aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
沙发#
发布于:2007-04-16 16:15
想请问一下
在几个event_receive当中的参数。
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
分别指什么啊,前两个以前做过miniport和imd大概知道,BytesTaken是干什么的
我试了几次 通常第一个和第二个是相等的,第三个就不等了。不知道是干什么的。
看tdi_fw,好像这个才是真正的接收字节数。感觉满奇怪的。
望牛人回答一下
周维彬
cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
板凳#
发布于:2007-04-17 10:16
BytesTaken 真正接收到的数据长度
BytesAvailable 可以接收的数据长度

WinpCap拦截不到tdi发送的数据??应该可以的,毕竟WinpCap是使用得imd的注册协议吧。
走走看看开源好 Solaris vs Linux
aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
地板#
发布于:2007-04-17 15:53
呵呵 自己想得太简单了 这个winpcap的还是参见cyliu的意见吧。
我一直以为应用层的抓不到tdi_client的数据
周维彬
aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
地下室#
发布于:2007-04-17 15:57
在tdi_fw里面有个问题 很不解
tdi_client_irp_complete 是什么东西啊
里面的这个函数
ULONG bytes = Irp->IoStatus.Information;
ote_conn->bytes_in += bytes;

我dpgprint过这个bytes ,大小很多都超过1514字节,很有有3000多字节的。
这是怎么回事???

我看了一下tdi_client_irp_complete是
tdi_event_receive里面注册的完成函数。
但是为什么这个接收的数据大于一个包长呢。
周维彬
游客

返回顶部