- 修正 WTS 会话相关类型、枚举与活动会话选择逻辑 - 对齐 FILE_ID_DESCRIPTOR 布局与 FILE_ID_TYPE 语义,修复 OpenFileById 调用前提 - 修正 user32/shell32/kernel32 部分 API 的返回值、参数个数与错误处理 - 完善剪贴板更新格式读取的缓冲区重试逻辑 - 补充常用进程、线程、调试、桌面与会话 helper - 增加结构体布局、会话查询、剪贴板、CreateProcess 等回归测试 - 将默认 CreateProcess 相关测试切到 helper 进程,并保留显式开启的 cmd.exe 集成覆盖
592 lines
13 KiB
Go
592 lines
13 KiB
Go
package win32api
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
func makeWord(low, high byte) WORD {
|
|
return WORD(uint16(low) | uint16(high)<<8)
|
|
}
|
|
|
|
func WSAStartup(versionRequested WORD, data *WSADATA) error {
|
|
proc, err := getProcAddr("ws2_32.dll", "WSAStartup")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 2, uintptr(versionRequested), uintptr(unsafe.Pointer(data)), 0)
|
|
if r != 0 {
|
|
return syscall.Errno(r)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func WSACleanup() error {
|
|
proc, err := getProcAddr("ws2_32.dll", "WSACleanup")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 0, 0, 0, 0)
|
|
if int32(r) == -1 {
|
|
last := WSAGetLastError()
|
|
if last != 0 {
|
|
return syscall.Errno(last)
|
|
}
|
|
return syscall.EINVAL
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func WSAGetLastError() int {
|
|
proc, err := getProcAddr("ws2_32.dll", "WSAGetLastError")
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 0, 0, 0, 0)
|
|
return int(int32(r))
|
|
}
|
|
|
|
func wsaLastErrorOr(defaultErr error) error {
|
|
last := WSAGetLastError()
|
|
if last != 0 {
|
|
return syscall.Errno(last)
|
|
}
|
|
if defaultErr != nil {
|
|
return defaultErr
|
|
}
|
|
return syscall.EINVAL
|
|
}
|
|
|
|
func GetHostName() (string, error) {
|
|
var data WSADATA
|
|
if err := WSAStartup(makeWord(2, 2), &data); err != nil {
|
|
return "", err
|
|
}
|
|
defer func() {
|
|
_ = WSACleanup()
|
|
}()
|
|
|
|
proc, err := getProcAddr("ws2_32.dll", "gethostname")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
buf := make([]byte, 256)
|
|
r, _, _ := syscall.Syscall(proc, 2, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
|
|
if int32(r) == -1 {
|
|
last := WSAGetLastError()
|
|
if last != 0 {
|
|
return "", syscall.Errno(last)
|
|
}
|
|
return "", syscall.EINVAL
|
|
}
|
|
|
|
idx := bytes.IndexByte(buf, 0)
|
|
if idx < 0 {
|
|
idx = len(buf)
|
|
}
|
|
host := string(buf[:idx])
|
|
if host == "" {
|
|
return "", fmt.Errorf("gethostname returned empty host")
|
|
}
|
|
return host, nil
|
|
}
|
|
|
|
func InetPton(family int, ip string) ([]byte, error) {
|
|
var data WSADATA
|
|
if err := WSAStartup(makeWord(2, 2), &data); err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() {
|
|
_ = WSACleanup()
|
|
}()
|
|
|
|
proc, err := getProcAddr("ws2_32.dll", "InetPtonW")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var out []byte
|
|
switch family {
|
|
case AF_INET:
|
|
out = make([]byte, 4)
|
|
case AF_INET6:
|
|
out = make([]byte, 16)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported address family: %d", family)
|
|
}
|
|
|
|
r, _, _ := syscall.Syscall(proc, 3,
|
|
uintptr(family),
|
|
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(ip))),
|
|
uintptr(unsafe.Pointer(&out[0])),
|
|
)
|
|
if int32(r) == 1 {
|
|
return out, nil
|
|
}
|
|
if int32(r) == 0 {
|
|
return nil, fmt.Errorf("invalid ip address: %s", ip)
|
|
}
|
|
last := WSAGetLastError()
|
|
if last != 0 {
|
|
return nil, syscall.Errno(last)
|
|
}
|
|
return nil, syscall.EINVAL
|
|
}
|
|
|
|
func InetNtop(family int, addr []byte) (string, error) {
|
|
var data WSADATA
|
|
if err := WSAStartup(makeWord(2, 2), &data); err != nil {
|
|
return "", err
|
|
}
|
|
defer func() {
|
|
_ = WSACleanup()
|
|
}()
|
|
|
|
switch family {
|
|
case AF_INET:
|
|
if len(addr) != 4 {
|
|
return "", fmt.Errorf("inet4 requires 4 bytes, got %d", len(addr))
|
|
}
|
|
case AF_INET6:
|
|
if len(addr) != 16 {
|
|
return "", fmt.Errorf("inet6 requires 16 bytes, got %d", len(addr))
|
|
}
|
|
default:
|
|
return "", fmt.Errorf("unsupported address family: %d", family)
|
|
}
|
|
|
|
proc, err := getProcAddr("ws2_32.dll", "InetNtopW")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
buf := make([]uint16, 65)
|
|
r, _, _ := syscall.Syscall6(proc, 4,
|
|
uintptr(family),
|
|
uintptr(unsafe.Pointer(&addr[0])),
|
|
uintptr(unsafe.Pointer(&buf[0])),
|
|
uintptr(len(buf)),
|
|
0,
|
|
0,
|
|
)
|
|
if r == 0 {
|
|
last := WSAGetLastError()
|
|
if last != 0 {
|
|
return "", syscall.Errno(last)
|
|
}
|
|
return "", syscall.EINVAL
|
|
}
|
|
return syscall.UTF16ToString(buf), nil
|
|
}
|
|
|
|
func Socket(family, socketType, protocol int32) (SOCKET, error) {
|
|
proc, err := getProcAddr("ws2_32.dll", "socket")
|
|
if err != nil {
|
|
return INVALID_SOCKET, err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 3, uintptr(family), uintptr(socketType), uintptr(protocol))
|
|
s := SOCKET(r)
|
|
if s == INVALID_SOCKET {
|
|
return INVALID_SOCKET, wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
func Closesocket(s SOCKET) error {
|
|
proc, err := getProcAddr("ws2_32.dll", "closesocket")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 1, uintptr(s), 0, 0)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Connect(s SOCKET, name *SOCKADDR, namelen int32) error {
|
|
if name == nil {
|
|
return fmt.Errorf("sockaddr is nil")
|
|
}
|
|
proc, err := getProcAddr("ws2_32.dll", "connect")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 3, uintptr(s), uintptr(unsafe.Pointer(name)), uintptr(namelen))
|
|
if int32(r) == SOCKET_ERROR {
|
|
return wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Bind(s SOCKET, name *SOCKADDR, namelen int32) error {
|
|
if name == nil {
|
|
return fmt.Errorf("sockaddr is nil")
|
|
}
|
|
proc, err := getProcAddr("ws2_32.dll", "bind")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 3, uintptr(s), uintptr(unsafe.Pointer(name)), uintptr(namelen))
|
|
if int32(r) == SOCKET_ERROR {
|
|
return wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Listen(s SOCKET, backlog int32) error {
|
|
proc, err := getProcAddr("ws2_32.dll", "listen")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 2, uintptr(s), uintptr(backlog), 0)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Accept(s SOCKET, addr *SOCKADDR, addrlen *int32) (SOCKET, error) {
|
|
proc, err := getProcAddr("ws2_32.dll", "accept")
|
|
if err != nil {
|
|
return INVALID_SOCKET, err
|
|
}
|
|
var addrPtr uintptr
|
|
if addr != nil {
|
|
addrPtr = uintptr(unsafe.Pointer(addr))
|
|
}
|
|
var addrLenPtr uintptr
|
|
if addrlen != nil {
|
|
addrLenPtr = uintptr(unsafe.Pointer(addrlen))
|
|
}
|
|
|
|
r, _, _ := syscall.Syscall(proc, 3, uintptr(s), addrPtr, addrLenPtr)
|
|
client := SOCKET(r)
|
|
if client == INVALID_SOCKET {
|
|
return INVALID_SOCKET, wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return client, nil
|
|
}
|
|
|
|
func Send(s SOCKET, buf []byte, flags int32) (int, error) {
|
|
proc, err := getProcAddr("ws2_32.dll", "send")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var bufPtr uintptr
|
|
if len(buf) > 0 {
|
|
bufPtr = uintptr(unsafe.Pointer(&buf[0]))
|
|
}
|
|
r, _, _ := syscall.Syscall6(proc, 4, uintptr(s), bufPtr, uintptr(len(buf)), uintptr(flags), 0, 0)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return 0, wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return int(r), nil
|
|
}
|
|
|
|
func Recv(s SOCKET, buf []byte, flags int32) (int, error) {
|
|
proc, err := getProcAddr("ws2_32.dll", "recv")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var bufPtr uintptr
|
|
if len(buf) > 0 {
|
|
bufPtr = uintptr(unsafe.Pointer(&buf[0]))
|
|
}
|
|
r, _, _ := syscall.Syscall6(proc, 4, uintptr(s), bufPtr, uintptr(len(buf)), uintptr(flags), 0, 0)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return 0, wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return int(r), nil
|
|
}
|
|
|
|
func Shutdown(s SOCKET, how int32) error {
|
|
proc, err := getProcAddr("ws2_32.dll", "shutdown")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 2, uintptr(s), uintptr(how), 0)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetSockName(s SOCKET, name *SOCKADDR, nameLen *int32) error {
|
|
if name == nil || nameLen == nil {
|
|
return syscall.EINVAL
|
|
}
|
|
proc, err := getProcAddr("ws2_32.dll", "getsockname")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 3, uintptr(s), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)))
|
|
if int32(r) == SOCKET_ERROR {
|
|
return wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetPeerName(s SOCKET, name *SOCKADDR, nameLen *int32) error {
|
|
if name == nil || nameLen == nil {
|
|
return syscall.EINVAL
|
|
}
|
|
proc, err := getProcAddr("ws2_32.dll", "getpeername")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, _ := syscall.Syscall(proc, 3, uintptr(s), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)))
|
|
if int32(r) == SOCKET_ERROR {
|
|
return wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func SetSockOpt(s SOCKET, level, optName int32, optValue []byte) error {
|
|
proc, err := getProcAddr("ws2_32.dll", "setsockopt")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var valuePtr uintptr
|
|
if len(optValue) > 0 {
|
|
valuePtr = uintptr(unsafe.Pointer(&optValue[0]))
|
|
}
|
|
r, _, _ := syscall.Syscall6(proc, 5,
|
|
uintptr(s),
|
|
uintptr(level),
|
|
uintptr(optName),
|
|
valuePtr,
|
|
uintptr(len(optValue)),
|
|
0,
|
|
)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetSockOpt(s SOCKET, level, optName int32, optValue []byte) (int32, error) {
|
|
proc, err := getProcAddr("ws2_32.dll", "getsockopt")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var valuePtr uintptr
|
|
if len(optValue) > 0 {
|
|
valuePtr = uintptr(unsafe.Pointer(&optValue[0]))
|
|
}
|
|
optLen := int32(len(optValue))
|
|
r, _, _ := syscall.Syscall6(proc, 5,
|
|
uintptr(s),
|
|
uintptr(level),
|
|
uintptr(optName),
|
|
valuePtr,
|
|
uintptr(unsafe.Pointer(&optLen)),
|
|
0,
|
|
)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return 0, wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return optLen, nil
|
|
}
|
|
|
|
func SetSockOptInt(s SOCKET, level, optName int32, value int32) error {
|
|
buf := (*[4]byte)(unsafe.Pointer(&value))[:]
|
|
return SetSockOpt(s, level, optName, buf)
|
|
}
|
|
|
|
func GetSockOptInt(s SOCKET, level, optName int32) (int32, error) {
|
|
var value int32
|
|
buf := (*[4]byte)(unsafe.Pointer(&value))[:]
|
|
optLen, err := GetSockOpt(s, level, optName, buf)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if optLen < 4 {
|
|
return 0, fmt.Errorf("getsockopt returned short length: %d", optLen)
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
func SendTo(s SOCKET, buf []byte, flags int32, to *SOCKADDR, toLen int32) (int, error) {
|
|
proc, err := getProcAddr("ws2_32.dll", "sendto")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var bufPtr uintptr
|
|
if len(buf) > 0 {
|
|
bufPtr = uintptr(unsafe.Pointer(&buf[0]))
|
|
}
|
|
var toPtr uintptr
|
|
if to != nil {
|
|
toPtr = uintptr(unsafe.Pointer(to))
|
|
}
|
|
r, _, _ := syscall.Syscall6(proc, 6,
|
|
uintptr(s),
|
|
bufPtr,
|
|
uintptr(len(buf)),
|
|
uintptr(flags),
|
|
toPtr,
|
|
uintptr(toLen),
|
|
)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return 0, wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return int(r), nil
|
|
}
|
|
|
|
func RecvFrom(s SOCKET, buf []byte, flags int32, from *SOCKADDR, fromLen *int32) (int, error) {
|
|
proc, err := getProcAddr("ws2_32.dll", "recvfrom")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var bufPtr uintptr
|
|
if len(buf) > 0 {
|
|
bufPtr = uintptr(unsafe.Pointer(&buf[0]))
|
|
}
|
|
var fromPtr uintptr
|
|
if from != nil {
|
|
fromPtr = uintptr(unsafe.Pointer(from))
|
|
}
|
|
var fromLenPtr uintptr
|
|
if fromLen != nil {
|
|
fromLenPtr = uintptr(unsafe.Pointer(fromLen))
|
|
}
|
|
r, _, _ := syscall.Syscall6(proc, 6,
|
|
uintptr(s),
|
|
bufPtr,
|
|
uintptr(len(buf)),
|
|
uintptr(flags),
|
|
fromPtr,
|
|
fromLenPtr,
|
|
)
|
|
if int32(r) == SOCKET_ERROR {
|
|
return 0, wsaLastErrorOr(syscall.EINVAL)
|
|
}
|
|
return int(r), nil
|
|
}
|
|
|
|
func GetAddrInfo(node, service string, hints *ADDRINFOW) (*ADDRINFOW, error) {
|
|
var data WSADATA
|
|
if err := WSAStartup(makeWord(2, 2), &data); err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() {
|
|
_ = WSACleanup()
|
|
}()
|
|
|
|
proc, err := getProcAddr("ws2_32.dll", "GetAddrInfoW")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var nodePtr *uint16
|
|
if node != "" {
|
|
nodePtr = syscall.StringToUTF16Ptr(node)
|
|
}
|
|
|
|
var servicePtr *uint16
|
|
if service != "" {
|
|
servicePtr = syscall.StringToUTF16Ptr(service)
|
|
}
|
|
|
|
var result *ADDRINFOW
|
|
r, _, _ := syscall.Syscall6(proc, 4,
|
|
uintptr(unsafe.Pointer(nodePtr)),
|
|
uintptr(unsafe.Pointer(servicePtr)),
|
|
uintptr(unsafe.Pointer(hints)),
|
|
uintptr(unsafe.Pointer(&result)),
|
|
0,
|
|
0,
|
|
)
|
|
if int32(r) != 0 {
|
|
return nil, fmt.Errorf("GetAddrInfoW failed: %d", int32(r))
|
|
}
|
|
if result == nil {
|
|
return nil, fmt.Errorf("GetAddrInfoW returned nil result")
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func FreeAddrInfo(result *ADDRINFOW) error {
|
|
if result == nil {
|
|
return nil
|
|
}
|
|
proc, err := getProcAddr("ws2_32.dll", "FreeAddrInfoW")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
syscall.Syscall(proc, 1, uintptr(unsafe.Pointer(result)), 0, 0)
|
|
return nil
|
|
}
|
|
|
|
func GetNameInfo(sa *SOCKADDR, saLen int32, flags int32) (string, string, error) {
|
|
if sa == nil {
|
|
return "", "", fmt.Errorf("sockaddr is nil")
|
|
}
|
|
|
|
var data WSADATA
|
|
if err := WSAStartup(makeWord(2, 2), &data); err != nil {
|
|
return "", "", err
|
|
}
|
|
defer func() {
|
|
_ = WSACleanup()
|
|
}()
|
|
|
|
proc, err := getProcAddr("ws2_32.dll", "GetNameInfoW")
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
host := make([]uint16, NI_MAXHOST)
|
|
service := make([]uint16, NI_MAXSERV)
|
|
r, _, _ := syscall.Syscall9(proc, 7,
|
|
uintptr(unsafe.Pointer(sa)),
|
|
uintptr(saLen),
|
|
uintptr(unsafe.Pointer(&host[0])),
|
|
uintptr(len(host)),
|
|
uintptr(unsafe.Pointer(&service[0])),
|
|
uintptr(len(service)),
|
|
uintptr(flags),
|
|
0,
|
|
0,
|
|
)
|
|
if int32(r) != 0 {
|
|
return "", "", fmt.Errorf("GetNameInfoW failed: %d", int32(r))
|
|
}
|
|
return syscall.UTF16ToString(host), syscall.UTF16ToString(service), nil
|
|
}
|
|
|
|
func SockaddrIPString(sa *SOCKADDR) (string, error) {
|
|
if sa == nil {
|
|
return "", fmt.Errorf("sockaddr is nil")
|
|
}
|
|
|
|
switch int(sa.Family) {
|
|
case AF_INET:
|
|
addr := (*SOCKADDR_IN)(unsafe.Pointer(sa))
|
|
return InetNtop(AF_INET, addr.Addr[:])
|
|
case AF_INET6:
|
|
addr := (*SOCKADDR_IN6)(unsafe.Pointer(sa))
|
|
return InetNtop(AF_INET6, addr.Addr[:])
|
|
default:
|
|
return "", fmt.Errorf("unsupported sockaddr family: %d", sa.Family)
|
|
}
|
|
}
|
|
|
|
func Htons(v uint16) uint16 {
|
|
return (v << 8) | (v >> 8)
|
|
}
|
|
|
|
func Ntohs(v uint16) uint16 {
|
|
return Htons(v)
|
|
}
|
|
|
|
func htons(v uint16) uint16 {
|
|
return Htons(v)
|
|
}
|