1. 程式人生 > 其它 >wireshark外掛開發 - 自定義協議

wireshark外掛開發 - 自定義協議

雖然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視窗,進入原始碼所在目錄

$env:GOPATH="原始碼所在目錄"

$env:GOPATH

go run src\main\server.go

2、啟動客戶端

開啟CMD視窗,進入原始碼所在目錄

$env:GOPATH="原始碼所在目錄"

$env:GOPATH

go run src\main\client.go

1.6.抓包