pax_global_header00006660000000000000000000000064132051154760014516gustar00rootroot0000000000000052 comment=f101200ed1ec7045e6568d4908953281f18eb03d dmg2img-1.6.7/000077500000000000000000000000001320511547600130575ustar00rootroot00000000000000dmg2img-1.6.7/COPYING000066400000000000000000000431331320511547600141160ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. dmg2img-1.6.7/Makefile000066400000000000000000000011531320511547600145170ustar00rootroot00000000000000#CC = gcc CFLAGS = -O2 -Wall BIN_DIR = ${DESTDIR}/usr/bin all: dmg2img vfdecrypt dmg2img: dmg2img.c dmg2img.h mntcmd.h gpt.h dmg2img.o base64.o adc.o $(CC) -s -o dmg2img dmg2img.o base64.o adc.o -L. -lz -lbz2 dmg2img.o: dmg2img.c dmg2img.h $(CC) $(CFLAGS) -c dmg2img.c base64.o: base64.c base64.h $(CC) $(CFLAGS) -c base64.c adc.o: adc.c adc.h $(CC) $(CFLAGS) -c adc.c vfdecrypt: vfdecrypt.c $(CC) $(CFLAGS) -s -o vfdecrypt vfdecrypt.c -lcrypto install: dmg2img vfdecrypt mkdir -p ${BIN_DIR} install -c -s -m 755 -o root -g root dmg2img vfdecrypt $(BIN_DIR) clean: rm -f dmg2img vfdecrypt *~ *.o core dmg2img-1.6.7/README000066400000000000000000000103211320511547600137340ustar00rootroot00000000000000 DMG2IMG is a tool which allows converting Apple compressed dmg archives to standard (hfsplus) image disk files. This tool handles zlib and bzip2 compressed dmg images. USAGE: dmg2img [-l] [-p N] [-s] [-v] [-V] [-d] [] or dmg2img -i -o It is derived from dmg2iso v0.2c by vu1tur NOTES: 1. An equivalent command under Mac OS X would be: hdiutil convert -format UDTO -o 2. Under linux, the image disk file can be mounted with the commands modprobe hfsplus mount -t hfsplus -o loop /mnt [normally, only 'root' might be able to do this] 3. Windows users should be able to open the image disk file with UltraISO. Jean-Pierre Demailly COMPILATION: The default included Makefile is for Linux/gcc. The development files in zlib-dev and libbz2-dev are needed to compile dmg2img, and those in openssl-dev are needed to compile vfdecrypt. CHANGELOG: 1.0 3 August 2007 * Initial version 1.1 4 August 2008 * Fixed segfault bug occurring when decompressing certain dmg files beyond the actual end of the file (due to not correctly setting the size of the compressed parts ...) * Added slightly modified vfdecrypt utility from Weinmann-Appelbaum-Fromme in order to decrypt encrypted dmg files. 1.2 17 September 2008 * Fixed segfault bug due to buffer overflow (buffer sizes incorrectly set, resulting in insufficient memory allocation). * Fixed most compilation warnings - remaining ones are irrelevant with standard compilers. 1.3 19 September 2008 * Further fixes which (hopefully) enable dmg2img to work on dmg archives of arbitrary size, while reducing RAM usage a lot. * A lot of thanks to Alfred E. Hegge and Randy Broman for testing and reporting bugs. 1.4 5 April 2009 * Applied patch from Vladimir 'phcoder' Serbinenko which brings correct handling of 64bit integers in koly signature and plist data, and should enable dmg2img to work on huge archives > 4GBytes (tested by 'phcoder'). * Added support for dmg archives involving bzip2 instead of zlib compression (this has not received much testing yet, as those archives are still unfrequent). * Many thanks to Pierre Duhem for useful hints. 1.4.1 6 April 2009 * Fixed a bug in writing the output file that caused some DMG images to convert to a broken unmountable IMG image. 1.5 8 April 2009 * Fixed a bug in parsing plist for image partitions. * Added support for ADC-compressed dmg images. 1.5.1 11 April 2009 * Added missing zero block type. * Small fixes and clean up. 1.6 15 April 2009 * Added support for dmg images that only have binary resource fork but no XML plist. * Refined koly block processing. * Fixed a bug in finding the offset for the next compressed block when offsets are defined relative to the current partition. * Fixed broken progress indicator. * Added detection of images with GUID Partition Table and respective mount commands in linux. 1.6.1 12 August 2009 * Fixed a bug in handling large files on win32 systems. 1.6.2 24 March 2010 * Fixed a bug in processing a terminal block type. * Added periodic flushing of debug log file. 1.6.3 07 April 2012 * Added option -l to list partitions * Added option -p to extract only specific partition * Added support for a rare case scenario of koly block being at the the beginning of the image (thanks to Friik) 1.6.4 25 April 2012 * Compilation bugfix (Linux) 1.6.5 23 July 2013 * Fixed a bug in handling some types of dmg files 1.6.6 06 February 2017 * Fixed a crash on invalid block signature (thanks to Peter Wu) 1.6.7 09 February 2017 * Fixed buffer underrun (thanks to Peter Wu) * Avoid truncating .img file when run to list partition (thanks to Frederic Germain) * Small fixes and cleanup http://vu1tur.eu.org/dmg2imgdmg2img-1.6.7/adc.c000066400000000000000000000044751320511547600137640ustar00rootroot00000000000000#include "adc.h" #include #include #include int adc_decompress(int in_size, unsigned char *input, int avail_size, unsigned char *output, int *bytes_written) { if (in_size == 0) return 0; bool output_full = false; unsigned char *inp = input; unsigned char *outp = output; int chunk_type; int chunk_size; int offset; int i; while (inp - input < in_size) { chunk_type = adc_chunk_type(*inp); switch (chunk_type) { case ADC_PLAIN: chunk_size = adc_chunk_size(*inp); if (outp + chunk_size - output > avail_size) { output_full = true; break; } memcpy(outp, inp + 1, chunk_size); inp += chunk_size + 1; outp += chunk_size; break; case ADC_2BYTE: chunk_size = adc_chunk_size(*inp); offset = adc_chunk_offset(inp); if (outp + chunk_size - output > avail_size) { output_full = true; break; } if (offset == 0) { memset(outp, *(outp - offset - 1), chunk_size); outp += chunk_size; inp += 2; } else { for (i = 0; i < chunk_size; i++) { memcpy(outp, outp - offset - 1, 1); outp++; } inp += 2; } break; case ADC_3BYTE: chunk_size = adc_chunk_size(*inp); offset = adc_chunk_offset(inp); if (outp + chunk_size - output > avail_size) { output_full = true; break; } if (offset == 0) { memset(outp, *(outp - offset - 1), chunk_size); outp += chunk_size; inp += 3; } else { for (i = 0; i < chunk_size; i++) { memcpy(outp, outp - offset - 1, 1); outp++; } inp += 3; } break; } if (output_full) break; } *bytes_written = outp - output; return inp - input; } int adc_chunk_type(char _byte) { if (_byte & 0x80) return ADC_PLAIN; if (_byte & 0x40) return ADC_3BYTE; return ADC_2BYTE; } int adc_chunk_size(char _byte) { switch (adc_chunk_type(_byte)) { case ADC_PLAIN: return (_byte & 0x7F) + 1; case ADC_2BYTE: return ((_byte & 0x3F) >> 2) + 3; case ADC_3BYTE: return (_byte & 0x3F) + 4; } return -1; } int adc_chunk_offset(unsigned char *chunk_start) { unsigned char *c = chunk_start; switch (adc_chunk_type(*c)) { case ADC_PLAIN: return 0; case ADC_2BYTE: return ((((unsigned char)*c & 0x03)) << 8) + (unsigned char)*(c + 1); case ADC_3BYTE: return (((unsigned char)*(c + 1)) << 8) + (unsigned char)*(c + 2); } return -1; } dmg2img-1.6.7/adc.h000066400000000000000000000006051320511547600137600ustar00rootroot00000000000000#include #include #define ADC_PLAIN 0x01 #define ADC_2BYTE 0x02 #define ADC_3BYTE 0x03 #define bool short #define true 1 #define false 0 int adc_decompress(int in_size, unsigned char *input, int avail_size, unsigned char *output, int *bytes_written); int adc_chunk_type(char _byte); int adc_chunk_size(char _byte); int adc_chunk_offset(unsigned char *chunk_start); dmg2img-1.6.7/base64.c000066400000000000000000000041611320511547600143110ustar00rootroot00000000000000/* * DMG2ISO base64.cc * * Copyright (c) 2004 vu1tur This program is free software; you * can redistribute it and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "base64.h" #include bool is_base64(const char c) { if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '+' || c == '/' || c == '=') return true; return false; } void cleanup_base64(char *inp, const unsigned int size) { char *tinp1, *tinp2; unsigned int i; tinp1 = inp; tinp2 = inp; for (i = 0; i < size; i++) { if (is_base64(*tinp2)) { *tinp1++ = *tinp2++; } else { *tinp1 = *tinp2++; } } *(tinp1) = 0; } unsigned char decode_base64_char(const char c) { if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'a' && c <= 'z') return c - 'a' + 26; if (c >= '0' && c <= '9') return c - '0' + 52; if (c == '+') return 62; if (c == '=') return 0; return 63; } void decode_base64(const char *inp, unsigned int isize, char *out, unsigned int *osize) { char *tinp = (char *)inp; char *tout; unsigned int i; *osize = isize / 4 * 3; if (inp != out) { tout = (char *)malloc(*osize); out = tout; } else { tout = tinp; } for (i = 0; i < (isize >> 2); i++) { *tout = decode_base64_char(*tinp++) << 2; *tout++ |= decode_base64_char(*tinp) >> 4; *tout = decode_base64_char(*tinp++) << 4; *tout++ |= decode_base64_char(*tinp) >> 2; *tout = decode_base64_char(*tinp++) << 6; *tout++ |= decode_base64_char(*tinp++); } if (*(tinp - 1) == '=') (*osize)--; if (*(tinp - 2) == '=') (*osize)--; } dmg2img-1.6.7/base64.h000066400000000000000000000017611320511547600143210ustar00rootroot00000000000000/* * DMG2ISO base64.h * * Copyright (c) 2004 vu1tur This program is free software; you * can redistribute it and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define bool short #define true 1 #define false 0 void decode_base64(const char *inp, unsigned int isize, char *out, unsigned int *osize); unsigned char decode_base64_char(const char c); void cleanup_base64(char *inp, const unsigned int size); bool is_base64(const char c); dmg2img-1.6.7/dmg2img.c000066400000000000000000000500461320511547600145560ustar00rootroot00000000000000/* * DMG2IMG dmg2img.c * * Copyright (c) 2004 vu1tur This program is free software; you * can redistribute it and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define _FILE_OFFSET_BITS 64 #define VERSION "dmg2img v1.6.7 (c) vu1tur (to@vu1tur.eu.org)" #define USAGE "\ Usage: dmg2img [-l] [-p N] [-s] [-v] [-V] [-d] []\n\ or dmg2img [-l] [-p N] [-s] [-v] [-V] [-d] -i -o \n\n\ Options: -s (silent) -v (verbose) -V (extremely verbose) -d (debug)\n\ -l (list partitions) -p N (extract only partition N)" #include #include #include #include #include #include "dmg2img.h" #include "base64.h" #include "mntcmd.h" /* take chunk size to be 1 MByte so it will work even with little RAM */ #define CHUNKSIZE 0x100000 #define DECODEDSIZE 0x100000 FILE *FIN = NULL, *FOUT = NULL, *FDBG = NULL; int debug = 0; int verbose = 1; int listparts = 0; int extractpart = -1; double percent; unsigned int offset; void mem_overflow() { printf("ERROR: not enough memory\n"); if (FIN != NULL) fclose(FIN); if (FDBG != NULL) fclose(FDBG); if (FOUT != NULL) fclose(FOUT); exit(-1); } void error_dmg_corrupted() { printf("ERROR: dmg image is corrupted\n"); if (FIN != NULL) fclose(FIN); if (FDBG != NULL) fclose(FDBG); if (FOUT != NULL) fclose(FOUT); exit(-1); } void percentage() { int i, s; char sp[128]; if (verbose < 1) return; s = offset / 0x28; if (verbose >= 3) printf("[%d] %6.2f%%\n", s, percent); else if (verbose == 2) { sprintf(sp, "[%d] %6.2f%%", s, percent); for (i = 0; i < strlen(sp); i++) printf("\b"); printf("%s", sp); } else { sprintf(sp, "%6.2f%%", percent); for (i = 0; i < strlen(sp); i++) printf("\b"); printf("%s", sp); } fflush(stdout); } int main(int argc, char *argv[]) { int i, err, partnum = 0, scb; Bytef *tmp = NULL, *otmp = NULL, *dtmp = NULL; char *input_file = NULL, *output_file = NULL; char *plist = NULL; char *blkx = NULL; unsigned int blkx_size; struct _mishblk *parts = NULL; char *data_begin = NULL, *data_end = NULL; char *partname_begin = NULL, *partname_end = NULL; char *mish_begin = NULL; char partname[255] = ""; unsigned int *partlen = NULL; unsigned int data_size; uint64_t out_offs, out_size, in_offs, in_size, in_offs_add, add_offs, to_read, to_write, chunk; char reserved[5] = " "; char sztype[64] = ""; unsigned int block_type, dw_reserved; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-s")) verbose = 0; else if (!strcmp(argv[i], "-v")) verbose = 2; else if (!strcmp(argv[i], "-V")) verbose = 3; else if (!strcmp(argv[i], "-d")) debug = 1; else if (!strcmp(argv[i], "-l")) listparts = 1; else if (!strcmp(argv[i], "-p")) sscanf(argv[++i], "%d", &extractpart); else if (!strcmp(argv[i], "-i") && i < argc - 1) input_file = argv[++i]; else if (!strcmp(argv[i], "-o") && i < argc - 1) output_file = argv[++i]; else if (!input_file) input_file = argv[i]; else if (!output_file) output_file = argv[i]; } if (!input_file) { printf("\n%s\n\n%s\n\n", VERSION, USAGE); return 0; } if (!output_file) { i = strlen(input_file); output_file = (char *)malloc(i + 6); if (output_file) { strcpy(output_file, input_file); if (i < 4 || strcasecmp(&output_file[i - 4], ".dmg")) strcat(output_file, ".img"); else strcpy(&output_file[i - 4], ".img"); } } if (verbose) printf("\n%s\n\n", VERSION); if (debug) { FDBG = fopen("dmg2img.log", "wb"); if (FDBG == NULL) { debug = 0; printf("ERROR: Can't create dmg2img.log. No debug info will be written.\n"); } } FIN = fopen(input_file, "rb"); if (FIN == NULL) { printf("ERROR: Can't open input file %s\n", input_file); return 1; } //parsing koly block fseeko(FIN, -0x200, SEEK_END); read_kolyblk(FIN, &kolyblk); if (kolyblk.Signature != 0x6b6f6c79) { fseeko(FIN, 0, SEEK_SET); read_kolyblk(FIN, &kolyblk); } char szSignature[5]; szSignature[4] = '\0'; int rSignature = convert_int(kolyblk.Signature); memcpy(szSignature, &rSignature, 4); if (debug) { fprintf(FDBG, "Signature:\t\t0x%08" PRIX32 " (%s)\n", kolyblk.Signature, szSignature); fprintf(FDBG, "Version:\t\t0x%08" PRIX32 "\n", kolyblk.Version); fprintf(FDBG, "HeaderSize:\t\t0x%08" PRIX32 "\n", kolyblk.HeaderSize); fprintf(FDBG, "Flags:\t\t\t0x%08" PRIX32 "\n", kolyblk.Flags); fprintf(FDBG, "RunningDataForkOffset:\t0x%016" PRIX64 "\n", kolyblk.RunningDataForkOffset); fprintf(FDBG, "DataForkOffset:\t\t0x%016" PRIX64 "\n", kolyblk.DataForkOffset); fprintf(FDBG, "DataForkLength:\t\t0x%016" PRIX64 "\n", kolyblk.DataForkLength); fprintf(FDBG, "RsrcForkOffset:\t\t0x%016" PRIX64 "\n", kolyblk.RsrcForkOffset); fprintf(FDBG, "RsrcForkLength:\t\t0x%016" PRIX64 "\n", kolyblk.RsrcForkLength); fprintf(FDBG, "SegmentNumber:\t\t0x%08" PRIX32 "\n", kolyblk.SegmentNumber); fprintf(FDBG, "SegmentCount:\t\t0x%08" PRIX32 "\n", kolyblk.SegmentCount); fprintf(FDBG, "SegmentID:\t\t0x%08" PRIX32 "%08" PRIX32 "%08" PRIX32 "%08" PRIX32 "\n", kolyblk.SegmentID1, kolyblk.SegmentID2, kolyblk.SegmentID3, kolyblk.SegmentID4); fprintf(FDBG, "DataForkChecksumType:\t0x%08" PRIX32 " %s\n", kolyblk.DataForkChecksumType, kolyblk.DataForkChecksumType == 0x02 ? "CRC-32" : ""); fprintf(FDBG, "DataForkChecksum:\t0x%08" PRIX32 "\n", kolyblk.DataForkChecksum); fprintf(FDBG, "XMLOffset:\t\t0x%016" PRIX64 "\n", kolyblk.XMLOffset); fprintf(FDBG, "XMLLength:\t\t0x%016" PRIX64 "\n", kolyblk.XMLLength); fprintf(FDBG, "MasterChecksumType:\t0x%08" PRIX32 " %s\n", kolyblk.MasterChecksumType, kolyblk.MasterChecksumType == 0x02 ? "CRC-32" : ""); fprintf(FDBG, "MasterChecksum:\t\t0x%08" PRIX32 "\n", kolyblk.MasterChecksum); fprintf(FDBG, "ImageVariant:\t\t0x%08" PRIX32 "\n", kolyblk.ImageVariant); fprintf(FDBG, "SectorCount:\t\t0x%016" PRIX64 "\n", kolyblk.SectorCount); fprintf(FDBG, "\n"); } if (kolyblk.Signature != 0x6b6f6c79) { error_dmg_corrupted(); } if (verbose) { if (input_file && (output_file || listparts)) printf("%s --> %s\n\n", input_file, listparts ? "(partition list)" : output_file); } if (debug) printf("Debug info will be written to dmg2img.log\n\n"); if (kolyblk.XMLOffset != 0 && kolyblk.XMLLength != 0) { //We have a plist to parse if (verbose > 1) printf("reading property list, %llu bytes from address %llu ...\n", (unsigned long long)kolyblk.XMLLength, (unsigned long long)kolyblk.XMLOffset); plist = (char *)malloc(kolyblk.XMLLength + 1); if (!plist) mem_overflow(); fseeko(FIN, kolyblk.XMLOffset, SEEK_SET); fread(plist, kolyblk.XMLLength, 1, FIN); plist[kolyblk.XMLLength] = '\0'; if (debug && verbose >= 3) { fprintf(FDBG, "%s\n", plist); } char *_blkx_begin = strstr(plist, blkx_begin); blkx_size = strstr(_blkx_begin, list_end) - _blkx_begin; blkx = (char *)malloc(blkx_size + 1); memcpy(blkx, _blkx_begin, blkx_size); blkx[blkx_size] = '\0'; if (!strstr(plist, plist_begin) || !strstr(&plist[kolyblk.XMLLength - 20], plist_end)) { printf("ERROR: Property list is corrupted.\n"); exit(-1); } data_begin = blkx; partnum = 0; scb = strlen(chunk_begin); while (1) { unsigned int tmplen; data_begin = strstr(data_begin, chunk_begin); if (!data_begin) break; data_begin += scb; data_end = strstr(data_begin, chunk_end); if (!data_end) break; data_size = data_end - data_begin; i = partnum; parts = (struct _mishblk *)realloc(parts, (partnum + 1) * sizeof(struct _mishblk)); if (!parts) mem_overflow(); char *base64data = (char *)malloc(data_size + 1); if (!base64data) mem_overflow(); base64data[data_size] = '\0'; memcpy(base64data, data_begin, data_size); if (verbose >= 3) printf("%s\n", base64data); cleanup_base64(base64data, data_size); decode_base64(base64data, strlen(base64data), base64data, &tmplen); fill_mishblk(base64data, &parts[i]); if (parts[i].BlocksSignature != 0x6D697368) { if (verbose >= 3) printf("Unrecognized block signature %08X", parts[i].BlocksSignature); break; } parts[i].Data = (char *)malloc(parts[i].BlocksRunCount * 0x28); if (!parts[i].Data) mem_overflow(); memcpy(parts[i].Data, base64data + 0xCC, parts[i].BlocksRunCount * 0x28); free(base64data); ++partnum; partname_begin = strstr(data_begin, name_key); partname_begin = strstr(partname_begin, name_begin) + strlen(name_begin); partname_end = strstr(partname_begin, name_end); memset(partname, 0, 255); memcpy(partname, partname_begin, partname_end - partname_begin); if (verbose >= 2) { printf("partition %d: begin=%d, size=%d, decoded=%d\n", i, (int)(data_begin - blkx), data_size, tmplen); if (listparts) printf(" %s\n", partname); } else if (listparts) printf("partition %d: %s\n", i, partname); } } else if (kolyblk.RsrcForkOffset != 0 && kolyblk.RsrcForkLength != 0) { //We have a binary resource fork to parse plist = (char *)malloc(kolyblk.RsrcForkLength); if (!plist) mem_overflow(); fseeko(FIN, kolyblk.RsrcForkOffset, SEEK_SET); fread(plist, kolyblk.RsrcForkLength, 1, FIN); partnum = 0; struct _mishblk mishblk; int next_mishblk = 0; mish_begin = plist + 0x104; while (1) { mish_begin += next_mishblk; if (mish_begin - plist + 0xCC > kolyblk.RsrcForkLength) break; fill_mishblk(mish_begin, &mishblk); if (mishblk.BlocksSignature != 0x6D697368) break; next_mishblk = 0xCC + 0x28 * mishblk.BlocksRunCount + 0x04; i = partnum; ++partnum; parts = (struct _mishblk *)realloc(parts, partnum * sizeof(struct _mishblk)); if (!parts) mem_overflow(); memcpy(&parts[i], &mishblk, sizeof(struct _mishblk)); parts[i].Data = (char *)malloc(0x28 * mishblk.BlocksRunCount); if (!parts[i].Data) mem_overflow(); memcpy(parts[i].Data, mish_begin + 0xCC, 0x28 * mishblk.BlocksRunCount); if (verbose >= 2) printf("partition %d: begin=%d, size=%" PRIu32 "\n", i, (int)(mish_begin - plist), 0xCC + mishblk.BlocksRunCount * 0x28); } } else { error_dmg_corrupted(); } if (listparts || extractpart > partnum-1) { if (extractpart > partnum-1) printf("partition %d not found\n", extractpart); for (i = 0; i < partnum; i++) if (parts[i].Data != NULL) free(parts[i].Data); if (parts != NULL) free(parts); if (plist != NULL) free(plist); if (blkx != NULL) free(blkx); return 0; } if (output_file) FOUT = fopen(output_file, "wb"); else FOUT = NULL; if (FOUT == NULL) { printf("ERROR: Can't create output file %s\n", output_file); fclose(FIN); return 1; } if (verbose) printf("\ndecompressing:\n"); tmp = (Bytef *) malloc(CHUNKSIZE); otmp = (Bytef *) malloc(CHUNKSIZE); dtmp = (Bytef *) malloc(DECODEDSIZE); if (!tmp || !otmp || !dtmp) mem_overflow(); z.zalloc = (alloc_func) 0; z.zfree = (free_func) 0; z.opaque = (voidpf) 0; bz.bzalloc = NULL; bz.bzfree = NULL; bz.opaque = NULL; in_offs = add_offs = in_offs_add = kolyblk.DataForkOffset; for (i = extractpart==-1?0:extractpart; i < (extractpart==-1?partnum:extractpart+1) && in_offs <= kolyblk.DataForkLength - kolyblk.DataForkOffset; i++) { if (verbose) printf("opening partition %d ... ", i); if (verbose >= 3) printf("\n"); else if (verbose) printf(" "); fflush(stdout); offset = 0; add_offs = in_offs_add; block_type = 0; if (debug) { fprintf(FDBG, "\n run..... ..type.... ..reserved ..sectorStart..... ..sectorCount..... ..compOffset...... ..compLength......\n"); } unsigned long bi = 0; while (block_type != BT_TERM && offset < parts[i].BlocksRunCount * 0x28) { block_type = convert_char4((unsigned char *)parts[i].Data + offset); dw_reserved = convert_char4((unsigned char *)parts[i].Data + offset + 4); memcpy(&reserved, parts[i].Data + offset + 4, 4); out_offs = convert_char8((unsigned char *)parts[i].Data + offset + 8) * 0x200; out_size = convert_char8((unsigned char *)parts[i].Data + offset + 16) * 0x200; in_offs = convert_char8((unsigned char *)parts[i].Data + offset + 24); in_size = convert_char8((unsigned char *)parts[i].Data + offset + 32); if (block_type != BT_TERM) in_offs_add = add_offs + in_offs + in_size; if (debug) { switch (block_type) { case BT_ADC: strcpy(sztype, "adc"); break; case BT_ZLIB: strcpy(sztype, "zlib"); break; case BT_BZLIB: strcpy(sztype, "bzlib"); break; case BT_ZERO: strcpy(sztype, "zero"); break; case BT_IGNORE: strcpy(sztype, "ignore"); break; case BT_RAW: strcpy(sztype, "raw"); break; case BT_COMMENT: strcpy(sztype, "comment "); strcat(sztype, reserved); break; case BT_TERM: strcpy(sztype, "terminator"); break; default: sztype[0] = '\0'; } fprintf(FDBG, " 0x%08lX 0x%08lX 0x%08lX 0x%016llX 0x%016llX 0x%016llX 0x%016llX %s\n", (unsigned long)bi, (unsigned long)block_type, (unsigned long)dw_reserved, (unsigned long long)out_offs / 0x200, (unsigned long long)out_size / 0x200, (unsigned long long)in_offs, (unsigned long long)in_size, sztype ); fflush(FDBG); bi++; } if (verbose >= 3) printf("offset = %u block_type = 0x%08x\n", offset, block_type); if (block_type == BT_ZLIB) { if (verbose >= 3) printf("zlib inflate (in_addr=%llu in_size=%llu out_addr=%llu out_size=%llu)\n", (unsigned long long)in_offs, (unsigned long long)in_size, (unsigned long long)out_offs, (unsigned long long)out_size); if (inflateInit(&z) != Z_OK) { printf("ERROR: Can't initialize inflate stream\n"); return 1; } fseeko(FIN, in_offs + add_offs, SEEK_SET); to_read = in_size; do { if (!to_read) break; if (to_read > CHUNKSIZE) chunk = CHUNKSIZE; else chunk = to_read; z.avail_in = fread(tmp, 1, chunk, FIN); if (ferror(FIN)) { (void)inflateEnd(&z); printf("ERROR: reading file %s \n", input_file); return 1; } if (z.avail_in == 0) break; to_read -= z.avail_in; z.next_in = tmp; do { z.avail_out = CHUNKSIZE; z.next_out = otmp; err = inflate(&z, Z_NO_FLUSH); assert(err != Z_STREAM_ERROR); /* state not clobbered */ switch (err) { case Z_NEED_DICT: err = Z_DATA_ERROR; /* and fall through */ case Z_DATA_ERROR: case Z_MEM_ERROR: (void)inflateEnd(&z); printf("ERROR: Inflation failed\n"); return 1; } to_write = CHUNKSIZE - z.avail_out; if (fwrite(otmp, 1, to_write, FOUT) != to_write || ferror(FOUT)) { (void)inflateEnd(&z); printf("ERROR: writing file %s \n", output_file); return 1; } } while (z.avail_out == 0); } while (err != Z_STREAM_END); (void)inflateEnd(&z); } else if (block_type == BT_BZLIB) { if (verbose >= 3) printf("bzip2 decompress (in_addr=%llu in_size=%llu out_addr=%llu out_size=%llu)\n", (unsigned long long)in_offs, (unsigned long long)in_size, (unsigned long long)out_offs, (unsigned long long)out_size); if (BZ2_bzDecompressInit(&bz, 0, 0) != BZ_OK) { printf("ERROR: Can't initialize inflate stream\n"); return 1; } fseeko(FIN, in_offs + add_offs, SEEK_SET); to_read = in_size; do { if (!to_read) break; if (to_read > CHUNKSIZE) chunk = CHUNKSIZE; else chunk = to_read; bz.avail_in = fread(tmp, 1, chunk, FIN); if (ferror(FIN)) { (void)BZ2_bzCompressEnd(&bz); printf("ERROR: reading file %s \n", input_file); return 1; } if (bz.avail_in == 0) break; to_read -= bz.avail_in; bz.next_in = (char *)tmp; do { bz.avail_out = CHUNKSIZE; bz.next_out = (char *)otmp; err = BZ2_bzDecompress(&bz); switch (err) { case BZ_PARAM_ERROR: case BZ_DATA_ERROR: case BZ_DATA_ERROR_MAGIC: case BZ_MEM_ERROR: (void)BZ2_bzDecompressEnd(&bz); printf("ERROR: Inflation failed\n"); return 1; } to_write = CHUNKSIZE - bz.avail_out; if (fwrite(otmp, 1, to_write, FOUT) != to_write || ferror(FOUT)) { (void)BZ2_bzDecompressEnd(&bz); printf("ERROR: writing file %s \n", output_file); return 1; } } while (bz.avail_out == 0); } while (err != BZ_STREAM_END); (void)BZ2_bzDecompressEnd(&bz); } else if (block_type == BT_ADC) { if (verbose >= 3) printf("ADC decompress (in_addr=%llu in_size=%llu out_addr=%llu out_size=%llu)\n", (unsigned long long)in_offs, (unsigned long long)in_size, (unsigned long long)out_offs, (unsigned long long)out_size); fseeko(FIN, in_offs + add_offs, SEEK_SET); to_read = in_size; while (to_read > 0) { chunk = to_read > CHUNKSIZE ? CHUNKSIZE : to_read; to_write = fread(tmp, 1, chunk, FIN); if (ferror(FIN) || to_write < chunk) { printf("ERROR: reading file %s\n", input_file); return 1; } int bytes_written; int read_from_input = adc_decompress(to_write, tmp, DECODEDSIZE, dtmp, &bytes_written); fwrite(dtmp, 1, bytes_written, FOUT); to_read -= read_from_input; } } else if (block_type == BT_RAW) { fseeko(FIN, in_offs + add_offs, SEEK_SET); to_read = in_size; while (to_read > 0) { if (to_read > CHUNKSIZE) chunk = CHUNKSIZE; else chunk = to_read; to_write = fread(tmp, 1, chunk, FIN); if (ferror(FIN) || to_write < chunk) { printf("ERROR: reading file %s \n", input_file); return 1; } fwrite(tmp, 1, chunk, FOUT); //copy to_read -= chunk; } if (verbose >= 3) printf("copy data (in_addr=%llu in_size=%llu out_size=%llu)\n", (unsigned long long)in_offs, (unsigned long long)in_size, (unsigned long long)out_size); } else if (block_type == BT_ZERO || block_type == BT_IGNORE) { memset(tmp, 0, CHUNKSIZE); to_write = out_size; while (to_write > 0) { if (to_write > CHUNKSIZE) chunk = CHUNKSIZE; else chunk = to_write; fwrite(tmp, 1, chunk, FOUT); to_write -= chunk; } if (verbose >= 3) printf("null bytes (out_size=%llu)\n", (unsigned long long)out_size); } else if (block_type == BT_COMMENT) { if (verbose >= 3) printf("0x%08x (in_addr=%llu in_size=%llu out_addr=%llu out_size=%llu) comment %s\n", block_type, (unsigned long long)in_offs, (unsigned long long)in_size, (unsigned long long)out_offs, (unsigned long long)out_size, reserved); } else if (block_type == BT_TERM) { if (in_offs == 0 && partnum > i+1) { if (convert_char8((unsigned char *)parts[i+1].Data + 24) != 0) in_offs_add = kolyblk.DataForkOffset; } else in_offs_add = kolyblk.DataForkOffset; if (verbose >= 3) printf("terminator\n"); } else { if (verbose) printf("\n Unsupported or corrupted block found: %d\n", block_type); } offset += 0x28; if (verbose) { percent = 100 * (double)offset / ((double)parts[i].BlocksRunCount * 0x28); percentage(); } } if (verbose) printf(" ok\n"); } if (verbose) printf("\nArchive successfully decompressed as %s\n", output_file); if (tmp != NULL) free(tmp); if (otmp != NULL) free(otmp); if (dtmp != NULL) free(dtmp); for (i = 0; i < partnum; i++) { if (parts[i].Data != NULL) free(parts[i].Data); } if (parts != NULL) free(parts); if (partlen != NULL) free(partlen); if (plist != NULL) free(plist); if (blkx != NULL) free(blkx); if (FIN != NULL) fclose(FIN); if (FOUT != NULL) fclose(FOUT); if (FDBG != NULL) fclose(FDBG); #if defined(__linux__) if (verbose && extractpart > -1) print_mountcmd(output_file); #endif return 0; } dmg2img-1.6.7/dmg2img.h000066400000000000000000000120031320511547600145520ustar00rootroot00000000000000/* * DMG2IMG dmg2img.h * * Copyright (c) 2004 vu1tur This program is free software; you * can redistribute it and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "adc.h" #include #define BT_ADC 0x80000004 #define BT_ZLIB 0x80000005 #define BT_BZLIB 0x80000006 #define BT_ZERO 0x00000000 #define BT_RAW 0x00000001 #define BT_IGNORE 0x00000002 #define BT_COMMENT 0x7ffffffe #define BT_TERM 0xffffffff #ifdef __MINGW32__ #define fseeko fseeko64 #endif z_stream z; bz_stream bz; const char plist_begin[] = ""; const char plist_end[] = ""; const char list_begin[] = ""; const char list_end[] = ""; const char chunk_begin[] = ""; const char chunk_end[] = ""; const char blkx_begin[] = "blkx"; const char name_key[] = "Name"; const char name_begin[] = ""; const char name_end[] = ""; int convert_int(int i) { int o; char *p_i = (char *) &i; char *p_o = (char *) &o; p_o[0] = p_i[3]; p_o[1] = p_i[2]; p_o[2] = p_i[1]; p_o[3] = p_i[0]; return o; } uint64_t convert_int64(uint64_t i) { uint64_t o; char *p_i = (char *) &i; char *p_o = (char *) &o; p_o[0] = p_i[7]; p_o[1] = p_i[6]; p_o[2] = p_i[5]; p_o[3] = p_i[4]; p_o[4] = p_i[3]; p_o[5] = p_i[2]; p_o[6] = p_i[1]; p_o[7] = p_i[0]; return o; } uint32_t convert_char4(unsigned char *c) { return (((uint32_t) c[0]) << 24) | (((uint32_t) c[1]) << 16) | (((uint32_t) c[2]) << 8) | ((uint32_t) c[3]); } uint64_t convert_char8(unsigned char *c) { return ((uint64_t) convert_char4(c) << 32) | (convert_char4(c + 4)); } struct _kolyblk { uint32_t Signature; uint32_t Version; uint32_t HeaderSize; uint32_t Flags; uint64_t RunningDataForkOffset; uint64_t DataForkOffset; uint64_t DataForkLength; uint64_t RsrcForkOffset; uint64_t RsrcForkLength; uint32_t SegmentNumber; uint32_t SegmentCount; uint32_t SegmentID1; uint32_t SegmentID2; uint32_t SegmentID3; uint32_t SegmentID4; uint32_t DataForkChecksumType; uint32_t Reserved1; uint32_t DataForkChecksum; uint32_t Reserved2; char Reserved3[120]; uint64_t XMLOffset; uint64_t XMLLength; char Reserved4[120]; uint32_t MasterChecksumType; uint32_t Reserved5; uint32_t MasterChecksum; uint32_t Reserved6; char Reserved7[120]; uint32_t ImageVariant; uint64_t SectorCount; char Reserved8[12]; } __attribute__ ((__packed__)); struct _kolyblk kolyblk; struct _mishblk { uint32_t BlocksSignature; uint32_t InfoVersion; uint64_t FirstSectorNumber; uint64_t SectorCount; uint64_t DataStart; uint32_t DecompressedBufferRequested; uint32_t BlocksDescriptor; char Reserved1[24]; uint32_t ChecksumType; uint32_t Reserved2; uint32_t Checksum; uint32_t Reserved3; char Reserved4[120]; uint32_t BlocksRunCount; char *Data; } __attribute__ ((__packed__)); void read_kolyblk(FILE* F, struct _kolyblk* k) { fread(k, 0x200, 1, F); k->Signature = convert_int(k->Signature); k->Version = convert_int(k->Version); k->HeaderSize = convert_int(k->HeaderSize); k->Flags = convert_int(k->Flags); k->RunningDataForkOffset = convert_int64(k->RunningDataForkOffset); k->DataForkOffset = convert_int64(k->DataForkOffset); k->DataForkLength = convert_int64(k->DataForkLength); k->RsrcForkOffset = convert_int64(k->RsrcForkOffset); k->RsrcForkLength = convert_int64(k->RsrcForkLength); k->SegmentNumber = convert_int(k->SegmentNumber); k->SegmentCount = convert_int(k->SegmentCount); k->DataForkChecksumType = convert_int(k->DataForkChecksumType); k->DataForkChecksum = convert_int(k->DataForkChecksum); k->XMLOffset = convert_int64(k->XMLOffset); k->XMLLength = convert_int64(k->XMLLength); k->MasterChecksumType = convert_int(k->MasterChecksumType); k->MasterChecksum = convert_int(k->MasterChecksum); k->ImageVariant = convert_int(k->ImageVariant); k->SectorCount = convert_int64(k->SectorCount); } void fill_mishblk(char* c, struct _mishblk* m) { memset(m, 0, sizeof(struct _mishblk)); memcpy(m, c, 0xCC); m->BlocksSignature = convert_int(m->BlocksSignature); m->InfoVersion = convert_int(m->InfoVersion); m->FirstSectorNumber = convert_int64(m->FirstSectorNumber); m->SectorCount = convert_int64(m->SectorCount); m->DataStart = convert_int64(m->DataStart); m->DecompressedBufferRequested = convert_int(m->DecompressedBufferRequested); m->BlocksDescriptor = convert_int(m->BlocksDescriptor); m->ChecksumType = convert_int(m->ChecksumType); m->Checksum = convert_int(m->Checksum); m->BlocksRunCount = convert_int(m->BlocksRunCount); } dmg2img-1.6.7/gpt.h000066400000000000000000000036671320511547600140360ustar00rootroot00000000000000#define GPT_HDR_SIG "EFI PART" #define GPT_HDR_REVISION 0x00010000 #define GPT_ENT_TYPE_UNUSED \ {0x00000000,0x0000,0x0000,0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}} #define GPT_ENT_TYPE_EFI \ {0xc12a7328,0xf81f,0x11d2,0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}} #define GPT_ENT_TYPE_MBR \ {0x024dee41,0x33e7,0x11d3,0x9d,0x69,{0x00,0x08,0xc7,0x81,0xf3,0x9f}} #define GPT_ENT_TYPE_HFSPLUS \ {0x48465300,0x0000,0x11aa,0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}} #define GPT_ENT_TYPE_APPLEUFS \ {0x55465300,0x0000,0x11aa,0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}} #define GPT_ENT_TYPE_ZFS \ {0x6a898cc3,0x1dd2,0x11b2,0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}} #define GPT_ENT_TYPE_MS_RESERVED \ {0xe3c9e316,0x0b5c,0x4db8,0x81,0x7d,{0xf9,0x2d,0xf0,0x02,0x15,0xae}} #define GPT_ENT_TYPE_MS_BASIC_DATA \ {0xebd0a0a2,0xb9e5,0x4433,0x87,0xc0,{0x68,0xb6,0xb7,0x26,0x99,0xc7}} #define GPT_ENT_TYPE_MS_LDM_METADATA \ {0x5808c8aa,0x7e8f,0x42e0,0x85,0xd2,{0xe1,0xe9,0x04,0x34,0xcf,0xb3}} #define GPT_ENT_TYPE_MS_LDM_DATA \ {0xaf9b60a0,0x1431,0x4f62,0xbc,0x68,{0x33,0x11,0x71,0x4a,0x69,0xad}} struct _guid { uint32_t time_low; uint16_t time_mid; uint16_t time_hi_and_version; uint8_t clock_seq_hi_and_reserved; uint8_t clock_seq_low; uint8_t node[6]; } __attribute__((__packed__)); struct _gpt_header { char hdr_sig[8]; uint32_t hdr_revision; uint32_t hdr_size; uint32_t hdr_crc_self; uint32_t __reserved; uint64_t hdr_lba_self; uint64_t hdr_lba_backup; uint64_t hdr_lba_start; uint64_t hdr_lba_end; struct _guid hdr_guid; uint64_t hdr_lba_table; uint32_t hdr_entries; uint32_t hdr_entsz; uint32_t hdr_crc_table; uint32_t padding; } __attribute__((__packed__)); struct _gpt_entry { struct _guid ent_type; struct _guid ent_guid; uint64_t ent_lba_start; uint64_t ent_lba_end; uint64_t ent_attr; uint16_t name[36]; /* UTF-16 */ } __attribute__((__packed__)); dmg2img-1.6.7/mntcmd.h000066400000000000000000000041501320511547600145120ustar00rootroot00000000000000#include #include "gpt.h" static struct _guid guid_hfsplus = GPT_ENT_TYPE_HFSPLUS; #define EQGUID(a,b) (memcmp(a, b, sizeof(struct _guid)) == 0) void read_gpt_header(FILE * F, struct _gpt_header *h) { memset(h, 0, sizeof(struct _gpt_header)); fread(h, sizeof(struct _gpt_header), 1, F); } void read_gpt_entry(FILE * F, struct _gpt_entry *e) { memset(e, 0, sizeof(struct _gpt_entry)); fread(e, sizeof(struct _gpt_entry), 1, F); } int print_mountcmd(char *filename) { if (!filename) return (-1); unsigned int i, pn = 0; char tmp[128]; struct _gpt_header gpt_header; struct _gpt_entry gpt_entry; struct _gpt_entry *gpt_ent_array; FILE *F = fopen(filename, "rb"); fseeko(F, 0x200, SEEK_SET); read_gpt_header(F, &gpt_header); if (memcmp(gpt_header.hdr_sig, GPT_HDR_SIG, sizeof(gpt_header.hdr_sig)) == 0) { gpt_ent_array = (struct _gpt_entry *)malloc(gpt_header.hdr_entries * sizeof(struct _gpt_entry)); if (!gpt_ent_array) { return (-1); } fseeko(F, 0x400, SEEK_SET); for (i = 0; i < gpt_header.hdr_entries; i++) { fseeko(F, 0x400 + i * gpt_header.hdr_entsz, SEEK_SET); read_gpt_entry(F, &gpt_entry); if (!EQGUID(&guid_hfsplus, &gpt_entry.ent_type)) break; ++pn; memcpy(&gpt_ent_array[i], &gpt_entry, sizeof(struct _gpt_entry)); } printf("\nImage appears to have GUID Partition Table with %d HFS+ partition%s.\n", pn, pn == 1 ? "" : "s"); if (pn > 0) { printf("You should be able to mount %s [as root] by:\n\n", pn == 1 ? "it" : "them"); printf("modprobe hfsplus\n"); for (i = 0; i < pn; i++) { sprintf(tmp, " (for partition %d)", i + 1); printf("mount -t hfsplus -o loop,offset=%" PRIu64 " %s /mnt%s\n", gpt_ent_array[i].ent_lba_start * 0x200, filename, pn > 1 ? tmp : ""); } } else { printf("\ But you might be able to mount the image [as root] by:\n\n\ modprobe hfsplus\n\ mount -t hfsplus -o loop %s /mnt\n\n", filename); } if (F != NULL) fclose(F); free(gpt_ent_array); } else { printf("\n\ You should be able to mount the image [as root] by:\n\n\ modprobe hfsplus\n\ mount -t hfsplus -o loop %s /mnt\n\n", filename); } return (pn); } dmg2img-1.6.7/vfdecrypt.1000066400000000000000000000016331320511547600151520ustar00rootroot00000000000000.TH "vfdecrypt" 1 .SH NAME vfdecrypt \- decrypt encrypted filevault disk images .SH SYNOPSIS .B vfdecrypt -i in-file -p password -o out-file .SH DESCRIPTION vile fault decrypts encrypted Mac OS X disk image files. It supports both version 1 and 2 of the non-documented proprietary format. .SH OPTIONS .TP .B \-i Path to the input file. Usually an encrypted disk image. It's also kosher to redirect from STDIN. .TP .B \-e Try to extract key from input file. .TP .B \-k The alphanumeric key you wish to use to decrypt the disk file. .TP .B \-p The password you wish to use to decrypt the disk file. .TP .B \-o The output file. It's also kosher to redirect to STDOUT. .SH "SEE ALSO" vfcrack(1) .SH BUGS Feel free to report them or to submit patches. .SH AUTHORS Ralf-Philipp Weinmann .TP David Hulton .TP Jacob Appelbaum dmg2img-1.6.7/vfdecrypt.c000066400000000000000000000376001320511547600152370ustar00rootroot00000000000000/* ** Copyright (c) 2006 ** Ralf-Philipp Weinmann ** Jacob Appelbaum ** Christian Fromme ** ** Decrypt a AES-128 encrypted disk image given the encryption key ** and the hmacsha1key of the image. These two keys can be found ** out by running hdiutil attach with -debug on the disk image. ** ** Permission is hereby granted, free of charge, to any person ** obtaining a copy of this software and associated documentation ** files (the "Software"), to deal in the Software without ** restriction, including without limitation the rights to use, ** copy, modify, merge, publish, distribute, sublicense, and/or sell ** copies of the Software, and to permit persons to whom the ** Software is furnished to do so, subject to the following ** conditions: ** ** The above copyright notice and this permission notice shall be ** included in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ** HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ** OTHER DEALINGS IN THE SOFTWARE. **/ #include #include #include #include #include #include #include #include #include #include #define OSSwapHostToBigInt32(x) ntohl(x) /* length of message digest output in bytes (160 bits) */ #define MD_LENGTH 20 /* length of cipher key in bytes (128 bits) */ #define CIPHER_KEY_LENGTH 16 /* block size of cipher in bytes (128 bits) */ #define CIPHER_BLOCKSIZE 16 /* number of iterations for PBKDF2 key derivation */ #define PBKDF2_ITERATION_COUNT 1000 typedef struct { /* 0x000: */ uint8_t filler1[48]; /* 0x034: */ uint32_t kdf_iteration_count; /* 0x034: */ uint32_t kdf_salt_len; /* 0x038: */ uint8_t kdf_salt[48]; /* salt value for key derivation */ /* 0x068: */ uint8_t unwrap_iv[32]; /* IV for encryption-key unwrapping */ /* 0x088: */ uint32_t len_wrapped_aes_key; /* 0x08c: */ uint8_t wrapped_aes_key[296]; /* 0x1b4: */ uint32_t len_hmac_sha1_key; /* 0x1b8: */ uint8_t wrapped_hmac_sha1_key[300]; /* 0x1b4: */ uint32_t len_integrity_key; /* 0x2e8: */ uint8_t wrapped_integrity_key[48]; /* 0x318: */ uint8_t filler6[484]; } cencrypted_v1_header; typedef struct { unsigned char sig[8]; uint32_t version; uint32_t enc_iv_size; uint32_t unk1; uint32_t unk2; uint32_t unk3; uint32_t unk4; uint32_t unk5; unsigned char uuid[16]; uint32_t blocksize; uint64_t datasize; uint64_t dataoffset; uint8_t filler1[0x260]; uint32_t kdf_algorithm; uint32_t kdf_prng_algorithm; uint32_t kdf_iteration_count; uint32_t kdf_salt_len; /* in bytes */ uint8_t kdf_salt[32]; uint32_t blob_enc_iv_size; uint8_t blob_enc_iv[32]; uint32_t blob_enc_key_bits; uint32_t blob_enc_algorithm; uint32_t blob_enc_padding; uint32_t blob_enc_mode; uint32_t encrypted_keyblob_size; uint8_t encrypted_keyblob[0x30]; } cencrypted_v2_pwheader; void print_hex(uint8_t * /* data */, uint32_t /* len */); void convert_hex(char * /* str */, uint8_t * /* bytes */, int /* maxlen */); void dump_v2_header(void * /* hdr */); void adjust_v1_header_byteorder(cencrypted_v1_header * /* hdr */); void adjust_v2_header_byteorder(cencrypted_v2_pwheader * /* pwhdr */); void print_hex(uint8_t *data, uint32_t len) { uint32_t ctr; char *sep; if (len > 64) len = 64; for(ctr = 0; ctr < len; ctr++) { sep = (((ctr&7)==0)&&ctr) ? "\n" : ""; fprintf(stderr, "%s%02x ", sep, data[ctr]); } fprintf(stderr, "\n\n"); } void convert_hex(char *str, uint8_t *bytes, int maxlen) { int bytelen = maxlen; int rpos, wpos = 0; for(rpos = 0; rpos < bytelen; rpos++) { sscanf(&str[rpos*2], "%02hhx", &bytes[wpos++]); } } void dump_v2_header(void *hdr) { cencrypted_v2_pwheader *pwhdr = (cencrypted_v2_pwheader *) hdr; fprintf(stderr, "sig\t%8s\n", pwhdr->sig); fprintf(stderr, "blocksize\t%"PRIX32"\n", pwhdr->blocksize); fprintf(stderr, "datasize\t%"PRIu64"\n", pwhdr->datasize); fprintf(stderr, "dataoffset\t%"PRIu64"\n", pwhdr->dataoffset); /* 103: CSSM_ALGID_PKCS5_PBKDF2 */ fprintf(stderr, "keyDerivationAlgorithm %lu\n", (unsigned long) pwhdr->kdf_algorithm); fprintf(stderr, "keyDerivationPRNGAlgorithm %lu\n", (unsigned long) pwhdr->kdf_prng_algorithm); /* by default the iteration count should be 1000 iterations */ fprintf(stderr, "keyDerivationIterationCount %lu\n", (unsigned long) pwhdr->kdf_iteration_count); fprintf(stderr, "keyDerivationSaltSize %lu\n", (unsigned long) pwhdr->kdf_salt_len); fprintf(stderr, "keyDerivationSalt \n"); print_hex(pwhdr->kdf_salt, pwhdr->kdf_salt_len); fprintf(stderr, "blobEncryptionIVSize %lu\n", (unsigned long) pwhdr->blob_enc_iv_size); fprintf(stderr, "blobEncryptionIV \n"); print_hex(pwhdr->blob_enc_iv, pwhdr->blob_enc_iv_size); fprintf(stderr, "blobEncryptionKeySizeInBits %lu\n", (unsigned long) pwhdr->blob_enc_key_bits); /* 17: CSSM_ALGID_3DES_3KEY_EDE */ fprintf(stderr, "blobEncryptionAlgorithm %lu\n", (unsigned long) pwhdr->blob_enc_algorithm); /* 7: CSSM_PADDING_PKCS7 */ fprintf(stderr, "blobEncryptionPadding %lu\n", (unsigned long) pwhdr->blob_enc_padding); /* 6: CSSM_ALGMODE_CBCPadIV8 */ fprintf(stderr, "blobEncryptionMode %lu\n", (unsigned long) pwhdr->blob_enc_mode); fprintf(stderr, "encryptedBlobSize %lu\n", (unsigned long) pwhdr->encrypted_keyblob_size); fprintf(stderr, "encryptedBlob \n"); print_hex(pwhdr->encrypted_keyblob, pwhdr->encrypted_keyblob_size); } void adjust_v1_header_byteorder(cencrypted_v1_header *hdr) { hdr->kdf_iteration_count = htonl(hdr->kdf_iteration_count); hdr->kdf_salt_len = htonl(hdr->kdf_salt_len); hdr->len_wrapped_aes_key = htonl(hdr->len_wrapped_aes_key); hdr->len_hmac_sha1_key = htonl(hdr->len_hmac_sha1_key); hdr->len_integrity_key = htonl(hdr->len_integrity_key); } #define swap32(x) x = OSSwapHostToBigInt32(x) #define swap64(x) x = ((uint64_t) ntohl(x >> 32)) | (((uint64_t) ntohl((uint32_t) (x & 0xFFFFFFFF))) << 32) void adjust_v2_header_byteorder(cencrypted_v2_pwheader *pwhdr) { swap32(pwhdr->blocksize); swap64(pwhdr->datasize); swap64(pwhdr->dataoffset); pwhdr->kdf_algorithm = htonl(pwhdr->kdf_algorithm); pwhdr->kdf_prng_algorithm = htonl(pwhdr->kdf_prng_algorithm); pwhdr->kdf_iteration_count = htonl(pwhdr->kdf_iteration_count); pwhdr->kdf_salt_len = htonl(pwhdr->kdf_salt_len); pwhdr->blob_enc_iv_size = htonl(pwhdr->blob_enc_iv_size); pwhdr->blob_enc_key_bits = htonl(pwhdr->blob_enc_key_bits); pwhdr->blob_enc_algorithm = htonl(pwhdr->blob_enc_algorithm); pwhdr->blob_enc_padding = htonl(pwhdr->blob_enc_padding); pwhdr->blob_enc_mode = htonl(pwhdr->blob_enc_mode); pwhdr->encrypted_keyblob_size = htonl(pwhdr->encrypted_keyblob_size); } HMAC_CTX hmacsha1_ctx; AES_KEY aes_decrypt_key; int CHUNK_SIZE=4096; // default /** * * Compute IV of current block as * * truncate128(HMAC-SHA1(hmacsha1key||blockno)) * */ void compute_iv(uint32_t chunk_no, uint8_t *iv) { unsigned char mdResult[MD_LENGTH]; unsigned int mdLen; chunk_no = OSSwapHostToBigInt32(chunk_no); HMAC_Init_ex(&hmacsha1_ctx, NULL, 0, NULL, NULL); HMAC_Update(&hmacsha1_ctx, (void *) &chunk_no, sizeof(uint32_t)); HMAC_Final(&hmacsha1_ctx, mdResult, &mdLen); memcpy(iv, mdResult, CIPHER_BLOCKSIZE); } void decrypt_chunk(uint8_t *ctext, uint8_t *ptext, uint32_t chunk_no) { uint8_t iv[CIPHER_BLOCKSIZE]; compute_iv(chunk_no, iv); AES_cbc_encrypt(ctext, ptext, CHUNK_SIZE, &aes_decrypt_key, iv, AES_DECRYPT); } /* DES3-EDE unwrap operation loosely based on to RFC 2630, section 12.6 * wrapped_key has to be 40 bytes in length. */ int apple_des3_ede_unwrap_key(uint8_t *wrapped_key, int wrapped_key_len, uint8_t *decryptKey, uint8_t *unwrapped_key) { EVP_CIPHER_CTX ctx; uint8_t *TEMP1, *TEMP2, *CEKICV; uint8_t IV[8] = { 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05 }; int outlen, tmplen, i; EVP_CIPHER_CTX_init(&ctx); /* result of the decryption operation shouldn't be bigger than ciphertext */ TEMP1 = malloc(wrapped_key_len); TEMP2 = malloc(wrapped_key_len); CEKICV = malloc(wrapped_key_len); /* uses PKCS#7 padding for symmetric key operations by default */ EVP_DecryptInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, decryptKey, IV); if(!EVP_DecryptUpdate(&ctx, TEMP1, &outlen, wrapped_key, wrapped_key_len)) { fprintf(stderr, "internal error (1) during key unwrap operation!\n"); return(-1); } if(!EVP_DecryptFinal_ex(&ctx, TEMP1 + outlen, &tmplen)) { fprintf(stderr, "internal error (2) during key unwrap operation!\n"); return(-1); } outlen += tmplen; EVP_CIPHER_CTX_cleanup(&ctx); /* reverse order of TEMP3 */ for(i = 0; i < outlen; i++) TEMP2[i] = TEMP1[outlen - i - 1]; EVP_CIPHER_CTX_init(&ctx); /* uses PKCS#7 padding for symmetric key operations by default */ EVP_DecryptInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, decryptKey, TEMP2); if(!EVP_DecryptUpdate(&ctx, CEKICV, &outlen, TEMP2+8, outlen-8)) { fprintf(stderr, "internal error (3) during key unwrap operation!\n"); return(-1); } if(!EVP_DecryptFinal_ex(&ctx, CEKICV + outlen, &tmplen)) { fprintf(stderr, "internal error (4) during key unwrap operation!\n"); return(-1); } outlen += tmplen; EVP_CIPHER_CTX_cleanup(&ctx); memcpy(unwrapped_key, CEKICV+4, outlen-4); free(TEMP1); free(TEMP2); free(CEKICV); return(0); } int unwrap_v1_header(char *passphrase, cencrypted_v1_header *header, uint8_t *aes_key, uint8_t *hmacsha1_key) { /* derived key is a 3DES-EDE key */ uint8_t derived_key[192/8]; PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase), (unsigned char*)header->kdf_salt, 20, PBKDF2_ITERATION_COUNT, sizeof(derived_key), derived_key); if (apple_des3_ede_unwrap_key(header->wrapped_aes_key, 40, derived_key, aes_key) != 0) return(-1); if (apple_des3_ede_unwrap_key(header->wrapped_hmac_sha1_key, 48, derived_key, hmacsha1_key) != 0) return(-1); return(0); } int unwrap_v2_header(char *passphrase, cencrypted_v2_pwheader *header, uint8_t *aes_key, uint8_t *hmacsha1_key) { /* derived key is a 3DES-EDE key */ uint8_t derived_key[192/8]; EVP_CIPHER_CTX ctx; uint8_t *TEMP1; int outlen, tmplen; PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase), (unsigned char*)header->kdf_salt, 20, PBKDF2_ITERATION_COUNT, sizeof(derived_key), derived_key); print_hex(derived_key, 192/8); EVP_CIPHER_CTX_init(&ctx); /* result of the decryption operation shouldn't be bigger than ciphertext */ TEMP1 = malloc(header->encrypted_keyblob_size); /* uses PKCS#7 padding for symmetric key operations by default */ EVP_DecryptInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, derived_key, header->blob_enc_iv); if(!EVP_DecryptUpdate(&ctx, TEMP1, &outlen, header->encrypted_keyblob, header->encrypted_keyblob_size)) { fprintf(stderr, "internal error (1) during key unwrap operation!\n"); return(-1); } if(!EVP_DecryptFinal_ex(&ctx, TEMP1 + outlen, &tmplen)) { fprintf(stderr, "internal error (2) during key unwrap operation!\n"); return(-1); } outlen += tmplen; EVP_CIPHER_CTX_cleanup(&ctx); memcpy(aes_key, TEMP1, 16); memcpy(hmacsha1_key, TEMP1, 20); return(0); } int determine_header_version(FILE *dmg) { return(2); } int usage(char *message) { fprintf(stderr, "%s\n", message); fprintf(stderr, "Usage: vfdecrypt [-e] [-p password] [-k key] -i in-file -o out-file\n"); fprintf(stderr, "Option -e attempts to extract key from \n"); exit(1); } int main(int argc, char *argv[]) { FILE *in, *out; cencrypted_v1_header v1header; cencrypted_v2_pwheader v2header; uint8_t hmacsha1_key[20], aes_key[16], inbuf[CHUNK_SIZE], outbuf[CHUNK_SIZE]; uint32_t chunk_no; int hdr_version, c, optError = 0; char inFile[512], outFile[512], passphrase[512], cmd[640]; int iflag = 0, oflag = 0, pflag = 0, kflag = 0, verbose = 0; extern char *optarg; extern int optind, optopt; memset(inFile, 0, 512); memset(outFile, 0, 512); memset(passphrase, 0, 512); memset(cmd, 0, 640); /* This was the key used in iPhone1,1_1.0_1A543a_Restore.ipsw ... */ /* convert_hex("28c909fc6d322fa18940f03279d70880", aes_key, 16); convert_hex("e59a4507998347c70d5b8ca7ef090ecccc15e82d", hmacsha1_key, 20); kflag = 1; */ while((c = getopt(argc, argv, "hvei:o:p:k:")) != -1) { switch(c) { case 'h': usage("Help is on the way. Stay calm."); break; case 'v': verbose++; break; case 'e': *cmd = 1; break; case 'i': if(optarg) strncpy(inFile, optarg, sizeof(inFile)-1); iflag = 1; break; case 'o': if (optarg) strncpy(outFile, optarg, sizeof(outFile)-1); oflag = 1; break; case 'p': if (optarg) strncpy(passphrase, optarg, sizeof(passphrase)-1); pflag = 1; break; case 'k': convert_hex(optarg, aes_key, 16); convert_hex(optarg+32, hmacsha1_key, 20); kflag=1; break; case '?': fprintf(stderr, "Unknown option: -%c\n", optopt); optError++; break; } } /* check to see if our user gave incorrect options */ if (optError) usage("Incorrect arguments."); if (strlen(inFile) == 0) { in = stdin; } else { if ((in = fopen(inFile, "rb")) == NULL) { fprintf(stderr, "Error: unable to open %s\n", inFile); exit(1); } } if (*cmd && *inFile) { sprintf(cmd, "strings %s | grep '^[0-9a-fA-F]*$' | awk '{ if (length($1) == 72) print; }'", inFile); system(cmd); exit(0); } if (strlen(outFile) == 0) { out = stdout; } else { if ((out = fopen(outFile, "wb")) == NULL) { fprintf(stderr, "Error: unable to open %s\n", outFile); exit(1); } } if (!pflag && !kflag) { usage("No Passphrase given."); exit(1); } hdr_version = determine_header_version(in); if (verbose >= 1) { if (hdr_version > 0) { fprintf(stderr, "v%d header detected.\n", hdr_version); } else { fprintf(stderr, "unknown format.\n"); exit(1); } } if (hdr_version == 1) { fseek(in, (long) -sizeof(cencrypted_v1_header), SEEK_END); if (fread(&v1header, sizeof(cencrypted_v1_header), 1, in) < 1) { fprintf(stderr, "header corrupted?\n"), exit(1); } adjust_v1_header_byteorder(&v1header); if(!kflag) unwrap_v1_header(passphrase, &v1header, aes_key, hmacsha1_key); } if (hdr_version == 2) { fseek(in, 0L, SEEK_SET); if (fread(&v2header, sizeof(cencrypted_v2_pwheader), 1, in) < 1) { fprintf(stderr, "header corrupted?\n"), exit(1); } adjust_v2_header_byteorder(&v2header); dump_v2_header(&v2header); if(!kflag) unwrap_v2_header(passphrase, &v2header, aes_key, hmacsha1_key); CHUNK_SIZE = v2header.blocksize; } HMAC_CTX_init(&hmacsha1_ctx); HMAC_Init_ex(&hmacsha1_ctx, hmacsha1_key, sizeof(hmacsha1_key), EVP_sha1(), NULL); AES_set_decrypt_key(aes_key, CIPHER_KEY_LENGTH * 8, &aes_decrypt_key); if (verbose >= 1) { printf("AES Key: \n"); print_hex(aes_key, 16); printf("SHA1 seed: \n"); print_hex(hmacsha1_key, 20); } if (hdr_version == 2) fseek(in, v2header.dataoffset, SEEK_SET); else fseek(in, 0L, SEEK_SET); chunk_no = 0; while(fread(inbuf, CHUNK_SIZE, 1, in) > 0) { decrypt_chunk(inbuf, outbuf, chunk_no); chunk_no++; if(hdr_version == 2 && (v2header.datasize-ftell(out)) < CHUNK_SIZE) { fwrite(outbuf, v2header.datasize - ftell(out), 1, out); break; } fwrite(outbuf, CHUNK_SIZE, 1, out); } if (verbose) fprintf(stderr, "%"PRIX32" chunks written\n", chunk_no); return(0); } dmg2img-1.6.7/vfdecrypt.h000066400000000000000000000102301320511547600152320ustar00rootroot00000000000000#ifndef _FVDECRYPT_H #define _FVDECRYPT_H 1 /* length of message digest output in bytes (160 bits) */ #define MD_LENGTH 20 /* length of cipher key in bytes (128 bits) */ #define CIPHER_KEY_LENGTH 16 /* block size of cipher in bytes (128 bits) */ #define CIPHER_BLOCKSIZE 16 /* chunk size (FileVault specific) */ #define CHUNK_SIZE 4096 /* number of iterations for PBKDF2 key derivation */ #define PBKDF2_ITERATION_COUNT 1000 typedef struct { /* 0x000: */ uint8_t filler1[48]; /* 0x034: */ uint32_t kdf_iteration_count; /* 0x034: */ uint32_t kdf_salt_len; /* 0x038: */ uint8_t kdf_salt[48]; /* salt value for key derivation */ /* 0x068: */ uint8_t unwrap_iv[32]; /* IV for encryption-key unwrapping */ /* 0x088: */ uint32_t len_wrapped_aes_key; /* 0x08c: */ uint8_t wrapped_aes_key[296]; /* 0x1b4: */ uint32_t len_hmac_sha1_key; /* 0x1b8: */ uint8_t wrapped_hmac_sha1_key[300]; /* 0x1b4: */ uint32_t len_integrity_key; /* 0x2e8: */ uint8_t wrapped_integrity_key[48]; /* 0x318: */ uint8_t filler6[484]; } cencrypted_v1_header; /* this structure is valid only if there's a recovery key defined */ typedef struct { unsigned char sig[8]; uint32_t version; uint32_t enc_iv_size; uint32_t unk1; uint32_t unk2; uint32_t unk3; uint32_t unk4; uint32_t unk5; unsigned char uuid[16]; uint32_t blocksize; uint64_t datasize; uint64_t dataoffset; uint8_t filler1[0x260]; uint32_t kdf_algorithm; uint32_t kdf_prng_algorithm; uint32_t kdf_iteration_count; uint32_t kdf_salt_len; /* in bytes */ uint8_t kdf_salt[32]; uint32_t blob_enc_iv_size; uint8_t blob_enc_iv[32]; uint32_t blob_enc_key_bits; uint32_t blob_enc_algorithm; uint32_t blob_enc_padding; uint32_t blob_enc_mode; uint32_t encrypted_keyblob_size; uint8_t encrypted_keyblob[0x30]; } cencrypted_v2_pwheader; /* PasswordHeader: 0x2a8: aHeader.keyDerivationAlgorithm %ld aHeader.keyDerivationPRNGAlgorithm %ld 0x70: aHeader.keyDerivationIterationCount %ld 0x74: aHeader.keyDerivationSaltSize %ld 0x78: aHeader.keyDerivationSalt aHeader.blobEncryptionIVSize %ld aHeader.blobEncryptionIV %ld aHeader.blobEncryptionKeySizeInBits %ld aHeader.blobEncryptionAlgorithm %ld aHeader.blobEncryptionPadding %ld aHeader.blobEncryptionMode %ld aHeader.encryptedBlobSize %ld aHeader.encryptedBlob */ /* aHeader.uuid aHeader.dataBlockSize %u aHeader.keyWrappingAlgorithm %ld aHeader.keyWrappingPadding aHeader.keyWrappingMode %ld aHeader.keyWrappingKeySizeInBits %ld aHeader.keyWrappingIVSize %ld aHeader.keyDerivationAlgorithm %ld aHeader.keyDerivationPRNGAlgorithm %ld aHeader.keyDerivationIterationCount %ld aHeader.keyDerivationSaltSize %ld aHeader.keyDerivationSalt aHeader.encryptionIVSize %ld aHeader.encryptionMode %ld aHeader.encryptionAlgorithm %ld aHeader.encryptionKeySizeInBits %ld aHeader.encryptionKeyWrappingIV aHeader.wrappedEncryptionKeySize %ld aHeader.wrappedEncryptionKey aHeader.prngAlgorithm %ld aHeader.prngKeySizeInBits %ld aHeader.prngKeyWrappingIV aHeader.wrappedPrngKeySize %ld aHeader.wrappedPrngKey aHeader.signingAlgorithm %ld aHeader.signingKeySizeInBits %ld aHeader.signingKeyWrappingIV aHeader.wrappedSigningKeySize %ld aHeader.wrappedSigningKey aHeader.signatureSize %ld aHeader.signature aHeader.dataForkSize %qd aHeader.version %ld aHeader.signature2 %4.4s aHeader.signature1 %4.4s aHeader.version %u aHeader.dataForkStartOffset %qd aHeader.blobEncryptionIVSize %ld aHeader.blobEncryptionIV aHeader.blobEncryptionKeySizeInBits %ld aHeader.blobEncryptionAlgorithm %ld aHeader.blobEncryptionPadding %ld aHeader.blobEncryptionMode %ld aHeader.encryptedBlobSize %ld aHeader.encryptedBlob aHeader.publicKeyHashSize %ld aHeader.publicKeyHash */ #endif