Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUGFIX: Update FieldRVA entries even when data is in its unresolved state #468

Merged
merged 3 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions src/AsmResolver.PE/DotNet/Builder/ManagedPEFileBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,31 @@ public IFieldRvaDataReader FieldRvaDataReader
}
}

/// <summary>
/// Creates a new managed PE file builder with default settings.
/// </summary>
public ManagedPEFileBuilder()
: this(ThrowErrorListener.Instance)
{
}

/// <summary>
/// Creates a new managed PE file builder with the provided error listener.
/// </summary>
public ManagedPEFileBuilder(IErrorListener errorListener)
{
ErrorListener = errorListener;
}

/// <summary>
/// Gets or sets the object responsible for recording diagnostic information during the building process.
/// </summary>
public IErrorListener ErrorListener
{
get;
set;
}

/// <inheritdoc />
protected override ManagedPEBuilderContext CreateContext(IPEImage image) => new(image);

Expand Down Expand Up @@ -436,7 +461,7 @@ protected override uint GetSectionAlignment(PEFile peFile, IPEImage image, Manag
protected override uint GetImageBase(PEFile peFile, IPEImage image, ManagedPEBuilderContext context)
=> (uint) image.ImageBase;

private static void ProcessRvasInMetadataTables(ManagedPEBuilderContext context)
private void ProcessRvasInMetadataTables(ManagedPEBuilderContext context)
{
var dotNetSegment = context.DotNetSegment;
var tablesStream = dotNetSegment.DotNetDirectory.Metadata?.GetStream<TablesStream>();
Expand All @@ -447,7 +472,7 @@ private static void ProcessRvasInMetadataTables(ManagedPEBuilderContext context)
AddFieldRvasToTable(context);
}

private static void AddMethodBodiesToTable(MethodBodyTableBuffer table, TablesStream tablesStream)
private void AddMethodBodiesToTable(MethodBodyTableBuffer table, TablesStream tablesStream)
{
var methodTable = tablesStream.GetTable<MethodDefinitionRow>();
for (int i = 0; i < methodTable.Count; i++)
Expand All @@ -472,7 +497,7 @@ private static void AddMethodBodiesToTable(MethodBodyTableBuffer table, TablesSt
}
}

private static ISegment? GetMethodBodySegment(MethodDefinitionRow methodRow)
private ISegment? GetMethodBodySegment(MethodDefinitionRow methodRow)
{
if (methodRow.Body.IsBounded)
return methodRow.Body.GetSegment();
Expand All @@ -485,13 +510,13 @@ private static void AddMethodBodiesToTable(MethodBodyTableBuffer table, TablesSt
return CilRawMethodBody.FromReader(ThrowErrorListener.Instance, ref reader);
}

throw new NotImplementedException("Native unbounded method bodies cannot be reassembled yet.");
ErrorListener.NotSupported("Native unbounded method bodies cannot be reassembled yet.");
}

return null;
}

private static void AddFieldRvasToTable(ManagedPEBuilderContext context)
private void AddFieldRvasToTable(ManagedPEBuilderContext context)
{
var directory = context.DotNetSegment.DotNetDirectory;
var fieldRvaTable = directory.Metadata!
Expand All @@ -504,18 +529,21 @@ private static void AddFieldRvasToTable(ManagedPEBuilderContext context)
var table = context.DotNetSegment.FieldRvaTable;
var reader = context.FieldRvaDataReader;

for (int i = 0; i < fieldRvaTable.Count; i++)
for (uint rid = 1; rid <= fieldRvaTable.Count; rid++)
{
ref var row = ref fieldRvaTable.GetRowRef(rid);
var data = reader.ResolveFieldData(
ThrowErrorListener.Instance,
ErrorListener,
context.Platform,
directory,
fieldRvaTable[i]);
row
);

if (data is null)
continue;

table.Add(data);
row.Data = data.ToReference();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.IO;
using AsmResolver.PE.Code;
using AsmResolver.PE.DotNet;
using AsmResolver.PE.DotNet.Builder;
Expand All @@ -21,33 +22,33 @@ public ManagedPEFileBuilderTest(TemporaryDirectoryFixture fixture)
{
_fixture = fixture;
}

[Fact]
public void HelloWorldRebuild32BitNoChange()
{
// Read image
var image = PEImage.FromBytes(Properties.Resources.HelloWorld);

// Rebuild
var builder = new ManagedPEFileBuilder();
var peFile = builder.CreateFile(image);

// Verify
_fixture
.GetRunner<FrameworkPERunner>()
.RebuildAndRun(peFile, "HelloWorld", "Hello World!" + Environment.NewLine);
}

[Fact]
public void HelloWorldRebuild64BitNoChange()
{
// Read image
var image = PEImage.FromBytes(Properties.Resources.HelloWorld_X64);

// Rebuild
var builder = new ManagedPEFileBuilder();
var peFile = builder.CreateFile(image);

// Verify
_fixture
.GetRunner<FrameworkPERunner>()
Expand All @@ -59,15 +60,15 @@ public void HelloWorld32BitTo64Bit()
{
// Read image
var image = PEImage.FromBytes(Properties.Resources.HelloWorld);

// Change machine type and pe kind to 64-bit
image.MachineType = MachineType.Amd64;
image.PEKind = OptionalHeaderMagic.PE32Plus;

// Rebuild
var builder = new ManagedPEFileBuilder();
var peFile = builder.CreateFile(image);

// Verify
_fixture
.GetRunner<FrameworkPERunner>()
Expand All @@ -79,20 +80,40 @@ public void HelloWorld64BitTo32Bit()
{
// Read image
var image = PEImage.FromBytes(Properties.Resources.HelloWorld_X64);

// Change machine type and pe kind to 32-bit
image.MachineType = MachineType.I386;
image.PEKind = OptionalHeaderMagic.PE32;

// Rebuild
var builder = new ManagedPEFileBuilder();
var peFile = builder.CreateFile(image);

// Verify
_fixture
.GetRunner<FrameworkPERunner>()
.RebuildAndRun(peFile, "HelloWorld", "Hello World!" + Environment.NewLine);
}


[Fact]
public void UpdateFieldRvaRowsUnchanged()
{
var image = PEImage.FromBytes(Properties.Resources.FieldRvaTest);

using var stream = new MemoryStream();
var file = new ManagedPEFileBuilder(EmptyErrorListener.Instance).CreateFile(image);
file.Write(stream);

var newImage = PEImage.FromBytes(stream.ToArray());
var table = newImage.DotNetDirectory!.Metadata!
.GetStream<TablesStream>()
.GetTable<FieldRvaRow>();

byte[] data = new byte[16];
table[0].Data.CreateReader().ReadBytes(data, 0, data.Length);
Assert.Equal(new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, data);
Assert.Equal(0x12345678u, table[1].Data.Rva);
}

}
}
}
7 changes: 7 additions & 0 deletions test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions test/AsmResolver.PE.Tests/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,7 @@
<data name="ForwarderDlls_ForwarderTest" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ForwarderTest.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="FieldRvaTest" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\FieldRvaTest.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
Binary file not shown.