
常用软件类: |
|杀毒安全 | |联络聊天 | |网络软件 | |多媒体类 | |系统工具 | |图形图像 | |系统工具 | |应用软件 | |行业软件 |
开发设计类: |
|动画制作 | |图像处理 | |3D设计 | |操作系统 | |站长学院 | |网络相关 | |WEB设计 | |数据库类 | |程序开发 |
摘要:本文介绍一个用C语言和网络数据包分析开发工具实现的简易网络Sniffer。
关键词:网络;数据包;Sniffer
引言
目前,已经有不少的Sniff工具软件,如Windows环境下,最富盛名的工具是Netxray和Sniffer pro,用它们在 Windows环境下抓包来分析,非常方便。在UNIX环境下如Sniffit,Snoop,Tcpdump,Dsniff 等都是比较常见的。这里介绍一个用C语言和网络数据包和分析开发工具libpcap及winpcap实现的简易网络Sniffer。
网络嗅探器程序框图
首先给出流程如图1所示。
图1 流程图
网络嗅探器程序实现
在c环境下编程,源码如下:
| /* June 2nd,2002 * Project for graduation qualification By Bby Team 19 */ #include <stdio.h> #include <conio.h> //必须加路径,必须把头文件packet32.h包含进去 #include "..\..\Include\packet32.h" #include "..\..\Include\ntddndis.h" #define Max_Num_Adapter 10 // Prototypes原形 //发包 void PrintPackets(LPPACKET lpPacket); //设备列表 char AdapterList[Max_Num_Adapter][1024]; // 主程序开始 int main() { //define a pointer to an ADAPTER structure设备指针 LPADAPTER lpAdapter = 0; //define a pointer to a PACKET structure包指针 LPPACKET lpPacket; int i; DWORD dwErrorCode; DWORD dwVersion; DWORD dwWindowsMajorVersion; //Unicode strings (WinNT) WCHAR AdapterName[8192]; //网络适配器设备列表 WCHAR *temp,*temp1; //ASCII strings (Win9x) char AdapterNamea[8192]; //网络适配器设备列表 char *tempa,*temp1a; int AdapterNum=0,Open; ULONG AdapterLength; char buffer[256000]; // 容纳来自驱动器的数据的缓冲区 struct bpf_stat stat; // 获得本机网卡名 AdapterLength=4096; printf("Packet.dll test application. Library version:%s\n", PacketGetVersion()); printf("Adapters installed:\n"); i=0; |
下面这段代码是用来在不同版本下得到网络适配器名:
Win9x 和WinNT中的网卡名称是分别用ASCII和UNICODE实现的,所以首先要得到本地操作系统的版本号:
| dwVersion=GetVersion(); dwWindowsMajorVersion= (DWORD)(LOBYTE(LOWORD(dwVersion))); |
| if (!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4)) { //是Windows NT // 找不到设备列表 if(PacketGetAdapterNames(AdapterName,&AdapterLength)==FALSE){ printf("Unable to retrieve the list of the adapters!\n"); return -1; } // 找到设备列表 temp=AdapterName; temp1=AdapterName; while ((*temp!='\0')||(*(temp-1)!='\0')) { if (*temp=='\0') { memcpy(AdapterList[i],temp1,(temp-temp1)*2); temp1=temp+1; i++; } temp++; } // 显示适配器列表 AdapterNum=i; for (i=0;i<AdapterNum;i++) wprintf(L"\n%d- %s\n",i+1,AdapterList[i]); printf("\n"); } else //否则就是windows 9x,获取适配器名的方法同WinNT下 { if(PacketGetAdapterNames(AdapterNamea,&AdapterLength)==FALSE){ printf("Unable to retrieve the list of the adapters!\n"); return -1; } tempa=AdapterNamea; temp1a=AdapterNamea; while ((*tempa!='\0')||(*(tempa-1)!='\0')) { if (*tempa=='\0') { memcpy(AdapterList[i],temp1a,tempa-temp1a); temp1a=tempa+1; i++; } tempa++; } AdapterNum=i; for (i=0;i<AdapterNum;i++) printf("\n%d- %s\n",i+1,AdapterList[i]); printf("\n"); } |
| // 选择设备 do { printf("Select the number of the adapter to open : "); scanf("%d",&Open); if (Open>AdapterNum) printf("\nThe number must be smaller than %d",AdapterNum); } while (Open>AdapterNum); |
| // 打开设备 lpAdapter = PacketOpenAdapter(AdapterList[Open-1]); // 当设备无法打开时,出示错误信息: if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE)) { dwErrorCode=GetLastError(); printf("Unable to open the adapter, Error Code : %lx\n",dwErrorCode); return -1; } |
| // set the network adapter in promiscuous mode // 如果混杂模式设置失败,提示错误: if(PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE){ printf("Warning: unable to set promiscuous mode!\n"); } |
| // set a 512K buffer in the driver // 当无法设置缓冲区时,提示错误: if(PacketSetBuff(lpAdapter,512000)==FALSE){ printf("Unable to set the kernel buffer!\n"); return -1; } |
| // set a 1 second read timeout // 设置1秒的读取操作超时 if(PacketSetReadTimeout(lpAdapter,1000)==FALSE){ printf("Warning: unable to set the read tiemout!\n"); |
接下来,定位设备,代码如下:
这里用到函数PacketAllocatePacket(Void)将在内存中分配一个PACKET结构并返回一个指向它的指针,但这个结构的Buffer字段还没有设定,所以应再调用PacketInitPacket函数来对其进行初始化。
| //allocate and initialize a packet structure that will be used to //receive the packets. // 当定位失败时,提示错误: if((lpPacket = PacketAllocatePacket())==NULL){ printf("\nError: failed to allocate the LPPACKET structure."); return (-1); } |
| PacketInitPacket(lpPacket,(char*)buffer,256000); |
| //main capture loop |
| // 直到有键盘键入: while(!kbhit()) { // capture the packets 捕获包 // 捕获包失败时,提示错误: if(PacketReceivePacket(lpAdapter,lpPacket,TRUE)==FALSE){ printf("Error: PacketReceivePacket failed"); return (-1); } // 打印包中的数据,调用自定义函数PrintPackets() PrintPackets(lpPacket); } |
| //print the capture statistics // 得到统计值 // 当无法从内核读取状态时,提示错误: if(PacketGetStats(lpAdapter,&stat)==FALSE){ printf("Warning: unable to get stats from the kernel!\n"); } // 打印“XX包被截取;XX包被丢弃”: else printf("\n\n%d packets received.\n%d Packets lost",stat.bs_recv,stat.bs_drop); |
| // 释放空间 PacketFreePacket(lpPacket); 用函数PacketCloseAdapter(LPADAPTER lpAdapter)来释放ADAPTER结构lpAdapter,并关闭网卡指针: // close the adapter and exit // 关闭设备退出 PacketCloseAdapter(lpAdapter); return (0); } // 主程序结束 |