www.pudn.com > ntcrypto.rar > cryptscn.c
#include#include #include "sha.h" int UpdateChanges( LPSTR szScanFile ); int ScanChanges( LPSTR szScanFile ); BOOL CheckHash( IN LPSTR szFileToCheck, IN BYTE HashExpected[A_SHA_DIGEST_LEN], IN OUT BOOL *pfMatch ); BOOL GetHash( IN LPSTR szFileToHash, IN BYTE HashCurrent[A_SHA_DIGEST_LEN] ); BOOL HashDiskImage( IN HANDLE hFile, // handle of file to hash IN BYTE FileHash[A_SHA_DIGEST_LEN] // on success, buffer contains file hash ); BOOL TranslateToMapped( IN LPSTR szFileCandidate, IN OUT LPSTR szFileMapped ); #define RTN_OK 0 #define RTN_USAGE 1 #define RTN_ERROR 13 #define RTN_CHANGED 14 // // default file path that defines the changes to check/update // #define SCANFILE_DEFAULT "\\nt\\private\\windows\\base\\ntcrypto\\cryptscn.txt" // // environment variable name that provides a mechanism for scanning against // a remote source tree shared out from the \nt directory. // eg: \\x86fre\sources is mapped to d:\nt on the source machine. // #define MAPPED_SRC_ENV "CRYPT_MAP_SRC" // // variables that indicate if and where the mapped source is // BOOL g_fMappedSource = FALSE; CHAR g_szMappedSource[ MAX_PATH + 1]; int __cdecl main( int argc, char *argv[] ) { LPSTR szScanFile = SCANFILE_DEFAULT; BOOL fUpdate = FALSE; DWORD cchBuf; DWORD cchEnv; int i; if( argc == 2 && (argv[1][0] == '-' || argv[1][0] == '/') && argv[1][1] == '?' ) { fprintf(stderr, "Usage: %s [-u] [ScanFilePath]\n", argv[0]); fprintf(stderr, " -u Update the default or specified ScanFilePath\n"); fprintf(stderr, " ScanFilePath is alternate input file. Default is:\n"); fprintf(stderr, " %s\n", SCANFILE_DEFAULT); fprintf(stderr, " Env. Var %s may point to remote sources, eg: \\\\x86fre\\sources\n", MAPPED_SRC_ENV); return RTN_USAGE; } for( i=1 ; i < argc ; i++) { if(argv[i][0] == '-' && argv[i][1] == 'u') fUpdate = TRUE; else szScanFile = argv[i]; } // // if the MAPPED_SRC_ENV var is set, enable \nt -> MAPPED_SRC_ENV translation // otherwise, make current directory %_NTDRIVE% if it is set. // cchBuf = sizeof(g_szMappedSource) / sizeof(CHAR); cchEnv = GetEnvironmentVariableA( MAPPED_SRC_ENV, g_szMappedSource, cchBuf ); if( cchEnv > 0 && cchEnv <= cchBuf ) { g_fMappedSource = TRUE; } else { CHAR szNTDrive[ MAX_PATH + 1 ]; cchBuf = sizeof(szNTDrive) / sizeof(CHAR); cchEnv = GetEnvironmentVariableA( "_NTDRIVE", szNTDrive, cchBuf ); if(cchEnv > 0 && cchEnv <= cchBuf) SetCurrentDirectoryA( szNTDrive ); } if( fUpdate ) return UpdateChanges( szScanFile ); else return ScanChanges( szScanFile ); } int UpdateChanges( LPSTR szScanFile ) { FILE *streamTemp = NULL; FILE *stream = NULL; FILE *streamHashes = NULL; CHAR szTempFile[ MAX_PATH + 1 ]; CHAR LineBuf[ 512 ]; int iRet = RTN_OK; // // get a temporary file name for the new output file... // if(GetTempFileNameA( ".", "cry", 0, szTempFile ) == 0) return RTN_ERROR; // // ... and open it for write binary mode. // streamTemp = fopen( szTempFile, "w+b" ); if(streamTemp == NULL) { iRet = RTN_ERROR; goto cleanup; } // // create a temporary intermediate file containing updated hash values. // this is done so we can just append all updated hashes to the end // of the filtered input file. // streamHashes = tmpfile(); if(streamHashes == NULL) { iRet = RTN_ERROR; goto cleanup; } // // open the input file that defines what files get hashed. // stream = fopen( szScanFile, "r" ); if(stream == NULL) { iRet = RTN_ERROR; goto cleanup; } while( fgets(LineBuf, sizeof(LineBuf), stream) ) { BYTE HashExpected[A_SHA_DIGEST_LEN]; CHAR szFileCandidate[ MAX_PATH + 1 ]; CHAR szFileToRead[ MAX_PATH + 1 ]; int iScanned; // // just copy comment block // if( LineBuf[0] == '#' ) { fprintf(streamTemp, LineBuf); continue; } // // ignore existing hash entries. // iScanned = sscanf(LineBuf, "%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx %s", &HashExpected[0], &HashExpected[1], &HashExpected[2], &HashExpected[3], &HashExpected[4], &HashExpected[5], &HashExpected[6], &HashExpected[7], &HashExpected[8], &HashExpected[9], &HashExpected[10], &HashExpected[11], &HashExpected[12], &HashExpected[13], &HashExpected[14], &HashExpected[15], &HashExpected[16], &HashExpected[17], &HashExpected[18], &HashExpected[19], szFileCandidate ); if( iScanned == 21 ) continue; // // write out anything that isn't a file specifier. // fprintf(streamTemp, LineBuf); iScanned = sscanf(LineBuf, "%s", szFileCandidate); if( iScanned != 1 ) continue; if( szFileCandidate[0] == '\0' ) continue; TranslateToMapped(szFileCandidate, szFileToRead); // // get current hash and output the result to file. // if(!GetHash( szFileToRead, HashExpected )) { fprintf(stderr, "%s: GetHash failed! (rc=%lu)\n", szFileToRead, GetLastError()); iRet = RTN_ERROR; break; } // // write the updated hash entry out to the intermediate hash file // fprintf(streamHashes, "%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx%.2lx %s\n", HashExpected[0], HashExpected[1], HashExpected[2], HashExpected[3], HashExpected[4], HashExpected[5], HashExpected[6], HashExpected[7], HashExpected[8], HashExpected[9], HashExpected[10], HashExpected[11], HashExpected[12], HashExpected[13], HashExpected[14], HashExpected[15], HashExpected[16], HashExpected[17], HashExpected[18], HashExpected[19], szFileCandidate ); } // // if everything succeeded, append the intermediate hash entry file // to the intermediate temporary file. // if( iRet == RTN_OK ) { rewind( streamHashes ); while( fgets( LineBuf, sizeof(LineBuf), streamHashes ) ) fprintf(streamTemp, LineBuf); } cleanup: if(stream) fclose(stream); if(streamTemp) fclose(streamTemp); if(streamHashes) fclose(streamHashes); // // update the original file. // if( iRet == RTN_OK ) { if(!CopyFileA(szTempFile, szScanFile, FALSE)) { iRet = RTN_ERROR; } else { printf("%s: update successful\n", szScanFile); } } DeleteFileA(szTempFile); return iRet; } int ScanChanges( LPSTR szScanFile ) { FILE *stream = NULL; CHAR LineBuf[ 512 ]; int iRet = RTN_OK; stream = fopen( szScanFile, "r" ); if(stream == NULL) return RTN_ERROR; while( fgets(LineBuf, sizeof(LineBuf), stream) ) { BYTE HashExpected[A_SHA_DIGEST_LEN]; CHAR szFileCandidate[ MAX_PATH + 1 ]; CHAR szFileToRead[ MAX_PATH + 1 ]; BOOL fMatch = FALSE; int iScanned = RTN_OK; // // ignore # comment block // if( LineBuf[0] == '#' ) continue; iScanned = sscanf(LineBuf, "%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx%2lx %s", &HashExpected[0], &HashExpected[1], &HashExpected[2], &HashExpected[3], &HashExpected[4], &HashExpected[5], &HashExpected[6], &HashExpected[7], &HashExpected[8], &HashExpected[9], &HashExpected[10], &HashExpected[11], &HashExpected[12], &HashExpected[13], &HashExpected[14], &HashExpected[15], &HashExpected[16], &HashExpected[17], &HashExpected[18], &HashExpected[19], szFileCandidate ); if(iScanned != 21) continue; TranslateToMapped(szFileCandidate, szFileToRead); if(!CheckHash( szFileToRead, HashExpected, &fMatch )) { fprintf(stderr, "%s: CheckHash failed! (rc=%lu)\n", szFileToRead, GetLastError()); iRet = RTN_CHANGED; // assume the worst: a change occurred. continue; } if(!fMatch) { fprintf(stderr, "%s: file has changed\n", szFileToRead); iRet = RTN_CHANGED; } else { printf("%s: no change\n", szFileToRead); } } fclose(stream); return iRet; } BOOL TranslateToMapped( IN LPSTR szFileCandidate, IN OUT LPSTR szFileMapped ) { DWORD cchFileCandidate = lstrlenA(szFileCandidate); if( g_fMappedSource && cchFileCandidate > 3 ) { CHAR charReplaced = szFileCandidate[3]; LPSTR szNTDir = "\\nt"; int icmp; szFileCandidate[3] = '\0'; icmp = lstrcmpiA( szFileCandidate, szNTDir ); szFileCandidate[3] = charReplaced; if( icmp == 0 ) { lstrcpyA(szFileMapped, g_szMappedSource); lstrcatA(szFileMapped, &szFileCandidate[3]); return TRUE; } } CopyMemory( szFileMapped, szFileCandidate, (cchFileCandidate+1) * sizeof(CHAR) ); return TRUE; } BOOL CheckHash( IN LPSTR szFileToCheck, IN BYTE HashExpected[A_SHA_DIGEST_LEN], IN OUT BOOL *pfMatch ) { BYTE HashCurrent[A_SHA_DIGEST_LEN]; HANDLE hFile; BOOL fSuccess; *pfMatch = FALSE; hFile = CreateFileA( szFileToCheck, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if(hFile == INVALID_HANDLE_VALUE) return FALSE; fSuccess = HashDiskImage( hFile, HashCurrent ); CloseHandle( hFile ); if( fSuccess ) { if(memcmp(HashExpected, HashCurrent, sizeof(HashCurrent)) == 0) *pfMatch = TRUE; } return fSuccess; } BOOL GetHash( IN LPSTR szFileToHash, IN BYTE HashCurrent[A_SHA_DIGEST_LEN] ) { HANDLE hFile; BOOL fSuccess; hFile = CreateFileA( szFileToHash, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if(hFile == INVALID_HANDLE_VALUE) return FALSE; fSuccess = HashDiskImage( hFile, HashCurrent ); CloseHandle( hFile ); return fSuccess; } BOOL HashDiskImage( IN HANDLE hFile, // handle of file to hash IN BYTE FileHash[A_SHA_DIGEST_LEN] // on success, buffer contains file hash ) /*++ This function hashes the file associated with the file specified by the hFile parameter. If the function succeeds, the return value is TRUE, and the buffer specified by the FileHash parameter is filled with the hash of the file. The hashing performed by this function begins at the current file position associated with the hFile parameter, and continues until EOF or and error occurs. The caller should make no assumptions about the file position upon return of this call. For that reason, the caller should preserve and restore file position associated with hFile parameter if necessary. This function should not be called from outside this module, unless absolutely necessary, because no caching or other performance improvements take place. The buffer specified by the FileHash parameter should be A_SHA_DIGEST_LEN length (20). --*/ { #define DISK_BUF_SIZE 4096 BYTE DiskBuffer[DISK_BUF_SIZE]; A_SHA_CTX context; DWORD dwBytesToRead; DWORD dwBytesRead; BOOL bSuccess = FALSE; A_SHAInit(&context); dwBytesToRead = sizeof(DiskBuffer); do { bSuccess = ReadFile(hFile, DiskBuffer, dwBytesToRead, &dwBytesRead, NULL); if( !bSuccess ) break; A_SHAUpdate(&context, DiskBuffer, dwBytesRead); } while ( dwBytesRead ); A_SHAFinal(&context, FileHash); return bSuccess; }