首页
社区
课程
招聘
[原创]科普NDIS封包过滤
发表于: 2012-5-28 12:28 33790

[原创]科普NDIS封包过滤

2012-5-28 12:28
33790
闲言:
    这个月一直在学习NDIS驱动编程,杂七杂八的资料都看个遍了,做了点笔记,捋捋思路,发上来备忘。
    Ps:只是小菜的一点学习笔记,没什么技术含量,不过版主如果觉得对大家稍微有点帮助的话,嘿嘿,你懂的...

主题:
    由于NDIS架构本身相对比较复杂,有着比其他过滤驱动更多的"游戏规则"需要开发者耐心地学习和理解。所以NDIS驱动开发起来略显繁琐,不过也不必畏惧,多看多写,熟悉后便豁然开朗了。本文以寒江独钓的passthru为例,详细讲解开发一个基于NDIS中间层驱动的封包过滤驱动的原理和流程。由于笔者初学驱动,水平有限,失误之处还请大虾不啬赐教。

1.[前置知识]
    所有网络通信最终必须通过NDIS完成,NDIS横跨传输层/网络层/数据链路层。NDIS负责上下层驱动程序间服务原语与驱动程序入口之间的转换,分派消息通知。NDIS提供三个层次的接口:网络接口卡驱动程序(NIC)、中间层驱动程序(MD)和协议驱动程序。
    NIC: 下端直接控制网络接口卡硬件,上端提供接口,处理初始化网卡、停止网卡、发送和接受数据包。
    PD:  接收来自网卡或中间驱动程序的信息。
    MD:  网卡驱动和协议驱动之间的桥梁。插入自己的中间层驱动,从而可以截获网络封包,并重新进行封包、加密、网络地址转换、过滤和认证等操作。可以处理更低级的操作、功能强大,但是编程接口复杂,自动化安装困难,容易导致网络瘫痪。
    windows内核网络驱动的总体格局(从下至上):小端口驱动实现了对网卡硬件的驱动,包括对其中各个寄存器的访问、中断处理等。协议驱动将链路层、网络层和传输层集合在一起的一个驱动模块。上层是传输驱动界面(TDI)。TDI上层是用来实现Socket机制的AFD驱动模块。
(参见《内核情景分析》 第十章 第一小节)

2.[NDIS架构简析]
    这里对协议驱动和小端口驱动的流程理解都是参考WDK的相应代码总结出来的。详细的代码我就不贴了,节省版面,都是WDK上的原版代码,对一些具体的实现细节有兴趣的童鞋可以自己看看。一些核心函数可以参考ReactOS源码,能够更深层次地理解NDIS内部的结构。直接贴初始化流程图。将NDIS的流程和框架搞清楚了,再深究细节就不那么容易晕了。小菜我研究这玩意的时候,晕了无数次了。由于本文重点在于封包过滤,所以对于NDIS协议驱动和小端口驱动的初始化和收包发包过程仅做一些简单的梳理。核心部分还是在中间层驱动。
NDIS协议驱动  [初始化]
流程图来源思路DDK2000/Packet:


NDIS小端口驱动  [初始化]
NDIS_MINIPORT_CHARACTERISTICS –> NdisMInitializeWrapper -> NdisMRegisterMiniport
    关键部分就是填写小端口驱动特征,设置各种回调,编写NDIS驱动程序的本质就是处理各色各样的回调,有初始化的有卸载的,也还有响应中断进行收包发包的等等等等。编写回调虽是编写NDIS驱动的核心,但不在本节讨论范围。小端口初始化流程,详见下图:


NDIS收包发包的总体流程  [小端口+协议]
    收包由响应网卡产生的中断开始,发包由TDI传入协议驱动的IRP开始。


3.[封包过滤]
    原理:由于NDIS中间层驱动位于协议驱动程序和网络驱动程序之间,所以它可以看到发生在一个系统中的所有网络流量。而不是像协议驱动那样只能看到从网络到来的封包。中间层驱动用于封包过滤和防火墙开发再适合不过了。这里以寒江独钓中的passthru为例编写一个具有端口屏蔽的过滤驱动。

①中间层驱动的初始化  [passthru]
1.初始化小端口部分:
NdisMInitializeWrapper -> NDIS_MINIPORT_CHARACTERISTICS –> NdisIMRegisterLayeredMiniport
2.初始化协议驱动部分并关联至小端口:
NDIS_PROTOCOL_CHARACTERISTICS -> NdisRegisterProtocol -> NdisIMAssociateMiniport
3.passthru初始化总体结构


②封包结构分析与过滤  [TCP端口过滤]
    要对TCP端口进行过滤,很明显必须得先对TCP协议封包的结构进行分析。不同协议的封包格式都不尽相同,对封包格式有兴趣的童鞋可以使用wireshark多抓几个进行分析。如上图所示,寒江独钓中的例子中在每一个发包与收包的相关回调函数中都调用了AnalysisPacket函数对封包进行分析。如果需要添加我们的过滤规则的话,在这个中函数进行即可。TCP协议的封包总共有三个部分:第一是以太网部分,第二是IP部分(前两部分是所有协议的封包都有的),第三就是TCP部分了。
下面是使用wireshark抓到的TCP协议封包:


再来看看TCP HEADER的定义:
[COLOR="Navy"]typedef[/COLOR] struct TCPv4_HEADER {
  USHORT SourcePort;        [COLOR="DarkGreen"]/* Source port */[/COLOR]
  USHORT DestinationPort;   [COLOR="DarkGreen"]/* Destination port */[/COLOR]
  ULONG  SequenceNumber;    [COLOR="DarkGreen"]/* Sequence number */[/COLOR]
  ULONG  AckNumber;         [COLOR="DarkGreen"]/* Acknowledgement number */[/COLOR]
  UCHAR  DataOffset;        [COLOR="DarkGreen"]/* Data offset; 32-bit words (leftmost 4 bits) */[/COLOR]
  UCHAR  Flags;             [COLOR="DarkGreen"]/* Control bits (rightmost 6 bits) */[/COLOR]
  USHORT Window;            [COLOR="DarkGreen"]/* Maximum acceptable receive window */[/COLOR]
  USHORT Checksum;          [COLOR="DarkGreen"]/* Checksum of segment */[/COLOR]
  USHORT Urgent;            [COLOR="DarkGreen"]/* Pointer to urgent data */[/COLOR]
} TCPv4_HEADER, *PTCPv4_HEADER;


    TCP HEADER的定位方式,定位到TCP Header并取得端口号,对需要过滤的端口返回STATUS_DRAP即可。搞端口转发稍微复杂点,不过除了修改端口和IP地址,也就是多了个计算校验和的问题。具体代码可以参考安全焦点上的《NAT在NDIS中间层驱动中的实现》。如果要对IP地址进行过滤的话也同样解析IP HEADER然后增加判断即可。
[COLOR="Navy"]PTCPv4_HEADER[/COLOR] pTCPHeader;
	USHORT iphdrlen;

	iphdrlen = (pIPHeader->VIHL & 0x0f) * sizeof(ULONG);
	pTCPHeader = (PTCPv4_HEADER)(pPacketContent+14 + iphdrlen);   [COLOR="DarkGreen"]//14是以太网包的固定长度+IP协议长度[/COLOR]

[COLOR="DarkGreen"]//如果要对TCP的端口进行过滤的话,加个if语句判断下即可[/COLOR]
DBGPRINT(("    TCP 源端口:  %u\n",ChangeHex(pTCPHeader->SourcePort)));
DBGPRINT(("    TCP 目的端口:%u\n",ChangeHex(pTCPHeader->DestinationPort)));


③获取封包
    中间层驱动初始化完毕后,只需要在初始化时设置的相应回调函数进行处理即可。回调函数设置好了,封包的发送与接收都会调用我们的回调函数。过滤函数一般都在相应的收包发包函数内部的前端,如此一来可以提升处理效率。当然也省了不少麻烦(比如人家内存都分配好了,结果你要丢包)。不过也不死板,可以根据实际情况进行编写。对于发送出去的数据包处理,只要在PassThru中的MiniportSend中加入必要的操作代码,而对于接收的数据包时,则需要在ProtocolReceive和ProtocolReceviePackets中加入必要的操作代码,在这里,我们简单看一下相关的收包发包函数。
发送处理:
[COLOR="Navy"]VOID[/COLOR]
MPSendPackets(
    IN NDIS_HANDLE             MiniportAdapterContext,
    IN PPNDIS_PACKET           PacketArray,
    IN UINT                    NumberOfPackets
    )
{
    ...
    [COLOR="DarkGreen"]// 在为封包分配内存之前,调用我们的过滤函数[/COLOR]
    [COLOR="DarkGreen"]// 分配一个新的包描述符[/COLOR]
    NdisAllocatePacket(&Status,
                       &MyPacket,
                       pAdapt->SendPacketPoolHandle);

    [COLOR="Navy"]if[/COLOR] (Status == NDIS_STATUS_SUCCESS)
    {
        PSEND_RSVD        SendRsvd;

        SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
        [COLOR="DarkGreen"]// 把原来的包描述符保存在新分配的包描述符中的Reserved字段中[/COLOR]
        SendRsvd->OriginalPkt = Packet;

        [COLOR="DarkGreen"]// 获取包标识符[/COLOR]
        NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);

        [COLOR="DarkGreen"]//处理缓冲区[/COLOR]
        NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
        NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
                
        [COLOR="DarkGreen"]//将OOB数据结构从原封包中复制至新包中[/COLOR]
        NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
                       NDIS_OOB_DATA_FROM_PACKET(Packet),
                       sizeof(NDIS_PACKET_OOB_DATA));
                
        [COLOR="DarkGreen"]// 复制中间层指定信息[/COLOR]
        NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
                                            &MediaSpecificInfo,
                                            &MediaSpecificInfoSize);

        [COLOR="Navy"]if[/COLOR] (MediaSpecificInfo || MediaSpecificInfoSize)
        {
            NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
                                                MediaSpecificInfo,
                                                MediaSpecificInfoSize);
        }
        [COLOR="DarkGreen"]// 调用NdisSend发送数据[/COLOR]
        NdisSend(&Status,
                 pAdapt->BindingHandle,
                 MyPacket);

        [COLOR="Navy"]if[/COLOR] (Status != NDIS_STATUS_PENDING)
        {
            NdisFreePacket(MyPacket);
            ADAPT_DECR_PENDING_SENDS(pAdapt);
        }
    ...
}


接收处理:
INT
PtReceivePacket(
    IN NDIS_HANDLE            ProtocolBindingContext,
    IN PNDIS_PACKET           Packet
    )
{
    [B]...[/B]
[COLOR="Sienna"]#ifdef NDIS51[/COLOR]
    [COLOR="DarkGreen"]//
    // Check [COLOR="Navy"]if[/COLOR] we can reuse the same packet for indicating up.
    // See also: PtReceive(). 
    //[/COLOR]
    (VOID)NdisIMGetCurrentPacketStack(Packet, &Remaining);
    [COLOR="Navy"]if[/COLOR] (Remaining)
    {
        [COLOR="DarkGreen"]//
        // We can reuse "Packet". Indicate it up and be done with it.
        //[/COLOR]
        Status = NDIS_GET_PACKET_STATUS(Packet);
        NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &Packet, 1);
        return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
    }
[COLOR="Sienna"]#endif[/COLOR] [COLOR="DarkGreen"]// NDIS51[/COLOR]

    [COLOR="DarkGreen"]// 从packet池中获取packet[/COLOR]
    NdisDprAllocatePacket(&Status,
                           &MyPacket,
                           pAdapt->RecvPacketPoolHandle);
	[B]...[/B]
    [COLOR="DarkGreen"]// 设置封包flags[/COLOR]
    NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);

    Status = NDIS_GET_PACKET_STATUS(Packet);

    NDIS_SET_PACKET_STATUS(MyPacket, Status);
    NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));

    [COLOR="Navy"]if[/COLOR] (pAdapt->MiniportHandle != NULL)
    {
        [COLOR="DarkGreen"]// 调用NDIS库函数接受封包[/COLOR]
        NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
    }
    [B]...[/B]
}


④过滤规则的编写
    NDIS封包的过滤有很多种处理方式:延迟或重新排序、加密或解密、压缩或解压、包路由(NAT网络地址转换、LBFO负载平衡和失效替换)。如果修改了封包的内容的话,例如端口转发,需要重新修正校验和调整缓冲区和长度等相关信息。修改时需要注意字节顺序的问题。

    示例驱动程序加载方式:控制面板 -> 网络连接 -> 本地连接 -> 属性 -> 安装 -> 服务 -> 添加 -> 从磁盘安装 -> 选择我们inf文件,忽略一切警告一路确定即可。
    示例驱动仅仅解析并打印TCP/IP的协议格式和封包数,如下图。更有趣的过滤规则大家自行探索吧!
    今天就讲到这吧,累挂了,希望能对和我一样的菜菜有所帮助吧。

passthru.zip

[课程]FART 脱壳王!加量不加价!FART作者讲授!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (31)
雪    币: 88
活跃值: (62)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
占楼备用   
2012-5-28 12:30
0
雪    币: 292
活跃值: (153)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
太空步滑过。。。。。  暗组的   西域 写过一个差不多的~  不过不是很RIA。。。

需要的下载~

NDISWDM驱动学习笔记.zip
上传的附件:
2012-5-28 12:33
0
雪    币: 88
活跃值: (62)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
[QUOTE=Dstlemoner;1075751]太空步滑过。。。。。  暗组的   西域 写过一个差不多的~  不过不是很RIA。。。

需要的下载~

NDISWDM驱动学习笔记.zip[/QUOTE]

这个是AntBean写的吧,内容还是有差距的。侧重点也不一样。
2012-5-28 14:14
1
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
5
好东西,谢谢楼主分享啊。
2012-5-28 19:06
0
雪    币: 602
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
很详细,正在看
2012-5-29 05:54
0
雪    币: 220
活跃值: (701)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
又一个要被+精的了
2012-5-29 09:56
0
雪    币: 1233
活跃值: (907)
能力值: ( LV12,RANK:750 )
在线值:
发帖
回帖
粉丝
8
不错的说,呵呵
2012-5-29 16:22
0
雪    币: 1683
活跃值: (674)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
很详细,LZ辛苦
2012-5-30 12:06
0
雪    币: 107
活跃值: (326)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
非常好的科普帖子。。。。。。
2012-5-30 12:10
0
雪    币: 322
活跃值: (113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
感谢分享,学习了!!
2012-6-1 16:17
0
雪    币: 58
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
哟哟哟哟哟 顶顶顶顶
2012-6-2 09:35
0
雪    币: 289
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
感谢楼主分享,我也在搞,但是没搞出来!!!楼主能告诉我一下,你看的是哪些书学的吗?
2012-6-2 15:52
0
雪    币: 88
活跃值: (62)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
14
寒江独钓最后三章,耐心慢慢看吧。呵呵。
2012-6-2 20:13
0
雪    币: 165
活跃值: (1431)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
思路清晰,学得还不错
2012-6-4 12:13
0
雪    币: 321
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
STATUS_DRAP --> STATUS_DROP
图很漂亮 用啥子画的?
2012-6-5 11:02
0
雪    币: 274
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
不错,好好学习~~
2012-6-8 09:19
0
雪    币: 223
活跃值: (80)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
64位WIN7支持吗
2012-6-11 15:18
0
雪    币: 88
活跃值: (62)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
19
没玩过x64,有兴趣可以自行测试下。
2012-6-11 17:51
0
雪    币: 156
活跃值: (27)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
科普NDIS。又学习了
2012-7-10 09:48
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
21
看到了,顺便学习下,顶一个
2012-7-10 10:26
0
雪    币: 230
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
22
辛苦了,楼主
2012-7-11 13:14
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
感谢分享,来学习一下
2013-3-11 16:30
0
雪    币: 30
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
mark!!
2013-3-11 23:52
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
感谢分享经验
2013-3-19 14:30
0
游客
登录 | 注册 方可回帖
返回
//