diff --git a/NeoBoot/ubi_reader_mips/ubi/__init__.py b/NeoBoot/ubi_reader_mips/ubi/__init__.py new file mode 100644 index 0000000..8da31e4 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/__init__.py @@ -0,0 +1,139 @@ +#!/usr/bin/python +import re +from ubi.volume import get_volumes +from ubi.block import sort, get_blocks_in_list, extract_blocks +from ubi.defines import * +from ubi import display +from ubi.image import description as image +from ubi.block import layout + +class ubi: + + def __init__(self, ubi_file): + self._file = ubi_file + self._first_peb_num = 0 + self._blocks = extract_blocks(self) + self._block_count = len(self.blocks) + if self._block_count <= 0: + raise Exception('No blocks found.') + layout_list, data_list, int_vol_list, unknown_list = sort.by_type(self.blocks) + self._layout_blocks_list = layout_list + self._data_blocks_list = data_list + self._int_vol_blocks_list = int_vol_list + self._unknown_blocks_list = unknown_list + arbitrary_block = self.blocks.itervalues().next() + self._min_io_size = arbitrary_block.ec_hdr.vid_hdr_offset + self._leb_size = self.file.block_size - arbitrary_block.ec_hdr.data_offset + layout_pairs = layout.group_pairs(self.blocks, self.layout_blocks_list) + layout_infos = layout.associate_blocks(self.blocks, layout_pairs, self.first_peb_num) + self._images = [] + for i in range(0, len(layout_infos)): + self._images.append(image(self.blocks, layout_infos[i])) + + def _get_file(self): + return self._file + + file = property(_get_file) + + def _get_images(self): + return self._images + + images = property(_get_images) + + def _get_data_blocks_list(self): + return self._data_blocks_list + + data_blocks_list = property(_get_data_blocks_list) + + def _get_layout_blocks_list(self): + return self._layout_blocks_list + + layout_blocks_list = property(_get_layout_blocks_list) + + def _get_int_vol_blocks_list(self): + return self._int_vol_blocks_list + + int_vol_blocks_list = property(_get_int_vol_blocks_list) + + def _get_unknown_blocks_list(self): + return self._unknown_blocks_list + + unknown_blocks_list = property(_get_unknown_blocks_list) + + def _get_block_count(self): + return self._block_count + + block_count = property(_get_block_count) + + def _set_first_peb_num(self, i): + self._first_peb_num = i + + def _get_first_peb_num(self): + return self._first_peb_num + + first_peb_num = property(_get_first_peb_num, _set_first_peb_num) + + def _get_leb_size(self): + return self._leb_size + + leb_size = property(_get_leb_size) + + def _get_peb_size(self): + return self.file.block_size + + peb_size = property(_get_peb_size) + + def _get_min_io_size(self): + return self._min_io_size + + min_io_size = property(_get_min_io_size) + + def _get_blocks(self): + return self._blocks + + blocks = property(_get_blocks) + + def display(self, tab = ''): + display.ubi(self, tab) + + +def get_peb_size(path): + file_offset = 0 + offsets = [] + f = open(path, 'rb') + f.seek(0, 2) + file_size = f.tell() + 1 + f.seek(0) + for i in range(0, file_size, FILE_CHUNK_SZ): + buf = f.read(FILE_CHUNK_SZ) + for m in re.finditer(UBI_EC_HDR_MAGIC, buf): + start = m.start() + if not file_offset: + file_offset = start + idx = start + else: + idx = start + file_offset + offsets.append(idx) + + file_offset += FILE_CHUNK_SZ + + f.close() + occurances = {} + for i in range(0, len(offsets)): + try: + diff = offsets[i] - offsets[i - 1] + except: + diff = offsets[i] + + if diff not in occurances: + occurances[diff] = 0 + occurances[diff] += 1 + + most_frequent = 0 + block_size = 0 + for offset in occurances: + if occurances[offset] > most_frequent: + most_frequent = occurances[offset] + block_size = offset + + return block_size \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi/__init__.pyo new file mode 100644 index 0000000..ca8b1f6 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/block/__init__.py b/NeoBoot/ubi_reader_mips/ubi/block/__init__.py new file mode 100644 index 0000000..7d8c1de --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/block/__init__.py @@ -0,0 +1,59 @@ +#!/usr/bin/python +import re +from ubi import display +from ubi.defines import * +from ubi.headers import * + +class description(object): + + def __init__(self, block_buf): + self.file_offset = -1 + self.peb_num = -1 + self.leb_num = -1 + self.size = -1 + self.vid_hdr = None + self.is_internal_vol = False + self.vtbl_recs = [] + self.ec_hdr = extract_ec_hdr(block_buf[0:UBI_EC_HDR_SZ]) + if not self.ec_hdr.errors: + self.vid_hdr = extract_vid_hdr(block_buf[self.ec_hdr.vid_hdr_offset:self.ec_hdr.vid_hdr_offset + UBI_VID_HDR_SZ]) + self.is_internal_vol = self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START + if self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START: + self.vtbl_recs = extract_vtbl_rec(block_buf[self.ec_hdr.data_offset:]) + self.leb_num = self.vid_hdr.lnum + self.is_vtbl = bool(self.vtbl_recs) or False + self.is_valid = not self.ec_hdr.errors and not self.vid_hdr.errors + return + + def __repr__(self): + return 'Block: PEB# %s: LEB# %s' % (self.peb_num, self.leb_num) + + def display(self, tab = ''): + display.block(self, tab) + + +def get_blocks_in_list(blocks, idx_list): + return {i:blocks[i] for i in idx_list} + + +def extract_blocks(ubi): + blocks = {} + start_peb = 0 + ubi.file.seek(ubi.file.start_offset) + peb_count = 0 + cur_offset = 0 + 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 + 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 \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/block/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi/block/__init__.pyo new file mode 100644 index 0000000..4865745 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/block/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/block/layout.py b/NeoBoot/ubi_reader_mips/ubi/block/layout.py new file mode 100644 index 0000000..d2f95de --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/block/layout.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +from ubi.block import sort + +def group_pairs(blocks, layout_blocks_list): + 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]) + + return layouts_grouped + + +def associate_blocks(blocks, layout_pairs, start_peb_num): + seq_blocks = [] + for layout_pair in layout_pairs: + seq_blocks = sort.by_image_seq(blocks, blocks[layout_pair[0]].ec_hdr.image_seq) + layout_pair.append(seq_blocks) + + return layout_pairs \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/block/layout.pyo b/NeoBoot/ubi_reader_mips/ubi/block/layout.pyo new file mode 100644 index 0000000..ef9d325 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/block/layout.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/block/sort.py b/NeoBoot/ubi_reader_mips/ubi/block/sort.py new file mode 100644 index 0000000..6687f9e --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/block/sort.py @@ -0,0 +1,84 @@ +#!/usr/bin/python +def list_by_list(blist, slist): + slist_blocks = [] + for block in blist: + if block in slist: + slist_blocks.append(block) + + return slist_blocks + + +def by_image_seq(blocks, image_seq): + seq_blocks = [] + for block in blocks: + if blocks[block].ec_hdr.image_seq == image_seq: + seq_blocks.append(block) + + return seq_blocks + + +def by_range(blocks, block_range): + peb_range = range(block_range[0], block_range[1]) + return [ i for i in blocks if i in peb_range ] + + +def by_leb(blocks): + slist_len = len(blocks) + slist = ['x'] * slist_len + for block in blocks: + if blocks[block].leb_num >= slist_len: + add_elements = blocks[block].leb_num - slist_len + 1 + slist += ['x'] * add_elements + slist_len = len(slist) + slist[blocks[block].leb_num] = block + + return slist + return sorted(blocks.iterkeys(), key=lambda x: blocks[x].leb_num) + + +def by_vol_id(blocks, slist = None): + vol_blocks = {} + for i in blocks: + if slist and i not in slist: + continue + elif not blocks[i].is_valid: + continue + if blocks[i].vid_hdr.vol_id not in vol_blocks: + vol_blocks[blocks[i].vid_hdr.vol_id] = [] + vol_blocks[blocks[i].vid_hdr.vol_id].append(blocks[i].peb_num) + + return vol_blocks + + +def clean_bad(blocks, slist = None): + clean_blocks = [] + for i in range(0, len(blocks)): + if slist and i not in slist: + continue + if blocks[i].is_valid: + clean_blocks.append(i) + + return clean_blocks + + +def by_type(blocks, slist = None): + layout = [] + data = [] + int_vol = [] + unknown = [] + for i in blocks: + if slist and i not in slist: + continue + if blocks[i].is_vtbl and blocks[i].is_valid: + layout.append(i) + elif blocks[i].is_internal_vol and blocks[i].is_valid: + int_vol.append(i) + elif blocks[i].is_valid: + data.append(i) + else: + unknown.append(i) + + return (layout, + data, + int_vol, + unknown) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/block/sort.pyo b/NeoBoot/ubi_reader_mips/ubi/block/sort.pyo new file mode 100644 index 0000000..4177c9e Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/block/sort.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/defines.py b/NeoBoot/ubi_reader_mips/ubi/defines.py new file mode 100644 index 0000000..668b197 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/defines.py @@ -0,0 +1,63 @@ +#!/usr/bin/python +import struct +UBI_CRC32_INIT = 4294967295L +UBI_MAX_VOLUMES = 128 +UBI_INTERNAL_VOL_START = 2147479551 +UBI_EC_HDR_MAGIC = 'UBI#' +EC_HDR_FORMAT = '>4sB3sQIII32sI' +EC_HDR_FIELDS = ['magic', + 'version', + 'padding', + 'ec', + 'vid_hdr_offset', + 'data_offset', + 'image_seq', + 'padding2', + 'hdr_crc'] +UBI_EC_HDR_SZ = struct.calcsize(EC_HDR_FORMAT) +UBI_VID_HDR_MAGIC = 'UBI!' +VID_HDR_FORMAT = '>4sBBBBII4sIIII4sQ12sI' +VID_HDR_FIELDS = ['magic', + 'version', + 'vol_type', + 'copy_flag', + 'compat', + 'vol_id', + 'lnum', + 'padding', + 'data_size', + 'used_ebs', + 'data_pad', + 'data_crc', + 'padding2', + 'sqnum', + 'padding3', + 'hdr_crc'] +UBI_VID_HDR_SZ = struct.calcsize(VID_HDR_FORMAT) +VTBL_REC_FORMAT = '>IIIBBH128sB23sI' +VTBL_REC_FIELDS = ['reserved_pebs', + 'alignment', + 'data_pad', + 'vol_type', + 'upd_marker', + 'name_len', + 'name', + 'flags', + 'padding', + 'crc'] +UBI_VTBL_REC_SZ = struct.calcsize(VTBL_REC_FORMAT) +UBI_VID_DYNAMIC = 1 +UBI_VID_STATIC = 2 +PRINT_VOL_TYPE_LIST = [0, 'dynamic', 'static'] +UBI_VTBL_AUTORESIZE_FLG = 1 +UBI_COMPAT_DELETE = 1 +UBI_COMPAT_RO = 2 +UBI_COMPAT_PRESERVE = 4 +UBI_COMPAT_REJECT = 5 +PRINT_COMPAT_LIST = [0, + 'Delete', + 'Read Only', + 0, + 'Preserve', + 'Reject'] +FILE_CHUNK_SZ = 5242880 \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/defines.pyo b/NeoBoot/ubi_reader_mips/ubi/defines.pyo new file mode 100644 index 0000000..50e1217 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/defines.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/display.py b/NeoBoot/ubi_reader_mips/ubi/display.py new file mode 100644 index 0000000..8081041 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/display.py @@ -0,0 +1,108 @@ +#!/usr/bin/python +from ubi.defines import PRINT_COMPAT_LIST, PRINT_VOL_TYPE_LIST, UBI_VTBL_AUTORESIZE_FLG + +def ubi(ubi, tab = ''): + print '%sUBI File' % tab + print '%s---------------------' % tab + print '\t%sMin I/O: %s' % (tab, ubi.min_io_size) + print '\t%sLEB Size: %s' % (tab, ubi.leb_size) + print '\t%sPEB Size: %s' % (tab, ubi.peb_size) + print '\t%sTotal Block Count: %s' % (tab, ubi.block_count) + print '\t%sData Block Count: %s' % (tab, len(ubi.data_blocks_list)) + print '\t%sLayout Block Count: %s' % (tab, len(ubi.layout_blocks_list)) + print '\t%sInternal Volume Block Count: %s' % (tab, len(ubi.int_vol_blocks_list)) + print '\t%sUnknown Block Count: %s' % (tab, len(ubi.unknown_blocks_list)) + print '\t%sFirst UBI PEB Number: %s' % (tab, ubi.first_peb_num) + + +def image(image, tab = ''): + print '%s%s' % (tab, image) + print '%s---------------------' % tab + print '\t%sImage Sequence Num: %s' % (tab, image.image_seq) + for volume in image.volumes: + print '\t%sVolume Name:%s' % (tab, volume) + + print '\t%sPEB Range: %s - %s' % (tab, image.peb_range[0], image.peb_range[1]) + + +def volume(volume, tab = ''): + print '%s%s' % (tab, volume) + print '%s---------------------' % tab + print '\t%sVol ID: %s' % (tab, volume.vol_id) + print '\t%sName: %s' % (tab, volume.name) + print '\t%sBlock Count: %s' % (tab, volume.block_count) + print '\n' + print '\t%sVolume Record' % tab + print '\t%s---------------------' % tab + vol_rec(volume.vol_rec, '\t\t%s' % tab) + print '\n' + + +def block(block, tab = '\t'): + print '%s%s' % (tab, block) + print '%s---------------------' % tab + print '\t%sFile Offset: %s' % (tab, block.file_offset) + print '\t%sPEB #: %s' % (tab, block.peb_num) + print '\t%sLEB #: %s' % (tab, block.leb_num) + print '\t%sBlock Size: %s' % (tab, block.size) + print '\t%sInternal Volume: %s' % (tab, block.is_internal_vol) + print '\t%sIs Volume Table: %s' % (tab, block.is_vtbl) + print '\t%sIs Valid: %s' % (tab, block.is_valid) + if not block.ec_hdr.errors: + print '\n' + print '\t%sErase Count Header' % tab + print '\t%s---------------------' % tab + ec_hdr(block.ec_hdr, '\t\t%s' % tab) + if block.vid_hdr and not block.vid_hdr.errors: + print '\n' + print '\t%sVID Header Header' % tab + print '\t%s---------------------' % tab + vid_hdr(block.vid_hdr, '\t\t%s' % tab) + if block.vtbl_recs: + print '\n' + print '\t%sVolume Records' % tab + print '\t%s---------------------' % tab + for vol in block.vtbl_recs: + vol_rec(vol, '\t\t%s' % tab) + + print '\n' + + +def ec_hdr(ec_hdr, tab = ''): + for key, value in ec_hdr: + if key == 'errors': + value = ','.join(value) + print '%s%s: %r' % (tab, key, value) + + +def vid_hdr(vid_hdr, tab = ''): + for key, value in vid_hdr: + if key == 'errors': + value = ','.join(value) + elif key == 'compat': + if value in PRINT_COMPAT_LIST: + value = PRINT_COMPAT_LIST[value] + else: + value = -1 + elif key == 'vol_type': + if value < len(PRINT_VOL_TYPE_LIST): + value = PRINT_VOL_TYPE_LIST[value] + else: + value = -1 + print '%s%s: %s' % (tab, key, value) + + +def vol_rec(vol_rec, tab = ''): + for key, value in vol_rec: + if key == 'errors': + value = ','.join(value) + elif key == 'vol_type': + if value < len(PRINT_VOL_TYPE_LIST): + value = PRINT_VOL_TYPE_LIST[value] + else: + value = -1 + elif key == 'flags' and value == UBI_VTBL_AUTORESIZE_FLG: + value = 'autoresize' + elif key == 'name': + value = value.strip('\x00') + print '%s%s: %s' % (tab, key, value) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/display.pyo b/NeoBoot/ubi_reader_mips/ubi/display.pyo new file mode 100644 index 0000000..386ba36 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/display.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/headers/__init__.py b/NeoBoot/ubi_reader_mips/ubi/headers/__init__.py new file mode 100644 index 0000000..474a369 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/headers/__init__.py @@ -0,0 +1,89 @@ +#!/usr/bin/python +import struct +from ubi.defines import * +from ubi.headers import errors + +class ec_hdr(object): + + def __init__(self, buf): + fields = dict(zip(EC_HDR_FIELDS, struct.unpack(EC_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __repr__(self): + return 'Error Count Header' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class vid_hdr(object): + + def __init__(self, buf): + fields = dict(zip(VID_HDR_FIELDS, struct.unpack(VID_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + def __repr__(self): + return 'VID Header' + + +class vtbl_rec(object): + + def __init__(self, buf): + fields = dict(zip(VTBL_REC_FIELDS, struct.unpack(VTBL_REC_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + setattr(self, 'rec_index', -1) + + def __repr__(self): + return 'Volume Table Record: %s' % getattr(self, 'name') + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +def extract_ec_hdr(buf): + ec_hdr_buf = buf + ec_hdr_ret = ec_hdr(ec_hdr_buf) + errors.ec_hdr(ec_hdr_ret, ec_hdr_buf) + return ec_hdr_ret + + +def extract_vid_hdr(buf): + vid_hdr_buf = buf + vid_hdr_ret = vid_hdr(vid_hdr_buf) + errors.vid_hdr(vid_hdr_ret, vid_hdr_buf) + return vid_hdr_ret + + +def extract_vtbl_rec(buf): + data_buf = buf + vtbl_recs = [] + vtbl_rec_ret = '' + for i in range(0, UBI_MAX_VOLUMES): + offset = i * UBI_VTBL_REC_SZ + vtbl_rec_buf = data_buf[offset:offset + UBI_VTBL_REC_SZ] + if len(vtbl_rec_buf) == UBI_VTBL_REC_SZ: + vtbl_rec_ret = vtbl_rec(vtbl_rec_buf) + errors.vtbl_rec(vtbl_rec_ret, vtbl_rec_buf) + if len(vtbl_rec_ret.errors) == 0: + vtbl_rec_ret.rec_index = i + vtbl_recs.append(vtbl_rec_ret) + + return vtbl_recs \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/headers/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi/headers/__init__.pyo new file mode 100644 index 0000000..f68e6bf Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/headers/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/headers/errors.py b/NeoBoot/ubi_reader_mips/ubi/headers/errors.py new file mode 100644 index 0000000..eee0ebd --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/headers/errors.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +from zlib import crc32 +from ubi.defines import * + +def ec_hdr(ec_hdr, buf): + if ec_hdr.hdr_crc != ~crc32(buf[:-4]) & 4294967295L: + ec_hdr.errors.append('crc') + return ec_hdr + + +def vid_hdr(vid_hdr, buf): + vid_hdr.errors = [] + if vid_hdr.hdr_crc != ~crc32(buf[:-4]) & 4294967295L: + vid_hdr.errors.append('crc') + return vid_hdr + + +def vtbl_rec(vtbl_rec, buf): + likely_vtbl = True + if vtbl_rec.name_len != len(vtbl_rec.name.strip('\x00')): + likely_vtbl = False + elif vtbl_rec.vol_type not in (1, 2): + likely_vtbl = False + if vtbl_rec.crc != ~crc32(buf[:-4]) & 4294967295L: + vtbl_rec.errors.append('crc') + if not likely_vtbl: + vtbl_rec.errors = ['False'] + return vtbl_rec \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/headers/errors.pyo b/NeoBoot/ubi_reader_mips/ubi/headers/errors.pyo new file mode 100644 index 0000000..2e17fb5 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/headers/errors.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/image.py b/NeoBoot/ubi_reader_mips/ubi/image.py new file mode 100644 index 0000000..b613ce4 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/image.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +from ubi import display +from ubi.volume import get_volumes +from ubi.block import get_blocks_in_list + +class description(object): + + 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._start_peb = min(layout_info[2]) + self._end_peb = max(layout_info[2]) + self._volumes = get_volumes(blocks, layout_info) + + def __repr__(self): + return 'Image: %s' % self.image_seq + + def get_blocks(self, blocks): + return get_blocks_in_list(blocks, range(self._start_peb, self._end_peb + 1)) + + def _get_peb_range(self): + return [self._start_peb, self._end_peb] + + peb_range = property(_get_peb_range) + + def _get_image_seq(self): + return self._image_seq + + image_seq = property(_get_image_seq) + + def _get_volumes(self): + return self._volumes + + volumes = property(_get_volumes) + + def display(self, tab = ''): + display.image(self, tab) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/image.pyo b/NeoBoot/ubi_reader_mips/ubi/image.pyo new file mode 100644 index 0000000..9c30e20 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/image.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi/volume/__init__.py b/NeoBoot/ubi_reader_mips/ubi/volume/__init__.py new file mode 100644 index 0000000..70d3e76 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/volume/__init__.py @@ -0,0 +1,67 @@ +#!/usr/bin/python +from ubi import display +from ubi.block import sort, get_blocks_in_list + +class description(object): + + 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 + + def __repr__(self): + return 'Volume: %s' % self.name + + def _get_name(self): + return self._name + + name = property(_get_name) + + def _get_vol_id(self): + return self._vol_id + + vol_id = property(_get_vol_id) + + def _get_block_count(self): + return len(self._block_list) + + block_count = property(_get_block_count) + + def _get_vol_rec(self): + return self._vol_rec + + vol_rec = property(_get_vol_rec) + + def _get_block_list(self): + return self._block_list + + block_list = property(_get_block_list) + + def get_blocks(self, blocks): + return get_blocks_in_list(blocks, self._block_list) + + def display(self, tab = ''): + display.volume(self, tab) + + def reader(self, ubi): + last_leb = 0 + for block in sort.by_leb(self.get_blocks(ubi.blocks)): + if block == 'x': + last_leb += 1 + yield '\xff' * ubi.leb_size + else: + last_leb += 1 + yield ubi.file.read_block_data(ubi.blocks[block]) + + +def get_volumes(blocks, layout_info): + volumes = {} + vol_blocks_lists = sort.by_vol_id(blocks, layout_info[2]) + for vol_rec in blocks[layout_info[0]].vtbl_recs: + vol_name = vol_rec.name.strip('\x00') + if vol_rec.rec_index not in vol_blocks_lists: + vol_blocks_lists[vol_rec.rec_index] = [] + volumes[vol_name] = description(vol_rec.rec_index, vol_rec, vol_blocks_lists[vol_rec.rec_index]) + + return volumes \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/volume/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi/volume/__init__.pyo new file mode 100644 index 0000000..07e0814 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi/volume/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubi_extract_files.py b/NeoBoot/ubi_reader_mips/ubi_extract_files.py new file mode 100644 index 0000000..154454d --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi_extract_files.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +import os +import sys +import argparse +from ubi import ubi, get_peb_size +from ubifs import ubifs +from ubi_io import ubi_file, leb_virtual_file +from ui.common import extract_files, output_dir +if __name__ == '__main__': + description = 'Extract contents of UBI image.' + usage = 'ubi_extract_files.py [options] filepath' + parser = argparse.ArgumentParser(usage=usage, description=description) + parser.add_argument('-l', '--log-file', dest='logpath', help='Log output to file output/LOGPATH. (default: ubifs_output.log)') + parser.add_argument('-k', '--keep-permissions', action='store_true', dest='permissions', help='Maintain file permissions, requires running as root. (default: False)') + parser.add_argument('-q', '--quiet', action='store_true', dest='quiet', help='Suppress warnings and non-fatal errors. (default: False)') + parser.add_argument('-p', '--peb-size', type=int, dest='block_size', help='Specify PEB size.') + parser.add_argument('-o', '--output-dir', dest='output_path', help='Specify output directory path.') + parser.add_argument('filepath', help='File to extract contents of.') + if len(sys.argv) == 1: + parser.print_help() + sys.exit() + args = parser.parse_args() + if args.filepath: + path = args.filepath + if not os.path.exists(path): + parser.error("File path doesn't exist.") + if args.output_path: + output_path = args.output_path + else: + img_name = os.path.splitext(os.path.basename(path))[0] + output_path = os.path.join(output_dir, img_name) + if args.logpath: + log_to_file = True + log_file = args.logpath + else: + log_to_file = None + log_file = None + if args.block_size: + block_size = args.block_size + else: + block_size = get_peb_size(path) + perms = args.permissions + quiet = args.quiet + if not os.path.exists(output_path): + os.makedirs(output_path) + ufile = ubi_file(path, block_size) + uubi = ubi(ufile) + for image in uubi.images: + for volume in image.volumes: + vol_out_path = os.path.join(output_path, volume) + if not os.path.exists(vol_out_path): + os.makedirs(vol_out_path) + elif os.listdir(vol_out_path): + parser.error('Volume output directory is not empty. %s' % vol_out_path) + ufsfile = leb_virtual_file(uubi, image.volumes[volume]) + uubifs = ubifs(ufsfile) + uubifs.log.log_file = log_file + uubifs.log.log_to_file = log_to_file + uubifs.log.quiet = quiet + print 'Writing to: %s' % vol_out_path + extract_files(uubifs, vol_out_path, perms) + + sys.exit(0) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi_io/__init__.py b/NeoBoot/ubi_reader_mips/ubi_io/__init__.py new file mode 100644 index 0000000..9f3bd62 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi_io/__init__.py @@ -0,0 +1,116 @@ +#!/usr/bin/python +from ubi.block import sort + +class ubi_file(object): + + def __init__(self, path, block_size, start_offset = 0, end_offset = None): + self._fhandle = open(path, 'rb') + self._start_offset = start_offset + if end_offset: + self._end_offset = end_offset + else: + self._fhandle.seek(0, 2) + self._end_offset = self.tell() + self._block_size = block_size + if start_offset >= self._end_offset: + raise Exception('Start offset larger than file size!') + self._fhandle.seek(self._start_offset) + + def _set_start(self, i): + self._start_offset = i + + def _get_start(self): + return self._start_offset + + start_offset = property(_get_start, _set_start) + + def _get_end(self): + return self._end_offset + + end_offset = property(_get_end) + + def _get_block_size(self): + return self._block_size + + block_size = property(_get_block_size) + + def seek(self, offset): + self._fhandle.seek(offset) + + def read(self, size): + return self._fhandle.read(size) + + def tell(self): + return self._fhandle.tell() + + def reset(self): + self._fhandle.seek(self.start_offset) + + def reader(self): + self.reset() + while True: + cur_loc = self._fhandle.tell() + if self.end_offset and cur_loc > self.end_offset: + break + elif self.end_offset and self.end_offset - cur_loc < self.block_size: + chunk_size = self.end_offset - cur_loc + else: + chunk_size = self.block_size + buf = self.read(chunk_size) + if not buf: + break + yield buf + + def read_block(self, block): + self.seek(block.file_offset) + return self._fhandle.read(block.size) + + def read_block_data(self, block): + self.seek(block.file_offset + block.ec_hdr.data_offset) + buf = self._fhandle.read(block.size - block.ec_hdr.data_offset - block.vid_hdr.data_pad) + return buf + + +class leb_virtual_file: + + def __init__(self, ubi, volume): + self._ubi = ubi + self._volume = volume + self._blocks = sort.by_leb(self._volume.get_blocks(self._ubi.blocks)) + self._seek = 0 + self.leb_data_size = len(self._blocks) * self._ubi.leb_size + self._last_leb = -1 + self._last_buf = '' + + def read(self, i): + buf = '' + leb = int(self.tell() / self._ubi.leb_size) + offset = self.tell() % self._ubi.leb_size + if leb == self._last_leb: + self.seek(self.tell() + i) + return self._last_buf[offset:offset + i] + else: + buf = self._ubi.file.read_block_data(self._ubi.blocks[self._blocks[leb]]) + self._last_buf = buf + self._last_leb = leb + self.seek(self.tell() + i) + return buf[offset:offset + i] + + def reset(self): + self.seek(0) + + def seek(self, offset): + self._seek = offset + + def tell(self): + return self._seek + + def reader(self): + last_leb = 0 + for block in self._blocks: + while 0 != self._ubi.blocks[block].leb_num - last_leb: + last_leb += 1 + yield '\xff' * self._ubi.leb_size + + last_leb += 1 + yield self._ubi.file.read_block_data(self._ubi.blocks[block]) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi_io/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi_io/__init__.pyo new file mode 100644 index 0000000..439d3b9 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubi_io/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubifs/__init__.py b/NeoBoot/ubi_reader_mips/ubifs/__init__.py new file mode 100644 index 0000000..05774c3 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/__init__.py @@ -0,0 +1,76 @@ +#!/usr/bin/python +import re +import struct +from ubifs.defines import * +from ubifs import nodes +from ubifs.nodes import extract +from ubifs.log import log + +class ubifs: + + def __init__(self, ubifs_file): + self.log = log() + self._file = ubifs_file + self._sb_node = extract.sb_node(self, UBIFS_COMMON_HDR_SZ) + self._min_io_size = self._sb_node.min_io_size + self._leb_size = self._sb_node.leb_size + self._mst_node = extract.mst_node(self, 1, UBIFS_COMMON_HDR_SZ) + self._mst_node = extract.mst_node(self, 2, UBIFS_COMMON_HDR_SZ) + + def _get_file(self): + return self._file + + file = property(_get_file) + + def _get_superblock(self): + return self._sb_node + + superblock_node = property(_get_superblock) + + def _get_master_node(self): + return self._mst_node + + master_node = property(_get_master_node) + + def _get_master_node2(self): + return self._mst_node + + master_node2 = property(_get_master_node2) + + def _get_leb_size(self): + return self._leb_size + + leb_size = property(_get_leb_size) + + def _get_min_io_size(self): + return self._min_io_size + + min_io_size = property(_get_min_io_size) + + +def get_leb_size(path): + f = open(path, 'rb') + f.seek(0, 2) + file_size = f.tell() + 1 + f.seek(0) + block_size = 0 + for i in range(0, file_size, FILE_CHUNK_SZ): + buf = f.read(FILE_CHUNK_SZ) + for m in re.finditer(UBIFS_NODE_MAGIC, buf): + start = m.start() + chdr = nodes.common_hdr(buf[start:start + UBIFS_COMMON_HDR_SZ]) + if chdr and chdr.node_type == UBIFS_SB_NODE: + sb_start = start + UBIFS_COMMON_HDR_SZ + sb_end = sb_start + UBIFS_SB_NODE_SZ + if chdr.len != len(buf[sb_start:sb_end]): + f.seek(sb_start) + buf = f.read(UBIFS_SB_NODE_SZ) + else: + buf = buf[sb_start:sb_end] + sbn = nodes.sb_node(buf) + block_size = sbn.leb_size + f.close() + return block_size + + f.close() + return block_size \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/__init__.pyo b/NeoBoot/ubi_reader_mips/ubifs/__init__.pyo new file mode 100644 index 0000000..195d726 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubifs/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubifs/defines.py b/NeoBoot/ubi_reader_mips/ubifs/defines.py new file mode 100644 index 0000000..a0b3aa9 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/defines.py @@ -0,0 +1,221 @@ +#!/usr/bin/python +import struct +UBIFS_NODE_MAGIC = '1\x18\x10\x06' +UBIFS_CRC32_INIT = 4294967295L +UBIFS_MIN_COMPR_LEN = 128 +UBIFS_MIN_COMPRESS_DIFF = 64 +UBIFS_ROOT_INO = 1 +UBIFS_FIRST_INO = 64 +UBIFS_MAX_NLEN = 255 +UBIFS_MAX_JHEADS = 1 +UBIFS_BLOCK_SIZE = 4096 +UBIFS_BLOCK_SHIFT = 12 +UBIFS_PADDING_BYTE = '\xce' +UBIFS_MAX_KEY_LEN = 16 +UBIFS_SK_LEN = 8 +UBIFS_MIN_FANOUT = 3 +UBIFS_MAX_LEVELS = 512 +UBIFS_MAX_INO_DATA = UBIFS_BLOCK_SIZE +UBIFS_LPT_FANOUT = 4 +UBIFS_LPT_FANOUT_SHIFT = 2 +UBIFS_LPT_CRC_BITS = 16 +UBIFS_LPT_CRC_BYTES = 2 +UBIFS_LPT_TYPE_BITS = 4 +UBIFS_LPT_PNODE = 0 +UBIFS_LPT_NNODE = 1 +UBIFS_LPT_LTAB = 2 +UBIFS_LPT_LSAVE = 3 +UBIFS_LPT_NODE_CNT = 4 +UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1 +UBIFS_ITYPE_REG = 0 +UBIFS_ITYPE_DIR = 1 +UBIFS_ITYPE_LNK = 2 +UBIFS_ITYPE_BLK = 3 +UBIFS_ITYPE_CHR = 4 +UBIFS_ITYPE_FIFO = 5 +UBIFS_ITYPE_SOCK = 6 +UBIFS_ITYPES_CNT = 7 +UBIFS_KEY_HASH_R5 = 0 +UBIFS_KEY_HASH_TEST = 1 +PRINT_UBIFS_KEY_HASH = ['r5', 'test'] +UBIFS_SIMPLE_KEY_FMT = 0 +UBIFS_S_KEY_BLOCK_BITS = 29 +UBIFS_S_KEY_BLOCK_MASK = 536870911 +UBIFS_S_KEY_HASH_BITS = UBIFS_S_KEY_BLOCK_BITS +UBIFS_S_KEY_HASH_MASK = UBIFS_S_KEY_BLOCK_MASK +UBIFS_INO_KEY = 0 +UBIFS_DATA_KEY = 1 +UBIFS_DENT_KEY = 2 +UBIFS_XENT_KEY = 3 +UBIFS_KEY_TYPES_CNT = 4 +UBIFS_SB_LEBS = 1 +UBIFS_MST_LEBS = 2 +UBIFS_SB_LNUM = 0 +UBIFS_MST_LNUM = UBIFS_SB_LNUM + UBIFS_SB_LEBS +UBIFS_LOG_LNUM = UBIFS_MST_LNUM + UBIFS_MST_LEBS +UBIFS_COMPR_FL = 1 +UBIFS_SYNC_FL = 2 +UBIFS_IMMUTABLE_FL = 4 +UBIFS_APPEND_FL = 8 +UBIFS_DIRSYNC_FL = 16 +UBIFS_XATTR_FL = 32 +UBIFS_FL_MASK = 31 +UBIFS_COMPR_NONE = 0 +UBIFS_COMPR_LZO = 1 +UBIFS_COMPR_ZLIB = 2 +UBIFS_COMPR_TYPES_CNT = 3 +PRINT_UBIFS_COMPR = ['none', 'lzo', 'zlib'] +UBIFS_INO_NODE = 0 +UBIFS_DATA_NODE = 1 +UBIFS_DENT_NODE = 2 +UBIFS_XENT_NODE = 3 +UBIFS_TRUN_NODE = 4 +UBIFS_PAD_NODE = 5 +UBIFS_SB_NODE = 6 +UBIFS_MST_NODE = 7 +UBIFS_REF_NODE = 8 +UBIFS_IDX_NODE = 9 +UBIFS_CS_NODE = 10 +UBIFS_ORPH_NODE = 11 +UBIFS_NODE_TYPES_CNT = 12 +UBIFS_MST_DIRTY = 1 +UBIFS_MST_NO_ORPHS = 2 +UBIFS_MST_RCVRY = 4 +UBIFS_NO_NODE_GROUP = 0 +UBIFS_IN_NODE_GROUP = 1 +UBIFS_LAST_OF_NODE_GROUP = 2 +UBIFS_FLG_BIGLPT = 2 +UBIFS_FLG_SPACE_FIXUP = 4 +UBIFS_COMMON_HDR_FORMAT = '> UBIFS_S_KEY_BLOCK_BITS + khash = lkey + return {'type': key_type, + 'ino_num': ino_num, + 'khash': khash} + + +def decompress(ctype, unc_len, data): + if ctype == UBIFS_COMPR_LZO: + return lzo.decompress(''.join(('\xf0', struct.pack('>I', unc_len), data))) + elif ctype == UBIFS_COMPR_ZLIB: + return zlib.decompress(data, -11) + else: + return data \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/misc.pyo b/NeoBoot/ubi_reader_mips/ubifs/misc.pyo new file mode 100644 index 0000000..85af7ad Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubifs/misc.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.py b/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.py new file mode 100644 index 0000000..d2b3346 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.py @@ -0,0 +1,151 @@ +#!/usr/bin/python +import struct +from ubifs.defines import * +from ubifs.misc import parse_key + +class common_hdr(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_COMMON_HDR_FIELDS, struct.unpack(UBIFS_COMMON_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __repr__(self): + return 'UBIFS Common Header' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class sb_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_SB_NODE_FIELDS, struct.unpack(UBIFS_SB_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Super Block Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class mst_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_MST_NODE_FIELDS, struct.unpack(UBIFS_MST_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Master Block Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class dent_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_DENT_NODE_FIELDS, struct.unpack(UBIFS_DENT_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'name', '') + + def __repr__(self): + return 'UBIFS Directory Entry Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class data_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_DATA_NODE_FIELDS, struct.unpack(UBIFS_DATA_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'offset', 0) + setattr(self, 'compr_len', 0) + + def __repr__(self): + return 'UBIFS Data Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class idx_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_IDX_NODE_FIELDS, struct.unpack(UBIFS_IDX_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'branches', []) + + def __repr__(self): + return 'UBIFS Index Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class ino_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_INO_NODE_FIELDS, struct.unpack(UBIFS_INO_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'data', '') + + def __repr__(self): + return 'UBIFS Ino Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class branch(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_BRANCH_FIELDS, struct.unpack(UBIFS_BRANCH_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Branch' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.pyo b/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.pyo new file mode 100644 index 0000000..cab9551 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.py b/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.py new file mode 100644 index 0000000..9f8f7b0 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +from ubifs import nodes +from ubifs.defines import * + +def common_hdr(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + return nodes.common_hdr(ubifs.file.read(UBIFS_COMMON_HDR_SZ)) + + +def ino_node(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + inon = nodes.ino_node(ubifs.file.read(UBIFS_INO_NODE_SZ)) + inon.data = ubifs.file.read(inon.data_len) + return inon + + +def mst_node(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + return nodes.mst_node(ubifs.file.read(UBIFS_MST_NODE_SZ)) + + +def sb_node(ubifs, offset = 0): + ubifs.file.seek(offset) + return nodes.sb_node(ubifs.file.read(UBIFS_SB_NODE_SZ)) + + +def dent_node(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + den = nodes.dent_node(ubifs.file.read(UBIFS_DENT_NODE_SZ)) + den.name = '%s' % ubifs.file.read(den.nlen) + return den + + +def data_node(ubifs, lnum, offset = 0, node_len = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + datn = nodes.data_node(ubifs.file.read(UBIFS_DATA_NODE_SZ)) + datn.offset = ubifs.leb_size * lnum + offset + UBIFS_DATA_NODE_SZ + datn.compr_len = node_len - UBIFS_COMMON_HDR_SZ - UBIFS_DATA_NODE_SZ + return datn + + +def idx_node(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + idxn = nodes.idx_node(ubifs.file.read(UBIFS_IDX_NODE_SZ)) + for i in range(0, idxn.child_cnt): + idxn.branches.append(nodes.branch(ubifs.file.read(UBIFS_BRANCH_SZ))) + + return idxn \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.pyo b/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.pyo new file mode 100644 index 0000000..59cfa8c Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubifs/output.py b/NeoBoot/ubi_reader_mips/ubifs/output.py new file mode 100644 index 0000000..dd3f4f4 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/output.py @@ -0,0 +1,114 @@ +#!/usr/bin/python +import os +import struct +from ubifs.defines import * +from ubifs.misc import decompress + +def 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) + if perms: + set_file_perms(dent_path, inode) + except Exception as e: + ubifs.log.write('DIR Fail: %s' % e) + + if 'dent' in inode: + for dnode in inode['dent']: + 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) + 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 as e: + ubifs.log.write('FILE Fail: %s' % e) + + elif dent_node.type == UBIFS_ITYPE_LNK: + try: + os.symlink('%s' % inode['ino'].data, dent_path) + except Exception as e: + ubifs.log.write('SYMLINK Fail: %s : %s' % (inode['ino'].data, dent_path)) + + elif dent_node.type in [UBIFS_ITYPE_BLK, UBIFS_ITYPE_CHR]: + try: + dev = struct.unpack(' len(buf): + buf += '\x00' * (inode['ino'].size - len(buf)) + return buf \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/output.pyo b/NeoBoot/ubi_reader_mips/ubifs/output.pyo new file mode 100644 index 0000000..48e29c0 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubifs/output.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ubifs/walk.py b/NeoBoot/ubi_reader_mips/ubifs/walk.py new file mode 100644 index 0000000..d8b8020 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/walk.py @@ -0,0 +1,33 @@ +#!/usr/bin/python +from ubifs import extract +from ubifs.defines import * + +def index(ubifs, lnum, offset, inodes = {}): + chdr = extract.common_hdr(ubifs, lnum, offset) + if chdr.node_type == UBIFS_IDX_NODE: + idxn = extract.idx_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + for branch in idxn.branches: + index(ubifs, branch.lnum, branch.offs, inodes) + + elif chdr.node_type == UBIFS_INO_NODE: + inon = extract.ino_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + ino_num = inon.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + inodes[ino_num]['ino'] = inon + elif chdr.node_type == UBIFS_DATA_NODE: + datn = extract.data_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ, chdr.len) + ino_num = datn.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + if 'data' not in inodes[ino_num]: + inodes[ino_num]['data'] = [] + inodes[ino_num]['data'].append(datn) + elif chdr.node_type == UBIFS_DENT_NODE: + dn = extract.dent_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + ino_num = dn.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + if 'dent' not in inodes[ino_num]: + inodes[ino_num]['dent'] = [] + inodes[ino_num]['dent'].append(dn) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/walk.pyo b/NeoBoot/ubi_reader_mips/ubifs/walk.pyo new file mode 100644 index 0000000..7079fba Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ubifs/walk.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ui/__init__.py b/NeoBoot/ubi_reader_mips/ui/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ui/__init__.py @@ -0,0 +1 @@ + diff --git a/NeoBoot/ubi_reader_mips/ui/__init__.pyo b/NeoBoot/ubi_reader_mips/ui/__init__.pyo new file mode 100644 index 0000000..63a124d Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ui/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_mips/ui/common.py b/NeoBoot/ubi_reader_mips/ui/common.py new file mode 100644 index 0000000..c8669fd --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ui/common.py @@ -0,0 +1,88 @@ +#!/usr/bin/python +import os +from ubi_io import leb_virtual_file +from ubifs import ubifs, walk, output +from ubifs.defines import PRINT_UBIFS_KEY_HASH, PRINT_UBIFS_COMPR +from ubi.defines import PRINT_VOL_TYPE_LIST, UBI_VTBL_AUTORESIZE_FLG +output_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'output') + +def extract_files(ubifs, out_path, perms = False): + try: + inodes = {} + walk.index(ubifs, ubifs.master_node.root_lnum, ubifs.master_node.root_offs, inodes) + for dent in inodes[1]['dent']: + output.dents(ubifs, inodes, dent, out_path, perms) + + except Exception as e: + import traceback + ubifs.log.write('%s' % e) + traceback.print_exc() + + +def get_ubi_params(ubi): + ubi_flags = {'min_io_size': '-m', + 'max_bud_bytes': '-j', + 'leb_size': '-e', + 'default_compr': '-x', + 'sub_page_size': '-s', + 'fanout': '-f', + 'key_hash': '-k', + 'orph_lebs': '-p', + 'log_lebs': '-l', + 'max_leb_cnt': '-c', + 'peb_size': '-p', + 'sub_page_size': '-s', + 'vid_hdr_offset': '-O', + 'version': '-x', + 'image_seq': '-Q', + 'alignment': '-a', + 'vol_id': '-n', + 'name': '-N'} + ubi_params = {} + ubi_args = {} + ini_params = {} + for image in ubi.images: + img_seq = image.image_seq + ubi_params[img_seq] = {} + ubi_args[img_seq] = {} + ini_params[img_seq] = {} + for volume in image.volumes: + ubi_args[img_seq][volume] = {} + ini_params[img_seq][volume] = {} + ini_params[img_seq][volume]['vol_type'] = PRINT_VOL_TYPE_LIST[image.volumes[volume].vol_rec.vol_type] + if image.volumes[volume].vol_rec.flags == UBI_VTBL_AUTORESIZE_FLG: + ini_params[img_seq][volume]['vol_flags'] = 'autoresize' + else: + ini_params[img_seq][volume]['vol_flags'] = image.volumes[volume].vol_rec.flags + ini_params[img_seq][volume]['vol_id'] = image.volumes[volume].vol_id + ini_params[img_seq][volume]['vol_name'] = image.volumes[volume].name.rstrip('\x00') + ini_params[img_seq][volume]['vol_alignment'] = image.volumes[volume].vol_rec.alignment + ini_params[img_seq][volume]['vol_size'] = image.volumes[volume].vol_rec.reserved_pebs * ubi.leb_size + ufsfile = leb_virtual_file(ubi, image.volumes[volume]) + uubifs = ubifs(ufsfile) + for key, value in uubifs.superblock_node: + if key == 'key_hash': + value = PRINT_UBIFS_KEY_HASH[value] + elif key == 'default_compr': + value = PRINT_UBIFS_COMPR[value] + if key in ubi_flags: + ubi_args[img_seq][volume][key] = value + + for key, value in image.volumes[volume].vol_rec: + if key == 'name': + value = value.rstrip('\x00') + if key in ubi_flags: + ubi_args[img_seq][volume][key] = value + + ubi_args[img_seq][volume]['version'] = image.version + ubi_args[img_seq][volume]['vid_hdr_offset'] = image.vid_hdr_offset + ubi_args[img_seq][volume]['sub_page_size'] = ubi_args[img_seq][volume]['vid_hdr_offset'] + ubi_args[img_seq][volume]['sub_page_size'] = ubi_args[img_seq][volume]['vid_hdr_offset'] + ubi_args[img_seq][volume]['image_seq'] = image.image_seq + ubi_args[img_seq][volume]['peb_size'] = ubi.peb_size + ubi_args[img_seq][volume]['vol_id'] = image.volumes[volume].vol_id + ubi_params[img_seq][volume] = {'flags': ubi_flags, + 'args': ubi_args[img_seq][volume], + 'ini': ini_params[img_seq][volume]} + + return ubi_params \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ui/common.pyo b/NeoBoot/ubi_reader_mips/ui/common.pyo new file mode 100644 index 0000000..b0ff888 Binary files /dev/null and b/NeoBoot/ubi_reader_mips/ui/common.pyo differ