<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>.NET Security Blog : Under the Hood</title><link>http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx</link><description>Tags: Under the Hood</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>CAS and Native Code</title><link>http://blogs.msdn.com/shawnfa/archive/2008/03/04/cas-and-native-code.aspx</link><pubDate>Tue, 04 Mar 2008 21:27:41 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8031807</guid><dc:creator>shawnfa</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/8031807.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=8031807</wfw:commentRss><description>&lt;p&gt;CAS is complicated enough to understand when all of the moving parts are written in managed code (and therefore have all the associated managed meta-information like grant sets, etc).&amp;nbsp; However, once native code comes into play things can get even more confusing.&amp;nbsp; Let's take a look at how CAS works when there's native code on the call stack.&lt;/p&gt; &lt;p&gt;For this discussion, lets assume we have a call stack (growing down) like so:&lt;/p&gt; &lt;p&gt; &lt;div style="border-right: black thin inset; padding-right: 0.5em; border-top: black thin inset; padding-left: 0.5em; padding-bottom: 0.5em; margin: 0.5em; border-left: black thin inset; padding-top: 0.5em; border-bottom: black thin inset"&gt; &lt;div style="border-right: black thin inset; padding-right: 0.5em; border-top: black thin inset; padding-left: 0.5em; padding-bottom: 0.5em; margin: 0.5em; border-left: black thin inset; padding-top: 0.5em; border-bottom: black thin inset"&gt;Managed code: M1&lt;/div&gt; &lt;div style="border-right: black thin inset; padding-right: 0.5em; border-top: black thin inset; padding-left: 0.5em; padding-bottom: 0.5em; margin: 0.5em; border-left: black thin inset; padding-top: 0.5em; border-bottom: black thin inset"&gt;Managed code: M2&lt;/div&gt; &lt;div style="border-right: black thin inset; padding-right: 0.5em; border-top: black thin inset; padding-left: 0.5em; padding-bottom: 0.5em; margin: 0.5em; border-left: black thin inset; padding-top: 0.5em; border-bottom: black thin inset"&gt;Native code: N1&lt;/div&gt; &lt;div style="border-right: black thin inset; padding-right: 0.5em; border-top: black thin inset; padding-left: 0.5em; padding-bottom: 0.5em; margin: 0.5em; border-left: black thin inset; padding-top: 0.5em; border-bottom: black thin inset"&gt;Managed code: M3&lt;/div&gt; &lt;div style="border-right: black thin inset; padding-right: 0.5em; border-top: black thin inset; padding-left: 0.5em; padding-bottom: 0.5em; margin: 0.5em; border-left: black thin inset; padding-top: 0.5em; border-bottom: black thin inset"&gt;Managed code: M4&lt;/div&gt;AppDomain: AD&lt;/div&gt; &lt;p&gt;So in this example, M1 calls M2, which calls N1, which calls back to managed code M3 and M4.&amp;nbsp; All of the managed objects live in AppDomain AD.&lt;/p&gt; &lt;h2&gt;&lt;/h2&gt; &lt;h2&gt;Full Demands&lt;/h2&gt; &lt;p&gt;Now lets consider what happens when M4 triggers a full stack walk for a demand.&amp;nbsp; In this case, the CLR essentially ignores the native code on the stack, and does a stack walk looking at M3, M2, M1, and AD.&amp;nbsp; Intuitively, this is done because the native code doesn't have a grant set associated with it, and therefore including it on a CAS stack walk wouldn't make much sense.&lt;/p&gt; &lt;p&gt;It's important to note however that the stack walk proceeds &lt;em&gt;through&lt;/em&gt; N1, rather than stopping at it.&amp;nbsp; So in this case if M3 and M2 are fully trusted, but M1 is partial trust and M4 triggered a FullTrust demand, that demand would fail.&lt;/p&gt; &lt;p&gt;Stack walk modifiers like Assert continue to work just as you would expect as well, so it's perfectly legal for M2 to Assert FullTrust, which would make M4's demand succeed.&lt;/p&gt; &lt;h2&gt;&lt;/h2&gt; &lt;h2&gt;Link Demands&lt;/h2&gt; &lt;p&gt;Link demands are much more interesting when native code gets involved.&amp;nbsp; In our example, imagine that managed method M3 has a LinkDemand for FullTrust on it.&amp;nbsp; Normally, LinkDemands are evaluated at JIT time against the caller of the method with the demand.&amp;nbsp; But in this case, the caller of M3 is native code which is not JITed (and doesn't have a grant set to evaluate against in any event).&lt;/p&gt; &lt;p&gt;The obvious solution then is to evaluate the LinkDemand against the last managed frame on the call stack before we transitioned to native code.&amp;nbsp; At the time we're JITing this method however, we only know that it's calling a native method -- we don't know what managed code that native code is going to turn around and call later on.&amp;nbsp; In this example, when M2 is being JITed we know that it may call N1, however we don't know that N1 will turn around and call M3 and therefore don't know that M3 has as a LinkDemand to evaluate against M2.&lt;/p&gt; &lt;p&gt;However, it turns out that we don't need to know what M3 is going to LinkDemand of M2.&amp;nbsp; Since M2 is calling N1, it must have UnmanagedCode permission, and since UnmanagedCode permission is never handed out without FullTrust, we can reason that M2 must be fully trusted.&amp;nbsp; If M2 is fully trusted, then it will satisfy any LinkDemand that M3 will require.&lt;/p&gt; &lt;p&gt;With this analysis, we could say that LinkDemands are implicitly satisfied by native code callers.&amp;nbsp; However, that may not be the effect that we want in all cases.&amp;nbsp; For instance, one common scenario might be to expose a managed object via COM Interop to a script.&amp;nbsp; (For instance, make a managed object available via COM to some JavaScript in a web page).&lt;/p&gt; &lt;p&gt;From the CLR's perspective, this script is just native code, so our reasoning would lead to any link demands on methods the script calls being satisfied.&amp;nbsp; However, we may not want the script to satisfy all link demands.&amp;nbsp; In order to solve this problem, the CLR treats calls to managed code from native via COM Interop differently.&lt;/p&gt; &lt;p&gt;If native code uses a COM interface to call a managed method protected with a LinkDemand, then that LinkDemand is evaluated against the AppDomain which the managed object lives in.&lt;/p&gt; &lt;p&gt;Let's go back to our example again, and see how these rules apply.&amp;nbsp; Let's suppose that N1 calls M3 through COM Interop, M3 has a LinkDemand for FullTrust, and the AppDomain AD is also fully trusted.&amp;nbsp; In this case, the call succeeds because the AppDomain's grant set satisfies M3's LinkDemand.&lt;/p&gt; &lt;p&gt;Now let's consider the case where this AppDomain is hosted by Internet Explorer, and therefore has only the Internet grant set.&amp;nbsp; When N1 calls into M3, we'll see that the object M3 is being called on lives in AppDomain AD, and that causes us to look up the grant set of that domain.&amp;nbsp; We then check M3's LinkDemand for FullTrust against the AppDomain's grant set of Internet.&amp;nbsp; Since the AppDomain's grant set does not satisfy the LinkDemand, we throw a SecurityException.&amp;nbsp; Note that this is true even if the last managed frame on the stack (M2) is fully trusted.&lt;/p&gt; &lt;p&gt;If we make one more change to the scenario, and have N1 call M3 via reverse P/Invoke we a different result.&amp;nbsp; Even though the AppDomain is partially trusted, since M3 was not invoked from COM Interop, we allow the call to succeed.&lt;/p&gt; &lt;h2&gt;3 Rules for Native Code CAS Evaluation&lt;/h2&gt; &lt;p&gt;That's a ton of complexity, but thankfully we can boil it down to three rules depending upon your scenario:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;If a full demand is done, native stack frames are ignored and the stack walk proceeds exactly as if there were only managed frames on the stack.&lt;/li&gt; &lt;li&gt;If a link demand is done via COM Interop, the link demand is evaluated against the grant set of the AppDomain that the managed object lives in.&lt;/li&gt; &lt;li&gt;If a link demand is done via reverse P/Invoke, the link demand is satisfied and the call succeeds. &lt;/li&gt;&lt;/ol&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8031807" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/CAS/default.aspx">CAS</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>Combining Strong Names with Authenticode</title><link>http://blogs.msdn.com/shawnfa/archive/2007/01/10/combining-strong-names-with-authenticode.aspx</link><pubDate>Wed, 10 Jan 2007 21:32:39 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1445429</guid><dc:creator>shawnfa</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/1445429.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=1445429</wfw:commentRss><description>&lt;p&gt;If you want to use both a strong name and Authenticode signature on your assembly (for instance if you need a strong name for strong assembly identity, and your company has a rule requiring Authenticode signatures on all shipped products), then you need to make sure to do these in a specific order.&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Strong name the assembly&lt;/li&gt; &lt;li&gt;Authenticode sign the assembly&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;The reason for this is that since Authenticode signatures were invented before strong naming was a twinkle in someone's eye, they don't know anything about strong name signatures.&amp;nbsp; However, the CLR does know about both signature types, and can therefore make sure that signatures are applied in a manner that allows both to validate.&lt;/p&gt; &lt;p&gt;Why does the CLR have to do anything at all to allow both signatures to validate?&amp;nbsp; Imagine for a minute that no extra work is done in the dual-signature case, and that we just hash and sign the assembly.&amp;nbsp; When you strong name sign the hash is of the assembly with no signatures; however the Authenticode signature will be with the hash of the assembly containing the strong name signature.&amp;nbsp; During verification, the problem appears -- when verifying the strong name signature the hash of the assembly is different than the one calculated during signing, because the Authenticode signature is now part of the assembly.&amp;nbsp; If&amp;nbsp;we attempt to fix this by&amp;nbsp;resigning the assembly after Authenticode signature is applied&amp;nbsp;the reverse is now true -- the hash of the assembly with the original strong name signature (which is what the Authenticode signature contains) is now different from the hash with the new strong name signature.&lt;/p&gt; &lt;p&gt;In order to prevent this cycle, when the hash of an assembly is calculated the CLR actually zeros out the directory entry in the&amp;nbsp;optional headers&amp;nbsp;of the PE file for the Authenticode signature, and will skip over the section of the file containing the Authenticode signature itself.&amp;nbsp; This means that the hash used for the strong name signature does not include any Authenticode information at all.&amp;nbsp; Since you should always strong name sign first, this step actually does nothing during the signing stage because there will not be an Authenticode signature to skip.&amp;nbsp; However, during the verification process there will be an Authenticode signature present .&amp;nbsp; By zeroing out the directory entry and skipping the section of the PE image containing the Authenticode signature the hash will be the same as it was at signing time -- therefore allowing the strong name signature to verify.&lt;/p&gt; &lt;p&gt;Since Authenticode doesn't know anything about strong names, it does not treat the strong name signature in any sort of special way.&amp;nbsp; That's why it needs to be applied after the assembly is strong name signed, since it needs to&amp;nbsp;see the exact same bits during signing and verification.&amp;nbsp;&amp;nbsp;Note that this means that if you're delay or test key signing, you need to&amp;nbsp;apply the Authenticode signature after the final signature is calculated, not just after the assembly&amp;nbsp;is built.&lt;/p&gt; &lt;p&gt;Incidentally, the Authenticode signature is not the only section of the PE file that is not covered by the strong name signature.&amp;nbsp; We also skip the checksum field of the PE header and the strong name signature blob.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1445429" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/StrongName/default.aspx">StrongName</category></item><item><title>Special Permissions in the SSCLI</title><link>http://blogs.msdn.com/shawnfa/archive/2006/06/06/619126.aspx</link><pubDate>Tue, 06 Jun 2006 19:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:619126</guid><dc:creator>shawnfa</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/619126.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=619126</wfw:commentRss><description>&lt;P&gt;Before digging into a pretty clever optimization that the &lt;A HREF="/shawnfa/archive/2006/03/24/560034.aspx"&gt;SSCLI&lt;/A&gt; makes for certain special permission demands, I want to point out that everything I’m about to cover is an implementation detail. Although this optimization does occur today, we can and will change it for future versions of the CLR (and potentially service packs for the v2.0 version) … the only thing guaranteed about the behavior of a demand is that it throws a SecurityException if the call stack does not meet the required permissions; and does nothing if it does. &lt;/P&gt;
&lt;P&gt;With that being said, the v2.0 CLR has a few special permissions which it can apply a clever optimization to in order to speed up demands. If you’ve got the SSCLI v2 installed, you can see these permission defined in managed code in the PermissionType enumeration (clr\src\bcl\System\Security\CodeAccessSecurityEngine.cs) and mirrored in the VM (clr\src\VM\SecurityPolicy.h). (Look for the set of #defines starting at line 297 with SECURITY_UNMANAGED_CODE). &lt;/P&gt;
&lt;P&gt;There are two categories of these special permissions defined: &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV&gt;A flag of a permission (Assert, SkipVerification, UnmanagedCode, etc) &lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV&gt;An unrestricted permission (UI, Environment, Security, etc) &lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Each of these is given an integer value in SecurityPolicy.h which matches its value in the PermissionType enumeration. The CLR maps these values into flags by using the corresponding bit of a DWORD to indicate that this permission is the one being talked about. For instance, given: &lt;/P&gt;
&lt;DIV style="BORDER-RIGHT: black thin inset; PADDING-RIGHT: 1em; BORDER-TOP: black thin inset; PADDING-LEFT: 2em; FONT-SIZE: x-small; PADDING-BOTTOM: 1em; MARGIN: 1em 1em 1em 2em; BORDER-LEFT: black thin inset; PADDING-TOP: 1em; BORDER-BOTTOM: black thin inset; FONT-FAMILY: monospace; BACKGROUND-COLOR: lightgrey; WORD-WRAP: break-word"&gt;&lt;SPAN style="COLOR: blue"&gt;#define&lt;/SPAN&gt; UI_PERMISSION 9&lt;/DIV&gt;
&lt;P&gt;We use 1 &amp;lt;&amp;lt; UI_PERMISSION or 0x00000200 as a flag to indicate that we’re referencing unrestricted UI permission. In this way, we can simply logically or together as many of these permissions as is needed to talk about any given set of the special permissions. This does imply a limit of 32 special permissions however -- currently the CLR defines only 18, so there is plenty of room to grow there. One interesting thing to note is that although we do define SECURITY_FULL_TRUST to be bit 7, generally the VM uses 0xFFFFFFFF to refer to the FullTrust special permission bitmask. &lt;/P&gt;
&lt;P&gt;
&lt;H2&gt;Calculating Special Permission Flags &lt;/H2&gt;
&lt;P&gt;When an assembly or an AppDomain is loaded, policy is resolved to get the grant set. The entry point for this resolution is SecurityPolicy::ResolvePolicy (clr\src\VM\SecurityPolicy.cpp), which takes the parameters you would expect such as the evidence and assembly level declarative permission sets. It returns the grant set, and as an out parameter the denied permission set. As an extra out parameter, dwSpecialFlags, is the set of special permission flags which are calculated from the grant and deny set. &lt;/P&gt;
&lt;P&gt;The logic is to return a bitmask that represents everything that was in the grant set and not in the deny set. So if an assembly was being resolved in SecurityPolicy::ResolvePolicy, and its grant set included SkipVerification, UnmanagedCode and unrestricted UIPermission while its deny set included SkipVerification and unrestricted EnvironmentPermission, the output would be: &lt;/P&gt;
&lt;DIV style="BORDER-RIGHT: black thin inset; PADDING-RIGHT: 1em; BORDER-TOP: black thin inset; PADDING-LEFT: 2em; FONT-SIZE: x-small; PADDING-BOTTOM: 1em; MARGIN: 1em 1em 1em 2em; BORDER-LEFT: black thin inset; PADDING-TOP: 1em; BORDER-BOTTOM: black thin inset; FONT-FAMILY: monospace; BACKGROUND-COLOR: lightgrey; WORD-WRAP: break-word"&gt;((1 &amp;lt;&amp;lt; SECURITY_SKIP_VER) | (1 &amp;lt;&amp;lt; SECURITY_UNMANAGED_CODE) | (1 &amp;lt;&amp;lt; UI_PERMISSION) ) &amp;amp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;~( (1 &amp;lt;&amp;lt; SECURITY_SKIP_VER) | (1 &amp;lt;&amp;lt; ENVIRONMENT_PERMISSION) ) = &lt;BR&gt;(0x00000103) &amp;amp; !(0x00000402) = &lt;BR&gt;0x00000103 &amp;amp; 0xFFFFFBFD = &lt;BR&gt;0x00000101 = &lt;BR&gt;(1 &amp;lt;&amp;lt; UI_PERMISSION) | (1 &amp;lt;&amp;lt; SECURITY_UNMANAGED_CODE) &lt;BR&gt;&lt;/DIV&gt;
&lt;P&gt;Which is what we would expect when you take the set (SkipVerification, UnmanagedCode, UIPermission) and remove (SkipVerification, EnvironmentPermission). &lt;/P&gt;
&lt;P&gt;The actual work of resolving policy and calculating these flags is delegated by SecurityPolicy::ResolvePolicy to System.Security.SecurityManager.ResolvePolicy (clr\src\bcl\System\Security\SecurityManager.cs). After ResolvePolicy computes the grant and deny sets, it passes those to SecurityManager.GetSpecialFlags, whose job it is to do the mapping from the permission sets to any appropriate special permission flags. It does this by scanning for any flags on permissions which have their flags represented in the special permissions (currently just SecurityPermission and ReflectionPermission) and saving those flags away. It also does a scan for any permissions which have their unrestricted permissions set as a special flag, saving those as well. &lt;/P&gt;
&lt;P&gt;Once all the permissions which may map to a special flag are found, SecurityManager.MapToSpecialFlags is called to map the flags from SecurityPermission and ReflectionPermission back to an appropriate flag, while the GetSpecialFlags method itself adds bits for any of the other permissions which are unrestricted. &lt;/P&gt;
&lt;P&gt;I mentioned earlier that FullTrust is represented as 0xFFFFFFFF rather than 0x00000080, you can see that mapping in the very first line of SecurityManager.GetSpecialFlags. &lt;/P&gt;
&lt;P&gt;
&lt;H2&gt;Security Descriptors and Special Permissions &lt;/H2&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;The base SecurityDescriptor class (clr\src\VM\SecurityDescriptor.h) defines a protected member, the DWORD m_dwSpecialFlags, which holds the set of special permission flags that apply to the VM object the security descriptor refers to (such as an AppDomain or Assembly). In addition to this set of flags, the ApplicationSecurityDescriptor (clr\src\VM\SecurityDescriptorAppDomain.h) defines a second member to hold these flags -- m_dwDomainWideSpecialFlags. &lt;/P&gt;
&lt;P&gt;The m_dwSpecialFlags member is populated with the result from calling SecurityPolicy::ResolvePolicy on the object being loaded. The extra field in the ApplicationSecurityDescriptor however is kept up to date differently, and allows us to perform an optimization when a demand for one of these special permissions comes in. &lt;/P&gt;
&lt;P&gt;After the AppDomain has had its policy resolved, m_dwDomainWideSpecialFlags is initialized to match the special flags of the AppDomain. (This is done in ApplicationSecurityDescriptor::InitializePLS in clr\src\VM\SecurityDescriptorAppDomain.cpp). This means an AppDomain with no loaded assemblies has an m_dwDomainWideSpecialFlags indicating the special permission grant set of the domain itself. &lt;/P&gt;
&lt;P&gt;As each assembly is loaded into the AppDomain, the AssemblySecurityDescriptor’s m_dwSpecialFlags is initialized while policy is resolved on that assembly. (See AssemblySecurityDescriptor::ResolveWorker in clr\src\VM\SecurityDescriptorAssembly.cpp). The AppDomain then updates the m_dwDomainWideSpecialFlags field with the information from the AssemblySecurityDescriptor in ApplicationSecurityDescriptor::AddNewSecDescToPLS. The domain wide flags are updated by doing a bitwise and between the current domain wide flags and the flags of the assembly’s security descriptor. &lt;/P&gt;
&lt;P&gt;Following this logic along, the domain wide special flags start out as the set of special permissions granted to the AppDomain itself, and then are potentially reduced by each assembly loaded so that at any given point the domain wide special flags are always the set of special permissions which are granted to every assembly in the domain as well as the domain boundary. &lt;/P&gt;
&lt;P&gt;With that setup, if a demand for one of the special permissions is done in the AppDomain, we can check to see if the domain wide flag for that permission is set. If it is, then the CLR can cause the demand to succeed without ever having to do a stack walk, since it knows that for the special permission bit to be set everything in the AppDomain must be granted the given permission. The code which maps the permissions in a demand to a set of special flags is in SecurityStackWalk::GetPermissionSpecialFlags (clr\src\VM\SecurityStackWalk.cpp). &lt;/P&gt;
&lt;P&gt;Obviously this optimization does not work in the face of stack walk modifiers such as Deny or PermitOnly, which can cause the permission set of the call stack to become a subset of the permissions granted to the assemblies in the domain -- and if you look at the code in SecurityStackWalk::HasFlagsOrFullyTrustedIgnoreMode (clr\src\VM\security.inl) this is what the check for pThread-&amp;gt;GetOverridesCount() == 0 is doing. [But as Alton Brown might say, that’s another show.] This is just one more reason that &lt;A HREF="/shawnfa/archive/2006/02/02/523390.aspx"&gt;you really want to avoid using Deny and PermitOnly&lt;/A&gt; in your code if at all possible. &lt;/P&gt;
&lt;P&gt;Also note that this logic works for determining if a demand will pass, however it cannot be used to determine that a demand will fail. For instance, if an AppDomain has assemblies A, B, and C loaded into it, and the AppDomain, assembly A, and assembly B are all granted SkipVerification while assembly C is not, the SECURITY_SKIP_VER bit will be clear on the domain wide flags. However, if a skip verification demand is done while only A and B are on the call stack (or if C is on the stack, but either A or B has done an Assert preventing a stack walk from reaching C), then the demand will still succeed even though the bit is clear. &lt;/P&gt;
&lt;P&gt;The take away from this is not that you should try to only demand special permissions -- again, these were all implementation details subject to change at any point. You should always demand the most appropriate permission for the resource you’re trying to protect. More importantly, it’s interesting to see how the CLR can optimize the performance of some demands, and how operations like Deny and PermitOnly can ruin the optimizations.&lt;/P&gt;
&lt;DIV&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=619126" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/SSCLI/default.aspx">SSCLI</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>How does the CLR figure out Zone evidence?</title><link>http://blogs.msdn.com/shawnfa/archive/2006/05/12/596419.aspx</link><pubDate>Fri, 12 May 2006 23:14:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:596419</guid><dc:creator>shawnfa</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/596419.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=596419</wfw:commentRss><description>&lt;P&gt;This week, I've had three separate cases where people have wondered why the CLR was assigning seemingly incorrect zone evidence to their assembly, causing their permission sets to be less than what was expected.&lt;/P&gt;
&lt;P&gt;The quick and dirty answer is that the CLR doesn't in fact assign zones (with one small exception).&amp;nbsp; What we do is ask Windows for zone information.&lt;/P&gt;
&lt;P&gt;If we can look at the URL of the assembly and tell that it's from the local machine, then we'll take a short cut and assign it MyComputer zone evidence directly.&amp;nbsp; However, if it's not obvious to us that the URL does belong to the local machine, we'll call urlmon via &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/workshop/security/szone/reference/ifaces/iinternetsecuritymanager/mapurltozone.asp"&gt;IInternetSecurityManager::MapUrlToZone&lt;/A&gt; in order to assign a zone.&lt;/P&gt;
&lt;P&gt;It's relatively easy to slap together a quick&amp;nbsp;function that checks what zone urlmon is assigning a URL with this API:&lt;/P&gt;
&lt;P&gt;
&lt;DIV style="BORDER-RIGHT: black thin inset; PADDING-RIGHT: 1em; BORDER-TOP: black thin inset; PADDING-LEFT: 2em; FONT-SIZE: x-small; PADDING-BOTTOM: 1em; MARGIN: 1em 1em 1em 2em; BORDER-LEFT: black thin inset; PADDING-TOP: 1em; BORDER-BOTTOM: black thin inset; FONT-FAMILY: monospace; BACKGROUND-COLOR: lightgrey; WORD-WRAP: break-word"&gt;HRESULT&amp;nbsp;MapUrlToZone(&lt;SPAN style="COLOR: blue"&gt;const&lt;/SPAN&gt;&amp;nbsp;std::wstring&amp;nbsp;&amp;amp;wsZone,&amp;nbsp;DWORD&amp;nbsp;*pdwZone)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt;&amp;nbsp;(pdwZone&amp;nbsp;==&amp;nbsp;NULL)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;&amp;nbsp;E_POINTER;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IInternetSecurityManagerPtr&amp;nbsp;pSecurityManager;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HRESULT&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;CoInternetCreateSecurityManager(NULL,&amp;nbsp;&amp;amp;pSecurityManager,&amp;nbsp;0);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt;&amp;nbsp;(FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;&amp;nbsp;hr;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;pSecurityManager-&amp;gt;MapUrlToZone(wsZone.c_str(),&amp;nbsp;pdwZone,&amp;nbsp;0);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt;&amp;nbsp;(FAILED(hr))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;&amp;nbsp;hr;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt;&amp;nbsp;S_OK;&lt;BR&gt;}&lt;BR&gt;&lt;/DIV&gt;
&lt;P&gt;The DWORD can be translated to a name with the &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/workshop/security/szone/reference/ifaces/iinternetzonemanager/getzoneattributes.asp"&gt;GetZoneAttributes&lt;/A&gt; API, checking the szDisplayName field in the ZONEATTRIBUTES structure that you're returned.&amp;nbsp; For quick reference however, MyComputer is 0, LocalIntranet 1, TrustedSites 2 and Internet 3.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=596419" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/CAS/default.aspx">CAS</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>What Happens When You Fully Sign a Test Signed Assembly</title><link>http://blogs.msdn.com/shawnfa/archive/2006/04/03/567651.aspx</link><pubDate>Tue, 04 Apr 2006 00:44:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:567651</guid><dc:creator>shawnfa</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/567651.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=567651</wfw:commentRss><description>&lt;P&gt;When an assembly is &lt;A HREF="/shawnfa/archive/2005/10/24/484170.aspx"&gt;test signed&lt;/A&gt;, the public key used to verify its signature is different from the public key that makes up part of the assembly identity.&amp;nbsp; So what happens when you take an assembly which is registered as a test signed assembly on your machine and fully sign it?&lt;/P&gt;
&lt;P&gt;The key here (aren't puns fun) is the fully signed bit in the CLR header.&amp;nbsp; An assembly which is fully signed (so not simply named, test signed, or delay signed) has the COMIMAGE_FLAGS_STRONGNAMESIGNED bit set in the Flags field of the IMAGE_COR20_HEADER.&amp;nbsp; (Both can be found in corhdr.h in the Framework SDK)&lt;/P&gt;
&lt;P&gt;If the CLR is verifying a signature, and it sees this bit set, it won't even attempt to check the skip verification or test sign lists.&amp;nbsp; Instead, verification proceeds with the public key embedded in the assembly itself.&amp;nbsp; So the answer to the question is that a fully signed assembly with a entry on the test signed assembly list will work as expected, and verify with the correct public key.&lt;/P&gt;
&lt;P&gt;In the &lt;A HREF="/shawnfa/archive/2006/03/24/560034.aspx"&gt;SSCLI v2&lt;/A&gt;, you can see this behavior in the strong name code located at sscli20\clr\src\VM\strongname.cpp.&amp;nbsp; Specifically, go to the VerifySignature method -- the relevant code starts at line 2498.&amp;nbsp; On 2504 we check to see if the fully signed bit is in place, and if not we check for a test public key on 2506.&amp;nbsp; The magic behind test key signing&amp;nbsp; is essentially on one line of code, line 2514, where we substitute the test public key for the assembly's real public key.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=567651" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/SSCLI/default.aspx">SSCLI</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/StrongName/default.aspx">StrongName</category></item><item><title>LinkDemands and InheritenceDemands Occur at JIT Time</title><link>http://blogs.msdn.com/shawnfa/archive/2006/01/11/511716.aspx</link><pubDate>Wed, 11 Jan 2006 22:55:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:511716</guid><dc:creator>shawnfa</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/511716.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=511716</wfw:commentRss><description>&lt;P&gt;We previously saw that &lt;a href="http://blogs.msdn.com/shawnfa/archive/2005/03/10/393755.aspx"&gt;the SkipVerification demand for calling a method with unverifiable code occurs at JIT time&lt;/A&gt; rather than at runtime.&amp;nbsp; Two other types of demands also occur at JIT time, LinkDemands and InheritenceDemands.&amp;nbsp; An InheritenceDemand will occur when the method of the derived class is being JITed, while a LinkDemand occurs when the method which calls the method containing the LinkDemand is being JITed.&amp;nbsp; For instance, if method A calls method B, which has a LinkDemand for FullTrust, the demand occurs when A is JITed.&amp;nbsp; If method C overrides a method in class D which is protected with an InheritenceDemand, the demand occurs when C is JITed.&lt;/P&gt;
&lt;P&gt;This has some interesting consequences.&amp;nbsp; Since the basic unit of JIT compilation is the method, you cannot have a single method which checks the permission set its running with, and then conditionally calls a method protected by a LinkDemand if if would satisfy that demand.&amp;nbsp; Instead, it would have to check it's permissions and if it had enough call another method which simply turned around and called the method with the LinkDemand.&amp;nbsp; Similarly, you cannot do a try ... catch(SecurityException) around a method protected by a LinkDemand.&lt;/P&gt;
&lt;P&gt;I recently was asked a question about a program &lt;a href="http://blogs.msdn.com/shawnfa/archive/2003/06/20/57023.aspx"&gt;that stopped working when it was moved to a file share&lt;/A&gt;.&amp;nbsp; The author of the application attempted &lt;a href="http://blogs.msdn.com/shawnfa/archive/2004/12/02/274036.aspx"&gt;handle this gracefully&lt;/A&gt; by displaying an error message to his users indicating that they need to increase the trust of the application.&amp;nbsp; However, even that code didn't help -- it seemed as though the application's Main method never even got to execute.&lt;/P&gt;
&lt;P&gt;It turns out that Main created a Mutex object, and the &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemthreadingmutexclassctortopic3.asp"&gt;Mutex constructor contains a LinkDemand for UnmanagedCode&lt;/A&gt;.&amp;nbsp; Now that we know that this demand will occur at JIT time, the observed behavior seems understandable.&amp;nbsp; When the JIT attempted to compile Main, it found a call to a method that had a LinkDemand for UnmanagedCode, and so checked the permission set of the assembly containing Main.&amp;nbsp; It then found that this assembly did not have UnmanagedCode Permission, so it threw a SecurityException rather than compiling the method.&amp;nbsp; This prevented the author's attempt to fail gracefully from ever running, and the application died with an unhandled exception.&amp;nbsp; In fact, since this occurred while JITing Main, there actually wasn't even a call stack yet, so the exception message wasn't even particularly helpful in tracking down the problem.&lt;/P&gt;
&lt;P&gt;One way to fix this is to have Main first do the check for FullTrust, then call another method which does the work that used to occur in the original Main method.&amp;nbsp; This way, the application's entry point is allowed to JIT, and it can provide a useful diagnostic message to the users in the case that they need to provide extra trust for the code.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=511716" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>Exploring the ADMHost Sample</title><link>http://blogs.msdn.com/shawnfa/archive/2005/10/06/478009.aspx</link><pubDate>Fri, 07 Oct 2005 01:10:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:478009</guid><dc:creator>shawnfa</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/478009.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=478009</wfw:commentRss><description>&lt;P&gt;When I first talked about &lt;a href="http://blogs.msdn.com/shawnfa/archive/2004/11/12/256550.aspx"&gt;AppDomainManagers&lt;/A&gt;, I mentioned that there were three ways to set them up.&amp;nbsp; You can either setup an environment block, use some registry keys, or use the unmanaged hosting API.&amp;nbsp; In most of my samples so far I've &lt;a href="http://blogs.msdn.com/shawnfa/archive/2005/07/25/443038.aspx"&gt;used the environment variables&lt;/A&gt;, and in fact I &lt;a href="http://blogs.msdn.com/shawnfa/archive/2005/07/21/441588.aspx"&gt;discourage using the registry keys&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;That leaves the unmanaged hosting API as the only entry point for setting up an AppDomainManager that I have left to explore.&amp;nbsp; Since this involves a decent chunk of code, I've posted it as a downloadable MSDN sample, &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=C5A01892-E2CC-473B-A042-48ED43687470&amp;amp;displaylang=en"&gt;ADMHost&lt;/A&gt; rather than putting it in the blog directly.&lt;/P&gt;
&lt;P&gt;ADMHost exists as a basic template of an application that uses managed and unmanaged hosting -- by itself it's not very useful, in fact it just prints Hello World and exits.&amp;nbsp; However, it does demonstrate how to split your host into a managed and an unmanaged half using AppDomainManagers, and you can replace the "Hello World" logic with your own application specific logic&amp;nbsp;in just a couple of minutes.&lt;/P&gt;
&lt;H2&gt;&lt;A name=ADMHost&gt;A Whirlwind Tour of a CLR Host&lt;/a&gt;&lt;/H2&gt;
&lt;P&gt;Let's take a look at the code then.&amp;nbsp; It comes as a solution that will open in Visual Studio 2005 beta 2 or later, and a set of pre-built binaries.&amp;nbsp; (By default the output will not work on Win9x, however the project could be pretty easily tweaked to support those platforms if you need).&amp;nbsp; The solution consists of two projects, ADMHost which is the unmanaged entry point and the unmanaged half of the CLR host, and ManagedHost which is surprisingly enough the managed half of the host.&lt;/P&gt;
&lt;P&gt;The COM interfaces that the two halves of the host use to communicate over are defined in ManagedHost as the imaginatively named IManagedHost and IUnmanagedHost.&amp;nbsp; These interfaces are then exported to a type library with tlbexp, and imported into the native host with Visual C++'s #import directive.&lt;/P&gt;
&lt;P&gt;The entry point to the application is wmain in ADMHost\ADMHost.cpp.&amp;nbsp; The first thing that ADMHost does when it starts up is call CClrHost::BindToRuntime in order to load up the CLR.&amp;nbsp; BindToRuntime just uses ATL to create a CClrHost object (which implements IUnmanagedHost), and returns that.&amp;nbsp; As part of the construction process of CClrHost, we call &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/grfuncorbindtoruntimeex.asp"&gt;CorBindToRuntimeEx&lt;/A&gt; telling it to bind to the latest CLR&amp;nbsp;which can be hosted via the ICLRRuntimeHost interface.&amp;nbsp; In practice this means that you'll get Whidbey for now, but when later releases of the CLR come out, you'll get them instead.&amp;nbsp; v1.x of the CLR does not support ICLRRuntimeHost, so you won't ever bind to those versions.&lt;/P&gt;
&lt;P&gt;Now that the entry point has an IUnmanagedHostPtr, it calls Start() to fire up the runtime.&amp;nbsp; The Start call translates into a call to CClrHost::raw_Start which&amp;nbsp;begins by validating that we've bound to a runtime and that the runtime has not yet started.&amp;nbsp; It then asks the CLR to get it's IClrControl object which allows the host to tweak some knobs on the CLR.&amp;nbsp; Similarly, it offers the CClrHost instance to the CLR as an IHostControl, which the CLR uses when it needs to tell the host to do something.&lt;/P&gt;
&lt;P&gt;The first knob that we set on the CLR is the AppDomainManager by calling &lt;A href="http://msdn2.microsoft.com/ms164355"&gt;IClrControl::SetAppDomainManagerType&lt;/A&gt;, and passing in the name of the ManagedHost assembly and the AppDomainManager type.&amp;nbsp; These are hard coded as constants CClrHost::AppDomainManagerAssembly and CClrHost::AppDomainManagerType on lines&amp;nbsp;4 and 5 of ClrHost.cpp, so if you rename the ManagedHost class or namespace, or rename, reversion, or sign the ManagedHost.dll with a new public key, you'll need to update the constants here as well.&amp;nbsp; Once we've told the CLR what class implements our AppDomainManager, we can go ahead and tell it to startup by calling &lt;A href="http://msdn2.microsoft.com/ms164415(en-US,VS.80).aspx"&gt;ICLRRuntimeHost::Start&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;In the process of starting up the CLR, the default AppDomain is created.&amp;nbsp; Since we told the CLR that ADMHost.ManagedHost was our AppDomainManager, as soon as this domain is created an instance of ManagedHost (ManagedHost\ManagedHost.cs) is created and &lt;A href="http://msdn2.microsoft.com/77eb2e8x"&gt;InitializeNewDomain&lt;/A&gt; will be called.&amp;nbsp; ManagedHost simply sets its InitializationFlags to &lt;A href="http://winfx.msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/T_System_AppDomainManagerInitializationOptions.asp"&gt;AppDomainInitilizationOptions::RegisterWithHost&lt;/A&gt;.&amp;nbsp; When InitializeNewDomain completes, the CLR checks the RegisterWithHost flag.&amp;nbsp; Seeing that it has been set, the CLR calls &lt;A href="http://msdn2.microsoft.com/ms164473(en-US,VS.80).aspx"&gt;IHostControl::SetAppDomainManager&lt;/A&gt; passing in the AppDomain ID and a pointer to the AppDomainManager for that domain.&lt;/P&gt;
&lt;P&gt;The implementation of SetAppDomainManager that CClrHost provides (line 84 in ClrHost.cpp) first does a QueryInterface on the AppDomainManager, to convert it to an IManagedHost.&amp;nbsp; Once it has the pointer to the IManagedHost, it calls IManagedHost::SetUnmanagedHost passing in a pointer to itself.&amp;nbsp; The supplied AppDomainManager saves away this reference in the ManagedHost.unmanagedHost field, but doesn't actually use it.&amp;nbsp; In a more complex hosting scenario, the AppDomainManager might use this reference to ask the unmanaged host to perform some service for it.&lt;/P&gt;
&lt;P&gt;Note that we haven't returned from ICLRRuntimeHost::Start() yet.&amp;nbsp; At this point,&amp;nbsp;a&amp;nbsp;conceptual&amp;nbsp;callstack looks something like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;TABLE border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;wmain()&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;IUnmanagedHostPtr::Start()&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;(IUnmanagedHost) CClrHost::raw_Start()&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;ICLRRuntimeHost::Start()&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;I&gt;CLR Stack Frames&lt;/I&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;(IHostControl) CClrHost::SetAppDomainManager()&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;IManagedHost::raw_SetUnmanagedHost()&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;I&gt;CLR Stack Frames&lt;/I&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;ADMHost.ManagedHost.SetUnmanagedHost()&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;After registering the unmanaged host with the AppDomainManager, SetUnmanagedHost saves the AppDomainManager reference in a STL map, indexed by it's AppDomain ID.&amp;nbsp; When it does that, control flow will now wind back down the stack and back into the main routine.&lt;/P&gt;
&lt;P&gt;At this point, the main function calls RunApplication located in ADMHost\ADMHost.cpp on line 10, passing it a reference to the IUnmanagedHost.&amp;nbsp; If you wanted to customize this sample quickly, this method would be the only one you need to replace since it's where all application specific code would go.&lt;/P&gt;
&lt;P&gt;RunApplication access the AppDomainManager of the default domain by getting the DefaultManagedHost property of the IUnmanagedHost.&amp;nbsp; CClrHost::get_DefaultManagedHost simply calls IUnmanagedHost::GetManagedHost passing it an ID of 1, representing the default domain.&amp;nbsp; CClrHost::raw_GetUnmanagedHost then accesses the STL map to get the specified AppDomainManager.&lt;/P&gt;
&lt;P&gt;RunApplication tells the default managed host to create a second AppDomain, which is implemented in ManagedHost.cs as ManagedHost::CreateAppDomain.&amp;nbsp; As you would expect this call does nothing more than call &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemappdomainclasscreatedomaintopic.asp"&gt;AppDomain.CreateDomain&lt;/A&gt;, returning the new domain's ID.&amp;nbsp; When the domain is created, the CLR will call the new ManagedHost's InitializeNewDomain, which will again set the RegisterWithHost flag.&amp;nbsp; This will cause CClrHost::raw_SetAppDomainManager to be called, and the new AppDomain will be added to the map.&amp;nbsp; RunApplication then gets a reference to the new managed host, and calls Write having it echo "Hello World".&lt;/P&gt;
&lt;P&gt;When RunApplication finishes, wmain calls Stop on the IUnmanagedHost reference.&amp;nbsp; CClrHost::raw_Stop first iterates over each AppDomainManager in the STL map, calling Dispose on them.&amp;nbsp; Note that this Dispose method was defined in IManagedHost.&amp;nbsp; The CLR will not automatically dispose of an AppDomainManager even if it implements IDisposable.&amp;nbsp; After the Dispose method is called on the AppDomainManagers, CClrHost stops the CLR itself, and the program terminates.&lt;/P&gt;
&lt;H2&gt;&lt;A name=CustomizingADMHost&gt;Customizing ADMHost&lt;/a&gt;&lt;/H2&gt;
&lt;P&gt;If you wanted to use ADMHost as a starting point for your application, the first thing you would want to do would be replace the keypair in ManagedHost\ManagedHost.snk with one that you generated yourself.&amp;nbsp; (of course this means you'll also have to update the strong name of ManagedHost.dll on line 4 of ADMHost\ClrHost.cpp).&lt;/P&gt;
&lt;P&gt;Next you'll want to customize the services that your managed and unmanaged hosts provide to each other by updating the IManagedHost and IUnmanagedHost interfaces in ManagedHost\IManagedHost.cs and ManagedHost\IUnmanagedHost.cs.&amp;nbsp; For instance, you might want your managed host to expose a method that loads up an assembly containing the bulk of your application and starts it off.&amp;nbsp; You would then implement these services by implementing IManagedHost on the ManagedHost class and implementing IUnmanagedHost on the CClrHost class.&amp;nbsp; Notice that when Visual C++ #import's the IUnmanagedHost interface, it will mangle the names, so you'll be implementing methods named raw_Method() rather than just Method().&lt;/P&gt;
&lt;P&gt;Finally, you'll want to replace the RunApplication method in ADMHost\ADMHost.cpp to actually perform the work of your application.&lt;/P&gt;
&lt;H2&gt;Wrapping Up&lt;/H2&gt;
&lt;P&gt;Although the ADMHost sample application doesn't do very much on it's own, it can be used as a starting point for an application that wishes to host the CLR and use an AppDomainManager.&amp;nbsp; The application specific code is very isolated, and can easily be customized.&amp;nbsp; I'll also be using this sample to demonstrate some other features that require interaction between managed and unmanaged code in a hosting environment.&lt;/P&gt;&lt;/A&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=478009" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>A Closer Look at the Simple Sandboxed AppDomain</title><link>http://blogs.msdn.com/shawnfa/archive/2005/08/09/449563.aspx</link><pubDate>Tue, 09 Aug 2005 22:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:449563</guid><dc:creator>shawnfa</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/449563.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=449563</wfw:commentRss><description>&lt;P&gt;Yesterday we took a look at &lt;a href="http://blogs.msdn.com/shawnfa/archive/2005/08/08/449050.aspx"&gt;Whidbey's new Simple Sandboxing API&lt;/A&gt;.&amp;nbsp; At first glance this API does seem relatively simple, however when you start to look closer at the AppDomain that is created for your sandboxed code, there are a few surprising properties.&lt;/P&gt;
&lt;P&gt;You might expect that under the covers this API is doing the grunt work of creating an AppDomain policy level which grants AllCode the specified permission set, and then has a code group&amp;nbsp;for each strong name specified on the FullTrust list in order to provide those assemblies FullTrust.&amp;nbsp; However, this is not how the API works -- &lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"&gt;it actually uses an entirely different security model than the traditional policy level based one&lt;/SPAN&gt;.&amp;nbsp; In fact, there is no AppDomain policy level in the sandboxed domain at all!&amp;nbsp; Instead the sandboxed domain simply keeps track of a set of FullTrust assemblies and a permission set to be granted to all other assemblies and the AppDomain itself.&amp;nbsp; No policy resolution will be done for assemblies loaded into this type of domain.&lt;/P&gt;
&lt;P&gt;Why does Whidbey add this second AppDomain security model?&amp;nbsp; Aside from making it trivial for applications to sandbox untrusted code, it's also required for the ClickOnce security model.&amp;nbsp; ClickOnce allows an application to specify the exact set of permissions it should run under.&amp;nbsp; ClickOnce application authors test their applications with these permissions and expect to have exactly their requested permissions at runtime.&amp;nbsp; This AppDomain security model allows for that to occur.&lt;/P&gt;
&lt;P&gt;Similarly, Visual Studio's debug-in-zone feature also requires an environment where the permissions it requests are exactly the permissions it gets -- if it were to debug your application with fewer privileges, debug-in-zone could lead to a lot of confusion when operations that are expected to pass start throwing SecurityExceptions.&lt;/P&gt;
&lt;P&gt;Finally lets take a look at that evidence parameter to the CreateDomain API.&amp;nbsp; Since a sandboxed AppDomain does not resolve policy and always has a domain permission set equal to the grant set of the assemblies loaded into it, why does it need Evidence?&amp;nbsp; Technically the domain itself doesn't need that parameter, and it won't ever look at it directly.&amp;nbsp; However, the evidence is still stored on the AppDomain's Evidence property.&amp;nbsp; This means that other features which make decisions based upon AppDomain evidence (such as isolated storage), can still work with code executing in a simple sandboxed domain without modification.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=449563" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/ClickOnce/default.aspx">ClickOnce</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/CAS/default.aspx">CAS</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>Setting up an AppDomainManager</title><link>http://blogs.msdn.com/shawnfa/archive/2005/07/21/441588.aspx</link><pubDate>Fri, 22 Jul 2005 03:34:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:441588</guid><dc:creator>shawnfa</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/441588.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=441588</wfw:commentRss><description>&lt;P&gt;When I &lt;a href="http://blogs.msdn.com/shawnfa/archive/2004/11/12/256550.aspx"&gt;first talked about AppDomainManagers&lt;/A&gt;, I mentioned that there were three ways to tell the CLR that you'd like to use the managed hosting infrastructure:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;The unmanaged hosting API&lt;/LI&gt;
&lt;LI&gt;Environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE&lt;/LI&gt;
&lt;LI&gt;A set of registry keys&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Of these three, which one should you pick?&amp;nbsp; Obviously the unmanaged hosting API is only available to you if you're willing to have an unmanaged component of your application.&amp;nbsp; Of course if you do have an unmanaged component, and you want to have communication back and forth between the two halves, using this API and setting AppDomainManagerInitializationOptions.RegisterWithHost in your InitializeNewDomain method is a great way to get that setup.&lt;/P&gt;
&lt;P&gt;If you're sticking with a purely managed application, that leaves you with the other two options.&amp;nbsp; Given the choice between the two, you should almost always choose the environment variables over the registry keys.&lt;/P&gt;
&lt;P&gt;The problem with the registry keys is that there's only one set of them for every application running under your user profile.&amp;nbsp; This means that if your application chooses to set these keys it creates several different types of problems.&amp;nbsp; First, every managed application that starts after the keys are set will use the AppDomainManager (unless they specify their own using one of the other two methods).&amp;nbsp; Since those applications have not been tested running with your AppDomainManager, and AppDomainManagers are generally used to modify the behavior of the CLR,&amp;nbsp;this&amp;nbsp;will likely&amp;nbsp;lead to all kinds of unpredictable behavior which will be very difficult to trace back to the source.&lt;/P&gt;
&lt;P&gt;Even if your AppDomainManager is relatively inert and does not affect the other applications in any way, the fact that there is only one set of registry keys creates another problem.&amp;nbsp; If two applications decide that they're going to setup their AppDomainManager using these keys&amp;nbsp;during setup,&amp;nbsp;you have an obvious problem.&amp;nbsp;&amp;nbsp;However,&amp;nbsp;even if two applications provide a shim&amp;nbsp;program to set the keys and then kick off their real code,&amp;nbsp;you still have a race condition:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Application A sets the registry key for AppDomainManager A&lt;/LI&gt;
&lt;LI&gt;Application B sets the registry key for AppDomainManager B&lt;/LI&gt;
&lt;LI&gt;Application A starts with AppDomainManager B&lt;/LI&gt;
&lt;LI&gt;Application B starts with AppDomainManager B&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;The world is great for Application B, however Application A probably is not going to run very well at all since the AppDomainManager it was depending upon is not running in its process.&lt;/P&gt;
&lt;P&gt;On the other hand, environment variables are inherited from the parent process, and can be modified by each child. Since different processes can have separate environment blocks with the same environment variables having different values, you avoid all the race conditions above.&lt;/P&gt;
&lt;P&gt;Incidentally, one question that comes up relatively often is why didn't we enable an application to specify its AppDomainManager in the .exe.config file?&amp;nbsp; The reason is security -- every managed .exe can supply an .exe.config file.&amp;nbsp; Since AppDomainManagers are so powerful, we didn't want to expose the ability to specify one to untrusted code.&amp;nbsp; Instead, the only ways to set one up involve running managed code, having write access to the environment, or having write access to the registry.&amp;nbsp; Since these are all trusted operations, fencing off the AppDomainManager to only applications that can perform them reduces the surface area for attack on this feature.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=441588" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>Whidbey's Security Off Model</title><link>http://blogs.msdn.com/shawnfa/archive/2005/04/28/412998.aspx</link><pubDate>Thu, 28 Apr 2005 17:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:412998</guid><dc:creator>shawnfa</dc:creator><slash:comments>17</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/412998.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=412998</wfw:commentRss><description>&lt;P&gt;Although the v1.0 and v1.1 versions of CasPol provided a switch to disable the CLR's security system, running without CAS enforcement on was never a scenario that we encouraged for obvious reasons.&amp;nbsp; The choice to disable security was a system wide switch that affected any managed application on any version of the runtime, and made running managed code incredibly unsafe.&lt;/P&gt;
&lt;P&gt;As of Whidbey, you'll find that the switch to turn security off no longer works as it used to.&amp;nbsp; If you run caspol -s off with beta 2 or later of Whidbey installed, you'll see:&lt;/P&gt;
&lt;P&gt;
&lt;DIV&gt;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50215&amp;gt;CasPol.exe -s off&lt;BR&gt;Microsoft (R) .NET Framework CasPol 2.0.50215.44&lt;BR&gt;Copyright (C) Microsoft Corporation. All rights reserved.&lt;BR&gt;&lt;BR&gt;CAS enforcement is being turned off temporarily. Press &amp;lt;ENTER&amp;gt; when you want to&lt;BR&gt;restore the setting back on.&lt;BR&gt;&lt;/DIV&gt;
&lt;P&gt;Security will then be disabled as long as the CasPol process remains active.&amp;nbsp; When CasPol is terminated, it returns security to the on state.&amp;nbsp; Even abruptly terminating the CasPol process will still return security to its on state.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;This works because the implementation of the internal security off flag has changed.&amp;nbsp; Instead of using a registry key to indicate the status of CLR security, we now use a named mutex which CasPol holds to&amp;nbsp;indicate to the CLR that it should disable security.&amp;nbsp; Examining the the handles held by the&amp;nbsp;CasPol process&amp;nbsp;in a debugger will enable you to quickly identify this mutex: 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;
&lt;DIV&gt;0:000&amp;gt;!handle 0 4 Mutant&lt;BR&gt;Handle&amp;nbsp;4c&lt;BR&gt;&amp;nbsp;&amp;nbsp;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\BaseNamedObjects\CLR_CASOFF_MUTEX&lt;BR&gt;Handle&amp;nbsp;428&lt;BR&gt;&amp;nbsp;&amp;nbsp;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;none&amp;gt;&lt;BR&gt;Handle&amp;nbsp;4a8&lt;BR&gt;&amp;nbsp;&amp;nbsp;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\BaseNamedObjects\ShimCacheMutex&lt;BR&gt;Handle&amp;nbsp;624&lt;BR&gt;&amp;nbsp;&amp;nbsp;Name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;none&amp;gt;&lt;BR&gt;4 handles of type Mutant&lt;/DIV&gt;
&lt;P&gt;Since security is being disabled by this mutex, the CasPol process is resilient to being terminated unexpectedly, because Windows will just clean up the handle for CasPol when cleaning up the process.&amp;nbsp; Another side effect is that if the machine is rebooted, the security state will revert to on.&lt;/P&gt;
&lt;P&gt;If we fire up the kernel debugger, we can take a look at the ACL of the mutex:&lt;/P&gt;
&lt;P&gt;
&lt;DIV&gt;lkd&amp;gt;&amp;nbsp;!object&amp;nbsp;\BaseNamedObjects\CLR_CASOFF_MUTEX&lt;BR&gt;Object:&amp;nbsp;85088d88&amp;nbsp;&amp;nbsp;Type:&amp;nbsp;(8679f040)&amp;nbsp;Mutant&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ObjectHeader:&amp;nbsp;&lt;B&gt;85088d70&lt;/B&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HandleCount:&amp;nbsp;1&amp;nbsp;&amp;nbsp;PointerCount:&amp;nbsp;2&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Directory&amp;nbsp;Object:&amp;nbsp;e179f980&amp;nbsp;&amp;nbsp;Name:&amp;nbsp;CLR_CASOFF_MUTEX&lt;BR&gt;&lt;BR&gt;lkd&amp;gt;&amp;nbsp;dt&amp;nbsp;nt!_OBJECT_HEADER&amp;nbsp;85088d70&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x000&amp;nbsp;PointerCount&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;2&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x004&amp;nbsp;HandleCount&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;1&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x004&amp;nbsp;NextToFree&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x00000001&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x008&amp;nbsp;Type&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x8679f040&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x00c&amp;nbsp;NameInfoOffset&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x10&amp;nbsp;''&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x00d&amp;nbsp;HandleInfoOffset&amp;nbsp;:&amp;nbsp;0&amp;nbsp;''&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x00e&amp;nbsp;QuotaInfoOffset&amp;nbsp;&amp;nbsp;:&amp;nbsp;0&amp;nbsp;''&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x00f&amp;nbsp;Flags&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x20&amp;nbsp;'&amp;nbsp;'&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x010&amp;nbsp;ObjectCreateInfo&amp;nbsp;:&amp;nbsp;0x853e3678&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x010&amp;nbsp;QuotaBlockCharged&amp;nbsp;:&amp;nbsp;0x853e3678&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x014&amp;nbsp;SecurityDescriptor&amp;nbsp;:&amp;nbsp;&lt;B&gt;0xe2c57b2c&lt;/B&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;+0x018&amp;nbsp;Body&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;_QUAD&lt;BR&gt;&lt;BR&gt;lkd&amp;gt;&amp;nbsp;??&amp;nbsp;0xe2c57b2c&amp;nbsp;&amp;amp;&amp;nbsp;~0x7&lt;BR&gt;unsigned&amp;nbsp;int&amp;nbsp;0xe2c57b28&lt;BR&gt;&lt;BR&gt;lkd&amp;gt;&amp;nbsp;!sd&amp;nbsp;e2c57b28 1&lt;BR&gt;-&amp;gt;Revision:&amp;nbsp;0x1&lt;BR&gt;-&amp;gt;Sbz1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x0&lt;BR&gt;-&amp;gt;Control&amp;nbsp;:&amp;nbsp;0x8004&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SE_DACL_PRESENT&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SE_SELF_RELATIVE&lt;BR&gt;-&amp;gt;Owner&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;S-1-5-32-544&amp;nbsp;(Alias:&amp;nbsp;BUILTIN\Administrators)&lt;BR&gt;-&amp;gt;Group&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;S-1-5-21-2127521184-1604012920-1887927527-513&amp;nbsp;(Group:&amp;nbsp;REDMOND\Domain&amp;nbsp;Users)&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;AclRevision:&amp;nbsp;0x2&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Sbz1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x0&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;AclSize&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x34&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;AceCount&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x2&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Sbz2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0x0&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[0]:&amp;nbsp;-&amp;gt;AceType:&amp;nbsp;ACCESS_ALLOWED_ACE_TYPE&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[0]:&amp;nbsp;-&amp;gt;AceFlags:&amp;nbsp;0x0&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[0]:&amp;nbsp;-&amp;gt;AceSize:&amp;nbsp;0x18&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[0]:&amp;nbsp;-&amp;gt;Mask&amp;nbsp;:&amp;nbsp;0x001f0001&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[0]:&amp;nbsp;-&amp;gt;SID:&amp;nbsp;S-1-5-32-544&amp;nbsp;(Alias:&amp;nbsp;BUILTIN\Administrators)&lt;BR&gt;&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[1]:&amp;nbsp;-&amp;gt;AceType:&amp;nbsp;ACCESS_ALLOWED_ACE_TYPE&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[1]:&amp;nbsp;-&amp;gt;AceFlags:&amp;nbsp;0x0&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[1]:&amp;nbsp;-&amp;gt;AceSize:&amp;nbsp;0x14&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[1]:&amp;nbsp;-&amp;gt;Mask&amp;nbsp;:&amp;nbsp;0x001f0001&lt;BR&gt;-&amp;gt;Dacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;-&amp;gt;Ace[1]:&amp;nbsp;-&amp;gt;SID:&amp;nbsp;S-1-5-18&amp;nbsp;(Well&amp;nbsp;Known&amp;nbsp;Group:&amp;nbsp;NT&amp;nbsp;AUTHORITY\SYSTEM)&lt;BR&gt;&lt;BR&gt;-&amp;gt;Sacl&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;&amp;nbsp;is&amp;nbsp;NULL&lt;BR&gt;&lt;BR&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;That shows that the mutex is created with an ACL that prevents anyone who isn't an administrator from owning it.&amp;nbsp; And although Windows does not provide a way to prevent non-administrators from creating this mutex, internally the CLR will not respect the existence of the named mutex if it is abandoned or not owned by the BUILTIN\Administrators group.&amp;nbsp; This prevents a squatting attack where a malicious user could turn off security simply by creating this mutex himself.&lt;/P&gt;
&lt;P&gt;One of the more interesting&amp;nbsp;effects&amp;nbsp;to note&amp;nbsp;of disabling security with this mutex is that the v2.0 CLR will no longer respect the registry key used by older versions of the runtime, and those versions will not have their security disabled by the new CasPol switch.&lt;/P&gt;
&lt;P&gt;Although there still is the ability to turn off security, the ability to turn it off permanently has been removed.&amp;nbsp; The new switch is useful mostly for debugging purposes, to establish if a problem you're diagnosing is related to the security system or not.&amp;nbsp; The recommendation is still to avoid using this mechanism if at all possible.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=412998" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/CAS/default.aspx">CAS</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Debugging/default.aspx">Debugging</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Windows/default.aspx">Windows</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>Safely Impersonating Another User</title><link>http://blogs.msdn.com/shawnfa/archive/2005/03/22/400749.aspx</link><pubDate>Wed, 23 Mar 2005 02:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:400749</guid><dc:creator>shawnfa</dc:creator><slash:comments>17</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/400749.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=400749</wfw:commentRss><description>&lt;p&gt;&lt;A href="http://blogs.msdn.com/shawnfa/archive/2005/03/21/400088.aspx"&gt;Yesterday I posted a bit of code&lt;/a&gt; that shows how to impersonate another user in managed code.&amp;nbsp; However, that code had a subtle security hole waiting to bite you if you used it directly.&amp;nbsp; Both &lt;A href="http://blogs.msdn.com/shawnfa/archive/2005/03/21/400088.aspx#400117"&gt;Dean&lt;/a&gt; and &lt;A href="http://blogs.msdn.com/shawnfa/archive/2005/03/21/400088.aspx#400120"&gt;Eric&lt;/a&gt;&amp;nbsp;found the problem.&amp;nbsp; In fact Eric reminded me&amp;nbsp;of a &lt;A href="http://blogs.msdn.com/ericlippert/archive/2004/09/01/224064.aspx"&gt;blog entry&lt;/a&gt; he wrote on the same subject last fall.&lt;/p&gt; &lt;p&gt;The basic problem is that unlike most CLR security settings, impersonation is tied to the executing thread and not to the stack frame.&amp;nbsp; This means that if malicious code sees that your code is going to impersonate a privileged user, and then call into a method that it can cause to throw an exception, that malicious code can catch the exception and be running as the privileged user in its exception handler.&lt;/p&gt; &lt;p&gt;&lt;A href="http://blogs.msdn.com/shawnfa/archive/2005/03/21/400088.aspx#400153"&gt;Steve&lt;/a&gt; suggested wrapping the entire impersonate / Undo operation in a simple utility object that implements IDisposable.&amp;nbsp; That way you could use the C# using construct and have the Dispose method undo impersonation if the stack frame was popped of during an exception unwind.&amp;nbsp; At first brush this seems like a really good idea, however some deeper analysis shows that even this won't stop a determined malicious assembly.&lt;/p&gt; &lt;p&gt;How's that?&amp;nbsp; CLR exception handling takes place in two passes.&amp;nbsp; On the first pass, the CLR walks down the call stack checking for a frame willing to handle the exception.&amp;nbsp; In C# this means that the type specified in your catch block matches the type of the exception.&amp;nbsp; However, in VB or IL you can write an exception filter, which is a block of arbitrary code that executes to determine if the exception handler should run.&lt;/p&gt; &lt;p&gt;Once the stack frame containing the exception handler is identified, the CLR returns back to the top of the stack to begin its second pass of exception handling.&amp;nbsp; On this step, finally and fault blocks are executed and then the frame is popped until the handling frame is reached.&lt;/p&gt; &lt;p&gt;So if we put our Undo call in the finally block, it won't get called until the second pass of exception handling.&amp;nbsp; That means any malicious code that can execute on the first pass, by implementing an exception filter,&amp;nbsp;will still run in the impersonated context, regardless of the best intentions of our finally block.&lt;/p&gt; &lt;p&gt;What's the solution?&amp;nbsp; If you're coding in C#, the only way to be called on the first pass of exception handling is to actually catch the exception.&amp;nbsp; That means that there is unfortunately nothing much more elegant than:&lt;/p&gt; &lt;p&gt; &lt;div style="BORDER-RIGHT: black thin inset; PADDING-RIGHT: 1em; BORDER-TOP: black thin inset; PADDING-LEFT: 2em; FONT-SIZE: x-small; PADDING-BOTTOM: 1em; MARGIN: 1em 1em 1em 2em; BORDER-LEFT: black thin inset; PADDING-TOP: 1em; BORDER-BOTTOM: black thin inset; FONT-FAMILY: monospace; BACKGROUND-COLOR: lightgrey; WORD-WRAP: break-word"&gt;&lt;span style="COLOR: green"&gt;// Begin impersonating the user&lt;/span&gt;&lt;br /&gt;WindowsImpersonationContext&amp;nbsp;impersonationContext&amp;nbsp;=&amp;nbsp;WindowsIdentity.Impersonate(userHandle.Token);&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: blue"&gt;try&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DoSomeWorkWhileImpersonating();&lt;br /&gt;}&lt;br /&gt;&lt;span style="COLOR: blue"&gt;catch&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: green"&gt;// Clean up&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;(userHandle != IntPtr.Zero)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CloseHandle(userHandle);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;userHandle = IntPtr.Zero;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;(impersonationContext != &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;impersonationContext.Undo();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;impersonationContext = &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: green"&gt;// allow the exception to continue on its way&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;throw&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;span style="COLOR: blue"&gt;finally&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: green"&gt;// Clean up&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;(userHandle != IntPtr.Zero)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CloseHandle(userHandle);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;if&lt;/span&gt;(impersonationContext != &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;impersonationContext.Undo();&lt;br /&gt;}&lt;br /&gt;&lt;/div&gt; &lt;p&gt; &lt;p&gt;Notice that we use a plain catch, since ECMA allows for objects not derived from Exception to be thrown.&amp;nbsp; We also use a throw operation to cause the IL rethrow opcode to be emitted, which limits the amount of interfering we did with the exception handling process.&lt;/p&gt; &lt;p&gt;In VB you can be a little more slick and use an exception filter:&lt;/p&gt; &lt;p&gt; &lt;div style="BORDER-RIGHT: black thin inset; PADDING-RIGHT: 1em; BORDER-TOP: black thin inset; PADDING-LEFT: 2em; FONT-SIZE: x-small; PADDING-BOTTOM: 1em; MARGIN: 1em 1em 1em 2em; BORDER-LEFT: black thin inset; PADDING-TOP: 1em; BORDER-BOTTOM: black thin inset; FONT-FAMILY: monospace; BACKGROUND-COLOR: lightgrey; WORD-WRAP: break-word"&gt;&lt;span style="COLOR: green"&gt;' Begin impersonating the user&lt;/span&gt;&lt;br /&gt;WindowsImpersonationContext&amp;nbsp;impersonationContext&amp;nbsp;=&amp;nbsp;WindowsIdentity.Impersonate(userHandle.Token)&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: blue"&gt;Try&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DoSomeWorkWhileImpersonating()&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: blue"&gt;Catch When&lt;/span&gt; UndoImpersonation(userHandle, impersonationContext) = &lt;span style="COLOR: blue"&gt;False&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Debug.Assert(&lt;span style="COLOR: blue"&gt;False&lt;/span&gt;, "CleanUp returned False")&lt;br /&gt;&lt;span style="COLOR: blue"&gt;Finally&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UndoImpersonation(userHandle, impersonationContext)&lt;br /&gt;&lt;span style="COLOR: blue"&gt;End Try&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: green"&gt;' ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: blue"&gt;Private Function&lt;/span&gt; UndoImpersonation(&lt;span style="COLOR: blue"&gt;ByRef&lt;/span&gt; userHandle &lt;span style="COLOR: blue"&gt;As&lt;/span&gt; IntPtr, &lt;span style="COLOR: blue"&gt;ByRef&lt;/span&gt; impersonationContext &lt;span style="COLOR: blue"&gt;As&lt;/span&gt; WindowsImpersonationContext) &lt;span style="COLOR: blue"&gt;As Boolean&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;If Not&lt;/span&gt; IntPtr.Zero.Equals(userHandle) &lt;span style="COLOR: blue"&gt;Then&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CloseHandle(userHandle)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;userHandle = IntPtr.Zero&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;End If&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;If&lt;/span&gt; impersonationContext &amp;lt;&amp;gt; &lt;span style="COLOR: blue"&gt;Nothing Then&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;impersonationContext.Undo()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;impersonationContext = &lt;span style="COLOR: blue"&gt;Nothing&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;End If&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;Return True&lt;/span&gt;&lt;br /&gt;&lt;span style="COLOR: blue"&gt;End Function&lt;/span&gt;&lt;br /&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Here, we undo the impersonation in the exception filter, but never actually catch the exception, since the filter will never evalutate to True.&amp;nbsp; It's a nicer approach than the C# method, since by not catching the exception we make debugging a lot easier.&lt;/p&gt; &lt;p&gt;Both approaches are ugly, but in order to be safe you'll need to implement at least one.&amp;nbsp; The lesson here is that coding when you don't necessarily trust your callers is difficult.&amp;nbsp; Throw in the fact that exception safe coding is also difficult to do properly, and you've got yourself into a very tricky situation.&amp;nbsp; Tomorrow, we'll look at using some new Whidbey features to make the whole process a lot nicer and safer.&lt;/p&gt; &lt;p&gt;&lt;em&gt;Updated 3/23: Fixed double-free problem&lt;/em&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=400749" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Windows/default.aspx">Windows</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>When is ReflectionPermission Needed?</title><link>http://blogs.msdn.com/shawnfa/archive/2005/03/08/389768.aspx</link><pubDate>Tue, 08 Mar 2005 20:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:389768</guid><dc:creator>shawnfa</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/389768.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=389768</wfw:commentRss><description>&lt;p&gt;Reflection and its interaction with security can sometimes be a bit of a confusing matter.&amp;nbsp; The easiest portion to figure out is the permissions needed to use Reflection.Emit.&amp;nbsp; In order to do anything with the reflection emit feature, you'll need to have ReflectionPermission with the ReflectionEmit flag set.&amp;nbsp; In the default policy, you'll have this permission if you're running on LocalIntranet or MyComputer.&lt;/p&gt; &lt;p&gt;Things get a little more dicey when you start to figure out what permissions you need in order to use standard reflection.&amp;nbsp; The general rule of thumb is that if you could do something with early binding, then you won't need ReflectionPermission in order to use reflection to do the same thing with late binding.&amp;nbsp; So, you could easily create an XmlDocument and load a string into it with the Load method via reflection, even if you didn't have any ReflectionPermission.&amp;nbsp; This makes sense because demanding a permission here really doesn't buy any extra security, since you could have just done these operations directly in your code anyway.&lt;/p&gt; &lt;p&gt;Getting a&amp;nbsp;Type object for a type that is not visible to you, or getting an object to represent a member that is not visible has different behavior between v1.x and v2.0.&amp;nbsp; On v1.x, you'll need ReflectionPermission with the TypeInformation flag.&amp;nbsp; This means if you want to get a Type object for System.AssemblyHandle (which is a type in mscorlib marked as internal), you'll need this permission.&amp;nbsp; You'll also need this permission to get a MethodInfo object for System.Array::GetMedian() even though Array is public,&amp;nbsp;since GetMedian() is a private member.&amp;nbsp; The same holds true of getting a FieldInfo for System.Security.PermissionSet::m_Unrestricted, a private field.&amp;nbsp; Getting a PropertyInfo for the protected property System.Security.Cryptography.HashAlgorithm::HashSize would not require any permissions if you derived from HashAlgorithm, otherwise TypeInformation would be needed there as well.&amp;nbsp; One thing that's interesting to note about this is that if you do not have TypeInformation, and you try to perform one of these protected operations, you won't get a SecurityException.&amp;nbsp; Instead, reflection will just return a null object back to you.&amp;nbsp; In Whidbey the TypeInformation flag has been marked as obsolete, and any code can get at these objects.&lt;/p&gt; &lt;p&gt;The reason this is safe is that once you have the appropriate xxxInfo object, and you want to either invoke it or read its value, you'll need ReflectionPermission with the ReflectionPermissionFlag.MemberAccess flag set.&amp;nbsp; By default, both TypeInformation and MemberAccess are only granted to code running on the local machine.&amp;nbsp; &lt;p&gt;&lt;/p&gt;So, from the discussion above, it would seem that I could easily call System.Reflection.Assembly::GetExecutingAssembly() from partial trust code, since Assembly is a public class, and GetExecutingAssembly() is a public method on that class.&amp;nbsp; However, if I tried to do that, I would end up with a SecurityException. &lt;p&gt;&lt;/p&gt; &lt;p&gt;Why is that?&amp;nbsp; The answer lies deep within the CLR, inside the reflection internals.&amp;nbsp; If you look inside the SSCLI, you can find the code that's responsible for dispatching the late-bound call in COMMember::InvokeMethod_Internal (located in sscli\clr\src\vm\COMMember.cpp, line 1154).&amp;nbsp; Scanning down a bit through that method, there's an interesting comment on line 1231, where the reflection system calls an IsDangerousMethod() function to check to see if it needs to demand additional permissions.&amp;nbsp; If IsDangerousMethod() returns true, then an RM_ATTR_RISK_METHOD flag gets set, which causes COMCodeAccessSecurityEngine::SpecialDemand(REFLECTION_MEMBER_ACCESS) to be called on line 1278.&lt;/p&gt; &lt;p&gt;It seems pretty obvious that this might be our problem, so lets go check out IsDangerousMethod() to see what it considers to be dangerous.&amp;nbsp; This function starts at line 1007 of COMMember.cpp, and the meat of it is between lines 1073 and 1093.&amp;nbsp; Basically, we check the method table of the method in question, and compare it to a method table of several classes.&amp;nbsp; If the method belongs to one of these classes, we consider it dangerous and return true.&amp;nbsp; The&amp;nbsp;list of classes to compare against is initialized on lines 1031 to 1049.&amp;nbsp; The 19 special classes are:&lt;/p&gt; &lt;p&gt; &lt;table border="1"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;System.Activator&lt;/td&gt; &lt;td&gt;System.AppDomain&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.RuntimeType&lt;/td&gt; &lt;td&gt;System.Type&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.IO.IsolatedStorage.IsolatedStorageFile&lt;/td&gt; &lt;td&gt;System.Reflection.Assembly&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.Reflection.ConstructorInfo&lt;/td&gt; &lt;td&gt;System.Reflection.EventInfo&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.Reflection.FieldInfo&lt;/td&gt; &lt;td&gt;System.Reflection.MethodBase&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.Reflection.PropertyInfo&lt;/td&gt; &lt;td&gt;System.Reflection.RuntimeConstructorInfo&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.Reflection.RuntimeEventInfo&lt;/td&gt; &lt;td&gt;System.Reflection.RuntimeFieldInfo&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.Reflection.RuntimeMethodInfo&lt;/td&gt; &lt;td&gt;System.Reflection.RuntimePropertyInfo&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.Reflection.Emit.AssemblyBuilder&lt;/td&gt; &lt;td&gt;Sytem.Reflection.Emit.MethodRental&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.Resources.ResourceManager&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;This table is defined in terms of macros that look like CLASS__APPDOMAIN, which should all be relatively easy to figure out on their own.&amp;nbsp; However, if you'd like to find the source of this definition, you can check clr\src\vm\mscorlib.h, where all of these macros are created.&amp;nbsp; For instance, CLASS__APPDOMIAN is created on line 64 of this file:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DEFINE_CLASS(APP_DOMAIN, System, AppDomain)&lt;/p&gt; &lt;p&gt;If a class belongs to this table, then none of its methods or properties are available through late binding unless the calling code is granted MemberAccess.&amp;nbsp; That's why my partial trust code above couldn't call Assembly::GetExecutingAssembly().&lt;/p&gt; &lt;p&gt;In addition to the 19 classes listed above, Whidbey adds the following four classes to the dangerous list:&lt;/p&gt; &lt;p&gt; &lt;table border="1"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;System.RuntimeFieldHandle&lt;/td&gt; &lt;td&gt;System.RuntimeMethodHandle&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;System.RuntimeTypeHandle&lt;/td&gt; &lt;td&gt;System.Reflection.RuntimeFieldInfo&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt; &lt;p&gt;Another area where reflection and security come together is when the target code is protected with a LinkDemand.&amp;nbsp; The problem with using reflection to invoke a method that contains a LinkDemand is that the reflection code and not your code will ultimately be the method's caller.&amp;nbsp; This means that if the LinkDemand is for a set of CAS permissions (FullTrust for instance), it may be satisfied by the reflection code which lives in mscorlib, even though the demand may not have been satisfied by your code.&amp;nbsp; In order to prevent malicious code from circumventing LinkDemands through the use of reflection,&amp;nbsp;invoking a method&amp;nbsp;through reflection has the effect of turning LinkDemands into full demands.&amp;nbsp; If you don't want the whole stack checked, then you should &lt;A href="http://blogs.msdn.com/shawnfa/archive/2004/08/23/219155.aspx"&gt;Assert the permissions being demanded&lt;/a&gt; before calling the method with reflection, and then RevertAssert those permissions after the method returns.&amp;nbsp; By following that pattern, you can most closely simulate the effect of the LinkDemand.&lt;/p&gt; &lt;p&gt;For instance, if I'm calling System.Security.Cryptography.X509Certificates.X509Certificate::Handle, which has a LinkDemand on its getter for UnmanagedCode, I would use something like this:&lt;/p&gt; &lt;p&gt; &lt;div style="BORDER-RIGHT: black thin inset; PADDING-RIGHT: 1em; BORDER-TOP: black thin inset; PADDING-LEFT: 2em; FONT-SIZE: x-small; PADDING-BOTTOM: 1em; MARGIN: 1em 1em 1em 2em; BORDER-LEFT: black thin inset; PADDING-TOP: 1em; BORDER-BOTTOM: black thin inset; FONT-FAMILY: monospace; BACKGROUND-COLOR: lightgrey; WORD-WRAP: break-word"&gt;IntPtr&amp;nbsp;handleValue&amp;nbsp;=&amp;nbsp;IntPtr.Zero;&lt;br /&gt;&lt;span style="COLOR: blue"&gt;try&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="COLOR: blue"&gt;new&lt;/span&gt;&amp;nbsp;SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;handleValue&amp;nbsp;=&amp;nbsp;(IntPtr)handleProperty.GetValue(cert,&amp;nbsp;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;span style="COLOR: blue"&gt;finally&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CodeAccessPermission.RevertAssert();&lt;br /&gt;}&lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;To sum up, when working with reflection, if you keep the following rules in mind, you shouldn't run into any issues:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;If you're using Reflection.Emit, you need ReflectionPermissionFlag.Emit &lt;li&gt;If you're accessing code that you would be able to access anyway, you don't need any permission &lt;li&gt;If you're getting objects describing items you don't have access to, you need ReflectionPermissionFlag.TypeDiscovery &lt;li&gt;If you're invoking objects you don't have access to, you need ReflectionPermissionFlag.MemberAccess &lt;li&gt;There are some special classes unavailable without ReflectionPermissionFlag.MemberAccess &lt;li&gt;All LinkDemands will turn into full Demands&lt;/li&gt;&lt;/ol&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=389768" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/SSCLI/default.aspx">SSCLI</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/CAS/default.aspx">CAS</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item><item><title>The Difference Between the Strong Name Hash and Hash Evidence</title><link>http://blogs.msdn.com/shawnfa/archive/2005/02/28/382027.aspx</link><pubDate>Tue, 01 Mar 2005 01:12:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:382027</guid><dc:creator>shawnfa</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/382027.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=382027</wfw:commentRss><description>&lt;p&gt;The &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemsecuritypolicyhashclasstopic.asp"&gt;System.Security.Policy.Hash&lt;/a&gt; class allows you to make security decisions based upon the hash of an assembly using the &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemsecuritypolicyhashmembershipconditionclasstopic.asp"&gt;HashMembershipCondition&lt;/a&gt;.&amp;nbsp;&amp;nbsp;That sounds awfully similar to how strong names are calculated ...&amp;nbsp;According to&amp;nbsp;&lt;a href="http://msdn.microsoft.com/net/ecma/"&gt;ECMA partition II section 6.2.1.3&lt;/a&gt;, a strong name is computed by using RSA to encrypt the SHA1 hash of the assembly.&amp;nbsp; Taking those two statements together, one logical jump to make would be that we could take an assembly's private key and use it to sign the value of the &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemsecuritypolicyhashclasssha1topic.asp"&gt;Hash.SHA1 property&lt;/a&gt;, creating the assembly's signature ourselves.&lt;/p&gt; &lt;p&gt;However, that wouldn't work as expected.&amp;nbsp; The value generated by Hash.SHA1 is a hash over every bit that makes up the assembly, whereas the hash used to create the strong name signature actually skips over portions of the assembly's PE image.&amp;nbsp; We can see this from looking&amp;nbsp;up the strong name signature algorithm in&amp;nbsp;the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=3A1C93FA-7462-47D0-8E56-8DD34C6292F0&amp;amp;displaylang=en"&gt;SSCLI source&lt;/a&gt;&amp;nbsp;--&amp;nbsp;the function in question is named ComputeHash(); it begins on line 1964 of sscli\clr\src\dlls\mscorsn\strongname.cpp.&lt;/p&gt; &lt;p&gt;Following&amp;nbsp;ComputeHash() along,&amp;nbsp;after adding the the DOS header to the hash on lines 1978-1979, we move on to the NT headers.&amp;nbsp; Here&amp;nbsp;we encounter the first section of the assembly that gets skipped.&amp;nbsp; In the OptionalHeaders, we zero out the checksum as well as the security data directory, which is used for Authenticode signing, before adding their values into the hash.&lt;/p&gt; &lt;p&gt;The reason for this is that we want the Authenticode signature to envelope the strong name signature instead of the other way around.&amp;nbsp; If we left these entries in place, providing an Authenticode signature for the assembly would change these values, invalidating our hash and thus the strong name signature.&lt;/p&gt; &lt;p&gt;Once the headers are hashed, lines 2004-2028 are responsible for computing the hash of the sections within the PE file.&amp;nbsp; Again, you'll notice that we don't hash every byte here --&amp;nbsp;before adding&amp;nbsp;a section to the hash, we need to check to see if the strong name blob falls within that section.&amp;nbsp; If not we can hash the entire section, however if it does, we hash everything but the blob itself ... effectively removing it from&amp;nbsp;our view of&amp;nbsp;the assembly.&amp;nbsp; This step is obviously necessary, since once the signature is computed, writing it into the assembly will change the contents of that blob, and if it was part of the hash would immediately render the signature invalid.&lt;/p&gt; &lt;p&gt;Hash.SHA1 doesn't have any of these restrictions&amp;nbsp;since the primary reason to use&amp;nbsp;this class is to&amp;nbsp;enable the HashMembershipCondition in policy.&amp;nbsp; At policy evaluation time, the assembly has already been signed with a strong name key and certificate (if it was going to be signed at all), so we don't need to skip&amp;nbsp;the&amp;nbsp;Authenticode directory entry.&amp;nbsp;&amp;nbsp;Additionally, since the value computed by&amp;nbsp;Hash is never written back to the assembly, we don't have to worry about skipping any space for it to be written to.&lt;/p&gt; &lt;p&gt;In summary, Hash.SHA1 is a hash over&amp;nbsp;every byte in the assembly, whereas the SHA1 hash used in the signing process:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Hashes the DOS headers if they exist&lt;/li&gt; &lt;li&gt;Hashes the NT headers, after&amp;nbsp;zeroing out&amp;nbsp;the checksum and Authenticode directory entry&lt;/li&gt; &lt;li&gt;Hashes each section of the PE file, skipping over the location where the signature will eventually be stored&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=382027" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Cryptography/default.aspx">Cryptography</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/CAS/default.aspx">CAS</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/StrongName/default.aspx">StrongName</category></item><item><title>Finding the Raw Strong Name Signature</title><link>http://blogs.msdn.com/shawnfa/archive/2005/01/26/361109.aspx</link><pubDate>Wed, 26 Jan 2005 23:11:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:361109</guid><dc:creator>shawnfa</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/361109.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=361109</wfw:commentRss><description>&lt;p&gt;Wow ... there's been lots of interest in signatures lately :-)&amp;nbsp; In response to my last post about reserving a larger section of the PE file for the signature when you create a signature with a larger key, &lt;A href="http://blogs.msdn.com/shawnfa/archive/2005/01/21/358528.aspx#360470"&gt;William wants to know&lt;/a&gt; if you can extract the actual signature bytes from the PE file.&lt;/p&gt; &lt;p&gt;Absolutely you can, it's even relatively easy to do.&amp;nbsp; Boiled down, the raw strong name signature is simply the array of bytes that are located at the RVA specified by the StrongNameSignature.VirtualAddress field of the CLR header.&amp;nbsp; The signature length is specified by the StrongNameSignature.Size&amp;nbsp;field of the header.&amp;nbsp; So once you have the CLR header of a PE file, its very easy to find the signature itself.&lt;/p&gt; &lt;p&gt;In the spirit of picking the right tool for the job, I'll show how to do this in C++ code, since creating &lt;a title="" href="http://www.pinvoke.net/"&gt;P/Invoke&lt;/a&gt; declarations for the various structures needed would take up a large chunk of time.&amp;nbsp; The code for a method that takes a memory mapped PE file and displays its raw signature would look something like this:&lt;/p&gt; &lt;p&gt; &lt;div style="BORDER-RIGHT: black thin inset; PADDING-RIGHT: 1em; BORDER-TOP: black thin inset; PADDING-LEFT: 2em; FONT-SIZE: x-small; PADDING-BOTTOM: 1em; MARGIN: 1em 1em 1em 2em; BORDER-LEFT: black thin inset; PADDING-TOP: 1em; BORDER-BOTTOM: black thin inset; FONT-FAMILY: monospace; BACKGROUND-COLOR: lightgrey; WORD-WRAP: break-word"&gt;&lt;font color="#804040"&gt;1&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;/// &amp;lt;summary&amp;gt;&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;2&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;///&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Display the raw strong name signature of a memory mapped assembly&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;3&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;/// &amp;lt;/summary&amp;gt;&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;4&lt;/font&gt;&amp;nbsp;&amp;nbsp;HRESULT DisplaySignature(BYTE *pbFile)&lt;br /&gt;&lt;font color="#804040"&gt;5&lt;/font&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;font color="#804040"&gt;6&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_ASSERTE(pbFile != &lt;span&gt;&lt;font color="#000080"&gt;NULL&lt;/font&gt;&lt;/span&gt;);&lt;br /&gt;&lt;font color="#804040"&gt;7&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_ASSERTE(&lt;span&gt;&lt;font color="#000080"&gt;0&lt;/font&gt;&lt;/span&gt; &amp;lt; cbFile);&lt;br /&gt;&lt;font color="#804040"&gt;8&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;9&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PIMAGE_NT_HEADERS pNtHeader = ImageNtHeader(pbFile);&lt;br /&gt;&lt;font color="#804040"&gt;10&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt;(&lt;span&gt;&lt;font color="#000080"&gt;NULL&lt;/font&gt;&lt;/span&gt; == pNtHeader)&lt;br /&gt;&lt;font color="#804040"&gt;11&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;font color="#804040"&gt;12&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; &lt;span&gt;&lt;font color="#000080"&gt;"Error: Could not get NT headers for file"&lt;/font&gt;&lt;/span&gt; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;font color="#804040"&gt;13&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; E_INVALIDARG;&lt;br /&gt;&lt;font color="#804040"&gt;14&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;font color="#804040"&gt;15&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;16&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;// find the data directories in the file&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;17&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PIMAGE_DATA_DIRECTORY pDataDirectories = &lt;span&gt;&lt;font color="#000080"&gt;NULL&lt;/font&gt;&lt;/span&gt;;&lt;br /&gt;&lt;font color="#804040"&gt;18&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;switch&lt;/font&gt;&lt;/span&gt;(pNtHeader-&amp;gt;OptionalHeader.Magic)&lt;br /&gt;&lt;font color="#804040"&gt;19&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;font color="#804040"&gt;20&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;case&lt;/font&gt;&lt;/span&gt; IMAGE_NT_OPTIONAL_HDR32_MAGIC:&lt;br /&gt;&lt;font color="#804040"&gt;21&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pDataDirectories = &lt;span&gt;&lt;font color="#0000ff"&gt;reinterpret_cast&lt;/font&gt;&lt;/span&gt;&amp;lt;PIMAGE_NT_HEADERS32&amp;gt;(pNtHeader)-&amp;gt;OptionalHeader.DataDirectory;&lt;br /&gt;&lt;font color="#804040"&gt;22&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;break&lt;/font&gt;&lt;/span&gt;;&lt;br /&gt;&lt;font color="#804040"&gt;23&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;24&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;case&lt;/font&gt;&lt;/span&gt; IMAGE_NT_OPTIONAL_HDR64_MAGIC:&lt;br /&gt;&lt;font color="#804040"&gt;25&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pDataDirectories = &lt;span&gt;&lt;font color="#0000ff"&gt;reinterpret_cast&lt;/font&gt;&lt;/span&gt;&amp;lt;PIMAGE_NT_HEADERS64&amp;gt;(pNtHeader)-&amp;gt;OptionalHeader.DataDirectory;&lt;br /&gt;&lt;font color="#804040"&gt;26&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;break&lt;/font&gt;&lt;/span&gt;;&lt;br /&gt;&lt;font color="#804040"&gt;27&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;28&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;default&lt;/font&gt;&lt;/span&gt;:&lt;br /&gt;&lt;font color="#804040"&gt;29&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; E_NOTIMPL;&lt;br /&gt;&lt;font color="#804040"&gt;30&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;font color="#804040"&gt;31&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;32&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;// Make sure there is a CLR header&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;33&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_ASSERTE(pDataDirectories != &lt;span&gt;&lt;font color="#000080"&gt;NULL&lt;/font&gt;&lt;/span&gt;);&lt;br /&gt;&lt;font color="#804040"&gt;34&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt;(&lt;span&gt;&lt;font color="#000080"&gt;0&lt;/font&gt;&lt;/span&gt; == pDataDirectories[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||&lt;br /&gt;&lt;font color="#804040"&gt;35&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span&gt;&lt;font color="#000080"&gt;0&lt;/font&gt;&lt;/span&gt; == pDataDirectories[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)&lt;br /&gt;&lt;font color="#804040"&gt;36&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;font color="#804040"&gt;37&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; &lt;span&gt;&lt;font color="#000080"&gt;"Error: No CLR header"&lt;/font&gt;&lt;/span&gt; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;font color="#804040"&gt;38&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; E_INVALIDARG;&lt;br /&gt;&lt;font color="#804040"&gt;39&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;font color="#804040"&gt;40&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;41&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;// get the CLR header&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;42&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PIMAGE_COR20_HEADER pCorHeader = &lt;span&gt;&lt;font color="#0000ff"&gt;reinterpret_cast&lt;/font&gt;&lt;/span&gt;&amp;lt;PIMAGE_COR20_HEADER&amp;gt;(&lt;br /&gt;&lt;font color="#804040"&gt;43&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ImageRvaToVa(&lt;br /&gt;&lt;font color="#804040"&gt;44&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pNtHeader,&lt;br /&gt;&lt;font color="#804040"&gt;45&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pbFile,&lt;br /&gt;&lt;font color="#804040"&gt;46&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pDataDirectories[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress,&lt;br /&gt;&lt;font color="#804040"&gt;47&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#000080"&gt;NULL&lt;/font&gt;&lt;/span&gt;));&lt;br /&gt;&lt;font color="#804040"&gt;48&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt;(&lt;span&gt;&lt;font color="#000080"&gt;NULL&lt;/font&gt;&lt;/span&gt; == pCorHeader)&lt;br /&gt;&lt;font color="#804040"&gt;49&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;font color="#804040"&gt;50&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; &lt;span&gt;&lt;font color="#000080"&gt;"Error: Could not get CLR header"&lt;/font&gt;&lt;/span&gt; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;font color="#804040"&gt;51&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; E_INVALIDARG;&lt;br /&gt;&lt;font color="#804040"&gt;52&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;font color="#804040"&gt;53&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;54&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;// check to see if there is a signature&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;55&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt;( &lt;span&gt;&lt;font color="#000080"&gt;0&lt;/font&gt;&lt;/span&gt; == pCorHeader-&amp;gt;StrongNameSignature.VirtualAddress || &lt;br /&gt;&lt;font color="#804040"&gt;56&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#000080"&gt;0&lt;/font&gt;&lt;/span&gt; == pCorHeader-&amp;gt;StrongNameSignature.Size)&lt;br /&gt;&lt;font color="#804040"&gt;57&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;font color="#804040"&gt;58&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; &lt;span&gt;&lt;font color="#000080"&gt;"Error: Image is not signed"&lt;/font&gt;&lt;/span&gt; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;font color="#804040"&gt;59&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; S_FALSE;&lt;br /&gt;&lt;font color="#804040"&gt;60&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;font color="#804040"&gt;61&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;62&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;// pull the signature from the header&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;63&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BYTE *pbSignature = &lt;span&gt;&lt;font color="#0000ff"&gt;reinterpret_cast&lt;/font&gt;&lt;/span&gt;&amp;lt;BYTE *&amp;gt;(&lt;br /&gt;&lt;font color="#804040"&gt;64&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ImageRvaToVa(&lt;br /&gt;&lt;font color="#804040"&gt;65&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pNtHeader,&lt;br /&gt;&lt;font color="#804040"&gt;66&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pbFile,&lt;br /&gt;&lt;font color="#804040"&gt;67&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pCorHeader-&amp;gt;StrongNameSignature.VirtualAddress,&lt;br /&gt;&lt;font color="#804040"&gt;68&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#000080"&gt;NULL&lt;/font&gt;&lt;/span&gt;));&lt;br /&gt;&lt;font color="#804040"&gt;69&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt;(&lt;span&gt;&lt;font color="#000080"&gt;NULL&lt;/font&gt;&lt;/span&gt; == pbSignature)&lt;br /&gt;&lt;font color="#804040"&gt;70&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;font color="#804040"&gt;71&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; &lt;span&gt;&lt;font color="#000080"&gt;"Error: Could not find signature directory"&lt;/font&gt;&lt;/span&gt; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;font color="#804040"&gt;72&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; E_INVALIDARG;&lt;br /&gt;&lt;font color="#804040"&gt;73&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;font color="#804040"&gt;74&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;75&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#008000"&gt;&lt;i&gt;// display it&lt;/i&gt;&lt;/font&gt;&lt;/span&gt;&lt;br /&gt;&lt;font color="#804040"&gt;76&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; &lt;span&gt;&lt;font color="#000080"&gt;"Strong name signature ("&lt;/font&gt;&lt;/span&gt; &amp;lt;&amp;lt; pCorHeader-&amp;gt;StrongNameSignature.Size &amp;lt;&amp;lt; &lt;span&gt;&lt;font color="#000080"&gt;" bytes):"&lt;/font&gt;&lt;/span&gt;;&lt;br /&gt;&lt;font color="#804040"&gt;77&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; std::hex;&lt;br /&gt;&lt;font color="#804040"&gt;78&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;for&lt;/font&gt;&lt;/span&gt;(DWORD i = &lt;span&gt;&lt;font color="#000080"&gt;0&lt;/font&gt;&lt;/span&gt;; i &amp;lt; pCorHeader-&amp;gt;StrongNameSignature.Size; i++)&lt;br /&gt;&lt;font color="#804040"&gt;79&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;font color="#804040"&gt;80&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt;(i % &lt;span&gt;&lt;font color="#000080"&gt;16&lt;/font&gt;&lt;/span&gt; == &lt;span&gt;&lt;font color="#000080"&gt;0&lt;/font&gt;&lt;/span&gt;)&lt;br /&gt;&lt;font color="#804040"&gt;81&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;font color="#804040"&gt;82&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; std::setw(&lt;span&gt;&lt;font color="#000080"&gt;2&lt;/font&gt;&lt;/span&gt;) &amp;lt;&amp;lt; (DWORD)(pbSignature[i]) &amp;lt;&amp;lt; &lt;span&gt;&lt;font color="#000080"&gt;" "&lt;/font&gt;&lt;/span&gt;;&lt;br /&gt;&lt;font color="#804040"&gt;83&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;font color="#804040"&gt;84&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;font color="#804040"&gt;85&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;std::cout &amp;lt;&amp;lt; std::dec &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;font color="#804040"&gt;86&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; S_OK;&lt;br /&gt;&lt;font color="#804040"&gt;87&lt;/font&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;OK, that's a chunk and a half of code right there.&amp;nbsp; However, the process its following is relatively straight forward.&amp;nbsp; On lines 9-14, I use the DbgHelp function &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/imagentheader.asp"&gt;ImageNtHeader&lt;/a&gt; to locate the IMAGE_NT_HEADERS structure in the file.&amp;nbsp; Once we have the NT headers, we need to find the data directories, but their location varies depending upon if the assembly is a PE32 or PE32+ file.&amp;nbsp; So on lines 16 through 30 we check the magic number in the beginning of the optional header, and get the correct pointer to the data directories.&amp;nbsp; If the PE is neither of these two formats, we bomb out. &lt;p&gt;So now that we've got the table of directory entries, on lines 32 through 52 we make sure that the entry for the COM descriptor directory exists, and if it does use another DbgHelp function &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/imagervatova.asp"&gt;ImageRvaToVa&lt;/a&gt;&amp;nbsp;in order to convert the RVA of the directory entry to an address within the mapped file.&amp;nbsp; The beginning of this directory entry is the CLR header, in the form of a IMAGE_COR20_HEADER structure. &lt;p&gt;Once we have our IMAGE_COR20_HEADER, the information about the signature is located in the StrongNameSignature field.&amp;nbsp; In lines 54-73 we check if a signature exists, and if it does, use ImageRvaToVa in order to calculate the location in the file of the signature itself. &lt;p&gt;Once we have that offset, dumping the signature to the display is easy.&amp;nbsp; Lines 75-83 simple iterate over the memory in the memory mapped file that contains the signature until we've dumped out pCorHeader-&amp;gt;StrongNameSignature.Size bytes.&amp;nbsp; At that point, we've displayed the entire signature, so the method returns.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=361109" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Security/default.aspx">Security</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Cryptography/default.aspx">Cryptography</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Windows/default.aspx">Windows</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category><category domain="http://blogs.msdn.com/shawnfa/archive/tags/StrongName/default.aspx">StrongName</category></item><item><title>Shri Starts Blogging</title><link>http://blogs.msdn.com/shawnfa/archive/2005/01/25/360413.aspx</link><pubDate>Tue, 25 Jan 2005 21:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:360413</guid><dc:creator>shawnfa</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/shawnfa/comments/360413.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnfa/commentrss.aspx?PostID=360413</wfw:commentRss><description>&lt;A href="http://blogs.msdn.com/shrib/"&gt;Shri started up a blog today&lt;/a&gt;, joining &lt;A href="http://blogs.msdn.com/davidnotario"&gt;David&lt;/a&gt; as members of the JIT team on &lt;a title="" href="http://msdn.microsoft.com" &gt;MSDN&lt;/a&gt; blogs.&amp;nbsp; &lt;A href="http://blogs.msdn.com/shrib/archive/2005/01/25/360370.aspx"&gt;His first post is on how the x86 JIT implements a tail call&lt;/a&gt; ... and why its not as fast as it could be.&amp;nbsp; Now that Shri has a blog, the percentage of people in my hallway that are blogging has overcome the percentage of people without MSDN blogs :-)&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=360413" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/shawnfa/archive/tags/Under+the+Hood/default.aspx">Under the Hood</category></item></channel></rss>