Solved

When TerminateProcess Fails

Posted on 2010-11-18
19
2,016 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
  • 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
 

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
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 

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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

Introduction In a recent article (http://www.experts-exchange.com/A_7811-A-Better-Concatenate-Function.html) for the Excel community, I showed an improved version of the Excel Concatenate() function.  While writing that article I realized that no o…
Introduction While answering a recent question about filtering a custom class collection, I realized that this could be accomplished with very little code by using the ScriptControl (SC) library.  This article will introduce you to the SC library a…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

747 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now