Added Microsoft executable format to main Executable plugin (since it is supported cross-platform by Wine)

This commit is contained in:
Michael Becker 2015-05-11 15:56:05 -04:00
parent e306842d6b
commit c807b7aaa5
12 changed files with 1094 additions and 0 deletions

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<!-- Associate the Chunked ObjectModel with the UXT DataFormats and the FileSystem Editor -->
<Filters>
<Filter Title="Microsoft executable">
<FileNameFilters>
<FileNameFilter>*.exe</FileNameFilter>
<FileNameFilter>*.com</FileNameFilter>
<FileNameFilter>*.dll</FileNameFilter>
<FileNameFilter>*.rll</FileNameFilter>
<FileNameFilter>*.fon</FileNameFilter>
<FileNameFilter>*.olb</FileNameFilter>
<FileNameFilter>*.tlb"</FileNameFilter>
</FileNameFilters>
<MagicByteSequences>
<MagicByteSequence>
<MagicByte Type="String">MZ</MagicByte>
</MagicByteSequence>
</MagicByteSequences>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Executable.ExecutableObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.Executable.Microsoft.MicrosoftExecutableDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -37,6 +37,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="Associations\Chunked.xml" />
<Content Include="Associations\Executable.xml" />
<Content Include="Associations\FormattedText.xml" />
<Content Include="Associations\Markup.xml" />
<Content Include="Associations\DataLink.xml" />

View File

@ -0,0 +1,76 @@
using System;
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
/// <summary>
/// Description of DOSExecutableHeader.
/// </summary>
public class DOSExecutableHeader
{
private bool mvarEnabled = true;
/// <summary>
/// Determines whether to write the 16-bit DOS executable header in the Microsoft executable file.
/// </summary>
public bool Enabled { get { return mvarEnabled; } set { mvarEnabled = value; } }
private ushort mvarLastBlockLength = 0;
public ushort LastBlockLength { get { return mvarLastBlockLength; } set { mvarLastBlockLength = value; } }
private ushort mvarNumBlocksInEXE = 0;
public ushort NumBlocksInEXE { get { return mvarNumBlocksInEXE; } set { mvarNumBlocksInEXE = value; } }
private ushort mvarNumRelocEntriesAfterHeader = 0;
public ushort NumRelocEntriesAfterHeader { get { return mvarNumRelocEntriesAfterHeader; } set { mvarNumRelocEntriesAfterHeader = value; } }
private ushort mvarNumParagraphsInHeader = 0;
public ushort NumParagraphsInHeader { get { return mvarNumParagraphsInHeader; } set { mvarNumParagraphsInHeader = value; } }
private ushort mvarNumParagraphsAdditionalMemory = 0;
public ushort NumParagraphsAdditionalMemory { get { return mvarNumParagraphsAdditionalMemory; } set { mvarNumParagraphsAdditionalMemory = value; } }
private ushort mvarNumMaxParagraphsAdditionalMemory = 0;
public ushort NumMaxParagraphsAdditionalMemory { get { return mvarNumMaxParagraphsAdditionalMemory; } set { mvarNumMaxParagraphsAdditionalMemory = value; } }
private ushort mvarRelativeStackSegmentValue = 0;
public ushort RelativeStackSegmentValue { get { return mvarRelativeStackSegmentValue; } set { mvarRelativeStackSegmentValue = value; } }
private ushort mvarInitialValueRegisterSP = 0;
public ushort InitialValueRegisterSP { get { return mvarInitialValueRegisterSP; } set { mvarInitialValueRegisterSP = value; } }
private ushort mvarWordChecksum = 0;
public ushort WordChecksum { get { return mvarWordChecksum; } set { mvarWordChecksum = value; } }
private ushort mvarInitialValueRegisterIP = 0;
public ushort InitialValueRegisterIP { get { return mvarInitialValueRegisterIP; } set { mvarInitialValueRegisterIP = value; } }
private ushort mvarInitialValueRegisterCS = 0;
public ushort InitialValueRegisterCS { get { return mvarInitialValueRegisterCS; } set { mvarInitialValueRegisterCS = value; } }
private ushort mvarFirstRelocationItemOffset = 0;
public ushort FirstRelocationItemOffset { get { return mvarFirstRelocationItemOffset; } set { mvarFirstRelocationItemOffset = value; } }
private ushort mvarOverlayNumber = 0;
public ushort OverlayNumber { get { return mvarOverlayNumber; } set { mvarOverlayNumber = value; } }
public long EXEDataStart
{
get
{
return (mvarNumParagraphsInHeader * 16L);
}
}
public long ExtraDataStart
{
get
{
long tmp = mvarNumBlocksInEXE * 512L;
if (mvarLastBlockLength > 0)
{
tmp -= (512 - mvarLastBlockLength);
}
return tmp;
}
}
}
}

View File

@ -0,0 +1,529 @@
// one line to give the program's name and an idea of what it does.
// Copyright (C) yyyy name of author
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
using System;
using UniversalEditor.Accessors;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.Executable;
using UniversalEditor.ObjectModels.FileSystem;
#if EXECUTABLE_LOAD_RESOURCES
using UniversalEditor.DataFormats.Resource.Microsoft;
using UniversalEditor.ObjectModels.Resource;
using UniversalEditor.ObjectModels.Resource.Blocks;
#endif
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
/// <summary>
/// Description of DOSExecutable.
/// </summary>
public class MicrosoftExecutableDataFormat : DataFormat
{
private DOSExecutableHeader mvarDOSHeader = new DOSExecutableHeader();
public DOSExecutableHeader DOSHeader { get { return mvarDOSHeader; } }
private NameValuePair<int>.NameValuePairCollection mvarImportTable = new NameValuePair<int>.NameValuePairCollection();
public NameValuePair<int>.NameValuePairCollection ImportTable { get { return mvarImportTable; } }
private System.Reflection.Assembly mvarCLRAssembly = null;
public System.Reflection.Assembly CLRAssembly { get { return mvarCLRAssembly; } }
private static DataFormatReference _dfr = null;
public override DataFormatReference MakeReference()
{
if (_dfr == null)
{
_dfr = base.MakeReference();
_dfr.Capabilities.Add(typeof(ExecutableObjectModel), DataFormatCapabilities.All);
// _dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
protected override void AfterLoadInternal(System.Collections.Generic.Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
FileAccessor fa = (base.Accessor as FileAccessor);
if (fa != null)
{
try
{
mvarCLRAssembly = System.Reflection.Assembly.LoadFile(fa.FileName);
}
catch (BadImageFormatException)
{
mvarCLRAssembly = null;
}
}
}
/*
C++ Name Mangling
Compiler void h(int) void h(int, char) void h(void)
Intel C++ 8.0 for Linux _Z1hi _Z1hic _Z1hv
HP aC++ A.05.55 IA-64 _Z1hi _Z1hic _Z1hv
IAR EWARM C++ 5.4 ARM _Z1hi _Z1hic _Z1hv
GCC 3.x and 4.x _Z1hi _Z1hic _Z1hv
GCC 2.9x h__Fi h__Fic h__Fv
HP aC++ A.03.45 PA-RISC h__Fi h__Fic h__Fv
Microsoft Visual C++ v6-v10 ?h@@YAXH@Z ?h@@YAXHD@Z ?h@@YAXXZ
Digital Mars C++ ?h@@YAXH@Z ?h@@YAXHD@Z ?h@@YAXXZ
Borland C++ v3.1 @h$qi @h$qizc @h$qv
OpenVMS C++ V6.5 (ARM mode) H__XI H__XIC H__XV
OpenVMS C++ V6.5 (ANSI mode) CXX$__7H__FI0ARG51T CXX$__7H__FIC26CDH77 CXX$__7H__FV2CB06E8
OpenVMS C++ X7.1 IA-64 CXX$_Z1HI2DSQ26A CXX$_Z1HIC2NP3LI4 CXX$_Z1HV0BCA19V
SunPro CC __1cBh6Fi_v_ __1cBh6Fic_v_ __1cBh6F_v_
Tru64 C++ V6.5 (ARM mode) h__Xi h__Xic h__Xv
Tru64 C++ V6.5 (ANSI mode) __7h__Fi __7h__Fic __7h__Fv
Watcom C++ 10.6 W?h$n(i)v W?h$n(ia)v W?h$n()v
*/
private string DecodeMangledName(string name, PECompiler compiler)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
switch (compiler)
{
case PECompiler.IntelCPP80Linux:
{
// _Z1hi _Z1hic _Z1hv
// void h(int) void h(int, char) void h(void)
string _Z1 = name.Substring(0, 2);
break;
}
case PECompiler.MsVCpp:
case PECompiler.DigitalMars:
{
// ?h@@YAXH@Z ?h@@YAXHD@Z ?h@@YAXXZ
// void h(int) void h(int, char) void h(void)
string prefix = name.Substring(0, 1); // ?
string funcName = name.Substring(1, name.IndexOf('@', 1) - 2); // h
string suffix = name.Substring(1 + funcName.Length, 4); // @@YA
//XH@Z
break;
}
}
return sb.ToString();
}
protected override void LoadInternal(ref ObjectModel objectModel)
{
Reader br = base.Accessor.Reader;
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
ExecutableObjectModel exec = (objectModel as ExecutableObjectModel);
if (fsom == null && exec == null) throw new ObjectModelNotSupportedException("Object model must be a FileSystem or an Executable");
ExecutableObjectModel exe = new ExecutableObjectModel();
#region DOS part
{
string signature = br.ReadFixedLengthString(2); // 0x4d, 0x5a. This is the "magic number" of an EXE file. The first byte of the file is 0x4d and the second is 0x5a.
if (signature != "MZ") throw new InvalidDataFormatException("File does not begin with \"MZ\"");
mvarDOSHeader.LastBlockLength = br.ReadUInt16(); // The number of bytes in the last block of the program that are actually used. If this value is zero, that means the entire last block is used (i.e. the effective value is 512).
mvarDOSHeader.NumBlocksInEXE = br.ReadUInt16(); // Number of blocks in the file that are part of the EXE file. If mvarDOSHeader.LastBlockLength is non-zero, only that much of the last block is used.
mvarDOSHeader.NumRelocEntriesAfterHeader = br.ReadUInt16(); // Number of relocation entries stored after the header. May be zero.
mvarDOSHeader.NumParagraphsInHeader = br.ReadUInt16(); // Number of paragraphs in the header. The program's data begins just after the header, and this field can be used to calculate the appropriate file offset. The header includes the relocation entries. Note that some OSs and/or programs may fail if the header is not a multiple of 512 bytes.
mvarDOSHeader.NumParagraphsAdditionalMemory = br.ReadUInt16(); // Number of paragraphs of additional memory that the program will need. This is the equivalent of the BSS size in a Unix program. The program can't be loaded if there isn't at least this much memory available to it.
mvarDOSHeader.NumMaxParagraphsAdditionalMemory = br.ReadUInt16(); // Maximum number of paragraphs of additional memory. Normally, the OS reserves all the remaining conventional memory for your program, but you can limit it with this field.
mvarDOSHeader.RelativeStackSegmentValue = br.ReadUInt16(); // Relative value of the stack segment. This value is added to the segment the program was loaded at, and the result is used to initialize the SS register.
mvarDOSHeader.InitialValueRegisterSP = br.ReadUInt16(); // Initial value of the SP register.
mvarDOSHeader.WordChecksum = br.ReadUInt16(); // Word checksum. If set properly, the 16-bit sum of all words in the file should be zero. Usually, this isn't filled in.
mvarDOSHeader.InitialValueRegisterIP = br.ReadUInt16(); // Initial value of the IP register.
mvarDOSHeader.InitialValueRegisterCS = br.ReadUInt16(); // Initial value of the CS register, relative to the segment the program was loaded at.
mvarDOSHeader.FirstRelocationItemOffset = br.ReadUInt16(); // Offset of the first relocation item in the file.
mvarDOSHeader.OverlayNumber = br.ReadUInt16(); // Overlay number. Normally zero, meaning that it's the main program.
}
#endregion
#region Portable Executable
{
br.Accessor.Position = 0x3C;
int e_lfanew = br.ReadInt32(); // offset to PE header
if (e_lfanew != 0)
{
br.Accessor.Position = e_lfanew;
#region PE header
PEHeader pe = new PEHeader();
pe.signature = br.ReadFixedLengthString(4);
if (pe.signature == "PE\0\0")
{
pe.enabled = true;
pe.machine = (PEMachineType)br.ReadUInt16();
pe.sectionCount = br.ReadInt16();
pe.unknown1 = br.ReadInt16();
pe.unknown2 = br.ReadInt16();
pe.unknown3 = br.ReadInt16();
pe.unknown4 = br.ReadInt16();
pe.unknown5 = br.ReadInt16();
pe.unknown6 = br.ReadInt16();
pe.sizeOfOptionalHeader = br.ReadInt16(); // relative offset to sectiontable
pe.characteristics = (PECharacteristics)br.ReadUInt16();
exe.TargetMachineType = (ExecutableMachine)pe.machine;
exe.Characteristics = (ExecutableCharacteristics)pe.characteristics;
}
else
{
pe.enabled = false;
br.Accessor.Position -= 4;
}
#endregion
#region Optional Header
PEOptionalHeader peoh = new PEOptionalHeader();
if (pe.sizeOfOptionalHeader > 0)
{
// offset: 0x58
peoh.enabled = true;
peoh.magic = br.ReadUInt16();
peoh.unknown1 = br.ReadUInt16();
peoh.unknown2 = br.ReadUInt32();
peoh.unknown3 = br.ReadUInt32();
peoh.unknown4 = br.ReadUInt32();
peoh.entryPointAddr = br.ReadUInt32();
peoh.unknown5 = br.ReadUInt32();
peoh.unknown6 = br.ReadUInt32();
peoh.imageBase = br.ReadUInt32();
peoh.sectionAlignment = br.ReadUInt32();
peoh.fileAlignment = br.ReadUInt32();
peoh.unknown7 = br.ReadUInt32();
peoh.unknown8 = br.ReadUInt32();
peoh.majorSubsystemVersion = br.ReadUInt16(); // 4 = NT 4 or later
peoh.unknown9 = br.ReadUInt16();
peoh.unknown10 = br.ReadUInt32();
peoh.imageSize = br.ReadUInt32();
peoh.headerSize = br.ReadUInt32();
peoh.unknown11 = br.ReadUInt32();
peoh.subsystem = br.ReadUInt16();
peoh.unknown12 = br.ReadUInt16();
peoh.unknown13 = br.ReadUInt32();
peoh.unknown14 = br.ReadUInt32();
peoh.unknown15 = br.ReadUInt32();
peoh.unknown16 = br.ReadUInt32();
peoh.unknown17 = br.ReadUInt32();
peoh.rvaCount = br.ReadUInt32();
}
else
{
peoh.enabled = false;
}
#endregion
#region Data Directories
{
for (int i = 0; i < peoh.rvaCount; i++)
{
uint rva = br.ReadUInt32();
}
}
#endregion
#region Sections Table
{
// offset: 0x138
br.Accessor.Seek(64, SeekOrigin.Current);
uint lastRawDataPtr = 0;
for (short i = 0; i < pe.sectionCount; i++)
{
PESectionHeader pesh = new PESectionHeader();
pesh.name = br.ReadFixedLengthString(8).TrimNull();
pesh.virtualSize = br.ReadUInt32();
pesh.virtualAddress = br.ReadUInt32();
pesh.rawDataSize = br.ReadUInt32();
pesh.rawDataPtr = br.ReadUInt32();
pesh.unknown1 = br.ReadUInt32();
pesh.unknown2 = br.ReadUInt32();
pesh.unknown3 = br.ReadUInt32();
pesh.characteristics = (PESectionCharacteristics)br.ReadUInt32();
if (fsom != null)
{
File file = new File();
file.Name = pesh.name;
file.Properties.Add("reader", br);
file.Properties.Add("offset", pesh.rawDataPtr);
file.Properties.Add("length", pesh.rawDataSize);
file.Size = pesh.rawDataSize;
file.DataRequest += file_DataRequest;
fsom.Files.Add(file);
}
ExecutableSection sect = new ExecutableSection();
sect.Name = pesh.name;
// sect.DataRequest += sect_DataRequest;
sect.VirtualSize = pesh.virtualSize;
sect.VirtualAddress = pesh.virtualAddress;
sect.PhysicalAddress = pesh.rawDataPtr;
sect.Characteristics = (ExecutableSectionCharacteristics)pesh.characteristics;
long ofs = br.Accessor.Position;
br.Accessor.Position = pesh.rawDataPtr;
sect.Data = br.ReadBytes(pesh.rawDataSize);
br.Accessor.Position = ofs;
exe.Sections.Add(sect);
}
}
#endregion
}
else
{
#region New Executable
// not a PE file, try NE?
br.Accessor.Position = 128;
string NE = br.ReadFixedLengthString(2);
if (NE == "NE")
{
byte MajLinkerVersion = br.ReadByte(); ; //The major linker version
byte MinLinkerVersion = br.ReadByte(); //The minor linker version
ushort EntryTableOffset = br.ReadUInt16(); //Offset of entry table, see below
ushort EntryTableLength = br.ReadUInt16(); //Length of entry table in bytes
uint FileLoadCRC = br.ReadUInt32(); //UNKNOWN - PLEASE ADD INFO
byte ProgFlags = br.ReadByte(); //Program flags, bitmapped
byte ApplFlags = br.ReadByte(); //Application flags, bitmapped
byte AutoDataSegIndex = br.ReadByte(); //The automatic data segment index
ushort InitHeapSize = br.ReadUInt16(); //The intial local heap size
ushort InitStackSize = br.ReadUInt16(); //The inital stack size
uint EntryPoint = br.ReadUInt32(); //CS:IP entry point, CS is index into segment table
uint InitStack = br.ReadUInt32(); //SS:SP inital stack pointer, SS is index into segment table
ushort SegCount = br.ReadUInt16(); //Number of segments in segment table
ushort ModRefs = br.ReadUInt16(); //Number of module references (DLLs)
ushort NoResNamesTabSiz = br.ReadUInt16(); //Size of non-resident names table, in bytes (Please clarify non-resident names table)
ushort SegTableOffset = br.ReadUInt16(); //Offset of Segment table
ushort ResTableOffset = br.ReadUInt16(); //Offset of resources table
ushort ResidNamTable = br.ReadUInt16(); //Offset of resident names table
ushort ModRefTable = br.ReadUInt16(); //Offset of module reference table
ushort ImportNameTable = br.ReadUInt16(); //Offset of imported names table (array of counted strings, terminated with string of length 00h)
uint OffStartNonResTab = br.ReadUInt32(); //Offset from start of file to non-resident names table
ushort MovEntryCount = br.ReadUInt16(); //Count of moveable entry point listed in entry table
ushort FileAlnSzShftCnt = br.ReadUInt16(); //File alligbment size shift count (0=9(default 512 byte pages))
ushort nResTabEntries = br.ReadUInt16(); //Number of resource table entries
byte targOS = br.ReadByte(); //Target OS
byte OS2EXEFlags = br.ReadByte(); //Other OS/2 flags
ushort retThunkOffset = br.ReadUInt16(); //Offset to return thunks or start of gangload area - what is gangload?
ushort segrefthunksoff = br.ReadUInt16(); //Offset to segment reference thunks or size of gangload area
ushort mincodeswap = br.ReadUInt16(); //Minimum code swap area size
byte expctwinver_min = br.ReadByte(); //Expected windows version (minor)
byte expctwinver_maj = br.ReadByte(); //Expected windows version (major)
}
#endregion
}
}
#endregion
#if EXECUTABLE_LOAD_RESOURCES
#region Resources
{
ExecutableSection sectRSRC = exe.Sections[".rsrc"];
if (sectRSRC != null)
{
byte[] rsrc_data = sectRSRC.Data;
ResourceObjectModel resources = new ResourceObjectModel();
Win32EmbeddedResourceDataFormat rsrc = new Win32EmbeddedResourceDataFormat();
rsrc.AddressOffset = sectRSRC.VirtualAddress;
FileAccessor fa = new FileAccessor(resources, rsrc);
fa.Open(ref rsrc_data);
fa.Load();
fa.Close();
if (fsom != null)
{
Folder fldrResources = fsom.Folders.Add("Resources");
foreach (ResourceBlock block in resources.Blocks)
{
RecursiveLoadResourceBlock(block, fldrResources);
}
}
#region Version Information
{
// find the VS_VERSION_INFO resource
DirectoryResourceBlock drbVersion = (resources.Blocks["Version"] as DirectoryResourceBlock);
if (drbVersion != null)
{
DirectoryResourceBlock drb1 = (drbVersion.Blocks[0] as DirectoryResourceBlock);
ContentResourceBlock crb = (drb1.Blocks[0] as ContentResourceBlock);
ObjectModels.Version.VersionObjectModel ver = new ObjectModels.Version.VersionObjectModel();
Version.Microsoft.Win32VersionDataFormat vs_version_info = new Version.Microsoft.Win32VersionDataFormat();
FileAccessor fa_ver = new FileAccessor(ver, vs_version_info);
byte[] ver_data = crb.Data;
fa_ver.Open(ref ver_data);
fa_ver.Load();
fa_ver.Close();
}
}
#endregion
}
}
#endregion
#endif
#region Push out Executable to the ObjectModel
{
if (exec != null)
{
exe.CopyTo(exec);
}
else if (fsom != null)
{
// don't do this again
/*
foreach (ExecutableSection sect in exe.Sections)
{
fsom.Files.Add(sect.Name, sect.Data);
}
*/
}
}
#endregion
}
#if EXECUTABLE_LOAD_RESOURCES
private void RecursiveLoadResourceBlock(ResourceBlock block, Folder parent)
{
if (block is UniversalEditor.ObjectModels.Resource.Blocks.DirectoryResourceBlock)
{
UniversalEditor.ObjectModels.Resource.Blocks.DirectoryResourceBlock dir = (block as UniversalEditor.ObjectModels.Resource.Blocks.DirectoryResourceBlock);
Folder fldr1 = parent.Folders.Add(dir.Name);
foreach (ResourceBlock block1 in dir.Blocks)
{
RecursiveLoadResourceBlock(block1, fldr1);
}
}
else if (block is UniversalEditor.ObjectModels.Resource.Blocks.ContentResourceBlock)
{
UniversalEditor.ObjectModels.Resource.Blocks.ContentResourceBlock crb = (block as UniversalEditor.ObjectModels.Resource.Blocks.ContentResourceBlock);
File file = parent.Files.Add(crb.Name, crb.Data);
}
}
#endif
private void file_DataRequest(object sender, DataRequestEventArgs e)
{
File file = (sender as File);
Reader br = (Reader)(file.Properties["reader"]);
uint offset = (uint)(file.Properties["offset"]);
uint length = (uint)(file.Properties["length"]);
br.Accessor.Position = offset;
e.Data = br.ReadBytes(length);
}
protected override void SaveInternal(ObjectModel objectModel)
{
Writer bw = base.Accessor.Writer;
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
ExecutableObjectModel exe = (objectModel as ExecutableObjectModel);
if (fsom == null && exe == null) throw new ObjectModelNotSupportedException("Object model must be a FileSystem or an Executable");
#region DOS part
bw.WriteFixedLengthString("MZ");
bw.WriteUInt16(mvarDOSHeader.LastBlockLength); // The number of bytes in the last block of the program that are actually used. If this value is zero, that means the entire last block is used (i.e. the effective value is 512).
bw.WriteUInt16(mvarDOSHeader.NumBlocksInEXE); // Number of blocks in the file that are part of the EXE file. If mvarDOSHeader.LastBlockLength is non-zero, only that much of the last block is used.
bw.WriteUInt16(mvarDOSHeader.NumRelocEntriesAfterHeader); // Number of relocation entries stored after the header. May be zero.
bw.WriteUInt16(mvarDOSHeader.NumParagraphsInHeader); // Number of paragraphs in the header. The program's data begins just after the header, and this field can be used to calculate the appropriate file offset. The header includes the relocation entries. Note that some OSs and/or programs may fail if the header is not a multiple of 512 bytes.
bw.WriteUInt16(mvarDOSHeader.NumParagraphsAdditionalMemory); // Number of paragraphs of additional memory that the program will need. This is the equivalent of the BSS size in a Unix program. The program can't be loaded if there isn't at least this much memory available to it.
bw.WriteUInt16(mvarDOSHeader.NumMaxParagraphsAdditionalMemory); // Maximum number of paragraphs of additional memory. Normally, the OS reserves all the remaining conventional memory for your program, but you can limit it with this field.
bw.WriteUInt16(mvarDOSHeader.RelativeStackSegmentValue); // Relative value of the stack segment. This value is added to the segment the program was loaded at, and the result is used to initialize the SS register.
bw.WriteUInt16(mvarDOSHeader.InitialValueRegisterSP); // Initial value of the SP register.
bw.WriteUInt16(mvarDOSHeader.WordChecksum); // Word checksum. If set properly, the 16-bit sum of all words in the file should be zero. Usually, this isn't filled in.
bw.WriteUInt16(mvarDOSHeader.InitialValueRegisterIP); // Initial value of the IP register.
bw.WriteUInt16(mvarDOSHeader.InitialValueRegisterCS); // Initial value of the CS register, relative to the segment the program was loaded at.
bw.WriteUInt16(mvarDOSHeader.FirstRelocationItemOffset); // Offset of the first relocation item in the file.
bw.WriteUInt16(mvarDOSHeader.OverlayNumber); // Overlay number. Normally zero, meaning that it's the main program.
#endregion
#region Portable Executable
bw.Accessor.Position = 0x3C;
int e_lfanew = (int)(bw.Accessor.Position + 4);
bw.WriteInt32(e_lfanew);
#region PE header
PEHeader pe = new PEHeader();
pe.signature = "PE\0\0";
pe.sectionCount = (short)fsom.Files.Count;
bw.WriteFixedLengthString(pe.signature);
bw.WriteUInt16((ushort)pe.machine);
bw.WriteUInt16((ushort)pe.sectionCount);
bw.WriteUInt16((ushort)pe.unknown1);
bw.WriteUInt16((ushort)pe.unknown2);
bw.WriteUInt16((ushort)pe.unknown3);
bw.WriteUInt16((ushort)pe.unknown4);
bw.WriteUInt16((ushort)pe.unknown5);
bw.WriteUInt16((ushort)pe.unknown6);
bw.WriteUInt16((ushort)pe.sizeOfOptionalHeader); // relative offset to sectiontable
bw.WriteUInt16((ushort)pe.characteristics);
#endregion
#region PE Optional Header
PEOptionalHeader peoh = new PEOptionalHeader();
peoh.enabled = true;
peoh.magic = 267;
peoh.entryPointAddr = 4096;
peoh.imageBase = 4194304;
peoh.sectionAlignment = 4096;
peoh.fileAlignment = 512;
peoh.majorSubsystemVersion = 4;
peoh.imageSize = 16384;
peoh.headerSize = 512;
peoh.subsystem = 2;
peoh.rvaCount = 16;
if (peoh.enabled)
{
bw.WriteUInt16((ushort)peoh.magic);
bw.WriteUInt16((ushort)peoh.unknown1);
bw.WriteUInt32((uint)peoh.unknown2);
bw.WriteUInt32((uint)peoh.unknown3);
bw.WriteUInt32((uint)peoh.unknown4);
bw.WriteUInt32((uint)peoh.entryPointAddr);
bw.WriteUInt32((uint)peoh.unknown5);
bw.WriteUInt32((uint)peoh.unknown6);
bw.WriteUInt32((uint)peoh.imageBase);
bw.WriteUInt32((uint)peoh.sectionAlignment);
bw.WriteUInt32((uint)peoh.fileAlignment);
bw.WriteUInt32((uint)peoh.unknown7);
bw.WriteUInt32((uint)peoh.unknown8);
bw.WriteUInt32((uint)peoh.majorSubsystemVersion); // 4 = NT 4 or later
bw.WriteUInt32((uint)peoh.unknown9);
bw.WriteUInt32((uint)peoh.unknown10);
bw.WriteUInt32((uint)peoh.imageSize);
bw.WriteUInt32((uint)peoh.headerSize);
bw.WriteUInt32((uint)peoh.unknown11);
bw.WriteUInt16((ushort)peoh.subsystem);
bw.WriteUInt16((ushort)peoh.unknown12);
bw.WriteUInt32((uint)peoh.unknown13);
bw.WriteUInt32((uint)peoh.unknown14);
bw.WriteUInt32((uint)peoh.unknown15);
bw.WriteUInt32((uint)peoh.unknown16);
bw.WriteUInt32((uint)peoh.unknown17);
bw.WriteUInt32((uint)peoh.rvaCount);
}
#endregion
#endregion
}
}
}

View File

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
/// <summary>
/// A set of bit flags indicating attributes of the file.
/// </summary>
[Flags()]
public enum PECharacteristics : ushort
{
/// <summary>
/// No characteristics defined.
/// </summary>
None = 0,
/// <summary>
/// Relocation information stripped from a file.
/// </summary>
RelocationInformationStripped = 0x0001,
/// <summary>
/// The file is executable.
/// </summary>
ExecutableImage = 0x0002,
/// <summary>
/// Line numbers stripped from file.
/// </summary>
LineNumbersStripped = 0x0004,
/// <summary>
/// Local symbols stripped from file.
/// </summary>
LocalSymbolsStripped = 0x0008,
/// <summary>
/// Lets the OS aggressively trim the working set.
/// </summary>
AggressiveWorkingSetTrim = 0x0010,
/// <summary>
/// Lets the OS aggressively trim the working set.
/// </summary>
MinimalObject = 0x0010,
/// <summary>
/// The application can handle addresses greater than two gigabytes.
/// </summary>
UpdateObject = 0x0020,
/// <summary>
/// The application can handle addresses greater than two gigabytes.
/// </summary>
LargeAddressAware = 0x0020,
/// <summary>
/// This requires a 32-bit word machine.
/// </summary>
Require32BitWord = 0x0100,
/// <summary>
/// Debug information is stripped to a .DBG file.
/// </summary>
DebugStripped = 0x0200,
/// <summary>
/// If the image is on removable media, copy to and run from the swap file.
/// </summary>
RemovableRunFromSwap = 0x0400,
/// <summary>
/// If the image is on a network, copy to and run from the swap file.
/// </summary>
NetworkRunFromSwap = 0x0800,
/// <summary>
/// File is a system file.
/// </summary>
IsSystemFile = 0x1000,
/// <summary>
/// File is a DLL.
/// </summary>
IsDynamicLinkLibrary = 0x2000,
/// <summary>
/// The file should only be run on single-processor machines.
/// </summary>
UniprocessorOnly = 0x4000,
/// <summary>
/// Bytes of machine word are reversed
/// </summary>
ReverseByteOrder = 0x8000
}
}

View File

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
public enum PECompiler
{
/// <summary>
/// Intel C++ 8.0 for Linux
/// </summary>
IntelCPP80Linux,
/// <summary>
/// HP aC++ A.05.55 IA-64
/// </summary>
HPaCppIA64,
/// <summary>
/// IAR EWARM C++ 5.4 ARM
/// </summary>
IAREwarmCPP54ARM,
/// <summary>
/// GCC 3.x and 4.x
/// </summary>
GCC3or4x,
/// <summary>
/// GCC 2.9x
/// </summary>
GCC29x,
/// <summary>
/// HP aC++ A.03.45 PA-RISC
/// </summary>
HPaCppPARISC,
/// <summary>
/// Microsoft Visual C++ v6-v10
/// </summary>
MsVCpp,
/// <summary>
/// Digital Mars C++
/// </summary>
DigitalMars,
/// <summary>
/// Borland C++ v3.1
/// </summary>
Borland31,
/// <summary>
/// OpenVMS C++ V6.5 (ARM mode)
/// </summary>
OpenVMS65ARM,
/// <summary>
/// OpenVMS C++ V6.5 (ANSI mode)
/// </summary>
OpenVMS65ANSI,
/// <summary>
/// OpenVMS C++ X7.1 IA-64
/// </summary>
OpenVMS71IA64,
/// <summary>
/// SunPro CC
/// </summary>
SunProCC,
/// <summary>
/// Tru64 C++ V6.5 (ARM mode)
/// </summary>
Tru64ARM,
/// <summary>
/// Tru64 C++ V6.5 (ANSI mode)
/// </summary>
Tru64ANSI,
/// <summary>
/// Watcom C++ 10.6
/// </summary>
Watcom
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
public struct PEHeader
{
public bool enabled;
public string signature;
public PEMachineType machine;
public short sectionCount;
public short unknown1;
public short unknown2;
public short unknown3;
public short unknown4;
public short unknown5;
public short unknown6;
public short sizeOfOptionalHeader; // relative offset to sectiontable
public PECharacteristics characteristics;
}
}

View File

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
public enum PEMachineType : ushort
{
/// <summary>
/// The contents of this field are assumed to be applicable to any machine type
/// </summary>
Unknown = 0,
/// <summary>
/// Matsushita AM33
/// </summary>
AM33 = 0x1d3,
/// <summary>
/// x64
/// </summary>
AMD64 = 0x8664,
/// <summary>
/// ARM little endian
/// </summary>
ARM = 0x1c0,
/// <summary>
/// ARMv7 (or higher) Thumb mode only
/// </summary>
ARMNT = 0x1c4,
/// <summary>
/// ARMv8 in 64-bit mode
/// </summary>
ARM64 = 0xaa64,
/// <summary>
/// EFI byte code
/// </summary>
EBC = 0xebc,
/// <summary>
/// Intel 386 or later processors and compatible processors
/// </summary>
Intel386 = 0x14c,
/// <summary>
/// Intel Itanium processor family
/// </summary>
Itanium64 = 0x200,
/// <summary>
/// Mitsubishi M32R little endian
/// </summary>
M32R = 0x9041,
/// <summary>
/// MIPS16
/// </summary>
MIPS16 = 0x266,
/// <summary>
/// MIPS with FPU
/// </summary>
MIPSFloatingPoint = 0x366,
/// <summary>
/// MIPS16 with FPU
/// </summary>
MIPS16FloatingPoint = 0x466,
/// <summary>
/// Power PC little endian
/// </summary>
PowerPC = 0x1f0,
/// <summary>
/// Power PC with floating point support
/// </summary>
PowerPCFloatingPoint = 0x1f1,
/// <summary>
/// MIPS little endian
/// </summary>
R4000 = 0x166,
/// <summary>
/// Hitachi SH3
/// </summary>
HitachiSH3 = 0x1a2,
/// <summary>
/// Hitachi SH3 DSP
/// </summary>
HitachiSH3DSP = 0x1a3,
/// <summary>
/// Hitachi SH4
/// </summary>
HitachiSH4 = 0x1a6,
/// <summary>
/// Hitachi SH5
/// </summary>
HitachiSH5 = 0x1a8,
/// <summary>
/// ARM or Thumb ("interworking")
/// </summary>
Thumb = 0x1c2,
/// <summary>
/// MIPS little-endian WCE v2
/// </summary>
MIPSWCEv2 = 0x169
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
public struct PEOptionalHeader
{
public bool enabled;
public ushort magic;
public ushort unknown1;
public uint unknown2;
public uint unknown3;
public uint unknown4;
public uint entryPointAddr;
public uint unknown5;
public uint unknown6;
public uint imageBase;
public uint sectionAlignment;
public uint fileAlignment;
public uint unknown7;
public uint unknown8;
public ushort majorSubsystemVersion; // 4 = NT 4 or later
public ushort unknown9;
public uint unknown10;
public uint imageSize;
public uint headerSize;
public uint unknown11;
public ushort subsystem;
public ushort unknown12;
public uint unknown13;
public uint unknown14;
public uint unknown15;
public uint unknown16;
public uint unknown17;
public uint rvaCount;
}
}

View File

@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
[Flags()]
public enum PESectionCharacteristics : uint
{
None = 0x00000000,
/// <summary>
/// Reserved.
/// </summary>
TypeNoPad = 0x00000008,
/// <summary>
/// Section contains code.
/// </summary>
ContainsCode = 0x00000020,
/// <summary>
/// Section contains initialized data.
/// </summary>
ContainsInitializedData = 0x00000040,
/// <summary>
/// Section contains uninitialized data.
/// </summary>
ContainsUninitializedData = 0x00000080,
/// <summary>
/// Reserved.
/// </summary>
LinkOther = 0x00000100,
/// <summary>
/// Section contains comments or some other type of information.
/// </summary>
LinkInformation = 0x00000200,
/// <summary>
/// Section contents will not become part of image.
/// </summary>
LinkRemove = 0x00000800,
/// <summary>
/// Section contents comdat.
/// </summary>
LinkComdat = 0x00001000,
/// <summary>
/// Reset speculative exceptions handling bits in the TLB entries for this section.
/// </summary>
ResetSpeculativeExceptions = 0x00004000,
/// <summary>
/// Section content can be accessed relative to GP
/// </summary>
GPRelative = 0x00008000,
MemoryFarData = 0x00008000,
MemoryPurgeable = 0x00020000,
Memory16Bit = 0x00020000,
MemoryLocked = 0x00040000,
MemoryPreload = 0x00080000,
Align1Byte = 0x00100000,
Align2Bytes = 0x00200000,
Align4Bytes = 0x00300000,
Align8Bytes = 0x00400000,
/// <summary>
/// Default alignment if no others are specified.
/// </summary>
Align16Bytes = 0x00500000,
Align32Bytes = 0x00600000,
Align64Bytes = 0x00700000,
Align128Bytes = 0x00800000,
Align256Bytes = 0x00900000,
Align512Bytes = 0x00A00000,
Align1024Bytes = 0x00B00000,
Align2048Bytes = 0x00C00000,
Align4096Bytes = 0x00D00000,
Align8192Bytes = 0x00E00000,
AlignMask = 0x00F00000,
/// <summary>
/// Section contains extended relocations.
/// </summary>
LinkExtendedRelocations = 0x01000000,
/// <summary>
/// Section can be discarded.
/// </summary>
MemoryDiscardable = 0x02000000,
/// <summary>
/// Section is not cachable.
/// </summary>
MemoryNotCached = 0x04000000,
/// <summary>
/// Section is not pageable.
/// </summary>
MemoryNotPaged = 0x08000000,
/// <summary>
/// Section is shareable.
/// </summary>
MemoryShared = 0x10000000,
/// <summary>
/// Section is executable.
/// </summary>
MemoryExecutable = 0x20000000,
/// <summary>
/// Section is readable.
/// </summary>
MemoryReadable = 0x40000000,
/// <summary>
/// Section is writeable.
/// </summary>
MemoryWritable = 0x80000000
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniversalEditor.DataFormats.Executable.Microsoft
{
public struct PESectionHeader
{
public string name;
public uint virtualSize;
public uint virtualAddress;
public uint rawDataSize;
public uint rawDataPtr;
public uint unknown1;
public uint unknown2;
public uint unknown3;
public PESectionCharacteristics characteristics;
}
}

View File

@ -44,6 +44,15 @@
<Compile Include="DataFormats\Executable\ELF\ELFSectionFlags.cs" />
<Compile Include="DataFormats\Executable\ELF\ELFSectionType.cs" />
<Compile Include="DataFormats\Executable\ELF\ELFSpecialSectionIndex.cs" />
<Compile Include="DataFormats\Executable\Microsoft\DOSExecutableHeader.cs" />
<Compile Include="DataFormats\Executable\Microsoft\MicrosoftExecutableDataFormat.cs" />
<Compile Include="DataFormats\Executable\Microsoft\PECharacteristics.cs" />
<Compile Include="DataFormats\Executable\Microsoft\PECompiler.cs" />
<Compile Include="DataFormats\Executable\Microsoft\PEHeader.cs" />
<Compile Include="DataFormats\Executable\Microsoft\PEMachineType.cs" />
<Compile Include="DataFormats\Executable\Microsoft\PEOptionalHeader.cs" />
<Compile Include="DataFormats\Executable\Microsoft\PESectionCharacteristics.cs" />
<Compile Include="DataFormats\Executable\Microsoft\PESectionHeader.cs" />
<Compile Include="ObjectModels\Executable\ExecutableCharacteristics.cs" />
<Compile Include="ObjectModels\Executable\ExecutableFunctionCall.cs" />
<Compile Include="ObjectModels\Executable\ExecutableInstruction.cs" />