/* * Process Hacker Extra Plugins - * NT Atom Table Plugin * * Copyright (C) 2015 dmex * * This file is part of Process Hacker. * * Process Hacker is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Process Hacker is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Process Hacker. If not, see . */ #define CINTERFACE #define COBJMACROS #include #include #include "resource.h" #define ATOM_TABLE_MENUITEM 1000 #define PLUGIN_NAME L"dmex.AtomTablePlugin" #define SETTING_NAME_WINDOW_POSITION (PLUGIN_NAME L".WindowPosition") #define SETTING_NAME_WINDOW_SIZE (PLUGIN_NAME L".WindowSize") #define SETTING_NAME_LISTVIEW_COLUMNS (PLUGIN_NAME L".ListViewColumns") static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; static PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration; static HWND ListViewWndHandle; static PH_LAYOUT_MANAGER LayoutManager; static PPH_PLUGIN PluginInstance; NTSTATUS PhEnumAtomTable( _Out_ PATOM_TABLE_INFORMATION* AtomTable ) { NTSTATUS status; PVOID buffer; ULONG bufferSize = 0x1000; buffer = PhAllocate(bufferSize); memset(buffer, 0, bufferSize); status = NtQueryInformationAtom( RTL_ATOM_INVALID_ATOM, AtomTableInformation, buffer, bufferSize, &bufferSize // Not used... ); if (!NT_SUCCESS(status)) { PhFree(buffer); return status; } *AtomTable = buffer; return status; } NTSTATUS PhQueryAtomTableEntry( _In_ RTL_ATOM Atom, _Out_ PATOM_BASIC_INFORMATION* AtomInfo ) { NTSTATUS status; PVOID buffer; ULONG bufferSize = 0x1000; buffer = PhAllocate(bufferSize); memset(buffer, 0, bufferSize); status = NtQueryInformationAtom( Atom, AtomBasicInformation, buffer, bufferSize, &bufferSize // Not used... ); if (!NT_SUCCESS(status)) { PhFree(buffer); return status; } *AtomInfo = buffer; return status; } VOID LoadAtomTable(VOID) { PATOM_TABLE_INFORMATION atomTable = NULL; if (!NT_SUCCESS(PhEnumAtomTable(&atomTable))) return; ExtendedListView_SetRedraw(ListViewWndHandle, FALSE); ListView_DeleteAllItems(ListViewWndHandle); for (ULONG i = 0; i < atomTable->NumberOfAtoms; i++) { PATOM_BASIC_INFORMATION atomInfo = NULL; if (!NT_SUCCESS(PhQueryAtomTableEntry(atomTable->Atoms[i], &atomInfo))) { PhAddListViewItem(ListViewWndHandle, MAXINT, PhaFormatString(L"(Error) #%lu", i)->Buffer, NULL); continue; } if ((atomInfo->Flags & RTL_ATOM_PINNED) == RTL_ATOM_PINNED) { INT index = PhAddListViewItem( ListViewWndHandle, MAXINT, PhaFormatString(L"%s (Pinned)", atomInfo->Name)->Buffer, NULL ); PhSetListViewSubItem( ListViewWndHandle, index, 1, PhaFormatString(L"%u", atomInfo->UsageCount)->Buffer ); } else { INT index = PhAddListViewItem( ListViewWndHandle, MAXINT, atomInfo->Name, NULL ); PhSetListViewSubItem( ListViewWndHandle, index, 1, PhaFormatString(L"%u", atomInfo->UsageCount)->Buffer ); } PhFree(atomInfo); } ExtendedListView_SetRedraw(ListViewWndHandle, TRUE); PhFree(atomTable); } PPH_STRING PhGetSelectedListViewItemText( _In_ HWND hWnd ) { INT index = PhFindListViewItemByFlags( hWnd, -1, LVNI_SELECTED ); if (index != -1) { WCHAR textBuffer[MAX_PATH] = L""; LVITEM item; item.mask = LVIF_TEXT; item.iItem = index; item.iSubItem = 0; item.pszText = textBuffer; item.cchTextMax = MAX_PATH; if (ListView_GetItem(hWnd, &item)) return PhCreateString(textBuffer); } return NULL; } VOID ShowStatusMenu( _In_ HWND hwndDlg ) { PPH_STRING cacheEntryName; cacheEntryName = PhGetSelectedListViewItemText(ListViewWndHandle); if (cacheEntryName) { POINT cursorPos; PPH_EMENU menu; PPH_EMENU_ITEM selectedItem; GetCursorPos(&cursorPos); menu = PhCreateEMenu(); PhInsertEMenuItem(menu, PhCreateEMenuItem(0, 1, L"Remove", NULL, NULL), -1); selectedItem = PhShowEMenu( menu, ListViewWndHandle, PH_EMENU_SHOW_LEFTRIGHT, PH_ALIGN_LEFT | PH_ALIGN_TOP, cursorPos.x, cursorPos.y ); if (selectedItem && selectedItem->Id != -1) { switch (selectedItem->Id) { case 1: { INT lvItemIndex = PhFindListViewItemByFlags( ListViewWndHandle, -1, LVNI_SELECTED ); if (lvItemIndex != -1) { if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage( hwndDlg, L"remove", cacheEntryName->Buffer, NULL, FALSE )) { PATOM_TABLE_INFORMATION atomTable = NULL; if (!NT_SUCCESS(PhEnumAtomTable(&atomTable))) return; for (ULONG i = 0; i < atomTable->NumberOfAtoms; i++) { PATOM_BASIC_INFORMATION atomInfo = NULL; if (!NT_SUCCESS(PhQueryAtomTableEntry(atomTable->Atoms[i], &atomInfo))) continue; if (!PhEqualStringZ(atomInfo->Name, cacheEntryName->Buffer, TRUE)) continue; do { if (!NT_SUCCESS(NtDeleteAtom(atomTable->Atoms[i]))) { break; } PhFree(atomInfo); atomInfo = NULL; if (!NT_SUCCESS(PhQueryAtomTableEntry(atomTable->Atoms[i], &atomInfo))) break; } while (atomInfo->UsageCount >= 1); ListView_DeleteItem(ListViewWndHandle, lvItemIndex); if (atomInfo) { PhFree(atomInfo); } } PhFree(atomTable); } } } break; } } PhDestroyEMenu(menu); PhDereferenceObject(cacheEntryName); } } INT_PTR CALLBACK MainWindowDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { PhCenterWindow(hwndDlg, PhMainWndHandle); ListViewWndHandle = GetDlgItem(hwndDlg, IDC_ATOMLIST); PhInitializeLayoutManager(&LayoutManager, hwndDlg); PhAddLayoutItem(&LayoutManager, ListViewWndHandle, NULL, PH_ANCHOR_ALL); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDRETRY), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT); PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT); PhRegisterDialog(hwndDlg); PhLoadWindowPlacementFromSetting(SETTING_NAME_WINDOW_POSITION, SETTING_NAME_WINDOW_SIZE, hwndDlg); PhSetListViewStyle(ListViewWndHandle, FALSE, TRUE); PhSetControlTheme(ListViewWndHandle, L"explorer"); PhAddListViewColumn(ListViewWndHandle, 0, 0, 0, LVCFMT_LEFT, 370, L"Atom Name"); PhAddListViewColumn(ListViewWndHandle, 1, 1, 1, LVCFMT_LEFT, 70, L"Ref Count"); PhSetExtendedListView(ListViewWndHandle); PhLoadListViewColumnsFromSetting(SETTING_NAME_LISTVIEW_COLUMNS, ListViewWndHandle); LoadAtomTable(); } break; case WM_SIZE: PhLayoutManagerLayout(&LayoutManager); break; case WM_DESTROY: PhSaveWindowPlacementToSetting(SETTING_NAME_WINDOW_POSITION, SETTING_NAME_WINDOW_SIZE, hwndDlg); PhSaveListViewColumnsToSetting(SETTING_NAME_LISTVIEW_COLUMNS, ListViewWndHandle); PhDeleteLayoutManager(&LayoutManager); PhUnregisterDialog(hwndDlg); break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: EndDialog(hwndDlg, IDOK); break; case IDRETRY: LoadAtomTable(); break; } } break; case WM_NOTIFY: { LPNMHDR hdr = (LPNMHDR)lParam; switch (hdr->code) { case NM_RCLICK: { if (hdr->hwndFrom == ListViewWndHandle) ShowStatusMenu(hwndDlg); } break; } } break; } return FALSE; } VOID NTAPI MainMenuInitializingCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; PPH_EMENU_ITEM systemMenu; if (menuInfo->u.MainMenu.SubMenuIndex != PH_MENU_ITEM_LOCATION_TOOLS) return; if (!(systemMenu = PhFindEMenuItem(menuInfo->Menu, 0, L"System", 0))) { PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, PH_EMENU_SEPARATOR, 0, L"", NULL), -1); PhInsertEMenuItem(menuInfo->Menu, systemMenu = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"System", NULL), -1); } PhInsertEMenuItem(systemMenu, PhPluginCreateEMenuItem(PluginInstance, 0, ATOM_TABLE_MENUITEM, L"Atom Table", NULL), -1); } VOID NTAPI MenuItemCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_PLUGIN_MENU_ITEM menuItem = (PPH_PLUGIN_MENU_ITEM)Parameter; switch (menuItem->Id) { case ATOM_TABLE_MENUITEM: { DialogBox( PluginInstance->DllBase, MAKEINTRESOURCE(IDD_ATOMDIALOG), NULL, MainWindowDlgProc ); } break; } } LOGICAL DllMain( _In_ HINSTANCE Instance, _In_ ULONG Reason, _Reserved_ PVOID Reserved ) { switch (Reason) { case DLL_PROCESS_ATTACH: { PPH_PLUGIN_INFORMATION info; PH_SETTING_CREATE settings[] = { { IntegerPairSettingType, SETTING_NAME_WINDOW_POSITION, L"350,350" }, { ScalableIntegerPairSettingType, SETTING_NAME_WINDOW_SIZE, L"@96|510,380" }, { StringSettingType, SETTING_NAME_LISTVIEW_COLUMNS, L"" } }; PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info); if (!PluginInstance) return FALSE; info->Author = L"dmex"; info->DisplayName = L"Global Atom Table"; info->Description = L"Plugin for viewing the Global Atom Table via the Tools menu."; info->HasOptions = FALSE; PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), MainMenuInitializingCallback, NULL, &MainMenuInitializingCallbackRegistration ); PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), MenuItemCallback, NULL, &PluginMenuItemCallbackRegistration ); PhAddSettings(settings, ARRAYSIZE(settings)); } break; } return TRUE; }