VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 4 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.8 KB
Line 
1/* $Id: VBoxPeSetVersion.cpp 106061 2024-09-16 14:03:52Z 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-2024 Oracle and/or its affiliates.
12 *
13 * This file is part of VirtualBox base platform packages, as
14 * available from https://www.virtualbox.org.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation, in version 3 of the
19 * License.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see <https://www.gnu.org/licenses>.
28 *
29 * SPDX-License-Identifier: GPL-3.0-only
30 */
31
32
33/*********************************************************************************************************************************
34* Header Files *
35*********************************************************************************************************************************/
36#include <iprt/formats/mz.h>
37#include <iprt/formats/pecoff.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46#define MK_VER(a_uHi, a_uLo) ( ((a_uHi) << 8) | (a_uLo))
47
48
49/*********************************************************************************************************************************
50* Global Variables *
51*********************************************************************************************************************************/
52static const char *g_pszFilename;
53static unsigned g_cVerbosity = 0;
54static enum { kUpdateCheckSum_Never, kUpdateCheckSum_WhenNeeded, kUpdateCheckSum_Always, kUpdateCheckSum_Zero }
55 g_enmUpdateChecksum = kUpdateCheckSum_WhenNeeded;
56
57
58static int Error(const char *pszFormat, ...)
59{
60 va_list va;
61 va_start(va, pszFormat);
62 char szTmp[1024];
63 _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
64 va_end(va);
65 fprintf(stderr, "VBoxPeSetVersion: %s: error: %s\n", g_pszFilename, szTmp);
66 return RTEXITCODE_FAILURE;
67}
68
69
70static void Info(unsigned iLevel, const char *pszFormat, ...)
71{
72 if (iLevel <= g_cVerbosity)
73 {
74 va_list va;
75 va_start(va, pszFormat);
76 char szTmp[1024];
77 _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
78 va_end(va);
79 fprintf(stderr, "VBoxPeSetVersion: %s: info: %s\n", g_pszFilename, szTmp);
80 }
81}
82
83
84/**
85 * File size.
86 *
87 * @returns file size in bytes.
88 * @returns 0 on failure.
89 * @param pFile File to size.
90 */
91static size_t fsize(FILE *pFile)
92{
93 long cbFile;
94 off_t Pos = ftell(pFile);
95 if ( Pos >= 0
96 && !fseek(pFile, 0, SEEK_END))
97 {
98 cbFile = ftell(pFile);
99 if ( cbFile >= 0
100 && !fseek(pFile, 0, SEEK_SET))
101 return cbFile;
102 }
103 return 0;
104}
105
106
107/**
108 * Calculates a raw PE-style checksum on a plain buffer.
109 *
110 * ASSUMES pvBuf is dword aligned.
111 */
112static uint16_t CalcRawPeChecksum(void const *pvBuf, size_t cb, uint32_t uChksum)
113{
114 /*
115 * Work thru the memory in 64 bits at a time.
116 * ASSUMES well aligned input.
117 */
118 uint64_t uBigSum = uChksum;
119 uint64_t const *pu64 = (uint64_t const *)pvBuf;
120 size_t cQWords = cb / 8;
121 while (cQWords-- > 0)
122 {
123 /* We emulate add with carry here. */
124 uint64_t uTmp = uBigSum + *pu64++;
125 uBigSum = uTmp >= uBigSum ? uTmp : uTmp + 1;
126 }
127
128 /*
129 * Zeropadd any remaining bytes before adding them.
130 */
131 if (cb & 7)
132 {
133 uint8_t const *pb = (uint8_t const *)pu64;
134 uint64_t uQWord = 0;
135 switch (cb & 7)
136 {
137 case 7: uQWord |= (uint64_t)pb[6] << 48; RT_FALL_THRU();
138 case 6: uQWord |= (uint64_t)pb[5] << 40; RT_FALL_THRU();
139 case 5: uQWord |= (uint64_t)pb[4] << 32; RT_FALL_THRU();
140 case 4: uQWord |= (uint64_t)pb[3] << 24; RT_FALL_THRU();
141 case 3: uQWord |= (uint64_t)pb[2] << 16; RT_FALL_THRU();
142 case 2: uQWord |= (uint64_t)pb[1] << 8; RT_FALL_THRU();
143 case 1: uQWord |= (uint64_t)pb[0]; break;
144 }
145
146 uint64_t uTmp = uBigSum + uQWord;
147 uBigSum = uTmp >= uBigSum ? uTmp : uTmp + 1;
148 }
149
150 /*
151 * Convert the 64-bit checksum to a 16-bit one.
152 */
153 uChksum = (uBigSum & 0xffffU)
154 + ((uBigSum >> 16) & 0xffffU)
155 + ((uBigSum >> 32) & 0xffffU)
156 + ((uBigSum >> 48) & 0xffffU);
157 uChksum = (uChksum & 0xffffU)
158 + (uChksum >> 16);
159 if (uChksum > 0xffffU) Error("Checksum IPE#1");
160 return uChksum & 0xffffU;
161}
162
163
164static int UpdateChecksum(FILE *pFile)
165{
166 /*
167 * Read the whole file into memory.
168 */
169 size_t const cbFile = fsize(pFile);
170 if (!cbFile)
171 return Error("Failed to determine file size: %s", strerror(errno));
172 uint8_t * const pbFile = (uint8_t *)malloc(cbFile + 4);
173 if (!pbFile)
174 return Error("Failed to allocate %#lx bytes for checksum calculations", (unsigned long)(cbFile + 4U));
175 memset(pbFile, 0, cbFile + 4);
176
177 int rcExit;
178 size_t cItemsRead = fread(pbFile, cbFile, 1, pFile);
179 if (cItemsRead == 1)
180 {
181 /*
182 * Locate the NT headers as we need the CheckSum field in order to update it.
183 * It has the same location in 32-bit and 64-bit images.
184 */
185 IMAGE_DOS_HEADER const * const pMzHdr = (IMAGE_DOS_HEADER const *)pbFile;
186 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum, IMAGE_NT_HEADERS64, OptionalHeader.CheckSum);
187 IMAGE_NT_HEADERS32 * const pNtHdrs
188 = (IMAGE_NT_HEADERS32 *)&pbFile[pMzHdr->e_magic == IMAGE_DOS_SIGNATURE ? pMzHdr->e_lfanew : 0];
189 if ((uintptr_t)&pNtHdrs->OptionalHeader.DataDirectory[0] - (uintptr_t)pbFile < cbFile)
190 {
191 if ( pNtHdrs->Signature == IMAGE_NT_SIGNATURE
192 && ( pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
193 || pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC))
194 {
195 /*
196 * Set the checksum field to zero to avoid having to do tedious
197 * adjustments of the raw checksum. Then calculate the raw check sum.
198 */
199 pNtHdrs->OptionalHeader.CheckSum = 0;
200 uint32_t uChksum = CalcRawPeChecksum(pbFile, RT_ALIGN_Z(cbFile, 2), 0);
201
202 /* Finalize the checksum by adding the image size to it. */
203 uChksum += (uint32_t)cbFile;
204 pNtHdrs->OptionalHeader.CheckSum = uChksum;
205
206 /*
207 * Write back the checksum to the file.
208 */
209 size_t const offChecksumField = (uintptr_t)&pNtHdrs->OptionalHeader.CheckSum - (uintptr_t)pbFile;
210
211 if (fseek(pFile, (long)offChecksumField, SEEK_SET) == 0)
212 {
213 if (fwrite(&pNtHdrs->OptionalHeader.CheckSum, sizeof(pNtHdrs->OptionalHeader.CheckSum), 1, pFile) == 1)
214 {
215 Info(1, "Checksum: %#x", uChksum);
216 rcExit = RTEXITCODE_SUCCESS;
217 }
218 else
219 rcExit = Error("Checksum write failed");
220 }
221 else
222 rcExit = Error("Failed seeking to %#lx for checksum write", (long)offChecksumField);
223 }
224 else
225 rcExit = Error("PE header not found");
226 }
227 else
228 rcExit = Error("NT headers not within file when checksumming");
229 }
230 else
231 rcExit = Error("Failed read in file (%#lx bytes) for checksum calculations", (unsigned long)(cbFile + 4U));
232
233 free(pbFile);
234 return rcExit;
235}
236
237
238static int UpdateFile(FILE *pFile, unsigned uNtVersion, PIMAGE_SECTION_HEADER *ppaShdr)
239{
240 unsigned cFileModifications = 0;
241
242 /*
243 * Locate and read the PE header.
244 *
245 * Note! We'll be reading the 64-bit size even for 32-bit since the difference
246 * is 16 bytes, which is less than a section header, so it won't be a problem.
247 */
248 unsigned long offNtHdrs;
249 {
250 IMAGE_DOS_HEADER MzHdr;
251 if (fread(&MzHdr, sizeof(MzHdr), 1, pFile) != 1)
252 return Error("Failed to read MZ header: %s", strerror(errno));
253 if (MzHdr.e_magic != IMAGE_DOS_SIGNATURE)
254 return Error("Invalid MZ magic: %#x", MzHdr.e_magic);
255 offNtHdrs = MzHdr.e_lfanew;
256 }
257
258 if (fseek(pFile, offNtHdrs, SEEK_SET) != 0)
259 return Error("Failed to seek to PE header at %#lx: %s", offNtHdrs, strerror(errno));
260 union
261 {
262 IMAGE_NT_HEADERS32 x32;
263 IMAGE_NT_HEADERS64 x64;
264 } NtHdrs,
265 NtHdrsNew;
266 if (fread(&NtHdrs, sizeof(NtHdrs), 1, pFile) != 1)
267 return Error("Failed to read PE header at %#lx: %s", offNtHdrs, strerror(errno));
268
269 /*
270 * Validate it a little bit.
271 */
272 if (NtHdrs.x32.Signature != IMAGE_NT_SIGNATURE)
273 return Error("Invalid PE signature: %#x", NtHdrs.x32.Signature);
274 uint32_t cbNewHdrs;
275 if (NtHdrs.x32.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
276 {
277 if (NtHdrs.x64.FileHeader.SizeOfOptionalHeader != sizeof(NtHdrs.x64.OptionalHeader))
278 return Error("Invalid optional header size: %#x", NtHdrs.x64.FileHeader.SizeOfOptionalHeader);
279 if (NtHdrs.x64.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
280 return Error("Invalid optional header magic: %#x", NtHdrs.x64.OptionalHeader.Magic);
281 if (!uNtVersion)
282 uNtVersion = MK_VER(5, 2);
283 else if (uNtVersion < MK_VER(5, 2))
284 return Error("Selected version is too old for AMD64: %u.%u", uNtVersion >> 8, uNtVersion & 0xff);
285 cbNewHdrs = sizeof(NtHdrsNew.x64);
286 }
287 else if (NtHdrs.x32.FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
288 return Error("Not I386 or AMD64 machine: %#x", NtHdrs.x32.FileHeader.Machine);
289 else
290 {
291 if (NtHdrs.x32.FileHeader.SizeOfOptionalHeader != sizeof(NtHdrs.x32.OptionalHeader))
292 return Error("Invalid optional header size: %#x", NtHdrs.x32.FileHeader.SizeOfOptionalHeader);
293 if (NtHdrs.x32.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
294 return Error("Invalid optional header magic: %#x", NtHdrs.x32.OptionalHeader.Magic);
295 if (!uNtVersion)
296 uNtVersion = MK_VER(3, 10);
297 cbNewHdrs = sizeof(NtHdrsNew.x32);
298 }
299
300 /*
301 * Do the header modifications.
302 */
303 memcpy(&NtHdrsNew, &NtHdrs, sizeof(NtHdrsNew));
304 NtHdrsNew.x32.OptionalHeader.MajorOperatingSystemVersion = uNtVersion >> 8;
305 NtHdrsNew.x32.OptionalHeader.MinorOperatingSystemVersion = uNtVersion & 0xff;
306 NtHdrsNew.x32.OptionalHeader.MajorSubsystemVersion = uNtVersion >> 8;
307 NtHdrsNew.x32.OptionalHeader.MinorSubsystemVersion = uNtVersion & 0xff;
308 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MajorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MajorOperatingSystemVersion);
309 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MinorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MinorOperatingSystemVersion);
310 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MajorSubsystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MajorSubsystemVersion);
311 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MinorSubsystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MinorSubsystemVersion);
312
313 if (uNtVersion <= MK_VER(3, 50))
314 {
315 NtHdrsNew.x32.OptionalHeader.MajorOperatingSystemVersion = 1;
316 NtHdrsNew.x32.OptionalHeader.MinorOperatingSystemVersion = 0;
317 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MajorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MajorOperatingSystemVersion);
318 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MinorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MinorOperatingSystemVersion);
319 }
320
321 if (memcmp(&NtHdrsNew, &NtHdrs, sizeof(NtHdrs)))
322 {
323 /** @todo calc checksum. */
324 NtHdrsNew.x32.OptionalHeader.CheckSum = 0;
325 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MinorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MinorOperatingSystemVersion);
326
327 if ( NtHdrsNew.x32.OptionalHeader.MajorOperatingSystemVersion != NtHdrs.x32.OptionalHeader.MajorOperatingSystemVersion
328 || NtHdrsNew.x32.OptionalHeader.MinorOperatingSystemVersion != NtHdrs.x32.OptionalHeader.MinorOperatingSystemVersion)
329 Info(1,"OperatingSystemVersion %u.%u -> %u.%u",
330 NtHdrs.x32.OptionalHeader.MajorOperatingSystemVersion, NtHdrs.x32.OptionalHeader.MinorOperatingSystemVersion,
331 NtHdrsNew.x32.OptionalHeader.MajorOperatingSystemVersion, NtHdrsNew.x32.OptionalHeader.MinorOperatingSystemVersion);
332 if ( NtHdrsNew.x32.OptionalHeader.MajorSubsystemVersion != NtHdrs.x32.OptionalHeader.MajorSubsystemVersion
333 || NtHdrsNew.x32.OptionalHeader.MinorSubsystemVersion != NtHdrs.x32.OptionalHeader.MinorSubsystemVersion)
334 Info(1,"SubsystemVersion %u.%u -> %u.%u",
335 NtHdrs.x32.OptionalHeader.MajorSubsystemVersion, NtHdrs.x32.OptionalHeader.MinorSubsystemVersion,
336 NtHdrsNew.x32.OptionalHeader.MajorSubsystemVersion, NtHdrsNew.x32.OptionalHeader.MinorSubsystemVersion);
337
338 if (fseek(pFile, offNtHdrs, SEEK_SET) != 0)
339 return Error("Failed to seek to PE header at %#lx: %s", offNtHdrs, strerror(errno));
340 if (fwrite(&NtHdrsNew, cbNewHdrs, 1, pFile) != 1)
341 return Error("Failed to write PE header at %#lx: %s", offNtHdrs, strerror(errno));
342 cFileModifications++;
343 }
344 else
345 Info(3, "No header changes");
346
347 /*
348 * Make the IAT writable for NT 3.1 and drop the non-cachable flag from .bss.
349 *
350 * The latter is a trick we use to prevent the linker from merging .data and .bss,
351 * because NT 3.1 does not honor Misc.VirtualSize and won't zero padd the .bss part
352 * if it's not zero padded in the file. This seemed simpler than adding zero padding.
353 */
354 if ( uNtVersion <= MK_VER(3, 10)
355 && NtHdrsNew.x32.FileHeader.NumberOfSections > 0)
356 {
357 uint32_t cbShdrs = sizeof(IMAGE_SECTION_HEADER) * NtHdrsNew.x32.FileHeader.NumberOfSections;
358 PIMAGE_SECTION_HEADER paShdrs = (PIMAGE_SECTION_HEADER)calloc(1, cbShdrs);
359 if (!paShdrs)
360 return Error("Out of memory");
361 *ppaShdr = paShdrs;
362
363 unsigned long offShdrs = offNtHdrs
364 + RT_UOFFSETOF_DYN(IMAGE_NT_HEADERS32,
365 OptionalHeader.DataDirectory[NtHdrsNew.x32.OptionalHeader.NumberOfRvaAndSizes]);
366 if (fseek(pFile, offShdrs, SEEK_SET) != 0)
367 return Error("Failed to seek to section headers at %#lx: %s", offShdrs, strerror(errno));
368 if (fread(paShdrs, cbShdrs, 1, pFile) != 1)
369 return Error("Failed to read section headers at %#lx: %s", offShdrs, strerror(errno));
370
371 bool fFoundBss = false;
372 uint32_t uRvaEnd = NtHdrsNew.x32.OptionalHeader.SizeOfImage;
373 uint32_t uRvaIat = NtHdrsNew.x32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size > 0
374 ? NtHdrsNew.x32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress : UINT32_MAX;
375 uint32_t i = NtHdrsNew.x32.FileHeader.NumberOfSections;
376 while (i-- > 0)
377 if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
378 {
379 bool fModified = false;
380 if (uRvaIat >= paShdrs[i].VirtualAddress && uRvaIat < uRvaEnd)
381 {
382 if (!(paShdrs[i].Characteristics & IMAGE_SCN_MEM_WRITE))
383 {
384 paShdrs[i].Characteristics |= IMAGE_SCN_MEM_WRITE;
385 fModified = true;
386 }
387 uRvaIat = UINT32_MAX;
388 }
389
390 if ( !fFoundBss
391 && strcmp((const char *)paShdrs[i].Name, ".bss") == 0)
392 {
393 if (paShdrs[i].Characteristics & IMAGE_SCN_MEM_NOT_CACHED)
394 {
395 paShdrs[i].Characteristics &= ~IMAGE_SCN_MEM_NOT_CACHED;
396 fModified = true;
397 }
398 fFoundBss = true;
399 }
400
401 if (fModified)
402 {
403 unsigned long offShdr = offShdrs + i * sizeof(IMAGE_SECTION_HEADER);
404 if (fseek(pFile, offShdr, SEEK_SET) != 0)
405 return Error("Failed to seek to section header #%u at %#lx: %s", i, offShdr, strerror(errno));
406 if (fwrite(&paShdrs[i], sizeof(IMAGE_SECTION_HEADER), 1, pFile) != 1)
407 return Error("Failed to write %8.8s section header header at %#lx: %s",
408 paShdrs[i].Name, offShdr, strerror(errno));
409 cFileModifications++;
410 if (uRvaIat == UINT32_MAX && fFoundBss)
411 break;
412 }
413
414 /* Advance */
415 uRvaEnd = paShdrs[i].VirtualAddress;
416 }
417 }
418
419 /*
420 * Recalculate the checksum if we changed anything or if it is zero.
421 */
422 if ( g_enmUpdateChecksum == kUpdateCheckSum_Always
423 || ( g_enmUpdateChecksum == kUpdateCheckSum_WhenNeeded
424 && (cFileModifications || NtHdrsNew.x32.OptionalHeader.CheckSum == 0)))
425 return UpdateChecksum(pFile);
426
427 /* Zero the checksum if explicitly requested. */
428 if ( g_enmUpdateChecksum == kUpdateCheckSum_Zero
429 && NtHdrsNew.x32.OptionalHeader.CheckSum != 0)
430 {
431 unsigned long const offCheckSumField = offNtHdrs + RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);
432 if (fseek(pFile, offCheckSumField, SEEK_SET) != 0)
433 return Error("Failed to seek to the CheckSum field in the PE at %#lx: %s", offCheckSumField, strerror(errno));
434
435 NtHdrsNew.x32.OptionalHeader.CheckSum = 0;
436 if (fwrite(&NtHdrsNew.x32.OptionalHeader.CheckSum, sizeof(NtHdrsNew.x32.OptionalHeader.CheckSum), 1, pFile) != 1)
437 return Error("Failed to write the CheckSum field in the PE header at %#lx: %s", offCheckSumField, strerror(errno));
438 }
439
440 return RTEXITCODE_SUCCESS;
441}
442
443
444static int Usage(FILE *pOutput)
445{
446 fprintf(pOutput,
447 "Usage: VBoxPeSetVersion [options] <PE-image>\n"
448 "Options:\n"
449 " -v, --verbose\n"
450 " Increases verbosity.\n"
451 " -q, --quiet\n"
452 " Quiet operation (default).\n"
453 " --nt31, --nt350, --nt351, --nt4, --w2k, --xp, --w2k3, --vista,\n"
454 " --w7, --w8, --w81, --w10\n"
455 " Which version to set. Default: --nt31 (x86), --w2k3 (amd64)\n"
456 " --update-checksum-when-needed, --always-update-checksum,\n"
457 " --never-update-checksum, --zero-checksum:\n"
458 " Checksum updating. Default: --update-checksum-when-needed\n"
459 );
460 return RTEXITCODE_SYNTAX;
461}
462
463
464/** @todo Rewrite this so it can take options and print out error messages. */
465int main(int argc, char **argv)
466{
467 /*
468 * Parse arguments.
469 * This stucks
470 */
471 unsigned uNtVersion = 0;
472 const char *pszFilename = NULL;
473 bool fAcceptOptions = true;
474 for (int i = 1; i < argc; i++)
475 {
476 const char *psz = argv[i];
477 if (fAcceptOptions && *psz == '-')
478 {
479 char ch = psz[1];
480 psz += 2;
481 if (ch == '-')
482 {
483 if (!*psz)
484 {
485 fAcceptOptions = false;
486 continue;
487 }
488
489 if (strcmp(psz, "verbose") == 0)
490 ch = 'v';
491 else if (strcmp(psz, "quiet") == 0)
492 ch = 'q';
493 else if (strcmp(psz, "help") == 0)
494 ch = 'h';
495 else if (strcmp(psz, "version") == 0)
496 ch = 'V';
497 else
498 {
499 if (strcmp(psz, "default") == 0)
500 uNtVersion = 0;
501 else if (strcmp(psz, "nt31") == 0)
502 uNtVersion = MK_VER(3,10);
503 else if (strcmp(psz, "nt350") == 0)
504 uNtVersion = MK_VER(3,50);
505 else if (strcmp(psz, "nt351") == 0)
506 uNtVersion = MK_VER(3,51);
507 else if (strcmp(psz, "nt4") == 0)
508 uNtVersion = MK_VER(4,0);
509 else if (strcmp(psz, "w2k") == 0)
510 uNtVersion = MK_VER(5,0);
511 else if (strcmp(psz, "xp") == 0)
512 uNtVersion = MK_VER(5,1);
513 else if (strcmp(psz, "w2k3") == 0 || strcmp(psz, "xp64") == 0)
514 uNtVersion = MK_VER(5,2);
515 else if (strcmp(psz, "vista") == 0)
516 uNtVersion = MK_VER(6,0);
517 else if (strcmp(psz, "w7") == 0)
518 uNtVersion = MK_VER(6,1);
519 else if (strcmp(psz, "w8") == 0)
520 uNtVersion = MK_VER(6,2);
521 else if (strcmp(psz, "w81") == 0)
522 uNtVersion = MK_VER(6,3);
523 else if (strcmp(psz, "w10") == 0)
524 uNtVersion = MK_VER(10,0);
525 else if (strcmp(psz, "always-update-checksum") == 0)
526 g_enmUpdateChecksum = kUpdateCheckSum_Always;
527 else if (strcmp(psz, "never-update-checksum") == 0)
528 g_enmUpdateChecksum = kUpdateCheckSum_Never;
529 else if (strcmp(psz, "update-checksum-when-needed") == 0)
530 g_enmUpdateChecksum = kUpdateCheckSum_WhenNeeded;
531 else if (strcmp(psz, "zero-checksum") == 0)
532 g_enmUpdateChecksum = kUpdateCheckSum_Zero;
533 else
534 {
535 fprintf(stderr, "VBoxPeSetVersion: syntax error: Unknown option: --%s\n", psz);
536 return RTEXITCODE_SYNTAX;
537 }
538 continue;
539 }
540 psz = " ";
541 }
542 do
543 {
544 switch (ch)
545 {
546 case 'q':
547 g_cVerbosity = 0;
548 break;
549 case 'v':
550 g_cVerbosity++;
551 break;
552 case 'V':
553 printf("2.0\n");
554 return RTEXITCODE_SUCCESS;
555 case 'h':
556 Usage(stdout);
557 return RTEXITCODE_SUCCESS;
558 default:
559 fprintf(stderr, "VBoxPeSetVersion: syntax error: Unknown option: -%c\n", ch ? ch : ' ');
560 return RTEXITCODE_SYNTAX;
561 }
562 } while ((ch = *psz++) != '\0');
563
564 }
565 else if (!pszFilename)
566 pszFilename = psz;
567 else
568 {
569 fprintf(stderr, "VBoxPeSetVersion: syntax error: More than one PE-image specified!\n");
570 return RTEXITCODE_SYNTAX;
571 }
572 }
573
574 if (!pszFilename)
575 {
576 fprintf(stderr, "VBoxPeSetVersion: syntax error: No PE-image specified!\n");
577 return RTEXITCODE_SYNTAX;
578 }
579 g_pszFilename = pszFilename;
580
581 /*
582 * Process the file.
583 */
584 int rcExit;
585 FILE *pFile = fopen(pszFilename, "r+b");
586 if (pFile)
587 {
588 PIMAGE_SECTION_HEADER paShdrs = NULL;
589 rcExit = UpdateFile(pFile, uNtVersion, &paShdrs);
590 if (paShdrs)
591 free(paShdrs);
592 if (fclose(pFile) != 0)
593 rcExit = Error("fclose failed on '%s': %s", pszFilename, strerror(errno));
594 }
595 else
596 rcExit = Error("Failed to open '%s' for updating: %s", pszFilename, strerror(errno));
597 return rcExit;
598}
599
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