Как узнать, что программа запущена под Администратором

Иногда требуется узнать, запущена ли ваша программа под учетной записью с правами Администратора, или же от обычного пользователя. Для чего это нужно? Например, некоторые операции с реестром или файлами требуют права Администратора. При попытке выполнить их обычному пользователю вернется ошибка ERROR_ACCESS_DENIED, но для более точного анализа ситуации надо будет проверить права доступа и уведомить об этом пользователя. Проверить, что программа запущена под Администратором, можно несколькими способами.

Первый способ наиболее универсальный и работает даже на старых операционных системах. Он заключается в том, что надо получить группы доступа для токена текущего процесса, а затем проверить, входит ли хоть одна из них в группу Администраторов локального компьютера. Вот пример реализации:
; Сегмент данных
section '.data' data readable writeable
 
SECURITY_NT_AUTHORITY       = 5
TOKEN_READ                  = 0x00020008
SECURITY_BUILTIN_DOMAIN_RID = 0x00000020
DOMAIN_ALIAS_RID_ADMINS     = 0x00000220
TokenGroups                 = 0x00000002
 
BUFF_SIZE = 1024h ;  Размер буфера для групп доступа токена
 
NtAuthority     db 0,0,0,0,0,SECURITY_NT_AUTHORITY
 
hTokenHandle    dd ?
dInfoSize       dd ?
psidAdmins      dd ?
hHeap           dd ?
pTokenGroups    dd ?
 
;---------------------------------------------
 
; Сегмент кода
section '.code' code readable executable
        ...
        ; Получить токен текущего процесса
        invoke  GetCurrentProcess
        invoke  OpenProcessToken,eax,TOKEN_READ,hTokenHandle
 
        ; Выделить память для массива групп
        invoke  GetProcessHeap
        mov     [hHeap],eax
 
        invoke  HeapAlloc,eax,HEAP_ZERO_MEMORY,BUFF_SIZE
        mov     [pTokenGroups],eax
 
        ; Получить информацию о группах доступа токена
        invoke  GetTokenInformation,[hTokenHandle],TokenGroups,\
                [pTokenGroups],dword BUFF_SIZE,dInfoSize
 
        ; Прибраться за собой
        invoke  CloseHandle,[hTokenHandle]
 
        invoke  AllocateAndInitializeSid,NtAuthority,2,\
                SECURITY_BUILTIN_DOMAIN_RID,\
                DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,psidAdmins
 
        ; Количество записей в структуре TOKEN_GROUPS
        mov     esi,[pTokenGroups]
        mov     ebx,dword [esi]
        ; Указатель на массив SID_AND_ATTRIBUTES
        add     esi,4
@@:
        ; Проверить соответствие SID
        mov     eax,dword [esi]
        invoke  EqualSid,[psidAdmins],eax
        or      eax,eax
        jnz     loc_admin
 
        ; Следующая группа
        add     esi,8
        dec     ebx
        or      ebx,ebx
        jnz     @b
 
loc_not_admin:
        ; Пользователь не Администратор
        ...
 
loc_admin:
        ; Пользователь Администратор
        ...

Обратите внимание, что никаких проверок на ошибки не выполняется, оставлен только рабочий код. Полный вариант вы можете посмотреть в приложении к статье.

Второй вариант очень похож на предыдущий, но будет работать только на системах, начиная с Windows 2000. В нем используется функция CheckTokenMembership, которая и выполняет все громоздкие проверки.
; Сегмент данных
section '.data' data readable writeable
 
SECURITY_NT_AUTHORITY       = 5
SECURITY_BUILTIN_DOMAIN_RID = 0x00000020
DOMAIN_ALIAS_RID_ADMINS     = 0x00000220
 
NtAuthority     db 0,0,0,0,0,SECURITY_NT_AUTHORITY
 
psidAdmins      dd ?
pbAdmin         dd ?
 
;---------------------------------------------
 
; Сегмент кода
section '.code' code readable executable
        ...
        invoke  AllocateAndInitializeSid,NtAuthority,2,\
                SECURITY_BUILTIN_DOMAIN_RID,\
                DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,psidAdmins
 
        invoke  CheckTokenMembership,NULL,[psidAdmins],pbAdmin
        mov     eax,[pbAdmin]
        ; Если EAX=1, то программа запущена под Администратором
        ...

Следующий вариант самый короткий, но он также будет работать только на новых системах. В нем используется функция IsUserAdmin из библиотеки setupapi.dll. Как вы можете догадаться из ее названия, результатом работы этой функции будет TRUE, если пользователь является Администратором, и FALSE, если нет.
        ...
        invoke  IsUserAdmin
        ; Если EAX=1, то программа запущена под Администратором
        ...

И последний способ, не совсем обычный, заключается в том, что сперва мы получаем логин текущего пользователя, а затем с помощью функции NetUserGetInfo запрашиваем подробную информацию о нем (структура USER_INFO_1). В поле usri1_priv хранится информация о правах доступа этого пользователя.
; Сегмент данных
section '.data' data readable writeable
 
struct  USER_INFO_1
        usri1_name         dd ?
        usri1_password     dd ?
        usri1_password_age dd ?
        usri1_priv         dd ?
        usri1_home_dir     dd ?
        usri1_comment      dd ?
        usri1_flags        dd ?
        usri1_script_path  dd ?
ends
 
dSize           dd 100h
szUname         rb 100h
info            dd ?
 
NERR_SUCCESS    = 0
USER_PRIV_ADMIN = 2
 
;---------------------------------------------
 
; Сегмент кода
section '.code' code readable executable
        ...
        ; Получить логин текущего пользователя
        invoke  GetUserName,szUname,dSize
 
        ; Получить информацию о пользователе
        invoke  NetUserGetInfo,NULL,szUname,1,info
        cmp     eax,NERR_SUCCESS
        jne     loc_error
 
        ; Указатель на структуру USER_INFO_1
        mov     eax,[info]
 
        ; Пользователь админ?
        cmp     dword [eax+USER_INFO_1.usri1_priv],USER_PRIV_ADMIN
        je      loc_admin
 
loc_not_admin:
        ; Пользователь не Администратор
        ...
 
loc_admin:
        ; Пользователь Администратор
        ...

Обратите внимание, что все функции, строки и другие ресурсы, использованные в последнем примере, должны быть юникодными. Также это очень ненадежный способ проверки, например, на домашнем компьютере под Windows 7 она работает нормально, а на работе под Windows XP функция NetUserGetInfo возвращает ошибку, что пользователя не существует.

Ну а в заключении еще один небольшой пример, не совсем относящийся к теме статьи, но очень близкий. Это проверка, загружена система в безопасном режиме или в нормальном.
        ; Получить информацию о загрузке системы
        invoke  GetSystemMetrics,SM_CLEANBOOT
        ; EAX=0 - нормальная загрузка
        ; EAX=1 - безопасный режим
        ; EAX=2 - безопасный режим с поддержкой сети

В приложении примеры программ, реализующие все четыре описанных способа проверки прав пользователя, и пример определения варианта загрузки системы.
Теги:
Администратор
Добавлено: 10 Апреля 2018 17:51:13 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...