MUI files under the hood

Have you ever copied after Vista a system file like notepad.exe onto the desktop and tried to execute it? Have you ever tried after Vista to modify the resources of a system file like regedit.exe? It’s most likely that neither of the two was a successful operation.

This will be very brief because the topic is very limited and because of my lack of time: bear with me. 🙂

If you try to copy, for instance, notepad.exe onto the desktop and run it in a debugger you will notice that it fails in its initialization routine when trying to load its accelerators. You take a look at the HINSTANCE passed to LoadAccelerators and notice that it’s NULL. You open notepad.exe in a resource viewer and notice that it doesn’t contain accelerator resources. Thus, you realize that the global instance is associated to some external resource as well. Go back to the system folder where you took the system executable and you’ll notice language directories such as “en-US”. Just copy the one which identifies the language of your system to the same directory of notepad.exe. You’ll notice that now notepad.exe runs correctly.

Vista introduced the separation between binary and language dependent resources to allow a single Windows image to contain more than just one language. You can obtain more information about the development aspects on MSDN.

The language directory contains files with names such as “notepad.exe.mui”, one for every file they provide resources for (including dlls). These are very basic PE files which contain only a resource directory and are loaded into the address space of the process as they are.

These files are associated to the main file in two ways:

1) By name: just rename the notepad to test.exe and the MUI file accordingly and it still works.
2) Via resource, as we’ll see.

If you open both notepad.exe and its MUI file with a resource viewer, you’ll see they both contain a “MUI” resource. What this data contains can be roughly understood from the MSDN or SDK:

//
// Information about a MUI file, used as input/output in GetFileMUIInfo
// All offsets are relative to start of the structure. Offsets with value 0 mean empty field.
//

typedef struct _FILEMUIINFO {
    DWORD       dwSize;                 // Size of the structure including buffer size [in]
    DWORD       dwVersion;              // Version of the structure [in]
    DWORD       dwFileType;             // Type of the file [out]
    BYTE        pChecksum[16];          // Checksum of the file [out]
    BYTE        pServiceChecksum[16];   // Checksum of the file [out]
    DWORD       dwLanguageNameOffset;   // Language name of the file [out]
    DWORD       dwTypeIDMainSize;       // Number of TypeIDs in main module [out]
    DWORD       dwTypeIDMainOffset;     // Array of TypeIDs (DWORD) in main module [out]
    DWORD       dwTypeNameMainOffset;   // Multistring array of TypeNames in main module [out]
    DWORD       dwTypeIDMUISize;        // Number of TypeIDs in MUI module [out]
    DWORD       dwTypeIDMUIOffset;      // Array of TypeIDs (DWORD) in MUI module [out]
    DWORD       dwTypeNameMUIOffset;    // Multistring array of TypeNames in MUI module [out]
    BYTE        abBuffer[8];             // Buffer for extra data [in] (Size 4 is for padding)
} FILEMUIINFO, *PFILEMUIINFO;

You’ll find this structure in WinNls.h. However, this structure is for GetFileMUIInfo, it doesn’t match the physical data.

Offset     0  1  2  3  4  5  6  7    8  9  A  B  C  D  E  F     Ascii   

00000000  CD FE CD FE C8 00 00 00   00 00 01 00 00 00 00 00     ................
00000010  12 00 00 00 00 00 00 00   00 00 00 00 EC 6C C4 C4     .............l..
00000020  FF 7C C9 CC F8 03 C7 B3   8C 8A 67 51 11 72 DC 72     .|........gQ.r.r
00000030  80 73 67 9E AB 20 3D FC   AA D4 2F 04 00 00 00 00     .sg...=.../.....
00000040  00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00     ................
00000050  00 00 00 00 88 00 00 00   0E 00 00 00 98 00 00 00     ................
00000060  20 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00     ................
00000070  00 00 00 00 B8 00 00 00   0C 00 00 00 00 00 00 00     ................
00000080  00 00 00 00 00 00 00 00   4D 00 55 00 49 00 00 00     ........M.U.I...
00000090  00 00 00 00 00 00 00 00   02 00 00 00 03 00 00 00     ................
000000A0  04 00 00 00 05 00 00 00   06 00 00 00 09 00 00 00     ................
000000B0  0E 00 00 00 10 00 00 00   65 00 6E 00 2D 00 55 00     ........e.n.-.U.
000000C0  53 00 00 00 00 00 00 00                               S.......        

The first DWORD is clearly a signature. If you change it, the MUI is invalidated and notepad won’t run. It is followed by another DWORD describing the size of the structure (including the signature).

Offset     0  1  2  3  4  5  6  7    8  9  A  B  C  D  E  F     Ascii   

00000010                                        EC 6C C4 C4                 .l..
00000020  FF 7C C9 CC F8 03 C7 B3   8C 8A 67 51 11 72 DC 72     .|........gQ.r.r
00000030  80 73 67 9E AB 20 3D FC   AA D4 2F 04                 .sg...=.../.    

These are the two checksums:

  BYTE  pChecksum[16];
  BYTE  pServiceChecksum[16];

These two checksums are probably in the same order of the structure. They both match the ones contained in the MUI file and if you change the second one, the application won’t run.

There are no other association criteria: I changed both the main file and the MUI file (by using a real DLL and just replacing the resource directory with the one of the MUI file) and it still worked.

About the second matter mentioned in the beginning: modification of resources. If you try to add/replace an icon to/in notepad.exe you will most likely not succeed. This is because as mentioned in the MSDN:

There are some restrictions on resource updates in files that contain Resource Configuration(RC Config) data: LN files and the associated .mui files. Details on which types of resources are allowed to be updated in these files are in the Remarks section for the UpdateResource function.

Basically, UpdateResource doesn’t work if the PE file contains a MUI resource. Now, prepare for an incredibly complicated and technically challenging hack to overcome this limitation… Ready? Rename the “MUI” resource to “CUI” or whatever, now try again and it works. Restore the MUI resource name and all is fine.

The new build of the CFF Explorer handles this automatically for your comfort.

This limitation probably broke most of the resource editors for Win32. Smart.