1*8a334094SJoseph Chen#!/usr/bin/env python 2*8a334094SJoseph Chen# Copyright 2018, The Android Open Source Project 3*8a334094SJoseph Chen# 4*8a334094SJoseph Chen# Licensed under the Apache License, Version 2.0 (the "License"); 5*8a334094SJoseph Chen# you may not use this file except in compliance with the License. 6*8a334094SJoseph Chen# You may obtain a copy of the License at 7*8a334094SJoseph Chen# 8*8a334094SJoseph Chen# http://www.apache.org/licenses/LICENSE-2.0 9*8a334094SJoseph Chen# 10*8a334094SJoseph Chen# Unless required by applicable law or agreed to in writing, software 11*8a334094SJoseph Chen# distributed under the License is distributed on an "AS IS" BASIS, 12*8a334094SJoseph Chen# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*8a334094SJoseph Chen# See the License for the specific language governing permissions and 14*8a334094SJoseph Chen# limitations under the License. 15*8a334094SJoseph Chen 16*8a334094SJoseph Chen"""unpacks the bootimage. 17*8a334094SJoseph Chen 18*8a334094SJoseph ChenExtracts the kernel, ramdisk, second bootloader, dtb and recovery dtbo images. 19*8a334094SJoseph Chen""" 20*8a334094SJoseph Chen 21*8a334094SJoseph Chenfrom __future__ import print_function 22*8a334094SJoseph Chenfrom argparse import ArgumentParser, FileType 23*8a334094SJoseph Chenfrom struct import unpack 24*8a334094SJoseph Chenimport os 25*8a334094SJoseph Chen 26*8a334094SJoseph Chen 27*8a334094SJoseph Chendef create_out_dir(dir_path): 28*8a334094SJoseph Chen """creates a directory 'dir_path' if it does not exist""" 29*8a334094SJoseph Chen if not os.path.exists(dir_path): 30*8a334094SJoseph Chen os.makedirs(dir_path) 31*8a334094SJoseph Chen 32*8a334094SJoseph Chen 33*8a334094SJoseph Chendef extract_image(offset, size, bootimage, extracted_image_name): 34*8a334094SJoseph Chen """extracts an image from the bootimage""" 35*8a334094SJoseph Chen bootimage.seek(offset) 36*8a334094SJoseph Chen with open(extracted_image_name, 'wb') as file_out: 37*8a334094SJoseph Chen file_out.write(bootimage.read(size)) 38*8a334094SJoseph Chen 39*8a334094SJoseph Chen 40*8a334094SJoseph Chendef get_number_of_pages(image_size, page_size): 41*8a334094SJoseph Chen """calculates the number of pages required for the image""" 42*8a334094SJoseph Chen return (image_size + page_size - 1) / page_size 43*8a334094SJoseph Chen 44*8a334094SJoseph Chen 45*8a334094SJoseph Chendef unpack_bootimage(args): 46*8a334094SJoseph Chen """extracts kernel, ramdisk, second bootloader and recovery dtbo""" 47*8a334094SJoseph Chen boot_magic = unpack('8s', args.boot_img.read(8)) 48*8a334094SJoseph Chen print('boot_magic: %s' % boot_magic) 49*8a334094SJoseph Chen kernel_ramdisk_second_info = unpack('10I', args.boot_img.read(10 * 4)) 50*8a334094SJoseph Chen print('kernel_size: %s' % kernel_ramdisk_second_info[0]) 51*8a334094SJoseph Chen print('kernel load address: %#x' % kernel_ramdisk_second_info[1]) 52*8a334094SJoseph Chen print('ramdisk size: %s' % kernel_ramdisk_second_info[2]) 53*8a334094SJoseph Chen print('ramdisk load address: %#x' % kernel_ramdisk_second_info[3]) 54*8a334094SJoseph Chen print('second bootloader size: %s' % kernel_ramdisk_second_info[4]) 55*8a334094SJoseph Chen print('second bootloader load address: %#x' % kernel_ramdisk_second_info[5]) 56*8a334094SJoseph Chen print('kernel tags load address: %#x' % kernel_ramdisk_second_info[6]) 57*8a334094SJoseph Chen print('page size: %s' % kernel_ramdisk_second_info[7]) 58*8a334094SJoseph Chen print('boot image header version: %s' % kernel_ramdisk_second_info[8]) 59*8a334094SJoseph Chen print('os version and patch level: %s' % kernel_ramdisk_second_info[9]) 60*8a334094SJoseph Chen 61*8a334094SJoseph Chen product_name = unpack('16s', args.boot_img.read(16)) 62*8a334094SJoseph Chen print('product name: %s' % product_name) 63*8a334094SJoseph Chen cmdline = unpack('512s', args.boot_img.read(512)) 64*8a334094SJoseph Chen print('command line args: %s' % cmdline) 65*8a334094SJoseph Chen 66*8a334094SJoseph Chen args.boot_img.read(32) # ignore SHA 67*8a334094SJoseph Chen 68*8a334094SJoseph Chen extra_cmdline = unpack('1024s', args.boot_img.read(1024)) 69*8a334094SJoseph Chen print('additional command line args: %s' % extra_cmdline) 70*8a334094SJoseph Chen 71*8a334094SJoseph Chen kernel_size = kernel_ramdisk_second_info[0] 72*8a334094SJoseph Chen ramdisk_size = kernel_ramdisk_second_info[2] 73*8a334094SJoseph Chen second_size = kernel_ramdisk_second_info[4] 74*8a334094SJoseph Chen page_size = kernel_ramdisk_second_info[7] 75*8a334094SJoseph Chen version = kernel_ramdisk_second_info[8] 76*8a334094SJoseph Chen if version > 0: 77*8a334094SJoseph Chen recovery_dtbo_size = unpack('I', args.boot_img.read(1 * 4))[0] 78*8a334094SJoseph Chen print('recovery dtbo size: %s' % recovery_dtbo_size) 79*8a334094SJoseph Chen recovery_dtbo_offset = unpack('Q', args.boot_img.read(8))[0] 80*8a334094SJoseph Chen print('recovery dtbo offset: %#x' % recovery_dtbo_offset) 81*8a334094SJoseph Chen boot_header_size = unpack('I', args.boot_img.read(4))[0] 82*8a334094SJoseph Chen print('boot header size: %s' % boot_header_size) 83*8a334094SJoseph Chen else: 84*8a334094SJoseph Chen recovery_dtbo_size = 0 85*8a334094SJoseph Chen if version > 1: 86*8a334094SJoseph Chen dtb_size = unpack('I', args.boot_img.read(4))[0] 87*8a334094SJoseph Chen print('dtb size: %s' % dtb_size) 88*8a334094SJoseph Chen dtb_load_address = unpack('Q', args.boot_img.read(8))[0] 89*8a334094SJoseph Chen print('dtb address: %#x' % dtb_load_address) 90*8a334094SJoseph Chen else: 91*8a334094SJoseph Chen dtb_size = 0 92*8a334094SJoseph Chen 93*8a334094SJoseph Chen 94*8a334094SJoseph Chen # The first page contains the boot header 95*8a334094SJoseph Chen num_header_pages = 1 96*8a334094SJoseph Chen 97*8a334094SJoseph Chen num_kernel_pages = get_number_of_pages(kernel_size, page_size) 98*8a334094SJoseph Chen kernel_offset = page_size * num_header_pages # header occupies a page 99*8a334094SJoseph Chen image_info_list = [(kernel_offset, kernel_size, 'kernel')] 100*8a334094SJoseph Chen 101*8a334094SJoseph Chen num_ramdisk_pages = get_number_of_pages(ramdisk_size, page_size) 102*8a334094SJoseph Chen ramdisk_offset = page_size * (num_header_pages + num_kernel_pages 103*8a334094SJoseph Chen ) # header + kernel 104*8a334094SJoseph Chen image_info_list.append((ramdisk_offset, ramdisk_size, 'ramdisk')) 105*8a334094SJoseph Chen 106*8a334094SJoseph Chen if second_size > 0: 107*8a334094SJoseph Chen second_offset = page_size * ( 108*8a334094SJoseph Chen num_header_pages + num_kernel_pages + num_ramdisk_pages 109*8a334094SJoseph Chen ) # header + kernel + ramdisk 110*8a334094SJoseph Chen image_info_list.append((second_offset, second_size, 'second')) 111*8a334094SJoseph Chen 112*8a334094SJoseph Chen if recovery_dtbo_size > 0: 113*8a334094SJoseph Chen image_info_list.append((recovery_dtbo_offset, recovery_dtbo_size, 114*8a334094SJoseph Chen 'recovery_dtbo')) 115*8a334094SJoseph Chen if dtb_size > 0: 116*8a334094SJoseph Chen num_second_pages = get_number_of_pages(second_size, page_size) 117*8a334094SJoseph Chen num_recovery_dtbo_pages = get_number_of_pages(recovery_dtbo_size, page_size) 118*8a334094SJoseph Chen dtb_offset = page_size * ( 119*8a334094SJoseph Chen num_header_pages + num_kernel_pages + num_ramdisk_pages + num_second_pages + 120*8a334094SJoseph Chen num_recovery_dtbo_pages 121*8a334094SJoseph Chen ) 122*8a334094SJoseph Chen 123*8a334094SJoseph Chen image_info_list.append((dtb_offset, dtb_size, 'dtb')) 124*8a334094SJoseph Chen 125*8a334094SJoseph Chen for image_info in image_info_list: 126*8a334094SJoseph Chen extract_image(image_info[0], image_info[1], args.boot_img, 127*8a334094SJoseph Chen os.path.join(args.out, image_info[2])) 128*8a334094SJoseph Chen 129*8a334094SJoseph Chen 130*8a334094SJoseph Chendef parse_cmdline(): 131*8a334094SJoseph Chen """parse command line arguments""" 132*8a334094SJoseph Chen parser = ArgumentParser( 133*8a334094SJoseph Chen description='Unpacks boot.img/recovery.img, extracts the kernel,' 134*8a334094SJoseph Chen 'ramdisk, second bootloader, recovery dtbo and dtb') 135*8a334094SJoseph Chen parser.add_argument( 136*8a334094SJoseph Chen '--boot_img', 137*8a334094SJoseph Chen help='path to boot image', 138*8a334094SJoseph Chen type=FileType('rb'), 139*8a334094SJoseph Chen required=True) 140*8a334094SJoseph Chen parser.add_argument('--out', help='path to out binaries', default='out') 141*8a334094SJoseph Chen return parser.parse_args() 142*8a334094SJoseph Chen 143*8a334094SJoseph Chen 144*8a334094SJoseph Chendef main(): 145*8a334094SJoseph Chen """parse arguments and unpack boot image""" 146*8a334094SJoseph Chen args = parse_cmdline() 147*8a334094SJoseph Chen create_out_dir(args.out) 148*8a334094SJoseph Chen unpack_bootimage(args) 149*8a334094SJoseph Chen 150*8a334094SJoseph Chen 151*8a334094SJoseph Chenif __name__ == '__main__': 152*8a334094SJoseph Chen main() 153