• 首页
  • 小学语文
  • 中学语文
  • 中学英语
  • 免费论文
  • 教学随笔
  • 学生作文
  • 综合考试
  • 试题教案
  • 育儿话题
  • 教学资源
  • 编程技术
  • 博客
  • sniffer技术原理及应用,包括编程方法和工具使用

    日期:2003-02-18  地址:  作者:

    首先,我今天来是做广告的哦:)
    很久没有更新专栏了,关键是写不出什么好东西,也怕大家见笑!
    虽然我还没被人骂过,但我见过别人被人骂,哎。不是说,这在csdn好像很正常哈!
    今天把这个贴子整理一下,这本是专题开发版的一个专题讨论贴:http://expert.csdn.net/Expert/topic/2333/2333459.xml?temp=.3382532,其实这个贴子也没有挖出更深入的东西,关键是专题版目前人气不太好吧。我发这个贴是希望更多的人能到专题版,参与和组织讨论,但结果并不是太理想。

    kingzai:
    sniffer中文翻译过来就是嗅探器,在当前网络技术中使用得非常得广泛。sniffer既可以做为网络故

    障的诊断工具,也可以作为黑客嗅探和监听的工具。最近两年,网络监听(sniffer)技术出现了新的

    重要特征。传统的sniffer技术是被动地监听网络通信、用户名和口令。而新的sniffer技术出现了主

    动地控制通信数据的特点,把sniffer技术扩展到了一个新的领域。Sniffer 技术除了目前在传统的

    网络侦测管理外,也开始被应用在资讯保全的领域。可以这样说,sniffer技术是一把双刃剑,如何

    更好的利用它,了解它的一些特性,将能使这项技术更好的为我们带来便利。
      sniffer的编程方法比较通用的有以下几种,1.winpcap 这是一个比较通用的库,相信做过抓包的

    工具大多数人都不会太陌生 2.raw socket 在2000以后的版本都支持此项功能,2000 server有

    个网络监视器就是基于raw socket 3.tdi,ndis,spi,hook socket技术,这种技术比较大的不同是

    ,可以将包截取而不是仅仅获得包的一份拷贝
    。总的说来,一般以前两者居多。
      我这里提的都还比较片面,更多的需要大家来补充。我办这个专题的目的是希望大家共同来了解

    ,讨论sniffer技术,让更多的人参与进来,让大家知道,这个板块能够给大家带来真正想要的东西


    warton:
    libpcap是个好东西,linux,windows下都能用,很多入侵检测之类的安全系统都是以这为核心。不

    过我一直没用过它,不知道它的跨平台性如何?
    要用spi的话,看看xfilter的代码和书,特别是那本书上讲得不错,可惜一直没用它做出什么东西来


    raw socket写的sniffer比较多,网上代码也很多!
    昨天见csdn首页有几篇关于sniffer的文章,保存了,还没来得及看...
    俺明天来说说目前常用的sniffer类工具和它们的技术实现!

    csdn首页的两篇文章,大家可以看看,里面好像还有几篇,暂时找不到了
    http://www.csdn.net/develop/article/21/21363.shtm
    http://www.csdn.net/develop/article/21/21352.shtm
    http://www.csdn.net/develop/article/15/15919.shtm

    netsys2:
     
    一)winpcap驱动简介
        winpcap(windows packet capture)是windows平台下一个免费,公共的网络访问系统。开

    发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。它提供了以下的各项

    功能:
        1> 捕获原始数据报,包括在共享网络上各主机发送/接收的以及相互之间交换的数据报;
        2> 在数据报发往应用程序之前,按照自定义的规则将某些特殊的数据报过滤掉;
        3> 在网络上发送原始的数据报;
        4> 收集网络通信过程中的统计信息。

       

    winpcap的主要功能在于独立于主机协议(如TCP-IP)而发送和接收原始数据报。也就是说,winp

    cap不能阻塞,过滤或控制其他应用程序数据报的发收,它仅仅只是监听共享网络上传送的数据报

    。因此,它不能用于QoS调度程序或个人防火墙。

        目前,winpcap开发的主要对象是windows NT/2000/XP,这主要是因为在使用winpcap的

    用户中只有一小部分是仅使用windows 95/98/Me,并且M$也已经放弃了对win9x的开发。因

    此本文相关的程序T-ARP也是面向NT/2000/XP用户的。其实winpcap中的面向9x系统的概念和

    NT系统的非常相似,只是在某些实现上有点差异,比如说9x只支持ANSI编码,而NT系统则提倡使

    用Unicode编码。

     zzhong2:
    有个软件叫sniffer pro.可以作网管软件用,有很多功能,可监视网络运行情况,每台网内机器的数据

    流量,实时反映每台机器所访问IP以及它们之间的数据流通情况,可以抓包,可对过滤器进行设置,以便

    只抓取想要的包,比如POP3包,smtp包,ftp包等,并可从中找到邮箱用户名和密码,还有ftp用户名和

    密码.它还可以在使用交换机的网络上监听,不过要在交换机上装它的一个软件.
    还有一个简单的监听软件叫 Passwordsniffer,可截获邮箱用户名和密码,还有ftp用户名和密码,它

    只能用在用HUB网络上
    以上两个软件都可在小凤居上下载到:http://www.chinesehack.org/


    warton:
    libpcap的最新版本是0.7.2,下载很多(基于linux/unix)
    winpcap的最新版本是3.0
    这里有winpcap的源代码:http://download.pchome.net/php/dl.php?sid=11474
    著名软件tcpdump及ids snort都是基于libpcap编写的,此外Nmap扫描器也是基于libpcap来捕

    获目标主机返回的数据包的。
    winpcap提供给用户两个不同级别的编程接口:一个基于libpcap的wpcap.dl,另一个是较底层的

    packet.dll。对于一般的要与unix平台上libpcap兼容的开发来说,使用pacap.dll是当然的选择


    下面几个库是与lipcap相关的:
    libnet1.0.2:数据包的发送个构造过程
    libnids:实现了ids的一些 框架
    libicmp:icmp数据包处理

     


    一些著名的嗅探器:
    tcpdump/windump:支持多种unix,后者支持windows。基于libpcap
    Sniffit:unix,windows,libpcap
    Ngrep:libpcap,unixwindows.可以用规则表达式,识别PPP,SLIP及FDDI数据包
    Sniffer pro/NetXray:专业的协议分析工具,是NAI提供的网络分析方案中的一部分
    其它:
    Iris
    LanExplorer
    NetMOnitor
    CommView

    单一用途的噢探器
    口令嗅:winsniffer,典型的黑客工具,嗅探并解析ftp,pop3,http,icq,smtp,telnet,IMAP,NNTP

    等口令
    password sniffer for NetHackerIII

    专用 嗅探器:
    SMB嗅探器:L0phtcrack,SMPRelay
    TCP连接会话嗅探器:CommView ,Iris,Juggernaut
    SSL嗅探器:SSLDump--sslv3/tls网络协议分析工具
    RIDIUS嗅控器:一个基于udp的论证记账协议,Radiusniff是其代表
    PPTP嗅 控器:Anger,PPTP-sniff(solaris)
    SNMP嗅探器:Snmpsniff

    交换网络嗅探器:Ettercap
    综合:Dsniff
    其它交换网络嗅探器:
    snarp,parasite

    嗅探对策.........

    netsys2:

    网络上流传的GUNIFFER是个基本的原型:

    http://asp.6to23.com/nowcan/code/guniffer.zip

    void main(int argc, char ** argv)

    {

    int iErrorCode;

    char RecvBuf[MAX_PACK_LEN] = {0};

    usage();

    if(GetCmdLine(argc, argv)==CMD_PARAM_HELP) exit(0);

    //初始化SOCKET

    WSADATA wsaData;

    iErrorCode = WSAStartup(MAKEWORD(2,1),&wsaData);

    CheckSockError(iErrorCode, "WSAStartup");

    SockRaw = socket(AF_INET , SOCK_RAW , IPPROTO_IP);

    CheckSockError(SockRaw, "socket");

    //获取本机IP地址

    char FAR name[MAX_HOSTNAME_LAN];

    iErrorCode = gethostname(name, MAX_HOSTNAME_LAN);

    CheckSockError(iErrorCode, "gethostname");

    struct hostent FAR * pHostent; //注意下面这三句,这里先对pHostent分配了一块

    pHostent = (struct hostent * )malloc(sizeof(struct hostent));

    //内存,然后有让它等于gethostbyname函数的返回

    pHostent = gethostbyname(name); //值,但gethostbyname函数是自己在函数内部分配内

    存的,因此上一句根本就是多余,把上一句删除后一切正常。但此程序用VC6编译运行都没有问题

    ,不知为何?也许是VC6的编译器优化在起作用。

    SOCKADDR_IN sa;

    sa.sin_family = AF_INET;

    sa.sin_port = htons(6000);

    memcpy(&sa.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length);

    free(pHostent); //由于前面分配内存的语句已经删除,所以这一句也要去掉,否则出错。感谢网

    友 Heyuming 发现这个问题。

    iErrorCode = bind(SockRaw, (PSOCKADDR)&sa, sizeof(sa));

    CheckSockError(iErrorCode, "bind");

    //设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包

    DWORD dwBufferLen[10] ;

    DWORD dwBufferInLen = 1 ;

    DWORD dwBytesReturned = 0 ;

    iErrorCode=WSAIoctl(SockRaw, SIO_RCVALL,&dwBufferInLen,

    sizeof(dwBufferInLen),

    &dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );

    CheckSockError(iErrorCode, "Ioctl");

    //侦听IP报文

    while(1)

    {

    memset(RecvBuf, 0, sizeof(RecvBuf));

    iErrorCode = recv(SockRaw, RecvBuf, sizeof(RecvBuf), 0);

    CheckSockError(iErrorCode, "recv");

    iErrorCode = DecodeIpPack(RecvBuf, iErrorCode);

    CheckSockError(iErrorCode, "Decode");

    }

    }

    它有2个不方便之处:
    1)不能选择网卡
    2)采用死循环方式读数据,改编到WINDOWS窗口模式下时有死机的感觉。

    sevencat():
    上次找了一些资料整理了一下,不过人气不旺,而且最近比较忙,暂时还没继续下去。
    http://expert.csdn.net/Expert/topic/2299/2299615.xml?temp=.2761499
    WINDOWS网络包过滤技术
                                  (原文:http://www.ndis.com/papers/winpktfilter.htm
    一、user-mode网络包过滤
    1、winsock分层service provider
    参照Microsoft Platform SDK上有关文档和例子
    http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
    这里有好几个microsoft lsp 例子,最新(可能最bug-free)的经常在这里能找到。需要知道的是

    可以通过TDI调用核心TCPIP驱动,而且可以完全绕开WINSOCK,在大多数情况下这不是一个问

    题。例如:QOS的实现可以在WINSOCK LSP上。
    然而,这样做的话,程序必须察看和操作每个包,而不能依靠WINSOCK LSP,他们要以一种接

    近核心态的方法来实现。
    2、win2000包过滤接口
      WIN2000包过滤接口提供了一种机制,这种机制允许用户态程序或者服务指定一系列的"过滤

    原则",这些过滤原则会被低层的TCPIP实现用来过滤包。这种过滤工主要是对IP原地址、目标地址

    、端口号(或者端口号范围)进行pass或者drop操作。
    Windows Developer's Journal
    《用iphlpapi.dll进行包过滤》作者:Ton plooy,October,2000,Volume 11, Number 10。
      WIN2000提供了一个较好对TCPIP的可编程控制,其中包括包过滤。不幸的是,有关这个新

    的API的文档并不是很容易能找到。这篇文章向你演示了怎样对特定IP地址或者特定TCP端口的包

    进行阻塞的编程。
    链接:www.wdj.com
    上面这个例子的下载:ftp://ftp.wdj.com/pub/webzip/1110/plooy.zip
    Hollis 的解决方案:
      HTS W2K IpHook例子演示了IP过滤和它的HOOK API,包含原文件,而且是免费的,

    需要HtsCpp运行时库(免费),下载地址:http://www.hollistech.com/
    3、winsock替代DLL
      在使用WINSOCK LSP之前,唯一的办法是用自己的DLL取代微软的WINSOCK DLL,假

    如实现顺利的话,自己的DLL会接收用户的WINSOCK调用请求,然后还可以调用原来的WINSOC

    K DLL来处理。
      不过这样的实现是比较费力的,其中有个困难就是微软的WINSOCK DLL里面经常有一些未

    公开的内部使用的函数,一个WINSOCK代替DLL至少要处理其中的一些未公开函数。
      随着WINDOWS系统结构的变化,有些方面得到了加强,比如系统文件保护,这使得这种技术

    变得不太可行。总的说来,使用WINSOCK DLL替换不是一个坏主意。(Xfilter就是用的这种技

    术,原代码可能在网上有流传,我以前看到过的)
    二、kernel-mode网络包过滤
    1、Transport Data Interface (TDI)
      这主要是一个直接在核心TCPIP驱动上面的一层过滤驱动。在WINXP上TDI驱动是一种传统的

    NT风格的驱动,使用了基于IRP的API,这里有两种方法来实现。
    A、使用核心模式服务的IoAttachDeviceXYZ函数族在TDI上实现一个过滤。
    B、对TDI驱动IRP DISPATCH表进行过滤。
      IoAttachDeviceXYZ函数在许多WINNT驱动开发的书上提到。这两种技术都需要对WINNT驱

    动开发编程技术十分了解,对TDI函数也要相当的了解。
    2、NDIS中间层(IM)
    具体请看NDIS IM FAQ:http://www.pcausa.com/resources/ndisimfaq.htm
    3、WIN2000 FILTER-HOOK
      请参照有关DDK文档,系统中只能有一个活动的Filter-Hook存在,这点使这种技术的使用有

    严重的限制。(平时所见的drvipflt就是用的这个)
    4、WIN2000 FIREWALL-HOOK 
      Firewall-Hook Driver函数在文档里介绍得很少,而且在有些win2000版本中不可用。请参

    照微软有关文档:http://msdn.microsoft.com/library/default.asp?url=/library/en-us

    /network/hh/network/firewall_3wfb.asp
    5、NDIS-HOOKING  (费尔防火墙就是用的这种技术吧,据我所知,虽然我没看过原码。)
    NDIS-Hooking驱动拦截或者叫"HOOK"一些由NDIS封装程序导出的函数。虽然从实现手段上来

    说有些不正规,但一个有系统的NDIS-Hooking过滤会非常有效。
    另外:NDIS-Hooking过滤驱动有下面的好处:
    A、容易安装(可以动态装卸,不过有时候会出问题,里面有些情况现在还未知。)
    B、支持拨号-ppp适配器。
      Ndis-Hooking技术在98和ME系统下非常有效和实用。在这些平台上,DDK文档和provide

    d services都能很有用的帮你HOOK由Ndis wrapper导出的函数。
      Ndis-Hooking技术在NT,2000和XP上同样有效和实用。这种技术很像核心模式的调试器。

    文档支持较少,而且基本上不会被WHQL认证。
    PCAUSA提供了一套NDIS PIM驱动例子,这些例子能在现有的WIN平台上运行成功(从95到X

    P)。地址:http://www.pcausa.com/ndispim/Default.htm

    其他:
    Network操作和进程信息:
      有许多人想知道网络上的操作和WIN进程(就是应用程序啦)之间怎样联系起来,举例来说,

    可能会想知道是哪个进程在一个特定的IP端口上发送或接收数据。
      先不考虑这种技术是否有用,或者是否可靠,我们认为核心模式TCPIP驱动上层的过滤程序可

    以处理这个问题。而TCPIP驱动下层的过滤程序根本看不到进程信息。特别要注意的是有些网络服

    务操作生成一个新的进程attach到系统进程上的。在这种情况下进程信息并不能告诉我们原先是哪

    个进程生成的。特别是单独在核心模式下的WIN服务(TDI客户)
      最后,有必要看看下面的资料United States Patent 5,987,611; "System and

    methodology for managing internet access on a per application basis for client

    computers connected to the internet "
      我们并不知道这项专利的价值,也不知道他是否能用在包过滤上。详情请参阅:http://www.

    uspto.gov/patft/index.html
    www.pcausa.com

    ============================================
    drvipflt具体解析,就是上面所提到的吧(2-3就是说的这东东)。
    假定大家对驱动框架已经有了一定的理解。IRP分配程序如下:
    NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
    ...
       switch (irpStack->MajorFunction)
        {
    ...
        case IRP_MJ_DEVICE_CONTROL:
            ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

            switch (ioControlCode)
            {
       // ioctl code to start filtering
       //这里可以从用户模式程序发送这样的请求。
       //直接用DeviceIoControl这个函数,就像下面这样调用就可

    以了吧,我想。
       

    //DeviceIoControl(drivehandle,START_IP_HOOK,NULL,0,NULL,0,&bytereturned,NU

    LL)
       case START_IP_HOOK:
       {
       //这个应该是最主要的函数了。
                 SetFilterFunction(cbFilterFunction);

        break;
       }

       // ioctl to stop filtering
       case STOP_IP_HOOK:
       {
        SetFilterFunction(NULL);
                
        break;
       }

                // ioctl to add a filter rule
       case ADD_FILTER:
       {
        if(inputBufferLength == sizeof(IPFilter))
        {
         IPFilter *nf;

         nf = (IPFilter *)ioBuffer;
         
         AddFilterToList(nf);
        }

        break;
       }

       // ioctl to free filter rule list
       case CLEAR_FILTER:
       {
        ClearFilterList();

        break;
       }

       default:
        Irp->IoStatus.Status =

    STATUS_INVALID_PARAMETER;


        break;
            }

            break;
    ...
    }
    SetFilterFunction(cbFilterFunction)可能是最重要的一个程序了。具体如下:
    实际上这个做法相当在系统中注册了一个回调函数。
    NTSTATUS SetFilterFunction(PacketFilterExtensionPtr filterFunction)
    {
     NTSTATUS status = STATUS_SUCCESS, waitStatus=STATUS_SUCCESS;
     UNICODE_STRING filterName;
     PDEVICE_OBJECT ipDeviceObject=NULL;
     PFILE_OBJECT ipFileObject=NULL;

     PF_SET_EXTENSION_HOOK_INFO filterData;

     KEVENT event;
     IO_STATUS_BLOCK ioStatus;
     PIRP irp;

     //首先获得一个设备指针。
     //first of all, we have to get a pointer to IpFilterDriver Device
     RtlInitUnicodeString(&filterName, DD_IPFLTRDRVR_DEVICE_NAME);
     status = IoGetDeviceObjectPointer(&filterName,STANDARD_RIGHTS_ALL,

    &ipFileObject, &ipDeviceObject);
     if(NT_SUCCESS(status))
     {
     //一些初始化工作,填充filterData。
      //initialize the struct with functions parameters
      filterData.ExtensionPointer = filterFunction;

      //we need initialize the event used later by the IpFilterDriver to

    signal us
      //when it finished its work
      KeInitializeEvent(&event, NotificationEvent, FALSE);

    //这个就是最重要的注册回调函数过程。DDK中具体讲述是这样的
    //IOCTL_PF_SET_EXTENSION_POINTER registers filter-hook callback functions to

    the IP filter driver
    //to inform the IP filter driver to call those filter hook callbacks for every IP packet
    //that is received or transmitted. Also, IOCTL_PF_SET_EXTENSION_POINTER

    clears filter-hook
    //callback functions from the IP filter driver. (看到了吧,最后一句话,注册新的回调函

    数,就将原先的清除掉了,
    //所以说系统中只存在一个这样的驱动有用。)
      //we build the irp needed to establish fitler function这个地方仅

    仅是生成这样的IRP,并没有注册
      irp =

    IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER,
               

         ipDeviceObject,
             

      (PVOID) &filterData,
             

      sizeof(PF_SET_EXTENSION_HOOK_INFO),
             

      NULL,
             

      0,
             

      FALSE,
             

      &event,
             

      &ioStatus);


      if(irp != NULL)
      {
       // we send the IRP
       //这个地方才是真正的注册呀。
       status = IoCallDriver(ipDeviceObject, irp);

       //and finally, we wait for "acknowledge" of

    IpDriverFilter
       if (status == STATUS_PENDING)
       {
        waitStatus = KeWaitForSingleObject(&event,

    Executive, KernelMode, FALSE, NULL);

        if (waitStatus  != STATUS_SUCCESS )

    {}
       }

       status = ioStatus.Status;

       if(!NT_SUCCESS(status)){}
      }
      
      else
      {
       //if we cant allocate the space, we return the

    corresponding code error
       status = STATUS_INSUFFICIENT_RESOURCES;

      }

      if(ipFileObject != NULL)
       ObDereferenceObject(ipFileObject);
      
      ipFileObject = NULL;
      ipDeviceObject = NULL;
     }
     
     else
     
     return status;
    }
    //真正的过滤函数是这个,在最早的IRPdispatch里面传递的这个函数。
    //这个函数就是系统传递了一个包头和包内容和包长度之类的东西,你可以在里面进行一些处理,
    //假如你想让这个包通过的话,就返回PF_FORWARD,或者你不想让包通过的话,就返回PF_D

    ROP就拦住了。是不是
    //听起来很简单,
    PF_FORWARD_ACTION cbFilterFunction(IN unsigned char *PacketHeader,IN

    unsigned char *Packet, IN unsigned int PacketLength, IN unsigned int

    RecvInterfaceIndex, IN unsigned int SendInterfaceIndex, IN unsigned long

    RecvLinkNextHop, IN unsigned long SendLinkNextHop)
    {
     IPPacket *ipp;
     TCPHeader *tcph;
     UDPHeader *udph;

     int countRule=0;

     struct filterList *aux = first;

     //we "extract" the ip Header
     ipp=(IPPacket *)PacketHeader;

    // dprintf("Source: %xDestination: %xProtocol: %d", ipp->ipSource,

    ipp->ipDestination, ipp->ipProtocol);
     
     //TCP -> protocol = 6
     //we accept all packets of established connections
     if(ipp->ipProtocol == 6)
     {
      tcph=(TCPHeader *)Packet;

    //  dprintf("FLAGS: %x", tcph->flags);
      
      //if we havent the bit SYN activate, we pass the packets
      if(!(tcph->flags & 0x02))
       return PF_FORWARD;
     }

     //otherwise, we compare the packet with our rules
     while(aux != NULL)
     {
    //  dprintf("Comparing with Rule %d", countRule);

      //if protocol is the same....
      if(aux->ipf.protocol == 0 || ipp->ipProtocol ==

    aux->ipf.protocol)
      {
       //we look in source Address
       if(aux->ipf.sourceIp != 0 && (ipp->ipSource &

    aux->ipf.sourceMask) != aux->ipf.sourceIp)
       {
        aux=aux->next;
       
        countRule++;
        continue;
       }
             
       // we look in destination address
       if(aux->ipf.destinationIp != 0 && (ipp->ipDestination

    & aux->ipf.destinationMask) != aux->ipf.destinationIp)
       {
        aux=aux->next;

        countRule++;
        continue;
       }
       
       //if we have a tcp packet, we look in ports
       //tcp, protocol = 6
       if(ipp->ipProtocol == 6)
       {
        if(aux->ipf.sourcePort == 0 ||

    tcph->sourcePort == aux->ipf.sourcePort)
        {
         if(aux->ipf.destinationPort == 0

    || tcph->destinationPort == aux->ipf.destinationPort) //puerto tcp destino
         {
          //now we decided what

    to do with the packet
          if(aux->ipf.drop)
            

    return  PF_DROP;
           else
            

    return PF_FORWARD;
         }
        }
       }
        
       //udp, protocol = 17
       else if(ipp->ipProtocol == 17)
       {
        udph=(UDPHeader *)Packet;

        if(aux->ipf.sourcePort == 0 ||

    udph->sourcePort == aux->ipf.sourcePort)
        {
         if(aux->ipf.destinationPort == 0

    || udph->destinationPort == aux->ipf.destinationPort)
         {
          //now we decided what

    to do with the packet
          if(aux->ipf.drop)
           return 

    PF_DROP;
          
          else
           return

    PF_FORWARD;
         }
        }
       } 
       
       else
       {
        //for other packet we dont look more and

    ....
        //now we decided what to do with the

    packet
        if(aux->ipf.drop)
         return  PF_DROP;
        else
         return PF_FORWARD;
       } 
      }
      
      //compare with the next rule
      countRule++;
      aux=aux->next;
     }

     //we accept all not registered
     return PF_FORWARD;
    }

    winpcap也是用的NDIS,将自己注册为一个协议处理驱动。(在原代码的driverentry里面能看到)

    又:上面这个drvipflt这个代码的过滤部分不知道大家是不是看起来很熟悉,是的,是抄的那个nu

    mege的驱动开发包里面的一个包过滤程序里的,看来老外也是喜欢到处抄的。

    ruike:
    读研的时候专门搞过nids,因此对winpcap可以说是情有独钟,这个东东确实好用,但也确实很烦

    人,它有一个致命的缺陷就是只适用于共享式以太网络,对于交换式网络下的数据则无能为力,我

    专门做过测试,在使用交换机连接的局域网下,只能监听到本网段内的数据,而对于来自其他网段

    的数据则无法监听,除非你把probe接到交换机之前或者接到交换机的console口上,不过那样的

    弊端是显而易见的。
    所以,winpcap的应用还是很有局限性的!

    kingzai:
    实现交换网络的嗅探也有不少方法的
    1.将你的抓包程序放在网关或代理服务器上,这样抓到整个局域网的包。
    2.对交换机实行端口映射,将该端口的数据包全部映射到某个监控机器上。
    3.在交换机和路由器之间连接一个HUB,这样数据将以广播的方式发送。
    4.实行ARP欺骗,即在你的机器上实现整个包的转发,不过会降低整个局域网的效率。

    warton:
    嗅探对策:
    光说嗅探了,我说说反嗅探吧:)
    1.检查网内的主机上是否将网卡设置为混合模式(有很多工具可以做到,AntiSniff,Promiscan,S

    entinel等)
    2.对EtterCap这样的交换网络嗅探器(进行ARP欺骗),可以采用防止ARP欺骗的方法来对待
    3.SSH加密通道
    4.SSL
    5.VPN
    6.PGP等

    目前这用利用网卡混合模式来进行sniffer的软件看来作用不太大了,所以应该多考虑交换网络的可

    行办法:

    MAC Flooding,MAC Duplicating,ARP欺骗等等
    这些方法实现起来就不怎么容易了,欢迎有兴趣的朋友提供相关的资料,呵呵!

    netsys:
    难道没人用过RAW SOCKET 吗?
    虽然WINPCP功能很大,但RAW SOCKET可以让你直接了SOCKET的原生机制。
    实际上我提的那两个问题是很容易解决的。。

    netsys2:
    对于一些混合模式的SNIFFER,大多采用发送特殊ARP包的方式,正确的网卡不会响应,而处于

    混合模式的网卡则会响应。

    当然,ARP与IP处于同层,因此你不能用RAW SOCKET完成,你需WinPcap支持工作。

    下面是部分代码

    AnsiString msgStatus;
    extern TArpFuncParam wParams;

    int BuildARPPacket(PArpPacket ArpPacket, unsigned char *dst_etheraddr,
         unsigned char *src_etheraddr, int ar_op, unsigned

    char *ar_sha,
         unsigned char *ar_sip, unsigned char *ar_tha,
                              unsigned char *ar_tip,unsigned short int ar_hw)
    {
      memcpy(&(ArpPacket->eth_dst_addr), dst_etheraddr, ETH_ADD_LEN);
      memcpy(&(ArpPacket->eth_src_addr), src_etheraddr, ETH_ADD_LEN);
      ArpPacket->eth_type = htons(ETH_TYPE_ARP);
      ArpPacket->ar_hrd = htons(ar_hw);
      ArpPacket->ar_pro = htons(ARP_PRO_IP);
      ArpPacket->ar_hln = ARP_ETH_ADD_SPACE;
      ArpPacket->ar_pln = ARP_IP_ADD_SPACE;
      ArpPacket->ar_op  = htons(ar_op);
      memcpy(&(ArpPacket->ar_sha), ar_sha, ARP_ETH_ADD_SPACE);
      memcpy(&(ArpPacket->ar_spa), ar_sip, ARP_IP_ADD_SPACE);
      memcpy(&(ArpPacket->ar_tha), ar_tha, ARP_ETH_ADD_SPACE);
      memcpy(&(ArpPacket->ar_tpa), ar_tip, ARP_IP_ADD_SPACE);
      memset(ArpPacket->eth_pad, 32, ETH_PADDING_ARP);
      return(EXIT_SUCCESS);
    }
    int OpenAdapter(LPADAPTER *lpAdapter)
    {
      *lpAdapter = 

    PacketOpenAdapter(wParams.AdapterList[wParams.SelectedAdapter]);

      if(!(*lpAdapter) || ((*lpAdapter)->hFile == INVALID_HANDLE_VALUE))
      {
        msgStatus = "Error : unable to open the driver.";
        SHOWSTAT(msgStatus);
        return(EXIT_FAILURE);
      }
      return(EXIT_SUCCESS);
    }
    void CloseAdapter(LPADAPTER lpAdapter)
    {
      PacketCloseAdapter(lpAdapter);

    }
    void GetLocalMAC(LPADAPTER lpAdapter, unsigned char *ether_addr)
    {

      ULONG IoCtlBufferLength = (sizeof(PACKET_OID_DATA) + sizeof(ULONG) - 1);
      PPACKET_OID_DATA OidData;

      OidData = (struct _PACKET_OID_DATA *)malloc(IoCtlBufferLength);
      OidData->Oid = OID_802_3_CURRENT_ADDRESS;
      OidData->Length = 6;
      if(PacketRequest(lpAdapter, FALSE, OidData) == FALSE)
          memcpy(ether_addr, 0, 6);
      else
          memcpy(ether_addr, OidData->Data, 6);
      free(OidData);
    }
    int GetARPReply(LPPACKET lpPacket, unsigned char *iptarget, unsigned char

    *result)
    {
      unsigned short int ether_type;
      unsigned char      ipsender[4];  
      unsigned int       off=0;
      unsigned int       tlen;
      struct bpf_hdr     *hdr;  
      char              *pChar;
      char              *buf;

      buf = (char *)lpPacket->Buffer;  
      hdr = (struct bpf_hdr *)(buf + off);
      tlen = hdr->bh_caplen;
      off += hdr->bh_hdrlen;  
      pChar = (char*)(buf + off); 
      off = Packet_WORDALIGN(off + tlen);
      memcpy(&ether_type, pChar + 12, 2);
      ether_type = ntohs(ether_type); 
      if(ether_type == ETH_TYPE_ARP)
      {
        memcpy(ipsender, pChar + 28, 4);
        if((iptarget[0] == ipsender[0])&&(iptarget[1] == ipsender[1])&&
           (iptarget[2] == ipsender[2])&&(iptarget[3] == ipsender[3]))
          memcpy(result, pChar + 22, 6);
        else
            return(EXIT_FAILURE);
      }
      else
          return(EXIT_FAILURE);
     return(EXIT_SUCCESS);
    }
    int CheckPROMode(LPADAPTER lpAdapter, unsigned char *iptarget, unsigned char

    *remotemac)
    {

      LPPACKET lpPacketRequest;
      LPPACKET lpPacketReply;
      char     buffer[256000];

      TArpPacket ArpPacket;
      unsigned char magicpack[ETH_ADD_LEN]= {0xFF,0xFF,0xFF,0xFF,0xFF,0xFE};
      unsigned char mactarget[ARP_ETH_ADD_SPACE];

      DWORD timestamp = 0;
      int numPacks = 0;
      /* Init fields */
      memset(mactarget, 0, 6);
      /* Allocate PACKET structure for ARP Request packet */
      if((lpPacketRequest = PacketAllocatePacket()) == NULL)
      {
        msgStatus =  "Error : failed to allocate the LPPACKET structure..";
        SHOWSTAT(msgStatus);
        return(EXIT_FAILURE);
      }

      /* Init packet structure */
      memset(&ArpPacket, 0, sizeof(TArpPacket));

      /* Build ARP Request packet */
      BuildARPPacket(&ArpPacket, magicpack, wParams.srcMAC, ARP_OP_REQUEST,

    wParams.srcMAC, wParams.srcIPAdd, mactarget, iptarget,wParams.ar_hw);

      /* Init ARP Request packet */
      PacketInitPacket(lpPacketRequest, &ArpPacket, sizeof(ArpPacket));
      
      /* Set number of ARP Request packets to send */
      if(PacketSetNumWrites(lpAdapter, 1) == FALSE)
      {
        msgStatus = "Warning : unable to send more than one packet in a single write..";
        SHOWSTAT(msgStatus);
      }
      /* Set hardware filter to directed mode */
      if(PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_DIRECTED) == FALSE)
      {
        msgStatus ="Warning: unable to set directed mode..";
        SHOWSTAT(msgStatus);
      }
      /* Set a 512K buffer in the driver */
      if(PacketSetBuff(lpAdapter, 512000) == FALSE)
      {
        msgStatus = "Error: unable to set the kernel buffer..";
        SHOWSTAT(msgStatus);
        PacketFreePacket(lpPacketRequest);
        return(EXIT_FAILURE);
      }
      /* Set a 1 second read timeout */
      if(PacketSetReadTimeout(lpAdapter, -1) == FALSE)
      {
        msgStatus = "Warning: unable to set the read tiemout..";
        SHOWSTAT(msgStatus);
      }
     
      /* Allocate PACKET structure for ARP Reply packet */
      if((lpPacketReply = PacketAllocatePacket()) == NULL)
      {
        msgStatus = "Error: failed to allocate the LPPACKET structure..";
        SHOWSTAT(msgStatus);
        PacketFreePacket(lpPacketRequest);
        return(EXIT_FAILURE);
      }
      /* Init ARP Reply packet */
      PacketInitPacket(lpPacketReply, (char*)buffer, 256000);
      /* Allocate memory for remote MAC address */
      timestamp = GetTickCount();

      /* Main capture loop */
      for(;;)
      {
        if(numPacks < wParams.numPacks)
        {
       /* Send packet */
          if(PacketSendPacket(lpAdapter, lpPacketRequest, TRUE) == FALSE)
          {
            msgStatus ="Error : unable to send the packets..";
            SHOWSTAT(msgStatus);
            PacketFreePacket(lpPacketRequest);
            PacketFreePacket(lpPacketReply);
            return(EXIT_FAILURE);
          }
          /* Free packet */
          PacketFreePacket(lpPacketRequest);
          numPacks += 1;
        }
        /* Capture the packets */
        if(PacketReceivePacket(lpAdapter, lpPacketReply, TRUE) == FALSE)
        {
            msgStatus = "Error: PacketReceivePacket failed..";
            SHOWSTAT(msgStatus);
     PacketFreePacket(lpPacketReply);
       return(EXIT_FAILURE);
        }
        if(lpPacketReply->ulBytesReceived > 0)
       if(GetARPReply(lpPacketReply, iptarget, remotemac) == EXIT_SUCCESS)
             break;
        if((GetTickCount() - timestamp) > wParams.delay)
        {
          PacketFreePacket(lpPacketReply);
          return(EXIT_FAILURE);
        }
      }
      /* Free packet */
      PacketFreePacket(lpPacketReply);
      return(EXIT_SUCCESS);
    }
    sunxufei:
    哦,交换机是以MAC地址进行交换的,不是IP那一层的,要IP已经路由器了
    现在交换机便宜了,因此以后你想用sniffer抓密码概率不大了,不过还能多公司仍然是交换机和H

    UB一起用的,这样小范围内是有效地,至于ADSL CABLE FTTB,我的FTTB是用华为设计的设备

    ,呵呵,不仅仅工网IP,只有我和交换机两个MAC(这次中国人干的不错),没希望找到第三者,很安全,但

    不都这样安全,很多人的网络还是很糟糕的.
    很多加密协议可以用来提高安全性,但老的POP3,SMTP,HTTP,FTP这种协议应用广泛,不可能在短

    时间内完全取代,而且加密也是有待价的,所以对于要求较高的场合,才会加密.
    不过sniffer不是给大家偷密码用的,我当初用来学习网络,看看包的样子,后来就用来当作网管工具,

    分析网络的健康与否,其实这样的话,你知道,很有可能sniffer就是接在我需要探测的网络上,听诊器

    吗,到处都听听,呵呵,因此即使用了交换机,sniffer仍然是有用处的,但不是抓密码!!
    Wincap很简单,大3的学生不要怕,去他的网站看看,有例子的,VC6编译,BCB也行的,把lib的格式转

    换一下,不过写这种程序,你最好先熟悉协议,很多协议在linux里有现成的源代码,主要是一些struct

    吧,移植时注意VC可不是gcc,有些c的高级语法,编译选项要注意,否则差一个byte你就得不到正确的

    结果.
    如果你搞不到sniffer,Win2000 Server也有网络包查看器的,不比sniffer强大,但简单的东西入手

    也快.
    反嗅探和嗅探技术其实很old了,呵呵,不过CSDN经常old的.
    注意不要干坏事,有矛必有盾

    sevencat:
    网卡的混杂模式好像要通过NDIS设置。
    下面是转贴的。
    哪位UP一下,我来贴完。
    一、驱动开发网
    作者:gjpland
    看到很多仁兄提供的数据包的拦截技术,其中最多的是编写IM DRIVER在NDIS中间层
    对MINIPORT(网卡驱动程序)和协议驱动程序之间的数据包进行拦截。这是微软提供的一种技术
    但编写该过滤程序拦截程序非常的复杂,安装也很麻烦。

    本人简单的介绍一种更有效的基于NDIS包拦截技术。

    大家都知道,NDIS协议驱动程序是通过填写一张NDIS_PROTOCOL_CHARACTERISTICS的表

    ,并调用NDIS API
    函数NdisRegisterProtocol进行注册。现在我们来关注一下NDIS_PROTOCOL_CHARACTERI

    STICS这张表,
    这张表中存有所有协议驱动程序与底层的派发函数的入口。如SendHandler,ReceiveHandler,Bi

    ndAdapterHandler等,
    当网卡有数据包进入时,会通过表中ReceiveHandle 或ReceivePacketHandler通知协议驱动程

    序有一个该协议
    的数据包进入,反之协议驱动程序是通过SendHandler或SendPacketsHandler函数向网卡驱动

    发送数据包到网络
    上去的,有人会奇怪程序中明明不是调用NdisSend或NdisSendPackets函数发送的吗?没错,

    是这样的,
    但是你可以看一下NDIS.H的头文件里对这两个函数的定义就知道了,他们都是一个
    宏定义,实际还是通过这表中SendHandler或SendPacketsHandler发送的。

    现在我们所要做的事情应该很清楚了,只要我们能够将每一个协议程序所填写的NDIS_PROTOCO

    L_CHARACTERISTICS
    表里的派发函数指向自己的函数,我们就能成功的对数据包进行拦截。那么每个协议驱动程序的这张

    表到底存放在
    那里呢?太简单了,看一下下面的我对NdisRegisterProtocol重新给出的原型就很明白了。

    struct _NDIS_PROTOCOL_BLOCK
    {
    PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this protocol
    REFERENCE Ref; // contains spinlock for OpenQueue
    UINT Length; // of this NDIS_PROTOCOL_BLOCK struct
    NDIS50_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics;// handler

    addresses

    struct _NDIS_PROTOCOL_BLOCK * NextProtocol; // Link to next
    ULONG MaxPatternSize;
    #if defined(NDIS_WRAPPER)
    //
    // Protocol filters
    //
    struct _NDIS_PROTOCOL_FILTER * ProtocolFilter[NdisMediumMax+1];
    WORK_QUEUE_ITEM WorkItem; // Used during NdisRegisterProtocol to
    // notify protocols of existing drivers.
    KMUTEX Mutex; // For serialization of Bind/Unbind requests
    PKEVENT DeregEvent; // Used by NdisDeregisterProtocol
    #endif
    };
    typedef struct _NDIS_PROTOCOL_BLOCK NDIS_PROTOCOL_BLOCK,

    *PNDIS_PROTOCOL_BLOCK;

    EXPORT
    VOID
    NdisRegisterProtocol(
    OUT PNDIS_STATUS Status,
    OUT PNDIS_PROTOCOL_BLOCK NdisProtocolHandle, /*注意NDIS_HANDLE所指向的

    就是PNDIS_PROTOCOL_BLOCK的结构,不要有什么怀疑。*/
    IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
    IN UINT CharacteristicsLength
    );


    NDIS_PROTOCOL_BLOCK(协议表)

    是NDIS维护所有系统中已注册协义的单向链接表。字段NextProtocol指向下一个协议表。
    庆幸的是,当我们注册一新的协议时,NDIS总是会把新注册的协义放在链表的头并返回这张表,

    所以只要我们注册一个新的协议
    通过新协议注册返回的链表头就可以轻而易举的遍历系统中所有协议表.现在我们所希望得到的每个

    协议的
    NDIS_PROTOCOL_CHARACTERISTICS表就放在我们面前了,如何勾挂表中的派发函数,我

    想不必多说了吧。顺便说一句
    NDISREGISTERPROTOCOL为NDIS_PROTOCOL_BLOCK所分配的内存是NonPagedPool

    类型的。对于核心DRIVER来说,核心区内存
    是一个线性的内存区,所有核心DRIVER是可以随便访问核心内存区的任意地址。所要注意的是不

    同IRQL级别下对分页
    和非分页内存。

    有人会问这样就行了吗?真的拦截下来了吗?如果有那位仁兄心急现在就写程序的话,
    准会失望的,因为他会发现结果什么东西都没拦截到或偶而会拦截到一些数据包。为什么?
    因为NDIS网卡驱动和协议驱动在发送和接收到数居时并不是调用PNDIS_OPEN_BLOCK->Proto

    colCharacteristics
    里的派发函数。怎么办?
    有必要先介绍一下NDIS网卡驱动和协议驱动之间是如何BINDING 的吧,
    NdisRegisterProtocol在注册完一个协议后,不久NDIS会通过调用表中
    BindAdapterHandler派发函数,通知协议对每一个网卡进行BINDING。或者当系统通PNP找到

    一块新的网卡时
    也会调用BindAdapterHandler对协议进行BINDING。协议在BINDING 调用里,会根据自己的

    需要使用NdisOpenAdapter
    将自身绑定到适合的网卡。并返回NdisBindingHandle.NdisBindingHandle是什么?NdisBin

    dingHandl其实是
    指向NDIS_OPEN_BLOCK表的一根指针,那么NDIS_OPEN_BLOCK表有什么用呢?当协议顺

    利的绑定后,每个绑定的网卡
    和每一个协议之间建立了数据传输的通道,而NDIS_OPEN_BLOCK就是用来维护这一数据通道的

    表。
    struct _NDIS_OPEN_BLOCK
    {
    PNDIS_MAC_BLOCK MacHandle; // pointer to our MAC
    NDIS_HANDLE MacBindingHandle; // context when calling MacXX funcs
    PNDIS_ADAPTER_BLOCK AdapterHandle; // pointer to our adapter
    PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol
    NDIS_HANDLE ProtocolBindingContext;// context when calling ProtXX funcs
    PNDIS_OPEN_BLOCK AdapterNextOpen; // used by adapter's OpenQueue
    PNDIS_OPEN_BLOCK ProtocolNextOpen; // used by protocol's OpenQueue
    PFILE_OBJECT FileObject; // created by operating system
    BOOLEAN Closing; // TRUE when removing this struct
    BOOLEAN Unloading; // TRUE when processing unload
    BOOLEAN NoProtRsvdOnRcvPkt; // Reflect the protocol_options
    NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close
    KSPIN_LOCK SpinLock; // guards Closing
    PNDIS_OPEN_BLOCK NextGlobalOpen;

    //
    // These are optimizations for getting to MAC routines. They are not
    // necessary, but are here to save a dereference through the MAC block.
    //
    SEND_HANDLER SendHandler;
    TRANSFER_DATA_HANDLER TransferDataHandler;

    //
    // These are optimizations for getting to PROTOCOL routines. They are not
    // necessary, but are here to save a dereference through the PROTOCOL block.
    //
    SEND_COMPLETE_HANDLER SendCompleteHandler;
    TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
    RECEIVE_HANDLER ReceiveHandler;
    RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;

    //
    // Extentions to the OPEN_BLOCK since Product 1.
    //
    RECEIVE_HANDLER PostNt31ReceiveHandler;
    RECEIVE_COMPLETE_HANDLER PostNt31ReceiveCompleteHandler;

    //
    // NDIS 4.0 extensions
    //
    RECEIVE_PACKET_HANDLER ReceivePacketHandler;
    SEND_PACKETS_HANDLER SendPacketsHandler;

    //
    // More NDIS 3.0 Cached Handlers
    //
    RESET_HANDLER ResetHandler;
    REQUEST_HANDLER RequestHandler;

    //
    // Needed for PnP
    //
    UNICODE_STRING AdapterName; // Upcased name of the adapter we are bound to
    };


    上面的表结构可以很清楚的看到这张表是一个单向链接表,并且存放了和PNDIS_OPEN_BLOCK-

    >ProtocolCharacteristics
    一样的数据收发派发函数,当第N块网卡发送数据包到第N个协议时,就会调用第N个协议与第N个

    网卡之间建立的
    NDIS_OPEN_BLOCK表里的SendHandler或SendPacketHandler。所以我们还需要对这张表

    里的派发函数进行处理(勾挂)。
    那么又如何勾挂协议与网卡之间的NDIS_OPEN_BLOCK表呢。我们再回到NDIS_PROTOCOL_

    BLOCK这张表中,在
    NDIS_PROTOCOL_BLOCK表中字段PNDIS_OPEN_BLOCK OpenQueue;就是所有该协议所

    有NDIS_OPEN_BLOCK的表头。
    通过AdapterNextOpen遍历一下,再勾挂一把。就可以顺利拦截了。

    值得注意的是。
    1。
    NDIS_OPEN_BLOCK
    NDIS_PROTOCOL_BLOCK
    这些结构不同NDIS版本是不同的,
    解决方法是在windows 98和windows95下(ndis 3.1)使用windows98ddk 带的NDIS.H 里的

    定义
    在windows me下(ndis 5.0或4。0)请使用WINDOWS 98ddk里NDIS.H里的定义
    nt(ndis4.0)用NTDDK里的定议,以此类推,2000(ndis5.0)
    2。不要重复勾挂同一个函数。

    有问题可以通过
    QQ:3955727
    mail:gjpland@netease.com

    //
    //Protocol Wrapper Version 1.05
    //Author:  gjp
    //email:   gjpland@netease.com
    //


    #include "NdisHook.h"
    #include "HookRule.h"

    #pragma pack(push)
    #pragma pack(1)
    typedef struct _HOOK_CONTEXT_STRUCT
    {
     //runtime code
     ubyte    code1_0x58; //0x58 | pop  eax      | pop caller IP from stack to

    eax
     ubyte    code2_0x68; //0x68 | push IMM      | push our hook context

    address
     struct _HOOK_CONTEXT_STRUCT *m_pHookContext;//point this
     ubyte    code3_0x50; //0x50 | push eax  | push caller

    IP from eax to stack
     ubyte    code4_0xE9; //0xE9 | jmp HookProc  | jump our hook proc
     udword   m_pHookProcOffset;

     //our context data

     PVOID    m_pOriginalProc;
     PVOID    m_pHookProc;
     PVOID    m_pBindAdaptHandle;
     PVOID    m_pProtocolContent;
     PVOID   *m_ppOriginPtr;

     struct _HOOK_CONTEXT_STRUCT *m_pHookNext;
     
    }HOOK_CONTEXT_STRUCT;
    #pragma pack(pop)

    HOOK_CONTEXT_STRUCT *m_pOurAllOfHookContext = NULL;

    dword     m_IsFilterEnabled     = FALSE;
    NDIS_HANDLE    m_ourPacketPoolHandle = NULL;
    NDIS_HANDLE    m_ourBufferPoolHandle = NULL;
    PNDIS_PACKET   m_ourPacketHandle     = NULL;
    PNDIS_BUFFER   m_ourBufferHandle     = NULL;
    PVOID          m_ourBuffer       = NULL;

    void      ReadPacket(PNDIS_PACKET Packet,PVOID pBuffer,udword dwBufSize);
    uword     wswap(uword value);

    void HookUnload(void)
    {
     ReleaseHookFunc();

     if( m_ourBufferHandle )
     {
      NdisFreeBuffer(m_ourBufferHandle);
      m_ourBufferHandle = NULL;
     }
     if( m_ourBuffer )
     {
      NdisFreeMemory(m_ourBuffer,MAX_PACKET_SIZE,0);
      m_ourBuffer = NULL;
     }
     if( m_ourPacketHandle )
     {
      NdisFreePacket(m_ourPacketHandle);
      m_ourPacketHandle = NULL;
     }
     if( m_ourBufferPoolHandle )
     {
      NdisFreeBufferPool(m_ourBufferPoolHandle);
      m_ourBufferPoolHandle = NULL;
     }
     if( m_ourPacketPoolHandle )
     {
      NdisFreePacketPool(m_ourPacketPoolHandle);
      m_ourPacketPoolHandle = NULL;
     }
     return;
    }
    dword HookInit(void)
    {
     NTSTATUS status;

     m_ourPacketPoolHandle = NULL;
     NdisAllocatePacketPool(&status,&m_ourPacketPoolHandle,0xFFF,0x10);
     if( status != NDIS_STATUS_SUCCESS )
      return FALSE;

     m_ourBufferPoolHandle = NULL;
     NdisAllocateBufferPool(&status,&m_ourBufferPoolHandle,0x10);
     if( status != NDIS_STATUS_SUCCESS )
      return FALSE;

     m_ourBuffer = NULL;
     status =

    NdisAllocateMemoryWithTag(&m_ourBuffer,MAX_PACKET_SIZE,'NAMW');
     if( status != NDIS_STATUS_SUCCESS )
      return FALSE;

     m_ourBufferHandle = NULL;
     

    NdisAllocateBuffer(&status,&m_ourBufferHandle,m_ourBufferPoolHandle,m_ourBuff

    er,MAX_PACKET_SIZE);
        if( status != NDIS_STATUS_SUCCESS )
      return FALSE;

     m_ourPacketHandle = NULL;
     

    NdisAllocatePacket(&status,&m_ourPacketHandle,m_ourPacketPoolHandle);
     if( status != NDIS_STATUS_SUCCESS )
      return FALSE;

     NdisChainBufferAtFront(m_ourPacketHandle,m_ourBufferHandle);
     return TRUE;
    }

    typedef struct _NDIS41_PROTOCOL_CHARACTERISTICS
    {
    #ifdef __cplusplus
     NDIS40_PROTOCOL_CHARACTERISTICS Ndis40Chars;
    #else
     NDIS40_PROTOCOL_CHARACTERISTICS;
    #endif
     
     //
     // Start of NDIS 4.1 extensions.
     //

     CO_SEND_COMPLETE_HANDLER  

    CoSendCompleteHandler;
     CO_STATUS_HANDLER    

    CoStatusHandler;
     CO_RECEIVE_PACKET_HANDLER  

    CoReceivePacketHandler;
     CO_REQUEST_HANDLER    

    CoRequestHandler;
     CO_REQUEST_COMPLETE_HANDLER  

    CoRequestCompleteHandler;

    } NDIS41_PROTOCOL_CHARACTERISTICS;

    dword HookProtocol(void)
    {
     //Default ndis version is 5.0
     NDIS_PROTOCOL_CHARACTERISTICS ourNPC;
     NDIS_STRING protoName = NDIS_STRING_CONST("HdFw_Slot");
     NDIS_STATUS Status;
     NDIS_HANDLE ourProtocolHandle = NULL;
     byte  *ProtocolChain;
     dword  offset;
     dword  len;

    // NDIS_PROTOCOL_BLOCK *pNdisBlock = NULL;

    // pNdisBlock = pNdisBlock->NextProtocol;
    // pNdisBlock->NextProtocol = NULL;

     memset(&ourNPC,0,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));


     if( m_dwMajorVersion == 0x03 )
     {
      len = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS);
      //We must need at least ndis version 3.10
      ourNPC.MajorNdisVersion = 0x03;
      ourNPC.MinorNdisVersion = 0x0A;
     }
     else
     if( m_dwMajorVersion == 0x04 )
     {
      len = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);

      ourNPC.MajorNdisVersion = 0x04;
      ourNPC.MinorNdisVersion = 0x00;
     }
     else
     { //treat as version 5.0
      len = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS);
      
      ourNPC.MajorNdisVersion = 0x05;
      ourNPC.MinorNdisVersion = 0x00;
     }

        ourNPC.Name                        = protoName;
        ourNPC.OpenAdapterCompleteHandler  = PtOpenAdapterComplete;
        ourNPC.CloseAdapterCompleteHandler = PtCloseAdapterComplete;
        ourNPC.SendCompleteHandler         = PtSendComplete;
        ourNPC.TransferDataCompleteHandler = PtTransferDataComplete;
        ourNPC.ResetCompleteHandler        = PtResetComplete;
        ourNPC.RequestCompleteHandler      = PtRequestComplete;
        ourNPC.ReceiveHandler              = PtReceive;
        ourNPC.ReceiveCompleteHandler      = PtReceiveComplete;
        ourNPC.StatusHandler               = PtStatus;
        ourNPC.StatusCompleteHandler       = PtStatusComplete;
        ourNPC.BindAdapterHandler          = PtBindAdapter;
        ourNPC.UnbindAdapterHandler        = PtUnbindAdapter;
        ourNPC.UnloadHandler               = PtUnload;
        ourNPC.ReceivePacketHandler        = PtReceivePacket;
        ourNPC.PnPEventHandler             = PtPNPHandler;

     NdisRegisterProtocol(&Status,&ourProtocolHandle,&ourNPC,len);
     if( !NT_SUCCESS(Status) || ourProtocolHandle == NULL )
      return FALSE;

     //NdisRegisterProtocol  return hand reference of

    NDIS_PROTOCOL_BLOCK;
     ProtocolChain = (byte *)ourProtocolHandle;
     while(1)
     {
      DebugInfoCount++;

      //Obtain pointer to next protocol link.
      if( m_dwMajorVersion == 0x03 )
       offset = 4;
      else
      if( m_dwMajorVersion == 0x04 )
      {
       if( m_dwMinorVersion == 0x01 )
        offset = 0x8C;
       else
        offset = 0x60;
      }
      else
      if( m_dwMajorVersion == 0x05 )
       //NDIS_PROTOCOL_BLOCK->NextProtocol
       offset = 0x10;
      else
       //Error
       break;

      ProtocolChain = ((byte **)(ProtocolChain + offset))[0];
      if( ProtocolChain == NULL )
       break;

      HookFuncBlock(ProtocolChain);
     }
     if( m_dwMajorVersion != 4 )
      NdisDeregisterProtocol(&Status,ourProtocolHandle);
     else
     {
    //  ((byte *)ourProtocolHandle)[0x0C] = 0x01;
    //  NdisDeregisterProtocol(&Status,ourProtocolHandle);
     }
     return TRUE;
    }
    // ProtocolContent
    // Version      NextChain offset    NDIS_PROTOCOL_CHARACTERISTICS offset  

    BindingAdaptHandle offset
    // NDIS 3.XX    0x04       

    0x14         

    0x08
    // NDIS 4.XX    0x60       

    0x14         

    0x00
    // NDIS 4.01       0x8C       

    0x14         

    0x00
    // NDIS 5.XX       0x10       

    0x14         

    0x00


    //-----
    VOID HookProtocolSendPackets(
        IN  HOOK_CONTEXT_STRUCT    *pOurContext,    
     IN NDIS_HANDLE    

    MiniportAdapterContext,
     IN PPNDIS_PACKET   PacketArray,
     IN UINT      

    NumberOfPackets
     );

    NDIS_STATUS HookProtocolWanSend(
        IN  HOOK_CONTEXT_STRUCT    *pOurContext,    
     IN NDIS_HANDLE    

    MacBindingHandle,
     IN NDIS_HANDLE    LinkHandle,
     IN PVOID     Packet
     );
    NDIS_STATUS HookProtocolSend(
        IN  HOOK_CONTEXT_STRUCT    *pOurContext,    
     IN NDIS_HANDLE    

    MacBindingHandle,
     IN PNDIS_PACKET   Packet
     );

    NDIS_STATUS  HookProtocolReceive(
       IN HOOK_CONTEXT_STRUCT *pOurContext,    
       IN NDIS_HANDLE  ProtocolBindingContext,
          IN NDIS_HANDLE  MacReceiveContext,
          IN PVOID    HeaderBuffer,
          IN UINT    HeaderBufferSize,
          IN PVOID    LookAheadBuffer,
          IN UINT    LookaheadBufferSize,
          IN UINT    PacketSize
          );
    NDIS_STATUS  HookWanReceive(
         IN  HOOK_CONTEXT_STRUCT    *pOurContext,    
      IN NDIS_HANDLE    

    NdisLinkHandle,
      IN PUCHAR     

    Packet,
      IN ULONG     

    PacketSize
      );
    INT HookProtocolReceivePacket(
        IN  HOOK_CONTEXT_STRUCT    *pOurContext,    
     IN NDIS_HANDLE    

    ProtocolBindingContext,
     IN PNDIS_PACKET   Packet
     );


    VOID HookBindAdapterHandler(
              IN 

    HOOK_CONTEXT_STRUCT *pOurContext,    
           OUT

    PNDIS_STATUS Status,
           IN 

    NDIS_HANDLE  BindContext,
           IN 

    PNDIS_STRING DeviceName,
           IN  PVOID 

      SystemSpecific1,
           IN  PVOID 

      SystemSpecific2);

    VOID  HookSendComplete(
          IN  HOOK_CONTEXT_STRUCT *pOurContext,    
          IN NDIS_HANDLE  ProtocolBindingContext,
          IN PNDIS_PACKET  Packet,
          IN NDIS_STATUS Status
          );


    void   ReleaseHookFunc(void)
    {

     HOOK_CONTEXT_STRUCT *pHookContext,*pNext;

     pHookContext = m_pOurAllOfHookContext;
     m_pOurAllOfHookContext = NULL;
     while(pHookContext)
     {
      pNext = pHookContext->m_pHookNext;
      pHookContext->m_ppOriginPtr[0] =

    pHookContext->m_pOriginalProc;
      ExFreePool(pHookContext);
      pHookContext = pNext;
     }
     return;
    }

    HOOK_CONTEXT_STRUCT *IsHookedNdisFunc(PVOID pAddr)
    {

     HOOK_CONTEXT_STRUCT *pHookContext;

     pHookContext = m_pOurAllOfHookContext;
     while(pHookContext)
     {
      if( pHookContext == pAddr )
       break;
      pHookContext = pHookContext->m_pHookNext;
     }
     return pHookContext;
    }
    HOOK_CONTEXT_STRUCT *IsHookedNdisFuncEx(PVOID *pAddr)
    {

     HOOK_CONTEXT_STRUCT *pHookContext;

     pHookContext = m_pOurAllOfHookContext;
     while(pHookContext)
     {
      if( pHookContext->m_ppOriginPtr == pAddr )
       break;
      pHookContext = pHookContext->m_pHookNext;
     }
     return pHookContext;
    }

    HOOK_CONTEXT_STRUCT *HookNdisFunc(PVOID pHookProc,PVOID

    *ppOrigProc,PVOID pBindAdaptHandle,PVOID pProtocolContent)
    {

     HOOK_CONTEXT_STRUCT *pHookContext;
     PVOID OrgFunc;

     pHookContext = IsHookedNdisFunc(ppOrigProc[0]);
     if( pHookContext )
      OrgFunc = pHookContext->m_pOriginalProc;
     else
      OrgFunc = ppOrigProc[0];
     if( OrgFunc == NULL )
      return NULL;

     pHookContext = IsHookedNdisFuncEx(ppOrigProc);
     if( pHookContext )
      return pHookContext;
     pHookContext =

    ExAllocatePoolWithTag(NonPagedPool,sizeof(HOOK_CONTEXT_STRUCT),'HCSP');
     if( pHookContext == NULL )
      return NULL;
     memset(pHookContext,0,sizeof(HOOK_CONTEXT_STRUCT));

     pHookContext->code1_0x58 = 0x58;
     pHookContext->code2_0x68 = 0x68;
     pHookContext->code3_0x50 = 0x50;
     pHookContext->code4_0xE9 = 0xE9;

     pHookContext->m_pHookContext     = pHookContext;
     pHookContext->m_pHookProcOffset  = ((udword)pHookProc) -

    (((udword)&pHookContext->m_pHookProcOffset) + sizeof(udword));
     pHookContext->m_pBindAdaptHandle = pBindAdaptHandle;
     pHookContext->m_pProtocolContent = pProtocolContent;
     pHookContext->m_pOriginalProc    = OrgFunc;//ppOrigProc[0];
     pHookContext->m_ppOriginPtr      = ppOrigProc;
     pHookContext->m_pHookProc        = pHookProc;
     pHookContext->m_pHookNext        = m_pOurAllOfHookContext;
     m_pOurAllOfHookContext    = pHookContext;

     ppOrigProc[0] = pHookContext;
     return pHookContext;
    }

    typedef
    struct _NDIS40_OPEN_BLOCK
    {
     PNDIS_MAC_BLOCK    MacHandle; 

      // pointer to our MAC
     NDIS_HANDLE     

    MacBindingHandle; // context when calling MacXX funcs
     PNDIS_ADAPTER_BLOCK   AdapterHandle;  

    // pointer to our adapter
     PNDIS_PROTOCOL_BLOCK  ProtocolHandle;  //

    pointer to our protocol
     NDIS_HANDLE     

    ProtocolBindingContext;// context when calling ProtXX funcs
     PNDIS_OPEN_BLOCK   AdapterNextOpen; //

    used by adapter's OpenQueue
     PNDIS_OPEN_BLOCK   ProtocolNextOpen; //

    used by protocol's OpenQueue
     PFILE_OBJECT    FileObject;  

     // created by operating system
     BOOLEAN      

    Closing;   // TRUE when removing this struct
     BOOLEAN      

    Unloading;   // TRUE when processing unload
     NDIS_HANDLE     

    CloseRequestHandle; // 0 indicates an internal close
     KSPIN_LOCK     SpinLock; 

      // guards Closing
     PNDIS_OPEN_BLOCK   NextGlobalOpen;

     //
     // These are optimizations for getting to MAC routines. They are not
     // necessary, but are here to save a dereference through the MAC block.
     //

     SEND_HANDLER    SendHandler;
     TRANSFER_DATA_HANDLER  TransferDataHandler;

     //
     // These are optimizations for getting to PROTOCOL routines.  They are

    not
     // necessary, but are here to save a dereference through the PROTOCOL

    block.
     //

     SEND_COMPLETE_HANDLER  SendCompleteHandler;
     TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
     RECEIVE_HANDLER    

    ReceiveHandler;
     RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;

     //
     // Extentions to the OPEN_BLOCK since Product 1.
     //
     RECEIVE_HANDLER    

    PostNt31ReceiveHandler;
     RECEIVE_COMPLETE_HANDLER PostNt31ReceiveCompleteHandler;

     //
     // NDIS 4.0 extensions
     //
     RECEIVE_PACKET_HANDLER  ReceivePacketHandler;
     SEND_PACKETS_HANDLER  SendPacketsHandler;

     //
     // Needed for PnP
     //
     UNICODE_STRING    AdapterName;  

    // Upcased name of the adapter we are bound to
    }NDIS40_OPEN_BLOCK,*PNDIS40_OPEN_BLOCK;

    void HookFuncBlock(byte *ProtocolContent)
    {

     PNDIS_PROTOCOL_CHARACTERISTICS pProChar;
     dword IsWan;
     NDIS_STRING Wan

    对 sniffer技术原理及应用,包括编程方法和工具使用 文章的评论    [查看网友评论]

    验证码:
    匿名发表: