NDRWriter.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* Copyright (C) 2014 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 System.Text;
  11. using Utilities;
  12. namespace SMBLibrary.RPC
  13. {
  14. /// <summary>
  15. /// NDR - Native Data Representation
  16. /// See DCE 1.1: Remote Procedure Call, Chapter 14 - Transfer Syntax NDR
  17. /// </summary>
  18. public class NDRWriter
  19. {
  20. private MemoryStream m_stream = new MemoryStream();
  21. private int m_depth;
  22. private List<INDRStructure> m_deferredStructures = new List<INDRStructure>();
  23. private Dictionary<uint, INDRStructure> m_referentToInstance = new Dictionary<uint, INDRStructure>();
  24. private uint m_nextReferentID = 0x00020000;
  25. public void BeginStructure()
  26. {
  27. m_depth++;
  28. }
  29. /// <summary>
  30. /// Add embedded pointer deferred structure (referent) writer
  31. /// </summary>
  32. private void AddDeferredStructure(INDRStructure structure)
  33. {
  34. m_deferredStructures.Add(structure);
  35. }
  36. public void EndStructure()
  37. {
  38. m_depth--;
  39. // 14.3.12.3 - Algorithm for Deferral of Referents
  40. // Representations of (embedded) pointer referents are ordered according to a left-to-right, depth-first traversal of the embedding construction.
  41. // referent representations for the embedded construction are further deferred to a position in the octet stream that
  42. // follows the representation of the embedding construction. The set of referent representations for the embedded construction
  43. // is inserted among the referent representations for any pointers in the embedding construction, according to the order of elements or
  44. // members in the embedding construction
  45. if (m_depth == 0)
  46. {
  47. // Make a copy of all the deferred structures, additional deferred structures will be inserted to m_deferredStructures
  48. // as we process the existing list
  49. List<INDRStructure> deferredStructures = new List<INDRStructure>(m_deferredStructures);
  50. m_deferredStructures.Clear();
  51. // Write all deferred types:
  52. foreach (INDRStructure deferredStructure in deferredStructures)
  53. {
  54. deferredStructure.Write(this);
  55. }
  56. }
  57. }
  58. public void WriteUnicodeString(string value)
  59. {
  60. NDRUnicodeString unicodeString = new NDRUnicodeString(value);
  61. unicodeString.Write(this);
  62. }
  63. public void WriteStructure(INDRStructure structure)
  64. {
  65. structure.Write(this);
  66. }
  67. public void WriteTopLevelUnicodeStringPointer(string value)
  68. {
  69. if (value == null)
  70. {
  71. WriteUInt32(0);
  72. return;
  73. }
  74. // Note: We do not bother searching for existing values
  75. uint referentID = GetNextReferentID();
  76. WriteUInt32(referentID);
  77. NDRUnicodeString unicodeString = new NDRUnicodeString(value);
  78. unicodeString.Write(this);
  79. m_referentToInstance.Add(referentID, unicodeString);
  80. }
  81. // 14.3.12.1 Embedded Full Pointers
  82. public void WriteEmbeddedStructureFullPointer(INDRStructure structure)
  83. {
  84. if (structure == null)
  85. {
  86. WriteUInt32(0); // null
  87. return;
  88. }
  89. else
  90. {
  91. // Note: We do not bother searching for existing values
  92. uint referentID = GetNextReferentID();
  93. WriteUInt32(referentID);
  94. AddDeferredStructure(structure);
  95. m_referentToInstance.Add(referentID, structure);
  96. }
  97. }
  98. // 14.2.2 - Alignment of Primitive Types
  99. public void WriteUInt16(ushort value)
  100. {
  101. uint padding = (uint)(2 - (m_stream.Position % 2)) % 2;
  102. m_stream.Position += padding;
  103. LittleEndianWriter.WriteUInt16(m_stream, value);
  104. }
  105. // 14.2.2 - Alignment of Primitive Types
  106. public void WriteUInt32(uint value)
  107. {
  108. uint padding = (uint)(4 - (m_stream.Position % 4)) % 4;
  109. m_stream.Position += padding;
  110. LittleEndianWriter.WriteUInt32(m_stream, value);
  111. }
  112. public byte[] GetBytes()
  113. {
  114. byte[] buffer = new byte[m_stream.Length];
  115. m_stream.Seek(0, SeekOrigin.Begin);
  116. m_stream.Read(buffer, 0, buffer.Length);
  117. return buffer;
  118. }
  119. private uint GetNextReferentID()
  120. {
  121. uint result = m_nextReferentID;
  122. m_nextReferentID++;
  123. return result;
  124. }
  125. }
  126. }