Skip to content

Commit

Permalink
Fixing issues #5
Browse files Browse the repository at this point in the history
Adding optional parameter to ignore CRC checking. Found multiple headers with bad CRCs, Ignoring the CRC still extracts the data and it's still useful.
  • Loading branch information
Caesurus committed Feb 17, 2021
1 parent 7b2bfca commit 8725581
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 23 deletions.
55 changes: 54 additions & 1 deletion tests/test_old_image.py
Expand Up @@ -35,7 +35,7 @@ def teardown_module(module):
os.remove(UBOOT_IMG_TEMP)


def test_01():
def test_01_multi_file_image():
# --------------------------------------------------------------------------------
# create dummy firmware image (u-boot executable image)
# --------------------------------------------------------------------------------
Expand Down Expand Up @@ -94,3 +94,56 @@ def test_01():

# check if are identical
assert mimg == img

def test_02_funky_chars_in_name():
# --------------------------------------------------------------------------------
# create dummy firmware image (u-boot executable image)
# --------------------------------------------------------------------------------
fwimg = uboot.StdImage(bytes([1] * 16),
name=str('\x03\x00\x00\x04\x52\x54\x2d\x41\x43\x35\x35\x55\x48\x50\x00\x00\x00\x00\x00\xa9'),
laddr=0,
eaddr=0,
arch=uboot.EnumArchType.ARM,
os=uboot.EnumOsType.LINUX,
image=uboot.EnumImageType.FIRMWARE,
compress=uboot.EnumCompressionType.NONE)

# --------------------------------------------------------------------------------
# save created image into file: uboot_mimg.img
# --------------------------------------------------------------------------------
with open(UBOOT_IMG_TEMP, "wb") as f:
f.write(fwimg.export())

# --------------------------------------------------------------------------------
# open and read image file: uboot_mimg.img
# --------------------------------------------------------------------------------
with open(UBOOT_IMG_TEMP, "rb") as f:
data = f.read()

# --------------------------------------------------------------------------------
# parse binary data into new img object of specific image type
# --------------------------------------------------------------------------------
img = uboot.parse_img(data)
# check if are identical
assert fwimg == img


def test_03_bad_crc():
bad_crc_image = b'\x27\x05\x19\x56\x4F\x7c\x89\x60\x60\x2d\xa6\xec\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x0b\xcd\x6a\xaf\x05\x02\x05\x00\x03\x00\x00\x04\x52\x54\x2d\x41\x43\x35\x35\x55\x48\x50\x00\x00\x00\x00\x00\xc2\xa9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01'

# --------------------------------------------------------------------------------
# parse binary data into new img object of specific image type
# --------------------------------------------------------------------------------
try:
img = uboot.parse_img(bad_crc_image)
except Exception:
pass
else:
assert False, 'Expected Exception when reading header with bad CRC'


# Don't expect an error
img = uboot.parse_img(bad_crc_image, ignore_crc=True)
expected_data = bytes([1] * 64)
assert img.data == expected_data, "Data wasn't correct"

55 changes: 33 additions & 22 deletions uboot/old_image.py
Expand Up @@ -199,7 +199,7 @@ def export(self):
self.name.encode('utf-8'))

@classmethod
def parse(cls, data, offset=0):
def parse(cls, data, offset=0, ignore_crc=False):
if len(data) < cls.SIZE:
raise Exception("Header: Too small size of input data !")

Expand All @@ -217,13 +217,14 @@ def parse(cls, data, offset=0):
header.arch_type = val[8]
header.image_type = val[9]
header.compression = val[10]
header.name = val[11].decode('utf-8').strip('\0')
header.name = val[11].decode('utf-8', errors='ignore').strip('\0')

if header.magic_number != header.MAGIC_NUMBER:
raise Exception("Header: Magic number not valid !")

if header_crc != header.header_crc:
raise Exception("Header: Uncorrect CRC of input data !")
if not ignore_crc:
if header_crc != header.header_crc:
raise Exception(f"Header: Uncorrect CRC of input data ! {hex(header_crc)} != {hex(header.header_crc)}")

return header
# ----------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -308,20 +309,22 @@ def export(self):
return self.header.export() + self.data

@classmethod
def parse(cls, data, offset=0):
def parse(cls, data, offset=0, ignore_crc=False):
""" Load the image from byte array.
:param data: The raw image as byte array
:param offset: The offset of input data
:param ignore_crc: ignore crc errors
"""
img = cls()
img.header = Header.parse(data, offset)
img.header = Header.parse(data, offset, ignore_crc)
offset += img.header.size
if len(data[offset:]) < img.header.data_size:
raise Exception("Image: Too small size of input data !")

img.data = data[offset:offset + img.header.data_size]
if CRC32(img.data) != img.header.data_crc:
raise Exception("Image: Uncorrect CRC of input data ")
if not ignore_crc:
raise Exception("Image: Uncorrect CRC of input data ")

return img

Expand Down Expand Up @@ -461,20 +464,22 @@ def export(self):
return self.header.export() + data

@classmethod
def parse(cls, data, offset=0):
def parse(cls, data, offset=0, ignore_crc=False):
""" Load the image from byte array.
:param data: The raw image as byte array
:param offset: The offset of input data
:param ignore_crc: ignore crc errors
"""
img = cls()
img.header = Header.parse(data, offset)
img.header = Header.parse(data, offset, ignore_crc)
offset += img.header.size
if len(data[offset:]) < img.header.data_size:
raise Exception("Image: Too small size of input data !")

data = data[offset:offset + img.header.data_size]
if CRC32(data) != img.header.data_crc:
raise Exception("Image: Uncorrect CRC of input data ")
if not ignore_crc:
raise Exception("Image: Uncorrect CRC of input data ")

# TODO: Check image format for script type
size = unpack_from('!2L', data)[0]
Expand Down Expand Up @@ -588,20 +593,22 @@ def export(self):
return self.header.export() + data

@classmethod
def parse(cls, data, offset=0):
def parse(cls, data, offset=0, ignore_crc=False):
""" Load the image from byte array.
:param data: The raw image as byte array
:param offset: The offset of input data
:param ignore_crc: ignore crc errors
"""
img = cls()
img.header = Header.parse(data, offset)
img.header = Header.parse(data, offset, ignore_crc)
offset += img.header.size

if len(data[offset:]) < img.header.data_size:
raise Exception("MultiImage: Too small size of input data !")

if CRC32(data[offset:offset + img.header.data_size]) != img.header.data_crc:
raise Exception("MultiImage: Uncorrect CRC of input data !")
if not ignore_crc:
raise Exception("MultiImage: Uncorrect CRC of input data !")

if img.header.image_type != EnumImageType.MULTI:
raise Exception("MultiImage: Not a Multi Image Type !")
Expand All @@ -623,22 +630,25 @@ def parse(cls, data, offset=0):
# ----------------------------------------------------------------------------------------------------------------------


def get_img_type(data, offset=0):
def get_img_type(data, offset=0, ignore_crc=False):
""" Help function for extracting image fom raw data
:param data: The raw data as byte array
:param offset: The offset
:return: Image type and offset where image start
"""
while True:
if (offset + Header.SIZE) > len(data):
raise Exception("Not an U-Boot image !")
raise Exception(f"Not an U-Boot image ! {(offset + Header.SIZE)} > {len(data)}")

(header_mn, header_crc,) = unpack_from('!2L', data, offset)
# Check the magic number if is U-Boot image
if header_mn == Header.MAGIC_NUMBER:
header = bytearray(data[offset:offset+Header.SIZE])
header[4:8] = [0]*4
if header_crc == CRC32(header):
if not ignore_crc:
if header_crc == CRC32(header):
break
else:
break
offset += 4

Expand Down Expand Up @@ -675,25 +685,26 @@ def new_img(**kwargs):
return img_obj


def parse_img(data, offset=0):
def parse_img(data, offset=0, ignore_crc=False):
""" Help function for extracting image fom raw data
:param data: The raw data as byte array
:param offset: The offset
:param ignore_crc: Ignore CRC mismatches
:return: Image object
"""
(img_type, offset) = get_img_type(bytearray(data), offset)
(img_type, offset) = get_img_type(bytearray(data), offset, ignore_crc)

if img_type not in EnumImageType:
raise Exception("Not a valid image type")

if img_type == EnumImageType.MULTI:
img = MultiImage.parse(data, offset)
img = MultiImage.parse(data, offset, ignore_crc)
elif img_type == EnumImageType.FIRMWARE:
img = FwImage.parse(data, offset)
img = FwImage.parse(data, offset, ignore_crc)
elif img_type == EnumImageType.SCRIPT:
img = ScriptImage.parse(data, offset)
img = ScriptImage.parse(data, offset, ignore_crc)
else:
img = StdImage.parse(data, offset)
img = StdImage.parse(data, offset, ignore_crc)
img.header.image_type = img_type

return img

0 comments on commit 8725581

Please sign in to comment.