News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Old test piece to determine administrative access.

Started by hutch--, December 07, 2009, 10:30:59 AM

Previous topic - Next topic

hutch--

I just fished this file of the French site that still carries some of Iczelion's downloads, an app called "IsAdmin" which I have done a quick knife and fork job on to tidy it up, get rid of the globals and reformat it.

It works fine on my XP Sp3 but I don't know if it wilol work properly with later OS versions like Vista and Win7.

I don't claim to know my way around this stuff all that well so I wondered if anyone had some experience in determining admin access on later OS versions and if there are any particular pitfalls in using a technique like this one.

This is the app code.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
;                                   original author Sami Paju
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

IF 0    ; -----------------------------------------------------------------

    IsAdmin
    Returns TRUE if calling process (you) have Admin privileges and
    FALSE if you don't or in case of error.

    Copy IsAdmin proc and variables (except those starting with Msg) to
    your own program.

ENDIF   ; -----------------------------------------------------------------

    include    \masm32\include\masm32rt.inc
   
    include    \masm32\include\advapi32.inc
    includelib \masm32\lib\advapi32.lib

    IsAdmin                PROTO

  .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

  Start:

    invoke IsAdmin
    .if eax == TRUE
      fn MessageBox, NULL,"You have Admin privileges!","IsAdmin", MB_OK
    .else
      fn MessageBox, NULL,"You don't have Admin privileges!","IsAdmin", MB_OK
    .endif

    invoke ExitProcess, 0

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    siaNtAuthority      SID_IDENTIFIER_AUTHORITY <SECURITY_NT_AUTHORITY>

IsAdmin proc

    LOCAL hCurrentThread     :DWORD
    LOCAL hAccessToken       :DWORD
    LOCAL hCurrentProcess    :DWORD
    LOCAL dwInfoBufferSize   :DWORD
    LOCAL bSuccess           :DWORD
    LOCAL pInfoBuffer        :DWORD
    LOCAL psidAdministrators :DWORD

    mov hCurrentThread, rv(GetCurrentThread)
    invoke OpenThreadToken, hCurrentThread, TOKEN_QUERY, TRUE, ADDR hAccessToken

    .if eax == 0
      invoke GetLastError
      .if eax != ERROR_NO_TOKEN
        mov eax, FALSE
        ret
      .endif
      mov hCurrentProcess, rv(GetCurrentProcess)
      invoke OpenProcessToken,hCurrentProcess, TOKEN_QUERY, ADDR hAccessToken
      .if eax == 0
        mov eax, FALSE
        ret
      .endif
    .endif

    invoke GetTokenInformation, hAccessToken, TokenGroups, NULL, NULL, ADDR dwInfoBufferSize

    .if dwInfoBufferSize > 0
        mov pInfoBuffer, rv(GlobalAlloc, GMEM_FIXED, dwInfoBufferSize)
        invoke GetTokenInformation, hAccessToken, TokenGroups,
               pInfoBuffer, dwInfoBufferSize, ADDR dwInfoBufferSize
    .endif

    mov bSuccess, eax
    invoke CloseHandle, hAccessToken

    .if bSuccess == 0
      mov eax, FALSE
      ret
    .endif

    invoke AllocateAndInitializeSid, ADDR siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
           DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, ADDR psidAdministrators

    .if eax == 0
      mov eax, FALSE
      ret
    .endif
   
    mov bSuccess, FALSE
   
    mov ebx, pInfoBuffer
    mov ecx, TOKEN_GROUPS.GroupCount[ebx]
    xor esi, esi

    .while esi < ecx
      push esi
      push ecx
      mov  ecx, TOKEN_GROUPS.Groups.Sid[ebx]
      mov  eax, sizeof TOKEN_GROUPS.Groups
      xor  edx, edx
      mul  esi                                    ;eax * esi -> eax
      add  ecx, eax
      invoke EqualSid, psidAdministrators, ecx
      pop ecx
      pop esi
      .if eax != 0
        mov bSuccess, TRUE
        .break
      .endif
      inc esi
    .endw

    invoke FreeSid, psidAdministrators
    invoke GlobalFree, pInfoBuffer

    mov eax, bSuccess
    ret

IsAdmin endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end Start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Ghandi

I cant see why it would have changed at all mate. Sure, Vista and 7 introduced a lot of change, but this code creates a system identifier (SID) for the Admin group and checks all user identifiers (tokens) that the process has against the SID. If there is a match, the process is being run by an account with admin privileges. (Apparently.)

The following is an example taken from MSDN, it is almost a verbatim of the code you supplied Hutch, except its in C.

http://msdn.microsoft.com/en-us/library/ms995339.aspx



/*------------------------------------------------------------------
| Name: RunningAsAdministrator
| Desc: checks if user has administrator privileges
| Notes: This function returns TRUE if the user identifier associated with
|   this process is a member of the the Administrators group.
------------------------------------------------------------------*/
BOOL RunningAsAdministrator ( VOID)
{
BOOL   fAdmin;
HANDLE  hThread;
TOKEN_GROUPS *ptg = NULL;
DWORD  cbTokenGroups;
DWORD  dwGroup;
PSID   psidAdmin;

SID_IDENTIFIER_AUTHORITY SystemSidAuthority= SECURITY_NT_AUTHORITY;

// First we must open a handle to the access token for this thread.

if ( !OpenThreadToken ( GetCurrentThread(), TOKEN_QUERY, FALSE, &hThread))
{
  if ( GetLastError() == ERROR_NO_TOKEN)
  {
   // If the thread does not have an access token, we'll examine the
   // access token associated with the process.

   if (! OpenProcessToken ( GetCurrentProcess(), TOKEN_QUERY,
                 &hThread))
   return ( FALSE);
  }
  else
   return ( FALSE);
}

// Then we must query the size of the group information associated with
// the token. Note that we expect a FALSE result from GetTokenInformation
// because we've given it a NULL buffer. On exit cbTokenGroups will tell
// the size of the group information.

if ( GetTokenInformation ( hThread, TokenGroups, NULL, 0, &cbTokenGroups))
  return ( FALSE);

// Here we verify that GetTokenInformation failed for lack of a large
// enough buffer.

if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  return ( FALSE);

// Now we allocate a buffer for the group information.
// Since _alloca allocates on the stack, we don't have
// to explicitly deallocate it. That happens automatically
// when we exit this function.

if ( ! ( ptg= _alloca ( cbTokenGroups)))
  return ( FALSE);

// Now we ask for the group information again.
// This may fail if an administrator has added this account
// to an additional group between our first call to
// GetTokenInformation and this one.

if ( !GetTokenInformation ( hThread, TokenGroups, ptg, cbTokenGroups,
          &cbTokenGroups) )
  return ( FALSE);

// Now we must create a System Identifier for the Admin group.

if ( ! AllocateAndInitializeSid ( &SystemSidAuthority, 2,
            SECURITY_BUILTIN_DOMAIN_RID,
            DOMAIN_ALIAS_RID_ADMINS,
            0, 0, 0, 0, 0, 0, &psidAdmin) )
  return ( FALSE);

// Finally we'll iterate through the list of groups for this access
// token looking for a match against the SID we created above.

fAdmin= FALSE;

for ( dwGroup= 0; dwGroup < ptg->GroupCount; dwGroup++)
{
  if ( EqualSid ( ptg->Groups[dwGroup].Sid, psidAdmin))
  {
   fAdmin = TRUE;

   break;
  }
}

// Before we exit we must explicity deallocate the SID we created.

FreeSid ( psidAdmin);

return ( fAdmin);
}
/* eof - RunningAsAdministrator */

hutch--

gratsie,  :U

I just don't do enough in this area to be up to date with it.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

oex

As a general rule of thumb what do administrator rights apply to?
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

Vortex

.386
.model flat,stdcall
option casemap:none

include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\user32.inc
include     \masm32\include\shell32.inc

includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib
includelib  \masm32\lib\shell32.lib

.data

text1       db 'The user is not a member of the Administrators group',0
text2       db 'The user is a member of the Administrators group',0
capt        db 'IsUserAnAdmin',0

array       dd text1,text2

.code

start:

    invoke  IsUserAnAdmin

    mov     edx,OFFSET array
    lea     edx,[edx+4*eax]

    invoke  MessageBox,0,DWORD PTR [edx],ADDR capt,MB_OK
   
    invoke  ExitProcess,0

END start


The function IsUserAnAdmin is available through Windows Vista. It might be altered or unavailable in subsequent versions of Microsoft Windows :

http://msdn.microsoft.com/en-us/library/bb776463%28VS.85%29.aspx

MichaelW

Running under Windows 2000, even though my SHELL32.DLL version is 5.0.3900.7155, IsUserAnAdmin is not exported by name. Apparently it is exported by ordinal, and this test code works without problems and it returns the expected values:

;==========================================================================
    include \masm32\include\masm32rt.inc
;==========================================================================
    .data
        hLib            dd 0
        pIsUserAnAdmin  dd 0
    .code
;==========================================================================
start:
;==========================================================================
    invoke LoadLibrary, chr$("shell32.dll")
    mov hLib, eax
    print hex$(eax),13,10

    invoke GetProcAddress, hLib, 680
    mov pIsUserAnAdmin, eax
    print hex$(eax),13,10

    call pIsUserAnAdmin
    print str$(eax),13,10

    invoke FreeLibrary, hLib

    inkey "Press any key to exit..."
    exit
;==========================================================================
end start

eschew obfuscation

Vortex

Hi MichaelW,

Thanks for the test. MSDN says that the minimum operating system is Windows 2000 to use the function. I am using Windows XP SP3.

hutch--

Thanks Michael,

That is particularly useful. I have used the info to write a small test piece after putting the technique into a proc of its own. What I need to find out is if this technique also works on Vista and Win7.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    IsAdmin PROTO

    .code

    start:

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    invoke IsAdmin
    switch SDWORD PTR eax
      case -1
        print "Function not available"
      case 0
        print "Sorry, you do not have Administrative rights",13,10
      case 1
        print "You are the Administrator",13,10
    endsw

    inkey "Press any key to exit..."
    exit

IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    IsAdmin procedure
    Return values
        -1 function not available
        0  profile does not have administrative rights
        1  profile has administrative rights

ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

IsAdmin proc

    LOCAL hLib          :DWORD
    LOCAL IsUserAnAdmin :DWORD
    LOCAL returnval     :DWORD

    mov hLib, rv(LoadLibrary,"shell32.dll")
    mov IsUserAnAdmin, rv(GetProcAddress,hLib,680)  ; 680 is ordinal for "IsUserAnAdmin"
    test eax, eax
    jz freelib                      ; if function not available

    call IsUserAnAdmin              ; call the function
    mov returnval, eax
    fn FreeLibrary,hLib
    mov eax, returnval              ; return the result in EAX
    ret

  freelib:
    fn FreeLibrary,hLib
    or eax, -1                      ; exit with -1, function not available
    ret

IsAdmin endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

sinsi

Had to change a few lines because ml choked
LOCAL pIsUserAnAdmin :DWORD
Run normally in win7 I wasn't admin, run 'as administrator' I was (surprise surprise)
Light travels faster than sound, that's why some people seem bright until you hear them.

MichaelW

According to this, IsUserAnAdmin was ordinal 680 starting with NT 4.0, and since the page refers to "Windows Vista and higher" in multiple places, I assume it's still the same through Windows 7.

Until I found this I had never considered that Geoff Chappell might have a web site. He was the author of one of my now well-used DOS references, DOS Internals.

Under Consultation, take a look at his Fee Schedule :U
eschew obfuscation

GregL

#10
Hutch,

The code you posted in your first post (IsAdmin) is telling me I don't have Admin privileges when I right-click and "Run as Administrator".  I'm running Windows 7 Professional x64.  I haven't been able to work out why it doesn't work.

Vortex's code and the second piece of code you posted, that call IsUserAnAdmin, do work correctly for me.


Here is some code that I had saved that also works correctly in Windows 7.


.586
.MODEL FLAT,STDCALL
OPTION CASEMAP:NONE

INCLUDE windows.inc

INCLUDE kernel32.inc
INCLUDE advapi32.inc
INCLUDE msvcrt.inc

INCLUDELIB kernel32.lib
INCLUDELIB advapi32.lib
INCLUDELIB msvcrt.lib

IsUserAdmin PROTO

.DATA

    szMsg    BYTE   "IsUserAdmin() = ",0
    szTrue   BYTE   "True",13,10,0
    szFalse  BYTE   "False",13,10,0
    szPrompt BYTE   13,10,"Press any key to exit ... ", 0
    szCrLf   BYTE   13,10,0

.CODE

  start:

    INVOKE crt_printf, ADDR szMsg
    INVOKE IsUserAdmin
    .IF eax == FALSE
        INVOKE crt_printf, ADDR szFalse
    .ELSE
        INVOKE crt_printf, ADDR szTrue
    .ENDIF

    INVOKE crt_printf, ADDR szPrompt
    INVOKE crt__getch
    .IF eax == 0 || eax == 0E0h
        INVOKE crt__getch
    .ENDIF
    INVOKE crt_printf, ADDR szCrLf

    INVOKE ExitProcess, 0

;---------------------------------------
PSID TYPEDEF PTR SID
SECURITY_NT_AUTHORITY EQU 5

IsUserAdmin PROC

    ;// Routine Description: 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 is a member of the Administrators local group.
    ;//   FALSE - Caller is not a member of the Administrators local group.

    LOCAL rv:DWORD

    LOCAL NtAuthority:SID_IDENTIFIER_AUTHORITY
    LOCAL pAdministratorsGroup:PSID

    mov rv, FALSE

    INVOKE RtlZeroMemory, ADDR NtAuthority, SIZEOF NtAuthority
    lea eax, NtAuthority
    mov BYTE PTR [eax+5], SECURITY_NT_AUTHORITY

    INVOKE AllocateAndInitializeSid, \
           ADDR NtAuthority, \
           2, \
           SECURITY_BUILTIN_DOMAIN_RID, \
           DOMAIN_ALIAS_RID_ADMINS, \
           0, 0, 0, 0, 0, 0, \
           ADDR pAdministratorsGroup

    .IF eax != 0
        INVOKE CheckTokenMembership, NULL, pAdministratorsGroup, ADDR rv
        .IF eax == 0
             mov rv, FALSE
        .ENDIF
        INVOKE FreeSid, pAdministratorsGroup
    .ENDIF

    mov eax, rv
    ret
IsUserAdmin ENDP
;---------------------------------------
END start





UtillMasm

invoke GetProcAddress,hLib,680
:U
code line 78
.if eax <> 0masm v6.14.8444IsAdmin.asm(78) : error A2154: syntax error in control-flow directive

ecube


hutch--

Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Vortex

Hi Greg,

Thanks for the code. It works fine on my Win XP SP3.