/// <summary> /// Identifies if the specified executable is a Microsoft/IBM Linear EXecutable /// </summary> /// <returns><c>true</c> if the specified executable is a Microsoft/IBM Linear EXecutable, <c>false</c> otherwise.</returns> /// <param name="stream">Stream containing the executable.</param> public static bool Identify(FileStream stream) { FileStream baseStream = stream; MZ baseExecutable = new MZ(baseStream); if (!baseExecutable.Recognized) { return(false); } if (baseExecutable.Header.new_offset >= baseStream.Length) { return(false); } 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); LXHeader header = (LXHeader)Marshal.PtrToStructure(hdrPtr, typeof(LXHeader)); Marshal.FreeHGlobal(hdrPtr); return(header.signature == SIGNATURE || header.signature == SIGNATURE16); }
public override Program Load(Address addrLoad) { var cfgSvc = Services.RequireService <IConfigurationService>(); this.arch = cfgSvc.GetArchitecture("x86-protected-32"); var rdr = new LeImageReader(RawImage, this.lfaNew); var hdrReader = new StructureReader <LXHeader>(rdr); this.hdr = hdrReader.Read(); LoadModuleTable(); var leSegs = LoadSegmentTable(); var segments = MakeSegmentMap(addrLoad, leSegs); var platform = MakePlatform(); return(new Program(segments, arch, platform)); }
// 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; }