阅读:7366回复:22
初学TDI的一点经验,与大家分享一下
前一段时间开始学习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代码中还有问题,希望可以一起讨论. |
|
最新喜欢:Leopar... |
沙发#
发布于:2007-01-07 20:05
鼓励这样做.
你方便,可以直接把代码作为附件帖上来,这样也方便后来者,自己也不用一个一个去发 |
|
|
板凳#
发布于:2007-01-07 20:48
代码贴出来了
代码测试过了,可以运行,但是有一个问题我没有搞明白,每次向下一层发送一个查询IRP报文的时候,要从NonPagedPool中申请一段内存,这个IRP处理完成后,在它的完成函数,没有释放掉这段内存(释放会蓝屏),这样理应会造成内存泄漏.但是感觉好像对系统性能没有造成什么大影响.不知道是什么原因. |
|
|
地板#
发布于:2007-01-08 09:14
太感谢你了
我最近也在研究TDI。 看tdifw1.4.4实在看不下去。 我现在研究的是pcausa的那个passthru的tdi例子 还是有一些体会的。 多多加油 |
|
|
地下室#
发布于:2007-01-08 11:15
正在试验你的这个FilterTdiDriver.rar
不过最好在注册表里改改 把路径改在sysytem32里面的driver。 而不是 sysytem32里面, 对了问大家一个问题 为什么FilterTdiDriver.sys和passthru.sys一样 , 都是一启动就老是打印irp_mj_device_control这个irp呢。 我有没有打开任何访问网络的程序 而且也没有任何应用程序调用这个sys服务。 根据以前的经验应该是有应用程序利用ioctl来调用驱动才有这个IRP的啊??? 很奇怪 |
|
|
5楼#
发布于:2007-01-08 11:27
还有啊 这个驱动只要一net stop 就死机了
softice 跳出page fault |
|
|
6楼#
发布于:2007-01-23 22:50
net stop当然不行了,还有irp在处理中
|
|
7楼#
发布于:2007-01-24 09:21
那么该怎么办?
我的想法是先断网,然后unload,再启动网络。 但是不知道该用什么函数,怎么做, |
|
|
8楼#
发布于:2007-01-30 17:41
你好zxm1983123
我看了你的代码 我现在要得到本地的ip和端口要整样处理呢? 看了一些例子但得到的地址不对 我用TdiBuildQueryInformation 发送irp但返回的信息里AddressType == TDI_ADDRESS_TYPE_IP 是0 所以导致查询不出来 你的代码是在哪里查询到本地地址和端口的呢? 我是在过滤connect里面去查询的 不知道大家有没有好办法 |
|
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不对 |
|
10楼#
发布于:2007-02-06 18:30
整没有人回答呢?
我想得到通过网络邻居访问时候的本地端口 其他的是可以得到的 |
|
11楼#
发布于:2007-02-08 11:56
应该用TdiBuildInternalDeviceControlIrp而不是IoAllocateIrp。
|
|
12楼#
发布于:2007-02-09 10:12
谢谢大家!
这个问题解决了! 是查询的时机有点不对 要等connect连接完成之后再去查 |
|
13楼#
发布于:2007-02-11 09:41
引用第12楼driver12345于2007-02-09 10:12发表的“”: 在create后,fileobj一旦建立,本地的端口就可以查到了,这是肯定的,但此时没有远端口。 |
|
14楼#
发布于:2008-05-08 22:14
lz 大哥,太谢谢你的code了,这几天看tdi_fw,头的大了啊!
|
|
15楼#
发布于:2008-05-13 15:01
非常感谢楼主的共享。我现在也在入门的极度郁闷中。
还有个问题请教一下各位。 这个TDI Filter Driver不用inf来安装么,就用那个注册表文件导入一下,然后将sys拷贝到system32\drivers目录就可以了吗?这样搞了,是不是还要重启一下电脑才能生效? 难道不是所有的驱动都需要用inf来安装的吗?谢谢 |
|
16楼#
发布于:2008-05-13 15:16
另一个问题,呵呵。
如果有多个TDI Filter Driver都往TCP上绑定,那怎么办? 我是怕在安装自己开发的TDI Filter Driver时,已经有别的杀毒或者网络监控软件使用了和这里TDI Filter Driver一样的方法,那我们自己的再装,会是一种什么情况。或者先装我们自己的,然后又有别的网络监控软件(也使用了TDI Filter Driver)来安装,会怎么样。 |
|
17楼#
发布于:2008-07-29 18:50
回16楼的 你可以自己试试绑定2个驱动设备看看啊
不会是给每个绑定的驱动设备都发IRP吧,这样的话就不能起到过滤效果了 |
|
18楼#
发布于:2008-08-01 23:14
收藏一下
|
|
19楼#
发布于:2008-10-06 18:10
请问TDI接收到的数据包括TCP/IP包的报文Head吗?
|
|
|
上一页
下一页