Packet32包说明

 

简述:

监听网络上的所有数据,是一个比较有趣的题目。流传比较广的一些监听程序,它们都使用了一个更加著名的开发包Packet32。比如,ntsniff、EthernetSpy、ntpacket等,还有赫赫有名的WinPcap。应用程序通过它可以设置网卡的工作模式,直接在网卡上读写数据,等等。

一般使用的Packet32的实现版本,是微软的Packet32.c和Packet32.h。这个版本写得比较简单。

WinPcap开发包中自带的Packet32,是Politecnico di Torino重写的,增加了许多错误处理,而且注释翔实,值得一读。

http://winpcap.polito.it/default.htm中,WinPcap开发包被描述为:WinPcap is an architecture for packet capture and network analysis for the Win32 platforms. It includes a kernel-level packet filter, a low-level dynamic link library (packet.dll), and a high-level and system-independent library (wpcap.dll, based on libpcap version 0.6.2).

下面就给出Packet32这个实现版本的说明,仿照Microsft SDK的风格。

内容依次为:

Packet32包的内容

Packet32包中的函数

PacketGetAdapterNames

PacketOpenAdapter等

Packet32包中的数据结构

例子1:用Packet32设置网卡为混杂模式,监听所有的数据包。

Packet32包的内容

Packet驱动:Oemsetup.inf安装信息文件、Packet.sys系统文件,在利用Packet32包开发网络监控程序前,需要用这两个文件安装Packet驱动。Packet32程序开发库:Packet32.lib静态链接库、 Packet32.dll动态链接库,用户可以通过调用库中的函数直接对网卡进行操作。

Packet32包中的函数说明:

No.1. PacketGetAdapterNames(从注册表中读取网卡名)

得到现有的网络适配器的列表和它们的描述。

BOOLEAN PacketGetAdapterNames(

PTSTR pStr,

PULONG BufferSize

);

Parameters:

pStr:

[in , out] 一块用户负责分配的缓冲区,将把适配器的名字填充进去。

BufferSize:

[in] pStr这块缓冲区的大小。

Return Values:

如果查询成功,返回一个非零值。

Usage:

[C/C++]

C/C++ Usage Sample

char         AdapterNamea[8192];

ULONG     AdapterLength;

PacketGetAdapterNames(AdapterName,&AdapterLength);

Remarks:

通常,这都是与网卡通信时要调用的第一个函数。它返回系统上安装了的网卡的名字。在每个网卡的名字后面,pStr中还有一个与之相应的描述。

由于结果都是通过查询注册表得到的,所以WindowsNTx和Windows9X/Me下得到的字符串编码是不同的。Windows9X下用ASCII编码存储,而WindowsNTx则是Unicode。

如果是在Windows9X下,调用完PacketGetAdapterNames后,得到的pStr将是这样的:

-     一串用"\0"分隔的ASCII字符串,每一个都是一个网卡的名字;

-     两个"\0";

-     一串用"\0"分隔的ASCII字符串,每一个都是一个网卡的描述;顺序是和网卡名字一样的;

-     两个"\0";

如果是在WindowsNTx下,调用完PacketGetAdapterNames后,得到的pStr将是这样的:

-     一串用一个Unicode的"\0"分隔的Unicode字符串,每一个都是一个网卡的名字;

-     两个Unicode的"\0";

-     一串用ASCII的"\0"分隔的ASCII字符串,每一个都是一个网卡的描述;顺序是和网卡名字一样的;

-     两个ASCII的"\0";


 

这个函数的操作大致为:

网卡的注册表项是:

HKEY_LOCAL_MACHINE\

SYSTEM\

CurrentControlSet\

Control\

Class\

{4D36E972-E325-11CE-BFC1-08002BE10318}

先打开这个键值;

再枚举下面的每一项,依次读取参数:

对子项\Linkage\UpperBind参数,核对是否等于” NdisWan”,如果不是,就跳过去;

如果是” NdisWan”,则读取子项\Linkage\Export,这就是网卡的名字。

如果前面的查询有网卡记录,那么执行下面这个循环:

将调用PacketOpenAdapter打开每个网卡;

其中将调用PacketRequest(adapter,FALSE,OidData)来得到网卡的描述;

具体方法是这样,OidData是一个PACKET_OID_DATA结构,我们事先设置它的Oid成员为OID_GEN_VENDOR_DESCRIPTION,然后调用PacketRequest把这个OID发送给网卡driver,就可以从OidData->Data中拿到网卡的描述了。

最后调用PacketCloseAdapter关闭适配器。

如果前面没有查询到网卡记录,那么执行我们将根据TCP/IP Binding来查找网卡:

先打开这个键值;

HKEY_LOCAL_MACHINE\

SYSTEM\

CurrentControlSet\

Services\

Tcpip\

Linkage

它的Bind参数设置的就是现在系统上绑定的网卡的名字。

得到名字之后,同上调用PacketOpenAdapter和PacketRequest方法向网卡查询它的描述。

(To be continued)

Writen by zhengyun@tomosoft.com

本文档所包含的信息代表了在发布之日,ZhengYun 对所讨论问题的当前看法,Zhengyun 不保证所给信息在发布之日以后的准确性。

本文档仅供参考。对本文档中的信息,Zhengyun 不做任何明示或默示的保证。

参考文献:

1.如何编写网络监视器 作者:邹建平

2.《Windows NT下开发网络监控程序》 作者:北京锐信科学技术培训中心


 

Packet32包中的函数说明:

No.2.PacketOpenAdapter (打开网卡)

根据传入的设备名,打开它。

LPADAPTER PacketOpenAdapter(
LPTSTR AdapterName
);

Parameters:

AdapterName:

[in] 要打开的设备的名字。

Return Values:

如果打开成功,返回一个指针,它指向一个正确初始化了的ADAPTER Object。

否则,返回NULL。

Usage:

[C/C++]

C/C++ Usage Sample

LPADAPTER   adapter;

adapter = PacketOpenAdapter(pStr+rewind);

Remarks:

这个函数尝试加载并启动packet driver,这样,管理driver对于应用程序来说就十分的透明了。

Windows9X版本的NPF driver用的是ASCII编码,而WindowsNTx用的是Unicode编码。所以提请注意这个输入参数AdapterName,在Windows9X下,必须是正确的编码格式!在WindowsNTx下,这个函数能够监测到ASCII编码,并在送给driver 之前先转换为Unicode编码。

这个函数的操作大致为:

首先调用OpenSCManager,以Administrators的身份连接Service Control Manager,权限是SC_MANAGER_ALL_ACCESS。这也说明,使用Packet.dll你必须是本机管理员组成员。


 

如果可以连接SCM,检查NPF注册表项是否存在。如果存在,说明driver已经安装了,就不需要我们调用PacketInstallDriver了。

NPF注册表项:

HKEY_LOCAL_MACHINE\

SYSTEM\

CurrentControlSet\

Services\

NPF

如果不存在此键,则调用PacketInstallDriver安装当前路径下的driver:npf.sys。

如果这次PacketInstallDriver安装也失败了,就到系统路径下查找并安装这个驱动。

如果以上操作都成功的话,调用OpenService打开NPF服务。如果服务存在的话,就调用QueryServiceStatus查询当前服务状态。这就是我们的driver的状态。

如果这个服务没有启动,就调用StartService启动之。

确认服务启动之后,检查AdapterName是否是ASCII编码,是的话,就转换为Unicode。

由于一般输入参数AdapterNAme类似于这样:

\Device\NPF_{A67CEC3B-C099-47E0-B096-480B01FAF348}

所以,我们会重新组织一个设备名SymbolicLink:

“Packet_”的前缀 + AdapterName[8]

也就是:

\\.\Packet_NPF_{A67CEC3B-C099-47E0-B096-480B01FAF348}

先尝试着CreateFile函数能不能马上用这个SymbolicLink名字打开设备。

如果可以,就调用PacketSetReadEvt函数打开一个open事件等。

否则,调用DefineDosDevice定义一个新的MS-DOS设备:

名字类似于” Packet_NPF_{A67CEC3B-C099-47E0-B096-480B01FAF348}”。

通过这个DOS设备名,我们的应用层程序才能向驱动发出请求。

接着,调用CreateFile函数来建立并打开一个联系设备的文件句柄(GENERIC_WRITE| GENERIC_READ,OPEN_EXISTING)。

之后,调用PacketSetReadEvt函数打开一个open事件等。

(To be continued)

Writen by zhengyun@tomosoft.com

本文档所包含的信息代表了在发布之日,ZhengYun 对所讨论问题的当前看法,Zhengyun 不保证所给信息在发布之日以后的准确性。

本文档仅供参考。对本文档中的信息,Zhengyun 不做任何明示或默示的保证。



 

Packet32包中的数据结构:

第一个重要的数据结构:_ADAPTER(关于Network Adapter的)

typedef struct _ADAPTER
{
// 一个打开的NPF driver实例的句柄:
HANDLE hFile;
// 当前打开的网卡的名字:
CHAR SymbolicLink[MAX_LINK_NAME_LENGTH];
// 在这块Adapter上,一个数据包被写的次数:
int NumWrites;

// 这块Adapter上的read操作的通知事件。它可以被传递给标准Win32函数(如WaitForSingleObject或者WaitForMultipleObjects),这样可以等待到driver的缓冲区内有数据到来。在同时等待几个事件的GUI程序中,它特别有用。在Windows2000/XP中,函数PacketSetMinToCopy()可以用来设置内核缓冲区中激发本事件的最小数据大小:

HANDLE ReadEvent;
// 设置一个时间,到时候,即使没有捕获任何包,read操作也会被释放,ReadEvent也会被触发:
UINT ReadTimeOut;
} ADAPTER, *LPADAPTER;

第二个重要的数据结构:_PACKET(关于Packet的)

typedef struct _PACKET
{
// 向后兼容用的:
HANDLE    hEvent;
// 向后兼容用的:
OVERLAPPED  OverLapped;
// 存放Packets的缓冲区:
PVOID    Buffer;
// 缓冲区的大小:
UINT     Length;
// 当前缓冲区中有效的字节数,如,上一次调用PacketReceivePacket()函数接收到的字节数:
DWORD    ulBytesReceived;
// 向后兼容用的:
BOOLEAN   bIoComplete
} PACKET, *LPPACKET;

第三个重要的数据结构:_PACKET_OID_DATA (关于OID请求的)

typedef struct _PACKET_OID_DATA
{
// OID的code,有效的OID code的定义参见ntddndis.h;比如:
// OID_GEN_SUPPORTED_LIST,OID_GEN_VENDOR_DESCRIPTION等:
ULONG Oid;
// 成员Data的长度:
ULONG Length;
// 存放发送给网卡或者从网卡接收的数据的缓冲区:
UCHAR Data[1];
}
typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA;


 

其他数据结构:

npf_if_addr(网卡的地址):

typedef struct npf_if_addr {
struct sockaddr IPAddress; // IP address.
struct sockaddr SubnetMask; // Netmask for that address.
struct sockaddr Broadcast; // Broadcast address.
}npf_if_addr;
bpf_hdr(Packet Header):
struct bpf_hdr {
// 捕获到的packet的timestamp:
struct timeval    bh_tstamp;
// 捕获到的packet的长度:
UINT    bh_caplen;
// 原始packet的长度:
UINT    bh_datalen;
// bpf header的长度(this struct plus alignment padding):
USHORT       bh_hdrlen;
};

bpf_insn(一个简单的BPF伪指令):

bpf_insn中包含了一个BPF注册机的简单指令,它被用来发送一个filter程序给driver。

struct bpf_insn {
// 指令的类型和寻址模式:
USHORT    code;
// Jump if true:
UCHAR jt;
// Jump if false:
UCHAR jf;
// 通用的一个字段,有多种目的:
int k;
};

bpf_program(一个BPF伪汇编程序):

这段程序将被PacketSetBPF()注射入内核,并被应用到每一个进来的Packet。

struct bpf_program {
// 程序指令数目,如,后面的bpf_insn结构的数目:
UINT bf_len;
// 指向第一个bpf_insn结构的指针:
struct bpf_insn *bf_insns;
};

bpf_stat (本次捕获的统计数据):

这个结构将被Packet.dll用来返回捕获过程中的统计数据。

struct bpf_stat {
// 从开始捕获起,这个driver从网卡上接收的Packet的数量(包括driver丢失的Packet):
UINT bs_recv;
//从开始捕获起,这个driver丢失的Packet的数量,一般地,包丢失,是因为driver的缓冲区满了,这时driver将扔掉这个包:
UINT bs_drop;
UINT ps_ifdrop;
// 通过filter的包的数量:
UINT bs_capt;
};
dump_bpf_hdr(Dump Packet Header):
struct dump_bpf_hdr{
// Packet的timestamp:
struct timeval    ts;
// 捕获到的packet的长度:
UINT           caplen;
// 原始Packet的长度:
UINT           len;
};

NetType (网络类型):

NetType用于PacketGetNetType(),返回当前网卡的类型和速度。

struct NetType{
//当前网卡的MAC:
UINT LinkType;
// 网络的速度(bits/s):
UINT LinkSpeed;
};

(To be continued)

Writen by zhengyun@tomosoft.com

本文档所包含的信息代表了在发布之日,ZhengYun 对所讨论问题的当前看法,Zhengyun 不保证所给信息在发布之日以后的准确性。

本文档仅供参考。对本文档中的信息,Zhengyun 不做任何明示或默示的保证。

 

Packet32包中的函数说明:

No.3. PacketSetHwFilter (设置过滤器)

设置一个hardware filter。比如,Filter参数传递NDIS_PACKET_TYPE_PROMISCUOUS,就可以设置网卡为混杂模式。

BOOLEAN PacketSetHwFilter(
LPADAPTER AdapterObject,
ULONG Filter
);

Parameters:

AdapterObject:

[in] 指向一个_ADAPTER结构的指针。

Filter:

[in] 过滤器的id。

Return Values:

如果执行成功,返回一个非零值。

Usage:

C/C++ Usage Sample

lpAdapter =  PacketOpenAdapter(AdapterList[Open-1]);

PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS);

Remarks:

过滤器定义在ntddndis.h中。下面是一些最常用的:

NDIS_PACKET_TYPE_PROMISCUOUS:设置混杂模式。网卡接收每一个Packet;

NDIS_PACKET_TYPE_DIRECTED;

NDIS_PACKET_TYPE_BROADCAST:只接收broadcast packets;

NDIS_PACKET_TYPE_MULTICAST:只接收multicast packets,而且本机网卡是接收组的一个成员;

NDIS_PACKET_TYPE_ALL_MULTICAST:所有multicast packets都接收;

NDIS_PACKET_TYPE_ALL_LOCAL:所有local packets。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ensp是一个网络仿真软件,用于模拟和分析网络环境。packet.dll 是ensp软件所需的动态连接库文件,它是实现底层网络操作的重要组成部分。如果找不到packet.dll文件,可能会导致ensp无法正常运行。以下是解决此问题的一些常见方法: 1. 检查文件路径:首先,请确保packet.dll文件位于正确的路径下。尝试在ensp的安装目录或系统的系统路径(System32)下搜索该文件。 2. 重新安装ensp软件:如果找不到packet.dll文件,可能是因为ensp软件安装过程中出现了问题。您可以尝试重新安装ensp软件,确保在安装过程中没有任何错误或中断。 3. 从其他来源获取packet.dll:如果重新安装ensp软件仍然没有解决问题,您可以尝试从其他途径获取packet.dll文件。例如,您可以咨询ensp官方网站或论坛,或者与其他ensp用户交流,获取有效的packet.dll文件。 4. 检查网络驱动程序:packet.dll文件与网络驱动程序密切相关。如果您的网络驱动程序过时或损坏,可能导致packet.dll无法正常工作。尝试更新您的网络驱动程序,或者从网络适配器的制造商处获取最新的驱动程序。 请注意,使用任何从非官方来源获取的dll文件都存在一定的风险,可能会导致系统不稳定或安全问题。建议您在尝试上述方法之前务必备份您的系统和数据,并谨慎使用来自不可信来源的文件。如果问题仍然存在,建议您联系ensp软件的技术支持或专业人士寻求进一步帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值