Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

844 lines
24 KiB

/*++
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;
}