diff --git a/bios_extract/src/ami.c b/bios_extract/src/ami.c index 8011baa..311b128 100644 --- a/bios_extract/src/ami.c +++ b/bios_extract/src/ami.c @@ -23,6 +23,7 @@ #define _GNU_SOURCE 1 /* for memmem */ #include +#include #include #include #include @@ -180,25 +181,6 @@ AMI940725Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, printf("AMI94 Version\t: %s (%s)\n", Version, Date); - /* First, the boot rom */ - uint32_t BootOffset; - int fd; - - BootOffset = AMIBOffset & 0xFFFE0000; - - printf("0x%05X (%6d bytes) -> amiboot.rom\n", BootOffset, - BIOSLength - BootOffset); - - fd = open("amiboot.rom", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - fprintf(stderr, "Error: unable to open %s: %s\n\n", - "amiboot.rom", strerror(errno)); - return FALSE; - } - - write(fd, BIOSImage + BootOffset, BIOSLength - BootOffset); - close(fd); - for (i = 0; i < 0x80; i++) { char filename[64]; unsigned char *Buffer; @@ -246,10 +228,14 @@ NotCompressed: strcpy(&filename[strlen(filename) - 3], "cmp"); } goto NotCompressed; + } else { + SetRemainder(Offset, ROMSize + 8, FALSE); } - } else + } else { memcpy(Buffer, BIOSImage + Offset + 8, BufferSize); + SetRemainder(Offset, BufferSize + 8, FALSE); + } munmap(Buffer, BufferSize); @@ -312,25 +298,6 @@ AMI941010Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, printf("AMI94 Version\t: %s (%s)\n", Version, Date); - /* First, the boot rom */ - uint32_t BootOffset; - int fd; - - BootOffset = AMIBOffset & 0xFFFE0000; - - printf("0x%05X (%6d bytes) -> amiboot.rom\n", BootOffset, - BIOSLength - BootOffset); - - fd = open("amiboot.rom", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - fprintf(stderr, "Error: unable to open %s: %s\n\n", - "amiboot.rom", strerror(errno)); - return FALSE; - } - - write(fd, BIOSImage + BootOffset, BIOSLength - BootOffset); - close(fd); - /* now dump the individual modules */ headerinfo = (struct headerinfo *)(BIOSImage + ABCOffset + 0x10); for (i = 0; i < headerinfo->ModuleCount; i++) { @@ -388,10 +355,14 @@ NotCompressed: strcpy(&filename[strlen(filename) - 3], "cmp"); } goto NotCompressed; + } else { + SetRemainder(ABCOffset + part->RealCS, ROMSize + 8, FALSE); } - } else + } else { memcpy(Buffer, BIOSImage + ABCOffset + part->RealCS, BufferSize); + SetRemainder(ABCOffset + part->RealCS, BufferSize, FALSE); + } munmap(Buffer, BufferSize); } @@ -482,25 +453,6 @@ AMI95Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, return TRUE; } - /* First, the boot rom */ - uint32_t BootOffset; - int fd; - - BootOffset = AMIBOffset & 0xFFFF0000; - - printf("0x%05X (%6d bytes) -> amiboot.rom\n", BootOffset, - BIOSLength - BootOffset); - - fd = open("amiboot.rom", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - fprintf(stderr, "Error: unable to open %s: %s\n\n", - "amiboot.rom", strerror(errno)); - return FALSE; - } - - write(fd, BIOSImage + BootOffset, BIOSLength - BootOffset); - close(fd); - /* now dump the individual modules */ if (BIOSLength > 0x100000) { OffsetMode = 'A'; @@ -626,6 +578,7 @@ NotCompressed: } else memcpy(Buffer, BIOSImage + NewOffset, ROMSize); + SetRemainder(Offset - BIOSOffset, (NewOffset - (Offset - BIOSOffset)) + ROMSize, FALSE); munmap(Buffer, BufferSize); @@ -683,7 +636,14 @@ AFUDOSExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, munmap(Buffer, hdr->ExpSize); - char *argv[] = {"", "afudos.bin"}; + if (remainder_buf) { + SetRemainder(((unsigned char *)hdr) - BIOSImage, hdr->ROMSize, FALSE); + SaveRemainder(BIOSImage); + free(remainder_buf); + rename("remainder.rom", "afudos_remainder.rom"); + } + + char *argv[] = {"\x01", "afudos.bin"}; int ret = main(2, argv); unlink("afudos.bin"); diff --git a/bios_extract/src/award.c b/bios_extract/src/award.c index f793253..86960c4 100644 --- a/bios_extract/src/award.c +++ b/bios_extract/src/award.c @@ -35,11 +35,10 @@ AwardExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, uint32_t Offset1, uint32_t BCPSegmentOffset) { unsigned char *p, *Buffer; - int HeaderSize; + int HeaderSize = 0; unsigned int BufferSize, PackedSize; - char *filename; + char *filename = {0}; unsigned short crc; - Bool First = TRUE; printf("Found Award BIOS.\n"); @@ -50,24 +49,6 @@ AwardExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, break; p -= 2; - if (First) { - First = FALSE; - BufferSize = p - BIOSImage; - if (BufferSize > 0) { - filename = "awardboot.rom"; - printf("0x%05X (%6d bytes) -> %s\n", - 0, BufferSize, filename); - - Buffer = MMapOutputFile(filename, BufferSize); - if (!Buffer) - return FALSE; - - memcpy(Buffer, BIOSImage, BufferSize); - - munmap(Buffer, BufferSize); - } - } - HeaderSize = LH5HeaderParse(p, BIOSLength - (p - BIOSImage), &BufferSize, &PackedSize, &filename, &crc); @@ -82,12 +63,13 @@ AwardExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, if (!Buffer) return FALSE; - LH5Decode(p + HeaderSize, PackedSize, Buffer, BufferSize); + if (LH5Decode(p + HeaderSize, PackedSize, Buffer, BufferSize) != -1) + SetRemainder(p - BIOSImage, HeaderSize + PackedSize, FALSE); munmap(Buffer, BufferSize); p += HeaderSize + PackedSize; } - return !First; + return !!filename[0]; } diff --git a/bios_extract/src/bios_extract.c b/bios_extract/src/bios_extract.c index ddd7890..4f20307 100644 --- a/bios_extract/src/bios_extract.c +++ b/bios_extract/src/bios_extract.c @@ -92,6 +92,84 @@ unsigned char *MMapOutputFile(char *filename, int size) return Buffer; } +unsigned char *remainder_buf = NULL; +static int remainder_size = 0, remainder_padding = 0; + +void InitRemainder(unsigned char *BIOSImage, int BIOSLength) +{ + unsigned char *new_remainder_buf = realloc(remainder_buf, BIOSLength); + if (new_remainder_buf) { + remainder_buf = new_remainder_buf; + remainder_size = BIOSLength; + } + + if (!remainder_buf) + return; + + /* Remove padding from the start only, as the end will have the entry point anyway. */ + if (remainder_size < BIOSLength) + BIOSLength = remainder_size; + unsigned char *p = BIOSImage, *q = BIOSImage + BIOSLength; + while ((p < q) && ((*p == 0x00) || (*p == 0xff))) + p++; + + remainder_padding = p - BIOSImage; + if (remainder_padding > 0) { + BIOSLength -= remainder_padding; + memset(remainder_buf, 0x00, remainder_padding); + } + memset(remainder_buf + remainder_padding, 0xff, BIOSLength); +} + +void SetRemainder(uint32_t Offset, uint32_t Length, int val) +{ + if (!remainder_buf) + return; + + if ((remainder_size - Offset) < Length) + Length = remainder_size - Offset; + memset(remainder_buf + Offset, 0xff * !!val, Length); +} + +int SaveRemainder(unsigned char *BIOSImage) +{ + if (!remainder_buf) + return TRUE; + + if (remainder_padding > 0) + printf("Padding (%6d bytes) -> [discarded]\n", + remainder_padding); + + int fd = open("remainder.rom", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd < 0) { + fprintf(stderr, "Error: unable to open remainder.rom: %s\n\n", + strerror(errno)); + return FALSE; + } + + int remaining = remainder_size, copy; + unsigned char *p = remainder_buf, *q, c = *p; + while (p) { + c = ~c; + q = memchr(p, c, remaining); + if (q) + copy = q - p; + else + copy = remaining; + if (!c) + write(fd, BIOSImage + (p - remainder_buf), copy); + remaining -= copy; + p = q; + } + + printf("Remains (%6ld bytes) -> remainder.rom\n", + lseek(fd, 0, SEEK_CUR)); + + close(fd); + + return TRUE; +} + /* TODO: Make bios identification more flexible */ static struct { @@ -191,11 +269,17 @@ int main(int argc, char *argv[]) Offset2 = Offset1; } - if (BIOSIdentification[i].Handler - (BIOSImage, FileLength, BIOSOffset, Offset1, Offset2)) - return 0; - else - return 1; + if ((argv[0][0] != 0x01) || (argv[0][1] != 0x00)) + InitRemainder(BIOSImage, FileLength); + + len = BIOSIdentification[i].Handler + (BIOSImage, FileLength, BIOSOffset, Offset1, Offset2); + if (remainder_buf) { + len &= SaveRemainder(BIOSImage); + free(remainder_buf); + remainder_buf = NULL; + } + return len ? 0 : 1; } /* Bruteforce Intel AMI Color fork LH5. */ @@ -206,28 +290,32 @@ CopyrightOffset:if ((LH5Decode(BIOSImage + BIOSOffset, FileLength - BIOSOffset, (!memcmp(IntelAMI, "AMIBIOS(C)AMI", 13) || ((IntelAMI[0] == 0x55) && (IntelAMI[1] == 0xaa)))) { if (Offset2 == 1) { printf("Found potential Intel AMIBIOS.\n"); + InitRemainder(BIOSImage, FileLength); Offset2 = 86; /* magic exit code if no main body found */ } if (IntelAMI[0] == 0x55) { len = IntelAMI[2] * 512; - sprintf((char *) IntelAMI, "intelopt_%05X.bin", BIOSOffset); + sprintf((char *) IntelAMI, "intelopt_%05X.rom", BIOSOffset); } else { len = 65536; - sprintf((char *) IntelAMI, "intelbody_%05X.bin", BIOSOffset); + sprintf((char *) IntelAMI, "intelbody_%05X.rom", BIOSOffset); Offset2 = 0; /* main body found, all good */ } - printf("0x%05X -> %s\t(%d bytes)\n", - BIOSOffset, IntelAMI, len); Buffer = MMapOutputFile((char *) IntelAMI, len); if (!Buffer) return 1; i = len; - while ((LH5Decode(BIOSImage + BIOSOffset, FileLength - BIOSOffset, Buffer, i) == -1) && + while (((fd = LH5Decode(BIOSImage + BIOSOffset, FileLength - BIOSOffset, Buffer, i)) == -1) && (i > 16)) i--; + if (fd > 0) { + printf("0x%05X (%6d bytes) -> %s\t(%d bytes)\n", + BIOSOffset, fd, IntelAMI, len); + SetRemainder(BIOSOffset, fd, FALSE); + } munmap(Buffer, len); } else if (!(BIOSOffset & 0xff)) { @@ -238,5 +326,7 @@ CopyrightOffset:if ((LH5Decode(BIOSImage + BIOSOffset, FileLength - BIOSOffset, if (Offset2) fprintf(stderr, "Error: Unable to detect BIOS Image type.\n"); + else + return !SaveRemainder(BIOSImage); return Offset2; } diff --git a/bios_extract/src/bios_extract.h b/bios_extract/src/bios_extract.h index 337582a..73aad45 100644 --- a/bios_extract/src/bios_extract.h +++ b/bios_extract/src/bios_extract.h @@ -36,6 +36,11 @@ /* bios_extract.c */ unsigned char *MMapOutputFile(char *filename, int size); +extern unsigned char *remainder_buf; +void InitRemainder(unsigned char *BIOSImage, int BIOSLength); +void SetRemainder(uint32_t Offset, uint32_t Length, int val); +int SaveRemainder(unsigned char *BIOSImage); + int main(int argc, char *argv[]); /* ami.c */ diff --git a/bios_extract/src/lh5_extract.c b/bios_extract/src/lh5_extract.c index bd50ed5..1d6d6e4 100644 --- a/bios_extract/src/lh5_extract.c +++ b/bios_extract/src/lh5_extract.c @@ -549,5 +549,5 @@ LH5Decode(unsigned char *PackedBuffer, int PackedBufferSize, } } } - return 0; + return CompressedOffset; } diff --git a/bios_extract/src/phoenix.c b/bios_extract/src/phoenix.c index 8156e1b..72bf766 100644 --- a/bios_extract/src/phoenix.c +++ b/bios_extract/src/phoenix.c @@ -309,7 +309,7 @@ phx_write_file(unsigned char *BIOSImage, char *filename, short filetype, #define MODULE_SIGNATURE_INVALID(Module) (Module->Signature[0] || (Module->Signature[1] != 0x31) || (Module->Signature[2] != 0x31)) -static int PhoenixModule(unsigned char *BIOSImage, int BIOSLength, int Offset, unsigned char *remainder) +static int PhoenixModule(unsigned char *BIOSImage, int BIOSLength, int Offset) { struct PhoenixModuleHeader *Module, *NewModule; @@ -395,8 +395,7 @@ valid_signature: memcpy(ModuleData, BIOSImage + Offset + Module->HeadLen, FragLength); - if (remainder) - memset(remainder + Offset, 0, Module->HeadLen + FragLength); + SetRemainder(Offset, Module->HeadLen + FragLength, FALSE); Packed = FragLength; FragOffset = le32toh(Module->NextFrag) & (BIOSLength - 1); @@ -418,8 +417,7 @@ valid_signature: Remain = BIOSLength - ((ModuleData + Packed) - BIOSImage); memcpy(ModuleData + Packed, BIOSImage + FragOffset + 9, (Remain < FragLength) ? Remain : FragLength); - if (remainder) - memset(remainder + FragOffset + 9, 0, (Remain < FragLength) ? Remain : FragLength); + SetRemainder(FragOffset + 9, (Remain < FragLength) ? Remain : FragLength, FALSE); Packed += FragLength; FragOffset = le32toh(Fragment->NextFrag) & (BIOSLength - 1); @@ -507,7 +505,7 @@ BadFragment: le32toh(Module->ExpLen)); munmap(Buffer, le32toh(Module->ExpLen)); /* Write compressed data if decompression failed. */ - if (ExtractResult) + if (ExtractResult == -1) goto Uncompressed; break; @@ -535,8 +533,8 @@ Uncompressed: if (IsFragment) free(ModuleData); - else if (remainder) - memset(remainder + Offset, 0, Module->HeadLen + Packed); + else + SetRemainder(Offset, Module->HeadLen + Packed, FALSE); if (le16toh(Module->Offset) || le16toh(Module->Segment)) { if (!Module->Compression) @@ -974,7 +972,7 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, struct PhoenixBCD6F1 *BCD6F1; uint32_t Offset, Length; int fd; - unsigned char *p, *Buffer, *remainder, + unsigned char *p, *Buffer, module_signature[] = {0x00, 0x31, 0x31}, bcd6f1_signature[] = {'B', 'C', 0xd6, 0xf1, 0x00, 0x00, 0x12}, optrom_signature[] = {0x55, 0xaa}, @@ -994,12 +992,9 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, */ if (BIOSLength > 0x100000 && BIOSOffset > 0) { BIOSLength = BIOSLength + BIOSOffset - 0x100000; + InitRemainder(BIOSImage, BIOSLength); } - remainder = malloc(BIOSLength); - if (remainder) - memcpy(remainder, BIOSImage, BIOSLength); - for (ID = (struct PhoenixID *)(BIOSImage + BCPSegmentOffset + 10); ((void *)ID < (void *)(BIOSImage + BIOSLength)) && ID->Name[0]; ID = @@ -1078,7 +1073,7 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, } while (Offset) { - Offset = PhoenixModule(BIOSImage, BIOSLength, Offset, remainder); + Offset = PhoenixModule(BIOSImage, BIOSLength, Offset); Offset &= BIOSLength - 1; } @@ -1102,8 +1097,7 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, if (!Buffer) break; - if (remainder) - memset(remainder + (p - BIOSImage), 0, sizeof(struct PhoenixBCD6F1) + le32toh(BCD6F1->FragLength)); + SetRemainder(p - BIOSImage, sizeof(struct PhoenixBCD6F1) + le32toh(BCD6F1->FragLength), FALSE); p += sizeof(struct PhoenixBCD6F1); if (phx.compression == 0) @@ -1144,8 +1138,7 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, write(fd, p, Length); close(fd); - if (remainder) - memset(remainder + (p - BIOSImage), 0, Length); + SetRemainder(p - BIOSImage, Length, FALSE); p += Length; } @@ -1177,8 +1170,7 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, write(fd, p, Length); close(fd); - if (remainder) - memset(remainder + (p - BIOSImage), 0, Length); + SetRemainder(p - BIOSImage, Length, FALSE); p += Length; } @@ -1193,7 +1185,7 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, Module = (struct PhoenixModuleHeader *)p; if (!MODULE_SIGNATURE_INVALID(Module)) - PhoenixModule(BIOSImage, BIOSLength, p - BIOSImage, remainder); + PhoenixModule(BIOSImage, BIOSLength, p - BIOSImage); p += sizeof(struct PhoenixModuleHeader); } @@ -1223,8 +1215,7 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, write(fd, p, Length); close(fd); - if (remainder) - memset(remainder + (p - BIOSImage), 0, Length); + SetRemainder(p - BIOSImage, Length, FALSE); p += Length; } @@ -1258,8 +1249,7 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, write(fd, p, Length); close(fd); - if (remainder) - memset(remainder + (p - BIOSImage), 0, Length); + SetRemainder(p - BIOSImage, Length, FALSE); p += Length; } @@ -1289,39 +1279,11 @@ PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, Offset, Length); write(fd, BIOSImage + Offset, Length); close(fd); - if (remainder) - memset(remainder + Offset, 0, Length); + SetRemainder(Offset, Length, FALSE); } - /* Extract remaining data */ - if (remainder) { - /* Manually flag BCPSEGMENT data as remaining, just in case */ - Offset = BCPSegmentOffset; - Length = ((unsigned char *)ID) - (BIOSImage + Offset); - if ((Offset + Length) > BIOSLength) - Length = BIOSLength - Offset; - memset(remainder + Offset, 0x55, Length); - - fd = open("remainder.rom", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - fprintf(stderr, "Error: unable to open remainder.rom: %s\n\n", - strerror(errno)); - return FALSE; - } - printf("0x%05X (%6d bytes) -> remainder.rom\n", - Offset, Length); - if (remainder) { - Offset = 0; - Length = BIOSLength - 1; - while ((Offset <= Length) && ((remainder[Offset] == 0x00) || (remainder[Offset] == 0xff))) - Offset++; - while ((Offset <= Length) && ((remainder[Length] == 0x00) || (remainder[Length] == 0xff))) - Length--; - if ((Offset <= Length) && (Length > 0)) - write(fd, BIOSImage + Offset, Length); - } - close(fd); - } + /* Manually flag BCPSEGMENT data as remaining, just in case */ + SetRemainder(BCPSegmentOffset, ((unsigned char *)ID) - (BIOSImage + BCPSegmentOffset), TRUE); return TRUE; } diff --git a/bios_extract/src/systemsoft.c b/bios_extract/src/systemsoft.c index b4bd81f..efee6fa 100644 --- a/bios_extract/src/systemsoft.c +++ b/bios_extract/src/systemsoft.c @@ -90,8 +90,7 @@ SystemSoftExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, Length = le16toh(part->PackedLen); sprintf(filename, "ssbody_%05X.rom", Offset); if (Magic == 0x88FF) { - /* another tool called insydeco might be able to decompress - Insyde modules, but it's been lost to time... */ + /* nobody seems to know how this compression works */ strcpy(ModuleName, "Insyde module"); } else { IsPart = 1; @@ -225,6 +224,9 @@ SystemSoftExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, printf("\t\t\t%s\n", ModuleName); } + i = ((unsigned char *)part) - BIOSImage; + SetRemainder(i, Offset - i, FALSE); + close(fd); } diff --git a/biostools/extractors.py b/biostools/extractors.py index 7068e1b..60bda1e 100644 --- a/biostools/extractors.py +++ b/biostools/extractors.py @@ -329,18 +329,17 @@ class BIOSExtractor(Extractor): proc = None self.debug_print('Processing timed out on:', file_path) - # Assume failure if nothing was extracted. A lone boot block file also counts as a failure, - # as the extractors produce them before attempting to extract any actual BIOS modules. + # Assume failure if nothing was extracted. A lone remainder file also counts as a failure. dest_dir_files = os.listdir(dest_dir_0) num_files_extracted = len(dest_dir_files) if num_files_extracted < 1: return False - elif num_files_extracted == 1 and dest_dir_files[0] in ('amiboot.rom', 'ssboot.rom'): - # Remove boot block file so that the destination directory can be rmdir'd later. + elif num_files_extracted == 1 and dest_dir_files[0] == 'remainder.rom': + # Remove remainder file so that the destination directory can be rmdir'd later. util.remove_all(dest_dir_files, lambda x: os.path.join(dest_dir_0, x)) return False elif proc and proc.returncode == 86: - # We received the magic exit code indicating the Intel pipeline found + # We received the magic exit code that tells us the Intel pipeline found # an option ROM but not the main body. This could indicate a non-Intel # BIOS with LH5-compressed option ROMs. Check the files just in case. have_intelopt = have_intelbody = False @@ -355,6 +354,11 @@ class BIOSExtractor(Extractor): util.remove_all(dest_dir_files, lambda x: os.path.join(dest_dir_0, x)) return False + # A missing remainder.rom may indicate an extraction interrupted by a segfault + # or something else gone wrong. Copy the original file to its place for safety. + if 'remainder.rom' not in dest_dir_files: + util.hardlink_or_copy(file_path, os.path.join(dest_dir_0, 'remainder.rom')) + # Extract Award BIOS PhoenixNet ROS filesystem. if not proc or b'Found Award BIOS.' in proc.stdout: for dest_dir_file in dest_dir_files: