File hfwget.c changed (mode: 100644) (index 1c3a95b..6ccea31) |
... |
... |
static int host_words_in_dword_be = 0; |
78 |
78 |
: swap_bytes_32(value)) : \ |
: swap_bytes_32(value)) : \ |
79 |
79 |
(host_bytes_in_word_be ? swap_words_32(value) : (value)) |
(host_bytes_in_word_be ? swap_words_32(value) : (value)) |
80 |
80 |
|
|
|
81 |
|
#define be16_to_host(value) \ |
|
82 |
|
host_bytes_in_word_be ? (value) : swap_bytes_16(value) |
|
83 |
|
#define be32_to_host(value) \ |
|
84 |
|
host_words_in_dword_be ? \ |
|
85 |
|
(host_bytes_in_word_be ? (value) : reverse_bytes_32(value)) : \ |
|
86 |
|
(host_bytes_in_word_be ? swap_words_32(value) : \ |
|
87 |
|
swap_bytes_32(value)) |
|
88 |
|
|
81 |
89 |
/* Structures to read image data */ |
/* Structures to read image data */ |
82 |
90 |
struct _segarray { |
struct _segarray { |
83 |
91 |
__le32 offset; |
__le32 offset; |
|
... |
... |
static unsigned int imagebase(const u8* data) |
315 |
323 |
return le32_to_host(*((u32*)(pehdr + 0x30))); |
return le32_to_host(*((u32*)(pehdr + 0x30))); |
316 |
324 |
} |
} |
317 |
325 |
|
|
|
326 |
|
struct mach_header { |
|
327 |
|
u32 magic; |
|
328 |
|
int cputype; |
|
329 |
|
int cpusubtype; |
|
330 |
|
u32 filetype; |
|
331 |
|
u32 ncmds; |
|
332 |
|
u32 sizeofcmds; |
|
333 |
|
u32 flags; |
|
334 |
|
}; |
|
335 |
|
|
|
336 |
|
struct mach_load_command |
|
337 |
|
{ |
|
338 |
|
u32 cmd; |
|
339 |
|
u32 cmdsize; |
|
340 |
|
}; |
|
341 |
|
|
|
342 |
|
struct mach_segment_command |
|
343 |
|
{ |
|
344 |
|
u32 cmd; |
|
345 |
|
u32 cmdsize; |
|
346 |
|
char segname[16]; |
|
347 |
|
u32 vmaddr; |
|
348 |
|
u32 vmsize; |
|
349 |
|
u32 fileoff; |
|
350 |
|
u32 filesize; |
|
351 |
|
int maxprot; |
|
352 |
|
int initprot; |
|
353 |
|
u32 nsects; |
|
354 |
|
u32 flags; |
|
355 |
|
}; |
|
356 |
|
|
|
357 |
|
struct mach_section |
|
358 |
|
{ |
|
359 |
|
char sectname[16]; |
|
360 |
|
char segname[16]; |
|
361 |
|
u32 addr; |
|
362 |
|
u32 size; |
|
363 |
|
u32 offset; |
|
364 |
|
u32 align; |
|
365 |
|
u32 reloff; |
|
366 |
|
u32 nreloc; |
|
367 |
|
u32 flags; |
|
368 |
|
u32 reserved1; |
|
369 |
|
u32 reserved2; |
|
370 |
|
}; |
|
371 |
|
|
|
372 |
|
/* returns the start of the segment that contains the firmware */ |
|
373 |
|
static unsigned int macho_imagebase(const u8 *data) |
|
374 |
|
{ |
|
375 |
|
struct mach_header *hdr = (struct mach_header *) data; |
|
376 |
|
int i, j; |
|
377 |
|
const u8 *p = data + sizeof(struct mach_header); |
|
378 |
|
|
|
379 |
|
for (i = 0; i < be32_to_host(hdr->ncmds); i++) { |
|
380 |
|
struct mach_load_command *load_cmd = (struct mach_load_command *) p; |
|
381 |
|
|
|
382 |
|
if (be32_to_host(load_cmd->cmd) == 0x0001) { /* LC_SEGMENT */ |
|
383 |
|
struct mach_segment_command *seg_cmd = (struct mach_segment_command *) p; |
|
384 |
|
|
|
385 |
|
p += sizeof(struct mach_segment_command); |
|
386 |
|
for (j = 0; j < be32_to_host(seg_cmd->nsects); j++) { |
|
387 |
|
struct mach_section *sect = (struct mach_section *) p; |
|
388 |
|
|
|
389 |
|
if (!strcmp (sect->sectname, "__data") && !strcmp (sect->segname, "__DATA")) { |
|
390 |
|
u32 *imgbase = (u32 *) (data + (be32_to_host(sect->addr) - be32_to_host(seg_cmd->vmaddr))); |
|
391 |
|
return *imgbase; |
|
392 |
|
} |
|
393 |
|
|
|
394 |
|
p += sizeof (struct mach_section); |
|
395 |
|
} |
|
396 |
|
} |
|
397 |
|
|
|
398 |
|
/* advance to past the load command */ |
|
399 |
|
p += sizeof (struct mach_load_command); |
|
400 |
|
p += be32_to_host(load_cmd->cmdsize); |
|
401 |
|
} |
|
402 |
|
|
|
403 |
|
printf("Couldn't find Mach-O __data/__DATA section\n"); |
|
404 |
|
return 0; |
|
405 |
|
} |
|
406 |
|
|
|
407 |
|
#define MH_MAGIC 0xfeedface /* BE Mach-O magic number */ |
|
408 |
|
#define MH_CIGAM 0xcefaedfe /* LE Mach-O magic number */ |
|
409 |
|
#define MH_MAGIC_64 0xfeedfacf /* BE Mach-O 64-bit magic number */ |
|
410 |
|
#define MH_CIGAM_64 0xcffaedfe /* LE Mach-O 64-bit magic number */ |
|
411 |
|
|
|
412 |
|
/* Validates the Mach-O object file; only accepts 32-bit BE |
|
413 |
|
* PPC Mach-O object files because classic AirPort was only |
|
414 |
|
* ever used on 32-bit PPC machines. |
|
415 |
|
* |
|
416 |
|
* Returns: |
|
417 |
|
* 0 = success |
|
418 |
|
* -1 = Not a 32-bit PPC Mach-O object file |
|
419 |
|
* -2 = Not a Mach-O object file |
|
420 |
|
*/ |
|
421 |
|
static int macho_validate(const u8 *data) |
|
422 |
|
{ |
|
423 |
|
struct mach_header *hdr = (struct mach_header *) data; |
|
424 |
|
|
|
425 |
|
switch (hdr->magic) { |
|
426 |
|
case MH_MAGIC: |
|
427 |
|
/* Yay, what we need */ |
|
428 |
|
break; |
|
429 |
|
case MH_MAGIC_64: |
|
430 |
|
case MH_CIGAM_64: |
|
431 |
|
case MH_CIGAM: |
|
432 |
|
/* 64-bit or LE 32-bit, can't use it */ |
|
433 |
|
return -1; |
|
434 |
|
default: |
|
435 |
|
/* Not a Mach-O file at all */ |
|
436 |
|
return -2; |
|
437 |
|
} |
|
438 |
|
|
|
439 |
|
if (hdr->cputype != 0x12) /* PPC */ |
|
440 |
|
return -1; |
|
441 |
|
|
|
442 |
|
if (hdr->filetype != 0x0001) /* MH_OBJECT */ |
|
443 |
|
return -1; |
|
444 |
|
|
|
445 |
|
return 0; |
|
446 |
|
} |
|
447 |
|
|
318 |
448 |
/* Returns the virtual location of the firmware block */ |
/* Returns the virtual location of the firmware block */ |
319 |
449 |
static unsigned int find_fwblock_entry(const u8* data, |
static unsigned int find_fwblock_entry(const u8* data, |
320 |
450 |
unsigned int flen, |
unsigned int flen, |
321 |
|
u32 vfwoffs) |
|
|
451 |
|
u32 vfwoffs, |
|
452 |
|
const u32 ibase) |
322 |
453 |
{ |
{ |
323 |
454 |
u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu); |
u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu); |
324 |
455 |
u8 *q; |
u8 *q; |
|
... |
... |
static unsigned int find_fwblock_entry(const u8* data, |
349 |
480 |
*/ |
*/ |
350 |
481 |
q = (u8*)(p - 1); |
q = (u8*)(p - 1); |
351 |
482 |
|
|
352 |
|
fwblock = (unsigned int)(q - data) + imagebase(data); |
|
|
483 |
|
fwblock = (unsigned int)(q - data) + ibase; |
353 |
484 |
if (found == false) { |
if (found == false) { |
354 |
485 |
printf("Firmware block entry not found - contact Mark!\n"); |
printf("Firmware block entry not found - contact Mark!\n"); |
355 |
486 |
return 0; |
return 0; |
|
... |
... |
static struct _firmwareblock* find_fwtable_entry(const u8* data, |
394 |
525 |
*/ |
*/ |
395 |
526 |
static void copy_fw_data(struct firmwareblock* firmware, |
static void copy_fw_data(struct firmwareblock* firmware, |
396 |
527 |
struct _firmwareblock *fw_image, |
struct _firmwareblock *fw_image, |
397 |
|
u8 *data) |
|
|
528 |
|
const u8 *data, |
|
529 |
|
const u32 ibase) |
398 |
530 |
{ |
{ |
399 |
|
u32 delta = (u32)data - imagebase(data); |
|
|
531 |
|
u32 delta = (u32)data - ibase; |
400 |
532 |
unsigned int i; |
unsigned int i; |
401 |
533 |
|
|
402 |
534 |
/* Deal with pointers in firmwareblock */ |
/* Deal with pointers in firmwareblock */ |
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
698 |
830 |
u32 vfwoffs; |
u32 vfwoffs; |
699 |
831 |
FILE* output; |
FILE* output; |
700 |
832 |
size_t len; |
size_t len; |
|
833 |
|
int found = 0; |
701 |
834 |
|
|
702 |
835 |
if (memcmp(data, "MZ", 2) == 0) |
if (memcmp(data, "MZ", 2) == 0) |
703 |
836 |
{ |
{ |
704 |
837 |
printf ("Driver looks like Microsoft PE format\n"); |
printf ("Driver looks like Microsoft PE format\n"); |
705 |
838 |
ibase = imagebase(data); |
ibase = imagebase(data); |
|
839 |
|
found = 1; |
|
840 |
|
} |
|
841 |
|
|
|
842 |
|
if (!found) |
|
843 |
|
{ |
|
844 |
|
int ret; |
|
845 |
|
|
|
846 |
|
ret = macho_validate(data); |
|
847 |
|
if (ret == 0) |
|
848 |
|
{ |
|
849 |
|
printf ("Driver looks like Apple Mach-O format\n"); |
|
850 |
|
ibase = macho_imagebase(data); |
|
851 |
|
found = 1; |
|
852 |
|
} |
|
853 |
|
else if (ret == -1) |
|
854 |
|
{ |
|
855 |
|
printf ("Driver looks like Apple Mach-O format\n" |
|
856 |
|
"But only a 32-bit PPC Mach-O format driver is supported.\n"); |
|
857 |
|
return -5; |
|
858 |
|
} |
706 |
859 |
} |
} |
707 |
|
else if (memcmp(data, "Joy!", 4) == 0) |
|
|
860 |
|
|
|
861 |
|
if (!found && memcmp(data, "Joy!", 4) == 0) |
708 |
862 |
{ |
{ |
709 |
863 |
printf ("Driver looks like Apple PEF format\n"); |
printf ("Driver looks like Apple PEF format\n"); |
710 |
864 |
printf ("I don't know how to extract for this format.\n" |
printf ("I don't know how to extract for this format.\n" |
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
724 |
878 |
/* ibase = pef_imagebase(data); */ |
/* ibase = pef_imagebase(data); */ |
725 |
879 |
return -5; |
return -5; |
726 |
880 |
} |
} |
727 |
|
else |
|
|
881 |
|
|
|
882 |
|
if (!found) |
728 |
883 |
{ |
{ |
729 |
884 |
printf ("Unknown object file format\n"); |
printf ("Unknown object file format\n"); |
730 |
885 |
return -5; |
return -5; |
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
751 |
906 |
|
|
752 |
907 |
vfwoffs = (u32)(fw - data) + ibase; |
vfwoffs = (u32)(fw - data) + ibase; |
753 |
908 |
|
|
754 |
|
printf("PE imagebase is 0x%08x, therefore virtual offset of firmware is 0x%08x\n", |
|
|
909 |
|
printf("Image base is 0x%08x, therefore virtual offset of firmware is 0x%08x\n", |
755 |
910 |
ibase, vfwoffs); |
ibase, vfwoffs); |
756 |
911 |
|
|
757 |
912 |
fwblock = find_fwblock_entry(data, |
fwblock = find_fwblock_entry(data, |
758 |
913 |
flen, |
flen, |
759 |
|
vfwoffs); |
|
|
914 |
|
vfwoffs, |
|
915 |
|
ibase); |
760 |
916 |
if (!fwblock) |
if (!fwblock) |
761 |
917 |
return -2; |
return -2; |
762 |
918 |
|
|
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
766 |
922 |
if (!fw_image) |
if (!fw_image) |
767 |
923 |
return -3; |
return -3; |
768 |
924 |
|
|
769 |
|
copy_fw_data(&firmware, fw_image, data); |
|
|
925 |
|
copy_fw_data(&firmware, fw_image, data, ibase); |
770 |
926 |
|
|
771 |
927 |
/* Print FW ident information */ |
/* Print FW ident information */ |
772 |
928 |
printf("Entry point at 0x%08x\n", firmware.halfentry * 2); |
printf("Entry point at 0x%08x\n", firmware.halfentry * 2); |