Click here to Skip to main content
15,884,298 members
Articles / Programming Languages / C++
Article

Extending Task Manager with DLL Injection

Rate me:
Please Sign up or sign in to vote.
4.62/5 (25 votes)
19 May 20054 min read 165.2K   3K   106   27
How to extend the features of Windows Task Manager using DLL injection.

Introduction

This article shows how to extend the Windows Task Manager application by using DLL injection. There are plenty of articles already that show how to use DLL injection but this article is intended to show you what you can do with it. It also gives you some nice features for Task Manager.

This application consists of three separate projects:

  • TaskExApp

    This is an application that sits in the background waiting for instances of Windows Task Manager to popup. It loops through the top level windows every 1 second looking for instances. When an instance is detected, it will inject the InstallTaskHook DLL into the process. This application has a system tray icon that will show and hide the application dialog box when double-clicked. To end the process, just click the "Exit" button.

  • InstallTaskHook

    This is a DLL that is injected into the Windows Task Manager application. On injection, it creates an extra menu on the application's main menu called "Extensions". In this menu there is a sub menu "Get Extended Info" which will display a dialog box of extended data for the application that is selected in the processes list. You must select an item in the processes list and the PID field must be visible for this to work correctly.

  • TaskExHook

    This DLL is injected into the application by the Task Manager hook to get the extended information. Currently the only extra information that it gets is the command line parameter that the application was started with.

The following extended information is given on the display dialog:

  • Command Line

    The command line parameters that the application was started with.

  • File

    The full path of the executable file.

  • Modules

    All modules loaded by the application.

It's important to note that when this application builds, the DLLs are copied to the System32 directory, this is so that they can be found by the Task Manager application. If they are not copied there then the application won't work correctly, so if it doesn't work, first check to see if these DLLs were copied correctly by the build process.

Background

I have done extensive work in the past with Windows hooks on many projects, that was my intent when I started this project as well. Then I found the method of using CreateRemoteThread to inject a DLL into a process. I decided to use this method both for a learning exercise and because this is only intended to work on Windows 2000 and XP anyway. The main reason that I created this application was that I constantly need to know the command line parameters of an application, especially java.exe. There are applications out there that show this, but I would like to just have it work from within Windows Task Manager.

Screen shots

This is the main application window, it's very simple. You can double click the system tray icon to hide it without exiting:

Sample Image

Here are the menu items that are added to the Windows Task Manager application:

Sample Image

Here is the dialog box that is used to display the extended information:

Sample Image

A look at the code

The code is fairly light-weight, here are some of the more interesting aspects of the code.

From TaskExApp, here is how it installs the InstallTaskHook into the Windows Task Manager:

void TaskExDlg::Install(HWND hWnd, DWORD pid)
{
    m_taskManagers.insert(pid);

    HANDLE hProcess = 
       OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION 
       | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, 
       FALSE, pid);

    if (hProcess != NULL)
    {
        HANDLE hThread;
        char   szLibPath [_MAX_PATH];
        void*  pLibRemote = 0;
        DWORD  hLibModule = 0;

        HMODULE hKernel32 = ::GetModuleHandle("Kernel32");

        if( !::GetSystemDirectory(szLibPath, _MAX_PATH))
            return;

        strcat(szLibPath, "\\InstallTaskHook.dll");

        pLibRemote = ::VirtualAllocEx( hProcess, NULL, 
                     sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE );

        if( pLibRemote == NULL )
            return;

        ::WriteProcessMemory(hProcess, pLibRemote, 
                            (void*)szLibPath,sizeof(szLibPath),NULL);

        hThread = ::CreateRemoteThread( hProcess, NULL, 0,
                  (LPTHREAD_START_ROUTINE)::GetProcAddress(hKernel32, 
                  "LoadLibraryA"), 
                  pLibRemote, 0, NULL );

        if( hThread != NULL )
        {
            ::WaitForSingleObject( hThread, INFINITE );
            ::GetExitCodeThread( hThread, &hLibModule );
            ::CloseHandle( hThread );

        }
    }
}

The code for the InstallTaskHook to inject the TaskExHook is fairly similar, except that it also un-injects the DLL as well, the DLL is only there during the load process:

std::string GetCmdLineData(DWORD pid)
{
    HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | 
           PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | 
           PROCESS_VM_WRITE | PROCESS_VM_READ, 
           FALSE, pid);

    if (hProcess != NULL)
    {
        HANDLE hThread;
        char   szLibPath [_MAX_PATH];
        void*  pLibRemote = 0;
        DWORD  hLibModule = 0;

        HMODULE hKernel32 = ::GetModuleHandle("Kernel32");

        ::GetSystemDirectory(szLibPath, _MAX_PATH);

        strcat(szLibPath, "\\TaskExHook.dll");

        pLibRemote = ::VirtualAllocEx( hProcess, NULL, 
                     sizeof(szLibPath), 
                     MEM_COMMIT, PAGE_READWRITE );

        if( pLibRemote == NULL )
            return "Failed to get command line information...\r\n\r\n";

        ::WriteProcessMemory(hProcess, pLibRemote, 
              (void*)szLibPath,sizeof(szLibPath),NULL);

        hThread = ::CreateRemoteThread( hProcess, NULL, 0,
           (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32, 
           "LoadLibraryA"),
           pLibRemote, 0, NULL );

        if( hThread != NULL )
        {
            ::WaitForSingleObject( hThread, INFINITE );
            ::GetExitCodeThread( hThread, &hLibModule );
            ::CloseHandle( hThread );

            //Now uninject the DLL using FreeLibrary...
            ::VirtualFreeEx( hProcess, pLibRemote, 
                             sizeof(szLibPath), MEM_RELEASE );

            if( hLibModule != NULL )
            {
                hThread = ::CreateRemoteThread( hProcess,
                  NULL, 0,
                  (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32, 
                  "FreeLibrary"),
                  (void*)hLibModule,
                  0, NULL );

                if( hThread != NULL )
                {
                    ::WaitForSingleObject( hThread, INFINITE );
                    ::GetExitCodeThread( hThread, &hLibModule );
                    ::CloseHandle( hThread );
                }
            }
        }

        CloseHandle(hProcess);

        return "Command Line:\r\n\t" + std::string(g_szCmdLine);
    }

    return "Failed to get command line information...\r\n\r\n";
}

This code sets the debug privileges so that the application can inject in all other applications:

void GetDebugPrivs()
{
    HANDLE hToken;
    LUID sedebugnameValue;
    TOKEN_PRIVILEGES tp;

    if (::OpenProcessToken(GetCurrentProcess(), 
          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        if ( !::LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) )
        {
            ::CloseHandle( hToken );
        }

        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = sedebugnameValue;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

        if ( !::AdjustTokenPrivileges( hToken, 
             FALSE, &tp, sizeof(tp), NULL, NULL ) )
        {
            ::CloseHandle( hToken );
        }

        ::CloseHandle( hToken );
    }
}

Here is where the InstallTaskHook DLL actually creates the menu items and subclasses the main window to capture the menu events:

BOOL APIENTRY DllMain(HANDLE hModule, 
        DWORD ul_reason_for_call, LPVOID lpReserved)
{
    if( (ul_reason_for_call == DLL_PROCESS_ATTACH) )
    {
        EnumWindows(EnumProc, GetCurrentProcessId());

        if (g_hWnd)
        {
            char sz[256];

            SetWindowText(g_hWnd, "Extended Task Manager");

            HMENU hMenu = GetMenu(g_hWnd);
            int numMenus = GetMenuItemCount(hMenu);

            HMENU hCheck = GetSubMenu(hMenu, numMenus - 1);

            GetMenuString(hMenu, numMenus - 1, sz, 
                          sizeof(sz), MF_BYPOSITION);

            if (strcmp(sz, "Extensions"))
            {
                HMENU hPopup = CreatePopupMenu();

                AppendMenu(hPopup, MF_STRING, 2112, "Get Extended Info");
                AppendMenu(hMenu, MF_STRING | MF_ENABLED | MF_POPUP, 
                                  (UINT_PTR)hPopup, "Extensions");

                //Subclass the window with our own window procedure.
                wndProcOriginal = (WNDPROC)SetWindowLong(g_hWnd, 
                                   GWL_WNDPROC, (LONG)(WNDPROC)FilterProc);

                DrawMenuBar(g_hWnd);

                GetDebugPrivs();
            }
        }
    }

    return TRUE;
}

Issues

For some reason, some times the Windows Task Manager application will freeze during the injection process. It doesn't happen very often so it's hard to debug. When this does happen, just bring up another instance of Task Manager and kill the previous instance. If anyone can figure out why this happens, please let me know. Also, the application was only tested on Windows XP, but it should work on 2000/XP/2003.

Conclusion

I hope that this article gave you a good idea on how you can use DLL injection to your advantage. Being able to control another application can give you a lot of power on the system and allow you to make simple modifications to a large application without needing the code for that application.

I would also like to acknowledge the Winspy article for introducing me to the CreateRemoteThread method of DLL injection.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I live in the Nothern Virginia/Washington D.C. area. I have been working in the software industry since 1995. My skills are primarily in C++ and Java on Windows and Unix platforms but I also work with C# and some other programming languages (even PL/I and COBOL when necessary!).

Check out my software web site: http://www.dreamsyssoft.com

Comments and Discussions

 
Generaluseful Pin
kazemtnt10-May-11 2:03
kazemtnt10-May-11 2:03 
QuestionMissing code Pin
David Crow24-Jul-06 3:15
David Crow24-Jul-06 3:15 
GeneralHide Process in task manager list Pin
mohrag2-Jul-06 22:43
mohrag2-Jul-06 22:43 
GeneralRe: Hide Process in task manager list Pin
karim1385108-Jan-07 3:17
karim1385108-Jan-07 3:17 
Generalhide a process in the task manager Pin
jojo291184-Jun-05 23:46
jojo291184-Jun-05 23:46 
Question? Pin
Member 93270324-May-05 23:52
Member 93270324-May-05 23:52 
AnswerRe: ? Pin
rocky_pulley25-May-05 1:11
rocky_pulley25-May-05 1:11 
GeneralWouldn't it be more useful... Pin
Alexander M.,21-May-05 6:52
Alexander M.,21-May-05 6:52 
GeneralRe: Wouldn't it be more useful... Pin
rocky_pulley22-May-05 7:36
rocky_pulley22-May-05 7:36 
GeneralGood Article but... Pin
Darren Schroeder20-May-05 4:01
Darren Schroeder20-May-05 4:01 
GeneralRe: Good Article but... Pin
rocky_pulley20-May-05 4:48
rocky_pulley20-May-05 4:48 
GeneralSuggestion Pin
David Crow20-May-05 3:37
David Crow20-May-05 3:37 
GeneralAnother Task Manager Extension Pin
Berry van Olphen19-May-05 21:35
professionalBerry van Olphen19-May-05 21:35 
GeneralRe: Another Task Manager Extension Pin
Uwe Keim19-May-05 22:47
sitebuilderUwe Keim19-May-05 22:47 
GeneralRe: Another Task Manager Extension Pin
rocky_pulley20-May-05 0:58
rocky_pulley20-May-05 0:58 
GeneralRe: Another Task Manager Extension Pin
Toby Opferman20-May-05 11:10
Toby Opferman20-May-05 11:10 
GeneralRe: Another Task Manager Extension Pin
rocky_pulley20-May-05 13:16
rocky_pulley20-May-05 13:16 
GeneralRe: Another Task Manager Extension Pin
The_Mega_ZZTer23-Jan-06 19:09
The_Mega_ZZTer23-Jan-06 19:09 
GeneralRe: Another Task Manager Extension Pin
Toby Opferman23-Jan-06 19:27
Toby Opferman23-Jan-06 19:27 
GeneralRe: Another Task Manager Extension Pin
Sergey Kolomenkin23-May-05 10:21
Sergey Kolomenkin23-May-05 10:21 
GeneralRe: Another Task Manager Extension Pin
rocky_pulley23-May-05 11:01
rocky_pulley23-May-05 11:01 
GeneralRe: Another Task Manager Extension Pin
Sergey Kolomenkin23-May-05 11:06
Sergey Kolomenkin23-May-05 11:06 
GeneralRe: Another Task Manager Extension Pin
Sergey Kolomenkin23-May-05 11:59
Sergey Kolomenkin23-May-05 11:59 
GeneralRe: Another Task Manager Extension Pin
rocky_pulley23-May-05 12:02
rocky_pulley23-May-05 12:02 
GeneralRe: Another Task Manager Extension Pin
Sergey Kolomenkin23-May-05 10:57
Sergey Kolomenkin23-May-05 10:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.