[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: more evil firmwares found



On Sun, Apr 25, 2004 at 11:57:28PM -0500, Ryan Underwood wrote:
> 
> I think I'll be doing some footwork on this one.

I wrote a quick program to parse out the microcode from the XFree86
mga_ucode.h files.  From here a disassembler can be written if we can
ever figure out the op codes.  The DDK says that they are 64-bits wide
and 64-bit aligned.  It seems that might be incorrect though.  There are
a lot of "dupes" if you examine the values at a width of 32-bits.

-- 
Ryan Underwood, <nemesis@icequake.net>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#include "warp_opcodes.h"

#define OPCODE_SIZE 8
/* Parse the XFree86 MGA ucodes and generate a source listing. */

static inline int whitespace(char c) {
	return (c == '\n' || c == '\r' || c == ' ' || c == '\t'); 
}

static char *slurp(char *src, char *what) {

	char *p = src;
	int i;

	while (p[0] != what[0]) {
		p++;
		if (*p == '\0') return src;
	}
	for (i = 0; what[i] != '\0'; i++) {
		if (p[i] != what[i]) {
			i--;
			break;
		}
	}
	src = p + i;
	return src;
}

static int disassemble_warp(int *ip, unsigned char *opcode) {

	int i;
	char buf[5];
	
	printf("%x:\t", *ip);
	/* for now just print op */
	for (i = 0; i < OPCODE_SIZE; i++) {
		printf("%2x ", opcode[i]);
	}
	printf("\n");
	*ip += OPCODE_SIZE;
	return 1;
}

int main(int argc, char**argv) {

	FILE *inp;
	char *filebuf, *p;
	int done = 0;
	int error = 0;
	int size;

	if (argc < 2) {
		fprintf(stderr, "Need an argument; a filename or '-' for stdin.\n");
		exit(EXIT_FAILURE);
	}
/*	if (argv[1][0] == '-') {
		fprintf(stderr, "Reading from standard input...\n");
		inp = stdin;
	}
	else {
*/
		if ((inp = fopen(argv[1], "r")) == NULL) {
			perror("fopen");
			exit(EXIT_FAILURE);
		}
		fprintf(stderr, "Reading from file %s...\n", argv[1]);
/*
	}
*/

	if (fseek(inp, 0, SEEK_END) == -1) {
		perror("fseek");
		exit(EXIT_FAILURE);
	}
	if ((size = ftell(inp)) == -1) {
		perror("ftell");
		exit(EXIT_FAILURE);
	}
	if (fseek(inp, 0, SEEK_SET) == -1) {
		perror("fseek");
		exit(EXIT_FAILURE);
	}
	
	filebuf = (char*)malloc(size+1);
	if (filebuf == NULL) {
		perror("malloc");
		exit(EXIT_FAILURE);
	}

	fread(filebuf, size, 1, inp);
	if (ferror(inp)) {
		perror("fread");
		error = 1;
		goto cleanup;
	}

	if (fclose(inp) == EOF) {
		perror("fclose");
	}

	filebuf[size] = '\0';
	p = filebuf;
	char cur_vname[255];
	int vname_next = 0;
	int data_next = 0;

	while (!done && *p != '\0') {
		while (whitespace(*p)) p++;
		if (vname_next) {
			if (*p == '*') { /* declared as pointer */
				p++;
			}
			char *q;
			q = slurp(p, " ");
			strncpy(cur_vname, p, q-p);
			cur_vname[q-p] = '\0';
			fprintf(stderr, "Parsing variable %s...\n", cur_vname);
			p = q;
			p = slurp(p, "{");
			vname_next = 0;
			data_next = 1;
			continue;
		}
		if (data_next) {
			int ip = 0;
			unsigned char cur_op[OPCODE_SIZE];
			int index = 0;

			printf("%s:\n", cur_vname);

			while (*p != '}') {
				if (whitespace(*p)) {
					p++;
					continue;
				}
				if (*p == ',') {
					p++;
					continue;
				}
				if (strncmp(p, "0x", 2) == 0) { /* next component is ready */
					int i;
					long int val = strtol(p, &p, 16);
					if (errno) {
						perror("strtol");
						goto cleanup;
					}
					cur_op[index] = (unsigned char)val;
					index++;
					if (index == OPCODE_SIZE) {
						index = 0;
						if (!disassemble_warp(&ip, cur_op)) {
							fprintf(stderr, "Error disassembly:\n");
							for (i = 0; i < OPCODE_SIZE; i++) {
								fprintf(stderr, "%x", cur_op[i]);
							}
							fprintf(stderr, "\n");
						}
					}
				}
				else {
					char err[50+1];
					strncpy(err, p, 50);
					err[50] = '\0';
					fprintf(stderr, "Malformed input at:\n%s\n", err);
					error = 1;
					goto cleanup;
				}
			}
			data_next = 0;
			p = slurp(p, "}");
			p = slurp(p, ";");
			printf("\n");
		}
		if (strncmp(p, "/*", 2) == 0) {  /* start comment */
			fprintf(stderr, "slurping a comment\n");
			p = slurp(p, "*/");
			continue;
		}
		else if ((strncmp(p, "static ", sizeof("static")) == 0)
				|| strncmp(p, "unsigned ", sizeof("unsigned")) == 0)
		{
			p = slurp(p, " ");
			continue;
		}
		else if (strncmp(p, "char ", sizeof("char")) == 0) {
			vname_next = 1;
			p = slurp(p, " ");
			continue;
		}
		else { /* advance */
//			fprintf(stderr, "advancing\n");
			p++;
		}
	}

cleanup:
	free(filebuf);

	if (error) {
		fprintf(stderr, "Errors were encountered.\n");
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);
}

Attachment: signature.asc
Description: Digital signature


Reply to: