Solved

When TerminateProcess Fails

Posted on 2010-11-18
19
2,288 Views
Last Modified: 2012-05-10
I have a third party  app that is misbehaving (CppUnit) dell wrAPPER.
Running test from VS2008 c++  (post build process) Sometimes the uni test "dos boxes" do not close.
and the will not close.
The app is visible in the task manager (TM), but not its process .
Killing the App in TM does nothing.
Cannot close windows  (XP) - have to "pull the plug"
Wrote a little app to do a Terminate process and it fials with access denied when I try to get the ExitCodeProcess()

That sometimes happens anyway, but call to TerminateProcess fails as well with access denied.
the process handle has ben gotten with TERMINATE PROCESS.


I would really like to kill these rogue apps off as they are harmelss enough.
what can do to exterminate 'em?
Code attached:
#include "stdafx.h"
#include "CPPUnitBash.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif



char buffer[1024];
CWinApp theApp;
const char* DisplayErrorStringExit(const char* msg, int exit_code);

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int		nRetCode		= 0;
	DWORD	dwProcessId 	= 0;
	DWORD	uExitCode		= 0;
	DWORD	dwError			= 0;
	DWORD	dwDesiredAccess = PROCESS_TERMINATE; 
	BOOL	bInheritHandle  = FALSE; 
	HANDLE	hProcess		= NULL; 
	*buffer = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		DisplayErrorStringExit("Fatal Error: MFC initialization", 1);
	}
	else
	{
		if( argc != 2)
		{
			DisplayErrorStringExit("Syntax: AppBash <process id>", 2);
		}

		// Process id from Spy++
		dwProcessId = atoi(argv[1]);
		uExitCode = 0;
		dwError = 0;
		dwDesiredAccess = PROCESS_TERMINATE; 
		bInheritHandle  = FALSE; 
		hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); 
	

		if( hProcess == NULL)
		{
			DisplayErrorStringExit("OpenProcess", 2);
		}

		// This usually fails with ACCESS DENIED, but for a normal exe even so TerminateProcess will still work
		dwError = GetExitCodeProcess( hProcess, &uExitCode);

		if( dwError == 0)
		{
			DisplayErrorStringExit("GetExitCodeProcess", 3);
		}

		// Fails to kill the roques
		if(!TerminateProcess( hProcess, uExitCode))
		{
			DisplayErrorStringExit("TerminateProcess", 4);
		}
	}

	return nRetCode;
}


const char* DisplayErrorStringExit(const char* msg, int exit_code)
{
	static char buffer[1024];
	*buffer = 0;
	DWORD dwError = GetLastError();
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
               NULL, 
               dwError,
               0,
               buffer, 
               1027, 
               NULL);
	printf("%s: failed, error: %d: %s\n", msg, dwError, buffer);
	exit(exit_code);

Open in new window

0
Comment
Question by:10Pints
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 11
  • 8
19 Comments
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 34165084
You might need to run as administrator and enable SeDebugPrivilege

How to obtain a handle to any process with SeDebugPrivilege
http://support.microsoft.com/kb/131065
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 34165139
In addition to the above your only specify the TERMINATE_PROCESS access right but you need specify additional access flag this is why you get access denied on GetExitCodeProcess()

* The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right.

You will need to specify both TERMINATE_PROCESS | PROCESS_QUERY_INFORMATION. All should work after you add the access flag.
0
 

Author Comment

by:10Pints
ID: 34165320
Hi folks - many thanks for getting back: much appreciated.
I have added the  | PROCESS_QUERY_INFORMATION to the GetExitCodeProcess()
And it now does not fail. It returns 0.
This is i have fed into terminate process but that now returns access denied.

There is more too this - just remembered - I am running this in a debug session using VS2008.  
The debug pareters are:
exe: $(CppUnitRoot)\lib\DllPlugInTesterd_dll.exe  ( which is a wrapper for the CppUnit DLL)
params: -s ..\Conf\Report.xsl -x UnitTests\Results\Ut$(ProjectName).$(ConfigurationName).xml -c $(ConfigurationName)\$(ProjectName).dll

It appears this does happen occasionally in this mode. I guess the debugger does nasty things if you break mid process rather than do a "Terminate  All" - may be a com ref is still held on the dll.

Its weird that the TM does list the process, but spy++ and my Open process can find it.

 
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:10Pints
ID: 34165349
I guess what I really need is a low level API call  like
ReallyKickThe!£*%OutOf( process)
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 34165369
Run VS2008 as administrator if your under XP administrator account it should already be running with the administrative token but if your using Vista, Windows 7 you will need to right click and choose Run As Administrator. If you get access denied you don't have enough rights to terminate the process but enabling SeDebugPrivilege should unless your dealing with a protected process or service.

Yeah... SeDebugPrivilege will kick it =)
0
 

Author Comment

by:10Pints
ID: 34168571
Hi eql1044 thanks.  I will try the SeDebugPrivilege  in the morn. I am on XP.
I reckon that should be a ggod approach as it was creted during a VS2008 debug session and I gues the debugger can do some nasty things. This orhaning appears to happen when we run the CppUnit  wrapper as the debug exe in the debug options - and then do a break and stop.

Thanks again for that will get at it in the Morn. and report back

T
0
 

Author Comment

by:10Pints
ID: 34192177
mmm still doesnt kill these procs.
I have included the code from How to obtain a handle to any process with SeDebugPrivilege
http://support.microsoft.com/kb/131065 
which works ... I reckon aas I can kill an innicent notepad.exe,
and the debugger shows us getting the token and setting/unsetting the privilege - attachd is the revised code.
the error on TerminateProcess is the same - access denied.

Bit of a sod - unless i have done something wrong - which is probable .... :)
WADDYAREKKUN??
T




// CPPUnitBash.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "CPPUnitBash.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13

char buffer[1024];
CWinApp theApp;
const char* DisplayErrorStringExit(const char* msg, int exit_code);
void DisplayError( LPTSTR szAPI);    // pointer to failed API name
BOOL SetPrivilege( HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege);

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int		nRetCode		= 0;
	DWORD	dwProcessId 	= 0;
	DWORD	uExitCode		= 0;
	DWORD	dwError			= 0;
	DWORD	dwDesiredAccess = PROCESS_TERMINATE; 
	BOOL	bInheritHandle  = FALSE; 
	HANDLE	hProcess		= NULL; 
	HANDLE	hToken			= NULL;

	*buffer = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		DisplayErrorStringExit("Fatal Error: MFC initialization", 1);
	}
	else
	{
		if( argc != 2)
		{
			DisplayErrorStringExit("Syntax: AppBash <process id>", 2);
		}

		if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken))
		{
			if (GetLastError() == ERROR_NO_TOKEN)
			{
				if (!ImpersonateSelf(SecurityImpersonation))
					return RTN_ERROR;

				if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken))
				{
					DisplayError("OpenThreadToken");

				return RTN_ERROR;
				}
			}
			else
			{
				return RTN_ERROR;
			}
		 }

		// enable SeDebugPrivilege
		if(!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))
		{
			DisplayError("SetPrivilege");

			// close token handle
			CloseHandle(hToken);

			// indicate failure
			return RTN_ERROR;
		}

		// Process id from Spy++
		dwProcessId = atoi(argv[1]);
		uExitCode = 0;
		dwError = 0;
		dwDesiredAccess = PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION; 
		bInheritHandle  = FALSE; 
		hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); 
	
		if( hProcess == NULL)
		{
			DisplayErrorStringExit("OpenProcess", 2);
		}

		// disable SeDebugPrivilege
		if(!SetPrivilege( hToken, SE_DEBUG_NAME, FALSE))
		{
			DisplayErrorStringExit("SetPrivilege", 5);
		}

		// This usually fails with ACCESS DENIED, but for a normal exe even so TerminateProcess will still work
		dwError = GetExitCodeProcess( hProcess, &uExitCode);

		if( dwError == 0)
		{
			DisplayErrorStringExit("GetExitCodeProcess", 3);
		}

		// Fails to kill the roques
		if(!TerminateProcess( hProcess, 0xffffffff))
		{
			DisplayErrorStringExit("TerminateProcess", 4);
		}
	}

	return nRetCode;
}


const char* DisplayErrorStringExit(const char* msg, int exit_code)
{
	static char buffer[1024];
	*buffer = 0;
	DWORD dwError = GetLastError();
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
               NULL, 
               dwError,
               0,
               buffer, 
               1027, 
               NULL);
	printf("%s: failed, error: %d: %s\n", msg, dwError, buffer);
	exit(exit_code);
}


BOOL SetPrivilege(
    HANDLE hToken,          // token handle
    LPCTSTR Privilege,      // Privilege to enable/disable
    BOOL bEnablePrivilege   // TRUE to enable.  FALSE to disable
    )
{
    TOKEN_PRIVILEGES tp;
    LUID luid;
    TOKEN_PRIVILEGES tpPrevious;
    DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);

    if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;

    // 
    // first pass.  get current privilege setting
    // 
    tp.PrivilegeCount           = 1;
    tp.Privileges[0].Luid       = luid;
    tp.Privileges[0].Attributes = 0;

    AdjustTokenPrivileges(
            hToken,
            FALSE,
            &tp,
            sizeof(TOKEN_PRIVILEGES),
            &tpPrevious,
            &cbPrevious
            );

    if (GetLastError() != ERROR_SUCCESS) return FALSE;

    // 
    // second pass.  set privilege based on previous setting
    // 
    tpPrevious.PrivilegeCount       = 1;
    tpPrevious.Privileges[0].Luid   = luid;

    if(bEnablePrivilege) {
        tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
    }
    else {
        tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
            tpPrevious.Privileges[0].Attributes);
    }

    AdjustTokenPrivileges(
            hToken,
            FALSE,
            &tpPrevious,
            cbPrevious,
            NULL,
            NULL
            );

    if (GetLastError() != ERROR_SUCCESS) return FALSE;

    return TRUE;
}

/*
BOOL SetPrivilege( HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege)  // bEnablePrivilege: TRUE to enable, FALSE to disable 
{ 
	TOKEN_PRIVILEGES tp = { 0 }; 
	// Initialize everything to zero 
	LUID luid; 
	DWORD cb=sizeof(TOKEN_PRIVILEGES); 
	if(!LookupPrivilegeValue( NULL, Privilege, &luid ))
		return FALSE; 
	tp.PrivilegeCount = 1; 
	tp.Privileges[0].Luid = luid; 
	if(bEnablePrivilege) { 
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
	} else { 
		tp.Privileges[0].Attributes = 0; 
	} 
	AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL ); 
	if (GetLastError() != ERROR_SUCCESS) 
		return FALSE; 

	return TRUE;
}
*/


void DisplayError( LPTSTR szAPI)    // pointer to failed API name
{
    LPTSTR MessageBuffer;
    DWORD dwBufferLength;

    fprintf(stderr,"%s() error!\n", szAPI);

    if(dwBufferLength=FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM,
                NULL,
                GetLastError(),
                GetSystemDefaultLangID(),
                (LPTSTR) &MessageBuffer,
                0,
                NULL
                ))
    {
        DWORD dwBytesWritten;

        // 
        // Output message string on stderr
        // 
        WriteFile(
                GetStdHandle(STD_ERROR_HANDLE),
                MessageBuffer,
                dwBufferLength,
                &dwBytesWritten,
                NULL
                );

        // 
        // free the buffer allocated by the system
        // 
        LocalFree(MessageBuffer);
    }
}

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 34192440
That should give it enough power to take down the process. Can you change the call to TerminateProcess to use either zero or the exitcode returned. It's worth trying just be sure thats not the issue.


TerminateProcess( hProcess, uExitCode);

TerminateProcess( hProcess, 0);

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 34192507
You should also just remove the call to disable SeDebugPrivilege() only disable the privilege when your finished.

1) Enable privilege
2) use OpenProcess()
3) use GetExitCodeProcess()
4) use TerminateProcess()
5) When all the above has been done then you may disable the privilege and in most cases for a console application it's not really required because the process will exit on its own and clean that up automatically.
0
 

Author Comment

by:10Pints
ID: 34195954
Hi eql1044 thanks

(cant keep calling you eql1044  - must have a friendly hanlde?)

yes I wondered about that, but being a microsoft example - was I going to query it?
I did try passing an exit code of zero.
I will try doing the disable the privilege after teh terminate process.
the thing is i only get the 'roque' cmd processes occsaiobally: when I am debugging using VS208 and CppUnit test dll wrapper exe (DllPlugInTesterd_dll.exe) is cited on its command line, and the debug session asserts, and i then "break all". this can sometimes leave teh orphan cmd exe floating, and i bet the debugger gives it SE Debug Privilege. So there is no parent exe visible in the Task Man. (but spy++ gives the Proc ID from the window).

I will try to create one today ASAP

ta again

T
0
 

Author Comment

by:10Pints
ID: 34253302
Yep - had 3 chances today to kill rogue app - but to no avail tried various permutations of SeDebugPrivilege and exit codes for the terminate process call - no luck as yet.
If it is com process - is there a way of viewing the com processes and stopping them?
There must be a Kill -9 somewhere in windows
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 34357271
Hmmm.. Not sure bud SeDebugPrivilege should take care of that process unless it's marked critical ( A process that needs to run in order for windows OS to work) .
0
 

Author Comment

by:10Pints
ID: 34363990
Hi there!
tried allsorts - checked the order of the task against your list - changed teh code retried, also tried all the other promissing looking privileges defined in WinNt.h like
SE_AUDIT_NAME
SE_DEBUG_NAME
SE_ENABLE_DELEGATION_NAME
SE_IMPERSONATE_NAME
SE_INC_BASE_PRIORITY_NAME
SE_INC_WORKING_SET_NAME
SE_LOAD_DRIVER_NAME
SE_MACHINE_ACCOUNT_NAME
SE_PROF_SINGLE_PROCESS_NAME
SE_REMOTE_SHUTDOWN_NAME
SE_SECURITY_NAME
SE_SHUTDOWN_NAME  
SE_SYNC_AGENT_NAME
SE_SYSTEM_ENVIRONMENT_NAME
SE_SYSTEM_PROFILE_NAME
SE_TCB_NAME
SE_TAKE_OWNERSHIP_NAME
SE_TRUSTED_CREDMAN_ACCESS_NAME
SE_UNDOCK_NAME
SE_UNSOLICITED_INPUT_NAME

to no avail - like you said rally.
Thing is the process is fired from VS2008 in the debug commandline so i suppose it inherits privileges from the debugger which presumably is pretty hi.
How about ...

i try a setwindowshookex and gp fault it or soemthing ...



0
 
LVL 29

Accepted Solution

by:
nffvrxqgrcfqvvc earned 500 total points
ID: 34802457
Hey bud,


I think I know what your refering about since I been working on a C++ project myself... When I debug it opens command window that won't go away until your close the develop IDE. I am using unmanaged C++ same thing occurs.. I think we have to live with it when debugging.
0
 

Author Comment

by:10Pints
ID: 34830810
Yes i have found a solution: it is a Microsoft problem with this build of XP:
http://support.microsoft.com/kb/982551
This hotfix fixes the issue.
0
 

Author Comment

by:10Pints
ID: 34830817
thanks eql1044, much asppreciated.
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 34832460
I run Windows 7 x64 I don't have to hard boot as the MSDN article mentions but I do have to exit out of the IDE ( can't use task manager to close the process either) that is definatley an issue at the kernel level though which reminds me of the same behavior that happens on XP when you use NtQueryObject API.

If you found your solution you can Delete this question or accept your own solution ;)

Take care Pints
0
 

Author Comment

by:10Pints
ID: 34844395
Hi matey! many thanks, i think you should have points - it is a worry if same problem has manifested its self on win 7
Bit like STL Debug warning you could not get rid of in VC6 -- back again CS2010 it seems!

Take care T
0
 

Author Closing Comment

by:10Pints
ID: 34844414
Check out
http://support.microsoft.com/kb/982551
for XP, Win 7 appears to have similar issue.
0

Featured Post

[Webinar] Learn How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them. Thursday, July 13, 2017 10:00 A.M. PDT

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Suggested Courses
Course of the Month3 days, 21 hours left to enroll

630 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question