版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
.z...课程设计Ⅰ设计报告题目:基于Winpcap的网络嗅探器的实现学号:姓名:学院:专业班级:指导教师:设计时间:指导教师评语:评定成绩:签名:日期:目录1概述31.1课程设计的目的31.2设计任务与要求31.3开发环境32系统设计的根本概念与原理32.1IP协议根本知识32.2TCP协议根本知识72.3UDP协议根本知识92.4winpcap根本知识92.5winpcap根本原理142.6MFC编程框架173基于Winpcap的单文档网络嗅探器的设计与分析203.1系统设计实现的根本原理与过程203.2系统功能设计223.3系统架构设计223.4子系统与模块设计233.4.1网络嗅探器设置模块233.4.2网络数据包的捕获模块243.4.3解析和显示模块244系统详细设计与实现244.1数据构造的设计244.2全局变量与函数的声明254.3嗅探器界面设计264.4嗅探器捕获模块的设计与实现264.5网络数据包捕获模块的设计与实现314.6解析和显示模块的设计与实现324.6.1列表视图初始化设置324.6.2从读取离线数据包并在列表视图中显示334.6.2响应用户鼠标消息,解析对应行的数据包信息。365系统调试与运行385.1winpcap函数库的安装385.2sniffer网络嗅探器的测试与运行386课程设计总结39参考文献401概述1.1课程设计的目的目的:设计一个GUI程序,实现IP、TCP、UDP数据包的捕获和解析。通过编程了解各类数据报的构造,掌握网络编程的根本原理和方法。1.2设计任务与要求本课程设计的根本内容是捕获IP,TCP,UDP数据包,通过解析数据包,理解和掌握各类数据包的构造(1)设计一个GUI程序,完成局域网数据包的捕获和IP、TCP、UDP数据包的解析;(2)捕获几个网络数据报,给出实例并分析各数据包各字段的含义;(3)说明基于Winpcap编程的根本原理、程序的总体框架,绘制每个函数的详细设计流程图。1.3开发环境标准PC机,Windows操作系统,vs2008集成开发环境,Winpcap函数库。2系统设计的根本概念与原理2.1IP协议根本知识IP协议介绍IP是英文InternetProtocol〔网络互连的协议〕的缩写,中文简称为“网协〞,也就是为计算机网络相互连接进展通信而设计的协议。在因特网中,它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在因特网上进展通信时应当遵守的规则。任何厂家生产的计算机系统,只要遵守IP协议就可以与因特网互连互通。IP协议的网络互连实现各个厂家生产的网络系统和设备,如以太网、分组交换网等,它们相互之间不能互通,不能互通的主要原因是因为它们所传送数据的根本单元〔技术上称之为“帧〞〕的格式不同。IP协议实际上是一套由软件程序组成的协议软件,它把各种不同“帧〞统一转换成“IP数据包〞格式,这种转换是因特网的一个最重要的特点,使所有各种计算机都能在因特网上实现互通,即具有“开放性〞的特点。IP数据报TCP/IP协议定义了一个在因特网上传输的包,称为IP数据报(IPDatagram)。这是一个与硬件无关的虚拟包,由首部和数据两局部组成,其格式如图2.1所示:数据报的数据区数据报首部数据报的数据区数据报首部图2.1IP数据报一般格式IP数据报的详细格式如图2.2所示:0371531版本首部长度效劳类型总长度标识标志片偏移生存时间协议头校验和源IP地址目的IP地址选项填充域数据局部图2.2IP数据报的详细格式IP数据报固定局部各字段含义:(1)版本占4位,指IP协议的版本。通信双方使用的IP协议版本必须一致。目前广泛使用的IP协议版本号为4〔即IPv4〕。关于IPv6,目前还处于草案阶段。(2)首部长度占4位,可表示的最大十进制数值是15。请注意,这个字段所表示数的单位是32位字长〔1个32位字长是4字节〕,因此,当IP的首部长度为1111时〔即十进制的15〕,首部长度就到达60字节。当IP分组的首部长度不是4字节的整数倍时,必须利用最后的填充字段加以填充。因此数据局部永远在4字节的整数倍开场,这样在实现IP协议时较为方便。首部长度限制为60字节的缺点是有时可能不够用。但这样做是希望用户尽量减少开销。最常用的首部长度就是20字节〔即首部长度为0101〕,这时不使用任何选项。(3)区分效劳占8位,用来获得更好的效劳。这个字段在旧标准中叫做效劳类型,但实际上一直没有被使用过。1998年IETF把这个字段改名为区分效劳DS(DifferentiatedServices)。只有在使用区分效劳时,这个字段才起作用。(4)总长度总长度指首部和数据之和的长度,单位为字节。总长度字段为16位,因此数据报的最大长度为216-1=65535字节。在IP层下面的每一种数据链路层都有自己的帧格式,其中包括帧格式中的数据字段的最大长度,这称为最大传送单元MTU(Ma*imumTransferUnit)。当一个数据报封装成链路层的帧时,此数据报的总长度〔即首部加上数据局部〕一定不能超过下面的数据链路层的MTU值。(5)标识(identification)占16位。IP软件在存储器中维持一个计数器,每产生一个数据报,计数器就加1,并将此值赋给标识字段。但这个“标识〞并不是序号,因为IP是无连接效劳,数据报不存在按序接收的问题。当数据报由于长度超过网络的MTU而必须分片时,这个标识字段的值就被复制到所有的数据报的标识字段中。一样的标识字段的值使分片后的各数据报片最后能正确地重装成为原来的数据报。(6)标志(flag)占3位,但目前只有2位有意义。标志字段中的最低位记为MF(MoreFragment)。MF=1即表示后面“还有分片〞的数据报。MF=0表示这已是假设干数据报片中的最后一个。标志字段中间的一位记为DF(Don’tFragment),意思是“不能分片〞。只有当DF=0时才允许分片。(7)片偏移占13位。片偏移指出:较长的分组在分片后,*片在原分组中的相对位置。也就是说,相对用户数据字段的起点,该片从何处开场。片偏移以8个字节为偏移单位。这就是说,每个分片的长度一定是8字节〔64位〕的整数倍。(8)生存时间占8位,生存时间字段常用的的英文缩写是TTL(TimeToLive),说明是数据报在网络中的寿命。由发出数据报的源点设置这个字段。其目的是防止无法交付的数据报无限制地在因特网中兜圈子,因而白白消耗网络资源。最初的设计是以秒作为TTL的单位。每经过一个路由器时,就把TTL减去数据报在路由器消耗掉的一段时间。假设数据报在路由器消耗的时间小于1秒,就把TTL值减1。当TTL值为0时,就丢弃这个数据报。(9)协议占8位,协议字段指出此数据报携带的数据是使用何种协议,以便使目的主机的IP层知道应将数据局部上交给哪个处理过程。(10)首部检验和占16位。这个字段只检验数据报的首部,但不包括数据局部。这是因为数据报每经过一个路由器,路由器都要重新计算一下首部检验和〔一些字段,如生存时间、标志、片偏移等都可能发生变化〕。不检验数据局部可减少计算的工作量。(11)源地址占32位。(12)目的地址占32位。IP数据报可选局部字段含义:IP首部的可变局部就是一个可选字段。选项字段用来支持排错、测量以及平安等措施,内容很丰富。此字段的长度可变,从1个字节到40个字节不等,取决于所选择的工程。*些选项工程只需要1个字节,它只包括1个字节的选项代码。但还有些选项需要多个字节,这些选项一个个拼接起来,中间不需要有分隔符,最后用全0的填充字段补齐成为4字节的整数倍。2.2TCP协议根本知识〔1〕TCP协议介绍TCP:TransmissionControlProtocol〔传输控制协议〕TCP是一种面向连接〔连接导向〕的、可靠的、基于字节流的运输层通信协议。在OSI/RM模型中,它完成第四层传输层所指定的功能,UDP是同一层内另一个重要的传输协议。〔2〕TCP协议的作用在因特网协议族〔Internetprotocolsuite〕中,TCP层是位于IP层之上,应用层之下的运输层。应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分割成适当长度的报文段〔通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)的限制〕。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个字节一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应确实认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,则对应的数据〔假设丧失了〕将会被重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。首先,TCP建立连接之后,通信双方都同时可以进展数据的传输,其次,他是全双工的;在保证可靠性上,采用超时重传和稍待确认机制。在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传。在拥塞控制上,采用慢启动算法。(3)TCP报文段格式两台机器上的TCP软件之间传送的数据单元称为报文段。两台机器通过报文段的交互来建立连接、传送数据、发送确认、通告窗口大小及关闭连接。每个报文段分为两个局部:首部和数据。TCP报文格式如图2.3:0410162431源端口目的端口序号确认序号首部长度保存代码比特窗口校验和紧急指针选项填充数据图2.3TCP报文段详细格式TCP报文字段说明:源端口号〔16位〕,标识主机上发起传送的应用程序;目的端口〔16位〕标识主机上传送要到达的应用程序。序号:占32比特。用来标识从TCP源端向TCP目标端发送的数据字节流,它表示在这个报文段中的第一个数据字节。
确认序号:占32比特。只有ACK标志为1时,确认号字段才有效。它包含目标端所期望收到源端的下一个数据字节。
首部长度:占4比特。给出头部占32比特的数目。没有任何选项字段的TCP头部长度为20字节;最多可以有60字节的TCP头部。预留:由跟在数据偏移字段后的6位构成,预留位通常为0.代码比特〔U、A、P、R、S、F〕:占6比特。各比特的含义如下:
URG:紧急指针〔urgentpointer〕有效。
ACK:确认序号有效。
PSH:接收方应该尽快将这个报文段交给应用层。
RST:重建连接。
SYN:发起一个连接。
FIN:释放一个连接。
窗口大小:占16比特。此字段用来进展流量控制。单位为字节数,这个值是本机期望一次接收的字节数。
TCP校验和:占16比特。对整个TCP报文段,即TCP头部和TCP数据进展校验和计算,并由目标端进展验证。
紧急指针:占16比特。它是一个偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。
选项、填充:占32比特。可能包括"窗口扩大因子"、"时间戳"等选项。2.3UDP协议根本知识(1)UDP协议介绍UDP协议的全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据报分组、组装和不能对数据包的排序的缺点,也就是说,当报文发送之后,是无法得知其是否平安完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/效劳器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光荣已经被一些类似协议所掩盖,但是即使是在今天,UDP仍然不失为一项非常实用和可行的网络传输层协议。(2)UDP报文格式UDP报文段首部只有8个字节;详细格式见图2.401357源端口目的端口长度校验和数据图2.4UDP报文详细格式2.4winpcap根本知识(1)winpcap简介(1)Winpcap简介大多数Uni*操作系统提供了一套允许应用程序直接与网络相互联系的系统调用。这些指令对于那些需要通过网络捕获连续的包数据而不用内核进展过多的干预的包捕获应用程序非常有用。在Windows环境下,WinPcap就是这样一类工具。WinPcap是一个在Windows操作系统下的免费、公开的用于直接网络的开发工具包〔编程API〕。大多数Windows网络应用程序都是通过WinsockAPI〔Windows套接口〕这类高级编程接口网络的。这种方法允许在网络上进展简单的数据传送,因为操作系统的TCP/IP协议栈实现软件会处理底层细节〔协议操作、流程重组等等〕,并提供一个类似于读写文件的函数接口。然而,有时候“简便方法〞并不能满足实际需要。有些程序希望绕过TCP/IP协议栈,直接处理底层网络中的通信数据,它们需要对网络进展底层进展直接,即在没有类似协议栈〔TCP/IP协议栈〕的实体介入条件下对网络进展原始。基于WinsockAPI编程,应用程序是通过调用操作系统提供的编程接口TCP/IP协议栈实现网络通信的。基于WinPcap编程,网络程序实际上是绕开操作系统的TCP/IP协议栈直接通过底层网络发送数据,因此,网络程序可以实现一些更低级、更灵活的功能。(2)Winpcap的目的和用途开发WinPcap的目的是为Win32应用程序提供一种直接底层网络的能力。通过WinPcap,网络应用程序可以实现如下功能:捕获原始数据包,包括发送到本主机以及在共享网络上的数据包。数据过滤。在将数据包发送给应用程序之前按照用户的规定对捕获的数据包进展过滤。发送原始数据包。向网络发送原始数据包。数据包统计。对网络通信进展统计。上述功能都通过一个设备驱动〔这个驱动程序安装在Win32内核的网络局部〕和一组动态连接库〔DLL〕获得。所有这些功能部件都通过一个强大的编程接口来实现,应用程序能易于开发并且能移植到各种操作系统中。(3)基于Winpcap可开发的网络应用程序基于WinPcap可以开发很多网络应用程序,典型的包括:网络和协议分析软件网络监听软件网络通信量记录软件网络数据生成软件用户机网桥和路由器网络入侵探测系统网络扫描软件网络平安工具Winpcap的局限性:WinPcap可以独立于主机的协议〔如TCP/IP协议〕进展接收和发送数据包。这意味着WinPcap不能阻塞、过滤或处理本机上其它程序产生的数据。它仅仅能嗅探在网线上传输的数据包。因此,WinPcap不能在trafficshapers、QoSschedulers和个人防火墙这类应用程序中使用。Winpcap的开发和运行环境:目前,winpcap主要的开发和运行环境是windowsNT/2000/*P。由于winpcap的用户中只有很小一局部使用windows95/98/Me,并且微软也已经放弃了对win9*的开发和支持。实际上,winpcap中的面向9*系统的概念和NT系统的非常相似,只是在*些实现上有点差异,比方说9*只支持ANSI编码,而NT系统则提倡使用Unicode编码。Winpcap的组成与构造:WinPcap由一个数据包监听设备驱动程序〔NPF〕、一个底层的动态连接库〔packet.dll〕和一个高层的不依赖于操作系统的静态库〔wpcap.dll〕共三个局部构成,如图2.5所示。这里,NPF在操作系统的内核级,packet.dll、wpcap.dll在用户级。图2.5WinPcap的组成和构造图2.5WinPcap的组成和构造应用程序wpcap.dllpacket.dllNPFDeviceDriver用户层核心层网络层数据包1〕数据包监听设备驱动程序技术实现上,为了实现抓包,系统必须绕过操作系统的协议栈来在网络上传输的原始数据包〔rawpacket〕。这就要求WinPcap的一局部运行在操作系统核心内部,直接与网络接口驱动交互。由于这个局部是系统依赖〔systemdependent〕的,在Winpcap的解决方案中它被视为是一个设备驱动,称作NPF〔NetgroupPacketFilter〕。Winpcap开发小组针对Windows95,Windows98,WindowsME,WindowsNT4,Windows2000和Windows*P提供了不同版本的驱动〔在Windows95/98/ME中是V*D文件,在WindowsNT/2000中是SYS文件〕。这些驱动不仅提供了根本的特性〔例如抓包、发送原始数据包——注入数据包〕,还有更高级的特性〔例如可编程的过滤器系统和监视引擎〕。前者可以被用来约束一个抓包会话只针对网络通信中的一个子集〔例如,只捕获特殊主机产生的ftp通信数据包〕,后者提供了一个强大而简单的统计网络通信量的机制〔例如,获得网络负载或两个主机间的数据交换量〕。2〕底层的动态连接库〔packet.dll〕和高层静态库〔wpcap.dll〕为了方便编程,WinPcap必须提供一个编程接口〔API〕,这就是WinPcap的底层的动态连接库〔packet.dll〕和高层静态库〔wpcap.dll〕。这里,packet.dll提供了一个底层API,伴随着一个独立于Microsoft操作系统的编程接口,这些API可以直接用来驱动的函数;wpcap.dll导出了一组更强大的与libpcap一致的高层抓包函数库〔captureprimitives〕,这些函数使得数据包的捕获以一种与网络硬件和操作系统无关的方式进展。底层动态库运行在用户层,它将应用程序和数据包监听设备驱动程序隔离开来,使得应用程序可以不加修改地在不同的WINDOWS系统上运行。高级的静态库和应用程序编译在一起,它使用低级动态库提供的效劳,向应用程序提供完善的监听接口。Winpcap的技术细节:1〕NPF驱动网络数据包过滤器〔NetgroupPacketFilter,简称NPF〕是Winpcap的核心局部,它是Winpcap完成困难工作的核心组件。NPF负责处理网络上传输的数据包,并向上层提供各种效劳,包括数据包的捕获〔capture〕、发送〔injection〕和分析性能〔analysiscapabilities〕。2〕NPF和NDISNDIS〔NetworkDriverInterfaceSpecification〕是Windows环境下的一个定义网络适配器〔或者说成是管理网络适配器的驱动程序〕与协议驱动〔例如TCP/IP的实现〕之间通信的规*,如图2.2。基于NDIS,顶层应用〔例如TCP/IP协议〕可以发送和接收网络〔LAN或WAN〕上的数据包而不必关心特定的适配器硬件或特定的Win32操作系统版本。网卡硬件网卡驱动程序网卡硬件网卡驱动程序NDISTCP/IP协议栈实现图2.2NDIS的作用和地位①网络接口卡或NIC驱动〔NetworkinterfacecardorNICdrivers〕。NIC驱动直接收理着网络接口卡〔NIC〕。NIC驱动接下边与硬件连接,从上边表现为一个接口,该接口允许高层发送数据包到网络上,处理中断,重置NIC,停顿NIC,查询和设置驱动的运行特征。NIC驱动可以是小端口〔miniport〕或完全的NIC驱动〔fullNICdriver〕。Miniport驱动仅仅实现了管理NIC的必要操作,包括在NIC上发送和接收数据。对于所有最底层的NIC驱动的操作由NDIS提供,例如同步〔synchronization〕。小端口〔miniport〕不直接调用操作系统函数,它们对于操作系统的接口是NDIS。完全NIC驱动〔FullNICdriver〕完成硬件细节的操作和所有由NDIS完成的同步和查询操作。例如,完全NIC驱动维持接收到的数据的绑定信息。②中间层驱动〔Intermediatedrivers〕中间层驱动位于高层驱动〔例如协议驱动〕和小端口之间。对于高层驱动,中间层驱动看起来像是小端口;对于小端口,中间层驱动看起来像协议驱动。一个中间层协议驱动可以位于另一个中间层驱动之上,尽管这种分层可能对系统性能带来负面影响。③传输驱动或协议驱动〔Transportdriversorprotocoldrivers〕协议驱动实现了网络协议栈。在协议驱动的上面,它为应用层客户程序效劳;在它的下面,它与一个或多个NIC驱动或中间层NDIS驱动连接。3〕NPF在Windows系统中的位置如图2.6,NPF是一个协议驱动。从性能方面来看,这不是最好的选择,但是它合理地独立于MAC层并且有权使用原始通信〔rawtraffic〕。可以看出,NPF在NDIS之上,它与TCP/IP协议栈的实现在同一层次。因此,应用程序不通过Winsock也可以实现数据的发送和承受。图2.6图2.6NPF在Windows系统中的位置基于Winsock的应用程序NPFTCP/IP协议实现NICDriver〔NDIS3.0或更高〕核心层网络层数据包基于Wincap的应用程序2.5winpcap根本原理抓包是WinPcap的根本功能,也是NPF最重要的操作。在抓包的时候,驱动〔例如NICDriver〕使用一个网络接口监视着数据包,并将这些数据包完整无缺地投递给用户级应用程序。如图2.7,WinPcap的NPF抓包主要依靠两个组件。1〕数据包过滤器〔filter〕。数据包过滤器决定是否接收进来的数据包并把数据包拷贝给监听程序。数据包过滤器是一个有布尔输出的函数。如果函数值是true,抓包驱动拷贝数据包给应用程序;如果是false,数据包将被丢弃。NPF数据包过滤器更复杂一些,因为它不仅决定数据包是否应该被保存,而且还决定要保存的字节数。应用程序采用用户自定义的过滤器并使用wpcap.dll将它们编译进BPF程序。然后,应用程序使用BIOCSETFIOCTL写入核心态的过滤器。这样,对于每一个到来的数据包该程序都将被执行,而满足条件的数据包将被接收。与传统解决方案不同,NPF不解释〔interpret〕过滤器,而是执行〔e*ecute〕它。由于性能的原因,在使用过滤器前,NPF提供一个JIT编译器将它转化本钱地的80*86函数。当一个数据包被捕获,NPF调用这个本地函数而不是调用过滤器解释器,这使得处理过程相当快。2〕循环缓冲区〔Buffer〕。NPF的循环缓冲区用来保存数据包以免丧失〔如果一个包符合过滤器的要求,就被复制到循环缓冲区〕。一个保存在缓冲区中的数据包有一个头,它包含了一些主要的信息,例如时间戳和数据包的大小,注意:它不是协议头。另外,循环缓冲区以队列插入的方式来保存数据包,提高数据的存储效率。程序员可以以组的方式将数据包从NPF缓冲区拷贝到应用程序,这样就提高了性能,因为它降低了读的次数。如果一个数据包到来的时候缓冲区已经满了,则该数据包将被丢弃,这时就发生了丢包现象。3〕NetworkTap是一个用于探听网络中所有数据流的函数。4〕数据统计如图2.7,为了提高数据处理的速度,WinPcap将统计和监听功能移到内核中,这样防止了将任何数据都传递给用户。WinPcap通过使用从NPF中得到的过滤器来执行一个内核级的可编统计模块,这使其变成一个强大的分级引擎,而不只是个简单的包过滤器。应用程序可以构造这个模块来监听网络活动的任意方面〔例如:网络负荷、两台主机间的流量、每秒web请求的次数等等〕,并在预定的时间间隔内接收内核传来的数据。图2.7图2.7Wincap的内部构造和原理基于Winpcap的监控程序packet.dllwpcap.dllNICDriver〔NDIS3.0或更高〕核心层网络层数据包基于Winpcap的应用程序1Filter1Filter2Filter3…Buffer1Buffer2统计引擎NetworkTapTCP/IP协议栈其他协议栈实现User-Buffer1User-Buffer2基于Winpcap的应用程序2NPF调用packet.dllAPI的程序直接NPF的程序用户层(4)基于Winpcap的网络编程——编程API接口的选择如前所述,WinPcap由三局部模块组成——NPF、packet.dll和wpcap.dll。编程方面,我们主要使用packet.dll和wpcap.dll提供的编程接口。基于packet.dll编写的程序可以不经过重新编译就在各种Win32平台下实现捕获数据包。另外,packet.dll还包含了其他一些函数,它可以进展一些底层的操作,如获取网络适配器名或动态的加载驱动程序。通过packet.dll还可以取得一些系统信息,如主机的MAC地址、一些硬件计数,例如以太网上冲突次数等。packet.dll和NPF都严重依赖于操作系统,并且由于Windows95/98和WindowsNT/2000之间OS构造的不同而在不同版本的操作系统上有所不同。为了提高应用程序的可移植性,WinPcap提供了基于wpcap.dll的编程方式。这里,wpcap.dll不依赖于操作系统,它包含了一些其它高层的函数,比方:过滤器生成器、用户定义的缓冲区和高层特性〔数据统计和构造数据包〕。wpcap.dll能自动调用packet.dll。一个“高层〞调用会被译成几个NPF系统调用。程序员一般使用wpcap.dll,只有在为数不多的程序中才直接使用packet.dll。2.6MFC编程框架MFC(MicrosoftFoundationClassLibrary)中的各种类结合起来构成了一个应用程序框架,它的目的就是让程序员在此根底上来建立Windows下的应用程序,这是一种相对SDK来说更为简单的方法。因为总体上,MFC框架定义了应用程序的轮廓,并提供了用户接口的标准实现方法,程序员所要做的就是通过预定义的接口把具体应用程序特有的东西填入这个轮廓。MicrosoftVisualC++提供了相应的工具来完成这个工作:AppWizard可以用来生成初步的框架文件〔代码和资源等〕;资源编辑器用于帮助直观地设计用户接口;ClassWizard用来协助添加代码到框架文件;最后,编译,则通过类库实现了应用程序特定的逻辑。MFC类的封装构成MFC框架的是MFC类库。MFC类库是C++类库。这些类或者封装了Win32应用程序编程接口,或者封装了应用程序的概念,或者封装了OLE特性,或者封装了ODBC和DAO数据的功能,等等,分述如下。对Win32应用程序编程接口的封装用一个C++Object来包装一个WindowsObject。例如:classCWnd是一个C++windowobject,它把Windowswindow(HWND)和Windowswindow有关的API函数封装在C++windowobject的成员函数内,后者的成员变量m_hWnd就是前者的窗口句柄。对应用程序概念的封装使用SDK编写Windows应用程序时,总要定义窗口过程,登记WindowsClass,创立窗口,等等。MFC把许多类似的处理封装起来,替程序员完成这些工作。另外,MFC提出了以文档-视图为中心的编程模式,MFC类库封装了对它的支持。文档是用户操作的数据对象,视图是数据操作的窗口,用户通过它处理、查看数据。对/OLE特性的封装OLE建立在模型之上,由于支持OLE的应用程序必须实现一系列的接口〔Interface〕,因而相当繁琐。MFC的OLE类封装了OLEAPI大量的复杂工作,这些类提供了实现OLE的更高级接口。对ODBC功能的封装以少量的能提供与ODBC之间更高级接口的C++类,封装了ODBCAPI的大量的复杂的工作,提供了一种数据库编程模式。MFC类的继承首先,MFC抽象出众多类的共同特性,设计出一些基类作为实现其他类的根底。这些类中,最重要的类是CObject和CCmdTarget。CObject是MFC的根类,绝大多数MFC类是其派生的,包括CCmdTarget。CObject实现了一些重要的特性,包括动态类信息、动态创立、对象序列化、对程序调试的支持,等等。所有从CObject派生的类都将具备或者可以具备CObject所拥有的特性。CCmdTarget通过封装一些属性和方法,提供了消息处理的架构。MFC中,任何可以处理消息的类都从CCmdTarget派生。针对每种不同的对象,MFC都设计了一组类对这些对象进展封装,每一组类都有一个基类,从基类派生出众多更具体的类。这些对象包括以下种类:窗口对象,基类是CWnd;应用程序对象,基类是CwinThread;文档对象,基类是Cdocument,等等。程序员将结合自己的实际,从适当的MFC类中派生出自己的类,实现特定的功能,到达自己的编程目的。虚拟函数和动态约束MFC以“C++〞为根底,自然支持虚拟函数和动态约束。但是作为一个编程框架,有一个问题必须解决:如果仅仅通过虚拟函数来支持动态约束,必然导致虚拟函数表过于臃肿,消耗内存,效率低下。例如,CWnd封装Windows窗口对象时,每一条Windows消息对应一个成员函数,这些成员函数为派生类所继承。如果这些函数都设计成虚拟函数,由于数量太多,实现起来不现实。于是,MFC建立了消息映射机制,以一种富有效率、便于使用的手段解决消息处理函数的动态约束问题。这样,通过虚拟函数和消息映射,MFC类提供了丰富的编程接口。程序员继承基类的同时,把自己实现的虚拟函数和消息处理函数嵌入MFC的编程框架。MFC编程框架将在适当的时候、适当的地方来调用程序的代码。本书将充分的展示MFC调用虚拟函数和消息处理函数的内幕,让读者对MFC的编程接口有清晰的理解。MFC的宏观框架体系如前所述,MFC实现了对应用程序概念的封装,把类、类的继承、动态约束、类的关系和相互作用等封装起来。这样封装的结果对程序员来说,是一套开发模板〔或者说模式〕。针对不同的应用和目的,程序员采用不同的模板。例如,SDI应用程序的模板,MDI应用程序的模板,规则DLL应用程序的模板,扩展DLL应用程序的模板,OLE/ACTIVE*应用程序的模板,等等。这些模板都采用了以文档-视为中心的思想,每一个模板都包含一组特定的类。典型的MDI应用程序的构成将在下一节具体讨论。为了支持对应用程序概念的封装,MFC内部必须作大量的工作。例如,为了实现消息映射机制,MFC编程框架必须要保证首先得到消息,然后按既定的方法进展处理。又如,为了实现对DLL编程的支持和多线程编程的支持,MFC内部使用了特别的处理方法,使用模块状态、线程状态等来管理一些重要信息。虽然,这些内部处理对程序员来说是透明的,但是,懂得和理解MFC内部机制有助于写出功能灵活而强大的程序。总之,MFC封装了Win32API,OLEAPI,ODBCAPI等底层函数的功能,并提供更高一层的接口,简化了Windows编程。同时,MFC支持对底层API的直接调用。MFC提供了一个Windows应用程序开发模式,对程序的控制主要是由MFC框架完成的,而且MFC也完成了大局部的功能,预定义或实现了许多事件和消息处理,等等。框架或者由其本身处理事件,不依赖程序员的代码;或者调用程序员的代码来处理应用程序特定的事件。MFC是C++类库,程序员就是通过使用、继承和扩展适当的类来实现特定的目的。例如,继承时,应用程序特定的事件由程序员的派生类来处理,不感兴趣的由基类处理。实现这种功能的根底是C++对继承的支持,对虚拟函数的支持,以及MFC实现的消息映射机制。3基于Winpcap的单文档网络嗅探器的设计与分析3.1系统设计实现的根本原理与过程基于winpcap捕获数据的机理运用以太网数据捕获的原理使得信息捕获系统能够拦截到我们所要的信息,这是捕获数据包的物理根底。在网络数据包的捕获过程中,首先,数据包捕获系统必须绕过操作系统的协议栈来在网络上传输的原始数据包,这就要求一局部程序要运行在操作系统核心内部,直接与网络接口驱动交互。这个局部是系统依赖的,在WinPcap的解决方案里它是由内核级的数据包监听设备驱动程序NPF实现的。WinPcap开发小组针对不同版本的Windows操作系统提供了不同的驱动。这些驱动不仅提供了根本的特性,例如抓包和injection;还有更高级的特性,例如可编程的过滤器系统和监视引擎等。其次,数据包捕获系统必须有用户级的程序接口,通过这些接口,用户程序可以利用内核驱动提供的高级特性。在WinPcap的解决方案中是由两个不同的库:Packet.dll和Wpcap.dll库来实现的。WinPcap的优势在于提供了一套标准的抓包接口与libpcap兼容,可使得原来许多UNI*平台下的网络分析工具快速移植过来便于开发各种网络分析工具,充分考虑了各种性能和效率的优化,包括对于NPF内核层次上的过滤器支持,支持内核态的统计模式,提供了发送数据包的能力。前者提供了一个底层API,伴随着一个独立于Windows操作系统的编程接口,这些API可以直接用来驱动的函数;后者导出了一组更强大的与libpcap一致的高层抓包函数库〔captureprimitives〕。这些函数使得WinPcap在数据包的捕获过程中可以以一种与网络硬件和操作系统无关的方式进展。基于winpcap数据包捕获的过程在利用WinPcap捕获分析网络数据时,主要是调用Packet.dll和Wpcap.dll中提供的API函数进展操作。以下是基于WinPcap的网络数据包捕获流程及相应的WinPcap库函数。获取网络适配器信息利用WinPcap捕获数据包的第一步是要获得本地的网络适配器〔网卡〕列表。WinPcap提供Pcap_findalldevs()和Pcap_findalldev_e*()这两个函数来实现些功能,这两个API函数都返回一个pcap_if构造列表,列表的每项内容都含有全面的网卡信息,尤其是字段名字和含有名字的描述以及有关驱动器的易读信息。设置并编译过滤器WinPcap使用的过滤规则兼容Tcpdump的过滤规则,它提供一种高效的方法来捕获网络数据包的*些数据,且常和系统的捕获机制相集成。函数Pcap_pile()和Pcap_setfilter()用来实现过滤数据的功能。Pcap_pile()来编译一个过滤设备,它通过一个高层的boolean型变量和字串产生一系列的能够被底层驱动所解释的二进制编码。boolean表示语法能够在这个文件的过滤表示语法中找到。pcap_setfilter()用来联系一个在内核驱动上过滤的过滤器,这时所有网络数据包都将流经过滤器,并拷贝到应用程序中。翻开网络设备使用函数Pcap_open()或者Pcap_open_line()。函数有三个参数snaplen、promisc、to_ms。snaplen用于指定要捕获数据包的长度,最大为65535,如果设定一个值,则捕获到大于这个设定值的数据时,后面的数据会被截断掉。Promisc表示是否把网卡设置为混杂模式,如果是1表示设为混杂模式,在通常情况下网卡只承受发往它的数据包而忽略发往其他主机的数据包。但网卡处于混杂模式时它将接收所有的流经它的数据包,这就意味着在共享介质的情况下我们可以捕获到其它主机的数据包;大局部的数据包捕获程序都将混杂模式设为默认。to_ms参数指定读数据的超时控制,超时以毫秒计算,当在超时时间内网卡上没有数据到来时对网卡的读操作将返回。捕获数据包一旦网卡被翻开,就可以调用Pcap_ne*t(),Pacp_ne*t_e*()或Pcap_loop()进展数据包的捕获。Pcap_ne*t()和Pacp_ne*t_e*()表示捕获一个可用数据包就返回;而Pcap_loop()表示捕获多个数据包,可以循环捕获数据包,直到出现错误为止。这三个函数都有返回一个指向Pcap_pkthdr构造的指针,Pcap_ne*t()与Pcap_ne*t_e*()的功能相似,不过后者只在win32环境下运行。读取离线数据包pcap_dump_open()被用来翻开一个savefile以供写入数据包。pcap_open_offlin〔〕被用来翻开savefile,并用pcap_ne*t〔〕来逐条读取数据包。3.2系统功能设计本系统的根本功能为实现网络数据包的捕获,并将其数据内容解析显示;网络数据包捕获功能主要负责从网络中捕获和过滤数据,这可以通过调用Winpcap提供的丰富的API函数来实现;数据解析及显示局部主要负责界面数据转化、解析、处理、格式化、协议分析等,这一局部主要通过MFC来设计一个单文档图形用户界面GUI,解析结果将通过MFC的类库显示到GUI中。3.3系统架构设计网络嗅探器的整体设计由三个模块组成,自底向上分别是嗅探器设置模块,数据包捕获模块,解析和显示模块;嗅探器设置模块主要调用Winpcap提供的API,分为获取网络设备信息,设置并编译过滤器,翻开网络设备三个步骤;数据包捕获模块创立了新的线程,利用了Winpcap的非回调函数pcap_ne*t_e*()函数从Winpcap底层驱动的数据缓冲区中读取数据包。并将数据包存储在系统临时文件中,以便之后的分析。用pcap_open_offline()函数从离线文件中读取包。读取到的任意一个符合捕获条件数据包,将其内容解析,并显示本数据包;捕获完成后,进入解析和显示模块。网络嗅探器总体构造如图3.1解析和显示模块解析和显示模块网络数据包捕获网络数据包捕获嗅探器设置模块嗅探器设置模块以太网网络适配器以太网网络适配器图3.1网络嗅探器总体构造3.4子系统与模块设计网络嗅探器设置模块该局部分为三个子过程:1〕获取已连接的网络设备列表,WinPcap提供了pcap_findalldevs_e*()函数,这个函数返回一个pcap_if构造的链表,每个这样的构造都包含了一个适配器的详细信息。2〕翻开网络设备,Winpcap提供了pcap_open()函数,该函数第一参数制定要捕获数据包的哪些局部,第二参数用来制定适配器是否为混杂模式,第三参数为读取数据的超时时间,当适配器被翻开后,就可以进展捕获工作了;3〕设置过滤器,Winpcap中用来过滤数据包的函数是pcap_pile()和pcap_setfilter()。pcap_pile()它将一个高层的布尔过滤表达式编译成一个能够被过滤引擎所解释的低层的字节码。pcap_setfilter()将一个过滤器与内核捕获会话相关联。当pcap_setfilter()被调用时,这个过滤器将被应用到来自网络的所有数据包,并且,所有的符合要求的数据包(即那些经过过滤器以后,布尔表达式为真的包),将会立即复制给应用程序。网络数据包的捕获模块该局部创立了一个用于捕获数据包的线程,在该线程中调用Winpcap提供的pcap_ne*t_e*()函数从底层驱动数据缓冲区中读取数据包,该函数承受已翻开的网络设备句柄,返回捕获数据包的实体。并用pcap_dump()函数将每一个数据包写入临时文件中。解析和显示模块该局部在接收到用户发出的捕获完成消息后,将数据包从离线文件中逐条取出并进展解析和显示。将解析完毕数据包中的各项内容填入已经预先声明的协议的数据构造中,包括〔序号,捕获时间,以太帧长度,传输层协议,源IP地址,目的IP地址,源MAC地址,目的MAC地址〕,然后将数据构造添加到列表视图中。4系统详细设计与实现4.1数据构造的设计以太帧协议首部/*以太网首部*/typedefstructeth_header{ u_chardestMac[6];//源MAC地址 u_charsourceMac[6]; //目的MAC地址 u_charethType[2]; //类型}eth_header;IP协议首部/*IPv4首部*/typedefstructip_header{u_charver_ihl;//版本(4bits)+首部长度(4bits)u_chartos;//效劳类型(Typeofservice)u_shorttlen;//总长(Totallength)u_shortidentification;//标识(Identification)u_shortflags_fo;//标志位(Flags)(3bits)+段偏移量(Fragmentoffset)(13bits)u_charttl;//存活时间(Timetolive)u_charproto;//协议(Protocol)u_shortcrc;//首部校验和(Headerchecksum)ip_addresssaddr;//源地址(Sourceaddress)ip_addressdaddr;//目的地址(Destinationaddress)u_intop_pad;//选项与填充(Option+Padding)}ip_header;TCP协议首部/*TCP首部*/typedefstructtcp_header{u_shortsport;/*源端口*/u_shortdport;/*目的端口*/u_intseq;/*序号*/u_intack;/*确认号*/u_shortoff_res;/*数据偏移+保存+URG+ACK+PSH+RST+SYN+FIN*/*defineTH_FIN0*01/*FIN:释放一个连接*/*defineTH_SYN0*02/*SYN:发起一个连接*/*defineTH_RST0*04/*RST:重建连接*/*defineTH_PSH0*08/*PSH:接收方应该尽快将这个报文段交给应用层*/*defineTH_ACK0*10/*ACK:确认序号有效。*/*defineTH_URG0*20/*URG:紧急指针〔urgentpointer〕有效*/u_shortwindow;/*窗口*/u_shortchecksum;/*校验和*/u_shorturp;/*紧急指针*/}tcp_header;UDP协议首部/*UDP首部*/typedefstructudp_header{u_shortsport;//源端口(Sourceport)u_shortdport;//目的端口(Destinationport)u_shortlen;//UDP数据包长度(Datagramlength)u_shortcrc;//校验和(Checksum)}udp_header;IP地址typedefstructip_address{u_charbyte1;u_charbyte2;u_charbyte3;u_charbyte4;}ip_address;4.2全局变量与函数的声明pcap_t*adhandle;BOOLisStart=FALSE;//是否启动了捕获程序intm_filter(0);//定义的过滤器intm_paum(0);//捕包总数constchar*m_filepath;//存储文件路径BOOLm_cinpromiscuousmode(false);//是否为混杂模式UINTCappacketlivethread(LPVOIDpParam);//捕获数据包线程pcap_dumper_t*dumpfile;//open_dump指针4.3嗅探器界面设计在CMainFrame类里面重载OnCreateClient函数,添加如下的代码:m_splitter.CreateStatic(this,2,1);
m_splitter.CreateView(0,0,RUNTIME_CLASS(CSetupdlgView),CSize(400,400),pConte*t);
m_splitter.CreateView(1,0,RUNTIME_CLASS(CViewDown),CSize(200,200),pConte*t);m_splitter是一个声明的CSplitterWnd变量,来将主窗口切分为两局部。视图的上面局部是从CListView派生的,用来显示捕获到的数据包的信息,下面局部嵌入了一个从CFormView继承的Dialog,用来响应用户单击选择列表所对应的数据包并做出具体分析。界面如图4.1所示:图4.STYLEREF5\s错误!文档中没有指定样式的文字。.SEQ图表\*ARABIC\s51嗅探器初始界面4.4嗅探器捕获模块的设计与实现捕获条件设置对话框的设计,效果如图4.2所示。检测并列表显示主机上网卡接口名称。图4.2捕获条件设置对话框具体实现代码如下:BOOLetCard::OnInitDialog(){ CDialog::OnInitDialog();pcap_if_t*alldevs;//设备索引指针pcap_if_t*d;intm_devnum=0;//设备索引m_inpromiscuousmode=1;//是否为混杂模式charerrbuf[PCAP_ERRBUF_SIZE];if(pcap_findalldevs(&alldevs,errbuf)==-1){Af*MessageBo*("Errorinpcap_findalldevs");Af*MessageBo*(errbuf);}for(d=alldevs;d;d=d->ne*t){if(d->description){m_cinterface.AddString(d->description);}elseAf*MessageBo*("Nodescriptionavailable");m_devnum++;}m_cfilter.AddString("udp");m_cfilter.AddString("tcp");m_cfilter.AddString("ip");((CButton*)GetDlgItem(IDC_CHECK1))->SetCheck(1);//将控制混杂模式的单项选择按扭初始为选中状态 returnTRUE;//returnTRUEunlessyousetthefocustoacontrol //异常:OC*属性页应返回FALSE}用户通过单击菜单栏的“捕获设置〞选项或工具栏的“设置〞按扭,来翻开捕获条件设置对话框,实现嗅探器的设置。如图4.3所示。程序获得用户设置信息,并对应设置过滤器,做好捕获数据包前的所有准备。图4.3用户设置捕获条件具体实现代码如下:voidCSetupdlgView::OnNcard(){//TODO:在此添加命令处理程序代码 etCarddlg; CStringm_prot;//存储用户所设置的过滤协议intdlgReturn; pcap_if_t*alldevs;//适配器索引指针 pcap_if_t*d;inti=0;charpfilter[10];//存储用户所设置的过滤协议 u_intnetmask;structbpf_programfcode;charerrbuf[PCAP_ERRBUF_SIZE];dlgReturn=dlg.DoModal();//接收用户设置信息if(IDOK==dlgReturn) {intm_devinde*=0;intm_filter=0; m_devinde*=dlg.m_devinde*; m_filter=dlg.m_filter; m_cinpromiscuousmode=dlg.m_inpromiscuousmode;if(pcap_findalldevs(&alldevs,errbuf)==-1) { CStringtemp; temp.Format("pcap_findalldevs出错:%s",errbuf); MessageBo*(temp);return; }for(d=alldevs;i<m_devinde*;d=d->ne*t,i++);if(m_cinpromiscuousmode==1)adhandle=pcap_open(d->name,//设备名65536,//指明最大可抓取的字节长度。//65535保证能捕获到不同数据链路层上的每个数据包的全部内容PCAP_OPENFLAG_PROMISCUOUS,//混杂模式500,//读取超时时间NULL,//远程机器验证errbuf//错误缓冲池);else adhandle=pcap_open(d->name,//设备名65536,//要捕捉的数据包的局部//65535保证能捕获到不同数据链路层上的每个数据包的全部内容0,//非混杂模式500,//读取超时时间NULL,//远程机器验证errbuf//错误缓冲池);if(adhandle==NULL) { CStringtemp; temp.Format(_T("不能翻开适配器.%s不支持wipcap"),d->name); MessageBo*(temp);/*释放设列表*/ pcap_freealldevs(alldevs);return; }switch(m_filter) { case0: m_prot="ip";break;case1: m_prot="tcp";break;case2: m_prot="udp";break;default:break; } lstrcpy(pfilter,m_prot);//将m_prot存储在数组中//检查工作在以太网if(pcap_datalink(adhandle)!=DLT_EN10MB) { CStringtemp; temp="不在局域网内!."; MessageBo*(temp);/*释放设备列表*/ pcap_freealldevs(alldevs);return; }//设置过滤器if(d->addresses!=NULL)/*获得接口第一个地址的掩码*/ netmask=((structsockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;else/*如果接口没有地址,则我们假设一个C类的掩码*/ netmask=0*ffffff;//编译过滤器if(pcap_pile(adhandle,&fcode,pfilter,1,netmask)<0) {//fprintf(stderr,"\nUnabletopilethepacketfilter.Checkthesynta*.\n"); MessageBo*("过滤规则出错!");/*释放设备列表*/ pcap_freealldevs(alldevs);return; }if(pcap_setfilter(adhandle,&fcode)<0) {//fprintf(stderr,"\nErrorsettingthefilter.\n"); MessageBo*("过滤规则出错!");/*释放设备列表*/ pcap_freealldevs(alldevs);return; } pcap_freealldevs(alldevs);//释放设备列表}}4.5网络数据包捕获模块的设计与实现对“开场捕获〞菜单的响应:voidCSetupdlgView::OnStart(){//TODO:在此添加命令处理程序代码if(adhandle!=NULL) { isStart=TRUE; CListCtrl&theCtrl=GetListCtrl();theCtrl.DeleteAllItems();//将列表视图清空//开场捕获线程Af*BeginThread(Cappacketlivethread,GetSafeHwnd()); }else Af*MessageBo*("请先对捕获程序进展设置!",MB_OK,0);}捕包线程函数的实现:UINTCappacketlivethread(LPVOIDpParam){structpcap_pkthdr*header;/*数据**部信息*/constu_char*pkt_data;//数据m_paum=0;//捕获包的个数 CFilem_file;if(m_file.Open("default.DAT",CFile::modeRead,NULL))//临时文件{m_file.Close();m_file.Remove("default.DAT");}m_filepath="default.DAT";dumpfile=pcap_dump_open(adhandle,m_filepath);intres=0;//当用户按下“开场〞按扭或选择“捕获开场〞菜单项选择项并满足捕获条件时,开场捕获线程while(res=(pcap_ne*t_e*(adhandle,&header,&pkt_data))>=0&&isStart){if(res==0)continue;++m_paum;pcap_dump((u_char*)dumpfile,header,pkt_data);//第捕一个数据包,就将包数据存储在临时文件中}return0;}4.6解析和显示模块的设计与实现列表视图初始化设置视图窗口列表显示初始化voidCSetupdlgView::OnInitialUpdate(){ CListView::OnInitialUpdate();//TODO:在此添加专用代码和/或调用基类 CListCtrl&theCtrl=GetListCtrl();DWORDdwStyle;dwStyle=theCtrl.GetE*tendedStyle();//GetStyle();dwStyle|=LVS_E*_FULLROWSELECT;theCtrl.SetE*tendedStyle(dwStyle);//Insertacolumn.Thisoverrideisthemostconvenient.theCtrl.InsertColumn(0,_T("序号"),LVCFMT_LEFT);theCtrl.InsertColumn(1,_T("捕获时间"),LVCFMT_LEFT);theCtrl.InsertColumn(2,_T("包长度"),LVCFMT_LEFT);theCtrl.InsertColumn(3,_T("源IP"),LVCFMT_LEFT);theCtr
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 收银对账操作流程
- 艾灸养生疗法安全指南
- 家政员心理健康辅导服务方案
- 安全风险分级管控工作指引
- 花卉采后保鲜贮藏技术规程
- 环境突发事故应急监测方案
- 化肥减量增效施用技术操作指引
- 春季玉米密植高产生产方案
- 新客户首次到店体验指南
- 牵引理疗注意事项规范
- 高三高效课堂与尖子生培养课件
- 餐厨垃圾清运服务方案
- 二氧化硫安全技术说明书msds
- GB/T 42306-2023软木粒和软木粉分类、性质和包装
- 幼儿园三年发展规划实施情况表
- 人教版六年级音乐下册教案(全册)
- GB/T 18839.1-2002涂覆涂料前钢材表面处理表面处理方法总则
- GB/T 18376.3-2015硬质合金牌号第3部分:耐磨零件用硬质合金牌号
- 关于规范贸易业务的指导意见
- 大岗山大坝接缝灌浆施工方案
- 国开大政府经济学自测题1-14章
评论
0/150
提交评论