SMB(ServerMessage Block)通信协议是微软(Microsoft)和英特尔(Intel)在1987年制定的协议,主要是作为Microsoft网络的通讯协议。SMB 是在会话层(session layer)和表示层(presentation layer)以及小部分应用层(application layer)的协议。SMB使用了NetBIOS的应用程序接口 (Application Program Interface,简称API),一般端口使用为139,445。另外,它是一个开放性的协议,允许了协议扩展——使得它变得更大而且复杂;大约有65个最上层的作业,而每个作业都超过120个函数,甚至Windows NT也没有全部支持到,最近微软又把 SMB 改名为 CIFS(CommonInternet File System),并且加入了许多新的特色。
SMB包头部分,分布如下:
SMB Header的长度为32字节:
typedef unsigned charUCHAR;
typedef unsigned shortUSHORT;
typedef unsigned longULONG;
typedef struct {
ULONG LowPart;
LONG HighPart;
} LARGE_INTEGER;
typedef struct {
UCHAR Protocol[4]; // Contains 0xFF,'SMB'
UCHAR Command; // Command code
union {
struct {
UCHAR ErrorClass; // Error class
UCHAR Reserved; // Reserved for future use
USHORT Error; // Error code
} DosError;
ULONG Status; // 32-bit error code
} Status;
UCHAR Flags; // Flags
USHORT Flags2; // More flags
union {
USHORT Pad[6]; // Ensure section is 12 bytes long
struct {
USHORTPidHigh; // High part of PID
ULONG Unused; // Not used
ULONG Unused2;
} Extra;
};
USHORT Tid; // Tree identifier
USHORT Pid; // Caller's process id
USHORT Uid; // Unauthenticated user id
USHORT Mid; // multiplex id
} SMB_HEADER;
NETBIOS Header的长度为4字节:
typedef struct netbiosHeader
{
UCHAR Type; // Type of the packet
UCHAR Flags; // Flags
USHORT Length; // Count of data bytes (netbios header not included)
} NETBIOSHEADER,*PNETBIOSHEADER;
TCP Header为20字节。SMBCommand Header的长度不是固定的,不同的命令有不同的长度。具体命令详解参考下一章节。
这是原始核心协议的一个命令,用来删除一个空的目录。
这是原始核心协议的一个命令,用来关闭和一个有效的FID关联的对象的一个实例。
这是原始核心协议的一个命令,用来要求服务器将当前文件的所有数据和信息都写回到存储器上。
这是原始核心协议的一个命令,用来删除一个或多个常规文件。支持文件名中有通配符,允许一次删除多个文件。
这是原始核心协议的一个命令,用来重命名一个或多个文件或目录。允许文
这是原始核心协议的一个命令。用来检查指定的路径是否在服务器上存在。
此命令在LAN Manager 1.0中引入,不适用大于32-bit的文件。支持最大64-bit的实现在NT LAN Manager中引入。
此命令用来锁定一个普通文件中一段连续的数据。支持锁定任一指定文件中任意多的数据段,前提是这些数据段没有重叠的部分。锁定可以防止其他进程使用一个独立的文件句柄(FID)对文件锁定部分进行锁、读和写操作。任何进程使用获取锁的文件的FID都可以访问被锁定的数据。
此命令也可以被服务器用来发送一个OpLock中断通知消息给客户端,客户端收到后发送确认消息。这是CIFS协议中服务器发送请求消息的一个例子。
下面列举的是SMB_COM_LOCKING_ANDX后可能发送的命令
· SMB_COM_CLOSE
· SMB_COM_FLUSH
· SMB_COM_LOCKING_ANDX
· SMB_COM_READ
· SMB_COM_READ_ANDX
· SMB_COM_WRITE
· SMB_COM_WRITE_ANDX
此命令在LAN Manager 1.0中引入。为事务处理协议的传输子协议服务。这些命令可以用于CIFS文件系统内部通信的邮箱和命名管道。如果出书的数据超过了会话建立时规定的MaxBufferSize,必须使用SMB_COM_TRANSACTION_SECONDARY命令来传输超出的部分:SMB_Data.Trans_Data 和 SMB_Data.Trans_Parameter。这两部分在初始化消息中没有固定。
如果客户端没有发送完所有的SMB_Data.Trans_Data,会将DataCount设置为小于TotalDataCount的一个值。同样的,如果SMB_Data.Trans_Parameters没有发送完,会设置ParameterCount为一个小于TotalParameterCount的值。参数部分优先级高于数据部分,客户端在每个消息中应该尽量多的发送数据。服务器应该可以接收无序到达的SMB_Data.Trans_Parameters 和 SMB_Data.Trans_Data,不论是大量还是少量的数据。
在请求和响应消息中,SMB_Data.Trans_Parameters和SMB_Data.Trans_Data的位置和长度都是由SMB_Parameters.ParameterOffset、SMB_Parameters.ParameterCount,SMB_Parameters.DataOffset和SMB_Parameters.DataCount决定。另外需要说明的是,SMB_Parameters.ParameterDisplacement和SMB_Parameters.DataDisplacement可以用来改变发送数据段的序号。服务器应该优先发送SMB_Data.Trans_Parameters。客户端应该准备好组装收到的SMB_Data.Trans_Parameters和SMB_Data.Trans_Data,即使它们是乱序到达的。
此命令在LAN Manager 1.0中引入。用来完成SMB_COM_TRANSACTION中未传输完毕数据的传输。
在请求和响应消息中,SMB_Data.Trans_Parameters和SMB_Data.Trans_Data的位置和长度都是由SMB_Parameters.ParameterOffset、SMB_Parameters.ParameterCount,SMB_Parameters.DataOffset和SMB_Parameters.DataCount决定。另外需要说明的是,SMB_Parameters.ParameterDisplacement和SMB_Parameters.DataDisplacement可以用来改变发送数据段的序号。服务器应该优先发送SMB_Data.Trans_Parameters。客户端应该准备好组装收到的SMB_Data.Trans_Parameters和SMB_Data.Trans_Data,即使它们是乱序到达的。
此命令在LAN Manager 1.0中引入。客户端发送此命令测试和服务器的传输层连接。
此命令在LAN Manager 1.0中引入。用来创建并打开一个文件,或者打开一个已存在的普通文件,并执行命令链中的命令。命令中包含客户端要打开的文件名,命名管道或设备。如果执行成功,服务器响应消息中要携带一个合法的FID。客户端在后续对此文件的操作请求中要提供相同的FID。
下面这些命令是可以放在SMB_COM_OPEN_ANDX命令的AndX链中:
· SMB_COM_READ
· SMB_COM_READ_ANDX
· SMB_COM_IOCTL
· SMB_COM_NO_ANDX_COMMAND
此命令在LAN Manager 1.0中引入,在NT LAN Manager中对其进行了扩展。用来读取数据,可以读取普通文件,命名管道,或直接访问设别,比如串口(COM)或打印机接口(LPT)。如果客户端用NT LAN Manager或以后的版本协商,应该发送带有12个参数的请求,这个版本支持最大64-bit的文件。此命令是唯一一个支持读取64-bit大小文件的读取命令。
下面这些命令是可以放在SMB_COM_READ_ANDX命令的AndX链中:
· SMB_COM_CLOSE
此命令在LAN Manager 1.0中引入。用来向普通文件,命名管道,或直接访问设别,比如串口(COM)或打印机接口(LPT)中写入数据。如果客户端用NT LAN Manager或以后的版本协商,应该发送带有14个参数的请求,这个版本支持最大64-bit的文件。此命令是唯一一个支持写64-bit大小文件的读取命令。
下面这些命令是可以放在SMB_COM_WRITE_ANDX命令的AndX链中:
· SMB_COM_READ
· SMB_COM_READ_ANDX
· SMB_COM_LOCK_AND_READ
· SMB_COM_CLOSE
此命令在LAN Manager 1.2中引入。支持服务器文件系统更丰富的语义集。允许客户端设置和获取扩展的key/value属性对,支持长文件名(比原始的8.3名字格式要长),可以执行目录搜索及其他任务。
如果客户端没有发送完所有的SMB_Data.Trans_Data,会将DataCount设置为小于TotalDataCount的一个值。同样的,如果SMB_Data.Trans_Parameters没有发送完,会设置ParameterCount为一个小于TotalParameterCount的值。参数部分优先级高于数据部分,客户端在每个消息中应该尽量多的发送数据。服务器应该可以接收无序到达的SMB_Data.Trans_Parameters 和 SMB_Data.Trans_Data,不论是大量还是少量的数据。
在请求和响应消息中,SMB_Data.Trans2_Parameters和SMB_Data.Trans2_Data的位置和长度都是由SMB_Parameters.ParameterOffset、SMB_Parameters.ParameterCount,SMB_Parameters.DataOffset和SMB_Parameters.DataCount决定。另外需要说明的是,SMB_Parameters.ParameterDisplacement和SMB_Parameters.DataDisplacement可以用来改变发送数据段的序号。服务器应该优先发送SMB_Data.Trans2_Parameters。客户端应该准备好组装收到的SMB_Data.Trans2_Parameters和SMB_Data.Trans2_Data,即使它们是乱序到达的。
此命令在LAN Manager 1.2中引入。用来完成SMB_COM_TRANSACTION2中未传完的数据。
此命令在LAN Manager 1.2中引入。用来关闭由命令TRANS2_FIND_FIRST2而打开的搜索句柄,服务器释放所有和此句柄相关的资源。
这是一个原始核心协议命令。用来关闭客户端访问服务器资源时使用的一条逻辑连接,连接依靠SMB头部的TID识别,断开后服务器将此TID视为无效的TID。所有和此TID相关的文件、目录及其他资源都被释放,文件和目录的锁也会被释放。
这是一个原始核心协议命令。用来初始化服务器和客户端之间的SMB会话,必须在其他任何SMB命令发送之前完成。
每个SMB会话只能有一次协商过程,后续的SMB_COM_NEGOTIATE会被服务器拒绝并返回一个错误响应。
此命令在LAN Manager 1.0中引入。相比最初的定义,请求和响应消息的格式都有所改变。本文介绍CIFS格式,在NT LAN Manager中定义。当协商使用NT LAN Manager时必须使用此格式。
此命令用来配置一个SMB会话。如果服务器运行在user级访问控制模式,至少发送一个SMB_COM_SESSION_SETUP_ANDX命令,执行用户登录服务器并建立一个有效的UID。
在CIFS协议中,在SMB_COM_SESSION_SETUP_ANDX命令执行成功之前发送SMB_COM_TREE_CONNECT或SMB_COM_TREE_CONNECT_ANDX是违反协议的,即使服务器运行在share级的访问控制模式。在SMB_COM_SESSION_SETUP_ANDX请求之后,包含SMB_COM_TREE_CONNECT_ANDX批处理请求的AndX链可以满足这一需求,匿名认证也可以满足这一需求。
一个SMB会话用允许有多个SMB_COM_SESSION_SETUP_ANDX,用来建立额外的UID或建立额外的虚拟链路。
下面的命令可以放在SMB_COM_SESSION_SETUP_ANDX后面的AndX链中:
· SMB_COM_TREE_CONNECT_ANDX
· SMB_COM_OPEN
· SMB_COM_OPEN_ANDX
· SMB_COM_CREATE
· SMB_COM_CREATE_NEW
· SMB_COM_CREATE_DIRECTORY
· SMB_COM_DELETE
· SMB_COM_DELETE_DIRECTORY
· SMB_COM_FIND
· SMB_COM_FIND_UNIQUE
· SMB_COM_RENAME
· SMB_COM_NT_RENAME
· SMB_COM_CHECK_DIRECTORY
· SMB_COM_QUERY_INFORMATION
· SMB_COM_SET_INFORMATION
· SMB_COM_OPEN_PRINT_FILE
· SMB_COM_TRANSACTION
SMB头部UID标记的用户被注销,服务器将释放所有此UID相关的资源,包括释放锁,关闭所有的文件,断开连接,取消所有没有处理完的命令,标记此UID无效。
下面的命令可以放在SMB_COM_LOGOFF_ANDX后面的AndX链中:
· SMB_COM_SESSION_SETUP_ANDX.
此命令在LAN Manager 1.0中引入。用来建立一条客户端和服务器之间的连接,共享资源依靠共享名确定。连接建立后,此连接将用服务器返回的TID作为识别标记。
下面的命令可以放在SMB_COM_TREE_CONNECT_ANDX后面的AndX链中:
· SMB_COM_OPEN
· SMB_COM_OPEN_ANDX
· SMB_COM_CREATE
· SMB_COM_CREATE_NEW
· SMB_COM_CREATE_DIRECTORY
· SMB_COM_DELETE
· SMB_COM_DELETE_DIRECTORY
· SMB_COM_SEARCH
· SMB_COM_FIND
· SMB_COM_FIND_UNIQUE
· SMB_COM_RENAME
· SMB_COM_NT_RENAME
· SMB_COM_CHECK_DIRECTORY
· SMB_COM_QUERY_INFORMATION
· SMB_COM_SET_INFORMATION
· SMB_COM_OPEN_PRINT_FILE
· SMB_COM_TRANSACTION
此命令在NT LAN Manager中引入。扩展了由SMB_COM_TRANSACTION2提供的文件系统访问服务,允许处理非常大的参数和数据块。
SMB_COM_NT_TRANSACT消息可以超过单个SMB消息允许的最大值(由参数MaxBufferSize决定)。在这种情况下,客户端使用一个或多个SMB_COM_NT_TRANSACT_SECONDARY消息来传输和消息初始化不匹配的data和Parameter。
如果客户端没有发送完所有的SMB_Data.Trans_Data,会将DataCount设置为小于TotalDataCount的一个值。同样的,如果SMB_Data.Trans_Parameters没有发送完,会设置ParameterCount为一个小于TotalParameterCount的值。参数部分优先级高于数据部分,客户端在每个消息中应该尽量多的发送数据。服务器应该可以接收无序到达的SMB_Data.Trans_Parameters 和 SMB_Data.Trans_Data,不论是大量还是少量的数据。
在请求和响应消息中,SMB_Data.NT_Trans_Parameters和SMB_Data.nt_Trans_Data的位置和长度都是由SMB_Parameters.ParameterOffset、SMB_Parameters.ParameterCount,SMB_Parameters.DataOffset和SMB_Parameters.DataCount决定。另外需要说明的是,SMB_Parameters.ParameterDisplacement和SMB_Parameters.DataDisplacement可以用来改变发送数据段的序号。服务器应该按照自己顺序发送,优先发送SMB_Data.NT_Trans_Parameters。客户端应该准备好组装收到的SMB_Data.NT_Trans_Parameters和SMB_Data.NT_Trans_Data,即使它们是乱序到达的。
此命令用来完成SMB_COM_NT_TRANSACT中未传完的数据。
此命令在NT LAN Manager中引入。用来创建并打开一个新文件,或者打开一个已存在的文件,或打开并清空一个已存在的文件,或创建一个目录,或创建一个命名管道。返回的FID可以用在后续的请求消息中。
消息中包含客户端想要创建或打开的文件名,目录,或命名管道和RootDirectoryFID。如果执行成功,服务器返回一个FID标记打开的资源。客户端在后续的请求消息中必须携带此FID。客户端必须拥有对资源所在目录的写权限,才能创建一个新的文件或目录;或者拥有文件的写权限来执行截断文件的操作。
下面的命令可以放在SMB_COM_NT_CREATE_ANDX后面的AndX链中:
· SMB_COM_READ
· SMB_COM_READ_ANDX
· SMB_COM_IOCTL
此命令在NT LAN Manager中引入。使客户端可以取消掉pending态的请求。服务器用SMB_Header中的信息识别客户端想要取消哪些请求,服务器可以取消或立即处理这些请求。服务器对此消息不能回复响应消息。客户端应该依靠服务器对指定取消的消息的响应来判断取消消息的结果。如果服务器不能识别客户端请求中的指定消息,也不应该发送响应。
此命令主要用来取消由SMB_COM_NT_TRANSACT和NT_TRANSACT_NOTIFY_CHANGE子命令引起的多余的通知消息。客户端一般用NT_TRANSACT_NOTIFY_CHANGE命令避免轮询目录的改变。此命令另外的用途包括取消一个无限期等待繁忙资源的请求,或尝试很多次来等待一个资源的请求。
这是一个原始核心协议命令。用来创建一个打印队列缓冲文件。此文件将会在打印机中排队。当文件打印完毕后,服务器应该删除这个文件。
此命令在LAN Manager 1.0中引入。这是一个保留的值,指明一个非法的命令。客户端不应该发送此命令,服务器收到此命令后应该返回STATUS_SMB_BAD_COMMAND (ERRDOC/ERRbadfunc)。
此命令在LAN Manager 1.0中引入。设计此命令的目的是用来指明一个AndX链的结束。
客户端不应该在主命令中使用此命令,服务器在主命令中收到此命令后应该返回STATUS_SMB_BAD_COMMAND(ERRSRV/ERRbadcmd)。
在早期的SMB协议规格(见[IBM-SMB])中,此命令保留来做特定协议的扩展。这个用法已过时。在最新的微软协议文档中,包括[SMB-CORE]和[MSFT-XEXTNP],都没有描述此命令作为协议扩展或其它目的的作用。