SMB1Command.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /* Copyright (C) 2014-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.IO;
  10. using Utilities;
  11. namespace SMBLibrary.SMB1
  12. {
  13. public abstract class SMB1Command
  14. {
  15. protected byte[] SMBParameters; // SMB_Parameters
  16. protected byte[] SMBData; // SMB_Data
  17. public SMB1Command()
  18. {
  19. SMBParameters = new byte[0];
  20. SMBData = new byte[0];
  21. }
  22. public SMB1Command(byte[] buffer, int offset, bool isUnicode)
  23. {
  24. byte wordCount = ByteReader.ReadByte(buffer, ref offset);
  25. SMBParameters = ByteReader.ReadBytes(buffer, ref offset, wordCount * 2);
  26. ushort byteCount = LittleEndianReader.ReadUInt16(buffer, ref offset);
  27. SMBData = ByteReader.ReadBytes(buffer, ref offset, byteCount);
  28. }
  29. public abstract CommandName CommandName
  30. {
  31. get;
  32. }
  33. public virtual byte[] GetBytes(bool isUnicode)
  34. {
  35. if (SMBParameters.Length % 2 > 0)
  36. {
  37. throw new Exception("SMB_Parameters Length must be a multiple of 2");
  38. }
  39. int length = 1 + SMBParameters.Length + 2 + SMBData.Length;
  40. byte[] buffer = new byte[length];
  41. byte wordCount = (byte)(SMBParameters.Length / 2);
  42. if (this is NTCreateAndXResponseExtended)
  43. {
  44. // [MS-SMB] Section 2.2.4.9.2 and Note <51>:
  45. // Windows-based SMB servers send 50 (0x32) words in the extended response
  46. // although they set the WordCount field to 0x2A
  47. // wordCount SHOULD be 0x2A
  48. wordCount = 0x2A;
  49. }
  50. ushort byteCount = (ushort)SMBData.Length;
  51. int offset = 0;
  52. ByteWriter.WriteByte(buffer, ref offset, wordCount);
  53. ByteWriter.WriteBytes(buffer, ref offset, SMBParameters);
  54. LittleEndianWriter.WriteUInt16(buffer, ref offset, byteCount);
  55. ByteWriter.WriteBytes(buffer, ref offset, SMBData);
  56. return buffer;
  57. }
  58. public static SMB1Command ReadCommand(byte[] buffer, int offset, CommandName commandName, SMB1Header header)
  59. {
  60. if ((header.Flags & HeaderFlags.Reply) > 0)
  61. {
  62. return ReadCommandResponse(buffer, offset, commandName, header.UnicodeFlag);
  63. }
  64. else
  65. {
  66. return ReadCommandRequest(buffer, offset, commandName, header.UnicodeFlag);
  67. }
  68. }
  69. public static SMB1Command ReadCommandRequest(byte[] buffer, int offset, CommandName commandName, bool isUnicode)
  70. {
  71. switch (commandName)
  72. {
  73. case CommandName.SMB_COM_CREATE_DIRECTORY:
  74. return new CreateDirectoryRequest(buffer, offset, isUnicode);
  75. case CommandName.SMB_COM_DELETE_DIRECTORY:
  76. return new DeleteDirectoryRequest(buffer, offset, isUnicode);
  77. case CommandName.SMB_COM_CLOSE:
  78. return new CloseRequest(buffer, offset);
  79. case CommandName.SMB_COM_FLUSH:
  80. return new FlushRequest(buffer, offset);
  81. case CommandName.SMB_COM_DELETE:
  82. return new DeleteRequest(buffer, offset, isUnicode);
  83. case CommandName.SMB_COM_RENAME:
  84. return new RenameRequest(buffer, offset, isUnicode);
  85. case CommandName.SMB_COM_QUERY_INFORMATION:
  86. return new QueryInformationRequest(buffer, offset, isUnicode);
  87. case CommandName.SMB_COM_SET_INFORMATION:
  88. return new SetInformationRequest(buffer, offset, isUnicode);
  89. case CommandName.SMB_COM_READ:
  90. return new ReadRequest(buffer, offset);
  91. case CommandName.SMB_COM_WRITE:
  92. return new WriteRequest(buffer, offset);
  93. case CommandName.SMB_COM_CHECK_DIRECTORY:
  94. return new CheckDirectoryRequest(buffer, offset, isUnicode);
  95. case CommandName.SMB_COM_WRITE_RAW:
  96. return new WriteRawRequest(buffer, offset);
  97. case CommandName.SMB_COM_SET_INFORMATION2:
  98. return new SetInformation2Request(buffer, offset);
  99. case CommandName.SMB_COM_LOCKING_ANDX:
  100. return new LockingAndXRequest(buffer, offset);
  101. case CommandName.SMB_COM_TRANSACTION:
  102. return new TransactionRequest(buffer, offset, isUnicode);
  103. case CommandName.SMB_COM_TRANSACTION_SECONDARY:
  104. return new TransactionSecondaryRequest(buffer, offset);
  105. case CommandName.SMB_COM_ECHO:
  106. return new EchoRequest(buffer, offset);
  107. case CommandName.SMB_COM_OPEN_ANDX:
  108. return new OpenAndXRequest(buffer, offset, isUnicode);
  109. case CommandName.SMB_COM_READ_ANDX:
  110. return new ReadAndXRequest(buffer, offset);
  111. case CommandName.SMB_COM_WRITE_ANDX:
  112. return new WriteAndXRequest(buffer, offset, isUnicode);
  113. case CommandName.SMB_COM_TRANSACTION2:
  114. return new Transaction2Request(buffer, offset, isUnicode);
  115. case CommandName.SMB_COM_TRANSACTION2_SECONDARY:
  116. return new Transaction2SecondaryRequest(buffer, offset);
  117. case CommandName.SMB_COM_FIND_CLOSE2:
  118. return new FindClose2Request(buffer, offset);
  119. case CommandName.SMB_COM_TREE_DISCONNECT:
  120. return new TreeDisconnectRequest(buffer, offset);
  121. case CommandName.SMB_COM_NEGOTIATE:
  122. return new NegotiateRequest(buffer, offset);
  123. case CommandName.SMB_COM_SESSION_SETUP_ANDX:
  124. {
  125. byte wordCount = ByteReader.ReadByte(buffer, offset);
  126. if (wordCount * 2 == SessionSetupAndXRequest.ParametersLength)
  127. {
  128. return new SessionSetupAndXRequest(buffer, offset, isUnicode);
  129. }
  130. else if (wordCount * 2 == SessionSetupAndXRequestExtended.ParametersLength)
  131. {
  132. return new SessionSetupAndXRequestExtended(buffer, offset, isUnicode);
  133. }
  134. else
  135. {
  136. throw new InvalidDataException();
  137. }
  138. }
  139. case CommandName.SMB_COM_LOGOFF_ANDX:
  140. return new LogoffAndXRequest(buffer, offset);
  141. case CommandName.SMB_COM_TREE_CONNECT_ANDX:
  142. return new TreeConnectAndXRequest(buffer, offset, isUnicode);
  143. case CommandName.SMB_COM_NT_TRANSACT:
  144. return new NTTransactRequest(buffer, offset);
  145. case CommandName.SMB_COM_NT_TRANSACT_SECONDARY:
  146. return new NTTransactSecondaryRequest(buffer, offset);
  147. case CommandName.SMB_COM_NT_CREATE_ANDX:
  148. return new NTCreateAndXRequest(buffer, offset, isUnicode);
  149. case CommandName.SMB_COM_NT_CANCEL:
  150. return new NTCancelRequest(buffer, offset);
  151. default:
  152. throw new NotImplementedException("SMB Command 0x" + commandName.ToString("X"));
  153. }
  154. }
  155. public static SMB1Command ReadCommandResponse(byte[] buffer, int offset, CommandName commandName, bool isUnicode)
  156. {
  157. byte wordCount = ByteReader.ReadByte(buffer, offset);
  158. switch (commandName)
  159. {
  160. case CommandName.SMB_COM_CREATE_DIRECTORY:
  161. return new CreateDirectoryResponse(buffer, offset);
  162. case CommandName.SMB_COM_DELETE_DIRECTORY:
  163. return new DeleteDirectoryResponse(buffer, offset);
  164. case CommandName.SMB_COM_CLOSE:
  165. return new CloseResponse(buffer, offset);
  166. case CommandName.SMB_COM_FLUSH:
  167. return new FlushResponse(buffer, offset);
  168. case CommandName.SMB_COM_DELETE:
  169. return new DeleteResponse(buffer, offset);
  170. case CommandName.SMB_COM_RENAME:
  171. return new RenameResponse(buffer, offset);
  172. case CommandName.SMB_COM_QUERY_INFORMATION:
  173. {
  174. if (wordCount * 2 == QueryInformationResponse.ParameterLength)
  175. {
  176. return new QueryInformationResponse(buffer, offset);
  177. }
  178. else if (wordCount == 0)
  179. {
  180. return new ErrorResponse(commandName);
  181. }
  182. else
  183. {
  184. throw new InvalidDataException();
  185. }
  186. }
  187. case CommandName.SMB_COM_SET_INFORMATION:
  188. return new SetInformationResponse(buffer, offset);
  189. case CommandName.SMB_COM_READ:
  190. {
  191. if (wordCount * 2 == ReadResponse.ParametersLength)
  192. {
  193. return new ReadResponse(buffer, offset);
  194. }
  195. else if (wordCount == 0)
  196. {
  197. return new ErrorResponse(commandName);
  198. }
  199. else
  200. {
  201. throw new InvalidDataException();
  202. }
  203. }
  204. case CommandName.SMB_COM_WRITE:
  205. {
  206. if (wordCount * 2 == WriteResponse.ParametersLength)
  207. {
  208. return new WriteResponse(buffer, offset);
  209. }
  210. else if (wordCount == 0)
  211. {
  212. return new ErrorResponse(commandName);
  213. }
  214. else
  215. {
  216. throw new InvalidDataException();
  217. }
  218. }
  219. case CommandName.SMB_COM_CHECK_DIRECTORY:
  220. return new CheckDirectoryResponse(buffer, offset);
  221. case CommandName.SMB_COM_WRITE_RAW:
  222. {
  223. if (wordCount * 2 == WriteRawInterimResponse.ParametersLength)
  224. {
  225. return new WriteRawInterimResponse(buffer, offset);
  226. }
  227. else if (wordCount == 0)
  228. {
  229. return new ErrorResponse(commandName);
  230. }
  231. else
  232. {
  233. throw new InvalidDataException();
  234. }
  235. }
  236. case CommandName.SMB_COM_WRITE_COMPLETE:
  237. {
  238. if (wordCount * 2 == WriteRawFinalResponse.ParametersLength)
  239. {
  240. return new WriteRawFinalResponse(buffer, offset);
  241. }
  242. else if (wordCount == 0)
  243. {
  244. return new ErrorResponse(commandName);
  245. }
  246. else
  247. {
  248. throw new InvalidDataException();
  249. }
  250. }
  251. case CommandName.SMB_COM_SET_INFORMATION2:
  252. return new SetInformation2Response(buffer, offset);
  253. case CommandName.SMB_COM_LOCKING_ANDX:
  254. {
  255. if (wordCount * 2 == LockingAndXResponse.ParametersLength)
  256. {
  257. return new LockingAndXResponse(buffer, offset);
  258. }
  259. else if (wordCount == 0)
  260. {
  261. return new ErrorResponse(commandName);
  262. }
  263. else
  264. {
  265. throw new InvalidDataException();
  266. }
  267. }
  268. case CommandName.SMB_COM_TRANSACTION:
  269. {
  270. if (wordCount * 2 == TransactionInterimResponse.ParametersLength)
  271. {
  272. return new TransactionInterimResponse(buffer, offset);
  273. }
  274. else
  275. {
  276. return new TransactionResponse(buffer, offset);
  277. }
  278. }
  279. case CommandName.SMB_COM_ECHO:
  280. {
  281. if (wordCount * 2 == EchoResponse.ParametersLength)
  282. {
  283. return new EchoResponse(buffer, offset);
  284. }
  285. else if (wordCount == 0)
  286. {
  287. return new ErrorResponse(commandName);
  288. }
  289. else
  290. {
  291. throw new InvalidDataException();
  292. }
  293. }
  294. case CommandName.SMB_COM_OPEN_ANDX:
  295. {
  296. if (wordCount * 2 == OpenAndXResponse.ParametersLength)
  297. {
  298. throw new NotImplementedException();
  299. }
  300. else if (wordCount * 2 == OpenAndXResponseExtended.ParametersLength)
  301. {
  302. throw new NotImplementedException();
  303. }
  304. else if (wordCount == 0)
  305. {
  306. return new ErrorResponse(commandName);
  307. }
  308. else
  309. {
  310. throw new InvalidDataException();
  311. }
  312. }
  313. case CommandName.SMB_COM_READ_ANDX:
  314. {
  315. if (wordCount * 2 == ReadAndXResponse.ParametersLength)
  316. {
  317. return new ReadAndXResponse(buffer, offset, isUnicode);
  318. }
  319. else if (wordCount == 0)
  320. {
  321. return new ErrorResponse(commandName);
  322. }
  323. else
  324. {
  325. throw new InvalidDataException();
  326. }
  327. }
  328. case CommandName.SMB_COM_WRITE_ANDX:
  329. {
  330. if (wordCount * 2 == WriteAndXResponse.ParametersLength)
  331. {
  332. return new WriteAndXResponse(buffer, offset);
  333. }
  334. else if (wordCount == 0)
  335. {
  336. return new ErrorResponse(commandName);
  337. }
  338. else
  339. {
  340. throw new InvalidDataException();
  341. }
  342. }
  343. case CommandName.SMB_COM_TRANSACTION2:
  344. {
  345. if (wordCount * 2 == Transaction2InterimResponse.ParametersLength)
  346. {
  347. return new Transaction2InterimResponse(buffer, offset);
  348. }
  349. else
  350. {
  351. return new Transaction2Response(buffer, offset);
  352. }
  353. }
  354. case CommandName.SMB_COM_FIND_CLOSE2:
  355. return new FindClose2Response(buffer, offset);
  356. case CommandName.SMB_COM_TREE_DISCONNECT:
  357. return new TreeDisconnectResponse(buffer, offset);
  358. case CommandName.SMB_COM_NEGOTIATE:
  359. {
  360. // Both NegotiateResponse and NegotiateResponseExtended have WordCount set to 17
  361. if (wordCount * 2 == NegotiateResponse.ParametersLength)
  362. {
  363. Capabilities capabilities = (Capabilities)LittleEndianConverter.ToUInt32(buffer, offset + 20);
  364. if ((capabilities & Capabilities.ExtendedSecurity) > 0)
  365. {
  366. return new NegotiateResponseExtended(buffer, offset);
  367. }
  368. else
  369. {
  370. return new NegotiateResponse(buffer, offset, isUnicode);
  371. }
  372. }
  373. if (wordCount == 0)
  374. {
  375. return new ErrorResponse(commandName);
  376. }
  377. else
  378. {
  379. throw new InvalidDataException();
  380. }
  381. }
  382. case CommandName.SMB_COM_SESSION_SETUP_ANDX:
  383. {
  384. if (wordCount * 2 == SessionSetupAndXResponse.ParametersLength)
  385. {
  386. return new SessionSetupAndXResponse(buffer, offset, isUnicode);
  387. }
  388. else if (wordCount * 2 == SessionSetupAndXResponseExtended.ParametersLength)
  389. {
  390. return new SessionSetupAndXResponseExtended(buffer, offset, isUnicode);
  391. }
  392. else if (wordCount == 0)
  393. {
  394. return new ErrorResponse(commandName);
  395. }
  396. else
  397. {
  398. throw new InvalidDataException();
  399. }
  400. }
  401. case CommandName.SMB_COM_LOGOFF_ANDX:
  402. {
  403. if (wordCount * 2 == LogoffAndXResponse.ParametersLength)
  404. {
  405. return new LogoffAndXResponse(buffer, offset);
  406. }
  407. else if (wordCount == 0)
  408. {
  409. return new ErrorResponse(commandName);
  410. }
  411. else
  412. {
  413. throw new InvalidDataException();
  414. }
  415. }
  416. case CommandName.SMB_COM_TREE_CONNECT_ANDX:
  417. {
  418. if (wordCount * 2 == TreeConnectAndXResponse.ParametersLength)
  419. {
  420. return new TreeConnectAndXResponse(buffer, offset, isUnicode);
  421. }
  422. else if (wordCount == 0)
  423. {
  424. return new ErrorResponse(commandName);
  425. }
  426. else
  427. {
  428. throw new InvalidDataException();
  429. }
  430. }
  431. case CommandName.SMB_COM_NT_TRANSACT:
  432. {
  433. if (wordCount * 2 == NTTransactInterimResponse.ParametersLength)
  434. {
  435. return new NTTransactInterimResponse(buffer, offset);
  436. }
  437. else
  438. {
  439. return new NTTransactResponse(buffer, offset);
  440. }
  441. }
  442. case CommandName.SMB_COM_NT_CREATE_ANDX:
  443. {
  444. if (wordCount * 2 == NTCreateAndXResponse.ParametersLength)
  445. {
  446. return new NTCreateAndXResponse(buffer, offset);
  447. }
  448. else if (wordCount == 0)
  449. {
  450. return new ErrorResponse(commandName);
  451. }
  452. else
  453. {
  454. throw new InvalidDataException();
  455. }
  456. }
  457. default:
  458. throw new NotImplementedException("SMB Command 0x" + commandName.ToString("X"));
  459. }
  460. }
  461. public static implicit operator List<SMB1Command>(SMB1Command command)
  462. {
  463. List<SMB1Command> result = new List<SMB1Command>();
  464. result.Add(command);
  465. return result;
  466. }
  467. }
  468. }