|
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
Grabmi.cpp
Abstract:
Contains the entry point & core code for the application.
Notes:
ANSI & Unicode via TCHAR - runs on Win9x/NT/2K/XP etc.
History:
07/18/00 jdoherty Created 12/16/00 jdoherty Modified to use SDBAPI routines 12/29/00 prashkud Modified to take space in the filepath 01/23/02 rparsons Re-wrote existing code 02/19/02 rparsons Implemented strsafe functions
--*/ #include "grabmi.h"
//
// This structure contains all the data we'll need to access
// throughout the application.
//
APPINFO g_ai;
/*++
Routine Description:
Prints a formatted string to the debugger.
Arguments:
dwDetail - Specifies the level of the information provided. pszFmt - The string to be displayed. ... - A va_list of insertion strings.
Return Value:
None.
--*/ void __cdecl DebugPrintfEx( IN DEBUGLEVEL dwDetail, IN LPSTR pszFmt, ... ) { char szT[1024]; va_list arglist; int len;
va_start(arglist, pszFmt);
//
// Reserve one character for the potential '\n' that we may be adding.
//
StringCchVPrintfA(szT, sizeof(szT) - 1, pszFmt, arglist);
va_end(arglist);
//
// Make sure we have a '\n' at the end of the string
//
len = strlen(szT);
if (len > 0 && szT[len - 1] != '\n') { szT[len] = '\n'; szT[len + 1] = 0; }
switch (dwDetail) { case dlPrint: OutputDebugString("[MSG ] "); break;
case dlError: OutputDebugString("[FAIL] "); break;
case dlWarning: OutputDebugString("[WARN] "); break;
case dlInfo: OutputDebugString("[INFO] "); break;
default: OutputDebugString("[XXXX] "); break; }
OutputDebugString(szT); }
/*++
Routine Description:
Displays command-line syntax to the user.
Arguments:
None.
Return Value:
None.
--*/ void DisplayUsage( void ) { _tprintf(_T("Microsoft(R) Windows(TM) Grab Matching Information\n")); _tprintf(_T("Copyright (C) Microsoft Corporation. All rights reserved.\n"));
_tprintf(_T("\nGrabMI can be used in one of the following ways:\n") _T(" *** The following flags can be used with other flags:\n") _T(" -f, -a, -n, and -h \n") _T(" otherwise the last flag specified will be used.\n") _T(" *** If no arguments are provided, matching information will be\n") _T(" extracted from the current directory.\n\n") _T(" grabmi [path to start generating info ie. c:\\progs]\n") _T(" Grabs matching information from the path specified. Limits the\n") _T(" information gathered to 10 miscellaneous files per directory,\n") _T(" and includes all files with extensions .icd, .exe, .dll,\n") _T(" .msi, ._mp. If a path is not specified, the directory that GrabMI\n") _T(" was executed from is used.\n\n") _T(" grabmi [-d]\n") _T(" Grabs matching information from %%windir%%\\system32\\drivers.\n") _T(" The format of the information is slightly different in this case\n") _T(" and only information for *.sys files will be grabbed.\n\n") _T(" grabmi [-f drive:\\filename.txt]\n") _T(" The matching information is stored in a file specified by the user.\n") _T(" If a full path is not specified and the -d flag is used, the file\n") _T(" is stored in the %%windir%%\\system(32) directory. Otherwise, the file\n") _T(" is stored in the directory that GrabMI was executed from.\n\n") _T(" grabmi [-h or -?]\n") _T(" Displays this help.\n\n") _T(" grabmi [-o]\n") _T(" Grabs information for the file specified. If a file was not specified,\n") _T(" the call will fail. If the destination file exists, then the information\n") _T(" will be concatenated to the end of the existing file.\n\n") _T(" grabmi [-p]\n") _T(" Grabs information for files with .icd, .exe, .dll, .msi, ._mp extensions\n") _T(" only.\n\n") _T(" grabmi [-q]\n") _T(" Grabs matching information and does not display the file when completed.\n\n") _T(" grabmi [-s]\n") _T(" Grabs information for the following system files:\n") _T(" advapi32.dll, gdi32.dll, ntdll.dll, kernel32.dll, winsock.dll\n") _T(" ole32.dll, oleaut32.dll, shell32.dll, user32.dll, and wininet.dll\n\n") _T(" grabmi [-v]\n") _T(" Grabs matching information for all files. \n\n") _T(" grabmi [-a]\n") _T(" Appends new matching information to the existing matching\n") _T(" information file. \n\n") _T(" grabmi [-n]\n") _T(" Allows to more information to be appended the file later (see -a). \n")); }
/*++
Routine Description:
Initializes the application. Saves away common paths and other useful items for later.
Arguments:
None.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL InitializeApplication( void ) { DWORD cchReturned; UINT cchSize; TCHAR* pszTemp = NULL; OSVERSIONINFO osvi;
//
// Initialize our defaults, determine where we're running
// from, and get the version of the OS we're on.
//
*g_ai.szOutputFile = 0; *g_ai.szGrabPath = 0; g_ai.dwFilter = GRABMI_FILTER_NORMAL; g_ai.fDisplayFile = TRUE;
g_ai.szCurrentDir[ARRAYSIZE(g_ai.szCurrentDir) - 1] = 0; cchReturned = GetModuleFileName(NULL, g_ai.szCurrentDir, ARRAYSIZE(g_ai.szCurrentDir));
if (g_ai.szCurrentDir[ARRAYSIZE(g_ai.szCurrentDir) - 1] != 0 || cchReturned == 0) { DPF(dlError, "[InitializeApplication] 0x%08X Failed to get module filename", GetLastError()); return FALSE; }
pszTemp = _tcsrchr(g_ai.szCurrentDir, '\\');
if (pszTemp) { *pszTemp = 0; }
cchSize = GetSystemDirectory(g_ai.szSystemDir, ARRAYSIZE(g_ai.szSystemDir));
if (cchSize > ARRAYSIZE(g_ai.szSystemDir) || cchSize == 0) { DPF(dlError, "[InitializeApplication] 0x%08X Failed to get system directory", GetLastError()); return FALSE; }
ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&osvi)) { DPF(dlError, "[InitializeApplication] 0x%08X Failed to get version info", GetLastError()); return FALSE; }
//
// Determine if we should use apphelp.dll, sdbapiu.dll, or sdbapi.dll.
//
if (osvi.dwMajorVersion >= 5 && osvi.dwMinorVersion >= 1) { //
// Apphelp.dll is available on XP.
//
g_ai.dwLibraryFlags = GRABMI_FLAG_APPHELP; } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { //
// Apphelp.dll is not available on Windows 2000, use sdbapiu.dll.
//
g_ai.dwLibraryFlags = GRABMI_FLAG_NT; } else { //
// Downlevel platforms should use sdbapi.dll.
//
g_ai.dwLibraryFlags = 0; }
return TRUE; }
/*++
Routine Description:
Parses the command-line to determine our mode of operation.
Arguments:
argc - Number command-line of arguments provided by the user. argv[] - An array of command-line arguments.
Return Value:
TRUE if valid arguments were provided, FALSE otherwise.
--*/ BOOL ParseCommandLine( IN int argc, IN TCHAR* argv[] ) { int nCount = 1; HRESULT hr;
if (argc == 1) { return TRUE; }
//
// The first argument should be our starting directory.
//
if ((argv[nCount][0] != '-') && (argv[nCount][0] != '/')) { hr = StringCchCopy(g_ai.szGrabPath, ARRAYSIZE(g_ai.szGrabPath), argv[nCount]);
if (FAILED(hr)) { DPF(dlError, "[ParseCommandLine] Buffer too small (1)"); return FALSE; } }
for (nCount = 1; nCount < argc; nCount++) { if ((argv[nCount][0] == '-') || (argv[nCount][0] == '/')) { switch (argv[nCount][1]) {
case '?': case 'H': case 'h': return FALSE;
case 'F': case 'f': //
// Do a little work to figure out if a file was specified.
//
if (nCount < argc - 1) { if ((argv[nCount + 1][0] == '-') || (argv[nCount + 1][0] == '/')) { return FALSE; } else { //
// Grab the specified path.
//
hr = StringCchCopy(g_ai.szOutputFile, ARRAYSIZE(g_ai.szOutputFile), argv[nCount + 1]);
if (FAILED(hr)) { DPF(dlError, "[ParseCommandLine] Buffer too small (2)"); return FALSE; } } } break;
case 'D': case 'd': g_ai.dwFilter = GRABMI_FILTER_DRIVERS; break;
case 'O': case 'o': g_ai.dwFilter = GRABMI_FILTER_THISFILEONLY; break;
case 'V': case 'v': g_ai.dwFilter = GRABMI_FILTER_VERBOSE; break;
case 'Q': case 'q': g_ai.fDisplayFile = FALSE; break;
case 'P': case 'p': g_ai.dwFilter = GRABMI_FILTER_PRIVACY; break;
case 'S': case 's': g_ai.dwFilter = GRABMI_FILTER_SYSTEM; break;
case 'A': case 'a': g_ai.dwFilterFlags |= GRABMI_FILTER_APPEND; break;
case 'N': case 'n': g_ai.dwFilterFlags |= GRABMI_FILTER_NOCLOSE; break;
default: return FALSE; } } }
return TRUE; }
/*++
Routine Description:
Displays a home-grown "progress bar" to inform the user that the application is working.
Arguments:
See below.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL CALLBACK _GrabmiCallback( IN LPVOID lpvCallbackParam, // application-defined parameter
IN LPCTSTR lpszRoot, // root directory path
IN LPCTSTR lpszRelative, // relative path
IN PATTRINFO pAttrInfo, // attributes
IN LPCWSTR pwszXML // resulting xml
) { static int State = 0; static TCHAR szIcon[] = _T("||//--\\\\");
State = ++State % (ARRAYSIZE(szIcon) - 1); _tcprintf(_T("%c\r"), szIcon[State]);
return TRUE; }
/*++
Routine Description:
Obtains function pointers to the SDB APIs and makes the call that obtains the matching information.
Arguments:
pszOutputFile - Contains the path to the file we will save the results to.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL CallSdbAPIFunctions( IN LPCTSTR pszOutputFile ) { HMODULE hModule; BOOL bResult = FALSE; TCHAR* pszLibrary = NULL; TCHAR szLibraryPath[MAX_PATH]; WCHAR wszGrabPath[MAX_PATH]; WCHAR wszOutputFile[MAX_PATH]; HRESULT hr;
PFNSdbGrabMatchingInfoExA pfnSdbGrabMatchingInfoExA = NULL; PFNSdbGrabMatchingInfoExW pfnSdbGrabMatchingInfoExW = NULL;
if (!pszOutputFile) { DPF(dlError, "[CallSdbAPIFunctions] Invalid argument"); return FALSE; }
//
// Attempt to load files from the current directory first.
// If this fails, attempt to load from %windir%\system.
// We don't call LoadLibrary without a full path because
// it's a security risk.
//
switch (g_ai.dwLibraryFlags) { case GRABMI_FLAG_APPHELP: pszLibrary = APPHELP_LIBRARY; break;
case GRABMI_FLAG_NT: pszLibrary = SDBAPIU_LIBRARY; break;
default: pszLibrary = SDBAPI_LIBRARY; break; }
hr = StringCchPrintf(szLibraryPath, ARRAYSIZE(szLibraryPath), "%s\\%s", g_ai.szCurrentDir, pszLibrary);
if (FAILED(hr)) { DPF(dlError, "[CallSdbAPIFunctions] Buffer too small (1)"); return FALSE; }
hModule = LoadLibrary(szLibraryPath);
if (!hModule) { DPF(dlWarning, "[CallSdbAPIFunctions] Attempt to load %s failed", szLibraryPath);
//
// Attempt to load from the system directory.
//
hr = StringCchPrintf(szLibraryPath, ARRAYSIZE(szLibraryPath), "%s\\%s", g_ai.szSystemDir, pszLibrary);
if (FAILED(hr)) { DPF(dlError, "[CallSdbAPIFunctions] Buffer too small (2)"); return FALSE; }
hModule = LoadLibrary(szLibraryPath);
if (!hModule) { DPF(dlError, "[CallSdbAPIFunctions] 0x%08X Attempt to load %s failed", GetLastError(), szLibraryPath); return FALSE; } }
//
// Get pointers to the functions that we'll be calling.
//
if (0 == g_ai.dwLibraryFlags) { pfnSdbGrabMatchingInfoExA = (PFNSdbGrabMatchingInfoExA)GetProcAddress(hModule, PFN_GMI);
if (!pfnSdbGrabMatchingInfoExA) { DPF(dlError, "[CallSdbAPIFunctions] 0x%08X Failed to get Ansi function pointer", GetLastError()); goto cleanup; } } else { pfnSdbGrabMatchingInfoExW = (PFNSdbGrabMatchingInfoExW)GetProcAddress(hModule, PFN_GMI);
if (!pfnSdbGrabMatchingInfoExW) { DPF(dlError, "[CallSdbAPIFunctions] 0x%08X Failed to get Unicode function pointer", GetLastError()); goto cleanup; }
}
//
// If we're running on NT/W2K/XP, convert strings to Unicode before making
// the function call.
//
if ((g_ai.dwLibraryFlags & GRABMI_FLAG_NT) || (g_ai.dwLibraryFlags & GRABMI_FLAG_APPHELP)) {
if (!MultiByteToWideChar(CP_ACP, 0, g_ai.szGrabPath, -1, wszGrabPath, ARRAYSIZE(wszGrabPath))) { DPF(dlError, "[CallSdbAPIFunctions] 0x%08X Failed to convert %s", GetLastError(), g_ai.szGrabPath); goto cleanup; }
if (!MultiByteToWideChar(CP_ACP, 0, pszOutputFile, -1, wszOutputFile, ARRAYSIZE(wszGrabPath))) { DPF(dlError, "[CallSdbAPIFunctions] 0x%08X Failed to convert %s", GetLastError(), pszOutputFile); goto cleanup; }
}
if (0 == g_ai.dwLibraryFlags) { if (pfnSdbGrabMatchingInfoExA(g_ai.szGrabPath, g_ai.dwFilter | g_ai.dwFilterFlags, pszOutputFile, _GrabmiCallback, NULL) != GMI_SUCCESS) { DPF(dlError, "[CallSdbAPIFunctions] Failed to get matching information (Ansi)"); goto cleanup; } } else { if (pfnSdbGrabMatchingInfoExW(wszGrabPath, g_ai.dwFilter | g_ai.dwFilterFlags, wszOutputFile, _GrabmiCallback, NULL) != GMI_SUCCESS) { DPF(dlError, "[CallSdbAPIFunctions] Failed to get matching information (Unicode)"); goto cleanup; } }
bResult = TRUE;
cleanup:
FreeLibrary(hModule);
return bResult; }
/*++
Routine Description:
Displays the contents of the output file to the user.
Arguments:
pszOutputFile - Contains the path to the file we will show to the user.
Return Value:
TRUE on success, FALSE otherwise.
--*/ BOOL DisplayOutputFile( IN LPTSTR pszOutputFile ) { const TCHAR szWrite[] = "write"; const TCHAR szNotepad[] = "notepad"; int cchSize; TCHAR* pszCmdLine = NULL; BOOL bReturn;
STARTUPINFO si; PROCESS_INFORMATION pi;
if (!pszOutputFile) { DPF(dlError, "[DisplayOuputFile] Invalid argument"); return FALSE; }
cchSize = _tcslen(pszOutputFile); cchSize += _tcslen(szNotepad); cchSize += 4; // space, two " marks, and a NULL
pszCmdLine = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cchSize * sizeof(TCHAR));
if (!pszCmdLine) { DPF(dlError, "[DisplayOutputFile] Failed to allocate memory"); return FALSE; }
StringCchPrintf(pszCmdLine, cchSize, "%s \"%s\"", g_ai.dwLibraryFlags ? szNotepad : szWrite, pszOutputFile);
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO);
//
// BUGBUG: Need to pass lpApplicationName also.
//
bReturn = CreateProcess(NULL, pszCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (pi.hThread) { CloseHandle(pi.hThread); }
if (pi.hProcess) { CloseHandle(pi.hProcess); }
HeapFree(GetProcessHeap(), 0, pszCmdLine);
return bReturn; }
/*++
Routine Description:
Application entry point.
Arguments:
argc - Number command-line of arguments provided by the user. argv[] - An array of command-line arguments.
Return Value:
0 on failure, 1 on success.
--*/ int __cdecl main( IN int argc, IN TCHAR* argv[] ) { TCHAR szOutputFile[MAX_PATH]; HRESULT hr;
//
// Perform some initialization.
//
if (!InitializeApplication()) { DPF(dlError, "[main] Failed to initialize the application"); _tprintf("An error occured while initializing the application\n"); return 0; }
//
// Parse the command-line and determine our mode of operation.
//
if (!ParseCommandLine(argc, argv)) { DPF(dlError, "[main] Invalid command-line arguments provided"); DisplayUsage(); return 0; }
//
// Sanity check here...can't specify a directory name and use the
// -d flag (drivers) at the same time.
//
if (*g_ai.szGrabPath && g_ai.dwFilter == GRABMI_FILTER_DRIVERS) { _tprintf("Invalid syntax - can't use directory and -d flag together\n\n"); DisplayUsage(); return 0; }
//
// If the user did not specify a destination file, default to
// %windir%\system32\matchinginfo.txt.
//
if (!*g_ai.szOutputFile) { hr = StringCchPrintf(szOutputFile, ARRAYSIZE(szOutputFile), "%s\\"MATCHINGINFO_FILENAME, g_ai.szSystemDir);
if (FAILED(hr)) { DPF(dlError, "[main] Buffer too small for output file"); _tprintf("An error occured while formatting the output file location"); return 0; } } else { hr = StringCchCopy(szOutputFile, ARRAYSIZE(szOutputFile), g_ai.szOutputFile);
if (FAILED(hr)) { DPF(dlError, "[main] Buffer too small for specified output file"); _tprintf("An error occured while formatting the output file location"); return 0; } }
//
// If no starting path was specified, check the filter specified
// and go to the system or current directory.
//
if (!*g_ai.szGrabPath) { if (GRABMI_FILTER_DRIVERS == g_ai.dwFilter) { hr = StringCchPrintf(g_ai.szGrabPath, ARRAYSIZE(g_ai.szGrabPath), "%s\\drivers", g_ai.szSystemDir);
if (FAILED(hr)) { DPF(dlError, "[main] Buffer too small for grab path"); _tprintf("An error occured while formatting the starting directory location"); return 0; } } else { hr = StringCchCopy(g_ai.szGrabPath, ARRAYSIZE(g_ai.szGrabPath), g_ai.szCurrentDir);
if (FAILED(hr)) { DPF(dlError, "[main] Buffer too small for specified grab path"); _tprintf("An error occured while formatting the starting directory location"); return 0; } } }
//
// Obtain pointers to functions within our libraries and perform
// the grunt of the work.
//
if (!CallSdbAPIFunctions(szOutputFile)) { DPF(dlError, "[main] Failed to call the Sdb API functions"); _tprintf("An error occured while attempting to get matching information"); return 0; }
//
// Success - inform the user and display the file if requested.
//
_tprintf("Matching information retrieved successfully\n");
if (g_ai.fDisplayFile) { if (!DisplayOutputFile(szOutputFile)) { DPF(dlError, "[main] Failed to display output file %s", szOutputFile); return 0; } }
return 1; }
|