Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / Win32

Retrieve the Assembly Identities from a Manifest using C++

Rate me:
Please Sign up or sign in to vote.
4.91/5 (20 votes)
20 Jun 2010CPOL8 min read 48.6K   1.1K   35   7
A set of C++ interfaces to retrieve the side-by-side information of a manifest embedded in an image file.

Goal

This article gives an overview of the Windows side-by-side assemblies technology, and then presents a set of C++ interfaces you can use to programmatically retrieve the side-by-side relevant information out of a manifest embedded in any image file.

Classes_diagram.png

Introduction

Since Windows XP, a new feature is available in the Operating System which enables different versions of a dynamic link-library to co-exist on a system without conflicting with one another. This feature, which is called side-by-side assemblies, resolves a problem which was known as "DLL Hell" where one library could overwrite another version (newer or older) regardless of whether or not any application would still need the previous one.

Ever noticed the size of the "\Windows\WinSxS" folder? Depending on the type of version of Windows (Home, Ultimate, Server...) and applications installed, it can grow up to several GB and more, with 20,000 folders and 80,000 files! By taking a closer look at the content of the directories hosted by WinSxs, you will notice that many of them store the same dynamic link-libraries, each having the same name but different paths.

As an example, seven different versions (8.0.7600.xxxxx) of the IEFRAME.DLL library are located in the side-by-side store of my system. All of these can potentially be used by any application built with different versions of this library.

comctl32_found_on_my_system.png

Assembly Cache

The WinSxS directory is sometimes called the assembly cache or the side-by-side store. Starting with Windows Vista and Windows Server 2008, it is named the Component Servicing Infrastructure (CSI) component store.

This store hosts not only side-by-side assemblies (dynamic link-libraries), but also other types of files like all the standard Windows built-in applications, manifests, and even help files.

"All of the components in the Operating System are found in the WinSxS folder - in fact, we call this location the component store. Each component has a unique name that includes the version, language, and processor architecture that it was built for. The WinSxS folder is the only location that the component is found on the system; all other instances of the files that you see on the system are "projected" by hard linking from the component store...."

(http://blogs.technet.com/b/askcore/archive/2008/09/17/what-is-the-winsxs-directory-in-windows-2008-and-windows-vista-and-why-is-it-so-large.aspx)

WinSxS Aware Applications

In order to use components located in the side-by-side store, applications must be compiled with a set of special tags. When an application starts, the Windows loader analyzes the application dependencies declared in the Import Address Table (IAT) of the image file, and then the Side-by-Side Manager tries to locate the referenced dynamic link-libraries.

One of the ways to make an application WinSxS-aware is to embed a manifest inside the image file of the application. The following illustration shows the RT_MANIFEST of NOTEPAD.EXE when opened in Visual Studio 2008.

RT_MANIFEST_of_Notepad.png

When exported, the XML file representing the manifest of NOTEPAD.EXE looks like this:

XML_Snapshot.png

As shown in the illustration above, NOTEPAD.EXE is WinSxS-aware while it integrates, in its manifest, a <dependency> block containing a <dependentAssembly> section.

The <assemblyIdentity> block contains several parameters (some are mandatory, some not) used to declare (manifest) to the system the expectations of the application regarding specific assemblies of the side-by-side store.

To reference an assembly from the side-by-side store, an application must provide some parameters like name, version, processor architecture, language, and public key token of the library. This kind of decoration allows a very granular selection of the library to consume among any other potentially previously (and future) installed versions of it.

The side-by-side feature is not only available for .NET but also for any standard Windows application and library. An application can be side-by-side dependent of libraries, but a library can also be side-by-side dependent of other libraries. This is a common Windows dynamic link-library issue.

The Import Address Table (IAT), the application manifest, the SxS Manager, and the side-by-side store work together as illustrated below:

SxsManager.png

When an application is launched, the system goes through the following steps:

  1. The loader inspects the Import Address Table (IAT) of the application and discovers all directly and indirectly imported libraries. The IAT contains only library names and extensions (e.g., advapi32.dll, gdi32.dll, winspool.drv, ...ntdll.dll) but no path information. The system itself has to find out where the referenced libraries are physically located. This is exactly where the DLL Hell used to begin...and where the side-by-side mechanism jumps into action - if an application contains a manifest.
  2. The SxS Manager locates and reads the application manifest and constructs the name of the fully qualified path of the libraries referenced by the application. This path is computed based on the information contained in the manifest.
  3. When an application references a side-by-side library, the loader does not search for it in the typical locations (application folder, Windows system directories, etc...) but exclusively in the side-by-side store.

The illustration below shows the (implicitly) imported libraries of NOTEPAD.EXE, using Dependency Walker (www.dependencywalker.com), containing an entry in its Import Address Table (IAT) which tells the system that it imports the COMCTL32.DLL library.

notepad_iat.png

For those of you who know Dependency Walker, you know that it has an option to show the path of the dependent libraries.

Image 7

As previously mentioned, no path whatsoever is stored in the image file in regard of the imported library. As you see in the illustrations above, Dependency Walker is showing two different kinds of paths:

  1. Almost all paths reference the typical System32 folder where the system has found the referenced libraries. If there is no manifest or if no entry has been found for a specific library, the system loads the library from the typical locations (system directory, application directory, etc.).
  2. One path entry references the WinSxs store where the specific version of the COMCTL32.DLL library (based on its version, name, language - culture, token...) has been found. In the case of NOTEPAD.EXE, only COMCTL32.DLL has been declared as to be retrieved from the side-by-side assemblies store.

How does Dependency Walker obtain the path of this COMCTL32.DLL library? By reading the application manifest, identifying the dependency, and concatenating out of the XML parameters the path of the assembly within the WinSxS directory.

As shown above, the image file of NOTEPAD.EXE contains a manifest that tells the system that it wants to use the Microsoft.Windows.Common-Controls which should be located in the side-by-side component store. From the point of view of the SxS Manager, this will map to COMCTL32.DLL!

The illustration below shows two different versions of the COMCTL32.DLL libraries found in the WinSxS folder of my system:

comctl32_found_on_my_system.png

When NOTEPAD.EXE is launched, the WinSxS Manager reads the manifest of NOTEPAD.EXE and identifies a dependency with one side-by-side assembly. It reads its different parameters and constructs with these fields a path:

Position

Parameter

Description

1

type

Win32 (x86)

2

name

Microsoft.Windows.Common-Controls

3

publicKeyToken

6595b64144ccf1df

4

version

6.0.0.0

5

language

* (none)

For more details about these fields, please look at the description provided by Microsoft at http://msdn.microsoft.com/en-us/library/aa374219(v=VS.85).aspx.

The path where the Windows loader should look for a side-by-side library is based on five parameters that are read from the manifest, each separated with one underscore.

Out of these parameters, the following fully qualified name of the COMCTL32.DLL library has been built as can be seen when running Dependency Walker on NOTEPAD.EXE:

depends_with_numbers.png

In case a side-by-side library that is referenced by an application through its manifest is missing, the loader will complain that the correct application environment has not been established and the program will not load. This will occur with any missing (implicit) library.

MyApp_-_Failed_to_start_messagebox.png

This kind of situation also occurs when you try to analyze (using Dependency Walker) an application whose dependency has not been found in the WinSxS store:

Depends_also_tests_WinSxs.png

As mentioned in the message box that appears, a look at the Event Log reveals the cause of the error:

MyApp_-_Failed_to_start_in_Event_Log.png

The well known quick fix of copying the missing library into the local application directory or the Windows directory will not fix the error. This is because the Windows loader looks only for the side-by-side assemblies used by the application in the WinSxS store. For this reason, any side-by-side assembly must be deployed in the WinSxS store!

A closer look at the error message of the Event Log shows an interesting hint to a utility called "sxstrace". Please try it, and you will see how the Windows probing does its best when trying to locate resources referenced by an application....

sxstrace_-_trace.png

sxstrace_-_parse.png

The illustration below is an extract of the myapp.txt file that contains the probing activities of the system when locating the libraries to load:

=================
Begin Activation Context Generation.
Input Parameter:
Flags = 0
ProcessorArchitecture = x86
CultureFallBacks = en-US;en
ManifestPath = C:\temp\MyApp.exe
AssemblyDirectory = C:\temp\
Application Config File =
-----------------
INFO: Parsing Manifest File C:\temp\MyApp.exe.
INFO: Manifest Definition Identity is myapp.processorArchitecture="x86",
      type="win32",version="5.1.0.0".
INFO: Reference: Microsoft.Windows.Common-Controls,language="*",
      processorArchitecture="*",publicKeyToken="6595b64144ccf2df",
      type="win32",version="6.0.0.0"
INFO: Resolving reference Microsoft.Windows.Common-Controls,language="*",
      processorArchitecture="*",publicKeyToken="6595b64144ccf2df",
      type="win32",version="6.0.0.0".
........
ERROR: Cannot resolve reference Microsoft.Windows.Common-Controls,language="*",
       processorArchitecture="*",publicKeyToken="6595b64144ccf2df",
       type="win32",version="6.0.0.0".
ERROR: Activation Context generation failed.
End Activation Context Generation.

Sample

The sample application provided here presents a set of C++ classes, developed with Visual Studio 2008, that you can use to programmatically retrieve the different items of any side-by-side assembly referenced in the manifest file of an application.

When working on a project that handles portable executable files and their dependencies, I came across on the issue presented here and the fact that the path for WinSxS libraries has to be retrieved at runtime.

Application_UI.png

Since I did not find any valuable C++ sample showing how to retrieve the fields of side-by-side dependencies referenced in a manifest, I decided to develop it on my own and to make the code available here. Enjoy it.

Benefit

You can use this set of classes presented here to validate applications during the installation of a program, to analyze executable files for their dependencies, to develop a tool that gathers statistical information about applications, or to develop any kind of forensic tool.

Using the code

Using the classes provided is really straightforward. Simply instantiate a CPeManifest object with the name of the Portable Executable file containing a manifest to analyze:

C++
CString s = "C:\temp\myapp.exe";
CPeManifest manifest(s);
const IPeManifestAssemblyIdentity* pIdentity = m_pPeManifest->GetFirstDependency(); 
while( pIdentity )
{
    m_listDependencies.InsertString( iPos, pIdentity->GetName() );
    m_listDependencies.SetItemDataPtr( iPos++, (void*)pIdentity );
    pIdentity = m_pPeManifest->GetNextDependency();
}

Later on, you can point the select dependency in your code and retrieve the associated parameters, like this:

C++
void CQueryManifestDlg::OnLbnSelchangeListDependentAssemblies()
{
    int iPos = m_listDependencies.GetCurSel();
    IPeManifestAssemblyIdentity* pIdentity = 
       (IPeManifestAssemblyIdentity*)m_listDependencies.GetItemDataPtr(iPos);
    if(pIdentity)
    {
        m_architecture = pIdentity->GetProcessorArchitecture();
        m_token = pIdentity->GetPublicKeyToken();
        m_type = pIdentity->GetType();
        m_language = pIdentity->GetPublicLanguage();
        m_version = pIdentity->GetVersion();
    }
    UpdateData(FALSE);
}

Links

History

  • 17 June 2010: First published.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer winitor
Germany Germany
Marc Ochsenmeier is the author of pestudio (www.winitor.com) and worked as developer with the focus on Windows Security. He now works as a Malware Analyst

pestudio is on twitter at: https://twitter.com/ochsenmeier

Comments and Discussions

 
Questionwhy comdlg32.dll Load the old comctl32.dll Pin
ylka15-Dec-13 1:34
ylka15-Dec-13 1:34 
GeneralMy vote of 5 Pin
gordon8815-Dec-11 6:44
professionalgordon8815-Dec-11 6:44 
GeneralRe: My vote of 5 Pin
marc ochsenmeier5-Jan-14 23:57
marc ochsenmeier5-Jan-14 23:57 
QuestionIntresting article, thanks. One question. Pin
xray200018-Jul-11 3:15
xray200018-Jul-11 3:15 
AnswerRe: Intresting article, thanks. One question. Pin
marc ochsenmeier18-Jul-11 9:02
marc ochsenmeier18-Jul-11 9:02 
GeneralMy vote of 5 Pin
John Sibly6-Jul-10 2:50
John Sibly6-Jul-10 2:50 
GeneralRe: My vote of 5 Pin
marc ochsenmeier8-Sep-10 8:23
marc ochsenmeier8-Sep-10 8:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.