Пример #1
0
VOID
WINAPI
GetServiceMainFunctions (
    _In_ PSVCHOST_SERVICE pService,
    _Out_ PVOID *pServiceMain,
    _Out_ PVOID *pPushServiceGlobals,
    _Out_ PDWORD lpdwError
    )
{
    DWORD dwError, cbDllLength, cbData, dwType;
    PSVCHOST_DLL pDll;
    ACTCTXW actCtx;
    LPCWSTR pszDllPath;
    HKEY hKey;
    HANDLE hActCtx;
    LPWSTR lpData;
    WCHAR szDllBuffer[MAX_PATH + 2], szManifestBuffer[MAX_PATH + 2];

    /* Initialize the activation context we might need later */
    RtlZeroMemory(&actCtx, sizeof(actCtx));
    actCtx.cbSize = sizeof(actCtx);

    /* We clean these up in our failure path so initialize them to NULL here */
    hActCtx = NULL;
    hKey = NULL;
    lpData = NULL;
    *lpdwError = ERROR_SUCCESS;

    /* Null terminate the string buffers */
    szDllBuffer[0] = UNICODE_NULL;
    szManifestBuffer[0] = UNICODE_NULL;

    /* Do we already have a DLL ready to go for this service? */
    pDll = pService->pDll;
    if (pDll != NULL) goto HaveDll;

    /* Nope, we're starting from scratch. Open a handle to parameters key */
    dwError = OpenServiceParametersKey(pService->pszServiceName, &hKey);
    if (dwError)
    {
        *lpdwError = dwError;
        ASSERT(*lpdwError != NO_ERROR);
        goto Quickie;
    }

    /* Allocate enough space to hold a unicode path (NULL-terminated) */
    cbData = MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL);
    lpData = MemAlloc(0, cbData);
    if (lpData == NULL)
    {
        /* No memory, bail out */
        *lpdwError = ERROR_NOT_ENOUGH_MEMORY;
        goto Quickie;
    }

    /* Query the DLL path */
    lpData[0] = UNICODE_NULL;
    dwError = RegQueryValueExW(hKey,
                               L"ServiceDll",
                               0,
                               &dwType,
                               (LPBYTE)lpData,
                               &cbData);
    if (dwError != ERROR_SUCCESS)
    {
        *lpdwError = dwError;
        DBG_ERR("RegQueryValueEx for the ServiceDll parameter of the %ws "
                "service returned %u\n",
                pService->pszServiceName,
                dwError);
        goto Quickie;
    }

    /* Is the registry data valid and present? */
    if ((dwType != REG_EXPAND_SZ) || (lpData[0] == UNICODE_NULL))
    {
        /* Nope, bail out */
        *lpdwError = ERROR_FILE_NOT_FOUND;
        DBG_ERR("The ServiceDll parameter for the %ws service is not of type "
                "REG_EXPAND_SZ\n",
                pService->pszServiceName);
        goto Quickie;
    }

    /* Convert the expandable path into an absolute path */
    ExpandEnvironmentStringsW(lpData, szDllBuffer, MAX_PATH);
    SvchostCharLowerW(szDllBuffer);

    /* Check if the service has a manifest file associated with it */
    cbData = MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL);
    dwError = RegQueryValueExW(hKey,
                               L"ServiceManifest",
                               NULL,
                               &dwType,
                               (LPBYTE)lpData,
                               &cbData);
    if (dwError != ERROR_SUCCESS)
    {
        /* Did we fail because one wasn't set? */
        if ((dwError != ERROR_PATH_NOT_FOUND) &&
            (dwError != ERROR_FILE_NOT_FOUND))
        {
            /* We failed for some other reason, bail out */
            *lpdwError = dwError;
            DBG_ERR("RegQueryValueEx for the ServiceManifest parameter of the "
                    "%ws service returned %u\n",
                    pService->pszServiceName,
                    dwError);
            goto Quickie;
        }

        /* We have no manifest, make sure the buffer is empty */
        szManifestBuffer[0] = UNICODE_NULL;

        /* We're done with this buffer */
        MemFree(lpData);
        lpData = NULL;

        /* Use the whole DLL path, since we don't have a manifest */
        pszDllPath = szDllBuffer;
    }
    else
    {
        /* Do we have invalid registry data? */
        if ((dwType != REG_EXPAND_SZ) || (*lpData == UNICODE_NULL))
        {
            /* Yes, pretend there's no manifest and bail out */
            *lpdwError = ERROR_FILE_NOT_FOUND;
            DBG_ERR("The ServiceManifest parameter for the %ws service is not "
                    "of type REG_EXPAND_SZ\n",
                    pService->pszServiceName);
            goto Quickie;
        }

        /* Expand the string into our stack buffer */
        ExpandEnvironmentStringsW(lpData, szManifestBuffer, MAX_PATH);

        /* We no longer need the heap buffer*/
        MemFree(lpData);
        lpData = NULL;

        /* Lowercase the manifest path */
        SvchostCharLowerW(szManifestBuffer);

        /* Now loop over the DLL path */
        cbDllLength = lstrlenW(szDllBuffer);
        while (cbDllLength)
        {
            /* From the end, until we find the first path separator */
            if (szDllBuffer[cbDllLength] == '\\' || szDllBuffer[cbDllLength] == '/')
            {
                /* Use just a short name (cut out the rest of the path) */
                pszDllPath = &szDllBuffer[cbDllLength + 1];
                break;
            }

            /* Try the next character */
            cbDllLength--;
        }
    }

    /* See if we already have a matching DLL and manifest for this service */
    pDll = FindDll(szManifestBuffer, pszDllPath, pService);
    if (pDll == NULL)
    {
        /* We don't have it yet -- does this DLL have a manifest? */
        if (szManifestBuffer[0] != UNICODE_NULL)
        {
            /* Create an activation context for it */
            actCtx.lpSource = szManifestBuffer;
            hActCtx = CreateActCtxW(&actCtx);
            if (hActCtx == INVALID_HANDLE_VALUE)
            {
                /* We've failed to create one, bail out */
                *lpdwError = GetLastError();
                DBG_ERR("CreateActCtxW(%ws) for the %ws service returned %u\n",
                        szManifestBuffer,
                        pService->pszServiceName,
                        *lpdwError);
                goto Quickie;
            }
        }

        /* Add this new DLL into the database */
        pDll = AddDll(szManifestBuffer, pszDllPath, pService, lpdwError);
        if (pDll)
        {
            /* Save the activation context and zero it so we don't release later */
            pDll->hActCtx = hActCtx;
            hActCtx = NULL;
        }
    }

    /* We either found, added, or failed to add, the DLL for this service */
    ASSERT(!pService->pDll);
    pService->pDll = pDll;

    /* In all cases, we will query the ServiceMain function, however*/
    RegQueryStringA(hKey,
                    L"ServiceMain",
                    REG_SZ,
                    &pService->pszServiceMain);

    /* And now we'll check if we were able to create it earlier (or find it) */
    if (!pService->pDll)
    {
        /* We were not, so there's no point in going on */
        ASSERT(*lpdwError != NO_ERROR);
        goto Quickie;
    }

    /* We do have a valid DLL, so now get the service main routine out of it */
HaveDll:
    *pServiceMain = GetServiceDllFunction(pDll,
                                          pService->pszServiceMain ?
                                          pService->pszServiceMain :
                                          "ServiceMain",
                                          lpdwError);

    /* And now get the globals routine out of it (this one is optional) */
    *pPushServiceGlobals = GetServiceDllFunction(pDll,
                                                 "SvchostPushServiceGlobals",
                                                 NULL);

Quickie:
    /* We're done, cleanup any resources we left behind */
    if (hKey != NULL) RegCloseKey(hKey);
    if (lpData != NULL) MemFree(lpData);
    if ((hActCtx) && (hActCtx != INVALID_HANDLE_VALUE)) ReleaseActCtx(hActCtx);
}
Пример #2
0
    void Create()
    {
        if ( ActivationCtxHandle != INVALID_HANDLE_VALUE )
        {
            return ;
        }

        HMODULE hKernel = GetModuleHandleW( L"KERNEL32" );
        if ( GetProcAddress( hKernel, "CreateActCtxW" ) == NULL )
        {
            // Pre XP OS
            return;
        }

        bool ManifestInFile = false;

        System::Reflection::Assembly^ CurrentAssembly = System::Reflection::Assembly::GetCallingAssembly();
        String^ AssemblyPath = CurrentAssembly->Location;
        try
        {
                if ( AssemblyPath == "" )
                {
                    String^ TempPath = System::IO::Path::GetTempFileName();
                    System::IO::StreamWriter^ sw = System::IO::File::CreateText(TempPath);
                    sw->Write (
                        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
                        "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"
                        "   <dependency>\n"
                        "       <dependentAssembly>\n"
                        "           <assemblyIdentity\n"
                        "               type='win32'\n"
#ifdef _DEBUG
                        "               name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugCRT'\n"
#else  /* _DEBUG */
                        "               name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT'\n"
#endif  /* _DEBUG */
                        "               version='" _CRT_ASSEMBLY_VERSION "'\n"
#ifdef _M_IX86
                        "               processorArchitecture='x86'\n"
#endif  /* _M_IX86 */
#ifdef _M_AMD64
                        "               processorArchitecture='amd64'\n"
#endif  /* _M_AMD64 */
#ifdef _M_IA64
                        "               processorArchitecture='ia64'\n"
#endif  /* _M_IA64 */
                        "               publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'/>\n"
                        "       </dependentAssembly>\n"
                        "   </dependency>\n"
                        "</assembly>\n"
                    );
                    sw->Close();
                    ManifestInFile = true;
                    AssemblyPath = TempPath;
                }

                cli::pin_ptr<const System::Char> pAssemblyPath = PtrToStringChars(AssemblyPath);

                ACTCTXW actctx;
                // Don't call memset. memset results in a call to msvcr*.dll which can be loaded from WinSXS
                // only after the activation context is activated.
                actctx.wProcessorArchitecture = 0;
                actctx.wLangId = 0;
                actctx.lpAssemblyDirectory = NULL;
                actctx.lpApplicationName = NULL;
                actctx.hModule = NULL;

                actctx.cbSize = sizeof( actctx );
                actctx.lpSource = pAssemblyPath;
                if (ManifestInFile)
                {
                    actctx.lpResourceName = 0;
                    actctx.dwFlags = 0;
                }
                else
                {
                    actctx.lpResourceName = MAKEINTRESOURCEW( 2 );
                    actctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
                }

                ActivationCtxHandle = CreateActCtxW( &actctx );
                if ( ActivationCtxHandle == INVALID_HANDLE_VALUE )
                {
                    if (!ManifestInFile)
                    {
                        actctx.lpResourceName = MAKEINTRESOURCEW( 1 );
                        ActivationCtxHandle = CreateActCtxW( &actctx );
                    }
                    if ( ActivationCtxHandle == INVALID_HANDLE_VALUE )
                    {
                    }
                }
            }
            finally
            {
                if (ManifestInFile)
                {
                    System::IO::File::Delete(AssemblyPath);
                }
            }
    }