(펌: Enabling and Disabling Privileges)

2016. 3. 6. 22:47IT-개발/winapi 및 MFC

반응형

Enabling and Disabling Privileges

 

The last program example in the previous Windows User & Groups, we failed to add the SACL to the ACL because we don’t have privilege to do that task.  We already demonstrated how to enable a privilege in our earlier program example.  Again, in the following program example we will try to enable the required privilege to accomplish our task.  Enabling a privilege in an access token allows the process to perform system-level actions that it could not previously.  Your application should thoroughly verify that the privilege is appropriate to the type of account, especially for the following powerful privileges:

 

Privilege constant/string

Display name

SE_ASSIGNPRIMARYTOKEN_NAME

SeAssignPrimaryTokenPrivilege

Replace a process level token

SE_BACKUP_NAME

SeBackupPrivilege

Backup files and directories

SE_DEBUG_NAME

SeDebugPrivilege

Debug programs

SE_INCREASE_QUOTA_NAME

SeIncreaseQuotaPrivilege

Adjust memory quotas for a process

SE_TCB_NAME

SeTchPrivilege

Act as part of the operating system

 

Table 1

 

Before enabling any of these potentially dangerous privileges, determine that functions or operations in your code actually require the privileges.  For example, very few functions in the operating system actually require the SeTchPrivilege.  The following example shows how to enable or disable a privilege in an access token.  The example calls the LookupPrivilegeValue() function to get the LUID that the local system uses to identify the privilege.  Then the example calls the AdjustTokenPrivileges() function, which either enables or disables the privilege that depends on the value of the bEnablePrivilege parameter.  The following is a code portion used to enable/disable privilege.

 

BOOL SetPrivilege(

    HANDLE hToken,              // access token handle

    LPCTSTR lpszPrivilege,   // name of privilege to enable/disable

    BOOL bEnablePrivilege   // to enable or disable privilege

    )

{

TOKEN_PRIVILEGES tp;

// Used by local system to identify the privilege

LUID luid;

 

if(!LookupPrivilegeValue(

        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;

}

 

return TRUE;

}

The following is a working program example that enables/disables privilege.

 

#include <windows.h>

#include <stdio.h>

 

BOOL SetPrivilege(

    HANDLE hToken,               // access token handle

    LPCTSTR lpszPrivilege,    // name of privilege to enable/disable

    BOOL bEnablePrivilege    // to enable (or disable privilege)

    )

{

// Token privilege structure

TOKEN_PRIVILEGES tp;

// Used by local system to identify the privilege

LUID luid;

 

if(!LookupPrivilegeValue(

        NULL,                // lookup privilege on local system

        lpszPrivilege,    // privilege to lookup

        &luid))               // receives LUID of privilege

{

    printf("LookupPrivilegeValue() error: %u\n", GetLastError());

    return FALSE;

}

else

  printf("LookupPrivilegeValue() is OK\n");

 

tp.PrivilegeCount = 1;

tp.Privileges[0].Luid = luid;

 

// Don't forget to disable the privileges after you enabled them,

// or have already completed your task. Don't mess up your system :o)

if(bEnablePrivilege)

{

       tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

       printf("tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED\n");

}

else

{

       tp.Privileges[0].Attributes = 0;

       printf("tp.Privileges[0].Attributes = 0\n");

}

 

// Enable the privilege (or disable all privileges).

if(!AdjustTokenPrivileges(

       hToken,

       FALSE, // If TRUE, function disables all privileges, if FALSE the function modifies privilege based on the tp

       &tp,

       sizeof(TOKEN_PRIVILEGES),

       (PTOKEN_PRIVILEGES) NULL,

       (PDWORD) NULL))

{

      printf("AdjustTokenPrivileges() error: %u\n", GetLastError());

      return FALSE;

}

else

{

   printf("AdjustTokenPrivileges() is OK, last error if any: %u\n", GetLastError());

   printf("Should be 0, means the operation completed successfully = ERROR_SUCCESS\n");

}

return TRUE;

}

 

int main()

{

LPCTSTR lpszPrivilege = "SeSecurityPrivilege";

// Change this BOOL value to set/unset the SE_PRIVILEGE_ENABLED attribute

BOOL bEnablePrivilege = TRUE;

HANDLE hToken;

 

// Open a handle to the access token for the calling process. That is this running program

if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))

{

    printf("OpenProcessToken() error %u\n", GetLastError());

    return FALSE;

}

else

printf("OpenProcessToken() is OK\n");

 

// Call the user defined SetPrivilege() function to enable and set the needed privilege

BOOL test = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);

printf("The SetPrivilege() return value: %d\n\n", test);

 

//************************************************

// TODO: Complete your task here

//***********************************************

 

// After we have completed our task, don't forget to disable the privilege

bEnablePrivilege = FALSE;

BOOL test1 = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);

printf("The SetPrivilage() return value: %d\n", test1);

 

return 0;

}

 

A sample output:

OpenProcessToken() is OK

LookupPrivilegeValue() is OK

tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED

AdjustTokenPrivileges() is OK, last error if any: 0

Should be 0, means the operation completed successfully = ERROR_SUCCESS

The SetPrivilage() return value: 1

 

LookupPrivilegeValue() is OK

tp.Privileges[0].Attributes = 0

AdjustTokenPrivileges() is OK, last error if any: 0

Should be 0, means the operation completed successfully = ERROR_SUCCESS

The SetPrivilage() return value: 1

Press any key to continue

In our previous program example, we failed to set the SACL for success auditing on the directory because we don’t have the privilege.  Let enable the privilege and then set the SACL using the same program example.  First of all let verify through the Testdir3 directory property page.

 

Auditing setting with no entries

 

Figure 1

 

Then execute our modified program.

 

// Modifying ACL of an object.  Here we are going to

// add Allow standard right access and set an ACE for SACL.

// This Win XP machine is logged in by user named Mike

// who is a member of Administrators group...

// To access a SACL using the GetNamedSecurityInfo()

// or SetNamedSecurityInfo() functions, you have to enable

// the SE_SECURITY_NAME privilege.

 

#include <windows.h>

#include <accctrl.h>

#include <aclapi.h>

#include <stdio.h>

 

//********* Enabling (Disabling) the privilege *********

BOOL SetPrivilege(

    HANDLE hToken,               // access token handle

    LPCTSTR lpszPrivilege,   // name of privilege to enable/disable

    BOOL bEnablePrivilege   // to enable (or disable privilege)

    )

{

TOKEN_PRIVILEGES tp;

// Used by local system to identify the privilege

LUID luid;

 

if(!LookupPrivilegeValue(

        NULL,                // lookup privilege on local system

        lpszPrivilege,   // privilege to lookup

        &luid))              // receives LUID of privilege

{

    printf("LookupPrivilegeValue() error: %u\n", GetLastError());

    return FALSE;

}

else

   printf("LookupPrivilegeValue() is OK\n");

tp.PrivilegeCount = 1;

tp.Privileges[0].Luid = luid;

// Don't forget to disable the privilege after you enable them, don't mess up your system :-)

if(bEnablePrivilege)

{

       tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

       printf("tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED\n");

}

else

{

       tp.Privileges[0].Attributes = 0;

       printf("tp.Privileges[0].Attributes = 0\n");

}

// Enable the privilege (or disable all privileges).

if(!AdjustTokenPrivileges(

       hToken,

       FALSE, // If TRUE, function disables all privileges, if FALSE the function modifies privileges based on the tp

       &tp,

       sizeof(TOKEN_PRIVILEGES),

       (PTOKEN_PRIVILEGES) NULL,

       (PDWORD) NULL))

{

      printf("AdjustTokenPrivileges() error: %u\n", GetLastError());

      return FALSE;

}

else

{

   printf("AdjustTokenPrivileges() is OK, last error if any: %u\n", GetLastError());

   printf("Should be 0, means the operation completed successfully = ERROR_SUCCESS\n");

}

return TRUE;

}

 

//************** Clean up routine ***************

void Cleanup(PSECURITY_DESCRIPTOR pSS, PACL pNewSACL)

{

if(pSS != NULL)

    LocalFree((HLOCAL) pSS);

else

    printf("pSS cleaning is OK\n");

 

if(pNewSACL != NULL)

    LocalFree((HLOCAL) pNewSACL);

else

    printf("pNewSACL cleaning is OK\n");

}

 

//******** The main() **********

int main()

{

// name of object, here we will add an ACE for a directory

LPTSTR pszObjName = "C:\\Testdir2\\Testdir3";

// type of object, file or directory, a directory

SE_OBJECT_TYPE ObjectType = SE_FILE_OBJECT;

// access mask for new ACE equal to 0X11000000 - GENERIC_ALL and ACCESS_SYSTEM_SECURITY

DWORD dwAccessRights = 0X11000000;

// type of ACE, set audit for success

ACCESS_MODE AccessMode = SET_AUDIT_SUCCESS;

// inheritance flags for new ACE. The OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE flags are not propagated to an inherited ACE.

DWORD dwInheritance = NO_PROPAGATE_INHERIT_ACE;

// format of trustee structure, the trustee is name

TRUSTEE_FORM TrusteeForm = TRUSTEE_IS_NAME;

// the new trustee for the ACE is set to testuser, a normal user

LPTSTR pszTrustee = "testuser";

// Result

DWORD dwRes = 0;

// Existing and new SACL pointers...

PACL pOldSACL = NULL, pNewSACL = NULL;

// Security descriptor

PSECURITY_DESCRIPTOR pSS = NULL;

// EXPLICIT_ACCESS structure

EXPLICIT_ACCESS ea;

// Verify the object name validity

if(pszObjName == NULL)

    return ERROR_INVALID_PARAMETER;

else

    printf("The object name is OK\n");

 

LPCTSTR lpszPrivilege = "SeSecurityPrivilege";

// Change this BOOL value to set/unset the SE_PRIVILEGE_ENABLED attribute

BOOL bEnablePrivilege = TRUE;

// Handle to the running process that is this (running) program

HANDLE hToken;

//*************** Get the handle to the process ********************

// Open a handle to the access token for the calling process. That is this running program...

if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))

{

    printf("OpenProcessToken() error %u\n", GetLastError());

    return FALSE;

}

else

    printf("OpenProcessToken() is OK\n");

 

//********************* Enabling privilege ***************************

// Call the user defined SetPrivilege() function to enable privilege

BOOL test = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);

// Verify

printf("The SetPrivilege() return value: %d\n\n", test);

//********************* End enabling privilege ************************

 

// By assuming that we have enabled the required privilege, accomplish our task. Here, get a pointer to the existing SACL.

dwRes = GetNamedSecurityInfo(pszObjName, ObjectType,

      SACL_SECURITY_INFORMATION,

      NULL, NULL, NULL, &pOldSACL, &pSS);

 

// Verify

if(dwRes != ERROR_SUCCESS)

{

    printf("GetNamedSecurityInfo() Error %u\n", dwRes);

    Cleanup(pSS, pNewSACL);

}

else

    printf("GetNamedSecurityInfo() is OK\n");

// Initialize an EXPLICIT_ACCESS structure for the new ACE. For more ACE entries, declare an array of the EXPLICIT_ACCESS structure

ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));

ea.grfAccessPermissions = dwAccessRights;

ea.grfAccessMode = AccessMode;

ea.grfInheritance= dwInheritance;

ea.Trustee.TrusteeForm = TrusteeForm;

// Other structure elements that might be needed...

// ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;

// ea.Trustee.TrusteeType = TRUSTEE_IS_USER;

// The trustee is testuser

ea.Trustee.ptstrName = pszTrustee;

// Create a new ACL that merges the new ACE into the existing ACL.

dwRes = SetEntriesInAcl(1, &ea, pOldSACL, &pNewSACL);

if(dwRes != ERROR_SUCCESS)

{

    printf("SetEntriesInAcl() error %u\n", dwRes);

    Cleanup(pSS, pNewSACL);

}

else

    printf("SetEntriesInAcl() is OK\n");

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

dwRes = SetNamedSecurityInfo(pszObjName, ObjectType, SACL_SECURITY_INFORMATION, NULL, NULL, NULL, pNewSACL);

if(dwRes != ERROR_SUCCESS)

{

    printf("SetNamedSecurityInfo() error %u\n", dwRes);

    Cleanup(pSS, pNewSACL);

 }

else

    printf("SetNamedSecurityInfo() is OK\n\n");

 

// Disable the privilege

//****************** Disabling privilege *******************

bEnablePrivilege = FALSE;

BOOL test1 = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);

printf("The SetPrivilege() return value: %d\n", test1);

//****************** End disabling privilege ***************

// Close the process handle by calling the CloseHandle(hToken)

return 0;

}

 

A sample output:

The object name is OK

OpenProcessToken() is OK

LookupPrivilegeValue() is OK

tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED

AdjustTokenPrivileges() is OK, last error if any: 0

Should be 0, means the operation completed successfully = ERROR_SUCCESS

The SetPrivilege() return value: 1

 

GetNamedSecurityInfo() is OK

SetEntriesInAcl() is OK

SetNamedSecurityInfo() is OK

 

LookupPrivilegeValue() is OK

tp.Privileges[0].Attributes = 0

AdjustTokenPrivileges() is OK, last error if any: 0

Should be 0, means the operation completed successfully = ERROR_SUCCESS

The SetPrivilege() return value: 1

Press any key to continue

Well, it seems that we have enabled the privilege successfully and set the SACL.  Let verify through the Testdir3 directory property, Advanced Security Settingsproperty page.

 

Well we successfully add SACL

 

Figure 2

 

Searching for a SID in an Access Token

 

The following example uses the OpenProcessToken() and GetTokenInformation() functions to get the group memberships in an access token.  Then it uses theAllocateAndInitializeSid() function to create a SID that identifies the well-known SID of the administrator group for the local computer.  Next, it uses the EqualSid()function to compare the well-known SID with the group SIDs from the access token.  If the SID is present in the token, the function checks the attributes of the SID to determine whether it is enabled.

The CheckTokenMembership() function used to determine whether a specified SID is present and enabled in an access token.  This function eliminates potential misinterpretations of the active group membership if changes to access tokens are made in future releases.

 

// Searching for a SID in an Access Token.

// This program run on the standalone Windows Xp Pro not a domain based machine...

#include <windows.h>

#include <stdio.h>

#define MAX_NAME 256

 

BOOL SearchTokenGroupsForSID(void)

{

DWORD i, dwSize = 0, dwResult = 0;

HANDLE hToken;

PTOKEN_GROUPS pGroupInfo;

SID_NAME_USE SidType;

char lpName[MAX_NAME];

char lpDomain[MAX_NAME];

BYTE sidBuffer[100];

PSID pSID = (PSID)&sidBuffer;

 

// Open a handle to the access token for the calling process, that is, this running program (process).  So we get the handle

// to the token for the current user that run this program and/or login to this machine.

//  Depend on your task, change the TOKEN_QUERY to others accordingly...

if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))

{

    printf("OpenProcessToken() error %u\n", GetLastError());

    return FALSE;

}

else

    printf("OpenProcessToken() for the current process is OK\n");

 

// By assuming that we got the handle to the token...

// Call GetTokenInformation() to get the buffer size for storage. This is for Tokengroups, change accordingly for others such

// as TokenUser, TokenOwner, TokenType etc

if(!GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize))

{

    dwResult = GetLastError();

    if(dwResult != ERROR_INSUFFICIENT_BUFFER)

       {

        printf("GetTokenInformation() error %u\n", dwResult);

        return FALSE;

    }

       else

         printf("GetTokenInformation() for the buffer size is OK\n");

}

else

    printf("GetTokenInformation() for storage of the Token group is OK\n");

// By assuming that we got the storage, then allocate the buffer.

pGroupInfo = (PTOKEN_GROUPS) GlobalAlloc(GPTR, dwSize);

// Call GetTokenInformation() again to get the group information.

if(!GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSize, &dwSize))

{

    printf("GetTokenInformation() error %u\n", GetLastError());

    return FALSE;

}

else

    printf("GetTokenInformation() for getting the TokenGroups is OK\n");

//****************** Playing with SIDs *****************************

// Create a SID for the BUILTIN\Administrators group...

// You can try other groups also lol as commented out on the following

// codes. Uncomment/comment out the SIDs for testing....

// This is 32 bit RID value. Applications that require longer RID values,

// use CreateWellKnownSid() instead

//*********************** Administrator group ***********************

SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;

if(!AllocateAndInitializeSid(&SIDAuth, 2,

                 SECURITY_BUILTIN_DOMAIN_RID,

                 DOMAIN_ALIAS_RID_ADMINS,

                 0, 0, 0, 0, 0, 0,

                 &pSID))

{

    printf("AllocateAndInitializeSid() error %u\n", GetLastError());

    return FALSE;

}

else

    printf("AllocateAndInitializeSid(), SID for BUILTIN\\Administrators group is\n successfully created\n");

 

//************************ Local group ********************

// An example for creating a SID for the Local group...

// SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_LOCAL_SID_AUTHORITY;

//

// if(!AllocateAndInitializeSid(&SIDAuth, 1,

//                 SECURITY_LOCAL_RID,

//                 0, 0, 0, 0, 0, 0, 0,

//                 &pSID))

// {

//    printf("AllocateAndInitializeSid() error %u\n", GetLastError());

//    return FALSE;

// }

// else

// printf("AllocateAndInitializeSid(), SID for Local group is\n successfully created\n");

//********************* Authenticated users ***********************

// Another example for creating a SID for the Authenticated users...

// SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;

// if(!AllocateAndInitializeSid(&SIDAuth, 1,

//                 SECURITY_AUTHENTICATED_USER_RID,

//                 0, 0, 0, 0, 0, 0, 0,

//                 &pSID))

// {

// printf("AllocateAndInitializeSid() error %u\n", GetLastError());

// return FALSE;

// }

// else

// printf("AllocateAndInitializeSid(), SID for Local group is\n successfully created\n");

//******************************************************************

// Loop through the group SIDs looking for the created group SID.

for(i=0; i<pGroupInfo->GroupCount; i++)

{

   // Compare the created SID with the available group SIDs

   if(EqualSid(pSID, pGroupInfo->Groups[i].Sid))

   {

   // Lookup the account name and print it.

    dwSize = MAX_NAME;

   if(!LookupAccountSid(NULL, pGroupInfo->Groups[i].Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType))

   {

    // If not found or something wrong...

    dwResult = GetLastError();

      if(dwResult == ERROR_NONE_MAPPED)

           strcpy(lpName, "NONE_MAPPED");

      else

       {

          printf("LookupAccountSid() error %u\n", GetLastError());

          return FALSE;

        }

    }

   // If found...

  else

  {

//******************* Built-in\Administrators group *********************

     printf("LookupAccountSid() for BUILTIN\\Administrators group is OK\n");

     printf("Current user is a member of the %s\\%s group\n", lpDomain, lpName);

//******************* Local group ***************************************

// printf("LookupAccountSid() for Local group is OK\n");

// printf("Current user is a member of the %s group\n", lpName);

//******************** Authenticated users *******************************

// printf("LookupAccountSid() for Authenticated users is OK\n");

// printf("Current user is a member of the %s\\%s group\n", lpDomain, lpName);

  }

//**************** End playing with SIDs *********************************

// Find out whether the SID is enabled in the token.

if(pGroupInfo->Groups[i].Attributes & SE_GROUP_ENABLED)

   printf("The group SID is enabled.\n");

else if (pGroupInfo->Groups[i].Attributes & SE_GROUP_USE_FOR_DENY_ONLY)

   printf("The group SID is a deny-only SID.\n");

else

   printf("The group SID is not enabled.\n");

}

}

// Release resources back to system

if(pSID)

    FreeSid(pSID);

if(pGroupInfo)

    GlobalFree(pGroupInfo);

return TRUE;

}

 

//******** main() ********

int main()

{

  // Call the user defined SearchTokenGroupsForSID() function to search the token group SID

  BOOL test = SearchTokenGroupsForSID();

  // Verify

  printf("The return value of SearchTokenGroupsForSID() is: %d\n", test);

return 0;

}

 

A sample output:

OpenProcessToken() for the current process is OK

GetTokenInformation() for the buffer size is OK

GetTokenInformation() for getting the TokenGroups is OK

AllocateAndInitializeSid(), SID for BUILTIN\Administrators group is

 successfully created

LookupAccountSid() for BUILTIN\Administrators group is OK

Current user is a member of the BUILTIN\Administrators group

The group SID is enabled.

The return value of SearchTokenGroupsForSID() is: 1

Press any key to continue

<<<----------------------------------------------------- smaller version------------------------------------------------------->>>

 

#include <windows.h>

#include <stdio.h>

 

BOOL IsUserAdminGrp(void)

/*

This routine returns TRUE if the caller's process is a member of the Administrators local group. Caller is NOT expected

to be impersonating anyone and is expected to be able to open its own process and process token.

Arguments: None.

Return Value:

   TRUE - Caller has Administrators local group.

   FALSE - Caller does not have Administrators local group.

*/

{

BOOL check;

SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

PSID AdministratorsGroup;

check = AllocateAndInitializeSid(

    &NtAuthority,

    2,

    SECURITY_BUILTIN_DOMAIN_RID,

    DOMAIN_ALIAS_RID_ADMINS,

    0, 0, 0, 0, 0, 0,

    &AdministratorsGroup);

 

if(check)

{

    printf("AllocateAndInitializeSid() is OK\n");

       if(!CheckTokenMembership(

          NULL, // uses the impersonation token of the calling thread. If the thread is not impersonating,

                      // the function duplicates the thread's primary token to create an impersonation token.

           AdministratorsGroup,  // Pointer to a SID structure

          &check       // Result of the SID

              ))

        {

           // If the SID (the 2nd parameter) is present and has the SE_GROUP_ENABLED attribute,

           // IsMember (3rd parameter) returns TRUE; otherwise, it returns FALSE.

           printf("The received value of the third parameter: %u\n", check);

           check = FALSE;

           printf("CheckTokenMembership() is NOT OK\n");

       }

       else

           printf("CheckTokenMembership() is OK\n");

       printf("You are Administrators Local Group lol!\n");

       printf("The received value of the third parameter: %u, last error if any: %u\n", check, GetLastError());

       FreeSid(AdministratorsGroup);

}

else

   printf("AllocateAndInitializeSid() is NOT OK\n");

return(check);

}

 

int main()

{

       BOOL test = IsUserAdminGrp();

       printf("The return value of the IsUserAdminGrp(): %u, last error if any: %u\n", test, GetLastError());

       return 0;

}

 

A sample output:

AllocateAndInitializeSid() is OK

CheckTokenMembership() is OK

You are Administrators Local Group lol!

The received value of the third parameter: 1, last error if any: 0

The return value of the IsUserAdminGrp(): 1, last error if any: 0

Press any key to continue