static int GetTokenFromExportOrdinal(Module module, ExportDirectoryTable edt, int ordinal) { byte[] buf = new byte[6]; module.__ReadDataFromRVA((int)edt.ExportAddressTableRVA + (int)(ordinal - edt.OrdinalBase) * 4, buf, 0, 4); int exportRVA = BitConverter.ToInt32(buf, 0); module.__ReadDataFromRVA(exportRVA, buf, 0, 6); PortableExecutableKinds peKind; ImageFileMachine machine; module.GetPEKind(out peKind, out machine); if (machine == ImageFileMachine.I386 && buf[0] == 0xFF && buf[1] == 0x25) { // for x86 the code here is: // FF 25 00 40 40 00 jmp dword ptr ds:[00404000h] } else if (machine == ImageFileMachine.AMD64 && buf[0] == 0x48 && buf[1] == 0xA1) { // for x64 the code here is: // 48 A1 00 40 40 00 00 00 00 00 mov rax,qword ptr [0000000000404000h] // FF E0 jmp rax } else { return(-1); } int vtableRVA = BitConverter.ToInt32(buf, 2) - (int)module.__ImageBase; module.__ReadDataFromRVA(vtableRVA, buf, 0, 4); return(BitConverter.ToInt32(buf, 0)); }
static Dictionary <int, List <ExportedMethod> > GetExportedMethods(Module module) { int rva; int length; module.__GetDataDirectoryEntry(0, out rva, out length); if (rva == 0 || length < 40) { return(new Dictionary <int, List <ExportedMethod> >()); } ExportDirectoryTable edt = new ExportDirectoryTable(); byte[] buf = new byte[512]; module.__ReadDataFromRVA(rva, buf, 0, 40); edt.Read(new BinaryReader(new MemoryStream(buf))); var methods = new Dictionary <int, List <ExportedMethod> >(); for (int i = 0; i < edt.NumberOfNamePointers; i++) { module.__ReadDataFromRVA((int)edt.OrdinalTableRVA + i * 2, buf, 0, 2); int ordinal = BitConverter.ToInt16(buf, 0) + (int)edt.OrdinalBase; string name = null; if (edt.NamePointerRVA != 0) { module.__ReadDataFromRVA((int)edt.NamePointerRVA + i * 4, buf, 0, 4); module.__ReadDataFromRVA(BitConverter.ToInt32(buf, 0), buf, 0, buf.Length); int len = 0; while (buf[len] != 0) { len++; } name = Encoding.ASCII.GetString(buf, 0, len); } int token = GetTokenFromExportOrdinal(module, edt, ordinal); if (token == -1) { continue; } List <ExportedMethod> list; if (!methods.TryGetValue(token, out list)) { list = new List <ExportedMethod>(); methods.Add(token, list); } ExportedMethod method; method.name = name; method.ordinal = ordinal; list.Add(method); } return(methods); }
static int GetTokenFromExportOrdinal(Module module, ExportDirectoryTable edt, int ordinal) { PortableExecutableKinds peKind; ImageFileMachine machine; module.GetPEKind(out peKind, out machine); byte[] buf = new byte[16]; module.__ReadDataFromRVA((int)edt.ExportAddressTableRVA + (int)(ordinal - edt.OrdinalBase) * 4, buf, 0, 4); int exportRVA = BitConverter.ToInt32(buf, 0); if (machine == ImageFileMachine.ARM) { // mask out the instruction set selection flag exportRVA &= ~1; } module.__ReadDataFromRVA(exportRVA, buf, 0, 16); int offset; if (machine == ImageFileMachine.I386 && buf[0] == 0xFF && buf[1] == 0x25) { // for x86 the code here is: // FF 25 00 40 40 00 jmp dword ptr ds:[00404000h] offset = 2; } else if (machine == ImageFileMachine.AMD64 && buf[0] == 0x48 && buf[1] == 0xA1) { // for x64 the code here is: // 48 A1 00 40 40 00 00 00 00 00 mov rax,qword ptr [0000000000404000h] // FF E0 jmp rax offset = 2; } else if (machine == ImageFileMachine.ARM && buf[0] == 0xDF && buf[1] == 0xF8 && buf[2] == 0x08 && buf[3] == 0xC0) { // for arm the code here is: // F8DF C008 ldr r12,0040145C // F8DC C000 ldr r12,[r12] // 4760 bx r12 // DEFE __debugbreak // here is the RVA offset = 12; } else { return(-1); } int vtableRVA = BitConverter.ToInt32(buf, offset) - (int)module.__ImageBase; module.__ReadDataFromRVA(vtableRVA, buf, 0, 4); return(BitConverter.ToInt32(buf, 0)); }
static Dictionary<int, List<ExportedMethod>> GetExportedMethods(Module module) { int rva; int length; module.__GetDataDirectoryEntry(0, out rva, out length); if (rva == 0 || length < 40) { return new Dictionary<int, List<ExportedMethod>>(); } ExportDirectoryTable edt = new ExportDirectoryTable(); byte[] buf = new byte[512]; module.__ReadDataFromRVA(rva, buf, 0, 40); edt.Read(new BinaryReader(new MemoryStream(buf))); var methods = new Dictionary<int, List<ExportedMethod>>(); for (int i = 0; i < edt.NumberOfNamePointers; i++) { module.__ReadDataFromRVA((int)edt.OrdinalTableRVA + i * 2, buf, 0, 2); int ordinal = BitConverter.ToInt16(buf, 0) + (int)edt.OrdinalBase; string name = null; if (edt.NamePointerRVA != 0) { module.__ReadDataFromRVA((int)edt.NamePointerRVA + i * 4, buf, 0, 4); module.__ReadDataFromRVA(BitConverter.ToInt32(buf, 0), buf, 0, buf.Length); int len = 0; while (buf[len] != 0) len++; name = Encoding.ASCII.GetString(buf, 0, len); } int token = GetTokenFromExportOrdinal(module, edt, ordinal); if (token == -1) { continue; } List<ExportedMethod> list; if (!methods.TryGetValue(token, out list)) { list = new List<ExportedMethod>(); methods.Add(token, list); } ExportedMethod method; method.name = name; method.ordinal = ordinal; list.Add(method); } return methods; }
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(PEHeader))]; BaseStream.Read(buffer, 0, buffer.Length); IntPtr hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); header = (PEHeader)Marshal.PtrToStructure(hdrPtr, typeof(PEHeader)); Marshal.FreeHGlobal(hdrPtr); Recognized = header.signature == SIGNATURE; if (!Recognized) { return; } Type = "Portable Executable (PE)"; if (header.coff.optionalHeader.magic == PE32Plus) { BaseStream.Position -= 4; buffer = new byte[Marshal.SizeOf(typeof(WindowsHeader64))]; BaseStream.Read(buffer, 0, buffer.Length); hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); winHeader = (WindowsHeader64)Marshal.PtrToStructure(hdrPtr, typeof(WindowsHeader64)); Marshal.FreeHGlobal(hdrPtr); } else { buffer = new byte[Marshal.SizeOf(typeof(WindowsHeader))]; BaseStream.Read(buffer, 0, buffer.Length); hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); WindowsHeader hdr32 = (WindowsHeader)Marshal.PtrToStructure(hdrPtr, typeof(WindowsHeader)); Marshal.FreeHGlobal(hdrPtr); winHeader = ToPlus(hdr32); } OperatingSystem reqOs = new OperatingSystem(); switch (winHeader.subsystem) { case Subsystems.IMAGE_SUBSYSTEM_UNKNOWN: reqOs.Name = "Unknown"; break; case Subsystems.IMAGE_SUBSYSTEM_NATIVE: reqOs.Name = "Windows NT"; reqOs.Subsystem = "Native"; break; case Subsystems.IMAGE_SUBSYSTEM_WINDOWS_GUI: reqOs.Name = winHeader.majorSubsystemVersion <= 3 ? "Windows NT" : "Windows"; reqOs.Subsystem = "GUI"; break; case Subsystems.IMAGE_SUBSYSTEM_WINDOWS_CUI: reqOs.Name = winHeader.majorSubsystemVersion <= 3 ? "Windows NT" : "Windows"; reqOs.Subsystem = "Console"; break; case Subsystems.IMAGE_SUBSYSTEM_OS2_CUI: reqOs.Name = "Windows NT"; reqOs.Subsystem = "OS/2"; break; case Subsystems.IMAGE_SUBSYSTEM_POSIX_CUI: reqOs.Name = "Windows NT"; reqOs.Subsystem = "POSIX"; break; case Subsystems.IMAGE_SUBSYSTEM_NATIVE_WINDOWS: reqOs.Name = "Windows"; reqOs.Subsystem = "Native"; break; case Subsystems.IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: reqOs.Name = "Windows CE"; break; case Subsystems.IMAGE_SUBSYSTEM_EFI_APPLICATION: case Subsystems.IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: case Subsystems.IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: case Subsystems.IMAGE_SUBSYSTEM_EFI_ROM: reqOs.Name = "EFI"; break; case Subsystems.IMAGE_SUBSYSTEM_XBOX: reqOs.Name = "Xbox OS"; break; case Subsystems.IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: reqOs.Name = "Windows NT"; reqOs.Subsystem = "Boot environment"; break; default: reqOs.Name = $"Unknown code ${(ushort)winHeader.subsystem}"; break; } reqOs.MajorVersion = winHeader.majorSubsystemVersion; reqOs.MinorVersion = winHeader.minorSubsystemVersion; RequiredOperatingSystem = reqOs; buffer = new byte[Marshal.SizeOf(typeof(ImageDataDirectory))]; directoryEntries = new ImageDataDirectory[winHeader.numberOfRvaAndSizes]; for (int i = 0; i < directoryEntries.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); directoryEntries[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <ImageDataDirectory>(buffer); } buffer = new byte[Marshal.SizeOf(typeof(COFF.SectionHeader))]; sectionHeaders = new COFF.SectionHeader[header.coff.numberOfSections]; for (int i = 0; i < sectionHeaders.Length; i++) { BaseStream.Read(buffer, 0, buffer.Length); sectionHeaders[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian <COFF.SectionHeader>(buffer); } Dictionary <string, COFF.SectionHeader> newSectionHeaders = sectionHeaders.ToDictionary(section => section.name); for (int i = 0; i < directoryEntries.Length; i++) { string tableName; switch (i) { case 0: tableName = ".edata"; break; case 1: tableName = ".idata"; break; case 2: tableName = ".rsrc"; break; case 3: tableName = ".pdata"; break; case 5: tableName = ".reloc"; break; case 6: tableName = ".debug"; break; case 9: tableName = ".tls"; break; case 14: tableName = ".cormeta"; break; default: continue; } if (newSectionHeaders.ContainsKey(tableName)) { continue; } if (directoryEntries[i].rva == 0) { continue; } newSectionHeaders.Add(tableName, new COFF.SectionHeader { characteristics = COFF.SectionFlags.IMAGE_SCN_CNT_INITIALIZED_DATA | COFF.SectionFlags.IMAGE_SCN_MEM_READ, name = tableName, pointerToRawData = RvaToReal(directoryEntries[i].rva, sectionHeaders), virtualAddress = directoryEntries[i].rva, sizeOfRawData = directoryEntries[i].size, virtualSize = directoryEntries[i].size }); } List <byte> chars; List <string> strings = new List <string>(); if (newSectionHeaders.TryGetValue(".edata", out COFF.SectionHeader edata)) { buffer = new byte[Marshal.SizeOf(typeof(ExportDirectoryTable))]; BaseStream.Position = edata.pointerToRawData; BaseStream.Read(buffer, 0, buffer.Length); ExportDirectoryTable edataTable = BigEndianMarshal.ByteArrayToStructureLittleEndian <ExportDirectoryTable>(buffer); BaseStream.Position = RvaToReal(edataTable.nameRva, sectionHeaders); chars = new List <byte>(); while (true) { int ch = BaseStream.ReadByte(); if (ch <= 0) { break; } chars.Add((byte)ch); } moduleName = Encoding.ASCII.GetString(chars.ToArray()); uint[] namePointers = new uint[edataTable.numberOfNamePointers]; exportedNames = new string[edataTable.numberOfNamePointers]; buffer = new byte[Marshal.SizeOf(typeof(uint)) * edataTable.numberOfNamePointers]; BaseStream.Position = RvaToReal(edataTable.namePointerRva, sectionHeaders); BaseStream.Read(buffer, 0, buffer.Length); for (int i = 0; i < edataTable.numberOfNamePointers; i++) { namePointers[i] = BitConverter.ToUInt32(buffer, i * 4); BaseStream.Position = RvaToReal(namePointers[i], sectionHeaders); chars = new List <byte>(); while (true) { int ch = BaseStream.ReadByte(); if (ch <= 0) { break; } chars.Add((byte)ch); } exportedNames[i] = Encoding.ASCII.GetString(chars.ToArray()); } } if (newSectionHeaders.TryGetValue(".idata", out COFF.SectionHeader idata)) { buffer = new byte[Marshal.SizeOf(typeof(ImportDirectoryTable))]; BaseStream.Position = idata.pointerToRawData; List <ImportDirectoryTable> importDirectoryEntries = new List <ImportDirectoryTable>(); while (true) { BaseStream.Read(buffer, 0, buffer.Length); if (buffer.All(b => b == 0)) { break; } importDirectoryEntries.Add(BigEndianMarshal .ByteArrayToStructureLittleEndian <ImportDirectoryTable>(buffer)); } importedNames = new string[importDirectoryEntries.Count]; for (int i = 0; i < importDirectoryEntries.Count; i++) { BaseStream.Position = RvaToReal(importDirectoryEntries[i].nameRva, sectionHeaders); chars = new List <byte>(); while (true) { int ch = BaseStream.ReadByte(); if (ch <= 0) { break; } chars.Add((byte)ch); } importedNames[i] = Encoding.ASCII.GetString(chars.ToArray()); // BeOS R3 uses PE with no subsystem if (importedNames[i].ToLower() == "libbe.so") { reqOs.MajorVersion = 3; reqOs.MinorVersion = 0; reqOs.Subsystem = null; reqOs.Name = "BeOS"; RequiredOperatingSystem = reqOs; } // Singularity appears as a native NT executable else if (importedNames[i].ToLower() == "singularity.v1.dll") { reqOs.MajorVersion = 1; reqOs.MinorVersion = 0; reqOs.Subsystem = null; reqOs.Name = "Singularity"; RequiredOperatingSystem = reqOs; } } } if (newSectionHeaders.TryGetValue(".debug", out COFF.SectionHeader debug) && debug.virtualAddress > 0) { buffer = new byte[Marshal.SizeOf(typeof(DebugDirectory))]; BaseStream.Position = debug.pointerToRawData; BaseStream.Read(buffer, 0, buffer.Length); debugDirectory = BigEndianMarshal.ByteArrayToStructureLittleEndian <DebugDirectory>(buffer); } if (newSectionHeaders.TryGetValue(".rsrc", out COFF.SectionHeader rsrc)) { if (reqOs.Name == "BeOS") { newSectionHeaders.Remove(".rsrc"); rsrc.pointerToRawData = rsrc.virtualAddress; long maxPosition = BaseStream.Length; foreach (KeyValuePair <string, COFF.SectionHeader> kvp in newSectionHeaders) { if (kvp.Value.pointerToRawData <= maxPosition && kvp.Value.pointerToRawData > rsrc.pointerToRawData) { maxPosition = kvp.Value.pointerToRawData; } } rsrc.sizeOfRawData = (uint)(maxPosition - rsrc.pointerToRawData); rsrc.virtualSize = rsrc.sizeOfRawData; newSectionHeaders.Add(".rsrc", rsrc); buffer = new byte[rsrc.sizeOfRawData]; BaseStream.Position = rsrc.pointerToRawData; BaseStream.Read(buffer, 0, buffer.Length); BeosResources = Resources.Decode(buffer); strings.AddRange(from type in BeosResources where type.type == Consts.B_VERSION_INFO_TYPE from resource in type.resources select BigEndianMarshal .ByteArrayToStructureLittleEndian <VersionInfo>(resource.data) into versionInfo select StringHandlers.CToString(versionInfo.long_info, Encoding.UTF8)); } else { WindowsResourcesRoot = GetResourceNode(BaseStream, rsrc.pointerToRawData, rsrc.virtualAddress, rsrc.pointerToRawData, 0, null, 0); Versions = GetVersions().ToArray(); strings.AddRange(from v in Versions from s in v.StringsByLanguage from k in s.Value select k.Value); foreach (ResourceNode rtype in WindowsResourcesRoot.children.Where(r => r.name == "RT_STRING")) { strings.AddRange(GetStrings(rtype)); } } } sectionHeaders = newSectionHeaders.Values.OrderBy(s => s.pointerToRawData).ToArray(); Segment[] segments = new Segment[sectionHeaders.Length]; for (int i = 0; i < segments.Length; i++) { segments[i] = new Segment { Flags = $"{sectionHeaders[i].characteristics}", Name = sectionHeaders[i].name, Offset = sectionHeaders[i].pointerToRawData, Size = sectionHeaders[i].sizeOfRawData } } ; Segments = segments; strings.Sort(); Strings = strings; }
static int GetTokenFromExportOrdinal(Module module, ExportDirectoryTable edt, int ordinal) { PortableExecutableKinds peKind; ImageFileMachine machine; module.GetPEKind(out peKind, out machine); byte[] buf = new byte[16]; module.__ReadDataFromRVA((int)edt.ExportAddressTableRVA + (int)(ordinal - edt.OrdinalBase) * 4, buf, 0, 4); int exportRVA = BitConverter.ToInt32(buf, 0); if (machine == ImageFileMachine.ARM) { // mask out the instruction set selection flag exportRVA &= ~1; } module.__ReadDataFromRVA(exportRVA, buf, 0, 16); int offset; if (machine == ImageFileMachine.I386 && buf[0] == 0xFF && buf[1] == 0x25) { // for x86 the code here is: // FF 25 00 40 40 00 jmp dword ptr ds:[00404000h] offset = 2; } else if (machine == ImageFileMachine.AMD64 && buf[0] == 0x48 && buf[1] == 0xA1) { // for x64 the code here is: // 48 A1 00 40 40 00 00 00 00 00 mov rax,qword ptr [0000000000404000h] // FF E0 jmp rax offset = 2; } else if (machine == ImageFileMachine.ARM && buf[0] == 0xDF && buf[1] == 0xF8 && buf[2] == 0x08 && buf[3] == 0xC0) { // for arm the code here is: // F8DF C008 ldr r12,0040145C // F8DC C000 ldr r12,[r12] // 4760 bx r12 // DEFE __debugbreak // here is the RVA offset = 12; } else { return -1; } int vtableRVA = BitConverter.ToInt32(buf, offset) - (int)module.__ImageBase; module.__ReadDataFromRVA(vtableRVA, buf, 0, 4); return BitConverter.ToInt32(buf, 0); }