protected void OnBtnLoadClick(object sender, EventArgs e) { txtFile.Text = ""; txtType.Text = ""; txtInformation.Text = ""; cmbArch.Items.Clear(); lblSubsystem.Visible = false; txtSubsystem.Visible = false; tabStrings.Visible = false; tabGemResources.Visible = false; tabSegments.Visible = false; tabNeResources.Visible = false; tabLeVxdVersion.Visible = false; tabLxResources.Visible = false; tabPeResources.Visible = false; tabBeResources.Visible = false; OpenFileDialog dlgOpen = new OpenFileDialog { Title = "Choose executable file", MultiSelect = false }; if (dlgOpen.ShowDialog(this) != DialogResult.Ok) { return; } txtFile.Text = dlgOpen.FileName; txtInformation.Text = ""; txtOs.Text = ""; txtSubsystem.Text = ""; txtType.Text = ""; IExecutable mzExe = new MZ(dlgOpen.FileName); IExecutable neExe = new libexeinfo.NE(dlgOpen.FileName); IExecutable stExe = new AtariST(dlgOpen.FileName); IExecutable lxExe = new libexeinfo.LX(dlgOpen.FileName); IExecutable coffExe = new COFF(dlgOpen.FileName); IExecutable peExe = new libexeinfo.PE(dlgOpen.FileName); IExecutable geosExe = new Geos(dlgOpen.FileName); IExecutable elfExe = new ELF(dlgOpen.FileName); IExecutable recognizedExe = null; if (mzExe.Recognized) { recognizedExe = mzExe; if (((MZ)mzExe).ResourceObjectRoots != null && ((MZ)mzExe).ResourceObjectRoots.Any()) { tabGemResources.Update(((MZ)mzExe).ResourceObjectRoots, ((MZ)mzExe).GemColorIcons); tabGemResources.Visible = true; } } if (neExe.Recognized) { recognizedExe = neExe; if (((libexeinfo.NE)neExe).Resources.types != null && ((libexeinfo.NE)neExe).Resources.types.Any()) { tabNeResources.Update(((libexeinfo.NE)neExe).Resources.types, ((libexeinfo.NE)neExe).Header.target_os); tabNeResources.Visible = true; } } else if (lxExe.Recognized) { recognizedExe = lxExe; if (((libexeinfo.LX)lxExe).WinVersion != null) { tabLeVxdVersion.Visible = true; tabLeVxdVersion.Update(((libexeinfo.LX)lxExe).WinVersion); } if (((libexeinfo.LX)lxExe).neFormatResourceTable.types != null && ((libexeinfo.LX)lxExe).neFormatResourceTable.types.Any()) { tabLxResources.Update(((libexeinfo.LX)lxExe).neFormatResourceTable.types); tabLxResources.Visible = true; } } else if (peExe.Recognized) { recognizedExe = peExe; if (((libexeinfo.PE)peExe).WindowsResourcesRoot?.children != null) { tabPeResources.Update(((libexeinfo.PE)peExe).WindowsResourcesRoot); tabPeResources.Visible = true; } if (((libexeinfo.PE)peExe).BeosResources != null) { tabBeResources.Update(((libexeinfo.PE)peExe).BeosResources, peExe.IsBigEndian); tabBeResources.Visible = true; } } else if (stExe.Recognized) { recognizedExe = stExe; if (((AtariST)stExe).ResourceObjectRoots != null && ((AtariST)stExe).ResourceObjectRoots.Any()) { tabGemResources.Update(((AtariST)stExe).ResourceObjectRoots, ((AtariST)stExe).GemColorIcons); tabGemResources.Visible = true; } } else if (coffExe.Recognized) { recognizedExe = coffExe; } else if (elfExe.Recognized) { recognizedExe = elfExe; } else if (geosExe.Recognized) { recognizedExe = geosExe; } else { txtType.Text = "Format not recognized"; } if (recognizedExe == null) { return; } txtType.Text = recognizedExe.Type; txtInformation.Text = recognizedExe.Information; foreach (Architecture arch in recognizedExe.Architectures) { cmbArch.Items.Add(Enums.ArchitectureName.FirstOrDefault(ar => ar.arch == arch).longName); } cmbArch.SelectedIndex = 0; if (recognizedExe.RequiredOperatingSystem.MajorVersion > 0) { txtOs.Text = $"{recognizedExe.RequiredOperatingSystem.Name}" + $" {recognizedExe.RequiredOperatingSystem.MajorVersion}" + $".{recognizedExe.RequiredOperatingSystem.MinorVersion}"; } else { txtOs.Text = recognizedExe.RequiredOperatingSystem.Name; } if (!string.IsNullOrEmpty(recognizedExe.RequiredOperatingSystem.Subsystem)) { lblSubsystem.Visible = true; txtSubsystem.Visible = true; txtSubsystem.Text = recognizedExe.RequiredOperatingSystem.Subsystem; } if (recognizedExe.Strings != null && recognizedExe.Strings.Any()) { tabStrings.Update(recognizedExe.Strings); tabStrings.Visible = true; } if (recognizedExe.Segments != null && recognizedExe.Segments.Any()) { tabSegments.Update(recognizedExe.Segments); tabSegments.Visible = true; } }
// TODO: How to know VxD structure offset void Initialize() { Recognized = false; if (BaseStream == null) { return; } BaseExecutable = new MZ(BaseStream); if (!BaseExecutable.Recognized) { return; } if (BaseExecutable.Header.new_offset >= BaseStream.Length) { return; } BaseStream.Seek(BaseExecutable.Header.new_offset, SeekOrigin.Begin); byte[] buffer = new byte[Marshal.SizeOf(typeof(LXHeader))]; BaseStream.Read(buffer, 0, buffer.Length); IntPtr hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); Header = (LXHeader)Marshal.PtrToStructure(hdrPtr, typeof(LXHeader)); Marshal.FreeHGlobal(hdrPtr); Recognized = Header.signature == SIGNATURE || Header.signature == SIGNATURE16; if (!Recognized) { return; } Type = Header.signature == SIGNATURE16 ? "Linear Executable (LE)" : "Linear eXecutable (LX)"; IsBigEndian = Header.byte_order == 1 || Header.word_order == 1; List <string> strings = new List <string>(); OperatingSystem reqOs = new OperatingSystem(); switch (Header.os_type) { case TargetOS.OS2: reqOs.Name = "OS/2"; if (Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && !Header.module_flags.HasFlag(ModuleFlags.PMCompatible) || !Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) { reqOs.Subsystem = "Console"; } else if (Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) { reqOs.Subsystem = "Presentation Manager"; } break; case TargetOS.Windows: case TargetOS.Win32: case TargetOS.Unknown: reqOs.Name = "Windows"; break; case TargetOS.DOS: reqOs.Name = "Windows"; break; default: reqOs.Name = $"Unknown code {(ushort)Header.os_type}"; break; } RequiredOperatingSystem = reqOs; if (Header.resident_names_off != 0) { ResidentNames = GetResidentStrings(BaseStream, BaseExecutable.Header.new_offset, Header.resident_names_off); if (ResidentNames.Length >= 1) { ModuleName = ResidentNames[0].name; if (ResidentNames.Length > 1) { NE.ResidentName[] newResidentNames = new NE.ResidentName[ResidentNames.Length - 1]; Array.Copy(ResidentNames, 1, newResidentNames, 0, ResidentNames.Length - 1); ResidentNames = newResidentNames; } else { ResidentNames = null; } } } if (Header.nonresident_name_table_len > 0) { NonResidentNames = GetResidentStrings(BaseStream, 0, Header.nonresident_name_table_off); if (NonResidentNames.Length >= 1) { ModuleDescription = NonResidentNames[0].name; if (NonResidentNames.Length > 1) { NE.ResidentName[] newNonResidentNames = new NE.ResidentName[NonResidentNames.Length - 1]; Array.Copy(NonResidentNames, 1, newNonResidentNames, 0, NonResidentNames.Length - 1); NonResidentNames = newNonResidentNames; } else { NonResidentNames = null; } } } if (Header.import_module_table_off != 0 && Header.import_module_entries > 0) { BaseStream.Position = Header.import_module_table_off + BaseExecutable.Header.new_offset; ImportedNames = new string[Header.import_module_entries]; for (int i = 0; i < Header.import_module_entries; i++) { int len = BaseStream.ReadByte(); buffer = new byte[len]; BaseStream.Read(buffer, 0, len); ImportedNames[i] = Encoding.ASCII.GetString(buffer); } } if (!string.IsNullOrEmpty(ModuleName)) { strings.Add(ModuleName); } if (!string.IsNullOrEmpty(ModuleDescription)) { strings.Add(ModuleDescription); } objectTableEntries = new ObjectTableEntry[Header.obj_no]; objectPageTableEntries = new ObjectPageTableEntry[Header.module_pages_no]; BaseStream.Position = Header.obj_table_off + BaseExecutable.Header.new_offset; buffer = new byte[Marshal.SizeOf(typeof(ObjectTableEntry))]; for (int i = 0; i < Header.obj_no; i++) { BaseStream.Read(buffer, 0, buffer.Length); objectTableEntries[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <ObjectTableEntry>(buffer); } BaseStream.Position = Header.obj_page_table_off + BaseExecutable.Header.new_offset; if (Header.signature == SIGNATURE16) { buffer = new byte[Marshal.SizeOf(typeof(ObjectPageTableEntry16))]; for (int i = 0; i < Header.module_pages_no; i++) { BaseStream.Read(buffer, 0, buffer.Length); ObjectPageTableEntry16 page16 = BigEndianMarshal.ByteArrayToStructureLittleEndian <ObjectPageTableEntry16>(buffer); int pageNo = (page16.High << 8) + page16.Low; objectPageTableEntries[i] = new ObjectPageTableEntry { DataSize = (ushort)Header.page_size, Flags = (PageTableAttributes)page16.Flags, PageDataOffset = (uint)((pageNo - 1) * Header.page_size) }; } } else { buffer = new byte[Marshal.SizeOf(typeof(ObjectPageTableEntry))]; for (int i = 0; i < Header.module_pages_no; i++) { BaseStream.Read(buffer, 0, buffer.Length); objectPageTableEntries[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <ObjectPageTableEntry>(buffer); } } int debugSections = 0; int winrsrcSections = 0; if (Header.debug_info_len > 0) { debugSections = 1; } if (Header.win_res_len > 0) { winrsrcSections = 1; } Segment[] sections = new Segment[objectTableEntries.Length + debugSections + winrsrcSections]; for (int i = 0; i < objectTableEntries.Length; i++) { sections[i] = new Segment { Flags = $"{objectTableEntries[i].ObjectFlags}" }; if (objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Resource)) { sections[i].Name = ".rsrc"; } else if (objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Executable)) { sections[i].Name = ".text"; } else if (!objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Writable)) { sections[i].Name = ".rodata"; } else if (StringHandlers.CToString(objectTableEntries[i].Name).ToLower() == "bss") { sections[i].Name = ".bss"; } else if (!string.IsNullOrWhiteSpace(StringHandlers.CToString(objectTableEntries[i].Name).Trim())) { sections[i].Name = StringHandlers.CToString(objectTableEntries[i].Name).Trim(); } else { sections[i].Name = ".data"; } if (objectTableEntries[i].PageTableEntries == 0 || objectTableEntries[i].PageTableIndex > objectPageTableEntries.Length) { sections[i].Size = objectTableEntries[i].VirtualSize; continue; } int shift = (int)(Header.signature == SIGNATURE16 ? 0 : Header.page_off_shift); if (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1] .Flags.HasFlag(PageTableAttributes.IteratedDataPage)) { sections[i].Offset = (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1].PageDataOffset << shift) + Header.obj_iter_pages_off; } else if (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1] .Flags.HasFlag(PageTableAttributes.LegalPhysicalPage)) { sections[i].Offset = (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1].PageDataOffset << shift) + Header.data_pages_off; } else { sections[i].Offset = 0; } sections[i].Size = 0; for (int j = 0; j < objectTableEntries[i].PageTableEntries; j++) { sections[i].Size += objectPageTableEntries[j + objectTableEntries[i].PageTableIndex - 1].DataSize; } if (sections[i].Offset + sections[i].Size > BaseStream.Length) { sections[i].Size = BaseStream.Length - sections[i].Offset; } } if (winrsrcSections > 0) { sections[sections.Length - debugSections - winrsrcSections] = new Segment { Name = ".rsrc", Size = Header.win_res_len, Offset = Header.win_res_off } } ; if (debugSections > 0) { sections[sections.Length - debugSections] = new Segment { Name = ".debug", Size = Header.debug_info_len, Offset = Header.debug_info_off } } ; // It only contains a RT_VERSION resource prefixed by some 12-byte header I can't find information about, so let's just skip it. if (winrsrcSections > 0) { buffer = new byte[Header.win_res_len]; BaseStream.Position = Header.win_res_off + 12; BaseStream.Read(buffer, 0, buffer.Length); WinVersion = new NE.Version(buffer); strings.AddRange(from s in WinVersion.StringsByLanguage from k in s.Value select k.Value); } resources = new ResourceTableEntry[Header.resource_entries]; BaseStream.Position = Header.resource_table_off + BaseExecutable.Header.new_offset; buffer = new byte[Marshal.SizeOf(typeof(ResourceTableEntry))]; for (int i = 0; i < resources.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); resources[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <ResourceTableEntry>(buffer); } SortedDictionary <ResourceTypes, List <NE.Resource> > os2Resources = new SortedDictionary <ResourceTypes, List <NE.Resource> >(); for (int i = 0; i < resources.Length; i++) { os2Resources.TryGetValue(resources[i].type, out List <NE.Resource> thisResourceType); if (thisResourceType == null) { thisResourceType = new List <NE.Resource>(); } NE.Resource thisResource = new NE.Resource { id = resources[i].id, name = $"{resources[i].id}", flags = 0, dataOffset = (uint)(sections[resources[i].obj_no - 1].Offset + resources[i].offset), length = resources[i].size }; thisResource.data = new byte[thisResource.length]; BaseStream.Position = thisResource.dataOffset; BaseStream.Read(thisResource.data, 0, thisResource.data.Length); thisResourceType.Add(thisResource); os2Resources.Remove(resources[i].type); os2Resources.Add(resources[i].type, thisResourceType); } if (os2Resources.Count > 0) { neFormatResourceTable = new NE.ResourceTable(); int counter = 0; neFormatResourceTable.types = new NE.ResourceType[os2Resources.Count]; foreach (KeyValuePair <ResourceTypes, List <NE.Resource> > kvp in os2Resources) { neFormatResourceTable.types[counter].count = (ushort)kvp.Value.Count; neFormatResourceTable.types[counter].id = (ushort)kvp.Key; neFormatResourceTable.types[counter].name = Resources.IdToName((ushort)kvp.Key); neFormatResourceTable.types[counter].resources = kvp.Value.OrderBy(r => r.id).ToArray(); counter++; } foreach (NE.ResourceType rtype in neFormatResourceTable.types) { if (rtype.name != "RT_STRING") { continue; } strings.AddRange(NE.GetOs2Strings(rtype)); } } Segments = sections; Strings = strings; }