Package rekall :: Package plugins :: Package filesystems :: Module lznt1
[frames] | no frames]

Source Code for Module rekall.plugins.filesystems.lznt1

  1  # Rekall Memory Forensics 
  2  # Copyright 2014 Google Inc. All Rights Reserved. 
  3  # 
  4  # Author: Michael Cohen scudette@google.com. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or (at 
  9  # your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, but 
 12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 14  # General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 19  # 
 20   
 21  """Decompression support for the LZNT1 compression algorithm. 
 22   
 23  Reference: 
 24  http://msdn.microsoft.com/en-us/library/jj665697.aspx 
 25  (2.5 LZNT1 Algorithm Details) 
 26   
 27  https://github.com/libyal/reviveit/ 
 28  https://github.com/sleuthkit/sleuthkit/blob/develop/tsk/fs/ntfs.c 
 29  """ 
 30  import array 
 31  import cStringIO 
 32  import logging 
 33  import struct 
 34   
 35   
 36   
37 -def get_displacement(offset):
38 """Calculate the displacement.""" 39 result = 0 40 while offset >= 0x10: 41 offset >>= 1 42 result += 1 43 44 return result
45 46 47 DISPLACEMENT_TABLE = array.array( 48 'B', [get_displacement(x) for x in xrange(8192)]) 49 50 COMPRESSED_MASK = 1 << 15 51 SIGNATURE_MASK = 3 << 12 52 SIZE_MASK = (1 << 12) - 1 53 TAG_MASKS = [(1 << i) for i in range(0, 8)] 54 55
56 -def decompress_data(cdata, logger=None):
57 """Decompresses the data.""" 58 59 if not logger: 60 lznt1_logger = logging.getLogger("ntfs.lznt1") 61 else: 62 lznt1_logger = logger.getChild("lznt1") 63 # Change to DEBUG to turn on module level debugging. 64 lznt1_logger.setLevel(logging.ERROR) 65 in_fd = cStringIO.StringIO(cdata) 66 output_fd = cStringIO.StringIO() 67 block_end = 0 68 69 while in_fd.tell() < len(cdata): 70 block_offset = in_fd.tell() 71 uncompressed_chunk_offset = output_fd.tell() 72 73 block_header = struct.unpack("<H", in_fd.read(2))[0] 74 lznt1_logger.debug("Header %#x @ %#x", block_header, block_offset) 75 if block_header & SIGNATURE_MASK != SIGNATURE_MASK: 76 break 77 78 size = (block_header & SIZE_MASK) 79 lznt1_logger.debug("Block size %s", size + 3) 80 81 block_end = block_offset + size + 3 82 83 if block_header & COMPRESSED_MASK: 84 while in_fd.tell() < block_end: 85 header = ord(in_fd.read(1)) 86 lznt1_logger.debug("Tag %#x", header) 87 for mask in TAG_MASKS: 88 if in_fd.tell() >= block_end: 89 break 90 91 if header & mask: 92 pointer = struct.unpack("<H", in_fd.read(2))[0] 93 displacement = DISPLACEMENT_TABLE[ 94 output_fd.tell() - uncompressed_chunk_offset - 1] 95 96 symbol_offset = (pointer >> (12 - displacement)) + 1 97 symbol_length = (pointer & (0xFFF >> displacement)) + 3 98 99 output_fd.seek(-symbol_offset, 2) 100 data = output_fd.read(symbol_length) 101 102 # Pad the data to make it fit. 103 if 0 < len(data) < symbol_length: 104 data = data * (symbol_length / len(data) + 1) 105 data = data[:symbol_length] 106 107 output_fd.seek(0, 2) 108 lznt1_logger.debug( 109 "Wrote %s @ %s/%s: Phrase %s %s %x", 110 len(data), in_fd.tell(), 111 output_fd.tell(), symbol_length, symbol_offset, 112 pointer) 113 114 output_fd.write(data) 115 116 else: 117 data = in_fd.read(1) 118 lznt1_logger.debug("Symbol %#x", ord(data)) 119 output_fd.write(data) 120 121 else: 122 # Block is not compressed 123 data = in_fd.read(size + 1) 124 output_fd.write(data) 125 126 result = output_fd.getvalue() 127 128 return result
129