1
0
Fork 0
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:
atom0s 2017-01-16 20:00:34 -08:00
parent 9a9aa8894d
commit a7fa5bb337
5 changed files with 1154 additions and 5 deletions

View 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;
}
}
}

View 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; }
}
}

View 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;
}
}
}
}

View file

@ -36,5 +36,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: Guid("56c95629-3b34-47fe-b988-04274409294f")] [assembly: Guid("56c95629-3b34-47fe-b988-04274409294f")]
[assembly: AssemblyVersion("1.0.0.1")] [assembly: AssemblyVersion("1.0.0.2")]
[assembly: AssemblyFileVersion("1.0.0.1")] [assembly: AssemblyFileVersion("1.0.0.2")]

View file

@ -45,6 +45,9 @@
<Compile Include="PE32\NativeApi32.cs" /> <Compile Include="PE32\NativeApi32.cs" />
<Compile Include="PE32\Pe32File.cs" /> <Compile Include="PE32\Pe32File.cs" />
<Compile Include="PE32\Pe32Helpers.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="SteamlessEvents.cs" />
<Compile Include="Events\LogMessageEventArgs.cs" /> <Compile Include="Events\LogMessageEventArgs.cs" />
<Compile Include="Events\LogMessageType.cs" /> <Compile Include="Events\LogMessageType.cs" />
@ -54,9 +57,7 @@
<Compile Include="Model\SteamlessPlugin.cs" /> <Compile Include="Model\SteamlessPlugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup />
<Folder Include="PE64\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.