Last active
August 29, 2015 14:11
-
-
Save amartinz/84c7ebc64f126bd6b3a8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
###################################################################### | |
# | |
# File : split_bootimg.pl | |
# Author(s) : William Enck <enck@cse.psu.edu> | |
# Description : Split appart an Android boot image created | |
# with mkbootimg. The format can be found in | |
# android-src/system/core/mkbootimg/bootimg.h | |
# | |
# Thanks to alansj on xda-developers.com for | |
# identifying the format in bootimg.h and | |
# describing initial instructions for splitting | |
# the boot.img file. | |
# | |
# Last Modified : Tue Dec 2 23:36:25 EST 2008 | |
# By : William Enck <enck@cse.psu.edu> | |
# | |
# Copyright (c) 2008 The Pennsylvania State University | |
# Systems and Internet Infrastructure Security Laboratory | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
# | |
# Last Modified : Tue Dec 12 00:12:25 MEZ 2014 | |
# By : Alexander Martinz <eviscerationls@gmail.com> | |
# Comment : Add support for extracting DT images | |
# | |
###################################################################### | |
use strict; | |
use warnings; | |
# Turn on print flushing | |
$|++; | |
###################################################################### | |
## Global Variables and Constants | |
my $SCRIPT = __FILE__; | |
my $IMAGE_FN = undef; | |
# Constants (from bootimg.h) | |
use constant BOOT_MAGIC => 'ANDROID!'; | |
use constant BOOT_MAGIC_SIZE => 8; | |
use constant BOOT_NAME_SIZE => 16; | |
use constant BOOT_ARGS_SIZE => 512; | |
# Unsigned integers are 4 bytes | |
use constant UNSIGNED_SIZE => 4; | |
# Parsed Values | |
my $PAGE_SIZE = undef; | |
my $KERNEL_SIZE = undef; | |
my $RAMDISK_SIZE = undef; | |
my $SECOND_SIZE = undef; | |
my $DT_SIZE = undef; | |
###################################################################### | |
## Main Code | |
&parse_cmdline(); | |
&parse_header($IMAGE_FN); | |
=format (from bootimg.h) | |
** +-----------------+ | |
** | boot header | 1 page | |
** +-----------------+ | |
** | kernel | n pages | |
** +-----------------+ | |
** | ramdisk | m pages | |
** +-----------------+ | |
** | second stage | o pages | |
** +-----------------+ | |
** | device tree | p pages | |
** +-----------------+ | |
=cut | |
my $n = int(($KERNEL_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE); | |
my $m = int(($RAMDISK_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE); | |
my $o = int(($SECOND_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE); | |
my $p = int(($DT_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE); | |
my $k_offset = $PAGE_SIZE; | |
my $r_offset = $k_offset + ($n * $PAGE_SIZE); | |
my $s_offset = $r_offset + ($m * $PAGE_SIZE); | |
my $d_offset = $s_offset + ($o * $PAGE_SIZE); | |
(my $base = $IMAGE_FN) =~ s/.*\/(.*)$/$1/; | |
my $k_file = $base . "-kernel"; | |
my $r_file = $base . "-ramdisk.gz"; | |
my $s_file = $base . "-second.gz"; | |
my $d_file = $base . "-dt.gz"; | |
# The kernel is always there | |
print "Writing $k_file ..."; | |
&dump_file($IMAGE_FN, $k_file, $k_offset, $KERNEL_SIZE); | |
print " complete.\n"; | |
# The ramdisk is always there | |
print "Writing $r_file ..."; | |
&dump_file($IMAGE_FN, $r_file, $r_offset, $RAMDISK_SIZE); | |
print " complete.\n"; | |
# The Second stage bootloader is optional | |
unless ($SECOND_SIZE == 0) { | |
print "Writing $s_file ..."; | |
&dump_file($IMAGE_FN, $s_file, $s_offset, $SECOND_SIZE); | |
print " complete.\n"; | |
} | |
# The Device tree is optional | |
unless ($DT_SIZE == 0) { | |
print "Writing $d_file ..."; | |
&dump_file($IMAGE_FN, $d_file, $d_offset, $DT_SIZE); | |
print " complete.\n"; | |
} | |
###################################################################### | |
## Supporting Subroutines | |
=header_format (from bootimg.h) | |
struct boot_img_hdr | |
{ | |
unsigned char magic[BOOT_MAGIC_SIZE]; | |
unsigned kernel_size; /* size in bytes */ | |
unsigned kernel_addr; /* physical load addr */ | |
unsigned ramdisk_size; /* size in bytes */ | |
unsigned ramdisk_addr; /* physical load addr */ | |
unsigned second_size; /* size in bytes */ | |
unsigned second_addr; /* physical load addr */ | |
unsigned tags_addr; /* physical addr for kernel tags */ | |
unsigned page_size; /* flash page size we assume */ | |
unsigned dt_size; /* device tree in bytes */ | |
unsigned unused; /* future expansion: should be 0 */ | |
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ | |
unsigned char cmdline[BOOT_ARGS_SIZE]; | |
unsigned id[8]; /* timestamp / checksum / sha1 / etc */ | |
/* Supplemental command line data; kept here to maintain | |
* binary compatibility with older versions of mkbootimg */ | |
unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE]; | |
}; | |
=cut | |
sub parse_header { | |
my ($fn) = @_; | |
my $buf = undef; | |
open INF, $fn or die "Could not open $fn: $!\n"; | |
binmode INF; | |
# Read the Magic | |
read(INF, $buf, BOOT_MAGIC_SIZE); | |
unless ($buf eq BOOT_MAGIC) { | |
die "Android Magic not found in $fn. Giving up.\n"; | |
} | |
# Read kernel size and address (assume little-endian) | |
read(INF, $buf, UNSIGNED_SIZE * 2); | |
my ($k_size, $k_addr) = unpack("VV", $buf); | |
# Read ramdisk size and address (assume little-endian) | |
read(INF, $buf, UNSIGNED_SIZE * 2); | |
my ($r_size, $r_addr) = unpack("VV", $buf); | |
# Read second size and address (assume little-endian) | |
read(INF, $buf, UNSIGNED_SIZE * 2); | |
my ($s_size, $s_addr) = unpack("VV", $buf); | |
# Ignore tags_addr | |
read(INF, $buf, UNSIGNED_SIZE); | |
# get the page size (assume little-endian) | |
read(INF, $buf, UNSIGNED_SIZE); | |
my ($p_size) = unpack("V", $buf); | |
# Read dt size | |
read(INF, $buf, UNSIGNED_SIZE); | |
my ($d_size) = unpack("V", $buf); | |
# Ignore unused | |
read(INF, $buf, UNSIGNED_SIZE); | |
# Read the name (board name) | |
read(INF, $buf, BOOT_NAME_SIZE); | |
my $name = $buf; | |
# Read the command line | |
read(INF, $buf, BOOT_ARGS_SIZE); | |
my $cmdline = $buf; | |
# Ignore the id | |
read(INF, $buf, UNSIGNED_SIZE * 8); | |
# Close the file | |
close INF; | |
# Print important values | |
printf "Page size: %d (0x%08x)\n", $p_size, $p_size; | |
printf "Kernel size: %d (0x%08x)\n", $k_size, $k_size; | |
printf "Ramdisk size: %d (0x%08x)\n", $r_size, $r_size; | |
printf "Second size: %d (0x%08x)\n", $s_size, $s_size; | |
printf "DT image size: %d (0x%08x)\n", $d_size, $d_size; | |
printf "Board name: $name\n"; | |
printf "Command line: $cmdline\n"; | |
# Save the values | |
$PAGE_SIZE = $p_size; | |
$KERNEL_SIZE = $k_size; | |
$RAMDISK_SIZE = $r_size; | |
$SECOND_SIZE = $s_size; | |
$DT_SIZE = $d_size; | |
} | |
sub dump_file { | |
my ($infn, $outfn, $offset, $size) = @_; | |
my $buf = undef; | |
open INF, $infn or die "Could not open $infn: $!\n"; | |
open OUTF, ">$outfn" or die "Could not open $outfn: $!\n"; | |
binmode INF; | |
binmode OUTF; | |
seek(INF, $offset, 0) or die "Could not seek in $infn: $!\n"; | |
read(INF, $buf, $size) or die "Could not read $infn: $!\n"; | |
print OUTF $buf or die "Could not write $outfn: $!\n"; | |
close INF; | |
close OUTF; | |
} | |
###################################################################### | |
## Configuration Subroutines | |
sub parse_cmdline { | |
unless ($#ARGV == 0) { | |
die "Usage: $SCRIPT boot.img\n"; | |
} | |
$IMAGE_FN = $ARGV[0]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment