Skip to content

Commit

Permalink
Lots of work on Imports, still work in progress but making it as gene…
Browse files Browse the repository at this point in the history
…ric as possible so code isn't duplicated.
  • Loading branch information
Lloyd Kinsella committed Jul 31, 2018
1 parent 1fe51e4 commit 326bae1
Show file tree
Hide file tree
Showing 23 changed files with 972 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Src/Workshell.PE/Annotations/EnumAnnotations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ public EnumAnnotations()

var underlayingType = Enum.GetUnderlyingType(typeof(T));

#pragma warning disable CS0618 // Type or member is obsolete
TypeSize = Marshal.SizeOf(underlayingType);
#pragma warning restore CS0618 // Type or member is obsolete
}

#region Methods
Expand Down
4 changes: 4 additions & 0 deletions Src/Workshell.PE/DataDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ public async Task<DataContent> GetContentAsync()
return await RelocationTable.LoadAsync(_image).ConfigureAwait(false);
case DataDirectoryType.ExportTable:
return await ExportDirectory.LoadAsync(_image).ConfigureAwait(false);
case DataDirectoryType.ImportTable:
return await ImportDirectory.LoadAsync(_image).ConfigureAwait(false);
case DataDirectoryType.DelayImportDescriptor:
return await DelayedImportDirectory.LoadAsync(_image).ConfigureAwait(false);
default:
{
var calc = _image.GetCalculator();
Expand Down
2 changes: 2 additions & 0 deletions Src/Workshell.PE/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ public static T Read<T>(byte[] bytes) where T : struct
{
Marshal.Copy(bytes,0,ptr,bytes.Length);

#pragma warning disable CS0618 // Type or member is obsolete
T result = (T)Marshal.PtrToStructure(ptr,typeof(T));
#pragma warning restore CS0618 // Type or member is obsolete

return result;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Workshell.PE.Testbed/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ static async Task RunAsync(string[] args)
{
//var image = await PortableExecutableImage.FromFileAsync(@"C:\Users\lkinsella\Downloads\IISCrypto.exe");
var image = await PortableExecutableImage.FromFileAsync(@"C:\Windows\System32\shell32.dll");
var dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.ExportTable];
var dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.DelayImportDescriptor];
var content = await dataDirectory.GetContentAsync().ConfigureAwait(false);

var exports = await Exports.GetAsync(image).ConfigureAwait(false);
var x = await ImportAddressTables.GetLookupTableAsync(image).ConfigureAwait(false);
}
}
}
2 changes: 2 additions & 0 deletions src/Workshell.PE/Annotations/FieldAnnotations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ internal FieldAnnotations(object annotatedObject)
var type = prop.PropertyType;
var size = 0;

#pragma warning disable CS0618 // Type or member is obsolete
if (type.IsArray)
{
size = Marshal.SizeOf(type.GetElementType());
Expand All @@ -79,6 +80,7 @@ internal FieldAnnotations(object annotatedObject)
{
size = Marshal.SizeOf(type);
}
#pragma warning restore CS0618 // Type or member is obsolete

var value = prop.GetValue(annotatedObject,null);
var annotation = new FieldAnnotation(desc,attr.ArrayLength,attr.Flags,name,type,value,size);
Expand Down
14 changes: 14 additions & 0 deletions src/Workshell.PE/Content/Imports/DelayedImportAddressTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Workshell.PE.Content
{
public sealed class DelayedImportAddressTable : ImportAddressTableBase<DelayedImportAddressTableEntry, DelayedImportDirectoryEntry>
{
internal DelayedImportAddressTable(PortableExecutableImage image, DelayedImportDirectoryEntry directoryEntry, uint tableRVA, ulong[] tableEntries) : base(image, directoryEntry, tableRVA, tableEntries, false)
{
}
}
}
15 changes: 15 additions & 0 deletions src/Workshell.PE/Content/Imports/DelayedImportAddressTableEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Workshell.PE.Extensions;

namespace Workshell.PE.Content
{
public sealed class DelayedImportAddressTableEntry : ImportAddressTableEntryBase
{
internal DelayedImportAddressTableEntry(PortableExecutableImage image, ulong offset, ulong value, uint address, ushort ordinal, bool isOrdinal) : base(image, offset, value, address, ordinal, isOrdinal, true)
{
}
}
}
46 changes: 46 additions & 0 deletions src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Workshell.PE.Content
{
public sealed class DelayedImportAddressTables : ImportAddressTablesBase<DelayedImportAddressTable, DelayedImportAddressTableEntry, DelayedImportDirectoryEntry>
{
internal DelayedImportAddressTables(PortableExecutableImage image, DataDirectory directory, Location location, Tuple<uint, DelayedImportDirectoryEntry, ulong[]>[] tables) : base(image, directory, location, tables)
{
}

#region Static Methods

public static async Task<DelayedImportAddressTables> GetLookupTableAsync(PortableExecutableImage image, DelayedImportDirectory directory = null)
{
if (directory == null)
directory = await DelayedImportDirectory.LoadAsync(image).ConfigureAwait(false);

var tables = await LoadAsync<DelayedImportAddressTable, DelayedImportAddressTableEntry, DelayedImportDirectoryEntry, DelayedImportAddressTables>(
image,
directory,
entry => entry.DelayNameTable
).ConfigureAwait(false);

return tables;
}

public static async Task<DelayedImportAddressTables> GetAddressTableAsync(PortableExecutableImage image, DelayedImportDirectory directory = null)
{
if (directory == null)
directory = await DelayedImportDirectory.LoadAsync(image).ConfigureAwait(false);

var tables = await LoadAsync<DelayedImportAddressTable, DelayedImportAddressTableEntry, DelayedImportDirectoryEntry, DelayedImportAddressTables>(
image,
directory,
entry => entry.DelayAddressTable
).ConfigureAwait(false);

return tables;
}

#endregion
}
}
94 changes: 94 additions & 0 deletions src/Workshell.PE/Content/Imports/DelayedImportDirectory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

using Workshell.PE.Extensions;
using Workshell.PE.Native;

namespace Workshell.PE.Content
{
public sealed class DelayedImportDirectory : ImportDirectoryBase<DelayedImportDirectoryEntry>
{
internal DelayedImportDirectory(PortableExecutableImage image, DataDirectory directory, Location location, DelayedImportDirectoryEntry[] entries) : base(image, directory, location, entries)
{
}

#region Static Methods

internal static async Task<DelayedImportDirectory> LoadAsync(PortableExecutableImage image)
{
if (!image.NTHeaders.DataDirectories.Exists(DataDirectoryType.DelayImportDescriptor))
return null;

var dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.DelayImportDescriptor];

if (DataDirectory.IsNullOrEmpty(dataDirectory))
return null;

var calc = image.GetCalculator();
var section = calc.RVAToSection(dataDirectory.VirtualAddress);
var fileOffset = calc.RVAToOffset(section, dataDirectory.VirtualAddress);
var stream = image.GetStream();

stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin);

var size = Marshal.SizeOf<IMAGE_DELAY_IMPORT_DESCRIPTOR>();
var descriptors = new List<Tuple<ulong, IMAGE_DELAY_IMPORT_DESCRIPTOR>>();

try
{
ulong offset = 0;

while (true)
{
var descriptor = await stream.ReadStructAsync<IMAGE_DELAY_IMPORT_DESCRIPTOR>(size).ConfigureAwait(false);

if (descriptor.Name == 0 && descriptor.ModuleHandle == 0)
break;

var tuple = new Tuple<ulong, IMAGE_DELAY_IMPORT_DESCRIPTOR>(offset, descriptor);

offset += size.ToUInt32();

descriptors.Add(tuple);
}
}
catch (Exception ex)
{
throw new PortableExecutableImageException(image, "Could not read delay import descriptor from stream.", ex);
}

var imageBase = image.NTHeaders.OptionalHeader.ImageBase;
var totalSize = (descriptors.Count + 1) * size;
var location = new Location(fileOffset, dataDirectory.VirtualAddress, imageBase + dataDirectory.VirtualAddress, totalSize.ToUInt32(), totalSize.ToUInt32(), section);
var entries = new DelayedImportDirectoryEntry[descriptors.Count];

for (var i = 0; i < descriptors.Count; i++)
{
try
{
var entryOffset = fileOffset + descriptors[i].Item1;
var entryRVA = calc.OffsetToRVA(entryOffset);
var entryVA = imageBase + entryRVA;
var entryLocation = new Location(calc, entryOffset, entryRVA, entryVA, size.ToUInt32(), size.ToUInt32());
var name = await GetNameAsync(calc, stream, descriptors[i].Item2.Name).ConfigureAwait(false);

entries[i] = new DelayedImportDirectoryEntry(image, entryLocation, descriptors[i].Item2, name);
}
catch (Exception ex)
{
throw new PortableExecutableImageException(image, "Could not read delay import library name from stream.", ex);
}
}

var result = new DelayedImportDirectory(image, dataDirectory, location, entries);

return result;
}

#endregion
}
}
69 changes: 69 additions & 0 deletions src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Text;
using Workshell.PE.Annotations;
using Workshell.PE.Native;

namespace Workshell.PE.Content
{
public sealed class DelayedImportDirectoryEntry : ImportDirectoryEntryBase
{
private readonly string _name;

internal DelayedImportDirectoryEntry(PortableExecutableImage image, Location location, IMAGE_DELAY_IMPORT_DESCRIPTOR descriptor, string name) : base(image, location, true)
{
_name = name;

Attributes = descriptor.Attributes;
Name = descriptor.Name;
ModuleHandle = descriptor.ModuleHandle;
DelayAddressTable = descriptor.DelayAddressTable;
DelayNameTable = descriptor.DelayNameTable;
BoundDelayIAT = descriptor.BoundDelayIAT;
UnloadDelayIAT = descriptor.UnloadDelayIAT;
TimeDateStamp = descriptor.TimeDateStamp;
}

#region Methods

public DateTime GetTimeDateStamp()
{
return Utils.ConvertTimeDateStamp(TimeDateStamp);
}

public string GetName()
{
return _name;
}

#endregion

#region Properties

[FieldAnnotation("Attributes")]
public uint Attributes { get; }

[FieldAnnotation("Name")]
public uint Name { get; }

[FieldAnnotation("Module Handle")]
public uint ModuleHandle { get; }

[FieldAnnotation("Delay Import Address Table")]
public uint DelayAddressTable { get; }

[FieldAnnotation("Delay Import Hint/Name Table")]
public uint DelayNameTable { get; }

[FieldAnnotation("Bound Delay Import Address Table")]
public uint BoundDelayIAT { get; }

[FieldAnnotation("Unload Delay Import Address Table")]
public uint UnloadDelayIAT { get; }

[FieldAnnotation("Date/Time Stamp")]
public uint TimeDateStamp { get; }

#endregion
}
}
14 changes: 14 additions & 0 deletions src/Workshell.PE/Content/Imports/ImportAddressTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Workshell.PE.Content
{
public sealed class ImportAddressTable : ImportAddressTableBase<ImportAddressTableEntry, ImportDirectoryEntry>
{
internal ImportAddressTable(PortableExecutableImage image, ImportDirectoryEntry directoryEntry, uint tableRVA, ulong[] tableEntries) : base(image, directoryEntry, tableRVA, tableEntries, false)
{
}
}
}
Loading

0 comments on commit 326bae1

Please sign in to comment.