zxm1983123
驱动牛犊
驱动牛犊
  • 注册日期2005-10-20
  • 最后登录2008-01-22
  • 粉丝1
  • 关注0
  • 积分475分
  • 威望49点
  • 贡献值0点
  • 好评度47点
  • 原创分0分
  • 专家分0分
阅读:7366回复:22

初学TDI的一点经验,与大家分享一下

楼主#
更多 发布于:2007-01-07 19:58
  前一段时间开始学习TDI驱动,参考的资料是楚狂人的那本经典的<<Windows_TDI过滤驱动开发>>以及开源的tdifw防火墙.对于我们这些从来没有接触过驱动开发的人来说,虽然楚狂人的书写的很详细,很有指导性,但是由于自身不具备很多基本的概念,比如IRP,IoCompletionRoution等.所以看的仍然是云里雾里.看书看不明白,想回过头来看代码,但是tdifw防火墙的代码对于一个初学者来说,还是很难看懂.于是想通过自己写代码来学习TDI.
    因为我手中有一本朱雁冰写的<<windows防火墙与网络封包截获技术>>,里面有一个tdi最简单的例子,FilterTdiDriver,这个例子的功能就是创建一个Device,然后attach到TCP设备上面去,然后用DbgPrint打印出每个IRP请求.我的想法是在这段代码上面增加两个最简单的功能.一是显示每个IRP请求是由哪个进程发出的.二是想当tcp的socket向服务器端口发起connect请求时,会绑定到本地的一个tcp端口,想通过IRP来获得这个端口.两个很简单的功能,但是花了两个星期才搞明白.
    得到进程信息很简单,只要在IRP请求的处理函数中调用PsGetCurrentProcess()函数, 该函数返回的是一个EPROCESS块结构,在ddk文档中没有找到这个块结构的描述.要得到这个块的结构,xp下可以用windbg中的dt !_EPROCESS命令(2000下好像是另外一个命令).这个结构中偏移值为0x174的位置就是进程名字(2000下的偏移值不一样).
    要得到本地端口,先要看看socket API与相应的IRP的关系.我开始以为调用socket函数创建一个tcp socket的时候就确定了本地端口的,后来发现其实不是.socket API与相应的IRP的关系如下.
Client端调用socket()创建一个socket时候没有任何IRP包;
    调用connect()时,产生下面十一个IRP包,左侧是主功能号,右侧是次功能号.
IRP_MJ_CREATE
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_QUERY_INFORMATION
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_SET_EVENT_HANDLER
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_SET_EVENT_HANDLER
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_SET_EVENT_HANDLER
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_SET_EVENT_HANDLER
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_SET_EVENT_HANDLER
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_QUERY_INFORMATION
IRP_MJ_CREATE
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_ASSOCIATE_ADDRESS
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_CONNECT
    调用Send()时,有一个IRP包:
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_SEND
    调用Close()时,有一个IRP包生成:
IRP_MJ_INTERNAL_DEVICE_CONTROL     TDI_DISCONNECT
    Connect()时,产生一个IRP请求包,主功能号IRP_MJ_CREATE(主功能号为IRP_MJ_CREATE的IRP包不一定就是创建本地地址的IRP请求包,需要通过IRP中的EA数据来确定,楚狂人的书中说的很清楚),这个IRP请求传给TCP设备,TCP设备处理完这个IRP请求后(也许是TCP device自己处理,也许是传给更下面的设备处理,我不知道),socket的端口号就确定了.注意,因为我们的device是绑定在tcp device之上的,因此我们得到请求创建本地地址的IRP包的时候, ,这个端口号还没有确定,需要我们把这个IRP传给TCP device,等它处理完毕后,这个端口号就确定了.获知这个端口的方法是自己创建一个用于查询地址信息的IRP包,发给下层的TCP device.那么什么时候发送这个用于查询的IRP包呢?显然要等到TCP device处理完转发的功能号为IRP_MJ_CREATE的IRP包后才能发送.怎么知道TCP device什么时候完成IRP请求?答案是通过IoCompletion Routine.通过给一个IRP指定一个IoCompletion Routine函数(这个函数是自己定义的),当这个IRP请求完成的时候,系统就会调用这个IoCompletion Routine函数. 在这个IoCompletionRoutine函数中,我们就可以发出我们的查询IRP了.当然,也要给查询IRP指定一个IoCompletionRoutine函数.以便得到想要查询的地址信息.
完成上面两个功能的代码都已经测试通过了,感兴趣的朋友可以找我要.邮箱是zxm1983123@yahoo.com.cn代码中还有问题,希望可以一起讨论.

最新喜欢:

LeopardLeopar...
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
沙发#
发布于:2007-01-07 20:05
鼓励这样做.

你方便,可以直接把代码作为附件帖上来,这样也方便后来者,自己也不用一个一个去发
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
zxm1983123
驱动牛犊
驱动牛犊
  • 注册日期2005-10-20
  • 最后登录2008-01-22
  • 粉丝1
  • 关注0
  • 积分475分
  • 威望49点
  • 贡献值0点
  • 好评度47点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-01-07 20:48
代码贴出来了
代码测试过了,可以运行,但是有一个问题我没有搞明白,每次向下一层发送一个查询IRP报文的时候,要从NonPagedPool中申请一段内存,这个IRP处理完成后,在它的完成函数,没有释放掉这段内存(释放会蓝屏),这样理应会造成内存泄漏.但是感觉好像对系统性能没有造成什么大影响.不知道是什么原因.
附件名称/大小 下载次数 最后更新
FilterTdiDriver2.rar (62KB)  401 2007-01-07 20:48
aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
地板#
发布于:2007-01-08 09:14
太感谢你了
我最近也在研究TDI。
看tdifw1.4.4实在看不下去。
我现在研究的是pcausa的那个passthru的tdi例子

还是有一些体会的。
多多加油
周维彬
aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
地下室#
发布于:2007-01-08 11:15
正在试验你的这个FilterTdiDriver.rar
不过最好在注册表里改改 把路径改在sysytem32里面的driver。
而不是 sysytem32里面,

对了问大家一个问题
为什么FilterTdiDriver.sys和passthru.sys一样 ,
都是一启动就老是打印irp_mj_device_control这个irp呢。
我有没有打开任何访问网络的程序 而且也没有任何应用程序调用这个sys服务。
根据以前的经验应该是有应用程序利用ioctl来调用驱动才有这个IRP的啊???
很奇怪
周维彬
aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
5楼#
发布于:2007-01-08 11:27
还有啊 这个驱动只要一net stop 就死机了
softice 跳出page fault
周维彬
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2007-01-23 22:50
net stop当然不行了,还有irp在处理中
aben1223
驱动小牛
驱动小牛
  • 注册日期2004-11-29
  • 最后登录2007-06-01
  • 粉丝1
  • 关注0
  • 积分1000分
  • 威望201点
  • 贡献值0点
  • 好评度192点
  • 原创分2分
  • 专家分0分
7楼#
发布于:2007-01-24 09:21
那么该怎么办?
我的想法是先断网,然后unload,再启动网络。
但是不知道该用什么函数,怎么做,
周维彬
driver12345
驱动牛犊
驱动牛犊
  • 注册日期2005-11-15
  • 最后登录2007-10-28
  • 粉丝0
  • 关注0
  • 积分814分
  • 威望84点
  • 贡献值0点
  • 好评度82点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2007-01-30 17:41
你好zxm1983123
 我看了你的代码
我现在要得到本地的ip和端口要整样处理呢?
看了一些例子但得到的地址不对
我用TdiBuildQueryInformation  发送irp但返回的信息里AddressType == TDI_ADDRESS_TYPE_IP 是0
所以导致查询不出来
你的代码是在哪里查询到本地地址和端口的呢?
我是在过滤connect里面去查询的
不知道大家有没有好办法
driver12345
驱动牛犊
驱动牛犊
  • 注册日期2005-11-15
  • 最后登录2007-10-28
  • 粉丝0
  • 关注0
  • 积分814分
  • 威望84点
  • 贡献值0点
  • 好评度82点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2007-02-05 10:08
没有人回答问题!
我现在想过滤TDICONNECT这个函数
我在这里想得到本地的地址和端口
代码如下:
pIrp = IoAllocateIrp( pDeviceObject->StackSize, FALSE );
if( !pIrp )
{
      return( STATUS_INSUFFICIENT_RESOURCES );
}
pMdl = KSUTIL_AllocateAndProbeMdl(
            pInfoBuffer,      // Virtual address for MDL construction
            *pInfoBufferSize,  // size of the buffer
            FALSE,
            FALSE,
            NULL
            );
if( !pMdl )
{
      IoFreeIrp( pIrp );
      return( STATUS_INSUFFICIENT_RESOURCES );
}

TdiBuildQueryInformation(
      pIrp,
      pDeviceObject,
      pFileObject,
      tdi_create_addrobj_complete,
      //KSUTIL_I_SimpleTdiRequestComplete,  // Completion routine
      //NULL,                            // Completion context
      pInfoBuffer,
      TDI_QUERY_ADDRESS_INFO,
      pMdl
      );
Status = KSUTIL_MakeSimpleTdiRequest1(
               pDeviceObject,
               pIrp
               );
KSUTIL_UnlockAndFreeMdl(pMdl);
*pInfoBufferSize = pIrp->IoStatus.Information;
IoFreeIrp( pIrp );
return( Status );
}
Status = IoCallDriver( pDeviceObject, pIrp );

在对应的回调历程里得到的本地端口和IP不对
driver12345
驱动牛犊
驱动牛犊
  • 注册日期2005-11-15
  • 最后登录2007-10-28
  • 粉丝0
  • 关注0
  • 积分814分
  • 威望84点
  • 贡献值0点
  • 好评度82点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2007-02-06 18:30
整没有人回答呢?
我想得到通过网络邻居访问时候的本地端口
其他的是可以得到的
asmsys
驱动老牛
驱动老牛
  • 注册日期2002-03-29
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望17点
  • 贡献值0点
  • 好评度8点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2007-02-08 11:56
应该用TdiBuildInternalDeviceControlIrp而不是IoAllocateIrp。
driver12345
驱动牛犊
驱动牛犊
  • 注册日期2005-11-15
  • 最后登录2007-10-28
  • 粉丝0
  • 关注0
  • 积分814分
  • 威望84点
  • 贡献值0点
  • 好评度82点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2007-02-09 10:12
谢谢大家!
这个问题解决了!
是查询的时机有点不对
要等connect连接完成之后再去查
asmsys
驱动老牛
驱动老牛
  • 注册日期2002-03-29
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望17点
  • 贡献值0点
  • 好评度8点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2007-02-11 09:41
引用第12楼driver123452007-02-09 10:12发表的“”:
谢谢大家!
这个问题解决了!
是查询的时机有点不对
要等connect连接完成之后再去查

在create后,fileobj一旦建立,本地的端口就可以查到了,这是肯定的,但此时没有远端口。
fancylf
驱动牛犊
驱动牛犊
  • 注册日期2007-07-29
  • 最后登录2016-06-21
  • 粉丝1
  • 关注0
  • 积分61分
  • 威望501点
  • 贡献值0点
  • 好评度23点
  • 原创分0分
  • 专家分0分
  • 社区居民
14楼#
发布于:2008-05-08 22:14
lz 大哥,太谢谢你的code了,这几天看tdi_fw,头的大了啊!
djjnet
驱动牛犊
驱动牛犊
  • 注册日期2005-12-15
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分234分
  • 威望117点
  • 贡献值0点
  • 好评度55点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2008-05-13 15:01
非常感谢楼主的共享。我现在也在入门的极度郁闷中。
还有个问题请教一下各位。
这个TDI Filter Driver不用inf来安装么,就用那个注册表文件导入一下,然后将sys拷贝到system32\drivers目录就可以了吗?这样搞了,是不是还要重启一下电脑才能生效?
难道不是所有的驱动都需要用inf来安装的吗?谢谢
djjnet
驱动牛犊
驱动牛犊
  • 注册日期2005-12-15
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分234分
  • 威望117点
  • 贡献值0点
  • 好评度55点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2008-05-13 15:16
另一个问题,呵呵。
如果有多个TDI Filter Driver都往TCP上绑定,那怎么办?
我是怕在安装自己开发的TDI Filter Driver时,已经有别的杀毒或者网络监控软件使用了和这里TDI Filter Driver一样的方法,那我们自己的再装,会是一种什么情况。或者先装我们自己的,然后又有别的网络监控软件(也使用了TDI Filter Driver)来安装,会怎么样。
ay19880703
驱动牛犊
驱动牛犊
  • 注册日期2008-05-24
  • 最后登录2010-03-25
  • 粉丝0
  • 关注0
  • 积分18分
  • 威望120点
  • 贡献值1点
  • 好评度1点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2008-07-29 18:50
回16楼的  你可以自己试试绑定2个驱动设备看看啊  
不会是给每个绑定的驱动设备都发IRP吧,这样的话就不能起到过滤效果了
snakebite2008
驱动牛犊
驱动牛犊
  • 注册日期2005-08-07
  • 最后登录2009-09-11
  • 粉丝1
  • 关注1
  • 积分2分
  • 威望12点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2008-08-01 23:14
收藏一下
jl2004
驱动小牛
驱动小牛
  • 注册日期2007-04-10
  • 最后登录2011-02-22
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望276点
  • 贡献值0点
  • 好评度129点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2008-10-06 18:10
请问TDI接收到的数据包括TCP/IP包的报文Head吗?
向前,向前,向前....
上一页
游客

返回顶部