/* * Process Hacker Extra Plugins - * Plugin Manager * * Copyright (C) 2016 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 . */ #include "main.h" PPH_PLUGIN PluginInstance; PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration; PH_CALLBACK_REGISTRATION MainMenuInitializingCallbackRegistration; PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration; BOOLEAN LastCleanupExpired( VOID ) { ULONG64 lastUpdateTimeTicks = 0; LARGE_INTEGER currentUpdateTimeTicks; PPH_STRING lastUpdateTimeString; PhQuerySystemTime(¤tUpdateTimeTicks); lastUpdateTimeString = PhGetStringSetting(SETTING_NAME_LAST_CLEANUP); PhStringToInteger64(&lastUpdateTimeString->sr, 0, &lastUpdateTimeTicks); PhDereferenceObject(lastUpdateTimeString); if (currentUpdateTimeTicks.QuadPart - lastUpdateTimeTicks >= 25 * PH_TICKS_PER_DAY) { PPH_STRING currentUpdateTimeString = PhFormatUInt64(currentUpdateTimeTicks.QuadPart, FALSE); PhSetStringSetting2(SETTING_NAME_LAST_CLEANUP, ¤tUpdateTimeString->sr); PhDereferenceObject(currentUpdateTimeString); return TRUE; } return FALSE; } BOOLEAN PluginsCleanupDirectoryCallback( _In_ PFILE_DIRECTORY_INFORMATION Information, _In_opt_ PVOID Context ) { PH_STRINGREF baseName; PPH_STRING fileName; PPH_STRING rootDirectoryPath; rootDirectoryPath = Context; baseName.Buffer = Information->FileName; baseName.Length = Information->FileNameLength; if (PhEqualStringRef2(&baseName, L".", TRUE) || PhEqualStringRef2(&baseName, L"..", TRUE)) return TRUE; if (Information->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { HANDLE pluginsDirectoryHandle; PPH_STRING directoryPath; PPH_STRING PluginsDirectoryPath; directoryPath = PhCreateString2(&baseName); PluginsDirectoryPath = PhConcatStrings(4, rootDirectoryPath->Buffer, L"\\", directoryPath->Buffer, L"\\"); if (NT_SUCCESS(PhCreateFileWin32( &pluginsDirectoryHandle, PluginsDirectoryPath->Buffer, FILE_GENERIC_READ, 0, FILE_SHARE_READ, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*"); PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, PluginsCleanupDirectoryCallback, PluginsDirectoryPath); NtClose(pluginsDirectoryHandle); } } else if (PhEndsWithStringRef2(&baseName, L".bak", TRUE)) { NTSTATUS status; HANDLE fileHandle; FILE_DISPOSITION_INFORMATION dispositionInfo; IO_STATUS_BLOCK isb; fileName = PhCreateStringEx(NULL, rootDirectoryPath->Length + Information->FileNameLength); memcpy(fileName->Buffer, rootDirectoryPath->Buffer, rootDirectoryPath->Length); memcpy(&fileName->Buffer[rootDirectoryPath->Length / 2], Information->FileName, Information->FileNameLength); if (NT_SUCCESS(status = PhCreateFileWin32( &fileHandle, fileName->Buffer, FILE_GENERIC_WRITE | DELETE, 0, 0, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { dispositionInfo.DeleteFile = TRUE; NtSetInformationFile( fileHandle, &isb, &dispositionInfo, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation ); NtClose(fileHandle); } PhDereferenceObject(fileName); } return TRUE; } VOID PluginsCleanup( VOID ) { static UNICODE_STRING pluginsPattern = RTL_CONSTANT_STRING(L"*"); HANDLE pluginsDirectoryHandle; PPH_STRING pluginsDirectory; PPH_STRING PluginsDirectoryPath; pluginsDirectory = PhGetStringSetting(L"PluginsDirectory"); if (RtlDetermineDosPathNameType_U(PhGetString(pluginsDirectory)) == RtlPathTypeRelative) { PluginsDirectoryPath = PhConcatStrings( 4, PhGetString(PhGetApplicationDirectory()), L"\\", PhGetStringOrEmpty(pluginsDirectory), L"\\" ); PhDereferenceObject(pluginsDirectory); } else { PluginsDirectoryPath = pluginsDirectory; } if (NT_SUCCESS(PhCreateFileWin32( &pluginsDirectoryHandle, PhGetStringOrEmpty(PluginsDirectoryPath), FILE_GENERIC_READ, 0, FILE_SHARE_READ, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))) { PhEnumDirectoryFile( pluginsDirectoryHandle, &pluginsPattern, PluginsCleanupDirectoryCallback, PluginsDirectoryPath ); NtClose(pluginsDirectoryHandle); } } VOID NTAPI LoadCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_LIST pluginArgvList = Parameter; if (pluginArgvList) { for (ULONG i = 0; i < pluginArgvList->Count; i++) { PPH_STRING pluginCommandParam = pluginArgvList->Items[i]; if (PhEqualString2(pluginCommandParam, L"INSTALL", TRUE)) { //PPH_STRING directory; //PPH_STRING path; // //directory = PH_AUTO(PhGetApplicationDirectory()); //path = PhaCreateString(L"\\plugins"); //path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr)); // //if (MoveFileWithProgress( // L"new.plugin", // path->Buffer, // NULL, // NULL, // MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING // )) //{ // //} NtTerminateProcess(NtCurrentProcess(), EXIT_SUCCESS); } else if (PhEqualString2(pluginCommandParam, L"UNINSTALL", TRUE)) { NtTerminateProcess(NtCurrentProcess(), EXIT_SUCCESS); } } } else { PluginsCleanup(); } } VOID NTAPI MainMenuInitializingCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter; PPH_EMENU_ITEM pluginMenu; if (menuInfo->u.MainMenu.SubMenuIndex != 0) return; if (pluginMenu = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_DESCEND, NULL, PHAPP_ID_HACKER_PLUGINS)) { PhInsertEMenuItem(menuInfo->Menu, PhPluginCreateEMenuItem(PluginInstance, 0, pluginMenu->Id, L"Plugins... (Beta)", NULL), PhIndexOfEMenuItem(menuInfo->Menu, pluginMenu)); PhRemoveEMenuItem(menuInfo->Menu, pluginMenu, 0); } } VOID NTAPI MenuItemCallback( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ) { PPH_PLUGIN_MENU_ITEM menuItem = Parameter; switch (menuItem->Id) { case PHAPP_ID_HACKER_PLUGINS: ShowPluginManagerDialog(); 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[] = { { StringSettingType, SETTING_NAME_TREE_LIST_COLUMNS, L"" }, { StringSettingType, SETTING_NAME_LAST_CLEANUP, L"" }, { IntegerPairSettingType, SETTING_NAME_WINDOW_POSITION, L"100,100" }, { ScalableIntegerPairSettingType, SETTING_NAME_WINDOW_SIZE, L"@96|690,540" } }; PluginInstance = PhRegisterPlugin(SETTING_PREFIX, Instance, &info); if (!PluginInstance) return FALSE; info->DisplayName = L"Extra Plugins Manager"; info->Author = L"dmex"; info->Description = L"Process Hacker plugins from the community."; info->HasOptions = FALSE; PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackLoad), LoadCallback, NULL, &PluginLoadCallbackRegistration ); PhRegisterCallback( PhGetGeneralCallback(GeneralCallbackMainMenuInitializing), MainMenuInitializingCallback, NULL, &MainMenuInitializingCallbackRegistration ); PhRegisterCallback( PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem), MenuItemCallback, NULL, &PluginMenuItemCallbackRegistration ); PhAddSettings(settings, ARRAYSIZE(settings)); } break; } return TRUE; }