NDIS中间层驱动实现网页跳转

  • 格式:doc
  • 大小:43.50 KB
  • 文档页数:4

在编写windows网络驱动之前,需要具备一定的计算机网络知识。

包括OSI/ISO 七层体系结构,常见的网络协议TCP/TP, UDP,ICMP,HTTP,FTP,SMTP/POP3等。

因为整个windows网络驱动就是建立在网络协议栈基础之上的。

Windows网络驱动有两个重要的规范:TDI,NDIS。

TDI(Transport Driver Interface)传输层接口,顾名思义,这个技术是建立在传输层之上的。

传输层位于七层协议的第三次,常见的TCP/UDP协议就属于传输层。

我们知道,传输层提供的服务包括:连接管理、差错检测、按端口号寻址。

事实上,TDI驱动主要作用就是过滤端口。

TDI是即将被淘汰的技术,微软宣布,vista之后的操作系统将不再提供TDI支持,取代它的是Windows Filter Platform和Winsock Kernel,有兴趣的朋友可以搜集一下相关的资料。

这里注重分析一下NDIS驱动框架。

NDIS(Network Driver Interface Specification)网络驱动接口标准,相比TDI,它位于七层协议的更低层次。

能够捕获更详细的信息。

可以做更多的事。

它是微软联合3com公司发布的一个标准。

NDIS网络驱动有3种表现形式:协议驱动、中间层驱动、小端口驱动。

它们的作用范围大致按照传输层、网络层、数据链路层依次往下排。

小端口驱动miniport,一般是网卡厂商提供,协议层驱动一般用来捕获数据包,大名鼎鼎的winpcap就是基于协议层驱动编写,而本文主要关心中间层驱动。

WDK文档的例子中,提供了一个中间层驱动,我的电脑中的路径是C:\WinDDK\6001.18002\src\network\ndis\passthru。

Passthru位于协议驱动和小端口驱动之间,比较灵活。

类似于它们两个的综合体。

它能捕获所有流入流出本机的数据,非常强悍。

常见的个人防火墙基本都是用中间层驱动写的。

它可以做的事情包括,过滤IP和端口号,禁止某类协议(ping/arp),加密解密数据流等,基本上你能想到的事它都可以干。

在我做的一个项目中,用到了中间层驱动,来实现一个网址跳转的功能。

下面免费贡献出我的经验。

整个跳转是在passthru的基础上稍加改动实现的。

所以,一定要多看看passthru。

要想实现网址跳转,比如ie中你输入,结果页面打开的是腾讯的首页,你就必须对从地址栏键入开始,到最终网页呈现出来的过程非常了解。

在了解了整个过程后,我们就可以伪装,篡改,让客户端和服务器都被蒙蔽。

现在的java语言,php语言等,都能实现页面跳转,而且极其简单,基本上就是一条代码的事儿。

这个做法是在应用层实现的,不靠谱,很容易被360视作非法操作,被强制干掉。

因为应用层ring3的东西没有内存保护,谁都可以去探测。

回到正题上,从请求到回送页面,这个过程包括两个阶段:发送和接收。

发送是这样走的:http-》tcp-》ip-》ether。

接收正好相反。

分别对应驱动中MpSend和PtReceive/PtReceivePacket。

接收比较复杂,有可能调用PtReceive,也有可能调用PtReceivePacket,这个最后再做讨论,现在先把整个流程捋清楚。

好,既然流程就是这样,我们要做的东西就很明确了。

一句话,篡改发送时候的目的ip。

将121.194.0.239改为59.64.114.98.(现在大多数网站的ip不一定只有一个,这里把这个问题留到最后再说)。

篡改的对象是发送包中目的ip为121.194.0.239的包。

于是,又来一个问题,怎么解析包?MpSend的时候,数据的参数是PNDIS_PACKET。

这个东西叫做包描述符。

描述符描述符,它不是真正的数据。

要想获得连续的数据,就要从它描述的内存中一块块拼接起来。

事实上的确是这样,NDIS_PACKET实际上包含了一个链式数据缓冲区,利用head,tail,next等联系起来。

好,获取连续包的代码如下:VOID PMgrGetPktData(IN PNDIS_PACKET Packet, OUT PUCHAR pDst, IN ULONG length){PNDIS_BUFFER pNdisBuffer;UINT BytesA vailable;UINT BytesRemaining = length;PUCHAR pSrc;pNdisBuffer = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);while (BytesRemaining && (pNdisBuffer != NULL)){NdisQueryBuffer(pNdisBuffer, (PVOID*)&pSrc, &BytesA vailable);if (BytesA vailable){ULONG BytesToCopy = MIN(BytesA vailable, BytesRemaining);NdisMoveMemory (pDst, pSrc, BytesToCopy);BytesRemaining -= BytesToCopy;pDst += BytesToCopy;}NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);}}其中pDst是预先用NdisAllocateMemoryWithTag分配好的一块内存。

这样,我们就把包装进pDst中了。

下面开始进行包的解析。

以太网包格式多种多样,不过绝大多数都是ETHER V2格式。

这里以我要处理的http请求包为例说明,格式大致如下:源mac地址+目的mac地址+ip头+tcp头+http数据。

其中ip头格式:typedef struct IPHeader{UCHAR versionLen;//version和首部长度决定是否有option字段UCHAR serviceType;USHORT ipPackLen;//USHORT flag;USHORT pieceFlag;UCHAR ttl;UCHAR protocol;USHORT headerCheckSum;UCHAR srcIpAddr[4];UCHAR dstIpAddr[4];}IPHeader;看到没有,只要修改ip头的最后四个字节dstIpAddr,就可以实现以假乱真。

在实际项目中,我修改了这个地址后,用wireshark抓包工具发现,服务器根本没有响应,也就是说,这个包在客户端就被丢弃了。

原因是什么?原因是没有进行校验和。

Ip,tcp,udp三个协议,哪怕修改一点点,它都要重新校验,将结果写回到headerCheckSum。

修改校验和字段后,果然,腾讯有反应了,给回送包了。

这里再贴出校验算法,c语言版的:USHORT CheckSum(USHORT *buff, int size)//计算校验和{USHORT* buffer = buff;unsigned long cksum=0;while(size >1){cksum += * buffer++;size -= sizeof(USHORT);}if(size){cksum += *(UCHAR*)buffer;}cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >>16);return (USHORT)(~cksum);}到这里,tcp连接开始了第一次握手,并且腾讯有回应了。

可是,客户端自己有问题了。

它收到腾讯的回应包后,不再进行第二次握手,而是选择了关闭连接。

这个问题困扰了我很久。

后来在一个英文资料中发现一些蛛丝马迹,大致意思是说,tcp在发生数据前,回记住目的ip,等它收到回应包后,将包的源ip和它保存的目的ip进行对比,如果发现不一致,它会认为是不安全的,直接丢弃了。

Tcp的事儿真多。

没办法,这个东西是协议规定的,绕不过去,只能继续伪造了。

怎么伪造,继续篡改回送包的源ip。

Tcp是传输层的东西,PtReceive 是链路层的东西,还好,在到达传输层之前,我们就收到了这个包,来得及。

将源ip修改后,重新发出去。

这个时候,tcp终于消停了,三次握手可以顺利进行,连接正式建立。

到这个时候,用wireshark抓包可以发现,客户端已经发出http的get请求包了。

可是,腾讯这个时候又出问题了,它没有回应任何包,单方面把连接关掉了(FIN,ACK)!什么情况!没办法,只能硬着头皮上了。

仔细查看这个http包,发现host字段是。

而正确的请求腾讯时该字段是。

难怪它关掉连接,原来它认为客户端在捉弄它,你ip请求是对的,http却不对,我就不给你回应。

好了,继续伪装吧。

客户端在发送时,如果有http包头,就篡改包头里面host字段。

篡改之后,一定要重新校验,将校验和写回tcp的checkSum字段。

Tcp头格式:Tcp头格式:typedef struct TCPHeader{USHORT srcPort;USHORT dstPort;UINT seqNum;UINT ackNum;UCHAR rsvLen;//首部长度UCHAR rsvFlag;//FlagUSHORT windowSize;USHORT checkSum;USHORT urgentPointer;}TCPHeader;好了,见证奇迹的时刻到了,我在IE中轻轻键入,刷的一下,腾讯的页面出来了!可是没等我高兴太久,又出问题了。

我把ie关了,重开,重新键入,发现打不开。

不该啊!第一次可以打开,第二次打不开,是不是cookie啥的问题?果然,wireshark 验证了我的猜测,虽然host里面sina改成qq了,可cookie却是sina的东西。

怎么办,果断丢掉cookie!重新校验。

我们知道,cookie的用处主要有加速页面载入速度,保存用户名密码等,去掉后影响也就只有这些。

网址重定向大致就这些东西了。

在实际测试中发现,有很多问题,包括不是顶级域名怎么办?有些网址还要求必须有cookie,有些网站本身也有自跳转功能,http协议也有1.1,1.0之分。

由于我的项目是在遇到某些网址时,弹出一个固定页面,所有情况都是可预知的,不存在前面的问题。

看来,要想在驱动级完美实现网页跳转,要走的路还很长。

现在回过头来聊下前面的问题。

一是不固定ip,而是passthru在接收时的处理。

第一个问题,没办法,只能让应用程序传参数的时候,将域名和ip一块传过来。

第二个问题比较麻烦。

慢慢展开。

根据网卡型号不同,PtReceive和PtReceivePacket都会被调到。