Skip to content

Commit

Permalink
Support for the Relocation Table (also fixed a bug from other branch).
Browse files Browse the repository at this point in the history
  • Loading branch information
Lloyd Kinsella committed Jul 25, 2018
1 parent 97ef57a commit ed71f02
Show file tree
Hide file tree
Showing 7 changed files with 437 additions and 7 deletions.
2 changes: 2 additions & 0 deletions Src/Workshell.PE/DataDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ public async Task<DataContent> GetContentAsync()
return await CLR.LoadAsync(_image).ConfigureAwait(false);
case DataDirectoryType.Debug:
return await DebugDirectory.LoadAsync(_image).ConfigureAwait(false);
case DataDirectoryType.BaseRelocationTable:
return await RelocationTable.LoadAsync(_image).ConfigureAwait(false);
default:
{
var calc = _image.GetCalculator();
Expand Down
138 changes: 134 additions & 4 deletions Src/Workshell.PE/Extensions/Conversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,51 @@ namespace Workshell.PE.Extensions
{
internal static class ConversionExtensions
{
#region Methods
#region int16

public static short ToInt16(this int value)
{
return Convert.ToInt16(value);
}

public static short ToInt16(this long value)
{
return Convert.ToInt16(value);
}

public static short ToInt16(this ushort value)
{
return Convert.ToInt16(value);
}

public static short ToInt16(this uint value)
{
return Convert.ToInt16(value);
}

public static short ToInt16(this ulong value)
{
return Convert.ToInt16(value);
}

#endregion

#region int32

public static int ToInt32(this short value)
{
return value;
}

public static int ToInt32(this long value)
{
return Convert.ToInt32(value);
}

public static int ToInt32(this ushort value)
{
return Convert.ToInt32(value);
}

public static int ToInt32(this uint value)
{
Expand All @@ -18,34 +62,120 @@ public static int ToInt32(this ulong value)
return Convert.ToInt32(value);
}

#endregion

#region int64

public static long ToInt64(this short value)
{
return value;
}

public static long ToInt64(this int value)
{
return value;
}

public static long ToInt64(this ushort value)
{
return Convert.ToInt64(value);
}

public static long ToInt64(this uint value)
{
return Convert.ToInt64(value);
}

public static long ToInt64(this ulong value)
{
return Convert.ToInt64(value);
return Convert.ToInt32(value);
}

#endregion

#region uint16

public static ushort ToUInt16(this short value)
{
return Convert.ToUInt16(value);
}

public static ushort ToUInt16(this int value)
{
return Convert.ToUInt16(value);
}

public static ushort ToUInt16(this long value)
{
return Convert.ToUInt16(value);
}

public static ushort ToUInt16(this uint value)
{
return Convert.ToUInt16(value);
}

public static ushort ToUInt16(this ulong value)
{
return Convert.ToUInt16(value);
}

#endregion

#region uint32

public static uint ToUInt32(this short value)
{
return Convert.ToUInt32(value);
}

public static uint ToUInt32(this int value)
{
return Convert.ToUInt32(value);
}

public static uint ToUInt32(this long value)
{
return Convert.ToUInt32(value);
}

public static uint ToUInt32(this ushort value)
{
return value;
}

public static uint ToUInt32(this ulong value)
{
return Convert.ToUInt32(value);
}

#endregion

#region uint64

public static ulong ToUInt64(this short value)
{
return Convert.ToUInt64(value);
}

public static ulong ToUInt64(this int value)
{
return Convert.ToUInt32(value);
return Convert.ToUInt64(value);
}

public static ulong ToUInt64(this long value)
{
return Convert.ToUInt32(value);
return Convert.ToUInt64(value);
}

public static ulong ToUInt64(this ushort value)
{
return value;
}

public static ulong ToUInt64(this uint value)
{
return value;
}

#endregion
Expand Down
6 changes: 3 additions & 3 deletions src/Workshell.PE.Testbed/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ static void Main(string[] args)

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.Debug];
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.BaseRelocationTable];
var content = await dataDirectory.GetContentAsync().ConfigureAwait(false);

}
Expand Down
84 changes: 84 additions & 0 deletions src/Workshell.PE/Content/Relocation/Relocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Text;
using Workshell.PE.Annotations;
using Workshell.PE.Extensions;

namespace Workshell.PE.Content
{
public enum RelocationType : byte
{
[EnumAnnotation("IMAGE_REL_BASED_ABSOLUTE")]
Absolute = 0,
[EnumAnnotationAttribute("IMAGE_REL_BASED_HIGH")]
High = 1,
[EnumAnnotationAttribute("IMAGE_REL_BASED_LOW")]
Low = 2,
[EnumAnnotationAttribute("IMAGE_REL_BASED_HIGHLOW")]
HighLow = 3,
[EnumAnnotationAttribute("IMAGE_REL_BASED_HIGHADJ")]
HighAdj = 4,
[EnumAnnotationAttribute("IMAGE_REL_BASED_MIPS_JMPADDR")]
MIPSJmpAddr = 5,
[EnumAnnotationAttribute("IMAGE_REL_BASED_ARM_MOV32A")]
ARMMov32a = 6,
[EnumAnnotationAttribute("IMAGE_REL_BASED_ARM_MOV32T")]
ARMMov32t = 7,
[EnumAnnotationAttribute("IMAGE_REL_BASED_MIPS_JMPADDR16")]
MIPSJmpAddr16 = 9,
[EnumAnnotationAttribute("IMAGE_REL_BASED_DIR64")]
Dir64 = 10
}

public sealed class Relocation
{
internal Relocation(RelocationBlock relocBlock, ushort relocValue)
{
Block = relocBlock;

var relocType = relocValue >> 12;
var relocOffset = relocValue & 0xFFF;

Type = (RelocationType)relocType;
Offset = relocOffset.ToUInt16();
Value = relocValue;
ComputedRVA = Block.PageRVA;

switch (Type)
{
case RelocationType.Absolute:
break;
case RelocationType.HighLow:
ComputedRVA += Offset;
break;
case RelocationType.Dir64:
ComputedRVA += Offset;
break;
case RelocationType.High:
case RelocationType.Low:
default:
ComputedRVA = 0;
break;
}
}

#region Methods

public override string ToString()
{
return $"Type: {Type}, Computed RVA: 0x{ComputedRVA:X8}";
}

#endregion

#region Properties

public RelocationBlock Block { get; }
public RelocationType Type { get; }
public ushort Offset { get; }
public ushort Value { get; }
public uint ComputedRVA { get; }

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

namespace Workshell.PE.Content
{
public sealed class RelocationBlock : IEnumerable<Relocation>, ISupportsLocation, ISupportsBytes
{
private readonly PortableExecutableImage _image;
private readonly Relocation[] _relocations;

internal RelocationBlock(PortableExecutableImage image, Location location, uint pageRVA, uint blockSize, ushort[] relocations)
{
_image = image;
_relocations = new Relocation[relocations.Length];

Location = location;
PageRVA = pageRVA;
BlockSize = blockSize;
Section = GetSection(pageRVA);
Count = relocations.Length;

for (var i = 0; i < relocations.Length; i++)
_relocations[i] = new Relocation(this, relocations[i]);
}

#region Methods

public override string ToString()
{
return $"Page RVA: 0x{PageRVA:X8}, Block Size: {BlockSize}, Relocations: {_relocations.Length}";
}

public IEnumerator<Relocation> GetEnumerator()
{
foreach (var relocation in _relocations)
yield return relocation;
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

public byte[] GetBytes()
{
return GetBytesAsync().GetAwaiter().GetResult();
}

public async Task<byte[]> GetBytesAsync()
{
var stream = _image.GetStream();
var buffer = await stream.ReadBytesAsync(Location).ConfigureAwait(false);

return buffer;
}

private Section GetSection(uint pageRVA)
{
var calc = _image.GetCalculator();
var section = calc.RVAToSection(pageRVA);

return section;
}

#endregion

#region Properties

public Location Location { get; }
public uint PageRVA { get; }
public uint BlockSize { get; }
public Section Section { get; }
public int Count { get; }
public Relocation this[int index] => _relocations[index];

#endregion
}
}
Loading

0 comments on commit ed71f02

Please sign in to comment.