windows-nt/Source/XPSP1/NT/sdktools/checksym/filedata.cpp

892 lines
21 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1999 - 2000
//
// File: filedata.cpp
//
//--------------------------------------------------------------------------
// FileData.cpp: implementation of the CFileData class.
//
//////////////////////////////////////////////////////////////////////
#ifndef NO_STRICT
#ifndef STRICT
#define STRICT 1
#endif
#endif /* NO_STRICT */
#include <WINDOWS.H>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <wtypes.h>
#include <winnt.h>
#include <time.h>
#include "FileData.h"
#include "Globals.h"
#include "Version.h"
#include "Processes.h"
#include "ProcessInfo.h"
#include "Modules.h"
#include "UtilityFunctions.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFileData::CFileData()
{
m_dwGetLastError = 0;
m_hFileHandle = INVALID_HANDLE_VALUE;
m_tszFilePath = NULL;
m_szLINEBUFFER[0] = 0;
m_hFileMappingObject = NULL;
m_lpBaseAddress = NULL;
m_lpCurrentFilePointer = NULL;
m_lpCurrentLocationInLINEBUFFER = NULL;
}
CFileData::~CFileData()
{
if (m_tszFilePath)
delete [] m_tszFilePath;
if (m_lpBaseAddress)
UnmapViewOfFile(m_lpBaseAddress);
if (m_hFileMappingObject)
CloseHandle(m_hFileMappingObject);
}
bool CFileData::SetFilePath(LPTSTR tszFilePath)
{
// Did we get a proper string?
if (!tszFilePath)
return false;
if (m_tszFilePath)
delete [] m_tszFilePath;
m_tszFilePath = new TCHAR[(_tcsclen(tszFilePath)+1)];
if (!m_tszFilePath)
return false;
_tcscpy(m_tszFilePath, tszFilePath);
return true;
}
LPTSTR CFileData::GetFilePath()
{
return m_tszFilePath;
}
bool CFileData::VerifyFileDirectory()
{
if (!m_tszFilePath)
return false;
TCHAR tszDrive[_MAX_DRIVE];
TCHAR tszDirectory[_MAX_DIR];
TCHAR tszDirectoryPath[_MAX_PATH];
// Get just the directory...
_tsplitpath(m_tszFilePath, tszDrive, tszDirectory, NULL, NULL);
// Now, recompose this into a directory path...
_tcscpy(tszDirectoryPath, tszDrive);
_tcscat(tszDirectoryPath, tszDirectory);
_tcscat(tszDirectoryPath, TEXT("*.*"));
WIN32_FIND_DATA FindFileData;
HANDLE hDirectoryHandle = FindFirstFile(tszDirectoryPath, &FindFileData);
if (hDirectoryHandle == INVALID_HANDLE_VALUE)
{
// Failure to find the directory...
SetLastError();
return false;
}
// Close this now that we're done...
FindClose(hDirectoryHandle);
return true;
}
/*
DWORD CFileData::GetLastError()
{
return m_dwGetLastError;
}
*/
bool CFileData::OpenFile(DWORD dwCreateOption, bool fReadOnlyMode)
{
if (!m_tszFilePath)
{
return false;
}
// Open the file for read/write
m_hFileHandle = CreateFile(m_tszFilePath,
fReadOnlyMode ? ( GENERIC_READ )
: ( GENERIC_READ | GENERIC_WRITE ),
0, // Not shareable
NULL, // Default security descriptor
dwCreateOption,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (m_hFileHandle == INVALID_HANDLE_VALUE)
{
SetLastError();
return false;
}
return true;
}
bool CFileData::CloseFile()
{
if (m_hFileHandle == INVALID_HANDLE_VALUE)
{
return false;
}
if (!CloseHandle(m_hFileHandle))
{
SetLastError();
return false;
}
m_hFileHandle = INVALID_HANDLE_VALUE;
return true;
}
bool CFileData::WriteString(LPTSTR tszString, bool fHandleQuotes /* = false */)
{
DWORD dwByteCount = 0;
DWORD dwBytesWritten;
LPSTR szStringBuffer = NULL; // Pointer to the ANSI string (after conversion if necessary)
bool fReturn = false;
if (m_hFileHandle == INVALID_HANDLE_VALUE)
{
goto cleanup;
}
// We'll first convert the string if we need to...
szStringBuffer = CUtilityFunctions::CopyTSTRStringToAnsi(tszString);
if (!szStringBuffer)
goto cleanup;
dwByteCount = _tcsclen(tszString); // This is the number of characters (not bytes!)
// See if we were asked to handle quotes, and if there exists a comma or quote in the string
if ( fHandleQuotes == true && ((strchr(szStringBuffer, ',') || strchr(szStringBuffer, '"' ))) )
{
unsigned int iQuotedStringIndex = 0;
unsigned int iStringBufferIndex = 0;
// Special processing is required... this doesn't happen often, so this
// allocation which I'm about to make won't be done regularly...
LPSTR szQuotedStringBuffer = new char[1024];
// Did we successfully allocate storage?
if (!szQuotedStringBuffer)
goto cleanup;
// Keep going until we're at the end of the string...
// We start by adding a quote (since we know that we have a comma or quote somewhere...
szQuotedStringBuffer[iQuotedStringIndex++] = '\"';
// Keep going until the end of the string...
while (szStringBuffer[iStringBufferIndex] != '\0')
{
// We found a quote
if (szStringBuffer[iStringBufferIndex] == '"')
{
// We found a quote... I'll copy another quote in, and the quote already here
// will ensure we have two quotes together "" which in a CSV file represents a
// single quote...
szQuotedStringBuffer[iQuotedStringIndex++] = '\"';
}
// Copy the source char to the dest...
szQuotedStringBuffer[iQuotedStringIndex++] = szStringBuffer[iStringBufferIndex++];
}
// Append the final quote (and \0)...
szQuotedStringBuffer[iQuotedStringIndex++] = '\"';
szQuotedStringBuffer[iQuotedStringIndex++] = '\0';
// Just write out the data the nice, fast way...
if (!WriteFile(m_hFileHandle, szQuotedStringBuffer, strlen(szQuotedStringBuffer), &dwBytesWritten, NULL))
{
delete [] szQuotedStringBuffer;
goto cleanup;
}
delete [] szQuotedStringBuffer;
} else
{
// Just write out the data the nice, fast way...
if (!WriteFile(m_hFileHandle, szStringBuffer, dwByteCount, &dwBytesWritten, NULL))
{
goto cleanup;
}
}
fReturn = true;
cleanup:
if (szStringBuffer)
delete [] szStringBuffer;
return fReturn;
}
bool CFileData::WriteDWORD(DWORD dwNumber)
{
TCHAR tszBuffer[10+1]; // 0xFFFFFFFF == 4294967295 (10 characters) + 1 for the \0
_stprintf(tszBuffer, TEXT("%u"), dwNumber);
if (!WriteString(tszBuffer))
return false;
return true;
}
bool CFileData::WriteTimeDateString(time_t Time)
{
enum {BUFFERSIZE = 128};
TCHAR tszBuffer[BUFFERSIZE];
struct tm * localTime = localtime(&Time);
if (localTime)
{
// This top version seems to be better Y2K friendly as I spit out the full year...
_tcsftime(tszBuffer, BUFFERSIZE, TEXT("%B %d, %Y %H:%M:%S"), localTime);
//_tcsftime(tszBuffer, BUFFERSIZE, TEXT("%c"), localtime(&Time));
if (!WriteString(tszBuffer, true))
return false;
} else
{ // A bad TimeDate stamp was provided
if (!WriteString(TEXT("<INVALID DATE>"), true))
return false;
}
return true;
}
bool CFileData::WriteFileHeader()
{
enum {BUFFERSIZE = 128};
TCHAR tszBuffer[BUFFERSIZE];
DWORD dwNum = BUFFERSIZE;
// Write the Checksym version info...
_stprintf(tszBuffer, TEXT("CHECKSYM, (%d.%d:%d.%d)\r\n"), VERSION_FILEVERSION);
if (!WriteString(tszBuffer))
return false;
// Write the current date/time info...
if (!WriteString(TEXT("Created:,")))
return false;
time_t Time;
time(&Time);
if (!WriteTimeDateString(Time))
return false;
// Write the carriage-return line-feed combo...
if (!WriteString(TEXT("\r\n")))
return false;
// Spit out the computername
if (!GetComputerName(tszBuffer, &dwNum))
return false;
if (!WriteString(TEXT("Computer:,")))
return false;
if (!WriteString(tszBuffer))
return false;
// Write the carriage-return line-feed combo... (a couple of times)...
if (!WriteString(TEXT("\r\n")))
return false;
return true;
}
void CFileData::PrintLastError()
{
CUtilityFunctions::PrintMessageString(GetLastError());
}
bool CFileData::CreateFileMapping()
{
m_hFileMappingObject = ::CreateFileMapping(m_hFileHandle,
NULL,
PAGE_READONLY | SEC_COMMIT,
0,
0,
NULL);
if (m_hFileMappingObject == NULL)
{
SetLastError();
return false;
}
// Okay, we'll map the view as well...
m_lpBaseAddress = MapViewOfFile(m_hFileMappingObject,
FILE_MAP_READ,
0,
0,
0);
if (m_lpBaseAddress == NULL)
{
SetLastError();
return false;
}
m_lpCurrentFilePointer = (LPSTR) m_lpBaseAddress;
return true;
}
bool CFileData::ReadFileHeader()
{
// For starters, let's read a line...
if (!ReadFileLine())
return false;
enum { BUFFER_SIZE = 128};
char szTemporaryBuffer[BUFFER_SIZE];
DWORD cbBytesRead;
cbBytesRead = ReadString(szTemporaryBuffer, BUFFER_SIZE);
// We gotta read something?
if (0 == cbBytesRead)
return false;
// Look for our "Magic" Value
if (_stricmp(szTemporaryBuffer, "CHECKSYM"))
{
_tprintf(TEXT("Error: Input file has invalid header. Missing CHECKSYM keyword!\n"));
return false;
}
// Read version number
// We'll do this later if needed...
// Read Created Time
if (!ReadFileLine())
return false;
// Read Computer this was created on
if (!ReadFileLine())
return false;
return true;
}
bool CFileData::ReadFileLine()
{
// We're ansi oriented (since this is a CSV file -- in case you were wondering)
size_t pos;
// Find the first \r or \n character (if we're point to \0, we'll figure that out)
pos = strcspn(m_lpCurrentFilePointer, "\r\n");
// Hmm... we don't read a line that starts on \r\n very well...
if (pos == 0)
{
m_szLINEBUFFER[0] = '\0';
ResetBufferPointerToStart();
return false;
}
// Read the line into our buffer
strncpy(m_szLINEBUFFER, m_lpCurrentFilePointer, pos);
// Null terminate for ease of use...
m_szLINEBUFFER[pos] = '\0';
ResetBufferPointerToStart();
// Advance the current file pointer to just beyond the last character we read...
// This should advance to the \r\n or \0
m_lpCurrentFilePointer += pos;
// We want this file pointer to advance beyond any \r \n chars we may have found...
while (*m_lpCurrentFilePointer)
{
// Advance pointer to non- \r or \n
if ( (*m_lpCurrentFilePointer == '\r') ||
(*m_lpCurrentFilePointer == '\n') )
{
m_lpCurrentFilePointer++;
}
else
{
break; // Found either the \0 or something else...
}
}
return true;
}
DWORD CFileData::ReadString(LPSTR szStringBuffer, DWORD iStringBufferSize)
{
// If we give a buffer size, we have to give a buffer...
if ( szStringBuffer == NULL && iStringBufferSize )
return 0;
// The ReadFileLine() call puts us at the start of a line (after
// the \r \n combinations... It's possible that we're at the
// end...
// If we're pointing to the end of the file, let's bail...
if (*m_lpCurrentLocationInLINEBUFFER == '\0')
return 0;
DWORD iBytesCopied = 0;
bool fFinished = false;
bool fFoundSeparatorChars = false; // These might be '\r', '\n', or ','
bool fQuoteMode = false;
while (!fFinished)
{
switch (*m_lpCurrentLocationInLINEBUFFER)
{
case '"':
// Okay, we found a quote... that's cool.. but are we quoting a quote,
// or... are we in quote mode?
// Probe ahead... is the next char a '"' also?
if ( *(m_lpCurrentLocationInLINEBUFFER+1) == '"')
{
// Yes it is... so go ahead and copy the quote
CopyCharIfRoom(iStringBufferSize, szStringBuffer, &iBytesCopied, &fFinished);
if (!fFinished)
*(m_lpCurrentLocationInLINEBUFFER++); // Skip the quote
}
else
{
*(m_lpCurrentLocationInLINEBUFFER++);
fQuoteMode = !fQuoteMode; // Toggle the quote mode...
continue;
}
case '\0':
fFinished = true;
break;
case ',':
if (!fQuoteMode)
{ // If we're not in quote mode, then this marks the end of a field...
fFinished = true;
fFoundSeparatorChars = true;
*(m_lpCurrentLocationInLINEBUFFER++);
}
else
{
// Okay, this marks a new character that happens to be a comma...
CopyCharIfRoom(iStringBufferSize, szStringBuffer, &iBytesCopied, &fFinished);
}
break;
case '\r':
case '\n':
// We note that we found these, and simply advance the pointer...
fFoundSeparatorChars = true;
*(m_lpCurrentLocationInLINEBUFFER++);
break;
default:
if (fFoundSeparatorChars)
{
// We were scanning... found a separator after some data... so we bail
fFinished = true;
break;
}
CopyCharIfRoom(iStringBufferSize, szStringBuffer, &iBytesCopied, &fFinished);
}
}
if (iStringBufferSize) // We only NULL terminate a buffer if one was provided...
szStringBuffer[iBytesCopied] = '\0'; // Null terminate this puppy...
return iBytesCopied;
}
//
// This function is responsible for reading through the CSV file and creating any necessary
// objects and populating them with data...
//
bool CFileData::DispatchCollectionObject(CProcesses ** lplpProcesses, CProcessInfo ** lplpProcess, CModules ** lplpModules, CModules ** lplpKernelModeDrivers, CModuleInfoCache * lpModuleInfoCache, CFileData * lpOutputFile)
{
enum { BUFFER_SIZE = 128};
char szTemporaryBuffer[BUFFER_SIZE];
TCHAR tszTemporaryBuffer[BUFFER_SIZE];
DWORD cbBytesRead;
bool fContinueReading = true;
// Read the Output Type
if (!ReadFileLine())
return false;
while (fContinueReading)
{
// If this is the second iteration (or more) we may not be at the
// start of our buffer (causing the read of the output type to fail)
ResetBufferPointerToStart();
// Read the Output Type line...
cbBytesRead = ReadString(szTemporaryBuffer, BUFFER_SIZE);
// We gotta read something?
if (0 == cbBytesRead)
return true;
// I hate to do this... but we read this stuff as ASCII... may need to
// convert to a TCHAR format to be neutral...
CUtilityFunctions::CopyAnsiStringToTSTR(szTemporaryBuffer, tszTemporaryBuffer, cbBytesRead+1);
// Printout the section we're attempting to read...
if (!g_lpProgramOptions->GetMode(CProgramOptions::QuietMode))
_tprintf(TEXT(" Reading %s data...\n"), tszTemporaryBuffer);
if ( _tcsicmp(g_tszCollectionArray[Processes].tszCSVLabel, tszTemporaryBuffer) == 0 )
{
/*
[PROCESSES]
*/
// Read to the end of the line
if (!ReadFileLine())
return false;
// Yup, it is... let's create a Processes Object
if (*lplpProcesses == NULL)
{
// Allocate a structure for our Processes Object.
*lplpProcesses = new CProcesses();
if (!*lplpProcesses)
{
_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 (!(*lplpProcesses)->Initialize(lpModuleInfoCache, this, lpOutputFile))
{
_tprintf(TEXT("Unable to initialize Processes Object!\n"));
goto cleanup;
}
}
// Okay, go get the Process Data...
(*lplpProcesses)->GetProcessesData();
} else
if ( _tcsicmp(g_tszCollectionArray[Process].tszCSVLabel, tszTemporaryBuffer) == 0 )
{
/*
[PROCESS]
*/
// Read to the end of the line
if (!ReadFileLine())
return false;
// Yup, it is... let's create a ProcessInfo Object
if (*lplpProcess== NULL)
{
// Allocate a structure for our ProcessInfo Object.
*lplpProcess = new CProcessInfo();
if (!*lplpProcess)
{
_tprintf(TEXT("Unable to allocate memory for the processinfo object!\n"));
goto cleanup;
}
// The Modules Object will init differently depending on what
// Command-Line arguments have been provided...
if (!(*lplpProcess)->Initialize(lpModuleInfoCache, this, lpOutputFile, NULL))
{
_tprintf(TEXT("Unable to initialize Modules Object!\n"));
goto cleanup;
}
}
// Okay, go get the Process Data
(*lplpProcess)->GetProcessData();
} else
if ( _tcsicmp(g_tszCollectionArray[Modules].tszCSVLabel, tszTemporaryBuffer) == 0 )
{
/*
[MODULES]
*/
// Read to the end of the line
if (!ReadFileLine())
return false;
// Yup, it is... let's create a Modules Object
if (*lplpModules == NULL)
{
// Allocate a structure for our Modules Object.
*lplpModules = new CModules();
if (!*lplpModules)
{
_tprintf(TEXT("Unable to allocate memory for the modules object!\n"));
goto cleanup;
}
// The Modules Object will init differently depending on what
// Command-Line arguments have been provided...
if (!(*lplpModules)->Initialize(lpModuleInfoCache, this, lpOutputFile, NULL))
{
_tprintf(TEXT("Unable to initialize Modules Object!\n"));
goto cleanup;
}
}
// Okay, go get the Modules Data (collected from the filesystem)
(*lplpModules)->GetModulesData(CProgramOptions::InputModulesDataFromFileSystemMode, true);
} else
if ( _tcsicmp(g_tszCollectionArray[KernelModeDrivers].tszCSVLabel, tszTemporaryBuffer) == 0 )
{
/*
[KERNEL-MODE DRIVERS]
*/
// Read to the end of the line
if (!ReadFileLine())
return false;
// Yup, it is... let's create a Modules Object
if (*lplpKernelModeDrivers == NULL)
{
// Allocate a structure for our Modules Object.
*lplpKernelModeDrivers = new CModules();
if (!*lplpKernelModeDrivers)
{
_tprintf(TEXT("Unable to allocate memory for the modules object!\n"));
goto cleanup;
}
// The Modules Object will init differently depending on what
// Command-Line arguments have been provided...
if (!(*lplpKernelModeDrivers)->Initialize(lpModuleInfoCache, this, lpOutputFile, NULL))
{
_tprintf(TEXT("Unable to initialize Modules Object!\n"));
goto cleanup;
}
}
// Okay, go get the Modules Data (collected from the filesystem)
(*lplpKernelModeDrivers)->GetModulesData(CProgramOptions::InputDriversFromLiveSystemMode, true);
} else
{
_tprintf(TEXT("Unrecognized section %s found!\n"), tszTemporaryBuffer);
return false;
}
}
cleanup:
return false;
}
bool CFileData::ReadDWORD(LPDWORD lpDWORD)
{
char szTempBuffer[10+1]; // 0xFFFFFFFF == 4294967295 (10 characters) + 1 for the \0
if (!ReadString(szTempBuffer, 10+1))
return false;
// Convert it... baby...
*lpDWORD = atoi(szTempBuffer);
return true;
}
bool CFileData::CopyCharIfRoom(DWORD iStringBufferSize, LPSTR szStringBuffer, LPDWORD piBytesCopied, bool *pfFinished)
{
if (iStringBufferSize)
{
// If we have room to copy the data... let's do it...
if (*piBytesCopied < iStringBufferSize)
{
szStringBuffer[(*piBytesCopied)++] = *(m_lpCurrentLocationInLINEBUFFER++);
} else
{
// No room... we're done.
*pfFinished = true;
}
} else
{
// Just advance the pointer... we have no buffer to copy to...
*(m_lpCurrentLocationInLINEBUFFER++);
}
return true;
}
bool CFileData::ResetBufferPointerToStart()
{
// Reset the Pointer with our line buffer to the start of this buffer
m_lpCurrentLocationInLINEBUFFER = m_szLINEBUFFER;
return true;
}
bool CFileData::EndOfFile()
{
//return (*m_lpCurrentFilePointer == '\0');
return (*m_lpCurrentLocationInLINEBUFFER == '\0');
}
bool CFileData::WriteFileTimeString(FILETIME ftFileTime)
{
enum {BUFFERSIZE = 128};
TCHAR tszBuffer[BUFFERSIZE];
FILETIME ftLocalFileTime;
SYSTEMTIME lpSystemTime;
int cch = 0;
// Let's convert this to a local file time first...
if (!FileTimeToLocalFileTime(&ftFileTime, &ftLocalFileTime))
return false;
FileTimeToSystemTime( &ftLocalFileTime, &lpSystemTime );
cch = GetDateFormat( LOCALE_USER_DEFAULT,
0,
&lpSystemTime,
TEXT("MMMM d',' yyyy"),
tszBuffer,
BUFFERSIZE );
if (!cch)
return false;
tszBuffer[cch-1] = TEXT(' ');
//
// Get time and format to characters
//
GetTimeFormat( LOCALE_USER_DEFAULT,
0,
&lpSystemTime, // use current time
NULL, // use default format
tszBuffer + cch,
BUFFERSIZE - cch );
// <Full Month Name> <day>, <Year with Century> <Hour>:<Minute>:<Second>
//_tcsftime(tszBuffer, BUFFERSIZE, TEXT("%B %d, %Y %H:%M:%S"), localtime(&Time));
//_tcsftime(tszBuffer, BUFFERSIZE, TEXT("%c"), localtime(&Time));
if (!WriteString(tszBuffer, true))
return false;
return true;
}
// Exception Monitor prefers a MM/DD/YYYY HH:MM:SS format...
bool CFileData::WriteTimeDateString2(time_t Time)
{
enum {BUFFERSIZE = 128};
TCHAR tszBuffer[BUFFERSIZE];
// This top version seems to be better Y2K friendly as I spit out the full year...
_tcsftime(tszBuffer, BUFFERSIZE, TEXT("%m/%d/%Y %H:%M:%S"), localtime(&Time));
//_tcsftime(tszBuffer, BUFFERSIZE, TEXT("%c"), localtime(&Time));
if (!WriteString(tszBuffer, true))
return false;
return true;
}
// Exception Monitor prefers a MM/DD/YYYY HH:MM:SS format...
bool CFileData::WriteFileTimeString2(FILETIME ftFileTime)
{
enum {BUFFERSIZE = 128};
TCHAR tszBuffer[BUFFERSIZE];
FILETIME ftLocalFileTime;
SYSTEMTIME lpSystemTime;
int cch = 0;
// Let's convert this to a local file time first...
if (!FileTimeToLocalFileTime(&ftFileTime, &ftLocalFileTime))
return false;
FileTimeToSystemTime( &ftLocalFileTime, &lpSystemTime );
cch = GetDateFormat( LOCALE_USER_DEFAULT,
0,
&lpSystemTime,
TEXT("MM/dd/yyyy"),
tszBuffer,
BUFFERSIZE );
if (!cch)
return false;
tszBuffer[cch-1] = TEXT(' ');
//
// Get time and format to characters
//
GetTimeFormat( LOCALE_USER_DEFAULT,
0,
&lpSystemTime, // use current time
TEXT("HH:mm:ss"), // use default format
tszBuffer + cch,
BUFFERSIZE - cch );
if (!WriteString(tszBuffer, true))
return false;
return true;
}
//#endif