Click here to Skip to main content
Email Password   helpLost your password?

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:

The following extended information is given on the display dialog:

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.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
QuestionMissing code
DavidCrow
4:15 24 Jul '06  
The GetCmdLineData() method does not show how g_szCmdLine gets populated. Is that intentional?


"Money talks. When my money starts to talk, I get a bill to shut it up." - Frank

"Judge not by the eye but by the heart." - Native American Proverb


GeneralHide Process in task manager list
mohrag
23:43 2 Jul '06  
Is it possible, starting with your code, to create a function which could hide/unhide any process in the task manager ??? (on Windows XP)

GeneralRe: Hide Process in task manager list
karim138510
4:17 8 Jan '07  
asasassa
Generalhide a process in the task manager
jojo29118
0:46 5 Jun '05  
Hi,

First, excuse my bad english, it's not my native language (I'm French).
Then, is it possible, starting with your code, to create a function which could hide/unhide any process in the task manager ??? (on Windows XP)

Regards.
General?
_WeeD_
0:52 25 May '05  
Is it possible to detect launching of task manager instead of checking every second? Perhaps hooking low level api calls?

-------------------------
"My software never has bugs. It just develops random features."

"Semper in excrementum, sole profundum qui variat."

GeneralRe: ?
rocky_pulley
2:11 25 May '05  
Yes, you can use a WH_SHELL hook, but I decided to just poll instead of adding more complexity to the demo. The polling every second doesn't eat up CPU as it is very fast and it's just for the purpose of demonstrating the use of DLL injection.

-- Rocky Dean Pulley
GeneralWouldn't it be more useful...
Alexander M.
7:52 21 May '05  
... to program a task manager self?
I mean that there are many things to improve and to add, and it's quite complilated to overwrite them all by DLL injection.
I'd prefer an own task manager with plugin extension, so that, as in the windows explorer, other developers are able to add columns for the list ctrl for example.

Don't try it, just do it! Wink
GeneralRe: Wouldn't it be more useful...
rocky_pulley
8:36 22 May '05  
Of course it would, but this site isn't about creating open source software, it's about showing how to do things. The point of this application is to show a use for DLL injection.

-- Rocky Dean Pulley
GeneralGood Article but...
Darren Schroeder
5:01 20 May '05  
I always find this stuff interesting but take a look at Zoltan Csizmadia's article on codeguru http://www.codeguru.com/Cpp/W-P/system/taskmanager/article.php/c5763. I haven't diff'd your code and his code but I bet they're similar.

Darren
GeneralRe: Good Article but...
rocky_pulley
5:48 20 May '05  
Yea, someone else pointed this out on this forum, I didn't know about the article, so if you diff the code you will see it's completely differnt. Also I think he uses one DLL where I use two.

-- Rocky Dean Pulley
GeneralSuggestion
DavidCrow
4:37 20 May '05  
My only suggestion would be to change your code snippets to not be so wide as to require scrolling.


"Ideas are a dime a dozen. People who put them into action are priceless." - Unknown


GeneralAnother Task Manager Extension
Berry van Olphen
22:35 19 May '05  
About 4 yours ago Zoltan Csizmadia made an excellent Task Manager Extension[^] with the following features:
* Show Application icons in Processes list (if available)
* Use different color for services
* Find a used file by any process. (Use * as file name for showing every used file)
(The search is a full text search, so for example you can use the extension only)
* Find a used module by any process
(The search is a full text search, so for example you can search for "kernel")
* Show Process ID in Applications tab
* Use different color for processes if the CPU usage reaches a given limit ( 25%, 50%, 75% )
* Query list of every files, handles, modules, windows used by a given process
* Close a used file (you can unlock an exclusively opened file, so you can delete it)
* Unload a used module (so you can delete it)
* You can kill services too
* Fast end process. Press DEL key!

I'm using it for a long time now and I can't live without it.

Grtx,
Berry

GeneralRe: Another Task Manager Extension
Uwe Keim
23:47 19 May '05  
Installed......now! Thanks Big Grin

--
Affordable Windows-based CMS for only 99 €: try www.zeta-producer.com for free!


GeneralRe: Another Task Manager Extension
rocky_pulley
1:58 20 May '05  
Cool, I didn't know about this one, maybe I will have to add some of his features, I hope he doesn't think I steal his ideas though. Funny, it looks like he has the same problem as me: "Sometimes TaskManager.exe crashes after start. Start it again!".


-- Rocky Dean Pulley
GeneralRe: Another Task Manager Extension
Toby Opferman
12:10 20 May '05  
Why not replace task manager all together? A lot of people use Process Explorer[^] as their task manager. Just rename your application to TASKMGR.EXE and put it in the system32 directory. That's one quick way to do it.

The other would be to create
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe

and add your application as the debugger.

BTW, you'd figure after 4 years they'd just duplicate Task Manager themselves and not worry about hacking up Task Manager and getting crashes!

Thanks,

Toby

GeneralRe: Another Task Manager Extension
rocky_pulley
14:16 20 May '05  
Yea, I actually use TaskInfo 2003 for this kind of stuff, it's awesome software. I really mainly created this article to show a real use for windows hooks, that and I'm constantly needing to find out the command line parameters of a process.

-- Rocky Dean Pulley
GeneralRe: Another Task Manager Extension
The_Mega_ZZTer
20:09 23 Jan '06  
Process Explorer, under XP, can replace Task Manager without replacing taskmgr.exe. It uses a powerful Windows feature that allows all references to one program (taskmgr.exe) to dynamically redirect to another (Process Explorer). I say powerful in the sense that it could be frightening if abused.

I figured this out because the guys who made Process Explorer also make an Autoruns tool that allows you to view image hijacks that use this method.
GeneralRe: Another Task Manager Extension
Toby Opferman
20:27 23 Jan '06  
Yes, the method in my post. It is most commonly used for attaching the debugger though.

8bc7c0ec02c0e404c0cc0680f7018827ebee
GeneralRe: Another Task Manager Extension
Sergey Kolomenkin
11:21 23 May '05  
Smile
There is one funny thing.
Some weeks ago I wrote the second (Advanced) version on Zoltan's TaskManagerEx.
I wanted to write an article to Codeproject, but had no time for this during May.
Smile
It was a real surprise for me that somebody published something like this exactly now. Not a year ago or two!
I think that such utility is very usefull for our community. I want to put sources
to SourceForge so people wouldn't develop something common twice, but will be able to do it together.


GeneralRe: Another Task Manager Extension
rocky_pulley
12:01 23 May '05  
that is pretty weird. Does yours use the same method? CreateRemoteThread that is.. Also, does it use two separate DLLs, one for injecting the new menus into Task Manager and one for injecting into the other processes? I just though of it when I had to kill a task, a java task, and here there are, like 10 java.exe processes in task manager with no idea which is which because it doesn't show command lines.
Smile

-- Rocky Dean Pulley
GeneralRe: Another Task Manager Extension
Sergey Kolomenkin
12:06 23 May '05  
I use CreateRemoteThread, but I have only two modules:
exe - this is a loader, that finds and infects Smile Task Managers
dll - it is a hook dll, that do everything in Task Manager process

GeneralRe: Another Task Manager Extension
Sergey Kolomenkin
12:59 23 May '05  
Here is my first Codeproject article: Smile
http://www.codeproject.com/useritems/Task_Manager_Extension.asp[^]
GeneralRe: Another Task Manager Extension
rocky_pulley
13:02 23 May '05  
Very cool, I was thinking about doing something on that large a scale but if I did, I would probably make it shareware and try to sell it for 5 or 10 bucks.

-- Rocky Dean Pulley
GeneralRe: Another Task Manager Extension
Sergey Kolomenkin
11:57 23 May '05  
There is one funny thing. Some weeks ago I wrote the second version of Zoltan's TaskManagerEx but had no time to write an article.
Smile
It was a real surprise to see your publication, when I browsed the Codeproject looking for an appropriate Section for my article.

GeneralExcellent
.dan.g.
21:27 19 May '05  
Smile

.dan.g.

AbstractSpoon Software


Last Updated 19 May 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010