/// <summary> /// Reassemble chunk data by the member field channelManager. /// This method is called when processing Virtual Channel PDU. /// </summary> /// <param name="pdu">The channel pdu includes header and data. This argument can be null.</param> /// <returns>If the reassemble is complete, then return the Virtual_Channel_Complete_Pdu. /// Else return null.</returns> internal Virtual_Channel_Complete_Pdu ReassembleChunkData(Virtual_Channel_RAW_Pdu pdu) { lock (contextLock) { return channelManager.ReassembleChunkData(pdu); } }
/// <summary> /// Decode Virtual Channel PDU /// </summary> /// <param name="data">data to be parsed</param> /// <param name="decryptedUserData">decrypted user data</param> /// <param name="type">security header type</param> /// <returns>decoded Virtual Channel PDU</returns> public StackPacket DecodeVirtualChannelPDU( byte[] data, byte[] decryptedUserData, SecurityHeaderType type) { Virtual_Channel_RAW_Pdu pdu = new Virtual_Channel_RAW_Pdu(); // data index int dataIndex = 0; // Virtual_Channel_RAW_Pdu: commonHeader pdu.commonHeader = ParseMcsCommonHeader(data, ref dataIndex, type); // user data index int userDataIndex = 0; // Virtual_Channel_RAW_PDU: channelPduHeader pdu.channelPduHeader = ParseChannelPduHeader(decryptedUserData, ref userDataIndex); // Virtual_Channel_RAW_PDU: virtualChannelData int remainLength = decryptedUserData.Length - Marshal.SizeOf(pdu.channelPduHeader); pdu.virtualChannelData = GetBytes(decryptedUserData, ref userDataIndex, remainLength); /* // ETW Provider Dump Message if (pdu.commonHeader.securityHeader != null) { // RDP Standard Security string messageName = "RDPBCGR:" + pdu.GetType().Name; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer3, pdu.GetType().Name, decryptedUserData); } * */ // Check if data length exceeded expectation VerifyDataLength(decryptedUserData.Length, userDataIndex, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED); return pdu; }
/// <summary> /// Decompress the virtual channel data into decompressedBuffer buffer. /// After decompressing the last pdu, the member decompressedBuffer contains /// the complete virtual data. /// </summary> /// <param name="pdu">The virtual channel pdu includes header and data.</param> /// <returns>If the reassemble is complete, then return the completePdu. Else return null.</returns> internal Virtual_Channel_Complete_Pdu ReassembleChunkData(Virtual_Channel_RAW_Pdu pdu) { if (pdu == null || pdu.virtualChannelData == null) { return null; } // the first chunk if ((pdu.channelPduHeader.flags & CHANNEL_PDU_HEADER_flags_Values.CHANNEL_FLAG_FIRST) == CHANNEL_PDU_HEADER_flags_Values.CHANNEL_FLAG_FIRST) { completePdu = new Virtual_Channel_Complete_Pdu(); completePdu.rawPdus = new System.Collections.ObjectModel.Collection<Virtual_Channel_RAW_Pdu>(); completePdu.channelId = channelId; decompressedBuffer.Clear(); } byte[] decompressedData = pdu.virtualChannelData; if (mppcDecompressor != null) // has compression { CompressMode flag = CompressMode.None; if ((pdu.channelPduHeader.flags & CHANNEL_PDU_HEADER_flags_Values.CHANNEL_PACKET_AT_FRONT) == CHANNEL_PDU_HEADER_flags_Values.CHANNEL_PACKET_AT_FRONT) { flag |= CompressMode.SetToFront; } if ((pdu.channelPduHeader.flags & CHANNEL_PDU_HEADER_flags_Values.CHANNEL_PACKET_COMPRESSED) == CHANNEL_PDU_HEADER_flags_Values.CHANNEL_PACKET_COMPRESSED) { flag |= CompressMode.Compressed; } if ((pdu.channelPduHeader.flags & CHANNEL_PDU_HEADER_flags_Values.CHANNEL_PACKET_FLUSHED) == CHANNEL_PDU_HEADER_flags_Values.CHANNEL_PACKET_FLUSHED) { flag |= CompressMode.Flush; } if (flag != CompressMode.None) { decompressedData = mppcDecompressor.Decompress(pdu.virtualChannelData, flag); } } if (completePdu != null) { completePdu.rawPdus.Add(pdu); decompressedBuffer.AddRange(decompressedData); } else { // not need to reassemble Virtual_Channel_Complete_Pdu returnPDU = new Virtual_Channel_Complete_Pdu(); returnPDU.rawPdus = new System.Collections.ObjectModel.Collection<Virtual_Channel_RAW_Pdu>(); returnPDU.channelId = channelId; returnPDU.rawPdus.Add(pdu); returnPDU.virtualChannelData = decompressedData; return returnPDU; } // the last chunk if ((pdu.channelPduHeader.flags & CHANNEL_PDU_HEADER_flags_Values.CHANNEL_FLAG_LAST) == CHANNEL_PDU_HEADER_flags_Values.CHANNEL_FLAG_LAST) { if (decompressedBuffer != null) { completePdu.virtualChannelData = decompressedBuffer.ToArray(); } Virtual_Channel_Complete_Pdu returnPDU = completePdu; completePdu = null; return returnPDU; } return null; }
/// <summary> /// Reasemble Chunk Data /// </summary> /// <param name="pdu"></param> /// <returns></returns> internal Virtual_Channel_Complete_Pdu ReassembleChunkData(Virtual_Channel_RAW_Pdu pdu) { if (!channelDicById.ContainsKey(pdu.commonHeader.channelId)) { // drop the pdu if the channel id does not exist //return null; throw new ArgumentException("The channel id of the pdu does not exist!"); } ServerStaticVirtualChannel channel = (ServerStaticVirtualChannel)channelDicById[pdu.commonHeader.channelId]; return channel.ReassembleChunkData(pdu); }
/// <summary> /// Split the virtualChannelData to several chunk data to send. /// </summary> public void SplitToChunks() { ChannelChunk[] chunks = context.SplitToChunks(channelId, virtualChannelData); if (chunks != null && chunks.Length > 0) { rawPdus = new Collection<Virtual_Channel_RAW_Pdu>(); for (int i = 0; i < chunks.Length; ++i) { Virtual_Channel_RAW_Pdu rawPdu = new Virtual_Channel_RAW_Pdu(context); rawPdu.channelPduHeader = chunks[i].channelPduHeader; rawPdu.virtualChannelData = chunks[i].chunkData; rawPdus.Add(rawPdu); RdpbcgrUtility.FillCommonHeader(ref rawPdus[i].commonHeader, TS_SECURITY_HEADER_flags_Values.SEC_IGNORE_SEQNO | TS_SECURITY_HEADER_flags_Values.SEC_RESET_SEQNO, context, channelId); } } }