From deff5d8e7962a5302dffdf1900e413a119648120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Stucke?= Date: Fri, 22 Nov 2024 12:17:25 +0100 Subject: [PATCH] feat: added xiaomi hdr unpacker based on unblob --- .../plugins/unpacking/xiaomi_hdr/__init__.py | 0 .../unpacking/xiaomi_hdr/code/__init__.py | 0 .../unpacking/xiaomi_hdr/code/xiaomi_hdr.py | 50 ++++++++++++++++++ .../unpacking/xiaomi_hdr/test/__init__.py | 0 .../unpacking/xiaomi_hdr/test/data/test.hdr1 | Bin 0 -> 574 bytes .../unpacking/xiaomi_hdr/test/test_hdr.py | 22 ++++++++ 6 files changed, 72 insertions(+) create mode 100644 fact_extractor/plugins/unpacking/xiaomi_hdr/__init__.py create mode 100644 fact_extractor/plugins/unpacking/xiaomi_hdr/code/__init__.py create mode 100644 fact_extractor/plugins/unpacking/xiaomi_hdr/code/xiaomi_hdr.py create mode 100644 fact_extractor/plugins/unpacking/xiaomi_hdr/test/__init__.py create mode 100644 fact_extractor/plugins/unpacking/xiaomi_hdr/test/data/test.hdr1 create mode 100644 fact_extractor/plugins/unpacking/xiaomi_hdr/test/test_hdr.py diff --git a/fact_extractor/plugins/unpacking/xiaomi_hdr/__init__.py b/fact_extractor/plugins/unpacking/xiaomi_hdr/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fact_extractor/plugins/unpacking/xiaomi_hdr/code/__init__.py b/fact_extractor/plugins/unpacking/xiaomi_hdr/code/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fact_extractor/plugins/unpacking/xiaomi_hdr/code/xiaomi_hdr.py b/fact_extractor/plugins/unpacking/xiaomi_hdr/code/xiaomi_hdr.py new file mode 100644 index 00000000..56e7a89f --- /dev/null +++ b/fact_extractor/plugins/unpacking/xiaomi_hdr/code/xiaomi_hdr.py @@ -0,0 +1,50 @@ +""" +This plugin uses unblob to unpack Xiaomi HDR1/2 images. +""" + +from __future__ import annotations + +import logging +from pathlib import Path + +import structlog +from structlog.testing import capture_logs +from unblob.handlers.archive.xiaomi.hdr import HDRExtractor + +NAME = 'Xiaomi HDR' +MIME_PATTERNS = ['firmware/xiaomi-hdr1', 'firmware/xiaomi-hdr2'] +VERSION = '0.1.0' + +structlog.configure( + wrapper_class=structlog.make_filtering_bound_logger(logging.DEBUG), +) + + +def unpack_function(file_path: str, tmp_dir: str) -> dict: + path = Path(file_path) + with path.open('rb') as fp: + magic = fp.read(4) + if magic in [b'HDR1', b'HDR2']: + extractor = HDRExtractor(f'{magic.decode().lower()}_header_t') + else: + return {'output': ''} + + # unblob uses structlog for logging, but we can capture the logs with this convenient testing function + with capture_logs() as log_list: + extractor.extract(path, Path(tmp_dir)) + return {'output': _format_logs(log_list)} + + +def _format_logs(logs: list[dict]) -> str: + output = '' + for entry in logs: + output += '\n'.join(f'{key}: {value}' for key, value in entry.items() if key not in {'_verbosity', 'log_level'}) + return output + + +# ----> 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/xiaomi_hdr/test/__init__.py b/fact_extractor/plugins/unpacking/xiaomi_hdr/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fact_extractor/plugins/unpacking/xiaomi_hdr/test/data/test.hdr1 b/fact_extractor/plugins/unpacking/xiaomi_hdr/test/data/test.hdr1 new file mode 100644 index 0000000000000000000000000000000000000000..3d97faa7cea5eb2a8135262780f7f51cd5a1c7fc GIT binary patch literal 574 zcmeZp2{P1UWMHszGXKiJ;Lc#cz`#%f#E*a&8`!stf#E+8hyW%3|7T!GPt8j$%1l;B z%g;$kEz&PZEiO?=%gjktFpk$NsVHFx$w*Zw$;d29QGiP+!pyLPngNml=`qA+Ay5pi z(~2uOKd&S;uf$5hw=x8%E2tD`lcAoGo-tQgYEf}!ex8*=Kv8~rQDUxwfgTug!EBR3 gv&{&HZ6O(%#R@=F0(5zCD$qhCr!xrP&@@7Y0r{v?AOHXW literal 0 HcmV?d00001 diff --git a/fact_extractor/plugins/unpacking/xiaomi_hdr/test/test_hdr.py b/fact_extractor/plugins/unpacking/xiaomi_hdr/test/test_hdr.py new file mode 100644 index 00000000..2fb11f5e --- /dev/null +++ b/fact_extractor/plugins/unpacking/xiaomi_hdr/test/test_hdr.py @@ -0,0 +1,22 @@ +from pathlib import Path + +from plugins.unpacking.xiaomi_hdr.code.xiaomi_hdr import MIME_PATTERNS +from test.unit.unpacker.test_unpacker import TestUnpackerBase + +TEST_DATA_DIR = Path(__file__).parent / 'data' + + +class TestXiaomiHdrUnpacker(TestUnpackerBase): + def test_unpacker_selection_generic(self): + for mime in MIME_PATTERNS: + self.check_unpacker_selection(mime, 'Xiaomi HDR') + + def test_extraction_hdr(self): + in_file = TEST_DATA_DIR / 'test.hdr1' + assert in_file.is_file(), 'test file is missing' + meta = self.check_unpacking_of_standard_unpack_set( + in_file, + output=True, + ) + assert 'output' in meta + assert 'testfile1' in meta['output']