diff --git a/Android.mk b/Android.mk index d7b4251..5a14e38 100644 --- a/Android.mk +++ b/Android.mk @@ -13,10 +13,12 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_UNSTRIPPED_PATH := $(TARGET_OUT_EXECUTABLES_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libc +LOCAL_CFLAGS := -DDEBUG_KMSG +LOCAL_STATIC_LIBRARIES := libc libcutils include $(BUILD_EXECUTABLE) +# bbootimge_host include $(CLEAR_VARS) LOCAL_SRC_FILES:= $(bbootimg_src_file) @@ -36,14 +38,19 @@ LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin LOCAL_MODULE_STEM := bbootimg LOCAL_SRC_FILES:= src/bbootimg.c src/libbootimg.c -LOCAL_SHARED_LIBRARIES := libc -include $(BUILD_EXECUTABLE) +LOCAL_CFLAGS := -DDEBUG_KMSG +LOCAL_SHARED_LIBRARIES := libc libcutils +include $(BUILD_EXECUTABLE) # libbootimg include $(CLEAR_VARS) + LOCAL_SRC_FILES := src/libbootimg.c LOCAL_MODULE := libbootimg LOCAL_MODULE_TAGS := eng + +LOCAL_CFLAGS := -DDEBUG_KMSG + include $(BUILD_STATIC_LIBRARY) diff --git a/include/boot_img_hdr.h b/include/boot_img_hdr.h index e92a423..09d1a22 100644 --- a/include/boot_img_hdr.h +++ b/include/boot_img_hdr.h @@ -20,7 +20,7 @@ #include /* -** +-----------------+ +** +-----------------+ ** | boot header | 1 page ** +-----------------+ ** | kernel | n pages @@ -51,11 +51,25 @@ #define BOOT_MAGIC "ANDROID!" #define BOOT_MAGIC_SIZE 8 -#define BOOT_MAGIC_ELF "ELF" -#define BOOT_MAGIC_ELF_SIZE 3 #define BOOT_NAME_SIZE 16 #define BOOT_ARGS_SIZE 512 +#define BOOT_MAGIC_ELF "ELF" +#define BOOT_MAGIC_ELF_SIZE 3 +#define VER_ELF_1 (1 << 0) +#define VER_ELF_2 (1 << 1) +#define VER_ELF_4 (1 << 3) + +#define OUT_ELF (1 << 0) /* Same output format: ELF container */ +#define OUT_AND (1 << 1) /* Different output format: standard Android container */ + +#define ELF_PROG_KER 0 +#define ELF_PROG_RAM 1 +#define ELF_PROG_RPM 2 +#define ELF_PROG_CMD 3 + +#define ELF_SECT_CMD 0 + struct boot_img_hdr { uint8_t magic[BOOT_MAGIC_SIZE]; @@ -81,58 +95,117 @@ struct boot_img_hdr uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ }; -struct boot_img_hdr_elf +struct boot_img_elf_hdr_32 { - uint8_t magic[8]; /* .ELF (0x00 to 0x07) */ - uint8_t unused[8]; /* unused chars */ - uint16_t type; /* boot type */ - uint16_t machine; /* boot machine */ - uint32_t version; /* boot version */ - uint32_t entry_addr; /* boot entry */ - uint32_t phoff; /* boot phoff */ - uint32_t shoff; /* boot shoff */ - uint32_t flags; /* boot flags */ - uint16_t ehsize; /* boot ehsize */ - uint16_t phentsize; /* boot phentsize */ - uint16_t phnum; /* boot phnum */ - uint16_t shentsize; /* boot shentsize */ - uint16_t shnum; /* boot shnum */ - uint16_t shstrndx; /* boot shstrndx */ - uint32_t kernel_type; /* kernel type (0x34 to 0x37) */ - uint32_t kernel_offset; /* kernel offset (0x38 to 0x3B) */ - uint32_t kernel_vaddr; /* kernel address (0x3C to 0x3F) */ - uint32_t kernel_paddr; /* kernel address duplicate */ - uint32_t kernel_size; /* kernel size (0x44 to 0x47) */ - uint32_t kernel_msize; /* kernel size duplicate */ - uint32_t kernel_flags; /* kernel flags (0x4C to 0x4F) */ - uint32_t kernel_align; /* kernel alignment */ - uint32_t ramdisk_type; /* kernel type (0x54) */ - uint32_t ramdisk_offset; /* ramdisk offset (0x58 to 0x5B) */ - uint32_t ramdisk_vaddr; /* ramdisk address (0x5C to 0x5F) */ - uint32_t ramdisk_paddr; /* ramdisk address duplicate */ - uint32_t ramdisk_size; /* ramdisk size (0x64 to 0x67) */ - uint32_t ramdisk_msize; /* ramdisk size duplicate */ - uint32_t ramdisk_flags; /* ramdisk flags (0x6C to 0x6F) */ - uint32_t ramdisk_align; /* cmdline alignment */ - uint32_t rpm_type; /* rpm type (0x74 to 0x77) */ - uint32_t rpm_offset; /* rpm offset (0x78 to 0x7B) */ - uint32_t rpm_vaddr; /* rpm address (0x7C to 0x7F) */ - uint32_t rpm_paddr; /* rpm address duplicate */ - uint32_t rpm_size; /* rpm size (0x84 to 0x87) */ - uint32_t rpm_msize; /* rpm size duplicate */ - uint32_t rpm_flags; /* rpm flags (0x8C to 0x8F) */ - uint32_t rpm_align; /* rpm alignment */ - uint32_t cmd_type; /* cmdline type (0x94 to 0x97) */ - uint32_t cmd_offset; /* cmdline offset (0x98 to 0x9B) */ - uint32_t cmd_vaddr; /* cmdline address (0x9C to 0x9F) */ - uint32_t cmd_paddr; /* cmdline address duplicate */ - uint32_t cmd_size; /* cmdline size (0xA4 to 0xA7) */ - uint32_t cmd_msize; /* cmdline size duplicate */ - uint32_t cmd_flags; /* cmdline flags (0xAC to 0xAF) */ - uint32_t cmd_align; /* cmdline alignment */ - uint8_t name[BOOT_NAME_SIZE]; /* added - asciiz product name */ + /* Global structure of the Sony ELF header - Respective usual values: | 8960 | 8974 | */ + uint8_t magic[8]; /* .ELF (0x00 to 0x07) | .ELF... | .ELF... | */ + uint8_t unused[8]; /* unused chars (0x08 to 0x0F) | 0x00 | 0x00 | */ + uint16_t type; /* boot type (0x10 to 0x11) | 0x02 | 0x02 | */ + uint16_t machine; /* boot machine (0x12 to 0x13) | 0x28 | 0x28 | */ + uint32_t version; /* boot version (0x14 to 0x17) | 0x01 | 0x01 | */ + uint32_t entry_addr; /* boot entry (0x18 to 0x1B) | 0x80208000 | 0x00008000 | */ + uint32_t phoff; /* boot phoff (0x1C to 0x1F) | 0x34 | 0x34 | */ + uint32_t shoff; /* boot shoff (0x20 to 0x23) | 0x00000000 | 0x00B3.... | */ + uint32_t flags; /* boot flags (0x24 to 0x27) | 0x00 | 0x00 | */ + uint16_t ehsize; /* boot ehsize (0x28 to 0x29) | 0x34 | 0x34 | */ + uint16_t phentsize; /* boot phentsize (0x2A to 0x2B) | 0x20 | 0x20 | */ + uint16_t phnum; /* boot phnum (0x2C to 0x2D) | 0x05/0x04 | 0x03 | */ + uint16_t shentsize; /* boot shentsize (0x2E to 0x2F) | 0x00 | 0x28 | */ + uint16_t shnum; /* boot shnum (0x30 to 0x31) | 0x00 | 0x01 | */ + uint16_t shstrndx; /* boot shstrndx (0x32 to 0x33) | 0x00 | 0x00 | */ +}; + +struct __attribute__((packed)) boot_img_elf_hdr +{ + /* Global structure of the Sony ELF header - Respective usual values: | 8996 | */ + uint8_t magic[8]; /* .ELF (0x00 to 0x07) | .ELF... | */ + uint8_t unused[8]; /* unused chars (0x08 to 0x0F) | 0x00 | */ + uint16_t type; /* boot type (0x10 to 0x11) | 0x02 | */ + uint16_t machine; /* boot machine (0x12 to 0x13) | 0x28 | */ + uint32_t version; /* boot version (0x14 to 0x17) | 0x01 | */ + uint64_t entry_addr; /* boot entry (0x18 to 0x1F) | 0x80080000 | */ + uint64_t phoff; /* boot phoff (0x20 to 0x27) | 0x40 | */ + uint64_t shoff; /* boot shoff (0x28 to 0x2F) | 0x0214.... | */ + uint32_t flags; /* boot flags (0x30 to 0x33) | 0x00 | */ + uint16_t ehsize; /* boot ehsize (0x34 to 0x35) | 0x40 | */ + uint16_t phentsize; /* boot phentsize (0x36 to 0x37) | 0x38 | */ + uint16_t phnum; /* boot phnum (0x38 to 0x39) | 0x03 | */ + uint16_t shentsize; /* boot shentsize (0x3A to 0x3B) | 0x40 | */ + uint16_t shnum; /* boot shnum (0x3C to 0x3D) | 0x01 | */ + uint16_t shstrndx; /* boot shstrndx (0x3E to 0x3F) | 0x00 | */ +}; + +struct boot_img_elf_info +{ + struct boot_img_elf_hdr hdr; /* The ELF file header (64 bits). */ + struct boot_img_elf_hdr_32 hdr_32; /* The ELF file header (32 bits). */ + struct boot_img_elf_prog_hdr* prog; /* The program header entries (64 bits). */ + struct boot_img_elf_prog_hdr_32* prog_32; /* The program header entries (32 bits). */ + struct boot_img_elf_sect_hdr* sect; /* The section header entries (64 bits). */ + struct boot_img_elf_sect_hdr_32* sect_32; /* The section header entries (32 bits). */ + struct boot_img_elf_misc_hdr* misc; /* Miscellaneous information found in some ELF versions. */ + uint8_t elf_architecture; + uint8_t elf_version; + uint8_t elf_out_format; + uint32_t cmdline_size; + uint8_t cmdline_metadata[8]; + uint32_t cmdline_metadata_cnt; + uint8_t* cmdline_signature; + uint32_t cmdline_signature_cnt; }; -typedef struct boot_img_hdr boot_img_hdr; +struct boot_img_elf_prog_hdr_32 +{ + uint32_t type; /* type (position + 0x0 to 0x3) */ + uint32_t offset; /* offset (position + 0x4 to 0x7) */ + uint32_t vaddr; /* address (position + 0x8 to 0xB) */ + uint32_t paddr; /* address duplicate (position + 0xC to 0xF) */ + uint32_t size; /* size (position + 0x10 to 0x13) */ + uint32_t msize; /* size duplicate (position + 0x14 to 0x17) */ + uint32_t flags; /* flags (position + 0x18 to 0x1B) */ + uint32_t align; /* alignment (position + 0x1C to 0x1F)*/ +}; + +struct __attribute__((packed)) boot_img_elf_prog_hdr +{ + uint64_t type; /* type (position + 0x0 to 0x3) */ + uint64_t offset; /* offset (position + 0x4 to 0x7) */ + uint64_t vaddr; /* address (position + 0x8 to 0xF) */ + uint64_t paddr; /* address duplicate (position + 0x10 to 0x17) */ + uint64_t size; /* size (position + 0x18 to 0x1F) */ + uint64_t msize; /* size duplicate (position + 0x20 to 0x23) */ + uint32_t flags; /* flags (position + 0x24 to 0x27) */ + uint32_t align; /* alignment (position + 0x28 to 0x2B)*/ +}; + +struct boot_img_elf_sect_hdr_32 +{ + uint32_t name; + uint32_t type; + uint32_t flags; + uint32_t addr; + uint32_t offset; + uint32_t size; + uint8_t misc[16]; +}; + +struct __attribute__((packed)) boot_img_elf_sect_hdr +{ + uint32_t name; + uint64_t type; + uint32_t flags; + uint64_t addr; + uint64_t offset; + uint64_t size; + uint8_t misc[16]; + uint8_t padding[8]; +}; + +struct boot_img_elf_misc_hdr +{ + uint8_t* data; /* header additional data */ + uint32_t data_size; /* header additional size */ + uint8_t name[BOOT_NAME_SIZE]; /* added - asciiz product name */ +}; #endif diff --git a/include/libbootimg.h b/include/libbootimg.h index 1aed9d1..4b6d51e 100644 --- a/include/libbootimg.h +++ b/include/libbootimg.h @@ -11,11 +11,23 @@ extern "C" { #include #include +#include #include "boot_img_hdr.h" #define LIBBOOTIMG_VERSION 0x000203 // 0xMMNNPP #define LIBBOOTIMG_VERSION_STR "0.2.3" +#ifdef DEBUG_KMSG +#define LOG_DBG(fmt, ...) klog_write(3, "<3>%s: " fmt, "libbootimg", ##__VA_ARGS__) +#elif DEBUG_STDOUT +#define LOG_DBG printf("libbootimg: "); printf +#else +#define LOG_DBG(fmt, ...) "" +#endif + +#define ARCH_32_BITS 0 +#define ARCH_64_BITS 1 + /** * Enum containing possible blob types in a boot image. */ @@ -84,10 +96,12 @@ struct bootimg_blob struct bootimg { struct boot_img_hdr hdr; /*!< Boot image header */ - struct bootimg_blob blobs[LIBBOOTIMG_BLOB_CNT]; /*!< Blobs packed in the boot image. */ - int start_offset; /*!< Offset of the boot image structure from the start of the file. Only used when loading blobs from boot.img file. */ - struct boot_img_hdr_elf* hdr_elf; /*!< Boot image header in ELF format */ + struct bootimg_blob blob; /* Complete blob */ + uint32_t blob_size; /* Size of the complete blob */ + struct bootimg_blob blobs[LIBBOOTIMG_BLOB_CNT]; /*!< Blobs packed in the boot image */ + int start_offset; /*!< Offset of the boot image structure from the start of the file. Only used when loading blobs from boot.img file */ uint8_t is_elf; /*!< Select the ELF boot image format */ + struct boot_img_elf_info* hdr_info; /*!< Boot image meta-information for ELF formats */ }; /** @@ -117,6 +131,71 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma */ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path); +/** + * Determines the ELF boot image version (custom definition) and the + * required output format (ELF or ANDROID!) based on the number of + * program headers given by the ELF header. + * @param hdr_info pointer to the structure holding the read header information + */ +void libbootimg_get_elf_version(struct boot_img_elf_info *hdr_info); + +/** + * Reads the image header from the given ELF file and adds the content + * to the given structure, adapting 32 bits to 64 bits if needed. + * @param hdr_info structure holding the meta-information of the given ELF file + * @param f pointer to the file descriptor of the ELF file + * @return zero on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_header(struct boot_img_elf_info *hdr_info, FILE *f); + +/** + * Reads the program headers from the given ELF file and adds the content + * of each header to the given structure. + * @param hdr_info structure holding the meta-information of the given ELF file + * @param f pointer to the file descriptor of the ELF file + * @return zero on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f); + +/** + * Reads the section headers from the given ELF file and adds the content + * of each header to the given structure. + * @param hdr_info structure holding the meta-information of the given ELF file + * @param f pointer to the file descriptor of the ELF file + * @return zero on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_sect_header(struct boot_img_elf_info *hdr_info, FILE *f); + +/** + * Reads the miscellaneous information from the given ELF file and adds the content + * to the given structure. This information is present in some ELF versions and + * required for them to operate properly (version 1). + * @param hdr_info structure holding the meta-information of the given ELF file + * @param size of the bootimage pagesize needed for alignment + * @param f pointer to the file descriptor of the ELF file + * @return one on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_misc_header(struct boot_img_elf_info *hdr_info, uint32_t page_size, FILE *f); + +/** + * Extracts the kernel boot command line from an ELF file and adds it to + * the generic structure describing the blob (-> hdr). + * @param hdr pointer to boot_img_hdr structure + * @param elf_info structure holding the meta-information of the given ELF file. + * @param f pointer to the file descriptor of the ELF file. + */ +void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info *elf_info, FILE *f); + +/** + * Returns a pointer referencing the ELF program header which describes the content + * of a given type like the kernel or ramdisk part of a boot image. + * @param hdr_info structure holding the meta-information of the given ELF file. + * @param type integer value that describes the desired pointer as given in the enum + * {@link libbootimg_blob_type}. + * @return pointer to the program header describing the desired part of the boot image. + */ +struct boot_img_elf_prog_hdr* get_elf_proc_hdr_of(struct boot_img_elf_info *elf_info, int type); + /** * Loads boot_img_hdr or boot_img_hdr_elf from file on disk * @param hdr pointer to boot_img_hdr structure @@ -127,7 +206,7 @@ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path); * successful, negative value from libbootimg_error if failed. */ int libbootimg_load_headers(struct boot_img_hdr *hdr, - struct boot_img_hdr_elf *hdr_elf, uint8_t *is_elf, const char *path); + struct boot_img_elf_info *hdr_elf, uint8_t *is_elf, const char *path); /** * Updates the header addresses to the blobs. @@ -142,8 +221,6 @@ int libbootimg_update_headers(struct bootimg *b); */ void libbootimg_destroy(struct bootimg *b); - - /** * Writes blob to a file. * @param blob pointer to source struct bootimg_blob @@ -244,6 +321,14 @@ int libbootimg_write_img(struct bootimg *b, const char *dest); */ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f); +/** + * Writes boot image to a file: Updated implementation that effectively *injects* data into an existing boot image + * @param b pointer to struct bootimg + * @param f pointer to FILE to write data into + * @return number of bytes written to the file if successful, negative value from libbootimg_error if failed. + */ +int libbootimg_write_img_fileptr_new(struct bootimg *b, FILE *f); + /** * Writes boot image to a file and then calls libbootimg_destroy. * The bootimg struct is destroyed even if this function fails. @@ -253,6 +338,11 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f); */ int libbootimg_write_img_and_destroy(struct bootimg *b, const char *dest); +/** + * Returns architecture type, 32bits or 64bits + * @return architecture identification ARCH_32_BITS or ARCH_64_BITS + */ +uint8_t libbootimg_architecture(void); /** * Returns version number, format is 0xMMNNPP, so for version 0.1.12 it would return 0x000112 @@ -274,6 +364,41 @@ const char *libbootimg_version_str(void); */ const char *libbootimg_error_str(int error); +/** + * Prints the content of the boot image information to the stdout or + * the kernel log (dmesg). + * @param hdr pointer to the boot image information. + */ +void print_hdr_to_log(struct boot_img_hdr* hdr); + +/** + * Prints the content of an elf header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_info pointer to the elf header information. + */ +void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info); + +/** + * Prints the content of an elf program header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_prog_hdr pointer to the program header information. + */ +void print_elf_prog_hdr_to_log(struct boot_img_elf_prog_hdr* elf_prog_hdr); + +/** + * Prints the content of an elf section header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_sect_hdr pointer to the section header information. + */ +void print_elf_sect_hdr_to_log(struct boot_img_elf_sect_hdr* elf_sect_hdr); + +/** + * Prints the content of an elf misc header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_sect_hdr pointer to the section header information. + */ +void print_elf_misc_hdr_to_log(struct boot_img_elf_misc_hdr* elf_misc_hdr); + #ifdef __cplusplus } #endif diff --git a/src/bbootimg.c b/src/bbootimg.c index aada563..4bc6fdf 100644 --- a/src/bbootimg.c +++ b/src/bbootimg.c @@ -286,12 +286,20 @@ static int print_info(const char *path) img.hdr.cmdline[BOOT_ARGS_SIZE-1] = 0; printf ("\nAndroid Boot Image Info:\n\n"); + printf ("* architecture = %s\n\n", + libbootimg_architecture() == ARCH_64_BITS ? "64bits" : "32bits"); + printf ("* file name = %s\n\n", path); printf ("* image size = %ld bytes (%.2f MB)\n", size, (double)size/0x100000); printf (" page size = %u bytes\n\n", img.hdr.page_size); - printf ("* Boot Name = \"%s\"\n\n", name); + printf ("* Boot Name = \"%s\" [ ", name); + for (i = 0; i < BOOT_NAME_SIZE && name[i] != '\0'; ++i) + { + printf ("0x%02X ", name[i]); + } + printf ("]\n\n", name); printf ("* kernel size = %u bytes (%.2f MB)\n", img.hdr.kernel_size, (double)img.hdr.kernel_size/0x100000); printf (" ramdisk size = %u bytes (%.2f MB)\n", img.hdr.ramdisk_size, (double)img.hdr.ramdisk_size/0x100000); diff --git a/src/libbootimg.c b/src/libbootimg.c index 0e44f3d..988ad0e 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -72,8 +74,13 @@ static void fill_id_hashes(struct bootimg *b) int i = 0; // hash blobs - for(; i < LIBBOOTIMG_BLOB_CNT && i < 5; ++i) - b->hdr.id[i] = calc_fnv_hash(b->blobs[i].data, *b->blobs[i].size); + for (; i < LIBBOOTIMG_BLOB_CNT ; ++i) + { + if (b->blobs[i].size != NULL) + { + b->hdr.id[i] = calc_fnv_hash(b->blobs[i].data, *b->blobs[i].size); + } + } // hash kernel, ramdisk and second _addr and _size together b->hdr.id[i++] = calc_fnv_hash(&b->hdr.kernel_size, sizeof(uint32_t)*6); @@ -92,8 +99,9 @@ void libbootimg_init_new(struct bootimg *img) memset(img, 0, sizeof(struct bootimg)); memcpy(img->hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); img->hdr.page_size = DEFAULT_PAGE_SIZE; - img->hdr_elf = malloc(sizeof(struct boot_img_hdr_elf)); - memset(img->hdr_elf, 0, sizeof(struct boot_img_hdr_elf)); + img->hdr_info = malloc(sizeof(struct boot_img_elf_info)); + memset(img->hdr_info, 0, sizeof(struct boot_img_elf_info)); + img->hdr_info->cmdline_signature = 0; img->is_elf = 0; img->blobs[LIBBOOTIMG_BLOB_KERNEL].size = &img->hdr.kernel_size; @@ -102,6 +110,30 @@ void libbootimg_init_new(struct bootimg *img) img->blobs[LIBBOOTIMG_BLOB_DTB].size = &img->hdr.dt_size; } +int libbootimg_read_blob(int64_t addr, struct bootimg_blob* blob, FILE* f) +{ + int res = 0; + if (fseek(f, addr, SEEK_SET) < 0) + { + if (errno == EINVAL) + { + res = LIBBOOTIMG_ERROR_IMG_EOF; + } + else + { + res = translate_errnum(errno); + } + return res; + } + blob->data = malloc(*blob->size); + if (fread(blob->data, *blob->size, 1, f) != 1) + { + res = translate_fread_error(f); + return res; + } + return res; +} + int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_mask) { int i; @@ -112,7 +144,7 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma libbootimg_init_new(img); - res = libbootimg_load_headers(&img->hdr, img->hdr_elf, &img->is_elf, path); + res = libbootimg_load_headers(&img->hdr, img->hdr_info, &img->is_elf, path); if(res < 0) { libbootimg_destroy(img); @@ -127,38 +159,27 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma addr = img->start_offset + img->hdr.page_size; - for(i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) + for (i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) { blob = &img->blobs[i]; - if((load_blob_mask & (1 << i)) && *blob->size != 0) + if (img->is_elf) { - if(fseek(f, addr, SEEK_SET) < 0) + struct boot_img_elf_prog_hdr *cur_prog_hdr = get_elf_proc_hdr_of(img->hdr_info, i); + if (cur_prog_hdr != NULL) { - if(errno == EINVAL) - res = LIBBOOTIMG_ERROR_IMG_EOF; - else - res = translate_errnum(errno); - goto fail; - } - - blob->data = malloc(*blob->size); - - if(fread(blob->data, *blob->size, 1, f) != 1) - { - res = translate_fread_error(f); - goto fail; + res = libbootimg_read_blob(cur_prog_hdr->offset, blob, f); } } + else if ((load_blob_mask & (1 << i)) && *blob->size != 0) + { + res = libbootimg_read_blob(addr, blob, f); + } if (!img->is_elf) { addr += align_size(*blob->size, img->hdr.page_size); } - else - { - addr += *blob->size; - } } fclose(f); @@ -174,7 +195,11 @@ void libbootimg_destroy(struct bootimg *b) { struct bootimg_blob *blob = b->blobs; struct bootimg_blob * const blobs_end = blob + LIBBOOTIMG_BLOB_CNT; - free(b->hdr_elf); + if (b->hdr_info->cmdline_signature != 0) + { + free(b->hdr_info->cmdline_signature); + } + free(b->hdr_info); for(; blob != blobs_end; ++blob) { free(blob->data); @@ -184,12 +209,12 @@ void libbootimg_destroy(struct bootimg *b) int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path) { - struct boot_img_hdr_elf hdr_elf; + struct boot_img_elf_info hdr_elf; return libbootimg_load_headers(hdr, &hdr_elf, NULL, path); } int libbootimg_load_headers(struct boot_img_hdr *hdr, - struct boot_img_hdr_elf *hdr_elf, uint8_t *is_elf, const char *path) + struct boot_img_elf_info *hdr_info, uint8_t *is_elf, const char *path) { int res = 0; FILE *f; @@ -219,33 +244,99 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, res = known_magic_pos[i]; break; } - else if (hdr_elf != NULL && memcmp(hdr->magic + 1, BOOT_MAGIC_ELF, + else if (hdr_info != NULL && memcmp(hdr->magic + 1, BOOT_MAGIC_ELF, BOOT_MAGIC_ELF_SIZE) == 0) { - fseek(f, 0, SEEK_SET); - if (fread(hdr_elf, sizeof(struct boot_img_hdr_elf), 1, f) == 1) + res = libbootimg_load_elf_header(hdr_info, f); + if (res == 1) { - hdr->kernel_size = hdr_elf->kernel_size; - hdr->kernel_addr = hdr_elf->kernel_offset; - hdr->ramdisk_size = hdr_elf->ramdisk_size; - hdr->ramdisk_addr = hdr_elf->ramdisk_offset; - hdr->second_size = hdr_elf->rpm_size; - hdr->second_addr = hdr_elf->rpm_offset; - hdr->page_size = hdr_elf->kernel_offset; - hdr->tags_addr = 0; - hdr->dt_size = 0; hdr->id[0] = '\0'; - memcpy(hdr->name, hdr_elf->name, BOOT_NAME_SIZE); - cmd_len = hdr_elf->cmd_size; - memset(hdr->cmdline, '\0', BOOT_ARGS_SIZE); - fseek(f, hdr_elf->cmd_offset, SEEK_SET); - fread(hdr->cmdline, cmd_len < BOOT_ARGS_SIZE ? - cmd_len : BOOT_ARGS_SIZE, 1, f); + + libbootimg_get_elf_version(hdr_info); + res = known_magic_pos[i]; if (is_elf != NULL) { *is_elf = 1; + print_elf_hdr_to_log(hdr_info); + } + + res = libbootimg_load_elf_prog_header(hdr_info, f); + if (res != 1) + { + break; + } + + // Update the standard boot image meta-information with + // the information found in the elf file + struct boot_img_elf_prog_hdr *kernel_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_KERNEL); + hdr->kernel_size = kernel_hdr->size; + hdr->kernel_addr = kernel_hdr->offset; + + struct boot_img_elf_prog_hdr *ramdisk_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_RAMDISK); + hdr->ramdisk_size = ramdisk_hdr->size; + hdr->ramdisk_addr = ramdisk_hdr->offset; + + struct boot_img_elf_prog_hdr *second_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_SECOND); + if (second_hdr != NULL) + { + hdr->second_size = second_hdr->size; + hdr->second_addr = second_hdr->offset; + } + else + { + hdr->second_size = 0; + hdr->second_addr = 0; } + + struct boot_img_elf_prog_hdr *dtb_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_DTB); + if (dtb_hdr != NULL) + { + hdr->dt_size = dtb_hdr->size; + hdr->tags_addr = dtb_hdr->offset; + } + else + { + hdr->dt_size = 0; + hdr->tags_addr = 0; + } + + // ELF files version 1 are page aligned, version 2 are not + if (hdr_info->elf_version == VER_ELF_1) + { + hdr->page_size = hdr->kernel_addr; + } + else + { + hdr->page_size = DEFAULT_PAGE_SIZE; + } + + if (hdr_info->elf_version == VER_ELF_1) + { + res = libbootimg_load_elf_misc_header(hdr_info, hdr->page_size, f); + if (res != 1) + { + break; + } + memcpy(hdr->name, hdr_info->misc->name, BOOT_NAME_SIZE); + } + else if (hdr_info->elf_version == VER_ELF_2 || + hdr_info->elf_version == VER_ELF_4) + { + res = libbootimg_load_elf_sect_header(hdr_info, f); + if (res != 1) + { + break; + } + } + + libbootimg_read_cmdline(hdr, hdr_info, f); + + print_hdr_to_log(hdr); break; } } @@ -261,36 +352,543 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, return res; } +void libbootimg_get_elf_version(struct boot_img_elf_info *hdr_info) +{ + if (hdr_info->elf_architecture == ARCH_64_BITS) + { + // Version 4 (found in XP, 8996) has 3 program headers + 1 section header + hdr_info->elf_version = VER_ELF_4; + // Also the bootloader does not load modified elf images + // Output to standard Android container format + hdr_info->elf_out_format = OUT_AND; + } + else + { + switch (hdr_info->hdr.phnum) + { + case 3: + // Version 2 (found in Z2, 8960) has 3 program headers + 1 section header + hdr_info->elf_version = VER_ELF_2; + // Also the bootloader does not load modified elf images + // Output to standard Android container format + hdr_info->elf_out_format = OUT_AND; + break; + case 4: + case 5: + default: + // Version 1 (found in SP, 8960) has 4 program headers + hdr_info->elf_version = VER_ELF_1; + hdr_info->elf_out_format = OUT_ELF; + break; + } + } +} + +int libbootimg_load_elf_header(struct boot_img_elf_info *hdr_info, FILE *f) +{ + int res = 0; + + fseek(f, 0, SEEK_SET); + hdr_info->elf_architecture = libbootimg_architecture(); + + if (hdr_info->elf_architecture == ARCH_64_BITS) + { + LOG_DBG("Reading elf header (64bits).\n"); + res = fread(&hdr_info->hdr, sizeof(struct boot_img_elf_hdr), 1, f); + } + else + { + LOG_DBG("Reading elf header (32bits).\n"); + res = fread(&hdr_info->hdr_32, sizeof(struct boot_img_elf_hdr_32), + 1, f); + if (res == 1) + { + memcpy(hdr_info->hdr.magic, hdr_info->hdr_32.magic, + 8 * sizeof(uint8_t)); + memcpy(hdr_info->hdr.unused, hdr_info->hdr_32.unused, + 8 * sizeof(uint8_t)); + hdr_info->hdr.type = hdr_info->hdr_32.type; + hdr_info->hdr.machine = hdr_info->hdr_32.machine; + hdr_info->hdr.version = hdr_info->hdr_32.version; + hdr_info->hdr.entry_addr = (uint64_t) hdr_info->hdr_32.entry_addr; + hdr_info->hdr.phoff = (uint64_t) hdr_info->hdr_32.phoff; + hdr_info->hdr.shoff = (uint64_t) hdr_info->hdr_32.shoff; + hdr_info->hdr.flags = hdr_info->hdr_32.flags; + hdr_info->hdr.ehsize = hdr_info->hdr_32.ehsize; + hdr_info->hdr.phentsize = hdr_info->hdr_32.phentsize; + hdr_info->hdr.phnum = hdr_info->hdr_32.phnum; + hdr_info->hdr.shentsize = hdr_info->hdr_32.shentsize; + hdr_info->hdr.shnum = hdr_info->hdr_32.shnum; + hdr_info->hdr.shstrndx = hdr_info->hdr_32.shstrndx; + } + } + + return res; +} + +int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f) +{ + int res = 0; + int prog_entry_size = sizeof(struct boot_img_elf_prog_hdr); + struct boot_img_elf_prog_hdr *prog_entry; + prog_entry = malloc(prog_entry_size * hdr_info->hdr.phnum); + hdr_info->prog = prog_entry; + + int prog_entry_idx = 0; + for (; prog_entry_idx < hdr_info->hdr.phnum; ++prog_entry_idx) + { + if (hdr_info->elf_architecture == ARCH_64_BITS) + { + LOG_DBG("Reading program header %u/%u (64bits).\n", + prog_entry_idx + 1, hdr_info->hdr.phnum); + + if (prog_entry_size != hdr_info->hdr.phentsize) + { + LOG_DBG("Program header %u/%u [%u != %u] mismatch.\n", + prog_entry_idx + 1, hdr_info->hdr.phnum, + prog_entry_size, hdr_info->hdr.phentsize); + free(prog_entry); + return 0; + } + + res = fread(&prog_entry[prog_entry_idx], + hdr_info->hdr.phentsize, 1, f); + } + else + { + LOG_DBG("Reading program header %u/%u (32bits).\n", + prog_entry_idx + 1, hdr_info->hdr.phnum); + + int prog_entry_size_32 = sizeof(struct boot_img_elf_prog_hdr_32); + struct boot_img_elf_prog_hdr_32 *prog_entry_32; + prog_entry_32 = malloc(prog_entry_size * hdr_info->hdr_32.phnum); + hdr_info->prog_32 = prog_entry_32; + + if (prog_entry_size_32 != hdr_info->hdr_32.phentsize) + { + LOG_DBG("Program header %u/%u [%u != %u] mismatch.\n", + prog_entry_idx + 1, hdr_info->hdr_32.phnum, + prog_entry_size_32, hdr_info->hdr_32.phentsize); + free(prog_entry_32); + free(prog_entry); + return 0; + } + + res = fread(&prog_entry_32[prog_entry_idx], + hdr_info->hdr_32.phentsize, 1, f); + if (res == 1) + { + prog_entry[prog_entry_idx].type = + (uint64_t) prog_entry_32[prog_entry_idx].type; + prog_entry[prog_entry_idx].offset = + (uint64_t) prog_entry_32[prog_entry_idx].offset; + prog_entry[prog_entry_idx].vaddr = + (uint64_t) prog_entry_32[prog_entry_idx].vaddr; + prog_entry[prog_entry_idx].paddr = + (uint64_t) prog_entry_32[prog_entry_idx].paddr; + prog_entry[prog_entry_idx].size = + (uint64_t) prog_entry_32[prog_entry_idx].size; + prog_entry[prog_entry_idx].msize = + (uint64_t) prog_entry_32[prog_entry_idx].msize; + prog_entry[prog_entry_idx].flags = + prog_entry_32[prog_entry_idx].flags; + prog_entry[prog_entry_idx].align = + prog_entry_32[prog_entry_idx].align; + } + } + + if (res == 1) + { + LOG_DBG("Program header %u/%u successfully read.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + print_elf_prog_hdr_to_log(&hdr_info->prog[prog_entry_idx]); + } + else + { + LOG_DBG("Program header %u/%u read failed.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + break; + } + } + return res; +} + +int libbootimg_load_elf_sect_header(struct boot_img_elf_info *hdr_info, FILE *f) +{ + int res = 0; + int sect_entry_size = sizeof(struct boot_img_elf_sect_hdr); + struct boot_img_elf_sect_hdr *sect_entry; + + fseek(f, hdr_info->hdr.shoff, SEEK_SET); + sect_entry = malloc(sect_entry_size * hdr_info->hdr.shnum); + hdr_info->sect = sect_entry; + + int sect_entry_idx = 0; + for (; sect_entry_idx < hdr_info->hdr.shnum; ++sect_entry_idx) + { + if (hdr_info->elf_architecture == ARCH_64_BITS) + { + LOG_DBG("Reading section header %u/%u (64bits).\n", + sect_entry_idx + 1, hdr_info->hdr.shnum); + + if (sect_entry_size != hdr_info->hdr.shentsize) + { + LOG_DBG("Section header %u/%u [%u != %u] mismatch.\n", + sect_entry_idx + 1, hdr_info->hdr.shnum, + sect_entry_size, hdr_info->hdr.shentsize); + free(sect_entry); + return 0; + } + + res = fread(§_entry[sect_entry_idx], + hdr_info->hdr.shentsize, 1, f); + } + else + { + LOG_DBG("Reading section header %u/%u (32bits).\n", + sect_entry_idx + 1, hdr_info->hdr.shnum); + + int sect_entry_size_32 = sizeof(struct boot_img_elf_sect_hdr_32); + struct boot_img_elf_sect_hdr_32 *sect_entry_32; + sect_entry_32 = malloc(hdr_info->hdr.shentsize * hdr_info->hdr.shnum); + hdr_info->sect_32 = sect_entry_32; + + if (sect_entry_size_32 != hdr_info->hdr_32.shentsize) + { + LOG_DBG("Section header %u/%u [%u != %u] mismatch.\n", + sect_entry_idx + 1, hdr_info->hdr_32.shnum, + sect_entry_size_32, hdr_info->hdr_32.shentsize); + free(sect_entry_32); + free(sect_entry); + return 0; + } + + res = fread(§_entry_32[sect_entry_idx], + hdr_info->hdr_32.shentsize, 1, f); + if (res == 1) + { + sect_entry[sect_entry_idx].name = + sect_entry_32[sect_entry_idx].name; + sect_entry[sect_entry_idx].type = + (uint64_t) sect_entry_32[sect_entry_idx].type; + sect_entry[sect_entry_idx].flags = + sect_entry_32[sect_entry_idx].flags; + sect_entry[sect_entry_idx].addr = + (uint64_t) sect_entry_32[sect_entry_idx].addr; + sect_entry[sect_entry_idx].offset = + (uint64_t) sect_entry_32[sect_entry_idx].offset; + sect_entry[sect_entry_idx].size = + sect_entry_32[sect_entry_idx].size; + memcpy(sect_entry[sect_entry_idx].misc, + sect_entry_32[sect_entry_idx].misc, + 16 * sizeof(uint8_t)); + } + } + + if (res == 1) + { + LOG_DBG("Section header %u/%u successfully read.\n", + sect_entry_idx + 1, hdr_info->hdr.shnum); + print_elf_sect_hdr_to_log(&hdr_info->sect[sect_entry_idx]); + } + else + { + LOG_DBG("Section header %u/%u read failed.\n", + sect_entry_idx + 1, hdr_info->hdr.shnum); + break; + } + } + + return res; +} + +int libbootimg_load_elf_misc_header(struct boot_img_elf_info *hdr_info, uint32_t page_size, FILE *f) +{ + if (hdr_info->elf_version != VER_ELF_1) + { + return -1; + } + + int res = 0; + int misc_entry_size = sizeof(struct boot_img_elf_misc_hdr); + struct boot_img_elf_misc_hdr *misc; + + int misc_offset = hdr_info->hdr.phoff + hdr_info->hdr.phnum * hdr_info->hdr.phentsize; + + fseek(f, misc_offset, SEEK_SET); + misc = malloc(misc_entry_size); + hdr_info->misc = misc; + + misc->data_size = (page_size - misc_offset - sizeof(misc->name)) * + sizeof(uint8_t); + misc->data = malloc(misc->data_size); + + res = fread(misc->data, misc->data_size, 1, f); + if (res == 1) + { + res = fread(misc->name, sizeof(misc->name), 1, f); + } + + LOG_DBG("Misc data size: %u / %u\n", misc->data_size, page_size); + LOG_DBG("Misc boot name: %s\n", misc->name); + + return res; +} + +void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info *elf_info, FILE *f) +{ + unsigned char buf[BOOT_ARGS_SIZE]; + int cmdline_start_pos = 0; + uint32_t cmdline_full_size = 0; + + if (elf_info->elf_version == VER_ELF_1) + { + cmdline_start_pos = elf_info->prog[ELF_PROG_CMD].offset; + elf_info->cmdline_size = elf_info->prog[ELF_PROG_CMD].size; + } + else if (elf_info->elf_version == VER_ELF_2 || + elf_info->elf_version == VER_ELF_4) + { + cmdline_start_pos = elf_info->sect[ELF_SECT_CMD].offset; + elf_info->cmdline_size = elf_info->sect[ELF_SECT_CMD].size; + } + + cmdline_full_size = elf_info->cmdline_size; + elf_info->cmdline_signature = 0; + elf_info->cmdline_signature_cnt = 0; + elf_info->cmdline_size = cmdline_full_size < BOOT_ARGS_SIZE ? + cmdline_full_size : BOOT_ARGS_SIZE; + + memset(&hdr->cmdline, '\0', BOOT_ARGS_SIZE); + fseek(f, cmdline_start_pos, SEEK_SET); + + int buf_idx; + if (elf_info->elf_version == VER_ELF_2 || + elf_info->elf_version == VER_ELF_4) + { + elf_info->cmdline_metadata_cnt = 8; + if (fread(elf_info->cmdline_metadata, 8, 1, f) != 1) + { + LOG_DBG("Cmd line metadata read failed.\n"); + } + } + else + { + elf_info->cmdline_metadata_cnt = 0; + memset(elf_info->cmdline_metadata, + 0, sizeof(elf_info->cmdline_metadata)); + } + + fread(hdr->cmdline, elf_info->cmdline_size, 1, f); + + if (cmdline_full_size > elf_info->cmdline_size) + { + elf_info->cmdline_signature_cnt = + cmdline_full_size - elf_info->cmdline_size; + elf_info->cmdline_signature = malloc( + elf_info->cmdline_signature_cnt * sizeof(uint8_t)); + + LOG_DBG("Cmd line signature size: %u\n", + elf_info->cmdline_signature_cnt); + if (fread(elf_info->cmdline_signature, elf_info->cmdline_signature_cnt, + 1, f) != 1) + { + LOG_DBG("Cmd line signature read failed.\n"); + } + } + + LOG_DBG("Cmd line: %s\n", hdr->cmdline); +} + +struct boot_img_elf_prog_hdr* get_elf_proc_hdr_of(struct boot_img_elf_info *elf_info, int type) +{ + switch (type) + { + case LIBBOOTIMG_BLOB_KERNEL: + return &elf_info->prog[ELF_PROG_KER]; + case LIBBOOTIMG_BLOB_RAMDISK: + return &elf_info->prog[ELF_PROG_RAM]; + case LIBBOOTIMG_BLOB_SECOND: + if (elf_info->elf_version == VER_ELF_1) + { + return &elf_info->prog[ELF_PROG_RPM]; + } + break; + case LIBBOOTIMG_BLOB_DTB: + if (elf_info->elf_version == VER_ELF_2 || + elf_info->elf_version == VER_ELF_4) + { + return &elf_info->prog[ELF_PROG_RPM]; + } + break; + default: + break; + } + return NULL; +} + int libbootimg_update_headers(struct bootimg *b) { - uint32_t addr; + uint32_t addr = 0; if (b == NULL) return translate_errnum(ENOENT); - if (b->is_elf) + if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) { - b->hdr_elf->kernel_size = b->hdr.kernel_size; - b->hdr_elf->kernel_msize = b->hdr.kernel_size; - b->hdr_elf->ramdisk_size = b->hdr.ramdisk_size; - b->hdr_elf->ramdisk_msize = b->hdr.ramdisk_size; - b->hdr_elf->rpm_size = b->hdr.second_size; - b->hdr_elf->rpm_msize = b->hdr.second_size; + b->hdr_info->prog[ELF_PROG_KER].size = b->hdr.kernel_size; + b->hdr_info->prog[ELF_PROG_KER].msize = b->hdr.kernel_size; + b->hdr_info->prog[ELF_PROG_RAM].size = b->hdr.ramdisk_size; + b->hdr_info->prog[ELF_PROG_RAM].msize = b->hdr.ramdisk_size; + + if (b->hdr_info->elf_version == VER_ELF_1) + { + b->hdr_info->prog[ELF_PROG_RPM].size = b->hdr.second_size; + b->hdr_info->prog[ELF_PROG_RPM].msize = b->hdr.second_size; + b->hdr_info->prog[ELF_PROG_CMD].size = b->hdr_info->cmdline_size; + b->hdr_info->prog[ELF_PROG_CMD].msize = b->hdr_info->cmdline_size; + } + else + { + b->hdr_info->prog[ELF_PROG_RPM].size = b->hdr.dt_size; + b->hdr_info->prog[ELF_PROG_RPM].msize = b->hdr.dt_size; + b->hdr_info->prog[ELF_PROG_CMD].size = b->hdr.dt_size; + b->hdr_info->prog[ELF_PROG_CMD].msize = b->hdr.dt_size; + } - addr = b->hdr_elf->kernel_offset; + LOG_DBG("Updating program headers...\n"); - addr += b->hdr_elf->kernel_size; - b->hdr_elf->ramdisk_offset = addr; + addr = b->hdr_info->prog[ELF_PROG_KER].offset; - addr += b->hdr_elf->ramdisk_size; - b->hdr_elf->rpm_offset = addr; + addr += b->hdr_info->prog[ELF_PROG_KER].size; + b->hdr_info->prog[ELF_PROG_RAM].offset = addr; - addr += b->hdr_elf->rpm_size; - b->hdr_elf->cmd_offset = addr; + addr += b->hdr_info->prog[ELF_PROG_RAM].size; + b->hdr_info->prog[ELF_PROG_RPM].offset = addr; - memcpy(b->hdr_elf->name, b->hdr.name, BOOT_NAME_SIZE); + addr += b->hdr_info->prog[ELF_PROG_RPM].size; + + if (b->hdr_info->elf_version == VER_ELF_1) + { + b->hdr_info->prog[ELF_PROG_CMD].offset = addr; + addr += b->hdr_info->prog[ELF_PROG_CMD].size; + } + + // Also, we need to update the address/offset pointers & sizes + // in the section header table + int sect_entry_idx = 0; + for (; sect_entry_idx < b->hdr_info->hdr.shnum; ++sect_entry_idx) + { + LOG_DBG("Updating section header entry %d/%d...\n", + sect_entry_idx + 1, b->hdr_info->hdr.shnum); + b->hdr_info->sect[sect_entry_idx].offset = addr; + addr += b->hdr_info->sect[sect_entry_idx].size; + } + + if (b->hdr_info->elf_version == VER_ELF_1) + { + LOG_DBG("Updating misc header: name %s...\n", b->hdr.name); + memcpy(b->hdr_info->misc->name, b->hdr.name, BOOT_NAME_SIZE); + } + + // The section header is placed after the last section + if (b->hdr_info->hdr.shnum > 0) + { + b->hdr_info->hdr.shoff = addr; + } + + // Update 32 bits structures + if (b->hdr_info->elf_architecture != ARCH_64_BITS) + { + // Update boot_img_elf_hdr_32 + memcpy(b->hdr_info->hdr_32.magic, b->hdr_info->hdr.magic, + 8 * sizeof(uint8_t)); + memcpy(b->hdr_info->hdr_32.unused, b->hdr_info->hdr.unused, + 8 * sizeof(uint8_t)); + b->hdr_info->hdr_32.type = b->hdr_info->hdr.type; + b->hdr_info->hdr_32.machine = b->hdr_info->hdr.machine; + b->hdr_info->hdr_32.version = b->hdr_info->hdr.version; + b->hdr_info->hdr_32.entry_addr = + (uint32_t) b->hdr_info->hdr.entry_addr; + b->hdr_info->hdr_32.phoff = + (uint32_t) b->hdr_info->hdr.phoff; + b->hdr_info->hdr_32.shoff = + (uint32_t) b->hdr_info->hdr.shoff; + b->hdr_info->hdr_32.flags = b->hdr_info->hdr.flags; + b->hdr_info->hdr_32.ehsize = b->hdr_info->hdr.ehsize; + b->hdr_info->hdr_32.phentsize = b->hdr_info->hdr.phentsize; + b->hdr_info->hdr_32.phnum = b->hdr_info->hdr.phnum; + b->hdr_info->hdr_32.shentsize = b->hdr_info->hdr.shentsize; + b->hdr_info->hdr_32.shnum = b->hdr_info->hdr.shnum; + b->hdr_info->hdr_32.shstrndx = b->hdr_info->hdr.shstrndx; + + // Update boot_img_elf_prog_hdr_32 + int prog_entry_idx = 0; + for (; prog_entry_idx < b->hdr_info->hdr.phnum; ++prog_entry_idx) + { + LOG_DBG("Syncing program header 32bits entry %d/%d.\n", + prog_entry_idx + 1, b->hdr_info->hdr_32.phnum); + b->hdr_info->prog_32[prog_entry_idx].type = + (uint32_t) b->hdr_info->prog[prog_entry_idx].type; + b->hdr_info->prog_32[prog_entry_idx].offset = + (uint32_t) b->hdr_info->prog[prog_entry_idx].offset; + b->hdr_info->prog_32[prog_entry_idx].vaddr = + (uint32_t) b->hdr_info->prog[prog_entry_idx].vaddr; + b->hdr_info->prog_32[prog_entry_idx].paddr = + (uint32_t) b->hdr_info->prog[prog_entry_idx].paddr; + b->hdr_info->prog_32[prog_entry_idx].size = + (uint32_t) b->hdr_info->prog[prog_entry_idx].size; + b->hdr_info->prog_32[prog_entry_idx].msize = + (uint32_t) b->hdr_info->prog[prog_entry_idx].msize; + b->hdr_info->prog_32[prog_entry_idx].flags = + b->hdr_info->prog[prog_entry_idx].flags; + b->hdr_info->prog_32[prog_entry_idx].align = + b->hdr_info->prog[prog_entry_idx].align; + } + + // Update boot_img_elf_sect_hdr_32 + sect_entry_idx = 0; + for (; sect_entry_idx < b->hdr_info->hdr.shnum; ++sect_entry_idx) + { + LOG_DBG("Syncing section header 32bits entry %d/%d.\n", + sect_entry_idx + 1, b->hdr_info->hdr_32.shnum); + b->hdr_info->sect_32[sect_entry_idx].name = + b->hdr_info->sect[sect_entry_idx].name; + b->hdr_info->sect_32[sect_entry_idx].type = + (uint32_t) b->hdr_info->sect[sect_entry_idx].type; + b->hdr_info->sect_32[sect_entry_idx].flags = + b->hdr_info->sect[sect_entry_idx].flags; + b->hdr_info->sect_32[sect_entry_idx].addr = + (uint32_t) b->hdr_info->sect[sect_entry_idx].addr; + b->hdr_info->sect_32[sect_entry_idx].offset = + (uint32_t) b->hdr_info->sect[sect_entry_idx].offset; + b->hdr_info->sect_32[sect_entry_idx].size = + (uint32_t) b->hdr_info->sect[sect_entry_idx].size; + memcpy(b->hdr_info->sect_32[sect_entry_idx].misc, + b->hdr_info->sect[sect_entry_idx].misc, + 16 * sizeof(uint8_t)); + } + } + } + else if (b->is_elf && b->hdr_info->elf_out_format == OUT_AND) + { + // ELF format found in stock Sony ROMs for, e.g, the Xperia Z2. + // If more formats exist, we should differ the assignments at + // the bottom of this function by the "elf version" + + b->hdr.magic[0] = 'A'; + b->hdr.magic[1] = 'N'; + b->hdr.magic[2] = 'D'; + b->hdr.magic[3] = 'R'; + b->hdr.magic[4] = 'O'; + b->hdr.magic[5] = 'I'; + b->hdr.magic[6] = 'D'; + b->hdr.magic[7] = '!'; + + b->hdr.kernel_addr = b->hdr_info->prog[ELF_PROG_KER].paddr; + b->hdr.ramdisk_addr = b->hdr_info->prog[ELF_PROG_RAM].paddr; + b->hdr.tags_addr = b->hdr_info->prog[ELF_PROG_RPM].paddr; } + print_hdr_to_log(&b->hdr); return 0; } @@ -402,12 +1000,6 @@ int libbootimg_write_img(struct bootimg *b, const char *dest) FILE *f; int res; - if(b->hdr.kernel_size == 0 || b->hdr.ramdisk_size == 0) - return LIBBOOTIMG_ERROR_MISSING_BLOB; - - if(b->hdr.page_size < sizeof(b->hdr)) - return LIBBOOTIMG_ERROR_INVALID_PAGESIZE; - f = fopen(dest, "w"); if(!f) return translate_errnum(errno); @@ -423,10 +1015,12 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) int i; int res = 0; char *blank = NULL; - size_t padding; + size_t padding = 0; struct bootimg_blob *blob; - int pos_start, pos_end; + int pos_start; + int pos_end = 0; + LOG_DBG("Writing.\n"); pos_start = ftell(f); if(pos_start < 0) return translate_errnum(errno); @@ -449,47 +1043,195 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) blank = malloc(b->hdr.page_size); memset(blank, 0, b->hdr.page_size); - // write header - if (!b->is_elf) + // Update & write header + libbootimg_update_headers(b); + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) { if (fwrite(&b->hdr, sizeof(b->hdr), 1, f) != 1) goto fail_fwrite; padding = align_size(sizeof(b->hdr), b->hdr.page_size) - sizeof(b->hdr); } - else + else if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) { - libbootimg_update_headers(b); - - if (fwrite(b->hdr_elf, sizeof(*b->hdr_elf), 1, f) != 1) + if (b->hdr_info->elf_architecture == ARCH_64_BITS) + { + res = fwrite(&b->hdr_info->hdr, sizeof(b->hdr_info->hdr), 1, f); + } + else + { + res = fwrite(&b->hdr_info->hdr_32, sizeof(b->hdr_info->hdr_32), + 1, f); + } + if (res != 1) + { goto fail_fwrite; + } - padding = align_size(sizeof(*b->hdr_elf), b->hdr.page_size) - sizeof(*b->hdr_elf); + // Write the Program headers. + int num_prog_hdr = b->hdr_info->hdr.phnum; + int hdr_entry_idx = 0; + for (; hdr_entry_idx < num_prog_hdr; ++hdr_entry_idx) + { + print_elf_prog_hdr_to_log(&b->hdr_info->prog[hdr_entry_idx]); + if (b->hdr_info->elf_architecture == ARCH_64_BITS) + { + res = fwrite(&b->hdr_info->prog[hdr_entry_idx], + b->hdr_info->hdr.phentsize, 1, f); + } + else + { + res = fwrite(&b->hdr_info->prog_32[hdr_entry_idx], + b->hdr_info->hdr_32.phentsize, 1, f); + } + if (res == 1) + { + LOG_DBG("Program header %u/%u writing successful.\n", + hdr_entry_idx + 1, b->hdr_info->hdr.phnum); + } + else + { + LOG_DBG("Program failed %u/%u writing failed.\n", + hdr_entry_idx + 1, b->hdr_info->hdr.phnum); + goto fail_fwrite; + } + } + + if (b->hdr_info->elf_version == VER_ELF_1) + { + print_elf_misc_hdr_to_log(b->hdr_info->misc); + if (fwrite(b->hdr_info->misc->data, b->hdr_info->misc->data_size, + 1, f) != 1) + { + LOG_DBG("Misc data writing successful.\n"); + goto fail_fwrite; + } + else if (fwrite(b->hdr_info->misc->name, + sizeof(b->hdr_info->misc->name), 1, f) != 1) + { + LOG_DBG("Misc boot name writing failed.\n"); + goto fail_fwrite; + } + else + { + LOG_DBG("Misc header writing successful.\n"); + } + } } - if (fwrite(blank, 1, padding, f) != padding) - goto fail_fwrite; + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) + { + if (fwrite(blank, 1, padding, f) != padding) + goto fail_fwrite; + } for (i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) { blob = &b->blobs[i]; if (*blob->size == 0) + { + LOG_DBG("Ignored empty blob number %d/%d...\n", i + 1, LIBBOOTIMG_BLOB_CNT); continue; + } + + LOG_DBG("Writing blob number %d/%d...\n", i + 1, LIBBOOTIMG_BLOB_CNT); + LOG_DBG("Writing to position 0x%lx.\n", ftell(f)); if (fwrite(blob->data, *blob->size, 1, f) != 1) + { + LOG_DBG("Writing blob %d failed.\n", i + 1); goto fail_fwrite; + } - if (!b->is_elf) + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) { padding = align_size(*blob->size, b->hdr.page_size) - *blob->size; if (fwrite(blank, 1, padding, f) != padding) + { + LOG_DBG("Writing padding of blob %d failed.\n", i + 1); goto fail_fwrite; + } } } - if (b->is_elf && fwrite(b->hdr.cmdline, b->hdr_elf->cmd_size, 1, f) != 1) - goto fail_fwrite; + if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) + { + if (b->hdr_info->elf_version == VER_ELF_1) + { + // Write the cmdline (last part ref by the prog header) + pos_end += b->hdr_info->cmdline_size; + LOG_DBG("cmdline: %s\n", b->hdr.cmdline); + LOG_DBG("cmdline size: %u\n", b->hdr_info->cmdline_size); + if (fwrite(&b->hdr.cmdline, b->hdr_info->cmdline_size, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline.\n"); + goto fail_fwrite; + } + } + + // Write the section header if needed by the ELF + if (b->hdr_info->hdr.shnum > 0) + { + // Prepare the cmdline data + LOG_DBG("Writing cmdline data.\n"); + LOG_DBG("cmdline: %s\n", b->hdr.cmdline); + LOG_DBG("cmdline size: %u\n", b->hdr_info->cmdline_size); + fseek(f, b->hdr_info->sect[ELF_SECT_CMD].offset, SEEK_SET); + + // Write the cmdline metadata + if (b->hdr_info->cmdline_metadata_cnt > 0 && + fwrite(&b->hdr_info->cmdline_metadata, + b->hdr_info->cmdline_metadata_cnt, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline metadata.\n"); + goto fail_fwrite; + } + + // Write the cmdline based on section header + if (fwrite(&b->hdr.cmdline, b->hdr_info->cmdline_size, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline.\n"); + goto fail_fwrite; + } + + // Write the cmdline signature based on section header + if (b->hdr_info->cmdline_signature_cnt > 0) + { + LOG_DBG("Writing cmdline signature.\n"); + fseek(f, b->hdr_info->sect[ELF_SECT_CMD].offset + + b->hdr_info->cmdline_metadata_cnt + BOOT_ARGS_SIZE, SEEK_SET); + if (fwrite(b->hdr_info->cmdline_signature, + b->hdr_info->cmdline_signature_cnt, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline signature.\n"); + goto fail_fwrite; + } + } + + // Write the section header + LOG_DBG("Writing section header.\n"); + fseek(f, b->hdr_info->hdr.shoff, SEEK_SET); + if (b->hdr_info->elf_architecture == ARCH_64_BITS) + { + res = fwrite(b->hdr_info->sect, + b->hdr_info->hdr.shentsize, 1, f); + } + else + { + res = fwrite(b->hdr_info->sect_32, + b->hdr_info->hdr_32.shentsize, 1, f); + } + if (res == 1) + { + print_elf_sect_hdr_to_log(&b->hdr_info->sect[ELF_SECT_CMD]); + } + else + { + goto fail_fwrite; + } + } + } pos_end = ftell(f); @@ -503,6 +1245,7 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) res = LIBBOOTIMG_ERROR_IO; exit: free(blank); + LOG_DBG("Done writing.\n"); return res; } @@ -513,6 +1256,19 @@ int libbootimg_write_img_and_destroy(struct bootimg *b, const char *dest) return res; } +uint8_t libbootimg_architecture(void) +{ + struct utsname sysinfo; + uname(&sysinfo); + + if (strstr(sysinfo.machine, "aarch64") || + strstr(sysinfo.machine, "armv8")) { + return ARCH_64_BITS; + } + + return ARCH_32_BITS; +} + uint32_t libbootimg_version(void) { return LIBBOOTIMG_VERSION; @@ -525,7 +1281,7 @@ const char *libbootimg_version_str(void) const char *libbootimg_error_str(int error) { - switch(error) + switch (error) { case LIBBOOTIMG_SUCCESS: return "No errors"; case LIBBOOTIMG_ERROR_IO: return "Input/output error"; @@ -542,3 +1298,94 @@ const char *libbootimg_error_str(int error) default: return "Unknown error"; } } + +void print_hdr_to_log(struct boot_img_hdr* hdr) +{ + LOG_DBG("* architecture = %s\n", + libbootimg_architecture() == ARCH_64_BITS ? "64bits" : "32bits"); + + LOG_DBG("* kernel size = %u bytes (%.2f MB)\n", hdr->kernel_size, + (double )hdr->kernel_size / 0x100000); + LOG_DBG(" ramdisk size = %u bytes (%.2f MB)\n", hdr->ramdisk_size, + (double )hdr->ramdisk_size / 0x100000); + if (hdr->second_size) + { + LOG_DBG(" second stage size = %u bytes (%.2f MB)\n", hdr->second_size, + (double )hdr->second_size / 0x100000); + } + if (hdr->dt_size) + { + LOG_DBG(" device tree size = %u bytes (%.2f MB)\n", hdr->dt_size, + (double )hdr->dt_size / 0x100000); + } + LOG_DBG("* load addresses:\n"); + LOG_DBG(" kernel: 0x%08x\n", hdr->kernel_addr); + LOG_DBG(" ramdisk: 0x%08x\n", hdr->ramdisk_addr); + if (hdr->second_size) + { + LOG_DBG(" second stage: 0x%08x\n", hdr->second_addr); + } + LOG_DBG(" tags: 0x%08x\n", hdr->tags_addr); +} + +void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info) +{ + (void)elf_info; + LOG_DBG("\n"); + LOG_DBG("========= ELF header content =========\n"); + LOG_DBG("Architecture = %s\n", + libbootimg_architecture() == ARCH_64_BITS ? "64bits" : "32bits"); + LOG_DBG("ELF Version = %x\n", elf_info->elf_version); + LOG_DBG("Output format = %s\n", elf_info->elf_out_format == OUT_ELF ? "ELF" : "ANDROID"); + LOG_DBG("Type = %u\n", elf_info->hdr.type); + LOG_DBG("Machine = %u\n", elf_info->hdr.machine); + LOG_DBG("Version = %u\n", elf_info->hdr.version); + LOG_DBG("Entry Address = %"PRIx64"\n", elf_info->hdr.entry_addr); + LOG_DBG("Program Offset = %"PRIx64"\n", elf_info->hdr.phoff); + LOG_DBG("Section Offset = %"PRIx64"\n", elf_info->hdr.shoff); + LOG_DBG("Flags = %x\n", elf_info->hdr.flags); + LOG_DBG("Ehsize = %u\n", elf_info->hdr.ehsize); + LOG_DBG("Program headers size = %u\n", elf_info->hdr.phentsize); + LOG_DBG("Program headers number = %u\n", elf_info->hdr.phnum); + LOG_DBG("Section headers size = %u\n", elf_info->hdr.shentsize); + LOG_DBG("Section headers number = %u\n", elf_info->hdr.shnum); + LOG_DBG("Section strndx = %x\n", elf_info->hdr.shstrndx); + LOG_DBG("======================================\n"); +} + +void print_elf_prog_hdr_to_log(struct boot_img_elf_prog_hdr* elf_prog_hdr) +{ + (void)elf_prog_hdr; + LOG_DBG("===== ELF program header content =====\n"); + LOG_DBG("Type = %"PRIx64"\n", elf_prog_hdr->type); + LOG_DBG("Offset = %"PRIx64"\n", elf_prog_hdr->offset); + LOG_DBG("VAddr = %"PRIx64"\n", elf_prog_hdr->vaddr); + LOG_DBG("PAddr = %"PRIx64"\n", elf_prog_hdr->paddr); + LOG_DBG("Size = %"PRIu64"\n", elf_prog_hdr->size); + LOG_DBG("MSize = %"PRIu64"\n", elf_prog_hdr->msize); + LOG_DBG("Flags = %x\n", elf_prog_hdr->flags); + LOG_DBG("Align = %x\n", elf_prog_hdr->align); + LOG_DBG("======================================\n"); +} + +void print_elf_sect_hdr_to_log(struct boot_img_elf_sect_hdr* elf_sect_hdr) +{ + (void)elf_sect_hdr; + LOG_DBG("===== ELF section header content =====\n"); + LOG_DBG("Name = %x\n", elf_sect_hdr->name); + LOG_DBG("Type = %"PRIx64"\n", elf_sect_hdr->type); + LOG_DBG("Flags = %x\n", elf_sect_hdr->flags); + LOG_DBG("Address = %"PRIx64"\n", elf_sect_hdr->addr); + LOG_DBG("Offset = %"PRIx64"\n", elf_sect_hdr->offset); + LOG_DBG("Size = %"PRIu64"\n", elf_sect_hdr->size); + LOG_DBG("======================================\n"); +} + +void print_elf_misc_hdr_to_log(struct boot_img_elf_misc_hdr* elf_misc_hdr) +{ + (void)elf_misc_hdr; + LOG_DBG("====== ELF misc header content =======\n"); + LOG_DBG("Data size = %u\n", elf_misc_hdr->data_size); + LOG_DBG("Boot name = %s\n", elf_misc_hdr->name); + LOG_DBG("======================================\n"); +}