From 87e593ddf6d5703f9c32677b599d90fd68fdda00 Mon Sep 17 00:00:00 2001 From: Sander Vanheule Date: Fri, 3 Feb 2023 23:03:23 +0100 Subject: [PATCH] tplink-safeloader: add QNEW image detection MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit An incompatible image type is now used, e.g. for the TL-WPA8631P v4, which has a header containing 0x3C extra bytes. This image type can be identified by the first four bytes of the image header being "?NEW". Only detection is implemented at this moment, as the full header format is not yet understood, and the preamble checksum can no longer be verified using the current md5sum salt. Devices still appear to accept images in the "old" format, so image generation is not required at this moment. Cc: Andreas Böhler Signed-off-by: Sander Vanheule --- src/tplink-safeloader.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/tplink-safeloader.c b/src/tplink-safeloader.c index 6937457..71dfe79 100644 --- a/src/tplink-safeloader.c +++ b/src/tplink-safeloader.c @@ -142,10 +142,18 @@ struct __attribute__((__packed__)) soft_version { * Header contains up to 0x1000 bytes of vendor data, starting with a big endian * UINT32 size, followed by that number of bytes containing (text) data. * Padded with 0xFF. Payload starts at offset 0x1014. + * + * SAFELOADER_TYPE_QNEW + * Reversed order preamble, with (apparent) md5 checksum before the image + * size. The size does not include the preamble length. + * Header starts with 0x3C bytes, starting with the string '?NEW' (format not + * understood). Then another 0x1000 bytes follow, with the data payload + * starting at 0x1050. */ enum safeloader_image_type { SAFELOADER_TYPE_DEFAULT, SAFELOADER_TYPE_VENDOR, + SAFELOADER_TYPE_QNEW, }; /* Internal representation of safeloader image data */ @@ -159,6 +167,10 @@ struct safeloader_image_info { #define SAFELOADER_HEADER_SIZE 0x1000 #define SAFELOADER_PAYLOAD_OFFSET (SAFELOADER_PREAMBLE_SIZE + SAFELOADER_HEADER_SIZE) +#define SAFELOADER_QNEW_HEADER_SIZE 0x3C +#define SAFELOADER_QNEW_PAYLOAD_OFFSET \ + (SAFELOADER_PREAMBLE_SIZE + SAFELOADER_QNEW_HEADER_SIZE + SAFELOADER_HEADER_SIZE) + #define SAFELOADER_PAYLOAD_TABLE_SIZE 0x800 static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde}; @@ -3846,6 +3858,8 @@ static void safeloader_read_partition(FILE *input_file, size_t payload_offset, static void safeloader_parse_image(FILE *input_file, struct safeloader_image_info *image) { + static const char *HEADER_ID_QNEW = "?NEW"; + char buf[64]; if (!input_file) @@ -3856,12 +3870,22 @@ static void safeloader_parse_image(FILE *input_file, struct safeloader_image_inf if (fread(buf, sizeof(buf), 1, input_file) != 1) error(1, errno, "Can not read image header"); - if (ntohl(*((uint32_t *) &buf[0])) <= SAFELOADER_HEADER_SIZE) + if (memcmp(HEADER_ID_QNEW, &buf[0], strlen(HEADER_ID_QNEW)) == 0) + image->type = SAFELOADER_TYPE_QNEW; + else if (ntohl(*((uint32_t *) &buf[0])) <= SAFELOADER_HEADER_SIZE) image->type = SAFELOADER_TYPE_VENDOR; else image->type = SAFELOADER_TYPE_DEFAULT; - image->payload_offset = SAFELOADER_PAYLOAD_OFFSET; + switch (image->type) { + case SAFELOADER_TYPE_DEFAULT: + case SAFELOADER_TYPE_VENDOR: + image->payload_offset = SAFELOADER_PAYLOAD_OFFSET; + break; + case SAFELOADER_TYPE_QNEW: + image->payload_offset = SAFELOADER_QNEW_PAYLOAD_OFFSET; + break; + } /* Parse image partition table */ read_partition_table(input_file, image->payload_offset, &image->entries[0], -- 2.30.2