225 lines · python
1#!/usr/bin/env python2 3import string4import struct5import sys6 7 8class FileExtract:9 """Decode binary data from a file"""10 11 def __init__(self, f, b="="):12 """Initialize with an open binary file and optional byte order"""13 14 self.file = f15 self.byte_order = b16 self.offsets = list()17 18 def set_byte_order(self, b):19 '''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="'''20 if b == "big":21 self.byte_order = ">"22 elif b == "little":23 self.byte_order = "<"24 elif b == "swap":25 # swap what ever the current byte order is26 self.byte_order = swap_unpack_char()27 elif b == "native":28 self.byte_order = "="29 elif b == "<" or b == ">" or b == "@" or b == "=":30 self.byte_order = b31 else:32 print("error: invalid byte order specified: '%s'" % b)33 34 def is_in_memory(self):35 return False36 37 def seek(self, offset, whence=0):38 if self.file:39 return self.file.seek(offset, whence)40 raise ValueError41 42 def tell(self):43 if self.file:44 return self.file.tell()45 raise ValueError46 47 def read_size(self, byte_size):48 s = self.file.read(byte_size)49 if len(s) != byte_size:50 return None51 return s52 53 def push_offset_and_seek(self, offset):54 '''Push the current file offset and seek to "offset"'''55 self.offsets.append(self.file.tell())56 self.file.seek(offset, 0)57 58 def pop_offset_and_seek(self):59 """Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets"""60 if len(self.offsets) > 0:61 self.file.seek(self.offsets.pop())62 63 def get_sint8(self, fail_value=0):64 """Extract a single int8_t from the binary file at the current file position, returns a single integer"""65 s = self.read_size(1)66 if s:67 (v,) = struct.unpack(self.byte_order + "b", s)68 return v69 else:70 return fail_value71 72 def get_uint8(self, fail_value=0):73 """Extract a single uint8_t from the binary file at the current file position, returns a single integer"""74 s = self.read_size(1)75 if s:76 (v,) = struct.unpack(self.byte_order + "B", s)77 return v78 else:79 return fail_value80 81 def get_sint16(self, fail_value=0):82 """Extract a single int16_t from the binary file at the current file position, returns a single integer"""83 s = self.read_size(2)84 if s:85 (v,) = struct.unpack(self.byte_order + "h", s)86 return v87 else:88 return fail_value89 90 def get_uint16(self, fail_value=0):91 """Extract a single uint16_t from the binary file at the current file position, returns a single integer"""92 s = self.read_size(2)93 if s:94 (v,) = struct.unpack(self.byte_order + "H", s)95 return v96 else:97 return fail_value98 99 def get_sint32(self, fail_value=0):100 """Extract a single int32_t from the binary file at the current file position, returns a single integer"""101 s = self.read_size(4)102 if s:103 (v,) = struct.unpack(self.byte_order + "i", s)104 return v105 else:106 return fail_value107 108 def get_uint32(self, fail_value=0):109 """Extract a single uint32_t from the binary file at the current file position, returns a single integer"""110 s = self.read_size(4)111 if s:112 (v,) = struct.unpack(self.byte_order + "I", s)113 return v114 else:115 return fail_value116 117 def get_sint64(self, fail_value=0):118 """Extract a single int64_t from the binary file at the current file position, returns a single integer"""119 s = self.read_size(8)120 if s:121 (v,) = struct.unpack(self.byte_order + "q", s)122 return v123 else:124 return fail_value125 126 def get_uint64(self, fail_value=0):127 """Extract a single uint64_t from the binary file at the current file position, returns a single integer"""128 s = self.read_size(8)129 if s:130 (v,) = struct.unpack(self.byte_order + "Q", s)131 return v132 else:133 return fail_value134 135 def get_fixed_length_c_string(136 self, n, fail_value="", isprint_only_with_space_padding=False137 ):138 """Extract a single fixed length C string from the binary file at the current file position, returns a single C string"""139 s = self.read_size(n)140 if s:141 (cstr,) = struct.unpack(self.byte_order + ("%i" % n) + "s", s)142 # Strip trialing NULLs143 cstr = string.strip(cstr, "\0")144 if isprint_only_with_space_padding:145 for c in cstr:146 if c in string.printable or ord(c) == 0:147 continue148 return fail_value149 return cstr150 else:151 return fail_value152 153 def get_c_string(self):154 """Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string"""155 cstr = ""156 byte = self.get_uint8()157 while byte != 0:158 cstr += "%c" % byte159 byte = self.get_uint8()160 return cstr161 162 def get_n_sint8(self, n, fail_value=0):163 """Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers"""164 s = self.read_size(n)165 if s:166 return struct.unpack(self.byte_order + ("%u" % n) + "b", s)167 else:168 return (fail_value,) * n169 170 def get_n_uint8(self, n, fail_value=0):171 """Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers"""172 s = self.read_size(n)173 if s:174 return struct.unpack(self.byte_order + ("%u" % n) + "B", s)175 else:176 return (fail_value,) * n177 178 def get_n_sint16(self, n, fail_value=0):179 """Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers"""180 s = self.read_size(2 * n)181 if s:182 return struct.unpack(self.byte_order + ("%u" % n) + "h", s)183 else:184 return (fail_value,) * n185 186 def get_n_uint16(self, n, fail_value=0):187 """Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers"""188 s = self.read_size(2 * n)189 if s:190 return struct.unpack(self.byte_order + ("%u" % n) + "H", s)191 else:192 return (fail_value,) * n193 194 def get_n_sint32(self, n, fail_value=0):195 """Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers"""196 s = self.read_size(4 * n)197 if s:198 return struct.unpack(self.byte_order + ("%u" % n) + "i", s)199 else:200 return (fail_value,) * n201 202 def get_n_uint32(self, n, fail_value=0):203 """Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers"""204 s = self.read_size(4 * n)205 if s:206 return struct.unpack(self.byte_order + ("%u" % n) + "I", s)207 else:208 return (fail_value,) * n209 210 def get_n_sint64(self, n, fail_value=0):211 """Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers"""212 s = self.read_size(8 * n)213 if s:214 return struct.unpack(self.byte_order + ("%u" % n) + "q", s)215 else:216 return (fail_value,) * n217 218 def get_n_uint64(self, n, fail_value=0):219 """Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers"""220 s = self.read_size(8 * n)221 if s:222 return struct.unpack(self.byte_order + ("%u" % n) + "Q", s)223 else:224 return (fail_value,) * n225