Skip to content

Commit

Permalink
Add better support for resource directory
Browse files Browse the repository at this point in the history
  • Loading branch information
xoofx committed Sep 28, 2024
1 parent 0f147b4 commit a8831a1
Show file tree
Hide file tree
Showing 44 changed files with 937 additions and 651 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -605,11 +605,20 @@ Sections
[04] .rsrc PESection Position = 0x00003E00, Size = 0x00000200, RVA = 0x00007000, VirtualSize = 0x000001E0, Characteristics = 0x40000040 (ContainsInitializedData, MemRead)

[00] PEResourceDirectory Position = 0x00003E00, Size = 0x000001E0, RVA = 0x00007000, VirtualSize = 0x000001E0
> PEResourceDirectoryEntry { Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDirectoryEntry { Id = 0x18 (RT_MANIFEST), Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDirectoryEntry { Id = 0x1, Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDataEntry { Id = 0x409 (en-US), Data = Stream (381 bytes) }
[00] PEStreamSectionData Position = 0x00003FD8, Size = 0x00000008, RVA = 0x000071D8, VirtualSize = 0x00000008
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x18, Entry = PEResourceDirectoryEntry { RVA = 0x7018, VirtualSize = 0x18, Position = 0x3E18, Size = 0x18, ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0 }
[00] PEResourceDirectoryEntry Position = 0x00003E18, Size = 0x00000018, RVA = 0x00007018, VirtualSize = 0x00000018
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x1, Entry = PEResourceDirectoryEntry { RVA = 0x7030, VirtualSize = 0x18, Position = 0x3E30, Size = 0x18, ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0 }

[01] PEResourceDirectoryEntry Position = 0x00003E30, Size = 0x00000018, RVA = 0x00007030, VirtualSize = 0x00000018
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x409, Entry = PEResourceDataEntry { RVA = 0x7048, VirtualSize = 0x10, Position = 0x3E48, Size = 0x10, CodePage = , Data = PEResourceData { RVA = 0x7060, VirtualSize = 0x17D, Position = 0x3E60, Size = 0x17D } }

[02] PEResourceDataEntry Position = 0x00003E48, Size = 0x00000010, RVA = 0x00007048, VirtualSize = 0x00000010
> CodePage = null, Data = PEResourceData { RVA = 0x7060, VirtualSize = 0x17D, Position = 0x3E60, Size = 0x17D }

[03] PEResourceData Position = 0x00003E60, Size = 0x0000017D, RVA = 0x00007060, VirtualSize = 0x0000017D


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,11 +512,20 @@ Sections
[04] .rsrc PESection Position = 0x00002E00, Size = 0x00000200, RVA = 0x00007000, VirtualSize = 0x000001E0, Characteristics = 0x40000040 (ContainsInitializedData, MemRead)

[00] PEResourceDirectory Position = 0x00002E00, Size = 0x000001E0, RVA = 0x00007000, VirtualSize = 0x000001E0
> PEResourceDirectoryEntry { Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDirectoryEntry { Id = 0x18 (RT_MANIFEST), Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDirectoryEntry { Id = 0x1, Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDataEntry { Id = 0x409 (en-US), Data = Stream (381 bytes) }
[00] PEStreamSectionData Position = 0x00002FD8, Size = 0x00000008, RVA = 0x000071D8, VirtualSize = 0x00000008
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x18, Entry = PEResourceDirectoryEntry { RVA = 0x7018, VirtualSize = 0x18, Position = 0x2E18, Size = 0x18, ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0 }
[00] PEResourceDirectoryEntry Position = 0x00002E18, Size = 0x00000018, RVA = 0x00007018, VirtualSize = 0x00000018
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x1, Entry = PEResourceDirectoryEntry { RVA = 0x7030, VirtualSize = 0x18, Position = 0x2E30, Size = 0x18, ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0 }

[01] PEResourceDirectoryEntry Position = 0x00002E30, Size = 0x00000018, RVA = 0x00007030, VirtualSize = 0x00000018
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x409, Entry = PEResourceDataEntry { RVA = 0x7048, VirtualSize = 0x10, Position = 0x2E48, Size = 0x10, CodePage = , Data = PEResourceData { RVA = 0x7060, VirtualSize = 0x17D, Position = 0x2E60, Size = 0x17D } }

[02] PEResourceDataEntry Position = 0x00002E48, Size = 0x00000010, RVA = 0x00007048, VirtualSize = 0x00000010
> CodePage = null, Data = PEResourceData { RVA = 0x7060, VirtualSize = 0x17D, Position = 0x2E60, Size = 0x17D }

[03] PEResourceData Position = 0x00002E60, Size = 0x0000017D, RVA = 0x00007060, VirtualSize = 0x0000017D


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,11 +436,22 @@ Sections
[04] .rsrc PESection Position = 0x00002600, Size = 0x00000200, RVA = 0x00005000, VirtualSize = 0x000000F8, Characteristics = 0x40000040 (ContainsInitializedData, MemRead)

[00] PEResourceDirectory Position = 0x00002600, Size = 0x000000F8, RVA = 0x00005000, VirtualSize = 0x000000F8
> PEResourceDirectoryEntry { Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDirectoryEntry { Id = 0x18 (RT_MANIFEST), Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDirectoryEntry { Id = 0x2, Entries[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0}
> PEResourceDataEntry { Id = 0x409 (en-US), Data = Stream (145 bytes) }
[00] PEStreamSectionData Position = 0x000026EC, Size = 0x0000000C, RVA = 0x000050EC, VirtualSize = 0x0000000C
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x18, Entry = PEResourceDirectoryEntry { RVA = 0x5018, VirtualSize = 0x18, Position = 0x2618, Size = 0x18, ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0 }
[00] PEResourceDirectoryEntry Position = 0x00002618, Size = 0x00000018, RVA = 0x00005018, VirtualSize = 0x00000018
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x2, Entry = PEResourceDirectoryEntry { RVA = 0x5030, VirtualSize = 0x18, Position = 0x2630, Size = 0x18, ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, MajorVersion = 0, MinorVersion = 0 }

[01] PEResourceDirectoryEntry Position = 0x00002630, Size = 0x00000018, RVA = 0x00005030, VirtualSize = 0x00000018
> ByNames[0], ByIds[1] , TimeDateStamp = 01/01/1970 00:00:00, Version = 0.0
[0] Id = 0x409, Entry = PEResourceDataEntry { RVA = 0x5048, VirtualSize = 0x10, Position = 0x2648, Size = 0x10, CodePage = , Data = PEResourceData { RVA = 0x5060, VirtualSize = 0x91, Position = 0x2660, Size = 0x91 } }

[02] PEResourceDataEntry Position = 0x00002648, Size = 0x00000010, RVA = 0x00005048, VirtualSize = 0x00000010
> CodePage = null, Data = PEResourceData { RVA = 0x5060, VirtualSize = 0x91, Position = 0x2660, Size = 0x91 }

[03] PEResourceData Position = 0x00002660, Size = 0x00000091, RVA = 0x00005060, VirtualSize = 0x00000091

[04] PEStreamSectionData Position = 0x000026F4, Size = 0x00000004, RVA = 0x000050F4, VirtualSize = 0x00000004


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/LibObjectFile/ObjectFileElement.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.

Expand Down
17 changes: 16 additions & 1 deletion src/LibObjectFile/ObjectFileReaderWriter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.

Expand All @@ -18,6 +18,7 @@ namespace LibObjectFile;
public abstract class ObjectFileReaderWriter : VisitorContextBase
{
private Stream _stream;
private readonly byte[] _zeroBuffer = new byte[1024];

internal ObjectFileReaderWriter(ObjectFileElement file, Stream stream) : this(file, stream, new DiagnosticBag())
{
Expand Down Expand Up @@ -192,6 +193,20 @@ public void Write(byte[] buffer, int offset, int count)
Stream.Write(buffer, offset, count);
}

/// <summary>
/// Writes count bytes with zero.
/// </summary>
/// <param name="count">The number of bytes to write with zero.</param>
public void WriteZero(int count)
{
while (count > 0)
{
var size = Math.Min(count, _zeroBuffer.Length);
Stream.Write(_zeroBuffer, 0, size);
count -= size;
}
}

/// <summary>
/// Writes to the <see cref="Stream"/> and current position from the specified buffer.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions src/LibObjectFile/PE/DataDirectory/PEArchitectureDirectory.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.

Expand All @@ -18,7 +18,7 @@ public PEArchitectureDirectory() : base(PEDataDirectoryKind.Architecture)
{
}

protected override uint ComputeHeaderSize(PEVisitorContext context)
protected override uint ComputeHeaderSize(PELayoutContext context)
{
return 0;
}
Expand Down
12 changes: 7 additions & 5 deletions src/LibObjectFile/PE/DataDirectory/PEBaseRelocationDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public PEBaseRelocationDirectory() : base(PEDataDirectoryKind.BaseRelocation)

public List<PEBaseRelocationBlock> Blocks { get; } = new();

protected override unsafe uint ComputeHeaderSize(PEVisitorContext context)
protected override unsafe uint ComputeHeaderSize(PELayoutContext context)
{
var size = 0U;
foreach (var block in Blocks)
Expand All @@ -44,8 +44,6 @@ public override unsafe void Read(PEImageReader reader)
return;
}

var allSectionData = reader.File.GetAllSectionData();

int blockIndex = 0;
while (buffer.Length > 0)
{
Expand All @@ -59,7 +57,6 @@ public override unsafe void Read(PEImageReader reader)
}

var sizeOfRelocations = (int)location.SizeOfBlock - sizeof(ImageBaseRelocation);


// Create a block
var block = new PEBaseRelocationBlock(new PESectionLink(section, (uint)(location.PageRVA - section.RVA)))
Expand Down Expand Up @@ -89,7 +86,12 @@ internal override void Bind(PEImageReader reader)

public override void Write(PEImageWriter writer)
{
throw new NotImplementedException();
ImageBaseRelocation rawBlock = default;
foreach (var block in Blocks)
{
rawBlock.PageRVA = block.SectionLink.RVA();
rawBlock.SizeOfBlock = block.CalculateSizeOf();
}
}

protected override bool PrintMembers(StringBuilder builder)
Expand Down
26 changes: 22 additions & 4 deletions src/LibObjectFile/PE/DataDirectory/PEBoundImportDirectory.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.

Expand Down Expand Up @@ -30,9 +30,10 @@ public PEBoundImportDirectory() : base(PEDataDirectoryKind.BoundImport)
public List<PEBoundImportDirectoryEntry> Entries { get; }

/// <inheritdoc/>
protected override uint ComputeHeaderSize(PEVisitorContext context)
protected override unsafe uint ComputeHeaderSize(PELayoutContext context)
{
var size = 0u;
// Last raw entry is zero
var size = (uint)sizeof(RawPEBoundImportDirectory);
var entries = CollectionsMarshal.AsSpan(Entries);
foreach (var entry in entries)
{
Expand Down Expand Up @@ -156,6 +157,23 @@ internal override void Bind(PEImageReader reader)
/// <inheritdoc/>
public override void Write(PEImageWriter writer)
{
throw new NotImplementedException();
RawPEBoundImportDirectory rawEntry = default;
RawPEBoundImportForwarderRef rawForwarderRef = default;
foreach (var entry in Entries)
{
rawEntry.OffsetModuleName = (ushort)entry.ModuleName.RVO;
rawEntry.NumberOfModuleForwarderRefs = (ushort)entry.ForwarderRefs.Count;
writer.Write(rawEntry);

foreach (var forwarderRef in entry.ForwarderRefs)
{
rawForwarderRef.OffsetModuleName = (ushort)forwarderRef.ModuleName.RVO;
writer.Write(rawForwarderRef);
}
}

// Last entry is null
rawEntry = default;
writer.Write(rawEntry);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.

Expand Down
4 changes: 2 additions & 2 deletions src/LibObjectFile/PE/DataDirectory/PEClrMetadata.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.

Expand All @@ -12,7 +12,7 @@ public PEClrMetadata() : base(PEDataDirectoryKind.ClrMetadata)
{
}

protected override uint ComputeHeaderSize(PEVisitorContext context)
protected override uint ComputeHeaderSize(PELayoutContext context)
{
return 0;
}
Expand Down
107 changes: 107 additions & 0 deletions src/LibObjectFile/PE/DataDirectory/PECompositeSectionData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.

using System.Collections.Generic;
using System.Linq;
using LibObjectFile.Collections;
using LibObjectFile.Utils;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace LibObjectFile.PE;

/// <summary>
/// A section data that contains a list of <see cref="PESectionData"/> and an optional header of data.
/// </summary>
public abstract class PECompositeSectionData : PESectionData
{
protected PECompositeSectionData()
{
Content = CreateObjectList<PESectionData>(this);
}

public sealed override bool HasChildren => true;

internal uint HeaderSize { get; private protected set; }

/// <summary>
/// Gets the content of this directory.
/// </summary>
public ObjectList<PESectionData> Content { get; }

public sealed override void UpdateLayout(PELayoutContext context)
{
var va = RVA;

// We compute the size of the directory header
// Each directory have a specific layout, so we delegate the computation to the derived class
var headerSize = ComputeHeaderSize(context);
HeaderSize = headerSize;
va += headerSize;
ulong size = headerSize;

// A directory could have a content in addition to the header
// So we update the VirtualAddress of each content and update the layout
var position = Position + headerSize;
foreach (var data in Content)
{
// Make sure we align the position and the virtual address
var alignment = data.GetRequiredPositionAlignment(context.File);

if (alignment > 1)
{
var newPosition = AlignHelper.AlignUp(position, alignment);
size += (uint)newPosition - position;
position = newPosition;
va = AlignHelper.AlignUp(va, alignment);
}

data.RVA = va;

// Update layout will update virtual address
if (!context.UpdateSizeOnly)
{
data.Position = position;
}
data.UpdateLayout(context);

var dataSize = AlignHelper.AlignUp((uint)data.Size, data.GetRequiredSizeAlignment(context.File));
va += (uint)dataSize;
size += dataSize;
position += dataSize;
}

Size = size;
}

internal virtual IEnumerable<PEObjectBase> CollectImplicitSectionDataList() => Enumerable.Empty<PEObjectBase>();

internal virtual void Bind(PEImageReader reader)
{
}

internal void WriteHeaderAndContent(PEImageWriter writer)
{
Write(writer);

foreach (var table in Content)
{
table.Write(writer);
}
}

protected abstract uint ComputeHeaderSize(PELayoutContext context);

protected sealed override bool TryFindByRVAInChildren(RVA rva, out PEObject? result)
=> Content.TryFindByRVA(rva, true, out result);

protected sealed override void UpdateRVAInChildren()
{
var va = RVA;
foreach (var table in Content)
{
table.UpdateRVA(va);
va += (uint)table.Size;
}
}
}
Loading

0 comments on commit a8831a1

Please sign in to comment.