static void PrintInspectionPE(Stream stream) { var metadata = Inspector.InspectAsPE(stream).Metadata; var msDosStubHeader = metadata.OfType <Packager.PE.MsDosStubHeader>().FirstOrDefault(); if (msDosStubHeader.Equals(default(Packager.PE.MsDosStubHeader))) { Console.Out.WriteLine("No MSDOS stub header found."); } Console.Out.WriteLine("MSDOS Header:"); stream.Seek(0, SeekOrigin.Begin); var first2 = new byte[2]; stream.Read(first2, 0, 2); Console.Out.WriteLine($" Magic: {first2.Select(b => $"{b:x2}").Aggregate((c, n) => $"{c} {n}")}"); Console.Out.WriteLine($" PE Header Offset: 0x{msDosStubHeader.e_lfanew:x}"); if (msDosStubHeader.e_lfanew % 8 != 0) { Console.Error.WriteLine("WARN: PE header should be aligned to an 8-byte boundary."); } { var peHeader = metadata.OfType <Packager.PE.PEHeader>().FirstOrDefault(); if (peHeader.Equals(default(Packager.PE.PEHeader))) { Console.Out.WriteLine("No PE header found."); } else { stream.Seek(msDosStubHeader.e_lfanew, SeekOrigin.Begin); stream.Read(first2, 0, 2); Console.Out.WriteLine("\r\nPE Header:"); Console.Out.WriteLine($" Magic: {first2.Select(b => $"{b:x2}").Aggregate((c, n) => $"{c} {n}")}"); Console.Out.WriteLine($" Machine: {PackagerUtility.GetEnumDescription<MachineType>(peHeader.mMachine)}"); Console.Out.WriteLine($" Number of sections: {peHeader.mNumberOfSections}"); var ts = DateTime.UnixEpoch.AddSeconds(peHeader.mTimeDateStamp).ToUniversalTime(); Console.Out.WriteLine($" Timestamp: {ts.ToLongDateString()} {ts.ToLongTimeString()} UTC"); Console.Out.WriteLine($" Pointer to symbol table: 0x{peHeader.mPointerToSymbolTable:x}"); Console.Out.WriteLine($" Number of symbols: {peHeader.mNumberOfSymbols}"); Console.Out.WriteLine($" Size of optional PE header: {peHeader.mSizeOfOptionalHeader} (bytes)"); Console.Out.WriteLine($" Characteristics: {PackagerUtility.GetEnumFlagsShortName<PECharacteristics>(peHeader.mCharacteristics, ", ")}"); } } { var pe32 = metadata.OfType <Packager.PE.PEHeaderOption32>().FirstOrDefault(); if (!pe32.Equals(default(Packager.PE.PEHeaderOption32))) { Console.Out.WriteLine("\r\nPE Optional 32-bit Header:"); Console.Out.WriteLine($" Linker version: {pe32.mMajorLinkerVersion}.{pe32.mMinorLinkerVersion}"); Console.Out.WriteLine($" Size of code: {pe32.mSizeOfCode} (bytes)"); Console.Out.WriteLine($" Size of initialized data: {pe32.mSizeOfInitializedData} (bytes)"); Console.Out.WriteLine($" Size of uninitialized data: {pe32.mSizeOfUninitializedData} (bytes)"); Console.Out.WriteLine($" Entry point: 0x{pe32.mAddressOfEntryPoint:x}"); Console.Out.WriteLine($" Base address of code section: 0x{pe32.mBaseOfCode:x}"); Console.Out.WriteLine($" Base address of data section: 0x{pe32.mBaseOfData:x}"); Console.Out.WriteLine($" Base address of image: 0x{pe32.mImageBase:x}"); Console.Out.WriteLine($" Section alignment: {pe32.mSectionAlignment}"); if (pe32.mSectionAlignment < pe32.mFileAlignment) { Console.Error.WriteLine($"ERROR: Section alignment value must be greater than or equal to the file alignment!"); } Console.Out.WriteLine($" File alignment: {pe32.mFileAlignment}{(pe32.mFileAlignment != 512 ? " (Default is 512)" : string.Empty)}"); if (pe32.mFileAlignment < 512 || pe32.mFileAlignment > 65536 || (pe32.mFileAlignment & (pe32.mFileAlignment - 1)) != 0) { Console.Error.WriteLine($"WARN: The value should be a power of 2 between 512 and 64K (inclusive)."); } Console.Out.WriteLine($" Operating system version: {pe32.mMajorOperatingSystemVersion}.{pe32.mMinorOperatingSystemVersion} ({GetWindowsVersion(pe32.mMajorOperatingSystemVersion, pe32.mMinorOperatingSystemVersion)})"); Console.Out.WriteLine($" Image version: {pe32.mMajorImageVersion}.{pe32.mMinorImageVersion}"); Console.Out.WriteLine($" Subsystem version: {pe32.mMajorSubsystemVersion}.{pe32.mMinorSubsystemVersion}"); if (pe32.mWin32VersionValue != 0) { Console.Out.WriteLine($" Win32 version: {pe32.mWin32VersionValue}"); Console.Error.WriteLine($"ERROR: This member is reserved and must be 0!"); } Console.Out.WriteLine($" Size of image: {pe32.mSizeOfImage} (bytes)"); if (pe32.mSizeOfImage % pe32.mSectionAlignment != 0) { Console.Error.WriteLine($"ERROR: Size of image must be a multiple of the section alignment!"); } Console.Out.WriteLine($" Size of headers: {pe32.mSizeOfHeaders} (bytes)"); Console.Out.WriteLine($" Checksum: 0x{pe32.mCheckSum:x}"); Console.Out.WriteLine($" Subsystem: {PackagerUtility.GetEnumDescription<Subsystem>(pe32.mSubsystem)} (0x{pe32.mSubsystem:x})"); Console.Out.WriteLine($" DLL characteristics: {PackagerUtility.GetEnumFlagsShortName<DllCharacteristics>(pe32.mDllCharacteristics, ", ")}"); Console.Out.WriteLine($" Size of stack reserve: {pe32.mSizeOfStackReserve} (bytes)"); Console.Out.WriteLine($" Size of stack commit: {pe32.mSizeOfStackCommit} (bytes)"); Console.Out.WriteLine($" Size of heap reserve: {pe32.mSizeOfHeapReserve} (bytes)"); Console.Out.WriteLine($" Size of heap commit: {pe32.mSizeOfHeapCommit} (bytes)"); Console.Out.WriteLine($" Loader flags (obsolete): 0x{pe32.mLoaderFlags:x}"); Console.Out.WriteLine($" Number of directory entries: {pe32.mNumberOfRvaAndSizes}"); } } { var pe64 = metadata.OfType <Packager.PE.PEHeaderOption64>().FirstOrDefault(); if (!pe64.Equals(default(Packager.PE.PEHeaderOption64))) { Console.Out.WriteLine("\r\nPE Optional 64-bit Header:"); Console.Out.WriteLine($" Linker major version: {pe64.mMajorLinkerVersion}"); Console.Out.WriteLine($" Linker minor version: {pe64.mMinorLinkerVersion}"); Console.Out.WriteLine($" Size of code: {pe64.mSizeOfCode} (bytes)"); Console.Out.WriteLine($" Size of initialized data: {pe64.mSizeOfInitializedData} (bytes)"); Console.Out.WriteLine($" Size of uninitialized data: {pe64.mSizeOfUninitializedData} (bytes)"); Console.Out.WriteLine($" Entry point: 0x{pe64.mAddressOfEntryPoint:x}"); Console.Out.WriteLine($" Base address of code section: 0x{pe64.mBaseOfCode:x}"); Console.Out.WriteLine($" Base address of image: 0x{pe64.mImageBase:x}"); Console.Out.WriteLine($" Section alignment: {pe64.mSectionAlignment}"); if (pe64.mSectionAlignment < pe64.mFileAlignment) { Console.Error.WriteLine($"ERROR: Section alignment value must be greater than or equal to the file alignment!"); } Console.Out.WriteLine($" File alignment: {pe64.mFileAlignment}{(pe64.mFileAlignment != 512 ? " (Default is 512)" : string.Empty)}"); if (pe64.mFileAlignment < 512 || pe64.mFileAlignment > 65536 || (pe64.mFileAlignment & (pe64.mFileAlignment - 1)) != 0) { Console.Error.WriteLine($"WARN: The value should be a power of 2 between 512 and 64K (inclusive)."); } Console.Out.WriteLine($" Operating system version: {pe64.mMajorOperatingSystemVersion}.{pe64.mMinorOperatingSystemVersion} ({GetWindowsVersion(pe64.mMajorOperatingSystemVersion, pe64.mMinorOperatingSystemVersion)})"); Console.Out.WriteLine($" Image version: {pe64.mMajorImageVersion}.{pe64.mMinorImageVersion}"); Console.Out.WriteLine($" Subsystem version: {pe64.mMajorSubsystemVersion}.{pe64.mMinorSubsystemVersion}"); if (pe64.mWin32VersionValue != 0) { Console.Out.WriteLine($" Win32 version: {pe64.mWin32VersionValue}"); Console.Error.WriteLine($"ERROR: This member is reserved and must be 0!"); } Console.Out.WriteLine($" Size of image: {pe64.mSizeOfImage} (bytes)"); if (pe64.mSizeOfImage % pe64.mSectionAlignment != 0) { Console.Error.WriteLine($"ERROR: Size of image must be a multiple of the section alignment!"); } Console.Out.WriteLine($" Size of headers: {pe64.mSizeOfHeaders} (bytes)"); Console.Out.WriteLine($" Checksum: 0x{pe64.mCheckSum:x}"); Console.Out.WriteLine($" Subsystem: {PackagerUtility.GetEnumDescription<Subsystem>(pe64.mSubsystem)} (0x{pe64.mSubsystem:x})"); Console.Out.WriteLine($" DLL characteristics: {PackagerUtility.GetEnumFlagsShortName<DllCharacteristics>(pe64.mDllCharacteristics, ", ")}"); Console.Out.WriteLine($" Size of stack reserve: {pe64.mSizeOfStackReserve} (bytes)"); Console.Out.WriteLine($" Size of stack commit: {pe64.mSizeOfStackCommit} (bytes)"); Console.Out.WriteLine($" Size of heap reserve: {pe64.mSizeOfHeapReserve} (bytes)"); Console.Out.WriteLine($" Size of heap commit: {pe64.mSizeOfHeapCommit} (bytes)"); Console.Out.WriteLine($" Loader flags (obsolete): 0x{pe64.mLoaderFlags:x}"); Console.Out.WriteLine($" Number of directory entries: {pe64.mNumberOfRvaAndSizes}"); } } { var sht = metadata.OfType <SectionHeaderTable>().FirstOrDefault(); Console.Out.WriteLine($"\r\nSection Headers:"); Console.Out.WriteLine($" [Nr] Name VirtualAddress VirtualSize"); Console.Out.WriteLine($" Characteristics"); var i = 0; foreach (var sh in sht) { var name = System.Text.Encoding.ASCII.GetString(BitConverter.GetBytes(sh.Name).TakeWhile(b => b != 0x00).ToArray()); Console.Out.WriteLine($" [{i.ToString().PadLeft(2)}] {name.LeftAlignToSize(8)} {sh.VirtualAddress.RightAlignHexToSize().LeftAlignToSize(14)} {sh.VirtualSize.RightAlignHexToSize()}"); var flagString = PackagerUtility.GetEnumFlagsShortName <SectionHeaderCharacteristics>(sh.Characteristics, ", "); Console.Out.WriteLine($" {flagString}"); i++; } } { var dd = metadata.OfType <PEDataDictionary>().FirstOrDefault(); if (!dd.Equals(default(PEDataDictionary))) { Console.Out.WriteLine("\r\nPE Data Dictionaries:"); var i = 0; foreach (var dde in dd) { if (dde.RelativeVirtualAddress > 0) { Console.Out.WriteLine($" {Enum.GetName(typeof(PEDataDictionaryIndex), i)?.LeftAlignToSize(30) ?? string.Empty} at 0x{dde.RelativeVirtualAddress:x}"); } i++; } } } var verbosity = 1; { var idt = metadata.OfType <PEImportDirectoryTable>().FirstOrDefault(); var ilts = metadata.OfType <PEImportLookupTable>().ToArray(); if (idt == default(PEImportDirectoryTable)) { Console.Error.WriteLine("WARN: Missing Import Directory Table.."); } else { if (ilts.Length == 0) { Console.Error.WriteLine("ERROR: Missing Import Lookup Table!"); } if (ilts.Length != idt.Count) { Console.Error.WriteLine($"ERROR: Import Lookup Table count ({ilts.Length}) did not match directory table entry count ({idt.Count})!"); } Console.Out.WriteLine("\r\nImport Directory Table:"); var i = 0; foreach (var ide in idt) { Console.Out.WriteLine($" {ide.Name}"); if (verbosity > 1) { var missingNames = 0; foreach (var ile in ilts[i]) { if (!string.IsNullOrEmpty(ile.Value)) { Console.Out.WriteLine($" {ile.Value}"); } else { missingNames++; } } if (missingNames > 0) { Console.Out.WriteLine($" ...and {missingNames} unresolvable ordinal imports"); } } i++; } } } }
static void PrintInspectionElf64(Stream stream) { var metadata = Inspector.InspectAsElf64(stream).Metadata; var header = metadata.OfType <Packager.Elf.Elf64.Header64>().FirstOrDefault(); if (header.Equals(default(Packager.Elf.Elf64.Header64))) { Console.Out.WriteLine("No Elf64 header found."); } Console.Out.WriteLine("ELF Header:"); stream.Seek(0, SeekOrigin.Begin); var first16 = new byte[16]; stream.Read(first16, 0, 16); var first16String = first16.Select(b => $"{b:x2}").Aggregate((c, n) => $"{c} {n}"); Console.Out.WriteLine($" Magic: {first16String}"); Console.Out.WriteLine($" Class: {PackagerUtility.GetEnumDescription(header.EI_CLASS)}"); Console.Out.WriteLine($" Data: {PackagerUtility.GetEnumDescription(header.EI_DATA)}"); Console.Out.WriteLine($" Version: {PackagerUtility.GetEnumDescription(header.EI_VERSION)}"); Console.Out.WriteLine($" OS/ABI: {PackagerUtility.GetEnumDescription(header.EI_OSABI)}"); Console.Out.WriteLine($" ABI Version: {header.EI_ABIVERSION}"); Console.Out.WriteLine($" Type: {PackagerUtility.GetEnumDescription(header.E_TYPE)}"); Console.Out.WriteLine($" Machine: {PackagerUtility.GetEnumDescription(header.E_MACHINE)}"); Console.Out.WriteLine($" Version: {PackagerUtility.GetEnumDescription(header.E_VERSION)}"); Console.Out.WriteLine($" Entry point address: 0x{header.E_ENTRY:x}"); Console.Out.WriteLine($" Start of program headers: {header.E_PHOFF} (bytes into file)"); Console.Out.WriteLine($" Start of section headers: {header.E_SHOFF} (bytes into file)"); Console.Out.WriteLine($" Flags: 0x{header.E_FLAGS:x}"); Console.Out.WriteLine($" Size of this header: {header.E_EHSIZE} (bytes)"); Console.Out.WriteLine($" Size of program headers: {header.E_PHENTSIZE} (bytes)"); Console.Out.WriteLine($" Number of program headers: {header.E_PHNUM}"); Console.Out.WriteLine($" Size of section headers: {header.E_SHENTSIZE} (bytes)"); Console.Out.WriteLine($" Number of section headers: {header.E_SHNUM}"); Console.Out.WriteLine($" Section header string table index: {header.E_SHSTRNDX}"); Console.Out.WriteLine($"\r\nSection Headers:"); Console.Out.WriteLine($" [Nr] Name Type Address Offset"); Console.Out.WriteLine($" Size EntSize Flags Link Info Align"); var sectionHeaders = metadata.OfType <Packager.Elf.Elf64.SectionHeader64>().ToArray(); var sectionHeaderNames = new Dictionary <UInt32, string>(); long?sectionHeaderNameTableOffset = header.E_SHSTRNDX == SpecialSectionIndexes.SHN_UNDEF ? default(long?) : (long)sectionHeaders[header.E_SHSTRNDX].SH_OFFSET; var i = 0; foreach (var sh in sectionHeaders) { string name = "<MISSING TABLE>"; if (sectionHeaderNameTableOffset != null) { stream.Seek((long)sectionHeaderNameTableOffset + sh.SH_NAME, SeekOrigin.Begin); name = stream.ReadNulTerminatedString(); sectionHeaderNames.Add(sh.SH_NAME, name); } var flagString = PackagerUtility.GetEnumFlagsShortName <SectionHeaderFlags>(sh.SH_FLAGS); Console.Out.WriteLine($" [{i.ToString().PadLeft(2)}] {name.LeftAlignToSize(17)} {PackagerUtility.GetEnumAttributeValue<SectionHeaderType, ShortNameAttribute>(sh.SH_TYPE, sn => sn.DisplayName).LeftAlignToSize(16)} {sh.SH_ADDR.RightAlignHexToSize()} {sh.SH_OFFSET.RightAlignHexToSize()}"); Console.Out.WriteLine($" {sh.SH_SIZE.RightAlignHexToSize()} {sh.SH_ENTSIZE.RightAlignHexToSize()} {flagString.LeftAlignToSize(4)} {sh.SH_LINK.RightAlignDecToSize(4, ' ')} {sh.SH_INFO.RightAlignDecToSize(4, ' ')} {sh.SH_ADDRALIGN.RightAlignDecToSize(4, ' ')}"); i++; } Console.Out.WriteLine("Key to Flags:"); Console.Out.WriteLine(" W (write), A (alloc), X (execute), M (merge), S (strings), I (info),"); Console.Out.WriteLine(" L (link order), O (extra OS processing required), G (group), T (TLS),"); Console.Out.WriteLine(" C (compressed), o (OS specific), E (exclude), p (processor specific)"); Console.Out.WriteLine("\r\nProgram Headers:"); Console.Out.WriteLine(" Type Offset VirtAddr PhysAddr"); Console.Out.WriteLine(" FileSiz MemSiz Flags Align"); var programHeaders = metadata.OfType <Packager.Elf.Elf64.ProgramHeader64>().ToArray(); foreach (var ph in programHeaders) { var flagString = new StringBuilder(); flagString.Append(((SegmentPermissionFlags)ph.P_FLAGS).HasFlag(SegmentPermissionFlags.PF_R) ? 'R' : ' '); flagString.Append(((SegmentPermissionFlags)ph.P_FLAGS).HasFlag(SegmentPermissionFlags.PF_W) ? 'W' : ' '); flagString.Append(((SegmentPermissionFlags)ph.P_FLAGS).HasFlag(SegmentPermissionFlags.PF_X) ? 'E' : ' '); Console.Out.WriteLine($" {PackagerUtility.GetEnumAttributeValue<ProgramHeaderType, ShortNameAttribute>(ph.P_TYPE, s => s.DisplayName).LeftAlignToSize(13)} 0x{ph.P_OFFSET.RightAlignHexToSize()} 0x{ph.P_VADDR.RightAlignHexToSize()} 0x{ph.P_PADDR.RightAlignHexToSize()}"); Console.Out.WriteLine($" 0x{ph.P_FILESZ.RightAlignHexToSize()} 0x{ph.P_MEMSZ.RightAlignHexToSize()} {flagString.LeftAlignToSize(6)} 0x{ph.P_ALIGN:x}"); } Console.Out.WriteLine("\r\nSection to Segment mapping:"); Console.Out.WriteLine(" Segment Sections..."); i = 0; foreach (var ph in programHeaders) { var shdrs = sectionHeaders .Where(sh => (sh.SH_ADDR > 0 || sh.SH_ENTSIZE > 0) && sh.SH_ADDR >= ph.P_VADDR && sh.SH_ADDR + sh.SH_SIZE <= ph.P_VADDR + ph.P_MEMSZ) .Select(sh => sectionHeaderNames[sh.SH_NAME]).ToArray(); var shdrNames = shdrs.Length == 0 ? string.Empty : shdrs.Aggregate((c, n) => $"{c} {n}"); Console.Out.WriteLine($" {i:00} {shdrNames}"); i++; } }