Releases: Washi1337/AsmResolver
6.0.0-beta.1
This marks the second major bump of AsmResolver since the rewrite. Note that this is still a pre-release and that last-minute breaking API changes may still be introduced before full release.
Summary
Version 6.0.0 of AsmResolver focuses on achieving three very important long-awaited milestones:
-
Unmanaged PE file building: A complete revamp of the underlying PE file building mechanism has finally allowed for a long-awaited
UnmanagedPEFileBuilder
: A robust yet flexible foundation for reconstructing fully native PE files as well as mixed-mode .NET modules. We are not quite there yet with integrating it into theAsmResolver.DotNet
package, but it should pave the way for it as well as help with processing ReadyToRun- and NativeAOT-compiled files in the future. See the new documentation for details. -
.NET Framework 3.5 support: Previously, AsmResolver targeted .NET standard 2.0, allowing developers to use a .NET Framework version as low as 4.6.1. While 4.8.1 is installed by default on modern Windows machines and we are approaching the release of .NET 9, many use-cases still require older versions of .NET (in particular, game-modding and dynamic code deobfuscation). With the awesome help of the people behind the @MonoMod project, we have been finally able to make AsmResolver 6.0.0 fully compatible with .NET Framework 3.5.
-
API simplification and improvements: The existing public API also has undergone many quality-of-life improvements to ensure a better developer experience. This includes removing many of the redundant interfaces, as well as flattening a lot of namespaces to reduce the number of
using
directives required for typical usecases of AsmResolver. Performance has also been improved a lot in various areas, partially thanks to the new concept ofRuntimeContext
s. And of course, many bug fixes have been squashed.
Important to note is that this release introduces breaking changes with respect to 5.x.x. In the following, the important changes are listed:
New Features
- Add
UnmanagedPEFileBuilder
, allowing forPEImage
s containing only native code or both native and managed .NET code to be built with little effort (#554). - It is now much easier to customize existing PE file builders (or create your own) to get full control over the final PE file layout thanks to the new
PEFileBuilder
base class. - Add .NET 3.5 support, using MonoMod.Backports (#536, #540, #544, #450, #439, with the help of @MonoMod and @Windows10CE).
- Add the concept of
RuntimeContext
s, allowing for .NET modules to be loaded under a specific .NET runtime or AppHost bundle context, which avoids many type resolution problems, drastically reduces memory footprint and also increases overall performance (#471, #537). - Add
PEImage::ToPEFile()
. - Add
TrampolineTableBuffer
, allowing for IAT trampolines to be built easily. - Add
TypeMemoryLayout::IsReferenceOrContainsReferences
flag, equivalent to RuntimeHelpers::IsReferenceOrContainsReferences<T> but determined statically (#530, #539). - Add
BundleAssemblyResolver
(2fc1872) - Add
SetAccessorMethods
toPropertyDefinition
andEventDefinition
(#555, thanks @ds5678). - Add
AggressiveInlining
,AggressiveOptimization
andHasSecurityMitigations
flags toMethodDefinition
andMethodImplAttributes
(bf80344). - Add
IInputFile::BaseAddress
(a1af121)
Improvements
- Remove many redundant interfaces (e.g.,
IPEFile
andIPEImage
). Developers are expected to use their immediate implementing class (i.e.,PEFile
andPEImage
) (#445, #561, #562). - Flatten many namespaces, drastically reducing the required
using
directives for typical AsmResolver usecases (#446, #560). - Use
EmptyErrorListener.Instance
for reading input files by default (#472, #564). - Remove
System.Text.Json
as a hard dependency requirement, making the library more portable for older .NET targets ( #450, #538). - Add .NET 9 as a known corlib (#548, thanks @ds5678).
- Add correct interpretation of
#Schema
and#JTD
metadata streams (#557, thanks @ElektroKill). - Add
FunctionPointerTypeSignature
support forSignatureComparer::GetHashCode
(#551, thanks @BadRyuner). - Rewrite
IconResource
into a more intuitive API that also supports language-specific icons and cursors (#565). - Let
PESection::Name
accept arbitrary UTF8 strings (#454). - Add
OptionalHeader::SetDataDirectory
(7b27c91). - Add
SetDataDirectory.CreateForSegment
(7b27c91.)
Bug Fixes
- Fix an issue where EnC metadata streams are looked up using case insensitive name lookup (#557, thanks @ElektroKill).
- Fix an issue where Win32 resources were inserted into a PE's root resource directory out-of-order, causing version info and icons to not be interpreted by Windows correctly (#552, #553).
- Fix a data race in caching mechanism of
StringsStream
andUserStringsStream
(b1ded1f). - Fix an issue related to reading and writing signed compressed integers for lower bounds in array type signatures (c7bc9f6).
Documentation
- Documentation on the new PE file building mechanism was added.
- The
AsmResolver.PE.Win32Resource
package now has its dedicated documentation section.
5.5.1
This is an incremental maintenance release that adds .NET 8.0 as an official target and fixes issues related to type signatures, CIL optimizations, as well as some rare edge cases in .NET metadata directory parsing.
New Features
- Add support for importing function pointer type signatures via reflection (#523, thanks @Windows10CE).
- Add
BinaryStreamWriter::AlignRelative
(af2e49d) - Add .NET 8.0 target.
Bug Fixes
- Fix a couple issues regarding hash computation of generic instance and custom modifier type signatures in
SignatureComparer
(#512, thanks @rstarkov) - Fix an issue where optimizing
ldloca
andldarga
opcodes would not shorten to their shorter variants (9ab4e94) - Fix an issue where the same metadata members could be added twice to the exact same collection, resulting in ownership problems (#513)
- Fix an issue where .NET modules containing a metadata directory at an unaligned offset would read stream headers incorrectly (af2e49d).
5.5.0
This version brings rudimentary low-level .NET ReadyToRun (R2R) parsing and writing to AsmResolver, allowing you to locate and read native code of precompiled managed method bodies (see documentation). Additionally, basic Span<T>
support was added to primitives like IDataSource
and Utf8String
for newer .NET runtime targets (netstandard 2.1 and above), and some new convenience APIs were added. Finally, some bugfixes were implemented, increasing general stability of the library.
New Features
- Add support for low level .NET ReadyToRun assembly parsing (#294, #495). See documentation.
- Add basic
Span<T>
support forIDataSource
s andUtf8String
(#483, thanks @DaZombieKiller). - Add option to suppress .NET resource data deduplication (#492).
- Add
TypeDefinition::GetConstructor
,MethodDefinition::CreateConstructor
and similar (#480). - Add
ReferenceTable
primitive segment class, representing structures like VTables that can be directly used as a writableISegment
. - Add
BinaryStreamReader::RemainingLength
. - Reduce allocations of null
SegmentReference
s. - Add
netstandard2.1
target.
Bug Fixes
TypeReference::IsImportedInModule
now correctly takes its resolution scope into account (#497).- Type resolution now correctly first checks whether the resolution scope refers to the current assembly (7403692).
TypeNameParser
now correctly does not return fully imported types, but they can still be resolved using.Resolve()
(#497).MemberCloner
now correctly fixes cross-references to includedSystem.Type
arguments in Custom Attributes (#482, #493).- Fixed an issue where .NET resource data with a malformed header would crash the parser (#492).
- Fixed an issue where
ZeroesDataSource
would clear out too much data in the buffer provided toReadBytes
(thanks @DaZombieKiller) - Fixed an issue where
BitList
would incorrectly accept negative indices (#478). - Fixed an issue where duplicated members would not be added even when preserving metadata tokens (#478).
- Fixed an issue where members with manually assigned tokens would not be saved correctly when assembly had no backing .NET directory (#478)
- Fixed a race condition in the caching mechanism of assembly resolution (61b6ddf)
- Fixed a race condition in the caching mechanism of input file services (61b6ddf)
- Fixed an issue where string operands in IL pretty printed instructions were not escaped properly (6e039b9)
Minor Breaking Changes
- Remove
TlsCallbackCollection
, replaced withReferenceTable
. TlsDirectory::CallbackFunctions
is now of typeReferenceTable
.IDotNetDirectory::ManagedNativeHeader
is now of the more specific segment typeIManagedNativeHeader
.
5.4.0
This release includes support for PE certificate tables, PE forwarder exports, as well as various quality of life improvements and bug fixes. Check out the documentation and the full change-log below:
New Features
- Add read/write support for PE certificate tables (#451).
- Add support for arbitrary symbols to be references in
NativeMethodBody
(#444, #449). - Let assembly resolution mechanism respect
ModuleReaderParameters::WorkingDirectory
(#438, #441). - Add read/write support for
ExportedSymbol::IsForwarder
(#437, #440). - Add
ManagedPEFileBuilder::ErrorListener
(#468). - Allow for
ITypeDescriptor::Scope
to benull
and of typeModuleDefinition
. (#466) - Add language identifiers for Version Info win32 resources (#457)
- Add support for attaching multiple listeners to the
MemberCloner
(#461) - Add
DotNetRuntimeInfo::GetDefaultCorLib
andKnownCorlibs::FromRuntimeInfo
(#462) PEFile::CreateReaderAtFileOffset
now supports reading from EOF data (5821428).- Add Source Link (#469, thanks @ds5678)
Bug fixes
- Fix an issue when resolution scope of a type reference set to 0 when the coded index to the current module was meant instead (#459, #466).
- Fix an issue where field RVA rows were not always correctly updated when writing unchanged serialized PEs (#468).
- Fix an issue where win32 resource VersionInfo tables were not correctly aligned to the next 4-byte boundary, resulting in some of the resource to be trimmed away when rebuilding (#456).
- Fix an issue where the
Culture=
part ofAssemblyDescriptor.FullName
was not included in the output (#458). - Fix an issue where PE section names would result in spurious "name too long" exceptions when containing unconventional UTF-8 code points (#453, #455).
- Fix an issue where
GetImpliedMemoryLayout
would stack-overflow with unresolved generic parameter type signatures (#447, #448). - Fix an issue where
ModuleReaderParameters
were not passed along correctly inModuleDefinition::FromBytes
(bbf5781)
5.3.0
This version is mostly a maintenance version with performance improvements and bug fixes. Developers of .NET obfsucators and deobfuscators will also be happy to know that ManagedPEImageBuilder
now accepts any IErrorListener
. This should make it easier to ignore any invalid metadata that is introduced to the assembly model (e.g., by passing in an EmptyErrorListener
). Finally, a migration from readthedocs to DocFX was made, giving a new home and look to the documentation. Let us know what you think of it!
New Features
- Add support for arbitrary
IErrorListener
objects as opposed to justDiagnosticBag
s inManagedPEImageBuilder
(#367, thanks @ds5678 for the help!). - Add
LazyVariable<TOwner, TValue>
, reducing the number of allocations made by AsmResolver's internals significantly for larger binaries (#428) - Add
Platform::Is32Bit
,Platform::Is64Bit
andPlatform::PointerSize
(#430) - Add
ZeroesSegment
andZeroesDataSource
for creating, reading and writing memory-efficient segments containing only zero bytes (#430). - Migrate documentation to DocFX with full API reference (2545e1a).
Bug Fixes
- Fixed an issue where
SignatureComparer::GetHashCode
for assembly descriptors did not respect the configuration flags passed into the constructor (#427, #429). - Field RVA reader now correctly supports reading the data for
IntPtr
andUIntPtr
typed fields (#430). - Fixed an issue where reading from a section that is empty on the disk would throw even if the section has a non-zero virtual size (#430).
- Fixed an issue where entries in an import descriptor were not read correctly if
OriginalFirstThunk
= 0. This is the case for many packed executables such as UPX packed binaries (#431, #432)
Deprecations
PEImageBuildContext::DiagnosticBag
is superseded byPEImageBuildContext::IErrorListener
.- The constructor
PEImageBuildResult
taking aDiagnosticBag
is superseded by the one taking anIErrorListener
.
Minor Breaking Changes
- The signature for
IFieldRvaDataReader::ResolveFieldData
has changed slightly. See the documentation for how to use the new interface (#430).
5.2.0
New Features
- Add
TypeSignature::IsCompatibleWith
andTypeSignature::IsAssignableTo
methods (#421) - Add support for patching AppHost / SingleFileHost files without requiring the original SDK template file (#420, #424)
- Add support for metadata tokens and unmanaged entry points in
DotNetDirectory
(#422) - Add
Parameter::GetOrCreateDefinition()
(#418, thanks @ElektroKill) - Add read support for PDB modules (#412)
- Add read support for many more PDB symbol and leaf record types (#412)
- Add basic metadata properties to
PdbImage
(e28df25) - Add
OptionalHeader::SetDataDirectory
helper method (8357a77) - Add
CallingConventionSignature::CallingConvention
convenience property that masks out the used convention fromAttributes
(#414) - Add undocumented
CallingConvention::NativeVarArg
(#414)
Bug Fixes
- Fix an issue related to metadata token preservation of MemberRefParents (caeef35)
- Fix an issue with
MethodSignature
's sentinel parameter type preservation (#413, #414). - Fix
ParameterCollection::ThisParameter
's parameter type for generic instance types (e27b6e8, thanks @ElektroKill) - Fix
MethodSignatureBase::GetTotalParameterCount()
forExplicitThis
signatures (dae9909, thanks @ElektroKill)
Deprecations
- All constructors of
BundlerParameters
are superseded byBundlerParameters::FromTemplate
andBundlerParameters::FromExistingFile
. - Assignments of
DotNetDirectory::EntryPoint
using anuint
are obsoleted and should be replaced with a construction of aDotNetEntryPoint
structure.
Minor Breaking ABI Changes
- Remove spurious
CallingConventionSignature::IsSentinel
(#414) - Change property type of
DotNetDirectory::EntryPoint
fromuint
toDotNetEntryPoint
DU struct.
5.1.0
New Features
- Add fluent patching API, allowing for easy and quick binary patches on PE files as well as individual segments (#403, #405). Check out the documentation.
- Add option to preserve spurious metadata streams and their order (#394, #406)
- Add generic
ModuleDefinition::LookupMember<T>
andModuleDefinition::TryLookupMember<T>
methods (#392, #402) - Add
TypeDefinition::IsModuleType
(#391, thanks @sunnamed434) - Add rudimentary custom attribute validation, avoiding the accidental construction of incorrect attribute signatures (#389, #407)
Bug Fixes
- Fix generic custom attributes reader errors (#397, #401)
- Fix
GetModuleType()
behavior for .NET Core / .NET 5+ modules (#395, #396) - Fix .NET runtime detection when multiple corlibs references are present in the binary (a0bb1df)
Deprecations
CodeSegment
is now deprecated. Use theDataSegment
combined with the new patching API for address fixups.
Other
- Fixed some spelling mistakes in the documentation (#398, #400, thanks @Svenskithesource)
5.0.0
This marks the first major version bump since the rewrite of AsmResolver. A huge thanks to all the contributors and testers. Without them this release would not have been possible!
Summary
- Significant performance boost and memory consumption reductions across the board.
- Rudimentary read support for PDB files (both Windows PDB and Portable PDB).
- Various Quality-of-Life improvements of the API.
- Overall robustness improvements against malformed input binaries and/or edge-cases.
Full change log
New Features
- Add read / write support for PortablePDB metadata streams and tables (#348)
- Add a new WIP package called
AsmResolver.Symbols.Pdb
for reading and writing Windows PDB files using only managed code (#324, #326, #342, #368 (thanks @ds5678)) - Add the notion of
IMemberClonerListener
s, allowing for automatically post-processing cloned metadata (e.g., automatically injecting it into the target module) as the cloner is cloning metadata (#333, #337, #354, thanks @CursedLand) - Add
DotNetRuntimeInfo::IsNetCoreApp
,IsNetFramework
andIsNetStandard
properties for easily identifying whether a module targets .NET Core, .NET Framework or .NET Standard (505da7a). - Add
SignatureComparer::Default
(#366, thanks @ds5678) - Add
TypeDefinition::IsByRefLike
(#358, #362) - Make
AsmResolver.DotNet
trimmable (#304, thanks @ds5678) - Add
MetadataTable::IsSorted
property (#348) DynamicMethodDefinition
now has better support for dynamic methods that are initialized viaDynamicILInfo
(b0b13c8)- Add convenience constructors for
BinaryStreamReader
that take abyte[]
or aIDataSource
alone (54c65ee). - Add
OriginalMetadataTokenProvider
(#361) - Add
type.IsTypeOfUtf8
to avoid conversions fromUtf8String
tostring
(baf25ac)
Breaking Changes
- Make
SignatureComparer
immutable (#366, thanks @ds5678) - Refactor
class BlobReadContext
to a mutablestruct BlobReaderContext
(#356, c0283c7). - Change
ISegment::UpdateOffsets
's method signature (#236, #346) - Remove
ITlsDirectory::ImageBase
andCodeSegment::ImageBase
(#346) - Remove
SegmentReference::CanUpdateOffsets
andSegmentReference::UpdateOffsets
(#346) - Add setter to
TypeDefOrRefSignature::Type
andGenericInstanceTypeSignature::Type
(#338, thanks @JPaja) - Move
AsmResolver.DotNet.Dynamic
into a separate nuget package (#304). - Rename
Entrypoint
toEntryPoint
(b6fa3ed). - Rename
OptionalHeaderMagic::Pe32
andPe32Plus
toPE32
andPE32Plus
(d954be0). - Let
LazyVariable
lock on itself (16367c1) - Consolidate
ContinuousMetadataRange
andRedirectedMetadataRange
to a single structMetadataRange
(3bb6b6a) - Let
OneToManyRelation
return aValueSet
with a struct enumerator instead of a genericICollection
(07b09c3) - Change type of
MemberClonerContext::Importer
toCloneContextAwareReferenceImporter
. - Many constructors of metadata members taking a name parameter are now of type
Utf8String
instead ofstring
(baf25ac, 5d8cb88). - Rename
FullNameGenerator
toMemberNameGenerator
. This class has a new layout and is not API compatible with the old version (#386).
Performance Improvements
- Precomputing capacity properties for lists containing read metadata reduced memory consumption by roughly 5%-10% (#316)
- Many small buffers and temporary memory streams are being reused during the writing process where possible. This reduces the number of allocations by up to 20% (#317).
- Various reader context types are now stack allocated (#356, c0283c7).
- Custom attribute signatures are now only read when absolutely necessary, preventing many unnecessary expensive type resolutions and thus many allocations (#336, #351).
MethodImplementation
now implementsIEquatable<MethodImplementation>
, drastically reducing allocations and increasing performance for large binaries with lots of interface implementations (d10cf47).- Replace PE section lookup LINQ code with expanded for loop, drastically reducing allocations in general (1ff0a0f)
OneToManyRelation
now returns aValueSet
with a struct enumerator instead of an interface (07b09c3)- Avoid many string allocations from
Utf8String
instances when resolving types and members (baf25ac) - Avoid many allocations of traversed tokens during type signature parsing where possible, reducing memory consumption of the reader in general (c0283c7)
- Avoid duplication of
Utf8String
objects inStringStreamBuffer
(533a911) - Avoid allocation of many empty metadata value sets (especially for custom attributes), significantly reducing memory consumption (ce0a94f)
- Significantly improve performance of
member.FullName
and reduced memory consumption by up to 70% (#386)
Bug Fixes
- Modifications to a LazyList (and all its derivatives) are now guarded with locks to prevent concurrency issues (#364).
- Importing a nested type via
System.Reflection
now correctly imports the declaring type. This was especially a problem when convertingDynamicMethod
s to aDynamicMethodDefinition
. (#365) - Local variables are now properly resolved from
DynamicMethod
s initialized withDynamicILInfo
. - Reading and importing complex
COR_ELEMENT_TYPE_INTERNAL
types should be fixed. - Various CIL body parsing improvements, allowing for better recovery of invalid method body code / data (#361)
- Metadata stream selection is now properly reflecting the behavior of the runtime for both compressed and EnC metadata (#352)
- ExpandMacros correctly expands
ldarga.s
andbge.un.s
to their correct expanded forms (#322, thanks @N78750469) - Importing via Reflection of
MethodBase
s that use generic parameters of its declaring type in its signature should now be fixed. LPArrayMarshalDesriptor
now correctly respects signatures with anull
ArrayElementType (d9ef330).- Fix stack overflow when trying to compute a token of a full sized public key of an assembly reference (#381, #382)
- The
endfinally
opcode correctly clears the stack during stack analysis (eb41d58) - Sorted metadata tables are now stable sorts, ensuring order for metadata members such as custom attributes (#387)
5.0.0-beta.2
This quick hotfix addresses a few problems in 5.0.0-beta.1 with DynamicILInfo
initialized DynamicMethod
s. In particular:
- Local variables are now properly resolved from
DynamicMethod
s. - Reading and importing complex
COR_ELEMENT_TYPE_INTERNAL
types should be fixed - Importing via Reflection of
MethodBase
s that use generic parameters of its declaring type in its signature should now be fixed.
Note this is still a prerelease. Breaking changes can still happen until the final release. See the remainder of changelog of 5.0.0-beta.1
5.0.0-beta.1
This marks the first major version bump since the rewrite of AsmResolver. Note that, this is still a pre-release. last-minute breaking API changes may still happen before the full release.
New Features
- Read / Write support for PortablePDB metadata streams and tables (#348)
- A new WIP package called
AsmResolver.Symbols.Pdb
for reading and writing Windows PDB files using only managed code (#324, #326, #342) - Add
SignatureComparer::Default
(#366, thanks @ds5678) - Add
TypeDefinition::IsByRefLike
(#358, #362) - Add the notion of
IMemberClonerListener
s, allowing for automatically post-processing cloned metadata (e.g., automatically injecting it into the target module) as the cloner is cloning metadata (#333, #337, #354, thanks @CursedLand) - AsmResolver.DotNet is now trimmable (#304, thanks @ds5678)
- Add
DotNetRuntimeInfo::IsNetCoreApp
,IsNetFramework
andIsNetStandard
properties for easily identifying whether a module targets .NET Core, .NET Framework or .NET Standard (505da7a). - Add
MetadataTable::IsSorted
property (#348) DynamicMethodDefinition
now supports dynamic methods that are initialized viaDynamicILInfo
(b0b13c8)- Add convenience constructors for
BinaryStreamReader
that take abyte[]
or aIDataSource
alone (54c65ee). - Add
OriginalMetadataTokenProvider
(#361)
Breaking Changes
- Make
SignatureComparer
immutable (#366, thanks @ds5678) - Make
BlobReadContext
a struct (#356). - Change
ISegment::UpdateOffsets
's method signature (#236, #346) - Remove
ITlsDirectory::ImageBase
andCodeSegment::ImageBase
(#346) - Remove
SegmentReference::CanUpdateOffsets
andSegmentReference::UpdateOffsets
(#346) - Add setter for
TypeDefOrRefSignature::Type
andGenericInstanceTypeSignature::Type
(#338, thanks @JPaja) - Move
AsmResolver.DotNet.Dynamic
into a separate nuget package (#304). - Rename
Entrypoint
toEntryPoint
(b6fa3ed). - Rename
OptionalHeaderMagic::Pe32
andPe32Plus
toPE32
andPE32Plus
(d954be0). - Let
LazyVariable
lock on itself (16367c1) - Consolidate
ContinuousMetadataRange
andRedirectedMetadataRange
to a single structMetadataRange
(3bb6b6a) - Let
OneToManyRelation
return aValueSet
with a struct enumerator instead of a genericICollection
(07b09c3) - Change type of
MemberClonerContext::Importer
toCloneContextAwareReferenceImporter
.
Performance Improvements
- Precomputing capacity properties for lists containing read metadata reduced memory consumption by roughly 5%-10% (#316)
- Many small buffers and temporary memory streams are being reused during the writing process where possible. This reduces the number of allocations by up to 20% (#317).
- Various reader context types are now stack allocated (#356).
- Custom attribute signatures are now only read when absolutely necessary, preventing many unnecessary expensive type resolutions and thus many allocations (#336, #351).
MethodImplementation
now implementsIEquatable<MethodImplementation>
, drastically reducing allocations and increasing performance for large binaries with lots of interface implementations (d10cf47).- Replace PE section lookup LINQ code with expanded for loop, drastically reducing allocations in general (1ff0a0f)
OneToManyRelation
now returns aValueSet
with a struct enumerator instead of an interface (07b09c3)
Bug Fixes
- Modifications to a LazyList (and all its derivatives) are now guarded with locks to prevent concurrency issues (#364).
- Importing a nested type via
System.Reflection
now correctly imports the declaring type. This was especially a problem when convertingDynamicMethod
s to aDynamicMethodDefinition
. (#365) - Various CIL body parsing improvements, allowing for better recovery of invalid method body code / data (#361)
- Metadata stream selection is now properly reflecting the behavior of the runtime for both compressed and EnC metadata (#352)
- ExpandMacros correctly expands
ldarga.s
andbge.un.s
to their correct expanded forms (#322, thanks @N78750469)