Update 2012-04-16: Later related blog entries (as the topic grew in its scope and version numbering/branch identification changed after Windows Server 2003):
Branching Out (2009-05-18) - gives a generic overview of the branching mechanism, with examples
Service Packs – Levels vs Installers (2009-05-29) - distinguishes between “service pack level” and “service pack installer” for disambiguation
GDR & LDR : The Next Generation (2010-07-14) - describes how to verify the version/branch of a given binary on XP/2003, Vista/W2K8 and Win7/W2K8R2
Original blog entry content follows: Out of the box, all of the files in Windows are on what we refer to as the "General Distribution Release" (GDR) branch.
If updates are only delivered from Windows (or Microsoft) Update (including via WSUS), then all the files remain on the GDR branch.
Some KB articles have packages to address specific issues that are not delivered by Windows Update - "Limited Distribution Release" (LDR) branch packages. Previously we used the term "Quick Fix Engineering" (QFE), but LDR has taken over – expect to see these terms used synonymously.
GDR packages contain only security and critical stability issue fixes. LDR packages contain "other" fixes that have not undergone as extensive testing, and resolve issues that only a fraction of the millions of Windows users might ever encounter.
It is not the entire OS that is considered GDR or LDR - it is down to the individual file level.
A package delivered by Windows Update contains both GDR and LDR versions of the files it updates, so that it is able to replace the files on the system regardless of which branch they are currently on.
A package acquired outside of Windows Update contains only LDR versions of the files it updates, and this will "move" the files onto the LDR branch where they will remain until the next Service Pack.
A Service Pack (SP) contains only GDR branch versions of the files which have been updated by ANY package since the previous Service Pack (or RTM).
So installing the latest Service Pack at, or shortly after release will likely put all of your files (back) onto the GDR branch.
One other thing that Service Packs imply is that hotfix packages need to have versions of the files to replace for the most current SP level and the previous one (dubbed "N and N-1 support").
So for every single file updated by a Windows Update hotfix package after the first SP, there are 4 versions of the file present: "N-1" GDR "N-1" LDR "N" GDR "N" LDR
Taking a ficticious example, where we have the following files straight out of the box: A.EXE RTMGDR 1.0 B.DLL RTMGDR 1.0 C.SYS RTMGDR 1.0
1) Hotfix package KB000001 is installed through windows Update, and contains an update to B.DLL - this pacakge contains: B.DLL SP1GDR 1.1 B.DLL SP1LDR 1.1
> The SP1GDR version is installed by default, and there are only 2 (identical) versions of this file in the package as we're not yet at SP1.
The machine now has: A.EXE RTMGDR 1.0 B.DLL SP1GDR 1.1 C.SYS RTMGDR 1.0
2) Hotfix package KB000002 is installed, NOT through Windows Update, and contains an update for A.EXE - this package contains: A.EXE SP1LDR 1.02
> No options here, the version that ends up on disk is now the LDR version
The machine now has: A.EXE SP1LDR 1.02 B.DLL SP1GDR 1.1 C.SYS RTMGDR 1.0
3) Hotfix package KB000003 is installed through Windows Update and contains an update to A.EXE and C.SYS - this package contains: A.EXE SP1GDR 1.11 A.EXE SP1LDR 1.11 C.SYS SP1GDR 1.11 C.SYS SP1LDR 1.11
> A.EXE is on the LDR branch because of KB000002, while C.SYS is still on the GDR branch
The machine now has: A.EXE SP1LDR 1.11 B.DLL SP1GDR 1.1 C.SYS SP1GDR 1.11
4) Hotfix package KB000100 is installed through Windows Update, and contains an update for C.SYS for the RTM and SP1 versions of the OS - this package contains: C.SYS SP1GDR 1.5 C.SYS SP1LDR 1.5 C.SYS SP2GDR 2.5 C.SYS SP2LDR 2.5
> OS level is still RTM, the current file is on the GDR branch, so we remain on the GDR branch
The machine now has: A.EXE SP1LDR 1.11 B.DLL SP1GDR 1.1 C.SYS SP1GDR 1.5
5) SP1 is now installed on the system, which contains only GDR version 2.0 of every file: A.EXE SP1GDR 2.0 B.DLL SP1GDR 2.0 C.SYS SP1GDR 2.0
> OS level is now raised to SP1 and we push all files on the GDR branch... but look what happens to C.SYS...
The machine now has: A.EXE SP1GDR 2.0 B.DLL SP1GDR 2.0 C.SYS SP2GDR 2.5
> The SP1 package does not contain anything other then the GDR 2.0 versions of the files… so where did the GDR 2.5 version come from?
The hidden, compressed folders named $NtUninstallKBxxxxxx$ in the %systemroot% folder contain the backup of the version(s) of the replaced file(s) when the hotfix was applied, plus the executable to uninstall the package (in the spuninst sub-folder).
The hidden $hf_mig$ folder in the %systemroot% folder contains all the files extracted from the hotfix packages in sub-folders KBxxxxxx- these are necessary to ‘migrate’ the hotfix in the event that a switch of branches occurs or an earlier hotfix package is later installed.
In the example above at step 5, the post-SP1 hotfix package was used to migrate the updated version of C.SYS during the installation of SP1. If this was not done, or if the folder had been deleted, then the file would have been regressed from 1.5 to 2.0.
What? A regression from a lower version to a higher version? Is that a typo? Think of 1.5 as "RTM with KB000100" and 2.0 as "SP1 without KB000100" and it makes a bit more sense.
The migration of hotfixes to avoid regression is done from hotfix to hotfix as well as with SPs.
Imagine we have module X.DLL which has a dependency on module Y.DLL, and they both start at GDR 1.0. Now a GDR hotfix KB000123 is applied which updates Y.DLL to 1.3. Now an LDR hotfix KB000075 is applied which updates X.DLL to 1.1 and Y.DLL to 1.1.
The resultant files on the system would be: X.DLL SP1LDR 1.1 Y.DLL SP1LDR 1.3
If we took Y.DLL 1.1 from the second hotfix then we regress in the security fixes, and if we left Y.DLL 1.3 from the GDR branch then we might miss a dependency that X.DLL LDR 1.1 may have which could lead to instability.
By switching to the LDR branch for the higher version of the file Y.DLL, we remain at the correct level in terms of security & stability fixes (changes in the GDR branch) but also add the fix for the issue mentioned in KB article KB000075.
Moving to the LDR branch for a specific KB article number will not just give you the security changes up to that point plus the 1 non-security issue mentioned in the KB article - it will also contain every non-security update to the files in the hotfix package.
For this reason you will see the all-too-familiar disclaimer: "A supported hotfix is available from Microsoft. However, this hotfix is intended to correct only the problem that is described in this article. Apply this hotfix only to systems that are experiencing this specific problem. This hotfix might receive additional testing. Therefore, if you are not severely affected by this problem, we recommend that you wait for the next software update that contains this hotfix."
If you followed the above then you will also understand why you should never manually delete the $NtUninstallKBxxxxxx$ folders – you will be unable to remove these hotfix packages yet they will be listed in Add/Remove Programs (and you will gain very little disk space by doing this as the contents are compressed on disk).
If you were to delete the $hf_mig$ folder then you would break migration and may prevent the installation of future hotfixes or introduce unexpected regressions when installing service packs.
As if that wasn’t enough… you then have separate packages for the same hotfixes (where appropriate) x86 (i386/IA32), x64 (amd64) and IA64.
x86 is “only 32-bit” and IA64 is “only 64-bit”… but x64-based Windows has the concept of WOW (Windows-On-Windows) so these packages can have an even bigger list of files for the native 64-bit versions and the WOW6432 versions to support 32-bit apps.
Now you can see the value in the file lists documented in the KB articles, showing not just the file version number, but the different branches which have fixes, and this has de-mystified the versioning system a little.
The above is correct for Windows versions up to and including 5.2 (Server 2003 & XP x64 Edition) – when we moved to 6.0 (Vista) we changed how it works.
First, thank you for this very informative and useful article. But, a request for clarification:
You wrote that the $NtUninstallKB*$ folders contain also "the extracted contents of the hotfix packages", and they are used for hotfix migration during subsequent updates.
I had thought %SystemRoot%\$hf_mig$ was used for hotfix migration.
I've checked many of those folders on my Win XP SP2 system. Many of the folder contain only the SPUnInst.EXE and its support files. None of them appear to contain more than one copy of any file; the files they do contain appear to be the old files (for restoration if the hotfix is uninstalled).
Am I missing something, or did you accidentally confuse $NtUninstallKB*$ with $hf_mig$ ?
Hi, and thanks for the feedback - on re-reading what I had originally put it was vague, so I have edited it.
Yes, you are correct - the $NtUninstallKBxxxxxx$ folders are the backed up copies of the files the hotfix package replaced, and a unique copy of its uninstaller.
(The hotfix packages before Vista had their own update.exe and spuninst.exe to allow for changes to how they worked, but now the Windows Installer service and TrustedInstaller user take care of this in a much neater fashion.)
$hf_mig$ is for "hotfix migration" and is where the files extracted per hotfix are stored to allow the servicing engine to avoid regressions.
The hotfix list as presented in Add/Remove Programs is not built from checking for the existence of $NtUninstallKBxxxxxx$ folders, but is maintained separately under SoftwareDistribution in a database - getting this database out of sync with the real disk contents through manual deletion of folders is another reason to not do so ;)
Hi so it the files that are LDR or GDR or there are different OS flavours one GDR and one LDR.Please help out in this regards
Each individual file is either from the LDR or the GDR branch, not the OS as a whole - in fact some binaries do not change from RTM, so neither their version nor branch will ever alter.
Sadly, my experiment does not support your opinion.
kb2286198 (shell32.dll 6.0.2900.6018 gdr/ 6.0.2900.6018 qfe)
, kb2483185(shell32.dll 6.0.2900.6072 gdr/ 6.0.2900.6072 qfe , shimgvw.dll 6.0.2900.6072 gdr/ 6.0.2900.6072 qfe)
original os file:
shell32.dll 6.00.2900.5622 gdr
shimgvw.dll 6.0.2900.5512 none
---force qfe branch
after kb2286198 /b:sp3qfe , os file:
shell32.dll 6.00.2900.6018 qfe
after kb2483185, os file:
shell32.dll 6.00.2900.6072 qfe
shimgvw.dll 6.0.2900.6072 qfe
I tested the hotfixes myself on XP SP3 and it worked as expected.
Applied KB2286198 with /b:sp3qfe switch to force the included files onto the QFE branch:
Applied KB2483185 without any special switch:
The second hotifx has to move BOTH files to the QFE branch because of a dependency in shell32.dll on non-security code changes in shimgw.dll.
I hope that clears things up a bit :)
Hi, Windows xp won't have service pack 4. Does that means that $hf_mig$ can be removed if you only applie windows updates KB?
Years ago i bought an Asus notebook with a hard disk with 8 gb and to free memory an Asus maintenance program scheduler removed the $hf_mig$ folder.
Yep you can reclaim some disk space from a system if you know there'll never be a service pack by deleting that folder.
Got it, thanks. To Force LDR branch on newer OS -