避免在 Vista 中使用 UAC

问题描述 投票:0回答:4

我正在编写一个应用程序,为需要将数据保存到程序文件(对于相关程序)的程序下载并安装插件。现在,这在禁用 uac 的 xp 和 vista 上运行良好,但由于虚拟文件夹的原因,它在普通 vista 上失败。

如何解决这个问题而不需要每次启动应用程序时都请求管理员权限?

P.s.程序是用 c++ 编写的,vis 2005

编辑:文件系统虚拟文件夹:http://www.codeproject.com/KB/vista-security/MakingAppsUACAware.aspx

c++ windows-vista uac
4个回答
9
投票

仅在安装过程中写入程序文件。之后,写入用户文件夹。

您可以稍后提升应用程序权限,但只会延迟提示。 UAC 的全部目的是防止随机应用程序写入需要管理员权限的文件夹。 (好吧,不是全部,而是其中的很大一部分。)

您可以创建一个具有管理员权限的服务并向其发送命令以将下载的文件移动到所需的目标目录中,但是如果您设计不仔细,这会导致用户的系统被其他应用程序滥用。

本文讨论如何让应用程序与 UAC 良好配合。另外,请在这里参阅这篇文章


1
投票

当我与 Microsoft 交谈时,他们建议我编写第二个应用程序,您将其视为需要管理权限。您使用此应用程序将文件从安全位置(例如用户程序数据目录)部署到程序文件目录(请注意,如果您的 DLL 未签名,那么这是一个巨大的安全漏洞,因为病毒/恶意用户可以操纵函数调用之前的文件)。

您的非管理应用程序可以调用此应用程序,这将触发 UAC。了解UAC的人不会在意,并且会很高兴地点击你的应用程序。那些讨厌它的人会关掉它。如果用户取消 UAC 对话框,启动新进程(需要管理员权限)的调用将引发 win32 异常,因此请小心捕获该异常。

vista 中的问题是,如果您不是管理员,它会尝试通过虚拟化程序文件目录来帮助您。根据设计,除非您是管理员,否则您无法写入程序文件目录。

另一个选项是将所有“更新”创建为 MSI 更新。这样 Windows 安装程序将为您触发 UAC,您可以为您的软件提供徽标等。

选项 3 是使用 clickonce 部署,这将允许您在没有 UAC 的情况下自动更新程序,但您生活在用户系统上的沙箱中,这可能不适用于您应用程序的当前设计。


0
投票

我通过创建一个 Windows 服务来解决 uac,该服务可以完成我需要的工作,并且仅在应用程序运行时运行。


0
投票

我正在编写一个应用程序,用于下载并安装需要将数据保存到程序文件的程序的插件(对于相关程序)。现在,这在禁用 uac 的 xp 和 vista 上运行良好,但由于虚拟文件夹的原因,它在普通 vista 上失败。

那是你的问题。

Program Files
不是插件的正确位置。 Program Files 文件夹用于存放应用程序。该文件夹受到保护,因此标准用户(或以标准用户身份运行的恶意软件)无法对其进行修改。

可更新的辅助数据属于

ProgramData
。例如:

%ProgramData%\Contoso\Frobber\Addons

然后在安装过程中更改 ProgramData 文件夹的权限,以向 Everyone 授予 完全控制

procedure GrantAllUsersFullControlOfFileOrFolder(Path: string);
const
    SECURITY_NULL_SID_AUTHORITY:    TSIDIdentifierAuthority = (Value: (0,0,0,0,0,0));  //S-1-0  ntifs.h
    SECURITY_WORLD_SID_AUTHORITY:   TSIDIdentifierAuthority = (Value: (0,0,0,0,0,1));  //S-1-1
    SECURITY_LOCAL_SID_AUTHORITY:   TSIDIdentifierAuthority = (Value: (0,0,0,0,0,2));  //S-1-2
    SECURITY_CREATOR_SID_AUTHORITY: TSIDIdentifierAuthority = (Value: (0,0,0,0,0,3));  //S-1-3
    SECURITY_NT_AUTHORITY:          TSIDIdentifierAuthority = (Value: (0,0,0,0,0,5));  //S-1-5

    //Relative identifiers (RIDs)
    SECURITY_NULL_RID  = 0;         //in authority S-1-0
    SECURITY_WORLD_RID = 0;         //in authority S-1-1
    SECURITY_LOCAL_RID = 0;         //in authority S-1-2
    SECURITY_CREATOR_OWNER_RID = 0; //in authority S-1-3
    SECURITY_CREATOR_GROUP_RID = 1; //in authority S-1-3

    SECURITY_BUILTIN_DOMAIN_RID = $00000020; // 32 --> S-1-5-32
    DOMAIN_ALIAS_RID_ADMINS     = $00000220; //544 --> S-1-5-32-544
    DOMAIN_ALIAS_RID_USERS      = $00000221; //545 --> S-1-5-32-545 A local group that represents all users in the domain.
var
    usersSID: PSID;
    sd: PSECURITY_DESCRIPTOR;
    oldAcl, newAcl: PACL;
    dw: DWORD;
    ea: EXPLICIT_ACCESS;
begin
    //Create a well-known SID for the "Users" group (S-1-5-32-545)
    usersSid := StringToSid('S-1-5-32-545'); //well-known "Users" group
    try
        //Get the current DACL. Free SecurityDescriptor with LocalFree
        sd := nil;
        dw := GetNamedSecurityInfo(PChar(Path), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, @oldAcl, nil, {var}sd);
        if (dw <> ERROR_SUCCESS) then
            RaiseLastWin32Error;
        try
            // Initialize an EXPLICIT_ACCESS structure for the new ACE
            ZeroMemory(@ea, SizeOf(EXPLICIT_ACCESS));
            ea.grfAccessPermissions  := GENERIC_READ or GENERIC_WRITE or GENERIC_EXECUTE {or GENERIC_ALL}; //Yes, it's not "really" full control
            ea.grfAccessMode         := GRANT_ACCESS;
            ea.grfInheritance        := SUB_CONTAINERS_AND_OBJECTS_INHERIT;
            ea.Trustee.TrusteeForm   := TRUSTEE_IS_SID;
            ea.Trustee.TrusteeType   := TRUSTEE_IS_GROUP; //TRUSTEE_IS_WELL_KNOWN_GROUP;
            ea.Trustee.ptstrName     := PChar(usersSID);

            // Create a new ACL that merges the new ACE into the existing ACL. Use LocalFree to free newAcl
            dw := SetEntriesInAcl(1, @ea, oldAcl, {var}newAcl); //use LocalFree to free newAcl
            if dw <> ERROR_SUCCESS then
                RaiseLastOSError(dw);
            try
                //Attach the new ACL as the object's new DACL
                dw := SetNamedSecurityInfo(PChar(Path), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, newAcl, nil);
                if (dw <> ERROR_SUCCESS) then
                    RaiseLastWin32Error;
            finally
                LocalFree(HLOCAL(newAcl));
            end;
        finally
            LocalFree(HLOCAL(sd));
        end;
    finally
        LocalFree(HLOCAL(usersSid));
    end;
end;

如果您确实不想将其放入正确的 ProgramData 文件夹中,您也可以授予每个人对您的 Program Files 文件夹的完全控制权。

© www.soinside.com 2019 - 2024. All rights reserved.