//+++2002-03-03 // Copyright (C) 2001,2002 Mike Rieker, Beverly, MA USA // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //---2002-03-03 #include #include #include #include #include #include typedef unsigned char uByte; typedef unsigned long uLong; typedef unsigned short uWord; typedef unsigned long OZ_Pointer; #include "disassemble.h" #define FLAG_IMPORT_RVA 0x01 #define FLAG_RELOC_HIGHLOW 0x02 #define FLAG_DISASSEMBLE 0x04 #include "pe_format.h" /* Table of addresses known to contain instructions to disassemble */ #define MAXSTARTADDRS 65536 static int nstartaddrs = 14; static uLong startaddrs[MAXSTARTADDRS] = { 0x985A // aic78xx_start, DriverEntry ,0xA19A // HwInitialize ,0xA408 // HwStartIo ,0xA3CA // HwInterrupt ,0x9BA3 // HwFindAdapter ,0xA360 // HwResetBus ,0xA284 // HwAdapterState ,0xABBA // bad call to GetDeviceBase ,0x23BE // start of routine that calls GetDeviceBase ,0xAB64 // ... more of routine that calls GetDeviceBase ,0x623E // start of routine that crashes called from 05E6 ,0xACBE // routine to read a byte from I/O port ,0xAD4E // ?? ,0xB084 // reads config space // ,0xA2AE // ?? }; int main (int argc, char *argv[]) { char disasmbuf[256]; FILE *pefile; int filesize, i, image_base_relocation_size, import_address_count, j, number_of_sections, rc, reloc_count; OZ_Pointer inst_operand; struct stat statbuf; uByte *filebuff, *flagbuff; uLong inst_flags; uLong address_of_entry_point, callvector, *import_address_table, lastva; uWord *reloc_entries, reloc_entry; IMAGE_BASE_RELOCATION *image_base_relocations; IMAGE_DATA_DIRECTORY *image_data_directory; IMAGE_DOS_HEADER *image_dos_header; IMAGE_FILE_HEADER *image_file_header; IMAGE_IMPORT_BY_NAME *image_import_by_name; IMAGE_IMPORT_DESCRIPTOR *image_import_descriptors; IMAGE_NT_HEADERS32 *image_nt_header; IMAGE_OPTIONAL_HEADER *image_optional_header; IMAGE_SECTION_HEADER *image_section_headers; /* Read image file into memory */ pefile = fopen ("aic78xx.sys", "rb"); if (pefile == NULL) { perror ("error opening aic78xx.sys"); return (-1); } if (stat ("aic78xx.sys", &statbuf) < 0) { perror ("error statting aic78xx.sys"); return (-1); } filesize = statbuf.st_size; filebuff = malloc (filesize); rc = fread (filebuff, 1, filesize, pefile); if (rc < 0) { perror ("error reading aic78xx.sys"); return (-1); } if (rc < filesize) { fprintf (stderr, "only read %d bytes of %d in aic78xx.sys\n", rc, filesize); return (-1); } flagbuff = malloc (filesize); memset (flagbuff, 0, filesize); /* DOS header is at the very beginning */ image_dos_header = (void *)filebuff; if (image_dos_header -> e_magic != IMAGE_DOS_SIGNATURE) { fprintf (stderr, "bad image_dos_header magic number %4.4X\n", image_dos_header -> e_magic); return (-1); } /* NT header = where e_lfanew points */ image_nt_header = (void *)(filebuff + image_dos_header -> e_lfanew); if (image_nt_header -> Signature != IMAGE_NT_SIGNATURE) { fprintf (stderr, "bad image_nt_header Signature %8.8X\n", image_nt_header -> Signature); return (-1); } image_file_header = &(image_nt_header -> FileHeader); image_optional_header = &(image_nt_header -> OptionalHeader); /* Check out things in the image_file_header */ if (image_file_header -> Machine != IMAGE_FILE_MACHINE_I386) { fprintf (stderr, "bad image_file_header Machine %4.4X\n", image_file_header -> Machine); return (-1); } number_of_sections = image_file_header -> NumberOfSections; /* Check out things in the image_optional_header */ if (image_optional_header -> Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { fprintf (stderr, "bad image_optional_header Magic %4.4X\n", image_optional_header -> Magic); return (-1); } address_of_entry_point = image_optional_header -> AddressOfEntryPoint; // this is the DriverEntry offset in filebuff image_data_directory = image_optional_header -> DataDirectory; // point to data directory array /* Image section headers directly follow image_nt_headers */ image_section_headers = (void *)(image_nt_header + 1); for (i = 0; i < number_of_sections; i ++) { if (image_section_headers[i].VirtualAddress != image_section_headers[i].PointerToRawData) { fprintf (stderr, "section %d VirtualAddress %8.8X != PointerToRawData %8.8X\n", i, image_section_headers[i].VirtualAddress, image_section_headers[i].PointerToRawData); return (-1); } } /* Mark all locations that need to be relocated by the actual load address of the image */ image_base_relocation_size = image_data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; image_base_relocations = (void *)(filebuff + image_data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); while (image_base_relocation_size > 0) { /* Process a relocation block - holds relocs for a page */ reloc_count = (image_base_relocations -> SizeOfBlock - sizeof *image_base_relocations) / sizeof *reloc_entries; reloc_entries = (void *)(image_base_relocations + 1); while (-- reloc_count >= 0) { reloc_entry = *(reloc_entries ++); switch (reloc_entry >> 12) { case IMAGE_REL_BASED_ABSOLUTE: { break; } case IMAGE_REL_BASED_HIGHLOW: { flagbuff[image_base_relocations->VirtualAddress+(reloc_entry&0x0FFF)] |= FLAG_RELOC_HIGHLOW; break; } default: { fprintf (stderr, "bad relocation entry %4.4X\n", reloc_entry); return (-1); } } } /* Increment on to next relocation block */ image_base_relocation_size -= image_base_relocations -> SizeOfBlock; (uByte *)image_base_relocations += image_base_relocations -> SizeOfBlock; } /* Find all the imported symbols */ import_address_count = image_data_directory[IMAGE_DIRECTORY_ENTRY_IAT].Size / sizeof *import_address_table; import_address_table = (void *)(filebuff + image_data_directory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress); while ((-- import_address_count >= 0) && ((i = *import_address_table) != 0)) { if (i < 0) { fprintf (stderr, "import_address_table RVA %8.8X has bit 31 set\n", i); return (-1); } flagbuff[((uByte *)import_address_table)-filebuff] |= FLAG_IMPORT_RVA; import_address_table ++; } /* Find all the instructions */ for (i = 0; i < nstartaddrs; i ++) { lastva = startaddrs[i]; do { if (lastva >= filesize) break; if (flagbuff[lastva] & FLAG_DISASSEMBLE) break; flagbuff[lastva] |= FLAG_DISASSEMBLE; j = disassemble (DISASM_MAXLEN, filebuff + lastva, lastva, sizeof disasmbuf, disasmbuf, &inst_flags, &inst_operand); lastva += j; if (inst_flags & INST_FLAG_FORK) { fprintf (stderr, "fork from %x to %x\n", lastva - j, inst_operand); if (nstartaddrs < MAXSTARTADDRS) startaddrs[nstartaddrs++] = inst_operand; } if (inst_flags & INST_FLAG_JUMP) { fprintf (stderr, "jump from %x to %x\n", lastva - j, inst_operand); lastva = inst_operand; } } while (!(inst_flags & INST_FLAG_TERM)); } /* Output everything */ printf (" .globl aic78xx_base\n"); printf (" .globl aic78xx_start\n"); printf (" .data\n"); printf ("aic78xx_base:\n"); lastva = 0; for (j = 0; j < number_of_sections; j ++) { printf ("\n# section %*.*s: %8.8X %8.8X @ %8.8X\n", IMAGE_SIZEOF_SHORT_NAME, IMAGE_SIZEOF_SHORT_NAME, image_section_headers[j].Name, image_section_headers[j].Characteristics, image_section_headers[j].SizeOfRawData, image_section_headers[j].VirtualAddress); if (image_section_headers[j].Characteristics & IMAGE_SCN_MEM_DISCARDABLE) continue; if (image_section_headers[j].VirtualAddress != lastva) { printf (" .space 0x%8.8X\n", image_section_headers[j].VirtualAddress - lastva); } for (i = image_section_headers[j].VirtualAddress; i < image_section_headers[j].VirtualAddress + image_section_headers[j].SizeOfRawData; i ++) { if (i == address_of_entry_point) { printf ("aic78xx_start:\n"); } if (((i & 3) == 0) && ((flagbuff[i+0] | flagbuff[i+1] | flagbuff[i+2] | flagbuff[i+3]) == 0) && ((address_of_entry_point < i) || (i + 4 <= address_of_entry_point))) { printf (" .long 0x%8.8X # %4.4X\n", *(uLong *)(filebuff + i), i); i += 3; continue; } if (flagbuff[i] == 0) { printf (" .byte 0x%2.2X\n", filebuff[i]); continue; } if (flagbuff[i] == FLAG_DISASSEMBLE) { disassemble (DISASM_MAXLEN, filebuff + i, i, sizeof disasmbuf, disasmbuf, &inst_flags, &inst_operand); if ((filebuff[i] == 0xFF) && (filebuff[i+1] == 0x15)) { callvector = *(uLong *)(filebuff + i + 2) - image_optional_header -> ImageBase; if ((callvector < filesize) && (flagbuff[callvector] == FLAG_IMPORT_RVA)) { strcat (disasmbuf, " -> "); strcat (disasmbuf, filebuff + *(uLong *)(filebuff + callvector) + 2); } } printf (" .byte 0x%2.2X # %4.4X %s\n", filebuff[i], i, disasmbuf); continue; } if (flagbuff[i] == FLAG_IMPORT_RVA) { printf (" .long %s # %4.4X\n", filebuff + *(uLong *)(filebuff + i) + 2, i); i += 3; continue; } if (flagbuff[i] == FLAG_RELOC_HIGHLOW) { printf (" .long 0x%8.8X+aic78xx_base\n", *(uLong *)(filebuff + i) - image_optional_header -> ImageBase); i += 3; continue; } fprintf (stderr, "unknown flagbuff[%d] = %X\n", i, flagbuff[i]); return (-1); } lastva = i; } printf ("# the end\n"); return (0); }