def create_output_dir(outpath): if not os.path.exists(outpath): try: os.makedirs(outpath) log(create_output_dir, 'Created output path: %s' % outpath) except Exception, e: error(create_output_dir, 'Fatal', '%s' % e)
def index(ubifs, lnum, offset, inodes={}): """Walk the index gathering Inode, Dir Entry, and File nodes. Arguments: Obj:ubifs -- UBIFS object. Int:lnum -- Logical erase block number. Int:offset -- Offset in logical erase block. Dict:inodes -- Dict of ino/dent/file nodes keyed to inode number. Returns: Dict:inodes -- Dict of ino/dent/file nodes keyed to inode number. 'ino' -- Inode node. 'data' -- List of data nodes if present. 'dent' -- List of directory entry nodes if present. """ try: ubifs.file.seek((ubifs.leb_size * lnum) + offset) buf = ubifs.file.read(UBIFS_COMMON_HDR_SZ) chdr = nodes.common_hdr(buf) log(index, '%s file addr: %s' % (chdr, ubifs.file.last_read_addr())) verbose_display(chdr) node_buf = ubifs.file.read(chdr.len - UBIFS_COMMON_HDR_SZ) file_offset = ubifs.file.last_read_addr() except Exception, e: error( index, 'Fatal', 'leb: %s, ubifs offset: %s, error: %s' % (lnum, ((ubifs.leb_size * lnum) + offset), e))
def group_pairs(blocks, layout_blocks_list): """Sort a list of layout blocks into pairs Arguments: List:blocks -- List of block objects List:layout_blocks -- List of layout block indexes Returns: List -- Layout block pair indexes grouped in a list """ try: layouts_grouped = [[blocks[layout_blocks_list[0]].peb_num]] for l in layout_blocks_list[1:]: for lnd in layouts_grouped: if blocks[l].vtbl_recs[0].name == blocks[ lnd[0]].vtbl_recs[0].name: lnd.append(blocks[l].peb_num) break else: layouts_grouped.append([blocks[l].peb_num]) log(group_pairs, layouts_grouped) return layouts_grouped except Exception, e: error(group_pairs, 'Fatal', e)
def extract_blocks(ubi): """Get a list of UBI block objects from file Arguments:. Obj:ubi -- UBI object. Returns: Dict -- Of block objects keyed by PEB number. """ blocks = {} ubi.file.seek(ubi.file.start_offset) peb_count = 0 cur_offset = 0 # range instead of xrange, as xrange breaks > 4GB end_offset. for i in range(ubi.file.start_offset, ubi.file.end_offset, ubi.file.block_size): buf = ubi.file.read(ubi.file.block_size) if buf.startswith(UBI_EC_HDR_MAGIC): blk = description(buf) blk.file_offset = i blk.peb_num = ubi.first_peb_num + peb_count blk.size = ubi.file.block_size blocks[blk.peb_num] = blk peb_count += 1 log(extract_blocks, blk) verbose_log(extract_blocks, 'file addr: %s' % (ubi.file.last_read_addr())) verbose_display(blk) else: cur_offset += ubi.file.block_size ubi.first_peb_num = cur_offset/ubi.file.block_size ubi.file.start_offset = cur_offset return blocks
def index(ubifs, lnum, offset, inodes={}): """Walk the index gathering Inode, Dir Entry, and File nodes. Arguments: Obj:ubifs -- UBIFS object. Int:lnum -- Logical erase block number. Int:offset -- Offset in logical erase block. Dict:inodes -- Dict of ino/dent/file nodes keyed to inode number. Returns: Dict:inodes -- Dict of ino/dent/file nodes keyed to inode number. 'ino' -- Inode node. 'data' -- List of data nodes if present. 'dent' -- List of directory entry nodes if present. """ try: ubifs.file.seek((ubifs.leb_size * lnum) + offset) buf = ubifs.file.read(UBIFS_COMMON_HDR_SZ) chdr = nodes.common_hdr(buf) log(index , '%s file addr: %s' % (chdr, ubifs.file.last_read_addr())) verbose_display(chdr) node_buf = ubifs.file.read(chdr.len - UBIFS_COMMON_HDR_SZ) file_offset = ubifs.file.last_read_addr() except Exception, e: error(index, 'Fatal', 'buf read, %s' % (e))
def group_pairs(blocks, layout_blocks_list): """Sort a list of layout blocks into pairs Arguments: List:blocks -- List of block objects List:layout_blocks -- List of layout block indexes Returns: List -- Layout block pair indexes grouped in a list """ try: layouts_grouped = [[blocks[layout_blocks_list[0]].peb_num]] for l in layout_blocks_list[1:]: for lnd in layouts_grouped: if blocks[l].vtbl_recs[0].name == blocks[lnd[0]].vtbl_recs[0].name: lnd.append(blocks[l].peb_num) break else: layouts_grouped.append([blocks[l].peb_num]) log(group_pairs, layouts_grouped) return layouts_grouped except Exception, e: error(group_pairs, 'Fatal', e)
def __init__(self, path, block_size, start_offset=0, end_offset=None): self.__name__ = 'UBI_File' self.is_valid = False try: log(self, 'Open Path: %s' % path) self._fhandle = open(path, 'rb') except Exception, e: error(self, 'Fatal', 'Open file: %s' % e)
def __init__(self, vol_id, vol_rec, block_list): self._vol_id = vol_id self._vol_rec = vol_rec self._name = self._vol_rec.name self._block_list = block_list log( description, 'Create Volume: %s, ID: %s, Block Cnt: %s' % (self.name, self.vol_id, len(self.block_list)))
def create_output_dir(outpath): if os.path.exists(outpath): if os.listdir(outpath): error(create_output_dir, 'Fatal', 'Output directory is not empty. %s' % outpath) else: try: os.makedirs(outpath) log(create_output_dir, 'Created output path: %s' % outpath) except Exception, e: error(create_output_dir, 'Fatal', '%s' % e)
def __init__(self, blocks, layout_info): self._image_seq = blocks[layout_info[0]].ec_hdr.image_seq self.vid_hdr_offset = blocks[layout_info[0]].ec_hdr.vid_hdr_offset self.version = blocks[layout_info[0]].ec_hdr.version self._block_list = layout_info[2] self._start_peb = min(layout_info[2]) self._end_peb = max(layout_info[2]) self._volumes = get_volumes(blocks, layout_info) log( description, 'Created Image: %s, Volume Cnt: %s' % (self.image_seq, len(self.volumes)))
def guess_filetype(path, start_offset=0): with open(path, 'rb') as f: f.seek(start_offset) buf = f.read(4) if buf == UBI_EC_HDR_MAGIC: ftype = UBI_EC_HDR_MAGIC log(guess_filetype, 'File looks like a UBI image.') elif buf == UBIFS_NODE_MAGIC: ftype = UBIFS_NODE_MAGIC log(guess_filetype, 'File looks like a UBIFS image.') else: ftype = None error(guess_filetype, 'Fatal', 'Could not determine file type.') return ftype
def extract_dents(ubifs, inodes, dent_node, path='', perms=False): inode = inodes[dent_node.inum] dent_path = os.path.join(path, dent_node.name) if dent_node.type == UBIFS_ITYPE_DIR: try: if not os.path.exists(dent_path): os.mkdir(dent_path) log(extract_dents, 'Make Dir: %s' % (dent_path)) if perms: _set_file_perms(dent_path, inode) except Exception, e: error(extract_dents, 'Warn', 'DIR Fail: %s' % e) if 'dent' in inode: for dnode in inode['dent']: extract_dents(ubifs, inodes, dnode, dent_path, perms)
def __init__(self, ubifs_file): self.__name__ = 'UBIFS' self._file = ubifs_file try: self.file.reset() sb_chdr = nodes.common_hdr(self.file.read(UBIFS_COMMON_HDR_SZ)) log(self , '%s file addr: %s' % (sb_chdr, self.file.last_read_addr())) verbose_display(sb_chdr) if sb_chdr.node_type == UBIFS_SB_NODE: self.file.seek(UBIFS_COMMON_HDR_SZ) buf = self.file.read(UBIFS_SB_NODE_SZ) self._sb_node = nodes.sb_node(buf) self._min_io_size = self._sb_node.min_io_size self._leb_size = self._sb_node.leb_size log(self , '%s file addr: %s' % (self._sb_node, self.file.last_read_addr())) verbose_display(self._sb_node) else: raise Exception('Wrong node type.') except Exception, e: error(self, 'Fatal', 'Super block error: %s' % e)
def extract_blocks(ubi): """Get a list of UBI block objects from file Arguments:. Obj:ubi -- UBI object. Returns: Dict -- Of block objects keyed by PEB number. """ blocks = {} ubi.file.seek(ubi.file.start_offset) peb_count = 0 cur_offset = 0 # range instead of xrange, as xrange breaks > 4GB end_offset. for i in range(ubi.file.start_offset, ubi.file.end_offset, ubi.file.block_size): buf = ubi.file.read(ubi.file.block_size) if buf.startswith(UBI_EC_HDR_MAGIC): blk = description(buf) blk.file_offset = i blk.peb_num = ubi.first_peb_num + peb_count blk.size = ubi.file.block_size blocks[blk.peb_num] = blk peb_count += 1 log(extract_blocks, blk) verbose_log(extract_blocks, 'file addr: %s' % (ubi.file.last_read_addr())) verbose_display(blk) else: cur_offset += ubi.file.block_size ubi.first_peb_num = cur_offset / ubi.file.block_size ubi.file.start_offset = cur_offset return blocks
def __init__(self, ubifs_file): self.__name__ = 'UBIFS' self._file = ubifs_file try: self.file.reset() sb_chdr = nodes.common_hdr(self.file.read(UBIFS_COMMON_HDR_SZ)) log(self, '%s file addr: %s' % (sb_chdr, self.file.last_read_addr())) verbose_display(sb_chdr) if sb_chdr.node_type == UBIFS_SB_NODE: self.file.seek(UBIFS_COMMON_HDR_SZ) buf = self.file.read(UBIFS_SB_NODE_SZ) self._sb_node = nodes.sb_node(buf) self._min_io_size = self._sb_node.min_io_size self._leb_size = self._sb_node.leb_size log( self, '%s file addr: %s' % (self._sb_node, self.file.last_read_addr())) verbose_display(self._sb_node) else: raise Exception('Wrong node type.') except Exception, e: error(self, 'Fatal', 'Super block error: %s' % e)
buf = ubifs.file.read(UBIFS_COMMON_HDR_SZ) chdr = nodes.common_hdr(buf) log(index, '%s file addr: %s' % (chdr, ubifs.file.last_read_addr())) verbose_display(chdr) node_buf = ubifs.file.read(chdr.len - UBIFS_COMMON_HDR_SZ) file_offset = ubifs.file.last_read_addr() except Exception, e: error( index, 'Fatal', 'leb: %s, ubifs offset: %s, error: %s' % (lnum, ((ubifs.leb_size * lnum) + offset), e)) if chdr.node_type == UBIFS_IDX_NODE: idxn = nodes.idx_node(node_buf) log(index, '%s file addr: %s' % (idxn, file_offset)) verbose_display(idxn) branch_idx = 0 for branch in idxn.branches: verbose_log(index, '-------------------') log( index, '%s file addr: %s' % (branch, file_offset + UBIFS_IDX_NODE_SZ + (branch_idx * UBIFS_BRANCH_SZ))) verbose_display(branch) index(ubifs, branch.lnum, branch.offs, inodes) branch_idx += 1 elif chdr.node_type == UBIFS_INO_NODE: inon = nodes.ino_node(node_buf)
class ubi_file(object): """UBI image file object Arguments: Str:path -- Path to file to parse Int:block_size -- Erase block size of NAND in bytes. Int:start_offset -- (optional) Where to start looking in the file for UBI data. Int:end_offset -- (optional) Where to stop looking in the file. Methods: seek -- Put file head to specified byte offset. Int:offset read -- Read specified bytes from file handle. Int:size tell -- Returns byte offset of current file location. read_block -- Returns complete PEB data of provided block description. Obj:block read_block_data -- Returns LEB data only from provided block. Obj:block reader -- Generator that returns data from file. reset -- Reset file position to start_offset. is_valid -- If the object intialized okay. Handles all the actual file interactions, read, seek, extract blocks, etc. """ def __init__(self, path, block_size, start_offset=0, end_offset=None): self.__name__ = 'UBI_File' self.is_valid = False try: log(self, 'Open Path: %s' % path) self._fhandle = open(path, 'rb') except Exception, e: error(self, 'Fatal', 'Open file: %s' % e) self._fhandle.seek(0, 2) file_size = self.tell() log(self, 'File Size: %s' % file_size) self._start_offset = start_offset log(self, 'Start Offset: %s' % (self._start_offset)) if end_offset: self._end_offset = end_offset else: self._end_offset = file_size log(self, 'End Offset: %s' % (self._end_offset)) self._block_size = block_size log(self, 'Block Size: %s' % block_size) if start_offset > self._end_offset: error(self, 'Fatal', 'Start offset larger than end offset.') if end_offset > file_size: error(self, 'Fatal', 'End offset larger than file size.') self._fhandle.seek(self._start_offset) self._last_read_addr = self._fhandle.tell() self.is_valid = True
def _write_reg_file(path, data): with open(path, 'wb') as f: f.write(data) log(_write_reg_file, 'Make File: %s' % (path))
error(extract_dents, 'Warn', 'DIR Fail: %s' % e) if 'dent' in inode: for dnode in inode['dent']: extract_dents(ubifs, inodes, dnode, dent_path, perms) elif dent_node.type == UBIFS_ITYPE_REG: try: if inode['ino'].nlink > 1: if 'hlink' not in inode: inode['hlink'] = dent_path buf = _process_reg_file(ubifs, inode, dent_path) _write_reg_file(dent_path, buf) else: os.link(inode['hlink'], dent_path) log(extract_dents, 'Make Link: %s > %s' % (dent_path, inode['hlink'])) else: buf = _process_reg_file(ubifs, inode, dent_path) _write_reg_file(dent_path, buf) if perms: _set_file_perms(dent_path, inode) except Exception, e: error(extract_dents, 'Warn', 'FILE Fail: %s' % e) elif dent_node.type == UBIFS_ITYPE_LNK: try: # probably will need to decompress ino data if > UBIFS_MIN_COMPR_LEN os.symlink('%s' % inode['ino'].data, dent_path) log(extract_dents,
def __init__(self, vol_id, vol_rec, block_list): self._vol_id = vol_id self._vol_rec = vol_rec self._name = self._vol_rec.name self._block_list = block_list log(description, 'Create Volume: %s, ID: %s, Block Cnt: %s' % (self.name, self.vol_id, len(self.block_list)))
class ubifs(): """UBIFS object Arguments: Str:path -- File path to UBIFS image. Attributes: Obj:file -- File object Int:leb_size -- Size of Logical Erase Blocks. Int:min_io -- Size of min I/O from vid_hdr_offset. Obj:sb_node -- Superblock node of UBIFS image LEB0 Obj:mst_node -- Master Node of UBIFS image LEB1 Obj:mst_node2 -- Master Node 2 of UBIFS image LEB2 """ def __init__(self, ubifs_file): self.__name__ = 'UBIFS' self._file = ubifs_file try: self.file.reset() sb_chdr = nodes.common_hdr(self.file.read(UBIFS_COMMON_HDR_SZ)) log(self, '%s file addr: %s' % (sb_chdr, self.file.last_read_addr())) verbose_display(sb_chdr) if sb_chdr.node_type == UBIFS_SB_NODE: self.file.seek(UBIFS_COMMON_HDR_SZ) buf = self.file.read(UBIFS_SB_NODE_SZ) self._sb_node = nodes.sb_node(buf) self._min_io_size = self._sb_node.min_io_size self._leb_size = self._sb_node.leb_size log( self, '%s file addr: %s' % (self._sb_node, self.file.last_read_addr())) verbose_display(self._sb_node) else: raise Exception('Wrong node type.') except Exception, e: error(self, 'Fatal', 'Super block error: %s' % e) self._mst_nodes = [None, None] for i in xrange(0, 2): 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) 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) 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.') except Exception, e: error(self, 'Fatal', 'Master block %s error: %s' % (i, e))
ubifs.file.seek((ubifs.leb_size * lnum) + offset) buf = ubifs.file.read(UBIFS_COMMON_HDR_SZ) chdr = nodes.common_hdr(buf) log(index , '%s file addr: %s' % (chdr, ubifs.file.last_read_addr())) verbose_display(chdr) node_buf = ubifs.file.read(chdr.len - UBIFS_COMMON_HDR_SZ) file_offset = ubifs.file.last_read_addr() except Exception, e: error(index, 'Fatal', 'buf read, %s' % (e)) if chdr.node_type == UBIFS_IDX_NODE: idxn = nodes.idx_node(node_buf) log(index, '%s file addr: %s' % (idxn, file_offset)) verbose_display(idxn) branch_idx = 0 for branch in idxn.branches: verbose_log(index, '-------------------') log(index, '%s file addr: %s' % (branch, file_offset + UBIFS_IDX_NODE_SZ + (branch_idx * UBIFS_BRANCH_SZ))) verbose_display(branch) index(ubifs, branch.lnum, branch.offs, inodes) branch_idx += 1 elif chdr.node_type == UBIFS_INO_NODE: inon = nodes.ino_node(node_buf) ino_num = inon.key['ino_num'] log(index, '%s file addr: %s, ino num: %s' % (inon, file_offset, ino_num)) verbose_display(inon)