mirror of
https://github.com/yv1ing/ShotRDP.git
synced 2025-09-16 15:10:57 +08:00
452 lines
13 KiB
Go
452 lines
13 KiB
Go
// rail.go
|
|
package rail
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
|
|
"ShotRDP/grdp/core"
|
|
"ShotRDP/grdp/glog"
|
|
"ShotRDP/grdp/plugin"
|
|
)
|
|
|
|
const (
|
|
ChannelName = plugin.RAIL_SVC_CHANNEL_NAME
|
|
ChannelOption = plugin.CHANNEL_OPTION_INITIALIZED | plugin.CHANNEL_OPTION_ENCRYPT_RDP |
|
|
plugin.CHANNEL_OPTION_COMPRESS_RDP | plugin.CHANNEL_OPTION_SHOW_PROTOCOL
|
|
)
|
|
|
|
const (
|
|
TS_RAIL_ORDER_EXEC = 0x0001
|
|
TS_RAIL_ORDER_ACTIVATE = 0x0002
|
|
TS_RAIL_ORDER_SYSPARAM = 0x0003
|
|
TS_RAIL_ORDER_SYSCOMMAND = 0x0004
|
|
TS_RAIL_ORDER_HANDSHAKE = 0x0005
|
|
TS_RAIL_ORDER_NOTIFY_EVENT = 0x0006
|
|
TS_RAIL_ORDER_WINDOWMOVE = 0x0008
|
|
TS_RAIL_ORDER_LOCALMOVESIZE = 0x0009
|
|
TS_RAIL_ORDER_MINMAXINFO = 0x000A
|
|
TS_RAIL_ORDER_CLIENTSTATUS = 0x000B
|
|
TS_RAIL_ORDER_SYSMENU = 0x000C
|
|
TS_RAIL_ORDER_LANGBARINFO = 0x000D
|
|
TS_RAIL_ORDER_GET_APPID_REQ = 0x000E
|
|
TS_RAIL_ORDER_GET_APPID_RESP = 0x000F
|
|
TS_RAIL_ORDER_TASKBARINFO = 0x0010
|
|
TS_RAIL_ORDER_LANGUAGEIMEINFO = 0x0011
|
|
TS_RAIL_ORDER_COMPARTMENTINFO = 0x0012
|
|
TS_RAIL_ORDER_HANDSHAKE_EX = 0x0013
|
|
TS_RAIL_ORDER_ZORDER_SYNC = 0x0014
|
|
TS_RAIL_ORDER_CLOAK = 0x0015
|
|
TS_RAIL_ORDER_POWER_DISPLAY_REQUEST = 0x0016
|
|
TS_RAIL_ORDER_SNAP_ARRANGE = 0x0017
|
|
TS_RAIL_ORDER_GET_APPID_RESP_EX = 0x0018
|
|
TS_RAIL_ORDER_EXEC_RESULT = 0x0080
|
|
)
|
|
|
|
type RailClient struct {
|
|
w core.ChannelSender
|
|
DesktopWidth uint16
|
|
DesktopHeight uint16
|
|
RemoteApplicationProgram string
|
|
ShellWorkingDirectory string
|
|
RemoteApplicationCmdLine string
|
|
}
|
|
|
|
func NewClient() *RailClient {
|
|
return &RailClient{
|
|
DesktopWidth: 800,
|
|
DesktopHeight: 600,
|
|
RemoteApplicationProgram: "calc",
|
|
ShellWorkingDirectory: "/tmp",
|
|
}
|
|
}
|
|
|
|
type RailPDUHeader struct {
|
|
OrderType uint16 `struc:"little"`
|
|
OrderLength uint16 `struc:"little"`
|
|
}
|
|
|
|
func NewRailPDUHeader(mType, ln uint16) *RailPDUHeader {
|
|
return &RailPDUHeader{
|
|
OrderType: mType,
|
|
OrderLength: ln,
|
|
}
|
|
}
|
|
|
|
func (h *RailPDUHeader) serialize() []byte {
|
|
b := &bytes.Buffer{}
|
|
core.WriteUInt16LE(h.OrderType, b)
|
|
core.WriteUInt16LE(h.OrderLength, b)
|
|
return b.Bytes()
|
|
}
|
|
|
|
func (c *RailClient) sendData(mType uint16, ln int, s []byte) {
|
|
glog.Debug(ln, ":ln:", len(s), "data:", hex.EncodeToString(s))
|
|
header := NewRailPDUHeader(mType, uint16(ln))
|
|
|
|
b := &bytes.Buffer{}
|
|
core.WriteBytes(header.serialize(), b)
|
|
core.WriteBytes(s, b)
|
|
|
|
c.Send(b.Bytes())
|
|
}
|
|
|
|
func (c *RailClient) Send(s []byte) (int, error) {
|
|
glog.Debug("len:", len(s), "data:", hex.EncodeToString(s))
|
|
name, _ := c.GetType()
|
|
return c.w.SendToChannel(name, s)
|
|
}
|
|
func (c *RailClient) Sender(f core.ChannelSender) {
|
|
c.w = f
|
|
}
|
|
func (c *RailClient) GetType() (string, uint32) {
|
|
return ChannelName, ChannelOption
|
|
}
|
|
|
|
func (c *RailClient) Process(s []byte) {
|
|
glog.Debug("recv:", hex.EncodeToString(s))
|
|
r := bytes.NewReader(s)
|
|
msgType, _ := core.ReadUint16LE(r)
|
|
length, _ := core.ReadUint16LE(r)
|
|
|
|
glog.Infof("rail: type=0x%x length=%d, all=%d", msgType, length, r.Len())
|
|
|
|
b, _ := core.ReadBytes(int(length), r)
|
|
glog.Info("b:", hex.EncodeToString(b))
|
|
|
|
switch msgType {
|
|
case TS_RAIL_ORDER_HANDSHAKE:
|
|
glog.Info("TS_RAIL_ORDER_HANDSHAKE")
|
|
c.processOrderHandshake(b)
|
|
case TS_RAIL_ORDER_SYSPARAM:
|
|
glog.Info("TS_RAIL_ORDER_SYSPARAM")
|
|
c.processOrderSysparam(b)
|
|
case TS_RAIL_ORDER_EXEC_RESULT:
|
|
glog.Info("TS_RAIL_ORDER_EXEC_RESULT")
|
|
c.processExecResult(b)
|
|
|
|
default:
|
|
glog.Errorf("type 0x%x not supported", msgType)
|
|
}
|
|
}
|
|
|
|
func (c *RailClient) processOrderHandshake(b []byte) {
|
|
r := bytes.NewReader(b)
|
|
buildNumber, _ := core.ReadUInt32LE(r)
|
|
glog.Info("buildNumber:", buildNumber)
|
|
|
|
//send client info
|
|
c.sendClientStatus()
|
|
|
|
//send client systemparam
|
|
c.sendClientSystemparam()
|
|
|
|
//send client execute
|
|
c.sendClientExecute()
|
|
}
|
|
|
|
const (
|
|
TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE = 0x00000001
|
|
TS_RAIL_CLIENTSTATUS_AUTORECONNECT = 0x00000002
|
|
TS_RAIL_CLIENTSTATUS_ZORDER_SYNC = 0x00000004
|
|
TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED = 0x00000010
|
|
TS_RAIL_CLIENTSTATUS_HIGH_DPI_ICONS_SUPPORTED = 0x00000020
|
|
TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED = 0x00000040
|
|
TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED = 0x00000080
|
|
TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED = 0x00000100
|
|
TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED = 0x00000200
|
|
)
|
|
|
|
func (c *RailClient) sendClientStatus() {
|
|
glog.Info("Send client Status")
|
|
var flags uint32 = TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE
|
|
|
|
//if (settings->AutoReconnectionEnabled)
|
|
//clientStatus.flags |= TS_RAIL_CLIENTSTATUS_AUTORECONNECT;
|
|
|
|
flags |= TS_RAIL_CLIENTSTATUS_ZORDER_SYNC
|
|
flags |= TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED
|
|
flags |= TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED
|
|
flags |= TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED
|
|
flags |= TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED
|
|
|
|
b := &bytes.Buffer{}
|
|
core.WriteUInt32LE(flags, b)
|
|
|
|
c.sendData(TS_RAIL_ORDER_CLIENTSTATUS, 4, b.Bytes())
|
|
}
|
|
|
|
const (
|
|
SPI_SET_SCREEN_SAVE_ACTIVE = 0x00000011
|
|
SPI_SET_SCREEN_SAVE_SECURE = 0x00000077
|
|
)
|
|
const (
|
|
/*Bit mask values for SPI_ parameters*/
|
|
SPI_MASK_SET_DRAG_FULL_WINDOWS = 0x00000001
|
|
SPI_MASK_SET_KEYBOARD_CUES = 0x00000002
|
|
SPI_MASK_SET_KEYBOARD_PREF = 0x00000004
|
|
SPI_MASK_SET_MOUSE_BUTTON_SWAP = 0x00000008
|
|
SPI_MASK_SET_WORK_AREA = 0x00000010
|
|
SPI_MASK_DISPLAY_CHANGE = 0x00000020
|
|
SPI_MASK_TASKBAR_POS = 0x00000040
|
|
SPI_MASK_SET_HIGH_CONTRAST = 0x00000080
|
|
SPI_MASK_SET_SCREEN_SAVE_ACTIVE = 0x00000100
|
|
SPI_MASK_SET_SET_SCREEN_SAVE_SECURE = 0x00000200
|
|
SPI_MASK_SET_CARET_WIDTH = 0x00000400
|
|
SPI_MASK_SET_STICKY_KEYS = 0x00000800
|
|
SPI_MASK_SET_TOGGLE_KEYS = 0x00001000
|
|
SPI_MASK_SET_FILTER_KEYS = 0x00002000
|
|
)
|
|
const (
|
|
SPI_SET_DRAG_FULL_WINDOWS = 0x00000025
|
|
SPI_SET_KEYBOARD_CUES = 0x0000100B
|
|
SPI_SET_KEYBOARD_PREF = 0x00000045
|
|
SPI_SET_MOUSE_BUTTON_SWAP = 0x00000021
|
|
SPI_SET_WORK_AREA = 0x0000002F
|
|
SPI_DISPLAY_CHANGE = 0x0000F001
|
|
SPI_TASKBAR_POS = 0x0000F000
|
|
SPI_SET_HIGH_CONTRAST = 0x00000043
|
|
SPI_SETCARETWIDTH = 0x00002007
|
|
SPI_SETSTICKYKEYS = 0x0000003B
|
|
SPI_SETTOGGLEKEYS = 0x00000035
|
|
SPI_SETFILTERKEYS = 0x00000033
|
|
)
|
|
|
|
type TsFilterKeys struct {
|
|
Flags uint32
|
|
WaitTime uint32
|
|
DelayTime uint32
|
|
RepeatTime uint32
|
|
BounceTime uint32
|
|
}
|
|
type RailHighContrast struct {
|
|
flags uint32
|
|
colorSchemeLength uint32
|
|
colorScheme string
|
|
}
|
|
type Rectangle16 struct {
|
|
left uint16
|
|
top uint16
|
|
right uint16
|
|
bottom uint16
|
|
}
|
|
type RailSysparamOrder struct {
|
|
param uint32
|
|
params uint32
|
|
dragFullWindows uint8
|
|
keyboardCues uint8
|
|
keyboardPref uint8
|
|
mouseButtonSwap uint8
|
|
workArea Rectangle16
|
|
displayChange Rectangle16
|
|
taskbarPos Rectangle16
|
|
highContrast RailHighContrast
|
|
caretWidth uint32
|
|
stickyKeys uint32
|
|
toggleKeys uint32
|
|
filterKeys TsFilterKeys
|
|
setScreenSaveActive uint8
|
|
setScreenSaveSecure uint8
|
|
}
|
|
|
|
func (c *RailClient) sendClientSystemparam() {
|
|
glog.Info("Send client Systemparam")
|
|
|
|
var sp RailSysparamOrder
|
|
sp.params = 0
|
|
sp.params |= SPI_MASK_SET_HIGH_CONTRAST
|
|
sp.highContrast.colorScheme = ""
|
|
sp.highContrast.colorSchemeLength = 0
|
|
sp.highContrast.flags = 0x7E
|
|
sp.params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP
|
|
sp.mouseButtonSwap = 0
|
|
sp.params |= SPI_MASK_SET_KEYBOARD_PREF
|
|
sp.keyboardPref = 0
|
|
sp.params |= SPI_MASK_SET_DRAG_FULL_WINDOWS
|
|
sp.dragFullWindows = 0
|
|
sp.params |= SPI_MASK_SET_KEYBOARD_CUES
|
|
sp.keyboardCues = 0
|
|
sp.params |= SPI_MASK_SET_WORK_AREA
|
|
sp.workArea.left = 0
|
|
sp.workArea.top = 0
|
|
sp.workArea.right = c.DesktopWidth
|
|
sp.workArea.bottom = c.DesktopHeight
|
|
|
|
if sp.params&SPI_MASK_SET_HIGH_CONTRAST != 0 {
|
|
sp.param = SPI_SET_HIGH_CONTRAST
|
|
c.sendOneClientSysparam(&sp)
|
|
}
|
|
|
|
if sp.params&SPI_MASK_TASKBAR_POS != 0 {
|
|
sp.param = SPI_TASKBAR_POS
|
|
c.sendOneClientSysparam(&sp)
|
|
}
|
|
|
|
if sp.params&SPI_MASK_SET_MOUSE_BUTTON_SWAP != 0 {
|
|
sp.param = SPI_SET_MOUSE_BUTTON_SWAP
|
|
c.sendOneClientSysparam(&sp)
|
|
}
|
|
|
|
if sp.params&SPI_MASK_SET_KEYBOARD_PREF != 0 {
|
|
sp.param = SPI_SET_KEYBOARD_PREF
|
|
c.sendOneClientSysparam(&sp)
|
|
}
|
|
|
|
if sp.params&SPI_MASK_SET_DRAG_FULL_WINDOWS != 0 {
|
|
sp.param = SPI_SET_DRAG_FULL_WINDOWS
|
|
c.sendOneClientSysparam(&sp)
|
|
}
|
|
|
|
if sp.params&SPI_MASK_SET_KEYBOARD_CUES != 0 {
|
|
sp.param = SPI_SET_KEYBOARD_CUES
|
|
c.sendOneClientSysparam(&sp)
|
|
}
|
|
|
|
if sp.params&SPI_MASK_SET_WORK_AREA != 0 {
|
|
sp.param = SPI_SET_WORK_AREA
|
|
glog.Debug("SPI_SET_WORK_AREA")
|
|
c.sendOneClientSysparam(&sp)
|
|
}
|
|
}
|
|
|
|
func (c *RailClient) sendOneClientSysparam(sp *RailSysparamOrder) {
|
|
length := 0
|
|
b := &bytes.Buffer{}
|
|
core.WriteUInt32LE(sp.param, b)
|
|
switch sp.param {
|
|
case SPI_SET_DRAG_FULL_WINDOWS:
|
|
core.WriteUInt8(sp.dragFullWindows, b)
|
|
|
|
case SPI_SET_KEYBOARD_CUES:
|
|
core.WriteUInt8(sp.keyboardCues, b)
|
|
|
|
case SPI_SET_KEYBOARD_PREF:
|
|
core.WriteUInt8(sp.keyboardPref, b)
|
|
|
|
case SPI_SET_MOUSE_BUTTON_SWAP:
|
|
core.WriteUInt8(sp.mouseButtonSwap, b)
|
|
|
|
case SPI_SET_WORK_AREA:
|
|
core.WriteUInt16LE(sp.workArea.left, b)
|
|
core.WriteUInt16LE(sp.workArea.top, b)
|
|
core.WriteUInt16LE(sp.workArea.right, b)
|
|
core.WriteUInt16LE(sp.workArea.bottom, b)
|
|
|
|
case SPI_DISPLAY_CHANGE:
|
|
core.WriteUInt16LE(sp.displayChange.left, b)
|
|
core.WriteUInt16LE(sp.displayChange.top, b)
|
|
core.WriteUInt16LE(sp.displayChange.right, b)
|
|
core.WriteUInt16LE(sp.displayChange.bottom, b)
|
|
|
|
case SPI_TASKBAR_POS:
|
|
core.WriteUInt16LE(sp.taskbarPos.left, b)
|
|
core.WriteUInt16LE(sp.taskbarPos.top, b)
|
|
core.WriteUInt16LE(sp.taskbarPos.right, b)
|
|
core.WriteUInt16LE(sp.taskbarPos.bottom, b)
|
|
|
|
case SPI_SET_HIGH_CONTRAST:
|
|
core.WriteUInt32LE(sp.highContrast.flags, b)
|
|
core.WriteUInt32LE(sp.highContrast.colorSchemeLength, b)
|
|
data := core.UnicodeEncode(sp.highContrast.colorScheme)
|
|
core.WriteBytes(data, b)
|
|
|
|
case SPI_SETFILTERKEYS:
|
|
core.WriteUInt32LE(sp.filterKeys.Flags, b)
|
|
core.WriteUInt32LE(sp.filterKeys.WaitTime, b)
|
|
core.WriteUInt32LE(sp.filterKeys.DelayTime, b)
|
|
core.WriteUInt32LE(sp.filterKeys.RepeatTime, b)
|
|
core.WriteUInt32LE(sp.filterKeys.BounceTime, b)
|
|
|
|
case SPI_SETSTICKYKEYS:
|
|
core.WriteUInt32LE(sp.stickyKeys, b)
|
|
|
|
case SPI_SETCARETWIDTH:
|
|
core.WriteUInt32LE(sp.caretWidth, b)
|
|
|
|
case SPI_SETTOGGLEKEYS:
|
|
core.WriteUInt32LE(sp.toggleKeys, b)
|
|
|
|
case SPI_MASK_SET_SET_SCREEN_SAVE_SECURE:
|
|
core.WriteUInt8(sp.setScreenSaveSecure, b)
|
|
|
|
case SPI_MASK_SET_SCREEN_SAVE_ACTIVE:
|
|
core.WriteUInt8(sp.setScreenSaveActive, b)
|
|
|
|
default:
|
|
glog.Error("ERROR_BAD_ARGUMENTS")
|
|
return
|
|
}
|
|
|
|
c.sendData(TS_RAIL_ORDER_SYSPARAM, length+b.Len(), b.Bytes())
|
|
}
|
|
|
|
type RailExecOrder struct {
|
|
flags uint16
|
|
RemoteApplicationProgram string
|
|
RemoteApplicationWorkingDir string
|
|
RemoteApplicationArguments string
|
|
}
|
|
|
|
func (c *RailClient) sendClientExecute() {
|
|
glog.Info("Send Client Execute")
|
|
var exec RailExecOrder
|
|
//exec.flags = TS_RAIL_EXEC_FLAG_EXPAND_ARGUMENTS
|
|
exec.RemoteApplicationProgram = c.RemoteApplicationProgram
|
|
exec.RemoteApplicationWorkingDir = c.ShellWorkingDirectory
|
|
exec.RemoteApplicationArguments = c.RemoteApplicationCmdLine
|
|
|
|
program := core.UnicodeEncode(exec.RemoteApplicationProgram)
|
|
workdir := core.UnicodeEncode(exec.RemoteApplicationWorkingDir)
|
|
arguments := core.UnicodeEncode(exec.RemoteApplicationArguments)
|
|
|
|
length := 4
|
|
b := &bytes.Buffer{}
|
|
core.WriteUInt16LE(exec.flags, b)
|
|
core.WriteUInt16LE(uint16(len(program)), b)
|
|
core.WriteUInt16LE(uint16(len(workdir)), b)
|
|
core.WriteUInt16LE(uint16(len(arguments)), b)
|
|
core.WriteBytes(program, b)
|
|
core.WriteBytes(workdir, b)
|
|
core.WriteBytes(arguments, b)
|
|
length += b.Len()
|
|
|
|
c.sendData(TS_RAIL_ORDER_EXEC, length, b.Bytes())
|
|
|
|
}
|
|
|
|
func (c *RailClient) processOrderSysparam(b []byte) {
|
|
r := bytes.NewReader(b)
|
|
systemParam, _ := core.ReadUInt32LE(r)
|
|
body, _ := core.ReadUInt8(r)
|
|
glog.Infof("systemParam:0x%x, body:%d", systemParam, body)
|
|
}
|
|
|
|
const (
|
|
//The Client Execute request was successful and the requested application or file has been launched.
|
|
RAIL_EXEC_S_OK = 0x0000
|
|
//The Client Execute request could not be satisfied because the server is not monitoring the current input desktop.
|
|
RAIL_EXEC_E_HOOK_NOT_LOADED = 0x0001
|
|
//The Execute request could not be satisfied because the request PDU was malformed.
|
|
RAIL_EXEC_E_DECODE_FAILED = 0x0002
|
|
//The Client Execute request could not be satisfied because the requested application was blocked by policy from being launched on the server.
|
|
RAIL_EXEC_E_NOT_IN_ALLOWLIST = 0x0003
|
|
//The Client Execute request could not be satisfied because the application or file path could not be found.
|
|
RAIL_EXEC_E_FILE_NOT_FOUND = 0x0005
|
|
//The Client Execute request could not be satisfied because an unspecified error occurred on the server.
|
|
RAIL_EXEC_E_FAIL = 0x0006
|
|
//The Client Execute request could not be satisfied because the remote session is locked.
|
|
RAIL_EXEC_E_SESSION_LOCKED = 0x0007
|
|
)
|
|
|
|
func (c *RailClient) processExecResult(b []byte) {
|
|
r := bytes.NewReader(b)
|
|
flags, _ := core.ReadUint16LE(r)
|
|
execResult, _ := core.ReadUint16LE(r)
|
|
rawResult, _ := core.ReadUInt32LE(r)
|
|
core.ReadUint16LE(r)
|
|
exeOrFileLength, _ := core.ReadUint16LE(r)
|
|
exeOrFile, _ := core.ReadBytes(r.Len(), r)
|
|
glog.Info("flags:", flags, "execResult:", execResult, "rawResult:", rawResult)
|
|
glog.Info("length:", exeOrFileLength, "file:", core.UnicodeDecode(exeOrFile))
|
|
}
|