#include "precomp.h" #include #include #include #include #include "cntserv.h" #include "winmgmt.h" #include "sched.h" #include "resync2.h" #include //*********************************************************************** // // 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 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 }