Identifies the architecture Windows PE (exe or dll) file was compiled C Program

How to write a C Program to Identifies the architecture for which a Windows PE (exe or dll) file was compiled in C Programming Language ?



Solution:
/*C Program to Identifies the architecture for which a Windows PE (exe or dll) file was compiled. */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>

void  displayProgramInfo();
char* extractFileName(char* filename);   // Returns pointer to filename in the passed string.
char* getArch(unsigned short int arch); // Returns a new string which must be deallocated by the caller.

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

const char FILE_SIGNATURE[2]      = { 0x4d, 0x5a };
const char PE_SIGNATURE[4]        = { 0x50, 0x45, 0x00, 0x00 };
const unsigned int PE_POINTER     = 0x3C;

displayProgramInfo();

if (argc < 2) {
printf(
"Identifies the architecture for which a Windows PE (exe or dll) file was compiled.\n"
"Please supply a filename via the command line.\n");
return 1;
}

char filename[strlen(argv[1])];
strcpy(filename, argv[1]);

FILE *ptr_pefile = fopen(filename, "rb");

if (!ptr_pefile) {
printf("Could not open file: \"%s\"\n", filename);
return 2;
}

unsigned char buffer[4];
unsigned int  offset_value;

// Get file signature
fseek(ptr_pefile, SEEK_SET, 0);
memset(buffer, 0, 4);
fread(buffer, 1, 2, ptr_pefile);

if (memcmp(buffer, FILE_SIGNATURE, 2) != 0) {
printf("Error: \"%s\" is not a valid PE file (file signature is invalid).\n", filename);
fclose(ptr_pefile);
return 3;
}

// Get PE signature pointer offset value
fseek(ptr_pefile, PE_POINTER, SEEK_SET);
offset_value = 0;
fread(&offset_value, 4, 1, ptr_pefile);

// Get PE signature
fseek(ptr_pefile, offset_value, SEEK_SET);
memset(buffer, 0, 4);
fread(&buffer, 1, 4, ptr_pefile);

if (memcmp(buffer, PE_SIGNATURE, 4) != 0) {
printf("Error: \"%s\" is not a valid PE file (PE signature is invalid).\n", filename);
fclose(ptr_pefile);
return 4;
}

// Get arch identifier (int) from current offset
offset_value = 0;
fread(&offset_value, 1, 2, ptr_pefile);

char* pArchStr = getArch(offset_value);

if (pArchStr[0] == 0) {
printf(
"Unrecognised machine type.\n"
"This executable is either corrupt or the file specification was revised "
"after this program was created.\n");
} else {
printf("%s was compiled for %s\n", extractFileName(filename), pArchStr);
}

free(pArchStr);

fclose(ptr_pefile);

return EXIT_SUCCESS;
}

void displayProgramInfo() {
static const char PROG_NAME[] = "ArchPE";
static const char PROG_VERS[] = "0.3";
static const char PROG_AUTH[] = "(c)2015 Walker Moore.";

printf("%s %s - %s\n\n", PROG_NAME, PROG_VERS, PROG_AUTH);
}

char* extractFileName(char* filename) {

size_t sz_filename = strlen(filename) + 1; // +1 to include null terminator in length
char *pEnd = &filename[sz_filename];

int i = 0;
while (*pEnd != 0x5c && i++ != sz_filename) {  // 0x5c is ASCII code for '\'
pEnd--;
}

return sz_filename == --i ? pEnd : pEnd + 1;
}

char* getArch(unsigned short int arch) {

char archStr[50];

switch (arch) {
case 0x14c:
strcpy(archStr, "Intel 386 or later, and compatibles (32bit)");
break;
case 0x14d:
strcpy(archStr, "Intel i860");
break;
case 0x162:
strcpy(archStr, "MIPS R3000");
break;
case 0x166:
strcpy(archStr, "MIPS little endian (R4000)");
break;
case 0x168:
strcpy(archStr, "MIPS R10000");
break;
case 0x169:
strcpy(archStr, "MIPS little endian WCI v2");
break;
case 0x183:
strcpy(archStr, "Alpha AXP (old)");
break;
case 0x184:
strcpy(archStr, "Alpha AXP");
break;
case 0x1a2:
strcpy(archStr, "Hitachi SH3");
break;
case 0x1a3:
strcpy(archStr, "Hitachi SH3 DSP");
break;
case 0x1a6:
strcpy(archStr, "Hitachi SH4");
break;
case 0x1a8:
strcpy(archStr, "Hitachi SH5");
break;
case 0x1c0:
strcpy(archStr, "ARM little endian");
break;
case 0x1c2:
strcpy(archStr, "Thumb");
break;
case 0x1d3:
strcpy(archStr, "Matsushita AM33");
break;
case 0x1f0:
strcpy(archStr, "PowerPC little endian");
break;
case 0x1f1:
strcpy(archStr, "PowerPC with floating point support");
break;
case 0x200:
strcpy(archStr, "Intel IA64");
break;
case 0x266:
strcpy(archStr, "MIPS16");
break;
case 0x268:
strcpy(archStr, "Motorola 68000 series");
break;
case 0x284:
strcpy(archStr, "Alpha AXP 64-bit");
break;
case 0x366:
strcpy(archStr, "MIPS with FPU");
break;
case 0x466:
strcpy(archStr, "MIPS16 with FPU");
break;
case 0xebc:
strcpy(archStr, "EFI Byte Code");
break;
case 0x8664:
strcpy(archStr, "AMD AMD64 (64bit)");
break;
case 0x9041:
strcpy(archStr, "Mitsubishi M32R little endian");
break;
case 0xc0ee:
strcpy(archStr, "clr pure MSIL");
break;
default:
strcpy(archStr, "");
break;
}

char *result = malloc(strlen(archStr) + 1);
strcpy(result, archStr);

return result;
}


Learn More :