Skip to content

Commit f7d0c27

Browse files
committed
Add full support for PE writing
1 parent 6b5147b commit f7d0c27

File tree

94 files changed

+1091
-582
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+1091
-582
lines changed

src/Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<ItemGroup>
77
<PackageVersion Include="MinVer" Version="6.0.0" />
88
<PackageVersion Include="MSTest" Version="3.6.0" />
9+
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
910
<PackageVersion Include="Verify.DiffPlex" Version="3.1.0" />
1011
<PackageVersion Include="Verify.MSTest" Version="26.6.0" />
1112
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />

src/LibObjectFile.Tests/PE/PEReaderTests.cs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// See the license.txt file in the project root for more information.
44

55
using System;
6+
using System.Collections.Generic;
7+
using System.Diagnostics;
68
using System.IO;
79
using System.Threading.Tasks;
810
using LibObjectFile.Diagnostics;
@@ -25,7 +27,7 @@ public async Task TestPrinter(string name)
2527

2628
var sourceFile = Path.Combine(AppContext.BaseDirectory, "PE", name);
2729
await using var stream = File.OpenRead(sourceFile);
28-
var peImage = PEFile.Read(stream);
30+
var peImage = PEFile.Read(stream, new() { EnableStackTrace = true });
2931
var afterReadWriter = new StringWriter();
3032
peImage.Print(afterReadWriter);
3133

@@ -64,7 +66,86 @@ public async Task TestPrinter(string name)
6466
// Compare the input and output buffer
6567
CollectionAssert.AreEqual(inputBuffer, outputBuffer);
6668
}
69+
70+
[DataTestMethod]
71+
[DynamicData(nameof(GetWindowsExeAndDlls), DynamicDataSourceType.Method)]
72+
public async Task TestWindows(string sourceFile)
73+
{
74+
if (!OperatingSystem.IsWindows())
75+
{
76+
Assert.Inconclusive("This test can only run on Windows");
77+
return;
78+
}
79+
80+
TestContext.WriteLine($"Testing {sourceFile}");
81+
await using var stream = File.OpenRead(sourceFile);
82+
var peImage = PEFile.Read(stream, new() { EnableStackTrace = true });
83+
84+
if (peImage.CoffHeader.PointerToSymbolTable != 0)
85+
{
86+
Assert.Inconclusive($"The file {sourceFile} contains a non supported symbol table");
87+
return;
88+
}
89+
90+
var sizeOfInitializedData = peImage.OptionalHeader.SizeOfInitializedData;
6791

92+
// Read in input as raw bytes
93+
stream.Position = 0;
94+
var inputBuffer = new byte[stream.Length];
95+
stream.ReadExactly(inputBuffer);
96+
97+
peImage.UpdateLayout(new DiagnosticBag());
98+
99+
var newSizeOfInitializedData = peImage.OptionalHeader.SizeOfInitializedData;
100+
101+
if (newSizeOfInitializedData != sizeOfInitializedData)
102+
{
103+
TestContext.WriteLine($"SizeOfInitializedData changed from {sizeOfInitializedData} to {newSizeOfInitializedData}. Trying to reuse old size");
104+
peImage.ForceSizeOfInitializedData = sizeOfInitializedData;
105+
}
106+
107+
108+
// Write the PE back to a byte buffer
109+
var output = new MemoryStream();
110+
peImage.Write(output);
111+
output.Position = 0;
112+
var outputBuffer = output.ToArray();
113+
114+
if (!inputBuffer.AsSpan().SequenceEqual(outputBuffer))
115+
{
116+
// Uncomment the following code to save the output file to compare it with the original file
117+
//{
118+
// var dir = Path.Combine(AppContext.BaseDirectory, "Errors");
119+
// Directory.CreateDirectory(dir);
120+
121+
// var sourceFileName = Path.GetFileName(sourceFile);
122+
// var outputFileName = Path.Combine(dir, $"{sourceFileName}.new");
123+
124+
// await File.WriteAllBytesAsync(outputFileName, outputBuffer);
125+
//}
126+
127+
CollectionAssert.AreEqual(inputBuffer, outputBuffer);
128+
}
129+
}
130+
131+
public static IEnumerable<object[]> GetWindowsExeAndDlls()
132+
{
133+
if (!OperatingSystem.IsWindows())
134+
{
135+
yield break;
136+
}
137+
138+
foreach (var file in Directory.EnumerateFiles(Environment.SystemDirectory, "*.exe", SearchOption.TopDirectoryOnly))
139+
{
140+
yield return [file];
141+
}
142+
143+
foreach (var file in Directory.EnumerateFiles(Environment.SystemDirectory, "*.dll", SearchOption.TopDirectoryOnly))
144+
{
145+
yield return [file];
146+
}
147+
}
148+
68149
[TestMethod]
69150
public async Task TestTinyExe97Bytes()
70151
{

src/LibObjectFile.Tests/Verified/PEReaderTests.TestPrinter_name=NativeConsole2Win64.exe.verified.txt

Lines changed: 31 additions & 33 deletions
Large diffs are not rendered by default.

src/LibObjectFile.Tests/Verified/PEReaderTests.TestPrinter_name=NativeConsoleWin64.exe.verified.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,11 @@ Sections
526526
[02] PEResourceDataEntry Position = 0x00002E48, Size = 0x00000010, RVA = 0x00007048, VirtualSize = 0x00000010
527527
> CodePage = null, Data = PEResourceData { RVA = 0x7060, VirtualSize = 0x17D, Position = 0x2E60, Size = 0x17D }
528528

529-
[03] PEResourceData Position = 0x00002E60, Size = 0x0000017D, RVA = 0x00007060, VirtualSize = 0x0000017D
529+
[03] PEStreamSectionData Position = 0x00002E58, Size = 0x00000008, RVA = 0x00007058, VirtualSize = 0x00000008
530+
531+
[04] PEResourceData Position = 0x00002E60, Size = 0x0000017D, RVA = 0x00007060, VirtualSize = 0x0000017D
532+
533+
[05] PEStreamSectionData Position = 0x00002FDD, Size = 0x00000003, RVA = 0x000071DD, VirtualSize = 0x00000003
530534

531535

532536
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

src/LibObjectFile.Tests/Verified/PEReaderTests.TestPrinter_name=NativeLibraryWin64.dll.verified.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,9 +450,11 @@ Sections
450450
[02] PEResourceDataEntry Position = 0x00002648, Size = 0x00000010, RVA = 0x00005048, VirtualSize = 0x00000010
451451
> CodePage = null, Data = PEResourceData { RVA = 0x5060, VirtualSize = 0x91, Position = 0x2660, Size = 0x91 }
452452

453-
[03] PEResourceData Position = 0x00002660, Size = 0x00000091, RVA = 0x00005060, VirtualSize = 0x00000091
453+
[03] PEStreamSectionData Position = 0x00002658, Size = 0x00000008, RVA = 0x00005058, VirtualSize = 0x00000008
454454

455-
[04] PEStreamSectionData Position = 0x000026F4, Size = 0x00000004, RVA = 0x000050F4, VirtualSize = 0x00000004
455+
[04] PEResourceData Position = 0x00002660, Size = 0x00000091, RVA = 0x00005060, VirtualSize = 0x00000091
456+
457+
[05] PEStreamSectionData Position = 0x000026F1, Size = 0x00000007, RVA = 0x000050F1, VirtualSize = 0x00000007
456458

457459

458460
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

src/LibObjectFile/Ar/ArArchiveFile.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ public void Write(Stream stream)
325325
writer.Write();
326326
}
327327

328-
public override void UpdateLayout(ArVisitorContext context)
328+
protected override void UpdateLayoutCore(ArVisitorContext context)
329329
{
330330

331331
}

src/LibObjectFile/Ar/ArBinaryFile.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public override void Write(ArArchiveFileWriter writer)
2929
}
3030
}
3131

32-
public override void UpdateLayout(ArVisitorContext context)
32+
protected override void UpdateLayoutCore(ArVisitorContext context)
3333
{
3434
Size = Stream != null ? (ulong) Stream.Length : 0;
3535
}

src/LibObjectFile/Ar/ArElfFile.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public override void Write(ArArchiveFileWriter writer)
4343
}
4444
}
4545

46-
public override void UpdateLayout(ArVisitorContext context)
46+
protected override void UpdateLayoutCore(ArVisitorContext context)
4747
{
4848
Size = 0;
4949

src/LibObjectFile/Ar/ArLongNamesTable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public override void Write(ArArchiveFileWriter writer)
108108
ArrayPool<byte>.Shared.Return(buffer);
109109
}
110110

111-
public override void UpdateLayout(ArVisitorContext context)
111+
protected override void UpdateLayoutCore(ArVisitorContext context)
112112
{
113113
Size = 0;
114114

src/LibObjectFile/Ar/ArSymbolTable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ protected override bool PrintMembers(StringBuilder builder)
205205
}
206206

207207

208-
public override void UpdateLayout(ArVisitorContext context)
208+
protected override void UpdateLayoutCore(ArVisitorContext context)
209209
{
210210
if (Parent == null) return;
211211

0 commit comments

Comments
 (0)