-
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
BadImageFormatException
on startup after adding a nested type to <Module>
in .NET 9
#111164
Comments
Tagging subscribers to this area: @mangod9 |
Likely introduced by #94825 |
- This isn't disallowed by spec, although ilasm and ildasm cannot handle these cases - Simply skip adding the type to the available class hash. Fix dotnet#111164
- This isn't disallowed by spec, although ilasm and ildasm cannot handle these cases - Simply skip adding the type to the available class hash. Backport of bugfix portion of PR dotnet#111435 Fixes dotnet#111164 in .NET 9
@4nonym0us the backport of this fix to .NET 9 was rejected with the following comment. #111479 (comment) If you have additional feedback to provide, please either re-open this issue or file a new one with evidence of the impact that not fixing this will have. |
@davidwrighton no problem. Even though I would like to have it backported to .NET 9, I tend to agree with the reviewer of the backport PR about this regression not having a widespread impact (the regression being spotted so late is a fine indicator of that). Personally, I can't even come up with any other use case of this other than assembly protection. There are not that many scenarios where code obfuscation makes sense and there are very few [decent] obfuscation tools as a result of that, which greatly narrows the scope of possibly affected projects. Furthermore, some other tools that I know of just inject their custom types into a different (not |
@4nonym0us Thanks for reporting this issue! You mention assembly protection tools. Would you mind sharing which ones already have a workaround for this issue? |
Description
Adding a nested type to the
<Module>
using dnlib/Cecil/AsmResolver used to be supported until .NET 9. Currently, [.NET 9] applications that have a nested type in the<Module>
, would just crash on startup due to unhandledBadImageFormatException
:Utilizing
<Module>
is not that uncommon when it's necessary to deprotect/unpack embedded resources or decrypt constants (or string literals) in runtime to make reverse-engineering of the assembly not as trivial as it is.This regression made some .NET obfuscators/protectors incompatible with .NET 9. This breaking change not being documented in the list of .NET 9 breaking changes (please, correct me if I'm wrong) makes it unclear whether the regression is a bug or merely a result of a well-thought design decision (which could be understandable granted that nested types in a global module must be very rare).
Reproduction Steps
dotnet publish -r win-x64 -f net9.0
to produce an assembly.<Module>
(alternatively, it's possible to manually add the nested type via dnSpy). Sample code for Mono.Cecil (dotnet add package Mono.Cecil --version 0.11.6
):where
asmPath
is a path to a .NET assembly that needs to be processed, obtained in a previous step.Note that this is not a Mono.Cecil bug, I have also tested all of the other libraries mentioned above and tried adding the nested type manually using dnSpy, the issue persisted.
Repeating the same steps when targeting .NET 8 (or earlier versions) or .NET Framework would produce a valid assembly, which wouldn't crash on startup.
I'm attaching final binaries for .NET 8 and .NET 9, which were created using the steps, described above.
BlankConsoleApp_NestedType_net8.zip ← working .NET 8 application with a NestedType in a
<Module>
.BlankConsoleApp_NestedType_net9.zip ← the same application, which targets .NET 9 and crashes on startup.
Expected behavior
Application shouldn't crash, enclosing type should be resolved (even if it's the
<Module>
class) as long as all of the necessaryTypeDef
andNestedClass
entries are present in the corresponding CLR metadata tables.On the other hand, if the breaking change was introduced by design, it should be documented on the Breaking changes in .NET 9 to prevent confusion.
Actual behavior
Following the reproduction steps above leads to .NET 9 assembly being corrupted, which is a regression from .NET 8.
Exception is thrown on startup:
Regression?
It is a regression, nested types in the
<Module>
are still supported on .NET Framework and has been supported on .NET Core until .NET 9 (.NET 8 is the latest version that works correctly).Known Workarounds
I guess not using nested types in the
<Module>
. It's still possible to create nested types, it's just that the enclosing type must not be<Module>
anymore.Configuration
SDK: .NET SDK 9.0.101
Runtime: win-x64
I'm quite confident that the issue is not platform-specific.
Other information
The IL of the
<Module>
with a nested struct is completely identical in .NET 8 and .NET 9:All of the CLR metadata tables are exactly the same, both assemblies (.NET 8 and .NET 9) have a
TypeDef
for aNestedType
,<Module>
andBlankConsoleApp.Program
, as well asNestedClass
definition forNestedType
having<Module>
as it's enclosing type.The exception is being thrown on clsload.cpp#3487:
runtime/src/coreclr/vm/clsload.cpp
Line 3487 in 6d250c7
The text was updated successfully, but these errors were encountered: