From 698cae2052014637d3bd6d5e6596c3a3a1c5e3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 16 Mar 2014 20:54:07 -0400 Subject: [PATCH] libfreerdp-codec: start hooking new NCrush decompressor --- include/freerdp/codec/ncrush.h | 5 +- libfreerdp/codec/ncrush.c | 118 ++++++++++++++++++++++----------- libfreerdp/core/bulk.c | 25 +++---- libfreerdp/core/bulk.h | 5 +- 4 files changed, 100 insertions(+), 53 deletions(-) diff --git a/include/freerdp/codec/ncrush.h b/include/freerdp/codec/ncrush.h index f2e45f46e..2cd291706 100644 --- a/include/freerdp/codec/ncrush.h +++ b/include/freerdp/codec/ncrush.h @@ -32,8 +32,9 @@ struct _NCRUSH_CONTEXT BOOL Compressor; BYTE* HistoryPtr; UINT32 HistoryOffset; - UINT32 HistoryBufferSize; + UINT32 HistoryEndOffset; BYTE HistoryBuffer[65536]; + UINT32 HistoryBufferFence; UINT32 OffsetCache[4]; }; typedef struct _NCRUSH_CONTEXT NCRUSH_CONTEXT; @@ -45,6 +46,8 @@ extern "C" { FREERDP_API int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, UINT32* pDstSize, UINT32* pFlags); FREERDP_API int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags); +FREERDP_API void ncrush_context_reset(NCRUSH_CONTEXT* ncrush); + FREERDP_API NCRUSH_CONTEXT* ncrush_context_new(BOOL Compressor); FREERDP_API void ncrush_context_free(NCRUSH_CONTEXT* ncrush); diff --git a/libfreerdp/codec/ncrush.c b/libfreerdp/codec/ncrush.c index 4d69fd3f1..75ab46e8b 100644 --- a/libfreerdp/codec/ncrush.c +++ b/libfreerdp/codec/ncrush.c @@ -1115,6 +1115,7 @@ UINT32 LOMBaseLUT[30] = int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags) { + UINT32 index; UINT32 bits; UINT32 nbits; BYTE* SrcPtr; @@ -1125,6 +1126,7 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY UINT32 BitLength; UINT32 MaskedBits; UINT32 CopyOffset; + UINT32 CopyLength; UINT32 OldCopyOffset; UINT32 LengthOfMatch; UINT32 CopyOffsetIndex; @@ -1132,30 +1134,36 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY BYTE* HistoryPtr; BYTE* HistoryBuffer; BYTE* HistoryBufferEnd; - UINT32 HistoryBufferSize; UINT32 CopyOffsetBits = 0; UINT32 CopyOffsetBase = 0; UINT32 LengthOfMatchBits = 0; UINT32 LengthOfMatchBase = 0; BYTE* CopyOffsetPtr = NULL; + if (ncrush->HistoryEndOffset != 65535) + return -1; + HistoryBuffer = ncrush->HistoryBuffer; - HistoryBufferSize = ncrush->HistoryBufferSize; - HistoryBufferEnd = &HistoryBuffer[HistoryBufferSize - 1]; + HistoryBufferEnd = &HistoryBuffer[ncrush->HistoryEndOffset]; if (flags & PACKET_AT_FRONT) { + printf("PACKET_AT_FRONT\n"); + if ((ncrush->HistoryPtr - 32768) <= HistoryBuffer) return -1; - CopyMemory(HistoryBuffer, (ncrush->HistoryPtr - 32768), 32768); + MoveMemory(HistoryBuffer, (ncrush->HistoryPtr - 32768), 32768); ncrush->HistoryPtr = &(HistoryBuffer[32768]); + ZeroMemory(&HistoryBuffer[32768], 32768); } if (flags & PACKET_FLUSHED) { + printf("PACKET_FLUSHED\n"); + ncrush->HistoryPtr = HistoryBuffer; - ZeroMemory(HistoryBuffer, ncrush->HistoryBufferSize); + ZeroMemory(HistoryBuffer, sizeof(ncrush->HistoryBuffer)); ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache)); } @@ -1163,6 +1171,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (!(flags & PACKET_COMPRESSED)) { + printf("PACKET_UNCOMPRESSED\n"); + CopyMemory(HistoryPtr, pSrcData, SrcSize); HistoryPtr += SrcSize; ncrush->HistoryPtr = HistoryPtr; @@ -1203,10 +1213,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY *HistoryPtr++ = Literal; } - if (IndexLEC <= 256) - { + if (IndexLEC == 256) break; /* EOS */ - } CopyOffsetIndex = IndexLEC - 257; @@ -1238,11 +1246,11 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY Mask = *((UINT16*) &HuffTableMask[(2 * LengthOfMatchBits) + 3]); MaskedBits = bits & Mask; - LengthOfMatchBase += MaskedBits; - bits >>= LengthOfMatchBits; nbits -= LengthOfMatchBits; + LengthOfMatchBase += MaskedBits; + NCrushFetchBits(); } @@ -1288,11 +1296,11 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY Mask = *((UINT16*) &HuffTableMask[(2 * LengthOfMatchBits) + 3]); MaskedBits = bits & Mask; - LengthOfMatchBase += MaskedBits; - bits >>= LengthOfMatchBits; nbits -= LengthOfMatchBits; + LengthOfMatchBase += MaskedBits; + NCrushFetchBits(); } @@ -1305,45 +1313,70 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY CopyOffsetPtr = HistoryPtr - CopyOffset; LengthOfMatch = LengthOfMatchBase; - if ((HistoryPtr >= &HistoryBufferEnd[-LengthOfMatch]) || - (CopyOffsetPtr >= &HistoryBufferEnd[-LengthOfMatch])) - { + if (HistoryPtr >= &HistoryBufferEnd[-LengthOfMatch]) return -1; - } if (LengthOfMatch < 2) - { return -1; - } - else if (LengthOfMatch == 2) + + index = 0; + CopyLength = (LengthOfMatch > CopyOffset) ? CopyOffset : LengthOfMatch; + + if (CopyOffsetPtr >= HistoryBuffer) { - HistoryPtr[0] = CopyOffsetPtr[0]; - HistoryPtr[1] = CopyOffsetPtr[1]; - HistoryPtr += 2; - continue; - } - else - { - while (LengthOfMatch > 0) + while (CopyLength > 0) { *HistoryPtr++ = *CopyOffsetPtr++; + CopyLength--; + } + + while (LengthOfMatch > CopyOffset) + { + index = ((index >= CopyOffset)) ? 0 : index; + *HistoryPtr++ = *(CopyOffsetPtr + index++); LengthOfMatch--; } } + else + { + CopyOffsetPtr = HistoryBufferEnd - (CopyOffset - (HistoryPtr - HistoryBuffer)); + CopyOffsetPtr++; + + while (CopyLength && (CopyOffsetPtr <= HistoryBufferEnd)) + { + *HistoryPtr++ = *CopyOffsetPtr++; + CopyLength--; + } + + CopyOffsetPtr = HistoryBuffer; + + while (LengthOfMatch > CopyOffset) + { + index = ((index >= CopyOffset)) ? 0 : index; + *HistoryPtr++ = *(CopyOffsetPtr + index++); + LengthOfMatch--; + } + } + + LengthOfMatch = LengthOfMatchBase; + + if (LengthOfMatch == 2) + continue; } - if (IndexLEC == 256) - { - *pDstSize = HistoryPtr - ncrush->HistoryPtr; - *ppDstData = ncrush->HistoryPtr; - ncrush->HistoryPtr = HistoryPtr; - return 1; - } - else + if (IndexLEC != 256) + return -1; + + if (ncrush->HistoryBufferFence != 0xABABABAB) { + printf("NCrushDecompress: history buffer fence was overwritten, potential buffer overflow detected\n"); return -1; } + *pDstSize = HistoryPtr - ncrush->HistoryPtr; + *ppDstData = ncrush->HistoryPtr; + ncrush->HistoryPtr = HistoryPtr; + return 1; } @@ -1352,6 +1385,15 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE return 1; } +void ncrush_context_reset(NCRUSH_CONTEXT* ncrush) +{ + ZeroMemory(&(ncrush->HistoryBuffer), sizeof(ncrush->HistoryBuffer)); + ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache)); + + ncrush->HistoryOffset = 0; + ncrush->HistoryPtr = &(ncrush->HistoryBuffer[ncrush->HistoryOffset]); +} + NCRUSH_CONTEXT* ncrush_context_new(BOOL Compressor) { NCRUSH_CONTEXT* ncrush; @@ -1362,10 +1404,12 @@ NCRUSH_CONTEXT* ncrush_context_new(BOOL Compressor) { ncrush->Compressor = Compressor; - ncrush->HistoryBufferSize = 65536; - ZeroMemory(&(ncrush->HistoryBuffer), sizeof(ncrush->HistoryBuffer)); ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache)); + ncrush->HistoryEndOffset = 65535; + ZeroMemory(&(ncrush->HistoryBuffer), sizeof(ncrush->HistoryBuffer)); + ncrush->HistoryBufferFence = 0xABABABAB; + ncrush->HistoryOffset = 0; ncrush->HistoryPtr = &(ncrush->HistoryBuffer[ncrush->HistoryOffset]); } diff --git a/libfreerdp/core/bulk.c b/libfreerdp/core/bulk.c index 1c6a9a195..d96f55538 100644 --- a/libfreerdp/core/bulk.c +++ b/libfreerdp/core/bulk.c @@ -23,7 +23,7 @@ #include "bulk.h" -//#define WITH_BULK_DEBUG 1 +#define WITH_BULK_DEBUG 1 UINT32 bulk_compression_level(rdpBulk* bulk) { @@ -42,8 +42,6 @@ UINT32 bulk_compression_max_size(rdpBulk* bulk) int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags) { int status = -1; - UINT32 roff = 0; - UINT32 rlen = 0; UINT32 CompressedBytes; UINT32 UncompressedBytes; UINT32 type = flags & 0x0F; @@ -61,9 +59,7 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD break; case PACKET_COMPR_TYPE_RDP6: - status = decompress_rdp_6(bulk->mppc_dec, pSrcData, SrcSize, flags, &roff, &rlen); - *ppDstData = (bulk->mppc_dec->history_buf + roff); - *pDstSize = rlen; + status = ncrush_decompress(bulk->ncrushRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags); break; case PACKET_COMPR_TYPE_RDP61: @@ -91,10 +87,17 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes); TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes); - printf("Compression Ratio: %f Total: %f\n", CompressionRatio, TotalCompressionRatio); + printf("Type: %d Compression Ratio: %f Total: %f %d / %d\n", + type, CompressionRatio, TotalCompressionRatio, CompressedBytes, UncompressedBytes); } #endif } + else + { +#ifdef WITH_BULK_DEBUG + printf("Decompression failure!\n"); +#endif + } return status; } @@ -140,9 +143,7 @@ void bulk_reset(rdpBulk* bulk) { mppc_context_reset(bulk->mppcSend); mppc_context_reset(bulk->mppcRecv); - - mppc_dec_free(bulk->mppc_dec); - bulk->mppc_dec = mppc_dec_new(); + ncrush_context_reset(bulk->ncrushRecv); } rdpBulk* bulk_new(rdpContext* context) @@ -158,7 +159,7 @@ rdpBulk* bulk_new(rdpContext* context) bulk->mppcSend = mppc_context_new(1, TRUE); bulk->mppcRecv = mppc_context_new(1, FALSE); - bulk->mppc_dec = mppc_dec_new(); + bulk->ncrushRecv = ncrush_context_new(FALSE); bulk->CompressionLevel = context->settings->CompressionLevel; @@ -176,7 +177,7 @@ void bulk_free(rdpBulk* bulk) mppc_context_free(bulk->mppcSend); mppc_context_free(bulk->mppcRecv); - mppc_dec_free(bulk->mppc_dec); + ncrush_context_free(bulk->ncrushRecv); free(bulk); } diff --git a/libfreerdp/core/bulk.h b/libfreerdp/core/bulk.h index 63dffaf93..9c8a6356d 100644 --- a/libfreerdp/core/bulk.h +++ b/libfreerdp/core/bulk.h @@ -25,8 +25,7 @@ typedef struct rdp_bulk rdpBulk; #include "rdp.h" #include -#include -#include +#include struct rdp_bulk { @@ -35,8 +34,8 @@ struct rdp_bulk UINT32 CompressionMaxSize; MPPC_CONTEXT* mppcSend; MPPC_CONTEXT* mppcRecv; + NCRUSH_CONTEXT* ncrushRecv; BYTE OutputBuffer[65536]; - struct rdp_mppc_dec* mppc_dec; UINT64 TotalCompressedBytes; UINT64 TotalUncompressedBytes;