首先,我今天來是做廣告的哦:)
很久沒有更新專欄了,關鍵是寫不出什麼好東西,也怕大家見笑!
雖然我還沒被人罵過,但我見過別人被人罵,哎。不是說,這在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: %x/nDestination: %x/nProtocol: %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/n", 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(ðer_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:[email protected]
//
//Protocol Wrapper Version 1.05
//Author: gjp
//email: [email protected]
//
#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 WanString = NDIS_STRING_CONST("NDISWAN");
NDIS_STRING DeviceWanString =
NDIS_STRING_CONST("//DEVICE//NDISWAN");
NDIS_STRING TcpipString = NDIS_STRING_CONST("Tcpip");
NDIS_STRING TcpArpString = NDIS_STRING_CONST("TCPIP_WANARP");
NDIS_STRING RasArpString = NDIS_STRING_CONST("RASARP");
if( ProtocolContent == NULL )
return;
//Get pointer to NDIS_PROTOCOL_CHARACTERISTICS from protocol
content
pProChar = (PNDIS_PROTOCOL_CHARACTERISTICS)(ProtocolContent +
0x14);
if( KeGetCurrentIrql() == PASSIVE_LEVEL )
{
//Check protocol name whether is Wan Lan protocol so that we
can correctly hook our function
if(
!RtlCompareUnicodeString(&pProChar->Name,&WanString,TRUE) ||
!RtlCompareUnicodeString(&pProChar->Name,&DeviceWanString,TRUE) )
{
IsWan = 1;
}
else
IsWan = 0;
//We r only interest in following protocol
if(
!(!RtlCompareUnicodeString(&pProChar->Name,&TcpipString,TRUE) ||
!RtlCompareUnicodeString(&pProChar->Name,&TcpArpString,TRUE) ||
!RtlCompareUnicodeString(&pProChar->Name,&RasArpString,TRUE)) )
{
return;
}
}
else
IsWan = 0;
//
if( !IsWan )
{
HookNdisFunc(HookProtocolReceive,(PVOID
*)&pProChar->ReceiveHandler,NULL,ProtocolContent);
//{{added by gjp 6.24
// __asm int 3;
// HookNdisFunc(HookSendComplete,(PVOID
*)&pProChar->SendCompleteHandler,NULL,ProtocolContent);
//}}
}
else
HookNdisFunc(HookWanReceive,(PVOID
*)&pProChar->WanReceiveHandler,NULL,ProtocolContent);
if(pProChar->MajorNdisVersion > 0x03 )
{
HookNdisFunc(HookProtocolReceivePacket,(PVOID
*)&pProChar->ReceivePacketHandler,NULL,ProtocolContent);
HookNdisFunc(HookBindAdapterHandler,(PVOID
*)&pProChar->BindAdapterHandler,NULL,ProtocolContent);
}
zihan:
Guniffer我做過修改,用線程實現,還比較好用.是bcb做的
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "SnifferThread.h"
#include "Main.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
__fastcall TSniffer::TSniffer(bool CreateSuspended)
: TThread(CreateSuspended)
{
MParamTcp = true; // 關注TCP 報文
MParamUdp = true; // 關注UDP 報文
MParamIcmp = true; // 關注ICMP報文
MParamDecode = true;
FreeOnTerminate = true;
strcpy(TcpFlag, "FSRPAU");
//TcpFlag[6]={'F','S','R','P','A','U'}; //定義TCP標誌位
strFromIpFilter = NULL; // 源IP地址過濾
strDestIpFilter = NULL; // 目的地址過濾
strSensitive = NULL; // 敏感字符串
iPortFilter = 0; // 端口過濾
RecvBuf[MAX_PACK_LEN] = NULL;
}
//---------------------------------------------------------------------------
void __fastcall TSniffer::Execute()
{
//---- Place thread code here ----
//偵聽IP報文
SnifferInit();
while(!Terminated)
{
ReceiveData();
}
Form1->ListView1->AddItem("線程結束,停止截獲...", 0);
}
void TSniffer::SnifferInit()
{
//初始化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 = (struct hostent * )malloc(sizeof(struct hostent));
pHostent = gethostbyname(name);
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);
iErrorCode = bind(SockRaw, (PSOCKADDR)&sa, sizeof(sa));
CheckSockError(iErrorCode, "bind");
//設置SOCK_RAW爲SIO_RCVALL,以便接收所有的IP包
LPVOID 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解包程序
int TSniffer::DecodeIpPack(char *buf, int iBufSize)
{
IP_HEADER *pIpheader;
SOCKADDR_IN saSource, saDest;
pIpheader = (IP_HEADER *)buf;
//協議甄別
iProtocol = pIpheader->proto;
strncpy(szProtocol, CheckProtocol(iProtocol), MAX_PROTO_TEXT_LEN);
if((iProtocol == IPPROTO_TCP) && (!MParamTcp))
return true;
if((iProtocol == IPPROTO_UDP) && (!MParamUdp))
return true;
if((iProtocol == IPPROTO_ICMP) && (!MParamIcmp))
return true;
//源地址
saSource.sin_addr.s_addr = pIpheader->sourceIP;
strncpy(szSourceIP, inet_ntoa(saSource.sin_addr), MAX_ADDR_LEN);
if (strFromIpFilter)
if (strcmp(strFromIpFilter,szSourceIP)) return true;
//目的地址
saDest.sin_addr.s_addr = pIpheader->destIP;
strncpy(szDestIP, inet_ntoa(saDest.sin_addr), MAX_ADDR_LEN);
if (strDestIpFilter)
if (strcmp(strDestIpFilter,szDestIP)) return true;
iTTL = pIpheader->ttl;
//計算IP首部的長度
int iIphLen = sizeof(unsigned long) * (pIpheader->h_lenver & 0xf);
//根據協議類型分別調用相應的函數
switch(iProtocol)
{
case IPPROTO_TCP :DecodeTcpPack(buf+iIphLen,
iBufSize);break;
case IPPROTO_UDP :DecodeUdpPack(buf+iIphLen,
iBufSize);break;
case IPPROTO_ICMP :DecodeIcmpPack(buf+iIphLen,
iBufSize);break;
default :break;
}
return true;
}
//協議識別程序
char* TSniffer::CheckProtocol(int iProtocol)
{
for(int i=0; i<MAX_PROTO_NUM; i++)
if(ProtoMap[i].ProtoNum==iProtocol)
return ProtoMap[i].ProtoText;
return "";
}
//TCP解包程序
int TSniffer::DecodeTcpPack(char * TcpBuf, int iBufSize)
{
TCP_HEADER * pTcpHeader;
int i;
int iSourcePort,iDestPort;
RECEIVEINFO *ReceiveInfo = new RECEIVEINFO;
pTcpHeader = (TCP_HEADER * )TcpBuf;
//計算TCP首部長度
int TcpHeaderLen = pTcpHeader->th_lenres>>4;
TcpHeaderLen *= sizeof(unsigned long);
char * TcpData=TcpBuf+TcpHeaderLen;
//如果過濾敏感字符串則判斷是否包含
if (strSensitive)
if ((strstr(TcpData, strSensitive))==NULL) return true;
//對端口進行過濾
iSourcePort = ntohs(pTcpHeader->th_sport);
iDestPort = ntohs(pTcpHeader->th_dport);
if ((iPortFilter) && (iSourcePort!=iPortFilter) && (iDestPort!=iPortFilter))
return true;
//輸出
//sprintf(OtherInfo, "%s ", szProtocol);
//sprintf(OtherInfo, "%15s:%5d ->%15s:%5d ", szSourceIP, iSourcePort,
szDestIP, iDestPort);
//sprintf(OtherInfo, "TTL=%3d ", iTTL);
ReceiveInfo->szProtocol = szProtocol;
ReceiveInfo->szSourceIP = szSourceIP;
ReceiveInfo->szDestIP = szDestIP;
ReceiveInfo->iSourcePort = iSourcePort;
ReceiveInfo->iDestPort = iDestPort;
ReceiveInfo->iTTL = iTTL;
//判斷TCP標誌位
unsigned char FlagMask = 1;
for( i=0; i<6; i++ )
{
if((pTcpHeader->th_flag) & FlagMask)
{
//sprintf(OtherInfo, "%c",TcpFlag[i]);
ReceiveInfo->TcpFlag[i] = TcpFlag[i];
}
else
{
//sprintf(OtherInfo, "-");
ReceiveInfo->TcpFlag[i] = '-';
}
FlagMask=FlagMask<<1;
}
//sprintf(OtherInfo, " bytes=%4d/n", iBufSize);
ReceiveInfo->iBufSize = iBufSize;
//對於長度大於40字節的包進行數據分析(IP_HEADER+TCP_HEADER=40)
if ((MParamDecode) && (iBufSize>40))
{
//分析TCP數據段
if ((!strSensitive) || (strstr(TcpData,strSensitive)))
{
//sprintf(OtherInfo, "[DATA]/n");
//sprintf(OtherInfo, "%s%s", OtherInfo, TcpData);
//sprintf(OtherInfo, "%s/n [DATA END]/n/n/n",
OtherInfo);
ReceiveInfo->ReceiveData = TcpData;
}
}
//Form1->Memo1->Lines->Add(OtherInfo);
AddReceiveData(ReceiveInfo);
delete ReceiveInfo;
return true;
}
//UDP解包程序
int TSniffer::DecodeUdpPack(char * UdpBuf, int iBufSize)
{
UDP_HEADER *pUdpHeader;
pUdpHeader = (UDP_HEADER * )UdpBuf;
int iSourcePort = ntohs(pUdpHeader->uh_sport);
int iDestPort = ntohs(pUdpHeader->uh_dport);
RECEIVEINFO *ReceiveInfo = new RECEIVEINFO;
//對端口進行過濾
if(iPortFilter)
if ((iSourcePort!=iPortFilter) && (iDestPort!=iPortFilter))
return true;
//printf("%s ", szProtocol);
//printf("%15s:%5d ->%15s:%5d ", szSourceIP, iSourcePort, szDestIP,
iDestPort);
//printf("TTL=%3d ", iTTL);
//printf("Len=%4d ", ntohs(pUdpHeader->uh_len));
//printf("bytes=%4d", iBufSize);
//printf("/n");
ReceiveInfo->szProtocol = szProtocol;
ReceiveInfo->szSourceIP = szSourceIP;
ReceiveInfo->iSourcePort = iSourcePort;
ReceiveInfo->szDestIP = szDestIP;
ReceiveInfo->iDestPort = iDestPort;
ReceiveInfo->iTTL = iTTL;
ReceiveInfo->Length = ntohs(pUdpHeader->uh_len);
ReceiveInfo->iBufSize = iBufSize;
//對於長度大於28字節的包進行數據分析(IP_HEADER+UDP_HEADER>28)
if ((MParamDecode) && (iBufSize>28))
{
//printf(" [DATA]/n");
//UDP首部長度爲8
char * UdpData=UdpBuf+8;
//分析UDP數據段
ReceiveInfo->ReceiveData = UdpData;
TStringStream *DataStringStream = new TStringStream(NULL);
try{
DataStringStream->Write(UdpData, sizeof(UdpData));
//DataStringStream->CopyFrom(UdpData, sizeof(UdpData))}
ReceiveInfo->ReceiveUdpData = DataStringStream->DataString;}
__finally{
delete DataStringStream;}
for(unsigned int i=0;i<(iBufSize-sizeof(UDP_HEADER));i++)
{
//if (!(i%8)) sprintf(OtherInfo, "%s/n", OtherInfo);
//memset(OtherInfo, 0, strlen(OtherInfo));
if ( (UdpData[i]>33) && (UdpData[i]<122) )
//sprintf(OtherInfo, "%c", UdpData[i]);
;
else
//sprintf(UdpData, "[%3x]", abs(UdpData[i]));
UdpData[i] = '_';
}
//printf("/n [DATA END]/n/n/n");
}
AddReceiveData(ReceiveInfo);
delete ReceiveInfo;
return true;
}
//ICMP解包程序
int TSniffer::DecodeIcmpPack(char * IcmpBuf, int iBufSize)
{
ICMP_HEADER * pIcmpHeader;
pIcmpHeader = (ICMP_HEADER * )IcmpBuf;
int iIcmpType = pIcmpHeader->i_type;
int iIcmpCode = pIcmpHeader->i_code;
RECEIVEINFO *ReceiveInfo = new RECEIVEINFO;
//對類型進行過濾
if ((iPortFilter) && (iIcmpType!=iPortFilter)) return true;
//printf("%s ", szProtocol);
//printf("%15s Type%d ->%15s Code%d ", szSourceIP, iIcmpType,
szDestIP, iIcmpCode);
//printf("%15s ->%15s ", szSourceIP, szDestIP);
//printf("TTL=%3d ", iTTL);
//printf("Type%2d,%d ",iIcmpType,iIcmpCode);
//printf("bytes=%4d", iBufSize);
//printf("/n");
ReceiveInfo->szProtocol = szProtocol;
ReceiveInfo->szSourceIP = szSourceIP;
ReceiveInfo->iIcmpType = iIcmpType;
ReceiveInfo->szDestIP = szDestIP;
ReceiveInfo->iIcmpCode = iIcmpCode;
ReceiveInfo->iTTL = iTTL;
ReceiveInfo->iBufSize = iBufSize;
//對於包含數據段的包進行數據分析
if ((MParamDecode) && (iBufSize>28))
{
char * IcmpData=IcmpBuf+4;
//分析ICMP數據段
//printf(" [DATA]");
//for(unsigned int i=0;i<(iBufSize-sizeof(ICMP_HEADER));i++)
//{
// if (!(i%8)) printf("/n");
// if ( (IcmpData[i]>33) && (IcmpData[i]<122) )
// printf("%3c [%3x]", IcmpData[i],
IcmpData[i]);
// else printf(" [%3x]", abs(IcmpData[i]));
//}
//printf("/n [DATA END]/n/n/n");
ReceiveInfo->ReceiveData = IcmpData;
}
AddReceiveData(ReceiveInfo);
delete ReceiveInfo;
return true;
}
//SOCK錯誤處理程序
void TSniffer::CheckSockError(int iErrorCode, char *pErrorMsg)
{
if(iErrorCode==SOCKET_ERROR)
{
//printf("%s Error:%d/n", pErrorMsg, GetLastError());
Form1->ListView1->AddItem(pErrorMsg,0);
closesocket(SockRaw);
exit(0);
}
}
void TSniffer::AddReceiveData(RECEIVEINFO *ReceiveInfo)
{
TListItem *Item;
Item = Form1->ListView1->Items->Add();
Item->Caption = ReceiveInfo->szProtocol;
Item->SubItems->Add(ReceiveInfo->szSourceIP);
Item->SubItems->Add(IntToStr(ReceiveInfo->iSourcePort));
Item->SubItems->Add(ReceiveInfo->szDestIP);
Item->SubItems->Add(IntToStr(ReceiveInfo->iDestPort));
Item->SubItems->Add(IntToStr(ReceiveInfo->iTTL));
Item->SubItems->Add(IntToStr(ReceiveInfo->iBufSize));
Item->SubItems->Add(ReceiveInfo->TcpFlag);
Item->SubItems->Add(IntToStr(ReceiveInfo->Length));
Item->SubItems->Add(ReceiveInfo->iIcmpType);
Item->SubItems->Add(ReceiveInfo->iIcmpCode);
try{
Item->SubItems->Add(ReceiveInfo->ReceiveData);
Item->SubItems->Add(ReceiveInfo->ReceiveUdpData);
}
catch(...){}
}
void TSniffer::ReceiveData()
{
memset(RecvBuf, 0, sizeof(RecvBuf));
iErrorCode = recv(SockRaw, RecvBuf, sizeof(RecvBuf), 0);
CheckSockError(iErrorCode, "recv");
iErrorCode = DecodeIpPack(RecvBuf, iErrorCode);
CheckSockError(iErrorCode, "Decode");
}
頭文件
//---------------------------------------------------------------------------
#ifndef SnifferThreadH
#define SnifferThreadH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <ComCtrls.hpp>
//---------------------------------------------------------------------------
#include <Winsock2.h>
#include "MSTcpIP.h"
#define STATUS_FAILED 0xFFFF //定義異常出錯代碼
#define MAX_PACK_LEN 655350 //接收的最大IP報文
#define MAX_ADDR_LEN 16 //點分十進制地址的最大長度
#define MAX_PROTO_TEXT_LEN 16 //子協議名稱(如"TCP")最
大長度
#define MAX_PROTO_NUM 12 //子協議數量
#define MAX_HOSTNAME_LAN 255 //最大主機名長度
#define CMD_PARAM_HELP true
typedef struct _iphdr
{
unsigned char h_lenver; //4位首部長度+4位IP版本號
unsigned char tos; //8位服務類型TOS
unsigned short total_len; //16位總長度(字節)
unsigned short ident; //16位標識
unsigned short frag_and_flags; //3位標誌位
unsigned char ttl; //8位生存時間 TTL
unsigned char proto; //8位協議 (TCP, UDP 或
其他)
unsigned short checksum; //16位IP首部校驗和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;
typedef struct _tcphdr //定義TCP首部
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
unsigned int th_seq; //32位序列號
unsigned int th_ack; //32位確認號
unsigned char th_lenres; //4位首部長度/6位保留字
unsigned char th_flag; //6位標誌位
USHORT th_win; //16位窗口大
小
USHORT th_sum; //16位校驗和
USHORT th_urp; //16位緊急數
據偏移量
}TCP_HEADER;
typedef struct _udphdr //定義UDP首部
{
unsigned short uh_sport; //16位源端口
unsigned short uh_dport; //16位目的端口
unsigned short uh_len; //16位長度
unsigned short uh_sum; //16位校驗和
} UDP_HEADER;
typedef struct _icmphdr //定義ICMP首部
{
BYTE i_type; //8位類型
BYTE i_code; //8位代碼
USHORT i_cksum; //16位校驗和
USHORT i_id; //識別號(一般
用進程號作爲識別號)
USHORT i_seq; //報文序列號
ULONG timestamp; //時間戳
}ICMP_HEADER;
typedef struct _protomap //定義子協議映射表
{
int ProtoNum;
char ProtoText[MAX_PROTO_TEXT_LEN];
}PROTOMAP;
typedef struct _receiveinfo
{
char* szProtocol;
char* szSourceIP;
int iSourcePort;
char* szDestIP;
int iDestPort;
int iTTL;
int Length;
char TcpFlag[6] ;
int iBufSize;
char iIcmpType;
char iIcmpCode;
char* ReceiveData;
AnsiString ReceiveUdpData;
}RECEIVEINFO;
PROTOMAP ProtoMap[MAX_PROTO_NUM]={ //爲子協議映射表賦值
{ IPPROTO_IP , "IP " },
{ IPPROTO_ICMP , "ICMP" },
{ IPPROTO_IGMP , "IGMP" },
{ IPPROTO_GGP , "GGP " },
{ IPPROTO_TCP , "TCP " },
{ IPPROTO_PUP , "PUP " },
{ IPPROTO_UDP , "UDP " },
{ IPPROTO_IDP , "IDP " },
{ IPPROTO_ND , "NP " },
{ IPPROTO_RAW , "RAW " },
{ IPPROTO_MAX , "MAX " },
{ NULL , "" } };
class TSniffer : public TThread
{
private:
int DecodeIpPack(char *, int); //IP解包函數
int DecodeTcpPack(char *, int); //TCP解包函數
int DecodeUdpPack(char *, int); //UDP解包函數
int DecodeIcmpPack(char *, int); //ICMP解包函數
void CheckSockError(int, char*); //出錯處理函數
char * CheckProtocol(int); //協議檢查
void SnifferInit();
void AddReceiveData(RECEIVEINFO *ReceiveInfo);
void ReceiveData();
protected:
void __fastcall Execute();
public:
SOCKET SockRaw;
bool MParamTcp; // 關注TCP 報文
bool MParamUdp; // 關注UDP 報文
bool MParamIcmp; // 關注ICMP報文
bool MParamDecode; // 對協議進行解碼
char TcpFlag[6]; //定義TCP標誌位
char *strFromIpFilter; // 源IP地址過濾
char *strDestIpFilter; // 目的地址過濾
char *strSensitive; // 敏感字符串
int iPortFilter; // 端口過濾
int iProtocol, iTTL;
char szProtocol[MAX_PROTO_TEXT_LEN];
char szSourceIP[MAX_ADDR_LEN], szDestIP[MAX_ADDR_LEN];
char OtherInfo[100];
int iErrorCode;
char RecvBuf[MAX_PACK_LEN];
__fastcall TSniffer(bool CreateSuspended);
};
//---------------------------------------------------------------------------
#endif
lovemaggic:
向大家推薦ethereal 0.9.14,它也是調用winpcap3.0,
它現在版本支持各種抓包軟件的數據文件,包括
tcpdump and Ethereal
snoop (including Shomiti) and atmsnoop
LanAlyzer
Sniffer (compressed or uncompressed)
Microsoft Network Monitor
AIX’s iptrace
NetXray
Sniffer Pro
RADCOM’s WAN/LAN analyzer
Lucent/Ascend router debug output
HP-UX’s nettl
the dump output from Toshiba’s ISDN routers
i4btrace from the ISDN4BSD project
而且它是從Linux下移植過來的,有免費的源代碼。
前幾天整理了一下winpcap的文檔,如果有誰想要的話,請到專題開發版給列留言:
http://expert.csdn.net/Expert/topic/2465/2465797.xml?temp=.4748651
希望大家有空沒空有事沒事常去[專題開發]版討論問題。
專題開發版新開發網絡安全和數據庫版塊,希望各位能人前往交流!!