/// <summary>
        /// The method creates a request without ROPs.
        /// </summary>
        /// <returns>The ROPs request.</returns>
        public byte[] BuildRequestBufferWithoutRop()
        {
            // Only RopSize field (2 bytes) exists in the payload of request without ROPs.
            int payloadLen = 2;
            ushort ropSize = 2;
            int rpcHeaderExtlength = Marshal.SizeOf(typeof(RPC_HEADER_EXT));

            byte[] requestBuffer = new byte[rpcHeaderExtlength + payloadLen];
            int index = 0;

            // Constructs RPC header ext buffer
            RPC_HEADER_EXT rpcHeaderExt = new RPC_HEADER_EXT
            {
                // According to Open Specification, Version filed MUST be set to 0x0000.
                Version = 0,
                Flags = (byte)RpcHeaderExtFlags.Last,
                Size = (ushort)payloadLen,
                SizeActual = (ushort)payloadLen
            };

            // No compression and No obfuscation
            IntPtr ptr = Marshal.AllocHGlobal(rpcHeaderExtlength);

            // Release ptr in final sub-statement to make sure the resources will be released even if an exception occurs
            try
            {
                Marshal.StructureToPtr(rpcHeaderExt, ptr, true);
                Marshal.Copy(ptr, requestBuffer, index, rpcHeaderExtlength);
                index += rpcHeaderExtlength;
            }
            catch (ArgumentException e)
            {
                // Marshal.StructureToPtr or Marshal.Copy throw exception.
                throw new NotImplementedException(e.Message);
            }
            finally
            {
                Marshal.FreeHGlobal(ptr);
            }

            Array.Copy(BitConverter.GetBytes(ropSize), 0, requestBuffer, index, sizeof(ushort));

            return requestBuffer;
        }
        /// <summary>
        /// Create ROPs request buffer.
        /// </summary>
        /// <param name="requestROPs">ROPs in request.</param>
        /// <param name="requestSOHTable">Server object handles table.</param>
        /// <returns>The ROPs request buffer.</returns>
        private byte[] BuildRequestBuffer(List<ISerializable> requestROPs, List<uint> requestSOHTable)
        {
            // Definition for PayloadLen which indicates the length of the field that represents the length of payload.
            int payloadLen = 0x2;
            if (requestROPs != null)
            {
                foreach (ISerializable requestROP in requestROPs)
                {
                    payloadLen += requestROP.Size();
                }
            }

            ushort ropSize = (ushort)payloadLen;

            if (requestSOHTable != null)
            {
                payloadLen += requestSOHTable.Count * sizeof(uint);
            }

            byte[] requestBuffer = new byte[RPCHEADEREXTLEN + payloadLen];
            int index = 0;

            // Construct RPC header ext buffer
            RPC_HEADER_EXT rpcHeaderExt = new RPC_HEADER_EXT
            {
                // There is only one version of the header at this time so this value MUST be set to 0x00.
                Version = 0x00,

                // Last (0x04) indicates that no other RPC_HEADER_EXT follows the data of the current RPC_HEADER_EXT. 
                Flags = (ushort)RpcHeaderExtFlags.Last,
                Size = (ushort)payloadLen
            };

            rpcHeaderExt.SizeActual = rpcHeaderExt.Size;

            IntPtr ptr = Marshal.AllocHGlobal(RPCHEADEREXTLEN);
            try
            {
                Marshal.StructureToPtr(rpcHeaderExt, ptr, true);
                Marshal.Copy(ptr, requestBuffer, index, RPCHEADEREXTLEN);
                index += RPCHEADEREXTLEN;
            }
            finally
            {
                Marshal.FreeHGlobal(ptr);
            }

            // RopSize's type is ushort. So the offset will be 2.
            Array.Copy(BitConverter.GetBytes(ropSize), 0, requestBuffer, index, 2);
            index += 2;

            if (requestROPs != null)
            {
                foreach (ISerializable requestROP in requestROPs)
                {
                    Array.Copy(requestROP.Serialize(), 0, requestBuffer, index, requestROP.Size());
                    index += requestROP.Size();
                }
            }

            if (requestSOHTable != null)
            {
                foreach (uint serverHandle in requestSOHTable)
                {
                    Array.Copy(BitConverter.GetBytes(serverHandle), 0, requestBuffer, index, sizeof(uint));
                    index += sizeof(uint);
                }
            }

            // Compress and obfuscate request buffer as configured.
            requestBuffer = Common.CompressAndObfuscateRequest(requestBuffer, this.site);

            return requestBuffer;
        }
        /// <summary>
        /// The method parses response buffer.
        /// </summary>
        /// <param name="rgbOut">The ROP response payload.</param>
        /// <param name="rpcHeaderExts">RPC header ext.</param>
        /// <param name="rops">ROPs in response.</param>
        /// <param name="serverHandleObjectsTables">Server handle objects tables</param>
        private void ParseResponseBuffer(byte[] rgbOut, out RPC_HEADER_EXT[] rpcHeaderExts, out byte[][] rops, out uint[][] serverHandleObjectsTables)
        {
            List<RPC_HEADER_EXT> rpcHeaderExtList = new List<RPC_HEADER_EXT>();
            List<byte[]> ropList = new List<byte[]>();
            List<uint[]> serverHandleObjectList = new List<uint[]>();
            IntPtr ptr = IntPtr.Zero;

            int index = 0;
            bool end = false;
            do
            {
                // Parse rpc header ext
                RPC_HEADER_EXT rpcHeaderExt;
                ptr = Marshal.AllocHGlobal(RPCHEADEREXTLEN);
                try
                {
                    Marshal.Copy(rgbOut, index, ptr, RPCHEADEREXTLEN);
                    rpcHeaderExt = (RPC_HEADER_EXT)Marshal.PtrToStructure(ptr, typeof(RPC_HEADER_EXT));
                    rpcHeaderExtList.Add(rpcHeaderExt);
                    index += RPCHEADEREXTLEN;
                    end = (rpcHeaderExt.Flags & (ushort)RpcHeaderExtFlags.Last) == (ushort)RpcHeaderExtFlags.Last;
                }
                finally
                {
                    Marshal.FreeHGlobal(ptr);
                }

                #region  start parse payload

                // Parse ropSize
                ushort ropSize = BitConverter.ToUInt16(rgbOut, index);
                index += sizeof(ushort);

                if ((ropSize - sizeof(ushort)) > 0)
                {
                    // Parse rop
                    byte[] rop = new byte[ropSize - sizeof(ushort)];
                    Array.Copy(rgbOut, index, rop, 0, ropSize - sizeof(ushort));
                    ropList.Add(rop);
                    index += ropSize - sizeof(ushort);
                }

                // Parse server handle objects table
                this.site.Assert.IsTrue((rpcHeaderExt.Size - ropSize) % sizeof(uint) == 0, "Server object handle should be uint32 array");

                int count = (rpcHeaderExt.Size - ropSize) / sizeof(uint);
                if (count > 0)
                {
                    uint[] sohs = new uint[count];
                    for (int k = 0; k < count; k++)
                    {
                        sohs[k] = BitConverter.ToUInt32(rgbOut, index);
                        index += sizeof(uint);
                    }

                    serverHandleObjectList.Add(sohs);
                }
                #endregion
            }
            while (!end);

            rpcHeaderExts = rpcHeaderExtList.ToArray();
            rops = ropList.ToArray();
            serverHandleObjectsTables = serverHandleObjectList.ToArray();
        }
        /// <summary>
        /// Parses a response with multiple ROPs. In this scenario, the response is designed as only containing two ROPs: RopSetColumn and RopQueryRows.
        /// </summary>
        /// <param name="rgbOutput">The raw data that contains the ROP response payload</param>
        /// <returns>The ROP response list which contains RopSetColumnResponse and RopQueryRawResponse</returns>
        private List<IDeserializable> ParseMultipleRopsResponse(byte[] rgbOutput)
        {
            int parseByteLength = 0;
            List<IDeserializable> multipleRopsResponse = new List<IDeserializable>();
            RPC_HEADER_EXT rpcHeader = new RPC_HEADER_EXT
            {
                Version = BitConverter.ToUInt16(rgbOutput, parseByteLength)
            };

            // Parse RPC_HEADER_EXT structure
            parseByteLength += sizeof(short);
            rpcHeader.Flags = BitConverter.ToUInt16(rgbOutput, parseByteLength);
            parseByteLength += sizeof(short);
            rpcHeader.Size = BitConverter.ToUInt16(rgbOutput, parseByteLength);
            parseByteLength += sizeof(short);
            rpcHeader.SizeActual = BitConverter.ToUInt16(rgbOutput, parseByteLength);
            parseByteLength += sizeof(short);

            // Passed 2 bytes which is size of ROP response.
            parseByteLength += sizeof(short);

            // Parse RopSetColumns response
            RopSetColumnsResponse setColumnsResponse = new RopSetColumnsResponse();
            parseByteLength += setColumnsResponse.Deserialize(rgbOutput, parseByteLength);

            // Parse RopQueryRows response
            RopQueryRowsResponse queryRowsResponse = new RopQueryRowsResponse();
            parseByteLength += queryRowsResponse.Deserialize(rgbOutput, parseByteLength);

            multipleRopsResponse.Add(setColumnsResponse);
            multipleRopsResponse.Add(queryRowsResponse);

            return multipleRopsResponse;
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Create ROPs request buffer.
        /// </summary>
        /// <param name="requestROPs">ROPs in request.</param>
        /// <param name="requestSOHTable">Server object handles table.</param>
        /// <returns>The ROPs request buffer.</returns>
        private byte[] BuildRequestBuffer(List <ISerializable> requestROPs, List <uint> requestSOHTable)
        {
            // Definition for PayloadLen which indicates the length of the field that represents the length of payload.
            int payloadLen = 0x2;

            if (requestROPs != null)
            {
                foreach (ISerializable requestROP in requestROPs)
                {
                    payloadLen += requestROP.Size();
                }
            }

            ushort ropSize = (ushort)payloadLen;

            if (requestSOHTable != null)
            {
                payloadLen += requestSOHTable.Count * sizeof(uint);
            }

            byte[] requestBuffer = new byte[RPCHEADEREXTLEN + payloadLen];
            int    index         = 0;

            // Construct RPC header ext buffer
            RPC_HEADER_EXT rpcHeaderExt = new RPC_HEADER_EXT
            {
                // There is only one version of the header at this time so this value MUST be set to 0x00.
                Version = 0x00,

                // Last (0x04) indicates that no other RPC_HEADER_EXT follows the data of the current RPC_HEADER_EXT.
                Flags = (ushort)RpcHeaderExtFlags.Last,
                Size  = (ushort)payloadLen
            };

            rpcHeaderExt.SizeActual = rpcHeaderExt.Size;

            IntPtr ptr = Marshal.AllocHGlobal(RPCHEADEREXTLEN);

            try
            {
                Marshal.StructureToPtr(rpcHeaderExt, ptr, true);
                Marshal.Copy(ptr, requestBuffer, index, RPCHEADEREXTLEN);
                index += RPCHEADEREXTLEN;
            }
            finally
            {
                Marshal.FreeHGlobal(ptr);
            }

            // RopSize's type is ushort. So the offset will be 2.
            Array.Copy(BitConverter.GetBytes(ropSize), 0, requestBuffer, index, 2);
            index += 2;

            if (requestROPs != null)
            {
                foreach (ISerializable requestROP in requestROPs)
                {
                    Array.Copy(requestROP.Serialize(), 0, requestBuffer, index, requestROP.Size());
                    index += requestROP.Size();
                }
            }

            if (requestSOHTable != null)
            {
                foreach (uint serverHandle in requestSOHTable)
                {
                    Array.Copy(BitConverter.GetBytes(serverHandle), 0, requestBuffer, index, sizeof(uint));
                    index += sizeof(uint);
                }
            }

            // Compress and obfuscate request buffer as configured.
            requestBuffer = Common.CompressAndObfuscateRequest(requestBuffer, this.site);

            return(requestBuffer);
        }
        /// <summary>
        /// The method creates ROPs request.
        /// </summary>
        /// <param name="requestROPs">ROPs in request.</param>
        /// <param name="requestSOHTable">Server object handles table.</param>
        /// <returns>The ROPs request.</returns>
        private byte[] BuildRequestBuffer(List<ISerializable> requestROPs, List<uint> requestSOHTable)
        {
            // Definition for PayloadLen which indicates the length of the field that represents the length of payload.
            int payloadLen = PayloadLen;
            if (requestROPs != null)
            {
                foreach (ISerializable requestROP in requestROPs)
                {
                    payloadLen += requestROP.Size();
                }
            }

            Site.Assert.IsTrue(
                payloadLen < ushort.MaxValue,
                "The number of bytes in this field MUST be 2 bytes less than the value specified in the RopSize field.");

            ushort ropSize = (ushort)payloadLen;

            if (requestSOHTable != null)
            {
                payloadLen += requestSOHTable.Count * sizeof(uint);
            }

            byte[] requestBuffer = new byte[RPCHEADEREXTLEN + payloadLen];
            int index = 0;

            // Construct RPC header extension buffer
            RPC_HEADER_EXT rpcHeaderExt = new RPC_HEADER_EXT
            {
                Version = VersionOfRpcHeaderExt, // There is only one version of the header at this time so this value MUST be set to 0x00.
                Flags = LastForFlagsOfHeader, // Last (0x04) indicates that no other RPC_HEADER_EXT follows the data of the current RPC_HEADER_EXT. 
                Size = (ushort)payloadLen
            };
            rpcHeaderExt.SizeActual = rpcHeaderExt.Size;

            IntPtr ptr = Marshal.AllocHGlobal(RPCHEADEREXTLEN);
            try
            {
                Marshal.StructureToPtr(rpcHeaderExt, ptr, true);
                Marshal.Copy(ptr, requestBuffer, index, RPCHEADEREXTLEN);
                index += RPCHEADEREXTLEN;
            }
            finally
            {
                Marshal.FreeHGlobal(ptr);
            }

            // RopSize's type is ushort. So the offset will be 2.
            Array.Copy(BitConverter.GetBytes(ropSize), 0, requestBuffer, index, 2);
            index += 2;

            if (requestROPs != null)
            {
                foreach (ISerializable requestROP in requestROPs)
                {
                    Array.Copy(requestROP.Serialize(), 0, requestBuffer, index, requestROP.Size());
                    index += requestROP.Size();
                }
            }

            if (requestSOHTable != null)
            {
                foreach (uint serverHandle in requestSOHTable)
                {
                    Array.Copy(BitConverter.GetBytes(serverHandle), 0, requestBuffer, index, sizeof(uint));
                    index += sizeof(uint);
                }
            }

            return requestBuffer;
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Composes rgbAuxIn buffer
        /// </summary>
        /// <param name="rgbAuxIn">Enum value of rgbAuxIn</param>
        /// <param name="rgbAuxInPayload">The payload of rgbAuxIn buffer.</param>
        /// <returns>Returns a buffer composed according to the parameters</returns>
        public static byte[] ComposeRgbAuxIn(RgbAuxInEnum rgbAuxIn, byte[] rgbAuxInPayload)
        {
            byte version;
            byte type;
            const string ErrorMessage = "This input structure name is not a valid AUX structure type";

            // Version set to 0x01 means the Version field of AUX_HEADER is AUX_VERSION_1
            // Version set to 0x02 means the Version field of AUX_HEADER is AUX_VERSION_2
            switch (rgbAuxIn)
            {
                case RgbAuxInEnum.AUX_PERF_SESSIONINFO:
                     version = (byte)AuxVersions.AUX_VERSION_1;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_SESSIONINFO;
                    break;
                case RgbAuxInEnum.AUX_PERF_SESSIONINFO_V2:
                    version = (byte)AuxVersions.AUX_VERSION_2;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_SESSIONINFO;
                    break;
                case RgbAuxInEnum.AUX_PERF_CLIENTINFO:
                    version = (byte)AuxVersions.AUX_VERSION_1;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_CLIENTINFO;
                    break;
                case RgbAuxInEnum.AUX_PERF_PROCESSINFO:
                    version = (byte)AuxVersions.AUX_VERSION_2;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_PROCESSINFO;
                    break;
                case RgbAuxInEnum.AUX_PERF_DEFMDB_SUCCESS:
                    version = (byte)AuxVersions.AUX_VERSION_1;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_BG_DEFMDB_SUCCESS;
                    break;
                case RgbAuxInEnum.AUX_PERF_DEFGC_SUCCESS:
                    version = (byte)AuxVersions.AUX_VERSION_1;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_BG_DEFGC_SUCCESS;
                    break;
                case RgbAuxInEnum.AUX_PERF_MDB_SUCCESS_V2:
                    version = (byte)AuxVersions.AUX_VERSION_2;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_MDB_SUCCESS;
                    break;
                case RgbAuxInEnum.AUX_PERF_GC_SUCCESS:
                    version = (byte)AuxVersions.AUX_VERSION_1;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_BG_GC_SUCCESS;
                    break;
                case RgbAuxInEnum.AUX_PERF_GC_SUCCESS_V2:
                    version = (byte)AuxVersions.AUX_VERSION_2;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_BG_GC_SUCCESS;
                    break;
                case RgbAuxInEnum.AUX_PERF_FAILURE:
                    version = (byte)AuxVersions.AUX_VERSION_1;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_BG_FAILURE;
                    break;
                case RgbAuxInEnum.AUX_PERF_FAILURE_V2:
                     version = (byte)AuxVersions.AUX_VERSION_2;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_BG_FAILURE;
                    break;
                case RgbAuxInEnum.AUX_PERF_ACCOUNTINFO:
                    version = (byte)AuxVersions.AUX_VERSION_1;
                    type = (byte)AuxTypes.AUX_TYPE_PERF_ACCOUNTINFO;
                    break;
                case RgbAuxInEnum.AUX_CLIENT_CONNECTION_INFO:
                    version = (byte)AuxVersions.AUX_VERSION_1;
                    type = (byte)AuxTypes.AUX_CLIENT_CONNECTION_INFO;
                    break;
                default:
                    throw new NotImplementedException(ErrorMessage);
            }

            RPC_HEADER_EXT rpcHeaderExt = new RPC_HEADER_EXT
            {
                Version = 0x0000, // This value MUST be set to 0x0000.
                Flags = (ushort)RpcHeaderExtFlags.Last, // No Compression and no obfuscation
                Size = (ushort)(rgbAuxInPayload.Length + ConstValues.AuxHeaderByteSize) // The total length of the payload data that follows the RPC_HEADER_EXT structure. 
            };

            // The length of the payload data after it has been uncompressed.
            rpcHeaderExt.SizeActual = rpcHeaderExt.Size;

            // The length of AuxHeader is the length of AUX_HEADER structure plus the length of any additional payload data.
            AUX_HEADER auxHeader = new AUX_HEADER
            {
                Size = (ushort)(rgbAuxInPayload.Length + ConstValues.AuxHeaderByteSize),
                Version = version,
                Type = type
            };
            int returnSize = rgbAuxInPayload.Length + Marshal.SizeOf(rpcHeaderExt) + Marshal.SizeOf(auxHeader);
            byte[] returnByte = new byte[returnSize];

            // RgbAuxIn serialization 
            // Serializes the RPC_HEADER_EXT
            int index = 0;
            Array.Copy(BitConverter.GetBytes(rpcHeaderExt.Version), 0, returnByte, index, sizeof(short));
            index += sizeof(short);
            Array.Copy(BitConverter.GetBytes(rpcHeaderExt.Flags), 0, returnByte, index, sizeof(short));
            index += sizeof(short);
            Array.Copy(BitConverter.GetBytes(rpcHeaderExt.Size), 0, returnByte, index, sizeof(short));
            index += sizeof(short);
            Array.Copy(BitConverter.GetBytes(rpcHeaderExt.SizeActual), 0, returnByte, index, sizeof(short));
            index += sizeof(short);

            // Serializes the AUX_HEADER
            Array.Copy(BitConverter.GetBytes(auxHeader.Size), 0, returnByte, index, sizeof(ushort));
            index += sizeof(ushort);
            returnByte[index] = auxHeader.Version;
            index++;
            returnByte[index] = auxHeader.Type;
            index++;

            Array.Copy(rgbAuxInPayload, 0, returnByte, index, rgbAuxInPayload.Length);

            return returnByte;
        }
        /// <summary>
        /// Verify the RPC header structure.
        /// </summary>
        /// <param name="flagValues">All flag values before decompressing.</param>
        /// <param name="header">The structure to store information which is used to determine how to interpret the data following the header.</param>
        /// <param name="isExOrExt2">A Boolean value, true means use method EcDoConnectEx, false means use method EcDoRpcExt2</param>
        /// <param name="isAuxOutOrOut">A Boolean value, true means field is rgbAuxOut, false means field is rgbOut</param>
        /// <param name="isLast">A Boolean value, true means the last header, otherwise is false</param>
        private void VerifyRPCHeaderExt(
            List<short> flagValues,
            RPC_HEADER_EXT header,
            bool isExOrExt2,
            bool isAuxOutOrOut,
            bool isLast)
        {
            #region Verify whether rgbAuxOut includes an RPC_HEADER_EXT

            // Use method EcDoConnectEx, output buffer is rgbAuxOut
            if (isExOrExt2 && isAuxOutOrOut)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R575");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R575
                // According to the Open Specification, RPC_HEADER_EXT can be determined by the version field. The version of the header MUST be set to 0x0000
                Site.CaptureRequirementIfAreEqual<ushort>(
                    0x0000,
                    header.Version,
                    575,
                    @"[In EcDoConnectEx Method (Opnum 10)] [rgbAuxOut] The server MUST include an RPC_HEADER_EXT structure before the auxiliary payload data.");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R747");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R747
                // According to the Open Specification, RPC_HEADER_EXT can be determined by the version field.
                // The version of the header MUST be set to 0x0000
                Site.CaptureRequirementIfAreEqual<ushort>(
                    0x0000,
                    header.Version,
                    747,
                    @"[In rgbAuxOut Output Buffer] The rgbAuxOut parameter output buffer contains an RPC_HEADER_EXT structure, as specified in section 2.2.2.1, followed by payload data.");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R748");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R748
                // According to the Open Specification, Flag field is from third byte in RPC_HEADER_EXT. Last flag value is 0x0004
                Site.CaptureRequirementIfAreEqual<int>(
                    0x0004,
                    header.Flags & 0x0004,
                    748,
                    @"[In rgbAuxOut Output Buffer] The RPC_HEADER_EXT structure MUST contain the Last flag in the Flags field.");
            }

            // Use method EcDoRpcExt2, output buffer is rgbAuxOut
            if ((!isExOrExt2) && isAuxOutOrOut)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R1649");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R1649
                // Version field of RPC_HEADER_EXT is 0x0000 indicates that the output buffer rgbAuxOut has an RPC_HEADER_EXT structure which is the same as that of the rgbAuxOut input buffer in the EcDoConnectEx method.
                Site.CaptureRequirementIfAreEqual<ushort>(
                    0x0000,
                    header.Version,
                    1649,
                    @"[In rgbAuxOut Output Buffer] The format of the rgbAuxOut parameter input buffer for the EcDoRpcExt2 method, as specified in section 3.1.4.2, is the same as that of the rgbAuxOut parameter input buffer for the EcDoConnectEx method, as specified in section 3.1.4.1.1.1.2.");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R682");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R682
                // According to the Open Specification, RPC_HEADER_EXT can be determined by the version field.
                // The version of the header MUST be set to 0x0000
                Site.CaptureRequirementIfAreEqual<ushort>(
                    0x0000,
                    header.Version,
                    682,
                    @"[In EcDoRpcExt2 Method (opnum 11)] [rgbAuxOut] The server MUST include a RPC_HEADER_EXT header before the auxiliary payload data.");
            }

            // Use method EcDoRpcExt2, output buffer is rgbOut
            if ((!isExOrExt2) && (!isAuxOutOrOut))
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R658");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R658
                // According to the Open Specification, RPC_HEADER_EXT can be determined by the version field.
                // The version of the header MUST be set to 0x0000
                Site.CaptureRequirementIfAreEqual<ushort>(
                    0x0000,
                    header.Version,
                    658,
                    @"[In EcDoRpcExt2 Method (opnum 11)] [rgbOut] Like the ROP request payload, the ROP response payload is also prefixed by a RPC_HEADER_EXT header.");
            }
            #endregion Verify whether rgbAuxOut includes an RPC_HEADER_EXT

            #region Verify Version field

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R33");

            // Verify MS-OXCRPC requirement: MS-OXCRPC_R33
            Site.CaptureRequirementIfAreEqual<ushort>(
                0x0000,
                header.Version,
                33,
                @"[In RPC_HEADER_EXT Structure] [Version (2 bytes)] This value MUST be set to 0x0000.");

            #endregion Verify Version field

            #region Verify Flags field
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R34");

            // Verify MS-OXCRPC requirement: MS-OXCRPC_R34
            // If the Flags is an unsigned short value, then it must be 2 bytes, and this requirement will be verified.
            Site.CaptureRequirementIfAreEqual<Type>(
                typeof(ushort),
                header.Flags.GetType(),
                34,
                @"[In RPC_HEADER_EXT Structure] Flags (2 bytes): The flags that specify how data that follows this header [RPC_HEADER_EXT] MUST be interpreted.");

            if (header.Flags != 0x0000)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R35, the value of Flags buffer is:{0}.", header.Flags);

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R35
                bool isVerifyR35 = ((header.Flags & 0x0001) == 0x0001) ||
                    ((header.Flags & 0x0002) == 0x0002) ||
                    ((header.Flags & 0x0004) == 0x0004);

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR35,
                    35,
                    @"[In RPC_HEADER_EXT Structure] [Flags (2 bytes)] The flags [Compressed, XorMagic, Last] in the following table are valid.");
            }

            // Flag values used here is the values before decompressing. All flag values in header.Flags are the values after decompressing 
            // and 0x0001 which indicates compressed data will no longer exists.
            foreach (short flag in flagValues)
            {
                if ((flag & 0x0001) == 0x0001)
                {
                    // Verify MS-OXCRPC requirement: MS-OXCRPC_R4794
                    // Compared with SizeActual, the value of Size field doesn't include the length of RPC_HEADER_EXT structure according to the Open Specification.
                    // And the value of Size field is updated to the value of SizeActual when decompressing. So if code can reach here, R4794 can be verified directly.
                    this.Site.CaptureRequirement(
                        4794,
                        @"[In RPC_HEADER_EXT Structure] [Flags (2 bytes)] [Compressed 0x0001] If this flag is set, the value of the Size field MUST be less than the value of the SizeActual field.");
                }
            }

            // Use method EcDoRpcExt2, output buffer is rgbOut, except last header
            if ((!isExOrExt2) && (!isAuxOutOrOut) && (!isLast))
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R778");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R778
                // According to Open Specification, rgbOut is only on the method EcDoRpcExt2
                // Last flag value is 0x0004
                Site.CaptureRequirementIfAreNotEqual<int>(
                    0x0004,
                    header.Flags & 0x0004,
                    778,
                    @"[In rgbOut Output Buffer] All RPC_HEADER_EXT structures in the output buffer except for the last MUST NOT contain the Last flag in the Flags field of the RPC_HEADER_EXT structure.");
            }

            // Use method EcDoRpcExt2, output buffer is rgbOut, header is last header
            if (!isExOrExt2 && !isAuxOutOrOut && isLast)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R779");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R779
                // According to Open Specification, rgbOut is only on the method EcDoRpcExt2
                // Last flag value is 0x0004
                Site.CaptureRequirementIfAreEqual<int>(
                    0x0004,
                    header.Flags & 0x0004,
                    779,
                    @"[In rgbOut Output Buffer] The last RPC_HEADER_EXT structure in the output buffer MUST contain the Last flag in its Flags field.");
            }

            if ((header.Flags & (ushort)RpcHeaderExtFlags.Last) == 0x0004)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R40, the value of Flags buffer is:{0}.", header.Flags);

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R40
                Site.CaptureRequirementIfIsTrue(
                    isLast,
                    40,
                    @"[In RPC_HEADER_EXT Structure] [Flags (2 bytes)] [Last 0x0004] No other RPC_HEADER_EXT structure follows the data of the current RPC_HEADER_EXT structure.");
            }

            #endregion Verify Flags field

            #region Verify Size and SizeActual fields

            // Verify the Compressed (0x0001) bit is not set in the Flags field.
            if ((header.Flags & 0x0001) != 0x0001)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R38");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R38
                Site.CaptureRequirementIfAreEqual<ushort>(
                    header.Size,
                    header.SizeActual,
                    38,
                    @"[In RPC_HEADER_EXT Structure] [Flags (2 bytes)] [Compressed 0x0001] If this flag is not set, the Size and SizeActual fields MUST be the same.");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCRPC_R46");

                // Verify MS-OXCRPC requirement: MS-OXCRPC_R46
                Site.CaptureRequirementIfAreEqual<ushort>(
                    header.Size,
                    header.SizeActual,
                    46,
                    @"[In RPC_HEADER_EXT Structure] [SizeActual (2 bytes)] If the Compressed flag is not set, this value [SizeActual] MUST be equal to the value of the Size field.");
            }
            #endregion Verify Size and SizeActual fields
        }
        /// <summary>
        /// The method parses ROP response buffer.
        /// </summary>
        /// <param name="rgbOut">The ROP response payload.</param>
        /// <param name="rpcHeaderExts">Array of RPCIHEADER_EXT.</param>
        /// <param name="rops">Byte array contains parsed ROP command.</param>
        /// <param name="serverHandleObjectsTables">Server handle objects tables.</param>
        private void ParseResponseBuffer(byte[] rgbOut, out RPC_HEADER_EXT[] rpcHeaderExts, out byte[][] rops, out uint[][] serverHandleObjectsTables)
        {
            List<RPC_HEADER_EXT> rpcHeaderExtList = new List<RPC_HEADER_EXT>();
            List<byte[]> ropList = new List<byte[]>();
            List<uint[]> serverHandleObjectList = new List<uint[]>();
            IntPtr ptr = IntPtr.Zero;

            int index = 0;
            bool isEnd = false;
            do
            {
                // Parse RPC header ext.
                RPC_HEADER_EXT rpcHeaderExt;
                ptr = Marshal.AllocHGlobal(AdapterHelper.RPCHeaderExtlength);
                                                                                                                                                                             
                // Release ptr in final sub-statement to make sure the resources will be released even if an exception occurs
                try
                {
                    Marshal.Copy(rgbOut, index, ptr, AdapterHelper.RPCHeaderExtlength);
                    rpcHeaderExt = (RPC_HEADER_EXT)Marshal.PtrToStructure(ptr, typeof(RPC_HEADER_EXT));
                    isEnd = (rpcHeaderExt.Flags & (ushort)RpcHeaderExtFlags.Last) == (ushort)RpcHeaderExtFlags.Last;
                    rpcHeaderExtList.Add(rpcHeaderExt);
                    index += AdapterHelper.RPCHeaderExtlength;
                }
                finally
                {
                    Marshal.FreeHGlobal(ptr);
                }

                // Parse payload
                // Parse ropSize
                ushort ropSize = BitConverter.ToUInt16(rgbOut, index);
                index += ConstValues.RopSizeInRopInputOutputBufferSize;

                if ((ropSize - ConstValues.RopSizeInRopInputOutputBufferSize) > 0)
                {
                    // Parse ROP
                    byte[] rop = new byte[ropSize - ConstValues.RopSizeInRopInputOutputBufferSize];
                    Array.Copy(rgbOut, index, rop, 0, ropSize - ConstValues.RopSizeInRopInputOutputBufferSize);
                    ropList.Add(rop);
                    index += ropSize - ConstValues.RopSizeInRopInputOutputBufferSize;
                }

                // Parse server handle objects table
                // Each server handle object is 32 bytes
                Site.Assert.IsTrue(
                    (rpcHeaderExt.Size - ropSize) % sizeof(uint) == 0, "Server object handle should be uint32 array. The actual size of the server object handle is {0}.", rpcHeaderExt.Size - ropSize);

                int count = (rpcHeaderExt.Size - ropSize) / sizeof(uint);
                if (count > 0)
                {
                    uint[] sohs = new uint[count];
                    for (int counter = 0; counter < count; counter++)
                    {
                        sohs[counter] = BitConverter.ToUInt32(rgbOut, index);
                        index += sizeof(uint);
                    }
                                                                                                                                                                                                
                    serverHandleObjectList.Add(sohs);
                }
                                                                                                                                                                             
                // End parse payload
            } 
            while (!isEnd);

            rpcHeaderExts = rpcHeaderExtList.ToArray();
            rops = ropList.Count > 0 ? ropList.ToArray() : null;
            serverHandleObjectsTables = serverHandleObjectList.ToArray();
        }
        /// <summary>
        /// Extracts RPC_HEADER_EXT structure from rgbAuxOut buffer.
        /// </summary>
        /// <param name="payload">The rgbAuxOut buffer contained in the response buffer.</param>
        /// <param name="headerExt">The RPC_HEADER_EXT structure. </param>
        /// <returns>The flag to indicate whether the rgbAuxOut is a valid buffer.</returns>
        private static bool ExtractExtendedHeader(byte[] payload, out RPC_HEADER_EXT headerExt)
        {
            headerExt = new RPC_HEADER_EXT();
            if (payload.Length < AdapterHelper.RPCHeaderExtlength)
            {
                return false;
            }

            headerExt.Version = BitConverter.ToUInt16(payload, 0);
            headerExt.Flags = BitConverter.ToUInt16(payload, ConstValues.RpcHeaderExtSizeByteSize);
            headerExt.Size = BitConverter.ToUInt16(payload, ConstValues.RpcHeaderExtVersionByteSize + ConstValues.RpcHeaderExtFlagsByteSize);
            headerExt.SizeActual = BitConverter.ToUInt16(payload, ConstValues.RpcHeaderExtVersionByteSize + ConstValues.RpcHeaderExtFlagsByteSize + ConstValues.RpcHeaderExtSizeByteSize);
            return true;
        }