登录社区:用户名: 密码: 忘记密码 网页功能:加入收藏 设为首页 网站搜索  

文档

下载

图书

论坛

安全

源码

硬件

游戏
首页 信息 空间 VB VC Delphi Java Flash 补丁 控件 安全 黑客 电子书 笔记本 手机 MP3 杀毒 QQ群 产品库 分类信息 编程网站
  立华软件园 - 安全技术中心 - 技术文档 - 防火墙 技术文章 | 相关下载 | 电子图书 | 攻防录像 | 安全网站 | 在线论坛 | QQ群组 | 搜索   
 安全技术技术文档
  · 安全配制
  · 工具介绍
  · 黑客教学
  · 防火墙
  · 漏洞分析
  · 破解专题
  · 黑客编程
  · 入侵检测
 安全技术工具下载
  · 扫描工具
  · 攻击程序
  · 后门木马
  · 拒绝服务
  · 口令破解
  · 代理程序
  · 防火墙
  · 加密解密
  · 入侵检测
  · 攻防演示
 安全技术论坛
  · 安全配制
  · 工具介绍
  · 防火墙
  · 黑客入侵
  · 漏洞检测
  · 破解方法
 其他安全技术资源
  · 攻防演示动画
  · 电子图书
  · QQ群组讨论区
  · 其他网站资源
最新招聘信息

基于IMD的包过滤防火墙原理与实现
发表日期:2006-03-12作者:xiaobai[转贴] 出处:安全焦点  

基于IMD的包过滤防火墙原理与实现
xiaobai
xiaobai@openfind.com.cn
711网络安全小组  http://www.cpyy.net


一、前言
二、IMD中间层技术介绍
三、passthru例程分析
四、部分演示代码
五、驱动编译与安装
六. 总结



一、前言

    前段时间,在安全焦点上看到了TOo2y朋友写的《基于SPI的数据报过滤原理与实现》,很是不错。文章中提到的基于SPI的数据报拦截技术是在用户级的。用户级的拦截有其优势,实现方便、便于移植、通用性强,但是,用户级并不能得到所有的数据报。本文提到的基于IMD的数据报过滤则是属于内核级的,它建立在网络驱动上面。
    其实两个月前就想写这篇文章了,可惜这个技术是我一年前做的,好久不用,已经忘的差不多了,所以一直没有写。不过,近来正巧有个课题,牵扯到了中间层驱动。于是,重新拾起丢了有一年的DDK,啃了起来。这期间,真的要非常感谢linxder的帮忙,让我少走了一些弯路,否则,我真的要从头学起了。废话不多说了,切入正题。
    


二、中间层驱动技术介绍

    中间层驱动,英文为NDIS intermediate driver。

    1)内核级网络驱动介绍
        Microsoft Windows 2000支持三种基本的内核级网络驱动,这三层driver顺序从下到上依次为:
        1. Miniport NIC drivers:微端口网卡驱动,位于最底层,直接操纵网卡并且对高层驱动提供接口。
        2. Intermediate drivers:IMD中间层驱动,这就是今天的主角,位于1和3之间,具体的作用下面就会介绍。
        3. Protocol drivers:高层协议驱动,俗称为TDI(传输驱动程序接口),高于前面两层,直接面向用户级,
                     为用户提供网络服务,也就是绝大多数程序所用到的网络接口。

    
    2)IMD驱动            
    IMD中间层,它的实质很简单,最经典的描述莫过于下面的话:
    
    An intermediate driver is typically layered over one or more NDIS NIC drivers and under a transport driver (possibly multilayered) that supports TDI at its upper edge.
    An NDIS intermediate driver exports MiniportXxx functions at its upper edge and ProtocolXxx functions at its lower edge.(见DDK文档)
    
    中间层插入网卡和协议层之间,对上面的协议层表现为一个虚拟的微端口网卡结构,而对下面的网卡则表现为一个协议层的结构。所以,无论是网卡接收并上传的数据报,还是上层要下送至网卡发送的数据报,无一例外地要经过中间层。
    

    3)IMD包过滤技术
    前面我们已经看到,所有的数据报都要经过中间层,所以,我们可以在中间层加入我们想要过滤的数据报的特征,实现基于中间层驱动的内核级包过滤。
    
    这样做的优势非常明显,首先,在驱动级别上做过滤,无须组包,速度快,效率自然就高;其次,所有的数据报无一例外,只要网卡上传的数据报均可以截获,避免了用户级无法得到所有数据报的缺点。当然,世界上没有完美的事情。IMD包过滤技术也存在其不可避免的缺点,与操作系统版本关系密切,与硬件联系大,可移植性低。我在调试这个驱动的时候,就碰到了无数次蓝屏,无数次重启动,进了几次安全模式,甚至还为此重新安装了一次系统。
    
    正是由于上面的一些问题,现在市面上还没有见到有厂家推出基于IMD的实用型防火墙,大部分都是在实验室中的作品,或许真的是要做到通用性很难吧,不过还是希望能尽快见到这样的产品面世。
    
    
    
三、passthru代码分析
    
    到这里,你或许已经非常想看看到底怎么来实现基于IMD的包过滤防火墙了,不过,你肯定会迟疑,如果让我们自己写整个中间层驱动的话,是不是有些太艰难了啊?况且,我只是个搞网络安全的,我不是专门写驱动的,让我完成一个驱动程序,还要对上层协议伪装成一个网卡,对下层伪装成一个协议层,这不是要命么?
    
    呵呵,其实微软很不错的,在提出这项技术之后,其DDK中附带了一个中间层驱动的例程,就是passthru。passthru实现了一个中间层的基本功能,对下表现为一个协议层的驱动,对上表现为一个虚拟网卡,安装passthru驱动之后,你可以在硬件管理中的网卡中看到一个虚拟网卡。不过,passthru只是插入到网卡和上层协议中间,却未做任何工作,也就是说,passthru只是让所有的数据报原原本本地流经自己而已。我们要想实现中间层包过滤的功能,需要对passthru进行修改。
    
    想想我们要实现的包过滤的功能,我们只需要在中间层接收到数据报的时候进行规则判断就可以了,而在passthru中,接收数据报是用protocol.c文件中的PtReceive和PtReceivePacket这两个函数来实现的。根据微软的解释,微软建议接收包用PtReceivePacket函数,因为可以得到更高的效率,然而,为了向下兼容,也保留了PtReceive函数给老的网卡使用。所以,在一块网卡上,只可能有一个函数在工作,这要取决于你的网卡型号了。巧的是,我的两台机器的网卡应用的函数正巧不一样。同样是IBM的机器,一台P4 1.5G的机器的网卡是Realtek RTL8139(A) PCI Fast Ethernet Adapter,另外一台P4 2.0G的机器的网卡是Intel(R) PRO/100 VE Network Connection,其中Realtek网卡用的是PtReceive来接包,而Intel的网卡是用PtReceivePacket来接包。
    
    现在我们知道了哪个函数负责接收数据报,那么我们就可以对这个函数进行修改了。从兼容和通用性考虑,我们需要对PtReceive和PtReceivePacket函数进行修改,其中加上我们需要判断的规则进行过滤,下面就贴详细的代码了。
    
    
    
四、部分演示代码

    我们的目的是在调用接受数据报函数的时候能执行我们的过滤代码,所以,我们要在函数代码中添加我们自己的代码,下面用过滤特定协议类型的数据报来做演示。
    
    首先修改PtReceive,看一下protocol.c文件中函数的代码,代码中用NdisGetReceivedPacket函数得到一个PNDIS_PACKET的结构Packet,数据报内容就存放在这个结构中的链表内。我们定义一个PUCHAR结构的pPacketContent,然后用下面的代码获得整个数据报的内容:
    
        //---------------------------------------------------------
        int        PacketSize;
    PUCHAR        pPacketContent;
    PUCHAR        pBuf;
    UINT         BufLength;
    MDL    *     pNext;
    UINT         i;
    
    //把数据包内容从Packet拷贝到pPacketContent

    NdisQueryPacket( Packet,NULL,NULL,NULL,&PacketSize);
    
    Status= NdisAllocateMemory( &pPacketContent, 2000, 0,HighestAcceptableMax);
    if (Status!=NDIS_STATUS_SUCCESS ) return Status;
    NdisZeroMemory (pPacketContent, 2000);
    
    NdisQueryBufferSafe(Packet->Private.Head, &pBuf, &BufLength, 32 );
    NdisMoveMemory(pPacketContent, pBuf, BufLength);

    i = BufLength;
    pNext = Packet->Private.Head;
    
    for(;;)
    {
        if(pNext == Packet->Private.Tail)
            break;
            pNext = pNext->Next;   //指针后移
            if(pNext == NULL)
                break;

            NdisQueryBufferSafe(pNext,&pBuf,&BufLength,32);
            NdisMoveMemory(pPacketContent+i,pBuf,BufLength);
            i+=BufLength;
    }
    
    //数据拷贝完毕
    //---------------------------------------------------------
    
    
    现在,我们已经在PtReceive函数中得到了数据报的内容,存放在pPacketContent中,数据报的格式你可以去查书。通常,在以太网中,得到的数据报大致是如下结构,以太帧头14个字节,放在pPacketContent[0]到pPacketContent[13]中,其中前六个字节是目的MAC地址,然后六个字节源MAC地址,然后两个字节是协议类型,通常的协议类型有0x08 0x00 ->IP,0x08 0x06 ->ARP,0x08 0x35 ->RARP,所以,可以通过pPacketContent[12]和pPacketContent[13]来判断协议类型。如果是IP包,然后pPacketContent中存放的是IP头,根据IP头的格式,可以得到第23个字节pPacketContent[23]表示传输层协议:1 ->ICMP,2 ->IGMP,6 ->TCP,17 ->UDP,剩下的就是数据报内容了。因为我们只是做演示,所以只要知道这几个标志性的就好了,其他的你可以根据你的需要扩展。我们通过pPacketContent中的内容可以做些规则,比如过滤ICMP包,我们只要比较pPacketContent[12]和pPacketContent[13]还有pPacketContent[23]这三个标志位就可以了,如果不是ICMP包,那么不做任何工作,如果匹配了,那就返回一个NDIS_STATUS_NOT_ACCEPTED,将包丢弃,释放pPacketContent,就可以过滤ICMP包了,下面就是过滤规则的代码。
    
        //---------------------------------------------------------
        //规则标志位(1表示过滤,0表示放行,你可以通过改这个数值来配置规则)
    UINT        ICMP = 1;     //ICMP数据报规则
    UINT        IGMP = 0;    //IGMP数据报规则
    UINT        TCP = 0;    //TCP数据报规则
    UINT        UDP = 0;    //UDP数据报规则
    
        //规则判断
    if (ICMP == 1)
    {
        if(((char *)pPacketContent)[12] == 8 &&
            ((char *)pPacketContent)[13] == 0 &&
                ((char *)pPacketContent)[23] == 1)
        {
            DbgPrint("ICMP被拦截!\n");
            NdisFreeMemory(pPacketContent, 2000, 0);
            return NDIS_STATUS_NOT_ACCEPTED;
        }
    }
    
    if (IGMP == 1)
    {
        if(((char *)pPacketContent)[12] == 8 &&
            ((char *)pPacketContent)[13] == 0 &&
                ((char *)pPacketContent)[23] == 2)
        {
            DbgPrint("IGMP被拦截!\n");
            NdisFreeMemory(pPacketContent, 2000, 0);
            return NDIS_STATUS_NOT_ACCEPTED;
        }
    }
    
    if (TCP == 1)
    {
        if(((char *)pPacketContent)[12] == 8 &&
            ((char *)pPacketContent)[13] == 0 &&
                ((char *)pPacketContent)[23] == 6)
        {
            DbgPrint("TCP被拦截!\n");
            NdisFreeMemory(pPacketContent, 2000, 0);
            return NDIS_STATUS_NOT_ACCEPTED;
        }
    }
    
    if (UDP == 1)
    {
        if(((char *)pPacketContent)[12] == 8 &&
            ((char *)pPacketContent)[13] == 0 &&
                ((char *)pPacketContent)[23] == 17)
        {
            DbgPrint("UDP被拦截!\n");
            NdisFreeMemory(pPacketContent, 2000, 0);
            return NDIS_STATUS_NOT_ACCEPTED;
        }
    }

    //规则判断结束
    //---------------------------------------------------------        

    
    到这里,PtReceive函数已经修改完了,只要调用PtReceive函数接收数据报的时候,就可以执行我们的规则了,下面修改PtReceivePacket函数,其实上面的修改代码内容都是一样的,只不过PtReceivePacket函数跟PtReceive函数不太一样,PtReceivePacket直接在入口参数中就得到了PNDIS_PACKET的结构Packet,存放了数据报的所有内容,所以,直接将上面的代码粘到函数PtReceivePacket的代码中就可以了。到现在,无论是网卡调用哪一个接收函数,都可以执行我们需要的规则。
    
    其实,上面所定义的规则是很简单的,因为只作为演示用,而我的课题嘛,嘿嘿,就不是那么简单了。其实在pPacketContent已经得到了所有的数据报内容,我们可以随意扩展规则。比如,过滤指定IP、指定端口的数据报,至于具体应该设置哪个位置,你只要去找一本介绍数据报结构的书看一下就知道了,呵呵。
    
    
    
五、驱动编译与安装

    前面谈了那么多,其实都是在说IMD包过滤的实现和驱动代码,但是,我已经修改了代码,怎么编译和安装呢?
    
    这一部分就解决驱动编译和安装的问题。我们用passthru的代码,对接收数据报的部分做了修改。然后,我们用DDK自带的builder工具来编译。我一般是用开始菜单中DDK程序组中的Free Build Environment,到passthru目录下执行build -cz来编译passthru,得到passthru.sys文件,然后再到NTDDK\src\network\config\filter目录下,执行build -cz来得到sfilter.dll,然后再加上passthru目录下的netsf.inf和netsf_m.inf,一共四个文件。这样,驱动安装所需要的文件就全了。
    
    打开网络属性,添加服务,找到passthru目录下,安装,弹出没有数字签名的警告,不理,继续安装,最后,你会发现,网络属性中增加了一个名为Sample Filter的组件,同时,硬件管理器中的网卡下增加了一个Sample Filter Miniport的设备。如果你已经到了这里,并且系统没有出现蓝屏和死机,那么恭喜你,你已经成功地安装上了中间层驱动,并且已经发挥包过滤作用了。
    
    
    
六. 总结

    难得我写了那么多,现在做一个总结吧。上文中的代码,我只是用来做演示的,只用来说明基于IMD的包过滤防火墙原理与实现,其实需要做的工作还有很多,驱动上面碰到的问题会很多,并且常常伴随着的是蓝屏,死机,甚至要重装系统。
    
    你也许会问,那我每次改一下规则难道还要重新再安装一遍驱动么,况且,必须重启动一次,旧的驱动才彻底卸载掉,多麻烦啊。呵呵,其实是中间层驱动是可以跟应用层的程序结合的。首先你要在驱动中指定好规则,应用层的程序通过DeviceIoControl传递指令到驱动中,可以控制驱动的规则标志位。
    
    特别推荐驱动开发网(www.driverdevelop.com)论坛的ndis网络接口开发版,这里是国内水平最高的地方,所有的与驱动有关的问题你都可以在那里得到解决。
    
    最后,附带说一句,调试驱动的时候先做好处理系统后事的准备,对于出现的任何系统问题也好,硬盘问题也好,我不负任何责任,呵呵。
    
    欢迎访问我们团队的站点:711网络安全小组  http://www.cpyy.net

我来说两句】 【发送给朋友】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 基于IMD的包过滤防火墙原理与实现

 ■ [欢迎对本文发表评论]
用  户:  匿名发出:
您要为您所发的言论的后果负责,故请各位遵纪守法并注意语言文明。

最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放 / 友情链接  
Copyright ©2001-2006 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00203