VirtualBox

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

Last change on this file since 105694 was 105160, checked in by vboxsync, 5 months ago

*.kmk,bldprogs/VBoxPeSetVersion: Created a unit for setting the PE version so it can more easily be controlled per target. This is helpful with the two GINA targets in the additions, since using NT 3.51 instead of NT 3.1 as minimum avoids trouble with some AV heuristics.

  • 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 105160 2024-07-05 12:02:04Z 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-2023 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