1427 lines
32 KiB
C++
1427 lines
32 KiB
C++
g// EmExtn.cpp : Defines the entry point for the DLL application.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include <Psapi.h>
|
|
#include <winsvc.h>
|
|
#include <comsvcs.h>
|
|
|
|
#include "Processes.h"
|
|
|
|
#define SUCCESS 0
|
|
|
|
DWORD
|
|
InvalidCallback
|
|
(
|
|
/* [in] */ ENUMPROCSANDSERVICES lpEnumSrvcsProc,
|
|
/* [in] */ LPARAM lParam,
|
|
/* [in] */ LONG nItemNum
|
|
)
|
|
{
|
|
return( lpEnumSrvcsProc( INVALID_PID, NULL, NULL, NULL, lParam, nItemNum ) );
|
|
}
|
|
|
|
DWORD
|
|
GetNumberOfRunningApps
|
|
(
|
|
/* [out] */ DWORD *pdwNumbApps
|
|
)
|
|
{
|
|
DWORD dwLastRet = 0L;
|
|
DWORD *pdwPIDs = NULL;
|
|
DWORD dwBuffSize = 256L;
|
|
UINT nIdx = 0;
|
|
bool bIsService = false;
|
|
|
|
do
|
|
{
|
|
//
|
|
// This loop is used to get all the running PIDs
|
|
// in the system. Because we do not know how many
|
|
// processes are running, we dynamically increase
|
|
// the array size. Limit = 256 DWORDs * 5
|
|
//
|
|
do {
|
|
|
|
if(pdwPIDs != NULL){
|
|
|
|
delete[] pdwPIDs;
|
|
pdwPIDs = NULL;
|
|
}
|
|
|
|
dwBuffSize *= (nIdx + 1);
|
|
pdwPIDs = new DWORD[dwBuffSize];
|
|
|
|
if(pdwPIDs == NULL){
|
|
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
dwLastRet = GetAllPids(
|
|
pdwPIDs,
|
|
dwBuffSize,
|
|
&dwBuffSize
|
|
);
|
|
}
|
|
while(dwLastRet == E_TOOMANY_PROCESSES);
|
|
|
|
if( dwLastRet == 0 ){
|
|
|
|
*pdwNumbApps = 0L;
|
|
|
|
for(UINT i = 0; i < dwBuffSize; ++i)
|
|
{
|
|
IsService( pdwPIDs[i], &bIsService );
|
|
if( bIsService != true ) *pdwNumbApps += 1;
|
|
}
|
|
}
|
|
}
|
|
while ( false );
|
|
|
|
if(pdwPIDs != NULL) {
|
|
|
|
delete[] pdwPIDs;
|
|
pdwPIDs = NULL;
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
DWORD
|
|
GetAllPids
|
|
(
|
|
/* [out] */ DWORD adwProcIDs[],
|
|
/* [in] */ DWORD dwBuffSize,
|
|
/* [out] */ DWORD *pdwNumbProcs
|
|
)
|
|
{
|
|
DWORD dwLastRet = 0L;
|
|
|
|
_ASSERT(adwProcIDs != NULL);
|
|
_ASSERT(dwBuffSize != 0L);
|
|
_ASSERT(pdwNumbProcs != NULL);
|
|
|
|
do
|
|
{
|
|
if( (adwProcIDs == NULL) ||
|
|
(dwBuffSize == 0L) ||
|
|
(pdwNumbProcs == 0L)) {
|
|
|
|
dwLastRet = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the list of process identifiers.
|
|
//
|
|
dwLastRet = (DWORD)EnumProcesses(
|
|
adwProcIDs,
|
|
dwBuffSize,
|
|
pdwNumbProcs);
|
|
|
|
if(dwLastRet == 0L){
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If both of them are same, it means that
|
|
// there may be more PIDs for which there
|
|
// is no space..
|
|
//
|
|
if(dwBuffSize == *pdwNumbProcs){
|
|
dwLastRet = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// This will give us the number of PIDs
|
|
//
|
|
(*pdwNumbProcs) = ((*pdwNumbProcs) / sizeof(DWORD));
|
|
dwLastRet = 0L;
|
|
}
|
|
while(FALSE);
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
DWORD
|
|
GetNumberOfServices
|
|
(
|
|
/* [out] */ DWORD *pdwNumbSrvcs,
|
|
/* [in] */ DWORD dwServiceType, /* = SERVICE_WIN32 */
|
|
/* [in] */ DWORD dwServiceState /* = SERVICE_ACTIVE */
|
|
)
|
|
{
|
|
_ASSERTE( pdwNumbSrvcs != NULL );
|
|
|
|
DWORD dwLastRet = 0L;
|
|
SC_HANDLE scm = NULL;
|
|
LPENUM_SERVICE_STATUS status = NULL;
|
|
DWORD cbBytesNeeded = 0L,
|
|
dwNumbSvcs = 0L,
|
|
dwResume = 0L;
|
|
ENUM_SERVICE_STATUS aServices[1]; // a-mando, bug ID: 296023
|
|
|
|
__try {
|
|
|
|
if( pdwNumbSrvcs == NULL ) { dwLastRet = -1L; goto qGetNumberOfServices; }
|
|
|
|
scm = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_ENUMERATE_SERVICE
|
|
);
|
|
|
|
if( !scm ) { dwLastRet = GetLastError(); goto qGetNumberOfServices; }
|
|
|
|
*pdwNumbSrvcs = 0L;
|
|
|
|
if( EnumServicesStatus(
|
|
scm,
|
|
dwServiceType,
|
|
dwServiceState,
|
|
aServices, // a-mando, bug ID: 296023
|
|
0,
|
|
&cbBytesNeeded,
|
|
&dwNumbSvcs,
|
|
&dwResume
|
|
) == false ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
}
|
|
|
|
if( dwLastRet != ERROR_MORE_DATA ) { goto qGetNumberOfServices;}
|
|
|
|
//
|
|
// Allocate space
|
|
//
|
|
status = (LPENUM_SERVICE_STATUS)LocalAlloc(
|
|
LPTR,
|
|
cbBytesNeeded
|
|
);
|
|
|
|
if( !status ) { dwLastRet = GetLastError(); goto qGetNumberOfServices; }
|
|
|
|
//
|
|
// Get the status records.
|
|
//
|
|
dwResume = 0;
|
|
dwLastRet = EnumServicesStatus(
|
|
scm,
|
|
dwServiceType,
|
|
dwServiceState,
|
|
status,
|
|
cbBytesNeeded,
|
|
&cbBytesNeeded,
|
|
&dwNumbSvcs,
|
|
&dwResume
|
|
);
|
|
|
|
if (dwLastRet == 0) { dwLastRet = GetLastError(); goto qGetNumberOfServices; }
|
|
|
|
*pdwNumbSrvcs = dwNumbSvcs;
|
|
|
|
dwLastRet = SUCCESS;
|
|
|
|
qGetNumberOfServices:
|
|
if( scm ) CloseServiceHandle( scm );
|
|
if( status ) LocalFree( status );
|
|
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
|
|
if( scm ) CloseServiceHandle( scm );
|
|
if( status ) LocalFree( status );
|
|
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
DWORD
|
|
GetNumberOfActiveServices
|
|
(
|
|
/* [out] */ DWORD *pdwNumbActiveSrvcs
|
|
)
|
|
{
|
|
return GetNumberOfServices( pdwNumbActiveSrvcs );
|
|
}
|
|
|
|
DWORD
|
|
GetNumberOfInactiveServices
|
|
(
|
|
/* [out] */ DWORD *pdwNumbInactiveSrvcs
|
|
)
|
|
{
|
|
return GetNumberOfServices( pdwNumbInactiveSrvcs, SERVICE_WIN32, SERVICE_INACTIVE );
|
|
}
|
|
|
|
DWORD
|
|
IsService
|
|
(
|
|
/* [in] */ UINT nPid,
|
|
/* [out] */ bool *pbIsService,
|
|
/* [out] */ LPTSTR lpszImagePath,
|
|
/* [out] */ ULONG cchImagePath,
|
|
/* [out] */ LPTSTR lpszServiceShortName,
|
|
/* [in] */ ULONG cchServiceShortName,
|
|
/* [out] */ LPTSTR lpszServiceDescription,
|
|
/* [in] */ ULONG cchServiceDescription
|
|
)
|
|
{
|
|
DWORD dwRet = 0L;
|
|
OSVERSIONINFO osvi;
|
|
|
|
ZeroMemory( (void *)&osvi, sizeof(OSVERSIONINFO) );
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if( !GetVersionEx (&osvi) ) {
|
|
|
|
return (dwRet = GetLastError());
|
|
}
|
|
|
|
if( osvi.dwPlatformId & VER_PLATFORM_WIN32_NT ) {
|
|
|
|
if( osvi.dwMajorVersion == 4 ) {
|
|
// && osvi.dwMinorVersion == 0 ) { // we will not look for the minor version.
|
|
|
|
IsService_NT4( nPid, pbIsService );
|
|
}
|
|
else if( osvi.dwMajorVersion == 5 ) {
|
|
// && osvi.dwMinorVersion == 0 ) {
|
|
|
|
IsService_NT5(
|
|
nPid,
|
|
pbIsService,
|
|
lpszImagePath,
|
|
cchImagePath,
|
|
lpszServiceShortName,
|
|
cchServiceShortName,
|
|
lpszServiceDescription,
|
|
cchServiceDescription
|
|
);
|
|
}
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
DWORD
|
|
IsService_NT5
|
|
(
|
|
/* [in] */ UINT nPid,
|
|
/* [out] */ bool *pbIsService,
|
|
/* [out] */ LPTSTR lpszImagePath,
|
|
/* [out] */ ULONG cchImagePath,
|
|
/* [out] */ LPTSTR lpszServiceShortName,
|
|
/* [in] */ ULONG cchServiceShortName,
|
|
/* [out] */ LPTSTR lpszServiceDescription,
|
|
/* [in] */ ULONG cchServiceDescription
|
|
)
|
|
{
|
|
_ASSERTE ( pbIsService != NULL );
|
|
|
|
bool bIsService = false;
|
|
DWORD dwLastRet = 0L;
|
|
int i = 0;
|
|
SC_HANDLE scm = NULL;
|
|
ENUM_SERVICE_STATUS_PROCESS *status = NULL;
|
|
DWORD numServices = 0L,
|
|
sizeNeeded = 0L,
|
|
resume = 0L;
|
|
|
|
__try
|
|
{
|
|
|
|
if( pbIsService == NULL ) { dwLastRet = -1L; goto qIsService; }
|
|
//
|
|
// Open a connection to the SCM
|
|
//
|
|
scm = OpenSCManager(0, 0, SC_MANAGER_ENUMERATE_SERVICE);
|
|
|
|
if ( !scm ){ dwLastRet = GetLastError(); goto qIsService; }
|
|
|
|
//
|
|
// Get the number of bytes to allocate
|
|
//
|
|
resume = 0;
|
|
if( EnumServicesStatusEx(
|
|
scm,
|
|
SC_ENUM_PROCESS_INFO,
|
|
SERVICE_WIN32, // We won't debug drivers
|
|
SERVICE_ACTIVE,
|
|
0,
|
|
0,
|
|
&sizeNeeded,
|
|
&numServices,
|
|
&resume,
|
|
NULL
|
|
) == 0 ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
|
|
//
|
|
// If it is any error other than this,
|
|
// we won't continue..
|
|
//
|
|
if(dwLastRet != ERROR_MORE_DATA) goto qIsService;
|
|
}
|
|
|
|
//
|
|
// Allocate space
|
|
//
|
|
status = (ENUM_SERVICE_STATUS_PROCESS *)LocalAlloc(
|
|
LPTR,
|
|
sizeNeeded
|
|
);
|
|
|
|
if( status == NULL ){ dwLastRet = GetLastError(); goto qIsService; }
|
|
|
|
//
|
|
// Get the status records.
|
|
//
|
|
resume = 0;
|
|
if( EnumServicesStatusEx(
|
|
scm,
|
|
SC_ENUM_PROCESS_INFO,
|
|
SERVICE_WIN32, // We won't debug drivers
|
|
SERVICE_ACTIVE,
|
|
(LPBYTE)status,
|
|
sizeNeeded,
|
|
&sizeNeeded,
|
|
&numServices,
|
|
&resume,
|
|
NULL
|
|
) == 0 ) {
|
|
|
|
dwLastRet = GetLastError(); goto qIsService;
|
|
}
|
|
|
|
*pbIsService = false;
|
|
for (i = 0; i < (int)numServices; i++)
|
|
{
|
|
if( status[i].ServiceStatusProcess.dwProcessId == nPid ) {
|
|
|
|
*pbIsService = true;
|
|
|
|
if(lpszImagePath)
|
|
{ _tcsncpy( lpszImagePath, _T(""), cchImagePath ); }
|
|
|
|
if(lpszServiceShortName)
|
|
{ _tcsncpy( lpszServiceShortName, status[i].lpServiceName, cchServiceShortName ); }
|
|
|
|
if(lpszServiceDescription)
|
|
{ _tcsncpy( lpszServiceDescription, status[i].lpDisplayName, cchServiceDescription ); }
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwLastRet = SUCCESS;
|
|
|
|
qIsService:
|
|
if( scm ) { CloseServiceHandle(scm); scm = NULL; }
|
|
if( status ){ LocalFree(status); status = NULL; }
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
|
|
if( scm ) { CloseServiceHandle( scm ); scm = NULL; }
|
|
if( status ){ LocalFree(status); status = NULL; }
|
|
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
DWORD
|
|
GetServiceInfo
|
|
(
|
|
/* [in] */ UINT nPid,
|
|
/* [out] */ LPTSTR lpszImagePath,
|
|
/* [out] */ ULONG cchImagePath,
|
|
/* [out] */ LPTSTR lpszServiceShortName,
|
|
/* [in] */ ULONG cchServiceShortName,
|
|
/* [out] */ LPTSTR lpszServiceDescription,
|
|
/* [in] */ ULONG cchServiceDescription
|
|
)
|
|
{
|
|
bool bIsService = false;
|
|
|
|
return IsService(
|
|
nPid,
|
|
&bIsService,
|
|
lpszImagePath,
|
|
cchImagePath,
|
|
lpszServiceShortName,
|
|
cchServiceShortName,
|
|
lpszServiceDescription,
|
|
cchServiceDescription
|
|
);
|
|
}
|
|
|
|
DWORD
|
|
EnumRunningProcesses
|
|
(
|
|
/* [in] */ ENUMPROCSANDSERVICES lpEnumRunProc,
|
|
/* [in] */ LPARAM lParam,
|
|
/* [in] */ UINT nStartIndex
|
|
)
|
|
{
|
|
// Nothing to do if this is NULL..
|
|
_ASSERT(lpEnumRunProc != NULL);
|
|
|
|
DWORD dwLastRet = 0L;
|
|
DWORD dwBuffSize = 256L;
|
|
DWORD *pdwPIDs = NULL;
|
|
UINT nIdx = 0;
|
|
UINT nItemNum = nStartIndex;
|
|
bool bService = FALSE;
|
|
TCHAR szShortName[_MAX_PATH] = _T("");
|
|
TCHAR szImagePath[_MAX_PATH] = _T("");
|
|
|
|
__try
|
|
{
|
|
if( !lpEnumRunProc ){ dwLastRet = E_INVALIDARG; goto qEnumRunningProcesses; }
|
|
|
|
//
|
|
// This loop is used to get all the running PIDs
|
|
// in the system. Because we do not know how many
|
|
// processes are running, we dynamically increase
|
|
// the array size. Limit = 256 DWORDs * 5
|
|
//
|
|
do{
|
|
if(pdwPIDs != NULL){
|
|
delete[] pdwPIDs;
|
|
pdwPIDs = NULL;
|
|
}
|
|
|
|
dwBuffSize *= (nIdx + 1);
|
|
pdwPIDs = new DWORD[dwBuffSize];
|
|
if(pdwPIDs == NULL){
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
dwLastRet = GetAllPids(
|
|
pdwPIDs,
|
|
dwBuffSize,
|
|
&dwBuffSize
|
|
);
|
|
}
|
|
while(dwLastRet == E_TOOMANY_PROCESSES);
|
|
|
|
//
|
|
// There are more processes than we
|
|
// can handle..
|
|
//
|
|
if( dwLastRet != E_TOOMANY_PROCESSES && dwLastRet != 0){ goto qEnumRunningProcesses; }
|
|
|
|
//
|
|
// If everything goes alright, call the Callback procedure
|
|
// once for each PID (or till the procedure returns FALSE)
|
|
// with the PID and the corresponding Image path..
|
|
//
|
|
nIdx = -1;
|
|
while(++nIdx < dwBuffSize){
|
|
dwLastRet = SUCCESS;
|
|
|
|
IsService( pdwPIDs[nIdx], &bService );
|
|
if( bService == true ) continue; // we won't add services into the list..
|
|
|
|
// This may fail for some procs like the system process.
|
|
if( GetImageNameFromPID( pdwPIDs[nIdx], szImagePath, _MAX_PATH )) {
|
|
|
|
if(lpEnumRunProc(INVALID_PID, NULL, NULL, NULL, lParam, nItemNum++) == FALSE){
|
|
|
|
dwLastRet = FALSE;
|
|
goto qEnumRunningProcesses; // Stop when the Callback procedure returns FALSE.
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
BSTR bstrDesc = _T("");
|
|
|
|
if( IsPackage( szImagePath ) ) {
|
|
|
|
GetPackageDescription( pdwPIDs[nIdx], bstrDesc );
|
|
}
|
|
|
|
if(lpEnumRunProc(pdwPIDs[nIdx], szImagePath, _T(""), bstrDesc, lParam, nItemNum++ ) == FALSE) {
|
|
|
|
dwLastRet = FALSE;
|
|
goto qEnumRunningProcesses; // Stop when the Callback procedure returns FALSE.
|
|
}
|
|
}
|
|
}
|
|
|
|
dwLastRet = SUCCESS;
|
|
|
|
qEnumRunningProcesses:
|
|
//
|
|
// Clean up memory allocated for PIDs array.
|
|
//
|
|
if( pdwPIDs ) { delete[] pdwPIDs; pdwPIDs = NULL; }
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
|
|
if( pdwPIDs ) { delete[] pdwPIDs; pdwPIDs = NULL; }
|
|
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
BOOL
|
|
IsPackage
|
|
(
|
|
IN LPTSTR lpszImageName
|
|
)
|
|
{
|
|
_ASSERTE( lpszImageName != NULL );
|
|
|
|
BOOL bRet = false;
|
|
const DWORD cTemplates = 2;
|
|
LPCTSTR szTemplate [cTemplates];
|
|
|
|
__try
|
|
{
|
|
if( !lpszImageName ) { return (bRet = false); }
|
|
|
|
_tcslwr( lpszImageName );
|
|
szTemplate[0] = _T("dllhost.exe");
|
|
szTemplate[1] = _T("mts.exe");
|
|
|
|
for( int i = 0; i < cTemplates; i++ ) {
|
|
|
|
if( _tcsstr( lpszImageName, szTemplate[i] ) != NULL ) {
|
|
|
|
bRet = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
bRet = false;
|
|
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
DWORD
|
|
EnumRunningServices
|
|
(
|
|
/* [in] */ ENUMPROCSANDSERVICES lpEnumSrvcsProc,
|
|
/* [in] */ LPARAM lParam,
|
|
/* [in] */ UINT nStartIndex
|
|
)
|
|
{
|
|
return EnumServices( lpEnumSrvcsProc, lParam, SERVICE_ACTIVE, nStartIndex );
|
|
}
|
|
|
|
|
|
DWORD
|
|
EnumStoppedServices
|
|
(
|
|
/* [in] */ ENUMPROCSANDSERVICES lpEnumSrvcsProc,
|
|
/* [in] */ LPARAM lParam,
|
|
/* [in] */ UINT nStartIndex
|
|
)
|
|
{
|
|
return EnumServices( lpEnumSrvcsProc, lParam, SERVICE_INACTIVE, nStartIndex );
|
|
}
|
|
|
|
DWORD
|
|
EnumServices
|
|
(
|
|
/* [in] */ ENUMPROCSANDSERVICES lpEnumSrvcsProc,
|
|
/* [in] */ LPARAM lParam,
|
|
/* [in] */ DWORD dwSrvcState,
|
|
/* [in] */ UINT nStartIndex
|
|
)
|
|
{
|
|
_ASSERTE ( lpEnumSrvcsProc != NULL );
|
|
|
|
bool bIsService = false;
|
|
DWORD dwLastRet = 0L;
|
|
int i = 0;
|
|
SC_HANDLE scm = NULL,
|
|
service = NULL;
|
|
LPQUERY_SERVICE_CONFIG buffer = NULL;
|
|
ENUM_SERVICE_STATUS_PROCESS *status = NULL;
|
|
DWORD numServices = 0L,
|
|
sizeNeeded = 0L,
|
|
resume = 0L;
|
|
UINT nItemNum = nStartIndex;
|
|
|
|
|
|
__try
|
|
{
|
|
|
|
if( lpEnumSrvcsProc == NULL ) { dwLastRet = -1L; goto qEnumServices; }
|
|
//
|
|
// Open a connection to the SCM
|
|
//
|
|
scm = OpenSCManager(0, 0, SC_MANAGER_ENUMERATE_SERVICE);
|
|
|
|
if ( !scm ){ dwLastRet = GetLastError(); goto qEnumServices; }
|
|
|
|
//
|
|
// Get the number of bytes to allocate
|
|
//
|
|
resume = 0;
|
|
if( EnumServicesStatusEx(
|
|
scm,
|
|
SC_ENUM_PROCESS_INFO,
|
|
SERVICE_WIN32, // We won't debug drivers
|
|
dwSrvcState,
|
|
0,
|
|
0,
|
|
&sizeNeeded,
|
|
&numServices,
|
|
&resume,
|
|
NULL
|
|
) == 0 ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
|
|
//
|
|
// If it is any error other than this,
|
|
// we won't continue..
|
|
//
|
|
if(dwLastRet != ERROR_MORE_DATA) goto qEnumServices;
|
|
}
|
|
|
|
//
|
|
// Allocate space
|
|
//
|
|
status = (ENUM_SERVICE_STATUS_PROCESS *)LocalAlloc(
|
|
LPTR,
|
|
sizeNeeded
|
|
);
|
|
|
|
if( status == NULL ){ dwLastRet = GetLastError(); goto qEnumServices; }
|
|
|
|
//
|
|
// Get the status records.
|
|
//
|
|
resume = 0;
|
|
if( EnumServicesStatusEx(
|
|
scm,
|
|
SC_ENUM_PROCESS_INFO,
|
|
SERVICE_WIN32, // We won't debug drivers
|
|
dwSrvcState,
|
|
(LPBYTE)status,
|
|
sizeNeeded,
|
|
&sizeNeeded,
|
|
&numServices,
|
|
&resume,
|
|
NULL
|
|
) == 0 ) {
|
|
|
|
dwLastRet = GetLastError(); goto qEnumServices;
|
|
}
|
|
|
|
for (i = 0; i < (int)numServices; i++)
|
|
{
|
|
if(service){
|
|
CloseServiceHandle(service);
|
|
service = NULL;
|
|
}
|
|
|
|
service = OpenService( scm,
|
|
status[i].lpServiceName,
|
|
SERVICE_QUERY_CONFIG
|
|
);
|
|
|
|
if (!service) {
|
|
|
|
dwLastRet = GetLastError();
|
|
InvalidCallback( lpEnumSrvcsProc, lParam, nItemNum++ );
|
|
continue;
|
|
} //goto qEnumServices; }
|
|
|
|
//
|
|
// Find out how big the buffer needs to be
|
|
//
|
|
dwLastRet = QueryServiceConfig(
|
|
service,
|
|
0,
|
|
0,
|
|
&sizeNeeded
|
|
);
|
|
|
|
if(dwLastRet == 0){
|
|
dwLastRet = GetLastError();
|
|
|
|
//
|
|
// If it is any error other than
|
|
// this, we won't continue..
|
|
//
|
|
if(dwLastRet != ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
InvalidCallback( lpEnumSrvcsProc, lParam, nItemNum++ );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate space for the buffer
|
|
//
|
|
buffer = (LPQUERY_SERVICE_CONFIG)
|
|
LocalAlloc(
|
|
LPTR,
|
|
sizeNeeded
|
|
);
|
|
|
|
//
|
|
// Get Buffer
|
|
//
|
|
dwLastRet = QueryServiceConfig(
|
|
service,
|
|
buffer,
|
|
sizeNeeded,
|
|
&sizeNeeded
|
|
);
|
|
if (dwLastRet == 0){
|
|
dwLastRet = GetLastError();
|
|
InvalidCallback( lpEnumSrvcsProc, lParam, nItemNum++ );
|
|
continue;
|
|
}
|
|
|
|
_tcslwr(buffer->lpBinaryPathName);
|
|
|
|
if(lpEnumSrvcsProc(
|
|
status[i].ServiceStatusProcess.dwProcessId,
|
|
buffer->lpBinaryPathName,
|
|
status[i].lpServiceName,
|
|
status[i].lpDisplayName,
|
|
lParam,
|
|
nItemNum++
|
|
) == FALSE) {
|
|
|
|
dwLastRet = FALSE;
|
|
goto qEnumServices; // Stop when the Callback procedure returns FALSE.
|
|
}
|
|
|
|
//
|
|
// CleanUp
|
|
//
|
|
if(buffer != NULL){
|
|
LocalFree(buffer);
|
|
buffer = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
dwLastRet = SUCCESS;
|
|
|
|
qEnumServices:
|
|
if( scm ) { CloseServiceHandle(scm); scm = NULL; }
|
|
if( status ){ LocalFree(status); status = NULL; }
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
|
|
if( scm ) { CloseServiceHandle( scm ); scm = NULL; }
|
|
if( status ){ LocalFree(status); status = NULL; }
|
|
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
DWORD
|
|
StartServiceAndGetPid
|
|
(
|
|
IN LPCTSTR lpszServiceShortName,
|
|
OUT UINT *pnPid
|
|
)
|
|
{
|
|
_ASSERTE(lpszServiceShortName != NULL);
|
|
|
|
DWORD dwLastRet = 0L;
|
|
DWORD dwBytesNeeded = 0L;
|
|
SC_HANDLE scm = NULL,
|
|
service = NULL;
|
|
|
|
SERVICE_STATUS_PROCESS stInfo;
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// Open a connection to the SCM
|
|
//
|
|
scm = OpenSCManager(0, 0, GENERIC_EXECUTE | STANDARD_RIGHTS_REQUIRED | SC_MANAGER_ENUMERATE_SERVICE);
|
|
|
|
if (!scm){
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
service = OpenService( scm, lpszServiceShortName, GENERIC_EXECUTE | STANDARD_RIGHTS_REQUIRED | SC_MANAGER_ENUMERATE_SERVICE );
|
|
|
|
if (!service){
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
if( StartService( service, 0L, NULL ) == 0 ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
if( QueryServiceStatusEx(
|
|
service,
|
|
SC_STATUS_PROCESS_INFO,
|
|
(LPBYTE) &stInfo,
|
|
sizeof stInfo,
|
|
&dwBytesNeeded
|
|
) == 0 ) {
|
|
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Successful..
|
|
//
|
|
*pnPid = stInfo.dwProcessId;
|
|
dwLastRet = 0L;
|
|
}
|
|
while(FALSE);
|
|
|
|
if(scm){
|
|
CloseServiceHandle(scm);
|
|
scm = NULL;
|
|
}
|
|
|
|
if(service){
|
|
CloseServiceHandle(service);
|
|
service = NULL;
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
BOOL
|
|
IsImageRunning
|
|
(
|
|
/* [in] */ ULONG lPID
|
|
)
|
|
{
|
|
bool bRet = FALSE;
|
|
|
|
HANDLE hProcess = ::OpenProcess(
|
|
PROCESS_QUERY_INFORMATION,
|
|
FALSE,
|
|
lPID
|
|
);
|
|
|
|
if(hProcess != NULL){
|
|
CloseHandle(hProcess);
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
DWORD
|
|
GetImageNameFromPID
|
|
(
|
|
/* [in] */ ULONG lPID,
|
|
/* [out] */ LPTSTR lpszImagePath,
|
|
/* [in] */ DWORD dwBuffSize
|
|
)
|
|
{
|
|
DWORD dwLastRet = S_OK;
|
|
HANDLE hProcess = NULL;
|
|
HMODULE hMod = NULL;
|
|
DWORD cbNeeded = 0L;
|
|
|
|
//
|
|
// 0 is a valid PID..
|
|
//
|
|
// _ASSERT(lPID != 0L);
|
|
_ASSERT(lpszImagePath != NULL);
|
|
|
|
do
|
|
{
|
|
if( /*(lPID == 0L) ||*/
|
|
(lpszImagePath == NULL) ){
|
|
dwLastRet = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get a handle to the process.
|
|
//
|
|
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
|
|
PROCESS_VM_READ,
|
|
FALSE,
|
|
lPID
|
|
);
|
|
|
|
if (hProcess == NULL){
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We do not want to enumerate all the modules in the
|
|
// process, but only one..
|
|
//
|
|
dwLastRet = EnumProcessModules(
|
|
hProcess,
|
|
&hMod,
|
|
sizeof(hMod),
|
|
&cbNeeded
|
|
);
|
|
|
|
if(dwLastRet == NULL){
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the process name.
|
|
//
|
|
dwLastRet = GetModuleBaseName(
|
|
hProcess,
|
|
hMod,
|
|
lpszImagePath,
|
|
dwBuffSize
|
|
);
|
|
|
|
if(dwLastRet == NULL){
|
|
dwLastRet = GetLastError();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We will store all the strings in
|
|
// lower case..
|
|
//
|
|
_tcslwr(lpszImagePath);
|
|
dwLastRet = SUCCESS;
|
|
|
|
}while(FALSE);
|
|
|
|
if(hProcess) CloseHandle(hProcess);
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
DWORD
|
|
IsValidImage
|
|
(
|
|
/* [in] */ ULONG lPID,
|
|
/* [in] */ LPCTSTR lpszImageName,
|
|
/* [out] */ bool *pbValidImage
|
|
)
|
|
{
|
|
_ASSERTE( lpszImageName != NULL );
|
|
|
|
DWORD dwLastRet = 0L;
|
|
TCHAR szImageName[_MAX_PATH+1] = _T("");
|
|
|
|
__try
|
|
{
|
|
if( lpszImageName == NULL ) {
|
|
|
|
return (dwLastRet = -1L);
|
|
}
|
|
|
|
*pbValidImage = false;
|
|
|
|
dwLastRet = GetImageNameFromPID( lPID, szImageName, _MAX_PATH );
|
|
if( dwLastRet != SUCCESS ) return dwLastRet;
|
|
|
|
*pbValidImage = (_tcsicmp( szImageName, lpszImageName) == 0);
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 )
|
|
{
|
|
dwLastRet = GetLastError();
|
|
_ASSERTE(false);
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
DWORD
|
|
IsValidProcess
|
|
(
|
|
/* [in] */ ULONG lPID,
|
|
/* [in] */ LPCTSTR lpszImageName,
|
|
/* [out] */ bool *pbValidImage
|
|
)
|
|
{
|
|
return IsValidImage( lPID, lpszImageName, pbValidImage );
|
|
}
|
|
|
|
DWORD
|
|
IsValidService
|
|
(
|
|
/* [in] */ ULONG lPID,
|
|
/* [in] */ LPCTSTR lpszImageName,
|
|
/* [out] */ bool *pbValidImage
|
|
)
|
|
{
|
|
_ASSERTE( lpszImageName != NULL );
|
|
|
|
DWORD dwLastRet = 0L;
|
|
TCHAR szImageName[_MAX_PATH+1] = _T("");
|
|
LPCTSTR lpszImage = NULL;
|
|
|
|
__try
|
|
{
|
|
if( lpszImageName == NULL ) {
|
|
|
|
return (dwLastRet = -1L);
|
|
}
|
|
|
|
lpszImage = _tcsrchr( lpszImageName, _T('\\') );
|
|
|
|
if( !lpszImage ) { lpszImage = lpszImageName; }
|
|
else { lpszImage += 1; }
|
|
|
|
dwLastRet = IsValidImage( lPID, lpszImage, pbValidImage );
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 )
|
|
{
|
|
dwLastRet = GetLastError();
|
|
_ASSERTE(false);
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
DWORD
|
|
GetProcessHandle
|
|
(
|
|
IN ULONG lPid,
|
|
OUT HANDLE *phProcess
|
|
)
|
|
{
|
|
DWORD dwLastRet = 0L;
|
|
|
|
__try
|
|
{
|
|
//
|
|
// Get a handle to the process.
|
|
//
|
|
dwLastRet = SUCCESS;
|
|
*phProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
|
|
PROCESS_VM_READ,
|
|
FALSE,
|
|
lPid
|
|
);
|
|
|
|
if (*phProcess == NULL){
|
|
|
|
dwLastRet = GetLastError();
|
|
}
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 )
|
|
{
|
|
dwLastRet = GetLastError();
|
|
_ASSERTE(false);
|
|
}
|
|
|
|
return dwLastRet;
|
|
}
|
|
|
|
HRESULT
|
|
GetPackageDescription
|
|
(
|
|
IN const long nPid,
|
|
OUT BSTR &bstrDescription
|
|
)
|
|
{
|
|
_ASSERTE( nPid != 0 );
|
|
|
|
HRESULT hr = E_FAIL;
|
|
IMtsGrp* pMtsGrp = NULL;
|
|
IUnknown* pUnk = NULL;
|
|
IMtsEvents* pEvents = NULL;
|
|
long lPackages = 0;
|
|
long lPID = 0;
|
|
long lLp = 0;
|
|
|
|
__try
|
|
{
|
|
if( !nPid ) { return (hr = E_INVALIDARG); }
|
|
|
|
//Create the MTS Group object
|
|
hr = CoInitialize( NULL );
|
|
if( FAILED(hr) ) { goto qGetPackageDescription; }
|
|
|
|
hr = CoCreateInstance (CLSID_MtsGrp, NULL, CLSCTX_ALL, IID_IMtsGrp, (void **)&pMtsGrp);
|
|
if( FAILED(hr) ) { goto qGetPackageDescription; }
|
|
|
|
hr = pMtsGrp->Refresh(); // its important to call this!
|
|
if( FAILED(hr) ) { goto qGetPackageDescription; }
|
|
|
|
hr = pMtsGrp->get_Count( &lPackages );
|
|
if( FAILED(hr) ) { goto qGetPackageDescription; }
|
|
|
|
for (lLp = 0; lLp < lPackages; lLp++)
|
|
{
|
|
|
|
hr = pMtsGrp->Item(lLp, &pUnk);
|
|
if( FAILED(hr) ) { goto qGetPackageDescription; }
|
|
|
|
hr = pUnk->QueryInterface(IID_IMtsEvents, (void **)&pEvents);
|
|
if( FAILED(hr) || !pEvents ) { goto qGetPackageDescription; }
|
|
if( pUnk ) { pUnk->Release(); pUnk = NULL; }
|
|
|
|
hr = pEvents->GetProcessID( &lPID );
|
|
if( FAILED(hr) ) { goto qGetPackageDescription; }
|
|
|
|
if( lPID == nPid ) { // This is the package we are looking for..
|
|
|
|
hr = pEvents->get_PackageName( &bstrDescription );
|
|
if( FAILED(hr) ) { goto qGetPackageDescription; }
|
|
break; // We got what we were looking for.
|
|
}
|
|
|
|
if( pEvents ) { pEvents->Release(); pEvents = NULL; }
|
|
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
qGetPackageDescription:
|
|
if( pEvents ) { pEvents->Release(); pEvents = NULL; }
|
|
if( pUnk ) { pUnk->Release(); pUnk = NULL; }
|
|
if( pMtsGrp ) { pMtsGrp->Release(); pMtsGrp = NULL; }
|
|
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 )
|
|
{
|
|
if( pEvents ) { pEvents->Release(); pEvents = NULL; }
|
|
if( pUnk ) { pUnk->Release(); pUnk = NULL; }
|
|
if( pMtsGrp ) { pMtsGrp->Release(); pMtsGrp = NULL; }
|
|
|
|
hr = E_UNEXPECTED;
|
|
|
|
_ASSERTE(false);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
|
|
EnumServicesStatusEx(..) is not supported on NT 4.0.
|
|
<http://www.mvps.org/win32/security/is_svc.html>
|
|
|
|
*/
|
|
|
|
HRESULT
|
|
IsService_NT4
|
|
(
|
|
IN UINT nPid,
|
|
OUT bool *pbIsService
|
|
)
|
|
{
|
|
_ASSERTE( nPid > 0 );
|
|
|
|
HRESULT hr = E_FAIL;
|
|
HANDLE hProcess = NULL;
|
|
HANDLE hProcessToken = NULL;
|
|
DWORD groupLength = 50;
|
|
PTOKEN_GROUPS groupInfo = NULL;
|
|
SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY;
|
|
PSID pInteractiveSid = NULL;
|
|
PSID pServiceSid = NULL;
|
|
DWORD dwRet = NO_ERROR;
|
|
DWORD ndx;
|
|
bool isInteractive = FALSE,
|
|
isService = FALSE;
|
|
|
|
|
|
__try
|
|
{
|
|
|
|
if( nPid <= 0 ) { hr = E_INVALIDARG; goto qIsService; }
|
|
|
|
hr = GetProcessHandle( nPid, &hProcess );
|
|
if( FAILED(hr) ) { goto qIsService; }
|
|
|
|
// open the token
|
|
if( !::OpenProcessToken( hProcess, TOKEN_QUERY, &hProcessToken) ) {
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto qIsService;
|
|
}
|
|
|
|
// allocate a buffer of default size
|
|
groupInfo = (PTOKEN_GROUPS)::LocalAlloc(0, groupLength);
|
|
if ( !groupInfo ) {
|
|
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto qIsService;
|
|
}
|
|
|
|
// try to get the info
|
|
if (!::GetTokenInformation(
|
|
hProcessToken,
|
|
TokenGroups,
|
|
groupInfo,
|
|
groupLength,
|
|
&groupLength
|
|
)
|
|
) {
|
|
|
|
// if buffer was too small, allocate to proper size, otherwise error
|
|
if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto qIsService;
|
|
}
|
|
|
|
::LocalFree(groupInfo);
|
|
|
|
groupInfo = (PTOKEN_GROUPS)::LocalAlloc(0, groupLength);
|
|
if (groupInfo == NULL) {
|
|
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto qIsService;
|
|
}
|
|
|
|
if (!GetTokenInformation(hProcessToken, TokenGroups,
|
|
groupInfo, groupLength, &groupLength)) {
|
|
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto qIsService;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We now know the groups associated with this token. We want
|
|
// to look to see if the interactive group is active in the
|
|
// token, and if so, we know that this is an interactive process.
|
|
//
|
|
// We also look for the "service" SID, and if it's present,
|
|
// we know we're a service.
|
|
//
|
|
// The service SID will be present iff the service is running in a
|
|
// user account (and was invoked by the service controller).
|
|
//
|
|
|
|
// create comparison sids
|
|
if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_INTERACTIVE_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &pInteractiveSid)) {
|
|
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto qIsService;
|
|
}
|
|
|
|
if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_SERVICE_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &pServiceSid)) {
|
|
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto qIsService;
|
|
}
|
|
|
|
|
|
// reset flags
|
|
isInteractive = FALSE;
|
|
isService = FALSE;
|
|
|
|
// try to match sids
|
|
for (ndx = 0; ndx < groupInfo->GroupCount ; ndx += 1)
|
|
{
|
|
SID_AND_ATTRIBUTES sanda = groupInfo->Groups[ndx];
|
|
PSID pSid = sanda.Sid;
|
|
|
|
//
|
|
// Check to see if the group we're looking at is one of
|
|
// the two groups we're interested in.
|
|
//
|
|
|
|
if (::EqualSid(pSid, pInteractiveSid))
|
|
{
|
|
//
|
|
// This process has the Interactive SID in its
|
|
// token. This means that the process is running as
|
|
// a console process
|
|
//
|
|
isInteractive = TRUE;
|
|
isService = FALSE;
|
|
break;
|
|
}
|
|
else if (::EqualSid(pSid, pServiceSid))
|
|
{
|
|
//
|
|
// This process has the Service SID in its
|
|
// token. This means that the process is running as
|
|
// a service running in a user account ( not local system ).
|
|
//
|
|
isService = TRUE;
|
|
isInteractive = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !( isService || isInteractive ) )
|
|
{
|
|
//
|
|
// Neither Interactive or Service was present in the current
|
|
// users token, This implies that the process is running as
|
|
// a service, most likely running as LocalSystem.
|
|
//
|
|
isService = TRUE;
|
|
|
|
}
|
|
|
|
qIsService:
|
|
if ( pServiceSid )
|
|
::FreeSid( pServiceSid );
|
|
|
|
if ( pInteractiveSid )
|
|
::FreeSid( pInteractiveSid );
|
|
|
|
if ( groupInfo )
|
|
::LocalFree( groupInfo );
|
|
|
|
if ( hProcessToken )
|
|
::CloseHandle( hProcessToken );
|
|
|
|
if( hProcess ) { CloseHandle( hProcess ); }
|
|
|
|
}
|
|
|
|
__except( EXCEPTION_EXECUTE_HANDLER, 1 )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE(false);
|
|
}
|
|
|
|
//
|
|
// BUGBUG: If the function fails, we treat
|
|
// the process as an app
|
|
//
|
|
*pbIsService = isService;
|
|
|
|
return hr;
|
|
}
|