From 414aa000373997192d39b706d2deb83e3b1f40f0 Mon Sep 17 00:00:00 2001 From: Alexander Couzens Date: Fri, 2 Mar 2018 00:44:31 +0100 Subject: [PATCH] tplink-safeloader: add support to convert factory into sysupgrade Those converted factory images can be used to regain the original tp-link firmware. Be aware of firmware upgrade which additional require changes of other partition than os-image (kernel) & file-system (rootfs). OEM factory images from tplink can change nearly all partitions. However using those images, OpenWrt's sysupgrade will only modify the partitions os-image and file-system. Signed-off-by: Alexander Couzens --- src/tplink-safeloader.c | 106 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/src/tplink-safeloader.c b/src/tplink-safeloader.c index 0a11287..fab6f05 100644 --- a/src/tplink-safeloader.c +++ b/src/tplink-safeloader.c @@ -1392,7 +1392,8 @@ static void usage(const char *argv0) { " -S create sysupgrade instead of factory image\n" "Extract an old image:\n" " -x extract all oem firmware partition\n" - " -d destination to extract the firmware partition\n", + " -d destination to extract the firmware partition\n" + " -z convert an oem firmware into a sysupgade file. Use -o for output file\n", argv0 ); }; @@ -1632,9 +1633,100 @@ static int extract_firmware(const char *input, const char *output_directory) return 0; } +static struct flash_partition_entry *find_partition( + struct flash_partition_entry *entries, size_t max_entries, + const char *name, const char *error_msg) +{ + for (int i=0; iname, name) == 0) + return entries; + } + + error(1, 0, "%s", error_msg); + return NULL; +} + +static void write_ff(FILE *output_file, size_t size) +{ + char buf[4096]; + int offset; + + memset(buf, 0xff, sizeof(buf)); + + for (offset = 0; offset + sizeof(buf) < size ; offset += sizeof(buf)) { + if (fwrite(buf, sizeof(buf), 1, output_file) < 0) + error(1, errno, "Can not write 0xff to output_file"); + } + + /* write last chunk smaller than buffer */ + if (offset < size) { + offset = size - offset; + if (fwrite(buf, offset, 1, output_file) < 0) + error(1, errno, "Can not write partition to output_file"); + } +} + +static void convert_firmware(const char *input, const char *output) +{ + struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 }; + struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 }; + struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL; + struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL; + struct flash_partition_entry *fwup_partition_table = NULL; + size_t firmware_offset = 0x1014; + FILE *input_file, *output_file; + + struct stat statbuf; + + /* check input file */ + if (stat(input, &statbuf)) { + error(1, errno, "Can not read input firmware %s", input); + } + + input_file = fopen(input, "rb"); + if (!input_file) + error(1, 0, "Can not open input firmware %s", input); + + output_file = fopen(output, "wb"); + if (!output_file) + error(1, 0, "Can not open output firmware %s", output); + + if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) { + error(1, 0, "Error can not read the partition table (fwup-ptn)"); + } + + fwup_os_image = find_partition(fwup, MAX_PARTITIONS, + "os-image", "Error can not find os-image partition (fwup)"); + fwup_file_system = find_partition(fwup, MAX_PARTITIONS, + "file-system", "Error can not find file-system partition (fwup)"); + fwup_partition_table = find_partition(fwup, MAX_PARTITIONS, + "partition-table", "Error can not find partition-table partition"); + + /* the flash partition table has a 0x00000004 magic haeder */ + if (read_partition_table(input_file, firmware_offset + fwup_partition_table->base + 4, flash, MAX_PARTITIONS, 1) != 0) + error(1, 0, "Error can not read the partition table (flash)"); + + flash_os_image = find_partition(flash, MAX_PARTITIONS, + "os-image", "Error can not find os-image partition (flash)"); + flash_file_system = find_partition(flash, MAX_PARTITIONS, + "file-system", "Error can not find file-system partition (flash)"); + + /* write os_image to 0x0 */ + write_partition(input_file, firmware_offset, fwup_os_image, output_file); + write_ff(output_file, flash_os_image->size - fwup_os_image->size); + + /* write file-system behind os_image */ + fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET); + write_partition(input_file, firmware_offset, fwup_file_system, output_file); + write_ff(output_file, flash_file_system->size - fwup_file_system->size); + + fclose(output_file); + fclose(input_file); +} + int main(int argc, char *argv[]) { const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL; - const char *extract_image = NULL, *output_directory = NULL; + const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL; bool add_jffs2_eof = false, sysupgrade = false; unsigned rev = 0; const struct device_info *info; @@ -1643,7 +1735,7 @@ int main(int argc, char *argv[]) { while (true) { int c; - c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:"); + c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:z:"); if (c == -1) break; @@ -1688,6 +1780,10 @@ int main(int argc, char *argv[]) { extract_image = optarg; break; + case 'z': + convert_image = optarg; + break; + default: usage(argv[0]); return 1; @@ -1700,6 +1796,10 @@ int main(int argc, char *argv[]) { if (!output_directory) error(1, 0, "Can not extract an image without output directory. Use -d "); extract_firmware(extract_image, output_directory); + } else if (convert_image) { + if (!output) + error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o "); + convert_firmware(convert_image, output); } else { if (!board) error(1, 0, "no board has been specified"); -- 2.30.2