Import bios_extract fork source

This commit is contained in:
RichardG867
2021-12-15 20:46:41 -03:00
parent c6c754bc52
commit fa4467f4ab
43 changed files with 9251 additions and 1 deletions

12
.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
# Python code
__pycache__
*.pyc
# bios_extract
bios_extract/src/bios_extract
lh5_test
ami_slab
bcpvpd
efidecomp
*.o
*~

View File

@@ -1,6 +1,6 @@
86Box BIOS Tools
================
A full toolkit for analyzing and extracting x86 BIOS ROM images (mostly) within the context of the 86Box project.
A toolkit for analyzing and extracting x86 BIOS ROM images (mostly) within the context of the 86Box project.
## System requirements
@@ -16,6 +16,7 @@ A full toolkit for analyzing and extracting x86 BIOS ROM images (mostly) within
```
cd bios_extract
make
cd ..
```
3. Download the `uefiextract` tool from its [GitHub repository](https://github.com/LongSoft/UEFITool/releases) and place its executable on the repository's root directory. Prebuilt versions are only available for `x86_64`, but this tool is optional; UEFI extraction will not work without it.

8
bios_extract/.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
bios_extract
lh5_test
ami_slab
bcpvpd
efidecomp
*.o
*~
*.pyc

5
bios_extract/.gitreview Normal file
View File

@@ -0,0 +1,5 @@
[gerrit]
host=review.coreboot.org
port=29418
project=bios_extract
defaultbranch=master

294
bios_extract/COPYING Normal file
View File

@@ -0,0 +1,294 @@
Unless a COPYING file in a subdirectory or file-specific license headers
specify a different license, the following applies to all files in this
directory and all subdirectories.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License below for more details.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

55
bios_extract/Makefile Normal file
View File

@@ -0,0 +1,55 @@
MAKE = make
CFLAGS ?= -g -fpack-struct -Wall -O0
CC ?= gcc
all: bios_extract bcpvpd ami_slab xfv
SRCDIR = src
BIOS_EXTRACT_OBJS = $(SRCDIR)/lh5_extract.o $(SRCDIR)/lzari_extract.o \
$(SRCDIR)/lzhuf_extract.o $(SRCDIR)/lzss_extract.o \
$(SRCDIR)/ami.o $(SRCDIR)/award.o \
$(SRCDIR)/phoenix.o $(SRCDIR)/systemsoft.o \
$(SRCDIR)/bios_extract.o $(SRCDIR)/compat.o
bios_extract: $(BIOS_EXTRACT_OBJS)
$(CC) $(CFLAGS) $(BIOS_EXTRACT_OBJS) -o bios_extract
BCPVPD_OBJS = $(SRCDIR)/lzss_extract.o $(SRCDIR)/bcpvpd.o
bcpvpd: $(BCPVPD_OBJS)
$(CC) $(CFLAGS) $(BCPVPD_OBJS) -o bcpvpd
AMISLAB_OBJS = $(SRCDIR)/ami_slab.o
ami_slab: $(AMISLAB_OBJS)
$(CC) $(CFLAGS) $(AMISLAB_OBJS) -o ami_slab
XFV_OBJS = xfv/Decompress.o xfv/efidecomp.o
xfv: $(XFV_OBJS)
$(CC) -I xfv/ $(CFLAGS) -o xfv/efidecomp $(XFV_OBJS)
# just here to easily verify the functionality of the lh5 routine
LH5_TEST_OBJS = $(SRCDIR)/lh5_extract.o $(SRCDIR)/lh5_test.o
lh5_test: $(LH5_TEST_OBJS)
$(CC) $(CFLAGS) $(LH5_TEST_OBJS) -o lh5_test
gitconfig:
[ -d .git ]
mkdir -p .git/hooks
for hook in commit-msg pre-commit ; do \
if [ util/gitconfig/$$hook -nt .git/hooks/$$hook -o \
! -x .git/hooks/$$hook ]; then \
sed -e "s,%MAKE%,$(MAKE),g" util/gitconfig/$$hook > .git/hooks/$$hook; \
chmod +x .git/hooks/$$hook; \
fi; \
done
git config remote.origin.push HEAD:refs/for/master
(git config --global --includes user.name >/dev/null && git config --global --includes user.email >/dev/null) || (printf 'Please configure your name and email in git:\n\n git config --global user.name "Your Name Comes Here"\n git config --global user.email your.email@example.com\n'; exit 1)
clean:
rm -f $(SRCDIR)/*.o
rm -f bios_extract
rm -f bcpvpd
rm -f lh5_test
rm -f ami_slab
rm -f xfv/efidecomp xfv/*.o
.PHONY: all bios_extract bcpvpd ami_slab efidecomp lh5_test clean gitconfig

13
bios_extract/README.md Normal file
View File

@@ -0,0 +1,13 @@
bios_extract
============
Fork of the [coreboot bios_extract tool](https://github.com/coreboot/bios_extract) modified for our needs.
## Modifications
* Added some sanity checks
* Improved AMI, Award and Phoenix BIOS detection
* Improved AMIBIOS extraction
* Added AMIBIOS WinBIOS (12/15/93), 4 (07/25/94) and 5 (10/10/94) extraction
* Added LH5 extraction bruteforcing for Intel AMI Color fork
* Improved Phoenix extraction based on PHOEDECO
* Implemented SystemSoft extraction based on SYSODECO

View File

@@ -0,0 +1,44 @@
#!/usr/bin/perl
#
# Update the onboard NIC mac address in a coreboot rom image for mcp55-based boards
#
# This program is free software (GPLv2 or higher).
#
# 2008-01-30 Ward Vandewege (ward@gnu.org)
my $mac = $ARGV[0];
my $file = $ARGV[1];
if (($mac eq '') or ($file eq '')) {
print "\nSyntax: $0 <mac address> <rom image>\n";
exit 1;
}
if (! -f $file) {
print "\nSyntax: $0 <mac address> <rom image>\n";
print "\nERROR: Could not find file '$file'.\n\n";
exit 1;
}
if (!($mac =~ /^[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}$/)) {
print "\nSyntax: $0 <mac address> <rom image>\n";
print "\nERROR: The mac address you specified ($mac) is not a valid mac address.\n\n";
exit 1;
}
my @mac = split(/:/,$mac);
my $newmac = '';
for (my $c = 5; $c >= 0; $c--) {
$newmac .= chr(hex($mac[$c]));
}
open(ROMIMAGE,"+<",$file) or die "Can't open file $file for writing\n";
seek(ROMIMAGE,-48,2);
print ROMIMAGE $newmac;
close(ROMIMAGE);
print "Mac address succesfully updated to $mac in $file\n";
exit 0;

View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python
#
# parse CSMCORE.raw from AMI UEFI
# 3-clause BSD license
# roxfan@skynet.be
import struct, sys
if len(sys.argv) < 2:
fn = "CSMCORE.raw"
else:
fn = sys.argv[1]
f = open(fn, "rb")
while True:
print "%08X"%f.tell(),
hdr = f.read(10)
if len(hdr) == 0:
break
typ, vid, did, size = struct.unpack("<HHHI", hdr)
if (typ & 0xFF00) == 0xA000:
#print "Multi-ID module"
count = typ & 0xFF
print "M %2X %04X %04X %8X" % (count, vid, did, size),
for i in range(count):
typ, vid, did = struct.unpack("<HHH", f.read(6))
print "\n %4X %04X %04X " % (typ, vid, did),
else:
print "%4X %04X %04X %8X" % (typ, vid, did, size),
fname = "csm_%02X_%04X_%04X.rom" % (typ, vid, did)
print " => %s" % fname
if size == 0xFFFFFFFF:
d = f.read()
else:
d = f.read(size)
open(fname, "wb").write(d)

40
bios_extract/decap.sh Normal file
View File

@@ -0,0 +1,40 @@
#!/bin/sh
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
# Takes a path to a file as first and only argument, removes the first 2048 B
# from that file and stores the result with the same name plus a '.bin' suffix.
# Useable to remove the header from UEFI Capsule files to use the resulting
# binary with flashrom.
main () {
if [ "$#" -lt 1 -o ! -r "$1" ]; then
echo "Removes the 2048 B header of UEFI Capsule files.\n"\
"Usage: $0 <FILE.CAP>"
return 1
fi
capsize=$(wc -c "$1" | cut -f 1 -d ' ')
binsize=$(($capsize-2048))
ispowoftwo=$(($binsize & ($binsize-1)))
if [ $ispowoftwo -ne 0 -o $binsize -eq 0 ]; then
echo "The size of the resulting file would not be a power of 2 (but $binsize B)."
return 1
fi
dd bs=2048 skip=1 if="$1" of="$1.bin"
}
main $*

View File

@@ -0,0 +1,121 @@
#!/usr/bin/env python2
# Dell/Phoenix ROM BIOS PLUS unpacker
# 2012-09-12 version 0.1
# 2012-10-10 version 0.2 added support for older BIOSes with 16-bit length (Dell Inspiron 1100)
# 3-clause BSD license
# roxfan@skynet.be
import array
import struct
import sys
def memcpy(arr1, off1, arr2, off2, count):
while count:
if off1 < len(arr1):
arr1[off1] = arr2[off2]
elif off1 == len(arr1):
arr1.append(arr2[off2])
else:
raise Exception("Trying to write out of bounds")
off1 += 1
off2 += 1
count -=1
# looks like some lzss variation
def dell_unpack(indata):
srcoff = 0
dstoff = 0
src = array.array('B', indata)
dst = array.array('B')
inlen = len(indata)
while srcoff < inlen:
b = src[srcoff]
nibl, nibh = b & 0x0F, (b >> 4) & 0x0F
srcoff += 1
if nibl:
if nibl == 0xF:
al = src[srcoff]
ah = src[srcoff+1]
srcoff += 2
cx = nibh | (ah << 4)
count = (cx & 0x3F) + 2
delta = ((ah >> 2) << 8) | al
else:
count = nibl + 1
delta = (nibh << 8) | src[srcoff]
srcoff += 1
memcpy(dst, dstoff, dst, dstoff - delta - 1, count)
dstoff += count
elif nibh == 0x0E:
count = src[srcoff] + 1
srcoff += 1
memcpy(dst, dstoff, dst, dstoff - 1, count)
dstoff += count
else:
if nibh == 0x0F:
count = src[srcoff] + 15
srcoff += 1
else:
count = nibh + 1
memcpy(dst, dstoff, src, srcoff, count)
dstoff += count
srcoff += count
return dst.tostring()
mod_types = {
0x01: "Main ROM",
0x0C: "Microcode update",
}
print "Dell/Phoenix ROM BIOS PLUS unpacker"
if len(sys.argv) < 2:
print "Usage: dell_unpack.py bios.bin [offset]"
sys.exit(1)
fname = sys.argv[1]
offs = 0
f = open(fname, "rb").read()
if len(sys.argv) > 2:
offs = int(sys.argv[2], 16)
else:
offs = f.find("\xF0\x00Copyright 1985-\x02\x04\xF0\x0F8 Phoenix Technologies Ltd.")
if offs == -1:
print "Does not look like a Dell/Phoenix ROM BIOS PLUS"
sys.exit(2)
if f[offs-5] == '\x01':
hlen = 5 # 32-bit length
offs -= 5
fmt = "<BI"
elif f[offs-3] == '\x01':
hlen = 3 # 16-bit length
offs -= 3
fmt = "<BH"
else:
print "Unhandled format!"
sys.exit(1)
print "Found compressed module at %08X" % offs
if offs > 0:
fn = "EC.bin"
print "%08X EC code, %08X %s" % (0, offs, fn)
open(fn, "wb").write(f[:offs])
while True:
type, leng = struct.unpack(fmt, f[offs:offs+hlen])
print "%08X type %02X" % (offs, type),
offs += hlen
if type == 0xFF:
print "<end of chain>"
break
data = f[offs:offs+leng]
offs += leng
if type != 0xC:
odata = dell_unpack(data)
else:
odata = data
print " %08X -> %08X" % (leng, len(odata)),
fn = "mod_%02X.bin" % type
print " %s" % fn,
if type in mod_types:
print "(%s)" % mod_types[type]
else:
print ""
open(fn, "wb").write(odata)

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python2
# HP Compaq 6715b ROM unpacker by roxfan
# compressed data begins like this:
# 0000010000: 01 00 14 01 70 00 00 00 | 60 00 00 00 00 00 02 00 O .Op . O
# 0000010010: 50 4F 53 54 FF B8 00 20 | 8E D8 66 B8 10 FF 20 00 POST.. ..f...
import struct, array, sys
def unpack1(cdata, ulen):
pos = 0
odata = ""
while ulen:
a = ord(cdata[pos])
# print "%x: %x" % (pos, a)
pos += 1
if a == 0xFF:
odata += cdata[pos:pos+8]
ulen -= 8
pos += 8
else:
mask = a | 0x100
while mask and ulen:
# print hex(mask), hex(pos)
b = mask & 1
mask >>= 1
if mask == 0:
break
if b:
odata += cdata[pos]
pos += 1
ulen -= 1
else:
delta = ord(cdata[pos])
pos += 1
delta |= ord(cdata[pos])<<8
pos += 1
count = (delta & 0xF) + 3
delta >>= 4
# print "d: %d, c: %d" % (delta, count)
opos = len(odata)-delta
while count:
odata += odata[opos]
opos += 1
count -= 1
ulen -= 1
return odata
f = open(sys.argv[1], "rb")
f.seek(0x10000)
while True:
flags, ulen, clen, dest = struct.unpack("<IIII", f.read(0x10))
comp = flags & 0xFF
if comp > 1:
break
hdrlen = (flags>>16) & 0xFF
unk = (flags>>24) & 0xFF
print "comp: %d, hdr len: 0x%X, unk: %d, ulen: 0x%X, clen: 0x%X, dest: 0x%X" % (comp, hdrlen, unk, ulen, clen,
dest)
extra = f.read(hdrlen-0x10).rstrip('\0')
print " %s" % extra
cdata = f.read(clen)
fname = "%04X_%s.bin" % (dest>>4, extra)
if comp == 1:
cdata = unpack1(cdata, ulen)
open(fname, "wb").write(cdata)

View File

@@ -0,0 +1,353 @@
#!/usr/bin/python
import sys
import struct
import codecs
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
STRING_TABLE = 0x6F80 # FaithX
STRING_TABLE = 0x10b60 # Original
#STRING_TABLE = 0x108e0 + 12 # No idea
STRING_TABLE = 0x10b30 # Mine?
storage_map = {}
FORMS = [
("Exit", 0xC600),
#('Exit', 0xc640),
#('Boot', 0xc6f0),
#('Power', 0xc810),
#('Security',0xd140),
#('Advanced',0xd390),
#('Main', 0x106b0),
#('OEM', 0x10a20)
]
def fguid(s):
a, b, c, d = struct.unpack("<IHH8s", s)
ds = ''.join('%02x' % ord(c) for c in d)
return "%08x-%04x-%04x-%s-%s" % (a, b, c, ds[:4], ds[4:])
def hexdump(s):
return ' '.join('%02x' % ord(c) for c in s)
class HiiPack(object):
def __init__(self, data, offset):
self.offset = offset
#print " Constructing HiiPack at 0x%x" % offset
hdr = data[offset:offset + 6]
#print " Has HDRlen: 0x%x DataLen: 0x%x" % (len(hdr), len(data))
#print repr(hdr)
self.length, self.type = struct.unpack("<IH", hdr)
#print " Real Length: 0x%x, type = 0x%x" % (self.length, self.type)
#print " Table end 0x%x" % (offset+len(hdr)+self.length)
self.end_offset = offset + len(hdr) + self.length
assert self.length + len(hdr) < len(data)
self.data = data[offset + 6:offset + self.length]
class StringTable(HiiPack):
def __init__(self, data, offset):
#print "Constructing StringTable"
HiiPack.__init__(self, data, offset)
assert self.type == 0x2
self.strings = []
hdr = self.data[:16]
lnoff, plnoff, count, attributes = struct.unpack("<IIII", hdr)
#print type(hdr), len(hdr), len(self.data), count
offsets = struct.unpack("<%dI" % count, self.data[16:16 + count * 4])
self.name = self._getstring(lnoff)
self.printablename = self._getstring(plnoff)
for i in range(count):
self.strings.append(self._getstring(offsets[i]))
def _getstring(self, off):
return self.data[off - 6:].decode('utf-16le').split('\0')[0]
def __getitem__(self, a):
return self.strings.__getitem__(a)
def showinfo(self, ts=''):
print ts + "String table:"
print ts + " Language: %s (%s)" % (self.name, self.printablename)
print ts + " String count: %d" % len(self.strings)
class FormOp(object):
EFI_IFR_FORM_OP = 0x01
EFI_IFR_SUBTITLE_OP = 0x02
EFI_IFR_TEXT_OP = 0x03
EFI_IFR_GRAPHIC_OP = 0x04
EFI_IFR_ONE_OF_OP = 0x05
EFI_IFR_CHECKBOX_OP = 0x06
EFI_IFR_NUMERIC_OP = 0x07
EFI_IFR_PASSWORD_OP = 0x08
EFI_IFR_ONE_OF_OPTION_OP = 0x09 # ONEOF OPTION field
EFI_IFR_SUPPRESS_IF_OP = 0x0A
EFI_IFR_END_FORM_OP = 0x0B
EFI_IFR_HIDDEN_OP = 0x0C
EFI_IFR_END_FORM_SET_OP = 0x0D
EFI_IFR_FORM_SET_OP = 0x0E
EFI_IFR_REF_OP = 0x0F
EFI_IFR_END_ONE_OF_OP = 0x10
EFI_IFR_END_OP = EFI_IFR_END_ONE_OF_OP
EFI_IFR_INCONSISTENT_IF_OP = 0x11
EFI_IFR_EQ_ID_VAL_OP = 0x12
EFI_IFR_EQ_ID_ID_OP = 0x13
EFI_IFR_EQ_ID_LIST_OP = 0x14
EFI_IFR_AND_OP = 0x15
EFI_IFR_OR_OP = 0x16
EFI_IFR_NOT_OP = 0x17
EFI_IFR_END_IF_OP = 0x18 # for endif of
# inconsistentif,
# suppressif, grayoutif
EFI_IFR_GRAYOUT_IF_OP = 0x19
EFI_IFR_DATE_OP = 0x1A
EFI_IFR_TIME_OP = 0x1B
EFI_IFR_STRING_OP = 0x1C
EFI_IFR_LABEL_OP = 0x1D
EFI_IFR_SAVE_DEFAULTS_OP = 0x1E
EFI_IFR_RESTORE_DEFAULTS_OP = 0x1F
EFI_IFR_BANNER_OP = 0x20
EFI_IFR_INVENTORY_OP = 0x21
EFI_IFR_EQ_VAR_VAL_OP = 0x22
EFI_IFR_ORDERED_LIST_OP = 0x23
EFI_IFR_VARSTORE_OP = 0x24
EFI_IFR_VARSTORE_SELECT_OP = 0x25
EFI_IFR_VARSTORE_SELECT_PAIR_OP = 0x26
EFI_IFR_LAST_OPCODE = EFI_IFR_VARSTORE_SELECT_PAIR_OP
EFI_IFR_OEM_OP = 0xFE
EFI_IFR_NV_ACCESS_COMMAND = 0xFF
INDENTS = {
#0 : 0,
#0x73 : 0,
EFI_IFR_FORM_OP: 1,
EFI_IFR_SUBTITLE_OP: 0,
EFI_IFR_TEXT_OP: 0,
EFI_IFR_GRAPHIC_OP: 0,
EFI_IFR_ONE_OF_OP: 1,
EFI_IFR_CHECKBOX_OP: 0,
EFI_IFR_NUMERIC_OP: 0,
EFI_IFR_PASSWORD_OP: 0,
EFI_IFR_ONE_OF_OPTION_OP: 0,
EFI_IFR_SUPPRESS_IF_OP: 1,
EFI_IFR_END_FORM_OP: -1,
EFI_IFR_HIDDEN_OP: 0,
EFI_IFR_END_FORM_SET_OP: -1,
EFI_IFR_FORM_SET_OP: 1,
EFI_IFR_REF_OP: 0,
EFI_IFR_END_OP: -1,
EFI_IFR_INCONSISTENT_IF_OP: 0,
EFI_IFR_EQ_ID_VAL_OP: 0,
EFI_IFR_EQ_ID_ID_OP: 0,
EFI_IFR_EQ_ID_LIST_OP: 0,
EFI_IFR_AND_OP: 0,
EFI_IFR_OR_OP: 0,
EFI_IFR_NOT_OP: 0,
EFI_IFR_END_IF_OP: -1,
EFI_IFR_GRAYOUT_IF_OP: 1,
EFI_IFR_DATE_OP: 0,
EFI_IFR_TIME_OP: 0,
EFI_IFR_STRING_OP: 0,
EFI_IFR_LABEL_OP: 0,
EFI_IFR_SAVE_DEFAULTS_OP: 0,
EFI_IFR_RESTORE_DEFAULTS_OP: 0,
EFI_IFR_BANNER_OP: 0,
EFI_IFR_INVENTORY_OP: 0,
EFI_IFR_EQ_VAR_VAL_OP: 0,
EFI_IFR_ORDERED_LIST_OP: 0,
EFI_IFR_VARSTORE_OP: 0,
EFI_IFR_VARSTORE_SELECT_OP: 0,
EFI_IFR_VARSTORE_SELECT_PAIR_OP: 0,
EFI_IFR_LAST_OPCODE: 0,
EFI_IFR_OEM_OP: 0,
EFI_IFR_NV_ACCESS_COMMAND: 0,
}
def __init__(self, data, stable):
self.stable = stable
self.opcode, self.length = struct.unpack("<BB", data[:2])
self.payload = data[2:self.length]
if self.opcode not in self.INDENTS:
raise RuntimeError("Undefined opcode: 0x%x" % self.opcode)
self.indent = self.INDENTS[self.opcode]
def get_info(self):
guid, fsid, hid, cb, cls, subcls, nvsize = struct.unpack(
"<16sHHQHHH", self.payload)
return self.stable[fsid]
def showinfo(self, s, ts=''):
if self.opcode == self.EFI_IFR_FORM_OP:
id, title = struct.unpack("<HH", self.payload)
print ts + "Form ID:0x%04x Name:'%s'" % (id, s[title])
elif self.opcode == self.EFI_IFR_SUBTITLE_OP:
print ts + "Subtitle: '%s'" % s[struct.unpack("<H",
self.payload)[0]]
elif self.opcode == self.EFI_IFR_TEXT_OP:
if len(self.payload) != 9:
print ts + "BROKEN TEXT OP %r" % self.payload
else:
hid, tid, t2id, flags, key = struct.unpack(
"<HHHBH", self.payload)
print ts + "Text: '%s','%s' Flags:0x%x Key:0x%x" % (
s[tid], s[t2id], flags, key)
if s[hid] and s[hid] != ' ':
print ts + "\Help text: '%s'" % s[hid]
elif self.opcode == self.EFI_IFR_FORM_SET_OP:
guid, fsid, hid, cb, cls, subcls, nvsize = struct.unpack(
"<16sHHQHHH", self.payload)
print ts + "Form Set '%s' Class %d-%d NvSize 0x%x Callback 0x%x" % (s[fsid], cls, subcls, nvsize, cb)
print ts + "\GUID: %s" % fguid(guid)
if s[hid] and s[hid] != ' ':
print ts + "\Help text: '%s'" % s[hid]
elif self.opcode == self.EFI_IFR_END_FORM_SET_OP:
print ts + "End Form Set"
elif self.opcode == self.EFI_IFR_END_FORM_OP:
print ts + "End Form"
elif self.opcode == self.EFI_IFR_GRAYOUT_IF_OP:
print ts + "Grayout If"
elif self.opcode == self.EFI_IFR_SUPPRESS_IF_OP:
print ts + "Suppress If"
elif self.opcode == self.EFI_IFR_END_IF_OP:
print ts + "End If", hexdump(self.payload)
elif self.opcode == self.EFI_IFR_EQ_ID_VAL_OP:
qid, width, val = struct.unpack("<HBH", self.payload)
print ts + "EQ [0x%x<%d>] == 0x%x" % (qid, width, val)
elif self.opcode == self.EFI_IFR_EQ_ID_ID_OP:
qid, width, qid2, width2, val = struct.unpack(
"<HBHB", self.payload)
print ts + "EQ [0x%x<%d>] == [0x%x.%d]" % (
qid, width, qid2, width2, val)
elif self.opcode == self.EFI_IFR_EQ_ID_LIST_OP:
qid, width, length = struct.unpack("<HBH", self.payload[:5])
l = struct.unpack("<%dH" % length, self.payload[5:])
print ts + "LIST [0x%x<%d>] in (%s)" % (
qid, width, ','.join(["0x%x" % i for i in l]))
elif self.opcode == self.EFI_IFR_AND_OP:
print ts + "AND"
elif self.opcode == self.EFI_IFR_OR_OP:
print ts + "OR"
elif self.opcode == self.EFI_IFR_NOT_OP:
print ts + "NOT"
elif self.opcode == self.EFI_IFR_ONE_OF_OP:
qid, width, pid, hid = struct.unpack("<HBHH", self.payload)
storage_map[qid] = s[pid]
print ts + "One Of [0x%x<%d>] '%s'" % (qid, width, s[pid])
if s[hid] and s[hid] != ' ':
print ts + "\Help text: '%s'" % s[hid]
elif self.opcode == self.EFI_IFR_ONE_OF_OPTION_OP:
oid, value, flags, key = struct.unpack("<HHBH", self.payload)
print ts + "Option '%s' = 0x%x Flags 0x%x Key 0x%x" % (
s[oid], value, flags, key)
elif self.opcode == self.EFI_IFR_END_ONE_OF_OP:
print ts + "End One Of"
elif self.opcode == self.EFI_IFR_LABEL_OP:
lid = struct.unpack("<H", self.payload)[0]
print ts + "Label ID: 0x%x" % lid
elif self.opcode == self.EFI_IFR_REF_OP:
fid, pid, hid, flags, key = struct.unpack("<HHHBH", self.payload)
print ts + "Reference: '%s' Form ID 0x%x Flags 0x%x Key 0x%x" % (
s[pid], fid, flags, key)
if s[hid] and s[hid] != ' ':
print ts + "\Help text: '%s'" % s[hid]
elif self.opcode in (self.EFI_IFR_TIME_OP, self.EFI_IFR_DATE_OP, self.EFI_IFR_NUMERIC_OP):
qid, width, pid, hid, flags, key, min, max, step, default = struct.unpack("<HBHHBHHHHH", self.payload)
t = {self.EFI_IFR_TIME_OP: 'Time', self.EFI_IFR_DATE_OP:
'Date', self.EFI_IFR_NUMERIC_OP: 'Numeric'}[self.opcode]
print ts + "%s: '%s' [0x%x<%d>] %d-%d Step %d Default %d Flags 0x%x" % (t, s[pid], qid, width, min, max, step, default, flags)
if s[hid] and s[hid] != ' ':
print ts + "\Help text: '%s'" % s[hid]
elif self.opcode == self.EFI_IFR_PASSWORD_OP:
qid, width, pid, hid, flags, key, mins, maxs, encoding = struct.unpack("<HBHHBHBBH", self.payload)
storage_map[qid] = s[pid]
print ts + "Password: '%s' [0x%x<%d>] Flags 0x%x Key 0x%x Size %d-%d Encoding %d" % (s[pid], qid, width, flags, key, mins, maxs, encoding)
if s[hid] and s[hid] != ' ':
print ts + "\Help text: '%s'" % s[hid]
else:
print ts + "Opcode 0x%x (%d)" % (
self.opcode, self.length), hexdump(self.payload)
class Form(HiiPack):
def __init__(self, data, offset, stable=None):
#print "Constructing form.."
HiiPack.__init__(self, data, offset)
data = self.data
self.opcodes = []
while len(data):
op = FormOp(data, stable)
#print "Created ", len(self.opcodes), op.length
assert op.length
data = data[op.length:]
self.opcodes.append(op)
def fetch_opcodes(self, opcode_wanted):
return filter(lambda x: x.opcode == opcode_wanted, self.opcodes)
def __repr__(self):
formset = self.fetch_opcodes(FormOp.EFI_IFR_FORM_SET_OP)
assert len(formset) == 1
return "<FormSet name=%s offset=0x%x>" % (formset[0].get_info(), self.offset)
return "%s" % formset
def locate_formset(self):
pass
def showinfo(self, stringtable, ts=''):
ind = 0
in_if = False
fstk = []
for op in self.opcodes:
if op.opcode == op.EFI_IFR_FORM_OP:
fstk.append(ind)
if op.indent < 0:
ind += op.indent
ots = ts + ' ' * ind
if in_if and op.opcode in (op.EFI_IFR_SUPPRESS_IF_OP, op.EFI_IFR_GRAYOUT_IF_OP):
ots = ts + ' ' * (ind - 1) + '+'
try:
op.showinfo(stringtable, ots)
#except:
# print ts+"ERROR DECODING OPCODE 0x%x LEN 0x%x"%(op.opcode, op.length)
finally:
pass
if (not in_if or op.opcode not in (op.EFI_IFR_SUPPRESS_IF_OP, op.EFI_IFR_GRAYOUT_IF_OP)) and op.indent > 0:
ind += op.indent
if op.opcode in (op.EFI_IFR_SUPPRESS_IF_OP, op.EFI_IFR_GRAYOUT_IF_OP):
in_if = True
elif op.opcode == op.EFI_IFR_END_IF_OP:
in_if = False
if op.opcode == op.EFI_IFR_END_FORM_OP:
xind = fstk.pop()
if xind != ind:
print "WARNING: Indentation mismatch"
ind = xind
#filename = "vt_bios.fd"
#filename = sys.argv[1]
#filename = "../test1/fv-00000010.bin"
#filename = "../test1/fe3542fe-c1d3-4ef8-7c65-8048606ff670-SetupUtility.sec0.sub2.pe"
#pe = open(filename, "rb").read()
def dump_setup(pe):
strings = StringTable(pe, STRING_TABLE)
strings.showinfo()
for fn, off in FORMS[0:]:
print
print "Reading form '%s'" % fn, off
f = Form(pe, off)
#f.showinfo(strings, ' ')
#print "Storage map:"
#for k in sorted(storage_map.keys()):
#print " 0x%x: %s"%(k,storage_map[k])

View File

@@ -0,0 +1,177 @@
#! /usr/bin/env python
from __future__ import with_statement
from util import from_b64
import sys
import struct
def fguid(s):
a, b, c, d, e = struct.unpack("<IHHH6s", s)
return "%08x-%04x-%04x-%04x-%s" % (a, b, c, d, ''.join('%02x' % ord(c) for c in e))
class FFSSection(object):
MAGIC_GUIDEF = from_b64("sM0b/DF9qkmTaqRgDZ3Qgw")
def __init__(self, data):
hdr = data[:0x4]
self.size, self.type = struct.unpack("<3sB", hdr)
self.size = struct.unpack("<I", self.size + "\x00")[0]
data = data[0x4:self.size]
self.data = data
self.sections = []
self.name = None
if self.type == 0x02:
dguid = self.data[:0x10]
if dguid == FFSSection.MAGIC_GUIDEF:
data = data[0x18:]
while len(data):
s = FFSSection(data)
self.sections.append(s)
data = data[(s.size + 3) & (~3):]
elif self.type == 0x15:
self.name = self.data.decode("utf-16le").split("\0")[0]
TI = {
0x01: ("compression", "Compression section"),
0x02: ("guiddef", "GUID-defined section"),
0x03: ("disp", "Disposable section"),
0x10: ("pe", "PE Image"),
0x11: ("pic.pe", "PE PIC Image"),
0x12: ("te", "TE Image"),
0x13: ("dxe.depex", "DXE Dependency Expression"),
0x14: ("ver", "Version"),
0x15: ("name", lambda self: "User Interface name: '%s'" % self.name),
0x16: ("16bit", "Compatibility16"),
0x17: ("fvi", "Firmware Volume Image"),
0x18: ("guid", "Freeform Subtype GUID"),
0x19: ("raw", "RAW"),
0x1b: ("pei.depex", "PEI Dependency Expression"),
0x1c: ("smm.depex", "SMM Dependency Expression"),
}
def get_type_info(self):
if self.type not in self.TI:
return ("unknown.0x%02x.bin" % self.type,
"<Unknown type=0x%02x>" % self.type)
small, large = self.TI[self.type]
if callable(large):
large = large(self)
return small, large
def showinfo(self, ts=''):
if self.type == 0x02:
print ts + "GUID-defined section"
if self.sections:
print ts + " CRC32 subsection container:"
for i, s in enumerate(self.sections):
print ts + " Subsection %d: type 0x%02x, size 0x%x" % (
i, s.type, s.size)
s.showinfo(ts + " ")
else:
print ts + self.get_type_info()[1]
def dump(self, base):
if self.sections:
for i, s in enumerate(self.sections):
s.dump("%s.sub%d" % (base, i))
return
name = "%s.%s" % (base, self.get_type_info()[0])
with open(name, "wb") as fd:
fd.write(self.data)
print name
def __repr__(self):
return "<FFS Section name=%s type=%s size=0x%x>" % (self.name, self.get_type_info()[0], self.size)
class FFSFile(object):
def __repr__(self):
return "<FFS File size=0x%x(0x%x) type=0x%02x state=0x%02x GUID=%s>" % (self.size - 0x18, len(self.data), self.type, self.state, fguid(self.guid))
def __init__(self, data):
hdr = data[:0x18]
self.guid, self.checksum, self.type, self.attributes, self.size, self.state = struct.unpack("<16sHBB3sB", hdr)
self.size = struct.unpack("<I", self.size + "\x00")[0]
data = data[0x18:self.size]
self.data = data
self.sections = []
if self.type == 0xf0:
# used to set self.sections
pass
else:
while len(data):
s = FFSSection(data)
self.sections.append(s)
data = data[(s.size + 3) & (~3):]
def showinfo(self, ts=''):
print ts + "GUID:", fguid(self.guid)
print ts + "Size: 0x%x (data 0x%x)" % (self.size, len(self.data))
print ts + "Type: 0x%02x" % self.type
print ts + "Attributes: 0x%02x" % self.attributes
print ts + "State: 0x%02x" % (self.state ^ 0xFF)
if self.sections:
for i, s in enumerate(self.sections):
print ts + " Section %d: type 0x%02x, size 0x%x" % (
i, s.type, s.size)
s.showinfo(ts + " ")
else:
print ts + "This is a padding file"
def dump(self):
if self.sections:
appn = ""
for s in self.sections:
if s.name is not None:
appn = "-" + s.name
elif s.sections is not None:
for s in s.sections:
if s.name is not None:
appn = "-" + s.name
for i, s in enumerate(self.sections):
s.dump("%s%s.sec%d" % (fguid(self.guid), appn, i))
def __iter__(self):
return iter(self.sections)
class FS(object):
def __init__(self, data):
self.files = []
while len(data) and data[:16] != ("\xff" * 16):
f = FFSFile(data)
self.files.append(f)
data = data[(f.size + 7) & (~7):]
def showinfo(self, ts=''):
for i, f in enumerate(self.files):
print ts + "File %d:" % i
f.showinfo(ts + ' ')
def dump(self):
for f in self.files:
f.dump()
def __iter__(self):
return iter(self.files)
if __name__ == "__main__":
f = open(sys.argv[1], "rb")
d = f.read()
fs = FS(d)
print "Filesystem:"
fs.showinfo(' ')
print "Dumping..."
fs.dump()

View File

@@ -0,0 +1,230 @@
#! /usr/bin/env python
# Written for LZMA Utils. Widely available for different distros, see
# Written and tested with version 4.32.7 on x86_64.
# Untested on x86_32.
# http://tukaani.org/lzma/download
# Copyright (c) 2009 d6z <d6z@tnymail.com>
# MIT License.
#~ Permission is hereby granted, free of charge, to any person
#~ obtaining a copy of this software and associated documentation
#~ files (the "Software"), to deal in the Software without
#~ restriction, including without limitation the rights to use,
#~ copy, modify, merge, publish, distribute, sublicense, and/or sell
#~ copies of the Software, and to permit persons to whom the
#~ Software is furnished to do so, subject to the following
#~ conditions:
#~ The above copyright notice and this permission notice shall be
#~ included in all copies or substantial portions of the Software.
#~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
#~ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#~ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
#~ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#~ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
#~ OTHER DEALINGS IN THE SOFTWARE.
from ctypes import (CDLL, c_int8, c_uint32, c_uint64, c_void_p, c_char_p,
c_size_t, cast, pointer, POINTER, Structure, create_string_buffer)
from ctypes.util import find_library
from hashlib import md5
def md5sum(data):
return md5(data).hexdigest()
class lzmadec_info_t(Structure):
_fields_ = [('uncompressed_size', c_uint64),
('dictionary_size', c_uint32),
('internal_data_size', c_uint32),
('is_streamed', c_uint32),
('pb', c_uint32),
('lp', c_uint32),
('lc', c_uint32), ]
def __repr__(self):
bits = []
for fieldname, fieldtype in self._fields_:
bits.append("%s=%s" % (fieldname, getattr(self, fieldname)))
return "<lmzadec_info %s>" % ", ".join(bits)
lzmadec_info_p = POINTER(lzmadec_info_t)
class lzmadec_stream_t(Structure):
_fields_ = [('next_in', c_char_p),
('avail_in', c_size_t),
('total_in', c_uint64),
('next_out', c_char_p),
('avail_out', c_size_t),
('total_out', c_uint64),
('state', c_void_p),
('lzma_alloc', c_void_p),
('lzma_free', c_void_p),
('opaque', c_void_p)]
lzmadec_stream_p = POINTER(lzmadec_stream_t)
class ctypes_function(object):
def __init__(self, lib, restype, argtypes):
self.lib, self.restype, self.argtypes = lib, restype, argtypes
def __call__(self, function):
func_name = function.__name__
f = getattr(self.lib, func_name)
f.restype, f.argtypes = self.restype, self.argtypes
return f
library_path = find_library("lzmadec")
assert library_path, (
"Couldn't find `liblzmadec.so`. Please install lzma_utils.\n"
" it can be found at http://tukaani.org/lzma/download"
)
lzma = CDLL(library_path)
# I tried the simpler lzmadec_buffer function but it didn't like that I was
# providing too much data and crashed, so I switched to the stream instead.
@ctypes_function(lzma, c_int8, [lzmadec_info_p, c_char_p, c_size_t])
def lzmadec_buffer_info():
pass
@ctypes_function(lzma, c_int8, [lzmadec_stream_p])
def lzmadec_init():
pass
@ctypes_function(lzma, c_int8, [lzmadec_stream_p, c_int8])
def lzmadec_decode():
pass
@ctypes_function(lzma, c_int8, [lzmadec_stream_p])
def lzmadec_end():
pass
#
# USEFUL CODE STARTS HERE
#
# Based on concepts from scanlzma.c
# scanlzma, scan for lzma compressed data in stdin and echo it to stdout.
# Copyright (C) 2006 Timo Lindfors
def find_lzma_headers(buffer):
MAGIC_CHAR = chr(0x5D)
position = 0
positions = []
while position < len(buffer) and MAGIC_CHAR in buffer[position:]:
position = buffer.index(MAGIC_CHAR, position) + 1
if (ord(buffer[position + 3]) < 0x20 and
(buffer[position + 9:].startswith("\x00" * 3) or
buffer[position + 4:].startswith("\xFF" * 8))):
positions.append(position - 1)
return positions
def lzma_decompressed_size(buffer):
"Given `buffer`, return the decompressed size"
lzmadec_info = lzmadec_info_t()
result = lzmadec_buffer_info(pointer(lzmadec_info), buffer, len(buffer))
assert not result, "lzmadec_buffer_info failed"
#print lzmadec_info
assert lzmadec_info.dictionary_size > lzmadec_info.uncompressed_size, (
"This probably doesn't make sense.."
)
#print "Here..", lzmadec_info
return lzmadec_info.uncompressed_size
def lzma_decode(input_buffer):
"""
`input_buffer`: string.
Return Value: (decompressed string, amount of `input_buffer` used)
"""
result_size = lzma_decompressed_size(input_buffer)
assert result_size
result_data = create_string_buffer(result_size)
lzmadec_stream = lzmadec_stream_t()
assert not lzmadec_init(lzmadec_stream)
lzmadec_stream.next_in = input_buffer
lzmadec_stream.avail_in = len(input_buffer)
lzmadec_stream.next_out = cast(result_data, c_char_p)
lzmadec_stream.avail_out = result_size
result = lzmadec_decode(lzmadec_stream, 1)
#s = lzmadec_stream
#print s.avail_in, s.total_in, s.avail_out, s.total_out
assert not lzmadec_end(lzmadec_stream)
result_data = result_data.raw
amount_read = lzmadec_stream.total_in
assert result == 1
return result_data, amount_read
def get_lzma_chunks(input_buffer):
"""
Scans `input_buffer` for LZMA-like data.
Returns a list of (position, "the data found decompressed").
"""
ph = possible_headers = find_lzma_headers(input_buffer)
# Not a real header location, but allows one last iteration to end of file
# in the following loop
ph.append(len(input_buffer) - 1)
result = []
for this_header, next_header in zip(ph, ph[1:]):
try:
#print this_header, next_header
data, length = lzma_decode(input_buffer[this_header:next_header])
except AssertionError:
continue
result.append((this_header, data))
return result
def test():
bios_data = open("data/original_bios_backup.fd", "rb").read()
results = get_lzma_chunks(bios_data)
print map(md5sum, zip(*results)[1])
#~ headers = find_lzma_headers(bios_data)
#~ decompr_data, amoun_read = lzma_decode(bios_data[headers[0]:])
#~ print md5sum(decompr_data)
if __name__ == "__main__":
test()

View File

@@ -0,0 +1,473 @@
#! /usr/bin/env python
# Copyright (c) 2009 d6z <d6z@tnymail.com>
# MIT License. Based on code found found at
# http://marcansoft.com/blog/2009/06/enabling-intel-vt-on-the-aspire-8930g/
#~ Permission is hereby granted, free of charge, to any person
#~ obtaining a copy of this software and associated documentation
#~ files (the "Software"), to deal in the Software without
#~ restriction, including without limitation the rights to use,
#~ copy, modify, merge, publish, distribute, sublicense, and/or sell
#~ copies of the Software, and to permit persons to whom the
#~ Software is furnished to do so, subject to the following
#~ conditions:
#~ The above copyright notice and this permission notice shall be
#~ included in all copies or substantial portions of the Software.
#~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
#~ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#~ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
#~ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#~ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
#~ OTHER DEALINGS IN THE SOFTWARE.
from __future__ import with_statement
import fsdump
from os import makedirs
from os.path import exists
from lzma import get_lzma_chunks
from struct import unpack_from
from pprint import pprint
from array import array
from dumpsetup import StringTable, Form, FormOp
from util import (md5sum, read_with_progress, find_all, find_all_backwards,
Struct, SI, from_b64, hexbytes, substitute, chexdump, FindBadPosition,
FindStopSearching
)
#~ SAVE_PATH = "data/original_bios-zchef.fd"; WHAT = "zchef"
#~ SAVE_PATH = "data/original_bios-dhlacik.fd"; WHAT = "dhlacik"
#~ SAVE_PATH = "data/original_bios-FaithX.fd"; WHAT = "FaithX"
#~ SAVE_PATH = "data/original_bios-mine.fd"; WHAT = "mine"
#~ SAVE_PATH = "data/KM2_110.fd"; WHAT = "v110"
SAVE_PATH = "data/original_bios-mine.fd"
WHAT = "mine"
KB, MB, GB = 2 ** 10, 2 ** 20, 2 ** 30
SAVE_PATH = "data/original_bios_backup1.fd"
BIOS_START = 4 * GB - 2 * MB
BIOS_SIZE = 2 * MB
# Only necessary to modify these if you are reading from /dev/mem
# If reading from BIOS dump, they are ignored.
# If someone knows how to detect the bios size automatically, that would
# be very useful
BIOS_SIZE = 2 * MB
BIOS_START = 4 * GB - BIOS_SIZE
class FirmwareVolumeHeader(Struct):
rsvd = SI("<16s")
guid = SI("16s")
size = SI("Q")
magic = SI("4s")
attributes = SI("I")
hdrlen = SI("H")
checksum = SI("H")
rsvd2 = SI("3s")
revision = SI("B")
cruft = SI("16s")
def showinfo(self, depth=0):
print " " * depth, "Reserved boot zone:", hexbytes(self.rsvd)
print " " * depth, "GUID:", hexbytes(self.guid)
print " " * depth, "Size: 0x%x (data 0x%x)" % (self.size,
len(self.data))
print " " * depth, "Attributes: 0x%08x" % self.attributes
print " " * depth, "Revision: %d" % self.revision
class VariableHeader(Struct):
magic = SI("<2s")
status = SI("H")
attributes = SI("I")
nsize = SI("I")
dsize = SI("I")
guid = SI("16s")
# Some bioses do not have a checksum.
# Comment me out if your bios does not work
cs = SI("H")
class FirmwareVolume(object):
def __init__(self, buffer, position, where=None):
buffer = buffer[position:]
try:
fvh = FirmwareVolumeHeader(buffer)
assert fvh.magic == "_FVH", "Invalid FirmwareVolume, wrong magic"
assert fvh.hdrlen == FirmwareVolumeHeader.struct_size, (
"Invalid FirmwareVolume, wrong header length "
"0x%04x, expected 0x%04x" %
(fvh.hdrlen, FirmwareVolumeHeader.struct_size)
)
assert fvh.size <= len(buffer), (
"FirmwareVolume too big? "
"size=0x%08x buflen=0x%08x" % (fvh.size, len(buffer))
)
#blockdata = buffer[fvh.py_struct.size:fvh.hdrlen]
self.data = buffer[fvh.hdrlen:fvh.size]
self.position = position
self.where = where
self.good = True
except AssertionError, e:
#print ">>BAD FV at 0x%08x" % position, e
self.good = False
def has_VSS(self):
return "$VSS" in self.data
def __repr__(self):
hasvss = " [VSS]" if self.has_vss() else ""
args = (self.position, len(self.data), self.where, hasvss)
return "<FirmVol position=0x%06x size=0x%06x where=%s%s>" % args
class Variable(object):
GLOBAL_VARIABLE = from_b64('Yd/ki8qT0hGqDQDgmAMrjA')
HEADER_MAGIC = "\xAA\x55"
ACTIVE = 0x7F
def __init__(self, complete_data):
header_size = VariableHeader.struct_size
header = complete_data[:header_size]
self.vh = vh = VariableHeader(header)
print "Blah:", hexbytes(vh.guid)
assert vh.magic == self.HEADER_MAGIC, "bad magic 0x%x" % vh.magic
total_length = vh.dsize + vh.nsize
assert len(complete_data) >= total_length, "input not long enough"
data = complete_data[header_size:]
data = data[:total_length]
nullterm = data.index("\x00\x00") + 1
strend = nullterm if nullterm < vh.nsize else vh.nsize
self.name = data[:strend].decode("utf-16le")
self.value = data[vh.nsize:total_length]
# Set the checksum to 0, and the status to 0x7F
fdata = substitute(header + data, header_size - 2, "\x00\x00")
fdata = substitute(fdata, 2, "\x7F\x00")
self.ccsum = self.checksum(fdata)
#assert self.ccsum == vh.cs, "Checksum Error"
def __repr__(self):
return "<Variable status=0x%02x size=0x%03x name=%s>" % (self.vh.status, self.vh.dsize, self.name)
def __len__(self):
return VariableHeader.struct_size + self.vh.nsize + self.vh.dsize
def checksum(self, data):
if len(data) % 2:
data += chr(0)
shorts = array("H", [])
shorts.fromstring(data)
return -sum(shorts) & 0xFFFF
def showinfo(self, ts=''):
print ts + "Variable %s" % repr(self.name)
print ts + " Attributes: 0x%08x" % self.vh.attributes
print ts + " Status: 0x%02x" % self.vh.status
if self.vh.guid == self.GLOBAL_VARIABLE:
print ts + (" VendorGUID: EFI_GLOBAL_VARIABLE (%s)" %
' '.join('%02x' % ord(c) for c in self.vh.guid))
else:
print ts + (" VendorGUID: %s" %
' '.join('%02x' % ord(c) for c in self.vh.guid))
#print ts+" Checksum: 0x%02x"%self.vh.cs
#print ts+" calc 0x%04x"%self.ccsum
print ts + " Value (0x%x bytes):" % (len(self.value))
chexdump(self.value, ts + " ")
class VSSData(object):
def __init__(self, data):
(size,) = unpack_from("I", data[4:])
assert size < len(data), (
"Too big! size = %i len = %i" % (size, len(data))
)
vssdata = data[0x10:size]
self.vars = []
self.size = size
position = 0
while (position < len(data) and
vssdata[position:].startswith(Variable.HEADER_MAGIC)):
print "Creating variable at", position
v = Variable(vssdata[position:])
position += len(v)
self.vars.append(v)
def __repr__(self):
return "<VSSData len=%i size=0x%x>" % (len(self.vars), self.size)
def __iter__(self):
return iter(self.vars)
class BIOS(object):
def __init__(self, from_where=None):
"Create a BIOS object"
bios_data = self.load_bios(from_where)
print "Operating on BIOS %s size = 0x%x" % (SAVE_PATH, len(bios_data))
print "Loading compressed sections"
compressed_chunks = get_lzma_chunks(bios_data)
print " .. found %i compressed sections" % len(compressed_chunks)
print "Locating Firmware Volumes"
volumes = self.locate_firmware_volumes(bios_data)
for position, data in compressed_chunks:
#if False:
#with open("data/fv-compr-0x%08x" % position, "wb") as f:
# Dump the executable with the PE header in the right place
#f.write(data[data.index("MZ"):])
where = "[compr at 0x%x]" % position
volumes.extend(self.locate_firmware_volumes(data, where))
# Only good volumes
volumes = filter(lambda fv: fv.good, volumes)
vol_compr = filter(
lambda fv: fv.where and "compr" in fv.where, volumes)
print (" .. found %i FirmwareVolumes (%i compressed)" %
(len(volumes), len(vol_compr)))
setup_utility = self.locate_setup_utility(vol_compr)
TYPE_PE = 0x10
setup_utility_pe = self.get_section_type(setup_utility[1], TYPE_PE)
dump_filename = "data/SetupUtility-%s.pe" % WHAT
if not exists(dump_filename):
pe = setup_utility_pe
with open(dump_filename, "wb") as fd:
fd.write(pe.data)
print "Wrote SetupUtility to %s" % dump_filename
print " Size = 0x%x MD5: %s" % (len(pe.data), md5sum(pe.data))
self.locate_packs(setup_utility_pe.data)
self.locate_vss(volumes)
def locate_vss(self, volumes):
for vss_volume in filter(FirmwareVolume.has_vss, volumes):
print "Have vss_volume:", vss_volume
try:
vssdata = VSSData(vss_volume.data)
except AssertionError, e:
#print " .. failed to load: '%s'" % e
continue
print vss_volume, vssdata
for var in vssdata:
if var.vh.status == Variable.ACTIVE:
print var
if var.name == "Setup":
var.showinfo()
def locate_packs(self, setuputility_binary):
"Searches for Forms and the English StringTable using a set of heuristics"
# 1st byte: upper bits from length: almost certainly zero
# 2-3: Short typecode, 3 == form
# 4-5: 0x0e is the formset opcode, and 0x24 is is length
# This magic string appears three bytes into the header
form_magic = "\x00\x03\x00\x0e\x24"
form_magic_offset = -3
# HiipackHeaderSize
HHS = 6
english_attribute_magic = "\x00" * 4
def create_stringtable(magic_location):
def test_stringtable(poss_header_location):
# We started at attributes, start at lnoff
poss_header_location -= 12
dat = setuputility_binary[poss_header_location:]
lnoff, plnoff, count, attributes = unpack_from("<IIII", dat)
# This check is extraordinarily unlikely to succeed in the case
# we haven't actually found the string table header.
if (magic_location - poss_header_location + HHS == lnoff and
magic_location - poss_header_location + HHS + 8 == plnoff):
string_table_loc = poss_header_location - HHS
stable = StringTable(setuputility_binary, string_table_loc)
raise FindStopSearching(stable)
raise FindBadPosition
result = find_all_backwards(setuputility_binary,
english_attribute_magic,
test_stringtable, magic_location)
if result:
raise FindStopSearching(result)
raise FindBadPosition
string_magic = u"eng\x00English".encode("utf-16le")
english_stringtable = find_all(setuputility_binary, string_magic,
create_stringtable)
if not english_stringtable:
raise RuntimeError
#~ english_stringtable.showinfo()
def create_form(location):
location += form_magic_offset
try:
return Form(setuputility_binary, location, english_stringtable)
except AttributeError:
raise FindBadPosition
forms = find_all(setuputility_binary, form_magic, create_form)
found = False
# We've finally reached the bottom layer!
# Now we just search for the location of the VT switch..
for form in forms:
for opcode in form.fetch_opcodes(FormOp.EFI_IFR_ONE_OF_OP):
qid, width, pid, hid = unpack_from("<HBHH", opcode.payload)
prnt_string = english_stringtable[pid]
help_string = english_stringtable[hid]
args = (qid, width, prnt_string, help_string)
if "Vanderpool" in help_string:
found = True
print "Location = 0x%03x<%d>, name='%s' help='%s'" % args
if not found:
print "Sorry, I couldn't locate the VT flag? :("
def get_sections(self, container):
"Return a recursive list of sections"
result = []
for section in container.sections:
result.append(section)
if section.sections:
result.append(self.get_sections(section))
return result
def get_section_type(self, sections, type):
"Return the first section that has type `type`"
for section in sections:
if section.type == type:
return section
def locate_setup_utility(self, volumes):
"Locate the SetupUtility section within `volumes`"
for vol in volumes:
if vol.position != 0x10:
continue
for file in fsdump.FS(vol.data):
FILE_TYPE_CONTAINS_PE = 0x07
if file.type != FILE_TYPE_CONTAINS_PE:
continue
sections = self.get_sections(file)
TYPE_NAME = 0x15
name_section = self.get_section_type(sections[1], TYPE_NAME)
if name_section.name == "SetupUtility":
return sections
raise RuntimeError("Shouldn't get here, seems we couldn't "
"find the SetupUtility :/")
def locate_firmware_volumes(self, data, where=None):
"""Search through `data` looking for firmware volume headers
`where` optionally specifies where it came from (e.g. compressed section)
"""
FVH_OFFSET_WITHIN_HEADER = 0x28
subtract_offset = lambda x: x - FVH_OFFSET_WITHIN_HEADER
items = find_all(data, "_FVH", subtract_offset)
#print "Found the following:", items
return [FirmwareVolume(data, position, where) for position in items]
def retrieve_from_memory(self):
"Download the BIOS directly from memory. Must be root to do this."
try:
with open("/dev/mem", "rb") as memory:
memory.seek(BIOS_START)
print "Reading BIOS data.."
bios_data = read_with_progress(memory, BIOS_SIZE, 2 ** 6 * KB)
except IOError, err:
if err.errno == 13:
print "Read error reading '%s' Are you root?" % path
else:
print "Unexpected error"
raise
return bios_data
def load_bios(self, from_where=None):
"If the desired bios file doesn't exist, try to load it from memory"
if from_where is None:
from_where = SAVE_PATH
if not exists(from_where):
bios_data = self.retrieve_from_memory()
print "Saving BIOS to '%s' md5:%s" % (SAVE_PATH, md5sum(bios_data))
with open(SAVE_PATH, "wb") as f_bios:
f_bios.write(bios_data)
else:
with open(from_where, "rb") as f_bios:
bios_data = f_bios.read()
print "Opened BIOS '%s' with md5:%s" % (
from_where, md5sum(bios_data))
return bios_data
def main():
if not exists("./data/"):
makedirs("./data/")
bios = BIOS()
print "Done"
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,75 @@
Offset (h) Length (h) Item
---------- ---------- ----
0 10 GUID - [EFI_GUID]
10 1 Header checksum (2's complement sum of first 17h bytes - assume extra checksum is 0) \ [EFI_FFS_INTEGRITY_CHECK]
11 1 Module checksum (2's complement sum of bytes from 18h to end of module (excluding any FFh padding)) /
12 1 Type of module - [EFI_FV_FILETYPE]
13 1 Module attributes - [EFI_FFS_FILE_ATTRIBUTES]
14 3 Size of header and module (excluding FFh padding at end, but including 00h padding) - [Size]
17 1 State - [EFI_FFS_FILE_STATE] - only ever seen F8h
Common header
18 3 Size of extended header and module (from 18h in header, excluding FFh padding, but including 00h padding)
1b 1 Type byte / Extended header byte
- if 1,10h-1Bh then module follows directly
- if 2 then extended header
Extended header
1c 10 GUID (? always FC1BCDB0-7D31-49AA-936A-A4600D9DD083)
2c 2 Data offset (from common header - normally 1Ch)
2e 2 Attributes (1 = Processing required, 2 = Status valid)
30 4 CRC32 of module (including last 4 bytes of header, excluding FFh padding, including 00h padding)
Next common header
34 3 Module size (including these 4 bytes, excluding ALL padding)
37 1 Type byte
All modules are padded 00h/FFh to QWORD boundry
Type
EFI_FV_FILETYPE_ALL 0x00
EFI_FV_FILETYPE_RAW 0x01
EFI_FV_FILETYPE_FREEFORM 0x02
EFI_FV_FILETYPE_SECURITY_CORE 0x03
EFI_FV_FILETYPE_PEI_CORE 0x04
EFI_FV_FILETYPE_DXE_CORE 0x05
EFI_FV_FILETYPE_PEIM 0x06
EFI_FV_FILETYPE_DRIVER 0x07
EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08
EFI_FV_FILETYPE_APPLICATION 0x09
Attributes
00000001 - Tail present
00000010 - Needed for crisis recovery
00000100 - Reserved (0)
00111000 - Alignment (000 - 111)
01000000 - If set, module checksum present
State
00000001 - EFI_FILE_HEADER_CONSTRUCTION
00000010 - EFI_FILE_HEADER_VALID
00000100 - EFI_FILE_DATA_VALID
00001000 - EFI_FILE_MARKED_FOR_UPDATE
00010000 - EFI_FILE_DELETED
00100000 - EFI_FILE_HEADER_INVALID
11000000 - ? Always 11
Type of region
EFI_SECTION_COMPRESSION 0x01 (not compressed in most insyde)
EFI_SECTION_GUID_DEFINED 0x02
EFI_SECTION_PE32 0x10
EFI_SECTION_PIC 0x11
EFI_SECTION_TE 0x12
EFI_SECTION_DXE_DEPEX 0x13
EFI_SECTION_VERSION 0x14
EFI_SECTION_USER_INTERFACE 0x15
EFI_SECTION_COMPATIBILITY16 0x16
EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17
EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18
EFI_SECTION_RAW 0x19
EFI_SECTION_PEI_DEPEX 0x1B
Source: http://forums.mydigitallife.info/threads/11693-Insyde-module-headers

View File

@@ -0,0 +1,168 @@
#! /usr/bin/env python
from hashlib import md5
from sys import stdout
from pprint import pprint
def md5sum(data):
return md5(data).hexdigest()
class FindBadPosition(Exception):
"""Raised to disallow a position from appearing in the result list in `find_all`"""
pass
class FindStopSearching(Exception):
"""Stop searching in find_all"""
def __init__(self, result):
self.result = result
def from_b64(what):
return str.decode(what + "=" * (3 - len(what) % 3), "base64")
def hexbytes(bytes):
return " ".join(["%02x" % ord(c) for c in bytes])
def substitute(input, where, what):
return "".join([input[:where], what, input[where + len(what):]])
def find_all(buffer, what, callback=lambda x: x, start=0, stop=None):
if stop is None:
stop = len(buffer)
position = start
result = []
while position < stop and what in buffer[position:stop + 1]:
position = buffer.index(what, position, stop)
try:
result.append(callback(position))
except FindStopSearching, exc:
return exc.result
except FindBadPosition:
pass
position += 1
return result
def find_all_backwards(buffer, what, callback=lambda x: x, start=None, stop=0):
"Beware! This function is not fully tested. I should really write some unit tests for the edge cases"
if start is None:
start = len(buffer)
position = start
result = []
while position > stop and what in buffer[stop:position]:
position = buffer.rindex(what, stop, position)
try:
result.append(callback(position))
except FindStopSearching, exc:
return exc.result
except FindBadPosition:
pass
position += 1
return result
def read_with_progress(file_handle, total, chunk_size):
assert not total % chunk_size, "chunk_size must be a divisor of total!"
data = []
length = (80 - 6)
for i in xrange(0, total, chunk_size):
data.append(file_handle.read(chunk_size))
done = length * i // total
print "\r[ %s>%s ]" % ("-" * done, " " * (length - done)),
stdout.flush()
print "\r[ %s> ]" % ("-" * length)
return "".join(data)
from struct import unpack, Struct as pyStruct
class StructMeta(type):
def __new__(meta, classname, bases, classDict):
is_structitem = lambda x: isinstance(x[1], SI)
struct_items = filter(is_structitem, classDict.iteritems())
struct_items.sort(key=lambda x: x[1].position)
struct_format = "".join(map(lambda x: x[1].packstr, struct_items))
struct = pyStruct(struct_format)
def __init__(self, data):
data_tuple = struct.unpack_from(data)
for (name, structitem), item_data in zip(struct_items, data_tuple):
setattr(self, name, item_data)
self.rest_of_data = data[struct.size:]
#def repack(self):
cls = type.__new__(meta, classname, bases, classDict)
cls.py_struct = struct
cls.struct_size = struct.size
cls.__init__ = __init__
return cls
class SI(object):
"StructItem"
counter = 0
def __init__(self, packstr):
self.position = SI.counter
SI.counter += 1
self.packstr = packstr
class Struct(object):
__metaclass__ = StructMeta
def hexdump(s, sep=" "):
return sep.join(map(lambda x: "%02x" % ord(x), s))
def ascii(s):
s2 = ""
for c in s:
if ord(c) < 0x20 or ord(c) > 0x7e:
s2 += "."
else:
s2 += c
return s2
def pad(s, c, l):
if len(s) < l:
s += c * (l - len(s))
return s
def chexdump(s, ts="", off=0):
for i in range(0, len(s), 16):
print ts + "%08x %s %s |%s|" % (i + off, pad(hexdump(s[i:i + 8], ' '), " ", 23), pad(hexdump(s[i + 8:i + 16], ' '), " ", 23), pad(ascii(s[i:i + 16]), " ", 16))
if __name__ == "__main__":
s = Header("test")
print "I have something:", s

View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python2
# extract microcode updates from binary BIOS files
# v 0.1 2012/07/23
# v 0.2 2012/07/23 added VIA Nano support (relaxed some checks)
# Licensed as Public Domain
import ctypes
import struct
import sys
import array
uint8_t = ctypes.c_ubyte
char = ctypes.c_char
uint32_t = ctypes.c_uint
uint64_t = ctypes.c_uint64
uint16_t = ctypes.c_ushort
def get_struct(str_, off, struct):
s = struct()
slen = ctypes.sizeof(s)
bytes = str_[off:off+slen]
fit = min(len(bytes), slen)
ctypes.memmove(ctypes.addressof(s), bytes, fit)
return s
def DwordAt(f, off):
return struct.unpack("<I", f[off:off+4])[0]
# Intel microcode update header
class IntelUcUpdateHeader(ctypes.LittleEndianStructure):
_fields_ = [
("HeaderVersion", uint32_t), #
("UpdateRevision", uint32_t), #
("Date", uint32_t), #
("ProcessorSignature", uint32_t), #
("Checksum", uint32_t), #
("LoaderRevision", uint32_t), #
("ProcessorFlags", uint32_t), #
("DataSize", uint32_t), #
("TotalSize", uint32_t), #
]
def check_valid_mcode(f, off, maxoff, is_via = False):
hdr = get_struct(f, off, IntelUcUpdateHeader)
# on Intel, Total Size is always a multiple of 1024.
if not is_via and hdr.TotalSize & 0x3FF:
return
# For microcode updates with a data size field
# equal to 00000000H, the size of the microcode
# update is 2048 bytes.
if hdr.DataSize == 0:
check_len = 2048
else:
check_len = hdr.TotalSize
if check_len < 2048:
return False
# it should not run off the end of file or another update
if check_len + off > maxoff:
return
# update size must be a multiple of DWORD
if (hdr.DataSize & 3) or (hdr.TotalSize & 3):
return
# looks okay. let's check the checksum
mdata = f[off:off+check_len]
# make an array of DWORDs
arr = array.array("I", mdata)
# sum them
ck = sum(arr) & 0xFFFFFFFF
if ck == 0:
print "%08X: found a valid-looking update" % off
print ["Date: %02X/%02X/%4X", "Date: %02d/%02d/%4d"][is_via] % ((hdr.Date >> 24)&0xFF, (hdr.Date >> 16)&0xFF, hdr.Date & 0xFFFF)
print "Processor signature: %08X" % hdr.ProcessorSignature
if not is_via:
print "Processor flags: %08X" % hdr.ProcessorFlags
print "Length: %08X" % check_len
fname = "mcode_upd_%08X.bin" % off
print "Extracting to %s" % fname
open(fname, "wb").write(mdata)
return True
# nope
return False
def find_ucode(f, is_via):
maxoff = len(f)
# minimal microcode update length is 2048 bytes
off = (maxoff-2048+8)&(~15)
# look for BCD date ddmmyyyy
# yyyy off-2
# dd off-1
# mm off
print "Scanning...\n%08X" % off
while off > 11:
# looks like a date?
m = ord(f[off])
if (1 <= m <= 0x12) and (1 <= ord(f[off-1]) <= 0x31):
if check_valid_mcode(f, off-11, maxoff, is_via):
maxoff = off-11
print "Scanning...\n%08X" % off
off -= 1
if (off & 0xFFFFF) == 0:
print "%08X" % off
print "\nDone"
if len(sys.argv) < 2:
print "Usage: microcode_extract.py <file.rom> [-i|-v]"
print " -i: look for Intel microcode (default)"
print " -v: look for VIA Nano microcode"
sys.exit(1)
else:
fn = None
is_via = False
for arg in sys.argv[1:]:
if arg == "-v":
is_via = True
elif arg == "-i":
is_via = False
else:
fn = arg
f = open(fn, "rb").read()
find_ucode(f, is_via)

View File

@@ -0,0 +1,857 @@
#!/usr/bin/env python2
# Phoenix FFV BIOS dumper/extractor by roxfan
# 2012-09-12 version 0.1
# 3-clause BSD license
import sys, struct, ctypes
import os.path
uint8_t = ctypes.c_ubyte
char = ctypes.c_char
uint32_t = ctypes.c_uint
uint64_t = ctypes.c_uint64
uint16_t = ctypes.c_ushort
def read_struct(li, struct):
s = struct()
slen = ctypes.sizeof(s)
bytes = li.read(slen)
fit = min(len(bytes), slen)
ctypes.memmove(ctypes.addressof(s), bytes, fit)
return s
def get_struct(str_, off, struct):
s = struct()
slen = ctypes.sizeof(s)
bytes = str_[off:off+slen]
fit = min(len(bytes), slen)
ctypes.memmove(ctypes.addressof(s), bytes, fit)
return s
def strguid(raw):
return "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}" % struct.unpack("<IHH8B", raw)
GUID_ESCD = "FDE821FD2525954ABB9047EC5763FF9E".decode('hex')
GUID_SETUP = "D01023C054D73945B0CF9F9F2618D4A9".decode('hex')
GUID_UEFIV = "112BF272ABCEE242958A0DA1622D94E3".decode('hex')
GUID_DMIV = "12ED2C42E5AEB94384E0AFB3E416254D".decode('hex')
GUID_HOLE = "630FAEF68C5F1643A2EA76B9AF762756".decode('hex')
def guid2type(guid):
gmap = {
GUID_ESCD: "ESCD",
GUID_SETUP: "SETUP",
GUID_UEFIV: "UEFIV",
GUID_DMIV: "DMIV",
GUID_HOLE: "HOLE",
}
if type(guid) != type(""):
guid = "".join(map(chr, guid))
if guid in gmap:
return gmap[guid]
elif guid[0] == '\xBA':
return "FFV"
else:
return None
def guidname2str(s):
s2 = s.rstrip('\0')
if s[8] == '\xFF':
return (s2[:8] + s2[9:]).rstrip('\0')
elif s2.isalnum():
return s2.rstrip('\0')
else:
return strguid(s)
LETTER_FILE_TYPE = {
'A': 'ACPI',
'B': 'BIOSCODE',
'C': 'UPDATE',
'D': 'DISPLAY',
'E': 'SETUP',
'F': 'PIF',
'F': 'MARKS',
'G': 'DECOMPCODE',
'I': 'BOOTBLOCK',
'L': 'LOGO',
'M': 'MISER',
'N': 'ROMPILOTLOAD',
'O': 'NETWORK',
'P': 'PSI',
'P': 'ROMPILOTINT',
'R': 'OPROM',
'S': 'STRINGS',
'T': 'TEMPLATE',
'U': 'USER',
'W': 'WAV',
'X': 'ROMEXEC',
'*': 'AUTOGEN',
'$': 'BIOSENTRY',
}
FILE_TYPE_NAMES = {
0x00 : "ALL",
0x01 : "BIN",
0x02 : "SECTION",
0x03 : "CEIMAIN",
0x04 : "PEIMAIN",
0x05 : "DXEMAIN",
0x06 : "PEI",
0x07 : "DXE",
0x08 : "COMBINED_PEIM_DRIVER",
0x09 : "APP",
0x0B : "FFV",
0xC2 : "CEI",
0xC3 : "XIP",
0xC4 : "BB",
0xD0 : "SDXE",
0xD1 : "DXESDXE",
0xF0 : "GAP",
}
FILETYPE_BIN = 0x01
FILETYPE_SECTION = 0x02
FILETYPE_CEIMAIN = 0x03
FILETYPE_PEIMAIN = 0x04
FILETYPE_DXEMAIN = 0x05
FILETYPE_PEI = 0x06
FILETYPE_DXE = 0x07
FILETYPE_COMBINED_PEIM_DRIVER = 0x08
FILETYPE_APP = 0x09
FILETYPE_FFV = 0x0B
FILETYPE_CEI = 0xC2
FILETYPE_XIP = 0xC3
FILETYPE_BB = 0xC4
FILETYPE_SDXE = 0xD0
FILETYPE_DXESDXE = 0xD1
FILETYPE_GAP = 0xF0
SectionedTypes = [FILETYPE_PEIMAIN, FILETYPE_SECTION, FILETYPE_CEIMAIN,
FILETYPE_DXEMAIN, FILETYPE_PEI, FILETYPE_DXE, FILETYPE_CEI,
FILETYPE_BB, FILETYPE_SDXE, FILETYPE_DXESDXE]
SECTION_TYPE_NAMES = {
0x01 : "COMPRESSION",
0x02 : "GUID_DEFINED",
0x10 : "PE32",
0x11 : "PIC",
0x12 : "TE",
0x13 : "DXE_DEPEX",
0x14 : "VERSION",
0x15 : "USER_INTERFACE",
0x16 : "COMPATIBILITY16",
0x17 : "FIRMWARE_VOLUME_IMAGE",
0x18 : "FREEFORM_SUBTYPE_GUID",
0x19 : "BIN",
0x1A : "PE64",
0x1B : "PEI_DEPEX",
0xC0 : "SOURCECODE",
0xC1 : "FFV",
0xC2 : "RE32",
0xC3 : "XIP16",
0xC4 : "XIP32",
0xC5 : "XIP64",
0xC6 : "PLACE16",
0xC7 : "PLACE32",
0xC8 : "PLACE64",
0xCF : "PCI_DEVICE",
0xD0 : "PDB",
}
SECTION_COMPRESSION = 0x01
SECTION_GUID_DEFINED = 0x02
SECTION_PE32 = 0x10
SECTION_PIC = 0x11
SECTION_TE = 0x12
SECTION_DXE_DEPEX = 0x13
SECTION_VERSION = 0x14
SECTION_USER_INTERFACE = 0x15
SECTION_COMPATIBILITY16 = 0x16
SECTION_FIRMWARE_VOLUME_IMAGE = 0x17
SECTION_FREEFORM_SUBTYPE_GUID = 0x18
SECTION_BIN = 0x19
SECTION_PE64 = 0x1A
SECTION_PEI_DEPEX = 0x1B
SECTION_SOURCECODE = 0xC0
SECTION_FFV = 0xC1
SECTION_RE32 = 0xC2
SECTION_XIP16 = 0xC3
SECTION_XIP32 = 0xC4
SECTION_XIP64 = 0xC5
SECTION_PLACE16 = 0xC6
SECTION_PLACE32 = 0xC7
SECTION_PLACE64 = 0xC8
SECTION_PCI_DEVICE = 0xCF
SECTION_PDB = 0xD0
"""
struct FlashFileHeader
{
uint8 FileState;
uint8 Flags;
uint8 HeaderChecksum;
uint8 DataChecksum;
DWORD SizeAndType;
UUID GuidName;
};
"""
class FfsFileHeader(ctypes.LittleEndianStructure):
_fields_ = [
("FileState", uint8_t), #
("Flags", uint8_t), #
("HeaderChecksum", uint8_t), #
("DataChecksum", uint8_t), #
("Size", uint8_t*3), #
("Type", uint8_t), #
("Name", uint8_t * 16), #
]
def name2str(self):
s = "".join(map(chr, self.Name))
return guidname2str(s)
def is_sectioned(self):
return self.Type in SectionedTypes
def size(self):
s = self.Size[:]
return ((s[2]<<16) | (s[1] << 8) | s[0]) & 0xFFFFFF
def pprint(self):
nm = self.name2str()
if nm[0] == '_' and nm[1] in LETTER_FILE_TYPE and nm[2:].isdigit():
print "File: '%s' (%s)" % (nm, LETTER_FILE_TYPE[nm[1]])
else:
print "File: '%s'" % nm
print "Type: %s (0x%02X)" % (FILE_TYPE_NAMES.get(self.Type, "Unknown"), self.Type)
print "Flags: 0x%02X" % self.Flags
print "Size: 0x%06X" % self.size()
class Xip1632(ctypes.LittleEndianStructure):
_fields_ = [
("Name", uint8_t * 16), #
("Offset", uint32_t), #
("Subsystem", uint16_t), #
]
def name2str(self):
s = "".join(map(chr, self.Name))
return guidname2str(s)
def pprint(self):
print "File: '%s'" % self.name2str()
print "Offset: 0x%08X" % (self.Offset)
print "Subsystem: 0x%04X" % (self.Subsystem)
"""
struct FlashSectionHeader
{
char Size[3];
char Type;
};
"""
class FfsSectionHeader(ctypes.LittleEndianStructure):
_fields_ = [
("Size", uint8_t*3), #
("Type", uint8_t), #
]
def size(self):
s = self.Size[:]
return ((s[2]<<16) | (s[1] << 8) | s[0]) & 0xFFFFFF
def sectype(self):
return SECTION_TYPE_NAMES.get(self.Type, "%02X" % self.Type)
def pprint(self):
print "Type: %s (0x%02X)" % (SECTION_TYPE_NAMES.get(self.Type, "Unknown"), self.Type)
print "Size: 0x%06X" % self.size()
def strdepex(data):
off = 0
opnames = [
"BEFORE",
"AFTER",
"PUSH",
"AND",
"OR",
"NOT",
"TRUE",
"FALSE",
"END",
"SOR",
]
ops = []
while off < len(data):
opc = ord(data[off])
off += 1
s = "0x%02X " % opc
if opc < len(opnames):
s += opnames[opc]
if opc in [0,1,2]:
s += " " + strguid(data[off:off+16])
off += 16
else:
s += " <bad opcode>"
ops.append(s)
return "\n".join(ops)
lzint_path = os.path.join(os.path.dirname(__file__), "unlzint")
def unlzint(data):
import subprocess
try:
clen, ulen = struct.unpack("<II", data[:8])
if clen + 8 > len(data):
print "<bad compressed data>"
return data
if clen + 8 < len(data):
data = data[:clen + 8]
p = subprocess.Popen([lzint_path, "-", "-"], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
outd, errd = p.communicate(input=data)
return outd
except:
print "<decompression error>"
return data
def parseSectionedFile(infile, pos1, endpos):
sections = []
i = 0
while pos1 < endpos:
sh = get_struct(infile, pos1, FfsSectionHeader)
print "\nSection %d" % i
sh.pprint()
dlen = sh.size() - ctypes.sizeof(sh)
data = infile[pos1 + ctypes.sizeof(sh):pos1 + ctypes.sizeof(sh) + dlen]
if sh.Type == SECTION_PLACE16:
offset = 0xFFFFFFFF
segment = 0xFFFF
if len(data) == 4:
addr = struct.unpack("<I", data)[0]
seg = addr >> 4
offset = addr - (seg<<4)
print " Address: %08X (%04X:%04X)" % (addr, seg, offset)
elif len(data) == 6:
offset, segment = struct.unpack("<IH", data)
print " Address: %04X:%08X" % (segment, offset)
else:
print " PLACE16 bad data length(%d)" % len(data)
elif sh.Type in [SECTION_XIP16, SECTION_XIP32]:
xip = get_struct(data, 0, Xip1632)
xip.pprint()
elif sh.Type == SECTION_COMPRESSION:
data = unlzint(data)
pass
elif sh.Type == SECTION_USER_INTERFACE:
name = data.decode('utf-16le').rstrip('\0')
print " Name: '%s'" % name
elif sh.Type in [SECTION_DXE_DEPEX, SECTION_PEI_DEPEX]:
print " Depex:\n%s" % strdepex(data)
sh.Data = data
sections.append(sh)
i += 1
pos1 += sh.size()
return sections
"""
struct VolumeDirHeader
{
uint8_t field_18;
uint8_t field_19;
uint16_t HeaderSize;
uint32_t VolDirSize;
};
"""
class VolumeDirHeader(ctypes.LittleEndianStructure):
_fields_ = [
("f0", uint8_t), #
("f1", uint8_t), #
("HeaderSize", uint16_t), #
("VolDirSize", uint32_t), #
]
"""
struct VolumeDir2Entry
{
UUID volumeGuid;
_DWORD volumeStart;
_DWORD volumeSize;
};
"""
class VolumeDir2Entry(ctypes.LittleEndianStructure):
_fields_ = [
("Guid", uint8_t * 16), #
("VolStart", uint32_t), #
("VolSize", uint32_t), #
]
def pprint(self):
print "Guid: '%s'" % strguid(self.Guid)
print "Start: 0x%06X" % self.VolStart
print "Size: 0x%06X" % self.VolSize
def parseVolumeDir2(infile, pos1, endpos, verbose):
entries = []
dirhdr = get_struct(infile, pos1, VolumeDirHeader)
pos1 += dirhdr.HeaderSize
numVols = dirhdr.VolDirSize // 0x18
i = 0
while i < numVols:
ve = get_struct(infile, pos1, VolumeDir2Entry)
if verbose:
print "\nEntry %d" % i
ve.pprint()
entries.append(ve)
i += 1
pos1 += 0x18
return entries
"""
struct FlashSectorInfo
{
unsigned __int8 iGuid;
char field_1;
unsigned __int16 numRepeats;
int byteSize;
int flags;
};
"""
class FlashSectorInfo(ctypes.LittleEndianStructure):
_pack_ = 1
_fields_ = [
("iGuid", uint8_t), #
("unk1", uint8_t), #
("numRepeats", uint16_t), #
("byteSize", uint32_t), #
("flags", uint32_t), #
]
def pprint(self, verbose):
if verbose:
print "iGuid: %d" % self.iGuid
print "unk1: %d" % self.unk1
print "repeats: %d" % self.numRepeats
print "size: 0x%08X" % self.byteSize
print "flags: 0x%08X" % self.flags
else:
print "%d * 0x%08X bytes, flags: %08X" % (self.numRepeats, self.byteSize, self.flags)
"""
struct VolumeInfoBinHeader
{
UUID volname;
int totalHeaderSize;
int field_14;
int field_18;
__int64 volumeAddress;
unsigned __int16 numGuids;
unsigned __int16 numSectorInfos;
};
"""
class VolumeInfoBinHeader(ctypes.LittleEndianStructure):
_pack_ = 1
_fields_ = [
("Name", uint8_t * 16), #
("HeaderSize", uint32_t), #
("unk14", uint32_t), #
("unk18", uint32_t), #
("VolumeAddress", uint64_t), #
("numGuids", uint16_t), #
("numSectorInfos", uint16_t), #
]
def name2str(self):
s = "".join(map(chr, self.Name))
return guidname2str(s)
def parse_extras(self, infile, pos):
pos += ctypes.sizeof(self)
self.guids = []
for i in range(self.numGuids):
self.guids.append(infile[pos:pos+16])
pos += 16
self.sectors = []
for i in range(self.numSectorInfos):
si = get_struct(infile, pos, FlashSectorInfo)
self.sectors.append(si)
pos += 12
def pprint(self, verbose):
if verbose:
print "Name: '%s'" % self.name2str()
print "Hdr len: 0x%02X" % self.HeaderSize
print "Unk14: 0x%02X" % self.unk14
print "Unk18: 0x%02X" % self.unk18
print "VolAddr: 0x%08X" % self.VolumeAddress
print "nGuids: 0x%02X" % self.numGuids
print "nSectorInfos: 0x%02X" % self.numSectorInfos
else:
print " volume '%s' @ 0x%08X" % (self.name2str(), self.VolumeAddress)
for i in range(len(self.sectors)):
si = self.sectors[i]
if si.iGuid == 0:
sguid = "{no GUID}"
elif si.iGuid <= len(self.guids):
sguid = strguid(self.guids[si.iGuid-1])
else:
sguid = "{iGuid out of range}"
if verbose:
print "[sector info %d %s]" % (i, sguid)
else:
print " sector %s:" % (sguid),
si.pprint(verbose)
def replace_bad(value, deletechars):
for c in deletechars:
value = value.replace(c,'_')
return value
vollist = []
filelist = []
class FfsFile:
def __init__(self, infile, pos):
self.filepos = pos
self.infile = infile
self.header = get_struct(infile, pos, FfsFileHeader)
def get_endpos(self):
return self.filepos + self.header.size()
def get_romaddr(self, bioslen):
return (self.filepos - bioslen)&0xFFFFFFFF
def parse_sections(self):
hdrlen = ctypes.sizeof(self.header)
pos = self.filepos
pos1 = pos + hdrlen
endpos = self.get_endpos()
self.sections = []
self.secmap = {}
while pos1 < endpos:
sh = get_struct(self.infile, pos1, FfsSectionHeader)
sh.filepos = pos1
self.sections.append(sh)
self.secmap[sh.Type] = sh
pos1 += sh.size()
def sect_data(self, stype):
sh = self.secmap[stype]
pos1 = sh.filepos
return self.infile[pos1 + ctypes.sizeof(sh):pos1 + sh.size()]
def raw_data(self):
datapos = self.filepos + ctypes.sizeof(self.header)
endpos = self.get_endpos()
return self.infile[datapos:endpos]
def pprint(self, bioslen, detailed = False):
if detailed:
print "ROM address: %08X, File offset: %08X" % (self.get_romaddr(bioslen), self.filepos)
print "Header:"
self.header.pprint()
addr = self.get_romaddr(bioslen)
enda = addr + self.header.size() - 1
dsize = self.header.size() - ctypes.sizeof(self.header)
namestr = self.header.name2str()
if namestr[0] == '_' and namestr[1] in LETTER_FILE_TYPE and namestr[2:].isdigit():
namestr = "%s (%s)" % (namestr, LETTER_FILE_TYPE[namestr[1]])
s = "%08X-%08X %08X %-40s %-8s %d(0x%x)" % (self.get_romaddr(bioslen), enda, self.filepos, namestr, FILE_TYPE_NAMES.get(self.header.Type, "Unknown"), dsize, dsize)
print s
if self.header.is_sectioned():
self.parse_sections()
if detailed:
for i in range(len(self.sections)):
print " section %d:" % i
self.sections[i].pprint()
# unhandled sections
us = set(self.secmap.keys())
if SECTION_COMPRESSION in self.secmap:
print " compressed payload"
us.remove(SECTION_COMPRESSION)
if SECTION_BIN in self.secmap:
print " raw payload"
us.remove(SECTION_BIN)
if SECTION_PE32 in self.secmap:
print " PE32 payload"
us.remove(SECTION_PE32)
if SECTION_DXE_DEPEX in self.secmap:
print " DXE DEPEX present"
us.remove(SECTION_DXE_DEPEX)
if SECTION_PEI_DEPEX in self.secmap:
print " PEI DEPEX present"
us.remove(SECTION_PEI_DEPEX)
if SECTION_USER_INTERFACE in self.secmap:
data = self.sect_data(SECTION_USER_INTERFACE)
name = data.decode('utf-16le').rstrip('\0')
print " UI name: %s" % name
us.remove(SECTION_USER_INTERFACE)
if SECTION_PLACE16 in self.secmap:
data = self.sect_data(SECTION_PLACE16)
offset = 0xFFFFFFFF
segment = 0xFFFF
if len(data) == 4:
addr = struct.unpack("<I", data)[0]
seg = addr >> 4
offset = addr - (seg<<4)
print " PLACE16: %08X (%04X:%04X)" % (addr, seg, offset)
elif len(data) == 6:
offset, segment = struct.unpack("<IH", data)
print " PLACE16: %04X:%08X" % (segment, offset)
else:
print " PLACE16 bad data length(%d)" % len(data)
us.remove(SECTION_PLACE16)
if SECTION_XIP16 in self.secmap:
xip = get_struct(self.sect_data(SECTION_XIP16), 0, Xip1632)
print " XIP16 file '%s', entry = 0x%08X, subsystem = %02X" % (xip.name2str(), xip.Offset, xip.Subsystem)
us.remove(SECTION_XIP16)
if SECTION_XIP32 in self.secmap:
xip = get_struct(self.sect_data(SECTION_XIP32), 0, Xip1632)
print " XIP32 file '%s', entry = 0x%08X, subsystem = %02X" % (xip.name2str(), xip.Offset, xip.Subsystem)
us.remove(SECTION_XIP32)
if us:
print " unhandled sections:", map(hex,us)
def parseFfsFile(infile, pos, bioslen, volno = None):
ff = get_struct(infile, pos, FfsFileHeader)
if ff.size() == 0 or ff.FileState != 0xF8:
return
ff.pprint()
pos0 = pos
hdrlen = ctypes.sizeof(ff)
pos1 = pos + hdrlen
pos += ff.size()
fname = ff.name2str()
if ff.Type in [FILETYPE_PEIMAIN, FILETYPE_SECTION, FILETYPE_CEIMAIN,
FILETYPE_DXEMAIN, FILETYPE_PEI, FILETYPE_DXE, FILETYPE_CEI,
FILETYPE_BB, FILETYPE_SDXE, FILETYPE_DXESDXE]:
ss = parseSectionedFile(infile, pos1, pos)
for i in range(len(ss)):
fname2 = "%08X_%s_S%d_%s.bin" % (pos0, fname, i, ss[i].sectype())
if volno != None:
fname2 = "V%d_" % volno + fname2
fname2 = replace_bad(fname2, '\/:*?"<>|')
print " ==> %s" % fname2
open(fname2,"wb").write(ss[i].Data)
if ff.Type == FILETYPE_BIN:
if ff.name2str() == "volumedir.bin2" and volno == None:
vols = parseVolumeDir2(infile, pos1, pos, False)
for i in range(len(vols)):
v = vols[i]
s = (v.VolStart + bioslen) & 0xFFFFFFFF # v.VolStart - 0xFF800000
print "\n***\nVolume %d: address %08X, file offset %08X, size %08X\n***\n" % (i, v.VolStart, s, v.VolSize)
parse_range(infile, s, s + v.VolSize, bioslen, i)
vollist.extend(vols)
fname2 = "%08X_%s.bin" % (pos0, fname)
if volno != None:
fname2 = "V%d_" % volno + fname2
fname2 = replace_bad(fname2, '\/:*?"<>|')
print " ==> %s" % fname2
dlen = ff.size() - hdrlen
data = infile[pos1:pos1 + dlen]
open(fname2,"wb").write(data)
return pos
class FfsVolume:
def __init__(self, infile, pos, size, guid, ord):
self.filepos = pos
self.infile = infile
self.size = size
self.guid = guid
self.volInfo = None
self.ord = ord
self.files = []
def parse_volinfo(self, data):
self.volInfo = get_struct(data, 0, VolumeInfoBinHeader)
self.volInfo.parse_extras(data, 0)
def parse_files(self):
pos = self.filepos
maxpos = pos + self.size
while True:
while pos < maxpos and self.infile[pos] in ['\xFF', '\x00']:
pos += 1
if pos >= maxpos:
break
if self.infile[pos] != '\xF8':
return
ff = FfsFile(self.infile, pos)
pos = ff.get_endpos()
self.files.append(ff)
if ff.header.Type == FILETYPE_BIN and ff.header.name2str() == "volumeinfo.bin":
self.parse_volinfo(ff.raw_data())
# skip padding after file
while pos < maxpos and infile[pos] in ['\xFF', '\x00']:
pos += 1
def pprint(self, bioslen, verbose):
if self.guid[0] == 0xBA:
self.parse_files()
addr = (self.filepos - bioslen)&0xFFFFFFFF
namestr = strguid(self.guid)
gt = guid2type(self.guid)
if gt == None:
gt = "VOL"
s = "%08X-%08X %08X %-40s %-8s %d(0x%x)" % (addr, addr + self.size-1, self.filepos, namestr, "<%s %d>" % (gt, self.ord), self.size, self.size)
# print "\n***\nVolume address %08X, file offset %08X, size %08X\n***\n" % (addr, self.filepos, self.size)
print s
if self.volInfo:
self.volInfo.pprint(verbose)
for f in self.files:
f.pprint(bioslen, verbose)
def parse_range(infile, pos, maxpos, bioslen, volno = None):
start = pos
while pos < maxpos:
nextpos = parseFfsFile(infile, pos, bioslen, volno)
if nextpos == None:
break
print "\nfile offset: %08X" % pos
pos = nextpos
while pos < maxpos and infile[pos] in ['\xFF', '\x00']:
pos += 1
if volno != None and start == pos and pos < maxpos:
fname = "V%d_%08X.bin" % (volno, pos)
print " ==> %s" % fname
open(fname,"wb").write(infile[pos:maxpos])
class PhoenixModuleHeader(ctypes.LittleEndianStructure):
_pack_ = 1
_fields_ = [
("Signature", uint32_t), #
("Signature2", uint8_t*3), #
("Id", uint8_t), #
("Type", uint8_t), #
("HeadLen", uint8_t), #
("Compression", uint8_t), #
("Address", uint32_t),
("ExpLen", uint32_t),
("FragLen", uint32_t),
("NextFrag", uint32_t),
]
def pprint(self):
print "Signature: 0x%08X" % self.Signature
print "Id: %d" % self.Id
print "Type: %02X" % self.Type
print "HeadLen: %02X" % self.HeadLen
print "Compression: %d" % self.Compression
addr = self.Address
seg = addr >> 4
offset = addr - (seg<<4)
print "Address: %08X (%04X:%04X)" % (addr, seg, offset)
print "ExpLen: %X" % (self.ExpLen)
print "FragLen: %X" % (self.FragLen)
print "NextFrag: %X" % (self.NextFrag)
"""
struct PhoenixModule {
uint32_t Signature;
uint8_t Signature2[3];
uint8_t Id;
uint8_t Type;
uint8_t HeadLen;
uint8_t Compression;
uint16_t Offset;
uint16_t Segment;
uint32_t ExpLen;
uint32_t FragLength;
uint32_t NextFrag;
} *Module;
"""
def parse_trailer(infile, pos, maxpos):
start = pos
i = 0
while pos < maxpos:
if infile[pos:pos+4] == "BC\xD6\xF1":
modhdr = get_struct(infile, pos, PhoenixModuleHeader)
modhdr.pprint()
pos += modhdr.HeadLen
addr = modhdr.Address
seg = addr >> 4
offset = addr - (seg<<4)
fname = "%08X_%04X_%04X.bin" % (pos, seg, offset)
print " ==> %s" % fname
open(fname,"wb").write(infile[pos:pos+modhdr.ExpLen])
pos += modhdr.ExpLen
elif infile[pos:pos+8] == "FLASHDXE":
pos += 8
while pos < maxpos:
nextpos = parseFfsFile(infile, pos, maxpos)
if nextpos == None:
break
print "\nfile offset: %08X" % pos
pos = nextpos
else:
print "\nunknown header at %08X" % pos
break
if len(sys.argv) < 1:
print "Usage: phoenix_scan.py BIOS.BIN [-d] [-t] [-v]"
print "-d: extract modules into files"
print "-t: extract the trailer parts"
print "-v: verbose info about flash layout"
sys.exit(1)
inf = open(sys.argv[1],"rb")
infile = inf.read()
pos = infile.find("volumedi\xFFr.bin2")
if pos != -1:
pos -= 8
print "Found Volume Directory v2 at %08X\n" % (pos)
else:
print "Volume dir not found; FFS dump won't be available"
#sys.exit(1)
dump_all = False
dump_trailer = False
print_verbose = False
for a in sys.argv[2:]:
if a == '-d':
dump_all = True
elif a == '-t':
dump_trailer = True
elif a == '-v':
print_verbose = True
alllen = len(infile)
bioslen = alllen & 0xFFFF0000
if dump_all and pos != -1:
parse_range(infile, pos, alllen, bioslen)
if dump_trailer:
parse_trailer(infile, bioslen, alllen)
if pos != -1:
voldir = FfsFile(infile, pos)
vols = parseVolumeDir2(voldir.raw_data(), 0, 0, print_verbose)
ffvols = []
for i in range(len(vols)):
v = vols[i]
pos = (v.VolStart + bioslen) & 0xFFFFFFFF
ffv = FfsVolume(infile, pos, v.VolSize, v.Guid, i)
ffvols.append(ffv)
print "FFS contents:"
for fv in ffvols:
print ""
fv.pprint(bioslen, print_verbose)

621
bios_extract/src/ami.c Normal file
View File

@@ -0,0 +1,621 @@
/*
* Decompression utility for AMI BIOSes.
*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
* Copyright 2000-2006 Anthony Borisow
* Copyright 2021 RichardG <richardg867@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define _GNU_SOURCE 1 /* for memmem */
#include <stdio.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "bios_extract.h"
#include "compat.h"
#include "lh5_extract.h"
struct AMI95ModuleName {
uint8_t Id;
char *Name;
};
static struct AMI95ModuleName AMI95ModuleNames[] = {
{0x00, "POST"},
{0x01, "Setup Server"},
{0x02, "RunTime"},
{0x03, "DIM"},
{0x04, "Setup Client"},
{0x05, "Remote Server"},
{0x06, "DMI Data"},
{0x07, "Green PC"},
{0x08, "Interface"},
{0x09, "MP"},
{0x0A, "Notebook"},
{0x0B, "Int-10"},
{0x0C, "ROM-ID"},
{0x0D, "Int-13"},
{0x0E, "OEM Logo"},
{0x0F, "ACPI Table"},
{0x10, "ACPI AML"},
{0x11, "P6 Microcode"},
{0x12, "Configuration"},
{0x13, "DMI Code"},
{0x14, "System Health"},
{0x15, "Memory Sizing"},
{0x16, "Memory Test"},
{0x17, "Debug"},
{0x18, "ADM (Display MGR)"},
{0x19, "ADM Font"},
{0x1A, "Small Logo"},
{0x1B, "SLAB"},
{0x1C, "BCP Info"},
{0x1D, "Dual Logo"},
{0x1E, "Intel OSB"},
{0x20, "PCI AddOn ROM"},
{0x21, "Multilanguage"},
{0x22, "UserDefined"},
{0x23, "ASCII Font"},
{0x24, "BIG5 Font"},
{0x25, "OEM Logo"},
{0x26, "Debugger"},
{0x27, "Debugger Port"},
{0x28, "BMC Output"},
{0x29, "MBI File"},
{0x2A, "User ROM"},
{0x2B, "PXE Code"},
{0x2C, "AMI Font"},
{0x2E, "User ROM"},
{0x2D, "Battery Refresh"},
{0x2F, "Serial Redirection"},
{0x30, "Font Database"},
{0x31, "OEM Logo Data"},
{0x32, "Graphic Logo Code"},
{0x33, "Graphic Logo Data"},
{0x34, "Action Logo Code"},
{0x35, "Action Logo Data"},
{0x36, "Virus"},
{0x37, "Online Menu"},
{0x38, "Lang1 as ROM"},
{0x39, "Lang2 as ROM"},
{0x3A, "Lang3 as ROM"},
{0x40, "AMD CIM-X NB binary"},
{0x60, "AMD CIM-X SB binary"},
{0x70, "OSD Bitmaps"},
{0x80, "Image Info"},
{0xab, "CompuTrace backdoor"},
{0xf0, "Asrock Backup Util or Windows SLIC"},
{0xf9, "Asrock AMD AHCI DLL"},
{0xfa, "Asrock LOGO GIF"},
{0xfb, "Asrock LOGO JPG"},
{0xfc, "Asrock LOGO JPG"},
{0xfd, "Asrock LOGO PCX - Instant boot"},
{0, NULL}
};
static char *AMI95ModuleNameGet(uint8_t ID)
{
int i;
for (i = 0; AMI95ModuleNames[i].Name; i++)
if (AMI95ModuleNames[i].Id == ID)
return AMI95ModuleNames[i].Name;
return NULL;
}
/*
*
*/
Bool
AMI940725Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t AMIBOffset, uint32_t ABCOffset)
{
Bool Compressed;
uint32_t Offset = ABCOffset + 0x10;
char Date[9];
unsigned char *ABWOffset;
char Version[5];
int i;
struct b94 {
const uint16_t PackLenLo;
const uint16_t PackLenHi;
const uint16_t RealLenLo;
const uint16_t RealLenHi;
} *b94;
/* Get Date */
memcpy(Date, BIOSImage + BIOSLength - 11, 8);
Date[8] = 0;
ABWOffset = memmem(BIOSImage, BIOSLength, "AMIBIOS W ", 10);
if (ABWOffset) {
Version[0] = *(ABWOffset + 10);
Version[1] = *(ABWOffset + 11);
Version[2] = *(ABWOffset + 13);
Version[3] = *(ABWOffset + 14);
Version[4] = 0;
} else {
Version[0] = 0;
}
printf("AMI94 Version\t: %s (%s)\n", Version, Date);
/* 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);
for (i = 0; i < 0x80; i++) {
char filename[64];
unsigned char *Buffer;
int BufferSize, ROMSize;
b94 = (struct b94 *)(BIOSImage + Offset);
if ((le16toh(b94->PackLenLo) == 0x0000)
|| (le16toh(b94->RealLenLo) == 0x0000))
break;
sprintf(filename, "amibody_%02x.rom", i);
Compressed = TRUE;
NotCompressed:
ROMSize = le32toh(b94->PackLenLo);
if (Compressed)
BufferSize = le32toh(b94->RealLenLo);
else
BufferSize = ROMSize;
printf("0x%05X (%6d bytes)", Offset + 8,
ROMSize);
printf(" -> %-20s", filename);
printf(" (%6d bytes)", BufferSize);
printf("\n");
Buffer = MMapOutputFile(filename, BufferSize);
if (!Buffer)
return FALSE;
if (Compressed) {
if (LH5Decode(BIOSImage + Offset + 8,
ROMSize, Buffer, BufferSize) == -1) {
Compressed = FALSE;
munmap(Buffer, BufferSize);
unlink(filename);
goto NotCompressed;
}
} else
memcpy(Buffer, BIOSImage + Offset + 8,
BufferSize);
munmap(Buffer, BufferSize);
Offset += ROMSize;
}
return TRUE;
}
/*
*
*/
Bool
AMI941010Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t AMIBOffset, uint32_t ABCOffset)
{
Bool Compressed;
char Date[9];
unsigned char *ABWOffset;
char Version[5];
int i;
struct part {
const uint16_t RealCS;
const uint8_t PartID;
const uint8_t IsComprs;
} *part;
struct headerinfo {
const uint16_t ModuleCount;
} *headerinfo;
struct b94 {
const uint16_t PackLenLo;
const uint16_t PackLenHi;
const uint16_t RealLenLo;
const uint16_t RealLenHi;
} *b94;
/* Get Date */
memcpy(Date, BIOSImage + BIOSLength - 11, 8);
Date[8] = 0;
if (AMIBOffset)
ABWOffset = BIOSImage + AMIBOffset;
else
ABWOffset = memmem(BIOSImage + AMIBOffset, BIOSLength - AMIBOffset, "AMIBIOS W ", 10);
if (ABWOffset) {
Version[0] = *(ABWOffset + 10);
Version[1] = *(ABWOffset + 11);
Version[2] = *(ABWOffset + 13);
Version[3] = *(ABWOffset + 14);
Version[4] = 0;
} else {
Version[0] = 0;
}
if (BIOSImage[ABCOffset] == 'O') /* NexGen */
ABCOffset -= 5;
printf("AMI94 Version\t: %s (%s)\n", Version, Date);
/* 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 */
headerinfo = (struct headerinfo *)(BIOSImage + ABCOffset + 0x10);
for (i = 0; i < headerinfo->ModuleCount; i++) {
char filename[64], *ModuleName;
unsigned char *Buffer;
int BufferSize, ROMSize;
part = (struct part *)(BIOSImage + ABCOffset + 0x14 + (i * 4));
b94 = (struct b94 *)(BIOSImage + ABCOffset + part->RealCS);
if (part->IsComprs & 0x80)
Compressed = FALSE;
else
Compressed = TRUE;
sprintf(filename, "amibody_%02x.rom", i);
NotCompressed:
if (Compressed) {
ROMSize = le16toh(b94->PackLenLo);
BufferSize = le16toh(b94->RealLenLo);
} else {
ROMSize = BufferSize = 0x10000 - part->RealCS;
}
printf("0x%05X (%6d bytes)", ABCOffset + part->RealCS + 8,
ROMSize);
printf(" -> %-20s", filename);
if (Compressed)
printf(" (%6d bytes)", BufferSize);
else
printf(" ");
ModuleName = AMI95ModuleNameGet(part->PartID);
if (ModuleName)
printf(" \"%s\"\n", ModuleName);
else
printf("\n");
Buffer = MMapOutputFile(filename, BufferSize);
if (!Buffer)
return FALSE;
if (Compressed) {
if (LH5Decode(BIOSImage + ABCOffset + part->RealCS + 8,
ROMSize, Buffer, BufferSize) == -1) {
Compressed = FALSE;
munmap(Buffer, BufferSize);
unlink(filename);
goto NotCompressed;
}
} else
memcpy(Buffer, BIOSImage + ABCOffset + part->RealCS,
BufferSize);
munmap(Buffer, BufferSize);
}
return TRUE;
}
/*
*
*/
Bool
AMI95Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t AMIBOffset, uint32_t ABCOffset)
{
Bool Compressed, ZeroVersion;
uint32_t Offset, PackedOffset, NewOffset;
char Date[9], OffsetMode;
int i;
struct abc {
const char AMIBIOSC[8];
const char Version[4];
const uint16_t CRCLen;
const uint32_t CRC32;
const uint16_t BeginLo;
const uint16_t BeginHi;
} *abc;
struct bigpart {
const uint32_t CSize;
const uint32_t Unknown;
} *bigpart;
struct part {
/* When Previous Part Address is 0xFFFFFFFF, then this is the last part. */
uint16_t PrePartLo; /* Previous part low word */
uint16_t PrePartHi; /* Previous part high word */
uint16_t CSize; /* Header length */
uint8_t PartID; /* ID for this header */
uint8_t IsComprs; /* 0x80 -> compressed */
uint32_t RealCS; /* Old BIOSes:
Real Address in RAM where to expand to
Now:
Type 0x20 PCI ID of device for this ROM
Type 0x21 Language ID (ascii) */
uint32_t ROMSize; /* Compressed Length */
uint32_t ExpSize; /* Expanded Length */
} *part;
if (!ABCOffset) {
if ((BIOSImage[8] == '1') && (BIOSImage[9] == '0') &&
(BIOSImage[11] == '1') && (BIOSImage[12] == '0'))
return AMI941010Extract(BIOSImage, BIOSLength, BIOSOffset, 0, 0);
else
return AMI940725Extract(BIOSImage, BIOSLength, BIOSOffset, 0, 0);
}
if (ABCOffset + sizeof (struct abc) < BIOSLength) {
abc = (struct abc *)(BIOSImage + ABCOffset);
ZeroVersion = (memcmp(abc->Version, "0000", 4) == 0);
if ((memcmp(abc->Version, "AMIN", 4) == 0) || ZeroVersion) {
/* Skip to next one if immediately followed by "AMINCBLK"
* header or "0000" in place of a version number. */
abc = (struct abc *)memmem (BIOSImage + ABCOffset + 1,
BIOSLength - ABCOffset - 1 - sizeof (struct abc),
"AMIBIOSC", 8);
/* go back to the original if only a 0000 is present */
if (!abc && ZeroVersion)
abc = (struct abc *)(BIOSImage + ABCOffset);
}
} else
abc = NULL;
if (!abc) {
fprintf(stderr,
"Error: short read after AMIBIOSC signature.\n");
return FALSE;
}
/* Get Date */
memcpy(Date, BIOSImage + BIOSLength - 11, 8);
Date[8] = 0;
printf("AMI95 Version\t: %.4s (%s)\n", abc->Version, Date);
/* 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';
Offset = (le16toh(abc->BeginHi) << 16) + le16toh(abc->BeginLo);
if ((Offset - BIOSOffset) >= BIOSLength) {
OffsetModeB:
OffsetMode = 'B';
/* amideco considers 0x100000, but this only works up to 4 MB
8 MB is undecipherable so far */
PackedOffset = 0x100000;
Offset = (le16toh(abc->BeginHi) << 4) + le16toh(abc->BeginLo);
Offset = BIOSLength - (PackedOffset - (Offset + sizeof(struct abc))) - sizeof(struct abc);
}
} else {
OffsetMode = 'C';
Offset = (le16toh(abc->BeginHi) << 4) + le16toh(abc->BeginLo);
}
for (i = 0; i < 0x80; i++) {
char filename[64], *ModuleName;
unsigned char *Buffer;
int BufferSize, ROMSize;
if ((Offset - BIOSOffset) >= BIOSLength) {
fprintf(stderr, "Error: part overruns buffer at %05X\n",
Offset - BIOSOffset);
return FALSE;
}
part = (struct part *)(BIOSImage + (Offset - BIOSOffset));
if (part->IsComprs & 0x80)
Compressed = FALSE;
else
Compressed = TRUE;
/* even they claim they are compressed they arent */
if ((part->PartID == 0x40) || (part->PartID == 0x60))
Compressed = FALSE;
if (part->PartID == 0x20) {
uint16_t vid = le32toh(part->RealCS) & 0xFFFF;
uint16_t pid = le32toh(part->RealCS) >> 16;
sprintf(filename, "amipci_%04X_%04X.rom", vid, pid);
} else if (part->PartID == 0x21) {
sprintf(filename, "amilang_%c%c.rom",
(le32toh(part->RealCS) >> 8) & 0xFF,
le32toh(part->RealCS) & 0xFF);
} else
sprintf(filename, "amibody_%02x.rom", part->PartID);
NotCompressed:
if (Compressed) {
ROMSize = le32toh(part->ROMSize);
BufferSize = le32toh(part->ExpSize);
} else {
BufferSize = le16toh(part->CSize);
if (!BufferSize || (BufferSize == 0xFFFF)) {
bigpart =
(struct bigpart *)(BIOSImage +
(Offset - BIOSOffset) -
sizeof(struct bigpart));
BufferSize = le32toh(bigpart->CSize);
}
ROMSize = BufferSize;
}
/* misunderstood an offset mode B image */
if ((i == 0) && (OffsetMode == 'A') && (ROMSize == 0xFFFFFFFF))
goto OffsetModeB;
if (Compressed)
printf("0x%05X (%6d bytes)", Offset - BIOSOffset + 0x14,
ROMSize);
else
printf("0x%05X (%6d bytes)", Offset - BIOSOffset + 0x0C,
ROMSize);
printf(" -> %-20s", filename);
if (Compressed)
printf(" (%6d bytes)", BufferSize);
else
printf(" ");
ModuleName = AMI95ModuleNameGet(part->PartID);
if (ModuleName)
printf(" \"%s\"\n", ModuleName);
else
printf("\n");
Buffer = MMapOutputFile(filename, BufferSize);
if (!Buffer) {
if (Compressed) {
Compressed = FALSE;
goto NotCompressed;
} else {
return FALSE;
}
}
NewOffset = Offset - BIOSOffset;
if (Compressed)
NewOffset += 0x14;
else
NewOffset += 0x0C;
if ((NewOffset + ROMSize) >= BIOSLength)
ROMSize = BIOSLength - NewOffset;
if (Compressed) {
if (LH5Decode(BIOSImage + NewOffset,
ROMSize, Buffer, BufferSize) == -1) {
Compressed = FALSE;
munmap(Buffer, BufferSize);
unlink(filename);
goto NotCompressed;
}
} else
memcpy(Buffer, BIOSImage + NewOffset,
ROMSize);
munmap(Buffer, BufferSize);
if ((le16toh(part->PrePartHi) == 0xFFFF)
|| (le16toh(part->PrePartLo) == 0xFFFF))
break;
switch (OffsetMode) {
case 'B':
Offset =
(le16toh(part->PrePartHi) << 4) +
le16toh(part->PrePartLo);
Offset = BIOSLength - (PackedOffset - (Offset + sizeof(struct abc))) - sizeof(struct abc);
if ((Offset - BIOSOffset) < BIOSLength)
break;
case 'A':
Offset =
(le16toh(part->PrePartHi) << 16) +
le16toh(part->PrePartLo);
break;
case 'C':
Offset =
(le16toh(part->PrePartHi) << 4) +
le16toh(part->PrePartLo);
break;
}
}
return TRUE;
}

195
bios_extract/src/ami_slab.c Normal file
View File

@@ -0,0 +1,195 @@
/*
* Copyright 2010 Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>
#include <sys/mman.h>
#include "compat.h"
#if !defined(le32toh) || !defined(le16toh)
#if BYTE_ORDER == LITTLE_ENDIAN
#define le32toh(x) (x)
#define le16toh(x) (x)
#else
#include <byteswap.h>
#define le32toh(x) bswap_32(x)
#define le16toh(x) bswap_16(x)
#endif
#endif
struct slabentry {
uint32_t destaddr;
uint32_t length_flag;
};
struct slabheader {
uint16_t entries;
uint16_t headersize;
struct slabentry blocks[0];
};
struct nameentry {
uint8_t segtype;
uint16_t dtor_offset;
char name[0];
};
int slabextract(const unsigned char *buffer, int bufferlen)
{
const struct slabheader *h = (const void *)buffer;
const unsigned char *listpointer;
const unsigned char *datapointer;
int i, count, headersize;
headersize = le16toh(h->headersize);
count = le16toh(h->entries);
if ((headersize < ((count * 8) + 4)) || (bufferlen < headersize)) {
fprintf(stderr,
"Invalid file header - probably not a SLAB file\n");
return 1;
}
printf("%d entries\n", count);
/* FIXME: Is the 37 really constant? */
if (((8 * count) + 37) < headersize) {
listpointer = buffer + 8 * count + 37;
printf("Name Tp ");
} else {
listpointer = NULL; /* No names present */
printf("Name ");
}
datapointer = buffer + le32toh(h->headersize);
printf("LoadAddr size initialized\n");
for (i = 0; i < count; i++) {
const struct slabentry *block;
char filename[25];
uint32_t len;
int has_data;
if (listpointer) {
const struct nameentry *entry =
(const void *)listpointer;
block =
(const void *)(buffer +
le16toh(entry->dtor_offset));
sprintf(filename, "%.20s.bin", entry->name);
listpointer += strlen(entry->name) + 4;
printf("%-15s %02x ", entry->name, entry->segtype);
} else {
block = (const void *)(buffer + 4 + 8 * i);
sprintf(filename, "block%02d.bin", i);
printf("block%02d ", i);
}
len = le32toh(block->length_flag);
if (len & 0x80000000)
has_data = 1;
else
has_data = 0;
len &= 0x7fffffff;
printf("%08x %8d\t %s\n", le32toh(block->destaddr), len,
has_data ? "yes" : "no");
if (has_data) {
int outfd;
if (datapointer + len > buffer + bufferlen) {
fprintf(stderr,
"Not enough data. File truncated?\n");
return 1;
}
outfd =
open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (outfd != -1) {
int ret = write(outfd, datapointer, len);
if (ret == -1)
fprintf(stderr, "Can't write %s: %s\n",
filename, strerror(errno));
else if (ret < len)
fprintf(stderr,
"Can't write %s completely: Disk full?\n",
filename);
close(outfd);
} else
fprintf(stderr,
"Can't create output file %s: %s\n",
filename, strerror(errno));
datapointer += len;
}
}
if (datapointer != buffer + bufferlen)
fprintf(stderr, "Warning: Unexpected %d trailing bytes",
(int)(buffer + bufferlen - datapointer));
return 0;
}
int main(int argc, char *argv[])
{
int infd;
unsigned char *InputBuffer;
int InputBufferSize;
if (argc != 2) {
printf("usage: %s <input file>\n", argv[0]);
return 1;
}
infd = open(argv[1], O_RDONLY);
if (infd < 0) {
fprintf(stderr, "Error: Failed to open %s: %s\n", argv[1],
strerror(errno));
return 1;
}
InputBufferSize = lseek(infd, 0, SEEK_END);
if (InputBufferSize < 0) {
fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1],
strerror(errno));
return 1;
}
InputBuffer =
mmap(NULL, InputBufferSize, PROT_READ, MAP_PRIVATE, infd, 0);
if (InputBuffer < 0) {
fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1],
strerror(errno));
return 1;
}
/* fixed header size - everything else is checked dynamically in slabextract */
if (InputBufferSize < 4) {
fprintf(stderr,
"Error: \"%s\" is too small to be a SLAB file.\n",
argv[1]);
return 1;
}
return slabextract(InputBuffer, InputBufferSize);
}

73
bios_extract/src/award.c Normal file
View File

@@ -0,0 +1,73 @@
/*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define _GNU_SOURCE 1 /* for memmem */
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <sys/mman.h>
#include "compat.h"
#include "bios_extract.h"
#include "lh5_extract.h"
/*
*
*/
Bool
AwardExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t Offset1, uint32_t BCPSegmentOffset)
{
unsigned char *p, *Buffer;
int HeaderSize;
unsigned int BufferSize, PackedSize;
char *filename;
unsigned short crc;
printf("Found Award BIOS.\n");
p = BIOSImage;
while (p) {
p = memmem(p, BIOSLength - (p - BIOSImage), "-lh5-", 5);
if (!p)
break;
p -= 2;
HeaderSize = LH5HeaderParse(p, BIOSLength - (p - BIOSImage),
&BufferSize, &PackedSize, &filename,
&crc);
if (!HeaderSize)
return FALSE;
printf("0x%05X (%6d bytes) -> %s \t(%6d bytes)\n",
(unsigned int)(p - BIOSImage), HeaderSize + PackedSize,
filename, BufferSize);
Buffer = MMapOutputFile(filename, BufferSize);
if (!Buffer)
return FALSE;
LH5Decode(p + HeaderSize, PackedSize, Buffer, BufferSize);
munmap(Buffer, BufferSize);
p += HeaderSize + PackedSize;
}
return TRUE;
}

97
bios_extract/src/bcpvpd.c Normal file
View File

@@ -0,0 +1,97 @@
/*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This code is heavily based on Veit Kannegiesers <veit@kannegieser.net>
* e_bcpvpd.pas program. This software comes with no license, but is freely
* downloadable at http://kannegieser.net/veit/quelle/phoedeco_src.arj
*/
/*
* It should be very straightfoward to add support for the $COMPIBM compressed
* bios images as well. According to Veits code, the id-string is "$COMPIBM",
* and the data starts straight after the (not null-terminated) id-string.
*/
#define _GNU_SOURCE 1
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include "compat.h"
#include "lzss_extract.h"
int main(int argc, char *argv[])
{
int infd, outfd;
unsigned char *InputBuffer;
int InputBufferSize;
if (argc != 3) {
printf("usage: %s <input file> <output file>\n", argv[0]);
return 1;
}
infd = open(argv[1], O_RDONLY);
if (infd < 0) {
fprintf(stderr, "Error: Failed to open %s: %s\n", argv[1],
strerror(errno));
return 1;
}
InputBufferSize = lseek(infd, 0, SEEK_END);
if (InputBufferSize < 0) {
fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1],
strerror(errno));
return 1;
}
InputBuffer =
mmap(NULL, InputBufferSize, PROT_READ, MAP_PRIVATE, infd, 0);
if (InputBuffer < 0) {
fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1],
strerror(errno));
return 1;
}
if (InputBufferSize < 0x52) {
fprintf(stderr,
"Error: \"%s\" is too small tp be a BCPVPD file.\n",
argv[1]);
return 1;
}
if (strncmp((char *)InputBuffer, "BCPVPD", 7)) {
fprintf(stderr,
"Error: unable to find BCPVPD header in \"%s\".\n",
argv[1]);
return 1;
}
outfd = open(argv[2], O_RDWR | O_TRUNC | O_CREAT, S_IRWXU);
if (outfd == -1) {
fprintf(stderr, "Error: Failed to open \"%s\": %s\n", argv[2],
strerror(errno));
return 1;
}
return LZSSExtract(InputBuffer + 0x52, InputBufferSize - 0x52, outfd);
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
* Copyright 2021 RichardG <richardg867@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define _GNU_SOURCE /* memmem is useful */
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "compat.h"
#include "bios_extract.h"
#include "lh5_extract.h"
static void HelpPrint(char *name)
{
printf("\n");
printf("Program to extract compressed modules from BIOS images.\n");
printf("Supports AMI, Award, Phoenix and SystemSoft BIOSes.\n");
printf("\n");
printf("Usage:\n\t%s <filename>\n", name);
}
unsigned char *MMapOutputFile(char *filename, int size)
{
unsigned char *Buffer;
char *tmp;
int fd;
if ((size < 0) || (size > 16777216)) {
fprintf(stderr, "Error: %s too big (%d bytes)\n", filename,
size);
return NULL;
}
/* all slash signs '/' in filenames will be replaced by a backslash sign '\' */
tmp = filename;
while ((tmp = strchr(tmp, '/')) != NULL)
tmp[0] = '\\';
fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
fprintf(stderr, "Error: unable to open %s: %s\n\n", filename,
strerror(errno));
return NULL;
}
/* grow file */
if (lseek(fd, size - 1, SEEK_SET) == -1) {
fprintf(stderr, "Error: Failed to grow \"%s\": %s\n", filename,
strerror(errno));
close(fd);
return NULL;
}
if (write(fd, "", 1) != 1) {
fprintf(stderr, "Error: Failed to write to \"%s\": %s\n",
filename, strerror(errno));
close(fd);
return NULL;
}
Buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (Buffer == ((void *)-1)) {
fprintf(stderr, "Error: Failed to mmap %s: %s\n", filename,
strerror(errno));
close(fd);
return NULL;
}
close(fd);
return Buffer;
}
/* TODO: Make bios identification more flexible */
static struct {
char *String1;
char *String2;
Bool(*Handler) (unsigned char *Image, int ImageLength, int ImageOffset,
uint32_t Offset1, uint32_t Offset2);
} BIOSIdentification[] = {
{
"AMIBIOS (C)1993 American Megatrends Inc.,", "AMIBIOSC", AMI940725Extract}, {
"AMIBIOS W 04 ", "AMIBIOSC", AMI940725Extract}, {
"AMIBIOS W 05 ", "AMIBIOSC", AMI941010Extract}, {
"AMIBIOS W 05 ", "OSC10/10/94", AMI941010Extract}, { /* NexGen */
"AMIBOOT ROM", "AMIBIOSC0", AMI95Extract}, {
"SUPER ROM", "AMIBIOSC0", AMI95Extract}, { /* Supermicro */
"$ASUSAMI$", "AMIBIOSC0", AMI95Extract}, {
"AMIEBBLK", "AMIBIOSC0", AMI95Extract}, {
"AMIBIOSC06", NULL, AMI95Extract}, {
"AMIBIOSC07", NULL, AMI95Extract}, {
"AMIBIOSC08", NULL, AMI95Extract}, {
"AMIBIOSC09", NULL, AMI95Extract}, { /* Hyper-V legacy BIOS */
"= Award Decompression Bios =", NULL, AwardExtract}, {
"awardext.rom", NULL, AwardExtract}, {
"Phoenix Technologies", "BCPSEGMENT", PhoenixExtract}, {
"\xEE\x88SYSBIOS", "\xEE\x88", SystemSoftExtract}, {
"\xFF\x88SYSBIOS", "\xFF\x88", SystemSoftExtract}, { /* Insyde */
NULL, NULL, NULL},};
int main(int argc, char *argv[])
{
int FileLength = 0;
uint32_t BIOSOffset = 0;
unsigned char *BIOSImage = NULL,
IntelAMI[256], /* just 13 bytes needed, but LH5Decode overflows the buffer */
*Buffer = NULL;
int fd;
uint32_t Offset1 = 0, Offset2 = 0;
int i, len;
unsigned char *tmp;
if ((argc != 2) || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
HelpPrint(argv[0]);
return 1;
}
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Error: Failed to open %s: %s\n", argv[1],
strerror(errno));
return 1;
}
FileLength = lseek(fd, 0, SEEK_END);
if (FileLength < 0) {
fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1],
strerror(errno));
return 1;
}
BIOSOffset = (0x100000 - FileLength) & 0xFFFFF;
BIOSImage = mmap(NULL, FileLength, PROT_READ, MAP_PRIVATE, fd, 0);
if (BIOSImage < 0) {
fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1],
strerror(errno));
return 1;
}
printf("Using file \"%s\" (%ukB)\n", argv[1], FileLength >> 10);
for (i = 0; BIOSIdentification[i].Handler; i++) {
if ((i == 0) || strcmp(BIOSIdentification[i].String1, BIOSIdentification[i - 1].String1)) {
len = strlen(BIOSIdentification[i].String1);
tmp =
memmem(BIOSImage, FileLength - len,
BIOSIdentification[i].String1, len);
if (!tmp) {
Offset1 = -1;
continue;
}
Offset1 = tmp - BIOSImage;
} else if (Offset1 == -1) {
continue;
}
if (BIOSIdentification[i].String2) {
len = strlen(BIOSIdentification[i].String2);
tmp =
memmem(BIOSImage, FileLength - len,
BIOSIdentification[i].String2, len);
if (!tmp)
continue;
Offset2 = tmp - BIOSImage;
} else {
Offset2 = Offset1;
}
if (BIOSIdentification[i].Handler
(BIOSImage, FileLength, BIOSOffset, Offset1, Offset2))
return 0;
else
return 1;
}
/* Bruteforce Intel AMI Color fork LH5. */
for (i = 0; i < (FileLength - 10); i += 0x10000) {
BIOSOffset = i;
CopyrightOffset:if ((LH5Decode(BIOSImage + BIOSOffset, FileLength - BIOSOffset, IntelAMI, 13) > -1) &&
!memcmp(IntelAMI, "AMIBIOS(C)AMI", 13)) {
printf("Found Intel AMIBIOS.\nOffset: %X\n", BIOSOffset);
Buffer = MMapOutputFile("intelbody.bin", 65536);
if (!Buffer)
return 1;
i = 65536;
while ((LH5Decode(BIOSImage + BIOSOffset, FileLength - BIOSOffset, Buffer, i) == -1) &&
(i > 16))
i--;
munmap(Buffer, 65536);
return 0;
} else if (!(BIOSOffset & 0xff)) {
BIOSOffset += 0x44;
goto CopyrightOffset;
}
}
fprintf(stderr, "Error: Unable to detect BIOS Image type.\n");
return 1;
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef BIOS_EXTRACT_H
#define BIOS_EXTRACT_H
#define Bool int
#define FALSE 0
#define TRUE 1
#if !defined(le32toh) || !defined(le16toh)
#if BYTE_ORDER == LITTLE_ENDIAN
#define le32toh(x) (x)
#define le16toh(x) (x)
#else
#include <byteswap.h>
#define le32toh(x) bswap_32(x)
#define le16toh(x) bswap_16(x)
#endif
#endif
/* bios_extract.c */
unsigned char *MMapOutputFile(char *filename, int size);
/* ami.c */
Bool AMI940725Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t Offset1, uint32_t Offset2);
Bool AMI941010Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t Offset1, uint32_t Offset2);
Bool AMI95Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t Offset1, uint32_t Offset2);
/* phoenix.c */
Bool PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t Offset1, uint32_t Offset2);
/* award.c */
Bool AwardExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t Offset1, uint32_t Offset2);
/* systemsoft.c */
Bool SystemSoftExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t Offset1, uint32_t Offset2);
#endif /* BIOS_EXTRACT_H */

63
bios_extract/src/compat.c Normal file
View File

@@ -0,0 +1,63 @@
/*
* Decompression utility for AMI BIOSes.
*
* Copyright (C) 2009-2010 coresystems GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <string.h>
#ifdef __APPLE__
void *memmem(const void *haystack, size_t haystacklen, const void *needle,
size_t needlelen)
{
char *searchpointer = (char *)haystack;
char *patternpointer = (char *)needle;
char *endofsearch = searchpointer + haystacklen - needlelen;
if (!(haystack && needle && haystacklen && needlelen))
return NULL;
while (searchpointer <= endofsearch) {
if (*searchpointer == *patternpointer)
if (memcmp(searchpointer, patternpointer, needlelen) ==
0)
return searchpointer;
searchpointer++;
}
return NULL;
}
size_t strnlen(const char *s, size_t maxlen)
{
const char *end = memchr(s, '\0', maxlen);
return end ? (size_t) (end - s) : maxlen;
}
char *strndup(const char *s, size_t n)
{
size_t len = strnlen(s, n);
char *new = malloc(len + 1);
if (new == NULL)
return NULL;
new[len] = '\0';
return memcpy(new, s, len);
}
#endif

48
bios_extract/src/compat.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* Decompression utility for AMI BIOSes.
*
* Copyright (C) 2009-2010 coresystems GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef __APPLE__
void *memmem(const void *haystack, size_t haystacklen, const void *needle,
size_t needlelen);
size_t strnlen(const char *s, size_t maxlen);
char *strndup(const char *s, size_t n);
#endif
// "endian.h" does not exist on (at least) these platforms:
// NetBSD, OSF/Tru64, HP-UX 10, Solaris, A/UX, Ultrix and
// AIX. It exists on FreeBSD, Linux and Irix.
#ifdef __linux__
#include <endian.h>
#include <sys/stat.h>
#elif __FreeBSD__
#include <sys/endian.h>
#include <sys/stat.h>
#endif
#if !defined(le32toh) || !defined(le16toh)
#if BYTE_ORDER == LITTLE_ENDIAN
#define le32toh(x) (x)
#define le16toh(x) (x)
#else
#include <byteswap.h>
#define le32toh(x) bswap_32(x)
#define le16toh(x) bswap_16(x)
#endif
#endif

View File

@@ -0,0 +1,553 @@
/*
* This file is a severely cut down and cleaned up version of lha.
*
* All changes compared to lha-svn894 are:
*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* LHA has a terrible history... It dates back to 1988, has had many different
* authors and has been mostly Public Domain Software.
*
* Since 1999, Koji Arai <arai@users.sourceforge.jp> has been doing most of
* the work at http://sourceforge.jp/projects/lha/.
*/
#define _GNU_SOURCE 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "compat.h"
#include "lh5_extract.h"
/*
* LHA header parsing.
*/
static int calc_sum(unsigned char *p, int len)
{
int sum = 0;
while (len--)
sum += *p++;
return sum & 0xff;
}
/*
* level 1 header
*
*
* offset size field name
* -----------------------------------
* 0 1 header size [*1]
* 1 1 header sum
* -------------------------------------
* 2 5 method ID ^
* 7 4 skip size [*2] |
* 11 4 original size |
* 15 2 time |
* 17 2 date |
* 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
* 20 1 level (0x01 fixed) |
* 21 1 name length |
* 22 X filename |
* X+ 22 2 file crc (CRC-16) |
* X+ 24 1 OS ID |
* X +25 Y ??? |
* X+Y+25 2 next-header size v
* -------------------------------------------------
* X+Y+27 Z ext-header ^
* : |
* ----------------------------------- | [*2] skip size
* X+Y+Z+27 data |
* : v
* -------------------------------------------------
*
*/
unsigned int
LH5HeaderParse(unsigned char *Buffer, int BufferSize,
unsigned int *original_size, unsigned int *packed_size,
char **name, unsigned short *crc)
{
unsigned int offset;
unsigned char header_size, checksum, name_length;
if (BufferSize < 27) {
fprintf(stderr,
"Error: Packed Buffer is too small to contain an lha header.\n");
return 0;
}
/* check attribute */
if (Buffer[19] != 0x20) {
fprintf(stderr, "Error: Invalid lha header attribute byte.\n");
return 0;
}
/* check method */
if (memcmp(Buffer + 2, "-lh5-", 5) != 0) {
fprintf(stderr, "Error: Compression method is not LZHUFF5.\n");
return 0;
}
/* check header level */
if (Buffer[20] != 1) {
fprintf(stderr, "Error: Header level %d is not supported\n",
Buffer[20]);
return 0;
}
/* read in the full header */
header_size = Buffer[0];
if (BufferSize < (header_size + 2)) {
fprintf(stderr,
"Error: Packed Buffer is too small to contain the full header.\n");
return 0;
}
/* verify checksum */
checksum = Buffer[1];
if (calc_sum(Buffer + 2, header_size) != checksum) {
fprintf(stderr, "Error: Invalid lha header checksum.\n");
return 0;
}
*packed_size = le32toh(*(unsigned int *)(Buffer + 7));
*original_size = le32toh(*(unsigned int *)(Buffer + 11));
name_length = Buffer[21];
*name = strndup((char *)Buffer + 22, name_length);
*crc = le16toh(*(unsigned short *)(Buffer + 22 + name_length));
offset = header_size + 2;
/* Skip extended headers */
while (1) {
unsigned short extend_size =
le16toh(*(unsigned short *)(Buffer + offset - 2));
if (!extend_size)
break;
*packed_size -= extend_size;
offset += extend_size;
if (BufferSize < offset) {
fprintf(stderr,
"Error: Buffer to small to contain extended header.\n");
return 0;
}
}
return offset;
}
/*
* CRC Calculation.
*/
#define CRCPOLY 0xA001 /* CRC-16 (x^16+x^15+x^2+1) */
unsigned short CRC16Calculate(unsigned char *Buffer, int BufferSize)
{
unsigned short CRCTable[0x100];
unsigned short crc;
int i;
/* First, initialise our CRCTable */
for (i = 0; i < 0x100; i++) {
unsigned short r = i;
unsigned int j;
for (j = 0; j < 8; j++) {
if (r & 1)
r = (r >> 1) ^ CRCPOLY;
else
r >>= 1;
}
CRCTable[i] = r;
}
/* now go over the entire Buffer */
crc = 0;
for (i = 0; i < BufferSize; i++)
crc = CRCTable[(crc ^ Buffer[i]) & 0xFF] ^ (crc >> 8);
return crc;
}
/*
* Bit handling code.
*/
static unsigned char *CompressedBuffer;
static int CompressedSize;
static int CompressedOffset;
static unsigned short bitbuf;
static unsigned char subbitbuf, bitcount;
static void BitBufInit(unsigned char *Buffer, int BufferSize)
{
CompressedBuffer = Buffer;
CompressedOffset = 0;
CompressedSize = BufferSize;
bitbuf = 0;
subbitbuf = 0;
bitcount = 0;
}
static void fillbuf(unsigned char n)
{ /* Shift bitbuf n bits left, read n bits */
while (n > bitcount) {
n -= bitcount;
bitbuf = (bitbuf << bitcount) + (subbitbuf >> (8 - bitcount));
if (CompressedOffset < CompressedSize) {
subbitbuf = CompressedBuffer[CompressedOffset];
CompressedOffset++;
} else
subbitbuf = 0;
bitcount = 8;
}
bitcount -= n;
bitbuf = (bitbuf << n) + (subbitbuf >> (8 - n));
subbitbuf <<= n;
}
static unsigned short getbits(unsigned char n)
{
unsigned short x;
x = bitbuf >> (16 - n);
fillbuf(n);
return x;
}
static unsigned short peekbits(unsigned char n)
{
unsigned short x;
x = bitbuf >> (16 - n);
return x;
}
/*
*
* LHA extraction.
*
*/
#define MIN(a,b) ((a) <= (b) ? (a) : (b))
#define LZHUFF5_DICBIT 13 /* 2^13 = 8KB sliding dictionary */
#define MAXMATCH 256 /* formerly F (not more than 255 + 1) */
#define THRESHOLD 3 /* choose optimal value */
#define NP (LZHUFF5_DICBIT + 1)
#define NT (16 + 3) /* USHORT + THRESHOLD */
#define NC (255 + MAXMATCH + 2 - THRESHOLD)
#define PBIT 4 /* smallest integer such that (1 << PBIT) > * NP */
#define TBIT 5 /* smallest integer such that (1 << TBIT) > * NT */
#define CBIT 9 /* smallest integer such that (1 << CBIT) > * NC */
/* #if NT > NP #define NPT NT #else #define NPT NP #endif */
#define NPT 0x80
static unsigned short left[2 * NC - 1], right[2 * NC - 1];
static unsigned short c_table[4096]; /* decode */
static unsigned short pt_table[256]; /* decode */
static unsigned char c_len[NC];
static unsigned char pt_len[NPT];
static int
make_table(short nchar, unsigned char bitlen[], short tablebits,
unsigned short table[])
{
unsigned short count[17]; /* count of bitlen */
unsigned short weight[17]; /* 0x10000ul >> bitlen */
unsigned short start[17]; /* first code of bitlen */
unsigned short total;
unsigned int i, l;
int j, k, m, n, avail;
unsigned short *p;
avail = nchar;
/* initialize */
for (i = 1; i <= 16; i++) {
count[i] = 0;
weight[i] = 1 << (16 - i);
}
/* count */
for (i = 0; i < nchar; i++) {
if (bitlen[i] > 16) {
/* CVE-2006-4335 */
fprintf(stderr, "Error: Bad table (case a)\n");
return -1;
} else
count[bitlen[i]]++;
}
/* calculate first code */
total = 0;
for (i = 1; i <= 16; i++) {
start[i] = total;
total += weight[i] * count[i];
}
if (((total & 0xffff) != 0) || (tablebits > 16)) { /* 16 for weight below */
fprintf(stderr, "Error: make_table(): Bad table (case b)\n");
return -1;
}
/* shift data for make table. */
m = 16 - tablebits;
for (i = 1; i <= tablebits; i++) {
start[i] >>= m;
weight[i] >>= m;
}
/* initialize */
j = start[tablebits + 1] >> m;
k = MIN(1 << tablebits, 4096);
if (j != 0)
for (i = j; i < k; i++)
table[i] = 0;
/* create table and tree */
for (j = 0; j < nchar; j++) {
k = bitlen[j];
if (k == 0)
continue;
l = start[k] + weight[k];
if (k <= tablebits) {
/* code in table */
l = MIN(l, 4096);
for (i = start[k]; i < l; i++)
table[i] = j;
} else {
/* code not in table */
i = start[k];
if ((i >> m) > 4096) {
/* CVE-2006-4337 */
fprintf(stderr, "Error: Bad table (case c)");
exit(1);
}
p = &table[i >> m];
i <<= tablebits;
n = k - tablebits;
/* make tree (n length) */
while (--n >= 0) {
if (*p == 0) {
right[avail] = left[avail] = 0;
*p = avail++;
}
if (i & 0x8000)
p = &right[*p];
else
p = &left[*p];
i <<= 1;
}
*p = j;
}
start[k] = l;
}
return 0;
}
static int read_pt_len(short nn, short nbit, short i_special)
{
int i, c, n;
n = getbits(nbit);
if (n == 0) {
c = getbits(nbit);
for (i = 0; i < nn; i++)
pt_len[i] = 0;
for (i = 0; i < 256; i++)
pt_table[i] = c;
} else {
i = 0;
while (i < MIN(n, NPT)) {
c = peekbits(3);
if (c != 7)
fillbuf(3);
else {
unsigned short mask = 1 << (16 - 4);
while (mask & bitbuf) {
mask >>= 1;
c++;
}
fillbuf(c - 3);
}
pt_len[i++] = c;
if (i == i_special) {
c = getbits(2);
while (--c >= 0 && i < NPT)
pt_len[i++] = 0;
}
}
while (i < nn)
pt_len[i++] = 0;
if (make_table(nn, pt_len, 8, pt_table) == -1)
return -1;
}
return 0;
}
static int read_c_len(void)
{
short i, c, n;
n = getbits(CBIT);
if (n == 0) {
c = getbits(CBIT);
for (i = 0; i < NC; i++)
c_len[i] = 0;
for (i = 0; i < 4096; i++)
c_table[i] = c;
} else {
i = 0;
while (i < MIN(n, NC)) {
c = pt_table[peekbits(8)];
if (c >= NT) {
unsigned short mask = 1 << (16 - 9);
do {
if (bitbuf & mask)
c = right[c];
else
c = left[c];
mask >>= 1;
} while (c >= NT && (mask || c != left[c])); /* CVE-2006-4338 */
}
fillbuf(pt_len[c]);
if (c <= 2) {
if (c == 0)
c = 1;
else if (c == 1)
c = getbits(4) + 3;
else
c = getbits(CBIT) + 20;
while (--c >= 0)
c_len[i++] = 0;
} else
c_len[i++] = c - 2;
}
while (i < NC)
c_len[i++] = 0;
if (make_table(NC, c_len, 12, c_table) == -1)
return -1;
}
return 0;
}
static unsigned short decode_c_st1(void)
{
unsigned short j, mask;
j = c_table[peekbits(12)];
if (j < NC)
fillbuf(c_len[j]);
else {
fillbuf(12);
mask = 1 << (16 - 1);
do {
if (bitbuf & mask)
j = right[j];
else
j = left[j];
mask >>= 1;
} while (j >= NC && (mask || j != left[j])); /* CVE-2006-4338 */
fillbuf(c_len[j] - 12);
}
return j;
}
static unsigned short decode_p_st1(void)
{
unsigned short j, mask;
j = pt_table[peekbits(8)];
if (j < NP)
fillbuf(pt_len[j]);
else {
fillbuf(8);
mask = 1 << (16 - 1);
do {
if (bitbuf & mask)
j = right[j];
else
j = left[j];
mask >>= 1;
} while (j >= NP && (mask || j != left[j])); /* CVE-2006-4338 */
fillbuf(pt_len[j] - 8);
}
if (j != 0)
j = (1 << (j - 1)) + getbits(j - 1);
return j;
}
int
LH5Decode(unsigned char *PackedBuffer, int PackedBufferSize,
unsigned char *OutputBuffer, int OutputBufferSize)
{
unsigned short blocksize = 0;
unsigned int i, c;
int n = 0;
BitBufInit(PackedBuffer, PackedBufferSize);
fillbuf(2 * 8);
while (n < OutputBufferSize) {
if (blocksize == 0) {
blocksize = getbits(16);
if (read_pt_len(NT, TBIT, 3) == -1)
return -1;
if (read_c_len() == -1)
return -1;
if (read_pt_len(NP, PBIT, -1) == -1)
return -1;
}
blocksize--;
c = decode_c_st1();
if (c < 256)
OutputBuffer[n++] = c;
else {
int length = c - 256 + THRESHOLD;
int offset = 1 + decode_p_st1();
if (offset > n)
return -1;
for (i = 0; i < length; i++) {
OutputBuffer[n] = OutputBuffer[n - offset];
n++;
}
}
}
return 0;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LH5_EXTRACT_H
#define LH5_EXTRACT_H
unsigned int LH5HeaderParse(unsigned char *Buffer, int BufferSize,
unsigned int *original_size,
unsigned int *packed_size,
char **name, unsigned short *crc);
unsigned short CRC16Calculate(unsigned char *Buffer, int BufferSize);
int LH5Decode(unsigned char *PackedBuffer, int PackedBufferSize,
unsigned char *OutputBuffer, int OutputBufferSize);
int unlzari(unsigned char *in, int insz, unsigned char *out, int outsz, char common);
int unlzh(unsigned char *in, int insz, unsigned char *out, int outsz);
#endif /* LH5_EXTRACT_H */

137
bios_extract/src/lh5_test.c Normal file
View File

@@ -0,0 +1,137 @@
/*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Test/Example code for LH5 extraction.
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include "lh5_extract.h"
int main(int argc, char *argv[])
{
char *filename;
unsigned short header_crc;
unsigned int header_size, original_size, packed_size;
int infd, outfd;
int LHABufferSize = 0;
unsigned char *LHABuffer, *OutBuffer;
if (argc != 2) {
fprintf(stderr, "Error: archive file not specified\n");
return 1;
}
/* open archive file */
infd = open(argv[1], O_RDONLY);
if (infd == -1) {
fprintf(stderr, "Error: Failed to open \"%s\": %s\n", argv[1],
strerror(errno));
return 1;
}
LHABufferSize = lseek(infd, 0, SEEK_END);
if (LHABufferSize < 0) {
fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1],
strerror(errno));
return 1;
}
LHABuffer = mmap(NULL, LHABufferSize, PROT_READ, MAP_PRIVATE, infd, 0);
if (LHABuffer == ((void *)-1)) {
fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1],
strerror(errno));
return 1;
}
header_size = LH5HeaderParse(LHABuffer, LHABufferSize, &original_size,
&packed_size, &filename, &header_crc);
if (!header_size)
return 1;
if ((header_size + packed_size) < LHABufferSize) {
fprintf(stderr, "Error: LHA archive is bigger than \"%s\".\n",
argv[1]);
return 1;
}
outfd = open(filename, O_RDWR | O_TRUNC | O_CREAT, S_IRWXU);
if (outfd == -1) {
fprintf(stderr, "Error: Failed to open \"%s\": %s\n", filename,
strerror(errno));
return 1;
}
/* grow file */
if (lseek(outfd, original_size - 1, SEEK_SET) == -1) {
fprintf(stderr, "Error: Failed to grow \"%s\": %s\n", filename,
strerror(errno));
return 1;
}
if (write(outfd, "", 1) != 1) {
fprintf(stderr, "Error: Failed to write to \"%s\": %s\n",
filename, strerror(errno));
return 1;
}
OutBuffer =
mmap(NULL, original_size, PROT_READ | PROT_WRITE, MAP_SHARED, outfd,
0);
if (OutBuffer == ((void *)-1)) {
fprintf(stderr, "Error: Failed to mmap %s: %s\n", filename,
strerror(errno));
return 1;
}
LH5Decode(LHABuffer + header_size, packed_size, OutBuffer,
original_size);
if (CRC16Calculate(OutBuffer, original_size) != header_crc) {
fprintf(stderr, "Warning: invalid CRC on \"%s\"\n", filename);
return 1;
}
if (munmap(OutBuffer, original_size))
fprintf(stderr, "Warning: Failed to munmap \"%s\": %s\n",
filename, strerror(errno));
if (close(outfd))
fprintf(stderr, "Warning: Failed to close \"%s\": %s\n",
filename, strerror(errno));
free(filename);
/* get rid of our input file */
if (munmap(LHABuffer, LHABufferSize))
fprintf(stderr, "Warning: Failed to munmap \"%s\": %s\n",
argv[1], strerror(errno));
if (close(infd))
fprintf(stderr, "Warning: Failed to close \"%s\": %s\n",
argv[1], strerror(errno));
return 0;
}

View File

@@ -0,0 +1,263 @@
// modified by Luigi Auriemma for memory2memory decompression and removing encoding
/**************************************************************
LZARI.C -- A Data Compression Program
(tab = 4 spaces)
***************************************************************
4/7/1989 Haruhiko Okumura
Use, distribute, and modify this program freely.
Please send me your improved versions.
PC-VAN SCIENCE
NIFTY-Serve PAF01022
CompuServe 74050,1022
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/********** Bit I/O **********/
static
unsigned char *infile = NULL,
*infilel = NULL,
*outfile = NULL,
*outfilel = NULL;
static int xgetc(void *skip) {
if(infile >= infilel) return(-1);
return(*infile++);
}
static int xputc(int chr, void *skip) {
if(outfile >= outfilel) return(-1);
*outfile++ = chr;
return(chr);
}
static
unsigned long int textsize = 0;
static
int GetBit(void) /* Get one bit (0 or 1) */
{
static unsigned int buffer, mask = 0;
if ((mask >>= 1) == 0) {
buffer = xgetc(infile); mask = 128;
}
return ((buffer & mask) != 0);
}
/********** LZSS with multiple binary trees **********/
#define N 4096 /* size of ring buffer */
#define F 60 /* upper limit for match_length */
#define THRESHOLD 2 /* encode string into position and length
if match_length is greater than this */
#define NIL N /* index for root of binary search trees */
unsigned char text_buf[N + F - 1]; /* ring buffer of size N,
with extra F-1 bytes to facilitate string comparison */
int match_position, match_length, /* of longest match. These are
set by the InsertNode() procedure. */
lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children &
parents -- These constitute binary search trees. */
/********** Arithmetic Compression **********/
/* If you are not familiar with arithmetic compression, you should read
I. E. Witten, R. M. Neal, and J. G. Cleary,
Communications of the ACM, Vol. 30, pp. 520-540 (1987),
from which much have been borrowed. */
#define M 15
/* Q1 (= 2 to the M) must be sufficiently large, but not so
large as the unsigned long 4 * Q1 * (Q1 - 1) overflows. */
#define Q1 (1UL << M)
#define Q2 (2 * Q1)
#define Q3 (3 * Q1)
#define Q4 (4 * Q1)
#define MAX_CUM (Q1 - 1)
#define N_CHAR (256 - THRESHOLD + F)
/* character code = 0, 1, ..., N_CHAR - 1 */
unsigned long int low = 0, high = Q4, value = 0;
int shifts = 0; /* counts for magnifying low and high around Q2 */
int char_to_sym[N_CHAR], sym_to_char[N_CHAR + 1];
unsigned int
sym_freq[N_CHAR + 1], /* frequency for symbols */
sym_cum[N_CHAR + 1], /* cumulative freq for symbols */
position_cum[N + 1]; /* cumulative freq for positions */
static
void StartModel(void) /* Initialize model */
{
int ch, sym, i;
sym_cum[N_CHAR] = 0;
for (sym = N_CHAR; sym >= 1; sym--) {
ch = sym - 1;
char_to_sym[ch] = sym; sym_to_char[sym] = ch;
sym_freq[sym] = 1;
sym_cum[sym - 1] = sym_cum[sym] + sym_freq[sym];
}
sym_freq[0] = 0; /* sentinel (!= sym_freq[1]) */
position_cum[N] = 0;
for (i = N; i >= 1; i--)
position_cum[i - 1] = position_cum[i] + 10000 / (i + 200);
/* empirical distribution function (quite tentative) */
/* Please devise a better mechanism! */
}
static
void UpdateModel(int sym)
{
int i, c, ch_i, ch_sym;
if (sym_cum[0] >= MAX_CUM) {
c = 0;
for (i = N_CHAR; i > 0; i--) {
sym_cum[i] = c;
c += (sym_freq[i] = (sym_freq[i] + 1) >> 1);
}
sym_cum[0] = c;
}
for (i = sym; sym_freq[i] == sym_freq[i - 1]; i--) ;
if (i < sym) {
ch_i = sym_to_char[i]; ch_sym = sym_to_char[sym];
sym_to_char[i] = ch_sym; sym_to_char[sym] = ch_i;
char_to_sym[ch_i] = sym; char_to_sym[ch_sym] = i;
}
sym_freq[i]++;
while (--i >= 0) sym_cum[i]++;
}
static
int BinarySearchSym(unsigned int x)
/* 1 if x >= sym_cum[1],
N_CHAR if sym_cum[N_CHAR] > x,
i such that sym_cum[i - 1] > x >= sym_cum[i] otherwise */
{
int i, j, k;
i = 1; j = N_CHAR;
while (i < j) {
k = (i + j) / 2;
if (sym_cum[k] > x) i = k + 1; else j = k;
}
return i;
}
static
int BinarySearchPos(unsigned int x)
/* 0 if x >= position_cum[1],
N - 1 if position_cum[N] > x,
i such that position_cum[i] > x >= position_cum[i + 1] otherwise */
{
int i, j, k;
i = 1; j = N;
while (i < j) {
k = (i + j) / 2;
if (position_cum[k] > x) i = k + 1; else j = k;
}
return i - 1;
}
static
void StartDecode(void)
{
int i;
for (i = 0; i < M + 2; i++)
value = 2 * value + GetBit();
}
static
int DecodeChar(void)
{
int sym, ch;
unsigned long int range;
range = high - low;
sym = BinarySearchSym((unsigned int)
(((value - low + 1) * sym_cum[0] - 1) / range));
high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
low += (range * sym_cum[sym ]) / sym_cum[0];
for ( ; ; ) {
if (low >= Q2) {
value -= Q2; low -= Q2; high -= Q2;
} else if (low >= Q1 && high <= Q3) {
value -= Q1; low -= Q1; high -= Q1;
} else if (high > Q2) break;
low += low; high += high;
value = 2 * value + GetBit();
}
ch = sym_to_char[sym];
UpdateModel(sym);
return ch;
}
static
int DecodePosition(void)
{
int position;
unsigned long int range;
range = high - low;
position = BinarySearchPos((unsigned int)
(((value - low + 1) * position_cum[0] - 1) / range));
high = low + (range * position_cum[position ]) / position_cum[0];
low += (range * position_cum[position + 1]) / position_cum[0];
for ( ; ; ) {
if (low >= Q2) {
value -= Q2; low -= Q2; high -= Q2;
} else if (low >= Q1 && high <= Q3) {
value -= Q1; low -= Q1; high -= Q1;
} else if (high > Q2) break;
low += low; high += high;
value = 2 * value + GetBit();
}
return position;
}
/********** Encode and Decode **********/
int unlzari(unsigned char *in, int insz, unsigned char *out, int outsz, char common) {
int i, j, k, r, c;
unsigned long int count;
infile = in;
infilel = in + insz;
outfile = out;
outfilel = out + outsz;
textsize = (xgetc(infile));
textsize |= (xgetc(infile) << 8);
textsize |= (xgetc(infile) << 16);
textsize |= (xgetc(infile) << 24);
//if (textsize == 0) return(-1);
if (textsize == 0) return(0);
if (textsize < 0) return(-1);
StartDecode(); StartModel();
for (i = 0; i < N - F; i++) text_buf[i] = common;
r = N - F;
for (count = 0; count < textsize; ) {
if(infile >= infilel) break;
c = DecodeChar();
if (c < 256) {
xputc(c, outfile); text_buf[r++] = c;
r &= (N - 1); count++;
} else {
i = (r - DecodePosition() - 1) & (N - 1);
j = c - 255 + THRESHOLD;
for (k = 0; k < j; k++) {
c = text_buf[(i + k) & (N - 1)];
xputc(c, outfile); text_buf[r++] = c;
r &= (N - 1); count++;
}
}
}
return(outfile - out);
}

View File

@@ -0,0 +1,394 @@
// modified by Luigi Auriemma for memory2memory decompression and removing encoding
/**************************************************************
lzhuf.c
written by Haruyasu Yoshizaki 1988/11/20
some minor changes 1989/04/06
comments translated by Haruhiko Okumura 1989/04/07
getbit and getbyte modified 1990/03/23 by Paul Edwards
so that they would work on machines where integers are
not necessarily 16 bits (although ANSI guarantees a
minimum of 16). This program has compiled and run with
no errors under Turbo C 2.0, Power C, and SAS/C 4.5
(running on an IBM mainframe under MVS/XA 2.2). Could
people please use YYYY/MM/DD date format so that everyone
in the world can know what format the date is in?
external storage of filesize changed 1990/04/18 by Paul Edwards to
Intel's "little endian" rather than a machine-dependant style so
that files produced on one machine with lzhuf can be decoded on
any other. "little endian" style was chosen since lzhuf
originated on PC's, and therefore they should dictate the
standard.
initialization of something predicting spaces changed 1990/04/22 by
Paul Edwards so that when the compressed file is taken somewhere
else, it will decode properly, without changing ascii spaces to
ebcdic spaces. This was done by changing the ' ' (space literal)
to 0x20 (which is the far most likely character to occur, if you
don't know what environment it will be running on.
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static
unsigned char *infile = NULL,
*infilel = NULL,
*outfile = NULL,
*outfilel = NULL;
static int xgetc(void *skip) {
if(infile >= infilel) return(-1);
return(*infile++);
}
static int xputc(int chr, void *skip) {
if(outfile >= outfilel) return(-1);
*outfile++ = chr;
return(chr);
}
static
unsigned long int textsize = 0;
/********** LZSS compression **********/
#define N 4096 /* buffer size */
#define F 60 /* lookahead buffer size */
#define THRESHOLD 2
#define NIL N /* leaf of tree */
static
unsigned char
text_buf[N + F - 1];
/* Huffman coding */
#define N_CHAR (256 - THRESHOLD + F)
/* kinds of characters (character code = 0..N_CHAR-1) */
#define T (N_CHAR * 2 - 1) /* size of table */
#define R (T - 1) /* position of root */
#define MAX_FREQ 0x8000 /* updates tree when the */
typedef unsigned char uchar;
/* table for encoding and decoding the upper 6 bits of position */
/* for encoding */
uchar p_len[64] = {
0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
};
uchar p_code[64] = {
0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/* for decoding */
uchar d_code[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
};
uchar d_len[256] = {
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
};
unsigned freq[T + 1]; /* frequency table */
int prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
/* elements [T..T + N_CHAR - 1] which are used to get */
/* the positions of leaves corresponding to the codes. */
int son[T]; /* pointers to child nodes (son[], son[] + 1) */
unsigned getbuf = 0;
uchar getlen = 0;
static int GetBit(void) /* get one bit */
{
unsigned i;
while (getlen <= 8) {
if ((int)(i = xgetc(infile)) < 0) return(0); //i = 0;
getbuf |= i << (8 - getlen);
getlen += 8;
}
i = getbuf;
getbuf <<= 1;
getlen--;
return (int)((i & 0x8000) >> 15);
}
static int GetByte(void) /* get one byte */
{
unsigned i;
while (getlen <= 8) {
if ((int)(i = xgetc(infile)) < 0) return(0); //i = 0;
getbuf |= i << (8 - getlen);
getlen += 8;
}
i = getbuf;
getbuf <<= 8;
getlen -= 8;
return (int)((i & 0xff00) >> 8);
}
unsigned putbuf = 0;
uchar putlen = 0;
/* initialization of tree */
static void StartHuff(void)
{
int i, j;
for (i = 0; i < N_CHAR; i++) {
freq[i] = 1;
son[i] = i + T;
prnt[i + T] = i;
}
i = 0; j = N_CHAR;
while (j <= R) {
freq[j] = freq[i] + freq[i + 1];
son[j] = i;
prnt[i] = prnt[i + 1] = j;
i += 2; j++;
}
freq[T] = 0xffff;
prnt[R] = 0;
}
/* reconstruction of tree */
static void reconst(void)
{
int i, j, k;
unsigned f, l;
/* collect leaf nodes in the first half of the table */
/* and replace the freq by (freq + 1) / 2. */
j = 0;
for (i = 0; i < T; i++) {
if (son[i] >= T) {
freq[j] = (freq[i] + 1) / 2;
son[j] = son[i];
j++;
}
}
/* begin constructing tree by connecting sons */
for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
k = i + 1;
f = freq[j] = freq[i] + freq[k];
for (k = j - 1; f < freq[k]; k--);
k++;
l = (j - k) * 2;
memmove(&freq[k + 1], &freq[k], l);
freq[k] = f;
memmove(&son[k + 1], &son[k], l);
son[k] = i;
}
/* connect prnt */
for (i = 0; i < T; i++) {
if ((k = son[i]) >= T) {
prnt[k] = i;
} else {
prnt[k] = prnt[k + 1] = i;
}
}
}
/* increment frequency of given code by one, and update tree */
static void update(int c)
{
int i, j, k, l;
if (freq[R] == MAX_FREQ) {
reconst();
}
c = prnt[c + T];
do {
k = ++freq[c];
/* if the order is disturbed, exchange nodes */
if ((unsigned)k > freq[l = c + 1]) {
while ((unsigned)k > freq[++l]);
l--;
freq[c] = freq[l];
freq[l] = k;
i = son[c];
prnt[i] = l;
if (i < T) prnt[i + 1] = l;
j = son[l];
son[l] = i;
prnt[j] = c;
if (j < T) prnt[j + 1] = c;
son[c] = j;
c = l;
}
} while ((c = prnt[c]) != 0); /* repeat up to root */
}
unsigned code, len;
static int DecodeChar(void)
{
unsigned c;
c = son[R];
/* travel from root to leaf, */
/* choosing the smaller child node (son[]) if the read bit is 0, */
/* the bigger (son[]+1} if 1 */
while (c < T) {
c += GetBit();
c = son[c];
}
c -= T;
update(c);
return (int)c;
}
static int DecodePosition(void)
{
unsigned i, j, c;
/* recover upper 6 bits from table */
i = GetByte();
c = (unsigned)d_code[i] << 6;
j = d_len[i];
/* read lower 6 bits verbatim */
j -= 2;
while (j--) {
i = (i << 1) + GetBit();
}
return (int)(c | (i & 0x3f));
}
/* compression */
int unlzh(unsigned char *in, int insz, unsigned char *out, int outsz) {
int i, j, k, r, c;
unsigned long int count;
infile = in;
infilel = in + insz;
outfile = out;
outfilel = out + outsz;
/*textsize = (xgetc(infile));
textsize |= (xgetc(infile) << 8);
textsize |= (xgetc(infile) << 16);
textsize |= (xgetc(infile) << 24);
if (textsize == 0)
return(-1);*/
textsize = outsz;
StartHuff();
for (i = 0; i < N - F; i++)
text_buf[i] = 0x20;
r = N - F;
for (count = 0; count < textsize; ) {
c = DecodeChar();
if (c < 256) {
if (xputc(c, outfile) == -1) {
return(-1);
}
text_buf[r++] = (unsigned char)c;
r &= (N - 1);
count++;
} else {
i = (r - DecodePosition() - 1) & (N - 1);
j = c - 255 + THRESHOLD;
for (k = 0; k < j; k++) {
c = text_buf[(i + k) & (N - 1)];
if (xputc(c, outfile) == -1) {
return(-1);
}
text_buf[r++] = (unsigned char)c;
r &= (N - 1);
count++;
}
}
}
return(outfile - out);
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "lzss_extract.h"
static inline int
LZSSBufferWrite(int fd, unsigned char *Buffer, int *BufferCount,
unsigned char value)
{
Buffer[*BufferCount] = value;
*BufferCount += 1;
if (*BufferCount == 0x1000) {
if (write(fd, Buffer, 0x1000) != 0x1000) {
fprintf(stderr, "Error writing to output file: %s",
strerror(errno));
return 1;
}
*BufferCount = 0;
}
return 0;
}
int LZSSExtract(unsigned char *Input, int InputSize, int fd)
{
unsigned char Buffer[0x1000];
unsigned short BitBuffer = 0;
int i = 0, k, BitCount = 8, BufferCount = 0;
while (i < InputSize) {
if (BitCount == 8) {
BitBuffer = Input[i];
BitCount = -1;
} else if ((BitBuffer >> BitCount) & 0x01) {
if (LZSSBufferWrite(fd, Buffer, &BufferCount, Input[i]))
return 1;
} else if ((i + 1) < InputSize) {
int offset =
((Input[i] | ((Input[i + 1] & 0xF0) << 4)) -
0xFEE) & 0xFFF;
int length = (Input[i + 1] & 0x0F) + 3;
for (k = 0; k < length; k++) {
if (LZSSBufferWrite
(fd, Buffer, &BufferCount,
Buffer[(offset + k) & 0xFFF]))
return 1;
}
i++;
} else {
fprintf(stderr,
"Error: requesting data beyond end of input file.\n");
return 1;
}
i++;
BitCount++;
}
if (BufferCount) {
if (write(fd, Buffer, BufferCount) != BufferCount) {
fprintf(stderr, "Error writing to output file: %s",
strerror(errno));
return 1;
}
}
return 0;
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2009 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LZSS_EXTRACT_H
#define LZSS_EXTRACT_H
int LZSSExtract(unsigned char *Input, int InputSize, int fd);
#endif /* LZSS_EXTRACT_H */

1244
bios_extract/src/phoenix.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
/*
* Decompression utility for SystemSoft and Insyde MobilePRO BIOSes.
*
* Copyright 2021 RichardG <richardg867@gmail.com>
* Based on SYSODECO (c) 2000-2004 Veit Kannegieser
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define _GNU_SOURCE 1 /* for memmem */
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "bios_extract.h"
#include "compat.h"
#include "lh5_extract.h"
Bool
SystemSoftExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset,
uint32_t SYSBIOSOffset, uint32_t EE88Offset)
{
Bool IsPart, IsInsyde;
uint16_t Magic, Length;
uint32_t Offset, AdditionalBlockCount;
char filename[256], ModuleName[32];
int fd, i, j;
struct part {
uint16_t Magic; /* EE 88 */
unsigned char Name[8];
uint16_t AdditionalBlocks;
uint16_t PackedLen;
uint16_t Offset;
uint16_t Segment;
uint16_t Checksum;
} *part;
struct microcode {
uint32_t Magic;
uint32_t Unused;
uint16_t Year;
uint8_t Day;
uint8_t Month;
} *microcode;
struct additional {
uint16_t Magic; /* DD 88 */
char Data[31];
} *additional;
printf("Found SystemSoft/Insyde BIOS\n");
/* dump modules */
Offset = 0;
while (Offset < (BIOSLength - 20)) {
IsPart = IsInsyde = 0;
Length = 0;
part = (struct part *)(BIOSImage + Offset);
Magic = le16toh(part->Magic);
if ((Magic == 0x88EE) || (Magic == 0x88FF)) {
/* part */
if (((part->Name[0] < 'A') || (part->Name[0] > 'Z')) &&
((part->Name[1] < 'A') || (part->Name[1] > 'Z')) &&
(((part->Name[2] < 'A') || (part->Name[2] > 'Z')) &&
(part->Name[2] != ' ') && (part->Name[2] != 0x00))) {
Offset += 2;
continue;
}
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... */
strcpy(ModuleName, "Insyde module");
} else {
IsPart = 1;
ModuleName[0] = ModuleName[sizeof(part->Name) + 1] = '"';
ModuleName[sizeof(part->Name) + 2] = 0;
for (i = 0; i < sizeof(part->Name); i++) {
if ((part->Name[i] == 0x00) || (part->Name[i] == '\n'))
ModuleName[i + 1] = ' ';
else
ModuleName[i + 1] = part->Name[i];
}
}
AdditionalBlockCount = (le16toh(part->AdditionalBlocks) >> 4) & 7;
Offset += 20 + (33 * AdditionalBlockCount);
} else if (Magic == 0xAA55) {
/* option ROM */
Length = part->Name[0] * 512;
sprintf(filename, "ssopt_%05X.rom", Offset);
sprintf(ModuleName, "Option ROM");
} else if ((Magic == 0x5349) && (part->Name[0] == 'A')) {
/* ISA ROM */
Length = 0x2000;
sprintf(filename, "ssisa_%05X.rom", Offset);
sprintf(ModuleName, "ISA ROM");
} else if ((Magic == 0x061E) && (part->Name[0] == 0x8A) &&
(part->Name[1] == 0xD8) && (part->Name[2] == 0xB7)) {
/* "Battery Management?" */
Length = 0x800;
sprintf(filename, "ssbat_%05X.rom", Offset);
sprintf(ModuleName, "Battery Management?");
} else {
microcode = (struct microcode *)(BIOSImage + Offset);
if ((le32toh(microcode->Magic) == 0x00000001) &&
(le16toh(microcode->Year) >= 1990) &&
(le16toh(microcode->Year) <= 2090) &&
(microcode->Day >= 1) && (microcode->Day <= 31) &&
(microcode->Month >= 1) && (microcode->Month <= 12)) {
/* CPU microcode */
Length = 0x800;
sprintf(filename, "ssucode_%05X.rom", Offset);
sprintf(ModuleName, "CPU Microcode");
} else if (((Magic & 0xFF) == 0x00) || ((Magic & 0xFF) == 0xFF)) {
/* ignore 0x00/0xFF sequences */
while ((Offset < BIOSLength) &&
((BIOSImage[Offset] == 0x00) ||
(BIOSImage[Offset] == 0xFF)))
Offset++;
continue;
} else if ((BIOSLength - Offset) < 0x4000) {
Length = BIOSLength - Offset;
sprintf(filename, "ssboot.rom");
sprintf(ModuleName, "Boot Block");
} else {
Offset += 2;
continue;
}
}
if (!Length)
break;
fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
fprintf(stderr, "Error: unable to open %s: %s\n\n", filename,
strerror(errno));
return FALSE;
}
printf("0x%05X (%6d bytes) -> %-20s",
Offset, Length, filename);
if (IsPart) {
/* arithmetic decoding */
unsigned char *PackedData = BIOSImage + Offset,
*DecodeBuffer = malloc(65536);
uint32_t DecodeBufferPos = 0;
memset(DecodeBuffer, 0, 65536);
while (Length > 0) {
if (DecodeBufferPos >= 65536)
break;
i = *PackedData++;
Length--;
if (i <= 0x0F) {
i += 1;
memcpy(DecodeBuffer + DecodeBufferPos, PackedData, i);
PackedData += i;
Length -= i;
DecodeBufferPos += i;
} else {
j = (i >> 4) + 1;
i = ((i & 0x0F) << 8) | *PackedData++;
Length--;
if (i > DecodeBufferPos)
break;
/* copy manually, as memcpy and memmove corrupt data */
i = DecodeBufferPos - i;
while (j--)
DecodeBuffer[DecodeBufferPos++] = DecodeBuffer[i++];
}
}
write(fd, DecodeBuffer, DecodeBufferPos);
free(DecodeBuffer);
Offset = PackedData - BIOSImage;
printf(" (%6d bytes)\t%s\n", DecodeBufferPos, ModuleName);
for (i = 0; i < AdditionalBlockCount; i++) {
additional = (struct additional *)(((unsigned char *)part) + 20 + (33 * i));
printf("\t\t\t\t\t\t\t\t\"");
for (j = 0; j < sizeof(additional->Data); j++) {
if ((additional->Data[j] == 0x00) ||
(additional->Data[j] == '\n'))
putchar(' ');
else
putchar(additional->Data[j]);
}
printf("\"\n");
}
} else {
write(fd, BIOSImage + Offset, Length);
Offset += Length;
printf("\t\t\t%s\n", ModuleName);
}
close(fd);
}
return TRUE;
}

View File

@@ -0,0 +1,173 @@
#!/bin/sh
#
# Part of Gerrit Code Review (http://code.google.com/p/gerrit/)
#
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
CHANGE_ID_AFTER="Bug|Issue"
MSG="$1"
# Check for, and add if missing, a unique Change-Id
#
add_ChangeId() {
clean_message=`sed -e '
/^diff --git a\/.*/{
s///
q
}
/^Signed-off-by:/d
/^#/d
' "$MSG" | git stripspace`
if test -z "$clean_message"
then
return
fi
# Does Change-Id: already exist? if so, exit (no change).
if grep -i '^Change-Id: I[0-9a-f]\{40\}$' "$MSG" >/dev/null
then
return
fi
id=`_gen_ChangeId`
T="$MSG.tmp.$$"
AWK=awk
if [ -x /usr/xpg4/bin/awk ]; then
# Solaris AWK is just too broken
AWK=/usr/xpg4/bin/awk
fi
# How this works:
# - parse the commit message as (textLine+ blankLine*)*
# - assume textLine+ to be a footer until proven otherwise
# - exception: the first block is not footer (as it is the title)
# - read textLine+ into a variable
# - then count blankLines
# - once the next textLine appears, print textLine+ blankLine* as these
# aren't footer
# - in END, the last textLine+ block is available for footer parsing
$AWK '
BEGIN {
# while we start with the assumption that textLine+
# is a footer, the first block is not.
isFooter = 0
footerComment = 0
blankLines = 0
}
# Skip lines starting with "#" without any spaces before it.
/^#/ { next }
# Skip the line starting with the diff command and everything after it,
# up to the end of the file, assuming it is only patch data.
# If more than one line before the diff was empty, strip all but one.
/^diff --git a/ {
blankLines = 0
while (getline) { }
next
}
# Count blank lines outside footer comments
/^$/ && (footerComment == 0) {
blankLines++
next
}
# Catch footer comment
/^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) {
footerComment = 1
}
/]$/ && (footerComment == 1) {
footerComment = 2
}
# We have a non-blank line after blank lines. Handle this.
(blankLines > 0) {
print lines
for (i = 0; i < blankLines; i++) {
print ""
}
lines = ""
blankLines = 0
isFooter = 1
footerComment = 0
}
# Detect that the current block is not the footer
(footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) {
isFooter = 0
}
{
# We need this information about the current last comment line
if (footerComment == 2) {
footerComment = 0
}
if (lines != "") {
lines = lines "\n";
}
lines = lines $0
}
# Footer handling:
# If the last block is considered a footer, splice in the Change-Id at the
# right place.
# Look for the right place to inject Change-Id by considering
# CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first,
# then Change-Id, then everything else (eg. Signed-off-by:).
#
# Otherwise just print the last block, a new line and the Change-Id as a
# block of its own.
END {
unprinted = 1
if (isFooter == 0) {
print lines "\n"
lines = ""
}
changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):"
numlines = split(lines, footer, "\n")
for (line = 1; line <= numlines; line++) {
if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) {
unprinted = 0
print "Change-Id: I'"$id"'"
}
print footer[line]
}
if (unprinted) {
print "Change-Id: I'"$id"'"
}
}' "$MSG" > $T && mv $T "$MSG" || rm -f $T
}
_gen_ChangeIdInput() {
echo "tree `git write-tree`"
if parent=`git rev-parse "HEAD^0" 2>/dev/null`
then
echo "parent $parent"
fi
echo "author `git var GIT_AUTHOR_IDENT`"
echo "committer `git var GIT_COMMITTER_IDENT`"
echo
printf '%s' "$clean_message"
}
_gen_ChangeId() {
_gen_ChangeIdInput |
git hash-object -t commit --stdin
}
add_ChangeId

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
This kit contains the tools to extract files from an EFI firmware
image.
Step 1: Getting the image
---------------------------
You can get a firmware image by extracting it from any vendor updater
package, or by using the 'dumpfv.efi' program from rEFIt.
The suffix of the image name is often ".fd".
Step 2: Extracting the image
------------------------------
Run "xfv.py" with the image file name as a parameter.
You may want to capture output from xfv for later reference, e.g.:
./xfv.py MBP11_0044_02B.fd | tee mbp11-output.txt
Some notes
------------
Early Apple firmware images (e.g. the original images for the iMac, MBP
and Mac mini models as present on the Firmware Restoration CD) include
file names for drivers and applications. Later images (e.g. the Boot
Camp firmware updates) don't. However, the GUID of the files is fixed,
so a future version of xfv may support building a dictionary of file
names and using them for images that don't have embedded file names.
The current version only supports one "firmware volume" per file. The
firmware images actually contain 4 parts:
Offset Size Content
000000 1A0000 Main firmware volume: DXE core, DXE drivers
1A0000 010000 Firmware volume, use unknown
1B0000 030000 Contents unknown
1E0000 020000 Firmware volume: PEI core, PEI drivers

View File

@@ -0,0 +1,107 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "efihack.h"
EFI_STATUS
EFIAPI
EfiGetInfo (
IN VOID *Source,
IN UINT32 SrcSize,
OUT UINT32 *DstSize,
OUT UINT32 *ScratchSize
);
EFI_STATUS
EFIAPI
EfiDecompress (
IN VOID *Source,
IN UINT32 SrcSize,
IN OUT VOID *Destination,
IN UINT32 DstSize,
IN OUT VOID *Scratch,
IN UINT32 ScratchSize
);
int main(int argc, char **argv)
{
char *buffer;
long buflen, fill;
ssize_t got;
char *dstbuf, *scratchbuf;
UINT32 DstSize;
UINT32 ScratchSize;
EFI_STATUS Status;
// read all data from stdin
buflen = 32768;
fill = 0;
buffer = malloc(buflen);
if (buffer == NULL) {
fprintf(stderr, "Out of memory!\n");
return 1;
}
for (;;) {
if (fill == buflen) {
long newbuflen;
newbuflen = buflen << 1;
buffer = realloc(buffer, newbuflen);
if (buffer == NULL) {
fprintf(stderr, "Out of memory!\n");
return 1;
}
buflen = newbuflen;
}
got = read(0, buffer + fill, buflen - fill);
if (got < 0) {
fprintf(stderr, "Error during read: %d\n", errno);
return 1;
} else if (got == 0) {
break; // EOF
} else {
fill += got;
}
}
//fprintf(stderr, "got %d bytes\n", fill);
// inspect data
Status = EfiGetInfo(buffer, fill, &DstSize, &ScratchSize);
if (Status != EFI_SUCCESS) {
fprintf(stderr, "EFI ERROR (get info)\n");
return 1;
}
dstbuf = malloc(DstSize);
scratchbuf = malloc(ScratchSize);
if (dstbuf == NULL || scratchbuf == NULL) {
fprintf(stderr, "Out of memory!\n");
return 1;
}
// decompress data
Status = EfiDecompress(buffer, fill, dstbuf, DstSize, scratchbuf, ScratchSize);
if (Status != EFI_SUCCESS) {
fprintf(stderr, "EFI ERROR (decompress)\n");
return 1;
}
// write to stdout
while (DstSize > 0) {
got = write(1, dstbuf, DstSize);
if (got < 0) {
fprintf(stderr, "Error during write: %d\n", errno);
return 1;
} else {
dstbuf += got;
DstSize -= got;
}
}
return 0;
}

View File

@@ -0,0 +1,24 @@
#include <stdint.h>
#define VOID void
#define UINT8 uint8_t
#define UINT16 uint16_t
#define UINT32 uint32_t
#define UINT64 uint64_t
#define INT8 int8_t
#define INT16 int16_t
#define INT32 int32_t
#define INT64 int64_t
#define EFI_STATUS UINT32
#define EFI_SUCCESS (0)
#define EFI_INVALID_PARAMETER (-5)
#define EFIAPI
#define IN
#define OUT
#define OPTIONAL
#define STATIC static
#undef UINT8_MAX

362
bios_extract/xfv/xfv.py Normal file
View File

@@ -0,0 +1,362 @@
#!/usr/bin/python
import sys
import os
from struct import unpack
fvh_count = 0
### Formatting: GUIDs
def format_guid(guid_s):
parts = unpack("<LHH8B", guid_s)
return "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" % parts
### Formatting: file types
filetypes = ("ALL ", "RAW ", "FREE", "SECc", "PEIc", "DXEc", "PEIM", "DRVR", "CPDR", "APPL", "SMM", "FVIM", "SMMDXE", "SMMCORE")
filetype_exts = ("all", "raw", "free", "seccore", "peicore", "dxecore", "peim", "drv", "comb_peim_drv", "app", "unkn0a", "fd")
def format_filetype(filetype_num):
if filetype_num < len(filetypes):
return filetypes[filetype_num]
if filetype_num == 0xF0:
return "PAD"
return "??%02X" % filetype_num
def extention_filetype(filetype_num):
if filetype_num < len(filetype_exts):
return filetype_exts[filetype_num]
return "unkn%02x" % filetype_num
### Main function to analyze a host disk file
def analyze_diskfile(filename, offset = 0):
f = file(filename, "rb")
fvdata = f.read()
f.close()
print "Analyzing %s, 0x%X bytes" % (filename, len(fvdata))
if fvdata[offset:offset+16] == "\xBD\x86\x66\x3B\x76\x0D\x30\x40\xB7\x0E\xB5\x51\x9E\x2F\xC5\xA0":
# EFI capsule
(capguid, capheadsize, capflags, capimagesize, capseqno, capinstance, capsplitinfooffset, capbodyoffset, cap3offset, cap4offset, cap5offset, cap6offset, cap7offset, cap8offset) = unpack("< 16s L L L L 16s L L 6L", fvdata[offset:offset+80])
print "EFI Capsule, %d bytes" % capimagesize
handle_fv(fvdata[offset+capbodyoffset:offset+capbodyoffset+capimagesize], format_guid(capguid))
else:
# treat as sequence of firmware volumes
while offset < len(fvdata):
print "offset: %08X" % offset
usedsize = handle_fv(fvdata[offset:], "%08X" % offset)
if usedsize == 0:
offset += 0x10000
else:
offset += usedsize
### Handle a firmware volume
def handle_fv(fvdata, name='default'):
### Check header
(fvzero, fvfstype, fvlen, fvsig, fvattr, fvhdrlen, fvchecksum, fvrev) = unpack("< 16s 16s Q 4s L H H 3x B", fvdata[0:0x38])
if fvsig != "_FVH" and fvfstype != '\xD9\x54\x93\x7A\x68\x04\x4A\x44\x81\xCE\x0B\xF6\x17\xD8\x90\xDF':
if fvdata[0] == '\xFF':
print "Skipping FFs"
offset = 0
while fvdata[offset] == '\xFF':
offset += 1
return offset
else:
print "Not a EFI firmware volume (sig and GUID missing)"
return 0
if fvlen > len(fvdata):
print "WARNING: File too short, header gives length as 0x%X bytes" % fvlen
else:
print "Size per header: 0x%X bytes" % fvlen
offset = fvhdrlen
global fvh_count
#fvhdir = "fvh-%d" % fvh_count
fvhdir = "fvh-" + name
fvh_count = fvh_count + 1
try:
os.mkdir(fvhdir)
except:
pass
os.chdir(fvhdir)
### Decode files
print "Listing files"
print "-----"
while True:
if offset == fvlen:
print "-----"
print "End of volume (size reached cleanly)"
break
if offset + 24 > fvlen:
print "-----"
print "End of volume (size reached uncleanly)"
break
(fileguid, fileintcheck, filetype, fileattr, filelenandstate) = unpack("< 16s H B B L", fvdata[offset:offset+24])
if filetype == 0xff:
print "-----"
print "End of volume (filler data found)"
break
fileentrylen = filelenandstate & 0xffffff
filestate = filelenandstate >> 24
filelen = fileentrylen - 24
if fileattr & 1:
print " has tail!"
filelen = filelen - 2
fileoffset = offset + 24
nextoffset = (offset + fileentrylen + 7) & ~7
print "%08X %08X" % (fileoffset, nextoffset)
filedata = fvdata[fileoffset:fileoffset+filelen]
compressed = False
if filetype != 1 and filelen > 3 and filedata[3] == "\x01":
compressed = True
filedata = decompress(filedata)
if compressed:
print "%08X %s %s C %d (%d)" % (offset, format_guid(fileguid), format_filetype(filetype), len(filedata), filelen)
else:
print "%08X %s %s U %d" % (offset, format_guid(fileguid), format_filetype(filetype), filelen)
if filetype != 0xF0:
handle_file("file-%s.%s" % (format_guid(fileguid), extention_filetype(filetype)), filetype, filedata)
else:
print "(skipping)"
offset = nextoffset
os.chdir('..')
return fvlen
if sys.platform == 'win32':
efidecomp_path = os.path.join(os.path.dirname(__file__), "UEFI_Decompressor")
efidecomp_cmd = '"%s" %s %s'
else:
efidecomp_path = os.path.dirname(os.path.realpath(__file__)) + "/efidecomp"
efidecomp_cmd = "%s < %s > %s"
### Handle decompression of a compressed section
def decompress2(compdata):
f = file("_tmp_decompress", "wb")
f.write(compdata)
f.close()
cmd = efidecomp_cmd % ( efidecomp_path, '_tmp_decompress', '_tmp_result')
print "cmd: %r" % cmd
os.system(cmd)
f = file("_tmp_result", "rb")
decompdata = f.read()
f.close()
return decompdata
def decompress(compdata):
(sectlenandtype, uncomplen, comptype) = unpack("< L L B", compdata[0:9])
sectlen = sectlenandtype & 0xffffff
if sectlen < len(compdata):
print "WARNING: Compressed section is not the only section! (%d/%d)" % (sectlen, len(compdata))
if comptype == 0:
return compdata[9:]
elif comptype == 1:
print "WARNING: this code path might not work";
f = file("_tmp_decompress", "wb")
f.write(compdata[9:])
f.close()
cmd = efidecomp_cmd % ( efidecomp_path, '_tmp_decompress', '_tmp_result')
#cmd = "./efidecomp <_tmp_decompress >_tmp_result"
os.system(cmd)
f = file("_tmp_result", "rb")
decompdata = f.read()
f.close()
if len(decompdata) < uncomplen:
print "WARNING: Decompressed data too short!"
return decompdata
elif comptype == 2:
f = file("_tmp_decompress", "wb")
f.write(compdata[13:sectlen+4]) # for some reason there is junk in 9:13 that I don't see in the raw files?! yuk.
f.close()
os.system("lzmadec <_tmp_decompress >_tmp_result")
f = file("_tmp_result", "rb")
decompdata = f.read()
f.close()
if len(decompdata) < uncomplen:
print "WARNING: Decompressed data too short!"
return decompdata
else:
print "ERROR: Unknown compression type %d" % comptype
return compdata
### Handle the contents of one firmware file
def handle_file(filename, filetype, filedata):
if filetype == 1:
f = file("%s.raw" % filename, "wb")
f.write(filedata)
f.close()
if filetype != 1:
handle_sections(filename, 0, filedata)
def get_filename(imagedata):
imagelen = len(imagedata)
filename_override = None
# first try to find a filename
offset = 0
while offset + 4 <= imagelen:
(sectlenandtype,) = unpack("< L", imagedata[offset:offset + 4])
sectlen = sectlenandtype & 0xffffff
secttype = sectlenandtype >> 24
nextoffset = (offset + sectlen + 3) & ~3
dataoffset = offset + 4
datalen = sectlen - 4
sectdata = imagedata[dataoffset:dataoffset + datalen]
if secttype == 0x15:
filename_override = sectdata[:-2].decode(
"utf-16le").encode("utf-8")
print " Filename '%s'" % filename_override
offset = nextoffset
return filename_override
### Handle section data (i.e. multiple sections), recurse if necessary
def handle_sections(filename, sectindex, imagedata):
imagelen = len(imagedata)
# first try to find a filename
filename_override = get_filename(imagedata)
# then analyze the sections for good
offset = 0
while offset + 4 <= imagelen:
(sectlenandtype,) = unpack("< L", imagedata[offset:offset + 4])
sectlen = sectlenandtype & 0xffffff
secttype = sectlenandtype >> 24
nextoffset = (offset + sectlen + 3) & ~3
dataoffset = offset + 4
datalen = sectlen - 4
if secttype == 2:
(sectguid, sectdataoffset, sectattr) = unpack("< 16s H H", imagedata[offset+4:offset+24])
dataoffset = offset + sectdataoffset
datalen = sectlen - sectdataoffset
if sectguid == "\xB0\xCD\x1B\xFC\x31\x7D\xAA\x49\x93\x6A\xA4\x60\x0D\x9D\xD0\x83":
# CRC32 section
sectindex = handle_sections(filename, sectindex, imagedata[
dataoffset:dataoffset + datalen])
else:
print " %02d GUID %s" % (sectindex, format_guid(sectguid))
sectindex += 1
sectindex = handle_sections(filename, sectindex, imagedata[
dataoffset:dataoffset + datalen])
elif secttype == 1: # compressed
sectdata = imagedata[dataoffset:dataoffset+datalen]
decdata = decompress2(sectdata)
print " %02d COMPRESSED %d => %d" % (sectindex, datalen, len(decdata))
if filename_override == None:
filename_override = get_filename(decdata)
sectindex += 1
sectindex = handle_sections(filename, sectindex, decdata)
else:
secttype_name = "UNKNOWN(%02X)" % secttype
ext = "data"
sectdata = imagedata[dataoffset:dataoffset + datalen]
extraprint = ""
if secttype == 0x1:
secttype_name = "COMPRESSED"
ext = "comp"
if secttype == 0x10:
secttype_name = "PE32"
ext = "efi"
elif secttype == 0x11:
secttype_name = "PIC"
ext = "pic.efi"
elif secttype == 0x12:
secttype_name = "TE"
ext = "te"
elif secttype == 0x13:
secttype_name = "DXE_DEPEX"
ext = "depex"
elif secttype == 0x14:
secttype_name = "VERSION"
ext = "ver"
elif secttype == 0x15:
secttype_name = "USER_INTERFACE"
ext = None
elif secttype == 0x16:
secttype_name = "COMPATIBILITY16"
ext = "bios"
elif secttype == 0x17:
secttype_name = "FIRMWARE_VOLUME_IMAGE"
ext = "fd"
elif secttype == 0x18:
secttype_name = "FREEFORM_SUBTYPE_GUID"
ext = "guid"
elif secttype == 0x19:
secttype_name = "RAW"
ext = "raw"
if sectdata[0:8] == "\x89PNG\x0D\x0A\x1A\x0A":
ext = "png"
elif sectdata[0:4] == "icns":
ext = "icns"
elif secttype == 0x1B:
secttype_name = "PEI_DEPEX"
ext = None
print " %02d %s %d%s" % (
sectindex, secttype_name, datalen, extraprint)
if ext is not None:
use_filename = "%s-%02d" % (filename, sectindex)
if filename_override is not None:
use_filename = filename_override
f = file("%s.%s" % (use_filename, ext), "wb")
f.write(sectdata)
f.close()
if secttype == 0x17:
print "*** Recursively analyzing the contained firmware volume..."
handle_fv(sectdata, filename)
sectindex += 1
offset = nextoffset
return sectindex
### main code
if __name__ == '__main__':
if len(sys.argv) > 1:
filename = sys.argv[1]
if len(sys.argv) > 2:
offset = int(sys.argv[2], 16)
else:
offset = 0
analyze_diskfile(filename, offset)
else:
print "Usage: xfv.py bios.rom [start offset]"