Hi, On Sun, Jul 28, 2013 at 12:23:35PM +0200, Felix Kaechele wrote: > This commit adds the basic elements to support Poray brand routers. > It contains a tool to do the encryption/obfuscation that is used in > Poray routers. > > Signed-off-by: Felix Kaechele <[email protected]> > Signed-off-by: Luis Soltero <[email protected]> > Signed-off-by: Michel Stempin <[email protected]> > --- > target/linux/ramips/image/Makefile | 36 ++ > target/linux/ramips/rt305x/profiles/poray.mk | 7 + > tools/firmware-utils/Makefile | 1 + > tools/firmware-utils/src/mkporayfw.c | 764 > +++++++++++++++++++++++++++ > 4 files changed, 808 insertions(+) > create mode 100644 target/linux/ramips/rt305x/profiles/poray.mk > create mode 100644 tools/firmware-utils/src/mkporayfw.c
... > diff --git a/tools/firmware-utils/src/mkporayfw.c > b/tools/firmware-utils/src/mkporayfw.c > new file mode 100644 > index 0000000..5af6871 > --- /dev/null > +++ b/tools/firmware-utils/src/mkporayfw.c > @@ -0,0 +1,764 @@ > +/* > + * Builder/viewer/extractor utility for Poray firmware image files > + * > + * Copyright (C) 2013 Michel Stempin <[email protected]> > + * Copyright (C) 2013 Felix Kaechele <[email protected]> > + * Copyright (C) 2103 <[email protected]> Should be 2013. > + * > + * This tool is based on: > + * TP-Link firmware upgrade tool. > + * Copyright (C) 2009 Gabor Juhos <[email protected]> > + * > + * Itself based on: > + * TP-Link WR941 V2 firmware checksum fixing tool. > + * Copyright (C) 2008,2009 Wang Jian <[email protected]> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > + * by the Free Software Foundation. > + * > + */ ... > + > +/* > + * Display usage > + */ > +static void usage(int status) > +{ > + FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; > + > + fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); > + fprintf(stream, > +"\n" > +"Options:\n" > +" -B <board> create image for the board specified with <board>\n" > +" -H <hwid> use hardware id specified with <hwid>\n" > +" -F <id> use flash layout specified with <id>\n" > +" -f <file> read firmware image from the file <file>\n" > +" -o <file> write output to the file <file>\n" > +" -i <file> inspect given firmware file <file>\n" A '-f <file>' to specify firmware should be more concise. '-i' does not need a '<file>' optarg. Otherwise people may get confused when trying to do '-f firmware.bin -x' and get an error message in check_options. > +" -x extract combined kernel and rootfs while inspecting > (requires -i)\n" > +" -h show this screen\n" > + ); > + > + exit(status); > +} > + > +/* > + * Get file statistics > + */ > +static int get_file_stat(struct file_info *fdata) > +{ > + struct stat st; > + int res; > + > + if (fdata->file_name == NULL) { > + return 0; > + } > + res = stat(fdata->file_name, &st); > + if (res){ > + ERRS("stat failed on %s", fdata->file_name); > + return res; > + } > + > + fdata->file_size = st.st_size; > + return 0; > +} > + > +/* > + * Read file into buffer > + */ > +static int read_to_buf(struct file_info *fdata, uint8_t *buf) > +{ > + FILE *f; > + int ret = EXIT_FAILURE; > + > + f = fopen(fdata->file_name, "r"); File open mode should be "rb" for good practice. Actually there are other tools that need to be patched. > + if (f == NULL) { > + ERRS("could not open \"%s\" for reading", fdata->file_name); > + goto out; > + } > + > + errno = 0; > + fread(buf, fdata->file_size, 1, f); > + if (errno != 0) { > + ERRS("unable to read from file \"%s\"", fdata->file_name); > + goto out_close; > + } > + > + ret = EXIT_SUCCESS; > + > + out_close: > + fclose(f); > + out: > + return ret; > +} > + > +/* > + * Check command line options > + */ > +static int check_options(void) > +{ > + int ret; > + > + if (inspect_info.file_name) { > + ret = get_file_stat(&inspect_info); > + if (ret) { > + return ret; > + } > + return 0; > + } else if (extract) { > + ERR("no firmware for inspection specified"); > + return -1; > + } > + > + if (board_id == NULL && opt_hw_id == NULL) { > + ERR("either board or hardware id must be specified"); > + return -1; > + } > + > + if (board_id) { > + board = find_board(board_id); > + if (board == NULL) { > + ERR("unknown/unsupported board id \"%s\"", board_id); > + return -1; > + } > + if (layout_id == NULL) { > + layout_id = board->layout_id; > + } > + hw_id = board->hw_id; > + } else { > + if (layout_id == NULL) { > + ERR("flash layout is not specified"); > + return -1; > + } > + hw_id = strtoul(opt_hw_id, NULL, 0); Layout and board can be inferred from find_board_by_hwid(hw_id). I am not sure why mktplinkfw was implemented this way. > + } > + > + layout = find_layout(layout_id); > + if (layout == NULL) { > + ERR("unknown flash layout \"%s\"", layout_id); > + return -1; > + } > + > + if (firmware_info.file_name == NULL) { > + ERR("no firmware image specified"); > + return -1; > + } > + > + ret = get_file_stat(&firmware_info); > + if (ret) { > + return ret; > + } > + firmware_len = firmware_info.file_size; > + > + if (firmware_info.file_size > > + layout->fw_max_len - sizeof (struct fw_header)) { > + ERR("firmware image is too big"); > + return -1; > + } > + > + if (ofname == NULL) { > + ERR("no output file specified"); > + return -1; > + } > + return 0; > +} > + ... > +static int write_fw(uint8_t *data, int len) > +{ > + FILE *f; > + int ret = EXIT_FAILURE; > + > + f = fopen(ofname, "w"); "wb" is preferred. > + if (f == NULL) { > + ERRS("could not open \"%s\" for writing", ofname); > + goto out; > + } > + > + errno = 0; > + fwrite(data, len, 1, f); > + if (errno) { > + ERRS("unable to write output file"); > + goto out_flush; > + } > + > + DBG("firmware file \"%s\" completed", ofname); > + > + ret = EXIT_SUCCESS; > + > + out_flush: > + fflush(f); > + fclose(f); > + if (ret != EXIT_SUCCESS) { > + unlink(ofname); > + } > + out: > + return ret; > +} > + ... > + > +static int inspect_fw(void) > +{ > + uint8_t *buf; > + struct fw_header *hdr; > + int ret = EXIT_FAILURE; > + uint16_t computed_checksum, file_checksum; > + > + buf = (uint8_t *) malloc(inspect_info.file_size); > + if (!buf) { > + ERR("no memory for buffer!\n"); > + goto out; > + } > + > + ret = read_to_buf(&inspect_info, buf); > + if (ret) { > + goto out_free_buf; > + } > + hdr = (struct fw_header *)buf; > + > + inspect_fw_pstr("File name", inspect_info.file_name); > + inspect_fw_phexdec("File size", inspect_info.file_size); > + > + printf("\n"); > + > + inspect_fw_phexdec("Header size", sizeof (struct fw_header)); > + board = find_board_by_hwid(LE32_TO_HOST(hdr->hw_id)); > + if (board) { > + layout = find_layout(board->layout_id); > + inspect_fw_phexpost("Hardware ID", > + LE32_TO_HOST( hdr->hw_id), board->id); > + } else { > + inspect_fw_phexpost("Hardware ID", > + LE32_TO_HOST(hdr->hw_id), "unknown"); > + } > + inspect_fw_phexdec("Firmware data length", > + LE32_TO_HOST(hdr->firmware_len)); > + > + inspect_fw_phexexp("Flags", > + LE32_TO_HOST(hdr->flags), HEADER_FLAGS); > + printf("\n"); > + > + /* XOR unobfuscate firmware */ > + xor_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len) > + 2); > + > + /* Compute firmware checksum */ > + computed_checksum = checksum_fw(buf + sizeof (struct fw_header), > LE32_TO_HOST(hdr->firmware_len)); > + > + /* Cannot use network order function because checksum is not > word-aligned */ > + file_checksum = (buf[inspect_info.file_size - 1] << 8) | > buf[inspect_info.file_size - 2]; > + inspect_fw_pchecksum("Firmware checksum", computed_checksum, > file_checksum); > + > + /* Verify checksum */ > + if (computed_checksum != file_checksum) { > + ret = -1; > + ERR("checksums do not match"); > + goto out_free_buf; > + } > + > + printf("\n"); > + > + if (extract) { > + FILE *fp; > + char *filename; > + > + if (ofname == NULL) { > + filename = malloc(strlen(inspect_info.file_name) + 10); > + sprintf(filename, "%s-firmware", > inspect_info.file_name); > + } else { > + filename = ofname; > + } > + printf("Extracting firmware to \"%s\"...\n", filename); > + fp = fopen(filename, "w"); "wb" for open mode. > + if (fp) { > + if (!fwrite(buf + sizeof (struct fw_header), > + LE32_TO_HOST(hdr->firmware_len), 1, fp)) { > + ERR("error in fwrite(): %s", strerror(errno)); I guess this is what ERRS was defined for. ;) > + } > + fclose(fp); > + } else { > + ERR("error in fopen(): %s", strerror(errno)); > + } > + if (ofname == NULL) { > + free(filename); > + } > + printf("\n"); > + } > + > + out_free_buf: > + free(buf); > + out: > + return ret; > +} > + > +/* > + * Main entry point > + */ > +int main(int argc, char *argv[]) > +{ > + int ret = EXIT_FAILURE; > + > + progname = basename(argv[0]); > + > + while (1) { > + int c; > + > + c = getopt(argc, argv, "B:H:F:f:i:o:xh"); > + if (c == -1) { > + break; > + } > + switch (c) { > + case 'B': > + board_id = optarg; > + break; > + case 'H': > + opt_hw_id = optarg; > + break; > + case 'F': > + layout_id = optarg; > + break; > + case 'f': > + firmware_info.file_name = optarg; > + break; > + case 'o': > + ofname = optarg; > + break; > + case 'i': > + inspect_info.file_name = optarg; > + break; > + case 'x': > + extract = 1; > + break; > + case 'h': > + usage(EXIT_SUCCESS); > + break; > + default: > + usage(EXIT_FAILURE); > + break; > + } > + } > + > + ret = check_options(); > + if (ret) { > + goto out; > + } > + if (!inspect_info.file_name) { > + ret = build_fw(); > + } else { > + ret = inspect_fw(); > + } > + > + out: > + return ret; > +} > -- > 1.8.3.1 > _______________________________________________ > openwrt-devel mailing list > [email protected] > https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel _______________________________________________ openwrt-devel mailing list [email protected] https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
