/// <summary> /// Gets a string with human readable information for a given MZ header /// </summary> /// <returns>Human readable information for given MZ header.</returns> /// <param name="header">MZ executable header.</param> static string GetInfo(MZHeader header) { StringBuilder sb = new StringBuilder(); sb.AppendLine("DOS MZ executable:"); sb.AppendFormat("\tBlocks in file: {0}", header.blocks_in_file).AppendLine(); sb.AppendFormat("\t{0} bytes used in last block", header.bytes_in_last_block == 0 ? 512 : header.bytes_in_last_block).AppendLine(); sb.AppendFormat("\t{0} relocations present after the header", header.num_relocs).AppendLine(); sb.AppendFormat("\t{0} paragraphs in header", header.header_paragraphs).AppendLine(); sb.AppendFormat("\t{0} paragraphs of additional memory required", header.min_extra_paragraphs) .AppendLine(); sb.AppendFormat("\t{0} paragraphs of additional memory requested", header.max_extra_paragraphs) .AppendLine(); sb.AppendFormat("\tSegment address for SS: {0:X4}h", header.ss).AppendLine(); sb.AppendFormat("\tInitial value of SP: {0:X4}h", header.sp).AppendLine(); sb.AppendFormat("\tInitial value of IP: {0:X4}h", header.ip).AppendLine(); sb.AppendFormat("\tInitial value of CS: {0:X4}h", header.cs).AppendLine(); sb.AppendFormat("\tOffset to relocation table: {0}", header.reloc_table_offset).AppendLine(); sb.AppendFormat("\tFile contains {0} overlays", header.overlay_number).AppendLine(); sb.AppendFormat("\tFile checksum: 0x{0:X4}", header.checksum).AppendLine(); sb.AppendFormat("\tOEM ID: {0}", header.oem_id).AppendLine(); sb.AppendFormat("\tOEM information: 0x{0:X4}", header.oem_info).AppendLine(); sb.AppendFormat("\tOffset to new header: {0}", header.new_offset).AppendLine(); return(sb.ToString()); }
public FarPtr StartingPointer = new FarPtr(1 + 0x10, 0); //PSP+10h for Segment public MZFile(string exeFile) { Segments = new List <Segment>(); RelocationRecords = new List <FarPtr>(); _exeFile = exeFile; _exeFileData = File.ReadAllBytes(_exeFile); _mzHeader = new MZHeader(_exeFileData); Load(); }
/// <summary> /// Identifies if the specified executable is a DOS relocatable executable /// </summary> /// <returns><c>true</c> if the specified executable is a DOS relocatable executable, <c>false</c> otherwise.</returns> /// <param name="stream">Stream containing the executable.</param> public static bool Identify(FileStream stream) { byte[] buffer = new byte[Marshal.SizeOf(typeof(MZHeader))]; stream.Position = 0; stream.Read(buffer, 0, buffer.Length); IntPtr hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); MZHeader mzHdr = (MZHeader)Marshal.PtrToStructure(hdrPtr, typeof(MZHeader)); Marshal.FreeHGlobal(hdrPtr); return(mzHdr.signature == SIGNATURE); }
void Initialize() { Recognized = false; if (BaseStream == null) { return; } byte[] buffer = new byte[Marshal.SizeOf(typeof(MZHeader))]; BaseStream.Position = 0; BaseStream.Read(buffer, 0, buffer.Length); IntPtr hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); Header = (MZHeader)Marshal.PtrToStructure(hdrPtr, typeof(MZHeader)); Marshal.FreeHGlobal(hdrPtr); Recognized = Header.signature == SIGNATURE; if (!Recognized) { return; } Type = "DOS Executable (MZ)"; RequiredOperatingSystem = new OperatingSystem { Name = "DOS" }; if (ResourceStream == null) { return; } buffer = new byte[Marshal.SizeOf(typeof(GEM.GemResourceHeader))]; ResourceStream.Position = 0; ResourceStream.Read(buffer, 0, buffer.Length); GEM.GemResourceHeader gemResourceHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian <GEM.GemResourceHeader>(buffer); if (gemResourceHeader.rsh_vrsn != 0 && gemResourceHeader.rsh_vrsn != 1 && gemResourceHeader.rsh_vrsn != 3 && gemResourceHeader.rsh_vrsn != 4 && gemResourceHeader.rsh_vrsn != 5) { return; } RequiredOperatingSystem = new OperatingSystem { Name = "PC-GEM" }; if (gemResourceHeader.rsh_vrsn == 3) { buffer = new byte[Marshal.SizeOf(typeof(GEM.MagiCResourceHeader))]; ResourceStream.Position = 0; ResourceStream.Read(buffer, 0, buffer.Length); ResourceHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian <GEM.MagiCResourceHeader>(buffer); RequiredOperatingSystem = new OperatingSystem { Name = "MagiC" }; } else { ResourceHeader = GEM.GemToMagiC(gemResourceHeader); } if ((ResourceHeader.rsh_vrsn & 4) == 4) { buffer = new byte[Marshal.SizeOf(typeof(GEM.GemResourceExtension))]; ResourceStream.Position = ResourceHeader.rsh_rssize; ResourceStream.Read(buffer, 0, buffer.Length); ResourceExtension = BigEndianMarshal.ByteArrayToStructureLittleEndian <GEM.GemResourceExtension>(buffer); GemColorIcons = GEM.GetColorIcons(ResourceStream, ResourceExtension.color_ic, false, Encoding.GemEncoding); } List <string> strings = new List <string>(); if (ResourceHeader.rsh_ntree > 0) { ResourceStream.Position = ResourceHeader.rsh_trindex; int[] treeOffsets = new int[ResourceHeader.rsh_ntree]; byte[] tmp = new byte[4]; for (int i = 0; i < ResourceHeader.rsh_ntree; i++) { ResourceStream.Read(tmp, 0, 4); treeOffsets[i] = BitConverter.ToInt32(tmp, 0); } ResourceObjectRoots = new GEM.TreeObjectNode[ResourceHeader.rsh_ntree]; for (int i = 0; i < ResourceHeader.rsh_ntree; i++) { if (treeOffsets[i] <= 0 || treeOffsets[i] >= ResourceStream.Length) { continue; } ResourceStream.Position = treeOffsets[i]; List <GEM.ObjectNode> nodes = new List <GEM.ObjectNode>(); while (true) { buffer = new byte[Marshal.SizeOf(typeof(GEM.ObjectNode))]; ResourceStream.Read(buffer, 0, buffer.Length); GEM.ObjectNode node = BigEndianMarshal.ByteArrayToStructureLittleEndian <GEM.ObjectNode>(buffer); nodes.Add(node); if (((GEM.ObjectFlags)node.ob_flags).HasFlag(GEM.ObjectFlags.Lastob)) { break; } } List <short> knownNodes = new List <short>(); ResourceObjectRoots[i] = GEM.ProcessResourceObject(nodes, ref knownNodes, 0, ResourceStream, strings, false, Encoding.GemEncoding); } } else if (ResourceHeader.rsh_nobs > 0) { GEM.ObjectNode[] nodes = new GEM.ObjectNode[ResourceHeader.rsh_nobs]; ResourceStream.Position = ResourceHeader.rsh_object; for (short i = 0; i < ResourceHeader.rsh_nobs; i++) { buffer = new byte[Marshal.SizeOf(typeof(GEM.ObjectNode))]; ResourceStream.Read(buffer, 0, buffer.Length); nodes[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <GEM.ObjectNode>(buffer); } List <short> knownNodes = new List <short>(); ResourceObjectRoots = new GEM.TreeObjectNode[1]; // TODO: Correct encoding? ResourceObjectRoots[0] = GEM.ProcessResourceObject(nodes, ref knownNodes, 0, ResourceStream, strings, false, Encoding.GemEncoding); } if (strings.Count > 0) { strings.Sort(); Strings = strings.Distinct(); } }
private void Load() { var data = new Span <byte>(FileContent); DOSHeader = new MZHeader(FileContent); //Verify old DOS header is correct if (DOSHeader.Signature != 23117) { throw new Exception("Invalid Header"); } //Locate Windows Header ushort windowsHeaderOffset; if (data[0x18] >= 0x40) { windowsHeaderOffset = BitConverter.ToUInt16(FileContent, 0x3C); } else { throw new Exception("Unable to locate Windows Header location"); } //Load Windows Header WindowsHeader = new NEHeader(data.Slice(windowsHeaderOffset, 0x3F).ToArray()) { FileOffset = windowsHeaderOffset }; //Adjust Offsets According to Spec (Offset from beginning of Windows Header, not file) WindowsHeader.SegmentTableOffset += windowsHeaderOffset; WindowsHeader.ResourceTableOffset += windowsHeaderOffset; WindowsHeader.ResidentNameTableOffset += windowsHeaderOffset; WindowsHeader.ModleReferenceTableOffset += windowsHeaderOffset; WindowsHeader.ImportedNamesTableOffset += windowsHeaderOffset; WindowsHeader.EntryTableOffset += windowsHeaderOffset; //Load Segment Table SegmentTable = new List <Segment>(WindowsHeader.SegmentTableEntries); for (var i = 0; i < WindowsHeader.SegmentTableEntries; i++) { //Load Segment Header (8 bytes per record) var segment = new Segment(data.Slice(WindowsHeader.SegmentTableOffset + (i * 8), 8).ToArray()) { Ordinal = (ushort)(i + 1) }; segment.Offset <<= WindowsHeader.LogicalSectorAlignmentShift; //Attach Segment Data segment.Data = data.Slice((int)segment.Offset, segment.Length).ToArray(); //Attach Relocation Records if (segment.Flags.Contains(EnumSegmentFlags.HasRelocationInfo)) { var relocationInfoCursor = (int)segment.Offset + segment.Length; var relocationRecordEntries = BitConverter.ToUInt16(FileContent, relocationInfoCursor); relocationInfoCursor += 2; var records = new Dictionary <ushort, RelocationRecord>(); for (var j = 0; j < relocationRecordEntries; j++) { var relocationRecord = new RelocationRecord(_logger) { Data = data.Slice(relocationInfoCursor + j * 8, 8).ToArray() }; records.Add(relocationRecord.Offset, relocationRecord); } segment.RelocationRecords = records; } SegmentTable.Add(segment); } //Load Resource Table //ResourceTable = new List<ResourceRecord>(); //TODO -- Resource Table isn't used by MBBS modules so we'll skip loading this for now //TODO -- Implement this in a future version //Load Resident Name Table ResidentNameTable = new List <ResidentName>(); for (var i = 0; i < WindowsHeader.ModleReferenceTableOffset; i += 2) { var residentName = new ResidentName(); var residentNameLength = data[WindowsHeader.ResidentNameTableOffset + i]; //End of Names if (residentNameLength == 0) { break; } i++; residentName.Name = Encoding.Default.GetString(data.Slice(WindowsHeader.ResidentNameTableOffset + i, residentNameLength) .ToArray()); i += residentNameLength; residentName.IndexIntoEntryTable = BitConverter.ToUInt16(FileContent, WindowsHeader.ResidentNameTableOffset + i); ResidentNameTable.Add(residentName); } //Load Module & Imported Name Reference Tables ModuleReferenceTable = new List <ModuleReference>(WindowsHeader.ModuleReferenceTableEntries); ImportedNameTable = new Dictionary <ushort, ImportedName>(); for (var i = 0; i < WindowsHeader.ModuleReferenceTableEntries; i++) { var nameOffset = BitConverter.ToUInt16(FileContent, WindowsHeader.ModleReferenceTableOffset + i * 2); var fileOffset = (ushort)(nameOffset + WindowsHeader.ImportedNamesTableOffset); var module = new ModuleReference(); var importedName = new ImportedName() { Offset = nameOffset, FileOffset = fileOffset }; var name = Encoding.Default.GetString(data.Slice(fileOffset + 1, data[fileOffset]).ToArray()); module.Name = name; importedName.Name = name; importedName.Ordinal = (ushort)(i + 1); //Ordinal Index in Resource Tables start with 1 ModuleReferenceTable.Add(module); ImportedNameTable.Add(importedName.Ordinal, importedName); } //Load Entry Table EntryTable = new List <Entry>(data[WindowsHeader.EntryTableOffset]); //Value of 0 denotes no segment data if (data[WindowsHeader.EntryTableOffset] > 0) { var entryByteOffset = 0; ushort entryOrdinal = 1; while (WindowsHeader.EntryTableOffset + entryByteOffset < WindowsHeader.NonResidentNameTableOffset) { //0xFF is moveable (6 bytes), anything else is fixed as it becomes the segment number var entryCount = data[WindowsHeader.EntryTableOffset + entryByteOffset]; var entrySegment = data[WindowsHeader.EntryTableOffset + entryByteOffset + 1]; if (entryCount == 1 && entrySegment == 0) { entryByteOffset += 2; entryOrdinal += 1; continue; } var entrySize = entrySegment == 0xFF ? 6 : 3; for (var i = 0; i < entryCount; i++) { var entry = new Entry { SegmentNumber = entrySegment }; if (entrySize == 3) { entry.Flag = data[WindowsHeader.EntryTableOffset + entryByteOffset + 2 + entrySize * i]; entry.Offset = BitConverter.ToUInt16(FileContent, WindowsHeader.EntryTableOffset + entryByteOffset + 3 + entrySize * i); entry.SegmentNumber = entrySegment; entry.Ordinal = entryOrdinal; //First Entry is the Resident Name table is the module name, so we shift the ordinals by 1 to line up } else { entry.Flag = data[WindowsHeader.EntryTableOffset + entryByteOffset + 2 + entrySize * i]; entry.SegmentNumber = data[WindowsHeader.EntryTableOffset + entryByteOffset + 5 + (entrySize * i)]; entry.Offset = BitConverter.ToUInt16(FileContent, WindowsHeader.EntryTableOffset + entryByteOffset + 6 + entrySize * i); } entryOrdinal++; EntryTable.Add(entry); } entryByteOffset += (entryCount * entrySize) + 2; } } //Load Non-Resident Name Table NonResidentNameTable = new List <NonResidentName>(); for (var i = (int)WindowsHeader.NonResidentNameTableOffset; i < (WindowsHeader.NonResidentNameTableOffset + WindowsHeader.NonResidentNameTableLength); i += 2) { var nameLength = data[i]; i++; var name = Encoding.Default.GetString(data.Slice(i, nameLength).ToArray()); i += nameLength; var indexIntoEntryTable = BitConverter.ToUInt16(FileContent, i); NonResidentNameTable.Add(new NonResidentName() { Name = name, IndexIntoEntryTable = indexIntoEntryTable }); } }
public MZResult(MZHeader header) { RawData = StructConverter.GetBytes(header); NewHeaderOffset = header.NewHeaderRVA; }
public unsafe IMZResult Package(IMZInfo param) => new MZResult(MZHeader.CreateWithDefaultStub((uint)sizeof(MZHeader)));