Version 1.05
[firmware_header_dump.git] / firmware_header_dump.c
1 static const char *title =\
2 "Broadcom Consumer Router Firmware Header Dump"
3 ;
4 static const float VERSION = 1.05f;
5
6 static const char *copyright = \
7 "Copyright 2015-2016 TJ <hacker@iam.tj>\n"
8 "Licensed on the terms of the GNU General Public License version 3\n"
9 ;
10
11 static const char *help = \
12 "For routers using the Broadcom CFE ((Customer Premises Equipment) CPE Firmware Environment) and firmware update files.\n\n"
13
14 "Displays the fields of the firmware update file header structure.\n\n"
15 ;
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdarg.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <arpa/inet.h>
26 #include <stdint.h>
27 #include <stddef.h>
28
29 #define BCMTAG_EXE_USE 1
30
31 #include "heap_reap.h"
32 #include "bcmTag.h"
33
34 static unsigned int MESSAGE_SIZE = 1024;
35
36 static char *image_type[] = {"IMGDEF", "ROMD", "HPNA"};
37
38 static void
39 pr_usage(int verbose)
40 {
41   fprintf(stderr,
42     "Usage:\n"
43     "  -h  show additional help\n"
44     "\n"
45     "%s",
46     verbose ? help : ""
47   );
48 }
49
50 static void
51 pr_error_exit(unsigned int usage, const char *error, ...)
52 {
53  va_list args;
54  char error_message[MESSAGE_SIZE + 1];
55
56  if (!error) return;
57
58  va_start(args, error);
59  (void) vsnprintf(error_message, MESSAGE_SIZE + 1, error, args);
60  va_end(args);
61  fprintf(stderr, "Error: %s\n", error_message);
62
63  if (usage) pr_usage(usage);
64
65  heap_and_reap(NULL-1, 0, 0);
66  exit(EXIT_FAILURE);
67 }
68
69 /* calculate standard CRC32
70  *
71  * @param data pointer to start of input data
72  * @param len  length in bytes of data to be checksummed
73  * @param crc32 seed value (Broadcom use 0xffffffff)
74  */
75 unsigned int crc32(const unsigned char *data, ssize_t len, unsigned int crc)
76 {
77    for ( ; len > 0; --len ) {
78      crc = (crc >> 8) ^ Crc32_table[ (crc ^ *data++) & 0xff ];
79    }
80    return crc;
81 }
82
83
84 int
85 main(int argc, char **argv)
86 {
87   unsigned int arg, crc_header, crc_payload;
88   char *filename = NULL;
89   int fd, fd_mode;
90   unsigned char *buffer = NULL;
91   unsigned long header_len = sizeof(FILE_TAG);
92   char *format_spec_user = "%-12s Manufacturer: %s Model: %s CRC32: %08x Length: %ld File: %s\n";
93   char *format_spec_test = "%-12s %s %s %08x %ld\n";
94   char *format_spec = format_spec_user; // default output format
95
96   unsigned int opt_quiet;
97   
98   opt_quiet = 0;
99
100   fprintf(stderr, "%s\nVersion: %0.2f\n%s\n", title, VERSION, copyright);
101
102   for (arg = 1; arg < (unsigned) argc; ++arg) {
103     char *p = argv[arg];
104     size_t arg_len = strlen(p);
105
106     if (p[0] == '-') {
107       if(p[1] != 0) {
108         switch (p[1]) {
109           case 'h': // help
110             pr_usage(1);
111             goto end;
112         }
113       } else {
114         pr_error_exit(0, "cannot read data from stdin; provide a filename");
115       }
116       continue;
117     }
118     else if (!filename) { // remaining non-option must be the filename
119       filename = p;
120     } else {
121       if (!opt_quiet)
122         fprintf(stderr, "Can only process one file; ignoring '%s'\n", p);
123     }
124   }
125
126
127   fd_mode = O_RDONLY;
128
129   if (filename) {
130    if ((fd = open(filename, fd_mode)) > 0) {
131
132      unsigned int offset = 0;
133      unsigned int count = 0;
134      unsigned int next = 1;
135      void *payload = NULL;
136
137      while (next) {
138        unsigned long len = 0;
139        crc_header = crc_payload = 0xffffffff;
140
141        if (count) // switch struct type after initial file header
142          header_len = sizeof(IMAGE_TAG);
143
144        lseek(fd, offset, SEEK_SET);
145        printf("Header Offset: 0x%08x (%u)\n", offset, offset);
146
147        if ( (buffer = heap_and_reap(NULL, header_len, 1)) != NULL) {
148          ssize_t qty;
149          if ( (qty = read(fd, buffer, header_len)) < header_len) {
150            if (!opt_quiet)
151              fprintf(stderr, "warning: only able to read %ld of %ld bytes\n", qty, header_len);
152            header_len = qty;
153          }
154
155          PFILE_TAG pfile = (PFILE_TAG) buffer;
156          PIMAGE_TAG pimage = (PIMAGE_TAG) buffer;
157
158          if (!count) {
159            next = *(unsigned char *)(pfile->imageNext);
160            len = atol(pfile->totalImageLen);
161            offset = 0x20000;
162          } else {
163            next = *(unsigned char *)(pimage->imageNext);
164            len = atol(pimage->imageLen);
165            offset += sizeof(IMAGE_TAG);
166          }
167
168          crc_header = crc32(buffer, header_len - (count ? CRC_LEN : TOKEN_LEN), crc_header);
169
170          // read payload and calculate CRC32
171          lseek(fd, offset, SEEK_SET);
172          if ( (payload = heap_and_reap(NULL, len, 1)) != NULL) {
173            if ( (qty = read(fd, payload, len)) < len) {
174              fprintf(stderr, "skipping CRC calculation: only able to read %ld of %ld bytes\n", qty, len);
175            } else {
176              crc_payload = crc32(payload, len, crc_payload);
177
178              heap_and_reap(payload, 0, 0);
179            }
180          } else {
181            close(fd);
182            pr_error_exit(0, "unable to allocate memory (%ld bytes)\n", len);
183          }
184
185          if (!count) {
186            printf("Image Offset:  0x%08x (%u)\n", offset, offset);
187            printf("%04lx Tag Version: %s\n"
188                   "%04lx Signature 1: %s (Model: %s)\n"
189                   "%04lx Signature 2: %s\n"
190                   "%04lx Chip ID: %s\n"
191                   "%04lx Board ID: %s\n"
192                   "%04lx Big Endian: %s\n"
193                   "%04lx Image Len: %s (0x%08lx)\n"
194                   "%04lx CFE Address: %s (0x%08lx)\n"
195                   "%04lx CFE Len: %s (0x%08lx)\n"
196                   "%04lx Root FS Address: %s (0x%08lx)\n"
197                   "%04lx Root FS Len: %s (0x%08lx)\n"
198                   "%04lx Kernel Address: %s (0x%08lx)\n"
199                   "%04lx Kernel Len: %s (0x%08lx)\n"
200                   "%04lx Image Sequence: %s (0x%08x)\n"
201                   "%04lx External Version: %s\n"
202                   "%04lx Internal Version: %s\n"
203                   "%04lx Image Next: %u\n"
204                   "%04lx Image Validation Token: 0x%08x\n"
205                   "%04lx Tag Validation Token:   0x%08x\n"
206                   "     Calculated Image CRC32: 0x%08x\n"
207                   "     Calculated Tag   CRC32: 0x%08x\n"
208                   "\n",
209                   offsetof(struct _FILE_TAG, tagVersion), pfile->tagVersion,
210                   offsetof(struct _FILE_TAG, signiture_1), pfile->signiture_1, pfile->signiture_1 + strlen(pfile->signiture_1) + 1,
211                   offsetof(struct _FILE_TAG, signiture_2), pfile->signiture_2,
212                   offsetof(struct _FILE_TAG, chipId), pfile->chipId,
213                   offsetof(struct _FILE_TAG, boardId), pfile->boardId,
214                   offsetof(struct _FILE_TAG, bigEndian), *pfile->bigEndian == '1' ? "Yes" : "No",
215                   offsetof(struct _FILE_TAG, totalImageLen), pfile->totalImageLen, len,
216                   offsetof(struct _FILE_TAG, cfeAddress), pfile->cfeAddress, atol(pfile->cfeAddress),
217                   offsetof(struct _FILE_TAG, cfeLen), pfile->cfeLen, atol(pfile->cfeLen),
218                   offsetof(struct _FILE_TAG, rootfsAddress), pfile->rootfsAddress, atol(pfile->rootfsAddress),
219                   offsetof(struct _FILE_TAG, rootfsLen), pfile->rootfsLen, atol(pfile->rootfsLen),
220                   offsetof(struct _FILE_TAG, kernelAddress), pfile->kernelAddress, atol(pfile->kernelAddress),
221                   offsetof(struct _FILE_TAG, kernelLen), pfile->kernelLen, atol(pfile->kernelLen),
222                   offsetof(struct _FILE_TAG, imageSequence), pfile->imageSequence, atoi(pfile->imageSequence),
223                   offsetof(struct _FILE_TAG, externalversion), pfile->externalversion,
224                   offsetof(struct _FILE_TAG, internalversion), pfile->internalversion,
225                   offsetof(struct _FILE_TAG, imageNext), next,
226                   offsetof(struct _FILE_TAG, imageValidationToken), ntohl( *((unsigned int *)(pfile->imageValidationToken)) ),
227                   offsetof(struct _FILE_TAG, tagValidationToken), ntohl( *((unsigned int *)(pfile->tagValidationToken)) ),
228                   crc_payload,
229                   crc_header
230            );
231
232          } else {
233            printf("Image Offset:  0x%08x (%u)\n", offset, offset);
234            printf("%04lx Image Next: %u\n"
235                   "%04lx Image Type: %s (%lu)\n"
236                   "%04lx Image Signature: %u\n"
237                   "%04lx Image Len: %s (0x%08lx)\n"
238                   "%04lx Image Validation Token: 0x%08x\n"
239                   "%04lx Tag Validation Token:   0x%08x\n"
240                   "     Calculated Image CRC32: 0x%08x\n"
241                   "     Calculated Tag CRC32:   0x%08x\n"
242                   "\n",
243                   offsetof(struct _IMAGE_TAG, imageNext), next,
244                   offsetof(struct _IMAGE_TAG, imageType), image_type[atol(pimage->imageType)], atol(pimage->imageType),
245                   offsetof(struct _IMAGE_TAG, imageSignature), (unsigned int)*pimage->imageSignature,
246                   offsetof(struct _IMAGE_TAG, imageLen), pimage->imageLen, len,
247                   offsetof(struct _IMAGE_TAG, imageValidationToken), ntohl( *((unsigned int *)(pimage->imageValidationToken)) ),
248                   offsetof(struct _IMAGE_TAG, tagValidationToken), ntohl( *((unsigned int *)(pimage->tagValidationToken)) ),
249                   crc_payload,
250                   crc_header
251            );
252          }
253
254
255          // next seek point will be end of current payload
256          offset += len;
257
258          heap_and_reap(buffer, 0, 0);
259
260          ++count;
261
262        } else {
263          close(fd);
264          pr_error_exit(0, "unable to allocate memory (%ld bytes)\n", header_len);
265        }
266
267      }
268      heap_and_reap(buffer, 0, 0);
269      close(fd);
270     } else {
271       fprintf(stderr, "Unable to open for %s (%s)\n", "reading" , filename );
272     }
273   } else {
274     pr_usage(0);
275   }
276
277 end:
278   heap_and_reap(NULL-1, 0, 0);
279   return 0;
280 }
281