package smb import ( "encoding/binary" "imuslab.com/smb/driver/mod/smb/encoder" ) const ProtocolSmb = "\xFFSMB" const ProtocolSmb2 = "\xFESMB" // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/6ab6ca20-b404-41fd-b91a-2ed39e3762ea type Status uint32 const ( StatusOk Status = 0x00000000 STATUS_PENDING Status = 0x00000103 StatusMoreProcessingRequired Status = 0xc0000016 StatusInvalidParameter Status = 0xc000000d StatusLogonFailure Status = 0xc000006d StatusUserSessionDeleted Status = 0xc0000203 STATUS_INVALID_SMB Status = 0x00010002 STATUS_SMB_BAD_TID Status = 0x00050002 STATUS_SMB_BAD_COMMAND Status = 0x00160002 STATUS_SMB_BAD_UID Status = 0x005B0002 STATUS_BUFFER_OVERFLOW Status = 0x80000005 STATUS_NO_MORE_FILES Status = 0x80000006 STATUS_NO_SUCK_FILE Status = 0xC000000f STATUS_STOPPED_ON_SYMLINK Status = 0x8000002D STATUS_NOT_IMPLEMENTED Status = 0xC0000002 STATUS_INVALID_PARAMETER Status = 0xC000000D STATUS_MORE_PROCESSING_REQUIRED Status = 0xC0000016 STATUS_ACCESS_DENIED Status = 0xC0000022 STATUS_BUFFER_TOO_SMALL Status = 0xC0000023 STATUS_OBJECT_NAME_NOT_FOUND Status = 0xC0000034 STATUS_OBJECT_PATH_NOT_FOUND Status = 0xC000003A STATUS_IO_TIMEOUT Status = 0xC00000B5 STATUS_FILE_IS_A_DIRECTORY Status = 0xC00000BA STATUS_NOT_SUPPORTED Status = 0xC00000BB STATUS_NETWORK_SESSION_EXPIRED Status = 0xC000035C STATUS_SMB_TOO_MANY_UIDS Status = 0xC000205A STATUS_NETWORK_NAME_DELETED Status = 0xC00000C9 STATUS_FILE_CLOSED Status = 0xC0000128 STATUS_UNSUCCESSFUL Status = 0xC0000001 STATUS_END_OF_FILE Status = 0xC0000011 ) var StatusMap = map[Status]string{ StatusOk: "OK", StatusMoreProcessingRequired: "More Processing Required", StatusInvalidParameter: "Invalid Parameter", StatusLogonFailure: "Logon failed", StatusUserSessionDeleted: "User session deleted", } // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/fac3655a-7eb5-4337-b0ab-244bbcd014e8 const DialectSmb_2_0_2 = 0x0202 const DialectSmb_2_1 = 0x0210 const DialectSmb_3_0 = 0x0300 const DialectSmb_3_0_2 = 0x0302 const DialectSmb_3_1_1 = 0x0311 const DialectSmb2_ALL = 0x02FF type Command uint16 const ( CommandNegotiate Command = iota //0 CommandSessionSetup //1 CommandLogoff //2 CommandTreeConnect //3 CommandTreeDisconnect //4 CommandCreate //5 CommandClose //6 CommandFlush //7 CommandRead //8 CommandWrite //9 CommandLock //0xa 10 CommandIOCtl //0xb 11 CommandCancel //0xc 12 CommandEcho //0xd 13 CommandFind //QueryDirectory //0xe 14 CommandChangeNotify //0xf 15 CommandQueryInfo //0x10 16 CommandSetInfo //0x11 17 CommandOplockBreak //0x12 18 ) func (c Command) String() string { switch c { case CommandNegotiate: return "CommandNegotiate" case CommandSessionSetup: return "CommandSessionSetup" case CommandLogoff: return "CommandLogoff" case CommandTreeConnect: return "CommandTreeConnect" case CommandTreeDisconnect: return "CommandTreeDisconnect" case CommandCreate: return "CommandCreate" case CommandClose: return "CommandClose" case CommandFlush: return "CommandFlush" case CommandRead: return "CommandRead" case CommandWrite: return "CommandWrite" case CommandLock: return "CommandLock" case CommandIOCtl: return "CommandIOCtl" case CommandCancel: return "CommandCancel" case CommandEcho: return "CommandEcho" case CommandFind: return "CommandQueryDirectory" case CommandChangeNotify: return "CommandChangeNotify" case CommandQueryInfo: return "CommandQueryInfo" case CommandSetInfo: return "CommandSetInfo" case CommandOplockBreak: return "CommandOplockBreak" default: return "NA" } } const ( SecurityModeSigningEnabled = 0x001 //When set, indicates that security signatures are enabled on the client. The server MUST ignore this bit. SecurityModeSigningRequired = 0x002 //When set, indicates that security signatures are required by the client. ) // const ( // _ byte = iota // ShareTypeDisk // ShareTypePipe // ShareTypePrint // ) // const ( // ShareFlagManualCaching uint32 = 0x00000000 // ShareFlagAutoCaching uint32 = 0x00000010 // ShareFlagVDOCaching uint32 = 0x00000020 // ShareFlagNoCaching uint32 = 0x00000030 // ShareFlagDFS uint32 = 0x00000001 // ShareFlagDFSRoot uint32 = 0x00000002 // ShareFlagRestriceExclusiveOpens uint32 = 0x00000100 // ShareFlagForceSharedDelete uint32 = 0x00000200 // ShareFlagAllowNamespaceCaching uint32 = 0x00000400 // ShareFlagAccessBasedDirectoryEnum uint32 = 0x00000800 // ShareFlagForceLevelIIOplock uint32 = 0x00001000 // ShareFlagEnableHashV1 uint32 = 0x00002000 // ShareFlagEnableHashV2 uint32 = 0x00004000 // ShareFlagEncryptData uint32 = 0x00008000 // ) // const ( // ShareCapDFS uint32 = 0x00000008 // ShareCapContinuousAvailability uint32 = 0x00000010 // ShareCapScaleout uint32 = 0x00000020 // ShareCapCluster uint32 = 0x00000040 // ShareCapAsymmetric uint32 = 0x00000080 // ) type HeadFlags uint32 const ( SMB2_FLAGS_RESPONSE HeadFlags = 0x00000001 SMB2_FLAGS_ASYNC_COMMAND HeadFlags = 0x00000002 SMB2_FLAGS_SIGNED HeadFlags = 0x00000008 SMB2_FLAGS_PRIORITY_MASK HeadFlags = 0x00000070 SMB2_FLAGS_DFS_OPERATIONS HeadFlags = 0x10000000 SMB2_FLAGS_REPLAY_OPERATION HeadFlags = 0x20000000 ) type Header struct { ProtocolID []byte `smb:"fixed:4"` HeaderLength uint16 //StructureSize CreditCharge uint16 Status Status Command Command Credits uint16 Flags HeadFlags //HeadFlags NextCommand uint32 // Chain Offset 就是这段的大小, 最后一段的时候为0, MessageID uint64 Reserved uint32 TreeID uint32 SessionID uint64 Signature []byte `smb:"fixed:16"` } var _ encoder.BinaryMarshallable = HeadFlags(0) func (c HeadFlags) MarshalBinary(meta *encoder.Metadata) ([]byte, error) { return MarshalBinary(c, meta, c) } func (c HeadFlags) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) { return UnmarshalBinary(c, data, meta, c) } var _ encoder.BinaryMarshallable = Status(0) func (c Status) MarshalBinary(meta *encoder.Metadata) ([]byte, error) { return MarshalBinary(c, meta, c) } func (c Status) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) { return UnmarshalBinary(c, data, meta, c) } var _ encoder.BinaryMarshallable = Command(0) func (c Command) MarshalBinary(meta *encoder.Metadata) ([]byte, error) { return MarshalBinary(c, meta, c) } func (c Command) UnmarshalBinary(data []byte, meta *encoder.Metadata) (interface{}, error) { return UnmarshalBinary(c, data, meta, c) } var _ encoder.BinaryMarshallable = Command(0) func MarshalBinary[ T Command | Status | CreateOptions | FileAttributes | AccessMask | HeadFlags | PDUType | CreateDisposition | FileInformationClass | CompletionFilter | ShareAccess | FindFlags | CreateAction | InfoType]( base T, meta *encoder.Metadata, check encoder.BinaryMarshallable) ([]byte, error) { size := binary.Size(base) switch size { default: timestamp := make([]byte, 2) binary.LittleEndian.PutUint16(timestamp, uint16(base)) return timestamp, nil case 4: timestamp := make([]byte, 4) binary.LittleEndian.PutUint32(timestamp, uint32(base)) return timestamp, nil case 1: timestamp := make([]byte, 1) timestamp[0] = uint8(base) return timestamp, nil } } func UnmarshalBinary[ T Command | Status | CreateOptions | FileAttributes | AccessMask | HeadFlags | PDUType | CreateDisposition | FileInformationClass | CompletionFilter | ShareAccess | FindFlags | CreateAction | InfoType]( base T, data []byte, meta *encoder.Metadata, check encoder.BinaryMarshallable) (T, error) { size := binary.Size(base) switch size { default: num := binary.LittleEndian.Uint16(data) meta.CurrOffset += uint64(binary.Size(num)) c := T(num) return c, nil case 4: num := binary.LittleEndian.Uint32(data) meta.CurrOffset += uint64(binary.Size(num)) c := T(num) return c, nil case 1: num := uint8(data[0]) meta.CurrOffset += uint64(binary.Size(num)) c := T(num) return c, nil } } type ErrResponse struct { Header StructureSize uint16 ErrorContextCount uint8 Reserved uint8 ByteCount uint32 ErrorData uint8 } func ERR(header Header, stat Status) (interface{}, error) { header.Flags = SMB2_FLAGS_RESPONSE header.Status = stat return ErrResponse{ Header: header, StructureSize: 0x0009, }, nil }