/*++ Copyright (c) 2000 Microsoft Corporation Module Name: GrabMatchingInformation.cpp Abstract: Upon ProcessAttach the shim gathers matching information from the current directory. Notes: This is a general purpose shim. History: 20-Oct-2000 jdoherty Created --*/ #include "precomp.h" #include // This module is *not* DBCS safe, but should only be used by our testers // We should, eventually, correct this file. // This module has been given an official blessing to use the str routines. #include "LegalStr.h" IMPLEMENT_SHIM_BEGIN(GrabMatchingInformation) #include "ShimHookMacro.h" APIHOOK_ENUM_BEGIN APIHOOK_ENUM_ENTRY(GetCommandLineA) APIHOOK_ENUM_ENTRY(GetCommandLineW) APIHOOK_ENUM_END BOOL gbCalledHook; LPSTR glpOriginalRootDir; VOID GrabMatchingInformationMain(); BOOL GrabMatchingInfo(LPSTR lpRootDirectory, HANDLE hStorageFile, int nLevel); BOOL GetRelativePath(LPSTR lpPathFromRoot, LPCSTR lpSubDir, LPCSTR lpFileName); VOID AddMatchingFile( LPSTR lpData, LPCSTR pszFullPath, LPCSTR pszRelativePath ); LPSTR APIHOOK(GetCommandLineA)() { if (!gbCalledHook) { int nLength = 0; LPSTR lpCursorEnd; glpOriginalRootDir = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); GetModuleFileNameA( NULL, glpOriginalRootDir, MAX_PATH ); nLength = strlen( glpOriginalRootDir ); lpCursorEnd = &glpOriginalRootDir[nLength-1]; while( --nLength ) { if ( *(lpCursorEnd) == '\\' ) { *(lpCursorEnd) = '\0'; break; } lpCursorEnd--; if (nLength==0) { GetCurrentDirectoryA( MAX_PATH, glpOriginalRootDir ); } } GrabMatchingInformationMain(); ShimFree(glpOriginalRootDir); gbCalledHook = TRUE; } return ORIGINAL_API(GetCommandLineA)(); } LPWSTR APIHOOK(GetCommandLineW)() { if (!gbCalledHook) { int nLength = 0; LPSTR lpCursorEnd; glpOriginalRootDir = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); GetModuleFileNameA( NULL, glpOriginalRootDir, MAX_PATH ); nLength = strlen( glpOriginalRootDir ); lpCursorEnd = &glpOriginalRootDir[nLength-1]; while( --nLength ) { if ( *(lpCursorEnd) == '\\' ) { *(lpCursorEnd) = '\0'; break; } lpCursorEnd--; if (nLength==0) { GetCurrentDirectoryA( MAX_PATH, glpOriginalRootDir ); } } GrabMatchingInformationMain(); ShimFree(glpOriginalRootDir); gbCalledHook = TRUE; } return ORIGINAL_API(GetCommandLineW)(); } VOID GrabMatchingInformationMain() { HANDLE hMutexHandle; LPSTR lpStorageFilePath; LPSTR lpDirInfo; LPSTR lpRootDir; HANDLE hStorageFile; DWORD dwBytesWritten = 0; lpStorageFilePath = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); lpDirInfo = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); lpRootDir = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); // Setup a mutex so only one process at a time can write to the matchinginfo.txt file. hMutexHandle = CreateMutexA( NULL, FALSE, "MyGrabMIFileMutex" ); WaitForSingleObject( hMutexHandle, INFINITE ); // Build path to where the matching information will be stored. SHGetSpecialFolderPathA(NULL, lpStorageFilePath, CSIDL_DESKTOPDIRECTORY, TRUE ); strcat( lpStorageFilePath, "\\matchinginfo.txt" ); /* if ( (strcmp(glpOriginalRootDir ,".") == 0) || (strcmp(glpOriginalRootDir ,"") == 0) ) { GetCurrentDirectoryA( MAX_PATH, glpOriginalRootDir ); } */ // Open matchinginfo.txt on the desktop for write if it exists and set the file pointer to the end // of the file, create a new file otherwise. hStorageFile = CreateFileA( lpStorageFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); SetFilePointer( hStorageFile, NULL, NULL, FILE_END ); if (hStorageFile == INVALID_HANDLE_VALUE) { return; } sprintf(lpDirInfo, "\r\n", glpOriginalRootDir, GetCommandLineA() ); WriteFile( hStorageFile, lpDirInfo, strlen(lpDirInfo), &dwBytesWritten, NULL ); strcpy(lpRootDir, glpOriginalRootDir); if (!GrabMatchingInfo(lpRootDir, hStorageFile, 0)) { CloseHandle(hStorageFile); return; } CloseHandle(hStorageFile); ShimFree(lpStorageFilePath); ShimFree(lpDirInfo); ShimFree(lpRootDir); ReleaseMutex( hMutexHandle ); return; } /*++ This function traverses lpRootDirectory and it's subdirectories while storing the size and checksum for the files in those directories. --*/ BOOL GrabMatchingInfo(LPSTR lpRootDirectory, HANDLE hStorageFile, int nLevel) { WIN32_FIND_DATAA FindFileData; HANDLE hSearch; // Search handle returned by FindFirstFile LPSTR lpSubDir; LPSTR lpFilePath; LPSTR lpData; LPSTR lpPathFromRoot; DWORD dwBytesWritten = 0; int cbFileCounter = 0; lpSubDir = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); lpFilePath = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); lpData = (LPSTR) ShimMalloc((MAX_PATH*2)*sizeof(LPSTR)); lpPathFromRoot = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); // Just repeat displaying a dot so the user knows something is happening. // USED IN GRABMI // printf("."); strcpy (lpSubDir, lpRootDirectory); strcat(lpRootDirectory, "\\*"); if ( (hSearch=FindFirstFileA( lpRootDirectory, &FindFileData )) == INVALID_HANDLE_VALUE ) { return FALSE; } BOOL bRepeat = FALSE; while ( (strcmp( FindFileData.cFileName, "." ) == 0) || (strcmp( FindFileData.cFileName, ".." ) == 0) && !bRepeat ) { FindNextFileA(hSearch, &FindFileData); if ( strcmp( FindFileData.cFileName, ".." ) == 0 ) bRepeat = TRUE; } if (!FindNextFileA(hSearch, &FindFileData)) { return TRUE; } do { if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { // Build path for matching file strcpy(lpFilePath, lpSubDir); strcat(lpFilePath, "\\"); strcat(lpFilePath, FindFileData.cFileName); ZeroMemory( lpData, (MAX_PATH*2)*sizeof(LPSTR) ); // Determine the relative path for the file from the original root directory. if (!GetRelativePath(lpPathFromRoot, lpSubDir, FindFileData.cFileName)) strcpy(lpPathFromRoot, FindFileData.cFileName); // Check to see if there is version information for the specified file and whether it is // an .exe, .icd, ._MP, or .dll. If so add the information to the file. if ( stristr(lpFilePath, ".exe") || stristr(lpFilePath, ".icd") || stristr(lpFilePath, "._MP") || stristr(lpFilePath, ".dll") ) { AddMatchingFile( lpData, lpFilePath, lpPathFromRoot ); } else { // Limit the amount of info gathered to 10 files per directory excluding the above file types. if (cbFileCounter < 10) { cbFileCounter++; AddMatchingFile( lpData, lpFilePath, lpPathFromRoot ); } } // Write the information stored in lpData to the file WriteFile( hStorageFile, lpData, strlen(lpData), &dwBytesWritten, NULL ); } } while ( FindNextFileA( hSearch, &FindFileData ) ); ///////////////////////////////////////////////////////////////////////////////// // // Now go through the directory again and go into the subdirectories // ///////////////////////////////////////////////////////////////////////////////// if (strlen(lpRootDirectory) < 4) { if ( (hSearch=FindFirstFileA(lpRootDirectory, &FindFileData)) == INVALID_HANDLE_VALUE) { return FALSE; } } else { if ( (hSearch=FindFirstFileA(lpRootDirectory, &FindFileData)) == INVALID_HANDLE_VALUE) { return FALSE; } FindNextFileA(hSearch, &FindFileData); if (!FindNextFileA(hSearch, &FindFileData)) { FindClose( hSearch ); return TRUE; } } do { if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && nLevel < 3) { strcat(lpSubDir, "\\"); strcat(lpSubDir, FindFileData.cFileName); GrabMatchingInfo (lpSubDir, hStorageFile, nLevel+1); lpSubDir[strlen(lpSubDir)-2]='\0'; strcpy(lpSubDir, lpRootDirectory); lpSubDir[strlen(lpSubDir)-2]='\0'; } }while ( FindNextFileA( hSearch, &FindFileData ) ); FindClose(hSearch); ShimFree(lpSubDir); ShimFree(lpFilePath); ShimFree(lpData); ShimFree(lpPathFromRoot); return TRUE; } BOOL GetRelativePath(LPSTR lpPathFromRoot, LPCSTR lpSubDir, LPCSTR lpFileName) { int difference=(strlen(lpSubDir)-strlen(glpOriginalRootDir)); if (difference) { for (int i=0; i < difference; i++) { lpPathFromRoot[i] = lpSubDir[strlen(glpOriginalRootDir)+i+1]; } strcat(lpPathFromRoot, "\\"); strcat(lpPathFromRoot, lpFileName); difference=0; return TRUE; } return FALSE; } /*++ AddMatchingFile Description: Adds a matching file and it's attributes to the tree. --*/ VOID AddMatchingFile( OUT LPSTR lpData, IN LPCSTR pszFullPath, IN LPCSTR pszRelativePath ) { PATTRINFO pAttrInfo; DWORD dwAttrCount; LPWSTR pwszFullPath; pwszFullPath = (LPWSTR) ShimMalloc(MAX_PATH*sizeof(LPWSTR)); mbstowcs( pwszFullPath, pszFullPath, MAX_PATH ); // // Call the attribute manager to get all the attributes for this file. // if (SdbGetFileAttributes(pwszFullPath, &pAttrInfo, &dwAttrCount)) { LPSTR lpBuffer; LPWSTR lpwBuffer; lpBuffer = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR)); lpwBuffer = (LPWSTR) ShimMalloc(MAX_PATH*sizeof(LPWSTR)); // // Loop through all the attributes and show the ones that are available. // // ZeroMemory( lpData, (MAX_PATH*2)*sizeof(LPSTR) ); sprintf(lpData, "\r\n" ); ShimFree( lpBuffer ); ShimFree( lpwBuffer ); SdbFreeFileAttributes(pAttrInfo); } ShimFree( pwszFullPath ); } /*++ Handle DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH in your notify function to do initialization and uninitialization. IMPORTANT: Make sure you ONLY call NTDLL, KERNEL32 and MSVCRT APIs during DLL_PROCESS_ATTACH notification. No other DLLs are initialized at that point. If your shim cannot initialize properly, return FALSE and none of the APIs specified will be hooked. --*/ BOOL NOTIFY_FUNCTION( DWORD fdwReason) { if (fdwReason == DLL_PROCESS_ATTACH) { gbCalledHook = FALSE; DPFN( eDbgLevelInfo, "Beginng to Grab Information."); } return TRUE; } /*++ Register hooked functions --*/ HOOK_BEGIN APIHOOK_ENTRY(KERNEL32.DLL, GetCommandLineA) APIHOOK_ENTRY(KERNEL32.DLL, GetCommandLineW) CALL_NOTIFY_FUNCTION HOOK_END IMPLEMENT_SHIM_END