diff --git a/Steamless.API/PE64/NativeApi64.cs b/Steamless.API/PE64/NativeApi64.cs new file mode 100644 index 0000000..e5dfdc8 --- /dev/null +++ b/Steamless.API/PE64/NativeApi64.cs @@ -0,0 +1,599 @@ +/** + * Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com] + * + * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License. + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to + * Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. + * + * By using Steamless, you agree to the above license and its terms. + * + * Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were + * made. You must do so in any reasonable manner, but not in any way that suggests the licensor + * endorses you or your use. + * + * Non-Commercial - You may not use the material (Steamless) for commercial purposes. + * + * No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the + * modified material. You are, however, allowed to submit the modified works back to the original + * Steamless project in attempt to have it added to the original project. + * + * You may not apply legal terms or technological measures that legally restrict others + * from doing anything the license permits. + * + * No warranties are given. + */ + +namespace Steamless.API.PE64 +{ + using System; + using System.Runtime.InteropServices; + + public class NativeApi64 + { + /// + /// IMAGE_DOS_HEADER Structure + /// + [StructLayout(LayoutKind.Sequential)] + public struct ImageDosHeader64 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public char[] e_magic; + + public ushort e_cblp; + public ushort e_cp; + public ushort e_crlc; + public ushort e_cparhdr; + public ushort e_minalloc; + public ushort e_maxalloc; + public ushort e_ss; + public ushort e_sp; + public ushort e_csum; + public ushort e_ip; + public ushort e_cs; + public ushort e_lfarlc; + public ushort e_ovno; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public ushort[] e_res1; + + public ushort e_oemid; + public ushort e_oeminfo; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public ushort[] e_res2; + + public int e_lfanew; + + /// + /// Gets if this structure is valid for a PE file. + /// + public bool IsValid => new string(this.e_magic) == "MZ"; + } + + /// + /// IMAGE_NT_HEADERS Structure + /// + [StructLayout(LayoutKind.Explicit)] + public struct ImageNtHeaders64 + { + [FieldOffset(0)] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public char[] Signature; + + [FieldOffset(4)] + public ImageFileHeader64 FileHeader; + + [FieldOffset(24)] + public ImageOptionalHeader64 OptionalHeader; + + /// + /// Gets if this structure is valid for a PE file. + /// + public bool IsValid => new string(this.Signature).Trim('\0') == "PE"; + } + + /// + /// IMAGE_FILE_HEADER Structure + /// + [StructLayout(LayoutKind.Sequential)] + public struct ImageFileHeader64 + { + public ushort Machine; + public ushort NumberOfSections; + public uint TimeDateStamp; + public uint PointerToSymbolTable; + public uint NumberOfSymbols; + public ushort SizeOfOptionalHeader; + public ushort Characteristics; + } + + /// + /// Machine Type Enumeration + /// + public enum MachineType : ushort + { + Native = 0, + I386 = 0x014C, + Itanium = 0x0200, + X64 = 0x8664 + } + + /// + /// Magic Type Enumeration + /// + public enum MagicType : ushort + { + ImageNtOptionalHdr32Magic = 0x10B, + ImageNtOptionalHdr64Magic = 0x20B + } + + /// + /// Sub System Type Enumeration + /// + public enum SubSystemType : ushort + { + ImageSubsystemUnknown = 0, + ImageSubsystemNative = 1, + ImageSubsystemWindowsGui = 2, + ImageSubsystemWindowsCui = 3, + ImageSubsystemPosixCui = 7, + ImageSubsystemWindowsCeGui = 9, + ImageSubsystemEfiApplication = 10, + ImageSubsystemEfiBootServiceDriver = 11, + ImageSubsystemEfiRuntimeDriver = 12, + ImageSubsystemEfiRom = 13, + ImageSubsystemXbox = 14 + } + + /// + /// Dll Characteristics Type Enumeration + /// + public enum DllCharacteristicsType : ushort + { + Reserved0 = 0x0001, + Reserved1 = 0x0002, + Reserved2 = 0x0004, + Reserved3 = 0x0008, + ImageDllCharacteristicsDynamicBase = 0x0040, + ImageDllCharacteristicsForceIntegrity = 0x0080, + ImageDllCharacteristicsNxCompat = 0x0100, + ImageDllcharacteristicsNoIsolation = 0x0200, + ImageDllcharacteristicsNoSeh = 0x0400, + ImageDllcharacteristicsNoBind = 0x0800, + Reserved4 = 0x1000, + ImageDllcharacteristicsWdmDriver = 0x2000, + ImageDllcharacteristicsTerminalServerAware = 0x8000 + } + + /// + /// IMAGE_OPTIONAL_HEADER Structure + /// + [StructLayout(LayoutKind.Explicit)] + public struct ImageOptionalHeader64 + { + [FieldOffset(0)] + public MagicType Magic; + + [FieldOffset(2)] + public byte MajorLinkerVersion; + + [FieldOffset(3)] + public byte MinorLinkerVersion; + + [FieldOffset(4)] + public uint SizeOfCode; + + [FieldOffset(8)] + public uint SizeOfInitializedData; + + [FieldOffset(12)] + public uint SizeOfUninitializedData; + + [FieldOffset(16)] + public uint AddressOfEntryPoint; + + [FieldOffset(20)] + public uint BaseOfCode; + + [FieldOffset(24)] + public ulong ImageBase; + + [FieldOffset(32)] + public uint SectionAlignment; + + [FieldOffset(36)] + public uint FileAlignment; + + [FieldOffset(40)] + public ushort MajorOperatingSystemVersion; + + [FieldOffset(42)] + public ushort MinorOperatingSystemVersion; + + [FieldOffset(44)] + public ushort MajorImageVersion; + + [FieldOffset(46)] + public ushort MinorImageVersion; + + [FieldOffset(48)] + public ushort MajorSubsystemVersion; + + [FieldOffset(50)] + public ushort MinorSubsystemVersion; + + [FieldOffset(52)] + public uint Win32VersionValue; + + [FieldOffset(56)] + public uint SizeOfImage; + + [FieldOffset(60)] + public uint SizeOfHeaders; + + [FieldOffset(64)] + public uint CheckSum; + + [FieldOffset(68)] + public SubSystemType Subsystem; + + [FieldOffset(70)] + public DllCharacteristicsType DllCharacteristics; + + [FieldOffset(72)] + public ulong SizeOfStackReserve; + + [FieldOffset(80)] + public ulong SizeOfStackCommit; + + [FieldOffset(88)] + public ulong SizeOfHeapReserve; + + [FieldOffset(96)] + public ulong SizeOfHeapCommit; + + [FieldOffset(104)] + public uint LoaderFlags; + + [FieldOffset(108)] + public uint NumberOfRvaAndSizes; + + [FieldOffset(112)] + public ImageDataDirectory64 ExportTable; + + [FieldOffset(120)] + public ImageDataDirectory64 ImportTable; + + [FieldOffset(128)] + public ImageDataDirectory64 ResourceTable; + + [FieldOffset(136)] + public ImageDataDirectory64 ExceptionTable; + + [FieldOffset(144)] + public ImageDataDirectory64 CertificateTable; + + [FieldOffset(152)] + public ImageDataDirectory64 BaseRelocationTable; + + [FieldOffset(160)] + public ImageDataDirectory64 Debug; + + [FieldOffset(168)] + public ImageDataDirectory64 Architecture; + + [FieldOffset(176)] + public ImageDataDirectory64 GlobalPtr; + + [FieldOffset(184)] + public ImageDataDirectory64 TLSTable; + + [FieldOffset(192)] + public ImageDataDirectory64 LoadConfigTable; + + [FieldOffset(200)] + public ImageDataDirectory64 BoundImport; + + [FieldOffset(208)] + public ImageDataDirectory64 IAT; + + [FieldOffset(216)] + public ImageDataDirectory64 DelayImportDescriptor; + + [FieldOffset(224)] + public ImageDataDirectory64 CLRRuntimeHeader; + + [FieldOffset(232)] + public ImageDataDirectory64 Reserved; + } + + /// + /// IMAGE_DATA_DIRECTORY Structure + /// + [StructLayout(LayoutKind.Sequential)] + public struct ImageDataDirectory64 + { + public uint VirtualAddress; + public uint Size; + } + + /// + /// IMAGE_SECTION_HEADER Structure + /// + [StructLayout(LayoutKind.Explicit)] + public struct ImageSectionHeader64 + { + [FieldOffset(0)] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public char[] Name; + + [FieldOffset(8)] + public uint VirtualSize; + + [FieldOffset(12)] + public uint VirtualAddress; + + [FieldOffset(16)] + public uint SizeOfRawData; + + [FieldOffset(20)] + public uint PointerToRawData; + + [FieldOffset(24)] + public uint PointerToRelocations; + + [FieldOffset(28)] + public uint PointerToLinenumbers; + + [FieldOffset(32)] + public ushort NumberOfRelocations; + + [FieldOffset(34)] + public ushort NumberOfLinenumbers; + + [FieldOffset(36)] + public DataSectionFlags Characteristics; + + /// + /// Gets the section name of this current section object. + /// + public string SectionName => new string(this.Name).Trim('\0'); + + /// + /// Gets if this structure is valid for a PE file. + /// + public bool IsValid => this.SizeOfRawData != 0 && this.PointerToRawData != 0; + } + + /// + /// Data Section Flags Enumeration + /// + [Flags] + public enum DataSectionFlags : uint + { + /// + /// Reserved for future use. + /// + TypeReg = 0x00000000, + + /// + /// Reserved for future use. + /// + TypeDsect = 0x00000001, + + /// + /// Reserved for future use. + /// + TypeNoLoad = 0x00000002, + + /// + /// Reserved for future use. + /// + TypeGroup = 0x00000004, + + /// + /// The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. + /// + TypeNoPadded = 0x00000008, + + /// + /// Reserved for future use. + /// + TypeCopy = 0x00000010, + + /// + /// The section contains executable code. + /// + ContentCode = 0x00000020, + + /// + /// The section contains initialized data. + /// + ContentInitializedData = 0x00000040, + + /// + /// The section contains uninitialized data. + /// + ContentUninitializedData = 0x00000080, + + /// + /// Reserved for future use. + /// + LinkOther = 0x00000100, + + /// + /// The section contains comments or other information. The .drectve section has this type. This is valid for object files only. + /// + LinkInfo = 0x00000200, + + /// + /// Reserved for future use. + /// + TypeOver = 0x00000400, + + /// + /// The section will not become part of the image. This is valid only for object files. + /// + LinkRemove = 0x00000800, + + /// + /// The section contains COMDAT data. For more information, see section 5.5.6, COMDAT Sections (Object Only). This is valid only for object files. + /// + LinkComDat = 0x00001000, + + /// + /// Reset speculative exceptions handling bits in the TLB entries for this section. + /// + NoDeferSpecExceptions = 0x00004000, + + /// + /// The section contains data referenced through the global pointer (GP). + /// + RelativeGp = 0x00008000, + + /// + /// Reserved for future use. + /// + MemPurgeable = 0x00020000, + + /// + /// Reserved for future use. + /// + Memory16Bit = 0x00020000, + + /// + /// Reserved for future use. + /// + MemoryLocked = 0x00040000, + + /// + /// Reserved for future use. + /// + MemoryPreload = 0x00080000, + + /// + /// Align data on a 1-byte boundary. Valid only for object files. + /// + Align1Bytes = 0x00100000, + + /// + /// Align data on a 2-byte boundary. Valid only for object files. + /// + Align2Bytes = 0x00200000, + + /// + /// Align data on a 4-byte boundary. Valid only for object files. + /// + Align4Bytes = 0x00300000, + + /// + /// Align data on an 8-byte boundary. Valid only for object files. + /// + Align8Bytes = 0x00400000, + + /// + /// Align data on a 16-byte boundary. Valid only for object files. + /// + Align16Bytes = 0x00500000, + + /// + /// Align data on a 32-byte boundary. Valid only for object files. + /// + Align32Bytes = 0x00600000, + + /// + /// Align data on a 64-byte boundary. Valid only for object files. + /// + Align64Bytes = 0x00700000, + + /// + /// Align data on a 128-byte boundary. Valid only for object files. + /// + Align128Bytes = 0x00800000, + + /// + /// Align data on a 256-byte boundary. Valid only for object files. + /// + Align256Bytes = 0x00900000, + + /// + /// Align data on a 512-byte boundary. Valid only for object files. + /// + Align512Bytes = 0x00A00000, + + /// + /// Align data on a 1024-byte boundary. Valid only for object files. + /// + Align1024Bytes = 0x00B00000, + + /// + /// Align data on a 2048-byte boundary. Valid only for object files. + /// + Align2048Bytes = 0x00C00000, + + /// + /// Align data on a 4096-byte boundary. Valid only for object files. + /// + Align4096Bytes = 0x00D00000, + + /// + /// Align data on an 8192-byte boundary. Valid only for object files. + /// + Align8192Bytes = 0x00E00000, + + /// + /// The section contains extended relocations. + /// + LinkExtendedRelocationOverflow = 0x01000000, + + /// + /// The section can be discarded as needed. + /// + MemoryDiscardable = 0x02000000, + + /// + /// The section cannot be cached. + /// + MemoryNotCached = 0x04000000, + + /// + /// The section is not pageable. + /// + MemoryNotPaged = 0x08000000, + + /// + /// The section can be shared in memory. + /// + MemoryShared = 0x10000000, + + /// + /// The section can be executed as code. + /// + MemoryExecute = 0x20000000, + + /// + /// The section can be read. + /// + MemoryRead = 0x40000000, + + /// + /// The section can be written to. + /// + MemoryWrite = 0x80000000 + } + + /// + /// IMAGE_TLS_DIRECTORY Structure + /// + [StructLayout(LayoutKind.Sequential)] + public struct ImageTlsDirectory64 + { + public ulong StartAddressOfRawData; + public ulong EndAddressOfRawData; + public ulong AddressOfIndex; + public ulong AddressOfCallBacks; + public uint SizeOfZeroFill; + public uint Characteristics; + } + } +} \ No newline at end of file diff --git a/Steamless.API/PE64/Pe64File.cs b/Steamless.API/PE64/Pe64File.cs new file mode 100644 index 0000000..f2a096d --- /dev/null +++ b/Steamless.API/PE64/Pe64File.cs @@ -0,0 +1,421 @@ +/** + * Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com] + * + * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License. + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to + * Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. + * + * By using Steamless, you agree to the above license and its terms. + * + * Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were + * made. You must do so in any reasonable manner, but not in any way that suggests the licensor + * endorses you or your use. + * + * Non-Commercial - You may not use the material (Steamless) for commercial purposes. + * + * No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the + * modified material. You are, however, allowed to submit the modified works back to the original + * Steamless project in attempt to have it added to the original project. + * + * You may not apply legal terms or technological measures that legally restrict others + * from doing anything the license permits. + * + * No warranties are given. + */ + +namespace Steamless.API.PE64 +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Runtime.InteropServices; + + /// + /// Portable Executable (64bit) Class + /// + public class Pe64File + { + /// + /// Default Constructor + /// + public Pe64File() + { + } + + /// + /// Overloaded Constructor + /// + /// + public Pe64File(string file) + { + this.FilePath = file; + } + + /// + /// Parses a Win64 PE file. + /// + /// + /// + public bool Parse(string file = null) + { + // Prepare the class variables.. + if (file != null) + this.FilePath = file; + + this.FileData = null; + this.DosHeader = new NativeApi64.ImageDosHeader64(); + this.NtHeaders = new NativeApi64.ImageNtHeaders64(); + this.DosStubSize = 0; + this.DosStubOffset = 0; + this.DosStubData = null; + this.Sections = new List(); + this.SectionData = new List(); + this.TlsDirectory = new NativeApi64.ImageTlsDirectory64(); + this.TlsCallbacks = new List(); + + // Ensure a file path has been set.. + if (string.IsNullOrEmpty(this.FilePath) || !File.Exists(this.FilePath)) + return false; + + // Read the file data.. + this.FileData = File.ReadAllBytes(this.FilePath); + + // Ensure we have valid data by the overall length.. + if (this.FileData.Length < (Marshal.SizeOf(typeof(NativeApi64.ImageDosHeader64)) + Marshal.SizeOf(typeof(NativeApi64.ImageNtHeaders64)))) + return false; + + // Read the file headers.. + this.DosHeader = Pe64Helpers.GetStructure(this.FileData); + this.NtHeaders = Pe64Helpers.GetStructure(this.FileData, this.DosHeader.e_lfanew); + + // Validate the headers.. + if (!this.DosHeader.IsValid || !this.NtHeaders.IsValid) + return false; + + // Read and store the dos header if it exists.. + this.DosStubSize = (uint)(this.DosHeader.e_lfanew - Marshal.SizeOf(typeof(NativeApi64.ImageDosHeader64))); + if (this.DosStubSize > 0) + { + this.DosStubOffset = (uint)Marshal.SizeOf(typeof(NativeApi64.ImageDosHeader64)); + this.DosStubData = new byte[this.DosStubSize]; + Array.Copy(this.FileData, (int)this.DosStubOffset, this.DosStubData, 0, (int)this.DosStubSize); + } + + // Read the file sections.. + for (var x = 0; x < this.NtHeaders.FileHeader.NumberOfSections; x++) + { + var section = Pe64Helpers.GetSection(this.FileData, x, this.DosHeader, this.NtHeaders); + this.Sections.Add(section); + + // Get the sections data.. + var sectionData = new byte[this.GetAlignment(section.SizeOfRawData, this.NtHeaders.OptionalHeader.FileAlignment)]; + Array.Copy(this.FileData, section.PointerToRawData, sectionData, 0, section.SizeOfRawData); + this.SectionData.Add(sectionData); + } + + try + { + // Obtain the file overlay if one exists.. + var lastSection = this.Sections.Last(); + var fileSize = lastSection.SizeOfRawData + lastSection.PointerToRawData; + if (fileSize < this.FileData.Length) + { + this.OverlayData = new byte[this.FileData.Length - fileSize]; + Array.Copy(this.FileData, fileSize, this.OverlayData, 0, this.FileData.Length - fileSize); + } + } + catch + { + return false; + } + + // Read the files Tls information if available.. + if (this.NtHeaders.OptionalHeader.TLSTable.VirtualAddress != 0) + { + // Get the file offset to the Tls data.. + var tls = this.NtHeaders.OptionalHeader.TLSTable; + var addr = this.GetFileOffsetFromRva(tls.VirtualAddress); + + // Read the Tls directory.. + this.TlsDirectory = Pe64Helpers.GetStructure(this.FileData, (int)addr); + + // Read the Tls callbacks.. + addr = this.GetRvaFromVa(this.TlsDirectory.AddressOfCallBacks); + addr = this.GetFileOffsetFromRva(addr); + + // Loop until we hit a null pointer.. + var count = 0; + while (true) + { + var callback = BitConverter.ToUInt64(this.FileData, (int)addr + (count * 4)); + if (callback == 0) + break; + + this.TlsCallbacks.Add(callback); + count++; + } + } + + return true; + } + + /// + /// Determines if the current file is 64bit. + /// + /// + public bool IsFile64Bit() + { + return (this.NtHeaders.FileHeader.Machine & (uint)NativeApi64.MachineType.X64) == (uint)NativeApi64.MachineType.X64; + } + + /// + /// Determines if the file has a section containing the given name. + /// + /// + /// + public bool HasSection(string name) + { + return this.Sections.Any(s => string.Compare(s.SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0); + } + + /// + /// Obtains a section by its name. + /// + /// + /// + public NativeApi64.ImageSectionHeader64 GetSection(string name) + { + return this.Sections.FirstOrDefault(s => string.Compare(s.SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0); + } + + /// + /// Obtains the owner section of the given rva. + /// + /// + /// + public NativeApi64.ImageSectionHeader64 GetOwnerSection(uint rva) + { + foreach (var s in this.Sections) + { + var size = s.VirtualSize; + if (size == 0) + size = s.SizeOfRawData; + + if ((rva >= s.VirtualAddress) && (rva < s.VirtualAddress + size)) + return s; + } + + return default(NativeApi64.ImageSectionHeader64); + } + + /// + /// Obtains the owner section of the given rva. + /// + /// + /// + public NativeApi64.ImageSectionHeader64 GetOwnerSection(ulong rva) + { + foreach (var s in this.Sections) + { + var size = s.VirtualSize; + if (size == 0) + size = s.SizeOfRawData; + + if ((rva >= s.VirtualAddress) && (rva < s.VirtualAddress + size)) + return s; + } + + return default(NativeApi64.ImageSectionHeader64); + } + + /// + /// Obtains a sections data by its index. + /// + /// + /// + public byte[] GetSectionData(int index) + { + if (index < 0 || index > this.Sections.Count) + return null; + + return this.SectionData[index]; + } + + /// + /// Obtains a sections data by its name. + /// + /// + /// + public byte[] GetSectionData(string name) + { + for (var x = 0; x < this.Sections.Count; x++) + { + if (string.Compare(this.Sections[x].SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0) + return this.SectionData[x]; + } + + return null; + } + + /// + /// Gets a sections index by its name. + /// + /// + /// + public int GetSectionIndex(string name) + { + for (var x = 0; x < this.Sections.Count; x++) + { + if (string.Compare(this.Sections[x].SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0) + return x; + } + + return -1; + } + + /// + /// Gets a sections index by its name. + /// + /// + /// + public int GetSectionIndex(NativeApi64.ImageSectionHeader64 section) + { + return this.Sections.IndexOf(section); + } + + /// + /// Removes a section from the files section list. + /// + /// + /// + public bool RemoveSection(NativeApi64.ImageSectionHeader64 section) + { + var index = this.Sections.IndexOf(section); + if (index == -1) + return false; + + this.Sections.RemoveAt(index); + this.SectionData.RemoveAt(index); + + return true; + } + + /// + /// Rebuilds the sections by aligning them as needed. Updates the Nt headers to + /// correct the new SizeOfImage after alignment is completed. + /// + public void RebuildSections() + { + for (var x = 0; x < this.Sections.Count; x++) + { + // Obtain the current section and realign the data.. + var section = this.Sections[x]; + section.VirtualAddress = (uint)this.GetAlignment(section.VirtualAddress, this.NtHeaders.OptionalHeader.SectionAlignment); + section.VirtualSize = (uint)this.GetAlignment(section.VirtualSize, this.NtHeaders.OptionalHeader.SectionAlignment); + section.PointerToRawData = (uint)this.GetAlignment(section.PointerToRawData, this.NtHeaders.OptionalHeader.FileAlignment); + section.SizeOfRawData = (uint)this.GetAlignment(section.SizeOfRawData, this.NtHeaders.OptionalHeader.FileAlignment); + + // Store the sections updates.. + this.Sections[x] = section; + } + + // Update the size of the image.. + var ntHeaders = this.NtHeaders; + ntHeaders.OptionalHeader.SizeOfImage = this.Sections.Last().VirtualAddress + this.Sections.Last().VirtualSize; + this.NtHeaders = ntHeaders; + } + + /// + /// Obtains the relative virtual address from the given virtual address. + /// + /// + /// + public ulong GetRvaFromVa(ulong va) + { + return va - this.NtHeaders.OptionalHeader.ImageBase; + } + + /// + /// Obtains the file offset from the given relative virtual address. + /// + /// + /// + public ulong GetFileOffsetFromRva(ulong rva) + { + var section = this.GetOwnerSection(rva); + return (rva - (section.VirtualAddress - section.PointerToRawData)); + } + + /// + /// Aligns the value based on the given alignment. + /// + /// + /// + /// + public ulong GetAlignment(ulong val, ulong align) + { + return (((val + align - 1) / align) * align); + } + + /// + /// Gets or sets the path to the file being processed. + /// + public string FilePath { get; set; } + + /// + /// Gets or sets the raw file data read from disk. + /// + public byte[] FileData { get; set; } + + /// + /// Gets or sets the dos header of the file. + /// + public NativeApi64.ImageDosHeader64 DosHeader { get; set; } + + /// + /// Gets or sets the NT headers of the file. + /// + public NativeApi64.ImageNtHeaders64 NtHeaders { get; set; } + + /// + /// Gets or sets the optional dos stub size. + /// + public ulong DosStubSize { get; set; } + + /// + /// Gets or sets the optional dos stub offset. + /// + public ulong DosStubOffset { get; set; } + + /// + /// Gets or sets the optional dos stub data. + /// + public byte[] DosStubData { get; set; } + + /// + /// Gets or sets the sections of the file. + /// + public List Sections; + + /// + /// Gets or sets the section data of the file. + /// + public List SectionData; + + /// + /// Gets or sets the overlay data of the file. + /// + public byte[] OverlayData; + + /// + /// Gets or sets the Tls directory of the file. + /// + public NativeApi64.ImageTlsDirectory64 TlsDirectory { get; set; } + + /// + /// Gets or sets a list of Tls callbacks of the file. + /// + public List TlsCallbacks { get; set; } + } +} \ No newline at end of file diff --git a/Steamless.API/PE64/Pe64Helpers.cs b/Steamless.API/PE64/Pe64Helpers.cs new file mode 100644 index 0000000..317aa1a --- /dev/null +++ b/Steamless.API/PE64/Pe64Helpers.cs @@ -0,0 +1,128 @@ +/** + * Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com] + * + * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License. + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to + * Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. + * + * By using Steamless, you agree to the above license and its terms. + * + * Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were + * made. You must do so in any reasonable manner, but not in any way that suggests the licensor + * endorses you or your use. + * + * Non-Commercial - You may not use the material (Steamless) for commercial purposes. + * + * No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the + * modified material. You are, however, allowed to submit the modified works back to the original + * Steamless project in attempt to have it added to the original project. + * + * You may not apply legal terms or technological measures that legally restrict others + * from doing anything the license permits. + * + * No warranties are given. + */ + +namespace Steamless.API.PE64 +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Runtime.InteropServices; + + public class Pe64Helpers + { + /// + /// Converts a byte array to the given structure type. + /// + /// + /// + /// + /// + public static T GetStructure(byte[] data, int offset = 0) + { + var ptr = Marshal.AllocHGlobal(data.Length); + Marshal.Copy(data, offset, ptr, data.Length - offset); + var obj = (T)Marshal.PtrToStructure(ptr, typeof(T)); + Marshal.FreeHGlobal(ptr); + + return obj; + } + + /// + /// Converts the given object back to a byte array. + /// + /// + /// + /// + public static byte[] GetStructureBytes(T obj) + { + var size = Marshal.SizeOf(obj); + var data = new byte[size]; + var ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + Marshal.Copy(ptr, data, 0, size); + Marshal.FreeHGlobal(ptr); + return data; + } + + /// + /// Obtains a section from the given file information. + /// + /// + /// + /// + /// + /// + public static NativeApi64.ImageSectionHeader64 GetSection(byte[] rawData, int index, NativeApi64.ImageDosHeader64 dosHeader, NativeApi64.ImageNtHeaders64 ntHeaders) + { + var sectionSize = Marshal.SizeOf(typeof(NativeApi64.ImageSectionHeader64)); + var optionalHeaderOffset = Marshal.OffsetOf(typeof(NativeApi64.ImageNtHeaders64), "OptionalHeader").ToInt64(); + var dataOffset = dosHeader.e_lfanew + optionalHeaderOffset + ntHeaders.FileHeader.SizeOfOptionalHeader; + + return GetStructure(rawData, (int)dataOffset + (index * sectionSize)); + } + + /// + /// Scans the given data for the given pattern. + /// + /// Notes: + /// Patterns are assumed to be 2 byte hex values with spaces. + /// Wildcards are represented by ??. + /// + /// + /// + /// + public static uint FindPattern(byte[] data, string pattern) + { + try + { + // Trim the pattern from extra whitespace.. + var trimPattern = pattern.Replace(" ", "").Trim(); + + // Convert the pattern to a byte array.. + var patternMask = new List(); + var patternData = Enumerable.Range(0, trimPattern.Length).Where(x => x % 2 == 0) + .Select(x => + { + var bt = trimPattern.Substring(x, 2); + patternMask.Add(!bt.Contains('?')); + return bt.Contains('?') ? (byte)0 : Convert.ToByte(bt, 16); + }).ToArray(); + + // Scan the given data for our pattern.. + for (var x = 0; x < data.Length; x++) + { + if (!patternData.Where((t, y) => patternMask[y] && t != data[x + y]).Any()) + return (uint)x; + } + + return 0; + } + catch + { + return 0; + } + } + } +} \ No newline at end of file diff --git a/Steamless.API/Properties/AssemblyInfo.cs b/Steamless.API/Properties/AssemblyInfo.cs index d9a4d96..d32b314 100644 --- a/Steamless.API/Properties/AssemblyInfo.cs +++ b/Steamless.API/Properties/AssemblyInfo.cs @@ -36,5 +36,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("56c95629-3b34-47fe-b988-04274409294f")] -[assembly: AssemblyVersion("1.0.0.1")] -[assembly: AssemblyFileVersion("1.0.0.1")] \ No newline at end of file +[assembly: AssemblyVersion("1.0.0.2")] +[assembly: AssemblyFileVersion("1.0.0.2")] \ No newline at end of file diff --git a/Steamless.API/Steamless.API.csproj b/Steamless.API/Steamless.API.csproj index 3f8fe1a..9da2089 100644 --- a/Steamless.API/Steamless.API.csproj +++ b/Steamless.API/Steamless.API.csproj @@ -45,6 +45,9 @@ + + + @@ -54,9 +57,7 @@ - - - +