Skip to content

Commit

Permalink
initial contribution
Browse files Browse the repository at this point in the history
  • Loading branch information
szym committed Dec 14, 2010
0 parents commit 5bf5139
Show file tree
Hide file tree
Showing 5 changed files with 323 additions and 0 deletions.
30 changes: 30 additions & 0 deletions Android.mk
@@ -0,0 +1,30 @@

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := mkbootimg.c
LOCAL_STATIC_LIBRARIES := libmincrypt

LOCAL_MODULE := mkbootimg

include $(BUILD_HOST_EXECUTABLE)


include $(CLEAR_VARS)

LOCAL_SRC_FILES := unbootimg.c
LOCAL_STATIC_LIBRARIES := libmincrypt

LOCAL_MODULE := unbootimg

include $(BUILD_HOST_EXECUTABLE)


include $(CLEAR_VARS)

LOCAL_PREBUILT_EXECUTABLES := unpack.sh repack.sh

include $(BUILD_HOST_PREBUILT)


$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
67 changes: 67 additions & 0 deletions README
@@ -0,0 +1,67 @@
Unbootimg
=========

When working on Android, I found it useful to be able to unpack a boot image,
replace a few files and repack it. unbootimg is the perfect complement to the
mkbootimg tool that is used to create boot images.

unbootimg takes a boot image and produces all that is necessary in order to
create a new image using mkbootimg. In particular it extracts the kernel command
line and the addresses of the image parts, and creates a command line for
mkbootimg to regenerate the image as close to the original one. It even verifies
the SHA1 checks!

unpack and repack
-----------------

`unpack.sh` and `repack.sh` are trivial shell wrappers for unbootimg that also
take care of the ramdisk packaging: cpio and gzip. They are designed to
complement, so that this would simply recreate boot.img without changes:

unpack.sh boot.img
repack.sh boot.img

Building
--------

If you already have the AOSP repo and managed to build mkbootimg, adding
unbootimg is easy.

- Download unbootimg.zip
- Unpack it to your mydroid/repo/system/core/mkbootimg. Note: it overwrites
Android.mk to include unbootimg.
- Build it:
cd mydroid/repo
. build/envsetup.sh
mmm system/core/mkbootimg
# OR
make mkbootimg unbootimg repack.sh unpack.sh
- Put `mydroid/repo/out/host/linux-x86/bin` in your path. Easiest way to do this
is:
setpaths # this is defined by Android build system

unbootimg depends (like mkbootimg) on libmincrypt for computing the SHA1, but
this can easily be disabled in the source code.

If you'd rather use pre-built binaries, here's a package with both unbootimg and
mkbootimg: unbootimg-bin.zip

Usage
-----

# on the phone: copy the boot or recovery image, for example
dd if=/dev/mtd/mtd3 of=/sdcard/recovery-backup.img
# on the host: pull the backup
adb pull /sdcard/recovery-backup.img .
# unpack it
unpack.sh recovery-backup.img
# edit as you wish:
# cmdline: recovery-backup.img-mk
# kernel: recovery-backup.img-kernel
# ramdisk: recovery-backup.img-ramdisk/
# repack it
repack.sh recovery-backup.img
# send to phone
adb push recovery-backup.img /sdcard
# flash it using flash_image

21 changes: 21 additions & 0 deletions repack.sh
@@ -0,0 +1,21 @@
#!/bin/bash
# szym.net, 2010
# Simple wrapper that uses mkbootimg to resassemble a boot image
# disassembled with unbootimg (see unpack.sh).

MKBOOTIMG=mkbootimg

if [ $# -ne 1 ]; then
echo 1>&2 Usage: $0 imagefile.img
exit 127
fi

set -e

IMG=$1

cd ${IMG}-ramdisk
find . | cpio -o -H newc | gzip > ../${IMG}-ramdisk.cpio.gz
cd ..
bash -c "${MKBOOTIMG} `cat ${IMG}-mk`"

183 changes: 183 additions & 0 deletions unbootimg.c
@@ -0,0 +1,183 @@
/* tools/unbootimg/unbootimg.c
**
** Copyright 2010 szym.net
**
** A simple utility that reverses the actions of mkbootimg.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#undef NDEBUG
#include <assert.h> // FIXME?

//#define NOMINCRYPT
#ifndef NOMINCRYPT
#include "mincrypt/sha.h"
#endif

#include "bootimg.h"

int usage(void)
{
fprintf(stderr,"usage: unbootimg <filename>\n"
" Creates <filename>-mk <filename>-kernel <filename>-ramdisk.cpio.gz [<filename>-second]\n"
" Remake with mkbootimg `cat <filename>-mk`\n");
return 1;
}

int main(int argc, char **argv)
{
const boot_img_hdr *hdr;

const void *kernel_data = 0;
const void *ramdisk_data = 0;
const void *second_data = 0;
const char *cmdline = 0;
const char *bootimg = 0;
const char *board = 0;
unsigned pagesize = 2048;
int fd;
void *img_data = 0;
unsigned int sz = 0;
#ifndef NOMINCRYPT
SHA_CTX ctx;
const uint8_t* sha;
#endif

unsigned int base;

char buf[256];
FILE *fout;

if (argc != 2) {
return usage();
}

// open img file -- read all into memory
bootimg = argv[1];
fd = open(bootimg, O_RDONLY);
if(fd < 0) {
fprintf(stderr,"Could not open %s\n", bootimg);
return 1;
}
// does not work
sz = lseek(fd, 0, SEEK_END);
assert (sz > 0);

assert(lseek(fd, 0, SEEK_SET) == 0);

img_data = (char*) malloc(sz);
assert(img_data != 0);

assert(read(fd, (char *)img_data, sz) == sz);
close(fd);

// parse and check hdr
hdr = (boot_img_hdr *)img_data;

if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) {
fprintf(stderr,"error: kernel magic mismatch\n");
fprintf(stderr,"%s\n", hdr->magic);
return 1;
}

cmdline = hdr->cmdline;
if(strnlen(cmdline, BOOT_ARGS_SIZE) == BOOT_ARGS_SIZE) {
fprintf(stderr,"error: kernel commandline too large\n");
return 1;
}

board = hdr->name;
if(strnlen(board, BOOT_NAME_SIZE) == BOOT_NAME_SIZE) {
fprintf(stderr,"error: board name too large\n");
return 1;
}

if (hdr->page_size != pagesize) {
fprintf(stderr,"WARNING: non-standard page_size!\n");
pagesize = hdr->page_size;
}

#define PADDED(x) ((((int)(x)-1)/pagesize+1)*pagesize)
kernel_data = (char*)hdr + pagesize;
ramdisk_data = (char*)kernel_data + PADDED(hdr->kernel_size);
second_data = (char*)ramdisk_data + PADDED(hdr->ramdisk_size);
if ((char *)second_data + PADDED(hdr->second_size) != (char *)img_data + sz) {
fprintf(stderr,"section sizes incorrect\nkernel %x %x\nramdisk %x %x\nsecond %x %x\ntotal %x %x\n",
(char*)kernel_data-(char*)hdr, hdr->kernel_size,
(char*)ramdisk_data-(char*)hdr, hdr->ramdisk_size,
(char*)second_data-(char*)hdr, hdr->second_size,
(char *)second_data-(char*)hdr + PADDED(hdr->second_size), sz);
if ((char *)second_data-(char*)hdr + PADDED(hdr->second_size) < sz) {
fprintf(stderr, "...but we can still continue\n");
} else {
return 1;
}
}
#undef PADDED

base = hdr->kernel_addr - 0x00008000;
if ((hdr->ramdisk_addr != base + 0x01000000) ||
(hdr->second_addr != base + 0x00F00000) ||
(hdr->tags_addr != base + 0x00000100)) {
fprintf(stderr,"WARNING: non-standard load addresses!\n");
}

#ifndef NOMINCRYPT
// check hash
SHA_init(&ctx);
SHA_update(&ctx, kernel_data, hdr->kernel_size);
SHA_update(&ctx, &hdr->kernel_size, sizeof(hdr->kernel_size));
SHA_update(&ctx, ramdisk_data, hdr->ramdisk_size);
SHA_update(&ctx, &hdr->ramdisk_size, sizeof(hdr->ramdisk_size));
SHA_update(&ctx, second_data, hdr->second_size);
SHA_update(&ctx, &hdr->second_size, sizeof(hdr->second_size));
sha = SHA_final(&ctx);
if(memcmp(hdr->id, sha,
SHA_DIGEST_SIZE > sizeof(hdr->id) ? sizeof(hdr->id) : SHA_DIGEST_SIZE) != 0) {
fprintf(stderr, "WARNING: SHA checksum does not match\n");
}
#endif

sprintf(buf, "%s-mk", bootimg);
fout = fopen(buf, "w");
if (fout == 0) {
fprintf(stderr,"could not open %s for writing", buf);
return 1;
}
fprintf(fout, "--output %s --kernel %s-kernel --ramdisk %s%s %s %s%s --cmdline '%s' --board '%s' --base %x",
bootimg, bootimg,
hdr->ramdisk_size ? bootimg : "NONE", hdr->ramdisk_size ? "-ramdisk.cpio.gz" : "",
hdr->second_size ? "--second" : "", hdr->second_size ? bootimg : "", hdr->second_size ? "-second" : "",
cmdline, board, base);
fclose(fout);

sprintf(buf, "%s-kernel", bootimg);
fd = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if(fd < 0) {
fprintf(stderr,"error: could not create '%s'\n", buf);
return 1;
}
assert(write(fd, kernel_data, hdr->kernel_size) == hdr->kernel_size);
close(fd);
if(hdr->ramdisk_size) {
sprintf(buf, "%s-ramdisk.cpio.gz", bootimg);
fd = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0644);
assert(fd >= 0);
assert(write(fd, ramdisk_data, hdr->ramdisk_size) == hdr->ramdisk_size);
close(fd);
}
if(hdr->second_size) {
sprintf(buf, "%s-second", bootimg);
fd = open(buf, O_CREAT | O_TRUNC | O_WRONLY, 0644);
assert(fd >= 0);
assert(write(fd, second_data, hdr->second_size) == hdr->second_size);
close(fd);
}
return 0;
}
22 changes: 22 additions & 0 deletions unpack.sh
@@ -0,0 +1,22 @@
#!/bin/bash
# szym.net, 2010
# Simple wrapper that uses unbootimg to disassemble a boot image
# and unzip the ramdisk.

UNBOOTIMG=unbootimg

if [ $# -ne 1 ]; then
echo 1>&2 Usage: $0 imagefile.img
exit 127
fi

set -e

IMG=$1

${UNBOOTIMG} ${IMG}
mkdir ${IMG}-ramdisk
cd ${IMG}-ramdisk
gunzip -c ../${IMG}-ramdisk.cpio.gz | cpio -i
cd ..

0 comments on commit 5bf5139

Please sign in to comment.