package pdu import ( "bytes" "errors" "fmt" "io" "ShotRDP/grdp/core" "ShotRDP/grdp/glog" "github.com/lunixbochs/struc" ) const ( PDUTYPE_DEMANDACTIVEPDU = 0x11 PDUTYPE_CONFIRMACTIVEPDU = 0x13 PDUTYPE_DEACTIVATEALLPDU = 0x16 PDUTYPE_DATAPDU = 0x17 PDUTYPE_SERVER_REDIR_PKT = 0x1A ) type PduType2 uint8 const ( PDUTYPE2_UPDATE = 0x02 PDUTYPE2_CONTROL = 0x14 PDUTYPE2_POINTER = 0x1B PDUTYPE2_INPUT = 0x1C PDUTYPE2_SYNCHRONIZE = 0x1F PDUTYPE2_REFRESH_RECT = 0x21 PDUTYPE2_PLAY_SOUND = 0x22 PDUTYPE2_SUPPRESS_OUTPUT = 0x23 PDUTYPE2_SHUTDOWN_REQUEST = 0x24 PDUTYPE2_SHUTDOWN_DENIED = 0x25 PDUTYPE2_SAVE_SESSION_INFO = 0x26 PDUTYPE2_FONTLIST = 0x27 PDUTYPE2_FONTMAP = 0x28 PDUTYPE2_SET_KEYBOARD_INDICATORS = 0x29 PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST = 0x2B PDUTYPE2_BITMAPCACHE_ERROR_PDU = 0x2C PDUTYPE2_SET_KEYBOARD_IME_STATUS = 0x2D PDUTYPE2_OFFSCRCACHE_ERROR_PDU = 0x2E PDUTYPE2_SET_ERROR_INFO_PDU = 0x2F PDUTYPE2_DRAWNINEGRID_ERROR_PDU = 0x30 PDUTYPE2_DRAWGDIPLUS_ERROR_PDU = 0x31 PDUTYPE2_ARC_STATUS_PDU = 0x32 PDUTYPE2_STATUS_INFO_PDU = 0x36 PDUTYPE2_MONITOR_LAYOUT_PDU = 0x37 ) func (p PduType2) String() string { switch p { case PDUTYPE2_UPDATE: return "PDUTYPE2_UPDATE" case PDUTYPE2_CONTROL: return "PDUTYPE2_CONTROL" case PDUTYPE2_POINTER: return "PDUTYPE2_POINTER" case PDUTYPE2_INPUT: return "PDUTYPE2_INPUT" case PDUTYPE2_SYNCHRONIZE: return "PDUTYPE2_SYNCHRONIZE" case PDUTYPE2_REFRESH_RECT: return "PDUTYPE2_REFRESH_RECT" case PDUTYPE2_PLAY_SOUND: return "PDUTYPE2_PLAY_SOUND" case PDUTYPE2_SUPPRESS_OUTPUT: return "PDUTYPE2_SUPPRESS_OUTPUT" case PDUTYPE2_SHUTDOWN_REQUEST: return "PDUTYPE2_SHUTDOWN_REQUEST" case PDUTYPE2_SHUTDOWN_DENIED: return "PDUTYPE2_SHUTDOWN_DENIED" case PDUTYPE2_SAVE_SESSION_INFO: return "PDUTYPE2_SAVE_SESSION_INFO" case PDUTYPE2_FONTLIST: return "PDUTYPE2_FONTLIST" case PDUTYPE2_FONTMAP: return "PDUTYPE2_FONTMAP" case PDUTYPE2_SET_KEYBOARD_INDICATORS: return "PDUTYPE2_SET_KEYBOARD_INDICATORS" case PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST: return "PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST" case PDUTYPE2_BITMAPCACHE_ERROR_PDU: return "PDUTYPE2_BITMAPCACHE_ERROR_PDU" case PDUTYPE2_SET_KEYBOARD_IME_STATUS: return "PDUTYPE2_SET_KEYBOARD_IME_STATUS" case PDUTYPE2_OFFSCRCACHE_ERROR_PDU: return "PDUTYPE2_OFFSCRCACHE_ERROR_PDU" case PDUTYPE2_SET_ERROR_INFO_PDU: return "PDUTYPE2_SET_ERROR_INFO_PDU" case PDUTYPE2_DRAWNINEGRID_ERROR_PDU: return "PDUTYPE2_DRAWNINEGRID_ERROR_PDU" case PDUTYPE2_DRAWGDIPLUS_ERROR_PDU: return "PDUTYPE2_DRAWGDIPLUS_ERROR_PDU" case PDUTYPE2_ARC_STATUS_PDU: return "PDUTYPE2_ARC_STATUS_PDU" case PDUTYPE2_STATUS_INFO_PDU: return "PDUTYPE2_STATUS_INFO_PDU" case PDUTYPE2_MONITOR_LAYOUT_PDU: return "PDUTYPE2_MONITOR_LAYOUT_PDU" } return "Unknown" } const ( CTRLACTION_REQUEST_CONTROL = 0x0001 CTRLACTION_GRANTED_CONTROL = 0x0002 CTRLACTION_DETACH = 0x0003 CTRLACTION_COOPERATE = 0x0004 ) const ( STREAM_UNDEFINED = 0x00 STREAM_LOW = 0x01 STREAM_MED = 0x02 STREAM_HI = 0x04 ) type FastPathUpdateType uint8 const ( FASTPATH_UPDATETYPE_ORDERS = 0x0 FASTPATH_UPDATETYPE_BITMAP = 0x1 FASTPATH_UPDATETYPE_PALETTE = 0x2 FASTPATH_UPDATETYPE_SYNCHRONIZE = 0x3 FASTPATH_UPDATETYPE_SURFCMDS = 0x4 FASTPATH_UPDATETYPE_PTR_NULL = 0x5 FASTPATH_UPDATETYPE_PTR_DEFAULT = 0x6 FASTPATH_UPDATETYPE_PTR_POSITION = 0x8 FASTPATH_UPDATETYPE_COLOR = 0x9 FASTPATH_UPDATETYPE_CACHED = 0xA FASTPATH_UPDATETYPE_POINTER = 0xB FASTPATH_UPDATETYPE_LARGE_POINTER = 0xC ) func (t FastPathUpdateType) String() string { switch t { case FASTPATH_UPDATETYPE_ORDERS: return "FASTPATH_UPDATETYPE_ORDERS" case FASTPATH_UPDATETYPE_BITMAP: return "FASTPATH_UPDATETYPE_BITMAP" case FASTPATH_UPDATETYPE_PALETTE: return "FASTPATH_UPDATETYPE_PALETTE" case FASTPATH_UPDATETYPE_SYNCHRONIZE: return "FASTPATH_UPDATETYPE_SYNCHRONIZE" case FASTPATH_UPDATETYPE_SURFCMDS: return "FASTPATH_UPDATETYPE_SURFCMDS" case FASTPATH_UPDATETYPE_PTR_NULL: return "FASTPATH_UPDATETYPE_PTR_NULL" case FASTPATH_UPDATETYPE_PTR_DEFAULT: return "FASTPATH_UPDATETYPE_PTR_DEFAULT" case FASTPATH_UPDATETYPE_PTR_POSITION: return "FASTPATH_UPDATETYPE_PTR_POSITION" case FASTPATH_UPDATETYPE_COLOR: return "FASTPATH_UPDATETYPE_COLOR" case FASTPATH_UPDATETYPE_CACHED: return "FASTPATH_UPDATETYPE_CACHED" case FASTPATH_UPDATETYPE_POINTER: return "FASTPATH_UPDATETYPE_POINTER" case FASTPATH_UPDATETYPE_LARGE_POINTER: return "FASTPATH_UPDATETYPE_LARGE_POINTER" } return "Unknown" } const ( BITMAP_COMPRESSION = 0x0001 //NO_BITMAP_COMPRESSION_HDR = 0x0400 ) /* compression types */ const ( RDP_MPPC_BIG = 0x01 RDP_MPPC_COMPRESSED = 0x20 RDP_MPPC_RESET = 0x40 RDP_MPPC_FLUSH = 0x80 RDP_MPPC_DICT_SIZE = 65536 ) type ShareDataHeader struct { SharedId uint32 `struc:"little"` Padding1 uint8 `struc:"little"` StreamId uint8 `struc:"little"` UncompressedLength uint16 `struc:"little"` PDUType2 uint8 `struc:"little"` CompressedType uint8 `struc:"little"` CompressedLength uint16 `struc:"little"` } func NewShareDataHeader(size int, type2 uint8, shareId uint32) *ShareDataHeader { return &ShareDataHeader{ SharedId: shareId, PDUType2: type2, StreamId: STREAM_LOW, UncompressedLength: uint16(size + 4), } } type PDUMessage interface { Type() uint16 Serialize() []byte } type DemandActivePDU struct { SharedId uint32 `struc:"little"` LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"` LengthCombinedCapabilities uint16 `struc:"little"` SourceDescriptor []byte `struc:"sizefrom=LengthSourceDescriptor"` NumberCapabilities uint16 `struc:"little,sizeof=CapabilitySets"` Pad2Octets uint16 `struc:"little"` CapabilitySets []Capability `struc:"sizefrom=NumberCapabilities"` SessionId uint32 `struc:"little"` } func (d *DemandActivePDU) Type() uint16 { return PDUTYPE_DEMANDACTIVEPDU } func (d *DemandActivePDU) Serialize() []byte { buff := &bytes.Buffer{} core.WriteUInt32LE(d.SharedId, buff) core.WriteUInt16LE(d.LengthSourceDescriptor, buff) core.WriteUInt16LE(d.LengthCombinedCapabilities, buff) core.WriteBytes([]byte(d.SourceDescriptor), buff) core.WriteUInt16LE(uint16(len(d.CapabilitySets)), buff) core.WriteUInt16LE(d.Pad2Octets, buff) for _, cap := range d.CapabilitySets { core.WriteUInt16LE(uint16(cap.Type()), buff) capBuff := &bytes.Buffer{} struc.Pack(capBuff, cap) capBytes := capBuff.Bytes() core.WriteUInt16LE(uint16(len(capBytes)+4), buff) core.WriteBytes(capBytes, buff) } core.WriteUInt32LE(d.SessionId, buff) return buff.Bytes() } func readDemandActivePDU(r io.Reader) (*DemandActivePDU, error) { d := &DemandActivePDU{} var err error d.SharedId, err = core.ReadUInt32LE(r) if err != nil { return nil, err } d.LengthSourceDescriptor, err = core.ReadUint16LE(r) d.LengthCombinedCapabilities, err = core.ReadUint16LE(r) sourceDescriptorBytes, err := core.ReadBytes(int(d.LengthSourceDescriptor), r) if err != nil { return nil, err } d.SourceDescriptor = sourceDescriptorBytes d.NumberCapabilities, err = core.ReadUint16LE(r) d.Pad2Octets, err = core.ReadUint16LE(r) d.CapabilitySets = make([]Capability, 0, d.NumberCapabilities) glog.Debug("NumberCapabilities is", d.NumberCapabilities) for i := 0; i < int(d.NumberCapabilities); i++ { c, err := readCapability(r) if err != nil { //return nil, err continue } d.CapabilitySets = append(d.CapabilitySets, c) } d.NumberCapabilities = uint16(len(d.CapabilitySets)) d.SessionId, err = core.ReadUInt32LE(r) if err != nil { return nil, err } return d, nil } type ConfirmActivePDU struct { SharedId uint32 `struc:"little"` OriginatorId uint16 `struc:"little"` LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"` LengthCombinedCapabilities uint16 `struc:"little"` SourceDescriptor []byte `struc:"sizefrom=LengthSourceDescriptor"` NumberCapabilities uint16 `struc:"little,sizeof=CapabilitySets"` Pad2Octets uint16 `struc:"little"` CapabilitySets []Capability `struc:"sizefrom=NumberCapabilities"` } func (*ConfirmActivePDU) Type() uint16 { return PDUTYPE_CONFIRMACTIVEPDU } func (c *ConfirmActivePDU) Serialize() []byte { buff := &bytes.Buffer{} core.WriteUInt32LE(c.SharedId, buff) core.WriteUInt16LE(c.OriginatorId, buff) core.WriteUInt16LE(uint16(len(c.SourceDescriptor)), buff) capsBuff := &bytes.Buffer{} for _, capa := range c.CapabilitySets { core.WriteUInt16LE(uint16(capa.Type()), capsBuff) capBuff := &bytes.Buffer{} struc.Pack(capBuff, capa) capBytes := capBuff.Bytes() core.WriteUInt16LE(uint16(len(capBytes)+4), capsBuff) core.WriteBytes(capBytes, capsBuff) } capsBytes := capsBuff.Bytes() core.WriteUInt16LE(uint16(2+2+len(capsBytes)), buff) core.WriteBytes(c.SourceDescriptor, buff) core.WriteUInt16LE(c.NumberCapabilities, buff) core.WriteUInt16LE(c.Pad2Octets, buff) core.WriteBytes(capsBytes, buff) return buff.Bytes() } // 9401 => share control header // 1300 => share control header // ec03 => share control header // ea030100 => shareId 66538 // ea03 => OriginatorId // 0400 // 8001 => LengthCombinedCapabilities // 72647079 // 0c00 => NumberCapabilities 12 // 0000 // caps below // 010018000100030000020000000015040000000000000000 // 02001c00180001000100010000052003000000000100000001000000 // 030058000000000000000000000000000000000000000000010014000000010000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000008403000000000000000000 // 04002800000000000000000000000000000000000000000000000000000000000000000000000000 // 0800080000001400 // 0c00080000000000 // 0d005c001500000009040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000 // 0f00080000000000 // 10003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 // 11000c000000000000000000 // 14000c000000000000000000 // 1a00080000000000 func NewConfirmActivePDU() *ConfirmActivePDU { return &ConfirmActivePDU{ OriginatorId: 0x03EA, CapabilitySets: make([]Capability, 0), SourceDescriptor: []byte("rdpy"), } } func readConfirmActivePDU(r io.Reader) (*ConfirmActivePDU, error) { p := &ConfirmActivePDU{} var err error p.SharedId, err = core.ReadUInt32LE(r) if err != nil { return nil, err } p.OriginatorId, err = core.ReadUint16LE(r) p.LengthSourceDescriptor, err = core.ReadUint16LE(r) p.LengthCombinedCapabilities, err = core.ReadUint16LE(r) sourceDescriptorBytes, err := core.ReadBytes(int(p.LengthSourceDescriptor), r) if err != nil { return nil, err } p.SourceDescriptor = sourceDescriptorBytes p.NumberCapabilities, err = core.ReadUint16LE(r) p.Pad2Octets, err = core.ReadUint16LE(r) p.CapabilitySets = make([]Capability, 0) for i := 0; i < int(p.NumberCapabilities); i++ { c, err := readCapability(r) if err != nil { return nil, err } p.CapabilitySets = append(p.CapabilitySets, c) } s, _ := core.ReadUInt32LE(r) glog.Info("sessionid:", s) return p, nil } type DeactiveAllPDU struct { ShareId uint32 `struc:"little"` LengthSourceDescriptor uint16 `struc:"little,sizeof=SourceDescriptor"` SourceDescriptor []byte } func (*DeactiveAllPDU) Type() uint16 { return PDUTYPE_DEACTIVATEALLPDU } func (d *DeactiveAllPDU) Serialize() []byte { buff := &bytes.Buffer{} struc.Pack(buff, d) return buff.Bytes() } func readDeactiveAllPDU(r io.Reader) (*DeactiveAllPDU, error) { p := &DeactiveAllPDU{} err := struc.Unpack(r, p) return p, err } type DataPDU struct { Header *ShareDataHeader Data DataPDUData } func (*DataPDU) Type() uint16 { return PDUTYPE_DATAPDU } func (d *DataPDU) Serialize() []byte { buff := &bytes.Buffer{} struc.Pack(buff, d.Header) struc.Pack(buff, d.Data) return buff.Bytes() } func NewDataPDU(data DataPDUData, shareId uint32) *DataPDU { dataBuff := &bytes.Buffer{} struc.Pack(dataBuff, data) return &DataPDU{ Header: NewShareDataHeader(len(dataBuff.Bytes()), data.Type2(), shareId), Data: data, } } func readDataPDU(r io.Reader) (*DataPDU, error) { header := &ShareDataHeader{} err := struc.Unpack(r, header) if err != nil { glog.Error("read data pdu header error", err) return nil, err } var d DataPDUData glog.Debugf("PDUType2 0x%02x", header.PDUType2) switch header.PDUType2 { case PDUTYPE2_UPDATE: d = &UpdateDataPDU{} case PDUTYPE2_SYNCHRONIZE: d = &SynchronizeDataPDU{} case PDUTYPE2_CONTROL: d = &ControlDataPDU{} case PDUTYPE2_FONTLIST: d = &FontListDataPDU{} case PDUTYPE2_SET_ERROR_INFO_PDU: d = &ErrorInfoDataPDU{} case PDUTYPE2_FONTMAP: d = &FontMapDataPDU{} case PDUTYPE2_SAVE_SESSION_INFO: d = &SaveSessionInfo{} default: err = errors.New(fmt.Sprintf("Unknown data pdu type2 0x%02x", header.PDUType2)) glog.Error(err) return nil, err } err = d.Unpack(r) if err != nil { glog.Error("Read data pdu:", err) return nil, err } p := &DataPDU{ Header: header, Data: d, } return p, nil } type DataPDUData interface { Type2() uint8 Unpack(io.Reader) error } type UpdateDataPDU struct { UpdateType uint16 Udata UpdateData } func (*UpdateDataPDU) Type2() uint8 { return PDUTYPE2_UPDATE } func (d *UpdateDataPDU) Unpack(r io.Reader) (err error) { //slow path update d.UpdateType, err = core.ReadUint16LE(r) glog.Debugf("UpdateType 0x%02x", d.UpdateType) var p UpdateData switch d.UpdateType { case FASTPATH_UPDATETYPE_ORDERS: case FASTPATH_UPDATETYPE_BITMAP: p = &BitmapUpdateDataPDU{} case FASTPATH_UPDATETYPE_PALETTE: case FASTPATH_UPDATETYPE_SYNCHRONIZE: } if p != nil { err = p.Unpack(r) if err != nil { //glog.Error("Unpack:", err) return err } } else { return errors.New(fmt.Sprintf("Unsupport slow update type 0x%x", d.UpdateType)) } d.Udata = p return nil } type BitmapUpdateDataPDU struct { NumberRectangles uint16 `struc:"little,sizeof=Rectangles"` Rectangles []BitmapData } func (*BitmapUpdateDataPDU) FastPathUpdateType() uint8 { return FASTPATH_UPDATETYPE_BITMAP } func (f *BitmapUpdateDataPDU) Unpack(r io.Reader) error { var err error f.NumberRectangles, err = core.ReadUint16LE(r) f.Rectangles = make([]BitmapData, 0, f.NumberRectangles) for i := 0; i < int(f.NumberRectangles); i++ { rect := BitmapData{} rect.DestLeft, err = core.ReadUint16LE(r) rect.DestTop, err = core.ReadUint16LE(r) rect.DestRight, err = core.ReadUint16LE(r) rect.DestBottom, err = core.ReadUint16LE(r) rect.Width, err = core.ReadUint16LE(r) rect.Height, err = core.ReadUint16LE(r) rect.BitsPerPixel, err = core.ReadUint16LE(r) rect.Flags, err = core.ReadUint16LE(r) rect.BitmapLength, err = core.ReadUint16LE(r) ln := rect.BitmapLength if rect.Flags&BITMAP_COMPRESSION != 0 && (rect.Flags&NO_BITMAP_COMPRESSION_HDR == 0) { rect.BitmapComprHdr = new(BitmapCompressedDataHeader) rect.BitmapComprHdr.CbCompFirstRowSize, err = core.ReadUint16LE(r) rect.BitmapComprHdr.CbCompMainBodySize, err = core.ReadUint16LE(r) rect.BitmapComprHdr.CbScanWidth, err = core.ReadUint16LE(r) rect.BitmapComprHdr.CbUncompressedSize, err = core.ReadUint16LE(r) ln = rect.BitmapComprHdr.CbCompMainBodySize } rect.BitmapDataStream, err = core.ReadBytes(int(ln), r) f.Rectangles = append(f.Rectangles, rect) } return err } type SynchronizeDataPDU struct { MessageType uint16 `struc:"little"` TargetUser uint16 `struc:"little"` } func (*SynchronizeDataPDU) Type2() uint8 { return PDUTYPE2_SYNCHRONIZE } func NewSynchronizeDataPDU(targetUser uint16) *SynchronizeDataPDU { return &SynchronizeDataPDU{ MessageType: 1, TargetUser: targetUser, } } func (d *SynchronizeDataPDU) Unpack(r io.Reader) error { return struc.Unpack(r, d) } type ControlDataPDU struct { Action uint16 `struc:"little"` GrantId uint16 `struc:"little"` ControlId uint32 `struc:"little"` } func (*ControlDataPDU) Type2() uint8 { return PDUTYPE2_CONTROL } func (d *ControlDataPDU) Unpack(r io.Reader) error { return struc.Unpack(r, d) } type FontListDataPDU struct { NumberFonts uint16 `struc:"little"` TotalNumFonts uint16 `struc:"little"` ListFlags uint16 `struc:"little"` EntrySize uint16 `struc:"little"` } func (*FontListDataPDU) Type2() uint8 { return PDUTYPE2_FONTLIST } func (d *FontListDataPDU) Unpack(r io.Reader) error { return struc.Unpack(r, d) } type ErrorInfoDataPDU struct { ErrorInfo uint32 `struc:"little"` } func (*ErrorInfoDataPDU) Type2() uint8 { return PDUTYPE2_SET_ERROR_INFO_PDU } func (d *ErrorInfoDataPDU) Unpack(r io.Reader) error { return struc.Unpack(r, d) } type FontMapDataPDU struct { NumberEntries uint16 `struc:"little"` TotalNumEntries uint16 `struc:"little"` MapFlags uint16 `struc:"little"` EntrySize uint16 `struc:"little"` } func (*FontMapDataPDU) Type2() uint8 { return PDUTYPE2_FONTMAP } func (d *FontMapDataPDU) Unpack(r io.Reader) error { return struc.Unpack(r, d) } type InfoType uint32 const ( INFOTYPE_LOGON = 0x00000000 INFOTYPE_LOGON_LONG = 0x00000001 INFOTYPE_LOGON_PLAINNOTIFY = 0x00000002 INFOTYPE_LOGON_EXTENDED_INFO = 0x00000003 ) const ( LOGON_EX_AUTORECONNECTCOOKIE = 0x00000001 LOGON_EX_LOGONERRORS = 0x00000002 ) type LogonFields struct { CbFileData uint32 `struc:"little"` Len uint32 //28 `struc:"little"` Version uint32 // 1 `struc:"little"` LogonId uint32 `struc:"little"` random [16]byte //16 `struc:"little"` } type SaveSessionInfo struct { InfoType uint32 Length uint16 FieldsPresent uint32 LogonId uint32 Random []byte } func (s *SaveSessionInfo) logonInfoV1(r io.Reader) (err error) { core.ReadUInt32LE(r) // cbDomain b, _ := core.ReadBytes(52, r) domain := core.UnicodeDecode(b) core.ReadUInt32LE(r) // cbUserName b, _ = core.ReadBytes(512, r) userName := core.UnicodeDecode(b) sessionId, _ := core.ReadUInt32LE(r) s.LogonId = sessionId glog.Infof("SessionId:[%d] UserName:[%s] Domain:[%s]", s.LogonId, userName, domain) return err } func (s *SaveSessionInfo) logonInfoV2(r io.Reader) (err error) { core.ReadUint16LE(r) core.ReadUInt32LE(r) sessionId, _ := core.ReadUInt32LE(r) s.LogonId = sessionId cbDomain, _ := core.ReadUInt32LE(r) cbUserName, _ := core.ReadUInt32LE(r) core.ReadBytes(558, r) b, _ := core.ReadBytes(int(cbDomain), r) domain := core.UnicodeDecode(b) b, _ = core.ReadBytes(int(cbUserName), r) userName := core.UnicodeDecode(b) glog.Infof("SessionId:[%d] UserName:[ %s] Domain:[ %s]", s.LogonId, userName, domain) return err } func (s *SaveSessionInfo) logonPlainNotify(r io.Reader) (err error) { core.ReadBytes(576, r) /* pad (576 bytes) */ return err } func (s *SaveSessionInfo) logonInfoExtended(r io.Reader) (err error) { s.Length, err = core.ReadUint16LE(r) s.FieldsPresent, err = core.ReadUInt32LE(r) //glog.Info("FieldsPresent:", s.FieldsPresent) // auto reconnect cookie if s.FieldsPresent&LOGON_EX_AUTORECONNECTCOOKIE != 0 { core.ReadUInt32LE(r) b, _ := core.ReadUInt32LE(r) if b != 28 { return errors.New(fmt.Sprintf("invalid length in Auto-Reconnect packet")) } b, _ = core.ReadUInt32LE(r) if b != 1 { return errors.New(fmt.Sprintf("unsupported version of Auto-Reconnect packet")) } b, _ = core.ReadUInt32LE(r) s.LogonId = b s.Random, _ = core.ReadBytes(16, r) } else { // logon error info core.ReadUInt32LE(r) b, _ := core.ReadUInt32LE(r) b, _ = core.ReadUInt32LE(r) s.LogonId = b } core.ReadBytes(570, r) return err } func (s *SaveSessionInfo) Unpack(r io.Reader) (err error) { s.InfoType, err = core.ReadUInt32LE(r) switch s.InfoType { case INFOTYPE_LOGON: err = s.logonInfoV1(r) case INFOTYPE_LOGON_LONG: err = s.logonInfoV2(r) case INFOTYPE_LOGON_PLAINNOTIFY: err = s.logonPlainNotify(r) case INFOTYPE_LOGON_EXTENDED_INFO: err = s.logonInfoExtended(r) default: glog.Errorf("Unhandled saveSessionInfo type 0x%x", s.InfoType) return fmt.Errorf("Unhandled saveSessionInfo type 0x%x", s.InfoType) } return err } func (*SaveSessionInfo) Type2() uint8 { return PDUTYPE2_SAVE_SESSION_INFO } type PersistKeyPDU struct { NumEntriesCache0 uint16 `struc:"little"` NumEntriesCache1 uint16 `struc:"little"` NumEntriesCache2 uint16 `struc:"little"` NumEntriesCache3 uint16 `struc:"little"` NumEntriesCache4 uint16 `struc:"little"` TotalEntriesCache0 uint16 `struc:"little"` TotalEntriesCache1 uint16 `struc:"little"` TotalEntriesCache2 uint16 `struc:"little"` TotalEntriesCache3 uint16 `struc:"little"` TotalEntriesCache4 uint16 `struc:"little"` BBitMask uint8 `struc:"little"` Pad1 uint8 `struc:"little"` Ppad3 uint16 `struc:"little"` } func (*PersistKeyPDU) Type2() uint8 { return PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST } type UpdateData interface { FastPathUpdateType() uint8 Unpack(io.Reader) error } type BitmapCompressedDataHeader struct { CbCompFirstRowSize uint16 `struc:"little"` CbCompMainBodySize uint16 `struc:"little"` CbScanWidth uint16 `struc:"little"` CbUncompressedSize uint16 `struc:"little"` } type BitmapData struct { DestLeft uint16 `struc:"little"` DestTop uint16 `struc:"little"` DestRight uint16 `struc:"little"` DestBottom uint16 `struc:"little"` Width uint16 `struc:"little"` Height uint16 `struc:"little"` BitsPerPixel uint16 `struc:"little"` Flags uint16 `struc:"little"` BitmapLength uint16 `struc:"little,sizeof=BitmapDataStream"` BitmapComprHdr *BitmapCompressedDataHeader BitmapDataStream []byte } func (b *BitmapData) IsCompress() bool { return b.Flags&BITMAP_COMPRESSION != 0 } type FastPathBitmapUpdateDataPDU struct { Header uint16 `struc:"little"` NumberRectangles uint16 `struc:"little,sizeof=Rectangles"` Rectangles []BitmapData } func (f *FastPathBitmapUpdateDataPDU) Unpack(r io.Reader) error { var err error f.Header, err = core.ReadUint16LE(r) f.NumberRectangles, err = core.ReadUint16LE(r) f.Rectangles = make([]BitmapData, 0, f.NumberRectangles) for i := 0; i < int(f.NumberRectangles); i++ { rect := BitmapData{} rect.DestLeft, err = core.ReadUint16LE(r) rect.DestTop, err = core.ReadUint16LE(r) rect.DestRight, err = core.ReadUint16LE(r) rect.DestBottom, err = core.ReadUint16LE(r) rect.Width, err = core.ReadUint16LE(r) rect.Height, err = core.ReadUint16LE(r) rect.BitsPerPixel, err = core.ReadUint16LE(r) rect.Flags, err = core.ReadUint16LE(r) rect.BitmapLength, err = core.ReadUint16LE(r) ln := rect.BitmapLength if rect.Flags&BITMAP_COMPRESSION != 0 && (rect.Flags&NO_BITMAP_COMPRESSION_HDR == 0) { rect.BitmapComprHdr = new(BitmapCompressedDataHeader) rect.BitmapComprHdr.CbCompFirstRowSize, err = core.ReadUint16LE(r) rect.BitmapComprHdr.CbCompMainBodySize, err = core.ReadUint16LE(r) rect.BitmapComprHdr.CbScanWidth, err = core.ReadUint16LE(r) rect.BitmapComprHdr.CbUncompressedSize, err = core.ReadUint16LE(r) ln = rect.BitmapComprHdr.CbCompMainBodySize } rect.BitmapDataStream, err = core.ReadBytes(int(ln), r) f.Rectangles = append(f.Rectangles, rect) } return err } func (*FastPathBitmapUpdateDataPDU) FastPathUpdateType() uint8 { return FASTPATH_UPDATETYPE_BITMAP } type FastPathColorPdu struct { CacheIdx uint16 X uint16 Y uint16 Width uint16 Height uint16 MaskLen uint16 `struc:"little,sizeof=Mask"` DataLen uint16 `struc:"little,sizeof=Data"` Mask []byte Data []byte } func (*FastPathColorPdu) FastPathUpdateType() uint8 { return FASTPATH_UPDATETYPE_COLOR } func (f *FastPathColorPdu) Unpack(r io.Reader) error { return struc.Unpack(r, f) } type FastPathSurfaceCmds struct { } func (*FastPathSurfaceCmds) FastPathUpdateType() uint8 { return FASTPATH_UPDATETYPE_SURFCMDS } func (f *FastPathSurfaceCmds) Unpack(r io.Reader) error { cmdType, _ := core.ReadUint16LE(r) switch cmdType { } return nil } type FastPathUpdatePDU struct { UpdateHeader uint8 Fragmentation uint8 CompressionFlags uint8 Size uint16 Data UpdateData } const ( FASTPATH_OUTPUT_COMPRESSION_USED = 0x2 ) const ( FASTPATH_FRAGMENT_SINGLE = (0x0 << 4) FASTPATH_FRAGMENT_LAST = (0x1 << 4) FASTPATH_FRAGMENT_FIRST = (0x2 << 4) FASTPATH_FRAGMENT_NEXT = (0x3 << 4) ) func readFastPathUpdatePDU(r io.Reader, code uint8) (*FastPathUpdatePDU, error) { f := &FastPathUpdatePDU{} var err error var d UpdateData //glog.Debugf("FastPathPDU type %s(0x%x)", FastPathUpdateType(code), code) switch code { case FASTPATH_UPDATETYPE_ORDERS: d = &FastPathOrdersPDU{} case FASTPATH_UPDATETYPE_BITMAP: d = &FastPathBitmapUpdateDataPDU{} case FASTPATH_UPDATETYPE_PALETTE: case FASTPATH_UPDATETYPE_SYNCHRONIZE: case FASTPATH_UPDATETYPE_SURFCMDS: //d = &FastPathSurfaceCmds{} case FASTPATH_UPDATETYPE_PTR_NULL: case FASTPATH_UPDATETYPE_PTR_DEFAULT: case FASTPATH_UPDATETYPE_PTR_POSITION: case FASTPATH_UPDATETYPE_COLOR: //d = &FastPathColorPdu{} case FASTPATH_UPDATETYPE_CACHED: case FASTPATH_UPDATETYPE_POINTER: case FASTPATH_UPDATETYPE_LARGE_POINTER: default: glog.Debugf("Unknown FastPathPDU type 0x%x", code) return f, errors.New(fmt.Sprintf("Unknown FastPathPDU type 0x%x", code)) } if d != nil { err = d.Unpack(r) if err != nil { //glog.Error("Unpack:", err) return nil, err } } else { return nil, errors.New(fmt.Sprintf("Unsupport FastPathPDU type 0x%x", code)) } f.Data = d return f, nil } type ShareControlHeader struct { TotalLength uint16 `struc:"little"` PDUType uint16 `struc:"little"` PDUSource uint16 `struc:"little"` } type PDU struct { ShareCtrlHeader *ShareControlHeader Message PDUMessage } func NewPDU(userId uint16, message PDUMessage) *PDU { pdu := &PDU{} pdu.ShareCtrlHeader = &ShareControlHeader{ TotalLength: uint16(len(message.Serialize()) + 6), PDUType: message.Type(), PDUSource: userId, } pdu.Message = message return pdu } func readPDU(r io.Reader) (*PDU, error) { pdu := &PDU{} var err error header := &ShareControlHeader{} err = struc.Unpack(r, header) if err != nil { return nil, err } pdu.ShareCtrlHeader = header var d PDUMessage switch pdu.ShareCtrlHeader.PDUType { case PDUTYPE_DEMANDACTIVEPDU: glog.Debug("PDUTYPE_DEMANDACTIVEPDU") d, err = readDemandActivePDU(r) case PDUTYPE_DATAPDU: glog.Debug("PDUTYPE_DATAPDU") d, err = readDataPDU(r) case PDUTYPE_CONFIRMACTIVEPDU: glog.Debug("PDUTYPE_CONFIRMACTIVEPDU") d, err = readConfirmActivePDU(r) case PDUTYPE_DEACTIVATEALLPDU: glog.Debug("PDUTYPE_DEACTIVATEALLPDU") d, err = readDeactiveAllPDU(r) default: glog.Errorf("PDU invalid pdu type: 0x%02x", pdu.ShareCtrlHeader.PDUType) } if err != nil { return nil, err } pdu.Message = d return pdu, err } func (p *PDU) serialize() []byte { buff := &bytes.Buffer{} struc.Pack(buff, p.ShareCtrlHeader) core.WriteBytes(p.Message.Serialize(), buff) return buff.Bytes() } type SlowPathInputEvent struct { EventTime uint32 `struc:"little"` MessageType uint16 `struc:"little"` Size int `struc:"skip"` SlowPathInputData []byte `struc:"sizefrom=Size"` } type PointerEvent struct { PointerFlags uint16 `struc:"little"` XPos uint16 `struc:"little"` YPos uint16 `struc:"little"` } func (p *PointerEvent) Serialize() []byte { buff := &bytes.Buffer{} struc.Pack(buff, p) return buff.Bytes() } type SynchronizeEvent struct { Pad2Octets uint16 `struc:"little"` ToggleFlags uint32 `struc:"little"` } func (p *SynchronizeEvent) Serialize() []byte { buff := &bytes.Buffer{} struc.Pack(buff, p) return buff.Bytes() } type ScancodeKeyEvent struct { KeyboardFlags uint16 `struc:"little"` KeyCode uint16 `struc:"little"` Pad2Octets uint16 `struc:"little"` } func (p *ScancodeKeyEvent) Serialize() []byte { buff := &bytes.Buffer{} struc.Pack(buff, p) return buff.Bytes() } type UnicodeKeyEvent struct { KeyboardFlags uint16 `struc:"little"` Unicode uint16 `struc:"little"` Pad2Octets uint16 `struc:"little"` } func (p *UnicodeKeyEvent) Serialize() []byte { buff := &bytes.Buffer{} struc.Pack(buff, p) return buff.Bytes() } type ClientInputEventPDU struct { NumEvents uint16 `struc:"little,sizeof=SlowPathInputEvents"` Pad2Octets uint16 `struc:"little"` SlowPathInputEvents []SlowPathInputEvent `struc:"little"` } func (*ClientInputEventPDU) Type2() uint8 { return PDUTYPE2_INPUT } func (*ClientInputEventPDU) Unpack(io.Reader) error { return nil }