tuxsavvy / agere_fw_utils (public) (License: Dual BSD 3-clause and GPLv2) (since 2021-02-07) (hash sha1)
Personal fork of https://repo.or.cz/agere_fw_utils.git

/hfwget.c (c3f095256f593e0352f0086dfe7f81c8a04a28df) (6292 bytes) (mode 100644) (type blob)

/*
 * 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);
}


Mode Type Size Ref File
100644 blob 751 f752eb00ad23ba3f85ee3434b2eb285dc85121bd README.dump_fw
100644 blob 6413 d0254ddd173534037da4ef28cd323a88673bd750 dump_fw.c
100644 blob 1108 83c95872fe12b9d279be420ca158a68232ad6f00 dump_fw.mk
100644 blob 6292 c3f095256f593e0352f0086dfe7f81c8a04a28df hfwget.c
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/tuxsavvy/agere_fw_utils

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/tuxsavvy/agere_fw_utils

Clone this repository using git:
git clone git://git.rocketgit.com/user/tuxsavvy/agere_fw_utils

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main