以编程方式允许对注册表项进行写访问

时间:2010-03-13 12:21:36

标签: c++ winapi registry

我需要在产品安装期间以编程方式修改已知注册表项上的访问描述符。我想要它的工作方式是:

  1. 安装程序以管理模式运行。
  2. 创建了一个注册表项。
  3. 一个函数(我需要的函数)从密钥中查询ACL。
  4. 如果此函数发现“用户”组已具有写访问权限,则不应执行任何操作。
  5. 如果没有,它应该添加一个新权限,允许对“用户”组进行写访问。
  6. 为注册表项保存权限。
  7. 这个问题类似于Setting Registry key write permissions using .NET,但是,我需要一个C ++ / Win32实现。

    提前致谢

4 个答案:

答案 0 :(得分:4)

要获取和设置密钥的ACL,您需要使用RegGetKeySecurity和RegSetKeySecurity。然后,您需要遍历ACE,检查适用于“用户”组SID的任何内容。然后,您将修改/删除现有的和/或添加新的。请注意,在普通的旧Win32 C中使用ACL是一件痛苦的事。

答案 1 :(得分:1)

只需扩展Mikhail Vorotilov的答案,还可以从以下示例代码中汲取灵感 https://docs.microsoft.com/en-us/windows/win32/secbp/creating-a-dacl

bool RegistryGrantAll(HKEY hKey)
{
    bool bResult = false;

    PSECURITY_DESCRIPTOR sd = nullptr;

    const TCHAR* szSD =
        TEXT("D:")                  // Discretionary ACL
        TEXT("(D;OICI;KA;;;BG)")    // Deny access to built-in guests
        TEXT("(D;OICI;KA;;;AN)")    // Deny access to anonymous logon
        TEXT("(A;OICI;KRKW;;;AU)")  // Allow KEY_READ and KEY_WRITE to authenticated users ("AU")
        TEXT("(A;OICI;KA;;;BA)");   // Allow KEY_ALL_ACCESS to administrators ("BA" = Built-in Administrators)

    if (ConvertStringSecurityDescriptorToSecurityDescriptor((LPCTSTR)szSD, SDDL_REVISION_1, &sd, 0))
    {
        auto result = RegSetKeySecurity(hKey, DACL_SECURITY_INFORMATION, sd);
        if (ERROR_SUCCESS == result)
            bResult = true;
        else
            SetLastError(result);

        // Free the memory allocated for the SECURITY_DESCRIPTOR.
        LocalFree(sd);
    }

    return bResult;
}

如果函数返回false,则调用GetLastError()以获取有关失败原因的更多信息。

代码在VS2019上编译并似乎可以工作。
我尚未添加代码来检查hKey是否为有效的注册表句柄。

编辑:在测试之后,我对此进行了几次编辑。对不起,所有修改。我最终得出的结论比开始时更接近米哈伊尔的答案。

链接到更多信息:

https://docs.microsoft.com/en-us/windows/win32/secbp/creating-a-dacl

https://docs.microsoft.com/en-us/windows/win32/api/sddl/nf-sddl-convertstringsecuritydescriptortosecuritydescriptorw

https://docs.microsoft.com/en-us/windows/win32/secauthz/ace-strings

答案 2 :(得分:0)

授予访问权限的最小代码包含3个API调用。它为所有经过身份验证的用户和管理员提供对给定hkey的完全访问权限。

此代码段不包含正确的错误处理和报告。请勿将其复制/粘贴到生产代码中。

    PSECURITY_DESCRIPTOR sd = nullptr;
    ULONG sd_size = 0;
    TCHAR* rights = TEXT( "D:" )                // Discretionary ACL
                  TEXT( "(A;OICI;GA;;;AU)" )    // Allow full control to all authenticated users
                  TEXT( "(A;OICI;GA;;;BA)" );   // Allow full control to administrators

    ConvertStringSecurityDescriptorToSecurityDescriptor( rights, SDDL_REVISION_1, &sd, &sd_size );
    RegSetKeySecurity( hkey, DACL_SECURITY_INFORMATION, sd );
    LocalFree( sd );

确定“用户”是否具有对该密钥的写访问权限可能比预期的难。我最后将测试值写入注册表并检查了写入结果。

答案 3 :(得分:0)

Sup,希望OP仍然对该答案感兴趣。这是将ACE添加到ACL的工作代码,可用于将ACE添加到注册表或文件系统DACL。我还没有尝试过其他任何方法。您可能会注意到,不需要繁琐的RegGetKeySecurity或手动ACL编写。甚至不需要RegOpenKeyEx。有关更多信息,请检查this MS doc.

UPD 当然,它需要管理员权限才能执行。

// sk - alloced string / path to needed key
// common look: MACHINE\\Software\\... where MACHINE == HKEY_LOCAL_MACHINE
// google for more address abbrevations
PSECURITY_DESCRIPTOR pSD = 0;
EXPLICIT_ACCESS ea;
PACL pOldDACL = 0, pNewDACL = 0;
if (ERROR_SUCCESS == GetNamedSecurityInfo(sk, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, 0, 0, &pOldDACL, 0, &pSD)) {
    memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = KEY_ALL_ACCESS;
    ea.grfAccessMode = GRANT_ACCESS;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    ea.Trustee.ptstrName = <USERNAME HERE>; //DOMAIN\\USERNAME
    if (ERROR_SUCCESS == SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL)) {
        if (ERROR_SUCCESS == SetNamedSecurityInfo(sk, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, 0, 0, pNewDACL, 0)) {
            if (pSD != 0) LocalFree((HLOCAL)pSD);
            if (pNewDACL != 0) LocalFree((HLOCAL)pNewDACL);
            SAFE_FREE(sk);
            // WE'RE GOOD!
            return ... ;
        } else {
            if (pSD) LocalFree((HLOCAL)pSD);
            if (pNewDACL) LocalFree((HLOCAL)pNewDACL);
            SAFE_FREE(sk);
            // SetNamedSecurityInfo failed
            return  ... ;
        }
    } else {
        if (pSD) LocalFree((HLOCAL)pSD);
        if (pNewDACL) LocalFree((HLOCAL)pNewDACL);
        SAFE_FREE(sk);
        // SetEntriesInAcl failed
        return ... ;
    }
} else {
    if (pSD) LocalFree((HLOCAL)pSD);
    SAFE_FREE(sk);
    // GetNamedSecurityInfo failed
    return ... ;
}