Blog. Just Blog

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

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

Первый способ наиболее универсальный и работает даже на старых операционных системах. Он заключается в том, что надо получить группы доступа для токена текущего процесса, а затем проверить, входит ли хоть одна из них в группу Администраторов локального компьютера. Вот пример реализации:
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. SECURITY_NT_AUTHORITY       = 5
  5. TOKEN_READ                  = 0x00020008
  6. SECURITY_BUILTIN_DOMAIN_RID = 0x00000020
  7. DOMAIN_ALIAS_RID_ADMINS     = 0x00000220
  8. TokenGroups                 = 0x00000002
  9.  
  10. BUFF_SIZE = 1024h ;  Размер буфера для групп доступа токена
  11.  
  12. NtAuthority     db 0,0,0,0,0,SECURITY_NT_AUTHORITY
  13.  
  14. hTokenHandle    dd ?
  15. dInfoSize       dd ?
  16. psidAdmins      dd ?
  17. hHeap           dd ?
  18. pTokenGroups    dd ?
  19.  
  20. ;---------------------------------------------
  21.  
  22. ; Сегмент кода
  23. section '.code' code readable executable
  24.         ...
  25.         ; Получить токен текущего процесса
  26.         invoke  GetCurrentProcess
  27.         invoke  OpenProcessToken,eax,TOKEN_READ,hTokenHandle
  28.  
  29.         ; Выделить память для массива групп
  30.         invoke  GetProcessHeap
  31.         mov     [hHeap],eax
  32.  
  33.         invoke  HeapAlloc,eax,HEAP_ZERO_MEMORY,BUFF_SIZE
  34.         mov     [pTokenGroups],eax
  35.  
  36.         ; Получить информацию о группах доступа токена
  37.         invoke  GetTokenInformation,[hTokenHandle],TokenGroups,\
  38.                 [pTokenGroups],dword BUFF_SIZE,dInfoSize
  39.  
  40.         ; Прибраться за собой
  41.         invoke  CloseHandle,[hTokenHandle]
  42.  
  43.         invoke  AllocateAndInitializeSid,NtAuthority,2,\
  44.                 SECURITY_BUILTIN_DOMAIN_RID,\
  45.                 DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,psidAdmins
  46.  
  47.         ; Количество записей в структуре TOKEN_GROUPS
  48.         mov     esi,[pTokenGroups]
  49.         mov     ebx,dword [esi]
  50.         ; Указатель на массив SID_AND_ATTRIBUTES
  51.         add     esi,4
  52. @@:
  53.         ; Проверить соответствие SID
  54.         mov     eax,dword [esi]
  55.         invoke  EqualSid,[psidAdmins],eax
  56.         or      eax,eax
  57.         jnz     loc_admin
  58.  
  59.         ; Следующая группа
  60.         add     esi,8
  61.         dec     ebx
  62.         or      ebx,ebx
  63.         jnz     @b
  64.  
  65. loc_not_admin:
  66.         ; Пользователь не Администратор
  67.         ...
  68.  
  69. loc_admin:
  70.         ; Пользователь Администратор
  71.         ...
Обратите внимание, что никаких проверок на ошибки не выполняется, оставлен только рабочий код. Полный вариант вы можете посмотреть в приложении к статье.

Второй вариант очень похож на предыдущий, но будет работать только на системах, начиная с Windows 2000. В нем используется функция CheckTokenMembership, которая и выполняет все громоздкие проверки.
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. SECURITY_NT_AUTHORITY       = 5
  5. SECURITY_BUILTIN_DOMAIN_RID = 0x00000020
  6. DOMAIN_ALIAS_RID_ADMINS     = 0x00000220
  7.  
  8. NtAuthority     db 0,0,0,0,0,SECURITY_NT_AUTHORITY
  9.  
  10. psidAdmins      dd ?
  11. pbAdmin         dd ?
  12.  
  13. ;---------------------------------------------
  14.  
  15. ; Сегмент кода
  16. section '.code' code readable executable
  17.         ...
  18.         invoke  AllocateAndInitializeSid,NtAuthority,2,\
  19.                 SECURITY_BUILTIN_DOMAIN_RID,\
  20.                 DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,psidAdmins
  21.  
  22.         invoke  CheckTokenMembership,NULL,[psidAdmins],pbAdmin
  23.         mov     eax,[pbAdmin]
  24.         ; Если EAX=1, то программа запущена под Администратором
  25.         ...
Следующий вариант самый короткий, но он также будет работать только на новых системах. В нем используется функция IsUserAdmin из библиотеки setupapi.dll. Как вы можете догадаться из ее названия, результатом работы этой функции будет TRUE, если пользователь является Администратором, и FALSE, если нет.
  1.         ...
  2.         invoke  IsUserAdmin
  3.         ; Если EAX=1, то программа запущена под Администратором
  4.         ...
И последний способ, не совсем обычный, заключается в том, что сперва мы получаем логин текущего пользователя, а затем с помощью функции NetUserGetInfo запрашиваем подробную информацию о нем (структура USER_INFO_1). В поле usri1_priv хранится информация о правах доступа этого пользователя.
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. struct  USER_INFO_1
  5.         usri1_name         dd ?
  6.         usri1_password     dd ?
  7.         usri1_password_age dd ?
  8.         usri1_priv         dd ?
  9.         usri1_home_dir     dd ?
  10.         usri1_comment      dd ?
  11.         usri1_flags        dd ?
  12.         usri1_script_path  dd ?
  13. ends
  14.  
  15. dSize           dd 100h
  16. szUname         rb 100h
  17. info            dd ?
  18.  
  19. NERR_SUCCESS    = 0
  20. USER_PRIV_ADMIN = 2
  21.  
  22. ;---------------------------------------------
  23.  
  24. ; Сегмент кода
  25. section '.code' code readable executable
  26.         ...
  27.         ; Получить логин текущего пользователя
  28.         invoke  GetUserName,szUname,dSize
  29.  
  30.         ; Получить информацию о пользователе
  31.         invoke  NetUserGetInfo,NULL,szUname,1,info
  32.         cmp     eax,NERR_SUCCESS
  33.         jne     loc_error
  34.  
  35.         ; Указатель на структуру USER_INFO_1
  36.         mov     eax,[info]
  37.  
  38.         ; Пользователь админ?
  39.         cmp     dword [eax+USER_INFO_1.usri1_priv],USER_PRIV_ADMIN
  40.         je      loc_admin
  41.  
  42. loc_not_admin:
  43.         ; Пользователь не Администратор
  44.         ...
  45.  
  46. loc_admin:
  47.         ; Пользователь Администратор
  48.         ...
Обратите внимание, что все функции, строки и другие ресурсы, использованные в последнем примере, должны быть юникодными. Также это очень ненадежный способ проверки, например, на домашнем компьютере под Windows 7 она работает нормально, а на работе под Windows XP функция NetUserGetInfo возвращает ошибку, что пользователя не существует.

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

Примеры программ с исходными текстами (FASM)Примеры программ с исходными текстами (FASM)

Is.User.Admin.Demo.zip (7,282 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 6912 | Комментариев: 21

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
addhaloka (26.02.2016 в 10:51):
Нашёл ещё вариант - с IsUserAnAdmin из shell32.dll:
section '.code' code readable executable

proc IsUserAnRoot
  invoke  GetModuleHandle,szSH32
  invoke  GetProcAddress,eax,2A8h ; по ординалу, вроде как нужно для старых осей (win2000): https://exelab.ru/f/index.php?...opic=10294#7
  or      eax,eax
  jz      @F
  call    eax
  @@:
  ret
  szSH32  db 'shell32.dll',0
endp

  start:
  call    IsUserAnRoot
  ; Пользователь админ?
  or      eax,eax
  ; далее, как в примере №3
ManHunter (16.05.2015 в 19:15):
Общепринятая формулировка - "запустите программу под администратором". Никто и никогда не говорит типа "запустите процесс, чтобы он имел права администратора".
капитошка (16.05.2015 в 14:49):
извините за то что придираюсь, немного не точные формулировки в названии поста и некоторых предложениях.
нужно точно указать что проверяется наличие прав администратора у запущенного процесса. иначе можно понять что проверяется не администратор ли тот от кого запущен процесс.
вот кстати творчество на основе способа №2.
proc IsUserAdmin
push 0
push esp
align 4
nop
nop
nop
call @F
db 1,2,0,0,0,0,0,SECURITY_NT_AUTHORITY
dd SECURITY_BUILTIN_DOMAIN_RID
dd DOMAIN_ALIAS_RID_ADMINS
@@: invoke  CheckTokenMembership, 0
pop  eax
ret
endp
ManHunter (16.11.2013 в 19:41):
Вряд ли получится, ограниченное приложение без дебажных прав в любом случае будет иметь минимальные права доступа.
А что касается Nt* функций, то не такие уж они и недокументированные, раз все ими пользуются. Я бы их назвал больше "неафишируемыми", чем недокументированными.
_lucius_ (16.11.2013 в 18:20):
ManHunter, здравствуйте. Спасибо вам за ваш замечательный блог. Не подскажите как узнать права у чужого процесса, при условии что у нас самих прав нет и в связи с этим мы не можем открыть процесс с правами PROCESS_QUERY_INFORMATION. Эти права нужны для того чтобы получить хэндл токена (через OpenProcessToken), а затем узнать права через SHTestTokenMembership. Читал то что можно получить хэндл через ZwQuerySystemInformation/ZwDuplicateObject, но очень не хотелось бы использовать недокументированные функции.
X (13.02.2012 в 18:56):
Супер! Работает!
ManHunter (13.02.2012 в 17:37):
Всегда пожалуйста.

данные:

sei     SHELLEXECUTEINFO
runas   db      'runas',0
program db      'fasmw.exe',0
buff    rb      200h

код:

mov     [sei.cbSize],sizeof.SHELLEXECUTEINFO
mov     [sei.lpVerb],runas
mov     [sei.lpFile],program
invoke  GetCurrentDirectory,200h,buff
mov     [sei.lpDirectory],buff
mov     [sei.nShow],SW_SHOW
invoke  ShellExecuteEx,sei

и при запуске дочерней программы будет выдан запрос учетки пользователя
X (13.02.2012 в 17:36):
Спасибо, я понял.
ManHunter (13.02.2012 в 17:31):
Которое из написанного непонятно? Запрашиваешь у пользователя логин-пароль Администратора, передаешь их на runas.exe, PROFIT.

А из юзера свое приложение ты все равно не поднимешь до админа без применения всяких сплойтов, равно как и не запустишь процесс из своего так, чтобы он вдруг заимел админские права без знания логина-пароля админа. Иначе тогда зачем все эти ограничения прав придуманы? Все трояны бы тогда работали из любой ограниченной учетки.
X (13.02.2012 в 17:23):
Пользователь запускает мою программу как не Администратор. Моей программе необходимо запустить cmd.exe с правами Администратора. Я не знаю логин и пароль Администратора. Для запуска cmd.exe я использую WinAPI CreateProcess -> процесс cmd.exe запускается с ограниченными привилегиями. Пробую повысить привилегии своего запускающего процесса:
invoke  LookupPrivilegeValue,NULL,SE_SECURITY_NAME,udtLUID
mov     [tkp.PrivilegeCount],1
mov     [tkp.Privileges.Attributes],SE_PRIVILEGE_ENABLED
mov     eax,[udtLUID.lowPart]
mov     [tkp.Privileges.pLuid.lowPart],eax
mov     eax,[udtLUID.HighPart]
mov     [tkp.Privileges.pLuid.HighPart],eax
invoke  AdjustTokenPrivileges,[TTokenHd],0,tkp,0,0,0

Не помогает.
ManHunter (13.02.2012 в 16:58):
google -> DialogBoxParam, CreateWindow - диалоговое окно с вводом пароля, логина, имени прабабушки и клички любимой собаки
google -> AdjustTokenPrivileges - повышение привилегий процесса

cmd -> runas.exe /?

Или ты чо, из юзерской учетки в своем процессе решил в админы выпрыгнуть? Тогда сразу можешь забыть.
X (13.02.2012 в 16:41):
Я имел ввиду, как заставить пользователя ввести логин и пароль администратора или повысить привилегии процесса?
ManHunter (13.02.2012 в 16:16):
google -> CreateProcessAsUser, CreateProcessWithLogonW, CreateProcessWithTokenW и т.д.
X (13.02.2012 в 16:14):
Если после проверки оказалось, что пользователь не администратор, как зная SID администратора (psidAdmins) запустить другой процесс с правами администратора?
ManHunter (09.01.2012 в 21:02):
UAC у меня выключено, и система стоит на минимальном уровне уведомлений. А об UAC я думаю, что это натуральная херня, которую в MS придумали, чтобы хомячки с предустановленными системами не разносили всякую заразу и не жрали мозги техподдержке.
Stanis (09.01.2012 в 11:23):
ManHunter, вопрос не совсем по теме, но все же
У вас UAC включено или выключенно? и что Вы думаете вообще о нём?
Andrew (28.11.2011 в 13:46):
ManHunter, спасибо за ответ!
ManHunter (28.11.2011 в 12:04):
OllyDbg и отлаживаю, для юзермода пока ничего лучше не придумали. И пока что обхожусь без отладочной информации :)
Andrew (28.11.2011 в 12:01):
ManHunter, скажите пожалуйста (если это не секрет), чем вы отлаживаете ваши приложения? Я пользуюсь OllyDbg, но при размере PE модуля в 10 КБ и больше без отладочной информации запутаться в строчках кода легче легкого (из-за этого даже хотел перейти с FASM на NASM/YASM, но тем не менее отказался от этой идеи).
ManHunter (21.11.2011 в 08:18):
4-й способ и под Гостем тоже показывает "Something wrong", я поэтому сразу написал, что способ очень ненадежный. Про UAC обязательно добавлю, спасибо.
Nutscracker (21.11.2011 в 02:12):
Наверное, надо про UAC добавить.
На Win 7 с включенным UAC правильное «You are NOT admin» сообщают is_admin2.exe и is_admin3.exe.
А если запустить с правами NT AUTHORITY\система (как у процесса winlogon), то is_admin4.exe сообщит «Something wrong ;(».

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0031 сек.) / Память: 4.5 Mb
Наверх