Exploring the Structure of an EXE File

The code included below will prompt the user to specify a Windows .exe file, read the file, and then display the structure of its headers as XML.

To see the code in action, copy it into an .html file, open that file in a web browser that runs HTML5 and JavaScript, click the button, and select an .exe file to be analyzed. Note that it may be necessary to disable certain browser security features first.

The code was tested against notepad.exe, which on many Windows systems can be found in the “C:\Windows\” directory. Some of the fields are being displayed as negative numbers, when in fact they are probably meant to represent large positive numbers. This and other bugs should probably be fixed at some point.

<html>
<body>



// program

function ExeFileFormatTest()
{
	this.main = function()
	{
		new ExeFileLoader().initialize();
	}
}

// classes

function ExeFileLoader()
{
	// do nothing
}
{
	ExeFileLoader.prototype.initialize = function()
	{
		Globals.Instance.initialize(this);

		var inputFileChooser = document.createElement("input");
		inputFileChooser.type = "file";
		inputFileChooser.addEventListener("change", this.loadFileAndDisplay);
		document.body.appendChild(inputFileChooser);
	}

	ExeFileLoader.prototype.loadFileAndDisplay = function(event)
	{
		var fileSpecified = event.target.files[0];			   
		ExeFile.readFromFile(fileSpecified);
	}

	ExeFileLoader.prototype.loadFileAndDisplay_LoadComplete = function(exeFileLoaded)
	{
		var exeFileLoadedAsString = exeFileLoaded.toStringXML("    ", "", true);
		var pForDisplay = document.createElement("p");
		pForDisplay.innerHTML = exeFileLoadedAsString;
		document.body.appendChild(pForDisplay);	
	}
}

function ByteStreamLittleEndian(bytes)
{
	this.bytes = bytes;  

	this.numberOfBytesTotal = this.bytes.length;
	this.byteIndexCurrent = 0;
}
{
	var prototype = ByteStreamLittleEndian.prototype;

	prototype.peekBytes = function(numberOfBytesToRead)
	{
		var returnValue = [];

		for (var b = 0; b \n";

		var indentNext = indentSoFar + indentSingle;

		returnValue += this.mzSection.toStringXML(indentSingle, indentNext);
		returnValue += this.peSectionHeader.toStringXML(indentSingle, indentNext);
		returnValue += this.optionalHeader.toStringXML(indentSingle, indentNext);
		returnValue += this.virtualAddresses.toStringXML(indentSingle, indentNext);

		returnValue += indentNext + "\n";

		for (var i = 0; i \n";

		returnValue += indentSoFar + "\n";

		if (doEscapingForHTML == true)
		{
			returnValue = returnValue.split("").join(">");
			returnValue = returnValue.split(" ").join(" ");
			returnValue = returnValue.split("\n").join("
"); } return returnValue; } // inner classes function ExportDirectory ( characteristics, timeDateStamp, majorVersion, minorVersion, name, base, numberOfFunctions, numberOfNames, addressOfFunctions, addressOfNames, addressOfNameOrdinals ) { this.characteristics = characteristics; this.timeDateStamp = timeDateStamp; this.majorVersion = majorVersion; this.minorVersion = minorVersion; this.name = name; this.base = base; this.numberOfFunctions = numberOfFunctions; this.numberOfNames = numberOfNames; this.addressOfFunctions = addressOfFunctions; this.addressOfNames = addressOfNames; this.addressOfNameOrdinals = addressOfNameOrdinals; } function ImportDirectory ( originalFirstThunk, timeDateStamp, forwarderChain, name, firstThunk ) { this.originalFirstThunk = originalFirstThunk; this.timeDateStamp = timeDateStamp; this.forwarderChain = forwarderChain; this.name = name; this.firstThunk = firstThunk; } function MZSection ( mzStringAsBytes, numberOfBytesOnLastPageOfFile, numberOfPagesInFile, relocations, sizeOfHeaderInParagraphs, minimumExtraParagraphsNeeded, maximumExtraParagraphsNeeded, initialRelativeSSValue, initialSPValue, checksum, initialIPValue, initialRelativeCSValue, fileAddressOfRelocationTable, overlayNumber, reserved0, oemIdentifier, oemInformation, reserved1, addressOfPEHeader, bodyBytes ) { this.mzStringAsBytes = mzStringAsBytes; this.numberOfBytesOnLastPageOfFile = numberOfBytesOnLastPageOfFile; this.numberOfPagesInFile = numberOfPagesInFile; this.relocations = relocations; this.sizeOfHeaderInParagraphs = sizeOfHeaderInParagraphs; this.minimumExtraParagraphsNeeded = minimumExtraParagraphsNeeded; this.maximumExtraParagraphsNeeded = maximumExtraParagraphsNeeded; this.initialRelativeSSValue = initialRelativeSSValue; this.initialSPValue = initialSPValue; this.checksum = checksum; this.initialIPValue = initialIPValue; this.initialRelativeCSValue = initialRelativeCSValue; this.fileAddressOfRelocationTable = fileAddressOfRelocationTable; this.overlayNumber = overlayNumber; this.reserved0 = reserved0; this.oemIdentifier = oemIdentifier; this.oemInformation = oemInformation; this.reserved1 = reserved1; this.addressOfPEHeader = addressOfPEHeader; this.bodyBytes = bodyBytes; } { MZSection.prototype.toStringXML = function(indentSingle, indentSoFar) { var returnValue = indentSoFar + "\n" returnValue += indentSoFar + indentSingle + "" + this.bodyBytes + "\n" returnValue += indentSoFar + "\n"; return returnValue; } } function OptionalHeader ( magicNumber, majorLinkerVersion, minorLinkerVersion, sizeOfCode, sizeOfInitializedData, sizeOfUninitializedData, addressOfEntryPoint, baseOfCode, baseOfData, imageBase, sectionAlignment, fileAlignment, majorOSVersion, minorOSVersion, majorImageVersion, minorImageVersion, majorSubsystemVersion, minorSubsystemVersion, reserved, sizeOfImage, sizeOfHeaders, checksum, subsystem, dllCharacteristics, sizeOfStackReserve, sizeOfStackCommit, sizeOfHeapReserve, sizeOfHeapCommit, loaderFlags, numberOfRVAAndSizes ) { this.magicNumber = magicNumber; this.majorLinkerVersion = majorLinkerVersion; this.minorLinkerVersion = minorLinkerVersion; this.sizeOfCode = sizeOfCode; this.sizeOfUninitializedData = sizeOfUninitializedData; this.sizeOfInitializedData = sizeOfInitializedData; this.addressOfEntryPoint = addressOfEntryPoint; this.baseOfCode = baseOfCode; this.baseOfData = baseOfData; this.imageBase = imageBase; this.sectionAlignment = sectionAlignment; this.fileAlignment = fileAlignment; this.majorOSVersion = majorOSVersion; this.minorOSVersion = minorOSVersion; this.majorImageVersion = majorImageVersion; this.minorImageVersion = minorImageVersion; this.majorSubsystemVersion = majorSubsystemVersion; this.minorSubsystemVersion = minorSubsystemVersion; this.reserved = reserved; this.sizeOfImage = sizeOfImage; this.sizeOfHeaders = sizeOfHeaders; this.checksum = checksum; this.subsystem = subsystem; this.dllCharacteristics = dllCharacteristics; this.sizeOfStackReserve = sizeOfStackReserve; this.sizeOfStackCommit = sizeOfStackCommit; this.sizeOfHeapReserve = sizeOfHeapReserve; this.sizeOfHeapCommit = sizeOfHeapCommit; this.loaderFlags = loaderFlags; this.numberOfRVAAndSizes = numberOfRVAAndSizes; } { OptionalHeader.prototype.toStringXML = function(indentSingle, indentSoFar) { var returnValue = indentSoFar + " \n"; return returnValue; } } function PESectionHeader ( peStringAsBytes, machine, numberOfSections, timeDateStamp, pointerToSymbolTable, numberOfSymbols, sizeOfOptionalHeader, characteristics ) { this.peStringAsBytes = peStringAsBytes; this.machine = machine = machine; this.numberOfSections = numberOfSections; this.timeDateStamp = timeDateStamp; this.pointerToSymbolTable = pointerToSymbolTable; this.numberOfSymbols = numberOfSymbols; this.sizeOfOptionalHeader = sizeOfOptionalHeader; this.characteristics = characteristics; } { PESectionHeader.prototype.toStringXML = function(indentSingle, indentSoFar) { var returnValue = indentSoFar + ""; returnValue += indentSoFar + "\n"; return returnValue; } } function SectionHeader ( ansiName, misc, virtualAddress, sizeOfRawData, pointerToRawData, pointerToRelocations, pointerToLineNumbers, numberOfRelocations, numberOfLineNumbers, characteristics ) { this.ansiName = ansiName; this.misc = misc; this.virtualAddress = virtualAddress; this.sizeOfRawData = sizeOfRawData; this.pointerToRawData = pointerToRawData; this.pointerToRelocations = pointerToRelocations; this.pointerToLineNumbers = pointerToLineNumbers; this.numberOfRelocations = numberOfRelocations; this.numberOfLineNumbers = numberOfLineNumbers; this.characteristics = characteristics; } { // instance methods SectionHeader.prototype.toStringXML = function(indentSingle, indentSoFar) { var returnValue = indentSoFar + " " + "\n"; return returnValue; } // inner classes function Characteristics() { // flag bits for characteristics // 0x00000020 - contains code // 0x00000040 - contains initialized data // 0x00000080 - contains uninitialized data // 0x00000200 - contains comments // 0x02000000 - can be discarded // 0x10000000 - This section is shareable. // 0x20000000 - This section is executable. // 0x40000000 - This section is readable. // 0x80000000 - The section is writeable. } } function VirtualAddressAndSize(virtualAddress, size) { this.virtualAddress = virtualAddress; this.size = size; } { VirtualAddressAndSize.prototype.toStringXML = function() { var returnValue = this.virtualAddress + "," + this.size; return returnValue; } } function VirtualAddresses ( exportDirectory, importDirectory, resourceDirectory, exceptionDirectory, securityDirectory, baseRelocationTable, debugDirectory, architectureSpecificData, rvaOfGP, tlsDirectory, loadConfigurationDirectory, boundImportDirectory, importAddressTable, delayLoadImportDescriptors, comRuntimeDescriptor, zeroes ) { this.exportDirectory = exportDirectory; this.importDirectory = importDirectory; this.resourceDirectory = resourceDirectory; this.exceptionDirectory = exceptionDirectory; this.securityDirectory = securityDirectory; this.baseRelocationTable = baseRelocationTable; this.debugDirectory = debugDirectory; this.architectureSpecificData = architectureSpecificData; this.rvaOfGP = rvaOfGP; this.tlsDirectory = tlsDirectory; this.loadConfigurationDirectory = loadConfigurationDirectory; this.boundImportDirectory = boundImportDirectory; this.importAddressTable = importAddressTable; this.delayLoadImportDescriptors = delayLoadImportDescriptors; this.comRuntimeDescriptor = comRuntimeDescriptor; this.zeroes = zeroes; } { VirtualAddresses.prototype.toStringXML = function(indentSingle, indentSoFar) { var returnValue = indentSoFar + " " + "\n"; return returnValue; } } } // run new ExeFileFormatTest().main(); </body> </html>
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s