分享
 
 
 

一个简单的tcp filter的例子

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

一个简单的tcp filter的例子

来源:华中白云黄鹤BBS

作者:huyuguang

这两天版面日渐萧条,我只好硬着头皮把我自己的一个尚在开发,非常不成熟

的东西拿出来了。

前面我曾经就网络加密这个议题讨论过,那个时候我提出的方法是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。

前面已经讲过driverentry了,经过driverentry,所有的原来应该发送到

tcp设备的irp现在都发送到我们的设备的处理函数了,如果什么事情都不做,

那么可以简单的调用iocalldriver把这个irp发到tcp设备去让它处理。

当然,我们是要做些事情的,于是代码如下:

UCHAR MajorFunction,MinorFunction;

PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( Irp );

MajorFunction = pIrpStack->MajorFunction;

MinorFunction = pIrpStack->MinorFunction;

file://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设备到底是如何工作的.

我们的任务是要得到本机发送出去的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, // pointer to device object

pTransportObject, // pointer to udp object

NULL, // pointer to event

NULL ); // pointer to return buffer

分配一块irp,然后调用

TdiBuildSendDatagram (

pIrp, // pointer to irp

pDeviceObject, // pointer to device object

pTransportObject, // pointer to file object

NULL, // completion routine

NULL, // completion context

pMdl, // pointer to data

dBufferSize, // size of data

pConnectInfo ); // connection 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,minorfunction=send/recv/...

和tcp通讯的。这就使得我们确信,这种方法是可行的。(不是直接调用tdi函数,而是发irp)

接收的过程较为复杂(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,设置一些回调函数,然后当事情发生的时候,tcp

就会调用这些回调函数,这些函数名字是clientEventxxx。这个过程可以仔细看ddk document,

看TdiBuildSetEventHandler,就知道哪些过程可以用这个方法。receive也是其中的一个,于是

我们的方法得到了。首先我们得到了irp,如果是set_eventhandler,那么就修改tdi client

向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-> Parameters.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 client

要根据这个参数决定是否要发tdi_receive irp得到数据。于是我们的处理函数就要判断这个

参数,以便做出相应的处理,我自己的代码在实际的环境中运行了一段时间,似乎没有问题,但是

我也不敢说,对于各种情况我都考虑到了。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有