Skip to content

Commit

Permalink
Continuing work getting various import classes working.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lloyd Kinsella committed Aug 6, 2018
1 parent c42b900 commit 62bfaa3
Show file tree
Hide file tree
Showing 20 changed files with 620 additions and 15 deletions.
3 changes: 2 additions & 1 deletion src/Workshell.PE.Testbed/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ static async Task RunAsync(string[] args)
var dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.DelayImportDescriptor];
var content = await dataDirectory.GetContentAsync().ConfigureAwait(false);

var table = await ImportAddressTables.GetLookupTableAsync(image);
var imports = await Imports.GetAsync(image);
var delayedImports = await DelayedImports.GetAsync(image);

//var table = await ImportHintNameTable.LoadAsync(image).ConfigureAwait(false);
//var entries = table.ToArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Workshell.PE.Content
{
public sealed class DelayedImportAddressTable : ImportAddressTableBase<DelayedImportAddressTableEntry>
{
internal DelayedImportAddressTable(PortableExecutableImage image, uint rva, ulong[] entries) : base(image, rva, entries, true)
internal DelayedImportAddressTable(PortableExecutableImage image, uint rva, ulong[] entries, ImportDirectoryEntryBase directoryEntry) : base(image, rva, entries, directoryEntry, true)
{
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Workshell.PE.Content
{
public sealed class DelayedImportAddressTables: ImportAddressTablesBase<DelayedImportAddressTable, DelayedImportAddressTableEntry>
{
internal DelayedImportAddressTables(PortableExecutableImage image, DataDirectory directory, Location location, Tuple<uint, ulong[]>[] tables) : base(image, directory, location, tables, false)
internal DelayedImportAddressTables(PortableExecutableImage image, DataDirectory directory, Location location, Tuple<uint, ulong[], ImportDirectoryEntryBase>[] tables) : base(image, directory, location, tables, false)
{
}

Expand All @@ -33,7 +33,7 @@ private static async Task<DelayedImportAddressTables> GetTableAsync(PortableExec

var calc = image.GetCalculator();
var stream = image.GetStream();
var tables = new List<Tuple<uint, ulong[]>>();
var tables = new List<Tuple<uint, ulong[], ImportDirectoryEntryBase>>();

foreach (var dirEntry in directory)
{
Expand All @@ -57,7 +57,7 @@ private static async Task<DelayedImportAddressTables> GetTableAsync(PortableExec
break;
}

var table = new Tuple<uint, ulong[]>(thunk, entries.ToArray());
var table = new Tuple<uint, ulong[], ImportDirectoryEntryBase>(thunk, entries.ToArray(), dirEntry);

tables.Add(table);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public string GetName()
public uint Attributes { get; }

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

[FieldAnnotation("Module Handle")]
public uint ModuleHandle { get; }
Expand Down
103 changes: 103 additions & 0 deletions src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Workshell.PE.Extensions;

namespace Workshell.PE.Content
{
public sealed class DelayedImportHintNameTable : ImportHintNameTableBase<DelayedImportHintNameEntry>
{
internal DelayedImportHintNameTable(PortableExecutableImage image, DataDirectory directory, Location location, Tuple<ulong, uint, ushort, string, bool>[] entries) : base(image, directory, location, entries, true)
{
}

#region Static Methods

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

var entries = new Dictionary<uint, Tuple<ulong, uint, ushort, string, bool>>();
var ilt = await DelayedImportAddressTables.GetLookupTableAsync(image, directory).ConfigureAwait(false);
var calc = image.GetCalculator();
var stream = image.GetStream();

foreach (var table in ilt)
{
foreach (var entry in table)
{
if (entry.Address == 0)
continue;

if (entries.ContainsKey(entry.Address))
continue;

if (!entry.IsOrdinal)
{
var offset = calc.RVAToOffset(entry.Address);
var size = 0u;
var isPadded = false;
ushort hint = 0;
var name = new StringBuilder(256);

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

hint = await stream.ReadUInt16Async().ConfigureAwait(false);
size += sizeof(ushort);

while (true)
{
var b = await stream.ReadByteAsync().ConfigureAwait(false);

size++;

if (b <= 0)
break;

name.Append((char)b);
}

if (size % 2 != 0)
{
isPadded = true;
size++;
}

var tuple = new Tuple<ulong, uint, ushort, string, bool>(offset, size, hint, name.ToString(), isPadded);

entries.Add(entry.Address, tuple);
}
}
}

Location location;

if (entries.Count > 0)
{
var firstEntry = entries.Values.MinBy(tuple => tuple.Item1);
var lastEntry = entries.Values.MaxBy(tuple => tuple.Item1);
var tableOffset = firstEntry.Item1;
var tableSize = ((lastEntry.Item1 + lastEntry.Item2) - tableOffset).ToUInt32();
var tableRVA = calc.OffsetToRVA(tableOffset);
var tableVA = image.NTHeaders.OptionalHeader.ImageBase + tableRVA;
var tableSection = calc.RVAToSection(tableRVA);

location = new Location(tableOffset, tableRVA, tableVA, tableSize, tableSize, tableSection);
}
else
{
location = new Location(0, 0, 0, 0, 0, null);
}

var result = new DelayedImportHintNameTable(image, directory.Directory, location, entries.Values.ToArray());

return result;
}

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

namespace Workshell.PE.Content
{
public sealed class DelayedImportLibrary : ImportLibraryBase
{
internal DelayedImportLibrary(ImportLibraryFunction[] functions, string name) : base(functions, name, true)
{
}
}
}
98 changes: 98 additions & 0 deletions src/Workshell.PE/Content/Imports/DelayedImports.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Workshell.PE.Extensions;

namespace Workshell.PE.Content
{
public sealed class DelayedImports : ImportsBase<DelayedImportLibrary>
{
internal DelayedImports(DelayedImportLibrary[] libraries) : base(libraries)
{
}

#region Static Methods

public static async Task<DelayedImports> GetAsync(PortableExecutableImage image)
{
var directory = await DelayedImportDirectory.LoadAsync(image).ConfigureAwait(false);

if (directory == null)
return null;

var ilt = await DelayedImportAddressTables.GetLookupTableAsync(image, directory).ConfigureAwait(false);

if (ilt == null)
return null;

var hnt = await DelayedImportHintNameTable.GetAsync(image, directory).ConfigureAwait(false);

if (hnt == null)
return null;

return await GetAsync(image, ilt, hnt).ConfigureAwait(false);
}

public static async Task<DelayedImports> GetAsync(PortableExecutableImage image, DelayedImportAddressTables ilt, DelayedImportHintNameTable hnt)
{
var libraries = new List<DelayedImportLibrary>();
var calc = image.GetCalculator();
var stream = image.GetStream();

foreach (var table in ilt)
{
var builder = new StringBuilder(256);
var offset = calc.RVAToOffset(table.DirectoryEntry.Name);

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

while (true)
{
var b = await stream.ReadByteAsync().ConfigureAwait(false);

if (b <= 0)
break;

builder.Append((char)b);
}

var name = builder.ToString();
var functions = new List<ImportLibraryFunction>(table.Count);

foreach (var entry in table)
{
ImportLibraryFunction function = null;

if (entry.IsOrdinal)
{
function = new ImportLibraryOrdinalFunction(entry, entry.Ordinal);
}
else
{
var hintEntry = hnt.FirstOrDefault(e => e.Location.RelativeVirtualAddress == entry.Address);

if (hintEntry != null)
function = new ImportLibraryNamedFunction(entry, hintEntry);
}

if (function != null)
functions.Add(function);
}

var library = new DelayedImportLibrary(functions.ToArray(), name);

libraries.Add(library);
}

var imports = new DelayedImports(libraries.ToArray());

return imports;
}

#endregion
}
}
2 changes: 1 addition & 1 deletion src/Workshell.PE/Content/Imports/ImportAddressTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Workshell.PE.Content
{
public sealed class ImportAddressTable : ImportAddressTableBase<ImportAddressTableEntry>
{
internal ImportAddressTable(PortableExecutableImage image, uint rva, ulong[] entries) : base(image, rva, entries, false)
internal ImportAddressTable(PortableExecutableImage image, uint rva, ulong[] entries, ImportDirectoryEntryBase directoryEntry) : base(image, rva, entries, directoryEntry, false)
{
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/Workshell.PE/Content/Imports/ImportAddressTableBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public abstract class ImportAddressTableBase<TEntry> : IEnumerable<TEntry>, ISup
private readonly PortableExecutableImage _image;
private readonly TEntry[] _entries;

protected internal ImportAddressTableBase(PortableExecutableImage image, uint rva, ulong[] entries, bool isDelayed)
protected internal ImportAddressTableBase(PortableExecutableImage image, uint rva, ulong[] entries, ImportDirectoryEntryBase directoryEntry, bool isDelayed)
{
var calc = image.GetCalculator();
var imageBase = image.NTHeaders.OptionalHeader.ImageBase;
Expand All @@ -30,6 +30,7 @@ protected internal ImportAddressTableBase(PortableExecutableImage image, uint rv

Location = new Location(offset, rva, va, size, size, section);
Count = _entries.Length;
DirectoryEntry = directoryEntry;
IsDelayed = isDelayed;
}

Expand Down Expand Up @@ -122,6 +123,7 @@ private TEntry[] BuildEntries(PortableExecutableImage image, ulong tableOffset,
public Location Location { get; }
public int Count { get; }
public TEntry this[int index] => _entries[index];
public ImportDirectoryEntryBase DirectoryEntry { get; }
public bool IsDelayed { get; }

#endregion
Expand Down
6 changes: 3 additions & 3 deletions src/Workshell.PE/Content/Imports/ImportAddressTables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Workshell.PE.Content
{
public sealed class ImportAddressTables: ImportAddressTablesBase<ImportAddressTable, ImportAddressTableEntry>
{
internal ImportAddressTables(PortableExecutableImage image, DataDirectory directory, Location location, Tuple<uint, ulong[]>[] tables) : base(image, directory, location, tables, false)
internal ImportAddressTables(PortableExecutableImage image, DataDirectory directory, Location location, Tuple<uint, ulong[], ImportDirectoryEntryBase>[] tables) : base(image, directory, location, tables, false)
{
}

Expand All @@ -33,7 +33,7 @@ private static async Task<ImportAddressTables> GetTableAsync(PortableExecutableI

var calc = image.GetCalculator();
var stream = image.GetStream();
var tables = new List<Tuple<uint, ulong[]>>();
var tables = new List<Tuple<uint, ulong[], ImportDirectoryEntryBase>>();

foreach (var dirEntry in directory)
{
Expand All @@ -57,7 +57,7 @@ private static async Task<ImportAddressTables> GetTableAsync(PortableExecutableI
break;
}

var table = new Tuple<uint, ulong[]>(thunk, entries.ToArray());
var table = new Tuple<uint, ulong[], ImportDirectoryEntryBase>(thunk, entries.ToArray(), dirEntry);

tables.Add(table);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Workshell.PE/Content/Imports/ImportAddressTablesBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public abstract class ImportAddressTablesBase<TTable, TTableEntry> : DataContent
{
private readonly TTable[] _tables;

protected internal ImportAddressTablesBase(PortableExecutableImage image, DataDirectory directory, Location location, Tuple<uint, ulong[]>[] tables, bool isDelayed) : base(image, directory, location)
protected internal ImportAddressTablesBase(PortableExecutableImage image, DataDirectory directory, Location location, Tuple<uint, ulong[], ImportDirectoryEntryBase>[] tables, bool isDelayed) : base(image, directory, location)
{
_tables = new TTable[tables.Length];

Expand All @@ -24,7 +24,7 @@ protected internal ImportAddressTablesBase(PortableExecutableImage image, DataDi
for (var i = 0; i < tables.Length; i++)
{
var tuple = tables[i];
var table = (TTable)ctor.Invoke(new object[] { image, tuple.Item1, tuple.Item2 });
var table = (TTable)ctor.Invoke(new object[] { image, tuple.Item1, tuple.Item2, tuple.Item3 });

_tables[i] = table;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Workshell.PE/Content/Imports/ImportDirectoryEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public string GetName()
public uint ForwarderChain { get; }

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

[FieldAnnotation("First Thunk")]
public uint FirstThunk { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public async Task<byte[]> GetBytesAsync()

public Location Location { get; }
public bool IsDelayed { get; }
public abstract uint Name { get; }

#endregion
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ protected internal ImportHintNameEntryBase(PortableExecutableImage image, ulong

public override string ToString()
{
return $"0x{hint:X4} {name}";
return $"0x{Hint:X4} {Name}";
}

public byte[] GetBytes()
Expand Down
Loading

0 comments on commit 62bfaa3

Please sign in to comment.