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

Find and kill a process which uses the specified loaded dynamic library (.dll)

Rate me:
Please Sign up or sign in to vote.
4.68/5 (16 votes)
29 May 20051 min read 106.2K   2.8K   50   20
Find and kill all processes which have the given DLL as a module.

Output

Main Features

This article demonstrates a console application that will search and kill all the processes which are holding the given library name (comparison is not case sensitive). It is useful by COM+ registration using gacutil.exe and regsvcs.exe utilities.

Introduction

Often it is necessary to terminate a process which holds the given dynamic library. This case is well-know for COM+ programmers who have to stop before COM+ registration all processes which are holding their DLL. Manual search and termination is very frustrating, onerous and slows-down the programmer. This problem is solved by a utility which searches and terminates all processes which hold the given DLL. This is an occasion to create a batch file and call this utility with the name of the DLL as an input parameter, before the COM+ registration.

The entire source code shows a technique of how to proceed step by step by several processes and owned modules (DLLs). Accessing some processes and modules requires special privileges. This problem is handled in Keith Brown's and Christophe Nasarre's articles (see Credits section). If the access is obtained successfully, there is an opened admission to several modules for the existing process and also a permission to kill the given process.

Code

Well, here is a batch file example for COM+ programmers:

@echo off

freelib.exe sample.dll

echo.
echo Just... paused!
pause > nul

gacutil /nologo /u sample
regsvcs /u /nologo sample.dll

gacutil /nologo /i sample.dll
regsvcs /fc /nologo sample.dll

echo.
echo Press any key to close this console window
pause > nul

And here is the whole source code.

C++
/*
 * FreeLib
 * 
 * Copyright (c) 2005 by eraser
 */

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <aclapi.h>
#include <tchar.h>
#include <stdlib.h>

#if defined (_DEBUG)
    #define TRACE(str)    OutputDebugString(str)
#else
    #define TRACE(str)
#endif

#if !defined (SID_REVISION)
    #define SID_REVISION (1) 
#endif

BOOL enable_privilege(LPCTSTR szPrivilege);
BOOL adjust_dacl(HANDLE h, DWORD dwDesiredAccess); 
BOOL enable_token_privilege(HANDLE htok, 
     LPCTSTR szPrivilege, TOKEN_PRIVILEGES *tpOld);
HANDLE adv_open_process(DWORD pid, DWORD dwAccessRights);
BOOL kill_process(DWORD pid);

BOOL get_process_list(LPCTSTR szLibrary);
BOOL list_process_modules(DWORD dwPID, 
     LPCTSTR szProcessExeFile, LPCTSTR szLibrary);

char HelpText[] = 
"%s - release library utility - (c) 2005 by eraser (eraser@senior.cz)\n\n"
"Syntax: %s.exe [library_name.dll]\n\n";

void __defaultTrapHandler(int code) 
{ 
    abort(); 
} 

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        printf(HelpText, *argv, *argv);

        return 1;
    }

    get_process_list(*(argv + 1));

    return 0;
}

BOOL get_process_list(LPCTSTR szLibrary)
{
    HANDLE hProcessSnap;
    HANDLE hProcess;
    PROCESSENTRY32 pe32;
    DWORD dwPriorityClass;

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        TRACE("CreateToolhelp32Snapshot (of processes)");

        return (FALSE);
    }

    pe32.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hProcessSnap, &pe32))
    {
        TRACE("Process32First");
        CloseHandle(hProcessSnap);

        return (FALSE);
    }

    do
    {
        dwPriorityClass = 0;
        hProcess = adv_open_process(pe32.th32ProcessID, PROCESS_ALL_ACCESS);

        if (hProcess == NULL)
        {
            TRACE("OpenProcess");
        }
        else
        {
            dwPriorityClass = GetPriorityClass(hProcess);

            if (!dwPriorityClass)
            {
                TRACE("GetPriorityClass");
            }

            CloseHandle(hProcess);
        }

        list_process_modules(pe32.th32ProcessID, pe32.szExeFile, szLibrary);

    } while (Process32Next(hProcessSnap, &pe32));

    CloseHandle(hProcessSnap);

    return (TRUE);
}

BOOL list_process_modules(DWORD dwPID, 
     LPCTSTR szProcessExeFile, LPCTSTR szLibrary)
{
    HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
    MODULEENTRY32 me32;

    enable_privilege(SE_DEBUG_NAME);
    hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);

    if (hModuleSnap == (HANDLE) - 1)
    {
        TRACE("CreateToolhelp32Snapshot() failed!");
        TRACE(szProcessExeFile);

        return (FALSE);
    }

    me32.dwSize = sizeof(MODULEENTRY32);

    if (!Module32First (hModuleSnap, &me32))
    {
        TRACE("Module32First");
        CloseHandle(hModuleSnap);

        return (FALSE);
    }

    do
    {
        if (!lstrcmpi(szLibrary, me32.szModule))
        {
            printf("\nPROCESS: [%d] %s \t MODULE: %s", 
                   dwPID, szProcessExeFile, me32.szModule);
            printf(kill_process(dwPID) ? " terminated!" : 
                                 " termination failed!");
        }

    } while (Module32Next(hModuleSnap, &me32));

    CloseHandle(hModuleSnap);

    return (TRUE);
}

BOOL enable_privilege(LPCTSTR szPrivilege)
{
    BOOL bReturn = FALSE;
    HANDLE hToken;
    TOKEN_PRIVILEGES tpOld;

    if (!OpenProcessToken(GetCurrentProcess(), 
         TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
    {
        TRACE("enable_privilege");

        return(FALSE);
    }

    bReturn = (enable_token_privilege(hToken, szPrivilege, &tpOld));
    CloseHandle(hToken);

    return (bReturn);
}


BOOL adjust_dacl(HANDLE h, DWORD dwDesiredAccess)
{
    SID world = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, 0 };

    EXPLICIT_ACCESS ea =
    {
        0,
            SET_ACCESS,
            NO_INHERITANCE,
        {
            0, NO_MULTIPLE_TRUSTEE,
                TRUSTEE_IS_SID,
                TRUSTEE_IS_USER,
                0
        }
    };

    ACL* pdacl = 0;
    DWORD err = SetEntriesInAcl(1, &ea, 0, &pdacl);

    ea.grfAccessPermissions = dwDesiredAccess;
    ea.Trustee.ptstrName = (LPTSTR)(&world);

    if (err == ERROR_SUCCESS)
    {
        err = SetSecurityInfo(h, SE_KERNEL_OBJECT, 
              DACL_SECURITY_INFORMATION, 0, 0, pdacl, 0);
        LocalFree(pdacl);

        return (err == ERROR_SUCCESS);
    }
    else
    {
        TRACE("adjust_dacl");

        return(FALSE);
    }
}

BOOL enable_token_privilege(HANDLE htok, 
     LPCTSTR szPrivilege, TOKEN_PRIVILEGES *tpOld)
{
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (LookupPrivilegeValue(0, szPrivilege, &tp.Privileges[0].Luid))
    {
        DWORD cbOld = sizeof (*tpOld);

        if (AdjustTokenPrivileges(htok, FALSE, &tp, cbOld, tpOld, &cbOld))
        {
            return (ERROR_NOT_ALL_ASSIGNED != GetLastError());
        }
        else
        {
            TRACE("enable_token_privilege");

            return (FALSE);
        }
    }
    else
    {
        TRACE("enable_token_privilege");

        return (FALSE);
    }
}


HANDLE adv_open_process(DWORD pid, DWORD dwAccessRights)
{
    HANDLE hProcess = OpenProcess(dwAccessRights, FALSE, pid);

    if (hProcess == NULL)
    {
        HANDLE hpWriteDAC = OpenProcess(WRITE_DAC, FALSE, pid);

        if (hpWriteDAC == NULL)
        {
            HANDLE htok;
            TOKEN_PRIVILEGES tpOld;

            if (!OpenProcessToken(GetCurrentProcess(), 
                 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &htok))
            {
                return(FALSE);
            }

            if (enable_token_privilege(htok, SE_TAKE_OWNERSHIP_NAME, &tpOld))
            {
                HANDLE hpWriteOwner = OpenProcess(WRITE_OWNER, FALSE, pid);

                if (hpWriteOwner != NULL)
                {
                    BYTE buf[512];
                    DWORD cb = sizeof buf;

                    if (GetTokenInformation(htok, TokenUser, buf, cb, &cb))
                    {
                        DWORD err = SetSecurityInfo(hpWriteOwner, SE_KERNEL_OBJECT, 
                                    OWNER_SECURITY_INFORMATION, 
                                    ((TOKEN_USER *)(buf))->User.Sid, 0, 0, 0);
                        
                        if (err == ERROR_SUCCESS)
                        {
                            if (!DuplicateHandle(GetCurrentProcess(), hpWriteOwner, 
                                 GetCurrentProcess(), &hpWriteDAC, 
                                 WRITE_DAC, FALSE, 0))
                            {
                                hpWriteDAC = NULL;
                            }
                        }
                    }

                    CloseHandle(hpWriteOwner);
                }

                AdjustTokenPrivileges(htok, FALSE, &tpOld, 0, 0, 0);
            }

            CloseHandle(htok);
        }

        if (hpWriteDAC)
        {
            adjust_dacl(hpWriteDAC, dwAccessRights);

            if (!DuplicateHandle(GetCurrentProcess(), hpWriteDAC, 
                GetCurrentProcess(), &hProcess, dwAccessRights, FALSE, 0))
            {
                hProcess = NULL;
            }

            CloseHandle(hpWriteDAC);
        }
    }

    return (hProcess);
}

BOOL kill_process(DWORD pid)
{
    HANDLE hp = adv_open_process(pid, PROCESS_TERMINATE);

    if (hp != NULL)
    {
        BOOL bRet = TerminateProcess(hp, 1);
        CloseHandle(hp);

        return (bRet);
    }

    return (FALSE);
}

Credits

Many thanks to Keith Brown for getting a process handle with high-level rights, and definitely to Christophe Nasarre for his excellent article. I recommend the articles for all interested persons. They can find explanations about this issue and also examine some commented functions which are in my code rewritten from C++ to C language.

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
Slovakia Slovakia
Wink | ;-)

Comments and Discussions

 
QuestionTHANNNNNNNNNNNKSSSSSSSSSSSSSSSSSSSSSS Pin
Diel Oliveira12-Feb-14 9:20
Diel Oliveira12-Feb-14 9:20 
GeneralThanks a Lot For Your Work Pin
Member 180440310-Jun-09 1:01
Member 180440310-Jun-09 1:01 
GeneralThanks Pin
shurzan30-Aug-07 21:02
shurzan30-Aug-07 21:02 
QuestionIs there 64bit version? Pin
sh40715-Jun-07 10:09
sh40715-Jun-07 10:09 
GeneralTHANK YOU! Pin
SparkyNZ20-Mar-07 16:22
SparkyNZ20-Mar-07 16:22 
AnswerRe: THANK YOU! Pin
Dalibor Drzik22-Mar-07 2:37
Dalibor Drzik22-Mar-07 2:37 
GeneralThanks Much! Pin
Paul Kissel24-Jul-06 13:46
Paul Kissel24-Jul-06 13:46 
AnswerRe: Thanks Much! Pin
Dalibor Drzik27-Jul-06 6:25
Dalibor Drzik27-Jul-06 6:25 
QuestionCode correct? Pin
Mark A. Johnson25-May-06 11:56
Mark A. Johnson25-May-06 11:56 
AnswerRe: Code correct? [modified] Pin
Dalibor Drzik26-May-06 1:34
Dalibor Drzik26-May-06 1:34 
QuestionHow About A GUI Version Pin
easter_200720-Feb-06 17:49
easter_200720-Feb-06 17:49 
Nice effort.

I have done literally thousands upon thousands of log analysis with reg utility HijackThis in helping counteless users to yank those notorious malaicious DLL's that always like to hook a Valid process, such as IE, Explorer, and others.

It always became neccessary of course to open the complete tree of those processes to identify the culprit DLL.

My question for this example is....

Is there a safe and complete way to separate the dll from the host process without terminating it first?
It's always been a juggling act with some of the on-the-fly batch files we have had to use as well as VBScripts where in the code we would apply say a line with pskill to drop Explorer.exe then DEL the attached DLL and then once done restart Explorer again.

Thanks and always interesting.
AnswerRe: How About A GUI Version Pin
Dalibor Drzik20-Feb-06 22:21
Dalibor Drzik20-Feb-06 22:21 
GeneralRe: How About A GUI Version Pin
easter_200721-Feb-06 12:46
easter_200721-Feb-06 12:46 
GeneralVery useful tool Pin
v1ncent20-Jan-06 10:21
v1ncent20-Jan-06 10:21 
GeneralRe: Very useful tool Pin
Dalibor Drzik20-Jan-06 12:20
Dalibor Drzik20-Jan-06 12:20 
GeneralMemory leak in get_process_list() Pin
Corillian29-Oct-05 9:26
Corillian29-Oct-05 9:26 
GeneralRe: Memory leak in get_process_list() Pin
Dalibor Drzik29-Oct-05 21:44
Dalibor Drzik29-Oct-05 21:44 
GeneralRe: Memory leak in get_process_list() Pin
Corillian4-Nov-05 16:48
Corillian4-Nov-05 16:48 
QuestionCool but ? Pin
Trance Junkie30-May-05 1:04
Trance Junkie30-May-05 1:04 
AnswerRe: Cool but ? Pin
Dalibor Drzik30-May-05 2:59
Dalibor Drzik30-May-05 2:59 

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.