├── Makefile ├── README.md ├── boot-extract.c └── bootimg.h /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS=-Wall 3 | PROGS=boot-extract 4 | 5 | all: $(PROGS) 6 | 7 | boot-extract: boot-extract.c 8 | 9 | clean: 10 | rm -f *.o 11 | rm -f $(PROGS) 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simple tool for extracting kernel, ramdisk and metadata from an 2 | Android boot or recovery image. 3 | 4 | ## To build (on Linux): 5 | ``` 6 | $ make 7 | ``` 8 | ## Usage: 9 | ``` 10 | $ ./boot-extract <-i> [boot or recovery image file] 11 | -i information only: do not extract images 12 | ``` 13 | ## For more information: 14 | * Presentation about Android boot format: 15 | [http://www.slideshare.net/chrissimmonds/android-bootslides20](http://www.slideshare.net/chrissimmonds/android-bootslides20) 16 | 17 | * My blog on implementing fastboot for BeagleBone Black 18 | [http://2net.co.uk/tutorial/fastboot-beaglebone](http://2net.co.uk/tutorial/fastboot-beaglebone) 19 | 20 | -------------------------------------------------------------------------------- /boot-extract.c: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------- */ 2 | /* */ 3 | /* Android Boot image extraction tool */ 4 | /* */ 5 | /* Copyright (C) 2012,2016 Chris Simmonds */ 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 of the License, or */ 10 | /* (at your option) 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 GNU */ 15 | /* 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; if not, write to the Free Software */ 19 | /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 20 | /* */ 21 | /* ------------------------------------------------------------------------- */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | /* bootimg.h is copied from AOSP: 33 | Jelly Bean/4.2: 34 | system/core/mkbootimg/bootimg.h 35 | Earlier releases: 36 | bootable/bootloader/legacy/include/boot/bootimg.h 37 | */ 38 | #include "bootimg.h" 39 | 40 | extern int optind; 41 | 42 | static void usage(char *prog) 43 | { 44 | printf("\nAndroid boot image extraction tool v1.1\n" 45 | "Copyright (C)2012,2016 Chris Simmonds\n\n" 46 | "Usage %s <-i> [boot or recovery image file]\n" 47 | " -i information only: do not extract images\n", prog); 48 | exit(1); 49 | } 50 | 51 | int main(int argc, char **argv) 52 | { 53 | int opt; 54 | int info_only = 0; 55 | int f; 56 | int fk; 57 | int fr; 58 | int n; 59 | char *buf; 60 | unsigned int flash_page_size; 61 | struct boot_img_hdr hdr; 62 | 63 | if (argc == 1) 64 | usage(argv[0]); 65 | 66 | while ((opt = getopt(argc, argv, "hi")) != -1) { 67 | switch (opt) { 68 | case 'i': 69 | info_only = 1; 70 | break; 71 | case 'h': 72 | usage(argv[0]); 73 | default: 74 | exit(1); 75 | } 76 | } 77 | printf("argc %d optind %d\n", argc, optind); 78 | 79 | if (optind == argc) 80 | usage(argv[0]); 81 | 82 | f = open(argv[optind], O_RDONLY); 83 | if (f == -1) { 84 | printf("Failed to open %s (%s)\n", argv[optind], strerror(errno)); 85 | return 1; 86 | } 87 | 88 | n = read(f, &hdr, sizeof(hdr)); 89 | if (n < sizeof(hdr)) { 90 | printf("read failed\n"); 91 | return 1; 92 | } 93 | 94 | if (strncmp((const char *)hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) { 95 | printf("Boot magic missing or corrupt: not a valid boot image\n"); 96 | return 1; 97 | } 98 | 99 | printf("Boot header\n" 100 | " flash page size\t%d\n" 101 | " kernel size\t\t0x%x\n" 102 | " kernel load addr\t0x%x\n" 103 | " ramdisk size\t\t0x%x\n" 104 | " ramdisk load addr\t0x%x\n" 105 | " second size\t\t0x%x\n" 106 | " second load addr\t0x%x\n" 107 | " tags addr\t\t0x%x\n" 108 | " product name\t\t'%s'\n" 109 | " kernel cmdline\t'%s'\n\n", 110 | hdr.page_size, 111 | hdr.kernel_size, hdr.kernel_addr, 112 | hdr.ramdisk_size, hdr.ramdisk_addr, 113 | hdr.second_size, hdr.second_addr, 114 | hdr.tags_addr, hdr.name, hdr.cmdline); 115 | 116 | if (info_only) 117 | return 0; 118 | 119 | flash_page_size = hdr.page_size; 120 | if (hdr.kernel_size > 0) { 121 | /* extract kernel */ 122 | lseek(f, flash_page_size, SEEK_SET); 123 | fk = open("zImage", O_WRONLY | O_CREAT | O_TRUNC, 0644); 124 | if (fk < 0) { 125 | printf("Failed to create kernel file\n"); 126 | return 1; 127 | } 128 | buf = malloc(hdr.kernel_size); 129 | if (buf == 0) { 130 | printf("malloc failed\n"); 131 | return 1; 132 | } 133 | n = read(f, buf, hdr.kernel_size); 134 | if (n != hdr.kernel_size) { 135 | printf ("Error in read\n"); 136 | return 1; 137 | } 138 | write(fk, buf, hdr.kernel_size); 139 | free(buf); 140 | close(fk); 141 | printf("zImage extracted\n"); 142 | } 143 | 144 | if (hdr.ramdisk_size > 0) { 145 | int ramdisk_offset; 146 | 147 | /* extract ramdisk */ 148 | ramdisk_offset = 149 | (((hdr.kernel_size + flash_page_size - 150 | 1) / flash_page_size) + 1) * flash_page_size; 151 | printf("ramdisk offset %d (0x%x)\n", ramdisk_offset, 152 | ramdisk_offset); 153 | 154 | lseek(f, ramdisk_offset, SEEK_SET); 155 | fr = open("ramdisk.cpio.gz", O_WRONLY | O_CREAT | O_TRUNC, 0644); 156 | if (fr < 0) { 157 | printf("Failed to create ramdisk file\n"); 158 | return 1; 159 | } 160 | buf = malloc(hdr.ramdisk_size); 161 | if (buf == 0) { 162 | printf("malloc failed\n"); 163 | return 1; 164 | } 165 | n = read(f, buf, hdr.ramdisk_size); 166 | if (n != hdr.ramdisk_size) { 167 | printf ("Error in read\n"); 168 | return 1; 169 | } 170 | write(fr, buf, hdr.ramdisk_size); 171 | free(buf); 172 | close(fr); 173 | printf("ramdisk.cpio.gz extracted\n"); 174 | } 175 | if (hdr.second_size > 0) { 176 | int second_offset; 177 | 178 | /* extract second binary */ 179 | second_offset = 180 | (((hdr.kernel_size + hdr.ramdisk_size + flash_page_size - 181 | 1) / flash_page_size) + 1) * flash_page_size; 182 | printf("Second binary at offset %d (0x%x)\n", second_offset, 183 | second_offset); 184 | 185 | lseek(f, second_offset, SEEK_SET); 186 | fr = open("second.dtb", O_WRONLY | O_CREAT | O_TRUNC, 0644); 187 | if (fr < 0) { 188 | printf("Failed to create second (dtb) file\n"); 189 | return 1; 190 | } 191 | buf = malloc(hdr.second_size); 192 | if (buf == 0) { 193 | printf("malloc failed\n"); 194 | return 1; 195 | } 196 | n = read(f, buf, hdr.second_size); 197 | if (n != hdr.second_size) { 198 | printf ("Error in read\n"); 199 | return 1; 200 | } 201 | write(fr, buf, hdr.second_size); 202 | free(buf); 203 | close(fr); 204 | printf("second.dtb extracted\n"); 205 | } 206 | 207 | return 0; 208 | } 209 | -------------------------------------------------------------------------------- /bootimg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef _BOOT_IMAGE_H_ 30 | #define _BOOT_IMAGE_H_ 31 | 32 | typedef struct boot_img_hdr boot_img_hdr; 33 | 34 | #define BOOT_MAGIC "ANDROID!" 35 | #define BOOT_MAGIC_SIZE 8 36 | #define BOOT_NAME_SIZE 16 37 | #define BOOT_ARGS_SIZE 512 38 | 39 | struct boot_img_hdr 40 | { 41 | unsigned char magic[BOOT_MAGIC_SIZE]; 42 | 43 | unsigned kernel_size; /* size in bytes */ 44 | unsigned kernel_addr; /* physical load addr */ 45 | 46 | unsigned ramdisk_size; /* size in bytes */ 47 | unsigned ramdisk_addr; /* physical load addr */ 48 | 49 | unsigned second_size; /* size in bytes */ 50 | unsigned second_addr; /* physical load addr */ 51 | 52 | unsigned tags_addr; /* physical addr for kernel tags */ 53 | unsigned page_size; /* flash page size we assume */ 54 | unsigned unused[2]; /* future expansion: should be 0 */ 55 | 56 | unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ 57 | 58 | unsigned char cmdline[BOOT_ARGS_SIZE]; 59 | 60 | unsigned id[8]; /* timestamp / checksum / sha1 / etc */ 61 | }; 62 | 63 | /* 64 | ** +-----------------+ 65 | ** | boot header | 1 page 66 | ** +-----------------+ 67 | ** | kernel | n pages 68 | ** +-----------------+ 69 | ** | ramdisk | m pages 70 | ** +-----------------+ 71 | ** | second stage | o pages 72 | ** +-----------------+ 73 | ** 74 | ** n = (kernel_size + page_size - 1) / page_size 75 | ** m = (ramdisk_size + page_size - 1) / page_size 76 | ** o = (second_size + page_size - 1) / page_size 77 | ** 78 | ** 0. all entities are page_size aligned in flash 79 | ** 1. kernel and ramdisk are required (size != 0) 80 | ** 2. second is optional (second_size == 0 -> no second) 81 | ** 3. load each element (kernel, ramdisk, second) at 82 | ** the specified physical address (kernel_addr, etc) 83 | ** 4. prepare tags at tag_addr. kernel_args[] is 84 | ** appended to the kernel commandline in the tags. 85 | ** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr 86 | ** 6. if second_size != 0: jump to second_addr 87 | ** else: jump to kernel_addr 88 | */ 89 | 90 | boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, 91 | void *ramdisk, unsigned ramdisk_size, 92 | void *second, unsigned second_size, 93 | unsigned page_size, 94 | unsigned *bootimg_size); 95 | 96 | void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline); 97 | #endif 98 | --------------------------------------------------------------------------------