@@ -1058,7 +1058,8 @@ def __init__(self, *args, **kwargs):
1058
1058
self ._dmi_strings_pattern = re .compile (b'''(?:[\\ x20-\\ x7E]{1,255}\\ x00){1,255}\\ x00''' )
1059
1059
self ._dmi_date_pattern = re .compile ('''[0-9]{2}/[0-9]{2}/[0-9]{2}(?:[0-9]{2})?$''' )
1060
1060
self ._ncr_pattern = re .compile (b''' SDMS \\ (TM\\ ) V([0-9\\ .]+)''' )
1061
- self ._orom_pattern = re .compile (b'''\\ x55\\ xAA([\\ x01-\\ xFF])[\\ x00-\\ xFF]{21}([\\ x00-\\ xFF]{4})([\\ x00-\\ xFF]{2}IBM)?''' )
1061
+ self ._orom_pattern = re .compile (b'''\\ x55\\ xAA([\\ x01-\\ xFF])([\\ x00-\\ xFF])[\\ x00-\\ xFF]{20}([\\ x00-\\ xFF]{4})([\\ x00-\\ xFF]{2}IBM)?''' )
1062
+ self ._orom_string_pattern = re .compile (b'''[\\ x0D\\ x0A\\ x20-\\ x7E]{9,}''' )
1062
1063
self ._pxe_patterns = (
1063
1064
re .compile (b'''PXE-M0F: Exiting ''' ),
1064
1065
re .compile (b'''PXE-EC6: UNDI driver image is invalid\\ .''' ),
@@ -1311,30 +1312,42 @@ def _read_dmi_strings(header_match, string_value_offsets):
1311
1312
self ._enumerate_metadata ('LAN' , lan_roms )
1312
1313
1313
1314
# Check for the VGA BIOS compatibility marker string and add it as metadata.
1314
- vga_marker = match .group (3 )
1315
- if vga_marker :
1315
+ orom_marker = match .group (4 )
1316
+ orom_is_vga = False
1317
+ if orom_marker :
1318
+ orom_is_vga = True
1319
+
1316
1320
# Find ASCII strings around the marker. There must be a space before/after
1317
1321
# the marker to avoid parsing of non-text bytes as ASCII characters.
1318
- vga_start = match .start (3 ) + 2 - rom_offset
1322
+ vga_start = match .start (4 ) + 2 - rom_offset
1319
1323
if rom_data [vga_start - 1 :vga_start ] == b' ' :
1320
1324
while vga_start > 0 and rom_data [vga_start - 1 ] >= 0x20 and rom_data [vga_start - 1 ] <= 0x7e :
1321
1325
vga_start -= 1
1322
- vga_end = match .end (3 ) - rom_offset
1326
+ vga_end = match .end (4 ) - rom_offset
1323
1327
if rom_data [vga_end :vga_end + 1 ] == b' ' :
1324
1328
while vga_end < len (rom_data ) and rom_data [vga_end ] >= 0x20 and rom_data [vga_end ] <= 0x7e :
1325
1329
vga_end += 1
1326
- vga_marker = util .read_string (rom_data [vga_start :vga_end ]).strip ()
1330
+ orom_marker = util .read_string (rom_data [vga_start :vga_end ]).strip ()
1327
1331
1328
1332
# Find an ASCII string after the IBM header, and if one is found, use it instead.
1329
1333
additional_match = self ._vga_string_pattern .search (rom_data [vga_end :])
1330
1334
if additional_match :
1331
- vga_marker = self ._vga_trim_pattern .sub ('' , vga_marker ).strip ()
1332
- if vga_marker :
1333
- vga_marker += '\n '
1334
- vga_marker += util .read_string (additional_match .group (0 ).replace (b'\x00 ' , b' ' )).strip ()
1335
+ orom_marker = self ._vga_trim_pattern .sub ('' , orom_marker ).strip ()
1336
+ if orom_marker :
1337
+ orom_marker += '\n '
1338
+ orom_marker += util .read_string (additional_match .group (0 ).replace (b'\x00 ' , b' ' )).strip ()
1339
+ elif match .group (2 ) in b'\xe9 \xeb ' :
1340
+ # Find ASCII strings near the header if the entry point jump looks valid.
1341
+ string_match = self ._orom_string_pattern .search (rom_data [5 :4096 ]) # spec says data starts at 6, but a short jump can make it start at 5
1342
+ if string_match and b'NetWare Ready ROM' in string_match .group (0 ): # ignore RPL signature
1343
+ string_match = self ._orom_string_pattern .search (rom_data [string_match .end (0 ):4096 ])
1344
+ if string_match :
1345
+ orom_marker = util .read_string (string_match .group (0 )).strip ()
1346
+ if len (orom_marker ) > 256 : # ignore Adaptec's essay about 1 GB drives
1347
+ orom_marker = None
1335
1348
1336
1349
# Extract PCI and PnP data structure pointers.
1337
- pci_header_ptr , pnp_header_ptr = struct .unpack ('<HH' , match .group (2 ))
1350
+ pci_header_ptr , pnp_header_ptr = struct .unpack ('<HH' , match .group (3 ))
1338
1351
1339
1352
# Check for a valid PCI data structure.
1340
1353
if pci_header_ptr >= 26 :
@@ -1348,8 +1361,8 @@ def _read_dmi_strings(header_match, string_value_offsets):
1348
1361
1349
1362
# Make sure the vendor ID is not bogus.
1350
1363
if vendor_id not in (0x0000 , 0xffff ):
1351
- # The generic VGA marker is no longer required.
1352
- vga_marker = None
1364
+ # The extracted option ROM marker is no longer required.
1365
+ orom_marker = None
1353
1366
1354
1367
# Add IDs to the option ROM list.
1355
1368
self .oroms .append ((vendor_id , device_id ))
@@ -1401,19 +1414,19 @@ def _read_dmi_strings(header_match, string_value_offsets):
1401
1414
1402
1415
# Take valid data only.
1403
1416
if device_id [:2 ] != b'\x00 \x00 ' and (vendor or device ):
1404
- # The generic VGA marker is no longer required.
1405
- vga_marker = None
1417
+ # The extracted option ROM marker is no longer required.
1418
+ orom_marker = None
1406
1419
1407
1420
# Add PnP ID (endianness swapped to help the front-end in
1408
1421
# processing it), vendor name and device name to the list.
1409
1422
self .oroms .append ((struct .unpack ('>I' , device_id )[0 ], vendor , device ))
1410
1423
1411
- # Add generic VGA marker if no PCI/PnP data was found.
1412
- if vga_marker :
1424
+ # Add extracted option ROM marker if no PCI/PnP data was found.
1425
+ if orom_marker :
1413
1426
# Strip lines that are too short or have a single repeated character.
1414
- stripped = (x .strip () for x in vga_marker .replace ('\r ' , '\n ' ).split ('\n ' ))
1415
- vga_marker = '\n ' .join (x for x in stripped if len (x ) > 3 and x [:10 ] != (x [0 ] * min (len (x ), 10 ))).strip ('\n ' )
1416
- self .oroms .append ((- 1 , 'VGA' , vga_marker ))
1427
+ stripped = (x .strip () for x in orom_marker .replace ('\r ' , '\n ' ).split ('\n ' ))
1428
+ orom_marker = '\n ' .join (x for x in stripped if len (x ) > 3 and x [:10 ] != (x [0 ] * min (len (x ), 10 ))).strip ('\n ' )
1429
+ self .oroms .append ((- 1 , 'VGA' if orom_is_vga else 'OROM' , orom_marker ))
1417
1430
1418
1431
# This analyzer should never return True.
1419
1432
return False
0 commit comments