This text is based on the reflection tip'n'trick from the incoming zine.net magazine (unfortunately entirely written in Polish), written by me and a friend of mine, Wojciech Gebczyk. I am permitted to publish his tool and anything else I need to :)
Generally if there's better solution, we should always choose not to reflect. Reflection is bad because it prevents type safety at compile time and because it's slow. Both reasons are based on the string based nature of the reflection. We use strings to provide the name of the type, method, etc. and CLR has to scan through an assembly's metadata to find the string we're asking for. But there are some cases, when reflection is very helpful. Everyone uses serialization, intellisense and designer helpers. All of them need information from the metadata to give us what we want.
There are also other uses of the reflection - which are not so obvious.
Reflection gives us access to lots of stuff, which isn't accessible in any other way. Thanks to the reflection we’ve got access to the private members.
TypeWrapper (included in the attachment to this post) is an example of a tool that uses reflection to give us access to private members. It simply wraps all the stuff from selected type and uses reflections to access them. But why should we use private members? Let’s imagine, that we have in our application a text box where user puts in his password. Of course, we use system’s password char to hide the actual content of the field, but we would like to give the user opportunity to see what’s in the box. There are many ways to accomplish this. For example we may send a ‘EM_SETPASSWORDCHAR’ message to the control with wParam set to 0. The only problem is, we have to P/Invoke Win32 SendMessage. But, wait a minute – there already is such a method imported in the System.Windows.Forms.Control class, and it’s private!
Using TypeWrapper lets us do it really fast:
1. Using TypeWrapper import System.Windows.Forms.dll, select the Control type and using context menu generate the wrapper (you may specify here the name of the namespace). Generated text put into the clipboard (use buttons).
2. Using VS2005 generate new project and add new class. Select the stub generated by VS and replace it with the contents from clipboard.
3. Now, in the code where you want to use the wrapped SendMessage method use the code below:
That’s all! Now we have the textbox with an unhidden input.
The funny thing here is, it's not so easy to protect our architecture from being abused. As Jeff Richter states in his great book “CLR via c#, second edition” (a frame on p. 577) we may use ReflectionPermission and strong name LinkDemand to restrict access to our private members, but when we work in a full-trust environment security checks are assumed to be successful :(. That’s why it’s really important to check if our code can successfully run in medium trust, which should be obligatory in shared hosting environments.
Thanks God, MS did some work to help admins in their job. In 1.1 ‘caspol –s off’ simply added the ‘HKLM\SOFTWARE\Microsoft\.NETFramework\Security\Policy\GlobalSettings’ with value of 0x0000001f and all checks against CAS on/off were done by querying the key. Of course, only admins, system and power users have full access to this key, but as from 2.0 it’s even harder. ‘caspol –s off’ firstly checks if we are admins and if so, creates a mutex named ‘Global\CLR_CASOFF_MUTEX’ and sets local admins as its owner (the code below comes from Reflector). Then CLR checks the existence of such an object and verifies if local admins are the owners.
To create a mutex we need a SecurityPermission we don’t have in medium trust, or at least (:) ) permission to do it via P/Invoke (which is blocked even in the High level because of the SecurityPermission.UnmanagedCode), so in the Medium Trust we are safe. This time we need an application which is running all the time to let the mutex live, so it looks pretty safer than before, when we had only registry key. I think such a restriction is very good for most of admins, who now need to rethink the design of the security if they based everything on the registry key. It’s also good for developers, who may produce secure software much easier. As from 2.0 we’ve got new tools, for example ‘permcalc’, which helps us specify security requirements for our app.
Very useful method which we can use to check current permission level is System.Security.SecurityManager.IsGranted(System.Security.IPermission perm), so we may find out if the user running our code has necessary permissions. So – if we are trying to protect our private methods we may use this method to check if the user has ReflectionPermission and if so – throw an exception ;). Of course this approach is very weak and don’t take it too serious.
At the end of the story I’d like to share with you my confusion about VS2K5 & disabling code access security. Simply execute ‘caspol –s off’, then run Visual Studio 2005 and try to load any of your c# projects. On my machine it ends up with:
‘Unable to read the project file 'Some.csproj'. Unverifiable code failed policy check. (Exception from HRESULT: 0x80131402)’
and the project stays unloaded. I consider this as a bug, because turning on CAS with the same VS session doesn’t change the situation. And vice versa – firing the VS and then disabling CAS has no impact on loading projects – VS works just fine. So – VS caches somehow at the init information about the CAS being on/off and doesn’t care about global changes.
12-12-2006 4:33 PM