From 03ce96ffbff51b7946660ca017124451fca5ffa8 Mon Sep 17 00:00:00 2001 From: Andrew LaMarche Date: Thu, 24 Oct 2024 15:06:56 +0000 Subject: [PATCH] unpacker: add broadcom SAO image support --- .../plugins/unpacking/broadcom/__init__.py | 0 .../unpacking/broadcom/code/__init__.py | 0 .../unpacking/broadcom/code/broadcom-sao.py | 47 ++++++++++++++++++ .../unpacking/broadcom/test/__init__.py | 0 .../broadcom/test/data/broadcom-sao.bin | Bin 0 -> 4540 bytes .../broadcom/test/test_plugin_broadcom_sao.py | 19 +++++++ 6 files changed, 66 insertions(+) create mode 100644 fact_extractor/plugins/unpacking/broadcom/__init__.py create mode 100644 fact_extractor/plugins/unpacking/broadcom/code/__init__.py create mode 100644 fact_extractor/plugins/unpacking/broadcom/code/broadcom-sao.py create mode 100644 fact_extractor/plugins/unpacking/broadcom/test/__init__.py create mode 100644 fact_extractor/plugins/unpacking/broadcom/test/data/broadcom-sao.bin create mode 100644 fact_extractor/plugins/unpacking/broadcom/test/test_plugin_broadcom_sao.py 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..0043ab9e --- /dev/null +++ b/fact_extractor/plugins/unpacking/broadcom/code/broadcom-sao.py @@ -0,0 +1,47 @@ +''' +This plugin unpacks Broadcom SAO images. +''' + +import os +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_SIZE = os.stat(file_path).st_size + + try: + with open(file_path, '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 IOError as io_error: + return {'output': 'failed to read file: {}'.format(str(io_error))} + + except struct.error as struct_error: + return {'output': 'failed to recognized firmware container: {}'.format(str(struct_error))} + + 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 0000000000000000000000000000000000000000..36a1c8b8b244baa7e79352b4ce1d4180845e7937 GIT binary patch literal 4540 zcmWIcck-IOytl{KHN=sT0Ssh;BnUI!|Ifhs9|$1A2=Z-=P$>fg69Y3)s9GttqNFG> zxg@_x$x11yC_gbJIX_poI5A(TmMa)&xb@}W%`PEMPEf>2*d(F3V?H7}J1mgGzzi%L-y6i7^4W zAj}DLbwOfDW>QWn1IXF?6%K9i4)XJXngg;{gFzMHYzBq~pb!E~TkCfK=4=Lr1rPCK zVBqF!NPz4S4)8Pz3ULdD*aPwv5F-cA1B4wQ*0v3jlVSE`6c-kQ{B&-OR60luWCjZ` zbPfPnEI_sc5QBgd*wYLQR!|xgry!63QUnBtpfnd$UI$7)OYLO;C27HMO89cE%jMZ3 zugvyrNHy?j3%~O(_Qrq5>aFkJFkW+fXSLv-s0qi>7WtPwQ~T%aJ*l+L?agk}__?y@ zqjMjz*!(PHV&2nGle_0qK~7)hi$#Z$c5A)5vNSDa^_j<6d+y8#u-2>j_Wsvs*4Gp&%CJL#sp{`&(HSmyk^ z_KWL>MA^$NJtCja2?%jqm=b^Vg$h%P_O`a899!0G7g^-Ht;Co+bY9ECy7(!FA5L9% z;Nr7GFLnEwe=IrS%a&)eN6NW`4lg?F3QQQ?&pNeeXQUlZEDHR?cS{f6gBbFQBL;jrA--D*#N)ozCyPd6+z_tGC@v2kI zmoq%@u@uwZZOvN?E`3@2B=7mta^qcFU+nt1uG8dmcxz$*3-5Dnz8_B5_d6{Lu#fuD z-@d#2-^%unInfgYZY)}=IYn6~lcD6EbV7*f8|`cDT=m(G&$ahm%&)O-v8z3&na_Pe zcFpre8_%qm#ls=>rBvr+cx~U37rU=~;*t{O$(}2@p5;F4dEeM{m$vC)8FS}`*KyAO zzF0F_YlVV6yMoMV+nK5*OA7bz2}r7RXuHCYb6b1;#l&Bk{{9x%-t9V5XaA*r_FEHk z@hToQuCo^B)^88ydM2VaHELJYrSsuFFWLiYPP|(7@qzxj-F`ng6HLWUo3(%ONm+Kk zp=n};!se%XH(ON}RGokFv5s-hBD?o&`gZxLZSVg02_CQaXxpl%QnWHwL3pW12h+bJ zg6fPyf9}bBzSQ&dflT1N$+tH@7Cn`5;M#Rj;~8g4k1uYVV)w?RbFOLVo1UeIV*{do z#~#xu_|qynZ5@lW`%PDu&E-dw)e3(~+?sK{Q%NmpN-)da#t)iO>lReytvDmWt$f;H z|JjlclPbyG9!MMZ~cCJSE& zFT2uZuY6JI*HrJf*^iBK_TPVae&W>MCl3EO%<90dG&v>ZL%|~HNza$KbpGGAz%I~q z#mmEgAH4o+qQY7^`}5&dE3Q23U-oB-^mYEQFX#1zBI8*W|Gm4JBdfG8c5?@>1pD-l zQ(omnu87~brBc8rtBkq0R4po{cfYpmM{Zd|JuBwY2cFW$a|I_~vo|{4qSpTB+_?%- zO^xumcfx1gyX4`0W6?t{1Fx{C?RH*GOM?;`m>9Nz3#OgG5(ZRCq5xp2!N~9zE)OZe zAf>51P$8&fg3140E|m`Ag8+z@W{?4wP$mr^5fFfx&cwhDE}r$0GV>rZAX69^6o8l! zsJAFTzeJ!R0muUb7O*744`>M{(Vzg8fKd)mh7hz&V`+E+bbtwz2U9glkA}c#2#kin WXb6mkz-S1JhQMeDjE2DA4*>x7Yljp7 literal 0 HcmV?d00001 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..55ff0614 --- /dev/null +++ b/fact_extractor/plugins/unpacking/broadcom/test/test_plugin_broadcom_sao.py @@ -0,0 +1,19 @@ +import os + +from test.unit.unpacker.test_unpacker import TestUnpackerBase + +TEST_DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data') + +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 = os.path.join(TEST_DATA_DIR, 'broadcom-sao.bin') + extracted_files, meta_data = self.unpacker.extract_files_from_file(test_file_path, self.tmp_dir.name) + + assert meta_data['plugin_used'] == 'Broadcom SAO', 'wrong plugin applied' + + assert len(extracted_files) == 4, 'not all files extracted' + assert all(element in ['META', 'DTBB', 'KRNL', 'RTFS'] for element in extracted_files), 'not all files extracted'