go语言开发windows抓包工具
使用syscall调用window api, go有封装, 暂时不需要自己调用dll
使用函数
syscall.WSAStartup
syscall.Socket
syscall.SockaddrInet4
syscall.WSAIoctl
syscall.WSARecv
废话不多说, 上代码简洁明了使用方法
package main
import (
"fmt"
"net"
"strconv"
"strings"
"syscall"
"unsafe"
"capture/console"
)
const (
SIO_RCVALL uint32 = 0x98000001
)
const (
SIO_RCVALL_ON uint32 = 0x00000001
)
func getLanIp() (string, error) {
var ip string = ""
addrs, _ := net.InterfaceAddrs()
for _, addr := range addrs {
// 检查是否为IP net
ipNet, _ := addr.(*net.IPNet)
if ipNet.IP.To4() != nil && ipNet.IP.IsGlobalUnicast() {
ip = ipNet.IP.String()
return ip, nil
}
}
return ip, nil
}
func ipToIpBytes(ip string) [4]byte {
ipStrArr := strings.Split(ip, ".")
var ipBytes [4]byte
for key, value := range ipStrArr {
u64, _ := strconv.ParseUint(value, 10, 64)
b := uint8(u64)
ipBytes[key] = byte(b)
}
return ipBytes
}
func main() {
var wsaData syscall.WSAData
err := syscall.WSAStartup(0x0202, &wsaData)
if err != nil {
console.Log("WSAStartup:", err)
return
}
var hints syscall.AddrinfoW
hints.Family = syscall.AF_INET
hints.Socktype = syscall.SOCK_RAW
hints.Protocol = syscall.IPPROTO_IP
rawSocket, err := syscall.Socket(int(hints.Family), int(hints.Socktype), int(hints.Protocol))
if err != nil {
console.Log("Socket:", err)
return
}
ip, _ := getLanIp()
addr := syscall.SockaddrInet4{
Port: 0,
Addr: ipToIpBytes(ip),
}
err = syscall.Bind(rawSocket, &addr)
if err != nil {
console.Log("Bind:", err)
return
}
dwValue := SIO_RCVALL_ON
dwValuePtr := unsafe.Pointer(&dwValue)
dwValuePtrlen := uint32(unsafe.Sizeof(dwValue))
dwOutValue := SIO_RCVALL_ON
dwOutValuePtr := unsafe.Pointer(&dwOutValue)
dwOutValuePtrlen := uint32(unsafe.Sizeof(dwOutValuePtr))
var dwValueReturn uint32
err = syscall.WSAIoctl(rawSocket, SIO_RCVALL, (*byte)(dwValuePtr), dwValuePtrlen, (*byte)(dwOutValuePtr), dwOutValuePtrlen, &dwValueReturn, nil, uintptr(0))
if err != nil {
console.Log("WSAIoctl: ", err)
return
}
console.Log("成功启动")
var buff [4096]byte
wsabuf := syscall.WSABuf{
Buf: (*byte)(unsafe.Pointer(&buff[0])),
Len: uint32(len(buff)),
}
var ret uint32 = 0
var flag uint32 = 0
for {
err = syscall.WSARecv(rawSocket, &wsabuf, 1, &ret, &flag, nil, nil)
if err != nil {
console.Log("WSARecv: ", err)
}
fmt.Printf("接收数据的长度: %d, 数据为: \n", ret)
fmt.Printf("%v \n\n", buff[:ret])
}
}
// WSAEINTR (10004): 系统中断错误
// WSAEBADF (10009): 文件描述符不正确
// WSAEACCES (10013): 权限被拒绝
// WSAEFAULT (10014): 内存访问错误
// WSAEINVAL (10022): 参数无效
// WSAEMFILE (10024): 打开的文件数量过多
// WSAEWOULDBLOCK (10035): 非阻塞socket操作现在无法完成
// WSAEINPROGRESS (10036): 进程中有一个阻塞的socket调用正在进行
// WSAEALREADY (10037): 操作已完成
// WSAENOTSOCK (10038): 描述符不是一个socket
// WSAEDESTADDRREQ (10039): 需要目标地址
// WSAEMSGSIZE (10040): 消息过长
// WSAEPROTOTYPE (10041): 协议类型错误
// WSAENOPROTOOPT (10042): 协议选项错误
// WSAEPROTONOSUPPORT (10043): 协议不支持
// WSAESOCKTNOSUPPORT (10044): socket类型不支持
// WSAEOPNOTSUPP (10045): 操作不支持
// WSAEPFNOSUPPORT (10046): 协议族不支持
// WSAEAFNOSUPPORT (10047): 地址族不支持
// WSAEADDRINUSE (10048): 地址已在使用中
// WSAEADDRNOTAVAIL (10049): 地址不可用
// WSAENETDOWN (10050): 网络下线
// WSAENETUNREACH (10051): 网络不可达
// WSAENETRESET (10052): 网络重置
// WSAECONNABORTED (10053): 连接中止
// WSAECONNRESET (10054): 连接重置
// WSAENOBUFS (10055): 无可用缓冲区
// WSAEISCONN (10056): 连接已经是连接状态
// WSAENOTCONN (10057): 连接未建立
// WSAESHUTDOWN (10058): 无法发送数据,socket被关闭
// WSAETOOMANYREFS (10059): 太多引用
// WSAETIMEDOUT (10060): 连接超时
// WSAECONNREFUSED (10061): 连接被拒绝
// WSAELOOP (10062): 有一个处理中的对话
// WSAENAMETOOLONG (10063): 地址名太长
// WSAEHOSTDOWN (10064): 主机宕机
capture是我的项目名字, console包是仿js的console
package console
import (
"encoding/json"
"fmt"
)
func Log(data ...interface{}) {
bytes, err := json.MarshalIndent(data, "", " ")
if err != nil {
fmt.Println(err)
}
fmt.Printf("%s\n", bytes)
}