diff --git a/ubireader/ubifs/__init__.py b/ubireader/ubifs/__init__.py index d8b5418..a544d13 100755 --- a/ubireader/ubifs/__init__.py +++ b/ubireader/ubifs/__init__.py @@ -21,6 +21,7 @@ from ubireader.ubifs.defines import * from ubireader.ubifs import nodes, display from typing import Optional +from zlib import crc32 class ubifs(): """UBIFS object @@ -61,23 +62,46 @@ def __init__(self, ubifs_file, master_key: Optional[bytes] = None): self._mst_nodes = [None, None] for i in range(0, 2): + s_mst_offset = self.leb_size * (UBIFS_MST_LNUM + i) + mst_offset = s_mst_offset + mst_nodes = [] try: - mst_offset = self.leb_size * (UBIFS_MST_LNUM + i) - self.file.seek(mst_offset) - mst_chdr = nodes.common_hdr(self.file.read(UBIFS_COMMON_HDR_SZ)) - log(self , '%s file addr: %s' % (mst_chdr, self.file.last_read_addr())) - verbose_display(mst_chdr) + while mst_offset < self.leb_size + s_mst_offset: + self.file.seek(mst_offset) + mst_chdr = nodes.common_hdr(self.file.read(UBIFS_COMMON_HDR_SZ)) + log(self , '%s file addr: %s' % (mst_chdr, self.file.last_read_addr())) + verbose_display(mst_chdr) + # crc + cpos = self.file.tell() + self.file.seek(mst_offset + 8) + crcdata = self.file.read(mst_chdr.len-8) + self.file.seek(cpos) + crc = (~crc32(crcdata) & 0xFFFFFFFF) + if crc != mst_chdr.crc: + break - if mst_chdr.node_type == UBIFS_MST_NODE: self.file.seek(mst_offset + UBIFS_COMMON_HDR_SZ) - buf = self.file.read(UBIFS_MST_NODE_SZ) - self._mst_nodes[i] = nodes.mst_node(buf, self.file.last_read_addr()) - log(self , '%s%s file addr: %s' % (self._mst_nodes[i], i, self.file.last_read_addr())) - verbose_display(self._mst_nodes[i]) - else: - raise Exception('Wrong node type.') + if mst_chdr.node_type == UBIFS_MST_NODE: + buf = self.file.read(UBIFS_MST_NODE_SZ) + mst_node = nodes.mst_node(buf, self.file.last_read_addr()) + mst_nodes.append(mst_node) + log(self , '%s%s file addr: %s' % (mst_node, i, self.file.last_read_addr())) + verbose_display(mst_node) + elif mst_chdr.node_type == UBIFS_PAD_NODE: + buf = self.file.read(UBIFS_PAD_NODE_SZ) + padnode = nodes.pad_node(buf, self.file.last_read_addr()) + mst_offset += padnode.pad_len + log(self , '%s%s file addr: %s' % (padnode, i, self.file.last_read_addr())) + verbose_display(padnode) + else: + raise Exception('Wrong node type.') + mst_offset += mst_chdr.len except Exception as e: error(self, 'Warn', 'Master block %s error: %s' % (i, e)) + + # Get the valid master node with the highest sequence number. + if len(mst_nodes): + self._mst_nodes[i] = max(mst_nodes, key=lambda x: x.cmt_no) if self._mst_nodes[0] is None and self._mst_nodes[1] is None: error(self, 'Fatal', 'No valid Master Node found.') diff --git a/ubireader/ubifs/display.py b/ubireader/ubifs/display.py index c7241f0..d0b423f 100644 --- a/ubireader/ubifs/display.py +++ b/ubireader/ubifs/display.py @@ -93,6 +93,14 @@ def mst_node(node, tab=''): buf += '%s%s: %r\n' % (tab, key, value) return buf +def pad_node(node, tab=''): + buf = '%s%s\n' % (tab, node) + buf += '%sFile offset: %s\n' % (tab, node.file_offset) + buf += '%s---------------------\n' % (tab) + tab += '\t' + for key, value in node: + buf += '%s%s: %r\n' % (tab, key, value) + return buf def dent_node(node, tab=''): buf = '%s%s\n' % (tab, node) diff --git a/ubireader/ubifs/nodes.py b/ubireader/ubifs/nodes.py index 321cf45..88b5023 100755 --- a/ubireader/ubifs/nodes.py +++ b/ubireader/ubifs/nodes.py @@ -293,3 +293,31 @@ def __iter__(self): def display(self, tab=''): return display.mst_node(self, tab) + +class pad_node(object): + """Get pad node at given LEB number + offset. + + Arguments: + Bin:buf -- Raw data to extract header information from. + Int:offset -- Offset in LEB of data node. + + See ubifs/defines.py for object attributes. + """ + def __init__(self, buf, file_offset=-1): + self.file_offset = file_offset + fields = dict(list(zip(UBIFS_PAD_NODE_FIELDS, struct.unpack(UBIFS_PAD_NODE_FORMAT, buf)))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __repr__(self): + return 'UBIFS Pad Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield key, getattr(self, key) + + def display(self, tab=''): + return display.pad_node(self, tab) diff --git a/ubireader/ubifs/output.py b/ubireader/ubifs/output.py index 349ef58..0058556 100755 --- a/ubireader/ubifs/output.py +++ b/ubireader/ubifs/output.py @@ -167,7 +167,9 @@ def _set_file_perms(path, inode): verbose_log(_set_file_perms, 'perms:%s, owner: %s.%s, path: %s' % (inode['ino'].mode, inode['ino'].uid, inode['ino'].gid, path)) def _set_file_timestamps(path, inode): - os.utime(path, (inode['ino'].atime_sec, inode['ino'].mtime_sec), follow_symlinks = False) + follow_symlinks = False + if os.name == 'nt': follow_symlinks = True + os.utime(path, (inode['ino'].atime_sec, inode['ino'].mtime_sec), follow_symlinks=follow_symlinks) verbose_log(_set_file_timestamps, 'timestamps: access: %s, modify: %s, path: %s' % (inode['ino'].atime_sec, inode['ino'].mtime_sec, path)) def _write_reg_file(path, data):