You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
5.2 KiB
Python
183 lines
5.2 KiB
Python
#!/usr/bin/env python
|
|
#############################################################
|
|
# ubi_reader
|
|
# (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#############################################################
|
|
|
|
import re
|
|
from ubireader.debug import error, log
|
|
from ubireader.ubi.defines import UBI_EC_HDR_MAGIC, FILE_CHUNK_SZ
|
|
from ubireader.ubifs.defines import UBIFS_NODE_MAGIC, UBIFS_SB_NODE_SZ, UBIFS_SB_NODE, UBIFS_COMMON_HDR_SZ
|
|
from ubireader.ubifs import nodes
|
|
|
|
def guess_start_offset(path, guess_offset=0):
|
|
file_offset = guess_offset
|
|
|
|
f = open(path, 'rb')
|
|
f.seek(0,2)
|
|
file_size = f.tell()+1
|
|
f.seek(guess_offset)
|
|
|
|
for _ in range(0, file_size, FILE_CHUNK_SZ):
|
|
buf = f.read(FILE_CHUNK_SZ)
|
|
ubi_loc = buf.find(UBI_EC_HDR_MAGIC)
|
|
ubifs_loc = buf.find(UBIFS_NODE_MAGIC)
|
|
|
|
if ubi_loc == -1 and ubifs_loc == -1:
|
|
file_offset += FILE_CHUNK_SZ
|
|
continue
|
|
else:
|
|
if ubi_loc == -1:
|
|
ubi_loc = file_size + 1
|
|
elif ubifs_loc == -1:
|
|
ubifs_loc = file_size + 1
|
|
|
|
if ubi_loc < ubifs_loc:
|
|
log(guess_start_offset, 'Found UBI magic number at %s' % (file_offset + ubi_loc))
|
|
return file_offset + ubi_loc
|
|
|
|
elif ubifs_loc < ubi_loc:
|
|
log(guess_start_offset, 'Found UBIFS magic number at %s' % (file_offset + ubifs_loc))
|
|
return file_offset + ubifs_loc
|
|
else:
|
|
error(guess_start_offset, 'Fatal', 'Could not determine start offset.')
|
|
else:
|
|
error(guess_start_offset, 'Fatal', 'Could not determine start offset.')
|
|
|
|
f.close()
|
|
|
|
|
|
def guess_filetype(path, start_offset=0):
|
|
log(guess_filetype, 'Looking for file type at %s' % start_offset)
|
|
|
|
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 guess_leb_size(path):
|
|
"""Get LEB size from superblock
|
|
|
|
Arguments:
|
|
Str:path -- Path to file.
|
|
|
|
Returns:
|
|
Int -- LEB size.
|
|
|
|
Searches file for superblock and retrieves leb size.
|
|
"""
|
|
|
|
f = open(path, 'rb')
|
|
f.seek(0,2)
|
|
file_size = f.tell()+1
|
|
f.seek(0)
|
|
block_size = None
|
|
|
|
for _ 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
|
|
|
|
|
|
def guess_peb_size(path):
|
|
"""Determine the most likely block size
|
|
|
|
Arguments:
|
|
Str:path -- Path to file.
|
|
|
|
Returns:
|
|
Int -- PEB size.
|
|
|
|
Searches file for Magic Number, picks most
|
|
common length between them.
|
|
"""
|
|
file_offset = 0
|
|
offsets = []
|
|
f = open(path, 'rb')
|
|
f.seek(0,2)
|
|
file_size = f.tell()+1
|
|
f.seek(0)
|
|
|
|
for _ 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()
|
|
|
|
occurrences = {}
|
|
for i in range(0, len(offsets)):
|
|
try:
|
|
diff = offsets[i] - offsets[i-1]
|
|
except:
|
|
diff = offsets[i]
|
|
|
|
if diff not in occurrences:
|
|
occurrences[diff] = 0
|
|
|
|
occurrences[diff] += 1
|
|
|
|
most_frequent = 0
|
|
block_size = None
|
|
|
|
for offset in occurrences:
|
|
if occurrences[offset] > most_frequent:
|
|
most_frequent = occurrences[offset]
|
|
block_size = offset
|
|
|
|
return block_size |