Coding Stephan

Analysing Win32 Content Prep Tool

In my quest to build an open-source, cross platform, tool that packages Win32 apps from Winget for Intune WingetIntune on GitHub, I’ve been looking at the Win32 Content Prep Tool. This tool is used by administrators to prepare Win32 apps for deployment in Intune. It’s a closed source application requiring windows to run. In this post I’ll be looking at the tool and how it works.

Detection.xml file from .intunewin

What is the Win32 Content Prep Tool

Use the Microsoft Win32 Content Prep Tool to pre-process Windows Classic apps. The packaging tool converts application installation files into the .intunewin format. The packaging tool also detects the parameters required by Intune to determine the application installation state. After you use this tool on your apps, you will be able to upload and assign the apps in the Microsoft Intune console. source.

The readme also contains some additional hints on how the tool works:

  • .NET Framework 4.7.2 is required.
  • For MSI setup file, this tool will retrieve required information for Intune.

And may the most important information:

Note: The generated .intunewin file contains all compressed and encrypted source setup files and the encryption information to decrypt it. Please keep it in the safe place as your source setup files.

You must also agree with the licenses before you can use the tool.

How does it work

It you run this tool it will ask you for a directory containing the setup files, mind you files so multiple files. It will also ask for a setup file inside that directory. And it asks for an output directory. After that it will start processing the files and create an .intunewin file in the output directory.

This .intunewin file is a compressed and encrypted file according to the readme. I’ve just given it a try by renaming the file to .zip and extracted it. This gives me the following files:

IntuneWinPackage
- Metadata
  - Detection.xml
- Contents
  - IntunePackage.intunewin

I noted the following observations:

  • The top .intunewin file is a zip file, which is not encrypted as specified in the readme.
  • There is a Detection.xml file in the Metadata folder.
  • There is a IntunePackage.intunewin file in the Contents folder, which is a bit smaller then the combination of all the files in the source directory, but it grows if I add more files. This file must contain the compressed source files.
  • The IntunePackage.intunewin file from the Contents folder is actually encrypted, I tried the renaming trick and failed miserably.

Detection.xml

Here is a sample of the Detection.xml file:

<ApplicationInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ToolVersion="1.8.4.0">
  <Name>install-amd64.exe</Name>
  <UnencryptedContentSize>5957009</UnencryptedContentSize>
  <FileName>IntunePackage.intunewin</FileName>
  <SetupFile>install-amd64.exe</SetupFile>
  <EncryptionInfo>
    <EncryptionKey>D+ybCjTETXC8MoVN50MHzD46e44S7utjv+joT3Z7beM=</EncryptionKey>
    <MacKey>UXblbITBQud2iQguE4Xrb0odDH3RVSIwEiPokQaBydE=</MacKey>
    <InitializationVector>KIkWu3WQuFiJdYGqerI1+Q==</InitializationVector>
    <Mac>5Gu4ndv6RhtRBPaeNzHjMZJcSDJc9yy7l9zqZTPvevE=</Mac>
    <ProfileIdentifier>ProfileVersion1</ProfileIdentifier>
    <FileDigest>0mRcAQNg2d0h0yvjTnCUQ/ZcuNeQXaYZ1BUUBNTILaU=</FileDigest>
    <FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
  </EncryptionInfo>
</ApplicationInfo>

I already figured out that this detection file contained all the information needed to publish a Win32 app to Intune, in a previous post. If I take the same installer and run it through the tool again, I get a slightly different detection file. Some properties change like the EncryptionKey, MacKey, InitializationVector and Mac. The FileDigest and FileDigestAlgorithm stay the same.

Just by looking at the detection file and the changes I can make a few assumptions:

  • The EncryptionKey, MacKey and InitializationVector are generated each time the tool runs.
  • The EncryptionKey and InitializationVector might be used to decrypt the IntunePackage.intunewin file.
  • The Mac and MacKey, if their name is derived from HMAC, are somehow used to verify the integrity of the IntunePackage.intunewin file.
  • The FileDigest and FileDigestAlgorithm are used to verify the integrity of the installer files?
  • There seems to be some sort of base64 encoding going on.
  • All the setup files are compressed into the IntunePackage.intunewin file, let’s assume it’s a zip file as well, but this time encrypted.
  • Why would you need the UnencryptedContentSize, if you’re not going to use it? Maybe because they embed encryption or integrity information in the file itself? Then you would need to have the original size to be able to decrypt it.

IntunePackage.intunewin

Let’s summarize all findings on this secretive IntunePackage.intunewin so far:

  • It’s a compressed file, presumably a zip file.
  • It’s encrypted, presumably using the EncryptionKey, and InitializationVector that are saved in the Detection.xml file.
  • There is some sort of file integrity check using a Mac and a MacKey, since the MacKey changes every time I run the tool, I assume they use HMAC, with a randomly generated key.
  • The UnencryptedContentSize is saved, so let’s assume the encrypted file is appended or prepended with some sort of encryption or integrity information.
  • The EncryptionKey seems to be exactly 32 bytes or 256 bits.
  • The IntunePackage.intunewin file is 5957072 bytes and the UnencryptedContentSize is 5957009 bytes, so the difference is 63 bytes. This is probably the size of the encryption and/or integrity information.

I’m by no means an expert in file encryption, but when I searched for InitializationVector with my favorite search engine, I found Initialization Vector on Wikipedia. This page mentions AES, so that’s where I’ll point my attention to. Taking the size of the encryption key in mind, my best guess is AES-256. Taking the Mac and the MacKey into account I found that they may be doing something like Authenticated encryption. This is a way to encrypt and verify the integrity of a file at the same time. This would also explain the UnencryptedContentSize property, since the encrypted file would be bigger then the original file.

Decryption time

To check all my assumptions I’ve asked GitHub CoPilot to help me out.

Question:

Can you explain how to decrypt a file that was encrypted using AES encryption with an initialization vector and a keyed hash message authentication code (HMAC) for integrity verification in C#?

Answer:

Apart from giving me a complete explanation on the topic (I’m really loving GitHub CoPilot, I makes my life as a developer a whole bunch easier), it also provided some code to get me started.

private static async Task DecryptFileWithIVAsync(
    string sourceFile,
    string targetFile,
    byte[] encryptionKey,
    byte[] hmacKey,
    CancellationToken cancellationToken)
{
    byte[]? decryptedFileHash = null;
    using (Aes aes = Aes.Create())
    using (HMACSHA256 hmac = new HMACSHA256(hmacKey))
    using (FileStream sourceFileStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.None, bufferSize: 4096, useAsync: true))
    using (MemoryStream encryptedData = new MemoryStream())
    {
        int offset = hmac.HashSize / 8;
        byte[] buffer = new byte[offset + aes.IV.Length];
        await sourceFileStream.ReadAsync(buffer, 0, offset + aes.IV.Length, cancellationToken);
        byte[] iv = buffer.Skip(offset).ToArray();
        byte[] hmacHash = buffer.Take(offset).ToArray();
        await sourceFileStream.CopyToAsync(encryptedData, 2097152, cancellationToken);
        encryptedData.Seek(0L, SeekOrigin.Begin);
        byte[] computedHash = await hmac.ComputeHashAsync(encryptedData, cancellationToken);
        if (!computedHash.SequenceEqual(hmacHash))
        {
            throw new CryptographicException("HMAC validation failed. The encrypted file may have been tampered with.");
        }
        encryptedData.Seek(0L, SeekOrigin.Begin);
        using (ICryptoTransform cryptoTransform = aes.CreateDecryptor(encryptionKey, iv))
        using (CryptoStream cryptoStream = new CryptoStream(encryptedData, cryptoTransform, CryptoStreamMode.Read))
        using (FileStream targetFileStream = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
        {
            cancellationToken.ThrowIfCancellationRequested();
            await cryptoStream.CopyToAsync(targetFileStream, 2097152, cancellationToken);
            targetFileStream.Flush();
            decryptedFileHash = await hmac.ComputeHashAsync(targetFileStream, cancellationToken);
        }
    }
}

Series: Intune

Conclusion

I’ve not tested the above code, but I feel I made some big steps in dissecting the mysterious IntunePackage.intunewin file. Being able to decrypt the file would also give me insight into how I could possibly create those files. It’s all part of my journey to be able to create those files myself, without the need for the Win32 Content Prep Tool. And thus making my WingetIntune tool cross platform and cloud ready.

I hope you enjoyed this post, and if you have any feedback, please let me know on Twitter or LinkedIn. All details about this tool are gained by thorough analysis of publicly available data.