修改 Windows 文件访问权限的多种方法_如何更改文件高级权限-程序员宅基地

技术标签: c++  Windows 基础编程  测试工具  windows  业余学习  

提示:本文修改后包含编程方法以及附注的工具方法,传统的资源管理器交互方法等等。

由于文件是安全对象,因此访问它们受访问控制模型控制,该模型控制对 Windows 中所有其他安全对象的访问。 

更改文件或目录对象的安全描述符,需要调用 SetNamedSecurityInfo 或 SetSecurityInfo 等函数。

ACLAccess Control List,用来表示用户(组)权限的列表,包括 DACL 和 SACL
ACEAccess Control Entry,ACL 中的元素;
DACLDiscretionary Access Control List,用来表示安全对象权限的列表;
SACLSystem Access Control List,用来记录对安全对象访问的日志。

关于这几个概念已经有很多资料解释,这里就不详细展开了。(以下仅介绍通过 Win32API 修改文件安全属性的一些内容)。

本文以 SetNamedSecurityInfo 函数为例,简单讲解如何通过编程修改指定文件的 ACL 主体和添加 ACE 条目。后文修改的文件比较特殊,它们受到本地内置安全主体 TrustedInstaller 的完全控制保护,本文旨在通过相关 API 实现修改这类文件的完全控制权限。有关内置安全主体 TrustedInstaller 的信息,需要具有一定的知识基础,限于篇幅原因这里不详细展开。


一、编程实现方法阐述

1.1 修改 ACL 的所有者

SetNamedSecurityInfo 函数用于在指定对象的安全描述符(ACL)中设置指定的安全信息。 调用方按名称标识对象。

这里的按名称标识对象,表示设置安全信息时候,目标对象名是字符串格式,且对于不同对象类型的字符串格式,可以参阅说明:SE_OBJECT_TYPE。我们这里要修改NTFS文件系统中指定文件的安全属性,按照标准需要填写文件绝对路径的宽字符串,其中路径以反斜杠 (" / ") 或者双斜杠 (" \\ ") 给出,并且要以 NULL 结尾。

下面给出该函数的参数:

DWORD SetNamedSecurityInfoW(
  [in]           LPWSTR               pObjectName,
  [in]           SE_OBJECT_TYPE       ObjectType,
  [in]           SECURITY_INFORMATION SecurityInfo,
  [in, optional] PSID                 psidOwner,
  [in, optional] PSID                 psidGroup,
  [in, optional] PACL                 pDacl,
  [in, optional] PACL                 pSacl
);

这些参数的定义是:

pObjectName 指定目标对象的名称;
ObjectType 指示 pObjectName 的类型,如果修改 NTFS 文件则填写为 SE_FILE_OBJECT;
SecurityInfo 指示要设置的安全信息的类型;
psidOwner 指向标识对象所有者的 SID 结构的指针;
psidGroup 指向标识对象主组的 SID 的指针;
pDacl 指向 对象的新 DACL 的指针;
pSacl 指向 对象的新 SACL 的指针。

其中,如果 SecurityInfo 填写为 OWNER_SECURITY_INFORMATION 表明对安全主体的操作(也就是控制列表所有者);如果填写为 DACL_SECURITY_INFORMATION 则表明对安全对象(ACE)的权限的操作。这里需要注意:如果调用方令牌对应的账户标识符(SID)不是文件安全主体指向的账户标识符,则对安全对象权限的操作会被拒绝

修改文件安全属性需要进程的令牌具有一定的访问控制权限,这里我们需要获取两个权限 SE_SECURITY_NAME 和 SE_TAKE_OWNERSHIP_NAME 。这两个权限可以通过 AdjustTokenPrivileges 函数获得,而赋予新的令牌则需要调用方线程具有管理员权限。所以进程需要以提升的令牌启动才能正确获取权限

从零开始的项目都是不容易的,有一个参考最好不过了。这里我们可以参考资源管理器的功能实现文件安全属性的修改,下面的图片展示了通过资源管理器查看的目标文件的安全属性页面信息:

目标文件的安全属性信息页
目标文件的安全属性信息页

通过观察,我们可以发现,当前的所有者为 TrustedInstaller 并且只有它具有完全控制权限,其他安全对象只具有读取和执行的权限。此外我们还发现,对于该文件权限修改的按钮都是灰色或者具有盾牌图标。我们将其与用户具有完全访问控制权的文件安全信息进行对比,就可以发现所有者信息起到了至关重要的作用,调用方必须为文件的安全主体或者权限比安全主体高,否则不能修改安全属性表。所以当正确获取权限后,我们首先需要修改文件的安全主体(所有者)。

首先我们简述一下通过资源管理器进行修改的步骤:

Step 1: 首先选中要修改的文件(夹),打开右键菜单,在菜单中找到“属性”项目,点击打开属性对话框;

Step 2: 在属性对话框中选中“安全”选项卡,右下角点击“高级(安全设置)”按钮;

Step 3: 可以看到该页面包含两个主要部分:1)所有者;2)成员及其权限

并且后面都有带有盾牌的“更改”按钮,再结合说明文档可知,如果当前进程代表的账户权限低于所有者所具有的权限,则低权限进程不具有修改高权限进程的权限能力;

这里我们需要先修改所有者,点击最上面的TrustedInstaller字样后面的更改按钮,此时可能弹出UAC对话框提示用户需要提升权限,也可能没有提示直接提升(取决于计算机配置的UAC警告级别)

Step 4: 此时会弹出选择所有者的对话框,点击“高级”按钮展开这个编辑器窗口:

Step 5: 在高级窗口中点击立即查找,在查找的列表中找到当前登陆用户的用户名,然后点击确定,或者选择everyone(字面意思,代表任何用户)。

Step 6: 逐级确定并应用,可以发现所有者被成功更改:

最后一步点击“应用”,然后再点击确定,应用更改,随后重新打开高级安全设置页面,选择要修改权限的成员,并发现编辑区域按钮被点亮,点击“添加/编辑”:

随后,在打开的窗口中,先点击蓝色字“选择主体”,类似于修改所有者的操作完成权限配置,并点击确定,最后点击应用即可完成整个修改操作:

最后,补充一下修改完成后改回TrustedInstaller的方法:在更改所有者时候,直接输入 NT SERVICE\TrustedInstaller 需要注意不能有拼写错误!然后其他步骤不变。

我们通过设置 SetNamedSecurityInfo 函数的 SecurityInfo 参数为 OWNER_SECURITY_INFORMATION 并指定 psidOwner 为指向新所有者的安全描述符 (SID) 结构的指针。

SID 就相当于所有者的身份证,那么我们如何获取到所需要的 SID 呢?

LookupAccountName 函数可供获取指定用户名对应的 SID 。

其参数如下:

BOOL LookupAccountNameW(
  [in, optional]  LPCWSTR       lpSystemName,
  [in]            LPCWSTR       lpAccountName,
  [out, optional] PSID          Sid,
  [in, out]       LPDWORD       cbSid,
  [out, optional] LPWSTR        ReferencedDomainName,
  [in, out]       LPDWORD       cchReferencedDomainName,
  [out]           PSID_NAME_USE peUse
);

其中,lpAccountName 指向指定帐户名称的以 NULL 结尾的字符串的指针。这里的本地账户名称可以通过输入已知的字符串如 "Administrators" 。注:采用 domain_name\user_name 格式的完全限定字符串来确保 LookupAccountName 函数在所需域中查找帐户,但本文不谈及域内操作,只谈本地操作。

关于账户名称的获取,有多种方法,如 GetUserName 可以获得创建当前调用线程所在帐户名称的字符串,环境变量函数 GetEnvironmentVariable 通过设置 lpName 参数为"USERNAME"可以获得当前所在帐户名称的字符串;使用 Windows Terminal Session API 获取当前会话对应的账户名称字符串,等等。这里通过 WTSQuerySessionInformation 函数并指定相关参数设置以获取当前登录账户的名称:

WTSQuerySessionInformationW(
        WTS_CURRENT_SERVER_HANDLE, 
        WTS_CURRENT_SESSION, 
        WTS_INFO_CLASS::WTSUserName, 
        &userName, 
        &nameSize);

然后将得到的字符串传递给 LookupAccountName 函数,获取对应的 SID 。

随后,调用 SetNamedSecurityInfo 并设置 pObjectNameObjectTypeSecurityInfo psidOwner 参数即可修改目标对象的所有者。

1.2 修改访问控制对象 (ACE) 信息

本文以在原有DACL表上添加新的对象权限为例进行讲解。有关于覆盖、删除、复制的方法需要自行调试。

一种通用的更新方法就是先获取到原始的DACL表,然后将其与要添加的内容合并为一张新的表。最后将新的表更新到文件对应的表上。

整个过程我们需要这几个步骤:

Step1: 调用 GetNamedSecurityInfo 并设置 DACL_SECURITY_INFORMATION 类型,获取旧的DACL表;

Step2: 调用 BuildExplicitAccessWithName 用于构建一个 ACE,包含需要的权限;

Step3: 调用 SetEntriesInAcl 合并 ACE 到 旧的DACL,返回合并后的新的 DACL;

Step4: 调用 SetNamedSecurityInfo 绑定新的 DACL 到文件对象。

一个典型的示例代码如下,其中 Step2 也可以直接为结构体成员赋值:

DWORD AddAceToObjectsSecurityDescriptor(
    LPTSTR pszObjName,          // name of object
    SE_OBJECT_TYPE ObjectType,  // type of object
    LPWSTR pszTrustee,          // trustee for new ACE
    TRUSTEE_FORM TrusteeForm,   // format of trustee structure
    DWORD dwAccessRights,       // access mask for new ACE
    ACCESS_MODE AccessMode,     // type of ACE
    DWORD dwInheritance         // inheritance flags for new ACE
)
{
    DWORD dwRes = 0;
    PACL pOldDACL = NULL, pNewDACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea = {};

    if (NULL == pszObjName)
        return ERROR_INVALID_PARAMETER;
    printf("|*|:为用户 %ws 获取文件:%ws 的访问权限。\n", pszTrustee, pszObjName);
    // Get a pointer to the existing DACL.

    dwRes = GetNamedSecurityInfoW(pszObjName, ObjectType,
        DACL_SECURITY_INFORMATION,
        NULL, NULL, &pOldDACL, NULL, &pSD);
    if (ERROR_SUCCESS != dwRes) {
        printf("GetNamedSecurityInfo Error %u\n", dwRes);
        goto Cleanup;
    }

    // Initialize an EXPLICIT_ACCESS structure for the new ACE. 

    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    //ea.grfAccessPermissions = dwAccessRights;
    //ea.grfAccessMode = AccessMode;
    //ea.grfInheritance = dwInheritance;
    //ea.Trustee.TrusteeForm = TrusteeForm;
    //ea.Trustee.ptstrName = pszTrustee;
    // 生成指定用户帐户的访问控制信息(这里指定赋予全部的访问权限)

    BuildExplicitAccessWithNameW(&ea, pszTrustee, dwAccessRights, AccessMode, dwInheritance);
    // Create a new ACL that merges the new ACE
    // into the existing DACL.

    dwRes = SetEntriesInAclW(1, &ea, pOldDACL, &pNewDACL);
    if (ERROR_SUCCESS != dwRes) {
        printf("SetEntriesInAcl Error %u\n", dwRes);
        goto Cleanup;
    }

    // Attach the new ACL as the object's DACL.

    dwRes = SetNamedSecurityInfoW(pszObjName, ObjectType,
        DACL_SECURITY_INFORMATION,
        NULL, NULL, pNewDACL, NULL);
    if (ERROR_SUCCESS != dwRes) {
        printf("SetNamedSecurityInfo Error %u\n", dwRes);
        goto Cleanup;
    }
    else {
        printf("成功:已经为用户 %ws 获取文件:%ws 的访问权限。\n", pszTrustee, pszObjName);
        return dwRes;
    }

Cleanup:

    if (pSD != NULL)
        LocalFree((HLOCAL)pSD);
    if (pNewDACL != NULL)
        LocalFree((HLOCAL)pNewDACL);

    std::cout << "|*|:操作失败! " << std::endl;
    return -1;
}

通过以上方法即可对指定路径文件进行安全访问权限的修改。

二、完整编程代码

2.1 完整代码

下面是按照上文思路编写的简单实现代码,需要将编译好的程序在提升的命令行中执行,命令行参数为 TestFile.exe <文件路径> 。(编译环境:Visual Studio C++)

注意:运行环境必须是管理员令牌,这样才能启用相应的权限,可以通过应用程序清单或者编程的方式(ShellExecuteEx, lpVerb + "runas")来请求管理员权限。

#include <iostream>
#include <stdio.h>
#include <aclapi.h>
#include <windows.h>
#include <tchar.h>
#include <stdlib.h>
#include <aclapi.h>
#include <wtsapi32.h>

#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "Wtsapi32.lib")

#define MAX_NAME 260

BOOL SetPrivilege(
    HANDLE hToken,          // access token handle
    LPCWSTR lpszPrivilege,  // name of privilege to enable/disable
    BOOL bEnablePrivilege   // to enable or disable privilege
)
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if (!LookupPrivilegeValueW(
        NULL,            // lookup privilege on local system
        lpszPrivilege,   // privilege to lookup 
        &luid))        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError());
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.

    if (!AdjustTokenPrivileges(
        hToken,
        FALSE,
        &tp,
        sizeof(TOKEN_PRIVILEGES),
        (PTOKEN_PRIVILEGES)NULL,
        (PDWORD)NULL))
    {
        printf("AdjustTokenPrivileges error: %u\n", GetLastError());
        return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)

    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    }

    return TRUE;
}

BOOL SeTakeOwnershipToken()
{

    printf("|*|操作:获取相关权限。该特权可以修改目标文件的 Ownership。\n");
    HANDLE hToken;
    BOOL bRet = OpenProcessToken(
        GetCurrentProcess(),    // 进程句柄(当前进程)
        TOKEN_ALL_ACCESS,    // 全权访问令牌
        &hToken    // 返回的参数 进程令牌句柄 (就是AdjustTokenPrivileges的第一个参数)
    ); // 获取进程的令牌句柄
    if (bRet != TRUE) {
        printf("获取令牌句柄失败!\nPlease wait...\n");
        return FALSE;
    }
    // 提升权限
    BOOL set_SECURITY = SetPrivilege(hToken, SE_SECURITY_NAME, TRUE);
    if (!set_SECURITY || GetLastError() != ERROR_SUCCESS)
    {
        printf("提升SECURITY权限失败 Error: %u\n|*|:操作失败!\nPlease wait...\n", GetLastError());
        Sleep(5000);
        return FALSE;
    }
    // 提升获得所有者权限
    BOOL set_OWNER = SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE);
    if (!set_OWNER || GetLastError() != ERROR_SUCCESS)
    {
        printf("提升TAKE OWNERSHIP权限失败 Error: %u\n|*|:操作失败!\nPlease wait...\n", GetLastError());
        Sleep(5000);
        return FALSE;
    }
    printf("提升权限成功! \n");
    return TRUE;
}


BOOL ChangeTrusteeViaObjectsSecurity(
    LPTSTR pszObjName,          // name of object
    LPTSTR pszTrustee,          // trustee for new ACE
    SE_OBJECT_TYPE ObjectType,  // type of object. value :SE_FILE_OBJECT, /* 注册表为:SE_REGISTRY_KEY */
    SECURITY_INFORMATION  SecurityInfo  // Security Operational Information. value:OWNER_SECURITY_INFORMATION

)
{
    DWORD dwRes = 0;
    // LookupAccountName函数所需要的变量
    wchar_t* userName = nullptr;
    wchar_t sid[MAX_NAME]{ L'\0' };
    DWORD nameSize = 0;

    WTSQuerySessionInformationW(
        WTS_CURRENT_SERVER_HANDLE, 
        WTS_CURRENT_SESSION, 
        WTS_INFO_CLASS::WTSUserName, 
        &userName, 
        &nameSize);

    wchar_t userSID[MAX_NAME]{ L'\0' };
    wchar_t userDomain[MAX_NAME]{ L'\0' };
    DWORD sidSize = sizeof(userSID);
    DWORD signSidSize = sizeof(userSID);
    DWORD domainSize = sizeof(userDomain) / sizeof(WCHAR);


    SID_NAME_USE snu;
    dwRes = LookupAccountNameW(NULL,
        userName,
        userSID,
        &sidSize,
        userDomain,
        &domainSize,
        &snu);
    WTSFreeMemory(userName);
    //获取用户名SID
    if (ERROR_SUCCESS != dwRes)// 调用成功返回值为0
    {
        PSID_IDENTIFIER_AUTHORITY psia = GetSidIdentifierAuthority(userSID);
        signSidSize = swprintf_s(sid, sizeof(sid)/sizeof(wchar_t), L"S-%lu-", SID_REVISION);
        signSidSize = (signSidSize + swprintf_s(sid + wcslen(sid), sizeof(sid), L"%-lu", psia->Value[5]));


        int i = 0;
        int subAuthorities = *GetSidSubAuthorityCount(userSID);


        for (i = 0; i < subAuthorities; i++)
        {
            signSidSize += swprintf_s(sid + signSidSize, sizeof(sid), L"-%lu", *GetSidSubAuthority(userSID, i));
        }
        printf("Account SID: %ws\n", sid);
        // 更改所有者
        if (!SetNamedSecurityInfoW
        (pszObjName,
            ObjectType, /* 注册表为:SE_REGISTRY_KEY */
            SecurityInfo, /* 更改所有者 */
            &userSID, /* 需要更改所有者的SID */
            NULL, NULL, NULL))
        {
            printf("成功更改所有者! \n");
            return TRUE;
        }
        else {
            printf("Security Info:OWNER_SECURITY_INFORMATION.\nSetNamedSecurityInfo Error %u\nPlease wait...\n", dwRes);
            Sleep(5000);
        }
    }
    else {
        printf("LookupAccountName Error %u\nPlease wait...\n", dwRes);
        Sleep(5000);
    }
    return FALSE;
}


DWORD AddAceToObjectsSecurityDescriptor(
    LPTSTR pszObjName,          // name of object
    SE_OBJECT_TYPE ObjectType,  // type of object
    LPWSTR pszTrustee,          // trustee for new ACE
    TRUSTEE_FORM TrusteeForm,   // format of trustee structure
    DWORD dwAccessRights,       // access mask for new ACE
    ACCESS_MODE AccessMode,     // type of ACE
    DWORD dwInheritance         // inheritance flags for new ACE
)
{
    DWORD dwRes = 0;
    PACL pOldDACL = NULL, pNewDACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea = {};

    if (NULL == pszObjName)
        return ERROR_INVALID_PARAMETER;
    printf("|*|:为用户 %ws 获取文件:%ws 的访问权限。\n", pszTrustee, pszObjName);
    // Get a pointer to the existing DACL.

    dwRes = GetNamedSecurityInfoW(pszObjName, ObjectType,
        DACL_SECURITY_INFORMATION,
        NULL, NULL, &pOldDACL, NULL, &pSD);
    if (ERROR_SUCCESS != dwRes) {
        printf("GetNamedSecurityInfo Error %u\n", dwRes);
        goto Cleanup;
    }

    // Initialize an EXPLICIT_ACCESS structure for the new ACE. 

    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    //ea.grfAccessPermissions = dwAccessRights;
    //ea.grfAccessMode = AccessMode;
    //ea.grfInheritance = dwInheritance;
    //ea.Trustee.TrusteeForm = TrusteeForm;
    //ea.Trustee.ptstrName = pszTrustee;
    // 生成指定用户帐户的访问控制信息(这里指定赋予全部的访问权限)

    BuildExplicitAccessWithNameW(&ea, pszTrustee, dwAccessRights, AccessMode, dwInheritance);
    // Create a new ACL that merges the new ACE
    // into the existing DACL.

    dwRes = SetEntriesInAclW(1, &ea, pOldDACL, &pNewDACL);
    if (ERROR_SUCCESS != dwRes) {
        printf("SetEntriesInAcl Error %u\n", dwRes);
        goto Cleanup;
    }

    // Attach the new ACL as the object's DACL.

    dwRes = SetNamedSecurityInfoW(pszObjName, ObjectType,
        DACL_SECURITY_INFORMATION,
        NULL, NULL, pNewDACL, NULL);
    if (ERROR_SUCCESS != dwRes) {
        printf("SetNamedSecurityInfo Error %u\n", dwRes);
        goto Cleanup;
    }
    else {
        printf("成功:已经为用户 %ws 获取文件:%ws 的访问权限。\n", pszTrustee, pszObjName);
        return dwRes;
    }

Cleanup:

    if (pSD != NULL)
        LocalFree((HLOCAL)pSD);
    if (pNewDACL != NULL)
        LocalFree((HLOCAL)pNewDACL);

    std::cout << "|*|:操作失败! " << std::endl;
    return -1;
}



int wmain(int argc, wchar_t* argv[])
{
    setlocale(LC_CTYPE, "CHS");//让wprintf()支持中文
    if (argc != 2)
    {
        std::cout << "Invalid Parameters!" << std::endl;
        return 0;
    }

    wchar_t* path = argv[1];
    wchar_t* pszObjName = path;

    // 获取当前用户名
    wchar_t* currentUser = nullptr;
    DWORD dwSize_currentUser = 0;

    WTSQuerySessionInformationW(
        WTS_CURRENT_SERVER_HANDLE, 
        WTS_CURRENT_SESSION,
        WTS_INFO_CLASS::WTSUserName,
        &currentUser,
        &dwSize_currentUser);

    if (!SeTakeOwnershipToken()) {
        std::cout << "|*|:在未获得SE_TAKE_OWNERSHIP_NAME特权时,继续更改文件所有者可能失败! " << std::endl;
    }

    // 更改ACL下的安全主体,以获得ACE控制权
    if (ChangeTrusteeViaObjectsSecurity(pszObjName,
        currentUser, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION))
    {
        // 覆盖ACL以获得完全控制的访问权限
        if (AddAceToObjectsSecurityDescriptor(pszObjName,
            SE_FILE_OBJECT,
            currentUser,
            TRUSTEE_IS_OBJECTS_AND_SID,
            GENERIC_ALL,
            GRANT_ACCESS,
            SUB_CONTAINERS_AND_OBJECTS_INHERIT) == -1)
        {
            std::cout << "ACE操作已执行。" << std::endl;
        }
    }
    else {
        std::cout << "无法更改ACL下的安全主体,继续更改ACE控制权可能会失败。" << std::endl;
        // 覆盖ACL以获得完全控制的访问权限
        if (AddAceToObjectsSecurityDescriptor(pszObjName,
            SE_FILE_OBJECT,
            currentUser,
            TRUSTEE_IS_OBJECTS_AND_SID,
            GENERIC_ALL,
            GRANT_ACCESS,
            SUB_CONTAINERS_AND_OBJECTS_INHERIT) == -1)
        {
            std::cout << "ACE操作已执行。" << std::endl;
        }

    }
    std::cout << "所有操作已完成。" << std::endl;
    system("pause");

    return 0;
}

2.2 调试效果

下图是在提升的命令提示符中执行的效果:

程序执行过程
程序执行过程

从图中可见程序执行完毕,并且没有错误。

下图展示的是程序执行完毕后,目标对象的属性变化:

目标被修改后的安全属性
目标被修改后的安全属性

从图中可以看出目标对象的所有者发生变化,且为当前登陆账户添加了完全控制权限。

三、利用Windows工具实现修改安全控制对象权限

3.1 通过 ICacls 命令实现修改访问控制权限

      icacls

      Intergrity Control Access Control List: 完整性权限控制列表
      Windows系统下控制文件及文件夹的访问权限的命令行指令,相当于Linux中的chmod
原命令cacls已经被废弃。

      这一篇博客园作者整理的命令详细信息比较全面清晰:Cacls和ICacls - 傩舞 - 博客园 (cnblogs.com)

3.2 通过 powershell / 注册表 实现修改访问控制权限

就不详细列出了,这里给出一篇知乎,整理的也比较全面:渗透技巧——Windows下的Access Control List - 知乎


本文为原创文章,转载请注明出处:

https://blog.csdn.net/qq_59075481/article/details/132459343

发布于:2023/08/23;修改于:2023/09/19,2024/03/14.

本人博客:涟幽516-程序员宅基地涟幽516擅长C++学习笔记,Win10动态壁纸开发,Windows上的编程,等方面的知识,涟幽516关注python,c++,c语言,系统安全领域.https://blog.csdn.net/qq_59075481

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_59075481/article/details/132459343

智能推荐

什么是内部类?成员内部类、静态内部类、局部内部类和匿名内部类的区别及作用?_成员内部类和局部内部类的区别-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别

分布式系统_分布式系统运维工具-程序员宅基地

文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具

用Exce分析l数据极简入门_exce l趋势分析数据量-程序员宅基地

文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量

宁盾堡垒机双因素认证方案_horizon宁盾双因素配置-程序员宅基地

文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置

谷歌浏览器安装(Win、Linux、离线安装)_chrome linux debian离线安装依赖-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖

烤仔TVの尚书房 | 逃离北上广?不如押宝越南“北上广”-程序员宅基地

文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...

随便推点

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序

汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用_uds协议栈 源代码-程序员宅基地

文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码

AUTOSAR基础篇之OS(下)_autosar 定义了 5 种多核支持类型-程序员宅基地

文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型

VS报错无法打开自己写的头文件_vs2013打不开自己定义的头文件-程序员宅基地

文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件

【Redis】Redis基础命令集详解_redis命令-程序员宅基地

文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令

URP渲染管线简介-程序员宅基地

文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线

推荐文章

热门文章

相关标签