Process Hacker & Plugins

In my previous blog entry https://chentiangemalc.wordpress.com/2011/07/03/process-explorer-vs-process-hackerpart-2-of-2/ I mentioned one major benefit of Process Hacker is that it has extensibility via Plug-In architecture. (I cannot tell you how much I wish Process Monitor had this capability! Maybe one day when I get enough time to reverse the PML format Winking smile ) Documentation remains incomplete so you can expect to read the header files or Process Hacker source to better understand the full functionality available via the SDK.

For Plug-Ins to work they must reside in a Plugins folder under the location of ProcessHacker.exe. Plugins will not work if you rename Process Hacker executable. In addition you must enable plugins in Process Hacker Options and restart Process Hacker as they are not enabled by default. Plugins are typically written in C++ and must be compiled for x64 and x86 to support both architectures.

To get started you need a Process Hacker SDK from here:

http://sourceforge.net/projects/processhacker/files/processhacker2/

To summarize the following APIs are available to plug-in developers:

API Description
PhRegisterPlugin Function
  • Registers a plugin with the Process Hacker plugin system
  • Specifies the name of your plugin, the base address of the DLL (HINSTANCE from your DllMain routine) allowing Process Hacker to use this address in calls to functions that require a module handle.
PhFindPlugin Function
  • Finds the PH_PLUGIN structure of a plugin.
PhGetPluginCallback Function
  • Retrieves a plugin-related callback object.
PhGetGeneralCallback Function
  • Retrieves a program-wide callback object.
PhPluginReserveIds Function
  • Reserves the specified number of control IDs guaranteed to be unique within Process Hacker.
    This function is not needed for most plugins.
PhPluginAddMenuItem Function
  • Adds a menu item to Process Hacker’s main menu.
PhPluginCreateEMenuItem Function
  • Creates a menu item for use within a GeneralCallback---MenuInitializing handler.
PhAddSettings Store settings for your plug-in.

 

The SDK includes a demo project so let’s take a look at it. The demo code below:

#include <phdk.h>

 

#define ID_SAMPLE_MENU_ITEM 1

#define ID_SHOW_ME_SOME_OBJECTS 2

 

VOID LoadCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    );

 

VOID ShowOptionsCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    );

 

VOID MenuItemCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    );

 

VOID MainWindowShowingCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    );

 

VOID GetProcessHighlightingColorCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    );

 

VOID GetProcessTooltipTextCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    );

 

PPH_PLUGIN PluginInstance;

PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;

PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;

PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;

PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration;

PH_CALLBACK_REGISTRATION GetProcessHighlightingColorCallbackRegistration;

PH_CALLBACK_REGISTRATION GetProcessTooltipTextCallbackRegistration;

 

LOGICAL DllMain(

    __in HINSTANCE Instance,

    __in ULONG Reason,

    __reserved PVOID Reserved

    )

{

    switch (Reason)

    {

    case DLL_PROCESS_ATTACH:

        {

            PPH_PLUGIN_INFORMATION info;

 

            // Register your plugin with a unique name, otherwise it will fail.

            PluginInstance = PhRegisterPlugin(L“ProcessHacker.SamplePlugin”, Instance, &info);

 

            if (!PluginInstance)

                return FALSE;

 

            info->DisplayName = L“Sample Plugin”;

            info->Author = L“Someone”;

            info->Description = L“Description goes here”;

            info->HasOptions = TRUE;

 

            PhRegisterCallback(

                PhGetPluginCallback(PluginInstance, PluginCallbackLoad),

                LoadCallback,

                NULL,

                &PluginLoadCallbackRegistration

                );

            PhRegisterCallback(

                PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions),

                ShowOptionsCallback,

                NULL,

                &PluginShowOptionsCallbackRegistration

                );

            PhRegisterCallback(

                PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem),

                MenuItemCallback,

                NULL,

                &PluginMenuItemCallbackRegistration

                );

 

            PhRegisterCallback(

                PhGetGeneralCallback(GeneralCallbackMainWindowShowing),

                MainWindowShowingCallback,

                NULL,

                &MainWindowShowingCallbackRegistration

                );

            PhRegisterCallback(

                PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor),

                GetProcessHighlightingColorCallback,

                NULL,

                &GetProcessHighlightingColorCallbackRegistration

                );

            PhRegisterCallback(

                PhGetGeneralCallback(GeneralCallbackGetProcessTooltipText),

                GetProcessTooltipTextCallback,

                NULL,

                &GetProcessTooltipTextCallbackRegistration

                );

 

            // Add some settings. Note that we cannot access these settings

            // in DllMain. Settings must be added in DllMain.

            {

                static PH_SETTING_CREATE settings[] =

                {

                    // You must prepend your plugin name to the setting names.

                    { IntegerSettingType, L“ProcessHacker.SamplePlugin.SomeInteger”, L“1234” },

                    { StringSettingType, L“ProcessHacker.SamplePlugin.SomeString”, L“my string” }

                };

 

                PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE));

            }

        }

        break;

    }

 

    return TRUE;

}

 

VOID LoadCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    )

{

    ULONG myInteger;

    PPH_STRING myString;

 

    myInteger = PhGetIntegerSetting(L“ProcessHacker.SamplePlugin.SomeInteger”);

    // Do stuff to the integer. Possibly modify the setting.

    PhSetIntegerSetting(L“ProcessHacker.SamplePlugin.SomeInteger”, myInteger + 100);

   

    myString = PhGetStringSetting(L“ProcessHacker.SamplePlugin.SomeString”);

    // Do stuff to the string.

    // Dereference the string when you’re done, or memory will be leaked.

    PhDereferenceObject(myString);

}

 

VOID ShowOptionsCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    )

{

    PhShowError((HWND)Parameter, L“Show some options here.”);

}

 

BOOLEAN NTAPI EnumDirectoryObjectsCallback(

    __in PPH_STRING Name,

    __in PPH_STRING TypeName,

    __in_opt PVOID Context

    )

{

    INT result;

 

    result = PhShowMessage(

        PhMainWndHandle,

        MB_ICONINFORMATION | MB_OKCANCEL,

        L“%s: %s”,

        Name->Buffer,

        TypeName->Buffer

        );

 

    return result == IDOK;

}

 

VOID MenuItemCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    )

{

    PPH_PLUGIN_MENU_ITEM menuItem = Parameter;

 

    switch (menuItem->Id)

    {

    case ID_SAMPLE_MENU_ITEM:

        {

            PhShowInformation(PhMainWndHandle, L“You clicked the sample menu item!”);

        }

        break;

    case ID_SHOW_ME_SOME_OBJECTS:

        {

            NTSTATUS status;

            HANDLE directoryHandle;

            OBJECT_ATTRIBUTES oa;

            UNICODE_STRING name;

           

            // Use the Native API seamlessly alongside Win32.

            RtlInitUnicodeString(&name, L“\\”);

            InitializeObjectAttributes(&oa, &name, 0, NULL, NULL);

           

            if (NT_SUCCESS(status = NtOpenDirectoryObject(&directoryHandle, DIRECTORY_QUERY, &oa)))

            {

                PhEnumDirectoryObjects(directoryHandle, EnumDirectoryObjectsCallback, NULL);

                NtClose(directoryHandle);

            }

        }

        break;

    }

}

 

VOID MainWindowShowingCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    )

{

    // $ won’t match anything, so the menu item will get added to the end.

    PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, L“$”,

        ID_SAMPLE_MENU_ITEM, L“Sample menu item”, NULL);

    PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_TOOLS, L“$”,

        ID_SHOW_ME_SOME_OBJECTS, L“Show me some objects”, NULL);

}

 

VOID GetProcessHighlightingColorCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    )

{

    PPH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor = Parameter;

    PPH_PROCESS_ITEM processItem;

   

    processItem = getHighlightingColor->Parameter;

   

    // Optional: if another plugin handled the highlighting, don’t override it.

    if (getHighlightingColor->Handled)

        return;

   

    // Set the background color of svchost.exe processes to black.

    if (PhEqualString2(processItem->ProcessName, L“svchost.exe”, TRUE))

    {

        getHighlightingColor->BackColor = RGB(0x00, 0x00, 0x00);

        getHighlightingColor->Cache = TRUE;

        getHighlightingColor->Handled = TRUE;

    }

}

 

VOID GetProcessTooltipTextCallback(

    __in_opt PVOID Parameter,

    __in_opt PVOID Context

    )

{

    PPH_PLUGIN_GET_TOOLTIP_TEXT getTooltipText = Parameter;

    PPH_PROCESS_ITEM processItem;

 

    processItem = getTooltipText->Parameter;

   

    // Put some text into the tooltip. This will go in just before the Notes section.

    PhAppendFormatStringBuilder(

        getTooltipText->StringBuilder,

        L“Sample plugin:\n    The process name is: %s\n”,

        processItem->ProcessName->Buffer

        );

}

 

From this demo I think we can see it is a very straightforward way to add functionality. So more importantly what have other people done with this plug-in architecture?

Importantly if you have downloaded the Process Hacker as a ZIP file you must move the plugins into correct directory. In this case I’m in x64 so I had to move .\Plugins\x64 folder into .\x64\Plugins directory

This enabled the following Plugins

image

Here they are in more detail (Remember source code is available for all these plugins from the Process Hacker sourceforge site):

Extended Notifications

This adds filtering capability to process notifications:

image

image

Extended Services

First this needs to be enabled via the Plugin’s options menu

image

Now right clicking on a service executable can show me all the services running under that process and take me straight to it, or stop it. The infamous svchost.exe shows it has a lot going on here..

image

Extended Tools

This plugin enables Disk and Network monitoring

image

This gives us a Disk & Network tab, similar to what is available in Process Explorer

image

Network Tools

This plugin provides ping, traceroute and whois for network connections.

image

Online Checks

Allows file to be checked with online services.

image

image

image

image

 

Sandboxie Support

Provides support for Sandboxed processes.

image

This adds

image

image

I think it also adds colour highlighting to sandboxed processes but didn’t have any process to test with.

Toolbar and Status Bar

Allows us to add the following functions

image

image

You can click and drag image like in Process Explorer target icon to find the process of a specific Window. However we also get image which is Find Window & Thread which will take us straight to the relevant GUI thread for the Window you drag it over.

The status bar looks like so:

image

Window Explorer

Allows you to manipulate Windows, adding the following functions when right clicking a process

image

 

Summary

Process Explorer Plugin Extensibility is a nice method to extend functionality. Do you know any other good Process Explorer plug-ins. Please let me know. Did you write one? Any suggestions for future plug-ins?

About chentiangemalc

specializes in end-user computing technologies. disclaimer 1) use at your own risk. test any solution in your environment. if you do not understand the impact/consequences of what you're doing please stop, and ask advice from somebody who does. 2) views are my own at the time of posting and do not necessarily represent my current view or the view of my employer and family members/relatives. 3) over the years Microsoft/Citrix/VMWare have given me a few free shirts, pens, paper notebooks/etc. despite these gifts i will try to remain unbiased.
This entry was posted in Tools, Troubleshooting, Win32 and tagged . Bookmark the permalink.

One Response to Process Hacker & Plugins

  1. Orgad says:

    You probably meant Process Hacker in the summary… :)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s