-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
[cDAC] DAC like entry point #112653
base: main
Are you sure you want to change the base?
[cDAC] DAC like entry point #112653
Conversation
Tagging subscribers to this area: @tommcdon |
using BinaryReader reader = new(new DataTargetStream(_dataTarget, _baseAddress)); | ||
|
||
ushort dosMagic = reader.ReadUInt16(); | ||
if (dosMagic != 0x5A4D) // "MZ" | ||
return false; | ||
|
||
// PE Header offset is at 0x3C in DOS header | ||
reader.BaseStream.Seek(0x3C, SeekOrigin.Begin); | ||
_peSigOffset = reader.ReadUInt32(); | ||
|
||
// Read PE signature | ||
reader.BaseStream.Seek(_peSigOffset, SeekOrigin.Begin); | ||
uint peSig = reader.ReadUInt32(); | ||
if (peSig != 0x00004550) // "PE00" | ||
return false; | ||
|
||
// Seek to beginning of opt header and read magic | ||
reader.BaseStream.Seek(_peSigOffset + 0x18, SeekOrigin.Begin); | ||
_optHeaderMagic = reader.ReadUInt16(); | ||
|
||
// Seek back to beginning of opt header and parse | ||
reader.BaseStream.Seek(_peSigOffset + 0x18, SeekOrigin.Begin); | ||
uint rva; | ||
switch (_optHeaderMagic) | ||
{ | ||
case 0x10B: // PE32 | ||
IMAGE_OPTIONAL_HEADER32 optHeader32 = new(reader); | ||
rva = optHeader32.DataDirectory[0].VirtualAddress; | ||
break; | ||
case 0x20B: // PE32+ | ||
IMAGE_OPTIONAL_HEADER64 optHeader64 = new(reader); | ||
rva = optHeader64.DataDirectory[0].VirtualAddress; | ||
break; | ||
// unknown type, invalid | ||
default: | ||
return false; | ||
} | ||
|
||
// Seek to export directory and parse | ||
reader.BaseStream.Seek(rva, SeekOrigin.Begin); | ||
_exportDir = new IMAGE_EXPORT_DIRECTORY(reader); | ||
|
||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use System.Reflection.PortableExecutable.PEReader to get to the export directory here?
Something like the following:
using Stream stream = new DataTargetStream(_dataTarget, _baseAddress);
using PEReader reader = new(stream);
var exportsDirectory = reader.PEHeaders.PEHeader.ExportTableDirectory;
if (!reader.PEHeaders.TryGetDirectoryOffset(exportsDirectory, out var offset))
{
return false;
}
stream.Seek(offset, SeekOrigin.Begin);
_exportDir = new IMAGE_EXPORT_DIRECTORY(new BinaryReader(stream));
return true;
This would let you get out of most of the PE decoding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw the PEReader and based some of the code off of it.
My concern is that the PEReader does not have the signature checking semantics I was looking for.
Because the DAC only targets a single platform, it invoked the exact reader for the executable format.
As far as I can tell, using the ICLRDataTarget, we don't know which platform we are targeting. Unless I'm overlooking something, my plan is to run the PEDecoder, ELFDecoder, and MACHODecoder on each target which will be verified using the known signatures.
It looks like the PEDecoder assumes that the PE is a COFF file if the PE DOS magic isn't correct. In this case, I'd want to bail.
Line 249 in 1d1bf92
private static void SkipDosHeader(ref PEBinaryReader reader, out bool isCOFFOnly) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at it again, if the file parses as COFFOnly, the PEHeader won't be available.
I can check if it's valid using that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, the PEReader
is not safe to use on non-PE/COFF files. Even if the signatures fail to parse, the PEHeaders.cs
will attempt to use the garbage COFFHeader to read an arbitrary number of sections potentially causing stream overrun.
Lines 292 to 308 in 4dde471
private ImmutableArray<SectionHeader> ReadSectionHeaders(ref PEBinaryReader reader) | |
{ | |
int numberOfSections = _coffHeader.NumberOfSections; | |
if (numberOfSections < 0) | |
{ | |
throw new BadImageFormatException(SR.InvalidNumberOfSections); | |
} | |
var builder = ImmutableArray.CreateBuilder<SectionHeader>(numberOfSections); | |
for (int i = 0; i < numberOfSections; i++) | |
{ | |
builder.Add(new SectionHeader(ref reader)); | |
} | |
return builder.MoveToImmutable(); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dang... Yeah that's not particularly helpful in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened #112830 to add this fail-fast capability to PEReader
; this is not the first time it was desired. In the meantime you can do a minimal signature validation yourself and create the PEReader
afterwards:
using DataTargetStream stream = new(_dataTarget, _baseAddress);
using BinaryReader reader = new(stream, Encoding.UTF8, leaveOpen: true);
ushort dosMagic = reader.ReadUInt16();
if (dosMagic != 0x5A4D) // "MZ"
return false;
// PE Header offset is at 0x3C in DOS header
reader.BaseStream.Seek(0x3C, SeekOrigin.Begin);
uint peSigOffset = reader.ReadUInt32();
// Read PE signature
reader.BaseStream.Seek(peSigOffset, SeekOrigin.Begin);
uint peSig = reader.ReadUInt32();
if (peSig != 0x00004550) // "PE00"
return false;
using PEReader reader = new(stream);
var exportsDirectory = reader.PEHeaders.PEHeader!.ExportTableDirectory;
if (!reader.PEHeaders.TryGetDirectoryOffset(exportsDirectory, out var offset))
{
return false;
}
stream.Seek(offset, SeekOrigin.Begin);
_exportDir = new IMAGE_EXPORT_DIRECTORY(reader);
return true;
64b6a79
to
b10c80b
Compare
|
||
public override long Position { get => _offset; set => _offset = value; } | ||
|
||
public override unsafe int Read(byte[] buffer, int offset, int count) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should also override the Read
overload that takes a span.
143aa67
to
e7ac06f
Compare
No description provided.