static inline void prepare_compressed_data(InStream & compressed_data_stream, bool compressed, uint16_t & MatchCount, uint8_t const * & MatchDetails, uint8_t const * & Literals, size_t & literals_length) { if (compressed) { unsigned expected = 2; // MatchCount(2) if (!compressed_data_stream.in_check_rem(expected)) { LOG(LOG_ERR, "RDP61_COMPRESSED_DATA: data truncated, expected=%u remains=%zu", expected, compressed_data_stream.in_remain()); throw Error(ERR_RDP61_DECOMPRESS_DATA_TRUNCATED); } MatchCount = compressed_data_stream.in_uint16_le(); expected = MatchCount * 8; // MatchCount(2) * (MatchLength(2) + MatchOutputOffset(2) + MatchHistoryOffset(4)) if (!compressed_data_stream.in_check_rem(expected)) { LOG(LOG_ERR, "RDP61_COMPRESSED_DATA: data truncated, expected=%u remains=%zu", expected, compressed_data_stream.in_remain()); throw Error(ERR_RDP61_DECOMPRESS_DATA_TRUNCATED); } MatchDetails = compressed_data_stream.get_current(); compressed_data_stream.in_skip_bytes(expected); } else { MatchCount = 0; MatchDetails = nullptr; } literals_length = compressed_data_stream.in_remain(); Literals = (literals_length ? compressed_data_stream.get_current() : nullptr); }
explicit ShareData_Recv(InStream & stream, rdp_mppc_dec * dec = nullptr) //============================================================================== : CheckShareData_Recv(stream) , share_id(stream.in_uint32_le()) , pad1(stream.in_uint8()) , streamid(stream.in_uint8()) , len(stream.in_uint16_le()) , pdutype2(stream.in_uint8()) , compressedType(stream.in_uint8()) , compressedLen(stream.in_uint16_le()) , payload([&stream, dec, this]() { if (this->compressedType & PACKET_COMPRESSED) { if (!dec) { LOG(LOG_INFO, "ShareData_Recv: got unexpected compressed share data"); throw Error(ERR_SEC); } const uint8_t * rdata; uint32_t rlen; dec->decompress(stream.get_data()+stream.get_offset(), stream.in_remain(), this->compressedType, rdata, rlen); return InStream(rdata, 0, rlen); } else { return InStream(stream.get_current(), stream.in_remain()); } }()) // BEGIN CONSTRUCTOR { //LOG( LOG_INFO, "ShareData_Recv: pdutype2=%u len=%u compressedLen=%u payload_size=%u" // , this->pdutype2, this->len, this->compressedLen, this->payload.size()); stream.in_skip_bytes(stream.in_remain()); } // END CONSTRUCTOR
explicit ClientInputEventPDU_Recv(InStream & stream) : numEvents( [&stream](){ if (!stream.in_check_rem(2)) { LOG(LOG_ERR, "SlowPath::ClientInputEventPDU: data truncated (numEvents)"); throw Error(ERR_RDP_SLOWPATH); } auto numEvents = stream.in_uint16_le(); const unsigned expected = 2 // pad(2) + numEvents * 12 // (time(4) + mes_type(2) + device_flags(2) + param1(2) + param2(2)) * 12 ; if (!stream.in_check_rem(expected)) { LOG(LOG_ERR, "SlowPath::ClientInputEventPDU: data truncated, expected=%u remains=%zu", expected, stream.in_remain()); throw Error(ERR_RDP_SLOWPATH); } stream.in_skip_bytes(2); // pad return numEvents; }() ) // (time(4) + mes_type(2) + device_flags(2) + param1(2) + param2(2)) * 12 , payload(stream.get_current(), this->numEvents * 12) { // This is the constructor body, we skip payload now that it is packaged stream.in_skip_bytes(this->payload.get_capacity()); }
explicit ShareControl_Recv(InStream & stream) : totalLength([&stream]() { if (!stream.in_check_rem(2+2)){ LOG(LOG_ERR, "Truncated [4: ShareControl packet] , remains=%zu", stream.in_remain()); throw Error(ERR_SEC); } return stream.in_uint16_le(); }()) , pduType(stream.in_uint16_le() & 0xF) , PDUSource([&stream, this]() { if (this->pduType == PDUTYPE_DEACTIVATEALLPDU && this->totalLength == 4) { // should not happen // but DEACTIVATEALLPDU seems to be broken on windows 2000 return static_cast<uint16_t>(0); } return stream.in_uint16_le(); }()) , payload([&stream, this]() { if (this->pduType == PDUTYPE_DEACTIVATEALLPDU && this->totalLength == 4) { // should not happen // but DEACTIVATEALLPDU seems to be broken on windows 2000 return InStream(stream.get_current(), 0); } if (this->totalLength < 6) { LOG(LOG_ERR, "ShareControl packet too short totalLength=%u pduType=%u mcs_channel=%u", this->totalLength, this->pduType, this->PDUSource); throw Error(ERR_SEC); } if (!stream.in_check_rem(this->totalLength - 6)) { LOG(LOG_ERR, "Truncated ShareControl packet, need=%u remains=%zu", this->totalLength - 6, stream.in_remain()); throw Error(ERR_SEC); } return InStream(stream.get_current(), this->totalLength - 6); }()) // body of constructor { if (this->totalLength == 0x8000) { LOG(LOG_ERR, "Expected ShareControl header, got flowMarker"); throw Error(ERR_SEC); } stream.in_skip_bytes(this->payload.get_capacity()); }
void recv(InStream & stream) { uint8_t const * pBegin = stream.get_current(); bool res; res = this->message.recv(stream); if (!res) { LOG(LOG_ERR, "INVALID MSG RECEIVED type: %u", this->message.msgType); } this->LmChallengeResponse.recv(stream); this->NtChallengeResponse.recv(stream); this->DomainName.recv(stream); this->UserName.recv(stream); this->Workstation.recv(stream); this->EncryptedRandomSessionKey.recv(stream); this->negoFlags.recv(stream); if (this->negoFlags.flags & NTLMSSP_NEGOTIATE_VERSION) { this->version.recv(stream); } uint32_t min_offset = this->LmChallengeResponse.bufferOffset; if (this->NtChallengeResponse.bufferOffset < min_offset) min_offset = this->NtChallengeResponse.bufferOffset; if (this->DomainName.bufferOffset < min_offset) min_offset = this->DomainName.bufferOffset; if (this->UserName.bufferOffset < min_offset) min_offset = this->UserName.bufferOffset; if (this->Workstation.bufferOffset < min_offset) min_offset = this->Workstation.bufferOffset; if (this->EncryptedRandomSessionKey.bufferOffset < min_offset) min_offset = this->EncryptedRandomSessionKey.bufferOffset; if (min_offset + pBegin > stream.get_current()) { this->has_mic = true; stream.in_copy_bytes(this->MIC, 16); } else { this->has_mic = false; } // PAYLOAD this->LmChallengeResponse.read_payload(stream, pBegin); this->NtChallengeResponse.read_payload(stream, pBegin); this->DomainName.read_payload(stream, pBegin); this->UserName.read_payload(stream, pBegin); this->Workstation.read_payload(stream, pBegin); this->EncryptedRandomSessionKey.read_payload(stream, pBegin); }
void receive(InStream & stream, const RDPPrimaryOrderHeader & header) { //LOG(LOG_INFO, "RDPMultiDstBlt::receive: header fields=0x%02X", header.fields); header.receive_coord(stream, 0x0001, this->nLeftRect); header.receive_coord(stream, 0x0002, this->nTopRect); header.receive_coord(stream, 0x0004, this->nWidth); header.receive_coord(stream, 0x0008, this->nHeight); if (header.fields & 0x0010) { this->bRop = stream.in_uint8(); } if (header.fields & 0x0020) { this->nDeltaEntries = stream.in_uint8(); } if (header.fields & 0x0040) { uint16_t cbData = stream.in_uint16_le(); //LOG(LOG_INFO, "cbData=%d", cbData); InStream rgbData(stream.get_current(), cbData); stream.in_skip_bytes(cbData); //hexdump_d(rgbData.get_current(), rgbData.get_capacity()); uint8_t zeroBitsSize = ((this->nDeltaEntries + 1) / 2); //LOG(LOG_INFO, "zeroBitsSize=%d", zeroBitsSize); InStream zeroBits(rgbData.get_current(), zeroBitsSize); rgbData.in_skip_bytes(zeroBitsSize); uint8_t zeroBit = 0; for (uint8_t i = 0, m2 = 0; i < this->nDeltaEntries; i++, m2++) { if (m2 == 2) { m2 = 0; } if (!m2) { zeroBit = zeroBits.in_uint8(); //LOG(LOG_INFO, "0x%02X", zeroBit); } this->deltaEncodedRectangles[i].leftDelta = (!(zeroBit & 0x80) ? rgbData.in_DEP() : 0); this->deltaEncodedRectangles[i].topDelta = (!(zeroBit & 0x40) ? rgbData.in_DEP() : 0); this->deltaEncodedRectangles[i].width = (!(zeroBit & 0x20) ? rgbData.in_DEP() : 0); this->deltaEncodedRectangles[i].height = (!(zeroBit & 0x10) ? rgbData.in_DEP() : 0); //LOG(LOG_INFO, "RDPMultiDstBlt::receive: delta rectangle=(%d, %d, %d, %d)", // this->deltaEncodedRectangles[i].leftDelta, this->deltaEncodedRectangles[i].topDelta, // this->deltaEncodedRectangles[i].width, this->deltaEncodedRectangles[i].height); zeroBit <<= 4; } } } // void receive(InStream & stream, const RDPPrimaryOrderHeader & header)
explicit SaveSessionInfoPDUData_Recv(InStream & stream) : infoType([&stream](){ if (!stream.in_check_rem(4)) { LOG(LOG_ERR, "Truncated Save Session Info PDU (data): expected=4 remains=%zu", stream.in_remain()); throw Error(ERR_RDP_DATA_TRUNCATED); } return stream.in_uint32_le(); }()), payload(stream.get_current(), stream.in_remain()) { stream.in_skip_bytes(this->payload.get_capacity()); }
void recv(InStream & stream) { for (std::size_t i = 0; i < AV_ID_MAX; ++i) { NTLM_AV_ID id = static_cast<NTLM_AV_ID>(stream.in_uint16_le()); uint16_t length = stream.in_uint16_le(); if (id == MsvAvEOL) { // ASSUME last element is MsvAvEOL stream.in_skip_bytes(length); break; } this->add(id, stream.get_current(), length); stream.in_skip_bytes(length); } }
explicit LogonInfoField_Recv(InStream & stream) : cbFieldData([&stream](){ const unsigned expected = 4; // cbFieldData(4) if (!stream.in_check_rem(expected)) { LOG(LOG_ERR, "Truncated Logon Info Field (data): expected=%u remains=%zu", expected, stream.in_remain()); throw Error(ERR_RDP_DATA_TRUNCATED); } return stream.in_uint32_le(); }()) , payload(stream.get_current(), stream.in_remain()) { stream.in_skip_bytes(this->payload.get_capacity()); }
explicit InputEvent_Recv(InStream & stream) : eventTime([&stream](){ // time(4) + mes_type(2) + device_flags(2) + param1(2) + param2(2) if (!stream.in_check_rem(12)) { LOG(LOG_ERR, "SlowPath::InputEvent: data truncated, expected=12 remains=%zu", stream.in_remain()); throw Error(ERR_RDP_SLOWPATH); } return stream.in_uint32_le(); }()) , messageType(stream.in_uint16_le()) // device_flags(2) + param1(2) + param2(2) , payload(stream.get_current(), 6) // Body of constructor { stream.in_skip_bytes(this->payload.get_capacity()); }
void receive(InStream & stream, const RDPPrimaryOrderHeader & header) { // LOG(LOG_INFO, "RDPPolygonSC::receive: header fields=0x%02X", header.fields); header.receive_coord(stream, 0x0001, this->xStart); header.receive_coord(stream, 0x0002, this->yStart); if (header.fields & 0x0004) { this->bRop2 = stream.in_uint8(); } if (header.fields & 0x0008) { this->fillMode = stream.in_uint8(); } if (header.fields & 0x0010) { receive_rdp_color(stream, this->backColor); } if (header.fields & 0x0020) { receive_rdp_color(stream, this->foreColor); } header.receive_brush(stream, 0x0040, this->brush); if (header.fields & 0x0800) { this->NumDeltaEntries = stream.in_uint8(); } if (header.fields & 0x1000) { uint8_t cbData = stream.in_uint8(); // LOG(LOG_INFO, "cbData=%d", cbData); InStream rgbData(stream.get_current(), cbData); stream.in_skip_bytes(cbData); // hexdump_d(rgbData.get_current(), rgbData.get_capacity()); uint8_t zeroBitsSize = ((this->NumDeltaEntries + 3) / 4); // LOG(LOG_INFO, "zeroBitsSize=%d", zeroBitsSize); InStream zeroBits(rgbData.get_current(), zeroBitsSize); rgbData.in_skip_bytes(zeroBitsSize); uint8_t zeroBit = 0; for (uint8_t i = 0, m4 = 0; i < this->NumDeltaEntries; i++, m4++) { if (m4 == 4) { m4 = 0; } if (!m4) { zeroBit = zeroBits.in_uint8(); // LOG(LOG_INFO, "0x%02X", zeroBit); } this->deltaPoints[i].xDelta = (!(zeroBit & 0x80) ? rgbData.in_DEP() : 0); this->deltaPoints[i].yDelta = (!(zeroBit & 0x40) ? rgbData.in_DEP() : 0); /* LOG(LOG_INFO, "RDPPolygonCB::receive: delta point=%d, %d", this->deltaPoints[i].xDelta, this->deltaPoints[i].yDelta); */ zeroBit <<= 2; } } } // receive
void ClientRDPSNDChannel::receive(InStream & chunk) { if (this->wave_data_to_wait) { this->wave_data_to_wait -= chunk.in_remain(); if (this->wave_data_to_wait < 0) { this->wave_data_to_wait = 0; } if (this->last_PDU_is_WaveInfo) { chunk.in_skip_bytes(4); this->last_PDU_is_WaveInfo = false; } if (this->impl_sound) { this->impl_sound->setData(chunk.get_current(), chunk.in_remain()); } if (!(this->wave_data_to_wait)) { if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU"); } LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU 1"); if (this->impl_sound) { LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU 2"); uint8_t data[] = {'\0'}; LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU 3"); this->impl_sound->setData(data, 1); LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU 4"); this->impl_sound->play(); LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU 5"); // LOG(LOG_INFO, "ClientRDPSNDChannel::receive play!!!"); } LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU 6"); StaticOutStream<16> out_stream; rdpsnd::RDPSNDPDUHeader header(rdpsnd::SNDC_WAVECONFIRM, 4); header.emit(out_stream); LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU 7"); rdpsnd::WaveConfirmPDU wc(this->last_wTimeStamp, this->last_cBlockNo); wc.emit(out_stream); InStream chunk_to_send(out_stream.get_bytes()); LOG(LOG_INFO, "SERVER >> RDPEA: Wave PDU 8"); this->callback->send_to_mod_channel( channel_names::rdpsnd , chunk_to_send , out_stream.get_offset() , this->channel_flags ); if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "CLIENT >> RDPEA: Wave Confirm PDU"); } } } else { rdpsnd::RDPSNDPDUHeader header; header.receive(chunk); switch (header.msgType) { case rdpsnd::SNDC_FORMATS: { if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: Server Audio Formats and Version PDU"); } rdpsnd::ServerAudioFormatsandVersionHeader safsvh; safsvh.receive(chunk); StaticOutStream<1024> out_stream; rdpsnd::RDPSNDPDUHeader header_out(rdpsnd::SNDC_FORMATS, 38); header_out.emit(out_stream); rdpsnd::ClientAudioFormatsandVersionHeader cafvh( this->dwFlags , this->dwVolume , this->dwPitch , this->wDGramPort , this->wNumberOfFormats , this->wVersion ); cafvh.emit(out_stream); for (uint16_t i = 0; i < safsvh.wNumberOfFormats; i++) { rdpsnd::AudioFormat format; format.receive(chunk); // format.log(); if (format.wFormatTag == rdpsnd::WAVE_FORMAT_PCM) { format.emit(out_stream); if (this->impl_sound) { this->impl_sound->n_sample_per_sec = format.nSamplesPerSec; this->impl_sound->bit_per_sample = format.wBitsPerSample; this->impl_sound->n_channels = format.nChannels; this->impl_sound->n_block_align = format.nBlockAlign; this->impl_sound->bit_per_sec = format.nSamplesPerSec * (format.wBitsPerSample/8) * format.nChannels; } else { //LOG(LOG_WARNING, "No Sound System module found"); } } } InStream chunk_to_send(out_stream.get_bytes()); this->callback->send_to_mod_channel( channel_names::rdpsnd , chunk_to_send , out_stream.get_offset() , this->channel_flags ); if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "CLIENT >> RDPEA: Client Audio Formats and Version PDU"); } StaticOutStream<32> quality_stream; rdpsnd::RDPSNDPDUHeader header_quality(rdpsnd::SNDC_QUALITYMODE, 8); header_quality.emit(quality_stream); rdpsnd::QualityModePDU qm(rdpsnd::HIGH_QUALITY); qm.emit(quality_stream); InStream chunk_to_send2(quality_stream.get_bytes()); this->callback->send_to_mod_channel( channel_names::rdpsnd , chunk_to_send2 , quality_stream.get_offset() , this->channel_flags ); if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "CLIENT >> RDPEA: Quality Mode PDU"); } } break; case rdpsnd::SNDC_TRAINING: { if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: Training PDU"); } rdpsnd::TrainingPDU train; train.receive(chunk); StaticOutStream<32> out_stream; rdpsnd::RDPSNDPDUHeader header_quality(rdpsnd::SNDC_TRAINING, 4); header_quality.emit(out_stream); rdpsnd::TrainingConfirmPDU train_conf(train.wTimeStamp, train.wPackSize); train_conf.emit(out_stream); InStream chunk_to_send(out_stream.get_bytes()); this->callback->send_to_mod_channel( channel_names::rdpsnd , chunk_to_send , out_stream.get_offset() , this->channel_flags ); if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "CLIENT >> RDPEA: Training Confirm PDU"); } } break; case rdpsnd::SNDC_WAVE: { if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: Wave Info PDU"); } this->wave_data_to_wait = header.BodySize - 8; rdpsnd::WaveInfoPDU wi; wi.receive(chunk); this->last_cBlockNo = wi.cBlockNo; this->last_wTimeStamp = wi.wTimeStamp; if (this->impl_sound) { this->impl_sound->init(header.BodySize - 12); this->impl_sound->setData(wi.Data, 4); } this->last_PDU_is_WaveInfo = true; } break; case rdpsnd::SNDC_CLOSE: if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: Close PDU"); } break; case rdpsnd::SNDC_SETVOLUME: if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: SNDC_SETVOLUME PDU"); } { rdpsnd::VolumePDU v; v.receive(chunk); } break; case rdpsnd::SNDC_SETPITCH: if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: SNDC_SETPITCH PDU"); } { rdpsnd::PitchPDU p; p.receive(chunk); } break; // case rdpsnd::SNDC_CRYPTKEY: // LOG(LOG_INFO, "SERVER >> RDPEA: SNDC_CRYPTKEY PDU"); // break; // case rdpsnd::SNDC_WAVEENCRYPT: // LOG(LOG_INFO, "SERVER >> RDPEA: SNDC_WAVEENCRYPT PDU"); // break; case rdpsnd::SNDC_QUALITYMODE: if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: SNDC_QUALITYMODE PDU"); } { rdpsnd::QualityModePDU qm; qm.receive(chunk); } break; case rdpsnd::SNDC_WAVE2: if (bool(this->verbose & RDPVerbose::rdpsnd)) { LOG(LOG_INFO, "SERVER >> RDPEA: SNDC_WAVE2 PDU"); } { this->wave_data_to_wait = header.BodySize - 12; rdpsnd::Wave2PDU w2; w2.receive(chunk); if (this->impl_sound) { this->impl_sound->init(header.BodySize - 12); this->impl_sound->setData(chunk.get_current(), chunk.in_remain()); } this->last_PDU_is_WaveInfo = true; } break; default: LOG(LOG_WARNING, "SERVER >> RDPEA: Unknown message type: %x", header.msgType); break; } } }