#include #include #include #include #include #include #define MAP_LEADING_SIGNATURE 0xABCD #define MAP_TRAILING_SIGNATURE 0xDCBA typedef std::vector > XFilesMap; DWORD ReadMapFile(const wchar_t *sFilename, XFilesMap &aPageMap, XFilesMap & aPhysFreeList); DWORD DumpHeapAdminPages(const wchar_t *sFilename, XFilesMap &aHeapMap, XFilesMap &aHeapFreeList); DWORD GetHeapManagedPageCount(const wchar_t *sFilename, XFilesMap &aHeapMap, DWORD &dwNumAdminPages, DWORD &dwNumMultiBlockPages, DWORD &dwNumMultiBlockObjects); DWORD GetMapUsageCount(XFilesMap &aHeapMap, DWORD &dwHeapMapUsed, DWORD &dwHeapMapFree); DWORD DumpMap(XFilesMap &aMap); void __cdecl main(int argc, char *argv[ ]) { printf("WMI XFiles repository dumper\n\n"); bool bDumpHeapAdminPage = false; bool bDumpTreeMap = false; bool bDumpHeapMap = false; for (int i = 1; i != argc; i++) { if ((_stricmp(argv[i], "/?") == 0) || (_stricmp(argv[i], "-?") == 0)) { printf("Usage: DumpTool.exe /? - display this message\n" " DumpTool.exe /DumpAdminPages - dumps the heap admin tables\n" " DumpTool.exe /DumpTreeMap - dumps the tree map usage\n" " DumpTool.exe /DumpHeapMap - dumps the heap map usage\n"); return; } else if (_stricmp(argv[i], "/DumpAdminPages") == 0) { bDumpHeapAdminPage = true; } else if (_stricmp(argv[i], "/DumpTreeMap") == 0) { bDumpTreeMap = true; } else if (_stricmp(argv[i], "/DumpHeapMap") == 0) { bDumpHeapMap = true; } } DWORD dwRet; XFilesMap aBTreeMap; XFilesMap aBTreeFreeList; DWORD dwBTreeSize = 0; DWORD dwBTreeUsed = 0; DWORD dwBTreeFree = 0; XFilesMap aHeapMap; XFilesMap aHeapFreeList; DWORD dwHeapSize = 0; DWORD dwHeapUsed = 0; DWORD dwHeapFree = 0; //Read MAP Files dwRet = ReadMapFile(L"index.map", aBTreeMap, aBTreeFreeList); if (dwRet) { printf("Failed to retrieve index.map details. Please run from within the repository\\fs directory\n"); return; } GetMapUsageCount(aBTreeMap, dwBTreeUsed, dwBTreeFree); dwRet = ReadMapFile(L"objects.map", aHeapMap, aHeapFreeList); if (dwRet) { printf("Failed to retrieve objects.map details. Please run from within the repository\\fs directory\n"); return; } GetMapUsageCount(aHeapMap, dwHeapUsed, dwHeapFree); WIN32_FILE_ATTRIBUTE_DATA fileInfo; dwRet = GetFileAttributesEx(L"INDEX.BTR", GetFileExInfoStandard, &fileInfo); if (dwRet == 0) { printf("Failed to retrieve size of index.btr file\n"); return; } dwBTreeSize = fileInfo.nFileSizeLow / WMIREP_PAGE_SIZE; dwRet = GetFileAttributesEx(L"OBJECTS.DATA", GetFileExInfoStandard, &fileInfo); if (dwRet == 0) { printf("Failed to retrieve size of objects.data file\n"); return; } dwHeapSize = fileInfo.nFileSizeLow / WMIREP_PAGE_SIZE; //Dump MAP file usage and free space sumary printf("BTree has %lu pages in it, of which %lu pages are in use and %lu pages are free\n", dwBTreeSize, dwBTreeUsed, dwBTreeSize - dwBTreeUsed); printf("Heap has %lu pages in it, of which %lu pages are in use and %lu pages are free\n", dwHeapSize, dwHeapUsed, dwHeapSize - dwHeapUsed); //Get number of managed pages for heap... DWORD dwNumAdminPages = 0; DWORD dwNumMultiBlockPages = 0; DWORD dwNumMultiBlockObjects = 0; dwRet = GetHeapManagedPageCount(L"OBJECTS.DATA", aHeapMap, dwNumAdminPages, dwNumMultiBlockPages, dwNumMultiBlockObjects); if (dwRet) { printf("Failed to retrieve number of pages used in object heap\n"); return; } printf("Heap has %lu admin pages, \n\t%lu pages used for small block allocation, total of %lu small block allocations, \n\t%lu pages for large block allocations\n", dwNumAdminPages, dwNumMultiBlockPages, dwNumMultiBlockObjects, dwHeapSize - (dwHeapSize - dwHeapUsed) - dwNumAdminPages - dwNumMultiBlockPages); if (bDumpHeapAdminPage) { dwRet = DumpHeapAdminPages(L"OBJECTS.DATA", aHeapMap, aHeapFreeList); if (dwRet) { printf("Failed to dump the admin pages in the heap\n"); return; } } if (bDumpTreeMap) { printf("**** BTree MAP Usage ****\n"); DumpMap(aBTreeMap); } if (bDumpHeapMap) { printf("**** Heap MAP Usage ****\n"); DumpMap(aHeapMap); } } DWORD ReadMapFile(const wchar_t *sFilename, XFilesMap &aPageMap,XFilesMap & aPhysFreeList) { BOOL bRes; HANDLE hFile = CreateFileW(sFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { DWORD dwRet = GetLastError(); return dwRet; } AutoClose _(hFile); // If here, read it. // ================= DWORD dwSignature = 0; DWORD dwRead = 0; bRes = ReadFile(hFile, &dwSignature, sizeof(DWORD), &dwRead, 0); if (!bRes || dwRead != sizeof(DWORD) || dwSignature != MAP_LEADING_SIGNATURE) { return ERROR_INVALID_DATA; } // Read transaction version. // ========================= DWORD dwTransVersion; bRes = ReadFile(hFile, &dwTransVersion, sizeof(DWORD), &dwRead, 0); if (!bRes || dwRead != sizeof(DWORD)) { return ERROR_INVALID_DATA; } // Read in physical page count. // ============================ DWORD dwPhysPages; bRes = ReadFile(hFile, &dwPhysPages, sizeof(DWORD), &dwRead, 0); if (!bRes || dwRead != sizeof(DWORD)) { return ERROR_INVALID_DATA; } // Read in the page map length and page map. // ========================================= DWORD dwNumPages = 0; bRes = ReadFile(hFile, &dwNumPages, sizeof(DWORD), &dwRead, 0); if (!bRes || dwRead != sizeof(DWORD)) { return ERROR_INVALID_DATA; } try { aPageMap.resize(dwNumPages); } catch (CX_MemoryException &) { return ERROR_OUTOFMEMORY; } bRes = ReadFile(hFile, &aPageMap[0], sizeof(DWORD)*dwNumPages, &dwRead, 0); if (!bRes || dwRead != sizeof(DWORD)*dwNumPages) return ERROR_INVALID_DATA; // Now, read in the physical free list. // ==================================== DWORD dwFreeListSize = 0; bRes = ReadFile(hFile, &dwFreeListSize, sizeof(DWORD), &dwRead, 0); if (!bRes || dwRead != sizeof(DWORD)) { return ERROR_INVALID_DATA; } try { aPhysFreeList.resize(dwFreeListSize); } catch (CX_MemoryException &) { return ERROR_OUTOFMEMORY; } bRes = ReadFile(hFile, &aPhysFreeList[0], sizeof(DWORD)*dwFreeListSize, &dwRead, 0); if (!bRes || dwRead != sizeof(DWORD)*dwFreeListSize) { return ERROR_INVALID_DATA; } // Read trailing signature. // ======================== bRes = ReadFile(hFile, &dwSignature, sizeof(DWORD), &dwRead, 0); if (!bRes || dwRead != sizeof(DWORD) || dwSignature != MAP_TRAILING_SIGNATURE) { return ERROR_INVALID_DATA; } return ERROR_SUCCESS; } DWORD DumpHeapAdminPages(const wchar_t *sFilename, XFilesMap &aHeapMap, XFilesMap &aHeapFreeList) { //Open the file... HANDLE hFile = CreateFile(sFilename, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,NULL); if (hFile == INVALID_HANDLE_VALUE) return GetLastError(); HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hMapping == NULL) { DWORD dwErr = GetLastError(); CloseHandle(hFile); return dwErr; } BYTE *pObj = (BYTE *)MapViewOfFile(hMapping, FILE_MAP_READ, 0,0,0); if (pObj == NULL) { DWORD dwErr = GetLastError(); CloseHandle(hMapping); CloseHandle(hFile); return dwErr;; } //Do stuff... DWORD dwVirtualPageId = 0; DWORD dwTotalObjectCount = 0; printf("Heap admin page dump...\n"); do { DWORD dwPhysicalPageId = aHeapMap[dwVirtualPageId]; VarObjHeapAdminPage *pAdminPageHeader = (VarObjHeapAdminPage *)(pObj + (dwPhysicalPageId * WMIREP_PAGE_SIZE)); VarObjHeapFreeList *pAdminPageEntry = (VarObjHeapFreeList *)((BYTE*)pAdminPageHeader + sizeof(VarObjHeapAdminPage)); printf("Admin page %lu (physical page %lu): number of page entries %lu\n", dwVirtualPageId, dwPhysicalPageId, pAdminPageHeader->dwNumberEntriesOnPage); for (DWORD dwIndex = 0; dwIndex != pAdminPageHeader->dwNumberEntriesOnPage; dwIndex++) { DWORD dwNumObjectsOnPage = 0; VarObjObjOffsetEntry *pObjPage = (VarObjObjOffsetEntry*)(pObj + (aHeapMap[pAdminPageEntry[dwIndex].dwPageId] * WMIREP_PAGE_SIZE)); for (DWORD dwIndex2 = 0; pObjPage[dwIndex2].dwOffsetId != 0; dwIndex2++) { dwNumObjectsOnPage++; } printf("\tPage % 6lu (physical page % 6lu): %4lu bytes free (% 2lu%%), %4lu objects on page\n", pAdminPageEntry[dwIndex].dwPageId, aHeapMap[pAdminPageEntry[dwIndex].dwPageId], pAdminPageEntry[dwIndex].dwFreeSpace, (pAdminPageEntry[dwIndex].dwFreeSpace * 100) / WMIREP_PAGE_SIZE, dwNumObjectsOnPage); } dwVirtualPageId = pAdminPageHeader->dwNextAdminPage; } while (dwVirtualPageId != 0); //Tidy up UnmapViewOfFile(pObj); CloseHandle(hMapping); CloseHandle(hFile); return ERROR_SUCCESS; } DWORD GetHeapManagedPageCount(const wchar_t *sFilename, XFilesMap &aHeapMap, DWORD &dwNumAdminPages, DWORD &dwNumMultiBlockPages, DWORD &dwNumMultiBlockObjects) { //Open the file... HANDLE hFile = CreateFile(sFilename, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,NULL); if (hFile == INVALID_HANDLE_VALUE) return GetLastError(); HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hMapping == NULL) { DWORD dwErr = GetLastError(); CloseHandle(hFile); return dwErr; } BYTE *pObj = (BYTE *)MapViewOfFile(hMapping, FILE_MAP_READ, 0,0,0); if (pObj == NULL) { DWORD dwErr = GetLastError(); CloseHandle(hMapping); CloseHandle(hFile); return dwErr;; } //Do stuff... DWORD dwVirtualPageId = 0; do { dwNumAdminPages++; DWORD dwPhysicalPageId = aHeapMap[dwVirtualPageId]; VarObjHeapAdminPage *pAdminPageHeader = (VarObjHeapAdminPage *)(pObj + (dwPhysicalPageId * WMIREP_PAGE_SIZE)); VarObjHeapFreeList *pAdminPageEntry = (VarObjHeapFreeList *)((BYTE*)pAdminPageHeader + sizeof(VarObjHeapAdminPage)); for (DWORD dwIndex = 0; dwIndex != pAdminPageHeader->dwNumberEntriesOnPage; dwIndex++) { dwNumMultiBlockPages++; DWORD dwNumObjectsOnPage = 0; VarObjObjOffsetEntry *pObjPage = (VarObjObjOffsetEntry*)(pObj + (aHeapMap[pAdminPageEntry[dwIndex].dwPageId] * WMIREP_PAGE_SIZE)); for (DWORD dwIndex2 = 0; pObjPage[dwIndex2].dwOffsetId != 0; dwIndex2++) { dwNumMultiBlockObjects++; } } dwVirtualPageId = pAdminPageHeader->dwNextAdminPage; } while (dwVirtualPageId != 0); //Tidy up UnmapViewOfFile(pObj); CloseHandle(hMapping); CloseHandle(hFile); return ERROR_SUCCESS; } DWORD GetMapUsageCount(XFilesMap &aMap, DWORD &dwMapUsed, DWORD &dwMapFree) { for (DWORD i = 0; i < aMap.size(); i++) { if (aMap[i] == WMIREP_INVALID_PAGE) dwMapFree++; else dwMapUsed++; } return ERROR_SUCCESS; } void ShellSort(XFilesMap &Array) { for (int nInterval = 1; nInterval < Array.size() / 9; nInterval = nInterval * 3 + 1); while (nInterval) { for (int iCursor = nInterval; iCursor < Array.size(); iCursor++) { int iBackscan = iCursor; while (iBackscan - nInterval >= 0 && Array[iBackscan] < Array[iBackscan-nInterval]) { DWORD dwTemp = Array[iBackscan-nInterval]; Array[iBackscan-nInterval] = Array[iBackscan]; Array[iBackscan] = dwTemp; iBackscan -= nInterval; } } nInterval /= 3; } } DWORD DumpMap(XFilesMap &aMap) { //Need to sort it... and need our own copy... XFilesMap aNewMap = aMap; ShellSort(aNewMap); printf("**** Usage dump... **** \n"); DWORD dwStartId = aNewMap[0]; for (DWORD dwOffset = 1; dwOffset < aNewMap.size(); dwOffset++) { if (dwStartId == 0xFFFFFFFF) break; //Work up to the end of this run for (DWORD dwCurrentRun = 1; (dwStartId+dwCurrentRun) == aNewMap[dwOffset]; dwOffset++, dwCurrentRun++) { } //Finished slot... dump usage use if (dwStartId == aNewMap[dwOffset-1]) { //Single location slot... printf("% 6lu Used\n", dwStartId); } else { //Multiple location slot... printf("% 6lu - % 6lu Used\n", dwStartId, aNewMap[dwOffset-1]); } if (dwOffset+1 <= aNewMap.size()) { //Dump free space usage now if (aNewMap[dwOffset-1]+1 == aNewMap[dwOffset]-1) { //Single location slot... printf("% 6lu Free\n", aNewMap[dwOffset-1]+1); } else { //Multiple location slot... printf("% 6lu - % 6lu Free\n", aNewMap[dwOffset-1]+1, aNewMap[dwOffset]-1); } dwStartId = aNewMap[dwOffset]; } } return ERROR_SUCCESS; }