/*
* Hermes AP firmware extractor for Windows drivers (c) 2003 by Mark Smith
* This may be distributed freely under the GPL v2 so long as this copyright
* notice is included.
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#define false 0
#define true (!0)
struct _segarray {
unsigned int offset;
unsigned int size;
unsigned char *data;
};
struct _plugarray {
unsigned int code;
unsigned int targ_off;
unsigned int length;
};
struct firmwareblock {
struct _segarray *segarray;
unsigned int halfentry;
struct _plugarray *plugarray;
} *firmware;
void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature, unsigned char hexchar);
/*
* Main
*/
int main(int argc, char *argv[])
{
FILE *input, *output;
unsigned char *data, *offset, *end, *hexstringoffs, *page1start, *peheader;
unsigned char hexstring[16];
unsigned int i, j, flen, found, imagebase, vfwoffs, fwblock;
printf("Lucent Firmware Extractor v1.0 alpha\n(c) 2003 Mark Smith (username 'Mark' on HermesAP board)\n");
// Attempt to load file
if (argc != 2) {
printf("Usage: %s wl???.sys\n", argv[0]);
return -1;
}
if ((input = fopen(argv[1], "rb")) == NULL) {
printf("Unable to open %s, aborting.\n", argv[1]);
return -1;
}
// Get file length
fseek(input, 0L, SEEK_END);
flen = ftell(input);
printf("File %s length %u (0x%08x)\n", argv[1], flen, flen);
// Rewind file pointer
fseek(input, 0L, SEEK_SET);
// Allocate memory and load the file
data = malloc(flen);
fread(data, 1, flen, input);
printf("Memory allocated and file read OK\n");
fclose(input);
// Dump Tertiary firmware
printf("\nAttempting to dump tertiary firmware:\n");
savefirmware(data, flen, 0xfbfe4461, 'T');
printf("\nAttempting to dump station firmware:\n");
savefirmware(data, flen, 0x63fc600f, 'R');
free(data);
printf("\nAll dumps complete.\n\n");
return 0;
}
void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature, unsigned char hexchar)
{
FILE *output;
unsigned char *offset, *end, *hexstringoffs, *page1start, *peheader;
unsigned char hexstring[16];
unsigned int i, j, found, imagebase, vfwoffs, fwblock;
// Find the ?1XXYYZZ.HEX string
offset = data;
end = (unsigned char *)((unsigned int)data + flen);
for (found = false; found == false && offset != NULL; ) {
offset = memchr(offset, hexchar, (unsigned int)(end - offset));
if (offset != NULL) {
if (memcmp(".HEX", offset + 8, 4) == 0) {
hexstringoffs = offset;
found = true;
} else
offset++;
}
}
if (offset == NULL) {
printf("%c-firmware not found!\n", hexchar);
exit(-1);
}
strncpy(hexstring, offset, 13);
hexstring[13] = 0;
printf("Found firmware %s at file offset 0x%08x\n", hexstring, offset-data);
printf("Searching for firmware start signature 0x%08x...\n", signature);
// Really should use a mask here, but its not necessary for the moment.
offset -= 4;
for (found = false; offset > data && found == false; offset--)
if (*(unsigned int *)offset == signature)
found = true;
if (found == false) {
printf("Signature not found!\n");
exit(-2);
} else {
page1start = offset;
printf("Found at file offset 0x%08x\n", page1start - data);
}
peheader = (unsigned char *)(*(unsigned int *)(data + 0x3c));
printf("Reading DOS driver header...\nPE header located at file offset 0x%08x\n", peheader);
imagebase = (unsigned int)(*(unsigned int *)((unsigned int)peheader + (unsigned int)data + 0x34));
vfwoffs = (unsigned int)((unsigned int)page1start - (unsigned int)data + imagebase);
printf("PE imagebase is 0x%08x, therefore virtual offset of firmware is 0x%08x\n",
imagebase, vfwoffs);
printf("Now searching for driver's tertiary firmware table...\n");
offset = end;
vfwoffs -= 3; // kludge for driver firmware structure: one redundant dword at start.
for (found = false; offset > data && found == false; offset--)
if (*(unsigned int *)offset == vfwoffs)
found = true;
fwblock = (unsigned int)offset - 7 + imagebase - (unsigned int)data;
if (found == false) {
printf("Tertiary table not found - contact Mark!\n");
exit(-3);
} else {
printf("Found at virtual offset 0x%08x\n", fwblock);
}
printf("Finding main firmware table....\n");
offset = end;
for (found = false; offset > data && found == false; offset--)
if (*(unsigned int *)offset == fwblock)
found = true;
firmware = (struct firmwareblock *)++offset;
if (found == false) {
printf("Main table not found - contact Mark!\n");
exit(-4);
} else {
printf("Found at file offset 0x%08x\n", offset - data);
}
printf("Entry point at 0x%08x\n", firmware->halfentry * 2);
(unsigned int)firmware->segarray += (unsigned int)data - imagebase;
for (i = 0; i < 4 && firmware->segarray[i].offset != 0; i++) {
(unsigned int)firmware->segarray[i].data -= imagebase - 4;
printf("Segment: %d File offs: 0x%08x Target mem: 0x%08x Length 0x%08x\n",
i,
firmware->segarray[i].data,
firmware->segarray[i].offset,
firmware->segarray[i].size);
}
printf("Plugrecords at file offset 0x%08x\n", (unsigned int)firmware->plugarray - imagebase);
hexstring[9] = 0;
strcat(hexstring, "hfw");
printf("Dumping to %s...\n", hexstring);
if ((output = fopen(hexstring, "wb")) == NULL) {
printf("Unable to open %s, aborting.\n", hexstring);
exit(-5);
}
(unsigned int)firmware->plugarray += (unsigned int)data - imagebase;
fprintf(output, "HFW1\nENTRY %08X\n", firmware->halfentry * 2);
for (i = 0; firmware->plugarray[i].code != 0; i++) {
fprintf(output, "PLUG %08X %08X %08X\n",
firmware->plugarray[i].code,
firmware->plugarray[i].targ_off,
firmware->plugarray[i].length);
}
for (i = 0; firmware->segarray[i].offset != 0; i++) {
(unsigned int)firmware->segarray[i].data += (unsigned int)data;
if (i != 0)
fprintf(output, "\n");
fprintf(output, "SEG %08X %08X %08X",
firmware->segarray[i].offset,
firmware->segarray[i].size,
0);
for (j = 0; j < firmware->segarray[i].size; j += 2) {
if ((j % 16) == 0)
fprintf(output, "\nDATA");
fprintf(output, " %02X%02X",
firmware->segarray[i].data[j],
firmware->segarray[i].data[j + 1]);
}
}
fputc('\n', output);
fclose(output);
printf("Dump of %s complete.\n", hexstring);
}