mirror of
https://github.com/86Box/bios-tools.git
synced 2026-02-21 09:05:33 -07:00
Import bios_extract fork source
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Python code
|
||||
__pycache__
|
||||
*.pyc
|
||||
|
||||
# bios_extract
|
||||
bios_extract/src/bios_extract
|
||||
lh5_test
|
||||
ami_slab
|
||||
bcpvpd
|
||||
efidecomp
|
||||
*.o
|
||||
*~
|
||||
@@ -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
8
bios_extract/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
bios_extract
|
||||
lh5_test
|
||||
ami_slab
|
||||
bcpvpd
|
||||
efidecomp
|
||||
*.o
|
||||
*~
|
||||
*.pyc
|
||||
5
bios_extract/.gitreview
Normal file
5
bios_extract/.gitreview
Normal file
@@ -0,0 +1,5 @@
|
||||
[gerrit]
|
||||
host=review.coreboot.org
|
||||
port=29418
|
||||
project=bios_extract
|
||||
defaultbranch=master
|
||||
294
bios_extract/COPYING
Normal file
294
bios_extract/COPYING
Normal 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
55
bios_extract/Makefile
Normal 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
13
bios_extract/README.md
Normal 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
|
||||
44
bios_extract/change-mcp55-mac.pl
Normal file
44
bios_extract/change-mcp55-mac.pl
Normal 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;
|
||||
34
bios_extract/csmcoreparse.py
Normal file
34
bios_extract/csmcoreparse.py
Normal 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
40
bios_extract/decap.sh
Normal 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 $*
|
||||
121
bios_extract/dell_inspiron_1100_unpacker.py
Normal file
121
bios_extract/dell_inspiron_1100_unpacker.py
Normal 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)
|
||||
66
bios_extract/hp_6715b_nc6320_unpacker.py
Normal file
66
bios_extract/hp_6715b_nc6320_unpacker.py
Normal 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)
|
||||
353
bios_extract/insyde-tools/dumpsetup.py
Normal file
353
bios_extract/insyde-tools/dumpsetup.py
Normal 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])
|
||||
177
bios_extract/insyde-tools/fsdump.py
Normal file
177
bios_extract/insyde-tools/fsdump.py
Normal 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()
|
||||
230
bios_extract/insyde-tools/lzma.py
Normal file
230
bios_extract/insyde-tools/lzma.py
Normal 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()
|
||||
473
bios_extract/insyde-tools/main.py
Normal file
473
bios_extract/insyde-tools/main.py
Normal 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()
|
||||
@@ -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
|
||||
|
||||
168
bios_extract/insyde-tools/util.py
Normal file
168
bios_extract/insyde-tools/util.py
Normal 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
|
||||
126
bios_extract/microcode_extract.py
Normal file
126
bios_extract/microcode_extract.py
Normal 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)
|
||||
857
bios_extract/phoenix_extract.py
Normal file
857
bios_extract/phoenix_extract.py
Normal 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
621
bios_extract/src/ami.c
Normal 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
195
bios_extract/src/ami_slab.c
Normal 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
73
bios_extract/src/award.c
Normal 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
97
bios_extract/src/bcpvpd.c
Normal 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);
|
||||
}
|
||||
226
bios_extract/src/bios_extract.c
Normal file
226
bios_extract/src/bios_extract.c
Normal 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;
|
||||
}
|
||||
60
bios_extract/src/bios_extract.h
Normal file
60
bios_extract/src/bios_extract.h
Normal 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
63
bios_extract/src/compat.c
Normal 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
48
bios_extract/src/compat.h
Normal 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
|
||||
553
bios_extract/src/lh5_extract.c
Normal file
553
bios_extract/src/lh5_extract.c
Normal 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;
|
||||
}
|
||||
36
bios_extract/src/lh5_extract.h
Normal file
36
bios_extract/src/lh5_extract.h
Normal 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
137
bios_extract/src/lh5_test.c
Normal 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;
|
||||
}
|
||||
263
bios_extract/src/lzari_extract.c
Normal file
263
bios_extract/src/lzari_extract.c
Normal 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);
|
||||
}
|
||||
394
bios_extract/src/lzhuf_extract.c
Normal file
394
bios_extract/src/lzhuf_extract.c
Normal 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);
|
||||
}
|
||||
92
bios_extract/src/lzss_extract.c
Normal file
92
bios_extract/src/lzss_extract.c
Normal 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;
|
||||
}
|
||||
24
bios_extract/src/lzss_extract.h
Normal file
24
bios_extract/src/lzss_extract.h
Normal 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
1244
bios_extract/src/phoenix.c
Normal file
File diff suppressed because it is too large
Load Diff
232
bios_extract/src/systemsoft.c
Normal file
232
bios_extract/src/systemsoft.c
Normal 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;
|
||||
}
|
||||
173
bios_extract/util/gitconfig/commit-msg
Normal file
173
bios_extract/util/gitconfig/commit-msg
Normal 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
|
||||
1041
bios_extract/xfv/Decompress.c
Normal file
1041
bios_extract/xfv/Decompress.c
Normal file
File diff suppressed because it is too large
Load Diff
33
bios_extract/xfv/README.txt
Normal file
33
bios_extract/xfv/README.txt
Normal 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
|
||||
107
bios_extract/xfv/efidecomp.c
Normal file
107
bios_extract/xfv/efidecomp.c
Normal 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;
|
||||
}
|
||||
24
bios_extract/xfv/efihack.h
Normal file
24
bios_extract/xfv/efihack.h
Normal 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
362
bios_extract/xfv/xfv.py
Normal 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]"
|
||||
Reference in New Issue
Block a user