VirtualBox

source: vbox/trunk/src/bldprogs/VBoxPeSetVersion.cpp@ 70368

Last change on this file since 70368 was 70368, checked in by vboxsync, 7 years ago

VBoxPeSetVersion.cpp: options and stuff

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1/* $Id: VBoxPeSetVersion.cpp 70368 2017-12-27 17:54:10Z vboxsync $ */
2/** @file
3 * IPRT - Change the OS and SubSystem version to value suitable for NT v3.1.
4 *
5 * Also make sure the IAT is writable, since NT v3.1 expects this. These are
6 * tricks necessary to make binaries created by newer Visual C++ linkers work
7 * on ancient NT version like W2K, NT4 and NT 3.x.
8 */
9
10/*
11 * Copyright (C) 2012-2017 Oracle Corporation
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22
23/*********************************************************************************************************************************
24* Header Files *
25*********************************************************************************************************************************/
26#include <iprt/formats/mz.h>
27#include <iprt/formats/pecoff.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32
33/*********************************************************************************************************************************
34* Defined Constants And Macros *
35*********************************************************************************************************************************/
36#define MK_VER(a_uHi, a_uLo) ( ((a_uHi) << 8) | (a_uLo))
37
38
39/*********************************************************************************************************************************
40* Global Variables *
41*********************************************************************************************************************************/
42static const char *g_pszFilename;
43static unsigned g_cVerbosity = 0;
44
45
46static int Error(const char *pszFormat, ...)
47{
48 va_list va;
49 va_start(va, pszFormat);
50 char szTmp[1024];
51 _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
52 va_end(va);
53 fprintf(stderr, "VBoxPeSetVersion: %s: error: %s\n", g_pszFilename, szTmp);
54 return RTEXITCODE_FAILURE;
55}
56
57
58static void Info(unsigned iLevel, const char *pszFormat, ...)
59{
60 if (iLevel <= g_cVerbosity)
61 {
62 va_list va;
63 va_start(va, pszFormat);
64 char szTmp[1024];
65 _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
66 va_end(va);
67 fprintf(stderr, "VBoxPeSetVersion: %s: info: %s\n", g_pszFilename, szTmp);
68 }
69}
70
71
72static int UpdateFile(FILE *pFile, unsigned uNtVersion, PIMAGE_SECTION_HEADER *ppaShdr)
73{
74 /*
75 * Locate and read the PE header.
76 */
77 unsigned long offNtHdrs;
78 {
79 IMAGE_DOS_HEADER MzHdr;
80 if (fread(&MzHdr, sizeof(MzHdr), 1, pFile) != 1)
81 return Error("Failed to read MZ header: %s", strerror(errno));
82 if (MzHdr.e_magic != IMAGE_DOS_SIGNATURE)
83 return Error("Invalid MZ magic: %#x", MzHdr.e_magic);
84 offNtHdrs = MzHdr.e_lfanew;
85 }
86
87 if (fseek(pFile, offNtHdrs, SEEK_SET) != 0)
88 return Error("Failed to seek to PE header at %#lx: %s", offNtHdrs, strerror(errno));
89 IMAGE_NT_HEADERS32 NtHdrs;
90 if (fread(&NtHdrs, sizeof(NtHdrs), 1, pFile) != 1)
91 return Error("Failed to read PE header at %#lx: %s", offNtHdrs, strerror(errno));
92
93 /*
94 * Validate it a little bit.
95 */
96 if (NtHdrs.Signature != IMAGE_NT_SIGNATURE)
97 return Error("Invalid PE signature: %#x", NtHdrs.Signature);
98 if (NtHdrs.FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
99 return Error("Not I386 machine: %#x", NtHdrs.FileHeader.Machine);
100 if (NtHdrs.FileHeader.SizeOfOptionalHeader != sizeof(NtHdrs.OptionalHeader))
101 return Error("Invalid optional header size: %#x", NtHdrs.FileHeader.SizeOfOptionalHeader);
102 if (NtHdrs.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
103 return Error("Invalid optional header magic: %#x", NtHdrs.OptionalHeader.Magic);
104
105 /*
106 * Do the header modifications.
107 */
108 IMAGE_NT_HEADERS32 NtHdrsNew = NtHdrs;
109 NtHdrsNew.OptionalHeader.MajorOperatingSystemVersion = uNtVersion >> 8;
110 NtHdrsNew.OptionalHeader.MinorOperatingSystemVersion = uNtVersion & 0xff;
111 NtHdrsNew.OptionalHeader.MajorSubsystemVersion = uNtVersion >> 8;
112 NtHdrsNew.OptionalHeader.MinorSubsystemVersion = uNtVersion & 0xff;
113
114 if (uNtVersion <= MK_VER(3, 50))
115 {
116 NtHdrsNew.OptionalHeader.MajorOperatingSystemVersion = 1;
117 NtHdrsNew.OptionalHeader.MinorOperatingSystemVersion = 0;
118 }
119
120 if (memcmp(&NtHdrsNew, &NtHdrs, sizeof(NtHdrs)))
121 {
122 /** @todo calc checksum. */
123 NtHdrsNew.OptionalHeader.CheckSum = 0;
124
125 if ( NtHdrsNew.OptionalHeader.MajorOperatingSystemVersion != NtHdrs.OptionalHeader.MajorOperatingSystemVersion
126 || NtHdrsNew.OptionalHeader.MinorOperatingSystemVersion != NtHdrs.OptionalHeader.MinorOperatingSystemVersion)
127 Info(1,"OperatingSystemVersion %u.%u -> %u.%u",
128 NtHdrs.OptionalHeader.MajorOperatingSystemVersion, NtHdrs.OptionalHeader.MinorOperatingSystemVersion,
129 NtHdrsNew.OptionalHeader.MajorOperatingSystemVersion, NtHdrsNew.OptionalHeader.MinorOperatingSystemVersion);
130 if ( NtHdrsNew.OptionalHeader.MajorSubsystemVersion != NtHdrs.OptionalHeader.MajorSubsystemVersion
131 || NtHdrsNew.OptionalHeader.MinorSubsystemVersion != NtHdrs.OptionalHeader.MinorSubsystemVersion)
132 Info(1,"SubsystemVersion %u.%u -> %u.%u",
133 NtHdrs.OptionalHeader.MajorSubsystemVersion, NtHdrs.OptionalHeader.MinorSubsystemVersion,
134 NtHdrsNew.OptionalHeader.MajorSubsystemVersion, NtHdrsNew.OptionalHeader.MinorSubsystemVersion);
135
136 if (fseek(pFile, offNtHdrs, SEEK_SET) != 0)
137 return Error("Failed to seek to PE header at %#lx: %s", offNtHdrs, strerror(errno));
138 if (fwrite(&NtHdrsNew, sizeof(NtHdrsNew), 1, pFile) != 1)
139 return Error("Failed to write PE header at %#lx: %s", offNtHdrs, strerror(errno));
140 }
141
142 /*
143 * Make the IAT writable for NT 3.1.
144 */
145 if ( uNtVersion <= MK_VER(3, 10)
146 && NtHdrsNew.FileHeader.NumberOfSections > 0
147 && NtHdrsNew.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size > 0)
148 {
149 uint32_t cbShdrs = sizeof(IMAGE_SECTION_HEADER) * NtHdrsNew.FileHeader.NumberOfSections;
150 PIMAGE_SECTION_HEADER paShdrs = (PIMAGE_SECTION_HEADER)calloc(1, cbShdrs);
151 if (!paShdrs)
152 return Error("Out of memory");
153 *ppaShdr = paShdrs;
154
155 unsigned long offShdrs = offNtHdrs
156 + RT_UOFFSETOF(IMAGE_NT_HEADERS32,
157 OptionalHeader.DataDirectory[NtHdrsNew.OptionalHeader.NumberOfRvaAndSizes]);
158 if (fseek(pFile, offShdrs, SEEK_SET) != 0)
159 return Error("Failed to seek to section headers at %#lx: %s", offShdrs, strerror(errno));
160 if (fread(paShdrs, cbShdrs, 1, pFile) != 1)
161 return Error("Failed to read section headers at %#lx: %s", offShdrs, strerror(errno));
162
163 uint32_t const uRvaIat = NtHdrsNew.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
164 uint32_t uRvaEnd = NtHdrsNew.OptionalHeader.SizeOfImage;
165 uint32_t i = NtHdrsNew.FileHeader.NumberOfSections;
166 while (i-- > 0)
167 if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
168 {
169 uint32_t uRva = paShdrs[i].VirtualAddress;
170 if (uRvaIat >= uRva && uRvaIat < uRvaEnd)
171 {
172 if (!(paShdrs[i].Characteristics & IMAGE_SCN_MEM_WRITE))
173 {
174 paShdrs[i].Characteristics |= IMAGE_SCN_MEM_WRITE;
175 unsigned long offShdr = offShdrs + i * sizeof(IMAGE_SECTION_HEADER);
176 if (fseek(pFile, offShdr, SEEK_SET) != 0)
177 return Error("Failed to seek to section header #%u at %#lx: %s", i, offShdr, strerror(errno));
178 if (fwrite(&paShdrs[i], sizeof(IMAGE_SECTION_HEADER), 1, pFile) != 1)
179 return Error("Failed to write IAT section header header at %#lx: %s", offShdr, strerror(errno));
180 }
181 break;
182 }
183 uRvaEnd = uRva;
184 }
185
186 }
187
188 return RTEXITCODE_SUCCESS;
189}
190
191
192static int Usage(FILE *pOutput)
193{
194 fprintf(pOutput,
195 "Usage: VBoxPeSetVersion [options] <PE-image>\n"
196 "Options:\n"
197 " -v, --verbose\n"
198 " Increases verbosity.\n"
199 " -q, --quiet\n"
200 " Quiet operation (default).\n"
201 " --nt31, --nt350, --nt351, --nt4, --w2k, --xp, --w2k3, --vista,\n"
202 " --w7, --w8, --w81, --w10\n"
203 " Which version to set. Default is --nt31.\n"
204 " --nt4\n"
205 " Set versions to NT 4.0\n"
206 " --nt4\n"
207 " Set versions to NT 4.0\n"
208 );
209 return RTEXITCODE_SYNTAX;
210}
211
212
213/** @todo Rewrite this so it can take options and print out error messages. */
214int main(int argc, char **argv)
215{
216 /*
217 * Parse arguments.
218 * This stucks
219 */
220 unsigned uNtVersion = 31;
221 const char *pszFilename = NULL;
222 bool fAcceptOptions = true;
223 for (int i = 1; i < argc; i++)
224 {
225 const char *psz = argv[i];
226 if (fAcceptOptions && *psz == '-')
227 {
228 char ch = psz[1];
229 psz += 2;
230 if (ch == '-')
231 {
232 if (!*psz)
233 {
234 fAcceptOptions = false;
235 continue;
236 }
237
238 if (strcmp(psz, "verbose") == 0)
239 ch = 'v';
240 else if (strcmp(psz, "quiet") == 0)
241 ch = 'q';
242 else if (strcmp(psz, "help") == 0)
243 ch = 'h';
244 else if (strcmp(psz, "version") == 0)
245 ch = 'V';
246 else
247 {
248 if (strcmp(psz, "nt31") == 0)
249 uNtVersion = MK_VER(3, 10);
250 else if (strcmp(psz, "nt350") == 0)
251 uNtVersion = MK_VER(3, 50);
252 else if (strcmp(psz, "nt351") == 0)
253 uNtVersion = MK_VER(3, 51);
254 else if (strcmp(psz, "nt4") == 0)
255 uNtVersion = MK_VER(4, 0);
256 else if (strcmp(psz, "w2k") == 0)
257 uNtVersion = MK_VER(5,0);
258 else if (strcmp(psz, "xp") == 0)
259 uNtVersion = MK_VER(5,1);
260 else if (strcmp(psz, "w2k3") == 0)
261 uNtVersion = MK_VER(5,2);
262 else if (strcmp(psz, "vista") == 0)
263 uNtVersion = MK_VER(6,0);
264 else if (strcmp(psz, "w7") == 0)
265 uNtVersion = MK_VER(6,1);
266 else if (strcmp(psz, "w8") == 0)
267 uNtVersion = MK_VER(6,2);
268 else if (strcmp(psz, "w81") == 0)
269 uNtVersion = MK_VER(6,3);
270 else if (strcmp(psz, "w10") == 0)
271 uNtVersion = MK_VER(10,0);
272 else
273 {
274 fprintf(stderr, "VBoxPeSetVersion: syntax error: Unknown option: --%s\n", psz);
275 return RTEXITCODE_SYNTAX;
276 }
277 continue;
278 }
279 psz = " ";
280 }
281 do
282 {
283 switch (ch)
284 {
285 case 'q':
286 g_cVerbosity = 0;
287 break;
288 case 'v':
289 g_cVerbosity++;
290 break;
291 case 'V':
292 printf("2.0\n");
293 return RTEXITCODE_SUCCESS;
294 case 'h':
295 Usage(stdout);
296 return RTEXITCODE_SUCCESS;
297 default:
298 fprintf(stderr, "VBoxPeSetVersion: syntax error: Unknown option: -%c\n", ch ? ch : ' ');
299 return RTEXITCODE_SYNTAX;
300 }
301 } while ((ch = *psz++) != '\0');
302
303 }
304 else if (!pszFilename)
305 pszFilename = psz;
306 else
307 {
308 fprintf(stderr, "VBoxPeSetVersion: syntax error: More than one PE-image specified!\n");
309 return RTEXITCODE_SYNTAX;
310 }
311 }
312
313 if (!pszFilename)
314 {
315 fprintf(stderr, "VBoxPeSetVersion: syntax error: No PE-image specified!\n");
316 return RTEXITCODE_SYNTAX;
317 }
318 g_pszFilename = pszFilename;
319
320 /*
321 * Process the file.
322 */
323 int rcExit;
324 FILE *pFile = fopen(pszFilename, "r+b");
325 if (pFile)
326 {
327 PIMAGE_SECTION_HEADER paShdrs = NULL;
328 rcExit = UpdateFile(pFile, uNtVersion, &paShdrs);
329 if (paShdrs)
330 free(paShdrs);
331 if (fclose(pFile) != 0)
332 rcExit = Error("fclose failed on '%s': %s", pszFilename, strerror(errno));
333 }
334 else
335 rcExit = Error("Failed to open '%s' for updating: %s", pszFilename, strerror(errno));
336 return rcExit;
337}
338
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette