Donnerstag, 24. März 2011

Manifests - Lets declare some principles!

Hello again!

In this article I like to spend a few words on a concept introduced with Windows XP: Manifest files. These files are used beside an executable to tell various things about the context the program will run in. I think the most common usage of manifests is to enable visual styles in an application. But if we look closer on that we can see that it actually is not like manifests directly enable the visual styles, no, the manifest actually only tells the operating system that our application depends on a so called 'assembly'. Don't be scared, it has nothing to do with assembler, ill explain later what to understand under assemblies and what dependency means.

So we have learned one important aspect of manifests:
  • They can declare dependencies to assemblies.
Ok, but ask yourself: Did you ever find a manifest in programming world yet? I bet no if you didn't intend to ;). So  is no one using manifests or what is the reason for that? No, id say every executable you start is using a manifest, but where is it? To answer that question you need to know how the operating system actually searches for that manifest.
  1. It searches in the global cache.
  2. It searches for the first resource inside the executable which has the type RT_MANIFEST (24 on my system) 
  3. If nothing is found inside the exe it searches inside the folder if it finds a file named EXENAME.exe.manifest.
Because modifying a manifest without knowledge about it by an end user may result in severe problems running the application the third method isn't chosen often by deployed programs. As modifying resources at least requires the knowledge how to access and compile resources into a file you can be pretty sure that most users of your application wont be able to accidentally destroy the manifest (and if they do its not our problem :D). Thats the reason why you probably have never seen a manifest file - they are inside the executable!

Well, i think its time now to have a view on an example manifest. If you create a new project in Visual Studio a manifest is automatically generated when you build your application. It can be found inside the Debug (or Release) folder of your project (not solution) and is called 'ProjectName.exe.intermediate.manifest'. It has the intermediate inside it because thats the part that gets automatically added but you can modify that inside the project settings and thus its not the final version but only an intermediate one.

I named my Project ManifestExample so the manifest is called ManifestExample.exe.intermediate.manifest and the contents are:
<assembly manifestversion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <trustinfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedprivileges>
        <requestedexecutionlevel level="asInvoker" uiaccess="false">
      </requestedexecutionlevel>
    </security>
  </trustinfo>
</assembly> 

First thing we see is that manifests are written using the XML syntax. That makes it pretty straightforward to understand and we can focus on the actual elements. What this manifest does is that it defines some security related properties of the application. To be more clear: It declares which access rights the user has to have this application will run in. That is controlled using the 'level' attribute inside the requestedexecutionlevel tag. There are 3 values valid for the level attribute:
  1. asInvoker -> The application will run with the same privileges as the calling user
  2. highestAvailable -> The application will run with the highest privileges the current user can reach
  3. requireAdministrator -> The application must be run in administrator mode (on Vista and Win7 a window will pop up asking the user to allow the application to run as administrator if thats enabled)
The default value of course is asInvoker as thats pretty neutral.

The uiaccess attribute is a bit more complex. Imagine you are writing an application that simulates a keyboard on the monitor where the user can make input. Now it may be necessary to bypass regular input control mechanics to work properly. To be able to do that the uiaccess attribute must be set to true.

In addition setting uiaccess to true requires some additional security options! The application first has to be signed by Authenticode and second it has to be in protected folder (for example system32 or program files).

Second thing we learned about manifests:
  • Manifests define security aspects of an application.
Now lets have a look at a manifest that does what i ment above: Add a dependency to an executable. In this example we add a dependency to the assembly called "CommonControls". It has to be said that your application be default already has a dependency to CommonControls but it depends on version 5 of CommonControls which contains the old visual themes and we need version 6 which contains the new visual themes since XP!

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level='asInvoker' uiAccess='false' />
      </requestedPrivileges>
    </security>
  </trustInfo>

  <dependency>
    <dependentAssembly>
      <assemblyIdentity 
        type='win32' 
        name='Microsoft.Windows.Common-Controls'
        version='6.0.0.0' 
        processorArchitecture='*'
        publicKeyToken='6595b64144ccf1df'
        language='*'
      />
    </dependentAssembly>
  </dependency>
</assembly>


The new tags we see are dependency, dependentAssembly, assemblyIndentity. The dependency tag lists a dependency for application the dependentAssembly tag hosts a dependency to an assembly and the assemblyIndentity tag finally specifies the assembly our application is depending from. There we find several possible attributes that identify the assembly. Actually only two of them are required the rest is optional and is used to distinguish it from other assemblies that may have the same attributes.

Explanation:
  • type - Optional - Only valid value is win32
  • name - Required - The name of the assembly
  • version - Required - The version of the assembly to load
  • processorArchitectur - Optional - May be clear. Valid values are (ia64, amd64, x86, msil)
  • publicKeyToken - Optional - The strong name of the assembly
  • language - Optional - The language ID of the assembly
As you can see we request version 6 of the Common-Controls which means controls with new visual styles!

Now its time to talk about how the system finds an assembly. This is actually pretty simple. The system does the same as it does when you launch an application. In the above code it will search a manifest which denotes an assembly witch defines an assemblyIdentity that matches the requested one. In our case it searches the following way:
  1. It searches the Microsoft.Windows.Common-Controls.dll inside global search paths and inside the current executables path. If it finds that dll it searches a manifest resource inside that dll that is called "Microsoft.Windows.Common-Controls.manifest" and compares it.
  2. If that didnt succeed the system searches in the same paths for a file called Microsoft.Windows.Common-Controls.manifest and parses it
  3. If that failed it searches for the folder "Microsoft.Windows.Common-Controls" inside all global search paths and the current executable path and does the same search as above again
To be identified a component (for example a DLL) must have a manifest that defines a global assemblyIdentity. That actually makes it an recognizable assembly inside the system. Here is an example manifest that identifies everything its included into as an assembly of the given name (and does nothing more):


      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <assembly xmlns="urn:schemas-microsoft-com:asm.v1"  manifestVersion="1.0">
        <assemblyIdentity
          type="Win32"
          name="MyNiceAssembly"
          version="1.0.0.0" 
        />
      </assembly>
      

      We learn:
      • Manifests can be used to give any component (DLL, exe, ...) a name with which it can be identified
      Thats it for this article! Feel free to post comments or ask questions. I dont think that everything got clear enough for everyone so im really happy if you tell me your problems or questions!

      Thanks
      Yanick

        Keine Kommentare:

        Kommentar veröffentlichen