欢迎访问binary的Blog   虚心使人进步,骄傲使人落后。

          W3CHINA Blog首页    管理页面    写新日志    退出



«September 2025»
123456
78910111213
14151617181920
21222324252627
282930


登录

用户名称:
登陆密码:
密码保存:


联系我
email: binaryluo(at)gmail.com

我的分类

日志更新

最新评论

留言板

Blog信息

 
blog名称:二进制-虚心使人进步,骄傲使人落后。
日志总数:42
评论数量:370
留言数量:88
访问次数:640620
建立时间:2005年2月19日




[网络编程技术]【转】利用 NDIS 中间层驱动程序截获网络封包
文章收藏,  读书笔记,  软件技术,  电脑与网络

binaryluo 发表于 2006/1/26 22:43:19

(中国黑客数据库)由于互联网发展的历史原因, TCP/IP 协议及 HTTP 、 FTP 等基于 TCP/IP 协议的各种应用层协议,在协议设计之初均未考虑安全传输问题。随着互联网的发展,国际标准组织虽陆续推出了 SSL 、 HTTP1.1 等具有安全传输能力的应用层协议,但作为应用层承载协议的 TCP/IP 协议仍存在着固有的安全缺陷,造成至今未能有彻底的、低成本的、不需硬件支持的互联网安全传输解决方案。正是由于网络传输安全问题的现实存在,推动着黑客攻击技术、防火墙技术的不断发展。  无论是黑客攻击技术还是防火墙技术,其实现均必须具备网络封包截获技术。黑客利用网络封包截获技术,侦听获取网络传输数据,并发起仿冒攻击、篡改攻击等;防火墙利用网络封包截获技术,截断式地或侦听式地获取通过本机的网络封包,进行安全策略捡择后,或放行、或拦截丢弃网络封包,以达到反攻击的目的。  一、概述  网络封包截获,涉及驱动编程技术、核心态编程技术、系统动态链接库编程技术、协议生成与解析编程技术等,集中体现了网络应用的核心技术,是防火墙等高级网络应用开发的基础。基于 Windows 2000 和 Windows XP 的网络封包截获技术主要分为三种: WinSock2 动态链接库重载、传输层过滤驱动、中间层驱动。  WinSock2 动态链接库重载 : 系统的 WinScok2 动态链接库( ..\system32\winsock.dll ),随系统启动而载入内存,提供 29 个用于网络传输的功能函数。 IE 等普通上层应用程序,调用 WinScok2 动态链接库中的 WSPSend 、 WSPRecv 等函数,实现网络收、发功能。修改注册表中 HKEY_LOCAL_MACHINE\SYSTM\CURRENTCONTROLSET\SERVICES\WinSock2 项,建立新的自定义 WSPStartup 入口函数,可以重载 winsock.dll 。通过重载 winsock.dll 中的有关网络收、发函数,增加网络封包收、发前、后的自定义处理功能,实现网络封包截获。公开源代码的费尔防火墙,使用了 WinSock2 动态链接库重载,实现网络封包的截获与安全解析。   传输层过滤驱动: 使用 NDIS ( Network Driver Interface Specification 网络驱动接口规范)技术,又称为 TDI 编程( Transport Driver Interface 传输层驱动接口编程 )。 Windows 2000 和 Windows XP 操作系统中, TCP/IP 协议作为系统驱动程序( ..\system32\TcpIp.sys ),在系统启动时加载入系统内存,以 TCP/IP 设备对象( DeviceObject )的形式供应用程序或其它系统程序调用。传输层过滤驱动程序创建一个或多个设备对象,直接挂接到 TCP/IP 设备对象之上。挂接成功后,当其它程序使用网络传输功能,调用 TCP/IP 设备对象时,操作系统首先将该调用映射到 TCP/IP 设备对象之上所挂接的传输层过滤驱动程序。通过传输层过滤驱动程序,再调用下层的 TCP/IP 设备对象,从而完成网络访问功能。同样,从 TCP/IP 层上传至应用程序的网络封包,也要经传输层过滤驱动程序后,再转发至目标应用程序端口。基于此工作原理,可以在传输层过滤驱动程序中实现网络封包截获,完成网络封包的过滤及加解密处理。公开原代码的 TcpIpDog.sys 及微软官方 2000 DDK 的 Packet.c 例程,使用传输层过滤驱动技术,实现了网络封包截获。   中间层驱动: 与传输层过滤驱动实现基本原理一致,也是使用 NDIS 技术。主要差别在于,中间层驱动程序,挂接在协议设备对象(包括 TCP/IP 设备对象)和网卡设备对象之间。任何进出网卡的网络封包,均必须首先经过中间层驱动程序的处理。从某种意义上分析,中间层驱动程序更象一个虚拟网卡。该虚拟卡封装了物理网卡,对物理网卡的一切网络访问操作,均必须先经虚拟卡处理。公开原代码的微软官方 2000 DDK 的 Passthru.c 例程,使用中间层驱动技术,实现了网络封包截获。 以上三种网络封包截获技术中, WinSock2 动态链接库重载、传输层过滤驱动截获网络封包不够彻底,均存在被绕开的技术可能,而 中间层驱动作用于协议层之下、物理网卡驱动层之上,与协议无关,对网络封包的截获最为彻底,基本不存在被绕开的技术可能,但也最具有技术难度。中间层驱动程序的技术难点主要体现为:  缺少公开的技术资料,基本无中文讲解资料、教材书籍。即使是 微软官方 2000 DDK 的 Passthru.c 例程,也仅公开了侦听式数据报头的截获方法与数据结构,而对 IRP ( I/O Request Packet 系统 I/O 请求包)结构未作进一步的公开。  与硬件相关性大。某种意义上,中间层驱动程序更象虚拟网卡,而网卡硬件性能的不一致,在中间层驱动程序中也必须有所体现。如,总线型网卡与非总线型网卡接收数据包的原理并不相同,就要求中间层驱动程序也必须同时考虑两种网卡的不同要求。  作用于协议层之下,必须手动解析各种传输协议,造成在中间层解析协议的技术难度较大。  编程与调试困难。驱动程序的编制与调试本身就极为困难,加之中间层驱动程序作用于网卡驱动程序之上,而基本不可能拥有网卡驱动的原程序,无法使用 So ftICE.exe 等调试工具加载网卡驱动的调试符号,加之网卡工作原理复杂,使得中间层驱动程序的调试较 USB 接口等一般硬件驱动程序调试更为困难。 由于以上原因,基于中间层驱动技术的网络通信产品,基本止于试验室内,止于项目定制式的产品,少有成熟的通用产品问世。而也正是由于中间层驱动程序的协议无关性、不可绕开性及存在的技术挑战性,吸引着包括黑客在内的大量精英程序员。 二、 NDIS 简介  NDIS 是 Network Driver Interface Specification (网络驱动程序接口规范)的缩写,为传输层提供了标准的网络接口。在 Windows 操作系统中,所有的应用程序都最终通过调用 NDIS 接口,实现网络访问。 NDIS 在操作系统中的结构如图一所示。 图一: NDIS 结构图 如图一所示, NDIS 支持 3 种类型的驱动程序:  传输层驱动程序 ( Protocol Drivers ): 对上层应用程序开放 TDI 接口,对下层驱动程序开放 Protocol 接口,与下层 Miniport 接口对接,实现协议驱动功能。严格意义上讲,传输层驱动与协议驱动尚有区别,但本文仅涉及 TCP/IP 协议,并不涉及本地介质认可的其它协议,为便于理解,而将传输层驱动、协议驱动简化为传输层驱动。  中间层驱动程序( Intermediate Drivers ): 位于物理网卡驱动程序(即微软官方所称的微型端口驱动程序)之上, 同时具备 Miniport 接口和 Protocol 接口,可与上、下层驱动程序对接,提供转发驱动功能。利用其位于物理网卡之上的转发功能,可以实现不可绕开的网络封包截获。  微型端口驱动程序( Miniport Drivers ): 对上层的中间层驱动程序开放 Miniport 接口,再通过 NDIS 接口完成对物理网卡的操作,实现对物理网卡的驱动功能。 三、开发工具简介  由于缺少教材性的中文资料,客观上造成理解、建立驱动程序开发环境有一定困难。许多对驱动开发感兴趣的程序员,往往是因为不能够正确理解和建立驱动程序开发环境,要么放弃了驱动程序研究,要么人为复杂化了驱动程序开发过程。笔者结合实际工作经验,在有关帮助文档之外,主要强调各种开发包的本质功能及相互关系。具体开发环境的建立步骤,特别是各种开发包的安装顺序,请参见有关开发包的帮助文档。  与 USB 接口驱动等其它驱动程序开发一样,中间层驱动程序开发也主要是利用微软提供的 Windows 2000 DDk 开发包,其中 DDK 是 Drivers Develop Kit 的简称。 DDK 提供了大量符合 Windows 操作系统 NDIS 接口规范的 C 语言函数,为驱动开发程序员提供了良好的开发接口。  鉴于 DDK 开发包理解和使用较为困难,许多第三方公司对 DDK 进行了不严格的面向对象的封装,为程序员在 VC++6.0 环境中使用面向对象的语言开发驱动程序,提供了更为友好的平台接口。其中影响较大,应用较为成功的是 Compware 公司的 DriverStudio 3.1 。特别是 DriverStudio 3.1 提供了封装类库的原代码(含注示),和常见的驱动例程,程序员不但可以参考其提供的驱动例程,而且可以通过修改现有的封装类库简化开发功能的实现,甚至能够生成自定义驱动类。同时, DriverStudio 3.1 还提供了开发向导功能,可以象使用 MFC 开发向导一样,通过向导功能自动生成大量难以编写的驱动公共模块,极大地减少了开发工作量,降低了开发难度。  VC++6.0 、 DriverStudio 3.1 、 Windows 2000 DDk 三种主要开发工具的关系可简述如下:  Windows 2000 DDk 是微软官方提供的 Windows 2000/XP NDIS 接口的具体 C 语言编程实现,是包括中间层驱动在内的各种驱动程序的核心开发包。  DriverStudio 3.1 是 Compware 公司提供的基于 Windows 2000 DDk 的开发包,其主要是对 Windows 2000 DDk 进行了不严格的面向对象的封装,并能够在安装过程中自动设置 VC++6.0 开发环境、自动设置系统环境变量,使程序员可以象调用 MFC 类库一样调用 DriverStudio 3.1 类库,可以使用面向对象的语言进行驱动程序开发,以降低开发难度。同时, DriverStudio 3.1 还提供了 Compware 公司的 SoftICE.exe 调试工具,以提高驱动程序调试效率。  通过 DriverStudio 3.1 的 DDK Build Setting 菜单功能调用 VC++6.0 ,能够自动设置环境参数,使 VC++6.0 能够编译链接至 DriverStudio 3.1 的类库文件,从而编译链接至 DDK 库文件,使 VC++6.0 成为驱动程序的最终开发平台。 四、中间层驱动程序模型分析  上文已简单地提到过中间层驱动程序位于 Miniport 和 Protocol 驱动程序之间,同时具有 Miniport 和 Protocol 两种驱动程序接口。具体来讲,中间层驱动程序在自己的上下两端分别开放出一个 Miniport 接口(对上)和 Protocol 接口(对下)。其中,位于中间驱动程序上面的 Miniport 接口,与上层驱动程序的 Protocol 接口对接;位于下面的 Protocol 接口,与下层驱动程序的 Miniport 接口对接。通过两种接口的使用,使得中间层驱动程序能够插入 Miniport 和 Protocol 驱动程序之间。  图二: NDIS 中间层驱动程序安装前后的对比结构示意  如图二所示,中间层驱动程序安装前,物理网卡驱动程序与传输层驱动程序进行直接通信,两者间通过 NDIS 接口完成网络封包传递;中间驱动程序安装后,网络封包经中间层驱动程序在物理网卡驱动程序、传输层驱动程序之间进行转发,从而使得中间层驱动程序具备了网络封包截获功能。  利用 NDIS 中间驱动程序,可以在网卡驱动程序和传输层驱动程序之间插入一层自定义处理,从而可以用来截获网络封包,并重新进行封包、加密、网络地址转换及过滤等操作。且由于中间层驱动程序位于网卡驱动程序和传输层驱动程序之间,可以截获较为底层的与协议无关的网络封包,可以完成更为底层的操作,编写网络安全软件的安全强度更有保证。  考虑到篇幅和水平所限,且考虑到 DriverStudio 3.1 开发向导能够自动生成大量中间层驱动的基础代码,本文不再对中间层驱动程序内部的 UML 模型展开深入分析,有兴趣的读者可参见 DriverStudio 3.1 帮助文档中的 DriverNetworks Help/Programing Guide/NDIS Drivers Framework/NDIS Intermediate Drivers Framework 的详细分析说明,且可参见 DriverStudio 3.1 目录 SOURCE 下的 DNW.dsw 中的 KndisLib Classes 进行原代码级的理解分析。在此,笔者特别强调,对 KndisLib Classes 进行原代码级的理解分析是打牢驱动程序开发技术基础、提高驱动程序开发能力的有效方法。 五、网络封包截获核心原代码分析  网络封包无外乎分为收、发两种封包,因此截获网络封包的理想位置应是发送封包之前,和接收封包之后。具体来讲,接收封包的截获位置,应位于物理网卡接收封包之后;发送封包的截获位置,应位于通过物理网卡发送封包之前。  DriverStudio 3.1 开发包提供了 OnReceive 和 OnSend 两个十分方便的虚函数。其中,物理网卡接收封包之后, NDIS 将调用 OnReceive 虚函数;通过物理网卡发送封包之前, NDIS 将调用 OnSend 虚函数。因此,只需在自开发的中间层驱动程序中实现这两个虚函数,加入自定义的封包处理方法,就能够很方便地实现网络封包截获处理功能。 DriverStudio 3.1 开发向导能够自动生成大量基础代码,甚至自动生成了空处理的 OnReceive 和 OnSend 两虚函数,程序员只要加以改写,就能够实现自定义的封包处理功能,极大地简化了开发过程。  但我们应注意到,中间层驱动程序位于传输层驱动程序或协议层驱动程序之下,因此就要求我们必须自编程实现协议的解析功能。之所以在此再次强调协议的解析,是因为 DriverStudio 3.1 开发包所提供的例程中,对 TCP/IP 协议的数据结构定义有误( TCP 包头长度的计算方法不正确),虽不影响该例程的正常编译和运行,但若在该例程基础上修改设计更完善的 TCP/IP 封包的截获程序,将会造成难以测试发现的漏包现象。 (一) TCP/IP 协议数据结构的定义  定义正确的协议数据结构,是实现协议解析,进而实现封包截获的基础。所谓协议数据结构,其实质是协议的包头数据结构,包体内是 HTTP 等应用层协议数据,无关于本文涉及的网络封包截获。任何有效的 TCP/IP 数据包均由包头数据和包体数据组成,其中包头包括以太帧数据头、 IP 数据头、 TCP 数据头;包体内包含应用层协议数据。  // Ethernet Packet Header  typedef struct _ETHERNET_HEADER { UCHAR eth_dest[6]; // Destination address  UCHAR eth_src[6]; // Source address union {  USHORT eth_len; // 802.3 length field.  USHORT eth_type; // Ethernet type field.  }; } ETHERNET_HEADER, *PETHERNET_HEADER;  // Internet Protocol (IP) Packet Header  typedef struct IP_HEADER  {  UCHAR iph_verlen; // Version and length  UCHAR iph_tos; // Type of service  USHORT iph_length; // Total datagram length  USHORT iph_id; // Identification  USHORT iph_offset; // Flags, fragment offset  UCHAR iph_ttl; // Time to live  UCHAR iph_protocol; // Protocol  USHORT iph_xsum; // Header checksum  ULONG iph_src; // Source address  ULONG iph_dest; // Destination address } IP_HEADER, *PIP_HEADER;  // TCP Packet Header  typedef struct TCP_HEADER  {  USHORT tcph_src; // Source Port Number  USHORT tcph_dest; // Destination Port Number  ULONG tcph_seq; // Sequence Number  ULONG tcph_ack_seq; // Acknowlegdement Number  USHORT tcph_flags; // Flags  USHORT tcph_window; // Window  USHORT tcph_check; // Checksum  USHORT tcph_urgent; // Urgent pointer  UCHAR GetDataOffset() {  USHORT nLen=(tcph_flags & 0x 00f 0);// 例程中无此处理,造成标志字段高 4 位为全零(如 //tcph_flags=0x0270 )时, TCP 包头长度计算出错。 // 虽标志字段高 4 位为全零在正常收发封包过程中不 // 会出现,但在通过“三次握手”建立 TCP 连接和结 // 束 TCP 连接过程中,必然出现高 4 位为全零情况, // 进而造成在此过程中 TCP 包头长度计算错。一但 //TCP 包头长度计算错,可能引发进一步的异常。  return (nLen >> 4)*4;  }  } TCP_HEADER, *PTCP_HEADER; (二) TCP/IP 协议解析函数的实现  在 TCP/IP 协议数据结构的定义的基础上,可根据项目开发需要实现协议解析功能函数。下文原代码中,主要实现了源 IP 地址、目的 IP 地址、源 TCP 端口号、目的 TCP 端口号、包头总长度的解析功能。现有的 DriverStudio 3.1 开发包例程和 Windows 2000 DDk 例程中,未能提供协议解析代码。因此,初学者应特别注意下文原代码中的移位计算。部分初学者就是因为对 VC 指针与协议中数据类型的对应关系理解不正确,或未进行移位处理,或移位处理不正确,均造成协议解析不正确,进而造成封包无法正确截获。  //Parse address in KNdistPacket  bool SecurityVirtualCardAdapter::GetAddr_OnRec(const KNdisPacket& Original, //Data packet  //Out parameters  ULONG *pIpScrAddr,ULONG *pIpDesctAddr,  USHORT *pTcpScrAddr,USHORT *pTcpDesctAddr,  ULONG *pPckHdLen)  {  //Return buffers count in the packet  UINT nBufCnt=Original.QueryBufferCount();  //Return the first buffer in the packet  KNdisBuffer Buf=Original.QueryFirstBuffer();  //Tests if the buffer is initialed correctly  if(!Buf.IsValid())  return false; //Return the first buffer length  //KNdisBuffer::Length  // UINT Length( ) ;  // Gets the length.  //Length of the underlying buffer in bytes.  ULONG nBufLen = Buf.Length();  //Return TCP packet header length  ULONG nHdrLen=sizeof(ETHERNET_HEADER)  +sizeof(TCP_HEADER)  +sizeof(IP_HEADER);  if(nHdrLen>nBufLen)  return false;  //KNdisBuffer::Address  // PVOID Address( ) ;  // Gets the virtual address.  //Virtual address of the first byte of the buffer, or NULL if an error has occurred.  PETHERNET_HEADER pEthHdr = (PETHERNET_HEADER) Buf.Address();  //Return false if ethernet packet is not IP protocol  if(pEthHdr->eth_type!=ETH_TYPE_IP)  return false; //Return false if not TCP protocol  PIP_HEADER pIpHdr=(PIP_HEADER)((PCHAR)pEthHdr+sizeof(ETHERNET_HEADER));  if(pIpHdr->iph_protocol!=IP_PROTOCOL_TCP)  return false;  //Get IP address  ULONG srcIp=pIpHdr->iph_src;  *pIpScrAddr=((srcIp&0xff)<<24)+  ((srcIp&0xff00)<<8)+  ((srcIp&0xff0000)>>8)+  ((srcIp&0xff000000)>>24);  ULONG destIp=pIpHdr->iph_dest;  *pIpDesctAddr=((destIp&0xff)<<24)+  ((destIp&0xff00)<<8)+  ((destIp&0xff0000)>>8)+  ((destIp&0xff000000)>>24);  //Get TCP port number and TCP packet header length  PTCP_HEADER pTcpHdr=(PTCP_HEADER)((PCHAR)pIpHdr+sizeof(IP_HEADER)); UCHAR nTcpPckHdLen=pTcpHdr->GetDataOffset();  USHORT scrPort=pTcpHdr->tcph_src;  *pTcpScrAddr=((scrPort&0xff00)>>8)+((scrPort&0x00ff)<<8);  //TRACE("GW Rec Source TCP port=%d\n",*pTcpScrAddr);  USHORT desctPort=pTcpHdr->tcph_dest;  *pTcpDesctAddr=((desctPort&0xff00)>>8)+((desctPort&0x00ff)<<8);  //TRACE("GW Rec Desct TCP port=%d\n",*pTcpDesctAddr);  //Return packet header length  *pPckHdLen=sizeof(ETHERNET_HEADER)+sizeof(IP_HEADER)+nTcpPckHdLen;  return true;  } (三) OnReceive 虚函数的实现  根据物理网卡工作方式的不同,接收封包方式主要有全包接收方式和部分接收方式。其中,全包接收方式对应于总线型网卡,网卡收到封包后, NDIS 将一次性把完整的封包提交至 OnReceive 虚函数;部分接收方式对应于非总线型网卡,网卡收到封包后, NDIS 将先把封包的一部分提交至 OnReceive 虚函数,上层程序根据封包的一部分判断是否同意接收,若同意接收网卡将再次提交封包的其它部分,若不同意接收网卡则丢弃该封包。相对应于以上两种接收方式, DriverStudio 3.1 开发包也提供了 OnReceive 虚函数的两种形式:   NDIS_STATUS SecurityVirtualCardAdapter::OnReceive  (const KNdisPacket& Original, KNdisPacket& Repackaged)// 对应于全包接收方式   NDIS_STATUS SecurityVirtualCardAdapter::OnReceive  (IN OUT KNdisPartialPacket& PacketToAccept,  IN PVOID HeaderBuffer, IN UINT HeaderBufferSize,  IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize,  IN UINT PacketSize)// 对应于部分接收方式 全包接收方式下的 OnReceive 虚函数的实现较为简单,且与 OnSend 虚函数的实现原理完全一致,开发包例程中有详细参考,本文“ OnSend 虚函数的实现”也将有原代码展示,因此下文原代码将仅涉及部分接收方式下的 OnReceive 虚函数的实现。  部分接收方式下,若在中间层程序程序中对全包进行处理,按照 DriverStudio 3.1 的帮助说明,将需要进行私有包池的建立和管理,编程复杂、调试难度大。笔者研究测试发现,在 Windows 2000/XP/2003 下,由于操作系统对网卡缓存管理有相当好的连续性,完全可以经计算后,通过部分接收包的指针获得全包指针。简而言之,在 Windows 2000/XP/2003 下,可以通过指针位置计算后,采用全包接收处理方式对部分接收进行全包处理,从而极大地降低了部分接收方式的中间层驱动程序开发难度。指针位置计算的关键,是在部分包缓存区中忽略以太帧头。  具体原代码如下(为补充上文的协议解析功能,其中涉及了包头中其它字段的解析):  NDIS_STATUS SecurityVirtualCardAdapter::OnReceive  (IN OUT KNdisPartialPacket& PacketToAccept,  IN PVOID HeaderBuffer, IN UINT HeaderBufferSize,  IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize,  IN UINT PacketSize)  {  PETHERNET_HEADER pEthHd=(PETHERNET_HEADER)HeaderBuffer;  PIP_HEADER pIpHd=(PIP_HEADER)((PUCHAR)HeaderBuffer+sizeof(ETHERNET_HEADER));  PTCP_HEADER pTcpHd=(PTCP_HEADER)((PUCHAR)HeaderBuffer+  sizeof(ETHERNET_HEADER)+  sizeof(IP_HEADER));  USHORT nEthType=pEthHd->eth_type;  UCHAR nProtocol=pIpHd->iph_protocol;  if(nEthType!=ETH_TYPE_IP||nProtocol!=IP_PROTOCOL_TCP)  {  //TRACE("Not TCP/IP");  UNREFERENCED_PARAMETER(PacketToAccept);  return NDIS_STATUS_SUCCESS;  }  ULONG nScrIpAddr=pIpHd->iph_src;  ULONG nDestIpAddr=pIpHd->iph_dest;  USHORT nScrPort=pTcpHd->tcph_src;  USHORT nDestPort=pTcpHd->tcph_dest;  USHORT nTcpHdLen=pTcpHd->GetDataOffset();  nScrIpAddr=((nScrIpAddr&0xff000000)>>24)+  ((nScrIpAddr&0x00ff0000)>>8)+  ((nScrIpAddr&0x0000ff00)<<8)+  ((nScrIpAddr&0x000000ff)<<24);  nScrPort=((nScrPort&0xff00)>>8)+((nScrPort&0x00ff)<<8);  nDestIpAddr=((nDestIpAddr&0xff000000)>>24)+  ((nDestIpAddr&0x00ff0000)>>8)+  ((nDestIpAddr&0x0000ff00)<<8)+  ((nDestIpAddr&0x000000ff)<<24);  nDestPort=((nDestPort&0xff00)>>8)+((nDestPort&0x00ff)<<8);  if(!IsEncrypt(nScrIpAddr,nDestIpAddr,nScrPort,nDestPort))  {  //TRACE("Submit not encrypt packet");  UNREFERENCED_PARAMETER(PacketToAccept);  return NDIS_STATUS_SUCCESS;  }  TRACE("******** Receive partial *************");  TRACE("HeaderBufferSize=%d",HeaderBufferSize);  TRACE("PacketSize=%d",PacketSize);  TRACE("LookaheadBufferSize=%d",LookaheadBufferSize);  TRACE("pHeaderBuffer=0x%0x",HeaderBuffer);  TRACE("pLookAheadBuffer=0x%0x",LookAheadBuffer);  TRACE("Source=%d.%d.%d.%d:%d",(nScrIpAddr&0xff000000)>>24,  (nScrIpAddr&0x00ff0000)>>16,  (nScrIpAddr&0x0000ff00)>>8,  (nScrIpAddr&0x000000ff),  nScrPort);  TRACE("Dest=%d.%d.%d.%d:%d",(nDestIpAddr&0xff000000)>>24,  (nDestIpAddr&0x00ff0000)>>16,  (nDestIpAddr&0x0000ff00)>>8,  (nDestIpAddr&0x000000ff),  nDestPort);  TRACE("////// TCP Pakcet Header ///////");  ULONG nSeq=pTcpHd->tcph_seq;  nSeq=((nSeq&0xff000000)>>24)+  ((nSeq&0x00ff0000)>>8)+  ((nSeq&0x0000ff00)<<8)+  ((nSeq&0x000000ff)<<24);  ULONG nAck=pTcpHd->tcph_ack_seq;  nAck=((nAck&0xff000000)>>24)+  ((nAck&0x00ff0000)>>8)+  ((nAck&0x0000ff00)<<8)+  ((nAck&0x000000ff)<<24);  USHORT nFlags=pTcpHd->tcph_flags;  USHORT nWin=pTcpHd->tcph_window;  TRACE("Seq=0x%0x",nSeq);  TRACE("Ack=0x%0x",nAck);  TRACE("Flags=0x%0x",nFlags);  TRACE("Win=0x%0x",nWin);  TRACE("///////////////////////");  PUCHAR pLook=(PUCHAR)LookAheadBuffer;  USHORT nIpandTcpHdLen=sizeof(IP_HEADER)+nTcpHdLen;  if(PacketSize<(UINT)(nIpandTcpHdLen+7))  {  TRACE("Submit no Encrypt packet");  UNREFERENCED_PARAMETER(PacketToAccept);  return NDIS_STATUS_SUCCESS;  }  //LookaheadBufferSize  for(USHORT i=0;i<PacketSize;i++)  {  if(i>nIpandTcpHdLen-1)  {  UCHAR test=pLook[i];  TRACE("Look[%d]=(0x%0x,%c)->(0x%0x,%c",i,test,test,pLook[i],pLook[i]);  }  }  UNREFERENCED_PARAMETER(PacketToAccept);  return NDIS_STATUS_SUCCESS;  }  (四) OnSend 虚函数的实现  OnReceive 虚函数的实现相对较为简单, DriverStudio 3.1 提供了详细例程及说明,本文不再详细分析,仅列出自编写的原代码。  NDIS_STATUS SecurityVirtualCardAdapter::OnSend  (const KNdisPacket& Original, KNdisPacket& Repackaged)  {  NDIS_STATUS Status = NDIS_STATUS_SUCCESS;  ULONG IpScrAddr=0,IpDesctAddr=0;  USHORT TcpScrAddr=0,TcpDesctAddr=0;  ULONG PckHdLen=0;  ULONG *pIpScrAddr,*pIpDesctAddr;  USHORT *pTcpScrAddr, *pTcpDesctAddr;  ULONG *pPckHdLen;  pIpScrAddr=&IpScrAddr;  pIpDesctAddr=&IpDesctAddr;  pPckHdLen=&PckHdLen;  pTcpScrAddr=&TcpScrAddr;  pTcpDesctAddr=&TcpDesctAddr;  if(GetAddr_OnSend(Original,  pIpScrAddr,pIpDesctAddr,  pTcpScrAddr,pTcpDesctAddr,  pPckHdLen))// 判断是否是须加密处理的封包  {  TRACE("----- Send Encrypt -----");  Repackaged.CloneDown(Original);// 开发包提供的向下复制封包方法  EncryptPacket_OnSend(Repackaged,*pPckHdLen);// 自定义的加密处理函数  TRACE("----- Send Encrypt End -----");  return Status;  }  else  {  Repackaged.CloneDown(Original); return Status;  } }  


阅读全文(5828) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.032 second(s), page refreshed 144796495 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号