diff --git a/src/AsmResolver.PE/DotNet/Builder/ManagedPEFileBuilder.cs b/src/AsmResolver.PE/DotNet/Builder/ManagedPEFileBuilder.cs
index 8475d8805..f2c32be92 100644
--- a/src/AsmResolver.PE/DotNet/Builder/ManagedPEFileBuilder.cs
+++ b/src/AsmResolver.PE/DotNet/Builder/ManagedPEFileBuilder.cs
@@ -154,6 +154,31 @@ public IFieldRvaDataReader FieldRvaDataReader
}
}
+ ///
+ /// Creates a new managed PE file builder with default settings.
+ ///
+ public ManagedPEFileBuilder()
+ : this(ThrowErrorListener.Instance)
+ {
+ }
+
+ ///
+ /// Creates a new managed PE file builder with the provided error listener.
+ ///
+ public ManagedPEFileBuilder(IErrorListener errorListener)
+ {
+ ErrorListener = errorListener;
+ }
+
+ ///
+ /// Gets or sets the object responsible for recording diagnostic information during the building process.
+ ///
+ public IErrorListener ErrorListener
+ {
+ get;
+ set;
+ }
+
///
protected override ManagedPEBuilderContext CreateContext(IPEImage image) => new(image);
@@ -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();
@@ -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();
for (int i = 0; i < methodTable.Count; i++)
@@ -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();
@@ -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!
@@ -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();
}
}
}
diff --git a/test/AsmResolver.PE.Tests/DotNet/Builder/ManagedPEFileBuilderTest.cs b/test/AsmResolver.PE.Tests/DotNet/Builder/ManagedPEFileBuilderTest.cs
index d9678ea24..1d2ccda32 100644
--- a/test/AsmResolver.PE.Tests/DotNet/Builder/ManagedPEFileBuilderTest.cs
+++ b/test/AsmResolver.PE.Tests/DotNet/Builder/ManagedPEFileBuilderTest.cs
@@ -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;
@@ -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()
.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()
@@ -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()
@@ -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()
.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()
+ .GetTable();
+
+ 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);
+ }
+
}
-}
\ No newline at end of file
+}
diff --git a/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs b/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs
index bd2e43a40..1ab8eda78 100644
--- a/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs
+++ b/test/AsmResolver.PE.Tests/Properties/Resources.Designer.cs
@@ -268,5 +268,12 @@ public static byte[] ForwarderDlls_ForwarderTest {
return ((byte[])(obj));
}
}
+
+ public static byte[] FieldRvaTest {
+ get {
+ object obj = ResourceManager.GetObject("FieldRvaTest", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
}
}
diff --git a/test/AsmResolver.PE.Tests/Properties/Resources.resx b/test/AsmResolver.PE.Tests/Properties/Resources.resx
index d916130a3..987d82cad 100644
--- a/test/AsmResolver.PE.Tests/Properties/Resources.resx
+++ b/test/AsmResolver.PE.Tests/Properties/Resources.resx
@@ -114,4 +114,7 @@
..\Resources\ForwarderTest.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\Resources\FieldRvaTest.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
diff --git a/test/AsmResolver.PE.Tests/Resources/FieldRvaTest.exe b/test/AsmResolver.PE.Tests/Resources/FieldRvaTest.exe
new file mode 100644
index 000000000..d3b4ff03e
Binary files /dev/null and b/test/AsmResolver.PE.Tests/Resources/FieldRvaTest.exe differ