Advanced Module Reading¶
Note
The documentation has a new home: Check it out!
Advanced users might need to configure AsmResolver’s module reader. For example, instead of letting the module reader throw exceptions upon reading invalid data, errors should be ignored and recovered from. Other uses might include changing the way the underlying PE or method bodies are read. These kinds of settings can be configured using the ModuleReaderParameters
class.
var parameters = new ModuleReaderParameters();
These parameters can then be passed on to any of the ModuleDefinition.FromXXX
methods.
var module = ModuleDefinition.FromFile(@"C:\Path\To\File.exe", parameters);
PE image reading parameters¶
.NET modules are stored in a normal PE file. To customize the way AsmResolver reads the underlying PE image before it is being interpreted as a .NET image, ModuleReaderParameters
provides a PEReaderParameters
property that can be modified or replaced completely.
parameters.PEReaderParameters = new PEReaderParameters
{
...
};
For example, this can be in particular useful if you want to let AsmResolver ignore and recover from invalid data in the input file:
parameters.PEReaderParameters.ErrorListener = EmptyErrorListener.Instance;
Alternatively, this property can also be set through the constructor of the ModuleReaderParameters
class directly:
var parameters = new ModuleReaderParameters(EmptyErrorListener.Instance);
For more information on customizing the underlying PE image reading process, see Advanced PE Image Reading.
Changing working directory¶
Modules often depend on other assemblies. These assemblies often are placed in the same directory as the original module. However, should this not be the case, it is possible to change the path of the working directory of the resolvers.
parameters.WorkingDirectory = @"C:\Path\To\Different\Folder";
Alternatively, this property can also be set through the constructor of the ModuleReaderParameters
class directly:
var parameters = new ModuleReaderParameters(@"C:\Path\To\Different\Folder");
Custom .netmodule resolvers¶
For multi-module assemblies, AsmResolver looks into the path stored in WorkingDirectory
for files with the .netmodule extension by default. If it is necessary to change this behaviour, it is possible to provide a custom implementation of the INetModuleResolver
interface.
public class CustomNetModuleResolver : INetModuleResolver
{
public ModuleDefinition Resolve(string name)
{
// ...
}
}
To let the reader use this implementation of the INetModuleResolver
, set the NetModuleResolver
property of the reader parameters.
parameters.NetModuleResolver = new CustomNetModuleResolver();
Custom method body readers¶
Some .NET obfuscators store the implementation of method definitions in an encrypted form, use native method bodies, or use a custom format that is interpreted at runtime by the means of JIT hooking. To change the way of how method bodies are being read, it is possible to provide a custom implementation of the IMethodBodyReader
interface, or extend the default implementation.
Below an example of how to add support for reading simple x86 method bodies:
public class CustomMethodBodyReader : DefaultMethodBodyReader
{
public override MethodBody ReadMethodBody(
ModuleReaderContext context,
MethodDefinition owner,
in MethodDefinitionRow row)
{
if (owner.IsNative && row.Body.CanRead)
{
// Create raw binary reader if method is native.
var reader = row.Body.CreateReader();
// Read until the first occurrence of a ret instruction (opcode 0xC3).
// Note: This is for demonstration purposes only, and is by no means
// a very accurate heuristic for finding the boundaries of native
// method bodies.
var code = reader.ReadBytesUntil(0xC3);
// Create native method body.
return new NativeMethodBody(owner, code);
}
// Off-load to default implementation.
return base.ReadMethodBody(context, owner, row);
}
}
To let the reader use this implementation of the IMethodBodyReader
, set the MethodBodyReader
property of the reader parameters.
parameters.MethodBodyReader = new CustomMethodBodyReader();
Custom Field RVA reading¶
By default, the field RVA data storing the initial binary value of a field is interpreted as raw byte blobs, and are turned into instances of the DataSegment
class. To adjust this behaviour, it is possible to provide a custom implementation of the IFieldRvaDataReader
interface.
public class CustomFieldRvaDataReader : FieldRvaDataReader
{
public override ISegment ResolveFieldData(
IErrorListener listener,
Platform platform,
IDotNetDirectory directory,
in FieldRvaRow fieldRvaRow)
{
// ...
}
}
To let the reader use this implementation of the IFieldRvaDataReader
, set the FieldRvaDataReader
property of the reader parameters.
parameters.FieldRvaDataReader = new CustomFieldRvaDataReader();