2 * Decompression routines used in RDP
3 * Copyright 2021, David Fort
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/tvbuff.h>
17 #include <epan/proto.h>
18 #include <epan/tvbuff_rdp.h>
19 #include <wsutil/array.h>
22 ZGFX_SEGMENTED_SINGLE
= 0xe0,
23 ZGFX_SEGMENTED_MULTIPART
= 0xe1,
25 ZGX_PACKET_COMPRESSED
= 0x20,
32 unsigned remainingBits
;
33 uint32_t currentValue
;
38 bitstream_init(bitstream_t
*b
, tvbuff_t
*input
, unsigned blen
) {
41 b
->remainingBits
= blen
;
47 bitstream_getbits(bitstream_t
*b
, uint8_t nbits
, bool *ok
) {
50 if (nbits
> b
->remainingBits
) {
55 while (b
->currentBits
< nbits
) {
56 if (!tvb_reported_length_remaining(b
->input
, b
->offset
)) {
61 b
->currentValue
<<= 8;
62 b
->currentValue
+= tvb_get_uint8(b
->input
, b
->offset
++);
68 ret
= b
->currentValue
>> (b
->currentBits
-nbits
);
69 b
->currentBits
-= nbits
;
70 b
->remainingBits
-= nbits
;
71 b
->currentValue
&= (1 << b
->currentBits
) - 1;
77 bitstream_copyraw(bitstream_t
*b
, uint8_t *dest
, int nbytes
)
79 if (tvb_captured_length_remaining(b
->input
, b
->offset
) < nbytes
)
82 tvb_memcpy(b
->input
, dest
, b
->offset
, nbytes
);
88 bitstream_copyraw_advance(bitstream_t
*b
, uint8_t *dest
, unsigned nbytes
)
90 if (!bitstream_copyraw(b
, dest
, nbytes
))
94 b
->remainingBits
-= (nbytes
* 8);
100 bitstream_realign(bitstream_t
*b
) {
101 b
->remainingBits
-= b
->currentBits
;
107 uint32_t prefixLength
;
113 static const zgfx_token_t ZGFX_LITERAL_TABLE
[] = {
114 // prefixLength prefixCode valueBits valueBase
115 { 5, 24, 0, 0x00 }, // 11000
116 { 5, 25, 0, 0x01 }, // 11001
117 { 6, 52, 0, 0x02 }, // 110100
118 { 6, 53, 0, 0x03 }, // 110101
119 { 6, 54, 0, 0xFF }, // 110110
120 { 7, 110, 0, 0x04 }, // 1101110
121 { 7, 111, 0, 0x05 }, // 1101111
122 { 7, 112, 0, 0x06 }, // 1110000
123 { 7, 113, 0, 0x07 }, // 1110001
124 { 7, 114, 0, 0x08 }, // 1110010
125 { 7, 115, 0, 0x09 }, // 1110011
126 { 7, 116, 0, 0x0A }, // 1110100
127 { 7, 117, 0, 0x0B }, // 1110101
128 { 7, 118, 0, 0x3A }, // 1110110
129 { 7, 119, 0, 0x3B }, // 1110111
130 { 7, 120, 0, 0x3C }, // 1111000
131 { 7, 121, 0, 0x3D }, // 1111001
132 { 7, 122, 0, 0x3E }, // 1111010
133 { 7, 123, 0, 0x3F }, // 1111011
134 { 7, 124, 0, 0x40 }, // 1111100
135 { 7, 125, 0, 0x80 }, // 1111101
136 { 8, 252, 0, 0x0C }, // 11111100
137 { 8, 253, 0, 0x38 }, // 11111101
138 { 8, 254, 0, 0x39 }, // 11111110
139 { 8, 255, 0, 0x66 }, // 11111111
142 static const zgfx_token_t ZGFX_MATCH_TABLE
[] = {
143 // prefixLength prefixCode valueBits tokenType valueBase
144 { 5, 17, 5, 0 }, // 10001
145 { 5, 18, 7, 32 }, // 10010
146 { 5, 19, 9, 160 }, // 10011
147 { 5, 20, 10, 672 }, // 10100
148 { 5, 21, 12, 1696 }, // 10101
149 { 6, 44, 14, 5792 }, // 101100
150 { 6, 45, 15, 22176 }, // 101101
151 { 7, 92, 18, 54944 }, // 1011100
152 { 7, 93, 20, 317088 }, // 1011101
153 { 8, 188, 20, 1365664 }, // 10111100
154 { 8, 189, 21, 2414240 }, // 10111101
155 { 9, 380, 22, 4511392 }, // 101111100
156 { 9, 381, 23, 8705696 }, // 101111101
157 { 9, 382, 24, 17094304 }, // 101111110
161 struct _zgfx_context_t
{
162 uint8_t historyBuffer
[2500000];
163 uint32_t historyIndex
;
164 uint32_t historyBufferSize
;
166 uint32_t outputCount
;
167 uint8_t outputSegment
[65536];
170 zgfx_context_t
*zgfx_context_new(wmem_allocator_t
*allocator
) {
171 zgfx_context_t
*ret
= wmem_alloc0(allocator
, sizeof(*ret
));
172 ret
->historyBufferSize
= sizeof(ret
->historyBuffer
);
177 zgfx_write_history_literal(zgfx_context_t
*zgfx
, uint8_t c
)
179 zgfx
->historyBuffer
[zgfx
->historyIndex
] = c
;
180 zgfx
->historyIndex
= (zgfx
->historyIndex
+ 1) % zgfx
->historyBufferSize
;
184 zgfx_write_history_buffer_tvb(zgfx_context_t
*zgfx
, tvbuff_t
*src
, uint32_t count
)
189 if (count
> zgfx
->historyBufferSize
) {
190 const uint32_t residue
= count
- zgfx
->historyBufferSize
;
191 count
= zgfx
->historyBufferSize
;
192 src_offset
+= residue
;
193 zgfx
->historyIndex
= (zgfx
->historyIndex
+ residue
) % zgfx
->historyBufferSize
;
196 if (zgfx
->historyIndex
+ count
<= zgfx
->historyBufferSize
)
198 tvb_memcpy(src
, &(zgfx
->historyBuffer
[zgfx
->historyIndex
]), src_offset
, count
);
202 front
= zgfx
->historyBufferSize
- zgfx
->historyIndex
;
203 tvb_memcpy(src
, &(zgfx
->historyBuffer
[zgfx
->historyIndex
]), src_offset
, front
);
204 tvb_memcpy(src
, &(zgfx
->historyBuffer
), src_offset
+ count
, count
- front
);
207 zgfx
->historyIndex
= (zgfx
->historyIndex
+ count
) % zgfx
->historyBufferSize
;
212 zgfx_write_history_buffer(zgfx_context_t
*zgfx
, const uint8_t *src
, uint32_t count
)
216 if (count
> zgfx
->historyBufferSize
) {
217 const uint32_t residue
= count
- zgfx
->historyBufferSize
;
218 count
= zgfx
->historyBufferSize
;
219 zgfx
->historyIndex
= (zgfx
->historyIndex
+ residue
) % zgfx
->historyBufferSize
;
222 if (zgfx
->historyIndex
+ count
<= zgfx
->historyBufferSize
)
224 memcpy(&(zgfx
->historyBuffer
[zgfx
->historyIndex
]), src
, count
);
228 front
= zgfx
->historyBufferSize
- zgfx
->historyIndex
;
229 memcpy(&(zgfx
->historyBuffer
[zgfx
->historyIndex
]), src
, front
);
230 memcpy(&(zgfx
->historyBuffer
), src
+ front
, count
- front
);
233 zgfx
->historyIndex
= (zgfx
->historyIndex
+ count
) % zgfx
->historyBufferSize
;
238 zgfx_write_literal(zgfx_context_t
*zgfx
, uint8_t c
)
240 if (zgfx
->outputCount
== 65535)
243 zgfx
->outputSegment
[zgfx
->outputCount
++] = c
;
245 zgfx_write_history_literal(zgfx
, c
);
250 zgfx_write_raw(zgfx_context_t
*zgfx
, bitstream_t
*b
, uint32_t count
)
252 uint32_t rest
, tocopy
;
254 /* first copy in the output buffer */
255 if (zgfx
->outputCount
> 65535 - count
)
258 if (!bitstream_copyraw(b
, &(zgfx
->outputSegment
[zgfx
->outputCount
]), count
))
261 zgfx
->outputCount
+= count
;
263 /* then update the history buffer */
264 rest
= (zgfx
->historyBufferSize
- zgfx
->historyIndex
);
269 if (!bitstream_copyraw_advance(b
, &(zgfx
->historyBuffer
[zgfx
->historyIndex
]), tocopy
))
272 zgfx
->historyIndex
= (zgfx
->historyIndex
+ tocopy
) % zgfx
->historyBufferSize
;
275 if (!bitstream_copyraw_advance(b
, &(zgfx
->historyBuffer
[zgfx
->historyIndex
]), tocopy
))
278 zgfx
->historyIndex
= (zgfx
->historyIndex
+ tocopy
) % zgfx
->historyBufferSize
;
285 zgfx_write_from_history(zgfx_context_t
*zgfx
, uint32_t distance
, uint32_t count
)
288 uint32_t remainingCount
, copyTemplateSize
, toCopy
;
291 if (zgfx
->outputCount
> 65535 - count
)
294 remainingCount
= count
;
295 idx
= (zgfx
->historyIndex
+ zgfx
->historyBufferSize
- distance
) % zgfx
->historyBufferSize
;
296 copyTemplateSize
= (distance
> count
) ? count
: distance
;
298 /* first do copy a single copy in output */
299 outputPtr
= &(zgfx
->outputSegment
[zgfx
->outputCount
]);
300 toCopy
= copyTemplateSize
;
301 if (idx
+ toCopy
< zgfx
->historyBufferSize
) {
302 memcpy(outputPtr
, &(zgfx
->historyBuffer
[idx
]), toCopy
);
304 uint32_t partial
= zgfx
->historyBufferSize
- idx
;
305 memcpy(outputPtr
, &(zgfx
->historyBuffer
[idx
]), partial
);
306 memcpy(outputPtr
+ partial
, zgfx
->historyBuffer
, toCopy
- partial
);
309 remainingCount
-= toCopy
;
311 /* then duplicate output as much as needed by count, at each loop turn we double
312 * the size of the template we can copy */
313 while (remainingCount
) {
314 toCopy
= (remainingCount
< copyTemplateSize
) ? remainingCount
: copyTemplateSize
;
315 memcpy(outputPtr
, &(zgfx
->outputSegment
[zgfx
->outputCount
]), toCopy
);
318 remainingCount
-= toCopy
;
319 copyTemplateSize
*= 2;
322 /* let's update the history from output and update counters */
323 zgfx_write_history_buffer(zgfx
, &(zgfx
->outputSegment
[zgfx
->outputCount
]), count
);
324 zgfx
->outputCount
+= count
;
330 rdp8_decompress_segment(zgfx_context_t
*zgfx
, tvbuff_t
*tvb
)
332 bitstream_t bitstream
;
334 int len
= tvb_reported_length(tvb
);
335 uint8_t flags
= tvb_get_uint8(tvb
, offset
);
340 if (!(flags
& ZGX_PACKET_COMPRESSED
)) {
341 tvbuff_t
*raw
= tvb_new_subset_remaining(tvb
, 1);
342 zgfx_write_history_buffer_tvb(zgfx
, raw
, len
);
344 tvb_memcpy(tvb
, zgfx
->outputSegment
, 1, len
);
345 zgfx
->outputCount
+= len
;
349 v
= tvb_get_uint8(tvb
, offset
+ len
- 1);
354 bitstream_init(&bitstream
, tvb_new_subset_length(tvb
, offset
, len
), (len
* 8) - v
);
355 while (bitstream
.remainingBits
) {
356 bool ok
, ismatch
, found
;
357 uint32_t bits_val
= bitstream_getbits(&bitstream
, 1, &ok
);
359 const zgfx_token_t
*tokens
;
369 bits_val
= bitstream_getbits(&bitstream
, 8, &ok
);
370 if (!zgfx_write_literal(zgfx
, bits_val
))
375 // 1x - match or literal branch
376 bits_val
= bitstream_getbits(&bitstream
, 1, &ok
);
380 tokens
= ZGFX_MATCH_TABLE
;
381 ntokens
= array_length(ZGFX_MATCH_TABLE
);
386 tokens
= ZGFX_LITERAL_TABLE
;
387 ntokens
= array_length(ZGFX_LITERAL_TABLE
);
393 for (i
= 0; i
< ntokens
; i
++) {
394 if (prefixBits
!= tokens
[i
].prefixLength
) {
395 uint32_t missingBits
= (tokens
[i
].prefixLength
- prefixBits
);
396 inPrefix
<<= missingBits
;
397 inPrefix
|= bitstream_getbits(&bitstream
, missingBits
, &ok
);
400 prefixBits
= tokens
[i
].prefixLength
;
403 if (inPrefix
== tokens
[i
].prefixCode
) {
409 if (!found
) // TODO: is it an error ?
414 uint32_t count
, distance
, extra
= 0;
416 distance
= tokens
[i
].valueBase
+ bitstream_getbits(&bitstream
, tokens
[i
].valueBits
, &ok
);
421 bits_val
= bitstream_getbits(&bitstream
, 1, &ok
);
431 bits_val
= bitstream_getbits(&bitstream
, 1, &ok
);
435 while (bits_val
== 1) {
438 bits_val
= bitstream_getbits(&bitstream
, 1, &ok
);
443 count
+= bitstream_getbits(&bitstream
, extra
, &ok
);
448 if (count
> sizeof(zgfx
->outputSegment
) - zgfx
->outputCount
)
451 if (!zgfx_write_from_history(zgfx
, distance
, count
))
455 count
= bitstream_getbits(&bitstream
, 15, &ok
);
459 bitstream_realign(&bitstream
);
460 if (!zgfx_write_raw(zgfx
, &bitstream
, count
))
465 bits_val
= tokens
[i
].valueBase
;
466 if (!zgfx_write_literal(zgfx
, bits_val
))
477 rdp8_decompress(zgfx_context_t
*zgfx
, wmem_allocator_t
*allocator
, tvbuff_t
*tvb
, unsigned offset
)
482 descriptor
= tvb_get_uint8(tvb
, offset
);
485 switch (descriptor
) {
486 case ZGFX_SEGMENTED_SINGLE
:
487 zgfx
->outputCount
= 0;
488 if (!rdp8_decompress_segment(zgfx
, tvb_new_subset_remaining(tvb
, offset
)))
491 output
= wmem_alloc(allocator
, zgfx
->outputCount
);
492 memcpy(output
, zgfx
->outputSegment
, zgfx
->outputCount
);
493 return tvb_new_real_data(output
, zgfx
->outputCount
, zgfx
->outputCount
);
495 case ZGFX_SEGMENTED_MULTIPART
: {
496 uint16_t segment_count
, i
;
497 uint32_t output_consumed
, uncompressed_size
;
500 segment_count
= tvb_get_uint16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
502 uncompressed_size
= tvb_get_uint32(tvb
, offset
, ENC_LITTLE_ENDIAN
);
505 output
= output_ptr
= wmem_alloc(allocator
, uncompressed_size
);
507 for (i
= 0; i
< segment_count
; i
++) {
508 uint32_t segment_size
= tvb_get_uint32(tvb
, offset
, ENC_LITTLE_ENDIAN
);
511 zgfx
->outputCount
= 0;
512 if (!rdp8_decompress_segment(zgfx
, tvb_new_subset_length(tvb
, offset
, segment_size
)))
515 output_consumed
+= zgfx
->outputCount
;
516 if (output_consumed
> uncompressed_size
) {
517 // TODO: error message ?
520 memcpy(output_ptr
, zgfx
->outputSegment
, zgfx
->outputCount
);
522 offset
+= segment_size
;
523 output_ptr
+= zgfx
->outputCount
;
525 return tvb_new_real_data(output
, uncompressed_size
, uncompressed_size
);