虽然wireshark自带了很多知名协议的解析插件,譬如HTTP、DHCP等等,然而在实际应用环境中,有不少软件之间的通信协议都是私有的,如游戏客户端和服务器之间的交互协议通常都是私有的,wireshark无法具体解析出各种字段之间的含义,只能显示接收到的二进制数据,给协议的分析和问题的排查带来了一定的困难,尤其是协议内容比较复杂时。
本文一个自定义的简单协议入手,分析如何基于wireshark开发自定义协议分析插件。
1.1. 概述
本书使用Go语言来描述协议的交互过程。Go由Google出品,号称是互联网上的C语言,有点类似于C语言,以其简洁和高并发著称。
即使不了解Go语言也没有关系,本书给出的代码,基本可以自释其义,了解过程即可,重点不在于此。
1.2. 协议描述
1 package packet 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "os" 8 ) 9 10 type NPacket struct { 11 Version int16 //两个字节 12 ID uint32 //四个字节 13 Buffer [1024]byte //简单起见,固定为1024个字节 14 } 15 16 func (packet *NPacket) String() string { 17 return fmt.Sprintf("%v, %v, %v\n", packet.Version, 18 packet.ID, string(packet.Buffer[:])) 19 } 20 21 func CheckError(err error) { 22 if err != nil { 23 fmt.Println("Error: %s", err.Error()) 24 os.Exit(1) 25 } 26 } 27 28 func ConvertToPacket(b []byte) (packet *NPacket, err error) { 29 buffer := bytes.NewBuffer(b[:]) 30 31 packet = &NPacket{} 32 #将缓冲区buffer的内容转换到NPacket结构体中 33 err = binary.Read(buffer, binary.BigEndian, packet) 34 35 return packet, err 36 } 37 38 func ConvertToBuffer(packet *NPacket) (b []byte, err error) { 39 buf := new(bytes.Buffer) 40 41 #将结构体内容转换到缓冲区中 42 err = binary.Write(buf, binary.BigEndian, packet) 43 44 return buf.Bytes(), err 45 }
1.3. 客户端
1 package main 2 3 import ( 4 "fmt" 5 "net" 6 ) 7 8 import "packet" 9 10 func main() { 11 #连接服务端,UDP协议 12 conn, err := net.Dial("udp", "192.168.5.4:11110") 13 defer conn.Close() 14 packet.CheckError(err) 15 16 #定义报文内容 17 pkt_send := packet.NPacket{Version: 1, ID: 1} 18 copy(pkt_send.Buffer[:], "Ping") 19 20 send_buff, err := packet.ConvertToBuffer(&pkt_send) 21 packet.CheckError(err) 22 #发送报文 23 conn.Write(send_buff) 24 25 var recv_msg [4096]byte 26 #读取报文 27 n, err := conn.Read(recv_msg[0:]) 28 packet.CheckError(err) 29 30 #报文转换到结构体中 31 pkt_recv, err := packet.ConvertToPacket(recv_msg[0:n]) 32 packet.CheckError(err) 33 34 #会调用NPacket结构体的String方法 35 fmt.Println(pkt_recv) 36 }
1.4. 服务端
1 package main 2 3 import ( 4 "fmt" 5 "net" 6 ) 7 8 import "packet" 9 10 func recvUDPMsg(conn *net.UDPConn) { 11 var buf [4096]byte 12 13 #读取UDP报文 14 n, raddr, err := conn.ReadFromUDP(buf[0:]) 15 packet.CheckError(err) 16 17 #网络数据转换到结构体中 18 pkt_recv, err := packet.ConvertToPacket(buf[0:n]) 19 packet.CheckError(err) 20 21 fmt.Println(pkt_recv) 22 23 #构造响应报文 24 pkt_send := packet.NPacket{Version: pkt_recv.Version, ID: pkt_recv.ID} 25 copy(pkt_send.Buffer[:], "Pong") 26 27 send_buff, err := packet.ConvertToBuffer(&pkt_send) 28 packet.CheckError(err) 29 #发送报文 30 _, err = conn.WriteToUDP(send_buff, raddr) 31 packet.CheckError(err) 32 } 33 34 func main() { 35 udp_addr, err := net.ResolveUDPAddr("udp", ":11110") 36 packet.CheckError(err) 37 38 conn, err := net.ListenUDP("udp", udp_addr) 39 defer conn.Close() 40 packet.CheckError(err) 41 42 recvUDPMsg(conn) 43 }
1.5. 启动方式
1、启动服务端
打开CMD窗口,进入源码所在目录
set GOPATH=源码所在目录
go run src\main\server.go
2、启动客户端
打开CMD窗口,进入源码所在目录
set GOPATH=源码所在目录
go run src\main\client.go
1.6. 抓包
更多更完整的内容,请移步百度阅读:
https://yuedu.baidu.com/ebook/ca33e60d3a3567ec102de2bd960590c69ec3d89b
时间: 2024-10-22 01:04:37