├── .gitignore ├── .gitreview ├── COPYING ├── Makefile ├── README ├── change-mcp55-mac.pl ├── csmcoreparse.py ├── decap.sh ├── dell_inspiron_1100_unpacker.py ├── hp_6715b_nc6320_unpacker.py ├── insyde-tools ├── dumpsetup.py ├── fsdump.py ├── lzma.py ├── main.py ├── specs │ └── insyde-module-header-format.txt └── util.py ├── microcode_extract.py ├── phoenix_extract.py ├── src ├── ami.c ├── ami_slab.c ├── award.c ├── bcpvpd.c ├── bios_extract.c ├── bios_extract.h ├── compat.c ├── compat.h ├── lh5_extract.c ├── lh5_extract.h ├── lh5_test.c ├── lzss_extract.c ├── lzss_extract.h └── phoenix.c ├── util └── gitconfig │ └── commit-msg └── xfv ├── Decompress.c ├── README.txt ├── efidecomp.c ├── efihack.h └── xfv.py /.gitignore: -------------------------------------------------------------------------------- 1 | bios_extract 2 | lh5_test 3 | ami_slab 4 | bcpvpd 5 | efidecomp 6 | *.o 7 | *~ 8 | *.pyc 9 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=review.coreboot.org 3 | port=29418 4 | project=bios_extract 5 | defaultbranch=master 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Unless a COPYING file in a subdirectory or file-specific license headers 2 | specify a different license, the following applies to all files in this 3 | directory and all subdirectories. 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License below for more details. 14 | 15 | 16 | 17 | GNU GENERAL PUBLIC LICENSE 18 | Version 2, June 1991 19 | 20 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | Everyone is permitted to copy and distribute verbatim copies 23 | of this license document, but changing it is not allowed. 24 | 25 | Preamble 26 | 27 | The licenses for most software are designed to take away your 28 | freedom to share and change it. By contrast, the GNU General Public 29 | License is intended to guarantee your freedom to share and change free 30 | software--to make sure the software is free for all its users. This 31 | General Public License applies to most of the Free Software 32 | Foundation's software and to any other program whose authors commit to 33 | using it. (Some other Free Software Foundation software is covered by 34 | the GNU Lesser General Public License instead.) You can apply it to 35 | your programs, too. 36 | 37 | When we speak of free software, we are referring to freedom, not 38 | price. Our General Public Licenses are designed to make sure that you 39 | have the freedom to distribute copies of free software (and charge for 40 | this service if you wish), that you receive source code or can get it 41 | if you want it, that you can change the software or use pieces of it 42 | in new free programs; and that you know you can do these things. 43 | 44 | To protect your rights, we need to make restrictions that forbid 45 | anyone to deny you these rights or to ask you to surrender the rights. 46 | These restrictions translate to certain responsibilities for you if you 47 | distribute copies of the software, or if you modify it. 48 | 49 | For example, if you distribute copies of such a program, whether 50 | gratis or for a fee, you must give the recipients all the rights that 51 | you have. You must make sure that they, too, receive or can get the 52 | source code. And you must show them these terms so they know their 53 | rights. 54 | 55 | We protect your rights with two steps: (1) copyright the software, and 56 | (2) offer you this license which gives you legal permission to copy, 57 | distribute and/or modify the software. 58 | 59 | Also, for each author's protection and ours, we want to make certain 60 | that everyone understands that there is no warranty for this free 61 | software. If the software is modified by someone else and passed on, we 62 | want its recipients to know that what they have is not the original, so 63 | that any problems introduced by others will not reflect on the original 64 | authors' reputations. 65 | 66 | Finally, any free program is threatened constantly by software 67 | patents. We wish to avoid the danger that redistributors of a free 68 | program will individually obtain patent licenses, in effect making the 69 | program proprietary. To prevent this, we have made it clear that any 70 | patent must be licensed for everyone's free use or not licensed at all. 71 | 72 | The precise terms and conditions for copying, distribution and 73 | modification follow. 74 | 75 | GNU GENERAL PUBLIC LICENSE 76 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 77 | 78 | 0. This License applies to any program or other work which contains 79 | a notice placed by the copyright holder saying it may be distributed 80 | under the terms of this General Public License. The "Program", below, 81 | refers to any such program or work, and a "work based on the Program" 82 | means either the Program or any derivative work under copyright law: 83 | that is to say, a work containing the Program or a portion of it, 84 | either verbatim or with modifications and/or translated into another 85 | language. (Hereinafter, translation is included without limitation in 86 | the term "modification".) Each licensee is addressed as "you". 87 | 88 | Activities other than copying, distribution and modification are not 89 | covered by this License; they are outside its scope. The act of 90 | running the Program is not restricted, and the output from the Program 91 | is covered only if its contents constitute a work based on the 92 | Program (independent of having been made by running the Program). 93 | Whether that is true depends on what the Program does. 94 | 95 | 1. You may copy and distribute verbatim copies of the Program's 96 | source code as you receive it, in any medium, provided that you 97 | conspicuously and appropriately publish on each copy an appropriate 98 | copyright notice and disclaimer of warranty; keep intact all the 99 | notices that refer to this License and to the absence of any warranty; 100 | and give any other recipients of the Program a copy of this License 101 | along with the Program. 102 | 103 | You may charge a fee for the physical act of transferring a copy, and 104 | you may at your option offer warranty protection in exchange for a fee. 105 | 106 | 2. You may modify your copy or copies of the Program or any portion 107 | of it, thus forming a work based on the Program, and copy and 108 | distribute such modifications or work under the terms of Section 1 109 | above, provided that you also meet all of these conditions: 110 | 111 | a) You must cause the modified files to carry prominent notices 112 | stating that you changed the files and the date of any change. 113 | 114 | b) You must cause any work that you distribute or publish, that in 115 | whole or in part contains or is derived from the Program or any 116 | part thereof, to be licensed as a whole at no charge to all third 117 | parties under the terms of this License. 118 | 119 | c) If the modified program normally reads commands interactively 120 | when run, you must cause it, when started running for such 121 | interactive use in the most ordinary way, to print or display an 122 | announcement including an appropriate copyright notice and a 123 | notice that there is no warranty (or else, saying that you provide 124 | a warranty) and that users may redistribute the program under 125 | these conditions, and telling the user how to view a copy of this 126 | License. (Exception: if the Program itself is interactive but 127 | does not normally print such an announcement, your work based on 128 | the Program is not required to print an announcement.) 129 | 130 | These requirements apply to the modified work as a whole. If 131 | identifiable sections of that work are not derived from the Program, 132 | and can be reasonably considered independent and separate works in 133 | themselves, then this License, and its terms, do not apply to those 134 | sections when you distribute them as separate works. But when you 135 | distribute the same sections as part of a whole which is a work based 136 | on the Program, the distribution of the whole must be on the terms of 137 | this License, whose permissions for other licensees extend to the 138 | entire whole, and thus to each and every part regardless of who wrote it. 139 | 140 | Thus, it is not the intent of this section to claim rights or contest 141 | your rights to work written entirely by you; rather, the intent is to 142 | exercise the right to control the distribution of derivative or 143 | collective works based on the Program. 144 | 145 | In addition, mere aggregation of another work not based on the Program 146 | with the Program (or with a work based on the Program) on a volume of 147 | a storage or distribution medium does not bring the other work under 148 | the scope of this License. 149 | 150 | 3. You may copy and distribute the Program (or a work based on it, 151 | under Section 2) in object code or executable form under the terms of 152 | Sections 1 and 2 above provided that you also do one of the following: 153 | 154 | a) Accompany it with the complete corresponding machine-readable 155 | source code, which must be distributed under the terms of Sections 156 | 1 and 2 above on a medium customarily used for software interchange; or, 157 | 158 | b) Accompany it with a written offer, valid for at least three 159 | years, to give any third party, for a charge no more than your 160 | cost of physically performing source distribution, a complete 161 | machine-readable copy of the corresponding source code, to be 162 | distributed under the terms of Sections 1 and 2 above on a medium 163 | customarily used for software interchange; or, 164 | 165 | c) Accompany it with the information you received as to the offer 166 | to distribute corresponding source code. (This alternative is 167 | allowed only for noncommercial distribution and only if you 168 | received the program in object code or executable form with such 169 | an offer, in accord with Subsection b above.) 170 | 171 | The source code for a work means the preferred form of the work for 172 | making modifications to it. For an executable work, complete source 173 | code means all the source code for all modules it contains, plus any 174 | associated interface definition files, plus the scripts used to 175 | control compilation and installation of the executable. However, as a 176 | special exception, the source code distributed need not include 177 | anything that is normally distributed (in either source or binary 178 | form) with the major components (compiler, kernel, and so on) of the 179 | operating system on which the executable runs, unless that component 180 | itself accompanies the executable. 181 | 182 | If distribution of executable or object code is made by offering 183 | access to copy from a designated place, then offering equivalent 184 | access to copy the source code from the same place counts as 185 | distribution of the source code, even though third parties are not 186 | compelled to copy the source along with the object code. 187 | 188 | 4. You may not copy, modify, sublicense, or distribute the Program 189 | except as expressly provided under this License. Any attempt 190 | otherwise to copy, modify, sublicense or distribute the Program is 191 | void, and will automatically terminate your rights under this License. 192 | However, parties who have received copies, or rights, from you under 193 | this License will not have their licenses terminated so long as such 194 | parties remain in full compliance. 195 | 196 | 5. You are not required to accept this License, since you have not 197 | signed it. However, nothing else grants you permission to modify or 198 | distribute the Program or its derivative works. These actions are 199 | prohibited by law if you do not accept this License. Therefore, by 200 | modifying or distributing the Program (or any work based on the 201 | Program), you indicate your acceptance of this License to do so, and 202 | all its terms and conditions for copying, distributing or modifying 203 | the Program or works based on it. 204 | 205 | 6. Each time you redistribute the Program (or any work based on the 206 | Program), the recipient automatically receives a license from the 207 | original licensor to copy, distribute or modify the Program subject to 208 | these terms and conditions. You may not impose any further 209 | restrictions on the recipients' exercise of the rights granted herein. 210 | You are not responsible for enforcing compliance by third parties to 211 | this License. 212 | 213 | 7. If, as a consequence of a court judgment or allegation of patent 214 | infringement or for any other reason (not limited to patent issues), 215 | conditions are imposed on you (whether by court order, agreement or 216 | otherwise) that contradict the conditions of this License, they do not 217 | excuse you from the conditions of this License. If you cannot 218 | distribute so as to satisfy simultaneously your obligations under this 219 | License and any other pertinent obligations, then as a consequence you 220 | may not distribute the Program at all. For example, if a patent 221 | license would not permit royalty-free redistribution of the Program by 222 | all those who receive copies directly or indirectly through you, then 223 | the only way you could satisfy both it and this License would be to 224 | refrain entirely from distribution of the Program. 225 | 226 | If any portion of this section is held invalid or unenforceable under 227 | any particular circumstance, the balance of the section is intended to 228 | apply and the section as a whole is intended to apply in other 229 | circumstances. 230 | 231 | It is not the purpose of this section to induce you to infringe any 232 | patents or other property right claims or to contest validity of any 233 | such claims; this section has the sole purpose of protecting the 234 | integrity of the free software distribution system, which is 235 | implemented by public license practices. Many people have made 236 | generous contributions to the wide range of software distributed 237 | through that system in reliance on consistent application of that 238 | system; it is up to the author/donor to decide if he or she is willing 239 | to distribute software through any other system and a licensee cannot 240 | impose that choice. 241 | 242 | This section is intended to make thoroughly clear what is believed to 243 | be a consequence of the rest of this License. 244 | 245 | 8. If the distribution and/or use of the Program is restricted in 246 | certain countries either by patents or by copyrighted interfaces, the 247 | original copyright holder who places the Program under this License 248 | may add an explicit geographical distribution limitation excluding 249 | those countries, so that distribution is permitted only in or among 250 | countries not thus excluded. In such case, this License incorporates 251 | the limitation as if written in the body of this License. 252 | 253 | 9. The Free Software Foundation may publish revised and/or new versions 254 | of the General Public License from time to time. Such new versions will 255 | be similar in spirit to the present version, but may differ in detail to 256 | address new problems or concerns. 257 | 258 | Each version is given a distinguishing version number. If the Program 259 | specifies a version number of this License which applies to it and "any 260 | later version", you have the option of following the terms and conditions 261 | either of that version or of any later version published by the Free 262 | Software Foundation. If the Program does not specify a version number of 263 | this License, you may choose any version ever published by the Free Software 264 | Foundation. 265 | 266 | 10. If you wish to incorporate parts of the Program into other free 267 | programs whose distribution conditions are different, write to the author 268 | to ask for permission. For software which is copyrighted by the Free 269 | Software Foundation, write to the Free Software Foundation; we sometimes 270 | make exceptions for this. Our decision will be guided by the two goals 271 | of preserving the free status of all derivatives of our free software and 272 | of promoting the sharing and reuse of software generally. 273 | 274 | NO WARRANTY 275 | 276 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 277 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 278 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 279 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 280 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 281 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 282 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 283 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 284 | REPAIR OR CORRECTION. 285 | 286 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 287 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 288 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 289 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 290 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 291 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 292 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 293 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 294 | POSSIBILITY OF SUCH DAMAGES. 295 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MAKE = make 2 | CFLAGS ?= -g -fpack-struct -Wall -O0 3 | CC ?= gcc 4 | 5 | all: bios_extract bcpvpd ami_slab xfv 6 | 7 | SRCDIR = src 8 | 9 | BIOS_EXTRACT_OBJS = $(SRCDIR)/lh5_extract.o $(SRCDIR)/ami.o $(SRCDIR)/award.o \ 10 | $(SRCDIR)/phoenix.o $(SRCDIR)/bios_extract.o $(SRCDIR)/compat.o 11 | bios_extract: $(BIOS_EXTRACT_OBJS) 12 | $(CC) $(CFLAGS) $(BIOS_EXTRACT_OBJS) -o bios_extract 13 | 14 | BCPVPD_OBJS = $(SRCDIR)/lzss_extract.o $(SRCDIR)/bcpvpd.o 15 | bcpvpd: $(BCPVPD_OBJS) 16 | $(CC) $(CFLAGS) $(BCPVPD_OBJS) -o bcpvpd 17 | 18 | AMISLAB_OBJS = $(SRCDIR)/ami_slab.o 19 | ami_slab: $(AMISLAB_OBJS) 20 | $(CC) $(CFLAGS) $(AMISLAB_OBJS) -o ami_slab 21 | 22 | XFV_OBJS = xfv/Decompress.o xfv/efidecomp.o 23 | xfv: $(XFV_OBJS) 24 | $(CC) -I xfv/ $(CFLAGS) -o xfv/efidecomp $(XFV_OBJS) 25 | 26 | # just here to easily verify the functionality of the lh5 routine 27 | LH5_TEST_OBJS = $(SRCDIR)/lh5_extract.o $(SRCDIR)/lh5_test.o 28 | lh5_test: $(LH5_TEST_OBJS) 29 | $(CC) $(CFLAGS) $(LH5_TEST_OBJS) -o lh5_test 30 | 31 | gitconfig: 32 | [ -d .git ] 33 | mkdir -p .git/hooks 34 | for hook in commit-msg pre-commit ; do \ 35 | if [ util/gitconfig/$$hook -nt .git/hooks/$$hook -o \ 36 | ! -x .git/hooks/$$hook ]; then \ 37 | sed -e "s,%MAKE%,$(MAKE),g" util/gitconfig/$$hook > .git/hooks/$$hook; \ 38 | chmod +x .git/hooks/$$hook; \ 39 | fi; \ 40 | done 41 | git config remote.origin.push HEAD:refs/for/master 42 | (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) 43 | 44 | clean: 45 | rm -f $(SRCDIR)/*.o 46 | rm -f bios_extract 47 | rm -f bcpvpd 48 | rm -f lh5_test 49 | rm -f ami_slab 50 | rm -f xfv/efidecomp xfv/*.o 51 | 52 | .PHONY: all bios_extract bcpvpd ami_slab efidecomp lh5_test clean gitconfig 53 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | bios_extract: 2 | ------------- 3 | Tool to extract the different submodules of common legacy bioses. Currently 4 | only supports AMI95 bioses. 5 | 6 | ami_slab: 7 | --------- 8 | Tool to extract the different submodules of an AMI SLAB (Single Link Arch BIOS) 9 | module from an AMI BIOS. 10 | 11 | bcpvpd: 12 | ------- 13 | Extracts IBM compressed BIOS images (BCPVPD and $IBMCOMP) so that bios_extract 14 | can handle it. 15 | 16 | decap.sh: 17 | ------ 18 | A simple shell script to remove headers of UEFI Capsule files. 19 | 20 | lh5_test: 21 | --------- 22 | Sample program left over from development, but kept to be able to easily 23 | verify lh5 extraction functionality. Will not be built per default. 24 | 25 | xfv: 26 | ---- 27 | Tool to dissect EFI capsules. 28 | 29 | phoenix_extract.py: 30 | ------------------- 31 | Simple python script to extract Phoenix FFV from ROM image 32 | 33 | microcode_extract.py: 34 | --------------------- 35 | Simple python script to extract microcode blobs from binary BIOS image 36 | 37 | -------------------------------------------------------------------------------- /change-mcp55-mac.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # Update the onboard NIC mac address in a coreboot rom image for mcp55-based boards 4 | # 5 | # This program is free software (GPLv2 or higher). 6 | # 7 | # 2008-01-30 Ward Vandewege (ward@gnu.org) 8 | 9 | my $mac = $ARGV[0]; 10 | my $file = $ARGV[1]; 11 | 12 | if (($mac eq '') or ($file eq '')) { 13 | print "\nSyntax: $0 \n"; 14 | exit 1; 15 | } 16 | 17 | if (! -f $file) { 18 | print "\nSyntax: $0 \n"; 19 | print "\nERROR: Could not find file '$file'.\n\n"; 20 | exit 1; 21 | } 22 | 23 | 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}$/)) { 24 | print "\nSyntax: $0 \n"; 25 | print "\nERROR: The mac address you specified ($mac) is not a valid mac address.\n\n"; 26 | exit 1; 27 | } 28 | 29 | my @mac = split(/:/,$mac); 30 | 31 | my $newmac = ''; 32 | 33 | for (my $c = 5; $c >= 0; $c--) { 34 | $newmac .= chr(hex($mac[$c])); 35 | } 36 | 37 | open(ROMIMAGE,"+<",$file) or die "Can't open file $file for writing\n"; 38 | seek(ROMIMAGE,-48,2); 39 | 40 | print ROMIMAGE $newmac; 41 | close(ROMIMAGE); 42 | 43 | print "Mac address succesfully updated to $mac in $file\n"; 44 | exit 0; 45 | -------------------------------------------------------------------------------- /csmcoreparse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # parse CSMCORE.raw from AMI UEFI 4 | # 3-clause BSD license 5 | # roxfan@skynet.be 6 | 7 | import struct, sys 8 | if len(sys.argv) < 2: 9 | fn = "CSMCORE.raw" 10 | else: 11 | fn = sys.argv[1] 12 | f = open(fn, "rb") 13 | while True: 14 | print "%08X"%f.tell(), 15 | hdr = f.read(10) 16 | if len(hdr) == 0: 17 | break 18 | typ, vid, did, size = struct.unpack(" %s" % fname 30 | if size == 0xFFFFFFFF: 31 | d = f.read() 32 | else: 33 | d = f.read(size) 34 | open(fname, "wb").write(d) 35 | -------------------------------------------------------------------------------- /decap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This program is free software; you can redistribute it and/or modify 3 | # it under the terms of the GNU General Public License as published by 4 | # the Free Software Foundation; either version 2 of the License, or 5 | # (at your option) any later version. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 15 | # MA 02110-1301, USA. 16 | # 17 | # Takes a path to a file as first and only argument, removes the first 2048 B 18 | # from that file and stores the result with the same name plus a '.bin' suffix. 19 | # Useable to remove the header from UEFI Capsule files to use the resulting 20 | # binary with flashrom. 21 | 22 | main () { 23 | if [ "$#" -lt 1 -o ! -r "$1" ]; then 24 | echo "Removes the 2048 B header of UEFI Capsule files.\n"\ 25 | "Usage: $0 " 26 | return 1 27 | fi 28 | 29 | capsize=$(wc -c "$1" | cut -f 1 -d ' ') 30 | binsize=$(($capsize-2048)) 31 | ispowoftwo=$(($binsize & ($binsize-1))) 32 | if [ $ispowoftwo -ne 0 -o $binsize -eq 0 ]; then 33 | echo "The size of the resulting file would not be a power of 2 (but $binsize B)." 34 | return 1 35 | fi 36 | 37 | dd bs=2048 skip=1 if="$1" of="$1.bin" 38 | } 39 | 40 | main $* 41 | -------------------------------------------------------------------------------- /dell_inspiron_1100_unpacker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Dell/Phoenix ROM BIOS PLUS unpacker 3 | # 2012-09-12 version 0.1 4 | # 2012-10-10 version 0.2 added support for older BIOSes with 16-bit length (Dell Inspiron 1100) 5 | # 3-clause BSD license 6 | # roxfan@skynet.be 7 | 8 | import array 9 | import struct 10 | import sys 11 | 12 | def memcpy(arr1, off1, arr2, off2, count): 13 | while count: 14 | if off1 < len(arr1): 15 | arr1[off1] = arr2[off2] 16 | elif off1 == len(arr1): 17 | arr1.append(arr2[off2]) 18 | else: 19 | raise Exception("Trying to write out of bounds") 20 | off1 += 1 21 | off2 += 1 22 | count -= 1 23 | 24 | # looks like some lzss variation 25 | def dell_unpack(indata): 26 | srcoff = 0 27 | dstoff = 0 28 | src = array.array('B', indata) 29 | dst = array.array('B') 30 | inlen = len(indata) 31 | while srcoff < inlen: 32 | b = src[srcoff] 33 | nibl, nibh = b & 0x0F, (b >> 4) & 0x0F 34 | srcoff += 1 35 | if nibl: 36 | if nibl == 0xF: 37 | al = src[srcoff] 38 | ah = src[srcoff+1] 39 | srcoff += 2 40 | cx = nibh | (ah << 4) 41 | count = (cx & 0x3F) + 2 42 | delta = ((ah >> 2) << 8) | al 43 | else: 44 | count = nibl + 1 45 | delta = (nibh << 8) | src[srcoff] 46 | srcoff += 1 47 | memcpy(dst, dstoff, dst, dstoff - delta - 1, count) 48 | dstoff += count 49 | elif nibh == 0x0E: 50 | count = src[srcoff] + 1 51 | srcoff += 1 52 | memcpy(dst, dstoff, dst, dstoff - 1, count) 53 | dstoff += count 54 | else: 55 | if nibh == 0x0F: 56 | count = src[srcoff] + 15 57 | srcoff += 1 58 | else: 59 | count = nibh + 1 60 | memcpy(dst, dstoff, src, srcoff, count) 61 | dstoff += count 62 | srcoff += count 63 | 64 | return dst 65 | 66 | mod_types = { 67 | 0x01: "Main ROM", 68 | 0x0C: "Microcode update", 69 | } 70 | 71 | print("Dell/Phoenix ROM BIOS PLUS unpacker") 72 | if len(sys.argv) < 2: 73 | print("Usage: dell_unpack.py bios.bin [offset]") 74 | sys.exit(1) 75 | fname = sys.argv[1] 76 | offs = 0 77 | f = open(fname, "rb").read() 78 | if len(sys.argv) > 2: 79 | offs = int(sys.argv[2], 16) 80 | else: 81 | offs = f.find(b"\xF0\x00Copyright 1985-\x02\x04\xF0\x0F8 Phoenix Technologies Ltd.") 82 | if offs == -1: 83 | print("Does not look like a Dell/Phoenix ROM BIOS PLUS") 84 | sys.exit(2) 85 | if f[offs-5] == 0x01: 86 | hlen = 5 # 32-bit length 87 | offs -= 5 88 | fmt = " 0: 98 | fn = "EC.bin" 99 | print("%08X EC code, %08X %s" % (0, offs, fn)) 100 | open(fn, "wb").write(f[:offs]) 101 | while True: 102 | type_id, leng = struct.unpack(fmt, f[offs:offs+hlen]) 103 | print("%08X type %02X" % (offs, type_id), end=" ") 104 | offs += hlen 105 | if type_id == 0xFF: 106 | print("") 107 | break 108 | data = f[offs:offs+leng] 109 | offs += leng 110 | if type_id != 0xC: 111 | odata = dell_unpack(data) 112 | else: 113 | odata = data 114 | print(" %08X -> %08X" % (leng, len(odata)), end=" ") 115 | fn = "mod_%02X.bin" % type_id 116 | print(" %s" % fn, end=" ") 117 | if type_id in mod_types: 118 | print("(%s)" % mod_types[type_id]) 119 | else: 120 | print("") 121 | open(fn, "wb").write(odata) 122 | -------------------------------------------------------------------------------- /hp_6715b_nc6320_unpacker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # HP Compaq 6715b ROM unpacker by roxfan 3 | # compressed data begins like this: 4 | # 0000010000: 01 00 14 01 70 00 00 00 | 60 00 00 00 00 00 02 00 O .Op . O 5 | # 0000010010: 50 4F 53 54 FF B8 00 20 | 8E D8 66 B8 10 FF 20 00 POST.. ..f... 6 | 7 | import struct, array, sys 8 | 9 | def unpack1(cdata, ulen): 10 | pos = 0 11 | odata = "" 12 | while ulen: 13 | a = ord(cdata[pos]) 14 | # print "%x: %x" % (pos, a) 15 | pos += 1 16 | if a == 0xFF: 17 | odata += cdata[pos:pos+8] 18 | ulen -= 8 19 | pos += 8 20 | else: 21 | mask = a | 0x100 22 | while mask and ulen: 23 | # print hex(mask), hex(pos) 24 | b = mask & 1 25 | mask >>= 1 26 | if mask == 0: 27 | break 28 | if b: 29 | odata += cdata[pos] 30 | pos += 1 31 | ulen -= 1 32 | else: 33 | delta = ord(cdata[pos]) 34 | pos += 1 35 | delta |= ord(cdata[pos])<<8 36 | pos += 1 37 | count = (delta & 0xF) + 3 38 | delta >>= 4 39 | # print "d: %d, c: %d" % (delta, count) 40 | opos = len(odata)-delta 41 | while count: 42 | odata += odata[opos] 43 | opos += 1 44 | count -= 1 45 | ulen -= 1 46 | return odata 47 | 48 | f = open(sys.argv[1], "rb") 49 | f.seek(0x10000) 50 | 51 | while True: 52 | flags, ulen, clen, dest = struct.unpack(" 1: 55 | break 56 | hdrlen = (flags>>16) & 0xFF 57 | unk = (flags>>24) & 0xFF 58 | print "comp: %d, hdr len: 0x%X, unk: %d, ulen: 0x%X, clen: 0x%X, dest: 0x%X" % (comp, hdrlen, unk, ulen, clen, 59 | dest) 60 | extra = f.read(hdrlen-0x10).rstrip('\0') 61 | print " %s" % extra 62 | cdata = f.read(clen) 63 | fname = "%04X_%s.bin" % (dest>>4, extra) 64 | if comp == 1: 65 | cdata = unpack1(cdata, ulen) 66 | open(fname, "wb").write(cdata) 67 | -------------------------------------------------------------------------------- /insyde-tools/dumpsetup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import struct 5 | import codecs 6 | 7 | sys.stdout = codecs.getwriter('utf-8')(sys.stdout) 8 | 9 | STRING_TABLE = 0x6F80 # FaithX 10 | STRING_TABLE = 0x10b60 # Original 11 | #STRING_TABLE = 0x108e0 + 12 # No idea 12 | STRING_TABLE = 0x10b30 # Mine? 13 | 14 | storage_map = {} 15 | 16 | FORMS = [ 17 | ("Exit", 0xC600), 18 | #('Exit', 0xc640), 19 | #('Boot', 0xc6f0), 20 | #('Power', 0xc810), 21 | #('Security',0xd140), 22 | #('Advanced',0xd390), 23 | #('Main', 0x106b0), 24 | #('OEM', 0x10a20) 25 | ] 26 | 27 | 28 | def fguid(s): 29 | a, b, c, d = struct.unpack("] == 0x%x" % (qid, width, val) 222 | elif self.opcode == self.EFI_IFR_EQ_ID_ID_OP: 223 | qid, width, qid2, width2, val = struct.unpack( 224 | "] == [0x%x.%d]" % ( 226 | qid, width, qid2, width2, val) 227 | elif self.opcode == self.EFI_IFR_EQ_ID_LIST_OP: 228 | qid, width, length = struct.unpack("] in (%s)" % ( 231 | qid, width, ','.join(["0x%x" % i for i in l])) 232 | elif self.opcode == self.EFI_IFR_AND_OP: 233 | print ts + "AND" 234 | elif self.opcode == self.EFI_IFR_OR_OP: 235 | print ts + "OR" 236 | elif self.opcode == self.EFI_IFR_NOT_OP: 237 | print ts + "NOT" 238 | elif self.opcode == self.EFI_IFR_ONE_OF_OP: 239 | qid, width, pid, hid = struct.unpack("] '%s'" % (qid, width, s[pid]) 242 | if s[hid] and s[hid] != ' ': 243 | print ts + "\Help text: '%s'" % s[hid] 244 | elif self.opcode == self.EFI_IFR_ONE_OF_OPTION_OP: 245 | oid, value, flags, key = struct.unpack("] %d-%d Step %d Default %d Flags 0x%x" % (t, s[pid], qid, width, min, max, step, default, flags) 264 | if s[hid] and s[hid] != ' ': 265 | print ts + "\Help text: '%s'" % s[hid] 266 | elif self.opcode == self.EFI_IFR_PASSWORD_OP: 267 | qid, width, pid, hid, flags, key, mins, maxs, encoding = struct.unpack("] Flags 0x%x Key 0x%x Size %d-%d Encoding %d" % (s[pid], qid, width, flags, key, mins, maxs, encoding) 270 | if s[hid] and s[hid] != ' ': 271 | print ts + "\Help text: '%s'" % s[hid] 272 | else: 273 | print ts + "Opcode 0x%x (%d)" % ( 274 | self.opcode, self.length), hexdump(self.payload) 275 | 276 | 277 | class Form(HiiPack): 278 | def __init__(self, data, offset, stable=None): 279 | #print "Constructing form.." 280 | HiiPack.__init__(self, data, offset) 281 | data = self.data 282 | self.opcodes = [] 283 | while len(data): 284 | op = FormOp(data, stable) 285 | #print "Created ", len(self.opcodes), op.length 286 | assert op.length 287 | data = data[op.length:] 288 | self.opcodes.append(op) 289 | 290 | def fetch_opcodes(self, opcode_wanted): 291 | return filter(lambda x: x.opcode == opcode_wanted, self.opcodes) 292 | 293 | def __repr__(self): 294 | formset = self.fetch_opcodes(FormOp.EFI_IFR_FORM_SET_OP) 295 | assert len(formset) == 1 296 | return "" % (formset[0].get_info(), self.offset) 297 | return "%s" % formset 298 | 299 | def locate_formset(self): 300 | pass 301 | 302 | def showinfo(self, stringtable, ts=''): 303 | ind = 0 304 | in_if = False 305 | fstk = [] 306 | for op in self.opcodes: 307 | if op.opcode == op.EFI_IFR_FORM_OP: 308 | fstk.append(ind) 309 | if op.indent < 0: 310 | ind += op.indent 311 | ots = ts + ' ' * ind 312 | if in_if and op.opcode in (op.EFI_IFR_SUPPRESS_IF_OP, op.EFI_IFR_GRAYOUT_IF_OP): 313 | ots = ts + ' ' * (ind - 1) + '+' 314 | try: 315 | op.showinfo(stringtable, ots) 316 | #except: 317 | # print ts+"ERROR DECODING OPCODE 0x%x LEN 0x%x"%(op.opcode, op.length) 318 | finally: 319 | pass 320 | 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: 321 | ind += op.indent 322 | if op.opcode in (op.EFI_IFR_SUPPRESS_IF_OP, op.EFI_IFR_GRAYOUT_IF_OP): 323 | in_if = True 324 | elif op.opcode == op.EFI_IFR_END_IF_OP: 325 | in_if = False 326 | if op.opcode == op.EFI_IFR_END_FORM_OP: 327 | xind = fstk.pop() 328 | if xind != ind: 329 | print "WARNING: Indentation mismatch" 330 | ind = xind 331 | 332 | #filename = "vt_bios.fd" 333 | #filename = sys.argv[1] 334 | #filename = "../test1/fv-00000010.bin" 335 | 336 | #filename = "../test1/fe3542fe-c1d3-4ef8-7c65-8048606ff670-SetupUtility.sec0.sub2.pe" 337 | 338 | #pe = open(filename, "rb").read() 339 | 340 | 341 | def dump_setup(pe): 342 | strings = StringTable(pe, STRING_TABLE) 343 | strings.showinfo() 344 | 345 | for fn, off in FORMS[0:]: 346 | print 347 | print "Reading form '%s'" % fn, off 348 | f = Form(pe, off) 349 | #f.showinfo(strings, ' ') 350 | 351 | #print "Storage map:" 352 | #for k in sorted(storage_map.keys()): 353 | #print " 0x%x: %s"%(k,storage_map[k]) 354 | -------------------------------------------------------------------------------- /insyde-tools/fsdump.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | from __future__ import with_statement 4 | 5 | from util import from_b64 6 | import sys 7 | import struct 8 | 9 | 10 | def fguid(s): 11 | a, b, c, d, e = struct.unpack("" % self.type) 60 | 61 | small, large = self.TI[self.type] 62 | if callable(large): 63 | large = large(self) 64 | return small, large 65 | 66 | def showinfo(self, ts=''): 67 | if self.type == 0x02: 68 | print ts + "GUID-defined section" 69 | if self.sections: 70 | print ts + " CRC32 subsection container:" 71 | for i, s in enumerate(self.sections): 72 | print ts + " Subsection %d: type 0x%02x, size 0x%x" % ( 73 | i, s.type, s.size) 74 | s.showinfo(ts + " ") 75 | 76 | else: 77 | print ts + self.get_type_info()[1] 78 | 79 | def dump(self, base): 80 | 81 | if self.sections: 82 | for i, s in enumerate(self.sections): 83 | s.dump("%s.sub%d" % (base, i)) 84 | return 85 | 86 | name = "%s.%s" % (base, self.get_type_info()[0]) 87 | with open(name, "wb") as fd: 88 | fd.write(self.data) 89 | 90 | print name 91 | 92 | def __repr__(self): 93 | return "" % (self.name, self.get_type_info()[0], self.size) 94 | 95 | 96 | class FFSFile(object): 97 | def __repr__(self): 98 | return "" % (self.size - 0x18, len(self.data), self.type, self.state, fguid(self.guid)) 99 | 100 | def __init__(self, data): 101 | hdr = data[:0x18] 102 | self.guid, self.checksum, self.type, self.attributes, self.size, self.state = struct.unpack("<16sHBB3sB", hdr) 103 | self.size = struct.unpack(" 9 | 10 | # MIT License. 11 | 12 | #~ Permission is hereby granted, free of charge, to any person 13 | #~ obtaining a copy of this software and associated documentation 14 | #~ files (the "Software"), to deal in the Software without 15 | #~ restriction, including without limitation the rights to use, 16 | #~ copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | #~ copies of the Software, and to permit persons to whom the 18 | #~ Software is furnished to do so, subject to the following 19 | #~ conditions: 20 | 21 | #~ The above copyright notice and this permission notice shall be 22 | #~ included in all copies or substantial portions of the Software. 23 | 24 | #~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | #~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 26 | #~ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | #~ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 28 | #~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 29 | #~ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | #~ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 31 | #~ OTHER DEALINGS IN THE SOFTWARE. 32 | 33 | from ctypes import (CDLL, c_int8, c_uint32, c_uint64, c_void_p, c_char_p, 34 | c_size_t, cast, pointer, POINTER, Structure, create_string_buffer) 35 | 36 | from ctypes.util import find_library 37 | 38 | from hashlib import md5 39 | 40 | 41 | def md5sum(data): 42 | return md5(data).hexdigest() 43 | 44 | 45 | class lzmadec_info_t(Structure): 46 | _fields_ = [('uncompressed_size', c_uint64), 47 | ('dictionary_size', c_uint32), 48 | ('internal_data_size', c_uint32), 49 | ('is_streamed', c_uint32), 50 | ('pb', c_uint32), 51 | ('lp', c_uint32), 52 | ('lc', c_uint32), ] 53 | 54 | def __repr__(self): 55 | bits = [] 56 | for fieldname, fieldtype in self._fields_: 57 | bits.append("%s=%s" % (fieldname, getattr(self, fieldname))) 58 | return "" % ", ".join(bits) 59 | 60 | lzmadec_info_p = POINTER(lzmadec_info_t) 61 | 62 | 63 | class lzmadec_stream_t(Structure): 64 | _fields_ = [('next_in', c_char_p), 65 | ('avail_in', c_size_t), 66 | ('total_in', c_uint64), 67 | ('next_out', c_char_p), 68 | ('avail_out', c_size_t), 69 | ('total_out', c_uint64), 70 | ('state', c_void_p), 71 | ('lzma_alloc', c_void_p), 72 | ('lzma_free', c_void_p), 73 | ('opaque', c_void_p)] 74 | lzmadec_stream_p = POINTER(lzmadec_stream_t) 75 | 76 | 77 | class ctypes_function(object): 78 | def __init__(self, lib, restype, argtypes): 79 | self.lib, self.restype, self.argtypes = lib, restype, argtypes 80 | 81 | def __call__(self, function): 82 | func_name = function.__name__ 83 | f = getattr(self.lib, func_name) 84 | f.restype, f.argtypes = self.restype, self.argtypes 85 | return f 86 | 87 | library_path = find_library("lzmadec") 88 | assert library_path, ( 89 | "Couldn't find `liblzmadec.so`. Please install lzma_utils.\n" 90 | " it can be found at http://tukaani.org/lzma/download" 91 | ) 92 | lzma = CDLL(library_path) 93 | 94 | # I tried the simpler lzmadec_buffer function but it didn't like that I was 95 | # providing too much data and crashed, so I switched to the stream instead. 96 | 97 | 98 | @ctypes_function(lzma, c_int8, [lzmadec_info_p, c_char_p, c_size_t]) 99 | def lzmadec_buffer_info(): 100 | pass 101 | 102 | 103 | @ctypes_function(lzma, c_int8, [lzmadec_stream_p]) 104 | def lzmadec_init(): 105 | pass 106 | 107 | 108 | @ctypes_function(lzma, c_int8, [lzmadec_stream_p, c_int8]) 109 | def lzmadec_decode(): 110 | pass 111 | 112 | 113 | @ctypes_function(lzma, c_int8, [lzmadec_stream_p]) 114 | def lzmadec_end(): 115 | pass 116 | 117 | # 118 | # USEFUL CODE STARTS HERE 119 | # 120 | 121 | # Based on concepts from scanlzma.c 122 | # scanlzma, scan for lzma compressed data in stdin and echo it to stdout. 123 | # Copyright (C) 2006 Timo Lindfors 124 | 125 | 126 | def find_lzma_headers(buffer): 127 | MAGIC_CHAR = chr(0x5D) 128 | 129 | position = 0 130 | positions = [] 131 | 132 | while position < len(buffer) and MAGIC_CHAR in buffer[position:]: 133 | 134 | position = buffer.index(MAGIC_CHAR, position) + 1 135 | 136 | if (ord(buffer[position + 3]) < 0x20 and 137 | (buffer[position + 9:].startswith("\x00" * 3) or 138 | buffer[position + 4:].startswith("\xFF" * 8))): 139 | positions.append(position - 1) 140 | 141 | return positions 142 | 143 | 144 | def lzma_decompressed_size(buffer): 145 | "Given `buffer`, return the decompressed size" 146 | lzmadec_info = lzmadec_info_t() 147 | result = lzmadec_buffer_info(pointer(lzmadec_info), buffer, len(buffer)) 148 | assert not result, "lzmadec_buffer_info failed" 149 | #print lzmadec_info 150 | assert lzmadec_info.dictionary_size > lzmadec_info.uncompressed_size, ( 151 | "This probably doesn't make sense.." 152 | ) 153 | #print "Here..", lzmadec_info 154 | return lzmadec_info.uncompressed_size 155 | 156 | 157 | def lzma_decode(input_buffer): 158 | """ 159 | `input_buffer`: string. 160 | Return Value: (decompressed string, amount of `input_buffer` used) 161 | """ 162 | 163 | result_size = lzma_decompressed_size(input_buffer) 164 | 165 | assert result_size 166 | 167 | result_data = create_string_buffer(result_size) 168 | 169 | lzmadec_stream = lzmadec_stream_t() 170 | 171 | assert not lzmadec_init(lzmadec_stream) 172 | 173 | lzmadec_stream.next_in = input_buffer 174 | lzmadec_stream.avail_in = len(input_buffer) 175 | 176 | lzmadec_stream.next_out = cast(result_data, c_char_p) 177 | lzmadec_stream.avail_out = result_size 178 | 179 | result = lzmadec_decode(lzmadec_stream, 1) 180 | 181 | #s = lzmadec_stream 182 | #print s.avail_in, s.total_in, s.avail_out, s.total_out 183 | 184 | assert not lzmadec_end(lzmadec_stream) 185 | 186 | result_data = result_data.raw 187 | amount_read = lzmadec_stream.total_in 188 | 189 | assert result == 1 190 | 191 | return result_data, amount_read 192 | 193 | 194 | def get_lzma_chunks(input_buffer): 195 | """ 196 | Scans `input_buffer` for LZMA-like data. 197 | Returns a list of (position, "the data found decompressed"). 198 | """ 199 | 200 | ph = possible_headers = find_lzma_headers(input_buffer) 201 | # Not a real header location, but allows one last iteration to end of file 202 | # in the following loop 203 | ph.append(len(input_buffer) - 1) 204 | 205 | result = [] 206 | 207 | for this_header, next_header in zip(ph, ph[1:]): 208 | try: 209 | #print this_header, next_header 210 | data, length = lzma_decode(input_buffer[this_header:next_header]) 211 | except AssertionError: 212 | continue 213 | 214 | result.append((this_header, data)) 215 | 216 | return result 217 | 218 | 219 | def test(): 220 | bios_data = open("data/original_bios_backup.fd", "rb").read() 221 | 222 | results = get_lzma_chunks(bios_data) 223 | print map(md5sum, zip(*results)[1]) 224 | 225 | #~ headers = find_lzma_headers(bios_data) 226 | #~ decompr_data, amoun_read = lzma_decode(bios_data[headers[0]:]) 227 | #~ print md5sum(decompr_data) 228 | 229 | if __name__ == "__main__": 230 | test() 231 | -------------------------------------------------------------------------------- /insyde-tools/main.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # Copyright (c) 2009 d6z 4 | 5 | # MIT License. Based on code found found at 6 | # http://marcansoft.com/blog/2009/06/enabling-intel-vt-on-the-aspire-8930g/ 7 | 8 | #~ Permission is hereby granted, free of charge, to any person 9 | #~ obtaining a copy of this software and associated documentation 10 | #~ files (the "Software"), to deal in the Software without 11 | #~ restriction, including without limitation the rights to use, 12 | #~ copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | #~ copies of the Software, and to permit persons to whom the 14 | #~ Software is furnished to do so, subject to the following 15 | #~ conditions: 16 | 17 | #~ The above copyright notice and this permission notice shall be 18 | #~ included in all copies or substantial portions of the Software. 19 | 20 | #~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | #~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | #~ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | #~ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | #~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | #~ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | #~ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | #~ OTHER DEALINGS IN THE SOFTWARE. 28 | 29 | from __future__ import with_statement 30 | 31 | import fsdump 32 | 33 | from os import makedirs 34 | from os.path import exists 35 | from lzma import get_lzma_chunks 36 | from struct import unpack_from 37 | from pprint import pprint 38 | from array import array 39 | from dumpsetup import StringTable, Form, FormOp 40 | from util import (md5sum, read_with_progress, find_all, find_all_backwards, 41 | Struct, SI, from_b64, hexbytes, substitute, chexdump, FindBadPosition, 42 | FindStopSearching 43 | ) 44 | 45 | #~ SAVE_PATH = "data/original_bios-zchef.fd"; WHAT = "zchef" 46 | #~ SAVE_PATH = "data/original_bios-dhlacik.fd"; WHAT = "dhlacik" 47 | #~ SAVE_PATH = "data/original_bios-FaithX.fd"; WHAT = "FaithX" 48 | #~ SAVE_PATH = "data/original_bios-mine.fd"; WHAT = "mine" 49 | #~ SAVE_PATH = "data/KM2_110.fd"; WHAT = "v110" 50 | 51 | SAVE_PATH = "data/original_bios-mine.fd" 52 | WHAT = "mine" 53 | 54 | 55 | KB, MB, GB = 2 ** 10, 2 ** 20, 2 ** 30 56 | 57 | SAVE_PATH = "data/original_bios_backup1.fd" 58 | BIOS_START = 4 * GB - 2 * MB 59 | BIOS_SIZE = 2 * MB 60 | 61 | # Only necessary to modify these if you are reading from /dev/mem 62 | # If reading from BIOS dump, they are ignored. 63 | # If someone knows how to detect the bios size automatically, that would 64 | # be very useful 65 | BIOS_SIZE = 2 * MB 66 | BIOS_START = 4 * GB - BIOS_SIZE 67 | 68 | 69 | class FirmwareVolumeHeader(Struct): 70 | rsvd = SI("<16s") 71 | guid = SI("16s") 72 | size = SI("Q") 73 | magic = SI("4s") 74 | attributes = SI("I") 75 | hdrlen = SI("H") 76 | checksum = SI("H") 77 | rsvd2 = SI("3s") 78 | revision = SI("B") 79 | cruft = SI("16s") 80 | 81 | def showinfo(self, depth=0): 82 | print " " * depth, "Reserved boot zone:", hexbytes(self.rsvd) 83 | print " " * depth, "GUID:", hexbytes(self.guid) 84 | print " " * depth, "Size: 0x%x (data 0x%x)" % (self.size, 85 | len(self.data)) 86 | print " " * depth, "Attributes: 0x%08x" % self.attributes 87 | print " " * depth, "Revision: %d" % self.revision 88 | 89 | 90 | class VariableHeader(Struct): 91 | magic = SI("<2s") 92 | status = SI("H") 93 | attributes = SI("I") 94 | nsize = SI("I") 95 | dsize = SI("I") 96 | guid = SI("16s") 97 | # Some bioses do not have a checksum. 98 | # Comment me out if your bios does not work 99 | cs = SI("H") 100 | 101 | 102 | class FirmwareVolume(object): 103 | def __init__(self, buffer, position, where=None): 104 | buffer = buffer[position:] 105 | 106 | try: 107 | fvh = FirmwareVolumeHeader(buffer) 108 | assert fvh.magic == "_FVH", "Invalid FirmwareVolume, wrong magic" 109 | assert fvh.hdrlen == FirmwareVolumeHeader.struct_size, ( 110 | "Invalid FirmwareVolume, wrong header length " 111 | "0x%04x, expected 0x%04x" % 112 | (fvh.hdrlen, FirmwareVolumeHeader.struct_size) 113 | ) 114 | assert fvh.size <= len(buffer), ( 115 | "FirmwareVolume too big? " 116 | "size=0x%08x buflen=0x%08x" % (fvh.size, len(buffer)) 117 | ) 118 | 119 | #blockdata = buffer[fvh.py_struct.size:fvh.hdrlen] 120 | self.data = buffer[fvh.hdrlen:fvh.size] 121 | self.position = position 122 | self.where = where 123 | self.good = True 124 | except AssertionError, e: 125 | #print ">>BAD FV at 0x%08x" % position, e 126 | self.good = False 127 | 128 | def has_VSS(self): 129 | return "$VSS" in self.data 130 | 131 | def __repr__(self): 132 | hasvss = " [VSS]" if self.has_vss() else "" 133 | args = (self.position, len(self.data), self.where, hasvss) 134 | return "" % args 135 | 136 | 137 | class Variable(object): 138 | GLOBAL_VARIABLE = from_b64('Yd/ki8qT0hGqDQDgmAMrjA') 139 | HEADER_MAGIC = "\xAA\x55" 140 | ACTIVE = 0x7F 141 | 142 | def __init__(self, complete_data): 143 | header_size = VariableHeader.struct_size 144 | 145 | header = complete_data[:header_size] 146 | self.vh = vh = VariableHeader(header) 147 | print "Blah:", hexbytes(vh.guid) 148 | 149 | assert vh.magic == self.HEADER_MAGIC, "bad magic 0x%x" % vh.magic 150 | 151 | total_length = vh.dsize + vh.nsize 152 | assert len(complete_data) >= total_length, "input not long enough" 153 | 154 | data = complete_data[header_size:] 155 | data = data[:total_length] 156 | 157 | nullterm = data.index("\x00\x00") + 1 158 | strend = nullterm if nullterm < vh.nsize else vh.nsize 159 | 160 | self.name = data[:strend].decode("utf-16le") 161 | self.value = data[vh.nsize:total_length] 162 | 163 | # Set the checksum to 0, and the status to 0x7F 164 | fdata = substitute(header + data, header_size - 2, "\x00\x00") 165 | fdata = substitute(fdata, 2, "\x7F\x00") 166 | 167 | self.ccsum = self.checksum(fdata) 168 | 169 | #assert self.ccsum == vh.cs, "Checksum Error" 170 | 171 | def __repr__(self): 172 | return "" % (self.vh.status, self.vh.dsize, self.name) 173 | 174 | def __len__(self): 175 | return VariableHeader.struct_size + self.vh.nsize + self.vh.dsize 176 | 177 | def checksum(self, data): 178 | if len(data) % 2: 179 | data += chr(0) 180 | shorts = array("H", []) 181 | shorts.fromstring(data) 182 | return -sum(shorts) & 0xFFFF 183 | 184 | def showinfo(self, ts=''): 185 | print ts + "Variable %s" % repr(self.name) 186 | print ts + " Attributes: 0x%08x" % self.vh.attributes 187 | print ts + " Status: 0x%02x" % self.vh.status 188 | if self.vh.guid == self.GLOBAL_VARIABLE: 189 | print ts + (" VendorGUID: EFI_GLOBAL_VARIABLE (%s)" % 190 | ' '.join('%02x' % ord(c) for c in self.vh.guid)) 191 | else: 192 | print ts + (" VendorGUID: %s" % 193 | ' '.join('%02x' % ord(c) for c in self.vh.guid)) 194 | #print ts+" Checksum: 0x%02x"%self.vh.cs 195 | #print ts+" calc 0x%04x"%self.ccsum 196 | print ts + " Value (0x%x bytes):" % (len(self.value)) 197 | chexdump(self.value, ts + " ") 198 | 199 | 200 | class VSSData(object): 201 | def __init__(self, data): 202 | (size,) = unpack_from("I", data[4:]) 203 | assert size < len(data), ( 204 | "Too big! size = %i len = %i" % (size, len(data)) 205 | ) 206 | 207 | vssdata = data[0x10:size] 208 | 209 | self.vars = [] 210 | self.size = size 211 | 212 | position = 0 213 | while (position < len(data) and 214 | vssdata[position:].startswith(Variable.HEADER_MAGIC)): 215 | print "Creating variable at", position 216 | v = Variable(vssdata[position:]) 217 | position += len(v) 218 | self.vars.append(v) 219 | 220 | def __repr__(self): 221 | return "" % (len(self.vars), self.size) 222 | 223 | def __iter__(self): 224 | return iter(self.vars) 225 | 226 | 227 | class BIOS(object): 228 | def __init__(self, from_where=None): 229 | "Create a BIOS object" 230 | 231 | bios_data = self.load_bios(from_where) 232 | 233 | print "Operating on BIOS %s size = 0x%x" % (SAVE_PATH, len(bios_data)) 234 | 235 | print "Loading compressed sections" 236 | compressed_chunks = get_lzma_chunks(bios_data) 237 | print " .. found %i compressed sections" % len(compressed_chunks) 238 | 239 | print "Locating Firmware Volumes" 240 | volumes = self.locate_firmware_volumes(bios_data) 241 | 242 | for position, data in compressed_chunks: 243 | #if False: 244 | #with open("data/fv-compr-0x%08x" % position, "wb") as f: 245 | # Dump the executable with the PE header in the right place 246 | #f.write(data[data.index("MZ"):]) 247 | 248 | where = "[compr at 0x%x]" % position 249 | volumes.extend(self.locate_firmware_volumes(data, where)) 250 | 251 | # Only good volumes 252 | volumes = filter(lambda fv: fv.good, volumes) 253 | vol_compr = filter( 254 | lambda fv: fv.where and "compr" in fv.where, volumes) 255 | 256 | print (" .. found %i FirmwareVolumes (%i compressed)" % 257 | (len(volumes), len(vol_compr))) 258 | 259 | setup_utility = self.locate_setup_utility(vol_compr) 260 | 261 | TYPE_PE = 0x10 262 | setup_utility_pe = self.get_section_type(setup_utility[1], TYPE_PE) 263 | 264 | dump_filename = "data/SetupUtility-%s.pe" % WHAT 265 | if not exists(dump_filename): 266 | 267 | pe = setup_utility_pe 268 | 269 | with open(dump_filename, "wb") as fd: 270 | fd.write(pe.data) 271 | 272 | print "Wrote SetupUtility to %s" % dump_filename 273 | print " Size = 0x%x MD5: %s" % (len(pe.data), md5sum(pe.data)) 274 | 275 | self.locate_packs(setup_utility_pe.data) 276 | 277 | self.locate_vss(volumes) 278 | 279 | def locate_vss(self, volumes): 280 | 281 | for vss_volume in filter(FirmwareVolume.has_vss, volumes): 282 | print "Have vss_volume:", vss_volume 283 | try: 284 | vssdata = VSSData(vss_volume.data) 285 | except AssertionError, e: 286 | #print " .. failed to load: '%s'" % e 287 | continue 288 | 289 | print vss_volume, vssdata 290 | 291 | for var in vssdata: 292 | if var.vh.status == Variable.ACTIVE: 293 | print var 294 | if var.name == "Setup": 295 | var.showinfo() 296 | 297 | def locate_packs(self, setuputility_binary): 298 | "Searches for Forms and the English StringTable using a set of heuristics" 299 | 300 | # 1st byte: upper bits from length: almost certainly zero 301 | # 2-3: Short typecode, 3 == form 302 | # 4-5: 0x0e is the formset opcode, and 0x24 is is length 303 | # This magic string appears three bytes into the header 304 | form_magic = "\x00\x03\x00\x0e\x24" 305 | form_magic_offset = -3 306 | 307 | # HiipackHeaderSize 308 | HHS = 6 309 | english_attribute_magic = "\x00" * 4 310 | 311 | def create_stringtable(magic_location): 312 | def test_stringtable(poss_header_location): 313 | # We started at attributes, start at lnoff 314 | poss_header_location -= 12 315 | 316 | dat = setuputility_binary[poss_header_location:] 317 | lnoff, plnoff, count, attributes = unpack_from(", name='%s' help='%s'" % args 369 | 370 | if not found: 371 | print "Sorry, I couldn't locate the VT flag? :(" 372 | 373 | def get_sections(self, container): 374 | "Return a recursive list of sections" 375 | result = [] 376 | for section in container.sections: 377 | result.append(section) 378 | if section.sections: 379 | result.append(self.get_sections(section)) 380 | return result 381 | 382 | def get_section_type(self, sections, type): 383 | "Return the first section that has type `type`" 384 | for section in sections: 385 | if section.type == type: 386 | return section 387 | 388 | def locate_setup_utility(self, volumes): 389 | "Locate the SetupUtility section within `volumes`" 390 | 391 | for vol in volumes: 392 | if vol.position != 0x10: 393 | continue 394 | 395 | for file in fsdump.FS(vol.data): 396 | FILE_TYPE_CONTAINS_PE = 0x07 397 | if file.type != FILE_TYPE_CONTAINS_PE: 398 | continue 399 | 400 | sections = self.get_sections(file) 401 | 402 | TYPE_NAME = 0x15 403 | name_section = self.get_section_type(sections[1], TYPE_NAME) 404 | 405 | if name_section.name == "SetupUtility": 406 | return sections 407 | 408 | raise RuntimeError("Shouldn't get here, seems we couldn't " 409 | "find the SetupUtility :/") 410 | 411 | def locate_firmware_volumes(self, data, where=None): 412 | """Search through `data` looking for firmware volume headers 413 | `where` optionally specifies where it came from (e.g. compressed section) 414 | """ 415 | FVH_OFFSET_WITHIN_HEADER = 0x28 416 | subtract_offset = lambda x: x - FVH_OFFSET_WITHIN_HEADER 417 | items = find_all(data, "_FVH", subtract_offset) 418 | 419 | #print "Found the following:", items 420 | 421 | return [FirmwareVolume(data, position, where) for position in items] 422 | 423 | def retrieve_from_memory(self): 424 | "Download the BIOS directly from memory. Must be root to do this." 425 | try: 426 | with open("/dev/mem", "rb") as memory: 427 | memory.seek(BIOS_START) 428 | 429 | print "Reading BIOS data.." 430 | bios_data = read_with_progress(memory, BIOS_SIZE, 2 ** 6 * KB) 431 | 432 | except IOError, err: 433 | if err.errno == 13: 434 | print "Read error reading '%s' Are you root?" % path 435 | else: 436 | print "Unexpected error" 437 | raise 438 | 439 | return bios_data 440 | 441 | def load_bios(self, from_where=None): 442 | "If the desired bios file doesn't exist, try to load it from memory" 443 | 444 | if from_where is None: 445 | from_where = SAVE_PATH 446 | 447 | if not exists(from_where): 448 | bios_data = self.retrieve_from_memory() 449 | 450 | print "Saving BIOS to '%s' md5:%s" % (SAVE_PATH, md5sum(bios_data)) 451 | with open(SAVE_PATH, "wb") as f_bios: 452 | f_bios.write(bios_data) 453 | 454 | else: 455 | with open(from_where, "rb") as f_bios: 456 | bios_data = f_bios.read() 457 | 458 | print "Opened BIOS '%s' with md5:%s" % ( 459 | from_where, md5sum(bios_data)) 460 | 461 | return bios_data 462 | 463 | 464 | def main(): 465 | if not exists("./data/"): 466 | makedirs("./data/") 467 | 468 | bios = BIOS() 469 | 470 | print "Done" 471 | 472 | if __name__ == "__main__": 473 | main() 474 | -------------------------------------------------------------------------------- /insyde-tools/specs/insyde-module-header-format.txt: -------------------------------------------------------------------------------- 1 | Offset (h) Length (h) Item 2 | ---------- ---------- ---- 3 | 0 10 GUID - [EFI_GUID] 4 | 10 1 Header checksum (2's complement sum of first 17h bytes - assume extra checksum is 0) \ [EFI_FFS_INTEGRITY_CHECK] 5 | 11 1 Module checksum (2's complement sum of bytes from 18h to end of module (excluding any FFh padding)) / 6 | 12 1 Type of module - [EFI_FV_FILETYPE] 7 | 13 1 Module attributes - [EFI_FFS_FILE_ATTRIBUTES] 8 | 14 3 Size of header and module (excluding FFh padding at end, but including 00h padding) - [Size] 9 | 17 1 State - [EFI_FFS_FILE_STATE] - only ever seen F8h 10 | 11 | Common header 12 | 13 | 18 3 Size of extended header and module (from 18h in header, excluding FFh padding, but including 00h padding) 14 | 1b 1 Type byte / Extended header byte 15 | - if 1,10h-1Bh then module follows directly 16 | - if 2 then extended header 17 | Extended header 18 | 19 | 1c 10 GUID (? always FC1BCDB0-7D31-49AA-936A-A4600D9DD083) 20 | 2c 2 Data offset (from common header - normally 1Ch) 21 | 2e 2 Attributes (1 = Processing required, 2 = Status valid) 22 | 30 4 CRC32 of module (including last 4 bytes of header, excluding FFh padding, including 00h padding) 23 | 24 | Next common header 25 | 26 | 34 3 Module size (including these 4 bytes, excluding ALL padding) 27 | 37 1 Type byte 28 | 29 | All modules are padded 00h/FFh to QWORD boundry 30 | 31 | Type 32 | EFI_FV_FILETYPE_ALL 0x00 33 | EFI_FV_FILETYPE_RAW 0x01 34 | EFI_FV_FILETYPE_FREEFORM 0x02 35 | EFI_FV_FILETYPE_SECURITY_CORE 0x03 36 | EFI_FV_FILETYPE_PEI_CORE 0x04 37 | EFI_FV_FILETYPE_DXE_CORE 0x05 38 | EFI_FV_FILETYPE_PEIM 0x06 39 | EFI_FV_FILETYPE_DRIVER 0x07 40 | EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08 41 | EFI_FV_FILETYPE_APPLICATION 0x09 42 | 43 | Attributes 44 | 00000001 - Tail present 45 | 00000010 - Needed for crisis recovery 46 | 00000100 - Reserved (0) 47 | 00111000 - Alignment (000 - 111) 48 | 01000000 - If set, module checksum present 49 | 50 | State 51 | 00000001 - EFI_FILE_HEADER_CONSTRUCTION 52 | 00000010 - EFI_FILE_HEADER_VALID 53 | 00000100 - EFI_FILE_DATA_VALID 54 | 00001000 - EFI_FILE_MARKED_FOR_UPDATE 55 | 00010000 - EFI_FILE_DELETED 56 | 00100000 - EFI_FILE_HEADER_INVALID 57 | 11000000 - ? Always 11 58 | 59 | Type of region 60 | EFI_SECTION_COMPRESSION 0x01 (not compressed in most insyde) 61 | EFI_SECTION_GUID_DEFINED 0x02 62 | EFI_SECTION_PE32 0x10 63 | EFI_SECTION_PIC 0x11 64 | EFI_SECTION_TE 0x12 65 | EFI_SECTION_DXE_DEPEX 0x13 66 | EFI_SECTION_VERSION 0x14 67 | EFI_SECTION_USER_INTERFACE 0x15 68 | EFI_SECTION_COMPATIBILITY16 0x16 69 | EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17 70 | EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18 71 | EFI_SECTION_RAW 0x19 72 | EFI_SECTION_PEI_DEPEX 0x1B 73 | 74 | Source: http://forums.mydigitallife.info/threads/11693-Insyde-module-headers 75 | 76 | -------------------------------------------------------------------------------- /insyde-tools/util.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | from hashlib import md5 4 | from sys import stdout 5 | from pprint import pprint 6 | 7 | 8 | def md5sum(data): 9 | return md5(data).hexdigest() 10 | 11 | 12 | class FindBadPosition(Exception): 13 | """Raised to disallow a position from appearing in the result list in `find_all`""" 14 | pass 15 | 16 | 17 | class FindStopSearching(Exception): 18 | """Stop searching in find_all""" 19 | def __init__(self, result): 20 | self.result = result 21 | 22 | 23 | def from_b64(what): 24 | return str.decode(what + "=" * (3 - len(what) % 3), "base64") 25 | 26 | 27 | def hexbytes(bytes): 28 | return " ".join(["%02x" % ord(c) for c in bytes]) 29 | 30 | 31 | def substitute(input, where, what): 32 | return "".join([input[:where], what, input[where + len(what):]]) 33 | 34 | 35 | def find_all(buffer, what, callback=lambda x: x, start=0, stop=None): 36 | if stop is None: 37 | stop = len(buffer) 38 | 39 | position = start 40 | result = [] 41 | 42 | while position < stop and what in buffer[position:stop + 1]: 43 | 44 | position = buffer.index(what, position, stop) 45 | 46 | try: 47 | result.append(callback(position)) 48 | except FindStopSearching, exc: 49 | return exc.result 50 | except FindBadPosition: 51 | pass 52 | 53 | position += 1 54 | 55 | return result 56 | 57 | 58 | def find_all_backwards(buffer, what, callback=lambda x: x, start=None, stop=0): 59 | "Beware! This function is not fully tested. I should really write some unit tests for the edge cases" 60 | 61 | if start is None: 62 | start = len(buffer) 63 | 64 | position = start 65 | result = [] 66 | 67 | while position > stop and what in buffer[stop:position]: 68 | 69 | position = buffer.rindex(what, stop, position) 70 | 71 | try: 72 | result.append(callback(position)) 73 | except FindStopSearching, exc: 74 | return exc.result 75 | except FindBadPosition: 76 | pass 77 | 78 | position += 1 79 | 80 | return result 81 | 82 | 83 | def read_with_progress(file_handle, total, chunk_size): 84 | assert not total % chunk_size, "chunk_size must be a divisor of total!" 85 | data = [] 86 | length = (80 - 6) 87 | for i in xrange(0, total, chunk_size): 88 | data.append(file_handle.read(chunk_size)) 89 | done = length * i // total 90 | print "\r[ %s>%s ]" % ("-" * done, " " * (length - done)), 91 | stdout.flush() 92 | print "\r[ %s> ]" % ("-" * length) 93 | return "".join(data) 94 | 95 | from struct import unpack, Struct as pyStruct 96 | 97 | 98 | class StructMeta(type): 99 | def __new__(meta, classname, bases, classDict): 100 | 101 | is_structitem = lambda x: isinstance(x[1], SI) 102 | struct_items = filter(is_structitem, classDict.iteritems()) 103 | struct_items.sort(key=lambda x: x[1].position) 104 | 105 | struct_format = "".join(map(lambda x: x[1].packstr, struct_items)) 106 | 107 | struct = pyStruct(struct_format) 108 | 109 | def __init__(self, data): 110 | 111 | data_tuple = struct.unpack_from(data) 112 | for (name, structitem), item_data in zip(struct_items, data_tuple): 113 | setattr(self, name, item_data) 114 | 115 | self.rest_of_data = data[struct.size:] 116 | 117 | #def repack(self): 118 | 119 | cls = type.__new__(meta, classname, bases, classDict) 120 | cls.py_struct = struct 121 | cls.struct_size = struct.size 122 | cls.__init__ = __init__ 123 | 124 | return cls 125 | 126 | 127 | class SI(object): 128 | "StructItem" 129 | counter = 0 130 | 131 | def __init__(self, packstr): 132 | self.position = SI.counter 133 | SI.counter += 1 134 | self.packstr = packstr 135 | 136 | 137 | class Struct(object): 138 | __metaclass__ = StructMeta 139 | 140 | 141 | def hexdump(s, sep=" "): 142 | return sep.join(map(lambda x: "%02x" % ord(x), s)) 143 | 144 | 145 | def ascii(s): 146 | s2 = "" 147 | for c in s: 148 | if ord(c) < 0x20 or ord(c) > 0x7e: 149 | s2 += "." 150 | else: 151 | s2 += c 152 | return s2 153 | 154 | 155 | def pad(s, c, l): 156 | if len(s) < l: 157 | s += c * (l - len(s)) 158 | return s 159 | 160 | 161 | def chexdump(s, ts="", off=0): 162 | for i in range(0, len(s), 16): 163 | 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)) 164 | 165 | if __name__ == "__main__": 166 | 167 | s = Header("test") 168 | print "I have something:", s 169 | -------------------------------------------------------------------------------- /microcode_extract.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # extract microcode updates from binary BIOS files 3 | # v 0.1 2012/07/23 4 | # v 0.2 2012/07/23 added VIA Nano support (relaxed some checks) 5 | # Licensed as Public Domain 6 | 7 | import ctypes 8 | import struct 9 | import sys 10 | import array 11 | 12 | uint8_t = ctypes.c_ubyte 13 | char = ctypes.c_char 14 | uint32_t = ctypes.c_uint 15 | uint64_t = ctypes.c_uint64 16 | uint16_t = ctypes.c_ushort 17 | 18 | def get_struct(str_, off, struct): 19 | s = struct() 20 | slen = ctypes.sizeof(s) 21 | bytes = str_[off:off+slen] 22 | fit = min(len(bytes), slen) 23 | ctypes.memmove(ctypes.addressof(s), bytes, fit) 24 | return s 25 | 26 | def DwordAt(f, off): 27 | return struct.unpack(" maxoff: 61 | return 62 | 63 | # update size must be a multiple of DWORD 64 | if (hdr.DataSize & 3) or (hdr.TotalSize & 3): 65 | return 66 | 67 | # looks okay. let's check the checksum 68 | 69 | mdata = f[off:off+check_len] 70 | # make an array of DWORDs 71 | arr = array.array("I", mdata) 72 | # sum them 73 | ck = sum(arr) & 0xFFFFFFFF 74 | if ck == 0: 75 | print "%08X: found a valid-looking update" % off 76 | print ["Date: %02X/%02X/%4X", "Date: %02d/%02d/%4d"][is_via] % ((hdr.Date >> 24)&0xFF, (hdr.Date >> 16)&0xFF, hdr.Date & 0xFFFF) 77 | print "Processor signature: %08X" % hdr.ProcessorSignature 78 | if not is_via: 79 | print "Processor flags: %08X" % hdr.ProcessorFlags 80 | print "Length: %08X" % check_len 81 | fname = "mcode_upd_%08X.bin" % off 82 | print "Extracting to %s" % fname 83 | open(fname, "wb").write(mdata) 84 | return True 85 | # nope 86 | return False 87 | 88 | def find_ucode(f, is_via): 89 | maxoff = len(f) 90 | # minimal microcode update length is 2048 bytes 91 | off = (maxoff-2048+8)&(~15) 92 | # look for BCD date ddmmyyyy 93 | # yyyy off-2 94 | # dd off-1 95 | # mm off 96 | print "Scanning...\n%08X" % off 97 | while off > 11: 98 | # looks like a date? 99 | m = ord(f[off]) 100 | if (1 <= m <= 0x12) and (1 <= ord(f[off-1]) <= 0x31): 101 | if check_valid_mcode(f, off-11, maxoff, is_via): 102 | maxoff = off-11 103 | print "Scanning...\n%08X" % off 104 | off -= 1 105 | if (off & 0xFFFFF) == 0: 106 | print "%08X" % off 107 | print "\nDone" 108 | 109 | if len(sys.argv) < 2: 110 | print "Usage: microcode_extract.py [-i|-v]" 111 | print " -i: look for Intel microcode (default)" 112 | print " -v: look for VIA Nano microcode" 113 | sys.exit(1) 114 | else: 115 | fn = None 116 | is_via = False 117 | for arg in sys.argv[1:]: 118 | if arg == "-v": 119 | is_via = True 120 | elif arg == "-i": 121 | is_via = False 122 | else: 123 | fn = arg 124 | 125 | f = open(fn, "rb").read() 126 | find_ucode(f, is_via) 127 | -------------------------------------------------------------------------------- /src/ami.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Decompression utility for AMI BIOSes. 3 | * 4 | * Copyright 2009 Luc Verhaegen 5 | * Copyright 2000-2006 Anthony Borisow 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2, or (at your option) 10 | * any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; see the file COPYING. If not, write to 19 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 20 | */ 21 | 22 | #define _GNU_SOURCE 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "bios_extract.h" 34 | #include "compat.h" 35 | #include "lh5_extract.h" 36 | 37 | struct AMI95ModuleName { 38 | uint8_t Id; 39 | char *Name; 40 | }; 41 | 42 | static struct AMI95ModuleName AMI95ModuleNames[] = { 43 | {0x00, "POST"}, 44 | {0x01, "Setup Server"}, 45 | {0x02, "RunTime"}, 46 | {0x03, "DIM"}, 47 | {0x04, "Setup Client"}, 48 | {0x05, "Remote Server"}, 49 | {0x06, "DMI Data"}, 50 | {0x07, "Green PC"}, 51 | {0x08, "Interface"}, 52 | {0x09, "MP"}, 53 | {0x0A, "Notebook"}, 54 | {0x0B, "Int-10"}, 55 | {0x0C, "ROM-ID"}, 56 | {0x0D, "Int-13"}, 57 | {0x0E, "OEM Logo"}, 58 | {0x0F, "ACPI Table"}, 59 | {0x10, "ACPI AML"}, 60 | {0x11, "P6 Microcode"}, 61 | {0x12, "Configuration"}, 62 | {0x13, "DMI Code"}, 63 | {0x14, "System Health"}, 64 | {0x15, "Memory Sizing"}, 65 | {0x16, "Memory Test"}, 66 | {0x17, "Debug"}, 67 | {0x18, "ADM (Display MGR)"}, 68 | {0x19, "ADM Font"}, 69 | {0x1A, "Small Logo"}, 70 | {0x1B, "SLAB"}, 71 | {0x1C, "BCP Info"}, 72 | {0x1D, "Dual Logo"}, 73 | {0x1E, "Intel OSB"}, 74 | {0x20, "PCI AddOn ROM"}, 75 | {0x21, "Multilanguage"}, 76 | {0x22, "UserDefined"}, 77 | {0x23, "ASCII Font"}, 78 | {0x24, "BIG5 Font"}, 79 | {0x25, "OEM Logo"}, 80 | {0x26, "Debugger"}, 81 | {0x27, "Debugger Port"}, 82 | {0x28, "BMC Output"}, 83 | {0x29, "MBI File"}, 84 | {0x2A, "User ROM"}, 85 | {0x2B, "PXE Code"}, 86 | {0x2C, "AMI Font"}, 87 | {0x2E, "User ROM"}, 88 | {0x2D, "Battery Refresh"}, 89 | {0x2F, "Serial Redirection"}, 90 | {0x30, "Font Database"}, 91 | {0x31, "OEM Logo Data"}, 92 | {0x32, "Graphic Logo Code"}, 93 | {0x33, "Graphic Logo Data"}, 94 | {0x34, "Action Logo Code"}, 95 | {0x35, "Action Logo Data"}, 96 | {0x36, "Virus"}, 97 | {0x37, "Online Menu"}, 98 | {0x38, "Lang1 as ROM"}, 99 | {0x39, "Lang2 as ROM"}, 100 | {0x3A, "Lang3 as ROM"}, 101 | {0x40, "AMD CIM-X NB binary"}, 102 | {0x60, "AMD CIM-X SB binary"}, 103 | {0x70, "OSD Bitmaps"}, 104 | {0x80, "Image Info"}, 105 | {0xab, "CompuTrace backdoor"}, 106 | {0xf0, "Asrock Backup Util or Windows SLIC"}, 107 | {0xf9, "Asrock AMD AHCI DLL"}, 108 | {0xfa, "Asrock LOGO GIF"}, 109 | {0xfb, "Asrock LOGO JPG"}, 110 | {0xfc, "Asrock LOGO JPG"}, 111 | {0xfd, "Asrock LOGO PCX - Instant boot"}, 112 | {0, NULL} 113 | }; 114 | 115 | static char *AMI95ModuleNameGet(uint8_t ID) 116 | { 117 | int i; 118 | 119 | for (i = 0; AMI95ModuleNames[i].Name; i++) 120 | if (AMI95ModuleNames[i].Id == ID) 121 | return AMI95ModuleNames[i].Name; 122 | return NULL; 123 | } 124 | 125 | /* 126 | * 127 | */ 128 | Bool 129 | AMI95Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, 130 | uint32_t AMIBOffset, uint32_t ABCOffset) 131 | { 132 | Bool Compressed; 133 | uint32_t Offset; 134 | char Date[9]; 135 | int i; 136 | 137 | struct abc { 138 | const char AMIBIOSC[8]; 139 | const char Version[4]; 140 | const uint16_t CRCLen; 141 | const uint32_t CRC32; 142 | const uint16_t BeginLo; 143 | const uint16_t BeginHi; 144 | } *abc; 145 | 146 | struct bigpart { 147 | const uint32_t CSize; 148 | const uint32_t Unknown; 149 | } *bigpart; 150 | 151 | struct part { 152 | /* When Previous Part Address is 0xFFFFFFFF, then this is the last part. */ 153 | const uint16_t PrePartLo; /* Previous part low word */ 154 | const uint16_t PrePartHi; /* Previous part high word */ 155 | const uint16_t CSize; /* Header length */ 156 | const uint8_t PartID; /* ID for this header */ 157 | const uint8_t IsComprs; /* 0x80 -> compressed */ 158 | const uint32_t RealCS; /* Old BIOSes: 159 | Real Address in RAM where to expand to 160 | Now: 161 | Type 0x20 PCI ID of device for this ROM 162 | Type 0x21 Language ID (ascii) */ 163 | const uint32_t ROMSize; /* Compressed Length */ 164 | const uint32_t ExpSize; /* Expanded Length */ 165 | } *part; 166 | 167 | if (!ABCOffset) { 168 | if ((BIOSImage[8] == '1') && (BIOSImage[9] == '0') && 169 | (BIOSImage[11] == '1') && (BIOSImage[12] == '0')) 170 | fprintf(stderr, 171 | "Error: This is an AMI '94 (1010) BIOS Image.\n"); 172 | else 173 | fprintf(stderr, 174 | "Error: This is an AMI '94 BIOS Image.\n"); 175 | return FALSE; 176 | } 177 | 178 | if (ABCOffset + sizeof (struct abc) < BIOSLength) { 179 | abc = (struct abc *)(BIOSImage + ABCOffset); 180 | if (memcmp (abc->Version, "AMIN", 4) == 0) { 181 | /* Skip to next one if immediately followed by "AMINCBLK" 182 | * header in place of a version number. */ 183 | abc = (struct abc *)memmem (BIOSImage + ABCOffset + 1, 184 | BIOSLength - ABCOffset - 1 - sizeof (struct abc), 185 | "AMIBIOSC", 8); 186 | } 187 | } else 188 | abc = NULL; 189 | 190 | if (!abc) { 191 | fprintf(stderr, 192 | "Error: short read after AMIBIOSC signature.\n"); 193 | return FALSE; 194 | } 195 | 196 | /* Get Date */ 197 | memcpy(Date, BIOSImage + BIOSLength - 11, 8); 198 | Date[8] = 0; 199 | 200 | printf("AMI95 Version\t: %.4s (%s)\n", abc->Version, Date); 201 | 202 | /* First, the boot rom */ 203 | uint32_t BootOffset; 204 | int fd; 205 | 206 | BootOffset = AMIBOffset & 0xFFFF0000; 207 | 208 | printf("0x%05X (%6d bytes) -> amiboot.rom\n", BootOffset, 209 | BIOSLength - BootOffset); 210 | 211 | fd = open("amiboot.rom", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 212 | if (fd < 0) { 213 | fprintf(stderr, "Error: unable to open %s: %s\n\n", 214 | "amiboot.rom", strerror(errno)); 215 | return FALSE; 216 | } 217 | 218 | write(fd, BIOSImage + BootOffset, BIOSLength - BootOffset); 219 | close(fd); 220 | 221 | /* now dump the individual modules */ 222 | if (BIOSLength > 0x100000) 223 | Offset = (le16toh(abc->BeginHi) << 16) + le16toh(abc->BeginLo); 224 | else 225 | Offset = (le16toh(abc->BeginHi) << 4) + le16toh(abc->BeginLo); 226 | 227 | for (i = 0; i < 0x80; i++) { 228 | char filename[64], *ModuleName; 229 | unsigned char *Buffer; 230 | int BufferSize, ROMSize; 231 | 232 | part = (struct part *)(BIOSImage + (Offset - BIOSOffset)); 233 | 234 | if (part->IsComprs & 0x80) 235 | Compressed = FALSE; 236 | else 237 | Compressed = TRUE; 238 | 239 | /* even they claim they are compressed they arent */ 240 | if ((part->PartID == 0x40) || (part->PartID == 0x60)) 241 | Compressed = FALSE; 242 | 243 | if (part->PartID == 0x20) { 244 | uint16_t vid = le32toh(part->RealCS) & 0xFFFF; 245 | uint16_t pid = le32toh(part->RealCS) >> 16; 246 | sprintf(filename, "amipci_%04X_%04X.rom", vid, pid); 247 | } else if (part->PartID == 0x21) { 248 | sprintf(filename, "amilang_%c%c.rom", 249 | (le32toh(part->RealCS) >> 8) & 0xFF, 250 | le32toh(part->RealCS) & 0xFF); 251 | } else 252 | sprintf(filename, "amibody_%02x.rom", part->PartID); 253 | 254 | if (Compressed) { 255 | ROMSize = le32toh(part->ROMSize); 256 | BufferSize = le32toh(part->ExpSize); 257 | } else { 258 | BufferSize = le16toh(part->CSize); 259 | if (!BufferSize || (BufferSize == 0xFFFF)) { 260 | bigpart = 261 | (struct bigpart *)(BIOSImage + 262 | (Offset - BIOSOffset) - 263 | sizeof(struct bigpart)); 264 | BufferSize = le32toh(bigpart->CSize); 265 | } 266 | ROMSize = BufferSize; 267 | } 268 | 269 | if (Compressed) 270 | printf("0x%05X (%6d bytes)", Offset - BIOSOffset + 0x14, 271 | ROMSize); 272 | else 273 | printf("0x%05X (%6d bytes)", Offset - BIOSOffset + 0x0C, 274 | ROMSize); 275 | 276 | printf(" -> %-20s", filename); 277 | 278 | if (Compressed) 279 | printf(" (%6d bytes)", BufferSize); 280 | else 281 | printf(" "); 282 | 283 | ModuleName = AMI95ModuleNameGet(part->PartID); 284 | if (ModuleName) 285 | printf(" \"%s\"\n", ModuleName); 286 | else 287 | printf("\n"); 288 | 289 | Buffer = MMapOutputFile(filename, BufferSize); 290 | if (!Buffer) 291 | return FALSE; 292 | 293 | if (Compressed) 294 | LH5Decode(BIOSImage + (Offset - BIOSOffset) + 0x14, 295 | ROMSize, Buffer, BufferSize); 296 | else 297 | memcpy(Buffer, BIOSImage + (Offset - BIOSOffset) + 0x0C, 298 | BufferSize); 299 | 300 | munmap(Buffer, BufferSize); 301 | 302 | if ((le16toh(part->PrePartHi) == 0xFFFF) 303 | || (le16toh(part->PrePartLo) == 0xFFFF)) 304 | break; 305 | 306 | if (BIOSLength > 0x100000) 307 | Offset = 308 | (le16toh(part->PrePartHi) << 16) + 309 | le16toh(part->PrePartLo); 310 | else 311 | Offset = 312 | (le16toh(part->PrePartHi) << 4) + 313 | le16toh(part->PrePartLo); 314 | } 315 | 316 | return TRUE; 317 | } 318 | -------------------------------------------------------------------------------- /src/ami_slab.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Michael Karcher 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "compat.h" 28 | 29 | #if !defined(le32toh) || !defined(le16toh) 30 | #if BYTE_ORDER == LITTLE_ENDIAN 31 | #define le32toh(x) (x) 32 | #define le16toh(x) (x) 33 | #else 34 | #include 35 | #define le32toh(x) bswap_32(x) 36 | #define le16toh(x) bswap_16(x) 37 | #endif 38 | #endif 39 | 40 | struct slabentry { 41 | uint32_t destaddr; 42 | uint32_t length_flag; 43 | }; 44 | 45 | struct slabheader { 46 | uint16_t entries; 47 | uint16_t headersize; 48 | struct slabentry blocks[0]; 49 | }; 50 | 51 | struct nameentry { 52 | uint8_t segtype; 53 | uint16_t dtor_offset; 54 | char name[0]; 55 | }; 56 | 57 | int slabextract(const unsigned char *buffer, int bufferlen) 58 | { 59 | const struct slabheader *h = (const void *)buffer; 60 | const unsigned char *listpointer; 61 | const unsigned char *datapointer; 62 | int i, count, headersize; 63 | 64 | headersize = le16toh(h->headersize); 65 | count = le16toh(h->entries); 66 | if ((headersize < ((count * 8) + 4)) || (bufferlen < headersize)) { 67 | fprintf(stderr, 68 | "Invalid file header - probably not a SLAB file\n"); 69 | return 1; 70 | } 71 | printf("%d entries\n", count); 72 | 73 | /* FIXME: Is the 37 really constant? */ 74 | if (((8 * count) + 37) < headersize) { 75 | listpointer = buffer + 8 * count + 37; 76 | printf("Name Tp "); 77 | } else { 78 | listpointer = NULL; /* No names present */ 79 | printf("Name "); 80 | } 81 | 82 | datapointer = buffer + le32toh(h->headersize); 83 | 84 | printf("LoadAddr size initialized\n"); 85 | 86 | for (i = 0; i < count; i++) { 87 | const struct slabentry *block; 88 | char filename[25]; 89 | uint32_t len; 90 | int has_data; 91 | 92 | if (listpointer) { 93 | const struct nameentry *entry = 94 | (const void *)listpointer; 95 | block = 96 | (const void *)(buffer + 97 | le16toh(entry->dtor_offset)); 98 | sprintf(filename, "%.20s.bin", entry->name); 99 | listpointer += strlen(entry->name) + 4; 100 | printf("%-15s %02x ", entry->name, entry->segtype); 101 | } else { 102 | block = (const void *)(buffer + 4 + 8 * i); 103 | sprintf(filename, "block%02d.bin", i); 104 | printf("block%02d ", i); 105 | } 106 | 107 | len = le32toh(block->length_flag); 108 | if (len & 0x80000000) 109 | has_data = 1; 110 | else 111 | has_data = 0; 112 | len &= 0x7fffffff; 113 | 114 | printf("%08x %8d\t %s\n", le32toh(block->destaddr), len, 115 | has_data ? "yes" : "no"); 116 | 117 | if (has_data) { 118 | int outfd; 119 | 120 | if (datapointer + len > buffer + bufferlen) { 121 | fprintf(stderr, 122 | "Not enough data. File truncated?\n"); 123 | return 1; 124 | } 125 | outfd = 126 | open(filename, O_WRONLY | O_CREAT | O_TRUNC, 127 | S_IRUSR | S_IWUSR); 128 | if (outfd != -1) { 129 | int ret = write(outfd, datapointer, len); 130 | if (ret == -1) 131 | fprintf(stderr, "Can't write %s: %s\n", 132 | filename, strerror(errno)); 133 | else if (ret < len) 134 | fprintf(stderr, 135 | "Can't write %s completely: Disk full?\n", 136 | filename); 137 | close(outfd); 138 | } else 139 | fprintf(stderr, 140 | "Can't create output file %s: %s\n", 141 | filename, strerror(errno)); 142 | datapointer += len; 143 | } 144 | } 145 | 146 | if (datapointer != buffer + bufferlen) 147 | fprintf(stderr, "Warning: Unexpected %d trailing bytes", 148 | (int)(buffer + bufferlen - datapointer)); 149 | 150 | return 0; 151 | } 152 | 153 | int main(int argc, char *argv[]) 154 | { 155 | int infd; 156 | unsigned char *InputBuffer; 157 | int InputBufferSize; 158 | 159 | if (argc != 2) { 160 | printf("usage: %s \n", argv[0]); 161 | return 1; 162 | } 163 | 164 | infd = open(argv[1], O_RDONLY); 165 | if (infd < 0) { 166 | fprintf(stderr, "Error: Failed to open %s: %s\n", argv[1], 167 | strerror(errno)); 168 | return 1; 169 | } 170 | 171 | InputBufferSize = lseek(infd, 0, SEEK_END); 172 | if (InputBufferSize < 0) { 173 | fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1], 174 | strerror(errno)); 175 | return 1; 176 | } 177 | 178 | InputBuffer = 179 | mmap(NULL, InputBufferSize, PROT_READ, MAP_PRIVATE, infd, 0); 180 | if (InputBuffer < 0) { 181 | fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1], 182 | strerror(errno)); 183 | return 1; 184 | } 185 | 186 | /* fixed header size - everything else is checked dynamically in slabextract */ 187 | if (InputBufferSize < 4) { 188 | fprintf(stderr, 189 | "Error: \"%s\" is too small to be a SLAB file.\n", 190 | argv[1]); 191 | return 1; 192 | } 193 | 194 | return slabextract(InputBuffer, InputBufferSize); 195 | } 196 | -------------------------------------------------------------------------------- /src/award.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #define _GNU_SOURCE 1 /* for memmem */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "compat.h" 27 | #include "bios_extract.h" 28 | #include "lh5_extract.h" 29 | 30 | /* 31 | * 32 | */ 33 | Bool 34 | AwardExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, 35 | uint32_t Offset1, uint32_t BCPSegmentOffset) 36 | { 37 | unsigned char *p, *Buffer; 38 | int HeaderSize; 39 | unsigned int BufferSize, PackedSize; 40 | char *filename; 41 | unsigned short crc; 42 | 43 | printf("Found Award BIOS.\n"); 44 | 45 | p = BIOSImage; 46 | while (p) { 47 | p = memmem(p, BIOSLength - (p - BIOSImage), "-lh5-", 5); 48 | if (!p) 49 | break; 50 | p -= 2; 51 | HeaderSize = LH5HeaderParse(p, BIOSLength - (p - BIOSImage), 52 | &BufferSize, &PackedSize, &filename, 53 | &crc); 54 | if (!HeaderSize) 55 | return FALSE; 56 | 57 | printf("0x%05X (%6d bytes) -> %s \t(%6d bytes)\n", 58 | (unsigned int)(p - BIOSImage), HeaderSize + PackedSize, 59 | filename, BufferSize); 60 | 61 | Buffer = MMapOutputFile(filename, BufferSize); 62 | if (!Buffer) 63 | return FALSE; 64 | 65 | LH5Decode(p + HeaderSize, PackedSize, Buffer, BufferSize); 66 | 67 | munmap(Buffer, BufferSize); 68 | 69 | p += HeaderSize + PackedSize; 70 | } 71 | 72 | return TRUE; 73 | } 74 | -------------------------------------------------------------------------------- /src/bcpvpd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* 20 | * This code is heavily based on Veit Kannegiesers 21 | * e_bcpvpd.pas program. This software comes with no license, but is freely 22 | * downloadable at http://kannegieser.net/veit/quelle/phoedeco_src.arj 23 | */ 24 | /* 25 | * It should be very straightfoward to add support for the $COMPIBM compressed 26 | * bios images as well. According to Veits code, the id-string is "$COMPIBM", 27 | * and the data starts straight after the (not null-terminated) id-string. 28 | */ 29 | 30 | #define _GNU_SOURCE 1 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "compat.h" 40 | #include "lzss_extract.h" 41 | 42 | int main(int argc, char *argv[]) 43 | { 44 | int infd, outfd; 45 | unsigned char *InputBuffer; 46 | int InputBufferSize; 47 | 48 | if (argc != 3) { 49 | printf("usage: %s \n", argv[0]); 50 | return 1; 51 | } 52 | 53 | infd = open(argv[1], O_RDONLY); 54 | if (infd < 0) { 55 | fprintf(stderr, "Error: Failed to open %s: %s\n", argv[1], 56 | strerror(errno)); 57 | return 1; 58 | } 59 | 60 | InputBufferSize = lseek(infd, 0, SEEK_END); 61 | if (InputBufferSize < 0) { 62 | fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1], 63 | strerror(errno)); 64 | return 1; 65 | } 66 | 67 | InputBuffer = 68 | mmap(NULL, InputBufferSize, PROT_READ, MAP_PRIVATE, infd, 0); 69 | if (InputBuffer < 0) { 70 | fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1], 71 | strerror(errno)); 72 | return 1; 73 | } 74 | 75 | if (InputBufferSize < 0x52) { 76 | fprintf(stderr, 77 | "Error: \"%s\" is too small tp be a BCPVPD file.\n", 78 | argv[1]); 79 | return 1; 80 | } 81 | 82 | if (strncmp((char *)InputBuffer, "BCPVPD", 7)) { 83 | fprintf(stderr, 84 | "Error: unable to find BCPVPD header in \"%s\".\n", 85 | argv[1]); 86 | return 1; 87 | } 88 | 89 | outfd = open(argv[2], O_RDWR | O_TRUNC | O_CREAT, S_IRWXU); 90 | if (outfd == -1) { 91 | fprintf(stderr, "Error: Failed to open \"%s\": %s\n", argv[2], 92 | strerror(errno)); 93 | return 1; 94 | } 95 | 96 | return LZSSExtract(InputBuffer + 0x52, InputBufferSize - 0x52, outfd); 97 | } 98 | -------------------------------------------------------------------------------- /src/bios_extract.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #define _GNU_SOURCE /* memmem is useful */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "compat.h" 29 | #include "bios_extract.h" 30 | 31 | static void HelpPrint(char *name) 32 | { 33 | printf("\n"); 34 | printf("Program to extract compressed modules from BIOS images.\n"); 35 | printf("Supports AMI, Award, Asus and Phoenix BIOSes.\n"); 36 | printf("\n"); 37 | printf("Usage:\n\t%s \n", name); 38 | } 39 | 40 | unsigned char *MMapOutputFile(char *filename, int size) 41 | { 42 | unsigned char *Buffer; 43 | char *tmp; 44 | int fd; 45 | 46 | /* all slash signs '/' in filenames will be replaced by a backslash sign '\' */ 47 | tmp = filename; 48 | while ((tmp = strchr(tmp, '/')) != NULL) 49 | tmp[0] = '\\'; 50 | 51 | fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 52 | if (fd < 0) { 53 | fprintf(stderr, "Error: unable to open %s: %s\n\n", filename, 54 | strerror(errno)); 55 | return NULL; 56 | } 57 | 58 | /* grow file */ 59 | if (lseek(fd, size - 1, SEEK_SET) == -1) { 60 | fprintf(stderr, "Error: Failed to grow \"%s\": %s\n", filename, 61 | strerror(errno)); 62 | close(fd); 63 | return NULL; 64 | } 65 | 66 | if (write(fd, "", 1) != 1) { 67 | fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", 68 | filename, strerror(errno)); 69 | close(fd); 70 | return NULL; 71 | } 72 | 73 | Buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 74 | if (Buffer == ((void *)-1)) { 75 | fprintf(stderr, "Error: Failed to mmap %s: %s\n", filename, 76 | strerror(errno)); 77 | close(fd); 78 | return NULL; 79 | } 80 | 81 | close(fd); 82 | 83 | return Buffer; 84 | } 85 | 86 | /* TODO: Make bios identification more flexible */ 87 | 88 | static struct { 89 | char *String1; 90 | char *String2; 91 | Bool(*Handler) (unsigned char *Image, int ImageLength, int ImageOffset, 92 | uint32_t Offset1, uint32_t Offset2); 93 | } BIOSIdentification[] = { 94 | { 95 | "AMIBOOT ROM", "AMIBIOSC", AMI95Extract}, { 96 | "$ASUSAMI$", "AMIBIOSC", AMI95Extract}, { 97 | "AMIEBBLK", "AMIBIOSC", AMI95Extract}, { 98 | "BootBlock SIO Table", "AMIBIOSC", AMI95Extract}, { 99 | "Award BootBlock", "= Award Decompression Bios =", AwardExtract}, { 100 | "Award Modular BIOS", "Award Software Inc", AwardExtract}, { 101 | "Phoenix FirstBIOS", "BCPSEGMENT", PhoenixExtract}, { 102 | "PhoenixBIOS 4.0", "BCPSEGMENT", PhoenixExtract}, { 103 | "PhoenixBIOS Version", "BCPSEGMENT", PhoenixExtract}, { 104 | "Phoenix ServerBIOS 3", "BCPSEGMENT", PhoenixExtract}, { 105 | "Phoenix TrustedCore", "BCPSEGMENT", PhoenixExtract}, { 106 | "Phoenix SecureCore", "BCPSEGMENT", PhoenixExtract}, { 107 | NULL, NULL, NULL},}; 108 | 109 | int main(int argc, char *argv[]) 110 | { 111 | int FileLength = 0; 112 | uint32_t BIOSOffset = 0; 113 | unsigned char *BIOSImage = NULL; 114 | int fd; 115 | uint32_t Offset1, Offset2; 116 | int i, len; 117 | unsigned char *tmp; 118 | 119 | if ((argc != 2) || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 120 | HelpPrint(argv[0]); 121 | return 1; 122 | } 123 | 124 | fd = open(argv[1], O_RDONLY); 125 | if (fd < 0) { 126 | fprintf(stderr, "Error: Failed to open %s: %s\n", argv[1], 127 | strerror(errno)); 128 | return 1; 129 | } 130 | 131 | FileLength = lseek(fd, 0, SEEK_END); 132 | if (FileLength < 0) { 133 | fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1], 134 | strerror(errno)); 135 | return 1; 136 | } 137 | 138 | BIOSOffset = (0x100000 - FileLength) & 0xFFFFF; 139 | 140 | BIOSImage = mmap(NULL, FileLength, PROT_READ, MAP_PRIVATE, fd, 0); 141 | if (BIOSImage < 0) { 142 | fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1], 143 | strerror(errno)); 144 | return 1; 145 | } 146 | 147 | printf("Using file \"%s\" (%ukB)\n", argv[1], FileLength >> 10); 148 | 149 | for (i = 0; BIOSIdentification[i].Handler; i++) { 150 | len = strlen(BIOSIdentification[i].String1); 151 | tmp = 152 | memmem(BIOSImage, FileLength - len, 153 | BIOSIdentification[i].String1, len); 154 | if (!tmp) 155 | continue; 156 | Offset1 = tmp - BIOSImage; 157 | 158 | len = strlen(BIOSIdentification[i].String2); 159 | tmp = 160 | memmem(BIOSImage, FileLength - len, 161 | BIOSIdentification[i].String2, len); 162 | if (!tmp) 163 | continue; 164 | Offset2 = tmp - BIOSImage; 165 | 166 | if (BIOSIdentification[i].Handler 167 | (BIOSImage, FileLength, BIOSOffset, Offset1, Offset2)) 168 | return 0; 169 | else 170 | return 1; 171 | } 172 | 173 | fprintf(stderr, "Error: Unable to detect BIOS Image type.\n"); 174 | return 1; 175 | } 176 | -------------------------------------------------------------------------------- /src/bios_extract.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #ifndef BIOS_EXTRACT_H 20 | #define BIOS_EXTRACT_H 21 | 22 | #define Bool int 23 | #define FALSE 0 24 | #define TRUE 1 25 | 26 | #if !defined(le32toh) || !defined(le16toh) 27 | #if BYTE_ORDER == LITTLE_ENDIAN 28 | #define le32toh(x) (x) 29 | #define le16toh(x) (x) 30 | #else 31 | #include 32 | #define le32toh(x) bswap_32(x) 33 | #define le16toh(x) bswap_16(x) 34 | #endif 35 | #endif 36 | 37 | /* bios_extract.c */ 38 | unsigned char *MMapOutputFile(char *filename, int size); 39 | 40 | /* ami.c */ 41 | Bool AMI95Extract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, 42 | uint32_t Offset1, uint32_t Offset2); 43 | 44 | /* phoenix.c */ 45 | Bool PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, 46 | uint32_t Offset1, uint32_t Offset2); 47 | 48 | /* award.c */ 49 | Bool AwardExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, 50 | uint32_t Offset1, uint32_t Offset2); 51 | 52 | #endif /* BIOS_EXTRACT_H */ 53 | -------------------------------------------------------------------------------- /src/compat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Decompression utility for AMI BIOSes. 3 | * 4 | * Copyright (C) 2009-2010 coresystems GmbH 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; see the file COPYING. If not, write to 18 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __APPLE__ 25 | void *memmem(const void *haystack, size_t haystacklen, const void *needle, 26 | size_t needlelen) 27 | { 28 | char *searchpointer = (char *)haystack; 29 | char *patternpointer = (char *)needle; 30 | char *endofsearch = searchpointer + haystacklen - needlelen; 31 | 32 | if (!(haystack && needle && haystacklen && needlelen)) 33 | return NULL; 34 | 35 | while (searchpointer <= endofsearch) { 36 | if (*searchpointer == *patternpointer) 37 | if (memcmp(searchpointer, patternpointer, needlelen) == 38 | 0) 39 | return searchpointer; 40 | searchpointer++; 41 | } 42 | 43 | return NULL; 44 | } 45 | 46 | size_t strnlen(const char *s, size_t maxlen) 47 | { 48 | const char *end = memchr(s, '\0', maxlen); 49 | return end ? (size_t) (end - s) : maxlen; 50 | } 51 | 52 | char *strndup(const char *s, size_t n) 53 | { 54 | size_t len = strnlen(s, n); 55 | char *new = malloc(len + 1); 56 | 57 | if (new == NULL) 58 | return NULL; 59 | 60 | new[len] = '\0'; 61 | return memcpy(new, s, len); 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /src/compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Decompression utility for AMI BIOSes. 3 | * 4 | * Copyright (C) 2009-2010 coresystems GmbH 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; see the file COPYING. If not, write to 18 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #ifdef __APPLE__ 22 | void *memmem(const void *haystack, size_t haystacklen, const void *needle, 23 | size_t needlelen); 24 | size_t strnlen(const char *s, size_t maxlen); 25 | char *strndup(const char *s, size_t n); 26 | #endif 27 | 28 | // "endian.h" does not exist on (at least) these platforms: 29 | // NetBSD, OSF/Tru64, HP-UX 10, Solaris, A/UX, Ultrix and 30 | // AIX. It exists on FreeBSD, Linux and Irix. 31 | #ifdef __linux__ 32 | #include 33 | #include 34 | #elif __FreeBSD__ 35 | #include 36 | #include 37 | #endif 38 | 39 | #if !defined(le32toh) || !defined(le16toh) 40 | #if BYTE_ORDER == LITTLE_ENDIAN 41 | #define le32toh(x) (x) 42 | #define le16toh(x) (x) 43 | #else 44 | #include 45 | #define le32toh(x) bswap_32(x) 46 | #define le16toh(x) bswap_16(x) 47 | #endif 48 | #endif 49 | -------------------------------------------------------------------------------- /src/lh5_extract.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a severely cut down and cleaned up version of lha. 3 | * 4 | * All changes compared to lha-svn894 are: 5 | * 6 | * Copyright 2009 Luc Verhaegen 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2, or (at your option) 11 | * any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; see the file COPYING. If not, write to 20 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 21 | */ 22 | /* 23 | * LHA has a terrible history... It dates back to 1988, has had many different 24 | * authors and has been mostly Public Domain Software. 25 | * 26 | * Since 1999, Koji Arai has been doing most of 27 | * the work at http://sourceforge.jp/projects/lha/. 28 | */ 29 | 30 | #define _GNU_SOURCE 1 31 | 32 | #include 33 | #include 34 | #include 35 | #include "compat.h" 36 | #include "lh5_extract.h" 37 | 38 | /* 39 | * LHA header parsing. 40 | */ 41 | static int calc_sum(unsigned char *p, int len) 42 | { 43 | int sum = 0; 44 | 45 | while (len--) 46 | sum += *p++; 47 | 48 | return sum & 0xff; 49 | } 50 | 51 | /* 52 | * level 1 header 53 | * 54 | * 55 | * offset size field name 56 | * ----------------------------------- 57 | * 0 1 header size [*1] 58 | * 1 1 header sum 59 | * ------------------------------------- 60 | * 2 5 method ID ^ 61 | * 7 4 skip size [*2] | 62 | * 11 4 original size | 63 | * 15 2 time | 64 | * 17 2 date | 65 | * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25) 66 | * 20 1 level (0x01 fixed) | 67 | * 21 1 name length | 68 | * 22 X filename | 69 | * X+ 22 2 file crc (CRC-16) | 70 | * X+ 24 1 OS ID | 71 | * X +25 Y ??? | 72 | * X+Y+25 2 next-header size v 73 | * ------------------------------------------------- 74 | * X+Y+27 Z ext-header ^ 75 | * : | 76 | * ----------------------------------- | [*2] skip size 77 | * X+Y+Z+27 data | 78 | * : v 79 | * ------------------------------------------------- 80 | * 81 | */ 82 | unsigned int 83 | LH5HeaderParse(unsigned char *Buffer, int BufferSize, 84 | unsigned int *original_size, unsigned int *packed_size, 85 | char **name, unsigned short *crc) 86 | { 87 | unsigned int offset; 88 | unsigned char header_size, checksum, name_length; 89 | 90 | if (BufferSize < 27) { 91 | fprintf(stderr, 92 | "Error: Packed Buffer is too small to contain an lha header.\n"); 93 | return 0; 94 | } 95 | 96 | /* check attribute */ 97 | if (Buffer[19] != 0x20) { 98 | fprintf(stderr, "Error: Invalid lha header attribute byte.\n"); 99 | return 0; 100 | } 101 | 102 | /* check method */ 103 | if (memcmp(Buffer + 2, "-lh5-", 5) != 0) { 104 | fprintf(stderr, "Error: Compression method is not LZHUFF5.\n"); 105 | return 0; 106 | } 107 | 108 | /* check header level */ 109 | if (Buffer[20] != 1) { 110 | fprintf(stderr, "Error: Header level %d is not supported\n", 111 | Buffer[20]); 112 | return 0; 113 | } 114 | 115 | /* read in the full header */ 116 | header_size = Buffer[0]; 117 | if (BufferSize < (header_size + 2)) { 118 | fprintf(stderr, 119 | "Error: Packed Buffer is too small to contain the full header.\n"); 120 | return 0; 121 | } 122 | 123 | /* verify checksum */ 124 | checksum = Buffer[1]; 125 | if (calc_sum(Buffer + 2, header_size) != checksum) { 126 | fprintf(stderr, "Error: Invalid lha header checksum.\n"); 127 | return 0; 128 | } 129 | 130 | *packed_size = le32toh(*(unsigned int *)(Buffer + 7)); 131 | *original_size = le32toh(*(unsigned int *)(Buffer + 11)); 132 | 133 | name_length = Buffer[21]; 134 | *name = strndup((char *)Buffer + 22, name_length); 135 | 136 | *crc = le16toh(*(unsigned short *)(Buffer + 22 + name_length)); 137 | 138 | offset = header_size + 2; 139 | /* Skip extended headers */ 140 | while (1) { 141 | unsigned short extend_size = 142 | le16toh(*(unsigned short *)(Buffer + offset - 2)); 143 | 144 | if (!extend_size) 145 | break; 146 | 147 | *packed_size -= extend_size; 148 | offset += extend_size; 149 | 150 | if (BufferSize < offset) { 151 | fprintf(stderr, 152 | "Error: Buffer to small to contain extended header.\n"); 153 | return 0; 154 | } 155 | } 156 | 157 | return offset; 158 | } 159 | 160 | /* 161 | * CRC Calculation. 162 | */ 163 | #define CRCPOLY 0xA001 /* CRC-16 (x^16+x^15+x^2+1) */ 164 | 165 | unsigned short CRC16Calculate(unsigned char *Buffer, int BufferSize) 166 | { 167 | unsigned short CRCTable[0x100]; 168 | unsigned short crc; 169 | int i; 170 | 171 | /* First, initialise our CRCTable */ 172 | for (i = 0; i < 0x100; i++) { 173 | unsigned short r = i; 174 | unsigned int j; 175 | 176 | for (j = 0; j < 8; j++) { 177 | if (r & 1) 178 | r = (r >> 1) ^ CRCPOLY; 179 | else 180 | r >>= 1; 181 | } 182 | CRCTable[i] = r; 183 | } 184 | 185 | /* now go over the entire Buffer */ 186 | crc = 0; 187 | for (i = 0; i < BufferSize; i++) 188 | crc = CRCTable[(crc ^ Buffer[i]) & 0xFF] ^ (crc >> 8); 189 | 190 | return crc; 191 | } 192 | 193 | /* 194 | * Bit handling code. 195 | */ 196 | static unsigned char *CompressedBuffer; 197 | static int CompressedSize; 198 | static int CompressedOffset; 199 | 200 | static unsigned short bitbuf; 201 | static unsigned char subbitbuf, bitcount; 202 | 203 | static void BitBufInit(unsigned char *Buffer, int BufferSize) 204 | { 205 | CompressedBuffer = Buffer; 206 | CompressedOffset = 0; 207 | CompressedSize = BufferSize; 208 | 209 | bitbuf = 0; 210 | subbitbuf = 0; 211 | bitcount = 0; 212 | } 213 | 214 | static void fillbuf(unsigned char n) 215 | { /* Shift bitbuf n bits left, read n bits */ 216 | while (n > bitcount) { 217 | n -= bitcount; 218 | bitbuf = (bitbuf << bitcount) + (subbitbuf >> (8 - bitcount)); 219 | 220 | if (CompressedOffset < CompressedSize) { 221 | subbitbuf = CompressedBuffer[CompressedOffset]; 222 | CompressedOffset++; 223 | } else 224 | subbitbuf = 0; 225 | 226 | bitcount = 8; 227 | } 228 | bitcount -= n; 229 | bitbuf = (bitbuf << n) + (subbitbuf >> (8 - n)); 230 | subbitbuf <<= n; 231 | } 232 | 233 | static unsigned short getbits(unsigned char n) 234 | { 235 | unsigned short x; 236 | 237 | x = bitbuf >> (16 - n); 238 | fillbuf(n); 239 | 240 | return x; 241 | } 242 | 243 | static unsigned short peekbits(unsigned char n) 244 | { 245 | unsigned short x; 246 | 247 | x = bitbuf >> (16 - n); 248 | 249 | return x; 250 | } 251 | 252 | /* 253 | * 254 | * LHA extraction. 255 | * 256 | */ 257 | #define MIN(a,b) ((a) <= (b) ? (a) : (b)) 258 | 259 | #define LZHUFF5_DICBIT 13 /* 2^13 = 8KB sliding dictionary */ 260 | #define MAXMATCH 256 /* formerly F (not more than 255 + 1) */ 261 | #define THRESHOLD 3 /* choose optimal value */ 262 | #define NP (LZHUFF5_DICBIT + 1) 263 | #define NT (16 + 3) /* USHORT + THRESHOLD */ 264 | #define NC (255 + MAXMATCH + 2 - THRESHOLD) 265 | 266 | #define PBIT 4 /* smallest integer such that (1 << PBIT) > * NP */ 267 | #define TBIT 5 /* smallest integer such that (1 << TBIT) > * NT */ 268 | #define CBIT 9 /* smallest integer such that (1 << CBIT) > * NC */ 269 | 270 | /* #if NT > NP #define NPT NT #else #define NPT NP #endif */ 271 | #define NPT 0x80 272 | 273 | static unsigned short left[2 * NC - 1], right[2 * NC - 1]; 274 | 275 | static unsigned short c_table[4096]; /* decode */ 276 | static unsigned short pt_table[256]; /* decode */ 277 | 278 | static unsigned char c_len[NC]; 279 | static unsigned char pt_len[NPT]; 280 | 281 | static int 282 | make_table(short nchar, unsigned char bitlen[], short tablebits, 283 | unsigned short table[]) 284 | { 285 | unsigned short count[17]; /* count of bitlen */ 286 | unsigned short weight[17]; /* 0x10000ul >> bitlen */ 287 | unsigned short start[17]; /* first code of bitlen */ 288 | unsigned short total; 289 | unsigned int i, l; 290 | int j, k, m, n, avail; 291 | unsigned short *p; 292 | 293 | avail = nchar; 294 | 295 | /* initialize */ 296 | for (i = 1; i <= 16; i++) { 297 | count[i] = 0; 298 | weight[i] = 1 << (16 - i); 299 | } 300 | 301 | /* count */ 302 | for (i = 0; i < nchar; i++) { 303 | if (bitlen[i] > 16) { 304 | /* CVE-2006-4335 */ 305 | fprintf(stderr, "Error: Bad table (case a)\n"); 306 | return -1; 307 | } else 308 | count[bitlen[i]]++; 309 | } 310 | 311 | /* calculate first code */ 312 | total = 0; 313 | for (i = 1; i <= 16; i++) { 314 | start[i] = total; 315 | total += weight[i] * count[i]; 316 | } 317 | if (((total & 0xffff) != 0) || (tablebits > 16)) { /* 16 for weight below */ 318 | fprintf(stderr, "Error: make_table(): Bad table (case b)\n"); 319 | return -1; 320 | } 321 | 322 | /* shift data for make table. */ 323 | m = 16 - tablebits; 324 | for (i = 1; i <= tablebits; i++) { 325 | start[i] >>= m; 326 | weight[i] >>= m; 327 | } 328 | 329 | /* initialize */ 330 | j = start[tablebits + 1] >> m; 331 | k = MIN(1 << tablebits, 4096); 332 | if (j != 0) 333 | for (i = j; i < k; i++) 334 | table[i] = 0; 335 | 336 | /* create table and tree */ 337 | for (j = 0; j < nchar; j++) { 338 | k = bitlen[j]; 339 | if (k == 0) 340 | continue; 341 | l = start[k] + weight[k]; 342 | if (k <= tablebits) { 343 | /* code in table */ 344 | l = MIN(l, 4096); 345 | for (i = start[k]; i < l; i++) 346 | table[i] = j; 347 | } else { 348 | /* code not in table */ 349 | i = start[k]; 350 | if ((i >> m) > 4096) { 351 | /* CVE-2006-4337 */ 352 | fprintf(stderr, "Error: Bad table (case c)"); 353 | exit(1); 354 | } 355 | p = &table[i >> m]; 356 | i <<= tablebits; 357 | n = k - tablebits; 358 | /* make tree (n length) */ 359 | while (--n >= 0) { 360 | if (*p == 0) { 361 | right[avail] = left[avail] = 0; 362 | *p = avail++; 363 | } 364 | if (i & 0x8000) 365 | p = &right[*p]; 366 | else 367 | p = &left[*p]; 368 | i <<= 1; 369 | } 370 | *p = j; 371 | } 372 | start[k] = l; 373 | } 374 | return 0; 375 | } 376 | 377 | static int read_pt_len(short nn, short nbit, short i_special) 378 | { 379 | int i, c, n; 380 | 381 | n = getbits(nbit); 382 | if (n == 0) { 383 | c = getbits(nbit); 384 | for (i = 0; i < nn; i++) 385 | pt_len[i] = 0; 386 | for (i = 0; i < 256; i++) 387 | pt_table[i] = c; 388 | } else { 389 | i = 0; 390 | while (i < MIN(n, NPT)) { 391 | c = peekbits(3); 392 | if (c != 7) 393 | fillbuf(3); 394 | else { 395 | unsigned short mask = 1 << (16 - 4); 396 | while (mask & bitbuf) { 397 | mask >>= 1; 398 | c++; 399 | } 400 | fillbuf(c - 3); 401 | } 402 | 403 | pt_len[i++] = c; 404 | if (i == i_special) { 405 | c = getbits(2); 406 | while (--c >= 0 && i < NPT) 407 | pt_len[i++] = 0; 408 | } 409 | } 410 | while (i < nn) 411 | pt_len[i++] = 0; 412 | 413 | if (make_table(nn, pt_len, 8, pt_table) == -1) 414 | return -1; 415 | } 416 | return 0; 417 | } 418 | 419 | static int read_c_len(void) 420 | { 421 | short i, c, n; 422 | 423 | n = getbits(CBIT); 424 | if (n == 0) { 425 | c = getbits(CBIT); 426 | for (i = 0; i < NC; i++) 427 | c_len[i] = 0; 428 | for (i = 0; i < 4096; i++) 429 | c_table[i] = c; 430 | } else { 431 | i = 0; 432 | while (i < MIN(n, NC)) { 433 | c = pt_table[peekbits(8)]; 434 | if (c >= NT) { 435 | unsigned short mask = 1 << (16 - 9); 436 | do { 437 | if (bitbuf & mask) 438 | c = right[c]; 439 | else 440 | c = left[c]; 441 | mask >>= 1; 442 | } while (c >= NT && (mask || c != left[c])); /* CVE-2006-4338 */ 443 | } 444 | fillbuf(pt_len[c]); 445 | if (c <= 2) { 446 | if (c == 0) 447 | c = 1; 448 | else if (c == 1) 449 | c = getbits(4) + 3; 450 | else 451 | c = getbits(CBIT) + 20; 452 | while (--c >= 0) 453 | c_len[i++] = 0; 454 | } else 455 | c_len[i++] = c - 2; 456 | } 457 | while (i < NC) 458 | c_len[i++] = 0; 459 | 460 | if (make_table(NC, c_len, 12, c_table) == -1) 461 | return -1; 462 | } 463 | return 0; 464 | } 465 | 466 | static unsigned short decode_c_st1(void) 467 | { 468 | unsigned short j, mask; 469 | 470 | j = c_table[peekbits(12)]; 471 | if (j < NC) 472 | fillbuf(c_len[j]); 473 | else { 474 | fillbuf(12); 475 | mask = 1 << (16 - 1); 476 | do { 477 | if (bitbuf & mask) 478 | j = right[j]; 479 | else 480 | j = left[j]; 481 | mask >>= 1; 482 | } while (j >= NC && (mask || j != left[j])); /* CVE-2006-4338 */ 483 | fillbuf(c_len[j] - 12); 484 | } 485 | return j; 486 | } 487 | 488 | static unsigned short decode_p_st1(void) 489 | { 490 | unsigned short j, mask; 491 | 492 | j = pt_table[peekbits(8)]; 493 | if (j < NP) 494 | fillbuf(pt_len[j]); 495 | else { 496 | fillbuf(8); 497 | mask = 1 << (16 - 1); 498 | do { 499 | if (bitbuf & mask) 500 | j = right[j]; 501 | else 502 | j = left[j]; 503 | mask >>= 1; 504 | } while (j >= NP && (mask || j != left[j])); /* CVE-2006-4338 */ 505 | fillbuf(pt_len[j] - 8); 506 | } 507 | if (j != 0) 508 | j = (1 << (j - 1)) + getbits(j - 1); 509 | return j; 510 | } 511 | 512 | int 513 | LH5Decode(unsigned char *PackedBuffer, int PackedBufferSize, 514 | unsigned char *OutputBuffer, int OutputBufferSize) 515 | { 516 | unsigned short blocksize = 0; 517 | unsigned int i, c; 518 | int n = 0; 519 | 520 | BitBufInit(PackedBuffer, PackedBufferSize); 521 | fillbuf(2 * 8); 522 | 523 | while (n < OutputBufferSize) { 524 | if (blocksize == 0) { 525 | blocksize = getbits(16); 526 | 527 | if (read_pt_len(NT, TBIT, 3) == -1) 528 | return -1; 529 | if (read_c_len() == -1) 530 | return -1; 531 | if (read_pt_len(NP, PBIT, -1) == -1) 532 | return -1; 533 | } 534 | blocksize--; 535 | c = decode_c_st1(); 536 | 537 | if (c < 256) 538 | OutputBuffer[n++] = c; 539 | else { 540 | int length = c - 256 + THRESHOLD; 541 | int offset = 1 + decode_p_st1(); 542 | 543 | if (offset > n) 544 | return -1; 545 | 546 | for (i = 0; i < length; i++) { 547 | OutputBuffer[n] = OutputBuffer[n - offset]; 548 | n++; 549 | } 550 | } 551 | } 552 | return 0; 553 | } 554 | -------------------------------------------------------------------------------- /src/lh5_extract.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #ifndef LH5_EXTRACT_H 20 | #define LH5_EXTRACT_H 21 | 22 | unsigned int LH5HeaderParse(unsigned char *Buffer, int BufferSize, 23 | unsigned int *original_size, 24 | unsigned int *packed_size, 25 | char **name, unsigned short *crc); 26 | 27 | unsigned short CRC16Calculate(unsigned char *Buffer, int BufferSize); 28 | 29 | int LH5Decode(unsigned char *PackedBuffer, int PackedBufferSize, 30 | unsigned char *OutputBuffer, int OutputBufferSize); 31 | 32 | #endif /* LH5_EXTRACT_H */ 33 | -------------------------------------------------------------------------------- /src/lh5_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* 20 | * Test/Example code for LH5 extraction. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "lh5_extract.h" 32 | 33 | int main(int argc, char *argv[]) 34 | { 35 | char *filename; 36 | unsigned short header_crc; 37 | unsigned int header_size, original_size, packed_size; 38 | int infd, outfd; 39 | int LHABufferSize = 0; 40 | unsigned char *LHABuffer, *OutBuffer; 41 | 42 | if (argc != 2) { 43 | fprintf(stderr, "Error: archive file not specified\n"); 44 | return 1; 45 | } 46 | 47 | /* open archive file */ 48 | infd = open(argv[1], O_RDONLY); 49 | if (infd == -1) { 50 | fprintf(stderr, "Error: Failed to open \"%s\": %s\n", argv[1], 51 | strerror(errno)); 52 | return 1; 53 | } 54 | 55 | LHABufferSize = lseek(infd, 0, SEEK_END); 56 | if (LHABufferSize < 0) { 57 | fprintf(stderr, "Error: Failed to lseek \"%s\": %s\n", argv[1], 58 | strerror(errno)); 59 | return 1; 60 | } 61 | 62 | LHABuffer = mmap(NULL, LHABufferSize, PROT_READ, MAP_PRIVATE, infd, 0); 63 | if (LHABuffer == ((void *)-1)) { 64 | fprintf(stderr, "Error: Failed to mmap %s: %s\n", argv[1], 65 | strerror(errno)); 66 | return 1; 67 | } 68 | 69 | header_size = LH5HeaderParse(LHABuffer, LHABufferSize, &original_size, 70 | &packed_size, &filename, &header_crc); 71 | if (!header_size) 72 | return 1; 73 | 74 | if ((header_size + packed_size) < LHABufferSize) { 75 | fprintf(stderr, "Error: LHA archive is bigger than \"%s\".\n", 76 | argv[1]); 77 | return 1; 78 | } 79 | 80 | outfd = open(filename, O_RDWR | O_TRUNC | O_CREAT, S_IRWXU); 81 | if (outfd == -1) { 82 | fprintf(stderr, "Error: Failed to open \"%s\": %s\n", filename, 83 | strerror(errno)); 84 | return 1; 85 | } 86 | 87 | /* grow file */ 88 | if (lseek(outfd, original_size - 1, SEEK_SET) == -1) { 89 | fprintf(stderr, "Error: Failed to grow \"%s\": %s\n", filename, 90 | strerror(errno)); 91 | return 1; 92 | } 93 | 94 | if (write(outfd, "", 1) != 1) { 95 | fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", 96 | filename, strerror(errno)); 97 | return 1; 98 | } 99 | 100 | OutBuffer = 101 | mmap(NULL, original_size, PROT_READ | PROT_WRITE, MAP_SHARED, outfd, 102 | 0); 103 | if (OutBuffer == ((void *)-1)) { 104 | fprintf(stderr, "Error: Failed to mmap %s: %s\n", filename, 105 | strerror(errno)); 106 | return 1; 107 | } 108 | 109 | LH5Decode(LHABuffer + header_size, packed_size, OutBuffer, 110 | original_size); 111 | 112 | if (CRC16Calculate(OutBuffer, original_size) != header_crc) { 113 | fprintf(stderr, "Warning: invalid CRC on \"%s\"\n", filename); 114 | return 1; 115 | } 116 | 117 | if (munmap(OutBuffer, original_size)) 118 | fprintf(stderr, "Warning: Failed to munmap \"%s\": %s\n", 119 | filename, strerror(errno)); 120 | 121 | if (close(outfd)) 122 | fprintf(stderr, "Warning: Failed to close \"%s\": %s\n", 123 | filename, strerror(errno)); 124 | 125 | free(filename); 126 | 127 | /* get rid of our input file */ 128 | if (munmap(LHABuffer, LHABufferSize)) 129 | fprintf(stderr, "Warning: Failed to munmap \"%s\": %s\n", 130 | argv[1], strerror(errno)); 131 | 132 | if (close(infd)) 133 | fprintf(stderr, "Warning: Failed to close \"%s\": %s\n", 134 | argv[1], strerror(errno)); 135 | 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /src/lzss_extract.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "lzss_extract.h" 26 | 27 | static inline int 28 | LZSSBufferWrite(int fd, unsigned char *Buffer, int *BufferCount, 29 | unsigned char value) 30 | { 31 | Buffer[*BufferCount] = value; 32 | *BufferCount += 1; 33 | 34 | if (*BufferCount == 0x1000) { 35 | if (write(fd, Buffer, 0x1000) != 0x1000) { 36 | fprintf(stderr, "Error writing to output file: %s", 37 | strerror(errno)); 38 | return 1; 39 | } 40 | *BufferCount = 0; 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | int LZSSExtract(unsigned char *Input, int InputSize, int fd) 47 | { 48 | unsigned char Buffer[0x1000]; 49 | unsigned short BitBuffer = 0; 50 | int i = 0, k, BitCount = 8, BufferCount = 0; 51 | 52 | while (i < InputSize) { 53 | 54 | if (BitCount == 8) { 55 | BitBuffer = Input[i]; 56 | BitCount = -1; 57 | } else if ((BitBuffer >> BitCount) & 0x01) { 58 | if (LZSSBufferWrite(fd, Buffer, &BufferCount, Input[i])) 59 | return 1; 60 | } else if ((i + 1) < InputSize) { 61 | int offset = 62 | ((Input[i] | ((Input[i + 1] & 0xF0) << 4)) - 63 | 0xFEE) & 0xFFF; 64 | int length = (Input[i + 1] & 0x0F) + 3; 65 | 66 | for (k = 0; k < length; k++) { 67 | if (LZSSBufferWrite 68 | (fd, Buffer, &BufferCount, 69 | Buffer[(offset + k) & 0xFFF])) 70 | return 1; 71 | } 72 | i++; 73 | } else { 74 | fprintf(stderr, 75 | "Error: requesting data beyond end of input file.\n"); 76 | return 1; 77 | } 78 | 79 | i++; 80 | BitCount++; 81 | } 82 | 83 | if (BufferCount) { 84 | if (write(fd, Buffer, BufferCount) != BufferCount) { 85 | fprintf(stderr, "Error writing to output file: %s", 86 | strerror(errno)); 87 | return 1; 88 | } 89 | } 90 | 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /src/lzss_extract.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2, or (at your option) 7 | * any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; see the file COPYING. If not, write to 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #ifndef LZSS_EXTRACT_H 20 | #define LZSS_EXTRACT_H 21 | 22 | int LZSSExtract(unsigned char *Input, int InputSize, int fd); 23 | 24 | #endif /* LZSS_EXTRACT_H */ 25 | -------------------------------------------------------------------------------- /src/phoenix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Luc Verhaegen 3 | * Copyright 2000-2003 Anthony Borisow 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2, or (at your option) 8 | * any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; see the file COPYING. If not, write to 17 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "compat.h" 30 | #include "bios_extract.h" 31 | #include "lh5_extract.h" 32 | 33 | struct bcpHeader { 34 | char signature[6]; 35 | uint8_t major_revision; 36 | uint8_t minor_revision; 37 | uint16_t length; 38 | }; 39 | 40 | /* Our own structure just to store important parameters */ 41 | struct Phoenix { 42 | uint8_t version; 43 | uint8_t type; 44 | uint8_t compression; 45 | }; 46 | 47 | static struct Phoenix phx = { 0, 0, 0 }; 48 | 49 | #define COMP_LZSS 0 50 | #define COMP_LZARI 1 51 | #define COMP_LZHUF 2 52 | #define COMP_LZINT 3 53 | 54 | struct bcpCompress { 55 | struct bcpHeader head; 56 | uint8_t flags; 57 | uint8_t alg; 58 | uint16_t unc_start_offset; 59 | uint32_t size_comp_data; 60 | uint16_t bcpiRamBiosStart; 61 | uint16_t bcpiWorkAreaStart; 62 | uint16_t bcpiLowMemStart; 63 | uint16_t bcpiLowMemSize; 64 | uint8_t commonCharacterLZSS; 65 | uint16_t oldRamBiosStart; 66 | uint16_t oldSetupScanStart; 67 | uint16_t oldSetupScanSize; 68 | }; 69 | 70 | #define GUID_FFVMODULE "FED91FBA-D37B-4EEA-8729-2EF29FB37A78" 71 | #define GUID_ESCD "FD21E8FD-2525-4A95-BB90-47EC5763FF9E" 72 | #define GUID_RAWCODE "F6AE0F63-5F8C-4316-A2EA-76B9AF762756" 73 | 74 | /* -------------- Phoenix module file type parsing -------------- */ 75 | 76 | /* See http://wiki.phoenix.com/wiki/index.php/EFI_FV_FILETYPE for 77 | * additional information */ 78 | 79 | struct PhoenixFFVFileType { 80 | uint8_t Id; 81 | char *Name; 82 | }; 83 | 84 | static struct PhoenixFFVFileType 85 | PhoenixFFVFileTypes[] = { 86 | {0x00, "ALL"}, 87 | {0x01, "BIN"}, 88 | {0x02, "SECTION"}, 89 | {0x03, "CEIMAIN"}, 90 | {0x04, "PEIMAIN"}, 91 | {0x05, "DXEMAIN"}, 92 | {0x06, "PEI"}, 93 | {0x07, "DXE"}, 94 | {0x08, "COMBINED_PEIM_DRIVER"}, 95 | {0x09, "APP"}, 96 | {0x0B, "FFV"}, 97 | {0xC2, "CEI"}, 98 | {0xC3, "XIP"}, 99 | {0xC4, "BB"}, 100 | {0xD0, "SDXE"}, 101 | {0xD1, "DXESDXE"}, 102 | {0xF0, "GAP"}, 103 | {0, NULL}, 104 | }; 105 | 106 | static char *get_file_type(uint8_t id) 107 | { 108 | short i = 0; 109 | while (PhoenixFFVFileTypes[i].Name != NULL) { 110 | if (PhoenixFFVFileTypes[i].Id == id) 111 | return PhoenixFFVFileTypes[i].Name; 112 | i++; 113 | } 114 | return "UNKNOWN"; 115 | } 116 | 117 | /* -------------- Phoenix section file type parsing -------------- */ 118 | 119 | /* See http://wiki.phoenix.com/wiki/index.php/EFI_SECTION_TYPE for 120 | * additional information */ 121 | 122 | struct PhoenixFFVSectionType { 123 | uint8_t Id; 124 | char *Name; 125 | }; 126 | 127 | static struct PhoenixFFVSectionType PhoenixFFVSectionTypes[] = { 128 | {0x01, "COMPRESSION"}, 129 | {0x02, "GUID_DEFINED"}, 130 | {0x10, "PE32"}, 131 | {0x11, "PIC"}, 132 | {0x12, "TE"}, 133 | {0x13, "DXE_DEPEX"}, 134 | {0x14, "VERSION"}, 135 | {0x15, "USER_INTERFACE"}, 136 | {0x16, "COMPATIBILITY16"}, 137 | {0x17, "FIRMWARE_VOLUME_IMAGE"}, 138 | {0x18, "FREEFORM_SUBTYPE_GUID"}, 139 | {0x19, "BIN"}, 140 | {0x1A, "PE64"}, 141 | {0x1B, "PEI_DEPEX"}, 142 | {0xC0, "SOURCECODE"}, 143 | {0xC1, "FFV"}, 144 | {0xC2, "RE32"}, 145 | {0xC3, "XIP16"}, 146 | {0xC4, "XIP32"}, 147 | {0xC5, "XIP64"}, 148 | {0xC6, "PLACE16"}, 149 | {0xC7, "PLACE32"}, 150 | {0xC8, "PLACE64"}, 151 | {0xCF, "PCI_DEVICE"}, 152 | {0xD0, "PDB"}, 153 | {0, NULL}, 154 | }; 155 | 156 | static char *get_section_type(uint8_t id) 157 | { 158 | short i = 0; 159 | while (PhoenixFFVSectionTypes[i].Name != NULL) { 160 | if (PhoenixFFVSectionTypes[i].Id == id) 161 | return PhoenixFFVSectionTypes[i].Name; 162 | i++; 163 | } 164 | return "UNKNOWN"; 165 | } 166 | 167 | /* -------------- Phoenix module name parsing -------------- */ 168 | 169 | struct PhoenixModuleName { 170 | char Id; 171 | char *Name; 172 | }; 173 | 174 | static struct PhoenixModuleName PhoenixModuleNames[] = { 175 | {'A', "acpi"}, 176 | {'B', "bioscode"}, 177 | {'C', "update"}, 178 | {'D', "display"}, 179 | {'E', "setup"}, 180 | {'F', "font"}, 181 | {'G', "decompcode"}, 182 | {'I', "bootblock"}, 183 | {'L', "logo"}, 184 | {'M', "miser"}, 185 | {'N', "rompilotload"}, 186 | {'O', "network"}, 187 | {'P', "rompilotinit"}, 188 | {'R', "oprom"}, 189 | {'S', "strings"}, 190 | {'T', "template"}, 191 | {'U', "user"}, 192 | {'X', "romexec"}, 193 | {'W', "wav"}, 194 | {'H', "tcpa_H"}, /* TCPA (Trusted Computing), USBKCLIB? */ 195 | {'K', "tcpa_K"}, /* TCPA (Trusted Computing), "AUTH"? */ 196 | {'Q', "tcpa_Q"}, /* TCPA (Trusted Computing), "SROM"? */ 197 | {'<', "tcpa_<"}, 198 | {'*', "tcpa_*"}, 199 | {'?', "tcpa_?"}, 200 | {'$', "biosentry"}, 201 | {'J', "SmartCardPAS"}, 202 | }; 203 | 204 | struct PhoenixID { 205 | char Name[6]; 206 | uint16_t Flags; 207 | uint16_t Length; 208 | }; 209 | 210 | struct PhoenixFFVModule { 211 | uint8_t Signature; 212 | uint8_t Flags; 213 | uint16_t Checksum; /* Can be splitted to header and data checksums */ 214 | uint16_t LengthLo; 215 | uint8_t LengthHi; 216 | uint8_t FileType; 217 | char Name[16]; /* GUID name */ 218 | }; 219 | 220 | struct PhoenixFFVSectionHeader { 221 | uint16_t SizeLo; 222 | uint8_t SizeHi; 223 | uint8_t Type; 224 | }; 225 | 226 | struct PhoenixFFVCompressionHeader { 227 | uint16_t TotalLengthLo; 228 | uint8_t TotalLengthHi; 229 | uint8_t CompType; 230 | uint16_t PackedLenLo; 231 | uint8_t PackedLenHi; 232 | uint8_t Unk2; 233 | uint16_t RealLenLo; 234 | uint8_t RealLenHi; 235 | uint8_t Unk3; 236 | }; 237 | 238 | static char *PhoenixModuleNameGet(char Id) 239 | { 240 | int i; 241 | 242 | for (i = 0; PhoenixModuleNames[i].Name; i++) 243 | if (PhoenixModuleNames[i].Id == Id) 244 | return PhoenixModuleNames[i].Name; 245 | return NULL; 246 | } 247 | 248 | static void 249 | phx_write_file(unsigned char *BIOSImage, char *filename, short filetype, 250 | int offset, uint32_t length) 251 | { 252 | int fd; 253 | 254 | if (filename[0] == '\0') { 255 | sprintf(filename, "%s_0x%08x-0x%08x", get_file_type(filetype), 256 | offset, offset + length); 257 | } 258 | fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 259 | if (fd < 0) { 260 | fprintf(stderr, "Error: unable to open %s: %s\n\n", filename, 261 | strerror(errno)); 262 | return; 263 | } 264 | write(fd, BIOSImage + offset + 0x18, length - 0x18); 265 | close(fd); 266 | } 267 | 268 | /* ---------- Extraction code ---------- */ 269 | 270 | static int PhoenixModule(unsigned char *BIOSImage, int BIOSLength, int Offset) 271 | { 272 | struct PhoenixModule { 273 | uint32_t Previous; 274 | uint8_t Signature[3]; 275 | uint8_t Id; 276 | uint8_t Type; 277 | uint8_t HeadLen; 278 | uint8_t Compression; 279 | uint16_t Offset; 280 | uint16_t Segment; 281 | uint32_t ExpLen; 282 | uint32_t FragLength; 283 | uint32_t NextFrag; 284 | } *Module; 285 | 286 | char *filename, *ModuleName; 287 | unsigned char *Buffer; 288 | unsigned char *ModuleData; 289 | uint32_t Packed; 290 | int fd; 291 | 292 | Module = (struct PhoenixModule *)(BIOSImage + Offset); 293 | 294 | if (Module->Signature[0] || (Module->Signature[1] != 0x31) 295 | || (Module->Signature[2] != 0x31)) { 296 | fprintf(stderr, "Error: Invalid module signature at 0x%05X\n", 297 | Offset); 298 | return 0; 299 | } 300 | 301 | if ((Offset + Module->HeadLen + 4 + le32toh(Module->FragLength)) > 302 | BIOSLength) { 303 | fprintf(stderr, "Error: Module overruns buffer at 0x%05X\n", 304 | Offset); 305 | return le32toh(Module->Previous); 306 | } 307 | 308 | /* NextFrag is either the unpacked length again *or* the virtual address 309 | of the next fragment. As long as BIOSses stay below 256MB, this works */ 310 | if ((le32toh(Module->NextFrag) & 0xF0000000) == 0xF0000000) { 311 | struct PhoenixFragment { 312 | uint32_t NextFrag; 313 | uint8_t NextBank; 314 | uint32_t FragLength; 315 | } *Fragment; 316 | 317 | int FragOffset; 318 | uint32_t FragLength = le32toh(Module->FragLength); 319 | 320 | if (FragLength > le32toh(Module->ExpLen)) { 321 | fprintf(stderr, 322 | "Error: First fragment exceeds total size at %05X\n", 323 | Offset); 324 | return le32toh(Module->Previous); 325 | } 326 | 327 | /* This over-allocates, but the total compressed size is not available here */ 328 | ModuleData = malloc(le32toh(Module->ExpLen)); 329 | if (!ModuleData) { 330 | fprintf(stderr, 331 | "Error: Can't reassemble fragments, no memory for %d bytes\n", 332 | le32toh(Module->ExpLen)); 333 | return le32toh(Module->Previous); 334 | } 335 | 336 | memcpy(ModuleData, BIOSImage + Offset + Module->HeadLen, 337 | FragLength); 338 | 339 | Packed = FragLength; 340 | FragOffset = le32toh(Module->NextFrag) & (BIOSLength - 1); 341 | 342 | printf("extra fragments: "); 343 | while (FragOffset) { 344 | Fragment = 345 | (struct PhoenixFragment *)(BIOSImage + FragOffset); 346 | FragLength = le32toh(Fragment->FragLength); 347 | printf("(%05X, %d bytes) ", FragOffset, FragLength); 348 | 349 | if (Packed + FragLength > le32toh(Module->ExpLen)) { 350 | fprintf(stderr, 351 | "\nFragment too big at %05X for %05X\n", 352 | FragOffset, Offset); 353 | free(ModuleData); 354 | return le32toh(Module->Previous); 355 | } 356 | memcpy(ModuleData + Packed, BIOSImage + FragOffset + 9, 357 | FragLength); 358 | Packed += FragLength; 359 | FragOffset = 360 | le32toh(Fragment->NextFrag) & (BIOSLength - 1); 361 | } 362 | printf("\n"); 363 | 364 | } else { 365 | ModuleData = BIOSImage + Offset + Module->HeadLen; 366 | Packed = le32toh(Module->FragLength); 367 | } 368 | 369 | ModuleName = PhoenixModuleNameGet(Module->Type); 370 | if (ModuleName) { 371 | filename = malloc(strlen(ModuleName) + 7); 372 | sprintf(filename, "%s_%1d.rom", ModuleName, Module->Id); 373 | } else { 374 | filename = malloc(9); 375 | sprintf(filename, "%02X_%1d.rom", Module->Type, Module->Id); 376 | } 377 | 378 | fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 379 | if (fd < 0) { 380 | fprintf(stderr, "Error: unable to open %s: %s\n\n", filename, 381 | strerror(errno)); 382 | free(filename); 383 | if ((le32toh(Module->NextFrag) & 0xF0000000) == 0xF0000000) 384 | free(ModuleData); 385 | return le32toh(Module->Previous); 386 | } 387 | 388 | switch (Module->Compression) { 389 | case 5: /* LH5 */ 390 | printf("0x%05X (%6d bytes) -> %s\t(%d bytes)", 391 | Offset + Module->HeadLen + 4, Packed, filename, 392 | le32toh(Module->ExpLen)); 393 | Buffer = MMapOutputFile(filename, le32toh(Module->ExpLen)); 394 | if (!Buffer) 395 | break; 396 | 397 | /* The first 4 bytes of the LH5 packing method is just the total 398 | * expanded length; skip them */ 399 | LH5Decode(ModuleData + 4, Packed - 4, Buffer, 400 | le32toh(Module->ExpLen)); 401 | munmap(Buffer, le32toh(Module->ExpLen)); 402 | break; 403 | 404 | /* case 3 *//* LZSS */ 405 | case 0: /* not compressed at all */ 406 | printf("0x%05X (%6d bytes) -> %s", Offset + Module->HeadLen, 407 | Packed, filename); 408 | write(fd, ModuleData, Packed); 409 | break; 410 | 411 | default: 412 | fprintf(stderr, "Unsupported compression type for %s: %d\n", 413 | filename, Module->Compression); 414 | printf("0x%05X (%6d bytes) -> %s\t(%d bytes)", 415 | Offset + Module->HeadLen, Packed, filename, 416 | le32toh(Module->ExpLen)); 417 | write(fd, ModuleData, Packed); 418 | break; 419 | } 420 | 421 | close(fd); 422 | free(filename); 423 | 424 | if ((le32toh(Module->NextFrag) & 0xF0000000) == 0xF0000000) 425 | free(ModuleData); 426 | 427 | if (le16toh(Module->Offset) || le16toh(Module->Segment)) { 428 | if (!Module->Compression) 429 | printf("\t\t"); 430 | printf("\t [0x%04X:0x%04X]\n", le16toh(Module->Segment) << 12, 431 | le16toh(Module->Offset)); 432 | } else 433 | printf("\n"); 434 | 435 | return le32toh(Module->Previous); 436 | } 437 | 438 | static int 439 | PhoenixExtractFFV(unsigned char *BIOSImage, int BIOSLength, int Offset) 440 | { 441 | struct PhoenixFFVSectionHeader *SectionHeader; 442 | struct PhoenixFFVCompressionHeader *CompHeader; 443 | struct PhoenixFFVModule *Module; 444 | char Name[16], filename[24]; 445 | char *ModuleName; 446 | uint32_t Length, PackedLen, RealLen; 447 | unsigned char *RealData; 448 | 449 | Module = (struct PhoenixFFVModule *)(BIOSImage + Offset); 450 | 451 | if (Module->Signature != 0xF8) { 452 | /* ignore and move on to the next byte... */ 453 | return 1; 454 | } 455 | 456 | Length = ((le16toh(Module->LengthHi) << 16) | Module->LengthLo) - 1; 457 | if ((Offset + Length) >= BIOSLength) { 458 | fprintf(stderr, "Error: Module overruns buffer at 0x%05X\n", 459 | Offset); 460 | return 1; 461 | } 462 | 463 | /* TODO: Improve module name parsing */ 464 | if (Module->FileType == 0xF0) { 465 | strcpy(Name, "GAP"); 466 | filename[0] = '\0'; 467 | } else if ((uint8_t) Module->Name[8] != 0xFF) { 468 | strcpy(Name, "GUID?"); 469 | filename[0] = '\0'; 470 | } else { 471 | /* get rid of the pesky 0xFF in the middle of the name */ 472 | memcpy(Name, Module->Name, 8); 473 | memcpy(Name + 8, Module->Name + 9, 7); 474 | Name[15] = '\0'; 475 | 476 | if (Name[0] == '_' && strlen(Name) == 4) { 477 | ModuleName = PhoenixModuleNameGet(Name[1]); 478 | if (ModuleName) { 479 | snprintf(filename, sizeof(filename), 480 | "%s_%c%c.rom", ModuleName, Name[2], 481 | Name[3]); 482 | } else { 483 | snprintf(filename, sizeof(filename), "%s.rom", 484 | Name); 485 | } 486 | } else { 487 | strncpy(filename, Name, sizeof(filename)); 488 | } 489 | } 490 | 491 | printf("\t%-15s (%08X-%08X) %08X %02X %02X %s [%s]\n", 492 | Name, Offset, Offset + Length, Length, Module->Flags, 493 | Module->FileType, filename, get_file_type(Module->FileType)); 494 | 495 | switch (Module->FileType) { 496 | case 0xF0: 497 | break; 498 | 499 | /* ---------- SECTION file type ---------- */ 500 | case 0x02: 501 | SectionHeader = 502 | (struct PhoenixFFVSectionHeader *)(BIOSImage + Offset + 503 | 0x18); 504 | if (Name[1] == 'G' || !*filename) { 505 | break; 506 | } 507 | 508 | /* COMPRESSION section */ 509 | if (SectionHeader->Type == 0x01) { 510 | CompHeader = 511 | (struct PhoenixFFVCompressionHeader *)(BIOSImage + 512 | Offset + 513 | 0x18); 514 | /* some blocks have a (8 byte?) header we need to skip */ 515 | if (CompHeader->TotalLengthLo != Length - 0x18 516 | && CompHeader->Unk3) { 517 | /* FIXME more advanced parsing of sections */ 518 | CompHeader = 519 | (struct PhoenixFFVCompressionHeader *) 520 | ((unsigned char *)CompHeader + 521 | CompHeader->TotalLengthLo); 522 | } 523 | PackedLen = 524 | (CompHeader-> 525 | PackedLenHi << 16) | CompHeader->PackedLenLo; 526 | RealLen = 527 | (CompHeader-> 528 | RealLenHi << 16) | CompHeader->RealLenLo; 529 | //printf("CompHeader->Type = %d\n", CompHeader->CompType); 530 | 531 | if (CompHeader->CompType == 0) /* Not compressed at all */ 532 | break; 533 | 534 | if (!RealLen) /* FIXME temporary hack */ 535 | break; 536 | 537 | RealData = MMapOutputFile(filename, RealLen); 538 | if (!RealData) { 539 | fprintf(stderr, 540 | "Failed to mmap file for uncompressed data.\n"); 541 | break; 542 | } 543 | if ((phx.compression == COMP_LZHUF) 544 | || (phx.compression == COMP_LZINT)) { 545 | if (LH5Decode 546 | ((unsigned char *)CompHeader + 547 | sizeof(struct PhoenixFFVCompressionHeader), 548 | PackedLen, RealData, RealLen) == -1) { 549 | munmap(RealData, RealLen); 550 | fprintf(stderr, 551 | "Failed to uncompress section with LHA5.\n"); 552 | /* dump original section in this case */ 553 | phx_write_file(BIOSImage, filename, 554 | Module->FileType, Offset, 555 | Length); 556 | } else 557 | printf("COMPRESSED\n"); 558 | } else 559 | printf("Unsupported compression!\n"); 560 | munmap(RealData, RealLen); 561 | break; 562 | } 563 | printf("\t\tSECTION: %s\n", 564 | get_section_type(SectionHeader->Type)); 565 | phx_write_file(BIOSImage, filename, Module->FileType, Offset, 566 | Length); 567 | break; 568 | 569 | default: 570 | phx_write_file(BIOSImage, filename, Module->FileType, Offset, 571 | Length); 572 | break; 573 | } 574 | return Length; 575 | } 576 | 577 | /* Parse initial volumedir layout: 578 | * - 1 byte Type indicates either raw code or an FFV module 579 | * - 4 byte Base provides the offset into the image to find the specified volume 580 | * - 4 byte Length 581 | */ 582 | void 583 | PhoenixVolume1(unsigned char *BIOSImage, int BIOSLength, int Offset, int ModLen) 584 | { 585 | struct PhoenixVolumeDirEntry { 586 | uint8_t Type; 587 | uint32_t Base; 588 | uint32_t Length; 589 | } *Modules; 590 | 591 | char Name[16]; 592 | int fd, HoleNum = 0; 593 | uint8_t Type; 594 | uint32_t Base, Length, NumModules, ModNum; 595 | 596 | Modules = (struct PhoenixVolumeDirEntry *)(BIOSImage + Offset + 0x18); 597 | NumModules = (ModLen - 0x18) / sizeof(struct PhoenixVolumeDirEntry); 598 | 599 | printf("FFV modules: %u\n", NumModules); 600 | 601 | for (ModNum = 0; ModNum < NumModules; ModNum++) { 602 | Type = Modules[ModNum].Type; 603 | Base = Modules[ModNum].Base & (BIOSLength - 1); 604 | Length = Modules[ModNum].Length - 1; 605 | printf("[%2u]: (%08X-%08X) %02x\n", ModNum, Base, Base + Length, 606 | Type); 607 | 608 | switch (Type) { 609 | case 0x01: 610 | printf("\tHole (raw code)\n"); 611 | snprintf(Name, sizeof(Name), "hole_%02x.bin", 612 | HoleNum++); 613 | fd = open(Name, O_RDWR | O_CREAT | O_TRUNC, 614 | S_IRUSR | S_IWUSR); 615 | if (fd < 0) { 616 | fprintf(stderr, 617 | "Error: unable to open %s: %s\n\n", 618 | Name, strerror(errno)); 619 | continue; 620 | } 621 | write(fd, BIOSImage + Base, Length); 622 | close(fd); 623 | break; 624 | 625 | case 0x02: 626 | /* FFV modules */ 627 | Offset = Base; 628 | while (Offset < Base + Length) { 629 | Offset += 630 | PhoenixExtractFFV(BIOSImage, BIOSLength, 631 | Offset); 632 | } 633 | break; 634 | } 635 | } 636 | } 637 | 638 | /* Parse GUID-based volumedir layout: 639 | * - 4 bytes of unknown data 640 | * - 4 byte Length 641 | * - array of module entries: 642 | * - 16 byte GUID indicating module type 643 | * - 4 byte Base 644 | * - 4 byte Length 645 | */ 646 | void PhoenixVolume2(unsigned char *BIOSImage, int BIOSLength, int Offset) 647 | { 648 | struct PhoenixVolumeDirEntry2 { 649 | /* these are stored little endian */ 650 | uint32_t guid1; 651 | uint16_t guid2; 652 | uint16_t guid3; 653 | /* these are big endian */ 654 | uint16_t guid4; 655 | /*uint48_t guid5; */ 656 | uint16_t guid5; 657 | uint32_t guid6; 658 | uint32_t Base; 659 | uint32_t Length; 660 | }; 661 | 662 | struct PhoenixVolumeDir2 { 663 | uint16_t Unk1; 664 | uint16_t Unk2; 665 | uint32_t Length; 666 | struct PhoenixVolumeDirEntry2 Modules[]; 667 | } *Volume; 668 | 669 | char Name[16], guid[37]; 670 | int fd, HoleNum = 0; 671 | uint32_t Base, Length, NumModules, ModNum; 672 | 673 | Volume = (struct PhoenixVolumeDir2 *)(BIOSImage + Offset + 0x18); 674 | NumModules = 675 | (Volume->Length - 8) / sizeof(struct PhoenixVolumeDirEntry2); 676 | 677 | printf("FFV modules: %u\n", NumModules); 678 | 679 | for (ModNum = 0; ModNum < NumModules; ModNum++) { 680 | sprintf(guid, "%08X-%04X-%04X-%04X-%04X%08X", 681 | le32toh(Volume->Modules[ModNum].guid1), 682 | le16toh(Volume->Modules[ModNum].guid2), 683 | le16toh(Volume->Modules[ModNum].guid3), 684 | be16toh(Volume->Modules[ModNum].guid4), 685 | be16toh(Volume->Modules[ModNum].guid5), 686 | be32toh(Volume->Modules[ModNum].guid6) 687 | ); 688 | Base = Volume->Modules[ModNum].Base & (BIOSLength - 1); 689 | Length = Volume->Modules[ModNum].Length - 1; 690 | printf("[%2u]: (%08X-%08X) %s\n", ModNum, Base, Base + Length, 691 | guid); 692 | 693 | if (!strcmp(guid, GUID_FFVMODULE)) { 694 | /* FFV modules */ 695 | Offset = Base; 696 | while (Offset < Base + Length) { 697 | Offset += 698 | PhoenixExtractFFV(BIOSImage, BIOSLength, 699 | Offset); 700 | } 701 | } else if (!strcmp(guid, GUID_ESCD)) { 702 | /* Extended System Configuration Data (and similar?) */ 703 | printf("\tESCD\n"); 704 | fd = open("ESCD.bin", O_RDWR | O_CREAT | O_TRUNC, 705 | S_IRUSR | S_IWUSR); 706 | if (fd < 0) { 707 | fprintf(stderr, 708 | "Error: unable to open ESCD.bin: %s\n\n", 709 | strerror(errno)); 710 | continue; 711 | } 712 | write(fd, BIOSImage + Base, Length); 713 | close(fd); 714 | } else if (!strcmp(guid, GUID_RAWCODE)) { 715 | /* Raw BIOS code */ 716 | printf("\tHole (raw code)\n"); 717 | snprintf(Name, sizeof(Name), "hole_%02x.bin", 718 | HoleNum++); 719 | fd = open(Name, O_RDWR | O_CREAT | O_TRUNC, 720 | S_IRUSR | S_IWUSR); 721 | if (fd < 0) { 722 | fprintf(stderr, 723 | "Error: unable to open %s: %s\n\n", 724 | Name, strerror(errno)); 725 | continue; 726 | } 727 | write(fd, BIOSImage + Base, Length); 728 | close(fd); 729 | } else { 730 | fprintf(stderr, "\tUnknown FFV module GUID: %s\n", 731 | guid); 732 | } 733 | } 734 | } 735 | 736 | void PhoenixFFVDirectory(unsigned char *BIOSImage, int BIOSLength, int Offset) 737 | { 738 | char Name[16]; 739 | uint32_t Length; 740 | struct PhoenixFFVModule *Module; 741 | 742 | Module = (struct PhoenixFFVModule *)(BIOSImage + Offset); 743 | 744 | if (Module->Signature != 0xF8) { 745 | fprintf(stderr, "Error: Invalid module signature at 0x%05X\n", 746 | Offset); 747 | return; 748 | } 749 | 750 | Length = (le16toh(Module->LengthHi) << 16) | Module->LengthLo; 751 | 752 | if ((Offset + Length) > BIOSLength) { 753 | fprintf(stderr, "Error: Module overruns buffer at 0x%05X\n", 754 | Offset); 755 | return; 756 | } 757 | 758 | /* get rid of the pesky 0xFF in the middle of the name */ 759 | memcpy(Name, Module->Name, 8); 760 | memcpy(Name + 8, Module->Name + 9, 7); 761 | Name[15] = '\0'; 762 | if (!strcmp(Name, "volumedir.bin")) { 763 | PhoenixVolume1(BIOSImage, BIOSLength, Offset, Length); 764 | } else if (!strcmp(Name, "volumedir.bin2")) { 765 | PhoenixVolume2(BIOSImage, BIOSLength, Offset); 766 | } else { 767 | fprintf(stderr, 768 | "FFV points to something other than the volumedir: %s\n", 769 | Name); 770 | } 771 | } 772 | 773 | Bool PhoenixFFV(unsigned char *BIOSImage, int BIOSLength, struct PhoenixID *FFV) 774 | { 775 | uint32_t Offset; 776 | 777 | Offset = 778 | le32toh(*((uint32_t *) (((char *)FFV) + 0xA))) & (BIOSLength - 1); 779 | 780 | if (!Offset) { 781 | fprintf(stderr, "BCPFFV module offset is NULL.\n"); 782 | return FALSE; 783 | } 784 | 785 | PhoenixFFVDirectory(BIOSImage, BIOSLength, Offset); 786 | 787 | return TRUE; 788 | } 789 | 790 | /* 791 | * 792 | */ 793 | Bool 794 | PhoenixExtract(unsigned char *BIOSImage, int BIOSLength, int BIOSOffset, 795 | uint32_t Offset1, uint32_t BCPSegmentOffset) 796 | { 797 | struct PhoenixID *ID, *SYS = NULL, *FFV = NULL; 798 | uint32_t Offset; 799 | 800 | printf("Found Phoenix BIOS \"%s\"\n", (char *)(BIOSImage + Offset1)); 801 | 802 | /* TODO: Print more information about image */ 803 | /* TODO: Group modules by firmware volumes */ 804 | 805 | /* 806 | * For newer Phoenix BIOSes, the BIOS has a trailing block that does not 807 | * match the signature as tested in PhoenixModule. We adjust the length 808 | * variable to handle that scenario. For example try the new BIOSes for the 809 | * SuperMicro motherboards X7DA8 and X7DB8. X7DB8 is supported by Coreboot. 810 | */ 811 | if (BIOSLength > 0x100000 && BIOSOffset > 0) { 812 | BIOSLength = BIOSLength + BIOSOffset - 0x100000; 813 | } 814 | 815 | for (ID = (struct PhoenixID *)(BIOSImage + BCPSegmentOffset + 10); 816 | ((void *)ID < (void *)(BIOSImage + BIOSLength)) && ID->Name[0]; 817 | ID = 818 | (struct PhoenixID *)(((unsigned char *)ID) + 819 | le16toh(ID->Length))) { 820 | #if 0 821 | printf 822 | ("PhoenixID: Name %c%c%c%c%c%c, Flags 0x%04X, Length %d\n", 823 | ID->Name[0], ID->Name[1], ID->Name[2], ID->Name[3], 824 | ID->Name[4], ID->Name[5], le16toh(ID->Flags), 825 | le16toh(ID->Length)); 826 | #endif 827 | if (!strncmp(ID->Name, "BCPSYS", 6)) { 828 | SYS = ID; 829 | if (FFV) 830 | break; 831 | } else if (!strncmp(ID->Name, "BCPFFV", 6)) { 832 | FFV = ID; 833 | if (SYS) 834 | break; 835 | } 836 | } 837 | 838 | if (!SYS) { 839 | fprintf(stderr, "Error: Failed to locate BCPSYS offset.\n"); 840 | return FALSE; 841 | } 842 | 843 | /* BCPCMP parsing */ 844 | 845 | unsigned char *bcpcmp = memmem(BIOSImage, BIOSLength - 6, "BCPCMP", 6); 846 | if (!bcpcmp) { 847 | fprintf(stderr, "Error: Failed to locate BCPCMP offset.\n"); 848 | return FALSE; 849 | } 850 | 851 | uint32_t bcpoff = bcpcmp - BIOSImage; 852 | struct bcpCompress *bcpComp = 853 | (struct bcpCompress *)(BIOSImage + bcpoff); 854 | phx.compression = bcpComp->alg; 855 | 856 | /* Get some info */ 857 | char Date[9], Time[9], Version[9]; 858 | 859 | strncpy(Date, ((char *)SYS) + 0x0F, 8); 860 | Date[8] = 0; 861 | strncpy(Time, ((char *)SYS) + 0x18, 8); 862 | Time[8] = 0; 863 | strncpy(Version, ((char *)SYS) + 0x37, 8); 864 | Version[8] = 0; 865 | 866 | printf("Version \"%s\", created on %s at %s.\n", Version, Date, Time); 867 | 868 | Offset = le32toh(*((uint32_t *) (((char *)SYS) + 0x77))); 869 | Offset &= (BIOSLength - 1); 870 | if (!Offset) { 871 | fprintf(stderr, "BCPSYS module offset is NULL.\n"); 872 | if (!FFV) { 873 | return FALSE; 874 | } 875 | return PhoenixFFV(BIOSImage, BIOSLength, FFV); 876 | } 877 | 878 | while (Offset) { 879 | Offset = PhoenixModule(BIOSImage, BIOSLength, Offset); 880 | Offset &= BIOSLength - 1; 881 | } 882 | 883 | return TRUE; 884 | } 885 | -------------------------------------------------------------------------------- /util/gitconfig/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Part of Gerrit Code Review (http://code.google.com/p/gerrit/) 4 | # 5 | # Copyright (C) 2009 The Android Open Source Project 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | CHANGE_ID_AFTER="Bug|Issue" 21 | MSG="$1" 22 | 23 | # Check for, and add if missing, a unique Change-Id 24 | # 25 | add_ChangeId() { 26 | clean_message=`sed -e ' 27 | /^diff --git a\/.*/{ 28 | s/// 29 | q 30 | } 31 | /^Signed-off-by:/d 32 | /^#/d 33 | ' "$MSG" | git stripspace` 34 | if test -z "$clean_message" 35 | then 36 | return 37 | fi 38 | 39 | # Does Change-Id: already exist? if so, exit (no change). 40 | if grep -i '^Change-Id: I[0-9a-f]\{40\}$' "$MSG" >/dev/null 41 | then 42 | return 43 | fi 44 | 45 | id=`_gen_ChangeId` 46 | T="$MSG.tmp.$$" 47 | AWK=awk 48 | if [ -x /usr/xpg4/bin/awk ]; then 49 | # Solaris AWK is just too broken 50 | AWK=/usr/xpg4/bin/awk 51 | fi 52 | 53 | # How this works: 54 | # - parse the commit message as (textLine+ blankLine*)* 55 | # - assume textLine+ to be a footer until proven otherwise 56 | # - exception: the first block is not footer (as it is the title) 57 | # - read textLine+ into a variable 58 | # - then count blankLines 59 | # - once the next textLine appears, print textLine+ blankLine* as these 60 | # aren't footer 61 | # - in END, the last textLine+ block is available for footer parsing 62 | $AWK ' 63 | BEGIN { 64 | # while we start with the assumption that textLine+ 65 | # is a footer, the first block is not. 66 | isFooter = 0 67 | footerComment = 0 68 | blankLines = 0 69 | } 70 | 71 | # Skip lines starting with "#" without any spaces before it. 72 | /^#/ { next } 73 | 74 | # Skip the line starting with the diff command and everything after it, 75 | # up to the end of the file, assuming it is only patch data. 76 | # If more than one line before the diff was empty, strip all but one. 77 | /^diff --git a/ { 78 | blankLines = 0 79 | while (getline) { } 80 | next 81 | } 82 | 83 | # Count blank lines outside footer comments 84 | /^$/ && (footerComment == 0) { 85 | blankLines++ 86 | next 87 | } 88 | 89 | # Catch footer comment 90 | /^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) { 91 | footerComment = 1 92 | } 93 | 94 | /]$/ && (footerComment == 1) { 95 | footerComment = 2 96 | } 97 | 98 | # We have a non-blank line after blank lines. Handle this. 99 | (blankLines > 0) { 100 | print lines 101 | for (i = 0; i < blankLines; i++) { 102 | print "" 103 | } 104 | 105 | lines = "" 106 | blankLines = 0 107 | isFooter = 1 108 | footerComment = 0 109 | } 110 | 111 | # Detect that the current block is not the footer 112 | (footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) { 113 | isFooter = 0 114 | } 115 | 116 | { 117 | # We need this information about the current last comment line 118 | if (footerComment == 2) { 119 | footerComment = 0 120 | } 121 | if (lines != "") { 122 | lines = lines "\n"; 123 | } 124 | lines = lines $0 125 | } 126 | 127 | # Footer handling: 128 | # If the last block is considered a footer, splice in the Change-Id at the 129 | # right place. 130 | # Look for the right place to inject Change-Id by considering 131 | # CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first, 132 | # then Change-Id, then everything else (eg. Signed-off-by:). 133 | # 134 | # Otherwise just print the last block, a new line and the Change-Id as a 135 | # block of its own. 136 | END { 137 | unprinted = 1 138 | if (isFooter == 0) { 139 | print lines "\n" 140 | lines = "" 141 | } 142 | changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):" 143 | numlines = split(lines, footer, "\n") 144 | for (line = 1; line <= numlines; line++) { 145 | if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) { 146 | unprinted = 0 147 | print "Change-Id: I'"$id"'" 148 | } 149 | print footer[line] 150 | } 151 | if (unprinted) { 152 | print "Change-Id: I'"$id"'" 153 | } 154 | }' "$MSG" > $T && mv $T "$MSG" || rm -f $T 155 | } 156 | _gen_ChangeIdInput() { 157 | echo "tree `git write-tree`" 158 | if parent=`git rev-parse "HEAD^0" 2>/dev/null` 159 | then 160 | echo "parent $parent" 161 | fi 162 | echo "author `git var GIT_AUTHOR_IDENT`" 163 | echo "committer `git var GIT_COMMITTER_IDENT`" 164 | echo 165 | printf '%s' "$clean_message" 166 | } 167 | _gen_ChangeId() { 168 | _gen_ChangeIdInput | 169 | git hash-object -t commit --stdin 170 | } 171 | 172 | 173 | add_ChangeId 174 | -------------------------------------------------------------------------------- /xfv/Decompress.c: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) 2004, Intel Corporation 4 | All rights reserved. This program and the accompanying materials 5 | are licensed and made available under the terms and conditions of the BSD License 6 | which accompanies this distribution. The full text of the license may be found at 7 | http://opensource.org/licenses/bsd-license.php 8 | 9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | 12 | Module Name: 13 | 14 | Decompress.c 15 | 16 | Abstract: 17 | 18 | Decompressor. Algorithm Ported from OPSD code (Decomp.asm) 19 | 20 | --*/ 21 | 22 | #include 23 | 24 | #include "efihack.h" 25 | 26 | EFI_STATUS 27 | EFIAPI 28 | EfiGetInfo ( 29 | IN VOID *Source, 30 | IN UINT32 SrcSize, 31 | OUT UINT32 *DstSize, 32 | OUT UINT32 *ScratchSize 33 | ); 34 | 35 | EFI_STATUS 36 | EFIAPI 37 | EfiDecompress ( 38 | IN VOID *Source, 39 | IN UINT32 SrcSize, 40 | IN OUT VOID *Destination, 41 | IN UINT32 DstSize, 42 | IN OUT VOID *Scratch, 43 | IN UINT32 ScratchSize 44 | ); 45 | 46 | EFI_STATUS 47 | EFIAPI 48 | TianoGetInfo ( 49 | IN VOID *Source, 50 | IN UINT32 SrcSize, 51 | OUT UINT32 *DstSize, 52 | OUT UINT32 *ScratchSize 53 | ); 54 | 55 | EFI_STATUS 56 | EFIAPI 57 | TianoDecompress ( 58 | IN VOID *Source, 59 | IN UINT32 SrcSize, 60 | IN OUT VOID *Destination, 61 | IN UINT32 DstSize, 62 | IN OUT VOID *Scratch, 63 | IN UINT32 ScratchSize 64 | ); 65 | 66 | // 67 | // Decompression algorithm begins here 68 | // 69 | #define BITBUFSIZ 32 70 | #define MAXMATCH 256 71 | #define THRESHOLD 3 72 | #define CODE_BIT 16 73 | #define UINT8_MAX 0xff 74 | #define BAD_TABLE - 1 75 | 76 | // 77 | // C: Char&Len Set; P: Position Set; T: exTra Set 78 | // 79 | #define NC (0xff + MAXMATCH + 2 - THRESHOLD) 80 | #define CBIT 9 81 | #define MAXPBIT 5 82 | #define TBIT 5 83 | #define MAXNP ((1U << MAXPBIT) - 1) 84 | #define NT (CODE_BIT + 3) 85 | #if NT > MAXNP 86 | #define NPT NT 87 | #else 88 | #define NPT MAXNP 89 | #endif 90 | 91 | typedef struct { 92 | UINT8 *mSrcBase; // Starting address of compressed data 93 | UINT8 *mDstBase; // Starting address of decompressed data 94 | UINT32 mOutBuf; 95 | UINT32 mInBuf; 96 | 97 | UINT16 mBitCount; 98 | UINT32 mBitBuf; 99 | UINT32 mSubBitBuf; 100 | UINT16 mBlockSize; 101 | UINT32 mCompSize; 102 | UINT32 mOrigSize; 103 | 104 | UINT16 mBadTableFlag; 105 | 106 | UINT16 mLeft[2 * NC - 1]; 107 | UINT16 mRight[2 * NC - 1]; 108 | UINT8 mCLen[NC]; 109 | UINT8 mPTLen[NPT]; 110 | UINT16 mCTable[4096]; 111 | UINT16 mPTTable[256]; 112 | 113 | // 114 | // The length of the field 'Position Set Code Length Array Size' in Block Header. 115 | // For EFI 1.1 de/compression algorithm, mPBit = 4 116 | // For Tiano de/compression algorithm, mPBit = 5 117 | // 118 | UINT8 mPBit; 119 | } SCRATCH_DATA; 120 | 121 | STATIC 122 | VOID 123 | FillBuf ( 124 | IN SCRATCH_DATA *Sd, 125 | IN UINT16 NumOfBits 126 | ) 127 | /*++ 128 | 129 | Routine Description: 130 | 131 | Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source. 132 | 133 | Arguments: 134 | 135 | Sd - The global scratch data 136 | NumOfBits - The number of bits to shift and read. 137 | 138 | Returns: (VOID) 139 | 140 | --*/ 141 | { 142 | Sd->mBitBuf = (UINT32) (Sd->mBitBuf << NumOfBits); 143 | 144 | while (NumOfBits > Sd->mBitCount) { 145 | 146 | Sd->mBitBuf |= (UINT32) (Sd->mSubBitBuf << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount))); 147 | 148 | if (Sd->mCompSize > 0) { 149 | // 150 | // Get 1 byte into SubBitBuf 151 | // 152 | Sd->mCompSize--; 153 | Sd->mSubBitBuf = 0; 154 | Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++]; 155 | Sd->mBitCount = 8; 156 | 157 | } else { 158 | // 159 | // No more bits from the source, just pad zero bit. 160 | // 161 | Sd->mSubBitBuf = 0; 162 | Sd->mBitCount = 8; 163 | 164 | } 165 | } 166 | 167 | Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits); 168 | Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount; 169 | } 170 | 171 | STATIC 172 | UINT32 173 | GetBits ( 174 | IN SCRATCH_DATA *Sd, 175 | IN UINT16 NumOfBits 176 | ) 177 | /*++ 178 | 179 | Routine Description: 180 | 181 | Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent 182 | NumOfBits of bits from source. Returns NumOfBits of bits that are 183 | popped out. 184 | 185 | Arguments: 186 | 187 | Sd - The global scratch data. 188 | NumOfBits - The number of bits to pop and read. 189 | 190 | Returns: 191 | 192 | The bits that are popped out. 193 | 194 | --*/ 195 | { 196 | UINT32 OutBits; 197 | 198 | OutBits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits)); 199 | 200 | FillBuf (Sd, NumOfBits); 201 | 202 | return OutBits; 203 | } 204 | 205 | STATIC 206 | UINT16 207 | MakeTable ( 208 | IN SCRATCH_DATA *Sd, 209 | IN UINT16 NumOfChar, 210 | IN UINT8 *BitLen, 211 | IN UINT16 TableBits, 212 | OUT UINT16 *Table 213 | ) 214 | /*++ 215 | 216 | Routine Description: 217 | 218 | Creates Huffman Code mapping table according to code length array. 219 | 220 | Arguments: 221 | 222 | Sd - The global scratch data 223 | NumOfChar - Number of symbols in the symbol set 224 | BitLen - Code length array 225 | TableBits - The width of the mapping table 226 | Table - The table 227 | 228 | Returns: 229 | 230 | 0 - OK. 231 | BAD_TABLE - The table is corrupted. 232 | 233 | --*/ 234 | { 235 | UINT16 Count[17]; 236 | UINT16 Weight[17]; 237 | UINT16 Start[18]; 238 | UINT16 *Pointer; 239 | UINT16 Index3; 240 | UINT16 Index; 241 | UINT16 Len; 242 | UINT16 Char; 243 | UINT16 JuBits; 244 | UINT16 Avail; 245 | UINT16 NextCode; 246 | UINT16 Mask; 247 | 248 | for (Index = 1; Index <= 16; Index++) { 249 | Count[Index] = 0; 250 | } 251 | 252 | for (Index = 0; Index < NumOfChar; Index++) { 253 | Count[BitLen[Index]]++; 254 | } 255 | 256 | Start[1] = 0; 257 | 258 | for (Index = 1; Index <= 16; Index++) { 259 | Start[Index + 1] = (UINT16) (Start[Index] + (Count[Index] << (16 - Index))); 260 | } 261 | 262 | if (Start[17] != 0) { 263 | /*(1U << 16)*/ 264 | return (UINT16) BAD_TABLE; 265 | } 266 | 267 | JuBits = (UINT16) (16 - TableBits); 268 | 269 | for (Index = 1; Index <= TableBits; Index++) { 270 | Start[Index] >>= JuBits; 271 | Weight[Index] = (UINT16) (1U << (TableBits - Index)); 272 | } 273 | 274 | for (; Index <= 16; Index++) { 275 | Weight[Index] = (UINT16) (1U << (16 - Index)); 276 | } 277 | 278 | Index = (UINT16) (Start[TableBits + 1] >> JuBits); 279 | 280 | if (Index != 0) { 281 | Index3 = (UINT16) (1U << TableBits); 282 | while (Index != Index3) { 283 | Table[Index++] = 0; 284 | } 285 | } 286 | 287 | Avail = NumOfChar; 288 | Mask = (UINT16) (1U << (15 - TableBits)); 289 | 290 | for (Char = 0; Char < NumOfChar; Char++) { 291 | 292 | Len = BitLen[Char]; 293 | if (Len == 0) { 294 | continue; 295 | } 296 | 297 | NextCode = (UINT16) (Start[Len] + Weight[Len]); 298 | 299 | if (Len <= TableBits) { 300 | 301 | for (Index = Start[Len]; Index < NextCode; Index++) { 302 | Table[Index] = Char; 303 | } 304 | 305 | } else { 306 | 307 | Index3 = Start[Len]; 308 | Pointer = &Table[Index3 >> JuBits]; 309 | Index = (UINT16) (Len - TableBits); 310 | 311 | while (Index != 0) { 312 | if (*Pointer == 0) { 313 | Sd->mRight[Avail] = Sd->mLeft[Avail] = 0; 314 | *Pointer = Avail++; 315 | } 316 | 317 | if (Index3 & Mask) { 318 | Pointer = &Sd->mRight[*Pointer]; 319 | } else { 320 | Pointer = &Sd->mLeft[*Pointer]; 321 | } 322 | 323 | Index3 <<= 1; 324 | Index--; 325 | } 326 | 327 | *Pointer = Char; 328 | 329 | } 330 | 331 | Start[Len] = NextCode; 332 | } 333 | // 334 | // Succeeds 335 | // 336 | return 0; 337 | } 338 | 339 | STATIC 340 | UINT32 341 | DecodeP ( 342 | IN SCRATCH_DATA *Sd 343 | ) 344 | /*++ 345 | 346 | Routine Description: 347 | 348 | Decodes a position value. 349 | 350 | Arguments: 351 | 352 | Sd - the global scratch data 353 | 354 | Returns: 355 | 356 | The position value decoded. 357 | 358 | --*/ 359 | { 360 | UINT16 Val; 361 | UINT32 Mask; 362 | UINT32 Pos; 363 | 364 | Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; 365 | 366 | if (Val >= MAXNP) { 367 | Mask = 1U << (BITBUFSIZ - 1 - 8); 368 | 369 | do { 370 | 371 | if (Sd->mBitBuf & Mask) { 372 | Val = Sd->mRight[Val]; 373 | } else { 374 | Val = Sd->mLeft[Val]; 375 | } 376 | 377 | Mask >>= 1; 378 | } while (Val >= MAXNP); 379 | } 380 | // 381 | // Advance what we have read 382 | // 383 | FillBuf (Sd, Sd->mPTLen[Val]); 384 | 385 | Pos = Val; 386 | if (Val > 1) { 387 | Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1))); 388 | } 389 | 390 | return Pos; 391 | } 392 | 393 | STATIC 394 | UINT16 395 | ReadPTLen ( 396 | IN SCRATCH_DATA *Sd, 397 | IN UINT16 nn, 398 | IN UINT16 nbit, 399 | IN UINT16 Special 400 | ) 401 | /*++ 402 | 403 | Routine Description: 404 | 405 | Reads code lengths for the Extra Set or the Position Set 406 | 407 | Arguments: 408 | 409 | Sd - The global scratch data 410 | nn - Number of symbols 411 | nbit - Number of bits needed to represent nn 412 | Special - The special symbol that needs to be taken care of 413 | 414 | Returns: 415 | 416 | 0 - OK. 417 | BAD_TABLE - Table is corrupted. 418 | 419 | --*/ 420 | { 421 | UINT16 Number; 422 | UINT16 CharC; 423 | UINT16 Index; 424 | UINT32 Mask; 425 | 426 | Number = (UINT16) GetBits (Sd, nbit); 427 | 428 | if (Number == 0) { 429 | CharC = (UINT16) GetBits (Sd, nbit); 430 | 431 | for (Index = 0; Index < 256; Index++) { 432 | Sd->mPTTable[Index] = CharC; 433 | } 434 | 435 | for (Index = 0; Index < nn; Index++) { 436 | Sd->mPTLen[Index] = 0; 437 | } 438 | 439 | return 0; 440 | } 441 | 442 | Index = 0; 443 | 444 | while (Index < Number) { 445 | 446 | CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3)); 447 | 448 | if (CharC == 7) { 449 | Mask = 1U << (BITBUFSIZ - 1 - 3); 450 | while (Mask & Sd->mBitBuf) { 451 | Mask >>= 1; 452 | CharC += 1; 453 | } 454 | } 455 | 456 | FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3)); 457 | 458 | Sd->mPTLen[Index++] = (UINT8) CharC; 459 | 460 | if (Index == Special) { 461 | CharC = (UINT16) GetBits (Sd, 2); 462 | while ((INT16) (--CharC) >= 0) { 463 | Sd->mPTLen[Index++] = 0; 464 | } 465 | } 466 | } 467 | 468 | while (Index < nn) { 469 | Sd->mPTLen[Index++] = 0; 470 | } 471 | 472 | return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable); 473 | } 474 | 475 | STATIC 476 | VOID 477 | ReadCLen ( 478 | SCRATCH_DATA *Sd 479 | ) 480 | /*++ 481 | 482 | Routine Description: 483 | 484 | Reads code lengths for Char&Len Set. 485 | 486 | Arguments: 487 | 488 | Sd - the global scratch data 489 | 490 | Returns: (VOID) 491 | 492 | --*/ 493 | { 494 | UINT16 Number; 495 | UINT16 CharC; 496 | UINT16 Index; 497 | UINT32 Mask; 498 | 499 | Number = (UINT16) GetBits (Sd, CBIT); 500 | 501 | if (Number == 0) { 502 | CharC = (UINT16) GetBits (Sd, CBIT); 503 | 504 | for (Index = 0; Index < NC; Index++) { 505 | Sd->mCLen[Index] = 0; 506 | } 507 | 508 | for (Index = 0; Index < 4096; Index++) { 509 | Sd->mCTable[Index] = CharC; 510 | } 511 | 512 | return ; 513 | } 514 | 515 | Index = 0; 516 | while (Index < Number) { 517 | 518 | CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; 519 | if (CharC >= NT) { 520 | Mask = 1U << (BITBUFSIZ - 1 - 8); 521 | 522 | do { 523 | 524 | if (Mask & Sd->mBitBuf) { 525 | CharC = Sd->mRight[CharC]; 526 | } else { 527 | CharC = Sd->mLeft[CharC]; 528 | } 529 | 530 | Mask >>= 1; 531 | 532 | } while (CharC >= NT); 533 | } 534 | // 535 | // Advance what we have read 536 | // 537 | FillBuf (Sd, Sd->mPTLen[CharC]); 538 | 539 | if (CharC <= 2) { 540 | 541 | if (CharC == 0) { 542 | CharC = 1; 543 | } else if (CharC == 1) { 544 | CharC = (UINT16) (GetBits (Sd, 4) + 3); 545 | } else if (CharC == 2) { 546 | CharC = (UINT16) (GetBits (Sd, CBIT) + 20); 547 | } 548 | 549 | while ((INT16) (--CharC) >= 0) { 550 | Sd->mCLen[Index++] = 0; 551 | } 552 | 553 | } else { 554 | 555 | Sd->mCLen[Index++] = (UINT8) (CharC - 2); 556 | 557 | } 558 | } 559 | 560 | while (Index < NC) { 561 | Sd->mCLen[Index++] = 0; 562 | } 563 | 564 | MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable); 565 | 566 | return ; 567 | } 568 | 569 | STATIC 570 | UINT16 571 | DecodeC ( 572 | SCRATCH_DATA *Sd 573 | ) 574 | /*++ 575 | 576 | Routine Description: 577 | 578 | Decode a character/length value. 579 | 580 | Arguments: 581 | 582 | Sd - The global scratch data. 583 | 584 | Returns: 585 | 586 | The value decoded. 587 | 588 | --*/ 589 | { 590 | UINT16 Index2; 591 | UINT32 Mask; 592 | 593 | if (Sd->mBlockSize == 0) { 594 | // 595 | // Starting a new block 596 | // 597 | Sd->mBlockSize = (UINT16) GetBits (Sd, 16); 598 | Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3); // there be segfaulting dragons 599 | if (Sd->mBadTableFlag != 0) { 600 | return 0; 601 | } 602 | 603 | ReadCLen (Sd); 604 | 605 | Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, Sd->mPBit, (UINT16) (-1)); 606 | if (Sd->mBadTableFlag != 0) { 607 | return 0; 608 | } 609 | } 610 | 611 | Sd->mBlockSize--; 612 | Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)]; 613 | 614 | if (Index2 >= NC) { 615 | Mask = 1U << (BITBUFSIZ - 1 - 12); 616 | 617 | do { 618 | if (Sd->mBitBuf & Mask) { 619 | Index2 = Sd->mRight[Index2]; 620 | } else { 621 | Index2 = Sd->mLeft[Index2]; 622 | } 623 | 624 | Mask >>= 1; 625 | } while (Index2 >= NC); 626 | } 627 | // 628 | // Advance what we have read 629 | // 630 | FillBuf (Sd, Sd->mCLen[Index2]); 631 | 632 | return Index2; 633 | } 634 | 635 | STATIC 636 | VOID 637 | Decode ( 638 | SCRATCH_DATA *Sd 639 | ) 640 | /*++ 641 | 642 | Routine Description: 643 | 644 | Decode the source data and put the resulting data into the destination buffer. 645 | 646 | Arguments: 647 | 648 | Sd - The global scratch data 649 | 650 | Returns: (VOID) 651 | 652 | --*/ 653 | { 654 | UINT16 BytesRemain; 655 | UINT32 DataIdx; 656 | UINT16 CharC; 657 | 658 | BytesRemain = (UINT16) (-1); 659 | 660 | DataIdx = 0; 661 | 662 | for (;;) { 663 | CharC = DecodeC (Sd); 664 | if (Sd->mBadTableFlag != 0) { 665 | return ; 666 | } 667 | 668 | if (CharC < 256) { 669 | // 670 | // Process an Original character 671 | // 672 | if (Sd->mOutBuf >= Sd->mOrigSize) { 673 | return ; 674 | } else { 675 | Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC; 676 | } 677 | 678 | } else { 679 | // 680 | // Process a Pointer 681 | // 682 | CharC = (UINT16) (CharC - (UINT8_MAX + 1 - THRESHOLD)); 683 | 684 | BytesRemain = CharC; 685 | 686 | DataIdx = Sd->mOutBuf - DecodeP (Sd) - 1; 687 | 688 | BytesRemain--; 689 | while ((INT16) (BytesRemain) >= 0) { 690 | Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++]; 691 | if (Sd->mOutBuf >= Sd->mOrigSize) { 692 | return ; 693 | } 694 | 695 | BytesRemain--; 696 | } 697 | } 698 | } 699 | 700 | return ; 701 | } 702 | 703 | EFI_STATUS 704 | GetInfo ( 705 | IN VOID *Source, 706 | IN UINT32 SrcSize, 707 | OUT UINT32 *DstSize, 708 | OUT UINT32 *ScratchSize 709 | ) 710 | /*++ 711 | 712 | Routine Description: 713 | 714 | The internal implementation of *_DECOMPRESS_PROTOCOL.GetInfo(). 715 | 716 | Arguments: 717 | 718 | Source - The source buffer containing the compressed data. 719 | SrcSize - The size of source buffer 720 | DstSize - The size of destination buffer. 721 | ScratchSize - The size of scratch buffer. 722 | 723 | Returns: 724 | 725 | EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. 726 | EFI_INVALID_PARAMETER - The source data is corrupted 727 | 728 | --*/ 729 | { 730 | UINT8 *Src; 731 | 732 | *ScratchSize = sizeof (SCRATCH_DATA); 733 | 734 | Src = Source; 735 | if (SrcSize < 8) { 736 | return EFI_INVALID_PARAMETER; 737 | } 738 | 739 | *DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); 740 | return EFI_SUCCESS; 741 | } 742 | 743 | EFI_STATUS 744 | Decompress ( 745 | IN VOID *Source, 746 | IN UINT32 SrcSize, 747 | IN OUT VOID *Destination, 748 | IN UINT32 DstSize, 749 | IN OUT VOID *Scratch, 750 | IN UINT32 ScratchSize, 751 | IN UINT8 Version 752 | ) 753 | /*++ 754 | 755 | Routine Description: 756 | 757 | The internal implementation of *_DECOMPRESS_PROTOCOL.Decompress(). 758 | 759 | Arguments: 760 | 761 | Source - The source buffer containing the compressed data. 762 | SrcSize - The size of source buffer 763 | Destination - The destination buffer to store the decompressed data 764 | DstSize - The size of destination buffer. 765 | Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. 766 | ScratchSize - The size of scratch buffer. 767 | Version - The version of de/compression algorithm. 768 | Version 1 for EFI 1.1 de/compression algorithm. 769 | Version 2 for Tiano de/compression algorithm. 770 | 771 | Returns: 772 | 773 | EFI_SUCCESS - Decompression is successfull 774 | EFI_INVALID_PARAMETER - The source data is corrupted 775 | 776 | --*/ 777 | { 778 | UINT32 Index; 779 | UINT32 CompSize; 780 | UINT32 OrigSize; 781 | EFI_STATUS Status; 782 | SCRATCH_DATA *Sd; 783 | UINT8 *Src; 784 | UINT8 *Dst; 785 | 786 | Status = EFI_SUCCESS; 787 | Src = Source; 788 | Dst = Destination; 789 | 790 | if (ScratchSize < sizeof (SCRATCH_DATA)) { 791 | fprintf(stderr, "ScratchSize\n"); 792 | return EFI_INVALID_PARAMETER; 793 | } 794 | 795 | Sd = (SCRATCH_DATA *) Scratch; 796 | 797 | if (SrcSize < 8) { 798 | fprintf(stderr, "SrcSize < 8\n"); 799 | return EFI_INVALID_PARAMETER; 800 | } 801 | 802 | CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24); 803 | OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); 804 | 805 | // 806 | // If compressed file size is 0, return 807 | // 808 | if (OrigSize == 0) { 809 | return Status; 810 | } 811 | 812 | if (SrcSize < CompSize + 8) { 813 | fprintf(stderr, "SrcSize < CompSize + 8\n"); 814 | return EFI_INVALID_PARAMETER; 815 | } 816 | 817 | if (DstSize != OrigSize) { 818 | fprintf(stderr, "DstSize != OrigSize\n"); 819 | return EFI_INVALID_PARAMETER; 820 | } 821 | 822 | Src = Src + 8; 823 | 824 | for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) { 825 | ((UINT8 *) Sd)[Index] = 0; 826 | } 827 | // 828 | // The length of the field 'Position Set Code Length Array Size' in Block Header. 829 | // For EFI 1.1 de/compression algorithm(Version 1), mPBit = 4 830 | // For Tiano de/compression algorithm(Version 2), mPBit = 5 831 | // 832 | switch (Version) { 833 | case 1: 834 | Sd->mPBit = 4; 835 | break; 836 | 837 | case 2: 838 | Sd->mPBit = 5; 839 | break; 840 | 841 | default: 842 | // 843 | // Currently, only have 2 versions 844 | // 845 | fprintf(stderr, "wrong Version\n"); 846 | return EFI_INVALID_PARAMETER; 847 | } 848 | 849 | Sd->mSrcBase = Src; 850 | Sd->mDstBase = Dst; 851 | Sd->mCompSize = CompSize; 852 | Sd->mOrigSize = OrigSize; 853 | 854 | // 855 | // Fill the first BITBUFSIZ bits 856 | // 857 | FillBuf (Sd, BITBUFSIZ); 858 | 859 | // 860 | // Decompress it 861 | // 862 | Decode (Sd); 863 | 864 | if (Sd->mBadTableFlag != 0) { 865 | // 866 | // Something wrong with the source 867 | // 868 | fprintf(stderr, "Sd->mBadTableFlag != 0\n"); 869 | Status = EFI_INVALID_PARAMETER; 870 | } 871 | 872 | return Status; 873 | } 874 | 875 | EFI_STATUS 876 | EFIAPI 877 | EfiGetInfo ( 878 | IN VOID *Source, 879 | IN UINT32 SrcSize, 880 | OUT UINT32 *DstSize, 881 | OUT UINT32 *ScratchSize 882 | ) 883 | /*++ 884 | 885 | Routine Description: 886 | 887 | The implementation of EFI_DECOMPRESS_PROTOCOL.GetInfo(). 888 | 889 | Arguments: 890 | 891 | This - The protocol instance pointer 892 | Source - The source buffer containing the compressed data. 893 | SrcSize - The size of source buffer 894 | DstSize - The size of destination buffer. 895 | ScratchSize - The size of scratch buffer. 896 | 897 | Returns: 898 | 899 | EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. 900 | EFI_INVALID_PARAMETER - The source data is corrupted 901 | 902 | --*/ 903 | { 904 | return GetInfo ( 905 | Source, 906 | SrcSize, 907 | DstSize, 908 | ScratchSize 909 | ); 910 | } 911 | 912 | EFI_STATUS 913 | EFIAPI 914 | EfiDecompress ( 915 | IN VOID *Source, 916 | IN UINT32 SrcSize, 917 | IN OUT VOID *Destination, 918 | IN UINT32 DstSize, 919 | IN OUT VOID *Scratch, 920 | IN UINT32 ScratchSize 921 | ) 922 | /*++ 923 | 924 | Routine Description: 925 | 926 | The implementation of EFI_DECOMPRESS_PROTOCOL.Decompress(). 927 | 928 | Arguments: 929 | 930 | This - The protocol instance pointer 931 | Source - The source buffer containing the compressed data. 932 | SrcSize - The size of source buffer 933 | Destination - The destination buffer to store the decompressed data 934 | DstSize - The size of destination buffer. 935 | Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. 936 | ScratchSize - The size of scratch buffer. 937 | 938 | Returns: 939 | 940 | EFI_SUCCESS - Decompression is successfull 941 | EFI_INVALID_PARAMETER - The source data is corrupted 942 | 943 | --*/ 944 | { 945 | // 946 | // For EFI 1.1 de/compression algorithm, the version is 1. 947 | // 948 | return Decompress ( 949 | Source, 950 | SrcSize, 951 | Destination, 952 | DstSize, 953 | Scratch, 954 | ScratchSize, 955 | 2 //1 956 | ); 957 | } 958 | 959 | EFI_STATUS 960 | EFIAPI 961 | TianoGetInfo ( 962 | IN VOID *Source, 963 | IN UINT32 SrcSize, 964 | OUT UINT32 *DstSize, 965 | OUT UINT32 *ScratchSize 966 | ) 967 | /*++ 968 | 969 | Routine Description: 970 | 971 | The implementation of EFI_TIANO_DECOMPRESS_PROTOCOL.GetInfo(). 972 | 973 | Arguments: 974 | 975 | This - The protocol instance pointer 976 | Source - The source buffer containing the compressed data. 977 | SrcSize - The size of source buffer 978 | DstSize - The size of destination buffer. 979 | ScratchSize - The size of scratch buffer. 980 | 981 | Returns: 982 | 983 | EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. 984 | EFI_INVALID_PARAMETER - The source data is corrupted 985 | 986 | --*/ 987 | { 988 | return GetInfo ( 989 | Source, 990 | SrcSize, 991 | DstSize, 992 | ScratchSize 993 | ); 994 | } 995 | 996 | EFI_STATUS 997 | EFIAPI 998 | TianoDecompress ( 999 | IN VOID *Source, 1000 | IN UINT32 SrcSize, 1001 | IN OUT VOID *Destination, 1002 | IN UINT32 DstSize, 1003 | IN OUT VOID *Scratch, 1004 | IN UINT32 ScratchSize 1005 | ) 1006 | /*++ 1007 | 1008 | Routine Description: 1009 | 1010 | The implementation of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress(). 1011 | 1012 | Arguments: 1013 | 1014 | This - The protocol instance pointer 1015 | Source - The source buffer containing the compressed data. 1016 | SrcSize - The size of source buffer 1017 | Destination - The destination buffer to store the decompressed data 1018 | DstSize - The size of destination buffer. 1019 | Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. 1020 | ScratchSize - The size of scratch buffer. 1021 | 1022 | Returns: 1023 | 1024 | EFI_SUCCESS - Decompression is successfull 1025 | EFI_INVALID_PARAMETER - The source data is corrupted 1026 | 1027 | --*/ 1028 | { 1029 | // 1030 | // For Tiano de/compression algorithm, the version is 2. 1031 | // 1032 | return Decompress ( 1033 | Source, 1034 | SrcSize, 1035 | Destination, 1036 | DstSize, 1037 | Scratch, 1038 | ScratchSize, 1039 | 2 1040 | ); 1041 | } 1042 | -------------------------------------------------------------------------------- /xfv/README.txt: -------------------------------------------------------------------------------- 1 | This kit contains the tools to extract files from an EFI firmware 2 | image. 3 | 4 | Step 1: Getting the image 5 | --------------------------- 6 | You can get a firmware image by extracting it from any vendor updater 7 | package, or by using the 'dumpfv.efi' program from rEFIt. 8 | The suffix of the image name is often ".fd". 9 | 10 | Step 2: Extracting the image 11 | ------------------------------ 12 | Run "xfv.py" with the image file name as a parameter. 13 | You may want to capture output from xfv for later reference, e.g.: 14 | 15 | ./xfv.py MBP11_0044_02B.fd | tee mbp11-output.txt 16 | 17 | Some notes 18 | ------------ 19 | Early Apple firmware images (e.g. the original images for the iMac, MBP 20 | and Mac mini models as present on the Firmware Restoration CD) include 21 | file names for drivers and applications. Later images (e.g. the Boot 22 | Camp firmware updates) don't. However, the GUID of the files is fixed, 23 | so a future version of xfv may support building a dictionary of file 24 | names and using them for images that don't have embedded file names. 25 | 26 | The current version only supports one "firmware volume" per file. The 27 | firmware images actually contain 4 parts: 28 | 29 | Offset Size Content 30 | 000000 1A0000 Main firmware volume: DXE core, DXE drivers 31 | 1A0000 010000 Firmware volume, use unknown 32 | 1B0000 030000 Contents unknown 33 | 1E0000 020000 Firmware volume: PEI core, PEI drivers 34 | -------------------------------------------------------------------------------- /xfv/efidecomp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "efihack.h" 8 | 9 | 10 | EFI_STATUS 11 | EFIAPI 12 | EfiGetInfo ( 13 | IN VOID *Source, 14 | IN UINT32 SrcSize, 15 | OUT UINT32 *DstSize, 16 | OUT UINT32 *ScratchSize 17 | ); 18 | 19 | EFI_STATUS 20 | EFIAPI 21 | EfiDecompress ( 22 | IN VOID *Source, 23 | IN UINT32 SrcSize, 24 | IN OUT VOID *Destination, 25 | IN UINT32 DstSize, 26 | IN OUT VOID *Scratch, 27 | IN UINT32 ScratchSize 28 | ); 29 | 30 | int main(int argc, char **argv) 31 | { 32 | char *buffer; 33 | long buflen, fill; 34 | ssize_t got; 35 | char *dstbuf, *scratchbuf; 36 | UINT32 DstSize; 37 | UINT32 ScratchSize; 38 | EFI_STATUS Status; 39 | 40 | // read all data from stdin 41 | buflen = 32768; 42 | fill = 0; 43 | buffer = malloc(buflen); 44 | if (buffer == NULL) { 45 | fprintf(stderr, "Out of memory!\n"); 46 | return 1; 47 | } 48 | for (;;) { 49 | if (fill == buflen) { 50 | long newbuflen; 51 | 52 | newbuflen = buflen << 1; 53 | buffer = realloc(buffer, newbuflen); 54 | if (buffer == NULL) { 55 | fprintf(stderr, "Out of memory!\n"); 56 | return 1; 57 | } 58 | buflen = newbuflen; 59 | } 60 | 61 | got = read(0, buffer + fill, buflen - fill); 62 | if (got < 0) { 63 | fprintf(stderr, "Error during read: %d\n", errno); 64 | return 1; 65 | } else if (got == 0) { 66 | break; // EOF 67 | } else { 68 | fill += got; 69 | } 70 | } 71 | 72 | //fprintf(stderr, "got %d bytes\n", fill); 73 | 74 | // inspect data 75 | Status = EfiGetInfo(buffer, fill, &DstSize, &ScratchSize); 76 | if (Status != EFI_SUCCESS) { 77 | fprintf(stderr, "EFI ERROR (get info)\n"); 78 | return 1; 79 | } 80 | dstbuf = malloc(DstSize); 81 | scratchbuf = malloc(ScratchSize); 82 | if (dstbuf == NULL || scratchbuf == NULL) { 83 | fprintf(stderr, "Out of memory!\n"); 84 | return 1; 85 | } 86 | 87 | // decompress data 88 | Status = EfiDecompress(buffer, fill, dstbuf, DstSize, scratchbuf, ScratchSize); 89 | if (Status != EFI_SUCCESS) { 90 | fprintf(stderr, "EFI ERROR (decompress)\n"); 91 | return 1; 92 | } 93 | 94 | // write to stdout 95 | while (DstSize > 0) { 96 | got = write(1, dstbuf, DstSize); 97 | if (got < 0) { 98 | fprintf(stderr, "Error during write: %d\n", errno); 99 | return 1; 100 | } else { 101 | dstbuf += got; 102 | DstSize -= got; 103 | } 104 | } 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /xfv/efihack.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #define VOID void 4 | #define UINT8 uint8_t 5 | #define UINT16 uint16_t 6 | #define UINT32 uint32_t 7 | #define UINT64 uint64_t 8 | #define INT8 int8_t 9 | #define INT16 int16_t 10 | #define INT32 int32_t 11 | #define INT64 int64_t 12 | 13 | #define EFI_STATUS UINT32 14 | #define EFI_SUCCESS (0) 15 | #define EFI_INVALID_PARAMETER (-5) 16 | 17 | 18 | #define EFIAPI 19 | 20 | #define IN 21 | #define OUT 22 | #define OPTIONAL 23 | #define STATIC static 24 | #undef UINT8_MAX 25 | -------------------------------------------------------------------------------- /xfv/xfv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import os 5 | from struct import unpack 6 | 7 | fvh_count = 0 8 | 9 | ### Formatting: GUIDs 10 | 11 | def format_guid(guid_s): 12 | parts = unpack(" len(fvdata): 76 | print "WARNING: File too short, header gives length as 0x%X bytes" % fvlen 77 | else: 78 | print "Size per header: 0x%X bytes" % fvlen 79 | offset = fvhdrlen 80 | 81 | global fvh_count 82 | #fvhdir = "fvh-%d" % fvh_count 83 | fvhdir = "fvh-" + name 84 | fvh_count = fvh_count + 1 85 | try: 86 | os.mkdir(fvhdir) 87 | except: 88 | pass 89 | os.chdir(fvhdir) 90 | 91 | ### Decode files 92 | 93 | print "Listing files" 94 | print "-----" 95 | 96 | while True: 97 | if offset == fvlen: 98 | print "-----" 99 | print "End of volume (size reached cleanly)" 100 | break 101 | if offset + 24 > fvlen: 102 | print "-----" 103 | print "End of volume (size reached uncleanly)" 104 | break 105 | 106 | (fileguid, fileintcheck, filetype, fileattr, filelenandstate) = unpack("< 16s H B B L", fvdata[offset:offset+24]) 107 | if filetype == 0xff: 108 | print "-----" 109 | print "End of volume (filler data found)" 110 | break 111 | fileentrylen = filelenandstate & 0xffffff 112 | filestate = filelenandstate >> 24 113 | filelen = fileentrylen - 24 114 | if fileattr & 1: 115 | print " has tail!" 116 | filelen = filelen - 2 117 | 118 | fileoffset = offset + 24 119 | nextoffset = (offset + fileentrylen + 7) & ~7 120 | 121 | print "%08X %08X" % (fileoffset, nextoffset) 122 | 123 | filedata = fvdata[fileoffset:fileoffset+filelen] 124 | compressed = False 125 | if filetype != 1 and filelen > 3 and filedata[3] == "\x01": 126 | compressed = True 127 | filedata = decompress(filedata) 128 | 129 | if compressed: 130 | print "%08X %s %s C %d (%d)" % (offset, format_guid(fileguid), format_filetype(filetype), len(filedata), filelen) 131 | else: 132 | print "%08X %s %s U %d" % (offset, format_guid(fileguid), format_filetype(filetype), filelen) 133 | 134 | if filetype != 0xF0: 135 | handle_file("file-%s.%s" % (format_guid(fileguid), extention_filetype(filetype)), filetype, filedata) 136 | else: 137 | print "(skipping)" 138 | 139 | offset = nextoffset 140 | 141 | os.chdir('..') 142 | return fvlen 143 | 144 | if sys.platform == 'win32': 145 | efidecomp_path = os.path.join(os.path.dirname(__file__), "UEFI_Decompressor") 146 | efidecomp_cmd = '"%s" %s %s' 147 | else: 148 | efidecomp_path = os.path.dirname(os.path.realpath(__file__)) + "/efidecomp" 149 | efidecomp_cmd = "%s < %s > %s" 150 | 151 | ### Handle decompression of a compressed section 152 | 153 | def decompress2(compdata): 154 | f = file("_tmp_decompress", "wb") 155 | f.write(compdata) 156 | f.close() 157 | 158 | cmd = efidecomp_cmd % ( efidecomp_path, '_tmp_decompress', '_tmp_result') 159 | print "cmd: %r" % cmd 160 | os.system(cmd) 161 | 162 | f = file("_tmp_result", "rb") 163 | decompdata = f.read() 164 | f.close() 165 | return decompdata 166 | 167 | def decompress(compdata): 168 | (sectlenandtype, uncomplen, comptype) = unpack("< L L B", compdata[0:9]) 169 | sectlen = sectlenandtype & 0xffffff 170 | if sectlen < len(compdata): 171 | print "WARNING: Compressed section is not the only section! (%d/%d)" % (sectlen, len(compdata)) 172 | if comptype == 0: 173 | return compdata[9:] 174 | elif comptype == 1: 175 | print "WARNING: this code path might not work"; 176 | f = file("_tmp_decompress", "wb") 177 | f.write(compdata[9:]) 178 | f.close() 179 | 180 | cmd = efidecomp_cmd % ( efidecomp_path, '_tmp_decompress', '_tmp_result') 181 | #cmd = "./efidecomp <_tmp_decompress >_tmp_result" 182 | os.system(cmd) 183 | 184 | f = file("_tmp_result", "rb") 185 | decompdata = f.read() 186 | f.close() 187 | 188 | if len(decompdata) < uncomplen: 189 | print "WARNING: Decompressed data too short!" 190 | return decompdata 191 | 192 | elif comptype == 2: 193 | f = file("_tmp_decompress", "wb") 194 | 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. 195 | f.close() 196 | 197 | os.system("lzmadec <_tmp_decompress >_tmp_result") 198 | 199 | f = file("_tmp_result", "rb") 200 | decompdata = f.read() 201 | f.close() 202 | 203 | if len(decompdata) < uncomplen: 204 | print "WARNING: Decompressed data too short!" 205 | return decompdata 206 | else: 207 | print "ERROR: Unknown compression type %d" % comptype 208 | return compdata 209 | 210 | ### Handle the contents of one firmware file 211 | 212 | 213 | def handle_file(filename, filetype, filedata): 214 | if filetype == 1: 215 | f = file("%s.raw" % filename, "wb") 216 | f.write(filedata) 217 | f.close() 218 | if filetype != 1: 219 | handle_sections(filename, 0, filedata) 220 | 221 | def get_filename(imagedata): 222 | imagelen = len(imagedata) 223 | filename_override = None 224 | 225 | # first try to find a filename 226 | offset = 0 227 | while offset + 4 <= imagelen: 228 | (sectlenandtype,) = unpack("< L", imagedata[offset:offset + 4]) 229 | sectlen = sectlenandtype & 0xffffff 230 | secttype = sectlenandtype >> 24 231 | nextoffset = (offset + sectlen + 3) & ~3 232 | dataoffset = offset + 4 233 | datalen = sectlen - 4 234 | sectdata = imagedata[dataoffset:dataoffset + datalen] 235 | 236 | if secttype == 0x15: 237 | filename_override = sectdata[:-2].decode( 238 | "utf-16le").encode("utf-8") 239 | print " Filename '%s'" % filename_override 240 | 241 | offset = nextoffset 242 | return filename_override 243 | 244 | ### Handle section data (i.e. multiple sections), recurse if necessary 245 | 246 | def handle_sections(filename, sectindex, imagedata): 247 | imagelen = len(imagedata) 248 | 249 | # first try to find a filename 250 | filename_override = get_filename(imagedata) 251 | 252 | # then analyze the sections for good 253 | offset = 0 254 | while offset + 4 <= imagelen: 255 | (sectlenandtype,) = unpack("< L", imagedata[offset:offset + 4]) 256 | sectlen = sectlenandtype & 0xffffff 257 | secttype = sectlenandtype >> 24 258 | nextoffset = (offset + sectlen + 3) & ~3 259 | dataoffset = offset + 4 260 | datalen = sectlen - 4 261 | 262 | if secttype == 2: 263 | (sectguid, sectdataoffset, sectattr) = unpack("< 16s H H", imagedata[offset+4:offset+24]) 264 | dataoffset = offset + sectdataoffset 265 | datalen = sectlen - sectdataoffset 266 | if sectguid == "\xB0\xCD\x1B\xFC\x31\x7D\xAA\x49\x93\x6A\xA4\x60\x0D\x9D\xD0\x83": 267 | # CRC32 section 268 | sectindex = handle_sections(filename, sectindex, imagedata[ 269 | dataoffset:dataoffset + datalen]) 270 | else: 271 | print " %02d GUID %s" % (sectindex, format_guid(sectguid)) 272 | sectindex += 1 273 | sectindex = handle_sections(filename, sectindex, imagedata[ 274 | dataoffset:dataoffset + datalen]) 275 | elif secttype == 1: # compressed 276 | sectdata = imagedata[dataoffset:dataoffset+datalen] 277 | decdata = decompress2(sectdata) 278 | print " %02d COMPRESSED %d => %d" % (sectindex, datalen, len(decdata)) 279 | if filename_override == None: 280 | filename_override = get_filename(decdata) 281 | sectindex += 1 282 | sectindex = handle_sections(filename, sectindex, decdata) 283 | else: 284 | secttype_name = "UNKNOWN(%02X)" % secttype 285 | ext = "data" 286 | sectdata = imagedata[dataoffset:dataoffset + datalen] 287 | extraprint = "" 288 | 289 | if secttype == 0x1: 290 | secttype_name = "COMPRESSED" 291 | ext = "comp" 292 | if secttype == 0x10: 293 | secttype_name = "PE32" 294 | ext = "efi" 295 | elif secttype == 0x11: 296 | secttype_name = "PIC" 297 | ext = "pic.efi" 298 | elif secttype == 0x12: 299 | secttype_name = "TE" 300 | ext = "te" 301 | elif secttype == 0x13: 302 | secttype_name = "DXE_DEPEX" 303 | ext = "depex" 304 | elif secttype == 0x14: 305 | secttype_name = "VERSION" 306 | ext = "ver" 307 | elif secttype == 0x15: 308 | secttype_name = "USER_INTERFACE" 309 | ext = None 310 | elif secttype == 0x16: 311 | secttype_name = "COMPATIBILITY16" 312 | ext = "bios" 313 | elif secttype == 0x17: 314 | secttype_name = "FIRMWARE_VOLUME_IMAGE" 315 | ext = "fd" 316 | elif secttype == 0x18: 317 | secttype_name = "FREEFORM_SUBTYPE_GUID" 318 | ext = "guid" 319 | elif secttype == 0x19: 320 | secttype_name = "RAW" 321 | ext = "raw" 322 | if sectdata[0:8] == "\x89PNG\x0D\x0A\x1A\x0A": 323 | ext = "png" 324 | elif sectdata[0:4] == "icns": 325 | ext = "icns" 326 | elif secttype == 0x1B: 327 | secttype_name = "PEI_DEPEX" 328 | ext = None 329 | 330 | print " %02d %s %d%s" % ( 331 | sectindex, secttype_name, datalen, extraprint) 332 | 333 | if ext is not None: 334 | use_filename = "%s-%02d" % (filename, sectindex) 335 | if filename_override is not None: 336 | use_filename = filename_override 337 | f = file("%s.%s" % (use_filename, ext), "wb") 338 | f.write(sectdata) 339 | f.close() 340 | 341 | if secttype == 0x17: 342 | print "*** Recursively analyzing the contained firmware volume..." 343 | handle_fv(sectdata, filename) 344 | 345 | sectindex += 1 346 | 347 | offset = nextoffset 348 | 349 | return sectindex 350 | 351 | ### main code 352 | 353 | if __name__ == '__main__': 354 | if len(sys.argv) > 1: 355 | filename = sys.argv[1] 356 | if len(sys.argv) > 2: 357 | offset = int(sys.argv[2], 16) 358 | else: 359 | offset = 0 360 | analyze_diskfile(filename, offset) 361 | else: 362 | print "Usage: xfv.py bios.rom [start offset]" 363 | --------------------------------------------------------------------------------