123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- /* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
- *
- * You can redistribute this program and/or modify it under the terms of
- * the GNU Lesser Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- */
- using System;
- using System.Collections.Generic;
- using System.IO;
- using Utilities;
- namespace SMBLibrary.SMB1
- {
- public abstract class SMB1Command
- {
- protected byte[] SMBParameters; // SMB_Parameters
- protected byte[] SMBData; // SMB_Data
- public SMB1Command()
- {
- SMBParameters = new byte[0];
- SMBData = new byte[0];
- }
- public SMB1Command(byte[] buffer, int offset, bool isUnicode)
- {
- byte wordCount = ByteReader.ReadByte(buffer, ref offset);
- SMBParameters = ByteReader.ReadBytes(buffer, ref offset, wordCount * 2);
- ushort byteCount = LittleEndianReader.ReadUInt16(buffer, ref offset);
- SMBData = ByteReader.ReadBytes(buffer, ref offset, byteCount);
- }
- public abstract CommandName CommandName
- {
- get;
- }
- public virtual byte[] GetBytes(bool isUnicode)
- {
- if (SMBParameters.Length % 2 > 0)
- {
- throw new Exception("SMB_Parameters Length must be a multiple of 2");
- }
- int length = 1 + SMBParameters.Length + 2 + SMBData.Length;
- byte[] buffer = new byte[length];
- byte wordCount = (byte)(SMBParameters.Length / 2);
- if (this is NTCreateAndXResponseExtended)
- {
- // [MS-SMB] Section 2.2.4.9.2 and Note <51>:
- // Windows-based SMB servers send 50 (0x32) words in the extended response
- // although they set the WordCount field to 0x2A
- // wordCount SHOULD be 0x2A
- wordCount = 0x2A;
- }
- ushort byteCount = (ushort)SMBData.Length;
- int offset = 0;
- ByteWriter.WriteByte(buffer, ref offset, wordCount);
- ByteWriter.WriteBytes(buffer, ref offset, SMBParameters);
- LittleEndianWriter.WriteUInt16(buffer, ref offset, byteCount);
- ByteWriter.WriteBytes(buffer, ref offset, SMBData);
- return buffer;
- }
- public static SMB1Command ReadCommand(byte[] buffer, int offset, CommandName commandName, SMB1Header header)
- {
- if ((header.Flags & HeaderFlags.Reply) > 0)
- {
- return ReadCommandResponse(buffer, offset, commandName, header.UnicodeFlag);
- }
- else
- {
- return ReadCommandRequest(buffer, offset, commandName, header.UnicodeFlag);
- }
- }
- public static SMB1Command ReadCommandRequest(byte[] buffer, int offset, CommandName commandName, bool isUnicode)
- {
- switch (commandName)
- {
- case CommandName.SMB_COM_CREATE_DIRECTORY:
- return new CreateDirectoryRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_DELETE_DIRECTORY:
- return new DeleteDirectoryRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_CLOSE:
- return new CloseRequest(buffer, offset);
- case CommandName.SMB_COM_FLUSH:
- return new FlushRequest(buffer, offset);
- case CommandName.SMB_COM_DELETE:
- return new DeleteRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_RENAME:
- return new RenameRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_QUERY_INFORMATION:
- return new QueryInformationRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_SET_INFORMATION:
- return new SetInformationRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_READ:
- return new ReadRequest(buffer, offset);
- case CommandName.SMB_COM_WRITE:
- return new WriteRequest(buffer, offset);
- case CommandName.SMB_COM_CHECK_DIRECTORY:
- return new CheckDirectoryRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_WRITE_RAW:
- return new WriteRawRequest(buffer, offset);
- case CommandName.SMB_COM_SET_INFORMATION2:
- return new SetInformation2Request(buffer, offset);
- case CommandName.SMB_COM_LOCKING_ANDX:
- return new LockingAndXRequest(buffer, offset);
- case CommandName.SMB_COM_TRANSACTION:
- return new TransactionRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_TRANSACTION_SECONDARY:
- return new TransactionSecondaryRequest(buffer, offset);
- case CommandName.SMB_COM_ECHO:
- return new EchoRequest(buffer, offset);
- case CommandName.SMB_COM_OPEN_ANDX:
- return new OpenAndXRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_READ_ANDX:
- return new ReadAndXRequest(buffer, offset);
- case CommandName.SMB_COM_WRITE_ANDX:
- return new WriteAndXRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_TRANSACTION2:
- return new Transaction2Request(buffer, offset, isUnicode);
- case CommandName.SMB_COM_TRANSACTION2_SECONDARY:
- return new Transaction2SecondaryRequest(buffer, offset);
- case CommandName.SMB_COM_FIND_CLOSE2:
- return new FindClose2Request(buffer, offset);
- case CommandName.SMB_COM_TREE_DISCONNECT:
- return new TreeDisconnectRequest(buffer, offset);
- case CommandName.SMB_COM_NEGOTIATE:
- return new NegotiateRequest(buffer, offset);
- case CommandName.SMB_COM_SESSION_SETUP_ANDX:
- {
- byte wordCount = ByteReader.ReadByte(buffer, offset);
- if (wordCount * 2 == SessionSetupAndXRequest.ParametersLength)
- {
- return new SessionSetupAndXRequest(buffer, offset, isUnicode);
- }
- else if (wordCount * 2 == SessionSetupAndXRequestExtended.ParametersLength)
- {
- return new SessionSetupAndXRequestExtended(buffer, offset, isUnicode);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_LOGOFF_ANDX:
- return new LogoffAndXRequest(buffer, offset);
- case CommandName.SMB_COM_TREE_CONNECT_ANDX:
- return new TreeConnectAndXRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_NT_TRANSACT:
- return new NTTransactRequest(buffer, offset);
- case CommandName.SMB_COM_NT_TRANSACT_SECONDARY:
- return new NTTransactSecondaryRequest(buffer, offset);
- case CommandName.SMB_COM_NT_CREATE_ANDX:
- return new NTCreateAndXRequest(buffer, offset, isUnicode);
- case CommandName.SMB_COM_NT_CANCEL:
- return new NTCancelRequest(buffer, offset);
- default:
- throw new NotImplementedException("SMB Command 0x" + commandName.ToString("X"));
- }
- }
- public static SMB1Command ReadCommandResponse(byte[] buffer, int offset, CommandName commandName, bool isUnicode)
- {
- byte wordCount = ByteReader.ReadByte(buffer, offset);
- switch (commandName)
- {
- case CommandName.SMB_COM_CREATE_DIRECTORY:
- return new CreateDirectoryResponse(buffer, offset);
- case CommandName.SMB_COM_DELETE_DIRECTORY:
- return new DeleteDirectoryResponse(buffer, offset);
- case CommandName.SMB_COM_CLOSE:
- return new CloseResponse(buffer, offset);
- case CommandName.SMB_COM_FLUSH:
- return new FlushResponse(buffer, offset);
- case CommandName.SMB_COM_DELETE:
- return new DeleteResponse(buffer, offset);
- case CommandName.SMB_COM_RENAME:
- return new RenameResponse(buffer, offset);
- case CommandName.SMB_COM_QUERY_INFORMATION:
- {
- if (wordCount * 2 == QueryInformationResponse.ParameterLength)
- {
- return new QueryInformationResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_SET_INFORMATION:
- return new SetInformationResponse(buffer, offset);
- case CommandName.SMB_COM_READ:
- {
- if (wordCount * 2 == ReadResponse.ParametersLength)
- {
- return new ReadResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_WRITE:
- {
- if (wordCount * 2 == WriteResponse.ParametersLength)
- {
- return new WriteResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_CHECK_DIRECTORY:
- return new CheckDirectoryResponse(buffer, offset);
- case CommandName.SMB_COM_WRITE_RAW:
- {
- if (wordCount * 2 == WriteRawInterimResponse.ParametersLength)
- {
- return new WriteRawInterimResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_WRITE_COMPLETE:
- {
- if (wordCount * 2 == WriteRawFinalResponse.ParametersLength)
- {
- return new WriteRawFinalResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_SET_INFORMATION2:
- return new SetInformation2Response(buffer, offset);
- case CommandName.SMB_COM_LOCKING_ANDX:
- {
- if (wordCount * 2 == LockingAndXResponse.ParametersLength)
- {
- return new LockingAndXResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_TRANSACTION:
- {
- if (wordCount * 2 == TransactionInterimResponse.ParametersLength)
- {
- return new TransactionInterimResponse(buffer, offset);
- }
- else
- {
- return new TransactionResponse(buffer, offset);
- }
- }
- case CommandName.SMB_COM_ECHO:
- {
- if (wordCount * 2 == EchoResponse.ParametersLength)
- {
- return new EchoResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_OPEN_ANDX:
- {
- if (wordCount * 2 == OpenAndXResponse.ParametersLength)
- {
- throw new NotImplementedException();
- }
- else if (wordCount * 2 == OpenAndXResponseExtended.ParametersLength)
- {
- throw new NotImplementedException();
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_READ_ANDX:
- {
- if (wordCount * 2 == ReadAndXResponse.ParametersLength)
- {
- return new ReadAndXResponse(buffer, offset, isUnicode);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_WRITE_ANDX:
- {
- if (wordCount * 2 == WriteAndXResponse.ParametersLength)
- {
- return new WriteAndXResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_TRANSACTION2:
- {
- if (wordCount * 2 == Transaction2InterimResponse.ParametersLength)
- {
- return new Transaction2InterimResponse(buffer, offset);
- }
- else
- {
- return new Transaction2Response(buffer, offset);
- }
- }
- case CommandName.SMB_COM_FIND_CLOSE2:
- return new FindClose2Response(buffer, offset);
- case CommandName.SMB_COM_TREE_DISCONNECT:
- return new TreeDisconnectResponse(buffer, offset);
- case CommandName.SMB_COM_NEGOTIATE:
- {
- // Both NegotiateResponse and NegotiateResponseExtended have WordCount set to 17
- if (wordCount * 2 == NegotiateResponse.ParametersLength)
- {
- Capabilities capabilities = (Capabilities)LittleEndianConverter.ToUInt32(buffer, offset + 20);
- if ((capabilities & Capabilities.ExtendedSecurity) > 0)
- {
- return new NegotiateResponseExtended(buffer, offset);
- }
- else
- {
- return new NegotiateResponse(buffer, offset, isUnicode);
- }
- }
- if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_SESSION_SETUP_ANDX:
- {
- if (wordCount * 2 == SessionSetupAndXResponse.ParametersLength)
- {
- return new SessionSetupAndXResponse(buffer, offset, isUnicode);
- }
- else if (wordCount * 2 == SessionSetupAndXResponseExtended.ParametersLength)
- {
- return new SessionSetupAndXResponseExtended(buffer, offset, isUnicode);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_LOGOFF_ANDX:
- {
- if (wordCount * 2 == LogoffAndXResponse.ParametersLength)
- {
- return new LogoffAndXResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_TREE_CONNECT_ANDX:
- {
- if (wordCount * 2 == TreeConnectAndXResponse.ParametersLength)
- {
- return new TreeConnectAndXResponse(buffer, offset, isUnicode);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- case CommandName.SMB_COM_NT_TRANSACT:
- {
- if (wordCount * 2 == NTTransactInterimResponse.ParametersLength)
- {
- return new NTTransactInterimResponse(buffer, offset);
- }
- else
- {
- return new NTTransactResponse(buffer, offset);
- }
- }
- case CommandName.SMB_COM_NT_CREATE_ANDX:
- {
- if (wordCount * 2 == NTCreateAndXResponse.ParametersLength)
- {
- return new NTCreateAndXResponse(buffer, offset);
- }
- else if (wordCount == 0)
- {
- return new ErrorResponse(commandName);
- }
- else
- {
- throw new InvalidDataException();
- }
- }
- default:
- throw new NotImplementedException("SMB Command 0x" + commandName.ToString("X"));
- }
- }
- public static implicit operator List<SMB1Command>(SMB1Command command)
- {
- List<SMB1Command> result = new List<SMB1Command>();
- result.Add(command);
- return result;
- }
- }
- }
|