diff --git a/fact_extractor/plugins/unpacking/broadcom/__init__.py b/fact_extractor/plugins/unpacking/broadcom/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fact_extractor/plugins/unpacking/broadcom/code/__init__.py b/fact_extractor/plugins/unpacking/broadcom/code/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fact_extractor/plugins/unpacking/broadcom/code/broadcom_sao.py b/fact_extractor/plugins/unpacking/broadcom/code/broadcom_sao.py new file mode 100644 index 00000000..d6f90399 --- /dev/null +++ b/fact_extractor/plugins/unpacking/broadcom/code/broadcom_sao.py @@ -0,0 +1,45 @@ +""" +This plugin unpacks Broadcom SAO images. +""" + +from pathlib import Path + +from common_helper_files import write_binary_to_file + +NAME = 'Broadcom SAO' +MIME_PATTERNS = ['firmware/broadcom-sao'] +VERSION = '0.1' + + +def unpack_function(file_path, tmp_dir): + """ + file_path specifies the input file. + tmp_dir must be used to store the extracted files. + Optional: Return a dict with meta information + """ + + file = Path(file_path) + file_size = file.stat().st_size + + try: + with file.open('rb') as f: + while f.tell() < file_size: + f.read(8) # skip 8 bytes to part name offset + name = f.read(4).decode('utf-8') + f.read(4) # skip 4 more bytes to size offset + size = int.from_bytes(f.read(4), 'big') + f.read(44) # skip rest of header + data = f.read(size) + outfile = Path(tmp_dir) / name + write_binary_to_file(data, outfile) + + except OSError as io_error: + return {'output': f'failed to read file: {io_error!s}'} + + return {'output': 'successfully unpacked Broadcom SAO image'} + + +# ----> Do not edit below this line <---- +def setup(unpack_tool): + for item in MIME_PATTERNS: + unpack_tool.register_plugin(item, (unpack_function, NAME, VERSION)) diff --git a/fact_extractor/plugins/unpacking/broadcom/test/__init__.py b/fact_extractor/plugins/unpacking/broadcom/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fact_extractor/plugins/unpacking/broadcom/test/data/broadcom-sao.bin b/fact_extractor/plugins/unpacking/broadcom/test/data/broadcom-sao.bin new file mode 100644 index 00000000..36a1c8b8 Binary files /dev/null and b/fact_extractor/plugins/unpacking/broadcom/test/data/broadcom-sao.bin differ diff --git a/fact_extractor/plugins/unpacking/broadcom/test/test_plugin_broadcom_sao.py b/fact_extractor/plugins/unpacking/broadcom/test/test_plugin_broadcom_sao.py new file mode 100644 index 00000000..489a882b --- /dev/null +++ b/fact_extractor/plugins/unpacking/broadcom/test/test_plugin_broadcom_sao.py @@ -0,0 +1,23 @@ +from pathlib import Path + +from test.unit.unpacker.test_unpacker import TestUnpackerBase + +TEST_DATA_DIR = Path(__file__).parent / 'data' + +EXPECTED_FILE_COUNT = 4 + + +class TestBroadcomSAOUnpacker(TestUnpackerBase): + def test_unpacker_selection_generic(self): + self.check_unpacker_selection('firmware/broadcom-sao', 'Broadcom SAO') + + def test_extraction(self): + test_file_path = Path(TEST_DATA_DIR) / 'broadcom-sao.bin' + extracted_files, meta_data = self.unpacker.extract_files_from_file(str(test_file_path), self.tmp_dir.name) + + assert meta_data['plugin_used'] == 'Broadcom SAO', 'wrong plugin applied' + + assert len(extracted_files) == EXPECTED_FILE_COUNT, 'not all files extracted' + assert all( + Path(element).name in ['META', 'DTBB', 'KRNL', 'RTFS'] for element in extracted_files + ), 'not all files extracted'