//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 2000 // // File: main.cpp // //-------------------------------------------------------------------------- #ifndef NO_STRICT #ifndef STRICT #define STRICT 1 #endif #endif /* NO_STRICT */ #include #include #include #include "Globals.h" #include "DelayLoad.h" #include "ProgramOptions.h" #include "Processes.h" #include "ProcessInfo.h" #include "SymbolVerification.h" #include "ModuleInfoCache.h" #include "FileData.h" #include "Modules.h" #include "UtilityFunctions.h" #include "DmpFile.h" //#if ( _MSC_VER < 1200 ) //extern "C" //{ //#endif #ifdef CHECKSYM_TEST #include "CheckSym_test.h" #endif #ifdef __cplusplus extern "C" { #endif //#ifdef _UNICODE // Adding support for Unicode on Ansi systems (Win9x) //#include "CheckSym_UAPI.h" //#endif #ifndef CHECKSYM_TEST // Normal startup! int _cdecl _tmain(int argc, TCHAR *argv[]) { int iReturnCode = EXIT_FAILURE; #else // Startup for testing... no command-line is interpreted... int _tmain() { // We'll populate this below for every test run... int argc = 0; TCHAR ** argv = NULL; LPTSTR tszPointerToCurrentArgument = NULL; int iArgvIndex; LPTSTR tszCopyOfTestString = NULL; bool fFoundNextArgument, fQuoteMode; int iReturnCode = EXIT_FAILURE; int iTotalNumberOfTests = sizeof(g_TestArguments) / sizeof(g_TestArguments[0]); _tprintf(TEXT("\n\n")); CUtilityFunctions::OutputLineOfStars(); _tprintf(TEXT("ABOUT TO BEGIN %d TESTS!\n"), iTotalNumberOfTests); CUtilityFunctions::OutputLineOfStars(); for (int iTestNumber = 0; iTestNumber < iTotalNumberOfTests; iTestNumber++) { _tprintf(TEXT("\n\n\n")); CUtilityFunctions::OutputLineOfStars(); CUtilityFunctions::OutputLineOfStars(); _tprintf(TEXT("TESTING [%3d]: %s\n"), iTestNumber, g_TestArguments[iTestNumber].tszTestDescription ); CUtilityFunctions::OutputLineOfStars(); CUtilityFunctions::OutputLineOfStars(); _tprintf(TEXT("\n\n")); #endif // Initialize our object pointers... CSymbolVerification * lpSymbolVerification = NULL; // Processes/Modules data collected on this machine CProcesses * lpLocalSystemProcesses = NULL; // -P Option CModules * lpLocalFileSystemModules = NULL; // -F Option CModules * lpKernelModeDrivers = NULL; // -D Option // CSV File Support CFileData * lpCSVInputFile = NULL; // -I Option CFileData * lpCSVOutputFile = NULL; // -O Option CProcesses * lpCSVProcesses = NULL; // [PROCESSES] CProcessInfo * lpCSVProcess = NULL; // [PROCESS] CModules * lpCSVModulesFromFileSystem = NULL; // [FILESYSTEM MODULES] CModules * lpCSVKernelModeDrivers = NULL; // [KERNEL-MODE DRIVERS] // // Module Caches (these implement separate name spaces for the modules collected) // // It is important that we separate the modules in these caches because a module // from a CSV file should not be assumed to be the same module if you also happen // to collect it from a DMP file... or your local system... CModuleInfoCache * lpLocalSystemModuleInfoCache = NULL; // Contains Local System modules CModuleInfoCache * lpCSVModuleInfoCache = NULL; // Contains CSV modules CModuleInfoCache * lpDmpModuleInfoCache = NULL; // Contains user.dmp & kernel.dmp modules long lTotalNumberOfModulesVerified = 0; long lTotalNumberOfVerifyErrors = 0; // Support for Dmp Files... CDmpFile * lpDmpFile = NULL; // This object allows a Dump file (user/kernel) to be manipulated CProcessInfo * lpDmpFileUserModeProcess = NULL; // User.dmp files use this object to contain modules CModules * lpDmpFileKernelModeDrivers = NULL; // Memory.dmp files use this object to contain modules // Allocate local values bool fQuietMode = false; //#ifdef _UNICODE // First, we need to enable the Unicode APIs (if this is a Win9x machine)... // if (!InitUnicodeAPI()) // { // goto cleanup; // } //#endif // Let's populate our Globals! g_lpDelayLoad = new CDelayLoad(); g_lpProgramOptions = new CProgramOptions(); if (!g_lpDelayLoad && !g_lpProgramOptions) goto cleanup; // Initialize Options to their defaults... if (!g_lpProgramOptions->Initialize()) { _tprintf(TEXT("Unable to initialize Program Options!\n")); goto cleanup; } #ifdef CHECKSYM_TEST // Okay, we need to create the appearance of a true argc, and argv (argc is easy)... argc = g_TestArguments[iTestNumber].nArguments; argv = new LPTSTR[argc]; if (!argv) goto cleanup; // Okay, we need to populate the argv with pointers... tszCopyOfTestString = CUtilityFunctions::CopyString(g_TestArguments[iTestNumber].tszCommandLineArguments); if (!tszCopyOfTestString) goto cleanup; tszPointerToCurrentArgument = tszCopyOfTestString; for (iArgvIndex = 0; iArgvIndex < argc; iArgvIndex++) { // Hey... if the first character is a quote skip it and enter quote mode... if (*tszPointerToCurrentArgument == '\"') { // Advance to next character.. tszPointerToCurrentArgument = _tcsinc(tszPointerToCurrentArgument); fQuoteMode = true; } else { fQuoteMode = false; } // We should be pointing to our next argument... argv[iArgvIndex] = tszPointerToCurrentArgument; fFoundNextArgument = false; // Keep hunting for the next argument and leave our pointer pointing to it... while (!fFoundNextArgument) { // Now, we need to find the next argument... look for either a quote or a space... tszPointerToCurrentArgument = _tcspbrk( tszPointerToCurrentArgument, TEXT(" \"") ); // If this returns NULL, then we're at the end... if (!tszPointerToCurrentArgument) { break; } // If we found a space... then we have our next argument if we're not in quote mode.. if (*tszPointerToCurrentArgument == ' ') { if (fQuoteMode == true) { // We're in quote mode... // Advance to next argument.. tszPointerToCurrentArgument = _tcsinc(tszPointerToCurrentArgument); continue; } else { // Hey, we found our argument! fFoundNextArgument = true; // Null terminate our last argument *tszPointerToCurrentArgument = '\0'; // Advance to next argument.. tszPointerToCurrentArgument = _tcsinc(tszPointerToCurrentArgument); continue; } } else if (*tszPointerToCurrentArgument == '\"') { // If the next character happens to be a space... then this is the final // quote in a quoted argument... go ahead and nuke it and skip to next // argument... if (fQuoteMode && *_tcsinc(tszPointerToCurrentArgument) == ' ') { *tszPointerToCurrentArgument = NULL; } // Reverse the value of our mode... fQuoteMode = !fQuoteMode; // Advance to next argument.. tszPointerToCurrentArgument = _tcsinc(tszPointerToCurrentArgument); } } } #endif // Take care of the commandline... if (!g_lpProgramOptions->ProcessCommandLineArguments(argc, argv)) { // An error occurred, simply comment about how to get more assistance _tprintf(TEXT("\n")); _tprintf(TEXT("For simple help, type: CHECKSYM -?\n")); _tprintf(TEXT("For extended help, type: CHECKSYM -???\n")); goto cleanup; } // Do we need to display help? if ( g_lpProgramOptions->GetMode(CProgramOptions::HelpMode) ) { g_lpProgramOptions->DisplayHelp(); goto cleanup; } // Do we need to display simple help? if ( g_lpProgramOptions->GetMode(CProgramOptions::SimpleHelpMode) ) { g_lpProgramOptions->DisplaySimpleHelp(); goto cleanup; } #ifdef _UNICODE // It's unsupported running the UNICODE version on a Windows Platform if (g_lpProgramOptions->IsRunningWindows()) { _tprintf(TEXT("The UNICODE version of CHECKSYM does not work on a Windows platform!\n")); _tprintf(TEXT("You require the ANSI version.\n")); goto cleanup; } #endif // Let's suppress nasty critical errors (like... there's no // disk in the cd-rom drive, etc...) SetErrorMode(SEM_FAILCRITICALERRORS); // Let's save this for ease of access... fQuietMode = g_lpProgramOptions->GetMode(CProgramOptions::QuietMode); // Dump the program arguments (so it's obvious what we're going to do) g_lpProgramOptions->DisplayProgramArguments(); // DBGHELP FUNCTIONS? // Do we need to instantiate a CDBGHelpFunctions Object? We do if we need to call... // - MakeSureDirectoryPathExists() Used for the -B (build symbol tree) option if ( g_lpProgramOptions->GetMode(CProgramOptions::BuildSymbolTreeMode) ) { // Now, we need to build the symbol tree root... if ( !g_lpDelayLoad->MakeSureDirectoryPathExists(g_lpProgramOptions->GetSymbolTreeToBuild()) ) { _tprintf(TEXT("ERROR: Unable to create symbol tree root [%s]\n"), g_lpProgramOptions->GetSymbolTreeToBuild() ); CUtilityFunctions::PrintMessageString(GetLastError()); goto cleanup; } } // VERIFICATION OPTION: -V (verification)? if (g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsMode)) { // Allocate a structure for our symbol verification object. lpSymbolVerification = new CSymbolVerification(); if (!lpSymbolVerification) { _tprintf(TEXT("Unable to allocate memory for a verification symbol object!\n")); goto cleanup; } // Initialize Symbol Verification (if necessary) if (!lpSymbolVerification->Initialize()) { _tprintf(TEXT("Unable to initialize Symbol Verification object!\n")); goto cleanup; } } // // Allocate a structure for our ModuleInfoCache if we're getting anything from the local system // if ( g_lpProgramOptions->GetMode(CProgramOptions::InputProcessesFromLiveSystemMode) || g_lpProgramOptions->GetMode(CProgramOptions::InputDriversFromLiveSystemMode) || g_lpProgramOptions->GetMode(CProgramOptions::InputModulesDataFromFileSystemMode) ) { lpLocalSystemModuleInfoCache= new CModuleInfoCache(); // Check for out of memory condition... if ( lpLocalSystemModuleInfoCache == NULL ) { _tprintf(TEXT("Unable to allocate memory for the ModuleInfoCache object!\n")); goto cleanup; } // Initialize Options to their defaults... if (!lpLocalSystemModuleInfoCache->Initialize(lpSymbolVerification)) { _tprintf(TEXT("Unable to initialize ModuleInfoCache!\n")); goto cleanup; } } // // Allocate a structure for our CSVModuleInfoCache (if needed)... we need a separate // ModuleInfoCache space because the location of files on a remote system // files and we don't want to clash... // if (g_lpProgramOptions->GetMode(CProgramOptions::InputCSVFileMode)) { // We need a Module Info Cache for these CSV data (it all was collected from // the same system (supposedly) lpCSVModuleInfoCache= new CModuleInfoCache(); // Check for out of memory condition... if ( lpCSVModuleInfoCache == NULL ) { _tprintf(TEXT("Unable to allocate memory for the CSVModuleInfoCache object!\n")); goto cleanup; } // Initialize Options to their defaults... if (!lpCSVModuleInfoCache->Initialize(lpSymbolVerification)) { _tprintf(TEXT("Unable to initialize CSVModuleInfoCache!\n")); goto cleanup; } } // // Since we're going to read in a file... try and open it now... // This has the advantage of detecting problems accessing the file // when we've spent tons of time collecting data... // if (g_lpProgramOptions->GetMode(CProgramOptions::InputCSVFileMode)) { // Create the file object lpCSVInputFile = new CFileData(); if (!lpCSVInputFile) { _tprintf(TEXT("Unable to allocate memory for an input file object!\n")); goto cleanup; } // Set the input file path if (!lpCSVInputFile->SetFilePath(g_lpProgramOptions->GetInputFilePath())) { _tprintf(TEXT("Unable set input file path in the file data object! Out of memory?\n")); goto cleanup; } // If we are going to produce an input file... try to do that now... if (!lpCSVInputFile->OpenFile(OPEN_EXISTING, true)) // Must exist, read only mode... { _tprintf(TEXT("Unable to open the input file %s.\n"), lpCSVInputFile->GetFilePath()); lpCSVInputFile->PrintLastError(); goto cleanup; } // Reading is so much easier in memory mapped mode... if (!lpCSVInputFile->CreateFileMapping()) { _tprintf(TEXT("Unable to CreateFileMapping of the input file %s.\n"), lpCSVInputFile->GetFilePath()); lpCSVInputFile->PrintLastError(); goto cleanup; } // Go ahead and read in the header of the file (validate it). // Reading is so much easier in memory mapped mode... if (!lpCSVInputFile->ReadFileHeader()) { _tprintf(TEXT("Invalid header found on input file %s.\n"), lpCSVInputFile->GetFilePath()); lpCSVInputFile->PrintLastError(); goto cleanup; } } // If we specified an output file, this is where we go ahead and allocate memory // for the object if (g_lpProgramOptions->GetMode(CProgramOptions::OutputCSVFileMode)) { // Allocate a structure for our output fileData Object... lpCSVOutputFile = new CFileData(); if (!lpCSVOutputFile ) { _tprintf(TEXT("Unable to allocate memory for an output file object!\n")); goto cleanup; } } // INPUT METHOD: -Z Option? (Dump files?) if (g_lpProgramOptions->GetMode(CProgramOptions::InputDmpFileMode)) { if (!fQuietMode) _tprintf(TEXT("\nReading Data from DMP File...\n")); // Create a Module Info Cache namespace to contain any modules found... lpDmpModuleInfoCache = new CModuleInfoCache(); // Check for out of memory condition... if ( lpDmpModuleInfoCache == NULL ) { _tprintf(TEXT("Unable to allocate memory for the DmpModuleInfoCache object!\n")); goto cleanup; } // Initialize Options to their defaults... if (!lpDmpModuleInfoCache->Initialize(lpSymbolVerification)) { _tprintf(TEXT("Unable to initialize DmpModuleInfoCache!\n")); goto cleanup; } // Create the DMP File object lpDmpFile = new CDmpFile(); if (!lpDmpFile) { _tprintf(TEXT("Unable to allocate memory for a DMP file object!\n")); goto cleanup; } // Initialize the DMP File if (!lpDmpFile->Initialize(lpCSVOutputFile)) { _tprintf(TEXT("ERROR: Unable to initialize DMP file!\n")); goto cleanup; } // Header is good... so let's go ahead and get some data... if (!lpDmpFile->CollectData(&lpDmpFileUserModeProcess, &lpDmpFileKernelModeDrivers, lpDmpModuleInfoCache) ) { _tprintf(TEXT("ERROR: Unable to collect data from the DMP file!\n")); } } // INPUT METHOD: -i Option? if (g_lpProgramOptions->GetMode(CProgramOptions::InputCSVFileMode)) { if (!fQuietMode) _tprintf(TEXT("\nReading Data from Input File...\n")); // Header is good... so let's go ahead and dispatch if (!lpCSVInputFile->DispatchCollectionObject(&lpCSVProcesses, &lpCSVProcess, &lpCSVModulesFromFileSystem, &lpCSVKernelModeDrivers, lpCSVModuleInfoCache, lpCSVOutputFile)) { _tprintf(TEXT("Failure reading data collection from input file %s.\n"), lpCSVInputFile->GetFilePath()); lpCSVInputFile->PrintLastError(); goto cleanup; } } // INPUT METHOD: -p Option? if ( g_lpProgramOptions->GetMode(CProgramOptions::InputProcessesFromLiveSystemMode) ) { // Allocate a structure for our Processes Object. lpLocalSystemProcesses = new CProcesses(); if (!lpLocalSystemProcesses) { _tprintf(TEXT("Unable to allocate memory for the processes object!\n")); goto cleanup; } // The Processes Object will init differently depending on what // Command-Line arguments have been provided... if (!lpLocalSystemProcesses->Initialize(lpLocalSystemModuleInfoCache, NULL, lpCSVOutputFile)) { _tprintf(TEXT("Unable to initialize Processes Object!\n")); goto cleanup; } // Mention the delay... if (!( fQuietMode || g_lpProgramOptions->GetMode(CProgramOptions::PrintTaskListMode) ) ) _tprintf(TEXT("\nCollecting Process Data.... (this may take a few minutes)\n")); // Get the goods from the local system! lpLocalSystemProcesses->GetProcessesData(); } // INPUT METHOD: -f OPTION? if ( g_lpProgramOptions->GetMode(CProgramOptions::InputModulesDataFromFileSystemMode) ) { // Allocate a structure for our CModules collection (a generic collection of // files from the filesystem) // Allocate a structure for our Processes Object. lpLocalFileSystemModules = new CModules(); if (!lpLocalFileSystemModules) { _tprintf(TEXT("Unable to allocate memory for the CModules object!\n")); goto cleanup; } if (!lpLocalFileSystemModules->Initialize(lpLocalSystemModuleInfoCache, NULL, lpCSVOutputFile, NULL)) { _tprintf(TEXT("Unable to initialize FileSystemModules Object!\n")); goto cleanup; } if (!fQuietMode) _tprintf(TEXT("\nCollecting Modules Data from file path.... (this may take a few minutes)\n")); lpLocalFileSystemModules->GetModulesData(CProgramOptions::InputModulesDataFromFileSystemMode); } // INPUT METHOD: -d OPTION? if ( g_lpProgramOptions->GetMode(CProgramOptions::InputDriversFromLiveSystemMode) ) { // Allocate a structure for our CModules collection (a generic collection of // files from the filesystem) // Allocate a structure for our Processes Object. lpKernelModeDrivers = new CModules(); if (!lpKernelModeDrivers) { _tprintf(TEXT("Unable to allocate memory for the CModules object!\n")); goto cleanup; } if (!lpKernelModeDrivers->Initialize(lpLocalSystemModuleInfoCache, NULL, lpCSVOutputFile, NULL)) { _tprintf(TEXT("Unable to initialize Modules Object!\n")); goto cleanup; } if (!fQuietMode) _tprintf(TEXT("\nCollecting Device Driver Data.... (this may take a few minutes)\n")); lpKernelModeDrivers->GetModulesData(CProgramOptions::InputDriversFromLiveSystemMode); } // If we specified an output file, this is where we go ahead and allocate memory // for the object if (g_lpProgramOptions->GetMode(CProgramOptions::OutputCSVFileMode)) { // Do we have any data to output? If we have any data in cache... we should... if ( ( lpLocalSystemModuleInfoCache && lpLocalSystemModuleInfoCache->GetNumberOfModulesInCache() ) || ( lpCSVModuleInfoCache && lpCSVModuleInfoCache->GetNumberOfModulesInCache() ) || ( lpDmpModuleInfoCache && lpDmpModuleInfoCache->GetNumberOfModulesInCache() ) ) { // Set the output file path if (!lpCSVOutputFile->SetFilePath(g_lpProgramOptions->GetOutputFilePath())) { _tprintf(TEXT("Unable set output file path in the file data object! Out of memory?\n")); goto cleanup; } // Verify the output file directory... if (!lpCSVOutputFile ->VerifyFileDirectory()) { _tprintf(TEXT("Directory provided is invalid!\n")); lpCSVOutputFile->PrintLastError(); goto cleanup; } // If we are going to produce an output file... try to do that now... if ( !lpCSVOutputFile->OpenFile(g_lpProgramOptions->GetMode(CProgramOptions::OverwriteOutputFileMode) ? CREATE_ALWAYS : CREATE_NEW) ) { _tprintf(TEXT("Unable to create the output file %s.\n"), lpCSVOutputFile->GetFilePath()); lpCSVOutputFile->PrintLastError(); goto cleanup; } // We skip output of the file header if -E was specified... if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode)) { // Write the file header! if (!lpCSVOutputFile->WriteFileHeader()) { _tprintf(TEXT("Unable to write the output file header.\n")); lpCSVOutputFile->PrintLastError(); goto cleanup; } } } else { // Nothing to output... do not enable this mode... g_lpProgramOptions->SetMode(CProgramOptions::OutputCSVFileMode, false); } } // Do we verify symbols on this machine? if ( g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsMode) && ( lpLocalSystemModuleInfoCache || lpCSVModuleInfoCache || lpDmpModuleInfoCache) ) { // If there is any data in any of our caches... we need to verify them... // Do a Verify on the ModuleCache... (We'll be quiet in QuietMode or when Building a Symbol Tree) if (lpLocalSystemModuleInfoCache) { if (!fQuietMode) _tprintf(TEXT("\nVerifying %d Modules from this System...\n"), lpLocalSystemModuleInfoCache->GetNumberOfModulesInCache()); lpLocalSystemModuleInfoCache->VerifySymbols( fQuietMode || g_lpProgramOptions->GetMode(CProgramOptions::BuildSymbolTreeMode) ); // Update our stats... lTotalNumberOfModulesVerified = lTotalNumberOfModulesVerified + lpLocalSystemModuleInfoCache->GetNumberOfModulesVerified(); lTotalNumberOfVerifyErrors = lTotalNumberOfVerifyErrors + lpLocalSystemModuleInfoCache->GetNumberOfVerifyErrors(); } // Do a Verify on the ModuleCache... (We'll be quiet in QuietMode or when Building a Symbol Tree) if (lpCSVModuleInfoCache) { if (!fQuietMode) _tprintf(TEXT("\nVerifying %d Modules from the CSV file...\n"), lpCSVModuleInfoCache->GetNumberOfModulesInCache()); lpCSVModuleInfoCache->VerifySymbols( fQuietMode || g_lpProgramOptions->GetMode(CProgramOptions::BuildSymbolTreeMode) ); // Update our stats... lTotalNumberOfModulesVerified = lTotalNumberOfModulesVerified + lpCSVModuleInfoCache->GetNumberOfModulesVerified(); lTotalNumberOfVerifyErrors = lTotalNumberOfVerifyErrors + lpCSVModuleInfoCache->GetNumberOfVerifyErrors(); } // Do a Verify on the ModuleCache... (We'll be quiet in QuietMode or when Building a Symbol Tree) if (lpDmpModuleInfoCache) { if (!fQuietMode) _tprintf(TEXT("\nVerifying %d Modules from the DMP file...\n"), lpDmpModuleInfoCache->GetNumberOfModulesInCache()); lpDmpModuleInfoCache->VerifySymbols( fQuietMode || g_lpProgramOptions->GetMode(CProgramOptions::BuildSymbolTreeMode) ); // Update our stats... lTotalNumberOfModulesVerified = lTotalNumberOfModulesVerified + lpDmpModuleInfoCache->GetNumberOfModulesVerified(); lTotalNumberOfVerifyErrors = lTotalNumberOfVerifyErrors + lpDmpModuleInfoCache->GetNumberOfVerifyErrors(); } } // OUTPUT Phase! // // PROCESS COLLECTIONS FIRST!!!! // // Let's output local system processes first! if (lpLocalSystemProcesses) lpLocalSystemProcesses->OutputProcessesData(Processes, false); // Let's output CSV Processes next... if (lpCSVProcesses) lpCSVProcesses->OutputProcessesData(Processes, true); // If we're going to Dump to a USER.DMP file... do it... // Dump the data from a USER.DMP file... if we have one... if (lpDmpFileUserModeProcess) lpDmpFileUserModeProcess->OutputProcessData(Process, false, true); // let's output CSV Process next... if (lpCSVProcess) lpCSVProcess->OutputProcessData(Processes, true); // // MODULE COLLECTIONS SECOND!!!! // // Dump modules we found from our local file system first... if (lpLocalFileSystemModules) lpLocalFileSystemModules->OutputModulesData(Modules, false); // Dump modules from the CSV file second... if (lpCSVModulesFromFileSystem) lpCSVModulesFromFileSystem->OutputModulesData(Modules, true); // Dump device drivers from our local system first if (lpKernelModeDrivers) lpKernelModeDrivers->OutputModulesData(KernelModeDrivers, false); if (lpDmpFileKernelModeDrivers) lpDmpFileKernelModeDrivers->OutputModulesData(KernelModeDrivers, false); if (lpCSVKernelModeDrivers) lpCSVKernelModeDrivers->OutputModulesData(KernelModeDrivers, true); // Dump device drivers from our CSV file second... // ISSUE-2000/07/24-GREGWI: Add support for Device Drivers here... // // DISPLAY RESULTS (IF VERIFICATION WAS USED) // // Dump the verification results... if (g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsMode) && !fQuietMode) { long lPercentageSuccessfullyVerified = 0; if (lTotalNumberOfModulesVerified) lPercentageSuccessfullyVerified = (lTotalNumberOfModulesVerified - lTotalNumberOfVerifyErrors) * 100 / lTotalNumberOfModulesVerified; _tprintf(TEXT("RESULTS: %d Total Files Checked, Total %d Verification Errors Found\n"), lTotalNumberOfModulesVerified , lTotalNumberOfVerifyErrors ); _tprintf(TEXT("RESULTS: Percentage Verified Successfully = %d%%\n"), lPercentageSuccessfullyVerified); // Return an error level equal to the number of errors found (0 == EXIT_SUCCESS) iReturnCode = lTotalNumberOfVerifyErrors; } else { // Success! iReturnCode = EXIT_SUCCESS; } cleanup: // If we specified an output file, this is where we close it... if (lpCSVOutputFile) { // Try and close the file this object is bound to... lpCSVOutputFile->CloseFile(); // Free the memory... delete lpCSVOutputFile; lpCSVOutputFile = NULL; } // If we specified an input file, this is where we close it... if (lpCSVInputFile) { // Try and close the file this object is bound to... lpCSVInputFile->CloseFile(); // Free the memory... delete lpCSVInputFile; lpCSVInputFile = NULL; } if (g_lpDelayLoad) { delete g_lpDelayLoad; g_lpDelayLoad = NULL; } if (g_lpProgramOptions) { delete g_lpProgramOptions; g_lpProgramOptions = NULL; } if (lpLocalSystemProcesses) { delete lpLocalSystemProcesses; lpLocalSystemProcesses = NULL; } if (lpSymbolVerification) { delete lpSymbolVerification; lpSymbolVerification = NULL; } if (lpCSVKernelModeDrivers) { delete lpCSVKernelModeDrivers; lpCSVKernelModeDrivers = NULL; } if (lpCSVProcesses) { delete lpCSVProcesses; lpCSVProcesses = NULL; } if (lpCSVProcess) { delete lpCSVProcess; lpCSVProcess = NULL; } if (lpCSVModulesFromFileSystem) { delete lpCSVModulesFromFileSystem; lpCSVModulesFromFileSystem = NULL; } if (lpLocalSystemModuleInfoCache) { delete lpLocalSystemModuleInfoCache; lpLocalSystemModuleInfoCache = NULL; } if (lpCSVModuleInfoCache) { delete lpCSVModuleInfoCache; lpCSVModuleInfoCache = NULL; } if (lpDmpModuleInfoCache) { delete lpDmpModuleInfoCache; lpDmpModuleInfoCache = NULL; } if (lpLocalFileSystemModules) { delete lpLocalFileSystemModules; lpLocalFileSystemModules = NULL; } if (lpKernelModeDrivers) { delete lpKernelModeDrivers; lpKernelModeDrivers = NULL; } if (lpDmpFile) { delete lpDmpFile; lpDmpFile = NULL; } if (lpDmpFileUserModeProcess) { delete lpDmpFileUserModeProcess; lpDmpFileUserModeProcess = NULL; } if (lpDmpFileKernelModeDrivers) { delete lpDmpFileKernelModeDrivers; lpDmpFileKernelModeDrivers = NULL; } #ifdef CHECKSYM_TEST if (argv) { delete [] argv; argv = NULL; } if (tszCopyOfTestString) { delete [] tszCopyOfTestString; tszCopyOfTestString = NULL; } } // Return for more tests? #endif return iReturnCode; } //#if ( _MSC_VER < 1200 ) #ifdef __cplusplus } #endif