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

Reply via email to