Basic I/O
Every raw PE file interaction is done through classes defined by the
AsmResolver.PE.File namespace:
using AsmResolver.PE.File;
Creating a new PE file
Creating a PE file can be done through one of the PEFile constructors:
var peFile = new PEFile();
This will create a new empty PE file with 0 sections, and sets some values in the file header and optional header that are typical for a 32-bit Windows console application targeting the x86 platform.
Opening a PE file
Opening a PE file can be done through one of the FromXXX methods:
byte[] raw = ...
var peFile = PEFile.FromBytes(raw);
var peFile = PEFile.FromFile(@"C:\myfile.exe");
BinaryStreamReader reader = ...
var peFile = PEFile.FromReader(reader);
By default, AsmResolver assumes the PE file is in its unmapped form.
This is usually the case when files are read directly from the file
system. For memory-mapped PE files, use the overload of the FromReader
method, which allows for specifying the memory layout of the input.
BinaryStreamReader reader = ...
var peFile = PEFile.FromReader(reader, PEMappingMode.Mapped);
If you want to read large files (+100MB), consider using memory-mapped I/O instead:
using var service = new MemoryMappedFileService();
var peFile = PEFile.FromFile(service.OpenFile(@"C:\myfile.exe"));
On Windows, if a module is loaded and mapped in memory (e.g. as a native
dependency or by the means of LoadLibrary), it is possible to load the
PE file from memory by providing the HINSTANCE (a.k.a. module base
address):
IntPtr hInstance = ...
var peFile = PEFile.FromModuleBaseAddress(hInstance);
Writing PE files
Writing PE files can be done through the PEFile.Write method:
using var fs = File.Create(@"C:\mynewfile.exe");
peFile.Write(new BinaryStreamWriter(fs));
AsmResolver will then reassemble the file with all the changes you made.
Note that this will also recalculate some fields in the headers, such as
FileHeader.NumberOfSections. Furthermore, it will also recalculate the
offsets and virtual addresses of each section.