diff options
| author | Sam Mortimer <sam@mortimer.me.uk> | 2013-05-28 22:56:37 -0700 |
|---|---|---|
| committer | Sam Mortimer <sam@mortimer.me.uk> | 2013-05-29 13:47:04 -0700 |
| commit | 3e04ac5def0572a1e14af49e780e880bf21b3f97 (patch) | |
| tree | b511fbe90c9f238d8e98b5acc97132d51ebe6b43 | |
| parent | cb65020eaa2a9757d8f071213acd266f68eec098 (diff) | |
Build loki from source
Change-Id: I8622be22f9e7b58dba976f0bf3d71d349eca4c5a
| -rw-r--r-- | full_jflteatt.mk | 7 | ||||
| -rw-r--r-- | loki/Android.mk | 33 | ||||
| -rwxr-xr-x | loki/loki_patch | bin | 64327 -> 0 bytes | |||
| -rw-r--r-- | loki/loki_patch.c | 323 |
4 files changed, 359 insertions, 4 deletions
diff --git a/full_jflteatt.mk b/full_jflteatt.mk index f8b5041..1fc1da3 100644 --- a/full_jflteatt.mk +++ b/full_jflteatt.mk @@ -34,7 +34,6 @@ PRODUCT_BRAND := samsung PRODUCT_MANUFACTURER := samsung PRODUCT_MODEL := SGH-I337 -# loki -PRODUCT_COPY_FILES += \ - device/samsung/jflteatt/loki/loki.sh:system/bin/loki.sh \ - device/samsung/jflteatt/loki/loki_patch:system/bin/loki_patch +PRODUCT_PACKAGES += \ + loki_patch \ + loki.sh diff --git a/loki/Android.mk b/loki/Android.mk new file mode 100644 index 0000000..759cc2d --- /dev/null +++ b/loki/Android.mk @@ -0,0 +1,33 @@ +# +# Copyright (C) 2013 The CyanogenMod Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := loki_patch +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_PATH := $(TARGET_OUT)/bin +LOCAL_SRC_FILES := loki_patch.c +LOCAL_STATIC_LIBRARIES += libc +LOCAL_FORCE_STATIC_EXECUTABLE := true +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := loki.sh +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT)/bin +LOCAL_SRC_FILES := loki.sh +include $(BUILD_PREBUILT) diff --git a/loki/loki_patch b/loki/loki_patch Binary files differdeleted file mode 100755 index 6d54e9d..0000000 --- a/loki/loki_patch +++ /dev/null diff --git a/loki/loki_patch.c b/loki/loki_patch.c new file mode 100644 index 0000000..b694eed --- /dev/null +++ b/loki/loki_patch.c @@ -0,0 +1,323 @@ +/* + * loki_patch + * + * A utility to patch unsigned boot and recovery images to make + * them suitable for booting on the AT&T and Verizon Samsung + * Galaxy S4 + * + * by Dan Rosenberg (@djrbliss) + * + */ +#include <stdio.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#define VERSION "1.2" + +#define BOOT_MAGIC_SIZE 8 +#define BOOT_NAME_SIZE 16 +#define BOOT_ARGS_SIZE 512 + +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 */ + unsigned char build[128]; /* Build number */ +}; + +struct target { + char *vendor; + char *build; + unsigned long check_sigs; + unsigned long hdr; +}; + +struct target targets[] = { + { + .vendor = "AT&T", + .build = "JDQ39.I337UCUAMDB or JDQ39.I337UCUAMDL", + .check_sigs = 0x88e0ff98, + .hdr = 0x88f3bafc, + }, + { + .vendor = "Verizon", + .build = "JDQ39.I545VRUAMDK", + .check_sigs = 0x88e0fe98, + .hdr = 0x88f372fc, + }, + { + .vendor = "DoCoMo", + .build = "JDQ39.SC04EOMUAMDI", + .check_sigs = 0x88e0fcd8, + .hdr = 0x88f0b2fc, + }, +}; + +#define PATTERN "\xf0\xb5\x8f\xb0\x06\x46\xf0\xf7" +#define ABOOT_BASE 0x88dfffd8 + +unsigned char patch[] = +"\xfe\xb5" +"\x0b\x4d" +"\xa8\x6a" +"\xab\x68" +"\x98\x42" +"\x0e\xd0" +"\xee\x69" +"\x09\x4c" +"\xef\x6a" +"\x07\xf5\x80\x57" +"\x0f\xce" +"\x0f\xc4" +"\x10\x3f" +"\xfb\xdc" +"\xa8\x6a" +"\x04\x49" +"\xea\x6a" +"\xa8\x60" +"\x69\x61" +"\x2a\x61" +"\x00\x20" +"\xfe\xbd" +"\x00\x00" +"\xff\xff\xff\xff" /* Replace with header address */ +"\x00\x00\x20\x82"; + +int patch_shellcode(unsigned int addr) +{ + + int i; + unsigned int *ptr; + + for (i = 0; i < sizeof(patch); i++) { + ptr = (unsigned int *)&patch[i]; + if (*ptr == 0xffffffff) { + *ptr = addr; + return 0; + } + } + + return -1; +} + +int main(int argc, char **argv) +{ + + int ifd, ofd, aboot_fd, pos, i, recovery; + unsigned int orig_ramdisk_size, orig_kernel_size, page_kernel_size, page_ramdisk_size, page_size, page_mask; + unsigned long target; + void *orig, *aboot, *ptr; + struct target *tgt; + struct stat st; + struct boot_img_hdr *hdr; + struct loki_hdr *loki_hdr; + char *buf; + + if (argc != 5) { + printf("Usage: %s [boot|recovery] [aboot.img] [in.img] [out.lok]\n", argv[0]); + return 1; + } + + printf("[+] loki_patch v%s\n", VERSION); + + if (!strcmp(argv[1], "boot")) { + recovery = 0; + } else if (!strcmp(argv[1], "recovery")) { + recovery = 1; + } else { + printf("[+] First argument must be \"boot\" or \"recovery\".\n"); + return 1; + } + + /* Open input files */ + aboot_fd = open(argv[2], O_RDONLY); + if (aboot_fd < 0) { + printf("[-] Failed to open %s for reading.\n", argv[2]); + return 1; + } + + ifd = open(argv[3], O_RDONLY); + if (ifd < 0) { + printf("[-] Failed to open %s for reading.\n", argv[3]); + return 1; + } + + ofd = open(argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (ofd < 0) { + printf("[-] Failed to open %s for writing.\n", argv[4]); + 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; + + for (ptr = aboot; ptr < aboot + st.st_size - 0x1000; ptr++) { + if (!memcmp(ptr, PATTERN, 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 build %s\n", tgt->vendor, tgt->build); + + if (patch_shellcode(tgt->hdr) < 0) { + printf("[-] Failed to patch shellcode.\n"); + 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 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", argv[4]); + + 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; + + /* Store the original values in uses fields of the header */ + hdr->dt_size = orig_kernel_size; + hdr->unused = orig_ramdisk_size; + hdr->second_addr = hdr->kernel_addr + ((hdr->kernel_size + page_mask) & ~page_mask); + + /* Ramdisk must be aligned to a page boundary */ + hdr->kernel_size = ((hdr->kernel_size + page_mask) & ~page_mask) + hdr->ramdisk_size; + hdr->ramdisk_addr = tgt->check_sigs - 8; + 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 0x800 bytes of original code to the output */ + buf = malloc(0x200); + if (!buf) { + printf("[-] Out of memory.\n"); + return 1; + } + + lseek(aboot_fd, tgt->check_sigs - ABOOT_BASE - 8, SEEK_SET); + read(aboot_fd, buf, 0x200); + + if (write(ofd, buf, 0x200) != 0x200) { + printf("[-] Failed to write original aboot code to output file.\n"); + return 1; + } + + pos = lseek(ofd, 0, SEEK_CUR); + lseek(ofd, pos - 0x1f8, 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", argv[4]); + + return 0; +} |
