zgc7622
驱动小牛
驱动小牛
  • 注册日期2003-02-24
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分136分
  • 威望15点
  • 贡献值0点
  • 好评度13点
  • 原创分0分
  • 专家分0分
阅读:1917回复:5

转贴“一个简单的tcp filter的例子”

楼主#
更多 发布于:2003-02-28 09:37
发信人: huyuguang (吃饭), 信区: SysInternals ;32mWWW-POSTm
标  题: 一个简单的tcp filter的例子
发信站: 武汉白云黄鹤站 (Thu Jul 13 09:22:44 2000) , 站内信件
 这两天版面日渐萧条,我只好硬着头皮把我自己的一个尚在开发,非常不成熟
的东西拿出来了。
 前面我曾经就网络加密这个议题讨论过,那个时候我提出的方法是imd,
9x下就是利用hook_device_service,用这些方法的一个好处就是,接收数据
比较低层,直接得到的就是mac数据,而且可以知道是哪块网卡上来的,而且,
可以加密各种数据帧,ipx,ip什么的都不在话下。因为我所遇到的加密环境和要求,
几乎都是要求对tcp加密,在这种情况下,做在imd上的话,显然会降低ipx或者icmp
之类的非加密数据包的效率。因此以前我就考虑在tcp 上做一个filter,直接加密tcp
的数据。
 正好在mark的站点上新出来一个小工具,叫做tdimon,工具很好,可以看到各个进程
的通讯状态。可惜的是1.没有源代码,2.free版本不能得到数据内容。有这两点限制,
这个
工具就只能当作玩具。正好那个时候我比较闲,就花了点时间做了一个类似的工具。
关于FILTER,art baker的书里说得很详细,我做的时候基本上也就是根据这本书上来的

做tcp的filter,和做别的设备的filter,没什么区别,但是不同是由于不知道tcp是如何

和别的设备(tdi clinet)通讯的,所以必须仔细看tdi的规范。
 我先描述一下2000/nt下的tcp/ip协议的一些情况。2000/nt下,ip,tcp,udp是在
一个驱动程序里实现的,叫做tcp.sys,这个驱动程序创建了3个设备,就是ip,tcp,udp

 首先描述一下driverentry。首先当然是iocreatedevice,用file_device_unknown,
因为tcp设备就是用的这个参数。代码如下:
    RtlInitUnicodeString( &usDeviceName, FILTER_NAME );
    status = IoCreateDevice( DriverObject,
                            sizeof(DEVICE_EXTENSION),
                            &usDeviceName,
                            FILE_DEVICE_UNKNOWN,
                            0,
                            FALSE,
                            &pDevObj );
然后就调用iogetdeviceobjectpointer来得到tcp设备的指针。
代码如下:
    RtlInitUnicodeString( &usTargetName, TARGET_NAME );
    status = IoGetDeviceObjectPointer( &usTargetName,
                                      FILE_ALL_ACCESS,
                                      &pTargetFileObj,
                                      &pTargetDevObj );
注意TARGET_NAME是大小写区分的,我是用#define TARGET_NAME L\"\\\\Device\\\\Tcp\",
不能写成#define TARGET_NAME L\"\\\\Device\\\\tcp\"。
然后我们就开始调用IoAttachDeviceToDevieStatck插入到tcp设备。
调用完成后,我们要让我们的设备表现的和tcp一样,于是把它的所有
特性都从tcpobj复制(pdevobj->xxx=ptcpobj->xxx)。
再扫描他tcpdriverobject的majorfunction,我们的driver必须都
支持。最后设置driverunload,因为为了方便调试,我们必须写一个
unload。



发信人: huyuguang (吃饭), 信区: SysInternals ;32mWWW-POSTm
标  题: 一个简单的tcp filter的例子(2)
发信站: 武汉白云黄鹤站 (Thu Jul 13 09:24:10 2000) , 站内信件
前面已经讲过driverentry了,经过driverentry,所有的原来应该发送到
tcp设备的irp现在都发送到我们的设备的处理函数了,如果什么事情都不做,
那么可以简单的调用iocalldriver把这个irp发到tcp设备去让它处理。
当然,我们是要做些事情的,于是代码如下:
    UCHAR MajorFunction,MinorFunction;
    PDEVICE_EXTENSION  pDevExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExt
ension;
    PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( Irp );
    MajorFunction = pIrpStack->MajorFunction;
    MinorFunction = pIrpStack->MinorFunction;
    //DBGPRINT( ...)
    ParseIrp(Irp);
    IoCopyCurrentIrpStackLocationToNext( Irp );
    IoSetCompletionRoutine( Irp,
                            CompletionRoutine,
                            NULL,   // context
                            TRUE,   // InvokeOnSuccess
                            TRUE,   // InvokeOnError
                            TRUE ); // InvokeOnCancel
    return IoCallDriver( pDevExt->TargetDevObj, Irp);
代码很简单,除了parseirp之外,其他都是例行公事。对于tcp设备的前期处理
就在这个函数里。后期处理的函数可以放在completionroution里。
好了,我们已经得到了发向tcp设备的所有irp了,这个时候我们的任务就是要了解
tcp设备到底是如何工作的.


发信人: huyuguang (吃饭), 信区: SysInternals ;32mWWW-POSTm
标  题: 一个简单的tcp filter的例子(3)
发信站: 武汉白云黄鹤站 (Thu Jul 13 15:49:13 2000) , 站内信件
我们的任务是要得到本机发送出去的tcp数据和接受的tcp数据。当然前提是发送数据
通过tcp设备,如果某些应用程序用packet.sys之类的协议driver,直接发送tcp数据,

这种情况下数据不经过tcp设备,filter也就无从得到了。
为了了解如何从发向tcp设备的irp中得到信息,首先我先描述一下tdi client是如何
与tcp通讯以及tdi client一般是如何工作的。
driverstdio里面有好几个例子都是关于tdi client的,但是这些例子都是基于它自己
的类库的,不过这些例子功能都很强大,其中一个usb+web的温度计的创意简直让我目瞪
口呆。
因为我也做过pci温度计的driver,但是我从来就没有想到还可以加上一个web server在
里面。
因为driverstdio里的例子太复杂,我在这里简单描述一下,给一个小例子。
因为发送过程较为简单,先描述发送。
首先调用pIrp = TdiBuildInternalDeviceControlIrp (
                     TDI_SEND_DATAGRAM,                              // sub
function
                     pDeviceObject,                                  // poin
ter to device object
                     pTransportObject,                               // poin
ter to udp object
                     NULL,                                           // poin
ter to event
                     NULL );                                         // poin
ter to return buffer
分配一块irp,然后调用
  TdiBuildSendDatagram (
                           pIrp,                                     // poin
ter to irp
                           pDeviceObject,                            // poin
ter to device object
                           pTransportObject,                         // poin
ter to file object
                           NULL,                                     // comp
letion routine
                           NULL,                                     // comp
letion context
                           pMdl,                                     // poin
ter to data
                           dBufferSize,                              // size
 of data
                           pConnectInfo );                           // conn
ection information
不用我说也应该知道,数据是放在一个buf里面,调用这个函数之前,要先构件一个mdl
,把这个buf
放进去。
然后...irp已经好了,只要IoCallDriver(pUDPObject,PIrp)就行了...
上面用的是UDP的例子(Datagram),但是tcp也是一样,虽然函数有点差别,但是也是大
同小异(TdiBuildSend)。
为了搞清楚上面的两个函数到底做了些什么(到底构建的irp是什么样子),没有必要去
跟踪,实际上,tdibuildxxx
都不过是一个宏,你可以在tdikrnl.h里找到。打开tdikrnl.h看看,发现每个宏里都有
这么一句:
        _IRPSP->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
于是我们知道tdi client就是通过majorfunction=IRP_MJ_INTERNAL_DEVICE_CONTROL,m
inorfunction=send/recv/...
和tcp通讯的。这就使得我们确信,这种方法是可行的。(不是直接调用tdi函数,而是
发irp)


发信人: huyuguang (吃饭), 信区: SysInternals ;32mWWW-POSTm
标  题: 一个简单的tcp filter的例子
发信站: 武汉白云黄鹤站 (Thu Jul 13 15:49:50 2000) , 站内信件
接收的过程较为复杂(tdi client的选择较多,因此要考虑各种情况)
开始的时候,我在ddk document里看到这么一个宏:tdibuildreceive,我想ok,
和send一样,我当时想的很简单,以为tdi client要接受数据了,它就向tcp发一个
irp,然后返回pending,当有数据来的时候,tcp处理完这个irp,然后tdi client只要在
这个irp的
irp_complete里处理得到的数据就行了。这的确是tdi client的一个选择,但是
当我试验的时候,我发现至少wsock不是这样做的,因为我打开了一个ie,浏览了一个网
页,
但是我发现我发出的数据都很好的捕获到了,但是接收的数据一个也没有,而且事实上

tcp似乎就没有受到minorfunction=tdi_receive的irp。我因为这件事苦恼了一段时间,

后来我仔细的读了读ddk document,发现tdi client还有第2种选择,首先向tcp发送一

irp,minorfunction=tdi_sethandler,设置一些回调函数,然后当事情发生的时候,tc
p
就会调用这些回调函数,这些函数名字是clientEventxxx。这个过程可以仔细看ddk do
cument,
看TdiBuildSetEventHandler,就知道哪些过程可以用这个方法。receive也是其中的一
个,于是
我们的方法得到了。首先我们得到了irp,如果是set_eventhandler,那么就修改tdi c
lient
向tcp设置的回调函数的入口,把它指向我们自己写的一个函数,同时保留原来的入口,

然后在我们自己写的函数里里调用它。
代码如下:
       PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( Irp );
 MajorFunction = pIrpStack->MajorFunction;
 MinorFunction = pIrpStack->MinorFunction;
 FileObject = pIrpStack->FileObject ;
       ....
 switch(MajorFunction)
 {
  ...
  case IRP_MJ_INTERNAL_DEVICE_CONTROL  :
  {
   switch(MinorFunction)
   {
    ...
    case TDI_SET_EVENT_HANDLER:
    pRequestSetEvent = (PTDI_REQUEST_KERNEL_SET_EVENT)(&(pIrpStack->      Pa
rameters.DeviceIoControl)) ;
    EventType=pRequestSetEvent->EventType;
    EventHandler=pRequestSetEvent->EventHandler;
          EventContext=pRequestSetEvent->EventContext;
    ...
    switch(EventType)
    {
     ...
     case TDI_EVENT_RECEIVE :
      pRequestSetEvent->EventHandler = OurClientEventReceive;
      g_EventReceive = EventHandler;
      break;
     ...
值得注意的是,就算是set_eventhandler,也不一定就是tdi_event_receive里接受数据

这个tdi_client的选择很多,还有ClientEventChainedReceive 什么的,详情可看ddk,

winsock似乎都是没有用过这个。不过这个不影响,我们可以把ddk里面所有可能的情况

全部列出来,一一判断,然后分别处理。对于clienteventreceive,这里还有几句话要

清楚,并不是每次调用这个函数就得到了数据,这还要根据ReceiveFlags参数,tdi cl
ient
要根据这个参数决定是否要发tdi_receive irp得到数据。于是我们的处理函数就要判断
这个
参数,以便做出相应的处理,我自己的代码在实际的环境中运行了一段时间,似乎没有
问题,但是
我也不敢说,对于各种情况我都考虑到了。

最新喜欢:

WY.lslrtWY.lsl... ljmmaryljmmar...
zgc7622
驱动小牛
驱动小牛
  • 注册日期2003-02-24
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分136分
  • 威望15点
  • 贡献值0点
  • 好评度13点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2003-03-03 08:58
怎么没有人回复呀!!!!!!!!
nicol
驱动大牛
驱动大牛
  • 注册日期2001-11-28
  • 最后登录2009-07-30
  • 粉丝0
  • 关注0
  • 积分45分
  • 威望5点
  • 贡献值0点
  • 好评度4点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2003-03-03 15:55
嘿嘿,。
有啊有啊,我在看也在回复。
多努力啊。
这样好的文章多发点。
偶已经保存下来了。 :D :D :D :D
==寂寞骆驼==
zgc7622
驱动小牛
驱动小牛
  • 注册日期2003-02-24
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分136分
  • 威望15点
  • 贡献值0点
  • 好评度13点
  • 原创分0分
  • 专家分0分
地板#
发布于:2003-03-03 16:44
这不是我写的,我只是转贴罢了。我是一个想学习NDIS的新手,以后还请大侠多多帮助呀!!!! :D
HuYuguang
论坛版主
论坛版主
  • 注册日期2001-04-25
  • 最后登录2013-04-29
  • 粉丝3
  • 关注1
  • 积分92分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分1分
  • 专家分0分
地下室#
发布于:2003-03-03 22:52
这不是我写的,我只是转贴罢了。我是一个想学习NDIS的新手,以后还请大侠多多帮助呀!!!! :D


关于tcp filter,这是个半拉子产品,200年这么做只是因为
闲得无聊,和朋友打赌证明这样可行。

推荐pcausa的tcp/udp/icmp filter的例子,更完整,更可靠,
更稳定。真不知道那个闲人是怎么在研究ndis之余,哄mm,挣
银子养家糊口的。

今晚心情不太好,心情不好的原因又不足为外人道,只好独立
体会了。唉,那无忧无虑的在技术道路上跋涉的时光怎么消失
的这么快,而且一去不复返了呢 :(
不再回忆从前,我已经生活在幸福当中。
nicol
驱动大牛
驱动大牛
  • 注册日期2001-11-28
  • 最后登录2009-07-30
  • 粉丝0
  • 关注0
  • 积分45分
  • 威望5点
  • 贡献值0点
  • 好评度4点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2003-03-04 09:35
啊。。。。。
 :D :D :D :D :D
胡大侠。
好久不见啊。真的是神龙见首不见尾。

这几天悟出一个道理,工作是必须的,MM也是一定要用心的。
有时候,不妨放下工作,用点心思在MM身上;也许事半而功倍。

==寂寞骆驼==
游客

返回顶部