From f3828bf921ded6002a4e2f633527ee2cf89cd89c Mon Sep 17 00:00:00 2001 From: Washi Date: Tue, 11 Jul 2023 22:20:18 +0200 Subject: [PATCH 1/3] Add failing FieldRVA test. --- .../Builder/ManagedPEFileBuilderTest.cs | 49 +++++++++++++----- .../Properties/Resources.Designer.cs | 7 +++ .../Properties/Resources.resx | 5 +- .../Resources/FieldRvaTest.exe | Bin 0 -> 2048 bytes 4 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 test/AsmResolver.PE.Tests/Resources/FieldRvaTest.exe 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..ea2add3ab 100644 --- a/test/AsmResolver.PE.Tests/Properties/Resources.resx +++ b/test/AsmResolver.PE.Tests/Properties/Resources.resx @@ -111,7 +111,10 @@ ..\Resources\ProxyDll.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + ..\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 0000000000000000000000000000000000000000..d3b4ff03e8d8717a0f1890f65e21676327a65dba GIT binary patch literal 2048 zcmeHG%}*0S6#q?IN?Sf`i66iLhA)G}Y#`-gLQH8vfq)WPAyE@q+6k`N?l!yIhH@|- zG|@z({so>0cVi;)#MLN?S3U6;c<|^2-|TKF0&4U~eA#*L{oeb{%zLvlb2ncg2p~jb zZx7faD<$RX->V0dZtZ^8iZ{`no-H=J)04Za*}P<#tCm{idDSpXhpz~3l?|>LeByeR z7tMlDT3TZL{?hZ4z$^;@QR8uKw_Wt2i49|j3TyU*{e9$c8Yvo5aWXVb)-9!Gu}pyC zQi4c50^;shw?6bJ_|gl^`2MjbRj=XL{I7x>h#bg82u~friX+w>!m>xV7ukScca6q@ zWyKP@nfGf*`J8Z#;aLjP_iqxD=Sm`L3!ni{IdF~YV1#KL+KGaH5*7%C8p4f{XsoHZ zrS%jJ;d|ZjXL9+0PqcbykW{Sw$fth3@gdu!W(BDSi)f>|jWEH|(;;(c#>3^)gKIU%CECcINtd`J z#W6-Xh7LSO8%D5=PRXE50Q1CPSX&%zlNEaPy3Rh@zx@=6V!WQbq6xjQP*HQjb}%+) z7RtJ~3_7!N-oc`(YlRvE(?;bdJf~^~igw<#bZtd)%OY1T31q9bBZ^2@9f5_i;b=uM zCG?W8Y(J&=Q6*y*OPVgMtgtFtUf8sS=4iCZx)`@CwF*!BbhnTx)hOr!8Pl*$vP+ic zh*`}L)Y0a9HS>A%^z_DsuiLLbD4hs~6A^knEb?~!_F~8A?vq9YSX&}-CIrSJ2>3T! y9!9(Lx%7@o?F9gLGNv`TChCm~p%io-djsI9qZ3a?gnMu8eDY+p^S_I~JAogpd! Date: Tue, 11 Jul 2023 22:21:41 +0200 Subject: [PATCH 2/3] BUGFIX: Update FieldRVA rows explicitly after adding to data table. --- .../DotNet/Builder/ManagedPEFileBuilder.cs | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) 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(); } } } From 0fc8c452171707b80ed807e3c264db0f6cd11b49 Mon Sep 17 00:00:00 2001 From: Washi Date: Tue, 11 Jul 2023 23:27:57 +0200 Subject: [PATCH 3/3] Fix unit test binary path. --- test/AsmResolver.PE.Tests/Properties/Resources.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/AsmResolver.PE.Tests/Properties/Resources.resx b/test/AsmResolver.PE.Tests/Properties/Resources.resx index ea2add3ab..987d82cad 100644 --- a/test/AsmResolver.PE.Tests/Properties/Resources.resx +++ b/test/AsmResolver.PE.Tests/Properties/Resources.resx @@ -111,7 +111,7 @@ ..\Resources\ProxyDll.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + ..\Resources\ForwarderTest.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089