Velocidex/go-ntfs

LZNT1 decompress error

Closed this issue · 1 comments

image

But RtlDecompressBuffer can decompress normally.

this is my code

package main

import (
	"encoding/binary"
	"errors"
	"log"
	"os"
)

/*
Decompression support for the LZNT1 compression algorithm.

Reference:
http://msdn.microsoft.com/en-us/library/jj665697.aspx
(2.5 LZNT1 Algorithm Details)

https://github.com/libyal/reviveit/
https://github.com/sleuthkit/sleuthkit/blob/develop/tsk/fs/ntfs.c
*/

var (
	COMPRESSED_MASK = uint16(1 << 15)
	SIGNATURE_MASK  = uint16(3 << 12)
	SIZE_MASK       = uint16(1<<12) - 1

	shiftTooLargeError = errors.New(
		"Decompression error - shift is too large")
	blockTooSmallError = errors.New("Block too small!")
)

func get_displacement(offset uint16) byte {
	result := byte(0)
	for {
		if offset < 0x10 {
			return result
		}

		offset >>= 1
		result += 1
	}
}

func LZNT1Decompress(in []byte) ([]byte, error) {

	// Index into the in buffer
	i := 0
	out := []byte{}

	for {
		if len(in) < i+2 {
			break
		}
		uncompressed_chunk_offset := len(out)
		block_offset := i

		block_header := binary.LittleEndian.Uint16(in[i:])

		i += 2

		size := int(block_header & SIZE_MASK)
		block_end := block_offset + size + 3

		if size == 0 {
			break
		}

		if len(in) < i+size {
			return nil, blockTooSmallError
		}

		if block_header&COMPRESSED_MASK != 0 {
			for i < block_end {
				header := uint8(in[i])

				i++

				for mask_idx := uint8(0); mask_idx < 8 && i < block_end; mask_idx++ {
					if (header & 1) == 0 {

						out = append(out, in[i])
						i++

					} else {
						pointer := binary.LittleEndian.Uint16(in[i:])
						i += 2

						displacement := get_displacement(
							uint16(len(out) - uncompressed_chunk_offset - 1))
						symbol_offset := int(pointer>>(12-displacement)) + 1
						symbol_length := int(pointer&(0xFFF>>displacement)) + 2
						start_offset := len(out) - symbol_offset
						for j := 0; j < symbol_length+1; j++ {
							idx := start_offset + j
							if idx < 0 || idx >= len(out) {

								return out, shiftTooLargeError
							}
							out = append(out, out[idx])
						}
					}
					header >>= 1
				}
			}

			// Block is not compressed.
		} else {
			out = append(out, in[i:i+size+1]...)
			i += size + 1
		}

	}

	return out, nil
}
func main() {

	source, err := os.ReadFile("PX_dec.TXT")
	if err != nil {
		log.Fatalln(err)
	}

	result, err := LZNT1Decompress(source)
	if err != nil {
		panic(err)
	}

	if err = os.WriteFile("PXX.TXT", result, 0666); err != nil {
		log.Fatalln(err)
	}


}