Advanced PE Image Reading¶
Note
The documentation has a new home: Check it out!
Advanced users might have the need to configure AsmResolver’s PE image reader. For example, instead of letting the PE reader throw exceptions upon reading invalid data, errors should be ignored and recovered from. Other uses might include a custom interpretation of .NET metadata streams. These kinds of settings can be configured using the PEReaderParameters
class.
var parameters = new PEReaderParameters();
These parameters can then be passed on to any of the PEImage.FromXXX
methods.
var image = PEImage.FromFile(@"C:\Path\To\File.exe", parameters);
Custom error handling¶
By default, AsmResolver throws exceptions upon encountering invalid data in the input file. To provide a custom method for handling parser errors, set the ErrorListener
property. There are a couple of default implementations that AsmResolver provides.
ThrowErrorListener
: Throws the recorded parser exception. This is the default.EmptyErrorListener
: Silently consumes any parser exception, and allows the reader to recover.DiagnosticBag
: Collects any parser exceptions, and allows the reader to recover.
Below an example on how to use the DiagnosticBag
for collecting parser errors and reporting them afterwards.
var bag = new DiagnosticBag();
var image = PEImage.FromFile("...", new PEReaderParameters(bag));
/* ... */
// Report any errors caught so far to the standard output.
foreach (var error in bag.Exceptions)
Console.WriteLine(error);
Note
The PEImage
class and its derivatives are initialized lazily. As a result, parser errors might not immediately appear in the Exceptions
property of the DiagnosticBag
class.
Custom metadata stream reading¶
Some .NET obfuscators insert custom metadata streams in the .NET metadata directory. By default, AsmResolver creates a CustomMetadataStream
object for any metadata stream for which the name is not recognized. To change this behaviour, you can provide a custom implementation of the IMetadataStreamReader
interface, or extend the existing DefaultMetadataStreamReader
class. Below an example of an implementation that changes the way a stream with the name #CustomStream
is parsed:
public class CustomMetadataStreamReader : DefaultMetadataStreamReader
{
public override IMetadataStream ReadStream(
PEReaderContext context,
MetadataStreamHeader header,
ref BinaryStreamReader reader)
{
if (header.Name == "#CustomStream")
{
// Do custom parsing here.
/* ... */
}
else
{
// Forward to default stream parser.
base.ReadStream(context, header, ref reader);
}
}
}
To let the reader use this implementation of the IMetadataStreamReader
, set the MetadataStreamReader
property of the reader parameters.
parameters.MetadataStreamReader = new CustomMetadataStreamReader();
Warning
Higher levels of abstractions (e.g. AsmResolver.DotNet
) depend on the existence of certain default stream types like the TablesStream
and StringsStream
. When these are not provided by your custom implementation, these abstractions will stop working correctly.
Custom debug data reading¶
Debug data directories can have arbitrary data stored in the PE image. By default, AsmResolver creates for every entry an instance of CustomDebugDataSegment
. This can be configured by providing a custom implementation of the IDebugDataReader
interface:
public class CustomDebugDataReader : DefaultDebugDataReader
{
public override IDebugDataSegment ReadDebugData(
PEReaderContext context,
DebugDataType type,
ref BinaryStreamReader reader)
{
if (type == DebugDataType.Coff)
{
// Do custom parsing here.
/* ... */
}
else
{
// Forward to default parser.
return base.ReadDebugData(context, type, ref reader);
}
}
}
To let the reader use this implementation of the IDebugDataReader
, set the DebugDataReader
property of the reader parameters.
parameters.DebugDataReader = new CustomDebugDataReader();