Earlier today, JArnold wrote a blog entry that looked at an instance-based constructor hack that is similar (in an opposite kind of way) to my earlier post on class constructors.
Whilst JArnold's blog is 100% correct, there's an important distinction from a security perspective: what (s)he (sorry JArnold, I don't know who you are! :-) ) does is fail to initialise the parent class in a constructor. This is clearly against the rules of the CLR and will cause your code to be unverifiable. It will not run from a partially-trusted location such as an internet web site.
I'll omit the source and IL code for this post, but in the following example "noconstructor" is the base C# executable (100% "pure" code) and "noconstructorhack" is the hand-tweaked IL version that doesn't call the base class' constructor:
Microsoft (R) .NET Framework PE Verifier Version 1.1.4322.573
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
[IL]: Error: [c:\scripts\noconstructorhack.exe : D::.ctor] [offset 0x00000000] [opcode ret] Return from ctor when this is uninitialized.
1 Errors Verifying noconstructorHack.EXE
caspol -u -ag 1.1 -url c:\scripts\noconstructorHack.EXE Internet -n "NoConstructorTest" -exclusive on
Microsoft (R) .NET Framework CasPol 1.1.4322.573
Added union code group with "-url" membership condition to the User level.
Unhandled Exception: System.Security.VerificationException: Operation could destabilize the runtime.
Master of everything Raymond Chen has a comment that gives another example of how you can do it without tweaking IL, but again serialisation requires privileges that are not granted to code in the Internet zone:
caspol -u -ag 1.1 -url c:\scripts\serialise.EXE Internet -n "Serialise" -exclusive on
Unhandled Exception: System.Security.SecurityException: Request for the permission of type System.Security.Permissions.SecurityPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 failed.
at System.Security.CodeAccessSecurityEngine.CheckHelper(PermissionSet grantedSet, PermissionSet deniedSet, CodeAccess
Permission demand, PermissionToken permToken)
at System.Security.CodeAccessSecurityEngine.Check(PermissionToken permToken, CodeAccessPermission demand, StackCrawlMark& stackMark, Int32 checkFrames, Int32 unrestrictedOverride)
at System.Security.CodeAccessSecurityEngine.Check(CodeAccessPermission cap, StackCrawlMark& stackMark, PermissionType permType)
at System.Security.CodeAccessPermission.DemandInternal(PermissionType permissionType)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header inHeaders, __BinaryWriter serWriter, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header headers, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
The state of the failed permission was:
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
The attack I posted yesterday would succeed even in the Internet zone, assuming that a highly-trusted assembly had been produced by a compiler that generated public static constructors.