SMB Message SMB消息包含:32字节 smb header, 可变长 parameter block,和最大64K的data block
SMB_Header //消息头
{
SMB_Parameters //参数块{
{
{
SMB_Header //消息头
{
UCHAR Protocol[4]; //4字节}
UCHAR Command; //1字节
SMB_ERROR Status; //4字节
UCHAR Flags; //1字节
USHORT Flags2; //2字节
USHORT PIDHigh; //2字节
UCHAR SecurityFeatures[8]; //8字节 =4 key+2 CID+2 sequenceNumber
USHORT Reserved; //2字节
USHORT TID; //2字节
USHORT PIDLow; //2字节
USHORT UID; //2字节
USHORT MID; //2字节
SMB_Parameters //参数块{
SMB_Data //数据块UCHAR WordCount; //1字节
USHORT Words[WordCount] (variable); //2字节*n 最后一项为空
}
{
USHORT ByteCount; //2字节
UCHAR Bytes[ByteCount] (variable); //1字节*n
}
(注:数据为空时包的长度为39,此时 参数块和数据块均为空)
AndX //批处理消息(只发送一次命令头,然后是 参数/数据块对,链表以一个空命令结束){
UCHAR AndXCommand;//1字节,下一个数据块对的命令码
UCHAR AndXReserved;//1字节,为0x0000
USHORT AndXOffset;//1字节,下一个数据块相对命令头的偏移
}
SMB 命令:(按功能分)
Session management:会话管理
SMB_COM_NEGOTIATE: 0x72 协义协商(当前使用)
SMB_COM_SESSION_SETUP_ANDX: 0x73 开始一个AndX链会话(当前使用)
SMB_COM_TREE_CONNECT: 0x70 连接到一个共享(不推荐)
SMB_COM_TREE_CONNECT_ANDX: 0x75 tree连接用andX链(当前使用)[0x76-0x7d unused]
SMB_COM_TREE_DISCONNECT: 0x71 断开一个共享(当前使用)
SMB_COM_LOGOFF_ANDX: 0x74 用户退出用AndX链(当前使用)
Transaction subprotocol:传输子协议
SMB_COM_TRANSACTION: 0x25 传输(当前使用)
SMB_COM_TRANSACTION_SECONDARY:0x26 传输子请求(当前使用)
SMB_COM_TRANSACTION2: 0x32 传输两种格式请求/响应(当前使用)
SMB_COM_TRANSACTION2_SECONDARY:0x33 传输二级子请求(当前使用)
SMB_COM_NT_TRANSACT: 0xa0 NT格式的请求/响应(当前使用)
SMB_COM_NT_TRANSACT_SECONDARY:0xa1 NT格式的传输子请求
File/directory access methods:文件/目录访问
SMB_COM_CREATE_DIRECTORY: 0x00 创建一个目录(不推荐)
SMB_COM_DELETE_DIRECTORY: 0x01 删除一个空目录(当前使用)
SMB_COM_OPEN: 0x02 打开一个文件(不推荐)
SMB_COM_OPEN_ANDX: 0x2d 打开一个扩展文件(不推荐)
SMB_COM_CREATE: 0x03 创建或打开一个文件(不推荐)
SMB_COM_CREATE_NEW: 0x0f 创建或打开一个新的文件(不推荐)
SMB_COM_CREATE_TEMPORARY: 0x0e 创建一个临时文件(obsolescent)
SMB_COM_NT_CREATE_ANDX: 0xa2 创建或打开一个目录(当前使用)
SMB_COM_CLOSE: 0x04 关闭一个文件(当前使用)
SMB_COM_DELETE: 0x06 删除一个文件(当前使用)
Read/write/lock methods:读/写/锁方法
SMB_COM_FLUSH: 0x05 刷新文件(当前使用)
SMB_COM_SEEK: 0x12 (obsolescent)
SMB_COM_READ: 0x0a 从文件读(不推荐)
SMB_COM_LOCK_AND_READ: 0x13 锁定并且读取一个字节范围的文件(不推荐)
SMB_COM_LOCK_BYTE_RANGE: 0x0c 请求一个字节范围锁(不推荐)
SMB_COM_UNLOCK_BYTE_RANGE: 0x0d 释放字节范围锁(不推荐)
SMB_COM_LOCKING_ANDX: 0x24 锁定多字节范围,AndX链(当前使用)
SMB_COM_READ_ANDX: 0x2e 读扩展文件用AndX链(当前使用)
SMB_COM_READ_RAW: 0x1a 读一个块以raw模式(不推荐)
SMB_COM_READ_MPX: 0x1b 多点读块(已废除)
SMB_COM_WRITE: 0x0b 从文件写(不推荐)
SMB_COM_WRITE_AND_CLOSE: 0x2c 写并关闭文件(不推荐)
SMB_COM_WRITE_AND_UNLOCK: 0x14 写并解锁一个字节范围的文件(不推荐)[0x15-0x19 未使用]
SMB_COM_WRITE_ANDX: 0x2f 写扩展文件用AndX链(当前使用)
SMB_COM_WRITE_RAW: 0x1d 写一个块以raw模式(不推荐)
SMB_COM_WRITE_COMPLETE: 0x20 写raw块,最后响应(不推荐)
SMB_COM_WRITE_MPX: 0x1e 多点(multiplexed)写块(已废除)
Query directory information:查询目录信息
SMB_COM_CHECK_DIRECTORY: 0x10 验证路径名解析到目录(当前使用)
SMB_COM_SEARCH: 0x81 目录通配符搜索(不推荐)
SMB_COM_FIND: 0x82 开始或继续一个扩展的通配符搜索(不推荐)
SMB_COM_FIND_UNIQUE: 0x83 执行一次性通配符搜索(不推荐)
SMB_COM_FIND_CLOSE: 0x84 结束一个扩展的通配符搜索(不推荐)[0x85-0x9f unused]
SMB_COM_FIND_CLOSE2: 0x34 关闭一个激活的搜索(当前使用) [0x36-0x5f Unused][0x60-0x6f Reserved]
Query/set attributes methods:查询或设置属性类
SMB_COM_RENAME: 0x07 重命名一个文件(当前使用)
SMB_COM_NT_RENAME: 0xa5 用扩展语义重命名文件(已废除)[0xa6-0xbf unused]
SMB_COM_QUERY_INFORMATION: 0x8 获取文件属性(不推荐)
SMB_COM_SET_INFORMATION: 0x09 设置文件属性(不推荐)
SMB_COM_QUERY_INFORMATION_DISK:0x80 获取文件系统信息(不推荐)
SMB_COM_QUERY_INFORMATION2: 0x23 获取文件扩展属性(不推荐)
SMB_COM_SET_INFORMATION2: 0x22 设置文件的扩展属性(不推荐)
Printing methods:打印类
SMB_COM_OPEN_PRINT_FILE: 0xc0 创建一个打印队列文件(当前使用)
SMB_COM_WRITE_PRINT_FILE: 0xc1 写打印队列文件(不推荐)
SMB_COM_CLOSE_PRINT_FILE: 0xc2 关闭打印队列文件(不推荐) [0xc4-0xcf unused 0xd0-0xd7 reserved]
Other:其它
SMB_COM_ECHO: 0x2b 回显一个请求ping(当前使用)
SMB_COM_PROCESS_EXIT: 0x11 表明进程退出(已废除)
SMB_COM_NT_CANCEL: 0xa4 取消一个正在阻塞的请求(当前使用)
SMB_COM_INVALID: 0xfe 不可能命令(当前使用)
SMB_COM_IOCTL: 0x27 IO控制请求(已废除)
SMB_COM_NO_ANDX_COMMAND: 0xff 表示AndX链接尾的空命令(当前使用)
样例:(只能打印第一个包信息)
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
typedef unsigned short uint16;
int NeedSwap=0;
typedef unsigned char BOOL;
#define PVAL(buf,pos,type) (*((type*)(buf+pos)))
#define CVAL(buf,pos) PVAL(buf,pos,unsigned char)
#define SVAL(buf,pos) sval((char *)buf,pos)
#define SSWP(x) (NeedSwap? uint16_byte_swap((uint16)x):(x))
void object_byte_swap(void *obj,int size)
{
int i; char c;
char *p1 = (char *)obj;
char *p2 = p1 + size - 1;
size /= 2;
for (i=0;i<size;i++){
c = *p1; *p1 = *p2; *p2 = c; p1++; p2--;
}
}
uint16 uint16_byte_swap(uint16 x)
{
uint16 res;
res = x;
object_byte_swap(&res,sizeof(res));
return(res);
}
uint16 sval(char *buf,int pos)
{
uint16 res;
memcpy((char *)&res,buf + pos,sizeof(uint16));
res = SSWP(res);
return(res);
}
#define smb_size 39 //DATA块为空时包的长度
#define smb_com 8 //SMB head 头中:command
#define smb_rcls 9 //status1
#define smb_reh 10 //status2
#define smb_err 11 //status3
#define smb_flg 13 //flags1
#define smb_flg2 14 //flags2
#define smb_reb 13 //flags1+2
#define smb_tid 28 //tid域
#define smb_pid 30 //PID域
#define smb_uid 32 //UID域
#define smb_mid 34 //MID域
#define smb_wct 36 //parameter 参数个数
#define smb_vwv 37 //参数域
#define smb_vwv0 37 //第0个参数
#define smb_vwv1 39 //第1个参数
#define smb_vwv2 41
#define smb_vwv3 43
#define smb_vwv4 45
#define smb_vwv5 47
#define smb_vwv6 49
#define smb_vwv7 51
#define smb_vwv8 53
#define smb_vwv9 55
#define smb_vwv10 57
#define smb_vwv11 59
int Client;
int smb_len(char *buf)
{
int msg_flags = CVAL(buf,1);
int len = (CVAL(buf,2) << 8) + CVAL(buf,3);
if (msg_flags & 1)
len += 1<<16;
return len;
}
void show_msg(char *buf)
{
int i;
printf("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\n", \
smb_len(buf), \
(int)CVAL(buf,smb_com), \
(int)CVAL(buf,smb_rcls), \
(int)CVAL(buf,smb_reh), \
(int)SVAL(buf,smb_err)); \
printf("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n", \
(int)SVAL(buf,smb_tid), \
(int)SVAL(buf,smb_pid), \
(int)SVAL(buf,smb_uid), \
(int)SVAL(buf,smb_mid), \
(int)CVAL(buf,smb_wct));
for (i=0;i<(int)CVAL(buf,smb_wct);i++)
printf("smb_vwv[%d]=%d (0x%X)\n",i, SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i));
printf("smb_bcc=%d\n",(int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)))); //data块
}
int read_data(int fd,char*buf,int N){
int nready;
int nread=0;
while(nread<N){
nready=read(fd,buf+nread,N-nread);
if(nready<=0) {printf("read failed !\n");exit(1);}
nread+=nready;
}
return 1;
}
int receive_smb(char *buffer)
{
int len, msg_type;
int fd = Client;
memset(buffer,0,smb_size + 100);
again:
if (!read_data(fd,buffer,4))
{
printf("couldn't read from client\n");
close(Client);
exit(1);
}
len = smb_len(buffer);
msg_type = CVAL(buffer,0);
if(len == 0 && msg_type == 0x85) {
printf("Got keepalive packet\n");
goto again;
}
if (!read_data(fd,buffer + 4,len))
{
printf("couldn't read %d bytes from client. Exiting\n",len);
close(Client);
exit(1);
}
//log_in(buffer,len+4);
return(len + 4);
}
void process(int fd){ //接受客户访问
int trans_num=0; //记录传输次数
int nread;
char*inbuffer;
char*outbuffer;
inbuffer=(char*)malloc(0xffff);//64k
outbuffer=(char*)malloc(0xffff);//64k
//while(1){
int len,msg_type,msg_flags,type;
if(!receive_smb(inbuffer))
return ;
msg_type=CVAL(inbuffer,0); //netbios head type(代表SMB包类型)
msg_flags=CVAL(inbuffer,1); //netbios flag
len=smb_len(inbuffer); //lenth SMB包长度
nread=len+4; //SMB长度+4 NETBIOS头长度
type=CVAL(inbuffer,smb_com); //smb command
printf("got netbios message[type:0x%x,flag=0x%x,len=%d]\n",msg_type,msg_flags,len);
show_msg(inbuffer);
//}
}
BOOL big_endian(void){
int x=2;
char*s;
s=(char*)&x;
return (s[0]==0);
}
int main(){
int daemon=0;
int port=139;
NeedSwap=big_endian();
//init_structs();
//lp_load(CONFIG_FILE);
struct sockaddr addr;
socklen_t addr_len;
struct sockaddr_in sock;
char host_name[100];
struct hostent *hp;
int in_addrlen = sizeof(addr);
int s;
memset(&sock, 0, sizeof(sock));
sock.sin_port = htons( 139 );
sock.sin_family = AF_INET;
sock.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, SOCK_STREAM, 0);
/* now we've got a socket - we need to bind it */
bind(s, (struct sockaddr * ) &sock,sizeof(sock));
listen(s, 5);
while(Client=accept(s,&addr,&addr_len)){
if(fork()==0){
//int one=1;
//signal(SIGPIPE, abort);
//setsockopt(Client,SOL_SOCKET,SO_KEEPALIVE,&one,sizeof(one));
process(Client);
exit(0);
}
}
}