789 lines
34 KiB
C#
789 lines
34 KiB
C#
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using System.IO;
|
||
|
using System.Runtime.InteropServices;
|
||
|
|
||
|
namespace Bartok.MSIL
|
||
|
{
|
||
|
|
||
|
public class PELoader {
|
||
|
|
||
|
// Constructor Methods
|
||
|
|
||
|
public PELoader(Stream stream)
|
||
|
: this(stream, "<anonymous>")
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public PELoader(Stream stream, String path)
|
||
|
{
|
||
|
this.path = path;
|
||
|
this.stream = stream;
|
||
|
this.loadPEHeaders();
|
||
|
}
|
||
|
|
||
|
// Access Methods
|
||
|
|
||
|
internal Stream getStream() {
|
||
|
return this.stream;
|
||
|
}
|
||
|
|
||
|
internal int getEntryPoint() {
|
||
|
return this.comHeader.entryPointToken;
|
||
|
}
|
||
|
|
||
|
internal int getMetaDataOffset() {
|
||
|
return this.VaToOffset(this.comHeader.metaData.virtualAddress);
|
||
|
}
|
||
|
|
||
|
internal int getResourceOffset() {
|
||
|
return this.VaToOffsetSafe(this.comHeader.resources.virtualAddress);
|
||
|
}
|
||
|
|
||
|
internal int getRelocationOffset() {
|
||
|
int limit = ntHeader.numberOfSections;
|
||
|
for (int i = 0; i < limit; i++) {
|
||
|
SectionHeader section = this.sectionArray[i];
|
||
|
if (section.name.StartsWith(".reloc")) {
|
||
|
return this.VaToOffset(section.virtualAddress);
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
internal int getVtableFixupOffset() {
|
||
|
return this.VaToOffsetSafe(this.comHeader.vtableFixups.virtualAddress);
|
||
|
}
|
||
|
|
||
|
internal int getDelayIATOffset() {
|
||
|
return this.VaToOffsetSafe(this.ntHeader.dataDirectory[13].virtualAddress);
|
||
|
}
|
||
|
|
||
|
internal int getImageBase() {
|
||
|
return ntHeader.imageBase;
|
||
|
}
|
||
|
|
||
|
internal int getResourceSize() {
|
||
|
return this.comHeader.resources.size;
|
||
|
}
|
||
|
|
||
|
internal int getVtableFixupSize() {
|
||
|
return this.comHeader.vtableFixups.size;
|
||
|
}
|
||
|
|
||
|
internal int getDelayIATSize() {
|
||
|
return this.ntHeader.dataDirectory[13].size;
|
||
|
}
|
||
|
|
||
|
internal bool IsExecutableImage() {
|
||
|
return ((this.ntHeader.characteristics & NTHeader.IMAGE_FILE_EXECUTABLE_IMAGE) != 0) &&
|
||
|
((this.ntHeader.characteristics & NTHeader.IMAGE_FILE_DLL) == 0);
|
||
|
}
|
||
|
|
||
|
// Output Routines
|
||
|
|
||
|
internal void DumpHeader(StreamWriter outputStream) {
|
||
|
outputStream.WriteLine("// PE Header:");
|
||
|
outputStream.WriteLine();
|
||
|
this.ntHeader.DumpLimitedToStream(outputStream, "// ");
|
||
|
|
||
|
this.DumpIAT(outputStream, "Import directory", ref ntHeader.dataDirectory[1]);
|
||
|
// this.DumpIAT(outputStream, "Import Address Table", ref ntHeader.dataDirectory[12]);
|
||
|
// this.DumpIAT(outputStream, "Delay Load Import Address Table", ref ntHeader.dataDirectory[13]);
|
||
|
|
||
|
outputStream.WriteLine("// CLR Header:");
|
||
|
outputStream.WriteLine("// "+this.comHeader.cb.ToString("x8")+" Header size");
|
||
|
outputStream.WriteLine("// "+this.comHeader.majorRuntimeVersion.ToString("x8")+" Major runtime version");
|
||
|
outputStream.WriteLine("// "+this.comHeader.minorRuntimeVersion.ToString("x8")+" Minor runtime version");
|
||
|
outputStream.WriteLine("// "+this.comHeader.flags.ToString("x8")+" Flags");
|
||
|
outputStream.WriteLine("// "+this.comHeader.entryPointToken.ToString("x8")+" Entrypoint token");
|
||
|
outputStream.WriteLine("// "+this.comHeader.metaData.virtualAddress.ToString("x8")+" ["+this.comHeader.metaData.size.ToString("x8")+"] address [size] of Metadata directory");
|
||
|
outputStream.WriteLine("// "+this.comHeader.resources.virtualAddress.ToString("x8")+" ["+this.comHeader.resources.size.ToString("x8")+"] address [size] of Resources directory");
|
||
|
outputStream.WriteLine("// "+this.comHeader.strongNameSignature.virtualAddress.ToString("x8")+" ["+this.comHeader.strongNameSignature.size.ToString("x8")+"] address [size] of Strong name signature");
|
||
|
outputStream.WriteLine("// "+this.comHeader.codeManagerTable.virtualAddress.ToString("x8")+" ["+this.comHeader.codeManagerTable.size.ToString("x8")+"] address [size] of CodeManager table");
|
||
|
outputStream.WriteLine("// "+this.comHeader.vtableFixups.virtualAddress.ToString("x8")+" ["+this.comHeader.vtableFixups.size.ToString("x8")+"] address [size] of VTableFixups directory");
|
||
|
outputStream.WriteLine("// "+this.comHeader.exportAddressTableJumps.virtualAddress.ToString("x8")+" ["+this.comHeader.exportAddressTableJumps.size.ToString("x8")+"] address [size] of Export address table");
|
||
|
outputStream.WriteLine("// "+this.comHeader.managedNativeHeader.virtualAddress.ToString("x8")+" ["+this.comHeader.managedNativeHeader.size.ToString("x8")+"] address [size] of Precompile header");
|
||
|
}
|
||
|
|
||
|
internal void DumpCodeManager(StreamWriter outputStream) {
|
||
|
outputStream.WriteLine("// Code Manager Table");
|
||
|
if (this.comHeader.codeManagerTable.size == 0) {
|
||
|
outputStream.WriteLine("// default");
|
||
|
return;
|
||
|
}
|
||
|
// BUGBUG
|
||
|
throw new NotYetImplemented("DumpCodeManager");
|
||
|
}
|
||
|
|
||
|
internal void DumpVTables(StreamWriter outputStream) {
|
||
|
outputStream.WriteLine("// VTableFixup Directory:");
|
||
|
if (comHeader.vtableFixups.virtualAddress == 0) {
|
||
|
outputStream.WriteLine("// No data.");
|
||
|
return;
|
||
|
}
|
||
|
// BUGBUG
|
||
|
throw new NotYetImplemented("DumpVTables");
|
||
|
}
|
||
|
|
||
|
internal void DumpEATTable(StreamWriter outputStream) {
|
||
|
outputStream.WriteLine("// Export Address Table Jumps:");
|
||
|
if (comHeader.exportAddressTableJumps.virtualAddress == 0) {
|
||
|
outputStream.WriteLine("// No data.");
|
||
|
return;
|
||
|
}
|
||
|
// BUGBUG
|
||
|
throw new NotYetImplemented("DumpEATTable");
|
||
|
}
|
||
|
|
||
|
internal void DumpStatistics(StreamWriter outputStream) {
|
||
|
throw new NotYetImplemented("DumpStatistics");
|
||
|
}
|
||
|
|
||
|
public override String ToString() {
|
||
|
return "PELoader("+path+")";
|
||
|
}
|
||
|
|
||
|
// Private Helper Methods
|
||
|
|
||
|
private void loadPEHeaders() {
|
||
|
// Ensure that we are at the beginning of the stream.
|
||
|
this.stream.Seek(0L, SeekOrigin.Begin);
|
||
|
DOSHeader dosHeader = new DOSHeader(this.stream);
|
||
|
// Move on to the NT header
|
||
|
this.stream.Seek(dosHeader.lfanew, SeekOrigin.Begin);
|
||
|
BinaryReader reader = new BinaryReader(this.stream);
|
||
|
this.ntHeader = new NTHeader(reader);
|
||
|
// Load the sections
|
||
|
int sectionCount = ntHeader.numberOfSections;
|
||
|
SectionHeader[] sectionArray = new SectionHeader[sectionCount];
|
||
|
this.sectionArray = sectionArray;
|
||
|
for (int i = 0; i < sectionCount; i++) {
|
||
|
this.sectionArray[i] = new SectionHeader(reader);
|
||
|
int startAddr = sectionArray[i].virtualAddress;
|
||
|
int endAddr = sectionArray[i].virtualAddress+sectionArray[i].sizeOfRawData;
|
||
|
int delta = sectionArray[i].pointerToRawData-sectionArray[i].virtualAddress;
|
||
|
}
|
||
|
// Load the COM/COR20 header
|
||
|
DirectoryEntry entry =
|
||
|
this.ntHeader.dataDirectory[COMHeader.ENTRYINDEX];
|
||
|
int comOffset = this.VaToOffset(entry.virtualAddress);
|
||
|
this.stream.Seek(comOffset, SeekOrigin.Begin);
|
||
|
this.comHeader = new COMHeader(this.stream);
|
||
|
}
|
||
|
|
||
|
internal int VaToOffset(int virtualAddress) {
|
||
|
int limit = ntHeader.numberOfSections;
|
||
|
for (int i = 0; i < limit; i++) {
|
||
|
SectionHeader section = this.sectionArray[i];
|
||
|
if (virtualAddress >= section.virtualAddress &&
|
||
|
virtualAddress < (section.virtualAddress + section.sizeOfRawData)) {
|
||
|
return (virtualAddress -
|
||
|
section.virtualAddress +
|
||
|
section.pointerToRawData);
|
||
|
}
|
||
|
}
|
||
|
throw new IllegalPEFormatException("Unknown VA "+virtualAddress);
|
||
|
}
|
||
|
|
||
|
internal int VaToOffsetSafe(int virtualAddress) {
|
||
|
int limit = ntHeader.numberOfSections;
|
||
|
for (int i = 0; i < limit; i++) {
|
||
|
SectionHeader section = this.sectionArray[i];
|
||
|
if (virtualAddress >= section.virtualAddress &&
|
||
|
virtualAddress < (section.virtualAddress + section.sizeOfRawData)) {
|
||
|
return (virtualAddress -
|
||
|
section.virtualAddress +
|
||
|
section.pointerToRawData);
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
private void DumpIAT(StreamWriter outputStream,
|
||
|
String title,
|
||
|
ref DirectoryEntry entry) {
|
||
|
outputStream.WriteLine("// "+title);
|
||
|
if (entry.size == 0) {
|
||
|
outputStream.WriteLine("// No data.");
|
||
|
outputStream.WriteLine();
|
||
|
return;
|
||
|
}
|
||
|
if (entry.size < ImportDescriptor.SIZE) {
|
||
|
outputStream.WriteLine("Not enough data for IMAGE_IMPORT_DESCRIPTOR");
|
||
|
return;
|
||
|
}
|
||
|
int importOffset = this.VaToOffset(entry.virtualAddress);
|
||
|
while (true) {
|
||
|
this.stream.Seek(importOffset, SeekOrigin.Begin);
|
||
|
ImportDescriptor importDescriptor =
|
||
|
new ImportDescriptor(this.stream);
|
||
|
if (importDescriptor.firstChunk == 0) {
|
||
|
return;
|
||
|
}
|
||
|
String name = null;
|
||
|
if (importDescriptor.name != 0) {
|
||
|
int nameOffset = this.VaToOffset(importDescriptor.name);
|
||
|
name = this.readString(nameOffset);
|
||
|
}
|
||
|
outputStream.WriteLine("// "+name);
|
||
|
importDescriptor.DumpToStream(outputStream, "// ");
|
||
|
outputStream.WriteLine("//");
|
||
|
|
||
|
int importTableOffset =
|
||
|
this.VaToOffset(importDescriptor.firstChunk);
|
||
|
while (true) {
|
||
|
this.stream.Seek(importTableOffset, SeekOrigin.Begin);
|
||
|
BinaryReader intReader = new BinaryReader(this.stream);
|
||
|
int importTableID = intReader.ReadInt32();
|
||
|
if (importTableID == 0) break;
|
||
|
outputStream.WriteLine("importTableID is "+importTableID.ToString("x"));
|
||
|
outputStream.Flush();
|
||
|
int nameStringOffset =
|
||
|
this.VaToOffset(importTableID & 0x7fffffff);
|
||
|
this.stream.Seek(nameStringOffset, SeekOrigin.Begin);
|
||
|
intReader = new BinaryReader(this.stream);
|
||
|
if ((importTableID & 0x8000000) != 0) {
|
||
|
outputStream.WriteLine("// "+intReader.ReadInt16().ToString("x8")+" by ordinal "+(importTableID & 0x7ffffff));
|
||
|
}
|
||
|
else {
|
||
|
outputStream.WriteLine("// "+intReader.ReadInt16().ToString("x8")+" "+this.readString(nameStringOffset+2));
|
||
|
}
|
||
|
importTableOffset += 4;
|
||
|
}
|
||
|
outputStream.WriteLine();
|
||
|
importOffset += ImportDescriptor.SIZE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal Section[] loadSections() {
|
||
|
Section[] sections = new Section[sectionArray.Length];
|
||
|
for (int i = 0; i < sectionArray.Length; i++) {
|
||
|
Section section = new Section(sectionArray[i]);
|
||
|
section.LoadSection(this);
|
||
|
sections[i] = section;
|
||
|
}
|
||
|
return sections;
|
||
|
}
|
||
|
|
||
|
public String readString(int offset) {
|
||
|
this.stream.Seek(offset, SeekOrigin.Begin);
|
||
|
int length = 8;
|
||
|
int startIndex = 0;
|
||
|
byte[] buffer = new byte[length];
|
||
|
while (true) {
|
||
|
int count = this.stream.Read(buffer, startIndex,
|
||
|
length - startIndex);
|
||
|
if (count == 0) {
|
||
|
throw new Exception("Got 0 bytes from Read of file");
|
||
|
}
|
||
|
int limit = startIndex + count;
|
||
|
for (int i = startIndex; i < limit; i++) {
|
||
|
if (buffer[i] == 0) {
|
||
|
char[] chars = new char[i];
|
||
|
for (int j = 0; j < i; j++) {
|
||
|
chars[j] = (char) buffer[j];
|
||
|
}
|
||
|
return new String(chars);
|
||
|
}
|
||
|
}
|
||
|
byte[] newBuffer = new byte[2*length];
|
||
|
for (int i = 0; i < length; i++) {
|
||
|
newBuffer[i] = buffer[i];
|
||
|
}
|
||
|
length = 2*length;
|
||
|
startIndex += count;
|
||
|
buffer = newBuffer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Private State
|
||
|
|
||
|
private String path;
|
||
|
private Stream stream;
|
||
|
private NTHeader ntHeader;
|
||
|
private COMHeader comHeader;
|
||
|
private SectionHeader[] sectionArray;
|
||
|
|
||
|
// Nested classes
|
||
|
|
||
|
internal class DOSHeader {
|
||
|
// Corresponds to the WinNT IMAGE_DOS_HEADER data structure
|
||
|
|
||
|
// How to read from stream
|
||
|
|
||
|
internal DOSHeader(Stream stream):
|
||
|
this(new BinaryReader(stream))
|
||
|
{ }
|
||
|
|
||
|
internal DOSHeader(BinaryReader reader) {
|
||
|
// We could just read the magic and lfanew fields, but
|
||
|
// let's read everything for now
|
||
|
this.magic = reader.ReadInt16();
|
||
|
this.cblp = reader.ReadInt16();
|
||
|
this.cp = reader.ReadInt16();
|
||
|
this.crlc = reader.ReadInt16();
|
||
|
this.cparhdr = reader.ReadInt16();
|
||
|
this.minalloc = reader.ReadInt16();
|
||
|
this.maxalloc = reader.ReadInt16();
|
||
|
this.ss = reader.ReadInt16();
|
||
|
this.sp = reader.ReadInt16();
|
||
|
this.csum = reader.ReadInt16();
|
||
|
this.ip = reader.ReadInt16();
|
||
|
this.cs = reader.ReadInt16();
|
||
|
this.lfarlc = reader.ReadInt16();
|
||
|
this.ovno = reader.ReadInt16();
|
||
|
this.res_0 = reader.ReadInt16();
|
||
|
this.res_1 = reader.ReadInt16();
|
||
|
this.res_2 = reader.ReadInt16();
|
||
|
this.res_3 = reader.ReadInt16();
|
||
|
this.oemid = reader.ReadInt16();
|
||
|
this.oeminfo = reader.ReadInt16();
|
||
|
this.res2_0 = reader.ReadInt16();
|
||
|
this.res2_1 = reader.ReadInt16();
|
||
|
this.res2_2 = reader.ReadInt16();
|
||
|
this.res2_3 = reader.ReadInt16();
|
||
|
this.res2_4 = reader.ReadInt16();
|
||
|
this.res2_5 = reader.ReadInt16();
|
||
|
this.res2_6 = reader.ReadInt16();
|
||
|
this.res2_7 = reader.ReadInt16();
|
||
|
this.res2_8 = reader.ReadInt16();
|
||
|
this.res2_9 = reader.ReadInt16();
|
||
|
this.lfanew = reader.ReadInt32();
|
||
|
// Verify that we have a correct DOS header and a valid
|
||
|
// pointer to the NT header
|
||
|
if (this.magic != DOSHeader.IMAGE_DOS_SIGNATURE ||
|
||
|
this.lfanew <= 0) {
|
||
|
throw new IllegalPEFormatException("DOS header problems");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// State
|
||
|
|
||
|
internal short magic; // Magic number
|
||
|
internal short cblp; // Bytes on last page of file
|
||
|
internal short cp; // Pages in file
|
||
|
internal short crlc; // Relocations
|
||
|
internal short cparhdr; // Size of header in paragraphs
|
||
|
internal short minalloc; // Minimum extra paragraphs needed
|
||
|
internal short maxalloc; // Maximum extra paragraphs needed
|
||
|
internal short ss; // Initial (relative) SS value
|
||
|
internal short sp; // Initial SP value
|
||
|
internal short csum; // Checksum
|
||
|
internal short ip; // Initial IP value
|
||
|
internal short cs; // Initial (relative) CS value
|
||
|
internal short lfarlc; // File address of relocation table
|
||
|
internal short ovno; // Overlay number
|
||
|
internal short res_0; // Reserved words
|
||
|
internal short res_1;
|
||
|
internal short res_2;
|
||
|
internal short res_3;
|
||
|
internal short oemid; // OEM identifier (for e_oeminfo)
|
||
|
internal short oeminfo; // OEM information; e_oemid specific
|
||
|
internal short res2_0; // Reserved words
|
||
|
internal short res2_1;
|
||
|
internal short res2_2;
|
||
|
internal short res2_3;
|
||
|
internal short res2_4;
|
||
|
internal short res2_5;
|
||
|
internal short res2_6;
|
||
|
internal short res2_7;
|
||
|
internal short res2_8;
|
||
|
internal short res2_9;
|
||
|
internal int lfanew; // File address of new exe header
|
||
|
|
||
|
internal const short IMAGE_DOS_SIGNATURE = 0x5A4D;
|
||
|
}
|
||
|
|
||
|
internal class NTHeader {
|
||
|
// Corresponds to the WinNT IMAGE_NT_HEADERS data structure
|
||
|
|
||
|
// How to read from stream
|
||
|
|
||
|
internal NTHeader(Stream stream):
|
||
|
this(new BinaryReader(stream))
|
||
|
{ }
|
||
|
|
||
|
internal NTHeader(BinaryReader reader) {
|
||
|
// We could read a selection of these, but read every
|
||
|
// field for now.
|
||
|
this.signature = reader.ReadInt32();
|
||
|
this.machine = reader.ReadInt16();
|
||
|
this.numberOfSections = reader.ReadInt16();
|
||
|
this.timeDateStamp = reader.ReadInt32();
|
||
|
this.pointerToSymbolTable = reader.ReadInt32();
|
||
|
this.numberOfSymbols = reader.ReadInt32();
|
||
|
this.sizeOfOptionalHeader = reader.ReadInt16();
|
||
|
this.characteristics = reader.ReadInt16();
|
||
|
this.magic = reader.ReadInt16();
|
||
|
this.majorLinkerVersion = reader.ReadByte();
|
||
|
this.minorLinkerVersion = reader.ReadByte();
|
||
|
this.sizeOfCode = reader.ReadInt32();
|
||
|
this.sizeOfInitializedData = reader.ReadInt32();
|
||
|
this.sizeOfUninitializedData = reader.ReadInt32();
|
||
|
this.addressOfEntryPoint = reader.ReadInt32();
|
||
|
this.baseOfCode = reader.ReadInt32();
|
||
|
this.baseOfData = reader.ReadInt32();
|
||
|
this.imageBase = reader.ReadInt32();
|
||
|
this.sectionAlignment = reader.ReadInt32();
|
||
|
this.fileAlignment = reader.ReadInt32();
|
||
|
this.majorOperatingSystemVersion = reader.ReadInt16();
|
||
|
this.minorOperatingSystemVersion = reader.ReadInt16();
|
||
|
this.majorImageVersion = reader.ReadInt16();
|
||
|
this.minorImageVersion = reader.ReadInt16();
|
||
|
this.majorSubsystemVersion = reader.ReadInt16();
|
||
|
this.minorSubsystemVersion = reader.ReadInt16();
|
||
|
this.win32VersionValue = reader.ReadInt32();
|
||
|
this.sizeOfImage = reader.ReadInt32();
|
||
|
this.sizeOfHeaders = reader.ReadInt32();
|
||
|
this.checkSum = reader.ReadInt32();
|
||
|
this.subsystem = reader.ReadInt16();
|
||
|
this.dllCharacteristics = reader.ReadInt16();
|
||
|
this.sizeOfStackReserve = reader.ReadInt32();
|
||
|
this.sizeOfStackCommit = reader.ReadInt32();
|
||
|
this.sizeOfHeapReserve = reader.ReadInt32();
|
||
|
this.sizeOfHeapCommit = reader.ReadInt32();
|
||
|
this.loaderFlags = reader.ReadInt32();
|
||
|
int count = reader.ReadInt32();
|
||
|
this.numberOfRvaAndSizes = count;
|
||
|
DirectoryEntry[] directoryArray = new DirectoryEntry[count];
|
||
|
this.dataDirectory = directoryArray;
|
||
|
for (int i = 0; i < count; i++) {
|
||
|
directoryArray[i] = new DirectoryEntry(reader);
|
||
|
}
|
||
|
// Verify that we have a valid NT header
|
||
|
if (this.signature != NTHeader.IMAGE_NT_SIGNATURE ||
|
||
|
this.sizeOfOptionalHeader != NTHeader.IMAGE_SIZEOF_NT_OPTIONAL32_HEADER ||
|
||
|
this.magic != NTHeader.IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
|
||
|
this.numberOfRvaAndSizes != 16) {
|
||
|
throw new IllegalPEFormatException("NT header problems");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Output Routines
|
||
|
|
||
|
internal void DumpLimitedToStream(StreamWriter outputStream,
|
||
|
String prefix) {
|
||
|
outputStream.WriteLine(prefix+
|
||
|
"Subsystem: "+
|
||
|
this.subsystem.ToString("x8"));
|
||
|
outputStream.WriteLine(prefix+
|
||
|
"Native entry point address: "+
|
||
|
this.addressOfEntryPoint.ToString("x8"));
|
||
|
outputStream.WriteLine(prefix+
|
||
|
"Image base: "+
|
||
|
this.imageBase.ToString("x8"));
|
||
|
outputStream.WriteLine(prefix+
|
||
|
"Section alignment: "+
|
||
|
this.sectionAlignment.ToString("x8"));
|
||
|
outputStream.WriteLine(prefix+
|
||
|
"File alignment: "+
|
||
|
this.fileAlignment.ToString("x8"));
|
||
|
outputStream.WriteLine(prefix+
|
||
|
"Stack reserve size: "+
|
||
|
this.sizeOfStackReserve.ToString("x8"));
|
||
|
outputStream.WriteLine(prefix+
|
||
|
"Stack commit size: "+
|
||
|
this.sizeOfStackCommit.ToString("x8"));
|
||
|
outputStream.WriteLine(prefix+
|
||
|
"Directories: "+
|
||
|
this.numberOfRvaAndSizes.ToString("x8"));
|
||
|
String indentedPrefix = prefix+" ";
|
||
|
this.dataDirectory[0].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Export directory ");
|
||
|
this.dataDirectory[1].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Import directory");
|
||
|
this.dataDirectory[2].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Resource directory");
|
||
|
this.dataDirectory[3].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Exception directory");
|
||
|
this.dataDirectory[4].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Security directory");
|
||
|
this.dataDirectory[5].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Base Relocation Table");
|
||
|
this.dataDirectory[6].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Debug directory");
|
||
|
this.dataDirectory[7].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Architecture specific");
|
||
|
this.dataDirectory[8].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Global pointer directory");
|
||
|
this.dataDirectory[9].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of TLS directory ");
|
||
|
this.dataDirectory[10].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Load config directory");
|
||
|
this.dataDirectory[11].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Bound import directory");
|
||
|
this.dataDirectory[12].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Import Address Table");
|
||
|
this.dataDirectory[13].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of Delay Load IAT");
|
||
|
this.dataDirectory[14].DumpToStream(outputStream, indentedPrefix,
|
||
|
" of CLR Header");
|
||
|
}
|
||
|
|
||
|
// State
|
||
|
|
||
|
internal int signature;
|
||
|
// IMAGE_FILE_HEADER
|
||
|
internal short machine;
|
||
|
internal short numberOfSections;
|
||
|
internal int timeDateStamp;
|
||
|
internal int pointerToSymbolTable;
|
||
|
internal int numberOfSymbols;
|
||
|
internal short sizeOfOptionalHeader;
|
||
|
internal short characteristics;
|
||
|
// IMAGE_OPTIONAL_HEADER32
|
||
|
internal short magic;
|
||
|
internal Byte majorLinkerVersion;
|
||
|
internal Byte minorLinkerVersion;
|
||
|
internal int sizeOfCode;
|
||
|
internal int sizeOfInitializedData;
|
||
|
internal int sizeOfUninitializedData;
|
||
|
internal int addressOfEntryPoint;
|
||
|
internal int baseOfCode;
|
||
|
internal int baseOfData;
|
||
|
internal int imageBase;
|
||
|
internal int sectionAlignment;
|
||
|
internal int fileAlignment;
|
||
|
internal short majorOperatingSystemVersion;
|
||
|
internal short minorOperatingSystemVersion;
|
||
|
internal short majorImageVersion;
|
||
|
internal short minorImageVersion;
|
||
|
internal short majorSubsystemVersion;
|
||
|
internal short minorSubsystemVersion;
|
||
|
internal int win32VersionValue;
|
||
|
internal int sizeOfImage;
|
||
|
internal int sizeOfHeaders;
|
||
|
internal int checkSum;
|
||
|
internal short subsystem;
|
||
|
internal short dllCharacteristics;
|
||
|
internal int sizeOfStackReserve;
|
||
|
internal int sizeOfStackCommit;
|
||
|
internal int sizeOfHeapReserve;
|
||
|
internal int sizeOfHeapCommit;
|
||
|
internal int loaderFlags;
|
||
|
internal int numberOfRvaAndSizes;
|
||
|
// IMAGE_DATA_DIRECTORY
|
||
|
internal DirectoryEntry[] dataDirectory;
|
||
|
|
||
|
internal const int IMAGE_NT_SIGNATURE = 0x00004550; // PE00
|
||
|
internal const short IMAGE_SIZEOF_NT_OPTIONAL32_HEADER = 224;
|
||
|
internal const short IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x010b;
|
||
|
// File is executable (i.e. no unresolved external references).
|
||
|
internal const short IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
|
||
|
// File is a DLL.
|
||
|
internal const short IMAGE_FILE_DLL = 0x2000;
|
||
|
}
|
||
|
|
||
|
internal struct DirectoryEntry {
|
||
|
|
||
|
// How to create from a stream
|
||
|
|
||
|
internal DirectoryEntry(Stream stream):
|
||
|
this(new BinaryReader(stream))
|
||
|
{ }
|
||
|
|
||
|
internal DirectoryEntry(BinaryReader reader) {
|
||
|
this.virtualAddress = reader.ReadInt32();
|
||
|
this.size = reader.ReadInt32();
|
||
|
}
|
||
|
|
||
|
// Output Routines
|
||
|
|
||
|
internal void DumpToStream(StreamWriter outputStream,
|
||
|
String prefix,
|
||
|
String suffix) {
|
||
|
outputStream.WriteLine(prefix+
|
||
|
this.virtualAddress.ToString("x8")+
|
||
|
" ["+
|
||
|
this.size.ToString("x8")+
|
||
|
"] address [size]"+
|
||
|
suffix);
|
||
|
}
|
||
|
|
||
|
// State
|
||
|
|
||
|
internal int virtualAddress;
|
||
|
internal int size;
|
||
|
}
|
||
|
|
||
|
public class Section {
|
||
|
public Section(SectionHeader header) {
|
||
|
this.header = header;
|
||
|
}
|
||
|
|
||
|
public void LoadSection(PELoader peLoader) {
|
||
|
Stream fileStream = peLoader.getStream();
|
||
|
fileStream.Seek(peLoader.VaToOffset(header.virtualAddress), SeekOrigin.Begin);
|
||
|
BinaryReader reader = new BinaryReader(fileStream);
|
||
|
this.rawData = reader.ReadBytes(header.sizeOfRawData);
|
||
|
}
|
||
|
|
||
|
public SectionHeader header;
|
||
|
byte[] rawData;
|
||
|
}
|
||
|
|
||
|
public class SectionHeader {
|
||
|
|
||
|
// How to create from a stream
|
||
|
|
||
|
public SectionHeader(Stream stream):
|
||
|
this(new BinaryReader(stream))
|
||
|
{ }
|
||
|
|
||
|
public SectionHeader(BinaryReader reader) {
|
||
|
byte[] bytes = new byte[8];
|
||
|
reader.Read(bytes, 0, 8);
|
||
|
char[] chars = new char[8];
|
||
|
for (int j = 0; j < 8; j++) {
|
||
|
chars[j] = (char) bytes[j];
|
||
|
}
|
||
|
this.name = new String(chars);
|
||
|
this.virtualSize = reader.ReadInt32();
|
||
|
this.virtualAddress = reader.ReadInt32();
|
||
|
this.sizeOfRawData = reader.ReadInt32();
|
||
|
this.pointerToRawData = reader.ReadInt32();
|
||
|
this.pointerToRelocations = reader.ReadInt32();
|
||
|
this.pointerToLinenumbers = reader.ReadInt32();
|
||
|
this.numberOfRelocations = reader.ReadInt16();
|
||
|
this.numberOfLinenumbers = reader.ReadInt16();
|
||
|
this.characteristics = reader.ReadInt32();
|
||
|
}
|
||
|
|
||
|
// State
|
||
|
|
||
|
public String name;
|
||
|
public int virtualSize;
|
||
|
public int virtualAddress;
|
||
|
public int sizeOfRawData;
|
||
|
public int pointerToRawData;
|
||
|
public int pointerToRelocations;
|
||
|
public int pointerToLinenumbers;
|
||
|
public short numberOfRelocations;
|
||
|
public short numberOfLinenumbers;
|
||
|
public int characteristics;
|
||
|
}
|
||
|
|
||
|
internal class COMHeader {
|
||
|
// Corresponds to the WinNT IMAGE_COR20_HEADER data structure
|
||
|
|
||
|
// How to create from a stream
|
||
|
|
||
|
internal COMHeader(Stream stream):
|
||
|
this(new BinaryReader(stream))
|
||
|
{ }
|
||
|
|
||
|
internal COMHeader(BinaryReader reader) {
|
||
|
this.cb = reader.ReadInt32();
|
||
|
this.majorRuntimeVersion = reader.ReadInt16();
|
||
|
this.minorRuntimeVersion = reader.ReadInt16();
|
||
|
this.metaData = new DirectoryEntry(reader);
|
||
|
this.flags = reader.ReadInt32();
|
||
|
this.entryPointToken = reader.ReadInt32();
|
||
|
this.resources = new DirectoryEntry(reader);
|
||
|
this.strongNameSignature = new DirectoryEntry(reader);
|
||
|
this.codeManagerTable = new DirectoryEntry(reader);
|
||
|
this.vtableFixups = new DirectoryEntry(reader);
|
||
|
this.exportAddressTableJumps = new DirectoryEntry(reader);
|
||
|
this.managedNativeHeader = new DirectoryEntry(reader);
|
||
|
// Verify that we have a valid header
|
||
|
if (this.majorRuntimeVersion == 1 ||
|
||
|
this.majorRuntimeVersion > 2) {
|
||
|
throw new IllegalPEFormatException("COM header problems");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// State
|
||
|
|
||
|
// Header Versioning
|
||
|
internal int cb;
|
||
|
internal short majorRuntimeVersion;
|
||
|
internal short minorRuntimeVersion;
|
||
|
// Symbol table and startup information
|
||
|
internal DirectoryEntry metaData;
|
||
|
internal int flags;
|
||
|
internal int entryPointToken;
|
||
|
// Binding information
|
||
|
internal DirectoryEntry resources;
|
||
|
internal DirectoryEntry strongNameSignature;
|
||
|
// Regular fixup and binding information
|
||
|
internal DirectoryEntry codeManagerTable;
|
||
|
internal DirectoryEntry vtableFixups;
|
||
|
internal DirectoryEntry exportAddressTableJumps;
|
||
|
// Managed Native Code
|
||
|
internal DirectoryEntry managedNativeHeader;
|
||
|
|
||
|
// Index of the COM header in the array of directories
|
||
|
internal const int ENTRYINDEX = 14;
|
||
|
}
|
||
|
|
||
|
internal class ImportDescriptor {
|
||
|
|
||
|
// How to create from a stream
|
||
|
|
||
|
internal ImportDescriptor(Stream stream):
|
||
|
this(new BinaryReader(stream))
|
||
|
{ }
|
||
|
|
||
|
internal ImportDescriptor(BinaryReader reader) {
|
||
|
this.characteristics = reader.ReadInt32();
|
||
|
this.timeDateStamp = reader.ReadInt32();
|
||
|
this.forwarderChain = reader.ReadInt32();
|
||
|
this.name = reader.ReadInt32();
|
||
|
this.firstChunk = reader.ReadInt32();
|
||
|
}
|
||
|
|
||
|
internal void DumpToStream(StreamWriter outputStream, String prefix) {
|
||
|
outputStream.WriteLine(prefix+
|
||
|
this.firstChunk.ToString("x8")+
|
||
|
" Import Address Table");
|
||
|
outputStream.WriteLine(prefix+
|
||
|
this.name.ToString("x8")+
|
||
|
" Import Name Table");
|
||
|
outputStream.WriteLine(prefix+
|
||
|
this.timeDateStamp.ToString("x8")+
|
||
|
" time date stamp");
|
||
|
outputStream.WriteLine(prefix+
|
||
|
this.forwarderChain.ToString("x8")+
|
||
|
" index of first forwarder reference");
|
||
|
}
|
||
|
|
||
|
// State
|
||
|
|
||
|
internal int characteristics;
|
||
|
internal int timeDateStamp;
|
||
|
internal int forwarderChain;
|
||
|
internal int name;
|
||
|
internal int firstChunk;
|
||
|
|
||
|
// Size of this structure in stream
|
||
|
|
||
|
internal const int SIZE = 20;
|
||
|
}
|
||
|
|
||
|
internal class IllegalPEFormatException: Exception {
|
||
|
|
||
|
// Constructor Methods
|
||
|
|
||
|
internal IllegalPEFormatException(String reason):
|
||
|
base(reason)
|
||
|
{ }
|
||
|
|
||
|
}
|
||
|
|
||
|
internal class NotYetImplemented: Exception {
|
||
|
|
||
|
// Constructor Methods
|
||
|
|
||
|
internal NotYetImplemented(String reason):
|
||
|
base(reason)
|
||
|
{ }
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|