Search code examples
c++windowsaccess-rightsrights

How to protect an file without denying read or execute access to it in c++


I'm making an computer management program (that runs only as an admin, of course) that shouldn't be accessible to normal users (only by the SYSTEM user, because my uninstaller will run as this user).

I have been trying to prevent normal users from modifying and deleting my main EXE file, and it works.

The problem is that I want the user to be able to execute it and read it, but it won't let them read/execute the file.

Here is my code:

#include <windows.h>
#include <stdio.h>
#include <accctrl.h>
#include <aclapi.h>
#include <iostream>
#include <cstdio>
                                                                                            
#pragma comment(lib, "ntdll.lib")

extern "C" NTSTATUS NTAPI RtlAdjustPrivilege(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrThread, PBOOLEAN StatusPointer);

BOOL ProtectFile(LPTSTR lpszOwnFile) 
{
    BOOL bRetval = FALSE;

    HANDLE hToken = NULL; 
    PSID pSIDAdmin = NULL;
    PSID pSIDEveryone = NULL;
    PACL pACL = NULL;
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
    const int NUM_ACES = 2;
    EXPLICIT_ACCESS ea[NUM_ACES];
    DWORD dwRes;

    // Specify the DACL to use.
    // Create a SID for the Everyone group.
    if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
                     SECURITY_WORLD_RID,
                     0,
                     0, 0, 0, 0, 0, 0,
                     &pSIDEveryone)) 
    {
        printf("AllocateAndInitializeSid (Everyone) error %u\n",
                GetLastError());
    }

    // Create a SID for the BUILTIN\Administrators group.
    if (!AllocateAndInitializeSid(&SIDAuthNT, 2,
                     SECURITY_BUILTIN_DOMAIN_RID,
                     DOMAIN_ALIAS_RID_ADMINS,
                     0, 0, 0, 0, 0, 0,
                     &pSIDAdmin)) 
    {
        printf("AllocateAndInitializeSid (Admin) error %u\n",
                GetLastError());
    }

    ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));

    // Set read and execute access for Everyone.
    ea[0].grfAccessPermissions = GENERIC_WRITE| GENERIC_EXECUTE | FILE_GENERIC_READ | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_EXECUTE | READ_CONTROL | FILE_EXECUTE| FILE_READ_EA | FILE_CREATE_PIPE_INSTANCE;
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName = (LPTSTR) pSIDEveryone;

    // Set read and execute access for Administrators.
    ea[1].grfAccessPermissions = GENERIC_READ| GENERIC_EXECUTE | FILE_GENERIC_READ | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_EXECUTE | READ_CONTROL | FILE_EXECUTE| FILE_READ_EA | FILE_CREATE_PIPE_INSTANCE ;
    ea[1].grfAccessMode = SET_ACCESS;
    ea[1].grfInheritance = NO_INHERITANCE;
    ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    ea[1].Trustee.ptstrName = (LPTSTR) pSIDAdmin;

    // Deny modify and delete access for Everyone.
    ea[0].grfAccessPermissions = GENERIC_WRITE| FILE_GENERIC_WRITE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |  WRITE_OWNER | DELETE | WRITE_DAC;
    ea[0].grfAccessMode = DENY_ACCESS;
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName = (LPTSTR) pSIDEveryone;

    // Deny modify and delete access for Administrators.
    ea[1].grfAccessPermissions = GENERIC_WRITE| FILE_GENERIC_WRITE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |  WRITE_OWNER | DELETE | WRITE_DAC;
    ea[1].grfAccessMode = DENY_ACCESS;
    ea[1].grfInheritance = NO_INHERITANCE;
    ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    ea[1].Trustee.ptstrName = (LPTSTR) pSIDAdmin;

    if (ERROR_SUCCESS != SetEntriesInAcl(NUM_ACES,
                                         ea,
                                         NULL,
                                         &pACL))
    {
        printf("Failed SetEntriesInAcl\n");
    }

    // Try to modify the object's DACL.
    dwRes = SetNamedSecurityInfo(
        lpszOwnFile,                 // name of the object
        SE_FILE_OBJECT,              // type of object
        DACL_SECURITY_INFORMATION,   // change only the object's DACL
        NULL, NULL,                  // do not change owner or group
        pACL,                        // DACL specified
        NULL);                       // do not change SACL

    if (ERROR_SUCCESS == dwRes) 
    {
        printf("Successfully changed DACL\n");
        bRetval = TRUE;
        // No more processing needed.
    }

    if (dwRes != ERROR_ACCESS_DENIED)
    {
        printf("First SetNamedSecurityInfo call failed: %u\n",
                dwRes); 
    }

    // If the preceding call failed because access was denied, 
    // enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for 
    // the Administrators group, take ownership of the object, and 
    // disable the privilege. Then try again to set the object's DACL.

    // Open a handle to the access token for the calling process.
    if (!OpenProcessToken(GetCurrentProcess(), 
                          TOKEN_ADJUST_PRIVILEGES, 
                          &hToken)) 
    {
        printf("OpenProcessToken failed: %u\n", GetLastError()); 
    } 

    //get the take ownership privilege

    BOOLEAN PrivilegeState = FALSE;
    RtlAdjustPrivilege(9, TRUE, FALSE, &PrivilegeState);

    // Set the owner in the object's security descriptor.
    dwRes = SetNamedSecurityInfo(
        lpszOwnFile,                 // name of the object
        SE_FILE_OBJECT,              // type of object
        OWNER_SECURITY_INFORMATION,  // change only the object's owner
        pSIDAdmin,                   // SID of Administrator group
        NULL,
        NULL,
        NULL); 

    if (dwRes != ERROR_SUCCESS) 
    {
        printf("Could not set owner. Error: %u\n", dwRes); 
    }

    // Try again to modify the object's DACL,
    // now that we are the owner.
    dwRes = SetNamedSecurityInfo(
        lpszOwnFile,                 // name of the object
        SE_FILE_OBJECT,              // type of object
        DACL_SECURITY_INFORMATION,   // change only the object's DACL
        NULL, NULL,                  // do not change owner or group
        pACL,                        // DACL specified
        NULL);                       // do not change SACL

    if (dwRes == ERROR_SUCCESS)
    {
        printf("Successfully changed DACL\n");
        bRetval = TRUE; 
    }
    else
    {
        printf("Second SetNamedSecurityInfo call failed: %u\n",
                dwRes); 
    }

    if (pSIDAdmin)
        FreeSid(pSIDAdmin); 

    if (pSIDEveryone)
        FreeSid(pSIDEveryone); 

    if (pACL)
       LocalFree(pACL);

    if (hToken)
       CloseHandle(hToken);

    return bRetval;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    ProtectFile("C:\\Windows\\program.exe");
}

Now, it sets correctly the delete/modify denied access permissions, as you can see right here:

image

But, when I try to execute the same file, as you can see here, it doesn't work, for some reason.

image

I'm not sure why it happens, but I think it is because I forgot to put one or multiple access right(s) in the allowed section, or that some access rights needed to read/execute the file are in the denied section.

BTW, here are the pictures of both allow/deny permissions section:

denied permissions section:

image

allowed permissions section:

image

Do you have any idea of the permissions I forgot, or that I set wrong? If yes, what are they?


Solution

  • You are denying and allowing Read permissions? How's that?

    If you are denying Read Permissions, how can it be run?

    Stop denying Read Permissions.

    Here is some info that could help you: How Permissions Work