Last time we looked at the format of 16-bit version resources. The 32-bit version is nearly identical, except that everything is now in Unicode. Each node is stored in the following structure (in pseudo-C):
struct VERSIONNODE { WORD cbNode; WORD cbData; WORD wType; WCHAR wszName[]; BYTE rgbPadding1[]; // DWORD alignment union { BYTE rgbData[cbData]; WCHAR wszValue[cbData / sizeof(WCHAR)]; }; BYTE rgbPadding2[]; // DWORD alignment VERSIONNODE rgvnChildren[]; };
In words, each version node begins with a 16-bit value
describing the size of the nodes in bytes (including its children),
followed by a 16-bit value that specifies how much data
(either binary or text) are associated with the node.
The wType
is zero if the node data is binary
or one if the node data is a string.
Other values of wType
are reserved for future use.
The rest is the same as before:
A null-terminated key name, padding for DWORD
alignment,
the node data,
more padding, and then the child nodes.
The only change beyond the conversion to Unicode is the
introduction of the wType
field.
This field is necessary so that the system knows whether to
convert the node data from Unicode to ANSI when somebody calls
the VerQueryStringA
.
If it’s binary data, then no conversion is done;
if it’s string data, then the string is converted.
We illustrate the 32-bit resource format by looking at the resources
for the 32-bit shell32.dll
.
0000 98 03 34 00 00 00 56 00-53 00 5F 00 56 00 45 00 ..4...V.S._.V.E. 0010 52 00 53 00 49 00 4F 00-4E 00 5F 00 49 00 4E 00 R.S.I.O.N._.I.N. 0020 46 00 4F 00 00 00 00 00-BD 04 EF FE 00 00 01 00 F.O............. 0030 00 00 06 00 35 0B 54 0B-00 00 06 00 35 0B 54 0b ....5.T.....5.T. 0040 3F 00 00 00 00 00 00 00-04 00 04 00 02 00 00 00 ?............... 0050 00 00 00 00 00 00 00 00-00 00 00 00 F6 02 00 00 ................ 0060 01 00 53 00 74 00 72 00-69 00 6E 00 67 00 46 00 ..S.t.r.i.n.g.F. 0070 69 00 6C 00 65 00 49 00-6E 00 66 00 6F 00 00 00 i.l.e.I.n.f.o... 0080 D2 02 00 00 01 00 30 00-34 00 30 00 39 00 30 00 ......0.4.0.9.0. 0090 34 00 42 00 30 00 00 00-4C 00 2C 00 01 00 43 00 4.B.0...L.....C. 00A0 6F 00 6D 00 70 00 61 00-6E 00 79 00 4E 00 61 00 o.m.p.a.n.y.N.a. 00B0 6D 00 65 00 00 00 00 00-4D 00 69 00 63 00 72 00 m.e.....M.i.c.r. 00C0 6F 00 73 00 6F 00 66 00-74 00 20 00 43 00 6F 00 o.s.o.f.t. .C.o. 00D0 72 00 70 00 6F 00 72 00-61 00 74 00 69 00 6F 00 r.p.o.r.a.t.i.o. 00E0 6E 00 00 00 5A 00 32 00-01 00 46 00 69 00 6C 00 n...Z.....F.i.l. 00F0 65 00 44 00 65 00 73 00-63 00 72 00 69 00 70 00 e.D.e.s.c.r.i.p. 0100 74 00 69 00 6F 00 6E 00-00 00 00 00 57 00 69 00 t.i.o.n.....W.i. 0110 6E 00 64 00 6F 00 77 00-73 00 20 00 53 00 68 00 n.d.o.w.s. .S.h. 0120 65 00 6C 00 6C 00 20 00-43 00 6F 00 6D 00 6D 00 e.l.l. .C.o.m.m. 0130 6F 00 6E 00 20 00 44 00-6C 00 6C 00 00 00 00 00 o.n. .D.l.l..... 0140 74 00 54 00 01 00 46 00-69 00 6C 00 65 00 56 00 t.*...F.i.l.e.V. 0150 65 00 72 00 73 00 69 00-6F 00 6E 00 00 00 00 00 e.r.s.i.o.n..... 0160 36 00 2E 00 30 00 30 00-2E 00 32 00 39 00 30 00 6...0.0...2.9.0. 0170 30 00 2E 00 32 00 38 00-36 00 39 00 20 00 28 00 0...2.8.6.9. .(. 0180 78 00 70 00 73 00 70 00-5F 00 73 00 70 00 32 00 x.p.s.p._.s.p.2. 0190 5F 00 67 00 64 00 72 00-2E 00 30 00 36 00 30 00 _.g.d.r...0.6.0. 01A0 33 00 31 00 36 00 2D 00-31 00 35 00 31 00 32 00 3.1.6.-.1.5.1.2. 01B0 29 00 00 00 30 00 10 00-01 00 49 00 6E 00 74 00 )...0.....I.n.t. 01C0 65 00 72 00 6E 00 61 00-6C 00 4E 00 61 00 6D 00 e.r.n.a.l.N.a.m. 01D0 65 00 00 00 53 00 48 00-45 00 4C 00 4C 00 33 00 e...S.H.E.L.L.3. 01E0 32 00 00 00 80 00 5C 00-01 00 4C 00 65 00 67 00 2.........L.e.g. 01F0 61 00 6C 00 43 00 6F 00-70 00 79 00 72 00 69 00 a.l.C.o.p.y.r.i. 0200 67 00 68 00 74 00 00 00-A9 00 20 00 4D 00 69 00 g.h.t..... .M.i. 0210 63 00 72 00 6F 00 73 00-6F 00 66 00 74 00 20 00 c.r.o.s.o.f.t. . 0220 43 00 6F 00 72 00 70 00-6F 00 72 00 61 00 74 00 C.o.r.p.o.r.a.t. 0230 69 00 6F 00 6E 00 2E 00-20 00 41 00 6C 00 6C 00 i.o.n... .A.l.l. 0240 20 00 72 00 69 00 67 00-68 00 74 00 73 00 20 00 .r.i.g.h.t.s. . 0250 72 00 65 00 73 00 65 00-72 00 76 00 65 00 64 00 r.e.s.e.r.v.e.d. 0260 2E 00 00 00 40 00 18 00-01 00 4F 00 72 00 69 00 ....@.....O.r.i. 0270 67 00 69 00 6E 00 61 00-6C 00 46 00 69 00 6C 00 g.i.n.a.l.F.i.l. 0280 65 00 6E 00 61 00 6D 00-65 00 00 00 53 00 48 00 e.n.a.m.e...S.H. 0290 45 00 4C 00 4C 00 33 00-32 00 2E 00 44 00 4C 00 E.L.L.3.2...D.L. 02A0 4C 00 00 00 6A 00 25 00-01 00 50 00 72 00 6F 00 L...j.%...P.r.o. 02B0 64 00 75 00 63 00 74 00-4E 00 61 00 6D 00 65 00 d.u.c.t.N.a.m.e. 02C0 00 00 00 00 4D 00 69 00-63 00 72 00 6F 00 73 00 ....M.i.c.r.o.s. 02D0 6F 00 66 00 74 00 AE 00-20 00 57 00 69 00 6E 00 o.f.t... .W.i.n. 02E0 64 00 6F 00 77 00 73 00-AE 00 20 00 4F 00 70 00 d.o.w.s... .O.p. 02F0 65 00 72 00 61 00 74 00-69 00 6E 00 67 00 20 00 e.r.a.t.i.n.g. . 0300 53 00 79 00 73 00 74 00-65 00 6D 00 00 00 00 00 S.y.s.t.e.m..... 0310 42 00 1E 00 01 00 50 00-72 00 6F 00 64 00 75 00 B.....P.r.o.d.u. 0320 63 00 74 00 56 00 65 00-72 00 73 00 69 00 6F 00 c.t.V.e.r.s.i.o. 0330 6E 00 00 00 36 00 2E 00-30 00 30 00 2E 00 32 00 n...6...0.0...2. 0340 39 00 30 00 30 00 2E 00-32 00 38 00 36 00 39 00 9.0.0...2.8.6.9. 0350 00 00 00 00 44 00 00 00-01 00 56 00 61 00 72 00 ....D.....V.a.r. 0360 46 00 69 00 6C 00 65 00-49 00 6E 00 66 00 6F 00 F.i.l.e.I.n.f.o. 0370 00 00 00 00 24 00 04 00-00 00 54 00 72 00 61 00 ....$.....T.r.a. 0380 6E 00 73 00 6C 00 61 00-74 00 69 00 6F 00 6E 00 n.s.l.a.t.i.o.n. 0390 00 00 00 00 09 04 B0 04 ........
As always, we start with the root node.
0000 98 03 // cbNode (node ends at 0x0000 + 0x0398 = 0x0398) 0002 34 00 // cbData = sizeof(VS_FIXEDFILEINFO) 0004 00 00 // wType = 0 (binary data) 0006 56 00 53 00 5F 00 56 00 45 00 52 00 53 00 49 00 4F 00 4E 00 5F 00 49 00 4E 00 46 00 4F 00 00 00 // L"VS_VERSION_INFO" + null terminator 0026 00 00 // padding to restore alignment 0028 BD 04 EF FE // dwSignature 002C 00 00 01 00 // dwStrucVersion 0030 00 00 06 00 // dwFileVersionMS = 6.0 0034 35 0B 54 0B // dwFileVersionLS = 2900.2869 0038 00 00 06 00 // dwProductVersionMS = 6.0 003C 35 0B 54 0B // dwProductVersionLS = 2900.2869 0040 3F 00 00 00 // dwFileFlagsMask 0044 00 00 00 00 // dwFileFlags 0048 04 00 04 00 // dwFileOS = VOS_NT_WINDOWS32 004C 02 00 00 00 // dwFileType = VFT_DLL 0050 00 00 00 00 // dwFileSubtype 0054 00 00 00 00 // dwFileDateMS 0058 00 00 00 00 // dwFileDateLS 005C // no padding needed
As with the 16-bit version resource, the root node is always
a binary node consisting of a VS_FIXEDFILEINFO
.
After the root node come its children.
005C F6 02 // cbNode (node ends at 0x005C + 0x02F6 = 0x0352) 005E 00 00 // cbData (no data) 0060 01 00 // wType = 1 (string data) 0062 53 00 74 00 72 00 69 00 6E 00 67 00 46 00 69 00 6C 00 65 00 49 00 6E 00 66 00 6F 00 00 00 // L"StringFileInfo" + null terminator 007E 00 00 // padding to restore alignment
The StringFileInfo
contains no data, so the fact
that it’s string data is irrelevant.
As before, the children of the StringFileInfo
are
language nodes.
0080 D2 02 // cbNode (node ends at 0x0080 + 0x02D2 = 0x0352) 0082 00 00 // cbData (no data) 0084 01 00 // wType = 1 (string data) 0086 30 00 34 00 30 00 39 00 30 00 34 00 42 00 30 00 00 00 // L"040904B0" + null terminator 0098 // no padding needed
The children of the language node are the strings that make up the bulk of the version information.
0098 4C 00 // cbNode (node ends at 0x0088 + 0x004C = 0x00D40) 009A 2C 00 // cbData 009C 01 00 // wType = 1 (string data) 009E 43 00 6F 00 6D 00 70 00 61 00 6E 00 79 00 4E 00 61 00 6D 00 65 00 00 00 // L"CompanyName" + null terminator 00B6 00 00 // padding to restore alignment 00B8 4D 00 69 00 63 00 72 00 6F 00 73 00 6F 00 66 00 74 00 20 00 43 00 6F 00 72 00 70 00 6F 00 72 00 61 00 74 00 69 00 6F 00 6E 00 00 00 // L"Microsoft Corporation" + null terminator 00E4 // no padding needed
Notice that for string types, the cbData
includes the null terminator.
00E4 5A 00 // cbNode (node ends at 0x00E4 + 0x005A = 0x013E) 00E6 32 00 // cbData 00E8 01 00 // wTypes = 1 (string data) 00EA 46 00 69 00 6C 00 65 00 44 00 65 00 73 00 63 00 72 00 69 00 70 00 74 00 69 00 6F 00 6E 00 00 00 // L"FileDescription" + null terminator 010A 00 00 // padding to restore alignment 010C 57 00 69 00 6E 00 64 00 6F 00 77 00 73 00 20 00 53 00 68 00 65 00 6C 00 6C 00 20 00 43 00 6F 00 6D 00 6D 00 6F 00 6E 00 20 00 44 00 6C 00 6C 00 00 00 // L"Windows Shell Common Dll" + null terminator 013E 00 00 // padding to restore alignment 0140 74 00 // cbNode (node ends at 0x0140 + 0x0074 = 0x01B4) 0142 54 00 // cbData 0144 01 00 // wType = 1 (string data) 0146 46 00 69 00 6C 00 65 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 00 00 // L"FileVersion" + null terminator 015E 00 00 // padding to restore alignment 0160 36 00 2E 00 30 00 30 00 2E 00 32 00 39 00 30 00 30 00 2E 00 32 00 38 00 36 00 39 00 20 00 28 00 78 00 70 00 73 00 70 00 5F 00 73 00 70 00 32 00 5F 00 67 00 64 00 72 00 2E 00 30 00 36 00 30 00 33 00 31 00 36 00 2D 00 31 00 35 00 31 00 32 00 29 00 00 00 // L"6.00.2900.2869 (xpsp_sp2_gdr.060316-1512)" // + null terminator 01B4 // no padding needed 01B4 30 00 // cbNode (node ends at 0x01B4 + 0x0030 = 0x01E4) 01B6 10 00 // cbData 01B8 01 00 // wType = 1 (string data) 01BA 49 00 6E 00 74 00 65 00 72 00 6E 00 61 00 6C 00 4E 00 61 00 6D 00 65 00 00 00 // L"InternalName" + null terminator 01D4 // no padding needed 01D4 53 00 48 00 45 00 4C 00 4C 00 33 00 32 00 00 00 // L"SHELL32" + null terminator 01E4 // no padding needed 01E4 80 00 // cbNode (node ends at 0x01E4 + 0x0080 = 0x0264) 01E6 5C 00 // cbData 01E8 01 00 // wType = 1 (string data) 01EA 4C 00 65 00 67 00 61 00 6C 00 43 00 6F 00 70 00 79 00 72 00 69 00 67 00 68 00 74 00 00 00 // L"LegalCopyright" + null terminator 0208 // no padding needed 0208 A9 00 20 00 4D 00 69 00 63 00 72 00 6F 00 73 00 6F 00 66 00 74 00 20 00 43 00 6F 00 72 00 70 00 6F 00 72 00 61 00 74 00 69 00 6F 00 6E 00 2E 00 20 00 41 00 6C 00 6C 00 20 00 72 00 69 00 67 00 68 00 74 00 73 00 20 00 72 00 65 00 73 00 65 00 72 00 76 00 65 00 64 00 2E 00 00 00 // L"© Microsoft Corporation. " // L"All rights reserved." + null terminator 0264 // no padding needed 0264 40 00 // cbNode (node ends at 0x0264 + 0x0040 = 0x02A4) 0266 18 00 // cbData 0268 01 00 // wType = 1 (string data) 026A 4F 00 72 00 69 00 67 00 69 00 6E 00 61 00 6C 00 46 00 69 00 6C 00 65 00 6E 00 61 00 6D 00 65 00 00 00 // L"OriginalFilename" + null terminator 028C // no padding needed 028C 53 00 48 00 45 00 4C 00 4C 00 33 00 32 00 2E 00 44 00 4C 00 4C 00 00 00 // L"SHELL32.DLL" + null terminator 02A4 // no padding needed 02A4 6A 00 // cbNode (node ends at 0x02A4 + 0x006A = 0x030E) 02A6 25 00 01 00 50 00 72 00 6F 00 64 00 75 00 63 00 74 00 4E 00 61 00 6D 00 65 00 00 00 // L"ProductName" + null terminator 02C2 00 00 // padding to restore alignment 02C4 4D 00 69 00 63 00 72 00 6F 00 73 00 6F 00 66 00 74 00 AE 00 20 00 57 00 69 00 6E 00 64 00 6F 00 77 00 73 00 AE 00 20 00 4F 00 70 00 65 00 72 00 61 00 74 00 69 00 6E 00 67 00 20 00 53 00 79 00 73 00 74 00 65 00 6D 00 00 00 // L"Microsoft® Windows® " // L"Operating System" + null terminator 030E 00 00 // padding to restore alignment 0310 42 00 // cbNode (node ends at 0x0310 + 0x0042 = 0x0352) 0312 1E 00 // cbData 0314 01 00 // wType = 1 (string data) 0316 50 00 72 00 6F 00 64 00 75 00 63 00 74 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 00 00 // L"ProductVersion" + null terminator 0334 // no padding needed 0334 36 00 2E 00 30 00 30 00 2E 00 32 00 39 00 30 00 30 00 2E 00 32 00 38 00 36 00 39 00 00 00 // L"6.00.2900.2869" + null terminator 0352 00 00 // padding to restore alignment
At offset 0x0352
, we’ve reached the end of the
ProductVersion
node, the language node, and
the StringFileInfo
node.
The next node is therefore a sibilng to StringFileInfo
.
0354 44 00 // cbNode (node ends at 0x0354 + 0x0044 = 0x0394) 0356 00 00 // cbData 0358 01 00 // wType = 1 (string data) 035A 56 00 61 00 72 00 46 00 69 00 6C 00 65 00 49 00 6E 00 66 00 6F 00 00 00 // L"VarFileInfo" + null terminator 0372 00 00 // padding to restore alignment
Since we haven’t exhausted the VarFileInfo
node,
the next node is a child.
0374 24 00 // cbNode (node ends at 0x0374 + 0x0024 = 0x0394) 0376 04 00 // cbData 0378 00 00 // wType = 0 (binary data) 037A 54 00 72 00 61 00 6E 00 73 00 6C 00 61 00 74 00 69 00 6F 00 6E 00 00 00 // L"Translation" + null terminator 0392 00 00 // padding to restore alignment 0394 09 04 B0 04 // 0x0409 = US English // 0x04B0 = 1200 = Unicode UCS-2 little-endian 0398 // no padding needed
We have reached the end of the Translation
node,
the VarFileInfo
node, and the root node.
Our parsing of the version data is complete and resulted in the
following version resource:
FILEVERSION 3,0,2900,2869 PRODUCTVERSION 3,0,2900,2869 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE VFT_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" BEGIN VALUE "CompanyName", "Microsoft Corporation" VALUE "FileDescription", Windows Shell Common Dll" VALUE "FileVersion", "6.00.2900.2869 (xpsp_sp2_gdr.060316-1512)" VALUE "InternalName", "SHELL32" VALUE "LegalCopyright", "\251 Microsoft Corporation. All rights reserved." VALUE "OriginalFilename", "SHELL32.DLL" VALUE "ProductName", "Microsoft\256 Windows\256 Operating System" VALUE "ProductVersion", "6.00.2900.2869" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x04B0 END END
There you have it, the format of 32-bit version resources. Future versions of Windows may extend this format, but that’s what it looks like up through Windows Vista.
Now, after all that byte-mashing, I have to confess that I’ve
been lying to you.
What you saw was not the actual version resource in
shell32.dll
.
We’ll discuss what’s really going on next time.
0 comments