wireshark源代码的一些分析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

wireshark源代码的一些分析
epan/dissector/packet-XXX.c
提供了相应协议的解析器
需要把解析器先注册到系统中,然后实现协议解析
proto_register_XXX()
dissect_XXX()
在协议解析中使用到的函数有三个变量, tvbuff_t , packet_info, proto_tree
每一个proto_item都将被添加到proto_tree中去
wiretap/
wiretap提供了大量读取文件的程序
文件读取分为两种,一种是读取正在捕获的文件,还有一种就是读取存在磁盘上的文件
每一个文件格式都有自己的文件读取的程序,如标准libpcap文件格式cap格式,就对映
libpcap.c和libpcap.h文件。

wiretap目录下的pcap_common.c和pcap_common.h提供一写文件格式的结构
标准libpcap文件是如下储存网络数据的
GLOABLE HEADER | PACKET HEADER | PACKET DATA | PACKET HEADER | PACKET DATA |
以libpcap.c为例
GLOABLE HEADER 分为两个部分 magic number 和 pcap_hdr 程序先调用libpcap_open打开文件并判断文件类型和初始化其他变量
然后用libpcap_read读入PACKET HEADER 和 PACKET DATA。

一次调用只能读一个PACKET HEADER 和 PACKET DATA, 然后保存在wtap结构体中!所以
一个wtap结构体只能保存一个packet!
在wtap.h中保存着wtap_file_type 和 wtap_encap_type 分别表示文件类型和协议的封
装类型
/capinfos.c
这是wireshark套件中的一个工具软件,它的作用是输出文件的信息
capinfos支持所有wireshark 支持的文件格式
在capinfos中文件中帧信息主要保存在wtag结构中体。

其中process_cap_file为文件处理函数!
文件的信息被保存在capture_info结构体中
最后由print_stats函数答应输出
wtap结构体由/wiretap/file_access.c中的wtap_open_offline函数构造
函数中最重要的一个部分是确认文件的类型并调用相应的文件实例来操作文件。

wireshark
支持的文件类型众多,也可以自己添加文件实例来处理自己定义的文件,具体的操作可以
在/wiretap/README.developer文件中找到。

在初始化wtap结构体的文件实例时,wtap_open_offline会在已注册的文件实例中寻找,先
调用open函数如果发现可以打开,则确定实例。

(在每一个文件实例的.c文件中都有体现)
如果打不开,则调用下一个open函数!
有两个变量保存在文件类型和文件open实例,在file_access.c 中。

一个是wtap_open_rout
ines_t的数组,记录着所有open实例。

另一个是file_type_info 的结构体,记录这所有文
件类型和其他信息!
在wtap_open_offline函数的最后阶段,会开启一个for循环,在这个循环中会逐一调用文件
open的实例
当初始化完wtap结构体后,所有对文件相关的操作比如读文件中的一个帧,都会调用wtap.c
文件中的函数如wtap_read。

这个函数会调用wtap结构体变量中的subtype_read函数指针来
读取文件,这个函数指针这初始化是已经被相应的文件read实例赋值。

具体的赋值过程发生
在每一个文件实例的.c文件中。

在读取所有帧之后会对capture_info中的变量赋值,这样就完成了文件信息的读取。

在privileges.c在获得于平台相关的信息如用户权限等!
这个函数会在开始的时候被调用用于初始化程序。

/tshark
tshark是wireshark的文字模式,可以进行抓包和分析,这里先看分析,即无需抓包,指定文
件令其分析
main函数开始先调用init_progfile_dir找出tshark这个命令的路径,并把结果保存在/epan/
filesystem.c的变量progfile_dir中。

在捕获数据包时,需要设定比较多的参数,这些参数用capture_opts保存,这个结构体被定
义在capture_opts.h文件中。

在main函数中调用capture_opts_init来初始化
/epan/timestamp.h 中定义了时间戳的相关变量和函数
在main函数中调用epan_init初始化分析器。

/epan/epan.c中定义了ethernet packet analyzer的相关操作,包括注册注销分析器等等。

/epan/dissector/register.c中注册了所有的proto_register_XXX 函数和其他的相关的函数
在注册分析器的过程中,函数先初始化包所需要的内存(一个包一块emem_header_t?)
cfile中的capture_file保存了大量将被分析的文件的信息。

此处文件可以是内存内的文件,
也可以是硬盘上的文件!
从1672行开始,tshark读取文件。

首先初始化capture_file这个结构体的变量cfile,调用tshark.c 文件中的cf_open函数,然
后初始化时间戳。

最后调用load_cap_file函数分析文件!
在load_cap_file函数在循环中调用了wtap_read函数读取一个帧,并对帧进行分析。

分析的过
程是调用process_packet。

在这个函数中调用了epan.c中的函数epan_dissect_run
函数,开始分析数据包。

这个函数又调用了/epan/packet.c中的dissect_packet函数。

/wtap/wtap.c文件中记录着关于文件操作的相关信息,如判断文件类型,判断文件中记录数据
的包类型等等,还有就是读取文件等操作。

/epan/epan_disssect.h 中定义了一个结构体epan_dissect_t,这个结构体包含了三个结构体
变量为tvbuff, packet_info和proto_tree,这些结构体变量在分析协议时及其重要。

/epan/frame_data.h中定义的frame_data结构体变量用于保存frame_data的数据,和wth中的
frame_buffer有区别,应该是经过一定的处理,而buffer是不经处理的!
main函数在938行调用了epan_init函数,这个函数调用了packet_init函数,在packet_init中
frame_handle被初始化。

在epan_init函数中也初始化了register_dissector_protocols函数,
这些函数会调用register_dissector函数,在这个函数中初始化了register_dissectors变量,
这个变量是个hash表,在初始化frame_handle时将要查找。

在packet-frame.c文件中找到的dissect_frame函数为第一个调用的dissect函数。

这个函数初始
化了一个wtap_encap_dissector_table,接下来的解析将交给这个table中的dissectors.
在packet.c中,有大量关于packet的操作。

其中的dissector_table的操作是用于解决各个不同
层的协议的调用问题的。

在第一个调用的frame协议中,wtap_encap_dissector_table只是进行
了初始化,并没有给他添加相应的handle,即只是调用了register_dissector_table函数,并返
回了一个subdissector_table。

可是frame下一层的协议,如ethernet协议就在自己注册dissector
的函数中调用了dissector_add_uint函数往frame的wtap_encap_dissector_table里添加了自己的
handle。

这样frame在解析的时候就可以调用dissector_try_uint函数来调用更高层的解析器。

每一个协议都有相应的subdissetor_table来装载更高层的协议的handle。

这个sub_table是保存
在packet.c文件的dissector_table这个hash变量中的。

用一个名字与其相对应。

wtap_encap这个
sub_table 的名字就是"wtap_encap"。

每一个sub_table里有一个GList* handle变量来保存更高
层将使用的协议的handle。

然后通过一个uint来找出应该调用那个handle。

比如当tcp协议已经把
自己协议树中的字段解析出后就会调用dissector_try_uint函数,如果更高层是http,在80端口,
那么dissector_try_uint的两个形参就是"tcp.port"(这个一个subdissector_table)和80 。

那么这个"tcp.port"的subdissector_table在packet-tcp.c中只是生成了一个空表,并没有往这
个表里面添加什么handle用于调用http的dissector。

而这个添加的过程是在packet-http.c这个文
件中实现的。

这样就把协议的注册都放在了更高层的协议里了。

在每一个协议的文件中都有三个函数分别是proto_register_XXX,proto_reg_handoff_XXX,
dissect_XXX。

第一个函数用于注册协议,协议的子类型和协议的各个字段。

实现这三个功能
函数分别调用了proto_register_protocol,proto_register_subtree_array,
proto_register_field_array。

最好函数还注册了处理这个协议所需要的dissector——调用了
register_dissector函数。

在proto_reg_handoff_XXX函数中,函数实现了向底层添加自身handle的调用——调用了
dissector_add_uint函数。

在dissect_XXX的最后解析阶段,函数调用了dissector_try_uint 函数,把解析的事宜交给了更高
层的协议。

在解析协议的过程中会使用到三个结构体变量,tvbuff,packet_info,proto_tree。

tvbuff变量保存
着本次解析需要用到的原始数据,也就是说每经过一次解析,这个变量的内容就会减少一部分。

packet_inofo保存这个数据包的所有信息。

这个变量是随着解析的进行,一点一点被更新的。

他包含
了源地址,目标地址等所有协议层的信息,方便于各个协议层之间进行交流。

proto_tree是一个包含
所有协议层的结构。

tree的每一个item都是一个协议层。

而本协议层在经过判断之后(判断协议的类
型)后会给这个item添加一个subtree。

由于proto_tree 和proto_item是同一个struct proto_node
的两个typedef,所以item转化成subtree以后可以接续添加item。

这时被添加的item就是本层协议里的
各个字段了。

在解析的过程中部分协议并不遵守既定的规则,比如一些协议占用了80端口,而http协议却从别的端
口进入计算机。

在这种情况下,tcp解析协议将调用disssector_try_heur函数。

这个函数和
dissector_try_uint函数一样需要一个subdissector_table,这个sub_table生成的模式和前一个一样。

相关文档
最新文档