- RDP/VNC(TightVNC)/Radmin 服务状态查询与启停重置、VNC 安装/配置读写/密码 加解密、GetRemoteInfo 汇总、CAD/SAS 注册表开关 - 与本库 file/shell/process 同属被控端远程运维能力; 新增依赖 kardianos/service、KarpelesLab/vncpasswd - 附 remote_test.go 与包 README(含平台支持矩阵与权限注意)
452 lines
12 KiB
Go
452 lines
12 KiB
Go
//go:build windows
|
|
|
|
package remote
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"golang.org/x/sys/windows/registry"
|
|
"math/big"
|
|
"os"
|
|
)
|
|
|
|
// GetRemoteInfo 一次性获取远程控制相关信息(服务状态/端口/密码/主机信息)
|
|
func GetRemoteInfo() Info {
|
|
info := Info{}
|
|
|
|
status, _ := GetVncServiceStatus()
|
|
info.VncState = int(status)
|
|
|
|
status, _ = GetRdpServiceStatus()
|
|
info.RdpState = int(status)
|
|
|
|
port, _ := GetRdpPort()
|
|
info.RdpPort = port
|
|
|
|
port, _ = GetVncPort()
|
|
info.VncPort = port
|
|
|
|
password, _ := GetVncPassword()
|
|
info.VncPassword = password
|
|
|
|
hostname, _ := os.Hostname()
|
|
info.Hostname = hostname
|
|
info.IpAddr = getIPs()
|
|
info.MacAddr = getMacAddrs()
|
|
|
|
return info
|
|
}
|
|
|
|
// GetVncPort 从注册表读取 TightVNC 主端口
|
|
func GetVncPort() (int, error) {
|
|
var key registry.Key
|
|
var err error
|
|
key, err = registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\TightVNC\Server`, registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var val uint64
|
|
val, _, err = key.GetIntegerValue("RfbPort")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var port int = int(val)
|
|
return port, nil
|
|
}
|
|
|
|
// GetRdpPort 从注册表读取远程桌面端口
|
|
func GetRdpPort() (int, error) {
|
|
var key registry.Key
|
|
var err error
|
|
key, err = registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp`, registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var val uint64
|
|
val, _, err = key.GetIntegerValue("PortNumber")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var port int = int(val)
|
|
return port, nil
|
|
}
|
|
|
|
// GetVncPassword 读取并解密 TightVNC 连接密码
|
|
func GetVncPassword() (string, error) {
|
|
var key registry.Key
|
|
var err error
|
|
key, err = registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\TightVNC\Server`, registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
val, _, err := key.GetBinaryValue("Password")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(val) == 0 {
|
|
return "", err
|
|
}
|
|
password := VncPasswordDecrypt(val)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return password, nil
|
|
}
|
|
|
|
// VncServerDefaultConfig 生成 TightVNC 服务端默认配置(连接 RDP 会话)
|
|
// randPass 为 true 时生成 8 位随机密码,否则使用固定密码
|
|
func VncServerDefaultConfig(randPass bool) VncServerConfig {
|
|
password := "tvncpass"
|
|
if randPass {
|
|
password = createRandomString(8)
|
|
}
|
|
config := VncServerConfig{
|
|
ExtraPorts: "",
|
|
QueryTimeout: 30,
|
|
QueryAcceptOnTimeout: 0,
|
|
LocalInputPriorityTimeout: 3,
|
|
LocalInputPriority: 1,
|
|
BlockRemoteInput: 0,
|
|
BlockLocalInput: 0,
|
|
IpAccessControl: "",
|
|
RfbPort: 5900,
|
|
HttpPort: 5800,
|
|
DisconnectAction: 0,
|
|
AcceptRfbConnections: 1,
|
|
UseVncAuthentication: 1,
|
|
UseControlAuthentication: 0,
|
|
RepeatControlAuthentication: 0,
|
|
LoopbackOnly: 0,
|
|
AcceptHttpConnections: 0,
|
|
LogLevel: 0,
|
|
EnableFileTransfers: 1,
|
|
RemoveWallpaper: 1,
|
|
UseD3D: 1,
|
|
UseMirrorDriver: 1,
|
|
EnableUrlParams: 1,
|
|
Password: VncPasswordCrypt(password),
|
|
AlwaysShared: 0,
|
|
NeverShared: 0,
|
|
DisconnectClients: 1,
|
|
PollingInterval: 1000,
|
|
AllowLoopback: 1,
|
|
VideoRecognitionInterval: 3000,
|
|
GrabTransparentWindows: 1,
|
|
SaveLogToAllUsersPath: 0,
|
|
RunControlInterface: 0,
|
|
IdleTimeout: 0,
|
|
VideoClasses: "",
|
|
VideoRects: "",
|
|
ConnectToRdp: 1,
|
|
}
|
|
|
|
return config
|
|
}
|
|
|
|
// VncClientDefaultConfig 生成 TightVNC 客户端默认配置(不连接 RDP 会话)
|
|
// randPass 为 true 时生成 8 位随机密码,否则使用固定密码
|
|
func VncClientDefaultConfig(randPass bool) VncServerConfig {
|
|
password := "tvncpass"
|
|
if randPass {
|
|
password = createRandomString(8)
|
|
}
|
|
config := VncServerConfig{
|
|
ExtraPorts: "",
|
|
QueryTimeout: 30,
|
|
QueryAcceptOnTimeout: 0,
|
|
LocalInputPriorityTimeout: 3,
|
|
LocalInputPriority: 1,
|
|
BlockRemoteInput: 0,
|
|
BlockLocalInput: 0,
|
|
IpAccessControl: "",
|
|
RfbPort: 5900,
|
|
HttpPort: 5800,
|
|
DisconnectAction: 0,
|
|
AcceptRfbConnections: 1,
|
|
UseVncAuthentication: 1,
|
|
UseControlAuthentication: 0,
|
|
RepeatControlAuthentication: 0,
|
|
LoopbackOnly: 0,
|
|
AcceptHttpConnections: 0,
|
|
LogLevel: 0,
|
|
EnableFileTransfers: 1,
|
|
RemoveWallpaper: 0,
|
|
UseD3D: 1,
|
|
UseMirrorDriver: 1,
|
|
EnableUrlParams: 1,
|
|
Password: VncPasswordCrypt(password),
|
|
AlwaysShared: 0,
|
|
NeverShared: 0,
|
|
DisconnectClients: 1,
|
|
PollingInterval: 1000,
|
|
AllowLoopback: 1,
|
|
VideoRecognitionInterval: 3000,
|
|
GrabTransparentWindows: 1,
|
|
SaveLogToAllUsersPath: 0,
|
|
RunControlInterface: 0,
|
|
IdleTimeout: 0,
|
|
VideoClasses: "",
|
|
VideoRects: "",
|
|
ConnectToRdp: 0,
|
|
}
|
|
|
|
return config
|
|
}
|
|
|
|
// WriteVncServerConfig 将 TightVNC 服务端配置写入注册表(项不存在时自动创建)
|
|
func WriteVncServerConfig(config VncServerConfig) error {
|
|
|
|
key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\TightVNC\\Server", registry.ALL_ACCESS)
|
|
if err != nil {
|
|
if err == registry.ErrNotExist {
|
|
// 项不存在 创建它
|
|
key, _, err = registry.CreateKey(registry.LOCAL_MACHINE, "SOFTWARE\\TightVNC\\Server", registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
|
|
defer key.Close()
|
|
|
|
err = key.SetStringValue("ExtraPorts", config.ExtraPorts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("QueryTimeout", config.QueryTimeout)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("QueryAcceptOnTimeout", config.QueryAcceptOnTimeout)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("LocalInputPriorityTimeout", config.LocalInputPriorityTimeout)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("LocalInputPriority", config.LocalInputPriority)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("BlockRemoteInput", config.BlockRemoteInput)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("BlockLocalInput", config.BlockLocalInput)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetStringValue("IpAccessControl", config.IpAccessControl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("RfbPort", config.RfbPort)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("HttpPort", config.HttpPort)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("DisconnectAction", config.DisconnectAction)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("AcceptRfbConnections", config.AcceptRfbConnections)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("UseVncAuthentication", config.UseVncAuthentication)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("UseControlAuthentication", config.UseControlAuthentication)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("RepeatControlAuthentication", config.RepeatControlAuthentication)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("LoopbackOnly", config.LoopbackOnly)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("AcceptHttpConnections", config.AcceptHttpConnections)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("EnableFileTransfers", config.EnableFileTransfers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("RemoveWallpaper", config.RemoveWallpaper)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("UseD3D", config.UseD3D)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("UseMirrorDriver", config.UseMirrorDriver)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("EnableUrlParams", config.EnableUrlParams)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetBinaryValue("Password", config.Password)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("AlwaysShared", config.AlwaysShared)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("NeverShared", config.NeverShared)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("DisconnectClients", config.DisconnectClients)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("PollingInterval", config.PollingInterval)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("AllowLoopback", config.AllowLoopback)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("VideoRecognitionInterval", config.VideoRecognitionInterval)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("GrabTransparentWindows", config.GrabTransparentWindows)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("SaveLogToAllUsersPath", config.SaveLogToAllUsersPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("RunControlInterface", config.RunControlInterface)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("IdleTimeout", config.IdleTimeout)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetStringValue("VideoClasses", config.VideoClasses)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetStringValue("VideoRects", config.VideoRects)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = key.SetDWordValue("ConnectToRdp", config.ConnectToRdp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// EnableSoftwareSASGeneration 启用软件SAS模拟输入
|
|
func EnableSoftwareSASGeneration() error {
|
|
// SAS模拟输入
|
|
key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", registry.ALL_ACCESS)
|
|
if err != nil {
|
|
if err == registry.ErrNotExist {
|
|
// 项不存在 创建它
|
|
key, _, err = registry.CreateKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
|
|
defer key.Close()
|
|
|
|
err = key.SetDWordValue("SoftwareSASGeneration", 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// EnableWinlogonDisableCAD 关闭 Ctrl + Alt + Del 组合键来登录
|
|
func EnableWinlogonDisableCAD() error {
|
|
key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", registry.ALL_ACCESS)
|
|
if err != nil {
|
|
if err == registry.ErrNotExist {
|
|
// 项不存在 创建它
|
|
key, _, err = registry.CreateKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
|
|
defer key.Close()
|
|
|
|
err = key.SetDWordValue("DisableCAD", 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// EnableSystemDisableCAD 关闭 Ctrl + Alt + Del 组合键来登录
|
|
func EnableSystemDisableCAD() error {
|
|
key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", registry.ALL_ACCESS)
|
|
if err != nil {
|
|
if err == registry.ErrNotExist {
|
|
// 项不存在 创建它
|
|
key, _, err = registry.CreateKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
|
|
defer key.Close()
|
|
|
|
err = key.SetDWordValue("DisableCAD", 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// createRandomString 生成指定长度的随机字符串
|
|
func createRandomString(len int) string {
|
|
var container string
|
|
var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
|
b := bytes.NewBufferString(str)
|
|
length := b.Len()
|
|
bigInt := big.NewInt(int64(length))
|
|
for i := 0; i < len; i++ {
|
|
randomInt, _ := rand.Int(rand.Reader, bigInt)
|
|
container += string(str[randomInt.Int64()])
|
|
}
|
|
return container
|
|
}
|