403 lines
9 KiB
C
403 lines
9 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1993 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
checksum.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements a function for computing the checksum of an
|
||
|
image file. It will also compute the checksum of other files as well.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
David N. Cutler 21-Mar-1993
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include "checksum.h"
|
||
|
#include "rlmsgtbl.h"
|
||
|
|
||
|
void QuitA( int, LPSTR, LPSTR);
|
||
|
void QuitW( int, LPWSTR, LPWSTR);
|
||
|
|
||
|
// Helper routines
|
||
|
|
||
|
static PIMAGE_NT_HEADERS ImageNtHeader( PVOID Base);
|
||
|
static USHORT ChkSum( DWORD PartialSum,
|
||
|
PUSHORT Source,
|
||
|
DWORD Length);
|
||
|
|
||
|
static PIMAGE_NT_HEADERS
|
||
|
CheckSumMappedFile (
|
||
|
LPVOID pBaseAddress,
|
||
|
DWORD dwFileLength,
|
||
|
LPDWORD pdwHeaderSum,
|
||
|
LPDWORD pdwCheckSum
|
||
|
);
|
||
|
|
||
|
static BOOL
|
||
|
TouchFileTimes (
|
||
|
HANDLE hFileHandle,
|
||
|
LPSYSTEMTIME lpSystemTime
|
||
|
);
|
||
|
|
||
|
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function returns the address of the NT Header.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Base - Supplies the base of the image.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns the address of the NT Header.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
static PIMAGE_NT_HEADERS ImageNtHeader( PVOID pBase)
|
||
|
{
|
||
|
PIMAGE_NT_HEADERS pNtHeaders = NULL;
|
||
|
|
||
|
if ( pBase != NULL && pBase != (PVOID)-1 )
|
||
|
{
|
||
|
if ( ((PIMAGE_DOS_HEADER)pBase)->e_magic == IMAGE_DOS_SIGNATURE )
|
||
|
{
|
||
|
pNtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)pBase + ((PIMAGE_DOS_HEADER)pBase)->e_lfanew);
|
||
|
|
||
|
if ( pNtHeaders->Signature != IMAGE_NT_SIGNATURE )
|
||
|
{
|
||
|
pNtHeaders = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return( pNtHeaders);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Compute a partial checksum on a portion of an imagefile.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PartialSum - Supplies the initial checksum value.
|
||
|
|
||
|
Sources - Supplies a pointer to the array of words for which the
|
||
|
checksum is computed.
|
||
|
|
||
|
Length - Supplies the length of the array in words.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The computed checksum value is returned as the function value.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
static USHORT ChkSum(
|
||
|
|
||
|
ULONG PartialSum,
|
||
|
PUSHORT Source,
|
||
|
ULONG Length)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Compute the word wise checksum allowing carries to occur into the
|
||
|
// high order half of the checksum longword.
|
||
|
//
|
||
|
|
||
|
while (Length--) {
|
||
|
PartialSum += *Source++;
|
||
|
PartialSum = (PartialSum >> 16) + (PartialSum & 0xffff);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fold final carry into a single word result and return the resultant
|
||
|
// value.
|
||
|
//
|
||
|
|
||
|
return (USHORT)(((PartialSum >> 16) + PartialSum) & 0xffff);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This functions computes the checksum of a mapped file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
BaseAddress - Supplies a pointer to the base of the mapped file.
|
||
|
|
||
|
FileLength - Supplies the length of the file in bytes.
|
||
|
|
||
|
HeaderSum - Suppllies a pointer to a variable that receives the checksum
|
||
|
from the image file, or zero if the file is not an image file.
|
||
|
|
||
|
CheckSum - Supplies a pointer to the variable that receive the computed
|
||
|
checksum.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
static PIMAGE_NT_HEADERS CheckSumMappedFile(
|
||
|
|
||
|
LPVOID pBaseAddress,
|
||
|
DWORD dwFileLength,
|
||
|
LPDWORD pdwHeaderSum,
|
||
|
LPDWORD pdwCheckSum)
|
||
|
{
|
||
|
USHORT usPartialSum;
|
||
|
PUSHORT pusAdjustSum;
|
||
|
PIMAGE_NT_HEADERS pNtHeaders = NULL;
|
||
|
|
||
|
//
|
||
|
// Compute the checksum of the file and zero the header checksum value.
|
||
|
//
|
||
|
|
||
|
*pdwHeaderSum = 0;
|
||
|
usPartialSum = ChkSum(0, (PUSHORT)pBaseAddress, (dwFileLength + 1) >> 1);
|
||
|
|
||
|
//
|
||
|
// If the file is an image file, then subtract the two checksum words
|
||
|
// in the optional header from the computed checksum before adding
|
||
|
// the file length, and set the value of the header checksum.
|
||
|
//
|
||
|
|
||
|
pNtHeaders = ImageNtHeader( pBaseAddress);
|
||
|
|
||
|
if ( (pNtHeaders != NULL) && (pNtHeaders != pBaseAddress) )
|
||
|
{
|
||
|
*pdwHeaderSum = pNtHeaders->OptionalHeader.CheckSum;
|
||
|
pusAdjustSum = (PUSHORT)(&pNtHeaders->OptionalHeader.CheckSum);
|
||
|
usPartialSum -= (usPartialSum < pusAdjustSum[0]);
|
||
|
usPartialSum -= pusAdjustSum[0];
|
||
|
usPartialSum -= (usPartialSum < pusAdjustSum[1]);
|
||
|
usPartialSum -= pusAdjustSum[1];
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Compute the final checksum value as the sum of the paritial checksum
|
||
|
// and the file length.
|
||
|
//
|
||
|
|
||
|
*pdwCheckSum = (DWORD)usPartialSum + dwFileLength;
|
||
|
return( pNtHeaders);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This functions maps the specified file and computes the checksum of
|
||
|
the file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Filename - Supplies a pointer to the name of the file whose checksum
|
||
|
is computed.
|
||
|
|
||
|
HeaderSum - Supplies a pointer to a variable that receives the checksum
|
||
|
from the image file, or zero if the file is not an image file.
|
||
|
|
||
|
CheckSum - Supplies a pointer to the variable that receive the computed
|
||
|
checksum.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
0 if successful, else error number.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
DWORD MapFileAndFixCheckSumW( PWSTR pszwFilename)
|
||
|
{
|
||
|
HANDLE hFileHandle = NULL;
|
||
|
HANDLE hMappingHandle = NULL;
|
||
|
LPVOID pBaseAddress = NULL;
|
||
|
DWORD dwFileLength = 0;
|
||
|
DWORD dwHeaderSum = 0;
|
||
|
DWORD dwCheckSum = 0;
|
||
|
DWORD dwOldCheckSum = 0;
|
||
|
PIMAGE_NT_HEADERS pNtHeaders = NULL;
|
||
|
|
||
|
//
|
||
|
// Open the file for read access
|
||
|
//
|
||
|
|
||
|
hFileHandle = CreateFileW( pszwFilename,
|
||
|
GENERIC_READ | GENERIC_WRITE,
|
||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL);
|
||
|
|
||
|
if ( hFileHandle == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
QuitW( IDS_ENGERR_01, L"image", pszwFilename);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create a file mapping, map a view of the file into memory,
|
||
|
// and close the file mapping handle.
|
||
|
//
|
||
|
|
||
|
hMappingHandle = CreateFileMapping( hFileHandle,
|
||
|
NULL,
|
||
|
PAGE_READWRITE,
|
||
|
0,
|
||
|
0,
|
||
|
NULL);
|
||
|
|
||
|
if ( hMappingHandle == NULL )
|
||
|
{
|
||
|
CloseHandle( hFileHandle );
|
||
|
QuitW( IDS_ENGERR_22, pszwFilename, NULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Map a view of the file
|
||
|
//
|
||
|
|
||
|
pBaseAddress = MapViewOfFile( hMappingHandle,
|
||
|
FILE_MAP_READ | FILE_MAP_WRITE,
|
||
|
0,
|
||
|
0,
|
||
|
0);
|
||
|
CloseHandle( hMappingHandle);
|
||
|
|
||
|
if ( pBaseAddress == NULL )
|
||
|
{
|
||
|
CloseHandle( hFileHandle );
|
||
|
QuitW( IDS_ENGERR_23, pszwFilename, NULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the length of the file in bytes and compute the checksum.
|
||
|
//
|
||
|
dwFileLength = GetFileSize( hFileHandle, NULL );
|
||
|
pNtHeaders = CheckSumMappedFile( pBaseAddress, dwFileLength, &dwHeaderSum, &dwCheckSum);
|
||
|
|
||
|
if ( pNtHeaders == NULL )
|
||
|
{
|
||
|
CloseHandle( hFileHandle );
|
||
|
UnmapViewOfFile( pBaseAddress );
|
||
|
QuitW( IDS_ENGERR_17, pszwFilename, NULL);
|
||
|
}
|
||
|
|
||
|
dwOldCheckSum = pNtHeaders->OptionalHeader.CheckSum;
|
||
|
|
||
|
pNtHeaders->OptionalHeader.CheckSum = dwCheckSum;
|
||
|
|
||
|
if ( ! FlushViewOfFile( pBaseAddress, dwFileLength) )
|
||
|
{
|
||
|
UnmapViewOfFile( pBaseAddress);
|
||
|
CloseHandle( hFileHandle);
|
||
|
QuitW( IDS_ENGERR_24, pszwFilename, NULL);
|
||
|
}
|
||
|
UnmapViewOfFile( pBaseAddress);
|
||
|
|
||
|
if ( dwCheckSum != dwOldCheckSum )
|
||
|
{
|
||
|
if ( ! TouchFileTimes( hFileHandle, NULL) )
|
||
|
{
|
||
|
CloseHandle( hFileHandle);
|
||
|
QuitW( IDS_ENGERR_25, pszwFilename, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CloseHandle( hFileHandle);
|
||
|
return( 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This functions maps the specified file and computes the checksum of
|
||
|
the file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Filename - Supplies a pointer to the name of the file whose checksum
|
||
|
is computed.
|
||
|
|
||
|
HeaderSum - Supplies a pointer to a variable that receives the checksum
|
||
|
from the image file, or zero if the file is not an image file.
|
||
|
|
||
|
CheckSum - Supplies a pointer to the variable that receive the computed
|
||
|
checksum.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
0 if successful, else error number.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
ULONG MapFileAndFixCheckSumA( LPSTR pszFilename)
|
||
|
{
|
||
|
WCHAR szFileNameW[ MAX_PATH ];
|
||
|
|
||
|
//
|
||
|
// Convert the file name to unicode and call the unicode version
|
||
|
// of this function.
|
||
|
//
|
||
|
|
||
|
if ( MultiByteToWideChar( CP_ACP,
|
||
|
MB_PRECOMPOSED,
|
||
|
pszFilename,
|
||
|
-1,
|
||
|
szFileNameW,
|
||
|
MAX_PATH) )
|
||
|
{
|
||
|
return( MapFileAndFixCheckSumW( szFileNameW));
|
||
|
}
|
||
|
return( (ULONG)-1L);
|
||
|
}
|
||
|
|
||
|
//.........................................
|
||
|
|
||
|
static BOOL TouchFileTimes(
|
||
|
|
||
|
HANDLE FileHandle,
|
||
|
LPSYSTEMTIME lpSystemTime)
|
||
|
{
|
||
|
SYSTEMTIME SystemTime;
|
||
|
FILETIME SystemFileTime;
|
||
|
|
||
|
if ( lpSystemTime == NULL )
|
||
|
{
|
||
|
lpSystemTime = &SystemTime;
|
||
|
GetSystemTime( lpSystemTime );
|
||
|
}
|
||
|
|
||
|
if ( SystemTimeToFileTime( lpSystemTime, &SystemFileTime ) )
|
||
|
{
|
||
|
return( SetFileTime( FileHandle, NULL, NULL, &SystemFileTime ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return( FALSE);
|
||
|
}
|
||
|
}
|