Introduction
This is a short article that shows you how to read a PE images manifest resource by accessing an undocumented internal .NET Framework class from inside an internal namespace by loading the class containing assembly into the executing assembly, then importing and instantiating the internal class and finally calling the method via reflection and dynamic invocation. In addition, it also shows how to encapsulate the code in a reusable static
method and how to convert the returned datastream
the right way. The final result will be a XmlDocument
object class instance which offers a comfortable way to explore the manifests internals by walking the XML document using the .NET Frameworks XML/DOM functions.
Background
I was looking for some quick and easy way to read the manifest file from PE images like the way Resource Editors, IDEs or Debuggers/Disassemblers can do, but unfortunately the .NET runtime did not offer an easy way to do this, at least I didn't know one until yet. The standard "easiest" way to do this is to use P/Invoke to access the manifest data compiled into a PE images resources section by using Windows API resource management functions. The steps to get the information you want look like this:
LoadLibrary(Ex)
FindResource
SizeOfResource
LoadResource
LockResource
CopyMemory
or similar suitable memory copy function like Marshal.Copy(...)
FreeLibrary
Another way would be to read the raw PE images binary data and parse its contents step-by-step until one gets the information needed, but this is truly very hard to do, because you have to access the PE images bytes and bits and one wrong offset calculation or data misinterpretation can result in totally useless information or corrupted resulting data. Another way would be using the Debug Help Library API, but this is again lots of P/invoke and we don't want that. There is another fully "managed" way to do this.
Looking at the .NET Frameworks source code, I found one undocumented class/method inside an undocumented namespace, that exactly does the steps above for me and I don't have import/declare any additional unnecessary P/invoke signatures. The method we are using is named GetManifestFromPEResources(...)
and the implementing class we are using is the internally (internal class
) declared SystemUtils
class inside the System.Deployment.Application.Win32InterOpt
namespace. The binary assembly DLL file implementing the class is named System.Deployment.dll in my 32-bit .NET installation directory inside "\Windows\Microsoft.NET\Framework\v2.0.50727\". The same libraries can be found inside the 64-bit .NET directories as well. The method is internally using exactly the same Windows API functions above by accessing them using P/Invoke (like most of the runtime classes are doing in any .NET versions by either accessing the Windows API or the Windows Runtime for some tasks), but the good news is, that all can be done in a single call to this undocumented function and we don't have to bother what it looks inside it in detail (but we know that it is exactly what we wanted to do). Once we get the manifest data, we convert it appropriately and create a XmlDocument
object from it for easy XML objects access, because we know that the manifest is plain text XML, but all this is explained inside the code.
Using the Code
The code is quite self-explanatory and has some basic comments to explain the steps. The classes used in the code have been declared with their full namespace qualifiers to clarify their origins in the frameworks runtime:
The desired functions signature looks like this:
public static byte[] GetManifestFromPEResources(string filePath)
and the full code looks like this:
C# Code
public static System.Xml.XmlDocument GetPEFileManifest(
System.String fileName)
{
System.Xml.XmlDocument xmld;
System.Exception err;
GetPEFileManifest(
fileName,
out xmld,
out err);
return xmld;
}
public static System.Boolean GetPEFileManifest(
System.String fileName,
out System.Xml.XmlDocument applicationXmlManifest,
out System.Exception error)
{
try
{
if(System.String.IsNullOrEmpty(fileName) == true)
throw new System.NullReferenceException("Parameter \"fileName\" cant be null or empty");
if(System.IO.File.Exists(fileName) == false)
throw new System.IO.FileNotFoundException
("Parameter \"fileName\" does not point to a existing file");
System.Reflection.Assembly SystemDeploymentAssembly = System.Reflection.Assembly.Load(
"System.Deployment, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
System.Type SystemUtilsClass = SystemDeploymentAssembly.GetType(
"System.Deployment.Application.Win32InterOp.SystemUtils");
System.Object SystemUtils = System.Activator.CreateInstance(SystemUtilsClass);
System.Byte[] ManifestBytes = SystemUtils.GetType().InvokeMember(
"GetManifestFromPEResources",
System.Reflection.BindingFlags.InvokeMethod |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Static,
null,
SystemUtils,
new System.Object[] { fileName }) as System.Byte[];
string ManifestXmlString = string.Empty;
using (System.IO.MemoryStream ManifestBytesMemoryStream =
new System.IO.MemoryStream(ManifestBytes))
using (System.IO.StreamReader ManifestBytesStreamReader = _
new System.IO.StreamReader(ManifestBytesMemoryStream, true))
{
ManifestXmlString = ManifestBytesStreamReader.ReadToEnd().Trim();
}
System.Xml.XmlDocument ManifestXmlDocument = new System.Xml.XmlDocument();
ManifestXmlDocument.LoadXml(ManifestXmlString);
applicationXmlManifest = ManifestXmlDocument;
error = null;
return true;
}
catch(System.Exception err)
{
error = err;
applicationXmlManifest = null;
return false;
}
}
VB.NET Code
Public Shared Function GetPEFileManifest(ByVal fileName As System.String) As System.Xml.XmlDocument
Dim xmld As System.Xml.XmlDocument
Dim err As System.Exception
GetPEFileManifest(fileName, xmld, err)
Return xmld
End Function
Public Shared Function GetPEFileManifest(ByVal fileName As System.String, _
ByRef applicationXmlManifest As System.Xml.XmlDocument, _
ByRef [error] As System.Exception) As System.Boolean
Try
If System.[String].IsNullOrEmpty(fileName) = True Then
Throw New System.NullReferenceException("Parameter ""fileName"" cant be null or empty")
End If
If System.IO.File.Exists(fileName) = False Then
Throw New System.IO.FileNotFoundException_
("Parameter ""fileName"" does not point to a existing file")
End If
Dim SystemDeploymentAssembly As System.Reflection.Assembly = _
System.Reflection.Assembly.Load("System.Deployment, _
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
Dim SystemUtilsClass As System.Type = _
SystemDeploymentAssembly.[GetType]_
("System.Deployment.Application.Win32InterOp.SystemUtils")
Dim SystemUtils As System.Object = System.Activator.CreateInstance(SystemUtilsClass)
Dim ManifestBytes As System.Byte() = TryCast(SystemUtils.[GetType]().InvokeMember(_
"GetManifestFromPEResources", System.Reflection.BindingFlags.InvokeMethod Or _
System.Reflection.BindingFlags.[Public] Or System.Reflection.BindingFlags.[Static], _
Nothing, SystemUtils, New System.Object() {fileName}), System.Byte())
Dim ManifestXmlString As String = String.Empty
Using ManifestBytesMemoryStream As New System.IO.MemoryStream(ManifestBytes)
Using ManifestBytesStreamReader As _
New System.IO.StreamReader(ManifestBytesMemoryStream, True)
ManifestXmlString = ManifestBytesStreamReader.ReadToEnd().Trim()
End Using
End Using
Dim ManifestXmlDocument As System.Xml.XmlDocument = New System.Xml.XmlDocument()
ManifestXmlDocument.LoadXml(ManifestXmlString)
applicationXmlManifest = ManifestXmlDocument
[error] = Nothing
Return True
Catch err As System.Exception
[error] = err
applicationXmlManifest = Nothing
Return False
End Try
End Function
Code in Detail (C#)
First, we check the input parameters to make sure we got a valid filename to access. Then, we load the assembly holding the method we want by using the:
System.Reflection.Assembly.Load()
method. There are several overloads for that method and maybe one wants to use another variant of it. Take a look at its documentation in the MSDN library. In our case, the assembly we are looking for to load is the "System.Deployment
" and we use the long form of the assembly name to reference and load it:
"System.Deployment, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
There are possibly other versions/cultures of that assembly, but I didnt investigate that yet. Please keep in mind that once the assembly is loaded into the applications AppDomain
, it can't be unloaded for several reasons that I don't want to discuss here. There are lots of articles here showing how to load an external assembly into a seperate AppDomain
and unload it after using it just for the case you want to unload it. After loading it into the executing assembly, we access the desired classes and methods inside the loaded assembly by using reflection:
System.Type SystemUtilsClass = SystemDeploymentAssembly.GetType
("System.Deployment.Application.Win32InterOp.SystemUtils");
System.Object SystemUtils = System.Activator.CreateInstance(SystemUtilsClass);
System.Byte[] ManifestBytes = SystemUtils.GetType().InvokeMember(
"GetManifestFromPEResources",
System.Reflection.BindingFlags.InvokeMethod |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Static,
null,
SystemUtils,
new System.Object[] { fileName }) as System.Byte[];
First, we get the SystemUtils
class type by querying the loaded assembly which gets the Type
object with the specified name, performing a case-sensitive search for further usage. It is important here to use the FQN (Full Qualified Name) of the type residing in the assembly. After successfully obtaining the SystemUtils
class type, we create an instance of it by using the Activator
classes CreateInstance(...)
method. Finally, we make a call to the hidden GetManifestFromPEResources(...)
method by invoking the member method of the instantiated class. To make a successful call, you have to pass the correct case of the methods name and the right binding flags as used above. For more information, please refer to the MSDN documentation. After getting the byte[]
array holding the PE manifest, we need to convert it into a string
. This is done like this:
string ManifestXmlString = string.Empty;
using (System.IO.MemoryStream ManifestBytesMemoryStream = new System.IO.MemoryStream(ManifestBytes))
using (System.IO.StreamReader ManifestBytesStreamReader =
new System.IO.StreamReader(ManifestBytesMemoryStream, true))
{
ManifestXmlString = ManifestBytesStreamReader.ReadToEnd().Trim();
}
The reason why we are using the StreamReader
class is that it is aware of the BOM (Byte Order Mark) in the manifests byte[]
arrays first bytes and we don't have to take care of it anymore. If there is a BOM in the array (there isn't always a BOM in the resource), the StreamReader
will handle it for us, if not, it will simply read the bytes into the stream. Looking at the BOM inside a hex editor, it looks like this:
Finally, we create an XmlDocument
from the XML string
we got and return it to the caller:
System.Xml.XmlDocument ManifestXmlDocument = new System.Xml.XmlDocument();
ManifestXmlDocument.LoadXml(ManifestXmlString);
applicationXmlManifest = ManifestXmlDocument;
The reasons why I decided to pack the XML text into an XmlDocument
class is quite simple. Once the manifest is mapped into a XmlDocument
, it can fully be accessed by the .NET Frameworks XML/DOM functions and can also be manipulated (read, written, extended, split, etc.) the way one wants to change it.
Summary
Although this all can be done with P/Invoke by using the single Windows API calls, I personally find it more "clean" to use this undocumented function, since it encapsulates all the calls inside one single function and all is done from outside the function in plain managed code and this undocumented class/method is available from .NET 2.0 up to the latest version of the .NET runtime library. Always keep in your mind: Undocumented functions are always a matter of taste and are always possibly subject to change or can be fully unavailable in future releases/updates, so one has to decide if he/she wants to use this function or completely rewrite it using the Windows API functions to have a own codebase for future usage.
There is also the other way: Updating a PE's manifest resource, but I wont cover this here and it is not the purpose of this article. The only thing I want to point out is, if someone is interested for sure, that it can be done with the Resource
functions from the Windows API in the following order:
BeginUpdateResource
UpdateResource
EndUpdateResource
History
- 19/01/2013 - Initial article release
- 22/01/2013 - Added VB.NET code and corrected a few typos
External Links