VirtualBox

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

Last change on this file since 106903 was 106398, checked in by vboxsync, 6 weeks ago

bldprogs: Add support for arm64 for VBoxEditCoffLib and VBoxPeSetVersion, bugref:10734

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.5 KB
Line 
1/* $Id: VBoxPeSetVersion.cpp 106398 2024-10-16 20:53:42Z 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_ARM64)
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(10, 0);
283 else if (uNtVersion < MK_VER(10, 0))
284 return Error("Selected version is too old for ARM64: %u.%u", uNtVersion >> 8, uNtVersion & 0xff);
285 cbNewHdrs = sizeof(NtHdrsNew.x64);
286 }
287 else if (NtHdrs.x32.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
288 {
289 if (NtHdrs.x64.FileHeader.SizeOfOptionalHeader != sizeof(NtHdrs.x64.OptionalHeader))
290 return Error("Invalid optional header size: %#x", NtHdrs.x64.FileHeader.SizeOfOptionalHeader);
291 if (NtHdrs.x64.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
292 return Error("Invalid optional header magic: %#x", NtHdrs.x64.OptionalHeader.Magic);
293 if (!uNtVersion)
294 uNtVersion = MK_VER(5, 2);
295 else if (uNtVersion < MK_VER(5, 2))
296 return Error("Selected version is too old for AMD64: %u.%u", uNtVersion >> 8, uNtVersion & 0xff);
297 cbNewHdrs = sizeof(NtHdrsNew.x64);
298 }
299 else if (NtHdrs.x32.FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
300 return Error("Not I386, AMD64 or ARM64 machine: %#x", NtHdrs.x32.FileHeader.Machine);
301 else
302 {
303 if (NtHdrs.x32.FileHeader.SizeOfOptionalHeader != sizeof(NtHdrs.x32.OptionalHeader))
304 return Error("Invalid optional header size: %#x", NtHdrs.x32.FileHeader.SizeOfOptionalHeader);
305 if (NtHdrs.x32.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
306 return Error("Invalid optional header magic: %#x", NtHdrs.x32.OptionalHeader.Magic);
307 if (!uNtVersion)
308 uNtVersion = MK_VER(3, 10);
309 cbNewHdrs = sizeof(NtHdrsNew.x32);
310 }
311
312 /*
313 * Do the header modifications.
314 */
315 memcpy(&NtHdrsNew, &NtHdrs, sizeof(NtHdrsNew));
316 NtHdrsNew.x32.OptionalHeader.MajorOperatingSystemVersion = uNtVersion >> 8;
317 NtHdrsNew.x32.OptionalHeader.MinorOperatingSystemVersion = uNtVersion & 0xff;
318 NtHdrsNew.x32.OptionalHeader.MajorSubsystemVersion = uNtVersion >> 8;
319 NtHdrsNew.x32.OptionalHeader.MinorSubsystemVersion = uNtVersion & 0xff;
320 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MajorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MajorOperatingSystemVersion);
321 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MinorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MinorOperatingSystemVersion);
322 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MajorSubsystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MajorSubsystemVersion);
323 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MinorSubsystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MinorSubsystemVersion);
324
325 if (uNtVersion <= MK_VER(3, 50))
326 {
327 NtHdrsNew.x32.OptionalHeader.MajorOperatingSystemVersion = 1;
328 NtHdrsNew.x32.OptionalHeader.MinorOperatingSystemVersion = 0;
329 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MajorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MajorOperatingSystemVersion);
330 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MinorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MinorOperatingSystemVersion);
331 }
332
333 if (memcmp(&NtHdrsNew, &NtHdrs, sizeof(NtHdrs)))
334 {
335 /** @todo calc checksum. */
336 NtHdrsNew.x32.OptionalHeader.CheckSum = 0;
337 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.MinorOperatingSystemVersion, IMAGE_NT_HEADERS64, OptionalHeader.MinorOperatingSystemVersion);
338
339 if ( NtHdrsNew.x32.OptionalHeader.MajorOperatingSystemVersion != NtHdrs.x32.OptionalHeader.MajorOperatingSystemVersion
340 || NtHdrsNew.x32.OptionalHeader.MinorOperatingSystemVersion != NtHdrs.x32.OptionalHeader.MinorOperatingSystemVersion)
341 Info(1,"OperatingSystemVersion %u.%u -> %u.%u",
342 NtHdrs.x32.OptionalHeader.MajorOperatingSystemVersion, NtHdrs.x32.OptionalHeader.MinorOperatingSystemVersion,
343 NtHdrsNew.x32.OptionalHeader.MajorOperatingSystemVersion, NtHdrsNew.x32.OptionalHeader.MinorOperatingSystemVersion);
344 if ( NtHdrsNew.x32.OptionalHeader.MajorSubsystemVersion != NtHdrs.x32.OptionalHeader.MajorSubsystemVersion
345 || NtHdrsNew.x32.OptionalHeader.MinorSubsystemVersion != NtHdrs.x32.OptionalHeader.MinorSubsystemVersion)
346 Info(1,"SubsystemVersion %u.%u -> %u.%u",
347 NtHdrs.x32.OptionalHeader.MajorSubsystemVersion, NtHdrs.x32.OptionalHeader.MinorSubsystemVersion,
348 NtHdrsNew.x32.OptionalHeader.MajorSubsystemVersion, NtHdrsNew.x32.OptionalHeader.MinorSubsystemVersion);
349
350 if (fseek(pFile, offNtHdrs, SEEK_SET) != 0)
351 return Error("Failed to seek to PE header at %#lx: %s", offNtHdrs, strerror(errno));
352 if (fwrite(&NtHdrsNew, cbNewHdrs, 1, pFile) != 1)
353 return Error("Failed to write PE header at %#lx: %s", offNtHdrs, strerror(errno));
354 cFileModifications++;
355 }
356 else
357 Info(3, "No header changes");
358
359 /*
360 * Make the IAT writable for NT 3.1 and drop the non-cachable flag from .bss.
361 *
362 * The latter is a trick we use to prevent the linker from merging .data and .bss,
363 * because NT 3.1 does not honor Misc.VirtualSize and won't zero padd the .bss part
364 * if it's not zero padded in the file. This seemed simpler than adding zero padding.
365 */
366 if ( uNtVersion <= MK_VER(3, 10)
367 && NtHdrsNew.x32.FileHeader.NumberOfSections > 0)
368 {
369 uint32_t cbShdrs = sizeof(IMAGE_SECTION_HEADER) * NtHdrsNew.x32.FileHeader.NumberOfSections;
370 PIMAGE_SECTION_HEADER paShdrs = (PIMAGE_SECTION_HEADER)calloc(1, cbShdrs);
371 if (!paShdrs)
372 return Error("Out of memory");
373 *ppaShdr = paShdrs;
374
375 unsigned long offShdrs = offNtHdrs
376 + RT_UOFFSETOF_DYN(IMAGE_NT_HEADERS32,
377 OptionalHeader.DataDirectory[NtHdrsNew.x32.OptionalHeader.NumberOfRvaAndSizes]);
378 if (fseek(pFile, offShdrs, SEEK_SET) != 0)
379 return Error("Failed to seek to section headers at %#lx: %s", offShdrs, strerror(errno));
380 if (fread(paShdrs, cbShdrs, 1, pFile) != 1)
381 return Error("Failed to read section headers at %#lx: %s", offShdrs, strerror(errno));
382
383 bool fFoundBss = false;
384 uint32_t uRvaEnd = NtHdrsNew.x32.OptionalHeader.SizeOfImage;
385 uint32_t uRvaIat = NtHdrsNew.x32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size > 0
386 ? NtHdrsNew.x32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress : UINT32_MAX;
387 uint32_t i = NtHdrsNew.x32.FileHeader.NumberOfSections;
388 while (i-- > 0)
389 if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
390 {
391 bool fModified = false;
392 if (uRvaIat >= paShdrs[i].VirtualAddress && uRvaIat < uRvaEnd)
393 {
394 if (!(paShdrs[i].Characteristics & IMAGE_SCN_MEM_WRITE))
395 {
396 paShdrs[i].Characteristics |= IMAGE_SCN_MEM_WRITE;
397 fModified = true;
398 }
399 uRvaIat = UINT32_MAX;
400 }
401
402 if ( !fFoundBss
403 && strcmp((const char *)paShdrs[i].Name, ".bss") == 0)
404 {
405 if (paShdrs[i].Characteristics & IMAGE_SCN_MEM_NOT_CACHED)
406 {
407 paShdrs[i].Characteristics &= ~IMAGE_SCN_MEM_NOT_CACHED;
408 fModified = true;
409 }
410 fFoundBss = true;
411 }
412
413 if (fModified)
414 {
415 unsigned long offShdr = offShdrs + i * sizeof(IMAGE_SECTION_HEADER);
416 if (fseek(pFile, offShdr, SEEK_SET) != 0)
417 return Error("Failed to seek to section header #%u at %#lx: %s", i, offShdr, strerror(errno));
418 if (fwrite(&paShdrs[i], sizeof(IMAGE_SECTION_HEADER), 1, pFile) != 1)
419 return Error("Failed to write %8.8s section header header at %#lx: %s",
420 paShdrs[i].Name, offShdr, strerror(errno));
421 cFileModifications++;
422 if (uRvaIat == UINT32_MAX && fFoundBss)
423 break;
424 }
425
426 /* Advance */
427 uRvaEnd = paShdrs[i].VirtualAddress;
428 }
429 }
430
431 /*
432 * Recalculate the checksum if we changed anything or if it is zero.
433 */
434 if ( g_enmUpdateChecksum == kUpdateCheckSum_Always
435 || ( g_enmUpdateChecksum == kUpdateCheckSum_WhenNeeded
436 && (cFileModifications || NtHdrsNew.x32.OptionalHeader.CheckSum == 0)))
437 return UpdateChecksum(pFile);
438
439 /* Zero the checksum if explicitly requested. */
440 if ( g_enmUpdateChecksum == kUpdateCheckSum_Zero
441 && NtHdrsNew.x32.OptionalHeader.CheckSum != 0)
442 {
443 unsigned long const offCheckSumField = offNtHdrs + RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);
444 if (fseek(pFile, offCheckSumField, SEEK_SET) != 0)
445 return Error("Failed to seek to the CheckSum field in the PE at %#lx: %s", offCheckSumField, strerror(errno));
446
447 NtHdrsNew.x32.OptionalHeader.CheckSum = 0;
448 if (fwrite(&NtHdrsNew.x32.OptionalHeader.CheckSum, sizeof(NtHdrsNew.x32.OptionalHeader.CheckSum), 1, pFile) != 1)
449 return Error("Failed to write the CheckSum field in the PE header at %#lx: %s", offCheckSumField, strerror(errno));
450 }
451
452 return RTEXITCODE_SUCCESS;
453}
454
455
456static int Usage(FILE *pOutput)
457{
458 fprintf(pOutput,
459 "Usage: VBoxPeSetVersion [options] <PE-image>\n"
460 "Options:\n"
461 " -v, --verbose\n"
462 " Increases verbosity.\n"
463 " -q, --quiet\n"
464 " Quiet operation (default).\n"
465 " --nt31, --nt350, --nt351, --nt4, --w2k, --xp, --w2k3, --vista,\n"
466 " --w7, --w8, --w81, --w10\n"
467 " Which version to set. Default: --nt31 (x86), --w2k3 (amd64)\n"
468 " --update-checksum-when-needed, --always-update-checksum,\n"
469 " --never-update-checksum, --zero-checksum:\n"
470 " Checksum updating. Default: --update-checksum-when-needed\n"
471 );
472 return RTEXITCODE_SYNTAX;
473}
474
475
476/** @todo Rewrite this so it can take options and print out error messages. */
477int main(int argc, char **argv)
478{
479 /*
480 * Parse arguments.
481 * This stucks
482 */
483 unsigned uNtVersion = 0;
484 const char *pszFilename = NULL;
485 bool fAcceptOptions = true;
486 for (int i = 1; i < argc; i++)
487 {
488 const char *psz = argv[i];
489 if (fAcceptOptions && *psz == '-')
490 {
491 char ch = psz[1];
492 psz += 2;
493 if (ch == '-')
494 {
495 if (!*psz)
496 {
497 fAcceptOptions = false;
498 continue;
499 }
500
501 if (strcmp(psz, "verbose") == 0)
502 ch = 'v';
503 else if (strcmp(psz, "quiet") == 0)
504 ch = 'q';
505 else if (strcmp(psz, "help") == 0)
506 ch = 'h';
507 else if (strcmp(psz, "version") == 0)
508 ch = 'V';
509 else
510 {
511 if (strcmp(psz, "default") == 0)
512 uNtVersion = 0;
513 else if (strcmp(psz, "nt31") == 0)
514 uNtVersion = MK_VER(3,10);
515 else if (strcmp(psz, "nt350") == 0)
516 uNtVersion = MK_VER(3,50);
517 else if (strcmp(psz, "nt351") == 0)
518 uNtVersion = MK_VER(3,51);
519 else if (strcmp(psz, "nt4") == 0)
520 uNtVersion = MK_VER(4,0);
521 else if (strcmp(psz, "w2k") == 0)
522 uNtVersion = MK_VER(5,0);
523 else if (strcmp(psz, "xp") == 0)
524 uNtVersion = MK_VER(5,1);
525 else if (strcmp(psz, "w2k3") == 0 || strcmp(psz, "xp64") == 0)
526 uNtVersion = MK_VER(5,2);
527 else if (strcmp(psz, "vista") == 0)
528 uNtVersion = MK_VER(6,0);
529 else if (strcmp(psz, "w7") == 0)
530 uNtVersion = MK_VER(6,1);
531 else if (strcmp(psz, "w8") == 0)
532 uNtVersion = MK_VER(6,2);
533 else if (strcmp(psz, "w81") == 0)
534 uNtVersion = MK_VER(6,3);
535 else if (strcmp(psz, "w10") == 0)
536 uNtVersion = MK_VER(10,0);
537 else if (strcmp(psz, "always-update-checksum") == 0)
538 g_enmUpdateChecksum = kUpdateCheckSum_Always;
539 else if (strcmp(psz, "never-update-checksum") == 0)
540 g_enmUpdateChecksum = kUpdateCheckSum_Never;
541 else if (strcmp(psz, "update-checksum-when-needed") == 0)
542 g_enmUpdateChecksum = kUpdateCheckSum_WhenNeeded;
543 else if (strcmp(psz, "zero-checksum") == 0)
544 g_enmUpdateChecksum = kUpdateCheckSum_Zero;
545 else
546 {
547 fprintf(stderr, "VBoxPeSetVersion: syntax error: Unknown option: --%s\n", psz);
548 return RTEXITCODE_SYNTAX;
549 }
550 continue;
551 }
552 psz = " ";
553 }
554 do
555 {
556 switch (ch)
557 {
558 case 'q':
559 g_cVerbosity = 0;
560 break;
561 case 'v':
562 g_cVerbosity++;
563 break;
564 case 'V':
565 printf("2.0\n");
566 return RTEXITCODE_SUCCESS;
567 case 'h':
568 Usage(stdout);
569 return RTEXITCODE_SUCCESS;
570 default:
571 fprintf(stderr, "VBoxPeSetVersion: syntax error: Unknown option: -%c\n", ch ? ch : ' ');
572 return RTEXITCODE_SYNTAX;
573 }
574 } while ((ch = *psz++) != '\0');
575
576 }
577 else if (!pszFilename)
578 pszFilename = psz;
579 else
580 {
581 fprintf(stderr, "VBoxPeSetVersion: syntax error: More than one PE-image specified!\n");
582 return RTEXITCODE_SYNTAX;
583 }
584 }
585
586 if (!pszFilename)
587 {
588 fprintf(stderr, "VBoxPeSetVersion: syntax error: No PE-image specified!\n");
589 return RTEXITCODE_SYNTAX;
590 }
591 g_pszFilename = pszFilename;
592
593 /*
594 * Process the file.
595 */
596 int rcExit;
597 FILE *pFile = fopen(pszFilename, "r+b");
598 if (pFile)
599 {
600 PIMAGE_SECTION_HEADER paShdrs = NULL;
601 rcExit = UpdateFile(pFile, uNtVersion, &paShdrs);
602 if (paShdrs)
603 free(paShdrs);
604 if (fclose(pFile) != 0)
605 rcExit = Error("fclose failed on '%s': %s", pszFilename, strerror(errno));
606 }
607 else
608 rcExit = Error("Failed to open '%s' for updating: %s", pszFilename, strerror(errno));
609 return rcExit;
610}
611
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