教你利用Windows訪問控制搞事情

開篇福利

FkUpdate
Win10自動更新是真的煩人,每次按照網上的步驟禁用自動更新後,不用過多久系統又自動恢復了Update!因而本身研究了訪問控制,利用訪問控制原理修改服務對應的註冊表權限,讓系統沒法修改服務的狀態,達到永久禁用自動更新的效果!目前爲止還沒有發現Bug,因此共享給你們使用!只但願你們給文章點點贊!
永久禁用Windows自動更新 - 下載鏈接編程

FileLocker
利用訪問控制原理修改文件和上層目錄的權限,使得文件不可被刪除。目前爲止也只能防止文件誤刪!以後可能會添加防止移動、防止修改等功能!
防止文件誤刪 - 下載連接安全

概念普及

經常使用術語
ACL(Access Control List) - Windows訪問控制列表spa

  • DACL(Discretionary Access Control List) - 任意訪問控制列表
  • SACL(System Access Control List) - 系統訪問控制列表

ACE(Access Control Entries) - 訪問控制條目操作系統

SD(Security Descriptor) - 安全描述符線程

SID(Security Identifier) - 安全標識符3d

AccessToken - 訪問令牌code

詳細解釋
從簡單到複雜的依次解釋對象

  1. SID,用於標識用戶,組和計算機賬戶,首次建立賬戶時會得到一個惟一的SID用於標識該帳戶。簡單來講就如同每一個大學生入學都會分配一個惟一的學號,這個學號就是你的證實
  2. ACL,用來講明某個對象的訪問權限,由DACL和SACL組成,具體的某項權限稱爲ACE。簡單來講就如同大學校園裏的各項規定,任何一個對象都有它特定的規則,假設某個具體對象爲教室裏的電腦,學生們只能看,而老師們能夠操控,這就是教室裏的電腦這個對象的訪問權限
  3. SD,包含與安全對象相關的一些安全信息,包括該對象的全部者和所屬組的SID,DACL,SACL以及一組控制位(用於限定全部者SID,DACL和SACL)
  4. AccessToken,用來控制對安全對象的訪問,訪問令牌包含登陸會話的安全信息,主要用來標識用戶,用戶組的權限。系統在用戶登陸時建立訪問令牌,而且該用戶執行的每一個進程都具備該令牌的副本

注意1:SACL主要用於審覈和記錄訪問的,DACL纔是具體的權限列表,因此咱們平時講的ACL一般是指DACL
注意2:SD是爲了方便編程提出的概念(一個結構體而已),實際上操做系統是利用AccessToken和ACL來肯定對某個文件、進程等的訪問權限blog

權限檢查過程
每一個計算機帳戶在登陸是都會得到一個訪問令牌AccessToken,這個令牌會說明當前用戶的權限!而每一個文件或其它對象都有它本身的訪問控制列表ACL,即說明哪些帳戶擁有哪些權限!當該帳戶嘗試讀取或改寫某個文件時,操做系統會將當前帳戶的訪問令牌權限和目標文件每一個具體的權限(ACE)按順序做比較(只與SID相同的ACE進行比較),直到發生如下事件:
1、拒絕訪問的ACE明確拒絕對線程訪問令牌中列出的其中一個受託者請求的任何訪問權限
2、線程訪問令牌中列出的受託者的一個或多個容許訪問的ACE明確授予全部請求的訪問權限
3、已檢查全部ACE,而且仍然至少有一個未明確容許的請求訪問權限,在這種狀況下,隱式拒絕訪問繼承

注意:訪問控制列表ACL中的ACE有幾大原則(拒絕大於容許、權限最小化、權限繼承性以及權限累加)

動手實踐

查看文件ACL
講了半天ACL是否是感受太抽象了,來實際看看什麼是ACL吧!你只須要在任意文件上右鍵-屬性-安全-高級就能看到該文件的ACL了!其中權限選項卡中就是DACL,審覈選項卡中就是SACL,全部者擁有對DACL的徹底控制權
圖片描述

其中SYSTEM用戶組擁有對該文件的讀取權限,這樣一條具體的某個用戶的某項權限就是ACL中的訪問控制條目(ACE)

簡單修改權限
修改當前用戶組對某個文件只有讀取權限,假如當前用戶組是管理員的話還須要修改Administrators組的權限!第一步右鍵-屬性-安全並選中當前用戶點擊編輯
圖片描述

第二步只勾選容許-讀取,發現不可勾選
圖片描述

第三步禁用繼承,必需要禁用繼承不然不可更改,點擊高級-更改權限並取消勾選包括可從該對象的父項繼承的權限,彈窗選擇添加,而後肯定
圖片描述

第四步重複第二步,並更改Administrators組的權限
圖片描述

第五步嘗試改寫該文件,會提示沒有權限

注意:文件夾擁有繼承和傳播屬性,文件擁有繼承屬性,繼承屬性很好理解就是直接複製父目錄的ACL,傳播就是當前文件夾是否容許子文件或子文件夾繼承

FkUpdate核心講解

服務相關
開啓關閉服務,必須用到的幾個API:
OpenSCManager
OpenService
StartService
ControlService
QueryServiceStatus
ChangeServiceConfig
CloseServiceHandle

註冊表ACL相關
核心API:
GetNamedSecurityInfo
SetNamedSecurityInfo
SetEntriesInAcl
GetExplicitEntriesFromAcl
AllocateAndInitializeSid
DeleteAce

具體思路
禁用自動更新:第一步中止Update服務,第二步Update啓動狀態改成禁用,第三步Update註冊表全部者改成當前用戶,第四步禁用繼承並添加,第五步修改全部用戶組的權限爲只讀,第六步註冊表全部者改成SYSTEM
恢復自動更新:第一步Update註冊表全部者改成當前用戶,第二步刪除全部ACL,第三步啓用繼承,第四步註冊表全部者改成SYSTEM,第五步Update服務狀態改成自動,第六步啓動Update服務

BOOL enableUpdate() {
    changeObjectOwner(updateReg, FALSE);
    enInherit(updateReg);
    changeObjectOwner(updateReg, TRUE);
    changeStartType(updateServ, SERVICE_AUTO_START);
    startSrv(updateServ);
    return TRUE;
}

BOOL disableUpdate() {
    PACL pOldDACL = NULL, pNewDACL = NULL;
    DWORD dwRes = 0, dwSize = 0, i = 0;
    PSECURITY_DESCRIPTOR pSD;
    SID_NAME_USE eUse = SidTypeUnknown;
    PEXPLICIT_ACCESS pEa;
    ULONG uCount;

    stopSrv(updateServ);
    changeStartType(updateServ, SERVICE_DISABLED);
    changeObjectOwner(updateReg, FALSE);
    // disInheritDelete(updateReg);
    enInherit(updateReg);
    disInheritCopy(updateReg);
    dwRes = GetNamedSecurityInfo(updateReg, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD);
    if (dwRes != ERROR_SUCCESS) {
        printf("GetNamedSecurityInfo Error %u\n", dwRes);
        return FALSE;
    }
    if (ERROR_SUCCESS == GetExplicitEntriesFromAcl(pOldDACL, &uCount, &pEa)) {
        for (i = 0; i < uCount; i++) {
            pEa[i].grfAccessPermissions = GENERIC_READ;
        }
    }
    if (ERROR_SUCCESS != SetEntriesInAcl(uCount, pEa, NULL, &pNewDACL)) {
        printf("Failed SetEntriesInAcl\n");
        return FALSE;
    }
    dwRes = SetNamedSecurityInfo(updateReg, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL);
    if (ERROR_SUCCESS == dwRes) {
        printf("Successfully Changed DACL\n");
    }
    changeObjectOwner(updateReg, TRUE);

    if (pOldDACL)
        LocalFree(pOldDACL);
    if (pNewDACL)
        LocalFree(pNewDACL);
    if (pSD)
        LocalFree(pSD);
    if(pEa)
        LocalFree(pEa);
    return TRUE;
}

FileLocker核心講解

文件相關
核心API:
GetFileAttributes
splitPath(本身封裝路徑分割)

ACL相關
核心API:
GetNamedSecurityInfo
SetNamedSecurityInfo
SetEntriesInAcl
GetExplicitEntriesFromAcl
AllocateAndInitializeSid
DeleteAce

核心思路
鎖文件:第一步獲取上層目錄的路徑,第二步上層目錄禁用繼承,第三步上層目錄設置拒絕刪除子文件的屬性,第四步當前文件禁用繼承,第五步當前文件添加拒絕刪除的屬性,第六步更改文件全部者爲SYSTEM
恢復文件:第一步獲取上層目錄的路徑,第二步上層目錄啓用繼承並刪除以前的ACL,第三步當前文件啓用繼承並刪除以前的ACL,第四步更改文件的全部者爲SYSTEM

BOOL lockFile(LPTSTR lpMyFile) {
    DWORD dwRes, i;
    PACL pOldDACL = NULL, pNewDACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    PEXPLICIT_ACCESS pEa;
    ULONG uCount;
    CHAR lpFileName[MAX_PATH] = { 0 };
    
    /* 首先獲得上層目錄路徑 */
    splitPath(lpMyFile, lpFileName);

    /* 上層目錄擁有者改成Admin */
    changeObjectOwner(lpFileName, FALSE);

    /* 禁止上層目錄繼承 */
    disInheritCopy(lpFileName);

    /* 保存一份原始DACL */
    dwRes = GetNamedSecurityInfo(lpFileName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD);
    if (dwRes != ERROR_SUCCESS) {
        printf("GetNamedSecurityInfo Error %u\n", dwRes);
        return FALSE;
    }

    /* 設置拒絕刪除子文件夾的屬性 */
    if (ERROR_SUCCESS == GetExplicitEntriesFromAcl(pOldDACL, &uCount, &pEa)) {
        for (i = 0; i < uCount; i++) {
            /*
            public enum ACCESS_MASK    {
            READ_FILE =         0x000001,
            WRITE_FILE =        0x000002,
            CREATE_SUBDIR =     0x000004,
            READ_EXT_ATTR =     0x000008,
            WRITE_EXT_ATTR =    0x000010,
            EXECUTE =           0x000020,
            DELETE_DIR =        0x000040,
            READ_FILE_ATTR =    0x000080,
            WRITE_FILE_ATTR =   0x000100,
            DELETE =            0x010000,
            READ_SD =           0x020000,
            WRITE_DACL =        0x040000,
            WRITE_OWNER =       0x080000,
            SYNCHRONIZE =       0x100000,
            SHARE_READ =    READ_FILE | READ_EXT_ATTR | EXECUTE | READ_FILE_ATTR | READ_SD | SYNCHRONIZE,
            SHARE_CHANGE =  SHARE_READ | WRITE_FILE | CREATE_SUBDIR | WRITE_EXT_ATTR | WRITE_FILE_ATTR | DELETE,
            SHARE_FULL =    SHARE_CHANGE | DELETE_DIR | WRITE_DACL | WRITE_OWNER
            }
            */
            pEa[i].grfAccessPermissions = 0x40;
            pEa[i].grfAccessMode = DENY_ACCESS;
            pEa[i].grfInheritance = NO_INHERITANCE;
        }
    }
    if (ERROR_SUCCESS != SetEntriesInAcl(uCount, pEa, pOldDACL, &pNewDACL)) {
        printf("Failed SetEntriesInAcl\n");
        return FALSE;
    }

    /* 設置新的DACL */
    dwRes = SetNamedSecurityInfo(lpFileName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL);
    if (dwRes != ERROR_SUCCESS) {
        printf("SetNamedSecurityInfo Error %u\n", dwRes);
        return FALSE;
    }

    /* 上層目錄擁有者改回System */
    changeObjectOwner(lpFileName, TRUE);

    /* 當前文件或目錄的擁有者改成Admin */
    changeObjectOwner(lpMyFile, FALSE);

    /* 當前文件或目錄禁止繼承 */
    disInheritCopy(lpMyFile);

    /* 保留當前文件或目錄的DACL */
    dwRes = GetNamedSecurityInfo(lpMyFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD);
    if (dwRes != ERROR_SUCCESS) {
        printf("GetNamedSecurityInfo Error %u\n", dwRes);
        return FALSE;
    }

    /* 設置拒絕屬性 */
    if (ERROR_SUCCESS == GetExplicitEntriesFromAcl(pOldDACL, &uCount, &pEa)) {
        for (i = 0; i < uCount; i++) {
            pEa[i].grfAccessPermissions = DELETE;
            pEa[i].grfAccessMode = DENY_ACCESS;
            pEa[i].grfInheritance = NO_INHERITANCE;
        }
    }
    if (ERROR_SUCCESS != SetEntriesInAcl(uCount, pEa, pOldDACL, &pNewDACL)) {
        printf("Failed SetEntriesInAcl\n");
        return FALSE;
    }

    /* 設置新的DACL */
    dwRes = SetNamedSecurityInfo(lpMyFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL);
    if (dwRes != ERROR_SUCCESS) {
        printf("SetNamedSecurityInfo Error %u\n", dwRes);
        return FALSE;
    }
    changeObjectOwner(lpMyFile, TRUE);

    /*
    SECURITY_DESCRIPTOR SD;
    InitializeSecurityDescriptor(&SD, SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl(&SD, TRUE, NULL, FALSE);
    */
    if (pOldDACL)
        LocalFree(pOldDACL);
    if (pNewDACL)
        LocalFree(pNewDACL);
    if (pSD)
        LocalFree(pSD);
    if (pEa)
        LocalFree(pEa);

    return TRUE;
}

BOOL recoveryFile(LPTSTR lpMyFile) {
    CHAR lpFileName[MAX_PATH] = { 0 };

    /* 首先獲得上層目錄路徑 */
    splitPath(lpMyFile, lpFileName);

    changeObjectOwner(lpFileName, FALSE);
    enInherit(lpFileName);
    changeObjectOwner(lpFileName, TRUE);

    changeObjectOwner(lpMyFile, FALSE);
    enInherit(lpMyFile);
    changeObjectOwner(lpMyFile, TRUE);

    return TRUE;
}

END

相關文章
相關標籤/搜索