65.9K
CodeProject 正在变化。 阅读更多。
Home

为新手准备的应用程序提升:提升并写入注册表的逐步指南

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2009年4月8日

CPOL

3分钟阅读

viewsIcon

46362

downloadIcon

433

我们将使您的应用程序能够写入HKEY_LOCAL_MACHINE中的条目,并在必要时提升您的应用程序权限。

引言

我们将使用http://msdn.microsoft.com/en-us/library/bb530410.aspx#vistauac_topic6c中列出的COM方法,使您的应用程序能够写入HKEY_LOCAL_MACHINE中的条目,并在必要时提升您的应用程序权限。

我们将创建一个具有两种方法的新COM对象:WriteStringWriteLong,并在写入本地计算机条目时使用该COM对象。然后,我们将创建一个控制台应用程序来演示其用法。这非常简单,我们将在5分钟内完成所有操作。所以,让我们开始吧。

背景

如果您在阅读完本主题:http://msdn.microsoft.com/en-us/library/bb530410.aspx#vistauac_topic6b后,确定您的应用程序是混合应用程序,那么本文适合您。

使用代码

注册服务器后,您的应用程序可以使用CElevatedRegistryWritter类随时提升权限并在注册表中写入。

CElevatedRegistryWritter writter(GetConsoleWindow());
if(writter.WriteString(_T("Software\\Microsoft"), 
                       _T("Message"), _T("Hello World")) &&
    writter.WriteLong(_T("Software\\Microsoft"), 
                      _T("MyValue"), 100))
{
    print("All done!");
}

阶段1:创建注册表COM对象

  1. 创建一个新的ATL项目(我将其命名为Elevator)。
  2. 在ATL项目向导对话框中选择可执行文件(EXE)作为服务器类型。
  3. 向您的Elevator项目添加一个新类。
  4. 在添加类对话框中选择ATL简单对象,然后按添加。
  5. 在ATL简单对象向导对话框中将您的类命名为“LocalMachineWriter”,然后按完成。
  6. 向接口ILocalMachineWritter添加一个新方法。
  7. 将您的新方法命名为WriteString,并添加三个in参数:pathvarvalue,它们都是BSTR,然后按完成。
  8. WriteLong方法重复步骤6和7(value参数必须为LONG)。
  9. 修改CLocalMachineWritter::WriteStringCLocalMachineWritter::WriteLong的代码如下所示
  10. STDMETHODIMP CLocalMachineWriter::WriteString(BSTR path, BSTR var, BSTR value)
    {
        HKEY hk = NULL;
        if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, 
                 KEY_READ | KEY_WRITE, &hk))
            return E_FAIL;
    
        bool nReturn = E_FAIL;
    
        if(ERROR_SUCCESS == RegSetValueEx( hk, var, 0, REG_SZ, 
               (const BYTE*)value, (1 + (DWORD)_tcslen(value)) * sizeof(TCHAR) ))
            nReturn = S_OK;
    
        RegCloseKey(hk);
    
        return nReturn;
    }
    
    STDMETHODIMP CLocalMachineWriter::WriteLong(BSTR path, BSTR var, LONG value)
    {
        HKEY hk = NULL;
        if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
                      path, 0, KEY_READ | KEY_WRITE, &hk))
            return E_FAIL;
    
        bool nReturn = E_FAIL;
    
        if(ERROR_SUCCESS == RegSetValueEx( hk, var, 0, REG_DWORD, 
                      (const BYTE*)&value, sizeof(LONG)))
            nReturn = S_OK;
    
        RegCloseKey(hk);
    
        return nReturn;
    }
  11. 现在,我们必须启用我们的COM对象以提升权限,向注册表中添加两个条目。
  12. 打开LocalMachineWriter.rgs并添加粗体行

    HKCR
    {
        Elevator.LocalMachineWriter.1 = s 'LocalMachineWriter Class'
        {
            CLSID = s '{E89BECE0-84AC-4EE0-BC26-835C269C166F}'
        }
        Elevator.LocalMachineWriter = s 'LocalMachineWriter Class'
        {
            CLSID = s '{E89BECE0-84AC-4EE0-BC26-835C269C166F}'
            CurVer = s 'Elevator.LocalMachineWriter.1'
        }
        NoRemove CLSID
        {
            ForceRemove {E89BECE0-84AC-4EE0-BC26-835C269C166F} = 
                           s 'LocalMachineWriter Class'
            {
                ProgID = s 'Elevator.LocalMachineWriter.1'
                VersionIndependentProgID = s 'Elevator.LocalMachineWriter'
                ForceRemove 'Programmable'
                LocalServer32 = s '%MODULE%'
                'TypeLib' = s '{A38F2A11-AF97-4903-9DF3-F757291C9358}'
    
                val LocalizedString = s '@%MODULE%,-100'
                ForceRemove Elevation = s ''
                {
                    val Enabled = d '1'
                }
            }
        }
    }

    有关.rgs文件的更多信息,请参阅此链接:http://msdn.microsoft.com/en-us/library/k32htktc.aspx。有关为什么添加这些条目的信息,请参阅此链接:http://msdn.microsoft.com/en-us/library/ms679687.aspx

  13. 现在,编译COM对象。
  14. 最后,我们必须注册我们的COM对象才能让其他应用程序使用它。打开一个提升权限的Cmd(按住Ctrl+Shift键执行CMD.exe),转到DebugRelease目录,并使用/RegServer参数执行服务器进行注册

    我们完成了!

    我们创建了一个COM对象,可以写入本地计算机。现在,我们必须创建客户端代码以使用提升的权限运行我们的COM对象。

  15. 创建一个新的Win32控制台应用程序。将其命名为Client,然后按OK。
  16. New project

  17. 在Win32应用程序向导对话框中选择控制台应用程序,然后按完成。
  18. 修改StdAfx.h文件以包含Windows.hcomutil.h
  19. #include <windows.h>
    #include <comutil.h>
    
    #ifdef _DEBUG
    #pragma comment(lib, "comsuppwd.lib")
    #else
    #pragma comment(lib, "comsuppw.lib")
    #endif

    我们包含了ComUtil.h和库comsuppw,因为我们将使用_bstr_t类(http://msdn.microsoft.com/en-us/library/zthfhkd6(VS.71).aspx)。

  20. Elevator_i.cElevator_i.h从您的Elevator项目目录复制到您全新的客户端应用程序目录(这些文件是必要的,因为它们声明了接口和接口和对象的GUID)。
  21. 向您的客户端应用程序添加一个新类
  22. 在添加类对话框中选择C++类
  23. 将您的新类命名为CElevatedRegistryWritter,然后在泛型C++类向导对话框中按完成。
  24. 用这个替换ElevatedRegistryWritter.h
  25. #pragma once
    
    #include "Elevator_i.h"
    
    ///    <summary>
    ///    Wrapper class to load the LocalMachineWritter object
    /// with elevated credentials.
    ///    </summary>
    ///    <creation date="08/04/2009" by="Jose Angel"/>
    class CElevatedRegistryWritter
    {
        HWND wndParent;
        ILocalMachineWriter* object;
    
    #pragma region Constructors and destructor
    public:
        ///    <summary>
        ///        Constructor of the class
        ///    </summary>
        ///    <param name="wndParent">
        ///        Handle to a window. 
        ///        Use <c>GetConsoleWindow</c>
        ///         or <c>AfxGetMainWnd</c> for instance
        ///    </param>
        CElevatedRegistryWritter(HWND wndParent);
    
        ///    <summary>
        ///        Destructor. It will unload the Com object if necessary.
        ///    </summary>
        ~CElevatedRegistryWritter();
    #pragma endregion
    
    #pragma region Public methods
        ///    <summary>
        ///        This method ininialize the Com object
        ///     if necessary and write a string in the registry.
        ///    </summary>
        ///    <param name="path">Path of the key to write.</param>
        ///    <param name="var">Name of the key to write.</param>
        ///    <param name="value">Value to write.</param>
        ///    <returns>True if success.</returns>
        bool WriteString(LPCTSTR path, LPCTSTR var, LPCTSTR value);
    
        ///    <summary>
        ///        This method ininialize the Com object
        ///     if necessary and write a long in the registry.
        ///    </summary>
        ///    <param name="path">Path of the key to write.</param>
        ///    <param name="var">Name of the key to write.</param>
        ///    <param name="value">Value to write.</param>
        ///    <returns>True if success.</returns>
        bool WriteLong(LPCTSTR path, LPCTSTR var, LONG value);
    #pragma endregion
    
    #pragma region Implementation
    private:
        ///    <summary>
        ///        Utility method to create the object as an administrator.
        ///    </summary>
        HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, 
                REFIID riid, __out void ** ppv);
    #pragma endregion
    };

    并用这个替换ElevatedRegistryWritter.cpp

    #include "StdAfx.h"
    #include "ElevatedRegistryWritter.h"
    #include "Elevator_i.c"
    
    CElevatedRegistryWritter::CElevatedRegistryWritter(HWND _wndParent)
        : object(NULL)
        , wndParent(_wndParent)
    {
    }
    
    CElevatedRegistryWritter::~CElevatedRegistryWritter(void)
    {
        if(NULL != object)
            object->Release();
    }
    
    bool CElevatedRegistryWritter::WriteString(LPCTSTR path, LPCTSTR var, LPCTSTR value)
    {
        if( NULL == object && FAILED(CoCreateInstanceAsAdmin(wndParent, 
                CLSID_LocalMachineWriter, IID_ILocalMachineWriter, (void**)&object)))
            return false;
    
        SUCCEEDED(object->WriteString(_bstr_t(path), _bstr_t(var), _bstr_t(value)));
    }
    
    bool CElevatedRegistryWritter::WriteLong(LPCTSTR path, LPCTSTR var, LONG value)
    {
        if( NULL == object && FAILED(CoCreateInstanceAsAdmin(wndParent, 
                  CLSID_LocalMachineWriter, IID_ILocalMachineWriter, (void**)&object)))
            return false;
    
        SUCCEEDED(object->WriteLong(_bstr_t(path), _bstr_t(var), value));
    }
    
    
    HRESULT CElevatedRegistryWritter::CoCreateInstanceAsAdmin(HWND hwnd, 
            REFCLSID rclsid, REFIID riid, __out void ** ppv)
    {
        BIND_OPTS3 bo;
        WCHAR  wszCLSID[50];
        WCHAR  wszMonikerName[300];
    
        StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0])); 
        _stprintf_s(wszMonikerName, L"Elevation:Administrator!new:%s", wszCLSID);
    
        memset(&bo, 0, sizeof(bo));
        bo.cbStruct = sizeof(bo);
        bo.hwnd = hwnd;
        bo.dwClassContext  = CLSCTX_LOCAL_SERVER;
        return CoGetObject(wszMonikerName, &bo, riid, ppv);
    }
  26. 最后,更新您的main()函数,首先初始化COM,然后使用我们的类。
  27. #include "stdafx.h"
    #include "ElevatedRegistryWritter.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        CoInitialize(NULL);
    
        MessageBox(NULL, _T("Accept to elevate"), 
                   _T("Testing elevation"), MB_OK);
    
        CElevatedRegistryWritter writter(GetConsoleWindow());
        if(writter.WriteString(_T("Software\\Microsoft"), 
                _T("Message"), _T("Hello World")) && 
                writter.WriteLong(_T("Software\\Microsoft"), 
                _T("MyValue"), 100))
        {}
    
        CoUninitialize();
        return 0;
    }
为初学者提升应用程序权限:逐步指导您提升权限并在注册表中写入 - CodeProject - 代码之家
© . All rights reserved.