/*
  PE reader by JoE xD
  http://joe-is-a-rocknroll-star.blogspot.com/  

*/



// Windows headers
#include<windows.h>
#include<winbase.h>
#include<winnt.h>

// Libc headers
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

// Manage the errors
#define CHECK_ERROR_LIBC(toCheck,s) if(toCheck==-1){perror(s);return EXIT_FAILURE;}
#define CHECK_ERROR_NULL(toCheck,s) if(toCheck==NULL){perror(s);return EXIT_FAILURE;}
#define CHECK_ERROR_EOF(toCheck,s) if(toCheck==EOF){perror(s);return EXIT_FAILURE;}

// Functions
void displayDosHeader(IMAGE_DOS_HEADER dosHeader);
void displayPeFileHeader(IMAGE_NT_HEADERS peHeader);
void displayCharacteristics(short characteristics);
void displaySubsystem(int subsystem);
void displayDataDirectory(PIMAGE_DATA_DIRECTORY dataDirectory);
void displaySections(IMAGE_SECTION_HEADER * sections,int numberOfSections);
void displaySectionCharacteristic(int characteristics);

// beurk
int numberOfSections;

// ----------------------------------
// --| Structures for the PE File |--
// --|   defined in winnt.h       |--
// ----------------------------------

// --> FIRST : the DOS Header :
       
//typedef struct _IMAGE_DOS_HEADER {      
//    WORD   e_magic;                     // Magic number ("MZ")
//    WORD   e_cblp;                      // Bytes on last page of file
//    WORD   e_cp;                        // Pages in file
//    WORD   e_crlc;                      // Relocations
//    WORD   e_cparhdr;                   // Size of header in paragraphs
//    WORD   e_minalloc;                  // Minimum extra paragraphs needed
//    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
//    WORD   e_ss;                        // Initial (relative) SS value
//    WORD   e_sp;                        // Initial SP value
//    WORD   e_csum;                      // Checksum
//    WORD   e_ip;                        // Initial IP value
//    WORD   e_cs;                        // Initial (relative) CS value
//    WORD   e_lfarlc;                    // File address of relocation table
//    WORD   e_ovno;                      // Overlay number
//    WORD   e_res[4];                    // Reserved words
//    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
//    WORD   e_oeminfo;                   // OEM information; e_oemid specific
//    WORD   e_res2[10];                  // Reserved words
//    DWORD  e_lfanew;                    // File address of new exe header
//  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
// 
// The last item in the struct (e_lfanew) is the offset that tells us where 
// to find the next structure 


// --> SECOND : the PE Header HiMs3Lf :
       
//typedef struct _IMAGE_NT_HEADERS {
//	DWORD Signature;
//	IMAGE_FILE_HEADER FileHeader;
//	IMAGE_OPTIONAL_HEADER OptionalHeader;
//} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;

//typedef struct _IMAGE_FILE_HEADER {
//	WORD Machine;
//	WORD NumberOfSections;
//	DWORD TimeDateStamp;
//	DWORD PointerToSymbolTable;
//	DWORD NumberOfSymbols;
//	WORD SizeOfOptionalHeader;
//	WORD Characteristics;
//} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

//typedef struct _IMAGE_OPTIONAL_HEADER {
//	WORD Magic;
//	BYTE MajorLinkerVersion;
//	BYTE MinorLinkerVersion;
//	DWORD SizeOfCode;
//	DWORD SizeOfInitializedData;
//	DWORD SizeOfUninitializedData;
//	DWORD AddressOfEntryPoint;
//	DWORD BaseOfCode;
//	DWORD BaseOfData;
//	DWORD ImageBase;
//	DWORD SectionAlignment;
//	DWORD FileAlignment;
//	WORD MajorOperatingSystemVersion;
//	WORD MinorOperatingSystemVersion;
//	WORD MajorImageVersion;
//	WORD MinorImageVersion;
//	WORD MajorSubsystemVersion;
//	WORD MinorSubsystemVersion;
//	DWORD Reserved1;
//	DWORD SizeOfImage;
//	DWORD SizeOfHeaders;
//	DWORD CheckSum;
//	WORD Subsystem;
//	WORD DllCharacteristics;
//	DWORD SizeOfStackReserve;
//	DWORD SizeOfStackCommit;
//	DWORD SizeOfHeapReserve;
//	DWORD SizeOfHeapCommit;
//	DWORD LoaderFlags;
//	DWORD NumberOfRvaAndSizes;
//	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
//} IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;

//typedef struct _IMAGE_DATA_DIRECTORY
//{
//    DWORD VirtualAddress;
//    DWORD Size;
//} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

//typedef struct _IMAGE_IMPORT_DESCRIPTOR {
//	_ANONYMOUS_UNION union {
//		DWORD Characteristics;
//		DWORD OriginalFirstThunk;
//	} DUMMYUNIONNAME;
//	DWORD TimeDateStamp;
//	DWORD ForwarderChain;
//	DWORD Name;
//	DWORD FirstThunk;
//} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;

//typedef struct _IMAGE_SECTION_HEADER {
//	BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
//	union {
//		DWORD PhysicalAddress;
//		DWORD VirtualSize;
//	} Misc;
//	DWORD VirtualAddress;
//	DWORD SizeOfRawData;
//	DWORD PointerToRawData;
//	DWORD PointerToRelocations;
//	DWORD PointerToLinenumbers;
//	WORD NumberOfRelocations;
//	WORD NumberOfLinenumbers;
//	DWORD Characteristics;
//} IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;

int main(int argc, char * argv[])
{
  if(argc!=2)
    {
      fprintf(stdout,"Use of the program : %s peFileToAnalyze\n",argv[0]);
      return EXIT_FAILURE;
    }
  printf("\n----------------------------\n");
  printf("----| PE Reader by JoE |----\n");
  printf("----------------------------\n");
  
  // open the file
  FILE * peFile=fopen(argv[1],"r");
  CHECK_ERROR_NULL(peFile,"Error when opening the file");
  
  // get the dos header
  IMAGE_DOS_HEADER dosHeader;
  if(fread(&dosHeader,1,sizeof(dosHeader),peFile)<sizeof(dosHeader))
    {
      if(feof(peFile))
	{
	  printf("Error : end of the file reached\n");
	  return EXIT_FAILURE;
	}
      else
	{
	  printf("Error during the reading of the file\n");
	  return EXIT_FAILURE;
	}
    }
  
  displayDosHeader(dosHeader);
 
  // get the PE file header (IMAGE_NT_HEADERS) 
  CHECK_ERROR_LIBC(fseek(peFile,(long)dosHeader.e_lfanew, SEEK_SET),"Error during the seek"); 
 
  IMAGE_NT_HEADERS peHeader;
  if(fread(&peHeader,1,sizeof(peHeader),peFile)<sizeof(peHeader))
    {
      if(feof(peFile))
	{
	  printf("Error : end of the file reached\n");
	  return EXIT_FAILURE;
	}
      else
	{
	  printf("Error during the reading of the file\n");
	  return EXIT_FAILURE;
	}
    }
  
  displayPeFileHeader(peHeader);

  // get the sections
  IMAGE_SECTION_HEADER sections[numberOfSections];
  if(fread(&sections,1,sizeof(sections),peFile)<sizeof(sections))
    {
      if(feof(peFile))
	{
	  printf("Error : end of the file reached\n");
	  return EXIT_FAILURE;
	}
      else
	{
	  printf("Error during the reading of the file\n");
	  return EXIT_FAILURE;
	}
    }
  displaySections(sections,numberOfSections);

  
  CHECK_ERROR_EOF(fclose(peFile),"Error when closing the file");
  return EXIT_SUCCESS;
}

void displaySections(PIMAGE_SECTION_HEADER sections,int numberOfSections)
{
  int i;

  printf("\n---| SECTION TABLE |---\n\n");
  
  for(i=0;i<numberOfSections;i++)
    {
      printf(">Section %d <\n",i);
      printf(" Name                       : %s\n",sections[i].Name);
      printf(" VirtualSize                : 0x%08x\n",sections[i].Misc.VirtualSize);
      printf(" VirtualAddress             : 0x%08x\n",sections[i].VirtualAddress);
      printf(" Size of raw data           : 0x%08x\n",sections[i].SizeOfRawData);
      printf(" Pointer to raw data        : 0x%08x\n",sections[i].PointerToRawData);
      printf(" Pointer to relocations     : 0x%08x\n",sections[i].PointerToRelocations);
      printf(" Pointer to line numbers    : 0x%08x\n",sections[i].PointerToLinenumbers);
      printf(" Number of relocations      : 0x%04x\n",sections[i].NumberOfRelocations);
      printf(" Number of line numbers     : 0x%04x\n",sections[i].NumberOfLinenumbers);
      displaySectionCharacteristic(sections[i].Characteristics);
    }
}

void displaySectionCharacteristic(int characteristics)
{
  
  char output[50];
  memset(output,'\0',50);

  if(characteristics & 0x20)
    strcat(output,"CODE|");
  if(characteristics & 0x40)
    strcat(output,"INITIALIZED_DATA|");
  if(characteristics & 0x80)
    strcat(output,"UNINITIALIZED_DATA|");
  if(characteristics & 0x40000000)
    strcat(output,"READ|");
  if(characteristics & 0x80000000)
    strcat(output,"WRITE|");

  output[strlen(output)-1]='\0';
  printf(" Characteristics            : %s\n",output); 

}

void displayPeFileHeader(IMAGE_NT_HEADERS peHeader)
{
  printf("\n---| PE FILE HEADER |---\n\n");
  
  printf(" Signature : 0x%08x\n",peHeader.Signature);
  
  printf("\n  -- File Header --\n");
  ((peHeader.FileHeader.Machine==IMAGE_FILE_MACHINE_I386)?printf(" Machine              : IMAGE_FILE_MACHINE_I386 (0x%04x)\n",peHeader.FileHeader.Machine):printf(" Machine : 0x%04x\n",peHeader.FileHeader.Machine));
  printf(" Number of sections   : 0x%04x\n",peHeader.FileHeader.NumberOfSections);
  numberOfSections=peHeader.FileHeader.NumberOfSections;
  printf(" Time date stamp      : 0x%08x\n",peHeader.FileHeader.TimeDateStamp);
  printf(" PointerToSymbolTable : 0x%08x\n",peHeader.FileHeader.PointerToSymbolTable);
  printf(" NumberOfSymbols      : 0x%08x\n",peHeader.FileHeader.NumberOfSymbols);
  printf(" SizeOfOptionalHeader : 0x%04x\n",peHeader.FileHeader.SizeOfOptionalHeader);
  displayCharacteristics(peHeader.FileHeader.Characteristics);

  printf("\n -- Optional Header --\n");
  ((peHeader.OptionalHeader.Magic==0x10b)?  printf(" Magic                          : PE32bits\n"):printf(" Magic               : 0x%04x\n",peHeader.OptionalHeader.Magic));
  printf(" Major linker version           : 0x%02x\n",peHeader.OptionalHeader.MajorLinkerVersion);
  printf(" Minor linker version           : 0x%02x\n",peHeader.OptionalHeader.MinorLinkerVersion);
  printf(" Size of code                   : 0x%08x\n",peHeader.OptionalHeader.SizeOfCode);
  printf(" Size of initialized data       : 0x%08x\n",peHeader.OptionalHeader.SizeOfInitializedData);
  printf(" Size of uninitialized data     : 0x%08x\n",peHeader.OptionalHeader.SizeOfUninitializedData);
  printf(" Address of entry point         : 0x%08x\n",peHeader.OptionalHeader.AddressOfEntryPoint);
  printf(" Base of code                   : 0x%08x\n",peHeader.OptionalHeader.BaseOfCode);
  printf(" Base of data                   : 0x%08x\n",peHeader.OptionalHeader.BaseOfData);
  printf(" Image base                     : 0x%08x\n",peHeader.OptionalHeader.ImageBase);
  printf(" Section alignment              : 0x%08x\n",peHeader.OptionalHeader.SectionAlignment);
  printf(" File alignment                 : 0x%08x\n",peHeader.OptionalHeader.FileAlignment);
  printf(" Major operating system version : 0x%04x\n",peHeader.OptionalHeader.MajorOperatingSystemVersion);
  printf(" Minor operating system version : 0x%04x\n",peHeader.OptionalHeader.MinorOperatingSystemVersion);
  printf(" Major image version            : 0x%04x\n",peHeader.OptionalHeader.MajorImageVersion);
  printf(" Minor image version            : 0x%04x\n",peHeader.OptionalHeader.MinorImageVersion);
  printf(" Minor subsystem version        : 0x%04x\n",peHeader.OptionalHeader.MinorSubsystemVersion);
  printf(" Reserved1                      : 0x%08x\n",peHeader.OptionalHeader.Reserved1);
  printf(" Size of image                  : 0x%08x\n",peHeader.OptionalHeader.SizeOfImage);
  printf(" Size of headers                : 0x%08x\n",peHeader.OptionalHeader.SizeOfHeaders);
  printf(" CheckSum                       : 0x%08x\n",peHeader.OptionalHeader.CheckSum);
  displaySubsystem(peHeader.OptionalHeader.Subsystem);
  printf(" Dll characteristics            : 0x%04x\n",peHeader.OptionalHeader.DllCharacteristics);
  printf(" Size of stack reserve          : 0x%08x\n",peHeader.OptionalHeader.SizeOfStackReserve);
  printf(" Size of stack commit           : 0x%08x\n",peHeader.OptionalHeader.SizeOfStackCommit);
  printf(" Size of heap reserve           : 0x%08x\n",peHeader.OptionalHeader.SizeOfHeapReserve);
  printf(" Size of heap commit            : 0x%08x\n",peHeader.OptionalHeader.SizeOfHeapCommit);
  printf(" Loader flags                   : 0x%08x\n",peHeader.OptionalHeader.LoaderFlags);
  printf(" Number of rva and sizes        : 0x%08x\n",peHeader.OptionalHeader.NumberOfRvaAndSizes);
  displayDataDirectory(peHeader.OptionalHeader.DataDirectory);

}

void displayDataDirectory(PIMAGE_DATA_DIRECTORY dataDirectory)
{
 
  if(dataDirectory[0].Size!=0)
    {
      printf(" Export table address           : 0x%08x\n", dataDirectory[0].VirtualAddress);
      printf(" Export table size              : 0x%08x\n", dataDirectory[0].Size);
    }
      

  if(dataDirectory[1].Size!=0)
    {
      printf(" Import table address           : 0x%08x\n",dataDirectory[1].VirtualAddress);
      printf(" Import table size              : 0x%08x\n",dataDirectory[1].Size);
    }
  
} 

void displaySubsystem(int subsystem)
{

  printf(" Subsystem                      : ");
  switch(subsystem)
    {
    case 0:
      printf("IMAGE_SUBSYSTEM_UNKNOWN\n");
      break;
    case 1:
      printf("IMAGE_SUBSYSTEM_NATIVE\n");
      break;
    case 2:
      printf("IMAGE_SUBSYSTEM_WINDOWS_GUI\n");
      break;
    case 3:
      printf("IMAGE_SUBSYSTEM_WINDOWS_CUI\n");
      break;
    case 7:
      printf("IMAGE_SUBSYSTEM_POSIX_CUI\n");
      break;
    }
      
}

void displayCharacteristics(short characteristics)
{

  char output[50];
  memset(output,'\0',50);

  if(characteristics & 0x0001)
    strcat(output,"RELOCS_STRIPPED|");
  if(characteristics & 0x0002)
    strcat(output,"EXECUTABLE_IMAGE|");
  if(characteristics & 0x0004)
    strcat(output,"LINE_NUMS_STRIPPED|");
  if(characteristics & 0x0100)
    strcat(output,"32BIT_MACHINE|");
  if(characteristics & 0x0200)
    strcat(output,"DEBUG_STRIPPED|");
  if(characteristics & 0x1000)
    strcat(output,"FILE_SYSTEM|");
  if(characteristics & 0x2000)
    strcat(output,"FILE_DLL|");

  output[strlen(output)-1]='\0';
  printf(" Characteristics      : %s\n",output);

}


void displayDosHeader(IMAGE_DOS_HEADER dosHeader)
{
  
  printf("\n---| DOS HEADER |---\n\n");
  
  printf(" Magic Number                     : 0x%04x\n",dosHeader.e_magic);
  printf(" Bytes on last page of file       : 0x%04x\n",dosHeader.e_cblp);
  printf(" Pages in file                    : 0x%04x\n",dosHeader.e_cp);
  printf(" Relocations                      : 0x%04x\n",dosHeader.e_crlc);
  printf(" Size of header in paragraphs     : 0x%04x\n",dosHeader.e_cparhdr);
  printf(" Minimum extra paragraphs needed  : 0x%04x\n",dosHeader.e_minalloc);
  printf(" Maximum extra paragraphs needed  : 0x%04x\n",dosHeader.e_maxalloc);
  printf(" Initial (relative) SS value      : 0x%04x\n",dosHeader.e_ss);
  printf(" Initial SP value                 : 0x%04x\n",dosHeader.e_sp);
  printf(" Checksum                         : 0x%04x\n",dosHeader.e_csum);
  printf(" Initial IP value                 : 0x%04x\n",dosHeader.e_ip);
  printf(" Initial (relative) CS value      : 0x%04x\n",dosHeader.e_cs);
  printf(" File address of relocation table : 0x%04x\n",dosHeader.e_lfarlc);
  printf(" Overlay number                   : 0x%04x\n",dosHeader.e_ovno);
  ((dosHeader.e_res[4]!=0)?printf(" Reserved words                   : 0x%08x\n",dosHeader.e_res[4]):printf(""));
  ((dosHeader.e_oemid!=0)?printf(" OEM identifier                   : 0x%04x\n",dosHeader.e_oemid):printf(""));
  ((dosHeader.e_oeminfo!=0)?printf(" OEM information                  : 0x%04x\n",dosHeader.e_oeminfo):printf(""));
  ((dosHeader.e_res2[10]!=0)?printf(" Reserved words                   : 0x%020x\n",dosHeader.e_res2[10]):printf(""));
  printf(" File address of new exe header   : 0x%04x\n",dosHeader.e_lfanew);
     
}




