SMB2Command.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /* Copyright (C) 2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Security.Cryptography;
  10. using Utilities;
  11. namespace SMBLibrary.SMB2
  12. {
  13. public abstract class SMB2Command
  14. {
  15. public SMB2Header Header;
  16. public SMB2Command(SMB2CommandName commandName)
  17. {
  18. Header = new SMB2Header(commandName);
  19. }
  20. public SMB2Command(byte[] buffer, int offset)
  21. {
  22. Header = new SMB2Header(buffer, offset);
  23. }
  24. public void WriteBytes(byte[] buffer, int offset)
  25. {
  26. Header.WriteBytes(buffer, offset);
  27. WriteCommandBytes(buffer, offset + SMB2Header.Length);
  28. }
  29. public abstract void WriteCommandBytes(byte[] buffer, int offset);
  30. public byte[] GetBytes()
  31. {
  32. byte[] buffer = new byte[this.Length];
  33. WriteBytes(buffer, 0);
  34. return buffer;
  35. }
  36. public SMB2CommandName CommandName
  37. {
  38. get
  39. {
  40. return Header.Command;
  41. }
  42. }
  43. public int Length
  44. {
  45. get
  46. {
  47. return SMB2Header.Length + CommandLength;
  48. }
  49. }
  50. public abstract int CommandLength
  51. {
  52. get;
  53. }
  54. public static SMB2Command ReadRequest(byte[] buffer, int offset)
  55. {
  56. SMB2CommandName Command = (SMB2CommandName)LittleEndianConverter.ToUInt16(buffer, offset + 12);
  57. switch (Command)
  58. {
  59. case SMB2CommandName.Negotiate:
  60. return new NegotiateRequest(buffer, offset);
  61. case SMB2CommandName.SessionSetup:
  62. return new SessionSetupRequest(buffer, offset);
  63. case SMB2CommandName.Logoff:
  64. return new LogoffRequest(buffer, offset);
  65. case SMB2CommandName.TreeConnect:
  66. return new TreeConnectRequest(buffer, offset);
  67. case SMB2CommandName.TreeDisconnect:
  68. return new TreeDisconnectRequest(buffer, offset);
  69. case SMB2CommandName.Create:
  70. return new CreateRequest(buffer, offset);
  71. case SMB2CommandName.Close:
  72. return new CloseRequest(buffer, offset);
  73. case SMB2CommandName.Flush:
  74. return new FlushRequest(buffer, offset);
  75. case SMB2CommandName.Read:
  76. return new ReadRequest(buffer, offset);
  77. case SMB2CommandName.Write:
  78. return new WriteRequest(buffer, offset);
  79. case SMB2CommandName.Lock:
  80. return new LockRequest(buffer, offset);
  81. case SMB2CommandName.IOCtl:
  82. return new IOCtlRequest(buffer, offset);
  83. case SMB2CommandName.Cancel:
  84. return new CancelRequest(buffer, offset);
  85. case SMB2CommandName.Echo:
  86. return new EchoRequest(buffer, offset);
  87. case SMB2CommandName.QueryDirectory:
  88. return new QueryDirectoryRequest(buffer, offset);
  89. case SMB2CommandName.ChangeNotify:
  90. return new ChangeNotifyRequest(buffer, offset);
  91. case SMB2CommandName.QueryInfo:
  92. return new QueryInfoRequest(buffer, offset);
  93. case SMB2CommandName.SetInfo:
  94. return new SetInfoRequest(buffer, offset);
  95. default:
  96. throw new System.IO.InvalidDataException("Invalid SMB2 command in buffer");
  97. }
  98. }
  99. public static List<SMB2Command> ReadRequestChain(byte[] buffer, int offset)
  100. {
  101. List<SMB2Command> result = new List<SMB2Command>();
  102. SMB2Command command;
  103. do
  104. {
  105. command = ReadRequest(buffer, offset);
  106. result.Add(command);
  107. offset += (int)command.Header.NextCommand;
  108. }
  109. while (command.Header.NextCommand != 0);
  110. return result;
  111. }
  112. public static byte[] GetCommandChainBytes(List<SMB2Command> commands)
  113. {
  114. return GetCommandChainBytes(commands, null);
  115. }
  116. /// <param name="sessionKey">
  117. /// command will be signed using this key if (not null and) SMB2_FLAGS_SIGNED is set.
  118. /// </param>
  119. public static byte[] GetCommandChainBytes(List<SMB2Command> commands, byte[] sessionKey)
  120. {
  121. int totalLength = 0;
  122. for (int index = 0; index < commands.Count; index++)
  123. {
  124. // Any subsequent SMB2 header MUST be 8-byte aligned
  125. int length = commands[index].Length;
  126. if (index < commands.Count - 1)
  127. {
  128. int paddedLength = (int)Math.Ceiling((double)length / 8) * 8;
  129. totalLength += paddedLength;
  130. }
  131. else
  132. {
  133. totalLength += length;
  134. }
  135. }
  136. byte[] buffer = new byte[totalLength];
  137. int offset = 0;
  138. for (int index = 0; index < commands.Count; index++)
  139. {
  140. SMB2Command command = commands[index];
  141. int commandLength = command.Length;
  142. int paddedLength;
  143. if (index < commands.Count - 1)
  144. {
  145. paddedLength = (int)Math.Ceiling((double)commandLength / 8) * 8;
  146. command.Header.NextCommand = (uint)paddedLength;
  147. }
  148. else
  149. {
  150. paddedLength = commandLength;
  151. }
  152. command.WriteBytes(buffer, offset);
  153. if (command.Header.IsSigned && sessionKey != null)
  154. {
  155. // [MS-SMB2] Any padding at the end of the message MUST be used in the hash computation.
  156. byte[] signature = new HMACSHA256(sessionKey).ComputeHash(buffer, offset, paddedLength);
  157. // [MS-SMB2] The first 16 bytes of the hash MUST be copied into the 16-byte signature field of the SMB2 Header.
  158. ByteWriter.WriteBytes(buffer, offset + SMB2Header.SignatureOffset, signature, 16);
  159. }
  160. offset += paddedLength;
  161. }
  162. return buffer;
  163. }
  164. }
  165. }