mirror of
https://github.com/atom0s/Steamless.git
synced 2024-12-19 23:07:41 +01:00
Begin initial work on supporting 64bit files.
- Implements the base 64bit file handling / reading. - This is untested and more or just less ported from the 32bit files. May have issues, will resolve as we get there.
This commit is contained in:
parent
9a9aa8894d
commit
a7fa5bb337
5 changed files with 1154 additions and 5 deletions
599
Steamless.API/PE64/NativeApi64.cs
Normal file
599
Steamless.API/PE64/NativeApi64.cs
Normal file
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// IMAGE_DOS_HEADER Structure
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets if this structure is valid for a PE file.
|
||||
/// </summary>
|
||||
public bool IsValid => new string(this.e_magic) == "MZ";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IMAGE_NT_HEADERS Structure
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets if this structure is valid for a PE file.
|
||||
/// </summary>
|
||||
public bool IsValid => new string(this.Signature).Trim('\0') == "PE";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IMAGE_FILE_HEADER Structure
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Machine Type Enumeration
|
||||
/// </summary>
|
||||
public enum MachineType : ushort
|
||||
{
|
||||
Native = 0,
|
||||
I386 = 0x014C,
|
||||
Itanium = 0x0200,
|
||||
X64 = 0x8664
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Magic Type Enumeration
|
||||
/// </summary>
|
||||
public enum MagicType : ushort
|
||||
{
|
||||
ImageNtOptionalHdr32Magic = 0x10B,
|
||||
ImageNtOptionalHdr64Magic = 0x20B
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sub System Type Enumeration
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dll Characteristics Type Enumeration
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IMAGE_OPTIONAL_HEADER Structure
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IMAGE_DATA_DIRECTORY Structure
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ImageDataDirectory64
|
||||
{
|
||||
public uint VirtualAddress;
|
||||
public uint Size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IMAGE_SECTION_HEADER Structure
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the section name of this current section object.
|
||||
/// </summary>
|
||||
public string SectionName => new string(this.Name).Trim('\0');
|
||||
|
||||
/// <summary>
|
||||
/// Gets if this structure is valid for a PE file.
|
||||
/// </summary>
|
||||
public bool IsValid => this.SizeOfRawData != 0 && this.PointerToRawData != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data Section Flags Enumeration
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum DataSectionFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
TypeReg = 0x00000000,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
TypeDsect = 0x00000001,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
TypeNoLoad = 0x00000002,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
TypeGroup = 0x00000004,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
TypeNoPadded = 0x00000008,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
TypeCopy = 0x00000010,
|
||||
|
||||
/// <summary>
|
||||
/// The section contains executable code.
|
||||
/// </summary>
|
||||
ContentCode = 0x00000020,
|
||||
|
||||
/// <summary>
|
||||
/// The section contains initialized data.
|
||||
/// </summary>
|
||||
ContentInitializedData = 0x00000040,
|
||||
|
||||
/// <summary>
|
||||
/// The section contains uninitialized data.
|
||||
/// </summary>
|
||||
ContentUninitializedData = 0x00000080,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
LinkOther = 0x00000100,
|
||||
|
||||
/// <summary>
|
||||
/// The section contains comments or other information. The .drectve section has this type. This is valid for object files only.
|
||||
/// </summary>
|
||||
LinkInfo = 0x00000200,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
TypeOver = 0x00000400,
|
||||
|
||||
/// <summary>
|
||||
/// The section will not become part of the image. This is valid only for object files.
|
||||
/// </summary>
|
||||
LinkRemove = 0x00000800,
|
||||
|
||||
/// <summary>
|
||||
/// The section contains COMDAT data. For more information, see section 5.5.6, COMDAT Sections (Object Only). This is valid only for object files.
|
||||
/// </summary>
|
||||
LinkComDat = 0x00001000,
|
||||
|
||||
/// <summary>
|
||||
/// Reset speculative exceptions handling bits in the TLB entries for this section.
|
||||
/// </summary>
|
||||
NoDeferSpecExceptions = 0x00004000,
|
||||
|
||||
/// <summary>
|
||||
/// The section contains data referenced through the global pointer (GP).
|
||||
/// </summary>
|
||||
RelativeGp = 0x00008000,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
MemPurgeable = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
Memory16Bit = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
MemoryLocked = 0x00040000,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use.
|
||||
/// </summary>
|
||||
MemoryPreload = 0x00080000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 1-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align1Bytes = 0x00100000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 2-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align2Bytes = 0x00200000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 4-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align4Bytes = 0x00300000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on an 8-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align8Bytes = 0x00400000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 16-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align16Bytes = 0x00500000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 32-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align32Bytes = 0x00600000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 64-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align64Bytes = 0x00700000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 128-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align128Bytes = 0x00800000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 256-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align256Bytes = 0x00900000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 512-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align512Bytes = 0x00A00000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 1024-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align1024Bytes = 0x00B00000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 2048-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align2048Bytes = 0x00C00000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on a 4096-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align4096Bytes = 0x00D00000,
|
||||
|
||||
/// <summary>
|
||||
/// Align data on an 8192-byte boundary. Valid only for object files.
|
||||
/// </summary>
|
||||
Align8192Bytes = 0x00E00000,
|
||||
|
||||
/// <summary>
|
||||
/// The section contains extended relocations.
|
||||
/// </summary>
|
||||
LinkExtendedRelocationOverflow = 0x01000000,
|
||||
|
||||
/// <summary>
|
||||
/// The section can be discarded as needed.
|
||||
/// </summary>
|
||||
MemoryDiscardable = 0x02000000,
|
||||
|
||||
/// <summary>
|
||||
/// The section cannot be cached.
|
||||
/// </summary>
|
||||
MemoryNotCached = 0x04000000,
|
||||
|
||||
/// <summary>
|
||||
/// The section is not pageable.
|
||||
/// </summary>
|
||||
MemoryNotPaged = 0x08000000,
|
||||
|
||||
/// <summary>
|
||||
/// The section can be shared in memory.
|
||||
/// </summary>
|
||||
MemoryShared = 0x10000000,
|
||||
|
||||
/// <summary>
|
||||
/// The section can be executed as code.
|
||||
/// </summary>
|
||||
MemoryExecute = 0x20000000,
|
||||
|
||||
/// <summary>
|
||||
/// The section can be read.
|
||||
/// </summary>
|
||||
MemoryRead = 0x40000000,
|
||||
|
||||
/// <summary>
|
||||
/// The section can be written to.
|
||||
/// </summary>
|
||||
MemoryWrite = 0x80000000
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IMAGE_TLS_DIRECTORY Structure
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ImageTlsDirectory64
|
||||
{
|
||||
public ulong StartAddressOfRawData;
|
||||
public ulong EndAddressOfRawData;
|
||||
public ulong AddressOfIndex;
|
||||
public ulong AddressOfCallBacks;
|
||||
public uint SizeOfZeroFill;
|
||||
public uint Characteristics;
|
||||
}
|
||||
}
|
||||
}
|
421
Steamless.API/PE64/Pe64File.cs
Normal file
421
Steamless.API/PE64/Pe64File.cs
Normal file
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Portable Executable (64bit) Class
|
||||
/// </summary>
|
||||
public class Pe64File
|
||||
{
|
||||
/// <summary>
|
||||
/// Default Constructor
|
||||
/// </summary>
|
||||
public Pe64File()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded Constructor
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
public Pe64File(string file)
|
||||
{
|
||||
this.FilePath = file;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a Win64 PE file.
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
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<NativeApi64.ImageSectionHeader64>();
|
||||
this.SectionData = new List<byte[]>();
|
||||
this.TlsDirectory = new NativeApi64.ImageTlsDirectory64();
|
||||
this.TlsCallbacks = new List<ulong>();
|
||||
|
||||
// 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<NativeApi64.ImageDosHeader64>(this.FileData);
|
||||
this.NtHeaders = Pe64Helpers.GetStructure<NativeApi64.ImageNtHeaders64>(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<NativeApi64.ImageTlsDirectory64>(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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the current file is 64bit.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsFile64Bit()
|
||||
{
|
||||
return (this.NtHeaders.FileHeader.Machine & (uint)NativeApi64.MachineType.X64) == (uint)NativeApi64.MachineType.X64;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the file has a section containing the given name.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public bool HasSection(string name)
|
||||
{
|
||||
return this.Sections.Any(s => string.Compare(s.SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a section by its name.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public NativeApi64.ImageSectionHeader64 GetSection(string name)
|
||||
{
|
||||
return this.Sections.FirstOrDefault(s => string.Compare(s.SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains the owner section of the given rva.
|
||||
/// </summary>
|
||||
/// <param name="rva"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains the owner section of the given rva.
|
||||
/// </summary>
|
||||
/// <param name="rva"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a sections data by its index.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetSectionData(int index)
|
||||
{
|
||||
if (index < 0 || index > this.Sections.Count)
|
||||
return null;
|
||||
|
||||
return this.SectionData[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a sections data by its name.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a sections index by its name.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a sections index by its name.
|
||||
/// </summary>
|
||||
/// <param name="section"></param>
|
||||
/// <returns></returns>
|
||||
public int GetSectionIndex(NativeApi64.ImageSectionHeader64 section)
|
||||
{
|
||||
return this.Sections.IndexOf(section);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a section from the files section list.
|
||||
/// </summary>
|
||||
/// <param name="section"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds the sections by aligning them as needed. Updates the Nt headers to
|
||||
/// correct the new SizeOfImage after alignment is completed.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains the relative virtual address from the given virtual address.
|
||||
/// </summary>
|
||||
/// <param name="va"></param>
|
||||
/// <returns></returns>
|
||||
public ulong GetRvaFromVa(ulong va)
|
||||
{
|
||||
return va - this.NtHeaders.OptionalHeader.ImageBase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains the file offset from the given relative virtual address.
|
||||
/// </summary>
|
||||
/// <param name="rva"></param>
|
||||
/// <returns></returns>
|
||||
public ulong GetFileOffsetFromRva(ulong rva)
|
||||
{
|
||||
var section = this.GetOwnerSection(rva);
|
||||
return (rva - (section.VirtualAddress - section.PointerToRawData));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aligns the value based on the given alignment.
|
||||
/// </summary>
|
||||
/// <param name="val"></param>
|
||||
/// <param name="align"></param>
|
||||
/// <returns></returns>
|
||||
public ulong GetAlignment(ulong val, ulong align)
|
||||
{
|
||||
return (((val + align - 1) / align) * align);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the file being processed.
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the raw file data read from disk.
|
||||
/// </summary>
|
||||
public byte[] FileData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the dos header of the file.
|
||||
/// </summary>
|
||||
public NativeApi64.ImageDosHeader64 DosHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the NT headers of the file.
|
||||
/// </summary>
|
||||
public NativeApi64.ImageNtHeaders64 NtHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the optional dos stub size.
|
||||
/// </summary>
|
||||
public ulong DosStubSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the optional dos stub offset.
|
||||
/// </summary>
|
||||
public ulong DosStubOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the optional dos stub data.
|
||||
/// </summary>
|
||||
public byte[] DosStubData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sections of the file.
|
||||
/// </summary>
|
||||
public List<NativeApi64.ImageSectionHeader64> Sections;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the section data of the file.
|
||||
/// </summary>
|
||||
public List<byte[]> SectionData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the overlay data of the file.
|
||||
/// </summary>
|
||||
public byte[] OverlayData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Tls directory of the file.
|
||||
/// </summary>
|
||||
public NativeApi64.ImageTlsDirectory64 TlsDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of Tls callbacks of the file.
|
||||
/// </summary>
|
||||
public List<ulong> TlsCallbacks { get; set; }
|
||||
}
|
||||
}
|
128
Steamless.API/PE64/Pe64Helpers.cs
Normal file
128
Steamless.API/PE64/Pe64Helpers.cs
Normal file
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a byte array to the given structure type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetStructure<T>(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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given object back to a byte array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] GetStructureBytes<T>(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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a section from the given file information.
|
||||
/// </summary>
|
||||
/// <param name="rawData"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="dosHeader"></param>
|
||||
/// <param name="ntHeaders"></param>
|
||||
/// <returns></returns>
|
||||
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<NativeApi64.ImageSectionHeader64>(rawData, (int)dataOffset + (index * sectionSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans the given data for the given pattern.
|
||||
///
|
||||
/// Notes:
|
||||
/// Patterns are assumed to be 2 byte hex values with spaces.
|
||||
/// Wildcards are represented by ??.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
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<bool>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")]
|
||||
[assembly: AssemblyVersion("1.0.0.2")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.2")]
|
|
@ -45,6 +45,9 @@
|
|||
<Compile Include="PE32\NativeApi32.cs" />
|
||||
<Compile Include="PE32\Pe32File.cs" />
|
||||
<Compile Include="PE32\Pe32Helpers.cs" />
|
||||
<Compile Include="PE64\NativeApi64.cs" />
|
||||
<Compile Include="PE64\Pe64File.cs" />
|
||||
<Compile Include="PE64\Pe64Helpers.cs" />
|
||||
<Compile Include="SteamlessEvents.cs" />
|
||||
<Compile Include="Events\LogMessageEventArgs.cs" />
|
||||
<Compile Include="Events\LogMessageType.cs" />
|
||||
|
@ -54,9 +57,7 @@
|
|||
<Compile Include="Model\SteamlessPlugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="PE64\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
|
Loading…
Reference in a new issue