您的位置:首页 > Web前端

sniffer技术原理及应用,包括编程方法和工具使用

2007-08-06 03:50 1161 查看
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.***
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:gjpland@netease.com

//
//Protocol Wrapper Version 1.05
//Author: gjp
//email:
[email]gjpland@netease.com[/email]
//

#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
希望大家有空没空有事没事常去[专题开发]版讨论问题。
专题开发版新开发网络安全和数据库版块,希望各位能人前往交流!!

作者Blog:http://blog.csdn.net/warton/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络 职场 休闲