Files
ShotRDP/grdp/plugin/rail/rail.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))
}