Changeset 105153 in vbox
- Timestamp:
- Jul 5, 2024 2:06:36 AM (8 months ago)
- svn:sync-xref-src-repo-rev:
- 163787
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/bldprogs/VBoxPeSetVersion.cpp
r98103 r105153 52 52 static const char *g_pszFilename; 53 53 static unsigned g_cVerbosity = 0; 54 static enum { kUpdateCheckSum_Never, kUpdateCheckSum_WhenNeeded, kUpdateCheckSum_Always, kUpdateCheckSum_Zero } 55 g_enmUpdateChecksum = kUpdateCheckSum_WhenNeeded; 54 56 55 57 … … 80 82 81 83 84 /** 85 * File size. 86 * 87 * @returns file size in bytes. 88 * @returns 0 on failure. 89 * @param pFile File to size. 90 */ 91 static 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 */ 112 static 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 164 static 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 82 238 static int UpdateFile(FILE *pFile, unsigned uNtVersion, PIMAGE_SECTION_HEADER *ppaShdr) 83 239 { 240 unsigned cFileModifications = 0; 241 84 242 /* 85 243 * Locate and read the PE header. … … 182 340 if (fwrite(&NtHdrsNew, cbNewHdrs, 1, pFile) != 1) 183 341 return Error("Failed to write PE header at %#lx: %s", offNtHdrs, strerror(errno)); 184 } 342 cFileModifications++; 343 } 344 else 345 Info(3, "No header changes"); 185 346 186 347 /* … … 246 407 return Error("Failed to write %8.8s section header header at %#lx: %s", 247 408 paShdrs[i].Name, offShdr, strerror(errno)); 409 cFileModifications++; 248 410 if (uRvaIat == UINT32_MAX && fFoundBss) 249 411 break; … … 253 415 uRvaEnd = paShdrs[i].VirtualAddress; 254 416 } 255 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)); 256 438 } 257 439 … … 271 453 " --nt31, --nt350, --nt351, --nt4, --w2k, --xp, --w2k3, --vista,\n" 272 454 " --w7, --w8, --w81, --w10\n" 273 " Which version to set. Default: --nt31\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" 274 459 ); 275 460 return RTEXITCODE_SYNTAX; … … 336 521 else if (strcmp(psz, "w10") == 0) 337 522 uNtVersion = MK_VER(10,0); 523 else if (strcmp(psz, "always-update-checksum") == 0) 524 g_enmUpdateChecksum = kUpdateCheckSum_Always; 525 else if (strcmp(psz, "never-update-checksum") == 0) 526 g_enmUpdateChecksum = kUpdateCheckSum_Never; 527 else if (strcmp(psz, "update-checksum-when-needed") == 0) 528 g_enmUpdateChecksum = kUpdateCheckSum_WhenNeeded; 529 else if (strcmp(psz, "zero-checksum") == 0) 530 g_enmUpdateChecksum = kUpdateCheckSum_Zero; 338 531 else 339 532 {
Note:
See TracChangeset
for help on using the changeset viewer.