|
|
#include "precomp.h"
#include <winsvc.h>
#include <tchar.h>
#include <persistcfg.h>
#include <winntsec.h>
#include "cntserv.h"
#include "winmgmt.h"
#include "sched.h"
#include "resync2.h"
#include <malloc.h>
//***********************************************************************
//
// Defines
//
//***********************************************************************
#define CORE_PROVIDER_UNLOAD_TIMEOUT ( 30 * 1000 )
//***********************************************************************
//
// Globals
//
//***********************************************************************
HINSTANCE g_hInstance;
//***********************************************************************
//
// Dll Entry points and export points
//
//***********************************************************************
BOOL APIENTRY DllMain( HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch(ul_reason_for_call){ case DLL_PROCESS_ATTACH: g_hInstance = hModule; DisableThreadLibraryCalls(hModule); break; case DLL_PROCESS_DETACH: break; } return TRUE; };
//
//
// InitialBreak
//
///////////////////////////////////////////////////////////
BOOL InitialBreak() { HKEY hKey; LONG lRet; BOOL bRet = FALSE;
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, HOME_REG_PATH, 0, KEY_READ, &hKey); if (ERROR_SUCCESS == lRet) { DWORD dwType; DWORD dwVal; DWORD dwSize = sizeof(DWORD); lRet = RegQueryValueEx(hKey, INITIAL_BREAK, NULL, &dwType, (BYTE *)&dwVal, &dwSize); if (ERROR_SUCCESS == lRet && dwType == REG_DWORD && dwVal) { bRet = TRUE; } RegCloseKey(hKey); } return bRet; }
//
// the global structure
//
struct _PROG_RESOURCES g_ProgRes;
void _PROG_RESOURCES::Init() {
m_hExclusive = NULL; m_hTerminateEvent = NULL; m_bOleInitialized = NULL;
m_pLoginFactory = NULL; m_pBackupFactory = NULL; m_dwLoginClsFacReg = 0; m_dwBackupClsFacReg = 0;
g_fSetup = FALSE; g_fDoResync = TRUE; hMainMutex = NULL; bShuttingDownWinMgmt = FALSE; gbCoreLoaded = FALSE;
ServiceStatus = SERVICE_STOPPED;
ghCoreCanUnload = NULL; ghProviderCanUnload = NULL; ghCoreUnloaded = NULL; ghCoreLoaded = NULL; ghNeedRegistration = NULL; ghRegistrationDone = NULL; ghMofDirChange = NULL; ghLoadCtrEvent = NULL; ghUnloadCtrEvent = NULL; ghHoldOffNewClients = NULL;
szHotMofDirectory = NULL; pWbemVssWriter = NULL; bWbemVssWriterSubscribed = false; };
BOOL _PROG_RESOURCES::Phase1Build() { hMainMutex = CreateMutex(NULL, FALSE, NULL);
g_fSetup = CheckSetupSwitch();
if ( g_fSetup ) { SetNoShellADAPSwitch(); }
// Look in the registry to decide if we will launch a resync perf or not
g_fDoResync = CheckNoResyncSwitch();
//
// set this to have the Console Control Handler notification
//
SetProcessShutdownParameters(0x400,0);
//
// set to some defined value parames that might be outstanding if someone killed us
//
RegSetDWORD(HKEY_LOCAL_MACHINE,HOME_REG_PATH,DO_THROTTLE,1); return hMainMutex?TRUE:FALSE; };
BOOL _PROG_RESOURCES::Phase2Build(HANDLE hTerminateEvt) { ghCoreCanUnload = CreateEvent(NULL,FALSE,FALSE, TEXT("WINMGMT_COREDLL_CANSHUTDOWN"));
ghProviderCanUnload = CreateEvent(NULL,FALSE,FALSE, TEXT("WINMGMT_PROVIDER_CANSHUTDOWN")); SetEventDacl(ghProviderCanUnload,EVENT_ALL_ACCESS);
ghCoreUnloaded = CreateEvent(NULL,FALSE,FALSE, TEXT("WINMGMT_COREDLL_UNLOADED"));
ghCoreLoaded = CreateEvent(NULL,FALSE,FALSE, TEXT("WINMGMT_COREDLL_LOADED"));
m_hTerminateEvent = CreateEvent(NULL,TRUE,FALSE, TEXT("WINMGMT_MARSHALLING_SERVER_TERMINATE")); if(m_hTerminateEvent == NULL) { TRACE((LOG_WINMGMT,"\nWINMGMT terminating because CreateEvent, last error = 0x%x\n", GetLastError())); return FALSE; }
DWORD dwRet; m_hExclusive = CreateMutex( NULL, FALSE, TEXT("WINMGMT_MARSHALLING_SERVER")); if(m_hExclusive) dwRet = WaitForSingleObject(m_hExclusive, 0); if(m_hExclusive == NULL || dwRet != WAIT_OBJECT_0) { if(m_hExclusive) CloseHandle(m_hExclusive); m_hExclusive = NULL; TRACE((LOG_WINMGMT,"\nWINMGMT terminating an existing copy was detected")); return FALSE; }
ghNeedRegistration = CreateEvent(NULL,TRUE,FALSE, __TEXT("WINMGMT_NEED_REGISTRATION")); SetObjectAccess2(ghNeedRegistration); ghRegistrationDone = CreateEvent(NULL,TRUE,FALSE, __TEXT("WINMGMT_REGISTRATION_DONE")); SetObjectAccess2(ghRegistrationDone);
ghHoldOffNewClients = CreateMutex(NULL, FALSE, __TEXT("WINMGMT_KEEP_NEW_CLIENTS_AT_BAY")); if(ghHoldOffNewClients == NULL) ghHoldOffNewClients = OpenMutex(SYNCHRONIZE, FALSE, __TEXT("WINMGMT_KEEP_NEW_CLIENTS_AT_BAY"));
if(ghNeedRegistration == NULL || ghRegistrationDone == NULL || ghHoldOffNewClients == NULL) { TRACE((LOG_WINMGMT,"\nWINMGMT couldnt create the sync objects")); return FALSE; } if (!m_Monitor.Init()) { return FALSE; }
// don't create a writer if during setup
if (!g_fSetup) { pWbemVssWriter = new CWbemVssWriter; if (!pWbemVssWriter) { TRACE((LOG_WINMGMT,"\nWINMGMT could not create the VssWriter")); return FALSE; } }
return TRUE; }
BOOL _PROG_RESOURCES::RegisterLogin() { HRESULT sc; DWORD dwFlags = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER;
g_ProgRes.m_pLoginFactory = new CForwardFactory(CLSID_InProcWbemLevel1Login); g_ProgRes.m_pLoginFactory->AddRef(); sc = CoRegisterClassObject(CLSID_WbemLevel1Login, g_ProgRes.m_pLoginFactory, dwFlags, REGCLS_MULTIPLEUSE, &g_ProgRes.m_dwLoginClsFacReg); if(sc != S_OK) { TRACE((LOG_WINMGMT,"\nFailed to register the " "CLSID_WbemLevel1Login class factory, " "sc = 0x%x", sc)); return FALSE; } else { DEBUGTRACE((LOG_WINMGMT, "\nRegistered class factory with flags: 0x%X\n", dwFlags)); return TRUE; } }
BOOL _PROG_RESOURCES::RevokeLogin() { if(m_pLoginFactory) { CoRevokeClassObject(m_dwLoginClsFacReg); m_dwLoginClsFacReg = 0; m_pLoginFactory->Release(); m_pLoginFactory = NULL; } return TRUE; }
BOOL _PROG_RESOURCES::RegisterBackup() { HRESULT sc; DWORD dwFlags = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER;
g_ProgRes.m_pBackupFactory = new CForwardFactory(CLSID_WbemBackupRestore); g_ProgRes.m_pBackupFactory->AddRef();
sc = CoRegisterClassObject(CLSID_WbemBackupRestore, g_ProgRes.m_pBackupFactory, dwFlags, REGCLS_MULTIPLEUSE, &g_ProgRes.m_dwBackupClsFacReg); if(sc != S_OK) { TRACE((LOG_WINMGMT,"\nFailed to register the " "Backup/recovery class factory, " "sc = 0x%x", sc)); return FALSE; } else { return TRUE; } }
BOOL _PROG_RESOURCES::RevokeBackup() { if(m_pBackupFactory) { CoRevokeClassObject(m_dwBackupClsFacReg); m_dwBackupClsFacReg = 0; m_pBackupFactory->Release(); m_pBackupFactory = NULL; } return TRUE; }
_PROG_RESOURCES::Phase1Delete(BOOL bIsSystemShutdown) {
if (!bIsSystemShutdown) { if(ghCoreCanUnload) { CloseHandle(ghCoreCanUnload); ghCoreCanUnload = NULL; }; if(ghProviderCanUnload) { CloseHandle(ghProviderCanUnload); ghProviderCanUnload = NULL; } if(ghCoreUnloaded) { CloseHandle(ghCoreUnloaded); ghCoreUnloaded = NULL; } if(ghCoreLoaded) { CloseHandle(ghCoreLoaded); ghCoreLoaded = NULL; }
if(ghNeedRegistration) { CloseHandle(ghNeedRegistration); ghNeedRegistration = NULL; } if(ghRegistrationDone) { CloseHandle(ghRegistrationDone); ghRegistrationDone = NULL; } if(ghMofDirChange) { CloseHandle(ghMofDirChange); ghMofDirChange = NULL; } }
if (m_Monitor.IsRegistred()) { m_Monitor.Unregister(bIsSystemShutdown); } if (!bIsSystemShutdown) { m_Monitor.Uninit();
if(ghHoldOffNewClients) { CloseHandle(ghHoldOffNewClients); ghHoldOffNewClients = NULL; }
if(m_hTerminateEvent) { CloseHandle(m_hTerminateEvent); m_hTerminateEvent = NULL; } if(m_hExclusive) { ReleaseMutex(m_hExclusive); CloseHandle(m_hExclusive); m_hExclusive = NULL; }
if(szHotMofDirectory) { delete [] szHotMofDirectory; szHotMofDirectory = NULL; }
}
// shut down and delete our writer for volume snapshot backup
if (pWbemVssWriter && !bIsSystemShutdown) { if (bWbemVssWriterSubscribed) { HRESULT hRes = pWbemVssWriter->Unsubscribe(); if (SUCCEEDED(hRes)) { bWbemVssWriterSubscribed = false; } else { TRACE((LOG_WINMGMT,"\nWINMGMT Could not unsubscribe the VssWriter")); } }
delete pWbemVssWriter; pWbemVssWriter = NULL; }
return TRUE; }
_PROG_RESOURCES::Phase2Delete(BOOL bIsSystemShutdown) {
if (!bIsSystemShutdown) { if(m_pLoginFactory) { CoRevokeClassObject(m_dwLoginClsFacReg); m_pLoginFactory->Release(); m_pLoginFactory = NULL; m_dwLoginClsFacReg = 0; } if(m_pBackupFactory) { CoRevokeClassObject(m_dwBackupClsFacReg); m_pBackupFactory->Release(); m_pBackupFactory = NULL; m_dwBackupClsFacReg = 0; }
if(m_bOleInitialized) { CoUninitialize(); m_bOleInitialized = FALSE; }
}
return TRUE; }
BOOL _PROG_RESOURCES::Phase3Delete() { if (hMainMutex) { CloseHandle(hMainMutex); hMainMutex = NULL; } return TRUE; }
//
//
// ShutDownCore
//
//
/////////////////////////////////////////////////////////////////
bool ShutDownCore(BOOL bProcessShutdown,BOOL bIsSystemShutDown) { SCODE sc = WBEM_E_FAILED; HMODULE hCoreModule = LoadLibrary(__TEXT("wbemcore.dll")); if(hCoreModule) { pfnShutDown pfn = (pfnShutDown)GetProcAddress(hCoreModule, "Shutdown"); if(pfn) { sc = (pfn)(bProcessShutdown,bIsSystemShutDown); DEBUGTRACE((LOG_WINMGMT, "core is being shut down by WinMgmt.exe, it returned 0x%x",sc)); }
FreeLibrary(hCoreModule); } return sc == S_OK; }
//
//
// void Cleanup
//
//
// Release any currently loaded transports and close Ole etc.
//
//
///////////////////////////////////////////////////////////////////
void Cleanup(BOOL bIsSystemShutDown) { //DBG_PRINTFA((pBuff,"Cleanup called\n"));
if (!bIsSystemShutDown) { DEBUGTRACE((LOG_WINMGMT,"\nStarting cleanup, ID = %x", GetCurrentProcessId())); CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ; CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ; }
g_ProgRes.Phase1Delete(bIsSystemShutDown);
// If the core is still loaded, call its shutdown function
ShutDownCore(TRUE,bIsSystemShutDown);
g_ProgRes.Phase2Delete(bIsSystemShutDown);
if (!bIsSystemShutDown) { DEBUGTRACE((LOG_WINMGMT,"\nEnding cleanup")); } return; }
//
//
// BOOL Initialize
//
//
///////////////////////////////////////////////////////////////
BOOL Initialize(HANDLE hTerminateEvt) { // Set the error mode. This is used to provent the system from putting up dialog boxs to
// open files
UINT errormode = SetErrorMode(0); errormode |= SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS; SetErrorMode(errormode);
int iCnt; TCHAR tcName[MAX_PATH+1]; DEBUGTRACE((LOG_WINMGMT,"\nStarting Initialize, ID = %x", GetCurrentProcessId()));
if(!InitHotMofStuff(&g_ProgRes)) return FALSE;
if (!g_ProgRes.Phase2Build(hTerminateEvt)) return FALSE;
// Initialize Ole
SCODE sc;
sc = CoInitializeEx(NULL,COINIT_MULTITHREADED);
if(FAILED(sc)) { TRACE((LOG_WINMGMT,"\nWINMGMT Could not initialize Ole\n")); return FALSE; } else { g_ProgRes.m_bOleInitialized = TRUE; }
//
// Call the initialize function in core
//
HMODULE hCoreModule = GetModuleHandle(_T("wbemcore.dll")); if(hCoreModule) { HRESULT (STDAPICALLTYPE *pfn)(DWORD); pfn = (long (__stdcall *)(DWORD))GetProcAddress(hCoreModule, "Reinitialize"); if(pfn) { sc = (*pfn)(0); DEBUGTRACE((LOG_WINMGMT, "core is being resumed: it returned 0x%x",sc)); } else { DEBUGTRACE((LOG_WINMGMT, "failed to re-initialize core")); return FALSE; } }
g_ProgRes.RegisterLogin(); g_ProgRes.RegisterBackup();
g_ProgRes.ServiceStatus = SERVICE_RUNNING; // Get the registry key which is the root for all the transports.
// ==============================================================
HKEY hKey;
long lRet = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\WBEM\\CIMOM\\TRANSPORTS"), &hKey); if(lRet != ERROR_SUCCESS) { DEBUGTRACE((LOG_WINMGMT,"\nRegOpenKey returned 0x%x while trying to open the transports node. Using default transports!",lRet)); } else { /*
// Loop through each transport subkey.
// ===================================
for(iCnt = 0;ERROR_SUCCESS == RegEnumKey(hKey,iCnt,tcName,MAX_PATH+1); iCnt++) { HKEY hSubKey; lRet = RegOpenKey(hKey,tcName,&hSubKey); if(lRet != ERROR_SUCCESS) continue; DWORD bytecount = sizeof(DWORD); DWORD dwType;
// If the Enabled value isnt 1, then the transport is disabled
// and is ignored.
// ===========================================================
char cTemp[20]; bytecount=20; lRet = RegQueryValueEx(hSubKey, TEXT("Enabled"), NULL, &dwType, (LPBYTE) cTemp, &bytecount); if(lRet != ERROR_SUCCESS || dwType != REG_SZ || cTemp[0] != '1') { RegCloseKey(hSubKey); continue; }
// Read the CLSID string and convert it into an CLSID structure.
// =============================================================
TCHAR szCLSID[50]; bytecount = sizeof(szCLSID); lRet = RegQueryValueEx(hSubKey, TEXT("CLSID"), NULL, &dwType, (LPBYTE) &szCLSID, &bytecount);
RegCloseKey(hSubKey); if(lRet != ERROR_SUCCESS) { continue; }
CLSID clsid;
sc = CLSIDFromString( szCLSID, &clsid); if(sc != S_OK) { continue; }
// Load up the transport object and then initialize it.
// ====================================================
IWbemTransport * pTransport = NULL; sc = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, IID_IWbemTransport, (LPVOID *) &pTransport); if(sc != S_OK || pTransport == NULL) { continue; }
sc = pTransport->Initialize(); if(sc != S_OK) pTransport->Release(); else g_ProgRes.m_TransportArray.Add(pTransport); // add it to the list
} */ RegCloseKey(hKey); };
// initialize our writer for volume snapshot backup
// this must be after CoInitializeEx and after wbem is initialized
// (this pointer will be NULL during setup)
if (g_ProgRes.pWbemVssWriter) { HRESULT hRes = g_ProgRes.pWbemVssWriter->Initialize(); if (SUCCEEDED(hRes)) { hRes = g_ProgRes.pWbemVssWriter->Subscribe(); if (SUCCEEDED(hRes)) { g_ProgRes.bWbemVssWriterSubscribed = true; } else { TRACE((LOG_WINMGMT,"\nWINMGMT Could not subscribe the VssWriter")); } } else { TRACE((LOG_WINMGMT,"\nWINMGMT Could not initialize the VssWriter")); } }
DEBUGTRACE((LOG_WINMGMT,"\nInitialize complete"));
// TO BE REPLACED WITH PROPER CODING --- FORCE CORE
// ================================================
return TRUE; }
//
//
// WaitingFunction
//
// DESCRIPTION:
//
// Here is where we wait for messages and events during WinMgmt execution.
// We return from here when the program/service is being stopped.
//
//////////////////////////////////////////////////////////////////
void WaitingFunction(HANDLE hTerminate) {
CSched sched;
DEBUGTRACE((LOG_WINMGMT,"\nInside the waiting function"));
HANDLE hEvents[] = {hTerminate, g_ProgRes.ghCoreCanUnload, g_ProgRes.ghCoreUnloaded, g_ProgRes.ghCoreLoaded, g_ProgRes.ghNeedRegistration, g_ProgRes.ghProviderCanUnload, g_ProgRes.ghMofDirChange // important, must be last entry!!!!
}; int iNumEvents = sizeof(hEvents) / sizeof(HANDLE); DWORD dwFlags; SCODE sc; CPersistentConfig per; per.TidyUp();
sched.SetWorkItem(PossibleStartCore, 60000);
//Load any MOFs in the MOF directory if needed...
LoadMofsInDirectory(g_ProgRes.szHotMofDirectory);
// resync the perf counters if
// we haven't turned this off for debugging AND
// we are not running during setup
if(GLOB_IsResyncAllowed()) { ResyncPerf(RESYNC_TYPE_INITIAL); GLOB_GetMonitor()->Register(); } while(TRUE) { DWORD dwDelay = sched.GetWaitPeriod(); DWORD dwObj = WaitForMultipleObjects(iNumEvents, hEvents, FALSE, dwDelay); switch (dwObj) { case 0: // bail out for terminate event
{ if (SERVICE_SHUTDOWN != g_ProgRes.ServiceStatus) { DEBUGTRACE((LOG_WINMGMT,"\nGot a termination event")); } { CInMutex im(g_ProgRes.hMainMutex); g_ProgRes.bShuttingDownWinMgmt = TRUE; } // call cleanup outside of a Mutex
Cleanup((g_ProgRes.ServiceStatus == SERVICE_SHUTDOWN)?TRUE:FALSE); } return; case 1: // core can unload
DEBUGTRACE((LOG_WINMGMT,"\nGot a core can unload event")); sched.SetWorkItem(FirstCoreShutdown, 30000); // 30 seconds until next unloac;
break; case 2: // core went away
DEBUGTRACE((LOG_WINMGMT,"\nGot a core unloaded event")); g_ProgRes.gbCoreLoaded = FALSE; break;
case 3: // core loaded
DEBUGTRACE((LOG_WINMGMT,"\nGot a core loaded event")); g_ProgRes.gbCoreLoaded = TRUE; break;
case 4: // Need Registration
DEBUGTRACE((LOG_WINMGMT,"\nGot a NeedRegistration event"));
if (g_ProgRes.ServiceStatus == SERVICE_RUNNING) { g_ProgRes.RevokeLogin(); g_ProgRes.RegisterLogin(); } SetEvent(g_ProgRes.ghRegistrationDone); ResetEvent(g_ProgRes.ghNeedRegistration); break; case 5: // provider can unload
{ DEBUGTRACE((LOG_WINMGMT,"\nGot a provider can unload event")); CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ; //
// HACKHACK: Call it again to make sure that components that
// were released by unloading the first one can be unloaded
//
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ; sched.SetWorkItem(FinalCoreShutdown, CORE_PROVIDER_UNLOAD_TIMEOUT); // 11 minutes until next unloac;
} break;
case 6: // change in the hot mof directory
{ DEBUGTRACE((LOG_WINMGMT,"\nGot change in the hot mof directory")); LoadMofsInDirectory(g_ProgRes.szHotMofDirectory);
//Continue to monitor changes
if (!FindNextChangeNotification(g_ProgRes.ghMofDirChange)) { iNumEvents--; } } break; case WAIT_TIMEOUT:
DEBUGTRACE((LOG_WINMGMT,"\nGot a TIMEOUT work item")); if(sched.IsWorkItemDue(FirstCoreShutdown)) {
// All the clients have left the core and a decent time interval has passed. Set the
// WINMGMT_CORE_CAN_BACKUP event. When the core is done, it will set the WINMGMT_CORE_BACKUP_DONE
// event which will start the final unloading.
DEBUGTRACE((LOG_WINMGMT,"\nGot a FirstCoreShutdown work item")); sched.ClearWorkItem(FirstCoreShutdown); CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ; CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ; } if(sched.IsWorkItemDue(FinalCoreShutdown)) { CInMutex im(g_ProgRes.hMainMutex); DEBUGTRACE((LOG_WINMGMT,"\nGot a FinalCoreShutdown work item")); CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ; //
// HACKHACK: Call it again to make sure that components that
// were released by unloading the first one can be unloaded
CoFreeUnusedLibrariesEx ( CORE_PROVIDER_UNLOAD_TIMEOUT , 0 ) ; sched.ClearWorkItem(FinalCoreShutdown); } if(sched.IsWorkItemDue(PossibleStartCore)) { sched.StartCoreIfEssNeeded(); sched.ClearWorkItem(PossibleStartCore); }
break; }
}
}
//***************************************************************************
//
// MyService::MyService
//
// DESCRIPTION:
//
// Constructor.
//
//***************************************************************************
MyService::MyService(DWORD CtrlAccepted):CNtService(CtrlAccepted) { m_hStopEvent = CreateEvent(NULL,TRUE,FALSE,NULL); if(m_hStopEvent == NULL) { DEBUGTRACE((LOG_WINMGMT,"\nMyService could not initialize")); } }
//***************************************************************************
//
// MyService::~MyService
//
// DESCRIPTION:
//
// Destructor.
//
//***************************************************************************
MyService::~MyService() { if(m_hStopEvent) CloseHandle(m_hStopEvent); }
//***************************************************************************
//
// DWORD MyService::WorkerThread
//
// DESCRIPTION:
//
// Where the service runs. In this case, the service just waits for
// the terminate event to be set.
//
// RETURN VALUE:
//
// 0
//***************************************************************************
DWORD MyService::WorkerThread() { DEBUGTRACE((LOG_WINMGMT,"\nStarting service worker thread")); if(!::Initialize(m_hStopEvent)) return 0; WaitingFunction(m_hStopEvent);
if (SERVICE_SHUTDOWN != g_ProgRes.ServiceStatus ) { DEBUGTRACE((LOG_WINMGMT,"\nStopping service worker thread")); } return 0; }
//
//
// VOID MyService::Log
//
///////////////////////////////////////////////////////////////////
VOID MyService::Log( IN LPCSTR lpszMsg) { TRACE((LOG_WINMGMT,lpszMsg)); }
//
//
// the stop function
//
//////////////////////////////////////////////////////////////////
VOID MyService::Stop(BOOL bSystemShutDownCalled) { g_ProgRes.ServiceStatus = (bSystemShutDownCalled)?SERVICE_SHUTDOWN:SERVICE_STOPPED; SetEvent(m_hStopEvent); };
//
// MyService::Pause
//
////////////////////////////////////////////////////////////////////
HRESULT WbemPauseService() { HRESULT hr = WBEM_S_NO_ERROR; g_ProgRes.ServiceStatus = SERVICE_PAUSED; g_ProgRes.RevokeLogin(); GLOB_GetMonitor()->Unregister(FALSE);
SCODE sc = WBEM_E_FAILED; HMODULE hCoreModule = LoadLibraryEx(__TEXT("wbemcore.dll"),NULL,0); if(hCoreModule) { pfnShutDown pfn = (pfnShutDown)GetProcAddress(hCoreModule, "Shutdown"); if(pfn) { sc = pfn(FALSE,FALSE); DEBUGTRACE((LOG_WINMGMT, "core is being shut down by WinMgmt.exe, it returned 0x%x",sc)); } else hr = WBEM_E_CRITICAL_ERROR;
FreeLibrary(hCoreModule); } else hr = WBEM_E_CRITICAL_ERROR;
return hr; } VOID MyService::Pause() { WbemPauseService(); }
//
// MyService::Continue
//
////////////////////////////////////////////////////////////////////
HRESULT WbemContinueService() { HRESULT hr = WBEM_S_NO_ERROR; // HRESULT APIENTRY Reinitialize(DWORD dwReserved);
SCODE sc = WBEM_E_FAILED; HMODULE hCoreModule = LoadLibraryEx(__TEXT("wbemcore.dll"),NULL,0); if(hCoreModule) { HRESULT (STDAPICALLTYPE *pfn)(DWORD); pfn = (long (__stdcall *)(DWORD))GetProcAddress(hCoreModule, "Reinitialize"); if(pfn) { sc = (*pfn)(0); DEBUGTRACE((LOG_WINMGMT, "core is being resumed: it returned 0x%x",sc)); } else hr = WBEM_E_CRITICAL_ERROR;
FreeLibrary(hCoreModule); } else hr = WBEM_E_CRITICAL_ERROR;
g_ProgRes.RegisterLogin(); GLOB_GetMonitor()->Register(); g_ProgRes.ServiceStatus = SERVICE_RUNNING; return hr; }
VOID MyService::Continue() { WbemContinueService(); }
//
//
// this function will be executed before
// the final SetServiceStatus(SERVICE_STOPPED)
//
//////////////////////////////////////////////////////////
VOID MyService::FinalCleanup() { g_ProgRes.Phase3Delete();
RegSetDWORD(HKEY_LOCAL_MACHINE, HOME_REG_PATH, _T("ProcessID"), 0); }
//
// TO be removed before RTM
// publish process ID in the registry
//
////////////////////////////////////////////////////
DWORD RegSetDWORD(HKEY hKey, TCHAR * pName, TCHAR * pValue, DWORD dwValue) { HKEY hKey2; LONG lRet;
lRet = RegOpenKeyEx(hKey, pName, 0, KEY_WRITE, &hKey2); if (ERROR_SUCCESS == lRet) { DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD); lRet = RegSetValueEx(hKey2, pValue, NULL, dwType, (BYTE *)&dwValue, dwSize); RegCloseKey(hKey2); } return lRet;
}
DWORD RegGetDWORD(HKEY hKey, TCHAR * pName, TCHAR * pValue, DWORD * pdwValue) { HKEY hKey2; LONG lRet;
if (0 == pdwValue) return ERROR_INVALID_PARAMETER;
lRet = RegOpenKeyEx(hKey, pName, 0, KEY_READ, &hKey2); if (ERROR_SUCCESS == lRet) { DWORD dwSize = sizeof(DWORD); DWORD dwType =0; lRet = RegQueryValueEx(hKey2, pValue, NULL, &dwType, (BYTE *)pdwValue, &dwSize); RegCloseKey(hKey2); } return lRet;
} //
//
// Interceptor
//
//
///////////////////////////////////////////////////////////
#ifdef INSTRUMENTED_BUILD
#ifdef _X86_
#include <malloc.h>
struct HEAP_ENTRY { WORD Size; WORD PrevSize; BYTE SegmentIndex; BYTE Flags; BYTE UnusedBytes; BYTE SmallTagIndex; };
#define HEAP_SLOW_FLAGS 0x7d030f60
// only the "header"
typedef struct _HEAP { HEAP_ENTRY Entry; ULONG Signature; ULONG Flags; ULONG ForceFlags; } HEAP;
BOOL g_FaultHeapEnabled = FALSE; BOOL g_FaultFileEnabled = FALSE; ULONG g_Seed; ULONG g_Factor = 100000; ULONG g_Percent = 0x20; //ULONG g_RowOfFailures = 10;
//LONG g_NumFailInARow = 0;
//LONG g_NumFailedAllocation = 0;
BOOL g_bDisableBreak = FALSE; LONG g_nSuccConn = 0;
#define SIZE_JUMP_ADR 5
#define SIZE_SAVED_INSTR 12
void _declspec(naked) Prolog__ReadFile(){ _asm { // this is the space for the "saved istructions"
nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; // this is the place for the JMP
nop ; nop ; nop ; nop ; nop ; nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
} }
BOOL _I_ReadFile( HANDLE hFile, // handle to file
LPVOID lpBuffer, // data buffer
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // number of bytes read
LPOVERLAPPED lpOverlapped // offset
){ DWORD * pDw = (DWORD *)_alloca(sizeof(DWORD)); BOOL bRet;
LONG Ret = RtlRandomEx(&g_Seed); if (g_FaultFileEnabled && (Ret%g_Factor < g_Percent)) { if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0; return FALSE; } _asm{ push lpOverlapped; push lpNumberOfBytesRead; push nNumberOfBytesToRead; push lpBuffer; push hFile; call Prolog__ReadFile; mov bRet,eax }
return bRet; }
void _declspec(naked) Prolog__WriteFile(){ _asm { // this is the space for the "saved istructions"
nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; // this is the place for the JMP
nop ; nop ; nop ; nop ; nop ; nop ; // dist
nop ; // dist
nop ; // dist
} }
BOOL _I_WriteFile( HANDLE hFile, // handle to file
LPCVOID lpBuffer, // data buffer
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // number of bytes written
LPOVERLAPPED lpOverlapped // overlapped buffer
){
DWORD * pDw = (DWORD *)_alloca(sizeof(DWORD)); BOOL bRet;
LONG Ret = RtlRandomEx(&g_Seed); if (g_FaultFileEnabled && (Ret%g_Factor < g_Percent)) { if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = 0; return FALSE; } _asm{ push lpOverlapped; push lpNumberOfBytesWritten; push nNumberOfBytesToWrite; push lpBuffer; push hFile; call Prolog__WriteFile; mov bRet,eax }
return bRet; }
void _declspec(naked) Prolog__CreateEvent(){ _asm { // this is the space for the "saved istructions"
nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; // this is the place for the JMP
nop ; nop ; nop ; nop ; nop ; nop ; // dist
nop ; // dist
} }
HANDLE _I_CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
BOOL bManualReset, // reset type
BOOL bInitialState, // initial state
LPCWSTR lpName // object name
) { DWORD * pDw = (DWORD *)_alloca(sizeof(DWORD)); HANDLE hHandle;
LONG Ret = RtlRandomEx(&g_Seed); if (g_FaultFileEnabled && (Ret%g_Factor < g_Percent)) { return NULL; }
_asm{ push lpName; push bInitialState; push bManualReset; push lpEventAttributes call Prolog__CreateEvent; mov hHandle,eax } return hHandle; }
void _declspec(naked) Prolog__RtlFreeHeap(){ _asm { // this is the space for the "saved istructions"
nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; // this is the place for the JMP
nop ; nop ; nop ; nop ; nop ; } }
#define SPACE_STACK_ALLOC (4*sizeof(ULONG_PTR))
DWORD _I_RtlFreeHeap(VOID * pHeap,DWORD Flags,VOID * pBlock) { ULONG * pLong = (ULONG *)_alloca(sizeof(DWORD)); Flags |= (((HEAP *)pHeap)->Flags) | (((HEAP *)pHeap)->ForceFlags); DWORD dwRet;
if (pBlock && !(HEAP_SLOW_FLAGS & Flags)) { HEAP_ENTRY * pEntry = (HEAP_ENTRY *)pBlock-1;
DWORD RealSize = pEntry->Size * sizeof(HEAP_ENTRY); DWORD Size = RealSize - pEntry->UnusedBytes;
ULONG_PTR * pL = (ULONG_PTR *)pBlock;
if (0 == (pEntry->Flags & 0x01) ||0xf0f0f0f0 == pL[1] ) { if (!g_bDisableBreak) DebugBreak(); }
DWORD CanMemset = RealSize-sizeof(HEAP_ENTRY); memset(pBlock,0xF0,(CanMemset > SPACE_STACK_ALLOC)?CanMemset-SPACE_STACK_ALLOC:CanMemset); if (pEntry->Size >=4) { RtlCaptureStackBackTrace (1, (4 == pEntry->Size)?4:6, (PVOID *)(pEntry+2), pLong); }
}
_asm { push pBlock ; push Flags ; push pHeap ; call Prolog__RtlFreeHeap ; mov dwRet,eax ; }
return dwRet; }
void _declspec(naked) Prolog__RtlAllocateHeap(){ _asm { // this is the space for the "saved istructions"
nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; // this is the place for the JMP
nop ; nop ; nop ; nop ; nop ; nop ; // to make this distinct
} }
VOID * _I_RtlAllocateHeap(VOID * pHeap,DWORD Flags,DWORD Size) { ULONG * pLong = (ULONG *)_alloca(sizeof(DWORD)); Flags |= (((HEAP *)pHeap)->Flags) | (((HEAP *)pHeap)->ForceFlags); VOID * pRet; DWORD NewSize = (Size < (3*sizeof(HEAP_ENTRY)))?(3*sizeof(HEAP_ENTRY)+SPACE_STACK_ALLOC):(Size+SPACE_STACK_ALLOC);
/*
if (g_FaultHeapEnabled && g_NumFailInARow) { InterlockedDecrement(&g_NumFailInARow); goto here; } */ LONG Ret = RtlRandomEx(&g_Seed); if (g_FaultHeapEnabled && (Ret%g_Factor < g_Percent)) { // g_NumFailInARow = g_RowOfFailures;
//here:
// InterlockedIncrement(&g_NumFailedAllocation);
return NULL; }
_asm { push NewSize ; push Flags ; push pHeap ; call Prolog__RtlAllocateHeap ; mov pRet,eax ; }
if (pRet && !(HEAP_SLOW_FLAGS & Flags) ) {
if (NewSize <= 0xffff) NewSize = sizeof(HEAP_ENTRY)*((HEAP_ENTRY *)pRet-1)->Size; if (!(HEAP_ZERO_MEMORY & Flags)) { memset(pRet,0xc0,NewSize-sizeof(HEAP_ENTRY)); }
RtlCaptureStackBackTrace(1, 4, (PVOID *)((BYTE *)pRet+(NewSize-SPACE_STACK_ALLOC-sizeof(HEAP_ENTRY))), pLong); }
return pRet; }
void _declspec(naked) Prolog__RtlReAllocateHeap(){ _asm { // this is the space for the "saved istructions"
nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; // this is the place for the JMP
nop ; nop ; nop ; nop ; nop ; nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
} }
VOID * _I_RtlReAllocateHeap( HANDLE pHeap, // handle to heap block
DWORD Flags, // heap reallocation options
LPVOID lpMem, // pointer to memory to reallocate
SIZE_T Size // number of bytes to reallocate
){ ULONG * pLong = (ULONG *)_alloca(sizeof(DWORD)); Flags |= (((HEAP *)pHeap)->Flags) | (((HEAP *)pHeap)->ForceFlags); VOID * pRet;
DWORD NewSize = (Size < (3*sizeof(HEAP_ENTRY)))?(3*sizeof(HEAP_ENTRY)+SPACE_STACK_ALLOC):(Size+SPACE_STACK_ALLOC); _asm { push NewSize ; push lpMem ; push Flags ; push pHeap ; call Prolog__RtlReAllocateHeap ; mov pRet,eax ; }
if (pRet && !(HEAP_SLOW_FLAGS & Flags) ) {
if (NewSize <= 0xffff) NewSize = sizeof(HEAP_ENTRY)*((HEAP_ENTRY *)pRet-1)->Size; RtlCaptureStackBackTrace(1, 4, (PVOID *)((BYTE *)pRet+(NewSize-SPACE_STACK_ALLOC-sizeof(HEAP_ENTRY))), pLong); }
return pRet; }
void _declspec(naked) Prolog__RtlValidateHeap(){ _asm { // this is the space for the "saved istructions"
nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; // this is the place for the JMP
nop ; nop ; nop ; nop ; nop ; nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
} }
BOOL _I_RtlValidateHeap( HANDLE pHeap, // handle to heap block
DWORD dwFlags, // heap reallocation options
LPVOID lpMem // pointer to memory to validate
){ ULONG * pLong = (ULONG *)_alloca(sizeof(DWORD)); BOOL bRet;
g_bDisableBreak = TRUE; _asm { push lpMem ; push dwFlags ; push pHeap ; call Prolog__RtlValidateHeap ; mov bRet,eax ; }
g_bDisableBreak = FALSE;
return bRet; }
#if 0
#define MAX_REMEMBER (1024)
struct CSCCTrace { VOID * p1; VOID * p2; DWORD Tid; ULONG_PTR Trace[5]; } g_CSCCTrace[MAX_REMEMBER];
LONG g_CSCCIndex = -1;
void _declspec(naked) Prolog__CoSwitchCallContext(){ _asm { // this is the space for the "saved istructions"
nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; // this is the place for the JMP
nop ; nop ; nop ; nop ; nop ; nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
nop ; // dist
} }
HRESULT WINAPI _I_CoSwitchCallContext(IUnknown * pNew, IUnknown ** ppOld) { ULONG * pLong = (ULONG * )_alloca(sizeof(ULONG ));
long nIndex = InterlockedIncrement(&g_CSCCIndex); nIndex %= MAX_REMEMBER; CSCCTrace * pTrace = &g_CSCCTrace[nIndex]; pTrace->p1 = pNew; if (ppOld) pTrace->p2 = *ppOld; else pTrace->p2 = 0; pTrace->Tid =GetCurrentThreadId();
RtlCaptureStackBackTrace (1,5,(PVOID *)pTrace->Trace,pLong); HRESULT hRes; _asm { push ppOld; push pNew; call Prolog__CoSwitchCallContext; mov hRes,eax; }; return hRes; } #endif
void intercept2(WCHAR * Module, LPSTR Function, VOID * NewRoutine, VOID * pPrologStorage, DWORD Size) { FARPROC OldRoutine = GetProcAddress(GetModuleHandleW(Module),Function);
if (OldRoutine) { MEMORY_BASIC_INFORMATION MemBI; DWORD dwOldProtect; BOOL bRet, bRet2; DWORD dwRet;
dwRet = VirtualQuery(OldRoutine,&MemBI,sizeof(MemBI));
bRet = VirtualProtect(MemBI.BaseAddress, MemBI.RegionSize, PAGE_EXECUTE_WRITECOPY, &dwOldProtect);
dwRet = VirtualQuery(pPrologStorage,&MemBI,sizeof(MemBI));
bRet2 = VirtualProtect(MemBI.BaseAddress, MemBI.RegionSize, PAGE_EXECUTE_WRITECOPY, &dwOldProtect);
if (bRet && bRet2) { VOID * pToJump = (VOID *)NewRoutine; BYTE Arr[SIZE_JUMP_ADR] = { 0xe9 }; LONG * pOffset = (LONG *)&Arr[1]; * pOffset = (LONG)NewRoutine - (LONG)OldRoutine - SIZE_JUMP_ADR ; // save the old code
memcpy(pPrologStorage,OldRoutine,Size); // put the new code
memset(OldRoutine,0x90,Size); memcpy(OldRoutine,Arr,SIZE_JUMP_ADR); // adjust the prolog to continue
* pOffset = (LONG)OldRoutine + Size - (LONG)pPrologStorage - SIZE_SAVED_INSTR - SIZE_JUMP_ADR; // magic for nops
memcpy((BYTE *)pPrologStorage+SIZE_SAVED_INSTR,Arr,SIZE_JUMP_ADR); } } else { OutputDebugStringA("GetProcAddress FAIL\n"); } }
void unintercept(WCHAR * Module, LPSTR Function, VOID * pPrologStorage, DWORD Size) { FARPROC OldRoutine = GetProcAddress(GetModuleHandleW(Module),Function);
if (OldRoutine) { memcpy((void *)OldRoutine,pPrologStorage,Size); }
}
#endif /*_X86_*/
#ifndef STATUS_POSSIBLE_DEADLOCK
#define STATUS_POSSIBLE_DEADLOCK (0xC0000194L)
#endif
class CSetVectoredHandler { private: // static ULONG_PTR Base;
// static ULONG_PTR Limit;
PVOID pVectorHandler; enum ExceptionTypes { StatusAccessViolation, CXXException, StatusNoMemory, OtherExceptions, LastException }; static LONG ExceptionCounters[LastException]; /*
BOOL GetDllLimits(WCHAR * pDllName) { UNICODE_STRING DllName; RtlInitUnicodeString(&DllName,pDllName); PEB_LDR_DATA * pLdr = NtCurrentPeb()->Ldr; LIST_ENTRY * pHeadEntry = &pLdr->InLoadOrderModuleList; LIST_ENTRY * pEntry = pLdr->InLoadOrderModuleList.Flink; BOOL bFound = FALSE; while (pHeadEntry != pEntry) { LDR_DATA_TABLE_ENTRY * pData = CONTAINING_RECORD(pEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (0 == _wcsicmp(DllName.Buffer,pData->BaseDllName.Buffer)) { //OutputDebugStringA("found\n");
Base = (ULONG_PTR)pData->DllBase; Limit = Base + (ULONG_PTR)pData->SizeOfImage; bFound = TRUE; break; } pEntry = pEntry->Flink; } return bFound; } */ public: CSetVectoredHandler() { pVectorHandler = NULL; //if (GetDllLimits(L"fastprox.dll"))
//{
pVectorHandler = AddVectoredExceptionHandler(TRUE,CSetVectoredHandler::VectoredHandler); //}
}; ~CSetVectoredHandler() { if (pVectorHandler) RemoveVectoredExceptionHandler(pVectorHandler); }; static LONG WINAPI VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo) { PEXCEPTION_RECORD pExr = ExceptionInfo->ExceptionRecord; PCONTEXT pCxr = ExceptionInfo->ContextRecord; switch (pExr->ExceptionCode) { case STATUS_PRIVILEGED_INSTRUCTION: case STATUS_INVALID_HANDLE: case STATUS_STACK_OVERFLOW: case STATUS_POSSIBLE_DEADLOCK: case STATUS_ACCESS_VIOLATION: InterlockedIncrement(&ExceptionCounters[(LONG)StatusAccessViolation]); DebugBreak(); break; case 0xe06d7363: InterlockedIncrement(&ExceptionCounters[(LONG)CXXException]); break; case STATUS_NO_MEMORY: InterlockedIncrement(&ExceptionCounters[(LONG)StatusNoMemory]); break; default: InterlockedIncrement(&ExceptionCounters[(LONG)OtherExceptions]); break; } return EXCEPTION_CONTINUE_SEARCH; } } g_C;
LONG CSetVectoredHandler::ExceptionCounters[CSetVectoredHandler::LastException];
#endif
//
//
// ServiceMain
//
///////////////////////////////////////////////////////////
VOID WINAPI ServiceMain(DWORD dwNumServicesArgs, LPWSTR *lpServiceArgVectors) {
#ifdef INSTRUMENTED_BUILD
#ifdef _X86_
intercept2(L"ntdll.dll","RtlFreeHeap",_I_RtlFreeHeap,Prolog__RtlFreeHeap,5); intercept2(L"ntdll.dll","RtlAllocateHeap",_I_RtlAllocateHeap,Prolog__RtlAllocateHeap,5); intercept2(L"ntdll.dll","RtlReAllocateHeap",_I_RtlReAllocateHeap,Prolog__RtlReAllocateHeap,5); intercept2(L"ntdll.dll","RtlValidateHeap",_I_RtlValidateHeap,Prolog__RtlValidateHeap,7); intercept2(L"kernel32.dll","CreateEventW",_I_CreateEvent,Prolog__CreateEvent,6); intercept2(L"kernel32.dll","WriteFile",_I_WriteFile,Prolog__WriteFile,7); intercept2(L"kernel32.dll","ReadFile",_I_ReadFile,Prolog__ReadFile,7); g_nSuccConn = 0; #endif /*_X86_*/
#endif
RegSetDWORD(HKEY_LOCAL_MACHINE, HOME_REG_PATH, _T("ProcessID"), GetCurrentProcessId());
if (InitialBreak()) { DebugBreak(); }
g_ProgRes.Init(); g_ProgRes.Phase1Build();
MyService ThisService(SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_PAUSE_CONTINUE); ThisService.Run(SERVICE_NAME, dwNumServicesArgs, lpServiceArgVectors, (void *)&ThisService);
#ifdef INSTRUMENTED_BUILD
#ifdef _X86_
unintercept(L"ntdll.dll","RtlFreeHeap",Prolog__RtlFreeHeap,5); unintercept(L"ntdll.dll","RtlAllocateHeap",Prolog__RtlAllocateHeap,5); unintercept(L"ntdll.dll","RtlReAllocateHeap",Prolog__RtlReAllocateHeap,5); unintercept(L"ntdll.dll","RtlValidateHeap",Prolog__RtlValidateHeap,7); unintercept(L"kernel32.dll","CreateEventW",Prolog__CreateEvent,6); unintercept(L"kernel32.dll","WriteFile",Prolog__WriteFile,7); unintercept(L"kernel32.dll","ReadFile",Prolog__ReadFile,7); #endif /*_X86_*/
#endif
}
|