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.