From 4e69861285434103d9fb353ed0bfada8d759c8da Mon Sep 17 00:00:00 2001 From: Nolen Johnson Date: Thu, 25 Apr 2024 23:21:12 -0400 Subject: [PATCH] Swap loki_tool out for out-of-range * out-of-range (oor) supports more devices on more bootloader versions, no point in keeping loki around. As-Of: 4246d34c52c9178085dd73e2e2ddd513d2a18547 Change-Id: Ifdbcdee5a4f2a14f0ded445436cb16b3eb69dd9e --- loki_tool/Android.bp | 15 - loki_tool/LICENSE.txt | 25 -- loki_tool/Makefile | 30 -- loki_tool/README.txt | 81 ----- loki_tool/loki.h | 88 ----- loki_tool/loki_find.c | 91 ----- loki_tool/loki_flash.c | 145 -------- loki_tool/loki_patch.c | 694 ------------------------------------ loki_tool/loki_unlok.c | 152 -------- loki_tool/main.c | 56 --- mkbootimg.mk | 16 +- oor/.gitignore | 6 + oor/Android.bp | 49 +++ oor/Makefile | 62 ++++ oor/README.md | 68 ++++ oor/obj-arm/patch_code.bin | Bin 0 -> 380 bytes oor/src/aboot_image.c | 95 +++++ oor/src/aboot_image.h | 26 ++ oor/src/asm.c | 166 +++++++++ oor/src/asm.h | 11 + oor/src/bin_to_c.c | 136 ++++++++ oor/src/boot_image.c | 257 ++++++++++++++ oor/src/boot_image.h | 49 +++ oor/src/cmd_crc.c | 40 +++ oor/src/cmd_crc.h | 6 + oor/src/cmd_list.c | 22 ++ oor/src/cmd_list.h | 6 + oor/src/cmd_patch.c | 131 +++++++ oor/src/cmd_patch.h | 6 + oor/src/cmd_redirect.c | 138 ++++++++ oor/src/cmd_redirect.h | 6 + oor/src/cmd_undo.c | 72 ++++ oor/src/cmd_undo.h | 6 + oor/src/cmd_verify.c | 74 ++++ oor/src/cmd_verify.h | 6 + oor/src/config.c | 696 +++++++++++++++++++++++++++++++++++++ oor/src/config.h | 117 +++++++ oor/src/crc.c | 18 + oor/src/crc.h | 9 + oor/src/file_utils.c | 59 ++++ oor/src/file_utils.h | 9 + oor/src/little_endian.c | 29 ++ oor/src/little_endian.h | 11 + oor/src/main.c | 95 +++++ oor/src/patch_code.S | 170 +++++++++ oor/src/udfs.h | 63 ++++ 46 files changed, 2722 insertions(+), 1385 deletions(-) delete mode 100644 loki_tool/Android.bp delete mode 100644 loki_tool/LICENSE.txt delete mode 100644 loki_tool/Makefile delete mode 100644 loki_tool/README.txt delete mode 100644 loki_tool/loki.h delete mode 100644 loki_tool/loki_find.c delete mode 100644 loki_tool/loki_flash.c delete mode 100644 loki_tool/loki_patch.c delete mode 100644 loki_tool/loki_unlok.c delete mode 100644 loki_tool/main.c create mode 100644 oor/.gitignore create mode 100644 oor/Android.bp create mode 100644 oor/Makefile create mode 100644 oor/README.md create mode 100644 oor/obj-arm/patch_code.bin create mode 100644 oor/src/aboot_image.c create mode 100644 oor/src/aboot_image.h create mode 100644 oor/src/asm.c create mode 100644 oor/src/asm.h create mode 100644 oor/src/bin_to_c.c create mode 100644 oor/src/boot_image.c create mode 100644 oor/src/boot_image.h create mode 100644 oor/src/cmd_crc.c create mode 100644 oor/src/cmd_crc.h create mode 100644 oor/src/cmd_list.c create mode 100644 oor/src/cmd_list.h create mode 100644 oor/src/cmd_patch.c create mode 100644 oor/src/cmd_patch.h create mode 100644 oor/src/cmd_redirect.c create mode 100644 oor/src/cmd_redirect.h create mode 100644 oor/src/cmd_undo.c create mode 100644 oor/src/cmd_undo.h create mode 100644 oor/src/cmd_verify.c create mode 100644 oor/src/cmd_verify.h create mode 100644 oor/src/config.c create mode 100644 oor/src/config.h create mode 100644 oor/src/crc.c create mode 100644 oor/src/crc.h create mode 100644 oor/src/file_utils.c create mode 100644 oor/src/file_utils.h create mode 100644 oor/src/little_endian.c create mode 100644 oor/src/little_endian.h create mode 100644 oor/src/main.c create mode 100644 oor/src/patch_code.S create mode 100644 oor/src/udfs.h diff --git a/loki_tool/Android.bp b/loki_tool/Android.bp deleted file mode 100644 index 06bae74..0000000 --- a/loki_tool/Android.bp +++ /dev/null @@ -1,15 +0,0 @@ -cc_binary_host { - name: "loki_tool", - cflags: [ - "-Wno-pointer-arith", - "-Wno-unused-result", - "-Wno-sign-compare", - ], - srcs: [ - "loki_flash.c", - "loki_patch.c", - "loki_find.c", - "loki_unlok.c", - "main.c", - ], -} diff --git a/loki_tool/LICENSE.txt b/loki_tool/LICENSE.txt deleted file mode 100644 index bc2a914..0000000 --- a/loki_tool/LICENSE.txt +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2013 Dan Rosenberg. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INFRAE OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/loki_tool/Makefile b/loki_tool/Makefile deleted file mode 100644 index 8d58748..0000000 --- a/loki_tool/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -SRC_LOKI := loki_flash.c loki_patch.c loki_find.c loki_unlok.c main.c -OBJ_LOKI = $(SRC_LOKI:.c=.o) -MODULE_LOKI := loki_tool - -CC := arm-linux-androideabi-gcc -CC_STRIP := arm-linux-androideabi-strip - -CFLAGS += -g -static -Wall -#$(LDFLAGS) += - -all: $(MODULE_LOKI) - -host: CC := gcc -host: $(MODULE_LOKI) - -%.o: %.c - $(CC) -c -o $@ $< $(CFLAGS) - -$(MODULE_LOKI): $(OBJ_LOKI) - $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) - -strip: - $(CC_STRIP) --strip-unneeded $(MODULE_LOKI) - $(CC_STRIP) --strip-debug $(MODULE_LOKI) - -clean: - rm -f *.o - rm -f loki_tool - -.phony: host all diff --git a/loki_tool/README.txt b/loki_tool/README.txt deleted file mode 100644 index 4b4368a..0000000 --- a/loki_tool/README.txt +++ /dev/null @@ -1,81 +0,0 @@ - -WARNING: - -This project is no longer actively maintained, because the vulnerability that -it leverages was patched several years ago. No new updates will be provided. -The current codebase will remain here for reference purposes. - - -============================= -Loki -by Dan Rosenberg (@djrbliss) -============================= - -Loki is a set of tools for creating and flashing custom kernels and recoveries -on the AT&T and Verizon branded Samsung Galaxy S4, the Samsung Galaxy Stellar, -and various locked LG devices. For an explanation of how the exploit works, -please see the technical blog post at: - -http://blog.azimuthsecurity.com/2013/05/exploiting-samsung-galaxy-s4-secure-boot.html - -Devices must be rooted in order to flash custom kernels and recoveries. - -loki_tool: -[patch] option is primarily intended for developers to create custom -kernels and recoveries. It's designed to take a specific aboot image and an -unmodified boot or recovery image, and it generates an output image in a new -file format, ".lok". The resulting .lok image is specifically tailored for the -device build it was created with, and can be flashed directly to the recovery -or boot partition on the target device. - -[flash] option can be used to flash a .lok image to an actual device. -It will verify that the provided .lok image is safe to flash for a given target -and then perform the flashing if validation is successful. It is also possible -to simply use "dd" to flash a .lok image directly to the boot or recovery partition, -but using [flash] option is recommended in order to validate that the .lok matches -the target device. - - -============= -Sample usage -============= - -First, a developer must pull the aboot image from a target device: - - -dan@pc:~$ adb shell -shell@android:/ $ su -shell@android:/ # dd if=/dev/block/platform/msm_sdcc.1/by-name/aboot of=/data/local/tmp/aboot.img -shell@android:/ # chmod 644 /data/local/tmp/aboot.img -shell@android:/ # exit -shell@android:/ $ exit -dan@pc:~$ adb pull /data/local/tmp/aboot.img -3293 KB/s (2097152 bytes in 0.621s) - - -Next, a .lok image can be prepared using loki_tool [patch]: - - -dan@pc:~$ loki_tool patch -Usage: ./loki_tool [patch] [boot|recovery] [aboot.img] [in.img] [out.lok] -dan@pc:~$ loki_tool patch recovery aboot.img cwm.img cwm.lok -[+] Detected target AT&T build JDQ39.I337UCUAMDB or JDQ39.I337UCUAMDL -[+] Output file written to cwm.lok - - -Finally, the .lok image can be flashed using loki_tool [flash]: - - -dan@pc:~$ adb push cwm.lok /data/local/tmp -dan@pc:~$ adb push loki_tool /data/local/tmp -dan@pc:~$ adb shell -shell@android:/ $ su -shell@android:/ # chmod 755 /data/local/tmp/loki_tool -shell@android:/ # /data/local/tmp/loki_tool -Usage: /data/local/tmp/loki_tool [flash] [boot|recovery] [in.lok] -shell@android:/ # /data/local/tmp/loki_tool flash recovery /data/local/tmp/cwm.lok -[+] Loki validation passed, flashing image. -2253+1 records in -2253+1 records out -9230848 bytes transferred in 0.656 secs (14071414 bytes/sec) -[+] Loki flashing complete! diff --git a/loki_tool/loki.h b/loki_tool/loki.h deleted file mode 100644 index c1d6b3e..0000000 --- a/loki_tool/loki.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef __LOKI_H_ -#define __LOKI_H_ - -#define VERSION "2.1" - -#define BOOT_MAGIC_SIZE 8 -#define BOOT_NAME_SIZE 16 -#define BOOT_ARGS_SIZE 512 - -#define BOOT_PARTITION "/dev/block/platform/msm_sdcc.1/by-name/boot" -#define RECOVERY_PARTITION "/dev/block/platform/msm_sdcc.1/by-name/recovery" -#define ABOOT_PARTITION "/dev/block/platform/msm_sdcc.1/by-name/aboot" - -#define PATTERN1 "\xf0\xb5\x8f\xb0\x06\x46\xf0\xf7" -#define PATTERN2 "\xf0\xb5\x8f\xb0\x07\x46\xf0\xf7" -#define PATTERN3 "\x2d\xe9\xf0\x41\x86\xb0\xf1\xf7" -#define PATTERN4 "\x2d\xe9\xf0\x4f\xad\xf5\xc6\x6d" -#define PATTERN5 "\x2d\xe9\xf0\x4f\xad\xf5\x21\x7d" -#define PATTERN6 "\x2d\xe9\xf0\x4f\xf3\xb0\x05\x46" - -#define ABOOT_BASE_SAMSUNG 0x88dfffd8 -#define ABOOT_BASE_LG 0x88efffd8 -#define ABOOT_BASE_G2 0xf7fffd8 -#define ABOOT_BASE_VIPER 0x40100000 - -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 */ -}; - -struct loki_hdr { - unsigned char magic[4]; /* 0x494b4f4c */ - unsigned int recovery; /* 0 = boot.img, 1 = recovery.img */ - char build[128]; /* Build number */ - - unsigned int orig_kernel_size; - unsigned int orig_ramdisk_size; - unsigned int ramdisk_addr; -}; - -int loki_patch(const char* partition_label, const char* aboot_image, const char* in_image, const char* out_image); -int loki_flash(const char* partition_label, const char* loki_image); -int loki_find(const char* aboot_image); -int loki_unlok(const char* in_image, const char* out_image); - -#define PATCH "\xfe\xb5" \ - "\x0d\x4d" \ - "\xd5\xf8" \ - "\x88\x04" \ - "\xab\x68" \ - "\x98\x42" \ - "\x12\xd0" \ - "\xd5\xf8" \ - "\x90\x64" \ - "\x0a\x4c" \ - "\xd5\xf8" \ - "\x8c\x74" \ - "\x07\xf5\x80\x57" \ - "\x0f\xce" \ - "\x0f\xc4" \ - "\x10\x3f" \ - "\xfb\xdc" \ - "\xd5\xf8" \ - "\x88\x04" \ - "\x04\x49" \ - "\xd5\xf8" \ - "\x8c\x24" \ - "\xa8\x60" \ - "\x69\x61" \ - "\x2a\x61" \ - "\x00\x20" \ - "\xfe\xbd" \ - "\xff\xff\xff\xff" \ - "\xee\xee\xee\xee" - -#endif //__LOKI_H_ diff --git a/loki_tool/loki_find.c b/loki_tool/loki_find.c deleted file mode 100644 index 151a309..0000000 --- a/loki_tool/loki_find.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include -#include - -#include "loki.h" - -#define BOOT_PATTERN1 "\x4f\xf4\x70\x40\xb3\x49\x2d\xe9" /* Samsung GS4 */ -#define BOOT_PATTERN2 "\x2d\xe9\xf0\x4f\xad\xf5\x82\x5d" /* LG */ -#define BOOT_PATTERN3 "\x2d\xe9\xf0\x4f\x4f\xf4\x70\x40" /* LG */ -#define BOOT_PATTERN4 "\x2d\xe9\xf0\x4f\xad\xf5\x80\x5d" /* LG G2 */ - -int loki_find(const char* aboot_image) -{ - int aboot_fd; - struct stat st; - void *aboot, *ptr; - unsigned long aboot_base, check_sigs, boot_mmc; - - aboot_fd = open(aboot_image, O_RDONLY); - if (aboot_fd < 0) { - printf("[-] Failed to open %s for reading.\n", aboot_image); - return 1; - } - - if (fstat(aboot_fd, &st)) { - printf("[-] fstat() failed.\n"); - return 1; - } - - aboot = mmap(0, (st.st_size + 0xfff) & ~0xfff, PROT_READ, MAP_PRIVATE, aboot_fd, 0); - if (aboot == MAP_FAILED) { - printf("[-] Failed to mmap aboot.\n"); - return 1; - } - - check_sigs = 0; - aboot_base = *(unsigned int *)(aboot + 12) - 0x28; - - /* Do a pass to find signature checking function */ - for (ptr = aboot; ptr < aboot + st.st_size - 0x1000; ptr++) { - if (!memcmp(ptr, PATTERN1, 8) || - !memcmp(ptr, PATTERN2, 8) || - !memcmp(ptr, PATTERN3, 8) || - !memcmp(ptr, PATTERN4, 8) || - !memcmp(ptr, PATTERN5, 8)) { - - check_sigs = (unsigned long)ptr - (unsigned long)aboot + aboot_base; - break; - } - - if (!memcmp(ptr, PATTERN6, 8)) { - - check_sigs = (unsigned long)ptr - (unsigned long)aboot + aboot_base; - - /* Don't break, because the other LG patterns override this one */ - continue; - } - } - - if (!check_sigs) { - printf("[-] Could not find signature checking function.\n"); - return 1; - } - - printf("[+] Signature check function: %.08lx\n", check_sigs); - - boot_mmc = 0; - - /* Do a second pass for the boot_linux_from_emmc function */ - for (ptr = aboot; ptr < aboot + st.st_size - 0x1000; ptr++) { - if (!memcmp(ptr, BOOT_PATTERN1, 8) || - !memcmp(ptr, BOOT_PATTERN2, 8) || - !memcmp(ptr, BOOT_PATTERN3, 8) || - !memcmp(ptr, BOOT_PATTERN4, 8)) { - - boot_mmc = (unsigned long)ptr - (unsigned long)aboot + aboot_base; - break; - } - } - - if (!boot_mmc) { - printf("[-] Could not find boot_linux_from_mmc.\n"); - return 1; - } - - printf("[+] boot_linux_from_mmc: %.08lx\n", boot_mmc); - - return 0; -} diff --git a/loki_tool/loki_flash.c b/loki_tool/loki_flash.c deleted file mode 100644 index 16bdd4d..0000000 --- a/loki_tool/loki_flash.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * loki_flash - * - * A sample utility to validate and flash .lok files - * - * by Dan Rosenberg (@djrbliss) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "loki.h" - -int loki_flash(const char* partition_label, const char* loki_image) -{ - int ifd, aboot_fd, ofd, recovery, offs, match; - void *orig, *aboot, *patch; - struct stat st; - struct boot_img_hdr *hdr; - struct loki_hdr *loki_hdr; - char outfile[1024]; - - if (!strcmp(partition_label, "boot")) { - recovery = 0; - } else if (!strcmp(partition_label, "recovery")) { - recovery = 1; - } else { - printf("[+] First argument must be \"boot\" or \"recovery\".\n"); - return 1; - } - - /* Verify input file */ - aboot_fd = open(ABOOT_PARTITION, O_RDONLY); - if (aboot_fd < 0) { - printf("[-] Failed to open aboot for reading.\n"); - return 1; - } - - ifd = open(loki_image, O_RDONLY); - if (ifd < 0) { - printf("[-] Failed to open %s for reading.\n", loki_image); - return 1; - } - - /* Map the image to be flashed */ - if (fstat(ifd, &st)) { - printf("[-] fstat() failed.\n"); - return 1; - } - - orig = mmap(0, (st.st_size + 0x2000 + 0xfff) & ~0xfff, PROT_READ, MAP_PRIVATE, ifd, 0); - if (orig == MAP_FAILED) { - printf("[-] Failed to mmap Loki image.\n"); - return 1; - } - - hdr = orig; - loki_hdr = orig + 0x400; - - /* Verify this is a Loki image */ - if (memcmp(loki_hdr->magic, "LOKI", 4)) { - printf("[-] Input file is not a Loki image.\n"); - return 1; - } - - /* Verify this is the right type of image */ - if (loki_hdr->recovery != recovery) { - printf("[-] Loki image is not a %s image.\n", recovery ? "recovery" : "boot"); - return 1; - } - - /* Verify the to-be-patched address matches the known code pattern */ - aboot = mmap(0, 0x40000, PROT_READ, MAP_PRIVATE, aboot_fd, 0); - if (aboot == MAP_FAILED) { - printf("[-] Failed to mmap aboot.\n"); - return 1; - } - - match = 0; - - for (offs = 0; offs < 0x10; offs += 0x4) { - - patch = NULL; - - if (hdr->ramdisk_addr > ABOOT_BASE_LG) - patch = hdr->ramdisk_addr - ABOOT_BASE_LG + aboot + offs; - else if (hdr->ramdisk_addr > ABOOT_BASE_SAMSUNG) - patch = hdr->ramdisk_addr - ABOOT_BASE_SAMSUNG + aboot + offs; - else if (hdr->ramdisk_addr > ABOOT_BASE_VIPER) - patch = hdr->ramdisk_addr - ABOOT_BASE_VIPER + aboot + offs; - else if (hdr->ramdisk_addr > ABOOT_BASE_G2) - patch = hdr->ramdisk_addr - ABOOT_BASE_G2 + aboot + offs; - - if (patch < aboot || patch > aboot + 0x40000 - 8) { - printf("[-] Invalid .lok file.\n"); - return 1; - } - - if (!memcmp(patch, PATTERN1, 8) || - !memcmp(patch, PATTERN2, 8) || - !memcmp(patch, PATTERN3, 8) || - !memcmp(patch, PATTERN4, 8) || - !memcmp(patch, PATTERN5, 8) || - !memcmp(patch, PATTERN6, 8)) { - - match = 1; - break; - } - } - - if (!match) { - printf("[-] Loki aboot version does not match device.\n"); - return 1; - } - - printf("[+] Loki validation passed, flashing image.\n"); - - snprintf(outfile, sizeof(outfile), - "%s", - recovery ? RECOVERY_PARTITION : BOOT_PARTITION); - - ofd = open(outfile, O_WRONLY); - if (ofd < 0) { - printf("[-] Failed to open output block device.\n"); - return 1; - } - - if (write(ofd, orig, st.st_size) != st.st_size) { - printf("[-] Failed to write to block device.\n"); - return 1; - } - - printf("[+] Loki flashing complete!\n"); - - close(ifd); - close(aboot_fd); - close(ofd); - - return 0; -} diff --git a/loki_tool/loki_patch.c b/loki_tool/loki_patch.c deleted file mode 100644 index 5d671bb..0000000 --- a/loki_tool/loki_patch.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * loki_patch - * - * A utility to patch unsigned boot and recovery images to make - * them suitable for booting on the AT&T/Verizon Samsung - * Galaxy S4, Galaxy Stellar, and various locked LG devices - * - * by Dan Rosenberg (@djrbliss) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "loki.h" - -struct target { - char *vendor; - char *device; - char *build; - unsigned long check_sigs; - unsigned long hdr; - int lg; -}; - -struct target targets[] = { - { - .vendor = "AT&T", - .device = "Samsung Galaxy S4", - .build = "JDQ39.I337UCUAMDB or JDQ39.I337UCUAMDL", - .check_sigs = 0x88e0ff98, - .hdr = 0x88f3bafc, - .lg = 0, - }, - { - .vendor = "Verizon", - .device = "Samsung Galaxy S4", - .build = "JDQ39.I545VRUAMDK", - .check_sigs = 0x88e0fe98, - .hdr = 0x88f372fc, - .lg = 0, - }, - { - .vendor = "DoCoMo", - .device = "Samsung Galaxy S4", - .build = "JDQ39.SC04EOMUAMDI", - .check_sigs = 0x88e0fcd8, - .hdr = 0x88f0b2fc, - .lg = 0, - }, - { - .vendor = "Verizon", - .device = "Samsung Galaxy Stellar", - .build = "IMM76D.I200VRALH2", - .check_sigs = 0x88e0f5c0, - .hdr = 0x88ed32e0, - .lg = 0, - }, - { - .vendor = "Verizon", - .device = "Samsung Galaxy Stellar", - .build = "JZO54K.I200VRBMA1", - .check_sigs = 0x88e101ac, - .hdr = 0x88ed72e0, - .lg = 0, - }, - { - .vendor = "T-Mobile", - .device = "LG Optimus F3Q", - .build = "D52010c", - .check_sigs = 0x88f1079c, - .hdr = 0x88f64508, - .lg = 1, - }, - { - .vendor = "DoCoMo", - .device = "LG Optimus G", - .build = "L01E20b", - .check_sigs = 0x88F10E48, - .hdr = 0x88F54418, - .lg = 1, - }, - { - .vendor = "DoCoMo", - .device = "LG Optimus it L05E", - .build = "L05E10d", - .check_sigs = 0x88f1157c, - .hdr = 0x88f31e10, - .lg = 1, - }, - { - .vendor = "DoCoMo", - .device = "LG Optimus G Pro", - .build = "L04E10f", - .check_sigs = 0x88f1102c, - .hdr = 0x88f54418, - .lg = 1, - }, - { - .vendor = "AT&T or HK", - .device = "LG Optimus G Pro", - .build = "E98010g or E98810b", - .check_sigs = 0x88f11084, - .hdr = 0x88f54418, - .lg = 1, - }, - { - .vendor = "KT, LGU, or SKT", - .device = "LG Optimus G Pro", - .build = "F240K10o, F240L10v, or F240S10w", - .check_sigs = 0x88f110b8, - .hdr = 0x88f54418, - .lg = 1, - }, - { - .vendor = "KT, LGU, or SKT", - .device = "LG Optimus LTE 2", - .build = "F160K20g, F160L20f, F160LV20d, or F160S20f", - .check_sigs = 0x88f10864, - .hdr = 0x88f802b8, - .lg = 1, - }, - { - .vendor = "MetroPCS", - .device = "LG Spirit", - .build = "MS87010a_05", - .check_sigs = 0x88f0e634, - .hdr = 0x88f68194, - .lg = 1, - }, - { - .vendor = "MetroPCS", - .device = "LG Motion", - .build = "MS77010f_01", - .check_sigs = 0x88f1015c, - .hdr = 0x88f58194, - .lg = 1, - }, - { - .vendor = "Verizon", - .device = "LG Lucid 2", - .build = "VS87010B_12", - .check_sigs = 0x88f10adc, - .hdr = 0x88f702bc, - .lg = 1, - }, - { - .vendor = "Verizon", - .device = "LG Spectrum 2", - .build = "VS93021B_05", - .check_sigs = 0x88f10c10, - .hdr = 0x88f84514, - .lg = 1, - }, - { - .vendor = "Boost Mobile", - .device = "LG Optimus F7", - .build = "LG870ZV4_06", - .check_sigs = 0x88f11714, - .hdr = 0x88f842ac, - .lg = 1, - }, - { - .vendor = "US Cellular", - .device = "LG Optimus F7", - .build = "US78011a", - .check_sigs = 0x88f112c8, - .hdr = 0x88f84518, - .lg = 1, - }, - { - .vendor = "Sprint", - .device = "LG Optimus F7", - .build = "LG870ZV5_02", - .check_sigs = 0x88f11710, - .hdr = 0x88f842a8, - .lg = 1, - }, - { - .vendor = "Virgin Mobile", - .device = "LG Optimus F3", - .build = "LS720ZV5", - .check_sigs = 0x88f108f0, - .hdr = 0x88f854f4, - .lg = 1, - }, - { - .vendor = "T-Mobile and MetroPCS", - .device = "LG Optimus F3", - .build = "LS720ZV5", - .check_sigs = 0x88f10264, - .hdr = 0x88f64508, - .lg = 1, - }, - { - .vendor = "AT&T", - .device = "LG G2", - .build = "D80010d", - .check_sigs = 0xf8132ac, - .hdr = 0xf906440, - .lg = 1, - }, - { - .vendor = "Verizon", - .device = "LG G2", - .build = "VS98010b", - .check_sigs = 0xf8131f0, - .hdr = 0xf906440, - .lg = 1, - }, - { - .vendor = "AT&T", - .device = "LG G2", - .build = "D80010o", - .check_sigs = 0xf813428, - .hdr = 0xf904400, - .lg = 1, - }, - { - .vendor = "Verizon", - .device = "LG G2", - .build = "VS98012b", - .check_sigs = 0xf813210, - .hdr = 0xf906440, - .lg = 1, - }, - { - .vendor = "T-Mobile or Canada", - .device = "LG G2", - .build = "D80110c or D803", - .check_sigs = 0xf813294, - .hdr = 0xf906440, - .lg = 1, - }, - { - .vendor = "International", - .device = "LG G2", - .build = "D802b", - .check_sigs = 0xf813a70, - .hdr = 0xf9041c0, - .lg = 1, - }, - { - .vendor = "Sprint", - .device = "LG G2", - .build = "LS980ZV7", - .check_sigs = 0xf813460, - .hdr = 0xf9041c0, - .lg = 1, - }, - { - .vendor = "KT or LGU", - .device = "LG G2", - .build = "F320K, F320L", - .check_sigs = 0xf81346c, - .hdr = 0xf8de440, - .lg = 1, - }, - { - .vendor = "SKT", - .device = "LG G2", - .build = "F320S", - .check_sigs = 0xf8132e4, - .hdr = 0xf8ee440, - .lg = 1, - }, - { - .vendor = "SKT", - .device = "LG G2", - .build = "F320S11c", - .check_sigs = 0xf813470, - .hdr = 0xf8de440, - .lg = 1, - }, - { - .vendor = "DoCoMo", - .device = "LG G2", - .build = "L-01F", - .check_sigs = 0xf813538, - .hdr = 0xf8d41c0, - .lg = 1, - }, - { - .vendor = "KT", - .device = "LG G Flex", - .build = "F340K", - .check_sigs = 0xf8124a4, - .hdr = 0xf8b6440, - .lg = 1, - }, - { - .vendor = "KDDI", - .device = "LG G Flex", - .build = "LGL2310d", - .check_sigs = 0xf81261c, - .hdr = 0xf8b41c0, - .lg = 1, - }, - { - .vendor = "International", - .device = "LG Optimus F5", - .build = "P87510e", - .check_sigs = 0x88f10a9c, - .hdr = 0x88f702b8, - .lg = 1, - }, - { - .vendor = "SKT", - .device = "LG Optimus LTE 3", - .build = "F260S10l", - .check_sigs = 0x88f11398, - .hdr = 0x88f8451c, - .lg = 1, - }, - { - .vendor = "International", - .device = "LG G Pad 8.3", - .build = "V50010a", - .check_sigs = 0x88f10814, - .hdr = 0x88f801b8, - .lg = 1, - }, - { - .vendor = "International", - .device = "LG G Pad 8.3", - .build = "V50010c or V50010e", - .check_sigs = 0x88f108bc, - .hdr = 0x88f801b8, - .lg = 1, - }, - { - .vendor = "Verizon", - .device = "LG G Pad 8.3", - .build = "VK81010c", - .check_sigs = 0x88f11080, - .hdr = 0x88fd81b8, - .lg = 1, - }, - { - .vendor = "International", - .device = "LG Optimus L9 II", - .build = "D60510a", - .check_sigs = 0x88f10d98, - .hdr = 0x88f84aa4, - .lg = 1, - }, - { - .vendor = "MetroPCS", - .device = "LG Optimus F6", - .build = "MS50010e", - .check_sigs = 0x88f10260, - .hdr = 0x88f70508, - .lg = 1, - }, - { - .vendor = "Open EU", - .device = "LG Optimus F6", - .build = "D50510a", - .check_sigs = 0x88f10284, - .hdr = 0x88f70aa4, - .lg = 1, - }, - { - .vendor = "KDDI", - .device = "LG Isai", - .build = "LGL22", - .check_sigs = 0xf813458, - .hdr = 0xf8d41c0, - .lg = 1, - }, - { - .vendor = "KDDI", - .device = "LG", - .build = "LGL21", - .check_sigs = 0x88f10218, - .hdr = 0x88f50198, - .lg = 1, - }, - { - .vendor = "KT", - .device = "LG Optimus GK", - .build = "F220K", - .check_sigs = 0x88f11034, - .hdr = 0x88f54418, - .lg = 1, - }, - { - .vendor = "International", - .device = "LG Vu 3", - .build = "F300L", - .check_sigs = 0xf813170, - .hdr = 0xf8d2440, - .lg = 1, - }, - { - .vendor = "Sprint", - .device = "LG Viper", - .build = "LS840ZVK", - .check_sigs = 0x4010fe18, - .hdr = 0x40194198, - .lg = 1, - }, - { - .vendor = "International", - .device = "LG G Flex", - .build = "D95510a", - .check_sigs = 0xf812490, - .hdr = 0xf8c2440, - .lg = 1, - }, - { - .vendor = "Sprint", - .device = "LG Mach", - .build = "LS860ZV7", - .check_sigs = 0x88f102b4, - .hdr = 0x88f6c194, - .lg = 1, - }, -}; - -static unsigned char patch[] = PATCH; - -int patch_shellcode(unsigned int header, unsigned int ramdisk) -{ - - unsigned int i; - int found_header, found_ramdisk; - unsigned int *ptr; - - found_header = 0; - found_ramdisk = 0; - - for (i = 0; i < sizeof(patch); i++) { - ptr = (unsigned int *)&patch[i]; - if (*ptr == 0xffffffff) { - *ptr = header; - found_header = 1; - } - - if (*ptr == 0xeeeeeeee) { - *ptr = ramdisk; - found_ramdisk = 1; - } - } - - if (found_header && found_ramdisk) - return 0; - - return -1; -} - -int loki_patch(const char* partition_label, const char* aboot_image, const char* in_image, const char* out_image) -{ - int ifd, ofd, aboot_fd, pos, i, recovery, offset, fake_size; - unsigned int orig_ramdisk_size, orig_kernel_size, page_kernel_size, page_ramdisk_size, page_size, page_mask; - unsigned long target, aboot_base; - void *orig, *aboot, *ptr; - struct target *tgt; - struct stat st; - struct boot_img_hdr *hdr; - struct loki_hdr *loki_hdr; - char *buf; - - if (!strcmp(partition_label, "boot")) { - recovery = 0; - } else if (!strcmp(partition_label, "recovery")) { - recovery = 1; - } else { - printf("[+] First argument must be \"boot\" or \"recovery\".\n"); - return 1; - } - - /* Open input files */ - aboot_fd = open(aboot_image, O_RDONLY); - if (aboot_fd < 0) { - printf("[-] Failed to open %s for reading.\n", aboot_image); - return 1; - } - - ifd = open(in_image, O_RDONLY); - if (ifd < 0) { - printf("[-] Failed to open %s for reading.\n", in_image); - return 1; - } - - ofd = open(out_image, O_WRONLY|O_CREAT|O_TRUNC, 0644); - if (ofd < 0) { - printf("[-] Failed to open %s for writing.\n", out_image); - return 1; - } - - /* Find the signature checking function via pattern matching */ - if (fstat(aboot_fd, &st)) { - printf("[-] fstat() failed.\n"); - return 1; - } - - aboot = mmap(0, (st.st_size + 0xfff) & ~0xfff, PROT_READ, MAP_PRIVATE, aboot_fd, 0); - if (aboot == MAP_FAILED) { - printf("[-] Failed to mmap aboot.\n"); - return 1; - } - - target = 0; - aboot_base = *(unsigned int *)(aboot + 12) - 0x28; - - for (ptr = aboot; ptr < aboot + st.st_size - 0x1000; ptr++) { - if (!memcmp(ptr, PATTERN1, 8) || - !memcmp(ptr, PATTERN2, 8) || - !memcmp(ptr, PATTERN3, 8) || - !memcmp(ptr, PATTERN4, 8) || - !memcmp(ptr, PATTERN5, 8)) { - - target = (unsigned long)ptr - (unsigned long)aboot + aboot_base; - break; - } - } - - /* Do a second pass for the second LG pattern. This is necessary because - * apparently some LG models have both LG patterns, which throws off the - * fingerprinting. */ - - if (!target) { - for (ptr = aboot; ptr < aboot + st.st_size - 0x1000; ptr++) { - if (!memcmp(ptr, PATTERN6, 8)) { - - target = (unsigned long)ptr - (unsigned long)aboot + aboot_base; - break; - } - } - } - - if (!target) { - printf("[-] Failed to find function to patch.\n"); - return 1; - } - - tgt = NULL; - - for (i = 0; i < (sizeof(targets)/sizeof(targets[0])); i++) { - if (targets[i].check_sigs == target) { - tgt = &targets[i]; - break; - } - } - - if (!tgt) { - printf("[-] Unsupported aboot image.\n"); - return 1; - } - - printf("[+] Detected target %s %s build %s\n", tgt->vendor, tgt->device, tgt->build); - - /* Map the original boot/recovery image */ - if (fstat(ifd, &st)) { - printf("[-] fstat() failed.\n"); - return 1; - } - - orig = mmap(0, (st.st_size + 0x2000 + 0xfff) & ~0xfff, PROT_READ|PROT_WRITE, MAP_PRIVATE, ifd, 0); - if (orig == MAP_FAILED) { - printf("[-] Failed to mmap input file.\n"); - return 1; - } - - hdr = orig; - loki_hdr = orig + 0x400; - - if (!memcmp(loki_hdr->magic, "LOKI", 4)) { - printf("[-] Input file is already a Loki image.\n"); - - /* Copy the entire file to the output transparently */ - if (write(ofd, orig, st.st_size) != st.st_size) { - printf("[-] Failed to copy Loki image.\n"); - return 1; - } - - printf("[+] Copied Loki image to %s.\n", out_image); - - return 0; - } - - /* Set the Loki header */ - memcpy(loki_hdr->magic, "LOKI", 4); - loki_hdr->recovery = recovery; - strncpy(loki_hdr->build, tgt->build, sizeof(loki_hdr->build) - 1); - - page_size = hdr->page_size; - page_mask = hdr->page_size - 1; - - orig_kernel_size = hdr->kernel_size; - orig_ramdisk_size = hdr->ramdisk_size; - - printf("[+] Original kernel address: %.08x\n", hdr->kernel_addr); - printf("[+] Original ramdisk address: %.08x\n", hdr->ramdisk_addr); - - /* Store the original values in unused fields of the header */ - loki_hdr->orig_kernel_size = orig_kernel_size; - loki_hdr->orig_ramdisk_size = orig_ramdisk_size; - loki_hdr->ramdisk_addr = hdr->kernel_addr + ((hdr->kernel_size + page_mask) & ~page_mask); - - if (patch_shellcode(tgt->hdr, hdr->ramdisk_addr) < 0) { - printf("[-] Failed to patch shellcode.\n"); - return 1; - } - - /* Ramdisk must be aligned to a page boundary */ - hdr->kernel_size = ((hdr->kernel_size + page_mask) & ~page_mask) + hdr->ramdisk_size; - - /* Guarantee 16-byte alignment */ - offset = tgt->check_sigs & 0xf; - - hdr->ramdisk_addr = tgt->check_sigs - offset; - - if (tgt->lg) { - fake_size = page_size; - hdr->ramdisk_size = page_size; - } - else { - fake_size = 0x200; - hdr->ramdisk_size = 0; - } - - /* Write the image header */ - if (write(ofd, orig, page_size) != page_size) { - printf("[-] Failed to write header to output file.\n"); - return 1; - } - - page_kernel_size = (orig_kernel_size + page_mask) & ~page_mask; - - /* Write the kernel */ - if (write(ofd, orig + page_size, page_kernel_size) != page_kernel_size) { - printf("[-] Failed to write kernel to output file.\n"); - return 1; - } - - page_ramdisk_size = (orig_ramdisk_size + page_mask) & ~page_mask; - - /* Write the ramdisk */ - if (write(ofd, orig + page_size + page_kernel_size, page_ramdisk_size) != page_ramdisk_size) { - printf("[-] Failed to write ramdisk to output file.\n"); - return 1; - } - - /* Write fake_size bytes of original code to the output */ - buf = malloc(fake_size); - if (!buf) { - printf("[-] Out of memory.\n"); - return 1; - } - - lseek(aboot_fd, tgt->check_sigs - aboot_base - offset, SEEK_SET); - read(aboot_fd, buf, fake_size); - - if (write(ofd, buf, fake_size) != fake_size) { - printf("[-] Failed to write original aboot code to output file.\n"); - return 1; - } - - /* Save this position for later */ - pos = lseek(ofd, 0, SEEK_CUR); - - /* Write the device tree if needed */ - if (hdr->dt_size) { - - printf("[+] Writing device tree.\n"); - - if (write(ofd, orig + page_size + page_kernel_size + page_ramdisk_size, hdr->dt_size) != hdr->dt_size) { - printf("[-] Failed to write device tree to output file.\n"); - return 1; - } - } - - lseek(ofd, pos - (fake_size - offset), SEEK_SET); - - /* Write the patch */ - if (write(ofd, patch, sizeof(patch)) != sizeof(patch)) { - printf("[-] Failed to write patch to output file.\n"); - return 1; - } - - close(ifd); - close(ofd); - close(aboot_fd); - - printf("[+] Output file written to %s\n", out_image); - - return 0; -} diff --git a/loki_tool/loki_unlok.c b/loki_tool/loki_unlok.c deleted file mode 100644 index f2e685a..0000000 --- a/loki_tool/loki_unlok.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * loki_unlok - * - * A utility to revert the changes made by loki_patch. - * - * by Dan Rosenberg (@djrbliss) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "loki.h" - -static unsigned char patch[] = PATCH; - -/* Find the original address of the ramdisk, which - * was embedded in the shellcode. */ -int find_ramdisk_addr(void *img, int sz) -{ - - int i, ramdisk = 0; - - for (i = 0; i < sz - (sizeof(patch) - 9); i++) { - if (!memcmp((char *)img + i, patch, sizeof(patch)-9)) { - ramdisk = *(int *)(img + i + sizeof(patch) - 5); - break; - } - } - - return ramdisk; -} - -int loki_unlok(const char* in_image, const char* out_image) -{ - int ifd, ofd; - unsigned int orig_ramdisk_size, orig_kernel_size, orig_ramdisk_addr; - unsigned int page_kernel_size, page_ramdisk_size, page_size, page_mask, fake_size; - void *orig; - struct stat st; - struct boot_img_hdr *hdr; - struct loki_hdr *loki_hdr; - - ifd = open(in_image, O_RDONLY); - if (ifd < 0) { - printf("[-] Failed to open %s for reading.\n", in_image); - return 1; - } - - ofd = open(out_image, O_WRONLY|O_CREAT|O_TRUNC, 0644); - if (ofd < 0) { - printf("[-] Failed to open %s for writing.\n", out_image); - return 1; - } - - /* Map the original boot/recovery image */ - if (fstat(ifd, &st)) { - printf("[-] fstat() failed.\n"); - return 1; - } - - orig = mmap(0, (st.st_size + 0x2000 + 0xfff) & ~0xfff, PROT_READ|PROT_WRITE, MAP_PRIVATE, ifd, 0); - if (orig == MAP_FAILED) { - printf("[-] Failed to mmap input file.\n"); - return 1; - } - - hdr = orig; - loki_hdr = orig + 0x400; - - if (memcmp(loki_hdr->magic, "LOKI", 4)) { - printf("[-] Input file is not a Loki image.\n"); - - /* Copy the entire file to the output transparently */ - if (write(ofd, orig, st.st_size) != st.st_size) { - printf("[-] Failed to copy Loki image.\n"); - return 1; - } - - printf("[+] Copied Loki image to %s.\n", out_image); - - return 0; - } - - page_size = hdr->page_size; - page_mask = hdr->page_size - 1; - - /* Infer the size of the fake block based on the newer ramdisk address */ - if (hdr->ramdisk_addr > 0x88f00000 || hdr->ramdisk_addr < 0xfa00000) - fake_size = page_size; - else - fake_size = 0x200; - - orig_ramdisk_addr = find_ramdisk_addr(orig, st.st_size); - if (orig_ramdisk_addr == 0) { - printf("[-] Failed to find original ramdisk address.\n"); - return 1; - } - - /* Restore the original header values */ - hdr->ramdisk_addr = orig_ramdisk_addr; - hdr->kernel_size = orig_kernel_size = loki_hdr->orig_kernel_size; - hdr->ramdisk_size = orig_ramdisk_size = loki_hdr->orig_ramdisk_size; - - /* Erase the loki header */ - memset(loki_hdr, 0, sizeof(*loki_hdr)); - - /* Write the image header */ - if (write(ofd, orig, page_size) != page_size) { - printf("[-] Failed to write header to output file.\n"); - return 1; - } - - page_kernel_size = (orig_kernel_size + page_mask) & ~page_mask; - - /* Write the kernel */ - if (write(ofd, orig + page_size, page_kernel_size) != page_kernel_size) { - printf("[-] Failed to write kernel to output file.\n"); - return 1; - } - - page_ramdisk_size = (orig_ramdisk_size + page_mask) & ~page_mask; - - /* Write the ramdisk */ - if (write(ofd, orig + page_size + page_kernel_size, page_ramdisk_size) != page_ramdisk_size) { - printf("[-] Failed to write ramdisk to output file.\n"); - return 1; - } - - /* Write the device tree if needed */ - if (hdr->dt_size) { - - printf("[+] Writing device tree.\n"); - - /* Skip an additional fake_size (page_size of 0x200) bytes */ - if (write(ofd, orig + page_size + page_kernel_size + page_ramdisk_size + fake_size, hdr->dt_size) != hdr->dt_size) { - printf("[-] Failed to write device tree to output file.\n"); - return 1; - } - } - - close(ifd); - close(ofd); - - printf("[+] Output file written to %s\n", out_image); - - return 0; -} diff --git a/loki_tool/main.c b/loki_tool/main.c deleted file mode 100644 index 1d3d9d3..0000000 --- a/loki_tool/main.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * loki_patch - * - * A utility to patch unsigned boot and recovery images to make - * them suitable for booting on the AT&T/Verizon Samsung - * Galaxy S4, Galaxy Stellar, and various locked LG devices - * - * by Dan Rosenberg (@djrbliss) - * - */ - -#include -#include -#include "loki.h" - -static int print_help(const char* cmd) { - printf("Usage\n"); - printf("> Patch partition file image:\n"); - printf("%s [patch] [boot|recovery] [aboot.img] [in.img] [out.lok]\n", cmd); - printf("\n"); - printf("> Flash loki image to boot|recovery:\n"); - printf("%s [flash] [boot|recovery] [in.lok]\n", cmd); - printf("\n"); - printf("> Find offset from aboot image:\n"); - printf("%s [find] [aboot.img]\n", cmd); - printf("\n"); - printf("> Revert Loki patching:\n"); - printf("%s [unlok] [in.lok] [out.img]\n", cmd); - printf("\n"); - return 1; -} - -int main(int argc, char **argv) { - printf("Loki tool v%s\n", VERSION); - - if (argc == 6 && strcmp(argv[1], "patch") == 0) { - // argv[2]: partition_label - // argv[3]: aboot_image - // argv[4]: in_image - // argv[5]: out_image - return loki_patch(argv[2], argv[3], argv[4], argv[5]); - } else if (argc == 4 && strcmp(argv[1], "flash") == 0) { - // argv[2]: partition_label - // argv[3]: loki_image - return loki_flash(argv[2], argv[3]); - } else if (argc == 3 && strcmp(argv[1], "find") == 0) { - // argv[2]: aboot_image - return loki_find(argv[2]); - } else if (argc == 4 && strcmp(argv[1], "unlok") == 0) { - // argv[2]: in_image - // argv[3]: out_image - return loki_unlok(argv[2], argv[3]); - } - - return print_help(argv[0]); -} diff --git a/mkbootimg.mk b/mkbootimg.mk index 3e3c5b2..f71a71a 100644 --- a/mkbootimg.mk +++ b/mkbootimg.mk @@ -60,19 +60,19 @@ dtimage: $(INSTALLED_DTIMAGE_TARGET) endif endif -ifeq ($(strip $(TARGET_NEEDS_LOKI)),true) -LOKI_TOOL := loki_tool +ifeq ($(strip $(TARGET_NEEDS_OOR)),true) +BYPASS_TOOL := oor else -LOKI_TOOL := echo -TARGET_LOKI_ABOOT_IMAGE := +BYPASS_TOOL := echo +TARGET_ABOOT_IMAGE := endif $(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES) $(BOOTIMAGE_EXTRA_DEPS) $(call pretty,"Target boot image: $@") $(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@ $(hide) echo -n "SEANDROIDENFORCE" >> $@ - $(hide) $(LOKI_TOOL) patch boot $(TARGET_LOKI_ABOOT_IMAGE) $@ $@.lok - $(hide) cp $@.lok $@ || true + $(hide) $(BYPASS_TOOL) -p $(TARGET_ABOOT_IMAGE) $@ $@.oor + $(hide) cp $@.oor $@ || true $(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE),raw) @echo "Made boot image: $@" @@ -80,7 +80,7 @@ $(INSTALLED_RECOVERYIMAGE_TARGET): $(MKBOOTIMG) $(recovery_ramdisk) $(recovery_k @echo "----- Making recovery image ------" $(hide) $(MKBOOTIMG) $(INTERNAL_RECOVERYIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@ $(hide) echo -n "SEANDROIDENFORCE" >> $@ - $(hide) $(LOKI_TOOL) patch recovery $(TARGET_LOKI_ABOOT_IMAGE) $@ $@.lok - $(hide) cp $@.lok $@ || true + $(hide) $(BYPASS_TOOL) -p $(TARGET_ABOOT_IMAGE) $@ $@.oor + $(hide) cp $@.oor $@ || true $(hide) $(call assert-max-image-size,$@,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE),raw) @echo "Made recovery image: $@" diff --git a/oor/.gitignore b/oor/.gitignore new file mode 100644 index 0000000..f6b17c2 --- /dev/null +++ b/oor/.gitignore @@ -0,0 +1,6 @@ +bin/ +obj-target/ +gen/ +obj-arm/*.o +tools/ +obj-host/ diff --git a/oor/Android.bp b/oor/Android.bp new file mode 100644 index 0000000..ec798a9 --- /dev/null +++ b/oor/Android.bp @@ -0,0 +1,49 @@ +cc_binary_host { + name: "bin_to_c", + cflags: [ + "-std=c99", + ], + srcs: [ + "src/bin_to_c.c", + "src/file_utils.c", + ], +} + +gensrcs { + name: "patch_code", + tools: [ + "bin_to_c", + ], + cmd: "mkdir -p $(genDir)/$(in) " + + "&& $(location bin_to_c) " + + " $(in) patch_code $(out)", + srcs: [ + "obj-arm/patch_code.bin", + ], + output_extension: "c", +} + +cc_binary { + name: "oor", + static_executable: true, + cflags: [ + "-std=c99", + ], + srcs: [ + "src/aboot_image.c", + "src/boot_image.c", + "src/cmd_patch.c", + "src/cmd_verify.c", + "src/file_utils.c", + "src/asm.c", + "src/cmd_crc.c", + "src/cmd_redirect.c", + "src/config.c", + "src/little_endian.c", + "src/cmd_list.c", + "src/cmd_undo.c", + "src/crc.c", + "src/main.c", + ":patch_code", + ], +} diff --git a/oor/Makefile b/oor/Makefile new file mode 100644 index 0000000..ded950f --- /dev/null +++ b/oor/Makefile @@ -0,0 +1,62 @@ +HOST_CC ?= gcc +TARGET_CC ?= gcc +TARGET_STRIP ?= $(TARGET_CC:%gcc=%)strip +ARM_CC ?= arm-linux-androideabi-gcc +ARM_OBJCOPY ?= $(ARM_CC:%gcc=%)objcopy + +OOR_MODULES := aboot_image asm boot_image cmd_crc cmd_list cmd_patch cmd_redirect \ + cmd_undo cmd_verify config crc file_utils little_endian main +ASM_MODULES := patch_code +BIN_TO_C_MODULES := bin_to_c file_utils + +OOR_OBJS := $(addsuffix .o,$(addprefix obj-target/,$(OOR_MODULES))) +ASM_GEN := $(addsuffix .c,$(addprefix gen/,$(ASM_MODULES))) +BIN_TO_C_OBJS := $(addsuffix .o,$(addprefix obj-host/,$(BIN_TO_C_MODULES))) + +all: bin/oor$(TARGET_SUFFIX) + +bin/oor$(TARGET_SUFFIX): $(OOR_OBJS) $(ASM_GEN) | bin + $(TARGET_CC) $(TARGET_CFLAGS) -o $@ $(OOR_OBJS) $(ASM_GEN) + $(TARGET_STRIP) $@ + +bin: + mkdir -p $@ + +obj-target/%.o: src/%.c src/*.h | obj-target + $(TARGET_CC) $(TARGET_CFLAGS) -std=c99 -c -o $@ $< + +obj-target: + mkdir -p $@ + +gen/%.c: obj-arm/%.bin tools/bin_to_c | gen + ./tools/bin_to_c $< $(@:gen/%.c=%) $@ + +gen: + mkdir -p $@ + +obj-arm/%.bin: obj-arm/%.o | obj-arm + $(ARM_OBJCOPY) -O binary $< $@ + +obj-arm/%.o: src/%.S src/*.h | obj-arm + $(ARM_CC) $(ARM_CFLAGS) -c -o $@ $< + +obj-arm: + mkdir -p $@ + +tools/bin_to_c: $(BIN_TO_C_OBJS) | tools + $(HOST_CC) $(HOST_CFLAGS) -o $@ $(BIN_TO_C_OBJS) + +tools: + mkdir -p $@ + +obj-host/%.o: src/%.c src/*.h | obj-host + $(HOST_CC) $(HOST_CFLAGS) -std=c99 -c -o $@ $< + +obj-host: + mkdir -p $@ + +clean: + -rm -rf bin obj-target gen obj-arm tools obj-host + +.PHONY: all clean +.PRECIOUS: obj-arm/%.o obj-arm/%.bin diff --git a/oor/README.md b/oor/README.md new file mode 100644 index 0000000..e4d3a08 --- /dev/null +++ b/oor/README.md @@ -0,0 +1,68 @@ +# OutOfRange + +This repository contains a tool that can be used to exploit a vulnerability in some bootloaders of Samsung phones from around 2013, in order to boot custom operating systems. + +## What to Expect + +**WARNING:** While this is unlikely to permanently brick your phone, it may still cause it to be in an unbootable state. In either case, I disclaim all responsibility. By using this tool, I assume you know what you are doing. + +Given a bootloader image and a custom boot or recovery image, this tool will output a modified image that can be used on a phone with that specific bootloader. This is similar to what the [Loki tool](https://github.com/djrbliss/loki) does. + +There is also a second mode where an image can be created redirecting the bootloader to boot from a different partition. This can be helpful for booting larger images that don't fit within the appropriate partition. + +Quirks / Things to keep in mind: + +- You will not be able to flash these modified images in Odin, as the bootloader is still locked. To flash them, use `dd` as root. +- The modified images are several hundred kilobytes larger than the original images, since the bootloader code needs to be bundled with the images. If an output image would be too large to flash, the program will error out. To work around this, you can find an unused partition, flash the original image there, and use this tool in redirection mode to boot from that partition. + +## How to Use + +Either Linux or Windows can be used here. + +Prerequisites: + +- A supported aboot image from your device +- A boot image to modify (except for redirection mode) + +Steps: + +- Download the appropriate ZIP file from the [releases page](https://github.com/jb881122/out-of-range/releases) +- Extract the `oor` binary file +- Go to that directory in a command-line shell +- Run either `./oor -p ` or `./oor -r ` (removing the `./` if running in a cmd.exe shell and replacing the arguments as appropriate) +- If it worked, you should have a new image you can flash. Otherwise, an error will be printed on the screen. + +## How to Compile + +It is best to do this in Linux, because I have not tested any of this on Windows. + +Prerequisites: +- `arm-linux-androideabi-gcc` and `arm-linux-androideabi-objcopy` (the NDK provides these; I used GCC 4.8) +- `gcc` and `strip` for your host and target platforms +- `make` +- `git` (only if you plan on cloning this repository) + +Steps: +- Clone or otherwise get the repository's files into a directory. +- Go to that directory +- Set `$HOST_CC`, `$TARGET_CC`, and `$ARM_CC` to the appropriate compilers if you need something other than the default values +- Other variables that can be set for different configurations: `$TARGET_STRIP`, `$ARM_OBJCOPY`, `$TARGET_SUFFIX`, `$HOST_CFLAGS`, `$TARGET_CFLAGS`, and `$ARM_CFLAGS` +- Run `make` + +If it came together correctly, the `oor` tool should be found in the `bin/` folder. + +## Adding Support for Another Bootloader + +The file `src/config.c` contains the configurations for all of the bootloaders supported by this tool. To add support for a bootloader, add another configuration to this list, using one of the existing configurations as a template. + +The `src/config.h` file has comments describing each value and how it is obtained. This will require some extensive disassembly of the bootloader in question, for which information can be found on [this article](https://newandroidbook.com/Articles/aboot.html). + +Once the configuration is added, compile and test the tool to make sure it works for your device and submit a pull request. + +## Room for Improvement + +- Adding configurations for more bootloaders and devices + +## Licensing + +The contents of this repository are hereby released into the public domain. diff --git a/oor/obj-arm/patch_code.bin b/oor/obj-arm/patch_code.bin new file mode 100644 index 0000000000000000000000000000000000000000..eebfb923619d6bfd31d41536b7e1030ba134082a GIT binary patch literal 380 zcmX|*J4*vW6ov03%^E~}1koUI#T0gyVkrc~M!_b6jX%I*EUawCDiMUNO|YBkEd3h_ zmRqGVGr1_SS>r1j&3FdH;$!c3&&=#uxzN0S-L#b>&1*zYF+4uiOzMm)LbI4Lj$-4& ze%-Hj1Yw@iT>SHa(VSOp&e5KmCn`K9n(s{0M$))tymt>zaVC|T7vU*lZ5T*f>LittHz$fm&pd=4J62~Z&F8N5RZ-O%$Avs9WR)v&?O;R!l4B>sW( zhw#vS +#include +#include + +aboot_image *aboot_image_read(char *file_name) { + aboot_image *ret = NULL; + aboot_image *image = NULL; + char *file_bytes = NULL; + size_t num_bytes = 0; + uint32_t img_base = 0; + uint32_t offset_val = 0; + uint32_t code_offset = 0; + uint32_t code_size = 0; + uint32_t code_end = 0; + uint32_t sig_offset = 0; + uint32_t sig_size = 0; + uint32_t sig_end = 0; + uint32_t certs_offset = 0; + uint32_t certs_size = 0; + uint32_t img_size = 0; + + file_bytes = read_all_bytes(file_name, &num_bytes); + if(!file_bytes) { + goto out; + } + + /* Make sure we can parse this file as an aboot image */ + + offset_val = 0x28; + if(num_bytes < offset_val + || le_uint32_read(file_bytes, 0x0) != 0x5 + || le_uint32_read(file_bytes, 0x4) != 0x3) { + goto out; + } + + img_base = le_uint32_read(file_bytes, 0xC); + code_offset = offset_val; + code_size = le_uint32_read(file_bytes, 0x14); + code_end = img_base + code_size; + + offset_val += code_size; + sig_offset = offset_val; + sig_size = le_uint32_read(file_bytes, 0x1C); + sig_end = code_end + sig_size; + + offset_val += sig_size; + certs_offset = offset_val; + certs_size = le_uint32_read(file_bytes, 0x24); + + offset_val += certs_size; + img_size = code_size + sig_size + certs_size; + if(num_bytes < offset_val + || le_uint32_read(file_bytes, 0x18) != code_end + || le_uint32_read(file_bytes, 0x20) != sig_end + || le_uint32_read(file_bytes, 0x10) != img_size) { + goto out; + } + + image = malloc(sizeof(aboot_image)); + if(!image) { + goto out; + } + + /* Now fill out the aboot_image structure */ + image->_buffer = file_bytes; + image->_buf_len = num_bytes; + image->img_base = img_base; + image->code_ptr = file_bytes + code_offset; + image->code_size = code_size; + image->sig_ptr = file_bytes + sig_offset; + image->sig_size = sig_size; + image->certs_ptr = file_bytes + certs_offset; + image->certs_size = certs_size; + + ret = image; +out: + if(!ret) { + if(image) { + free(image); + } + if(file_bytes) { + free(file_bytes); + } + } + return ret; +} + +void aboot_image_delete(aboot_image *image) { + free(image->_buffer); + free(image); +} diff --git a/oor/src/aboot_image.h b/oor/src/aboot_image.h new file mode 100644 index 0000000..0323717 --- /dev/null +++ b/oor/src/aboot_image.h @@ -0,0 +1,26 @@ +#ifndef _ABOOT_IMAGE_H +#define _ABOOT_IMAGE_H + +#include +#include + +/* Note: This does not contain all information in an aboot image. */ +typedef struct { + uint32_t img_base; + + uint32_t code_size; + char *code_ptr; + uint32_t sig_size; + char *sig_ptr; + uint32_t certs_size; + char *certs_ptr; + + char *_buffer; + size_t _buf_len; +} aboot_image; + +aboot_image *aboot_image_read(char *file_name); + +void aboot_image_delete(aboot_image *image); + +#endif diff --git a/oor/src/asm.c b/oor/src/asm.c new file mode 100644 index 0000000..d69595a --- /dev/null +++ b/oor/src/asm.c @@ -0,0 +1,166 @@ +#include "asm.h" +#include "boot_image.h" +#include "config.h" +#include "little_endian.h" +#include "udfs.h" + +#include +#include +#include +#include + +extern char patch_code[]; +extern size_t patch_code_len; + +void add_slide_thumb(char *code, size_t offset, size_t len, uint32_t img_base) { + size_t curr_pos = offset; + + le_uint32_write(0x47004800, code, curr_pos); + curr_pos += 4; + le_uint32_write(img_base - 0x800, code, curr_pos); + curr_pos += 4; + le_uint16_write(0xE7FA, code, curr_pos); + curr_pos += 2; + while(curr_pos <= offset + len - 2) { + le_uint16_write(0xE7FD, code, curr_pos); + curr_pos += 2; + } +} + +void add_slide_arm(char *code, size_t offset, size_t len, uint32_t img_base) { + size_t curr_pos = offset; + + le_uint32_write(0xE59F0000, code, curr_pos); + curr_pos += 4; + le_uint32_write(0xE12FFF10, code, curr_pos); + curr_pos += 4; + le_uint32_write(img_base - 0x800, code, curr_pos); + curr_pos += 4; + le_uint32_write(0xEAFFFFFB, code, curr_pos); + curr_pos += 4; + while(curr_pos <= offset + len - 4) { + le_uint32_write(0xEAFFFFFD, code, curr_pos); + curr_pos += 4; + } +} + +void add_slide(char *code, size_t offset, size_t len, uint32_t img_base, + instr_type instr) { + if(instr == IT_THUMB) { + add_slide_thumb(code, offset, len, img_base); + } else { + add_slide_arm(code, offset, len, img_base); + } +} + +int get_udf_offsets(size_t *buf, size_t num_udfs, char *code, size_t len) { + for(uint32_t i = 0; i < num_udfs; i++) { + buf[i] = 0xFFFFFFFF; + for(uint32_t o = 0; o <= len - 4; o += 4) { + if(le_uint32_read(code, o) == UDF(i)) { + buf[i] = o; + break; + } + } + if(buf[i] == 0xFFFFFFFF) { + return -1; + } + } + return 0; +} + +char *make_exploit_ramdisk(char *aboot_code, size_t aboot_code_len, + bootloader_config *config, size_t input_len, size_t *output_len) { + size_t ramdisk_len = 0; + int sub_ret = 0; + char *ret = NULL; + char *ramdisk = NULL; + char *patched_aboot = NULL; + uint32_t func_addr = 0; + uint32_t fifo_read_offset = 0; + size_t udf_locs[NUM_UDFS]; + size_t stored_code_len = 0; + + if(output_len) { + *output_len = 0; + } + + if(patch_code_len + config->mmc_boot_fifo_read_len - 4 > 0x800) { + goto out; + } + + stored_code_len = aboot_code_len < config->max_stored_code ? + aboot_code_len : config->max_stored_code; + ramdisk_len = 0x800 + stored_code_len; + + sub_ret = get_udf_offsets(udf_locs, NUM_UDFS, patch_code, patch_code_len); + if(sub_ret) { + goto out; + } + + ramdisk = malloc(ramdisk_len); + if(!ramdisk) { + goto out; + } + memset(ramdisk, 0, 0x800); + + patched_aboot = ramdisk + 0x800; + memcpy(ramdisk, patch_code, patch_code_len); + memcpy(patched_aboot, aboot_code, stored_code_len); + + le_uint32_write(config->mmc_boot_fifo_read, ramdisk, udf_locs[UDF_MBFRP]); + le_uint32_write(config->mmc_boot_fifo_read_len, ramdisk, udf_locs[UDF_MBFRL]); + le_uint32_write(config->img_base + 4, ramdisk, udf_locs[UDF_UIHP]); + le_uint32_write(le_uint32_read(aboot_code, 4), ramdisk, udf_locs[UDF_UIHO]); + le_uint32_write(config->kernel_load_ptr, ramdisk, udf_locs[UDF_LBI]); + le_uint32_write(input_len, ramdisk, udf_locs[UDF_BIL]); + le_uint32_write(config->scratch_addr, ramdisk, udf_locs[UDF_SA]); + le_uint32_write(config->unified_addr, ramdisk, udf_locs[UDF_UA]); + func_addr = config->mmc_boot_fifo_read; + if(config->mmc_boot_fifo_read_instr == IT_THUMB) { + func_addr++; + } + le_uint32_write(func_addr, ramdisk, udf_locs[UDF_MBFR]); + func_addr = config->mmc_boot_main; + if(config->mmc_boot_main_instr == IT_THUMB) { + func_addr++; + } + le_uint32_write(func_addr, ramdisk, udf_locs[UDF_MBM]); + func_addr = config->boot_linux_from_mmc; + if(config->boot_linux_from_mmc_instr == IT_THUMB) { + func_addr++; + } + le_uint32_write(func_addr, ramdisk, udf_locs[UDF_BLFM]); + le_uint32_write(config->mmc_sdc1_base, ramdisk, udf_locs[UDF_MSB]); + le_uint32_write(config->boot_from_recovery, ramdisk, udf_locs[UDF_BFR]); + le_uint32_write(config->boot_name_ptr, ramdisk, udf_locs[UDF_BNP]); + le_uint32_write(config->check_sig, ramdisk, udf_locs[UDF_CSP]); + if(config->check_sig_instr == IT_THUMB) { + le_uint32_write(4, ramdisk, udf_locs[UDF_CSPL]); + le_uint32_write(0x47702000, ramdisk, udf_locs[UDF_CSP1]); + } else { + le_uint32_write(8, ramdisk, udf_locs[UDF_CSPL]); + le_uint32_write(0xE3A00000, ramdisk, udf_locs[UDF_CSP1]); + le_uint32_write(0xE12FFF1E, ramdisk, udf_locs[UDF_CSP2]); + } + fifo_read_offset = config->mmc_boot_fifo_read - config->img_base; + memcpy(ramdisk + udf_locs[UDF_OB], aboot_code + fifo_read_offset, + config->mmc_boot_fifo_read_len); + + add_slide(patched_aboot, fifo_read_offset, config->mmc_boot_fifo_read_len, + config->img_base, config->mmc_boot_fifo_read_instr); + le_uint32_write(0xEAFFFDFD, patched_aboot, 4); + + if(output_len) { + *output_len = ramdisk_len; + } + + ret = ramdisk; +out: + if(!ret) { + if(ramdisk) { + free(ramdisk); + } + } + return ret; +} diff --git a/oor/src/asm.h b/oor/src/asm.h new file mode 100644 index 0000000..1761883 --- /dev/null +++ b/oor/src/asm.h @@ -0,0 +1,11 @@ +#ifndef _ASM_H +#define _ASM_H + +#include "config.h" + +#include + +char *make_exploit_ramdisk(char *aboot_code, size_t aboot_code_len, + bootloader_config *config, size_t input_len, size_t *output_len); + +#endif diff --git a/oor/src/bin_to_c.c b/oor/src/bin_to_c.c new file mode 100644 index 0000000..b6c5c36 --- /dev/null +++ b/oor/src/bin_to_c.c @@ -0,0 +1,136 @@ +#include "file_utils.h" + +#include +#include +#include +#include +#include + +const char begin_template[] = "#include \nchar %s[] = {\n "; +#define BT_EMPTY_LEN (sizeof("#include \nchar [] = {\n ") - 1) + +const char byte_format[] = "0x%02X"; +#define BF_LEN (sizeof("0x00") - 1) + +const char non_16_separator[] = ", "; +#define N16S_LEN (sizeof(non_16_separator) - 1) + +const char per_16_separator[] = ",\n "; +#define P16S_LEN (sizeof(per_16_separator) - 1) + +const char ending[] = "\n};\n"; +#define ENDING_LEN (sizeof(ending) - 1) + +const char size_template[] = "size_t %s_len = sizeof(%s);\n"; +#define ST_EMPTY_LEN (sizeof("size_t _len = sizeof();\n") - 1) + +size_t get_output_size(size_t num_bytes, char *var_name) { + size_t varlen = strlen(var_name); + size_t ret = BT_EMPTY_LEN; + + ret += varlen; + for(size_t i = 0; i < num_bytes; i++) { + ret += BF_LEN; + if(i != num_bytes - 1) { + if(i % 16 == 15) { + ret += P16S_LEN; + } else { + ret += N16S_LEN; + } + } + } + ret += ENDING_LEN; + + ret += ST_EMPTY_LEN; + ret += 2 * varlen; + + ret += 1; /* terminating null byte */ + + return ret; +} + +#define OUT_APPEND(out_ptr, format...) \ + sprintf_ret = sprintf(out_ptr, format); \ + if(sprintf_ret < 0) { \ + goto out; \ + } \ + out_ptr += sprintf_ret + +int write_output_text(char *output, char *bytes, size_t num_bytes, char *var_name) { + int ret = -1; + int sprintf_ret = 0; + char *out_ptr = output; + + OUT_APPEND(out_ptr, begin_template, var_name); + for(size_t i = 0; i < num_bytes; i++) { + OUT_APPEND(out_ptr, byte_format, (uint8_t)bytes[i]); + if(i != num_bytes - 1) { + if(i % 16 == 15) { + OUT_APPEND(out_ptr, per_16_separator); + } else { + OUT_APPEND(out_ptr, non_16_separator); + } + } + } + OUT_APPEND(out_ptr, ending); + + OUT_APPEND(out_ptr, size_template, var_name, var_name); + + ret = 0; +out: + return ret; +} + +int main(int argc, char *argv[]) { + int ret = -2; + int write_ret = 0; + char *file_bytes = NULL; + size_t num_bytes = 0; + char *file_text = NULL; + size_t text_size = 0; + + if(argc != 4) { + printf("Wrong number of arguments\n" + "Usage: bin_to_c \n"); + goto out; + } + + ret = -1; + + file_bytes = read_all_bytes(argv[1], &num_bytes); + if(!file_bytes) { + printf("Failed to read binary file\n"); + goto out; + } + + text_size = get_output_size(num_bytes, argv[2]); + file_text = malloc(text_size); + if(!file_text) { + printf("Failed to allocate memory for output text\n"); + goto out; + } + + write_ret = write_output_text(file_text, file_bytes, num_bytes, argv[2]); + if(write_ret) { + printf("Failed to generate output text\n"); + goto out; + } + + /* Don't include the trailing null byte in the file */ + write_ret = write_all_bytes(argv[3], file_text, text_size - 1); + if(write_ret) { + printf("Failed to write output file\n"); + goto out; + } + + ret = 0; + printf("Success\n"); +out: + if(file_bytes) { + free(file_bytes); + } + if(file_text) { + free(file_text); + } + return ret; +} diff --git a/oor/src/boot_image.c b/oor/src/boot_image.c new file mode 100644 index 0000000..5c24e6b --- /dev/null +++ b/oor/src/boot_image.c @@ -0,0 +1,257 @@ +#include "boot_image.h" +#include "file_utils.h" +#include "little_endian.h" + +#include +#include +#include +#include + +char boot_magic[] = {'A', 'N', 'D', 'R', 'O', 'I', 'D', '!'}; +size_t boot_magic_len = sizeof(boot_magic); + +uint32_t round_up_page(uint32_t offset) { + return (((offset - 1) >> 11) + 1) << 11; +} + +boot_image *boot_image_new(void) { + boot_image *ret = NULL; + + ret = malloc(sizeof(boot_image)); + if(!ret) { + goto out; + } + + memset(ret, 0, sizeof(boot_image)); + memcpy(ret->magic, boot_magic, boot_magic_len); + +out: + return ret; +} + +boot_image *boot_image_read(char *file_name) { + boot_image *ret = NULL; + boot_image *image = NULL; + char *file_bytes = NULL; + size_t num_bytes = 0; + uint32_t offset_val = 0; + uint32_t kernel_offset = 0; + uint32_t ramdisk_offset = 0; + uint32_t second_offset = 0; + uint32_t dt_offset = 0; + int truncated_ramdisk = 0; + + file_bytes = read_all_bytes(file_name, &num_bytes); + if(!file_bytes) { + goto out; + } + + /* Make sure we can parse this file as a boot image */ + offset_val = 0x800; + if(num_bytes < offset_val) { + goto out; + } + if(le_uint32_read(file_bytes, 0x24) != 0x800) { + goto out; + } + kernel_offset = offset_val; + offset_val += round_up_page(le_uint32_read(file_bytes, 0x8)); + if(num_bytes < offset_val) { + goto out; + } + ramdisk_offset = offset_val; + offset_val += round_up_page(le_uint32_read(file_bytes, 0x10)); + if(num_bytes < offset_val) { + truncated_ramdisk = 1; + } else { + second_offset = offset_val; + offset_val += round_up_page(le_uint32_read(file_bytes, 0x18)); + dt_offset = offset_val; + offset_val += round_up_page(le_uint32_read(file_bytes, 0x28)); + if(num_bytes < offset_val) { + goto out; + } + } + + image = malloc(sizeof(boot_image)); + if(!image) { + goto out; + } + + /* Now fill out the boot_image structure */ + image->_buffer = file_bytes; + image->_buf_len = num_bytes; + image->_kernel_ptr_separate = 0; + image->_ramdisk_ptr_separate = 0; + memcpy(image->magic, file_bytes, boot_magic_len); + image->kernel_ptr = file_bytes + kernel_offset; + image->kernel_size = le_uint32_read(file_bytes, 0x8); + image->kernel_addr = le_uint32_read(file_bytes, 0xC); + image->ramdisk_ptr = file_bytes + ramdisk_offset; + image->ramdisk_size_display = le_uint32_read(file_bytes, 0x10); + image->ramdisk_addr = le_uint32_read(file_bytes, 0x14); + image->second_addr = le_uint32_read(file_bytes, 0x1C); + image->tags_addr = le_uint32_read(file_bytes, 0x20); + if(!truncated_ramdisk) { + image->ramdisk_size = image->ramdisk_size_display; + image->second_ptr = file_bytes + second_offset; + image->second_size = le_uint32_read(file_bytes, 0x18); + image->dt_ptr = file_bytes + dt_offset; + image->dt_size = le_uint32_read(file_bytes, 0x28); + } else { + image->ramdisk_size = num_bytes - ramdisk_offset; + image->second_ptr = NULL; + image->second_size = 0; + image->dt_ptr = NULL; + image->dt_size = 0; + } + + ret = image; +out: + if(!ret) { + if(image) { + free(image); + } + if(file_bytes) { + free(file_bytes); + } + } + return ret; +} + +int boot_image_set_kernel(char *kernel, size_t num_bytes, boot_image *image) { + int ret = -1; + char *kernel_copy = NULL; + + kernel_copy = malloc(num_bytes); + if(!kernel_copy) { + goto out; + } + + memcpy(kernel_copy, kernel, num_bytes); + image->kernel_ptr = kernel_copy; + image->kernel_size = num_bytes; + image->_kernel_ptr_separate = 1; + + ret = 0; +out: + return ret; +} + +int boot_image_set_ramdisk(char *ramdisk, size_t num_bytes, boot_image *image) { + int ret = -1; + char *ramdisk_copy = NULL; + + ramdisk_copy = malloc(num_bytes); + if(!ramdisk_copy) { + goto out; + } + + memcpy(ramdisk_copy, ramdisk, num_bytes); + image->ramdisk_ptr = ramdisk_copy; + image->ramdisk_size = num_bytes; + image->ramdisk_size_display = num_bytes; + image->_ramdisk_ptr_separate = 1; + + ret = 0; +out: + return ret; +} + +char *boot_image_to_bytes(boot_image *image, size_t *output_len) { + char *ret = NULL; + size_t num_bytes = 0; + size_t kernel_offset = 0; + size_t ramdisk_offset = 0; + size_t second_offset = 0; + size_t dt_offset = 0; + + if(output_len) { + *output_len = 0; + } + + num_bytes = 0x800; + kernel_offset = num_bytes; + num_bytes += round_up_page(image->kernel_size); + ramdisk_offset = num_bytes; + num_bytes += round_up_page(image->ramdisk_size); + second_offset = num_bytes; + num_bytes += round_up_page(image->second_size); + dt_offset = num_bytes; + num_bytes += round_up_page(image->dt_size); + + ret = malloc(num_bytes); + if(!ret) { + goto out; + } + + memset(ret, 0, num_bytes); + if(image->_buffer) { + memcpy(ret, image->_buffer, 0x800); + } + memcpy(ret, image->magic, boot_magic_len); + le_uint32_write(image->kernel_size, ret, 0x8); + le_uint32_write(image->kernel_addr, ret, 0xC); + le_uint32_write(image->ramdisk_size_display, ret, 0x10); + le_uint32_write(image->ramdisk_addr, ret, 0x14); + le_uint32_write(image->second_size, ret, 0x18); + le_uint32_write(image->second_addr, ret, 0x1C); + le_uint32_write(image->tags_addr, ret, 0x20); + le_uint32_write(0x800, ret, 0x24); + le_uint32_write(image->dt_size, ret, 0x28); + + if(image->kernel_size) { + memcpy(ret + kernel_offset, image->kernel_ptr, image->kernel_size); + } + if(image->ramdisk_size) { + memcpy(ret + ramdisk_offset, image->ramdisk_ptr, image->ramdisk_size); + } + if(image->second_size) { + memcpy(ret + second_offset, image->second_ptr, image->second_size); + } + if(image->dt_size) { + memcpy(ret + dt_offset, image->dt_ptr, image->dt_size); + } + + if(output_len) { + *output_len = num_bytes; + } + +out: + return ret; +} + +int boot_image_write(char *file_name, boot_image *image) { + int ret = -1; + int write_ret = 0; + size_t num_bytes = 0; + char *image_bytes = NULL; + + image_bytes = boot_image_to_bytes(image, &num_bytes); + if(!image_bytes) { + goto out; + } + + write_ret = write_all_bytes(file_name, image_bytes, num_bytes); + if(write_ret) { + goto out; + } + + ret = 0; +out: + if(image_bytes) { + free(image_bytes); + } + return ret; +} + +void boot_image_delete(boot_image *image) { + free(image->_buffer); + if(image->_kernel_ptr_separate) { + free(image->kernel_ptr); + } + if(image->_ramdisk_ptr_separate) { + free(image->ramdisk_ptr); + } + free(image); +} diff --git a/oor/src/boot_image.h b/oor/src/boot_image.h new file mode 100644 index 0000000..436069c --- /dev/null +++ b/oor/src/boot_image.h @@ -0,0 +1,49 @@ +#ifndef _BOOT_IMAGE_H +#define _BOOT_IMAGE_H + +#include +#include + +/* Note: This does not contain all information in a boot image. + If any fields are missing, they will be preserved in existing + images and blank or 0 in new images */ +typedef struct { + char magic[8]; + uint32_t kernel_addr; + uint32_t ramdisk_size_display; + uint32_t ramdisk_addr; + uint32_t second_addr; + uint32_t tags_addr; + + uint32_t kernel_size; + char *kernel_ptr; + uint32_t ramdisk_size; + char *ramdisk_ptr; + uint32_t second_size; + char *second_ptr; + uint32_t dt_size; + char *dt_ptr; + + char *_buffer; + size_t _buf_len; + int _kernel_ptr_separate; + int _ramdisk_ptr_separate; +} boot_image; + +uint32_t round_up_page(uint32_t offset); + +boot_image *boot_image_new(void); +boot_image *boot_image_read(char *file_name); + +int boot_image_set_kernel(char *kernel, size_t num_bytes, boot_image *image); +int boot_image_set_ramdisk(char *ramdisk, size_t num_bytes, boot_image *image); + +char *boot_image_to_bytes(boot_image *image, size_t *len); +int boot_image_write(char *file_name, boot_image *image); + +void boot_image_delete(boot_image *image); + +extern char boot_magic[]; +extern size_t boot_magic_len; + +#endif diff --git a/oor/src/cmd_crc.c b/oor/src/cmd_crc.c new file mode 100644 index 0000000..f684c70 --- /dev/null +++ b/oor/src/cmd_crc.c @@ -0,0 +1,40 @@ +#include "cmd_crc.h" +#include "aboot_image.h" +#include "crc.h" + +#include +#include + +int cmd_crc_main(int argc, char *argv[]) { + int ret = -2; + aboot_image *image = NULL; + char *image_code = NULL; + size_t num_bytes = 0; + uint32_t code_crc = 0; + + if(argc != 3) { + printf("Wrong number of arguments\n"); + goto out; + } + + ret = -1; + + image = aboot_image_read(argv[2]); + if(!image) { + printf("Failed to read aboot image\n"); + goto out; + } + + image_code = image->code_ptr; + num_bytes = image->code_size; + + code_crc = crc32(image_code, num_bytes); + printf("0x%08X\n", code_crc); + + ret = 0; +out: + if(image) { + aboot_image_delete(image); + } + return ret; +} diff --git a/oor/src/cmd_crc.h b/oor/src/cmd_crc.h new file mode 100644 index 0000000..3ce8432 --- /dev/null +++ b/oor/src/cmd_crc.h @@ -0,0 +1,6 @@ +#ifndef _CMD_CRC_H +#define _CMD_CRC_H + +int cmd_crc_main(int argc, char *argv[]); + +#endif diff --git a/oor/src/cmd_list.c b/oor/src/cmd_list.c new file mode 100644 index 0000000..1de36e0 --- /dev/null +++ b/oor/src/cmd_list.c @@ -0,0 +1,22 @@ +#include "cmd_list.h" +#include "config.h" + +#include +#include + +int cmd_list_main(int argc, char *argv[]) { + /* Unused arguments */ + (void)argc; + (void)argv; + + printf("Supported bootloaders: "); + for(size_t i = 0; i < num_configs; i++) { + printf("%s", configs[i].name); + if(i != num_configs - 1) { + printf(", "); + } + } + printf("\n"); + + return 0; +} diff --git a/oor/src/cmd_list.h b/oor/src/cmd_list.h new file mode 100644 index 0000000..c28571e --- /dev/null +++ b/oor/src/cmd_list.h @@ -0,0 +1,6 @@ +#ifndef _CMD_LIST_H +#define _CMD_LIST_H + +int cmd_list_main(int argc, char *argv[]); + +#endif diff --git a/oor/src/cmd_patch.c b/oor/src/cmd_patch.c new file mode 100644 index 0000000..033b49f --- /dev/null +++ b/oor/src/cmd_patch.c @@ -0,0 +1,131 @@ +#include "cmd_patch.h" +#include "config.h" +#include "boot_image.h" +#include "aboot_image.h" +#include "crc.h" +#include "asm.h" +#include "little_endian.h" + +#include +#include +#include +#include +#include + +int cmd_patch_main(int argc, char *argv[]) { + int ret = -2; + int write_ret = 0; + aboot_image *bootloader = NULL; + bootloader_config *config = NULL; + boot_image *input = NULL; + boot_image *output = NULL; + char *bl_code = NULL; + size_t bl_code_len = 0; + char *image_kernel = NULL; + size_t image_kernel_len = 0; + char *image_ramdisk = NULL; + size_t image_ramdisk_len = 0; + uint32_t bl_crc = 0; + + if(argc != 5) { + printf("Wrong number of arguments\n"); + goto out; + } + + ret = -1; + + bootloader = aboot_image_read(argv[2]); + if(!bootloader) { + printf("Failed to read aboot image\n"); + goto out; + } + + bl_code = bootloader->code_ptr; + bl_code_len = bootloader->code_size; + + bl_crc = crc32(bl_code, bl_code_len); + for(size_t i = 0; i < num_configs; i++) { + if(configs[i].code_crc == bl_crc) { + config = &configs[i]; + printf("Supported bootloader found: %s\n", config->name); + break; + } + } + if(!config) { + printf("Unsupported bootloader\n"); + goto out; + } + + input = boot_image_read(argv[3]); + if(!input) { + printf("Failed to open original image\n"); + goto out; + } + + if(input->kernel_size >= 8 + && !memcmp(input->kernel_ptr, boot_magic, 3) + && input->kernel_ptr[3] >= 1 + && input->kernel_ptr[3] <= 2) { + printf("Original image already patched\n"); + goto out; + } + + output = boot_image_new(); + if(!output) { + printf("Failed to allocate memory for output image\n"); + goto out; + } + + image_kernel = boot_image_to_bytes(input, &image_kernel_len); + if(!image_kernel || image_kernel_len < 8) { + printf("Failed to embed original boot image\n"); + goto out; + } + image_kernel[3] = 1; + le_uint32_write(bl_crc, image_kernel, 4); + + image_ramdisk = make_exploit_ramdisk(bl_code, bl_code_len, config, + image_kernel_len, &image_ramdisk_len); + if(!image_ramdisk) { + printf("Failed to generate patched aboot code\n"); + goto out; + } + + if(0x800 + round_up_page(image_kernel_len) + round_up_page(image_ramdisk_len) + > config->max_boot_img_size) { + printf("Output image too large\n"); + goto out; + } + + output->kernel_addr = config->kernel_load_ptr; + boot_image_set_kernel(image_kernel, image_kernel_len, output); + output->ramdisk_addr = config->img_base - 0x800; + boot_image_set_ramdisk(image_ramdisk, image_ramdisk_len, output); + output->ramdisk_size_display = config->img_end - config->img_base + 0x800; + + write_ret = boot_image_write(argv[4], output); + if(write_ret) { + printf("Failed to write output image\n"); + goto out; + } + + printf("Success\n"); + ret = 0; +out: + if(bootloader) { + aboot_image_delete(bootloader); + } + if(input) { + boot_image_delete(input); + } + if(output) { + boot_image_delete(output); + } + if(image_kernel) { + free(image_kernel); + } + if(image_ramdisk) { + free(image_ramdisk); + } + return ret; +} diff --git a/oor/src/cmd_patch.h b/oor/src/cmd_patch.h new file mode 100644 index 0000000..52a4894 --- /dev/null +++ b/oor/src/cmd_patch.h @@ -0,0 +1,6 @@ +#ifndef _CMD_PATCH_H +#define _CMD_PATCH_H + +int cmd_patch_main(int argc, char *argv[]); + +#endif diff --git a/oor/src/cmd_redirect.c b/oor/src/cmd_redirect.c new file mode 100644 index 0000000..bc789de --- /dev/null +++ b/oor/src/cmd_redirect.c @@ -0,0 +1,138 @@ +#include "cmd_redirect.h" +#include "config.h" +#include "boot_image.h" +#include "aboot_image.h" +#include "crc.h" +#include "asm.h" +#include "little_endian.h" + +#include +#include +#include +#include +#include + +char *make_redirect_binary(char *part_name, uint32_t crc, size_t *output_len) { + size_t len = 0; + char *ret = NULL; + + if(output_len) { + *output_len = 0; + } + + len = 8 + strlen(part_name) + 1; + ret = malloc(len); + if(!ret) { + goto out; + } + + memcpy(ret, boot_magic, 3); + ret[3] = 2; + le_uint32_write(crc, ret, 4); + strcpy(ret + 8, part_name); + + if(output_len) { + *output_len = len; + } + +out: + return ret; +} + +int cmd_redirect_main(int argc, char *argv[]) { + int ret = -2; + int write_ret = 0; + aboot_image *bootloader = NULL; + bootloader_config *config = NULL; + boot_image *output = NULL; + char *bl_code = NULL; + size_t bl_code_len = 0; + char *image_kernel = NULL; + size_t image_kernel_len = 0; + char *image_ramdisk = NULL; + size_t image_ramdisk_len = 0; + uint32_t bl_crc = 0; + + if(argc != 5) { + printf("Wrong number of arguments\n"); + goto out; + } + + ret = -1; + + bootloader = aboot_image_read(argv[2]); + if(!bootloader) { + printf("Failed to read aboot image\n"); + goto out; + } + + bl_code = bootloader->code_ptr; + bl_code_len = bootloader->code_size; + + bl_crc = crc32(bl_code, bl_code_len); + for(size_t i = 0; i < num_configs; i++) { + if(configs[i].code_crc == bl_crc) { + config = &configs[i]; + printf("Supported bootloader found: %s\n", config->name); + break; + } + } + if(!config) { + printf("Unsupported bootloader\n"); + goto out; + } + + output = boot_image_new(); + if(!output) { + printf("Failed to allocate memory for output image\n"); + goto out; + } + + image_kernel = make_redirect_binary(argv[3], bl_crc, &image_kernel_len); + if(!image_kernel) { + printf("Failed to generate redirect binary\n"); + goto out; + } + + image_ramdisk = make_exploit_ramdisk(bl_code, bl_code_len, config, + image_kernel_len, &image_ramdisk_len); + if(!image_ramdisk) { + printf("Failed to generate patched aboot code\n"); + goto out; + } + + if(0x800 + round_up_page(image_kernel_len) + round_up_page(image_ramdisk_len) + > config->max_boot_img_size) { + printf("Output image too large\n"); + goto out; + } + + output->kernel_addr = config->kernel_load_ptr; + boot_image_set_kernel(image_kernel, image_kernel_len, output); + output->ramdisk_addr = config->img_base - 0x800; + boot_image_set_ramdisk(image_ramdisk, image_ramdisk_len, output); + output->ramdisk_size_display = config->img_end - config->img_base + 0x800; + + write_ret = boot_image_write(argv[4], output); + if(write_ret) { + printf("Failed to write output image\n"); + goto out; + } + + printf("Success\n"); + ret = 0; +out: + if(bootloader) { + aboot_image_delete(bootloader); + } + if(output) { + boot_image_delete(output); + } + if(image_kernel) { + free(image_kernel); + } + if(image_ramdisk) { + free(image_ramdisk); + } + return ret; +} diff --git a/oor/src/cmd_redirect.h b/oor/src/cmd_redirect.h new file mode 100644 index 0000000..eb14c20 --- /dev/null +++ b/oor/src/cmd_redirect.h @@ -0,0 +1,6 @@ +#ifndef _CMD_REDIRECT_H +#define _CMD_REDIRECT_H + +int cmd_redirect_main(int argc, char *argv[]); + +#endif diff --git a/oor/src/cmd_undo.c b/oor/src/cmd_undo.c new file mode 100644 index 0000000..1676833 --- /dev/null +++ b/oor/src/cmd_undo.c @@ -0,0 +1,72 @@ +#include "cmd_undo.h" +#include "boot_image.h" +#include "file_utils.h" + +#include +#include +#include + +int cmd_undo_main(int argc, char *argv[]) { + int ret = -2; + int write_ret = 0; + boot_image *image = NULL; + char *image_kernel = NULL; + size_t num_bytes = 0; + + if(argc != 4) { + printf("Wrong number of arguments\n"); + goto out; + } + + ret = -1; + + image = boot_image_read(argv[2]); + if(!image) { + printf("Failed to read patched image\n"); + goto out; + } + + image_kernel = image->kernel_ptr; + num_bytes = image->kernel_size; + + if(num_bytes < 8 + || memcmp(image_kernel, boot_magic, 3)) { + goto invalid; + } + + switch(image_kernel[3]) { + case 1: + if(num_bytes < 0x800) { + goto invalid; + } + memcpy(image_kernel, boot_magic, boot_magic_len); + write_ret = write_all_bytes(argv[3], image_kernel, num_bytes); + if(write_ret) { + printf("Failed to write output file\n"); + goto out; + } + break; + case 2: + if(num_bytes < 9 || image_kernel[num_bytes - 1]) { + goto invalid; + } + printf("Redirected image: %s\n", image_kernel + 8); + ret = 1; + goto out; + default: + goto invalid; + } + + ret = 0; + printf("Success\n"); + goto out; + +invalid: + printf("Not a valid patched image\n"); + +out: + if(image) { + boot_image_delete(image); + } + return ret; +} diff --git a/oor/src/cmd_undo.h b/oor/src/cmd_undo.h new file mode 100644 index 0000000..a4b0ba1 --- /dev/null +++ b/oor/src/cmd_undo.h @@ -0,0 +1,6 @@ +#ifndef _CMD_UNDO_H +#define _CMD_UNDO_H + +int cmd_undo_main(int argc, char *argv[]); + +#endif diff --git a/oor/src/cmd_verify.c b/oor/src/cmd_verify.c new file mode 100644 index 0000000..6c02439 --- /dev/null +++ b/oor/src/cmd_verify.c @@ -0,0 +1,74 @@ +#include "cmd_verify.h" +#include "config.h" +#include "boot_image.h" +#include "aboot_image.h" +#include "crc.h" +#include "little_endian.h" + +#include +#include +#include +#include + +int cmd_verify_main(int argc, char *argv[]) { + int ret = -2; + aboot_image *bootloader = NULL; + boot_image *image = NULL; + char *bl_code = NULL; + char *image_kernel = NULL; + size_t num_bytes = 0; + uint32_t bl_crc = 0; + uint32_t image_crc = 0; + + if(argc != 4) { + printf("Wrong number of arguments\n"); + goto out; + } + + ret = -1; + + bootloader = aboot_image_read(argv[2]); + if(!bootloader) { + printf("Failed to read aboot image\n"); + goto out; + } + + bl_code = bootloader->code_ptr; + num_bytes = bootloader->code_size; + + bl_crc = crc32(bl_code, num_bytes); + + image = boot_image_read(argv[3]); + if(!image) { + printf("Failed to read patched image\n"); + goto out; + } + + image_kernel = image->kernel_ptr; + num_bytes = image->kernel_size; + + if(num_bytes < 8 + || memcmp(image_kernel, boot_magic, 3) + || image_kernel[3] < 1 || image_kernel[3] > 2) { + printf("Not a valid patched image\n"); + goto out; + } + + image_crc = le_uint32_read(image_kernel, 4); + + if(image_crc != bl_crc) { + printf("Patched image does not match bootloader\n"); + goto out; + } + + printf("Patched image matches bootloader\n"); + ret = 0; +out: + if(bootloader) { + aboot_image_delete(bootloader); + } + if(image) { + boot_image_delete(image); + } + return ret; +} diff --git a/oor/src/cmd_verify.h b/oor/src/cmd_verify.h new file mode 100644 index 0000000..9df47ef --- /dev/null +++ b/oor/src/cmd_verify.h @@ -0,0 +1,6 @@ +#ifndef _CMD_VERIFY_H +#define _CMD_VERIFY_H + +int cmd_verify_main(int argc, char *argv[]); + +#endif diff --git a/oor/src/config.c b/oor/src/config.c new file mode 100644 index 0000000..7ba17e4 --- /dev/null +++ b/oor/src/config.c @@ -0,0 +1,696 @@ +#include "config.h" + +bootloader_config configs[] = { + { + .code_crc = 0x3572BE4A, + .name = "G730AUCUAMH4", + .img_base = 0x88E00000, + .img_end = 0x89000000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E0564C, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEA, + .mmc_boot_main = 0x88E067F0, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E136FC, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0F994, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88EA5B00, + .boot_name_ptr = 0x88E13988, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x0DE7CE16, + .name = "FAJP_G730AUCUANE2", + .img_base = 0x88E00000, + .img_end = 0x89000000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E05670, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEA, + .mmc_boot_main = 0x88E06804, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E1383C, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FA28, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88EA5B30, + .boot_name_ptr = 0x88E13AC8, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x0185B80B, + .name = "G730AUCUBNG3", + .img_base = 0x88E00000, + .img_end = 0x89000000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056AC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEA, + .mmc_boot_main = 0x88E06850, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13B2C, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FB4C, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88EBEB14, + .boot_name_ptr = 0x88E14198, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x3FB96300, + .name = "G730AUCUBNG4", + .img_base = 0x88E00000, + .img_end = 0x89000000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056AC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEA, + .mmc_boot_main = 0x88E06850, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13B2C, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FB4C, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88EBEB14, + .boot_name_ptr = 0x88E14198, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xB62DCDC6, + .name = "G730AUCSBNG5", + .img_base = 0x88E00000, + .img_end = 0x89000000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056AC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEA, + .mmc_boot_main = 0x88E06850, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13B2C, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FB4C, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88EBEB14, + .boot_name_ptr = 0x88E14198, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x246AE13B, + .name = "G730VVRUBNE2", + .img_base = 0x88E00000, + .img_end = 0x89000000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056AC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEA, + .mmc_boot_main = 0x88E06850, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13B2C, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FB4C, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88ECAB14, + .boot_name_ptr = 0x88E14198, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xD5DB08AD, + .name = "G730VVRSBQA1", + .img_base = 0x88E00000, + .img_end = 0x89000000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056AC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEA, + .mmc_boot_main = 0x88E06850, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13B2C, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FB4C, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88ECAB14, + .boot_name_ptr = 0x88E14198, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xB404F3D1, + .name = "I545VRUAMDK", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E05688, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E0684C, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13B28, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FE98, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F39310, + .boot_name_ptr = 0x88E140E8, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xD9B200AB, + .name = "I545VRUAME7", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056A0, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06864, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13F04, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FFF8, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F39B10, + .boot_name_ptr = 0x88E14554, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x623207FE, + .name = "I545VRUDMI1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056A0, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06864, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E1419C, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E1024C, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F45B10, + .boot_name_ptr = 0x88E14774, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x743C810E, + .name = "I545VRUEMJ7", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056B8, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E0687C, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E14274, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E102B8, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F51B10, + .boot_name_ptr = 0x88E1484C, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x95210636, + .name = "I545VRUEMK2", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056B8, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E0687C, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E14274, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E102B8, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F51B10, + .boot_name_ptr = 0x88E1484C, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xCBB5AEC4, + .name = "I545VRUFNC5", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056BC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06880, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144A4, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10400, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F5EB10, + .boot_name_ptr = 0x88E14AB0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x76912BE0, + .name = "I545VRUFNG6", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056DC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E068A0, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144C4, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10420, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F5EB10, + .boot_name_ptr = 0x88E14AD0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xE398ED56, + .name = "I545VRUFNK1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056DC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E068A0, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144C4, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10420, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F5EB10, + .boot_name_ptr = 0x88E14AD0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x7ECC3B24, + .name = "FAJP_I545VRUGOC1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E05700, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E068D0, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E145F8, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10420, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F3AB40, + .boot_name_ptr = 0x88E14BEC, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xDD1037CA, + .name = "I545VRUGOF1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E05750, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06914, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E14758, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E106E8, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F4AB10, + .boot_name_ptr = 0x88E14D9C, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x57B06CB6, + .name = "I545VRSGPL1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E05750, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06914, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E14758, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E106E8, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F4AB10, + .boot_name_ptr = 0x88E14D9C, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xA12617BB, + .name = "I337UCUAMDB", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E05688, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E0684C, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13CA8, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FF98, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F3DB10, + .boot_name_ptr = 0x88E14268, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xDEC28170, + .name = "I337UCUAMDL", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E05688, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E0684C, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E13CA8, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E0FF98, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F3DB10, + .boot_name_ptr = 0x88E14268, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xFE774F8C, + .name = "I337UCUEMK2", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056B8, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E0687C, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E14274, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E102B8, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F65B10, + .boot_name_ptr = 0x88E1484C, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xBA6A7450, + .name = "I337UCUFMLD", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056BC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06880, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E143C4, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10318, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F66B10, + .boot_name_ptr = 0x88E149D0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x7B2F0F39, + .name = "I337UCUFNB1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056BC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06880, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144A4, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10400, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F72B10, + .boot_name_ptr = 0x88E14AB0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xA3F0EB03, + .name = "I337UCUFNC1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056BC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06880, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144A4, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10400, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F72B10, + .boot_name_ptr = 0x88E14AB0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x547B5929, + .name = "FAJP_I337UCUFNG1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056A4, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06874, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E1425C, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10170, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F2EB40, + .boot_name_ptr = 0x88E148C0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xB9741BA3, + .name = "I337UCUFNI1", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056BC, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E06880, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144A4, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10400, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F72B10, + .boot_name_ptr = 0x88E14AB0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xC05C8EF7, + .name = "I337UCUFNJ4", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E056F4, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E068B8, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144D8, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10438, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F72B10, + .boot_name_ptr = 0x88E14AE4, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x96F5172D, + .name = "I337UCUGOC3", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E0570C, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E068D0, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144F0, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10450, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F72B10, + .boot_name_ptr = 0x88E14B08, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0x309AA9A2, + .name = "I337UCUGOK2", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E0570C, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E068D0, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144A8, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10450, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F72B10, + .boot_name_ptr = 0x88E14AC0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + }, + { + .code_crc = 0xAAD44BDE, + .name = "I337UCSGOK3", + .img_base = 0x88E00000, + .img_end = 0x89100000, + .max_boot_img_size = 10485760, + .max_stored_code = 0x60000, + .mmc_boot_fifo_read = 0x88E0570C, + .mmc_boot_fifo_read_instr = IT_THUMB, + .mmc_boot_fifo_read_len = 0xEC, + .mmc_boot_main = 0x88E068D0, + .mmc_boot_main_instr = IT_THUMB, + .boot_linux_from_mmc = 0x88E144A8, + .boot_linux_from_mmc_instr = IT_THUMB, + .check_sig = 0x88E10450, + .check_sig_instr = IT_THUMB, + .boot_from_recovery = 0x88F72B10, + .boot_name_ptr = 0x88E14AC0, + .kernel_load_ptr = 0x81000000, + .scratch_addr = 0x90000000, + .unified_addr = 0x88EFF000, + .mmc_sdc1_base = 0x12400000 + } +}; + +size_t num_configs = sizeof(configs) / sizeof(bootloader_config); diff --git a/oor/src/config.h b/oor/src/config.h new file mode 100644 index 0000000..c5a7c8b --- /dev/null +++ b/oor/src/config.h @@ -0,0 +1,117 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include +#include + +typedef enum { + IT_THUMB, + IT_ARM +} instr_type; + +typedef struct bootloader_config { + /* The output of running `oor -c` on the aboot image */ + uint32_t code_crc; + + /* The name of this bootloader version */ + char *name; + + /* The load address for the code + Can be found in the aboot image header */ + uint32_t img_base; + + /* The address just after the end of aboot's memory range + This is found in the range checks within boot_linux_from_mmc */ + uint32_t img_end; + + /* The size in bytes of the boot partition on this device */ + uint32_t max_boot_img_size; + + /* The size in bytes of the maximum amount of aboot code to store in + a patched image + It can be nice to shorten this to limit how much larger the patched + image is than the original. However, shortening it too much will + result in bugs as some code ends up corrupted + For a conservative, reliable approach, store the entirety of the code by + setting this very large, e.g. 0x10000000 */ + uint32_t max_stored_code; + + /* The address of the mmc_boot_fifo_read function + Look for where the following string is printed: + "Error No.%d: Failure on data transfer from the Card(RCA:%x)" + The function whose return value is checked just before this should + be it, having some loops and no function calls of its own */ + uint32_t mmc_boot_fifo_read; + + /* Whether the mmc_boot_fifo_read function uses ARM (all 4-byte) or Thumb + (mostly 2-byte, some 4-byte) instructions */ + instr_type mmc_boot_fifo_read_instr; + + /* The code size in bytes of the mmc_boot_fifo_read function + Found by taking the address just after the end of this function and + subtracting the beginning address */ + uint32_t mmc_boot_fifo_read_len; + + /* The address of the mmc_boot_main function + Look for where the following two strings are printed: + "MMC Boot: Error Initializing MMC Card!!!" + "MMC Boot: Failed detecting MMC/SDC @ slot%d" + The function where these are printed should be the correct function */ + uint32_t mmc_boot_main; + + /* Whether the mmc_boot_main function uses ARM or Thumb instructions */ + instr_type mmc_boot_main_instr; + + /* The address of the boot_linux_from_mmc function + This is where the following string is printed: + "ERROR: Not valid address of boot-header" */ + uint32_t boot_linux_from_mmc; + + /* Whether the boot_linux_from_mmc function uses ARM or Thumb instructions */ + instr_type boot_linux_from_mmc_instr; + + /* The address of the check_sig function + The boot_linux_from_mmc function prints the following string after + checking the return value of two different functions: + "kernel secure check fail." + The check_sig function is the first of these two (where returning 0 = success) */ + uint32_t check_sig; + + /* Whether the check_sig function uses ARM or Thumb instructions */ + instr_type check_sig_instr; + + /* The address of the boot_from_recovery variable + This is the variable checked by boot_linux_from_mmc before branching out to + get the offset of either the "boot" or "recovery" partition */ + uint32_t boot_from_recovery; + + /* The location of the address constant that points to the boot partition name + Not the address of the string itself, but the address of the word in + boot_linux_from_mmc that contains its address */ + uint32_t boot_name_ptr; + + /* A valid address for loading a kernel + This can be found in the header of an original boot image */ + uint32_t kernel_load_ptr; + + /* An out-of-the-way address to put things + After boot_linux_from_mmc finds a valid "ANDROID!" magic string (not for + unified boot, but the normal way), the next function that is called + should simply return a fixed value + That value is most likely the scratch address for the bootloader */ + uint32_t scratch_addr; + + /* The address where the boot_linux_from_mmc checks for a boot header + for unified boot mode (usually img_base + 0xFF000) */ + uint32_t unified_addr; + + /* This value is dependent on the phone's SoC + At several points in the bootloader, mmc_boot_main should be called with + 1 in r0 and this value in r1 */ + uint32_t mmc_sdc1_base; +} bootloader_config; + +extern bootloader_config configs[]; +extern size_t num_configs; + +#endif diff --git a/oor/src/crc.c b/oor/src/crc.c new file mode 100644 index 0000000..f631a3b --- /dev/null +++ b/oor/src/crc.c @@ -0,0 +1,18 @@ +#include "crc.h" + +#include +#include + +uint32_t crc32(char *bytes, size_t num_bytes) { + uint32_t crc; + + crc = 0xFFFFFFFF; + for(size_t i = 0; i < num_bytes; i++) { + crc = crc ^ (uint32_t)(uint8_t)bytes[i]; + for(int j = 7; j >= 0; j--) { + uint32_t mask = -(crc & 1); + crc = (crc >> 1) ^ (0xEDB88320 & mask); + } + } + return ~crc; +} diff --git a/oor/src/crc.h b/oor/src/crc.h new file mode 100644 index 0000000..2535713 --- /dev/null +++ b/oor/src/crc.h @@ -0,0 +1,9 @@ +#ifndef _CRC_H +#define _CRC_H + +#include +#include + +uint32_t crc32(char *bytes, size_t num_bytes); + +#endif diff --git a/oor/src/file_utils.c b/oor/src/file_utils.c new file mode 100644 index 0000000..eec9734 --- /dev/null +++ b/oor/src/file_utils.c @@ -0,0 +1,59 @@ +#include "file_utils.h" + +#include +#include +#include + +char *read_all_bytes(char *file_name, size_t *bytes_read) { + char *ret = NULL; + FILE *fp = NULL; + + if(bytes_read) { + *bytes_read = 0; + } + + fp = fopen(file_name, "rb"); + if(!fp) { + goto out; + } + + fseek(fp, 0L, SEEK_END); + size_t size = ftell(fp); + rewind(fp); + + ret = malloc(size); + if(!ret) { + goto out; + } + + size_t tmp_bytes_read = fread(ret, 1, size, fp); + if(bytes_read) { + *bytes_read = tmp_bytes_read; + } + +out: + if(fp) { + fclose(fp); + } + return ret; +} + +int write_all_bytes(char *file_name, char *bytes, size_t num_bytes) { + int ret = -1; + FILE *fp = NULL; + + fp = fopen(file_name, "wb"); + if(!fp) { + goto out; + } + + if(fwrite(bytes, 1, num_bytes, fp) == num_bytes) { + ret = 0; + } + +out: + if(fp) { + fclose(fp); + } + return ret; +} diff --git a/oor/src/file_utils.h b/oor/src/file_utils.h new file mode 100644 index 0000000..7af0bd2 --- /dev/null +++ b/oor/src/file_utils.h @@ -0,0 +1,9 @@ +#ifndef _FILE_UTILS_H +#define _FILE_UTILS_H + +#include + +char *read_all_bytes(char *file_name, size_t *bytes_read); +int write_all_bytes(char *file_name, char *bytes, size_t num_bytes); + +#endif diff --git a/oor/src/little_endian.c b/oor/src/little_endian.c new file mode 100644 index 0000000..f1c7f10 --- /dev/null +++ b/oor/src/little_endian.c @@ -0,0 +1,29 @@ +#include "little_endian.h" + +#include +#include + +uint32_t le_uint32_read(char *bytes, size_t offset) { + uint32_t ret = 0; + for(size_t i = offset; i < offset + 4; i++) { + ret >>= 8; + ret += (uint32_t)(uint8_t)bytes[i] << 24; + } + return ret; +} + +void le_uint16_write(uint16_t to_write, char *bytes, size_t offset) { + uint16_t remaining = to_write; + for(size_t i = offset; i < offset + 2; i++) { + bytes[i] = (char)(remaining & 0xFF); + remaining >>= 8; + } +} + +void le_uint32_write(uint32_t to_write, char *bytes, size_t offset) { + uint32_t remaining = to_write; + for(size_t i = offset; i < offset + 4; i++) { + bytes[i] = (char)(remaining & 0xFF); + remaining >>= 8; + } +} diff --git a/oor/src/little_endian.h b/oor/src/little_endian.h new file mode 100644 index 0000000..2da9282 --- /dev/null +++ b/oor/src/little_endian.h @@ -0,0 +1,11 @@ +#ifndef _LITTLE_ENDIAN_H +#define _LITTLE_ENDIAN_H + +#include +#include + +uint32_t le_uint32_read(char *bytes, size_t offset); +void le_uint16_write(uint16_t to_write, char *bytes, size_t offset); +void le_uint32_write(uint32_t to_write, char *bytes, size_t offset); + +#endif diff --git a/oor/src/main.c b/oor/src/main.c new file mode 100644 index 0000000..259a3c3 --- /dev/null +++ b/oor/src/main.c @@ -0,0 +1,95 @@ +#include "cmd_patch.h" +#include "cmd_redirect.h" +#include "cmd_undo.h" +#include "cmd_verify.h" +#include "cmd_crc.h" +#include "cmd_list.h" + +#include +#include +#include + +typedef struct { + char *cmd_switch; + char *description; + char *syntax; + int (*main_func)(int, char *[]); +} command; + +int main(int argc, char *argv[]); + +command commands[] = { + { + .cmd_switch = "-p", + .description = "Patch a boot/recovery image to be bootable using a given bootloader", + .syntax = " ", + .main_func = cmd_patch_main + }, + { + .cmd_switch = "-r", + .description = "Create an image telling the bootloader to boot from a different partition", + .syntax = " ", + .main_func = cmd_redirect_main + }, + { + .cmd_switch = "-u", + .description = "Get the original boot image from an already-patched file", + .syntax = " ", + .main_func = cmd_undo_main + }, + { + .cmd_switch = "-v", + .description = "Verify that the given image is patched for the given bootloader", + .syntax = " ", + .main_func = cmd_verify_main + }, + { + .cmd_switch = "-c", + .description = "Get the CRC32 checksum of the code in an aboot image", + .syntax = "", + .main_func = cmd_crc_main + }, + { + .cmd_switch = "-l", + .description = "List all supported bootloader versions", + .syntax = "", + .main_func = cmd_list_main + } +}; + +size_t num_commands = sizeof(commands) / sizeof(command); + +void print_help() { + printf("OutOfRange: Load unsigned boot images on some Android devices with locked bootloaders\n"); + + printf("\nCommands:\n"); + for(size_t i = 0; i < num_commands; i++) { + printf(" %s: %s\n", commands[i].cmd_switch, commands[i].description); + } + + printf("\nSyntax:\n"); + for(size_t i = 0; i < num_commands; i++) { + printf(" oor %s %s\n", commands[i].cmd_switch, commands[i].syntax); + } +} + +int main(int argc, char *argv[]) { + int ret = -2; + + if(argc < 2) { + print_help(); + goto out; + } + + for(size_t i = 0; i < num_commands; i++) { + if(!strcmp(commands[i].cmd_switch, argv[1])) { + ret = commands[i].main_func(argc, argv); + goto out; + } + } + + print_help(); + +out: + return ret; +} diff --git a/oor/src/patch_code.S b/oor/src/patch_code.S new file mode 100644 index 0000000..b0f0fc2 --- /dev/null +++ b/oor/src/patch_code.S @@ -0,0 +1,170 @@ +#include "udfs.h" + +.text + +start: + /* Fix the bytes we clobbered getting here */ + ldr r9, mmc_boot_fifo_read_ptr + adr r10, orig_bytes + ldr r7, mmc_boot_fifo_read_len + bl copy_bytes + + /* Restore the undefined opcode handler as well */ + ldr r9, undef_inst_handler_ptr + ldr r8, undef_inst_handler_orig + str r8, [r9] + + /* Finish the stalled MMC read in a scratch location */ + ldr r0, scratch_addr + mov r1, #0x04000000 /* 64 MB, way larger than any known aboot range */ + mov r2, #0 + ldr r9, mmc_boot_fifo_read + blx r9 + + /* Re-initialize the MMC controller */ + mov r0, #1 + ldr r1, mmc_sdc1_base + ldr r9, mmc_boot_main + blx r9 + + /* Check if we're loading from another partition or not */ + ldr r10, loaded_boot_img + ldrb r8, [r10, #3] + cmp r8, #2 + beq new_partition + + /* Fix the boot header magic */ + ldr r9, loaded_boot_img + adr r10, boot_magic + mov r7, #8 + bl copy_bytes + + /* Copy the boot image to an out-of-the-way address */ + ldr r9, scratch_addr + ldr r10, loaded_boot_img + ldr r7, boot_img_len + bl copy_bytes + + /* Copy the boot header to the unified location */ + ldr r9, unified_addr + mov r6, r9 + ldr r10, scratch_addr + mov r7, #0x800 + bl copy_bytes + + /* Copy the kernel to its proper location */ + ldr r9, [r6, #0xC] + ldr r7, [r6, #0x8] + bl page_boundary + bl copy_bytes + + /* Copy the ramdisk to its proper location */ + ldr r9, [r6, #0x14] + ldr r7, [r6, #0x10] + bl page_boundary + bl copy_bytes + + /* Copy the second image to its proper location */ + ldr r9, [r6, #0x1C] + ldr r7, [r6, #0x18] + bl page_boundary + bl copy_bytes + + /* Merge paths and finish booting */ + b finish_boot + +new_partition: + /* Don't boot to recovery (we're not patching that name) */ + ldr r9, boot_from_recovery + mov r8, #0 + str r8, [r9] + + /* Patch boot partition name */ + ldr r9, boot_name_ptr + ldr r8, loaded_boot_img + add r8, #8 + str r8, [r9] + + /* Patch check_sig to always succeed */ + ldr r9, check_sig_ptr + adr r10, check_sig_patch + ldr r7, check_sig_patch_len + bl copy_bytes + +finish_boot: + /* Call the bootloader */ + ldr r9, boot_linux_from_mmc + blx r9 + + /* If it returned, it failed. Hang here */ + b . + +/* r7 = # of bytes, r9 = dest, r10 = src */ +copy_bytes: + cmp r7, #0 + beq copy_bytes_done +copy_bytes_loop: + ldrb r8, [r10], #1 + strb r8, [r9], #1 + subs r7, #1 + bne copy_bytes_loop +copy_bytes_done: + bx lr + +/* This assumes the page size is 0x800 */ +/* r7 = byte offset */ +page_boundary: + cmp r7, #0 + beq page_boundary_done + sub r7, r7, #1 + mov r7, r7, LSR #11 + add r7, r7, #1 + mov r7, r7, LSL #11 +page_boundary_done: + bx lr + +/* These variables are known at assemble-time */ +boot_magic: + .ascii "ANDROID!" + +.align + +/* These variables will be filled out when the code is inserted into a boot image */ +mmc_boot_fifo_read_ptr: + .word UDF(UDF_MBFRP) +mmc_boot_fifo_read_len: + .word UDF(UDF_MBFRL) +undef_inst_handler_ptr: + .word UDF(UDF_UIHP) +undef_inst_handler_orig: + .word UDF(UDF_UIHO) +loaded_boot_img: + .word UDF(UDF_LBI) +boot_img_len: + .word UDF(UDF_BIL) +scratch_addr: + .word UDF(UDF_SA) +unified_addr: + .word UDF(UDF_UA) +mmc_boot_fifo_read: + .word UDF(UDF_MBFR) +mmc_boot_main: + .word UDF(UDF_MBM) +boot_linux_from_mmc: + .word UDF(UDF_BLFM) +mmc_sdc1_base: + .word UDF(UDF_MSB) +boot_from_recovery: + .word UDF(UDF_BFR) +boot_name_ptr: + .word UDF(UDF_BNP) +check_sig_ptr: + .word UDF(UDF_CSP) +check_sig_patch_len: + .word UDF(UDF_CSPL) +check_sig_patch: + .word UDF(UDF_CSP1), UDF(UDF_CSP2) + +/* This should be at the end, since the length varies */ +orig_bytes: + .word UDF(UDF_OB) diff --git a/oor/src/udfs.h b/oor/src/udfs.h new file mode 100644 index 0000000..b82566d --- /dev/null +++ b/oor/src/udfs.h @@ -0,0 +1,63 @@ +#ifndef _UDFS_H +#define _UDFS_H + +#define UDF(x) (0xE7F000F0 + ((x) & 0xF) + (((x) & 0xFFF0) << 4)) + +/* mmc_boot_fifo_read_ptr */ +#define UDF_MBFRP 0 + +/* mmc_boot_fifo_read_len */ +#define UDF_MBFRL 1 + +/* undef_inst_handler_ptr */ +#define UDF_UIHP 2 + +/* undef_inst_handler_orig */ +#define UDF_UIHO 3 + +/* loaded_boot_img */ +#define UDF_LBI 4 + +/* boot_img_len */ +#define UDF_BIL 5 + +/* scratch_addr */ +#define UDF_SA 6 + +/* unified_addr */ +#define UDF_UA 7 + +/* mmc_boot_fifo_read */ +#define UDF_MBFR 8 + +/* mmc_boot_main */ +#define UDF_MBM 9 + +/* boot_linux_from_mmc */ +#define UDF_BLFM 10 + +/* mmc_sdc1_base */ +#define UDF_MSB 11 + +/* boot_from_recovery */ +#define UDF_BFR 12 + +/* boot_name_ptr */ +#define UDF_BNP 13 + +/* check_sig_ptr */ +#define UDF_CSP 14 + +/* check_sig_patch_len */ +#define UDF_CSPL 15 + +/* check_sig_patch */ +#define UDF_CSP1 16 +#define UDF_CSP2 17 + +/* orig_bytes */ +#define UDF_OB 18 + +#define NUM_UDFS 19 + +#endif -- 2.20.1