1 static const char *title =\
2 "Broadcom Consumer Router Firmware Header Dump"
4 static const float VERSION = 1.05f;
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"
11 static const char *help = \
12 "For routers using the Broadcom CFE ((Customer Premises Equipment) CPE Firmware Environment) and firmware update files.\n\n"
14 "Displays the fields of the firmware update file header structure.\n\n"
21 #include <sys/types.h>
25 #include <arpa/inet.h>
29 #define BCMTAG_EXE_USE 1
31 #include "heap_reap.h"
34 static unsigned int MESSAGE_SIZE = 1024;
36 static char *image_type[] = {"IMGDEF", "ROMD", "HPNA"};
43 " -h show additional help\n"
51 pr_error_exit(unsigned int usage, const char *error, ...)
54 char error_message[MESSAGE_SIZE + 1];
58 va_start(args, error);
59 (void) vsnprintf(error_message, MESSAGE_SIZE + 1, error, args);
61 fprintf(stderr, "Error: %s\n", error_message);
63 if (usage) pr_usage(usage);
65 heap_and_reap(NULL-1, 0, 0);
69 /* calculate standard CRC32
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)
75 unsigned int crc32(const unsigned char *data, ssize_t len, unsigned int crc)
77 for ( ; len > 0; --len ) {
78 crc = (crc >> 8) ^ Crc32_table[ (crc ^ *data++) & 0xff ];
85 main(int argc, char **argv)
87 unsigned int arg, crc_header, crc_payload;
88 char *filename = NULL;
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
96 unsigned int opt_quiet;
100 fprintf(stderr, "%s\nVersion: %0.2f\n%s\n", title, VERSION, copyright);
102 for (arg = 1; arg < (unsigned) argc; ++arg) {
104 size_t arg_len = strlen(p);
114 pr_error_exit(0, "cannot read data from stdin; provide a filename");
118 else if (!filename) { // remaining non-option must be the filename
122 fprintf(stderr, "Can only process one file; ignoring '%s'\n", p);
130 if ((fd = open(filename, fd_mode)) > 0) {
132 unsigned int offset = 0;
133 unsigned int count = 0;
134 unsigned int next = 1;
135 void *payload = NULL;
138 unsigned long len = 0;
139 crc_header = crc_payload = 0xffffffff;
141 if (count) // switch struct type after initial file header
142 header_len = sizeof(IMAGE_TAG);
144 lseek(fd, offset, SEEK_SET);
145 printf("Header Offset: 0x%08x (%u)\n", offset, offset);
147 if ( (buffer = heap_and_reap(NULL, header_len, 1)) != NULL) {
149 if ( (qty = read(fd, buffer, header_len)) < header_len) {
151 fprintf(stderr, "warning: only able to read %ld of %ld bytes\n", qty, header_len);
155 PFILE_TAG pfile = (PFILE_TAG) buffer;
156 PIMAGE_TAG pimage = (PIMAGE_TAG) buffer;
159 next = *(unsigned char *)(pfile->imageNext);
160 len = atol(pfile->totalImageLen);
163 next = *(unsigned char *)(pimage->imageNext);
164 len = atol(pimage->imageLen);
165 offset += sizeof(IMAGE_TAG);
168 crc_header = crc32(buffer, header_len - (count ? CRC_LEN : TOKEN_LEN), crc_header);
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);
176 crc_payload = crc32(payload, len, crc_payload);
178 heap_and_reap(payload, 0, 0);
182 pr_error_exit(0, "unable to allocate memory (%ld bytes)\n", len);
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"
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)) ),
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"
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)) ),
255 // next seek point will be end of current payload
258 heap_and_reap(buffer, 0, 0);
264 pr_error_exit(0, "unable to allocate memory (%ld bytes)\n", header_len);
268 heap_and_reap(buffer, 0, 0);
271 fprintf(stderr, "Unable to open for %s (%s)\n", "reading" , filename );
278 heap_and_reap(NULL-1, 0, 0);