bios_extract: Replace Phoenix remainder, amiboot, etc. with an unified remainder saving API

This commit is contained in:
RichardG867
2022-04-16 01:45:56 -03:00
parent 2c20f4e441
commit cd036008e0
8 changed files with 162 additions and 157 deletions

View File

@@ -23,6 +23,7 @@
#define _GNU_SOURCE 1 /* for memmem */
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
@@ -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");

View File

@@ -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];
}

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -549,5 +549,5 @@ LH5Decode(unsigned char *PackedBuffer, int PackedBufferSize,
}
}
}
return 0;
return CompressedOffset;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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: