//===================================================================
// Exe File Information v1.0 by Cronos
//-------------------------------------------------------------------
// Language:		C (DOS)
//
// Usage:		PEINFO [flags] <exename>
//
// Flags:		-h :help screen
//
// Action:		Gives detailed information on PE format.
//===================================================================


//-------------------------------------------------------------------
// Set-up includes,typedefs,etc
// ----------------------------
//
//
//-------------------------------------------------------------------

#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include "peinfo.h"

char vers[]="PEINFO v1.0 by Cronos";

struct opt
{ bool help;
  char file[MAX_STRLEN];
} options;

//
// initialise
// - call before processing the command line
//
void initialise(void)
{ printf("%s\n\n",vers);
  options.help=false;
  options.file[0]=0;
}

//-------------------------------------------------------------------
// PE Library Routines
// -------------------
// peoffset	offset to pe header in file
// optsize	size of optional header
// shoffset	offset to section headers
//-------------------------------------------------------------------

struct IMAGE_FILE_HEADER      ifh;
struct IMAGE_OPTIONAL_HEADER  ioh;
struct IMAGE_SECTION_HEADER   ish;

int pefile;
dword peoffset,shoffset;
dword optsize;

void pefileshutdown(void)
{ close(pefile);
}

void pefileinit(void)
{ char filename[MAX_STRLEN];
  byte pebuff[1024];
  int i;
  if ((pefile=open(options.file,O_BINARY))==-1)
  { strcpy(filename,options.file);
    strcat(filename,".exe");
    if ((pefile=open(filename,O_BINARY))==-1)
    { printf("Fatal Error:Can't open : %s\n",options.file);
      exit(1);
    }
  }
  printf("\nOpened file, reading header\n");
  if(read(pefile,pebuff,0x40)<0x40)
  { printf("Fatal error:File is not a PE file\n");
    close(pefile);
    exit(1);
  }
  if(!(((pebuff[0]=='M')&&(pebuff[1]=='Z'))||((pebuff[1]=='M')&&(pebuff[0]=='Z'))))
  { printf("Fatal Error:File is not an executable file\n");
    close(pefile);
    exit(1);
  }
  if(((word *)&pebuff[0x18])[0]<0x40)
  { printf("Fatal Error:DOS reloc table position incorrect for PE file format\n");
    close(pefile);
    exit(1);
  }
  peoffset=((dword *)&pebuff[0x3c])[0];
  if(peoffset<0x40)
  { printf("Fatal Error:No extended header found in executable file\n");
    close(pefile);
    exit(1);
  }
  if(lseek(pefile,peoffset,SEEK_SET)==-1)
  { printf("Fatal Error:Error seeking PE Header\n");
    close(pefile);
    exit(1);
  }
  if(read(pefile,pebuff,4)!=4)
  { printf("Fatal Error:Error reading PE magic\n");
    close(pefile);
    exit(1);
  }
  if(((dword *)pebuff)[0]!=PEMAGIC)
  { printf("PE Magic not found\n");
    close(pefile);
    exit(1);
  }
  printf("Found PE Magic, reading header info\n");
  if(read(pefile,&ifh,sizeof(ifh))!=sizeof(ifh))
  { printf("Fatal Error:Error reading PE header info\n");
    close(pefile);
    exit(1);
  }
  printf("Read PE Header, reading optional header\n");
  optsize=sizeof(ioh)-IMAGE_NUMBEROF_DIRECTORY_ENTRIES*sizeof(struct IMAGE_DATA_DIRECTORY);
  if(read(pefile,&ioh,(int)optsize)!=optsize)
  { printf("Fatal Error:Error reading PE optional header info\n");
    close(pefile);
    exit(1);
  }
  for(i=0;i<IMAGE_NUMBEROF_DIRECTORY_ENTRIES;i++)
  { ioh.DataDirectory[i].VirtualAddress=0;
    ioh.DataDirectory[i].Size=0;
  }
  printf("Read optional header, reading data directory summaries\n");
  for(i=0;i<ioh.NumberOfRvaAndSizes;i++)
  { if(read(pefile,&ioh.DataDirectory[i],
      sizeof(struct IMAGE_DATA_DIRECTORY))!=sizeof(struct IMAGE_DATA_DIRECTORY))
    { printf("Fatal Error:Error reading data directories\n\n");
      close(pefile);
      exit(1);
    }
  }
  shoffset=peoffset+optsize+sizeof(ifh)+4+ioh.NumberOfRvaAndSizes*sizeof(struct IMAGE_DATA_DIRECTORY);
  printf("\nPE File Header Entries Summary\n");
  printf("------------------------------\n");
  printf("Machine                    :0x%0x\n",ifh.Machine);
  printf("NumberOfSections           :0x%0x\n",ifh.NumberOfSections);
  printf("TimeDateStamp              :0x%0lx\n",ifh.TimeDateStamp);
  printf("PointerToSymbolTable       :0x%0lx\n",ifh.PointerToSymbolTable);
  printf("NumberOfSymbols            :0x%0lx\n",ifh.NumberOfSymbols);
  printf("SizeOfOptionalHeader       :0x%0x\n",ifh.SizeOfOptionalHeader);
  printf("Characteristics            :0x%0x\n",ifh.Characteristics);
  printf("\n");
  printf("PE File Optional Header Entries Summary\n");
  printf("---------------------------------------\n");
  printf("Standard fields:\n");
  printf("Magic                      :0x%x\n",ioh.Magic);
  printf("MajorLinkerVersion         :0x%x\n",ioh.MajorLinkerVersion);
  printf("MinorLinkerVersion         :0x%x\n",ioh.MinorLinkerVersion);
  printf("SizeOfCode                 :0x%lx\n",ioh.SizeOfCode);
  printf("SizeOfInitializedData      :0x%lx\n",ioh.SizeOfInitializedData);
  printf("SizeOfUninitializedData    :0x%lx\n",ioh.SizeOfUninitializedData);
  printf("AddressOfEntryPoint        :0x%lx\n",ioh.AddressOfEntryPoint);
  printf("BaseOfCode                 :0x%lx\n",ioh.BaseOfCode);
  printf("BaseOfData                 :0x%lx\n",ioh.BaseOfData);
  printf("NT [Windows] additional fields:\n");
  printf("ImageBase                  :0x%lx\n",ioh.ImageBase);
  printf("SectionAlignment           :0x%lx\n",ioh.SectionAlignment);
  printf("FileAlignment              :0x%lx\n",ioh.FileAlignment);
  printf("MajorOperatingSystemVersion:0x%x\n",ioh.MajorOperatingSystemVersion);
  printf("MinorOperatingSystemVersion:0x%x\n",ioh.MinorOperatingSystemVersion);
  printf("MajorImageVersion          :0x%x\n",ioh.MajorImageVersion);
  printf("MinorImageVersion          :0x%x\n",ioh.MinorImageVersion);
  printf("MajorSubsystemVersion      :0x%x\n",ioh.MajorSubsystemVersion);
  printf("MinorSubsystemVersion      :0x%x\n",ioh.MinorSubsystemVersion);
  printf("Reserved1                  :0x%lx\n",ioh.Reserved1);
  printf("SizeOfImage                :0x%lx\n",ioh.SizeOfImage);
  printf("SizeOfHeaders              :0x%lx\n",ioh.SizeOfHeaders);
  printf("CheckSum                   :0x%lx\n",ioh.CheckSum);
  printf("Subsystem                  :0x%x\n",ioh.Subsystem);
  printf("DllCharacteristics         :0x%x\n",ioh.DllCharacteristics);
  printf("SizeOfStackReserve         :0x%lx\n",ioh.SizeOfStackReserve);
  printf("SizeOfStackCommit          :0x%lx\n",ioh.SizeOfStackCommit);
  printf("SizeOfHeapReserve          :0x%lx\n",ioh.SizeOfHeapReserve);
  printf("SizeOfHeapCommit           :0x%lx\n",ioh.SizeOfHeapCommit);
  printf("LoaderFlags                :0x%lx\n",ioh.LoaderFlags);
  printf("NumberOfRvaAndSizes        :0x%lx\n",ioh.NumberOfRvaAndSizes);
  printf("\n");
  printf("Data Directory Summary\n");
  printf("----------------------\n");
  for(i=0;i<ioh.NumberOfRvaAndSizes;i++)
  { printf("\n");
    switch(i)
    { case IMAGE_DIRECTORY_ENTRY_EXPORT:
	printf("Export Directory :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_IMPORT:
	printf("Import Directory :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_RESOURCE:
	printf("Resource Directory :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_EXCEPTION:
	printf("Exception Directory :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_SECURITY:
	printf("Security Directory :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_BASERELOC:
	printf("Base Relocation Table :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_DEBUG:
	printf("Debug Directory :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_COPYRIGHT:
	printf("Description String :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_GLOBALPTR:
	printf("Machine Value (MIPS GP) :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_TLS:
	printf("TLS Directory :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG:
	printf("Load Configuration Directory :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT:
	printf("Bound Import Directory in headers :\n");
	break;
      case IMAGE_DIRECTORY_ENTRY_IAT:
	printf("Import Address Table :\n");
	break;
      default:
	printf("Unknown Directory :0x%x\n",i);
	break;
    }
    printf("VirtualAddress             :0x%lx\n",ioh.DataDirectory[i].VirtualAddress);
    printf("Size                       :0x%lx\n",ioh.DataDirectory[i].Size);
  }
  printf("\n");
}

void loadsectionheaderinfo(word snum)
{ printf("\nLoading section header info : section number %d\n",snum);
  if(lseek(pefile,shoffset+snum*sizeof(ish),SEEK_SET)==-1)
  { printf("Fatal Error:Error seeking Section Header\n");
    close(pefile);
    exit(1);
  }
  if(read(pefile,&ish,sizeof(ish))!=sizeof(ish))
  { printf("Fatal Error:Error reading Section header info\n");
    close(pefile);
    exit(1);
  }
}

void sectionheadersummary(void)
{ int i,j;
  char namebuff[IMAGE_SIZEOF_SHORT_NAME+2];
  printf("Section Header summary\n");
  printf("----------------------\n");
  for(i=0;i<ifh.NumberOfSections;i++)
  { loadsectionheaderinfo(i);
    for(j=0;j<IMAGE_SIZEOF_SHORT_NAME;j++) namebuff[j]=ish.Name[j];
    namebuff[j]=0;
    printf("Section Name : %s\n",namebuff);
    printf("VirtualSize         :0x%lx\n",ish.Misc.VirtualSize); // union ish.Misc
    printf("VirtualAddress      :0x%lx\n",ish.VirtualAddress);
    printf("SizeOfRawData       :0x%lx\n",ish.SizeOfRawData);
    printf("PointerToRawData    :0x%lx\n",ish.PointerToRawData);
    printf("PointerToRelocations:0x%lx\n",ish.PointerToRelocations);
    printf("PointerToLinenumbers:0x%lx\n",ish.PointerToLinenumbers);
    printf("NumberOfRelocations :0x%x\n",ish.NumberOfRelocations);
    printf("NumberOfLinenumbers :0x%x\n",ish.NumberOfLinenumbers);
    printf("Characteristics     :0x%lx\n",ish.Characteristics);
    if(ish.Characteristics&0x00000020) printf("Property            :Code Section\n");
    if(ish.Characteristics&0x00000040) printf("Property            :Initialized data section\n"); 
    if(ish.Characteristics&0x00000080) printf("Property            :Uninitialized data section\n"); 
    if(ish.Characteristics&0x04000000L) printf("Property            :Section cannot be cached\n");
    if(ish.Characteristics&0x08000000L) printf("Property            :Section is not pageable\n");
    if(ish.Characteristics&0x10000000L) printf("Property            :Section is shared\n");
    if(ish.Characteristics&0x20000000L) printf("Property            :Executable section\n");
    if(ish.Characteristics&0x40000000L) printf("Property            :Readable section\n");
    if(ish.Characteristics&0x80000000L) printf("Property            :Writable section\n");
  }
}

//-------------------------------------------------------------------
// Main Application
// ----------------
//-------------------------------------------------------------------

//
// readcommandline
// - processes command line
// - checks options for conflicts,validity,etc
//
void readcommandline(int argc,char *argv[])
{ int i;
  for(i=1;i<argc;i++)
  { if(argv[i][0]=='-')
    { switch(argv[i][1])
      { case 'h':
	case 'H':
	  options.help=true;
	  break;
	default:
	  printf("Unknown option : %c\n",argv[i][1]);
	  exit(1);
      }
    }
    else
    { if(!options.file[0])
      { strcpy(options.file,argv[i]);
      }
      else
      { printf("File ? %s or %s ?\n",options.file,argv[i]);
	exit(1);
      }
    }
  }
  if(!options.file[0])
  { printf("Fatal error:No file specified\n");
    exit(1);
  }
}

int main(int argc,char *argv[])
{ initialise();
  readcommandline(argc,argv);
  pefileinit();
  sectionheadersummary();
  pefileshutdown();
  return 0;
}

