○ Collation
This article was written one year ago and was not completed for some reason. Today, I sorted out shadowstar's home and accidentally found this unfinished article. Although it was a year ago, it is still not out of date and should be helpful to anyone who wants to know sniffer. My father said that everything should start and end. Today is the Dragon Boat Festival. I would like to send a message to my loved ones who are far away from each other.
I. Introduction
The last time we introduced the method of using raw socket to implement sniffer, it is relatively simple to implement, but one drawback is that it can only intercept packets above the IP layer. The data header does not contain frame information. Some special requirements cannot be met. The most important one is that ARP packets cannot be processed. The NDIS driver can be used to intercept the entire Ethernet packet, but the complicated driver can be discouraged by many people. It doesn't matter. Why don't we make good use of the ready-made stuff? In Microsoft's DDK, a packet example is provided, packet. sys can perform any operations on the NIC. packete32.dll provides a convenient interface for the application, and the complicated internal operations related to driver communication are completed by the DLL, programmers at the application layer do not need to understand these details. Unfortunately, I did it step by step using the interface provided by packet32.dll, but I still couldn't get the desired result. I grabbed the package and died there. It seems that it does not want to work for me :( or do not want to write the driver by yourself ......
Fortunately there is a set of Winpcap stuff, specifically used to capture Packets Under the Win32 platform, can be downloaded on the http://winpcap.polito.it. Besides, the interfaces are basically the same as those of Microsoft packet. Haha, this is good. The original code can be used. It will work after a try! The following describes how to use Winpcap to perform operations on the NIC and analyze the received data.
Ii. network communication structure in Windows
1. network communication structure in Windows
Figure 1 upper-layer applications include various network-based software such as IE and outlook. The Network Driver protocols include network layer and transport layer protocols supported by windows, such as TCP/IP and netbeui, NDIS is a key part of the Windows operating system's network function drive, which is described below.
2. NDIS and Its Features
NDIS (Network Driver Interface Specification) is a network driver specification jointly developed by Microsoft and 3Com, and provides a large number of operation functions. It provides services for the upper-layer protocol drivers and shields the differences between the lower-layer NICs.
NDIS supports multiple network protocols, such as TCP/IP, nwlink IPX/SPX, and netbeui, and supports multiple network adapters from different manufacturers. NDIS also supports multiple working modes, multiple processors, and a complete NDIS library ). However, all the functions provided in the library work in the core mode, and users are not allowed to perform operations directly. Therefore, you need to find another interface.
Iii. Winpcap Introduction
1. Winpcap Structure Diagram
2. Winpcap consists of three parts:
- The first module NPF (netgroup Packet Filter) is a virtual device driver file. Its function is to filter data packets and pass these data packets to the user mode module intact. This process includes some operating system-specific code.
- The second module, packet. dll, provides a common interface for the Win32 platform. Different versions of Windows have their own kernel modules and user-layer modules. Packet. dll is used to solve these differences. Programs that call packet. dll can run on different versions of Windows without recompiling.
- The third module, wpcap. dll, is independent of the operating system. It provides high-level and abstract functions.
3. packet. dll and wpcap. dll
- Packet. dll directly maps the kernel call.
- Wpcap. dll provides more friendly and powerful function calls.
4. Advantages of Winpcap
- Provides a set of standard packet capture interfaces, which are compatible with Libpcap, so that many network analysis tools on the original UNIX platform can be quickly transplanted.
Easy to develop various network analysis tools
- Various performance and efficiency optimizations are fully taken into account, including NPF kernel-level Filter support
- Supports kernel-mode statistics.
- Provides the ability to send data packets
Iv. Use of packet. dll
Winpcap homepage: http://winpcap.polito.it/you can download your driver, such as dllsand development kit. Here is just a brief introduction to the implementation of Sniffer In Winpcap, without in-depth research. You only need to install the downloaded driver on your computer and use your program to call packet. dll. Packet. dll will be copied to your system directory during installation. You can also use WinRAR to open the installation packet. dll packet.
Packet. dll provides a complete set of powerful APIs. Its Interface format is basically the same as packet32.dll provided by Microsoft DDK. If you have developed a Windows application, you cannot call the DLL. If you do not know how to use the DLL, please refer to relevant books. Create a DLL project named sniffer2 and save it to the hard disk. Copy the include and Lib directories in the development package to the project directory. If you are using Visual C ++, you can directly use the import library in Lib. Shadowstar uses C ++ builder and uses the implib tool provided by C ++ builder to generate a lib file for packet. dll. The command line is as follows:
Implib-a packet. Lib packet. dll
V. Simple implementation
Shadowstar wrote a simple demo program using C ++ builder. Here, only the main part of the code is provided. The complete code can be downloaded at http://shadowstar.126.com.
void __fastcall TMainForm::btnCtrlClick(TObject *Sender){ //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]; // string that contains a list of the network adapters WCHAR *temp,*temp1; //ascii strings (win95) char AdapterNamea[8192]; // string that contains a list of the network adapters char *tempa,*temp1a; int AdapterNum=0,Open; ULONG AdapterLength; char buffer[256000]; // buffer to hold the data coming from the driver struct bpf_stat stat; // obtain the name of the adapters installed on this machine AdapterLength=4096; ShowMessage(AnsiString("Packet.dll test application. Library version: ") + PacketGetVersion()); ShowMessage("Adapters installed:"); i=0; // the data returned by PacketGetAdapterNames is different in Win95 and in WinNT. // We have to check the os on which we are running dwVersion=GetVersion(); dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); if (!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4)) { // Windows NT if(PacketGetAdapterNames((PTSTR)AdapterName,&AdapterLength) == FALSE) { ShowMessage("Unable to retrieve the list of the adapters!/n"); return; } 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++) ShowMessage(Format(L"/n%d- %s/n",ARRAYOFCONST((i+1, AdapterList[i])))); } else //windows 95 { if(PacketGetAdapterNames((PTSTR)AdapterNamea,&AdapterLength) == FALSE) { ShowMessage("Unable to retrieve the list of the adapters!/n"); return; } 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++) ShowMessage(Format("/n%d- %s/n", ARRAYOFCONST((i+1,AdapterList[i])))); } lpAdapter = PacketOpenAdapter(AdapterList[0]); if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE)) { dwErrorCode=GetLastError(); ShowMessage(Format("Unable to open the adapter, Error Code : %lx/n", ARRAYOFCONST(((int)dwErrorCode)))); return; } // set the network adapter in promiscuous mode if(PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE) { ShowMessage("Warning: unable to set promiscuous mode!/n"); } // set a 512K buffer in the driver if(PacketSetBuff(lpAdapter,512000) == FALSE) { ShowMessage("Unable to set the kernel buffer!/n"); return; } // set a 1 second read timeout if(PacketSetReadTimeout(lpAdapter,1000)==FALSE) { ShowMessage("Warning: unable to set the read tiemout!/n"); } //allocate and initialize a packet structure that will be used to //receive the packets. if((lpPacket = PacketAllocatePacket()) == NULL) { ShowMessage("/nError: failed to allocate the LPPACKET structure."); return; } PacketInitPacket(lpPacket,(char*)buffer,256000); if (btnCtrl->Caption == "&Start") { bStop = false; btnCtrl->Caption = "&Stop"; } else { bStop = true; btnCtrl->Caption = "&Start"; } int nIndex = 0; LPIP ip; LPTCP tcp; TListItem *Item; struct bpf_hdr *hdr; int off; BYTE* buf; //main capture loop while(!bStop) { // capture the packets if(PacketReceivePacket(lpAdapter,lpPacket,TRUE)==FALSE) ShowMessage("Error: PacketReceivePacket failed"); off = 0; buf = (BYTE*)lpPacket->Buffer; while(off<lpPacket->ulBytesReceived & !bStop) { nIndex++; hdr = (struct bpf_hdr *)(buf+off); off+= hdr->bh_hdrlen; ip = (IP*)(buf + off + ETHERNET_HEADER_LENGTH); tcp = (TCP*)((BYTE*)ip + (ip->HdrLen & IP_HDRLEN_MASK)); off = Packet_WORDALIGN(off+hdr->bh_caplen); Item = lsvPacket->Items->Add(); Item->Caption = nIndex; Item->SubItems->Add(GetProtocolTxt(ip->Protocol)); Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip->SrcAddr)); Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip->DstAddr)); Item->SubItems->Add(tcp->SrcPort); Item->SubItems->Add(tcp->DstPort); Item->SubItems->Add(hdr->bh_datalen); Application->ProcessMessages(); } } //print the capture statistics if(PacketGetStats(lpAdapter,&stat)==FALSE) ShowMessage("Warning: unable to get stats from the kernel!/n"); else ShowMessage(Format("/n/n%d packets received./n%d Packets lost", ARRAYOFCONST(((int)stat.bs_recv,(int)stat.bs_drop)))); PacketFreePacket(lpPacket); // close the adapter and exit PacketCloseAdapter(lpAdapter); return;}
Vi. Conclusion
If you intercept packets on a busy network and do not set any filters, you may obtain a large number of packets, which may result in thousands of packets in one second. If the application does not perform necessary performance optimization, a large amount of data packets will be lost. The following is an optimization solution for performance.
This solution uses multiple threads to process data packets. Create a public data packet buffer pool in the program, which is a lilo queue. In the program, three threads are used for operations: one thread only captures data packets and adds the data packets obtained from the driver to the header of the data packet queue; the other thread only filters data packets, it checks the data packets at the end of the new team and checks whether the data packets meet the filtering conditions. If the data packets do not meet the conditions, it deletes the data packets from the queue. The last thread processes the data packets, it is used to send new data packets based on received data packets. Among the above three threads, the condition for minimizing data packet loss should be the highest priority of the capture thread. Of course, the specific problem is analyzed to see what the application focuses on.